Search Linux Wireless

[PATCH 2/8] mac80211: fix A-MPDU queue assignment

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxxxxxx>
---
 net/mac80211/tx.c |   35 +++++++++++++++++++++++++++--------
 1 file changed, 27 insertions(+), 8 deletions(-)

--- wireless-testing.orig/net/mac80211/tx.c	2009-03-23 13:59:20.000000000 +0100
+++ wireless-testing/net/mac80211/tx.c	2009-03-23 14:03:45.000000000 +0100
@@ -1024,13 +1024,8 @@ __ieee80211_tx_prepare(struct ieee80211_
 
 		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 ieee802
 					    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 
 	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 
 		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 
 		}
 	}
 	netif_tx_unlock_bh(dev);
+	rcu_read_unlock();
 }
 
 /* functions for drivers to get certain frames */

-- 

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux