[PATCH] wifi: mt76: add set_chip/get_chip debugfs for chip_config
JB Tsai
jb.tsai at mediatek.com
Mon Oct 26 20:32:37 PDT 2026
From: "allen.chien" <yung-lun.chien at mediatek.com>
Add set_chip/get_chip debugfs for chip_config in mt76 driver
Signed-off-by: allen.chien <yung-lun.chien at mediatek.com>
---
.../wireless/mediatek/mt76/mt7925/debugfs.c | 180 ++++++++++++++++--
1 file changed, 169 insertions(+), 11 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
index 9a5ea12b76c7..060ab59f969d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/* Copyright (C) 2023 MediaTek Inc. */
+#include <linux/seq_buf.h>
+
#include "mt7925.h"
#include "mcu.h"
@@ -286,13 +288,172 @@ static int mt7925_chip_reset(void *data, u64 val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_reset, NULL, mt7925_chip_reset, "%lld\n");
+#define MT7925_CHIP_CONFIG_SIZE sizeof_field(struct mt76_connac_config, data)
+#define MT7925_CHIP_CONFIG_COLS 16
+/* Max reply is MT7925_CHIP_CONFIG_SIZE bytes. A full binary dump is the
+ * worst form: 16 bytes/row as "%04x: %*ph" = 20 * (6 + 47 + 1) = 1080
+ * chars + NUL, well under the 4x budget below. seq_buf bounds writes.
+ */
+#define MT7925_CHIP_CONFIG_DUMP_SIZE (MT7925_CHIP_CONFIG_SIZE * 4)
+
+struct mt7925_chip_config_dbg {
+ struct mt792x_dev *dev;
+ int len;
+ char resp[MT7925_CHIP_CONFIG_DUMP_SIZE];
+};
+
+static char *
+mt7925_chip_config_copy_cmd(const char __user *userbuf, size_t count,
+ char *buf, size_t buf_size)
+{
+ if (!count || count >= buf_size)
+ return ERR_PTR(-EINVAL);
+
+ if (copy_from_user(buf, userbuf, count))
+ return ERR_PTR(-EFAULT);
+
+ buf[count] = '\0';
+ buf = strim(buf);
+
+ return buf[0] ? buf : ERR_PTR(-EINVAL);
+}
+
+/* Format a firmware chip_config reply into buf; returns the number of bytes
+ * written (not counting the NUL seq_buf appends). An empty reply prints
+ * "no reply", an ASCII reply is printed verbatim, and a binary reply is
+ * dumped in MT7925_CHIP_CONFIG_COLS-byte rows. seq_buf tracks the write
+ * offset and stops on overflow, so the caller never has to budget bytes.
+ * Shared by get_chip and coex_info so the formatting logic lives in one
+ * place.
+ */
+static int
+mt7925_chip_config_format(char *buf, size_t size, u8 resp_type,
+ const u8 *resp, int ret)
+{
+ struct seq_buf s;
+ int i;
+
+ seq_buf_init(&s, buf, size);
+
+ if (!ret)
+ seq_buf_puts(&s, "no reply\n");
+ else if (resp_type == CHIP_CONFIG_TYPE_ASCII)
+ seq_buf_printf(&s, "%.*s\n", ret, resp);
+ else
+ for (i = 0; i < ret; i += MT7925_CHIP_CONFIG_COLS)
+ seq_buf_printf(&s, "%04x: %*ph\n", i,
+ min_t(int, MT7925_CHIP_CONFIG_COLS,
+ ret - i), resp + i);
+
+ return seq_buf_used(&s);
+}
+
+static ssize_t
+mt7925_set_chip_write(struct file *file, const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct mt792x_dev *dev = file->private_data;
+ char buf[MT7925_CHIP_CONFIG_SIZE];
+ char *cmd;
+ int ret;
+
+ cmd = mt7925_chip_config_copy_cmd(userbuf, count, buf, sizeof(buf));
+ if (IS_ERR(cmd))
+ return PTR_ERR(cmd);
+
+ mt792x_mutex_acquire(dev);
+ ret = mt7925_mcu_chip_config(dev, cmd);
+ mt792x_mutex_release(dev);
+
+ return ret ? ret : count;
+}
+
+static ssize_t
+mt7925_get_chip_write(struct file *file, const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct mt7925_chip_config_dbg *ctx = file->private_data;
+ u8 resp[MT7925_CHIP_CONFIG_SIZE], resp_type;
+ char buf[MT7925_CHIP_CONFIG_SIZE];
+ int ret;
+ char *cmd;
+
+ cmd = mt7925_chip_config_copy_cmd(userbuf, count, buf, sizeof(buf));
+ if (IS_ERR(cmd))
+ return PTR_ERR(cmd);
+
+ mt792x_mutex_acquire(ctx->dev);
+ ret = mt7925_mcu_chip_config_query(ctx->dev, cmd, &resp_type, resp,
+ sizeof(resp));
+ mt792x_mutex_release(ctx->dev);
+
+ ctx->len = 0;
+ if (ret < 0)
+ return ret;
+
+ ctx->len = mt7925_chip_config_format(ctx->resp, sizeof(ctx->resp),
+ resp_type, resp, ret);
+
+ return count;
+}
+
+static ssize_t
+mt7925_get_chip_read(struct file *file, char __user *userbuf, size_t count,
+ loff_t *ppos)
+{
+ struct mt7925_chip_config_dbg *ctx = file->private_data;
+
+ return simple_read_from_buffer(userbuf, count, ppos, ctx->resp,
+ ctx->len);
+}
+
+static const struct file_operations fops_set_chip = {
+ .write = mt7925_set_chip_write,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static int mt7925_get_chip_open(struct inode *inode, struct file *file)
+{
+ struct mt792x_dev *dev = inode->i_private;
+ struct mt7925_chip_config_dbg *ctx;
+
+ ctx = kzalloc_obj(*ctx, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->dev = dev;
+ file->private_data = ctx;
+
+ return 0;
+}
+
+static int mt7925_get_chip_release(struct inode *inode, struct file *file)
+{
+ struct mt7925_chip_config_dbg *ctx = file->private_data;
+
+ kfree(ctx);
+
+ return 0;
+}
+
+static const struct file_operations fops_get_chip = {
+ .read = mt7925_get_chip_read,
+ .write = mt7925_get_chip_write,
+ .open = mt7925_get_chip_open,
+ .release = mt7925_get_chip_release,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
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;
+ char out[MT7925_CHIP_CONFIG_DUMP_SIZE];
+ u8 resp[MT7925_CHIP_CONFIG_SIZE], resp_type;
+ int ret;
mt792x_mutex_acquire(dev);
ret = mt7925_mcu_chip_config_query(dev, "coexBwcGetModeInfo 0",
@@ -302,14 +463,8 @@ mt7925_coex_info(struct seq_file *s, void *data)
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);
+ ret = mt7925_chip_config_format(out, sizeof(out), resp_type, resp, ret);
+ seq_printf(s, "%.*s", ret, out);
return 0;
}
@@ -339,6 +494,9 @@ int mt7925_init_debugfs(struct mt792x_dev *dev)
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_file("set_chip", 0200, dir, dev, &fops_set_chip);
+ /* pass dev as data: mt7925_get_chip_open() reads it from i_private */
+ debugfs_create_file("get_chip", 0600, dir, dev, &fops_get_chip);
debugfs_create_devm_seqfile(dev->mt76.dev, "runtime_pm_stats", dir,
mt792x_pm_stats);
debugfs_create_file("deep-sleep", 0600, dir, dev, &fops_ds);
--
2.45.2
More information about the Linux-mediatek
mailing list