Branch data Line data Source code
1 : : // SPDX-License-Identifier: ISC
2 : : /*
3 : : * Copyright (c) 2005-2011 Atheros Communications Inc.
4 : : * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
5 : : * Copyright (c) 2018, The Linux Foundation. All rights reserved.
6 : : */
7 : :
8 : : #include <linux/module.h>
9 : : #include <linux/debugfs.h>
10 : : #include <linux/vmalloc.h>
11 : : #include <linux/crc32.h>
12 : : #include <linux/firmware.h>
13 : :
14 : : #include "core.h"
15 : : #include "debug.h"
16 : : #include "hif.h"
17 : : #include "wmi-ops.h"
18 : :
19 : : /* ms */
20 : : #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
21 : :
22 : : #define ATH10K_DEBUG_CAL_DATA_LEN 12064
23 : :
24 : 48 : void ath10k_info(struct ath10k *ar, const char *fmt, ...)
25 : : {
26 : 48 : struct va_format vaf = {
27 : : .fmt = fmt,
28 : : };
29 : 48 : va_list args;
30 : :
31 : 48 : va_start(args, fmt);
32 : 48 : vaf.va = &args;
33 : 48 : dev_info(ar->dev, "%pV", &vaf);
34 : 48 : trace_ath10k_log_info(ar, &vaf);
35 : 48 : va_end(args);
36 : 48 : }
37 : : EXPORT_SYMBOL(ath10k_info);
38 : :
39 : 4 : void ath10k_debug_print_hwfw_info(struct ath10k *ar)
40 : : {
41 : 4 : const struct firmware *firmware;
42 : 4 : char fw_features[128] = {};
43 : 4 : u32 crc = 0;
44 : :
45 : 4 : ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features));
46 : :
47 : 4 : ath10k_info(ar, "%s target 0x%08x chip_id 0x%08x sub %04x:%04x",
48 : : ar->hw_params.name,
49 : : ar->target_version,
50 : : ar->bus_param.chip_id,
51 : : ar->id.subsystem_vendor, ar->id.subsystem_device);
52 : :
53 : 4 : ath10k_info(ar, "kconfig debug %d debugfs %d tracing %d dfs %d testmode %d\n",
54 : : IS_ENABLED(CONFIG_ATH10K_DEBUG),
55 : : IS_ENABLED(CONFIG_ATH10K_DEBUGFS),
56 : : IS_ENABLED(CONFIG_ATH10K_TRACING),
57 : : IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED),
58 : : IS_ENABLED(CONFIG_NL80211_TESTMODE));
59 : :
60 : 4 : firmware = ar->normal_mode_fw.fw_file.firmware;
61 [ - + ]: 4 : if (firmware)
62 : 0 : crc = crc32_le(0, firmware->data, firmware->size);
63 : :
64 : 4 : ath10k_info(ar, "firmware ver %s api %d features %s crc32 %08x\n",
65 : 4 : ar->hw->wiphy->fw_version,
66 : : ar->fw_api,
67 : : fw_features,
68 : : crc);
69 : 4 : }
70 : :
71 : 4 : void ath10k_debug_print_board_info(struct ath10k *ar)
72 : : {
73 : 4 : char boardinfo[100];
74 : 4 : const struct firmware *board;
75 : 4 : u32 crc;
76 : :
77 [ - + ]: 4 : if (ar->id.bmi_ids_valid)
78 : 0 : scnprintf(boardinfo, sizeof(boardinfo), "%d:%d",
79 : 0 : ar->id.bmi_chip_id, ar->id.bmi_board_id);
80 : : else
81 : 4 : scnprintf(boardinfo, sizeof(boardinfo), "N/A");
82 : :
83 : 4 : board = ar->normal_mode_fw.board;
84 [ - + - + ]: 4 : if (!IS_ERR_OR_NULL(board))
85 : 0 : crc = crc32_le(0, board->data, board->size);
86 : : else
87 : : crc = 0;
88 : :
89 : 4 : ath10k_info(ar, "board_file api %d bmi_id %s crc32 %08x",
90 : : ar->bd_api,
91 : : boardinfo,
92 : : crc);
93 : 4 : }
94 : :
95 : 4 : void ath10k_debug_print_boot_info(struct ath10k *ar)
96 : : {
97 [ + - ]: 4 : ath10k_info(ar, "htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d raw %d hwcrypto %d\n",
98 : 4 : ar->htt.target_version_major,
99 : 4 : ar->htt.target_version_minor,
100 : 4 : ar->normal_mode_fw.fw_file.wmi_op_version,
101 : 4 : ar->normal_mode_fw.fw_file.htt_op_version,
102 : : ath10k_cal_mode_str(ar->cal_mode),
103 : : ar->max_num_stations,
104 : : test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags),
105 : 4 : !test_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags));
106 : 4 : }
107 : :
108 : 4 : void ath10k_print_driver_info(struct ath10k *ar)
109 : : {
110 : 4 : ath10k_debug_print_hwfw_info(ar);
111 : 4 : ath10k_debug_print_board_info(ar);
112 : 4 : ath10k_debug_print_boot_info(ar);
113 : 4 : }
114 : : EXPORT_SYMBOL(ath10k_print_driver_info);
115 : :
116 : 134 : void ath10k_err(struct ath10k *ar, const char *fmt, ...)
117 : : {
118 : 134 : struct va_format vaf = {
119 : : .fmt = fmt,
120 : : };
121 : 134 : va_list args;
122 : :
123 : 134 : va_start(args, fmt);
124 : 134 : vaf.va = &args;
125 : 134 : dev_err(ar->dev, "%pV", &vaf);
126 : 134 : trace_ath10k_log_err(ar, &vaf);
127 : 134 : va_end(args);
128 : 134 : }
129 : : EXPORT_SYMBOL(ath10k_err);
130 : :
131 : 38 : void ath10k_warn(struct ath10k *ar, const char *fmt, ...)
132 : : {
133 : 38 : struct va_format vaf = {
134 : : .fmt = fmt,
135 : : };
136 : 38 : va_list args;
137 : :
138 : 38 : va_start(args, fmt);
139 : 38 : vaf.va = &args;
140 [ + - ]: 38 : dev_warn_ratelimited(ar->dev, "%pV", &vaf);
141 : 38 : trace_ath10k_log_warn(ar, &vaf);
142 : :
143 : 38 : va_end(args);
144 : 38 : }
145 : : EXPORT_SYMBOL(ath10k_warn);
146 : :
147 : : #ifdef CONFIG_ATH10K_DEBUGFS
148 : :
149 : 0 : static ssize_t ath10k_read_wmi_services(struct file *file,
150 : : char __user *user_buf,
151 : : size_t count, loff_t *ppos)
152 : : {
153 : 0 : struct ath10k *ar = file->private_data;
154 : 0 : char *buf;
155 : 0 : size_t len = 0, buf_len = 8192;
156 : 0 : const char *name;
157 : 0 : ssize_t ret_cnt;
158 : 0 : bool enabled;
159 : 0 : int i;
160 : :
161 : 0 : buf = kzalloc(buf_len, GFP_KERNEL);
162 [ # # ]: 0 : if (!buf)
163 : : return -ENOMEM;
164 : :
165 : 0 : mutex_lock(&ar->conf_mutex);
166 : :
167 : 0 : spin_lock_bh(&ar->data_lock);
168 [ # # ]: 0 : for (i = 0; i < WMI_SERVICE_MAX; i++) {
169 : 0 : enabled = test_bit(i, ar->wmi.svc_map);
170 [ # # ]: 0 : name = wmi_service_name(i);
171 : :
172 [ # # ]: 0 : if (!name) {
173 [ # # ]: 0 : if (enabled)
174 : 0 : len += scnprintf(buf + len, buf_len - len,
175 : : "%-40s %s (bit %d)\n",
176 : : "unknown", "enabled", i);
177 : :
178 : 0 : continue;
179 : : }
180 : :
181 [ # # ]: 0 : len += scnprintf(buf + len, buf_len - len,
182 : : "%-40s %s\n",
183 : : name, enabled ? "enabled" : "-");
184 : : }
185 : 0 : spin_unlock_bh(&ar->data_lock);
186 : :
187 : 0 : ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
188 : :
189 : 0 : mutex_unlock(&ar->conf_mutex);
190 : :
191 : 0 : kfree(buf);
192 : 0 : return ret_cnt;
193 : : }
194 : :
195 : : static const struct file_operations fops_wmi_services = {
196 : : .read = ath10k_read_wmi_services,
197 : : .open = simple_open,
198 : : .owner = THIS_MODULE,
199 : : .llseek = default_llseek,
200 : : };
201 : :
202 : 3 : static void ath10k_fw_stats_pdevs_free(struct list_head *head)
203 : : {
204 : 3 : struct ath10k_fw_stats_pdev *i, *tmp;
205 : :
206 [ - + ]: 3 : list_for_each_entry_safe(i, tmp, head, list) {
207 : 0 : list_del(&i->list);
208 : 0 : kfree(i);
209 : : }
210 : 3 : }
211 : :
212 : 3 : static void ath10k_fw_stats_vdevs_free(struct list_head *head)
213 : : {
214 : 3 : struct ath10k_fw_stats_vdev *i, *tmp;
215 : :
216 [ - + ]: 3 : list_for_each_entry_safe(i, tmp, head, list) {
217 : 0 : list_del(&i->list);
218 : 0 : kfree(i);
219 : : }
220 : 3 : }
221 : :
222 : 3 : static void ath10k_fw_stats_peers_free(struct list_head *head)
223 : : {
224 : 3 : struct ath10k_fw_stats_peer *i, *tmp;
225 : :
226 [ - + ]: 3 : list_for_each_entry_safe(i, tmp, head, list) {
227 : 0 : list_del(&i->list);
228 : 0 : kfree(i);
229 : : }
230 : 3 : }
231 : :
232 : 3 : static void ath10k_fw_extd_stats_peers_free(struct list_head *head)
233 : : {
234 : 3 : struct ath10k_fw_extd_stats_peer *i, *tmp;
235 : :
236 [ - + ]: 3 : list_for_each_entry_safe(i, tmp, head, list) {
237 : 0 : list_del(&i->list);
238 : 0 : kfree(i);
239 : : }
240 : 3 : }
241 : :
242 : 3 : static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
243 : : {
244 : 3 : spin_lock_bh(&ar->data_lock);
245 : 3 : ar->debug.fw_stats_done = false;
246 : 3 : ar->debug.fw_stats.extended = false;
247 : 3 : ath10k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
248 : 3 : ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
249 : 3 : ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers);
250 : 3 : ath10k_fw_extd_stats_peers_free(&ar->debug.fw_stats.peers_extd);
251 : 3 : spin_unlock_bh(&ar->data_lock);
252 : 3 : }
253 : :
254 : 0 : void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
255 : : {
256 : 0 : struct ath10k_fw_stats stats = {};
257 : 0 : bool is_start, is_started, is_end;
258 : 0 : size_t num_peers;
259 : 0 : size_t num_vdevs;
260 : 0 : int ret;
261 : :
262 : 0 : INIT_LIST_HEAD(&stats.pdevs);
263 : 0 : INIT_LIST_HEAD(&stats.vdevs);
264 : 0 : INIT_LIST_HEAD(&stats.peers);
265 : 0 : INIT_LIST_HEAD(&stats.peers_extd);
266 : :
267 : 0 : spin_lock_bh(&ar->data_lock);
268 [ # # ]: 0 : ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats);
269 [ # # ]: 0 : if (ret) {
270 : 0 : ath10k_warn(ar, "failed to pull fw stats: %d\n", ret);
271 : 0 : goto free;
272 : : }
273 : :
274 : : /* Stat data may exceed htc-wmi buffer limit. In such case firmware
275 : : * splits the stats data and delivers it in a ping-pong fashion of
276 : : * request cmd-update event.
277 : : *
278 : : * However there is no explicit end-of-data. Instead start-of-data is
279 : : * used as an implicit one. This works as follows:
280 : : * a) discard stat update events until one with pdev stats is
281 : : * delivered - this skips session started at end of (b)
282 : : * b) consume stat update events until another one with pdev stats is
283 : : * delivered which is treated as end-of-data and is itself discarded
284 : : */
285 [ # # ]: 0 : if (ath10k_peer_stats_enabled(ar))
286 : 0 : ath10k_sta_update_rx_duration(ar, &stats);
287 : :
288 [ # # ]: 0 : if (ar->debug.fw_stats_done) {
289 [ # # ]: 0 : if (!ath10k_peer_stats_enabled(ar))
290 : 0 : ath10k_warn(ar, "received unsolicited stats update event\n");
291 : :
292 : 0 : goto free;
293 : : }
294 : :
295 : 0 : num_peers = ath10k_wmi_fw_stats_num_peers(&ar->debug.fw_stats.peers);
296 : 0 : num_vdevs = ath10k_wmi_fw_stats_num_vdevs(&ar->debug.fw_stats.vdevs);
297 [ # # # # ]: 0 : is_start = (list_empty(&ar->debug.fw_stats.pdevs) &&
298 : : !list_empty(&stats.pdevs));
299 [ # # # # ]: 0 : is_end = (!list_empty(&ar->debug.fw_stats.pdevs) &&
300 : : !list_empty(&stats.pdevs));
301 : :
302 [ # # ]: 0 : if (is_start)
303 [ # # ]: 0 : list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs);
304 : :
305 [ # # ]: 0 : if (is_end)
306 : 0 : ar->debug.fw_stats_done = true;
307 : :
308 [ # # ]: 0 : if (stats.extended)
309 : 0 : ar->debug.fw_stats.extended = true;
310 : :
311 [ # # ]: 0 : is_started = !list_empty(&ar->debug.fw_stats.pdevs);
312 : :
313 [ # # # # ]: 0 : if (is_started && !is_end) {
314 [ # # ]: 0 : if (num_peers >= ATH10K_MAX_NUM_PEER_IDS) {
315 : : /* Although this is unlikely impose a sane limit to
316 : : * prevent firmware from DoS-ing the host.
317 : : */
318 : 0 : ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers);
319 : 0 : ath10k_fw_extd_stats_peers_free(&ar->debug.fw_stats.peers_extd);
320 : 0 : ath10k_warn(ar, "dropping fw peer stats\n");
321 : 0 : goto free;
322 : : }
323 : :
324 [ # # ]: 0 : if (num_vdevs >= BITS_PER_LONG) {
325 : 0 : ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
326 : 0 : ath10k_warn(ar, "dropping fw vdev stats\n");
327 : 0 : goto free;
328 : : }
329 : :
330 [ # # ]: 0 : if (!list_empty(&stats.peers))
331 [ # # ]: 0 : list_splice_tail_init(&stats.peers_extd,
332 : : &ar->debug.fw_stats.peers_extd);
333 : :
334 [ # # ]: 0 : list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers);
335 [ # # ]: 0 : list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs);
336 : : }
337 : :
338 : 0 : complete(&ar->debug.fw_stats_complete);
339 : :
340 : 0 : free:
341 : : /* In some cases lists have been spliced and cleared. Free up
342 : : * resources if that is not the case.
343 : : */
344 : 0 : ath10k_fw_stats_pdevs_free(&stats.pdevs);
345 : 0 : ath10k_fw_stats_vdevs_free(&stats.vdevs);
346 : 0 : ath10k_fw_stats_peers_free(&stats.peers);
347 : 0 : ath10k_fw_extd_stats_peers_free(&stats.peers_extd);
348 : :
349 : 0 : spin_unlock_bh(&ar->data_lock);
350 : 0 : }
351 : :
352 : 0 : static int ath10k_debug_fw_stats_request(struct ath10k *ar)
353 : : {
354 : 0 : unsigned long timeout, time_left;
355 : 0 : int ret;
356 : :
357 : 0 : lockdep_assert_held(&ar->conf_mutex);
358 : :
359 : 0 : timeout = jiffies + msecs_to_jiffies(1 * HZ);
360 : :
361 : 0 : ath10k_debug_fw_stats_reset(ar);
362 : :
363 : 0 : for (;;) {
364 [ # # ]: 0 : if (time_after(jiffies, timeout))
365 : : return -ETIMEDOUT;
366 : :
367 : 0 : reinit_completion(&ar->debug.fw_stats_complete);
368 : :
369 : 0 : ret = ath10k_wmi_request_stats(ar, ar->fw_stats_req_mask);
370 [ # # ]: 0 : if (ret) {
371 : 0 : ath10k_warn(ar, "could not request stats (%d)\n", ret);
372 : 0 : return ret;
373 : : }
374 : :
375 : 0 : time_left =
376 : 0 : wait_for_completion_timeout(&ar->debug.fw_stats_complete,
377 : : 1 * HZ);
378 [ # # ]: 0 : if (!time_left)
379 : : return -ETIMEDOUT;
380 : :
381 : 0 : spin_lock_bh(&ar->data_lock);
382 [ # # ]: 0 : if (ar->debug.fw_stats_done) {
383 : 0 : spin_unlock_bh(&ar->data_lock);
384 : 0 : break;
385 : : }
386 : 0 : spin_unlock_bh(&ar->data_lock);
387 : : }
388 : :
389 : 0 : return 0;
390 : : }
391 : :
392 : 0 : static int ath10k_fw_stats_open(struct inode *inode, struct file *file)
393 : : {
394 : 0 : struct ath10k *ar = inode->i_private;
395 : 0 : void *buf = NULL;
396 : 0 : int ret;
397 : :
398 : 0 : mutex_lock(&ar->conf_mutex);
399 : :
400 [ # # ]: 0 : if (ar->state != ATH10K_STATE_ON) {
401 : 0 : ret = -ENETDOWN;
402 : 0 : goto err_unlock;
403 : : }
404 : :
405 : 0 : buf = vmalloc(ATH10K_FW_STATS_BUF_SIZE);
406 [ # # ]: 0 : if (!buf) {
407 : 0 : ret = -ENOMEM;
408 : 0 : goto err_unlock;
409 : : }
410 : :
411 : 0 : ret = ath10k_debug_fw_stats_request(ar);
412 [ # # ]: 0 : if (ret) {
413 : 0 : ath10k_warn(ar, "failed to request fw stats: %d\n", ret);
414 : 0 : goto err_free;
415 : : }
416 : :
417 [ # # ]: 0 : ret = ath10k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, buf);
418 : 0 : if (ret) {
419 : 0 : ath10k_warn(ar, "failed to fill fw stats: %d\n", ret);
420 : 0 : goto err_free;
421 : : }
422 : :
423 : 0 : file->private_data = buf;
424 : :
425 : 0 : mutex_unlock(&ar->conf_mutex);
426 : 0 : return 0;
427 : :
428 : 0 : err_free:
429 : 0 : vfree(buf);
430 : :
431 : 0 : err_unlock:
432 : 0 : mutex_unlock(&ar->conf_mutex);
433 : 0 : return ret;
434 : : }
435 : :
436 : 0 : static int ath10k_fw_stats_release(struct inode *inode, struct file *file)
437 : : {
438 : 0 : vfree(file->private_data);
439 : :
440 : 0 : return 0;
441 : : }
442 : :
443 : 0 : static ssize_t ath10k_fw_stats_read(struct file *file, char __user *user_buf,
444 : : size_t count, loff_t *ppos)
445 : : {
446 : 0 : const char *buf = file->private_data;
447 : 0 : size_t len = strlen(buf);
448 : :
449 : 0 : return simple_read_from_buffer(user_buf, count, ppos, buf, len);
450 : : }
451 : :
452 : : static const struct file_operations fops_fw_stats = {
453 : : .open = ath10k_fw_stats_open,
454 : : .release = ath10k_fw_stats_release,
455 : : .read = ath10k_fw_stats_read,
456 : : .owner = THIS_MODULE,
457 : : .llseek = default_llseek,
458 : : };
459 : :
460 : 0 : static ssize_t ath10k_debug_fw_reset_stats_read(struct file *file,
461 : : char __user *user_buf,
462 : : size_t count, loff_t *ppos)
463 : : {
464 : 0 : struct ath10k *ar = file->private_data;
465 : 0 : int ret;
466 : 0 : size_t len = 0, buf_len = 500;
467 : 0 : char *buf;
468 : :
469 : 0 : buf = kmalloc(buf_len, GFP_KERNEL);
470 [ # # ]: 0 : if (!buf)
471 : : return -ENOMEM;
472 : :
473 : 0 : spin_lock_bh(&ar->data_lock);
474 : :
475 : 0 : len += scnprintf(buf + len, buf_len - len,
476 : : "fw_crash_counter\t\t%d\n", ar->stats.fw_crash_counter);
477 : 0 : len += scnprintf(buf + len, buf_len - len,
478 : : "fw_warm_reset_counter\t\t%d\n",
479 : : ar->stats.fw_warm_reset_counter);
480 : 0 : len += scnprintf(buf + len, buf_len - len,
481 : : "fw_cold_reset_counter\t\t%d\n",
482 : : ar->stats.fw_cold_reset_counter);
483 : :
484 : 0 : spin_unlock_bh(&ar->data_lock);
485 : :
486 : 0 : ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
487 : :
488 : 0 : kfree(buf);
489 : :
490 : 0 : return ret;
491 : : }
492 : :
493 : : static const struct file_operations fops_fw_reset_stats = {
494 : : .open = simple_open,
495 : : .read = ath10k_debug_fw_reset_stats_read,
496 : : .owner = THIS_MODULE,
497 : : .llseek = default_llseek,
498 : : };
499 : :
500 : : /* This is a clean assert crash in firmware. */
501 : 0 : static int ath10k_debug_fw_assert(struct ath10k *ar)
502 : : {
503 : 0 : struct wmi_vdev_install_key_cmd *cmd;
504 : 0 : struct sk_buff *skb;
505 : :
506 : 0 : skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + 16);
507 [ # # ]: 0 : if (!skb)
508 : : return -ENOMEM;
509 : :
510 : 0 : cmd = (struct wmi_vdev_install_key_cmd *)skb->data;
511 : 0 : memset(cmd, 0, sizeof(*cmd));
512 : :
513 : : /* big enough number so that firmware asserts */
514 : 0 : cmd->vdev_id = __cpu_to_le32(0x7ffe);
515 : :
516 : 0 : return ath10k_wmi_cmd_send(ar, skb,
517 : 0 : ar->wmi.cmd->vdev_install_key_cmdid);
518 : : }
519 : :
520 : 0 : static ssize_t ath10k_read_simulate_fw_crash(struct file *file,
521 : : char __user *user_buf,
522 : : size_t count, loff_t *ppos)
523 : : {
524 : 0 : const char buf[] =
525 : : "To simulate firmware crash write one of the keywords to this file:\n"
526 : : "`soft` - this will send WMI_FORCE_FW_HANG_ASSERT to firmware if FW supports that command.\n"
527 : : "`hard` - this will send to firmware command with illegal parameters causing firmware crash.\n"
528 : : "`assert` - this will send special illegal parameter to firmware to cause assert failure and crash.\n"
529 : : "`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n";
530 : :
531 : 0 : return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
532 : : }
533 : :
534 : : /* Simulate firmware crash:
535 : : * 'soft': Call wmi command causing firmware hang. This firmware hang is
536 : : * recoverable by warm firmware reset.
537 : : * 'hard': Force firmware crash by setting any vdev parameter for not allowed
538 : : * vdev id. This is hard firmware crash because it is recoverable only by cold
539 : : * firmware reset.
540 : : */
541 : 0 : static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
542 : : const char __user *user_buf,
543 : : size_t count, loff_t *ppos)
544 : : {
545 : 0 : struct ath10k *ar = file->private_data;
546 : 0 : char buf[32] = {0};
547 : 0 : ssize_t rc;
548 : 0 : int ret;
549 : :
550 : : /* filter partial writes and invalid commands */
551 [ # # # # : 0 : if (*ppos != 0 || count >= sizeof(buf) || count == 0)
# # ]
552 : : return -EINVAL;
553 : :
554 : 0 : rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
555 [ # # ]: 0 : if (rc < 0)
556 : : return rc;
557 : :
558 : : /* drop the possible '\n' from the end */
559 [ # # ]: 0 : if (buf[*ppos - 1] == '\n')
560 : 0 : buf[*ppos - 1] = '\0';
561 : :
562 : 0 : mutex_lock(&ar->conf_mutex);
563 : :
564 [ # # # # ]: 0 : if (ar->state != ATH10K_STATE_ON &&
565 : : ar->state != ATH10K_STATE_RESTARTED) {
566 : 0 : ret = -ENETDOWN;
567 : 0 : goto exit;
568 : : }
569 : :
570 [ # # ]: 0 : if (!strcmp(buf, "soft")) {
571 : 0 : ath10k_info(ar, "simulating soft firmware crash\n");
572 : 0 : ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0);
573 [ # # ]: 0 : } else if (!strcmp(buf, "hard")) {
574 : 0 : ath10k_info(ar, "simulating hard firmware crash\n");
575 : : /* 0x7fff is vdev id, and it is always out of range for all
576 : : * firmware variants in order to force a firmware crash.
577 : : */
578 : 0 : ret = ath10k_wmi_vdev_set_param(ar, 0x7fff,
579 : 0 : ar->wmi.vdev_param->rts_threshold,
580 : : 0);
581 [ # # ]: 0 : } else if (!strcmp(buf, "assert")) {
582 : 0 : ath10k_info(ar, "simulating firmware assert crash\n");
583 : 0 : ret = ath10k_debug_fw_assert(ar);
584 [ # # ]: 0 : } else if (!strcmp(buf, "hw-restart")) {
585 : 0 : ath10k_info(ar, "user requested hw restart\n");
586 : 0 : queue_work(ar->workqueue, &ar->restart_work);
587 : 0 : ret = 0;
588 : : } else {
589 : 0 : ret = -EINVAL;
590 : 0 : goto exit;
591 : : }
592 : :
593 [ # # ]: 0 : if (ret) {
594 : 0 : ath10k_warn(ar, "failed to simulate firmware crash: %d\n", ret);
595 : 0 : goto exit;
596 : : }
597 : :
598 : 0 : ret = count;
599 : :
600 : 0 : exit:
601 : 0 : mutex_unlock(&ar->conf_mutex);
602 : 0 : return ret;
603 : : }
604 : :
605 : : static const struct file_operations fops_simulate_fw_crash = {
606 : : .read = ath10k_read_simulate_fw_crash,
607 : : .write = ath10k_write_simulate_fw_crash,
608 : : .open = simple_open,
609 : : .owner = THIS_MODULE,
610 : : .llseek = default_llseek,
611 : : };
612 : :
613 : 0 : static ssize_t ath10k_read_chip_id(struct file *file, char __user *user_buf,
614 : : size_t count, loff_t *ppos)
615 : : {
616 : 0 : struct ath10k *ar = file->private_data;
617 : 0 : size_t len;
618 : 0 : char buf[50];
619 : :
620 : 0 : len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->bus_param.chip_id);
621 : :
622 : 0 : return simple_read_from_buffer(user_buf, count, ppos, buf, len);
623 : : }
624 : :
625 : : static const struct file_operations fops_chip_id = {
626 : : .read = ath10k_read_chip_id,
627 : : .open = simple_open,
628 : : .owner = THIS_MODULE,
629 : : .llseek = default_llseek,
630 : : };
631 : :
632 : 0 : static ssize_t ath10k_reg_addr_read(struct file *file,
633 : : char __user *user_buf,
634 : : size_t count, loff_t *ppos)
635 : : {
636 : 0 : struct ath10k *ar = file->private_data;
637 : 0 : u8 buf[32];
638 : 0 : size_t len = 0;
639 : 0 : u32 reg_addr;
640 : :
641 : 0 : mutex_lock(&ar->conf_mutex);
642 : 0 : reg_addr = ar->debug.reg_addr;
643 : 0 : mutex_unlock(&ar->conf_mutex);
644 : :
645 : 0 : len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", reg_addr);
646 : :
647 : 0 : return simple_read_from_buffer(user_buf, count, ppos, buf, len);
648 : : }
649 : :
650 : 0 : static ssize_t ath10k_reg_addr_write(struct file *file,
651 : : const char __user *user_buf,
652 : : size_t count, loff_t *ppos)
653 : : {
654 : 0 : struct ath10k *ar = file->private_data;
655 : 0 : u32 reg_addr;
656 : 0 : int ret;
657 : :
658 : 0 : ret = kstrtou32_from_user(user_buf, count, 0, ®_addr);
659 [ # # ]: 0 : if (ret)
660 : 0 : return ret;
661 : :
662 [ # # ]: 0 : if (!IS_ALIGNED(reg_addr, 4))
663 : : return -EFAULT;
664 : :
665 : 0 : mutex_lock(&ar->conf_mutex);
666 : 0 : ar->debug.reg_addr = reg_addr;
667 : 0 : mutex_unlock(&ar->conf_mutex);
668 : :
669 : 0 : return count;
670 : : }
671 : :
672 : : static const struct file_operations fops_reg_addr = {
673 : : .read = ath10k_reg_addr_read,
674 : : .write = ath10k_reg_addr_write,
675 : : .open = simple_open,
676 : : .owner = THIS_MODULE,
677 : : .llseek = default_llseek,
678 : : };
679 : :
680 : 0 : static ssize_t ath10k_reg_value_read(struct file *file,
681 : : char __user *user_buf,
682 : : size_t count, loff_t *ppos)
683 : : {
684 : 0 : struct ath10k *ar = file->private_data;
685 : 0 : u8 buf[48];
686 : 0 : size_t len;
687 : 0 : u32 reg_addr, reg_val;
688 : 0 : int ret;
689 : :
690 : 0 : mutex_lock(&ar->conf_mutex);
691 : :
692 [ # # # # ]: 0 : if (ar->state != ATH10K_STATE_ON &&
693 : : ar->state != ATH10K_STATE_UTF) {
694 : 0 : ret = -ENETDOWN;
695 : 0 : goto exit;
696 : : }
697 : :
698 : 0 : reg_addr = ar->debug.reg_addr;
699 : :
700 : 0 : reg_val = ath10k_hif_read32(ar, reg_addr);
701 : 0 : len = scnprintf(buf, sizeof(buf), "0x%08x:0x%08x\n", reg_addr, reg_val);
702 : :
703 : 0 : ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
704 : :
705 : 0 : exit:
706 : 0 : mutex_unlock(&ar->conf_mutex);
707 : :
708 : 0 : return ret;
709 : : }
710 : :
711 : 0 : static ssize_t ath10k_reg_value_write(struct file *file,
712 : : const char __user *user_buf,
713 : : size_t count, loff_t *ppos)
714 : : {
715 : 0 : struct ath10k *ar = file->private_data;
716 : 0 : u32 reg_addr, reg_val;
717 : 0 : int ret;
718 : :
719 : 0 : mutex_lock(&ar->conf_mutex);
720 : :
721 [ # # # # ]: 0 : if (ar->state != ATH10K_STATE_ON &&
722 : : ar->state != ATH10K_STATE_UTF) {
723 : 0 : ret = -ENETDOWN;
724 : 0 : goto exit;
725 : : }
726 : :
727 : 0 : reg_addr = ar->debug.reg_addr;
728 : :
729 : 0 : ret = kstrtou32_from_user(user_buf, count, 0, ®_val);
730 [ # # ]: 0 : if (ret)
731 : 0 : goto exit;
732 : :
733 : 0 : ath10k_hif_write32(ar, reg_addr, reg_val);
734 : :
735 : 0 : ret = count;
736 : :
737 : 0 : exit:
738 : 0 : mutex_unlock(&ar->conf_mutex);
739 : :
740 : 0 : return ret;
741 : : }
742 : :
743 : : static const struct file_operations fops_reg_value = {
744 : : .read = ath10k_reg_value_read,
745 : : .write = ath10k_reg_value_write,
746 : : .open = simple_open,
747 : : .owner = THIS_MODULE,
748 : : .llseek = default_llseek,
749 : : };
750 : :
751 : 0 : static ssize_t ath10k_mem_value_read(struct file *file,
752 : : char __user *user_buf,
753 : : size_t count, loff_t *ppos)
754 : : {
755 : 0 : struct ath10k *ar = file->private_data;
756 : 0 : u8 *buf;
757 : 0 : int ret;
758 : :
759 [ # # ]: 0 : if (*ppos < 0)
760 : : return -EINVAL;
761 : :
762 [ # # ]: 0 : if (!count)
763 : : return 0;
764 : :
765 : 0 : mutex_lock(&ar->conf_mutex);
766 : :
767 : 0 : buf = vmalloc(count);
768 [ # # ]: 0 : if (!buf) {
769 : 0 : ret = -ENOMEM;
770 : 0 : goto exit;
771 : : }
772 : :
773 [ # # # # ]: 0 : if (ar->state != ATH10K_STATE_ON &&
774 : : ar->state != ATH10K_STATE_UTF) {
775 : 0 : ret = -ENETDOWN;
776 : 0 : goto exit;
777 : : }
778 : :
779 : 0 : ret = ath10k_hif_diag_read(ar, *ppos, buf, count);
780 [ # # ]: 0 : if (ret) {
781 : 0 : ath10k_warn(ar, "failed to read address 0x%08x via diagnose window fnrom debugfs: %d\n",
782 : 0 : (u32)(*ppos), ret);
783 : 0 : goto exit;
784 : : }
785 : :
786 [ # # ]: 0 : ret = copy_to_user(user_buf, buf, count);
787 [ # # ]: 0 : if (ret) {
788 : 0 : ret = -EFAULT;
789 : 0 : goto exit;
790 : : }
791 : :
792 : 0 : count -= ret;
793 : 0 : *ppos += count;
794 : 0 : ret = count;
795 : :
796 : 0 : exit:
797 : 0 : vfree(buf);
798 : 0 : mutex_unlock(&ar->conf_mutex);
799 : :
800 : 0 : return ret;
801 : : }
802 : :
803 : 0 : static ssize_t ath10k_mem_value_write(struct file *file,
804 : : const char __user *user_buf,
805 : : size_t count, loff_t *ppos)
806 : : {
807 : 0 : struct ath10k *ar = file->private_data;
808 : 0 : u8 *buf;
809 : 0 : int ret;
810 : :
811 [ # # ]: 0 : if (*ppos < 0)
812 : : return -EINVAL;
813 : :
814 [ # # ]: 0 : if (!count)
815 : : return 0;
816 : :
817 : 0 : mutex_lock(&ar->conf_mutex);
818 : :
819 : 0 : buf = vmalloc(count);
820 [ # # ]: 0 : if (!buf) {
821 : 0 : ret = -ENOMEM;
822 : 0 : goto exit;
823 : : }
824 : :
825 [ # # # # ]: 0 : if (ar->state != ATH10K_STATE_ON &&
826 : : ar->state != ATH10K_STATE_UTF) {
827 : 0 : ret = -ENETDOWN;
828 : 0 : goto exit;
829 : : }
830 : :
831 [ # # ]: 0 : ret = copy_from_user(buf, user_buf, count);
832 [ # # ]: 0 : if (ret) {
833 : 0 : ret = -EFAULT;
834 : 0 : goto exit;
835 : : }
836 : :
837 [ # # ]: 0 : ret = ath10k_hif_diag_write(ar, *ppos, buf, count);
838 [ # # ]: 0 : if (ret) {
839 : 0 : ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n",
840 : 0 : (u32)(*ppos), ret);
841 : 0 : goto exit;
842 : : }
843 : :
844 : 0 : *ppos += count;
845 : 0 : ret = count;
846 : :
847 : 0 : exit:
848 : 0 : vfree(buf);
849 : 0 : mutex_unlock(&ar->conf_mutex);
850 : :
851 : 0 : return ret;
852 : : }
853 : :
854 : : static const struct file_operations fops_mem_value = {
855 : : .read = ath10k_mem_value_read,
856 : : .write = ath10k_mem_value_write,
857 : : .open = simple_open,
858 : : .owner = THIS_MODULE,
859 : : .llseek = default_llseek,
860 : : };
861 : :
862 : 0 : static int ath10k_debug_htt_stats_req(struct ath10k *ar)
863 : : {
864 : 0 : u64 cookie;
865 : 0 : int ret;
866 : :
867 : 0 : lockdep_assert_held(&ar->conf_mutex);
868 : :
869 [ # # ]: 0 : if (ar->debug.htt_stats_mask == 0)
870 : : /* htt stats are disabled */
871 : : return 0;
872 : :
873 [ # # ]: 0 : if (ar->state != ATH10K_STATE_ON)
874 : : return 0;
875 : :
876 : 0 : cookie = get_jiffies_64();
877 : :
878 : 0 : ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask,
879 : 0 : ar->debug.reset_htt_stats, cookie);
880 [ # # ]: 0 : if (ret) {
881 : 0 : ath10k_warn(ar, "failed to send htt stats request: %d\n", ret);
882 : 0 : return ret;
883 : : }
884 : :
885 : 0 : queue_delayed_work(ar->workqueue, &ar->debug.htt_stats_dwork,
886 : : msecs_to_jiffies(ATH10K_DEBUG_HTT_STATS_INTERVAL));
887 : :
888 : 0 : return 0;
889 : : }
890 : :
891 : 0 : static void ath10k_debug_htt_stats_dwork(struct work_struct *work)
892 : : {
893 : 0 : struct ath10k *ar = container_of(work, struct ath10k,
894 : : debug.htt_stats_dwork.work);
895 : :
896 : 0 : mutex_lock(&ar->conf_mutex);
897 : :
898 : 0 : ath10k_debug_htt_stats_req(ar);
899 : :
900 : 0 : mutex_unlock(&ar->conf_mutex);
901 : 0 : }
902 : :
903 : 0 : static ssize_t ath10k_read_htt_stats_mask(struct file *file,
904 : : char __user *user_buf,
905 : : size_t count, loff_t *ppos)
906 : : {
907 : 0 : struct ath10k *ar = file->private_data;
908 : 0 : char buf[32];
909 : 0 : size_t len;
910 : :
911 : 0 : len = scnprintf(buf, sizeof(buf), "%lu\n", ar->debug.htt_stats_mask);
912 : :
913 : 0 : return simple_read_from_buffer(user_buf, count, ppos, buf, len);
914 : : }
915 : :
916 : 0 : static ssize_t ath10k_write_htt_stats_mask(struct file *file,
917 : : const char __user *user_buf,
918 : : size_t count, loff_t *ppos)
919 : : {
920 : 0 : struct ath10k *ar = file->private_data;
921 : 0 : unsigned long mask;
922 : 0 : int ret;
923 : :
924 : 0 : ret = kstrtoul_from_user(user_buf, count, 0, &mask);
925 [ # # ]: 0 : if (ret)
926 : 0 : return ret;
927 : :
928 : : /* max 17 bit masks (for now) */
929 [ # # ]: 0 : if (mask > HTT_STATS_BIT_MASK)
930 : : return -E2BIG;
931 : :
932 : 0 : mutex_lock(&ar->conf_mutex);
933 : :
934 : 0 : ar->debug.htt_stats_mask = mask;
935 : :
936 : 0 : ret = ath10k_debug_htt_stats_req(ar);
937 [ # # ]: 0 : if (ret)
938 : 0 : goto out;
939 : :
940 : 0 : ret = count;
941 : :
942 : 0 : out:
943 : 0 : mutex_unlock(&ar->conf_mutex);
944 : :
945 : 0 : return ret;
946 : : }
947 : :
948 : : static const struct file_operations fops_htt_stats_mask = {
949 : : .read = ath10k_read_htt_stats_mask,
950 : : .write = ath10k_write_htt_stats_mask,
951 : : .open = simple_open,
952 : : .owner = THIS_MODULE,
953 : : .llseek = default_llseek,
954 : : };
955 : :
956 : 0 : static ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file,
957 : : char __user *user_buf,
958 : : size_t count, loff_t *ppos)
959 : : {
960 : 0 : struct ath10k *ar = file->private_data;
961 : 0 : char buf[64];
962 : 0 : u8 amsdu, ampdu;
963 : 0 : size_t len;
964 : :
965 : 0 : mutex_lock(&ar->conf_mutex);
966 : :
967 : 0 : amsdu = ar->htt.max_num_amsdu;
968 : 0 : ampdu = ar->htt.max_num_ampdu;
969 : 0 : mutex_unlock(&ar->conf_mutex);
970 : :
971 : 0 : len = scnprintf(buf, sizeof(buf), "%u %u\n", amsdu, ampdu);
972 : :
973 : 0 : return simple_read_from_buffer(user_buf, count, ppos, buf, len);
974 : : }
975 : :
976 : 0 : static ssize_t ath10k_write_htt_max_amsdu_ampdu(struct file *file,
977 : : const char __user *user_buf,
978 : : size_t count, loff_t *ppos)
979 : : {
980 : 0 : struct ath10k *ar = file->private_data;
981 : 0 : int res;
982 : 0 : char buf[64] = {0};
983 : 0 : unsigned int amsdu, ampdu;
984 : :
985 : 0 : res = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
986 : : user_buf, count);
987 [ # # ]: 0 : if (res <= 0)
988 : 0 : return res;
989 : :
990 : 0 : res = sscanf(buf, "%u %u", &amsdu, &du);
991 : :
992 [ # # ]: 0 : if (res != 2)
993 : : return -EINVAL;
994 : :
995 : 0 : mutex_lock(&ar->conf_mutex);
996 : :
997 [ # # ]: 0 : res = ath10k_htt_h2t_aggr_cfg_msg(&ar->htt, ampdu, amsdu);
998 [ # # ]: 0 : if (res)
999 : 0 : goto out;
1000 : :
1001 : 0 : res = count;
1002 : 0 : ar->htt.max_num_amsdu = amsdu;
1003 : 0 : ar->htt.max_num_ampdu = ampdu;
1004 : :
1005 : 0 : out:
1006 : 0 : mutex_unlock(&ar->conf_mutex);
1007 : 0 : return res;
1008 : : }
1009 : :
1010 : : static const struct file_operations fops_htt_max_amsdu_ampdu = {
1011 : : .read = ath10k_read_htt_max_amsdu_ampdu,
1012 : : .write = ath10k_write_htt_max_amsdu_ampdu,
1013 : : .open = simple_open,
1014 : : .owner = THIS_MODULE,
1015 : : .llseek = default_llseek,
1016 : : };
1017 : :
1018 : 0 : static ssize_t ath10k_read_fw_dbglog(struct file *file,
1019 : : char __user *user_buf,
1020 : : size_t count, loff_t *ppos)
1021 : : {
1022 : 0 : struct ath10k *ar = file->private_data;
1023 : 0 : size_t len;
1024 : 0 : char buf[96];
1025 : :
1026 : 0 : len = scnprintf(buf, sizeof(buf), "0x%16llx %u\n",
1027 : : ar->debug.fw_dbglog_mask, ar->debug.fw_dbglog_level);
1028 : :
1029 : 0 : return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1030 : : }
1031 : :
1032 : 0 : static ssize_t ath10k_write_fw_dbglog(struct file *file,
1033 : : const char __user *user_buf,
1034 : : size_t count, loff_t *ppos)
1035 : : {
1036 : 0 : struct ath10k *ar = file->private_data;
1037 : 0 : int ret;
1038 : 0 : char buf[96] = {0};
1039 : 0 : unsigned int log_level;
1040 : 0 : u64 mask;
1041 : :
1042 : 0 : ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
1043 : : user_buf, count);
1044 [ # # ]: 0 : if (ret <= 0)
1045 : 0 : return ret;
1046 : :
1047 : 0 : ret = sscanf(buf, "%llx %u", &mask, &log_level);
1048 : :
1049 [ # # ]: 0 : if (!ret)
1050 : : return -EINVAL;
1051 : :
1052 [ # # ]: 0 : if (ret == 1)
1053 : : /* default if user did not specify */
1054 : 0 : log_level = ATH10K_DBGLOG_LEVEL_WARN;
1055 : :
1056 : 0 : mutex_lock(&ar->conf_mutex);
1057 : :
1058 : 0 : ar->debug.fw_dbglog_mask = mask;
1059 : 0 : ar->debug.fw_dbglog_level = log_level;
1060 : :
1061 [ # # ]: 0 : if (ar->state == ATH10K_STATE_ON) {
1062 : 0 : ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask,
1063 : : ar->debug.fw_dbglog_level);
1064 [ # # ]: 0 : if (ret) {
1065 : 0 : ath10k_warn(ar, "dbglog cfg failed from debugfs: %d\n",
1066 : : ret);
1067 : 0 : goto exit;
1068 : : }
1069 : : }
1070 : :
1071 : 0 : ret = count;
1072 : :
1073 : 0 : exit:
1074 : 0 : mutex_unlock(&ar->conf_mutex);
1075 : :
1076 : 0 : return ret;
1077 : : }
1078 : :
1079 : : /* TODO: Would be nice to always support ethtool stats, would need to
1080 : : * move the stats storage out of ath10k_debug, or always have ath10k_debug
1081 : : * struct available..
1082 : : */
1083 : :
1084 : : /* This generally cooresponds to the debugfs fw_stats file */
1085 : : static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = {
1086 : : "tx_pkts_nic",
1087 : : "tx_bytes_nic",
1088 : : "rx_pkts_nic",
1089 : : "rx_bytes_nic",
1090 : : "d_noise_floor",
1091 : : "d_cycle_count",
1092 : : "d_phy_error",
1093 : : "d_rts_bad",
1094 : : "d_rts_good",
1095 : : "d_tx_power", /* in .5 dbM I think */
1096 : : "d_rx_crc_err", /* fcs_bad */
1097 : : "d_rx_crc_err_drop", /* frame with FCS error, dropped late in kernel */
1098 : : "d_no_beacon",
1099 : : "d_tx_mpdus_queued",
1100 : : "d_tx_msdu_queued",
1101 : : "d_tx_msdu_dropped",
1102 : : "d_local_enqued",
1103 : : "d_local_freed",
1104 : : "d_tx_ppdu_hw_queued",
1105 : : "d_tx_ppdu_reaped",
1106 : : "d_tx_fifo_underrun",
1107 : : "d_tx_ppdu_abort",
1108 : : "d_tx_mpdu_requed",
1109 : : "d_tx_excessive_retries",
1110 : : "d_tx_hw_rate",
1111 : : "d_tx_dropped_sw_retries",
1112 : : "d_tx_illegal_rate",
1113 : : "d_tx_continuous_xretries",
1114 : : "d_tx_timeout",
1115 : : "d_tx_mpdu_txop_limit",
1116 : : "d_pdev_resets",
1117 : : "d_rx_mid_ppdu_route_change",
1118 : : "d_rx_status",
1119 : : "d_rx_extra_frags_ring0",
1120 : : "d_rx_extra_frags_ring1",
1121 : : "d_rx_extra_frags_ring2",
1122 : : "d_rx_extra_frags_ring3",
1123 : : "d_rx_msdu_htt",
1124 : : "d_rx_mpdu_htt",
1125 : : "d_rx_msdu_stack",
1126 : : "d_rx_mpdu_stack",
1127 : : "d_rx_phy_err",
1128 : : "d_rx_phy_err_drops",
1129 : : "d_rx_mpdu_errors", /* FCS, MIC, ENC */
1130 : : "d_fw_crash_count",
1131 : : "d_fw_warm_reset_count",
1132 : : "d_fw_cold_reset_count",
1133 : : };
1134 : :
1135 : : #define ATH10K_SSTATS_LEN ARRAY_SIZE(ath10k_gstrings_stats)
1136 : :
1137 : 0 : void ath10k_debug_get_et_strings(struct ieee80211_hw *hw,
1138 : : struct ieee80211_vif *vif,
1139 : : u32 sset, u8 *data)
1140 : : {
1141 [ # # ]: 0 : if (sset == ETH_SS_STATS)
1142 : 0 : memcpy(data, *ath10k_gstrings_stats,
1143 : : sizeof(ath10k_gstrings_stats));
1144 : 0 : }
1145 : :
1146 : 0 : int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
1147 : : struct ieee80211_vif *vif, int sset)
1148 : : {
1149 [ # # ]: 0 : if (sset == ETH_SS_STATS)
1150 : 0 : return ATH10K_SSTATS_LEN;
1151 : :
1152 : : return 0;
1153 : : }
1154 : :
1155 : 0 : void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
1156 : : struct ieee80211_vif *vif,
1157 : : struct ethtool_stats *stats, u64 *data)
1158 : : {
1159 : 0 : struct ath10k *ar = hw->priv;
1160 : 0 : static const struct ath10k_fw_stats_pdev zero_stats = {};
1161 : 0 : const struct ath10k_fw_stats_pdev *pdev_stats;
1162 : 0 : int i = 0, ret;
1163 : :
1164 : 0 : mutex_lock(&ar->conf_mutex);
1165 : :
1166 [ # # ]: 0 : if (ar->state == ATH10K_STATE_ON) {
1167 : 0 : ret = ath10k_debug_fw_stats_request(ar);
1168 [ # # ]: 0 : if (ret) {
1169 : : /* just print a warning and try to use older results */
1170 : 0 : ath10k_warn(ar,
1171 : : "failed to get fw stats for ethtool: %d\n",
1172 : : ret);
1173 : : }
1174 : : }
1175 : :
1176 [ # # ]: 0 : pdev_stats = list_first_entry_or_null(&ar->debug.fw_stats.pdevs,
1177 : : struct ath10k_fw_stats_pdev,
1178 : : list);
1179 [ # # ]: 0 : if (!pdev_stats) {
1180 : : /* no results available so just return zeroes */
1181 : 0 : pdev_stats = &zero_stats;
1182 : : }
1183 : :
1184 : 0 : spin_lock_bh(&ar->data_lock);
1185 : :
1186 : 0 : data[i++] = pdev_stats->hw_reaped; /* ppdu reaped */
1187 : 0 : data[i++] = 0; /* tx bytes */
1188 : 0 : data[i++] = pdev_stats->htt_mpdus;
1189 : 0 : data[i++] = 0; /* rx bytes */
1190 : 0 : data[i++] = pdev_stats->ch_noise_floor;
1191 : 0 : data[i++] = pdev_stats->cycle_count;
1192 : 0 : data[i++] = pdev_stats->phy_err_count;
1193 : 0 : data[i++] = pdev_stats->rts_bad;
1194 : 0 : data[i++] = pdev_stats->rts_good;
1195 : 0 : data[i++] = pdev_stats->chan_tx_power;
1196 : 0 : data[i++] = pdev_stats->fcs_bad;
1197 : 0 : data[i++] = ar->stats.rx_crc_err_drop;
1198 : 0 : data[i++] = pdev_stats->no_beacons;
1199 : 0 : data[i++] = pdev_stats->mpdu_enqued;
1200 : 0 : data[i++] = pdev_stats->msdu_enqued;
1201 : 0 : data[i++] = pdev_stats->wmm_drop;
1202 : 0 : data[i++] = pdev_stats->local_enqued;
1203 : 0 : data[i++] = pdev_stats->local_freed;
1204 : 0 : data[i++] = pdev_stats->hw_queued;
1205 : 0 : data[i++] = pdev_stats->hw_reaped;
1206 : 0 : data[i++] = pdev_stats->underrun;
1207 : 0 : data[i++] = pdev_stats->tx_abort;
1208 : 0 : data[i++] = pdev_stats->mpdus_requed;
1209 : 0 : data[i++] = pdev_stats->tx_ko;
1210 : 0 : data[i++] = pdev_stats->data_rc;
1211 : 0 : data[i++] = pdev_stats->sw_retry_failure;
1212 : 0 : data[i++] = pdev_stats->illgl_rate_phy_err;
1213 : 0 : data[i++] = pdev_stats->pdev_cont_xretry;
1214 : 0 : data[i++] = pdev_stats->pdev_tx_timeout;
1215 : 0 : data[i++] = pdev_stats->txop_ovf;
1216 : 0 : data[i++] = pdev_stats->pdev_resets;
1217 : 0 : data[i++] = pdev_stats->mid_ppdu_route_change;
1218 : 0 : data[i++] = pdev_stats->status_rcvd;
1219 : 0 : data[i++] = pdev_stats->r0_frags;
1220 : 0 : data[i++] = pdev_stats->r1_frags;
1221 : 0 : data[i++] = pdev_stats->r2_frags;
1222 : 0 : data[i++] = pdev_stats->r3_frags;
1223 : 0 : data[i++] = pdev_stats->htt_msdus;
1224 : 0 : data[i++] = pdev_stats->htt_mpdus;
1225 : 0 : data[i++] = pdev_stats->loc_msdus;
1226 : 0 : data[i++] = pdev_stats->loc_mpdus;
1227 : 0 : data[i++] = pdev_stats->phy_errs;
1228 : 0 : data[i++] = pdev_stats->phy_err_drop;
1229 : 0 : data[i++] = pdev_stats->mpdu_errs;
1230 : 0 : data[i++] = ar->stats.fw_crash_counter;
1231 : 0 : data[i++] = ar->stats.fw_warm_reset_counter;
1232 : 0 : data[i++] = ar->stats.fw_cold_reset_counter;
1233 : :
1234 : 0 : spin_unlock_bh(&ar->data_lock);
1235 : :
1236 : 0 : mutex_unlock(&ar->conf_mutex);
1237 : :
1238 : 0 : WARN_ON(i != ATH10K_SSTATS_LEN);
1239 : 0 : }
1240 : :
1241 : : static const struct file_operations fops_fw_dbglog = {
1242 : : .read = ath10k_read_fw_dbglog,
1243 : : .write = ath10k_write_fw_dbglog,
1244 : : .open = simple_open,
1245 : : .owner = THIS_MODULE,
1246 : : .llseek = default_llseek,
1247 : : };
1248 : :
1249 : 0 : static int ath10k_debug_cal_data_fetch(struct ath10k *ar)
1250 : : {
1251 : 0 : u32 hi_addr;
1252 : 0 : __le32 addr;
1253 : 0 : int ret;
1254 : :
1255 : 0 : lockdep_assert_held(&ar->conf_mutex);
1256 : :
1257 [ # # # # ]: 0 : if (WARN_ON(ar->hw_params.cal_data_len > ATH10K_DEBUG_CAL_DATA_LEN))
1258 : : return -EINVAL;
1259 : :
1260 [ # # ]: 0 : if (ar->hw_params.cal_data_len == 0)
1261 : : return -EOPNOTSUPP;
1262 : :
1263 : 0 : hi_addr = host_interest_item_address(HI_ITEM(hi_board_data));
1264 : :
1265 : 0 : ret = ath10k_hif_diag_read(ar, hi_addr, &addr, sizeof(addr));
1266 [ # # ]: 0 : if (ret) {
1267 : 0 : ath10k_warn(ar, "failed to read hi_board_data address: %d\n",
1268 : : ret);
1269 : 0 : return ret;
1270 : : }
1271 : :
1272 : 0 : ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), ar->debug.cal_data,
1273 : 0 : ar->hw_params.cal_data_len);
1274 [ # # ]: 0 : if (ret) {
1275 : 0 : ath10k_warn(ar, "failed to read calibration data: %d\n", ret);
1276 : 0 : return ret;
1277 : : }
1278 : :
1279 : : return 0;
1280 : : }
1281 : :
1282 : 0 : static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file)
1283 : : {
1284 : 0 : struct ath10k *ar = inode->i_private;
1285 : :
1286 : 0 : mutex_lock(&ar->conf_mutex);
1287 : :
1288 [ # # # # ]: 0 : if (ar->state == ATH10K_STATE_ON ||
1289 : : ar->state == ATH10K_STATE_UTF) {
1290 : 0 : ath10k_debug_cal_data_fetch(ar);
1291 : : }
1292 : :
1293 : 0 : file->private_data = ar;
1294 : 0 : mutex_unlock(&ar->conf_mutex);
1295 : :
1296 : 0 : return 0;
1297 : : }
1298 : :
1299 : 0 : static ssize_t ath10k_debug_cal_data_read(struct file *file,
1300 : : char __user *user_buf,
1301 : : size_t count, loff_t *ppos)
1302 : : {
1303 : 0 : struct ath10k *ar = file->private_data;
1304 : :
1305 : 0 : mutex_lock(&ar->conf_mutex);
1306 : :
1307 : 0 : count = simple_read_from_buffer(user_buf, count, ppos,
1308 : 0 : ar->debug.cal_data,
1309 : 0 : ar->hw_params.cal_data_len);
1310 : :
1311 : 0 : mutex_unlock(&ar->conf_mutex);
1312 : :
1313 : 0 : return count;
1314 : : }
1315 : :
1316 : 0 : static ssize_t ath10k_write_ani_enable(struct file *file,
1317 : : const char __user *user_buf,
1318 : : size_t count, loff_t *ppos)
1319 : : {
1320 : 0 : struct ath10k *ar = file->private_data;
1321 : 0 : int ret;
1322 : 0 : u8 enable;
1323 : :
1324 [ # # ]: 0 : if (kstrtou8_from_user(user_buf, count, 0, &enable))
1325 : : return -EINVAL;
1326 : :
1327 : 0 : mutex_lock(&ar->conf_mutex);
1328 : :
1329 [ # # ]: 0 : if (ar->ani_enabled == enable) {
1330 : 0 : ret = count;
1331 : 0 : goto exit;
1332 : : }
1333 : :
1334 : 0 : ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->ani_enable,
1335 : : enable);
1336 [ # # ]: 0 : if (ret) {
1337 : 0 : ath10k_warn(ar, "ani_enable failed from debugfs: %d\n", ret);
1338 : 0 : goto exit;
1339 : : }
1340 : 0 : ar->ani_enabled = enable;
1341 : :
1342 : 0 : ret = count;
1343 : :
1344 : 0 : exit:
1345 : 0 : mutex_unlock(&ar->conf_mutex);
1346 : :
1347 : 0 : return ret;
1348 : : }
1349 : :
1350 : 0 : static ssize_t ath10k_read_ani_enable(struct file *file, char __user *user_buf,
1351 : : size_t count, loff_t *ppos)
1352 : : {
1353 : 0 : struct ath10k *ar = file->private_data;
1354 : 0 : size_t len;
1355 : 0 : char buf[32];
1356 : :
1357 : 0 : len = scnprintf(buf, sizeof(buf), "%d\n", ar->ani_enabled);
1358 : :
1359 : 0 : return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1360 : : }
1361 : :
1362 : : static const struct file_operations fops_ani_enable = {
1363 : : .read = ath10k_read_ani_enable,
1364 : : .write = ath10k_write_ani_enable,
1365 : : .open = simple_open,
1366 : : .owner = THIS_MODULE,
1367 : : .llseek = default_llseek,
1368 : : };
1369 : :
1370 : : static const struct file_operations fops_cal_data = {
1371 : : .open = ath10k_debug_cal_data_open,
1372 : : .read = ath10k_debug_cal_data_read,
1373 : : .owner = THIS_MODULE,
1374 : : .llseek = default_llseek,
1375 : : };
1376 : :
1377 : 0 : static ssize_t ath10k_read_nf_cal_period(struct file *file,
1378 : : char __user *user_buf,
1379 : : size_t count, loff_t *ppos)
1380 : : {
1381 : 0 : struct ath10k *ar = file->private_data;
1382 : 0 : size_t len;
1383 : 0 : char buf[32];
1384 : :
1385 : 0 : len = scnprintf(buf, sizeof(buf), "%d\n", ar->debug.nf_cal_period);
1386 : :
1387 : 0 : return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1388 : : }
1389 : :
1390 : 0 : static ssize_t ath10k_write_nf_cal_period(struct file *file,
1391 : : const char __user *user_buf,
1392 : : size_t count, loff_t *ppos)
1393 : : {
1394 : 0 : struct ath10k *ar = file->private_data;
1395 : 0 : unsigned long period;
1396 : 0 : int ret;
1397 : :
1398 : 0 : ret = kstrtoul_from_user(user_buf, count, 0, &period);
1399 [ # # ]: 0 : if (ret)
1400 : 0 : return ret;
1401 : :
1402 [ # # ]: 0 : if (period > WMI_PDEV_PARAM_CAL_PERIOD_MAX)
1403 : : return -EINVAL;
1404 : :
1405 : : /* there's no way to switch back to the firmware default */
1406 [ # # ]: 0 : if (period == 0)
1407 : : return -EINVAL;
1408 : :
1409 : 0 : mutex_lock(&ar->conf_mutex);
1410 : :
1411 : 0 : ar->debug.nf_cal_period = period;
1412 : :
1413 [ # # ]: 0 : if (ar->state != ATH10K_STATE_ON) {
1414 : : /* firmware is not running, nothing else to do */
1415 : 0 : ret = count;
1416 : 0 : goto exit;
1417 : : }
1418 : :
1419 : 0 : ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->cal_period,
1420 : : ar->debug.nf_cal_period);
1421 [ # # ]: 0 : if (ret) {
1422 : 0 : ath10k_warn(ar, "cal period cfg failed from debugfs: %d\n",
1423 : : ret);
1424 : 0 : goto exit;
1425 : : }
1426 : :
1427 : 0 : ret = count;
1428 : :
1429 : 0 : exit:
1430 : 0 : mutex_unlock(&ar->conf_mutex);
1431 : :
1432 : 0 : return ret;
1433 : : }
1434 : :
1435 : : static const struct file_operations fops_nf_cal_period = {
1436 : : .read = ath10k_read_nf_cal_period,
1437 : : .write = ath10k_write_nf_cal_period,
1438 : : .open = simple_open,
1439 : : .owner = THIS_MODULE,
1440 : : .llseek = default_llseek,
1441 : : };
1442 : :
1443 : : #define ATH10K_TPC_CONFIG_BUF_SIZE (1024 * 1024)
1444 : :
1445 : 0 : static int ath10k_debug_tpc_stats_request(struct ath10k *ar)
1446 : : {
1447 : 0 : int ret;
1448 : 0 : unsigned long time_left;
1449 : :
1450 : 0 : lockdep_assert_held(&ar->conf_mutex);
1451 : :
1452 : 0 : reinit_completion(&ar->debug.tpc_complete);
1453 : :
1454 : 0 : ret = ath10k_wmi_pdev_get_tpc_config(ar, WMI_TPC_CONFIG_PARAM);
1455 [ # # ]: 0 : if (ret) {
1456 : 0 : ath10k_warn(ar, "failed to request tpc config: %d\n", ret);
1457 : 0 : return ret;
1458 : : }
1459 : :
1460 : 0 : time_left = wait_for_completion_timeout(&ar->debug.tpc_complete,
1461 : : 1 * HZ);
1462 [ # # ]: 0 : if (time_left == 0)
1463 : 0 : return -ETIMEDOUT;
1464 : :
1465 : : return 0;
1466 : : }
1467 : :
1468 : 0 : void ath10k_debug_tpc_stats_process(struct ath10k *ar,
1469 : : struct ath10k_tpc_stats *tpc_stats)
1470 : : {
1471 : 0 : spin_lock_bh(&ar->data_lock);
1472 : :
1473 : 0 : kfree(ar->debug.tpc_stats);
1474 : 0 : ar->debug.tpc_stats = tpc_stats;
1475 : 0 : complete(&ar->debug.tpc_complete);
1476 : :
1477 : 0 : spin_unlock_bh(&ar->data_lock);
1478 : 0 : }
1479 : :
1480 : : void
1481 : 0 : ath10k_debug_tpc_stats_final_process(struct ath10k *ar,
1482 : : struct ath10k_tpc_stats_final *tpc_stats)
1483 : : {
1484 : 0 : spin_lock_bh(&ar->data_lock);
1485 : :
1486 : 0 : kfree(ar->debug.tpc_stats_final);
1487 : 0 : ar->debug.tpc_stats_final = tpc_stats;
1488 : 0 : complete(&ar->debug.tpc_complete);
1489 : :
1490 : 0 : spin_unlock_bh(&ar->data_lock);
1491 : 0 : }
1492 : :
1493 : 0 : static void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats,
1494 : : unsigned int j, char *buf, size_t *len)
1495 : : {
1496 : 0 : int i;
1497 : 0 : size_t buf_len;
1498 : 0 : static const char table_str[][5] = { "CDD",
1499 : : "STBC",
1500 : : "TXBF" };
1501 : 0 : static const char pream_str[][6] = { "CCK",
1502 : : "OFDM",
1503 : : "HT20",
1504 : : "HT40",
1505 : : "VHT20",
1506 : : "VHT40",
1507 : : "VHT80",
1508 : : "HTCUP" };
1509 : :
1510 : 0 : buf_len = ATH10K_TPC_CONFIG_BUF_SIZE;
1511 : 0 : *len += scnprintf(buf + *len, buf_len - *len,
1512 : : "********************************\n");
1513 : 0 : *len += scnprintf(buf + *len, buf_len - *len,
1514 : : "******************* %s POWER TABLE ****************\n",
1515 : 0 : table_str[j]);
1516 : 0 : *len += scnprintf(buf + *len, buf_len - *len,
1517 : : "********************************\n");
1518 : 0 : *len += scnprintf(buf + *len, buf_len - *len,
1519 : : "No. Preamble Rate_code ");
1520 : :
1521 [ # # ]: 0 : for (i = 0; i < tpc_stats->num_tx_chain; i++)
1522 : 0 : *len += scnprintf(buf + *len, buf_len - *len,
1523 : : "tpc_value%d ", i);
1524 : :
1525 : 0 : *len += scnprintf(buf + *len, buf_len - *len, "\n");
1526 : :
1527 [ # # ]: 0 : for (i = 0; i < tpc_stats->rate_max; i++) {
1528 : 0 : *len += scnprintf(buf + *len, buf_len - *len,
1529 : : "%8d %s 0x%2x %s\n", i,
1530 : 0 : pream_str[tpc_stats->tpc_table[j].pream_idx[i]],
1531 : 0 : tpc_stats->tpc_table[j].rate_code[i],
1532 : 0 : tpc_stats->tpc_table[j].tpc_value[i]);
1533 : : }
1534 : :
1535 : 0 : *len += scnprintf(buf + *len, buf_len - *len,
1536 : : "***********************************\n");
1537 : 0 : }
1538 : :
1539 : 0 : static void ath10k_tpc_stats_fill(struct ath10k *ar,
1540 : : struct ath10k_tpc_stats *tpc_stats,
1541 : : char *buf)
1542 : : {
1543 : 0 : int j;
1544 : 0 : size_t len, buf_len;
1545 : :
1546 : 0 : len = 0;
1547 : 0 : buf_len = ATH10K_TPC_CONFIG_BUF_SIZE;
1548 : :
1549 : 0 : spin_lock_bh(&ar->data_lock);
1550 : :
1551 [ # # ]: 0 : if (!tpc_stats) {
1552 : 0 : ath10k_warn(ar, "failed to get tpc stats\n");
1553 : 0 : goto unlock;
1554 : : }
1555 : :
1556 : 0 : len += scnprintf(buf + len, buf_len - len, "\n");
1557 : 0 : len += scnprintf(buf + len, buf_len - len,
1558 : : "*************************************\n");
1559 : 0 : len += scnprintf(buf + len, buf_len - len,
1560 : : "TPC config for channel %4d mode %d\n",
1561 : : tpc_stats->chan_freq,
1562 : : tpc_stats->phy_mode);
1563 : 0 : len += scnprintf(buf + len, buf_len - len,
1564 : : "*************************************\n");
1565 : 0 : len += scnprintf(buf + len, buf_len - len,
1566 : : "CTL = 0x%2x Reg. Domain = %2d\n",
1567 : : tpc_stats->ctl,
1568 : : tpc_stats->reg_domain);
1569 : 0 : len += scnprintf(buf + len, buf_len - len,
1570 : : "Antenna Gain = %2d Reg. Max Antenna Gain = %2d\n",
1571 : : tpc_stats->twice_antenna_gain,
1572 : : tpc_stats->twice_antenna_reduction);
1573 : 0 : len += scnprintf(buf + len, buf_len - len,
1574 : : "Power Limit = %2d Reg. Max Power = %2d\n",
1575 : : tpc_stats->power_limit,
1576 : 0 : tpc_stats->twice_max_rd_power / 2);
1577 : 0 : len += scnprintf(buf + len, buf_len - len,
1578 : : "Num tx chains = %2d Num supported rates = %2d\n",
1579 : : tpc_stats->num_tx_chain,
1580 : : tpc_stats->rate_max);
1581 : :
1582 [ # # ]: 0 : for (j = 0; j < WMI_TPC_FLAG; j++) {
1583 [ # # # ]: 0 : switch (j) {
1584 : 0 : case WMI_TPC_TABLE_TYPE_CDD:
1585 [ # # ]: 0 : if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) {
1586 : 0 : len += scnprintf(buf + len, buf_len - len,
1587 : : "CDD not supported\n");
1588 : 0 : break;
1589 : : }
1590 : :
1591 : 0 : ath10k_tpc_stats_print(tpc_stats, j, buf, &len);
1592 : 0 : break;
1593 : 0 : case WMI_TPC_TABLE_TYPE_STBC:
1594 [ # # ]: 0 : if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) {
1595 : 0 : len += scnprintf(buf + len, buf_len - len,
1596 : : "STBC not supported\n");
1597 : 0 : break;
1598 : : }
1599 : :
1600 : 0 : ath10k_tpc_stats_print(tpc_stats, j, buf, &len);
1601 : 0 : break;
1602 : 0 : case WMI_TPC_TABLE_TYPE_TXBF:
1603 [ # # ]: 0 : if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) {
1604 : 0 : len += scnprintf(buf + len, buf_len - len,
1605 : : "TXBF not supported\n***************************\n");
1606 : 0 : break;
1607 : : }
1608 : :
1609 : 0 : ath10k_tpc_stats_print(tpc_stats, j, buf, &len);
1610 : 0 : break;
1611 : : default:
1612 : : len += scnprintf(buf + len, buf_len - len,
1613 : : "Invalid Type\n");
1614 : : break;
1615 : : }
1616 : : }
1617 : :
1618 : 0 : unlock:
1619 : 0 : spin_unlock_bh(&ar->data_lock);
1620 : :
1621 [ # # ]: 0 : if (len >= buf_len)
1622 : 0 : buf[len - 1] = 0;
1623 : : else
1624 : 0 : buf[len] = 0;
1625 : 0 : }
1626 : :
1627 : 0 : static int ath10k_tpc_stats_open(struct inode *inode, struct file *file)
1628 : : {
1629 : 0 : struct ath10k *ar = inode->i_private;
1630 : 0 : void *buf = NULL;
1631 : 0 : int ret;
1632 : :
1633 : 0 : mutex_lock(&ar->conf_mutex);
1634 : :
1635 [ # # ]: 0 : if (ar->state != ATH10K_STATE_ON) {
1636 : 0 : ret = -ENETDOWN;
1637 : 0 : goto err_unlock;
1638 : : }
1639 : :
1640 : 0 : buf = vmalloc(ATH10K_TPC_CONFIG_BUF_SIZE);
1641 [ # # ]: 0 : if (!buf) {
1642 : 0 : ret = -ENOMEM;
1643 : 0 : goto err_unlock;
1644 : : }
1645 : :
1646 : 0 : ret = ath10k_debug_tpc_stats_request(ar);
1647 [ # # ]: 0 : if (ret) {
1648 : 0 : ath10k_warn(ar, "failed to request tpc config stats: %d\n",
1649 : : ret);
1650 : 0 : goto err_free;
1651 : : }
1652 : :
1653 : 0 : ath10k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf);
1654 : 0 : file->private_data = buf;
1655 : :
1656 : 0 : mutex_unlock(&ar->conf_mutex);
1657 : 0 : return 0;
1658 : :
1659 : : err_free:
1660 : 0 : vfree(buf);
1661 : :
1662 : 0 : err_unlock:
1663 : 0 : mutex_unlock(&ar->conf_mutex);
1664 : 0 : return ret;
1665 : : }
1666 : :
1667 : 0 : static int ath10k_tpc_stats_release(struct inode *inode, struct file *file)
1668 : : {
1669 : 0 : vfree(file->private_data);
1670 : :
1671 : 0 : return 0;
1672 : : }
1673 : :
1674 : 0 : static ssize_t ath10k_tpc_stats_read(struct file *file, char __user *user_buf,
1675 : : size_t count, loff_t *ppos)
1676 : : {
1677 : 0 : const char *buf = file->private_data;
1678 : 0 : size_t len = strlen(buf);
1679 : :
1680 : 0 : return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1681 : : }
1682 : :
1683 : : static const struct file_operations fops_tpc_stats = {
1684 : : .open = ath10k_tpc_stats_open,
1685 : : .release = ath10k_tpc_stats_release,
1686 : : .read = ath10k_tpc_stats_read,
1687 : : .owner = THIS_MODULE,
1688 : : .llseek = default_llseek,
1689 : : };
1690 : :
1691 : 0 : int ath10k_debug_start(struct ath10k *ar)
1692 : : {
1693 : 0 : int ret;
1694 : :
1695 : 0 : lockdep_assert_held(&ar->conf_mutex);
1696 : :
1697 : 0 : ret = ath10k_debug_htt_stats_req(ar);
1698 [ # # ]: 0 : if (ret)
1699 : : /* continue normally anyway, this isn't serious */
1700 : 0 : ath10k_warn(ar, "failed to start htt stats workqueue: %d\n",
1701 : : ret);
1702 : :
1703 [ # # ]: 0 : if (ar->debug.fw_dbglog_mask) {
1704 : 0 : ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask,
1705 : : ATH10K_DBGLOG_LEVEL_WARN);
1706 [ # # ]: 0 : if (ret)
1707 : : /* not serious */
1708 : 0 : ath10k_warn(ar, "failed to enable dbglog during start: %d",
1709 : : ret);
1710 : : }
1711 : :
1712 [ # # ]: 0 : if (ar->pktlog_filter) {
1713 : 0 : ret = ath10k_wmi_pdev_pktlog_enable(ar,
1714 : : ar->pktlog_filter);
1715 [ # # ]: 0 : if (ret)
1716 : : /* not serious */
1717 : 0 : ath10k_warn(ar,
1718 : : "failed to enable pktlog filter %x: %d\n",
1719 : : ar->pktlog_filter, ret);
1720 : : } else {
1721 : 0 : ret = ath10k_wmi_pdev_pktlog_disable(ar);
1722 [ # # ]: 0 : if (ret)
1723 : : /* not serious */
1724 : 0 : ath10k_warn(ar, "failed to disable pktlog: %d\n", ret);
1725 : : }
1726 : :
1727 [ # # # # ]: 0 : if (ar->debug.nf_cal_period &&
1728 : : !test_bit(ATH10K_FW_FEATURE_NON_BMI,
1729 : 0 : ar->normal_mode_fw.fw_file.fw_features)) {
1730 : 0 : ret = ath10k_wmi_pdev_set_param(ar,
1731 : 0 : ar->wmi.pdev_param->cal_period,
1732 : : ar->debug.nf_cal_period);
1733 [ # # ]: 0 : if (ret)
1734 : : /* not serious */
1735 : 0 : ath10k_warn(ar, "cal period cfg failed from debug start: %d\n",
1736 : : ret);
1737 : : }
1738 : :
1739 : 0 : return ret;
1740 : : }
1741 : :
1742 : 0 : void ath10k_debug_stop(struct ath10k *ar)
1743 : : {
1744 : 0 : lockdep_assert_held(&ar->conf_mutex);
1745 : :
1746 [ # # ]: 0 : if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,
1747 : 0 : ar->normal_mode_fw.fw_file.fw_features))
1748 : 0 : ath10k_debug_cal_data_fetch(ar);
1749 : :
1750 : : /* Must not use _sync to avoid deadlock, we do that in
1751 : : * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid
1752 : : * warning from del_timer().
1753 : : */
1754 [ # # ]: 0 : if (ar->debug.htt_stats_mask != 0)
1755 : 0 : cancel_delayed_work(&ar->debug.htt_stats_dwork);
1756 : :
1757 : 0 : ath10k_wmi_pdev_pktlog_disable(ar);
1758 : 0 : }
1759 : :
1760 : : static ssize_t ath10k_write_simulate_radar(struct file *file,
1761 : : const char __user *user_buf,
1762 : : size_t count, loff_t *ppos)
1763 : : {
1764 : : struct ath10k *ar = file->private_data;
1765 : : struct ath10k_vif *arvif;
1766 : :
1767 : : /* Just check for for the first vif alone, as all the vifs will be
1768 : : * sharing the same channel and if the channel is disabled, all the
1769 : : * vifs will share the same 'is_started' state.
1770 : : */
1771 : : arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list);
1772 : : if (!arvif->is_started)
1773 : : return -EINVAL;
1774 : :
1775 : : ieee80211_radar_detected(ar->hw);
1776 : :
1777 : : return count;
1778 : : }
1779 : :
1780 : : static const struct file_operations fops_simulate_radar = {
1781 : : .write = ath10k_write_simulate_radar,
1782 : : .open = simple_open,
1783 : : .owner = THIS_MODULE,
1784 : : .llseek = default_llseek,
1785 : : };
1786 : :
1787 : : #define ATH10K_DFS_STAT(s, p) (\
1788 : : len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \
1789 : : ar->debug.dfs_stats.p))
1790 : :
1791 : : #define ATH10K_DFS_POOL_STAT(s, p) (\
1792 : : len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \
1793 : : ar->debug.dfs_pool_stats.p))
1794 : :
1795 : : static ssize_t ath10k_read_dfs_stats(struct file *file, char __user *user_buf,
1796 : : size_t count, loff_t *ppos)
1797 : : {
1798 : : int retval = 0, len = 0;
1799 : : const int size = 8000;
1800 : : struct ath10k *ar = file->private_data;
1801 : : char *buf;
1802 : :
1803 : : buf = kzalloc(size, GFP_KERNEL);
1804 : : if (buf == NULL)
1805 : : return -ENOMEM;
1806 : :
1807 : : if (!ar->dfs_detector) {
1808 : : len += scnprintf(buf + len, size - len, "DFS not enabled\n");
1809 : : goto exit;
1810 : : }
1811 : :
1812 : : ar->debug.dfs_pool_stats =
1813 : : ar->dfs_detector->get_stats(ar->dfs_detector);
1814 : :
1815 : : len += scnprintf(buf + len, size - len, "Pulse detector statistics:\n");
1816 : :
1817 : : ATH10K_DFS_STAT("reported phy errors", phy_errors);
1818 : : ATH10K_DFS_STAT("pulse events reported", pulses_total);
1819 : : ATH10K_DFS_STAT("DFS pulses detected", pulses_detected);
1820 : : ATH10K_DFS_STAT("DFS pulses discarded", pulses_discarded);
1821 : : ATH10K_DFS_STAT("Radars detected", radar_detected);
1822 : :
1823 : : len += scnprintf(buf + len, size - len, "Global Pool statistics:\n");
1824 : : ATH10K_DFS_POOL_STAT("Pool references", pool_reference);
1825 : : ATH10K_DFS_POOL_STAT("Pulses allocated", pulse_allocated);
1826 : : ATH10K_DFS_POOL_STAT("Pulses alloc error", pulse_alloc_error);
1827 : : ATH10K_DFS_POOL_STAT("Pulses in use", pulse_used);
1828 : : ATH10K_DFS_POOL_STAT("Seqs. allocated", pseq_allocated);
1829 : : ATH10K_DFS_POOL_STAT("Seqs. alloc error", pseq_alloc_error);
1830 : : ATH10K_DFS_POOL_STAT("Seqs. in use", pseq_used);
1831 : :
1832 : : exit:
1833 : : if (len > size)
1834 : : len = size;
1835 : :
1836 : : retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
1837 : : kfree(buf);
1838 : :
1839 : : return retval;
1840 : : }
1841 : :
1842 : : static const struct file_operations fops_dfs_stats = {
1843 : : .read = ath10k_read_dfs_stats,
1844 : : .open = simple_open,
1845 : : .owner = THIS_MODULE,
1846 : : .llseek = default_llseek,
1847 : : };
1848 : :
1849 : 0 : static ssize_t ath10k_write_pktlog_filter(struct file *file,
1850 : : const char __user *ubuf,
1851 : : size_t count, loff_t *ppos)
1852 : : {
1853 : 0 : struct ath10k *ar = file->private_data;
1854 : 0 : u32 filter;
1855 : 0 : int ret;
1856 : :
1857 [ # # ]: 0 : if (kstrtouint_from_user(ubuf, count, 0, &filter))
1858 : : return -EINVAL;
1859 : :
1860 : 0 : mutex_lock(&ar->conf_mutex);
1861 : :
1862 [ # # ]: 0 : if (ar->state != ATH10K_STATE_ON) {
1863 : 0 : ar->pktlog_filter = filter;
1864 : 0 : ret = count;
1865 : 0 : goto out;
1866 : : }
1867 : :
1868 [ # # ]: 0 : if (filter == ar->pktlog_filter) {
1869 : 0 : ret = count;
1870 : 0 : goto out;
1871 : : }
1872 : :
1873 [ # # ]: 0 : if (filter) {
1874 : 0 : ret = ath10k_wmi_pdev_pktlog_enable(ar, filter);
1875 [ # # ]: 0 : if (ret) {
1876 : 0 : ath10k_warn(ar, "failed to enable pktlog filter %x: %d\n",
1877 : : ar->pktlog_filter, ret);
1878 : 0 : goto out;
1879 : : }
1880 : : } else {
1881 : 0 : ret = ath10k_wmi_pdev_pktlog_disable(ar);
1882 [ # # ]: 0 : if (ret) {
1883 : 0 : ath10k_warn(ar, "failed to disable pktlog: %d\n", ret);
1884 : 0 : goto out;
1885 : : }
1886 : : }
1887 : :
1888 : 0 : ar->pktlog_filter = filter;
1889 : 0 : ret = count;
1890 : :
1891 : 0 : out:
1892 : 0 : mutex_unlock(&ar->conf_mutex);
1893 : 0 : return ret;
1894 : : }
1895 : :
1896 : 0 : static ssize_t ath10k_read_pktlog_filter(struct file *file, char __user *ubuf,
1897 : : size_t count, loff_t *ppos)
1898 : : {
1899 : 0 : char buf[32];
1900 : 0 : struct ath10k *ar = file->private_data;
1901 : 0 : int len = 0;
1902 : :
1903 : 0 : mutex_lock(&ar->conf_mutex);
1904 : 0 : len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
1905 : : ar->pktlog_filter);
1906 : 0 : mutex_unlock(&ar->conf_mutex);
1907 : :
1908 : 0 : return simple_read_from_buffer(ubuf, count, ppos, buf, len);
1909 : : }
1910 : :
1911 : : static const struct file_operations fops_pktlog_filter = {
1912 : : .read = ath10k_read_pktlog_filter,
1913 : : .write = ath10k_write_pktlog_filter,
1914 : : .open = simple_open
1915 : : };
1916 : :
1917 : 0 : static ssize_t ath10k_write_quiet_period(struct file *file,
1918 : : const char __user *ubuf,
1919 : : size_t count, loff_t *ppos)
1920 : : {
1921 : 0 : struct ath10k *ar = file->private_data;
1922 : 0 : u32 period;
1923 : :
1924 [ # # ]: 0 : if (kstrtouint_from_user(ubuf, count, 0, &period))
1925 : : return -EINVAL;
1926 : :
1927 [ # # ]: 0 : if (period < ATH10K_QUIET_PERIOD_MIN) {
1928 : 0 : ath10k_warn(ar, "Quiet period %u can not be lesser than 25ms\n",
1929 : : period);
1930 : 0 : return -EINVAL;
1931 : : }
1932 : 0 : mutex_lock(&ar->conf_mutex);
1933 : 0 : ar->thermal.quiet_period = period;
1934 : 0 : ath10k_thermal_set_throttling(ar);
1935 : 0 : mutex_unlock(&ar->conf_mutex);
1936 : :
1937 : 0 : return count;
1938 : : }
1939 : :
1940 : 0 : static ssize_t ath10k_read_quiet_period(struct file *file, char __user *ubuf,
1941 : : size_t count, loff_t *ppos)
1942 : : {
1943 : 0 : char buf[32];
1944 : 0 : struct ath10k *ar = file->private_data;
1945 : 0 : int len = 0;
1946 : :
1947 : 0 : mutex_lock(&ar->conf_mutex);
1948 : 0 : len = scnprintf(buf, sizeof(buf) - len, "%d\n",
1949 : : ar->thermal.quiet_period);
1950 : 0 : mutex_unlock(&ar->conf_mutex);
1951 : :
1952 : 0 : return simple_read_from_buffer(ubuf, count, ppos, buf, len);
1953 : : }
1954 : :
1955 : : static const struct file_operations fops_quiet_period = {
1956 : : .read = ath10k_read_quiet_period,
1957 : : .write = ath10k_write_quiet_period,
1958 : : .open = simple_open
1959 : : };
1960 : :
1961 : 0 : static ssize_t ath10k_write_btcoex(struct file *file,
1962 : : const char __user *ubuf,
1963 : : size_t count, loff_t *ppos)
1964 : : {
1965 : 0 : struct ath10k *ar = file->private_data;
1966 : 0 : char buf[32];
1967 : 0 : size_t buf_size;
1968 : 0 : int ret;
1969 : 0 : bool val;
1970 : 0 : u32 pdev_param;
1971 : :
1972 : 0 : buf_size = min(count, (sizeof(buf) - 1));
1973 [ # # ]: 0 : if (copy_from_user(buf, ubuf, buf_size))
1974 : : return -EFAULT;
1975 : :
1976 : 0 : buf[buf_size] = '\0';
1977 : :
1978 [ # # ]: 0 : if (strtobool(buf, &val) != 0)
1979 : : return -EINVAL;
1980 : :
1981 : 0 : mutex_lock(&ar->conf_mutex);
1982 : :
1983 [ # # # # ]: 0 : if (ar->state != ATH10K_STATE_ON &&
1984 : : ar->state != ATH10K_STATE_RESTARTED) {
1985 : 0 : ret = -ENETDOWN;
1986 : 0 : goto exit;
1987 : : }
1988 : :
1989 [ # # ]: 0 : if (!(test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags) ^ val)) {
1990 : 0 : ret = count;
1991 : 0 : goto exit;
1992 : : }
1993 : :
1994 : 0 : pdev_param = ar->wmi.pdev_param->enable_btcoex;
1995 [ # # ]: 0 : if (test_bit(ATH10K_FW_FEATURE_BTCOEX_PARAM,
1996 : 0 : ar->running_fw->fw_file.fw_features)) {
1997 : 0 : ret = ath10k_wmi_pdev_set_param(ar, pdev_param, val);
1998 [ # # ]: 0 : if (ret) {
1999 : 0 : ath10k_warn(ar, "failed to enable btcoex: %d\n", ret);
2000 : 0 : ret = count;
2001 : 0 : goto exit;
2002 : : }
2003 : : } else {
2004 : 0 : ath10k_info(ar, "restarting firmware due to btcoex change");
2005 : 0 : queue_work(ar->workqueue, &ar->restart_work);
2006 : : }
2007 : :
2008 [ # # ]: 0 : if (val)
2009 : 0 : set_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags);
2010 : : else
2011 : 0 : clear_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags);
2012 : :
2013 : 0 : ret = count;
2014 : :
2015 : 0 : exit:
2016 : 0 : mutex_unlock(&ar->conf_mutex);
2017 : :
2018 : 0 : return ret;
2019 : : }
2020 : :
2021 : 0 : static ssize_t ath10k_read_btcoex(struct file *file, char __user *ubuf,
2022 : : size_t count, loff_t *ppos)
2023 : : {
2024 : 0 : char buf[32];
2025 : 0 : struct ath10k *ar = file->private_data;
2026 : 0 : int len = 0;
2027 : :
2028 : 0 : mutex_lock(&ar->conf_mutex);
2029 : 0 : len = scnprintf(buf, sizeof(buf) - len, "%d\n",
2030 : 0 : test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags));
2031 : 0 : mutex_unlock(&ar->conf_mutex);
2032 : :
2033 : 0 : return simple_read_from_buffer(ubuf, count, ppos, buf, len);
2034 : : }
2035 : :
2036 : : static const struct file_operations fops_btcoex = {
2037 : : .read = ath10k_read_btcoex,
2038 : : .write = ath10k_write_btcoex,
2039 : : .open = simple_open
2040 : : };
2041 : :
2042 : 0 : static ssize_t ath10k_write_enable_extd_tx_stats(struct file *file,
2043 : : const char __user *ubuf,
2044 : : size_t count, loff_t *ppos)
2045 : : {
2046 : 0 : struct ath10k *ar = file->private_data;
2047 : 0 : u32 filter;
2048 : 0 : int ret;
2049 : :
2050 [ # # ]: 0 : if (kstrtouint_from_user(ubuf, count, 0, &filter))
2051 : : return -EINVAL;
2052 : :
2053 : 0 : mutex_lock(&ar->conf_mutex);
2054 : :
2055 [ # # ]: 0 : if (ar->state != ATH10K_STATE_ON) {
2056 : 0 : ar->debug.enable_extd_tx_stats = filter;
2057 : 0 : ret = count;
2058 : 0 : goto out;
2059 : : }
2060 : :
2061 [ # # ]: 0 : if (filter == ar->debug.enable_extd_tx_stats) {
2062 : 0 : ret = count;
2063 : 0 : goto out;
2064 : : }
2065 : :
2066 : 0 : ar->debug.enable_extd_tx_stats = filter;
2067 : 0 : ret = count;
2068 : :
2069 : 0 : out:
2070 : 0 : mutex_unlock(&ar->conf_mutex);
2071 : 0 : return ret;
2072 : : }
2073 : :
2074 : 0 : static ssize_t ath10k_read_enable_extd_tx_stats(struct file *file,
2075 : : char __user *ubuf,
2076 : : size_t count, loff_t *ppos)
2077 : :
2078 : : {
2079 : 0 : char buf[32];
2080 : 0 : struct ath10k *ar = file->private_data;
2081 : 0 : int len = 0;
2082 : :
2083 : 0 : mutex_lock(&ar->conf_mutex);
2084 : 0 : len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
2085 : : ar->debug.enable_extd_tx_stats);
2086 : 0 : mutex_unlock(&ar->conf_mutex);
2087 : :
2088 : 0 : return simple_read_from_buffer(ubuf, count, ppos, buf, len);
2089 : : }
2090 : :
2091 : : static const struct file_operations fops_enable_extd_tx_stats = {
2092 : : .read = ath10k_read_enable_extd_tx_stats,
2093 : : .write = ath10k_write_enable_extd_tx_stats,
2094 : : .open = simple_open
2095 : : };
2096 : :
2097 : 0 : static ssize_t ath10k_write_peer_stats(struct file *file,
2098 : : const char __user *ubuf,
2099 : : size_t count, loff_t *ppos)
2100 : : {
2101 : 0 : struct ath10k *ar = file->private_data;
2102 : 0 : char buf[32];
2103 : 0 : size_t buf_size;
2104 : 0 : int ret;
2105 : 0 : bool val;
2106 : :
2107 : 0 : buf_size = min(count, (sizeof(buf) - 1));
2108 [ # # ]: 0 : if (copy_from_user(buf, ubuf, buf_size))
2109 : : return -EFAULT;
2110 : :
2111 : 0 : buf[buf_size] = '\0';
2112 : :
2113 [ # # ]: 0 : if (strtobool(buf, &val) != 0)
2114 : : return -EINVAL;
2115 : :
2116 : 0 : mutex_lock(&ar->conf_mutex);
2117 : :
2118 [ # # # # ]: 0 : if (ar->state != ATH10K_STATE_ON &&
2119 : : ar->state != ATH10K_STATE_RESTARTED) {
2120 : 0 : ret = -ENETDOWN;
2121 : 0 : goto exit;
2122 : : }
2123 : :
2124 [ # # ]: 0 : if (!(test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags) ^ val)) {
2125 : 0 : ret = count;
2126 : 0 : goto exit;
2127 : : }
2128 : :
2129 [ # # ]: 0 : if (val)
2130 : 0 : set_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags);
2131 : : else
2132 : 0 : clear_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags);
2133 : :
2134 : 0 : ath10k_info(ar, "restarting firmware due to Peer stats change");
2135 : :
2136 : 0 : queue_work(ar->workqueue, &ar->restart_work);
2137 : 0 : ret = count;
2138 : :
2139 : 0 : exit:
2140 : 0 : mutex_unlock(&ar->conf_mutex);
2141 : 0 : return ret;
2142 : : }
2143 : :
2144 : 0 : static ssize_t ath10k_read_peer_stats(struct file *file, char __user *ubuf,
2145 : : size_t count, loff_t *ppos)
2146 : :
2147 : : {
2148 : 0 : char buf[32];
2149 : 0 : struct ath10k *ar = file->private_data;
2150 : 0 : int len = 0;
2151 : :
2152 : 0 : mutex_lock(&ar->conf_mutex);
2153 : 0 : len = scnprintf(buf, sizeof(buf) - len, "%d\n",
2154 : 0 : test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags));
2155 : 0 : mutex_unlock(&ar->conf_mutex);
2156 : :
2157 : 0 : return simple_read_from_buffer(ubuf, count, ppos, buf, len);
2158 : : }
2159 : :
2160 : : static const struct file_operations fops_peer_stats = {
2161 : : .read = ath10k_read_peer_stats,
2162 : : .write = ath10k_write_peer_stats,
2163 : : .open = simple_open
2164 : : };
2165 : :
2166 : 0 : static ssize_t ath10k_debug_fw_checksums_read(struct file *file,
2167 : : char __user *user_buf,
2168 : : size_t count, loff_t *ppos)
2169 : : {
2170 : 0 : struct ath10k *ar = file->private_data;
2171 : 0 : size_t len = 0, buf_len = 4096;
2172 : 0 : ssize_t ret_cnt;
2173 : 0 : char *buf;
2174 : :
2175 : 0 : buf = kzalloc(buf_len, GFP_KERNEL);
2176 [ # # ]: 0 : if (!buf)
2177 : : return -ENOMEM;
2178 : :
2179 : 0 : mutex_lock(&ar->conf_mutex);
2180 : :
2181 : 0 : len += scnprintf(buf + len, buf_len - len,
2182 : : "firmware-N.bin\t\t%08x\n",
2183 : 0 : crc32_le(0, ar->normal_mode_fw.fw_file.firmware->data,
2184 : 0 : ar->normal_mode_fw.fw_file.firmware->size));
2185 : 0 : len += scnprintf(buf + len, buf_len - len,
2186 : : "athwlan\t\t\t%08x\n",
2187 : 0 : crc32_le(0, ar->normal_mode_fw.fw_file.firmware_data,
2188 : : ar->normal_mode_fw.fw_file.firmware_len));
2189 : 0 : len += scnprintf(buf + len, buf_len - len,
2190 : : "otp\t\t\t%08x\n",
2191 : 0 : crc32_le(0, ar->normal_mode_fw.fw_file.otp_data,
2192 : : ar->normal_mode_fw.fw_file.otp_len));
2193 : 0 : len += scnprintf(buf + len, buf_len - len,
2194 : : "codeswap\t\t%08x\n",
2195 : 0 : crc32_le(0, ar->normal_mode_fw.fw_file.codeswap_data,
2196 : : ar->normal_mode_fw.fw_file.codeswap_len));
2197 : 0 : len += scnprintf(buf + len, buf_len - len,
2198 : : "board-N.bin\t\t%08x\n",
2199 : 0 : crc32_le(0, ar->normal_mode_fw.board->data,
2200 : 0 : ar->normal_mode_fw.board->size));
2201 : 0 : len += scnprintf(buf + len, buf_len - len,
2202 : : "board\t\t\t%08x\n",
2203 : 0 : crc32_le(0, ar->normal_mode_fw.board_data,
2204 : : ar->normal_mode_fw.board_len));
2205 : :
2206 : 0 : ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
2207 : :
2208 : 0 : mutex_unlock(&ar->conf_mutex);
2209 : :
2210 : 0 : kfree(buf);
2211 : 0 : return ret_cnt;
2212 : : }
2213 : :
2214 : : static const struct file_operations fops_fw_checksums = {
2215 : : .read = ath10k_debug_fw_checksums_read,
2216 : : .open = simple_open,
2217 : : .owner = THIS_MODULE,
2218 : : .llseek = default_llseek,
2219 : : };
2220 : :
2221 : 0 : static ssize_t ath10k_sta_tid_stats_mask_read(struct file *file,
2222 : : char __user *user_buf,
2223 : : size_t count, loff_t *ppos)
2224 : : {
2225 : 0 : struct ath10k *ar = file->private_data;
2226 : 0 : char buf[32];
2227 : 0 : size_t len;
2228 : :
2229 : 0 : len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->sta_tid_stats_mask);
2230 : 0 : return simple_read_from_buffer(user_buf, count, ppos, buf, len);
2231 : : }
2232 : :
2233 : 0 : static ssize_t ath10k_sta_tid_stats_mask_write(struct file *file,
2234 : : const char __user *user_buf,
2235 : : size_t count, loff_t *ppos)
2236 : : {
2237 : 0 : struct ath10k *ar = file->private_data;
2238 : 0 : char buf[32];
2239 : 0 : ssize_t len;
2240 : 0 : u32 mask;
2241 : :
2242 : 0 : len = min(count, sizeof(buf) - 1);
2243 [ # # ]: 0 : if (copy_from_user(buf, user_buf, len))
2244 : : return -EFAULT;
2245 : :
2246 : 0 : buf[len] = '\0';
2247 [ # # ]: 0 : if (kstrtoint(buf, 0, &mask))
2248 : : return -EINVAL;
2249 : :
2250 : 0 : ar->sta_tid_stats_mask = mask;
2251 : :
2252 : 0 : return len;
2253 : : }
2254 : :
2255 : : static const struct file_operations fops_sta_tid_stats_mask = {
2256 : : .read = ath10k_sta_tid_stats_mask_read,
2257 : : .write = ath10k_sta_tid_stats_mask_write,
2258 : : .open = simple_open,
2259 : : .owner = THIS_MODULE,
2260 : : .llseek = default_llseek,
2261 : : };
2262 : :
2263 : 0 : static int ath10k_debug_tpc_stats_final_request(struct ath10k *ar)
2264 : : {
2265 : 0 : int ret;
2266 : 0 : unsigned long time_left;
2267 : :
2268 : 0 : lockdep_assert_held(&ar->conf_mutex);
2269 : :
2270 : 0 : reinit_completion(&ar->debug.tpc_complete);
2271 : :
2272 : 0 : ret = ath10k_wmi_pdev_get_tpc_table_cmdid(ar, WMI_TPC_CONFIG_PARAM);
2273 [ # # ]: 0 : if (ret) {
2274 : 0 : ath10k_warn(ar, "failed to request tpc table cmdid: %d\n", ret);
2275 : 0 : return ret;
2276 : : }
2277 : :
2278 : 0 : time_left = wait_for_completion_timeout(&ar->debug.tpc_complete,
2279 : : 1 * HZ);
2280 [ # # ]: 0 : if (time_left == 0)
2281 : 0 : return -ETIMEDOUT;
2282 : :
2283 : : return 0;
2284 : : }
2285 : :
2286 : 0 : static int ath10k_tpc_stats_final_open(struct inode *inode, struct file *file)
2287 : : {
2288 : 0 : struct ath10k *ar = inode->i_private;
2289 : 0 : void *buf;
2290 : 0 : int ret;
2291 : :
2292 : 0 : mutex_lock(&ar->conf_mutex);
2293 : :
2294 [ # # ]: 0 : if (ar->state != ATH10K_STATE_ON) {
2295 : 0 : ret = -ENETDOWN;
2296 : 0 : goto err_unlock;
2297 : : }
2298 : :
2299 : 0 : buf = vmalloc(ATH10K_TPC_CONFIG_BUF_SIZE);
2300 [ # # ]: 0 : if (!buf) {
2301 : 0 : ret = -ENOMEM;
2302 : 0 : goto err_unlock;
2303 : : }
2304 : :
2305 : 0 : ret = ath10k_debug_tpc_stats_final_request(ar);
2306 [ # # ]: 0 : if (ret) {
2307 : 0 : ath10k_warn(ar, "failed to request tpc stats final: %d\n",
2308 : : ret);
2309 : 0 : goto err_free;
2310 : : }
2311 : :
2312 : 0 : ath10k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf);
2313 : 0 : file->private_data = buf;
2314 : :
2315 : 0 : mutex_unlock(&ar->conf_mutex);
2316 : 0 : return 0;
2317 : :
2318 : : err_free:
2319 : 0 : vfree(buf);
2320 : :
2321 : 0 : err_unlock:
2322 : 0 : mutex_unlock(&ar->conf_mutex);
2323 : 0 : return ret;
2324 : : }
2325 : :
2326 : 0 : static int ath10k_tpc_stats_final_release(struct inode *inode,
2327 : : struct file *file)
2328 : : {
2329 : 0 : vfree(file->private_data);
2330 : :
2331 : 0 : return 0;
2332 : : }
2333 : :
2334 : 0 : static ssize_t ath10k_tpc_stats_final_read(struct file *file,
2335 : : char __user *user_buf,
2336 : : size_t count, loff_t *ppos)
2337 : : {
2338 : 0 : const char *buf = file->private_data;
2339 : 0 : unsigned int len = strlen(buf);
2340 : :
2341 : 0 : return simple_read_from_buffer(user_buf, count, ppos, buf, len);
2342 : : }
2343 : :
2344 : : static const struct file_operations fops_tpc_stats_final = {
2345 : : .open = ath10k_tpc_stats_final_open,
2346 : : .release = ath10k_tpc_stats_final_release,
2347 : : .read = ath10k_tpc_stats_final_read,
2348 : : .owner = THIS_MODULE,
2349 : : .llseek = default_llseek,
2350 : : };
2351 : :
2352 : 0 : static ssize_t ath10k_write_warm_hw_reset(struct file *file,
2353 : : const char __user *user_buf,
2354 : : size_t count, loff_t *ppos)
2355 : : {
2356 : 0 : struct ath10k *ar = file->private_data;
2357 : 0 : int ret;
2358 : 0 : bool val;
2359 : :
2360 [ # # ]: 0 : if (kstrtobool_from_user(user_buf, count, &val))
2361 : : return -EFAULT;
2362 : :
2363 [ # # ]: 0 : if (!val)
2364 : : return -EINVAL;
2365 : :
2366 : 0 : mutex_lock(&ar->conf_mutex);
2367 : :
2368 [ # # ]: 0 : if (ar->state != ATH10K_STATE_ON) {
2369 : 0 : ret = -ENETDOWN;
2370 : 0 : goto exit;
2371 : : }
2372 : :
2373 [ # # ]: 0 : if (!(test_bit(WMI_SERVICE_RESET_CHIP, ar->wmi.svc_map)))
2374 : 0 : ath10k_warn(ar, "wmi service for reset chip is not available\n");
2375 : :
2376 : 0 : ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pdev_reset,
2377 : : WMI_RST_MODE_WARM_RESET);
2378 : :
2379 [ # # ]: 0 : if (ret) {
2380 : 0 : ath10k_warn(ar, "failed to enable warm hw reset: %d\n", ret);
2381 : 0 : goto exit;
2382 : : }
2383 : :
2384 : 0 : ret = count;
2385 : :
2386 : 0 : exit:
2387 : 0 : mutex_unlock(&ar->conf_mutex);
2388 : 0 : return ret;
2389 : : }
2390 : :
2391 : : static const struct file_operations fops_warm_hw_reset = {
2392 : : .write = ath10k_write_warm_hw_reset,
2393 : : .open = simple_open,
2394 : : .owner = THIS_MODULE,
2395 : : .llseek = default_llseek,
2396 : : };
2397 : :
2398 : 0 : static void ath10k_peer_ps_state_disable(void *data,
2399 : : struct ieee80211_sta *sta)
2400 : : {
2401 : 0 : struct ath10k *ar = data;
2402 : 0 : struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
2403 : :
2404 : 0 : spin_lock_bh(&ar->data_lock);
2405 : 0 : arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;
2406 : 0 : spin_unlock_bh(&ar->data_lock);
2407 : 0 : }
2408 : :
2409 : 0 : static ssize_t ath10k_write_ps_state_enable(struct file *file,
2410 : : const char __user *user_buf,
2411 : : size_t count, loff_t *ppos)
2412 : : {
2413 : 0 : struct ath10k *ar = file->private_data;
2414 : 0 : int ret;
2415 : 0 : u32 param;
2416 : 0 : u8 ps_state_enable;
2417 : :
2418 [ # # ]: 0 : if (kstrtou8_from_user(user_buf, count, 0, &ps_state_enable))
2419 : : return -EINVAL;
2420 : :
2421 [ # # ]: 0 : if (ps_state_enable > 1)
2422 : : return -EINVAL;
2423 : :
2424 : 0 : mutex_lock(&ar->conf_mutex);
2425 : :
2426 [ # # ]: 0 : if (ar->ps_state_enable == ps_state_enable) {
2427 : 0 : ret = count;
2428 : 0 : goto exit;
2429 : : }
2430 : :
2431 : 0 : param = ar->wmi.pdev_param->peer_sta_ps_statechg_enable;
2432 : 0 : ret = ath10k_wmi_pdev_set_param(ar, param, ps_state_enable);
2433 [ # # ]: 0 : if (ret) {
2434 : 0 : ath10k_warn(ar, "failed to enable ps_state_enable: %d\n",
2435 : : ret);
2436 : 0 : goto exit;
2437 : : }
2438 : 0 : ar->ps_state_enable = ps_state_enable;
2439 : :
2440 [ # # ]: 0 : if (!ar->ps_state_enable)
2441 : 0 : ieee80211_iterate_stations_atomic(ar->hw,
2442 : : ath10k_peer_ps_state_disable,
2443 : : ar);
2444 : :
2445 : 0 : ret = count;
2446 : :
2447 : 0 : exit:
2448 : 0 : mutex_unlock(&ar->conf_mutex);
2449 : :
2450 : 0 : return ret;
2451 : : }
2452 : :
2453 : 0 : static ssize_t ath10k_read_ps_state_enable(struct file *file,
2454 : : char __user *user_buf,
2455 : : size_t count, loff_t *ppos)
2456 : : {
2457 : 0 : struct ath10k *ar = file->private_data;
2458 : 0 : int len = 0;
2459 : 0 : char buf[32];
2460 : :
2461 : 0 : mutex_lock(&ar->conf_mutex);
2462 : 0 : len = scnprintf(buf, sizeof(buf) - len, "%d\n",
2463 : 0 : ar->ps_state_enable);
2464 : 0 : mutex_unlock(&ar->conf_mutex);
2465 : :
2466 : 0 : return simple_read_from_buffer(user_buf, count, ppos, buf, len);
2467 : : }
2468 : :
2469 : : static const struct file_operations fops_ps_state_enable = {
2470 : : .read = ath10k_read_ps_state_enable,
2471 : : .write = ath10k_write_ps_state_enable,
2472 : : .open = simple_open,
2473 : : .owner = THIS_MODULE,
2474 : : .llseek = default_llseek,
2475 : : };
2476 : :
2477 : 0 : static ssize_t ath10k_write_reset_htt_stats(struct file *file,
2478 : : const char __user *user_buf,
2479 : : size_t count, loff_t *ppos)
2480 : : {
2481 : 0 : struct ath10k *ar = file->private_data;
2482 : 0 : unsigned long reset;
2483 : 0 : int ret;
2484 : :
2485 : 0 : ret = kstrtoul_from_user(user_buf, count, 0, &reset);
2486 [ # # ]: 0 : if (ret)
2487 : 0 : return ret;
2488 : :
2489 [ # # ]: 0 : if (reset == 0 || reset > 0x1ffff)
2490 : : return -EINVAL;
2491 : :
2492 : 0 : mutex_lock(&ar->conf_mutex);
2493 : :
2494 : 0 : ar->debug.reset_htt_stats = reset;
2495 : :
2496 : 0 : ret = ath10k_debug_htt_stats_req(ar);
2497 [ # # ]: 0 : if (ret)
2498 : 0 : goto out;
2499 : :
2500 : 0 : ar->debug.reset_htt_stats = 0;
2501 : 0 : ret = count;
2502 : :
2503 : 0 : out:
2504 : 0 : mutex_unlock(&ar->conf_mutex);
2505 : 0 : return ret;
2506 : : }
2507 : :
2508 : : static const struct file_operations fops_reset_htt_stats = {
2509 : : .write = ath10k_write_reset_htt_stats,
2510 : : .owner = THIS_MODULE,
2511 : : .open = simple_open,
2512 : : .llseek = default_llseek,
2513 : : };
2514 : :
2515 : 28 : int ath10k_debug_create(struct ath10k *ar)
2516 : : {
2517 : 28 : ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);
2518 [ + - ]: 28 : if (!ar->debug.cal_data)
2519 : : return -ENOMEM;
2520 : :
2521 : 28 : INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
2522 : 28 : INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
2523 : 28 : INIT_LIST_HEAD(&ar->debug.fw_stats.peers);
2524 : 28 : INIT_LIST_HEAD(&ar->debug.fw_stats.peers_extd);
2525 : :
2526 : 28 : return 0;
2527 : : }
2528 : :
2529 : 3 : void ath10k_debug_destroy(struct ath10k *ar)
2530 : : {
2531 : 3 : vfree(ar->debug.cal_data);
2532 : 3 : ar->debug.cal_data = NULL;
2533 : :
2534 : 3 : ath10k_debug_fw_stats_reset(ar);
2535 : :
2536 : 3 : kfree(ar->debug.tpc_stats);
2537 : 3 : kfree(ar->debug.tpc_stats_final);
2538 : 3 : }
2539 : :
2540 : 0 : int ath10k_debug_register(struct ath10k *ar)
2541 : : {
2542 : 0 : ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
2543 : 0 : ar->hw->wiphy->debugfsdir);
2544 [ # # # # ]: 0 : if (IS_ERR_OR_NULL(ar->debug.debugfs_phy)) {
2545 [ # # ]: 0 : if (IS_ERR(ar->debug.debugfs_phy))
2546 : 0 : return PTR_ERR(ar->debug.debugfs_phy);
2547 : :
2548 : : return -ENOMEM;
2549 : : }
2550 : :
2551 : 0 : INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork,
2552 : : ath10k_debug_htt_stats_dwork);
2553 : :
2554 : 0 : init_completion(&ar->debug.tpc_complete);
2555 : 0 : init_completion(&ar->debug.fw_stats_complete);
2556 : :
2557 : 0 : debugfs_create_file("fw_stats", 0400, ar->debug.debugfs_phy, ar,
2558 : : &fops_fw_stats);
2559 : :
2560 : 0 : debugfs_create_file("fw_reset_stats", 0400, ar->debug.debugfs_phy, ar,
2561 : : &fops_fw_reset_stats);
2562 : :
2563 : 0 : debugfs_create_file("wmi_services", 0400, ar->debug.debugfs_phy, ar,
2564 : : &fops_wmi_services);
2565 : :
2566 : 0 : debugfs_create_file("simulate_fw_crash", 0600, ar->debug.debugfs_phy, ar,
2567 : : &fops_simulate_fw_crash);
2568 : :
2569 : 0 : debugfs_create_file("reg_addr", 0600, ar->debug.debugfs_phy, ar,
2570 : : &fops_reg_addr);
2571 : :
2572 : 0 : debugfs_create_file("reg_value", 0600, ar->debug.debugfs_phy, ar,
2573 : : &fops_reg_value);
2574 : :
2575 : 0 : debugfs_create_file("mem_value", 0600, ar->debug.debugfs_phy, ar,
2576 : : &fops_mem_value);
2577 : :
2578 : 0 : debugfs_create_file("chip_id", 0400, ar->debug.debugfs_phy, ar,
2579 : : &fops_chip_id);
2580 : :
2581 : 0 : debugfs_create_file("htt_stats_mask", 0600, ar->debug.debugfs_phy, ar,
2582 : : &fops_htt_stats_mask);
2583 : :
2584 : 0 : debugfs_create_file("htt_max_amsdu_ampdu", 0600, ar->debug.debugfs_phy, ar,
2585 : : &fops_htt_max_amsdu_ampdu);
2586 : :
2587 : 0 : debugfs_create_file("fw_dbglog", 0600, ar->debug.debugfs_phy, ar,
2588 : : &fops_fw_dbglog);
2589 : :
2590 [ # # ]: 0 : if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,
2591 : 0 : ar->normal_mode_fw.fw_file.fw_features)) {
2592 : 0 : debugfs_create_file("cal_data", 0400, ar->debug.debugfs_phy, ar,
2593 : : &fops_cal_data);
2594 : :
2595 : 0 : debugfs_create_file("nf_cal_period", 0600, ar->debug.debugfs_phy, ar,
2596 : : &fops_nf_cal_period);
2597 : : }
2598 : :
2599 : 0 : debugfs_create_file("ani_enable", 0600, ar->debug.debugfs_phy, ar,
2600 : : &fops_ani_enable);
2601 : :
2602 : 0 : if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED)) {
2603 : : debugfs_create_file("dfs_simulate_radar", 0200, ar->debug.debugfs_phy,
2604 : : ar, &fops_simulate_radar);
2605 : :
2606 : : debugfs_create_bool("dfs_block_radar_events", 0200,
2607 : : ar->debug.debugfs_phy,
2608 : : &ar->dfs_block_radar_events);
2609 : :
2610 : : debugfs_create_file("dfs_stats", 0400, ar->debug.debugfs_phy, ar,
2611 : : &fops_dfs_stats);
2612 : : }
2613 : :
2614 : 0 : debugfs_create_file("pktlog_filter", 0644, ar->debug.debugfs_phy, ar,
2615 : : &fops_pktlog_filter);
2616 : :
2617 [ # # ]: 0 : if (test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
2618 : 0 : debugfs_create_file("quiet_period", 0644, ar->debug.debugfs_phy, ar,
2619 : : &fops_quiet_period);
2620 : :
2621 : 0 : debugfs_create_file("tpc_stats", 0400, ar->debug.debugfs_phy, ar,
2622 : : &fops_tpc_stats);
2623 : :
2624 [ # # ]: 0 : if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map))
2625 : 0 : debugfs_create_file("btcoex", 0644, ar->debug.debugfs_phy, ar,
2626 : : &fops_btcoex);
2627 : :
2628 [ # # ]: 0 : if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) {
2629 : 0 : debugfs_create_file("peer_stats", 0644, ar->debug.debugfs_phy, ar,
2630 : : &fops_peer_stats);
2631 : :
2632 : 0 : debugfs_create_file("enable_extd_tx_stats", 0644,
2633 : : ar->debug.debugfs_phy, ar,
2634 : : &fops_enable_extd_tx_stats);
2635 : : }
2636 : :
2637 : 0 : debugfs_create_file("fw_checksums", 0400, ar->debug.debugfs_phy, ar,
2638 : : &fops_fw_checksums);
2639 : :
2640 : 0 : if (IS_ENABLED(CONFIG_MAC80211_DEBUGFS))
2641 : 0 : debugfs_create_file("sta_tid_stats_mask", 0600,
2642 : : ar->debug.debugfs_phy,
2643 : : ar, &fops_sta_tid_stats_mask);
2644 : :
2645 [ # # ]: 0 : if (test_bit(WMI_SERVICE_TPC_STATS_FINAL, ar->wmi.svc_map))
2646 : 0 : debugfs_create_file("tpc_stats_final", 0400,
2647 : : ar->debug.debugfs_phy, ar,
2648 : : &fops_tpc_stats_final);
2649 : :
2650 : 0 : debugfs_create_file("warm_hw_reset", 0600, ar->debug.debugfs_phy, ar,
2651 : : &fops_warm_hw_reset);
2652 : :
2653 : 0 : debugfs_create_file("ps_state_enable", 0600, ar->debug.debugfs_phy, ar,
2654 : : &fops_ps_state_enable);
2655 : :
2656 : 0 : debugfs_create_file("reset_htt_stats", 0200, ar->debug.debugfs_phy, ar,
2657 : : &fops_reset_htt_stats);
2658 : :
2659 : 0 : return 0;
2660 : : }
2661 : :
2662 : 0 : void ath10k_debug_unregister(struct ath10k *ar)
2663 : : {
2664 : 0 : cancel_delayed_work_sync(&ar->debug.htt_stats_dwork);
2665 : 0 : }
2666 : :
2667 : : #endif /* CONFIG_ATH10K_DEBUGFS */
2668 : :
2669 : : #ifdef CONFIG_ATH10K_DEBUG
2670 : 0 : void __ath10k_dbg(struct ath10k *ar, enum ath10k_debug_mask mask,
2671 : : const char *fmt, ...)
2672 : : {
2673 : 0 : struct va_format vaf;
2674 : 0 : va_list args;
2675 : :
2676 : 0 : va_start(args, fmt);
2677 : :
2678 : 0 : vaf.fmt = fmt;
2679 : 0 : vaf.va = &args;
2680 : :
2681 [ # # ]: 0 : if (ath10k_debug_mask & mask)
2682 : 0 : dev_printk(KERN_DEBUG, ar->dev, "%pV", &vaf);
2683 : :
2684 : 0 : trace_ath10k_log_dbg(ar, mask, &vaf);
2685 : :
2686 : 0 : va_end(args);
2687 : 0 : }
2688 : : EXPORT_SYMBOL(__ath10k_dbg);
2689 : :
2690 : 0 : void ath10k_dbg_dump(struct ath10k *ar,
2691 : : enum ath10k_debug_mask mask,
2692 : : const char *msg, const char *prefix,
2693 : : const void *buf, size_t len)
2694 : : {
2695 : 0 : char linebuf[256];
2696 : 0 : size_t linebuflen;
2697 : 0 : const void *ptr;
2698 : :
2699 [ # # ]: 0 : if (ath10k_debug_mask & mask) {
2700 [ # # ]: 0 : if (msg)
2701 : 0 : __ath10k_dbg(ar, mask, "%s\n", msg);
2702 : :
2703 [ # # ]: 0 : for (ptr = buf; (ptr - buf) < len; ptr += 16) {
2704 : 0 : linebuflen = 0;
2705 [ # # ]: 0 : linebuflen += scnprintf(linebuf + linebuflen,
2706 : : sizeof(linebuf) - linebuflen,
2707 : : "%s%08x: ",
2708 : : (prefix ? prefix : ""),
2709 : : (unsigned int)(ptr - buf));
2710 : 0 : hex_dump_to_buffer(ptr, len - (ptr - buf), 16, 1,
2711 : : linebuf + linebuflen,
2712 : : sizeof(linebuf) - linebuflen, true);
2713 : 0 : dev_printk(KERN_DEBUG, ar->dev, "%s\n", linebuf);
2714 : : }
2715 : : }
2716 : :
2717 : : /* tracing code doesn't like null strings :/ */
2718 [ # # # # ]: 0 : trace_ath10k_log_dbg_dump(ar, msg ? msg : "", prefix ? prefix : "",
2719 : : buf, len);
2720 : 0 : }
2721 : : EXPORT_SYMBOL(ath10k_dbg_dump);
2722 : :
2723 : : #endif /* CONFIG_ATH10K_DEBUG */
|