blob: 4d577aa1d285575b733cee1875c513758efacb74 [file] [log] [blame]
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -08001// SPDX-License-Identifier: GPL-2.0-only
2/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */
3
4#include <linux/err.h>
5#include <linux/seq_file.h>
6#include <linux/debugfs.h>
7#include "main.h"
Yue Ma710d5222019-09-20 16:35:10 -07008#include "bus.h"
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -08009#include "debug.h"
10#include "pci.h"
11
Yue Ma710d5222019-09-20 16:35:10 -070012#define MMIO_REG_ACCESS_MEM_TYPE 0xFF
13
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -080014void *cnss_ipc_log_context;
Yue Mafc1ff6f2019-07-10 18:09:13 -070015void *cnss_ipc_log_long_context;
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -080016
17static int cnss_pin_connect_show(struct seq_file *s, void *data)
18{
19 struct cnss_plat_data *cnss_priv = s->private;
20
21 seq_puts(s, "Pin connect results\n");
22 seq_printf(s, "FW power pin result: %04x\n",
23 cnss_priv->pin_result.fw_pwr_pin_result);
24 seq_printf(s, "FW PHY IO pin result: %04x\n",
25 cnss_priv->pin_result.fw_phy_io_pin_result);
26 seq_printf(s, "FW RF pin result: %04x\n",
27 cnss_priv->pin_result.fw_rf_pin_result);
28 seq_printf(s, "Host pin result: %04x\n",
29 cnss_priv->pin_result.host_pin_result);
30 seq_puts(s, "\n");
31
32 return 0;
33}
34
35static int cnss_pin_connect_open(struct inode *inode, struct file *file)
36{
37 return single_open(file, cnss_pin_connect_show, inode->i_private);
38}
39
40static const struct file_operations cnss_pin_connect_fops = {
41 .read = seq_read,
42 .release = single_release,
43 .open = cnss_pin_connect_open,
44 .owner = THIS_MODULE,
45 .llseek = seq_lseek,
46};
47
48static int cnss_stats_show_state(struct seq_file *s,
49 struct cnss_plat_data *plat_priv)
50{
51 enum cnss_driver_state i;
52 int skip = 0;
53 unsigned long state;
54
55 seq_printf(s, "\nState: 0x%lx(", plat_priv->driver_state);
56 for (i = 0, state = plat_priv->driver_state; state != 0;
57 state >>= 1, i++) {
58 if (!(state & 0x1))
59 continue;
60
61 if (skip++)
62 seq_puts(s, " | ");
63
64 switch (i) {
65 case CNSS_QMI_WLFW_CONNECTED:
66 seq_puts(s, "QMI_WLFW_CONNECTED");
67 continue;
68 case CNSS_FW_MEM_READY:
69 seq_puts(s, "FW_MEM_READY");
70 continue;
71 case CNSS_FW_READY:
72 seq_puts(s, "FW_READY");
73 continue;
74 case CNSS_COLD_BOOT_CAL:
75 seq_puts(s, "COLD_BOOT_CAL");
76 continue;
77 case CNSS_DRIVER_LOADING:
78 seq_puts(s, "DRIVER_LOADING");
79 continue;
80 case CNSS_DRIVER_UNLOADING:
81 seq_puts(s, "DRIVER_UNLOADING");
82 continue;
Yue Ma2b45e362019-05-02 15:59:06 -070083 case CNSS_DRIVER_IDLE_RESTART:
84 seq_puts(s, "IDLE_RESTART");
85 continue;
86 case CNSS_DRIVER_IDLE_SHUTDOWN:
87 seq_puts(s, "IDLE_SHUTDOWN");
88 continue;
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -080089 case CNSS_DRIVER_PROBED:
90 seq_puts(s, "DRIVER_PROBED");
91 continue;
92 case CNSS_DRIVER_RECOVERY:
93 seq_puts(s, "DRIVER_RECOVERY");
94 continue;
95 case CNSS_FW_BOOT_RECOVERY:
96 seq_puts(s, "FW_BOOT_RECOVERY");
97 continue;
98 case CNSS_DEV_ERR_NOTIFY:
99 seq_puts(s, "DEV_ERR");
100 continue;
101 case CNSS_DRIVER_DEBUG:
102 seq_puts(s, "DRIVER_DEBUG");
103 continue;
Yuanyuan Liu659d5f32019-01-25 14:29:22 -0800104 case CNSS_COEX_CONNECTED:
105 seq_puts(s, "COEX_CONNECTED");
106 continue;
Yuanyuan Liucdb04072019-06-06 11:18:49 -0700107 case CNSS_IMS_CONNECTED:
108 seq_puts(s, "IMS_CONNECTED");
109 continue;
Yue Maa1c93222019-07-25 16:59:57 -0700110 case CNSS_IN_SUSPEND_RESUME:
111 seq_puts(s, "IN_SUSPEND_RESUME");
112 continue;
Yue Ma89c36cf2019-09-24 18:11:24 -0700113 case CNSS_IN_REBOOT:
114 seq_puts(s, "IN_REBOOT");
115 continue;
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800116 }
117
118 seq_printf(s, "UNKNOWN-%d", i);
119 }
120 seq_puts(s, ")\n");
121
122 return 0;
123}
124
125static int cnss_stats_show(struct seq_file *s, void *data)
126{
127 struct cnss_plat_data *plat_priv = s->private;
128
129 cnss_stats_show_state(s, plat_priv);
130
131 return 0;
132}
133
134static int cnss_stats_open(struct inode *inode, struct file *file)
135{
136 return single_open(file, cnss_stats_show, inode->i_private);
137}
138
139static const struct file_operations cnss_stats_fops = {
140 .read = seq_read,
141 .release = single_release,
142 .open = cnss_stats_open,
143 .owner = THIS_MODULE,
144 .llseek = seq_lseek,
145};
146
147static ssize_t cnss_dev_boot_debug_write(struct file *fp,
148 const char __user *user_buf,
149 size_t count, loff_t *off)
150{
151 struct cnss_plat_data *plat_priv =
152 ((struct seq_file *)fp->private_data)->private;
153 struct cnss_pci_data *pci_priv;
154 char buf[64];
155 char *cmd;
156 unsigned int len = 0;
157 int ret = 0;
158
159 if (!plat_priv)
160 return -ENODEV;
161
162 pci_priv = plat_priv->bus_priv;
163 if (!pci_priv)
164 return -ENODEV;
165
166 len = min(count, sizeof(buf) - 1);
167 if (copy_from_user(buf, user_buf, len))
168 return -EFAULT;
169
170 buf[len] = '\0';
171 cmd = buf;
172
173 if (sysfs_streq(cmd, "on")) {
174 ret = cnss_power_on_device(plat_priv);
175 } else if (sysfs_streq(cmd, "off")) {
176 cnss_power_off_device(plat_priv);
177 } else if (sysfs_streq(cmd, "enumerate")) {
178 ret = cnss_pci_init(plat_priv);
179 } else if (sysfs_streq(cmd, "download")) {
180 set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
181 ret = cnss_pci_start_mhi(pci_priv);
182 } else if (sysfs_streq(cmd, "linkup")) {
183 ret = cnss_resume_pci_link(pci_priv);
184 } else if (sysfs_streq(cmd, "linkdown")) {
185 ret = cnss_suspend_pci_link(pci_priv);
186 } else if (sysfs_streq(cmd, "powerup")) {
187 set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
188 ret = cnss_driver_event_post(plat_priv,
189 CNSS_DRIVER_EVENT_POWER_UP,
190 CNSS_EVENT_SYNC, NULL);
191 } else if (sysfs_streq(cmd, "shutdown")) {
192 ret = cnss_driver_event_post(plat_priv,
193 CNSS_DRIVER_EVENT_POWER_DOWN,
194 0, NULL);
195 clear_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
196 } else if (sysfs_streq(cmd, "assert")) {
197 ret = cnss_force_fw_assert(&pci_priv->pci_dev->dev);
198 } else {
199 cnss_pr_err("Device boot debugfs command is invalid\n");
200 ret = -EINVAL;
201 }
202
Yue Mac2e5e5e2019-07-29 12:02:36 -0700203 if (ret < 0)
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800204 return ret;
205
206 return count;
207}
208
209static int cnss_dev_boot_debug_show(struct seq_file *s, void *data)
210{
211 seq_puts(s, "\nUsage: echo <action> > <debugfs_path>/cnss/dev_boot\n");
212 seq_puts(s, "<action> can be one of below:\n");
213 seq_puts(s, "on: turn on device power, assert WLAN_EN\n");
214 seq_puts(s, "off: de-assert WLAN_EN, turn off device power\n");
215 seq_puts(s, "enumerate: de-assert PERST, enumerate PCIe\n");
216 seq_puts(s, "download: download FW and do QMI handshake with FW\n");
217 seq_puts(s, "linkup: bring up PCIe link\n");
218 seq_puts(s, "linkdown: bring down PCIe link\n");
219 seq_puts(s, "powerup: full power on sequence to boot device, download FW and do QMI handshake with FW\n");
220 seq_puts(s, "shutdown: full power off sequence to shutdown device\n");
221 seq_puts(s, "assert: trigger firmware assert\n");
222
223 return 0;
224}
225
226static int cnss_dev_boot_debug_open(struct inode *inode, struct file *file)
227{
228 return single_open(file, cnss_dev_boot_debug_show, inode->i_private);
229}
230
231static const struct file_operations cnss_dev_boot_debug_fops = {
232 .read = seq_read,
233 .write = cnss_dev_boot_debug_write,
234 .release = single_release,
235 .open = cnss_dev_boot_debug_open,
236 .owner = THIS_MODULE,
237 .llseek = seq_lseek,
238};
239
240static int cnss_reg_read_debug_show(struct seq_file *s, void *data)
241{
242 struct cnss_plat_data *plat_priv = s->private;
243
244 mutex_lock(&plat_priv->dev_lock);
245 if (!plat_priv->diag_reg_read_buf) {
246 seq_puts(s, "\nUsage: echo <mem_type> <offset> <data_len> > <debugfs_path>/cnss/reg_read\n");
Yue Ma710d5222019-09-20 16:35:10 -0700247 seq_puts(s, "Use mem_type = 0xff for register read by IO access, data_len will be ignored\n");
248 seq_puts(s, "Use other mem_type for register read by QMI\n");
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800249 mutex_unlock(&plat_priv->dev_lock);
250 return 0;
251 }
252
253 seq_printf(s, "\nRegister read, address: 0x%x memory type: 0x%x length: 0x%x\n\n",
254 plat_priv->diag_reg_read_addr,
255 plat_priv->diag_reg_read_mem_type,
256 plat_priv->diag_reg_read_len);
257
258 seq_hex_dump(s, "", DUMP_PREFIX_OFFSET, 32, 4,
259 plat_priv->diag_reg_read_buf,
260 plat_priv->diag_reg_read_len, false);
261
262 plat_priv->diag_reg_read_len = 0;
263 kfree(plat_priv->diag_reg_read_buf);
264 plat_priv->diag_reg_read_buf = NULL;
265 mutex_unlock(&plat_priv->dev_lock);
266
267 return 0;
268}
269
270static ssize_t cnss_reg_read_debug_write(struct file *fp,
271 const char __user *user_buf,
272 size_t count, loff_t *off)
273{
274 struct cnss_plat_data *plat_priv =
275 ((struct seq_file *)fp->private_data)->private;
276 char buf[64];
277 char *sptr, *token;
278 unsigned int len = 0;
279 u32 reg_offset, mem_type;
Yue Ma710d5222019-09-20 16:35:10 -0700280 u32 data_len = 0, reg_val = 0;
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800281 u8 *reg_buf = NULL;
282 const char *delim = " ";
283 int ret = 0;
284
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800285 len = min(count, sizeof(buf) - 1);
286 if (copy_from_user(buf, user_buf, len))
287 return -EFAULT;
288
289 buf[len] = '\0';
290 sptr = buf;
291
292 token = strsep(&sptr, delim);
293 if (!token)
294 return -EINVAL;
295
296 if (!sptr)
297 return -EINVAL;
298
299 if (kstrtou32(token, 0, &mem_type))
300 return -EINVAL;
301
302 token = strsep(&sptr, delim);
303 if (!token)
304 return -EINVAL;
305
306 if (!sptr)
307 return -EINVAL;
308
309 if (kstrtou32(token, 0, &reg_offset))
310 return -EINVAL;
311
312 token = strsep(&sptr, delim);
313 if (!token)
314 return -EINVAL;
315
316 if (kstrtou32(token, 0, &data_len))
317 return -EINVAL;
318
Yue Ma710d5222019-09-20 16:35:10 -0700319 if (mem_type == MMIO_REG_ACCESS_MEM_TYPE) {
320 ret = cnss_bus_debug_reg_read(plat_priv, reg_offset, &reg_val);
321 if (ret)
322 return ret;
323 cnss_pr_dbg("Read 0x%x from register offset 0x%x\n", reg_val,
324 reg_offset);
325 return count;
326 }
327
328 if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
329 cnss_pr_err("Firmware is not ready yet\n");
330 return -EINVAL;
331 }
332
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800333 mutex_lock(&plat_priv->dev_lock);
334 kfree(plat_priv->diag_reg_read_buf);
335 plat_priv->diag_reg_read_buf = NULL;
336
337 reg_buf = kzalloc(data_len, GFP_KERNEL);
338 if (!reg_buf) {
339 mutex_unlock(&plat_priv->dev_lock);
340 return -ENOMEM;
341 }
342
343 ret = cnss_wlfw_athdiag_read_send_sync(plat_priv, reg_offset,
344 mem_type, data_len,
345 reg_buf);
346 if (ret) {
347 kfree(reg_buf);
348 mutex_unlock(&plat_priv->dev_lock);
349 return ret;
350 }
351
352 plat_priv->diag_reg_read_addr = reg_offset;
353 plat_priv->diag_reg_read_mem_type = mem_type;
354 plat_priv->diag_reg_read_len = data_len;
355 plat_priv->diag_reg_read_buf = reg_buf;
356 mutex_unlock(&plat_priv->dev_lock);
357
358 return count;
359}
360
361static int cnss_reg_read_debug_open(struct inode *inode, struct file *file)
362{
363 return single_open(file, cnss_reg_read_debug_show, inode->i_private);
364}
365
366static const struct file_operations cnss_reg_read_debug_fops = {
367 .read = seq_read,
368 .write = cnss_reg_read_debug_write,
369 .open = cnss_reg_read_debug_open,
370 .owner = THIS_MODULE,
371 .llseek = seq_lseek,
372};
373
374static int cnss_reg_write_debug_show(struct seq_file *s, void *data)
375{
376 seq_puts(s, "\nUsage: echo <mem_type> <offset> <reg_val> > <debugfs_path>/cnss/reg_write\n");
Yue Ma710d5222019-09-20 16:35:10 -0700377 seq_puts(s, "Use mem_type = 0xff for register write by IO access\n");
378 seq_puts(s, "Use other mem_type for register write by QMI\n");
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800379
380 return 0;
381}
382
383static ssize_t cnss_reg_write_debug_write(struct file *fp,
384 const char __user *user_buf,
385 size_t count, loff_t *off)
386{
387 struct cnss_plat_data *plat_priv =
388 ((struct seq_file *)fp->private_data)->private;
389 char buf[64];
390 char *sptr, *token;
391 unsigned int len = 0;
392 u32 reg_offset, mem_type, reg_val;
393 const char *delim = " ";
394 int ret = 0;
395
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800396 len = min(count, sizeof(buf) - 1);
397 if (copy_from_user(buf, user_buf, len))
398 return -EFAULT;
399
400 buf[len] = '\0';
401 sptr = buf;
402
403 token = strsep(&sptr, delim);
404 if (!token)
405 return -EINVAL;
406
407 if (!sptr)
408 return -EINVAL;
409
410 if (kstrtou32(token, 0, &mem_type))
411 return -EINVAL;
412
413 token = strsep(&sptr, delim);
414 if (!token)
415 return -EINVAL;
416
417 if (!sptr)
418 return -EINVAL;
419
420 if (kstrtou32(token, 0, &reg_offset))
421 return -EINVAL;
422
423 token = strsep(&sptr, delim);
424 if (!token)
425 return -EINVAL;
426
427 if (kstrtou32(token, 0, &reg_val))
428 return -EINVAL;
429
Yue Ma710d5222019-09-20 16:35:10 -0700430 if (mem_type == MMIO_REG_ACCESS_MEM_TYPE) {
431 ret = cnss_bus_debug_reg_write(plat_priv, reg_offset, reg_val);
432 if (ret)
433 return ret;
434 cnss_pr_dbg("Wrote 0x%x to register offset 0x%x\n", reg_val,
435 reg_offset);
436 return count;
437 }
438
439 if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
440 cnss_pr_err("Firmware is not ready yet\n");
441 return -EINVAL;
442 }
443
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800444 ret = cnss_wlfw_athdiag_write_send_sync(plat_priv, reg_offset, mem_type,
445 sizeof(u32),
446 (u8 *)&reg_val);
447 if (ret)
448 return ret;
449
450 return count;
451}
452
453static int cnss_reg_write_debug_open(struct inode *inode, struct file *file)
454{
455 return single_open(file, cnss_reg_write_debug_show, inode->i_private);
456}
457
458static const struct file_operations cnss_reg_write_debug_fops = {
459 .read = seq_read,
460 .write = cnss_reg_write_debug_write,
461 .open = cnss_reg_write_debug_open,
462 .owner = THIS_MODULE,
463 .llseek = seq_lseek,
464};
465
466static ssize_t cnss_runtime_pm_debug_write(struct file *fp,
467 const char __user *user_buf,
468 size_t count, loff_t *off)
469{
470 struct cnss_plat_data *plat_priv =
471 ((struct seq_file *)fp->private_data)->private;
472 struct cnss_pci_data *pci_priv;
473 char buf[64];
474 char *cmd;
475 unsigned int len = 0;
476 int ret = 0;
477
478 if (!plat_priv)
479 return -ENODEV;
480
481 pci_priv = plat_priv->bus_priv;
482 if (!pci_priv)
483 return -ENODEV;
484
485 len = min(count, sizeof(buf) - 1);
486 if (copy_from_user(buf, user_buf, len))
487 return -EFAULT;
488
489 buf[len] = '\0';
490 cmd = buf;
491
492 if (sysfs_streq(cmd, "usage_count")) {
493 cnss_pci_pm_runtime_show_usage_count(pci_priv);
Yue Ma6476dc92019-05-03 11:21:37 -0700494 } else if (sysfs_streq(cmd, "request_resume")) {
495 ret = cnss_pci_pm_request_resume(pci_priv);
496 } else if (sysfs_streq(cmd, "resume")) {
497 ret = cnss_pci_pm_runtime_resume(pci_priv);
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800498 } else if (sysfs_streq(cmd, "get")) {
499 ret = cnss_pci_pm_runtime_get(pci_priv);
500 } else if (sysfs_streq(cmd, "get_noresume")) {
501 cnss_pci_pm_runtime_get_noresume(pci_priv);
502 } else if (sysfs_streq(cmd, "put_autosuspend")) {
503 ret = cnss_pci_pm_runtime_put_autosuspend(pci_priv);
504 } else if (sysfs_streq(cmd, "put_noidle")) {
505 cnss_pci_pm_runtime_put_noidle(pci_priv);
506 } else if (sysfs_streq(cmd, "mark_last_busy")) {
507 cnss_pci_pm_runtime_mark_last_busy(pci_priv);
Yue Macdd61612019-08-23 11:58:31 -0700508 } else if (sysfs_streq(cmd, "resume_bus")) {
509 cnss_pci_resume_bus(pci_priv);
510 } else if (sysfs_streq(cmd, "suspend_bus")) {
511 cnss_pci_suspend_bus(pci_priv);
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800512 } else {
513 cnss_pr_err("Runtime PM debugfs command is invalid\n");
514 ret = -EINVAL;
515 }
516
Yue Mac2e5e5e2019-07-29 12:02:36 -0700517 if (ret < 0)
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800518 return ret;
519
520 return count;
521}
522
523static int cnss_runtime_pm_debug_show(struct seq_file *s, void *data)
524{
525 seq_puts(s, "\nUsage: echo <action> > <debugfs_path>/cnss/runtime_pm\n");
526 seq_puts(s, "<action> can be one of below:\n");
527 seq_puts(s, "usage_count: get runtime PM usage count\n");
Yue Mac2e5e5e2019-07-29 12:02:36 -0700528 seq_puts(s, "reques_resume: do async runtime PM resume\n");
529 seq_puts(s, "resume: do sync runtime PM resume\n");
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800530 seq_puts(s, "get: do runtime PM get\n");
531 seq_puts(s, "get_noresume: do runtime PM get noresume\n");
532 seq_puts(s, "put_noidle: do runtime PM put noidle\n");
533 seq_puts(s, "put_autosuspend: do runtime PM put autosuspend\n");
534 seq_puts(s, "mark_last_busy: do runtime PM mark last busy\n");
Yue Macdd61612019-08-23 11:58:31 -0700535 seq_puts(s, "resume_bus: do bus resume only\n");
536 seq_puts(s, "suspend_bus: do bus suspend only\n");
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800537
538 return 0;
539}
540
541static int cnss_runtime_pm_debug_open(struct inode *inode, struct file *file)
542{
543 return single_open(file, cnss_runtime_pm_debug_show, inode->i_private);
544}
545
546static const struct file_operations cnss_runtime_pm_debug_fops = {
547 .read = seq_read,
548 .write = cnss_runtime_pm_debug_write,
549 .open = cnss_runtime_pm_debug_open,
550 .owner = THIS_MODULE,
551 .llseek = seq_lseek,
552};
553
554static ssize_t cnss_control_params_debug_write(struct file *fp,
555 const char __user *user_buf,
556 size_t count, loff_t *off)
557{
558 struct cnss_plat_data *plat_priv =
559 ((struct seq_file *)fp->private_data)->private;
560 char buf[64];
561 char *sptr, *token;
562 char *cmd;
563 u32 val;
564 unsigned int len = 0;
565 const char *delim = " ";
566
567 if (!plat_priv)
568 return -ENODEV;
569
570 len = min(count, sizeof(buf) - 1);
571 if (copy_from_user(buf, user_buf, len))
572 return -EFAULT;
573
574 buf[len] = '\0';
575 sptr = buf;
576
577 token = strsep(&sptr, delim);
578 if (!token)
579 return -EINVAL;
580 if (!sptr)
581 return -EINVAL;
582 cmd = token;
583
584 token = strsep(&sptr, delim);
585 if (!token)
586 return -EINVAL;
587 if (kstrtou32(token, 0, &val))
588 return -EINVAL;
589
590 if (strcmp(cmd, "quirks") == 0)
591 plat_priv->ctrl_params.quirks = val;
592 else if (strcmp(cmd, "mhi_timeout") == 0)
593 plat_priv->ctrl_params.mhi_timeout = val;
Yue Mab246f1e2019-09-10 14:49:25 -0700594 else if (strcmp(cmd, "mhi_m2_timeout") == 0)
595 plat_priv->ctrl_params.mhi_m2_timeout = val;
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800596 else if (strcmp(cmd, "qmi_timeout") == 0)
597 plat_priv->ctrl_params.qmi_timeout = val;
598 else if (strcmp(cmd, "bdf_type") == 0)
599 plat_priv->ctrl_params.bdf_type = val;
Yue Ma8ee81752019-07-10 11:56:51 -0700600 else if (strcmp(cmd, "time_sync_period") == 0)
601 plat_priv->ctrl_params.time_sync_period = val;
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800602 else
603 return -EINVAL;
604
605 return count;
606}
607
608static int cnss_show_quirks_state(struct seq_file *s,
609 struct cnss_plat_data *plat_priv)
610{
611 enum cnss_debug_quirks i;
612 int skip = 0;
613 unsigned long state;
614
615 seq_printf(s, "quirks: 0x%lx (", plat_priv->ctrl_params.quirks);
616 for (i = 0, state = plat_priv->ctrl_params.quirks;
617 state != 0; state >>= 1, i++) {
618 if (!(state & 0x1))
619 continue;
620 if (skip++)
621 seq_puts(s, " | ");
622
623 switch (i) {
624 case LINK_DOWN_SELF_RECOVERY:
625 seq_puts(s, "LINK_DOWN_SELF_RECOVERY");
626 continue;
627 case SKIP_DEVICE_BOOT:
628 seq_puts(s, "SKIP_DEVICE_BOOT");
629 continue;
630 case USE_CORE_ONLY_FW:
631 seq_puts(s, "USE_CORE_ONLY_FW");
632 continue;
633 case SKIP_RECOVERY:
634 seq_puts(s, "SKIP_RECOVERY");
635 continue;
636 case QMI_BYPASS:
637 seq_puts(s, "QMI_BYPASS");
638 continue;
639 case ENABLE_WALTEST:
640 seq_puts(s, "WALTEST");
641 continue;
642 case ENABLE_PCI_LINK_DOWN_PANIC:
643 seq_puts(s, "PCI_LINK_DOWN_PANIC");
644 continue;
645 case FBC_BYPASS:
646 seq_puts(s, "FBC_BYPASS");
647 continue;
648 case ENABLE_DAEMON_SUPPORT:
649 seq_puts(s, "DAEMON_SUPPORT");
650 continue;
Yue Maf28455c2019-04-09 18:17:03 -0700651 case DISABLE_DRV:
652 seq_puts(s, "DISABLE_DRV");
653 continue;
Yuanyuan Liu9830ab72019-09-09 10:53:23 -0700654 case DISABLE_IO_COHERENCY:
655 seq_puts(s, "DISABLE_IO_COHERENCY");
656 continue;
Yue Ma46b142a2019-10-11 14:00:45 -0700657 case IGNORE_PCI_LINK_FAILURE:
658 seq_puts(s, "IGNORE_PCI_LINK_FAILURE");
659 continue;
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800660 }
661
662 seq_printf(s, "UNKNOWN-%d", i);
663 }
664 seq_puts(s, ")\n");
665 return 0;
666}
667
668static int cnss_control_params_debug_show(struct seq_file *s, void *data)
669{
670 struct cnss_plat_data *cnss_priv = s->private;
671
672 seq_puts(s, "\nUsage: echo <params_name> <value> > <debugfs_path>/cnss/control_params\n");
673 seq_puts(s, "<params_name> can be one of below:\n");
674 seq_puts(s, "quirks: Debug quirks for driver\n");
675 seq_puts(s, "mhi_timeout: Timeout for MHI operation in milliseconds\n");
676 seq_puts(s, "qmi_timeout: Timeout for QMI message in milliseconds\n");
677 seq_puts(s, "bdf_type: Type of board data file to be downloaded\n");
Yue Ma8ee81752019-07-10 11:56:51 -0700678 seq_puts(s, "time_sync_period: Time period to do time sync with device in milliseconds\n");
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800679
680 seq_puts(s, "\nCurrent value:\n");
681 cnss_show_quirks_state(s, cnss_priv);
682 seq_printf(s, "mhi_timeout: %u\n", cnss_priv->ctrl_params.mhi_timeout);
Yue Mab246f1e2019-09-10 14:49:25 -0700683 seq_printf(s, "mhi_m2_timeout: %u\n",
684 cnss_priv->ctrl_params.mhi_m2_timeout);
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800685 seq_printf(s, "qmi_timeout: %u\n", cnss_priv->ctrl_params.qmi_timeout);
686 seq_printf(s, "bdf_type: %u\n", cnss_priv->ctrl_params.bdf_type);
Yue Ma8ee81752019-07-10 11:56:51 -0700687 seq_printf(s, "time_sync_period: %u\n",
688 cnss_priv->ctrl_params.time_sync_period);
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800689
690 return 0;
691}
692
693static int cnss_control_params_debug_open(struct inode *inode,
694 struct file *file)
695{
696 return single_open(file, cnss_control_params_debug_show,
697 inode->i_private);
698}
699
700static const struct file_operations cnss_control_params_debug_fops = {
701 .read = seq_read,
702 .write = cnss_control_params_debug_write,
703 .open = cnss_control_params_debug_open,
704 .owner = THIS_MODULE,
705 .llseek = seq_lseek,
706};
707
Yuanyuan Liu420c76b2019-06-10 16:11:18 -0700708static ssize_t cnss_dynamic_feature_write(struct file *fp,
709 const char __user *user_buf,
710 size_t count, loff_t *off)
711{
712 struct cnss_plat_data *plat_priv =
713 ((struct seq_file *)fp->private_data)->private;
714 int ret = 0;
715 u64 val;
716
717 ret = kstrtou64_from_user(user_buf, count, 0, &val);
718 if (ret)
719 return ret;
720
721 plat_priv->dynamic_feature = val;
722 ret = cnss_wlfw_dynamic_feature_mask_send_sync(plat_priv);
723 if (ret < 0)
724 return ret;
725
726 return count;
727}
728
729static int cnss_dynamic_feature_show(struct seq_file *s, void *data)
730{
731 struct cnss_plat_data *cnss_priv = s->private;
732
733 seq_printf(s, "dynamic_feature: 0x%llx\n", cnss_priv->dynamic_feature);
734
735 return 0;
736}
737
738static int cnss_dynamic_feature_open(struct inode *inode,
739 struct file *file)
740{
741 return single_open(file, cnss_dynamic_feature_show,
742 inode->i_private);
743}
744
745static const struct file_operations cnss_dynamic_feature_fops = {
746 .read = seq_read,
747 .write = cnss_dynamic_feature_write,
748 .open = cnss_dynamic_feature_open,
749 .owner = THIS_MODULE,
750 .llseek = seq_lseek,
751};
752
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800753#ifdef CONFIG_CNSS2_DEBUG
754static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
755{
756 struct dentry *root_dentry = plat_priv->root_dentry;
757
758 debugfs_create_file("dev_boot", 0600, root_dentry, plat_priv,
759 &cnss_dev_boot_debug_fops);
760 debugfs_create_file("reg_read", 0600, root_dentry, plat_priv,
761 &cnss_reg_read_debug_fops);
762 debugfs_create_file("reg_write", 0600, root_dentry, plat_priv,
763 &cnss_reg_write_debug_fops);
764 debugfs_create_file("runtime_pm", 0600, root_dentry, plat_priv,
765 &cnss_runtime_pm_debug_fops);
766 debugfs_create_file("control_params", 0600, root_dentry, plat_priv,
767 &cnss_control_params_debug_fops);
Yuanyuan Liu420c76b2019-06-10 16:11:18 -0700768 debugfs_create_file("dynamic_feature", 0600, root_dentry, plat_priv,
769 &cnss_dynamic_feature_fops);
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800770
771 return 0;
772}
773#else
774static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
775{
776 return 0;
777}
778#endif
779
780int cnss_debugfs_create(struct cnss_plat_data *plat_priv)
781{
782 int ret = 0;
783 struct dentry *root_dentry;
784
785 root_dentry = debugfs_create_dir("cnss", 0);
786 if (IS_ERR(root_dentry)) {
787 ret = PTR_ERR(root_dentry);
788 cnss_pr_err("Unable to create debugfs %d\n", ret);
789 goto out;
790 }
791
792 plat_priv->root_dentry = root_dentry;
793
794 debugfs_create_file("pin_connect_result", 0644, root_dentry, plat_priv,
795 &cnss_pin_connect_fops);
796 debugfs_create_file("stats", 0644, root_dentry, plat_priv,
797 &cnss_stats_fops);
798
799 cnss_create_debug_only_node(plat_priv);
800
801out:
802 return ret;
803}
804
805void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv)
806{
807 debugfs_remove_recursive(plat_priv->root_dentry);
808}
809
810int cnss_debug_init(void)
811{
812 cnss_ipc_log_context = ipc_log_context_create(CNSS_IPC_LOG_PAGES,
813 "cnss", 0);
814 if (!cnss_ipc_log_context) {
Yue Mafc1ff6f2019-07-10 18:09:13 -0700815 cnss_pr_err("Unable to create IPC log context\n");
816 return -EINVAL;
817 }
818
819 cnss_ipc_log_long_context = ipc_log_context_create(CNSS_IPC_LOG_PAGES,
820 "cnss-long", 0);
821 if (!cnss_ipc_log_long_context) {
822 cnss_pr_err("Unable to create IPC long log context\n");
823 ipc_log_context_destroy(cnss_ipc_log_context);
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800824 return -EINVAL;
825 }
826
827 return 0;
828}
829
830void cnss_debug_deinit(void)
831{
Yue Mafc1ff6f2019-07-10 18:09:13 -0700832 if (cnss_ipc_log_long_context) {
833 ipc_log_context_destroy(cnss_ipc_log_long_context);
834 cnss_ipc_log_long_context = NULL;
835 }
836
Yuanyuan Liud5ec14c2019-01-03 11:25:40 -0800837 if (cnss_ipc_log_context) {
838 ipc_log_context_destroy(cnss_ipc_log_context);
839 cnss_ipc_log_context = NULL;
840 }
841}