Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 300700
b: refs/heads/master
c: 3a25a8c
h: refs/heads/master
v: v3
  • Loading branch information
Johannes Berg authored and John W. Linville committed Apr 11, 2012
1 parent 22bcaf0 commit 2d1d9b3
Show file tree
Hide file tree
Showing 9 changed files with 240 additions and 43 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 4b6f1dd6a6faf4ed8d209bbd548e78b15e55aee8
refs/heads/master: 3a25a8c8b75b430c4f4022918e26fa51d557ecde
81 changes: 77 additions & 4 deletions trunk/include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,11 @@ struct device;
* @IEEE80211_MAX_QUEUES: Maximum number of regular device queues.
*/
enum ieee80211_max_queues {
IEEE80211_MAX_QUEUES = 4,
IEEE80211_MAX_QUEUES = 16,
};

#define IEEE80211_INVAL_HW_QUEUE 0xff

/**
* enum ieee80211_ac_numbers - AC numbers as used in mac80211
* @IEEE80211_AC_VO: voice
Expand Down Expand Up @@ -522,7 +524,7 @@ struct ieee80211_tx_rate {
*
* @flags: transmit info flags, defined above
* @band: the band to transmit on (use for checking for races)
* @reserved: reserved for future use
* @hw_queue: HW queue to put the frame on, skb_get_queue_mapping() gives the AC
* @ack_frame_id: internal frame ID for TX status, used internally
* @control: union for control data
* @status: union for status data
Expand All @@ -538,7 +540,7 @@ struct ieee80211_tx_info {
u32 flags;
u8 band;

u8 reserved;
u8 hw_queue;

u16 ack_frame_id;

Expand Down Expand Up @@ -889,6 +891,8 @@ enum ieee80211_vif_flags {
* these need to be set (or cleared) when the interface is added
* or, if supported by the driver, the interface type is changed
* at runtime, mac80211 will never touch this field
* @hw_queue: hardware queue for each AC
* @cab_queue: content-after-beacon (DTIM beacon really) queue, AP mode only
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void *).
*/
Expand All @@ -897,7 +901,12 @@ struct ieee80211_vif {
struct ieee80211_bss_conf bss_conf;
u8 addr[ETH_ALEN];
bool p2p;

u8 cab_queue;
u8 hw_queue[IEEE80211_NUM_ACS];

u32 driver_flags;

/* must be last */
u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
};
Expand Down Expand Up @@ -1179,6 +1188,11 @@ enum sta_notify_cmd {
* @IEEE80211_HW_WANT_MONITOR_VIF: The driver would like to be informed of
* a virtual monitor interface when monitor interfaces are the only
* active interfaces.
*
* @IEEE80211_HW_QUEUE_CONTROL: The driver wants to control per-interface
* queue mapping in order to use different queues (not just one per AC)
* for different virtual interfaces. See the doc section on HW queue
* control for more details.
*/
enum ieee80211_hw_flags {
IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
Expand All @@ -1201,7 +1215,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_SUPPORTS_UAPSD = 1<<17,
IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18,
IEEE80211_HW_CONNECTION_MONITOR = 1<<19,
/* reuse bit 20 */
IEEE80211_HW_QUEUE_CONTROL = 1<<20,
IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21,
IEEE80211_HW_AP_LINK_PS = 1<<22,
IEEE80211_HW_TX_AMPDU_SETUP_IN_HW = 1<<23,
Expand Down Expand Up @@ -1271,6 +1285,9 @@ enum ieee80211_hw_flags {
* @max_tx_aggregation_subframes: maximum number of subframes in an
* aggregate an HT driver will transmit, used by the peer as a
* hint to size its reorder buffer.
*
* @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX
* (if %IEEE80211_HW_QUEUE_CONTROL is set)
*/
struct ieee80211_hw {
struct ieee80211_conf conf;
Expand All @@ -1291,6 +1308,7 @@ struct ieee80211_hw {
u8 max_rate_tries;
u8 max_rx_aggregation_subframes;
u8 max_tx_aggregation_subframes;
u8 offchannel_tx_hw_queue;
};

/**
Expand Down Expand Up @@ -1698,6 +1716,61 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
* The driver may also use ieee80211_sta_eosp_irqsafe() in this case.
*/

/**
* DOC: HW queue control
*
* Before HW queue control was introduced, mac80211 only had a single static
* assignment of per-interface AC software queues to hardware queues. This
* was problematic for a few reasons:
* 1) off-channel transmissions might get stuck behind other frames
* 2) multiple virtual interfaces couldn't be handled correctly
* 3) after-DTIM frames could get stuck behind other frames
*
* To solve this, hardware typically uses multiple different queues for all
* the different usages, and this needs to be propagated into mac80211 so it
* won't have the same problem with the software queues.
*
* Therefore, mac80211 now offers the %IEEE80211_HW_QUEUE_CONTROL capability
* flag that tells it that the driver implements its own queue control. To do
* so, the driver will set up the various queues in each &struct ieee80211_vif
* and the offchannel queue in &struct ieee80211_hw. In response, mac80211 will
* use those queue IDs in the hw_queue field of &struct ieee80211_tx_info and
* if necessary will queue the frame on the right software queue that mirrors
* the hardware queue.
* Additionally, the driver has to then use these HW queue IDs for the queue
* management functions (ieee80211_stop_queue() et al.)
*
* The driver is free to set up the queue mappings as needed, multiple virtual
* interfaces may map to the same hardware queues if needed. The setup has to
* happen during add_interface or change_interface callbacks. For example, a
* driver supporting station+station and station+AP modes might decide to have
* 10 hardware queues to handle different scenarios:
*
* 4 AC HW queues for 1st vif: 0, 1, 2, 3
* 4 AC HW queues for 2nd vif: 4, 5, 6, 7
* after-DTIM queue for AP: 8
* off-channel queue: 9
*
* It would then set up the hardware like this:
* hw.offchannel_tx_hw_queue = 9
*
* and the first virtual interface that is added as follows:
* vif.hw_queue[IEEE80211_AC_VO] = 0
* vif.hw_queue[IEEE80211_AC_VI] = 1
* vif.hw_queue[IEEE80211_AC_BE] = 2
* vif.hw_queue[IEEE80211_AC_BK] = 3
* vif.cab_queue = 8 // if AP mode, otherwise %IEEE80211_INVAL_HW_QUEUE
* and the second virtual interface with 4-7.
*
* If queue 6 gets full, for example, mac80211 would only stop the second
* virtual interface's BE queue since virtual interface queues are per AC.
*
* Note that the vif.cab_queue value should be set to %IEEE80211_INVAL_HW_QUEUE
* whenever the queue is not used (i.e. the interface is not in AP mode) if the
* queue could potentially be shared since mac80211 will look at cab_queue when
* a queue is stopped/woken even if the interface is not in AP mode.
*/

/**
* enum ieee80211_filter_flags - hardware filter flags
*
Expand Down
39 changes: 20 additions & 19 deletions trunk/net/mac80211/agg-tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,25 +286,25 @@ static inline int ieee80211_ac_from_tid(int tid)
* a global "agg_queue_stop" refcount.
*/
static void __acquires(agg_queue)
ieee80211_stop_queue_agg(struct ieee80211_local *local, int tid)
ieee80211_stop_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
{
int queue = ieee80211_ac_from_tid(tid);
int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];

if (atomic_inc_return(&local->agg_queue_stop[queue]) == 1)
if (atomic_inc_return(&sdata->local->agg_queue_stop[queue]) == 1)
ieee80211_stop_queue_by_reason(
&local->hw, queue,
&sdata->local->hw, queue,
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
__acquire(agg_queue);
}

static void __releases(agg_queue)
ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid)
ieee80211_wake_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
{
int queue = ieee80211_ac_from_tid(tid);
int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];

if (atomic_dec_return(&local->agg_queue_stop[queue]) == 0)
if (atomic_dec_return(&sdata->local->agg_queue_stop[queue]) == 0)
ieee80211_wake_queue_by_reason(
&local->hw, queue,
&sdata->local->hw, queue,
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
__release(agg_queue);
}
Expand All @@ -314,13 +314,14 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid)
* requires a call to ieee80211_agg_splice_finish later
*/
static void __acquires(agg_queue)
ieee80211_agg_splice_packets(struct ieee80211_local *local,
ieee80211_agg_splice_packets(struct ieee80211_sub_if_data *sdata,
struct tid_ampdu_tx *tid_tx, u16 tid)
{
int queue = ieee80211_ac_from_tid(tid);
struct ieee80211_local *local = sdata->local;
int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
unsigned long flags;

ieee80211_stop_queue_agg(local, tid);
ieee80211_stop_queue_agg(sdata, tid);

if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
" from the pending queue\n", tid))
Expand All @@ -336,9 +337,9 @@ ieee80211_agg_splice_packets(struct ieee80211_local *local,
}

static void __releases(agg_queue)
ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid)
ieee80211_agg_splice_finish(struct ieee80211_sub_if_data *sdata, u16 tid)
{
ieee80211_wake_queue_agg(local, tid);
ieee80211_wake_queue_agg(sdata, tid);
}

void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
Expand Down Expand Up @@ -376,9 +377,9 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
" tid %d\n", tid);
#endif
spin_lock_bh(&sta->lock);
ieee80211_agg_splice_packets(local, tid_tx, tid);
ieee80211_agg_splice_packets(sdata, tid_tx, tid);
ieee80211_assign_tid_tx(sta, tid, NULL);
ieee80211_agg_splice_finish(local, tid);
ieee80211_agg_splice_finish(sdata, tid);
spin_unlock_bh(&sta->lock);

