From ed30fd79d3de201f51181583fed2f849173470d7 Mon Sep 17 00:00:00 2001 From: Manish Dharanenthiran Date: Fri, 31 Oct 2025 08:37:45 +0530 Subject: [PATCH 1/2] UPSTREAM: wifi: ath12k: Make firmware stats reset caller-driven Currently, ath12k_fw_stats_reset() is called in ath12k_mac_get_fw_stats() before fetching the required stats from the firmware. However, ath12k_open_bcn_stats() requests firmware stats for each enabled BSS individually. Since the firmware stats are reset before fetching, only the last BSS's data is displayed. Also, in ath12k_mac_op_get_txpower(), ath12k_mac_op_sta_statistics(), and ath12k_mac_op_link_sta_statistics(), after getting the stats from the firmware, the reset function is not called until the next firmware stats are requested or while unloading the module. Hence, the stats buffer will not be freed until one of the above sequences is executed. However, in ath12k_open_vdev_stats(), ath12k_open_bcn_stats() and ath12k_open_pdev_stats(), firmware stats are reset after copying the necessary data in ath12k_wmi_fw_stats_dump(). This leads to inconsistent usage of ath12k_fw_stats_reset() for freeing the firmware stats. Avoid these discrepancies by making it the caller's responsibility to free the stats buffer, thereby removing the need to free the stats buffer in ath12k_mac_get_fw_stats() and ath12k_wmi_fw_stats_dump(). Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Manish Dharanenthiran Reviewed-by: Vasanthakumar Thiagarajan Reviewed-by: Baochen Qiang Signed-off-by: Qian Zhang Link: https://lore.kernel.org/all/20251031-beacon_stats-v1-1-f52fce7b03ac@qti.qualcomm.com/ --- drivers/net/wireless/ath/ath12k/debugfs.c | 9 +++------ drivers/net/wireless/ath/ath12k/mac.c | 15 ++++++++++----- drivers/net/wireless/ath/ath12k/wmi.c | 2 -- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c index 16601a8c36448..d4bfe0944e4e7 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs.c +++ b/drivers/net/wireless/ath/ath12k/debugfs.c @@ -1283,6 +1283,7 @@ static int ath12k_open_vdev_stats(struct inode *inode, struct file *file) ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id, buf); + ath12k_fw_stats_reset(ar); file->private_data = no_free_ptr(buf); @@ -1349,12 +1350,7 @@ static int ath12k_open_bcn_stats(struct inode *inode, struct file *file) 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); + ath12k_fw_stats_reset(ar); file->private_data = no_free_ptr(buf); @@ -1415,6 +1411,7 @@ static int ath12k_open_pdev_stats(struct inode *inode, struct file *file) ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id, buf); + ath12k_fw_stats_reset(ar); file->private_data = no_free_ptr(buf); diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index db351c9220181..97ec054b99176 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -4837,8 +4837,6 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar, if (ah->state != ATH12K_HW_STATE_ON) return -ENETDOWN; - ath12k_fw_stats_reset(ar); - reinit_completion(&ar->fw_stats_complete); reinit_completion(&ar->fw_stats_done); @@ -4936,6 +4934,7 @@ static int ath12k_mac_op_get_txpower(struct ieee80211_hw *hw, ar->chan_tx_pwr = pdev->chan_tx_power / 2; spin_unlock_bh(&ar->data_lock); ar->last_tx_power_update = jiffies; + ath12k_fw_stats_reset(ar); send_tx_power: *dbm = ar->chan_tx_pwr; @@ -12701,14 +12700,18 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, if (!signal && ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA && - !(ath12k_mac_get_fw_stats(ar, ¶ms))) + !(ath12k_mac_get_fw_stats(ar, ¶ms))) { signal = arsta->rssi_beacon; + ath12k_fw_stats_reset(ar); + } params.stats_id = WMI_REQUEST_RSSI_PER_CHAIN_STAT; if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) && ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA && - !(ath12k_mac_get_fw_stats(ar, ¶ms))) + !(ath12k_mac_get_fw_stats(ar, ¶ms))) { ath12k_mac_put_chain_rssi(sinfo, arsta); + ath12k_fw_stats_reset(ar); + } spin_lock_bh(&ar->data_lock); noise_floor = ath12k_pdev_get_noise_floor(ar); @@ -12792,8 +12795,10 @@ static void ath12k_mac_op_link_sta_statistics(struct ieee80211_hw *hw, if (!signal && ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA && - !(ath12k_mac_get_fw_stats(ar, ¶ms))) + !(ath12k_mac_get_fw_stats(ar, ¶ms))) { signal = arsta->rssi_beacon; + ath12k_fw_stats_reset(ar); + } if (signal) { link_sinfo->signal = diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index ff6b3d4ea8208..455ae32c8afd9 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -8017,8 +8017,6 @@ void ath12k_wmi_fw_stats_dump(struct ath12k *ar, buf[len - 1] = 0; else buf[len] = 0; - - ath12k_fw_stats_reset(ar); } static void From 597aa8b0cccce21299853ac917a39d223904354d Mon Sep 17 00:00:00 2001 From: Manish Dharanenthiran Date: Fri, 31 Oct 2025 08:37:46 +0530 Subject: [PATCH 2/2] UPSTREAM: wifi: ath12k: Fix timeout error during beacon stats retrieval Currently, for beacon_stats, ath12k_mac_get_fw_stats() is called for each started BSS on the specified hardware. ath12k_mac_get_fw_stats() will wait for the fw_stats_done completion after fetching the requested data from firmware. For the beacon_stats, fw_stats_done completion will be set only when stats are received for all BSSes. However, for other stats like vdev_stats or pdev_stats, there is one request to the firmware for all enabled BSSes. Since beacon_stats is fetched individually for all BSSes enabled in that pdev, waiting for the completion event results in a timeout error when multiple BSSes are enabled. Avoid this by completing the fw_stats_done immediately after updating the requested BSS's beacon stats in the list. Subsequently, this list will be used to display the beacon stats for all enabled BSSes in the requested pdev. Additionally, remove 'num_bcn_recvd' from the ath12k_fw_stats struct as it is no longer needed. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Fixes: 9fe4669ae919 ("wifi: ath12k: Request beacon stats from firmware") Signed-off-by: Manish Dharanenthiran Reviewed-by: Vasanthakumar Thiagarajan Reviewed-by: Baochen Qiang Signed-off-by: Qian Zhang Link: https://lore.kernel.org/all/20251031-beacon_stats-v1-2-f52fce7b03ac@qti.qualcomm.com/ --- drivers/net/wireless/ath/ath12k/core.c | 2 -- drivers/net/wireless/ath/ath12k/core.h | 1 - drivers/net/wireless/ath/ath12k/wmi.c | 10 +--------- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 5d494c5cdc0da..f0994f3918f5c 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ @@ -1250,7 +1249,6 @@ void ath12k_fw_stats_reset(struct ath12k *ar) spin_lock_bh(&ar->data_lock); ath12k_fw_stats_free(&ar->fw_stats); ar->fw_stats.num_vdev_recvd = 0; - ar->fw_stats.num_bcn_recvd = 0; spin_unlock_bh(&ar->data_lock); } diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 3d1956966a485..d7688b383f62c 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -644,7 +644,6 @@ struct ath12k_fw_stats { struct list_head vdevs; struct list_head bcn; u32 num_vdev_recvd; - u32 num_bcn_recvd; }; struct ath12k_dbg_htt_stats { diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 455ae32c8afd9..8250fd5a75b7f 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -8413,18 +8413,10 @@ static void ath12k_wmi_fw_stats_process(struct ath12k *ar, ath12k_warn(ab, "empty beacon stats"); return; } - /* Mark end until we reached the count of all started VDEVs - * within the PDEV - */ - if (ar->num_started_vdevs) - is_end = ((++ar->fw_stats.num_bcn_recvd) == - ar->num_started_vdevs); list_splice_tail_init(&stats->bcn, &ar->fw_stats.bcn); - - if (is_end) - complete(&ar->fw_stats_done); + complete(&ar->fw_stats_done); } }