summaryrefslogtreecommitdiffstats
path: root/package/mac80211/patches/542-ath9k_limit_qlen.patch
blob: f05db0a7c0a78b4edac65f886a3981cc34d9b299 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -240,6 +240,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;
@@ -286,6 +287,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
@@ -1341,6 +1341,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
@@ -340,6 +340,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,
@@ -435,6 +443,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 = sendbar = 0;
 		bf_next = bf->bf_next;
@@ -799,6 +809,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) {
@@ -1451,6 +1462,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;
@@ -1515,7 +1528,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);
 
@@ -1526,13 +1538,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);
@@ -1776,24 +1786,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) {
 		/*
@@ -1833,6 +1833,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;
@@ -1866,6 +1867,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 &&
@@ -1875,6 +1877,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.
@@ -1893,7 +1913,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;
 }