xref: /wlan-driver/platform/icnss2/debug.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
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, &reg_offset))
63 		return -EINVAL;
64 
65 	token = strsep(&sptr, delim);
66 	if (!token)
67 		return -EINVAL;
68 
69 	if (kstrtou32(token, 0, &reg_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 *)&reg_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, &reg_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, &reg_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, &reg_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, &reg_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