aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k
diff options
context:
space:
mode:
authorLuis R. Rodriguez <lrodriguez@atheros.com>2010-10-20 19:07:06 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-10-27 15:42:58 -0400
commit5e848f789d60000d39d9a5f26ab02dbdd963f6cd (patch)
tree1489d23e7934767c48c4ba604e55cd447c497276 /drivers/net/wireless/ath/ath9k
parentb79b33c4baf2532aac2c0924dce5a738099b888c (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.c27
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c2
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
534void ath_flushrecv(struct ath_softc *sc) 534void 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
545static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) 543static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)