1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause-Clear
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <linux/vmalloc.h>
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include "debugfs_sta.h"
9*4882a593Smuzhiyun #include "core.h"
10*4882a593Smuzhiyun #include "peer.h"
11*4882a593Smuzhiyun #include "debug.h"
12*4882a593Smuzhiyun #include "dp_tx.h"
13*4882a593Smuzhiyun #include "debugfs_htt_stats.h"
14*4882a593Smuzhiyun
ath11k_debugfs_sta_add_tx_stats(struct ath11k_sta * arsta,struct ath11k_per_peer_tx_stats * peer_stats,u8 legacy_rate_idx)15*4882a593Smuzhiyun void ath11k_debugfs_sta_add_tx_stats(struct ath11k_sta *arsta,
16*4882a593Smuzhiyun struct ath11k_per_peer_tx_stats *peer_stats,
17*4882a593Smuzhiyun u8 legacy_rate_idx)
18*4882a593Smuzhiyun {
19*4882a593Smuzhiyun struct rate_info *txrate = &arsta->txrate;
20*4882a593Smuzhiyun struct ath11k_htt_tx_stats *tx_stats;
21*4882a593Smuzhiyun int gi, mcs, bw, nss;
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun if (!arsta->tx_stats)
24*4882a593Smuzhiyun return;
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun tx_stats = arsta->tx_stats;
27*4882a593Smuzhiyun gi = FIELD_GET(RATE_INFO_FLAGS_SHORT_GI, arsta->txrate.flags);
28*4882a593Smuzhiyun mcs = txrate->mcs;
29*4882a593Smuzhiyun bw = ath11k_mac_mac80211_bw_to_ath11k_bw(txrate->bw);
30*4882a593Smuzhiyun nss = txrate->nss - 1;
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #define STATS_OP_FMT(name) tx_stats->stats[ATH11K_STATS_TYPE_##name]
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
35*4882a593Smuzhiyun STATS_OP_FMT(SUCC).he[0][mcs] += peer_stats->succ_bytes;
36*4882a593Smuzhiyun STATS_OP_FMT(SUCC).he[1][mcs] += peer_stats->succ_pkts;
37*4882a593Smuzhiyun STATS_OP_FMT(FAIL).he[0][mcs] += peer_stats->failed_bytes;
38*4882a593Smuzhiyun STATS_OP_FMT(FAIL).he[1][mcs] += peer_stats->failed_pkts;
39*4882a593Smuzhiyun STATS_OP_FMT(RETRY).he[0][mcs] += peer_stats->retry_bytes;
40*4882a593Smuzhiyun STATS_OP_FMT(RETRY).he[1][mcs] += peer_stats->retry_pkts;
41*4882a593Smuzhiyun } else if (txrate->flags & RATE_INFO_FLAGS_VHT_MCS) {
42*4882a593Smuzhiyun STATS_OP_FMT(SUCC).vht[0][mcs] += peer_stats->succ_bytes;
43*4882a593Smuzhiyun STATS_OP_FMT(SUCC).vht[1][mcs] += peer_stats->succ_pkts;
44*4882a593Smuzhiyun STATS_OP_FMT(FAIL).vht[0][mcs] += peer_stats->failed_bytes;
45*4882a593Smuzhiyun STATS_OP_FMT(FAIL).vht[1][mcs] += peer_stats->failed_pkts;
46*4882a593Smuzhiyun STATS_OP_FMT(RETRY).vht[0][mcs] += peer_stats->retry_bytes;
47*4882a593Smuzhiyun STATS_OP_FMT(RETRY).vht[1][mcs] += peer_stats->retry_pkts;
48*4882a593Smuzhiyun } else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
49*4882a593Smuzhiyun STATS_OP_FMT(SUCC).ht[0][mcs] += peer_stats->succ_bytes;
50*4882a593Smuzhiyun STATS_OP_FMT(SUCC).ht[1][mcs] += peer_stats->succ_pkts;
51*4882a593Smuzhiyun STATS_OP_FMT(FAIL).ht[0][mcs] += peer_stats->failed_bytes;
52*4882a593Smuzhiyun STATS_OP_FMT(FAIL).ht[1][mcs] += peer_stats->failed_pkts;
53*4882a593Smuzhiyun STATS_OP_FMT(RETRY).ht[0][mcs] += peer_stats->retry_bytes;
54*4882a593Smuzhiyun STATS_OP_FMT(RETRY).ht[1][mcs] += peer_stats->retry_pkts;
55*4882a593Smuzhiyun } else {
56*4882a593Smuzhiyun mcs = legacy_rate_idx;
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun STATS_OP_FMT(SUCC).legacy[0][mcs] += peer_stats->succ_bytes;
59*4882a593Smuzhiyun STATS_OP_FMT(SUCC).legacy[1][mcs] += peer_stats->succ_pkts;
60*4882a593Smuzhiyun STATS_OP_FMT(FAIL).legacy[0][mcs] += peer_stats->failed_bytes;
61*4882a593Smuzhiyun STATS_OP_FMT(FAIL).legacy[1][mcs] += peer_stats->failed_pkts;
62*4882a593Smuzhiyun STATS_OP_FMT(RETRY).legacy[0][mcs] += peer_stats->retry_bytes;
63*4882a593Smuzhiyun STATS_OP_FMT(RETRY).legacy[1][mcs] += peer_stats->retry_pkts;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun if (peer_stats->is_ampdu) {
67*4882a593Smuzhiyun tx_stats->ba_fails += peer_stats->ba_fails;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
70*4882a593Smuzhiyun STATS_OP_FMT(AMPDU).he[0][mcs] +=
71*4882a593Smuzhiyun peer_stats->succ_bytes + peer_stats->retry_bytes;
72*4882a593Smuzhiyun STATS_OP_FMT(AMPDU).he[1][mcs] +=
73*4882a593Smuzhiyun peer_stats->succ_pkts + peer_stats->retry_pkts;
74*4882a593Smuzhiyun } else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
75*4882a593Smuzhiyun STATS_OP_FMT(AMPDU).ht[0][mcs] +=
76*4882a593Smuzhiyun peer_stats->succ_bytes + peer_stats->retry_bytes;
77*4882a593Smuzhiyun STATS_OP_FMT(AMPDU).ht[1][mcs] +=
78*4882a593Smuzhiyun peer_stats->succ_pkts + peer_stats->retry_pkts;
79*4882a593Smuzhiyun } else {
80*4882a593Smuzhiyun STATS_OP_FMT(AMPDU).vht[0][mcs] +=
81*4882a593Smuzhiyun peer_stats->succ_bytes + peer_stats->retry_bytes;
82*4882a593Smuzhiyun STATS_OP_FMT(AMPDU).vht[1][mcs] +=
83*4882a593Smuzhiyun peer_stats->succ_pkts + peer_stats->retry_pkts;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun STATS_OP_FMT(AMPDU).bw[0][bw] +=
86*4882a593Smuzhiyun peer_stats->succ_bytes + peer_stats->retry_bytes;
87*4882a593Smuzhiyun STATS_OP_FMT(AMPDU).nss[0][nss] +=
88*4882a593Smuzhiyun peer_stats->succ_bytes + peer_stats->retry_bytes;
89*4882a593Smuzhiyun STATS_OP_FMT(AMPDU).gi[0][gi] +=
90*4882a593Smuzhiyun peer_stats->succ_bytes + peer_stats->retry_bytes;
91*4882a593Smuzhiyun STATS_OP_FMT(AMPDU).bw[1][bw] +=
92*4882a593Smuzhiyun peer_stats->succ_pkts + peer_stats->retry_pkts;
93*4882a593Smuzhiyun STATS_OP_FMT(AMPDU).nss[1][nss] +=
94*4882a593Smuzhiyun peer_stats->succ_pkts + peer_stats->retry_pkts;
95*4882a593Smuzhiyun STATS_OP_FMT(AMPDU).gi[1][gi] +=
96*4882a593Smuzhiyun peer_stats->succ_pkts + peer_stats->retry_pkts;
97*4882a593Smuzhiyun } else {
98*4882a593Smuzhiyun tx_stats->ack_fails += peer_stats->ba_fails;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun STATS_OP_FMT(SUCC).bw[0][bw] += peer_stats->succ_bytes;
102*4882a593Smuzhiyun STATS_OP_FMT(SUCC).nss[0][nss] += peer_stats->succ_bytes;
103*4882a593Smuzhiyun STATS_OP_FMT(SUCC).gi[0][gi] += peer_stats->succ_bytes;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun STATS_OP_FMT(SUCC).bw[1][bw] += peer_stats->succ_pkts;
106*4882a593Smuzhiyun STATS_OP_FMT(SUCC).nss[1][nss] += peer_stats->succ_pkts;
107*4882a593Smuzhiyun STATS_OP_FMT(SUCC).gi[1][gi] += peer_stats->succ_pkts;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun STATS_OP_FMT(FAIL).bw[0][bw] += peer_stats->failed_bytes;
110*4882a593Smuzhiyun STATS_OP_FMT(FAIL).nss[0][nss] += peer_stats->failed_bytes;
111*4882a593Smuzhiyun STATS_OP_FMT(FAIL).gi[0][gi] += peer_stats->failed_bytes;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun STATS_OP_FMT(FAIL).bw[1][bw] += peer_stats->failed_pkts;
114*4882a593Smuzhiyun STATS_OP_FMT(FAIL).nss[1][nss] += peer_stats->failed_pkts;
115*4882a593Smuzhiyun STATS_OP_FMT(FAIL).gi[1][gi] += peer_stats->failed_pkts;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun STATS_OP_FMT(RETRY).bw[0][bw] += peer_stats->retry_bytes;
118*4882a593Smuzhiyun STATS_OP_FMT(RETRY).nss[0][nss] += peer_stats->retry_bytes;
119*4882a593Smuzhiyun STATS_OP_FMT(RETRY).gi[0][gi] += peer_stats->retry_bytes;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun STATS_OP_FMT(RETRY).bw[1][bw] += peer_stats->retry_pkts;
122*4882a593Smuzhiyun STATS_OP_FMT(RETRY).nss[1][nss] += peer_stats->retry_pkts;
123*4882a593Smuzhiyun STATS_OP_FMT(RETRY).gi[1][gi] += peer_stats->retry_pkts;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun tx_stats->tx_duration += peer_stats->duration;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
ath11k_debugfs_sta_update_txcompl(struct ath11k * ar,struct sk_buff * msdu,struct hal_tx_status * ts)128*4882a593Smuzhiyun void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar,
129*4882a593Smuzhiyun struct sk_buff *msdu,
130*4882a593Smuzhiyun struct hal_tx_status *ts)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun struct ath11k_base *ab = ar->ab;
133*4882a593Smuzhiyun struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats;
134*4882a593Smuzhiyun enum hal_tx_rate_stats_pkt_type pkt_type;
135*4882a593Smuzhiyun enum hal_tx_rate_stats_sgi sgi;
136*4882a593Smuzhiyun enum hal_tx_rate_stats_bw bw;
137*4882a593Smuzhiyun struct ath11k_peer *peer;
138*4882a593Smuzhiyun struct ath11k_sta *arsta;
139*4882a593Smuzhiyun struct ieee80211_sta *sta;
140*4882a593Smuzhiyun u16 rate;
141*4882a593Smuzhiyun u8 rate_idx = 0;
142*4882a593Smuzhiyun int ret;
143*4882a593Smuzhiyun u8 mcs;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun rcu_read_lock();
146*4882a593Smuzhiyun spin_lock_bh(&ab->base_lock);
147*4882a593Smuzhiyun peer = ath11k_peer_find_by_id(ab, ts->peer_id);
148*4882a593Smuzhiyun if (!peer || !peer->sta) {
149*4882a593Smuzhiyun ath11k_warn(ab, "failed to find the peer\n");
150*4882a593Smuzhiyun spin_unlock_bh(&ab->base_lock);
151*4882a593Smuzhiyun rcu_read_unlock();
152*4882a593Smuzhiyun return;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun sta = peer->sta;
156*4882a593Smuzhiyun arsta = (struct ath11k_sta *)sta->drv_priv;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun memset(&arsta->txrate, 0, sizeof(arsta->txrate));
159*4882a593Smuzhiyun pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE,
160*4882a593Smuzhiyun ts->rate_stats);
161*4882a593Smuzhiyun mcs = FIELD_GET(HAL_TX_RATE_STATS_INFO0_MCS,
162*4882a593Smuzhiyun ts->rate_stats);
163*4882a593Smuzhiyun sgi = FIELD_GET(HAL_TX_RATE_STATS_INFO0_SGI,
164*4882a593Smuzhiyun ts->rate_stats);
165*4882a593Smuzhiyun bw = FIELD_GET(HAL_TX_RATE_STATS_INFO0_BW, ts->rate_stats);
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A ||
168*4882a593Smuzhiyun pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) {
169*4882a593Smuzhiyun ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs,
170*4882a593Smuzhiyun pkt_type,
171*4882a593Smuzhiyun &rate_idx,
172*4882a593Smuzhiyun &rate);
173*4882a593Smuzhiyun if (ret < 0)
174*4882a593Smuzhiyun goto err_out;
175*4882a593Smuzhiyun arsta->txrate.legacy = rate;
176*4882a593Smuzhiyun } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) {
177*4882a593Smuzhiyun if (mcs > 7) {
178*4882a593Smuzhiyun ath11k_warn(ab, "Invalid HT mcs index %d\n", mcs);
179*4882a593Smuzhiyun goto err_out;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun arsta->txrate.mcs = mcs + 8 * (arsta->last_txrate.nss - 1);
183*4882a593Smuzhiyun arsta->txrate.flags = RATE_INFO_FLAGS_MCS;
184*4882a593Smuzhiyun if (sgi)
185*4882a593Smuzhiyun arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
186*4882a593Smuzhiyun } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AC) {
187*4882a593Smuzhiyun if (mcs > 9) {
188*4882a593Smuzhiyun ath11k_warn(ab, "Invalid VHT mcs index %d\n", mcs);
189*4882a593Smuzhiyun goto err_out;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun arsta->txrate.mcs = mcs;
193*4882a593Smuzhiyun arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
194*4882a593Smuzhiyun if (sgi)
195*4882a593Smuzhiyun arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
196*4882a593Smuzhiyun } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) {
197*4882a593Smuzhiyun /* TODO */
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun arsta->txrate.nss = arsta->last_txrate.nss;
201*4882a593Smuzhiyun arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw);
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, rate_idx);
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun err_out:
206*4882a593Smuzhiyun spin_unlock_bh(&ab->base_lock);
207*4882a593Smuzhiyun rcu_read_unlock();
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
ath11k_dbg_sta_dump_tx_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)210*4882a593Smuzhiyun static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file,
211*4882a593Smuzhiyun char __user *user_buf,
212*4882a593Smuzhiyun size_t count, loff_t *ppos)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun struct ieee80211_sta *sta = file->private_data;
215*4882a593Smuzhiyun struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
216*4882a593Smuzhiyun struct ath11k *ar = arsta->arvif->ar;
217*4882a593Smuzhiyun struct ath11k_htt_data_stats *stats;
218*4882a593Smuzhiyun static const char *str_name[ATH11K_STATS_TYPE_MAX] = {"succ", "fail",
219*4882a593Smuzhiyun "retry", "ampdu"};
220*4882a593Smuzhiyun static const char *str[ATH11K_COUNTER_TYPE_MAX] = {"bytes", "packets"};
221*4882a593Smuzhiyun int len = 0, i, j, k, retval = 0;
222*4882a593Smuzhiyun const int size = 2 * 4096;
223*4882a593Smuzhiyun char *buf;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun if (!arsta->tx_stats)
226*4882a593Smuzhiyun return -ENOENT;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun buf = kzalloc(size, GFP_KERNEL);
229*4882a593Smuzhiyun if (!buf)
230*4882a593Smuzhiyun return -ENOMEM;
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun mutex_lock(&ar->conf_mutex);
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun spin_lock_bh(&ar->data_lock);
235*4882a593Smuzhiyun for (k = 0; k < ATH11K_STATS_TYPE_MAX; k++) {
236*4882a593Smuzhiyun for (j = 0; j < ATH11K_COUNTER_TYPE_MAX; j++) {
237*4882a593Smuzhiyun stats = &arsta->tx_stats->stats[k];
238*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "%s_%s\n",
239*4882a593Smuzhiyun str_name[k],
240*4882a593Smuzhiyun str[j]);
241*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
242*4882a593Smuzhiyun " HE MCS %s\n",
243*4882a593Smuzhiyun str[j]);
244*4882a593Smuzhiyun for (i = 0; i < ATH11K_HE_MCS_NUM; i++)
245*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
246*4882a593Smuzhiyun " %llu ",
247*4882a593Smuzhiyun stats->he[j][i]);
248*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "\n");
249*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
250*4882a593Smuzhiyun " VHT MCS %s\n",
251*4882a593Smuzhiyun str[j]);
252*4882a593Smuzhiyun for (i = 0; i < ATH11K_VHT_MCS_NUM; i++)
253*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
254*4882a593Smuzhiyun " %llu ",
255*4882a593Smuzhiyun stats->vht[j][i]);
256*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "\n");
257*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, " HT MCS %s\n",
258*4882a593Smuzhiyun str[j]);
259*4882a593Smuzhiyun for (i = 0; i < ATH11K_HT_MCS_NUM; i++)
260*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
261*4882a593Smuzhiyun " %llu ", stats->ht[j][i]);
262*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "\n");
263*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
264*4882a593Smuzhiyun " BW %s (20,40,80,160 MHz)\n", str[j]);
265*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
266*4882a593Smuzhiyun " %llu %llu %llu %llu\n",
267*4882a593Smuzhiyun stats->bw[j][0], stats->bw[j][1],
268*4882a593Smuzhiyun stats->bw[j][2], stats->bw[j][3]);
269*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
270*4882a593Smuzhiyun " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]);
271*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
272*4882a593Smuzhiyun " %llu %llu %llu %llu\n",
273*4882a593Smuzhiyun stats->nss[j][0], stats->nss[j][1],
274*4882a593Smuzhiyun stats->nss[j][2], stats->nss[j][3]);
275*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
276*4882a593Smuzhiyun " GI %s (0.4us,0.8us,1.6us,3.2us)\n",
277*4882a593Smuzhiyun str[j]);
278*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
279*4882a593Smuzhiyun " %llu %llu %llu %llu\n",
280*4882a593Smuzhiyun stats->gi[j][0], stats->gi[j][1],
281*4882a593Smuzhiyun stats->gi[j][2], stats->gi[j][3]);
282*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
283*4882a593Smuzhiyun " legacy rate %s (1,2 ... Mbps)\n ",
284*4882a593Smuzhiyun str[j]);
285*4882a593Smuzhiyun for (i = 0; i < ATH11K_LEGACY_NUM; i++)
286*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "%llu ",
287*4882a593Smuzhiyun stats->legacy[j][i]);
288*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "\n");
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
293*4882a593Smuzhiyun "\nTX duration\n %llu usecs\n",
294*4882a593Smuzhiyun arsta->tx_stats->tx_duration);
295*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
296*4882a593Smuzhiyun "BA fails\n %llu\n", arsta->tx_stats->ba_fails);
297*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
298*4882a593Smuzhiyun "ack fails\n %llu\n", arsta->tx_stats->ack_fails);
299*4882a593Smuzhiyun spin_unlock_bh(&ar->data_lock);
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun if (len > size)
302*4882a593Smuzhiyun len = size;
303*4882a593Smuzhiyun retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
304*4882a593Smuzhiyun kfree(buf);
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun mutex_unlock(&ar->conf_mutex);
307*4882a593Smuzhiyun return retval;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun static const struct file_operations fops_tx_stats = {
311*4882a593Smuzhiyun .read = ath11k_dbg_sta_dump_tx_stats,
312*4882a593Smuzhiyun .open = simple_open,
313*4882a593Smuzhiyun .owner = THIS_MODULE,
314*4882a593Smuzhiyun .llseek = default_llseek,
315*4882a593Smuzhiyun };
316*4882a593Smuzhiyun
ath11k_dbg_sta_dump_rx_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)317*4882a593Smuzhiyun static ssize_t ath11k_dbg_sta_dump_rx_stats(struct file *file,
318*4882a593Smuzhiyun char __user *user_buf,
319*4882a593Smuzhiyun size_t count, loff_t *ppos)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun struct ieee80211_sta *sta = file->private_data;
322*4882a593Smuzhiyun struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
323*4882a593Smuzhiyun struct ath11k *ar = arsta->arvif->ar;
324*4882a593Smuzhiyun struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;
325*4882a593Smuzhiyun int len = 0, i, retval = 0;
326*4882a593Smuzhiyun const int size = 4096;
327*4882a593Smuzhiyun char *buf;
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun if (!rx_stats)
330*4882a593Smuzhiyun return -ENOENT;
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun buf = kzalloc(size, GFP_KERNEL);
333*4882a593Smuzhiyun if (!buf)
334*4882a593Smuzhiyun return -ENOMEM;
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun mutex_lock(&ar->conf_mutex);
337*4882a593Smuzhiyun spin_lock_bh(&ar->ab->base_lock);
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "RX peer stats:\n");
340*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "Num of MSDUs: %llu\n",
341*4882a593Smuzhiyun rx_stats->num_msdu);
342*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "Num of MSDUs with TCP L4: %llu\n",
343*4882a593Smuzhiyun rx_stats->tcp_msdu_count);
344*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "Num of MSDUs with UDP L4: %llu\n",
345*4882a593Smuzhiyun rx_stats->udp_msdu_count);
346*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "Num of MSDUs part of AMPDU: %llu\n",
347*4882a593Smuzhiyun rx_stats->ampdu_msdu_count);
348*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "Num of MSDUs not part of AMPDU: %llu\n",
349*4882a593Smuzhiyun rx_stats->non_ampdu_msdu_count);
350*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "Num of MSDUs using STBC: %llu\n",
351*4882a593Smuzhiyun rx_stats->stbc_count);
352*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "Num of MSDUs beamformed: %llu\n",
353*4882a593Smuzhiyun rx_stats->beamformed_count);
354*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS ok: %llu\n",
355*4882a593Smuzhiyun rx_stats->num_mpdu_fcs_ok);
356*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS error: %llu\n",
357*4882a593Smuzhiyun rx_stats->num_mpdu_fcs_err);
358*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
359*4882a593Smuzhiyun "GI: 0.8us %llu 0.4us %llu 1.6us %llu 3.2us %llu\n",
360*4882a593Smuzhiyun rx_stats->gi_count[0], rx_stats->gi_count[1],
361*4882a593Smuzhiyun rx_stats->gi_count[2], rx_stats->gi_count[3]);
362*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
363*4882a593Smuzhiyun "BW: 20Mhz %llu 40Mhz %llu 80Mhz %llu 160Mhz %llu\n",
364*4882a593Smuzhiyun rx_stats->bw_count[0], rx_stats->bw_count[1],
365*4882a593Smuzhiyun rx_stats->bw_count[2], rx_stats->bw_count[3]);
366*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "BCC %llu LDPC %llu\n",
367*4882a593Smuzhiyun rx_stats->coding_count[0], rx_stats->coding_count[1]);
368*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
369*4882a593Smuzhiyun "preamble: 11A %llu 11B %llu 11N %llu 11AC %llu 11AX %llu\n",
370*4882a593Smuzhiyun rx_stats->pream_cnt[0], rx_stats->pream_cnt[1],
371*4882a593Smuzhiyun rx_stats->pream_cnt[2], rx_stats->pream_cnt[3],
372*4882a593Smuzhiyun rx_stats->pream_cnt[4]);
373*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
374*4882a593Smuzhiyun "reception type: SU %llu MU_MIMO %llu MU_OFDMA %llu MU_OFDMA_MIMO %llu\n",
375*4882a593Smuzhiyun rx_stats->reception_type[0], rx_stats->reception_type[1],
376*4882a593Smuzhiyun rx_stats->reception_type[2], rx_stats->reception_type[3]);
377*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "TID(0-15) Legacy TID(16):");
378*4882a593Smuzhiyun for (i = 0; i <= IEEE80211_NUM_TIDS; i++)
379*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "%llu ", rx_stats->tid_count[i]);
380*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "\nMCS(0-11) Legacy MCS(12):");
381*4882a593Smuzhiyun for (i = 0; i < HAL_RX_MAX_MCS + 1; i++)
382*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "%llu ", rx_stats->mcs_count[i]);
383*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "\nNSS(1-8):");
384*4882a593Smuzhiyun for (i = 0; i < HAL_RX_MAX_NSS; i++)
385*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "%llu ", rx_stats->nss_count[i]);
386*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "\nRX Duration:%llu ",
387*4882a593Smuzhiyun rx_stats->rx_duration);
388*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
389*4882a593Smuzhiyun "\nDCM: %llu\nRU: 26 %llu 52: %llu 106: %llu 242: %llu 484: %llu 996: %llu\n",
390*4882a593Smuzhiyun rx_stats->dcm_count, rx_stats->ru_alloc_cnt[0],
391*4882a593Smuzhiyun rx_stats->ru_alloc_cnt[1], rx_stats->ru_alloc_cnt[2],
392*4882a593Smuzhiyun rx_stats->ru_alloc_cnt[3], rx_stats->ru_alloc_cnt[4],
393*4882a593Smuzhiyun rx_stats->ru_alloc_cnt[5]);
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "\n");
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun spin_unlock_bh(&ar->ab->base_lock);
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun if (len > size)
400*4882a593Smuzhiyun len = size;
401*4882a593Smuzhiyun retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
402*4882a593Smuzhiyun kfree(buf);
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun mutex_unlock(&ar->conf_mutex);
405*4882a593Smuzhiyun return retval;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun static const struct file_operations fops_rx_stats = {
409*4882a593Smuzhiyun .read = ath11k_dbg_sta_dump_rx_stats,
410*4882a593Smuzhiyun .open = simple_open,
411*4882a593Smuzhiyun .owner = THIS_MODULE,
412*4882a593Smuzhiyun .llseek = default_llseek,
413*4882a593Smuzhiyun };
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun static int
ath11k_dbg_sta_open_htt_peer_stats(struct inode * inode,struct file * file)416*4882a593Smuzhiyun ath11k_dbg_sta_open_htt_peer_stats(struct inode *inode, struct file *file)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun struct ieee80211_sta *sta = inode->i_private;
419*4882a593Smuzhiyun struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
420*4882a593Smuzhiyun struct ath11k *ar = arsta->arvif->ar;
421*4882a593Smuzhiyun struct debug_htt_stats_req *stats_req;
422*4882a593Smuzhiyun int ret;
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun stats_req = vzalloc(sizeof(*stats_req) + ATH11K_HTT_STATS_BUF_SIZE);
425*4882a593Smuzhiyun if (!stats_req)
426*4882a593Smuzhiyun return -ENOMEM;
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun mutex_lock(&ar->conf_mutex);
429*4882a593Smuzhiyun ar->debug.htt_stats.stats_req = stats_req;
430*4882a593Smuzhiyun stats_req->type = ATH11K_DBG_HTT_EXT_STATS_PEER_INFO;
431*4882a593Smuzhiyun memcpy(stats_req->peer_addr, sta->addr, ETH_ALEN);
432*4882a593Smuzhiyun ret = ath11k_debugfs_htt_stats_req(ar);
433*4882a593Smuzhiyun mutex_unlock(&ar->conf_mutex);
434*4882a593Smuzhiyun if (ret < 0)
435*4882a593Smuzhiyun goto out;
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun file->private_data = stats_req;
438*4882a593Smuzhiyun return 0;
439*4882a593Smuzhiyun out:
440*4882a593Smuzhiyun vfree(stats_req);
441*4882a593Smuzhiyun ar->debug.htt_stats.stats_req = NULL;
442*4882a593Smuzhiyun return ret;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun static int
ath11k_dbg_sta_release_htt_peer_stats(struct inode * inode,struct file * file)446*4882a593Smuzhiyun ath11k_dbg_sta_release_htt_peer_stats(struct inode *inode, struct file *file)
447*4882a593Smuzhiyun {
448*4882a593Smuzhiyun struct ieee80211_sta *sta = inode->i_private;
449*4882a593Smuzhiyun struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
450*4882a593Smuzhiyun struct ath11k *ar = arsta->arvif->ar;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun mutex_lock(&ar->conf_mutex);
453*4882a593Smuzhiyun vfree(file->private_data);
454*4882a593Smuzhiyun ar->debug.htt_stats.stats_req = NULL;
455*4882a593Smuzhiyun mutex_unlock(&ar->conf_mutex);
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun return 0;
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun
ath11k_dbg_sta_read_htt_peer_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)460*4882a593Smuzhiyun static ssize_t ath11k_dbg_sta_read_htt_peer_stats(struct file *file,
461*4882a593Smuzhiyun char __user *user_buf,
462*4882a593Smuzhiyun size_t count, loff_t *ppos)
463*4882a593Smuzhiyun {
464*4882a593Smuzhiyun struct debug_htt_stats_req *stats_req = file->private_data;
465*4882a593Smuzhiyun char *buf;
466*4882a593Smuzhiyun u32 length = 0;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun buf = stats_req->buf;
469*4882a593Smuzhiyun length = min_t(u32, stats_req->buf_len, ATH11K_HTT_STATS_BUF_SIZE);
470*4882a593Smuzhiyun return simple_read_from_buffer(user_buf, count, ppos, buf, length);
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun static const struct file_operations fops_htt_peer_stats = {
474*4882a593Smuzhiyun .open = ath11k_dbg_sta_open_htt_peer_stats,
475*4882a593Smuzhiyun .release = ath11k_dbg_sta_release_htt_peer_stats,
476*4882a593Smuzhiyun .read = ath11k_dbg_sta_read_htt_peer_stats,
477*4882a593Smuzhiyun .owner = THIS_MODULE,
478*4882a593Smuzhiyun .llseek = default_llseek,
479*4882a593Smuzhiyun };
480*4882a593Smuzhiyun
ath11k_dbg_sta_write_peer_pktlog(struct file * file,const char __user * buf,size_t count,loff_t * ppos)481*4882a593Smuzhiyun static ssize_t ath11k_dbg_sta_write_peer_pktlog(struct file *file,
482*4882a593Smuzhiyun const char __user *buf,
483*4882a593Smuzhiyun size_t count, loff_t *ppos)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun struct ieee80211_sta *sta = file->private_data;
486*4882a593Smuzhiyun struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
487*4882a593Smuzhiyun struct ath11k *ar = arsta->arvif->ar;
488*4882a593Smuzhiyun int ret, enable;
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun mutex_lock(&ar->conf_mutex);
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun if (ar->state != ATH11K_STATE_ON) {
493*4882a593Smuzhiyun ret = -ENETDOWN;
494*4882a593Smuzhiyun goto out;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun ret = kstrtoint_from_user(buf, count, 0, &enable);
498*4882a593Smuzhiyun if (ret)
499*4882a593Smuzhiyun goto out;
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun ar->debug.pktlog_peer_valid = enable;
502*4882a593Smuzhiyun memcpy(ar->debug.pktlog_peer_addr, sta->addr, ETH_ALEN);
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun /* Send peer based pktlog enable/disable */
505*4882a593Smuzhiyun ret = ath11k_wmi_pdev_peer_pktlog_filter(ar, sta->addr, enable);
506*4882a593Smuzhiyun if (ret) {
507*4882a593Smuzhiyun ath11k_warn(ar->ab, "failed to set peer pktlog filter %pM: %d\n",
508*4882a593Smuzhiyun sta->addr, ret);
509*4882a593Smuzhiyun goto out;
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "peer pktlog filter set to %d\n",
513*4882a593Smuzhiyun enable);
514*4882a593Smuzhiyun ret = count;
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun out:
517*4882a593Smuzhiyun mutex_unlock(&ar->conf_mutex);
518*4882a593Smuzhiyun return ret;
519*4882a593Smuzhiyun }
520*4882a593Smuzhiyun
ath11k_dbg_sta_read_peer_pktlog(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)521*4882a593Smuzhiyun static ssize_t ath11k_dbg_sta_read_peer_pktlog(struct file *file,
522*4882a593Smuzhiyun char __user *ubuf,
523*4882a593Smuzhiyun size_t count, loff_t *ppos)
524*4882a593Smuzhiyun {
525*4882a593Smuzhiyun struct ieee80211_sta *sta = file->private_data;
526*4882a593Smuzhiyun struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
527*4882a593Smuzhiyun struct ath11k *ar = arsta->arvif->ar;
528*4882a593Smuzhiyun char buf[32] = {0};
529*4882a593Smuzhiyun int len;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun mutex_lock(&ar->conf_mutex);
532*4882a593Smuzhiyun len = scnprintf(buf, sizeof(buf), "%08x %pM\n",
533*4882a593Smuzhiyun ar->debug.pktlog_peer_valid,
534*4882a593Smuzhiyun ar->debug.pktlog_peer_addr);
535*4882a593Smuzhiyun mutex_unlock(&ar->conf_mutex);
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun return simple_read_from_buffer(ubuf, count, ppos, buf, len);
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun static const struct file_operations fops_peer_pktlog = {
541*4882a593Smuzhiyun .write = ath11k_dbg_sta_write_peer_pktlog,
542*4882a593Smuzhiyun .read = ath11k_dbg_sta_read_peer_pktlog,
543*4882a593Smuzhiyun .open = simple_open,
544*4882a593Smuzhiyun .owner = THIS_MODULE,
545*4882a593Smuzhiyun .llseek = default_llseek,
546*4882a593Smuzhiyun };
547*4882a593Smuzhiyun
ath11k_dbg_sta_write_delba(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)548*4882a593Smuzhiyun static ssize_t ath11k_dbg_sta_write_delba(struct file *file,
549*4882a593Smuzhiyun const char __user *user_buf,
550*4882a593Smuzhiyun size_t count, loff_t *ppos)
551*4882a593Smuzhiyun {
552*4882a593Smuzhiyun struct ieee80211_sta *sta = file->private_data;
553*4882a593Smuzhiyun struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
554*4882a593Smuzhiyun struct ath11k *ar = arsta->arvif->ar;
555*4882a593Smuzhiyun u32 tid, initiator, reason;
556*4882a593Smuzhiyun int ret;
557*4882a593Smuzhiyun char buf[64] = {0};
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
560*4882a593Smuzhiyun user_buf, count);
561*4882a593Smuzhiyun if (ret <= 0)
562*4882a593Smuzhiyun return ret;
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);
565*4882a593Smuzhiyun if (ret != 3)
566*4882a593Smuzhiyun return -EINVAL;
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun /* Valid TID values are 0 through 15 */
569*4882a593Smuzhiyun if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
570*4882a593Smuzhiyun return -EINVAL;
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun mutex_lock(&ar->conf_mutex);
573*4882a593Smuzhiyun if (ar->state != ATH11K_STATE_ON ||
574*4882a593Smuzhiyun arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
575*4882a593Smuzhiyun ret = count;
576*4882a593Smuzhiyun goto out;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun ret = ath11k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,
580*4882a593Smuzhiyun tid, initiator, reason);
581*4882a593Smuzhiyun if (ret) {
582*4882a593Smuzhiyun ath11k_warn(ar->ab, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",
583*4882a593Smuzhiyun arsta->arvif->vdev_id, sta->addr, tid, initiator,
584*4882a593Smuzhiyun reason);
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun ret = count;
587*4882a593Smuzhiyun out:
588*4882a593Smuzhiyun mutex_unlock(&ar->conf_mutex);
589*4882a593Smuzhiyun return ret;
590*4882a593Smuzhiyun }
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun static const struct file_operations fops_delba = {
593*4882a593Smuzhiyun .write = ath11k_dbg_sta_write_delba,
594*4882a593Smuzhiyun .open = simple_open,
595*4882a593Smuzhiyun .owner = THIS_MODULE,
596*4882a593Smuzhiyun .llseek = default_llseek,
597*4882a593Smuzhiyun };
598*4882a593Smuzhiyun
ath11k_dbg_sta_write_addba_resp(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)599*4882a593Smuzhiyun static ssize_t ath11k_dbg_sta_write_addba_resp(struct file *file,
600*4882a593Smuzhiyun const char __user *user_buf,
601*4882a593Smuzhiyun size_t count, loff_t *ppos)
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun struct ieee80211_sta *sta = file->private_data;
604*4882a593Smuzhiyun struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
605*4882a593Smuzhiyun struct ath11k *ar = arsta->arvif->ar;
606*4882a593Smuzhiyun u32 tid, status;
607*4882a593Smuzhiyun int ret;
608*4882a593Smuzhiyun char buf[64] = {0};
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
611*4882a593Smuzhiyun user_buf, count);
612*4882a593Smuzhiyun if (ret <= 0)
613*4882a593Smuzhiyun return ret;
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun ret = sscanf(buf, "%u %u", &tid, &status);
616*4882a593Smuzhiyun if (ret != 2)
617*4882a593Smuzhiyun return -EINVAL;
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun /* Valid TID values are 0 through 15 */
620*4882a593Smuzhiyun if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
621*4882a593Smuzhiyun return -EINVAL;
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun mutex_lock(&ar->conf_mutex);
624*4882a593Smuzhiyun if (ar->state != ATH11K_STATE_ON ||
625*4882a593Smuzhiyun arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
626*4882a593Smuzhiyun ret = count;
627*4882a593Smuzhiyun goto out;
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun ret = ath11k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,
631*4882a593Smuzhiyun tid, status);
632*4882a593Smuzhiyun if (ret) {
633*4882a593Smuzhiyun ath11k_warn(ar->ab, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",
634*4882a593Smuzhiyun arsta->arvif->vdev_id, sta->addr, tid, status);
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun ret = count;
637*4882a593Smuzhiyun out:
638*4882a593Smuzhiyun mutex_unlock(&ar->conf_mutex);
639*4882a593Smuzhiyun return ret;
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun static const struct file_operations fops_addba_resp = {
643*4882a593Smuzhiyun .write = ath11k_dbg_sta_write_addba_resp,
644*4882a593Smuzhiyun .open = simple_open,
645*4882a593Smuzhiyun .owner = THIS_MODULE,
646*4882a593Smuzhiyun .llseek = default_llseek,
647*4882a593Smuzhiyun };
648*4882a593Smuzhiyun
ath11k_dbg_sta_write_addba(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)649*4882a593Smuzhiyun static ssize_t ath11k_dbg_sta_write_addba(struct file *file,
650*4882a593Smuzhiyun const char __user *user_buf,
651*4882a593Smuzhiyun size_t count, loff_t *ppos)
652*4882a593Smuzhiyun {
653*4882a593Smuzhiyun struct ieee80211_sta *sta = file->private_data;
654*4882a593Smuzhiyun struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
655*4882a593Smuzhiyun struct ath11k *ar = arsta->arvif->ar;
656*4882a593Smuzhiyun u32 tid, buf_size;
657*4882a593Smuzhiyun int ret;
658*4882a593Smuzhiyun char buf[64] = {0};
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
661*4882a593Smuzhiyun user_buf, count);
662*4882a593Smuzhiyun if (ret <= 0)
663*4882a593Smuzhiyun return ret;
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun ret = sscanf(buf, "%u %u", &tid, &buf_size);
666*4882a593Smuzhiyun if (ret != 2)
667*4882a593Smuzhiyun return -EINVAL;
668*4882a593Smuzhiyun
669*4882a593Smuzhiyun /* Valid TID values are 0 through 15 */
670*4882a593Smuzhiyun if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
671*4882a593Smuzhiyun return -EINVAL;
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun mutex_lock(&ar->conf_mutex);
674*4882a593Smuzhiyun if (ar->state != ATH11K_STATE_ON ||
675*4882a593Smuzhiyun arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
676*4882a593Smuzhiyun ret = count;
677*4882a593Smuzhiyun goto out;
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun ret = ath11k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,
681*4882a593Smuzhiyun tid, buf_size);
682*4882a593Smuzhiyun if (ret) {
683*4882a593Smuzhiyun ath11k_warn(ar->ab, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",
684*4882a593Smuzhiyun arsta->arvif->vdev_id, sta->addr, tid, buf_size);
685*4882a593Smuzhiyun }
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun ret = count;
688*4882a593Smuzhiyun out:
689*4882a593Smuzhiyun mutex_unlock(&ar->conf_mutex);
690*4882a593Smuzhiyun return ret;
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun static const struct file_operations fops_addba = {
694*4882a593Smuzhiyun .write = ath11k_dbg_sta_write_addba,
695*4882a593Smuzhiyun .open = simple_open,
696*4882a593Smuzhiyun .owner = THIS_MODULE,
697*4882a593Smuzhiyun .llseek = default_llseek,
698*4882a593Smuzhiyun };
699*4882a593Smuzhiyun
ath11k_dbg_sta_read_aggr_mode(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)700*4882a593Smuzhiyun static ssize_t ath11k_dbg_sta_read_aggr_mode(struct file *file,
701*4882a593Smuzhiyun char __user *user_buf,
702*4882a593Smuzhiyun size_t count, loff_t *ppos)
703*4882a593Smuzhiyun {
704*4882a593Smuzhiyun struct ieee80211_sta *sta = file->private_data;
705*4882a593Smuzhiyun struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
706*4882a593Smuzhiyun struct ath11k *ar = arsta->arvif->ar;
707*4882a593Smuzhiyun char buf[64];
708*4882a593Smuzhiyun int len = 0;
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun mutex_lock(&ar->conf_mutex);
711*4882a593Smuzhiyun len = scnprintf(buf, sizeof(buf) - len,
712*4882a593Smuzhiyun "aggregation mode: %s\n\n%s\n%s\n",
713*4882a593Smuzhiyun (arsta->aggr_mode == ATH11K_DBG_AGGR_MODE_AUTO) ?
714*4882a593Smuzhiyun "auto" : "manual", "auto = 0", "manual = 1");
715*4882a593Smuzhiyun mutex_unlock(&ar->conf_mutex);
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun return simple_read_from_buffer(user_buf, count, ppos, buf, len);
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun
ath11k_dbg_sta_write_aggr_mode(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)720*4882a593Smuzhiyun static ssize_t ath11k_dbg_sta_write_aggr_mode(struct file *file,
721*4882a593Smuzhiyun const char __user *user_buf,
722*4882a593Smuzhiyun size_t count, loff_t *ppos)
723*4882a593Smuzhiyun {
724*4882a593Smuzhiyun struct ieee80211_sta *sta = file->private_data;
725*4882a593Smuzhiyun struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
726*4882a593Smuzhiyun struct ath11k *ar = arsta->arvif->ar;
727*4882a593Smuzhiyun u32 aggr_mode;
728*4882a593Smuzhiyun int ret;
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))
731*4882a593Smuzhiyun return -EINVAL;
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun if (aggr_mode >= ATH11K_DBG_AGGR_MODE_MAX)
734*4882a593Smuzhiyun return -EINVAL;
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun mutex_lock(&ar->conf_mutex);
737*4882a593Smuzhiyun if (ar->state != ATH11K_STATE_ON ||
738*4882a593Smuzhiyun aggr_mode == arsta->aggr_mode) {
739*4882a593Smuzhiyun ret = count;
740*4882a593Smuzhiyun goto out;
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun ret = ath11k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);
744*4882a593Smuzhiyun if (ret) {
745*4882a593Smuzhiyun ath11k_warn(ar->ab, "failed to clear addba session ret: %d\n",
746*4882a593Smuzhiyun ret);
747*4882a593Smuzhiyun goto out;
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun
750*4882a593Smuzhiyun arsta->aggr_mode = aggr_mode;
751*4882a593Smuzhiyun out:
752*4882a593Smuzhiyun mutex_unlock(&ar->conf_mutex);
753*4882a593Smuzhiyun return ret;
754*4882a593Smuzhiyun }
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun static const struct file_operations fops_aggr_mode = {
757*4882a593Smuzhiyun .read = ath11k_dbg_sta_read_aggr_mode,
758*4882a593Smuzhiyun .write = ath11k_dbg_sta_write_aggr_mode,
759*4882a593Smuzhiyun .open = simple_open,
760*4882a593Smuzhiyun .owner = THIS_MODULE,
761*4882a593Smuzhiyun .llseek = default_llseek,
762*4882a593Smuzhiyun };
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun static ssize_t
ath11k_write_htt_peer_stats_reset(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)765*4882a593Smuzhiyun ath11k_write_htt_peer_stats_reset(struct file *file,
766*4882a593Smuzhiyun const char __user *user_buf,
767*4882a593Smuzhiyun size_t count, loff_t *ppos)
768*4882a593Smuzhiyun {
769*4882a593Smuzhiyun struct ieee80211_sta *sta = file->private_data;
770*4882a593Smuzhiyun struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
771*4882a593Smuzhiyun struct ath11k *ar = arsta->arvif->ar;
772*4882a593Smuzhiyun struct htt_ext_stats_cfg_params cfg_params = { 0 };
773*4882a593Smuzhiyun int ret;
774*4882a593Smuzhiyun u8 type;
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun ret = kstrtou8_from_user(user_buf, count, 0, &type);
777*4882a593Smuzhiyun if (ret)
778*4882a593Smuzhiyun return ret;
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun if (!type)
781*4882a593Smuzhiyun return ret;
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun mutex_lock(&ar->conf_mutex);
784*4882a593Smuzhiyun cfg_params.cfg0 = HTT_STAT_PEER_INFO_MAC_ADDR;
785*4882a593Smuzhiyun cfg_params.cfg0 |= FIELD_PREP(GENMASK(15, 1),
786*4882a593Smuzhiyun HTT_PEER_STATS_REQ_MODE_FLUSH_TQM);
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun cfg_params.cfg1 = HTT_STAT_DEFAULT_PEER_REQ_TYPE;
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun cfg_params.cfg2 |= FIELD_PREP(GENMASK(7, 0), sta->addr[0]);
791*4882a593Smuzhiyun cfg_params.cfg2 |= FIELD_PREP(GENMASK(15, 8), sta->addr[1]);
792*4882a593Smuzhiyun cfg_params.cfg2 |= FIELD_PREP(GENMASK(23, 16), sta->addr[2]);
793*4882a593Smuzhiyun cfg_params.cfg2 |= FIELD_PREP(GENMASK(31, 24), sta->addr[3]);
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun cfg_params.cfg3 |= FIELD_PREP(GENMASK(7, 0), sta->addr[4]);
796*4882a593Smuzhiyun cfg_params.cfg3 |= FIELD_PREP(GENMASK(15, 8), sta->addr[5]);
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun cfg_params.cfg3 |= ATH11K_HTT_PEER_STATS_RESET;
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun ret = ath11k_dp_tx_htt_h2t_ext_stats_req(ar,
801*4882a593Smuzhiyun ATH11K_DBG_HTT_EXT_STATS_PEER_INFO,
802*4882a593Smuzhiyun &cfg_params,
803*4882a593Smuzhiyun 0ULL);
804*4882a593Smuzhiyun if (ret) {
805*4882a593Smuzhiyun ath11k_warn(ar->ab, "failed to send htt peer stats request: %d\n", ret);
806*4882a593Smuzhiyun mutex_unlock(&ar->conf_mutex);
807*4882a593Smuzhiyun return ret;
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun mutex_unlock(&ar->conf_mutex);
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun ret = count;
813*4882a593Smuzhiyun
814*4882a593Smuzhiyun return ret;
815*4882a593Smuzhiyun }
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun static const struct file_operations fops_htt_peer_stats_reset = {
818*4882a593Smuzhiyun .write = ath11k_write_htt_peer_stats_reset,
819*4882a593Smuzhiyun .open = simple_open,
820*4882a593Smuzhiyun .owner = THIS_MODULE,
821*4882a593Smuzhiyun .llseek = default_llseek,
822*4882a593Smuzhiyun };
823*4882a593Smuzhiyun
ath11k_debugfs_sta_op_add(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct dentry * dir)824*4882a593Smuzhiyun void ath11k_debugfs_sta_op_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
825*4882a593Smuzhiyun struct ieee80211_sta *sta, struct dentry *dir)
826*4882a593Smuzhiyun {
827*4882a593Smuzhiyun struct ath11k *ar = hw->priv;
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun if (ath11k_debugfs_is_extd_tx_stats_enabled(ar))
830*4882a593Smuzhiyun debugfs_create_file("tx_stats", 0400, dir, sta,
831*4882a593Smuzhiyun &fops_tx_stats);
832*4882a593Smuzhiyun if (ath11k_debugfs_is_extd_rx_stats_enabled(ar))
833*4882a593Smuzhiyun debugfs_create_file("rx_stats", 0400, dir, sta,
834*4882a593Smuzhiyun &fops_rx_stats);
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun debugfs_create_file("htt_peer_stats", 0400, dir, sta,
837*4882a593Smuzhiyun &fops_htt_peer_stats);
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun debugfs_create_file("peer_pktlog", 0644, dir, sta,
840*4882a593Smuzhiyun &fops_peer_pktlog);
841*4882a593Smuzhiyun
842*4882a593Smuzhiyun debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode);
843*4882a593Smuzhiyun debugfs_create_file("addba", 0200, dir, sta, &fops_addba);
844*4882a593Smuzhiyun debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);
845*4882a593Smuzhiyun debugfs_create_file("delba", 0200, dir, sta, &fops_delba);
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun if (test_bit(WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET,
848*4882a593Smuzhiyun ar->ab->wmi_ab.svc_map))
849*4882a593Smuzhiyun debugfs_create_file("htt_peer_stats_reset", 0600, dir, sta,
850*4882a593Smuzhiyun &fops_htt_peer_stats_reset);
851*4882a593Smuzhiyun }
852