mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-11 05:17:10 +09:00
ath9k: lock reset and PCU start/stopping
commit 5e848f789d upstream.
Apart from locking the start and stop PCU we need
to ensure we also content starting and stopping the PCU
between hardware resets.
This is part of a series that will help resolve the bug:
https://bugzilla.kernel.org/show_bug.cgi?id=14624
For more details about this issue refer to:
http://marc.info/?l=linux-wireless&m=128629803703756&w=2
Cc: Ben Greear <greearb@candelatech.com>
Cc: Kyungwan Nam <kyungwan.nam@atheros.com>
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Tested-by: Ben Greear <greearb@candelatech.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
a0d37381be
commit
f8245147e3
@@ -213,6 +213,9 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
||||
*/
|
||||
ath9k_hw_set_interrupts(ah, 0);
|
||||
ath_drain_all_txq(sc, false);
|
||||
|
||||
spin_lock_bh(&sc->rx.pcu_lock);
|
||||
|
||||
stopped = ath_stoprecv(sc);
|
||||
|
||||
/* XXX: do not flush receive queue here. We don't want
|
||||
@@ -239,6 +242,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
||||
"reset status %d\n",
|
||||
channel->center_freq, r);
|
||||
spin_unlock_bh(&sc->sc_resetlock);
|
||||
spin_unlock_bh(&sc->rx.pcu_lock);
|
||||
goto ps_restore;
|
||||
}
|
||||
spin_unlock_bh(&sc->sc_resetlock);
|
||||
@@ -247,9 +251,12 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"Unable to restart recv logic\n");
|
||||
r = -EIO;
|
||||
spin_unlock_bh(&sc->rx.pcu_lock);
|
||||
goto ps_restore;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&sc->rx.pcu_lock);
|
||||
|
||||
ath_cache_conf_rate(sc, &hw->conf);
|
||||
ath_update_txpow(sc);
|
||||
ath9k_hw_set_interrupts(ah, ah->imask);
|
||||
@@ -840,6 +847,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
|
||||
if (!ah->curchan)
|
||||
ah->curchan = ath_get_curchannel(sc, sc->hw);
|
||||
|
||||
spin_lock_bh(&sc->rx.pcu_lock);
|
||||
spin_lock_bh(&sc->sc_resetlock);
|
||||
r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
|
||||
if (r) {
|
||||
@@ -854,8 +862,10 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
|
||||
if (ath_startrecv(sc) != 0) {
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"Unable to restart recv logic\n");
|
||||
spin_unlock_bh(&sc->rx.pcu_lock);
|
||||
return;
|
||||
}
|
||||
spin_unlock_bh(&sc->rx.pcu_lock);
|
||||
|
||||
if (sc->sc_flags & SC_OP_BEACONS)
|
||||
ath_beacon_config(sc, NULL); /* restart beacons */
|
||||
@@ -894,6 +904,9 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
|
||||
ath9k_hw_set_interrupts(ah, 0);
|
||||
|
||||
ath_drain_all_txq(sc, false); /* clear pending tx frames */
|
||||
|
||||
spin_lock_bh(&sc->rx.pcu_lock);
|
||||
|
||||
ath_stoprecv(sc); /* turn off frame recv */
|
||||
ath_flushrecv(sc); /* flush recv queue */
|
||||
|
||||
@@ -911,6 +924,9 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
|
||||
spin_unlock_bh(&sc->sc_resetlock);
|
||||
|
||||
ath9k_hw_phy_disable(ah);
|
||||
|
||||
spin_unlock_bh(&sc->rx.pcu_lock);
|
||||
|
||||
ath9k_hw_configpcipowersave(ah, 1, 1);
|
||||
ath9k_ps_restore(sc);
|
||||
ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
|
||||
@@ -930,6 +946,9 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
|
||||
|
||||
ath9k_hw_set_interrupts(ah, 0);
|
||||
ath_drain_all_txq(sc, retry_tx);
|
||||
|
||||
spin_lock_bh(&sc->rx.pcu_lock);
|
||||
|
||||
ath_stoprecv(sc);
|
||||
ath_flushrecv(sc);
|
||||
|
||||
@@ -944,6 +963,8 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"Unable to start recv logic\n");
|
||||
|
||||
spin_unlock_bh(&sc->rx.pcu_lock);
|
||||
|
||||
/*
|
||||
* We may be doing a reset in response to a request
|
||||
* that changes the channel so update any state that
|
||||
@@ -1108,6 +1129,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
|
||||
* be followed by initialization of the appropriate bits
|
||||
* and then setup of the interrupt mask.
|
||||
*/
|
||||
spin_lock_bh(&sc->rx.pcu_lock);
|
||||
spin_lock_bh(&sc->sc_resetlock);
|
||||
r = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
|
||||
if (r) {
|
||||
@@ -1116,6 +1138,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
|
||||
"(freq %u MHz)\n", r,
|
||||
curchan->center_freq);
|
||||
spin_unlock_bh(&sc->sc_resetlock);
|
||||
spin_unlock_bh(&sc->rx.pcu_lock);
|
||||
goto mutex_unlock;
|
||||
}
|
||||
spin_unlock_bh(&sc->sc_resetlock);
|
||||
@@ -1137,8 +1160,10 @@ static int ath9k_start(struct ieee80211_hw *hw)
|
||||
ath_print(common, ATH_DBG_FATAL,
|
||||
"Unable to start recv logic\n");
|
||||
r = -EIO;
|
||||
spin_unlock_bh(&sc->rx.pcu_lock);
|
||||
goto mutex_unlock;
|
||||
}
|
||||
spin_unlock_bh(&sc->rx.pcu_lock);
|
||||
|
||||
/* Setup our intr mask. */
|
||||
ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL |
|
||||
@@ -1340,12 +1365,14 @@ static void ath9k_stop(struct ieee80211_hw *hw)
|
||||
* before setting the invalid flag. */
|
||||
ath9k_hw_set_interrupts(ah, 0);
|
||||
|
||||
spin_lock_bh(&sc->rx.pcu_lock);
|
||||
if (!(sc->sc_flags & SC_OP_INVALID)) {
|
||||
ath_drain_all_txq(sc, false);
|
||||
ath_stoprecv(sc);
|
||||
ath9k_hw_phy_disable(ah);
|
||||
} else
|
||||
sc->rx.rxlink = NULL;
|
||||
spin_unlock_bh(&sc->rx.pcu_lock);
|
||||
|
||||
/* disable HAL and put h/w to sleep */
|
||||
ath9k_hw_disable(ah);
|
||||
|
||||
@@ -523,13 +523,11 @@ bool ath_stoprecv(struct ath_softc *sc)
|
||||
|
||||
void ath_flushrecv(struct ath_softc *sc)
|
||||
{
|
||||
spin_lock_bh(&sc->rx.pcu_lock);
|
||||
sc->sc_flags |= SC_OP_RXFLUSH;
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
|
||||
ath_rx_tasklet(sc, 1, true);
|
||||
ath_rx_tasklet(sc, 1, false);
|
||||
sc->sc_flags &= ~SC_OP_RXFLUSH;
|
||||
spin_unlock_bh(&sc->rx.pcu_lock);
|
||||
}
|
||||
|
||||
static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
|
||||
|
||||
Reference in New Issue
Block a user