15fd3ac3cSJanusz Dziedzic /* 2*8b1083d6SKalle Valo * Copyright (c) 2015-2017 Qualcomm Atheros, Inc. 35fd3ac3cSJanusz Dziedzic * 45fd3ac3cSJanusz Dziedzic * Permission to use, copy, modify, and/or distribute this software for any 55fd3ac3cSJanusz Dziedzic * purpose with or without fee is hereby granted, provided that the above 65fd3ac3cSJanusz Dziedzic * copyright notice and this permission notice appear in all copies. 75fd3ac3cSJanusz Dziedzic * 85fd3ac3cSJanusz Dziedzic * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 95fd3ac3cSJanusz Dziedzic * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 105fd3ac3cSJanusz Dziedzic * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 115fd3ac3cSJanusz Dziedzic * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 125fd3ac3cSJanusz Dziedzic * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 135fd3ac3cSJanusz Dziedzic * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 145fd3ac3cSJanusz Dziedzic * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 155fd3ac3cSJanusz Dziedzic */ 165fd3ac3cSJanusz Dziedzic 175fd3ac3cSJanusz Dziedzic #include "mac.h" 185fd3ac3cSJanusz Dziedzic 195fd3ac3cSJanusz Dziedzic #include <net/mac80211.h> 205fd3ac3cSJanusz Dziedzic #include "hif.h" 215fd3ac3cSJanusz Dziedzic #include "core.h" 225fd3ac3cSJanusz Dziedzic #include "debug.h" 235fd3ac3cSJanusz Dziedzic #include "wmi.h" 245fd3ac3cSJanusz Dziedzic #include "wmi-ops.h" 255fd3ac3cSJanusz Dziedzic 265fd3ac3cSJanusz Dziedzic static const struct wiphy_wowlan_support ath10k_wowlan_support = { 275fd3ac3cSJanusz Dziedzic .flags = WIPHY_WOWLAN_DISCONNECT | 285fd3ac3cSJanusz Dziedzic WIPHY_WOWLAN_MAGIC_PKT, 2925c86619SJanusz Dziedzic .pattern_min_len = WOW_MIN_PATTERN_SIZE, 3025c86619SJanusz Dziedzic .pattern_max_len = WOW_MAX_PATTERN_SIZE, 3125c86619SJanusz Dziedzic .max_pkt_offset = WOW_MAX_PKT_OFFSET, 325fd3ac3cSJanusz Dziedzic }; 335fd3ac3cSJanusz Dziedzic 345fd3ac3cSJanusz Dziedzic static int ath10k_wow_vif_cleanup(struct ath10k_vif *arvif) 355fd3ac3cSJanusz Dziedzic { 365fd3ac3cSJanusz Dziedzic struct ath10k *ar = arvif->ar; 375fd3ac3cSJanusz Dziedzic int i, ret; 385fd3ac3cSJanusz Dziedzic 395fd3ac3cSJanusz Dziedzic for (i = 0; i < WOW_EVENT_MAX; i++) { 405fd3ac3cSJanusz Dziedzic ret = ath10k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 0); 415fd3ac3cSJanusz Dziedzic if (ret) { 425fd3ac3cSJanusz Dziedzic ath10k_warn(ar, "failed to issue wow wakeup for event %s on vdev %i: %d\n", 435fd3ac3cSJanusz Dziedzic wow_wakeup_event(i), arvif->vdev_id, ret); 445fd3ac3cSJanusz Dziedzic return ret; 455fd3ac3cSJanusz Dziedzic } 465fd3ac3cSJanusz Dziedzic } 475fd3ac3cSJanusz Dziedzic 4825c86619SJanusz Dziedzic for (i = 0; i < ar->wow.max_num_patterns; i++) { 4925c86619SJanusz Dziedzic ret = ath10k_wmi_wow_del_pattern(ar, arvif->vdev_id, i); 5025c86619SJanusz Dziedzic if (ret) { 5125c86619SJanusz Dziedzic ath10k_warn(ar, "failed to delete wow pattern %d for vdev %i: %d\n", 5225c86619SJanusz Dziedzic i, arvif->vdev_id, ret); 5325c86619SJanusz Dziedzic return ret; 5425c86619SJanusz Dziedzic } 5525c86619SJanusz Dziedzic } 5625c86619SJanusz Dziedzic 575fd3ac3cSJanusz Dziedzic return 0; 585fd3ac3cSJanusz Dziedzic } 595fd3ac3cSJanusz Dziedzic 605fd3ac3cSJanusz Dziedzic static int ath10k_wow_cleanup(struct ath10k *ar) 615fd3ac3cSJanusz Dziedzic { 625fd3ac3cSJanusz Dziedzic struct ath10k_vif *arvif; 635fd3ac3cSJanusz Dziedzic int ret; 645fd3ac3cSJanusz Dziedzic 655fd3ac3cSJanusz Dziedzic lockdep_assert_held(&ar->conf_mutex); 665fd3ac3cSJanusz Dziedzic 675fd3ac3cSJanusz Dziedzic list_for_each_entry(arvif, &ar->arvifs, list) { 685fd3ac3cSJanusz Dziedzic ret = ath10k_wow_vif_cleanup(arvif); 695fd3ac3cSJanusz Dziedzic if (ret) { 705fd3ac3cSJanusz Dziedzic ath10k_warn(ar, "failed to clean wow wakeups on vdev %i: %d\n", 715fd3ac3cSJanusz Dziedzic arvif->vdev_id, ret); 725fd3ac3cSJanusz Dziedzic return ret; 735fd3ac3cSJanusz Dziedzic } 745fd3ac3cSJanusz Dziedzic } 755fd3ac3cSJanusz Dziedzic 765fd3ac3cSJanusz Dziedzic return 0; 775fd3ac3cSJanusz Dziedzic } 785fd3ac3cSJanusz Dziedzic 795fd3ac3cSJanusz Dziedzic static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif, 805fd3ac3cSJanusz Dziedzic struct cfg80211_wowlan *wowlan) 815fd3ac3cSJanusz Dziedzic { 825fd3ac3cSJanusz Dziedzic int ret, i; 835fd3ac3cSJanusz Dziedzic unsigned long wow_mask = 0; 845fd3ac3cSJanusz Dziedzic struct ath10k *ar = arvif->ar; 8525c86619SJanusz Dziedzic const struct cfg80211_pkt_pattern *patterns = wowlan->patterns; 8625c86619SJanusz Dziedzic int pattern_id = 0; 875fd3ac3cSJanusz Dziedzic 885fd3ac3cSJanusz Dziedzic /* Setup requested WOW features */ 895fd3ac3cSJanusz Dziedzic switch (arvif->vdev_type) { 905fd3ac3cSJanusz Dziedzic case WMI_VDEV_TYPE_IBSS: 915fd3ac3cSJanusz Dziedzic __set_bit(WOW_BEACON_EVENT, &wow_mask); 925fd3ac3cSJanusz Dziedzic /* fall through */ 935fd3ac3cSJanusz Dziedzic case WMI_VDEV_TYPE_AP: 945fd3ac3cSJanusz Dziedzic __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask); 955fd3ac3cSJanusz Dziedzic __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask); 965fd3ac3cSJanusz Dziedzic __set_bit(WOW_PROBE_REQ_WPS_IE_EVENT, &wow_mask); 975fd3ac3cSJanusz Dziedzic __set_bit(WOW_AUTH_REQ_EVENT, &wow_mask); 985fd3ac3cSJanusz Dziedzic __set_bit(WOW_ASSOC_REQ_EVENT, &wow_mask); 995fd3ac3cSJanusz Dziedzic __set_bit(WOW_HTT_EVENT, &wow_mask); 1005fd3ac3cSJanusz Dziedzic __set_bit(WOW_RA_MATCH_EVENT, &wow_mask); 1015fd3ac3cSJanusz Dziedzic break; 1025fd3ac3cSJanusz Dziedzic case WMI_VDEV_TYPE_STA: 1035fd3ac3cSJanusz Dziedzic if (wowlan->disconnect) { 1045fd3ac3cSJanusz Dziedzic __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask); 1055fd3ac3cSJanusz Dziedzic __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask); 1065fd3ac3cSJanusz Dziedzic __set_bit(WOW_BMISS_EVENT, &wow_mask); 1075fd3ac3cSJanusz Dziedzic __set_bit(WOW_CSA_IE_EVENT, &wow_mask); 1085fd3ac3cSJanusz Dziedzic } 1095fd3ac3cSJanusz Dziedzic 1105fd3ac3cSJanusz Dziedzic if (wowlan->magic_pkt) 1115fd3ac3cSJanusz Dziedzic __set_bit(WOW_MAGIC_PKT_RECVD_EVENT, &wow_mask); 1125fd3ac3cSJanusz Dziedzic break; 1135fd3ac3cSJanusz Dziedzic default: 1145fd3ac3cSJanusz Dziedzic break; 1155fd3ac3cSJanusz Dziedzic } 1165fd3ac3cSJanusz Dziedzic 11725c86619SJanusz Dziedzic for (i = 0; i < wowlan->n_patterns; i++) { 11825c86619SJanusz Dziedzic u8 bitmask[WOW_MAX_PATTERN_SIZE] = {}; 11925c86619SJanusz Dziedzic int j; 12025c86619SJanusz Dziedzic 12125c86619SJanusz Dziedzic if (patterns[i].pattern_len > WOW_MAX_PATTERN_SIZE) 12225c86619SJanusz Dziedzic continue; 12325c86619SJanusz Dziedzic 12425c86619SJanusz Dziedzic /* convert bytemask to bitmask */ 12525c86619SJanusz Dziedzic for (j = 0; j < patterns[i].pattern_len; j++) 12625c86619SJanusz Dziedzic if (patterns[i].mask[j / 8] & BIT(j % 8)) 12725c86619SJanusz Dziedzic bitmask[j] = 0xff; 12825c86619SJanusz Dziedzic 12925c86619SJanusz Dziedzic ret = ath10k_wmi_wow_add_pattern(ar, arvif->vdev_id, 13025c86619SJanusz Dziedzic pattern_id, 13125c86619SJanusz Dziedzic patterns[i].pattern, 13225c86619SJanusz Dziedzic bitmask, 13325c86619SJanusz Dziedzic patterns[i].pattern_len, 13425c86619SJanusz Dziedzic patterns[i].pkt_offset); 13525c86619SJanusz Dziedzic if (ret) { 13625c86619SJanusz Dziedzic ath10k_warn(ar, "failed to add pattern %i to vdev %i: %d\n", 13725c86619SJanusz Dziedzic pattern_id, 13825c86619SJanusz Dziedzic arvif->vdev_id, ret); 13925c86619SJanusz Dziedzic return ret; 14025c86619SJanusz Dziedzic } 14125c86619SJanusz Dziedzic 14225c86619SJanusz Dziedzic pattern_id++; 14325c86619SJanusz Dziedzic __set_bit(WOW_PATTERN_MATCH_EVENT, &wow_mask); 14425c86619SJanusz Dziedzic } 14525c86619SJanusz Dziedzic 1465fd3ac3cSJanusz Dziedzic for (i = 0; i < WOW_EVENT_MAX; i++) { 1475fd3ac3cSJanusz Dziedzic if (!test_bit(i, &wow_mask)) 1485fd3ac3cSJanusz Dziedzic continue; 1495fd3ac3cSJanusz Dziedzic ret = ath10k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 1); 1505fd3ac3cSJanusz Dziedzic if (ret) { 1515fd3ac3cSJanusz Dziedzic ath10k_warn(ar, "failed to enable wakeup event %s on vdev %i: %d\n", 1525fd3ac3cSJanusz Dziedzic wow_wakeup_event(i), arvif->vdev_id, ret); 1535fd3ac3cSJanusz Dziedzic return ret; 1545fd3ac3cSJanusz Dziedzic } 1555fd3ac3cSJanusz Dziedzic } 1565fd3ac3cSJanusz Dziedzic 1575fd3ac3cSJanusz Dziedzic return 0; 1585fd3ac3cSJanusz Dziedzic } 1595fd3ac3cSJanusz Dziedzic 1605fd3ac3cSJanusz Dziedzic static int ath10k_wow_set_wakeups(struct ath10k *ar, 1615fd3ac3cSJanusz Dziedzic struct cfg80211_wowlan *wowlan) 1625fd3ac3cSJanusz Dziedzic { 1635fd3ac3cSJanusz Dziedzic struct ath10k_vif *arvif; 1645fd3ac3cSJanusz Dziedzic int ret; 1655fd3ac3cSJanusz Dziedzic 1665fd3ac3cSJanusz Dziedzic lockdep_assert_held(&ar->conf_mutex); 1675fd3ac3cSJanusz Dziedzic 1685fd3ac3cSJanusz Dziedzic list_for_each_entry(arvif, &ar->arvifs, list) { 1695fd3ac3cSJanusz Dziedzic ret = ath10k_vif_wow_set_wakeups(arvif, wowlan); 1705fd3ac3cSJanusz Dziedzic if (ret) { 1715fd3ac3cSJanusz Dziedzic ath10k_warn(ar, "failed to set wow wakeups on vdev %i: %d\n", 1725fd3ac3cSJanusz Dziedzic arvif->vdev_id, ret); 1735fd3ac3cSJanusz Dziedzic return ret; 1745fd3ac3cSJanusz Dziedzic } 1755fd3ac3cSJanusz Dziedzic } 1765fd3ac3cSJanusz Dziedzic 1775fd3ac3cSJanusz Dziedzic return 0; 1785fd3ac3cSJanusz Dziedzic } 1795fd3ac3cSJanusz Dziedzic 1805fd3ac3cSJanusz Dziedzic static int ath10k_wow_enable(struct ath10k *ar) 1815fd3ac3cSJanusz Dziedzic { 1825fd3ac3cSJanusz Dziedzic int ret; 1835fd3ac3cSJanusz Dziedzic 1845fd3ac3cSJanusz Dziedzic lockdep_assert_held(&ar->conf_mutex); 1855fd3ac3cSJanusz Dziedzic 1865fd3ac3cSJanusz Dziedzic reinit_completion(&ar->target_suspend); 1875fd3ac3cSJanusz Dziedzic 1885fd3ac3cSJanusz Dziedzic ret = ath10k_wmi_wow_enable(ar); 1895fd3ac3cSJanusz Dziedzic if (ret) { 1905fd3ac3cSJanusz Dziedzic ath10k_warn(ar, "failed to issue wow enable: %d\n", ret); 1915fd3ac3cSJanusz Dziedzic return ret; 1925fd3ac3cSJanusz Dziedzic } 1935fd3ac3cSJanusz Dziedzic 1945fd3ac3cSJanusz Dziedzic ret = wait_for_completion_timeout(&ar->target_suspend, 3 * HZ); 1955fd3ac3cSJanusz Dziedzic if (ret == 0) { 1965fd3ac3cSJanusz Dziedzic ath10k_warn(ar, "timed out while waiting for suspend completion\n"); 1975fd3ac3cSJanusz Dziedzic return -ETIMEDOUT; 1985fd3ac3cSJanusz Dziedzic } 1995fd3ac3cSJanusz Dziedzic 2005fd3ac3cSJanusz Dziedzic return 0; 2015fd3ac3cSJanusz Dziedzic } 2025fd3ac3cSJanusz Dziedzic 2035fd3ac3cSJanusz Dziedzic static int ath10k_wow_wakeup(struct ath10k *ar) 2045fd3ac3cSJanusz Dziedzic { 2055fd3ac3cSJanusz Dziedzic int ret; 2065fd3ac3cSJanusz Dziedzic 2075fd3ac3cSJanusz Dziedzic lockdep_assert_held(&ar->conf_mutex); 2085fd3ac3cSJanusz Dziedzic 2095fd3ac3cSJanusz Dziedzic reinit_completion(&ar->wow.wakeup_completed); 2105fd3ac3cSJanusz Dziedzic 2115fd3ac3cSJanusz Dziedzic ret = ath10k_wmi_wow_host_wakeup_ind(ar); 2125fd3ac3cSJanusz Dziedzic if (ret) { 2135fd3ac3cSJanusz Dziedzic ath10k_warn(ar, "failed to send wow wakeup indication: %d\n", 2145fd3ac3cSJanusz Dziedzic ret); 2155fd3ac3cSJanusz Dziedzic return ret; 2165fd3ac3cSJanusz Dziedzic } 2175fd3ac3cSJanusz Dziedzic 2185fd3ac3cSJanusz Dziedzic ret = wait_for_completion_timeout(&ar->wow.wakeup_completed, 3 * HZ); 2195fd3ac3cSJanusz Dziedzic if (ret == 0) { 2205fd3ac3cSJanusz Dziedzic ath10k_warn(ar, "timed out while waiting for wow wakeup completion\n"); 2215fd3ac3cSJanusz Dziedzic return -ETIMEDOUT; 2225fd3ac3cSJanusz Dziedzic } 2235fd3ac3cSJanusz Dziedzic 2245fd3ac3cSJanusz Dziedzic return 0; 2255fd3ac3cSJanusz Dziedzic } 2265fd3ac3cSJanusz Dziedzic 2275fd3ac3cSJanusz Dziedzic int ath10k_wow_op_suspend(struct ieee80211_hw *hw, 2285fd3ac3cSJanusz Dziedzic struct cfg80211_wowlan *wowlan) 2295fd3ac3cSJanusz Dziedzic { 2305fd3ac3cSJanusz Dziedzic struct ath10k *ar = hw->priv; 2315fd3ac3cSJanusz Dziedzic int ret; 2325fd3ac3cSJanusz Dziedzic 2335fd3ac3cSJanusz Dziedzic mutex_lock(&ar->conf_mutex); 2345fd3ac3cSJanusz Dziedzic 2355fd3ac3cSJanusz Dziedzic if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, 236c4cdf753SKalle Valo ar->running_fw->fw_file.fw_features))) { 2375fd3ac3cSJanusz Dziedzic ret = 1; 2385fd3ac3cSJanusz Dziedzic goto exit; 2395fd3ac3cSJanusz Dziedzic } 2405fd3ac3cSJanusz Dziedzic 2415fd3ac3cSJanusz Dziedzic ret = ath10k_wow_cleanup(ar); 2425fd3ac3cSJanusz Dziedzic if (ret) { 2435fd3ac3cSJanusz Dziedzic ath10k_warn(ar, "failed to clear wow wakeup events: %d\n", 2445fd3ac3cSJanusz Dziedzic ret); 2455fd3ac3cSJanusz Dziedzic goto exit; 2465fd3ac3cSJanusz Dziedzic } 2475fd3ac3cSJanusz Dziedzic 2485fd3ac3cSJanusz Dziedzic ret = ath10k_wow_set_wakeups(ar, wowlan); 2495fd3ac3cSJanusz Dziedzic if (ret) { 2505fd3ac3cSJanusz Dziedzic ath10k_warn(ar, "failed to set wow wakeup events: %d\n", 2515fd3ac3cSJanusz Dziedzic ret); 2525fd3ac3cSJanusz Dziedzic goto cleanup; 2535fd3ac3cSJanusz Dziedzic } 2545fd3ac3cSJanusz Dziedzic 2555fd3ac3cSJanusz Dziedzic ret = ath10k_wow_enable(ar); 2565fd3ac3cSJanusz Dziedzic if (ret) { 2575fd3ac3cSJanusz Dziedzic ath10k_warn(ar, "failed to start wow: %d\n", ret); 2585fd3ac3cSJanusz Dziedzic goto cleanup; 2595fd3ac3cSJanusz Dziedzic } 2605fd3ac3cSJanusz Dziedzic 2615fd3ac3cSJanusz Dziedzic ret = ath10k_hif_suspend(ar); 2625fd3ac3cSJanusz Dziedzic if (ret) { 2635fd3ac3cSJanusz Dziedzic ath10k_warn(ar, "failed to suspend hif: %d\n", ret); 2645fd3ac3cSJanusz Dziedzic goto wakeup; 2655fd3ac3cSJanusz Dziedzic } 2665fd3ac3cSJanusz Dziedzic 2675fd3ac3cSJanusz Dziedzic goto exit; 2685fd3ac3cSJanusz Dziedzic 2695fd3ac3cSJanusz Dziedzic wakeup: 2705fd3ac3cSJanusz Dziedzic ath10k_wow_wakeup(ar); 2715fd3ac3cSJanusz Dziedzic 2725fd3ac3cSJanusz Dziedzic cleanup: 2735fd3ac3cSJanusz Dziedzic ath10k_wow_cleanup(ar); 2745fd3ac3cSJanusz Dziedzic 2755fd3ac3cSJanusz Dziedzic exit: 2765fd3ac3cSJanusz Dziedzic mutex_unlock(&ar->conf_mutex); 2775fd3ac3cSJanusz Dziedzic return ret ? 1 : 0; 2785fd3ac3cSJanusz Dziedzic } 2795fd3ac3cSJanusz Dziedzic 280393b706cSRyan Hsu void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled) 281393b706cSRyan Hsu { 282393b706cSRyan Hsu struct ath10k *ar = hw->priv; 283393b706cSRyan Hsu 284393b706cSRyan Hsu mutex_lock(&ar->conf_mutex); 285393b706cSRyan Hsu if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, 286393b706cSRyan Hsu ar->running_fw->fw_file.fw_features)) { 287393b706cSRyan Hsu device_set_wakeup_enable(ar->dev, enabled); 288393b706cSRyan Hsu } 289393b706cSRyan Hsu mutex_unlock(&ar->conf_mutex); 290393b706cSRyan Hsu } 291393b706cSRyan Hsu 2925fd3ac3cSJanusz Dziedzic int ath10k_wow_op_resume(struct ieee80211_hw *hw) 2935fd3ac3cSJanusz Dziedzic { 2945fd3ac3cSJanusz Dziedzic struct ath10k *ar = hw->priv; 2955fd3ac3cSJanusz Dziedzic int ret; 2965fd3ac3cSJanusz Dziedzic 2975fd3ac3cSJanusz Dziedzic mutex_lock(&ar->conf_mutex); 2985fd3ac3cSJanusz Dziedzic 2995fd3ac3cSJanusz Dziedzic if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, 300c4cdf753SKalle Valo ar->running_fw->fw_file.fw_features))) { 3015fd3ac3cSJanusz Dziedzic ret = 1; 3025fd3ac3cSJanusz Dziedzic goto exit; 3035fd3ac3cSJanusz Dziedzic } 3045fd3ac3cSJanusz Dziedzic 3055fd3ac3cSJanusz Dziedzic ret = ath10k_hif_resume(ar); 3065fd3ac3cSJanusz Dziedzic if (ret) { 3075fd3ac3cSJanusz Dziedzic ath10k_warn(ar, "failed to resume hif: %d\n", ret); 3085fd3ac3cSJanusz Dziedzic goto exit; 3095fd3ac3cSJanusz Dziedzic } 3105fd3ac3cSJanusz Dziedzic 3115fd3ac3cSJanusz Dziedzic ret = ath10k_wow_wakeup(ar); 3125fd3ac3cSJanusz Dziedzic if (ret) 3135fd3ac3cSJanusz Dziedzic ath10k_warn(ar, "failed to wakeup from wow: %d\n", ret); 3145fd3ac3cSJanusz Dziedzic 3155fd3ac3cSJanusz Dziedzic exit: 3166f7429c2SMichal Kazior if (ret) { 3176f7429c2SMichal Kazior switch (ar->state) { 3186f7429c2SMichal Kazior case ATH10K_STATE_ON: 3196f7429c2SMichal Kazior ar->state = ATH10K_STATE_RESTARTING; 3206f7429c2SMichal Kazior ret = 1; 3216f7429c2SMichal Kazior break; 3226f7429c2SMichal Kazior case ATH10K_STATE_OFF: 3236f7429c2SMichal Kazior case ATH10K_STATE_RESTARTING: 3246f7429c2SMichal Kazior case ATH10K_STATE_RESTARTED: 3256f7429c2SMichal Kazior case ATH10K_STATE_UTF: 3266f7429c2SMichal Kazior case ATH10K_STATE_WEDGED: 3276f7429c2SMichal Kazior ath10k_warn(ar, "encountered unexpected device state %d on resume, cannot recover\n", 3286f7429c2SMichal Kazior ar->state); 3296f7429c2SMichal Kazior ret = -EIO; 3306f7429c2SMichal Kazior break; 3316f7429c2SMichal Kazior } 3326f7429c2SMichal Kazior } 3336f7429c2SMichal Kazior 3345fd3ac3cSJanusz Dziedzic mutex_unlock(&ar->conf_mutex); 3356f7429c2SMichal Kazior return ret; 3365fd3ac3cSJanusz Dziedzic } 3375fd3ac3cSJanusz Dziedzic 3385fd3ac3cSJanusz Dziedzic int ath10k_wow_init(struct ath10k *ar) 3395fd3ac3cSJanusz Dziedzic { 340c4cdf753SKalle Valo if (!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, 341c4cdf753SKalle Valo ar->running_fw->fw_file.fw_features)) 3425fd3ac3cSJanusz Dziedzic return 0; 3435fd3ac3cSJanusz Dziedzic 3445fd3ac3cSJanusz Dziedzic if (WARN_ON(!test_bit(WMI_SERVICE_WOW, ar->wmi.svc_map))) 3455fd3ac3cSJanusz Dziedzic return -EINVAL; 3465fd3ac3cSJanusz Dziedzic 34725c86619SJanusz Dziedzic ar->wow.wowlan_support = ath10k_wowlan_support; 34825c86619SJanusz Dziedzic ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns; 34925c86619SJanusz Dziedzic ar->hw->wiphy->wowlan = &ar->wow.wowlan_support; 3505fd3ac3cSJanusz Dziedzic 351393b706cSRyan Hsu device_set_wakeup_capable(ar->dev, true); 352393b706cSRyan Hsu 3535fd3ac3cSJanusz Dziedzic return 0; 3545fd3ac3cSJanusz Dziedzic } 355