From: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
To: Roopni Devanathan <roopni.devanathan@oss.qualcomm.com>,
ath12k@lists.infradead.org
Cc: linux-wireless@vger.kernel.org,
Harish Rachakonda <quic_rachakon@quicinc.com>
Subject: Re: [PATCH ath-next] wifi: ath12k: Support channel change stats
Date: Tue, 7 Apr 2026 11:23:08 +0800 [thread overview]
Message-ID: <63acfa83-753c-4b45-8f11-8e18e760cbf2@oss.qualcomm.com> (raw)
In-Reply-To: <20260326050641.3066562-1-roopni.devanathan@oss.qualcomm.com>
On 3/26/2026 1:06 PM, Roopni Devanathan wrote:
> 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.
this note also applies to QCC2072.
>
> 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
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
next prev parent reply other threads:[~2026-04-07 3:23 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-26 5:06 [PATCH ath-next] wifi: ath12k: Support channel change stats Roopni Devanathan
2026-04-07 3:23 ` Baochen Qiang [this message]
2026-04-07 15:22 ` Jeff Johnson
2026-04-07 9:18 ` Rameshkumar Sundaram
2026-04-08 0:50 ` Jeff Johnson
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=63acfa83-753c-4b45-8f11-8e18e760cbf2@oss.qualcomm.com \
--to=baochen.qiang@oss.qualcomm.com \
--cc=ath12k@lists.infradead.org \
--cc=linux-wireless@vger.kernel.org \
--cc=quic_rachakon@quicinc.com \
--cc=roopni.devanathan@oss.qualcomm.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