From: JB Tsai <jb.tsai@mediatek.com>
To: <nbd@nbd.name>, <lorenzo@kernel.org>
Cc: <linux-wireless@vger.kernel.org>,
<linux-mediatek@lists.infradead.org>, <Sean.Wang@mediatek.com>,
<Quan.Zhou@mediatek.com>, <Ryder.Lee@mediatek.com>,
<litien.chang@mediatek.com>, <Charlie-cy.Wu@mediatek.com>,
<jb.tsai@mediatek.com>
Subject: [PATCH] wifi: mt76: connac3: add fixedrate and autorate debugfs for rate control
Date: Fri, 24 Jul 2026 16:50:45 +0800 [thread overview]
Message-ID: <20260724085045.3155797-1-jb.tsai@mediatek.com> (raw)
From: Charlie-cy Wu <Charlie-cy.Wu@mediatek.com>
Add two debugfs interfaces to manually control the per-STA rate
adaptation via the UNI_CMD_RA firmware command:
- fixedrate: lock a STA to a fixed TX rate (SET_FIXED_RATE tag). The
value is a packed hex field describing the full PHY rate:
0x[WCID(2)][Mode][BW][MCS][Nss][SGI][Preamble]
[STBC][LDPC][SPE_EN][HeLtf]
- autorate: re-enable/disable firmware rate adaptation for a STA
(SET_AUTO_RATE tag):
0x[WCID(2)][En][Mode]
Key changes:
- Add mt7925_mcu_set_fixed_rate() sending the SET_FIXED_RATE(0x0F) TLV
- Add mt7925_mcu_set_auto_rate() sending the SET_AUTO_RATE(0x11) TLV
- Add RA command TLV structures (mt7925_ra_hdr,
mt7925_ra_fixed_rate_tlv/_v1, mt7925_ra_auto_rate_tlv) and the
UNI_CMD_RA tag enum
- Register fixedrate/autorate debugfs files and store the last value
in mt792x_dev for read back
- Translate the LDPC input to the FW's "on" value (7)
Note: EHT modes require HeLtf=1, otherwise the firmware drops all TX.
Usage:
echo 0x1D372000101 > /sys/kernel/debug/ieee80211/phyX/mt76/fixedrate
echo 0x110 > /sys/kernel/debug/ieee80211/phyX/mt76/autorate
Signed-off-by: Charlie-cy Wu <Charlie-cy.Wu@mediatek.com>
---
.../wireless/mediatek/mt76/mt7925/debugfs.c | 97 +++++++++++++++++++
.../net/wireless/mediatek/mt76/mt7925/mcu.c | 40 ++++++++
.../net/wireless/mediatek/mt76/mt7925/mcu.h | 42 ++++++++
drivers/net/wireless/mediatek/mt76/mt792x.h | 3 +
4 files changed, 182 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
index 3db564d63c15..4a043855a049 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
@@ -427,6 +427,101 @@ static int mt7925_chip_reset(void *data, u64 val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_reset, NULL, mt7925_chip_reset, "%lld\n");
+/* fixedrate input format (12 hex digits):
+ * 0x[WCID(2)][Mode][BW][MCS][Nss][SGI][Preamble][STBC][LDPC][SPE_EN][HeLtf]
+ * The RA tag is fixed to SET_FIXED_RATE internally.
+ * WCID is 2 nibbles, all others are 1 nibble.
+ *
+ * [WCID] Wireless Client ID
+ * [Mode] CCK=0, OFDM=1, HT=2, GF=3, VHT=4, PLR=5, HE_SU=8, HE_ER_SU=9,
+ * HE_TRIG=10, HE_MU=11, EHT_ER=13, EHT_TB=14, EHT_SU and EHT_MU=15
+ * [BW] BW20=0, BW40=1, BW80=2, BW160=3, BW320=4
+ * [MCS] CCK=0~3, OFDM=0~7, HT=0~32, VHT=0~9, HE=0~11, EHT=0~13, EHT_ER=14~15
+ * [Nss] 1~8
+ * [GI] HT/VHT: 0=Long, 1=Short; HE/EHT: 0=0.8us, 1=1.6us, 2=3.2us
+ * [Preamble] Long=0, Short=other
+ * [STBC] Enable=1, Disable=0
+ * [LDPC] BCC=0, LDPC=1 (driver sends the FW's "on" value 7)
+ * [SPE_EN] spatial extension index
+ * [HeLtf] 1X=0, 2X=1, 4X=2 (NOTE: EHT modes require HeLtf=1)
+ */
+static int
+mt7925_fixedrate_set(void *data, u64 val)
+{
+ struct mt792x_dev *dev = data;
+ struct mt7925_ra_fixed_rate_v1 rate = {};
+
+ dev->fixed_rate = val;
+
+ rate.wlan_idx = cpu_to_le16((val >> 40) & 0xff);
+ rate.phy_mode = (val >> 36) & 0xf;
+ rate.bw = (val >> 32) & 0xf;
+ rate.mcs = (val >> 28) & 0xf;
+ rate.nss = (val >> 24) & 0xf;
+ rate.short_gi = cpu_to_le16((val >> 20) & 0xf);
+ rate.short_preamble = (val >> 16) & 0xf;
+ rate.stbc = (val >> 12) & 0xf;
+ rate.ecc = ((val >> 8) & 0xf) ? 7 : 0;
+ rate.spe = (val >> 4) & 0xf;
+ rate.he_ltf = cpu_to_le16((val >> 0) & 0xf);
+
+ mt792x_mutex_acquire(dev);
+ mt7925_mcu_set_fixed_rate(dev, &rate);
+ mt792x_mutex_release(dev);
+
+ return 0;
+}
+
+static int
+mt7925_fixedrate_get(void *data, u64 *val)
+{
+ struct mt792x_dev *dev = data;
+
+ *val = dev->fixed_rate;
+
+ return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(fops_fixedrate, mt7925_fixedrate_get,
+ mt7925_fixedrate_set, "0x%llx\n");
+
+/* autorate input format (6 hex digits):
+ * 0x[Tag(2)][WCID(2)][En][Mode]
+ * The RA tag is fixed to SET_AUTO_RATE internally.
+ * WCID is 2 nibbles, En and Mode are 1 nibble each.
+ *
+ * [WCID] Wireless Client ID
+ * [En] Auto rate: Enable=1, Disable=0
+ * [Mode] don't care (RA picks the rate)
+ */
+static int
+mt7925_autorate_set(void *data, u64 val)
+{
+ struct mt792x_dev *dev = data;
+ u16 wlan_idx = (val >> 8) & 0xff;
+ bool enable = (val >> 4) & 0xf;
+ u8 mode = val & 0xf;
+
+ dev->auto_rate = val;
+
+ mt792x_mutex_acquire(dev);
+ mt7925_mcu_set_auto_rate(dev, wlan_idx, enable, mode);
+ mt792x_mutex_release(dev);
+
+ return 0;
+}
+
+static int
+mt7925_autorate_get(void *data, u64 *val)
+{
+ struct mt792x_dev *dev = data;
+
+ *val = dev->auto_rate;
+
+ return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(fops_autorate, mt7925_autorate_get,
+ mt7925_autorate_set, "0x%llx\n");
+
int mt7925_init_debugfs(struct mt792x_dev *dev)
{
struct dentry *dir;
@@ -461,6 +556,8 @@ int mt7925_init_debugfs(struct mt792x_dev *dev)
debugfs_create_devm_seqfile(dev->mt76.dev, "runtime_pm_stats", dir,
mt792x_pm_stats);
debugfs_create_file("deep-sleep", 0600, dir, dev, &fops_ds);
+ debugfs_create_file("fixedrate", 0600, dir, dev, &fops_fixedrate);
+ debugfs_create_file("autorate", 0600, dir, dev, &fops_autorate);
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 7162eca8e23e..b8062eb91ba5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -4113,3 +4113,43 @@ int mt7925_mcu_set_rssimonitor(struct mt792x_dev *dev, struct ieee80211_vif *vif
return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(RSSI_MONITOR), &req,
sizeof(req), false);
}
+
+int mt7925_mcu_set_fixed_rate(struct mt792x_dev *dev,
+ struct mt7925_ra_fixed_rate_v1 *rate)
+{
+ struct {
+ struct mt7925_ra_hdr hdr;
+ struct mt7925_ra_fixed_rate_tlv tlv;
+ struct mt7925_ra_fixed_rate_v1 v1;
+ } __packed req = {
+ .tlv = {
+ .tag = cpu_to_le16(UNI_CMD_RA_TAG_SET_FIXED_RATE),
+ .len = cpu_to_le16(sizeof(req.tlv) + sizeof(req.v1)),
+ .version = cpu_to_le16(0),
+ },
+ .v1 = *rate,
+ };
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(RA), &req,
+ sizeof(req), true);
+}
+
+int mt7925_mcu_set_auto_rate(struct mt792x_dev *dev, u16 wlan_idx,
+ bool enable, u8 mode)
+{
+ struct {
+ struct mt7925_ra_hdr hdr;
+ struct mt7925_ra_auto_rate_tlv tlv;
+ } __packed req = {
+ .tlv = {
+ .tag = cpu_to_le16(UNI_CMD_RA_TAG_SET_AUTO_RATE),
+ .len = cpu_to_le16(sizeof(req.tlv)),
+ .wlan_idx = cpu_to_le16(wlan_idx),
+ .auto_rate_en = enable,
+ .mode = mode,
+ },
+ };
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(RA), &req,
+ sizeof(req), true);
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h
index 754db84200d8..855613f0b29d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h
@@ -61,6 +61,44 @@ struct mt7925_mcu_ant_id_config {
u8 ant_id[4];
} __packed;
+enum {
+ UNI_CMD_RA_TAG_SET_FIXED_RATE = 0x0F,
+ UNI_CMD_RA_TAG_SET_AUTO_RATE = 0x11,
+};
+
+struct mt7925_ra_hdr {
+ u8 _rsv[4];
+} __packed;
+
+struct mt7925_ra_fixed_rate_tlv {
+ __le16 tag;
+ __le16 len;
+ __le16 version;
+} __packed;
+
+struct mt7925_ra_fixed_rate_v1 {
+ __le16 wlan_idx;
+ u8 phy_mode;
+ u8 stbc;
+ __le16 short_gi;
+ u8 bw;
+ u8 ecc;
+ u8 mcs;
+ u8 nss;
+ __le16 he_ltf;
+ u8 spe;
+ u8 short_preamble;
+ __le16 _rsv;
+} __packed;
+
+struct mt7925_ra_auto_rate_tlv {
+ __le16 tag;
+ __le16 len;
+ __le16 wlan_idx;
+ u8 auto_rate_en;
+ u8 mode;
+} __packed;
+
struct mt7925_txpwr_req {
u8 _rsv[4];
__le16 tag;
@@ -758,4 +796,8 @@ int mt7925_mcu_update_arp_filter(struct mt76_dev *dev,
int
mt7925_mcu_uni_bss_bcnft(struct mt792x_dev *dev,
struct ieee80211_bss_conf *link_conf, bool enable);
+int mt7925_mcu_set_fixed_rate(struct mt792x_dev *dev,
+ struct mt7925_ra_fixed_rate_v1 *rate);
+int mt7925_mcu_set_auto_rate(struct mt792x_dev *dev, u16 wlan_idx,
+ bool enable, u8 mode);
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h
index fbe1793e5598..eecd0b1a5d0e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x.h
+++ b/drivers/net/wireless/mediatek/mt76/mt792x.h
@@ -283,6 +283,9 @@ struct mt792x_dev {
u8 fw_features;
u8 txpwr_tbl;
+ u64 fixed_rate;
+ u64 auto_rate;
+
struct mt76_connac_pm pm;
struct mt76_connac_coredump coredump;
const struct mt792x_hif_ops *hif_ops;
--
2.18.0
reply other threads:[~2026-07-24 8:50 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20260724085045.3155797-1-jb.tsai@mediatek.com \
--to=jb.tsai@mediatek.com \
--cc=Charlie-cy.Wu@mediatek.com \
--cc=Quan.Zhou@mediatek.com \
--cc=Ryder.Lee@mediatek.com \
--cc=Sean.Wang@mediatek.com \
--cc=linux-mediatek@lists.infradead.org \
--cc=linux-wireless@vger.kernel.org \
--cc=litien.chang@mediatek.com \
--cc=lorenzo@kernel.org \
--cc=nbd@nbd.name \
/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