File Index
Files and directories
Sign in
FILE

debugfs_sta.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/ath/ath11k/debugfs_sta.c C
  1// SPDX-License-Identifier: BSD-3-Clause-Clear
  2/*
  3 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
  4 * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  5 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
  6 */
  7
  8#include <linux/vmalloc.h>
  9
 10#include "debugfs_sta.h"
 11#include "core.h"
 12#include "peer.h"
 13#include "debug.h"
 14#include "dp_tx.h"
 15#include "debugfs_htt_stats.h"
 16
 17void ath11k_debugfs_sta_add_tx_stats(struct ath11k_sta *arsta,
 18				     struct ath11k_per_peer_tx_stats *peer_stats,
 19				     u8 legacy_rate_idx)
 20{
 21	struct rate_info *txrate = &arsta->txrate;
 22	struct ath11k_htt_tx_stats *tx_stats;
 23	int gi, mcs, bw, nss;
 24
 25	if (!arsta->tx_stats)
 26		return;
 27
 28	tx_stats = arsta->tx_stats;
 29	gi = FIELD_GET(RATE_INFO_FLAGS_SHORT_GI, arsta->txrate.flags);
 30	mcs = txrate->mcs;
 31	bw = ath11k_mac_mac80211_bw_to_ath11k_bw(txrate->bw);
 32	nss = txrate->nss - 1;
 33
 34#define STATS_OP_FMT(name) tx_stats->stats[ATH11K_STATS_TYPE_##name]
 35
 36	if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
 37		STATS_OP_FMT(SUCC).he[0][mcs] += peer_stats->succ_bytes;
 38		STATS_OP_FMT(SUCC).he[1][mcs] += peer_stats->succ_pkts;
 39		STATS_OP_FMT(FAIL).he[0][mcs] += peer_stats->failed_bytes;
 40		STATS_OP_FMT(FAIL).he[1][mcs] += peer_stats->failed_pkts;
 41		STATS_OP_FMT(RETRY).he[0][mcs] += peer_stats->retry_bytes;
 42		STATS_OP_FMT(RETRY).he[1][mcs] += peer_stats->retry_pkts;
 43	} else if (txrate->flags & RATE_INFO_FLAGS_VHT_MCS) {
 44		STATS_OP_FMT(SUCC).vht[0][mcs] += peer_stats->succ_bytes;
 45		STATS_OP_FMT(SUCC).vht[1][mcs] += peer_stats->succ_pkts;
 46		STATS_OP_FMT(FAIL).vht[0][mcs] += peer_stats->failed_bytes;
 47		STATS_OP_FMT(FAIL).vht[1][mcs] += peer_stats->failed_pkts;
 48		STATS_OP_FMT(RETRY).vht[0][mcs] += peer_stats->retry_bytes;
 49		STATS_OP_FMT(RETRY).vht[1][mcs] += peer_stats->retry_pkts;
 50	} else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
 51		STATS_OP_FMT(SUCC).ht[0][mcs] += peer_stats->succ_bytes;
 52		STATS_OP_FMT(SUCC).ht[1][mcs] += peer_stats->succ_pkts;
 53		STATS_OP_FMT(FAIL).ht[0][mcs] += peer_stats->failed_bytes;
 54		STATS_OP_FMT(FAIL).ht[1][mcs] += peer_stats->failed_pkts;
 55		STATS_OP_FMT(RETRY).ht[0][mcs] += peer_stats->retry_bytes;
 56		STATS_OP_FMT(RETRY).ht[1][mcs] += peer_stats->retry_pkts;
 57	} else {
 58		mcs = legacy_rate_idx;
 59
 60		STATS_OP_FMT(SUCC).legacy[0][mcs] += peer_stats->succ_bytes;
 61		STATS_OP_FMT(SUCC).legacy[1][mcs] += peer_stats->succ_pkts;
 62		STATS_OP_FMT(FAIL).legacy[0][mcs] += peer_stats->failed_bytes;
 63		STATS_OP_FMT(FAIL).legacy[1][mcs] += peer_stats->failed_pkts;
 64		STATS_OP_FMT(RETRY).legacy[0][mcs] += peer_stats->retry_bytes;
 65		STATS_OP_FMT(RETRY).legacy[1][mcs] += peer_stats->retry_pkts;
 66	}
 67
 68	if (peer_stats->is_ampdu) {
 69		tx_stats->ba_fails += peer_stats->ba_fails;
 70
 71		if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
 72			STATS_OP_FMT(AMPDU).he[0][mcs] +=
 73			peer_stats->succ_bytes + peer_stats->retry_bytes;
 74			STATS_OP_FMT(AMPDU).he[1][mcs] +=
 75			peer_stats->succ_pkts + peer_stats->retry_pkts;
 76		} else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
 77			STATS_OP_FMT(AMPDU).ht[0][mcs] +=
 78			peer_stats->succ_bytes + peer_stats->retry_bytes;
 79			STATS_OP_FMT(AMPDU).ht[1][mcs] +=
 80			peer_stats->succ_pkts + peer_stats->retry_pkts;
 81		} else {
 82			STATS_OP_FMT(AMPDU).vht[0][mcs] +=
 83			peer_stats->succ_bytes + peer_stats->retry_bytes;
 84			STATS_OP_FMT(AMPDU).vht[1][mcs] +=
 85			peer_stats->succ_pkts + peer_stats->retry_pkts;
 86		}
 87		STATS_OP_FMT(AMPDU).bw[0][bw] +=
 88			peer_stats->succ_bytes + peer_stats->retry_bytes;
 89		STATS_OP_FMT(AMPDU).nss[0][nss] +=
 90			peer_stats->succ_bytes + peer_stats->retry_bytes;
 91		STATS_OP_FMT(AMPDU).gi[0][gi] +=
 92			peer_stats->succ_bytes + peer_stats->retry_bytes;
 93		STATS_OP_FMT(AMPDU).bw[1][bw] +=
 94			peer_stats->succ_pkts + peer_stats->retry_pkts;
 95		STATS_OP_FMT(AMPDU).nss[1][nss] +=
 96			peer_stats->succ_pkts + peer_stats->retry_pkts;
 97		STATS_OP_FMT(AMPDU).gi[1][gi] +=
 98			peer_stats->succ_pkts + peer_stats->retry_pkts;
 99	} else {
100		tx_stats->ack_fails += peer_stats->ba_fails;
101	}
102
103	STATS_OP_FMT(SUCC).bw[0][bw] += peer_stats->succ_bytes;
104	STATS_OP_FMT(SUCC).nss[0][nss] += peer_stats->succ_bytes;
105	STATS_OP_FMT(SUCC).gi[0][gi] += peer_stats->succ_bytes;
106
107	STATS_OP_FMT(SUCC).bw[1][bw] += peer_stats->succ_pkts;
108	STATS_OP_FMT(SUCC).nss[1][nss] += peer_stats->succ_pkts;
109	STATS_OP_FMT(SUCC).gi[1][gi] += peer_stats->succ_pkts;
110
111	STATS_OP_FMT(FAIL).bw[0][bw] += peer_stats->failed_bytes;
112	STATS_OP_FMT(FAIL).nss[0][nss] += peer_stats->failed_bytes;
113	STATS_OP_FMT(FAIL).gi[0][gi] += peer_stats->failed_bytes;
114
115	STATS_OP_FMT(FAIL).bw[1][bw] += peer_stats->failed_pkts;
116	STATS_OP_FMT(FAIL).nss[1][nss] += peer_stats->failed_pkts;
117	STATS_OP_FMT(FAIL).gi[1][gi] += peer_stats->failed_pkts;
118
119	STATS_OP_FMT(RETRY).bw[0][bw] += peer_stats->retry_bytes;
120	STATS_OP_FMT(RETRY).nss[0][nss] += peer_stats->retry_bytes;
121	STATS_OP_FMT(RETRY).gi[0][gi] += peer_stats->retry_bytes;
122
123	STATS_OP_FMT(RETRY).bw[1][bw] += peer_stats->retry_pkts;
124	STATS_OP_FMT(RETRY).nss[1][nss] += peer_stats->retry_pkts;
125	STATS_OP_FMT(RETRY).gi[1][gi] += peer_stats->retry_pkts;
126
127	tx_stats->tx_duration += peer_stats->duration;
128}
129
130void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar,
131				       struct hal_tx_status *ts)
132{
133	ath11k_dp_tx_update_txcompl(ar, ts);
134}
135
136static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file,
137					    char __user *user_buf,
138					    size_t count, loff_t *ppos)
139{
140	struct ieee80211_sta *sta = file->private_data;
141	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
142	struct ath11k *ar = arsta->arvif->ar;
143	struct ath11k_htt_data_stats *stats;
144	static const char *str_name[ATH11K_STATS_TYPE_MAX] = {"succ", "fail",
145							      "retry", "ampdu"};
146	static const char *str[ATH11K_COUNTER_TYPE_MAX] = {"bytes", "packets"};
147	int len = 0, i, j, k, retval = 0;
148	const int size = 2 * 4096;
149	char *buf;
150
151	if (!arsta->tx_stats)
152		return -ENOENT;
153
154	buf = kzalloc(size, GFP_KERNEL);
155	if (!buf)
156		return -ENOMEM;
157
158	mutex_lock(&ar->conf_mutex);
159
160	spin_lock_bh(&ar->data_lock);
161	for (k = 0; k < ATH11K_STATS_TYPE_MAX; k++) {
162		for (j = 0; j < ATH11K_COUNTER_TYPE_MAX; j++) {
163			stats = &arsta->tx_stats->stats[k];
164			len += scnprintf(buf + len, size - len, "%s_%s\n",
165					 str_name[k],
166					 str[j]);
167			len += scnprintf(buf + len, size - len,
168					 " HE MCS %s\n",
169					 str[j]);
170			for (i = 0; i < ATH11K_HE_MCS_NUM; i++)
171				len += scnprintf(buf + len, size - len,
172						 "  %llu ",
173						 stats->he[j][i]);
174			len += scnprintf(buf + len, size - len, "\n");
175			len += scnprintf(buf + len, size - len,
176					 " VHT MCS %s\n",
177					 str[j]);
178			for (i = 0; i < ATH11K_VHT_MCS_NUM; i++)
179				len += scnprintf(buf + len, size - len,
180						 "  %llu ",
181						 stats->vht[j][i]);
182			len += scnprintf(buf + len, size - len, "\n");
183			len += scnprintf(buf + len, size - len, " HT MCS %s\n",
184					 str[j]);
185			for (i = 0; i < ATH11K_HT_MCS_NUM; i++)
186				len += scnprintf(buf + len, size - len,
187						 "  %llu ", stats->ht[j][i]);
188			len += scnprintf(buf + len, size - len, "\n");
189			len += scnprintf(buf + len, size - len,
190					" BW %s (20,40,80,160 MHz)\n", str[j]);
191			len += scnprintf(buf + len, size - len,
192					 "  %llu %llu %llu %llu\n",
193					 stats->bw[j][0], stats->bw[j][1],
194					 stats->bw[j][2], stats->bw[j][3]);
195			len += scnprintf(buf + len, size - len,
196					 " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]);
197			len += scnprintf(buf + len, size - len,
198					 "  %llu %llu %llu %llu\n",
199					 stats->nss[j][0], stats->nss[j][1],
200					 stats->nss[j][2], stats->nss[j][3]);
201			len += scnprintf(buf + len, size - len,
202					 " GI %s (0.4us,0.8us,1.6us,3.2us)\n",
203					 str[j]);
204			len += scnprintf(buf + len, size - len,
205					 "  %llu %llu %llu %llu\n",
206					 stats->gi[j][0], stats->gi[j][1],
207					 stats->gi[j][2], stats->gi[j][3]);
208			len += scnprintf(buf + len, size - len,
209					 " legacy rate %s (1,2 ... Mbps)\n  ",
210					 str[j]);
211			for (i = 0; i < ATH11K_LEGACY_NUM; i++)
212				len += scnprintf(buf + len, size - len, "%llu ",
213						 stats->legacy[j][i]);
214			len += scnprintf(buf + len, size - len, "\n");
215		}
216	}
217
218	len += scnprintf(buf + len, size - len,
219			 "\nTX duration\n %llu usecs\n",
220			 arsta->tx_stats->tx_duration);
221	len += scnprintf(buf + len, size - len,
222			"BA fails\n %llu\n", arsta->tx_stats->ba_fails);
223	len += scnprintf(buf + len, size - len,
224			"ack fails\n %llu\n", arsta->tx_stats->ack_fails);
225	spin_unlock_bh(&ar->data_lock);
226
227	if (len > size)
228		len = size;
229	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
230	kfree(buf);
231
232	mutex_unlock(&ar->conf_mutex);
233	return retval;
234}
235
236static const struct file_operations fops_tx_stats = {
237	.read = ath11k_dbg_sta_dump_tx_stats,
238	.open = simple_open,
239	.owner = THIS_MODULE,
240	.llseek = default_llseek,
241};
242
243static ssize_t ath11k_dbg_sta_dump_rx_stats(struct file *file,
244					    char __user *user_buf,
245					    size_t count, loff_t *ppos)
246{
247	struct ieee80211_sta *sta = file->private_data;
248	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
249	struct ath11k *ar = arsta->arvif->ar;
250	struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;
251	int len = 0, i, retval = 0;
252	const int size = 4096;
253	char *buf;
254
255	if (!rx_stats)
256		return -ENOENT;
257
258	buf = kzalloc(size, GFP_KERNEL);
259	if (!buf)
260		return -ENOMEM;
261
262	mutex_lock(&ar->conf_mutex);
263	spin_lock_bh(&ar->ab->base_lock);
264
265	len += scnprintf(buf + len, size - len, "RX peer stats:\n");
266	len += scnprintf(buf + len, size - len, "Num of MSDUs: %llu\n",
267			 rx_stats->num_msdu);
268	len += scnprintf(buf + len, size - len, "Num of MSDUs with TCP L4: %llu\n",
269			 rx_stats->tcp_msdu_count);
270	len += scnprintf(buf + len, size - len, "Num of MSDUs with UDP L4: %llu\n",
271			 rx_stats->udp_msdu_count);
272	len += scnprintf(buf + len, size - len, "Num of MSDUs part of AMPDU: %llu\n",
273			 rx_stats->ampdu_msdu_count);
274	len += scnprintf(buf + len, size - len, "Num of MSDUs not part of AMPDU: %llu\n",
275			 rx_stats->non_ampdu_msdu_count);
276	len += scnprintf(buf + len, size - len, "Num of MSDUs using STBC: %llu\n",
277			 rx_stats->stbc_count);
278	len += scnprintf(buf + len, size - len, "Num of MSDUs beamformed: %llu\n",
279			 rx_stats->beamformed_count);
280	len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS ok: %llu\n",
281			 rx_stats->num_mpdu_fcs_ok);
282	len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS error: %llu\n",
283			 rx_stats->num_mpdu_fcs_err);
284	len += scnprintf(buf + len, size - len,
285			 "GI: 0.8us %llu 0.4us %llu 1.6us %llu 3.2us %llu\n",
286			 rx_stats->gi_count[0], rx_stats->gi_count[1],
287			 rx_stats->gi_count[2], rx_stats->gi_count[3]);
288	len += scnprintf(buf + len, size - len,
289			 "BW: 20Mhz %llu 40Mhz %llu 80Mhz %llu 160Mhz %llu\n",
290			 rx_stats->bw_count[0], rx_stats->bw_count[1],
291			 rx_stats->bw_count[2], rx_stats->bw_count[3]);
292	len += scnprintf(buf + len, size - len, "BCC %llu LDPC %llu\n",
293			 rx_stats->coding_count[0], rx_stats->coding_count[1]);
294	len += scnprintf(buf + len, size - len,
295			 "preamble: 11A %llu 11B %llu 11N %llu 11AC %llu 11AX %llu\n",
296			 rx_stats->pream_cnt[0], rx_stats->pream_cnt[1],
297			 rx_stats->pream_cnt[2], rx_stats->pream_cnt[3],
298			 rx_stats->pream_cnt[4]);
299	len += scnprintf(buf + len, size - len,
300			 "reception type: SU %llu MU_MIMO %llu MU_OFDMA %llu MU_OFDMA_MIMO %llu\n",
301			 rx_stats->reception_type[0], rx_stats->reception_type[1],
302			 rx_stats->reception_type[2], rx_stats->reception_type[3]);
303	len += scnprintf(buf + len, size - len, "TID(0-15) Legacy TID(16):");
304	for (i = 0; i <= IEEE80211_NUM_TIDS; i++)
305		len += scnprintf(buf + len, size - len, "%llu ", rx_stats->tid_count[i]);
306	len += scnprintf(buf + len, size - len, "\nMCS(0-11) Legacy MCS(12):");
307	for (i = 0; i < HAL_RX_MAX_MCS + 1; i++)
308		len += scnprintf(buf + len, size - len, "%llu ", rx_stats->mcs_count[i]);
309	len += scnprintf(buf + len, size - len, "\nNSS(1-8):");
310	for (i = 0; i < HAL_RX_MAX_NSS; i++)
311		len += scnprintf(buf + len, size - len, "%llu ", rx_stats->nss_count[i]);
312	len += scnprintf(buf + len, size - len, "\nRX Duration:%llu ",
313			 rx_stats->rx_duration);
314	len += scnprintf(buf + len, size - len,
315			 "\nDCM: %llu\nRU: 26 %llu 52: %llu 106: %llu 242: %llu 484: %llu 996: %llu\n",
316			 rx_stats->dcm_count, rx_stats->ru_alloc_cnt[0],
317			 rx_stats->ru_alloc_cnt[1], rx_stats->ru_alloc_cnt[2],
318			 rx_stats->ru_alloc_cnt[3], rx_stats->ru_alloc_cnt[4],
319			 rx_stats->ru_alloc_cnt[5]);
320
321	len += scnprintf(buf + len, size - len, "\n");
322
323	spin_unlock_bh(&ar->ab->base_lock);
324
325	if (len > size)
326		len = size;
327	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
328	kfree(buf);
329
330	mutex_unlock(&ar->conf_mutex);
331	return retval;
332}
333
334static const struct file_operations fops_rx_stats = {
335	.read = ath11k_dbg_sta_dump_rx_stats,
336	.open = simple_open,
337	.owner = THIS_MODULE,
338	.llseek = default_llseek,
339};
340
341static int
342ath11k_dbg_sta_open_htt_peer_stats(struct inode *inode, struct file *file)
343{
344	struct ieee80211_sta *sta = inode->i_private;
345	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
346	struct ath11k *ar = arsta->arvif->ar;
347	struct debug_htt_stats_req *stats_req;
348	int type = ar->debug.htt_stats.type;
349	int ret;
350
351	if ((type != ATH11K_DBG_HTT_EXT_STATS_PEER_INFO &&
352	     type != ATH11K_DBG_HTT_EXT_STATS_PEER_CTRL_PATH_TXRX_STATS) ||
353	    type == ATH11K_DBG_HTT_EXT_STATS_RESET)
354		return -EPERM;
355
356	stats_req = vzalloc(sizeof(*stats_req) + ATH11K_HTT_STATS_BUF_SIZE);
357	if (!stats_req)
358		return -ENOMEM;
359
360	mutex_lock(&ar->conf_mutex);
361	ar->debug.htt_stats.stats_req = stats_req;
362	stats_req->type = type;
363	memcpy(stats_req->peer_addr, sta->addr, ETH_ALEN);
364	ret = ath11k_debugfs_htt_stats_req(ar);
365	mutex_unlock(&ar->conf_mutex);
366	if (ret < 0)
367		goto out;
368
369	file->private_data = stats_req;
370	return 0;
371out:
372	vfree(stats_req);
373	ar->debug.htt_stats.stats_req = NULL;
374	return ret;
375}
376
377static int
378ath11k_dbg_sta_release_htt_peer_stats(struct inode *inode, struct file *file)
379{
380	struct ieee80211_sta *sta = inode->i_private;
381	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
382	struct ath11k *ar = arsta->arvif->ar;
383
384	mutex_lock(&ar->conf_mutex);
385	vfree(file->private_data);
386	ar->debug.htt_stats.stats_req = NULL;
387	mutex_unlock(&ar->conf_mutex);
388
389	return 0;
390}
391
392static ssize_t ath11k_dbg_sta_read_htt_peer_stats(struct file *file,
393						  char __user *user_buf,
394						  size_t count, loff_t *ppos)
395{
396	struct debug_htt_stats_req *stats_req = file->private_data;
397	char *buf;
398	u32 length = 0;
399
400	buf = stats_req->buf;
401	length = min_t(u32, stats_req->buf_len, ATH11K_HTT_STATS_BUF_SIZE);
402	return simple_read_from_buffer(user_buf, count, ppos, buf, length);
403}
404
405static const struct file_operations fops_htt_peer_stats = {
406	.open = ath11k_dbg_sta_open_htt_peer_stats,
407	.release = ath11k_dbg_sta_release_htt_peer_stats,
408	.read = ath11k_dbg_sta_read_htt_peer_stats,
409	.owner = THIS_MODULE,
410	.llseek = default_llseek,
411};
412
413static ssize_t ath11k_dbg_sta_write_peer_pktlog(struct file *file,
414						const char __user *buf,
415						size_t count, loff_t *ppos)
416{
417	struct ieee80211_sta *sta = file->private_data;
418	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
419	struct ath11k *ar = arsta->arvif->ar;
420	int ret, enable;
421
422	mutex_lock(&ar->conf_mutex);
423
424	if (ar->state != ATH11K_STATE_ON) {
425		ret = -ENETDOWN;
426		goto out;
427	}
428
429	ret = kstrtoint_from_user(buf, count, 0, &enable);
430	if (ret)
431		goto out;
432
433	ar->debug.pktlog_peer_valid = enable;
434	memcpy(ar->debug.pktlog_peer_addr, sta->addr, ETH_ALEN);
435
436	/* Send peer based pktlog enable/disable */
437	ret = ath11k_wmi_pdev_peer_pktlog_filter(ar, sta->addr, enable);
438	if (ret) {
439		ath11k_warn(ar->ab, "failed to set peer pktlog filter %pM: %d\n",
440			    sta->addr, ret);
441		goto out;
442	}
443
444	ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "peer pktlog filter set to %d\n",
445		   enable);
446	ret = count;
447
448out:
449	mutex_unlock(&ar->conf_mutex);
450	return ret;
451}
452
453static ssize_t ath11k_dbg_sta_read_peer_pktlog(struct file *file,
454					       char __user *ubuf,
455					       size_t count, loff_t *ppos)
456{
457	struct ieee80211_sta *sta = file->private_data;
458	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
459	struct ath11k *ar = arsta->arvif->ar;
460	char buf[32] = {};
461	int len;
462
463	mutex_lock(&ar->conf_mutex);
464	len = scnprintf(buf, sizeof(buf), "%08x %pM\n",
465			ar->debug.pktlog_peer_valid,
466			ar->debug.pktlog_peer_addr);
467	mutex_unlock(&ar->conf_mutex);
468
469	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
470}
471
472static const struct file_operations fops_peer_pktlog = {
473	.write = ath11k_dbg_sta_write_peer_pktlog,
474	.read = ath11k_dbg_sta_read_peer_pktlog,
475	.open = simple_open,
476	.owner = THIS_MODULE,
477	.llseek = default_llseek,
478};
479
480static ssize_t ath11k_dbg_sta_write_delba(struct file *file,
481					  const char __user *user_buf,
482					  size_t count, loff_t *ppos)
483{
484	struct ieee80211_sta *sta = file->private_data;
485	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
486	struct ath11k *ar = arsta->arvif->ar;
487	u32 tid, initiator, reason;
488	int ret;
489	char buf[64] = {};
490
491	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
492				     user_buf, count);
493	if (ret <= 0)
494		return ret;
495
496	ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);
497	if (ret != 3)
498		return -EINVAL;
499
500	/* Valid TID values are 0 through 15 */
501	if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
502		return -EINVAL;
503
504	mutex_lock(&ar->conf_mutex);
505	if (ar->state != ATH11K_STATE_ON ||
506	    arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
507		ret = count;
508		goto out;
509	}
510
511	ret = ath11k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,
512				    tid, initiator, reason);
513	if (ret) {
514		ath11k_warn(ar->ab, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",
515			    arsta->arvif->vdev_id, sta->addr, tid, initiator,
516			    reason);
517	}
518	ret = count;
519out:
520	mutex_unlock(&ar->conf_mutex);
521	return ret;
522}
523
524static const struct file_operations fops_delba = {
525	.write = ath11k_dbg_sta_write_delba,
526	.open = simple_open,
527	.owner = THIS_MODULE,
528	.llseek = default_llseek,
529};
530
531static ssize_t ath11k_dbg_sta_write_addba_resp(struct file *file,
532					       const char __user *user_buf,
533					       size_t count, loff_t *ppos)
534{
535	struct ieee80211_sta *sta = file->private_data;
536	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
537	struct ath11k *ar = arsta->arvif->ar;
538	u32 tid, status;
539	int ret;
540	char buf[64] = {};
541
542	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
543				     user_buf, count);
544	if (ret <= 0)
545		return ret;
546
547	ret = sscanf(buf, "%u %u", &tid, &status);
548	if (ret != 2)
549		return -EINVAL;
550
551	/* Valid TID values are 0 through 15 */
552	if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
553		return -EINVAL;
554
555	mutex_lock(&ar->conf_mutex);
556	if (ar->state != ATH11K_STATE_ON ||
557	    arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
558		ret = count;
559		goto out;
560	}
561
562	ret = ath11k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,
563					tid, status);
564	if (ret) {
565		ath11k_warn(ar->ab, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",
566			    arsta->arvif->vdev_id, sta->addr, tid, status);
567	}
568	ret = count;
569out:
570	mutex_unlock(&ar->conf_mutex);
571	return ret;
572}
573
574static const struct file_operations fops_addba_resp = {
575	.write = ath11k_dbg_sta_write_addba_resp,
576	.open = simple_open,
577	.owner = THIS_MODULE,
578	.llseek = default_llseek,
579};
580
581static ssize_t ath11k_dbg_sta_write_addba(struct file *file,
582					  const char __user *user_buf,
583					  size_t count, loff_t *ppos)
584{
585	struct ieee80211_sta *sta = file->private_data;
586	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
587	struct ath11k *ar = arsta->arvif->ar;
588	u32 tid, buf_size;
589	int ret;
590	char buf[64] = {};
591
592	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
593				     user_buf, count);
594	if (ret <= 0)
595		return ret;
596
597	ret = sscanf(buf, "%u %u", &tid, &buf_size);
598	if (ret != 2)
599		return -EINVAL;
600
601	/* Valid TID values are 0 through 15 */
602	if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
603		return -EINVAL;
604
605	mutex_lock(&ar->conf_mutex);
606	if (ar->state != ATH11K_STATE_ON ||
607	    arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
608		ret = count;
609		goto out;
610	}
611
612	ret = ath11k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,
613				    tid, buf_size);
614	if (ret) {
615		ath11k_warn(ar->ab, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",
616			    arsta->arvif->vdev_id, sta->addr, tid, buf_size);
617	}
618
619	ret = count;
620out:
621	mutex_unlock(&ar->conf_mutex);
622	return ret;
623}
624
625static const struct file_operations fops_addba = {
626	.write = ath11k_dbg_sta_write_addba,
627	.open = simple_open,
628	.owner = THIS_MODULE,
629	.llseek = default_llseek,
630};
631
632static ssize_t ath11k_dbg_sta_read_aggr_mode(struct file *file,
633					     char __user *user_buf,
634					     size_t count, loff_t *ppos)
635{
636	struct ieee80211_sta *sta = file->private_data;
637	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
638	struct ath11k *ar = arsta->arvif->ar;
639	char buf[64];
640	int len = 0;
641
642	mutex_lock(&ar->conf_mutex);
643	len = scnprintf(buf, sizeof(buf) - len,
644			"aggregation mode: %s\n\n%s\n%s\n",
645			(arsta->aggr_mode == ATH11K_DBG_AGGR_MODE_AUTO) ?
646			"auto" : "manual", "auto = 0", "manual = 1");
647	mutex_unlock(&ar->conf_mutex);
648
649	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
650}
651
652static ssize_t ath11k_dbg_sta_write_aggr_mode(struct file *file,
653					      const char __user *user_buf,
654					      size_t count, loff_t *ppos)
655{
656	struct ieee80211_sta *sta = file->private_data;
657	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
658	struct ath11k *ar = arsta->arvif->ar;
659	u32 aggr_mode;
660	int ret;
661
662	if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))
663		return -EINVAL;
664
665	if (aggr_mode >= ATH11K_DBG_AGGR_MODE_MAX)
666		return -EINVAL;
667
668	mutex_lock(&ar->conf_mutex);
669	if (ar->state != ATH11K_STATE_ON ||
670	    aggr_mode == arsta->aggr_mode) {
671		ret = count;
672		goto out;
673	}
674
675	ret = ath11k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);
676	if (ret) {
677		ath11k_warn(ar->ab, "failed to clear addba session ret: %d\n",
678			    ret);
679		goto out;
680	}
681
682	arsta->aggr_mode = aggr_mode;
683out:
684	mutex_unlock(&ar->conf_mutex);
685	return ret;
686}
687
688static const struct file_operations fops_aggr_mode = {
689	.read = ath11k_dbg_sta_read_aggr_mode,
690	.write = ath11k_dbg_sta_write_aggr_mode,
691	.open = simple_open,
692	.owner = THIS_MODULE,
693	.llseek = default_llseek,
694};
695
696static ssize_t
697ath11k_write_htt_peer_stats_reset(struct file *file,
698				  const char __user *user_buf,
699				  size_t count, loff_t *ppos)
700{
701	struct ieee80211_sta *sta = file->private_data;
702	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
703	struct ath11k *ar = arsta->arvif->ar;
704	struct htt_ext_stats_cfg_params cfg_params = {};
705	int ret;
706	u8 type;
707
708	ret = kstrtou8_from_user(user_buf, count, 0, &type);
709	if (ret)
710		return ret;
711
712	if (!type)
713		return ret;
714
715	mutex_lock(&ar->conf_mutex);
716	cfg_params.cfg0 = HTT_STAT_PEER_INFO_MAC_ADDR;
717	cfg_params.cfg0 |= FIELD_PREP(GENMASK(15, 1),
718				HTT_PEER_STATS_REQ_MODE_FLUSH_TQM);
719
720	cfg_params.cfg1 = HTT_STAT_DEFAULT_PEER_REQ_TYPE;
721
722	cfg_params.cfg2 |= FIELD_PREP(GENMASK(7, 0), sta->addr[0]);
723	cfg_params.cfg2 |= FIELD_PREP(GENMASK(15, 8), sta->addr[1]);
724	cfg_params.cfg2 |= FIELD_PREP(GENMASK(23, 16), sta->addr[2]);
725	cfg_params.cfg2 |= FIELD_PREP(GENMASK(31, 24), sta->addr[3]);
726
727	cfg_params.cfg3 |= FIELD_PREP(GENMASK(7, 0), sta->addr[4]);
728	cfg_params.cfg3 |= FIELD_PREP(GENMASK(15, 8), sta->addr[5]);
729
730	cfg_params.cfg3 |= ATH11K_HTT_PEER_STATS_RESET;
731
732	ret = ath11k_dp_tx_htt_h2t_ext_stats_req(ar,
733						 ATH11K_DBG_HTT_EXT_STATS_PEER_INFO,
734						 &cfg_params,
735						 0ULL);
736	if (ret) {
737		ath11k_warn(ar->ab, "failed to send htt peer stats request: %d\n", ret);
738		mutex_unlock(&ar->conf_mutex);
739		return ret;
740	}
741
742	mutex_unlock(&ar->conf_mutex);
743
744	ret = count;
745
746	return ret;
747}
748
749static const struct file_operations fops_htt_peer_stats_reset = {
750	.write = ath11k_write_htt_peer_stats_reset,
751	.open = simple_open,
752	.owner = THIS_MODULE,
753	.llseek = default_llseek,
754};
755
756static ssize_t ath11k_dbg_sta_read_peer_ps_state(struct file *file,
757						 char __user *user_buf,
758						 size_t count, loff_t *ppos)
759{
760	struct ieee80211_sta *sta = file->private_data;
761	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
762	struct ath11k *ar = arsta->arvif->ar;
763	char buf[20];
764	int len;
765
766	spin_lock_bh(&ar->data_lock);
767
768	len = scnprintf(buf, sizeof(buf), "%d\n", arsta->peer_ps_state);
769
770	spin_unlock_bh(&ar->data_lock);
771
772	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
773}
774
775static const struct file_operations fops_peer_ps_state = {
776	.open = simple_open,
777	.read = ath11k_dbg_sta_read_peer_ps_state,
778	.owner = THIS_MODULE,
779	.llseek = default_llseek,
780};
781
782static ssize_t ath11k_dbg_sta_read_current_ps_duration(struct file *file,
783						       char __user *user_buf,
784						       size_t count,
785						       loff_t *ppos)
786{
787	struct ieee80211_sta *sta = file->private_data;
788	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
789	struct ath11k *ar = arsta->arvif->ar;
790	u64 time_since_station_in_power_save;
791	char buf[20];
792	int len;
793
794	spin_lock_bh(&ar->data_lock);
795
796	if (arsta->peer_ps_state == WMI_PEER_PS_STATE_ON &&
797	    arsta->peer_current_ps_valid)
798		time_since_station_in_power_save = jiffies_to_msecs(jiffies
799						- arsta->ps_start_jiffies);
800	else
801		time_since_station_in_power_save = 0;
802
803	len = scnprintf(buf, sizeof(buf), "%llu\n",
804			time_since_station_in_power_save);
805	spin_unlock_bh(&ar->data_lock);
806
807	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
808}
809
810static const struct file_operations fops_current_ps_duration = {
811	.open = simple_open,
812	.read = ath11k_dbg_sta_read_current_ps_duration,
813	.owner = THIS_MODULE,
814	.llseek = default_llseek,
815};
816
817static ssize_t ath11k_dbg_sta_read_total_ps_duration(struct file *file,
818						     char __user *user_buf,
819						     size_t count, loff_t *ppos)
820{
821	struct ieee80211_sta *sta = file->private_data;
822	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
823	struct ath11k *ar = arsta->arvif->ar;
824	char buf[20];
825	u64 power_save_duration;
826	int len;
827
828	spin_lock_bh(&ar->data_lock);
829
830	if (arsta->peer_ps_state == WMI_PEER_PS_STATE_ON &&
831	    arsta->peer_current_ps_valid)
832		power_save_duration = jiffies_to_msecs(jiffies
833						- arsta->ps_start_jiffies)
834						+ arsta->ps_total_duration;
835	else
836		power_save_duration = arsta->ps_total_duration;
837
838	len = scnprintf(buf, sizeof(buf), "%llu\n", power_save_duration);
839
840	spin_unlock_bh(&ar->data_lock);
841
842	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
843}
844
845static const struct file_operations fops_total_ps_duration = {
846	.open = simple_open,
847	.read = ath11k_dbg_sta_read_total_ps_duration,
848	.owner = THIS_MODULE,
849	.llseek = default_llseek,
850};
851
852void ath11k_debugfs_sta_op_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
853			       struct ieee80211_sta *sta, struct dentry *dir)
854{
855	struct ath11k *ar = hw->priv;
856
857	if (ath11k_debugfs_is_extd_tx_stats_enabled(ar))
858		debugfs_create_file("tx_stats", 0400, dir, sta,
859				    &fops_tx_stats);
860	if (ath11k_debugfs_is_extd_rx_stats_enabled(ar))
861		debugfs_create_file("rx_stats", 0400, dir, sta,
862				    &fops_rx_stats);
863
864	debugfs_create_file("htt_peer_stats", 0400, dir, sta,
865			    &fops_htt_peer_stats);
866
867	debugfs_create_file("peer_pktlog", 0644, dir, sta,
868			    &fops_peer_pktlog);
869
870	debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode);
871	debugfs_create_file("addba", 0200, dir, sta, &fops_addba);
872	debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);
873	debugfs_create_file("delba", 0200, dir, sta, &fops_delba);
874
875	if (test_bit(WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET,
876		     ar->ab->wmi_ab.svc_map))
877		debugfs_create_file("htt_peer_stats_reset", 0600, dir, sta,
878				    &fops_htt_peer_stats_reset);
879
880	debugfs_create_file("peer_ps_state", 0400, dir, sta,
881			    &fops_peer_ps_state);
882
883	if (test_bit(WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT,
884		     ar->ab->wmi_ab.svc_map)) {
885		debugfs_create_file("current_ps_duration", 0440, dir, sta,
886				    &fops_current_ps_duration);
887		debugfs_create_file("total_ps_duration", 0440, dir, sta,
888				    &fops_total_ps_duration);
889	}
890}
~/ Read-only file preview.