[PATCH] wifi: mt76: mt7925: add coex_info debugfs for WiFi/BT coex
JB Tsai
jb.tsai at mediatek.com
Sun Aug 9 19:05:26 PDT 2026
From: Vick Cheng <vick.cheng at mediatek.com>
This is FW MCU CMD API.
Add mt7925_mcu_chip_config_query() which sends the ASCII command as a
UNI query, walks the reply TLVs and copies the payload of the
UNI_CHIP_CONFIG_CHIP_CFG entry back to the caller along with its
response type. Expose it through a read-only 'coex_info' debugfs entry
that queries the firmware on every read, printing the reply as text or
as a hexdump depending on the reported type.
MCU_UNI_QUERY(CHIP_CONFIG) also needs the MCU_CMD_ACK option cleared in
mt7925_mcu_fill_message(), same as the set variant.
This gives a way to read the live WiFi/BT coex state on an upstream
kernel without a vendor tool. The entry is read-only and only issues the
command when read, so it costs nothing when unused, and the
mt7925_mcu_fill_message() change only matches the new query opcode, so
no existing command path changes behaviour.
Signed-off-by: Vick Cheng <vick.cheng at mediatek.com>
---
.../wireless/mediatek/mt76/mt7925/debugfs.c | 30 +++++++
.../net/wireless/mediatek/mt76/mt7925/mcu.c | 78 ++++++++++++++++++-
.../net/wireless/mediatek/mt76/mt7925/mcu.h | 9 +++
.../wireless/mediatek/mt76/mt7925/mt7925.h | 2 +
4 files changed, 118 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
index d01ff49de47a..9a5ea12b76c7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
@@ -286,6 +286,34 @@ static int mt7925_chip_reset(void *data, u64 val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_reset, NULL, mt7925_chip_reset, "%lld\n");
+static int
+mt7925_coex_info(struct seq_file *s, void *data)
+{
+#define MT7925_CHIP_CONFIG_RESP_SIZE 320
+ struct mt792x_dev *dev = dev_get_drvdata(s->private);
+ u8 resp[MT7925_CHIP_CONFIG_RESP_SIZE], resp_type;
+ int i, ret;
+
+ mt792x_mutex_acquire(dev);
+ ret = mt7925_mcu_chip_config_query(dev, "coexBwcGetModeInfo 0",
+ &resp_type, resp, sizeof(resp));
+ mt792x_mutex_release(dev);
+
+ if (ret < 0)
+ return ret;
+
+ if (!ret)
+ seq_puts(s, "no reply\n");
+ else if (resp_type == CHIP_CONFIG_TYPE_ASCII)
+ seq_printf(s, "%.*s\n", ret, resp);
+ else
+ for (i = 0; i < ret; i += 16)
+ seq_printf(s, "%04x: %*ph\n", i,
+ min_t(int, 16, ret - i), resp + i);
+
+ return 0;
+}
+
int mt7925_init_debugfs(struct mt792x_dev *dev)
{
struct dentry *dir;
@@ -309,6 +337,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, "coex_info", dir,
+ mt7925_coex_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 fa29c486a455..e6316cea1865 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1160,6 +1160,81 @@ int mt7925_mcu_chip_config(struct mt792x_dev *dev, const char *cmd)
&req, sizeof(req), false);
}
+int mt7925_mcu_chip_config_query(struct mt792x_dev *dev, const char *cmd,
+ u8 *resp_type, void *resp, u16 resp_size)
+{
+ u16 len = strlen(cmd);
+ struct {
+ u8 _rsv[4];
+ __le16 tag;
+ __le16 len;
+ struct mt76_connac_config config;
+ } __packed req = {
+ .tag = cpu_to_le16(UNI_CHIP_CONFIG_CHIP_CFG),
+ .len = cpu_to_le16(sizeof(req) - 4),
+ .config = {
+ .resp_type = 0,
+ .type = CHIP_CONFIG_TYPE_ASCII,
+ .data_size = cpu_to_le16(len),
+ },
+ };
+ const u16 hdr_len = sizeof(struct tlv) +
+ offsetof(struct mt76_connac_config, data);
+ struct mt76_connac_config *cfg;
+ struct sk_buff *skb;
+ int ret;
+
+ if (!len || len >= sizeof(req.config.data))
+ return -EINVAL;
+
+ memcpy(req.config.data, cmd, len);
+
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_UNI_QUERY(CHIP_CONFIG),
+ &req, sizeof(req), true, &skb);
+ if (ret)
+ return ret;
+
+ /* skip the fixed field of the event, the TLVs follow it */
+ if (skb->len < 4) {
+ ret = -EINVAL;
+ goto out;
+ }
+ skb_pull(skb, 4);
+
+ ret = -ENOENT;
+ while (skb->len >= sizeof(struct tlv)) {
+ struct tlv *tlv = (struct tlv *)skb->data;
+ u16 tlv_len = le16_to_cpu(tlv->len);
+ u16 data_size;
+
+ if (tlv_len < sizeof(*tlv) || tlv_len > skb->len)
+ break;
+
+ if (le16_to_cpu(tlv->tag) != UNI_CHIP_CONFIG_CHIP_CFG) {
+ skb_pull(skb, tlv_len);
+ continue;
+ }
+
+ if (tlv_len < hdr_len)
+ break;
+
+ cfg = (struct mt76_connac_config *)tlv->data;
+ data_size = le16_to_cpu(cfg->data_size);
+ if (data_size > tlv_len - hdr_len)
+ break;
+
+ *resp_type = cfg->resp_type;
+ ret = min_t(u16, data_size, resp_size);
+ memcpy(resp, cfg->data, ret);
+ break;
+ }
+
+out:
+ dev_kfree_skb(skb);
+
+ return ret;
+}
+
int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable)
{
char cmd[16];
@@ -3772,7 +3847,8 @@ int mt7925_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb,
uni_txd->option = MCU_CMD_UNI_EXT_ACK;
if (cmd == MCU_UNI_CMD(HIF_CTRL) ||
- cmd == MCU_UNI_CMD(CHIP_CONFIG))
+ cmd == MCU_UNI_CMD(CHIP_CONFIG) ||
+ cmd == MCU_UNI_QUERY(CHIP_CONFIG))
uni_txd->option &= ~MCU_CMD_ACK;
if (mcu_cmd == MCU_UNI_CMD_TESTMODE_CTRL ||
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h
index 11f9eac13ffc..2cf3971d9853 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h
@@ -119,6 +119,15 @@ enum {
UNI_CHIP_CONFIG_NIC_CAPA = 0x3,
};
+/* type/resp_type of struct mt76_connac_config */
+enum {
+ CHIP_CONFIG_TYPE_WO_RESPONSE,
+ CHIP_CONFIG_TYPE_MEM8,
+ CHIP_CONFIG_TYPE_MEM32,
+ CHIP_CONFIG_TYPE_ASCII,
+ CHIP_CONFIG_TYPE_BINARY,
+};
+
enum {
UNI_BAND_CONFIG_RADIO_ENABLE,
UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
index 321e732347f2..d0db5d8dae48 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
@@ -295,6 +295,8 @@ int mt7925_mcu_get_rx_rate(struct mt792x_phy *phy, struct ieee80211_vif *vif,
int mt7925_mcu_fw_log_2_host(struct mt792x_dev *dev, u8 ctrl);
void mt7925_mcu_rx_event(struct mt792x_dev *dev, struct sk_buff *skb);
int mt7925_mcu_chip_config(struct mt792x_dev *dev, const char *cmd);
+int mt7925_mcu_chip_config_query(struct mt792x_dev *dev, const char *cmd,
+ u8 *resp_type, void *resp, u16 resp_size);
int mt7925_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif,
u8 bit_op, u32 bit_map);
--
2.45.2
More information about the Linux-mediatek
mailing list