aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/util.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-04-03 10:28:50 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-04-11 16:23:50 -0400
commit3a25a8c8b75b430c4f4022918e26fa51d557ecde (patch)
treed4863b7f17c2ea44fb523e29951b6bd202ddb1ad /net/mac80211/util.c
parent4b6f1dd6a6faf4ed8d209bbd548e78b15e55aee8 (diff)
mac80211: add improved HW queue control
mac80211 currently only supports one hardware queue per AC. This is already problematic for off-channel uses since if we go off channel while the BE queue is full and then try to send an off-channel frame the frame will never go out. This will become worse when we support multi-channel since then a queue on one channel might be full, but we have to stop the software queue for all channels. That is obviously not desirable. To address this problem allow drivers to register more hardware queues, and allow them to map them to virtual interfaces. When they stop a hardware queue the corresponding AC software queues on the correct interfaces will be stopped as well. Additionally, there's an off-channel queue to solve that problem and a per-interface after-DTIM beacon queue. This allows drivers to manage software queues closer to how the hardware works. Currently, there's a limit of 16 hardware queues. This may or may not be sufficient, we can adjust it as needed. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r--net/mac80211/util.c48
1 files changed, 38 insertions, 10 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 9e8f4b892555..e67fe5c1def9 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -265,11 +265,36 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
265} 265}
266EXPORT_SYMBOL(ieee80211_ctstoself_duration); 266EXPORT_SYMBOL(ieee80211_ctstoself_duration);
267 267
268void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
269{
270 struct ieee80211_sub_if_data *sdata;
271
272 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
273 int ac;
274
275 if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
276 continue;
277
278 if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE &&
279 local->queue_stop_reasons[sdata->vif.cab_queue] != 0)
280 continue;
281
282 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
283 int ac_queue = sdata->vif.hw_queue[ac];
284
285 if (ac_queue == queue ||
286 (sdata->vif.cab_queue == queue &&
287 local->queue_stop_reasons[ac_queue] == 0 &&
288 skb_queue_empty(&local->pending[ac_queue])))
289 netif_wake_subqueue(sdata->dev, ac);
290 }
291 }
292}
293
268static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, 294static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
269 enum queue_stop_reason reason) 295 enum queue_stop_reason reason)
270{ 296{
271 struct ieee80211_local *local = hw_to_local(hw); 297 struct ieee80211_local *local = hw_to_local(hw);
272 struct ieee80211_sub_if_data *sdata;
273 298
274 trace_wake_queue(local, queue, reason); 299 trace_wake_queue(local, queue, reason);
275 300
@@ -287,11 +312,7 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
287 312
288 if (skb_queue_empty(&local->pending[queue])) { 313 if (skb_queue_empty(&local->pending[queue])) {
289 rcu_read_lock(); 314 rcu_read_lock();
290 list_for_each_entry_rcu(sdata, &local->interfaces, list) { 315 ieee80211_propagate_queue_wake(local, queue);
291 if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
292 continue;
293 netif_wake_subqueue(sdata->dev, queue);
294 }
295 rcu_read_unlock(); 316 rcu_read_unlock();
296 } else 317 } else
297 tasklet_schedule(&local->tx_pending_tasklet); 318 tasklet_schedule(&local->tx_pending_tasklet);
@@ -332,8 +353,15 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
332 __set_bit(reason, &local->queue_stop_reasons[queue]); 353 __set_bit(reason, &local->queue_stop_reasons[queue]);
333 354
334 rcu_read_lock(); 355 rcu_read_lock();
335 list_for_each_entry_rcu(sdata, &local->interfaces, list) 356 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
336 netif_stop_subqueue(sdata->dev, queue); 357 int ac;
358
359 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
360 if (sdata->vif.hw_queue[ac] == queue ||
361 sdata->vif.cab_queue == queue)
362 netif_stop_subqueue(sdata->dev, ac);
363 }
364 }
337 rcu_read_unlock(); 365 rcu_read_unlock();
338} 366}
339 367
@@ -360,8 +388,8 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
360{ 388{
361 struct ieee80211_hw *hw = &local->hw; 389 struct ieee80211_hw *hw = &local->hw;
362 unsigned long flags; 390 unsigned long flags;
363 int queue = skb_get_queue_mapping(skb);
364 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 391 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
392 int queue = info->hw_queue;
365 393
366 if (WARN_ON(!info->control.vif)) { 394 if (WARN_ON(!info->control.vif)) {
367 kfree_skb(skb); 395 kfree_skb(skb);
@@ -393,7 +421,7 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
393 continue; 421 continue;
394 } 422 }
395 423
396 queue = skb_get_queue_mapping(skb); 424 queue = info->hw_queue;
397 425
398 __ieee80211_stop_queue(hw, queue, 426 __ieee80211_stop_queue(hw, queue,
399 IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 427 IEEE80211_QUEUE_STOP_REASON_SKB_ADD);