2008/7/15 Jiri Slaby <jirislaby@xxxxxxxxx>: > 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@xxxxxxxxx> > Cc: Nick Kossifidis <mickflemm@xxxxxxxxx> > Cc: Luis R. Rodriguez <mcgrof@xxxxxxxxx> > --- > drivers/net/wireless/ath5k/base.c | 13 +++++++++++-- > 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 4d9ff97..4874a6f 100644 > --- a/drivers/net/wireless/ath5k/base.c > +++ b/drivers/net/wireless/ath5k/base.c > @@ -43,7 +43,9 @@ > #include <linux/version.h> > #include <linux/module.h> > #include <linux/delay.h> > +#include <linux/hardirq.h> > #include <linux/if.h> > +#include <linux/io.h> > #include <linux/netdevice.h> > #include <linux/cache.h> > #include <linux/pci.h> > @@ -1250,6 +1252,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) > > txq->link = &ds->ds_link; > ath5k_hw_tx_start(ah, txq->qnum); > + mmiowb(); > spin_unlock_bh(&txq->lock); > > return 0; > @@ -1584,7 +1587,6 @@ ath5k_rx_stop(struct ath5k_softc *sc) > ath5k_hw_stop_pcu_recv(ah); /* disable PCU */ > ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */ > ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */ > - mdelay(3); /* 3ms is long enough for 1 frame */ > > ath5k_debug_printrxbuffs(sc, ah); > > @@ -2259,6 +2261,7 @@ ath5k_init(struct ath5k_softc *sc) > > ret = 0; > done: > + mmiowb(); > mutex_unlock(&sc->lock); > return ret; > } > @@ -2291,6 +2294,7 @@ ath5k_stop_locked(struct ath5k_softc *sc) > if (!test_bit(ATH_STAT_INVALID, sc->status)) { > ath5k_led_off(sc); > ath5k_hw_set_intr(ah, 0); > + synchronize_irq(sc->pdev->irq); > } > ath5k_txq_cleanup(sc); > if (!test_bit(ATH_STAT_INVALID, sc->status)) { > @@ -2340,6 +2344,7 @@ ath5k_stop_hw(struct ath5k_softc *sc) > } > } > ath5k_txbuf_free(sc, sc->bbuf); > + mmiowb(); > mutex_unlock(&sc->lock); > > del_timer_sync(&sc->calib_tim); > @@ -2805,6 +2810,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 > * a clean way of letting us retrieve this yet. */ > ath5k_hw_set_associd(ah, ah->ah_bssid, 0); > + mmiowb(); > } > mutex_unlock(&sc->lock); > > @@ -2981,6 +2987,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, > } > > unlock: > + mmiowb(); > mutex_unlock(&sc->lock); > return ret; > } > @@ -3054,8 +3061,10 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) > ret = ath5k_beacon_setup(sc, sc->bbuf); > if (ret) > sc->bbuf->skb = NULL; > - else > + else { > ath5k_beacon_config(sc); > + mmiowb(); > + } > > end: > mutex_unlock(&sc->lock); > diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c > index c6d12c5..7ca87a5 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) > > /* Stop queue */ > ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); > + ath5k_hw_reg_read(ah, AR5K_CR); > } else { > /* > * 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) > > /* Clear register */ > ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD); > + if (pending) > + return -EBUSY; > } > > /* 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) > > /* ..re-enable interrupts */ > ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER); > + ath5k_hw_reg_read(ah, AR5K_IER); > > return old_mask; > } > -- > 1.5.6.2 > > Acked-by: Nick Kossifidis <mickflemm@xxxxxxxxx> -- GPG ID: 0xD21DB2DB As you read this post global entropy rises. Have Fun ;-) Nick -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html