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 /drivers/net/wireless/ath/ath9k/main.c | |
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>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/main.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 8 |
1 files changed, 4 insertions, 4 deletions
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)) { |