Bring in the basic infrastructure necessary for enabling htt_stats via debugfs.
Patch series bring support to request stats type to firmware, dump the stats
and request to reset the stats from firmware.
Schema with one ath12k device:
ath12k
`-- pci-0000:06:00.0
|-- mac0
`-- htt_stats
|-- htt_stats_type
|-- htt_stats_reset
Dinesh Karthikeyan (3):
wifi: ath12k: Add support to enable debugfs_htt_stats
wifi: ath12k: Add htt_stats_dump file ops support
wifi: ath12k: Add support to parse requested stats_type
Lingbo Kong (1):
wifi: ath12k: Fix Pdev id in HTT stats request for WCN7850
Ramya Gnanasekar (1):
wifi: ath12k: Dump additional Tx PDEV HTT stats
drivers/net/wireless/ath/ath12k/Makefile | 2 +-
drivers/net/wireless/ath/ath12k/core.h | 11 +
drivers/net/wireless/ath/ath12k/debugfs.c | 3 +
.../wireless/ath/ath12k/debugfs_htt_stats.c | 714 ++++++++++++++++++
.../wireless/ath/ath12k/debugfs_htt_stats.h | 300 ++++++++
drivers/net/wireless/ath/ath12k/dp_rx.c | 10 +-
drivers/net/wireless/ath/ath12k/dp_rx.h | 4 +
drivers/net/wireless/ath/ath12k/dp_tx.c | 8 +-
drivers/net/wireless/ath/ath12k/mac.c | 61 ++
drivers/net/wireless/ath/ath12k/mac.h | 3 +
10 files changed, 1110 insertions(+), 6 deletions(-)
create mode 100644 drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
create mode 100644 drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
base-commit: 1025c616ee13372f3803b158abb1d87ef368ae3d
--
2.34.1
---
v2:
- Handled pdev id sent in HTT stats request command for WCN7850
Added changes as a separate patch #3
- Tested in WCN7850 and added Tested-on tag
- Rebased on ToT
---
From: Dinesh Karthikeyan <[email protected]>
Create debugfs_htt_stats file when ath12k debugfs support is enabled.
Add basic ath12k_debugfs_htt_stats_init and handle htt_stats_type
file operations.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
Signed-off-by: Dinesh Karthikeyan <[email protected]>
Co-developed-by: Ramya Gnanasekar <[email protected]>
Signed-off-by: Ramya Gnanasekar <[email protected]>
---
drivers/net/wireless/ath/ath12k/Makefile | 2 +-
drivers/net/wireless/ath/ath12k/core.h | 9 +++
drivers/net/wireless/ath/ath12k/debugfs.c | 3 +
.../wireless/ath/ath12k/debugfs_htt_stats.c | 74 +++++++++++++++++++
.../wireless/ath/ath12k/debugfs_htt_stats.h | 20 +++++
5 files changed, 107 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
create mode 100644 drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile
index d42480db7463..3491b8b8a1e2 100644
--- a/drivers/net/wireless/ath/ath12k/Makefile
+++ b/drivers/net/wireless/ath/ath12k/Makefile
@@ -23,7 +23,7 @@ ath12k-y += core.o \
fw.o \
p2p.o
-ath12k-$(CONFIG_ATH12K_DEBUGFS) += debugfs.o
+ath12k-$(CONFIG_ATH12K_DEBUGFS) += debugfs.o debugfs_htt_stats.o
ath12k-$(CONFIG_ACPI) += acpi.o
ath12k-$(CONFIG_ATH12K_TRACING) += trace.o
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index bb6c1b562baf..3919bc828620 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -27,6 +27,7 @@
#include "dbring.h"
#include "fw.h"
#include "acpi.h"
+#include "debugfs_htt_stats.h"
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
@@ -473,8 +474,16 @@ struct ath12k_fw_stats {
struct list_head bcn;
};
+struct ath12k_dbg_htt_stats {
+ enum ath12k_dbg_htt_ext_stats_type type;
+ u32 cfg_param[4];
+ /* protects shared stats req buffer */
+ spinlock_t lock;
+};
+
struct ath12k_debug {
struct dentry *debugfs_pdev;
+ struct ath12k_dbg_htt_stats htt_stats;
};
struct ath12k_per_peer_tx_stats {
diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c
index 8d8ba951093b..30a80f04d824 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs.c
+++ b/drivers/net/wireless/ath/ath12k/debugfs.c
@@ -6,6 +6,7 @@
#include "core.h"
#include "debugfs.h"
+#include "debugfs_htt_stats.h"
static ssize_t ath12k_write_simulate_radar(struct file *file,
const char __user *user_buf,
@@ -87,4 +88,6 @@ void ath12k_debugfs_register(struct ath12k *ar)
ar->debug.debugfs_pdev, ar,
&fops_simulate_radar);
}
+
+ ath12k_debugfs_htt_stats_init(ar);
}
diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
new file mode 100644
index 000000000000..4a58362bdaea
--- /dev/null
+++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/vmalloc.h>
+#include "core.h"
+#include "debug.h"
+#include "debugfs_htt_stats.h"
+
+static ssize_t ath12k_read_htt_stats_type(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath12k *ar = file->private_data;
+ char buf[32];
+ size_t len;
+
+ len = scnprintf(buf, sizeof(buf), "%u\n", ar->debug.htt_stats.type);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath12k_write_htt_stats_type(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath12k *ar = file->private_data;
+ enum ath12k_dbg_htt_ext_stats_type type;
+ unsigned int cfg_param[4] = {0};
+ int num_args;
+
+ char *buf __free(kfree) = kzalloc(count, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, user_buf, count))
+ return -EFAULT;
+
+ num_args = sscanf(buf, "%u %u %u %u %u\n", &type, &cfg_param[0],
+ &cfg_param[1], &cfg_param[2], &cfg_param[3]);
+ if (!num_args || num_args > 5)
+ return -EINVAL;
+
+ if (type >= ATH12K_DBG_HTT_NUM_EXT_STATS)
+ return -E2BIG;
+
+ if (type == ATH12K_DBG_HTT_EXT_STATS_RESET)
+ return -EPERM;
+
+ ar->debug.htt_stats.type = type;
+ ar->debug.htt_stats.cfg_param[0] = cfg_param[0];
+ ar->debug.htt_stats.cfg_param[1] = cfg_param[1];
+ ar->debug.htt_stats.cfg_param[2] = cfg_param[2];
+ ar->debug.htt_stats.cfg_param[3] = cfg_param[3];
+
+ return count;
+}
+
+static const struct file_operations fops_htt_stats_type = {
+ .read = ath12k_read_htt_stats_type,
+ .write = ath12k_write_htt_stats_type,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+void ath12k_debugfs_htt_stats_init(struct ath12k *ar)
+{
+ spin_lock_init(&ar->debug.htt_stats.lock);
+ debugfs_create_file("htt_stats_type", 0600, ar->debug.debugfs_pdev,
+ ar, &fops_htt_stats_type);
+}
diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
new file mode 100644
index 000000000000..6bd34d72b407
--- /dev/null
+++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef DEBUG_HTT_STATS_H
+#define DEBUG_HTT_STATS_H
+
+void ath12k_debugfs_htt_stats_init(struct ath12k *ar);
+
+/* htt_dbg_ext_stats_type */
+enum ath12k_dbg_htt_ext_stats_type {
+ ATH12K_DBG_HTT_EXT_STATS_RESET,
+
+ /* keep this last */
+ ATH12K_DBG_HTT_NUM_EXT_STATS,
+};
+
+#endif
--
2.34.1
From: Dinesh Karthikeyan <[email protected]>
Add dump_htt_stats file operation to dump the stats value requested
for the requested stats_type.
Stats sent from firmware will be cumulative. Hence add debugfs to reset
the requested stats type.
Example with one ath12k device:
ath12k
`-- pci-0000:06:00.0
|-- mac0
`-- htt_stats
|-- htt_stats_type
|-- htt_stats_reset
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
Signed-off-by: Dinesh Karthikeyan <[email protected]>
Co-developed-by: Ramya Gnanasekar <[email protected]>
Signed-off-by: Ramya Gnanasekar <[email protected]>
---
drivers/net/wireless/ath/ath12k/core.h | 2 +
.../wireless/ath/ath12k/debugfs_htt_stats.c | 202 ++++++++++++++++++
.../wireless/ath/ath12k/debugfs_htt_stats.h | 30 +++
3 files changed, 234 insertions(+)
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 3919bc828620..77c0842e5ab0 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -477,6 +477,8 @@ struct ath12k_fw_stats {
struct ath12k_dbg_htt_stats {
enum ath12k_dbg_htt_ext_stats_type type;
u32 cfg_param[4];
+ u8 reset;
+ struct debug_htt_stats_req *stats_req;
/* protects shared stats req buffer */
spinlock_t lock;
};
diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
index 4a58362bdaea..2c64f3b4c239 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
+++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
@@ -8,6 +8,7 @@
#include "core.h"
#include "debug.h"
#include "debugfs_htt_stats.h"
+#include "dp_tx.h"
static ssize_t ath12k_read_htt_stats_type(struct file *file,
char __user *user_buf,
@@ -66,9 +67,210 @@ static const struct file_operations fops_htt_stats_type = {
.llseek = default_llseek,
};
+static int ath12k_debugfs_htt_stats_req(struct ath12k *ar)
+{
+ struct debug_htt_stats_req *stats_req = ar->debug.htt_stats.stats_req;
+ enum ath12k_dbg_htt_ext_stats_type type = stats_req->type;
+ u64 cookie;
+ int ret, pdev_id = ar->pdev->pdev_id;
+ struct htt_ext_stats_cfg_params cfg_params = { 0 };
+
+ init_completion(&stats_req->htt_stats_rcvd);
+
+ stats_req->done = false;
+ stats_req->pdev_id = pdev_id;
+
+ cookie = u64_encode_bits(ATH12K_HTT_STATS_MAGIC_VALUE,
+ ATH12K_HTT_STATS_COOKIE_MSB);
+ cookie |= u64_encode_bits(pdev_id, ATH12K_HTT_STATS_COOKIE_LSB);
+
+ if (stats_req->override_cfg_param) {
+ cfg_params.cfg0 = stats_req->cfg_param[0];
+ cfg_params.cfg1 = stats_req->cfg_param[1];
+ cfg_params.cfg2 = stats_req->cfg_param[2];
+ cfg_params.cfg3 = stats_req->cfg_param[3];
+ }
+
+ ret = ath12k_dp_tx_htt_h2t_ext_stats_req(ar, type, &cfg_params, cookie);
+ if (ret) {
+ ath12k_warn(ar->ab, "failed to send htt stats request: %d\n", ret);
+ return ret;
+ }
+ if (!wait_for_completion_timeout(&stats_req->htt_stats_rcvd, 3 * HZ)) {
+ spin_lock_bh(&ar->debug.htt_stats.lock);
+ if (!stats_req->done) {
+ stats_req->done = true;
+ spin_unlock_bh(&ar->debug.htt_stats.lock);
+ ath12k_warn(ar->ab, "stats request timed out\n");
+ return -ETIMEDOUT;
+ }
+ spin_unlock_bh(&ar->debug.htt_stats.lock);
+ }
+
+ return 0;
+}
+
+static int ath12k_open_htt_stats(struct inode *inode,
+ struct file *file)
+{
+ struct ath12k *ar = inode->i_private;
+ struct debug_htt_stats_req *stats_req;
+ enum ath12k_dbg_htt_ext_stats_type type = ar->debug.htt_stats.type;
+ struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
+ int ret;
+
+ if (type == ATH12K_DBG_HTT_EXT_STATS_RESET)
+ return -EPERM;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (ah->state != ATH12K_HW_STATE_ON) {
+ ret = -ENETDOWN;
+ goto err_unlock;
+ }
+
+ if (ar->debug.htt_stats.stats_req) {
+ ret = -EAGAIN;
+ goto err_unlock;
+ }
+
+ stats_req = kzalloc(sizeof(*stats_req) + ATH12K_HTT_STATS_BUF_SIZE, GFP_KERNEL);
+ if (!stats_req) {
+ ret = -ENOMEM;
+ goto err_unlock;
+ }
+
+ ar->debug.htt_stats.stats_req = stats_req;
+ stats_req->type = type;
+ stats_req->cfg_param[0] = ar->debug.htt_stats.cfg_param[0];
+ stats_req->cfg_param[1] = ar->debug.htt_stats.cfg_param[1];
+ stats_req->cfg_param[2] = ar->debug.htt_stats.cfg_param[2];
+ stats_req->cfg_param[3] = ar->debug.htt_stats.cfg_param[3];
+ stats_req->override_cfg_param = !!stats_req->cfg_param[0] ||
+ !!stats_req->cfg_param[1] ||
+ !!stats_req->cfg_param[2] ||
+ !!stats_req->cfg_param[3];
+
+ ret = ath12k_debugfs_htt_stats_req(ar);
+ if (ret < 0)
+ goto out;
+
+ file->private_data = stats_req;
+
+ mutex_unlock(&ar->conf_mutex);
+
+ return 0;
+out:
+ kfree(stats_req);
+ ar->debug.htt_stats.stats_req = NULL;
+err_unlock:
+ mutex_unlock(&ar->conf_mutex);
+
+ return ret;
+}
+
+static int ath12k_release_htt_stats(struct inode *inode,
+ struct file *file)
+{
+ struct ath12k *ar = inode->i_private;
+
+ mutex_lock(&ar->conf_mutex);
+ kfree(file->private_data);
+ ar->debug.htt_stats.stats_req = NULL;
+ mutex_unlock(&ar->conf_mutex);
+
+ return 0;
+}
+
+static ssize_t ath12k_read_htt_stats(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct debug_htt_stats_req *stats_req = file->private_data;
+ char *buf;
+ u32 length;
+
+ buf = stats_req->buf;
+ length = min_t(u32, stats_req->buf_len, ATH12K_HTT_STATS_BUF_SIZE);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, length);
+}
+
+static const struct file_operations fops_dump_htt_stats = {
+ .open = ath12k_open_htt_stats,
+ .release = ath12k_release_htt_stats,
+ .read = ath12k_read_htt_stats,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t ath12k_write_htt_stats_reset(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath12k *ar = file->private_data;
+ enum ath12k_dbg_htt_ext_stats_type type;
+ struct htt_ext_stats_cfg_params cfg_params = { 0 };
+ u8 param_pos;
+ int ret;
+
+ ret = kstrtou32_from_user(user_buf, count, 0, &type);
+ if (ret)
+ return ret;
+
+ if (type >= ATH12K_DBG_HTT_NUM_EXT_STATS ||
+ type == ATH12K_DBG_HTT_EXT_STATS_RESET)
+ return -E2BIG;
+
+ mutex_lock(&ar->conf_mutex);
+ cfg_params.cfg0 = HTT_STAT_DEFAULT_RESET_START_OFFSET;
+ param_pos = (type >> 5) + 1;
+
+ switch (param_pos) {
+ case ATH12K_HTT_STATS_RESET_PARAM_CFG_32_BYTES:
+ cfg_params.cfg1 = 1 << (cfg_params.cfg0 + type);
+ break;
+ case ATH12K_HTT_STATS_RESET_PARAM_CFG_64_BYTES:
+ cfg_params.cfg2 = ATH12K_HTT_STATS_RESET_BITMAP32_BIT(cfg_params.cfg0 +
+ type);
+ break;
+ case ATH12K_HTT_STATS_RESET_PARAM_CFG_128_BYTES:
+ cfg_params.cfg3 = ATH12K_HTT_STATS_RESET_BITMAP64_BIT(cfg_params.cfg0 +
+ type);
+ break;
+ default:
+ break;
+ }
+
+ ret = ath12k_dp_tx_htt_h2t_ext_stats_req(ar,
+ ATH12K_DBG_HTT_EXT_STATS_RESET,
+ &cfg_params,
+ 0ULL);
+ if (ret) {
+ ath12k_warn(ar->ab, "failed to send htt stats request: %d\n", ret);
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+ }
+
+ ar->debug.htt_stats.reset = type;
+ mutex_unlock(&ar->conf_mutex);
+
+ return count;
+}
+
+static const struct file_operations fops_htt_stats_reset = {
+ .write = ath12k_write_htt_stats_reset,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
void ath12k_debugfs_htt_stats_init(struct ath12k *ar)
{
spin_lock_init(&ar->debug.htt_stats.lock);
debugfs_create_file("htt_stats_type", 0600, ar->debug.debugfs_pdev,
ar, &fops_htt_stats_type);
+ debugfs_create_file("htt_stats", 0400, ar->debug.debugfs_pdev,
+ ar, &fops_dump_htt_stats);
+ debugfs_create_file("htt_stats_reset", 0200, ar->debug.debugfs_pdev,
+ ar, &fops_htt_stats_reset);
}
diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
index 6bd34d72b407..eade49d91720 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
+++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
@@ -7,6 +7,18 @@
#ifndef DEBUG_HTT_STATS_H
#define DEBUG_HTT_STATS_H
+#define ATH12K_HTT_STATS_BUF_SIZE (1024 * 512)
+#define ATH12K_HTT_STATS_COOKIE_LSB GENMASK_ULL(31, 0)
+#define ATH12K_HTT_STATS_COOKIE_MSB GENMASK_ULL(63, 32)
+#define ATH12K_HTT_STATS_MAGIC_VALUE 0xF0F0F0F0
+
+#define ATH12K_HTT_STATS_RESET_BITMAP32_OFFSET(_idx) ((_idx) & 0x1f)
+#define ATH12K_HTT_STATS_RESET_BITMAP64_OFFSET(_idx) ((_idx) & 0x3f)
+#define ATH12K_HTT_STATS_RESET_BITMAP32_BIT(_idx) (1 << \
+ ATH12K_HTT_STATS_RESET_BITMAP32_OFFSET(_idx))
+#define ATH12K_HTT_STATS_RESET_BITMAP64_BIT(_idx) (1 << \
+ ATH12K_HTT_STATS_RESET_BITMAP64_OFFSET(_idx))
+
void ath12k_debugfs_htt_stats_init(struct ath12k *ar);
/* htt_dbg_ext_stats_type */
@@ -17,4 +29,22 @@ enum ath12k_dbg_htt_ext_stats_type {
ATH12K_DBG_HTT_NUM_EXT_STATS,
};
+enum ath12k_htt_stats_reset_cfg_param_alloc_pos {
+ ATH12K_HTT_STATS_RESET_PARAM_CFG_32_BYTES = 1,
+ ATH12K_HTT_STATS_RESET_PARAM_CFG_64_BYTES,
+ ATH12K_HTT_STATS_RESET_PARAM_CFG_128_BYTES,
+};
+
+struct debug_htt_stats_req {
+ bool done;
+ bool override_cfg_param;
+ u8 pdev_id;
+ enum ath12k_dbg_htt_ext_stats_type type;
+ u32 cfg_param[4];
+ u8 peer_addr[ETH_ALEN];
+ struct completion htt_stats_rcvd;
+ u32 buf_len;
+ u8 buf[];
+};
+
#endif
--
2.34.1
Support to dump additional Tx PDEV stats through HTT stats debugfs.
Following stats dump are supported:
1. PDEV control path stat to dump Tx management frame count
2. Tx PDEV SIFS histogram stats
3. Tx MU MIMO PPDU stats for 802.11ac, 802.11ax and 802.11be
Sample Output:
--------------
echo 1 > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats_type
cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats
HTT_TX_PDEV_STATS_CMN_TLV:
mac_id = 0
comp_delivered = 0
self_triggers = 13
......
......
HTT_TX_PDEV_STATS_CTRL_PATH_TX_STATS:
fw_tx_mgmt_subtype = 0:1, 1:0, 2:0, 3:0, 4:38, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:1, 12:0, 13:7, 14:0, 15:0,
HTT_TX_PDEV_STATS_SIFS_HIST_TLV:
sifs_hist_status = 0:237, 1:185, 2:1, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:
ac_mu_mimo_num_seq_posted_nr4 = 0
ac_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
ac_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
ac_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
ac_mu_mimo_num_seq_posted_nr8 = 0
ac_mu_mimo_num_ppdu_posted_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
ac_mu_mimo_num_ppdu_completed_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
ac_mu_mimo_num_seq_term_status_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
ax_mu_mimo_num_seq_posted_nr4 = 0
ax_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
ax_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
ax_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
ax_mu_mimo_num_seq_posted_nr8 = 0
ax_mu_mimo_num_ppdu_posted_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
ax_mu_mimo_num_ppdu_completed_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
ax_mu_mimo_num_seq_term_status_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
be_mu_mimo_num_seq_posted_nr4 = 0
be_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
be_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
be_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
be_mu_mimo_num_seq_posted_nr8 = 0
be_mu_mimo_num_ppdu_posted_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
be_mu_mimo_num_ppdu_completed_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
be_mu_mimo_num_seq_term_status_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
Signed-off-by: Ramya Gnanasekar <[email protected]>
---
.../wireless/ath/ath12k/debugfs_htt_stats.c | 126 ++++++++++++++++++
.../wireless/ath/ath12k/debugfs_htt_stats.h | 39 ++++++
2 files changed, 165 insertions(+)
diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
index 0be20e4f4097..b4b58e49c33b 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
+++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
@@ -242,6 +242,123 @@ htt_print_tx_pdev_stats_sifs_tlv(const void *tag_buf,
stats_req->buf_len = len;
}
+static inline void
+ath12k_htt_print_tx_pdev_mu_ppdu_dist_stats_tlv(const void *tag_buf,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_tx_pdev_mu_ppdu_dist_stats_tlv *htt_stats_buf = tag_buf;
+ char *mode;
+ u8 j, hw_mode, i, str_buf_len;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u32 stats_value;
+ u8 max_ppdu = ATH12K_HTT_STATS_MAX_NUM_MU_PPDU_PER_BURST;
+ u8 max_sched = ATH12K_HTT_STATS_MAX_NUM_SCHED_STATUS;
+ char str_buf[ATH12K_HTT_MAX_STRING_LEN];
+
+ hw_mode = le32_to_cpu(htt_stats_buf->hw_mode);
+
+ switch (hw_mode) {
+ case ATH12K_HTT_STATS_HWMODE_AC:
+ len += scnprintf(buf + len, buf_len - len,
+ "HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n");
+ mode = "ac";
+ break;
+ case ATH12K_HTT_STATS_HWMODE_AX:
+ mode = "ax";
+ break;
+ case ATH12K_HTT_STATS_HWMODE_BE:
+ mode = "be";
+ break;
+ default:
+ return;
+ }
+
+ for (i = 0; i < ATH12K_HTT_STATS_NUM_NR_BINS ; i++) {
+ len += scnprintf(buf + len, buf_len - len,
+ "%s_mu_mimo_num_seq_posted_nr%u = %u\n", mode,
+ ((i + 1) * 4), htt_stats_buf->num_seq_posted[i]);
+ str_buf_len = 0;
+ memset(str_buf, 0x0, sizeof(str_buf));
+ for (j = 0; j < ATH12K_HTT_STATS_MAX_NUM_MU_PPDU_PER_BURST ; j++) {
+ stats_value = le32_to_cpu(htt_stats_buf->num_ppdu_posted_per_burst
+ [i * max_ppdu + j]);
+ str_buf_len += scnprintf(&str_buf[str_buf_len],
+ ATH12K_HTT_MAX_STRING_LEN - str_buf_len,
+ " %u:%u,", j, stats_value);
+ }
+ len += scnprintf(buf + len, buf_len - len,
+ "%s_mu_mimo_num_ppdu_posted_per_burst_nr%u = %s\n",
+ mode, ((i + 1) * 4), str_buf);
+ str_buf_len = 0;
+ memset(str_buf, 0x0, sizeof(str_buf));
+ for (j = 0; j < ATH12K_HTT_STATS_MAX_NUM_MU_PPDU_PER_BURST ; j++) {
+ stats_value = le32_to_cpu(htt_stats_buf->num_ppdu_cmpl_per_burst
+ [i * max_ppdu + j]);
+ str_buf_len += scnprintf(&str_buf[str_buf_len],
+ ATH12K_HTT_MAX_STRING_LEN - str_buf_len,
+ " %u:%u,", j, stats_value);
+ }
+ len += scnprintf(buf + len, buf_len - len,
+ "%s_mu_mimo_num_ppdu_completed_per_burst_nr%u = %s\n",
+ mode, ((i + 1) * 4), str_buf);
+ str_buf_len = 0;
+ memset(str_buf, 0x0, sizeof(str_buf));
+ for (j = 0; j < ATH12K_HTT_STATS_MAX_NUM_SCHED_STATUS ; j++) {
+ stats_value = le32_to_cpu(htt_stats_buf->num_seq_term_status
+ [i * max_sched + j]);
+ str_buf_len += scnprintf(&str_buf[str_buf_len],
+ ATH12K_HTT_MAX_STRING_LEN - str_buf_len,
+ " %u:%u,", j, stats_value);
+ }
+ len += scnprintf(buf + len, buf_len - len,
+ "%s_mu_mimo_num_seq_term_status_nr%u = %s\n\n",
+ mode, ((i + 1) * 4), str_buf);
+ }
+
+ stats_req->buf_len = len;
+}
+
+static inline void
+ath12k_htt_print_tx_pdev_stats_sifs_hist_tlv(const void *tag_buf,
+ u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_tx_pdev_stats_sifs_hist_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u16 num_elems = min_t(u16, (tag_len >> 2),
+ ATH12K_HTT_TX_PDEV_MAX_SIFS_BURST_HIST_STATS);
+
+ len += scnprintf(buf + len, buf_len - len,
+ "HTT_TX_PDEV_STATS_SIFS_HIST_TLV:\n");
+
+ len += print_array_to_buf(buf, len, "sifs_hist_status",
+ htt_stats_buf->sifs_hist_status, num_elems);
+
+ stats_req->buf_len = len;
+}
+
+static inline void
+ath12k_htt_print_pdev_ctrl_path_tx_stats_tlv(const void *tag_buf,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_pdev_ctrl_path_tx_stats_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+
+ len += scnprintf(buf + len, buf_len - len,
+ "HTT_TX_PDEV_STATS_CTRL_PATH_TX_STATS:\n");
+ len += print_array_to_buf(buf, len, "fw_tx_mgmt_subtype",
+ htt_stats_buf->fw_tx_mgmt_subtype,
+ ATH12K_HTT_STATS_SUBTYPE_MAX);
+
+ stats_req->buf_len = len;
+}
+
static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab,
u16 tag, u16 len, const void *tag_buf,
void *user_data)
@@ -261,6 +378,15 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab,
case HTT_STATS_TX_PDEV_FLUSH_TAG:
htt_print_tx_pdev_stats_flush_tlv(tag_buf, len, stats_req);
break;
+ case HTT_STATS_TX_PDEV_SIFS_HIST_TAG:
+ ath12k_htt_print_tx_pdev_stats_sifs_hist_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_PDEV_CTRL_PATH_TX_STATS_TAG:
+ ath12k_htt_print_pdev_ctrl_path_tx_stats_tlv(tag_buf, stats_req);
+ break;
+ case HTT_STATS_MU_PPDU_DIST_TAG:
+ ath12k_htt_print_tx_pdev_mu_ppdu_dist_stats_tlv(tag_buf, stats_req);
+ break;
default:
break;
}
diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
index 477ae75f8175..885630fdcb37 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
+++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
@@ -11,6 +11,8 @@
#define ATH12K_HTT_STATS_COOKIE_LSB GENMASK_ULL(31, 0)
#define ATH12K_HTT_STATS_COOKIE_MSB GENMASK_ULL(63, 32)
#define ATH12K_HTT_STATS_MAGIC_VALUE 0xF0F0F0F0
+#define ATH12K_HTT_STATS_SUBTYPE_MAX 16
+#define ATH12K_HTT_MAX_STRING_LEN 256
#define ATH12K_HTT_STATS_RESET_BITMAP32_OFFSET(_idx) ((_idx) & 0x1f)
#define ATH12K_HTT_STATS_RESET_BITMAP64_OFFSET(_idx) ((_idx) & 0x3f)
@@ -133,6 +135,9 @@ enum ath12k_dbg_htt_tlv_tag {
HTT_STATS_TX_PDEV_UNDERRUN_TAG = 1,
HTT_STATS_TX_PDEV_SIFS_TAG = 2,
HTT_STATS_TX_PDEV_FLUSH_TAG = 3,
+ HTT_STATS_TX_PDEV_SIFS_HIST_TAG = 67,
+ HTT_STATS_PDEV_CTRL_PATH_TX_STATS_TAG = 102,
+ HTT_STATS_MU_PPDU_DIST_TAG = 129,
HTT_STATS_MAX_TAG,
};
@@ -142,6 +147,18 @@ enum ath12k_dbg_htt_tlv_tag {
#define ATH12K_HTT_TX_PDEV_MAX_SIFS_BURST_STATS 9
#define ATH12K_HTT_TX_PDEV_MAX_FLUSH_REASON_STATS 150
+/* MU MIMO distribution stats is a 2-dimensional array
+ * with dimension one denoting stats for nr4[0] or nr8[1]
+ */
+#define ATH12K_HTT_STATS_NUM_NR_BINS 2
+#define ATH12K_HTT_STATS_MAX_NUM_MU_PPDU_PER_BURST 10
+#define ATH12K_HTT_TX_PDEV_MAX_SIFS_BURST_HIST_STATS 10
+#define ATH12K_HTT_STATS_MAX_NUM_SCHED_STATUS 9
+#define ATH12K_HTT_STATS_NUM_SCHED_STATUS_WORDS \
+ (ATH12K_HTT_STATS_NUM_NR_BINS * ATH12K_HTT_STATS_MAX_NUM_SCHED_STATUS)
+#define ATH12K_HTT_STATS_MU_PPDU_PER_BURST_WORDS \
+ (ATH12K_HTT_STATS_NUM_NR_BINS * ATH12K_HTT_STATS_MAX_NUM_MU_PPDU_PER_BURST)
+
enum ath12k_htt_tx_pdev_underrun_enum {
HTT_STATS_TX_PDEV_NO_DATA_UNDERRUN = 0,
HTT_STATS_TX_PDEV_DATA_UNDERRUN_BETWEEN_MPDU = 1,
@@ -258,4 +275,26 @@ struct ath12k_htt_tx_pdev_stats_sifs_tlv {
DECLARE_FLEX_ARRAY(__le32, sifs_status);
} __packed;
+struct ath12k_htt_pdev_ctrl_path_tx_stats_tlv {
+ __le32 fw_tx_mgmt_subtype[ATH12K_HTT_STATS_SUBTYPE_MAX];
+} __packed;
+
+struct ath12k_htt_tx_pdev_stats_sifs_hist_tlv {
+ DECLARE_FLEX_ARRAY(__le32, sifs_hist_status);
+} __packed;
+
+enum ath12k_htt_stats_hw_mode {
+ ATH12K_HTT_STATS_HWMODE_AC = 0,
+ ATH12K_HTT_STATS_HWMODE_AX = 1,
+ ATH12K_HTT_STATS_HWMODE_BE = 2,
+};
+
+struct ath12k_htt_tx_pdev_mu_ppdu_dist_stats_tlv {
+ __le32 hw_mode;
+ __le32 num_seq_term_status[ATH12K_HTT_STATS_NUM_SCHED_STATUS_WORDS];
+ __le32 num_ppdu_cmpl_per_burst[ATH12K_HTT_STATS_MU_PPDU_PER_BURST_WORDS];
+ __le32 num_seq_posted[ATH12K_HTT_STATS_NUM_NR_BINS];
+ __le32 num_ppdu_posted_per_burst[ATH12K_HTT_STATS_MU_PPDU_PER_BURST_WORDS];
+} __packed;
+
#endif
--
2.34.1
From: Dinesh Karthikeyan <[email protected]>
Add extended htt stats parser and print the corresponding TLVs associated
with the requested htt_stats_type.
Add support for TX PDEV related htt stats.
Sample output:
-------------
echo 1 > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats_type
cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats
HTT_TX_PDEV_STATS_CMN_TLV:
mac_id = 0
comp_delivered = 0
self_triggers = 256
hw_queued = 275
hw_reaped = 275
underrun = 241
hw_paused = 0
hw_flush = 0
hw_filt = 1
tx_abort = 0
ppdu_ok = 246
mpdu_requeued = 0
tx_xretry = 0
data_rc = 3
mpdu_dropped_xretry = 0
illegal_rate_phy_err = 0
cont_xretry = 0
tx_timeout = 0
tx_time_dur_data = 0
pdev_resets = 0
phy_underrun = 0
txop_ovf = 0
seq_posted = 247
seq_failed_queueing = 0
seq_completed = 247
seq_restarted = 0
seq_txop_repost_stop = 0
next_seq_cancel = 0
dl_mu_mimo_seq_posted = 0
dl_mu_ofdma_seq_posted = 0
ul_mu_mimo_seq_posted = 0
ul_mu_ofdma_seq_posted = 0
mu_mimo_peer_blacklisted = 0
seq_qdepth_repost_stop = 0
seq_min_msdu_repost_stop = 0
mu_seq_min_msdu_repost_stop = 0
seq_switch_hw_paused = 0
next_seq_posted_dsr = 0
seq_posted_isr = 0
seq_ctrl_cached = 0
mpdu_count_tqm = 0
msdu_count_tqm = 0
mpdu_removed_tqm = 0
msdu_removed_tqm = 0
remove_mpdus_max_retries = 0
mpdus_sw_flush = 0
mpdus_hw_filter = 0
mpdus_truncated = 0
mpdus_ack_failed = 0
mpdus_expired = 0
mpdus_seq_hw_retry = 0
ack_tlv_proc = 0
coex_abort_mpdu_cnt_valid = 0
coex_abort_mpdu_cnt = 5
num_total_ppdus_tried_ota = 5
num_data_ppdus_tried_ota = 0
local_ctrl_mgmt_enqued = 247
local_ctrl_mgmt_freed = 247
local_data_enqued = 0
local_data_freed = 0
mpdu_tried = 0
isr_wait_seq_posted = 0
tx_active_dur_us_low = 0
tx_active_dur_us_high = 0
fes_offsets_err_cnt = 0
HTT_TX_PDEV_STATS_URRN_TLV:
urrn_stats = 0:0, 1:241, 2:0,
HTT_TX_PDEV_STATS_SIFS_TLV:
sifs_status = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
HTT_TX_PDEV_STATS_FLUSH_TLV:
flush_errs = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0,
11:0, 12:0, 13:0, 14:0, 15:0, 16:0, 17:0, 18:0, 19:0, 20:0, 21:0, 22:0,
23:0, 24:0, 25:0, 26:0, 27:0, 28:0, 29:0, 30:0, 31:0, 32:0, 33:0, 34:0,
35:0, 36:0, 37:0, 38:0, 39:0, 40:0, 41:0, 42:0, 43:0, 44:0, 45:0, 46:0,
47:0, 48:0, 49:0, 50:0, 51:0, 52:0, 53:0, 54:0, 55:0, 56:0, 57:0, 58:0,
59:0, 60:0, 61:0, 62:0, 63:0, 64:0, 65:0, 66:0, 67:0, 68:0, 69:0, 70:0,
71:0, 72:0, 73:0, 74:0, 75:0, 76:0, 77:0, 78:0, 79:0, 80:0, 81:0, 82:0,
83:0, 84:0, 85:0, 86:0, 87:0, 88:0, 89:0, 90:0, 91:0, 92:0, 93:0, 94:0,
95:0, 96:0, 97:0, 98:0, 99:0, 100:0, 101:0, 102:0, 103:0, 104:0, 105:0,
106:0, 107:0, 108:0, 109:0, 110:0, 111:0, 112:0, 113:0, 114:0, 115:0,
116:0, 117:0, 118:0, 119:0, 120:0, 121:0, 122:0, 123:0, 124:0, 125:0,
126:0, 127:0,
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
Signed-off-by: Dinesh Karthikeyan <[email protected]>
Co-developed-by: Ramya Gnanasekar <[email protected]>
Signed-off-by: Ramya Gnanasekar <[email protected]>
---
.../wireless/ath/ath12k/debugfs_htt_stats.c | 312 ++++++++++++++++++
.../wireless/ath/ath12k/debugfs_htt_stats.h | 211 ++++++++++++
drivers/net/wireless/ath/ath12k/dp_rx.c | 10 +-
drivers/net/wireless/ath/ath12k/dp_rx.h | 4 +
4 files changed, 533 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
index 2c64f3b4c239..0be20e4f4097 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
+++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
@@ -9,6 +9,318 @@
#include "debug.h"
#include "debugfs_htt_stats.h"
#include "dp_tx.h"
+#include "dp_rx.h"
+
+static u32
+print_array_to_buf(u8 *buf, u32 offset, const char *header,
+ const __le32 *array, u32 array_len)
+{
+ int index = 0;
+ u8 i;
+
+ if (header) {
+ index += scnprintf(buf + offset,
+ ATH12K_HTT_STATS_BUF_SIZE - offset,
+ "%s = ", header);
+ }
+ for (i = 0; i < array_len; i++) {
+ index += scnprintf(buf + offset + index,
+ (ATH12K_HTT_STATS_BUF_SIZE - offset) - index,
+ " %u:%u,", i, le32_to_cpu(array[i]));
+ }
+ index += scnprintf(buf + offset + index,
+ (ATH12K_HTT_STATS_BUF_SIZE - offset) - index,
+ "\n\n");
+ return index;
+}
+
+static void
+htt_print_tx_pdev_stats_cmn_tlv(const void *tag_buf,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_tx_pdev_stats_cmn_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u32 mac_id_word = le32_to_cpu(htt_stats_buf->mac_id__word);
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_CMN_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n",
+ u32_get_bits(mac_id_word, ATH12K_HTT_STATS_MAC_ID));
+ len += scnprintf(buf + len, buf_len - len, "comp_delivered = %u\n",
+ le32_to_cpu(htt_stats_buf->comp_delivered));
+ len += scnprintf(buf + len, buf_len - len, "self_triggers = %u\n",
+ le32_to_cpu(htt_stats_buf->self_triggers));
+ len += scnprintf(buf + len, buf_len - len, "hw_queued = %u\n",
+ le32_to_cpu(htt_stats_buf->hw_queued));
+ len += scnprintf(buf + len, buf_len - len, "hw_reaped = %u\n",
+ le32_to_cpu(htt_stats_buf->hw_reaped));
+ len += scnprintf(buf + len, buf_len - len, "underrun = %u\n",
+ le32_to_cpu(htt_stats_buf->underrun));
+ len += scnprintf(buf + len, buf_len - len, "hw_paused = %u\n",
+ le32_to_cpu(htt_stats_buf->hw_paused));
+ len += scnprintf(buf + len, buf_len - len, "hw_flush = %u\n",
+ le32_to_cpu(htt_stats_buf->hw_flush));
+ len += scnprintf(buf + len, buf_len - len, "hw_filt = %u\n",
+ le32_to_cpu(htt_stats_buf->hw_filt));
+ len += scnprintf(buf + len, buf_len - len, "tx_abort = %u\n",
+ le32_to_cpu(htt_stats_buf->tx_abort));
+ len += scnprintf(buf + len, buf_len - len, "ppdu_ok = %u\n",
+ le32_to_cpu(htt_stats_buf->ppdu_ok));
+ len += scnprintf(buf + len, buf_len - len, "mpdu_requeued = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdu_requed));
+ len += scnprintf(buf + len, buf_len - len, "tx_xretry = %u\n",
+ le32_to_cpu(htt_stats_buf->tx_xretry));
+ len += scnprintf(buf + len, buf_len - len, "data_rc = %u\n",
+ le32_to_cpu(htt_stats_buf->data_rc));
+ len += scnprintf(buf + len, buf_len - len, "mpdu_dropped_xretry = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdu_dropped_xretry));
+ len += scnprintf(buf + len, buf_len - len, "illegal_rate_phy_err = %u\n",
+ le32_to_cpu(htt_stats_buf->illgl_rate_phy_err));
+ len += scnprintf(buf + len, buf_len - len, "cont_xretry = %u\n",
+ le32_to_cpu(htt_stats_buf->cont_xretry));
+ len += scnprintf(buf + len, buf_len - len, "tx_timeout = %u\n",
+ le32_to_cpu(htt_stats_buf->tx_timeout));
+ len += scnprintf(buf + len, buf_len - len, "tx_time_dur_data = %u\n",
+ le32_to_cpu(htt_stats_buf->tx_time_dur_data));
+ len += scnprintf(buf + len, buf_len - len, "pdev_resets = %u\n",
+ le32_to_cpu(htt_stats_buf->pdev_resets));
+ len += scnprintf(buf + len, buf_len - len, "phy_underrun = %u\n",
+ le32_to_cpu(htt_stats_buf->phy_underrun));
+ len += scnprintf(buf + len, buf_len - len, "txop_ovf = %u\n",
+ le32_to_cpu(htt_stats_buf->txop_ovf));
+ len += scnprintf(buf + len, buf_len - len, "seq_posted = %u\n",
+ le32_to_cpu(htt_stats_buf->seq_posted));
+ len += scnprintf(buf + len, buf_len - len, "seq_failed_queueing = %u\n",
+ le32_to_cpu(htt_stats_buf->seq_failed_queueing));
+ len += scnprintf(buf + len, buf_len - len, "seq_completed = %u\n",
+ le32_to_cpu(htt_stats_buf->seq_completed));
+ len += scnprintf(buf + len, buf_len - len, "seq_restarted = %u\n",
+ le32_to_cpu(htt_stats_buf->seq_restarted));
+ len += scnprintf(buf + len, buf_len - len, "seq_txop_repost_stop = %u\n",
+ le32_to_cpu(htt_stats_buf->seq_txop_repost_stop));
+ len += scnprintf(buf + len, buf_len - len, "next_seq_cancel = %u\n",
+ le32_to_cpu(htt_stats_buf->next_seq_cancel));
+ len += scnprintf(buf + len, buf_len - len, "dl_mu_mimo_seq_posted = %u\n",
+ le32_to_cpu(htt_stats_buf->mu_seq_posted));
+ len += scnprintf(buf + len, buf_len - len, "dl_mu_ofdma_seq_posted = %u\n",
+ le32_to_cpu(htt_stats_buf->mu_ofdma_seq_posted));
+ len += scnprintf(buf + len, buf_len - len, "ul_mu_mimo_seq_posted = %u\n",
+ le32_to_cpu(htt_stats_buf->ul_mumimo_seq_posted));
+ len += scnprintf(buf + len, buf_len - len, "ul_mu_ofdma_seq_posted = %u\n",
+ le32_to_cpu(htt_stats_buf->ul_ofdma_seq_posted));
+ len += scnprintf(buf + len, buf_len - len, "mu_mimo_peer_blacklisted = %u\n",
+ le32_to_cpu(htt_stats_buf->num_mu_peer_blacklisted));
+ len += scnprintf(buf + len, buf_len - len, "seq_qdepth_repost_stop = %u\n",
+ le32_to_cpu(htt_stats_buf->seq_qdepth_repost_stop));
+ len += scnprintf(buf + len, buf_len - len, "seq_min_msdu_repost_stop = %u\n",
+ le32_to_cpu(htt_stats_buf->seq_min_msdu_repost_stop));
+ len += scnprintf(buf + len, buf_len - len, "mu_seq_min_msdu_repost_stop = %u\n",
+ le32_to_cpu(htt_stats_buf->mu_seq_min_msdu_repost_stop));
+ len += scnprintf(buf + len, buf_len - len, "seq_switch_hw_paused = %u\n",
+ le32_to_cpu(htt_stats_buf->seq_switch_hw_paused));
+ len += scnprintf(buf + len, buf_len - len, "next_seq_posted_dsr = %u\n",
+ le32_to_cpu(htt_stats_buf->next_seq_posted_dsr));
+ len += scnprintf(buf + len, buf_len - len, "seq_posted_isr = %u\n",
+ le32_to_cpu(htt_stats_buf->seq_posted_isr));
+ len += scnprintf(buf + len, buf_len - len, "seq_ctrl_cached = %u\n",
+ le32_to_cpu(htt_stats_buf->seq_ctrl_cached));
+ len += scnprintf(buf + len, buf_len - len, "mpdu_count_tqm = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdu_count_tqm));
+ len += scnprintf(buf + len, buf_len - len, "msdu_count_tqm = %u\n",
+ le32_to_cpu(htt_stats_buf->msdu_count_tqm));
+ len += scnprintf(buf + len, buf_len - len, "mpdu_removed_tqm = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdu_removed_tqm));
+ len += scnprintf(buf + len, buf_len - len, "msdu_removed_tqm = %u\n",
+ le32_to_cpu(htt_stats_buf->msdu_removed_tqm));
+ len += scnprintf(buf + len, buf_len - len, "remove_mpdus_max_retries = %u\n",
+ le32_to_cpu(htt_stats_buf->remove_mpdus_max_retries));
+ len += scnprintf(buf + len, buf_len - len, "mpdus_sw_flush = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdus_sw_flush));
+ len += scnprintf(buf + len, buf_len - len, "mpdus_hw_filter = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdus_hw_filter));
+ len += scnprintf(buf + len, buf_len - len, "mpdus_truncated = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdus_truncated));
+ len += scnprintf(buf + len, buf_len - len, "mpdus_ack_failed = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdus_ack_failed));
+ len += scnprintf(buf + len, buf_len - len, "mpdus_expired = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdus_expired));
+ len += scnprintf(buf + len, buf_len - len, "mpdus_seq_hw_retry = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdus_seq_hw_retry));
+ len += scnprintf(buf + len, buf_len - len, "ack_tlv_proc = %u\n",
+ le32_to_cpu(htt_stats_buf->ack_tlv_proc));
+ len += scnprintf(buf + len, buf_len - len, "coex_abort_mpdu_cnt_valid = %u\n",
+ le32_to_cpu(htt_stats_buf->coex_abort_mpdu_cnt_valid));
+ len += scnprintf(buf + len, buf_len - len, "coex_abort_mpdu_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->coex_abort_mpdu_cnt));
+ len += scnprintf(buf + len, buf_len - len, "num_total_ppdus_tried_ota = %u\n",
+ le32_to_cpu(htt_stats_buf->num_total_ppdus_tried_ota));
+ len += scnprintf(buf + len, buf_len - len, "num_data_ppdus_tried_ota = %u\n",
+ le32_to_cpu(htt_stats_buf->num_data_ppdus_tried_ota));
+ len += scnprintf(buf + len, buf_len - len, "local_ctrl_mgmt_enqued = %u\n",
+ le32_to_cpu(htt_stats_buf->local_ctrl_mgmt_enqued));
+ len += scnprintf(buf + len, buf_len - len, "local_ctrl_mgmt_freed = %u\n",
+ le32_to_cpu(htt_stats_buf->local_ctrl_mgmt_freed));
+ len += scnprintf(buf + len, buf_len - len, "local_data_enqued = %u\n",
+ le32_to_cpu(htt_stats_buf->local_data_enqued));
+ len += scnprintf(buf + len, buf_len - len, "local_data_freed = %u\n",
+ le32_to_cpu(htt_stats_buf->local_data_freed));
+ len += scnprintf(buf + len, buf_len - len, "mpdu_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdu_tried));
+ len += scnprintf(buf + len, buf_len - len, "isr_wait_seq_posted = %u\n",
+ le32_to_cpu(htt_stats_buf->isr_wait_seq_posted));
+ len += scnprintf(buf + len, buf_len - len, "tx_active_dur_us_low = %u\n",
+ le32_to_cpu(htt_stats_buf->tx_active_dur_us_low));
+ len += scnprintf(buf + len, buf_len - len, "tx_active_dur_us_high = %u\n",
+ le32_to_cpu(htt_stats_buf->tx_active_dur_us_high));
+ len += scnprintf(buf + len, buf_len - len, "fes_offsets_err_cnt = %u\n\n",
+ le32_to_cpu(htt_stats_buf->fes_offsets_err_cnt));
+
+ stats_req->buf_len = len;
+}
+
+static void
+htt_print_tx_pdev_stats_urrn_tlv(const void *tag_buf,
+ u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_tx_pdev_stats_urrn_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u16 num_elems = min_t(u16, (tag_len >> 2),
+ HTT_TX_PDEV_MAX_URRN_STATS);
+
+ len += scnprintf(buf + len, buf_len - len,
+ "HTT_TX_PDEV_STATS_URRN_TLV:\n");
+
+ len += print_array_to_buf(buf, len, "urrn_stats", htt_stats_buf->urrn_stats,
+ num_elems);
+
+ stats_req->buf_len = len;
+}
+
+static void
+htt_print_tx_pdev_stats_flush_tlv(const void *tag_buf,
+ u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_tx_pdev_stats_flush_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u16 num_elems = min_t(u16, (tag_len >> 2),
+ ATH12K_HTT_TX_PDEV_MAX_FLUSH_REASON_STATS);
+
+ len += scnprintf(buf + len, buf_len - len,
+ "HTT_TX_PDEV_STATS_FLUSH_TLV:\n");
+
+ len += print_array_to_buf(buf, len, "flush_errs", htt_stats_buf->flush_errs,
+ num_elems);
+
+ stats_req->buf_len = len;
+}
+
+static void
+htt_print_tx_pdev_stats_sifs_tlv(const void *tag_buf,
+ u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_tx_pdev_stats_sifs_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u16 num_elems = min_t(u16, (tag_len >> 2),
+ ATH12K_HTT_TX_PDEV_MAX_SIFS_BURST_STATS);
+
+ len += scnprintf(buf + len, buf_len - len,
+ "HTT_TX_PDEV_STATS_SIFS_TLV:\n");
+
+ len += print_array_to_buf(buf, len, "sifs_status", htt_stats_buf->sifs_status,
+ num_elems);
+
+ stats_req->buf_len = len;
+}
+
+static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab,
+ u16 tag, u16 len, const void *tag_buf,
+ void *user_data)
+{
+ struct debug_htt_stats_req *stats_req = user_data;
+
+ switch (tag) {
+ case HTT_STATS_TX_PDEV_CMN_TAG:
+ htt_print_tx_pdev_stats_cmn_tlv(tag_buf, stats_req);
+ break;
+ case HTT_STATS_TX_PDEV_UNDERRUN_TAG:
+ htt_print_tx_pdev_stats_urrn_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_TX_PDEV_SIFS_TAG:
+ htt_print_tx_pdev_stats_sifs_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_TX_PDEV_FLUSH_TAG:
+ htt_print_tx_pdev_stats_flush_tlv(tag_buf, len, stats_req);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+void ath12k_debugfs_htt_ext_stats_handler(struct ath12k_base *ab,
+ struct sk_buff *skb)
+{
+ struct ath12k_htt_extd_stats_msg *msg;
+ struct debug_htt_stats_req *stats_req;
+ struct ath12k *ar;
+ u32 len, pdev_id, stats_info;
+ u64 cookie;
+ int ret;
+ bool send_completion = false;
+
+ msg = (struct ath12k_htt_extd_stats_msg *)skb->data;
+ cookie = le64_to_cpu(msg->cookie);
+
+ if (u64_get_bits(cookie, ATH12K_HTT_STATS_COOKIE_MSB) !=
+ ATH12K_HTT_STATS_MAGIC_VALUE) {
+ ath12k_warn(ab, "received invalid htt ext stats event\n");
+ return;
+ }
+
+ pdev_id = u64_get_bits(cookie, ATH12K_HTT_STATS_COOKIE_LSB);
+ rcu_read_lock();
+ ar = ath12k_mac_get_ar_by_pdev_id(ab, pdev_id);
+ if (!ar) {
+ ath12k_warn(ab, "failed to get ar for pdev_id %d\n", pdev_id);
+ goto exit;
+ }
+
+ stats_req = ar->debug.htt_stats.stats_req;
+ if (!stats_req)
+ goto exit;
+
+ spin_lock_bh(&ar->debug.htt_stats.lock);
+
+ stats_info = le32_to_cpu(msg->info1);
+ stats_req->done = u32_get_bits(stats_info, ATH12K_HTT_T2H_EXT_STATS_INFO1_DONE);
+ if (stats_req->done)
+ send_completion = true;
+
+ spin_unlock_bh(&ar->debug.htt_stats.lock);
+
+ len = u32_get_bits(stats_info, ATH12K_HTT_T2H_EXT_STATS_INFO1_LENGTH);
+ ret = ath12k_dp_htt_tlv_iter(ab, msg->data, len,
+ ath12k_dbg_htt_ext_stats_parse,
+ stats_req);
+ if (ret)
+ ath12k_warn(ab, "Failed to parse tlv %d\n", ret);
+
+ if (send_completion)
+ complete(&stats_req->htt_stats_rcvd);
+exit:
+ rcu_read_unlock();
+}
static ssize_t ath12k_read_htt_stats_type(struct file *file,
char __user *user_buf,
diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
index eade49d91720..477ae75f8175 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
+++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
@@ -21,14 +21,134 @@
void ath12k_debugfs_htt_stats_init(struct ath12k *ar);
+#ifdef CONFIG_ATH12K_DEBUGFS
+void ath12k_debugfs_htt_ext_stats_handler(struct ath12k_base *ab,
+ struct sk_buff *skb);
+#else /* CONFIG_ATH12K_DEBUGFS */
+static inline void ath12k_debugfs_htt_ext_stats_handler(struct ath12k_base *ab,
+ struct sk_buff *skb)
+{
+}
+#endif
+
+/**
+ * DOC: target -> host extended statistics upload
+ *
+ * The following field definitions describe the format of the HTT
+ * target to host stats upload confirmation message.
+ * The message contains a cookie echoed from the HTT host->target stats
+ * upload request, which identifies which request the confirmation is
+ * for, and a single stats can span over multiple HTT stats indication
+ * due to the HTT message size limitation so every HTT ext stats
+ * indication will have tag-length-value stats information elements.
+ * The tag-length header for each HTT stats IND message also includes a
+ * status field, to indicate whether the request for the stat type in
+ * question was fully met, partially met, unable to be met, or invalid
+ * (if the stat type in question is disabled in the target).
+ * A Done bit 1's indicate the end of the of stats info elements.
+ *
+ *
+ * |31 16|15 12|11|10 8|7 5|4 0|
+ * |--------------------------------------------------------------|
+ * | reserved | msg type |
+ * |--------------------------------------------------------------|
+ * | cookie LSBs |
+ * |--------------------------------------------------------------|
+ * | cookie MSBs |
+ * |--------------------------------------------------------------|
+ * | stats entry length | rsvd | D| S | stat type |
+ * |--------------------------------------------------------------|
+ * | type-specific stats info |
+ * | (see debugfs_htt_stats.h) |
+ * |--------------------------------------------------------------|
+ * Header fields:
+ * - MSG_TYPE
+ * Bits 7:0
+ * Purpose: Identifies this is a extended statistics upload confirmation
+ * message.
+ * Value: 0x1c
+ * - COOKIE_LSBS
+ * Bits 31:0
+ * Purpose: Provide a mechanism to match a target->host stats confirmation
+ * message with its preceding host->target stats request message.
+ * Value: MSBs of the opaque cookie specified by the host-side requestor
+ * - COOKIE_MSBS
+ * Bits 31:0
+ * Purpose: Provide a mechanism to match a target->host stats confirmation
+ * message with its preceding host->target stats request message.
+ * Value: MSBs of the opaque cookie specified by the host-side requestor
+ *
+ * Stats Information Element tag-length header fields:
+ * - STAT_TYPE
+ * Bits 7:0
+ * Purpose: identifies the type of statistics info held in the
+ * following information element
+ * Value: ath12k_dbg_htt_ext_stats_type
+ * - STATUS
+ * Bits 10:8
+ * Purpose: indicate whether the requested stats are present
+ * Value:
+ * 0 -> The requested stats have been delivered in full
+ * 1 -> The requested stats have been delivered in part
+ * 2 -> The requested stats could not be delivered (error case)
+ * 3 -> The requested stat type is either not recognized (invalid)
+ * - DONE
+ * Bits 11
+ * Purpose:
+ * Indicates the completion of the stats entry, this will be the last
+ * stats conf HTT segment for the requested stats type.
+ * Value:
+ * 0 -> the stats retrieval is ongoing
+ * 1 -> the stats retrieval is complete
+ * - LENGTH
+ * Bits 31:16
+ * Purpose: indicate the stats information size
+ * Value: This field specifies the number of bytes of stats information
+ * that follows the element tag-length header.
+ * It is expected but not required that this length is a multiple of
+ * 4 bytes.
+ */
+
+#define ATH12K_HTT_T2H_EXT_STATS_INFO1_DONE BIT(11)
+#define ATH12K_HTT_T2H_EXT_STATS_INFO1_LENGTH GENMASK(31, 16)
+
+struct ath12k_htt_extd_stats_msg {
+ __le32 info0;
+ __le64 cookie;
+ __le32 info1;
+ u8 data[];
+} __packed;
+
/* htt_dbg_ext_stats_type */
enum ath12k_dbg_htt_ext_stats_type {
ATH12K_DBG_HTT_EXT_STATS_RESET,
+ ATH12K_DBG_HTT_EXT_STATS_PDEV_TX,
/* keep this last */
ATH12K_DBG_HTT_NUM_EXT_STATS,
};
+enum ath12k_dbg_htt_tlv_tag {
+ HTT_STATS_TX_PDEV_CMN_TAG = 0,
+ HTT_STATS_TX_PDEV_UNDERRUN_TAG = 1,
+ HTT_STATS_TX_PDEV_SIFS_TAG = 2,
+ HTT_STATS_TX_PDEV_FLUSH_TAG = 3,
+
+ HTT_STATS_MAX_TAG,
+};
+
+#define ATH12K_HTT_STATS_MAC_ID GENMASK(7, 0)
+
+#define ATH12K_HTT_TX_PDEV_MAX_SIFS_BURST_STATS 9
+#define ATH12K_HTT_TX_PDEV_MAX_FLUSH_REASON_STATS 150
+
+enum ath12k_htt_tx_pdev_underrun_enum {
+ HTT_STATS_TX_PDEV_NO_DATA_UNDERRUN = 0,
+ HTT_STATS_TX_PDEV_DATA_UNDERRUN_BETWEEN_MPDU = 1,
+ HTT_STATS_TX_PDEV_DATA_UNDERRUN_WITHIN_MPDU = 2,
+ HTT_TX_PDEV_MAX_URRN_STATS = 3,
+};
+
enum ath12k_htt_stats_reset_cfg_param_alloc_pos {
ATH12K_HTT_STATS_RESET_PARAM_CFG_32_BYTES = 1,
ATH12K_HTT_STATS_RESET_PARAM_CFG_64_BYTES,
@@ -47,4 +167,95 @@ struct debug_htt_stats_req {
u8 buf[];
};
+struct ath12k_htt_tx_pdev_stats_cmn_tlv {
+ __le32 mac_id__word;
+ __le32 hw_queued;
+ __le32 hw_reaped;
+ __le32 underrun;
+ __le32 hw_paused;
+ __le32 hw_flush;
+ __le32 hw_filt;
+ __le32 tx_abort;
+ __le32 mpdu_requed;
+ __le32 tx_xretry;
+ __le32 data_rc;
+ __le32 mpdu_dropped_xretry;
+ __le32 illgl_rate_phy_err;
+ __le32 cont_xretry;
+ __le32 tx_timeout;
+ __le32 pdev_resets;
+ __le32 phy_underrun;
+ __le32 txop_ovf;
+ __le32 seq_posted;
+ __le32 seq_failed_queueing;
+ __le32 seq_completed;
+ __le32 seq_restarted;
+ __le32 mu_seq_posted;
+ __le32 seq_switch_hw_paused;
+ __le32 next_seq_posted_dsr;
+ __le32 seq_posted_isr;
+ __le32 seq_ctrl_cached;
+ __le32 mpdu_count_tqm;
+ __le32 msdu_count_tqm;
+ __le32 mpdu_removed_tqm;
+ __le32 msdu_removed_tqm;
+ __le32 mpdus_sw_flush;
+ __le32 mpdus_hw_filter;
+ __le32 mpdus_truncated;
+ __le32 mpdus_ack_failed;
+ __le32 mpdus_expired;
+ __le32 mpdus_seq_hw_retry;
+ __le32 ack_tlv_proc;
+ __le32 coex_abort_mpdu_cnt_valid;
+ __le32 coex_abort_mpdu_cnt;
+ __le32 num_total_ppdus_tried_ota;
+ __le32 num_data_ppdus_tried_ota;
+ __le32 local_ctrl_mgmt_enqued;
+ __le32 local_ctrl_mgmt_freed;
+ __le32 local_data_enqued;
+ __le32 local_data_freed;
+ __le32 mpdu_tried;
+ __le32 isr_wait_seq_posted;
+
+ __le32 tx_active_dur_us_low;
+ __le32 tx_active_dur_us_high;
+ __le32 remove_mpdus_max_retries;
+ __le32 comp_delivered;
+ __le32 ppdu_ok;
+ __le32 self_triggers;
+ __le32 tx_time_dur_data;
+ __le32 seq_qdepth_repost_stop;
+ __le32 mu_seq_min_msdu_repost_stop;
+ __le32 seq_min_msdu_repost_stop;
+ __le32 seq_txop_repost_stop;
+ __le32 next_seq_cancel;
+ __le32 fes_offsets_err_cnt;
+ __le32 num_mu_peer_blacklisted;
+ __le32 mu_ofdma_seq_posted;
+ __le32 ul_mumimo_seq_posted;
+ __le32 ul_ofdma_seq_posted;
+
+ __le32 thermal_suspend_cnt;
+ __le32 dfs_suspend_cnt;
+ __le32 tx_abort_suspend_cnt;
+ __le32 tgt_specific_opaque_txq_suspend_info;
+ __le32 last_suspend_reason;
+} __packed;
+
+struct ath12k_htt_tx_pdev_stats_urrn_tlv {
+ DECLARE_FLEX_ARRAY(__le32, urrn_stats);
+} __packed;
+
+struct ath12k_htt_tx_pdev_stats_flush_tlv {
+ DECLARE_FLEX_ARRAY(__le32, flush_errs);
+} __packed;
+
+struct ath12k_htt_tx_pdev_stats_phy_err_tlv {
+ DECLARE_FLEX_ARRAY(__le32, phy_errs);
+} __packed;
+
+struct ath12k_htt_tx_pdev_stats_sifs_tlv {
+ DECLARE_FLEX_ARRAY(__le32, sifs_status);
+} __packed;
+
#endif
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
index 952a377b5491..b19d4836fbf4 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -17,6 +17,7 @@
#include "dp_tx.h"
#include "peer.h"
#include "dp_mon.h"
+#include "debugfs_htt_stats.h"
#define ATH12K_DP_RX_FRAGMENT_TIMEOUT_MS (2 * HZ)
@@ -1268,10 +1269,10 @@ static int ath12k_htt_tlv_ppdu_stats_parse(struct ath12k_base *ab,
return 0;
}
-static int ath12k_dp_htt_tlv_iter(struct ath12k_base *ab, const void *ptr, size_t len,
- int (*iter)(struct ath12k_base *ar, u16 tag, u16 len,
- const void *ptr, void *data),
- void *data)
+int ath12k_dp_htt_tlv_iter(struct ath12k_base *ab, const void *ptr, size_t len,
+ int (*iter)(struct ath12k_base *ar, u16 tag, u16 len,
+ const void *ptr, void *data),
+ void *data)
{
const struct htt_tlv *tlv;
const void *begin = ptr;
@@ -1741,6 +1742,7 @@ void ath12k_dp_htt_htc_t2h_msg_handler(struct ath12k_base *ab,
ath12k_htt_pull_ppdu_stats(ab, skb);
break;
case HTT_T2H_MSG_TYPE_EXT_STATS_CONF:
+ ath12k_debugfs_htt_ext_stats_handler(ab, skb);
break;
case HTT_T2H_MSG_TYPE_MLO_TIMESTAMP_OFFSET_IND:
ath12k_htt_mlo_offset_event_handler(ab, skb);
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h
index 2ff421160181..eb1f92559179 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.h
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.h
@@ -139,4 +139,8 @@ ath12k_dp_rx_h_find_peer(struct ath12k_base *ab, struct sk_buff *msdu);
int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab);
int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab);
+int ath12k_dp_htt_tlv_iter(struct ath12k_base *ab, const void *ptr, size_t len,
+ int (*iter)(struct ath12k_base *ar, u16 tag, u16 len,
+ const void *ptr, void *data),
+ void *data);
#endif /* ATH12K_DP_RX_H */
--
2.34.1
On 5/9/2024 10:08 PM, Ramya Gnanasekar wrote:
> From: Dinesh Karthikeyan <[email protected]>
>
> Create debugfs_htt_stats file when ath12k debugfs support is enabled.
> Add basic ath12k_debugfs_htt_stats_init and handle htt_stats_type
> file operations.
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
>
> Signed-off-by: Dinesh Karthikeyan <[email protected]>
> Co-developed-by: Ramya Gnanasekar <[email protected]>
> Signed-off-by: Ramya Gnanasekar <[email protected]>
Acked-by: Jeff Johnson <[email protected]>
On 5/9/2024 10:08 PM, Ramya Gnanasekar wrote:
> From: Dinesh Karthikeyan <[email protected]>
>
> Add dump_htt_stats file operation to dump the stats value requested
> for the requested stats_type.
> Stats sent from firmware will be cumulative. Hence add debugfs to reset
> the requested stats type.
>
> Example with one ath12k device:
>
> ath12k
> `-- pci-0000:06:00.0
> |-- mac0
> `-- htt_stats
> |-- htt_stats_type
> |-- htt_stats_reset
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
>
> Signed-off-by: Dinesh Karthikeyan <[email protected]>
> Co-developed-by: Ramya Gnanasekar <[email protected]>
> Signed-off-by: Ramya Gnanasekar <[email protected]>
Acked-by: Jeff Johnson <[email protected]>
On 5/9/2024 10:08 PM, Ramya Gnanasekar wrote:
> From: Dinesh Karthikeyan <[email protected]>
>
> Add extended htt stats parser and print the corresponding TLVs associated
> with the requested htt_stats_type.
> Add support for TX PDEV related htt stats.
>
> Sample output:
> -------------
> echo 1 > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats_type
> cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats
> HTT_TX_PDEV_STATS_CMN_TLV:
> mac_id = 0
> comp_delivered = 0
> self_triggers = 256
> hw_queued = 275
> hw_reaped = 275
> underrun = 241
> hw_paused = 0
> hw_flush = 0
> hw_filt = 1
> tx_abort = 0
> ppdu_ok = 246
> mpdu_requeued = 0
> tx_xretry = 0
> data_rc = 3
> mpdu_dropped_xretry = 0
> illegal_rate_phy_err = 0
> cont_xretry = 0
> tx_timeout = 0
> tx_time_dur_data = 0
> pdev_resets = 0
> phy_underrun = 0
> txop_ovf = 0
> seq_posted = 247
> seq_failed_queueing = 0
> seq_completed = 247
> seq_restarted = 0
> seq_txop_repost_stop = 0
> next_seq_cancel = 0
> dl_mu_mimo_seq_posted = 0
> dl_mu_ofdma_seq_posted = 0
> ul_mu_mimo_seq_posted = 0
> ul_mu_ofdma_seq_posted = 0
> mu_mimo_peer_blacklisted = 0
> seq_qdepth_repost_stop = 0
> seq_min_msdu_repost_stop = 0
> mu_seq_min_msdu_repost_stop = 0
> seq_switch_hw_paused = 0
> next_seq_posted_dsr = 0
> seq_posted_isr = 0
> seq_ctrl_cached = 0
> mpdu_count_tqm = 0
> msdu_count_tqm = 0
> mpdu_removed_tqm = 0
> msdu_removed_tqm = 0
> remove_mpdus_max_retries = 0
> mpdus_sw_flush = 0
> mpdus_hw_filter = 0
> mpdus_truncated = 0
> mpdus_ack_failed = 0
> mpdus_expired = 0
> mpdus_seq_hw_retry = 0
> ack_tlv_proc = 0
> coex_abort_mpdu_cnt_valid = 0
> coex_abort_mpdu_cnt = 5
> num_total_ppdus_tried_ota = 5
> num_data_ppdus_tried_ota = 0
> local_ctrl_mgmt_enqued = 247
> local_ctrl_mgmt_freed = 247
> local_data_enqued = 0
> local_data_freed = 0
> mpdu_tried = 0
> isr_wait_seq_posted = 0
> tx_active_dur_us_low = 0
> tx_active_dur_us_high = 0
> fes_offsets_err_cnt = 0
>
> HTT_TX_PDEV_STATS_URRN_TLV:
> urrn_stats = 0:0, 1:241, 2:0,
>
> HTT_TX_PDEV_STATS_SIFS_TLV:
> sifs_status = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>
> HTT_TX_PDEV_STATS_FLUSH_TLV:
> flush_errs = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0,
> 11:0, 12:0, 13:0, 14:0, 15:0, 16:0, 17:0, 18:0, 19:0, 20:0, 21:0, 22:0,
> 23:0, 24:0, 25:0, 26:0, 27:0, 28:0, 29:0, 30:0, 31:0, 32:0, 33:0, 34:0,
> 35:0, 36:0, 37:0, 38:0, 39:0, 40:0, 41:0, 42:0, 43:0, 44:0, 45:0, 46:0,
> 47:0, 48:0, 49:0, 50:0, 51:0, 52:0, 53:0, 54:0, 55:0, 56:0, 57:0, 58:0,
> 59:0, 60:0, 61:0, 62:0, 63:0, 64:0, 65:0, 66:0, 67:0, 68:0, 69:0, 70:0,
> 71:0, 72:0, 73:0, 74:0, 75:0, 76:0, 77:0, 78:0, 79:0, 80:0, 81:0, 82:0,
> 83:0, 84:0, 85:0, 86:0, 87:0, 88:0, 89:0, 90:0, 91:0, 92:0, 93:0, 94:0,
> 95:0, 96:0, 97:0, 98:0, 99:0, 100:0, 101:0, 102:0, 103:0, 104:0, 105:0,
> 106:0, 107:0, 108:0, 109:0, 110:0, 111:0, 112:0, 113:0, 114:0, 115:0,
> 116:0, 117:0, 118:0, 119:0, 120:0, 121:0, 122:0, 123:0, 124:0, 125:0,
> 126:0, 127:0,
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
>
> Signed-off-by: Dinesh Karthikeyan <[email protected]>
> Co-developed-by: Ramya Gnanasekar <[email protected]>
> Signed-off-by: Ramya Gnanasekar <[email protected]>
Acked-by: Jeff Johnson <[email protected]>
On 5/9/2024 10:08 PM, Ramya Gnanasekar wrote:
> Support to dump additional Tx PDEV stats through HTT stats debugfs.
> Following stats dump are supported:
> 1. PDEV control path stat to dump Tx management frame count
> 2. Tx PDEV SIFS histogram stats
> 3. Tx MU MIMO PPDU stats for 802.11ac, 802.11ax and 802.11be
>
> Sample Output:
> --------------
> echo 1 > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats_type
> cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats
> HTT_TX_PDEV_STATS_CMN_TLV:
> mac_id = 0
> comp_delivered = 0
> self_triggers = 13
> ......
> ......
> HTT_TX_PDEV_STATS_CTRL_PATH_TX_STATS:
> fw_tx_mgmt_subtype = 0:1, 1:0, 2:0, 3:0, 4:38, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:1, 12:0, 13:7, 14:0, 15:0,
>
> HTT_TX_PDEV_STATS_SIFS_HIST_TLV:
> sifs_hist_status = 0:237, 1:185, 2:1, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
>
> HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:
> ac_mu_mimo_num_seq_posted_nr4 = 0
> ac_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ac_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ac_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>
> ac_mu_mimo_num_seq_posted_nr8 = 0
> ac_mu_mimo_num_ppdu_posted_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ac_mu_mimo_num_ppdu_completed_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ac_mu_mimo_num_seq_term_status_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>
> ax_mu_mimo_num_seq_posted_nr4 = 0
> ax_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ax_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ax_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>
> ax_mu_mimo_num_seq_posted_nr8 = 0
> ax_mu_mimo_num_ppdu_posted_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ax_mu_mimo_num_ppdu_completed_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ax_mu_mimo_num_seq_term_status_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>
> be_mu_mimo_num_seq_posted_nr4 = 0
> be_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> be_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> be_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>
> be_mu_mimo_num_seq_posted_nr8 = 0
> be_mu_mimo_num_ppdu_posted_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> be_mu_mimo_num_ppdu_completed_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> be_mu_mimo_num_seq_term_status_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
>
> Signed-off-by: Ramya Gnanasekar <[email protected]>
Acked-by: Jeff Johnson <[email protected]>
Ramya Gnanasekar <[email protected]> writes:
> Bring in the basic infrastructure necessary for enabling htt_stats via debugfs.
> Patch series bring support to request stats type to firmware, dump the stats
> and request to reset the stats from firmware.
>
> Schema with one ath12k device:
>
> ath12k
> `-- pci-0000:06:00.0
> |-- mac0
> `-- htt_stats
> |-- htt_stats_type
> |-- htt_stats_reset
>
> Dinesh Karthikeyan (3):
> wifi: ath12k: Add support to enable debugfs_htt_stats
> wifi: ath12k: Add htt_stats_dump file ops support
> wifi: ath12k: Add support to parse requested stats_type
>
> Lingbo Kong (1):
> wifi: ath12k: Fix Pdev id in HTT stats request for WCN7850
>
> Ramya Gnanasekar (1):
> wifi: ath12k: Dump additional Tx PDEV HTT stats
I did a quick test with WCN7850:
cd /sys/kernel/debug/ath12k/pci-0000:06:00.0/mac0
echo 1 > htt_stats_type
cat htt_stats
And in the dmesg I see:
[ 178.634501] ==================================================================
[ 178.634870] BUG: KASAN: slab-out-of-bounds in skip_spaces+0x105/0x110
[ 178.635156] Read of size 1 at addr ffff888109d4696a by task bash/1474
[ 178.635367]
[ 178.635513] CPU: 1 PID: 1474 Comm: bash Not tainted 6.9.0-wt-ath+ #1523
[ 178.635747] Hardware name: Intel(R) Client Systems NUC8i7HVK/NUC8i7HVB, BIOS HNKBLi70.86A.0067.2021.0528.1339 05/28/2021
[ 178.636078] Call Trace:
[ 178.636238] <TASK>
[ 178.636393] dump_stack_lvl+0x7d/0xe0
[ 178.636578] print_address_description.constprop.0+0x33/0x3a0
[ 178.636786] print_report+0xb5/0x260
[ 178.637004] ? kasan_complete_mode_report_info+0x3c/0x1a0
[ 178.637211] kasan_report+0xd8/0x110
[ 178.637353] ? skip_spaces+0x105/0x110
[ 178.637392] ? skip_spaces+0x105/0x110
[ 178.637433] __asan_report_load1_noabort+0x14/0x20
[ 178.637488] skip_spaces+0x105/0x110
[ 178.637526] vsscanf+0x3e9/0x3100
[ 178.637573] ? ip6_compressed_string+0xb80/0xb80
[ 178.637614] ? debug_smp_processor_id+0x17/0x20
[ 178.637655] ? __lock_release.isra.0+0x49c/0xae0
[ 178.637696] ? reacquire_held_locks+0x4d0/0x4d0
[ 178.637736] ? lock_sync+0x1a0/0x1a0
[ 178.637774] sscanf+0xa6/0xd0
[ 178.637809] ? vsscanf+0x3100/0x3100
[ 178.637846] ? __might_fault+0x119/0x170
[ 178.637933] ? __might_fault+0xc0/0x170
[ 178.637983] ? __kasan_check_write+0x14/0x20
[ 178.638023] ath12k_write_htt_stats_type+0x122/0x330 [ath12k]
[ 178.638092] ? ath12k_open_htt_stats+0xbe0/0xbe0 [ath12k]
[ 178.638515] full_proxy_write+0xf8/0x180
[ 178.638563] vfs_write+0x220/0x1200
[ 178.638601] ? do_user_addr_fault+0x3f5/0xbb0
[ 178.638640] ? reacquire_held_locks+0x220/0x4d0
[ 178.638680] ? kernel_write+0x680/0x680
[ 178.638720] ? __kasan_check_read+0x11/0x20
[ 178.638757] ? __fget_light+0x53/0x1e0
[ 178.638796] ksys_write+0x10e/0x230
[ 178.638833] ? __ia32_sys_read+0xa0/0xa0
[ 178.638917] ? debug_smp_processor_id+0x17/0x20
[ 178.638959] __x64_sys_write+0x6d/0xa0
[ 178.638997] ? lockdep_hardirqs_on+0x7d/0x100
[ 178.639036] x64_sys_call+0x9cf/0x9e0
[ 178.639073] do_syscall_64+0x65/0x130
[ 178.639111] entry_SYSCALL_64_after_hwframe+0x4b/0x53
[ 178.639721] RIP: 0033:0x7f35ca96b297
[ 178.640363] Code: 64 89 02 48 c7 c0 ff ff ff ff eb bb 0f 1f 80 00 00 00 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 48 89 54 24 18 48 89 74 24
[ 178.641642] RSP: 002b:00007fff7addfa38 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
[ 178.642327] RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 00007f35ca96b297
[ 178.643013] RDX: 0000000000000002 RSI: 000055c737df4390 RDI: 0000000000000001
[ 178.643652] RBP: 000055c737df4390 R08: 000000000000000a R09: 0000000000000001
[ 178.644332] R10: 000055c703828017 R11: 0000000000000246 R12: 0000000000000002
[ 178.645010] R13: 00007f35caa4a6a0 R14: 00007f35caa464a0 R15: 00007f35caa458a0
[ 178.645643] </TASK>
[ 178.646321]
[ 178.646984] Allocated by task 1474 on cpu 1 at 178.634368s:
[ 178.647616] kasan_save_stack+0x26/0x50
[ 178.648290] kasan_save_track+0x18/0x60
[ 178.648955] kasan_save_alloc_info+0x37/0x40
[ 178.649560] __kasan_kmalloc+0x90/0xa0
[ 178.650197] __kmalloc+0x1be/0x3f0
[ 178.650765] ath12k_write_htt_stats_type+0xc1/0x330 [ath12k]
[ 178.651408] full_proxy_write+0xf8/0x180
[ 178.652029] vfs_write+0x220/0x1200
[ 178.652583] ksys_write+0x10e/0x230
[ 178.653181] __x64_sys_write+0x6d/0xa0
[ 178.653726] x64_sys_call+0x9cf/0x9e0
[ 178.654319] do_syscall_64+0x65/0x130
[ 178.654844] entry_SYSCALL_64_after_hwframe+0x4b/0x53
[ 178.655410]
[ 178.655970] The buggy address belongs to the object at ffff888109d46968#012[ 178.655970] which belongs to the cache kmalloc-8 of size 8
[ 178.657054] The buggy address is located 0 bytes to the right of#012[ 178.657054] allocated 2-byte region [ffff888109d46968, ffff888109d4696a)
[ 178.658142]
[ 178.658668] The buggy address belongs to the physical page:
[ 178.659256] page: refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff888109d46a08 pfn:0x109d46
[ 178.659824] flags: 0x200000000000a00(workingset|slab|node=0|zone=2)
[ 178.660438] page_type: 0xffffffff()
[ 178.661053] raw: 0200000000000a00 ffff88810004c3c0 ffffea0004275850 ffff8881000403d0
[ 178.661637] raw: ffff888109d46a08 0000000000190010 00000001ffffffff 0000000000000000
[ 178.662265] page dumped because: kasan: bad access detected
[ 178.662872]
[ 178.663475] Memory state around the buggy address:
[ 178.664108] ffff888109d46800: fc fc fc fc fc fa fc fc fc fc fc fc fc fc fc fc
[ 178.664710] ffff888109d46880: fc fc fc fc fc fc fc fc fc fa fc fc fc fc fc fc
[ 178.665972] >ffff888109d46900: fc fc fc fc fc fc fc fc fc fc fc fc fc 02 fc fc
[ 178.666571] ^
[ 178.667223] ffff888109d46980: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 178.667836] ffff888109d46a00: fc fa fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 178.668488] ==================================================================
[ 178.669233] Disabling lock debugging due to kernel taint
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
Ramya Gnanasekar <[email protected]> writes:
> From: Dinesh Karthikeyan <[email protected]>
>
> Add dump_htt_stats file operation to dump the stats value requested
> for the requested stats_type.
> Stats sent from firmware will be cumulative. Hence add debugfs to reset
> the requested stats type.
>
> Example with one ath12k device:
>
> ath12k
> `-- pci-0000:06:00.0
> |-- mac0
> `-- htt_stats
> |-- htt_stats_type
> |-- htt_stats_reset
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
>
> Signed-off-by: Dinesh Karthikeyan <[email protected]>
> Co-developed-by: Ramya Gnanasekar <[email protected]>
> Signed-off-by: Ramya Gnanasekar <[email protected]>
> ---
> drivers/net/wireless/ath/ath12k/core.h | 2 +
> .../wireless/ath/ath12k/debugfs_htt_stats.c | 202 ++++++++++++++++++
> .../wireless/ath/ath12k/debugfs_htt_stats.h | 30 +++
> 3 files changed, 234 insertions(+)
>
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index 3919bc828620..77c0842e5ab0 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -477,6 +477,8 @@ struct ath12k_fw_stats {
> struct ath12k_dbg_htt_stats {
> enum ath12k_dbg_htt_ext_stats_type type;
> u32 cfg_param[4];
> + u8 reset;
> + struct debug_htt_stats_req *stats_req;
Please document with a code comment how these are protected
> /* protects shared stats req buffer */
> spinlock_t lock;
I'm guessing "stats req buffer" refers to struct
ath12k_dbg_htt_stats::stats_req. But at least in
ath12k_release_htt_stats() you are using conf_mutex for protection:
static int ath12k_release_htt_stats(struct inode *inode,
struct file *file)
{
struct ath12k *ar = inode->i_private;
mutex_lock(&ar->conf_mutex);
kfree(file->private_data);
ar->debug.htt_stats.stats_req = NULL;
mutex_unlock(&ar->conf_mutex);
return 0;
}
> +static int ath12k_debugfs_htt_stats_req(struct ath12k *ar)
> +{
> + struct debug_htt_stats_req *stats_req = ar->debug.htt_stats.stats_req;
> + enum ath12k_dbg_htt_ext_stats_type type = stats_req->type;
> + u64 cookie;
> + int ret, pdev_id = ar->pdev->pdev_id;
> + struct htt_ext_stats_cfg_params cfg_params = { 0 };
> +
> + init_completion(&stats_req->htt_stats_rcvd);
> +
> + stats_req->done = false;
> + stats_req->pdev_id = pdev_id;
The locking design is not clear for me yet but I suspect this function
needs:
lockdep_assert_held(&ar->conf_mutex);
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
Ramya Gnanasekar <[email protected]> writes:
> From: Dinesh Karthikeyan <[email protected]>
>
> Create debugfs_htt_stats file when ath12k debugfs support is enabled.
> Add basic ath12k_debugfs_htt_stats_init and handle htt_stats_type
> file operations.
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
>
> Signed-off-by: Dinesh Karthikeyan <[email protected]>
> Co-developed-by: Ramya Gnanasekar <[email protected]>
> Signed-off-by: Ramya Gnanasekar <[email protected]>
[...]
> +struct ath12k_dbg_htt_stats {
> + enum ath12k_dbg_htt_ext_stats_type type;
> + u32 cfg_param[4];
> + /* protects shared stats req buffer */
> + spinlock_t lock;
> +};
Is there a specific reason why a new lock is needed? Why not just use
struct ath12k::data_lock?
> +
> struct ath12k_debug {
> struct dentry *debugfs_pdev;
> + struct ath12k_dbg_htt_stats htt_stats;
> };
>
> struct ath12k_per_peer_tx_stats {
> diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c
> index 8d8ba951093b..30a80f04d824 100644
> --- a/drivers/net/wireless/ath/ath12k/debugfs.c
> +++ b/drivers/net/wireless/ath/ath12k/debugfs.c
> @@ -6,6 +6,7 @@
>
> #include "core.h"
> #include "debugfs.h"
> +#include "debugfs_htt_stats.h"
>
> static ssize_t ath12k_write_simulate_radar(struct file *file,
> const char __user *user_buf,
> @@ -87,4 +88,6 @@ void ath12k_debugfs_register(struct ath12k *ar)
> ar->debug.debugfs_pdev, ar,
> &fops_simulate_radar);
> }
> +
> + ath12k_debugfs_htt_stats_init(ar);
Let's try to have consistent naming: ath12k_debugfs_htt_stats_register()
> +static ssize_t ath12k_read_htt_stats_type(struct file *file,
> + char __user *user_buf,
> + size_t count, loff_t *ppos)
> +{
> + struct ath12k *ar = file->private_data;
> + char buf[32];
> + size_t len;
> +
> + len = scnprintf(buf, sizeof(buf), "%u\n", ar->debug.htt_stats.type);
> +
> + return simple_read_from_buffer(user_buf, count, ppos, buf, len);
> +}
Access to ar->debug.htt_stats.type isn't protected in any way.
> +
> +static ssize_t ath12k_write_htt_stats_type(struct file *file,
> + const char __user *user_buf,
> + size_t count, loff_t *ppos)
> +{
> + struct ath12k *ar = file->private_data;
> + enum ath12k_dbg_htt_ext_stats_type type;
> + unsigned int cfg_param[4] = {0};
> + int num_args;
> +
> + char *buf __free(kfree) = kzalloc(count, GFP_KERNEL);
> + if (!buf)
> + return -ENOMEM;
> +
> + if (copy_from_user(buf, user_buf, count))
> + return -EFAULT;
> +
> + num_args = sscanf(buf, "%u %u %u %u %u\n", &type, &cfg_param[0],
> + &cfg_param[1], &cfg_param[2], &cfg_param[3]);
> + if (!num_args || num_args > 5)
> + return -EINVAL;
> +
> + if (type >= ATH12K_DBG_HTT_NUM_EXT_STATS)
> + return -E2BIG;
> +
> + if (type == ATH12K_DBG_HTT_EXT_STATS_RESET)
> + return -EPERM;
> +
> + ar->debug.htt_stats.type = type;
> + ar->debug.htt_stats.cfg_param[0] = cfg_param[0];
> + ar->debug.htt_stats.cfg_param[1] = cfg_param[1];
> + ar->debug.htt_stats.cfg_param[2] = cfg_param[2];
> + ar->debug.htt_stats.cfg_param[3] = cfg_param[3];
> +
> + return count;
> +}
Same here with both type and cfg_param. Maybe it's ok to skip
protection, I didn't do analysis yet, but this makes me suspicious.
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
Ramya Gnanasekar <[email protected]> writes:
> Support to dump additional Tx PDEV stats through HTT stats debugfs.
> Following stats dump are supported:
> 1. PDEV control path stat to dump Tx management frame count
> 2. Tx PDEV SIFS histogram stats
> 3. Tx MU MIMO PPDU stats for 802.11ac, 802.11ax and 802.11be
>
> Sample Output:
> --------------
> echo 1 > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats_type
> cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats
> HTT_TX_PDEV_STATS_CMN_TLV:
> mac_id = 0
> comp_delivered = 0
> self_triggers = 13
> ......
> ......
> HTT_TX_PDEV_STATS_CTRL_PATH_TX_STATS:
> fw_tx_mgmt_subtype = 0:1, 1:0, 2:0, 3:0, 4:38, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:1, 12:0, 13:7, 14:0, 15:0,
>
> HTT_TX_PDEV_STATS_SIFS_HIST_TLV:
> sifs_hist_status = 0:237, 1:185, 2:1, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
>
> HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:
> ac_mu_mimo_num_seq_posted_nr4 = 0
> ac_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ac_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ac_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>
> ac_mu_mimo_num_seq_posted_nr8 = 0
> ac_mu_mimo_num_ppdu_posted_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ac_mu_mimo_num_ppdu_completed_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ac_mu_mimo_num_seq_term_status_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>
> ax_mu_mimo_num_seq_posted_nr4 = 0
> ax_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ax_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ax_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>
> ax_mu_mimo_num_seq_posted_nr8 = 0
> ax_mu_mimo_num_ppdu_posted_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ax_mu_mimo_num_ppdu_completed_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ax_mu_mimo_num_seq_term_status_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>
> be_mu_mimo_num_seq_posted_nr4 = 0
> be_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> be_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> be_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>
> be_mu_mimo_num_seq_posted_nr8 = 0
> be_mu_mimo_num_ppdu_posted_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> be_mu_mimo_num_ppdu_completed_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> be_mu_mimo_num_seq_term_status_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
>
> Signed-off-by: Ramya Gnanasekar <[email protected]>
[...]
> +static inline void
> +ath12k_htt_print_tx_pdev_mu_ppdu_dist_stats_tlv(const void *tag_buf,
> + struct debug_htt_stats_req *stats_req)
> +{
> + const struct ath12k_htt_tx_pdev_mu_ppdu_dist_stats_tlv *htt_stats_buf = tag_buf;
> + char *mode;
> + u8 j, hw_mode, i, str_buf_len;
> + u8 *buf = stats_req->buf;
> + u32 len = stats_req->buf_len;
> + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
> + u32 stats_value;
> + u8 max_ppdu = ATH12K_HTT_STATS_MAX_NUM_MU_PPDU_PER_BURST;
> + u8 max_sched = ATH12K_HTT_STATS_MAX_NUM_SCHED_STATUS;
> + char str_buf[ATH12K_HTT_MAX_STRING_LEN];
> +
> + hw_mode = le32_to_cpu(htt_stats_buf->hw_mode);
> +
> + switch (hw_mode) {
> + case ATH12K_HTT_STATS_HWMODE_AC:
> + len += scnprintf(buf + len, buf_len - len,
> + "HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n");
> + mode = "ac";
> + break;
> + case ATH12K_HTT_STATS_HWMODE_AX:
> + mode = "ax";
> + break;
> + case ATH12K_HTT_STATS_HWMODE_BE:
> + mode = "be";
> + break;
> + default:
> + return;
> + }
Why are we not adding "HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n" with
ax and be modes?
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
On 5/21/2024 1:30 PM, Kalle Valo wrote:
> Ramya Gnanasekar <[email protected]> writes:
>
>> Support to dump additional Tx PDEV stats through HTT stats debugfs.
>> Following stats dump are supported:
>> 1. PDEV control path stat to dump Tx management frame count
>> 2. Tx PDEV SIFS histogram stats
>> 3. Tx MU MIMO PPDU stats for 802.11ac, 802.11ax and 802.11be
>>
>> Sample Output:
>> --------------
>> echo 1 > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats_type
>> cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/htt_stats
>> HTT_TX_PDEV_STATS_CMN_TLV:
>> mac_id = 0
>> comp_delivered = 0
>> self_triggers = 13
>> ......
>> ......
>> HTT_TX_PDEV_STATS_CTRL_PATH_TX_STATS:
>> fw_tx_mgmt_subtype = 0:1, 1:0, 2:0, 3:0, 4:38, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:1, 12:0, 13:7, 14:0, 15:0,
>>
>> HTT_TX_PDEV_STATS_SIFS_HIST_TLV:
>> sifs_hist_status = 0:237, 1:185, 2:1, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
>>
>> HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:
>> ac_mu_mimo_num_seq_posted_nr4 = 0
>> ac_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
>> ac_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
>> ac_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>>
>> ac_mu_mimo_num_seq_posted_nr8 = 0
>> ac_mu_mimo_num_ppdu_posted_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
>> ac_mu_mimo_num_ppdu_completed_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
>> ac_mu_mimo_num_seq_term_status_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>>
>> ax_mu_mimo_num_seq_posted_nr4 = 0
>> ax_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
>> ax_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
>> ax_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>>
>> ax_mu_mimo_num_seq_posted_nr8 = 0
>> ax_mu_mimo_num_ppdu_posted_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
>> ax_mu_mimo_num_ppdu_completed_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
>> ax_mu_mimo_num_seq_term_status_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>>
>> be_mu_mimo_num_seq_posted_nr4 = 0
>> be_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
>> be_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
>> be_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>>
>> be_mu_mimo_num_seq_posted_nr8 = 0
>> be_mu_mimo_num_ppdu_posted_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
>> be_mu_mimo_num_ppdu_completed_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
>> be_mu_mimo_num_seq_term_status_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>>
>> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
>> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
>>
>> Signed-off-by: Ramya Gnanasekar <[email protected]>
>
> [...]
>
>> +static inline void
>> +ath12k_htt_print_tx_pdev_mu_ppdu_dist_stats_tlv(const void *tag_buf,
>> + struct debug_htt_stats_req *stats_req)
>> +{
>> + const struct ath12k_htt_tx_pdev_mu_ppdu_dist_stats_tlv *htt_stats_buf = tag_buf;
>> + char *mode;
>> + u8 j, hw_mode, i, str_buf_len;
>> + u8 *buf = stats_req->buf;
>> + u32 len = stats_req->buf_len;
>> + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
>> + u32 stats_value;
>> + u8 max_ppdu = ATH12K_HTT_STATS_MAX_NUM_MU_PPDU_PER_BURST;
>> + u8 max_sched = ATH12K_HTT_STATS_MAX_NUM_SCHED_STATUS;
>> + char str_buf[ATH12K_HTT_MAX_STRING_LEN];
>> +
>> + hw_mode = le32_to_cpu(htt_stats_buf->hw_mode);
>> +
>> + switch (hw_mode) {
>> + case ATH12K_HTT_STATS_HWMODE_AC:
>> + len += scnprintf(buf + len, buf_len - len,
>> + "HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n");
>> + mode = "ac";
>> + break;
>> + case ATH12K_HTT_STATS_HWMODE_AX:
>> + mode = "ax";
>> + break;
>> + case ATH12K_HTT_STATS_HWMODE_BE:
>> + mode = "be";
>> + break;
>> + default:
>> + return;
>> + }
>
> Why are we not adding "HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n" with
> ax and be modes?
>
Sorry for the delayed response. I was on OoO for a week.
We will receive this TLV for each hw modes. Since
"HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n" is header and it would be
suffice to print it once, hence added it inside hw mode ac which will be
the first hw mode integrated inside the TLV.
On 5/21/2024 1:19 PM, Kalle Valo wrote:
> Ramya Gnanasekar <[email protected]> writes:
>
>> From: Dinesh Karthikeyan <[email protected]>
>>
>> Create debugfs_htt_stats file when ath12k debugfs support is enabled.
>> Add basic ath12k_debugfs_htt_stats_init and handle htt_stats_type
>> file operations.
>>
>> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
>> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
>>
>> Signed-off-by: Dinesh Karthikeyan <[email protected]>
>> Co-developed-by: Ramya Gnanasekar <[email protected]>
>> Signed-off-by: Ramya Gnanasekar <[email protected]>
>
> [...]
>
>> +struct ath12k_dbg_htt_stats {
>> + enum ath12k_dbg_htt_ext_stats_type type;
>> + u32 cfg_param[4];
>> + /* protects shared stats req buffer */
>> + spinlock_t lock;
>> +};
>
> Is there a specific reason why a new lock is needed? Why not just use
> struct ath12k::data_lock?
We can use ath12k::data_lock as well since that is also per radio. I
will check and address in next version.
>
>> +
>> struct ath12k_debug {
>> struct dentry *debugfs_pdev;
>> + struct ath12k_dbg_htt_stats htt_stats;
>> };
>>
>> struct ath12k_per_peer_tx_stats {
>> diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c
>> index 8d8ba951093b..30a80f04d824 100644
>> --- a/drivers/net/wireless/ath/ath12k/debugfs.c
>> +++ b/drivers/net/wireless/ath/ath12k/debugfs.c
>> @@ -6,6 +6,7 @@
>>
>> #include "core.h"
>> #include "debugfs.h"
>> +#include "debugfs_htt_stats.h"
>>
>> static ssize_t ath12k_write_simulate_radar(struct file *file,
>> const char __user *user_buf,
>> @@ -87,4 +88,6 @@ void ath12k_debugfs_register(struct ath12k *ar)
>> ar->debug.debugfs_pdev, ar,
>> &fops_simulate_radar);
>> }
>> +
>> + ath12k_debugfs_htt_stats_init(ar);
>
> Let's try to have consistent naming: ath12k_debugfs_htt_stats_register()
Sure Kalle. I will take care in next version.
>
>> +static ssize_t ath12k_read_htt_stats_type(struct file *file,
>> + char __user *user_buf,
>> + size_t count, loff_t *ppos)
>> +{
>> + struct ath12k *ar = file->private_data;
>> + char buf[32];
>> + size_t len;
>> +
>> + len = scnprintf(buf, sizeof(buf), "%u\n", ar->debug.htt_stats.type);
>> +
>> + return simple_read_from_buffer(user_buf, count, ppos, buf, len);
>> +}
>
> Access to ar->debug.htt_stats.type isn't protected in any way.
I will check and address this.
>
>> +
>> +static ssize_t ath12k_write_htt_stats_type(struct file *file,
>> + const char __user *user_buf,
>> + size_t count, loff_t *ppos)
>> +{
>> + struct ath12k *ar = file->private_data;
>> + enum ath12k_dbg_htt_ext_stats_type type;
>> + unsigned int cfg_param[4] = {0};
>> + int num_args;
>> +
>> + char *buf __free(kfree) = kzalloc(count, GFP_KERNEL);
>> + if (!buf)
>> + return -ENOMEM;
>> +
>> + if (copy_from_user(buf, user_buf, count))
>> + return -EFAULT;
>> +
>> + num_args = sscanf(buf, "%u %u %u %u %u\n", &type, &cfg_param[0],
>> + &cfg_param[1], &cfg_param[2], &cfg_param[3]);
>> + if (!num_args || num_args > 5)
>> + return -EINVAL;
>> +
>> + if (type >= ATH12K_DBG_HTT_NUM_EXT_STATS)
>> + return -E2BIG;
>> +
>> + if (type == ATH12K_DBG_HTT_EXT_STATS_RESET)
>> + return -EPERM;
>> +
>> + ar->debug.htt_stats.type = type;
>> + ar->debug.htt_stats.cfg_param[0] = cfg_param[0];
>> + ar->debug.htt_stats.cfg_param[1] = cfg_param[1];
>> + ar->debug.htt_stats.cfg_param[2] = cfg_param[2];
>> + ar->debug.htt_stats.cfg_param[3] = cfg_param[3];
>> +
>> + return count;
>> +}
>
> Same here with both type and cfg_param. Maybe it's ok to skip
> protection, I didn't do analysis yet, but this makes me suspicious.>
Sure Kalle. I will check and address the same.
On 5/21/2024 1:10 PM, Kalle Valo wrote:
> Ramya Gnanasekar <[email protected]> writes:
>
>> Bring in the basic infrastructure necessary for enabling htt_stats via debugfs.
>> Patch series bring support to request stats type to firmware, dump the stats
>> and request to reset the stats from firmware.
>>
>> Schema with one ath12k device:
>>
>> ath12k
>> `-- pci-0000:06:00.0
>> |-- mac0
>> `-- htt_stats
>> |-- htt_stats_type
>> |-- htt_stats_reset
>>
>> Dinesh Karthikeyan (3):
>> wifi: ath12k: Add support to enable debugfs_htt_stats
>> wifi: ath12k: Add htt_stats_dump file ops support
>> wifi: ath12k: Add support to parse requested stats_type
>>
>> Lingbo Kong (1):
>> wifi: ath12k: Fix Pdev id in HTT stats request for WCN7850
>>
>> Ramya Gnanasekar (1):
>> wifi: ath12k: Dump additional Tx PDEV HTT stats
>
> I did a quick test with WCN7850:
>
> cd /sys/kernel/debug/ath12k/pci-0000:06:00.0/mac0
> echo 1 > htt_stats_type
> cat htt_stats
>
> And in the dmesg I see:
>
> [ 178.634501] ==================================================================
> [ 178.634870] BUG: KASAN: slab-out-of-bounds in skip_spaces+0x105/0x110
> [ 178.635156] Read of size 1 at addr ffff888109d4696a by task bash/1474
> [ 178.635367]
> [ 178.635513] CPU: 1 PID: 1474 Comm: bash Not tainted 6.9.0-wt-ath+ #1523
> [ 178.635747] Hardware name: Intel(R) Client Systems NUC8i7HVK/NUC8i7HVB, BIOS HNKBLi70.86A.0067.2021.0528.1339 05/28/2021
> [ 178.636078] Call Trace:
> [ 178.636238] <TASK>
> [ 178.636393] dump_stack_lvl+0x7d/0xe0
> [ 178.636578] print_address_description.constprop.0+0x33/0x3a0
> [ 178.636786] print_report+0xb5/0x260
> [ 178.637004] ? kasan_complete_mode_report_info+0x3c/0x1a0
> [ 178.637211] kasan_report+0xd8/0x110
> [ 178.637353] ? skip_spaces+0x105/0x110
> [ 178.637392] ? skip_spaces+0x105/0x110
> [ 178.637433] __asan_report_load1_noabort+0x14/0x20
> [ 178.637488] skip_spaces+0x105/0x110
> [ 178.637526] vsscanf+0x3e9/0x3100
> [ 178.637573] ? ip6_compressed_string+0xb80/0xb80
> [ 178.637614] ? debug_smp_processor_id+0x17/0x20
> [ 178.637655] ? __lock_release.isra.0+0x49c/0xae0
> [ 178.637696] ? reacquire_held_locks+0x4d0/0x4d0
> [ 178.637736] ? lock_sync+0x1a0/0x1a0
> [ 178.637774] sscanf+0xa6/0xd0
> [ 178.637809] ? vsscanf+0x3100/0x3100
> [ 178.637846] ? __might_fault+0x119/0x170
> [ 178.637933] ? __might_fault+0xc0/0x170
> [ 178.637983] ? __kasan_check_write+0x14/0x20
> [ 178.638023] ath12k_write_htt_stats_type+0x122/0x330 [ath12k]
> [ 178.638092] ? ath12k_open_htt_stats+0xbe0/0xbe0 [ath12k]
> [ 178.638515] full_proxy_write+0xf8/0x180
> [ 178.638563] vfs_write+0x220/0x1200
> [ 178.638601] ? do_user_addr_fault+0x3f5/0xbb0
> [ 178.638640] ? reacquire_held_locks+0x220/0x4d0
> [ 178.638680] ? kernel_write+0x680/0x680
> [ 178.638720] ? __kasan_check_read+0x11/0x20
> [ 178.638757] ? __fget_light+0x53/0x1e0
> [ 178.638796] ksys_write+0x10e/0x230
> [ 178.638833] ? __ia32_sys_read+0xa0/0xa0
> [ 178.638917] ? debug_smp_processor_id+0x17/0x20
> [ 178.638959] __x64_sys_write+0x6d/0xa0
> [ 178.638997] ? lockdep_hardirqs_on+0x7d/0x100
> [ 178.639036] x64_sys_call+0x9cf/0x9e0
> [ 178.639073] do_syscall_64+0x65/0x130
> [ 178.639111] entry_SYSCALL_64_after_hwframe+0x4b/0x53
> [ 178.639721] RIP: 0033:0x7f35ca96b297
> [ 178.640363] Code: 64 89 02 48 c7 c0 ff ff ff ff eb bb 0f 1f 80 00 00 00 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 48 89 54 24 18 48 89 74 24
> [ 178.641642] RSP: 002b:00007fff7addfa38 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
> [ 178.642327] RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 00007f35ca96b297
> [ 178.643013] RDX: 0000000000000002 RSI: 000055c737df4390 RDI: 0000000000000001
> [ 178.643652] RBP: 000055c737df4390 R08: 000000000000000a R09: 0000000000000001
> [ 178.644332] R10: 000055c703828017 R11: 0000000000000246 R12: 0000000000000002
> [ 178.645010] R13: 00007f35caa4a6a0 R14: 00007f35caa464a0 R15: 00007f35caa458a0
> [ 178.645643] </TASK>
> [ 178.646321]
> [ 178.646984] Allocated by task 1474 on cpu 1 at 178.634368s:
> [ 178.647616] kasan_save_stack+0x26/0x50
> [ 178.648290] kasan_save_track+0x18/0x60
> [ 178.648955] kasan_save_alloc_info+0x37/0x40
> [ 178.649560] __kasan_kmalloc+0x90/0xa0
> [ 178.650197] __kmalloc+0x1be/0x3f0
> [ 178.650765] ath12k_write_htt_stats_type+0xc1/0x330 [ath12k]
> [ 178.651408] full_proxy_write+0xf8/0x180
> [ 178.652029] vfs_write+0x220/0x1200
> [ 178.652583] ksys_write+0x10e/0x230
> [ 178.653181] __x64_sys_write+0x6d/0xa0
> [ 178.653726] x64_sys_call+0x9cf/0x9e0
> [ 178.654319] do_syscall_64+0x65/0x130
> [ 178.654844] entry_SYSCALL_64_after_hwframe+0x4b/0x53
> [ 178.655410]
> [ 178.655970] The buggy address belongs to the object at ffff888109d46968#012[ 178.655970] which belongs to the cache kmalloc-8 of size 8
> [ 178.657054] The buggy address is located 0 bytes to the right of#012[ 178.657054] allocated 2-byte region [ffff888109d46968, ffff888109d4696a)
> [ 178.658142]
> [ 178.658668] The buggy address belongs to the physical page:
> [ 178.659256] page: refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff888109d46a08 pfn:0x109d46
> [ 178.659824] flags: 0x200000000000a00(workingset|slab|node=0|zone=2)
> [ 178.660438] page_type: 0xffffffff()
> [ 178.661053] raw: 0200000000000a00 ffff88810004c3c0 ffffea0004275850 ffff8881000403d0
> [ 178.661637] raw: ffff888109d46a08 0000000000190010 00000001ffffffff 0000000000000000
> [ 178.662265] page dumped because: kasan: bad access detected
> [ 178.662872]
> [ 178.663475] Memory state around the buggy address:
> [ 178.664108] ffff888109d46800: fc fc fc fc fc fa fc fc fc fc fc fc fc fc fc fc
> [ 178.664710] ffff888109d46880: fc fc fc fc fc fc fc fc fc fa fc fc fc fc fc fc
> [ 178.665972] >ffff888109d46900: fc fc fc fc fc fc fc fc fc fc fc fc fc 02 fc fc
> [ 178.666571] ^
> [ 178.667223] ffff888109d46980: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> [ 178.667836] ffff888109d46a00: fc fa fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> [ 178.668488] ==================================================================
> [ 178.669233] Disabling lock debugging due to kernel taint
>
Thanks Kalle. I was not facing this in QCN9274. May be I will check my
.config to confirm whether KASAN config is enabled.
Ramya Gnanasekar <[email protected]> writes:
>>> +static inline void
>>> +ath12k_htt_print_tx_pdev_mu_ppdu_dist_stats_tlv(const void *tag_buf,
>>> + struct debug_htt_stats_req *stats_req)
>>> +{
>>> + const struct ath12k_htt_tx_pdev_mu_ppdu_dist_stats_tlv
>>> *htt_stats_buf = tag_buf;
>>> + char *mode;
>>> + u8 j, hw_mode, i, str_buf_len;
>>> + u8 *buf = stats_req->buf;
>>> + u32 len = stats_req->buf_len;
>>> + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
>>> + u32 stats_value;
>>> + u8 max_ppdu = ATH12K_HTT_STATS_MAX_NUM_MU_PPDU_PER_BURST;
>>> + u8 max_sched = ATH12K_HTT_STATS_MAX_NUM_SCHED_STATUS;
>>> + char str_buf[ATH12K_HTT_MAX_STRING_LEN];
>>> +
>>> + hw_mode = le32_to_cpu(htt_stats_buf->hw_mode);
>>> +
>>> + switch (hw_mode) {
>>> + case ATH12K_HTT_STATS_HWMODE_AC:
>>> + len += scnprintf(buf + len, buf_len - len,
>>> + "HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n");
>>> + mode = "ac";
>>> + break;
>>> + case ATH12K_HTT_STATS_HWMODE_AX:
>>> + mode = "ax";
>>> + break;
>>> + case ATH12K_HTT_STATS_HWMODE_BE:
>>> + mode = "be";
>>> + break;
>>> + default:
>>> + return;
>>> + }
>>
>> Why are we not adding "HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n" with
>> ax and be modes?
>>
> Sorry for the delayed response. I was on OoO for a week.
No worries.
> We will receive this TLV for each hw modes. Since
> "HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n" is header and it would be
> suffice to print it once, hence added it inside hw mode ac which will be
> the first hw mode integrated inside the TLV.
I would have expected that we print that outside of
ath12k_htt_print_tx_pdev_mu_ppdu_dist_stats_tlv(), before the function
is called at all.
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
On 5/28/2024 4:36 PM, Kalle Valo wrote:
> Ramya Gnanasekar <[email protected]> writes:
>
>>>> +static inline void
>>>> +ath12k_htt_print_tx_pdev_mu_ppdu_dist_stats_tlv(const void *tag_buf,
>>>> + struct debug_htt_stats_req *stats_req)
>>>> +{
>>>> + const struct ath12k_htt_tx_pdev_mu_ppdu_dist_stats_tlv
>>>> *htt_stats_buf = tag_buf;
>>>> + char *mode;
>>>> + u8 j, hw_mode, i, str_buf_len;
>>>> + u8 *buf = stats_req->buf;
>>>> + u32 len = stats_req->buf_len;
>>>> + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
>>>> + u32 stats_value;
>>>> + u8 max_ppdu = ATH12K_HTT_STATS_MAX_NUM_MU_PPDU_PER_BURST;
>>>> + u8 max_sched = ATH12K_HTT_STATS_MAX_NUM_SCHED_STATUS;
>>>> + char str_buf[ATH12K_HTT_MAX_STRING_LEN];
>>>> +
>>>> + hw_mode = le32_to_cpu(htt_stats_buf->hw_mode);
>>>> +
>>>> + switch (hw_mode) {
>>>> + case ATH12K_HTT_STATS_HWMODE_AC:
>>>> + len += scnprintf(buf + len, buf_len - len,
>>>> + "HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n");
>>>> + mode = "ac";
>>>> + break;
>>>> + case ATH12K_HTT_STATS_HWMODE_AX:
>>>> + mode = "ax";
>>>> + break;
>>>> + case ATH12K_HTT_STATS_HWMODE_BE:
>>>> + mode = "be";
>>>> + break;
>>>> + default:
>>>> + return;
>>>> + }
>>>
>>> Why are we not adding "HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n" with
>>> ax and be modes?
>>>
>> Sorry for the delayed response. I was on OoO for a week.
>
> No worries.
>
>> We will receive this TLV for each hw modes. Since
>> "HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n" is header and it would be
>> suffice to print it once, hence added it inside hw mode ac which will be
>> the first hw mode integrated inside the TLV.
>
> I would have expected that we print that outside of
> ath12k_htt_print_tx_pdev_mu_ppdu_dist_stats_tlv(), before the function
> is called at all.
>
Function itself will be called more than once. The overall HTT TLV will
be integrated with tag HTT_STATS_MU_PPDU_DIST_TAG (129) for all the hw
modes separately.
Ramya Gnanasekar <[email protected]> writes:
> On 5/28/2024 4:36 PM, Kalle Valo wrote:
>> Ramya Gnanasekar <[email protected]> writes:
>>
>>>>> +static inline void
>>>>> +ath12k_htt_print_tx_pdev_mu_ppdu_dist_stats_tlv(const void *tag_buf,
>>>>> + struct debug_htt_stats_req *stats_req)
>>>>> +{
>>>>> + const struct ath12k_htt_tx_pdev_mu_ppdu_dist_stats_tlv
>>>>> *htt_stats_buf = tag_buf;
>>>>> + char *mode;
>>>>> + u8 j, hw_mode, i, str_buf_len;
>>>>> + u8 *buf = stats_req->buf;
>>>>> + u32 len = stats_req->buf_len;
>>>>> + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
>>>>> + u32 stats_value;
>>>>> + u8 max_ppdu = ATH12K_HTT_STATS_MAX_NUM_MU_PPDU_PER_BURST;
>>>>> + u8 max_sched = ATH12K_HTT_STATS_MAX_NUM_SCHED_STATUS;
>>>>> + char str_buf[ATH12K_HTT_MAX_STRING_LEN];
>>>>> +
>>>>> + hw_mode = le32_to_cpu(htt_stats_buf->hw_mode);
>>>>> +
>>>>> + switch (hw_mode) {
>>>>> + case ATH12K_HTT_STATS_HWMODE_AC:
>>>>> + len += scnprintf(buf + len, buf_len - len,
>>>>> + "HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n");
>>>>> + mode = "ac";
>>>>> + break;
>>>>> + case ATH12K_HTT_STATS_HWMODE_AX:
>>>>> + mode = "ax";
>>>>> + break;
>>>>> + case ATH12K_HTT_STATS_HWMODE_BE:
>>>>> + mode = "be";
>>>>> + break;
>>>>> + default:
>>>>> + return;
>>>>> + }
>>>>
>>>> Why are we not adding "HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n" with
>>>> ax and be modes?
>>>>
>>> Sorry for the delayed response. I was on OoO for a week.
>>
>> No worries.
>>
>>> We will receive this TLV for each hw modes. Since
>>> "HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n" is header and it would be
>>> suffice to print it once, hence added it inside hw mode ac which will be
>>> the first hw mode integrated inside the TLV.
>>
>> I would have expected that we print that outside of
>> ath12k_htt_print_tx_pdev_mu_ppdu_dist_stats_tlv(), before the function
>> is called at all.
>>
>
> Function itself will be called more than once.
Sure, I got that. But I still think it is not really good design to
print it like that.
Maybe the output could be something like below? Or print the mode
separate in the first line?
HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:
ac_mu_mimo_num_seq_posted_nr4 = 0
ac_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
ac_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
ac_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
....
HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:
ax_mu_mimo_num_seq_posted_nr4 = 0
ax_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
ax_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
ax_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
ax_mu_mimo_num_seq_posted_nr8 = 0
ax_mu_mimo_num_ppdu_posted_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
ax_mu_mimo_num_ppdu_completed_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
ax_mu_mimo_num_seq_term_status_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
On 5/31/2024 11:30 PM, Kalle Valo wrote:
> Ramya Gnanasekar <[email protected]> writes:
>
>> On 5/28/2024 4:36 PM, Kalle Valo wrote:
>>> Ramya Gnanasekar <[email protected]> writes:
>>>
>>>>>> +static inline void
>>>>>> +ath12k_htt_print_tx_pdev_mu_ppdu_dist_stats_tlv(const void *tag_buf,
>>>>>> + struct debug_htt_stats_req *stats_req)
>>>>>> +{
>>>>>> + const struct ath12k_htt_tx_pdev_mu_ppdu_dist_stats_tlv
>>>>>> *htt_stats_buf = tag_buf;
>>>>>> + char *mode;
>>>>>> + u8 j, hw_mode, i, str_buf_len;
>>>>>> + u8 *buf = stats_req->buf;
>>>>>> + u32 len = stats_req->buf_len;
>>>>>> + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
>>>>>> + u32 stats_value;
>>>>>> + u8 max_ppdu = ATH12K_HTT_STATS_MAX_NUM_MU_PPDU_PER_BURST;
>>>>>> + u8 max_sched = ATH12K_HTT_STATS_MAX_NUM_SCHED_STATUS;
>>>>>> + char str_buf[ATH12K_HTT_MAX_STRING_LEN];
>>>>>> +
>>>>>> + hw_mode = le32_to_cpu(htt_stats_buf->hw_mode);
>>>>>> +
>>>>>> + switch (hw_mode) {
>>>>>> + case ATH12K_HTT_STATS_HWMODE_AC:
>>>>>> + len += scnprintf(buf + len, buf_len - len,
>>>>>> + "HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n");
>>>>>> + mode = "ac";
>>>>>> + break;
>>>>>> + case ATH12K_HTT_STATS_HWMODE_AX:
>>>>>> + mode = "ax";
>>>>>> + break;
>>>>>> + case ATH12K_HTT_STATS_HWMODE_BE:
>>>>>> + mode = "be";
>>>>>> + break;
>>>>>> + default:
>>>>>> + return;
>>>>>> + }
>>>>>
>>>>> Why are we not adding "HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n" with
>>>>> ax and be modes?
>>>>>
>>>> Sorry for the delayed response. I was on OoO for a week.
>>>
>>> No worries.
>>>
>>>> We will receive this TLV for each hw modes. Since
>>>> "HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:\n" is header and it would be
>>>> suffice to print it once, hence added it inside hw mode ac which will be
>>>> the first hw mode integrated inside the TLV.
>>>
>>> I would have expected that we print that outside of
>>> ath12k_htt_print_tx_pdev_mu_ppdu_dist_stats_tlv(), before the function
>>> is called at all.
>>>
>>
>> Function itself will be called more than once.
>
> Sure, I got that. But I still think it is not really good design to
> print it like that.
>
> Maybe the output could be something like below? Or print the mode
> separate in the first line?
>
> HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:
>
> ac_mu_mimo_num_seq_posted_nr4 = 0
> ac_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ac_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ac_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>
> ....
>
> HTT_TX_PDEV_MU_PPDU_DISTRIBUTION_STATS:
>
> ax_mu_mimo_num_seq_posted_nr4 = 0
> ax_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ax_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ax_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>
> ax_mu_mimo_num_seq_posted_nr8 = 0
> ax_mu_mimo_num_ppdu_posted_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ax_mu_mimo_num_ppdu_completed_per_burst_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0,
> ax_mu_mimo_num_seq_term_status_nr8 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0,
>
Sure Kalle. I understand. Will change like below and re-spin with all
the comments addressed:
HTT_TX_PDEV_AC_MU_PPDU_DISTRIBUTION_STATS:
ac_mu_mimo_num_seq_posted_nr4 = 0
ac_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0,
5:0, 6:0, 7:0, 8:0, 9:0,
ac_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0,
5:0, 6:0, 7:0, 8:0, 9:0,
ac_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0,
7:0, 8:0,
......
......
HTT_TX_PDEV_AX_MU_PPDU_DISTRIBUTION_STATS:
ax_mu_mimo_num_seq_posted_nr4 = 0
ax_mu_mimo_num_ppdu_posted_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0,
5:0, 6:0, 7:0, 8:0, 9:0,
ax_mu_mimo_num_ppdu_completed_per_burst_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0,
5:0, 6:0, 7:0, 8:0, 9:0,
ax_mu_mimo_num_seq_term_status_nr4 = 0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0,
7:0, 8:0,
......
......