diff options
author | Bob Copeland <me@bobcopeland.com> | 2010-04-07 23:55:58 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-04-08 15:24:16 -0400 |
commit | a05988bbbef5ac2391fe696646f0b80708f33f2e (patch) | |
tree | 6c3bce02d933f0de99776104450bd9d442befcf9 | |
parent | 6b5d117eddc09cd976ad8030d715f4350f598a22 (diff) |
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 <me@bobcopeland.com>
Acked-by: Bruno Randolf <br1@einfach.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 11 |
1 files changed, 11 insertions, 0 deletions
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) | |||
2083 | list_for_each_entry_safe(bf, bf0, &txq->q, list) { | 2083 | list_for_each_entry_safe(bf, bf0, &txq->q, list) { |
2084 | ds = bf->desc; | 2084 | ds = bf->desc; |
2085 | 2085 | ||
2086 | /* | ||
2087 | * It's possible that the hardware can say the buffer is | ||
2088 | * completed when it hasn't yet loaded the ds_link from | ||
2089 | * host memory and moved on. If there are more TX | ||
2090 | * descriptors in the queue, wait for TXDP to change | ||
2091 | * before processing this one. | ||
2092 | */ | ||
2093 | if (ath5k_hw_get_txdp(sc->ah, txq->qnum) == bf->daddr && | ||
2094 | !list_is_last(&bf->list, &txq->q)) | ||
2095 | break; | ||
2096 | |||
2086 | ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); | 2097 | ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); |
2087 | if (unlikely(ret == -EINPROGRESS)) | 2098 | if (unlikely(ret == -EINPROGRESS)) |
2088 | break; | 2099 | break; |