Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 136209
b: refs/heads/master
c: cd8ffc8
h: refs/heads/master
i:
  136207: 966f430
v: v3
  • Loading branch information
Johannes Berg authored and John W. Linville committed Mar 28, 2009
1 parent e49af1c commit cbf3c77
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 79 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: a220858d30604902f650074bfac5a7598bc97ea4
refs/heads/master: cd8ffc800ce18e558335c4946b2217864fc16045
4 changes: 4 additions & 0 deletions trunk/include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,9 @@ struct ieee80211_bss_conf {
* @IEEE80211_TX_INTFL_RCALGO: mac80211 internal flag, do not test or
* set this flag in the driver; indicates that the rate control
* algorithm was used and should be notified of TX status
* @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211,
* used to indicate that a pending frame requires TX processing before
* it can be sent out.
*/
enum mac80211_tx_control_flags {
IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0),
Expand All @@ -264,6 +267,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11),
IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12),
IEEE80211_TX_INTFL_RCALGO = BIT(13),
IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14),
};

/**
Expand Down
136 changes: 84 additions & 52 deletions trunk/net/mac80211/agg-tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,16 +132,6 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
state = &sta->ampdu_mlme.tid_state_tx[tid];

if (local->hw.ampdu_queues) {
if (initiator) {
/*
* Stop the AC queue to avoid issues where we send
* unaggregated frames already before the delba.
*/
ieee80211_stop_queue_by_reason(&local->hw,
local->hw.queues + sta->tid_to_tx_q[tid],
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
}

/*
* Pretend the driver woke the queue, just in case
* it disabled it before the session was stopped.
Expand All @@ -158,6 +148,10 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
/* HW shall not deny going back to legacy */
if (WARN_ON(ret)) {
*state = HT_AGG_STATE_OPERATIONAL;
/*
* We may have pending packets get stuck in this case...
* Not bothering with a workaround for now.
*/
}

return ret;
Expand Down Expand Up @@ -226,13 +220,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
ra, tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */

if (hw->ampdu_queues && ieee80211_ac_from_tid(tid) == 0) {
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "rejecting on voice AC\n");
#endif
return -EINVAL;
}

rcu_read_lock();

sta = sta_info_get(local, ra);
Expand Down Expand Up @@ -267,6 +254,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
}

spin_lock_bh(&sta->lock);
spin_lock(&local->ampdu_lock);

sdata = sta->sdata;

Expand Down Expand Up @@ -308,21 +296,19 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
ret = -ENOSPC;
goto err_unlock_sta;
}

/*
* If we successfully allocate the session, we can't have
* anything going on on the queue this TID maps into, so
* stop it for now. This is a "virtual" stop using the same
* mechanism that drivers will use.
*
* XXX: queue up frames for this session in the sta_info
* struct instead to avoid hitting all other STAs.
*/
ieee80211_stop_queue_by_reason(
&local->hw, hw->queues + qn,
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
}

/*
* While we're asking the driver about the aggregation,
* stop the AC queue so that we don't have to worry
* about frames that came in while we were doing that,
* which would require us to put them to the AC pending
* afterwards which just makes the code more complex.
*/
ieee80211_stop_queue_by_reason(
&local->hw, ieee80211_ac_from_tid(tid),
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);

/* prepare A-MPDU MLME for Tx aggregation */
sta->ampdu_mlme.tid_tx[tid] =
kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
Expand All @@ -336,6 +322,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
goto err_return_queue;
}

skb_queue_head_init(&sta->ampdu_mlme.tid_tx[tid]->pending);

/* Tx timer */
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
sta_addba_resp_timer_expired;
Expand All @@ -362,6 +350,12 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
}
sta->tid_to_tx_q[tid] = qn;

/* Driver vetoed or OKed, but we can take packets again now */
ieee80211_wake_queue_by_reason(
&local->hw, ieee80211_ac_from_tid(tid),
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);

spin_unlock(&local->ampdu_lock);
spin_unlock_bh(&sta->lock);

/* send an addBA request */
Expand All @@ -388,38 +382,79 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
sta->ampdu_mlme.tid_tx[tid] = NULL;
err_return_queue:
if (qn >= 0) {
/* We failed, so start queue again right away. */
ieee80211_wake_queue_by_reason(hw, hw->queues + qn,
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
/* give queue back to pool */
spin_lock(&local->queue_stop_reason_lock);
local->ampdu_ac_queue[qn] = -1;
spin_unlock(&local->queue_stop_reason_lock);
}
ieee80211_wake_queue_by_reason(
&local->hw, ieee80211_ac_from_tid(tid),
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
err_unlock_sta:
spin_unlock(&local->ampdu_lock);
spin_unlock_bh(&sta->lock);
unlock:
rcu_read_unlock();
return ret;
}
EXPORT_SYMBOL(ieee80211_start_tx_ba_session);

/*
* splice packets from the STA's pending to the local pending,
* requires a call to ieee80211_agg_splice_finish and holding
* local->ampdu_lock across both calls.
*/
static void ieee80211_agg_splice_packets(struct ieee80211_local *local,
struct sta_info *sta, u16 tid)
{
unsigned long flags;
u16 queue = ieee80211_ac_from_tid(tid);

ieee80211_stop_queue_by_reason(
&local->hw, queue,
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);

if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) {
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
/* mark queue as pending, it is stopped already */
__set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING,
&local->queue_stop_reasons[queue]);
/* copy over remaining packets */
skb_queue_splice_tail_init(
&sta->ampdu_mlme.tid_tx[tid]->pending,
&local->pending[queue]);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}
}

