wow.c (16975B)
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 16static 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 24static 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 50static 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 */ 80static 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 171static 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 265static 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 341 if (ar->wmi.rx_decap_mode == ATH10K_HW_TXRX_NATIVE_WIFI) { 342 if (patterns[i].pkt_offset < ETH_HLEN) { 343 ath10k_wow_convert_8023_to_80211(&new_pattern, 344 &old_pattern); 345 } else { 346 new_pattern = old_pattern; 347 new_pattern.pkt_offset += WOW_HDR_LEN - ETH_HLEN; 348 } 349 } 350 351 if (WARN_ON(new_pattern.pattern_len > WOW_MAX_PATTERN_SIZE)) 352 return -EINVAL; 353 354 ret = ath10k_wmi_wow_add_pattern(ar, arvif->vdev_id, 355 pattern_id, 356 new_pattern.pattern, 357 new_pattern.mask, 358 new_pattern.pattern_len, 359 new_pattern.pkt_offset); 360 if (ret) { 361 ath10k_warn(ar, "failed to add pattern %i to vdev %i: %d\n", 362 pattern_id, 363 arvif->vdev_id, ret); 364 return ret; 365 } 366 367 pattern_id++; 368 __set_bit(WOW_PATTERN_MATCH_EVENT, &wow_mask); 369 } 370 371 for (i = 0; i < WOW_EVENT_MAX; i++) { 372 if (!test_bit(i, &wow_mask)) 373 continue; 374 ret = ath10k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 1); 375 if (ret) { 376 ath10k_warn(ar, "failed to enable wakeup event %s on vdev %i: %d\n", 377 wow_wakeup_event(i), arvif->vdev_id, ret); 378 return ret; 379 } 380 } 381 382 return 0; 383} 384 385static int ath10k_wow_set_wakeups(struct ath10k *ar, 386 struct cfg80211_wowlan *wowlan) 387{ 388 struct ath10k_vif *arvif; 389 int ret; 390 391 lockdep_assert_held(&ar->conf_mutex); 392 393 list_for_each_entry(arvif, &ar->arvifs, list) { 394 ret = ath10k_vif_wow_set_wakeups(arvif, wowlan); 395 if (ret) { 396 ath10k_warn(ar, "failed to set wow wakeups on vdev %i: %d\n", 397 arvif->vdev_id, ret); 398 return ret; 399 } 400 } 401 402 return 0; 403} 404 405static int ath10k_vif_wow_clean_nlo(struct ath10k_vif *arvif) 406{ 407 int ret = 0; 408 struct ath10k *ar = arvif->ar; 409 410 switch (arvif->vdev_type) { 411 case WMI_VDEV_TYPE_STA: 412 if (ar->nlo_enabled) { 413 struct wmi_pno_scan_req *pno; 414 415 pno = kzalloc(sizeof(*pno), GFP_KERNEL); 416 if (!pno) 417 return -ENOMEM; 418 419 pno->enable = 0; 420 ar->nlo_enabled = false; 421 ret = ath10k_wmi_wow_config_pno(ar, arvif->vdev_id, pno); 422 kfree(pno); 423 } 424 break; 425 default: 426 break; 427 } 428 return ret; 429} 430 431static int ath10k_wow_nlo_cleanup(struct ath10k *ar) 432{ 433 struct ath10k_vif *arvif; 434 int ret = 0; 435 436 lockdep_assert_held(&ar->conf_mutex); 437 438 list_for_each_entry(arvif, &ar->arvifs, list) { 439 ret = ath10k_vif_wow_clean_nlo(arvif); 440 if (ret) { 441 ath10k_warn(ar, "failed to clean nlo settings on vdev %i: %d\n", 442 arvif->vdev_id, ret); 443 return ret; 444 } 445 } 446 447 return 0; 448} 449 450static int ath10k_wow_enable(struct ath10k *ar) 451{ 452 int ret; 453 454 lockdep_assert_held(&ar->conf_mutex); 455 456 reinit_completion(&ar->target_suspend); 457 458 ret = ath10k_wmi_wow_enable(ar); 459 if (ret) { 460 ath10k_warn(ar, "failed to issue wow enable: %d\n", ret); 461 return ret; 462 } 463 464 ret = wait_for_completion_timeout(&ar->target_suspend, 3 * HZ); 465 if (ret == 0) { 466 ath10k_warn(ar, "timed out while waiting for suspend completion\n"); 467 return -ETIMEDOUT; 468 } 469 470 return 0; 471} 472 473static int ath10k_wow_wakeup(struct ath10k *ar) 474{ 475 int ret; 476 477 lockdep_assert_held(&ar->conf_mutex); 478 479 reinit_completion(&ar->wow.wakeup_completed); 480 481 ret = ath10k_wmi_wow_host_wakeup_ind(ar); 482 if (ret) { 483 ath10k_warn(ar, "failed to send wow wakeup indication: %d\n", 484 ret); 485 return ret; 486 } 487 488 ret = wait_for_completion_timeout(&ar->wow.wakeup_completed, 3 * HZ); 489 if (ret == 0) { 490 ath10k_warn(ar, "timed out while waiting for wow wakeup completion\n"); 491 return -ETIMEDOUT; 492 } 493 494 return 0; 495} 496 497int ath10k_wow_op_suspend(struct ieee80211_hw *hw, 498 struct cfg80211_wowlan *wowlan) 499{ 500 struct ath10k *ar = hw->priv; 501 int ret; 502 503 mutex_lock(&ar->conf_mutex); 504 505 if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, 506 ar->running_fw->fw_file.fw_features))) { 507 ret = 1; 508 goto exit; 509 } 510 511 ret = ath10k_wow_cleanup(ar); 512 if (ret) { 513 ath10k_warn(ar, "failed to clear wow wakeup events: %d\n", 514 ret); 515 goto exit; 516 } 517 518 ret = ath10k_wow_set_wakeups(ar, wowlan); 519 if (ret) { 520 ath10k_warn(ar, "failed to set wow wakeup events: %d\n", 521 ret); 522 goto cleanup; 523 } 524 525 ath10k_mac_wait_tx_complete(ar); 526 527 ret = ath10k_wow_enable(ar); 528 if (ret) { 529 ath10k_warn(ar, "failed to start wow: %d\n", ret); 530 goto cleanup; 531 } 532 533 ret = ath10k_hif_suspend(ar); 534 if (ret) { 535 ath10k_warn(ar, "failed to suspend hif: %d\n", ret); 536 goto wakeup; 537 } 538 539 goto exit; 540 541wakeup: 542 ath10k_wow_wakeup(ar); 543 544cleanup: 545 ath10k_wow_cleanup(ar); 546 547exit: 548 mutex_unlock(&ar->conf_mutex); 549 return ret ? 1 : 0; 550} 551 552void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled) 553{ 554 struct ath10k *ar = hw->priv; 555 556 mutex_lock(&ar->conf_mutex); 557 if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, 558 ar->running_fw->fw_file.fw_features)) { 559 device_set_wakeup_enable(ar->dev, enabled); 560 } 561 mutex_unlock(&ar->conf_mutex); 562} 563 564int ath10k_wow_op_resume(struct ieee80211_hw *hw) 565{ 566 struct ath10k *ar = hw->priv; 567 int ret; 568 569 mutex_lock(&ar->conf_mutex); 570 571 if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, 572 ar->running_fw->fw_file.fw_features))) { 573 ret = 1; 574 goto exit; 575 } 576 577 ret = ath10k_hif_resume(ar); 578 if (ret) { 579 ath10k_warn(ar, "failed to resume hif: %d\n", ret); 580 goto exit; 581 } 582 583 ret = ath10k_wow_wakeup(ar); 584 if (ret) 585 ath10k_warn(ar, "failed to wakeup from wow: %d\n", ret); 586 587 ret = ath10k_wow_nlo_cleanup(ar); 588 if (ret) 589 ath10k_warn(ar, "failed to cleanup nlo: %d\n", ret); 590 591exit: 592 if (ret) { 593 switch (ar->state) { 594 case ATH10K_STATE_ON: 595 ar->state = ATH10K_STATE_RESTARTING; 596 ret = 1; 597 break; 598 case ATH10K_STATE_OFF: 599 case ATH10K_STATE_RESTARTING: 600 case ATH10K_STATE_RESTARTED: 601 case ATH10K_STATE_UTF: 602 case ATH10K_STATE_WEDGED: 603 ath10k_warn(ar, "encountered unexpected device state %d on resume, cannot recover\n", 604 ar->state); 605 ret = -EIO; 606 break; 607 } 608 } 609 610 mutex_unlock(&ar->conf_mutex); 611 return ret; 612} 613 614int ath10k_wow_init(struct ath10k *ar) 615{ 616 if (!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, 617 ar->running_fw->fw_file.fw_features)) 618 return 0; 619 620 if (WARN_ON(!test_bit(WMI_SERVICE_WOW, ar->wmi.svc_map))) 621 return -EINVAL; 622 623 ar->wow.wowlan_support = ath10k_wowlan_support; 624 625 if (ar->wmi.rx_decap_mode == ATH10K_HW_TXRX_NATIVE_WIFI) { 626 ar->wow.wowlan_support.pattern_max_len -= WOW_MAX_REDUCE; 627 ar->wow.wowlan_support.max_pkt_offset -= WOW_MAX_REDUCE; 628 } 629 630 if (test_bit(WMI_SERVICE_NLO, ar->wmi.svc_map)) { 631 ar->wow.wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT; 632 ar->wow.wowlan_support.max_nd_match_sets = WMI_PNO_MAX_SUPP_NETWORKS; 633 } 634 635 ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns; 636 ar->hw->wiphy->wowlan = &ar->wow.wowlan_support; 637 638 device_set_wakeup_capable(ar->dev, true); 639 640 return 0; 641}