summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjoern A. Zeeb <bz@FreeBSD.org>2025-12-28 17:03:41 +0000
committerBjoern A. Zeeb <bz@FreeBSD.org>2026-01-16 08:48:47 +0000
commit6b9c0ac008a9c52b21b05c96ead6def41aa89ead (patch)
treefa9ae5bcfbe9772f8ed13ca18ebe953a4149b888
parent9755a80363549cc5504b4bb2d18a4a12e34ded28 (diff)
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 (cherry picked from commit 32ea8209825af594cbfa1fc654d45eb9a6aab528)
-rw-r--r--share/man/man4/linuxkpi_wlan.49
-rw-r--r--sys/compat/linuxkpi/common/src/linux_80211.c78
-rw-r--r--sys/compat/linuxkpi/common/src/linux_80211.h4
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);