Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f0e72851 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville
Browse files

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: default avatarJohannes Berg <johannes@sipsolutions.net>
Reviewed-by: default avatarLuis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 2de8e0d9
Loading
Loading
Loading
Loading
+27 −8
Original line number Diff line number Diff line
@@ -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);

		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 */