1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */
3 /* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */
4
5
6 #include <linux/err.h>
7 #include <linux/seq_file.h>
8 #include <linux/debugfs.h>
9 #include "main.h"
10 #include "bus.h"
11 #include "debug.h"
12 #include "pci.h"
13
14 #define MMIO_REG_ACCESS_MEM_TYPE 0xFF
15 #define MMIO_REG_RAW_ACCESS_MEM_TYPE 0xFE
16 #define DEFAULT_KERNEL_LOG_LEVEL INFO_LOG
17 #define DEFAULT_IPC_LOG_LEVEL DEBUG_LOG
18
19 enum log_level cnss_kernel_log_level = DEFAULT_KERNEL_LOG_LEVEL;
20
21 #if IS_ENABLED(CONFIG_IPC_LOGGING)
22 void *cnss_ipc_log_context;
23 void *cnss_ipc_log_long_context;
24 enum log_level cnss_ipc_log_level = DEFAULT_IPC_LOG_LEVEL;
25
cnss_set_ipc_log_level(u32 val)26 static int cnss_set_ipc_log_level(u32 val)
27 {
28 if (val < MAX_LOG) {
29 cnss_ipc_log_level = val;
30 return 0;
31 }
32
33 return -EINVAL;
34 }
35
cnss_get_ipc_log_level(void)36 static u32 cnss_get_ipc_log_level(void)
37 {
38 return cnss_ipc_log_level;
39 }
40 #else
cnss_set_ipc_log_level(int val)41 static int cnss_set_ipc_log_level(int val) { return -EINVAL; }
cnss_get_ipc_log_level(void)42 static u32 cnss_get_ipc_log_level(void) { return MAX_LOG; }
43 #endif
44
cnss_pin_connect_show(struct seq_file * s,void * data)45 static int cnss_pin_connect_show(struct seq_file *s, void *data)
46 {
47 struct cnss_plat_data *cnss_priv = s->private;
48
49 seq_puts(s, "Pin connect results\n");
50 seq_printf(s, "FW power pin result: %04x\n",
51 cnss_priv->pin_result.fw_pwr_pin_result);
52 seq_printf(s, "FW PHY IO pin result: %04x\n",
53 cnss_priv->pin_result.fw_phy_io_pin_result);
54 seq_printf(s, "FW RF pin result: %04x\n",
55 cnss_priv->pin_result.fw_rf_pin_result);
56 seq_printf(s, "Host pin result: %04x\n",
57 cnss_priv->pin_result.host_pin_result);
58 seq_puts(s, "\n");
59
60 return 0;
61 }
62
cnss_pin_connect_open(struct inode * inode,struct file * file)63 static int cnss_pin_connect_open(struct inode *inode, struct file *file)
64 {
65 return single_open(file, cnss_pin_connect_show, inode->i_private);
66 }
67
68 static const struct file_operations cnss_pin_connect_fops = {
69 .read = seq_read,
70 .release = single_release,
71 .open = cnss_pin_connect_open,
72 .owner = THIS_MODULE,
73 .llseek = seq_lseek,
74 };
75
cnss_get_serial_id(struct cnss_plat_data * plat_priv)76 static u64 cnss_get_serial_id(struct cnss_plat_data *plat_priv)
77 {
78 u32 msb = plat_priv->serial_id.serial_id_msb;
79 u32 lsb = plat_priv->serial_id.serial_id_lsb;
80
81 msb &= 0xFFFF;
82 return (((u64)msb << 32) | lsb);
83 }
84
cnss_stats_show_state(struct seq_file * s,struct cnss_plat_data * plat_priv)85 static int cnss_stats_show_state(struct seq_file *s,
86 struct cnss_plat_data *plat_priv)
87 {
88 enum cnss_driver_state i;
89 int skip = 0;
90 unsigned long state;
91
92 seq_printf(s, "\nSerial Number: 0x%llx",
93 cnss_get_serial_id(plat_priv));
94 seq_printf(s, "\nState: 0x%lx(", plat_priv->driver_state);
95 for (i = 0, state = plat_priv->driver_state; state != 0;
96 state >>= 1, i++) {
97 if (!(state & 0x1))
98 continue;
99
100 if (skip++)
101 seq_puts(s, " | ");
102
103 switch (i) {
104 case CNSS_QMI_WLFW_CONNECTED:
105 seq_puts(s, "QMI_WLFW_CONNECTED");
106 continue;
107 case CNSS_FW_MEM_READY:
108 seq_puts(s, "FW_MEM_READY");
109 continue;
110 case CNSS_FW_READY:
111 seq_puts(s, "FW_READY");
112 continue;
113 case CNSS_IN_COLD_BOOT_CAL:
114 seq_puts(s, "IN_COLD_BOOT_CAL");
115 continue;
116 case CNSS_DRIVER_LOADING:
117 seq_puts(s, "DRIVER_LOADING");
118 continue;
119 case CNSS_DRIVER_UNLOADING:
120 seq_puts(s, "DRIVER_UNLOADING");
121 continue;
122 case CNSS_DRIVER_IDLE_RESTART:
123 seq_puts(s, "IDLE_RESTART");
124 continue;
125 case CNSS_DRIVER_IDLE_SHUTDOWN:
126 seq_puts(s, "IDLE_SHUTDOWN");
127 continue;
128 case CNSS_DRIVER_PROBED:
129 seq_puts(s, "DRIVER_PROBED");
130 continue;
131 case CNSS_DRIVER_RECOVERY:
132 seq_puts(s, "DRIVER_RECOVERY");
133 continue;
134 case CNSS_FW_BOOT_RECOVERY:
135 seq_puts(s, "FW_BOOT_RECOVERY");
136 continue;
137 case CNSS_DEV_ERR_NOTIFY:
138 seq_puts(s, "DEV_ERR");
139 continue;
140 case CNSS_DRIVER_DEBUG:
141 seq_puts(s, "DRIVER_DEBUG");
142 continue;
143 case CNSS_COEX_CONNECTED:
144 seq_puts(s, "COEX_CONNECTED");
145 continue;
146 case CNSS_IMS_CONNECTED:
147 seq_puts(s, "IMS_CONNECTED");
148 continue;
149 case CNSS_IN_SUSPEND_RESUME:
150 seq_puts(s, "IN_SUSPEND_RESUME");
151 continue;
152 case CNSS_IN_REBOOT:
153 seq_puts(s, "IN_REBOOT");
154 continue;
155 case CNSS_COLD_BOOT_CAL_DONE:
156 seq_puts(s, "COLD_BOOT_CAL_DONE");
157 continue;
158 case CNSS_IN_PANIC:
159 seq_puts(s, "IN_PANIC");
160 continue;
161 case CNSS_QMI_DEL_SERVER:
162 seq_puts(s, "DEL_SERVER_IN_PROGRESS");
163 continue;
164 case CNSS_QMI_DMS_CONNECTED:
165 seq_puts(s, "DMS_CONNECTED");
166 continue;
167 case CNSS_DMS_DEL_SERVER:
168 seq_puts(s, "DMS_DEL_SERVER");
169 continue;
170 case CNSS_DAEMON_CONNECTED:
171 seq_puts(s, "DAEMON_CONNECTED");
172 continue;
173 case CNSS_PCI_PROBE_DONE:
174 seq_puts(s, "PCI PROBE DONE");
175 continue;
176 case CNSS_DRIVER_REGISTER:
177 seq_puts(s, "DRIVER REGISTERED");
178 continue;
179 case CNSS_WLAN_HW_DISABLED:
180 seq_puts(s, "WLAN HW DISABLED");
181 continue;
182 case CNSS_FS_READY:
183 seq_puts(s, "FS READY");
184 continue;
185 case CNSS_DRIVER_REGISTERED:
186 seq_puts(s, "DRIVER REGISTERED");
187 continue;
188 case CNSS_POWER_OFF:
189 seq_puts(s, "POWER OFF");
190 continue;
191 }
192
193 seq_printf(s, "UNKNOWN-%d", i);
194 }
195 seq_puts(s, ")\n");
196
197 return 0;
198 }
199
cnss_stats_show_gpio_state(struct seq_file * s,struct cnss_plat_data * plat_priv)200 static int cnss_stats_show_gpio_state(struct seq_file *s,
201 struct cnss_plat_data *plat_priv)
202 {
203 seq_printf(s, "\nHost SOL: %d", cnss_get_host_sol_value(plat_priv));
204 seq_printf(s, "\nDev SOL: %d", cnss_get_dev_sol_value(plat_priv));
205
206 return 0;
207 }
208
cnss_stats_show(struct seq_file * s,void * data)209 static int cnss_stats_show(struct seq_file *s, void *data)
210 {
211 struct cnss_plat_data *plat_priv = s->private;
212
213 cnss_stats_show_state(s, plat_priv);
214 cnss_stats_show_gpio_state(s, plat_priv);
215
216 return 0;
217 }
218
cnss_stats_open(struct inode * inode,struct file * file)219 static int cnss_stats_open(struct inode *inode, struct file *file)
220 {
221 return single_open(file, cnss_stats_show, inode->i_private);
222 }
223
224 static const struct file_operations cnss_stats_fops = {
225 .read = seq_read,
226 .release = single_release,
227 .open = cnss_stats_open,
228 .owner = THIS_MODULE,
229 .llseek = seq_lseek,
230 };
231
cnss_dev_boot_debug_write(struct file * fp,const char __user * user_buf,size_t count,loff_t * off)232 static ssize_t cnss_dev_boot_debug_write(struct file *fp,
233 const char __user *user_buf,
234 size_t count, loff_t *off)
235 {
236 struct cnss_plat_data *plat_priv =
237 ((struct seq_file *)fp->private_data)->private;
238 struct cnss_pci_data *pci_priv;
239 char buf[64];
240 char *cmd;
241 unsigned int len = 0;
242 char *sptr, *token;
243 const char *delim = " ";
244 int ret = 0;
245
246 if (!plat_priv)
247 return -ENODEV;
248
249 len = min(count, sizeof(buf) - 1);
250 if (copy_from_user(buf, user_buf, len))
251 return -EFAULT;
252
253 buf[len] = '\0';
254 sptr = buf;
255
256 token = strsep(&sptr, delim);
257 if (!token)
258 return -EINVAL;
259 cmd = token;
260 cnss_pr_dbg("Received dev_boot debug command: %s\n", cmd);
261
262 if (sysfs_streq(cmd, "on")) {
263 ret = cnss_power_on_device(plat_priv, false);
264 } else if (sysfs_streq(cmd, "off")) {
265 cnss_power_off_device(plat_priv);
266 } else if (sysfs_streq(cmd, "enumerate")) {
267 ret = cnss_pci_init(plat_priv);
268 } else if (sysfs_streq(cmd, "powerup")) {
269 set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
270 ret = cnss_driver_event_post(plat_priv,
271 CNSS_DRIVER_EVENT_POWER_UP,
272 CNSS_EVENT_SYNC, NULL);
273 } else if (sysfs_streq(cmd, "shutdown")) {
274 ret = cnss_driver_event_post(plat_priv,
275 CNSS_DRIVER_EVENT_POWER_DOWN,
276 0, NULL);
277 clear_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
278 } else if (sysfs_streq(cmd, "assert_host_sol")) {
279 pci_priv = plat_priv->bus_priv;
280 cnss_auto_resume(&pci_priv->pci_dev->dev);
281 ret = cnss_set_host_sol_value(plat_priv, 1);
282 } else if (sysfs_streq(cmd, "deassert_host_sol")) {
283 ret = cnss_set_host_sol_value(plat_priv, 0);
284 } else if (sysfs_streq(cmd, "pdc_update")) {
285 if (!sptr)
286 return -EINVAL;
287 ret = cnss_aop_send_msg(plat_priv, sptr);
288 } else if (sysfs_streq(cmd, "dev_check")) {
289 cnss_wlan_hw_disable_check(plat_priv);
290 } else if (sysfs_streq(cmd, "dev_enable")) {
291 cnss_wlan_hw_enable();
292 } else {
293 pci_priv = plat_priv->bus_priv;
294 if (!pci_priv)
295 return -ENODEV;
296
297 if (sysfs_streq(cmd, "download")) {
298 set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
299 ret = cnss_pci_start_mhi(pci_priv);
300 } else if (sysfs_streq(cmd, "linkup")) {
301 ret = cnss_resume_pci_link(pci_priv);
302 } else if (sysfs_streq(cmd, "linkdown")) {
303 ret = cnss_suspend_pci_link(pci_priv);
304 } else if (sysfs_streq(cmd, "assert")) {
305 cnss_pr_info("FW Assert triggered for debug\n");
306 ret = cnss_force_fw_assert(&pci_priv->pci_dev->dev);
307 } else if (sysfs_streq(cmd, "set_cbc_done")) {
308 cnss_pr_dbg("Force set cold boot cal done status\n");
309 set_bit(CNSS_COLD_BOOT_CAL_DONE,
310 &plat_priv->driver_state);
311 } else {
312 cnss_pr_err("Device boot debugfs command is invalid\n");
313 ret = -EINVAL;
314 }
315 }
316
317 if (ret < 0)
318 return ret;
319
320 return count;
321 }
322
cnss_dev_boot_debug_show(struct seq_file * s,void * data)323 static int cnss_dev_boot_debug_show(struct seq_file *s, void *data)
324 {
325 seq_puts(s, "\nUsage: echo <action> > <debugfs_path>/cnss/dev_boot\n");
326 seq_puts(s, "<action> can be one of below:\n");
327 seq_puts(s, "on: turn on device power, assert WLAN_EN\n");
328 seq_puts(s, "off: de-assert WLAN_EN, turn off device power\n");
329 seq_puts(s, "enumerate: de-assert PERST, enumerate PCIe\n");
330 seq_puts(s, "download: download FW and do QMI handshake with FW\n");
331 seq_puts(s, "linkup: bring up PCIe link\n");
332 seq_puts(s, "linkdown: bring down PCIe link\n");
333 seq_puts(s, "powerup: full power on sequence to boot device, download FW and do QMI handshake with FW\n");
334 seq_puts(s, "shutdown: full power off sequence to shutdown device\n");
335 seq_puts(s, "assert: trigger firmware assert\n");
336 seq_puts(s, "set_cbc_done: Set cold boot calibration done status\n");
337 seq_puts(s, "\npdc_update usage:");
338 seq_puts(s, "1. echo pdc_update {class: wlan_pdc ss: <pdc_ss>, res: <vreg>.<mode>, <seq>: <val>} > <debugfs_path>/cnss/dev_boot\n");
339 seq_puts(s, "2. echo pdc_update {class: wlan_pdc ss: <pdc_ss>, res: pdc, enable: <val>} > <debugfs_path>/cnss/dev_boot\n");
340 seq_puts(s, "assert_host_sol: Assert host sol\n");
341 seq_puts(s, "deassert_host_sol: Deassert host sol\n");
342 seq_puts(s, "dev_check: Check whether HW is disabled or not\n");
343 seq_puts(s, "dev_enable: Enable HW\n");
344
345 return 0;
346 }
347
cnss_dev_boot_debug_open(struct inode * inode,struct file * file)348 static int cnss_dev_boot_debug_open(struct inode *inode, struct file *file)
349 {
350 return single_open(file, cnss_dev_boot_debug_show, inode->i_private);
351 }
352
353 static const struct file_operations cnss_dev_boot_debug_fops = {
354 .read = seq_read,
355 .write = cnss_dev_boot_debug_write,
356 .release = single_release,
357 .open = cnss_dev_boot_debug_open,
358 .owner = THIS_MODULE,
359 .llseek = seq_lseek,
360 };
361
cnss_reg_read_debug_show(struct seq_file * s,void * data)362 static int cnss_reg_read_debug_show(struct seq_file *s, void *data)
363 {
364 struct cnss_plat_data *plat_priv = s->private;
365
366 mutex_lock(&plat_priv->dev_lock);
367 if (!plat_priv->diag_reg_read_buf) {
368 seq_puts(s, "\nUsage: echo <mem_type> <offset> <data_len> > <debugfs_path>/cnss/reg_read\n");
369 seq_puts(s, "Use mem_type = 0xff for register read by IO access, data_len will be ignored\n");
370 seq_puts(s, "Use mem_type = 0xfe for register read by raw IO access which skips sanity checks, data_len will be ignored\n");
371 seq_puts(s, "Use other mem_type for register read by QMI\n");
372 mutex_unlock(&plat_priv->dev_lock);
373 return 0;
374 }
375
376 seq_printf(s, "\nRegister read, address: 0x%x memory type: 0x%x length: 0x%x\n\n",
377 plat_priv->diag_reg_read_addr,
378 plat_priv->diag_reg_read_mem_type,
379 plat_priv->diag_reg_read_len);
380
381 seq_hex_dump(s, "", DUMP_PREFIX_OFFSET, 32, 4,
382 plat_priv->diag_reg_read_buf,
383 plat_priv->diag_reg_read_len, false);
384
385 plat_priv->diag_reg_read_len = 0;
386 kfree(plat_priv->diag_reg_read_buf);
387 plat_priv->diag_reg_read_buf = NULL;
388 mutex_unlock(&plat_priv->dev_lock);
389
390 return 0;
391 }
392
cnss_reg_read_debug_write(struct file * fp,const char __user * user_buf,size_t count,loff_t * off)393 static ssize_t cnss_reg_read_debug_write(struct file *fp,
394 const char __user *user_buf,
395 size_t count, loff_t *off)
396 {
397 struct cnss_plat_data *plat_priv =
398 ((struct seq_file *)fp->private_data)->private;
399 char buf[64];
400 char *sptr, *token;
401 unsigned int len = 0;
402 u32 reg_offset, mem_type;
403 u32 data_len = 0, reg_val = 0;
404 u8 *reg_buf = NULL;
405 const char *delim = " ";
406 int ret = 0;
407
408 len = min(count, sizeof(buf) - 1);
409 if (copy_from_user(buf, user_buf, len))
410 return -EFAULT;
411
412 buf[len] = '\0';
413 sptr = buf;
414
415 token = strsep(&sptr, delim);
416 if (!token)
417 return -EINVAL;
418
419 if (!sptr)
420 return -EINVAL;
421
422 if (kstrtou32(token, 0, &mem_type))
423 return -EINVAL;
424
425 token = strsep(&sptr, delim);
426 if (!token)
427 return -EINVAL;
428
429 if (!sptr)
430 return -EINVAL;
431
432 if (kstrtou32(token, 0, ®_offset))
433 return -EINVAL;
434
435 token = strsep(&sptr, delim);
436 if (!token)
437 return -EINVAL;
438
439 if (kstrtou32(token, 0, &data_len))
440 return -EINVAL;
441
442 if (mem_type == MMIO_REG_ACCESS_MEM_TYPE ||
443 mem_type == MMIO_REG_RAW_ACCESS_MEM_TYPE) {
444 ret = cnss_bus_debug_reg_read(plat_priv, reg_offset, ®_val,
445 mem_type ==
446 MMIO_REG_RAW_ACCESS_MEM_TYPE);
447 if (ret)
448 return ret;
449 cnss_pr_dbg("Read 0x%x from register offset 0x%x\n", reg_val,
450 reg_offset);
451 return count;
452 }
453
454 if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
455 cnss_pr_err("Firmware is not ready yet\n");
456 return -EINVAL;
457 }
458
459 mutex_lock(&plat_priv->dev_lock);
460 kfree(plat_priv->diag_reg_read_buf);
461 plat_priv->diag_reg_read_buf = NULL;
462
463 reg_buf = kzalloc(data_len, GFP_KERNEL);
464 if (!reg_buf) {
465 mutex_unlock(&plat_priv->dev_lock);
466 return -ENOMEM;
467 }
468
469 ret = cnss_wlfw_athdiag_read_send_sync(plat_priv, reg_offset,
470 mem_type, data_len,
471 reg_buf);
472 if (ret) {
473 kfree(reg_buf);
474 mutex_unlock(&plat_priv->dev_lock);
475 return ret;
476 }
477
478 plat_priv->diag_reg_read_addr = reg_offset;
479 plat_priv->diag_reg_read_mem_type = mem_type;
480 plat_priv->diag_reg_read_len = data_len;
481 plat_priv->diag_reg_read_buf = reg_buf;
482 mutex_unlock(&plat_priv->dev_lock);
483
484 return count;
485 }
486
cnss_reg_read_debug_open(struct inode * inode,struct file * file)487 static int cnss_reg_read_debug_open(struct inode *inode, struct file *file)
488 {
489 return single_open(file, cnss_reg_read_debug_show, inode->i_private);
490 }
491
492 static const struct file_operations cnss_reg_read_debug_fops = {
493 .read = seq_read,
494 .write = cnss_reg_read_debug_write,
495 .open = cnss_reg_read_debug_open,
496 .owner = THIS_MODULE,
497 .llseek = seq_lseek,
498 };
499
cnss_reg_write_debug_show(struct seq_file * s,void * data)500 static int cnss_reg_write_debug_show(struct seq_file *s, void *data)
501 {
502 seq_puts(s, "\nUsage: echo <mem_type> <offset> <reg_val> > <debugfs_path>/cnss/reg_write\n");
503 seq_puts(s, "Use mem_type = 0xff for register write by IO access\n");
504 seq_puts(s, "Use mem_type = 0xfe for register write by raw IO access which skips sanity checks\n");
505 seq_puts(s, "Use other mem_type for register write by QMI\n");
506
507 return 0;
508 }
509
cnss_reg_write_debug_write(struct file * fp,const char __user * user_buf,size_t count,loff_t * off)510 static ssize_t cnss_reg_write_debug_write(struct file *fp,
511 const char __user *user_buf,
512 size_t count, loff_t *off)
513 {
514 struct cnss_plat_data *plat_priv =
515 ((struct seq_file *)fp->private_data)->private;
516 char buf[64];
517 char *sptr, *token;
518 unsigned int len = 0;
519 u32 reg_offset, mem_type, reg_val;
520 const char *delim = " ";
521 int ret = 0;
522
523 len = min(count, sizeof(buf) - 1);
524 if (copy_from_user(buf, user_buf, len))
525 return -EFAULT;
526
527 buf[len] = '\0';
528 sptr = buf;
529
530 token = strsep(&sptr, delim);
531 if (!token)
532 return -EINVAL;
533
534 if (!sptr)
535 return -EINVAL;
536
537 if (kstrtou32(token, 0, &mem_type))
538 return -EINVAL;
539
540 token = strsep(&sptr, delim);
541 if (!token)
542 return -EINVAL;
543
544 if (!sptr)
545 return -EINVAL;
546
547 if (kstrtou32(token, 0, ®_offset))
548 return -EINVAL;
549
550 token = strsep(&sptr, delim);
551 if (!token)
552 return -EINVAL;
553
554 if (kstrtou32(token, 0, ®_val))
555 return -EINVAL;
556
557 if (mem_type == MMIO_REG_ACCESS_MEM_TYPE ||
558 mem_type == MMIO_REG_RAW_ACCESS_MEM_TYPE) {
559 ret = cnss_bus_debug_reg_write(plat_priv, reg_offset, reg_val,
560 mem_type ==
561 MMIO_REG_RAW_ACCESS_MEM_TYPE);
562 if (ret)
563 return ret;
564 cnss_pr_dbg("Wrote 0x%x to register offset 0x%x\n", reg_val,
565 reg_offset);
566 return count;
567 }
568
569 if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
570 cnss_pr_err("Firmware is not ready yet\n");
571 return -EINVAL;
572 }
573
574 ret = cnss_wlfw_athdiag_write_send_sync(plat_priv, reg_offset, mem_type,
575 sizeof(u32),
576 (u8 *)®_val);
577 if (ret)
578 return ret;
579
580 return count;
581 }
582
cnss_reg_write_debug_open(struct inode * inode,struct file * file)583 static int cnss_reg_write_debug_open(struct inode *inode, struct file *file)
584 {
585 return single_open(file, cnss_reg_write_debug_show, inode->i_private);
586 }
587
588 static const struct file_operations cnss_reg_write_debug_fops = {
589 .read = seq_read,
590 .write = cnss_reg_write_debug_write,
591 .open = cnss_reg_write_debug_open,
592 .owner = THIS_MODULE,
593 .llseek = seq_lseek,
594 };
595
cnss_runtime_pm_debug_write(struct file * fp,const char __user * user_buf,size_t count,loff_t * off)596 static ssize_t cnss_runtime_pm_debug_write(struct file *fp,
597 const char __user *user_buf,
598 size_t count, loff_t *off)
599 {
600 struct cnss_plat_data *plat_priv =
601 ((struct seq_file *)fp->private_data)->private;
602 struct cnss_pci_data *pci_priv;
603 char buf[64];
604 char *cmd;
605 unsigned int len = 0;
606 int ret = 0;
607
608 if (!plat_priv)
609 return -ENODEV;
610
611 pci_priv = plat_priv->bus_priv;
612 if (!pci_priv)
613 return -ENODEV;
614
615 len = min(count, sizeof(buf) - 1);
616 if (copy_from_user(buf, user_buf, len))
617 return -EFAULT;
618
619 buf[len] = '\0';
620 cmd = buf;
621
622 cnss_pr_dbg("Received runtime_pm debug command: %s\n", cmd);
623
624 if (sysfs_streq(cmd, "usage_count")) {
625 cnss_pci_pm_runtime_show_usage_count(pci_priv);
626 } else if (sysfs_streq(cmd, "request_resume")) {
627 ret = cnss_pci_pm_request_resume(pci_priv);
628 } else if (sysfs_streq(cmd, "resume")) {
629 ret = cnss_pci_pm_runtime_resume(pci_priv);
630 } else if (sysfs_streq(cmd, "get")) {
631 ret = cnss_pci_pm_runtime_get(pci_priv, RTPM_ID_CNSS);
632 } else if (sysfs_streq(cmd, "get_noresume")) {
633 cnss_pci_pm_runtime_get_noresume(pci_priv, RTPM_ID_CNSS);
634 } else if (sysfs_streq(cmd, "put_autosuspend")) {
635 ret = cnss_pci_pm_runtime_put_autosuspend(pci_priv,
636 RTPM_ID_CNSS);
637 } else if (sysfs_streq(cmd, "put_noidle")) {
638 cnss_pci_pm_runtime_put_noidle(pci_priv, RTPM_ID_CNSS);
639 } else if (sysfs_streq(cmd, "mark_last_busy")) {
640 cnss_pci_pm_runtime_mark_last_busy(pci_priv);
641 } else if (sysfs_streq(cmd, "resume_bus")) {
642 cnss_pci_resume_bus(pci_priv);
643 } else if (sysfs_streq(cmd, "suspend_bus")) {
644 cnss_pci_suspend_bus(pci_priv);
645 } else {
646 cnss_pr_err("Runtime PM debugfs command is invalid\n");
647 ret = -EINVAL;
648 }
649
650 if (ret < 0)
651 return ret;
652
653 return count;
654 }
655
cnss_runtime_pm_debug_show(struct seq_file * s,void * data)656 static int cnss_runtime_pm_debug_show(struct seq_file *s, void *data)
657 {
658 struct cnss_plat_data *plat_priv = s->private;
659 struct cnss_pci_data *pci_priv;
660 int i;
661
662 if (!plat_priv)
663 return -ENODEV;
664
665 pci_priv = plat_priv->bus_priv;
666 if (!pci_priv)
667 return -ENODEV;
668
669 seq_puts(s, "\nUsage: echo <action> > <debugfs_path>/cnss/runtime_pm\n");
670 seq_puts(s, "<action> can be one of below:\n");
671 seq_puts(s, "usage_count: get runtime PM usage count\n");
672 seq_puts(s, "reques_resume: do async runtime PM resume\n");
673 seq_puts(s, "resume: do sync runtime PM resume\n");
674 seq_puts(s, "get: do runtime PM get\n");
675 seq_puts(s, "get_noresume: do runtime PM get noresume\n");
676 seq_puts(s, "put_noidle: do runtime PM put noidle\n");
677 seq_puts(s, "put_autosuspend: do runtime PM put autosuspend\n");
678 seq_puts(s, "mark_last_busy: do runtime PM mark last busy\n");
679 seq_puts(s, "resume_bus: do bus resume only\n");
680 seq_puts(s, "suspend_bus: do bus suspend only\n");
681
682 seq_puts(s, "\nStats:\n");
683 seq_printf(s, "%s: %u\n", "get count",
684 atomic_read(&pci_priv->pm_stats.runtime_get));
685 seq_printf(s, "%s: %u\n", "put count",
686 atomic_read(&pci_priv->pm_stats.runtime_put));
687 seq_printf(s, "%-10s%-10s%-10s%-15s%-15s\n",
688 "id:", "get", "put", "get time(us)", "put time(us)");
689 for (i = 0; i < RTPM_ID_MAX; i++) {
690 seq_printf(s, "%d%-9s", i, ":");
691 seq_printf(s, "%-10d",
692 atomic_read(&pci_priv->pm_stats.runtime_get_id[i]));
693 seq_printf(s, "%-10d",
694 atomic_read(&pci_priv->pm_stats.runtime_put_id[i]));
695 seq_printf(s, "%-15llu",
696 pci_priv->pm_stats.runtime_get_timestamp_id[i]);
697 seq_printf(s, "%-15llu\n",
698 pci_priv->pm_stats.runtime_put_timestamp_id[i]);
699 }
700
701 return 0;
702 }
703
cnss_runtime_pm_debug_open(struct inode * inode,struct file * file)704 static int cnss_runtime_pm_debug_open(struct inode *inode, struct file *file)
705 {
706 return single_open(file, cnss_runtime_pm_debug_show, inode->i_private);
707 }
708
709 static const struct file_operations cnss_runtime_pm_debug_fops = {
710 .read = seq_read,
711 .write = cnss_runtime_pm_debug_write,
712 .open = cnss_runtime_pm_debug_open,
713 .owner = THIS_MODULE,
714 .llseek = seq_lseek,
715 };
716
process_drv(struct cnss_plat_data * plat_priv,bool enabled)717 static int process_drv(struct cnss_plat_data *plat_priv, bool enabled)
718 {
719 if (test_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state)) {
720 cnss_pr_err("DRV cmd must be used before QMI ready\n");
721 return -EINVAL;
722 }
723
724 enabled ? cnss_set_feature_list(plat_priv, CNSS_DRV_SUPPORT_V01) :
725 cnss_clear_feature_list(plat_priv, CNSS_DRV_SUPPORT_V01);
726
727 cnss_pr_info("%s DRV suspend\n", enabled ? "enable" : "disable");
728 return 0;
729 }
730
process_quirks(struct cnss_plat_data * plat_priv,u32 val)731 static int process_quirks(struct cnss_plat_data *plat_priv, u32 val)
732 {
733 enum cnss_debug_quirks i;
734 int ret = 0;
735 unsigned long state;
736 unsigned long quirks = 0;
737
738 for (i = 0, state = val; i < QUIRK_MAX_VALUE; state >>= 1, i++) {
739 switch (i) {
740 case DISABLE_DRV:
741 ret = process_drv(plat_priv, !(state & 0x1));
742 if (!ret)
743 quirks |= (state & 0x1) << i;
744 continue;
745 default:
746 quirks |= (state & 0x1) << i;
747 continue;
748 }
749 }
750
751 plat_priv->ctrl_params.quirks = quirks;
752 return 0;
753 }
754
cnss_control_params_debug_write(struct file * fp,const char __user * user_buf,size_t count,loff_t * off)755 static ssize_t cnss_control_params_debug_write(struct file *fp,
756 const char __user *user_buf,
757 size_t count, loff_t *off)
758 {
759 struct cnss_plat_data *plat_priv =
760 ((struct seq_file *)fp->private_data)->private;
761 char buf[64];
762 char *sptr, *token;
763 char *cmd;
764 u32 val;
765 unsigned int len = 0;
766 const char *delim = " ";
767
768 if (!plat_priv)
769 return -ENODEV;
770
771 len = min(count, sizeof(buf) - 1);
772 if (copy_from_user(buf, user_buf, len))
773 return -EFAULT;
774
775 buf[len] = '\0';
776 sptr = buf;
777
778 token = strsep(&sptr, delim);
779 if (!token)
780 return -EINVAL;
781 if (!sptr)
782 return -EINVAL;
783 cmd = token;
784
785 token = strsep(&sptr, delim);
786 if (!token)
787 return -EINVAL;
788 if (kstrtou32(token, 0, &val))
789 return -EINVAL;
790
791 if (strcmp(cmd, "quirks") == 0)
792 process_quirks(plat_priv, val);
793 else if (strcmp(cmd, "mhi_timeout") == 0)
794 plat_priv->ctrl_params.mhi_timeout = val;
795 else if (strcmp(cmd, "mhi_m2_timeout") == 0)
796 plat_priv->ctrl_params.mhi_m2_timeout = val;
797 else if (strcmp(cmd, "qmi_timeout") == 0)
798 plat_priv->ctrl_params.qmi_timeout = val;
799 else if (strcmp(cmd, "bdf_type") == 0)
800 plat_priv->ctrl_params.bdf_type = val;
801 else if (strcmp(cmd, "time_sync_period") == 0)
802 plat_priv->ctrl_params.time_sync_period = val;
803 else if (strcmp(cmd, "kern_log_level") == 0) {
804 if (val < MAX_LOG)
805 cnss_kernel_log_level = val;
806 } else if (strcmp(cmd, "ipc_log_level") == 0) {
807 return cnss_set_ipc_log_level(val) ? -EINVAL : count;
808 } else
809 return -EINVAL;
810
811 return count;
812 }
813
cnss_show_quirks_state(struct seq_file * s,struct cnss_plat_data * plat_priv)814 static int cnss_show_quirks_state(struct seq_file *s,
815 struct cnss_plat_data *plat_priv)
816 {
817 enum cnss_debug_quirks i;
818 int skip = 0;
819 unsigned long state;
820
821 seq_printf(s, "quirks: 0x%lx (", plat_priv->ctrl_params.quirks);
822 for (i = 0, state = plat_priv->ctrl_params.quirks;
823 state != 0; state >>= 1, i++) {
824 if (!(state & 0x1))
825 continue;
826 if (skip++)
827 seq_puts(s, " | ");
828
829 switch (i) {
830 case LINK_DOWN_SELF_RECOVERY:
831 seq_puts(s, "LINK_DOWN_SELF_RECOVERY");
832 continue;
833 case SKIP_DEVICE_BOOT:
834 seq_puts(s, "SKIP_DEVICE_BOOT");
835 continue;
836 case USE_CORE_ONLY_FW:
837 seq_puts(s, "USE_CORE_ONLY_FW");
838 continue;
839 case SKIP_RECOVERY:
840 seq_puts(s, "SKIP_RECOVERY");
841 continue;
842 case QMI_BYPASS:
843 seq_puts(s, "QMI_BYPASS");
844 continue;
845 case ENABLE_WALTEST:
846 seq_puts(s, "WALTEST");
847 continue;
848 case ENABLE_PCI_LINK_DOWN_PANIC:
849 seq_puts(s, "PCI_LINK_DOWN_PANIC");
850 continue;
851 case FBC_BYPASS:
852 seq_puts(s, "FBC_BYPASS");
853 continue;
854 case ENABLE_DAEMON_SUPPORT:
855 seq_puts(s, "DAEMON_SUPPORT");
856 continue;
857 case DISABLE_DRV:
858 seq_puts(s, "DISABLE_DRV");
859 continue;
860 case DISABLE_IO_COHERENCY:
861 seq_puts(s, "DISABLE_IO_COHERENCY");
862 continue;
863 case IGNORE_PCI_LINK_FAILURE:
864 seq_puts(s, "IGNORE_PCI_LINK_FAILURE");
865 continue;
866 case DISABLE_TIME_SYNC:
867 seq_puts(s, "DISABLE_TIME_SYNC");
868 continue;
869 case FORCE_ONE_MSI:
870 seq_puts(s, "FORCE_ONE_MSI");
871 continue;
872 default:
873 continue;
874 }
875 }
876 seq_puts(s, ")\n");
877 return 0;
878 }
879
cnss_control_params_debug_show(struct seq_file * s,void * data)880 static int cnss_control_params_debug_show(struct seq_file *s, void *data)
881 {
882 struct cnss_plat_data *cnss_priv = s->private;
883 u32 ipc_log_level;
884
885 seq_puts(s, "\nUsage: echo <params_name> <value> > <debugfs_path>/cnss/control_params\n");
886 seq_puts(s, "<params_name> can be one of below:\n");
887 seq_puts(s, "quirks: Debug quirks for driver\n");
888 seq_puts(s, "mhi_timeout: Timeout for MHI operation in milliseconds\n");
889 seq_puts(s, "qmi_timeout: Timeout for QMI message in milliseconds\n");
890 seq_puts(s, "bdf_type: Type of board data file to be downloaded\n");
891 seq_puts(s, "time_sync_period: Time period to do time sync with device in milliseconds\n");
892
893 seq_puts(s, "\nCurrent value:\n");
894 cnss_show_quirks_state(s, cnss_priv);
895 seq_printf(s, "mhi_timeout: %u\n", cnss_priv->ctrl_params.mhi_timeout);
896 seq_printf(s, "mhi_m2_timeout: %u\n",
897 cnss_priv->ctrl_params.mhi_m2_timeout);
898 seq_printf(s, "qmi_timeout: %u\n", cnss_priv->ctrl_params.qmi_timeout);
899 seq_printf(s, "bdf_type: %u\n", cnss_priv->ctrl_params.bdf_type);
900 seq_printf(s, "time_sync_period: %u\n",
901 cnss_priv->ctrl_params.time_sync_period);
902 seq_printf(s, "kern_log_level: %u\n", cnss_kernel_log_level);
903
904 ipc_log_level = cnss_get_ipc_log_level();
905 if (ipc_log_level != MAX_LOG)
906 seq_printf(s, "ipc_log_level: %u\n", ipc_log_level);
907
908 return 0;
909 }
910
cnss_control_params_debug_open(struct inode * inode,struct file * file)911 static int cnss_control_params_debug_open(struct inode *inode,
912 struct file *file)
913 {
914 return single_open(file, cnss_control_params_debug_show,
915 inode->i_private);
916 }
917
918 static const struct file_operations cnss_control_params_debug_fops = {
919 .read = seq_read,
920 .write = cnss_control_params_debug_write,
921 .open = cnss_control_params_debug_open,
922 .owner = THIS_MODULE,
923 .llseek = seq_lseek,
924 };
925
cnss_dynamic_feature_write(struct file * fp,const char __user * user_buf,size_t count,loff_t * off)926 static ssize_t cnss_dynamic_feature_write(struct file *fp,
927 const char __user *user_buf,
928 size_t count, loff_t *off)
929 {
930 struct cnss_plat_data *plat_priv =
931 ((struct seq_file *)fp->private_data)->private;
932 int ret = 0;
933 u64 val;
934
935 ret = kstrtou64_from_user(user_buf, count, 0, &val);
936 if (ret)
937 return ret;
938
939 plat_priv->dynamic_feature = val;
940 ret = cnss_wlfw_dynamic_feature_mask_send_sync(plat_priv);
941 if (ret < 0)
942 return ret;
943
944 return count;
945 }
946
cnss_dynamic_feature_show(struct seq_file * s,void * data)947 static int cnss_dynamic_feature_show(struct seq_file *s, void *data)
948 {
949 struct cnss_plat_data *cnss_priv = s->private;
950
951 seq_printf(s, "dynamic_feature: 0x%llx\n", cnss_priv->dynamic_feature);
952
953 return 0;
954 }
955
cnss_dynamic_feature_open(struct inode * inode,struct file * file)956 static int cnss_dynamic_feature_open(struct inode *inode,
957 struct file *file)
958 {
959 return single_open(file, cnss_dynamic_feature_show,
960 inode->i_private);
961 }
962
963 static const struct file_operations cnss_dynamic_feature_fops = {
964 .read = seq_read,
965 .write = cnss_dynamic_feature_write,
966 .open = cnss_dynamic_feature_open,
967 .owner = THIS_MODULE,
968 .llseek = seq_lseek,
969 };
970
cnss_smmu_fault_timestamp_show(struct seq_file * s,void * data)971 static int cnss_smmu_fault_timestamp_show(struct seq_file *s, void *data)
972 {
973 struct cnss_plat_data *plat_priv = s->private;
974 struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
975
976 if (!pci_priv)
977 return -ENODEV;
978
979 seq_printf(s, "smmu irq cb entry timestamp : %llu ns\n",
980 pci_priv->smmu_fault_timestamp[SMMU_CB_ENTRY]);
981 seq_printf(s, "smmu irq cb before doorbell ring timestamp : %llu ns\n",
982 pci_priv->smmu_fault_timestamp[SMMU_CB_DOORBELL_RING]);
983 seq_printf(s, "smmu irq cb after doorbell ring timestamp : %llu ns\n",
984 pci_priv->smmu_fault_timestamp[SMMU_CB_EXIT]);
985
986 return 0;
987 }
988
cnss_smmu_fault_timestamp_open(struct inode * inode,struct file * file)989 static int cnss_smmu_fault_timestamp_open(struct inode *inode,
990 struct file *file)
991 {
992 return single_open(file, cnss_smmu_fault_timestamp_show,
993 inode->i_private);
994 }
995
996 static const struct file_operations cnss_smmu_fault_timestamp_fops = {
997 .read = seq_read,
998 .release = single_release,
999 .open = cnss_smmu_fault_timestamp_open,
1000 .owner = THIS_MODULE,
1001 .llseek = seq_lseek,
1002 };
1003
1004 #ifdef CONFIG_DEBUG_FS
1005 #ifdef CONFIG_CNSS2_DEBUG
cnss_create_debug_only_node(struct cnss_plat_data * plat_priv)1006 static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
1007 {
1008 struct dentry *root_dentry = plat_priv->root_dentry;
1009
1010 debugfs_create_file("dev_boot", 0600, root_dentry, plat_priv,
1011 &cnss_dev_boot_debug_fops);
1012 debugfs_create_file("reg_read", 0600, root_dentry, plat_priv,
1013 &cnss_reg_read_debug_fops);
1014 debugfs_create_file("reg_write", 0600, root_dentry, plat_priv,
1015 &cnss_reg_write_debug_fops);
1016 debugfs_create_file("runtime_pm", 0600, root_dentry, plat_priv,
1017 &cnss_runtime_pm_debug_fops);
1018 debugfs_create_file("control_params", 0600, root_dentry, plat_priv,
1019 &cnss_control_params_debug_fops);
1020 debugfs_create_file("dynamic_feature", 0600, root_dentry, plat_priv,
1021 &cnss_dynamic_feature_fops);
1022 debugfs_create_file("cnss_smmu_fault_timestamp", 0600, root_dentry,
1023 plat_priv, &cnss_smmu_fault_timestamp_fops);
1024
1025 return 0;
1026 }
1027 #else
cnss_create_debug_only_node(struct cnss_plat_data * plat_priv)1028 static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
1029 {
1030 return 0;
1031 }
1032 #endif
1033
cnss_debugfs_create(struct cnss_plat_data * plat_priv)1034 int cnss_debugfs_create(struct cnss_plat_data *plat_priv)
1035 {
1036 int ret = 0;
1037 struct dentry *root_dentry;
1038 char name[CNSS_FS_NAME_SIZE];
1039
1040 if (cnss_is_dual_wlan_enabled())
1041 snprintf(name, CNSS_FS_NAME_SIZE, CNSS_FS_NAME "_%d",
1042 plat_priv->plat_idx);
1043 else
1044 snprintf(name, CNSS_FS_NAME_SIZE, CNSS_FS_NAME);
1045
1046 root_dentry = debugfs_create_dir(name, 0);
1047 if (IS_ERR(root_dentry)) {
1048 ret = PTR_ERR(root_dentry);
1049 cnss_pr_err("Unable to create debugfs %d\n", ret);
1050 goto out;
1051 }
1052
1053 plat_priv->root_dentry = root_dentry;
1054
1055 debugfs_create_file("pin_connect_result", 0644, root_dentry, plat_priv,
1056 &cnss_pin_connect_fops);
1057 debugfs_create_file("stats", 0644, root_dentry, plat_priv,
1058 &cnss_stats_fops);
1059
1060 cnss_create_debug_only_node(plat_priv);
1061
1062 out:
1063 return ret;
1064 }
1065
cnss_debugfs_destroy(struct cnss_plat_data * plat_priv)1066 void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv)
1067 {
1068 debugfs_remove_recursive(plat_priv->root_dentry);
1069 }
1070 #else
cnss_debugfs_create(struct cnss_plat_data * plat_priv)1071 int cnss_debugfs_create(struct cnss_plat_data *plat_priv)
1072 {
1073 plat_priv->root_dentry = NULL;
1074 return 0;
1075 }
1076
cnss_debugfs_destroy(struct cnss_plat_data * plat_priv)1077 void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv)
1078 {
1079 }
1080 #endif
1081
1082 #if IS_ENABLED(CONFIG_IPC_LOGGING)
cnss_debug_ipc_log_print(void * log_ctx,char * process,const char * fn,enum log_level kern_log_level,enum log_level ipc_log_level,char * fmt,...)1083 void cnss_debug_ipc_log_print(void *log_ctx, char *process, const char *fn,
1084 enum log_level kern_log_level,
1085 enum log_level ipc_log_level, char *fmt, ...)
1086 {
1087 struct va_format vaf;
1088 va_list va_args;
1089
1090 va_start(va_args, fmt);
1091 vaf.fmt = fmt;
1092 vaf.va = &va_args;
1093
1094 if (kern_log_level <= cnss_kernel_log_level) {
1095 switch (kern_log_level) {
1096 case EMERG_LOG:
1097 pr_emerg("cnss: %pV", &vaf);
1098 break;
1099 case ALERT_LOG:
1100 pr_alert("cnss: %pV", &vaf);
1101 break;
1102 case CRIT_LOG:
1103 pr_crit("cnss: %pV", &vaf);
1104 break;
1105 case ERR_LOG:
1106 pr_err("cnss: %pV", &vaf);
1107 break;
1108 case WARNING_LOG:
1109 pr_warn("cnss: %pV", &vaf);
1110 break;
1111 case NOTICE_LOG:
1112 pr_notice("cnss: %pV", &vaf);
1113 break;
1114 case INFO_LOG:
1115 pr_info("cnss: %pV", &vaf);
1116 break;
1117 case DEBUG_LOG:
1118 case DEBUG_HI_LOG:
1119 pr_debug("cnss: %pV", &vaf);
1120 break;
1121 default:
1122 break;
1123 }
1124 }
1125
1126 if (ipc_log_level <= cnss_ipc_log_level)
1127 ipc_log_string(log_ctx, "[%s] %s: %pV", process, fn, &vaf);
1128
1129 va_end(va_args);
1130 }
1131
cnss_ipc_logging_init(void)1132 static int cnss_ipc_logging_init(void)
1133 {
1134 cnss_ipc_log_context = ipc_log_context_create(CNSS_IPC_LOG_PAGES,
1135 "cnss", 0);
1136 if (!cnss_ipc_log_context) {
1137 cnss_pr_err("Unable to create IPC log context\n");
1138 return -EINVAL;
1139 }
1140
1141 cnss_ipc_log_long_context = ipc_log_context_create(CNSS_IPC_LOG_PAGES,
1142 "cnss-long", 0);
1143 if (!cnss_ipc_log_long_context) {
1144 cnss_pr_err("Unable to create IPC long log context\n");
1145 ipc_log_context_destroy(cnss_ipc_log_context);
1146 return -EINVAL;
1147 }
1148
1149 return 0;
1150 }
1151
cnss_ipc_logging_deinit(void)1152 static void cnss_ipc_logging_deinit(void)
1153 {
1154 if (cnss_ipc_log_long_context) {
1155 ipc_log_context_destroy(cnss_ipc_log_long_context);
1156 cnss_ipc_log_long_context = NULL;
1157 }
1158
1159 if (cnss_ipc_log_context) {
1160 ipc_log_context_destroy(cnss_ipc_log_context);
1161 cnss_ipc_log_context = NULL;
1162 }
1163 }
1164 #else
cnss_ipc_logging_init(void)1165 static int cnss_ipc_logging_init(void) { return 0; }
cnss_ipc_logging_deinit(void)1166 static void cnss_ipc_logging_deinit(void) {}
cnss_debug_ipc_log_print(void * log_ctx,char * process,const char * fn,enum log_level kern_log_level,enum log_level ipc_log_level,char * fmt,...)1167 void cnss_debug_ipc_log_print(void *log_ctx, char *process, const char *fn,
1168 enum log_level kern_log_level,
1169 enum log_level ipc_log_level, char *fmt, ...)
1170 {
1171 struct va_format vaf;
1172 va_list va_args;
1173
1174 va_start(va_args, fmt);
1175 vaf.fmt = fmt;
1176 vaf.va = &va_args;
1177
1178 if (kern_log_level <= cnss_kernel_log_level) {
1179 switch (kern_log_level) {
1180 case EMERG_LOG:
1181 pr_emerg("cnss: %pV", &vaf);
1182 break;
1183 case ALERT_LOG:
1184 pr_alert("cnss: %pV", &vaf);
1185 break;
1186 case CRIT_LOG:
1187 pr_crit("cnss: %pV", &vaf);
1188 break;
1189 case ERR_LOG:
1190 pr_err("cnss: %pV", &vaf);
1191 break;
1192 case WARNING_LOG:
1193 pr_warn("cnss: %pV", &vaf);
1194 break;
1195 case NOTICE_LOG:
1196 pr_notice("cnss: %pV", &vaf);
1197 break;
1198 case INFO_LOG:
1199 pr_info("cnss: %pV", &vaf);
1200 break;
1201 case DEBUG_LOG:
1202 case DEBUG_HI_LOG:
1203 pr_debug("cnss: %pV", &vaf);
1204 break;
1205 default:
1206 break;
1207 }
1208 }
1209
1210 va_end(va_args);
1211 }
1212 #endif
1213
cnss_debug_init(void)1214 int cnss_debug_init(void)
1215 {
1216 return cnss_ipc_logging_init();
1217 }
1218
cnss_debug_deinit(void)1219 void cnss_debug_deinit(void)
1220 {
1221 cnss_ipc_logging_deinit();
1222 }
1223