diff options
| author | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2011-08-04 00:35:20 +0000 | 
|---|---|---|
| committer | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2011-08-04 00:35:20 +0000 | 
| commit | fc4de04076d8c4a9cef0d354b9b1649de50b3eb7 (patch) | |
| tree | 8825f5719213f6db1ec4ce05382952c597aedb34 | |
| parent | a040c13eb6c63e1799ce17ad8d3dd2267d9ae4b3 (diff) | |
ath9k: add some code to control internal driver queue length limits
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@27890 3c298f89-4303-0410-b956-a3cf2f4a3e73
| -rw-r--r-- | package/mac80211/patches/573-ath9k_aggr_queue_cleanup.patch | 281 | ||||
| -rw-r--r-- | package/mac80211/patches/574-ath9k_limit_qlen.patch | 176 | 
2 files changed, 457 insertions, 0 deletions
diff --git a/package/mac80211/patches/573-ath9k_aggr_queue_cleanup.patch b/package/mac80211/patches/573-ath9k_aggr_queue_cleanup.patch new file mode 100644 index 000000000..2bec9dc3a --- /dev/null +++ b/package/mac80211/patches/573-ath9k_aggr_queue_cleanup.patch @@ -0,0 +1,281 @@ +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -200,6 +200,7 @@ struct ath_atx_ac { + }; +  + struct ath_frame_info { ++	struct ath_buf *bf; + 	int framelen; + 	u32 keyix; + 	enum ath9k_key_type keytype; +@@ -230,7 +231,7 @@ struct ath_buf { +  + struct ath_atx_tid { + 	struct list_head list; +-	struct list_head buf_q; ++	struct sk_buff_head buf_q; + 	struct ath_node *an; + 	struct ath_atx_ac *ac; + 	unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)]; +--- a/drivers/net/wireless/ath/ath9k/debug.c ++++ b/drivers/net/wireless/ath/ath9k/debug.c +@@ -711,7 +711,7 @@ static ssize_t read_file_stations(struct + 					" tid: %p %s %s %i %p %p\n", + 					tid, tid->sched ? "sched" : "idle", + 					tid->paused ? "paused" : "running", +-					list_empty(&tid->buf_q), ++					skb_queue_empty(&tid->buf_q), + 					tid->an, tid->ac); + 			if (len >= size) + 				goto done; +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -128,7 +128,7 @@ static void ath_tx_resume_tid(struct ath + 	spin_lock_bh(&txq->axq_lock); + 	tid->paused = false; +  +-	if (list_empty(&tid->buf_q)) ++	if (skb_queue_empty(&tid->buf_q)) + 		goto unlock; +  + 	ath_tx_queue_tid(txq, tid); +@@ -148,6 +148,7 @@ static struct ath_frame_info *get_frame_ + static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) + { + 	struct ath_txq *txq = tid->ac->txq; ++	struct sk_buff *skb; + 	struct ath_buf *bf; + 	struct list_head bf_head; + 	struct ath_tx_status ts; +@@ -158,12 +159,13 @@ static void ath_tx_flush_tid(struct ath_ + 	memset(&ts, 0, sizeof(ts)); + 	spin_lock_bh(&txq->axq_lock); +  +-	while (!list_empty(&tid->buf_q)) { +-		bf = list_first_entry(&tid->buf_q, struct ath_buf, list); +-		list_move_tail(&bf->list, &bf_head); ++	while ((skb = __skb_dequeue(&tid->buf_q))) { ++		fi = get_frame_info(skb); ++		bf = fi->bf; ++ ++		list_add_tail(&bf->list, &bf_head); +  + 		spin_unlock_bh(&txq->axq_lock); +-		fi = get_frame_info(bf->bf_mpdu); + 		if (fi->retries) { + 			ath_tx_update_baw(sc, tid, fi->seqno); + 			ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); +@@ -218,6 +220,7 @@ static void ath_tid_drain(struct ath_sof + 			  struct ath_atx_tid *tid) +  + { ++	struct sk_buff *skb; + 	struct ath_buf *bf; + 	struct list_head bf_head; + 	struct ath_tx_status ts; +@@ -226,14 +229,12 @@ static void ath_tid_drain(struct ath_sof + 	memset(&ts, 0, sizeof(ts)); + 	INIT_LIST_HEAD(&bf_head); +  +-	for (;;) { +-		if (list_empty(&tid->buf_q)) +-			break; ++	while ((skb = __skb_dequeue(&tid->buf_q))) { ++		fi = get_frame_info(skb); ++		bf = fi->bf; +  +-		bf = list_first_entry(&tid->buf_q, struct ath_buf, list); +-		list_move_tail(&bf->list, &bf_head); ++		list_add_tail(&bf->list, &bf_head); +  +-		fi = get_frame_info(bf->bf_mpdu); + 		if (fi->retries) + 			ath_tx_update_baw(sc, tid, fi->seqno); +  +@@ -351,7 +352,8 @@ static void ath_tx_complete_aggr(struct  + 	struct ieee80211_tx_info *tx_info; + 	struct ath_atx_tid *tid = NULL; + 	struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; +-	struct list_head bf_head, bf_pending; ++	struct list_head bf_head; ++	struct sk_buff_head bf_pending; + 	u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0; + 	u32 ba[WME_BA_BMP_SIZE >> 5]; + 	int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; +@@ -428,8 +430,7 @@ static void ath_tx_complete_aggr(struct  + 		} + 	} +  +-	INIT_LIST_HEAD(&bf_pending); +-	INIT_LIST_HEAD(&bf_head); ++	__skb_queue_head_init(&bf_pending); +  + 	ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad); + 	while (bf) { +@@ -474,10 +475,10 @@ static void ath_tx_complete_aggr(struct  + 		 * Make sure the last desc is reclaimed if it + 		 * not a holding desc. + 		 */ +-		if (!bf_last->bf_stale || bf_next != NULL) ++		INIT_LIST_HEAD(&bf_head); ++		if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) || ++		    bf_next != NULL || !bf_last->bf_stale) + 			list_move_tail(&bf->list, &bf_head); +-		else +-			INIT_LIST_HEAD(&bf_head); +  + 		if (!txpending || (tid->state & AGGR_CLEANUP)) { + 			/* +@@ -528,7 +529,7 @@ static void ath_tx_complete_aggr(struct  +  + 					ath9k_hw_cleartxdesc(sc->sc_ah, + 							     tbf->bf_desc); +-					list_add_tail(&tbf->list, &bf_head); ++					fi->bf = tbf; + 				} else { + 					/* + 					 * Clear descriptor status words for +@@ -543,21 +544,21 @@ static void ath_tx_complete_aggr(struct  + 			 * Put this buffer to the temporary pending + 			 * queue to retain ordering + 			 */ +-			list_splice_tail_init(&bf_head, &bf_pending); ++			__skb_queue_tail(&bf_pending, skb); + 		} +  + 		bf = bf_next; + 	} +  + 	/* prepend un-acked frames to the beginning of the pending frame queue */ +-	if (!list_empty(&bf_pending)) { ++	if (!skb_queue_empty(&bf_pending)) { + 		if (an->sleeping) + 			ieee80211_sta_set_tim(sta); +  + 		spin_lock_bh(&txq->axq_lock); + 		if (clear_filter) + 			tid->ac->clear_ps_filter = true; +-		list_splice(&bf_pending, &tid->buf_q); ++		skb_queue_splice(&bf_pending, &tid->buf_q); + 		if (!an->sleeping) + 			ath_tx_queue_tid(txq, tid); + 		spin_unlock_bh(&txq->axq_lock); +@@ -722,19 +723,22 @@ static enum ATH_AGGR_STATUS ath_tx_form_ + 					     int *aggr_len) + { + #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) +-	struct ath_buf *bf, *bf_first, *bf_prev = NULL; ++	struct ath_buf *bf, *bf_first = NULL, *bf_prev = NULL; + 	int rl = 0, nframes = 0, ndelim, prev_al = 0; + 	u16 aggr_limit = 0, al = 0, bpad = 0, + 		al_delta, h_baw = tid->baw_size / 2; + 	enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; + 	struct ieee80211_tx_info *tx_info; + 	struct ath_frame_info *fi; +- +-	bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list); ++	struct sk_buff *skb; +  + 	do { +-		bf = list_first_entry(&tid->buf_q, struct ath_buf, list); +-		fi = get_frame_info(bf->bf_mpdu); ++		skb = skb_peek(&tid->buf_q); ++		fi = get_frame_info(skb); ++		bf = fi->bf; ++ ++		if (!bf_first) ++			bf_first = bf; +  + 		/* do not step over block-ack window */ + 		if (!BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno)) { +@@ -785,7 +789,9 @@ static enum ATH_AGGR_STATUS ath_tx_form_ + 		if (!fi->retries) + 			ath_tx_addto_baw(sc, tid, fi->seqno); + 		ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim); +-		list_move_tail(&bf->list, bf_q); ++ ++		__skb_unlink(skb, &tid->buf_q); ++		list_add_tail(&bf->list, bf_q); + 		if (bf_prev) { + 			bf_prev->bf_next = bf; + 			ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc, +@@ -793,7 +799,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_ + 		} + 		bf_prev = bf; +  +-	} while (!list_empty(&tid->buf_q)); ++	} while (!skb_queue_empty(&tid->buf_q)); +  + 	*aggr_len = al; +  +@@ -811,7 +817,7 @@ static void ath_tx_sched_aggr(struct ath + 	int aggr_len; +  + 	do { +-		if (list_empty(&tid->buf_q)) ++		if (skb_queue_empty(&tid->buf_q)) + 			return; +  + 		INIT_LIST_HEAD(&bf_q); +@@ -933,7 +939,7 @@ bool ath_tx_aggr_sleep(struct ath_softc  +  + 		spin_lock_bh(&txq->axq_lock); +  +-		if (!list_empty(&tid->buf_q)) ++		if (!skb_queue_empty(&tid->buf_q)) + 			buffered = true; +  + 		tid->sched = false; +@@ -966,7 +972,7 @@ void ath_tx_aggr_wakeup(struct ath_softc + 		spin_lock_bh(&txq->axq_lock); + 		ac->clear_ps_filter = true; +  +-		if (!list_empty(&tid->buf_q) && !tid->paused) { ++		if (!skb_queue_empty(&tid->buf_q) && !tid->paused) { + 			ath_tx_queue_tid(txq, tid); + 			ath_txq_schedule(sc, txq); + 		} +@@ -1308,7 +1314,7 @@ void ath_txq_schedule(struct ath_softc * + 			 * add tid to round-robin queue if more frames + 			 * are pending for the tid + 			 */ +-			if (!list_empty(&tid->buf_q)) ++			if (!skb_queue_empty(&tid->buf_q)) + 				ath_tx_queue_tid(txq, tid); +  + 			if (tid == last_tid || +@@ -1414,7 +1420,7 @@ static void ath_tx_send_ampdu(struct ath + 	 * - seqno is not within block-ack window + 	 * - h/w queue depth exceeds low water mark + 	 */ +-	if (!list_empty(&tid->buf_q) || tid->paused || ++	if (!skb_queue_empty(&tid->buf_q) || tid->paused || + 	    !BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno) || + 	    txctl->txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) { + 		/* +@@ -1422,7 +1428,7 @@ static void ath_tx_send_ampdu(struct ath + 		 * for aggregation. + 		 */ + 		TX_STAT_INC(txctl->txq->axq_qnum, a_queued_sw); +-		list_add_tail(&bf->list, &tid->buf_q); ++		__skb_queue_tail(&tid->buf_q, bf->bf_mpdu); + 		if (!txctl->an || !txctl->an->sleeping) + 			ath_tx_queue_tid(txctl->txq, tid); + 		return; +@@ -1753,6 +1759,7 @@ static struct ath_buf *ath_tx_setup_buff + 			    bf->bf_buf_addr, + 			    txq->axq_qnum); +  ++	fi->bf = bf; +  + 	return bf; + } +@@ -2364,7 +2371,7 @@ void ath_tx_node_init(struct ath_softc * + 		tid->sched     = false; + 		tid->paused    = false; + 		tid->state &= ~AGGR_CLEANUP; +-		INIT_LIST_HEAD(&tid->buf_q); ++		__skb_queue_head_init(&tid->buf_q); + 		acno = TID_TO_WME_AC(tidno); + 		tid->ac = &an->ac[acno]; + 		tid->state &= ~AGGR_ADDBA_COMPLETE; diff --git a/package/mac80211/patches/574-ath9k_limit_qlen.patch b/package/mac80211/patches/574-ath9k_limit_qlen.patch new file mode 100644 index 000000000..77f1f5c8a --- /dev/null +++ b/package/mac80211/patches/574-ath9k_limit_qlen.patch @@ -0,0 +1,176 @@ +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -235,6 +235,7 @@ struct ath_atx_tid { + 	struct ath_node *an; + 	struct ath_atx_ac *ac; + 	unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)]; ++	int buf_pending; + 	u16 seq_start; + 	u16 seq_next; + 	u16 baw_size; +@@ -283,6 +284,9 @@ struct ath_tx_control { +  *  (axq_qnum). +  */ + struct ath_tx { ++	u32 qlen_single; ++	u32 qlen_aggr; ++ + 	u16 seq_no; + 	u32 txqsetup; + 	spinlock_t txbuflock; +--- a/drivers/net/wireless/ath/ath9k/debug.c ++++ b/drivers/net/wireless/ath/ath9k/debug.c +@@ -1250,6 +1250,10 @@ int ath9k_init_debug(struct ath_hw *ah) + 			    sc, &fops_wiphy); + 	debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc, + 			    &fops_xmit); ++	debugfs_create_u32("qlen_single", S_IRUSR | S_IWUSR, ++			   sc->debug.debugfs_phy, &sc->tx.qlen_single); ++	debugfs_create_u32("qlen_aggr", S_IRUSR | S_IWUSR, ++			   sc->debug.debugfs_phy, &sc->tx.qlen_aggr); + 	debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc, + 			    &fops_stations); + 	debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc, +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -339,6 +339,14 @@ static void ath_tx_count_frames(struct a + 	} + } +  ++static struct ath_atx_tid *ath_get_tid(struct ath_node *an, struct sk_buff *skb) ++{ ++	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; ++	u8 tidno; ++ ++	tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; ++	return ATH_AN_2_TID(an, tidno); ++} +  + static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, + 				 struct ath_buf *bf, struct list_head *bf_q, +@@ -433,6 +441,8 @@ static void ath_tx_complete_aggr(struct  + 	__skb_queue_head_init(&bf_pending); +  + 	ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad); ++	tid->buf_pending -= nframes; ++ + 	while (bf) { + 		txfail = txpending = 0; + 		bf_next = bf->bf_next; +@@ -790,6 +800,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_ + 			ath_tx_addto_baw(sc, tid, fi->seqno); + 		ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim); +  ++		tid->buf_pending++; + 		__skb_unlink(skb, &tid->buf_q); + 		list_add_tail(&bf->list, bf_q); + 		if (bf_prev) { +@@ -1441,6 +1452,8 @@ static void ath_tx_send_ampdu(struct ath + 	if (!fi->retries) + 		ath_tx_addto_baw(sc, tid, fi->seqno); +  ++	tid->buf_pending++; ++ + 	/* Queue to h/w without aggregation */ + 	TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw); + 	bf->bf_lastbf = bf; +@@ -1505,7 +1518,6 @@ static void setup_frame_info(struct ieee + 	struct ath_atx_tid *tid; + 	enum ath9k_key_type keytype; + 	u16 seqno = 0; +-	u8 tidno; +  + 	keytype = ath9k_cmn_get_hw_crypto_keytype(skb); +  +@@ -1516,13 +1528,11 @@ static void setup_frame_info(struct ieee + 	if (an && ieee80211_is_data_qos(hdr->frame_control) && + 		conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) { +  +-		tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; +- + 		/* + 		 * Override seqno set by upper layer with the one + 		 * in tx aggregation state. + 		 */ +-		tid = ATH_AN_2_TID(an, tidno); ++		tid = ath_get_tid(an, skb); + 		seqno = tid->seq_next; + 		hdr->seq_ctrl = cpu_to_le16(seqno << IEEE80211_SEQ_SEQ_SHIFT); + 		INCR(tid->seq_next, IEEE80211_SEQ_MAX); +@@ -1766,24 +1776,14 @@ static struct ath_buf *ath_tx_setup_buff +  + /* FIXME: tx power */ + static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, +-			     struct ath_tx_control *txctl) ++			     struct ath_tx_control *txctl, ++			     struct ath_atx_tid *tid) + { + 	struct sk_buff *skb = bf->bf_mpdu; + 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); +-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + 	struct list_head bf_head; +-	struct ath_atx_tid *tid = NULL; +-	u8 tidno; +  + 	spin_lock_bh(&txctl->txq->axq_lock); +-	if ((sc->sc_flags & SC_OP_TXAGGR) && txctl->an && +-		ieee80211_is_data_qos(hdr->frame_control)) { +-		tidno = ieee80211_get_qos_ctl(hdr)[0] & +-			IEEE80211_QOS_CTL_TID_MASK; +-		tid = ATH_AN_2_TID(txctl->an, tidno); +- +-		WARN_ON(tid->ac->txq != txctl->txq); +-	} +  + 	if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && tid) { + 		/* +@@ -1824,6 +1824,7 @@ int ath_tx_start(struct ieee80211_hw *hw + 	struct ieee80211_vif *vif = info->control.vif; + 	struct ath_softc *sc = hw->priv; + 	struct ath_txq *txq = txctl->txq; ++	struct ath_atx_tid *tid = NULL; + 	struct ath_buf *bf; + 	int padpos, padsize; + 	int frmlen = skb->len + FCS_LEN; +@@ -1857,6 +1858,7 @@ int ath_tx_start(struct ieee80211_hw *hw +  + 		skb_push(skb, padsize); + 		memmove(skb->data, skb->data + padsize, padpos); ++		hdr = (struct ieee80211_hdr *) skb->data; + 	} +  + 	if ((vif && vif->type != NL80211_IFTYPE_AP && +@@ -1866,6 +1868,24 @@ int ath_tx_start(struct ieee80211_hw *hw +  + 	setup_frame_info(hw, skb, frmlen); +  ++	if ((sc->sc_flags & SC_OP_TXAGGR) && txctl->an && ++	    ieee80211_is_data_qos(hdr->frame_control)) { ++		tid = ath_get_tid(txctl->an, skb); ++ ++		WARN_ON(tid->ac->txq != txq); ++	} ++ ++	if ((info->flags & IEEE80211_TX_CTL_AMPDU) && tid) { ++		if (sc->tx.qlen_aggr > 0 && skb_queue_len(&tid->buf_q) + ++		    tid->buf_pending >= sc->tx.qlen_aggr) ++			return -ENOMEM; ++	} else { ++		if (sc->tx.qlen_single > 0 && ++		    txq->axq_depth - txq->axq_ampdu_depth >= ++		      sc->tx.qlen_single) ++			return -ENOMEM; ++	} ++ + 	/* + 	 * At this point, the vif, hw_key and sta pointers in the tx control + 	 * info are no longer valid (overwritten by the ath_frame_info data. +@@ -1884,7 +1904,7 @@ int ath_tx_start(struct ieee80211_hw *hw + 	} + 	spin_unlock_bh(&txq->axq_lock); +  +-	ath_tx_start_dma(sc, bf, txctl); ++	ath_tx_start_dma(sc, bf, txctl, tid); +  + 	return 0; + }  | 
