diff mbox

[RFC] ath9k: Try all queues when looking for next packet to send.

Message ID 1294446455-19806-1-git-send-email-greearb@candelatech.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Ben Greear Jan. 8, 2011, 12:27 a.m. UTC
None
diff mbox

Patch

diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index e63de71..a7a8f8f 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -54,8 +54,8 @@  static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
 static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
 				struct ath_txq *txq, struct list_head *bf_q,
 				struct ath_tx_status *ts, int txok, int sendbar);
-static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
-			     struct list_head *head);
+static int ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
+			    struct list_head *head);
 static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
 static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
 			     int nframes, int nbad, int txok, bool update_rc);
@@ -789,18 +789,21 @@  static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 #undef PADBYTES
 }
 
-static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
-			      struct ath_atx_tid *tid)
+/* Return number of buffers set up for transmit. */
+static int ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
+			     struct ath_atx_tid *tid)
 {
 	struct ath_buf *bf;
 	enum ATH_AGGR_STATUS status;
 	struct ath_frame_info *fi;
 	struct list_head bf_q;
 	int aggr_len;
+	int cnt = 0;
+	int rv;
 
 	do {
 		if (list_empty(&tid->buf_q))
-			return;
+			return cnt;
 
 		INIT_LIST_HEAD(&bf_q);
 
@@ -811,7 +814,7 @@  static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
 		 * block-ack window is not open.
 		 */
 		if (list_empty(&bf_q))
-			break;
+			return cnt;
 
 		bf = list_first_entry(&bf_q, struct ath_buf, list);
 		bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
@@ -823,7 +826,11 @@  static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
 			bf->bf_state.bf_type &= ~BUF_AGGR;
 			ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
 			ath_buf_set_rate(sc, bf, fi->framelen);
-			ath_tx_txqaddbuf(sc, txq, &bf_q);
+			rv = ath_tx_txqaddbuf(sc, txq, &bf_q);
+			if (rv > 0) {
+				TX_STAT_INC(txq->axq_qnum, a_aggr);
+				cnt += rv;
+			}
 			continue;
 		}
 
@@ -835,11 +842,15 @@  static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
 		/* anchor last desc of aggregate */
 		ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
 
-		ath_tx_txqaddbuf(sc, txq, &bf_q);
-		TX_STAT_INC(txq->axq_qnum, a_aggr);
+		rv = ath_tx_txqaddbuf(sc, txq, &bf_q);
+		if (rv > 0) {
+			TX_STAT_INC(txq->axq_qnum, a_aggr);
+			cnt += rv;
+		}
 
 	} while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH &&
 		 status != ATH_AGGR_BAW_CLOSED);
+	return rv;
 }
 
 int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
@@ -1218,46 +1229,54 @@  void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
 	sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
 }
 
+/** For each axq_acq entry, for each tid, if we can transmit
+ * one, do so and break out.
+ */
 void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
 {
-	struct ath_atx_ac *ac;
+	struct ath_atx_ac *ac, *ac_tmp, *last;
 	struct ath_atx_tid *tid;
+	bool did_one = false;
 
 	if (list_empty(&txq->axq_acq))
 		return;
+	
+	last = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list);
+	list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
+		list_del(&ac->list);
+		ac->sched = false;
 
-	ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
-	list_del(&ac->list);
-	ac->sched = false;
-
-	do {
-		if (list_empty(&ac->tid_q))
-			return;
+		while (!list_empty(&ac->tid_q)) {
 
-		tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
-		list_del(&tid->list);
-		tid->sched = false;
+			tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
+			list_del(&tid->list);
+			tid->sched = false;
 
-		if (tid->paused)
-			continue;
+			if (tid->paused)
+				continue;
 
-		ath_tx_sched_aggr(sc, txq, tid);
+			if (ath_tx_sched_aggr(sc, txq, tid) > 0)
+				did_one = true;
 
-		/*
-		 * add tid to round-robin queue if more frames
-		 * are pending for the tid
-		 */
-		if (!list_empty(&tid->buf_q))
-			ath_tx_queue_tid(txq, tid);
+			/*
+			 * add tid to round-robin queue if more frames
+			 * are pending for the tid
+			 */
+			if (!list_empty(&tid->buf_q))
+				ath_tx_queue_tid(txq, tid);
 
-		break;
-	} while (!list_empty(&ac->tid_q));
+			break;
+		}
 
-	if (!list_empty(&ac->tid_q)) {
-		if (!ac->sched) {
-			ac->sched = true;
-			list_add_tail(&ac->list, &txq->axq_acq);
+		if (!list_empty(&ac->tid_q)) {
+			if (!ac->sched) {
+				ac->sched = true;
+				list_add_tail(&ac->list, &txq->axq_acq);
+			}
 		}
+
+		if (did_one || (ac == last))
+			return;
 	}
 }
 
@@ -1268,9 +1287,10 @@  void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
 /*
  * Insert a chain of ath_buf (descriptors) on a txq and
  * assume the descriptors are already chained together by caller.
+ * Return number of buffers sent to DMA.
  */
-static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
-			     struct list_head *head)
+static int ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
+			    struct list_head *head)
 {
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -1282,7 +1302,7 @@  static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 	 */
 
 	if (list_empty(head))
-		return;
+		return 0;
 
 	bf = list_first_entry(head, struct ath_buf, list);
 
@@ -1292,7 +1312,7 @@  static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
 		if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
 			list_splice_tail_init(head, &txq->txq_fifo_pending);
-			return;
+			return 0;
 		}
 		if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
 			ath_dbg(common, ATH_DBG_XMIT,
@@ -1326,6 +1346,7 @@  static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 	txq->axq_depth++;
 	if (bf_is_ampdu_not_probing(bf))
 		txq->axq_ampdu_depth++;
+	return 1;
 }
 
 static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,