static void ieee80211_agg_splice_finish(struct ieee80211_local *local,
struct sta_info *sta, u16 tid)
{
u16 queue = ieee80211_ac_from_tid(tid);

ieee80211_wake_queue_by_reason(
&local->hw, queue,
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
}

/* caller must hold sta->lock */
static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
struct sta_info *sta, u16 tid)
{
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
#endif

if (local->hw.ampdu_queues) {
/*
* Wake up the A-MPDU queue, we stopped it earlier,
* this will in turn wake the entire AC.
*/
ieee80211_wake_queue_by_reason(&local->hw,
local->hw.queues + sta->tid_to_tx_q[tid],
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
}
spin_lock(&local->ampdu_lock);
ieee80211_agg_splice_packets(local, sta, tid);
/*
* NB: we rely on sta->lock being taken in the TX
* processing here when adding to the pending queue,
* otherwise we could only change the state of the
* session to OPERATIONAL _here_.
*/
ieee80211_agg_splice_finish(local, sta, tid);
spin_unlock(&local->ampdu_lock);

local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_OPERATIONAL,
&sta->sta, tid, NULL);
Expand Down Expand Up @@ -602,22 +637,19 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);

spin_lock_bh(&sta->lock);
spin_lock(&local->ampdu_lock);

if (*state & HT_AGG_STATE_INITIATOR_MSK &&
hw->ampdu_queues) {
/*
* Wake up this queue, we stopped it earlier,
* this will in turn wake the entire AC.
*/
ieee80211_wake_queue_by_reason(hw,
hw->queues + sta->tid_to_tx_q[tid],
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
}
ieee80211_agg_splice_packets(local, sta, tid);

*state = HT_AGG_STATE_IDLE;
/* from now on packets are no longer put onto sta->pending */
sta->ampdu_mlme.addba_req_num[tid] = 0;
kfree(sta->ampdu_mlme.tid_tx[tid]);
sta->ampdu_mlme.tid_tx[tid] = NULL;

ieee80211_agg_splice_finish(local, sta, tid);

spin_unlock(&local->ampdu_lock);
spin_unlock_bh(&sta->lock);

rcu_read_unlock();
Expand Down
8 changes: 8 additions & 0 deletions trunk/net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,14 @@ struct ieee80211_local {
struct sk_buff_head pending[IEEE80211_MAX_QUEUES];
struct tasklet_struct tx_pending_tasklet;

/*
* This lock is used to prevent concurrent A-MPDU
* session start/stop processing, this thus also
* synchronises the ->ampdu_action() callback to
* drivers and limits it to one at a time.
*/
spinlock_t ampdu_lock;

/* number of interfaces with corresponding IFF_ flags */
atomic_t iff_allmultis, iff_promiscs;

Expand Down
2 changes: 2 additions & 0 deletions trunk/net/mac80211/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
skb_queue_head_init(&local->skb_queue);
skb_queue_head_init(&local->skb_queue_unreliable);

spin_lock_init(&local->ampdu_lock);

return local_to_hw(local);
}
EXPORT_SYMBOL(ieee80211_alloc_hw);
Expand Down
5 changes: 5 additions & 0 deletions trunk/net/mac80211/sta_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,11 @@ void sta_info_destroy(struct sta_info *sta)
tid_tx = sta->ampdu_mlme.tid_tx[i];
if (tid_tx) {
del_timer_sync(&tid_tx->addba_resp_timer);
/*
* STA removed while aggregation session being
* started? Bit odd, but purge frames anyway.
*/
skb_queue_purge(&tid_tx->pending);
kfree(tid_tx);
}
}
Expand Down
2 changes: 2 additions & 0 deletions trunk/net/mac80211/sta_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,13 @@ enum ieee80211_sta_info_flags {
* struct tid_ampdu_tx - TID aggregation information (Tx).
*
* @addba_resp_timer: timer for peer's response to addba request
* @pending: pending frames queue -- use sta's spinlock to protect
* @ssn: Starting Sequence Number expected to be aggregated.
* @dialog_token: dialog token for aggregation session
*/
struct tid_ampdu_tx {
struct timer_list addba_resp_timer;
struct sk_buff_head pending;
u16 ssn;
u8 dialog_token;
};
Expand Down
Loading

0 comments on commit cbf3c77

Please sign in to comment.