aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2013-08-06 08:18:11 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-08-09 15:58:20 -0400
commit2800e82bcc3ba8d2a2bbb42557e2f320f8b27da1 (patch)
treea6619774e3d3faafd66c6336a508a703602e1d96
parent026d5b07c03458f9c0ccd19c3850564a5409c325 (diff)
ath9k: use software queues for un-aggregated data packets
This is a first step for improving fairness between legacy and 802.11n traffic, and it should also improve reliability of resets and channel changes by keeping the hardware queue depth very short. When an aggregation session is torn down, all packets in the retry queue will be removed from the BAW and freed. For all subframes that have not been transmitted yet, the A-MPDU flag will be cleared, and a sequence number allocated. This ensures that the next A-MPDU session will get the correct initial sequence number. This happens both on aggregation session start and stop. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h8
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c264
2 files changed, 145 insertions, 127 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 126f98066f1b..41ea3fd5b9bb 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -137,6 +137,8 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
137#define ATH_AGGR_ENCRYPTDELIM 10 137#define ATH_AGGR_ENCRYPTDELIM 10
138/* minimum h/w qdepth to be sustained to maximize aggregation */ 138/* minimum h/w qdepth to be sustained to maximize aggregation */
139#define ATH_AGGR_MIN_QDEPTH 2 139#define ATH_AGGR_MIN_QDEPTH 2
140/* minimum h/w qdepth for non-aggregated traffic */
141#define ATH_NON_AGGR_MIN_QDEPTH 8
140 142
141#define IEEE80211_SEQ_SEQ_SHIFT 4 143#define IEEE80211_SEQ_SEQ_SHIFT 4
142#define IEEE80211_SEQ_MAX 4096 144#define IEEE80211_SEQ_MAX 4096
@@ -173,12 +175,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
173 175
174#define ATH_TX_COMPLETE_POLL_INT 1000 176#define ATH_TX_COMPLETE_POLL_INT 1000
175 177
176enum ATH_AGGR_STATUS {
177 ATH_AGGR_DONE,
178 ATH_AGGR_BAW_CLOSED,
179 ATH_AGGR_LIMITED,
180};
181
182#define ATH_TXFIFO_DEPTH 8 178#define ATH_TXFIFO_DEPTH 8
183struct ath_txq { 179struct ath_txq {
184 int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */ 180 int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index dfa85f1aee73..3b66f2b67fec 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -198,6 +198,41 @@ static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
198 return skb; 198 return skb;
199} 199}
200 200
201/*
202 * ath_tx_tid_change_state:
203 * - clears a-mpdu flag of previous session
204 * - force sequence number allocation to fix next BlockAck Window
205 */
206static void
207ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid)
208{
209 struct ath_txq *txq = tid->ac->txq;
210 struct ieee80211_tx_info *tx_info;
211 struct sk_buff *skb, *tskb;
212 struct ath_buf *bf;
213 struct ath_frame_info *fi;
214
215 skb_queue_walk_safe(&tid->buf_q, skb, tskb) {
216 fi = get_frame_info(skb);
217 bf = fi->bf;
218
219 tx_info = IEEE80211_SKB_CB(skb);
220 tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU;
221
222 if (bf)
223 continue;
224
225 bf = ath_tx_setup_buffer(sc, txq, tid, skb);
226 if (!bf) {
227 __skb_unlink(skb, &tid->buf_q);
228 ath_txq_skb_done(sc, txq, skb);
229 ieee80211_free_txskb(sc->hw, skb);
230 continue;
231 }
232 }
233
234}
235
201static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) 236static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
202{ 237{
203 struct ath_txq *txq = tid->ac->txq; 238 struct ath_txq *txq = tid->ac->txq;
@@ -212,28 +247,22 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
212 247
213 memset(&ts, 0, sizeof(ts)); 248 memset(&ts, 0, sizeof(ts));
214 249
215 while ((skb = ath_tid_dequeue(tid))) { 250 while ((skb = __skb_dequeue(&tid->retry_q))) {
216 fi = get_frame_info(skb); 251 fi = get_frame_info(skb);
217 bf = fi->bf; 252 bf = fi->bf;
218
219 if (!bf) { 253 if (!bf) {
220 bf = ath_tx_setup_buffer(sc, txq, tid, skb); 254 ath_txq_skb_done(sc, txq, skb);
221 if (!bf) { 255 ieee80211_free_txskb(sc->hw, skb);
222 ath_txq_skb_done(sc, txq, skb); 256 continue;
223 ieee80211_free_txskb(sc->hw, skb);
224 continue;
225 }
226 } 257 }
227 258
228 if (fi->baw_tracked) { 259 if (fi->baw_tracked) {
229 list_add_tail(&bf->list, &bf_head);
230 ath_tx_update_baw(sc, tid, bf->bf_state.seqno); 260 ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
231 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
232 sendbar = true; 261 sendbar = true;
233 } else {
234 ath_set_rates(tid->an->vif, tid->an->sta, bf);
235 ath_tx_send_normal(sc, txq, NULL, skb);
236 } 262 }
263
264 list_add_tail(&bf->list, &bf_head);
265 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
237 } 266 }
238 267
239 if (sendbar) { 268 if (sendbar) {
@@ -911,50 +940,39 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
911 return NULL; 940 return NULL;
912} 941}
913 942
914static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, 943static bool
915 struct ath_txq *txq, 944ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
916 struct ath_atx_tid *tid, 945 struct ath_atx_tid *tid, struct list_head *bf_q,
917 struct list_head *bf_q, 946 struct ath_buf *bf_first, struct sk_buff_head *tid_q,
918 int *aggr_len) 947 int *aggr_len)
919{ 948{
920#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) 949#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
921 struct ath_buf *bf, *bf_first = NULL, *bf_prev = NULL; 950 struct ath_buf *bf = bf_first, *bf_prev = NULL;
922 int nframes = 0, ndelim; 951 int nframes = 0, ndelim;
923 u16 aggr_limit = 0, al = 0, bpad = 0, 952 u16 aggr_limit = 0, al = 0, bpad = 0,
924 al_delta, h_baw = tid->baw_size / 2; 953 al_delta, h_baw = tid->baw_size / 2;
925 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
926 struct ieee80211_tx_info *tx_info; 954 struct ieee80211_tx_info *tx_info;
927 struct ath_frame_info *fi; 955 struct ath_frame_info *fi;
928 struct sk_buff *skb; 956 struct sk_buff *skb;
929 struct sk_buff_head *tid_q; 957 bool closed = false;
930 958
931 do { 959 bf = bf_first;
932 bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); 960 aggr_limit = ath_lookup_rate(sc, bf, tid);
933 if (!bf) {
934 status = ATH_AGGR_BAW_CLOSED;
935 break;
936 }
937 961
962 do {
938 skb = bf->bf_mpdu; 963 skb = bf->bf_mpdu;
939 fi = get_frame_info(skb); 964 fi = get_frame_info(skb);
940 965
941 if (!bf_first) {
942 bf_first = bf;
943 ath_set_rates(tid->an->vif, tid->an->sta, bf);
944 aggr_limit = ath_lookup_rate(sc, bf, tid);
945 }
946
947 /* do not exceed aggregation limit */ 966 /* do not exceed aggregation limit */
948 al_delta = ATH_AGGR_DELIM_SZ + fi->framelen; 967 al_delta = ATH_AGGR_DELIM_SZ + fi->framelen;
949 if (nframes) { 968 if (nframes) {
950 if (aggr_limit < al + bpad + al_delta || 969 if (aggr_limit < al + bpad + al_delta ||
951 ath_lookup_legacy(bf) || nframes >= h_baw) { 970 ath_lookup_legacy(bf) || nframes >= h_baw)
952 status = ATH_AGGR_LIMITED;
953 break; 971 break;
954 }
955 972
956 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); 973 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
957 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) 974 if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
975 !(tx_info->flags & IEEE80211_TX_CTL_AMPDU))
958 break; 976 break;
959 } 977 }
960 978
@@ -984,11 +1002,26 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
984 1002
985 bf_prev = bf; 1003 bf_prev = bf;
986 1004
1005 bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
1006 if (!bf) {
1007 closed = true;
1008 break;
1009 }
987 } while (ath_tid_has_buffered(tid)); 1010 } while (ath_tid_has_buffered(tid));
988 1011
1012 bf = bf_first;
1013 bf->bf_lastbf = bf_prev;
1014
1015 if (bf == bf_prev) {
1016 al = get_frame_info(bf->bf_mpdu)->framelen;
1017 bf->bf_state.bf_type = BUF_AMPDU;
1018 } else {
1019 TX_STAT_INC(txq->axq_qnum, a_aggr);
1020 }
1021
989 *aggr_len = al; 1022 *aggr_len = al;
990 1023
991 return status; 1024 return closed;
992#undef PADBYTES 1025#undef PADBYTES
993} 1026}
994 1027
@@ -1277,14 +1310,50 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
1277 } 1310 }
1278} 1311}
1279 1312
1313static void
1314ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
1315 struct ath_atx_tid *tid, struct list_head *bf_q,
1316 struct ath_buf *bf_first, struct sk_buff_head *tid_q)
1317{
1318 struct ath_buf *bf = bf_first, *bf_prev = NULL;
1319 struct sk_buff *skb;
1320 int nframes = 0;
1321
1322 do {
1323 struct ieee80211_tx_info *tx_info;
1324 skb = bf->bf_mpdu;
1325
1326 nframes++;
1327 __skb_unlink(skb, tid_q);
1328 list_add_tail(&bf->list, bf_q);
1329 if (bf_prev)
1330 bf_prev->bf_next = bf;
1331 bf_prev = bf;
1332
1333 if (nframes >= 2)
1334 break;
1335
1336 bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
1337 if (!bf)
1338 break;
1339
1340 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
1341 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
1342 break;
1343
1344 ath_set_rates(tid->an->vif, tid->an->sta, bf);
1345 } while (1);
1346}
1347
1280static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, 1348static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
1281 struct ath_atx_tid *tid) 1349 struct ath_atx_tid *tid)
1282{ 1350{
1283 struct ath_buf *bf; 1351 struct ath_buf *bf;
1284 enum ATH_AGGR_STATUS status;
1285 struct ieee80211_tx_info *tx_info; 1352 struct ieee80211_tx_info *tx_info;
1353 struct sk_buff_head *tid_q;
1286 struct list_head bf_q; 1354 struct list_head bf_q;
1287 int aggr_len; 1355 int aggr_len = 0;
1356 bool aggr, last = true;
1288 1357
1289 do { 1358 do {
1290 if (!ath_tid_has_buffered(tid)) 1359 if (!ath_tid_has_buffered(tid))
@@ -1292,38 +1361,34 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
1292 1361
1293 INIT_LIST_HEAD(&bf_q); 1362 INIT_LIST_HEAD(&bf_q);
1294 1363
1295 status = ath_tx_form_aggr(sc, txq, tid, &bf_q, &aggr_len); 1364 bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
1296 1365 if (!bf)
1297 /*
1298 * no frames picked up to be aggregated;
1299 * block-ack window is not open.
1300 */
1301 if (list_empty(&bf_q))
1302 break; 1366 break;
1303 1367
1304 bf = list_first_entry(&bf_q, struct ath_buf, list);
1305 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
1306 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); 1368 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
1369 aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
1370 if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) ||
1371 (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH))
1372 break;
1373
1374 ath_set_rates(tid->an->vif, tid->an->sta, bf);
1375 if (aggr)
1376 last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
1377 tid_q, &aggr_len);
1378 else
1379 ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q);
1380
1381 if (list_empty(&bf_q))
1382 return;
1307 1383
1308 if (tid->ac->clear_ps_filter) { 1384 if (tid->ac->clear_ps_filter) {
1309 tid->ac->clear_ps_filter = false; 1385 tid->ac->clear_ps_filter = false;
1310 tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; 1386 tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
1311 } else {
1312 tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT;
1313 }
1314
1315 /* if only one frame, send as non-aggregate */
1316 if (bf == bf->bf_lastbf) {
1317 aggr_len = get_frame_info(bf->bf_mpdu)->framelen;
1318 bf->bf_state.bf_type = BUF_AMPDU;
1319 } else {
1320 TX_STAT_INC(txq->axq_qnum, a_aggr);
1321 } 1387 }
1322 1388
1323 ath_tx_fill_desc(sc, bf, txq, aggr_len); 1389 ath_tx_fill_desc(sc, bf, txq, aggr_len);
1324 ath_tx_txqaddbuf(sc, txq, &bf_q, false); 1390 ath_tx_txqaddbuf(sc, txq, &bf_q, false);
1325 } while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH && 1391 } while (!last);
1326 status != ATH_AGGR_BAW_CLOSED);
1327} 1392}
1328 1393
1329int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, 1394int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
@@ -1347,6 +1412,9 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
1347 an->mpdudensity = density; 1412 an->mpdudensity = density;
1348 } 1413 }
1349 1414
1415 /* force sequence number allocation for pending frames */
1416 ath_tx_tid_change_state(sc, txtid);
1417
1350 txtid->active = true; 1418 txtid->active = true;
1351 txtid->paused = true; 1419 txtid->paused = true;
1352 *ssn = txtid->seq_start = txtid->seq_next; 1420 *ssn = txtid->seq_start = txtid->seq_next;
@@ -1368,6 +1436,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
1368 txtid->active = false; 1436 txtid->active = false;
1369 txtid->paused = false; 1437 txtid->paused = false;
1370 ath_tx_flush_tid(sc, txtid); 1438 ath_tx_flush_tid(sc, txtid);
1439 ath_tx_tid_change_state(sc, txtid);
1371 ath_txq_unlock_complete(sc, txq); 1440 ath_txq_unlock_complete(sc, txq);
1372} 1441}
1373 1442
@@ -1882,58 +1951,6 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1882 } 1951 }
1883} 1952}
1884 1953
1885static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_txq *txq,
1886 struct ath_atx_tid *tid, struct sk_buff *skb,
1887 struct ath_tx_control *txctl)
1888{
1889 struct ath_frame_info *fi = get_frame_info(skb);
1890 struct list_head bf_head;
1891 struct ath_buf *bf;
1892
1893 /*
1894 * Do not queue to h/w when any of the following conditions is true:
1895 * - there are pending frames in software queue
1896 * - the TID is currently paused for ADDBA/BAR request
1897 * - seqno is not within block-ack window
1898 * - h/w queue depth exceeds low water mark
1899 */
1900 if ((ath_tid_has_buffered(tid) || tid->paused ||
1901 !BAW_WITHIN(tid->seq_start, tid->baw_size, tid->seq_next) ||
1902 txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) &&
1903 txq != sc->tx.uapsdq) {
1904 /*
1905 * Add this frame to software queue for scheduling later
1906 * for aggregation.
1907 */
1908 TX_STAT_INC(txq->axq_qnum, a_queued_sw);
1909 __skb_queue_tail(&tid->buf_q, skb);
1910 if (!txctl->an || !txctl->an->sleeping)
1911 ath_tx_queue_tid(txq, tid);
1912 return;
1913 }
1914
1915 bf = ath_tx_setup_buffer(sc, txq, tid, skb);
1916 if (!bf) {
1917 ath_txq_skb_done(sc, txq, skb);
1918 ieee80211_free_txskb(sc->hw, skb);
1919 return;
1920 }
1921
1922 ath_set_rates(tid->an->vif, tid->an->sta, bf);
1923 bf->bf_state.bf_type = BUF_AMPDU;
1924 INIT_LIST_HEAD(&bf_head);
1925 list_add(&bf->list, &bf_head);
1926
1927 /* Add sub-frame to BAW */
1928 ath_tx_addto_baw(sc, tid, bf);
1929
1930 /* Queue to h/w without aggregation */
1931 TX_STAT_INC(txq->axq_qnum, a_queued_hw);
1932 bf->bf_lastbf = bf;
1933 ath_tx_fill_desc(sc, bf, txq, fi->framelen);
1934 ath_tx_txqaddbuf(sc, txq, &bf_head, false);
1935}
1936
1937static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, 1954static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1938 struct ath_atx_tid *tid, struct sk_buff *skb) 1955 struct ath_atx_tid *tid, struct sk_buff *skb)
1939{ 1956{
@@ -2159,20 +2176,25 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
2159 ath_txq_unlock(sc, txq); 2176 ath_txq_unlock(sc, txq);
2160 txq = sc->tx.uapsdq; 2177 txq = sc->tx.uapsdq;
2161 ath_txq_lock(sc, txq); 2178 ath_txq_lock(sc, txq);
2162 } 2179 } else if (txctl->an &&
2163 2180 ieee80211_is_data_present(hdr->frame_control)) {
2164 if (txctl->an && ieee80211_is_data_qos(hdr->frame_control)) {
2165 tid = ath_get_skb_tid(sc, txctl->an, skb); 2181 tid = ath_get_skb_tid(sc, txctl->an, skb);
2166 2182
2167 WARN_ON(tid->ac->txq != txctl->txq); 2183 WARN_ON(tid->ac->txq != txctl->txq);
2168 }
2169 2184
2170 if ((info->flags & IEEE80211_TX_CTL_AMPDU) && tid) { 2185 if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
2186 tid->ac->clear_ps_filter = true;
2187
2171 /* 2188 /*
2172 * Try aggregation if it's a unicast data frame 2189 * Add this frame to software queue for scheduling later
2173 * and the destination is HT capable. 2190 * for aggregation.
2174 */ 2191 */
2175 ath_tx_send_ampdu(sc, txq, tid, skb, txctl); 2192 TX_STAT_INC(txq->axq_qnum, a_queued_sw);
2193 __skb_queue_tail(&tid->buf_q, skb);
2194 if (!txctl->an->sleeping)
2195 ath_tx_queue_tid(txq, tid);
2196
2197 ath_txq_schedule(sc, txq);
2176 goto out; 2198 goto out;
2177 } 2199 }
2178 2200