diff options
author | Jiri Slaby <jirislaby@gmail.com> | 2008-07-15 11:44:20 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-07-29 16:36:27 -0400 |
commit | 274c7c3638cd027b46f76d0caef96c1bad8b6701 (patch) | |
tree | 8f487576932dd957d7de5f2f3054b2c39c7a850b /drivers/net/wireless/ath5k | |
parent | 10488f8ad62be3b860bad74e60b4fe6ab87aece3 (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/net/wireless/ath5k')
-rw-r--r-- | drivers/net/wireless/ath5k/base.c | 13 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/hw.c | 4 |
2 files changed, 15 insertions, 2 deletions
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index c5bf8a2ef5c..8e9afb3b3a5 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; |
2260 | done: | 2262 | done: |
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 | ||
2994 | unlock: | 3000 | unlock: |
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 | ||
3071 | end: | 3080 | end: |
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 c6d12c53bda..7ca87a55731 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 | } |