blob: 94d7b265e054873974731e14decccdc019b0f351 [file] [log] [blame]
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -08001// SPDX-License-Identifier: GPL-2.0-only
2/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */
3
4#include <linux/err.h>
5#include <linux/seq_file.h>
6#include <linux/debugfs.h>
7#include "main.h"
8#include "debug.h"
9#include "pci.h"
10
11void *cnss_ipc_log_context;
12
13static int cnss_pin_connect_show(struct seq_file *s, void *data)
14{
15 struct cnss_plat_data *cnss_priv = s->private;
16
17 seq_puts(s, "Pin connect results\n");
18 seq_printf(s, "FW power pin result: %04x\n",
19 cnss_priv->pin_result.fw_pwr_pin_result);
20 seq_printf(s, "FW PHY IO pin result: %04x\n",
21 cnss_priv->pin_result.fw_phy_io_pin_result);
22 seq_printf(s, "FW RF pin result: %04x\n",
23 cnss_priv->pin_result.fw_rf_pin_result);
24 seq_printf(s, "Host pin result: %04x\n",
25 cnss_priv->pin_result.host_pin_result);
26 seq_puts(s, "\n");
27
28 return 0;
29}
30
31static int cnss_pin_connect_open(struct inode *inode, struct file *file)
32{
33 return single_open(file, cnss_pin_connect_show, inode->i_private);
34}
35
36static const struct file_operations cnss_pin_connect_fops = {
37 .read = seq_read,
38 .release = single_release,
39 .open = cnss_pin_connect_open,
40 .owner = THIS_MODULE,
41 .llseek = seq_lseek,
42};
43
44static int cnss_stats_show_state(struct seq_file *s,
45 struct cnss_plat_data *plat_priv)
46{
47 enum cnss_driver_state i;
48 int skip = 0;
49 unsigned long state;
50
51 seq_printf(s, "\nState: 0x%lx(", plat_priv->driver_state);
52 for (i = 0, state = plat_priv->driver_state; state != 0;
53 state >>= 1, i++) {
54 if (!(state & 0x1))
55 continue;
56
57 if (skip++)
58 seq_puts(s, " | ");
59
60 switch (i) {
61 case CNSS_QMI_WLFW_CONNECTED:
62 seq_puts(s, "QMI_WLFW_CONNECTED");
63 continue;
64 case CNSS_FW_MEM_READY:
65 seq_puts(s, "FW_MEM_READY");
66 continue;
67 case CNSS_FW_READY:
68 seq_puts(s, "FW_READY");
69 continue;
70 case CNSS_COLD_BOOT_CAL:
71 seq_puts(s, "COLD_BOOT_CAL");
72 continue;
73 case CNSS_DRIVER_LOADING:
74 seq_puts(s, "DRIVER_LOADING");
75 continue;
76 case CNSS_DRIVER_UNLOADING:
77 seq_puts(s, "DRIVER_UNLOADING");
78 continue;
Yue Ma2b45e362019-05-02 15:59:06 -070079 case CNSS_DRIVER_IDLE_RESTART:
80 seq_puts(s, "IDLE_RESTART");
81 continue;
82 case CNSS_DRIVER_IDLE_SHUTDOWN:
83 seq_puts(s, "IDLE_SHUTDOWN");
84 continue;
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -080085 case CNSS_DRIVER_PROBED:
86 seq_puts(s, "DRIVER_PROBED");
87 continue;
88 case CNSS_DRIVER_RECOVERY:
89 seq_puts(s, "DRIVER_RECOVERY");
90 continue;
91 case CNSS_FW_BOOT_RECOVERY:
92 seq_puts(s, "FW_BOOT_RECOVERY");
93 continue;
94 case CNSS_DEV_ERR_NOTIFY:
95 seq_puts(s, "DEV_ERR");
96 continue;
97 case CNSS_DRIVER_DEBUG:
98 seq_puts(s, "DRIVER_DEBUG");
99 continue;
Yuanyuan Liu659d5f32019-01-25 14:29:22 -0800100 case CNSS_COEX_CONNECTED:
101 seq_puts(s, "COEX_CONNECTED");
102 continue;
Yuanyuan Liucdb04072019-06-06 11:18:49 -0700103 case CNSS_IMS_CONNECTED:
104 seq_puts(s, "IMS_CONNECTED");
105 continue;
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800106 }
107
108 seq_printf(s, "UNKNOWN-%d", i);
109 }
110 seq_puts(s, ")\n");
111
112 return 0;
113}
114
115static int cnss_stats_show(struct seq_file *s, void *data)
116{
117 struct cnss_plat_data *plat_priv = s->private;
118
119 cnss_stats_show_state(s, plat_priv);
120
121 return 0;
122}
123
124static int cnss_stats_open(struct inode *inode, struct file *file)
125{
126 return single_open(file, cnss_stats_show, inode->i_private);
127}
128
129static const struct file_operations cnss_stats_fops = {
130 .read = seq_read,
131 .release = single_release,
132 .open = cnss_stats_open,
133 .owner = THIS_MODULE,
134 .llseek = seq_lseek,
135};
136
137static ssize_t cnss_dev_boot_debug_write(struct file *fp,
138 const char __user *user_buf,
139 size_t count, loff_t *off)
140{
141 struct cnss_plat_data *plat_priv =
142 ((struct seq_file *)fp->private_data)->private;
143 struct cnss_pci_data *pci_priv;
144 char buf[64];
145 char *cmd;
146 unsigned int len = 0;
147 int ret = 0;
148
149 if (!plat_priv)
150 return -ENODEV;
151
152 pci_priv = plat_priv->bus_priv;
153 if (!pci_priv)
154 return -ENODEV;
155
156 len = min(count, sizeof(buf) - 1);
157 if (copy_from_user(buf, user_buf, len))
158 return -EFAULT;
159
160 buf[len] = '\0';
161 cmd = buf;
162
163 if (sysfs_streq(cmd, "on")) {
164 ret = cnss_power_on_device(plat_priv);
165 } else if (sysfs_streq(cmd, "off")) {
166 cnss_power_off_device(plat_priv);
167 } else if (sysfs_streq(cmd, "enumerate")) {
168 ret = cnss_pci_init(plat_priv);
169 } else if (sysfs_streq(cmd, "download")) {
170 set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
171 ret = cnss_pci_start_mhi(pci_priv);
172 } else if (sysfs_streq(cmd, "linkup")) {
173 ret = cnss_resume_pci_link(pci_priv);
174 } else if (sysfs_streq(cmd, "linkdown")) {
175 ret = cnss_suspend_pci_link(pci_priv);
176 } else if (sysfs_streq(cmd, "powerup")) {
177 set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
178 ret = cnss_driver_event_post(plat_priv,
179 CNSS_DRIVER_EVENT_POWER_UP,
180 CNSS_EVENT_SYNC, NULL);
181 } else if (sysfs_streq(cmd, "shutdown")) {
182 ret = cnss_driver_event_post(plat_priv,
183 CNSS_DRIVER_EVENT_POWER_DOWN,
184 0, NULL);
185 clear_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
186 } else if (sysfs_streq(cmd, "assert")) {
187 ret = cnss_force_fw_assert(&pci_priv->pci_dev->dev);
188 } else {
189 cnss_pr_err("Device boot debugfs command is invalid\n");
190 ret = -EINVAL;
191 }
192
193 if (ret)
194 return ret;
195
196 return count;
197}
198
199static int cnss_dev_boot_debug_show(struct seq_file *s, void *data)
200{
201 seq_puts(s, "\nUsage: echo <action> > <debugfs_path>/cnss/dev_boot\n");
202 seq_puts(s, "<action> can be one of below:\n");
203 seq_puts(s, "on: turn on device power, assert WLAN_EN\n");
204 seq_puts(s, "off: de-assert WLAN_EN, turn off device power\n");
205 seq_puts(s, "enumerate: de-assert PERST, enumerate PCIe\n");
206 seq_puts(s, "download: download FW and do QMI handshake with FW\n");
207 seq_puts(s, "linkup: bring up PCIe link\n");
208 seq_puts(s, "linkdown: bring down PCIe link\n");
209 seq_puts(s, "powerup: full power on sequence to boot device, download FW and do QMI handshake with FW\n");
210 seq_puts(s, "shutdown: full power off sequence to shutdown device\n");
211 seq_puts(s, "assert: trigger firmware assert\n");
212
213 return 0;
214}
215
216static int cnss_dev_boot_debug_open(struct inode *inode, struct file *file)
217{
218 return single_open(file, cnss_dev_boot_debug_show, inode->i_private);
219}
220
221static const struct file_operations cnss_dev_boot_debug_fops = {
222 .read = seq_read,
223 .write = cnss_dev_boot_debug_write,
224 .release = single_release,
225 .open = cnss_dev_boot_debug_open,
226 .owner = THIS_MODULE,
227 .llseek = seq_lseek,
228};
229
230static int cnss_reg_read_debug_show(struct seq_file *s, void *data)
231{
232 struct cnss_plat_data *plat_priv = s->private;
233
234 mutex_lock(&plat_priv->dev_lock);
235 if (!plat_priv->diag_reg_read_buf) {
236 seq_puts(s, "\nUsage: echo <mem_type> <offset> <data_len> > <debugfs_path>/cnss/reg_read\n");
237 mutex_unlock(&plat_priv->dev_lock);
238 return 0;
239 }
240
241 seq_printf(s, "\nRegister read, address: 0x%x memory type: 0x%x length: 0x%x\n\n",
242 plat_priv->diag_reg_read_addr,
243 plat_priv->diag_reg_read_mem_type,
244 plat_priv->diag_reg_read_len);
245
246 seq_hex_dump(s, "", DUMP_PREFIX_OFFSET, 32, 4,
247 plat_priv->diag_reg_read_buf,
248 plat_priv->diag_reg_read_len, false);
249
250 plat_priv->diag_reg_read_len = 0;
251 kfree(plat_priv->diag_reg_read_buf);
252 plat_priv->diag_reg_read_buf = NULL;
253 mutex_unlock(&plat_priv->dev_lock);
254
255 return 0;
256}
257
258static ssize_t cnss_reg_read_debug_write(struct file *fp,
259 const char __user *user_buf,
260 size_t count, loff_t *off)
261{
262 struct cnss_plat_data *plat_priv =
263 ((struct seq_file *)fp->private_data)->private;
264 char buf[64];
265 char *sptr, *token;
266 unsigned int len = 0;
267 u32 reg_offset, mem_type;
268 u32 data_len = 0;
269 u8 *reg_buf = NULL;
270 const char *delim = " ";
271 int ret = 0;
272
273 if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
274 cnss_pr_err("Firmware is not ready yet\n");
275 return -EINVAL;
276 }
277
278 len = min(count, sizeof(buf) - 1);
279 if (copy_from_user(buf, user_buf, len))
280 return -EFAULT;
281
282 buf[len] = '\0';
283 sptr = buf;
284
285 token = strsep(&sptr, delim);
286 if (!token)
287 return -EINVAL;
288
289 if (!sptr)
290 return -EINVAL;
291
292 if (kstrtou32(token, 0, &mem_type))
293 return -EINVAL;
294
295 token = strsep(&sptr, delim);
296 if (!token)
297 return -EINVAL;
298
299 if (!sptr)
300 return -EINVAL;
301
302 if (kstrtou32(token, 0, &reg_offset))
303 return -EINVAL;
304
305 token = strsep(&sptr, delim);
306 if (!token)
307 return -EINVAL;
308
309 if (kstrtou32(token, 0, &data_len))
310 return -EINVAL;
311
312 mutex_lock(&plat_priv->dev_lock);
313 kfree(plat_priv->diag_reg_read_buf);
314 plat_priv->diag_reg_read_buf = NULL;
315
316 reg_buf = kzalloc(data_len, GFP_KERNEL);
317 if (!reg_buf) {
318 mutex_unlock(&plat_priv->dev_lock);
319 return -ENOMEM;
320 }
321
322 ret = cnss_wlfw_athdiag_read_send_sync(plat_priv, reg_offset,
323 mem_type, data_len,
324 reg_buf);
325 if (ret) {
326 kfree(reg_buf);
327 mutex_unlock(&plat_priv->dev_lock);
328 return ret;
329 }
330
331 plat_priv->diag_reg_read_addr = reg_offset;
332 plat_priv->diag_reg_read_mem_type = mem_type;
333 plat_priv->diag_reg_read_len = data_len;
334 plat_priv->diag_reg_read_buf = reg_buf;
335 mutex_unlock(&plat_priv->dev_lock);
336
337 return count;
338}
339
340static int cnss_reg_read_debug_open(struct inode *inode, struct file *file)
341{
342 return single_open(file, cnss_reg_read_debug_show, inode->i_private);
343}
344
345static const struct file_operations cnss_reg_read_debug_fops = {
346 .read = seq_read,
347 .write = cnss_reg_read_debug_write,
348 .open = cnss_reg_read_debug_open,
349 .owner = THIS_MODULE,
350 .llseek = seq_lseek,
351};
352
353static int cnss_reg_write_debug_show(struct seq_file *s, void *data)
354{
355 seq_puts(s, "\nUsage: echo <mem_type> <offset> <reg_val> > <debugfs_path>/cnss/reg_write\n");
356
357 return 0;
358}
359
360static ssize_t cnss_reg_write_debug_write(struct file *fp,
361 const char __user *user_buf,
362 size_t count, loff_t *off)
363{
364 struct cnss_plat_data *plat_priv =
365 ((struct seq_file *)fp->private_data)->private;
366 char buf[64];
367 char *sptr, *token;
368 unsigned int len = 0;
369 u32 reg_offset, mem_type, reg_val;
370 const char *delim = " ";
371 int ret = 0;
372
373 if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
374 cnss_pr_err("Firmware is not ready yet\n");
375 return -EINVAL;
376 }
377
378 len = min(count, sizeof(buf) - 1);
379 if (copy_from_user(buf, user_buf, len))
380 return -EFAULT;
381
382 buf[len] = '\0';
383 sptr = buf;
384
385 token = strsep(&sptr, delim);
386 if (!token)
387 return -EINVAL;
388
389 if (!sptr)
390 return -EINVAL;
391
392 if (kstrtou32(token, 0, &mem_type))
393 return -EINVAL;
394
395 token = strsep(&sptr, delim);
396 if (!token)
397 return -EINVAL;
398
399 if (!sptr)
400 return -EINVAL;
401
402 if (kstrtou32(token, 0, &reg_offset))
403 return -EINVAL;
404
405 token = strsep(&sptr, delim);
406 if (!token)
407 return -EINVAL;
408
409 if (kstrtou32(token, 0, &reg_val))
410 return -EINVAL;
411
412 ret = cnss_wlfw_athdiag_write_send_sync(plat_priv, reg_offset, mem_type,
413 sizeof(u32),
414 (u8 *)&reg_val);
415 if (ret)
416 return ret;
417
418 return count;
419}
420
421static int cnss_reg_write_debug_open(struct inode *inode, struct file *file)
422{
423 return single_open(file, cnss_reg_write_debug_show, inode->i_private);
424}
425
426static const struct file_operations cnss_reg_write_debug_fops = {
427 .read = seq_read,
428 .write = cnss_reg_write_debug_write,
429 .open = cnss_reg_write_debug_open,
430 .owner = THIS_MODULE,
431 .llseek = seq_lseek,
432};
433
434static ssize_t cnss_runtime_pm_debug_write(struct file *fp,
435 const char __user *user_buf,
436 size_t count, loff_t *off)
437{
438 struct cnss_plat_data *plat_priv =
439 ((struct seq_file *)fp->private_data)->private;
440 struct cnss_pci_data *pci_priv;
441 char buf[64];
442 char *cmd;
443 unsigned int len = 0;
444 int ret = 0;
445
446 if (!plat_priv)
447 return -ENODEV;
448
449 pci_priv = plat_priv->bus_priv;
450 if (!pci_priv)
451 return -ENODEV;
452
453 len = min(count, sizeof(buf) - 1);
454 if (copy_from_user(buf, user_buf, len))
455 return -EFAULT;
456
457 buf[len] = '\0';
458 cmd = buf;
459
460 if (sysfs_streq(cmd, "usage_count")) {
461 cnss_pci_pm_runtime_show_usage_count(pci_priv);
Yue Ma6476dc92019-05-03 11:21:37 -0700462 } else if (sysfs_streq(cmd, "request_resume")) {
463 ret = cnss_pci_pm_request_resume(pci_priv);
464 } else if (sysfs_streq(cmd, "resume")) {
465 ret = cnss_pci_pm_runtime_resume(pci_priv);
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800466 } else if (sysfs_streq(cmd, "get")) {
467 ret = cnss_pci_pm_runtime_get(pci_priv);
468 } else if (sysfs_streq(cmd, "get_noresume")) {
469 cnss_pci_pm_runtime_get_noresume(pci_priv);
470 } else if (sysfs_streq(cmd, "put_autosuspend")) {
471 ret = cnss_pci_pm_runtime_put_autosuspend(pci_priv);
472 } else if (sysfs_streq(cmd, "put_noidle")) {
473 cnss_pci_pm_runtime_put_noidle(pci_priv);
474 } else if (sysfs_streq(cmd, "mark_last_busy")) {
475 cnss_pci_pm_runtime_mark_last_busy(pci_priv);
476 } else {
477 cnss_pr_err("Runtime PM debugfs command is invalid\n");
478 ret = -EINVAL;
479 }
480
481 if (ret)
482 return ret;
483
484 return count;
485}
486
487static int cnss_runtime_pm_debug_show(struct seq_file *s, void *data)
488{
489 seq_puts(s, "\nUsage: echo <action> > <debugfs_path>/cnss/runtime_pm\n");
490 seq_puts(s, "<action> can be one of below:\n");
491 seq_puts(s, "usage_count: get runtime PM usage count\n");
492 seq_puts(s, "get: do runtime PM get\n");
493 seq_puts(s, "get_noresume: do runtime PM get noresume\n");
494 seq_puts(s, "put_noidle: do runtime PM put noidle\n");
495 seq_puts(s, "put_autosuspend: do runtime PM put autosuspend\n");
496 seq_puts(s, "mark_last_busy: do runtime PM mark last busy\n");
497
498 return 0;
499}
500
501static int cnss_runtime_pm_debug_open(struct inode *inode, struct file *file)
502{
503 return single_open(file, cnss_runtime_pm_debug_show, inode->i_private);
504}
505
506static const struct file_operations cnss_runtime_pm_debug_fops = {
507 .read = seq_read,
508 .write = cnss_runtime_pm_debug_write,
509 .open = cnss_runtime_pm_debug_open,
510 .owner = THIS_MODULE,
511 .llseek = seq_lseek,
512};
513
514static ssize_t cnss_control_params_debug_write(struct file *fp,
515 const char __user *user_buf,
516 size_t count, loff_t *off)
517{
518 struct cnss_plat_data *plat_priv =
519 ((struct seq_file *)fp->private_data)->private;
520 char buf[64];
521 char *sptr, *token;
522 char *cmd;
523 u32 val;
524 unsigned int len = 0;
525 const char *delim = " ";
526
527 if (!plat_priv)
528 return -ENODEV;
529
530 len = min(count, sizeof(buf) - 1);
531 if (copy_from_user(buf, user_buf, len))
532 return -EFAULT;
533
534 buf[len] = '\0';
535 sptr = buf;
536
537 token = strsep(&sptr, delim);
538 if (!token)
539 return -EINVAL;
540 if (!sptr)
541 return -EINVAL;
542 cmd = token;
543
544 token = strsep(&sptr, delim);
545 if (!token)
546 return -EINVAL;
547 if (kstrtou32(token, 0, &val))
548 return -EINVAL;
549
550 if (strcmp(cmd, "quirks") == 0)
551 plat_priv->ctrl_params.quirks = val;
552 else if (strcmp(cmd, "mhi_timeout") == 0)
553 plat_priv->ctrl_params.mhi_timeout = val;
554 else if (strcmp(cmd, "qmi_timeout") == 0)
555 plat_priv->ctrl_params.qmi_timeout = val;
556 else if (strcmp(cmd, "bdf_type") == 0)
557 plat_priv->ctrl_params.bdf_type = val;
Yue Ma8ee81752019-07-10 11:56:51 -0700558 else if (strcmp(cmd, "time_sync_period") == 0)
559 plat_priv->ctrl_params.time_sync_period = val;
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800560 else
561 return -EINVAL;
562
563 return count;
564}
565
566static int cnss_show_quirks_state(struct seq_file *s,
567 struct cnss_plat_data *plat_priv)
568{
569 enum cnss_debug_quirks i;
570 int skip = 0;
571 unsigned long state;
572
573 seq_printf(s, "quirks: 0x%lx (", plat_priv->ctrl_params.quirks);
574 for (i = 0, state = plat_priv->ctrl_params.quirks;
575 state != 0; state >>= 1, i++) {
576 if (!(state & 0x1))
577 continue;
578 if (skip++)
579 seq_puts(s, " | ");
580
581 switch (i) {
582 case LINK_DOWN_SELF_RECOVERY:
583 seq_puts(s, "LINK_DOWN_SELF_RECOVERY");
584 continue;
585 case SKIP_DEVICE_BOOT:
586 seq_puts(s, "SKIP_DEVICE_BOOT");
587 continue;
588 case USE_CORE_ONLY_FW:
589 seq_puts(s, "USE_CORE_ONLY_FW");
590 continue;
591 case SKIP_RECOVERY:
592 seq_puts(s, "SKIP_RECOVERY");
593 continue;
594 case QMI_BYPASS:
595 seq_puts(s, "QMI_BYPASS");
596 continue;
597 case ENABLE_WALTEST:
598 seq_puts(s, "WALTEST");
599 continue;
600 case ENABLE_PCI_LINK_DOWN_PANIC:
601 seq_puts(s, "PCI_LINK_DOWN_PANIC");
602 continue;
603 case FBC_BYPASS:
604 seq_puts(s, "FBC_BYPASS");
605 continue;
606 case ENABLE_DAEMON_SUPPORT:
607 seq_puts(s, "DAEMON_SUPPORT");
608 continue;
Yue Maf28455c2019-04-09 18:17:03 -0700609 case DISABLE_DRV:
610 seq_puts(s, "DISABLE_DRV");
611 continue;
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800612 }
613
614 seq_printf(s, "UNKNOWN-%d", i);
615 }
616 seq_puts(s, ")\n");
617 return 0;
618}
619
620static int cnss_control_params_debug_show(struct seq_file *s, void *data)
621{
622 struct cnss_plat_data *cnss_priv = s->private;
623
624 seq_puts(s, "\nUsage: echo <params_name> <value> > <debugfs_path>/cnss/control_params\n");
625 seq_puts(s, "<params_name> can be one of below:\n");
626 seq_puts(s, "quirks: Debug quirks for driver\n");
627 seq_puts(s, "mhi_timeout: Timeout for MHI operation in milliseconds\n");
628 seq_puts(s, "qmi_timeout: Timeout for QMI message in milliseconds\n");
629 seq_puts(s, "bdf_type: Type of board data file to be downloaded\n");
Yue Ma8ee81752019-07-10 11:56:51 -0700630 seq_puts(s, "time_sync_period: Time period to do time sync with device in milliseconds\n");
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800631
632 seq_puts(s, "\nCurrent value:\n");
633 cnss_show_quirks_state(s, cnss_priv);
634 seq_printf(s, "mhi_timeout: %u\n", cnss_priv->ctrl_params.mhi_timeout);
635 seq_printf(s, "qmi_timeout: %u\n", cnss_priv->ctrl_params.qmi_timeout);
636 seq_printf(s, "bdf_type: %u\n", cnss_priv->ctrl_params.bdf_type);
Yue Ma8ee81752019-07-10 11:56:51 -0700637 seq_printf(s, "time_sync_period: %u\n",
638 cnss_priv->ctrl_params.time_sync_period);
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800639
640 return 0;
641}
642
643static int cnss_control_params_debug_open(struct inode *inode,
644 struct file *file)
645{
646 return single_open(file, cnss_control_params_debug_show,
647 inode->i_private);
648}
649
650static const struct file_operations cnss_control_params_debug_fops = {
651 .read = seq_read,
652 .write = cnss_control_params_debug_write,
653 .open = cnss_control_params_debug_open,
654 .owner = THIS_MODULE,
655 .llseek = seq_lseek,
656};
657
658#ifdef CONFIG_CNSS2_DEBUG
659static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
660{
661 struct dentry *root_dentry = plat_priv->root_dentry;
662
663 debugfs_create_file("dev_boot", 0600, root_dentry, plat_priv,
664 &cnss_dev_boot_debug_fops);
665 debugfs_create_file("reg_read", 0600, root_dentry, plat_priv,
666 &cnss_reg_read_debug_fops);
667 debugfs_create_file("reg_write", 0600, root_dentry, plat_priv,
668 &cnss_reg_write_debug_fops);
669 debugfs_create_file("runtime_pm", 0600, root_dentry, plat_priv,
670 &cnss_runtime_pm_debug_fops);
671 debugfs_create_file("control_params", 0600, root_dentry, plat_priv,
672 &cnss_control_params_debug_fops);
673
674 return 0;
675}
676#else
677static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
678{
679 return 0;
680}
681#endif
682
683int cnss_debugfs_create(struct cnss_plat_data *plat_priv)
684{
685 int ret = 0;
686 struct dentry *root_dentry;
687
688 root_dentry = debugfs_create_dir("cnss", 0);
689 if (IS_ERR(root_dentry)) {
690 ret = PTR_ERR(root_dentry);
691 cnss_pr_err("Unable to create debugfs %d\n", ret);
692 goto out;
693 }
694
695 plat_priv->root_dentry = root_dentry;
696
697 debugfs_create_file("pin_connect_result", 0644, root_dentry, plat_priv,
698 &cnss_pin_connect_fops);
699 debugfs_create_file("stats", 0644, root_dentry, plat_priv,
700 &cnss_stats_fops);
701
702 cnss_create_debug_only_node(plat_priv);
703
704out:
705 return ret;
706}
707
708void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv)
709{
710 debugfs_remove_recursive(plat_priv->root_dentry);
711}
712
713int cnss_debug_init(void)
714{
715 cnss_ipc_log_context = ipc_log_context_create(CNSS_IPC_LOG_PAGES,
716 "cnss", 0);
717 if (!cnss_ipc_log_context) {
718 cnss_pr_err("Unable to create IPC log context!\n");
719 return -EINVAL;
720 }
721
722 return 0;
723}
724
725void cnss_debug_deinit(void)
726{
727 if (cnss_ipc_log_context) {
728 ipc_log_context_destroy(cnss_ipc_log_context);
729 cnss_ipc_log_context = NULL;
730 }
731}