From: Cristian Papa <pcristian292@gmail.com>
To: linux-wireless@vger.kernel.org
Cc: nbd@nbd.name, lorenzo@kernel.org, ryder.lee@mediatek.com,
shayne.chen@mediatek.com, sean.wang@mediatek.com,
linux-mediatek@lists.infradead.org
Subject: [RFC PATCH 0/2] wifi: mt76: mt7603: bound the frames a station keeps in the hardware
Date: Wed, 23 Sep 2026 10:22:54 -0300 [thread overview]
Message-ID: <20260923132257.8729-1-pcristian292@gmail.com> (raw)
mt7603 completes a frame to mac80211 as soon as DMA has copied it, so
AQL never sees the frames the hardware still holds for a station. On a
TP-Link Archer XR500v (EN751221 + MT7603E) with one client, counters
added to upstream mt76 showed the hardware holding about 200 frames for
a single downloading client, nearly the whole 256-entry tx ring, and up
to 740 under bidirectional load.
With a client that toggles PM often (here a Samsung Galaxy A56 with
Bluetooth on, which enters power save several times per second under
load), every PS entry loops all of those frames back to the host, and
the PS queue keeps only 64 of them. The frames freed per second roughly
matched the client's TCP retransmissions per second.
The series holds a station's tx queues while the hardware owes it too
many TX statuses (a new MT_WCID_FLAG_TX_HOLD, honoured by the mt76 tx
scheduler like the non-AQL limit), and sizes the PS queue so that what
the hardware loops back fits. It depends on "wifi: mt76: mt7603: don't
drop short frames looped back on PS entry" [1], without which the count
leaks one frame for every BlockAck request that is looped back.
This is an RFC because I am not sure a driver-side hold is the approach
you want. Questions:
- Would you rather keep the airtime of each frame accounted until its TX
status, so that AQL sees what the hardware holds, instead of a count
in the driver?
- The marks (hold at 96, release at 48) and the PS queue size (tx ring
minus 64) were tuned with one client only.
- If a held station sees neither a TX status nor a loop-back return for
a second, its count is reset. In the tests below this happened 0 to 3
times in 30 minutes, probably when the client slept for more than a
second with frames still in the hardware. Is there a better signal?
- The raw re-send of the PS queue on wake-up bypasses the hold, so the
count can briefly exceed the high mark (up to 134 here).
Either change alone makes things worse, which is why the cap and the PS
queue size are one patch. In a 30 minute bidirectional test (iperf3
-P 4, one client, a ping from a wired host every 200 ms) that cycled
through the four combinations every minute, about 7 minutes each:
upstream bigger PSQ cap cap + PSQ
frames in hw (max) 748 844 98 134
PSQ frees per second 92 213 51 0
downlink Mbit/s 12.2 15.2 10.6 17.0
seconds without downlink 45 108 111 10
longest stall (s) 10 53 16 1
retransmits per second 15.4 8.9 10.2 3.0
uplink Mbit/s 64.0 60.7 63.8 59.3
ping median/p99 (ms) 119/339 145/2915 125/482 130/292
pings lost 6.0% 13.7% 7.5% 0.13%
The stalls come in bursts of PM toggling, with up to 22-28 PS entries
per second. In the worst stretch, the minute with the cap and the
bigger queue had 2 seconds without downlink progress, against 20, 41 and
39 in the neighbouring minutes of the other combinations.
Two shorter runs toggled the cap alone (PS queue of 64) every 30
seconds, over 60 seconds of download and 300 of bidirectional traffic,
with a 2.4 GHz wireless headset dongle nearby. In the download phases,
with the cap: PSQ frees went from 59.5 to 7.3 and from 54.5 to 5.3 per
second, retransmits from 54.9 to 8.2 and from 58.8 to 9.1 per second,
the ping median from 38 to 23 and from 32 to 25 ms, and throughput from
56 to 61 and from 59 to 63 Mbit/s. Bidirectional retransmits went from
13.5 to 6.0 and from 13.8 to 8.3 per second.
Testing: OpenWrt with kernel 6.18.41 and the mac80211 backport of
6.18.39, openwrt/mt76 at be5ce79105 plus [1], this series, the board's
local patches (EEPROM file from DT, two crash fixes, beacon stall
recovery, fixes for the mt76x2e radio) and debugfs counters that are
not part of the series. AP on channel 1, HT20. One device and one client
only: no MT7628/MT7688, and nothing with several busy stations. The
series is against wireless-next; on openwrt/mt76, where it was built
and tested, patch 1 only differs in context (mt76_wcid_primary() in the
non-AQL check).
[1] https://lore.kernel.org/linux-wireless/20260922220814.15070-1-pcristian292@gmail.com/
Tools: an AI coding assistant (Claude Opus 5.5 in Claude Code) wrote the
instrumentation, analyzed the data, and drafted these patches and this
letter; the tests ran on my device.
Cristian Papa (2):
wifi: mt76: let a driver hold a station's tx queues
wifi: mt76: mt7603: bound the frames a station keeps in the hardware
drivers/net/wireless/mediatek/mt76/mt76.h | 1 +
.../wireless/mediatek/mt76/mt7603/debugfs.c | 32 ++++++++++
.../net/wireless/mediatek/mt76/mt7603/dma.c | 7 ++-
.../net/wireless/mediatek/mt76/mt7603/init.c | 2 +
.../net/wireless/mediatek/mt76/mt7603/mac.c | 58 +++++++++++++++++++
.../net/wireless/mediatek/mt76/mt7603/main.c | 20 +++++--
.../wireless/mediatek/mt76/mt7603/mt7603.h | 51 ++++++++++++++++
drivers/net/wireless/mediatek/mt76/tx.c | 7 +++
8 files changed, 172 insertions(+), 6 deletions(-)
base-commit: 10cfa109c880092df32e396647b4afdca9be8350
prerequisite-patch-id: b2c7fb85fb032bec084c6e325be32ea1172af916
--
2.47.3
next reply other threads:[~2026-09-23 13:23 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-23 13:22 Cristian Papa [this message]
2026-09-23 13:22 ` [RFC PATCH 1/2] wifi: mt76: let a driver hold a station's tx queues Cristian Papa
2026-09-23 13:22 ` [RFC PATCH 2/2] wifi: mt76: mt7603: bound the frames a station keeps in the hardware Cristian Papa
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260923132257.8729-1-pcristian292@gmail.com \
--to=pcristian292@gmail.com \
--cc=linux-mediatek@lists.infradead.org \
--cc=linux-wireless@vger.kernel.org \
--cc=lorenzo@kernel.org \
--cc=nbd@nbd.name \
--cc=ryder.lee@mediatek.com \
--cc=sean.wang@mediatek.com \
--cc=shayne.chen@mediatek.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox