git: 32ea8209825a - main - LinuxKPI: 802.11: add compat.linuxkpi.80211.IF.dump_stas_queues

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Mon, 29 Dec 2025 02:55:14 UTC
The branch main has been updated by bz:

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

commit 32ea8209825af594cbfa1fc654d45eb9a6aab528
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2025-12-28 17:03:41 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2025-12-29 02:48:14 +0000

    LinuxKPI: 802.11: add compat.linuxkpi.80211.IF.dump_stas_queues
    
    Extend the normal compat.linuxkpi.80211.IF.dump_stas sysctl by
    queue information.  This was helpful for debugging various issues,
    like selecting the outbound queue, stopping queues for BAR and helped
    finding multiple bugs.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      3 days
---
 share/man/man4/linuxkpi_wlan.4               |  9 +++-
 sys/compat/linuxkpi/common/src/linux_80211.c | 78 ++++++++++++++++++++++++++--
 sys/compat/linuxkpi/common/src/linux_80211.h |  4 ++
 3 files changed, 85 insertions(+), 6 deletions(-)

diff --git a/share/man/man4/linuxkpi_wlan.4 b/share/man/man4/linuxkpi_wlan.4
index 136e04c32bb7..65c77d8d7631 100644
--- a/share/man/man4/linuxkpi_wlan.4
+++ b/share/man/man4/linuxkpi_wlan.4
@@ -6,7 +6,7 @@
 .\" This documentation was written by Bj\xc3\xb6rn Zeeb under sponsorship from
 .\" the FreeBSD Foundation.
 .\"
-.Dd June 13, 2025
+.Dd December 28, 2025
 .Dt LINUXKPI_WLAN 4
 .Os
 .Sh NAME
@@ -112,6 +112,13 @@ Print statistics for a given, associated
 .Xr wlan 4
 interface; typically IF would be
 .Em wlan0 .
+.It Va compat.linuxkpi.80211.IF.dump_stas_queues
+Like
+.Va compat.linuxkpi.80211.IF.dump_stas
+but also print queue statistics.
+This sysctl is
+.Sq hidden
+and normally only needed for debugging purposes.
 .El
 .Sh SEE ALSO
 .Xr iwlwifi 4 ,
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c
index 02724433d89d..28c9c62309fe 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211.c
@@ -282,7 +282,7 @@ lkpi_nl80211_sta_info_to_str(struct sbuf *s, const char *prefix,
 }
 
 static void
-lkpi_80211_dump_lvif_stas(struct lkpi_vif *lvif, struct sbuf *s)
+lkpi_80211_dump_lvif_stas(struct lkpi_vif *lvif, struct sbuf *s, bool dump_queues)
 {
 	struct lkpi_hw *lhw;
 	struct ieee80211_hw *hw;
@@ -292,6 +292,7 @@ lkpi_80211_dump_lvif_stas(struct lkpi_vif *lvif, struct sbuf *s)
 	struct ieee80211_sta *sta;
 	struct station_info sinfo;
 	int error;
+	uint8_t tid;
 
 	vif = LVIF_TO_VIF(lvif);
 	vap = LVIF_TO_VAP(lvif);
@@ -376,6 +377,39 @@ lkpi_80211_dump_lvif_stas(struct lkpi_vif *lvif, struct sbuf *s)
 		sbuf_printf(s, "         he_dcm %u he_gi %u he_ru_alloc %u eht_gi %u\n",
 		    sinfo.txrate.he_dcm, sinfo.txrate.he_gi, sinfo.txrate.he_ru_alloc,
 		    sinfo.txrate.eht_gi);
+
+		if (!dump_queues)
+			continue;
+
+		/* Dump queue information. */
+		sbuf_printf(s, " Queue information:\n");
+		sbuf_printf(s, "  frms direct tx %ju\n", lsta->frms_tx);
+		for (tid = 0; tid <= IEEE80211_NUM_TIDS; tid++) {
+			struct lkpi_txq *ltxq;
+
+			if (sta->txq[tid] == NULL) {
+				sbuf_printf(s, "  tid %-2u NOQ\n", tid);
+				continue;
+			}
+
+			ltxq = TXQ_TO_LTXQ(sta->txq[tid]);
+#ifdef __notyet__
+			sbuf_printf(s, "  tid %-2u flags: %b "
+			    "txq_generation %u skbq len %d\n",
+			    tid, ltxq->flags, LKPI_TXQ_FLAGS_BITS,
+			    ltxq->txq_generation,
+			    skb_queue_len_lockless(&ltxq->skbq));
+#else
+			sbuf_printf(s, "  tid %-2u "
+			    "txq_generation %u skbq len %d\n",
+			    tid,
+			    ltxq->txq_generation,
+			    skb_queue_len_lockless(&ltxq->skbq));
+#endif
+			sbuf_printf(s, "         frms_enqueued %ju frms_dequeued %ju "
+			    "frms_tx %ju\n",
+			    ltxq->frms_enqueued, ltxq->frms_dequeued, ltxq->frms_tx);
+		}
 	}
 	wiphy_unlock(hw->wiphy);
 }
@@ -393,7 +427,28 @@ lkpi_80211_dump_stas(SYSCTL_HANDLER_ARGS)
 
 	sbuf_new_for_sysctl(&s, NULL, 1024, req);
 
-	lkpi_80211_dump_lvif_stas(lvif, &s);
+	lkpi_80211_dump_lvif_stas(lvif, &s, false);
+
+	sbuf_finish(&s);
+	sbuf_delete(&s);
+
+	return (0);
+}
+
+static int
+lkpi_80211_dump_sta_queues(SYSCTL_HANDLER_ARGS)
+{
+	struct lkpi_vif *lvif;
+	struct sbuf s;
+
+	if (req->newptr)
+		return (EPERM);
+
+	lvif = (struct lkpi_vif *)arg1;
+
+	sbuf_new_for_sysctl(&s, NULL, 1024, req);
+
+	lkpi_80211_dump_lvif_stas(lvif, &s, true);
 
 	sbuf_finish(&s);
 	sbuf_delete(&s);
@@ -4173,6 +4228,11 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],
 	    SYSCTL_CHILDREN(node), OID_AUTO, "dump_stas",
 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, lvif, 0,
 	    lkpi_80211_dump_stas, "A", "Dump sta statistics of this vif");
+	SYSCTL_ADD_PROC(&lvif->sysctl_ctx,
+	    SYSCTL_CHILDREN(node), OID_AUTO, "dump_stas_queues",
+	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE | CTLFLAG_SKIP, lvif, 0,
+	    lkpi_80211_dump_sta_queues, "A",
+	    "Dump queue statistics for any sta of this vif");
 
 	IMPROVE();
 
@@ -5690,6 +5750,7 @@ lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m)
 
 	LKPI_80211_LTXQ_LOCK(ltxq);
 	skb_queue_tail(&ltxq->skbq, skb);
+	ltxq->frms_enqueued++;
 #ifdef LINUXKPI_DEBUG_80211
 	if (linuxkpi_debug_80211 & D80211_TRACE_TX)
 		printf("%s:%d mo_wake_tx_queue :: %d %lu lsta %p sta %p "
@@ -5719,6 +5780,7 @@ ops_tx:
 	control.sta = sta;
 	wiphy_lock(hw->wiphy);
 	lkpi_80211_mo_tx(hw, &control, skb);
+	lsta->frms_tx++;
 	wiphy_unlock(hw->wiphy);
 }
 
@@ -8121,6 +8183,8 @@ linuxkpi_ieee80211_tx_dequeue(struct ieee80211_hw *hw,
 
 	LKPI_80211_LTXQ_LOCK(ltxq);
 	skb = skb_dequeue(&ltxq->skbq);
+	if (skb != NULL)
+		ltxq->frms_dequeued++;
 	LKPI_80211_LTXQ_UNLOCK(ltxq);
 
 stopped:
@@ -8769,18 +8833,21 @@ linuxkpi_ieee80211_handle_wake_tx_queue(struct ieee80211_hw *hw,
     struct ieee80211_txq *txq)
 {
 	struct lkpi_hw *lhw;
-	struct ieee80211_txq *ntxq;
-	struct ieee80211_tx_control control;
-        struct sk_buff *skb;
 
 	lhw = HW_TO_LHW(hw);
 
 	LKPI_80211_LHW_TXQ_LOCK(lhw);
 	ieee80211_txq_schedule_start(hw, txq->ac);
 	do {
+		struct lkpi_txq *ltxq;
+		struct ieee80211_txq *ntxq;
+		struct ieee80211_tx_control control;
+		struct sk_buff *skb;
+
 		ntxq = ieee80211_next_txq(hw, txq->ac);
 		if (ntxq == NULL)
 			break;
+		ltxq = TXQ_TO_LTXQ(ntxq);
 
 		memset(&control, 0, sizeof(control));
 		control.sta = ntxq->sta;
@@ -8788,6 +8855,7 @@ linuxkpi_ieee80211_handle_wake_tx_queue(struct ieee80211_hw *hw,
 			skb = linuxkpi_ieee80211_tx_dequeue(hw, ntxq);
 			if (skb == NULL)
 				break;
+			ltxq->frms_tx++;
 			lkpi_80211_mo_tx(hw, &control, skb);
 		} while(1);
 
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.h b/sys/compat/linuxkpi/common/src/linux_80211.h
index fcbef46fc6de..d4f18fcafbba 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.h
+++ b/sys/compat/linuxkpi/common/src/linux_80211.h
@@ -154,6 +154,9 @@ struct lkpi_txq {
 	bool			stopped;
 	uint32_t		txq_generation;
 	struct sk_buff_head	skbq;
+	uint64_t		frms_enqueued;
+	uint64_t		frms_dequeued;
+	uint64_t		frms_tx;
 
 	/* Must be last! */
 	struct ieee80211_txq	txq __aligned(CACHE_LINE_SIZE);
@@ -180,6 +183,7 @@ struct lkpi_sta {
 	bool			in_mgd;				/* XXX-BZ should this be per-vif? */
 
 	struct station_info	sinfo;				/* statistics */
+	uint64_t		frms_tx;			/* (*tx) */
 
 	/* Must be last! */
 	struct ieee80211_sta	sta __aligned(CACHE_LINE_SIZE);