xref: /linux/drivers/net/wireless/ath/ath9k/wow.c (revision e5451c8f8330e03ad3cfa16048b4daf961af434f)
1e60001e7SSujith Manoharan /*
2e60001e7SSujith Manoharan  * Copyright (c) 2013 Qualcomm Atheros, Inc.
3e60001e7SSujith Manoharan  *
4e60001e7SSujith Manoharan  * Permission to use, copy, modify, and/or distribute this software for any
5e60001e7SSujith Manoharan  * purpose with or without fee is hereby granted, provided that the above
6e60001e7SSujith Manoharan  * copyright notice and this permission notice appear in all copies.
7e60001e7SSujith Manoharan  *
8e60001e7SSujith Manoharan  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9e60001e7SSujith Manoharan  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10e60001e7SSujith Manoharan  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11e60001e7SSujith Manoharan  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12e60001e7SSujith Manoharan  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13e60001e7SSujith Manoharan  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14e60001e7SSujith Manoharan  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15e60001e7SSujith Manoharan  */
16e60001e7SSujith Manoharan 
17e60001e7SSujith Manoharan #include "ath9k.h"
18e60001e7SSujith Manoharan 
19*e68e9c10SSujith Manoharan static const struct wiphy_wowlan_support ath9k_wowlan_support_legacy = {
20babaa80aSSujith Manoharan 	.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
21babaa80aSSujith Manoharan 	.n_patterns = MAX_NUM_USER_PATTERN,
22babaa80aSSujith Manoharan 	.pattern_min_len = 1,
23babaa80aSSujith Manoharan 	.pattern_max_len = MAX_PATTERN_SIZE,
24babaa80aSSujith Manoharan };
25babaa80aSSujith Manoharan 
26*e68e9c10SSujith Manoharan static const struct wiphy_wowlan_support ath9k_wowlan_support = {
27*e68e9c10SSujith Manoharan 	.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
28*e68e9c10SSujith Manoharan 	.n_patterns = MAX_NUM_PATTERN - 2,
29*e68e9c10SSujith Manoharan 	.pattern_min_len = 1,
30*e68e9c10SSujith Manoharan 	.pattern_max_len = MAX_PATTERN_SIZE,
31*e68e9c10SSujith Manoharan };
32*e68e9c10SSujith Manoharan 
33249943a2SSujith Manoharan static u8 ath9k_wow_map_triggers(struct ath_softc *sc,
34249943a2SSujith Manoharan 				 struct cfg80211_wowlan *wowlan)
35e60001e7SSujith Manoharan {
36249943a2SSujith Manoharan 	u8 wow_triggers = 0;
37249943a2SSujith Manoharan 
38e60001e7SSujith Manoharan 	if (wowlan->disconnect)
39249943a2SSujith Manoharan 		wow_triggers |= AH_WOW_LINK_CHANGE |
40e60001e7SSujith Manoharan 				AH_WOW_BEACON_MISS;
41e60001e7SSujith Manoharan 	if (wowlan->magic_pkt)
42249943a2SSujith Manoharan 		wow_triggers |= AH_WOW_MAGIC_PATTERN_EN;
43e60001e7SSujith Manoharan 
44e60001e7SSujith Manoharan 	if (wowlan->n_patterns)
45249943a2SSujith Manoharan 		wow_triggers |= AH_WOW_USER_PATTERN_EN;
46e60001e7SSujith Manoharan 
47249943a2SSujith Manoharan 	return wow_triggers;
48e60001e7SSujith Manoharan }
49e60001e7SSujith Manoharan 
506af75e4dSSujith Manoharan static int ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
51e60001e7SSujith Manoharan {
52e60001e7SSujith Manoharan 	struct ath_hw *ah = sc->sc_ah;
53e60001e7SSujith Manoharan 	struct ath_common *common = ath9k_hw_common(ah);
54e60001e7SSujith Manoharan 	int pattern_count = 0;
556af75e4dSSujith Manoharan 	int ret, i, byte_cnt = 0;
56e60001e7SSujith Manoharan 	u8 dis_deauth_pattern[MAX_PATTERN_SIZE];
57e60001e7SSujith Manoharan 	u8 dis_deauth_mask[MAX_PATTERN_SIZE];
58e60001e7SSujith Manoharan 
59e60001e7SSujith Manoharan 	memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE);
60e60001e7SSujith Manoharan 	memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE);
61e60001e7SSujith Manoharan 
62e60001e7SSujith Manoharan 	/*
63e60001e7SSujith Manoharan 	 * Create Dissassociate / Deauthenticate packet filter
64e60001e7SSujith Manoharan 	 *
65e60001e7SSujith Manoharan 	 *     2 bytes        2 byte    6 bytes   6 bytes  6 bytes
66e60001e7SSujith Manoharan 	 *  +--------------+----------+---------+--------+--------+----
67e60001e7SSujith Manoharan 	 *  + Frame Control+ Duration +   DA    +  SA    +  BSSID +
68e60001e7SSujith Manoharan 	 *  +--------------+----------+---------+--------+--------+----
69e60001e7SSujith Manoharan 	 *
70e60001e7SSujith Manoharan 	 * The above is the management frame format for disassociate/
71e60001e7SSujith Manoharan 	 * deauthenticate pattern, from this we need to match the first byte
72e60001e7SSujith Manoharan 	 * of 'Frame Control' and DA, SA, and BSSID fields
73e60001e7SSujith Manoharan 	 * (skipping 2nd byte of FC and Duration feild.
74e60001e7SSujith Manoharan 	 *
75e60001e7SSujith Manoharan 	 * Disassociate pattern
76e60001e7SSujith Manoharan 	 * --------------------
77e60001e7SSujith Manoharan 	 * Frame control = 00 00 1010
78e60001e7SSujith Manoharan 	 * DA, SA, BSSID = x:x:x:x:x:x
79e60001e7SSujith Manoharan 	 * Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x
80e60001e7SSujith Manoharan 	 *			    | x:x:x:x:x:x  -- 22 bytes
81e60001e7SSujith Manoharan 	 *
82e60001e7SSujith Manoharan 	 * Deauthenticate pattern
83e60001e7SSujith Manoharan 	 * ----------------------
84e60001e7SSujith Manoharan 	 * Frame control = 00 00 1100
85e60001e7SSujith Manoharan 	 * DA, SA, BSSID = x:x:x:x:x:x
86e60001e7SSujith Manoharan 	 * Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x
87e60001e7SSujith Manoharan 	 *			    | x:x:x:x:x:x  -- 22 bytes
88e60001e7SSujith Manoharan 	 */
89e60001e7SSujith Manoharan 
90e60001e7SSujith Manoharan 	/* Fill out the mask with all FF's */
91e60001e7SSujith Manoharan 	for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++)
92e60001e7SSujith Manoharan 		dis_deauth_mask[i] = 0xff;
93e60001e7SSujith Manoharan 
94e60001e7SSujith Manoharan 	/* copy the first byte of frame control field */
95e60001e7SSujith Manoharan 	dis_deauth_pattern[byte_cnt] = 0xa0;
96e60001e7SSujith Manoharan 	byte_cnt++;
97e60001e7SSujith Manoharan 
98e60001e7SSujith Manoharan 	/* skip 2nd byte of frame control and Duration field */
99e60001e7SSujith Manoharan 	byte_cnt += 3;
100e60001e7SSujith Manoharan 
101e60001e7SSujith Manoharan 	/*
102e60001e7SSujith Manoharan 	 * need not match the destination mac address, it can be a broadcast
103e60001e7SSujith Manoharan 	 * mac address or an unicast to this station
104e60001e7SSujith Manoharan 	 */
105e60001e7SSujith Manoharan 	byte_cnt += 6;
106e60001e7SSujith Manoharan 
107e60001e7SSujith Manoharan 	/* copy the source mac address */
108e60001e7SSujith Manoharan 	memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
109e60001e7SSujith Manoharan 
110e60001e7SSujith Manoharan 	byte_cnt += 6;
111e60001e7SSujith Manoharan 
112e60001e7SSujith Manoharan 	/* copy the bssid, its same as the source mac address */
113e60001e7SSujith Manoharan 	memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
114e60001e7SSujith Manoharan 
115e60001e7SSujith Manoharan 	/* Create Disassociate pattern mask */
116e60001e7SSujith Manoharan 	dis_deauth_mask[0] = 0xfe;
117e60001e7SSujith Manoharan 	dis_deauth_mask[1] = 0x03;
118e60001e7SSujith Manoharan 	dis_deauth_mask[2] = 0xc0;
119e60001e7SSujith Manoharan 
1206af75e4dSSujith Manoharan 	ret = ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
121e60001e7SSujith Manoharan 					 pattern_count, byte_cnt);
1226af75e4dSSujith Manoharan 	if (ret)
1236af75e4dSSujith Manoharan 		goto exit;
124e60001e7SSujith Manoharan 
125e60001e7SSujith Manoharan 	pattern_count++;
126e60001e7SSujith Manoharan 	/*
127e60001e7SSujith Manoharan 	 * for de-authenticate pattern, only the first byte of the frame
128e60001e7SSujith Manoharan 	 * control field gets changed from 0xA0 to 0xC0
129e60001e7SSujith Manoharan 	 */
130e60001e7SSujith Manoharan 	dis_deauth_pattern[0] = 0xC0;
131e60001e7SSujith Manoharan 
1326af75e4dSSujith Manoharan 	ret = ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
133e60001e7SSujith Manoharan 					 pattern_count, byte_cnt);
1346af75e4dSSujith Manoharan exit:
1356af75e4dSSujith Manoharan 	return ret;
136e60001e7SSujith Manoharan }
137e60001e7SSujith Manoharan 
1386af75e4dSSujith Manoharan static int ath9k_wow_add_pattern(struct ath_softc *sc,
139e60001e7SSujith Manoharan 				 struct cfg80211_wowlan *wowlan)
140e60001e7SSujith Manoharan {
141e60001e7SSujith Manoharan 	struct ath_hw *ah = sc->sc_ah;
142e60001e7SSujith Manoharan 	struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
14334d102c9SSujith Manoharan 	u8 wow_pattern[MAX_PATTERN_SIZE];
14434d102c9SSujith Manoharan 	u8 wow_mask[MAX_PATTERN_SIZE];
1456af75e4dSSujith Manoharan 	int mask_len, ret = 0;
146e60001e7SSujith Manoharan 	s8 i = 0;
147e60001e7SSujith Manoharan 
148e60001e7SSujith Manoharan 	for (i = 0; i < wowlan->n_patterns; i++) {
14934d102c9SSujith Manoharan 		mask_len = DIV_ROUND_UP(patterns[i].pattern_len, 8);
15034d102c9SSujith Manoharan 		memset(wow_pattern, 0, MAX_PATTERN_SIZE);
15134d102c9SSujith Manoharan 		memset(wow_mask, 0, MAX_PATTERN_SIZE);
15234d102c9SSujith Manoharan 		memcpy(wow_pattern, patterns[i].pattern, patterns[i].pattern_len);
15334d102c9SSujith Manoharan 		memcpy(wow_mask, patterns[i].mask, mask_len);
154e60001e7SSujith Manoharan 
1556af75e4dSSujith Manoharan 		ret = ath9k_hw_wow_apply_pattern(ah,
15634d102c9SSujith Manoharan 						 wow_pattern,
15734d102c9SSujith Manoharan 						 wow_mask,
158e60001e7SSujith Manoharan 						 i + 2,
15934d102c9SSujith Manoharan 						 patterns[i].pattern_len);
1606af75e4dSSujith Manoharan 		if (ret)
1616af75e4dSSujith Manoharan 			break;
162e60001e7SSujith Manoharan 	}
1636af75e4dSSujith Manoharan 
1646af75e4dSSujith Manoharan 	return ret;
165e60001e7SSujith Manoharan }
166e60001e7SSujith Manoharan 
167e60001e7SSujith Manoharan int ath9k_suspend(struct ieee80211_hw *hw,
168e60001e7SSujith Manoharan 		  struct cfg80211_wowlan *wowlan)
169e60001e7SSujith Manoharan {
170e60001e7SSujith Manoharan 	struct ath_softc *sc = hw->priv;
171e60001e7SSujith Manoharan 	struct ath_hw *ah = sc->sc_ah;
172e60001e7SSujith Manoharan 	struct ath_common *common = ath9k_hw_common(ah);
173249943a2SSujith Manoharan 	u8 triggers;
174e60001e7SSujith Manoharan 	int ret = 0;
175e60001e7SSujith Manoharan 
176ea22df29SSujith Manoharan 	ath9k_deinit_channel_context(sc);
177ea22df29SSujith Manoharan 
178e60001e7SSujith Manoharan 	mutex_lock(&sc->mutex);
179e60001e7SSujith Manoharan 
180eefa01ddSOleksij Rempel 	if (test_bit(ATH_OP_INVALID, &common->op_flags)) {
18113084c2dSSujith Manoharan 		ath_err(common, "Device not present\n");
18213084c2dSSujith Manoharan 		ret = -ENODEV;
183e60001e7SSujith Manoharan 		goto fail_wow;
184e60001e7SSujith Manoharan 	}
185e60001e7SSujith Manoharan 
186e60001e7SSujith Manoharan 	if (WARN_ON(!wowlan)) {
18713084c2dSSujith Manoharan 		ath_err(common, "None of the WoW triggers enabled\n");
188e60001e7SSujith Manoharan 		ret = -EINVAL;
189e60001e7SSujith Manoharan 		goto fail_wow;
190e60001e7SSujith Manoharan 	}
191e60001e7SSujith Manoharan 
192dc4b277dSSujith Manoharan 	if (sc->cur_chan->nvifs > 1) {
193dc4b277dSSujith Manoharan 		ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");
194dc4b277dSSujith Manoharan 		ret = 1;
195dc4b277dSSujith Manoharan 		goto fail_wow;
196dc4b277dSSujith Manoharan 	}
197e60001e7SSujith Manoharan 
1981331f5a7SSujith Manoharan 	if (ath9k_is_chanctx_enabled()) {
1991331f5a7SSujith Manoharan 		if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) {
2001331f5a7SSujith Manoharan 			ath_dbg(common, WOW,
2011331f5a7SSujith Manoharan 				"Multi-channel WOW is not supported\n");
2021331f5a7SSujith Manoharan 			ret = 1;
2031331f5a7SSujith Manoharan 			goto fail_wow;
2041331f5a7SSujith Manoharan 		}
2051331f5a7SSujith Manoharan 	}
2061331f5a7SSujith Manoharan 
207eefa01ddSOleksij Rempel 	if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) {
208e60001e7SSujith Manoharan 		ath_dbg(common, WOW, "None of the STA vifs are associated\n");
209e60001e7SSujith Manoharan 		ret = 1;
210e60001e7SSujith Manoharan 		goto fail_wow;
211e60001e7SSujith Manoharan 	}
212e60001e7SSujith Manoharan 
213249943a2SSujith Manoharan 	triggers = ath9k_wow_map_triggers(sc, wowlan);
214249943a2SSujith Manoharan 	if (!triggers) {
215249943a2SSujith Manoharan 		ath_dbg(common, WOW, "No valid WoW triggers\n");
216249943a2SSujith Manoharan 		ret = 1;
217249943a2SSujith Manoharan 		goto fail_wow;
218249943a2SSujith Manoharan 	}
219249943a2SSujith Manoharan 
220dc4b277dSSujith Manoharan 	ath_cancel_work(sc);
221dc4b277dSSujith Manoharan 	ath_stop_ani(sc);
222e60001e7SSujith Manoharan 
223e60001e7SSujith Manoharan 	ath9k_ps_wakeup(sc);
224e60001e7SSujith Manoharan 
225e60001e7SSujith Manoharan 	ath9k_stop_btcoex(sc);
226e60001e7SSujith Manoharan 
227e60001e7SSujith Manoharan 	/*
228e60001e7SSujith Manoharan 	 * Enable wake up on recieving disassoc/deauth
229e60001e7SSujith Manoharan 	 * frame by default.
230e60001e7SSujith Manoharan 	 */
2316af75e4dSSujith Manoharan 	ret = ath9k_wow_add_disassoc_deauth_pattern(sc);
2326af75e4dSSujith Manoharan 	if (ret) {
2336af75e4dSSujith Manoharan 		ath_err(common,
2346af75e4dSSujith Manoharan 			"Unable to add disassoc/deauth pattern: %d\n", ret);
2356af75e4dSSujith Manoharan 		goto fail_wow;
2366af75e4dSSujith Manoharan 	}
237e60001e7SSujith Manoharan 
2386af75e4dSSujith Manoharan 	if (triggers & AH_WOW_USER_PATTERN_EN) {
2396af75e4dSSujith Manoharan 		ret = ath9k_wow_add_pattern(sc, wowlan);
2406af75e4dSSujith Manoharan 		if (ret) {
2416af75e4dSSujith Manoharan 			ath_err(common,
2426af75e4dSSujith Manoharan 				"Unable to add user pattern: %d\n", ret);
2436af75e4dSSujith Manoharan 			goto fail_wow;
2446af75e4dSSujith Manoharan 		}
2456af75e4dSSujith Manoharan 	}
246e60001e7SSujith Manoharan 
247e60001e7SSujith Manoharan 	spin_lock_bh(&sc->sc_pcu_lock);
248e60001e7SSujith Manoharan 	/*
249e60001e7SSujith Manoharan 	 * To avoid false wake, we enable beacon miss interrupt only
250e60001e7SSujith Manoharan 	 * when we go to sleep. We save the current interrupt mask
251e60001e7SSujith Manoharan 	 * so we can restore it after the system wakes up
252e60001e7SSujith Manoharan 	 */
253e60001e7SSujith Manoharan 	sc->wow_intr_before_sleep = ah->imask;
254e60001e7SSujith Manoharan 	ah->imask &= ~ATH9K_INT_GLOBAL;
255e60001e7SSujith Manoharan 	ath9k_hw_disable_interrupts(ah);
256e60001e7SSujith Manoharan 	ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL;
257e60001e7SSujith Manoharan 	ath9k_hw_set_interrupts(ah);
258e60001e7SSujith Manoharan 	ath9k_hw_enable_interrupts(ah);
259e60001e7SSujith Manoharan 
260e60001e7SSujith Manoharan 	spin_unlock_bh(&sc->sc_pcu_lock);
261e60001e7SSujith Manoharan 
262e60001e7SSujith Manoharan 	/*
263e60001e7SSujith Manoharan 	 * we can now sync irq and kill any running tasklets, since we already
264e60001e7SSujith Manoharan 	 * disabled interrupts and not holding a spin lock
265e60001e7SSujith Manoharan 	 */
266e60001e7SSujith Manoharan 	synchronize_irq(sc->irq);
267e60001e7SSujith Manoharan 	tasklet_kill(&sc->intr_tq);
268e60001e7SSujith Manoharan 
269249943a2SSujith Manoharan 	ath9k_hw_wow_enable(ah, triggers);
270e60001e7SSujith Manoharan 
271e60001e7SSujith Manoharan 	ath9k_ps_restore(sc);
272249943a2SSujith Manoharan 	ath_dbg(common, WOW, "Suspend with WoW triggers: 0x%x\n", triggers);
273e60001e7SSujith Manoharan 
274249943a2SSujith Manoharan 	set_bit(ATH_OP_WOW_ENABLED, &common->op_flags);
275e60001e7SSujith Manoharan fail_wow:
276e60001e7SSujith Manoharan 	mutex_unlock(&sc->mutex);
277e60001e7SSujith Manoharan 	return ret;
278e60001e7SSujith Manoharan }
279e60001e7SSujith Manoharan 
280e60001e7SSujith Manoharan int ath9k_resume(struct ieee80211_hw *hw)
281e60001e7SSujith Manoharan {
282e60001e7SSujith Manoharan 	struct ath_softc *sc = hw->priv;
283e60001e7SSujith Manoharan 	struct ath_hw *ah = sc->sc_ah;
284e60001e7SSujith Manoharan 	struct ath_common *common = ath9k_hw_common(ah);
285e094c337SSujith Manoharan 	u8 status;
286e60001e7SSujith Manoharan 
287e60001e7SSujith Manoharan 	mutex_lock(&sc->mutex);
288e60001e7SSujith Manoharan 
289e60001e7SSujith Manoharan 	ath9k_ps_wakeup(sc);
290e60001e7SSujith Manoharan 
291e60001e7SSujith Manoharan 	spin_lock_bh(&sc->sc_pcu_lock);
292e60001e7SSujith Manoharan 
293e60001e7SSujith Manoharan 	ath9k_hw_disable_interrupts(ah);
294e60001e7SSujith Manoharan 	ah->imask = sc->wow_intr_before_sleep;
295e60001e7SSujith Manoharan 	ath9k_hw_set_interrupts(ah);
296e60001e7SSujith Manoharan 	ath9k_hw_enable_interrupts(ah);
297e60001e7SSujith Manoharan 
298e60001e7SSujith Manoharan 	spin_unlock_bh(&sc->sc_pcu_lock);
299e60001e7SSujith Manoharan 
300e094c337SSujith Manoharan 	status = ath9k_hw_wow_wakeup(ah);
301e094c337SSujith Manoharan 	ath_dbg(common, WOW, "Resume with WoW status: 0x%x\n", status);
302e60001e7SSujith Manoharan 
303e60001e7SSujith Manoharan 	ath_restart_work(sc);
304e60001e7SSujith Manoharan 	ath9k_start_btcoex(sc);
305e60001e7SSujith Manoharan 
306249943a2SSujith Manoharan 	clear_bit(ATH_OP_WOW_ENABLED, &common->op_flags);
307249943a2SSujith Manoharan 
308e60001e7SSujith Manoharan 	ath9k_ps_restore(sc);
309e60001e7SSujith Manoharan 	mutex_unlock(&sc->mutex);
310e60001e7SSujith Manoharan 
311e60001e7SSujith Manoharan 	return 0;
312e60001e7SSujith Manoharan }
313e60001e7SSujith Manoharan 
314e60001e7SSujith Manoharan void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
315e60001e7SSujith Manoharan {
316e60001e7SSujith Manoharan 	struct ath_softc *sc = hw->priv;
317661d2581SSujith Manoharan 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
318e60001e7SSujith Manoharan 
319e60001e7SSujith Manoharan 	mutex_lock(&sc->mutex);
320e60001e7SSujith Manoharan 	device_set_wakeup_enable(sc->dev, enabled);
321e60001e7SSujith Manoharan 	mutex_unlock(&sc->mutex);
322661d2581SSujith Manoharan 
323661d2581SSujith Manoharan 	ath_dbg(common, WOW, "WoW wakeup source is %s\n",
324661d2581SSujith Manoharan 		(enabled) ? "enabled" : "disabled");
325e60001e7SSujith Manoharan }
326babaa80aSSujith Manoharan 
327babaa80aSSujith Manoharan void ath9k_init_wow(struct ieee80211_hw *hw)
328babaa80aSSujith Manoharan {
329babaa80aSSujith Manoharan 	struct ath_softc *sc = hw->priv;
330*e68e9c10SSujith Manoharan 	struct ath_hw *ah = sc->sc_ah;
331babaa80aSSujith Manoharan 
3328b861715SSujith Manoharan 	if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow) {
333*e68e9c10SSujith Manoharan 		if (AR_SREV_9462_20_OR_LATER(ah) || AR_SREV_9565_11_OR_LATER(ah))
334babaa80aSSujith Manoharan 			hw->wiphy->wowlan = &ath9k_wowlan_support;
335*e68e9c10SSujith Manoharan 		else
336*e68e9c10SSujith Manoharan 			hw->wiphy->wowlan = &ath9k_wowlan_support_legacy;
337*e68e9c10SSujith Manoharan 
338661d2581SSujith Manoharan 		device_init_wakeup(sc->dev, 1);
339661d2581SSujith Manoharan 	}
340661d2581SSujith Manoharan }
341661d2581SSujith Manoharan 
342661d2581SSujith Manoharan void ath9k_deinit_wow(struct ieee80211_hw *hw)
343661d2581SSujith Manoharan {
344661d2581SSujith Manoharan 	struct ath_softc *sc = hw->priv;
345661d2581SSujith Manoharan 
3468b861715SSujith Manoharan 	if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow)
347661d2581SSujith Manoharan 		device_init_wakeup(sc->dev, 0);
348babaa80aSSujith Manoharan }
349