new file mode 100644
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * This file contains debugfs handlers.
+ *
+ * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <net/cfg80211.h>
+
+#include "core.h"
+#include "cfg80211.h"
+#include "params.h"
+#include "dbg.h"
+#include "dbgfs.h"
+
+static ssize_t ra6w_dbgfs_stats_read(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+ const struct ra6w_cfg80211_priv *priv = file->private_data;
+ const struct ra6w_core_stat *tx = &priv->core->stats.tx;
+ const struct ra6w_core_stat *rx = &priv->core->stats.rx;
+ char *buf;
+ size_t n = 0;
+ size_t len = 256;
+ ssize_t ret = 0;
+
+ buf = kzalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ n += scnprintf(&buf[n], len - n, "tx packets: %u\n", tx->packets);
+ n += scnprintf(&buf[n], len - n, "tx errors : %u\n", tx->err);
+ n += scnprintf(&buf[n], len - n, "rx packets: %u\n", rx->packets);
+ n += scnprintf(&buf[n], len - n, "rx errors : %u\n", rx->err);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, n);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static const struct file_operations ra6w_dbgfs_stats_ops = {
+ .read = ra6w_dbgfs_stats_read,
+ .open = simple_open,
+ .llseek = generic_file_llseek,
+};
+
+static ssize_t ra6w_dbgfs_dev_info_read(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+#define FSCNPRINTF(n, len, buf, NBIT, str) \
+do { \
+ bool set = test_bit(NBIT, &features); \
+ (n) += scnprintf(&(buf)[n], (len) - (n), "%s : %d\n", str, set); \
+} while (0)
+
+ struct ra6w_cfg80211_priv *priv = file->private_data;
+ struct ra6w_core *core = priv->core;
+ const struct ra6w_cmd_fw_ver_rsp *fw_ver = &core->sinfo.fw_ver;
+ unsigned long features;
+ char *buf;
+ size_t n = 0;
+ size_t len = count;
+ ssize_t ret = 0;
+
+ buf = kzalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ n += scnprintf(&buf[n], len - n, "fw_version : %s\n", core->sinfo.fw_version);
+ n += scnprintf(&buf[n], len - n, "machw_features : 0x%X\n",
+ le32_to_cpu(fw_ver->machw_features));
+ n += scnprintf(&buf[n], len - n, "machw_version : 0x%X\n",
+ le32_to_cpu(fw_ver->machw_version));
+ n += scnprintf(&buf[n], len - n, "phy_feature : 0x%X\n",
+ le32_to_cpu(fw_ver->phy_feature));
+ n += scnprintf(&buf[n], len - n, "phy_version : 0x%X\n",
+ le32_to_cpu(fw_ver->phy_version));
+ n += scnprintf(&buf[n], len - n, "dev features : 0x%X:\n", fw_ver->features);
+
+ features = (unsigned long)le32_to_cpu(fw_ver->features);
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_BCN_BIT, " BCN ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_RADAR_BIT, " RADAR ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_PS_BIT, " PS ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_UAPSD_BIT, " UAPSD ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_AMPDU_BIT, " AMPDU ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_AMSDU_BIT, " AMSDU ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_P2P_BIT, " P2P ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_P2P_GO_BIT, " P2P_GO ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_UMAC_BIT, " UMAC ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_VHT_BIT, " VHT ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_BFMEE_BIT, " BFMEE ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_BFMER_BIT, " BFMER ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_WAPI_BIT, " WAPI ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_MFP_BIT, " MFP ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_MU_MIMO_RX_BIT, " MU_MIMO_RX ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_MU_MIMO_TX_BIT, " MU_MIMO_TX ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_MESH_BIT, " MESH ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_TDLS_BIT, " TDLS ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_ANT_DIV_BIT, " ANT_DIV ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_UF_BIT, " UF ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_AMSDU_MAX_SIZE_0_BIT, " AMSDU_MAX_SIZE_0");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_AMSDU_MAX_SIZE_1_BIT, " AMSDU_MAX_SIZE_1");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_HE_BIT, " HE ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_TWT_BIT, " TWT ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_FTM_INIT_BIT, " FTM_INIT ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_FAKE_FTM_RSP_BIT, " FAKE_FTM_RSP ");
+ FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_HW_LLCSNAP_INS_BIT, " HW_LLCSNAP_INS ");
+
+ n += scnprintf(&buf[n], len - n, "max sta : %u\n", le16_to_cpu(fw_ver->max_sta_nb));
+ n += scnprintf(&buf[n], len - n, "max vif : %u\n", fw_ver->max_vif_nb);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, n);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static const struct file_operations ra6w_dbgfs_dev_info_ops = {
+ .read = ra6w_dbgfs_dev_info_read,
+ .open = simple_open,
+ .llseek = generic_file_llseek,
+};
+
+static ssize_t ra6w_dbgfs_mac_info_read(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+#define FSCNPRINTF(n, len, buf, NBIT, str) \
+do { \
+ bool set = test_bit(NBIT, &features); \
+ (n) += scnprintf(&(buf)[n], (len) - (n), "%s : %d\n", str, set); \
+} while (0)
+
+ struct ra6w_cfg80211_priv *priv = file->private_data;
+ struct ra6w_core *core = priv->core;
+ struct ra6w_sys_info *sinfo = &core->sinfo;
+ u32 mac_feat = le32_to_cpu(sinfo->fw_ver.machw_features);
+ unsigned long features = (unsigned long)mac_feat;
+ char *buf;
+ size_t n = 0;
+ size_t len = count;
+ ssize_t ret = 0;
+
+ buf = kzalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ n += scnprintf(&buf[n], len - n, "mac features: 0x%X:\n", mac_feat);
+ FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_QOS_BIT, " QOS ");
+ FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_EDCA_BIT, " EDCA ");
+ FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_SME_BIT, " SME ");
+ FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_SECURITY_BIT, " SECURITY ");
+ FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_TKIP_BIT, " TKIP ");
+ FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_CCMP_BIT, " CCMP ");
+ FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_RCE_BIT, " RCE ");
+ FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_GCMP_BIT, " GCMP ");
+ FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_HT_BIT, " HT ");
+ FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_VHT_BIT, " VHT ");
+ FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_TPC_BIT, " TPC ");
+ FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_WAPI_BIT, " WAPI ");
+ FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_COEX_BIT, " COEX ");
+ FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_HE_BIT, " HE ");
+ FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_BFMEE_BIT, " BFMEE ");
+ FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_BFMER_BIT, " BFMER ");
+ FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_MU_MIMO_TX_BIT, " MU_MIMO_TX");
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, n);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static const struct file_operations ra6w_dbgfs_mac_info_ops = {
+ .read = ra6w_dbgfs_mac_info_read,
+ .open = simple_open,
+ .llseek = generic_file_llseek,
+};
+
+void ra6w_dbgfs_register(struct ra6w_cfg80211_priv *priv)
+{
+ struct dentry *root;
+
+ root = debugfs_create_dir(KBUILD_MODNAME, priv->wiphy->debugfsdir);
+ priv->root = root;
+
+ debugfs_create_file("stats", 0600, root, priv, &ra6w_dbgfs_stats_ops);
+ debugfs_create_file("dev_info", 0600, root, priv, &ra6w_dbgfs_dev_info_ops);
+ debugfs_create_file("mac_info", 0600, root, priv, &ra6w_dbgfs_mac_info_ops);
+ debugfs_create_u32("log_level", 0600, root, &ra6w_params_list.module_params.log_level);
+}
+
+void ra6w_dbgfs_deregister(struct ra6w_cfg80211_priv *priv)
+{
+ debugfs_remove_recursive(priv->root);
+ priv->root = NULL;
+}