[PATCH] wifi: mt76: connac3: add fixedrate and autorate debugfs for rate control

JB Tsai <[email protected]>
Newsgroups org.infradead.lists.linux-mediatek,org.kernel.vger.linux-wireless
Message-ID <[email protected]>
From: Charlie-cy Wu <[email protected]>

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 <[email protected]>
---
 .../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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.