aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSujith Manoharan <c_manoha@qca.qualcomm.com>2015-01-30 08:35:27 -0500
committerKalle Valo <kvalo@codeaurora.org>2015-02-03 08:31:04 -0500
commit249943a2215c4d03c5dacf549b4ef9bf8439f17b (patch)
treecefd3cf181f81c0f8a8d10545230f7031c027abf
parent661d25815ea533d06c7535ddd1c4810fa7ab9e22 (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.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/wow.c53
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
69enum ath_bus_type { 70enum 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
26static void ath9k_wow_map_triggers(struct ath_softc *sc, 26static 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
43static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) 43static 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
137static void ath9k_wow_add_pattern(struct ath_softc *sc, 127static 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);
282fail_wow: 275fail_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