xref: /wlan-dirver/platform/cnss2/debug.c (revision 5b29459b17821e3d9b1e6fcc7bd0a69222e90f53)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2016-2021, 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 "bus.h"
9 #include "debug.h"
10 #include "pci.h"
11 
12 #define MMIO_REG_ACCESS_MEM_TYPE		0xFF
13 #define MMIO_REG_RAW_ACCESS_MEM_TYPE		0xFE
14 
15 #if IS_ENABLED(CONFIG_IPC_LOGGING)
16 void *cnss_ipc_log_context;
17 void *cnss_ipc_log_long_context;
18 #endif
19 
20 static int cnss_pin_connect_show(struct seq_file *s, void *data)
21 {
22 	struct cnss_plat_data *cnss_priv = s->private;
23 
24 	seq_puts(s, "Pin connect results\n");
25 	seq_printf(s, "FW power pin result: %04x\n",
26 		   cnss_priv->pin_result.fw_pwr_pin_result);
27 	seq_printf(s, "FW PHY IO pin result: %04x\n",
28 		   cnss_priv->pin_result.fw_phy_io_pin_result);
29 	seq_printf(s, "FW RF pin result: %04x\n",
30 		   cnss_priv->pin_result.fw_rf_pin_result);
31 	seq_printf(s, "Host pin result: %04x\n",
32 		   cnss_priv->pin_result.host_pin_result);
33 	seq_puts(s, "\n");
34 
35 	return 0;
36 }
37 
38 static int cnss_pin_connect_open(struct inode *inode, struct file *file)
39 {
40 	return single_open(file, cnss_pin_connect_show, inode->i_private);
41 }
42 
43 static const struct file_operations cnss_pin_connect_fops = {
44 	.read		= seq_read,
45 	.release	= single_release,
46 	.open		= cnss_pin_connect_open,
47 	.owner		= THIS_MODULE,
48 	.llseek		= seq_lseek,
49 };
50 
51 static int cnss_stats_show_state(struct seq_file *s,
52 				 struct cnss_plat_data *plat_priv)
53 {
54 	enum cnss_driver_state i;
55 	int skip = 0;
56 	unsigned long state;
57 
58 	seq_printf(s, "\nState: 0x%lx(", plat_priv->driver_state);
59 	for (i = 0, state = plat_priv->driver_state; state != 0;
60 	     state >>= 1, i++) {
61 		if (!(state & 0x1))
62 			continue;
63 
64 		if (skip++)
65 			seq_puts(s, " | ");
66 
67 		switch (i) {
68 		case CNSS_QMI_WLFW_CONNECTED:
69 			seq_puts(s, "QMI_WLFW_CONNECTED");
70 			continue;
71 		case CNSS_FW_MEM_READY:
72 			seq_puts(s, "FW_MEM_READY");
73 			continue;
74 		case CNSS_FW_READY:
75 			seq_puts(s, "FW_READY");
76 			continue;
77 		case CNSS_IN_COLD_BOOT_CAL:
78 			seq_puts(s, "IN_COLD_BOOT_CAL");
79 			continue;
80 		case CNSS_DRIVER_LOADING:
81 			seq_puts(s, "DRIVER_LOADING");
82 			continue;
83 		case CNSS_DRIVER_UNLOADING:
84 			seq_puts(s, "DRIVER_UNLOADING");
85 			continue;
86 		case CNSS_DRIVER_IDLE_RESTART:
87 			seq_puts(s, "IDLE_RESTART");
88 			continue;
89 		case CNSS_DRIVER_IDLE_SHUTDOWN:
90 			seq_puts(s, "IDLE_SHUTDOWN");
91 			continue;
92 		case CNSS_DRIVER_PROBED:
93 			seq_puts(s, "DRIVER_PROBED");
94 			continue;
95 		case CNSS_DRIVER_RECOVERY:
96 			seq_puts(s, "DRIVER_RECOVERY");
97 			continue;
98 		case CNSS_FW_BOOT_RECOVERY:
99 			seq_puts(s, "FW_BOOT_RECOVERY");
100 			continue;
101 		case CNSS_DEV_ERR_NOTIFY:
102 			seq_puts(s, "DEV_ERR");
103 			continue;
104 		case CNSS_DRIVER_DEBUG:
105 			seq_puts(s, "DRIVER_DEBUG");
106 			continue;
107 		case CNSS_COEX_CONNECTED:
108 			seq_puts(s, "COEX_CONNECTED");
109 			continue;
110 		case CNSS_IMS_CONNECTED:
111 			seq_puts(s, "IMS_CONNECTED");
112 			continue;
113 		case CNSS_IN_SUSPEND_RESUME:
114 			seq_puts(s, "IN_SUSPEND_RESUME");
115 			continue;
116 		case CNSS_IN_REBOOT:
117 			seq_puts(s, "IN_REBOOT");
118 			continue;
119 		case CNSS_COLD_BOOT_CAL_DONE:
120 			seq_puts(s, "COLD_BOOT_CAL_DONE");
121 			continue;
122 		case CNSS_IN_PANIC:
123 			seq_puts(s, "IN_PANIC");
124 			continue;
125 		case CNSS_QMI_DEL_SERVER:
126 			seq_puts(s, "DEL_SERVER_IN_PROGRESS");
127 			continue;
128 		case CNSS_QMI_DMS_CONNECTED:
129 			seq_puts(s, "DMS_CONNECTED");
130 			continue;
131 		case CNSS_DAEMON_CONNECTED:
132 			seq_puts(s, "DAEMON_CONNECTED");
133 			continue;
134 		case CNSS_PCI_PROBE_DONE:
135 			seq_puts(s, "PCI PROBE DONE");
136 			continue;
137 		}
138 
139 		seq_printf(s, "UNKNOWN-%d", i);
140 	}
141 	seq_puts(s, ")\n");
142 
143 	return 0;
144 }
145 
146 static int cnss_stats_show(struct seq_file *s, void *data)
147 {
148 	struct cnss_plat_data *plat_priv = s->private;
149 
150 	cnss_stats_show_state(s, plat_priv);
151 
152 	return 0;
153 }
154 
155 static int cnss_stats_open(struct inode *inode, struct file *file)
156 {
157 	return single_open(file, cnss_stats_show, inode->i_private);
158 }
159 
160 static const struct file_operations cnss_stats_fops = {
161 	.read		= seq_read,
162 	.release	= single_release,
163 	.open		= cnss_stats_open,
164 	.owner		= THIS_MODULE,
165 	.llseek		= seq_lseek,
166 };
167 
168 static ssize_t cnss_dev_boot_debug_write(struct file *fp,
169 					 const char __user *user_buf,
170 					 size_t count, loff_t *off)
171 {
172 	struct cnss_plat_data *plat_priv =
173 		((struct seq_file *)fp->private_data)->private;
174 	struct cnss_pci_data *pci_priv;
175 	char buf[64];
176 	char *cmd;
177 	unsigned int len = 0;
178 	int ret = 0;
179 
180 	if (!plat_priv)
181 		return -ENODEV;
182 
183 	len = min(count, sizeof(buf) - 1);
184 	if (copy_from_user(buf, user_buf, len))
185 		return -EFAULT;
186 
187 	buf[len] = '\0';
188 	cmd = buf;
189 	cnss_pr_dbg("Received dev_boot debug command: %s\n", cmd);
190 
191 	if (sysfs_streq(cmd, "on")) {
192 		ret = cnss_power_on_device(plat_priv);
193 	} else if (sysfs_streq(cmd, "off")) {
194 		cnss_power_off_device(plat_priv);
195 	} else if (sysfs_streq(cmd, "enumerate")) {
196 		ret = cnss_pci_init(plat_priv);
197 	} else if (sysfs_streq(cmd, "powerup")) {
198 		set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
199 		ret = cnss_driver_event_post(plat_priv,
200 					     CNSS_DRIVER_EVENT_POWER_UP,
201 					     CNSS_EVENT_SYNC, NULL);
202 	} else if (sysfs_streq(cmd, "shutdown")) {
203 		ret = cnss_driver_event_post(plat_priv,
204 					     CNSS_DRIVER_EVENT_POWER_DOWN,
205 					     0, NULL);
206 		clear_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
207 	} else {
208 		pci_priv = plat_priv->bus_priv;
209 		if (!pci_priv)
210 			return -ENODEV;
211 
212 		if (sysfs_streq(cmd, "download")) {
213 			set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
214 			ret = cnss_pci_start_mhi(pci_priv);
215 		} else if (sysfs_streq(cmd, "linkup")) {
216 			ret = cnss_resume_pci_link(pci_priv);
217 		} else if (sysfs_streq(cmd, "linkdown")) {
218 			ret = cnss_suspend_pci_link(pci_priv);
219 		} else if (sysfs_streq(cmd, "assert")) {
220 			cnss_pr_info("FW Assert triggered for debug\n");
221 			ret = cnss_force_fw_assert(&pci_priv->pci_dev->dev);
222 		} else if (sysfs_streq(cmd, "set_cbc_done")) {
223 			cnss_pr_dbg("Force set cold boot cal done status\n");
224 			set_bit(CNSS_COLD_BOOT_CAL_DONE,
225 				&plat_priv->driver_state);
226 		} else {
227 			cnss_pr_err("Device boot debugfs command is invalid\n");
228 			ret = -EINVAL;
229 		}
230 	}
231 
232 	if (ret < 0)
233 		return ret;
234 
235 	return count;
236 }
237 
238 static int cnss_dev_boot_debug_show(struct seq_file *s, void *data)
239 {
240 	seq_puts(s, "\nUsage: echo <action> > <debugfs_path>/cnss/dev_boot\n");
241 	seq_puts(s, "<action> can be one of below:\n");
242 	seq_puts(s, "on: turn on device power, assert WLAN_EN\n");
243 	seq_puts(s, "off: de-assert WLAN_EN, turn off device power\n");
244 	seq_puts(s, "enumerate: de-assert PERST, enumerate PCIe\n");
245 	seq_puts(s, "download: download FW and do QMI handshake with FW\n");
246 	seq_puts(s, "linkup: bring up PCIe link\n");
247 	seq_puts(s, "linkdown: bring down PCIe link\n");
248 	seq_puts(s, "powerup: full power on sequence to boot device, download FW and do QMI handshake with FW\n");
249 	seq_puts(s, "shutdown: full power off sequence to shutdown device\n");
250 	seq_puts(s, "assert: trigger firmware assert\n");
251 	seq_puts(s, "set_cbc_done: Set cold boot calibration done status\n");
252 
253 	return 0;
254 }
255 
256 static int cnss_dev_boot_debug_open(struct inode *inode, struct file *file)
257 {
258 	return single_open(file, cnss_dev_boot_debug_show, inode->i_private);
259 }
260 
261 static const struct file_operations cnss_dev_boot_debug_fops = {
262 	.read		= seq_read,
263 	.write		= cnss_dev_boot_debug_write,
264 	.release	= single_release,
265 	.open		= cnss_dev_boot_debug_open,
266 	.owner		= THIS_MODULE,
267 	.llseek		= seq_lseek,
268 };
269 
270 static int cnss_reg_read_debug_show(struct seq_file *s, void *data)
271 {
272 	struct cnss_plat_data *plat_priv = s->private;
273 
274 	mutex_lock(&plat_priv->dev_lock);
275 	if (!plat_priv->diag_reg_read_buf) {
276 		seq_puts(s, "\nUsage: echo <mem_type> <offset> <data_len> > <debugfs_path>/cnss/reg_read\n");
277 		seq_puts(s, "Use mem_type = 0xff for register read by IO access, data_len will be ignored\n");
278 		seq_puts(s, "Use mem_type = 0xfe for register read by raw IO access which skips sanity checks, data_len will be ignored\n");
279 		seq_puts(s, "Use other mem_type for register read by QMI\n");
280 		mutex_unlock(&plat_priv->dev_lock);
281 		return 0;
282 	}
283 
284 	seq_printf(s, "\nRegister read, address: 0x%x memory type: 0x%x length: 0x%x\n\n",
285 		   plat_priv->diag_reg_read_addr,
286 		   plat_priv->diag_reg_read_mem_type,
287 		   plat_priv->diag_reg_read_len);
288 
289 	seq_hex_dump(s, "", DUMP_PREFIX_OFFSET, 32, 4,
290 		     plat_priv->diag_reg_read_buf,
291 		     plat_priv->diag_reg_read_len, false);
292 
293 	plat_priv->diag_reg_read_len = 0;
294 	kfree(plat_priv->diag_reg_read_buf);
295 	plat_priv->diag_reg_read_buf = NULL;
296 	mutex_unlock(&plat_priv->dev_lock);
297 
298 	return 0;
299 }
300 
301 static ssize_t cnss_reg_read_debug_write(struct file *fp,
302 					 const char __user *user_buf,
303 					 size_t count, loff_t *off)
304 {
305 	struct cnss_plat_data *plat_priv =
306 		((struct seq_file *)fp->private_data)->private;
307 	char buf[64];
308 	char *sptr, *token;
309 	unsigned int len = 0;
310 	u32 reg_offset, mem_type;
311 	u32 data_len = 0, reg_val = 0;
312 	u8 *reg_buf = NULL;
313 	const char *delim = " ";
314 	int ret = 0;
315 
316 	len = min(count, sizeof(buf) - 1);
317 	if (copy_from_user(buf, user_buf, len))
318 		return -EFAULT;
319 
320 	buf[len] = '\0';
321 	sptr = buf;
322 
323 	token = strsep(&sptr, delim);
324 	if (!token)
325 		return -EINVAL;
326 
327 	if (!sptr)
328 		return -EINVAL;
329 
330 	if (kstrtou32(token, 0, &mem_type))
331 		return -EINVAL;
332 
333 	token = strsep(&sptr, delim);
334 	if (!token)
335 		return -EINVAL;
336 
337 	if (!sptr)
338 		return -EINVAL;
339 
340 	if (kstrtou32(token, 0, &reg_offset))
341 		return -EINVAL;
342 
343 	token = strsep(&sptr, delim);
344 	if (!token)
345 		return -EINVAL;
346 
347 	if (kstrtou32(token, 0, &data_len))
348 		return -EINVAL;
349 
350 	if (mem_type == MMIO_REG_ACCESS_MEM_TYPE ||
351 	    mem_type == MMIO_REG_RAW_ACCESS_MEM_TYPE) {
352 		ret = cnss_bus_debug_reg_read(plat_priv, reg_offset, &reg_val,
353 					      mem_type ==
354 					      MMIO_REG_RAW_ACCESS_MEM_TYPE);
355 		if (ret)
356 			return ret;
357 		cnss_pr_dbg("Read 0x%x from register offset 0x%x\n", reg_val,
358 			    reg_offset);
359 		return count;
360 	}
361 
362 	if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
363 		cnss_pr_err("Firmware is not ready yet\n");
364 		return -EINVAL;
365 	}
366 
367 	mutex_lock(&plat_priv->dev_lock);
368 	kfree(plat_priv->diag_reg_read_buf);
369 	plat_priv->diag_reg_read_buf = NULL;
370 
371 	reg_buf = kzalloc(data_len, GFP_KERNEL);
372 	if (!reg_buf) {
373 		mutex_unlock(&plat_priv->dev_lock);
374 		return -ENOMEM;
375 	}
376 
377 	ret = cnss_wlfw_athdiag_read_send_sync(plat_priv, reg_offset,
378 					       mem_type, data_len,
379 					       reg_buf);
380 	if (ret) {
381 		kfree(reg_buf);
382 		mutex_unlock(&plat_priv->dev_lock);
383 		return ret;
384 	}
385 
386 	plat_priv->diag_reg_read_addr = reg_offset;
387 	plat_priv->diag_reg_read_mem_type = mem_type;
388 	plat_priv->diag_reg_read_len = data_len;
389 	plat_priv->diag_reg_read_buf = reg_buf;
390 	mutex_unlock(&plat_priv->dev_lock);
391 
392 	return count;
393 }
394 
395 static int cnss_reg_read_debug_open(struct inode *inode, struct file *file)
396 {
397 	return single_open(file, cnss_reg_read_debug_show, inode->i_private);
398 }
399 
400 static const struct file_operations cnss_reg_read_debug_fops = {
401 	.read		= seq_read,
402 	.write		= cnss_reg_read_debug_write,
403 	.open		= cnss_reg_read_debug_open,
404 	.owner		= THIS_MODULE,
405 	.llseek		= seq_lseek,
406 };
407 
408 static int cnss_reg_write_debug_show(struct seq_file *s, void *data)
409 {
410 	seq_puts(s, "\nUsage: echo <mem_type> <offset> <reg_val> > <debugfs_path>/cnss/reg_write\n");
411 	seq_puts(s, "Use mem_type = 0xff for register write by IO access\n");
412 	seq_puts(s, "Use mem_type = 0xfe for register write by raw IO access which skips sanity checks\n");
413 	seq_puts(s, "Use other mem_type for register write by QMI\n");
414 
415 	return 0;
416 }
417 
418 static ssize_t cnss_reg_write_debug_write(struct file *fp,
419 					  const char __user *user_buf,
420 					  size_t count, loff_t *off)
421 {
422 	struct cnss_plat_data *plat_priv =
423 		((struct seq_file *)fp->private_data)->private;
424 	char buf[64];
425 	char *sptr, *token;
426 	unsigned int len = 0;
427 	u32 reg_offset, mem_type, reg_val;
428 	const char *delim = " ";
429 	int ret = 0;
430 
431 	len = min(count, sizeof(buf) - 1);
432 	if (copy_from_user(buf, user_buf, len))
433 		return -EFAULT;
434 
435 	buf[len] = '\0';
436 	sptr = buf;
437 
438 	token = strsep(&sptr, delim);
439 	if (!token)
440 		return -EINVAL;
441 
442 	if (!sptr)
443 		return -EINVAL;
444 
445 	if (kstrtou32(token, 0, &mem_type))
446 		return -EINVAL;
447 
448 	token = strsep(&sptr, delim);
449 	if (!token)
450 		return -EINVAL;
451 
452 	if (!sptr)
453 		return -EINVAL;
454 
455 	if (kstrtou32(token, 0, &reg_offset))
456 		return -EINVAL;
457 
458 	token = strsep(&sptr, delim);
459 	if (!token)
460 		return -EINVAL;
461 
462 	if (kstrtou32(token, 0, &reg_val))
463 		return -EINVAL;
464 
465 	if (mem_type == MMIO_REG_ACCESS_MEM_TYPE ||
466 	    mem_type == MMIO_REG_RAW_ACCESS_MEM_TYPE) {
467 		ret = cnss_bus_debug_reg_write(plat_priv, reg_offset, reg_val,
468 					       mem_type ==
469 					       MMIO_REG_RAW_ACCESS_MEM_TYPE);
470 		if (ret)
471 			return ret;
472 		cnss_pr_dbg("Wrote 0x%x to register offset 0x%x\n", reg_val,
473 			    reg_offset);
474 		return count;
475 	}
476 
477 	if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
478 		cnss_pr_err("Firmware is not ready yet\n");
479 		return -EINVAL;
480 	}
481 
482 	ret = cnss_wlfw_athdiag_write_send_sync(plat_priv, reg_offset, mem_type,
483 						sizeof(u32),
484 						(u8 *)&reg_val);
485 	if (ret)
486 		return ret;
487 
488 	return count;
489 }
490 
491 static int cnss_reg_write_debug_open(struct inode *inode, struct file *file)
492 {
493 	return single_open(file, cnss_reg_write_debug_show, inode->i_private);
494 }
495 
496 static const struct file_operations cnss_reg_write_debug_fops = {
497 	.read		= seq_read,
498 	.write		= cnss_reg_write_debug_write,
499 	.open		= cnss_reg_write_debug_open,
500 	.owner		= THIS_MODULE,
501 	.llseek		= seq_lseek,
502 };
503 
504 static ssize_t cnss_runtime_pm_debug_write(struct file *fp,
505 					   const char __user *user_buf,
506 					   size_t count, loff_t *off)
507 {
508 	struct cnss_plat_data *plat_priv =
509 		((struct seq_file *)fp->private_data)->private;
510 	struct cnss_pci_data *pci_priv;
511 	char buf[64];
512 	char *cmd;
513 	unsigned int len = 0;
514 	int ret = 0;
515 
516 	if (!plat_priv)
517 		return -ENODEV;
518 
519 	pci_priv = plat_priv->bus_priv;
520 	if (!pci_priv)
521 		return -ENODEV;
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 	cmd = buf;
529 
530 	if (sysfs_streq(cmd, "usage_count")) {
531 		cnss_pci_pm_runtime_show_usage_count(pci_priv);
532 	} else if (sysfs_streq(cmd, "request_resume")) {
533 		ret = cnss_pci_pm_request_resume(pci_priv);
534 	} else if (sysfs_streq(cmd, "resume")) {
535 		ret = cnss_pci_pm_runtime_resume(pci_priv);
536 	} else if (sysfs_streq(cmd, "get")) {
537 		ret = cnss_pci_pm_runtime_get(pci_priv, RTPM_ID_CNSS);
538 	} else if (sysfs_streq(cmd, "get_noresume")) {
539 		cnss_pci_pm_runtime_get_noresume(pci_priv, RTPM_ID_CNSS);
540 	} else if (sysfs_streq(cmd, "put_autosuspend")) {
541 		ret = cnss_pci_pm_runtime_put_autosuspend(pci_priv,
542 							  RTPM_ID_CNSS);
543 	} else if (sysfs_streq(cmd, "put_noidle")) {
544 		cnss_pci_pm_runtime_put_noidle(pci_priv, RTPM_ID_CNSS);
545 	} else if (sysfs_streq(cmd, "mark_last_busy")) {
546 		cnss_pci_pm_runtime_mark_last_busy(pci_priv);
547 	} else if (sysfs_streq(cmd, "resume_bus")) {
548 		cnss_pci_resume_bus(pci_priv);
549 	} else if (sysfs_streq(cmd, "suspend_bus")) {
550 		cnss_pci_suspend_bus(pci_priv);
551 	} else {
552 		cnss_pr_err("Runtime PM debugfs command is invalid\n");
553 		ret = -EINVAL;
554 	}
555 
556 	if (ret < 0)
557 		return ret;
558 
559 	return count;
560 }
561 
562 static int cnss_runtime_pm_debug_show(struct seq_file *s, void *data)
563 {
564 	struct cnss_plat_data *plat_priv = s->private;
565 	struct cnss_pci_data *pci_priv;
566 	int i;
567 
568 	if (!plat_priv)
569 		return -ENODEV;
570 
571 	pci_priv = plat_priv->bus_priv;
572 	if (!pci_priv)
573 		return -ENODEV;
574 
575 	seq_puts(s, "\nUsage: echo <action> > <debugfs_path>/cnss/runtime_pm\n");
576 	seq_puts(s, "<action> can be one of below:\n");
577 	seq_puts(s, "usage_count: get runtime PM usage count\n");
578 	seq_puts(s, "reques_resume: do async runtime PM resume\n");
579 	seq_puts(s, "resume: do sync runtime PM resume\n");
580 	seq_puts(s, "get: do runtime PM get\n");
581 	seq_puts(s, "get_noresume: do runtime PM get noresume\n");
582 	seq_puts(s, "put_noidle: do runtime PM put noidle\n");
583 	seq_puts(s, "put_autosuspend: do runtime PM put autosuspend\n");
584 	seq_puts(s, "mark_last_busy: do runtime PM mark last busy\n");
585 	seq_puts(s, "resume_bus: do bus resume only\n");
586 	seq_puts(s, "suspend_bus: do bus suspend only\n");
587 
588 	seq_puts(s, "\nStats:\n");
589 	seq_printf(s, "%s: %u\n", "get count",
590 		   atomic_read(&pci_priv->pm_stats.runtime_get));
591 	seq_printf(s, "%s: %u\n", "put count",
592 		   atomic_read(&pci_priv->pm_stats.runtime_put));
593 	seq_printf(s, "%-10s%-10s%-10s%-15s%-15s\n",
594 		   "id:", "get",  "put", "get time(us)", "put time(us)");
595 	for (i = 0; i < RTPM_ID_MAX; i++) {
596 		seq_printf(s, "%d%-9s", i, ":");
597 		seq_printf(s, "%-10d",
598 			   atomic_read(&pci_priv->pm_stats.runtime_get_id[i]));
599 		seq_printf(s, "%-10d",
600 			   atomic_read(&pci_priv->pm_stats.runtime_put_id[i]));
601 		seq_printf(s, "%-15llu",
602 			   pci_priv->pm_stats.runtime_get_timestamp_id[i]);
603 		seq_printf(s, "%-15llu\n",
604 			   pci_priv->pm_stats.runtime_put_timestamp_id[i]);
605 	}
606 
607 	return 0;
608 }
609 
610 static int cnss_runtime_pm_debug_open(struct inode *inode, struct file *file)
611 {
612 	return single_open(file, cnss_runtime_pm_debug_show, inode->i_private);
613 }
614 
615 static const struct file_operations cnss_runtime_pm_debug_fops = {
616 	.read		= seq_read,
617 	.write		= cnss_runtime_pm_debug_write,
618 	.open		= cnss_runtime_pm_debug_open,
619 	.owner		= THIS_MODULE,
620 	.llseek		= seq_lseek,
621 };
622 
623 static ssize_t cnss_control_params_debug_write(struct file *fp,
624 					       const char __user *user_buf,
625 					       size_t count, loff_t *off)
626 {
627 	struct cnss_plat_data *plat_priv =
628 		((struct seq_file *)fp->private_data)->private;
629 	char buf[64];
630 	char *sptr, *token;
631 	char *cmd;
632 	u32 val;
633 	unsigned int len = 0;
634 	const char *delim = " ";
635 
636 	if (!plat_priv)
637 		return -ENODEV;
638 
639 	len = min(count, sizeof(buf) - 1);
640 	if (copy_from_user(buf, user_buf, len))
641 		return -EFAULT;
642 
643 	buf[len] = '\0';
644 	sptr = buf;
645 
646 	token = strsep(&sptr, delim);
647 	if (!token)
648 		return -EINVAL;
649 	if (!sptr)
650 		return -EINVAL;
651 	cmd = token;
652 
653 	token = strsep(&sptr, delim);
654 	if (!token)
655 		return -EINVAL;
656 	if (kstrtou32(token, 0, &val))
657 		return -EINVAL;
658 
659 	if (strcmp(cmd, "quirks") == 0)
660 		plat_priv->ctrl_params.quirks = val;
661 	else if (strcmp(cmd, "mhi_timeout") == 0)
662 		plat_priv->ctrl_params.mhi_timeout = val;
663 	else if (strcmp(cmd, "mhi_m2_timeout") == 0)
664 		plat_priv->ctrl_params.mhi_m2_timeout = val;
665 	else if (strcmp(cmd, "qmi_timeout") == 0)
666 		plat_priv->ctrl_params.qmi_timeout = val;
667 	else if (strcmp(cmd, "bdf_type") == 0)
668 		plat_priv->ctrl_params.bdf_type = val;
669 	else if (strcmp(cmd, "time_sync_period") == 0)
670 		plat_priv->ctrl_params.time_sync_period = val;
671 	else
672 		return -EINVAL;
673 
674 	return count;
675 }
676 
677 static int cnss_show_quirks_state(struct seq_file *s,
678 				  struct cnss_plat_data *plat_priv)
679 {
680 	enum cnss_debug_quirks i;
681 	int skip = 0;
682 	unsigned long state;
683 
684 	seq_printf(s, "quirks: 0x%lx (", plat_priv->ctrl_params.quirks);
685 	for (i = 0, state = plat_priv->ctrl_params.quirks;
686 	     state != 0; state >>= 1, i++) {
687 		if (!(state & 0x1))
688 			continue;
689 		if (skip++)
690 			seq_puts(s, " | ");
691 
692 		switch (i) {
693 		case LINK_DOWN_SELF_RECOVERY:
694 			seq_puts(s, "LINK_DOWN_SELF_RECOVERY");
695 			continue;
696 		case SKIP_DEVICE_BOOT:
697 			seq_puts(s, "SKIP_DEVICE_BOOT");
698 			continue;
699 		case USE_CORE_ONLY_FW:
700 			seq_puts(s, "USE_CORE_ONLY_FW");
701 			continue;
702 		case SKIP_RECOVERY:
703 			seq_puts(s, "SKIP_RECOVERY");
704 			continue;
705 		case QMI_BYPASS:
706 			seq_puts(s, "QMI_BYPASS");
707 			continue;
708 		case ENABLE_WALTEST:
709 			seq_puts(s, "WALTEST");
710 			continue;
711 		case ENABLE_PCI_LINK_DOWN_PANIC:
712 			seq_puts(s, "PCI_LINK_DOWN_PANIC");
713 			continue;
714 		case FBC_BYPASS:
715 			seq_puts(s, "FBC_BYPASS");
716 			continue;
717 		case ENABLE_DAEMON_SUPPORT:
718 			seq_puts(s, "DAEMON_SUPPORT");
719 			continue;
720 		case DISABLE_DRV:
721 			seq_puts(s, "DISABLE_DRV");
722 			continue;
723 		case DISABLE_IO_COHERENCY:
724 			seq_puts(s, "DISABLE_IO_COHERENCY");
725 			continue;
726 		case IGNORE_PCI_LINK_FAILURE:
727 			seq_puts(s, "IGNORE_PCI_LINK_FAILURE");
728 			continue;
729 		case DISABLE_TIME_SYNC:
730 			seq_puts(s, "DISABLE_TIME_SYNC");
731 			continue;
732 		}
733 
734 		seq_printf(s, "UNKNOWN-%d", i);
735 	}
736 	seq_puts(s, ")\n");
737 	return 0;
738 }
739 
740 static int cnss_control_params_debug_show(struct seq_file *s, void *data)
741 {
742 	struct cnss_plat_data *cnss_priv = s->private;
743 
744 	seq_puts(s, "\nUsage: echo <params_name> <value> > <debugfs_path>/cnss/control_params\n");
745 	seq_puts(s, "<params_name> can be one of below:\n");
746 	seq_puts(s, "quirks: Debug quirks for driver\n");
747 	seq_puts(s, "mhi_timeout: Timeout for MHI operation in milliseconds\n");
748 	seq_puts(s, "qmi_timeout: Timeout for QMI message in milliseconds\n");
749 	seq_puts(s, "bdf_type: Type of board data file to be downloaded\n");
750 	seq_puts(s, "time_sync_period: Time period to do time sync with device in milliseconds\n");
751 
752 	seq_puts(s, "\nCurrent value:\n");
753 	cnss_show_quirks_state(s, cnss_priv);
754 	seq_printf(s, "mhi_timeout: %u\n", cnss_priv->ctrl_params.mhi_timeout);
755 	seq_printf(s, "mhi_m2_timeout: %u\n",
756 		   cnss_priv->ctrl_params.mhi_m2_timeout);
757 	seq_printf(s, "qmi_timeout: %u\n", cnss_priv->ctrl_params.qmi_timeout);
758 	seq_printf(s, "bdf_type: %u\n", cnss_priv->ctrl_params.bdf_type);
759 	seq_printf(s, "time_sync_period: %u\n",
760 		   cnss_priv->ctrl_params.time_sync_period);
761 
762 	return 0;
763 }
764 
765 static int cnss_control_params_debug_open(struct inode *inode,
766 					  struct file *file)
767 {
768 	return single_open(file, cnss_control_params_debug_show,
769 			   inode->i_private);
770 }
771 
772 static const struct file_operations cnss_control_params_debug_fops = {
773 	.read = seq_read,
774 	.write = cnss_control_params_debug_write,
775 	.open = cnss_control_params_debug_open,
776 	.owner = THIS_MODULE,
777 	.llseek = seq_lseek,
778 };
779 
780 static ssize_t cnss_dynamic_feature_write(struct file *fp,
781 					  const char __user *user_buf,
782 					  size_t count, loff_t *off)
783 {
784 	struct cnss_plat_data *plat_priv =
785 		((struct seq_file *)fp->private_data)->private;
786 	int ret = 0;
787 	u64 val;
788 
789 	ret = kstrtou64_from_user(user_buf, count, 0, &val);
790 	if (ret)
791 		return ret;
792 
793 	plat_priv->dynamic_feature = val;
794 	ret = cnss_wlfw_dynamic_feature_mask_send_sync(plat_priv);
795 	if (ret < 0)
796 		return ret;
797 
798 	return count;
799 }
800 
801 static int cnss_dynamic_feature_show(struct seq_file *s, void *data)
802 {
803 	struct cnss_plat_data *cnss_priv = s->private;
804 
805 	seq_printf(s, "dynamic_feature: 0x%llx\n", cnss_priv->dynamic_feature);
806 
807 	return 0;
808 }
809 
810 static int cnss_dynamic_feature_open(struct inode *inode,
811 				     struct file *file)
812 {
813 	return single_open(file, cnss_dynamic_feature_show,
814 			   inode->i_private);
815 }
816 
817 static const struct file_operations cnss_dynamic_feature_fops = {
818 	.read = seq_read,
819 	.write = cnss_dynamic_feature_write,
820 	.open = cnss_dynamic_feature_open,
821 	.owner = THIS_MODULE,
822 	.llseek = seq_lseek,
823 };
824 
825 #ifdef CONFIG_DEBUG_FS
826 #ifdef CONFIG_CNSS2_DEBUG
827 static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
828 {
829 	struct dentry *root_dentry = plat_priv->root_dentry;
830 
831 	debugfs_create_file("dev_boot", 0600, root_dentry, plat_priv,
832 			    &cnss_dev_boot_debug_fops);
833 	debugfs_create_file("reg_read", 0600, root_dentry, plat_priv,
834 			    &cnss_reg_read_debug_fops);
835 	debugfs_create_file("reg_write", 0600, root_dentry, plat_priv,
836 			    &cnss_reg_write_debug_fops);
837 	debugfs_create_file("runtime_pm", 0600, root_dentry, plat_priv,
838 			    &cnss_runtime_pm_debug_fops);
839 	debugfs_create_file("control_params", 0600, root_dentry, plat_priv,
840 			    &cnss_control_params_debug_fops);
841 	debugfs_create_file("dynamic_feature", 0600, root_dentry, plat_priv,
842 			    &cnss_dynamic_feature_fops);
843 
844 	return 0;
845 }
846 #else
847 static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
848 {
849 	return 0;
850 }
851 #endif
852 
853 int cnss_debugfs_create(struct cnss_plat_data *plat_priv)
854 {
855 	int ret = 0;
856 	struct dentry *root_dentry;
857 
858 	root_dentry = debugfs_create_dir("cnss", 0);
859 	if (IS_ERR(root_dentry)) {
860 		ret = PTR_ERR(root_dentry);
861 		cnss_pr_err("Unable to create debugfs %d\n", ret);
862 		goto out;
863 	}
864 
865 	plat_priv->root_dentry = root_dentry;
866 
867 	debugfs_create_file("pin_connect_result", 0644, root_dentry, plat_priv,
868 			    &cnss_pin_connect_fops);
869 	debugfs_create_file("stats", 0644, root_dentry, plat_priv,
870 			    &cnss_stats_fops);
871 
872 	cnss_create_debug_only_node(plat_priv);
873 
874 out:
875 	return ret;
876 }
877 
878 void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv)
879 {
880 	debugfs_remove_recursive(plat_priv->root_dentry);
881 }
882 #else
883 int cnss_debugfs_create(struct cnss_plat_data *plat_priv)
884 {
885 	plat_priv->root_dentry = NULL;
886 	return 0;
887 }
888 
889 void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv)
890 {
891 }
892 #endif
893 
894 #if IS_ENABLED(CONFIG_IPC_LOGGING)
895 void cnss_debug_ipc_log_print(void *log_ctx, char *process, const char *fn,
896 			      const char *log_level, char *fmt, ...)
897 {
898 	struct va_format vaf;
899 	va_list va_args;
900 
901 	va_start(va_args, fmt);
902 	vaf.fmt = fmt;
903 	vaf.va = &va_args;
904 
905 	if (log_level)
906 		printk("%scnss: %pV", log_level, &vaf);
907 
908 	ipc_log_string(log_ctx, "[%s] %s: %pV", process, fn, &vaf);
909 
910 	va_end(va_args);
911 }
912 
913 static int cnss_ipc_logging_init(void)
914 {
915 	cnss_ipc_log_context = ipc_log_context_create(CNSS_IPC_LOG_PAGES,
916 						      "cnss", 0);
917 	if (!cnss_ipc_log_context) {
918 		cnss_pr_err("Unable to create IPC log context\n");
919 		return -EINVAL;
920 	}
921 
922 	cnss_ipc_log_long_context = ipc_log_context_create(CNSS_IPC_LOG_PAGES,
923 							   "cnss-long", 0);
924 	if (!cnss_ipc_log_long_context) {
925 		cnss_pr_err("Unable to create IPC long log context\n");
926 		ipc_log_context_destroy(cnss_ipc_log_context);
927 		return -EINVAL;
928 	}
929 
930 	return 0;
931 }
932 
933 static void cnss_ipc_logging_deinit(void)
934 {
935 	if (cnss_ipc_log_long_context) {
936 		ipc_log_context_destroy(cnss_ipc_log_long_context);
937 		cnss_ipc_log_long_context = NULL;
938 	}
939 
940 	if (cnss_ipc_log_context) {
941 		ipc_log_context_destroy(cnss_ipc_log_context);
942 		cnss_ipc_log_context = NULL;
943 	}
944 }
945 #else
946 static int cnss_ipc_logging_init(void) { return 0; }
947 static void cnss_ipc_logging_deinit(void) {}
948 void cnss_debug_ipc_log_print(void *log_ctx, char *process, const char *fn,
949 			      const char *log_level, char *fmt, ...)
950 {
951 	struct va_format vaf;
952 	va_list va_args;
953 
954 	va_start(va_args, fmt);
955 	vaf.fmt = fmt;
956 	vaf.va = &va_args;
957 
958 	if (log_level)
959 		printk("%scnss: %pV", log_level, &vaf);
960 
961 	va_end(va_args);
962 }
963 #endif
964 
965 int cnss_debug_init(void)
966 {
967 	return cnss_ipc_logging_init();
968 }
969 
970 void cnss_debug_deinit(void)
971 {
972 	cnss_ipc_logging_deinit();
973 }
974