summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2016-05-19 04:37:49 -0400
committerJohannes Berg <johannes.berg@intel.com>2016-06-09 05:34:08 -0400
commitfa962b92120bb70693a4db545f89067eb3373294 (patch)
treec8e159c99501f312756ad295088c884ef2a2361c /net
parent80a83cfc434b1e3afe38974570b460db4898bec6 (diff)
mac80211: implement fair queueing per txq
mac80211's software queues were designed to work very closely with device tx queues. They are required to make use of 802.11 packet aggregation easily and efficiently. Due to the way 802.11 aggregation is designed it only makes sense to keep fair queuing as close to hardware as possible to reduce induced latency and inertia and provide the best flow responsiveness. This change doesn't translate directly to immediate and significant gains. End result depends on driver's induced latency. Best results can be achieved if driver keeps its own tx queue/fifo fill level to a minimum. Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/agg-tx.c8
-rw-r--r--net/mac80211/ieee80211_i.h24
-rw-r--r--net/mac80211/iface.c12
-rw-r--r--net/mac80211/main.c7
-rw-r--r--net/mac80211/rx.c2
-rw-r--r--net/mac80211/sta_info.c14
-rw-r--r--net/mac80211/tx.c136
-rw-r--r--net/mac80211/util.c23
8 files changed, 162 insertions, 64 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 42fa81031dfa..5650c46bf91a 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -194,17 +194,21 @@ static void
194ieee80211_agg_stop_txq(struct sta_info *sta, int tid) 194ieee80211_agg_stop_txq(struct sta_info *sta, int tid)
195{ 195{
196 struct ieee80211_txq *txq = sta->sta.txq[tid]; 196 struct ieee80211_txq *txq = sta->sta.txq[tid];
197 struct ieee80211_sub_if_data *sdata;
198 struct fq *fq;
197 struct txq_info *txqi; 199 struct txq_info *txqi;
198 200
199 if (!txq) 201 if (!txq)
200 return; 202 return;
201 203
202 txqi = to_txq_info(txq); 204 txqi = to_txq_info(txq);
205 sdata = vif_to_sdata(txq->vif);
206 fq = &sdata->local->fq;
203 207
204 /* Lock here to protect against further seqno updates on dequeue */ 208 /* Lock here to protect against further seqno updates on dequeue */
205 spin_lock_bh(&txqi->queue.lock); 209 spin_lock_bh(&fq->lock);
206 set_bit(IEEE80211_TXQ_STOP, &txqi->flags); 210 set_bit(IEEE80211_TXQ_STOP, &txqi->flags);
207 spin_unlock_bh(&txqi->queue.lock); 211 spin_unlock_bh(&fq->lock);
208} 212}
209 213
210static void 214static void
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 634603320374..6f8375f1df88 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -30,6 +30,7 @@
30#include <net/ieee80211_radiotap.h> 30#include <net/ieee80211_radiotap.h>
31#include <net/cfg80211.h> 31#include <net/cfg80211.h>
32#include <net/mac80211.h> 32#include <net/mac80211.h>
33#include <net/fq.h>
33#include "key.h" 34#include "key.h"
34#include "sta_info.h" 35#include "sta_info.h"
35#include "debug.h" 36#include "debug.h"
@@ -805,10 +806,17 @@ enum txq_info_flags {
805 IEEE80211_TXQ_NO_AMSDU, 806 IEEE80211_TXQ_NO_AMSDU,
806}; 807};
807 808
809/**
810 * struct txq_info - per tid queue
811 *
812 * @tin: contains packets split into multiple flows
813 * @def_flow: used as a fallback flow when a packet destined to @tin hashes to
814 * a fq_flow which is already owned by a different tin
815 */
808struct txq_info { 816struct txq_info {
809 struct sk_buff_head queue; 817 struct fq_tin tin;
818 struct fq_flow def_flow;
810 unsigned long flags; 819 unsigned long flags;
811 unsigned long byte_cnt;
812 820
813 /* keep last! */ 821 /* keep last! */
814 struct ieee80211_txq txq; 822 struct ieee80211_txq txq;
@@ -1099,6 +1107,8 @@ struct ieee80211_local {
1099 * it first anyway so they become a no-op */ 1107 * it first anyway so they become a no-op */
1100 struct ieee80211_hw hw; 1108 struct ieee80211_hw hw;
1101 1109
1110 struct fq fq;
1111
1102 const struct ieee80211_ops *ops; 1112 const struct ieee80211_ops *ops;
1103 1113
1104 /* 1114 /*
@@ -1931,9 +1941,13 @@ static inline bool ieee80211_can_run_worker(struct ieee80211_local *local)
1931 return true; 1941 return true;
1932} 1942}
1933 1943
1934void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata, 1944int ieee80211_txq_setup_flows(struct ieee80211_local *local);
1935 struct sta_info *sta, 1945void ieee80211_txq_teardown_flows(struct ieee80211_local *local);
1936 struct txq_info *txq, int tid); 1946void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
1947 struct sta_info *sta,
1948 struct txq_info *txq, int tid);
1949void ieee80211_txq_purge(struct ieee80211_local *local,
1950 struct txq_info *txqi);
1937void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, 1951void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
1938 u16 transaction, u16 auth_alg, u16 status, 1952 u16 transaction, u16 auth_alg, u16 status,
1939 const u8 *extra, size_t extra_len, const u8 *bssid, 1953 const u8 *extra, size_t extra_len, const u8 *bssid,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 609c5174d798..b123a9e325b3 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -779,6 +779,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
779 bool going_down) 779 bool going_down)
780{ 780{
781 struct ieee80211_local *local = sdata->local; 781 struct ieee80211_local *local = sdata->local;
782 struct fq *fq = &local->fq;
782 unsigned long flags; 783 unsigned long flags;
783 struct sk_buff *skb, *tmp; 784 struct sk_buff *skb, *tmp;
784 u32 hw_reconf_flags = 0; 785 u32 hw_reconf_flags = 0;
@@ -976,13 +977,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
976 977
977 if (sdata->vif.txq) { 978 if (sdata->vif.txq) {
978 struct txq_info *txqi = to_txq_info(sdata->vif.txq); 979 struct txq_info *txqi = to_txq_info(sdata->vif.txq);
979 int n = skb_queue_len(&txqi->queue);
980 980
981 spin_lock_bh(&txqi->queue.lock); 981 spin_lock_bh(&fq->lock);
982 ieee80211_purge_tx_queue(&local->hw, &txqi->queue); 982 ieee80211_txq_purge(local, txqi);
983 atomic_sub(n, &sdata->num_tx_queued); 983 spin_unlock_bh(&fq->lock);
984 txqi->byte_cnt = 0;
985 spin_unlock_bh(&txqi->queue.lock);
986 } 984 }
987 985
988 if (local->open_count == 0) 986 if (local->open_count == 0)
@@ -1792,7 +1790,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
1792 1790
1793 if (txq_size) { 1791 if (txq_size) {
1794 txqi = netdev_priv(ndev) + size; 1792 txqi = netdev_priv(ndev) + size;
1795 ieee80211_init_tx_queue(sdata, NULL, txqi, 0); 1793 ieee80211_txq_init(sdata, NULL, txqi, 0);
1796 } 1794 }
1797 1795
1798 sdata->dev = ndev; 1796 sdata->dev = ndev;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 160ac6b8b9a1..d00ea9b13f49 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1086,6 +1086,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
1086 1086
1087 rtnl_unlock(); 1087 rtnl_unlock();
1088 1088
1089 result = ieee80211_txq_setup_flows(local);
1090 if (result)
1091 goto fail_flows;
1092
1089#ifdef CONFIG_INET 1093#ifdef CONFIG_INET
1090 local->ifa_notifier.notifier_call = ieee80211_ifa_changed; 1094 local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
1091 result = register_inetaddr_notifier(&local->ifa_notifier); 1095 result = register_inetaddr_notifier(&local->ifa_notifier);
@@ -1111,6 +1115,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
1111#if defined(CONFIG_INET) || defined(CONFIG_IPV6) 1115#if defined(CONFIG_INET) || defined(CONFIG_IPV6)
1112 fail_ifa: 1116 fail_ifa:
1113#endif 1117#endif
1118 ieee80211_txq_teardown_flows(local);
1119 fail_flows:
1114 rtnl_lock(); 1120 rtnl_lock();
1115 rate_control_deinitialize(local); 1121 rate_control_deinitialize(local);
1116 ieee80211_remove_interfaces(local); 1122 ieee80211_remove_interfaces(local);
@@ -1169,6 +1175,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
1169 skb_queue_purge(&local->skb_queue); 1175 skb_queue_purge(&local->skb_queue);
1170 skb_queue_purge(&local->skb_queue_unreliable); 1176 skb_queue_purge(&local->skb_queue_unreliable);
1171 skb_queue_purge(&local->skb_queue_tdls_chsw); 1177 skb_queue_purge(&local->skb_queue_tdls_chsw);
1178 ieee80211_txq_teardown_flows(local);
1172 1179
1173 destroy_workqueue(local->workqueue); 1180 destroy_workqueue(local->workqueue);
1174 wiphy_unregister(local->hw.wiphy); 1181 wiphy_unregister(local->hw.wiphy);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 5e65e838992a..9a1eb70cb120 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1268,7 +1268,7 @@ static void sta_ps_start(struct sta_info *sta)
1268 for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { 1268 for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
1269 struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]); 1269 struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);
1270 1270
1271 if (!skb_queue_len(&txqi->queue)) 1271 if (!txqi->tin.backlog_packets)
1272 set_bit(tid, &sta->txq_buffered_tids); 1272 set_bit(tid, &sta->txq_buffered_tids);
1273 else 1273 else
1274 clear_bit(tid, &sta->txq_buffered_tids); 1274 clear_bit(tid, &sta->txq_buffered_tids);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 177cc6cd6416..76b737dcc36f 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -90,6 +90,7 @@ static void __cleanup_single_sta(struct sta_info *sta)
90 struct tid_ampdu_tx *tid_tx; 90 struct tid_ampdu_tx *tid_tx;
91 struct ieee80211_sub_if_data *sdata = sta->sdata; 91 struct ieee80211_sub_if_data *sdata = sta->sdata;
92 struct ieee80211_local *local = sdata->local; 92 struct ieee80211_local *local = sdata->local;
93 struct fq *fq = &local->fq;
93 struct ps_data *ps; 94 struct ps_data *ps;
94 95
95 if (test_sta_flag(sta, WLAN_STA_PS_STA) || 96 if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
@@ -113,11 +114,10 @@ static void __cleanup_single_sta(struct sta_info *sta)
113 if (sta->sta.txq[0]) { 114 if (sta->sta.txq[0]) {
114 for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { 115 for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
115 struct txq_info *txqi = to_txq_info(sta->sta.txq[i]); 116 struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
116 int n = skb_queue_len(&txqi->queue);
117 117
118 ieee80211_purge_tx_queue(&local->hw, &txqi->queue); 118 spin_lock_bh(&fq->lock);
119 atomic_sub(n, &sdata->num_tx_queued); 119 ieee80211_txq_purge(local, txqi);
120 txqi->byte_cnt = 0; 120 spin_unlock_bh(&fq->lock);
121 } 121 }
122 } 122 }
123 123
@@ -368,7 +368,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
368 for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { 368 for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
369 struct txq_info *txq = txq_data + i * size; 369 struct txq_info *txq = txq_data + i * size;
370 370
371 ieee80211_init_tx_queue(sdata, sta, txq, i); 371 ieee80211_txq_init(sdata, sta, txq, i);
372 } 372 }
373 } 373 }
374 374
@@ -1211,7 +1211,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
1211 for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { 1211 for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
1212 struct txq_info *txqi = to_txq_info(sta->sta.txq[i]); 1212 struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
1213 1213
1214 if (!skb_queue_len(&txqi->queue)) 1214 if (!txqi->tin.backlog_packets)
1215 continue; 1215 continue;
1216 1216
1217 drv_wake_tx_queue(local, txqi); 1217 drv_wake_tx_queue(local, txqi);
@@ -1648,7 +1648,7 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
1648 for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { 1648 for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
1649 struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]); 1649 struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);
1650 1650
1651 if (!(tids & BIT(tid)) || skb_queue_len(&txqi->queue)) 1651 if (!(tids & BIT(tid)) || txqi->tin.backlog_packets)
1652 continue; 1652 continue;
1653 1653
1654 sta_info_recalc_tim(sta); 1654 sta_info_recalc_tim(sta);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 3e77da195ce8..1d8343fca6d4 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -25,6 +25,7 @@
25#include <net/cfg80211.h> 25#include <net/cfg80211.h>
26#include <net/mac80211.h> 26#include <net/mac80211.h>
27#include <asm/unaligned.h> 27#include <asm/unaligned.h>
28#include <net/fq_impl.h>
28 29
29#include "ieee80211_i.h" 30#include "ieee80211_i.h"
30#include "driver-ops.h" 31#include "driver-ops.h"
@@ -1266,46 +1267,121 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
1266 return to_txq_info(txq); 1267 return to_txq_info(txq);
1267} 1268}
1268 1269
1270static struct sk_buff *fq_tin_dequeue_func(struct fq *fq,
1271 struct fq_tin *tin,
1272 struct fq_flow *flow)
1273{
1274 return fq_flow_dequeue(fq, flow);
1275}
1276
1277static void fq_skb_free_func(struct fq *fq,
1278 struct fq_tin *tin,
1279 struct fq_flow *flow,
1280 struct sk_buff *skb)
1281{
1282 struct ieee80211_local *local;
1283
1284 local = container_of(fq, struct ieee80211_local, fq);
1285 ieee80211_free_txskb(&local->hw, skb);
1286}
1287
1288static struct fq_flow *fq_flow_get_default_func(struct fq *fq,
1289 struct fq_tin *tin,
1290 int idx,
1291 struct sk_buff *skb)
1292{
1293 struct txq_info *txqi;
1294
1295 txqi = container_of(tin, struct txq_info, tin);
1296 return &txqi->def_flow;
1297}
1298
1269static void ieee80211_txq_enqueue(struct ieee80211_local *local, 1299static void ieee80211_txq_enqueue(struct ieee80211_local *local,
1270 struct txq_info *txqi, 1300 struct txq_info *txqi,
1271 struct sk_buff *skb) 1301 struct sk_buff *skb)
1272{ 1302{
1273 struct ieee80211_sub_if_data *sdata = vif_to_sdata(txqi->txq.vif); 1303 struct fq *fq = &local->fq;
1304 struct fq_tin *tin = &txqi->tin;
1274 1305
1275 lockdep_assert_held(&txqi->queue.lock); 1306 fq_tin_enqueue(fq, tin, skb,
1307 fq_skb_free_func,
1308 fq_flow_get_default_func);
1309}
1276 1310
1277 if (atomic_read(&sdata->num_tx_queued) >= TOTAL_MAX_TX_BUFFER || 1311void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
1278 txqi->queue.qlen >= STA_MAX_TX_BUFFER) { 1312 struct sta_info *sta,
1279 ieee80211_free_txskb(&local->hw, skb); 1313 struct txq_info *txqi, int tid)
1280 return; 1314{
1315 fq_tin_init(&txqi->tin);
1316 fq_flow_init(&txqi->def_flow);
1317
1318 txqi->txq.vif = &sdata->vif;
1319
1320 if (sta) {
1321 txqi->txq.sta = &sta->sta;
1322 sta->sta.txq[tid] = &txqi->txq;
1323 txqi->txq.tid = tid;
1324 txqi->txq.ac = ieee802_1d_to_ac[tid & 7];
1325 } else {
1326 sdata->vif.txq = &txqi->txq;
1327 txqi->txq.tid = 0;
1328 txqi->txq.ac = IEEE80211_AC_BE;
1281 } 1329 }
1330}
1282 1331
1283 atomic_inc(&sdata->num_tx_queued); 1332void ieee80211_txq_purge(struct ieee80211_local *local,
1284 txqi->byte_cnt += skb->len; 1333 struct txq_info *txqi)
1285 __skb_queue_tail(&txqi->queue, skb); 1334{
1335 struct fq *fq = &local->fq;
1336 struct fq_tin *tin = &txqi->tin;
1337
1338 fq_tin_reset(fq, tin, fq_skb_free_func);
1339}
1340
1341int ieee80211_txq_setup_flows(struct ieee80211_local *local)
1342{
1343 struct fq *fq = &local->fq;
1344 int ret;
1345
1346 if (!local->ops->wake_tx_queue)
1347 return 0;
1348
1349 ret = fq_init(fq, 4096);
1350 if (ret)
1351 return ret;
1352
1353 return 0;
1354}
1355
1356void ieee80211_txq_teardown_flows(struct ieee80211_local *local)
1357{
1358 struct fq *fq = &local->fq;
1359
1360 if (!local->ops->wake_tx_queue)
1361 return;
1362
1363 fq_reset(fq, fq_skb_free_func);
1286} 1364}
1287 1365
1288struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, 1366struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
1289 struct ieee80211_txq *txq) 1367 struct ieee80211_txq *txq)
1290{ 1368{
1291 struct ieee80211_local *local = hw_to_local(hw); 1369 struct ieee80211_local *local = hw_to_local(hw);
1292 struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif);
1293 struct txq_info *txqi = container_of(txq, struct txq_info, txq); 1370 struct txq_info *txqi = container_of(txq, struct txq_info, txq);
1294 struct ieee80211_hdr *hdr; 1371 struct ieee80211_hdr *hdr;
1295 struct sk_buff *skb = NULL; 1372 struct sk_buff *skb = NULL;
1373 struct fq *fq = &local->fq;
1374 struct fq_tin *tin = &txqi->tin;
1296 1375
1297 spin_lock_bh(&txqi->queue.lock); 1376 spin_lock_bh(&fq->lock);
1298 1377
1299 if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags)) 1378 if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags))
1300 goto out; 1379 goto out;
1301 1380
1302 skb = __skb_dequeue(&txqi->queue); 1381 skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func);
1303 if (!skb) 1382 if (!skb)
1304 goto out; 1383 goto out;
1305 1384
1306 atomic_dec(&sdata->num_tx_queued);
1307 txqi->byte_cnt -= skb->len;
1308
1309 hdr = (struct ieee80211_hdr *)skb->data; 1385 hdr = (struct ieee80211_hdr *)skb->data;
1310 if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) { 1386 if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) {
1311 struct sta_info *sta = container_of(txq->sta, struct sta_info, 1387 struct sta_info *sta = container_of(txq->sta, struct sta_info,
@@ -1320,7 +1396,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
1320 } 1396 }
1321 1397
1322out: 1398out:
1323 spin_unlock_bh(&txqi->queue.lock); 1399 spin_unlock_bh(&fq->lock);
1324 1400
1325 if (skb && skb_has_frag_list(skb) && 1401 if (skb && skb_has_frag_list(skb) &&
1326 !ieee80211_hw_check(&local->hw, TX_FRAG_LIST)) 1402 !ieee80211_hw_check(&local->hw, TX_FRAG_LIST))
@@ -1337,6 +1413,7 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
1337 bool txpending) 1413 bool txpending)
1338{ 1414{
1339 struct ieee80211_tx_control control = {}; 1415 struct ieee80211_tx_control control = {};
1416 struct fq *fq = &local->fq;
1340 struct sk_buff *skb, *tmp; 1417 struct sk_buff *skb, *tmp;
1341 struct txq_info *txqi; 1418 struct txq_info *txqi;
1342 unsigned long flags; 1419 unsigned long flags;
@@ -1359,9 +1436,9 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
1359 1436
1360 __skb_unlink(skb, skbs); 1437 __skb_unlink(skb, skbs);
1361 1438
1362 spin_lock_bh(&txqi->queue.lock); 1439 spin_lock_bh(&fq->lock);
1363 ieee80211_txq_enqueue(local, txqi, skb); 1440 ieee80211_txq_enqueue(local, txqi, skb);
1364 spin_unlock_bh(&txqi->queue.lock); 1441 spin_unlock_bh(&fq->lock);
1365 1442
1366 drv_wake_tx_queue(local, txqi); 1443 drv_wake_tx_queue(local, txqi);
1367 1444
@@ -2893,6 +2970,9 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
2893 struct sk_buff *skb) 2970 struct sk_buff *skb)
2894{ 2971{
2895 struct ieee80211_local *local = sdata->local; 2972 struct ieee80211_local *local = sdata->local;
2973 struct fq *fq = &local->fq;
2974 struct fq_tin *tin;
2975 struct fq_flow *flow;
2896 u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; 2976 u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
2897 struct ieee80211_txq *txq = sta->sta.txq[tid]; 2977 struct ieee80211_txq *txq = sta->sta.txq[tid];
2898 struct txq_info *txqi; 2978 struct txq_info *txqi;
@@ -2904,6 +2984,7 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
2904 __be16 len; 2984 __be16 len;
2905 void *data; 2985 void *data;
2906 bool ret = false; 2986 bool ret = false;
2987 unsigned int orig_len;
2907 int n = 1, nfrags; 2988 int n = 1, nfrags;
2908 2989
2909 if (!ieee80211_hw_check(&local->hw, TX_AMSDU)) 2990 if (!ieee80211_hw_check(&local->hw, TX_AMSDU))
@@ -2920,12 +3001,20 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
2920 max_amsdu_len = min_t(int, max_amsdu_len, 3001 max_amsdu_len = min_t(int, max_amsdu_len,
2921 sta->sta.max_rc_amsdu_len); 3002 sta->sta.max_rc_amsdu_len);
2922 3003
2923 spin_lock_bh(&txqi->queue.lock); 3004 spin_lock_bh(&fq->lock);
2924 3005
2925 head = skb_peek_tail(&txqi->queue); 3006 /* TODO: Ideally aggregation should be done on dequeue to remain
3007 * responsive to environment changes.
3008 */
3009
3010 tin = &txqi->tin;
3011 flow = fq_flow_classify(fq, tin, skb, fq_flow_get_default_func);
3012 head = skb_peek_tail(&flow->queue);
2926 if (!head) 3013 if (!head)
2927 goto out; 3014 goto out;
2928 3015
3016 orig_len = head->len;
3017
2929 if (skb->len + head->len > max_amsdu_len) 3018 if (skb->len + head->len > max_amsdu_len)
2930 goto out; 3019 goto out;
2931 3020
@@ -2964,8 +3053,13 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
2964 head->data_len += skb->len; 3053 head->data_len += skb->len;
2965 *frag_tail = skb; 3054 *frag_tail = skb;
2966 3055
3056 flow->backlog += head->len - orig_len;
3057 tin->backlog_bytes += head->len - orig_len;
3058
3059 fq_recalc_backlog(fq, tin, flow);
3060
2967out: 3061out:
2968 spin_unlock_bh(&txqi->queue.lock); 3062 spin_unlock_bh(&fq->lock);
2969 3063
2970 return ret; 3064 return ret;
2971} 3065}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 0db46442bdcf..42bf0b6685e8 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3389,25 +3389,6 @@ u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo)
3389 return buf; 3389 return buf;
3390} 3390}
3391 3391
3392void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata,
3393 struct sta_info *sta,
3394 struct txq_info *txqi, int tid)
3395{
3396 skb_queue_head_init(&txqi->queue);
3397 txqi->txq.vif = &sdata->vif;
3398
3399 if (sta) {
3400 txqi->txq.sta = &sta->sta;
3401 sta->sta.txq[tid] = &txqi->txq;
3402 txqi->txq.tid = tid;
3403 txqi->txq.ac = ieee802_1d_to_ac[tid & 7];
3404 } else {
3405 sdata->vif.txq = &txqi->txq;
3406 txqi->txq.tid = 0;
3407 txqi->txq.ac = IEEE80211_AC_BE;
3408 }
3409}
3410
3411void ieee80211_txq_get_depth(struct ieee80211_txq *txq, 3392void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
3412 unsigned long *frame_cnt, 3393 unsigned long *frame_cnt,
3413 unsigned long *byte_cnt) 3394 unsigned long *byte_cnt)
@@ -3415,9 +3396,9 @@ void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
3415 struct txq_info *txqi = to_txq_info(txq); 3396 struct txq_info *txqi = to_txq_info(txq);
3416 3397
3417 if (frame_cnt) 3398 if (frame_cnt)
3418 *frame_cnt = txqi->queue.qlen; 3399 *frame_cnt = txqi->tin.backlog_packets;
3419 3400
3420 if (byte_cnt) 3401 if (byte_cnt)
3421 *byte_cnt = txqi->byte_cnt; 3402 *byte_cnt = txqi->tin.backlog_bytes;
3422} 3403}
3423EXPORT_SYMBOL(ieee80211_txq_get_depth); 3404EXPORT_SYMBOL(ieee80211_txq_get_depth);