git: c78d70298ede - main - iwn: fix TX QoS AC -> TID mapping for A-MPDU selection

From: Adrian Chadd <adrian_at_FreeBSD.org>
Date: Mon, 19 Oct 2026 00:36:27 UTC
The branch main has been updated by adrian:

URL: https://cgit.FreeBSD.org/src/commit/?id=c78d70298edef4c599b503536d193caeb8204784

commit c78d70298edef4c599b503536d193caeb8204784
Author:     Adrian Chadd <adrian@FreeBSD.org>
AuthorDate: 2026-10-19 00:34:46 +0000
Commit:     Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2026-10-19 00:34:46 +0000

    iwn: fix TX QoS AC -> TID mapping for A-MPDU selection
    
    Map the packet QoS value to a TID before looking it up in the
    per node + TID AMPDU state array.
    
    The TX A-MPDU state used to be per-AC, but I changed it to be
    per-TID because it /is/ negotiated per-TID.  However this is
    not aligned correctly and A-MPDU on eg the voice queue would
    cause a mismatch and thus packets to get dropped.
    
    (TIDs 8..15 are special and session based, not traffic QoS based.)
    
    I noticed this because "ssh host" failed after a while, but
    "telnet host 22" succeeded.  It turned out that frames weren't
    making it to the driver transmit path and I traced it
    back to being dropped here.  Traffic worked for a while until
    A-MPDU TX was negotiated, and then all traffic on a TID
    would fail until the 802.11 association was re-established.
    
    Locally tested:
    
    * iwn 6205, STA mode - forced traffic into VO AC/TID
    
    MFC after: 1 week
    
    Differential Revision:  https://reviews.freebsd.org/D60848
---
 sys/dev/iwn/if_iwn.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/sys/dev/iwn/if_iwn.c b/sys/dev/iwn/if_iwn.c
index 7fc013704253..0a5e608c8071 100644
--- a/sys/dev/iwn/if_iwn.c
+++ b/sys/dev/iwn/if_iwn.c
@@ -4587,9 +4587,19 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
 	 * anyway ourselves (and should stub out / warn / etc.)
 	 */
 
+	/*
+	 * Ok, this is a bit "fun" and could do with some cleanup.
+	 * 'ac' here is (mostly) the AC, not TID.  It's actually used
+	 * as the destination txq.
+	 *
+	 * For A-MPDU enabled queues, 'ac' becomes the private queue
+	 * allocated for this TID.  However, ni_tx_ampdu[] is now per
+	 * TID, not per AC.  So a little twisty logic is done here.
+	 */
 	ac = M_WME_GETAC(m);
 	if (m->m_flags & M_AMPDU_MPDU) {
-		struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac];
+		struct ieee80211_tx_ampdu *tap =
+		    &ni->ni_tx_ampdu[WME_AC_TO_TID(ac)];
 
 		if (!IEEE80211_AMPDU_RUNNING(tap))
 			return (EINVAL);