kfree_rcu(tid_tx, rcu_head);
Expand Down Expand Up @@ -598,14 +599,14 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
*/
spin_lock_bh(&sta->lock);

ieee80211_agg_splice_packets(local, tid_tx, tid);
ieee80211_agg_splice_packets(sta->sdata, tid_tx, tid);
/*
* Now mark as operational. This will be visible
* in the TX path, and lets it go lock-free in
* the common case.
*/
set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
ieee80211_agg_splice_finish(local, tid);
ieee80211_agg_splice_finish(sta->sdata, tid);

spin_unlock_bh(&sta->lock);
}
Expand Down Expand Up @@ -790,12 +791,12 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
* more.
*/

ieee80211_agg_splice_packets(local, tid_tx, tid);
ieee80211_agg_splice_packets(sta->sdata, tid_tx, tid);

/* future packets must not find the tid_tx struct any more */
ieee80211_assign_tid_tx(sta, tid, NULL);

ieee80211_agg_splice_finish(local, tid);
ieee80211_agg_splice_finish(sta->sdata, tid);

kfree_rcu(tid_tx, rcu_head);

Expand Down
6 changes: 6 additions & 0 deletions trunk/net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -2106,6 +2106,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,

IEEE80211_SKB_CB(skb)->flags = flags;

if (flags & IEEE80211_TX_CTL_TX_OFFCHAN)
IEEE80211_SKB_CB(skb)->hw_queue =
local->hw.offchannel_tx_hw_queue;

skb->dev = sdata->dev;

*cookie = (unsigned long) skb;
Expand Down Expand Up @@ -2147,6 +2151,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
/* modify cookie to prevent API mismatches */
*cookie ^= 2;
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
IEEE80211_SKB_CB(skb)->hw_queue =
local->hw.offchannel_tx_hw_queue;
local->hw_roc_skb = skb;
local->hw_roc_skb_for_status = skb;
mutex_unlock(&local->mtx);
Expand Down
1 change: 1 addition & 0 deletions trunk/net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -1449,6 +1449,7 @@ void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
enum queue_stop_reason reason);
void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
enum queue_stop_reason reason);
void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue);
void ieee80211_add_pending_skb(struct ieee80211_local *local,
struct sk_buff *skb);
void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
Expand Down
Loading

0 comments on commit 2d1d9b3

Please sign in to comment.