|
|
@@ -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);
|