Commit 72610ed7 authored by Baochen Qiang's avatar Baochen Qiang Committed by Jeff Johnson
Browse files

wifi: ath11k: move some firmware stats related functions outside of debugfs



Commit b488c766 ("ath11k: report rssi of each chain to mac80211 for QCA6390/WCN6855")
and commit c3b39553 ("ath11k: add signal report to mac80211 for QCA6390 and WCN6855")
call debugfs functions in mac ops. Those functions are no-ops if CONFIG_ATH11K_DEBUGFS is
not enabled, thus cause wrong status reported.

Move them to mac.c.

Besides, since WMI_REQUEST_RSSI_PER_CHAIN_STAT and WMI_REQUEST_VDEV_STAT stats could also
be requested via mac ops, process them directly in ath11k_update_stats_event().

Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.37

Fixes: b488c766 ("ath11k: report rssi of each chain to mac80211 for QCA6390/WCN6855")
Fixes: c3b39553 ("ath11k: add signal report to mac80211 for QCA6390 and WCN6855")
Signed-off-by: default avatarBaochen Qiang <quic_bqiang@quicinc.com>
Reviewed-by: default avatarVasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20250220082448.31039-5-quic_bqiang@quicinc.com


Signed-off-by: default avatarJeff Johnson <jeff.johnson@oss.qualcomm.com>
parent 3b6d00fa
Loading
Loading
Loading
Loading
+6 −120
Original line number Diff line number Diff line
@@ -93,58 +93,14 @@ void ath11k_debugfs_add_dbring_entry(struct ath11k *ar,
	spin_unlock_bh(&dbr_data->lock);
}

static void ath11k_debugfs_fw_stats_reset(struct ath11k *ar)
{
	spin_lock_bh(&ar->data_lock);
	ath11k_fw_stats_pdevs_free(&ar->fw_stats.pdevs);
	ath11k_fw_stats_vdevs_free(&ar->fw_stats.vdevs);
	ar->fw_stats.num_vdev_recvd = 0;
	ar->fw_stats.num_bcn_recvd = 0;
	spin_unlock_bh(&ar->data_lock);
}

