diff options
| -rw-r--r-- | net/mac80211/ieee80211_i.h | 12 | ||||
| -rw-r--r-- | net/mac80211/main.c | 2 | ||||
| -rw-r--r-- | net/mac80211/util.c | 86 |
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 | ||
| 541 | enum 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); | |||
| 972 | u64 ieee80211_mandatory_rates(struct ieee80211_local *local, | 977 | u64 ieee80211_mandatory_rates(struct ieee80211_local *local, |
| 973 | enum ieee80211_band band); | 978 | enum ieee80211_band band); |
| 974 | 979 | ||
| 980 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | ||
| 981 | enum queue_stop_reason reason); | ||
| 982 | void 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 | } |
| 331 | EXPORT_SYMBOL(ieee80211_ctstoself_duration); | 331 | EXPORT_SYMBOL(ieee80211_ctstoself_duration); |
| 332 | 332 | ||
| 333 | void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) | 333 | static 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 | |||
| 355 | void 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 | |||
| 366 | void 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 | } | ||
| 344 | EXPORT_SYMBOL(ieee80211_wake_queue); | 371 | EXPORT_SYMBOL(ieee80211_wake_queue); |
| 345 | 372 | ||
| 346 | void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) | 373 | static 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 | |||
| 385 | void 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 | |||
| 396 | void 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 | } | ||
| 352 | EXPORT_SYMBOL(ieee80211_stop_queue); | 401 | EXPORT_SYMBOL(ieee80211_stop_queue); |
| 353 | 402 | ||
| 354 | void ieee80211_stop_queues(struct ieee80211_hw *hw) | 403 | void 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 | |||
| 418 | void ieee80211_stop_queues(struct ieee80211_hw *hw) | ||
| 419 | { | ||
| 420 | ieee80211_stop_queues_by_reason(hw, | ||
| 421 | IEEE80211_QUEUE_STOP_REASON_DRIVER); | ||
| 360 | } | 422 | } |
| 361 | EXPORT_SYMBOL(ieee80211_stop_queues); | 423 | EXPORT_SYMBOL(ieee80211_stop_queues); |
| 362 | 424 | ||
| @@ -367,12 +429,24 @@ int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) | |||
| 367 | } | 429 | } |
| 368 | EXPORT_SYMBOL(ieee80211_queue_stopped); | 430 | EXPORT_SYMBOL(ieee80211_queue_stopped); |
| 369 | 431 | ||
| 370 | void ieee80211_wake_queues(struct ieee80211_hw *hw) | 432 | void 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 | |||
| 447 | void ieee80211_wake_queues(struct ieee80211_hw *hw) | ||
| 448 | { | ||
| 449 | ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER); | ||
| 376 | } | 450 | } |
| 377 | EXPORT_SYMBOL(ieee80211_wake_queues); | 451 | EXPORT_SYMBOL(ieee80211_wake_queues); |
| 378 | 452 | ||
