xref: /linux/drivers/net/wireless/ath/ath11k/debugfs_sta.c (revision 4f6b838c378a52ea3ae0b15f12ca8a20849072fa)
1d5c65159SKalle Valo // SPDX-License-Identifier: BSD-3-Clause-Clear
2d5c65159SKalle Valo /*
3d5c65159SKalle Valo  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
4d5c65159SKalle Valo  */
5d5c65159SKalle Valo 
6d5c65159SKalle Valo #include <linux/vmalloc.h>
7d5c65159SKalle Valo 
8*568f0603SKalle Valo #include "debugfs_sta.h"
9d5c65159SKalle Valo #include "core.h"
10d5c65159SKalle Valo #include "peer.h"
11d5c65159SKalle Valo #include "debug.h"
12559ef68fSAshok Raj Nagarajan #include "dp_tx.h"
1356292162SKalle Valo #include "debugfs_htt_stats.h"
14d5c65159SKalle Valo 
15*568f0603SKalle Valo void ath11k_debugfs_sta_add_tx_stats(struct ath11k_sta *arsta,
16d5c65159SKalle Valo 				     struct ath11k_per_peer_tx_stats *peer_stats,
17d5c65159SKalle Valo 				     u8 legacy_rate_idx)
18d5c65159SKalle Valo {
19d5c65159SKalle Valo 	struct rate_info *txrate = &arsta->txrate;
20d5c65159SKalle Valo 	struct ath11k_htt_tx_stats *tx_stats;
21d5c65159SKalle Valo 	int gi, mcs, bw, nss;
22d5c65159SKalle Valo 
23d5c65159SKalle Valo 	if (!arsta->tx_stats)
24d5c65159SKalle Valo 		return;
25d5c65159SKalle Valo 
26d5c65159SKalle Valo 	tx_stats = arsta->tx_stats;
27d5c65159SKalle Valo 	gi = FIELD_GET(RATE_INFO_FLAGS_SHORT_GI, arsta->txrate.flags);
28d5c65159SKalle Valo 	mcs = txrate->mcs;
2992bacd1cSVenkateswara Naralasetty 	bw = ath11k_mac_mac80211_bw_to_ath11k_bw(txrate->bw);
30d5c65159SKalle Valo 	nss = txrate->nss - 1;
31d5c65159SKalle Valo 
32d5c65159SKalle Valo #define STATS_OP_FMT(name) tx_stats->stats[ATH11K_STATS_TYPE_##name]
33d5c65159SKalle Valo 
34d5c65159SKalle Valo 	if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
35d5c65159SKalle Valo 		STATS_OP_FMT(SUCC).he[0][mcs] += peer_stats->succ_bytes;
36d5c65159SKalle Valo 		STATS_OP_FMT(SUCC).he[1][mcs] += peer_stats->succ_pkts;
37d5c65159SKalle Valo 		STATS_OP_FMT(FAIL).he[0][mcs] += peer_stats->failed_bytes;
38d5c65159SKalle Valo 		STATS_OP_FMT(FAIL).he[1][mcs] += peer_stats->failed_pkts;
39d5c65159SKalle Valo 		STATS_OP_FMT(RETRY).he[0][mcs] += peer_stats->retry_bytes;
40d5c65159SKalle Valo 		STATS_OP_FMT(RETRY).he[1][mcs] += peer_stats->retry_pkts;
41d5c65159SKalle Valo 	} else if (txrate->flags & RATE_INFO_FLAGS_VHT_MCS) {
42d5c65159SKalle Valo 		STATS_OP_FMT(SUCC).vht[0][mcs] += peer_stats->succ_bytes;
43d5c65159SKalle Valo 		STATS_OP_FMT(SUCC).vht[1][mcs] += peer_stats->succ_pkts;
44d5c65159SKalle Valo 		STATS_OP_FMT(FAIL).vht[0][mcs] += peer_stats->failed_bytes;
45d5c65159SKalle Valo 		STATS_OP_FMT(FAIL).vht[1][mcs] += peer_stats->failed_pkts;
46d5c65159SKalle Valo 		STATS_OP_FMT(RETRY).vht[0][mcs] += peer_stats->retry_bytes;
47d5c65159SKalle Valo 		STATS_OP_FMT(RETRY).vht[1][mcs] += peer_stats->retry_pkts;
48d5c65159SKalle Valo 	} else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
49d5c65159SKalle Valo 		STATS_OP_FMT(SUCC).ht[0][mcs] += peer_stats->succ_bytes;
50d5c65159SKalle Valo 		STATS_OP_FMT(SUCC).ht[1][mcs] += peer_stats->succ_pkts;
51d5c65159SKalle Valo 		STATS_OP_FMT(FAIL).ht[0][mcs] += peer_stats->failed_bytes;
52d5c65159SKalle Valo 		STATS_OP_FMT(FAIL).ht[1][mcs] += peer_stats->failed_pkts;
53d5c65159SKalle Valo 		STATS_OP_FMT(RETRY).ht[0][mcs] += peer_stats->retry_bytes;
54d5c65159SKalle Valo 		STATS_OP_FMT(RETRY).ht[1][mcs] += peer_stats->retry_pkts;
55d5c65159SKalle Valo 	} else {
56d5c65159SKalle Valo 		mcs = legacy_rate_idx;
57d5c65159SKalle Valo 
58d5c65159SKalle Valo 		STATS_OP_FMT(SUCC).legacy[0][mcs] += peer_stats->succ_bytes;
59d5c65159SKalle Valo 		STATS_OP_FMT(SUCC).legacy[1][mcs] += peer_stats->succ_pkts;
60d5c65159SKalle Valo 		STATS_OP_FMT(FAIL).legacy[0][mcs] += peer_stats->failed_bytes;
61d5c65159SKalle Valo 		STATS_OP_FMT(FAIL).legacy[1][mcs] += peer_stats->failed_pkts;
62d5c65159SKalle Valo 		STATS_OP_FMT(RETRY).legacy[0][mcs] += peer_stats->retry_bytes;
63d5c65159SKalle Valo 		STATS_OP_FMT(RETRY).legacy[1][mcs] += peer_stats->retry_pkts;
64d5c65159SKalle Valo 	}
65d5c65159SKalle Valo 
66d5c65159SKalle Valo 	if (peer_stats->is_ampdu) {
67d5c65159SKalle Valo 		tx_stats->ba_fails += peer_stats->ba_fails;
68d5c65159SKalle Valo 
69d5c65159SKalle Valo 		if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
70d5c65159SKalle Valo 			STATS_OP_FMT(AMPDU).he[0][mcs] +=
71d5c65159SKalle Valo 			peer_stats->succ_bytes + peer_stats->retry_bytes;
72d5c65159SKalle Valo 			STATS_OP_FMT(AMPDU).he[1][mcs] +=
73d5c65159SKalle Valo 			peer_stats->succ_pkts + peer_stats->retry_pkts;
74d5c65159SKalle Valo 		} else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
75d5c65159SKalle Valo 			STATS_OP_FMT(AMPDU).ht[0][mcs] +=
76d5c65159SKalle Valo 			peer_stats->succ_bytes + peer_stats->retry_bytes;
77d5c65159SKalle Valo 			STATS_OP_FMT(AMPDU).ht[1][mcs] +=
78d5c65159SKalle Valo 			peer_stats->succ_pkts + peer_stats->retry_pkts;
79d5c65159SKalle Valo 		} else {
80d5c65159SKalle Valo 			STATS_OP_FMT(AMPDU).vht[0][mcs] +=
81d5c65159SKalle Valo 			peer_stats->succ_bytes + peer_stats->retry_bytes;
82d5c65159SKalle Valo 			STATS_OP_FMT(AMPDU).vht[1][mcs] +=
83d5c65159SKalle Valo 			peer_stats->succ_pkts + peer_stats->retry_pkts;
84d5c65159SKalle Valo 		}
85d5c65159SKalle Valo 		STATS_OP_FMT(AMPDU).bw[0][bw] +=
86d5c65159SKalle Valo 			peer_stats->succ_bytes + peer_stats->retry_bytes;
87d5c65159SKalle Valo 		STATS_OP_FMT(AMPDU).nss[0][nss] +=
88d5c65159SKalle Valo 			peer_stats->succ_bytes + peer_stats->retry_bytes;
89d5c65159SKalle Valo 		STATS_OP_FMT(AMPDU).gi[0][gi] +=
90d5c65159SKalle Valo 			peer_stats->succ_bytes + peer_stats->retry_bytes;
91d5c65159SKalle Valo 		STATS_OP_FMT(AMPDU).bw[1][bw] +=
92d5c65159SKalle Valo 			peer_stats->succ_pkts + peer_stats->retry_pkts;
93d5c65159SKalle Valo 		STATS_OP_FMT(AMPDU).nss[1][nss] +=
94d5c65159SKalle Valo 			peer_stats->succ_pkts + peer_stats->retry_pkts;
95d5c65159SKalle Valo 		STATS_OP_FMT(AMPDU).gi[1][gi] +=
96d5c65159SKalle Valo 			peer_stats->succ_pkts + peer_stats->retry_pkts;
97d5c65159SKalle Valo 	} else {
98d5c65159SKalle Valo 		tx_stats->ack_fails += peer_stats->ba_fails;
99d5c65159SKalle Valo 	}
100d5c65159SKalle Valo 
101d5c65159SKalle Valo 	STATS_OP_FMT(SUCC).bw[0][bw] += peer_stats->succ_bytes;
102d5c65159SKalle Valo 	STATS_OP_FMT(SUCC).nss[0][nss] += peer_stats->succ_bytes;
103d5c65159SKalle Valo 	STATS_OP_FMT(SUCC).gi[0][gi] += peer_stats->succ_bytes;
104d5c65159SKalle Valo 
105d5c65159SKalle Valo 	STATS_OP_FMT(SUCC).bw[1][bw] += peer_stats->succ_pkts;
106d5c65159SKalle Valo 	STATS_OP_FMT(SUCC).nss[1][nss] += peer_stats->succ_pkts;
107d5c65159SKalle Valo 	STATS_OP_FMT(SUCC).gi[1][gi] += peer_stats->succ_pkts;
108d5c65159SKalle Valo 
109d5c65159SKalle Valo 	STATS_OP_FMT(FAIL).bw[0][bw] += peer_stats->failed_bytes;
110d5c65159SKalle Valo 	STATS_OP_FMT(FAIL).nss[0][nss] += peer_stats->failed_bytes;
111d5c65159SKalle Valo 	STATS_OP_FMT(FAIL).gi[0][gi] += peer_stats->failed_bytes;
112d5c65159SKalle Valo 
113d5c65159SKalle Valo 	STATS_OP_FMT(FAIL).bw[1][bw] += peer_stats->failed_pkts;
114d5c65159SKalle Valo 	STATS_OP_FMT(FAIL).nss[1][nss] += peer_stats->failed_pkts;
115d5c65159SKalle Valo 	STATS_OP_FMT(FAIL).gi[1][gi] += peer_stats->failed_pkts;
116d5c65159SKalle Valo 
117d5c65159SKalle Valo 	STATS_OP_FMT(RETRY).bw[0][bw] += peer_stats->retry_bytes;
118d5c65159SKalle Valo 	STATS_OP_FMT(RETRY).nss[0][nss] += peer_stats->retry_bytes;
119d5c65159SKalle Valo 	STATS_OP_FMT(RETRY).gi[0][gi] += peer_stats->retry_bytes;
120d5c65159SKalle Valo 
121d5c65159SKalle Valo 	STATS_OP_FMT(RETRY).bw[1][bw] += peer_stats->retry_pkts;
122d5c65159SKalle Valo 	STATS_OP_FMT(RETRY).nss[1][nss] += peer_stats->retry_pkts;
123d5c65159SKalle Valo 	STATS_OP_FMT(RETRY).gi[1][gi] += peer_stats->retry_pkts;
124d5c65159SKalle Valo 
125d5c65159SKalle Valo 	tx_stats->tx_duration += peer_stats->duration;
126d5c65159SKalle Valo }
127d5c65159SKalle Valo 
128*568f0603SKalle Valo void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar,
129d5c65159SKalle Valo 				       struct sk_buff *msdu,
130d5c65159SKalle Valo 				       struct hal_tx_status *ts)
131d5c65159SKalle Valo {
132d5c65159SKalle Valo 	struct ath11k_base *ab = ar->ab;
133d5c65159SKalle Valo 	struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats;
1348cfa7ef8SJohn Crispin 	enum hal_tx_rate_stats_pkt_type pkt_type;
1358cfa7ef8SJohn Crispin 	enum hal_tx_rate_stats_sgi sgi;
1368cfa7ef8SJohn Crispin 	enum hal_tx_rate_stats_bw bw;
137d5c65159SKalle Valo 	struct ath11k_peer *peer;
138d5c65159SKalle Valo 	struct ath11k_sta *arsta;
139d5c65159SKalle Valo 	struct ieee80211_sta *sta;
140d5c65159SKalle Valo 	u16 rate;
141df57acc4SNathan Chancellor 	u8 rate_idx = 0;
142d5c65159SKalle Valo 	int ret;
1438cfa7ef8SJohn Crispin 	u8 mcs;
144d5c65159SKalle Valo 
145d5c65159SKalle Valo 	rcu_read_lock();
146d5c65159SKalle Valo 	spin_lock_bh(&ab->base_lock);
147d5c65159SKalle Valo 	peer = ath11k_peer_find_by_id(ab, ts->peer_id);
148d5c65159SKalle Valo 	if (!peer || !peer->sta) {
149d5c65159SKalle Valo 		ath11k_warn(ab, "failed to find the peer\n");
150d5c65159SKalle Valo 		spin_unlock_bh(&ab->base_lock);
151d5c65159SKalle Valo 		rcu_read_unlock();
152d5c65159SKalle Valo 		return;
153d5c65159SKalle Valo 	}
154d5c65159SKalle Valo 
155d5c65159SKalle Valo 	sta = peer->sta;
156d5c65159SKalle Valo 	arsta = (struct ath11k_sta *)sta->drv_priv;
157d5c65159SKalle Valo 
158d5c65159SKalle Valo 	memset(&arsta->txrate, 0, sizeof(arsta->txrate));
1598cfa7ef8SJohn Crispin 	pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE,
1608cfa7ef8SJohn Crispin 			     ts->rate_stats);
1618cfa7ef8SJohn Crispin 	mcs = FIELD_GET(HAL_TX_RATE_STATS_INFO0_MCS,
1628cfa7ef8SJohn Crispin 			ts->rate_stats);
1638cfa7ef8SJohn Crispin 	sgi = FIELD_GET(HAL_TX_RATE_STATS_INFO0_SGI,
1648cfa7ef8SJohn Crispin 			ts->rate_stats);
1658cfa7ef8SJohn Crispin 	bw = FIELD_GET(HAL_TX_RATE_STATS_INFO0_BW, ts->rate_stats);
166d5c65159SKalle Valo 
1678cfa7ef8SJohn Crispin 	if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A ||
1688cfa7ef8SJohn Crispin 	    pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) {
1698cfa7ef8SJohn Crispin 		ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs,
1708cfa7ef8SJohn Crispin 							    pkt_type,
171d5c65159SKalle Valo 							    &rate_idx,
172d5c65159SKalle Valo 							    &rate);
1738cfa7ef8SJohn Crispin 		if (ret < 0)
1748cfa7ef8SJohn Crispin 			goto err_out;
175d5c65159SKalle Valo 		arsta->txrate.legacy = rate;
1768cfa7ef8SJohn Crispin 	} else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) {
1778cfa7ef8SJohn Crispin 		if (mcs > 7) {
1788cfa7ef8SJohn Crispin 			ath11k_warn(ab, "Invalid HT mcs index %d\n", mcs);
1798cfa7ef8SJohn Crispin 			goto err_out;
180d5c65159SKalle Valo 		}
181d5c65159SKalle Valo 
1828cfa7ef8SJohn Crispin 		arsta->txrate.mcs = mcs + 8 * (arsta->last_txrate.nss - 1);
183d5c65159SKalle Valo 		arsta->txrate.flags = RATE_INFO_FLAGS_MCS;
1848cfa7ef8SJohn Crispin 		if (sgi)
185d5c65159SKalle Valo 			arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1868cfa7ef8SJohn Crispin 	} else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AC) {
1878cfa7ef8SJohn Crispin 		if (mcs > 9) {
1888cfa7ef8SJohn Crispin 			ath11k_warn(ab, "Invalid VHT mcs index %d\n", mcs);
1898cfa7ef8SJohn Crispin 			goto err_out;
190d5c65159SKalle Valo 		}
191d5c65159SKalle Valo 
1928cfa7ef8SJohn Crispin 		arsta->txrate.mcs = mcs;
193d5c65159SKalle Valo 		arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
1948cfa7ef8SJohn Crispin 		if (sgi)
195d5c65159SKalle Valo 			arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
1968cfa7ef8SJohn Crispin 	} else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) {
1978cfa7ef8SJohn Crispin 		/* TODO */
198d5c65159SKalle Valo 	}
199d5c65159SKalle Valo 
200d5c65159SKalle Valo 	arsta->txrate.nss = arsta->last_txrate.nss;
2018cfa7ef8SJohn Crispin 	arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw);
202d5c65159SKalle Valo 
203*568f0603SKalle Valo 	ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, rate_idx);
204*568f0603SKalle Valo 
2058cfa7ef8SJohn Crispin err_out:
206d5c65159SKalle Valo 	spin_unlock_bh(&ab->base_lock);
207d5c65159SKalle Valo 	rcu_read_unlock();
208d5c65159SKalle Valo }
209d5c65159SKalle Valo 
210d5c65159SKalle Valo static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file,
211d5c65159SKalle Valo 					    char __user *user_buf,
212d5c65159SKalle Valo 					    size_t count, loff_t *ppos)
213d5c65159SKalle Valo {
214d5c65159SKalle Valo 	struct ieee80211_sta *sta = file->private_data;
215d5c65159SKalle Valo 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
216d5c65159SKalle Valo 	struct ath11k *ar = arsta->arvif->ar;
217d5c65159SKalle Valo 	struct ath11k_htt_data_stats *stats;
218d5c65159SKalle Valo 	static const char *str_name[ATH11K_STATS_TYPE_MAX] = {"succ", "fail",
219d5c65159SKalle Valo 							      "retry", "ampdu"};
220d5c65159SKalle Valo 	static const char *str[ATH11K_COUNTER_TYPE_MAX] = {"bytes", "packets"};
221d5c65159SKalle Valo 	int len = 0, i, j, k, retval = 0;
222d5c65159SKalle Valo 	const int size = 2 * 4096;
223d5c65159SKalle Valo 	char *buf;
224d5c65159SKalle Valo 
225fe0ebb51SPravas Kumar Panda 	if (!arsta->tx_stats)
226fe0ebb51SPravas Kumar Panda 		return -ENOENT;
227fe0ebb51SPravas Kumar Panda 
228d5c65159SKalle Valo 	buf = kzalloc(size, GFP_KERNEL);
229d5c65159SKalle Valo 	if (!buf)
230d5c65159SKalle Valo 		return -ENOMEM;
231d5c65159SKalle Valo 
232d5c65159SKalle Valo 	mutex_lock(&ar->conf_mutex);
233d5c65159SKalle Valo 
234d5c65159SKalle Valo 	spin_lock_bh(&ar->data_lock);
235d5c65159SKalle Valo 	for (k = 0; k < ATH11K_STATS_TYPE_MAX; k++) {
236d5c65159SKalle Valo 		for (j = 0; j < ATH11K_COUNTER_TYPE_MAX; j++) {
237d5c65159SKalle Valo 			stats = &arsta->tx_stats->stats[k];
238d5c65159SKalle Valo 			len += scnprintf(buf + len, size - len, "%s_%s\n",
239d5c65159SKalle Valo 					 str_name[k],
240d5c65159SKalle Valo 					 str[j]);
241d5c65159SKalle Valo 			len += scnprintf(buf + len, size - len,
242d5c65159SKalle Valo 					 " HE MCS %s\n",
243d5c65159SKalle Valo 					 str[j]);
244d5c65159SKalle Valo 			for (i = 0; i < ATH11K_HE_MCS_NUM; i++)
245d5c65159SKalle Valo 				len += scnprintf(buf + len, size - len,
246d5c65159SKalle Valo 						 "  %llu ",
247d5c65159SKalle Valo 						 stats->he[j][i]);
248d5c65159SKalle Valo 			len += scnprintf(buf + len, size - len, "\n");
249d5c65159SKalle Valo 			len += scnprintf(buf + len, size - len,
250d5c65159SKalle Valo 					 " VHT MCS %s\n",
251d5c65159SKalle Valo 					 str[j]);
252d5c65159SKalle Valo 			for (i = 0; i < ATH11K_VHT_MCS_NUM; i++)
253d5c65159SKalle Valo 				len += scnprintf(buf + len, size - len,
254d5c65159SKalle Valo 						 "  %llu ",
255d5c65159SKalle Valo 						 stats->vht[j][i]);
256d5c65159SKalle Valo 			len += scnprintf(buf + len, size - len, "\n");
257d5c65159SKalle Valo 			len += scnprintf(buf + len, size - len, " HT MCS %s\n",
258d5c65159SKalle Valo 					 str[j]);
259d5c65159SKalle Valo 			for (i = 0; i < ATH11K_HT_MCS_NUM; i++)
260d5c65159SKalle Valo 				len += scnprintf(buf + len, size - len,
261d5c65159SKalle Valo 						 "  %llu ", stats->ht[j][i]);
262d5c65159SKalle Valo 			len += scnprintf(buf + len, size - len, "\n");
263d5c65159SKalle Valo 			len += scnprintf(buf + len, size - len,
264d5c65159SKalle Valo 					" BW %s (20,40,80,160 MHz)\n", str[j]);
265d5c65159SKalle Valo 			len += scnprintf(buf + len, size - len,
266d5c65159SKalle Valo 					 "  %llu %llu %llu %llu\n",
267d5c65159SKalle Valo 					 stats->bw[j][0], stats->bw[j][1],
268d5c65159SKalle Valo 					 stats->bw[j][2], stats->bw[j][3]);
269d5c65159SKalle Valo 			len += scnprintf(buf + len, size - len,
270d5c65159SKalle Valo 					 " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]);
271d5c65159SKalle Valo 			len += scnprintf(buf + len, size - len,
272d5c65159SKalle Valo 					 "  %llu %llu %llu %llu\n",
273d5c65159SKalle Valo 					 stats->nss[j][0], stats->nss[j][1],
274d5c65159SKalle Valo 					 stats->nss[j][2], stats->nss[j][3]);
275d5c65159SKalle Valo 			len += scnprintf(buf + len, size - len,
276d5c65159SKalle Valo 					 " GI %s (0.4us,0.8us,1.6us,3.2us)\n",
277d5c65159SKalle Valo 					 str[j]);
278d5c65159SKalle Valo 			len += scnprintf(buf + len, size - len,
279d5c65159SKalle Valo 					 "  %llu %llu %llu %llu\n",
280d5c65159SKalle Valo 					 stats->gi[j][0], stats->gi[j][1],
281d5c65159SKalle Valo 					 stats->gi[j][2], stats->gi[j][3]);
282d5c65159SKalle Valo 			len += scnprintf(buf + len, size - len,
283d5c65159SKalle Valo 					 " legacy rate %s (1,2 ... Mbps)\n  ",
284d5c65159SKalle Valo 					 str[j]);
285d5c65159SKalle Valo 			for (i = 0; i < ATH11K_LEGACY_NUM; i++)
286d5c65159SKalle Valo 				len += scnprintf(buf + len, size - len, "%llu ",
287d5c65159SKalle Valo 						 stats->legacy[j][i]);
288d5c65159SKalle Valo 			len += scnprintf(buf + len, size - len, "\n");
289d5c65159SKalle Valo 		}
290d5c65159SKalle Valo 	}
291d5c65159SKalle Valo 
292d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len,
293d5c65159SKalle Valo 			 "\nTX duration\n %llu usecs\n",
294d5c65159SKalle Valo 			 arsta->tx_stats->tx_duration);
295d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len,
296d5c65159SKalle Valo 			"BA fails\n %llu\n", arsta->tx_stats->ba_fails);
297d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len,
298d5c65159SKalle Valo 			"ack fails\n %llu\n", arsta->tx_stats->ack_fails);
299d5c65159SKalle Valo 	spin_unlock_bh(&ar->data_lock);
300d5c65159SKalle Valo 
301d5c65159SKalle Valo 	if (len > size)
302d5c65159SKalle Valo 		len = size;
303d5c65159SKalle Valo 	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
304d5c65159SKalle Valo 	kfree(buf);
305d5c65159SKalle Valo 
306d5c65159SKalle Valo 	mutex_unlock(&ar->conf_mutex);
307d5c65159SKalle Valo 	return retval;
308d5c65159SKalle Valo }
309d5c65159SKalle Valo 
310d5c65159SKalle Valo static const struct file_operations fops_tx_stats = {
311d5c65159SKalle Valo 	.read = ath11k_dbg_sta_dump_tx_stats,
312d5c65159SKalle Valo 	.open = simple_open,
313d5c65159SKalle Valo 	.owner = THIS_MODULE,
314d5c65159SKalle Valo 	.llseek = default_llseek,
315d5c65159SKalle Valo };
316d5c65159SKalle Valo 
317d5c65159SKalle Valo static ssize_t ath11k_dbg_sta_dump_rx_stats(struct file *file,
318d5c65159SKalle Valo 					    char __user *user_buf,
319d5c65159SKalle Valo 					    size_t count, loff_t *ppos)
320d5c65159SKalle Valo {
321d5c65159SKalle Valo 	struct ieee80211_sta *sta = file->private_data;
322d5c65159SKalle Valo 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
323d5c65159SKalle Valo 	struct ath11k *ar = arsta->arvif->ar;
324d5c65159SKalle Valo 	struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;
325d5c65159SKalle Valo 	int len = 0, i, retval = 0;
326d5c65159SKalle Valo 	const int size = 4096;
327d5c65159SKalle Valo 	char *buf;
328d5c65159SKalle Valo 
329d5c65159SKalle Valo 	if (!rx_stats)
330d5c65159SKalle Valo 		return -ENOENT;
331d5c65159SKalle Valo 
332d5c65159SKalle Valo 	buf = kzalloc(size, GFP_KERNEL);
333d5c65159SKalle Valo 	if (!buf)
334d5c65159SKalle Valo 		return -ENOMEM;
335d5c65159SKalle Valo 
336d5c65159SKalle Valo 	mutex_lock(&ar->conf_mutex);
337d5c65159SKalle Valo 	spin_lock_bh(&ar->ab->base_lock);
338d5c65159SKalle Valo 
339d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len, "RX peer stats:\n");
340d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len, "Num of MSDUs: %llu\n",
341d5c65159SKalle Valo 			 rx_stats->num_msdu);
342d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len, "Num of MSDUs with TCP L4: %llu\n",
343d5c65159SKalle Valo 			 rx_stats->tcp_msdu_count);
344d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len, "Num of MSDUs with UDP L4: %llu\n",
345d5c65159SKalle Valo 			 rx_stats->udp_msdu_count);
346d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len, "Num of MSDUs part of AMPDU: %llu\n",
347d5c65159SKalle Valo 			 rx_stats->ampdu_msdu_count);
348d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len, "Num of MSDUs not part of AMPDU: %llu\n",
349d5c65159SKalle Valo 			 rx_stats->non_ampdu_msdu_count);
350d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len, "Num of MSDUs using STBC: %llu\n",
351d5c65159SKalle Valo 			 rx_stats->stbc_count);
352d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len, "Num of MSDUs beamformed: %llu\n",
353d5c65159SKalle Valo 			 rx_stats->beamformed_count);
354d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS ok: %llu\n",
355d5c65159SKalle Valo 			 rx_stats->num_mpdu_fcs_ok);
356d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS error: %llu\n",
357d5c65159SKalle Valo 			 rx_stats->num_mpdu_fcs_err);
358d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len,
359d5c65159SKalle Valo 			 "GI: 0.8us %llu 0.4us %llu 1.6us %llu 3.2us %llu\n",
360d5c65159SKalle Valo 			 rx_stats->gi_count[0], rx_stats->gi_count[1],
361d5c65159SKalle Valo 			 rx_stats->gi_count[2], rx_stats->gi_count[3]);
362d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len,
363d5c65159SKalle Valo 			 "BW: 20Mhz %llu 40Mhz %llu 80Mhz %llu 160Mhz %llu\n",
364d5c65159SKalle Valo 			 rx_stats->bw_count[0], rx_stats->bw_count[1],
365d5c65159SKalle Valo 			 rx_stats->bw_count[2], rx_stats->bw_count[3]);
366d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len, "BCC %llu LDPC %llu\n",
367d5c65159SKalle Valo 			 rx_stats->coding_count[0], rx_stats->coding_count[1]);
368d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len,
369d5c65159SKalle Valo 			 "preamble: 11A %llu 11B %llu 11N %llu 11AC %llu 11AX %llu\n",
370d5c65159SKalle Valo 			 rx_stats->pream_cnt[0], rx_stats->pream_cnt[1],
371d5c65159SKalle Valo 			 rx_stats->pream_cnt[2], rx_stats->pream_cnt[3],
372d5c65159SKalle Valo 			 rx_stats->pream_cnt[4]);
373d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len,
374d5c65159SKalle Valo 			 "reception type: SU %llu MU_MIMO %llu MU_OFDMA %llu MU_OFDMA_MIMO %llu\n",
375d5c65159SKalle Valo 			 rx_stats->reception_type[0], rx_stats->reception_type[1],
376d5c65159SKalle Valo 			 rx_stats->reception_type[2], rx_stats->reception_type[3]);
377d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len, "TID(0-15) Legacy TID(16):");
378d5c65159SKalle Valo 	for (i = 0; i <= IEEE80211_NUM_TIDS; i++)
379d5c65159SKalle Valo 		len += scnprintf(buf + len, size - len, "%llu ", rx_stats->tid_count[i]);
380d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len, "\nMCS(0-11) Legacy MCS(12):");
381d5c65159SKalle Valo 	for (i = 0; i < HAL_RX_MAX_MCS + 1; i++)
382d5c65159SKalle Valo 		len += scnprintf(buf + len, size - len, "%llu ", rx_stats->mcs_count[i]);
383d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len, "\nNSS(1-8):");
384d5c65159SKalle Valo 	for (i = 0; i < HAL_RX_MAX_NSS; i++)
385d5c65159SKalle Valo 		len += scnprintf(buf + len, size - len, "%llu ", rx_stats->nss_count[i]);
386d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len, "\nRX Duration:%llu ",
387d5c65159SKalle Valo 			 rx_stats->rx_duration);
3886a0c3702SJohn Crispin 	len += scnprintf(buf + len, size - len,
3896a0c3702SJohn Crispin 			 "\nDCM: %llu\nRU: 26 %llu 52: %llu 106: %llu 242: %llu 484: %llu 996: %llu\n",
3906a0c3702SJohn Crispin 			 rx_stats->dcm_count, rx_stats->ru_alloc_cnt[0],
3916a0c3702SJohn Crispin 			 rx_stats->ru_alloc_cnt[1], rx_stats->ru_alloc_cnt[2],
3926a0c3702SJohn Crispin 			 rx_stats->ru_alloc_cnt[3], rx_stats->ru_alloc_cnt[4],
3936a0c3702SJohn Crispin 			 rx_stats->ru_alloc_cnt[5]);
3946a0c3702SJohn Crispin 
395d5c65159SKalle Valo 	len += scnprintf(buf + len, size - len, "\n");
396d5c65159SKalle Valo 
397d5c65159SKalle Valo 	spin_unlock_bh(&ar->ab->base_lock);
398d5c65159SKalle Valo 
399d5c65159SKalle Valo 	if (len > size)
400d5c65159SKalle Valo 		len = size;
401d5c65159SKalle Valo 	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
402d5c65159SKalle Valo 	kfree(buf);
403d5c65159SKalle Valo 
404d5c65159SKalle Valo 	mutex_unlock(&ar->conf_mutex);
405d5c65159SKalle Valo 	return retval;
406d5c65159SKalle Valo }
407d5c65159SKalle Valo 
408d5c65159SKalle Valo static const struct file_operations fops_rx_stats = {
409d5c65159SKalle Valo 	.read = ath11k_dbg_sta_dump_rx_stats,
410d5c65159SKalle Valo 	.open = simple_open,
411d5c65159SKalle Valo 	.owner = THIS_MODULE,
412d5c65159SKalle Valo 	.llseek = default_llseek,
413d5c65159SKalle Valo };
414d5c65159SKalle Valo 
415d5c65159SKalle Valo static int
416d5c65159SKalle Valo ath11k_dbg_sta_open_htt_peer_stats(struct inode *inode, struct file *file)
417d5c65159SKalle Valo {
418d5c65159SKalle Valo 	struct ieee80211_sta *sta = inode->i_private;
419d5c65159SKalle Valo 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
420d5c65159SKalle Valo 	struct ath11k *ar = arsta->arvif->ar;
421d5c65159SKalle Valo 	struct debug_htt_stats_req *stats_req;
422d5c65159SKalle Valo 	int ret;
423d5c65159SKalle Valo 
424d5c65159SKalle Valo 	stats_req = vzalloc(sizeof(*stats_req) + ATH11K_HTT_STATS_BUF_SIZE);
425d5c65159SKalle Valo 	if (!stats_req)
426d5c65159SKalle Valo 		return -ENOMEM;
427d5c65159SKalle Valo 
428d5c65159SKalle Valo 	mutex_lock(&ar->conf_mutex);
429d5c65159SKalle Valo 	ar->debug.htt_stats.stats_req = stats_req;
430d5c65159SKalle Valo 	stats_req->type = ATH11K_DBG_HTT_EXT_STATS_PEER_INFO;
431d5c65159SKalle Valo 	memcpy(stats_req->peer_addr, sta->addr, ETH_ALEN);
432*568f0603SKalle Valo 	ret = ath11k_debugfs_htt_stats_req(ar);
433d5c65159SKalle Valo 	mutex_unlock(&ar->conf_mutex);
434d5c65159SKalle Valo 	if (ret < 0)
435d5c65159SKalle Valo 		goto out;
436d5c65159SKalle Valo 
437d5c65159SKalle Valo 	file->private_data = stats_req;
438d5c65159SKalle Valo 	return 0;
439d5c65159SKalle Valo out:
440d5c65159SKalle Valo 	vfree(stats_req);
44152f274b5SSowmiya Sree Elavalagan 	ar->debug.htt_stats.stats_req = NULL;
442d5c65159SKalle Valo 	return ret;
443d5c65159SKalle Valo }
444d5c65159SKalle Valo 
445d5c65159SKalle Valo static int
446d5c65159SKalle Valo ath11k_dbg_sta_release_htt_peer_stats(struct inode *inode, struct file *file)
447d5c65159SKalle Valo {
44852f274b5SSowmiya Sree Elavalagan 	struct ieee80211_sta *sta = inode->i_private;
44952f274b5SSowmiya Sree Elavalagan 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
45052f274b5SSowmiya Sree Elavalagan 	struct ath11k *ar = arsta->arvif->ar;
45152f274b5SSowmiya Sree Elavalagan 
45252f274b5SSowmiya Sree Elavalagan 	mutex_lock(&ar->conf_mutex);
453d5c65159SKalle Valo 	vfree(file->private_data);
45452f274b5SSowmiya Sree Elavalagan 	ar->debug.htt_stats.stats_req = NULL;
45552f274b5SSowmiya Sree Elavalagan 	mutex_unlock(&ar->conf_mutex);
45652f274b5SSowmiya Sree Elavalagan 
457d5c65159SKalle Valo 	return 0;
458d5c65159SKalle Valo }
459d5c65159SKalle Valo 
460d5c65159SKalle Valo static ssize_t ath11k_dbg_sta_read_htt_peer_stats(struct file *file,
461d5c65159SKalle Valo 						  char __user *user_buf,
462d5c65159SKalle Valo 						  size_t count, loff_t *ppos)
463d5c65159SKalle Valo {
464d5c65159SKalle Valo 	struct debug_htt_stats_req *stats_req = file->private_data;
465d5c65159SKalle Valo 	char *buf;
466d5c65159SKalle Valo 	u32 length = 0;
467d5c65159SKalle Valo 
468d5c65159SKalle Valo 	buf = stats_req->buf;
469d5c65159SKalle Valo 	length = min_t(u32, stats_req->buf_len, ATH11K_HTT_STATS_BUF_SIZE);
470d5c65159SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, length);
471d5c65159SKalle Valo }
472d5c65159SKalle Valo 
473d5c65159SKalle Valo static const struct file_operations fops_htt_peer_stats = {
474d5c65159SKalle Valo 	.open = ath11k_dbg_sta_open_htt_peer_stats,
475d5c65159SKalle Valo 	.release = ath11k_dbg_sta_release_htt_peer_stats,
476d5c65159SKalle Valo 	.read = ath11k_dbg_sta_read_htt_peer_stats,
477d5c65159SKalle Valo 	.owner = THIS_MODULE,
478d5c65159SKalle Valo 	.llseek = default_llseek,
479d5c65159SKalle Valo };
480d5c65159SKalle Valo 
481d5c65159SKalle Valo static ssize_t ath11k_dbg_sta_write_peer_pktlog(struct file *file,
482d5c65159SKalle Valo 						const char __user *buf,
483d5c65159SKalle Valo 						size_t count, loff_t *ppos)
484d5c65159SKalle Valo {
485d5c65159SKalle Valo 	struct ieee80211_sta *sta = file->private_data;
486d5c65159SKalle Valo 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
487d5c65159SKalle Valo 	struct ath11k *ar = arsta->arvif->ar;
488d5c65159SKalle Valo 	int ret, enable;
489d5c65159SKalle Valo 
490d5c65159SKalle Valo 	mutex_lock(&ar->conf_mutex);
491d5c65159SKalle Valo 
492d5c65159SKalle Valo 	if (ar->state != ATH11K_STATE_ON) {
493d5c65159SKalle Valo 		ret = -ENETDOWN;
494d5c65159SKalle Valo 		goto out;
495d5c65159SKalle Valo 	}
496d5c65159SKalle Valo 
497d5c65159SKalle Valo 	ret = kstrtoint_from_user(buf, count, 0, &enable);
498d5c65159SKalle Valo 	if (ret)
499d5c65159SKalle Valo 		goto out;
500d5c65159SKalle Valo 
501d5c65159SKalle Valo 	ar->debug.pktlog_peer_valid = enable;
502d5c65159SKalle Valo 	memcpy(ar->debug.pktlog_peer_addr, sta->addr, ETH_ALEN);
503d5c65159SKalle Valo 
504d5c65159SKalle Valo 	/* Send peer based pktlog enable/disable */
505d5c65159SKalle Valo 	ret = ath11k_wmi_pdev_peer_pktlog_filter(ar, sta->addr, enable);
506d5c65159SKalle Valo 	if (ret) {
507d5c65159SKalle Valo 		ath11k_warn(ar->ab, "failed to set peer pktlog filter %pM: %d\n",
508d5c65159SKalle Valo 			    sta->addr, ret);
509d5c65159SKalle Valo 		goto out;
510d5c65159SKalle Valo 	}
511d5c65159SKalle Valo 
512d5c65159SKalle Valo 	ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "peer pktlog filter set to %d\n",
513d5c65159SKalle Valo 		   enable);
514d5c65159SKalle Valo 	ret = count;
515d5c65159SKalle Valo 
516d5c65159SKalle Valo out:
517d5c65159SKalle Valo 	mutex_unlock(&ar->conf_mutex);
518d5c65159SKalle Valo 	return ret;
519d5c65159SKalle Valo }
520d5c65159SKalle Valo 
521d5c65159SKalle Valo static ssize_t ath11k_dbg_sta_read_peer_pktlog(struct file *file,
522d5c65159SKalle Valo 					       char __user *ubuf,
523d5c65159SKalle Valo 					       size_t count, loff_t *ppos)
524d5c65159SKalle Valo {
525d5c65159SKalle Valo 	struct ieee80211_sta *sta = file->private_data;
526d5c65159SKalle Valo 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
527d5c65159SKalle Valo 	struct ath11k *ar = arsta->arvif->ar;
528d5c65159SKalle Valo 	char buf[32] = {0};
529d5c65159SKalle Valo 	int len;
530d5c65159SKalle Valo 
531d5c65159SKalle Valo 	mutex_lock(&ar->conf_mutex);
532d5c65159SKalle Valo 	len = scnprintf(buf, sizeof(buf), "%08x %pM\n",
533d5c65159SKalle Valo 			ar->debug.pktlog_peer_valid,
534d5c65159SKalle Valo 			ar->debug.pktlog_peer_addr);
535d5c65159SKalle Valo 	mutex_unlock(&ar->conf_mutex);
536d5c65159SKalle Valo 
537d5c65159SKalle Valo 	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
538d5c65159SKalle Valo }
539d5c65159SKalle Valo 
540d5c65159SKalle Valo static const struct file_operations fops_peer_pktlog = {
541d5c65159SKalle Valo 	.write = ath11k_dbg_sta_write_peer_pktlog,
542d5c65159SKalle Valo 	.read = ath11k_dbg_sta_read_peer_pktlog,
543d5c65159SKalle Valo 	.open = simple_open,
544d5c65159SKalle Valo 	.owner = THIS_MODULE,
545d5c65159SKalle Valo 	.llseek = default_llseek,
546d5c65159SKalle Valo };
547d5c65159SKalle Valo 
5489556dfa2SMaharaja Kennadyrajan static ssize_t ath11k_dbg_sta_write_delba(struct file *file,
5499556dfa2SMaharaja Kennadyrajan 					  const char __user *user_buf,
5509556dfa2SMaharaja Kennadyrajan 					  size_t count, loff_t *ppos)
5519556dfa2SMaharaja Kennadyrajan {
5529556dfa2SMaharaja Kennadyrajan 	struct ieee80211_sta *sta = file->private_data;
5539556dfa2SMaharaja Kennadyrajan 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
5549556dfa2SMaharaja Kennadyrajan 	struct ath11k *ar = arsta->arvif->ar;
5559556dfa2SMaharaja Kennadyrajan 	u32 tid, initiator, reason;
5569556dfa2SMaharaja Kennadyrajan 	int ret;
5579556dfa2SMaharaja Kennadyrajan 	char buf[64] = {0};
5589556dfa2SMaharaja Kennadyrajan 
5599556dfa2SMaharaja Kennadyrajan 	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
5609556dfa2SMaharaja Kennadyrajan 				     user_buf, count);
5619556dfa2SMaharaja Kennadyrajan 	if (ret <= 0)
5629556dfa2SMaharaja Kennadyrajan 		return ret;
5639556dfa2SMaharaja Kennadyrajan 
5649556dfa2SMaharaja Kennadyrajan 	ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);
5659556dfa2SMaharaja Kennadyrajan 	if (ret != 3)
5669556dfa2SMaharaja Kennadyrajan 		return -EINVAL;
5679556dfa2SMaharaja Kennadyrajan 
5689556dfa2SMaharaja Kennadyrajan 	/* Valid TID values are 0 through 15 */
5699556dfa2SMaharaja Kennadyrajan 	if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
5709556dfa2SMaharaja Kennadyrajan 		return -EINVAL;
5719556dfa2SMaharaja Kennadyrajan 
5729556dfa2SMaharaja Kennadyrajan 	mutex_lock(&ar->conf_mutex);
5739556dfa2SMaharaja Kennadyrajan 	if (ar->state != ATH11K_STATE_ON ||
5749556dfa2SMaharaja Kennadyrajan 	    arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
5759556dfa2SMaharaja Kennadyrajan 		ret = count;
5769556dfa2SMaharaja Kennadyrajan 		goto out;
5779556dfa2SMaharaja Kennadyrajan 	}
5789556dfa2SMaharaja Kennadyrajan 
5799556dfa2SMaharaja Kennadyrajan 	ret = ath11k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,
5809556dfa2SMaharaja Kennadyrajan 				    tid, initiator, reason);
5819556dfa2SMaharaja Kennadyrajan 	if (ret) {
5829556dfa2SMaharaja Kennadyrajan 		ath11k_warn(ar->ab, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",
5839556dfa2SMaharaja Kennadyrajan 			    arsta->arvif->vdev_id, sta->addr, tid, initiator,
5849556dfa2SMaharaja Kennadyrajan 			    reason);
5859556dfa2SMaharaja Kennadyrajan 	}
5869556dfa2SMaharaja Kennadyrajan 	ret = count;
5879556dfa2SMaharaja Kennadyrajan out:
5889556dfa2SMaharaja Kennadyrajan 	mutex_unlock(&ar->conf_mutex);
5899556dfa2SMaharaja Kennadyrajan 	return ret;
5909556dfa2SMaharaja Kennadyrajan }
5919556dfa2SMaharaja Kennadyrajan 
5929556dfa2SMaharaja Kennadyrajan static const struct file_operations fops_delba = {
5939556dfa2SMaharaja Kennadyrajan 	.write = ath11k_dbg_sta_write_delba,
5949556dfa2SMaharaja Kennadyrajan 	.open = simple_open,
5959556dfa2SMaharaja Kennadyrajan 	.owner = THIS_MODULE,
5969556dfa2SMaharaja Kennadyrajan 	.llseek = default_llseek,
5979556dfa2SMaharaja Kennadyrajan };
5989556dfa2SMaharaja Kennadyrajan 
5999556dfa2SMaharaja Kennadyrajan static ssize_t ath11k_dbg_sta_write_addba_resp(struct file *file,
6009556dfa2SMaharaja Kennadyrajan 					       const char __user *user_buf,
6019556dfa2SMaharaja Kennadyrajan 					       size_t count, loff_t *ppos)
6029556dfa2SMaharaja Kennadyrajan {
6039556dfa2SMaharaja Kennadyrajan 	struct ieee80211_sta *sta = file->private_data;
6049556dfa2SMaharaja Kennadyrajan 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
6059556dfa2SMaharaja Kennadyrajan 	struct ath11k *ar = arsta->arvif->ar;
6069556dfa2SMaharaja Kennadyrajan 	u32 tid, status;
6079556dfa2SMaharaja Kennadyrajan 	int ret;
6089556dfa2SMaharaja Kennadyrajan 	char buf[64] = {0};
6099556dfa2SMaharaja Kennadyrajan 
6109556dfa2SMaharaja Kennadyrajan 	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
6119556dfa2SMaharaja Kennadyrajan 				     user_buf, count);
6129556dfa2SMaharaja Kennadyrajan 	if (ret <= 0)
6139556dfa2SMaharaja Kennadyrajan 		return ret;
6149556dfa2SMaharaja Kennadyrajan 
6159556dfa2SMaharaja Kennadyrajan 	ret = sscanf(buf, "%u %u", &tid, &status);
6169556dfa2SMaharaja Kennadyrajan 	if (ret != 2)
6179556dfa2SMaharaja Kennadyrajan 		return -EINVAL;
6189556dfa2SMaharaja Kennadyrajan 
6199556dfa2SMaharaja Kennadyrajan 	/* Valid TID values are 0 through 15 */
6209556dfa2SMaharaja Kennadyrajan 	if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
6219556dfa2SMaharaja Kennadyrajan 		return -EINVAL;
6229556dfa2SMaharaja Kennadyrajan 
6239556dfa2SMaharaja Kennadyrajan 	mutex_lock(&ar->conf_mutex);
6249556dfa2SMaharaja Kennadyrajan 	if (ar->state != ATH11K_STATE_ON ||
6259556dfa2SMaharaja Kennadyrajan 	    arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
6269556dfa2SMaharaja Kennadyrajan 		ret = count;
6279556dfa2SMaharaja Kennadyrajan 		goto out;
6289556dfa2SMaharaja Kennadyrajan 	}
6299556dfa2SMaharaja Kennadyrajan 
6309556dfa2SMaharaja Kennadyrajan 	ret = ath11k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,
6319556dfa2SMaharaja Kennadyrajan 					tid, status);
6329556dfa2SMaharaja Kennadyrajan 	if (ret) {
6339556dfa2SMaharaja Kennadyrajan 		ath11k_warn(ar->ab, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",
6349556dfa2SMaharaja Kennadyrajan 			    arsta->arvif->vdev_id, sta->addr, tid, status);
6359556dfa2SMaharaja Kennadyrajan 	}
6369556dfa2SMaharaja Kennadyrajan 	ret = count;
6379556dfa2SMaharaja Kennadyrajan out:
6389556dfa2SMaharaja Kennadyrajan 	mutex_unlock(&ar->conf_mutex);
6399556dfa2SMaharaja Kennadyrajan 	return ret;
6409556dfa2SMaharaja Kennadyrajan }
6419556dfa2SMaharaja Kennadyrajan 
6429556dfa2SMaharaja Kennadyrajan static const struct file_operations fops_addba_resp = {
6439556dfa2SMaharaja Kennadyrajan 	.write = ath11k_dbg_sta_write_addba_resp,
6449556dfa2SMaharaja Kennadyrajan 	.open = simple_open,
6459556dfa2SMaharaja Kennadyrajan 	.owner = THIS_MODULE,
6469556dfa2SMaharaja Kennadyrajan 	.llseek = default_llseek,
6479556dfa2SMaharaja Kennadyrajan };
6489556dfa2SMaharaja Kennadyrajan 
6499556dfa2SMaharaja Kennadyrajan static ssize_t ath11k_dbg_sta_write_addba(struct file *file,
6509556dfa2SMaharaja Kennadyrajan 					  const char __user *user_buf,
6519556dfa2SMaharaja Kennadyrajan 					  size_t count, loff_t *ppos)
6529556dfa2SMaharaja Kennadyrajan {
6539556dfa2SMaharaja Kennadyrajan 	struct ieee80211_sta *sta = file->private_data;
6549556dfa2SMaharaja Kennadyrajan 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
6559556dfa2SMaharaja Kennadyrajan 	struct ath11k *ar = arsta->arvif->ar;
6569556dfa2SMaharaja Kennadyrajan 	u32 tid, buf_size;
6579556dfa2SMaharaja Kennadyrajan 	int ret;
6589556dfa2SMaharaja Kennadyrajan 	char buf[64] = {0};
6599556dfa2SMaharaja Kennadyrajan 
6609556dfa2SMaharaja Kennadyrajan 	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
6619556dfa2SMaharaja Kennadyrajan 				     user_buf, count);
6629556dfa2SMaharaja Kennadyrajan 	if (ret <= 0)
6639556dfa2SMaharaja Kennadyrajan 		return ret;
6649556dfa2SMaharaja Kennadyrajan 
6659556dfa2SMaharaja Kennadyrajan 	ret = sscanf(buf, "%u %u", &tid, &buf_size);
6669556dfa2SMaharaja Kennadyrajan 	if (ret != 2)
6679556dfa2SMaharaja Kennadyrajan 		return -EINVAL;
6689556dfa2SMaharaja Kennadyrajan 
6699556dfa2SMaharaja Kennadyrajan 	/* Valid TID values are 0 through 15 */
6709556dfa2SMaharaja Kennadyrajan 	if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
6719556dfa2SMaharaja Kennadyrajan 		return -EINVAL;
6729556dfa2SMaharaja Kennadyrajan 
6739556dfa2SMaharaja Kennadyrajan 	mutex_lock(&ar->conf_mutex);
6749556dfa2SMaharaja Kennadyrajan 	if (ar->state != ATH11K_STATE_ON ||
6759556dfa2SMaharaja Kennadyrajan 	    arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
6769556dfa2SMaharaja Kennadyrajan 		ret = count;
6779556dfa2SMaharaja Kennadyrajan 		goto out;
6789556dfa2SMaharaja Kennadyrajan 	}
6799556dfa2SMaharaja Kennadyrajan 
6809556dfa2SMaharaja Kennadyrajan 	ret = ath11k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,
6819556dfa2SMaharaja Kennadyrajan 				    tid, buf_size);
6829556dfa2SMaharaja Kennadyrajan 	if (ret) {
6839556dfa2SMaharaja Kennadyrajan 		ath11k_warn(ar->ab, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",
6849556dfa2SMaharaja Kennadyrajan 			    arsta->arvif->vdev_id, sta->addr, tid, buf_size);
6859556dfa2SMaharaja Kennadyrajan 	}
6869556dfa2SMaharaja Kennadyrajan 
6879556dfa2SMaharaja Kennadyrajan 	ret = count;
6889556dfa2SMaharaja Kennadyrajan out:
6899556dfa2SMaharaja Kennadyrajan 	mutex_unlock(&ar->conf_mutex);
6909556dfa2SMaharaja Kennadyrajan 	return ret;
6919556dfa2SMaharaja Kennadyrajan }
6929556dfa2SMaharaja Kennadyrajan 
6939556dfa2SMaharaja Kennadyrajan static const struct file_operations fops_addba = {
6949556dfa2SMaharaja Kennadyrajan 	.write = ath11k_dbg_sta_write_addba,
6959556dfa2SMaharaja Kennadyrajan 	.open = simple_open,
6969556dfa2SMaharaja Kennadyrajan 	.owner = THIS_MODULE,
6979556dfa2SMaharaja Kennadyrajan 	.llseek = default_llseek,
6989556dfa2SMaharaja Kennadyrajan };
6999556dfa2SMaharaja Kennadyrajan 
7009556dfa2SMaharaja Kennadyrajan static ssize_t ath11k_dbg_sta_read_aggr_mode(struct file *file,
7019556dfa2SMaharaja Kennadyrajan 					     char __user *user_buf,
7029556dfa2SMaharaja Kennadyrajan 					     size_t count, loff_t *ppos)
7039556dfa2SMaharaja Kennadyrajan {
7049556dfa2SMaharaja Kennadyrajan 	struct ieee80211_sta *sta = file->private_data;
7059556dfa2SMaharaja Kennadyrajan 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
7069556dfa2SMaharaja Kennadyrajan 	struct ath11k *ar = arsta->arvif->ar;
7079556dfa2SMaharaja Kennadyrajan 	char buf[64];
7089556dfa2SMaharaja Kennadyrajan 	int len = 0;
7099556dfa2SMaharaja Kennadyrajan 
7109556dfa2SMaharaja Kennadyrajan 	mutex_lock(&ar->conf_mutex);
7119556dfa2SMaharaja Kennadyrajan 	len = scnprintf(buf, sizeof(buf) - len,
7129556dfa2SMaharaja Kennadyrajan 			"aggregation mode: %s\n\n%s\n%s\n",
7139556dfa2SMaharaja Kennadyrajan 			(arsta->aggr_mode == ATH11K_DBG_AGGR_MODE_AUTO) ?
7149556dfa2SMaharaja Kennadyrajan 			"auto" : "manual", "auto = 0", "manual = 1");
7159556dfa2SMaharaja Kennadyrajan 	mutex_unlock(&ar->conf_mutex);
7169556dfa2SMaharaja Kennadyrajan 
7179556dfa2SMaharaja Kennadyrajan 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
7189556dfa2SMaharaja Kennadyrajan }
7199556dfa2SMaharaja Kennadyrajan 
7209556dfa2SMaharaja Kennadyrajan static ssize_t ath11k_dbg_sta_write_aggr_mode(struct file *file,
7219556dfa2SMaharaja Kennadyrajan 					      const char __user *user_buf,
7229556dfa2SMaharaja Kennadyrajan 					      size_t count, loff_t *ppos)
7239556dfa2SMaharaja Kennadyrajan {
7249556dfa2SMaharaja Kennadyrajan 	struct ieee80211_sta *sta = file->private_data;
7259556dfa2SMaharaja Kennadyrajan 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
7269556dfa2SMaharaja Kennadyrajan 	struct ath11k *ar = arsta->arvif->ar;
7279556dfa2SMaharaja Kennadyrajan 	u32 aggr_mode;
7289556dfa2SMaharaja Kennadyrajan 	int ret;
7299556dfa2SMaharaja Kennadyrajan 
7309556dfa2SMaharaja Kennadyrajan 	if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))
7319556dfa2SMaharaja Kennadyrajan 		return -EINVAL;
7329556dfa2SMaharaja Kennadyrajan 
7339556dfa2SMaharaja Kennadyrajan 	if (aggr_mode >= ATH11K_DBG_AGGR_MODE_MAX)
7349556dfa2SMaharaja Kennadyrajan 		return -EINVAL;
7359556dfa2SMaharaja Kennadyrajan 
7369556dfa2SMaharaja Kennadyrajan 	mutex_lock(&ar->conf_mutex);
7379556dfa2SMaharaja Kennadyrajan 	if (ar->state != ATH11K_STATE_ON ||
7389556dfa2SMaharaja Kennadyrajan 	    aggr_mode == arsta->aggr_mode) {
7399556dfa2SMaharaja Kennadyrajan 		ret = count;
7409556dfa2SMaharaja Kennadyrajan 		goto out;
7419556dfa2SMaharaja Kennadyrajan 	}
7429556dfa2SMaharaja Kennadyrajan 
7439556dfa2SMaharaja Kennadyrajan 	ret = ath11k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);
7449556dfa2SMaharaja Kennadyrajan 	if (ret) {
7459556dfa2SMaharaja Kennadyrajan 		ath11k_warn(ar->ab, "failed to clear addba session ret: %d\n",
7469556dfa2SMaharaja Kennadyrajan 			    ret);
7479556dfa2SMaharaja Kennadyrajan 		goto out;
7489556dfa2SMaharaja Kennadyrajan 	}
7499556dfa2SMaharaja Kennadyrajan 
7509556dfa2SMaharaja Kennadyrajan 	arsta->aggr_mode = aggr_mode;
7519556dfa2SMaharaja Kennadyrajan out:
7529556dfa2SMaharaja Kennadyrajan 	mutex_unlock(&ar->conf_mutex);
7539556dfa2SMaharaja Kennadyrajan 	return ret;
7549556dfa2SMaharaja Kennadyrajan }
7559556dfa2SMaharaja Kennadyrajan 
7569556dfa2SMaharaja Kennadyrajan static const struct file_operations fops_aggr_mode = {
7579556dfa2SMaharaja Kennadyrajan 	.read = ath11k_dbg_sta_read_aggr_mode,
7589556dfa2SMaharaja Kennadyrajan 	.write = ath11k_dbg_sta_write_aggr_mode,
7599556dfa2SMaharaja Kennadyrajan 	.open = simple_open,
7609556dfa2SMaharaja Kennadyrajan 	.owner = THIS_MODULE,
7619556dfa2SMaharaja Kennadyrajan 	.llseek = default_llseek,
7629556dfa2SMaharaja Kennadyrajan };
7639556dfa2SMaharaja Kennadyrajan 
764559ef68fSAshok Raj Nagarajan static ssize_t
765559ef68fSAshok Raj Nagarajan ath11k_write_htt_peer_stats_reset(struct file *file,
766559ef68fSAshok Raj Nagarajan 				  const char __user *user_buf,
767559ef68fSAshok Raj Nagarajan 				  size_t count, loff_t *ppos)
768559ef68fSAshok Raj Nagarajan {
769559ef68fSAshok Raj Nagarajan 	struct ieee80211_sta *sta = file->private_data;
770559ef68fSAshok Raj Nagarajan 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
771559ef68fSAshok Raj Nagarajan 	struct ath11k *ar = arsta->arvif->ar;
772559ef68fSAshok Raj Nagarajan 	struct htt_ext_stats_cfg_params cfg_params = { 0 };
773559ef68fSAshok Raj Nagarajan 	int ret;
774559ef68fSAshok Raj Nagarajan 	u8 type;
775559ef68fSAshok Raj Nagarajan 
776559ef68fSAshok Raj Nagarajan 	ret = kstrtou8_from_user(user_buf, count, 0, &type);
777559ef68fSAshok Raj Nagarajan 	if (ret)
778559ef68fSAshok Raj Nagarajan 		return ret;
779559ef68fSAshok Raj Nagarajan 
780559ef68fSAshok Raj Nagarajan 	if (!type)
781559ef68fSAshok Raj Nagarajan 		return ret;
782559ef68fSAshok Raj Nagarajan 
783559ef68fSAshok Raj Nagarajan 	mutex_lock(&ar->conf_mutex);
784559ef68fSAshok Raj Nagarajan 	cfg_params.cfg0 = HTT_STAT_PEER_INFO_MAC_ADDR;
785559ef68fSAshok Raj Nagarajan 	cfg_params.cfg0 |= FIELD_PREP(GENMASK(15, 1),
786559ef68fSAshok Raj Nagarajan 				HTT_PEER_STATS_REQ_MODE_FLUSH_TQM);
787559ef68fSAshok Raj Nagarajan 
788559ef68fSAshok Raj Nagarajan 	cfg_params.cfg1 = HTT_STAT_DEFAULT_PEER_REQ_TYPE;
789559ef68fSAshok Raj Nagarajan 
790559ef68fSAshok Raj Nagarajan 	cfg_params.cfg2 |= FIELD_PREP(GENMASK(7, 0), sta->addr[0]);
791559ef68fSAshok Raj Nagarajan 	cfg_params.cfg2 |= FIELD_PREP(GENMASK(15, 8), sta->addr[1]);
792559ef68fSAshok Raj Nagarajan 	cfg_params.cfg2 |= FIELD_PREP(GENMASK(23, 16), sta->addr[2]);
793559ef68fSAshok Raj Nagarajan 	cfg_params.cfg2 |= FIELD_PREP(GENMASK(31, 24), sta->addr[3]);
794559ef68fSAshok Raj Nagarajan 
795559ef68fSAshok Raj Nagarajan 	cfg_params.cfg3 |= FIELD_PREP(GENMASK(7, 0), sta->addr[4]);
796559ef68fSAshok Raj Nagarajan 	cfg_params.cfg3 |= FIELD_PREP(GENMASK(15, 8), sta->addr[5]);
797559ef68fSAshok Raj Nagarajan 
798559ef68fSAshok Raj Nagarajan 	cfg_params.cfg3 |= ATH11K_HTT_PEER_STATS_RESET;
799559ef68fSAshok Raj Nagarajan 
800559ef68fSAshok Raj Nagarajan 	ret = ath11k_dp_tx_htt_h2t_ext_stats_req(ar,
801559ef68fSAshok Raj Nagarajan 						 ATH11K_DBG_HTT_EXT_STATS_PEER_INFO,
802559ef68fSAshok Raj Nagarajan 						 &cfg_params,
803559ef68fSAshok Raj Nagarajan 						 0ULL);
804559ef68fSAshok Raj Nagarajan 	if (ret) {
805559ef68fSAshok Raj Nagarajan 		ath11k_warn(ar->ab, "failed to send htt peer stats request: %d\n", ret);
806559ef68fSAshok Raj Nagarajan 		mutex_unlock(&ar->conf_mutex);
807559ef68fSAshok Raj Nagarajan 		return ret;
808559ef68fSAshok Raj Nagarajan 	}
809559ef68fSAshok Raj Nagarajan 
810559ef68fSAshok Raj Nagarajan 	mutex_unlock(&ar->conf_mutex);
811559ef68fSAshok Raj Nagarajan 
812559ef68fSAshok Raj Nagarajan 	ret = count;
813559ef68fSAshok Raj Nagarajan 
814559ef68fSAshok Raj Nagarajan 	return ret;
815559ef68fSAshok Raj Nagarajan }
816559ef68fSAshok Raj Nagarajan 
817559ef68fSAshok Raj Nagarajan static const struct file_operations fops_htt_peer_stats_reset = {
818559ef68fSAshok Raj Nagarajan 	.write = ath11k_write_htt_peer_stats_reset,
819559ef68fSAshok Raj Nagarajan 	.open = simple_open,
820559ef68fSAshok Raj Nagarajan 	.owner = THIS_MODULE,
821559ef68fSAshok Raj Nagarajan 	.llseek = default_llseek,
822559ef68fSAshok Raj Nagarajan };
823559ef68fSAshok Raj Nagarajan 
824*568f0603SKalle Valo void ath11k_debugfs_sta_op_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
825d5c65159SKalle Valo 			       struct ieee80211_sta *sta, struct dentry *dir)
826d5c65159SKalle Valo {
827d5c65159SKalle Valo 	struct ath11k *ar = hw->priv;
828d5c65159SKalle Valo 
829cb4e57dbSKalle Valo 	if (ath11k_debugfs_is_extd_tx_stats_enabled(ar))
830d5c65159SKalle Valo 		debugfs_create_file("tx_stats", 0400, dir, sta,
831d5c65159SKalle Valo 				    &fops_tx_stats);
832cb4e57dbSKalle Valo 	if (ath11k_debugfs_is_extd_rx_stats_enabled(ar))
833d5c65159SKalle Valo 		debugfs_create_file("rx_stats", 0400, dir, sta,
834d5c65159SKalle Valo 				    &fops_rx_stats);
835d5c65159SKalle Valo 
836d5c65159SKalle Valo 	debugfs_create_file("htt_peer_stats", 0400, dir, sta,
837d5c65159SKalle Valo 			    &fops_htt_peer_stats);
838d5c65159SKalle Valo 
839d5c65159SKalle Valo 	debugfs_create_file("peer_pktlog", 0644, dir, sta,
840d5c65159SKalle Valo 			    &fops_peer_pktlog);
8419556dfa2SMaharaja Kennadyrajan 
8429556dfa2SMaharaja Kennadyrajan 	debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode);
8439556dfa2SMaharaja Kennadyrajan 	debugfs_create_file("addba", 0200, dir, sta, &fops_addba);
8449556dfa2SMaharaja Kennadyrajan 	debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);
8459556dfa2SMaharaja Kennadyrajan 	debugfs_create_file("delba", 0200, dir, sta, &fops_delba);
846559ef68fSAshok Raj Nagarajan 
847559ef68fSAshok Raj Nagarajan 	if (test_bit(WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET,
848559ef68fSAshok Raj Nagarajan 		     ar->ab->wmi_ab.svc_map))
849559ef68fSAshok Raj Nagarajan 		debugfs_create_file("htt_peer_stats_reset", 0600, dir, sta,
850559ef68fSAshok Raj Nagarajan 				    &fops_htt_peer_stats_reset);
851d5c65159SKalle Valo }
852