diff options
author | Luis R. Rodriguez <lrodriguez@atheros.com> | 2010-10-20 19:07:06 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-10-27 15:42:58 -0400 |
commit | 5e848f789d60000d39d9a5f26ab02dbdd963f6cd (patch) | |
tree | 1489d23e7934767c48c4ba604e55cd447c497276 /drivers/net/wireless/ath/ath9k | |
parent | b79b33c4baf2532aac2c0924dce5a738099b888c (diff) |
ath9k: lock reset and PCU start/stopping
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: stable@kernel.org
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>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 27 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 2 |
2 files changed, 27 insertions, 2 deletions
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 47df22b14cf8..b52f1cf8a603 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -241,6 +241,9 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
241 | */ | 241 | */ |
242 | ath9k_hw_set_interrupts(ah, 0); | 242 | ath9k_hw_set_interrupts(ah, 0); |
243 | ath_drain_all_txq(sc, false); | 243 | ath_drain_all_txq(sc, false); |
244 | |||
245 | spin_lock_bh(&sc->rx.pcu_lock); | ||
246 | |||
244 | stopped = ath_stoprecv(sc); | 247 | stopped = ath_stoprecv(sc); |
245 | 248 | ||
246 | /* XXX: do not flush receive queue here. We don't want | 249 | /* XXX: do not flush receive queue here. We don't want |
@@ -268,6 +271,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
268 | "reset status %d\n", | 271 | "reset status %d\n", |
269 | channel->center_freq, r); | 272 | channel->center_freq, r); |
270 | spin_unlock_bh(&sc->sc_resetlock); | 273 | spin_unlock_bh(&sc->sc_resetlock); |
274 | spin_unlock_bh(&sc->rx.pcu_lock); | ||
271 | goto ps_restore; | 275 | goto ps_restore; |
272 | } | 276 | } |
273 | spin_unlock_bh(&sc->sc_resetlock); | 277 | spin_unlock_bh(&sc->sc_resetlock); |
@@ -276,9 +280,12 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
276 | ath_print(common, ATH_DBG_FATAL, | 280 | ath_print(common, ATH_DBG_FATAL, |
277 | "Unable to restart recv logic\n"); | 281 | "Unable to restart recv logic\n"); |
278 | r = -EIO; | 282 | r = -EIO; |
283 | spin_unlock_bh(&sc->rx.pcu_lock); | ||
279 | goto ps_restore; | 284 | goto ps_restore; |
280 | } | 285 | } |
281 | 286 | ||
287 | spin_unlock_bh(&sc->rx.pcu_lock); | ||
288 | |||
282 | ath_update_txpow(sc); | 289 | ath_update_txpow(sc); |
283 | ath9k_hw_set_interrupts(ah, ah->imask); | 290 | ath9k_hw_set_interrupts(ah, ah->imask); |
284 | 291 | ||
@@ -876,6 +883,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
876 | if (!ah->curchan) | 883 | if (!ah->curchan) |
877 | ah->curchan = ath_get_curchannel(sc, sc->hw); | 884 | ah->curchan = ath_get_curchannel(sc, sc->hw); |
878 | 885 | ||
886 | spin_lock_bh(&sc->rx.pcu_lock); | ||
879 | spin_lock_bh(&sc->sc_resetlock); | 887 | spin_lock_bh(&sc->sc_resetlock); |
880 | r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); | 888 | r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); |
881 | if (r) { | 889 | if (r) { |
@@ -890,8 +898,10 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
890 | if (ath_startrecv(sc) != 0) { | 898 | if (ath_startrecv(sc) != 0) { |
891 | ath_print(common, ATH_DBG_FATAL, | 899 | ath_print(common, ATH_DBG_FATAL, |
892 | "Unable to restart recv logic\n"); | 900 | "Unable to restart recv logic\n"); |
901 | spin_unlock_bh(&sc->rx.pcu_lock); | ||
893 | return; | 902 | return; |
894 | } | 903 | } |
904 | spin_unlock_bh(&sc->rx.pcu_lock); | ||
895 | 905 | ||
896 | if (sc->sc_flags & SC_OP_BEACONS) | 906 | if (sc->sc_flags & SC_OP_BEACONS) |
897 | ath_beacon_config(sc, NULL); /* restart beacons */ | 907 | ath_beacon_config(sc, NULL); /* restart beacons */ |
@@ -930,6 +940,9 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
930 | ath9k_hw_set_interrupts(ah, 0); | 940 | ath9k_hw_set_interrupts(ah, 0); |
931 | 941 | ||
932 | ath_drain_all_txq(sc, false); /* clear pending tx frames */ | 942 | ath_drain_all_txq(sc, false); /* clear pending tx frames */ |
943 | |||
944 | spin_lock_bh(&sc->rx.pcu_lock); | ||
945 | |||
933 | ath_stoprecv(sc); /* turn off frame recv */ | 946 | ath_stoprecv(sc); /* turn off frame recv */ |
934 | ath_flushrecv(sc); /* flush recv queue */ | 947 | ath_flushrecv(sc); /* flush recv queue */ |
935 | 948 | ||
@@ -947,6 +960,9 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
947 | spin_unlock_bh(&sc->sc_resetlock); | 960 | spin_unlock_bh(&sc->sc_resetlock); |
948 | 961 | ||
949 | ath9k_hw_phy_disable(ah); | 962 | ath9k_hw_phy_disable(ah); |
963 | |||
964 | spin_unlock_bh(&sc->rx.pcu_lock); | ||
965 | |||
950 | ath9k_hw_configpcipowersave(ah, 1, 1); | 966 | ath9k_hw_configpcipowersave(ah, 1, 1); |
951 | ath9k_ps_restore(sc); | 967 | ath9k_ps_restore(sc); |
952 | ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); | 968 | ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); |
@@ -966,6 +982,9 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) | |||
966 | 982 | ||
967 | ath9k_hw_set_interrupts(ah, 0); | 983 | ath9k_hw_set_interrupts(ah, 0); |
968 | ath_drain_all_txq(sc, retry_tx); | 984 | ath_drain_all_txq(sc, retry_tx); |
985 | |||
986 | spin_lock_bh(&sc->rx.pcu_lock); | ||
987 | |||
969 | ath_stoprecv(sc); | 988 | ath_stoprecv(sc); |
970 | ath_flushrecv(sc); | 989 | ath_flushrecv(sc); |
971 | 990 | ||
@@ -980,6 +999,8 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) | |||
980 | ath_print(common, ATH_DBG_FATAL, | 999 | ath_print(common, ATH_DBG_FATAL, |
981 | "Unable to start recv logic\n"); | 1000 | "Unable to start recv logic\n"); |
982 | 1001 | ||
1002 | spin_unlock_bh(&sc->rx.pcu_lock); | ||
1003 | |||
983 | /* | 1004 | /* |
984 | * We may be doing a reset in response to a request | 1005 | * We may be doing a reset in response to a request |
985 | * that changes the channel so update any state that | 1006 | * that changes the channel so update any state that |
@@ -1142,6 +1163,7 @@ static int ath9k_start(struct ieee80211_hw *hw) | |||
1142 | * be followed by initialization of the appropriate bits | 1163 | * be followed by initialization of the appropriate bits |
1143 | * and then setup of the interrupt mask. | 1164 | * and then setup of the interrupt mask. |
1144 | */ | 1165 | */ |
1166 | spin_lock_bh(&sc->rx.pcu_lock); | ||
1145 | spin_lock_bh(&sc->sc_resetlock); | 1167 | spin_lock_bh(&sc->sc_resetlock); |
1146 | r = ath9k_hw_reset(ah, init_channel, ah->caldata, false); | 1168 | r = ath9k_hw_reset(ah, init_channel, ah->caldata, false); |
1147 | if (r) { | 1169 | if (r) { |
@@ -1150,6 +1172,7 @@ static int ath9k_start(struct ieee80211_hw *hw) | |||
1150 | "(freq %u MHz)\n", r, | 1172 | "(freq %u MHz)\n", r, |
1151 | curchan->center_freq); | 1173 | curchan->center_freq); |
1152 | spin_unlock_bh(&sc->sc_resetlock); | 1174 | spin_unlock_bh(&sc->sc_resetlock); |
1175 | spin_unlock_bh(&sc->rx.pcu_lock); | ||
1153 | goto mutex_unlock; | 1176 | goto mutex_unlock; |
1154 | } | 1177 | } |
1155 | spin_unlock_bh(&sc->sc_resetlock); | 1178 | spin_unlock_bh(&sc->sc_resetlock); |
@@ -1171,8 +1194,10 @@ static int ath9k_start(struct ieee80211_hw *hw) | |||
1171 | ath_print(common, ATH_DBG_FATAL, | 1194 | ath_print(common, ATH_DBG_FATAL, |
1172 | "Unable to start recv logic\n"); | 1195 | "Unable to start recv logic\n"); |
1173 | r = -EIO; | 1196 | r = -EIO; |
1197 | spin_unlock_bh(&sc->rx.pcu_lock); | ||
1174 | goto mutex_unlock; | 1198 | goto mutex_unlock; |
1175 | } | 1199 | } |
1200 | spin_unlock_bh(&sc->rx.pcu_lock); | ||
1176 | 1201 | ||
1177 | /* Setup our intr mask. */ | 1202 | /* Setup our intr mask. */ |
1178 | ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL | | 1203 | ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL | |
@@ -1371,12 +1396,14 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
1371 | * before setting the invalid flag. */ | 1396 | * before setting the invalid flag. */ |
1372 | ath9k_hw_set_interrupts(ah, 0); | 1397 | ath9k_hw_set_interrupts(ah, 0); |
1373 | 1398 | ||
1399 | spin_lock_bh(&sc->rx.pcu_lock); | ||
1374 | if (!(sc->sc_flags & SC_OP_INVALID)) { | 1400 | if (!(sc->sc_flags & SC_OP_INVALID)) { |
1375 | ath_drain_all_txq(sc, false); | 1401 | ath_drain_all_txq(sc, false); |
1376 | ath_stoprecv(sc); | 1402 | ath_stoprecv(sc); |
1377 | ath9k_hw_phy_disable(ah); | 1403 | ath9k_hw_phy_disable(ah); |
1378 | } else | 1404 | } else |
1379 | sc->rx.rxlink = NULL; | 1405 | sc->rx.rxlink = NULL; |
1406 | spin_unlock_bh(&sc->rx.pcu_lock); | ||
1380 | 1407 | ||
1381 | /* disable HAL and put h/w to sleep */ | 1408 | /* disable HAL and put h/w to sleep */ |
1382 | ath9k_hw_disable(ah); | 1409 | ath9k_hw_disable(ah); |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 67fe1f8a6439..fddb0129bb57 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -533,13 +533,11 @@ bool ath_stoprecv(struct ath_softc *sc) | |||
533 | 533 | ||
534 | void ath_flushrecv(struct ath_softc *sc) | 534 | void ath_flushrecv(struct ath_softc *sc) |
535 | { | 535 | { |
536 | spin_lock_bh(&sc->rx.pcu_lock); | ||
537 | sc->sc_flags |= SC_OP_RXFLUSH; | 536 | sc->sc_flags |= SC_OP_RXFLUSH; |
538 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | 537 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) |
539 | ath_rx_tasklet(sc, 1, true); | 538 | ath_rx_tasklet(sc, 1, true); |
540 | ath_rx_tasklet(sc, 1, false); | 539 | ath_rx_tasklet(sc, 1, false); |
541 | sc->sc_flags &= ~SC_OP_RXFLUSH; | 540 | sc->sc_flags &= ~SC_OP_RXFLUSH; |
542 | spin_unlock_bh(&sc->rx.pcu_lock); | ||
543 | } | 541 | } |
544 | 542 | ||
545 | static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) | 543 | static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) |