File Index
Files and directories
Sign in
FILE

debugfs_sta.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/ath/ath12k/debugfs_sta.c C
  1// SPDX-License-Identifier: BSD-3-Clause-Clear
  2/*
  3 * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
  4 */
  5
  6#include <linux/vmalloc.h>
  7
  8#include "debugfs_sta.h"
  9#include "core.h"
 10#include "peer.h"
 11#include "debug.h"
 12#include "debugfs_htt_stats.h"
 13#include "debugfs.h"
 14
 15static
 16u32 ath12k_dbg_sta_dump_rate_stats(u8 *buf, u32 offset, const int size,
 17				   bool he_rates_avail,
 18				   const struct ath12k_rx_peer_rate_stats *stats)
 19{
 20	static const char *legacy_rate_str[HAL_RX_MAX_NUM_LEGACY_RATES] = {
 21					"1 Mbps", "2 Mbps", "5.5 Mbps", "6 Mbps",
 22					"9 Mbps", "11 Mbps", "12 Mbps", "18 Mbps",
 23					"24 Mbps", "36 Mbps", "48 Mbps", "54 Mbps"};
 24	u8 max_bw = HAL_RX_BW_MAX, max_gi = HAL_RX_GI_MAX, max_mcs = HAL_RX_MAX_NSS;
 25	int mcs = 0, bw = 0, nss = 0, gi = 0, bw_num = 0;
 26	u32 i, len = offset, max = max_bw * max_gi * max_mcs;
 27	bool found;
 28
 29	len += scnprintf(buf + len, size - len, "\nEHT stats:\n");
 30	for (i = 0; i <= HAL_RX_MAX_MCS_BE; i++)
 31		len += scnprintf(buf + len, size - len,
 32				   "MCS %d: %llu%s", i, stats->be_mcs_count[i],
 33				   (i + 1) % 8 ? "\t" : "\n");
 34
 35	len += scnprintf(buf + len, size - len, "\nHE stats:\n");
 36	for (i = 0; i <= HAL_RX_MAX_MCS_HE; i++)
 37		len += scnprintf(buf + len, size - len,
 38				   "MCS %d: %llu%s", i, stats->he_mcs_count[i],
 39				   (i + 1) % 6 ? "\t" : "\n");
 40
 41	len += scnprintf(buf + len, size - len, "\nVHT stats:\n");
 42	for (i = 0; i <= HAL_RX_MAX_MCS_VHT; i++)
 43		len += scnprintf(buf + len, size - len,
 44				   "MCS %d: %llu%s", i, stats->vht_mcs_count[i],
 45				   (i + 1) % 5 ? "\t" : "\n");
 46
 47	len += scnprintf(buf + len, size - len, "\nHT stats:\n");
 48	for (i = 0; i <= HAL_RX_MAX_MCS_HT; i++)
 49		len += scnprintf(buf + len, size - len,
 50				   "MCS %d: %llu%s", i, stats->ht_mcs_count[i],
 51				   (i + 1) % 8 ? "\t" : "\n");
 52
 53	len += scnprintf(buf + len, size - len, "\nLegacy stats:\n");
 54	for (i = 0; i < HAL_RX_MAX_NUM_LEGACY_RATES; i++)
 55		len += scnprintf(buf + len, size - len,
 56				   "%s: %llu%s", legacy_rate_str[i],
 57				   stats->legacy_count[i],
 58				   (i + 1) % 4 ? "\t" : "\n");
 59
 60	len += scnprintf(buf + len, size - len, "\nNSS stats:\n");
 61	for (i = 0; i < HAL_RX_MAX_NSS; i++)
 62		len += scnprintf(buf + len, size - len,
 63				   "%dx%d: %llu ", i + 1, i + 1,
 64				   stats->nss_count[i]);
 65
 66	len += scnprintf(buf + len, size - len,
 67			  "\n\nGI: 0.8 us %llu 0.4 us %llu 1.6 us %llu 3.2 us %llu\n",
 68			  stats->gi_count[0],
 69			  stats->gi_count[1],
 70			  stats->gi_count[2],
 71			  stats->gi_count[3]);
 72
 73	len += scnprintf(buf + len, size - len,
 74			   "BW: 20 MHz %llu 40 MHz %llu 80 MHz %llu 160 MHz %llu 320 MHz %llu\n",
 75			   stats->bw_count[0],
 76			   stats->bw_count[1],
 77			   stats->bw_count[2],
 78			   stats->bw_count[3],
 79			   stats->bw_count[4]);
 80
 81	for (i = 0; i < max; i++) {
 82		found = false;
 83
 84		for (mcs = 0; mcs <= HAL_RX_MAX_MCS_HT; mcs++) {
 85			if (stats->rx_rate[bw][gi][nss][mcs]) {
 86				found = true;
 87				break;
 88			}
 89		}
 90
 91		if (!found)
 92			goto skip_report;
 93
 94		switch (bw) {
 95		case HAL_RX_BW_20MHZ:
 96			bw_num = 20;
 97			break;
 98		case HAL_RX_BW_40MHZ:
 99			bw_num = 40;
100			break;
101		case HAL_RX_BW_80MHZ:
102			bw_num = 80;
103			break;
104		case HAL_RX_BW_160MHZ:
105			bw_num = 160;
106			break;
107		case HAL_RX_BW_320MHZ:
108			bw_num = 320;
109			break;
110		}
111
112		len += scnprintf(buf + len, size - len, "\n%d Mhz gi %d us %dx%d : ",
113				 bw_num, gi, nss + 1, nss + 1);
114
115		for (mcs = 0; mcs <= HAL_RX_MAX_MCS_HT; mcs++) {
116			if (stats->rx_rate[bw][gi][nss][mcs])
117				len += scnprintf(buf + len, size - len,
118						 " %d:%llu", mcs,
119						 stats->rx_rate[bw][gi][nss][mcs]);
120		}
121
122skip_report:
123		if (nss++ >= max_mcs - 1) {
124			nss = 0;
125			if (gi++ >= max_gi - 1) {
126				gi = 0;
127				if (bw < max_bw - 1)
128					bw++;
129			}
130		}
131	}
132
133	len += scnprintf(buf + len, size - len, "\n");
134
135	return len - offset;
136}
137
138static ssize_t ath12k_dbg_sta_dump_rx_stats(struct file *file,
139					    char __user *user_buf,
140					    size_t count, loff_t *ppos)
141{
142	struct ieee80211_link_sta *link_sta = file->private_data;
143	struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(link_sta->sta);
144	const int size = ATH12K_STA_RX_STATS_BUF_SIZE;
145	struct ath12k_hw *ah = ahsta->ahvif->ah;
146	struct ath12k_rx_peer_stats *rx_stats;
147	struct ath12k_link_sta *arsta;
148	u8 link_id = link_sta->link_id;
149	int len = 0, i, ret = 0;
150	bool he_rates_avail;
151	struct ath12k *ar;
152
153	wiphy_lock(ah->hw->wiphy);
154
155	if (!(BIT(link_id) & ahsta->links_map)) {
156		wiphy_unlock(ah->hw->wiphy);
157		return -ENOENT;
158	}
159
160	arsta = wiphy_dereference(ah->hw->wiphy, ahsta->link[link_id]);
161	if (!arsta || !arsta->arvif->ar) {
162		wiphy_unlock(ah->hw->wiphy);
163		return -ENOENT;
164	}
165
166	ar = arsta->arvif->ar;
167
168	u8 *buf __free(kfree) = kzalloc(size, GFP_KERNEL);
169	if (!buf) {
170		ret = -ENOENT;
171		goto out;
172	}
173
174	spin_lock_bh(&ar->ab->base_lock);
175
176	rx_stats = arsta->rx_stats;
177	if (!rx_stats) {
178		ret = -ENOENT;
179		goto unlock;
180	}
181
182	len += scnprintf(buf + len, size - len, "RX peer stats:\n\n");
183	len += scnprintf(buf + len, size - len, "Num of MSDUs: %llu\n",
184			 rx_stats->num_msdu);
185	len += scnprintf(buf + len, size - len, "Num of MSDUs with TCP L4: %llu\n",
186			 rx_stats->tcp_msdu_count);
187	len += scnprintf(buf + len, size - len, "Num of MSDUs with UDP L4: %llu\n",
188			 rx_stats->udp_msdu_count);
189	len += scnprintf(buf + len, size - len, "Num of other MSDUs: %llu\n",
190			 rx_stats->other_msdu_count);
191	len += scnprintf(buf + len, size - len, "Num of MSDUs part of AMPDU: %llu\n",
192			 rx_stats->ampdu_msdu_count);
193	len += scnprintf(buf + len, size - len, "Num of MSDUs not part of AMPDU: %llu\n",
194			 rx_stats->non_ampdu_msdu_count);
195	len += scnprintf(buf + len, size - len, "Num of MSDUs using STBC: %llu\n",
196			 rx_stats->stbc_count);
197	len += scnprintf(buf + len, size - len, "Num of MSDUs beamformed: %llu\n",
198			 rx_stats->beamformed_count);
199	len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS ok: %llu\n",
200			 rx_stats->num_mpdu_fcs_ok);
201	len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS error: %llu\n",
202			 rx_stats->num_mpdu_fcs_err);
203
204	he_rates_avail = (rx_stats->pream_cnt[HAL_RX_PREAMBLE_11AX] > 1) ? true : false;
205
206	len += scnprintf(buf + len, size - len,
207			 "preamble: 11A %llu 11B %llu 11N %llu 11AC %llu 11AX %llu 11BE %llu\n",
208			 rx_stats->pream_cnt[0], rx_stats->pream_cnt[1],
209			 rx_stats->pream_cnt[2], rx_stats->pream_cnt[3],
210			 rx_stats->pream_cnt[4], rx_stats->pream_cnt[6]);
211	len += scnprintf(buf + len, size - len,
212			 "reception type: SU %llu MU_MIMO %llu MU_OFDMA %llu MU_OFDMA_MIMO %llu\n",
213			 rx_stats->reception_type[0], rx_stats->reception_type[1],
214			 rx_stats->reception_type[2], rx_stats->reception_type[3]);
215
216	len += scnprintf(buf + len, size - len, "TID(0-15) Legacy TID(16):");
217	for (i = 0; i <= IEEE80211_NUM_TIDS; i++)
218		len += scnprintf(buf + len, size - len, "%llu ", rx_stats->tid_count[i]);
219
220	len += scnprintf(buf + len, size - len, "\nRX Duration:%llu\n",
221			 rx_stats->rx_duration);
222
223	len += scnprintf(buf + len, size - len,
224			 "\nDCM: %llu\nRU26:  %llu\nRU52:  %llu\nRU106: %llu\nRU242: %llu\nRU484: %llu\nRU996: %llu\nRU996x2: %llu\n",
225			 rx_stats->dcm_count, rx_stats->ru_alloc_cnt[0],
226			 rx_stats->ru_alloc_cnt[1], rx_stats->ru_alloc_cnt[2],
227			 rx_stats->ru_alloc_cnt[3], rx_stats->ru_alloc_cnt[4],
228			 rx_stats->ru_alloc_cnt[5], rx_stats->ru_alloc_cnt[6]);
229
230	len += scnprintf(buf + len, size - len, "\nRX success packet stats:\n");
231	len += ath12k_dbg_sta_dump_rate_stats(buf, len, size, he_rates_avail,
232					      &rx_stats->pkt_stats);
233
234	len += scnprintf(buf + len, size - len, "\n");
235
236	len += scnprintf(buf + len, size - len, "\nRX success byte stats:\n");
237	len += ath12k_dbg_sta_dump_rate_stats(buf, len, size, he_rates_avail,
238					      &rx_stats->byte_stats);
239
240unlock:
241	spin_unlock_bh(&ar->ab->base_lock);
242
243	if (len)
244		ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
245out:
246	wiphy_unlock(ah->hw->wiphy);
247	return ret;
248}
249
250static const struct file_operations fops_rx_stats = {
251	.read = ath12k_dbg_sta_dump_rx_stats,
252	.open = simple_open,
253	.owner = THIS_MODULE,
254	.llseek = default_llseek,
255};
256
257static ssize_t ath12k_dbg_sta_reset_rx_stats(struct file *file,
258					     const char __user *buf,
259					     size_t count, loff_t *ppos)
260{
261	struct ieee80211_link_sta *link_sta = file->private_data;
262	struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(link_sta->sta);
263	struct ath12k_hw *ah = ahsta->ahvif->ah;
264	struct ath12k_rx_peer_stats *rx_stats;
265	struct ath12k_link_sta *arsta;
266	u8 link_id = link_sta->link_id;
267	struct ath12k *ar;
268	bool reset;
269	int ret;
270
271	ret = kstrtobool_from_user(buf, count, &reset);
272	if (ret)
273		return ret;
274
275	if (!reset)
276		return -EINVAL;
277
278	wiphy_lock(ah->hw->wiphy);
279
280	if (!(BIT(link_id) & ahsta->links_map)) {
281		ret = -ENOENT;
282		goto out;
283	}
284
285	arsta = wiphy_dereference(ah->hw->wiphy, ahsta->link[link_id]);
286	if (!arsta || !arsta->arvif->ar) {
287		ret = -ENOENT;
288		goto out;
289	}
290
291	ar = arsta->arvif->ar;
292
293	spin_lock_bh(&ar->ab->base_lock);
294
295	rx_stats = arsta->rx_stats;
296	if (!rx_stats) {
297		spin_unlock_bh(&ar->ab->base_lock);
298		ret = -ENOENT;
299		goto out;
300	}
301
302	memset(rx_stats, 0, sizeof(*rx_stats));
303	spin_unlock_bh(&ar->ab->base_lock);
304
305	ret = count;
306out:
307	wiphy_unlock(ah->hw->wiphy);
308	return ret;
309}
310
311static const struct file_operations fops_reset_rx_stats = {
312	.write = ath12k_dbg_sta_reset_rx_stats,
313	.open = simple_open,
314	.owner = THIS_MODULE,
315	.llseek = default_llseek,
316};
317
318void ath12k_debugfs_link_sta_op_add(struct ieee80211_hw *hw,
319				    struct ieee80211_vif *vif,
320				    struct ieee80211_link_sta *link_sta,
321				    struct dentry *dir)
322{
323	struct ath12k *ar;
324
325	lockdep_assert_wiphy(hw->wiphy);
326
327	ar = ath12k_get_ar_by_vif(hw, vif, link_sta->link_id);
328	if (!ar)
329		return;
330
331	if (ath12k_debugfs_is_extd_rx_stats_enabled(ar)) {
332		debugfs_create_file("rx_stats", 0400, dir, link_sta,
333				    &fops_rx_stats);
334		debugfs_create_file("reset_rx_stats", 0200, dir, link_sta,
335				    &fops_reset_rx_stats);
336	}
337}
~/ Read-only file preview.