Commit 274c7c36 authored by Jiri Slaby's avatar Jiri Slaby Committed by John W. Linville

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: default avatarJiri Slaby <jirislaby@gmail.com>
Acked-by: default avatarNick Kossifidis <mickflemm@gmail.com>
Cc: Luis R. Rodriguez <mcgrof@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 10488f8a
...@@ -43,7 +43,9 @@ ...@@ -43,7 +43,9 @@
#include <linux/version.h> #include <linux/version.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/hardirq.h>
#include <linux/if.h> #include <linux/if.h>
#include <linux/io.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/cache.h> #include <linux/cache.h>
#include <linux/pci.h> #include <linux/pci.h>
...@@ -1249,6 +1251,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) ...@@ -1249,6 +1251,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
txq->link = &ds->ds_link; txq->link = &ds->ds_link;
ath5k_hw_tx_start(ah, txq->qnum); ath5k_hw_tx_start(ah, txq->qnum);
mmiowb();
spin_unlock_bh(&txq->lock); spin_unlock_bh(&txq->lock);
return 0; return 0;
...@@ -1583,7 +1586,6 @@ ath5k_rx_stop(struct ath5k_softc *sc) ...@@ -1583,7 +1586,6 @@ ath5k_rx_stop(struct ath5k_softc *sc)
ath5k_hw_stop_pcu_recv(ah); /* disable PCU */ ath5k_hw_stop_pcu_recv(ah); /* disable PCU */
ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */ ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */
ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */ ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */
mdelay(3); /* 3ms is long enough for 1 frame */
ath5k_debug_printrxbuffs(sc, ah); ath5k_debug_printrxbuffs(sc, ah);
...@@ -2258,6 +2260,7 @@ ath5k_init(struct ath5k_softc *sc) ...@@ -2258,6 +2260,7 @@ ath5k_init(struct ath5k_softc *sc)
ret = 0; ret = 0;
done: done:
mmiowb();
mutex_unlock(&sc->lock); mutex_unlock(&sc->lock);
return ret; return ret;
} }
...@@ -2290,6 +2293,7 @@ ath5k_stop_locked(struct ath5k_softc *sc) ...@@ -2290,6 +2293,7 @@ ath5k_stop_locked(struct ath5k_softc *sc)
if (!test_bit(ATH_STAT_INVALID, sc->status)) { if (!test_bit(ATH_STAT_INVALID, sc->status)) {
ath5k_led_off(sc); ath5k_led_off(sc);
ath5k_hw_set_intr(ah, 0); ath5k_hw_set_intr(ah, 0);
synchronize_irq(sc->pdev->irq);
} }
ath5k_txq_cleanup(sc); ath5k_txq_cleanup(sc);
if (!test_bit(ATH_STAT_INVALID, sc->status)) { if (!test_bit(ATH_STAT_INVALID, sc->status)) {
...@@ -2339,6 +2343,7 @@ ath5k_stop_hw(struct ath5k_softc *sc) ...@@ -2339,6 +2343,7 @@ ath5k_stop_hw(struct ath5k_softc *sc)
} }
} }
ath5k_txbuf_free(sc, sc->bbuf); ath5k_txbuf_free(sc, sc->bbuf);
mmiowb();
mutex_unlock(&sc->lock); mutex_unlock(&sc->lock);
del_timer_sync(&sc->calib_tim); del_timer_sync(&sc->calib_tim);
...@@ -2804,6 +2809,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ...@@ -2804,6 +2809,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
/* XXX: assoc id is set to 0 for now, mac80211 doesn't have /* XXX: assoc id is set to 0 for now, mac80211 doesn't have
* a clean way of letting us retrieve this yet. */ * a clean way of letting us retrieve this yet. */
ath5k_hw_set_associd(ah, ah->ah_bssid, 0); ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
mmiowb();
} }
if (conf->changed & IEEE80211_IFCC_BEACON && if (conf->changed & IEEE80211_IFCC_BEACON &&
...@@ -2992,6 +2998,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -2992,6 +2998,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
} }
unlock: unlock:
mmiowb();
mutex_unlock(&sc->lock); mutex_unlock(&sc->lock);
return ret; return ret;
} }
...@@ -3065,8 +3072,10 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) ...@@ -3065,8 +3072,10 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
ret = ath5k_beacon_setup(sc, sc->bbuf); ret = ath5k_beacon_setup(sc, sc->bbuf);
if (ret) if (ret)
sc->bbuf->skb = NULL; sc->bbuf->skb = NULL;
else else {
ath5k_beacon_config(sc); ath5k_beacon_config(sc);
mmiowb();
}
end: end:
mutex_unlock(&sc->lock); mutex_unlock(&sc->lock);
......
...@@ -1440,6 +1440,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) ...@@ -1440,6 +1440,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
/* Stop queue */ /* Stop queue */
ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
ath5k_hw_reg_read(ah, AR5K_CR);
} else { } else {
/* /*
* Schedule TX disable and wait until queue is empty * 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,6 +1457,8 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
/* Clear register */ /* Clear register */
ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD); ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
if (pending)
return -EBUSY;
} }
/* TODO: Check for success else return error */ /* 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,6 +1719,7 @@ enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask)
/* ..re-enable interrupts */ /* ..re-enable interrupts */
ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER); ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER);
ath5k_hw_reg_read(ah, AR5K_IER);
return old_mask; return old_mask;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment