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
This commit is contained in:
Bjoern A. Zeeb
2025-12-28 17:03:41 +00:00
parent b6672803a1
commit 32ea820982
3 changed files with 85 additions and 6 deletions
+8 -1
View File
@@ -6,7 +6,7 @@
.\" This documentation was written by Bj\xc3\xb6rn Zeeb under sponsorship from .\" This documentation was written by Bj\xc3\xb6rn Zeeb under sponsorship from
.\" the FreeBSD Foundation. .\" the FreeBSD Foundation.
.\" .\"
.Dd June 13, 2025 .Dd December 28, 2025
.Dt LINUXKPI_WLAN 4 .Dt LINUXKPI_WLAN 4
.Os .Os
.Sh NAME .Sh NAME
@@ -112,6 +112,13 @@ Print statistics for a given, associated
.Xr wlan 4 .Xr wlan 4
interface; typically IF would be interface; typically IF would be
.Em wlan0 . .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 .El
.Sh SEE ALSO .Sh SEE ALSO
.Xr iwlwifi 4 , .Xr iwlwifi 4 ,
+73 -5
View File
@@ -282,7 +282,7 @@ lkpi_nl80211_sta_info_to_str(struct sbuf *s, const char *prefix,
} }
static void 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 lkpi_hw *lhw;
struct ieee80211_hw *hw; 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 ieee80211_sta *sta;
struct station_info sinfo; struct station_info sinfo;
int error; int error;
uint8_t tid;
vif = LVIF_TO_VIF(lvif); vif = LVIF_TO_VIF(lvif);
vap = LVIF_TO_VAP(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", 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.he_dcm, sinfo.txrate.he_gi, sinfo.txrate.he_ru_alloc,
sinfo.txrate.eht_gi); 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); wiphy_unlock(hw->wiphy);
} }
@@ -393,7 +427,28 @@ lkpi_80211_dump_stas(SYSCTL_HANDLER_ARGS)
sbuf_new_for_sysctl(&s, NULL, 1024, req); 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_finish(&s);
sbuf_delete(&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", SYSCTL_CHILDREN(node), OID_AUTO, "dump_stas",
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, lvif, 0, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, lvif, 0,
lkpi_80211_dump_stas, "A", "Dump sta statistics of this vif"); 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(); IMPROVE();
@@ -5690,6 +5750,7 @@ lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m)
LKPI_80211_LTXQ_LOCK(ltxq); LKPI_80211_LTXQ_LOCK(ltxq);
skb_queue_tail(&ltxq->skbq, skb); skb_queue_tail(&ltxq->skbq, skb);
ltxq->frms_enqueued++;
#ifdef LINUXKPI_DEBUG_80211 #ifdef LINUXKPI_DEBUG_80211
if (linuxkpi_debug_80211 & D80211_TRACE_TX) if (linuxkpi_debug_80211 & D80211_TRACE_TX)
printf("%s:%d mo_wake_tx_queue :: %d %lu lsta %p sta %p " printf("%s:%d mo_wake_tx_queue :: %d %lu lsta %p sta %p "
@@ -5719,6 +5780,7 @@ lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m)
control.sta = sta; control.sta = sta;
wiphy_lock(hw->wiphy); wiphy_lock(hw->wiphy);
lkpi_80211_mo_tx(hw, &control, skb); lkpi_80211_mo_tx(hw, &control, skb);
lsta->frms_tx++;
wiphy_unlock(hw->wiphy); wiphy_unlock(hw->wiphy);
} }
@@ -8121,6 +8183,8 @@ linuxkpi_ieee80211_tx_dequeue(struct ieee80211_hw *hw,
LKPI_80211_LTXQ_LOCK(ltxq); LKPI_80211_LTXQ_LOCK(ltxq);
skb = skb_dequeue(&ltxq->skbq); skb = skb_dequeue(&ltxq->skbq);
if (skb != NULL)
ltxq->frms_dequeued++;
LKPI_80211_LTXQ_UNLOCK(ltxq); LKPI_80211_LTXQ_UNLOCK(ltxq);
stopped: stopped:
@@ -8769,18 +8833,21 @@ linuxkpi_ieee80211_handle_wake_tx_queue(struct ieee80211_hw *hw,
struct ieee80211_txq *txq) struct ieee80211_txq *txq)
{ {
struct lkpi_hw *lhw; struct lkpi_hw *lhw;
struct ieee80211_txq *ntxq;
struct ieee80211_tx_control control;
struct sk_buff *skb;
lhw = HW_TO_LHW(hw); lhw = HW_TO_LHW(hw);
LKPI_80211_LHW_TXQ_LOCK(lhw); LKPI_80211_LHW_TXQ_LOCK(lhw);
ieee80211_txq_schedule_start(hw, txq->ac); ieee80211_txq_schedule_start(hw, txq->ac);
do { 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); ntxq = ieee80211_next_txq(hw, txq->ac);
if (ntxq == NULL) if (ntxq == NULL)
break; break;
ltxq = TXQ_TO_LTXQ(ntxq);
memset(&control, 0, sizeof(control)); memset(&control, 0, sizeof(control));
control.sta = ntxq->sta; 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); skb = linuxkpi_ieee80211_tx_dequeue(hw, ntxq);
if (skb == NULL) if (skb == NULL)
break; break;
ltxq->frms_tx++;
lkpi_80211_mo_tx(hw, &control, skb); lkpi_80211_mo_tx(hw, &control, skb);
} while(1); } while(1);
@@ -154,6 +154,9 @@ struct lkpi_txq {
bool stopped; bool stopped;
uint32_t txq_generation; uint32_t txq_generation;
struct sk_buff_head skbq; struct sk_buff_head skbq;
uint64_t frms_enqueued;
uint64_t frms_dequeued;
uint64_t frms_tx;
/* Must be last! */ /* Must be last! */
struct ieee80211_txq txq __aligned(CACHE_LINE_SIZE); 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? */ bool in_mgd; /* XXX-BZ should this be per-vif? */
struct station_info sinfo; /* statistics */ struct station_info sinfo; /* statistics */
uint64_t frms_tx; /* (*tx) */
/* Must be last! */ /* Must be last! */
struct ieee80211_sta sta __aligned(CACHE_LINE_SIZE); struct ieee80211_sta sta __aligned(CACHE_LINE_SIZE);