1 // SPDX-License-Identifier: BSD-3-Clause-Clear
2 /*
3 * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
4 * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
5 */
6
7 #include "core.h"
8 #include "dp_tx.h"
9 #include "debug.h"
10 #include "debugfs.h"
11 #include "debugfs_htt_stats.h"
12
ath12k_write_simulate_radar(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)13 static ssize_t ath12k_write_simulate_radar(struct file *file,
14 const char __user *user_buf,
15 size_t count, loff_t *ppos)
16 {
17 struct ath12k *ar = file->private_data;
18 int ret;
19
20 wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
21 ret = ath12k_wmi_simulate_radar(ar);
22 if (ret)
23 goto exit;
24
25 ret = count;
26 exit:
27 wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
28 return ret;
29 }
30
31 static const struct file_operations fops_simulate_radar = {
32 .write = ath12k_write_simulate_radar,
33 .open = simple_open
34 };
35
ath12k_read_simulate_fw_crash(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)36 static ssize_t ath12k_read_simulate_fw_crash(struct file *file,
37 char __user *user_buf,
38 size_t count, loff_t *ppos)
39 {
40 const char buf[] =
41 "To simulate firmware crash write one of the keywords to this file:\n"
42 "`assert` - send WMI_FORCE_FW_HANG_CMDID to firmware to cause assert.\n";
43
44 return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
45 }
46
47 static ssize_t
ath12k_write_simulate_fw_crash(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)48 ath12k_write_simulate_fw_crash(struct file *file,
49 const char __user *user_buf,
50 size_t count, loff_t *ppos)
51 {
52 struct ath12k_base *ab = file->private_data;
53 struct ath12k_pdev *pdev;
54 struct ath12k *ar = NULL;
55 char buf[32] = {0};
56 int i, ret;
57 ssize_t rc;
58
59 /* filter partial writes and invalid commands */
60 if (*ppos != 0 || count >= sizeof(buf) || count == 0)
61 return -EINVAL;
62
63 rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
64 if (rc < 0)
65 return rc;
66
67 /* drop the possible '\n' from the end */
68 if (buf[*ppos - 1] == '\n')
69 buf[*ppos - 1] = '\0';
70
71 for (i = 0; i < ab->num_radios; i++) {
72 pdev = &ab->pdevs[i];
73 ar = pdev->ar;
74 if (ar)
75 break;
76 }
77
78 if (!ar)
79 return -ENETDOWN;
80
81 if (!strcmp(buf, "assert")) {
82 ath12k_info(ab, "simulating firmware assert crash\n");
83 ret = ath12k_wmi_force_fw_hang_cmd(ar,
84 ATH12K_WMI_FW_HANG_ASSERT_TYPE,
85 ATH12K_WMI_FW_HANG_DELAY);
86 } else {
87 return -EINVAL;
88 }
89
90 if (ret) {
91 ath12k_warn(ab, "failed to simulate firmware crash: %d\n", ret);
92 return ret;
93 }
94
95 return count;
96 }
97
98 static const struct file_operations fops_simulate_fw_crash = {
99 .read = ath12k_read_simulate_fw_crash,
100 .write = ath12k_write_simulate_fw_crash,
101 .open = simple_open,
102 .owner = THIS_MODULE,
103 .llseek = default_llseek,
104 };
105
ath12k_write_tpc_stats_type(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)106 static ssize_t ath12k_write_tpc_stats_type(struct file *file,
107 const char __user *user_buf,
108 size_t count, loff_t *ppos)
109 {
110 struct ath12k *ar = file->private_data;
111 u8 type;
112 int ret;
113
114 ret = kstrtou8_from_user(user_buf, count, 0, &type);
115 if (ret)
116 return ret;
117
118 if (type >= WMI_HALPHY_PDEV_TX_STATS_MAX)
119 return -EINVAL;
120
121 spin_lock_bh(&ar->data_lock);
122 ar->debug.tpc_stats_type = type;
123 spin_unlock_bh(&ar->data_lock);
124
125 return count;
126 }
127
ath12k_debug_tpc_stats_request(struct ath12k * ar)128 static int ath12k_debug_tpc_stats_request(struct ath12k *ar)
129 {
130 enum wmi_halphy_ctrl_path_stats_id tpc_stats_sub_id;
131 struct ath12k_base *ab = ar->ab;
132 int ret;
133
134 lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
135
136 reinit_completion(&ar->debug.tpc_complete);
137
138 spin_lock_bh(&ar->data_lock);
139 ar->debug.tpc_request = true;
140 tpc_stats_sub_id = ar->debug.tpc_stats_type;
141 spin_unlock_bh(&ar->data_lock);
142
143 ret = ath12k_wmi_send_tpc_stats_request(ar, tpc_stats_sub_id);
144 if (ret) {
145 ath12k_warn(ab, "failed to request pdev tpc stats: %d\n", ret);
146 spin_lock_bh(&ar->data_lock);
147 ar->debug.tpc_request = false;
148 spin_unlock_bh(&ar->data_lock);
149 return ret;
150 }
151
152 return 0;
153 }
154
ath12k_get_tpc_ctl_mode_idx(struct wmi_tpc_stats_arg * tpc_stats,enum wmi_tpc_pream_bw pream_bw,int * mode_idx)155 static int ath12k_get_tpc_ctl_mode_idx(struct wmi_tpc_stats_arg *tpc_stats,
156 enum wmi_tpc_pream_bw pream_bw, int *mode_idx)
157 {
158 u32 chan_freq = le32_to_cpu(tpc_stats->tpc_config.chan_freq);
159 u8 band;
160
161 band = ((chan_freq > ATH12K_MIN_6GHZ_FREQ) ? NL80211_BAND_6GHZ :
162 ((chan_freq > ATH12K_MIN_5GHZ_FREQ) ? NL80211_BAND_5GHZ :
163 NL80211_BAND_2GHZ));
164
165 if (band == NL80211_BAND_5GHZ || band == NL80211_BAND_6GHZ) {
166 switch (pream_bw) {
167 case WMI_TPC_PREAM_HT20:
168 case WMI_TPC_PREAM_VHT20:
169 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT_VHT20_5GHZ_6GHZ;
170 break;
171 case WMI_TPC_PREAM_HE20:
172 case WMI_TPC_PREAM_EHT20:
173 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT20_5GHZ_6GHZ;
174 break;
175 case WMI_TPC_PREAM_HT40:
176 case WMI_TPC_PREAM_VHT40:
177 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT_VHT40_5GHZ_6GHZ;
178 break;
179 case WMI_TPC_PREAM_HE40:
180 case WMI_TPC_PREAM_EHT40:
181 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT40_5GHZ_6GHZ;
182 break;
183 case WMI_TPC_PREAM_VHT80:
184 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_VHT80_5GHZ_6GHZ;
185 break;
186 case WMI_TPC_PREAM_EHT60:
187 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT80_SU_PUNC20;
188 break;
189 case WMI_TPC_PREAM_HE80:
190 case WMI_TPC_PREAM_EHT80:
191 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT80_5GHZ_6GHZ;
192 break;
193 case WMI_TPC_PREAM_VHT160:
194 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_VHT160_5GHZ_6GHZ;
195 break;
196 case WMI_TPC_PREAM_EHT120:
197 case WMI_TPC_PREAM_EHT140:
198 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT160_SU_PUNC20;
199 break;
200 case WMI_TPC_PREAM_HE160:
201 case WMI_TPC_PREAM_EHT160:
202 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT160_5GHZ_6GHZ;
203 break;
204 case WMI_TPC_PREAM_EHT200:
205 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC120;
206 break;
207 case WMI_TPC_PREAM_EHT240:
208 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC80;
209 break;
210 case WMI_TPC_PREAM_EHT280:
211 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC40;
212 break;
213 case WMI_TPC_PREAM_EHT320:
214 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT320_5GHZ_6GHZ;
215 break;
216 default:
217 /* for 5GHZ and 6GHZ, default case will be for OFDM */
218 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_LEGACY_5GHZ_6GHZ;
219 break;
220 }
221 } else {
222 switch (pream_bw) {
223 case WMI_TPC_PREAM_OFDM:
224 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_LEGACY_2GHZ;
225 break;
226 case WMI_TPC_PREAM_HT20:
227 case WMI_TPC_PREAM_VHT20:
228 case WMI_TPC_PREAM_HE20:
229 case WMI_TPC_PREAM_EHT20:
230 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT20_2GHZ;
231 break;
232 case WMI_TPC_PREAM_HT40:
233 case WMI_TPC_PREAM_VHT40:
234 case WMI_TPC_PREAM_HE40:
235 case WMI_TPC_PREAM_EHT40:
236 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT40_2GHZ;
237 break;
238 default:
239 /* for 2GHZ, default case will be CCK */
240 *mode_idx = ATH12K_TPC_STATS_CTL_MODE_CCK_2GHZ;
241 break;
242 }
243 }
244
245 return 0;
246 }
247
ath12k_tpc_get_rate(struct ath12k * ar,struct wmi_tpc_stats_arg * tpc_stats,u32 rate_idx,u32 num_chains,u32 rate_code,enum wmi_tpc_pream_bw pream_bw,enum wmi_halphy_ctrl_path_stats_id type,u32 eht_rate_idx)248 static s16 ath12k_tpc_get_rate(struct ath12k *ar,
249 struct wmi_tpc_stats_arg *tpc_stats,
250 u32 rate_idx, u32 num_chains, u32 rate_code,
251 enum wmi_tpc_pream_bw pream_bw,
252 enum wmi_halphy_ctrl_path_stats_id type,
253 u32 eht_rate_idx)
254 {
255 u32 tot_nss, tot_modes, txbf_on_off, index_offset1, index_offset2, index_offset3;
256 u8 chain_idx, stm_idx, num_streams;
257 bool is_mu, txbf_enabled = 0;
258 s8 rates_ctl_min, tpc_ctl;
259 s16 rates, tpc, reg_pwr;
260 u16 rate1, rate2;
261 int mode, ret;
262
263 num_streams = 1 + ATH12K_HW_NSS(rate_code);
264 chain_idx = num_chains - 1;
265 stm_idx = num_streams - 1;
266 mode = -1;
267
268 ret = ath12k_get_tpc_ctl_mode_idx(tpc_stats, pream_bw, &mode);
269 if (ret) {
270 ath12k_warn(ar->ab, "Invalid mode index received\n");
271 tpc = TPC_INVAL;
272 goto out;
273 }
274
275 if (num_chains < num_streams) {
276 tpc = TPC_INVAL;
277 goto out;
278 }
279
280 if (le32_to_cpu(tpc_stats->tpc_config.num_tx_chain) <= 1) {
281 tpc = TPC_INVAL;
282 goto out;
283 }
284
285 if (type == WMI_HALPHY_PDEV_TX_SUTXBF_STATS ||
286 type == WMI_HALPHY_PDEV_TX_MUTXBF_STATS)
287 txbf_enabled = 1;
288
289 if (type == WMI_HALPHY_PDEV_TX_MU_STATS ||
290 type == WMI_HALPHY_PDEV_TX_MUTXBF_STATS) {
291 is_mu = true;
292 } else {
293 is_mu = false;
294 }
295
296 /* Below is the min calculation of ctl array, rates array and
297 * regulator power table. tpc is minimum of all 3
298 */
299 if (pream_bw >= WMI_TPC_PREAM_EHT20 && pream_bw <= WMI_TPC_PREAM_EHT320) {
300 rate2 = tpc_stats->rates_array2.rate_array[eht_rate_idx];
301 if (is_mu)
302 rates = u32_get_bits(rate2, ATH12K_TPC_RATE_ARRAY_MU);
303 else
304 rates = u32_get_bits(rate2, ATH12K_TPC_RATE_ARRAY_SU);
305 } else {
306 rate1 = tpc_stats->rates_array1.rate_array[rate_idx];
307 if (is_mu)
308 rates = u32_get_bits(rate1, ATH12K_TPC_RATE_ARRAY_MU);
309 else
310 rates = u32_get_bits(rate1, ATH12K_TPC_RATE_ARRAY_SU);
311 }
312
313 if (tpc_stats->tlvs_rcvd & WMI_TPC_CTL_PWR_ARRAY) {
314 tot_nss = le32_to_cpu(tpc_stats->ctl_array.tpc_ctl_pwr.d1);
315 tot_modes = le32_to_cpu(tpc_stats->ctl_array.tpc_ctl_pwr.d2);
316 txbf_on_off = le32_to_cpu(tpc_stats->ctl_array.tpc_ctl_pwr.d3);
317 index_offset1 = txbf_on_off * tot_modes * tot_nss;
318 index_offset2 = tot_modes * tot_nss;
319 index_offset3 = tot_nss;
320
321 tpc_ctl = *(tpc_stats->ctl_array.ctl_pwr_table +
322 chain_idx * index_offset1 + txbf_enabled * index_offset2
323 + mode * index_offset3 + stm_idx);
324 } else {
325 tpc_ctl = TPC_MAX;
326 ath12k_warn(ar->ab,
327 "ctl array for tpc stats not received from fw\n");
328 }
329
330 rates_ctl_min = min_t(s16, rates, tpc_ctl);
331
332 reg_pwr = tpc_stats->max_reg_allowed_power.reg_pwr_array[chain_idx];
333
334 if (reg_pwr < 0)
335 reg_pwr = TPC_INVAL;
336
337 tpc = min_t(s16, rates_ctl_min, reg_pwr);
338
339 /* MODULATION_LIMIT is the maximum power limit,tpc should not exceed
340 * modulation limit even if min tpc of all three array is greater
341 * modulation limit
342 */
343 tpc = min_t(s16, tpc, MODULATION_LIMIT);
344
345 out:
346 return tpc;
347 }
348
ath12k_get_ratecode(u16 pream_idx,u16 nss,u16 mcs_rate)349 static u16 ath12k_get_ratecode(u16 pream_idx, u16 nss, u16 mcs_rate)
350 {
351 u16 mode_type = ~0;
352
353 /* Below assignments are just for printing purpose only */
354 switch (pream_idx) {
355 case WMI_TPC_PREAM_CCK:
356 mode_type = WMI_RATE_PREAMBLE_CCK;
357 break;
358 case WMI_TPC_PREAM_OFDM:
359 mode_type = WMI_RATE_PREAMBLE_OFDM;
360 break;
361 case WMI_TPC_PREAM_HT20:
362 case WMI_TPC_PREAM_HT40:
363 mode_type = WMI_RATE_PREAMBLE_HT;
364 break;
365 case WMI_TPC_PREAM_VHT20:
366 case WMI_TPC_PREAM_VHT40:
367 case WMI_TPC_PREAM_VHT80:
368 case WMI_TPC_PREAM_VHT160:
369 mode_type = WMI_RATE_PREAMBLE_VHT;
370 break;
371 case WMI_TPC_PREAM_HE20:
372 case WMI_TPC_PREAM_HE40:
373 case WMI_TPC_PREAM_HE80:
374 case WMI_TPC_PREAM_HE160:
375 mode_type = WMI_RATE_PREAMBLE_HE;
376 break;
377 case WMI_TPC_PREAM_EHT20:
378 case WMI_TPC_PREAM_EHT40:
379 case WMI_TPC_PREAM_EHT60:
380 case WMI_TPC_PREAM_EHT80:
381 case WMI_TPC_PREAM_EHT120:
382 case WMI_TPC_PREAM_EHT140:
383 case WMI_TPC_PREAM_EHT160:
384 case WMI_TPC_PREAM_EHT200:
385 case WMI_TPC_PREAM_EHT240:
386 case WMI_TPC_PREAM_EHT280:
387 case WMI_TPC_PREAM_EHT320:
388 mode_type = WMI_RATE_PREAMBLE_EHT;
389 if (mcs_rate == 0 || mcs_rate == 1)
390 mcs_rate += 14;
391 else
392 mcs_rate -= 2;
393 break;
394 default:
395 return mode_type;
396 }
397 return ((mode_type << 8) | ((nss & 0x7) << 5) | (mcs_rate & 0x1F));
398 }
399
ath12k_he_supports_extra_mcs(struct ath12k * ar,int freq)400 static bool ath12k_he_supports_extra_mcs(struct ath12k *ar, int freq)
401 {
402 struct ath12k_pdev_cap *cap = &ar->pdev->cap;
403 struct ath12k_band_cap *cap_band;
404 bool extra_mcs_supported;
405
406 if (freq <= ATH12K_2GHZ_MAX_FREQUENCY)
407 cap_band = &cap->band[NL80211_BAND_2GHZ];
408 else if (freq <= ATH12K_5GHZ_MAX_FREQUENCY)
409 cap_band = &cap->band[NL80211_BAND_5GHZ];
410 else
411 cap_band = &cap->band[NL80211_BAND_6GHZ];
412
413 extra_mcs_supported = u32_get_bits(cap_band->he_cap_info[1],
414 HE_EXTRA_MCS_SUPPORT);
415 return extra_mcs_supported;
416 }
417
ath12k_tpc_fill_pream(struct ath12k * ar,char * buf,int buf_len,int len,enum wmi_tpc_pream_bw pream_bw,u32 max_rix,int max_nss,int max_rates,int pream_type,enum wmi_halphy_ctrl_path_stats_id tpc_type,int rate_idx,int eht_rate_idx)418 static int ath12k_tpc_fill_pream(struct ath12k *ar, char *buf, int buf_len, int len,
419 enum wmi_tpc_pream_bw pream_bw, u32 max_rix,
420 int max_nss, int max_rates, int pream_type,
421 enum wmi_halphy_ctrl_path_stats_id tpc_type,
422 int rate_idx, int eht_rate_idx)
423 {
424 struct wmi_tpc_stats_arg *tpc_stats = ar->debug.tpc_stats;
425 int nss, rates, chains;
426 u8 active_tx_chains;
427 u16 rate_code;
428 s16 tpc;
429
430 static const char *const pream_str[] = {
431 [WMI_TPC_PREAM_CCK] = "CCK",
432 [WMI_TPC_PREAM_OFDM] = "OFDM",
433 [WMI_TPC_PREAM_HT20] = "HT20",
434 [WMI_TPC_PREAM_HT40] = "HT40",
435 [WMI_TPC_PREAM_VHT20] = "VHT20",
436 [WMI_TPC_PREAM_VHT40] = "VHT40",
437 [WMI_TPC_PREAM_VHT80] = "VHT80",
438 [WMI_TPC_PREAM_VHT160] = "VHT160",
439 [WMI_TPC_PREAM_HE20] = "HE20",
440 [WMI_TPC_PREAM_HE40] = "HE40",
441 [WMI_TPC_PREAM_HE80] = "HE80",
442 [WMI_TPC_PREAM_HE160] = "HE160",
443 [WMI_TPC_PREAM_EHT20] = "EHT20",
444 [WMI_TPC_PREAM_EHT40] = "EHT40",
445 [WMI_TPC_PREAM_EHT60] = "EHT60",
446 [WMI_TPC_PREAM_EHT80] = "EHT80",
447 [WMI_TPC_PREAM_EHT120] = "EHT120",
448 [WMI_TPC_PREAM_EHT140] = "EHT140",
449 [WMI_TPC_PREAM_EHT160] = "EHT160",
450 [WMI_TPC_PREAM_EHT200] = "EHT200",
451 [WMI_TPC_PREAM_EHT240] = "EHT240",
452 [WMI_TPC_PREAM_EHT280] = "EHT280",
453 [WMI_TPC_PREAM_EHT320] = "EHT320"};
454
455 active_tx_chains = ar->num_tx_chains;
456
457 for (nss = 0; nss < max_nss; nss++) {
458 for (rates = 0; rates < max_rates; rates++, rate_idx++, max_rix++) {
459 /* FW send extra MCS(10&11) for VHT and HE rates,
460 * this is not used. Hence skipping it here
461 */
462 if (pream_type == WMI_RATE_PREAMBLE_VHT &&
463 rates > ATH12K_VHT_MCS_MAX)
464 continue;
465
466 if (pream_type == WMI_RATE_PREAMBLE_HE &&
467 rates > ATH12K_HE_MCS_MAX)
468 continue;
469
470 if (pream_type == WMI_RATE_PREAMBLE_EHT &&
471 rates > ATH12K_EHT_MCS_MAX)
472 continue;
473
474 rate_code = ath12k_get_ratecode(pream_bw, nss, rates);
475 len += scnprintf(buf + len, buf_len - len,
476 "%d\t %s\t 0x%03x\t", max_rix,
477 pream_str[pream_bw], rate_code);
478
479 for (chains = 0; chains < active_tx_chains; chains++) {
480 if (nss > chains) {
481 len += scnprintf(buf + len,
482 buf_len - len,
483 "\t%s", "NA");
484 } else {
485 tpc = ath12k_tpc_get_rate(ar, tpc_stats,
486 rate_idx, chains + 1,
487 rate_code, pream_bw,
488 tpc_type,
489 eht_rate_idx);
490
491 if (tpc == TPC_INVAL) {
492 len += scnprintf(buf + len,
493 buf_len - len, "\tNA");
494 } else {
495 len += scnprintf(buf + len,
496 buf_len - len, "\t%d",
497 tpc);
498 }
499 }
500 }
501 len += scnprintf(buf + len, buf_len - len, "\n");
502
503 if (pream_type == WMI_RATE_PREAMBLE_EHT)
504 /*For fetching the next eht rates pwr from rates array2*/
505 ++eht_rate_idx;
506 }
507 }
508
509 return len;
510 }
511
ath12k_tpc_stats_print(struct ath12k * ar,struct wmi_tpc_stats_arg * tpc_stats,char * buf,size_t len,enum wmi_halphy_ctrl_path_stats_id type)512 static int ath12k_tpc_stats_print(struct ath12k *ar,
513 struct wmi_tpc_stats_arg *tpc_stats,
514 char *buf, size_t len,
515 enum wmi_halphy_ctrl_path_stats_id type)
516 {
517 u32 eht_idx = 0, pream_idx = 0, rate_pream_idx = 0, total_rates = 0, max_rix = 0;
518 u32 chan_freq, num_tx_chain, caps, i, j = 1;
519 size_t buf_len = ATH12K_TPC_STATS_BUF_SIZE;
520 u8 nss, active_tx_chains;
521 bool he_ext_mcs;
522 static const char *const type_str[WMI_HALPHY_PDEV_TX_STATS_MAX] = {
523 [WMI_HALPHY_PDEV_TX_SU_STATS] = "SU",
524 [WMI_HALPHY_PDEV_TX_SUTXBF_STATS] = "SU WITH TXBF",
525 [WMI_HALPHY_PDEV_TX_MU_STATS] = "MU",
526 [WMI_HALPHY_PDEV_TX_MUTXBF_STATS] = "MU WITH TXBF"};
527
528 u8 max_rates[WMI_TPC_PREAM_MAX] = {
529 [WMI_TPC_PREAM_CCK] = ATH12K_CCK_RATES,
530 [WMI_TPC_PREAM_OFDM] = ATH12K_OFDM_RATES,
531 [WMI_TPC_PREAM_HT20] = ATH12K_HT_RATES,
532 [WMI_TPC_PREAM_HT40] = ATH12K_HT_RATES,
533 [WMI_TPC_PREAM_VHT20] = ATH12K_VHT_RATES,
534 [WMI_TPC_PREAM_VHT40] = ATH12K_VHT_RATES,
535 [WMI_TPC_PREAM_VHT80] = ATH12K_VHT_RATES,
536 [WMI_TPC_PREAM_VHT160] = ATH12K_VHT_RATES,
537 [WMI_TPC_PREAM_HE20] = ATH12K_HE_RATES,
538 [WMI_TPC_PREAM_HE40] = ATH12K_HE_RATES,
539 [WMI_TPC_PREAM_HE80] = ATH12K_HE_RATES,
540 [WMI_TPC_PREAM_HE160] = ATH12K_HE_RATES,
541 [WMI_TPC_PREAM_EHT20] = ATH12K_EHT_RATES,
542 [WMI_TPC_PREAM_EHT40] = ATH12K_EHT_RATES,
543 [WMI_TPC_PREAM_EHT60] = ATH12K_EHT_RATES,
544 [WMI_TPC_PREAM_EHT80] = ATH12K_EHT_RATES,
545 [WMI_TPC_PREAM_EHT120] = ATH12K_EHT_RATES,
546 [WMI_TPC_PREAM_EHT140] = ATH12K_EHT_RATES,
547 [WMI_TPC_PREAM_EHT160] = ATH12K_EHT_RATES,
548 [WMI_TPC_PREAM_EHT200] = ATH12K_EHT_RATES,
549 [WMI_TPC_PREAM_EHT240] = ATH12K_EHT_RATES,
550 [WMI_TPC_PREAM_EHT280] = ATH12K_EHT_RATES,
551 [WMI_TPC_PREAM_EHT320] = ATH12K_EHT_RATES};
552 static const u8 max_nss[WMI_TPC_PREAM_MAX] = {
553 [WMI_TPC_PREAM_CCK] = ATH12K_NSS_1,
554 [WMI_TPC_PREAM_OFDM] = ATH12K_NSS_1,
555 [WMI_TPC_PREAM_HT20] = ATH12K_NSS_4,
556 [WMI_TPC_PREAM_HT40] = ATH12K_NSS_4,
557 [WMI_TPC_PREAM_VHT20] = ATH12K_NSS_8,
558 [WMI_TPC_PREAM_VHT40] = ATH12K_NSS_8,
559 [WMI_TPC_PREAM_VHT80] = ATH12K_NSS_8,
560 [WMI_TPC_PREAM_VHT160] = ATH12K_NSS_4,
561 [WMI_TPC_PREAM_HE20] = ATH12K_NSS_8,
562 [WMI_TPC_PREAM_HE40] = ATH12K_NSS_8,
563 [WMI_TPC_PREAM_HE80] = ATH12K_NSS_8,
564 [WMI_TPC_PREAM_HE160] = ATH12K_NSS_4,
565 [WMI_TPC_PREAM_EHT20] = ATH12K_NSS_4,
566 [WMI_TPC_PREAM_EHT40] = ATH12K_NSS_4,
567 [WMI_TPC_PREAM_EHT60] = ATH12K_NSS_4,
568 [WMI_TPC_PREAM_EHT80] = ATH12K_NSS_4,
569 [WMI_TPC_PREAM_EHT120] = ATH12K_NSS_4,
570 [WMI_TPC_PREAM_EHT140] = ATH12K_NSS_4,
571 [WMI_TPC_PREAM_EHT160] = ATH12K_NSS_4,
572 [WMI_TPC_PREAM_EHT200] = ATH12K_NSS_4,
573 [WMI_TPC_PREAM_EHT240] = ATH12K_NSS_4,
574 [WMI_TPC_PREAM_EHT280] = ATH12K_NSS_4,
575 [WMI_TPC_PREAM_EHT320] = ATH12K_NSS_4};
576
577 u16 rate_idx[WMI_TPC_PREAM_MAX] = {}, eht_rate_idx[WMI_TPC_PREAM_MAX] = {};
578 static const u8 pream_type[WMI_TPC_PREAM_MAX] = {
579 [WMI_TPC_PREAM_CCK] = WMI_RATE_PREAMBLE_CCK,
580 [WMI_TPC_PREAM_OFDM] = WMI_RATE_PREAMBLE_OFDM,
581 [WMI_TPC_PREAM_HT20] = WMI_RATE_PREAMBLE_HT,
582 [WMI_TPC_PREAM_HT40] = WMI_RATE_PREAMBLE_HT,
583 [WMI_TPC_PREAM_VHT20] = WMI_RATE_PREAMBLE_VHT,
584 [WMI_TPC_PREAM_VHT40] = WMI_RATE_PREAMBLE_VHT,
585 [WMI_TPC_PREAM_VHT80] = WMI_RATE_PREAMBLE_VHT,
586 [WMI_TPC_PREAM_VHT160] = WMI_RATE_PREAMBLE_VHT,
587 [WMI_TPC_PREAM_HE20] = WMI_RATE_PREAMBLE_HE,
588 [WMI_TPC_PREAM_HE40] = WMI_RATE_PREAMBLE_HE,
589 [WMI_TPC_PREAM_HE80] = WMI_RATE_PREAMBLE_HE,
590 [WMI_TPC_PREAM_HE160] = WMI_RATE_PREAMBLE_HE,
591 [WMI_TPC_PREAM_EHT20] = WMI_RATE_PREAMBLE_EHT,
592 [WMI_TPC_PREAM_EHT40] = WMI_RATE_PREAMBLE_EHT,
593 [WMI_TPC_PREAM_EHT60] = WMI_RATE_PREAMBLE_EHT,
594 [WMI_TPC_PREAM_EHT80] = WMI_RATE_PREAMBLE_EHT,
595 [WMI_TPC_PREAM_EHT120] = WMI_RATE_PREAMBLE_EHT,
596 [WMI_TPC_PREAM_EHT140] = WMI_RATE_PREAMBLE_EHT,
597 [WMI_TPC_PREAM_EHT160] = WMI_RATE_PREAMBLE_EHT,
598 [WMI_TPC_PREAM_EHT200] = WMI_RATE_PREAMBLE_EHT,
599 [WMI_TPC_PREAM_EHT240] = WMI_RATE_PREAMBLE_EHT,
600 [WMI_TPC_PREAM_EHT280] = WMI_RATE_PREAMBLE_EHT,
601 [WMI_TPC_PREAM_EHT320] = WMI_RATE_PREAMBLE_EHT};
602
603 chan_freq = le32_to_cpu(tpc_stats->tpc_config.chan_freq);
604 num_tx_chain = le32_to_cpu(tpc_stats->tpc_config.num_tx_chain);
605 caps = le32_to_cpu(tpc_stats->tpc_config.caps);
606
607 active_tx_chains = ar->num_tx_chains;
608 he_ext_mcs = ath12k_he_supports_extra_mcs(ar, chan_freq);
609
610 /* mcs 12&13 is sent by FW for certain HWs in rate array, skipping it as
611 * it is not supported
612 */
613 if (he_ext_mcs) {
614 for (i = WMI_TPC_PREAM_HE20; i <= WMI_TPC_PREAM_HE160; ++i)
615 max_rates[i] = ATH12K_HE_RATES;
616 }
617
618 if (type == WMI_HALPHY_PDEV_TX_MU_STATS ||
619 type == WMI_HALPHY_PDEV_TX_MUTXBF_STATS) {
620 pream_idx = WMI_TPC_PREAM_VHT20;
621
622 for (i = WMI_TPC_PREAM_CCK; i <= WMI_TPC_PREAM_HT40; ++i)
623 max_rix += max_nss[i] * max_rates[i];
624 }
625 /* Enumerate all the rate indices */
626 for (i = rate_pream_idx + 1; i < WMI_TPC_PREAM_MAX; i++) {
627 nss = (max_nss[i - 1] < num_tx_chain ?
628 max_nss[i - 1] : num_tx_chain);
629
630 rate_idx[i] = rate_idx[i - 1] + max_rates[i - 1] * nss;
631
632 if (pream_type[i] == WMI_RATE_PREAMBLE_EHT) {
633 eht_rate_idx[j] = eht_rate_idx[j - 1] + max_rates[i] * nss;
634 ++j;
635 }
636 }
637
638 for (i = 0; i < WMI_TPC_PREAM_MAX; i++) {
639 nss = (max_nss[i] < num_tx_chain ?
640 max_nss[i] : num_tx_chain);
641 total_rates += max_rates[i] * nss;
642 }
643
644 len += scnprintf(buf + len, buf_len - len,
645 "No.of rates-%d\n", total_rates);
646
647 len += scnprintf(buf + len, buf_len - len,
648 "**************** %s ****************\n",
649 type_str[type]);
650 len += scnprintf(buf + len, buf_len - len,
651 "\t\t\t\tTPC values for Active chains\n");
652 len += scnprintf(buf + len, buf_len - len,
653 "Rate idx Preamble Rate code");
654
655 for (i = 1; i <= active_tx_chains; ++i) {
656 len += scnprintf(buf + len, buf_len - len,
657 "\t%d-Chain", i);
658 }
659
660 len += scnprintf(buf + len, buf_len - len, "\n");
661 for (i = pream_idx; i < WMI_TPC_PREAM_MAX; i++) {
662 if (chan_freq <= 2483) {
663 if (i == WMI_TPC_PREAM_VHT80 ||
664 i == WMI_TPC_PREAM_VHT160 ||
665 i == WMI_TPC_PREAM_HE80 ||
666 i == WMI_TPC_PREAM_HE160 ||
667 (i >= WMI_TPC_PREAM_EHT60 &&
668 i <= WMI_TPC_PREAM_EHT320)) {
669 max_rix += max_nss[i] * max_rates[i];
670 continue;
671 }
672 } else {
673 if (i == WMI_TPC_PREAM_CCK) {
674 max_rix += max_rates[i];
675 continue;
676 }
677 }
678
679 nss = (max_nss[i] < ar->num_tx_chains ? max_nss[i] : ar->num_tx_chains);
680
681 if (!(caps &
682 (1 << ATH12K_TPC_STATS_SUPPORT_BE_PUNC))) {
683 if (i == WMI_TPC_PREAM_EHT60 || i == WMI_TPC_PREAM_EHT120 ||
684 i == WMI_TPC_PREAM_EHT140 || i == WMI_TPC_PREAM_EHT200 ||
685 i == WMI_TPC_PREAM_EHT240 || i == WMI_TPC_PREAM_EHT280) {
686 max_rix += max_nss[i] * max_rates[i];
687 continue;
688 }
689 }
690
691 len = ath12k_tpc_fill_pream(ar, buf, buf_len, len, i, max_rix, nss,
692 max_rates[i], pream_type[i],
693 type, rate_idx[i], eht_rate_idx[eht_idx]);
694
695 if (pream_type[i] == WMI_RATE_PREAMBLE_EHT)
696 /*For fetch the next index eht rates from rates array2*/
697 ++eht_idx;
698
699 max_rix += max_nss[i] * max_rates[i];
700 }
701 return len;
702 }
703
ath12k_tpc_stats_fill(struct ath12k * ar,struct wmi_tpc_stats_arg * tpc_stats,char * buf)704 static void ath12k_tpc_stats_fill(struct ath12k *ar,
705 struct wmi_tpc_stats_arg *tpc_stats,
706 char *buf)
707 {
708 size_t buf_len = ATH12K_TPC_STATS_BUF_SIZE;
709 struct wmi_tpc_config_params *tpc;
710 size_t len = 0;
711
712 if (!tpc_stats) {
713 ath12k_warn(ar->ab, "failed to find tpc stats\n");
714 return;
715 }
716
717 spin_lock_bh(&ar->data_lock);
718
719 tpc = &tpc_stats->tpc_config;
720 len += scnprintf(buf + len, buf_len - len, "\n");
721 len += scnprintf(buf + len, buf_len - len,
722 "*************** TPC config **************\n");
723 len += scnprintf(buf + len, buf_len - len,
724 "* powers are in 0.25 dBm steps\n");
725 len += scnprintf(buf + len, buf_len - len,
726 "reg domain-%d\t\tchan freq-%d\n",
727 tpc->reg_domain, tpc->chan_freq);
728 len += scnprintf(buf + len, buf_len - len,
729 "power limit-%d\t\tmax reg-domain Power-%d\n",
730 le32_to_cpu(tpc->twice_max_reg_power) / 2, tpc->power_limit);
731 len += scnprintf(buf + len, buf_len - len,
732 "No.of tx chain-%d\t",
733 ar->num_tx_chains);
734
735 ath12k_tpc_stats_print(ar, tpc_stats, buf, len,
736 ar->debug.tpc_stats_type);
737
738 spin_unlock_bh(&ar->data_lock);
739 }
740
ath12k_open_tpc_stats(struct inode * inode,struct file * file)741 static int ath12k_open_tpc_stats(struct inode *inode, struct file *file)
742 {
743 struct ath12k *ar = inode->i_private;
744 struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
745 int ret;
746
747 guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);
748
749 if (ah->state != ATH12K_HW_STATE_ON) {
750 ath12k_warn(ar->ab, "Interface not up\n");
751 return -ENETDOWN;
752 }
753
754 void *buf __free(kfree) = kzalloc(ATH12K_TPC_STATS_BUF_SIZE, GFP_KERNEL);
755 if (!buf)
756 return -ENOMEM;
757
758 ret = ath12k_debug_tpc_stats_request(ar);
759 if (ret) {
760 ath12k_warn(ar->ab, "failed to request tpc stats: %d\n",
761 ret);
762 return ret;
763 }
764
765 if (!wait_for_completion_timeout(&ar->debug.tpc_complete, TPC_STATS_WAIT_TIME)) {
766 spin_lock_bh(&ar->data_lock);
767 ath12k_wmi_free_tpc_stats_mem(ar);
768 ar->debug.tpc_request = false;
769 spin_unlock_bh(&ar->data_lock);
770 return -ETIMEDOUT;
771 }
772
773 ath12k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf);
774 file->private_data = no_free_ptr(buf);
775
776 spin_lock_bh(&ar->data_lock);
777 ath12k_wmi_free_tpc_stats_mem(ar);
778 spin_unlock_bh(&ar->data_lock);
779
780 return 0;
781 }
782
ath12k_read_tpc_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)783 static ssize_t ath12k_read_tpc_stats(struct file *file,
784 char __user *user_buf,
785 size_t count, loff_t *ppos)
786 {
787 const char *buf = file->private_data;
788 size_t len = strlen(buf);
789
790 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
791 }
792
ath12k_release_tpc_stats(struct inode * inode,struct file * file)793 static int ath12k_release_tpc_stats(struct inode *inode,
794 struct file *file)
795 {
796 kfree(file->private_data);
797 return 0;
798 }
799
800 static const struct file_operations fops_tpc_stats = {
801 .open = ath12k_open_tpc_stats,
802 .release = ath12k_release_tpc_stats,
803 .read = ath12k_read_tpc_stats,
804 .owner = THIS_MODULE,
805 .llseek = default_llseek,
806 };
807
808 static const struct file_operations fops_tpc_stats_type = {
809 .write = ath12k_write_tpc_stats_type,
810 .open = simple_open,
811 .llseek = default_llseek,
812 };
813
ath12k_write_extd_rx_stats(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)814 static ssize_t ath12k_write_extd_rx_stats(struct file *file,
815 const char __user *ubuf,
816 size_t count, loff_t *ppos)
817 {
818 struct ath12k *ar = file->private_data;
819 struct htt_rx_ring_tlv_filter tlv_filter = {0};
820 u32 ring_id, rx_filter = 0;
821 bool enable;
822 int ret, i;
823
824 if (kstrtobool_from_user(ubuf, count, &enable))
825 return -EINVAL;
826
827 wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
828
829 if (!ar->ab->hw_params->rxdma1_enable) {
830 ret = count;
831 goto exit;
832 }
833
834 if (ar->ah->state != ATH12K_HW_STATE_ON) {
835 ret = -ENETDOWN;
836 goto exit;
837 }
838
839 if (enable == ar->debug.extd_rx_stats) {
840 ret = count;
841 goto exit;
842 }
843
844 if (enable) {
845 rx_filter = HTT_RX_FILTER_TLV_FLAGS_MPDU_START;
846 rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START;
847 rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END;
848 rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS;
849 rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT;
850 rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE;
851 rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START_USER_INFO;
852
853 tlv_filter.rx_filter = rx_filter;
854 tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
855 tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
856 tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
857 tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
858 HTT_RX_FP_DATA_FILTER_FLASG3;
859 } else {
860 tlv_filter = ath12k_mac_mon_status_filter_default;
861 }
862
863 ar->debug.rx_filter = tlv_filter.rx_filter;
864
865 for (i = 0; i < ar->ab->hw_params->num_rxdma_per_pdev; i++) {
866 ring_id = ar->dp.rxdma_mon_dst_ring[i].ring_id;
867 ret = ath12k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id + i,
868 HAL_RXDMA_MONITOR_DST,
869 DP_RXDMA_REFILL_RING_SIZE,
870 &tlv_filter);
871 if (ret) {
872 ath12k_warn(ar->ab, "failed to set rx filter for monitor status ring\n");
873 goto exit;
874 }
875 }
876
877 ar->debug.extd_rx_stats = !!enable;
878 ret = count;
879 exit:
880 wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
881 return ret;
882 }
883
ath12k_read_extd_rx_stats(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)884 static ssize_t ath12k_read_extd_rx_stats(struct file *file,
885 char __user *ubuf,
886 size_t count, loff_t *ppos)
887 {
888 struct ath12k *ar = file->private_data;
889 char buf[32];
890 int len = 0;
891
892 wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
893 len = scnprintf(buf, sizeof(buf) - len, "%d\n",
894 ar->debug.extd_rx_stats);
895 wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
896
897 return simple_read_from_buffer(ubuf, count, ppos, buf, len);
898 }
899
900 static const struct file_operations fops_extd_rx_stats = {
901 .read = ath12k_read_extd_rx_stats,
902 .write = ath12k_write_extd_rx_stats,
903 .open = simple_open,
904 };
905
ath12k_open_link_stats(struct inode * inode,struct file * file)906 static int ath12k_open_link_stats(struct inode *inode, struct file *file)
907 {
908 struct ath12k_vif *ahvif = inode->i_private;
909 size_t len = 0, buf_len = (PAGE_SIZE * 2);
910 struct ath12k_link_stats linkstat;
911 struct ath12k_link_vif *arvif;
912 unsigned long links_map;
913 struct wiphy *wiphy;
914 int link_id, i;
915 char *buf;
916
917 if (!ahvif)
918 return -EINVAL;
919
920 buf = kzalloc(buf_len, GFP_KERNEL);
921 if (!buf)
922 return -ENOMEM;
923
924 wiphy = ahvif->ah->hw->wiphy;
925 wiphy_lock(wiphy);
926
927 links_map = ahvif->links_map;
928 for_each_set_bit(link_id, &links_map,
929 IEEE80211_MLD_MAX_NUM_LINKS) {
930 arvif = rcu_dereference_protected(ahvif->link[link_id],
931 lockdep_is_held(&wiphy->mtx));
932
933 spin_lock_bh(&arvif->link_stats_lock);
934 linkstat = arvif->link_stats;
935 spin_unlock_bh(&arvif->link_stats_lock);
936
937 len += scnprintf(buf + len, buf_len - len,
938 "link[%d] Tx Unicast Frames Enqueued = %d\n",
939 link_id, linkstat.tx_enqueued);
940 len += scnprintf(buf + len, buf_len - len,
941 "link[%d] Tx Broadcast Frames Enqueued = %d\n",
942 link_id, linkstat.tx_bcast_mcast);
943 len += scnprintf(buf + len, buf_len - len,
944 "link[%d] Tx Frames Completed = %d\n",
945 link_id, linkstat.tx_completed);
946 len += scnprintf(buf + len, buf_len - len,
947 "link[%d] Tx Frames Dropped = %d\n",
948 link_id, linkstat.tx_dropped);
949
950 len += scnprintf(buf + len, buf_len - len,
951 "link[%d] Tx Frame descriptor Encap Type = ",
952 link_id);
953
954 len += scnprintf(buf + len, buf_len - len,
955 " raw:%d",
956 linkstat.tx_encap_type[0]);
957
958 len += scnprintf(buf + len, buf_len - len,
959 " native_wifi:%d",
960 linkstat.tx_encap_type[1]);
961
962 len += scnprintf(buf + len, buf_len - len,
963 " ethernet:%d",
964 linkstat.tx_encap_type[2]);
965
966 len += scnprintf(buf + len, buf_len - len,
967 "\nlink[%d] Tx Frame descriptor Encrypt Type = ",
968 link_id);
969
970 for (i = 0; i < HAL_ENCRYPT_TYPE_MAX; i++) {
971 len += scnprintf(buf + len, buf_len - len,
972 " %d:%d", i,
973 linkstat.tx_encrypt_type[i]);
974 }
975 len += scnprintf(buf + len, buf_len - len,
976 "\nlink[%d] Tx Frame descriptor Type = buffer:%d extension:%d\n",
977 link_id, linkstat.tx_desc_type[0],
978 linkstat.tx_desc_type[1]);
979
980 len += scnprintf(buf + len, buf_len - len,
981 "------------------------------------------------------\n");
982 }
983
984 wiphy_unlock(wiphy);
985
986 file->private_data = buf;
987
988 return 0;
989 }
990
ath12k_release_link_stats(struct inode * inode,struct file * file)991 static int ath12k_release_link_stats(struct inode *inode, struct file *file)
992 {
993 kfree(file->private_data);
994 return 0;
995 }
996
ath12k_read_link_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)997 static ssize_t ath12k_read_link_stats(struct file *file,
998 char __user *user_buf,
999 size_t count, loff_t *ppos)
1000 {
1001 const char *buf = file->private_data;
1002 size_t len = strlen(buf);
1003
1004 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1005 }
1006
1007 static const struct file_operations ath12k_fops_link_stats = {
1008 .open = ath12k_open_link_stats,
1009 .release = ath12k_release_link_stats,
1010 .read = ath12k_read_link_stats,
1011 .owner = THIS_MODULE,
1012 .llseek = default_llseek,
1013 };
1014
ath12k_debugfs_op_vif_add(struct ieee80211_hw * hw,struct ieee80211_vif * vif)1015 void ath12k_debugfs_op_vif_add(struct ieee80211_hw *hw,
1016 struct ieee80211_vif *vif)
1017 {
1018 struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
1019
1020 debugfs_create_file("link_stats", 0400, vif->debugfs_dir, ahvif,
1021 &ath12k_fops_link_stats);
1022 }
1023
ath12k_debugfs_dump_device_dp_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1024 static ssize_t ath12k_debugfs_dump_device_dp_stats(struct file *file,
1025 char __user *user_buf,
1026 size_t count, loff_t *ppos)
1027 {
1028 struct ath12k_base *ab = file->private_data;
1029 struct ath12k_device_dp_stats *device_stats = &ab->device_stats;
1030 int len = 0, i, j, ret;
1031 struct ath12k *ar;
1032 const int size = 4096;
1033 static const char *rxdma_err[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX] = {
1034 [HAL_REO_ENTR_RING_RXDMA_ECODE_OVERFLOW_ERR] = "Overflow",
1035 [HAL_REO_ENTR_RING_RXDMA_ECODE_MPDU_LEN_ERR] = "MPDU len",
1036 [HAL_REO_ENTR_RING_RXDMA_ECODE_FCS_ERR] = "FCS",
1037 [HAL_REO_ENTR_RING_RXDMA_ECODE_DECRYPT_ERR] = "Decrypt",
1038 [HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR] = "TKIP MIC",
1039 [HAL_REO_ENTR_RING_RXDMA_ECODE_UNECRYPTED_ERR] = "Unencrypt",
1040 [HAL_REO_ENTR_RING_RXDMA_ECODE_MSDU_LEN_ERR] = "MSDU len",
1041 [HAL_REO_ENTR_RING_RXDMA_ECODE_MSDU_LIMIT_ERR] = "MSDU limit",
1042 [HAL_REO_ENTR_RING_RXDMA_ECODE_WIFI_PARSE_ERR] = "WiFi parse",
1043 [HAL_REO_ENTR_RING_RXDMA_ECODE_AMSDU_PARSE_ERR] = "AMSDU parse",
1044 [HAL_REO_ENTR_RING_RXDMA_ECODE_SA_TIMEOUT_ERR] = "SA timeout",
1045 [HAL_REO_ENTR_RING_RXDMA_ECODE_DA_TIMEOUT_ERR] = "DA timeout",
1046 [HAL_REO_ENTR_RING_RXDMA_ECODE_FLOW_TIMEOUT_ERR] = "Flow timeout",
1047 [HAL_REO_ENTR_RING_RXDMA_ECODE_FLUSH_REQUEST_ERR] = "Flush req",
1048 [HAL_REO_ENTR_RING_RXDMA_ECODE_AMSDU_FRAG_ERR] = "AMSDU frag",
1049 [HAL_REO_ENTR_RING_RXDMA_ECODE_MULTICAST_ECHO_ERR] = "Multicast echo",
1050 [HAL_REO_ENTR_RING_RXDMA_ECODE_AMSDU_MISMATCH_ERR] = "AMSDU mismatch",
1051 [HAL_REO_ENTR_RING_RXDMA_ECODE_UNAUTH_WDS_ERR] = "Unauth WDS",
1052 [HAL_REO_ENTR_RING_RXDMA_ECODE_GRPCAST_AMSDU_WDS_ERR] = "AMSDU or WDS"};
1053
1054 static const char *reo_err[HAL_REO_DEST_RING_ERROR_CODE_MAX] = {
1055 [HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO] = "Desc addr zero",
1056 [HAL_REO_DEST_RING_ERROR_CODE_DESC_INVALID] = "Desc inval",
1057 [HAL_REO_DEST_RING_ERROR_CODE_AMPDU_IN_NON_BA] = "AMPDU in non BA",
1058 [HAL_REO_DEST_RING_ERROR_CODE_NON_BA_DUPLICATE] = "Non BA dup",
1059 [HAL_REO_DEST_RING_ERROR_CODE_BA_DUPLICATE] = "BA dup",
1060 [HAL_REO_DEST_RING_ERROR_CODE_FRAME_2K_JUMP] = "Frame 2k jump",
1061 [HAL_REO_DEST_RING_ERROR_CODE_BAR_2K_JUMP] = "BAR 2k jump",
1062 [HAL_REO_DEST_RING_ERROR_CODE_FRAME_OOR] = "Frame OOR",
1063 [HAL_REO_DEST_RING_ERROR_CODE_BAR_OOR] = "BAR OOR",
1064 [HAL_REO_DEST_RING_ERROR_CODE_NO_BA_SESSION] = "No BA session",
1065 [HAL_REO_DEST_RING_ERROR_CODE_FRAME_SN_EQUALS_SSN] = "Frame SN equal SSN",
1066 [HAL_REO_DEST_RING_ERROR_CODE_PN_CHECK_FAILED] = "PN check fail",
1067 [HAL_REO_DEST_RING_ERROR_CODE_2K_ERR_FLAG_SET] = "2k err",
1068 [HAL_REO_DEST_RING_ERROR_CODE_PN_ERR_FLAG_SET] = "PN err",
1069 [HAL_REO_DEST_RING_ERROR_CODE_DESC_BLOCKED] = "Desc blocked"};
1070
1071 static const char *wbm_rel_src[HAL_WBM_REL_SRC_MODULE_MAX] = {
1072 [HAL_WBM_REL_SRC_MODULE_TQM] = "TQM",
1073 [HAL_WBM_REL_SRC_MODULE_RXDMA] = "Rxdma",
1074 [HAL_WBM_REL_SRC_MODULE_REO] = "Reo",
1075 [HAL_WBM_REL_SRC_MODULE_FW] = "FW",
1076 [HAL_WBM_REL_SRC_MODULE_SW] = "SW"};
1077
1078 char *buf __free(kfree) = kzalloc(size, GFP_KERNEL);
1079
1080 if (!buf)
1081 return -ENOMEM;
1082
1083 len += scnprintf(buf + len, size - len, "DEVICE RX STATS:\n\n");
1084 len += scnprintf(buf + len, size - len, "err ring pkts: %u\n",
1085 device_stats->err_ring_pkts);
1086 len += scnprintf(buf + len, size - len, "Invalid RBM: %u\n\n",
1087 device_stats->invalid_rbm);
1088 len += scnprintf(buf + len, size - len, "RXDMA errors:\n");
1089
1090 for (i = 0; i < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX; i++)
1091 len += scnprintf(buf + len, size - len, "%s: %u\n",
1092 rxdma_err[i], device_stats->rxdma_error[i]);
1093
1094 len += scnprintf(buf + len, size - len, "\nREO errors:\n");
1095
1096 for (i = 0; i < HAL_REO_DEST_RING_ERROR_CODE_MAX; i++)
1097 len += scnprintf(buf + len, size - len, "%s: %u\n",
1098 reo_err[i], device_stats->reo_error[i]);
1099
1100 len += scnprintf(buf + len, size - len, "\nHAL REO errors:\n");
1101
1102 for (i = 0; i < DP_REO_DST_RING_MAX; i++)
1103 len += scnprintf(buf + len, size - len,
1104 "ring%d: %u\n", i,
1105 device_stats->hal_reo_error[i]);
1106
1107 len += scnprintf(buf + len, size - len, "\nDEVICE TX STATS:\n");
1108 len += scnprintf(buf + len, size - len, "\nTCL Ring Full Failures:\n");
1109
1110 for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)
1111 len += scnprintf(buf + len, size - len, "ring%d: %u\n",
1112 i, device_stats->tx_err.desc_na[i]);
1113
1114 len += scnprintf(buf + len, size - len,
1115 "\nMisc Transmit Failures: %d\n",
1116 atomic_read(&device_stats->tx_err.misc_fail));
1117
1118 len += scnprintf(buf + len, size - len, "\ntx_wbm_rel_source:");
1119
1120 for (i = 0; i < HAL_WBM_REL_SRC_MODULE_MAX; i++)
1121 len += scnprintf(buf + len, size - len, " %d:%u",
1122 i, device_stats->tx_wbm_rel_source[i]);
1123
1124 len += scnprintf(buf + len, size - len, "\n");
1125
1126 len += scnprintf(buf + len, size - len, "\ntqm_rel_reason:");
1127
1128 for (i = 0; i < MAX_TQM_RELEASE_REASON; i++)
1129 len += scnprintf(buf + len, size - len, " %d:%u",
1130 i, device_stats->tqm_rel_reason[i]);
1131
1132 len += scnprintf(buf + len, size - len, "\n");
1133
1134 len += scnprintf(buf + len, size - len, "\nfw_tx_status:");
1135
1136 for (i = 0; i < MAX_FW_TX_STATUS; i++)
1137 len += scnprintf(buf + len, size - len, " %d:%u",
1138 i, device_stats->fw_tx_status[i]);
1139
1140 len += scnprintf(buf + len, size - len, "\n");
1141
1142 len += scnprintf(buf + len, size - len, "\ntx_enqueued:");
1143
1144 for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)
1145 len += scnprintf(buf + len, size - len, " %d:%u", i,
1146 device_stats->tx_enqueued[i]);
1147
1148 len += scnprintf(buf + len, size - len, "\n");
1149
1150 len += scnprintf(buf + len, size - len, "\ntx_completed:");
1151
1152 for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)
1153 len += scnprintf(buf + len, size - len, " %d:%u",
1154 i, device_stats->tx_completed[i]);
1155
1156 len += scnprintf(buf + len, size - len, "\n");
1157
1158 for (i = 0; i < ab->num_radios; i++) {
1159 ar = ath12k_mac_get_ar_by_pdev_id(ab, DP_SW2HW_MACID(i));
1160 if (ar) {
1161 len += scnprintf(buf + len, size - len,
1162 "\nradio%d tx_pending: %u\n", i,
1163 atomic_read(&ar->dp.num_tx_pending));
1164 }
1165 }
1166
1167 len += scnprintf(buf + len, size - len, "\nREO Rx Received:\n");
1168
1169 for (i = 0; i < DP_REO_DST_RING_MAX; i++) {
1170 len += scnprintf(buf + len, size - len, "Ring%d:", i + 1);
1171
1172 for (j = 0; j < ATH12K_MAX_DEVICES; j++) {
1173 len += scnprintf(buf + len, size - len,
1174 "\t%d:%u", j,
1175 device_stats->reo_rx[i][j]);
1176 }
1177
1178 len += scnprintf(buf + len, size - len, "\n");
1179 }
1180
1181 len += scnprintf(buf + len, size - len, "\nRx WBM REL SRC Errors:\n");
1182
1183 for (i = 0; i < HAL_WBM_REL_SRC_MODULE_MAX; i++) {
1184 len += scnprintf(buf + len, size - len, "%s:", wbm_rel_src[i]);
1185
1186 for (j = 0; j < ATH12K_MAX_DEVICES; j++) {
1187 len += scnprintf(buf + len,
1188 size - len,
1189 "\t%d:%u", j,
1190 device_stats->rx_wbm_rel_source[i][j]);
1191 }
1192
1193 len += scnprintf(buf + len, size - len, "\n");
1194 }
1195
1196 ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
1197
1198 return ret;
1199 }
1200
1201 static const struct file_operations fops_device_dp_stats = {
1202 .read = ath12k_debugfs_dump_device_dp_stats,
1203 .open = simple_open,
1204 .owner = THIS_MODULE,
1205 .llseek = default_llseek,
1206 };
1207
ath12k_debugfs_pdev_create(struct ath12k_base * ab)1208 void ath12k_debugfs_pdev_create(struct ath12k_base *ab)
1209 {
1210 debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab,
1211 &fops_simulate_fw_crash);
1212
1213 debugfs_create_file("device_dp_stats", 0400, ab->debugfs_soc, ab,
1214 &fops_device_dp_stats);
1215 }
1216
ath12k_debugfs_soc_create(struct ath12k_base * ab)1217 void ath12k_debugfs_soc_create(struct ath12k_base *ab)
1218 {
1219 bool dput_needed;
1220 char soc_name[64] = { 0 };
1221 struct dentry *debugfs_ath12k;
1222
1223 debugfs_ath12k = debugfs_lookup("ath12k", NULL);
1224 if (debugfs_ath12k) {
1225 /* a dentry from lookup() needs dput() after we don't use it */
1226 dput_needed = true;
1227 } else {
1228 debugfs_ath12k = debugfs_create_dir("ath12k", NULL);
1229 if (IS_ERR_OR_NULL(debugfs_ath12k))
1230 return;
1231 dput_needed = false;
1232 }
1233
1234 scnprintf(soc_name, sizeof(soc_name), "%s-%s", ath12k_bus_str(ab->hif.bus),
1235 dev_name(ab->dev));
1236
1237 ab->debugfs_soc = debugfs_create_dir(soc_name, debugfs_ath12k);
1238
1239 if (dput_needed)
1240 dput(debugfs_ath12k);
1241 }
1242
ath12k_debugfs_soc_destroy(struct ath12k_base * ab)1243 void ath12k_debugfs_soc_destroy(struct ath12k_base *ab)
1244 {
1245 debugfs_remove_recursive(ab->debugfs_soc);
1246 ab->debugfs_soc = NULL;
1247 /* We are not removing ath12k directory on purpose, even if it
1248 * would be empty. This simplifies the directory handling and it's
1249 * a minor cosmetic issue to leave an empty ath12k directory to
1250 * debugfs.
1251 */
1252 }
1253
ath12k_open_vdev_stats(struct inode * inode,struct file * file)1254 static int ath12k_open_vdev_stats(struct inode *inode, struct file *file)
1255 {
1256 struct ath12k *ar = inode->i_private;
1257 struct ath12k_fw_stats_req_params param;
1258 struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
1259 int ret;
1260
1261 guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);
1262
1263 if (!ah)
1264 return -ENETDOWN;
1265
1266 if (ah->state != ATH12K_HW_STATE_ON)
1267 return -ENETDOWN;
1268
1269 void *buf __free(kfree) = kzalloc(ATH12K_FW_STATS_BUF_SIZE, GFP_ATOMIC);
1270 if (!buf)
1271 return -ENOMEM;
1272
1273 param.pdev_id = ath12k_mac_get_target_pdev_id(ar);
1274 /* VDEV stats is always sent for all active VDEVs from FW */
1275 param.vdev_id = 0;
1276 param.stats_id = WMI_REQUEST_VDEV_STAT;
1277
1278 ret = ath12k_mac_get_fw_stats(ar, ¶m);
1279 if (ret) {
1280 ath12k_warn(ar->ab, "failed to request fw vdev stats: %d\n", ret);
1281 return ret;
1282 }
1283
1284 ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,
1285 buf);
1286
1287 file->private_data = no_free_ptr(buf);
1288
1289 return 0;
1290 }
1291
ath12k_release_vdev_stats(struct inode * inode,struct file * file)1292 static int ath12k_release_vdev_stats(struct inode *inode, struct file *file)
1293 {
1294 kfree(file->private_data);
1295
1296 return 0;
1297 }
1298
ath12k_read_vdev_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1299 static ssize_t ath12k_read_vdev_stats(struct file *file,
1300 char __user *user_buf,
1301 size_t count, loff_t *ppos)
1302 {
1303 const char *buf = file->private_data;
1304 size_t len = strlen(buf);
1305
1306 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1307 }
1308
1309 static const struct file_operations fops_vdev_stats = {
1310 .open = ath12k_open_vdev_stats,
1311 .release = ath12k_release_vdev_stats,
1312 .read = ath12k_read_vdev_stats,
1313 .owner = THIS_MODULE,
1314 .llseek = default_llseek,
1315 };
1316
ath12k_open_bcn_stats(struct inode * inode,struct file * file)1317 static int ath12k_open_bcn_stats(struct inode *inode, struct file *file)
1318 {
1319 struct ath12k *ar = inode->i_private;
1320 struct ath12k_link_vif *arvif;
1321 struct ath12k_fw_stats_req_params param;
1322 struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
1323 int ret;
1324
1325 guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);
1326
1327 if (ah && ah->state != ATH12K_HW_STATE_ON)
1328 return -ENETDOWN;
1329
1330 void *buf __free(kfree) = kzalloc(ATH12K_FW_STATS_BUF_SIZE, GFP_ATOMIC);
1331 if (!buf)
1332 return -ENOMEM;
1333
1334 param.pdev_id = ath12k_mac_get_target_pdev_id(ar);
1335 param.stats_id = WMI_REQUEST_BCN_STAT;
1336
1337 /* loop all active VDEVs for bcn stats */
1338 list_for_each_entry(arvif, &ar->arvifs, list) {
1339 if (!arvif->is_up)
1340 continue;
1341
1342 param.vdev_id = arvif->vdev_id;
1343 ret = ath12k_mac_get_fw_stats(ar, ¶m);
1344 if (ret) {
1345 ath12k_warn(ar->ab, "failed to request fw bcn stats: %d\n", ret);
1346 return ret;
1347 }
1348 }
1349
1350 ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,
1351 buf);
1352 /* since beacon stats request is looped for all active VDEVs, saved fw
1353 * stats is not freed for each request until done for all active VDEVs
1354 */
1355 spin_lock_bh(&ar->data_lock);
1356 ath12k_fw_stats_bcn_free(&ar->fw_stats.bcn);
1357 spin_unlock_bh(&ar->data_lock);
1358
1359 file->private_data = no_free_ptr(buf);
1360
1361 return 0;
1362 }
1363
ath12k_release_bcn_stats(struct inode * inode,struct file * file)1364 static int ath12k_release_bcn_stats(struct inode *inode, struct file *file)
1365 {
1366 kfree(file->private_data);
1367
1368 return 0;
1369 }
1370
ath12k_read_bcn_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1371 static ssize_t ath12k_read_bcn_stats(struct file *file,
1372 char __user *user_buf,
1373 size_t count, loff_t *ppos)
1374 {
1375 const char *buf = file->private_data;
1376 size_t len = strlen(buf);
1377
1378 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1379 }
1380
1381 static const struct file_operations fops_bcn_stats = {
1382 .open = ath12k_open_bcn_stats,
1383 .release = ath12k_release_bcn_stats,
1384 .read = ath12k_read_bcn_stats,
1385 .owner = THIS_MODULE,
1386 .llseek = default_llseek,
1387 };
1388
ath12k_open_pdev_stats(struct inode * inode,struct file * file)1389 static int ath12k_open_pdev_stats(struct inode *inode, struct file *file)
1390 {
1391 struct ath12k *ar = inode->i_private;
1392 struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
1393 struct ath12k_base *ab = ar->ab;
1394 struct ath12k_fw_stats_req_params param;
1395 int ret;
1396
1397 guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);
1398
1399 if (ah && ah->state != ATH12K_HW_STATE_ON)
1400 return -ENETDOWN;
1401
1402 void *buf __free(kfree) = kzalloc(ATH12K_FW_STATS_BUF_SIZE, GFP_ATOMIC);
1403 if (!buf)
1404 return -ENOMEM;
1405
1406 param.pdev_id = ath12k_mac_get_target_pdev_id(ar);
1407 param.vdev_id = 0;
1408 param.stats_id = WMI_REQUEST_PDEV_STAT;
1409
1410 ret = ath12k_mac_get_fw_stats(ar, ¶m);
1411 if (ret) {
1412 ath12k_warn(ab, "failed to request fw pdev stats: %d\n", ret);
1413 return ret;
1414 }
1415
1416 ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,
1417 buf);
1418
1419 file->private_data = no_free_ptr(buf);
1420
1421 return 0;
1422 }
1423
ath12k_release_pdev_stats(struct inode * inode,struct file * file)1424 static int ath12k_release_pdev_stats(struct inode *inode, struct file *file)
1425 {
1426 kfree(file->private_data);
1427
1428 return 0;
1429 }
1430
ath12k_read_pdev_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1431 static ssize_t ath12k_read_pdev_stats(struct file *file,
1432 char __user *user_buf,
1433 size_t count, loff_t *ppos)
1434 {
1435 const char *buf = file->private_data;
1436 size_t len = strlen(buf);
1437
1438 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1439 }
1440
1441 static const struct file_operations fops_pdev_stats = {
1442 .open = ath12k_open_pdev_stats,
1443 .release = ath12k_release_pdev_stats,
1444 .read = ath12k_read_pdev_stats,
1445 .owner = THIS_MODULE,
1446 .llseek = default_llseek,
1447 };
1448
1449 static
ath12k_debugfs_fw_stats_register(struct ath12k * ar)1450 void ath12k_debugfs_fw_stats_register(struct ath12k *ar)
1451 {
1452 struct dentry *fwstats_dir = debugfs_create_dir("fw_stats",
1453 ar->debug.debugfs_pdev);
1454
1455 /* all stats debugfs files created are under "fw_stats" directory
1456 * created per PDEV
1457 */
1458 debugfs_create_file("vdev_stats", 0600, fwstats_dir, ar,
1459 &fops_vdev_stats);
1460 debugfs_create_file("beacon_stats", 0600, fwstats_dir, ar,
1461 &fops_bcn_stats);
1462 debugfs_create_file("pdev_stats", 0600, fwstats_dir, ar,
1463 &fops_pdev_stats);
1464
1465 ath12k_fw_stats_init(ar);
1466 }
1467
ath12k_debugfs_register(struct ath12k * ar)1468 void ath12k_debugfs_register(struct ath12k *ar)
1469 {
1470 struct ath12k_base *ab = ar->ab;
1471 struct ieee80211_hw *hw = ar->ah->hw;
1472 char pdev_name[5];
1473 char buf[100] = {0};
1474
1475 scnprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx);
1476
1477 ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc);
1478
1479 /* Create a symlink under ieee80211/phy* */
1480 scnprintf(buf, sizeof(buf), "../../ath12k/%pd2", ar->debug.debugfs_pdev);
1481 ar->debug.debugfs_pdev_symlink = debugfs_create_symlink("ath12k",
1482 hw->wiphy->debugfsdir,
1483 buf);
1484
1485 if (ar->mac.sbands[NL80211_BAND_5GHZ].channels) {
1486 debugfs_create_file("dfs_simulate_radar", 0200,
1487 ar->debug.debugfs_pdev, ar,
1488 &fops_simulate_radar);
1489 }
1490
1491 debugfs_create_file("tpc_stats", 0400, ar->debug.debugfs_pdev, ar,
1492 &fops_tpc_stats);
1493 debugfs_create_file("tpc_stats_type", 0200, ar->debug.debugfs_pdev,
1494 ar, &fops_tpc_stats_type);
1495 init_completion(&ar->debug.tpc_complete);
1496
1497 ath12k_debugfs_htt_stats_register(ar);
1498 ath12k_debugfs_fw_stats_register(ar);
1499
1500 debugfs_create_file("ext_rx_stats", 0644,
1501 ar->debug.debugfs_pdev, ar,
1502 &fops_extd_rx_stats);
1503 }
1504
ath12k_debugfs_unregister(struct ath12k * ar)1505 void ath12k_debugfs_unregister(struct ath12k *ar)
1506 {
1507 if (!ar->debug.debugfs_pdev)
1508 return;
1509
1510 /* Remove symlink under ieee80211/phy* */
1511 debugfs_remove(ar->debug.debugfs_pdev_symlink);
1512 debugfs_remove_recursive(ar->debug.debugfs_pdev);
1513 ar->debug.debugfs_pdev_symlink = NULL;
1514 ar->debug.debugfs_pdev = NULL;
1515 }
1516