[PATCH] wifi: mt76: mt7925/mt7928: add get_roc debugfs dumps

JB Tsai jb.tsai at mediatek.com
Thu Oct 8 00:23:40 PDT 2026


From: "Silver.Chen" <silver.chen at mediatek.com>

Add read-only debugfs entries to help debug ROC(CNM) status and OPCH info.
 - get ROC info: print roc info for debug,
   including MBMC enable/OPCH detail/ BSS info.

Usage (DIR=/sys/kernel/debug/ieee80211/phyX/mt76, X = phy index):
 - Print ROC info (MBMC state/OPCH info/BSS info):
     cat $DIR/roc_info

The UNI CMD definitions needed by these dumps are added to mt7925/regs.h.
The required structure are added to mt7925/mcu.h and mt7925/mcu.c.
- mt7925_roc_ch_info_tlv
- mt7925_roc_channel_info
- mt7925_roc_bss_info_tlv
- mt7925_roc_bss_info

Signed-off-by: Silver.Chen <silver.chen at mediatek.com>
---
 .../wireless/mediatek/mt76/mt7925/debugfs.c   | 84 +++++++++++++++++++
 .../net/wireless/mediatek/mt76/mt7925/mcu.c   | 21 +++++
 .../net/wireless/mediatek/mt76/mt7925/mcu.h   | 44 ++++++++++
 .../wireless/mediatek/mt76/mt7925/mt7925.h    |  4 +
 4 files changed, 153 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
index d01ff49de47a..22db9e27fa53 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
@@ -286,6 +286,88 @@ static int mt7925_chip_reset(void *data, u64 val)
 
 DEFINE_DEBUGFS_ATTRIBUTE(fops_reset, NULL, mt7925_chip_reset, "%lld\n");
 
+static int
+mt7925_roc_info(struct seq_file *s, void *data)
+{
+	struct mt792x_dev *dev = dev_get_drvdata(s->private);
+	struct mt7925_roc_ch_info_tlv *ch_tlv;
+	struct mt7925_roc_bss_info_tlv *bss_tlv;
+	struct mt7925_roc_channel_info *ch_info;
+	struct mt7925_roc_bss_info *bss_info;
+	struct sk_buff *skb;
+	bool dbdc_shown = false;
+	u8 *pos, *end;
+	int i, ret;
+
+	mt792x_mutex_acquire(dev);
+	ret = mt7925_mcu_get_roc_info(dev, &skb);
+	mt792x_mutex_release(dev);
+	if (ret)
+		return ret;
+
+	/* skb->data: 4-byte UNI event fixed header + TLVs */
+	pos = skb->data + 4;
+	end = skb->data + skb->len;
+
+	seq_puts(s, "\n[ROC Info]\n");
+
+	while (pos + sizeof(struct tlv) <= end) {
+		struct tlv *tlv = (struct tlv *)pos;
+		u16 tag = le16_to_cpu(tlv->tag);
+		u16 len = le16_to_cpu(tlv->len);
+
+		if (!len || pos + len > end)
+			break;
+
+		switch (tag) {
+		case UNI_EVENT_ROC_GET_CH_INFO:
+			if (len < sizeof(*ch_tlv))
+				break;
+			ch_tlv = (struct mt7925_roc_ch_info_tlv *)pos;
+			if (!dbdc_shown) {
+				seq_printf(s, "MBMC Mode : %s\n\n",
+					   ch_tlv->dbdc_enable ? "Enable" : "Disable");
+				dbdc_shown = true;
+			}
+			ch_info = (struct mt7925_roc_channel_info *)ch_tlv->ch_info;
+			seq_printf(s, "Band %u OPCH %u [", ch_tlv->dbdc_band,
+				   ch_tlv->op_ch_num);
+			for (i = 0; i < ch_tlv->op_ch_num; i++)
+				seq_printf(s, "%u%s", ch_info[i].pri_ch,
+					   i + 1 < ch_tlv->op_ch_num ? ", " : "");
+			seq_puts(s, "]\n");
+			break;
+
+		case UNI_EVENT_ROC_GET_BSS_INFO:
+			if (len < sizeof(*bss_tlv))
+				break;
+			bss_tlv = (struct mt7925_roc_bss_info_tlv *)pos;
+			bss_info = (struct mt7925_roc_bss_info *)bss_tlv->bss_info;
+			seq_puts(s, "\n");
+			for (i = 0; i < bss_tlv->bss_num; i++) {
+				if (!bss_info[i].inuse)
+					continue;
+				seq_printf(s, "BSS%d Inuse%u Act%u ConnStat%u [CH%3u][Band%u][TxNSS%u][RxNSS%u][LinkIdx%u]\n",
+					   i,
+					   bss_info[i].inuse,
+					   bss_info[i].active,
+					   bss_info[i].conn_state,
+					   bss_info[i].pri_ch,
+					   bss_info[i].dbdc_band,
+					   bss_info[i].op_tx_nss,
+					   bss_info[i].op_rx_nss,
+					   bss_info[i].link_idx);
+			}
+			break;
+		}
+
+		pos += len;
+	}
+
+	dev_kfree_skb(skb);
+	return 0;
+}
+
 int mt7925_init_debugfs(struct mt792x_dev *dev)
 {
 	struct dentry *dir;
@@ -309,6 +391,8 @@ int mt7925_init_debugfs(struct mt792x_dev *dev)
 	debugfs_create_file("idle-timeout", 0600, dir, dev,
 			    &fops_pm_idle_timeout);
 	debugfs_create_file("chip_reset", 0600, dir, dev, &fops_reset);
+	debugfs_create_devm_seqfile(dev->mt76.dev, "roc_info", dir,
+				    mt7925_roc_info);
 	debugfs_create_devm_seqfile(dev->mt76.dev, "runtime_pm_stats", dir,
 				    mt792x_pm_stats);
 	debugfs_create_file("deep-sleep", 0600, dir, dev, &fops_ds);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 2afd3f5e3266..37aec6ed84dc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1608,6 +1608,27 @@ int mt7925_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf,
 				 &req, sizeof(req), true);
 }
 
