* [PATCH 1/3] wifi: ath12k: Request vdev stats from firmware
2025-01-24 18:53 [PATCH ath-pending 0/3] Support to request pdev, vdev and beacon stats Ramya Gnanasekar
@ 2025-01-24 18:53 ` Ramya Gnanasekar
2025-01-25 5:23 ` Aditya Kumar Singh
2025-01-24 18:53 ` [PATCH 2/3] wifi: ath12k: Request beacon " Ramya Gnanasekar
` (2 subsequent siblings)
3 siblings, 1 reply; 8+ messages in thread
From: Ramya Gnanasekar @ 2025-01-24 18:53 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless, Ramya Gnanasekar
Add support to request and print vdev stats from firmware through WMI.
Sample output:
-------------
cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/fw_stats/vdev_stats
ath12k VDEV stats
=================
VDEV ID 0
VDEV MAC address 00:03:7f:6c:9c:1a
beacon snr 96
data snr 255
num rx frames 0
num rts fail 0
num rts success 0
num rx err 0
num rx discard 0
num tx not acked 0
num tx frames [00] 0
num tx frames [01] 0
num tx frames [02] 0
num tx frames [03] 2
num tx frames retries [00] 0
num tx frames retries [01] 0
num tx frames retries [02] 0
num tx frames retries [03] 0
num tx frames failures [00] 0
num tx frames failures [01] 0
num tx frames failures [02] 0
num tx frames failures [03] 0
tx rate history [00] 0x00000000
tx rate history [01] 0x00000000
tx rate history [02] 0x00000000
tx rate history [03] 0x00000000
tx rate history [04] 0x00000000
tx rate history [05] 0x00000000
tx rate history [06] 0x00000000
tx rate history [07] 0x00000000
tx rate history [08] 0x00000000
tx rate history [09] 0x00000000
beacon rssi history [00] 0
beacon rssi history [01] 0
beacon rssi history [02] 0
beacon rssi history [03] 0
beacon rssi history [04] 0
beacon rssi history [05] 0
beacon rssi history [06] 0
beacon rssi history [07] 0
beacon rssi history [08] 0
beacon rssi history [09] 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 <ramya.gnanasekar@oss.qualcomm.com>
---
drivers/net/wireless/ath/ath12k/core.h | 21 +++
drivers/net/wireless/ath/ath12k/debugfs.c | 197 +++++++++++++++++++++-
drivers/net/wireless/ath/ath12k/debugfs.h | 13 +-
drivers/net/wireless/ath/ath12k/wmi.c | 155 +++++++++++++++++
drivers/net/wireless/ath/ath12k/wmi.h | 10 ++
5 files changed, 394 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 81fd87def2da..fffdf17fcb1c 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -558,6 +558,7 @@ struct ath12k_fw_stats {
struct list_head pdevs;
struct list_head vdevs;
struct list_head bcn;
+ bool fw_stats_done;
};
struct ath12k_dbg_htt_stats {
@@ -729,6 +730,7 @@ struct ath12k {
struct completion mlo_setup_done;
u32 mlo_setup_status;
u8 ftm_msgref;
+ struct ath12k_fw_stats fw_stats;
};
struct ath12k_hw {
@@ -1079,6 +1081,25 @@ struct ath12k_pdev_map {
u8 pdev_idx;
};
+struct ath12k_fw_stats_vdev {
+ struct list_head list;
+
+ u32 vdev_id;
+ u32 beacon_snr;
+ u32 data_snr;
+ u32 num_tx_frames[WLAN_MAX_AC];
+ u32 num_rx_frames;
+ u32 num_tx_frames_retries[WLAN_MAX_AC];
+ u32 num_tx_frames_failures[WLAN_MAX_AC];
+ u32 num_rts_fail;
+ u32 num_rts_success;
+ u32 num_rx_err;
+ u32 num_rx_discard;
+ u32 num_tx_not_acked;
+ u32 tx_rate_history[MAX_TX_RATE_VALUES];
+ u32 beacon_rssi_history[MAX_TX_RATE_VALUES];
+};
+
int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab);
int ath12k_core_pre_init(struct ath12k_base *ab);
int ath12k_core_init(struct ath12k_base *ath12k);
diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c
index d4b32d1a431c..1ee9a3e00514 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs.c
+++ b/drivers/net/wireless/ath/ath12k/debugfs.c
@@ -1,10 +1,11 @@
// 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.
+ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "core.h"
+#include "debug.h"
#include "debugfs.h"
#include "debugfs_htt_stats.h"
@@ -68,6 +69,199 @@ void ath12k_debugfs_soc_destroy(struct ath12k_base *ab)
*/
}
+static void ath12k_fw_stats_vdevs_free(struct list_head *head)
+{
+ struct ath12k_fw_stats_vdev *i, *tmp;
+
+ list_for_each_entry_safe(i, tmp, head, list) {
+ list_del(&i->list);
+ kfree(i);
+ }
+}
+
+void ath12k_debugfs_fw_stats_reset(struct ath12k *ar)
+{
+ spin_lock_bh(&ar->data_lock);
+ ar->fw_stats.fw_stats_done = false;
+ ath12k_fw_stats_vdevs_free(&ar->fw_stats.vdevs);
+ spin_unlock_bh(&ar->data_lock);
+}
+
+static int ath12k_debugfs_fw_stats_request(struct ath12k *ar,
+ struct ath12k_fw_stats_req_params *param)
+{
+ struct ath12k_base *ab = ar->ab;
+ unsigned long timeout, time_left;
+ int ret;
+
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
+
+ /* FW stats can get split when exceeding the stats data buffer limit.
+ * In that case, since there is no end marking for the back-to-back
+ * received 'update stats' event, we keep a 3 seconds timeout in case,
+ * fw_stats_done is not marked yet
+ */
+ timeout = jiffies + msecs_to_jiffies(3 * 1000);
+
+ ath12k_debugfs_fw_stats_reset(ar);
+
+ reinit_completion(&ar->fw_stats_complete);
+
+ ret = ath12k_wmi_send_stats_request_cmd(ar, param->stats_id,
+ param->vdev_id, param->pdev_id);
+
+ if (ret) {
+ ath12k_warn(ab, "could not request fw stats (%d)\n",
+ ret);
+ return ret;
+ }
+
+ time_left = wait_for_completion_timeout(&ar->fw_stats_complete,
+ 1 * HZ);
+ /* If the wait timed out, return -ETIMEDOUT */
+ if (!time_left)
+ return -ETIMEDOUT;
+
+ /* Firmware sends WMI_UPDATE_STATS_EVENTID back-to-back
+ * when stats data buffer limit is reached. fw_stats_complete
+ * is completed once host receives first event from firmware, but
+ * still end might not be marked in the TLV.
+ * Below loop is to confirm that firmware completed sending all the event
+ * and fw_stats_done is marked true when end is marked in the TLV
+ */
+ for (;;) {
+ if (time_after(jiffies, timeout))
+ break;
+
+ spin_lock_bh(&ar->data_lock);
+ if (ar->fw_stats.fw_stats_done) {
+ spin_unlock_bh(&ar->data_lock);
+ break;
+ }
+ spin_unlock_bh(&ar->data_lock);
+ }
+ return 0;
+}
+
+void
+ath12k_debugfs_fw_stats_process(struct ath12k *ar,
+ struct ath12k_fw_stats *stats)
+{
+ struct ath12k_base *ab = ar->ab;
+ struct ath12k_pdev *pdev;
+ bool is_end;
+ static unsigned int num_vdev;
+ size_t total_vdevs_started = 0;
+ int i;
+
+ if (stats->stats_id == WMI_REQUEST_VDEV_STAT) {
+ if (list_empty(&stats->vdevs)) {
+ ath12k_warn(ab, "empty vdev stats");
+ return;
+ }
+ /* FW sends all the active VDEV stats irrespective of PDEV,
+ * hence limit until the count of all VDEVs started
+ */
+ rcu_read_lock();
+ for (i = 0; i < ab->num_radios; i++) {
+ pdev = rcu_dereference(ab->pdevs_active[i]);
+ if (pdev && pdev->ar)
+ total_vdevs_started += pdev->ar->num_started_vdevs;
+ }
+ rcu_read_unlock();
+
+ is_end = ((++num_vdev) == total_vdevs_started);
+
+ list_splice_tail_init(&stats->vdevs,
+ &ar->fw_stats.vdevs);
+
+ if (is_end) {
+ ar->fw_stats.fw_stats_done = true;
+ num_vdev = 0;
+ }
+ return;
+ }
+}
+
+static int ath12k_open_vdev_stats(struct inode *inode, struct file *file)
+{
+ struct ath12k *ar = inode->i_private;
+ struct ath12k_fw_stats_req_params param;
+ struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
+ int ret;
+
+ guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);
+
+ if (!ah)
+ return -ENETDOWN;
+
+ if (ah->state != ATH12K_HW_STATE_ON)
+ return -ENETDOWN;
+
+ void *buf __free(kfree) = kzalloc(ATH12K_FW_STATS_BUF_SIZE, GFP_ATOMIC);
+ if (!buf)
+ return -ENOMEM;
+
+ param.pdev_id = ath12k_mac_get_target_pdev_id(ar);
+ /* VDEV stats is always sent for all active VDEVs from FW */
+ param.vdev_id = 0;
+ param.stats_id = WMI_REQUEST_VDEV_STAT;
+
+ ret = ath12k_debugfs_fw_stats_request(ar, ¶m);
+ if (ret) {
+ ath12k_warn(ar->ab, "failed to request fw vdev stats: %d\n", ret);
+ return ret;
+ }
+
+ ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,
+ buf);
+
+ file->private_data = no_free_ptr(buf);
+
+ return 0;
+}
+
+static int ath12k_release_vdev_stats(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+
+ return 0;
+}
+
+static ssize_t ath12k_read_vdev_stats(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ const char *buf = file->private_data;
+ size_t len = strlen(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_vdev_stats = {
+ .open = ath12k_open_vdev_stats,
+ .release = ath12k_release_vdev_stats,
+ .read = ath12k_read_vdev_stats,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static
+void ath12k_debugfs_fw_stats_register(struct ath12k *ar)
+{
+ struct dentry *fwstats_dir = debugfs_create_dir("fw_stats",
+ ar->debug.debugfs_pdev);
+
+ /* all stats debugfs files created are under "fw_stats" directory
+ * created per PDEV
+ */
+ debugfs_create_file("vdev_stats", 0600, fwstats_dir, ar,
+ &fops_vdev_stats);
+
+ INIT_LIST_HEAD(&ar->fw_stats.vdevs);
+ init_completion(&ar->fw_stats_complete);
+}
+
void ath12k_debugfs_register(struct ath12k *ar)
{
struct ath12k_base *ab = ar->ab;
@@ -92,6 +286,7 @@ void ath12k_debugfs_register(struct ath12k *ar)
}
ath12k_debugfs_htt_stats_register(ar);
+ ath12k_debugfs_fw_stats_register(ar);
}
void ath12k_debugfs_unregister(struct ath12k *ar)
diff --git a/drivers/net/wireless/ath/ath12k/debugfs.h b/drivers/net/wireless/ath/ath12k/debugfs.h
index 8d64ba03aa9a..1c30745ee415 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs.h
+++ b/drivers/net/wireless/ath/ath12k/debugfs.h
@@ -1,7 +1,7 @@
/* 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.
+ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _ATH12K_DEBUGFS_H_
@@ -12,6 +12,9 @@ void ath12k_debugfs_soc_create(struct ath12k_base *ab);
void ath12k_debugfs_soc_destroy(struct ath12k_base *ab);
void ath12k_debugfs_register(struct ath12k *ar);
void ath12k_debugfs_unregister(struct ath12k *ar);
+void ath12k_debugfs_fw_stats_process(struct ath12k *ar,
+ struct ath12k_fw_stats *stats);
+void ath12k_debugfs_fw_stats_reset(struct ath12k *ar);
#else
static inline void ath12k_debugfs_soc_create(struct ath12k_base *ab)
{
@@ -29,6 +32,14 @@ static inline void ath12k_debugfs_unregister(struct ath12k *ar)
{
}
+static inline void ath12k_debugfs_fw_stats_process(struct ath12k *ar,
+ struct ath12k_fw_stats *stats)
+{
+}
+
+static inline void ath12k_debugfs_fw_stats_reset(struct ath12k *ar)
+{
+}
#endif /* CONFIG_ATH12K_DEBUGFS */
#endif /* _ATH12K_DEBUGFS_H_ */
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index ba6f5afd81e3..b91b4767515a 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -15,6 +15,7 @@
#include <linux/time.h>
#include <linux/of.h>
#include "core.h"
+#include "debugfs.h"
#include "debug.h"
#include "mac.h"
#include "hw.h"
@@ -6882,12 +6883,156 @@ static void ath12k_peer_assoc_conf_event(struct ath12k_base *ab, struct sk_buff
rcu_read_unlock();
}
+static void
+ath12k_wmi_fw_vdev_stats_dump(struct ath12k *ar,
+ struct ath12k_fw_stats *fw_stats,
+ char *buf, u32 *length)
+{
+ const struct ath12k_fw_stats_vdev *vdev;
+ u32 buf_len = ATH12K_FW_STATS_BUF_SIZE;
+ struct ath12k_link_vif *arvif;
+ u32 len = *length;
+ u8 *vif_macaddr;
+ int i;
+
+ len += scnprintf(buf + len, buf_len - len, "\n");
+ len += scnprintf(buf + len, buf_len - len, "%30s\n",
+ "ath12k VDEV stats");
+ len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
+ "=================");
+
+ list_for_each_entry(vdev, &fw_stats->vdevs, list) {
+ arvif = ath12k_mac_get_arvif(ar, vdev->vdev_id);
+ if (!arvif)
+ continue;
+ vif_macaddr = arvif->ahvif->vif->addr;
+
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "VDEV ID", vdev->vdev_id);
+ len += scnprintf(buf + len, buf_len - len, "%30s %pM\n",
+ "VDEV MAC address", vif_macaddr);
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "beacon snr", vdev->beacon_snr);
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "data snr", vdev->data_snr);
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "num rx frames", vdev->num_rx_frames);
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "num rts fail", vdev->num_rts_fail);
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "num rts success", vdev->num_rts_success);
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "num rx err", vdev->num_rx_err);
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "num rx discard", vdev->num_rx_discard);
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "num tx not acked", vdev->num_tx_not_acked);
+
+ for (i = 0 ; i < WLAN_MAX_AC; i++)
+ len += scnprintf(buf + len, buf_len - len,
+ "%25s [%02d] %u\n",
+ "num tx frames", i,
+ vdev->num_tx_frames[i]);
+
+ for (i = 0 ; i < WLAN_MAX_AC; i++)
+ len += scnprintf(buf + len, buf_len - len,
+ "%25s [%02d] %u\n",
+ "num tx frames retries", i,
+ vdev->num_tx_frames_retries[i]);
+
+ for (i = 0 ; i < WLAN_MAX_AC; i++)
+ len += scnprintf(buf + len, buf_len - len,
+ "%25s [%02d] %u\n",
+ "num tx frames failures", i,
+ vdev->num_tx_frames_failures[i]);
+
+ for (i = 0 ; i < MAX_TX_RATE_VALUES; i++)
+ len += scnprintf(buf + len, buf_len - len,
+ "%25s [%02d] 0x%08x\n",
+ "tx rate history", i,
+ vdev->tx_rate_history[i]);
+ for (i = 0 ; i < MAX_TX_RATE_VALUES; i++)
+ len += scnprintf(buf + len, buf_len - len,
+ "%25s [%02d] %u\n",
+ "beacon rssi history", i,
+ vdev->beacon_rssi_history[i]);
+
+ len += scnprintf(buf + len, buf_len - len, "\n");
+ *length = len;
+ }
+}
+
+void ath12k_wmi_fw_stats_dump(struct ath12k *ar,
+ struct ath12k_fw_stats *fw_stats,
+ u32 stats_id, char *buf)
+{
+ u32 len = 0;
+ u32 buf_len = ATH12K_FW_STATS_BUF_SIZE;
+
+ spin_lock_bh(&ar->data_lock);
+
+ switch (stats_id) {
+ case WMI_REQUEST_VDEV_STAT:
+ ath12k_wmi_fw_vdev_stats_dump(ar, fw_stats, buf, &len);
+ break;
+ default:
+ break;
+ }
+
+ spin_unlock_bh(&ar->data_lock);
+
+ if (len >= buf_len)
+ buf[len - 1] = 0;
+ else
+ buf[len] = 0;
+
+ ath12k_debugfs_fw_stats_reset(ar);
+}
+
+static void
+ath12k_wmi_pull_vdev_stats(const struct wmi_vdev_stats_params *src,
+ struct ath12k_fw_stats_vdev *dst)
+{
+ int i;
+
+ dst->vdev_id = le32_to_cpu(src->vdev_id);
+ dst->beacon_snr = le32_to_cpu(src->beacon_snr);
+ dst->data_snr = le32_to_cpu(src->data_snr);
+ dst->num_rx_frames = le32_to_cpu(src->num_rx_frames);
+ dst->num_rts_fail = le32_to_cpu(src->num_rts_fail);
+ dst->num_rts_success = le32_to_cpu(src->num_rts_success);
+ dst->num_rx_err = le32_to_cpu(src->num_rx_err);
+ dst->num_rx_discard = le32_to_cpu(src->num_rx_discard);
+ dst->num_tx_not_acked = le32_to_cpu(src->num_tx_not_acked);
+
+ for (i = 0; i < WLAN_MAX_AC; i++)
+ dst->num_tx_frames[i] =
+ le32_to_cpu(src->num_tx_frames[i]);
+
+ for (i = 0; i < WLAN_MAX_AC; i++)
+ dst->num_tx_frames_retries[i] =
+ le32_to_cpu(src->num_tx_frames_retries[i]);
+
+ for (i = 0; i < WLAN_MAX_AC; i++)
+ dst->num_tx_frames_failures[i] =
+ le32_to_cpu(src->num_tx_frames_failures[i]);
+
+ for (i = 0; i < MAX_TX_RATE_VALUES; i++)
+ dst->tx_rate_history[i] =
+ le32_to_cpu(src->tx_rate_history[i]);
+
+ for (i = 0; i < MAX_TX_RATE_VALUES; i++)
+ dst->beacon_rssi_history[i] =
+ le32_to_cpu(src->beacon_rssi_history[i]);
+}
+
static int ath12k_wmi_tlv_fw_stats_data_parse(struct ath12k_base *ab,
struct wmi_tlv_fw_stats_parse *parse,
const void *ptr,
u16 len)
{
const struct wmi_stats_event *ev = parse->ev;
+ struct ath12k_fw_stats stats = {0};
struct ath12k *ar;
struct ath12k_link_vif *arvif;
struct ieee80211_sta *sta;
@@ -6896,6 +7041,8 @@ static int ath12k_wmi_tlv_fw_stats_data_parse(struct ath12k_base *ab,
int i, ret = 0;
const void *data = ptr;
+ INIT_LIST_HEAD(&stats.vdevs);
+
if (!ev) {
ath12k_warn(ab, "failed to fetch update stats ev");
return -EPROTO;
@@ -6913,6 +7060,7 @@ static int ath12k_wmi_tlv_fw_stats_data_parse(struct ath12k_base *ab,
for (i = 0; i < le32_to_cpu(ev->num_vdev_stats); i++) {
const struct wmi_vdev_stats_params *src;
+ struct ath12k_fw_stats_vdev *dst;
src = data;
if (len < sizeof(*src)) {
@@ -6941,9 +7089,16 @@ static int ath12k_wmi_tlv_fw_stats_data_parse(struct ath12k_base *ab,
data += sizeof(*src);
len -= sizeof(*src);
+ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+ if (!dst)
+ continue;
+ ath12k_wmi_pull_vdev_stats(src, dst);
+ stats.stats_id = WMI_REQUEST_VDEV_STAT;
+ list_add_tail(&dst->list, &stats.vdevs);
}
complete(&ar->fw_stats_complete);
+ ath12k_debugfs_fw_stats_process(ar, &stats);
exit:
rcu_read_unlock();
return ret;
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index afa2832ba282..1c9500594f1d 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -25,6 +25,7 @@
struct ath12k_base;
struct ath12k;
struct ath12k_link_vif;
+struct ath12k_fw_stats;
/* There is no signed version of __le32, so for a temporary solution come
* up with our own version. The idea is from fs/ntfs/endian.h.
@@ -5694,6 +5695,12 @@ struct wmi_vdev_stats_params {
__le32 beacon_rssi_history[MAX_TX_RATE_VALUES];
} __packed;
+struct ath12k_fw_stats_req_params {
+ u32 stats_id;
+ u32 vdev_id;
+ u32 pdev_id;
+};
+
void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
struct ath12k_wmi_resource_config_arg *config);
void ath12k_wmi_init_wcn7850(struct ath12k_base *ab,
@@ -5875,5 +5882,8 @@ int ath12k_wmi_sta_keepalive(struct ath12k *ar,
int ath12k_wmi_mlo_setup(struct ath12k *ar, struct wmi_mlo_setup_arg *mlo_params);
int ath12k_wmi_mlo_ready(struct ath12k *ar);
int ath12k_wmi_mlo_teardown(struct ath12k *ar);
+void ath12k_wmi_fw_stats_dump(struct ath12k *ar,
+ struct ath12k_fw_stats *fw_stats, u32 stats_id,
+ char *buf);
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH 1/3] wifi: ath12k: Request vdev stats from firmware
2025-01-24 18:53 ` [PATCH 1/3] wifi: ath12k: Request vdev stats from firmware Ramya Gnanasekar
@ 2025-01-25 5:23 ` Aditya Kumar Singh
0 siblings, 0 replies; 8+ messages in thread
From: Aditya Kumar Singh @ 2025-01-25 5:23 UTC (permalink / raw)
To: Ramya Gnanasekar, ath12k; +Cc: linux-wireless
On 1/25/25 00:23, Ramya Gnanasekar wrote:
> Add support to request and print vdev stats from firmware through WMI.
>
> Sample output:
> -------------
> cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/fw_stats/vdev_stats
>
> ath12k VDEV stats
> =================
>
> VDEV ID 0
> VDEV MAC address 00:03:7f:6c:9c:1a
> beacon snr 96
> data snr 255
> num rx frames 0
> num rts fail 0
> num rts success 0
> num rx err 0
> num rx discard 0
> num tx not acked 0
> num tx frames [00] 0
> num tx frames [01] 0
> num tx frames [02] 0
> num tx frames [03] 2
> num tx frames retries [00] 0
> num tx frames retries [01] 0
> num tx frames retries [02] 0
> num tx frames retries [03] 0
> num tx frames failures [00] 0
> num tx frames failures [01] 0
> num tx frames failures [02] 0
> num tx frames failures [03] 0
> tx rate history [00] 0x00000000
> tx rate history [01] 0x00000000
> tx rate history [02] 0x00000000
> tx rate history [03] 0x00000000
> tx rate history [04] 0x00000000
> tx rate history [05] 0x00000000
> tx rate history [06] 0x00000000
> tx rate history [07] 0x00000000
> tx rate history [08] 0x00000000
> tx rate history [09] 0x00000000
> beacon rssi history [00] 0
> beacon rssi history [01] 0
> beacon rssi history [02] 0
> beacon rssi history [03] 0
> beacon rssi history [04] 0
> beacon rssi history [05] 0
> beacon rssi history [06] 0
> beacon rssi history [07] 0
> beacon rssi history [08] 0
> beacon rssi history [09] 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<ramya.gnanasekar@oss.qualcomm.com>
> ---
Reviewed-by: Aditya Kumar Singh <aditya.kumar.singh@oss.qualcomm.com>
--
Aditya
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/3] wifi: ath12k: Request beacon stats from firmware
2025-01-24 18:53 [PATCH ath-pending 0/3] Support to request pdev, vdev and beacon stats Ramya Gnanasekar
2025-01-24 18:53 ` [PATCH 1/3] wifi: ath12k: Request vdev stats from firmware Ramya Gnanasekar
@ 2025-01-24 18:53 ` Ramya Gnanasekar
2025-01-25 5:25 ` Aditya Kumar Singh
2025-01-24 18:53 ` [PATCH 3/3] wifi: ath12k: Request pdev " Ramya Gnanasekar
2025-01-26 18:45 ` [PATCH ath-pending 0/3] Support to request pdev, vdev and beacon stats Jeff Johnson
3 siblings, 1 reply; 8+ messages in thread
From: Ramya Gnanasekar @ 2025-01-24 18:53 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless, Ramya Gnanasekar
Add support to request and dump beacon statistics from firmware
Sample output:
-------------
cat /sys/kernel/debug/ath12k/pci-0000:06:00.0/mac0/fw_stats/beacon_stats
ath12k Beacon stats (1)
===================
VDEV ID 0
VDEV MAC address 00:03:7f:04:37:58
================
Num of beacon tx success 20
Num of beacon tx failures 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 <ramya.gnanasekar@oss.qualcomm.com>
---
drivers/net/wireless/ath/ath12k/core.h | 8 ++
drivers/net/wireless/ath/ath12k/debugfs.c | 106 +++++++++++++++++++++-
drivers/net/wireless/ath/ath12k/wmi.c | 71 +++++++++++++++
drivers/net/wireless/ath/ath12k/wmi.h | 7 ++
4 files changed, 191 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index fffdf17fcb1c..49780fe51b0b 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -1100,6 +1100,14 @@ struct ath12k_fw_stats_vdev {
u32 beacon_rssi_history[MAX_TX_RATE_VALUES];
};
+struct ath12k_fw_stats_bcn {
+ struct list_head list;
+
+ u32 vdev_id;
+ u32 tx_bcn_succ_cnt;
+ u32 tx_bcn_outage_cnt;
+};
+
int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab);
int ath12k_core_pre_init(struct ath12k_base *ab);
int ath12k_core_init(struct ath12k_base *ath12k);
diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c
index 1ee9a3e00514..3cb2bb9fa424 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs.c
+++ b/drivers/net/wireless/ath/ath12k/debugfs.c
@@ -69,6 +69,16 @@ void ath12k_debugfs_soc_destroy(struct ath12k_base *ab)
*/
}
+static void ath12k_fw_stats_bcn_free(struct list_head *head)
+{
+ struct ath12k_fw_stats_bcn *i, *tmp;
+
+ list_for_each_entry_safe(i, tmp, head, list) {
+ list_del(&i->list);
+ kfree(i);
+ }
+}
+
static void ath12k_fw_stats_vdevs_free(struct list_head *head)
{
struct ath12k_fw_stats_vdev *i, *tmp;
@@ -84,6 +94,7 @@ void ath12k_debugfs_fw_stats_reset(struct ath12k *ar)
spin_lock_bh(&ar->data_lock);
ar->fw_stats.fw_stats_done = false;
ath12k_fw_stats_vdevs_free(&ar->fw_stats.vdevs);
+ ath12k_fw_stats_bcn_free(&ar->fw_stats.bcn);
spin_unlock_bh(&ar->data_lock);
}
@@ -150,7 +161,7 @@ ath12k_debugfs_fw_stats_process(struct ath12k *ar,
struct ath12k_base *ab = ar->ab;
struct ath12k_pdev *pdev;
bool is_end;
- static unsigned int num_vdev;
+ static unsigned int num_vdev, num_bcn;
size_t total_vdevs_started = 0;
int i;
@@ -181,6 +192,24 @@ ath12k_debugfs_fw_stats_process(struct ath12k *ar,
}
return;
}
+ if (stats->stats_id == WMI_REQUEST_BCN_STAT) {
+ if (list_empty(&stats->bcn)) {
+ ath12k_warn(ab, "empty beacon stats");
+ return;
+ }
+ /* Mark end until we reached the count of all started VDEVs
+ * within the PDEV
+ */
+ is_end = ((++num_bcn) == ar->num_started_vdevs);
+
+ list_splice_tail_init(&stats->bcn,
+ &ar->fw_stats.bcn);
+
+ if (is_end) {
+ ar->fw_stats.fw_stats_done = true;
+ num_bcn = 0;
+ }
+ }
}
static int ath12k_open_vdev_stats(struct inode *inode, struct file *file)
@@ -246,6 +275,78 @@ static const struct file_operations fops_vdev_stats = {
.llseek = default_llseek,
};
+static int ath12k_open_bcn_stats(struct inode *inode, struct file *file)
+{
+ struct ath12k *ar = inode->i_private;
+ struct ath12k_link_vif *arvif;
+ struct ath12k_fw_stats_req_params param;
+ struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
+ int ret;
+
+ guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);
+
+ if (ah && ah->state != ATH12K_HW_STATE_ON)
+ return -ENETDOWN;
+
+ void *buf __free(kfree) = kzalloc(ATH12K_FW_STATS_BUF_SIZE, GFP_ATOMIC);
+ if (!buf)
+ return -ENOMEM;
+
+ param.pdev_id = ath12k_mac_get_target_pdev_id(ar);
+ param.stats_id = WMI_REQUEST_BCN_STAT;
+
+ /* loop all active VDEVs for bcn stats */
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ if (!arvif->is_up)
+ continue;
+
+ param.vdev_id = arvif->vdev_id;
+ ret = ath12k_debugfs_fw_stats_request(ar, ¶m);
+ if (ret) {
+ ath12k_warn(ar->ab, "failed to request fw bcn stats: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,
+ buf);
+ /* since beacon stats request is looped for all active VDEVs, saved fw
+ * stats is not freed for each request until done for all active VDEVs
+ */
+ spin_lock_bh(&ar->data_lock);
+ ath12k_fw_stats_bcn_free(&ar->fw_stats.bcn);
+ spin_unlock_bh(&ar->data_lock);
+
+ file->private_data = no_free_ptr(buf);
+
+ return 0;
+}
+
+static int ath12k_release_bcn_stats(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+
+ return 0;
+}
+
+static ssize_t ath12k_read_bcn_stats(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ const char *buf = file->private_data;
+ size_t len = strlen(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_bcn_stats = {
+ .open = ath12k_open_bcn_stats,
+ .release = ath12k_release_bcn_stats,
+ .read = ath12k_read_bcn_stats,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
static
void ath12k_debugfs_fw_stats_register(struct ath12k *ar)
{
@@ -257,8 +358,11 @@ void ath12k_debugfs_fw_stats_register(struct ath12k *ar)
*/
debugfs_create_file("vdev_stats", 0600, fwstats_dir, ar,
&fops_vdev_stats);
+ debugfs_create_file("beacon_stats", 0600, fwstats_dir, ar,
+ &fops_bcn_stats);
INIT_LIST_HEAD(&ar->fw_stats.vdevs);
+ INIT_LIST_HEAD(&ar->fw_stats.bcn);
init_completion(&ar->fw_stats_complete);
}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index b91b4767515a..f84102852438 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -6962,6 +6962,45 @@ ath12k_wmi_fw_vdev_stats_dump(struct ath12k *ar,
}
}
+static void
+ath12k_wmi_fw_bcn_stats_dump(struct ath12k *ar,
+ struct ath12k_fw_stats *fw_stats,
+ char *buf, u32 *length)
+{
+ const struct ath12k_fw_stats_bcn *bcn;
+ u32 buf_len = ATH12K_FW_STATS_BUF_SIZE;
+ struct ath12k_link_vif *arvif;
+ u32 len = *length;
+ size_t num_bcn;
+
+ num_bcn = list_count_nodes(&fw_stats->bcn);
+
+ len += scnprintf(buf + len, buf_len - len, "\n");
+ len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
+ "ath12k Beacon stats", num_bcn);
+ len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
+ "===================");
+
+ list_for_each_entry(bcn, &fw_stats->bcn, list) {
+ arvif = ath12k_mac_get_arvif(ar, bcn->vdev_id);
+ if (!arvif)
+ continue;
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "VDEV ID", bcn->vdev_id);
+ len += scnprintf(buf + len, buf_len - len, "%30s %pM\n",
+ "VDEV MAC address", arvif->ahvif->vif->addr);
+ len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
+ "================");
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "Num of beacon tx success", bcn->tx_bcn_succ_cnt);
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "Num of beacon tx failures", bcn->tx_bcn_outage_cnt);
+
+ len += scnprintf(buf + len, buf_len - len, "\n");
+ *length = len;
+ }
+}
+
void ath12k_wmi_fw_stats_dump(struct ath12k *ar,
struct ath12k_fw_stats *fw_stats,
u32 stats_id, char *buf)
@@ -6975,6 +7014,9 @@ void ath12k_wmi_fw_stats_dump(struct ath12k *ar,
case WMI_REQUEST_VDEV_STAT:
ath12k_wmi_fw_vdev_stats_dump(ar, fw_stats, buf, &len);
break;
+ case WMI_REQUEST_BCN_STAT:
+ ath12k_wmi_fw_bcn_stats_dump(ar, fw_stats, buf, &len);
+ break;
default:
break;
}
@@ -7026,6 +7068,15 @@ ath12k_wmi_pull_vdev_stats(const struct wmi_vdev_stats_params *src,
le32_to_cpu(src->beacon_rssi_history[i]);
}
+static void
+ath12k_wmi_pull_bcn_stats(const struct ath12k_wmi_bcn_stats_params *src,
+ struct ath12k_fw_stats_bcn *dst)
+{
+ dst->vdev_id = le32_to_cpu(src->vdev_id);
+ dst->tx_bcn_succ_cnt = le32_to_cpu(src->tx_bcn_succ_cnt);
+ dst->tx_bcn_outage_cnt = le32_to_cpu(src->tx_bcn_outage_cnt);
+}
+
static int ath12k_wmi_tlv_fw_stats_data_parse(struct ath12k_base *ab,
struct wmi_tlv_fw_stats_parse *parse,
const void *ptr,
@@ -7042,6 +7093,7 @@ static int ath12k_wmi_tlv_fw_stats_data_parse(struct ath12k_base *ab,
const void *data = ptr;
INIT_LIST_HEAD(&stats.vdevs);
+ INIT_LIST_HEAD(&stats.bcn);
if (!ev) {
ath12k_warn(ab, "failed to fetch update stats ev");
@@ -7096,6 +7148,25 @@ static int ath12k_wmi_tlv_fw_stats_data_parse(struct ath12k_base *ab,
stats.stats_id = WMI_REQUEST_VDEV_STAT;
list_add_tail(&dst->list, &stats.vdevs);
}
+ for (i = 0; i < le32_to_cpu(ev->num_bcn_stats); i++) {
+ const struct ath12k_wmi_bcn_stats_params *src;
+ struct ath12k_fw_stats_bcn *dst;
+
+ src = data;
+ if (len < sizeof(*src)) {
+ ret = -EPROTO;
+ goto exit;
+ }
+
+ data += sizeof(*src);
+ len -= sizeof(*src);
+ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+ if (!dst)
+ continue;
+ ath12k_wmi_pull_bcn_stats(src, dst);
+ stats.stats_id = WMI_REQUEST_BCN_STAT;
+ list_add_tail(&dst->list, &stats.bcn);
+ }
complete(&ar->fw_stats_complete);
ath12k_debugfs_fw_stats_process(ar, &stats);
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 1c9500594f1d..ec2664c62e53 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -5665,6 +5665,7 @@ struct wmi_stats_event {
enum wmi_stats_id {
WMI_REQUEST_VDEV_STAT = BIT(3),
+ WMI_REQUEST_BCN_STAT = BIT(11),
};
struct wmi_request_stats_cmd {
@@ -5695,6 +5696,12 @@ struct wmi_vdev_stats_params {
__le32 beacon_rssi_history[MAX_TX_RATE_VALUES];
} __packed;
+struct ath12k_wmi_bcn_stats_params {
+ __le32 vdev_id;
+ __le32 tx_bcn_succ_cnt;
+ __le32 tx_bcn_outage_cnt;
+} __packed;
+
struct ath12k_fw_stats_req_params {
u32 stats_id;
u32 vdev_id;
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH 2/3] wifi: ath12k: Request beacon stats from firmware
2025-01-24 18:53 ` [PATCH 2/3] wifi: ath12k: Request beacon " Ramya Gnanasekar
@ 2025-01-25 5:25 ` Aditya Kumar Singh
0 siblings, 0 replies; 8+ messages in thread
From: Aditya Kumar Singh @ 2025-01-25 5:25 UTC (permalink / raw)
To: Ramya Gnanasekar, ath12k; +Cc: linux-wireless
On 1/25/25 00:23, Ramya Gnanasekar wrote:
> Add support to request and dump beacon statistics from firmware
>
> Sample output:
> -------------
> cat /sys/kernel/debug/ath12k/pci-0000:06:00.0/mac0/fw_stats/beacon_stats
>
> ath12k Beacon stats (1)
> ===================
>
> VDEV ID 0
> VDEV MAC address 00:03:7f:04:37:58
> ================
>
> Num of beacon tx success 20
> Num of beacon tx failures 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<ramya.gnanasekar@oss.qualcomm.com>
> ---
Reviewed-by: Aditya Kumar Singh <aditya.kumar.singh@oss.qualcomm.com>
--
Aditya
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 3/3] wifi: ath12k: Request pdev stats from firmware
2025-01-24 18:53 [PATCH ath-pending 0/3] Support to request pdev, vdev and beacon stats Ramya Gnanasekar
2025-01-24 18:53 ` [PATCH 1/3] wifi: ath12k: Request vdev stats from firmware Ramya Gnanasekar
2025-01-24 18:53 ` [PATCH 2/3] wifi: ath12k: Request beacon " Ramya Gnanasekar
@ 2025-01-24 18:53 ` Ramya Gnanasekar
2025-01-25 5:27 ` Aditya Kumar Singh
2025-01-26 18:45 ` [PATCH ath-pending 0/3] Support to request pdev, vdev and beacon stats Jeff Johnson
3 siblings, 1 reply; 8+ messages in thread
From: Ramya Gnanasekar @ 2025-01-24 18:53 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless, Ramya Gnanasekar
Add support to request pdev stats from firmware through WMI and
print the information
Sample Output:
-------------
cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/fw_stats/pdev_stats
ath12k PDEV stats
=================
Channel noise floor -85
Channel TX power 126
TX frame count 0
RX frame count 8637
RX clear count 37424
Cycle count 4372024
PHY error count 0
soc drop count 0
ath12k PDEV TX stats
====================
HTT cookies queued 0
HTT cookies disp. 0
MSDU queued 0
MPDU queued 0
MSDUs dropped 0
Local enqued 0
Local freed 0
HW queued 0
PPDUs reaped 0
Num underruns 0
PPDUs cleaned 0
MPDUs requeued 0
Excessive retries 0
HW rate 0
Sched self triggers 0
Dropped due to SW retries 0
Illegal rate phy errors 0
PDEV continuous xretry 0
TX timeout 9
PDEV resets 0
Stateless TIDs alloc failures 0
PHY underrun 0
MPDU is more than txop limit 0
ath12k PDEV RX stats
====================
Mid PPDU route change 0
Tot. number of statuses 0
Extra frags on rings 0 0
Extra frags on rings 1 0
Extra frags on rings 2 0
Extra frags on rings 3 0
MSDUs delivered to HTT 0
MPDUs delivered to HTT 0
MSDUs delivered to stack 0
MPDUs delivered to stack 0
Oversized AMSUs 0
PHY errors 0
PHY errors drops 0
MPDU errors (FCS, MIC, ENC) 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 <ramya.gnanasekar@oss.qualcomm.com>
---
drivers/net/wireless/ath/ath12k/core.h | 60 +++++
drivers/net/wireless/ath/ath12k/debugfs.c | 79 +++++++
drivers/net/wireless/ath/ath12k/wmi.c | 256 ++++++++++++++++++++++
drivers/net/wireless/ath/ath12k/wmi.h | 60 +++++
4 files changed, 455 insertions(+)
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 49780fe51b0b..91e862a6d020 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -1108,6 +1108,66 @@ struct ath12k_fw_stats_bcn {
u32 tx_bcn_outage_cnt;
};
+struct ath12k_fw_stats_pdev {
+ struct list_head list;
+
+ /* PDEV stats */
+ s32 ch_noise_floor;
+ u32 tx_frame_count;
+ u32 rx_frame_count;
+ u32 rx_clear_count;
+ u32 cycle_count;
+ u32 phy_err_count;
+ u32 chan_tx_power;
+ u32 ack_rx_bad;
+ u32 rts_bad;
+ u32 rts_good;
+ u32 fcs_bad;
+ u32 no_beacons;
+ u32 mib_int_count;
+
+ /* PDEV TX stats */
+ s32 comp_queued;
+ s32 comp_delivered;
+ s32 msdu_enqued;
+ s32 mpdu_enqued;
+ s32 wmm_drop;
+ s32 local_enqued;
+ s32 local_freed;
+ s32 hw_queued;
+ s32 hw_reaped;
+ s32 underrun;
+ s32 tx_abort;
+ s32 mpdus_requed;
+ u32 tx_ko;
+ u32 data_rc;
+ u32 self_triggers;
+ u32 sw_retry_failure;
+ u32 illgl_rate_phy_err;
+ u32 pdev_cont_xretry;
+ u32 pdev_tx_timeout;
+ u32 pdev_resets;
+ u32 stateless_tid_alloc_failure;
+ u32 phy_underrun;
+ u32 txop_ovf;
+
+ /* PDEV RX stats */
+ s32 mid_ppdu_route_change;
+ s32 status_rcvd;
+ s32 r0_frags;
+ s32 r1_frags;
+ s32 r2_frags;
+ s32 r3_frags;
+ s32 htt_msdus;
+ s32 htt_mpdus;
+ s32 loc_msdus;
+ s32 loc_mpdus;
+ s32 oversize_amsdu;
+ s32 phy_errs;
+ s32 phy_err_drop;
+ s32 mpdu_errs;
+};
+
int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab);
int ath12k_core_pre_init(struct ath12k_base *ab);
int ath12k_core_init(struct ath12k_base *ath12k);
diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c
index 3cb2bb9fa424..6d6708486d14 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs.c
+++ b/drivers/net/wireless/ath/ath12k/debugfs.c
@@ -69,6 +69,16 @@ void ath12k_debugfs_soc_destroy(struct ath12k_base *ab)
*/
}
+static void ath12k_fw_stats_pdevs_free(struct list_head *head)
+{
+ struct ath12k_fw_stats_pdev *i, *tmp;
+
+ list_for_each_entry_safe(i, tmp, head, list) {
+ list_del(&i->list);
+ kfree(i);
+ }
+}
+
static void ath12k_fw_stats_bcn_free(struct list_head *head)
{
struct ath12k_fw_stats_bcn *i, *tmp;
@@ -95,6 +105,7 @@ void ath12k_debugfs_fw_stats_reset(struct ath12k *ar)
ar->fw_stats.fw_stats_done = false;
ath12k_fw_stats_vdevs_free(&ar->fw_stats.vdevs);
ath12k_fw_stats_bcn_free(&ar->fw_stats.bcn);
+ ath12k_fw_stats_pdevs_free(&ar->fw_stats.pdevs);
spin_unlock_bh(&ar->data_lock);
}
@@ -210,6 +221,10 @@ ath12k_debugfs_fw_stats_process(struct ath12k *ar,
num_bcn = 0;
}
}
+ if (stats->stats_id == WMI_REQUEST_PDEV_STAT) {
+ list_splice_tail_init(&stats->pdevs, &ar->fw_stats.pdevs);
+ ar->fw_stats.fw_stats_done = true;
+ }
}
static int ath12k_open_vdev_stats(struct inode *inode, struct file *file)
@@ -347,6 +362,66 @@ static const struct file_operations fops_bcn_stats = {
.llseek = default_llseek,
};
+static int ath12k_open_pdev_stats(struct inode *inode, struct file *file)
+{
+ struct ath12k *ar = inode->i_private;
+ struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
+ struct ath12k_base *ab = ar->ab;
+ struct ath12k_fw_stats_req_params param;
+ int ret;
+
+ guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);
+
+ if (ah && ah->state != ATH12K_HW_STATE_ON)
+ return -ENETDOWN;
+
+ void *buf __free(kfree) = kzalloc(ATH12K_FW_STATS_BUF_SIZE, GFP_ATOMIC);
+ if (!buf)
+ return -ENOMEM;
+
+ param.pdev_id = ath12k_mac_get_target_pdev_id(ar);
+ param.vdev_id = 0;
+ param.stats_id = WMI_REQUEST_PDEV_STAT;
+
+ ret = ath12k_debugfs_fw_stats_request(ar, ¶m);
+ if (ret) {
+ ath12k_warn(ab, "failed to request fw pdev stats: %d\n", ret);
+ return ret;
+ }
+
+ ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,
+ buf);
+
+ file->private_data = no_free_ptr(buf);
+
+ return 0;
+}
+
+static int ath12k_release_pdev_stats(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+
+ return 0;
+}
+
+static ssize_t ath12k_read_pdev_stats(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ const char *buf = file->private_data;
+ size_t len = strlen(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_pdev_stats = {
+ .open = ath12k_open_pdev_stats,
+ .release = ath12k_release_pdev_stats,
+ .read = ath12k_read_pdev_stats,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
static
void ath12k_debugfs_fw_stats_register(struct ath12k *ar)
{
@@ -360,9 +435,13 @@ void ath12k_debugfs_fw_stats_register(struct ath12k *ar)
&fops_vdev_stats);
debugfs_create_file("beacon_stats", 0600, fwstats_dir, ar,
&fops_bcn_stats);
+ debugfs_create_file("pdev_stats", 0600, fwstats_dir, ar,
+ &fops_pdev_stats);
INIT_LIST_HEAD(&ar->fw_stats.vdevs);
INIT_LIST_HEAD(&ar->fw_stats.bcn);
+ INIT_LIST_HEAD(&ar->fw_stats.pdevs);
+
init_completion(&ar->fw_stats_complete);
}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index f84102852438..61aa5f509338 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -7001,6 +7001,170 @@ ath12k_wmi_fw_bcn_stats_dump(struct ath12k *ar,
}
}
+static void
+ath12k_wmi_fw_pdev_base_stats_dump(const struct ath12k_fw_stats_pdev *pdev,
+ char *buf, u32 *length, u64 fw_soc_drop_cnt)
+{
+ u32 len = *length;
+ u32 buf_len = ATH12K_FW_STATS_BUF_SIZE;
+
+ len = scnprintf(buf + len, buf_len - len, "\n");
+ len += scnprintf(buf + len, buf_len - len, "%30s\n",
+ "ath12k PDEV stats");
+ len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
+ "=================");
+
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "Channel noise floor", pdev->ch_noise_floor);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+ "Channel TX power", pdev->chan_tx_power);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+ "TX frame count", pdev->tx_frame_count);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+ "RX frame count", pdev->rx_frame_count);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+ "RX clear count", pdev->rx_clear_count);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+ "Cycle count", pdev->cycle_count);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+ "PHY error count", pdev->phy_err_count);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10llu\n",
+ "soc drop count", fw_soc_drop_cnt);
+
+ *length = len;
+}
+
+static void
+ath12k_wmi_fw_pdev_tx_stats_dump(const struct ath12k_fw_stats_pdev *pdev,
+ char *buf, u32 *length)
+{
+ u32 len = *length;
+ u32 buf_len = ATH12K_FW_STATS_BUF_SIZE;
+
+ len += scnprintf(buf + len, buf_len - len, "\n%30s\n",
+ "ath12k PDEV TX stats");
+ len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
+ "====================");
+
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "HTT cookies queued", pdev->comp_queued);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "HTT cookies disp.", pdev->comp_delivered);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "MSDU queued", pdev->msdu_enqued);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "MPDU queued", pdev->mpdu_enqued);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "MSDUs dropped", pdev->wmm_drop);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "Local enqued", pdev->local_enqued);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "Local freed", pdev->local_freed);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "HW queued", pdev->hw_queued);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "PPDUs reaped", pdev->hw_reaped);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "Num underruns", pdev->underrun);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "PPDUs cleaned", pdev->tx_abort);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "MPDUs requeued", pdev->mpdus_requed);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+ "Excessive retries", pdev->tx_ko);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+ "HW rate", pdev->data_rc);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+ "Sched self triggers", pdev->self_triggers);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+ "Dropped due to SW retries",
+ pdev->sw_retry_failure);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+ "Illegal rate phy errors",
+ pdev->illgl_rate_phy_err);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+ "PDEV continuous xretry", pdev->pdev_cont_xretry);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+ "TX timeout", pdev->pdev_tx_timeout);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+ "PDEV resets", pdev->pdev_resets);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+ "Stateless TIDs alloc failures",
+ pdev->stateless_tid_alloc_failure);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+ "PHY underrun", pdev->phy_underrun);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+ "MPDU is more than txop limit", pdev->txop_ovf);
+ *length = len;
+}
+
+static void
+ath12k_wmi_fw_pdev_rx_stats_dump(const struct ath12k_fw_stats_pdev *pdev,
+ char *buf, u32 *length)
+{
+ u32 len = *length;
+ u32 buf_len = ATH12K_FW_STATS_BUF_SIZE;
+
+ len += scnprintf(buf + len, buf_len - len, "\n%30s\n",
+ "ath12k PDEV RX stats");
+ len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
+ "====================");
+
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "Mid PPDU route change",
+ pdev->mid_ppdu_route_change);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "Tot. number of statuses", pdev->status_rcvd);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "Extra frags on rings 0", pdev->r0_frags);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "Extra frags on rings 1", pdev->r1_frags);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "Extra frags on rings 2", pdev->r2_frags);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "Extra frags on rings 3", pdev->r3_frags);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "MSDUs delivered to HTT", pdev->htt_msdus);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "MPDUs delivered to HTT", pdev->htt_mpdus);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "MSDUs delivered to stack", pdev->loc_msdus);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "MPDUs delivered to stack", pdev->loc_mpdus);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "Oversized AMSUs", pdev->oversize_amsdu);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "PHY errors", pdev->phy_errs);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "PHY errors drops", pdev->phy_err_drop);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "MPDU errors (FCS, MIC, ENC)", pdev->mpdu_errs);
+ *length = len;
+}
+
+static void
+ath12k_wmi_fw_pdev_stats_dump(struct ath12k *ar,
+ struct ath12k_fw_stats *fw_stats,
+ char *buf, u32 *length)
+{
+ const struct ath12k_fw_stats_pdev *pdev;
+ u32 len = *length;
+
+ pdev = list_first_entry_or_null(&fw_stats->pdevs,
+ struct ath12k_fw_stats_pdev, list);
+ if (!pdev) {
+ ath12k_warn(ar->ab, "failed to get pdev stats\n");
+ return;
+ }
+
+ ath12k_wmi_fw_pdev_base_stats_dump(pdev, buf, &len,
+ ar->ab->fw_soc_drop_count);
+ ath12k_wmi_fw_pdev_tx_stats_dump(pdev, buf, &len);
+ ath12k_wmi_fw_pdev_rx_stats_dump(pdev, buf, &len);
+
+ *length = len;
+}
+
void ath12k_wmi_fw_stats_dump(struct ath12k *ar,
struct ath12k_fw_stats *fw_stats,
u32 stats_id, char *buf)
@@ -7017,6 +7181,9 @@ void ath12k_wmi_fw_stats_dump(struct ath12k *ar,
case WMI_REQUEST_BCN_STAT:
ath12k_wmi_fw_bcn_stats_dump(ar, fw_stats, buf, &len);
break;
+ case WMI_REQUEST_PDEV_STAT:
+ ath12k_wmi_fw_pdev_stats_dump(ar, fw_stats, buf, &len);
+ break;
default:
break;
}
@@ -7077,6 +7244,70 @@ ath12k_wmi_pull_bcn_stats(const struct ath12k_wmi_bcn_stats_params *src,
dst->tx_bcn_outage_cnt = le32_to_cpu(src->tx_bcn_outage_cnt);
}
+static void
+ath12k_wmi_pull_pdev_stats_base(const struct ath12k_wmi_pdev_base_stats_params *src,
+ struct ath12k_fw_stats_pdev *dst)
+{
+ dst->ch_noise_floor = a_sle32_to_cpu(src->chan_nf);
+ dst->tx_frame_count = __le32_to_cpu(src->tx_frame_count);
+ dst->rx_frame_count = __le32_to_cpu(src->rx_frame_count);
+ dst->rx_clear_count = __le32_to_cpu(src->rx_clear_count);
+ dst->cycle_count = __le32_to_cpu(src->cycle_count);
+ dst->phy_err_count = __le32_to_cpu(src->phy_err_count);
+ dst->chan_tx_power = __le32_to_cpu(src->chan_tx_pwr);
+}
+
+static void
+ath12k_wmi_pull_pdev_stats_tx(const struct ath12k_wmi_pdev_tx_stats_params *src,
+ struct ath12k_fw_stats_pdev *dst)
+{
+ dst->comp_queued = a_sle32_to_cpu(src->comp_queued);
+ dst->comp_delivered = a_sle32_to_cpu(src->comp_delivered);
+ dst->msdu_enqued = a_sle32_to_cpu(src->msdu_enqued);
+ dst->mpdu_enqued = a_sle32_to_cpu(src->mpdu_enqued);
+ dst->wmm_drop = a_sle32_to_cpu(src->wmm_drop);
+ dst->local_enqued = a_sle32_to_cpu(src->local_enqued);
+ dst->local_freed = a_sle32_to_cpu(src->local_freed);
+ dst->hw_queued = a_sle32_to_cpu(src->hw_queued);
+ dst->hw_reaped = a_sle32_to_cpu(src->hw_reaped);
+ dst->underrun = a_sle32_to_cpu(src->underrun);
+ dst->tx_abort = a_sle32_to_cpu(src->tx_abort);
+ dst->mpdus_requed = a_sle32_to_cpu(src->mpdus_requed);
+ dst->tx_ko = __le32_to_cpu(src->tx_ko);
+ dst->data_rc = __le32_to_cpu(src->data_rc);
+ dst->self_triggers = __le32_to_cpu(src->self_triggers);
+ dst->sw_retry_failure = __le32_to_cpu(src->sw_retry_failure);
+ dst->illgl_rate_phy_err = __le32_to_cpu(src->illgl_rate_phy_err);
+ dst->pdev_cont_xretry = __le32_to_cpu(src->pdev_cont_xretry);
+ dst->pdev_tx_timeout = __le32_to_cpu(src->pdev_tx_timeout);
+ dst->pdev_resets = __le32_to_cpu(src->pdev_resets);
+ dst->stateless_tid_alloc_failure =
+ __le32_to_cpu(src->stateless_tid_alloc_failure);
+ dst->phy_underrun = __le32_to_cpu(src->phy_underrun);
+ dst->txop_ovf = __le32_to_cpu(src->txop_ovf);
+}
+
+static void
+ath12k_wmi_pull_pdev_stats_rx(const struct ath12k_wmi_pdev_rx_stats_params *src,
+ struct ath12k_fw_stats_pdev *dst)
+{
+ dst->mid_ppdu_route_change =
+ a_sle32_to_cpu(src->mid_ppdu_route_change);
+ dst->status_rcvd = a_sle32_to_cpu(src->status_rcvd);
+ dst->r0_frags = a_sle32_to_cpu(src->r0_frags);
+ dst->r1_frags = a_sle32_to_cpu(src->r1_frags);
+ dst->r2_frags = a_sle32_to_cpu(src->r2_frags);
+ dst->r3_frags = a_sle32_to_cpu(src->r3_frags);
+ dst->htt_msdus = a_sle32_to_cpu(src->htt_msdus);
+ dst->htt_mpdus = a_sle32_to_cpu(src->htt_mpdus);
+ dst->loc_msdus = a_sle32_to_cpu(src->loc_msdus);
+ dst->loc_mpdus = a_sle32_to_cpu(src->loc_mpdus);
+ dst->oversize_amsdu = a_sle32_to_cpu(src->oversize_amsdu);
+ dst->phy_errs = a_sle32_to_cpu(src->phy_errs);
+ dst->phy_err_drop = a_sle32_to_cpu(src->phy_err_drop);
+ dst->mpdu_errs = a_sle32_to_cpu(src->mpdu_errs);
+}
+
static int ath12k_wmi_tlv_fw_stats_data_parse(struct ath12k_base *ab,
struct wmi_tlv_fw_stats_parse *parse,
const void *ptr,
@@ -7094,6 +7325,7 @@ static int ath12k_wmi_tlv_fw_stats_data_parse(struct ath12k_base *ab,
INIT_LIST_HEAD(&stats.vdevs);
INIT_LIST_HEAD(&stats.bcn);
+ INIT_LIST_HEAD(&stats.pdevs);
if (!ev) {
ath12k_warn(ab, "failed to fetch update stats ev");
@@ -7167,6 +7399,30 @@ static int ath12k_wmi_tlv_fw_stats_data_parse(struct ath12k_base *ab,
stats.stats_id = WMI_REQUEST_BCN_STAT;
list_add_tail(&dst->list, &stats.bcn);
}
+ for (i = 0; i < le32_to_cpu(ev->num_pdev_stats); i++) {
+ const struct ath12k_wmi_pdev_stats_params *src;
+ struct ath12k_fw_stats_pdev *dst;
+
+ src = data;
+ if (len < sizeof(*src)) {
+ ret = -EPROTO;
+ goto exit;
+ }
+
+ stats.stats_id = WMI_REQUEST_PDEV_STAT;
+
+ data += sizeof(*src);
+ len -= sizeof(*src);
+
+ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+ if (!dst)
+ continue;
+
+ ath12k_wmi_pull_pdev_stats_base(&src->base, dst);
+ ath12k_wmi_pull_pdev_stats_tx(&src->tx, dst);
+ ath12k_wmi_pull_pdev_stats_rx(&src->rx, dst);
+ list_add_tail(&dst->list, &stats.pdevs);
+ }
complete(&ar->fw_stats_complete);
ath12k_debugfs_fw_stats_process(ar, &stats);
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index ec2664c62e53..2934d9589007 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -5664,6 +5664,7 @@ struct wmi_stats_event {
} __packed;
enum wmi_stats_id {
+ WMI_REQUEST_PDEV_STAT = BIT(2),
WMI_REQUEST_VDEV_STAT = BIT(3),
WMI_REQUEST_BCN_STAT = BIT(11),
};
@@ -5702,6 +5703,65 @@ struct ath12k_wmi_bcn_stats_params {
__le32 tx_bcn_outage_cnt;
} __packed;
+struct ath12k_wmi_pdev_base_stats_params {
+ a_sle32 chan_nf;
+ __le32 tx_frame_count; /* Cycles spent transmitting frames */
+ __le32 rx_frame_count; /* Cycles spent receiving frames */
+ __le32 rx_clear_count; /* Total channel busy time, evidently */
+ __le32 cycle_count; /* Total on-channel time */
+ __le32 phy_err_count;
+ __le32 chan_tx_pwr;
+} __packed;
+
+struct ath12k_wmi_pdev_tx_stats_params {
+ a_sle32 comp_queued;
+ a_sle32 comp_delivered;
+ a_sle32 msdu_enqued;
+ a_sle32 mpdu_enqued;
+ a_sle32 wmm_drop;
+ a_sle32 local_enqued;
+ a_sle32 local_freed;
+ a_sle32 hw_queued;
+ a_sle32 hw_reaped;
+ a_sle32 underrun;
+ a_sle32 tx_abort;
+ a_sle32 mpdus_requed;
+ __le32 tx_ko;
+ __le32 data_rc;
+ __le32 self_triggers;
+ __le32 sw_retry_failure;
+ __le32 illgl_rate_phy_err;
+ __le32 pdev_cont_xretry;
+ __le32 pdev_tx_timeout;
+ __le32 pdev_resets;
+ __le32 stateless_tid_alloc_failure;
+ __le32 phy_underrun;
+ __le32 txop_ovf;
+} __packed;
+
+struct ath12k_wmi_pdev_rx_stats_params {
+ a_sle32 mid_ppdu_route_change;
+ a_sle32 status_rcvd;
+ a_sle32 r0_frags;
+ a_sle32 r1_frags;
+ a_sle32 r2_frags;
+ a_sle32 r3_frags;
+ a_sle32 htt_msdus;
+ a_sle32 htt_mpdus;
+ a_sle32 loc_msdus;
+ a_sle32 loc_mpdus;
+ a_sle32 oversize_amsdu;
+ a_sle32 phy_errs;
+ a_sle32 phy_err_drop;
+ a_sle32 mpdu_errs;
+} __packed;
+
+struct ath12k_wmi_pdev_stats_params {
+ struct ath12k_wmi_pdev_base_stats_params base;
+ struct ath12k_wmi_pdev_tx_stats_params tx;
+ struct ath12k_wmi_pdev_rx_stats_params rx;
+} __packed;
+
struct ath12k_fw_stats_req_params {
u32 stats_id;
u32 vdev_id;
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH 3/3] wifi: ath12k: Request pdev stats from firmware
2025-01-24 18:53 ` [PATCH 3/3] wifi: ath12k: Request pdev " Ramya Gnanasekar
@ 2025-01-25 5:27 ` Aditya Kumar Singh
0 siblings, 0 replies; 8+ messages in thread
From: Aditya Kumar Singh @ 2025-01-25 5:27 UTC (permalink / raw)
To: Ramya Gnanasekar, ath12k; +Cc: linux-wireless
On 1/25/25 00:23, Ramya Gnanasekar wrote:
> Add support to request pdev stats from firmware through WMI and
> print the information
>
> Sample Output:
> -------------
> cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/fw_stats/pdev_stats
>
> ath12k PDEV stats
> =================
>
> Channel noise floor -85
> Channel TX power 126
> TX frame count 0
> RX frame count 8637
> RX clear count 37424
> Cycle count 4372024
> PHY error count 0
> soc drop count 0
>
> ath12k PDEV TX stats
> ====================
>
> HTT cookies queued 0
> HTT cookies disp. 0
> MSDU queued 0
> MPDU queued 0
> MSDUs dropped 0
> Local enqued 0
> Local freed 0
> HW queued 0
> PPDUs reaped 0
> Num underruns 0
> PPDUs cleaned 0
> MPDUs requeued 0
> Excessive retries 0
> HW rate 0
> Sched self triggers 0
> Dropped due to SW retries 0
> Illegal rate phy errors 0
> PDEV continuous xretry 0
> TX timeout 9
> PDEV resets 0
> Stateless TIDs alloc failures 0
> PHY underrun 0
> MPDU is more than txop limit 0
>
> ath12k PDEV RX stats
> ====================
>
> Mid PPDU route change 0
> Tot. number of statuses 0
> Extra frags on rings 0 0
> Extra frags on rings 1 0
> Extra frags on rings 2 0
> Extra frags on rings 3 0
> MSDUs delivered to HTT 0
> MPDUs delivered to HTT 0
> MSDUs delivered to stack 0
> MPDUs delivered to stack 0
> Oversized AMSUs 0
> PHY errors 0
> PHY errors drops 0
> MPDU errors (FCS, MIC, ENC) 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<ramya.gnanasekar@oss.qualcomm.com>
> ---
Reviewed-by: Aditya Kumar Singh <aditya.kumar.singh@oss.qualcomm.com>
--
Aditya
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH ath-pending 0/3] Support to request pdev, vdev and beacon stats
2025-01-24 18:53 [PATCH ath-pending 0/3] Support to request pdev, vdev and beacon stats Ramya Gnanasekar
` (2 preceding siblings ...)
2025-01-24 18:53 ` [PATCH 3/3] wifi: ath12k: Request pdev " Ramya Gnanasekar
@ 2025-01-26 18:45 ` Jeff Johnson
3 siblings, 0 replies; 8+ messages in thread
From: Jeff Johnson @ 2025-01-26 18:45 UTC (permalink / raw)
To: ath12k, Ramya Gnanasekar; +Cc: linux-wireless
On Sat, 25 Jan 2025 00:23:27 +0530, Ramya Gnanasekar wrote:
> PDEV, VDEV and beacon stats will be maintained in firmware by
> stats module. These stats can be requested by host through
> WMI cmd on demand and can be used for debugging.
>
> This patch creates debugfs file for each stats which sends
> request to firmware upon read and print the corresponding information.
>
> [...]
Applied, thanks!
[1/3] wifi: ath12k: Request vdev stats from firmware
commit: e367c924768b11d28727efbf2a6426c7aef66f0f
[2/3] wifi: ath12k: Request beacon stats from firmware
commit: 9fe4669ae9193b27d1d4add9a26c82dca9d59da0
[3/3] wifi: ath12k: Request pdev stats from firmware
commit: b826ad94d89615e222a3682b02adcbe45ecbde0e
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 8+ messages in thread