Skip to content

Commit

Permalink
mac80211: track master queue status
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Kalle Valo authored and John W. Linville committed Dec 19, 2008
1 parent e0cb686 commit ce7c911
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 7 deletions.
12 changes: 11 additions & 1 deletion net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,10 @@ enum {
IEEE80211_ADDBA_MSG = 4,
};

enum queue_stop_reason {
IEEE80211_QUEUE_STOP_REASON_DRIVER,
};

/* maximum number of hardware queues we support. */
#define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES)

Expand All @@ -554,7 +558,8 @@ struct ieee80211_local {
const struct ieee80211_ops *ops;

unsigned long queue_pool[BITS_TO_LONGS(QD_MAX_QUEUES)];

unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES];
spinlock_t queue_stop_reason_lock;
struct net_device *mdev; /* wmaster# - "master" 802.11 device */
int open_count;
int monitors, cooked_mntrs;
Expand Down Expand Up @@ -972,6 +977,11 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq);
u64 ieee80211_mandatory_rates(struct ieee80211_local *local,
enum ieee80211_band band);

void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
enum queue_stop_reason reason);
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
enum queue_stop_reason reason);

#ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline
#else
Expand Down
2 changes: 2 additions & 0 deletions net/mac80211/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,

spin_lock_init(&local->key_lock);

spin_lock_init(&local->queue_stop_reason_lock);

INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);

sta_info_init(local);
Expand Down
86 changes: 80 additions & 6 deletions net/mac80211/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,33 +330,95 @@ __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);
} else {
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);

Expand All @@ -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);

Expand Down

0 comments on commit ce7c911

Please sign in to comment.