1 // SPDX-License-Identifier: ISC 2 /* 3 * Copyright (c) 2015-2017 Qualcomm Atheros, Inc. 4 * Copyright (c) 2018, The Linux Foundation. All rights reserved. 5 */ 6 7 #include "mac.h" 8 9 #include <net/mac80211.h> 10 #include "hif.h" 11 #include "core.h" 12 #include "debug.h" 13 #include "wmi.h" 14 #include "wmi-ops.h" 15 16 static const struct wiphy_wowlan_support ath10k_wowlan_support = { 17 .flags = WIPHY_WOWLAN_DISCONNECT | 18 WIPHY_WOWLAN_MAGIC_PKT, 19 .pattern_min_len = WOW_MIN_PATTERN_SIZE, 20 .pattern_max_len = WOW_MAX_PATTERN_SIZE, 21 .max_pkt_offset = WOW_MAX_PKT_OFFSET, 22 }; 23 24 static int ath10k_wow_vif_cleanup(struct ath10k_vif *arvif) 25 { 26 struct ath10k *ar = arvif->ar; 27 int i, ret; 28 29 for (i = 0; i < WOW_EVENT_MAX; i++) { 30 ret = ath10k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 0); 31 if (ret) { 32 ath10k_warn(ar, "failed to issue wow wakeup for event %s on vdev %i: %d\n", 33 wow_wakeup_event(i), arvif->vdev_id, ret); 34 return ret; 35 } 36 } 37 38 for (i = 0; i < ar->wow.max_num_patterns; i++) { 39 ret = ath10k_wmi_wow_del_pattern(ar, arvif->vdev_id, i); 40 if (ret) { 41 ath10k_warn(ar, "failed to delete wow pattern %d for vdev %i: %d\n", 42 i, arvif->vdev_id, ret); 43 return ret; 44 } 45 } 46 47 return 0; 48 } 49 50 static int ath10k_wow_cleanup(struct ath10k *ar) 51 { 52 struct ath10k_vif *arvif; 53 int ret; 54 55 lockdep_assert_held(&ar->conf_mutex); 56 57 list_for_each_entry(arvif, &ar->arvifs, list) { 58 ret = ath10k_wow_vif_cleanup(arvif); 59 if (ret) { 60 ath10k_warn(ar, "failed to clean wow wakeups on vdev %i: %d\n", 61 arvif->vdev_id, ret); 62 return ret; 63 } 64 } 65 66 return 0; 67 } 68 69 /* 70 * Convert a 802.3 format to a 802.11 format. 71 * +------------+-----------+--------+----------------+ 72 * 802.3: |dest mac(6B)|src mac(6B)|type(2B)| body... | 73 * +------------+-----------+--------+----------------+ 74 * |__ |_______ |____________ |________ 75 * | | | | 76 * +--+------------+----+-----------+---------------+-----------+ 77 * 802.11: |4B|dest mac(6B)| 6B |src mac(6B)| 8B |type(2B)| body... | 78 * +--+------------+----+-----------+---------------+-----------+ 79 */ 80 static void ath10k_wow_convert_8023_to_80211(struct cfg80211_pkt_pattern *new, 81 const struct cfg80211_pkt_pattern *old) 82 { 83 u8 hdr_8023_pattern[ETH_HLEN] = {}; 84 u8 hdr_8023_bit_mask[ETH_HLEN] = {}; 85 u8 hdr_80211_pattern[WOW_HDR_LEN] = {}; 86 u8 hdr_80211_bit_mask[WOW_HDR_LEN] = {}; 87 88 int total_len = old->pkt_offset + old->pattern_len; 89 int hdr_80211_end_offset; 90 91 struct ieee80211_hdr_3addr *new_hdr_pattern = 92 (struct ieee80211_hdr_3addr *)hdr_80211_pattern; 93 struct ieee80211_hdr_3addr *new_hdr_mask = 94 (struct ieee80211_hdr_3addr *)hdr_80211_bit_mask; 95 struct ethhdr *old_hdr_pattern = (struct ethhdr *)hdr_8023_pattern; 96 struct ethhdr *old_hdr_mask = (struct ethhdr *)hdr_8023_bit_mask; 97 int hdr_len = sizeof(*new_hdr_pattern); 98 99 struct rfc1042_hdr *new_rfc_pattern = 100 (struct rfc1042_hdr *)(hdr_80211_pattern + hdr_len); 101 struct rfc1042_hdr *new_rfc_mask = 102 (struct rfc1042_hdr *)(hdr_80211_bit_mask + hdr_len); 103 int rfc_len = sizeof(*new_rfc_pattern); 104 105 memcpy(hdr_8023_pattern + old->pkt_offset, 106 old->pattern, ETH_HLEN - old->pkt_offset); 107 memcpy(hdr_8023_bit_mask + old->pkt_offset, 108 old->mask, ETH_HLEN - old->pkt_offset); 109 110 /* Copy destination address */ 111 memcpy(new_hdr_pattern->addr1, old_hdr_pattern->h_dest, ETH_ALEN); 112 memcpy(new_hdr_mask->addr1, old_hdr_mask->h_dest, ETH_ALEN); 113 114 /* Copy source address */ 115 memcpy(new_hdr_pattern->addr3, old_hdr_pattern->h_source, ETH_ALEN); 116 memcpy(new_hdr_mask->addr3, old_hdr_mask->h_source, ETH_ALEN); 117 118 /* Copy logic link type */ 119 memcpy(&new_rfc_pattern->snap_type, 120 &old_hdr_pattern->h_proto, 121 sizeof(old_hdr_pattern->h_proto)); 122 memcpy(&new_rfc_mask->snap_type, 123 &old_hdr_mask->h_proto, 124 sizeof(old_hdr_mask->h_proto)); 125 126 /* Calculate new pkt_offset */ 127 if (old->pkt_offset < ETH_ALEN) 128 new->pkt_offset = old->pkt_offset + 129 offsetof(struct ieee80211_hdr_3addr, addr1); 130 else if (old->pkt_offset < offsetof(struct ethhdr, h_proto)) 131 new->pkt_offset = old->pkt_offset + 132 offsetof(struct ieee80211_hdr_3addr, addr3) - 133 offsetof(struct ethhdr, h_source); 134 else 135 new->pkt_offset = old->pkt_offset + hdr_len + rfc_len - ETH_HLEN; 136 137 /* Calculate new hdr end offset */ 138 if (total_len > ETH_HLEN) 139 hdr_80211_end_offset = hdr_len + rfc_len; 140 else if (total_len > offsetof(struct ethhdr, h_proto)) 141 hdr_80211_end_offset = hdr_len + rfc_len + total_len - ETH_HLEN; 142 else if (total_len > ETH_ALEN) 143 hdr_80211_end_offset = total_len - ETH_ALEN + 144 offsetof(struct ieee80211_hdr_3addr, addr3); 145 else 146 hdr_80211_end_offset = total_len + 147 offsetof(struct ieee80211_hdr_3addr, addr1); 148 149 new->pattern_len = hdr_80211_end_offset - new->pkt_offset; 150 151 memcpy((u8 *)new->pattern, 152 hdr_80211_pattern + new->pkt_offset, 153 new->pattern_len); 154 memcpy((u8 *)new->mask, 155 hdr_80211_bit_mask + new->pkt_offset, 156 new->pattern_len); 157 158 if (total_len > ETH_HLEN) { 159 /* Copy frame body */ 160 memcpy((u8 *)new->pattern + new->pattern_len, 161 (void *)old->pattern + ETH_HLEN - old->pkt_offset, 162 total_len - ETH_HLEN); 163 memcpy((u8 *)new->mask + new->pattern_len, 164 (void *)old->mask + ETH_HLEN - old->pkt_offset, 165 total_len - ETH_HLEN); 166 167 new->pattern_len += total_len - ETH_HLEN; 168 } 169 } 170 171 static int ath10k_wmi_pno_check(struct ath10k *ar, u32 vdev_id, 172 struct cfg80211_sched_scan_request *nd_config, 173 struct wmi_pno_scan_req *pno) 174 { 175 int i, j, ret = 0; 176 u8 ssid_len; 177 178 pno->enable = 1; 179 pno->vdev_id = vdev_id; 180 pno->uc_networks_count = nd_config->n_match_sets; 181 182 if (!pno->uc_networks_count || 183 pno->uc_networks_count > WMI_PNO_MAX_SUPP_NETWORKS) 184 return -EINVAL; 185 186 if (nd_config->n_channels > WMI_PNO_MAX_NETW_CHANNELS_EX) 187 return -EINVAL; 188 189 /* Filling per profile params */ 190 for (i = 0; i < pno->uc_networks_count; i++) { 191 ssid_len = nd_config->match_sets[i].ssid.ssid_len; 192 193 if (ssid_len == 0 || ssid_len > 32) 194 return -EINVAL; 195 196 pno->a_networks[i].ssid.ssid_len = __cpu_to_le32(ssid_len); 197 198 memcpy(pno->a_networks[i].ssid.ssid, 199 nd_config->match_sets[i].ssid.ssid, 200 nd_config->match_sets[i].ssid.ssid_len); 201 pno->a_networks[i].authentication = 0; 202 pno->a_networks[i].encryption = 0; 203 pno->a_networks[i].bcast_nw_type = 0; 204 205 /*Copying list of valid channel into request */ 206 pno->a_networks[i].channel_count = nd_config->n_channels; 207 pno->a_networks[i].rssi_threshold = nd_config->match_sets[i].rssi_thold; 208 209 for (j = 0; j < nd_config->n_channels; j++) { 210 pno->a_networks[i].channels[j] = 211 nd_config->channels[j]->center_freq; 212 } 213 } 214 215 /* set scan to passive if no SSIDs are specified in the request */ 216 if (nd_config->n_ssids == 0) 217 pno->do_passive_scan = true; 218 else 219 pno->do_passive_scan = false; 220 221 for (i = 0; i < nd_config->n_ssids; i++) { 222 j = 0; 223 while (j < pno->uc_networks_count) { 224 if (__le32_to_cpu(pno->a_networks[j].ssid.ssid_len) == 225 nd_config->ssids[i].ssid_len && 226 (memcmp(pno->a_networks[j].ssid.ssid, 227 nd_config->ssids[i].ssid, 228 __le32_to_cpu(pno->a_networks[j].ssid.ssid_len)) == 0)) { 229 pno->a_networks[j].bcast_nw_type = BCAST_HIDDEN; 230 break; 231 } 232 j++; 233 } 234 } 235 236 if (nd_config->n_scan_plans == 2) { 237 pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC; 238 pno->fast_scan_max_cycles = nd_config->scan_plans[0].iterations; 239 pno->slow_scan_period = 240 nd_config->scan_plans[1].interval * MSEC_PER_SEC; 241 } else if (nd_config->n_scan_plans == 1) { 242 pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC; 243 pno->fast_scan_max_cycles = 1; 244 pno->slow_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC; 245 } else { 246 ath10k_warn(ar, "Invalid number of scan plans %d !!", 247 nd_config->n_scan_plans); 248 } 249 250 if (nd_config->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { 251 /* enable mac randomization */ 252 pno->enable_pno_scan_randomization = 1; 253 memcpy(pno->mac_addr, nd_config->mac_addr, ETH_ALEN); 254 memcpy(pno->mac_addr_mask, nd_config->mac_addr_mask, ETH_ALEN); 255 } 256 257 pno->delay_start_time = nd_config->delay; 258 259 /* Current FW does not support min-max range for dwell time */ 260 pno->active_max_time = WMI_ACTIVE_MAX_CHANNEL_TIME; 261 pno->passive_max_time = WMI_PASSIVE_MAX_CHANNEL_TIME; 262 return ret; 263 } 264 265 static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif, 266 struct cfg80211_wowlan *wowlan) 267 { 268 int ret, i; 269 unsigned long wow_mask = 0; 270 struct ath10k *ar = arvif->ar; 271 const struct cfg80211_pkt_pattern *patterns = wowlan->patterns; 272 int pattern_id = 0; 273 274 /* Setup requested WOW features */ 275 switch (arvif->vdev_type) { 276 case WMI_VDEV_TYPE_IBSS: 277 __set_bit(WOW_BEACON_EVENT, &wow_mask); 278 fallthrough; 279 case WMI_VDEV_TYPE_AP: 280 __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask); 281 __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask); 282 __set_bit(WOW_PROBE_REQ_WPS_IE_EVENT, &wow_mask); 283 __set_bit(WOW_AUTH_REQ_EVENT, &wow_mask); 284 __set_bit(WOW_ASSOC_REQ_EVENT, &wow_mask); 285 __set_bit(WOW_HTT_EVENT, &wow_mask); 286 __set_bit(WOW_RA_MATCH_EVENT, &wow_mask); 287 break; 288 case WMI_VDEV_TYPE_STA: 289 if (wowlan->disconnect) { 290 __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask); 291 __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask); 292 __set_bit(WOW_BMISS_EVENT, &wow_mask); 293 __set_bit(WOW_CSA_IE_EVENT, &wow_mask); 294 } 295 296 if (wowlan->magic_pkt) 297 __set_bit(WOW_MAGIC_PKT_RECVD_EVENT, &wow_mask); 298 299 if (wowlan->nd_config) { 300 struct wmi_pno_scan_req *pno; 301 int ret; 302 303 pno = kzalloc(sizeof(*pno), GFP_KERNEL); 304 if (!pno) 305 return -ENOMEM; 306 307 ar->nlo_enabled = true; 308 309 ret = ath10k_wmi_pno_check(ar, arvif->vdev_id, 310 wowlan->nd_config, pno); 311 if (!ret) { 312 ath10k_wmi_wow_config_pno(ar, arvif->vdev_id, pno); 313 __set_bit(WOW_NLO_DETECTED_EVENT, &wow_mask); 314 } 315 316 kfree(pno); 317 } 318 break; 319 default: 320 break; 321 } 322 323 for (i = 0; i < wowlan->n_patterns; i++) { 324 u8 bitmask[WOW_MAX_PATTERN_SIZE] = {}; 325 u8 ath_pattern[WOW_MAX_PATTERN_SIZE] = {}; 326 u8 ath_bitmask[WOW_MAX_PATTERN_SIZE] = {}; 327 struct cfg80211_pkt_pattern new_pattern = {}; 328 struct cfg80211_pkt_pattern old_pattern = patterns[i]; 329 int j; 330 331 new_pattern.pattern = ath_pattern; 332 new_pattern.mask = ath_bitmask; 333 if (patterns[i].pattern_len > WOW_MAX_PATTERN_SIZE) 334 continue; 335 /* convert bytemask to bitmask */ 336 for (j = 0; j < patterns[i].pattern_len; j++) 337 if (patterns[i].mask[j / 8] & BIT(j % 8)) 338 bitmask[j] = 0xff; 339 old_pattern.mask = bitmask; 340 new_pattern = old_pattern; 341 342 if (ar->wmi.rx_decap_mode == ATH10K_HW_TXRX_NATIVE_WIFI) { 343 if (patterns[i].pkt_offset < ETH_HLEN) 344 ath10k_wow_convert_8023_to_80211(&new_pattern, 345 &old_pattern); 346 else 347 new_pattern.pkt_offset += WOW_HDR_LEN - ETH_HLEN; 348 } 349 350 if (WARN_ON(new_pattern.pattern_len > WOW_MAX_PATTERN_SIZE)) 351 return -EINVAL; 352 353 ret = ath10k_wmi_wow_add_pattern(ar, arvif->vdev_id, 354 pattern_id, 355 new_pattern.pattern, 356 new_pattern.mask, 357 new_pattern.pattern_len, 358 new_pattern.pkt_offset); 359 if (ret) { 360 ath10k_warn(ar, "failed to add pattern %i to vdev %i: %d\n", 361 pattern_id, 362 arvif->vdev_id, ret); 363 return ret; 364 } 365 366 pattern_id++; 367 __set_bit(WOW_PATTERN_MATCH_EVENT, &wow_mask); 368 } 369 370 for (i = 0; i < WOW_EVENT_MAX; i++) { 371 if (!test_bit(i, &wow_mask)) 372 continue; 373 ret = ath10k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 1); 374 if (ret) { 375 ath10k_warn(ar, "failed to enable wakeup event %s on vdev %i: %d\n", 376 wow_wakeup_event(i), arvif->vdev_id, ret); 377 return ret; 378 } 379 } 380 381 return 0; 382 } 383 384 static int ath10k_wow_set_wakeups(struct ath10k *ar, 385 struct cfg80211_wowlan *wowlan) 386 { 387 struct ath10k_vif *arvif; 388 int ret; 389 390 lockdep_assert_held(&ar->conf_mutex); 391 392 list_for_each_entry(arvif, &ar->arvifs, list) { 393 ret = ath10k_vif_wow_set_wakeups(arvif, wowlan); 394 if (ret) { 395 ath10k_warn(ar, "failed to set wow wakeups on vdev %i: %d\n", 396 arvif->vdev_id, ret); 397 return ret; 398 } 399 } 400 401 return 0; 402 } 403 404 static int ath10k_vif_wow_clean_nlo(struct ath10k_vif *arvif) 405 { 406 int ret = 0; 407 struct ath10k *ar = arvif->ar; 408 409 switch (arvif->vdev_type) { 410 case WMI_VDEV_TYPE_STA: 411 if (ar->nlo_enabled) { 412 struct wmi_pno_scan_req *pno; 413 414 pno = kzalloc(sizeof(*pno), GFP_KERNEL); 415 if (!pno) 416 return -ENOMEM; 417 418 pno->enable = 0; 419 ar->nlo_enabled = false; 420 ret = ath10k_wmi_wow_config_pno(ar, arvif->vdev_id, pno); 421 kfree(pno); 422 } 423 break; 424 default: 425 break; 426 } 427 return ret; 428 } 429 430 static int ath10k_wow_nlo_cleanup(struct ath10k *ar) 431 { 432 struct ath10k_vif *arvif; 433 int ret = 0; 434 435 lockdep_assert_held(&ar->conf_mutex); 436 437 list_for_each_entry(arvif, &ar->arvifs, list) { 438 ret = ath10k_vif_wow_clean_nlo(arvif); 439 if (ret) { 440 ath10k_warn(ar, "failed to clean nlo settings on vdev %i: %d\n", 441 arvif->vdev_id, ret); 442 return ret; 443 } 444 } 445 446 return 0; 447 } 448 449 static int ath10k_wow_enable(struct ath10k *ar) 450 { 451 int ret; 452 453 lockdep_assert_held(&ar->conf_mutex); 454 455 reinit_completion(&ar->target_suspend); 456 457 ret = ath10k_wmi_wow_enable(ar); 458 if (ret) { 459 ath10k_warn(ar, "failed to issue wow enable: %d\n", ret); 460 return ret; 461 } 462 463 ret = wait_for_completion_timeout(&ar->target_suspend, 3 * HZ); 464 if (ret == 0) { 465 ath10k_warn(ar, "timed out while waiting for suspend completion\n"); 466 return -ETIMEDOUT; 467 } 468 469 return 0; 470 } 471 472 static int ath10k_wow_wakeup(struct ath10k *ar) 473 { 474 int ret; 475 476 lockdep_assert_held(&ar->conf_mutex); 477 478 reinit_completion(&ar->wow.wakeup_completed); 479 480 ret = ath10k_wmi_wow_host_wakeup_ind(ar); 481 if (ret) { 482 ath10k_warn(ar, "failed to send wow wakeup indication: %d\n", 483 ret); 484 return ret; 485 } 486 487 ret = wait_for_completion_timeout(&ar->wow.wakeup_completed, 3 * HZ); 488 if (ret == 0) { 489 ath10k_warn(ar, "timed out while waiting for wow wakeup completion\n"); 490 return -ETIMEDOUT; 491 } 492 493 return 0; 494 } 495 496 int ath10k_wow_op_suspend(struct ieee80211_hw *hw, 497 struct cfg80211_wowlan *wowlan) 498 { 499 struct ath10k *ar = hw->priv; 500 int ret; 501 502 mutex_lock(&ar->conf_mutex); 503 504 if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, 505 ar->running_fw->fw_file.fw_features))) { 506 ret = 1; 507 goto exit; 508 } 509 510 ret = ath10k_wow_cleanup(ar); 511 if (ret) { 512 ath10k_warn(ar, "failed to clear wow wakeup events: %d\n", 513 ret); 514 goto exit; 515 } 516 517 ret = ath10k_wow_set_wakeups(ar, wowlan); 518 if (ret) { 519 ath10k_warn(ar, "failed to set wow wakeup events: %d\n", 520 ret); 521 goto cleanup; 522 } 523 524 ath10k_mac_wait_tx_complete(ar); 525 526 ret = ath10k_wow_enable(ar); 527 if (ret) { 528 ath10k_warn(ar, "failed to start wow: %d\n", ret); 529 goto cleanup; 530 } 531 532 ret = ath10k_hif_suspend(ar); 533 if (ret) { 534 ath10k_warn(ar, "failed to suspend hif: %d\n", ret); 535 goto wakeup; 536 } 537 538 goto exit; 539 540 wakeup: 541 ath10k_wow_wakeup(ar); 542 543 cleanup: 544 ath10k_wow_cleanup(ar); 545 546 exit: 547 mutex_unlock(&ar->conf_mutex); 548 return ret ? 1 : 0; 549 } 550 551 void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled) 552 { 553 struct ath10k *ar = hw->priv; 554 555 mutex_lock(&ar->conf_mutex); 556 if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, 557 ar->running_fw->fw_file.fw_features)) { 558 device_set_wakeup_enable(ar->dev, enabled); 559 } 560 mutex_unlock(&ar->conf_mutex); 561 } 562 563 int ath10k_wow_op_resume(struct ieee80211_hw *hw) 564 { 565 struct ath10k *ar = hw->priv; 566 int ret; 567 568 mutex_lock(&ar->conf_mutex); 569 570 if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, 571 ar->running_fw->fw_file.fw_features))) { 572 ret = 1; 573 goto exit; 574 } 575 576 ret = ath10k_hif_resume(ar); 577 if (ret) { 578 ath10k_warn(ar, "failed to resume hif: %d\n", ret); 579 goto exit; 580 } 581 582 ret = ath10k_wow_wakeup(ar); 583 if (ret) 584 ath10k_warn(ar, "failed to wakeup from wow: %d\n", ret); 585 586 ret = ath10k_wow_nlo_cleanup(ar); 587 if (ret) 588 ath10k_warn(ar, "failed to cleanup nlo: %d\n", ret); 589 590 exit: 591 if (ret) { 592 switch (ar->state) { 593 case ATH10K_STATE_ON: 594 ar->state = ATH10K_STATE_RESTARTING; 595 ret = 1; 596 break; 597 case ATH10K_STATE_OFF: 598 case ATH10K_STATE_RESTARTING: 599 case ATH10K_STATE_RESTARTED: 600 case ATH10K_STATE_UTF: 601 case ATH10K_STATE_WEDGED: 602 ath10k_warn(ar, "encountered unexpected device state %d on resume, cannot recover\n", 603 ar->state); 604 ret = -EIO; 605 break; 606 } 607 } 608 609 mutex_unlock(&ar->conf_mutex); 610 return ret; 611 } 612 613 int ath10k_wow_init(struct ath10k *ar) 614 { 615 if (!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, 616 ar->running_fw->fw_file.fw_features)) 617 return 0; 618 619 if (WARN_ON(!test_bit(WMI_SERVICE_WOW, ar->wmi.svc_map))) 620 return -EINVAL; 621 622 ar->wow.wowlan_support = ath10k_wowlan_support; 623 624 if (ar->wmi.rx_decap_mode == ATH10K_HW_TXRX_NATIVE_WIFI) { 625 ar->wow.wowlan_support.pattern_max_len -= WOW_MAX_REDUCE; 626 ar->wow.wowlan_support.max_pkt_offset -= WOW_MAX_REDUCE; 627 } 628 629 if (test_bit(WMI_SERVICE_NLO, ar->wmi.svc_map)) { 630 ar->wow.wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT; 631 ar->wow.wowlan_support.max_nd_match_sets = WMI_PNO_MAX_SUPP_NETWORKS; 632 } 633 634 ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns; 635 ar->hw->wiphy->wowlan = &ar->wow.wowlan_support; 636 637 device_set_wakeup_capable(ar->dev, true); 638 639 return 0; 640 } 641