xref: /wlan-driver/platform/cnss2/debug.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
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, &reg_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, &reg_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, &reg_offset))
548 		return -EINVAL;
549 
550 	token = strsep(&sptr, delim);
551 	if (!token)
552 		return -EINVAL;
553 
554 	if (kstrtou32(token, 0, &reg_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 *)&reg_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