+int mt7925_mcu_get_roc_info(struct mt792x_dev *dev, struct sk_buff **skb)
+{
+	struct {
+		struct {
+			u8 rsv[4];
+		} __packed hdr;
+		struct {
+			__le16 tag;
+			__le16 len;
+		} __packed get_info;
+	} __packed req = {
+		.get_info = {
+			.tag = cpu_to_le16(UNI_ROC_GET_INFO),
+			.len = cpu_to_le16(sizeof(req.get_info)),
+		},
+	};
+
+	return mt76_mcu_send_and_get_msg(&dev->mt76, MCU_UNI_CMD(ROC),
+					 &req, sizeof(req), true, skb);
+}
+
 int mt7925_mcu_set_eeprom(struct mt792x_dev *dev)
 {
 	struct {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h
index 11f9eac13ffc..bc6ecf704564 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h
@@ -72,6 +72,50 @@ struct mt7925_txpwr_req {
 	u8 _rsv1;
 } __packed;
 
+/* ROC GET_INFO event structures (response to UNI_ROC_GET_INFO command) */
+struct mt7925_roc_ch_info_tlv {
+	__le16 tag;
+	__le16 len;
+	u8 dbdc_band;
+	u8 cnm_timeline_en;
+	u8 op_ch_num;
+	u8 dbdc_enable;
+	u8 ch_info[];
+} __packed;
+
+struct mt7925_roc_channel_info {
+	u8 pri_ch;
+	u8 ch_bw;
+	u8 ch_sco;
+	u8 ch_s1;
+	u8 ch_s2;
+	u8 bss_num;
+	__le16 bss_bitmap;
+} __packed;
+
+struct mt7925_roc_bss_info_tlv {
+	__le16 tag;
+	__le16 len;
+	u8 bss_num;
+	u8 rsv[3];
+	u8 bss_info[];
+} __packed;
+
+struct mt7925_roc_bss_info {
+	u8 bss_type;
+	u8 inuse;
+	u8 active;
+	u8 conn_state;
+	u8 pri_ch;
+	u8 dbdc_band;
+	u8 omac_idx;
+	u8 omac_dbdc_band;
+	u8 op_tx_nss;
+	u8 op_rx_nss;
+	u8 link_idx;
+	u8 rsv;
+} __packed;
+
 struct mt7925_txpwr_event {
 	u8 rsv[4];
 	__le16 tag;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
index 33782d9ba9ed..1e0b9001901a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
@@ -51,6 +51,7 @@ struct mt7925_mcu_hif_ctrl_basic_tlv {
 enum {
 	UNI_ROC_ACQUIRE,
 	UNI_ROC_ABORT,
+	UNI_ROC_GET_INFO = 2,
 	UNI_ROC_SUB_LINK = 3,
 	UNI_ROC_NUM
 };
@@ -66,6 +67,8 @@ enum mt7925_roc_req {
 
 enum {
 	UNI_EVENT_ROC_GRANT = 0,
+	UNI_EVENT_ROC_GET_CH_INFO = 1,
+	UNI_EVENT_ROC_GET_BSS_INFO = 2,
 	UNI_EVENT_ROC_GRANT_SUB_LINK = 4,
 	UNI_EVENT_ROC_TAG_NUM
 };
@@ -394,6 +397,7 @@ int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf,
 		       enum mt7925_roc_req type, u8 token_id);
 int mt7925_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf,
 			 u8 token_id);
+int mt7925_mcu_get_roc_info(struct mt792x_dev *dev, struct sk_buff **skb);
 void mt7925_roc_abort_sync(struct mt792x_dev *dev);
 int mt7925_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb,
 			    int cmd, int *wait_seq);
-- 
2.45.2




More information about the Linux-mediatek mailing list