1 // SPDX-License-Identifier: BSD-3-Clause-Clear
2 /*
3  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
4  */
5 
6 #include <linux/vmalloc.h>
7 
8 #include "core.h"
9 #include "peer.h"
10 #include "debug.h"
11 
12 void
13 ath11k_accumulate_per_peer_tx_stats(struct ath11k_sta *arsta,
14 				    struct ath11k_per_peer_tx_stats *peer_stats,
15 				    u8 legacy_rate_idx)
16 {
17 	struct rate_info *txrate = &arsta->txrate;
18 	struct ath11k_htt_tx_stats *tx_stats;
19 	int gi, mcs, bw, nss;
20 
21 	if (!arsta->tx_stats)
22 		return;
23 
24 	tx_stats = arsta->tx_stats;
25 	gi = FIELD_GET(RATE_INFO_FLAGS_SHORT_GI, arsta->txrate.flags);
26 	mcs = txrate->mcs;
27 	bw = txrate->bw;
28 	nss = txrate->nss - 1;
29 
30 #define STATS_OP_FMT(name) tx_stats->stats[ATH11K_STATS_TYPE_##name]
31 
32 	if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
33 		STATS_OP_FMT(SUCC).he[0][mcs] += peer_stats->succ_bytes;
34 		STATS_OP_FMT(SUCC).he[1][mcs] += peer_stats->succ_pkts;
35 		STATS_OP_FMT(FAIL).he[0][mcs] += peer_stats->failed_bytes;
36 		STATS_OP_FMT(FAIL).he[1][mcs] += peer_stats->failed_pkts;
37 		STATS_OP_FMT(RETRY).he[0][mcs] += peer_stats->retry_bytes;
38 		STATS_OP_FMT(RETRY).he[1][mcs] += peer_stats->retry_pkts;
39 	} else if (txrate->flags & RATE_INFO_FLAGS_VHT_MCS) {
40 		STATS_OP_FMT(SUCC).vht[0][mcs] += peer_stats->succ_bytes;
41 		STATS_OP_FMT(SUCC).vht[1][mcs] += peer_stats->succ_pkts;
42 		STATS_OP_FMT(FAIL).vht[0][mcs] += peer_stats->failed_bytes;
43 		STATS_OP_FMT(FAIL).vht[1][mcs] += peer_stats->failed_pkts;
44 		STATS_OP_FMT(RETRY).vht[0][mcs] += peer_stats->retry_bytes;
45 		STATS_OP_FMT(RETRY).vht[1][mcs] += peer_stats->retry_pkts;
46 	} else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
47 		STATS_OP_FMT(SUCC).ht[0][mcs] += peer_stats->succ_bytes;
48 		STATS_OP_FMT(SUCC).ht[1][mcs] += peer_stats->succ_pkts;
49 		STATS_OP_FMT(FAIL).ht[0][mcs] += peer_stats->failed_bytes;
50 		STATS_OP_FMT(FAIL).ht[1][mcs] += peer_stats->failed_pkts;
51 		STATS_OP_FMT(RETRY).ht[0][mcs] += peer_stats->retry_bytes;
52 		STATS_OP_FMT(RETRY).ht[1][mcs] += peer_stats->retry_pkts;
53 	} else {
54 		mcs = legacy_rate_idx;
55 
56 		STATS_OP_FMT(SUCC).legacy[0][mcs] += peer_stats->succ_bytes;
57 		STATS_OP_FMT(SUCC).legacy[1][mcs] += peer_stats->succ_pkts;
58 		STATS_OP_FMT(FAIL).legacy[0][mcs] += peer_stats->failed_bytes;
59 		STATS_OP_FMT(FAIL).legacy[1][mcs] += peer_stats->failed_pkts;
60 		STATS_OP_FMT(RETRY).legacy[0][mcs] += peer_stats->retry_bytes;
61 		STATS_OP_FMT(RETRY).legacy[1][mcs] += peer_stats->retry_pkts;
62 	}
63 
64 	if (peer_stats->is_ampdu) {
65 		tx_stats->ba_fails += peer_stats->ba_fails;
66 
67 		if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
68 			STATS_OP_FMT(AMPDU).he[0][mcs] +=
69 			peer_stats->succ_bytes + peer_stats->retry_bytes;
70 			STATS_OP_FMT(AMPDU).he[1][mcs] +=
71 			peer_stats->succ_pkts + peer_stats->retry_pkts;
72 		} else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
73 			STATS_OP_FMT(AMPDU).ht[0][mcs] +=
74 			peer_stats->succ_bytes + peer_stats->retry_bytes;
75 			STATS_OP_FMT(AMPDU).ht[1][mcs] +=
76 			peer_stats->succ_pkts + peer_stats->retry_pkts;
77 		} else {
78 			STATS_OP_FMT(AMPDU).vht[0][mcs] +=
79 			peer_stats->succ_bytes + peer_stats->retry_bytes;
80 			STATS_OP_FMT(AMPDU).vht[1][mcs] +=
81 			peer_stats->succ_pkts + peer_stats->retry_pkts;
82 		}
83 		STATS_OP_FMT(AMPDU).bw[0][bw] +=
84 			peer_stats->succ_bytes + peer_stats->retry_bytes;
85 		STATS_OP_FMT(AMPDU).nss[0][nss] +=
86 			peer_stats->succ_bytes + peer_stats->retry_bytes;
87 		STATS_OP_FMT(AMPDU).gi[0][gi] +=
88 			peer_stats->succ_bytes + peer_stats->retry_bytes;
89 		STATS_OP_FMT(AMPDU).bw[1][bw] +=
90 			peer_stats->succ_pkts + peer_stats->retry_pkts;
91 		STATS_OP_FMT(AMPDU).nss[1][nss] +=
92 			peer_stats->succ_pkts + peer_stats->retry_pkts;
93 		STATS_OP_FMT(AMPDU).gi[1][gi] +=
94 			peer_stats->succ_pkts + peer_stats->retry_pkts;
95 	} else {
96 		tx_stats->ack_fails += peer_stats->ba_fails;
97 	}
98 
99 	STATS_OP_FMT(SUCC).bw[0][bw] += peer_stats->succ_bytes;
100 	STATS_OP_FMT(SUCC).nss[0][nss] += peer_stats->succ_bytes;
101 	STATS_OP_FMT(SUCC).gi[0][gi] += peer_stats->succ_bytes;
102 
103 	STATS_OP_FMT(SUCC).bw[1][bw] += peer_stats->succ_pkts;
104 	STATS_OP_FMT(SUCC).nss[1][nss] += peer_stats->succ_pkts;
105 	STATS_OP_FMT(SUCC).gi[1][gi] += peer_stats->succ_pkts;
106 
107 	STATS_OP_FMT(FAIL).bw[0][bw] += peer_stats->failed_bytes;
108 	STATS_OP_FMT(FAIL).nss[0][nss] += peer_stats->failed_bytes;
109 	STATS_OP_FMT(FAIL).gi[0][gi] += peer_stats->failed_bytes;
110 
111 	STATS_OP_FMT(FAIL).bw[1][bw] += peer_stats->failed_pkts;
112 	STATS_OP_FMT(FAIL).nss[1][nss] += peer_stats->failed_pkts;
113 	STATS_OP_FMT(FAIL).gi[1][gi] += peer_stats->failed_pkts;
114 
115 	STATS_OP_FMT(RETRY).bw[0][bw] += peer_stats->retry_bytes;
116 	STATS_OP_FMT(RETRY).nss[0][nss] += peer_stats->retry_bytes;
117 	STATS_OP_FMT(RETRY).gi[0][gi] += peer_stats->retry_bytes;
118 
119 	STATS_OP_FMT(RETRY).bw[1][bw] += peer_stats->retry_pkts;
120 	STATS_OP_FMT(RETRY).nss[1][nss] += peer_stats->retry_pkts;
121 	STATS_OP_FMT(RETRY).gi[1][gi] += peer_stats->retry_pkts;
122 
123 	tx_stats->tx_duration += peer_stats->duration;
124 }
125 
126 void ath11k_update_per_peer_stats_from_txcompl(struct ath11k *ar,
127 					       struct sk_buff *msdu,
128 					       struct hal_tx_status *ts)
129 {
130 	struct ath11k_base *ab = ar->ab;
131 	struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats;
132 	struct ath11k_peer *peer;
133 	struct ath11k_sta *arsta;
134 	struct ieee80211_sta *sta;
135 	u16 rate;
136 	u8 rate_idx;
137 	int ret;
138 
139 	rcu_read_lock();
140 	spin_lock_bh(&ab->base_lock);
141 	peer = ath11k_peer_find_by_id(ab, ts->peer_id);
142 	if (!peer || !peer->sta) {
143 		ath11k_warn(ab, "failed to find the peer\n");
144 		spin_unlock_bh(&ab->base_lock);
145 		rcu_read_unlock();
146 		return;
147 	}
148 
149 	sta = peer->sta;
150 	arsta = (struct ath11k_sta *)sta->drv_priv;
151 
152 	memset(&arsta->txrate, 0, sizeof(arsta->txrate));
153 
154 	if (ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A ||
155 	    ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) {
156 		ret = ath11k_mac_hw_ratecode_to_legacy_rate(ts->mcs,
157 							    ts->pkt_type,
158 							    &rate_idx,
159 							    &rate);
160 		if (ret < 0) {
161 			spin_unlock_bh(&ab->base_lock);
162 			rcu_read_unlock();
163 			return;
164 		}
165 		arsta->txrate.legacy = rate;
166 	} else if (ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) {
167 		if (ts->mcs > 7) {
168 			ath11k_warn(ab, "Invalid HT mcs index %d\n", ts->mcs);
169 			spin_unlock_bh(&ab->base_lock);
170 			rcu_read_unlock();
171 			return;
172 		}
173 
174 		arsta->txrate.mcs = ts->mcs + 8 * (arsta->last_txrate.nss - 1);
175 		arsta->txrate.flags = RATE_INFO_FLAGS_MCS;
176 		if (ts->sgi)
177 			arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
178 	} else if (ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AC) {
179 		if (ts->mcs > 9) {
180 			ath11k_warn(ab, "Invalid VHT mcs index %d\n", ts->mcs);
181 			spin_unlock_bh(&ab->base_lock);
182 			rcu_read_unlock();
183 			return;
184 		}
185 
186 		arsta->txrate.mcs = ts->mcs;
187 		arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
188 		if (ts->sgi)
189 			arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
190 	} else {
191 		/*TODO: update HE rates */
192 	}
193 
194 	arsta->txrate.nss = arsta->last_txrate.nss;
195 	arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(ts->bw);
196 
197 	ath11k_accumulate_per_peer_tx_stats(arsta, peer_stats, rate_idx);
198 	spin_unlock_bh(&ab->base_lock);
199 	rcu_read_unlock();
200 }
201 
202 static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file,
203 					    char __user *user_buf,
204 					    size_t count, loff_t *ppos)
205 {
206 	struct ieee80211_sta *sta = file->private_data;
207 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
208 	struct ath11k *ar = arsta->arvif->ar;
209 	struct ath11k_htt_data_stats *stats;
210 	static const char *str_name[ATH11K_STATS_TYPE_MAX] = {"succ", "fail",
211 							      "retry", "ampdu"};
212 	static const char *str[ATH11K_COUNTER_TYPE_MAX] = {"bytes", "packets"};
213 	int len = 0, i, j, k, retval = 0;
214 	const int size = 2 * 4096;
215 	char *buf;
216 
217 	buf = kzalloc(size, GFP_KERNEL);
218 	if (!buf)
219 		return -ENOMEM;
220 
221 	mutex_lock(&ar->conf_mutex);
222 
223 	spin_lock_bh(&ar->data_lock);
224 	for (k = 0; k < ATH11K_STATS_TYPE_MAX; k++) {
225 		for (j = 0; j < ATH11K_COUNTER_TYPE_MAX; j++) {
226 			stats = &arsta->tx_stats->stats[k];
227 			len += scnprintf(buf + len, size - len, "%s_%s\n",
228 					 str_name[k],
229 					 str[j]);
230 			len += scnprintf(buf + len, size - len,
231 					 " HE MCS %s\n",
232 					 str[j]);
233 			for (i = 0; i < ATH11K_HE_MCS_NUM; i++)
234 				len += scnprintf(buf + len, size - len,
235 						 "  %llu ",
236 						 stats->he[j][i]);
237 			len += scnprintf(buf + len, size - len, "\n");
238 			len += scnprintf(buf + len, size - len,
239 					 " VHT MCS %s\n",
240 					 str[j]);
241 			for (i = 0; i < ATH11K_VHT_MCS_NUM; i++)
242 				len += scnprintf(buf + len, size - len,
243 						 "  %llu ",
244 						 stats->vht[j][i]);
245 			len += scnprintf(buf + len, size - len, "\n");
246 			len += scnprintf(buf + len, size - len, " HT MCS %s\n",
247 					 str[j]);
248 			for (i = 0; i < ATH11K_HT_MCS_NUM; i++)
249 				len += scnprintf(buf + len, size - len,
250 						 "  %llu ", stats->ht[j][i]);
251 			len += scnprintf(buf + len, size - len, "\n");
252 			len += scnprintf(buf + len, size - len,
253 					" BW %s (20,40,80,160 MHz)\n", str[j]);
254 			len += scnprintf(buf + len, size - len,
255 					 "  %llu %llu %llu %llu\n",
256 					 stats->bw[j][0], stats->bw[j][1],
257 					 stats->bw[j][2], stats->bw[j][3]);
258 			len += scnprintf(buf + len, size - len,
259 					 " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]);
260 			len += scnprintf(buf + len, size - len,
261 					 "  %llu %llu %llu %llu\n",
262 					 stats->nss[j][0], stats->nss[j][1],
263 					 stats->nss[j][2], stats->nss[j][3]);
264 			len += scnprintf(buf + len, size - len,
265 					 " GI %s (0.4us,0.8us,1.6us,3.2us)\n",
266 					 str[j]);
267 			len += scnprintf(buf + len, size - len,
268 					 "  %llu %llu %llu %llu\n",
269 					 stats->gi[j][0], stats->gi[j][1],
270 					 stats->gi[j][2], stats->gi[j][3]);
271 			len += scnprintf(buf + len, size - len,
272 					 " legacy rate %s (1,2 ... Mbps)\n  ",
273 					 str[j]);
274 			for (i = 0; i < ATH11K_LEGACY_NUM; i++)
275 				len += scnprintf(buf + len, size - len, "%llu ",
276 						 stats->legacy[j][i]);
277 			len += scnprintf(buf + len, size - len, "\n");
278 		}
279 	}
280 
281 	len += scnprintf(buf + len, size - len,
282 			 "\nTX duration\n %llu usecs\n",
283 			 arsta->tx_stats->tx_duration);
284 	len += scnprintf(buf + len, size - len,
285 			"BA fails\n %llu\n", arsta->tx_stats->ba_fails);
286 	len += scnprintf(buf + len, size - len,
287 			"ack fails\n %llu\n", arsta->tx_stats->ack_fails);
288 	spin_unlock_bh(&ar->data_lock);
289 
290 	if (len > size)
291 		len = size;
292 	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
293 	kfree(buf);
294 
295 	mutex_unlock(&ar->conf_mutex);
296 	return retval;
297 }
298 
299 static const struct file_operations fops_tx_stats = {
300 	.read = ath11k_dbg_sta_dump_tx_stats,
301 	.open = simple_open,
302 	.owner = THIS_MODULE,
303 	.llseek = default_llseek,
304 };
305 
306 static ssize_t ath11k_dbg_sta_dump_rx_stats(struct file *file,
307 					    char __user *user_buf,
308 					    size_t count, loff_t *ppos)
309 {
310 	struct ieee80211_sta *sta = file->private_data;
311 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
312 	struct ath11k *ar = arsta->arvif->ar;
313 	struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;
314 	int len = 0, i, retval = 0;
315 	const int size = 4096;
316 	char *buf;
317 
318 	if (!rx_stats)
319 		return -ENOENT;
320 
321 	buf = kzalloc(size, GFP_KERNEL);
322 	if (!buf)
323 		return -ENOMEM;
324 
325 	mutex_lock(&ar->conf_mutex);
326 	spin_lock_bh(&ar->ab->base_lock);
327 
328 	len += scnprintf(buf + len, size - len, "RX peer stats:\n");
329 	len += scnprintf(buf + len, size - len, "Num of MSDUs: %llu\n",
330 			 rx_stats->num_msdu);
331 	len += scnprintf(buf + len, size - len, "Num of MSDUs with TCP L4: %llu\n",
332 			 rx_stats->tcp_msdu_count);
333 	len += scnprintf(buf + len, size - len, "Num of MSDUs with UDP L4: %llu\n",
334 			 rx_stats->udp_msdu_count);
335 	len += scnprintf(buf + len, size - len, "Num of MSDUs part of AMPDU: %llu\n",
336 			 rx_stats->ampdu_msdu_count);
337 	len += scnprintf(buf + len, size - len, "Num of MSDUs not part of AMPDU: %llu\n",
338 			 rx_stats->non_ampdu_msdu_count);
339 	len += scnprintf(buf + len, size - len, "Num of MSDUs using STBC: %llu\n",
340 			 rx_stats->stbc_count);
341 	len += scnprintf(buf + len, size - len, "Num of MSDUs beamformed: %llu\n",
342 			 rx_stats->beamformed_count);
343 	len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS ok: %llu\n",
344 			 rx_stats->num_mpdu_fcs_ok);
345 	len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS error: %llu\n",
346 			 rx_stats->num_mpdu_fcs_err);
347 	len += scnprintf(buf + len, size - len,
348 			 "GI: 0.8us %llu 0.4us %llu 1.6us %llu 3.2us %llu\n",
349 			 rx_stats->gi_count[0], rx_stats->gi_count[1],
350 			 rx_stats->gi_count[2], rx_stats->gi_count[3]);
351 	len += scnprintf(buf + len, size - len,
352 			 "BW: 20Mhz %llu 40Mhz %llu 80Mhz %llu 160Mhz %llu\n",
353 			 rx_stats->bw_count[0], rx_stats->bw_count[1],
354 			 rx_stats->bw_count[2], rx_stats->bw_count[3]);
355 	len += scnprintf(buf + len, size - len, "BCC %llu LDPC %llu\n",
356 			 rx_stats->coding_count[0], rx_stats->coding_count[1]);
357 	len += scnprintf(buf + len, size - len,
358 			 "preamble: 11A %llu 11B %llu 11N %llu 11AC %llu 11AX %llu\n",
359 			 rx_stats->pream_cnt[0], rx_stats->pream_cnt[1],
360 			 rx_stats->pream_cnt[2], rx_stats->pream_cnt[3],
361 			 rx_stats->pream_cnt[4]);
362 	len += scnprintf(buf + len, size - len,
363 			 "reception type: SU %llu MU_MIMO %llu MU_OFDMA %llu MU_OFDMA_MIMO %llu\n",
364 			 rx_stats->reception_type[0], rx_stats->reception_type[1],
365 			 rx_stats->reception_type[2], rx_stats->reception_type[3]);
366 	len += scnprintf(buf + len, size - len, "TID(0-15) Legacy TID(16):");
367 	for (i = 0; i <= IEEE80211_NUM_TIDS; i++)
368 		len += scnprintf(buf + len, size - len, "%llu ", rx_stats->tid_count[i]);
369 	len += scnprintf(buf + len, size - len, "\nMCS(0-11) Legacy MCS(12):");
370 	for (i = 0; i < HAL_RX_MAX_MCS + 1; i++)
371 		len += scnprintf(buf + len, size - len, "%llu ", rx_stats->mcs_count[i]);
372 	len += scnprintf(buf + len, size - len, "\nNSS(1-8):");
373 	for (i = 0; i < HAL_RX_MAX_NSS; i++)
374 		len += scnprintf(buf + len, size - len, "%llu ", rx_stats->nss_count[i]);
375 	len += scnprintf(buf + len, size - len, "\nRX Duration:%llu ",
376 			 rx_stats->rx_duration);
377 	len += scnprintf(buf + len, size - len, "\n");
378 
379 	spin_unlock_bh(&ar->ab->base_lock);
380 
381 	if (len > size)
382 		len = size;
383 	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
384 	kfree(buf);
385 
386 	mutex_unlock(&ar->conf_mutex);
387 	return retval;
388 }
389 
390 static const struct file_operations fops_rx_stats = {
391 	.read = ath11k_dbg_sta_dump_rx_stats,
392 	.open = simple_open,
393 	.owner = THIS_MODULE,
394 	.llseek = default_llseek,
395 };
396 
397 static int
398 ath11k_dbg_sta_open_htt_peer_stats(struct inode *inode, struct file *file)
399 {
400 	struct ieee80211_sta *sta = inode->i_private;
401 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
402 	struct ath11k *ar = arsta->arvif->ar;
403 	struct debug_htt_stats_req *stats_req;
404 	int ret;
405 
406 	stats_req = vzalloc(sizeof(*stats_req) + ATH11K_HTT_STATS_BUF_SIZE);
407 	if (!stats_req)
408 		return -ENOMEM;
409 
410 	mutex_lock(&ar->conf_mutex);
411 	ar->debug.htt_stats.stats_req = stats_req;
412 	stats_req->type = ATH11K_DBG_HTT_EXT_STATS_PEER_INFO;
413 	memcpy(stats_req->peer_addr, sta->addr, ETH_ALEN);
414 	ret = ath11k_dbg_htt_stats_req(ar);
415 	mutex_unlock(&ar->conf_mutex);
416 	if (ret < 0)
417 		goto out;
418 
419 	file->private_data = stats_req;
420 	return 0;
421 out:
422 	vfree(stats_req);
423 	return ret;
424 }
425 
426 static int
427 ath11k_dbg_sta_release_htt_peer_stats(struct inode *inode, struct file *file)
428 {
429 	vfree(file->private_data);
430 	return 0;
431 }
432 
433 static ssize_t ath11k_dbg_sta_read_htt_peer_stats(struct file *file,
434 						  char __user *user_buf,
435 						  size_t count, loff_t *ppos)
436 {
437 	struct debug_htt_stats_req *stats_req = file->private_data;
438 	char *buf;
439 	u32 length = 0;
440 
441 	buf = stats_req->buf;
442 	length = min_t(u32, stats_req->buf_len, ATH11K_HTT_STATS_BUF_SIZE);
443 	return simple_read_from_buffer(user_buf, count, ppos, buf, length);
444 }
445 
446 static const struct file_operations fops_htt_peer_stats = {
447 	.open = ath11k_dbg_sta_open_htt_peer_stats,
448 	.release = ath11k_dbg_sta_release_htt_peer_stats,
449 	.read = ath11k_dbg_sta_read_htt_peer_stats,
450 	.owner = THIS_MODULE,
451 	.llseek = default_llseek,
452 };
453 
454 static ssize_t ath11k_dbg_sta_write_peer_pktlog(struct file *file,
455 						const char __user *buf,
456 						size_t count, loff_t *ppos)
457 {
458 	struct ieee80211_sta *sta = file->private_data;
459 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
460 	struct ath11k *ar = arsta->arvif->ar;
461 	int ret, enable;
462 
463 	mutex_lock(&ar->conf_mutex);
464 
465 	if (ar->state != ATH11K_STATE_ON) {
466 		ret = -ENETDOWN;
467 		goto out;
468 	}
469 
470 	ret = kstrtoint_from_user(buf, count, 0, &enable);
471 	if (ret)
472 		goto out;
473 
474 	ar->debug.pktlog_peer_valid = enable;
475 	memcpy(ar->debug.pktlog_peer_addr, sta->addr, ETH_ALEN);
476 
477 	/* Send peer based pktlog enable/disable */
478 	ret = ath11k_wmi_pdev_peer_pktlog_filter(ar, sta->addr, enable);
479 	if (ret) {
480 		ath11k_warn(ar->ab, "failed to set peer pktlog filter %pM: %d\n",
481 			    sta->addr, ret);
482 		goto out;
483 	}
484 
485 	ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "peer pktlog filter set to %d\n",
486 		   enable);
487 	ret = count;
488 
489 out:
490 	mutex_unlock(&ar->conf_mutex);
491 	return ret;
492 }
493 
494 static ssize_t ath11k_dbg_sta_read_peer_pktlog(struct file *file,
495 					       char __user *ubuf,
496 					       size_t count, loff_t *ppos)
497 {
498 	struct ieee80211_sta *sta = file->private_data;
499 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
500 	struct ath11k *ar = arsta->arvif->ar;
501 	char buf[32] = {0};
502 	int len;
503 
504 	mutex_lock(&ar->conf_mutex);
505 	len = scnprintf(buf, sizeof(buf), "%08x %pM\n",
506 			ar->debug.pktlog_peer_valid,
507 			ar->debug.pktlog_peer_addr);
508 	mutex_unlock(&ar->conf_mutex);
509 
510 	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
511 }
512 
513 static const struct file_operations fops_peer_pktlog = {
514 	.write = ath11k_dbg_sta_write_peer_pktlog,
515 	.read = ath11k_dbg_sta_read_peer_pktlog,
516 	.open = simple_open,
517 	.owner = THIS_MODULE,
518 	.llseek = default_llseek,
519 };
520 
521 void ath11k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
522 			    struct ieee80211_sta *sta, struct dentry *dir)
523 {
524 	struct ath11k *ar = hw->priv;
525 
526 	if (ath11k_debug_is_extd_tx_stats_enabled(ar))
527 		debugfs_create_file("tx_stats", 0400, dir, sta,
528 				    &fops_tx_stats);
529 	if (ath11k_debug_is_extd_rx_stats_enabled(ar))
530 		debugfs_create_file("rx_stats", 0400, dir, sta,
531 				    &fops_rx_stats);
532 
533 	debugfs_create_file("htt_peer_stats", 0400, dir, sta,
534 			    &fops_htt_peer_stats);
535 
536 	debugfs_create_file("peer_pktlog", 0644, dir, sta,
537 			    &fops_peer_pktlog);
538 }
539