From: Bob Copeland Date: Thu, 8 Apr 2010 03:55:58 +0000 (-0400) Subject: ath5k: fix race condition in tx desc processing X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=a05988bbbef5ac2391fe696646f0b80708f33f2e;p=linux-beck.git ath5k: fix race condition in tx desc processing As pointed out by Benoit Papillault, there is a potential race condition between the host and the hardware in reading the next link in the transmit descriptor list: cpu0 hw tx for buf completed raise tx_ok interrupt process buf buf->ds_link = 0 read buf->ds_link This change checks txdp before processing a descriptor (if there are any subsequent descriptors) to see if hardware moved on. We'll then process this descriptor on the next tasklet. Signed-off-by: Bob Copeland Acked-by: Bruno Randolf Signed-off-by: John W. Linville --- diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 38c41e3c7988..f7f57c1cca7d 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2083,6 +2083,17 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) list_for_each_entry_safe(bf, bf0, &txq->q, list) { ds = bf->desc; + /* + * It's possible that the hardware can say the buffer is + * completed when it hasn't yet loaded the ds_link from + * host memory and moved on. If there are more TX + * descriptors in the queue, wait for TXDP to change + * before processing this one. + */ + if (ath5k_hw_get_txdp(sc->ah, txq->qnum) == bf->daddr && + !list_is_last(&bf->list, &txq->q)) + break; + ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); if (unlikely(ret == -EINPROGRESS)) break;