File Index
Files and directories
Sign in
FILE

debugfs_sta.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/ath/ath10k/debugfs_sta.c C
  1// SPDX-License-Identifier: ISC
  2/*
  3 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
  4 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  5 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  6 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
  7 */
  8
  9#include "core.h"
 10#include "wmi-ops.h"
 11#include "txrx.h"
 12#include "debug.h"
 13
 14static void ath10k_rx_stats_update_amsdu_subfrm(struct ath10k *ar,
 15						struct ath10k_sta_tid_stats *stats,
 16						u32 msdu_count)
 17{
 18	if (msdu_count == 1)
 19		stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_1]++;
 20	else if (msdu_count == 2)
 21		stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_2]++;
 22	else if (msdu_count == 3)
 23		stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_3]++;
 24	else if (msdu_count == 4)
 25		stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_4]++;
 26	else if (msdu_count > 4)
 27		stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MORE]++;
 28}
 29
 30static void ath10k_rx_stats_update_ampdu_subfrm(struct ath10k *ar,
 31						struct ath10k_sta_tid_stats *stats,
 32						u32 mpdu_count)
 33{
 34	if (mpdu_count <= 10)
 35		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_10]++;
 36	else if (mpdu_count <= 20)
 37		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_20]++;
 38	else if (mpdu_count <= 30)
 39		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_30]++;
 40	else if (mpdu_count <= 40)
 41		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_40]++;
 42	else if (mpdu_count <= 50)
 43		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_50]++;
 44	else if (mpdu_count <= 60)
 45		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_60]++;
 46	else if (mpdu_count > 60)
 47		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_MORE]++;
 48}
 49
 50void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar, u16 peer_id, u8 tid,
 51					  struct htt_rx_indication_mpdu_range *ranges,
 52					  int num_ranges)
 53{
 54	struct ath10k_sta *arsta;
 55	struct ath10k_peer *peer;
 56	int i;
 57
 58	if (tid > IEEE80211_NUM_TIDS || !(ar->sta_tid_stats_mask & BIT(tid)))
 59		return;
 60
 61	rcu_read_lock();
 62	spin_lock_bh(&ar->data_lock);
 63
 64	peer = ath10k_peer_find_by_id(ar, peer_id);
 65	if (!peer || !peer->sta)
 66		goto out;
 67
 68	arsta = (struct ath10k_sta *)peer->sta->drv_priv;
 69
 70	for (i = 0; i < num_ranges; i++)
 71		ath10k_rx_stats_update_ampdu_subfrm(ar,
 72						    &arsta->tid_stats[tid],
 73						    ranges[i].mpdu_count);
 74
 75out:
 76	spin_unlock_bh(&ar->data_lock);
 77	rcu_read_unlock();
 78}
 79
 80void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr,
 81				    unsigned long num_msdus,
 82				    enum ath10k_pkt_rx_err err,
 83				    unsigned long unchain_cnt,
 84				    unsigned long drop_cnt,
 85				    unsigned long drop_cnt_filter,
 86				    unsigned long queued_msdus)
 87{
 88	struct ieee80211_sta *sta;
 89	struct ath10k_sta *arsta;
 90	struct ieee80211_hdr *hdr;
 91	struct ath10k_sta_tid_stats *stats;
 92	u8 tid = IEEE80211_NUM_TIDS;
 93	bool non_data_frm = false;
 94
 95	hdr = (struct ieee80211_hdr *)first_hdr;
 96	if (!ieee80211_is_data(hdr->frame_control))
 97		non_data_frm = true;
 98
 99	if (ieee80211_is_data_qos(hdr->frame_control))
100		tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
101
102	if (!(ar->sta_tid_stats_mask & BIT(tid)) || non_data_frm)
103		return;
104
105	rcu_read_lock();
106
107	sta = ieee80211_find_sta_by_ifaddr(ar->hw, hdr->addr2, NULL);
108	if (!sta)
109		goto exit;
110
111	arsta = (struct ath10k_sta *)sta->drv_priv;
112
113	spin_lock_bh(&ar->data_lock);
114	stats = &arsta->tid_stats[tid];
115	stats->rx_pkt_from_fw += num_msdus;
116	stats->rx_pkt_unchained += unchain_cnt;
117	stats->rx_pkt_drop_chained += drop_cnt;
118	stats->rx_pkt_drop_filter += drop_cnt_filter;
119	if (err != ATH10K_PKT_RX_ERR_MAX)
120		stats->rx_pkt_err[err] += queued_msdus;
121	stats->rx_pkt_queued_for_mac += queued_msdus;
122	ath10k_rx_stats_update_amsdu_subfrm(ar, &arsta->tid_stats[tid],
123					    num_msdus);
124	spin_unlock_bh(&ar->data_lock);
125
126exit:
127	rcu_read_unlock();
128}
129
130static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar,
131						     struct ath10k_fw_stats *stats)
132{
133	struct ath10k_fw_extd_stats_peer *peer;
134	struct ieee80211_sta *sta;
135	struct ath10k_sta *arsta;
136
137	rcu_read_lock();
138	list_for_each_entry(peer, &stats->peers_extd, list) {
139		sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,
140						   NULL);
141		if (!sta)
142			continue;
143		arsta = (struct ath10k_sta *)sta->drv_priv;
144		arsta->rx_duration += (u64)peer->rx_duration;
145	}
146	rcu_read_unlock();
147}
148
149static void ath10k_sta_update_stats_rx_duration(struct ath10k *ar,
150						struct ath10k_fw_stats *stats)
151{
152	struct ath10k_fw_stats_peer *peer;
153	struct ieee80211_sta *sta;
154	struct ath10k_sta *arsta;
155
156	rcu_read_lock();
157	list_for_each_entry(peer, &stats->peers, list) {
158		sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,
159						   NULL);
160		if (!sta)
161			continue;
162		arsta = (struct ath10k_sta *)sta->drv_priv;
163		arsta->rx_duration += (u64)peer->rx_duration;
164	}
165	rcu_read_unlock();
166}
167
168void ath10k_sta_update_rx_duration(struct ath10k *ar,
169				   struct ath10k_fw_stats *stats)
170{
171	if (stats->extended)
172		ath10k_sta_update_extd_stats_rx_duration(ar, stats);
173	else
174		ath10k_sta_update_stats_rx_duration(ar, stats);
175}
176
177static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
178					     char __user *user_buf,
179					     size_t count, loff_t *ppos)
180{
181	struct ieee80211_sta *sta = file->private_data;
182	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
183	struct ath10k *ar = arsta->arvif->ar;
184	char buf[32];
185	int len = 0;
186
187	mutex_lock(&ar->conf_mutex);
188	len = scnprintf(buf, sizeof(buf) - len, "aggregation mode: %s\n",
189			(arsta->aggr_mode == ATH10K_DBG_AGGR_MODE_AUTO) ?
190			"auto" : "manual");
191	mutex_unlock(&ar->conf_mutex);
192
193	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
194}
195
196static ssize_t ath10k_dbg_sta_write_aggr_mode(struct file *file,
197					      const char __user *user_buf,
198					      size_t count, loff_t *ppos)
199{
200	struct ieee80211_sta *sta = file->private_data;
201	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
202	struct ath10k *ar = arsta->arvif->ar;
203	u32 aggr_mode;
204	int ret;
205
206	if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))
207		return -EINVAL;
208
209	if (aggr_mode >= ATH10K_DBG_AGGR_MODE_MAX)
210		return -EINVAL;
211
212	mutex_lock(&ar->conf_mutex);
213	if ((ar->state != ATH10K_STATE_ON) ||
214	    (aggr_mode == arsta->aggr_mode)) {
215		ret = count;
216		goto out;
217	}
218
219	ret = ath10k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);
220	if (ret) {
221		ath10k_warn(ar, "failed to clear addba session ret: %d\n", ret);
222		goto out;
223	}
224
225	arsta->aggr_mode = aggr_mode;
226out:
227	mutex_unlock(&ar->conf_mutex);
228	return ret;
229}
230
231static const struct file_operations fops_aggr_mode = {
232	.read = ath10k_dbg_sta_read_aggr_mode,
233	.write = ath10k_dbg_sta_write_aggr_mode,
234	.open = simple_open,
235	.owner = THIS_MODULE,
236	.llseek = default_llseek,
237};
238
239static ssize_t ath10k_dbg_sta_write_addba(struct file *file,
240					  const char __user *user_buf,
241					  size_t count, loff_t *ppos)
242{
243	struct ieee80211_sta *sta = file->private_data;
244	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
245	struct ath10k *ar = arsta->arvif->ar;
246	u32 tid, buf_size;
247	int ret;
248	char buf[64] = {};
249
250	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
251				     user_buf, count);
252	if (ret <= 0)
253		return ret;
254
255	ret = sscanf(buf, "%u %u", &tid, &buf_size);
256	if (ret != 2)
257		return -EINVAL;
258
259	/* Valid TID values are 0 through 15 */
260	if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
261		return -EINVAL;
262
263	mutex_lock(&ar->conf_mutex);
264	if ((ar->state != ATH10K_STATE_ON) ||
265	    (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
266		ret = count;
267		goto out;
268	}
269
270	ret = ath10k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,
271				    tid, buf_size);
272	if (ret) {
273		ath10k_warn(ar, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",
274			    arsta->arvif->vdev_id, sta->addr, tid, buf_size);
275	}
276
277	ret = count;
278out:
279	mutex_unlock(&ar->conf_mutex);
280	return ret;
281}
282
283static const struct file_operations fops_addba = {
284	.write = ath10k_dbg_sta_write_addba,
285	.open = simple_open,
286	.owner = THIS_MODULE,
287	.llseek = default_llseek,
288};
289
290static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file,
291					       const char __user *user_buf,
292					       size_t count, loff_t *ppos)
293{
294	struct ieee80211_sta *sta = file->private_data;
295	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
296	struct ath10k *ar = arsta->arvif->ar;
297	u32 tid, status;
298	int ret;
299	char buf[64] = {};
300
301	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
302				     user_buf, count);
303	if (ret <= 0)
304		return ret;
305
306	ret = sscanf(buf, "%u %u", &tid, &status);
307	if (ret != 2)
308		return -EINVAL;
309
310	/* Valid TID values are 0 through 15 */
311	if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
312		return -EINVAL;
313
314	mutex_lock(&ar->conf_mutex);
315	if ((ar->state != ATH10K_STATE_ON) ||
316	    (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
317		ret = count;
318		goto out;
319	}
320
321	ret = ath10k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,
322					tid, status);
323	if (ret) {
324		ath10k_warn(ar, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",
325			    arsta->arvif->vdev_id, sta->addr, tid, status);
326	}
327	ret = count;
328out:
329	mutex_unlock(&ar->conf_mutex);
330	return ret;
331}
332
333static const struct file_operations fops_addba_resp = {
334	.write = ath10k_dbg_sta_write_addba_resp,
335	.open = simple_open,
336	.owner = THIS_MODULE,
337	.llseek = default_llseek,
338};
339
340static ssize_t ath10k_dbg_sta_write_delba(struct file *file,
341					  const char __user *user_buf,
342					  size_t count, loff_t *ppos)
343{
344	struct ieee80211_sta *sta = file->private_data;
345	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
346	struct ath10k *ar = arsta->arvif->ar;
347	u32 tid, initiator, reason;
348	int ret;
349	char buf[64] = {};
350
351	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
352				     user_buf, count);
353	if (ret <= 0)
354		return ret;
355
356	ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);
357	if (ret != 3)
358		return -EINVAL;
359
360	/* Valid TID values are 0 through 15 */
361	if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
362		return -EINVAL;
363
364	mutex_lock(&ar->conf_mutex);
365	if ((ar->state != ATH10K_STATE_ON) ||
366	    (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
367		ret = count;
368		goto out;
369	}
370
371	ret = ath10k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,
372				    tid, initiator, reason);
373	if (ret) {
374		ath10k_warn(ar, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",
375			    arsta->arvif->vdev_id, sta->addr, tid, initiator,
376			    reason);
377	}
378	ret = count;
379out:
380	mutex_unlock(&ar->conf_mutex);
381	return ret;
382}
383
384static const struct file_operations fops_delba = {
385	.write = ath10k_dbg_sta_write_delba,
386	.open = simple_open,
387	.owner = THIS_MODULE,
388	.llseek = default_llseek,
389};
390
391static ssize_t ath10k_dbg_sta_read_peer_debug_trigger(struct file *file,
392						      char __user *user_buf,
393						      size_t count,
394						      loff_t *ppos)
395{
396	struct ieee80211_sta *sta = file->private_data;
397	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
398	struct ath10k *ar = arsta->arvif->ar;
399	char buf[8];
400	int len = 0;
401
402	mutex_lock(&ar->conf_mutex);
403	len = scnprintf(buf, sizeof(buf) - len,
404			"Write 1 to once trigger the debug logs\n");
405	mutex_unlock(&ar->conf_mutex);
406
407	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
408}
409
410static ssize_t
411ath10k_dbg_sta_write_peer_debug_trigger(struct file *file,
412					const char __user *user_buf,
413					size_t count, loff_t *ppos)
414{
415	struct ieee80211_sta *sta = file->private_data;
416	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
417	struct ath10k *ar = arsta->arvif->ar;
418	u8 peer_debug_trigger;
419	int ret;
420
421	if (kstrtou8_from_user(user_buf, count, 0, &peer_debug_trigger))
422		return -EINVAL;
423
424	if (peer_debug_trigger != 1)
425		return -EINVAL;
426
427	mutex_lock(&ar->conf_mutex);
428
429	if (ar->state != ATH10K_STATE_ON) {
430		ret = -ENETDOWN;
431		goto out;
432	}
433
434	ret = ath10k_wmi_peer_set_param(ar, arsta->arvif->vdev_id, sta->addr,
435					ar->wmi.peer_param->debug, peer_debug_trigger);
436	if (ret) {
437		ath10k_warn(ar, "failed to set param to trigger peer tid logs for station ret: %d\n",
438			    ret);
439		goto out;
440	}
441out:
442	mutex_unlock(&ar->conf_mutex);
443	return ret ?: count;
444}
445
446static const struct file_operations fops_peer_debug_trigger = {
447	.open = simple_open,
448	.read = ath10k_dbg_sta_read_peer_debug_trigger,
449	.write = ath10k_dbg_sta_write_peer_debug_trigger,
450	.owner = THIS_MODULE,
451	.llseek = default_llseek,
452};
453
454static ssize_t ath10k_dbg_sta_read_peer_ps_state(struct file *file,
455						 char __user *user_buf,
456						 size_t count, loff_t *ppos)
457{
458	struct ieee80211_sta *sta = file->private_data;
459	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
460	struct ath10k *ar = arsta->arvif->ar;
461	char buf[20];
462	int len = 0;
463
464	spin_lock_bh(&ar->data_lock);
465
466	len = scnprintf(buf, sizeof(buf) - len, "%d\n",
467			arsta->peer_ps_state);
468
469	spin_unlock_bh(&ar->data_lock);
470
471	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
472}
473
474static const struct file_operations fops_peer_ps_state = {
475	.open = simple_open,
476	.read = ath10k_dbg_sta_read_peer_ps_state,
477	.owner = THIS_MODULE,
478	.llseek = default_llseek,
479};
480
481static char *get_err_str(enum ath10k_pkt_rx_err i)
482{
483	switch (i) {
484	case ATH10K_PKT_RX_ERR_FCS:
485		return "fcs_err";
486	case ATH10K_PKT_RX_ERR_TKIP:
487		return "tkip_err";
488	case ATH10K_PKT_RX_ERR_CRYPT:
489		return "crypt_err";
490	case ATH10K_PKT_RX_ERR_PEER_IDX_INVAL:
491		return "peer_idx_inval";
492	case ATH10K_PKT_RX_ERR_MAX:
493		return "unknown";
494	}
495
496	return "unknown";
497}
498
499static char *get_num_ampdu_subfrm_str(enum ath10k_ampdu_subfrm_num i)
500{
501	switch (i) {
502	case ATH10K_AMPDU_SUBFRM_NUM_10:
503		return "up to 10";
504	case ATH10K_AMPDU_SUBFRM_NUM_20:
505		return "11-20";
506	case ATH10K_AMPDU_SUBFRM_NUM_30:
507		return "21-30";
508	case ATH10K_AMPDU_SUBFRM_NUM_40:
509		return "31-40";
510	case ATH10K_AMPDU_SUBFRM_NUM_50:
511		return "41-50";
512	case ATH10K_AMPDU_SUBFRM_NUM_60:
513		return "51-60";
514	case ATH10K_AMPDU_SUBFRM_NUM_MORE:
515		return ">60";
516	case ATH10K_AMPDU_SUBFRM_NUM_MAX:
517		return "0";
518	}
519
520	return "0";
521}
522
523static char *get_num_amsdu_subfrm_str(enum ath10k_amsdu_subfrm_num i)
524{
525	switch (i) {
526	case ATH10K_AMSDU_SUBFRM_NUM_1:
527		return "1";
528	case ATH10K_AMSDU_SUBFRM_NUM_2:
529		return "2";
530	case ATH10K_AMSDU_SUBFRM_NUM_3:
531		return "3";
532	case ATH10K_AMSDU_SUBFRM_NUM_4:
533		return "4";
534	case ATH10K_AMSDU_SUBFRM_NUM_MORE:
535		return ">4";
536	case ATH10K_AMSDU_SUBFRM_NUM_MAX:
537		return "0";
538	}
539
540	return "0";
541}
542
543#define PRINT_TID_STATS(_field, _tabs) \
544	do { \
545		int k = 0; \
546		for (j = 0; j <= IEEE80211_NUM_TIDS; j++) { \
547			if (ar->sta_tid_stats_mask & BIT(j))  { \
548				len += scnprintf(buf + len, buf_len - len, \
549						 "[%02d] %-10lu  ", \
550						 j, stats[j]._field); \
551				k++; \
552				if (k % 8 == 0)  { \
553					len += scnprintf(buf + len, \
554							 buf_len - len, "\n"); \
555					len += scnprintf(buf + len, \
556							 buf_len - len, \
557							 _tabs); \
558				} \
559			} \
560		} \
561		len += scnprintf(buf + len, buf_len - len, "\n"); \
562	} while (0)
563
564static ssize_t ath10k_dbg_sta_read_tid_stats(struct file *file,
565					     char __user *user_buf,
566					     size_t count, loff_t *ppos)
567{
568	struct ieee80211_sta *sta = file->private_data;
569	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
570	struct ath10k *ar = arsta->arvif->ar;
571	struct ath10k_sta_tid_stats *stats = arsta->tid_stats;
572	size_t len = 0, buf_len = 1048 * IEEE80211_NUM_TIDS;
573	char *buf;
574	int i, j;
575	ssize_t ret;
576
577	buf = kzalloc(buf_len, GFP_KERNEL);
578	if (!buf)
579		return -ENOMEM;
580
581	mutex_lock(&ar->conf_mutex);
582
583	spin_lock_bh(&ar->data_lock);
584
585	len += scnprintf(buf + len, buf_len - len,
586			 "\n\t\tDriver Rx pkt stats per tid, ([tid] count)\n");
587	len += scnprintf(buf + len, buf_len - len,
588			 "\t\t------------------------------------------\n");
589	len += scnprintf(buf + len, buf_len - len, "MSDUs from FW\t\t\t");
590	PRINT_TID_STATS(rx_pkt_from_fw, "\t\t\t\t");
591
592	len += scnprintf(buf + len, buf_len - len, "MSDUs unchained\t\t\t");
593	PRINT_TID_STATS(rx_pkt_unchained, "\t\t\t\t");
594
595	len += scnprintf(buf + len, buf_len - len,
596			 "MSDUs locally dropped:chained\t");
597	PRINT_TID_STATS(rx_pkt_drop_chained, "\t\t\t\t");
598
599	len += scnprintf(buf + len, buf_len - len,
600			 "MSDUs locally dropped:filtered\t");
601	PRINT_TID_STATS(rx_pkt_drop_filter, "\t\t\t\t");
602
603	len += scnprintf(buf + len, buf_len - len,
604			 "MSDUs queued for mac80211\t");
605	PRINT_TID_STATS(rx_pkt_queued_for_mac, "\t\t\t\t");
606
607	for (i = 0; i < ATH10K_PKT_RX_ERR_MAX; i++) {
608		len += scnprintf(buf + len, buf_len - len,
609				 "MSDUs with error:%s\t", get_err_str(i));
610		PRINT_TID_STATS(rx_pkt_err[i], "\t\t\t\t");
611	}
612
613	len += scnprintf(buf + len, buf_len - len, "\n");
614	for (i = 0; i < ATH10K_AMPDU_SUBFRM_NUM_MAX; i++) {
615		len += scnprintf(buf + len, buf_len - len,
616				 "A-MPDU num subframes %s\t",
617				 get_num_ampdu_subfrm_str(i));
618		PRINT_TID_STATS(rx_pkt_ampdu[i], "\t\t\t\t");
619	}
620
621	len += scnprintf(buf + len, buf_len - len, "\n");
622	for (i = 0; i < ATH10K_AMSDU_SUBFRM_NUM_MAX; i++) {
623		len += scnprintf(buf + len, buf_len - len,
624				 "A-MSDU num subframes %s\t\t",
625				 get_num_amsdu_subfrm_str(i));
626		PRINT_TID_STATS(rx_pkt_amsdu[i], "\t\t\t\t");
627	}
628
629	spin_unlock_bh(&ar->data_lock);
630
631	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
632
633	kfree(buf);
634
635	mutex_unlock(&ar->conf_mutex);
636
637	return ret;
638}
639
640static const struct file_operations fops_tid_stats_dump = {
641	.open = simple_open,
642	.read = ath10k_dbg_sta_read_tid_stats,
643	.owner = THIS_MODULE,
644	.llseek = default_llseek,
645};
646
647static ssize_t ath10k_dbg_sta_dump_tx_stats(struct file *file,
648					    char __user *user_buf,
649					    size_t count, loff_t *ppos)
650{
651	struct ieee80211_sta *sta = file->private_data;
652	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
653	struct ath10k *ar = arsta->arvif->ar;
654	struct ath10k_htt_data_stats *stats;
655	const char *str_name[ATH10K_STATS_TYPE_MAX] = {"succ", "fail",
656						       "retry", "ampdu"};
657	const char *str[ATH10K_COUNTER_TYPE_MAX] = {"bytes", "packets"};
658	int len = 0, i, j, k, retval = 0;
659	const int size = 16 * 4096;
660	char *buf;
661
662	buf = kzalloc(size, GFP_KERNEL);
663	if (!buf)
664		return -ENOMEM;
665
666	mutex_lock(&ar->conf_mutex);
667
668	if (!arsta->tx_stats) {
669		ath10k_warn(ar, "failed to get tx stats");
670		mutex_unlock(&ar->conf_mutex);
671		kfree(buf);
672		return 0;
673	}
674
675	spin_lock_bh(&ar->data_lock);
676	for (k = 0; k < ATH10K_STATS_TYPE_MAX; k++) {
677		for (j = 0; j < ATH10K_COUNTER_TYPE_MAX; j++) {
678			stats = &arsta->tx_stats->stats[k];
679			len += scnprintf(buf + len, size - len, "%s_%s\n",
680					 str_name[k],
681					 str[j]);
682			len += scnprintf(buf + len, size - len,
683					 " VHT MCS %s\n",
684					 str[j]);
685			for (i = 0; i < ATH10K_VHT_MCS_NUM; i++)
686				len += scnprintf(buf + len, size - len,
687						 "  %llu ",
688						 stats->vht[j][i]);
689			len += scnprintf(buf + len, size - len, "\n");
690			len += scnprintf(buf + len, size - len, " HT MCS %s\n",
691					 str[j]);
692			for (i = 0; i < ATH10K_HT_MCS_NUM; i++)
693				len += scnprintf(buf + len, size - len,
694						 "  %llu ", stats->ht[j][i]);
695			len += scnprintf(buf + len, size - len, "\n");
696			len += scnprintf(buf + len, size - len,
697					" BW %s (20,5,10,40,80,160 MHz)\n", str[j]);
698			len += scnprintf(buf + len, size - len,
699					 "  %llu %llu %llu %llu %llu %llu\n",
700					 stats->bw[j][0], stats->bw[j][1],
701					 stats->bw[j][2], stats->bw[j][3],
702					 stats->bw[j][4], stats->bw[j][5]);
703			len += scnprintf(buf + len, size - len,
704					 " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]);
705			len += scnprintf(buf + len, size - len,
706					 "  %llu %llu %llu %llu\n",
707					 stats->nss[j][0], stats->nss[j][1],
708					 stats->nss[j][2], stats->nss[j][3]);
709			len += scnprintf(buf + len, size - len,
710					 " GI %s (LGI,SGI)\n",
711					 str[j]);
712			len += scnprintf(buf + len, size - len, "  %llu %llu\n",
713					 stats->gi[j][0], stats->gi[j][1]);
714			len += scnprintf(buf + len, size - len,
715					 " legacy rate %s (1,2 ... Mbps)\n  ",
716					 str[j]);
717			for (i = 0; i < ATH10K_LEGACY_NUM; i++)
718				len += scnprintf(buf + len, size - len, "%llu ",
719						 stats->legacy[j][i]);
720			len += scnprintf(buf + len, size - len, "\n");
721			len += scnprintf(buf + len, size - len,
722					 " Rate table %s (1,2 ... Mbps)\n  ",
723					 str[j]);
724			for (i = 0; i < ATH10K_RATE_TABLE_NUM; i++) {
725				len += scnprintf(buf + len, size - len, "%llu ",
726						 stats->rate_table[j][i]);
727				if (!((i + 1) % 8))
728					len +=
729					scnprintf(buf + len, size - len, "\n  ");
730			}
731		}
732	}
733
734	len += scnprintf(buf + len, size - len,
735			 "\nTX duration\n %llu usecs\n",
736			 arsta->tx_stats->tx_duration);
737	len += scnprintf(buf + len, size - len,
738			"BA fails\n %llu\n", arsta->tx_stats->ba_fails);
739	len += scnprintf(buf + len, size - len,
740			"ack fails\n %llu\n", arsta->tx_stats->ack_fails);
741	spin_unlock_bh(&ar->data_lock);
742
743	if (len > size)
744		len = size;
745	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
746	kfree(buf);
747
748	mutex_unlock(&ar->conf_mutex);
749	return retval;
750}
751
752static const struct file_operations fops_tx_stats = {
753	.read = ath10k_dbg_sta_dump_tx_stats,
754	.open = simple_open,
755	.owner = THIS_MODULE,
756	.llseek = default_llseek,
757};
758
759void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
760			    struct ieee80211_sta *sta, struct dentry *dir)
761{
762	struct ath10k *ar = hw->priv;
763
764	debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode);
765	debugfs_create_file("addba", 0200, dir, sta, &fops_addba);
766	debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);
767	debugfs_create_file("delba", 0200, dir, sta, &fops_delba);
768	debugfs_create_file("peer_debug_trigger", 0600, dir, sta,
769			    &fops_peer_debug_trigger);
770	debugfs_create_file("dump_tid_stats", 0400, dir, sta,
771			    &fops_tid_stats_dump);
772
773	if (ath10k_peer_stats_enabled(ar) &&
774	    ath10k_debug_is_extd_tx_stats_enabled(ar))
775		debugfs_create_file("tx_stats", 0400, dir, sta,
776				    &fops_tx_stats);
777	debugfs_create_file("peer_ps_state", 0400, dir, sta,
778			    &fops_peer_ps_state);
779}
~/ Read-only file preview.