diff options
author | Gabor Juhos <juhosg@openwrt.org> | 2009-07-24 11:27:21 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-07-29 15:46:03 -0400 |
commit | 96148326c4b54db5c384def1a5ab285c359d1395 (patch) | |
tree | 86985eb7ab56819992066500ad215bfea63121a0 | |
parent | ff8365ca889cb86ba5bd40fe3047d047bc632f4c (diff) |
ath9k: fix race with IEEE80211_CONF_PS checks
There is a small window where the mac80211 changes the IEEE80211_CONF_PS
flag, and then informs the driver about the change. We have a race
condition if we are checking the flag in the same time. Avoid it by
introducing a local variable, and using that instead of checking the
IEEE80211_CONF_PS flag directly.
This fix the problem reported by Luis:
http://article.gmane.org/gmane.linux.kernel.wireless.general/34363
Changes-licensed-under: ISC
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.c | 17 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 8 |
4 files changed, 12 insertions, 15 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e2ebf1a56c00..3a978bfa246e 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -573,6 +573,7 @@ struct ath_softc { | |||
573 | u32 keymax; | 573 | u32 keymax; |
574 | DECLARE_BITMAP(keymap, ATH_KEYMAX); | 574 | DECLARE_BITMAP(keymap, ATH_KEYMAX); |
575 | u8 splitmic; | 575 | u8 splitmic; |
576 | bool ps_enabled; | ||
576 | unsigned long ps_usecount; | 577 | unsigned long ps_usecount; |
577 | enum ath9k_int imask; | 578 | enum ath9k_int imask; |
578 | enum ath9k_ht_extprotspacing ht_extprotspacing; | 579 | enum ath9k_ht_extprotspacing ht_extprotspacing; |
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index da3226994de7..e6e52f48e718 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -2863,10 +2863,8 @@ void ath9k_ps_wakeup(struct ath_softc *sc) | |||
2863 | if (++sc->ps_usecount != 1) | 2863 | if (++sc->ps_usecount != 1) |
2864 | goto unlock; | 2864 | goto unlock; |
2865 | 2865 | ||
2866 | if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) { | 2866 | if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) |
2867 | sc->sc_ah->restore_mode = sc->sc_ah->power_mode; | ||
2868 | ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE); | 2867 | ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE); |
2869 | } | ||
2870 | 2868 | ||
2871 | unlock: | 2869 | unlock: |
2872 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); | 2870 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); |
@@ -2880,13 +2878,12 @@ void ath9k_ps_restore(struct ath_softc *sc) | |||
2880 | if (--sc->ps_usecount != 0) | 2878 | if (--sc->ps_usecount != 0) |
2881 | goto unlock; | 2879 | goto unlock; |
2882 | 2880 | ||
2883 | if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && | 2881 | if (sc->ps_enabled && |
2884 | !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | | 2882 | !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | |
2885 | SC_OP_WAIT_FOR_CAB | | 2883 | SC_OP_WAIT_FOR_CAB | |
2886 | SC_OP_WAIT_FOR_PSPOLL_DATA | | 2884 | SC_OP_WAIT_FOR_PSPOLL_DATA | |
2887 | SC_OP_WAIT_FOR_TX_ACK))) | 2885 | SC_OP_WAIT_FOR_TX_ACK))) |
2888 | ath9k_hw_setpower_nolock(sc->sc_ah, | 2886 | ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); |
2889 | sc->sc_ah->restore_mode); | ||
2890 | 2887 | ||
2891 | unlock: | 2888 | unlock: |
2892 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); | 2889 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 37f7d3defb82..2e196df10894 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -421,7 +421,6 @@ struct ath_hw { | |||
421 | 421 | ||
422 | enum nl80211_iftype opmode; | 422 | enum nl80211_iftype opmode; |
423 | enum ath9k_power_mode power_mode; | 423 | enum ath9k_power_mode power_mode; |
424 | enum ath9k_power_mode restore_mode; | ||
425 | 424 | ||
426 | struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; | 425 | struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; |
427 | struct ar5416Stats stats; | 426 | struct ar5416Stats stats; |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 1c648db10920..87f997183936 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -499,8 +499,7 @@ static void ath9k_tasklet(unsigned long data) | |||
499 | if (status & ATH9K_INT_TX) | 499 | if (status & ATH9K_INT_TX) |
500 | ath_tx_tasklet(sc); | 500 | ath_tx_tasklet(sc); |
501 | 501 | ||
502 | if ((status & ATH9K_INT_TSFOOR) && | 502 | if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) { |
503 | (sc->hw->conf.flags & IEEE80211_CONF_PS)) { | ||
504 | /* | 503 | /* |
505 | * TSF sync does not look correct; remain awake to sync with | 504 | * TSF sync does not look correct; remain awake to sync with |
506 | * the next Beacon. | 505 | * the next Beacon. |
@@ -2001,7 +2000,7 @@ static int ath9k_tx(struct ieee80211_hw *hw, | |||
2001 | goto exit; | 2000 | goto exit; |
2002 | } | 2001 | } |
2003 | 2002 | ||
2004 | if (sc->hw->conf.flags & IEEE80211_CONF_PS) { | 2003 | if (sc->ps_enabled) { |
2005 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 2004 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
2006 | /* | 2005 | /* |
2007 | * mac80211 does not set PM field for normal data frames, so we | 2006 | * mac80211 does not set PM field for normal data frames, so we |
@@ -2289,8 +2288,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | |||
2289 | } | 2288 | } |
2290 | ath9k_hw_setrxabort(sc->sc_ah, 1); | 2289 | ath9k_hw_setrxabort(sc->sc_ah, 1); |
2291 | } | 2290 | } |
2292 | ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); | 2291 | sc->ps_enabled = true; |
2293 | } else { | 2292 | } else { |
2293 | sc->ps_enabled = false; | ||
2294 | ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); | 2294 | ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); |
2295 | if (!(ah->caps.hw_caps & | 2295 | if (!(ah->caps.hw_caps & |
2296 | ATH9K_HW_CAP_AUTOSLEEP)) { | 2296 | ATH9K_HW_CAP_AUTOSLEEP)) { |