Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: ISC
0002 /*
0003  * Copyright (c) 2015-2017 Qualcomm Atheros, Inc.
0004  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
0005  */
0006 
0007 #include "mac.h"
0008 
0009 #include <net/mac80211.h>
0010 #include "hif.h"
0011 #include "core.h"
0012 #include "debug.h"
0013 #include "wmi.h"
0014 #include "wmi-ops.h"
0015 
0016 static const struct wiphy_wowlan_support ath10k_wowlan_support = {
0017     .flags = WIPHY_WOWLAN_DISCONNECT |
0018          WIPHY_WOWLAN_MAGIC_PKT,
0019     .pattern_min_len = WOW_MIN_PATTERN_SIZE,
0020     .pattern_max_len = WOW_MAX_PATTERN_SIZE,
0021     .max_pkt_offset = WOW_MAX_PKT_OFFSET,
0022 };
0023 
0024 static int ath10k_wow_vif_cleanup(struct ath10k_vif *arvif)
0025 {
0026     struct ath10k *ar = arvif->ar;
0027     int i, ret;
0028 
0029     for (i = 0; i < WOW_EVENT_MAX; i++) {
0030         ret = ath10k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 0);
0031         if (ret) {
0032             ath10k_warn(ar, "failed to issue wow wakeup for event %s on vdev %i: %d\n",
0033                     wow_wakeup_event(i), arvif->vdev_id, ret);
0034             return ret;
0035         }
0036     }
0037 
0038     for (i = 0; i < ar->wow.max_num_patterns; i++) {
0039         ret = ath10k_wmi_wow_del_pattern(ar, arvif->vdev_id, i);
0040         if (ret) {
0041             ath10k_warn(ar, "failed to delete wow pattern %d for vdev %i: %d\n",
0042                     i, arvif->vdev_id, ret);
0043             return ret;
0044         }
0045     }
0046 
0047     return 0;
0048 }
0049 
0050 static int ath10k_wow_cleanup(struct ath10k *ar)
0051 {
0052     struct ath10k_vif *arvif;
0053     int ret;
0054 
0055     lockdep_assert_held(&ar->conf_mutex);
0056 
0057     list_for_each_entry(arvif, &ar->arvifs, list) {
0058         ret = ath10k_wow_vif_cleanup(arvif);
0059         if (ret) {
0060             ath10k_warn(ar, "failed to clean wow wakeups on vdev %i: %d\n",
0061                     arvif->vdev_id, ret);
0062             return ret;
0063         }
0064     }
0065 
0066     return 0;
0067 }
0068 
0069 /*
0070  * Convert a 802.3 format to a 802.11 format.
0071  *         +------------+-----------+--------+----------------+
0072  * 802.3:  |dest mac(6B)|src mac(6B)|type(2B)|     body...    |
0073  *         +------------+-----------+--------+----------------+
0074  *                |__         |_______    |____________  |________
0075  *                   |                |                |          |
0076  *         +--+------------+----+-----------+---------------+-----------+
0077  * 802.11: |4B|dest mac(6B)| 6B |src mac(6B)|  8B  |type(2B)|  body...  |
0078  *         +--+------------+----+-----------+---------------+-----------+
0079  */
0080 static void ath10k_wow_convert_8023_to_80211(struct cfg80211_pkt_pattern *new,
0081                          const struct cfg80211_pkt_pattern *old)
0082 {
0083     u8 hdr_8023_pattern[ETH_HLEN] = {};
0084     u8 hdr_8023_bit_mask[ETH_HLEN] = {};
0085     u8 hdr_80211_pattern[WOW_HDR_LEN] = {};
0086     u8 hdr_80211_bit_mask[WOW_HDR_LEN] = {};
0087 
0088     int total_len = old->pkt_offset + old->pattern_len;
0089     int hdr_80211_end_offset;
0090 
0091     struct ieee80211_hdr_3addr *new_hdr_pattern =
0092         (struct ieee80211_hdr_3addr *)hdr_80211_pattern;
0093     struct ieee80211_hdr_3addr *new_hdr_mask =
0094         (struct ieee80211_hdr_3addr *)hdr_80211_bit_mask;
0095     struct ethhdr *old_hdr_pattern = (struct ethhdr *)hdr_8023_pattern;
0096     struct ethhdr *old_hdr_mask = (struct ethhdr *)hdr_8023_bit_mask;
0097     int hdr_len = sizeof(*new_hdr_pattern);
0098 
0099     struct rfc1042_hdr *new_rfc_pattern =
0100         (struct rfc1042_hdr *)(hdr_80211_pattern + hdr_len);
0101     struct rfc1042_hdr *new_rfc_mask =
0102         (struct rfc1042_hdr *)(hdr_80211_bit_mask + hdr_len);
0103     int rfc_len = sizeof(*new_rfc_pattern);
0104 
0105     memcpy(hdr_8023_pattern + old->pkt_offset,
0106            old->pattern, ETH_HLEN - old->pkt_offset);
0107     memcpy(hdr_8023_bit_mask + old->pkt_offset,
0108            old->mask, ETH_HLEN - old->pkt_offset);
0109 
0110     /* Copy destination address */
0111     memcpy(new_hdr_pattern->addr1, old_hdr_pattern->h_dest, ETH_ALEN);
0112     memcpy(new_hdr_mask->addr1, old_hdr_mask->h_dest, ETH_ALEN);
0113 
0114     /* Copy source address */
0115     memcpy(new_hdr_pattern->addr3, old_hdr_pattern->h_source, ETH_ALEN);
0116     memcpy(new_hdr_mask->addr3, old_hdr_mask->h_source, ETH_ALEN);
0117 
0118     /* Copy logic link type */
0119     memcpy(&new_rfc_pattern->snap_type,
0120            &old_hdr_pattern->h_proto,
0121            sizeof(old_hdr_pattern->h_proto));
0122     memcpy(&new_rfc_mask->snap_type,
0123            &old_hdr_mask->h_proto,
0124            sizeof(old_hdr_mask->h_proto));
0125 
0126     /* Calculate new pkt_offset */
0127     if (old->pkt_offset < ETH_ALEN)
0128         new->pkt_offset = old->pkt_offset +
0129             offsetof(struct ieee80211_hdr_3addr, addr1);
0130     else if (old->pkt_offset < offsetof(struct ethhdr, h_proto))
0131         new->pkt_offset = old->pkt_offset +
0132             offsetof(struct ieee80211_hdr_3addr, addr3) -
0133             offsetof(struct ethhdr, h_source);
0134     else
0135         new->pkt_offset = old->pkt_offset + hdr_len + rfc_len - ETH_HLEN;
0136 
0137     /* Calculate new hdr end offset */
0138     if (total_len > ETH_HLEN)
0139         hdr_80211_end_offset = hdr_len + rfc_len;
0140     else if (total_len > offsetof(struct ethhdr, h_proto))
0141         hdr_80211_end_offset = hdr_len + rfc_len + total_len - ETH_HLEN;
0142     else if (total_len > ETH_ALEN)
0143         hdr_80211_end_offset = total_len - ETH_ALEN +
0144             offsetof(struct ieee80211_hdr_3addr, addr3);
0145     else
0146         hdr_80211_end_offset = total_len +
0147             offsetof(struct ieee80211_hdr_3addr, addr1);
0148 
0149     new->pattern_len = hdr_80211_end_offset - new->pkt_offset;
0150 
0151     memcpy((u8 *)new->pattern,
0152            hdr_80211_pattern + new->pkt_offset,
0153            new->pattern_len);
0154     memcpy((u8 *)new->mask,
0155            hdr_80211_bit_mask + new->pkt_offset,
0156            new->pattern_len);
0157 
0158     if (total_len > ETH_HLEN) {
0159         /* Copy frame body */
0160         memcpy((u8 *)new->pattern + new->pattern_len,
0161                (void *)old->pattern + ETH_HLEN - old->pkt_offset,
0162                total_len - ETH_HLEN);
0163         memcpy((u8 *)new->mask + new->pattern_len,
0164                (void *)old->mask + ETH_HLEN - old->pkt_offset,
0165                total_len - ETH_HLEN);
0166 
0167         new->pattern_len += total_len - ETH_HLEN;
0168     }
0169 }
0170 
0171 static int ath10k_wmi_pno_check(struct ath10k *ar, u32 vdev_id,
0172                 struct cfg80211_sched_scan_request *nd_config,
0173                 struct wmi_pno_scan_req *pno)
0174 {
0175     int i, j, ret = 0;
0176     u8 ssid_len;
0177 
0178     pno->enable = 1;
0179     pno->vdev_id = vdev_id;
0180     pno->uc_networks_count = nd_config->n_match_sets;
0181 
0182     if (!pno->uc_networks_count ||
0183         pno->uc_networks_count > WMI_PNO_MAX_SUPP_NETWORKS)
0184         return -EINVAL;
0185 
0186     if (nd_config->n_channels > WMI_PNO_MAX_NETW_CHANNELS_EX)
0187         return -EINVAL;
0188 
0189     /* Filling per profile  params */
0190     for (i = 0; i < pno->uc_networks_count; i++) {
0191         ssid_len = nd_config->match_sets[i].ssid.ssid_len;
0192 
0193         if (ssid_len == 0 || ssid_len > 32)
0194             return -EINVAL;
0195 
0196         pno->a_networks[i].ssid.ssid_len = __cpu_to_le32(ssid_len);
0197 
0198         memcpy(pno->a_networks[i].ssid.ssid,
0199                nd_config->match_sets[i].ssid.ssid,
0200                nd_config->match_sets[i].ssid.ssid_len);
0201         pno->a_networks[i].authentication = 0;
0202         pno->a_networks[i].encryption     = 0;
0203         pno->a_networks[i].bcast_nw_type  = 0;
0204 
0205         /*Copying list of valid channel into request */
0206         pno->a_networks[i].channel_count = nd_config->n_channels;
0207         pno->a_networks[i].rssi_threshold = nd_config->match_sets[i].rssi_thold;
0208 
0209         for (j = 0; j < nd_config->n_channels; j++) {
0210             pno->a_networks[i].channels[j] =
0211                     nd_config->channels[j]->center_freq;
0212         }
0213     }
0214 
0215     /* set scan to passive if no SSIDs are specified in the request */
0216     if (nd_config->n_ssids == 0)
0217         pno->do_passive_scan = true;
0218     else
0219         pno->do_passive_scan = false;
0220 
0221     for (i = 0; i < nd_config->n_ssids; i++) {
0222         j = 0;
0223         while (j < pno->uc_networks_count) {
0224             if (__le32_to_cpu(pno->a_networks[j].ssid.ssid_len) ==
0225                 nd_config->ssids[i].ssid_len &&
0226             (memcmp(pno->a_networks[j].ssid.ssid,
0227                 nd_config->ssids[i].ssid,
0228                 __le32_to_cpu(pno->a_networks[j].ssid.ssid_len)) == 0)) {
0229                 pno->a_networks[j].bcast_nw_type = BCAST_HIDDEN;
0230                 break;
0231             }
0232             j++;
0233         }
0234     }
0235 
0236     if (nd_config->n_scan_plans == 2) {
0237         pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC;
0238         pno->fast_scan_max_cycles = nd_config->scan_plans[0].iterations;
0239         pno->slow_scan_period =
0240             nd_config->scan_plans[1].interval * MSEC_PER_SEC;
0241     } else if (nd_config->n_scan_plans == 1) {
0242         pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC;
0243         pno->fast_scan_max_cycles = 1;
0244         pno->slow_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC;
0245     } else {
0246         ath10k_warn(ar, "Invalid number of scan plans %d !!",
0247                 nd_config->n_scan_plans);
0248     }
0249 
0250     if (nd_config->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
0251         /* enable mac randomization */
0252         pno->enable_pno_scan_randomization = 1;
0253         memcpy(pno->mac_addr, nd_config->mac_addr, ETH_ALEN);
0254         memcpy(pno->mac_addr_mask, nd_config->mac_addr_mask, ETH_ALEN);
0255     }
0256 
0257     pno->delay_start_time = nd_config->delay;
0258 
0259     /* Current FW does not support min-max range for dwell time */
0260     pno->active_max_time = WMI_ACTIVE_MAX_CHANNEL_TIME;
0261     pno->passive_max_time = WMI_PASSIVE_MAX_CHANNEL_TIME;
0262     return ret;
0263 }
0264 
0265 static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif,
0266                       struct cfg80211_wowlan *wowlan)
0267 {
0268     int ret, i;
0269     unsigned long wow_mask = 0;
0270     struct ath10k *ar = arvif->ar;
0271     const struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
0272     int pattern_id = 0;
0273 
0274     /* Setup requested WOW features */
0275     switch (arvif->vdev_type) {
0276     case WMI_VDEV_TYPE_IBSS:
0277         __set_bit(WOW_BEACON_EVENT, &wow_mask);
0278         fallthrough;
0279     case WMI_VDEV_TYPE_AP:
0280         __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask);
0281         __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask);
0282         __set_bit(WOW_PROBE_REQ_WPS_IE_EVENT, &wow_mask);
0283         __set_bit(WOW_AUTH_REQ_EVENT, &wow_mask);
0284         __set_bit(WOW_ASSOC_REQ_EVENT, &wow_mask);
0285         __set_bit(WOW_HTT_EVENT, &wow_mask);
0286         __set_bit(WOW_RA_MATCH_EVENT, &wow_mask);
0287         break;
0288     case WMI_VDEV_TYPE_STA:
0289         if (wowlan->disconnect) {
0290             __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask);
0291             __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask);
0292             __set_bit(WOW_BMISS_EVENT, &wow_mask);
0293             __set_bit(WOW_CSA_IE_EVENT, &wow_mask);
0294         }
0295 
0296         if (wowlan->magic_pkt)
0297             __set_bit(WOW_MAGIC_PKT_RECVD_EVENT, &wow_mask);
0298 
0299         if (wowlan->nd_config) {
0300             struct wmi_pno_scan_req *pno;
0301             int ret;
0302 
0303             pno = kzalloc(sizeof(*pno), GFP_KERNEL);
0304             if (!pno)
0305                 return -ENOMEM;
0306 
0307             ar->nlo_enabled = true;
0308 
0309             ret = ath10k_wmi_pno_check(ar, arvif->vdev_id,
0310                            wowlan->nd_config, pno);
0311             if (!ret) {
0312                 ath10k_wmi_wow_config_pno(ar, arvif->vdev_id, pno);
0313                 __set_bit(WOW_NLO_DETECTED_EVENT, &wow_mask);
0314             }
0315 
0316             kfree(pno);
0317         }
0318         break;
0319     default:
0320         break;
0321     }
0322 
0323     for (i = 0; i < wowlan->n_patterns; i++) {
0324         u8 bitmask[WOW_MAX_PATTERN_SIZE] = {};
0325         u8 ath_pattern[WOW_MAX_PATTERN_SIZE] = {};
0326         u8 ath_bitmask[WOW_MAX_PATTERN_SIZE] = {};
0327         struct cfg80211_pkt_pattern new_pattern = {};
0328         struct cfg80211_pkt_pattern old_pattern = patterns[i];
0329         int j;
0330 
0331         new_pattern.pattern = ath_pattern;
0332         new_pattern.mask = ath_bitmask;
0333         if (patterns[i].pattern_len > WOW_MAX_PATTERN_SIZE)
0334             continue;
0335         /* convert bytemask to bitmask */
0336         for (j = 0; j < patterns[i].pattern_len; j++)
0337             if (patterns[i].mask[j / 8] & BIT(j % 8))
0338                 bitmask[j] = 0xff;
0339         old_pattern.mask = bitmask;
0340 
0341         if (ar->wmi.rx_decap_mode == ATH10K_HW_TXRX_NATIVE_WIFI) {
0342             if (patterns[i].pkt_offset < ETH_HLEN) {
0343                 ath10k_wow_convert_8023_to_80211(&new_pattern,
0344                                  &old_pattern);
0345             } else {
0346                 new_pattern = old_pattern;
0347                 new_pattern.pkt_offset += WOW_HDR_LEN - ETH_HLEN;
0348             }
0349         }
0350 
0351         if (WARN_ON(new_pattern.pattern_len > WOW_MAX_PATTERN_SIZE))
0352             return -EINVAL;
0353 
0354         ret = ath10k_wmi_wow_add_pattern(ar, arvif->vdev_id,
0355                          pattern_id,
0356                          new_pattern.pattern,
0357                          new_pattern.mask,
0358                          new_pattern.pattern_len,
0359                          new_pattern.pkt_offset);
0360         if (ret) {
0361             ath10k_warn(ar, "failed to add pattern %i to vdev %i: %d\n",
0362                     pattern_id,
0363                     arvif->vdev_id, ret);
0364             return ret;
0365         }
0366 
0367         pattern_id++;
0368         __set_bit(WOW_PATTERN_MATCH_EVENT, &wow_mask);
0369     }
0370 
0371     for (i = 0; i < WOW_EVENT_MAX; i++) {
0372         if (!test_bit(i, &wow_mask))
0373             continue;
0374         ret = ath10k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 1);
0375         if (ret) {
0376             ath10k_warn(ar, "failed to enable wakeup event %s on vdev %i: %d\n",
0377                     wow_wakeup_event(i), arvif->vdev_id, ret);
0378             return ret;
0379         }
0380     }
0381 
0382     return 0;
0383 }
0384 
0385 static int ath10k_wow_set_wakeups(struct ath10k *ar,
0386                   struct cfg80211_wowlan *wowlan)
0387 {
0388     struct ath10k_vif *arvif;
0389     int ret;
0390 
0391     lockdep_assert_held(&ar->conf_mutex);
0392 
0393     list_for_each_entry(arvif, &ar->arvifs, list) {
0394         ret = ath10k_vif_wow_set_wakeups(arvif, wowlan);
0395         if (ret) {
0396             ath10k_warn(ar, "failed to set wow wakeups on vdev %i: %d\n",
0397                     arvif->vdev_id, ret);
0398             return ret;
0399         }
0400     }
0401 
0402     return 0;
0403 }
0404 
0405 static int ath10k_vif_wow_clean_nlo(struct ath10k_vif *arvif)
0406 {
0407     int ret = 0;
0408     struct ath10k *ar = arvif->ar;
0409 
0410     switch (arvif->vdev_type) {
0411     case WMI_VDEV_TYPE_STA:
0412         if (ar->nlo_enabled) {
0413             struct wmi_pno_scan_req *pno;
0414 
0415             pno = kzalloc(sizeof(*pno), GFP_KERNEL);
0416             if (!pno)
0417                 return -ENOMEM;
0418 
0419             pno->enable = 0;
0420             ar->nlo_enabled = false;
0421             ret = ath10k_wmi_wow_config_pno(ar, arvif->vdev_id, pno);
0422             kfree(pno);
0423         }
0424         break;
0425     default:
0426         break;
0427     }
0428     return ret;
0429 }
0430 
0431 static int ath10k_wow_nlo_cleanup(struct ath10k *ar)
0432 {
0433     struct ath10k_vif *arvif;
0434     int ret = 0;
0435 
0436     lockdep_assert_held(&ar->conf_mutex);
0437 
0438     list_for_each_entry(arvif, &ar->arvifs, list) {
0439         ret = ath10k_vif_wow_clean_nlo(arvif);
0440         if (ret) {
0441             ath10k_warn(ar, "failed to clean nlo settings on vdev %i: %d\n",
0442                     arvif->vdev_id, ret);
0443             return ret;
0444         }
0445     }
0446 
0447     return 0;
0448 }
0449 
0450 static int ath10k_wow_enable(struct ath10k *ar)
0451 {
0452     int ret;
0453 
0454     lockdep_assert_held(&ar->conf_mutex);
0455 
0456     reinit_completion(&ar->target_suspend);
0457 
0458     ret = ath10k_wmi_wow_enable(ar);
0459     if (ret) {
0460         ath10k_warn(ar, "failed to issue wow enable: %d\n", ret);
0461         return ret;
0462     }
0463 
0464     ret = wait_for_completion_timeout(&ar->target_suspend, 3 * HZ);
0465     if (ret == 0) {
0466         ath10k_warn(ar, "timed out while waiting for suspend completion\n");
0467         return -ETIMEDOUT;
0468     }
0469 
0470     return 0;
0471 }
0472 
0473 static int ath10k_wow_wakeup(struct ath10k *ar)
0474 {
0475     int ret;
0476 
0477     lockdep_assert_held(&ar->conf_mutex);
0478 
0479     reinit_completion(&ar->wow.wakeup_completed);
0480 
0481     ret = ath10k_wmi_wow_host_wakeup_ind(ar);
0482     if (ret) {
0483         ath10k_warn(ar, "failed to send wow wakeup indication: %d\n",
0484                 ret);
0485         return ret;
0486     }
0487 
0488     ret = wait_for_completion_timeout(&ar->wow.wakeup_completed, 3 * HZ);
0489     if (ret == 0) {
0490         ath10k_warn(ar, "timed out while waiting for wow wakeup completion\n");
0491         return -ETIMEDOUT;
0492     }
0493 
0494     return 0;
0495 }
0496 
0497 int ath10k_wow_op_suspend(struct ieee80211_hw *hw,
0498               struct cfg80211_wowlan *wowlan)
0499 {
0500     struct ath10k *ar = hw->priv;
0501     int ret;
0502 
0503     mutex_lock(&ar->conf_mutex);
0504 
0505     if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
0506                   ar->running_fw->fw_file.fw_features))) {
0507         ret = 1;
0508         goto exit;
0509     }
0510 
0511     ret =  ath10k_wow_cleanup(ar);
0512     if (ret) {
0513         ath10k_warn(ar, "failed to clear wow wakeup events: %d\n",
0514                 ret);
0515         goto exit;
0516     }
0517 
0518     ret = ath10k_wow_set_wakeups(ar, wowlan);
0519     if (ret) {
0520         ath10k_warn(ar, "failed to set wow wakeup events: %d\n",
0521                 ret);
0522         goto cleanup;
0523     }
0524 
0525     ath10k_mac_wait_tx_complete(ar);
0526 
0527     ret = ath10k_wow_enable(ar);
0528     if (ret) {
0529         ath10k_warn(ar, "failed to start wow: %d\n", ret);
0530         goto cleanup;
0531     }
0532 
0533     ret = ath10k_hif_suspend(ar);
0534     if (ret) {
0535         ath10k_warn(ar, "failed to suspend hif: %d\n", ret);
0536         goto wakeup;
0537     }
0538 
0539     goto exit;
0540 
0541 wakeup:
0542     ath10k_wow_wakeup(ar);
0543 
0544 cleanup:
0545     ath10k_wow_cleanup(ar);
0546 
0547 exit:
0548     mutex_unlock(&ar->conf_mutex);
0549     return ret ? 1 : 0;
0550 }
0551 
0552 void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled)
0553 {
0554     struct ath10k *ar = hw->priv;
0555 
0556     mutex_lock(&ar->conf_mutex);
0557     if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
0558              ar->running_fw->fw_file.fw_features)) {
0559         device_set_wakeup_enable(ar->dev, enabled);
0560     }
0561     mutex_unlock(&ar->conf_mutex);
0562 }
0563 
0564 int ath10k_wow_op_resume(struct ieee80211_hw *hw)
0565 {
0566     struct ath10k *ar = hw->priv;
0567     int ret;
0568 
0569     mutex_lock(&ar->conf_mutex);
0570 
0571     if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
0572                   ar->running_fw->fw_file.fw_features))) {
0573         ret = 1;
0574         goto exit;
0575     }
0576 
0577     ret = ath10k_hif_resume(ar);
0578     if (ret) {
0579         ath10k_warn(ar, "failed to resume hif: %d\n", ret);
0580         goto exit;
0581     }
0582 
0583     ret = ath10k_wow_wakeup(ar);
0584     if (ret)
0585         ath10k_warn(ar, "failed to wakeup from wow: %d\n", ret);
0586 
0587     ret = ath10k_wow_nlo_cleanup(ar);
0588     if (ret)
0589         ath10k_warn(ar, "failed to cleanup nlo: %d\n", ret);
0590 
0591 exit:
0592     if (ret) {
0593         switch (ar->state) {
0594         case ATH10K_STATE_ON:
0595             ar->state = ATH10K_STATE_RESTARTING;
0596             ret = 1;
0597             break;
0598         case ATH10K_STATE_OFF:
0599         case ATH10K_STATE_RESTARTING:
0600         case ATH10K_STATE_RESTARTED:
0601         case ATH10K_STATE_UTF:
0602         case ATH10K_STATE_WEDGED:
0603             ath10k_warn(ar, "encountered unexpected device state %d on resume, cannot recover\n",
0604                     ar->state);
0605             ret = -EIO;
0606             break;
0607         }
0608     }
0609 
0610     mutex_unlock(&ar->conf_mutex);
0611     return ret;
0612 }
0613 
0614 int ath10k_wow_init(struct ath10k *ar)
0615 {
0616     if (!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
0617               ar->running_fw->fw_file.fw_features))
0618         return 0;
0619 
0620     if (WARN_ON(!test_bit(WMI_SERVICE_WOW, ar->wmi.svc_map)))
0621         return -EINVAL;
0622 
0623     ar->wow.wowlan_support = ath10k_wowlan_support;
0624 
0625     if (ar->wmi.rx_decap_mode == ATH10K_HW_TXRX_NATIVE_WIFI) {
0626         ar->wow.wowlan_support.pattern_max_len -= WOW_MAX_REDUCE;
0627         ar->wow.wowlan_support.max_pkt_offset -= WOW_MAX_REDUCE;
0628     }
0629 
0630     if (test_bit(WMI_SERVICE_NLO, ar->wmi.svc_map)) {
0631         ar->wow.wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT;
0632         ar->wow.wowlan_support.max_nd_match_sets = WMI_PNO_MAX_SUPP_NETWORKS;
0633     }
0634 
0635     ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns;
0636     ar->hw->wiphy->wowlan = &ar->wow.wowlan_support;
0637 
0638     device_set_wakeup_capable(ar->dev, true);
0639 
0640     return 0;
0641 }