1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
4 * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
5 */
6 #include <linux/err.h>
7 #include <linux/seq_file.h>
8 #include <linux/debugfs.h>
9 #include <linux/uaccess.h>
10 #include <linux/slab.h>
11 #include "main.h"
12 #include "debug.h"
13 #include "qmi.h"
14 #include "power.h"
15
16 void *icnss_ipc_log_context;
17 void *icnss_ipc_log_long_context;
18 void *icnss_ipc_log_smp2p_context;
19 void *icnss_ipc_soc_wake_context;
20
icnss_regwrite_write(struct file * fp,const char __user * user_buf,size_t count,loff_t * off)21 static ssize_t icnss_regwrite_write(struct file *fp,
22 const char __user *user_buf,
23 size_t count, loff_t *off)
24 {
25 struct icnss_priv *priv =
26 ((struct seq_file *)fp->private_data)->private;
27 char buf[64];
28 char *sptr, *token;
29 unsigned int len = 0;
30 uint32_t reg_offset, mem_type, reg_val;
31 const char *delim = " ";
32 int ret = 0;
33
34 if (!test_bit(ICNSS_FW_READY, &priv->state) ||
35 !test_bit(ICNSS_POWER_ON, &priv->state))
36 return -EINVAL;
37
38 len = min(count, sizeof(buf) - 1);
39 if (copy_from_user(buf, user_buf, len))
40 return -EFAULT;
41
42 buf[len] = '\0';
43 sptr = buf;
44
45 token = strsep(&sptr, delim);
46 if (!token)
47 return -EINVAL;
48
49 if (!sptr)
50 return -EINVAL;
51
52 if (kstrtou32(token, 0, &mem_type))
53 return -EINVAL;
54
55 token = strsep(&sptr, delim);
56 if (!token)
57 return -EINVAL;
58
59 if (!sptr)
60 return -EINVAL;
61
62 if (kstrtou32(token, 0, ®_offset))
63 return -EINVAL;
64
65 token = strsep(&sptr, delim);
66 if (!token)
67 return -EINVAL;
68
69 if (kstrtou32(token, 0, ®_val))
70 return -EINVAL;
71
72 ret = wlfw_athdiag_write_send_sync_msg(priv, reg_offset, mem_type,
73 sizeof(uint32_t),
74 (uint8_t *)®_val);
75 if (ret)
76 return ret;
77
78 return count;
79 }
80
icnss_regwrite_show(struct seq_file * s,void * data)81 static int icnss_regwrite_show(struct seq_file *s, void *data)
82 {
83 struct icnss_priv *priv = s->private;
84
85 seq_puts(s, "Usage: echo <mem_type> <offset> <reg_val> > <debugfs>/icnss/reg_write\n");
86
87 if (!test_bit(ICNSS_FW_READY, &priv->state))
88 seq_puts(s, "Firmware is not ready yet!, wait for FW READY\n");
89
90 return 0;
91 }
92
icnss_regwrite_open(struct inode * inode,struct file * file)93 static int icnss_regwrite_open(struct inode *inode, struct file *file)
94 {
95 return single_open(file, icnss_regwrite_show, inode->i_private);
96 }
97
98 static const struct file_operations icnss_regwrite_fops = {
99 .read = seq_read,
100 .write = icnss_regwrite_write,
101 .open = icnss_regwrite_open,
102 .owner = THIS_MODULE,
103 .llseek = seq_lseek,
104 };
105
icnss_regread_show(struct seq_file * s,void * data)106 static int icnss_regread_show(struct seq_file *s, void *data)
107 {
108 struct icnss_priv *priv = s->private;
109
110 mutex_lock(&priv->dev_lock);
111 if (!priv->diag_reg_read_buf) {
112 seq_puts(s, "Usage: echo <mem_type> <offset> <data_len> > <debugfs>/icnss/reg_read\n");
113
114 if (!test_bit(ICNSS_FW_READY, &priv->state))
115 seq_puts(s, "Firmware is not ready yet!, wait for FW READY\n");
116
117 mutex_unlock(&priv->dev_lock);
118 return 0;
119 }
120
121 seq_printf(s, "REGREAD: Addr 0x%x Type 0x%x Length 0x%x\n",
122 priv->diag_reg_read_addr, priv->diag_reg_read_mem_type,
123 priv->diag_reg_read_len);
124
125 seq_hex_dump(s, "", DUMP_PREFIX_OFFSET, 32, 4, priv->diag_reg_read_buf,
126 priv->diag_reg_read_len, false);
127
128 priv->diag_reg_read_len = 0;
129 kfree(priv->diag_reg_read_buf);
130 priv->diag_reg_read_buf = NULL;
131 mutex_unlock(&priv->dev_lock);
132
133 return 0;
134 }
135
icnss_regread_open(struct inode * inode,struct file * file)136 static int icnss_regread_open(struct inode *inode, struct file *file)
137 {
138 return single_open(file, icnss_regread_show, inode->i_private);
139 }
140
icnss_reg_parse(const char __user * user_buf,size_t count,struct icnss_reg_info * reg_info_ptr)141 static ssize_t icnss_reg_parse(const char __user *user_buf, size_t count,
142 struct icnss_reg_info *reg_info_ptr)
143 {
144 char buf[64] = {0};
145 char *sptr = NULL, *token = NULL;
146 const char *delim = " ";
147 unsigned int len = 0;
148
149 if (user_buf == NULL)
150 return -EFAULT;
151
152 len = min(count, sizeof(buf) - 1);
153 if (copy_from_user(buf, user_buf, len))
154 return -EFAULT;
155
156 buf[len] = '\0';
157 sptr = buf;
158
159 token = strsep(&sptr, delim);
160 if (!token)
161 return -EINVAL;
162
163 if (!sptr)
164 return -EINVAL;
165
166 if (kstrtou32(token, 0, ®_info_ptr->mem_type))
167 return -EINVAL;
168
169 token = strsep(&sptr, delim);
170 if (!token)
171 return -EINVAL;
172
173 if (!sptr)
174 return -EINVAL;
175
176 if (kstrtou32(token, 0, ®_info_ptr->reg_offset))
177 return -EINVAL;
178
179 token = strsep(&sptr, delim);
180 if (!token)
181 return -EINVAL;
182
183 if (kstrtou32(token, 0, ®_info_ptr->data_len))
184 return -EINVAL;
185
186 if (reg_info_ptr->data_len == 0 ||
187 reg_info_ptr->data_len > WLFW_MAX_DATA_SIZE)
188 return -EINVAL;
189
190 return 0;
191 }
192
icnss_regread_write(struct file * fp,const char __user * user_buf,size_t count,loff_t * off)193 static ssize_t icnss_regread_write(struct file *fp, const char __user *user_buf,
194 size_t count, loff_t *off)
195 {
196 struct icnss_priv *priv =
197 ((struct seq_file *)fp->private_data)->private;
198 uint8_t *reg_buf = NULL;
199 int ret = 0;
200 struct icnss_reg_info reg_info;
201
202 if (!test_bit(ICNSS_FW_READY, &priv->state) ||
203 !test_bit(ICNSS_POWER_ON, &priv->state))
204 return -EINVAL;
205
206 ret = icnss_reg_parse(user_buf, count, ®_info);
207 if (ret)
208 return ret;
209
210 mutex_lock(&priv->dev_lock);
211 kfree(priv->diag_reg_read_buf);
212 priv->diag_reg_read_buf = NULL;
213
214 reg_buf = kzalloc(reg_info.data_len, GFP_KERNEL);
215 if (!reg_buf) {
216 mutex_unlock(&priv->dev_lock);
217 return -ENOMEM;
218 }
219
220 ret = wlfw_athdiag_read_send_sync_msg(priv, reg_info.reg_offset,
221 reg_info.mem_type,
222 reg_info.data_len,
223 reg_buf);
224 if (ret) {
225 kfree(reg_buf);
226 mutex_unlock(&priv->dev_lock);
227 return ret;
228 }
229
230 priv->diag_reg_read_addr = reg_info.reg_offset;
231 priv->diag_reg_read_mem_type = reg_info.mem_type;
232 priv->diag_reg_read_len = reg_info.data_len;
233 priv->diag_reg_read_buf = reg_buf;
234 mutex_unlock(&priv->dev_lock);
235
236 return count;
237 }
238
239 static const struct file_operations icnss_regread_fops = {
240 .read = seq_read,
241 .write = icnss_regread_write,
242 .open = icnss_regread_open,
243 .owner = THIS_MODULE,
244 .llseek = seq_lseek,
245 };
246
icnss_stats_write(struct file * fp,const char __user * buf,size_t count,loff_t * off)247 static ssize_t icnss_stats_write(struct file *fp, const char __user *buf,
248 size_t count, loff_t *off)
249 {
250 struct icnss_priv *priv =
251 ((struct seq_file *)fp->private_data)->private;
252 int ret;
253 u32 val;
254
255 ret = kstrtou32_from_user(buf, count, 0, &val);
256 if (ret)
257 return ret;
258
259 if (ret == 0)
260 memset(&priv->stats, 0, sizeof(priv->stats));
261
262 return count;
263 }
264
icnss_stats_show_rejuvenate_info(struct seq_file * s,struct icnss_priv * priv)265 static int icnss_stats_show_rejuvenate_info(struct seq_file *s,
266 struct icnss_priv *priv)
267 {
268 if (priv->stats.rejuvenate_ind) {
269 seq_puts(s, "\n<---------------- Rejuvenate Info ----------------->\n");
270 seq_printf(s, "Number of Rejuvenations: %u\n",
271 priv->stats.rejuvenate_ind);
272 seq_printf(s, "Cause for Rejuvenation: 0x%x\n",
273 priv->cause_for_rejuvenation);
274 seq_printf(s, "Requesting Sub-System: 0x%x\n",
275 priv->requesting_sub_system);
276 seq_printf(s, "Line Number: %u\n",
277 priv->line_number);
278 seq_printf(s, "Function Name: %s\n",
279 priv->function_name);
280 }
281
282 return 0;
283 }
284
icnss_stats_show_irqs(struct seq_file * s,struct icnss_priv * priv)285 static int icnss_stats_show_irqs(struct seq_file *s, struct icnss_priv *priv)
286 {
287 int i;
288
289 seq_puts(s, "\n<------------------ IRQ stats ------------------->\n");
290 seq_printf(s, "%4s %4s %8s %8s %8s %8s\n", "CE_ID", "IRQ", "Request",
291 "Free", "Enable", "Disable");
292 for (i = 0; i < ICNSS_MAX_IRQ_REGISTRATIONS; i++)
293 seq_printf(s, "%4d: %4u %8u %8u %8u %8u\n", i,
294 priv->ce_irqs[i], priv->stats.ce_irqs[i].request,
295 priv->stats.ce_irqs[i].free,
296 priv->stats.ce_irqs[i].enable,
297 priv->stats.ce_irqs[i].disable);
298
299 return 0;
300 }
301
icnss_stats_show_capability(struct seq_file * s,struct icnss_priv * priv)302 static int icnss_stats_show_capability(struct seq_file *s,
303 struct icnss_priv *priv)
304 {
305 if (test_bit(ICNSS_FW_READY, &priv->state)) {
306 seq_puts(s, "\n<---------------- FW Capability ----------------->\n");
307 seq_printf(s, "Chip ID: 0x%x\n", priv->chip_info.chip_id);
308 seq_printf(s, "Chip family: 0x%x\n",
309 priv->chip_info.chip_family);
310 seq_printf(s, "Board ID: 0x%x\n", priv->board_id);
311 seq_printf(s, "SOC Info: 0x%x\n", priv->soc_id);
312 seq_printf(s, "Firmware Version: 0x%x\n",
313 priv->fw_version_info.fw_version);
314 seq_printf(s, "Firmware Build Timestamp: %s\n",
315 priv->fw_version_info.fw_build_timestamp);
316 seq_printf(s, "Firmware Build ID: %s\n",
317 priv->fw_build_id);
318 seq_printf(s, "RD card chain cap: %d\n",
319 priv->rd_card_chain_cap);
320 seq_printf(s, "PHY HE channel width cap: %d\n",
321 priv->phy_he_channel_width_cap);
322 seq_printf(s, "PHY QAM cap: %d\n",
323 priv->phy_qam_cap);
324 }
325
326 return 0;
327 }
328
icnss_stats_show_events(struct seq_file * s,struct icnss_priv * priv)329 static int icnss_stats_show_events(struct seq_file *s, struct icnss_priv *priv)
330 {
331 int i;
332
333 seq_puts(s, "\n<----------------- Events stats ------------------->\n");
334 seq_printf(s, "%24s %16s %16s\n", "Events", "Posted", "Processed");
335 for (i = 0; i < ICNSS_DRIVER_EVENT_MAX; i++)
336 seq_printf(s, "%24s %16u %16u\n",
337 icnss_driver_event_to_str(i),
338 priv->stats.events[i].posted,
339 priv->stats.events[i].processed);
340
341 return 0;
342 }
343
icnss_get_serial_id(struct icnss_priv * priv)344 static u64 icnss_get_serial_id(struct icnss_priv *priv)
345 {
346 u32 msb = priv->serial_id.serial_id_msb;
347 u32 lsb = priv->serial_id.serial_id_lsb;
348
349 msb &= 0xFFFF;
350 return (((u64)msb << 32) | lsb);
351 }
352
icnss_stats_show_state(struct seq_file * s,struct icnss_priv * priv)353 static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
354 {
355 enum icnss_driver_state i;
356 int skip = 0;
357 unsigned long state;
358
359 seq_printf(s, "\nSerial Number: 0x%llx", icnss_get_serial_id(priv));
360 seq_printf(s, "\nState: 0x%lx(", priv->state);
361 for (i = 0, state = priv->state; state != 0; state >>= 1, i++) {
362
363 if (!(state & 0x1))
364 continue;
365
366 if (skip++)
367 seq_puts(s, " | ");
368
369 switch (i) {
370 case ICNSS_WLFW_CONNECTED:
371 seq_puts(s, "FW CONN");
372 continue;
373 case ICNSS_POWER_ON:
374 seq_puts(s, "POWER ON");
375 continue;
376 case ICNSS_FW_READY:
377 seq_puts(s, "FW READY");
378 continue;
379 case ICNSS_DRIVER_PROBED:
380 seq_puts(s, "DRIVER PROBED");
381 continue;
382 case ICNSS_FW_TEST_MODE:
383 seq_puts(s, "FW TEST MODE");
384 continue;
385 case ICNSS_PM_SUSPEND:
386 seq_puts(s, "PM SUSPEND");
387 continue;
388 case ICNSS_PM_SUSPEND_NOIRQ:
389 seq_puts(s, "PM SUSPEND NOIRQ");
390 continue;
391 case ICNSS_SSR_REGISTERED:
392 seq_puts(s, "SSR REGISTERED");
393 continue;
394 case ICNSS_PDR_REGISTERED:
395 seq_puts(s, "PDR REGISTERED");
396 continue;
397 case ICNSS_PD_RESTART:
398 seq_puts(s, "PD RESTART");
399 continue;
400 case ICNSS_WLFW_EXISTS:
401 seq_puts(s, "WLAN FW EXISTS");
402 continue;
403 case ICNSS_SHUTDOWN_DONE:
404 seq_puts(s, "SHUTDOWN DONE");
405 continue;
406 case ICNSS_HOST_TRIGGERED_PDR:
407 seq_puts(s, "HOST TRIGGERED PDR");
408 continue;
409 case ICNSS_FW_DOWN:
410 seq_puts(s, "FW DOWN");
411 continue;
412 case ICNSS_DRIVER_UNLOADING:
413 seq_puts(s, "DRIVER UNLOADING");
414 continue;
415 case ICNSS_REJUVENATE:
416 seq_puts(s, "FW REJUVENATE");
417 continue;
418 case ICNSS_MODE_ON:
419 seq_puts(s, "MODE ON DONE");
420 continue;
421 case ICNSS_BLOCK_SHUTDOWN:
422 seq_puts(s, "BLOCK SHUTDOWN");
423 continue;
424 case ICNSS_PDR:
425 seq_puts(s, "PDR TRIGGERED");
426 continue;
427 case ICNSS_IMS_CONNECTED:
428 seq_puts(s, "IMS_CONNECTED");
429 continue;
430 case ICNSS_DEL_SERVER:
431 seq_puts(s, "DEL SERVER");
432 continue;
433 case ICNSS_COLD_BOOT_CAL:
434 seq_puts(s, "COLD BOOT CALIBRATION");
435 continue;
436 case ICNSS_QMI_DMS_CONNECTED:
437 seq_puts(s, "DMS_CONNECTED");
438 continue;
439 case ICNSS_SLATE_SSR_REGISTERED:
440 seq_puts(s, "SLATE SSR REGISTERED");
441 continue;
442 case ICNSS_SLATE_UP:
443 seq_puts(s, "ICNSS SLATE UP");
444 continue;
445 case ICNSS_SLATE_READY:
446 seq_puts(s, "ICNSS SLATE READY");
447 continue;
448 case ICNSS_LOW_POWER:
449 seq_puts(s, "ICNSS LOW POWER");
450 }
451
452 seq_printf(s, "UNKNOWN-%d", i);
453 }
454 seq_puts(s, ")\n");
455
456 return 0;
457 }
458
459 #define ICNSS_STATS_DUMP(_s, _priv, _x) \
460 seq_printf(_s, "%24s: %u\n", #_x, _priv->stats._x)
461
icnss_stats_show(struct seq_file * s,void * data)462 static int icnss_stats_show(struct seq_file *s, void *data)
463 {
464
465 struct icnss_priv *priv = s->private;
466
467 ICNSS_STATS_DUMP(s, priv, ind_register_req);
468 ICNSS_STATS_DUMP(s, priv, ind_register_resp);
469 ICNSS_STATS_DUMP(s, priv, ind_register_err);
470 ICNSS_STATS_DUMP(s, priv, cap_req);
471 ICNSS_STATS_DUMP(s, priv, cap_resp);
472 ICNSS_STATS_DUMP(s, priv, cap_err);
473 ICNSS_STATS_DUMP(s, priv, pin_connect_result);
474 ICNSS_STATS_DUMP(s, priv, cfg_req);
475 ICNSS_STATS_DUMP(s, priv, cfg_resp);
476 ICNSS_STATS_DUMP(s, priv, cfg_req_err);
477 ICNSS_STATS_DUMP(s, priv, mode_req);
478 ICNSS_STATS_DUMP(s, priv, mode_resp);
479 ICNSS_STATS_DUMP(s, priv, mode_req_err);
480 ICNSS_STATS_DUMP(s, priv, ini_req);
481 ICNSS_STATS_DUMP(s, priv, ini_resp);
482 ICNSS_STATS_DUMP(s, priv, ini_req_err);
483 ICNSS_STATS_DUMP(s, priv, recovery.pdr_fw_crash);
484 ICNSS_STATS_DUMP(s, priv, recovery.pdr_host_error);
485 ICNSS_STATS_DUMP(s, priv, recovery.root_pd_crash);
486 ICNSS_STATS_DUMP(s, priv, recovery.root_pd_shutdown);
487
488 seq_puts(s, "\n<------------------ PM stats ------------------->\n");
489 ICNSS_STATS_DUMP(s, priv, pm_suspend);
490 ICNSS_STATS_DUMP(s, priv, pm_suspend_err);
491 ICNSS_STATS_DUMP(s, priv, pm_resume);
492 ICNSS_STATS_DUMP(s, priv, pm_resume_err);
493 ICNSS_STATS_DUMP(s, priv, pm_suspend_noirq);
494 ICNSS_STATS_DUMP(s, priv, pm_suspend_noirq_err);
495 ICNSS_STATS_DUMP(s, priv, pm_resume_noirq);
496 ICNSS_STATS_DUMP(s, priv, pm_resume_noirq_err);
497 ICNSS_STATS_DUMP(s, priv, pm_stay_awake);
498 ICNSS_STATS_DUMP(s, priv, pm_relax);
499
500 if (priv->device_id == ADRASTEA_DEVICE_ID) {
501 seq_puts(s, "\n<------------------ MSA stats ------------------->\n");
502 ICNSS_STATS_DUMP(s, priv, msa_info_req);
503 ICNSS_STATS_DUMP(s, priv, msa_info_resp);
504 ICNSS_STATS_DUMP(s, priv, msa_info_err);
505 ICNSS_STATS_DUMP(s, priv, msa_ready_req);
506 ICNSS_STATS_DUMP(s, priv, msa_ready_resp);
507 ICNSS_STATS_DUMP(s, priv, msa_ready_err);
508 ICNSS_STATS_DUMP(s, priv, msa_ready_ind);
509
510 seq_puts(s, "\n<------------------ Rejuvenate stats ------------------->\n");
511 ICNSS_STATS_DUMP(s, priv, rejuvenate_ind);
512 ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_req);
513 ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_resp);
514 ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_err);
515 icnss_stats_show_rejuvenate_info(s, priv);
516
517 }
518
519 icnss_stats_show_irqs(s, priv);
520
521 icnss_stats_show_capability(s, priv);
522
523 icnss_stats_show_events(s, priv);
524
525 icnss_stats_show_state(s, priv);
526
527 return 0;
528 }
529
icnss_stats_open(struct inode * inode,struct file * file)530 static int icnss_stats_open(struct inode *inode, struct file *file)
531 {
532 return single_open(file, icnss_stats_show, inode->i_private);
533 }
534
535 static const struct file_operations icnss_stats_fops = {
536 .read = seq_read,
537 .write = icnss_stats_write,
538 .release = single_release,
539 .open = icnss_stats_open,
540 .owner = THIS_MODULE,
541 .llseek = seq_lseek,
542 };
543
icnss_fw_debug_show(struct seq_file * s,void * data)544 static int icnss_fw_debug_show(struct seq_file *s, void *data)
545 {
546 struct icnss_priv *priv = s->private;
547
548 seq_puts(s, "\nUsage: echo <CMD> <VAL> > <DEBUGFS>/icnss/fw_debug\n");
549
550 seq_puts(s, "\nCMD: test_mode\n");
551 seq_puts(s, " VAL: 0 (Test mode disable)\n");
552 seq_puts(s, " VAL: 1 (WLAN FW test)\n");
553 seq_puts(s, " VAL: 2 (CCPM test)\n");
554 seq_puts(s, " VAL: 3 (Trigger Recovery)\n");
555 seq_puts(s, " VAL: 4 (allow recursive recovery)\n");
556 seq_puts(s, " VAL: 5 (Disallow recursive recovery)\n");
557 seq_puts(s, " VAL: 6 (Trigger power supply callback)\n");
558
559 seq_puts(s, "\nCMD: dynamic_feature_mask\n");
560 seq_puts(s, " VAL: (64 bit feature mask)\n");
561
562 if (!test_bit(ICNSS_FW_READY, &priv->state)) {
563 seq_puts(s, "Firmware is not ready yet, can't run test_mode!\n");
564 goto out;
565 }
566
567 if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) {
568 seq_puts(s, "Machine mode is running, can't run test_mode!\n");
569 goto out;
570 }
571
572 if (test_bit(ICNSS_FW_TEST_MODE, &priv->state)) {
573 seq_puts(s, "test_mode is running, can't run test_mode!\n");
574 goto out;
575 }
576
577 out:
578 seq_puts(s, "\n");
579 return 0;
580 }
581
icnss_test_mode_fw_test_off(struct icnss_priv * priv)582 static int icnss_test_mode_fw_test_off(struct icnss_priv *priv)
583 {
584 int ret;
585
586 if (!test_bit(ICNSS_FW_READY, &priv->state)) {
587 icnss_pr_err("Firmware is not ready yet!, wait for FW READY: state: 0x%lx\n",
588 priv->state);
589 ret = -ENODEV;
590 goto out;
591 }
592
593 if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) {
594 icnss_pr_err("Machine mode is running, can't run test mode: state: 0x%lx\n",
595 priv->state);
596 ret = -EINVAL;
597 goto out;
598 }
599
600 if (!test_bit(ICNSS_FW_TEST_MODE, &priv->state)) {
601 icnss_pr_err("Test mode not started, state: 0x%lx\n",
602 priv->state);
603 ret = -EINVAL;
604 goto out;
605 }
606
607 icnss_wlan_disable(&priv->pdev->dev, ICNSS_OFF);
608
609 ret = icnss_hw_power_off(priv);
610
611 clear_bit(ICNSS_FW_TEST_MODE, &priv->state);
612
613 out:
614 return ret;
615 }
616
icnss_test_mode_fw_test(struct icnss_priv * priv,enum icnss_driver_mode mode)617 static int icnss_test_mode_fw_test(struct icnss_priv *priv,
618 enum icnss_driver_mode mode)
619 {
620 int ret;
621
622 if (!test_bit(ICNSS_FW_READY, &priv->state)) {
623 icnss_pr_err("Firmware is not ready yet!, wait for FW READY, state: 0x%lx\n",
624 priv->state);
625 ret = -ENODEV;
626 goto out;
627 }
628
629 if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) {
630 icnss_pr_err("Machine mode is running, can't run test mode, state: 0x%lx\n",
631 priv->state);
632 ret = -EINVAL;
633 goto out;
634 }
635
636 if (test_bit(ICNSS_FW_TEST_MODE, &priv->state)) {
637 icnss_pr_err("Test mode already started, state: 0x%lx\n",
638 priv->state);
639 ret = -EBUSY;
640 goto out;
641 }
642
643 ret = icnss_hw_power_on(priv);
644 if (ret)
645 goto out;
646
647 set_bit(ICNSS_FW_TEST_MODE, &priv->state);
648
649 ret = icnss_wlan_enable(&priv->pdev->dev, NULL, mode, NULL);
650 if (ret)
651 goto power_off;
652
653 return 0;
654
655 power_off:
656 icnss_hw_power_off(priv);
657 clear_bit(ICNSS_FW_TEST_MODE, &priv->state);
658
659 out:
660 return ret;
661 }
662
663
icnss_fw_debug_write(struct file * fp,const char __user * user_buf,size_t count,loff_t * off)664 static ssize_t icnss_fw_debug_write(struct file *fp,
665 const char __user *user_buf,
666 size_t count, loff_t *off)
667 {
668 struct icnss_priv *priv =
669 ((struct seq_file *)fp->private_data)->private;
670 char buf[64];
671 char *sptr, *token;
672 unsigned int len = 0;
673 char *cmd;
674 uint64_t val;
675 const char *delim = " ";
676 int ret = 0;
677
678 len = min(count, sizeof(buf) - 1);
679 if (copy_from_user(buf, user_buf, len))
680 return -EINVAL;
681
682 buf[len] = '\0';
683 sptr = buf;
684
685 token = strsep(&sptr, delim);
686 if (!token)
687 return -EINVAL;
688 if (!sptr)
689 return -EINVAL;
690 cmd = token;
691
692 token = strsep(&sptr, delim);
693 if (!token)
694 return -EINVAL;
695 if (kstrtou64(token, 0, &val))
696 return -EINVAL;
697
698 if (strcmp(cmd, "test_mode") == 0) {
699 switch (val) {
700 case 0:
701 ret = icnss_test_mode_fw_test_off(priv);
702 break;
703 case 1:
704 ret = icnss_test_mode_fw_test(priv, ICNSS_WALTEST);
705 break;
706 case 2:
707 ret = icnss_test_mode_fw_test(priv, ICNSS_CCPM);
708 break;
709 case 3:
710 ret = icnss_trigger_recovery(&priv->pdev->dev);
711 break;
712 case 4:
713 icnss_allow_recursive_recovery(&priv->pdev->dev);
714 break;
715 case 5:
716 icnss_disallow_recursive_recovery(&priv->pdev->dev);
717 break;
718 case 6:
719 power_supply_changed(priv->batt_psy);
720 break;
721 default:
722 return -EINVAL;
723 }
724 } else if (strcmp(cmd, "dynamic_feature_mask") == 0) {
725 ret = wlfw_dynamic_feature_mask_send_sync_msg(priv, val);
726 } else {
727 return -EINVAL;
728 }
729
730 if (ret)
731 return ret;
732
733 return count;
734 }
735
icnss_fw_debug_open(struct inode * inode,struct file * file)736 static int icnss_fw_debug_open(struct inode *inode, struct file *file)
737 {
738 return single_open(file, icnss_fw_debug_show, inode->i_private);
739 }
740
741 static const struct file_operations icnss_fw_debug_fops = {
742 .read = seq_read,
743 .write = icnss_fw_debug_write,
744 .release = single_release,
745 .open = icnss_fw_debug_open,
746 .owner = THIS_MODULE,
747 .llseek = seq_lseek,
748 };
749
icnss_control_params_debug_write(struct file * fp,const char __user * user_buf,size_t count,loff_t * off)750 static ssize_t icnss_control_params_debug_write(struct file *fp,
751 const char __user *user_buf,
752 size_t count, loff_t *off)
753 {
754 struct icnss_priv *priv =
755 ((struct seq_file *)fp->private_data)->private;
756
757 char buf[64];
758 char *sptr, *token;
759 char *cmd;
760 u32 val;
761 unsigned int len = 0;
762 const char *delim = " ";
763
764 if (!priv)
765 return -ENODEV;
766
767 len = min(count, sizeof(buf) - 1);
768 if (copy_from_user(buf, user_buf, len))
769 return -EINVAL;
770
771 buf[len] = '\0';
772 sptr = buf;
773
774 token = strsep(&sptr, delim);
775 if (!token)
776 return -EINVAL;
777 if (!sptr)
778 return -EINVAL;
779 cmd = token;
780
781 token = strsep(&sptr, delim);
782 if (!token)
783 return -EINVAL;
784 if (kstrtou32(token, 0, &val))
785 return -EINVAL;
786
787 if (strcmp(cmd, "qmi_timeout") == 0)
788 priv->ctrl_params.qmi_timeout = msecs_to_jiffies(val);
789 else
790 return -EINVAL;
791
792 return count;
793 }
794
icnss_control_params_debug_show(struct seq_file * s,void * data)795 static int icnss_control_params_debug_show(struct seq_file *s, void *data)
796 {
797 struct icnss_priv *priv = s->private;
798
799 seq_puts(s, "\nUsage: echo <params_name> <value> > <debugfs>/icnss/control_params\n");
800 seq_puts(s, "<params_name> can be from below:\n");
801 seq_puts(s, "qmi_timeout: Timeout for QMI message in milliseconds\n");
802
803 seq_puts(s, "\nCurrent value:\n");
804
805 seq_printf(s, "qmi_timeout: %u\n", jiffies_to_msecs(priv->ctrl_params.qmi_timeout));
806
807 return 0;
808 }
809
icnss_control_params_debug_open(struct inode * inode,struct file * file)810 static int icnss_control_params_debug_open(struct inode *inode,
811 struct file *file)
812 {
813 return single_open(file, icnss_control_params_debug_show,
814 inode->i_private);
815 }
816
817 static const struct file_operations icnss_control_params_debug_fops = {
818 .read = seq_read,
819 .write = icnss_control_params_debug_write,
820 .release = single_release,
821 .open = icnss_control_params_debug_open,
822 .owner = THIS_MODULE,
823 .llseek = seq_lseek,
824 };
825
826 #ifdef CONFIG_ICNSS2_DEBUG
icnss_debugfs_create(struct icnss_priv * priv)827 int icnss_debugfs_create(struct icnss_priv *priv)
828 {
829 int ret = 0;
830 struct dentry *root_dentry;
831
832 root_dentry = debugfs_create_dir("icnss", NULL);
833
834 if (IS_ERR(root_dentry)) {
835 ret = PTR_ERR(root_dentry);
836 icnss_pr_err("Unable to create debugfs %d\n", ret);
837 goto out;
838 }
839
840 priv->root_dentry = root_dentry;
841
842 debugfs_create_file("fw_debug", 0600, root_dentry, priv,
843 &icnss_fw_debug_fops);
844 debugfs_create_file("stats", 0600, root_dentry, priv,
845 &icnss_stats_fops);
846 debugfs_create_file("reg_read", 0600, root_dentry, priv,
847 &icnss_regread_fops);
848 debugfs_create_file("reg_write", 0600, root_dentry, priv,
849 &icnss_regwrite_fops);
850 debugfs_create_file("control_params", 0600, root_dentry, priv,
851 &icnss_control_params_debug_fops);
852 out:
853 return ret;
854 }
855 #else
icnss_debugfs_create(struct icnss_priv * priv)856 int icnss_debugfs_create(struct icnss_priv *priv)
857 {
858 int ret = 0;
859 struct dentry *root_dentry;
860
861 root_dentry = debugfs_create_dir("icnss", NULL);
862
863 if (IS_ERR(root_dentry)) {
864 ret = PTR_ERR(root_dentry);
865 icnss_pr_err("Unable to create debugfs %d\n", ret);
866 return ret;
867 }
868
869 priv->root_dentry = root_dentry;
870
871 debugfs_create_file("stats", 0600, root_dentry, priv,
872 &icnss_stats_fops);
873 return 0;
874 }
875 #endif
876
icnss_debugfs_destroy(struct icnss_priv * priv)877 void icnss_debugfs_destroy(struct icnss_priv *priv)
878 {
879 debugfs_remove_recursive(priv->root_dentry);
880 }
881
icnss_debug_init(void)882 void icnss_debug_init(void)
883 {
884 icnss_ipc_log_context = ipc_log_context_create(NUM_LOG_PAGES,
885 "icnss", 0);
886 if (!icnss_ipc_log_context)
887 icnss_pr_err("Unable to create log context\n");
888
889 icnss_ipc_log_long_context = ipc_log_context_create(NUM_LOG_LONG_PAGES,
890 "icnss_long", 0);
891 if (!icnss_ipc_log_long_context)
892 icnss_pr_err("Unable to create log long context\n");
893
894 icnss_ipc_log_smp2p_context = ipc_log_context_create(NUM_LOG_LONG_PAGES,
895 "icnss_smp2p", 0);
896 if (!icnss_ipc_log_smp2p_context)
897 icnss_pr_err("Unable to create log smp2p context\n");
898
899 icnss_ipc_soc_wake_context = ipc_log_context_create(NUM_LOG_LONG_PAGES,
900 "icnss_soc_wake", 0);
901 if (!icnss_ipc_soc_wake_context)
902 icnss_pr_err("Unable to create log soc_wake context\n");
903
904 }
905
icnss_debug_deinit(void)906 void icnss_debug_deinit(void)
907 {
908 if (icnss_ipc_log_context) {
909 ipc_log_context_destroy(icnss_ipc_log_context);
910 icnss_ipc_log_context = NULL;
911 }
912
913 if (icnss_ipc_log_long_context) {
914 ipc_log_context_destroy(icnss_ipc_log_long_context);
915 icnss_ipc_log_long_context = NULL;
916 }
917
918 if (icnss_ipc_log_smp2p_context) {
919 ipc_log_context_destroy(icnss_ipc_log_smp2p_context);
920 icnss_ipc_log_smp2p_context = NULL;
921 }
922
923 if (icnss_ipc_soc_wake_context) {
924 ipc_log_context_destroy(icnss_ipc_soc_wake_context);
925 icnss_ipc_soc_wake_context = NULL;
926 }
927 }
928