void ath11k_debugfs_fw_stats_process(struct ath11k *ar, struct ath11k_fw_stats *stats)
{
	struct ath11k_base *ab = ar->ab;
	struct ath11k_pdev *pdev;
	bool is_end = true;
	size_t total_vdevs_started = 0;
	int i;

	/* WMI_REQUEST_PDEV_STAT request has been already processed */

	if (stats->stats_id == WMI_REQUEST_RSSI_PER_CHAIN_STAT) {
		complete(&ar->fw_stats_done);
		return;
	}

	if (stats->stats_id == WMI_REQUEST_VDEV_STAT) {
		if (list_empty(&stats->vdevs)) {
			ath11k_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
	/* WMI_REQUEST_PDEV_STAT, WMI_REQUEST_RSSI_PER_CHAIN_STAT and
	 * WMI_REQUEST_VDEV_STAT requests have been already processed.
	 */
		for (i = 0; i < ab->num_radios; i++) {
			pdev = rcu_dereference(ab->pdevs_active[i]);
			if (pdev && pdev->ar)
				total_vdevs_started += ar->num_started_vdevs;
		}

		if (total_vdevs_started)
			is_end = ((++ar->fw_stats.num_vdev_recvd) ==
				  total_vdevs_started);

		list_splice_tail_init(&stats->vdevs,
				      &ar->fw_stats.vdevs);

		if (is_end)
			complete(&ar->fw_stats_done);

		return;
	}

	if (stats->stats_id == WMI_REQUEST_BCN_STAT) {
		if (list_empty(&stats->bcn)) {
			ath11k_warn(ab, "empty bcn stats");
@@ -165,76 +121,6 @@ void ath11k_debugfs_fw_stats_process(struct ath11k *ar, struct ath11k_fw_stats *
	}
}

static int ath11k_debugfs_fw_stats_request(struct ath11k *ar,
					   struct stats_request_params *req_param)
{
	struct ath11k_base *ab = ar->ab;
	unsigned long time_left;
	int ret;

	lockdep_assert_held(&ar->conf_mutex);

	ath11k_debugfs_fw_stats_reset(ar);

	reinit_completion(&ar->fw_stats_complete);
	reinit_completion(&ar->fw_stats_done);

	ret = ath11k_wmi_send_stats_request_cmd(ar, req_param);

	if (ret) {
		ath11k_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 (!time_left)
		return -ETIMEDOUT;

	/* 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
	 */
	time_left = wait_for_completion_timeout(&ar->fw_stats_done, 3 * HZ);
	if (!time_left)
		return -ETIMEDOUT;

	return 0;
}

int ath11k_debugfs_get_fw_stats(struct ath11k *ar, u32 pdev_id,
				u32 vdev_id, u32 stats_id)
{
	struct ath11k_base *ab = ar->ab;
	struct stats_request_params req_param;
	int ret;

	mutex_lock(&ar->conf_mutex);

	if (ar->state != ATH11K_STATE_ON) {
		ret = -ENETDOWN;
		goto err_unlock;
	}

	req_param.pdev_id = pdev_id;
	req_param.vdev_id = vdev_id;
	req_param.stats_id = stats_id;

	ret = ath11k_debugfs_fw_stats_request(ar, &req_param);
	if (ret)
		ath11k_warn(ab, "failed to request fw stats: %d\n", ret);

	ath11k_dbg(ab, ATH11K_DBG_WMI,
		   "debug get fw stat pdev id %d vdev id %d stats id 0x%x\n",
		   pdev_id, vdev_id, stats_id);

err_unlock:
	mutex_unlock(&ar->conf_mutex);

	return ret;
}

static int ath11k_open_pdev_stats(struct inode *inode, struct file *file)
{
	struct ath11k *ar = inode->i_private;
@@ -260,7 +146,7 @@ static int ath11k_open_pdev_stats(struct inode *inode, struct file *file)
	req_param.vdev_id = 0;
	req_param.stats_id = WMI_REQUEST_PDEV_STAT;

	ret = ath11k_debugfs_fw_stats_request(ar, &req_param);
	ret = ath11k_mac_fw_stats_request(ar, &req_param);
	if (ret) {
		ath11k_warn(ab, "failed to request fw pdev stats: %d\n", ret);
		goto err_free;
@@ -331,7 +217,7 @@ static int ath11k_open_vdev_stats(struct inode *inode, struct file *file)
	req_param.vdev_id = 0;
	req_param.stats_id = WMI_REQUEST_VDEV_STAT;

	ret = ath11k_debugfs_fw_stats_request(ar, &req_param);
	ret = ath11k_mac_fw_stats_request(ar, &req_param);
	if (ret) {
		ath11k_warn(ar->ab, "failed to request fw vdev stats: %d\n", ret);
		goto err_free;
@@ -407,7 +293,7 @@ static int ath11k_open_bcn_stats(struct inode *inode, struct file *file)
			continue;

		req_param.vdev_id = arvif->vdev_id;
		ret = ath11k_debugfs_fw_stats_request(ar, &req_param);
		ret = ath11k_mac_fw_stats_request(ar, &req_param);
		if (ret) {
			ath11k_warn(ar->ab, "failed to request fw bcn stats: %d\n", ret);
			goto err_free;
+1 −9
Original line number Diff line number Diff line
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
 * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
 * Copyright (c) 2021-2022, 2025 Qualcomm Innovation Center, Inc. All rights reserved.
 */

#ifndef _ATH11K_DEBUGFS_H_
@@ -273,8 +273,6 @@ void ath11k_debugfs_unregister(struct ath11k *ar);
void ath11k_debugfs_fw_stats_process(struct ath11k *ar, struct ath11k_fw_stats *stats);

void ath11k_debugfs_fw_stats_init(struct ath11k *ar);
int ath11k_debugfs_get_fw_stats(struct ath11k *ar, u32 pdev_id,
				u32 vdev_id, u32 stats_id);

static inline bool ath11k_debugfs_is_pktlog_lite_mode_enabled(struct ath11k *ar)
{
@@ -381,12 +379,6 @@ static inline int ath11k_debugfs_rx_filter(struct ath11k *ar)
	return 0;
}

static inline int ath11k_debugfs_get_fw_stats(struct ath11k *ar,
					      u32 pdev_id, u32 vdev_id, u32 stats_id)
{
	return 0;
}

static inline void
ath11k_debugfs_add_dbring_entry(struct ath11k *ar,
				enum wmi_direct_buffer_module id,
+84 −4
Original line number Diff line number Diff line
@@ -8997,6 +8997,86 @@ static void ath11k_mac_put_chain_rssi(struct station_info *sinfo,
	}
}

static void ath11k_mac_fw_stats_reset(struct ath11k *ar)
{
	spin_lock_bh(&ar->data_lock);
	ath11k_fw_stats_pdevs_free(&ar->fw_stats.pdevs);
	ath11k_fw_stats_vdevs_free(&ar->fw_stats.vdevs);
	ar->fw_stats.num_vdev_recvd = 0;
	ar->fw_stats.num_bcn_recvd = 0;
	spin_unlock_bh(&ar->data_lock);
}

int ath11k_mac_fw_stats_request(struct ath11k *ar,
				struct stats_request_params *req_param)
{
	struct ath11k_base *ab = ar->ab;
	unsigned long time_left;
	int ret;

	lockdep_assert_held(&ar->conf_mutex);

	ath11k_mac_fw_stats_reset(ar);

	reinit_completion(&ar->fw_stats_complete);
	reinit_completion(&ar->fw_stats_done);

	ret = ath11k_wmi_send_stats_request_cmd(ar, req_param);

	if (ret) {
		ath11k_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 (!time_left)
		return -ETIMEDOUT;

	/* 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
	 */
	time_left = wait_for_completion_timeout(&ar->fw_stats_done, 3 * HZ);
	if (!time_left)
		return -ETIMEDOUT;

	return 0;
}

static int ath11k_mac_get_fw_stats(struct ath11k *ar, u32 pdev_id,
				   u32 vdev_id, u32 stats_id)
{
	struct ath11k_base *ab = ar->ab;
	struct stats_request_params req_param;
	int ret;

	mutex_lock(&ar->conf_mutex);

	if (ar->state != ATH11K_STATE_ON) {
		ret = -ENETDOWN;
		goto err_unlock;
	}

	req_param.pdev_id = pdev_id;
	req_param.vdev_id = vdev_id;
	req_param.stats_id = stats_id;

	ret = ath11k_mac_fw_stats_request(ar, &req_param);
	if (ret)
		ath11k_warn(ab, "failed to request fw stats: %d\n", ret);

	ath11k_dbg(ab, ATH11K_DBG_WMI,
		   "debug get fw stat pdev id %d vdev id %d stats id 0x%x\n",
		   pdev_id, vdev_id, stats_id);

err_unlock:
	mutex_unlock(&ar->conf_mutex);

	return ret;
}

static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw,
					 struct ieee80211_vif *vif,
					 struct ieee80211_sta *sta,
@@ -9034,7 +9114,7 @@ static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw,
	if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) &&
	    arsta->arvif->vdev_type == WMI_VDEV_TYPE_STA &&
	    ar->ab->hw_params.supports_rssi_stats &&
	    !ath11k_debugfs_get_fw_stats(ar, ar->pdev->pdev_id, 0,
	    !ath11k_mac_get_fw_stats(ar, ar->pdev->pdev_id, 0,
				     WMI_REQUEST_RSSI_PER_CHAIN_STAT)) {
		ath11k_mac_put_chain_rssi(sinfo, arsta, "fw stats", true);
	}
@@ -9043,7 +9123,7 @@ static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw,
	if (!signal &&
	    arsta->arvif->vdev_type == WMI_VDEV_TYPE_STA &&
	    ar->ab->hw_params.supports_rssi_stats &&
	    !(ath11k_debugfs_get_fw_stats(ar, ar->pdev->pdev_id, 0,
	    !(ath11k_mac_get_fw_stats(ar, ar->pdev->pdev_id, 0,
				      WMI_REQUEST_VDEV_STAT)))
		signal = arsta->rssi_beacon;

+3 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
 * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
 * Copyright (c) 2021-2023, 2025 Qualcomm Innovation Center, Inc. All rights reserved.
 */

#ifndef ATH11K_MAC_H
@@ -179,4 +179,6 @@ int ath11k_mac_vif_set_keepalive(struct ath11k_vif *arvif,
void ath11k_mac_fill_reg_tpc_info(struct ath11k *ar,
				  struct ieee80211_vif *vif,
				  struct ieee80211_chanctx_conf *ctx);
int ath11k_mac_fw_stats_request(struct ath11k *ar,
				struct stats_request_params *req_param);
#endif
+41 −4
Original line number Diff line number Diff line
@@ -8158,6 +8158,11 @@ static void ath11k_peer_assoc_conf_event(struct ath11k_base *ab, struct sk_buff
static void ath11k_update_stats_event(struct ath11k_base *ab, struct sk_buff *skb)
{
	struct ath11k_fw_stats stats = {};
	size_t total_vdevs_started = 0;
	struct ath11k_pdev *pdev;
	bool is_end = true;
	int i;

	struct ath11k *ar;
	int ret;

@@ -8184,7 +8189,8 @@ static void ath11k_update_stats_event(struct ath11k_base *ab, struct sk_buff *sk

	spin_lock_bh(&ar->data_lock);

	/* WMI_REQUEST_PDEV_STAT can be requested via .get_txpower mac ops or via
	/* WMI_REQUEST_PDEV_STAT, WMI_REQUEST_VDEV_STAT and
	 * WMI_REQUEST_RSSI_PER_CHAIN_STAT can be requested via mac ops or via
	 * debugfs fw stats. Therefore, processing it separately.
	 */
	if (stats.stats_id == WMI_REQUEST_PDEV_STAT) {
@@ -8193,9 +8199,40 @@ static void ath11k_update_stats_event(struct ath11k_base *ab, struct sk_buff *sk
		goto complete;
	}

	/* WMI_REQUEST_VDEV_STAT, WMI_REQUEST_BCN_STAT and WMI_REQUEST_RSSI_PER_CHAIN_STAT
	 * are currently requested only via debugfs fw stats. Hence, processing these
	 * in debugfs context
	if (stats.stats_id == WMI_REQUEST_RSSI_PER_CHAIN_STAT) {
		complete(&ar->fw_stats_done);
		goto complete;
	}

	if (stats.stats_id == WMI_REQUEST_VDEV_STAT) {
		if (list_empty(&stats.vdevs)) {
			ath11k_warn(ab, "empty vdev stats");
			goto complete;
		}
		/* FW sends all the active VDEV stats irrespective of PDEV,
		 * hence limit until the count of all VDEVs started
		 */
		for (i = 0; i < ab->num_radios; i++) {
			pdev = rcu_dereference(ab->pdevs_active[i]);
			if (pdev && pdev->ar)
				total_vdevs_started += ar->num_started_vdevs;
		}

		if (total_vdevs_started)
			is_end = ((++ar->fw_stats.num_vdev_recvd) ==
				  total_vdevs_started);

		list_splice_tail_init(&stats.vdevs,
				      &ar->fw_stats.vdevs);

		if (is_end)
			complete(&ar->fw_stats_done);

		goto complete;
	}

	/* WMI_REQUEST_BCN_STAT is currently requested only via debugfs fw stats.
	 * Hence, processing it in debugfs context
	 */
	ath11k_debugfs_fw_stats_process(ar, &stats);