Commit 249943a2 authored by Sujith Manoharan's avatar Sujith Manoharan Committed by Kalle Valo

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: default avatarSujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 661d2581
...@@ -64,6 +64,7 @@ enum ath_op_flags { ...@@ -64,6 +64,7 @@ enum ath_op_flags {
ATH_OP_HW_RESET, ATH_OP_HW_RESET,
ATH_OP_SCANNING, ATH_OP_SCANNING,
ATH_OP_MULTI_CHANNEL, ATH_OP_MULTI_CHANNEL,
ATH_OP_WOW_ENABLED,
}; };
enum ath_bus_type { enum ath_bus_type {
......
...@@ -998,9 +998,12 @@ static int ath_pci_suspend(struct device *device) ...@@ -998,9 +998,12 @@ static int ath_pci_suspend(struct device *device)
struct pci_dev *pdev = to_pci_dev(device); struct pci_dev *pdev = to_pci_dev(device);
struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
if (sc->wow_enabled) if (test_bit(ATH_OP_WOW_ENABLED, &common->op_flags)) {
dev_info(&pdev->dev, "WOW is enabled, bypassing PCI suspend\n");
return 0; return 0;
}
/* The device has to be moved to FULLSLEEP forcibly. /* The device has to be moved to FULLSLEEP forcibly.
* Otherwise the chip never moved to full sleep, * Otherwise the chip never moved to full sleep,
......
...@@ -23,21 +23,21 @@ static const struct wiphy_wowlan_support ath9k_wowlan_support = { ...@@ -23,21 +23,21 @@ static const struct wiphy_wowlan_support ath9k_wowlan_support = {
.pattern_max_len = MAX_PATTERN_SIZE, .pattern_max_len = MAX_PATTERN_SIZE,
}; };
static void ath9k_wow_map_triggers(struct ath_softc *sc, static u8 ath9k_wow_map_triggers(struct ath_softc *sc,
struct cfg80211_wowlan *wowlan, struct cfg80211_wowlan *wowlan)
u32 *wow_triggers)
{ {
u8 wow_triggers = 0;
if (wowlan->disconnect) if (wowlan->disconnect)
*wow_triggers |= AH_WOW_LINK_CHANGE | wow_triggers |= AH_WOW_LINK_CHANGE |
AH_WOW_BEACON_MISS; AH_WOW_BEACON_MISS;
if (wowlan->magic_pkt) if (wowlan->magic_pkt)
*wow_triggers |= AH_WOW_MAGIC_PATTERN_EN; wow_triggers |= AH_WOW_MAGIC_PATTERN_EN;
if (wowlan->n_patterns) if (wowlan->n_patterns)
*wow_triggers |= AH_WOW_USER_PATTERN_EN; wow_triggers |= AH_WOW_USER_PATTERN_EN;
sc->wow_enabled = *wow_triggers;
return wow_triggers;
} }
static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) 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,7 +45,7 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
int pattern_count = 0; int pattern_count = 0;
int i, byte_cnt; int i, byte_cnt = 0;
u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; u8 dis_deauth_pattern[MAX_PATTERN_SIZE];
u8 dis_deauth_mask[MAX_PATTERN_SIZE]; u8 dis_deauth_mask[MAX_PATTERN_SIZE];
...@@ -80,12 +80,7 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) ...@@ -80,12 +80,7 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
* | x:x:x:x:x:x -- 22 bytes * | x:x:x:x:x:x -- 22 bytes
*/ */
/* Create Disassociate Pattern first */
byte_cnt = 0;
/* Fill out the mask with all FF's */ /* Fill out the mask with all FF's */
for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++) for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++)
dis_deauth_mask[i] = 0xff; dis_deauth_mask[i] = 0xff;
...@@ -108,17 +103,13 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) ...@@ -108,17 +103,13 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
byte_cnt += 6; byte_cnt += 6;
/* copy the bssid, its same as the source mac address */ /* copy the bssid, its same as the source mac address */
memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
/* Create Disassociate pattern mask */ /* Create Disassociate pattern mask */
dis_deauth_mask[0] = 0xfe; dis_deauth_mask[0] = 0xfe;
dis_deauth_mask[1] = 0x03; dis_deauth_mask[1] = 0x03;
dis_deauth_mask[2] = 0xc0; dis_deauth_mask[2] = 0xc0;
ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n");
ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
pattern_count, byte_cnt); pattern_count, byte_cnt);
...@@ -131,7 +122,6 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) ...@@ -131,7 +122,6 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
pattern_count, byte_cnt); pattern_count, byte_cnt);
} }
static void ath9k_wow_add_pattern(struct ath_softc *sc, static void ath9k_wow_add_pattern(struct ath_softc *sc,
...@@ -190,7 +180,7 @@ int ath9k_suspend(struct ieee80211_hw *hw, ...@@ -190,7 +180,7 @@ int ath9k_suspend(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
u32 wow_triggers_enabled = 0; u8 triggers;
int ret = 0; int ret = 0;
ath9k_deinit_channel_context(sc); ath9k_deinit_channel_context(sc);
...@@ -230,14 +220,16 @@ int ath9k_suspend(struct ieee80211_hw *hw, ...@@ -230,14 +220,16 @@ int ath9k_suspend(struct ieee80211_hw *hw,
goto fail_wow; goto fail_wow;
} }
triggers = ath9k_wow_map_triggers(sc, wowlan);
if (!triggers) {
ath_dbg(common, WOW, "No valid WoW triggers\n");
ret = 1;
goto fail_wow;
}
ath_cancel_work(sc); ath_cancel_work(sc);
ath_stop_ani(sc); ath_stop_ani(sc);
ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled);
ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n",
wow_triggers_enabled);
ath9k_ps_wakeup(sc); ath9k_ps_wakeup(sc);
ath9k_stop_btcoex(sc); ath9k_stop_btcoex(sc);
...@@ -248,7 +240,7 @@ int ath9k_suspend(struct ieee80211_hw *hw, ...@@ -248,7 +240,7 @@ int ath9k_suspend(struct ieee80211_hw *hw,
*/ */
ath9k_wow_add_disassoc_deauth_pattern(sc); ath9k_wow_add_disassoc_deauth_pattern(sc);
if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN) if (triggers & AH_WOW_USER_PATTERN_EN)
ath9k_wow_add_pattern(sc, wowlan); ath9k_wow_add_pattern(sc, wowlan);
spin_lock_bh(&sc->sc_pcu_lock); spin_lock_bh(&sc->sc_pcu_lock);
...@@ -273,12 +265,13 @@ int ath9k_suspend(struct ieee80211_hw *hw, ...@@ -273,12 +265,13 @@ int ath9k_suspend(struct ieee80211_hw *hw,
synchronize_irq(sc->irq); synchronize_irq(sc->irq);
tasklet_kill(&sc->intr_tq); tasklet_kill(&sc->intr_tq);
ath9k_hw_wow_enable(ah, wow_triggers_enabled); ath9k_hw_wow_enable(ah, triggers);
ath9k_ps_restore(sc); ath9k_ps_restore(sc);
ath_dbg(common, ANY, "WoW enabled in ath9k\n"); ath_dbg(common, WOW, "Suspend with WoW triggers: 0x%x\n", triggers);
atomic_inc(&sc->wow_sleep_proc_intr); atomic_inc(&sc->wow_sleep_proc_intr);
set_bit(ATH_OP_WOW_ENABLED, &common->op_flags);
fail_wow: fail_wow:
mutex_unlock(&sc->mutex); mutex_unlock(&sc->mutex);
return ret; return ret;
...@@ -327,6 +320,8 @@ int ath9k_resume(struct ieee80211_hw *hw) ...@@ -327,6 +320,8 @@ int ath9k_resume(struct ieee80211_hw *hw)
ath_restart_work(sc); ath_restart_work(sc);
ath9k_start_btcoex(sc); ath9k_start_btcoex(sc);
clear_bit(ATH_OP_WOW_ENABLED, &common->op_flags);
ath9k_ps_restore(sc); ath9k_ps_restore(sc);
mutex_unlock(&sc->mutex); mutex_unlock(&sc->mutex);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment