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