diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-03-23 19:28:36 +0300 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-03-28 03:13:21 +0300 |
commit | f0e72851f7ad108fed20426b46a18ab5fcd5729f (patch) | |
tree | 5e8d1795fa06127f9c9ae9755140eb0d871ae2f9 /net | |
parent | 2de8e0d999b8790861cd3749bec2236ccc1c8110 (diff) | |
download | linux-f0e72851f7ad108fed20426b46a18ab5fcd5729f.tar.xz |
mac80211: fix A-MPDU queue assignment
Internally, mac80211 requires the skb's queue mapping to be set
to the AC queue, not the virtual A-MPDU queue. This is not done
correctly currently, this patch moves the code down to directly
before the driver is invoked and adds a comment that it will be
moved into the driver later.
Since this requires __ieee80211_tx() to have the sta pointer,
make sure to provide it in ieee80211_tx_pending().
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Reviewed-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/tx.c | 35 |
1 files changed, 27 insertions, 8 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 51bf49cc75bc..0d97cad84b1b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1024,13 +1024,8 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, spin_lock_irqsave(&tx->sta->lock, flags); state = &tx->sta->ampdu_mlme.tid_state_tx[tid]; - if (*state == HT_AGG_STATE_OPERATIONAL) { + if (*state == HT_AGG_STATE_OPERATIONAL) info->flags |= IEEE80211_TX_CTL_AMPDU; - if (local->hw.ampdu_queues) - skb_set_queue_mapping( - skb, tx->local->hw.queues + - tx->sta->tid_to_tx_q[tid]); - } spin_unlock_irqrestore(&tx->sta->lock, flags); } @@ -1103,10 +1098,29 @@ static int __ieee80211_tx(struct ieee80211_local *local, skb_get_queue_mapping(skb))) return IEEE80211_TX_PENDING; - if (fragm) { - info = IEEE80211_SKB_CB(skb); + info = IEEE80211_SKB_CB(skb); + + if (fragm) info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | IEEE80211_TX_CTL_FIRST_FRAGMENT); + + /* + * Internally, we need to have the queue mapping point to + * the real AC queue, not the virtual A-MPDU queue. This + * now finally sets the queue to what the driver wants. + * We will later move this down into the only driver that + * needs it, iwlwifi. + */ + if (tx->sta && local->hw.ampdu_queues && + info->flags & IEEE80211_TX_CTL_AMPDU) { + unsigned long flags; + u8 *qc = ieee80211_get_qos_ctl((void *) skb->data); + int tid = *qc & IEEE80211_QOS_CTL_TID_MASK; + + spin_lock_irqsave(&tx->sta->lock, flags); + skb_set_queue_mapping(skb, local->hw.queues + + tx->sta->tid_to_tx_q[tid]); + spin_unlock_irqrestore(&tx->sta->lock, flags); } next = skb->next; @@ -1817,9 +1831,11 @@ void ieee80211_tx_pending(unsigned long data) struct ieee80211_local *local = (struct ieee80211_local *)data; struct net_device *dev = local->mdev; struct ieee80211_tx_stored_packet *store; + struct ieee80211_hdr *hdr; struct ieee80211_tx_data tx; int i, ret; + rcu_read_lock(); netif_tx_lock_bh(dev); for (i = 0; i < local->hw.queues; i++) { /* Check that this queue is ok */ @@ -1839,6 +1855,8 @@ void ieee80211_tx_pending(unsigned long data) store = &local->pending_packet[i]; tx.flags = 0; tx.skb = store->skb; + hdr = (struct ieee80211_hdr *)tx.skb->data; + tx.sta = sta_info_get(local, hdr->addr1); ret = __ieee80211_tx(local, &tx); store->skb = tx.skb; if (!ret) { @@ -1847,6 +1865,7 @@ void ieee80211_tx_pending(unsigned long data) } } netif_tx_unlock_bh(dev); + rcu_read_unlock(); } /* functions for drivers to get certain frames */ |