From: Roopni Devanathan <roopni.devanathan@oss.qualcomm.com>
To: ath12k@lists.infradead.org
Cc: linux-wireless@vger.kernel.org,
Harish Rachakonda <quic_rachakon@quicinc.com>,
Roopni Devanathan <roopni.devanathan@oss.qualcomm.com>
Subject: [PATCH ath-next] wifi: ath12k: Support channel change stats
Date: Thu, 26 Mar 2026 10:36:41 +0530 [thread overview]
Message-ID: <20260326050641.3066562-1-roopni.devanathan@oss.qualcomm.com> (raw)
From: Harish Rachakonda <quic_rachakon@quicinc.com>
Add support to request channel change stats from the firmware through
HTT stats type 76. These stats give channel switch details like the
channel that the radio changed to, its center frequency, time taken
for the switch, chainmask details, etc.
Sample output:
echo 76 > /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
Channel Change Timings:
|PRIMARY CHANNEL FREQ|BANDWIDTH CENTER FREQ|PHYMODE|TX_CHAINMASK|RX_CHAINMASK|SWITCH TIME(us)|INI(us)|TPC+CTL(us)|CAL(us)|MISC(us)|CTL(us)|SW PROFILE|
| 5200| 5200| 24| 15| 15| 448850| 2410| 10546| 434593| 1071| 1100| 4|
| 5240| 5240| 24| 15| 15| 450730| 4106| 10524| 434528| 1306| 1150| 4|
| 5180| 5210| 26| 15| 15| 467894| 4764| 10438| 451101| 1337| 1508| 4|
| 5200| 5200| 0| 15| 15| 13838| 2692| 1736| 8558| 686| 802| 6|
| 5180| 5180| 0| 15| 15| 13465| 3207| 855| 8579| 578| 760| 6|
| 5200| 5200| 24| 15| 15| 570321| 2441| 10439| 555661| 1574| 949| 4|
Note: WCN7850 firmware does not support HTT stats type 76.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01181-QCAHKSWPL_SILICONZ-1
Signed-off-by: Harish Rachakonda <quic_rachakon@quicinc.com>
Signed-off-by: Roopni Devanathan <roopni.devanathan@oss.qualcomm.com>
---
.../wireless/ath/ath12k/debugfs_htt_stats.c | 72 +++++++++++++++++++
.../wireless/ath/ath12k/debugfs_htt_stats.h | 26 +++++++
2 files changed, 98 insertions(+)
diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
index 7f6ca07fb335..b772181a496e 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
+++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
@@ -5722,6 +5722,75 @@ ath12k_htt_print_tx_hwq_stats_cmn_tlv(const void *tag_buf, u16 tag_len,
stats_req->buf_len = len;
}
+static void
+ath12k_htt_print_chan_switch_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_chan_switch_stats_tlv *sbuf = tag_buf;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u32 switch_freq, switch_profile;
+ u32 len = stats_req->buf_len;
+ u8 *buf = stats_req->buf;
+ u8 i;
+
+ if (tag_len < sizeof(*sbuf))
+ return;
+
+ i = min(le32_to_cpu(sbuf->switch_count), ATH12K_HTT_CHAN_SWITCH_STATS_BUF_LEN);
+ if (!i)
+ return;
+
+ len += scnprintf(buf + len, buf_len - len, "Channel Change Timings:\n");
+ len += scnprintf(buf + len, buf_len - len,
+ "|%-20s|%-21s|%-7s|%-12s|%-12s|%-15s|",
+ "PRIMARY CHANNEL FREQ", "BANDWIDTH CENTER FREQ", "PHYMODE",
+ "TX_CHAINMASK", "RX_CHAINMASK", "SWITCH TIME(us)");
+ len += scnprintf(buf + len, buf_len - len,
+ "%-7s|%-11s|%-7s|%-8s|%-7s|%-10s|\n",
+ "INI(us)", "TPC+CTL(us)", "CAL(us)", "MISC(us)", "CTL(us)",
+ "SW PROFILE");
+
+ /*
+ * sbuf->switch_count has the number of successful channel changes. The firmware
+ * sends the record of channel change in such a way that sbuf->chan_stats[0] will
+ * point to the channel change that occurred first and the recent channel change
+ * records will be stored in sbuf->chan_stats[9]. As and when new channel change
+ * occurs, sbuf->chan_stats[0] will be replaced by records from the next index,
+ * sbuf->chan_stats[1]. While printing the records, reverse chronological order
+ * is followed, i.e., the most recent channel change records are printed first
+ * and the oldest one, last.
+ */
+ while (i--) {
+ switch_freq = le32_to_cpu(sbuf->chan_stats[i].chan_switch_freq);
+ switch_profile = le32_to_cpu(sbuf->chan_stats[i].chan_switch_profile);
+
+ len += scnprintf(buf + len, buf_len - len,
+ "|%20u|%21u|%7u|%12u|%12u|%15u|",
+ u32_get_bits(switch_freq,
+ ATH12K_HTT_STATS_CHAN_SWITCH_BW_MHZ),
+ u32_get_bits(switch_freq,
+ ATH12K_HTT_STATS_CHAN_SWITCH_BAND_FREQ),
+ u32_get_bits(switch_profile,
+ ATH12K_HTT_STATS_CHAN_SWITCH_PHY_MODE),
+ u32_get_bits(switch_profile,
+ ATH12K_HTT_STATS_CHAN_SWITCH_TX_CHAINMASK),
+ u32_get_bits(switch_profile,
+ ATH12K_HTT_STATS_CHAN_SWITCH_RX_CHAINMASK),
+ le32_to_cpu(sbuf->chan_stats[i].chan_switch_time));
+ len += scnprintf(buf + len, buf_len - len,
+ "%7u|%11u|%7u|%8u|%7u|%10u|\n",
+ le32_to_cpu(sbuf->chan_stats[i].ini_module_time),
+ le32_to_cpu(sbuf->chan_stats[i].tpc_module_time),
+ le32_to_cpu(sbuf->chan_stats[i].cal_module_time),
+ le32_to_cpu(sbuf->chan_stats[i].misc_module_time),
+ le32_to_cpu(sbuf->chan_stats[i].ctl_module_time),
+ u32_get_bits(switch_profile,
+ ATH12K_HTT_STATS_CHAN_SWITCH_SW_PROFILE));
+ }
+
+ 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)
@@ -6024,6 +6093,9 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab,
case HTT_STATS_TX_HWQ_CMN_TAG:
ath12k_htt_print_tx_hwq_stats_cmn_tlv(tag_buf, len, stats_req);
break;
+ case HTT_STATS_CHAN_SWITCH_STATS_TAG:
+ ath12k_htt_print_chan_switch_stats_tlv(tag_buf, len, 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 bfabe6500d44..82ab7b9e4db9 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
+++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
@@ -164,6 +164,7 @@ enum ath12k_dbg_htt_ext_stats_type {
ATH12K_DBG_HTT_PDEV_MLO_IPC_STATS = 64,
ATH12K_DBG_HTT_EXT_PDEV_RTT_RESP_STATS = 65,
ATH12K_DBG_HTT_EXT_PDEV_RTT_INITIATOR_STATS = 66,
+ ATH12K_DBG_HTT_EXT_CHAN_SWITCH_STATS = 76,
/* keep this last */
ATH12K_DBG_HTT_NUM_EXT_STATS,
@@ -267,6 +268,7 @@ enum ath12k_dbg_htt_tlv_tag {
HTT_STATS_PDEV_RTT_HW_STATS_TAG = 196,
HTT_STATS_PDEV_RTT_TBR_SELFGEN_QUEUED_STATS_TAG = 197,
HTT_STATS_PDEV_RTT_TBR_CMD_RESULT_STATS_TAG = 198,
+ HTT_STATS_CHAN_SWITCH_STATS_TAG = 213,
HTT_STATS_MAX_TAG,
};
@@ -2156,4 +2158,28 @@ struct htt_tx_hwq_stats_cmn_tlv {
__le32 txq_timeout;
} __packed;
+#define ATH12K_HTT_CHAN_SWITCH_STATS_BUF_LEN 10
+
+#define ATH12K_HTT_STATS_CHAN_SWITCH_BW_MHZ GENMASK(15, 0)
+#define ATH12K_HTT_STATS_CHAN_SWITCH_BAND_FREQ GENMASK(31, 16)
+#define ATH12K_HTT_STATS_CHAN_SWITCH_PHY_MODE GENMASK(7, 0)
+#define ATH12K_HTT_STATS_CHAN_SWITCH_TX_CHAINMASK GENMASK(15, 8)
+#define ATH12K_HTT_STATS_CHAN_SWITCH_RX_CHAINMASK GENMASK(23, 16)
+#define ATH12K_HTT_STATS_CHAN_SWITCH_SW_PROFILE GENMASK(31, 24)
+
+struct ath12k_htt_chan_switch_stats_tlv {
+ struct {
+ __le32 chan_switch_freq;
+ __le32 chan_switch_profile;
+ __le32 chan_switch_time;
+ __le32 cal_module_time;
+ __le32 ini_module_time;
+ __le32 tpc_module_time;
+ __le32 misc_module_time;
+ __le32 ctl_module_time;
+ __le32 reserved;
+ } chan_stats[ATH12K_HTT_CHAN_SWITCH_STATS_BUF_LEN];
+ __le32 switch_count; /* shows how many channel changes have occurred */
+} __packed;
+
#endif
base-commit: 37538641dac955f6690372f0ebb94e5e14a23418
--
2.43.0
reply other threads:[~2026-03-26 5:06 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260326050641.3066562-1-roopni.devanathan@oss.qualcomm.com \
--to=roopni.devanathan@oss.qualcomm.com \
--cc=ath12k@lists.infradead.org \
--cc=linux-wireless@vger.kernel.org \
--cc=quic_rachakon@quicinc.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox