aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKalle Valo <kalle.valo@nokia.com>2008-12-18 16:35:20 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-12-19 15:23:59 -0500
commitce7c9111a97492d04c504f40736a669c235d664a (patch)
tree6a294d373e19a99048dafa632966096371f3b1bb
parente0cb686ff879dc9ac045ad7258ec687088d4e450 (diff)
mac80211: track master queue status
This is a preparation for the dynamic power save support. In future there are two paths to stop the master queues and we need to track this properly to avoid starting queues incorrectly. Implement this by adding a status array for each queue. The original idea and design is from Johannes Berg, I just did the implementation based on his notes. All the bugs are mine, of course. Signed-off-by: Kalle Valo <kalle.valo@nokia.com> Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--net/mac80211/ieee80211_i.h12
-rw-r--r--net/mac80211/main.c2
-rw-r--r--net/mac80211/util.c86
3 files changed, 93 insertions, 7 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 18b91601770a..a74d6738b30a 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -538,6 +538,10 @@ enum {
538 IEEE80211_ADDBA_MSG = 4, 538 IEEE80211_ADDBA_MSG = 4,
539}; 539};
540 540
541enum queue_stop_reason {
542 IEEE80211_QUEUE_STOP_REASON_DRIVER,
543};
544
541/* maximum number of hardware queues we support. */ 545/* maximum number of hardware queues we support. */
542#define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES) 546#define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES)
543 547
@@ -554,7 +558,8 @@ struct ieee80211_local {
554 const struct ieee80211_ops *ops; 558 const struct ieee80211_ops *ops;
555 559
556 unsigned long queue_pool[BITS_TO_LONGS(QD_MAX_QUEUES)]; 560 unsigned long queue_pool[BITS_TO_LONGS(QD_MAX_QUEUES)];
557 561 unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES];
562 spinlock_t queue_stop_reason_lock;
558 struct net_device *mdev; /* wmaster# - "master" 802.11 device */ 563 struct net_device *mdev; /* wmaster# - "master" 802.11 device */
559 int open_count; 564 int open_count;
560 int monitors, cooked_mntrs; 565 int monitors, cooked_mntrs;
@@ -972,6 +977,11 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq);
972u64 ieee80211_mandatory_rates(struct ieee80211_local *local, 977u64 ieee80211_mandatory_rates(struct ieee80211_local *local,
973 enum ieee80211_band band); 978 enum ieee80211_band band);
974 979
980void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
981 enum queue_stop_reason reason);
982void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
983 enum queue_stop_reason reason);
984
975#ifdef CONFIG_MAC80211_NOINLINE 985#ifdef CONFIG_MAC80211_NOINLINE
976#define debug_noinline noinline 986#define debug_noinline noinline
977#else 987#else
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index ab6b73647b3e..21335382f530 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -725,6 +725,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
725 725
726 spin_lock_init(&local->key_lock); 726 spin_lock_init(&local->key_lock);
727 727
728 spin_lock_init(&local->queue_stop_reason_lock);
729
728 INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); 730 INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
729 731
730 sta_info_init(local); 732 sta_info_init(local);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 71a8391c54f6..fb89e1d0aa03 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -330,10 +330,20 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
330} 330}
331EXPORT_SYMBOL(ieee80211_ctstoself_duration); 331EXPORT_SYMBOL(ieee80211_ctstoself_duration);
332 332
333void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) 333static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
334 enum queue_stop_reason reason)
334{ 335{
335 struct ieee80211_local *local = hw_to_local(hw); 336 struct ieee80211_local *local = hw_to_local(hw);
336 337
338 /* we don't need to track ampdu queues */
339 if (queue < ieee80211_num_regular_queues(hw)) {
340 __clear_bit(reason, &local->queue_stop_reasons[queue]);
341
342 if (local->queue_stop_reasons[queue] != 0)
343 /* someone still has this queue stopped */
344 return;
345 }
346
337 if (test_bit(queue, local->queues_pending)) { 347 if (test_bit(queue, local->queues_pending)) {
338 set_bit(queue, local->queues_pending_run); 348 set_bit(queue, local->queues_pending_run);
339 tasklet_schedule(&local->tx_pending_tasklet); 349 tasklet_schedule(&local->tx_pending_tasklet);
@@ -341,22 +351,74 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
341 netif_wake_subqueue(local->mdev, queue); 351 netif_wake_subqueue(local->mdev, queue);
342 } 352 }
343} 353}
354
355void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
356 enum queue_stop_reason reason)
357{
358 struct ieee80211_local *local = hw_to_local(hw);
359 unsigned long flags;
360
361 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
362 __ieee80211_wake_queue(hw, queue, reason);
363 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
364}
365
366void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
367{
368 ieee80211_wake_queue_by_reason(hw, queue,
369 IEEE80211_QUEUE_STOP_REASON_DRIVER);
370}
344EXPORT_SYMBOL(ieee80211_wake_queue); 371EXPORT_SYMBOL(ieee80211_wake_queue);
345 372
346void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) 373static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
374 enum queue_stop_reason reason)
347{ 375{
348 struct ieee80211_local *local = hw_to_local(hw); 376 struct ieee80211_local *local = hw_to_local(hw);
349 377
378 /* we don't need to track ampdu queues */
379 if (queue < ieee80211_num_regular_queues(hw))
380 __set_bit(reason, &local->queue_stop_reasons[queue]);
381
350 netif_stop_subqueue(local->mdev, queue); 382 netif_stop_subqueue(local->mdev, queue);
351} 383}
384
385void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
386 enum queue_stop_reason reason)
387{
388 struct ieee80211_local *local = hw_to_local(hw);
389 unsigned long flags;
390
391 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
392 __ieee80211_stop_queue(hw, queue, reason);
393 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
394}
395
396void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
397{
398 ieee80211_stop_queue_by_reason(hw, queue,
399 IEEE80211_QUEUE_STOP_REASON_DRIVER);
400}
352EXPORT_SYMBOL(ieee80211_stop_queue); 401EXPORT_SYMBOL(ieee80211_stop_queue);
353 402
354void ieee80211_stop_queues(struct ieee80211_hw *hw) 403void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
404 enum queue_stop_reason reason)
355{ 405{
406 struct ieee80211_local *local = hw_to_local(hw);
407 unsigned long flags;
356 int i; 408 int i;
357 409
410 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
411
358 for (i = 0; i < ieee80211_num_queues(hw); i++) 412 for (i = 0; i < ieee80211_num_queues(hw); i++)
359 ieee80211_stop_queue(hw, i); 413 __ieee80211_stop_queue(hw, i, reason);
414
415 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
416}
417
418void ieee80211_stop_queues(struct ieee80211_hw *hw)
419{
420 ieee80211_stop_queues_by_reason(hw,
421 IEEE80211_QUEUE_STOP_REASON_DRIVER);
360} 422}
361EXPORT_SYMBOL(ieee80211_stop_queues); 423EXPORT_SYMBOL(ieee80211_stop_queues);
362 424
@@ -367,12 +429,24 @@ int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
367} 429}
368EXPORT_SYMBOL(ieee80211_queue_stopped); 430EXPORT_SYMBOL(ieee80211_queue_stopped);
369 431
370void ieee80211_wake_queues(struct ieee80211_hw *hw) 432void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
433 enum queue_stop_reason reason)
371{ 434{
435 struct ieee80211_local *local = hw_to_local(hw);
436 unsigned long flags;
372 int i; 437 int i;
373 438
439 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
440
374 for (i = 0; i < hw->queues + hw->ampdu_queues; i++) 441 for (i = 0; i < hw->queues + hw->ampdu_queues; i++)
375 ieee80211_wake_queue(hw, i); 442 __ieee80211_wake_queue(hw, i, reason);
443
444 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
445}
446
447void ieee80211_wake_queues(struct ieee80211_hw *hw)
448{
449 ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER);
376} 450}
377EXPORT_SYMBOL(ieee80211_wake_queues); 451EXPORT_SYMBOL(ieee80211_wake_queues);
378 452