Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
  3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  4 *
  5 * Permission to use, copy, modify, and/or distribute this software for any
  6 * purpose with or without fee is hereby granted, provided that the above
  7 * copyright notice and this permission notice appear in all copies.
  8 *
  9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 16 */
 17
 18#include "core.h"
 19#include "wmi-ops.h"
 20#include "txrx.h"
 21#include "debug.h"
 22
 23static void ath10k_rx_stats_update_amsdu_subfrm(struct ath10k *ar,
 24						struct ath10k_sta_tid_stats *stats,
 25						u32 msdu_count)
 26{
 27	if (msdu_count == 1)
 28		stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_1]++;
 29	else if (msdu_count == 2)
 30		stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_2]++;
 31	else if (msdu_count == 3)
 32		stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_3]++;
 33	else if (msdu_count == 4)
 34		stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_4]++;
 35	else if (msdu_count > 4)
 36		stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MORE]++;
 37}
 38
 39static void ath10k_rx_stats_update_ampdu_subfrm(struct ath10k *ar,
 40						struct ath10k_sta_tid_stats *stats,
 41						u32 mpdu_count)
 42{
 43	if (mpdu_count <= 10)
 44		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_10]++;
 45	else if (mpdu_count <= 20)
 46		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_20]++;
 47	else if (mpdu_count <= 30)
 48		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_30]++;
 49	else if (mpdu_count <= 40)
 50		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_40]++;
 51	else if (mpdu_count <= 50)
 52		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_50]++;
 53	else if (mpdu_count <= 60)
 54		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_60]++;
 55	else if (mpdu_count > 60)
 56		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_MORE]++;
 57}
 58
 59void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar, u16 peer_id, u8 tid,
 60					  struct htt_rx_indication_mpdu_range *ranges,
 61					  int num_ranges)
 62{
 63	struct ath10k_sta *arsta;
 64	struct ath10k_peer *peer;
 65	int i;
 66
 67	if (tid > IEEE80211_NUM_TIDS || !(ar->sta_tid_stats_mask & BIT(tid)))
 68		return;
 69
 70	rcu_read_lock();
 71	spin_lock_bh(&ar->data_lock);
 72
 73	peer = ath10k_peer_find_by_id(ar, peer_id);
 74	if (!peer)
 75		goto out;
 76
 77	arsta = (struct ath10k_sta *)peer->sta->drv_priv;
 78
 79	for (i = 0; i < num_ranges; i++)
 80		ath10k_rx_stats_update_ampdu_subfrm(ar,
 81						    &arsta->tid_stats[tid],
 82						    ranges[i].mpdu_count);
 83
 84out:
 85	spin_unlock_bh(&ar->data_lock);
 86	rcu_read_unlock();
 87}
 88
 89void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr,
 90				    unsigned long int num_msdus,
 91				    enum ath10k_pkt_rx_err err,
 92				    unsigned long int unchain_cnt,
 93				    unsigned long int drop_cnt,
 94				    unsigned long int drop_cnt_filter,
 95				    unsigned long int queued_msdus)
 96{
 97	struct ieee80211_sta *sta;
 98	struct ath10k_sta *arsta;
 99	struct ieee80211_hdr *hdr;
100	struct ath10k_sta_tid_stats *stats;
101	u8 tid = IEEE80211_NUM_TIDS;
102	bool non_data_frm = false;
103
104	hdr = (struct ieee80211_hdr *)first_hdr;
105	if (!ieee80211_is_data(hdr->frame_control))
106		non_data_frm = true;
107
108	if (ieee80211_is_data_qos(hdr->frame_control))
109		tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
110
111	if (!(ar->sta_tid_stats_mask & BIT(tid)) || non_data_frm)
112		return;
113
114	rcu_read_lock();
115
116	sta = ieee80211_find_sta_by_ifaddr(ar->hw, hdr->addr2, NULL);
117	if (!sta)
118		goto exit;
119
120	arsta = (struct ath10k_sta *)sta->drv_priv;
121
122	spin_lock_bh(&ar->data_lock);
123	stats = &arsta->tid_stats[tid];
124	stats->rx_pkt_from_fw += num_msdus;
125	stats->rx_pkt_unchained += unchain_cnt;
126	stats->rx_pkt_drop_chained += drop_cnt;
127	stats->rx_pkt_drop_filter += drop_cnt_filter;
128	if (err != ATH10K_PKT_RX_ERR_MAX)
129		stats->rx_pkt_err[err] += queued_msdus;
130	stats->rx_pkt_queued_for_mac += queued_msdus;
131	ath10k_rx_stats_update_amsdu_subfrm(ar, &arsta->tid_stats[tid],
132					    num_msdus);
133	spin_unlock_bh(&ar->data_lock);
134
135exit:
136	rcu_read_unlock();
137}
138
139static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar,
140						     struct ath10k_fw_stats *stats)
141{
142	struct ath10k_fw_extd_stats_peer *peer;
143	struct ieee80211_sta *sta;
144	struct ath10k_sta *arsta;
145
146	rcu_read_lock();
147	list_for_each_entry(peer, &stats->peers_extd, list) {
148		sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,
149						   NULL);
150		if (!sta)
151			continue;
152		arsta = (struct ath10k_sta *)sta->drv_priv;
153		arsta->rx_duration += (u64)peer->rx_duration;
154	}
155	rcu_read_unlock();
156}
157
158static void ath10k_sta_update_stats_rx_duration(struct ath10k *ar,
159						struct ath10k_fw_stats *stats)
160{
161	struct ath10k_fw_stats_peer *peer;
162	struct ieee80211_sta *sta;
163	struct ath10k_sta *arsta;
164
165	rcu_read_lock();
166	list_for_each_entry(peer, &stats->peers, list) {
167		sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,
168						   NULL);
169		if (!sta)
170			continue;
171		arsta = (struct ath10k_sta *)sta->drv_priv;
172		arsta->rx_duration += (u64)peer->rx_duration;
173	}
174	rcu_read_unlock();
175}
176
177void ath10k_sta_update_rx_duration(struct ath10k *ar,
178				   struct ath10k_fw_stats *stats)
179{
180	if (stats->extended)
181		ath10k_sta_update_extd_stats_rx_duration(ar, stats);
182	else
183		ath10k_sta_update_stats_rx_duration(ar, stats);
184}
185
186static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
187					     char __user *user_buf,
188					     size_t count, loff_t *ppos)
189{
190	struct ieee80211_sta *sta = file->private_data;
191	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
192	struct ath10k *ar = arsta->arvif->ar;
193	char buf[32];
194	int len = 0;
195
196	mutex_lock(&ar->conf_mutex);
197	len = scnprintf(buf, sizeof(buf) - len, "aggregation mode: %s\n",
198			(arsta->aggr_mode == ATH10K_DBG_AGGR_MODE_AUTO) ?
199			"auto" : "manual");
200	mutex_unlock(&ar->conf_mutex);
201
202	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
203}
204
205static ssize_t ath10k_dbg_sta_write_aggr_mode(struct file *file,
206					      const char __user *user_buf,
207					      size_t count, loff_t *ppos)
208{
209	struct ieee80211_sta *sta = file->private_data;
210	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
211	struct ath10k *ar = arsta->arvif->ar;
212	u32 aggr_mode;
213	int ret;
214
215	if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))
216		return -EINVAL;
217
218	if (aggr_mode >= ATH10K_DBG_AGGR_MODE_MAX)
219		return -EINVAL;
220
221	mutex_lock(&ar->conf_mutex);
222	if ((ar->state != ATH10K_STATE_ON) ||
223	    (aggr_mode == arsta->aggr_mode)) {
224		ret = count;
225		goto out;
226	}
227
228	ret = ath10k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);
229	if (ret) {
230		ath10k_warn(ar, "failed to clear addba session ret: %d\n", ret);
231		goto out;
232	}
233
234	arsta->aggr_mode = aggr_mode;
235out:
236	mutex_unlock(&ar->conf_mutex);
237	return ret;
238}
239
240static const struct file_operations fops_aggr_mode = {
241	.read = ath10k_dbg_sta_read_aggr_mode,
242	.write = ath10k_dbg_sta_write_aggr_mode,
243	.open = simple_open,
244	.owner = THIS_MODULE,
245	.llseek = default_llseek,
246};
247
248static ssize_t ath10k_dbg_sta_write_addba(struct file *file,
249					  const char __user *user_buf,
250					  size_t count, loff_t *ppos)
251{
252	struct ieee80211_sta *sta = file->private_data;
253	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
254	struct ath10k *ar = arsta->arvif->ar;
255	u32 tid, buf_size;
256	int ret;
257	char buf[64];
258
259	simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
260
261	/* make sure that buf is null terminated */
262	buf[sizeof(buf) - 1] = '\0';
263
264	ret = sscanf(buf, "%u %u", &tid, &buf_size);
265	if (ret != 2)
266		return -EINVAL;
267
268	/* Valid TID values are 0 through 15 */
269	if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
270		return -EINVAL;
271
272	mutex_lock(&ar->conf_mutex);
273	if ((ar->state != ATH10K_STATE_ON) ||
274	    (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
275		ret = count;
276		goto out;
277	}
278
279	ret = ath10k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,
280				    tid, buf_size);
281	if (ret) {
282		ath10k_warn(ar, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",
283			    arsta->arvif->vdev_id, sta->addr, tid, buf_size);
284	}
285
286	ret = count;
287out:
288	mutex_unlock(&ar->conf_mutex);
289	return ret;
290}
291
292static const struct file_operations fops_addba = {
293	.write = ath10k_dbg_sta_write_addba,
294	.open = simple_open,
295	.owner = THIS_MODULE,
296	.llseek = default_llseek,
297};
298
299static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file,
300					       const char __user *user_buf,
301					       size_t count, loff_t *ppos)
302{
303	struct ieee80211_sta *sta = file->private_data;
304	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
305	struct ath10k *ar = arsta->arvif->ar;
306	u32 tid, status;
307	int ret;
308	char buf[64];
309
310	simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
311
312	/* make sure that buf is null terminated */
313	buf[sizeof(buf) - 1] = '\0';
314
315	ret = sscanf(buf, "%u %u", &tid, &status);
316	if (ret != 2)
317		return -EINVAL;
318
319	/* Valid TID values are 0 through 15 */
320	if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
321		return -EINVAL;
322
323	mutex_lock(&ar->conf_mutex);
324	if ((ar->state != ATH10K_STATE_ON) ||
325	    (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
326		ret = count;
327		goto out;
328	}
329
330	ret = ath10k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,
331					tid, status);
332	if (ret) {
333		ath10k_warn(ar, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",
334			    arsta->arvif->vdev_id, sta->addr, tid, status);
335	}
336	ret = count;
337out:
338	mutex_unlock(&ar->conf_mutex);
339	return ret;
340}
341
342static const struct file_operations fops_addba_resp = {
343	.write = ath10k_dbg_sta_write_addba_resp,
344	.open = simple_open,
345	.owner = THIS_MODULE,
346	.llseek = default_llseek,
347};
348
349static ssize_t ath10k_dbg_sta_write_delba(struct file *file,
350					  const char __user *user_buf,
351					  size_t count, loff_t *ppos)
352{
353	struct ieee80211_sta *sta = file->private_data;
354	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
355	struct ath10k *ar = arsta->arvif->ar;
356	u32 tid, initiator, reason;
357	int ret;
358	char buf[64];
359
360	simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
361
362	/* make sure that buf is null terminated */
363	buf[sizeof(buf) - 1] = '\0';
364
365	ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);
366	if (ret != 3)
367		return -EINVAL;
368
369	/* Valid TID values are 0 through 15 */
370	if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
371		return -EINVAL;
372
373	mutex_lock(&ar->conf_mutex);
374	if ((ar->state != ATH10K_STATE_ON) ||
375	    (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
376		ret = count;
377		goto out;
378	}
379
380	ret = ath10k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,
381				    tid, initiator, reason);
382	if (ret) {
383		ath10k_warn(ar, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",
384			    arsta->arvif->vdev_id, sta->addr, tid, initiator,
385			    reason);
386	}
387	ret = count;
388out:
389	mutex_unlock(&ar->conf_mutex);
390	return ret;
391}
392
393static const struct file_operations fops_delba = {
394	.write = ath10k_dbg_sta_write_delba,
395	.open = simple_open,
396	.owner = THIS_MODULE,
397	.llseek = default_llseek,
398};
399
400static ssize_t ath10k_dbg_sta_read_peer_debug_trigger(struct file *file,
401						      char __user *user_buf,
402						      size_t count,
403						      loff_t *ppos)
404{
405	struct ieee80211_sta *sta = file->private_data;
406	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
407	struct ath10k *ar = arsta->arvif->ar;
408	char buf[8];
409	int len = 0;
410
411	mutex_lock(&ar->conf_mutex);
412	len = scnprintf(buf, sizeof(buf) - len,
413			"Write 1 to once trigger the debug logs\n");
414	mutex_unlock(&ar->conf_mutex);
415
416	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
417}
418
419static ssize_t
420ath10k_dbg_sta_write_peer_debug_trigger(struct file *file,
421					const char __user *user_buf,
422					size_t count, loff_t *ppos)
423{
424	struct ieee80211_sta *sta = file->private_data;
425	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
426	struct ath10k *ar = arsta->arvif->ar;
427	u8 peer_debug_trigger;
428	int ret;
429
430	if (kstrtou8_from_user(user_buf, count, 0, &peer_debug_trigger))
431		return -EINVAL;
432
433	if (peer_debug_trigger != 1)
434		return -EINVAL;
435
436	mutex_lock(&ar->conf_mutex);
437
438	if (ar->state != ATH10K_STATE_ON) {
439		ret = -ENETDOWN;
440		goto out;
441	}
442
443	ret = ath10k_wmi_peer_set_param(ar, arsta->arvif->vdev_id, sta->addr,
444					WMI_PEER_DEBUG, peer_debug_trigger);
445	if (ret) {
446		ath10k_warn(ar, "failed to set param to trigger peer tid logs for station ret: %d\n",
447			    ret);
448		goto out;
449	}
450out:
451	mutex_unlock(&ar->conf_mutex);
452	return count;
453}
454
455static const struct file_operations fops_peer_debug_trigger = {
456	.open = simple_open,
457	.read = ath10k_dbg_sta_read_peer_debug_trigger,
458	.write = ath10k_dbg_sta_write_peer_debug_trigger,
459	.owner = THIS_MODULE,
460	.llseek = default_llseek,
461};
462
463static char *get_err_str(enum ath10k_pkt_rx_err i)
464{
465	switch (i) {
466	case ATH10K_PKT_RX_ERR_FCS:
467		return "fcs_err";
468	case ATH10K_PKT_RX_ERR_TKIP:
469		return "tkip_err";
470	case ATH10K_PKT_RX_ERR_CRYPT:
471		return "crypt_err";
472	case ATH10K_PKT_RX_ERR_PEER_IDX_INVAL:
473		return "peer_idx_inval";
474	case ATH10K_PKT_RX_ERR_MAX:
475		return "unknown";
476	}
477
478	return "unknown";
479}
480
481static char *get_num_ampdu_subfrm_str(enum ath10k_ampdu_subfrm_num i)
482{
483	switch (i) {
484	case ATH10K_AMPDU_SUBFRM_NUM_10:
485		return "upto 10";
486	case ATH10K_AMPDU_SUBFRM_NUM_20:
487		return "11-20";
488	case ATH10K_AMPDU_SUBFRM_NUM_30:
489		return "21-30";
490	case ATH10K_AMPDU_SUBFRM_NUM_40:
491		return "31-40";
492	case ATH10K_AMPDU_SUBFRM_NUM_50:
493		return "41-50";
494	case ATH10K_AMPDU_SUBFRM_NUM_60:
495		return "51-60";
496	case ATH10K_AMPDU_SUBFRM_NUM_MORE:
497		return ">60";
498	case ATH10K_AMPDU_SUBFRM_NUM_MAX:
499		return "0";
500	}
501
502	return "0";
503}
504
505static char *get_num_amsdu_subfrm_str(enum ath10k_amsdu_subfrm_num i)
506{
507	switch (i) {
508	case ATH10K_AMSDU_SUBFRM_NUM_1:
509		return "1";
510	case ATH10K_AMSDU_SUBFRM_NUM_2:
511		return "2";
512	case ATH10K_AMSDU_SUBFRM_NUM_3:
513		return "3";
514	case ATH10K_AMSDU_SUBFRM_NUM_4:
515		return "4";
516	case ATH10K_AMSDU_SUBFRM_NUM_MORE:
517		return ">4";
518	case ATH10K_AMSDU_SUBFRM_NUM_MAX:
519		return "0";
520	}
521
522	return "0";
523}
524
525#define PRINT_TID_STATS(_field, _tabs) \
526	do { \
527		int k = 0; \
528		for (j = 0; j <= IEEE80211_NUM_TIDS; j++) { \
529			if (ar->sta_tid_stats_mask & BIT(j))  { \
530				len += scnprintf(buf + len, buf_len - len, \
531						 "[%02d] %-10lu  ", \
532						 j, stats[j]._field); \
533				k++; \
534				if (k % 8 == 0)  { \
535					len += scnprintf(buf + len, \
536							 buf_len - len, "\n"); \
537					len += scnprintf(buf + len, \
538							 buf_len - len, \
539							 _tabs); \
540				} \
541			} \
542		} \
543		len += scnprintf(buf + len, buf_len - len, "\n"); \
544	} while (0)
545
546static ssize_t ath10k_dbg_sta_read_tid_stats(struct file *file,
547					     char __user *user_buf,
548					     size_t count, loff_t *ppos)
549{
550	struct ieee80211_sta *sta = file->private_data;
551	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
552	struct ath10k *ar = arsta->arvif->ar;
553	struct ath10k_sta_tid_stats *stats = arsta->tid_stats;
554	size_t len = 0, buf_len = 1048 * IEEE80211_NUM_TIDS;
555	char *buf;
556	int i, j;
557	ssize_t ret;
558
559	buf = kzalloc(buf_len, GFP_KERNEL);
560	if (!buf)
561		return -ENOMEM;
562
563	mutex_lock(&ar->conf_mutex);
564
565	spin_lock_bh(&ar->data_lock);
566
567	len += scnprintf(buf + len, buf_len - len,
568			 "\n\t\tDriver Rx pkt stats per tid, ([tid] count)\n");
569	len += scnprintf(buf + len, buf_len - len,
570			 "\t\t------------------------------------------\n");
571	len += scnprintf(buf + len, buf_len - len, "MSDUs from FW\t\t\t");
572	PRINT_TID_STATS(rx_pkt_from_fw, "\t\t\t\t");
573
574	len += scnprintf(buf + len, buf_len - len, "MSDUs unchained\t\t\t");
575	PRINT_TID_STATS(rx_pkt_unchained, "\t\t\t\t");
576
577	len += scnprintf(buf + len, buf_len - len,
578			 "MSDUs locally dropped:chained\t");
579	PRINT_TID_STATS(rx_pkt_drop_chained, "\t\t\t\t");
580
581	len += scnprintf(buf + len, buf_len - len,
582			 "MSDUs locally dropped:filtered\t");
583	PRINT_TID_STATS(rx_pkt_drop_filter, "\t\t\t\t");
584
585	len += scnprintf(buf + len, buf_len - len,
586			 "MSDUs queued for mac80211\t");
587	PRINT_TID_STATS(rx_pkt_queued_for_mac, "\t\t\t\t");
588
589	for (i = 0; i < ATH10K_PKT_RX_ERR_MAX; i++) {
590		len += scnprintf(buf + len, buf_len - len,
591				 "MSDUs with error:%s\t", get_err_str(i));
592		PRINT_TID_STATS(rx_pkt_err[i], "\t\t\t\t");
593	}
594
595	len += scnprintf(buf + len, buf_len - len, "\n");
596	for (i = 0; i < ATH10K_AMPDU_SUBFRM_NUM_MAX; i++) {
597		len += scnprintf(buf + len, buf_len - len,
598				 "A-MPDU num subframes %s\t",
599				 get_num_ampdu_subfrm_str(i));
600		PRINT_TID_STATS(rx_pkt_ampdu[i], "\t\t\t\t");
601	}
602
603	len += scnprintf(buf + len, buf_len - len, "\n");
604	for (i = 0; i < ATH10K_AMSDU_SUBFRM_NUM_MAX; i++) {
605		len += scnprintf(buf + len, buf_len - len,
606				 "A-MSDU num subframes %s\t\t",
607				 get_num_amsdu_subfrm_str(i));
608		PRINT_TID_STATS(rx_pkt_amsdu[i], "\t\t\t\t");
609	}
610
611	spin_unlock_bh(&ar->data_lock);
612
613	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
614
615	kfree(buf);
616
617	mutex_unlock(&ar->conf_mutex);
618
619	return ret;
620}
621
622static const struct file_operations fops_tid_stats_dump = {
623	.open = simple_open,
624	.read = ath10k_dbg_sta_read_tid_stats,
625	.owner = THIS_MODULE,
626	.llseek = default_llseek,
627};
628
629void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
630			    struct ieee80211_sta *sta, struct dentry *dir)
631{
632	debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode);
633	debugfs_create_file("addba", 0200, dir, sta, &fops_addba);
634	debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);
635	debugfs_create_file("delba", 0200, dir, sta, &fops_delba);
636	debugfs_create_file("peer_debug_trigger", 0600, dir, sta,
637			    &fops_peer_debug_trigger);
638	debugfs_create_file("dump_tid_stats", 0400, dir, sta,
639			    &fops_tid_stats_dump);
640}