Commit e5f0921a authored by Senthil Balasubramanian's avatar Senthil Balasubramanian Committed by John W. Linville

ath9k: race condition in SCANNING state check during ANI calibration

ANI calibration shouldn't be done when we are not on our home channel.
This is already verified. However, it is racy. Fix this by proper
spin locks.
Signed-off-by: default avatarSenthil Balasubramanian <senthilkumar@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent f38faa31
...@@ -540,6 +540,7 @@ struct ath_softc { ...@@ -540,6 +540,7 @@ struct ath_softc {
int irq; int irq;
spinlock_t sc_resetlock; spinlock_t sc_resetlock;
spinlock_t sc_serial_rw; spinlock_t sc_serial_rw;
spinlock_t ani_lock;
struct mutex mutex; struct mutex mutex;
u8 curbssid[ETH_ALEN]; u8 curbssid[ETH_ALEN];
......
...@@ -342,6 +342,7 @@ static void ath_ani_calibrate(unsigned long data) ...@@ -342,6 +342,7 @@ static void ath_ani_calibrate(unsigned long data)
* don't calibrate when we're scanning. * don't calibrate when we're scanning.
* we are most likely not on our home channel. * we are most likely not on our home channel.
*/ */
spin_lock(&sc->ani_lock);
if (sc->sc_flags & SC_OP_SCANNING) if (sc->sc_flags & SC_OP_SCANNING)
goto set_timer; goto set_timer;
...@@ -405,6 +406,7 @@ static void ath_ani_calibrate(unsigned long data) ...@@ -405,6 +406,7 @@ static void ath_ani_calibrate(unsigned long data)
ath9k_ps_restore(sc); ath9k_ps_restore(sc);
set_timer: set_timer:
spin_unlock(&sc->ani_lock);
/* /*
* Set timer interval based on previous results. * Set timer interval based on previous results.
* The interval must be the shortest necessary to satisfy ANI, * The interval must be the shortest necessary to satisfy ANI,
...@@ -1310,6 +1312,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) ...@@ -1310,6 +1312,7 @@ static int ath_init(u16 devid, struct ath_softc *sc)
spin_lock_init(&sc->wiphy_lock); spin_lock_init(&sc->wiphy_lock);
spin_lock_init(&sc->sc_resetlock); spin_lock_init(&sc->sc_resetlock);
spin_lock_init(&sc->sc_serial_rw); spin_lock_init(&sc->sc_serial_rw);
spin_lock_init(&sc->ani_lock);
mutex_init(&sc->mutex); mutex_init(&sc->mutex);
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
...@@ -2682,9 +2685,9 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw) ...@@ -2682,9 +2685,9 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
aphy->state = ATH_WIPHY_SCAN; aphy->state = ATH_WIPHY_SCAN;
ath9k_wiphy_pause_all_forced(sc, aphy); ath9k_wiphy_pause_all_forced(sc, aphy);
mutex_lock(&sc->mutex); spin_lock_bh(&sc->ani_lock);
sc->sc_flags |= SC_OP_SCANNING; sc->sc_flags |= SC_OP_SCANNING;
mutex_unlock(&sc->mutex); spin_unlock_bh(&sc->ani_lock);
} }
static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
...@@ -2692,11 +2695,11 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) ...@@ -2692,11 +2695,11 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
struct ath_wiphy *aphy = hw->priv; struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc; struct ath_softc *sc = aphy->sc;
mutex_lock(&sc->mutex); spin_lock_bh(&sc->ani_lock);
aphy->state = ATH_WIPHY_ACTIVE; aphy->state = ATH_WIPHY_ACTIVE;
sc->sc_flags &= ~SC_OP_SCANNING; sc->sc_flags &= ~SC_OP_SCANNING;
sc->sc_flags |= SC_OP_FULL_RESET; sc->sc_flags |= SC_OP_FULL_RESET;
mutex_unlock(&sc->mutex); spin_unlock_bh(&sc->ani_lock);
} }
struct ieee80211_ops ath9k_ops = { struct ieee80211_ops ath9k_ops = {
......
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