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