1*a9655020SBjoern A. Zeeb // SPDX-License-Identifier: BSD-3-Clause-Clear
2*a9655020SBjoern A. Zeeb /*
3*a9655020SBjoern A. Zeeb * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
4*a9655020SBjoern A. Zeeb */
5*a9655020SBjoern A. Zeeb
6*a9655020SBjoern A. Zeeb #include <linux/vmalloc.h>
7*a9655020SBjoern A. Zeeb
8*a9655020SBjoern A. Zeeb #include "debugfs_sta.h"
9*a9655020SBjoern A. Zeeb #include "core.h"
10*a9655020SBjoern A. Zeeb #include "peer.h"
11*a9655020SBjoern A. Zeeb #include "debug.h"
12*a9655020SBjoern A. Zeeb #include "debugfs_htt_stats.h"
13*a9655020SBjoern A. Zeeb #include "debugfs.h"
14*a9655020SBjoern A. Zeeb
15*a9655020SBjoern A. Zeeb static
ath12k_dbg_sta_dump_rate_stats(u8 * buf,u32 offset,const int size,bool he_rates_avail,const struct ath12k_rx_peer_rate_stats * stats)16*a9655020SBjoern A. Zeeb u32 ath12k_dbg_sta_dump_rate_stats(u8 *buf, u32 offset, const int size,
17*a9655020SBjoern A. Zeeb bool he_rates_avail,
18*a9655020SBjoern A. Zeeb const struct ath12k_rx_peer_rate_stats *stats)
19*a9655020SBjoern A. Zeeb {
20*a9655020SBjoern A. Zeeb static const char *legacy_rate_str[HAL_RX_MAX_NUM_LEGACY_RATES] = {
21*a9655020SBjoern A. Zeeb "1 Mbps", "2 Mbps", "5.5 Mbps", "6 Mbps",
22*a9655020SBjoern A. Zeeb "9 Mbps", "11 Mbps", "12 Mbps", "18 Mbps",
23*a9655020SBjoern A. Zeeb "24 Mbps", "36 Mbps", "48 Mbps", "54 Mbps"};
24*a9655020SBjoern A. Zeeb u8 max_bw = HAL_RX_BW_MAX, max_gi = HAL_RX_GI_MAX, max_mcs = HAL_RX_MAX_NSS;
25*a9655020SBjoern A. Zeeb int mcs = 0, bw = 0, nss = 0, gi = 0, bw_num = 0;
26*a9655020SBjoern A. Zeeb u32 i, len = offset, max = max_bw * max_gi * max_mcs;
27*a9655020SBjoern A. Zeeb bool found;
28*a9655020SBjoern A. Zeeb
29*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "\nEHT stats:\n");
30*a9655020SBjoern A. Zeeb for (i = 0; i <= HAL_RX_MAX_MCS_BE; i++)
31*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len,
32*a9655020SBjoern A. Zeeb "MCS %d: %llu%s", i, stats->be_mcs_count[i],
33*a9655020SBjoern A. Zeeb (i + 1) % 8 ? "\t" : "\n");
34*a9655020SBjoern A. Zeeb
35*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "\nHE stats:\n");
36*a9655020SBjoern A. Zeeb for (i = 0; i <= HAL_RX_MAX_MCS_HE; i++)
37*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len,
38*a9655020SBjoern A. Zeeb "MCS %d: %llu%s", i, stats->he_mcs_count[i],
39*a9655020SBjoern A. Zeeb (i + 1) % 6 ? "\t" : "\n");
40*a9655020SBjoern A. Zeeb
41*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "\nVHT stats:\n");
42*a9655020SBjoern A. Zeeb for (i = 0; i <= HAL_RX_MAX_MCS_VHT; i++)
43*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len,
44*a9655020SBjoern A. Zeeb "MCS %d: %llu%s", i, stats->vht_mcs_count[i],
45*a9655020SBjoern A. Zeeb (i + 1) % 5 ? "\t" : "\n");
46*a9655020SBjoern A. Zeeb
47*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "\nHT stats:\n");
48*a9655020SBjoern A. Zeeb for (i = 0; i <= HAL_RX_MAX_MCS_HT; i++)
49*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len,
50*a9655020SBjoern A. Zeeb "MCS %d: %llu%s", i, stats->ht_mcs_count[i],
51*a9655020SBjoern A. Zeeb (i + 1) % 8 ? "\t" : "\n");
52*a9655020SBjoern A. Zeeb
53*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "\nLegacy stats:\n");
54*a9655020SBjoern A. Zeeb for (i = 0; i < HAL_RX_MAX_NUM_LEGACY_RATES; i++)
55*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len,
56*a9655020SBjoern A. Zeeb "%s: %llu%s", legacy_rate_str[i],
57*a9655020SBjoern A. Zeeb stats->legacy_count[i],
58*a9655020SBjoern A. Zeeb (i + 1) % 4 ? "\t" : "\n");
59*a9655020SBjoern A. Zeeb
60*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "\nNSS stats:\n");
61*a9655020SBjoern A. Zeeb for (i = 0; i < HAL_RX_MAX_NSS; i++)
62*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len,
63*a9655020SBjoern A. Zeeb "%dx%d: %llu ", i + 1, i + 1,
64*a9655020SBjoern A. Zeeb stats->nss_count[i]);
65*a9655020SBjoern A. Zeeb
66*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len,
67*a9655020SBjoern A. Zeeb "\n\nGI: 0.8 us %llu 0.4 us %llu 1.6 us %llu 3.2 us %llu\n",
68*a9655020SBjoern A. Zeeb stats->gi_count[0],
69*a9655020SBjoern A. Zeeb stats->gi_count[1],
70*a9655020SBjoern A. Zeeb stats->gi_count[2],
71*a9655020SBjoern A. Zeeb stats->gi_count[3]);
72*a9655020SBjoern A. Zeeb
73*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len,
74*a9655020SBjoern A. Zeeb "BW: 20 MHz %llu 40 MHz %llu 80 MHz %llu 160 MHz %llu 320 MHz %llu\n",
75*a9655020SBjoern A. Zeeb stats->bw_count[0],
76*a9655020SBjoern A. Zeeb stats->bw_count[1],
77*a9655020SBjoern A. Zeeb stats->bw_count[2],
78*a9655020SBjoern A. Zeeb stats->bw_count[3],
79*a9655020SBjoern A. Zeeb stats->bw_count[4]);
80*a9655020SBjoern A. Zeeb
81*a9655020SBjoern A. Zeeb for (i = 0; i < max; i++) {
82*a9655020SBjoern A. Zeeb found = false;
83*a9655020SBjoern A. Zeeb
84*a9655020SBjoern A. Zeeb for (mcs = 0; mcs <= HAL_RX_MAX_MCS_HT; mcs++) {
85*a9655020SBjoern A. Zeeb if (stats->rx_rate[bw][gi][nss][mcs]) {
86*a9655020SBjoern A. Zeeb found = true;
87*a9655020SBjoern A. Zeeb break;
88*a9655020SBjoern A. Zeeb }
89*a9655020SBjoern A. Zeeb }
90*a9655020SBjoern A. Zeeb
91*a9655020SBjoern A. Zeeb if (!found)
92*a9655020SBjoern A. Zeeb goto skip_report;
93*a9655020SBjoern A. Zeeb
94*a9655020SBjoern A. Zeeb switch (bw) {
95*a9655020SBjoern A. Zeeb case HAL_RX_BW_20MHZ:
96*a9655020SBjoern A. Zeeb bw_num = 20;
97*a9655020SBjoern A. Zeeb break;
98*a9655020SBjoern A. Zeeb case HAL_RX_BW_40MHZ:
99*a9655020SBjoern A. Zeeb bw_num = 40;
100*a9655020SBjoern A. Zeeb break;
101*a9655020SBjoern A. Zeeb case HAL_RX_BW_80MHZ:
102*a9655020SBjoern A. Zeeb bw_num = 80;
103*a9655020SBjoern A. Zeeb break;
104*a9655020SBjoern A. Zeeb case HAL_RX_BW_160MHZ:
105*a9655020SBjoern A. Zeeb bw_num = 160;
106*a9655020SBjoern A. Zeeb break;
107*a9655020SBjoern A. Zeeb case HAL_RX_BW_320MHZ:
108*a9655020SBjoern A. Zeeb bw_num = 320;
109*a9655020SBjoern A. Zeeb break;
110*a9655020SBjoern A. Zeeb }
111*a9655020SBjoern A. Zeeb
112*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "\n%d Mhz gi %d us %dx%d : ",
113*a9655020SBjoern A. Zeeb bw_num, gi, nss + 1, nss + 1);
114*a9655020SBjoern A. Zeeb
115*a9655020SBjoern A. Zeeb for (mcs = 0; mcs <= HAL_RX_MAX_MCS_HT; mcs++) {
116*a9655020SBjoern A. Zeeb if (stats->rx_rate[bw][gi][nss][mcs])
117*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len,
118*a9655020SBjoern A. Zeeb " %d:%llu", mcs,
119*a9655020SBjoern A. Zeeb stats->rx_rate[bw][gi][nss][mcs]);
120*a9655020SBjoern A. Zeeb }
121*a9655020SBjoern A. Zeeb
122*a9655020SBjoern A. Zeeb skip_report:
123*a9655020SBjoern A. Zeeb if (nss++ >= max_mcs - 1) {
124*a9655020SBjoern A. Zeeb nss = 0;
125*a9655020SBjoern A. Zeeb if (gi++ >= max_gi - 1) {
126*a9655020SBjoern A. Zeeb gi = 0;
127*a9655020SBjoern A. Zeeb if (bw < max_bw - 1)
128*a9655020SBjoern A. Zeeb bw++;
129*a9655020SBjoern A. Zeeb }
130*a9655020SBjoern A. Zeeb }
131*a9655020SBjoern A. Zeeb }
132*a9655020SBjoern A. Zeeb
133*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "\n");
134*a9655020SBjoern A. Zeeb
135*a9655020SBjoern A. Zeeb return len - offset;
136*a9655020SBjoern A. Zeeb }
137*a9655020SBjoern A. Zeeb
ath12k_dbg_sta_dump_rx_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)138*a9655020SBjoern A. Zeeb static ssize_t ath12k_dbg_sta_dump_rx_stats(struct file *file,
139*a9655020SBjoern A. Zeeb char __user *user_buf,
140*a9655020SBjoern A. Zeeb size_t count, loff_t *ppos)
141*a9655020SBjoern A. Zeeb {
142*a9655020SBjoern A. Zeeb struct ieee80211_link_sta *link_sta = file->private_data;
143*a9655020SBjoern A. Zeeb struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(link_sta->sta);
144*a9655020SBjoern A. Zeeb const int size = ATH12K_STA_RX_STATS_BUF_SIZE;
145*a9655020SBjoern A. Zeeb struct ath12k_hw *ah = ahsta->ahvif->ah;
146*a9655020SBjoern A. Zeeb struct ath12k_rx_peer_stats *rx_stats;
147*a9655020SBjoern A. Zeeb struct ath12k_link_sta *arsta;
148*a9655020SBjoern A. Zeeb u8 link_id = link_sta->link_id;
149*a9655020SBjoern A. Zeeb int len = 0, i, ret = 0;
150*a9655020SBjoern A. Zeeb bool he_rates_avail;
151*a9655020SBjoern A. Zeeb struct ath12k *ar;
152*a9655020SBjoern A. Zeeb
153*a9655020SBjoern A. Zeeb wiphy_lock(ah->hw->wiphy);
154*a9655020SBjoern A. Zeeb
155*a9655020SBjoern A. Zeeb if (!(BIT(link_id) & ahsta->links_map)) {
156*a9655020SBjoern A. Zeeb wiphy_unlock(ah->hw->wiphy);
157*a9655020SBjoern A. Zeeb return -ENOENT;
158*a9655020SBjoern A. Zeeb }
159*a9655020SBjoern A. Zeeb
160*a9655020SBjoern A. Zeeb arsta = wiphy_dereference(ah->hw->wiphy, ahsta->link[link_id]);
161*a9655020SBjoern A. Zeeb if (!arsta || !arsta->arvif->ar) {
162*a9655020SBjoern A. Zeeb wiphy_unlock(ah->hw->wiphy);
163*a9655020SBjoern A. Zeeb return -ENOENT;
164*a9655020SBjoern A. Zeeb }
165*a9655020SBjoern A. Zeeb
166*a9655020SBjoern A. Zeeb ar = arsta->arvif->ar;
167*a9655020SBjoern A. Zeeb
168*a9655020SBjoern A. Zeeb u8 *buf __free(kfree) = kzalloc(size, GFP_KERNEL);
169*a9655020SBjoern A. Zeeb if (!buf) {
170*a9655020SBjoern A. Zeeb ret = -ENOENT;
171*a9655020SBjoern A. Zeeb goto out;
172*a9655020SBjoern A. Zeeb }
173*a9655020SBjoern A. Zeeb
174*a9655020SBjoern A. Zeeb spin_lock_bh(&ar->ab->base_lock);
175*a9655020SBjoern A. Zeeb
176*a9655020SBjoern A. Zeeb rx_stats = arsta->rx_stats;
177*a9655020SBjoern A. Zeeb if (!rx_stats) {
178*a9655020SBjoern A. Zeeb ret = -ENOENT;
179*a9655020SBjoern A. Zeeb goto unlock;
180*a9655020SBjoern A. Zeeb }
181*a9655020SBjoern A. Zeeb
182*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "RX peer stats:\n\n");
183*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "Num of MSDUs: %llu\n",
184*a9655020SBjoern A. Zeeb rx_stats->num_msdu);
185*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "Num of MSDUs with TCP L4: %llu\n",
186*a9655020SBjoern A. Zeeb rx_stats->tcp_msdu_count);
187*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "Num of MSDUs with UDP L4: %llu\n",
188*a9655020SBjoern A. Zeeb rx_stats->udp_msdu_count);
189*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "Num of other MSDUs: %llu\n",
190*a9655020SBjoern A. Zeeb rx_stats->other_msdu_count);
191*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "Num of MSDUs part of AMPDU: %llu\n",
192*a9655020SBjoern A. Zeeb rx_stats->ampdu_msdu_count);
193*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "Num of MSDUs not part of AMPDU: %llu\n",
194*a9655020SBjoern A. Zeeb rx_stats->non_ampdu_msdu_count);
195*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "Num of MSDUs using STBC: %llu\n",
196*a9655020SBjoern A. Zeeb rx_stats->stbc_count);
197*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "Num of MSDUs beamformed: %llu\n",
198*a9655020SBjoern A. Zeeb rx_stats->beamformed_count);
199*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS ok: %llu\n",
200*a9655020SBjoern A. Zeeb rx_stats->num_mpdu_fcs_ok);
201*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS error: %llu\n",
202*a9655020SBjoern A. Zeeb rx_stats->num_mpdu_fcs_err);
203*a9655020SBjoern A. Zeeb
204*a9655020SBjoern A. Zeeb he_rates_avail = (rx_stats->pream_cnt[HAL_RX_PREAMBLE_11AX] > 1) ? true : false;
205*a9655020SBjoern A. Zeeb
206*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len,
207*a9655020SBjoern A. Zeeb "preamble: 11A %llu 11B %llu 11N %llu 11AC %llu 11AX %llu 11BE %llu\n",
208*a9655020SBjoern A. Zeeb rx_stats->pream_cnt[0], rx_stats->pream_cnt[1],
209*a9655020SBjoern A. Zeeb rx_stats->pream_cnt[2], rx_stats->pream_cnt[3],
210*a9655020SBjoern A. Zeeb rx_stats->pream_cnt[4], rx_stats->pream_cnt[6]);
211*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len,
212*a9655020SBjoern A. Zeeb "reception type: SU %llu MU_MIMO %llu MU_OFDMA %llu MU_OFDMA_MIMO %llu\n",
213*a9655020SBjoern A. Zeeb rx_stats->reception_type[0], rx_stats->reception_type[1],
214*a9655020SBjoern A. Zeeb rx_stats->reception_type[2], rx_stats->reception_type[3]);
215*a9655020SBjoern A. Zeeb
216*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "TID(0-15) Legacy TID(16):");
217*a9655020SBjoern A. Zeeb for (i = 0; i <= IEEE80211_NUM_TIDS; i++)
218*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "%llu ", rx_stats->tid_count[i]);
219*a9655020SBjoern A. Zeeb
220*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "\nRX Duration:%llu\n",
221*a9655020SBjoern A. Zeeb rx_stats->rx_duration);
222*a9655020SBjoern A. Zeeb
223*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len,
224*a9655020SBjoern A. Zeeb "\nDCM: %llu\nRU26: %llu\nRU52: %llu\nRU106: %llu\nRU242: %llu\nRU484: %llu\nRU996: %llu\nRU996x2: %llu\n",
225*a9655020SBjoern A. Zeeb rx_stats->dcm_count, rx_stats->ru_alloc_cnt[0],
226*a9655020SBjoern A. Zeeb rx_stats->ru_alloc_cnt[1], rx_stats->ru_alloc_cnt[2],
227*a9655020SBjoern A. Zeeb rx_stats->ru_alloc_cnt[3], rx_stats->ru_alloc_cnt[4],
228*a9655020SBjoern A. Zeeb rx_stats->ru_alloc_cnt[5], rx_stats->ru_alloc_cnt[6]);
229*a9655020SBjoern A. Zeeb
230*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "\nRX success packet stats:\n");
231*a9655020SBjoern A. Zeeb len += ath12k_dbg_sta_dump_rate_stats(buf, len, size, he_rates_avail,
232*a9655020SBjoern A. Zeeb &rx_stats->pkt_stats);
233*a9655020SBjoern A. Zeeb
234*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "\n");
235*a9655020SBjoern A. Zeeb
236*a9655020SBjoern A. Zeeb len += scnprintf(buf + len, size - len, "\nRX success byte stats:\n");
237*a9655020SBjoern A. Zeeb len += ath12k_dbg_sta_dump_rate_stats(buf, len, size, he_rates_avail,
238*a9655020SBjoern A. Zeeb &rx_stats->byte_stats);
239*a9655020SBjoern A. Zeeb
240*a9655020SBjoern A. Zeeb unlock:
241*a9655020SBjoern A. Zeeb spin_unlock_bh(&ar->ab->base_lock);
242*a9655020SBjoern A. Zeeb
243*a9655020SBjoern A. Zeeb if (len)
244*a9655020SBjoern A. Zeeb ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
245*a9655020SBjoern A. Zeeb out:
246*a9655020SBjoern A. Zeeb wiphy_unlock(ah->hw->wiphy);
247*a9655020SBjoern A. Zeeb return ret;
248*a9655020SBjoern A. Zeeb }
249*a9655020SBjoern A. Zeeb
250*a9655020SBjoern A. Zeeb static const struct file_operations fops_rx_stats = {
251*a9655020SBjoern A. Zeeb .read = ath12k_dbg_sta_dump_rx_stats,
252*a9655020SBjoern A. Zeeb .open = simple_open,
253*a9655020SBjoern A. Zeeb .owner = THIS_MODULE,
254*a9655020SBjoern A. Zeeb .llseek = default_llseek,
255*a9655020SBjoern A. Zeeb };
256*a9655020SBjoern A. Zeeb
ath12k_dbg_sta_reset_rx_stats(struct file * file,const char __user * buf,size_t count,loff_t * ppos)257*a9655020SBjoern A. Zeeb static ssize_t ath12k_dbg_sta_reset_rx_stats(struct file *file,
258*a9655020SBjoern A. Zeeb const char __user *buf,
259*a9655020SBjoern A. Zeeb size_t count, loff_t *ppos)
260*a9655020SBjoern A. Zeeb {
261*a9655020SBjoern A. Zeeb struct ieee80211_link_sta *link_sta = file->private_data;
262*a9655020SBjoern A. Zeeb struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(link_sta->sta);
263*a9655020SBjoern A. Zeeb struct ath12k_hw *ah = ahsta->ahvif->ah;
264*a9655020SBjoern A. Zeeb struct ath12k_rx_peer_stats *rx_stats;
265*a9655020SBjoern A. Zeeb struct ath12k_link_sta *arsta;
266*a9655020SBjoern A. Zeeb u8 link_id = link_sta->link_id;
267*a9655020SBjoern A. Zeeb struct ath12k *ar;
268*a9655020SBjoern A. Zeeb bool reset;
269*a9655020SBjoern A. Zeeb int ret;
270*a9655020SBjoern A. Zeeb
271*a9655020SBjoern A. Zeeb ret = kstrtobool_from_user(buf, count, &reset);
272*a9655020SBjoern A. Zeeb if (ret)
273*a9655020SBjoern A. Zeeb return ret;
274*a9655020SBjoern A. Zeeb
275*a9655020SBjoern A. Zeeb if (!reset)
276*a9655020SBjoern A. Zeeb return -EINVAL;
277*a9655020SBjoern A. Zeeb
278*a9655020SBjoern A. Zeeb wiphy_lock(ah->hw->wiphy);
279*a9655020SBjoern A. Zeeb
280*a9655020SBjoern A. Zeeb if (!(BIT(link_id) & ahsta->links_map)) {
281*a9655020SBjoern A. Zeeb ret = -ENOENT;
282*a9655020SBjoern A. Zeeb goto out;
283*a9655020SBjoern A. Zeeb }
284*a9655020SBjoern A. Zeeb
285*a9655020SBjoern A. Zeeb arsta = wiphy_dereference(ah->hw->wiphy, ahsta->link[link_id]);
286*a9655020SBjoern A. Zeeb if (!arsta || !arsta->arvif->ar) {
287*a9655020SBjoern A. Zeeb ret = -ENOENT;
288*a9655020SBjoern A. Zeeb goto out;
289*a9655020SBjoern A. Zeeb }
290*a9655020SBjoern A. Zeeb
291*a9655020SBjoern A. Zeeb ar = arsta->arvif->ar;
292*a9655020SBjoern A. Zeeb
293*a9655020SBjoern A. Zeeb spin_lock_bh(&ar->ab->base_lock);
294*a9655020SBjoern A. Zeeb
295*a9655020SBjoern A. Zeeb rx_stats = arsta->rx_stats;
296*a9655020SBjoern A. Zeeb if (!rx_stats) {
297*a9655020SBjoern A. Zeeb spin_unlock_bh(&ar->ab->base_lock);
298*a9655020SBjoern A. Zeeb ret = -ENOENT;
299*a9655020SBjoern A. Zeeb goto out;
300*a9655020SBjoern A. Zeeb }
301*a9655020SBjoern A. Zeeb
302*a9655020SBjoern A. Zeeb memset(rx_stats, 0, sizeof(*rx_stats));
303*a9655020SBjoern A. Zeeb spin_unlock_bh(&ar->ab->base_lock);
304*a9655020SBjoern A. Zeeb
305*a9655020SBjoern A. Zeeb ret = count;
306*a9655020SBjoern A. Zeeb out:
307*a9655020SBjoern A. Zeeb wiphy_unlock(ah->hw->wiphy);
308*a9655020SBjoern A. Zeeb return ret;
309*a9655020SBjoern A. Zeeb }
310*a9655020SBjoern A. Zeeb
311*a9655020SBjoern A. Zeeb static const struct file_operations fops_reset_rx_stats = {
312*a9655020SBjoern A. Zeeb .write = ath12k_dbg_sta_reset_rx_stats,
313*a9655020SBjoern A. Zeeb .open = simple_open,
314*a9655020SBjoern A. Zeeb .owner = THIS_MODULE,
315*a9655020SBjoern A. Zeeb .llseek = default_llseek,
316*a9655020SBjoern A. Zeeb };
317*a9655020SBjoern A. Zeeb
ath12k_debugfs_link_sta_op_add(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_link_sta * link_sta,struct dentry * dir)318*a9655020SBjoern A. Zeeb void ath12k_debugfs_link_sta_op_add(struct ieee80211_hw *hw,
319*a9655020SBjoern A. Zeeb struct ieee80211_vif *vif,
320*a9655020SBjoern A. Zeeb struct ieee80211_link_sta *link_sta,
321*a9655020SBjoern A. Zeeb struct dentry *dir)
322*a9655020SBjoern A. Zeeb {
323*a9655020SBjoern A. Zeeb struct ath12k *ar;
324*a9655020SBjoern A. Zeeb
325*a9655020SBjoern A. Zeeb lockdep_assert_wiphy(hw->wiphy);
326*a9655020SBjoern A. Zeeb
327*a9655020SBjoern A. Zeeb ar = ath12k_get_ar_by_vif(hw, vif, link_sta->link_id);
328*a9655020SBjoern A. Zeeb if (!ar)
329*a9655020SBjoern A. Zeeb return;
330*a9655020SBjoern A. Zeeb
331*a9655020SBjoern A. Zeeb if (ath12k_debugfs_is_extd_rx_stats_enabled(ar)) {
332*a9655020SBjoern A. Zeeb debugfs_create_file("rx_stats", 0400, dir, link_sta,
333*a9655020SBjoern A. Zeeb &fops_rx_stats);
334*a9655020SBjoern A. Zeeb debugfs_create_file("reset_rx_stats", 0200, dir, link_sta,
335*a9655020SBjoern A. Zeeb &fops_reset_rx_stats);
336*a9655020SBjoern A. Zeeb }
337*a9655020SBjoern A. Zeeb }
338