diff options
author | Sujith Manoharan <c_manoha@qca.qualcomm.com> | 2015-01-30 08:35:27 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2015-02-03 08:31:04 -0500 |
commit | 249943a2215c4d03c5dacf549b4ef9bf8439f17b (patch) | |
tree | cefd3cf181f81c0f8a8d10545230f7031c027abf | |
parent | 661d25815ea533d06c7535ddd1c4810fa7ab9e22 (diff) |
ath9k: Check WOW triggers properly
This patch makes sure that valid WOW triggers
are present before trying to suspend the device.
Also, introduce and use ATH_OP_WOW_ENABLED to
bypass PCI suspend and clear it in resume().
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
-rw-r--r-- | drivers/net/wireless/ath/ath.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/pci.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/wow.c | 53 |
3 files changed, 29 insertions, 30 deletions
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index ccba4fea7269..1eebe2ea3dfb 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h | |||
@@ -64,6 +64,7 @@ enum ath_op_flags { | |||
64 | ATH_OP_HW_RESET, | 64 | ATH_OP_HW_RESET, |
65 | ATH_OP_SCANNING, | 65 | ATH_OP_SCANNING, |
66 | ATH_OP_MULTI_CHANNEL, | 66 | ATH_OP_MULTI_CHANNEL, |
67 | ATH_OP_WOW_ENABLED, | ||
67 | }; | 68 | }; |
68 | 69 | ||
69 | enum ath_bus_type { | 70 | enum ath_bus_type { |
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index cc5c6810f32e..e6fef1be9977 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c | |||
@@ -998,9 +998,12 @@ static int ath_pci_suspend(struct device *device) | |||
998 | struct pci_dev *pdev = to_pci_dev(device); | 998 | struct pci_dev *pdev = to_pci_dev(device); |
999 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | 999 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); |
1000 | struct ath_softc *sc = hw->priv; | 1000 | struct ath_softc *sc = hw->priv; |
1001 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
1001 | 1002 | ||
1002 | if (sc->wow_enabled) | 1003 | if (test_bit(ATH_OP_WOW_ENABLED, &common->op_flags)) { |
1004 | dev_info(&pdev->dev, "WOW is enabled, bypassing PCI suspend\n"); | ||
1003 | return 0; | 1005 | return 0; |
1006 | } | ||
1004 | 1007 | ||
1005 | /* The device has to be moved to FULLSLEEP forcibly. | 1008 | /* The device has to be moved to FULLSLEEP forcibly. |
1006 | * Otherwise the chip never moved to full sleep, | 1009 | * Otherwise the chip never moved to full sleep, |
diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 8bcbaa91529e..c0c564de982e 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c | |||
@@ -23,21 +23,21 @@ static const struct wiphy_wowlan_support ath9k_wowlan_support = { | |||
23 | .pattern_max_len = MAX_PATTERN_SIZE, | 23 | .pattern_max_len = MAX_PATTERN_SIZE, |
24 | }; | 24 | }; |
25 | 25 | ||
26 | static void ath9k_wow_map_triggers(struct ath_softc *sc, | 26 | static u8 ath9k_wow_map_triggers(struct ath_softc *sc, |
27 | struct cfg80211_wowlan *wowlan, | 27 | struct cfg80211_wowlan *wowlan) |
28 | u32 *wow_triggers) | ||
29 | { | 28 | { |
29 | u8 wow_triggers = 0; | ||
30 | |||
30 | if (wowlan->disconnect) | 31 | if (wowlan->disconnect) |
31 | *wow_triggers |= AH_WOW_LINK_CHANGE | | 32 | wow_triggers |= AH_WOW_LINK_CHANGE | |
32 | AH_WOW_BEACON_MISS; | 33 | AH_WOW_BEACON_MISS; |
33 | if (wowlan->magic_pkt) | 34 | if (wowlan->magic_pkt) |
34 | *wow_triggers |= AH_WOW_MAGIC_PATTERN_EN; | 35 | wow_triggers |= AH_WOW_MAGIC_PATTERN_EN; |
35 | 36 | ||
36 | if (wowlan->n_patterns) | 37 | if (wowlan->n_patterns) |
37 | *wow_triggers |= AH_WOW_USER_PATTERN_EN; | 38 | wow_triggers |= AH_WOW_USER_PATTERN_EN; |
38 | |||
39 | sc->wow_enabled = *wow_triggers; | ||
40 | 39 | ||
40 | return wow_triggers; | ||
41 | } | 41 | } |
42 | 42 | ||
43 | static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) | 43 | static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) |
@@ -45,7 +45,7 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) | |||
45 | struct ath_hw *ah = sc->sc_ah; | 45 | struct ath_hw *ah = sc->sc_ah; |
46 | struct ath_common *common = ath9k_hw_common(ah); | 46 | struct ath_common *common = ath9k_hw_common(ah); |
47 | int pattern_count = 0; | 47 | int pattern_count = 0; |
48 | int i, byte_cnt; | 48 | int i, byte_cnt = 0; |
49 | u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; | 49 | u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; |
50 | u8 dis_deauth_mask[MAX_PATTERN_SIZE]; | 50 | u8 dis_deauth_mask[MAX_PATTERN_SIZE]; |
51 | 51 | ||
@@ -80,12 +80,7 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) | |||
80 | * | x:x:x:x:x:x -- 22 bytes | 80 | * | x:x:x:x:x:x -- 22 bytes |
81 | */ | 81 | */ |
82 | 82 | ||
83 | /* Create Disassociate Pattern first */ | ||
84 | |||
85 | byte_cnt = 0; | ||
86 | |||
87 | /* Fill out the mask with all FF's */ | 83 | /* Fill out the mask with all FF's */ |
88 | |||
89 | for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++) | 84 | for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++) |
90 | dis_deauth_mask[i] = 0xff; | 85 | dis_deauth_mask[i] = 0xff; |
91 | 86 | ||
@@ -108,17 +103,13 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) | |||
108 | byte_cnt += 6; | 103 | byte_cnt += 6; |
109 | 104 | ||
110 | /* copy the bssid, its same as the source mac address */ | 105 | /* copy the bssid, its same as the source mac address */ |
111 | |||
112 | memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); | 106 | memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); |
113 | 107 | ||
114 | /* Create Disassociate pattern mask */ | 108 | /* Create Disassociate pattern mask */ |
115 | |||
116 | dis_deauth_mask[0] = 0xfe; | 109 | dis_deauth_mask[0] = 0xfe; |
117 | dis_deauth_mask[1] = 0x03; | 110 | dis_deauth_mask[1] = 0x03; |
118 | dis_deauth_mask[2] = 0xc0; | 111 | dis_deauth_mask[2] = 0xc0; |
119 | 112 | ||
120 | ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n"); | ||
121 | |||
122 | ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, | 113 | ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, |
123 | pattern_count, byte_cnt); | 114 | pattern_count, byte_cnt); |
124 | 115 | ||
@@ -131,7 +122,6 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) | |||
131 | 122 | ||
132 | ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, | 123 | ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, |
133 | pattern_count, byte_cnt); | 124 | pattern_count, byte_cnt); |
134 | |||
135 | } | 125 | } |
136 | 126 | ||
137 | static void ath9k_wow_add_pattern(struct ath_softc *sc, | 127 | static void ath9k_wow_add_pattern(struct ath_softc *sc, |
@@ -190,7 +180,7 @@ int ath9k_suspend(struct ieee80211_hw *hw, | |||
190 | struct ath_softc *sc = hw->priv; | 180 | struct ath_softc *sc = hw->priv; |
191 | struct ath_hw *ah = sc->sc_ah; | 181 | struct ath_hw *ah = sc->sc_ah; |
192 | struct ath_common *common = ath9k_hw_common(ah); | 182 | struct ath_common *common = ath9k_hw_common(ah); |
193 | u32 wow_triggers_enabled = 0; | 183 | u8 triggers; |
194 | int ret = 0; | 184 | int ret = 0; |
195 | 185 | ||
196 | ath9k_deinit_channel_context(sc); | 186 | ath9k_deinit_channel_context(sc); |
@@ -230,14 +220,16 @@ int ath9k_suspend(struct ieee80211_hw *hw, | |||
230 | goto fail_wow; | 220 | goto fail_wow; |
231 | } | 221 | } |
232 | 222 | ||
223 | triggers = ath9k_wow_map_triggers(sc, wowlan); | ||
224 | if (!triggers) { | ||
225 | ath_dbg(common, WOW, "No valid WoW triggers\n"); | ||
226 | ret = 1; | ||
227 | goto fail_wow; | ||
228 | } | ||
229 | |||
233 | ath_cancel_work(sc); | 230 | ath_cancel_work(sc); |
234 | ath_stop_ani(sc); | 231 | ath_stop_ani(sc); |
235 | 232 | ||
236 | ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled); | ||
237 | |||
238 | ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n", | ||
239 | wow_triggers_enabled); | ||
240 | |||
241 | ath9k_ps_wakeup(sc); | 233 | ath9k_ps_wakeup(sc); |
242 | 234 | ||
243 | ath9k_stop_btcoex(sc); | 235 | ath9k_stop_btcoex(sc); |
@@ -248,7 +240,7 @@ int ath9k_suspend(struct ieee80211_hw *hw, | |||
248 | */ | 240 | */ |
249 | ath9k_wow_add_disassoc_deauth_pattern(sc); | 241 | ath9k_wow_add_disassoc_deauth_pattern(sc); |
250 | 242 | ||
251 | if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN) | 243 | if (triggers & AH_WOW_USER_PATTERN_EN) |
252 | ath9k_wow_add_pattern(sc, wowlan); | 244 | ath9k_wow_add_pattern(sc, wowlan); |
253 | 245 | ||
254 | spin_lock_bh(&sc->sc_pcu_lock); | 246 | spin_lock_bh(&sc->sc_pcu_lock); |
@@ -273,12 +265,13 @@ int ath9k_suspend(struct ieee80211_hw *hw, | |||
273 | synchronize_irq(sc->irq); | 265 | synchronize_irq(sc->irq); |
274 | tasklet_kill(&sc->intr_tq); | 266 | tasklet_kill(&sc->intr_tq); |
275 | 267 | ||
276 | ath9k_hw_wow_enable(ah, wow_triggers_enabled); | 268 | ath9k_hw_wow_enable(ah, triggers); |
277 | 269 | ||
278 | ath9k_ps_restore(sc); | 270 | ath9k_ps_restore(sc); |
279 | ath_dbg(common, ANY, "WoW enabled in ath9k\n"); | 271 | ath_dbg(common, WOW, "Suspend with WoW triggers: 0x%x\n", triggers); |
280 | atomic_inc(&sc->wow_sleep_proc_intr); | 272 | atomic_inc(&sc->wow_sleep_proc_intr); |
281 | 273 | ||
274 | set_bit(ATH_OP_WOW_ENABLED, &common->op_flags); | ||
282 | fail_wow: | 275 | fail_wow: |
283 | mutex_unlock(&sc->mutex); | 276 | mutex_unlock(&sc->mutex); |
284 | return ret; | 277 | return ret; |
@@ -327,6 +320,8 @@ int ath9k_resume(struct ieee80211_hw *hw) | |||
327 | ath_restart_work(sc); | 320 | ath_restart_work(sc); |
328 | ath9k_start_btcoex(sc); | 321 | ath9k_start_btcoex(sc); |
329 | 322 | ||
323 | clear_bit(ATH_OP_WOW_ENABLED, &common->op_flags); | ||
324 | |||
330 | ath9k_ps_restore(sc); | 325 | ath9k_ps_restore(sc); |
331 | mutex_unlock(&sc->mutex); | 326 | mutex_unlock(&sc->mutex); |
332 | 327 | ||