aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJiri Slaby <jirislaby@gmail.com>2008-07-15 11:44:20 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-07-29 16:36:27 -0400
commit274c7c3638cd027b46f76d0caef96c1bad8b6701 (patch)
tree8f487576932dd957d7de5f2f3054b2c39c7a850b /drivers
parent10488f8ad62be3b860bad74e60b4fe6ab87aece3 (diff)
Ath5k: flush work
Make sure that the irq is not in progress after stop. This means two things: - ensure the intr setting register is set by flushing posted values - call synchronize_irq() after that Also flush stop tx write, inform callers of the tx stop about still pending transfers (unsuccessful stop) and finally don't wait another 3ms in ath5k_rx_stop, since ath5k_hw_stop_rx_dma ensures transfer to be finished. Make sure all writes will be ordered in respect to locks by mmiowb(). Signed-off-by: Jiri Slaby <jirislaby@gmail.com> Acked-by: Nick Kossifidis <mickflemm@gmail.com> Cc: Luis R. Rodriguez <mcgrof@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath5k/base.c13
-rw-r--r--drivers/net/wireless/ath5k/hw.c4
2 files changed, 15 insertions, 2 deletions
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index c5bf8a2ef5cd..8e9afb3b3a56 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -43,7 +43,9 @@
43#include <linux/version.h> 43#include <linux/version.h>
44#include <linux/module.h> 44#include <linux/module.h>
45#include <linux/delay.h> 45#include <linux/delay.h>
46#include <linux/hardirq.h>
46#include <linux/if.h> 47#include <linux/if.h>
48#include <linux/io.h>
47#include <linux/netdevice.h> 49#include <linux/netdevice.h>
48#include <linux/cache.h> 50#include <linux/cache.h>
49#include <linux/pci.h> 51#include <linux/pci.h>
@@ -1249,6 +1251,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
1249 1251
1250 txq->link = &ds->ds_link; 1252 txq->link = &ds->ds_link;
1251 ath5k_hw_tx_start(ah, txq->qnum); 1253 ath5k_hw_tx_start(ah, txq->qnum);
1254 mmiowb();
1252 spin_unlock_bh(&txq->lock); 1255 spin_unlock_bh(&txq->lock);
1253 1256
1254 return 0; 1257 return 0;
@@ -1583,7 +1586,6 @@ ath5k_rx_stop(struct ath5k_softc *sc)
1583 ath5k_hw_stop_pcu_recv(ah); /* disable PCU */ 1586 ath5k_hw_stop_pcu_recv(ah); /* disable PCU */
1584 ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */ 1587 ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */
1585 ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */ 1588 ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */
1586 mdelay(3); /* 3ms is long enough for 1 frame */
1587 1589
1588 ath5k_debug_printrxbuffs(sc, ah); 1590 ath5k_debug_printrxbuffs(sc, ah);
1589 1591
@@ -2258,6 +2260,7 @@ ath5k_init(struct ath5k_softc *sc)
2258 2260
2259 ret = 0; 2261 ret = 0;
2260done: 2262done:
2263 mmiowb();
2261 mutex_unlock(&sc->lock); 2264 mutex_unlock(&sc->lock);
2262 return ret; 2265 return ret;
2263} 2266}
@@ -2290,6 +2293,7 @@ ath5k_stop_locked(struct ath5k_softc *sc)
2290 if (!test_bit(ATH_STAT_INVALID, sc->status)) { 2293 if (!test_bit(ATH_STAT_INVALID, sc->status)) {
2291 ath5k_led_off(sc); 2294 ath5k_led_off(sc);
2292 ath5k_hw_set_intr(ah, 0); 2295 ath5k_hw_set_intr(ah, 0);
2296 synchronize_irq(sc->pdev->irq);
2293 } 2297 }
2294 ath5k_txq_cleanup(sc); 2298 ath5k_txq_cleanup(sc);
2295 if (!test_bit(ATH_STAT_INVALID, sc->status)) { 2299 if (!test_bit(ATH_STAT_INVALID, sc->status)) {
@@ -2339,6 +2343,7 @@ ath5k_stop_hw(struct ath5k_softc *sc)
2339 } 2343 }
2340 } 2344 }
2341 ath5k_txbuf_free(sc, sc->bbuf); 2345 ath5k_txbuf_free(sc, sc->bbuf);
2346 mmiowb();
2342 mutex_unlock(&sc->lock); 2347 mutex_unlock(&sc->lock);
2343 2348
2344 del_timer_sync(&sc->calib_tim); 2349 del_timer_sync(&sc->calib_tim);
@@ -2804,6 +2809,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
2804 /* XXX: assoc id is set to 0 for now, mac80211 doesn't have 2809 /* XXX: assoc id is set to 0 for now, mac80211 doesn't have
2805 * a clean way of letting us retrieve this yet. */ 2810 * a clean way of letting us retrieve this yet. */
2806 ath5k_hw_set_associd(ah, ah->ah_bssid, 0); 2811 ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
2812 mmiowb();
2807 } 2813 }
2808 2814
2809 if (conf->changed & IEEE80211_IFCC_BEACON && 2815 if (conf->changed & IEEE80211_IFCC_BEACON &&
@@ -2992,6 +2998,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2992 } 2998 }
2993 2999
2994unlock: 3000unlock:
3001 mmiowb();
2995 mutex_unlock(&sc->lock); 3002 mutex_unlock(&sc->lock);
2996 return ret; 3003 return ret;
2997} 3004}
@@ -3065,8 +3072,10 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
3065 ret = ath5k_beacon_setup(sc, sc->bbuf); 3072 ret = ath5k_beacon_setup(sc, sc->bbuf);
3066 if (ret) 3073 if (ret)
3067 sc->bbuf->skb = NULL; 3074 sc->bbuf->skb = NULL;
3068 else 3075 else {
3069 ath5k_beacon_config(sc); 3076 ath5k_beacon_config(sc);
3077 mmiowb();
3078 }
3070 3079
3071end: 3080end:
3072 mutex_unlock(&sc->lock); 3081 mutex_unlock(&sc->lock);
diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c
index c6d12c53bda4..7ca87a557312 100644
--- a/drivers/net/wireless/ath5k/hw.c
+++ b/drivers/net/wireless/ath5k/hw.c
@@ -1440,6 +1440,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
1440 1440
1441 /* Stop queue */ 1441 /* Stop queue */
1442 ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); 1442 ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
1443 ath5k_hw_reg_read(ah, AR5K_CR);
1443 } else { 1444 } else {
1444 /* 1445 /*
1445 * Schedule TX disable and wait until queue is empty 1446 * Schedule TX disable and wait until queue is empty
@@ -1456,6 +1457,8 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
1456 1457
1457 /* Clear register */ 1458 /* Clear register */
1458 ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD); 1459 ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
1460 if (pending)
1461 return -EBUSY;
1459 } 1462 }
1460 1463
1461 /* TODO: Check for success else return error */ 1464 /* TODO: Check for success else return error */
@@ -1716,6 +1719,7 @@ enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask)
1716 1719
1717 /* ..re-enable interrupts */ 1720 /* ..re-enable interrupts */
1718 ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER); 1721 ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER);
1722 ath5k_hw_reg_read(ah, AR5K_IER);
1719 1723
1720 return old_mask; 1724 return old_mask;
1721} 1725}