]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: ath12k: Add htt_stats_dump file ops support
authorDinesh Karthikeyan <quic_dinek@quicinc.com>
Thu, 27 Jun 2024 16:36:50 +0000 (19:36 +0300)
committerKalle Valo <quic_kvalo@quicinc.com>
Mon, 1 Jul 2024 18:54:27 +0000 (21:54 +0300)
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 <quic_dinek@quicinc.com>
Co-developed-by: Ramya Gnanasekar <quic_rgnanase@quicinc.com>
Signed-off-by: Ramya Gnanasekar <quic_rgnanase@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://patch.msgid.link/20240626085854.2500681-3-quic_rgnanase@quicinc.com
drivers/net/wireless/ath/ath12k/core.h
drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
drivers/net/wireless/ath/ath12k/dp_tx.c

index 7173c7e174a7fec5d7b808ab2624ef3873a24cf7..cdfd43a7321a9efc51e45ccb1dc546777942f59c 100644 (file)
@@ -485,6 +485,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;
 };
 
 struct ath12k_debug {
index d1d469ae6d2b8d6db06e6df88e5aa8fc10872ab5..9f44285caa588a4e65d39039810546968f2c9213 100644 (file)
@@ -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,
@@ -74,8 +75,212 @@ 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;
+       struct htt_ext_stats_cfg_params cfg_params = { 0 };
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       init_completion(&stats_req->htt_stats_rcvd);
+
+       pdev_id = ath12k_mac_get_target_pdev_id(ar);
+       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->data_lock);
+               if (!stats_req->done) {
+                       stats_req->done = true;
+                       spin_unlock_bh(&ar->data_lock);
+                       ath12k_warn(ar->ab, "stats request timed out\n");
+                       return -ETIMEDOUT;
+               }
+               spin_unlock_bh(&ar->data_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_register(struct ath12k *ar)
 {
        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);
 }
index 8610db89289a59603d2f98aff2320a444ddf4a67..252c59f5eac895bfd10cf193bf83f73b9da89b21 100644 (file)
@@ -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_register(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
index c4cfa7cf7cb93aa9cd52a0bfbc16c262a5aa1bfc..d08c04343e9007f61c8e11a543ee3c8c011962bd 100644 (file)
@@ -1086,6 +1086,7 @@ ath12k_dp_tx_htt_h2t_ext_stats_req(struct ath12k *ar, u8 type,
        struct htt_ext_stats_cfg_cmd *cmd;
        int len = sizeof(*cmd);
        int ret;
+       u32 pdev_id;
 
        skb = ath12k_htc_alloc_skb(ab, len);
        if (!skb)
@@ -1097,7 +1098,8 @@ ath12k_dp_tx_htt_h2t_ext_stats_req(struct ath12k *ar, u8 type,
        memset(cmd, 0, sizeof(*cmd));
        cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_EXT_STATS_CFG;
 
-       cmd->hdr.pdev_mask = 1 << ar->pdev->pdev_id;
+       pdev_id = ath12k_mac_get_target_pdev_id(ar);
+       cmd->hdr.pdev_mask = 1 << pdev_id;
 
        cmd->hdr.stats_type = type;
        cmd->cfg_param0 = cpu_to_le32(cfg_params->cfg0);