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>
This commit is contained in:
committed by
John W. Linville
parent
e0cb686ff8
commit
ce7c9111a9
@@ -330,10 +330,20 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_ctstoself_duration);
|
||||
|
||||
void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
|
||||
static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
/* we don't need to track ampdu queues */
|
||||
if (queue < ieee80211_num_regular_queues(hw)) {
|
||||
__clear_bit(reason, &local->queue_stop_reasons[queue]);
|
||||
|
||||
if (local->queue_stop_reasons[queue] != 0)
|
||||
/* someone still has this queue stopped */
|
||||
return;
|
||||
}
|
||||
|
||||
if (test_bit(queue, local->queues_pending)) {
|
||||
set_bit(queue, local->queues_pending_run);
|
||||
tasklet_schedule(&local->tx_pending_tasklet);
|
||||
@@ -341,22 +351,74 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
|
||||
netif_wake_subqueue(local->mdev, queue);
|
||||
}
|
||||
}
|
||||
|
||||
void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
__ieee80211_wake_queue(hw, queue, reason);
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
}
|
||||
|
||||
void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
|
||||
{
|
||||
ieee80211_wake_queue_by_reason(hw, queue,
|
||||
IEEE80211_QUEUE_STOP_REASON_DRIVER);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_wake_queue);
|
||||
|
||||
void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
|
||||
static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
/* we don't need to track ampdu queues */
|
||||
if (queue < ieee80211_num_regular_queues(hw))
|
||||
__set_bit(reason, &local->queue_stop_reasons[queue]);
|
||||
|
||||
netif_stop_subqueue(local->mdev, queue);
|
||||
}
|
||||
|
||||
void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
__ieee80211_stop_queue(hw, queue, reason);
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
}
|
||||
|
||||
void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
|
||||
{
|
||||
ieee80211_stop_queue_by_reason(hw, queue,
|
||||
IEEE80211_QUEUE_STOP_REASON_DRIVER);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_stop_queue);
|
||||
|
||||
void ieee80211_stop_queues(struct ieee80211_hw *hw)
|
||||
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
|
||||
for (i = 0; i < ieee80211_num_queues(hw); i++)
|
||||
ieee80211_stop_queue(hw, i);
|
||||
__ieee80211_stop_queue(hw, i, reason);
|
||||
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
}
|
||||
|
||||
void ieee80211_stop_queues(struct ieee80211_hw *hw)
|
||||
{
|
||||
ieee80211_stop_queues_by_reason(hw,
|
||||
IEEE80211_QUEUE_STOP_REASON_DRIVER);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_stop_queues);
|
||||
|
||||
@@ -367,12 +429,24 @@ int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_queue_stopped);
|
||||
|
||||
void ieee80211_wake_queues(struct ieee80211_hw *hw)
|
||||
void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
|
||||
for (i = 0; i < hw->queues + hw->ampdu_queues; i++)
|
||||
ieee80211_wake_queue(hw, i);
|
||||
__ieee80211_wake_queue(hw, i, reason);
|
||||
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
}
|
||||
|
||||
void ieee80211_wake_queues(struct ieee80211_hw *hw)
|
||||
{
|
||||
ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_wake_queues);
|
||||
|
||||
|
Reference in New Issue
Block a user