From: Felix Fietkau Date: Sun, 7 Apr 2013 22:05:45 +0000 (+0000) Subject: ath9k: fix a tx processing race condition on AR9300+ X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=c42c4837b9be2ca7437c6bb8d524c841dc349fbe;p=openwrt%2Fstaging%2Fdedeckeh.git ath9k: fix a tx processing race condition on AR9300+ Signed-off-by: Felix Fietkau SVN-Revision: 36267 --- diff --git a/package/mac80211/patches/300-pending_work.patch b/package/mac80211/patches/300-pending_work.patch index 7558c3d1a2..569bf7f06a 100644 --- a/package/mac80211/patches/300-pending_work.patch +++ b/package/mac80211/patches/300-pending_work.patch @@ -1036,3 +1036,77 @@ dev_err(priv->dev, "ath9k_htc: Please upgrade to FW version %d.%d\n", MAJOR_VERSION_REQ, MINOR_VERSION_REQ); return -EINVAL; +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -516,8 +516,7 @@ static void ath_tx_complete_aggr(struct + * not a holding desc. + */ + INIT_LIST_HEAD(&bf_head); +- if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) || +- bf_next != NULL || !bf_last->bf_stale) ++ if (bf_next != NULL || !bf_last->bf_stale) + list_move_tail(&bf->list, &bf_head); + + if (!txpending || (tid->state & AGGR_CLEANUP)) { +@@ -537,8 +536,7 @@ static void ath_tx_complete_aggr(struct + !txfail); + } else { + /* retry the un-acked ones */ +- if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && +- bf->bf_next == NULL && bf_last->bf_stale) { ++ if (bf->bf_next == NULL && bf_last->bf_stale) { + struct ath_buf *tbf; + + tbf = ath_clone_txbuf(sc, bf_last); +@@ -2264,6 +2262,7 @@ void ath_tx_edma_tasklet(struct ath_soft + struct ath_txq *txq; + struct ath_buf *bf, *lastbf; + struct list_head bf_head; ++ struct list_head *fifo_list; + int status; + + for (;;) { +@@ -2291,20 +2290,24 @@ void ath_tx_edma_tasklet(struct ath_soft + + TX_STAT_INC(txq->axq_qnum, txprocdesc); + +- if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) { ++ fifo_list = &txq->txq_fifo[txq->txq_tailidx]; ++ if (list_empty(fifo_list)) { + ath_txq_unlock(sc, txq); + return; + } + +- bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx], +- struct ath_buf, list); ++ bf = list_first_entry(fifo_list, struct ath_buf, list); ++ if (bf->bf_stale) { ++ list_del(&bf->list); ++ ath_tx_return_buffer(sc, bf); ++ bf = list_first_entry(fifo_list, struct ath_buf, list); ++ } ++ + lastbf = bf->bf_lastbf; + + INIT_LIST_HEAD(&bf_head); +- list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx], +- &lastbf->list); +- +- if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) { ++ if (list_is_last(&lastbf->list, fifo_list)) { ++ list_splice_tail_init(fifo_list, &bf_head); + INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH); + + if (!list_empty(&txq->axq_q)) { +@@ -2315,6 +2318,11 @@ void ath_tx_edma_tasklet(struct ath_soft + list_splice_tail_init(&txq->axq_q, &bf_q); + ath_tx_txqaddbuf(sc, txq, &bf_q, true); + } ++ } else { ++ lastbf->bf_stale = true; ++ if (bf != lastbf) ++ list_cut_position(&bf_head, fifo_list, ++ lastbf->list.prev); + } + + ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);