xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/dhd_linux_exportfs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Broadcom Dongle Host Driver (DHD), Linux-specific network interface
3  * Basically selected code segments from usb-cdc.c and usb-rndis.c
4  *
5  * Copyright (C) 2020, Broadcom.
6  *
7  *      Unless you and Broadcom execute a separate written software license
8  * agreement governing use of this software, this software is licensed to you
9  * under the terms of the GNU General Public License version 2 (the "GPL"),
10  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11  * following added to such license:
12  *
13  *      As a special exception, the copyright holders of this software give you
14  * permission to link this software with independent modules, and to copy and
15  * distribute the resulting executable under terms of your choice, provided that
16  * you also meet, for each linked independent module, the terms and conditions of
17  * the license of that module.  An independent module is a module which is not
18  * derived from this software.  The special exception does not apply to any
19  * modifications of the software.
20  *
21  *
22  * <<Broadcom-WL-IPTag/Open:>>
23  *
24  * $Id$
25  */
26 #include <linux/kobject.h>
27 #include <linux/proc_fs.h>
28 #include <linux/sysfs.h>
29 #include <osl.h>
30 #include <dhd.h>
31 #include <dhd_dbg.h>
32 #include <dhd_linux_priv.h>
33 #if defined(DHD_ADPS_BAM_EXPORT) && defined(WL_BAM)
34 #include <wl_bam.h>
35 #endif	/* DHD_ADPS_BAM_EXPORT && WL_BAM */
36 #ifdef PWRSTATS_SYSFS
37 #include <wldev_common.h>
38 #endif /* PWRSTATS_SYSFS */
39 #ifdef WL_CFG80211
40 #include <wl_cfg80211.h>
41 #endif /* WL_CFG80211 */
42 #ifdef CSI_SUPPORT
43 #include <dhd_csi.h>
44 #endif /* CSI_SUPPORT */
45 
46 #ifdef SHOW_LOGTRACE
47 extern dhd_pub_t* g_dhd_pub;
48 static int dhd_ring_proc_open(struct inode *inode, struct file *file);
49 ssize_t dhd_ring_proc_read(struct file *file, char *buffer, size_t tt, loff_t *loff);
50 
51 static const struct file_operations dhd_ring_proc_fops = {
52 	.open = dhd_ring_proc_open,
53 	.read = dhd_ring_proc_read,
54 	.release = single_release,
55 };
56 
57 static int
dhd_ring_proc_open(struct inode * inode,struct file * file)58 dhd_ring_proc_open(struct inode *inode, struct file *file)
59 {
60 	int ret = BCME_ERROR;
61 	if (inode) {
62 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0))
63 		ret = single_open(file, 0, pde_data(inode));
64 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
65 		ret = single_open(file, 0, PDE_DATA(inode));
66 #else
67 		/* This feature is not supported for lower kernel versions */
68 		ret = single_open(file, 0, NULL);
69 #endif
70 	} else {
71 		DHD_ERROR(("%s: inode is NULL\n", __FUNCTION__));
72 	}
73 	return ret;
74 }
75 
76 ssize_t
dhd_ring_proc_read(struct file * file,char __user * buffer,size_t tt,loff_t * loff)77 dhd_ring_proc_read(struct file *file, char __user *buffer, size_t tt, loff_t *loff)
78 {
79 	trace_buf_info_t *trace_buf_info;
80 	int ret = BCME_ERROR;
81 	dhd_dbg_ring_t *ring = (dhd_dbg_ring_t *)((struct seq_file *)(file->private_data))->private;
82 
83 	if (ring == NULL) {
84 		DHD_ERROR(("%s: ring is NULL\n", __FUNCTION__));
85 		return ret;
86 	}
87 
88 	ASSERT(g_dhd_pub);
89 
90 	trace_buf_info = (trace_buf_info_t *)MALLOCZ(g_dhd_pub->osh, sizeof(trace_buf_info_t));
91 	if (trace_buf_info) {
92 		dhd_dbg_read_ring_into_trace_buf(ring, trace_buf_info);
93 		if (copy_to_user(buffer, (void*)trace_buf_info->buf, MIN(trace_buf_info->size, tt)))
94 		{
95 			ret = -EFAULT;
96 			goto exit;
97 		}
98 		if (trace_buf_info->availability == BUF_NOT_AVAILABLE)
99 			ret = BUF_NOT_AVAILABLE;
100 		else
101 			ret = trace_buf_info->size;
102 	} else
103 		DHD_ERROR(("Memory allocation Failed\n"));
104 
105 exit:
106 	if (trace_buf_info) {
107 		MFREE(g_dhd_pub->osh, trace_buf_info, sizeof(trace_buf_info_t));
108 	}
109 	return ret;
110 }
111 
112 void
dhd_dbg_ring_proc_create(dhd_pub_t * dhdp)113 dhd_dbg_ring_proc_create(dhd_pub_t *dhdp)
114 {
115 #ifdef DEBUGABILITY
116 	dhd_dbg_ring_t *dbg_verbose_ring = NULL;
117 
118 	dbg_verbose_ring = dhd_dbg_get_ring_from_ring_id(dhdp, FW_VERBOSE_RING_ID);
119 	if (dbg_verbose_ring) {
120 		if (!proc_create_data("dhd_trace", S_IRUSR, NULL, &dhd_ring_proc_fops,
121 			dbg_verbose_ring)) {
122 			DHD_ERROR(("Failed to create /proc/dhd_trace procfs interface\n"));
123 		} else {
124 			DHD_ERROR(("Created /proc/dhd_trace procfs interface\n"));
125 		}
126 	} else {
127 		DHD_ERROR(("dbg_verbose_ring is NULL, /proc/dhd_trace not created\n"));
128 	}
129 #endif /* DEBUGABILITY */
130 
131 #ifdef EWP_ECNTRS_LOGGING
132 	if (!proc_create_data("dhd_ecounters", S_IRUSR, NULL, &dhd_ring_proc_fops,
133 		dhdp->ecntr_dbg_ring)) {
134 		DHD_ERROR(("Failed to create /proc/dhd_ecounters procfs interface\n"));
135 	} else {
136 		DHD_ERROR(("Created /proc/dhd_ecounters procfs interface\n"));
137 	}
138 #endif /* EWP_ECNTRS_LOGGING */
139 
140 #ifdef EWP_RTT_LOGGING
141 	if (!proc_create_data("dhd_rtt", S_IRUSR, NULL, &dhd_ring_proc_fops,
142 		dhdp->rtt_dbg_ring)) {
143 		DHD_ERROR(("Failed to create /proc/dhd_rtt procfs interface\n"));
144 	} else {
145 		DHD_ERROR(("Created /proc/dhd_rtt procfs interface\n"));
146 	}
147 #endif /* EWP_RTT_LOGGING */
148 }
149 
150 void
dhd_dbg_ring_proc_destroy(dhd_pub_t * dhdp)151 dhd_dbg_ring_proc_destroy(dhd_pub_t *dhdp)
152 {
153 #ifdef DEBUGABILITY
154 	remove_proc_entry("dhd_trace", NULL);
155 #endif /* DEBUGABILITY */
156 
157 #ifdef EWP_ECNTRS_LOGGING
158 	remove_proc_entry("dhd_ecounters", NULL);
159 #endif /* EWP_ECNTRS_LOGGING */
160 
161 #ifdef EWP_RTT_LOGGING
162 	remove_proc_entry("dhd_rtt", NULL);
163 #endif /* EWP_RTT_LOGGING */
164 
165 }
166 #endif /* SHOW_LOGTRACE */
167 
168 /* ----------------------------------------------------------------------------
169  * Infrastructure code for sysfs interface support for DHD
170  *
171  * What is sysfs interface?
172  * https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt
173  *
174  * Why sysfs interface?
175  * This is the Linux standard way of changing/configuring Run Time parameters
176  * for a driver. We can use this interface to control "linux" specific driver
177  * parameters.
178  *
179  * -----------------------------------------------------------------------------
180  */
181 
182 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
183 #if defined(DHD_TRACE_WAKE_LOCK)
184 extern atomic_t trace_wklock_onoff;
185 
186 /* Function to show the history buffer */
187 static ssize_t
show_wklock_trace(struct dhd_info * dev,char * buf)188 show_wklock_trace(struct dhd_info *dev, char *buf)
189 {
190 	ssize_t ret = 0;
191 	dhd_info_t *dhd = (dhd_info_t *)dev;
192 
193 	buf[ret] = '\n';
194 	buf[ret+1] = 0;
195 
196 	dhd_wk_lock_stats_dump(&dhd->pub);
197 	return ret+1;
198 }
199 
200 /* Function to enable/disable wakelock trace */
201 static ssize_t
wklock_trace_onoff(struct dhd_info * dev,const char * buf,size_t count)202 wklock_trace_onoff(struct dhd_info *dev, const char *buf, size_t count)
203 {
204 	unsigned long onoff;
205 	dhd_info_t *dhd = (dhd_info_t *)dev;
206 	BCM_REFERENCE(dhd);
207 
208 	onoff = bcm_strtoul(buf, NULL, 10);
209 	if (onoff != 0 && onoff != 1) {
210 		return -EINVAL;
211 	}
212 
213 	atomic_set(&trace_wklock_onoff, onoff);
214 	if (atomic_read(&trace_wklock_onoff)) {
215 		DHD_ERROR(("ENABLE WAKLOCK TRACE\n"));
216 	} else {
217 		DHD_ERROR(("DISABLE WAKELOCK TRACE\n"));
218 	}
219 
220 	return (ssize_t)(onoff+1);
221 }
222 #endif /* DHD_TRACE_WAKE_LOCK */
223 
224 #ifdef DHD_LOG_DUMP
225 extern int logdump_periodic_flush;
226 extern int logdump_ecntr_enable;
227 static ssize_t
show_logdump_periodic_flush(struct dhd_info * dev,char * buf)228 show_logdump_periodic_flush(struct dhd_info *dev, char *buf)
229 {
230 	ssize_t ret = 0;
231 	unsigned long val;
232 
233 	val = logdump_periodic_flush;
234 	ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n", val);
235 	return ret;
236 }
237 
238 static ssize_t
logdump_periodic_flush_onoff(struct dhd_info * dev,const char * buf,size_t count)239 logdump_periodic_flush_onoff(struct dhd_info *dev, const char *buf, size_t count)
240 {
241 	unsigned long val;
242 
243 	val = bcm_strtoul(buf, NULL, 10);
244 
245 	sscanf(buf, "%lu", &val);
246 	if (val != 0 && val != 1) {
247 		 return -EINVAL;
248 	}
249 	logdump_periodic_flush = val;
250 	return count;
251 }
252 
253 static ssize_t
show_logdump_ecntr(struct dhd_info * dev,char * buf)254 show_logdump_ecntr(struct dhd_info *dev, char *buf)
255 {
256 	ssize_t ret = 0;
257 	unsigned long val;
258 
259 	val = logdump_ecntr_enable;
260 	ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n", val);
261 	return ret;
262 }
263 
264 static ssize_t
logdump_ecntr_onoff(struct dhd_info * dev,const char * buf,size_t count)265 logdump_ecntr_onoff(struct dhd_info *dev, const char *buf, size_t count)
266 {
267 	unsigned long val;
268 
269 	val = bcm_strtoul(buf, NULL, 10);
270 
271 	sscanf(buf, "%lu", &val);
272 	if (val != 0 && val != 1) {
273 		 return -EINVAL;
274 	}
275 	logdump_ecntr_enable = val;
276 	return count;
277 }
278 
279 #endif /* DHD_LOG_DUMP */
280 
281 extern uint enable_ecounter;
282 static ssize_t
show_enable_ecounter(struct dhd_info * dev,char * buf)283 show_enable_ecounter(struct dhd_info *dev, char *buf)
284 {
285 	ssize_t ret = 0;
286 	unsigned long onoff;
287 
288 	onoff = enable_ecounter;
289 	ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n",
290 		onoff);
291 	return ret;
292 }
293 
294 static ssize_t
ecounter_onoff(struct dhd_info * dev,const char * buf,size_t count)295 ecounter_onoff(struct dhd_info *dev, const char *buf, size_t count)
296 {
297 	unsigned long onoff;
298 	dhd_info_t *dhd = (dhd_info_t *)dev;
299 	dhd_pub_t *dhdp;
300 
301 	if (!dhd) {
302 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
303 		return count;
304 	}
305 	dhdp = &dhd->pub;
306 	if (!FW_SUPPORTED(dhdp, ecounters)) {
307 		DHD_ERROR(("%s: ecounters not supported by FW\n", __FUNCTION__));
308 		return count;
309 	}
310 
311 	onoff = bcm_strtoul(buf, NULL, 10);
312 
313 	sscanf(buf, "%lu", &onoff);
314 	if (onoff != 0 && onoff != 1) {
315 		return -EINVAL;
316 	}
317 
318 	if (enable_ecounter == onoff) {
319 		DHD_ERROR(("%s: ecounters already %d\n", __FUNCTION__, enable_ecounter));
320 		return count;
321 	}
322 
323 	enable_ecounter = onoff;
324 	dhd_ecounter_configure(dhdp, enable_ecounter);
325 
326 	return count;
327 }
328 
329 #if defined(DHD_QOS_ON_SOCK_FLOW)
330 #include <dhd_linux_sock_qos.h>
331 
332 static ssize_t
show_sock_qos_onoff(struct dhd_info * dev,char * buf)333 show_sock_qos_onoff(struct dhd_info *dev, char *buf)
334 {
335 	ssize_t ret = 0;
336 	unsigned long onoff;
337 	dhd_info_t *dhd = (dhd_info_t *)dev;
338 
339 	onoff = dhd_sock_qos_get_status(dhd);
340 	ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n",
341 		onoff);
342 	return ret;
343 }
344 
345 static ssize_t
update_sock_qos_onoff(struct dhd_info * dev,const char * buf,size_t count)346 update_sock_qos_onoff(struct dhd_info *dev, const char *buf, size_t count)
347 {
348 	unsigned long onoff;
349 	dhd_info_t *dhd = (dhd_info_t *)dev;
350 
351 	onoff = bcm_strtoul(buf, NULL, 10);
352 
353 	sscanf(buf, "%lu", &onoff);
354 	if (onoff != 0 && onoff != 1) {
355 		return -EINVAL;
356 	}
357 
358 	dhd_sock_qos_set_status(dhd, onoff);
359 
360 	return count;
361 }
362 
363 static ssize_t
show_sock_qos_upgrade(struct dhd_info * dev,char * buf)364 show_sock_qos_upgrade(struct dhd_info *dev, char *buf)
365 {
366 	ssize_t ret = 0;
367 	unsigned long onoff;
368 	dhd_info_t *dhd = (dhd_info_t *)dev;
369 
370 	onoff = dhd_sock_qos_get_force_upgrade(dhd);
371 	ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n",
372 		onoff);
373 	return ret;
374 }
375 
376 static ssize_t
update_sock_qos_upgrade(struct dhd_info * dev,const char * buf,size_t count)377 update_sock_qos_upgrade(struct dhd_info *dev, const char *buf, size_t count)
378 {
379 	unsigned long onoff;
380 	dhd_info_t *dhd = (dhd_info_t *)dev;
381 
382 	onoff = bcm_strtoul(buf, NULL, 10);
383 
384 	sscanf(buf, "%lu", &onoff);
385 	if (onoff != 0 && onoff != 1) {
386 		return -EINVAL;
387 	}
388 
389 	dhd_sock_qos_set_force_upgrade(dhd, onoff);
390 
391 	return count;
392 }
393 
394 static ssize_t
show_sock_qos_numfl_upgrd_thresh(struct dhd_info * dev,char * buf)395 show_sock_qos_numfl_upgrd_thresh(struct dhd_info *dev, char *buf)
396 {
397 	ssize_t ret = 0;
398 	int upgrade_thresh;
399 	dhd_info_t *dhd = (dhd_info_t *)dev;
400 
401 	upgrade_thresh = dhd_sock_qos_get_numfl_upgrd_thresh(dhd);
402 	ret = scnprintf(buf, PAGE_SIZE - 1, "%d \n",
403 		upgrade_thresh);
404 	return ret;
405 }
406 
407 static ssize_t
update_sock_qos_numfl_upgrd_thresh(struct dhd_info * dev,const char * buf,size_t count)408 update_sock_qos_numfl_upgrd_thresh(struct dhd_info *dev, const char *buf, size_t count)
409 {
410 	int upgrade_thresh;
411 	dhd_info_t *dhd = (dhd_info_t *)dev;
412 
413 	sscanf(buf, "%d", &upgrade_thresh);
414 	if (upgrade_thresh < 0) {
415 		return -EINVAL;
416 	}
417 
418 	dhd_sock_qos_set_numfl_upgrd_thresh(dhd, upgrade_thresh);
419 
420 	return count;
421 }
422 
423 static ssize_t
show_sock_qos_avgpktsize_thresh(struct dhd_info * dev,char * buf)424 show_sock_qos_avgpktsize_thresh(struct dhd_info *dev, char *buf)
425 {
426 	ssize_t ret = 0;
427 	unsigned long avgpktsize_low, avgpktsize_high;
428 	dhd_info_t *dhd = (dhd_info_t *)dev;
429 
430 	dhd_sock_qos_get_avgpktsize_thresh(dhd, &avgpktsize_low, &avgpktsize_high);
431 	ret = scnprintf(buf, PAGE_SIZE - 1, "%lu %lu\n",
432 		avgpktsize_low, avgpktsize_high);
433 
434 	return ret;
435 }
436 
437 static ssize_t
update_sock_qos_avgpktsize_thresh(struct dhd_info * dev,const char * buf,size_t count)438 update_sock_qos_avgpktsize_thresh(struct dhd_info *dev, const char *buf, size_t count)
439 {
440 	unsigned long avgpktsize_low, avgpktsize_high;
441 	dhd_info_t *dhd = (dhd_info_t *)dev;
442 
443 	sscanf(buf, "%lu %lu", &avgpktsize_low, &avgpktsize_high);
444 
445 	dhd_sock_qos_set_avgpktsize_thresh(dhd, avgpktsize_low, avgpktsize_high);
446 
447 	return count;
448 }
449 
450 static ssize_t
show_sock_qos_numpkts_thresh(struct dhd_info * dev,char * buf)451 show_sock_qos_numpkts_thresh(struct dhd_info *dev, char *buf)
452 {
453 	ssize_t ret = 0;
454 	unsigned long numpkts_low, numpkts_high;
455 	dhd_info_t *dhd = (dhd_info_t *)dev;
456 
457 	dhd_sock_qos_get_numpkts_thresh(dhd, &numpkts_low, &numpkts_high);
458 	ret = scnprintf(buf, PAGE_SIZE - 1, "%lu %lu\n",
459 		numpkts_low, numpkts_high);
460 
461 	return ret;
462 }
463 
464 static ssize_t
update_sock_qos_numpkts_thresh(struct dhd_info * dev,const char * buf,size_t count)465 update_sock_qos_numpkts_thresh(struct dhd_info *dev, const char *buf, size_t count)
466 {
467 	unsigned long numpkts_low, numpkts_high;
468 	dhd_info_t *dhd = (dhd_info_t *)dev;
469 
470 	sscanf(buf, "%lu %lu", &numpkts_low, &numpkts_high);
471 
472 	dhd_sock_qos_set_numpkts_thresh(dhd, numpkts_low, numpkts_high);
473 
474 	return count;
475 }
476 
477 static ssize_t
show_sock_qos_detectcnt_thresh(struct dhd_info * dev,char * buf)478 show_sock_qos_detectcnt_thresh(struct dhd_info *dev, char *buf)
479 {
480 	ssize_t ret = 0;
481 	unsigned char detectcnt_inc, detectcnt_dec;
482 	dhd_info_t *dhd = (dhd_info_t *)dev;
483 
484 	dhd_sock_qos_get_detectcnt_thresh(dhd, &detectcnt_inc, &detectcnt_dec);
485 	ret = scnprintf(buf, PAGE_SIZE - 1, "%d %d\n",
486 		detectcnt_inc, detectcnt_dec);
487 
488 	return ret;
489 }
490 
491 static ssize_t
update_sock_qos_detectcnt_thresh(struct dhd_info * dev,const char * buf,size_t count)492 update_sock_qos_detectcnt_thresh(struct dhd_info *dev, const char *buf, size_t count)
493 {
494 	unsigned int detectcnt_inc, detectcnt_dec;
495 	dhd_info_t *dhd = (dhd_info_t *)dev;
496 
497 	sscanf(buf, "%u %u", &detectcnt_inc, &detectcnt_dec);
498 
499 	dhd_sock_qos_set_detectcnt_thresh(dhd, detectcnt_inc, detectcnt_dec);
500 
501 	return count;
502 }
503 
504 static ssize_t
show_sock_qos_detectcnt_upgrd_thresh(struct dhd_info * dev,char * buf)505 show_sock_qos_detectcnt_upgrd_thresh(struct dhd_info *dev, char *buf)
506 {
507 	ssize_t ret = 0;
508 	unsigned int detectcnt_upgrd_thresh;
509 	dhd_info_t *dhd = (dhd_info_t *)dev;
510 
511 	detectcnt_upgrd_thresh = dhd_sock_qos_get_detectcnt_upgrd_thresh(dhd);
512 	ret = scnprintf(buf, PAGE_SIZE - 1, "%d \n", detectcnt_upgrd_thresh);
513 
514 	return ret;
515 }
516 
517 static ssize_t
update_sock_qos_detectcnt_upgrd_thresh(struct dhd_info * dev,const char * buf,size_t count)518 update_sock_qos_detectcnt_upgrd_thresh(struct dhd_info *dev, const char *buf, size_t count)
519 {
520 	unsigned int detectcnt_upgrd_thresh;
521 	dhd_info_t *dhd = (dhd_info_t *)dev;
522 
523 	sscanf(buf, "%u", &detectcnt_upgrd_thresh);
524 
525 	dhd_sock_qos_set_detectcnt_upgrd_thresh(dhd, detectcnt_upgrd_thresh);
526 
527 	return count;
528 }
529 
530 static ssize_t
show_sock_qos_maxfl(struct dhd_info * dev,char * buf)531 show_sock_qos_maxfl(struct dhd_info *dev, char *buf)
532 {
533 	ssize_t ret = 0;
534 	unsigned int maxfl;
535 	dhd_info_t *dhd = (dhd_info_t *)dev;
536 
537 	maxfl = dhd_sock_qos_get_maxfl(dhd);
538 	ret = scnprintf(buf, PAGE_SIZE - 1, "%u \n", maxfl);
539 
540 	return ret;
541 }
542 
543 static ssize_t
update_sock_qos_maxfl(struct dhd_info * dev,const char * buf,size_t count)544 update_sock_qos_maxfl(struct dhd_info *dev, const char *buf, size_t count)
545 {
546 	unsigned int maxfl;
547 	dhd_info_t *dhd = (dhd_info_t *)dev;
548 
549 	sscanf(buf, "%u", &maxfl);
550 
551 	dhd_sock_qos_set_maxfl(dhd, maxfl);
552 
553 	return count;
554 }
555 
556 static ssize_t
show_sock_qos_stats(struct dhd_info * dev,char * buf)557 show_sock_qos_stats(struct dhd_info *dev, char *buf)
558 {
559 	dhd_info_t *dhd = (dhd_info_t *)dev;
560 
561 	dhd_sock_qos_show_stats(dhd, buf, PAGE_SIZE);
562 
563 	return PAGE_SIZE - 1;
564 }
565 
566 static ssize_t
clear_sock_qos_stats(struct dhd_info * dev,const char * buf,size_t count)567 clear_sock_qos_stats(struct dhd_info *dev, const char *buf, size_t count)
568 {
569 	unsigned long clear;
570 	dhd_info_t *dhd = (dhd_info_t *)dev;
571 
572 	clear = bcm_strtoul(buf, NULL, 10);
573 
574 	sscanf(buf, "%lu", &clear);
575 	if (clear != 0) {
576 		return -EINVAL;
577 	}
578 
579 	dhd_sock_qos_clear_stats(dhd);
580 
581 	return count;
582 }
583 
584 #ifdef DHD_QOS_ON_SOCK_FLOW_UT
585 
586 /*
587  * test_id sub_id  Description
588  * ------  ------  -----------
589  *   1      0     psk_qos->sk_fl
590  *				  The number of free sk_fl entries in the Table is exhausted
591  *				  and more sockets are still getting created
592  *
593  *	1      1	  psk_qos->sk_fl
594  *				  is Full for more than x seconds, there are lot of periodic
595  *				  flows, but none of them are detected for upgrade for more
596  *				  than 'x' seconds
597  *
598  *	2			  Force upgrade the socket flows to reach skfl_upgrade_thresh
599  *				  check the behaviour
600  *
601  *				  Downgrade one of the sk_fls and check if the 'next' pending
602  *				  sk_fl is getting upgraded. The sk_fl getting upgraded
603  *				  should follow FIFO scheme.
604  *
605  *   3			  Upgrade a socket flow ... after some time downgrade the
606  *				  same and check if the sk_fl is actually getting downgraded
607  *				  Keep switching the behavior every 'x' seconds and observe
608  *				  the switches
609  */
610 static ssize_t
do_sock_qos_unit_test(struct dhd_info * dev,const char * buf,size_t count)611 do_sock_qos_unit_test(struct dhd_info *dev, const char *buf, size_t count)
612 {
613 	unsigned int test_id = 0;
614 	unsigned int sub_id = 0;
615 	dhd_info_t *dhd = (dhd_info_t *)dev;
616 	int ret;
617 
618 	BCM_REFERENCE(dhd);
619 
620 	ret = sscanf(buf, "%d %d", &test_id, &sub_id);
621 	if (ret < 1) {
622 		return -EINVAL;
623 	}
624 
625 	return count;
626 }
627 
628 #endif /* DHD_QOS_ON_SOCK_FLOW_UT */
629 #endif /* DHD_QOS_ON_SOCK_FLOW */
630 
631 #ifdef DHD_SSSR_DUMP
632 static ssize_t
show_sssr_enab(struct dhd_info * dev,char * buf)633 show_sssr_enab(struct dhd_info *dev, char *buf)
634 {
635 	ssize_t ret = 0;
636 	unsigned long onoff;
637 
638 	onoff = sssr_enab;
639 	ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n",
640 		onoff);
641 	return ret;
642 }
643 
644 static ssize_t
set_sssr_enab(struct dhd_info * dev,const char * buf,size_t count)645 set_sssr_enab(struct dhd_info *dev, const char *buf, size_t count)
646 {
647 	unsigned long onoff;
648 
649 	onoff = bcm_strtoul(buf, NULL, 10);
650 
651 	sscanf(buf, "%lu", &onoff);
652 	if (onoff != 0 && onoff != 1) {
653 		return -EINVAL;
654 	}
655 
656 	sssr_enab = (uint)onoff;
657 
658 	return count;
659 }
660 
661 static ssize_t
show_fis_enab(struct dhd_info * dev,char * buf)662 show_fis_enab(struct dhd_info *dev, char *buf)
663 {
664 	ssize_t ret = 0;
665 	unsigned long onoff;
666 
667 	onoff = fis_enab;
668 	ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n",
669 		onoff);
670 	return ret;
671 }
672 
673 static ssize_t
set_fis_enab(struct dhd_info * dev,const char * buf,size_t count)674 set_fis_enab(struct dhd_info *dev, const char *buf, size_t count)
675 {
676 	unsigned long onoff;
677 
678 	onoff = bcm_strtoul(buf, NULL, 10);
679 
680 	sscanf(buf, "%lu", &onoff);
681 	if (onoff != 0 && onoff != 1) {
682 		return -EINVAL;
683 	}
684 
685 	fis_enab = (uint)onoff;
686 
687 	return count;
688 }
689 #endif /* DHD_SSSR_DUMP */
690 
691 #define FMT_BUFSZ	32
692 extern char firmware_path[];
693 
694 static ssize_t
show_firmware_path(struct dhd_info * dev,char * buf)695 show_firmware_path(struct dhd_info *dev, char *buf)
696 {
697 	ssize_t ret = 0;
698 	ret = scnprintf(buf, PAGE_SIZE - 1, "%s\n", firmware_path);
699 
700 	return ret;
701 }
702 
703 static ssize_t
store_firmware_path(struct dhd_info * dev,const char * buf,size_t count)704 store_firmware_path(struct dhd_info *dev, const char *buf, size_t count)
705 {
706 	char fmt_spec[FMT_BUFSZ] = "";
707 
708 	if ((int)strlen(buf) >= MOD_PARAM_PATHLEN) {
709 		return -EINVAL;
710 	}
711 
712 	snprintf(fmt_spec, FMT_BUFSZ, "%%%ds", MOD_PARAM_PATHLEN - 1);
713 	sscanf(buf, fmt_spec, firmware_path);
714 
715 	return count;
716 }
717 
718 extern char nvram_path[];
719 
720 static ssize_t
show_nvram_path(struct dhd_info * dev,char * buf)721 show_nvram_path(struct dhd_info *dev, char *buf)
722 {
723 	ssize_t ret = 0;
724 	ret = scnprintf(buf, PAGE_SIZE - 1, "%s\n", nvram_path);
725 
726 	return ret;
727 }
728 
729 static ssize_t
store_nvram_path(struct dhd_info * dev,const char * buf,size_t count)730 store_nvram_path(struct dhd_info *dev, const char *buf, size_t count)
731 {
732 	char fmt_spec[FMT_BUFSZ] = "";
733 
734 	if ((int)strlen(buf) >= MOD_PARAM_PATHLEN) {
735 		return -EINVAL;
736 	}
737 
738 	snprintf(fmt_spec, FMT_BUFSZ, "%%%ds", MOD_PARAM_PATHLEN - 1);
739 	sscanf(buf, fmt_spec, nvram_path);
740 
741 	return count;
742 }
743 
744 #ifdef PWRSTATS_SYSFS
745 typedef struct wl_pwrstats_sysfs {
746 	uint64	current_ts;
747 	uint64	pm_cnt;
748 	uint64	pm_dur;
749 	uint64	pm_last_entry_us;
750 	uint64	awake_cnt;
751 	uint64	awake_dur;
752 	uint64	awake_last_entry_us;
753 	uint64	l0_cnt;
754 	uint64	l0_dur_us;
755 	uint64	l1_cnt;
756 	uint64	l1_dur_us;
757 	uint64	l1_1_cnt;
758 	uint64	l1_1_dur_us;
759 	uint64	l1_2_cnt;
760 	uint64	l1_2_dur_us;
761 	uint64	l2_cnt;
762 	uint64	l2_dur_us;
763 } wl_pwrstats_sysfs_t;
764 
765 uint64 last_delta = 0;
766 wl_pwrstats_sysfs_t accumstats = {0, };
767 wl_pwrstats_sysfs_t laststats = {0, };
768 static const char pwrstr_cnt[] = "count:";
769 static const char pwrstr_dur[] = "duration_usec:";
770 static const char pwrstr_ts[] = "last_entry_timestamp_usec:";
771 
update_pwrstats_cum(uint64 * accum,uint64 * last,uint64 * now,bool force)772 void update_pwrstats_cum(uint64 *accum, uint64 *last, uint64 *now, bool force)
773 {
774 	if (accum) { /* accumulation case, ex; counts, duration */
775 		if (*now < *last) {
776 			if (force || ((*last - *now) > USEC_PER_MSEC)) {
777 				/* not to update accum for pm_dur/awake_dur case */
778 				*accum += *now;
779 				*last = *now;
780 			}
781 		} else {
782 			*accum += (*now - *last);
783 			*last = *now;
784 		}
785 	} else if (*now != 0) { /* last entry timestamp case */
786 		*last = *now + last_delta;
787 	}
788 }
789 
790 static const uint16 pwrstats_req_type[] = {
791 	WL_PWRSTATS_TYPE_PCIE,
792 	WL_PWRSTATS_TYPE_PM_ACCUMUL
793 };
794 #define PWRSTATS_REQ_TYPE_NUM	sizeof(pwrstats_req_type) / sizeof(uint16)
795 #define PWRSTATS_IOV_BUF_LEN	OFFSETOF(wl_pwrstats_t, data) \
796 	+ sizeof(uint32) * PWRSTATS_REQ_TYPE_NUM \
797 	+ sizeof(wl_pwr_pcie_stats_t) \
798 	+ sizeof(wl_pwr_pm_accum_stats_v1_t) \
799 	+ (uint)strlen("pwrstats") + 1
800 
801 static ssize_t
show_pwrstats_path(struct dhd_info * dev,char * buf)802 show_pwrstats_path(struct dhd_info *dev, char *buf)
803 {
804 	int err = 0;
805 	void *p_data = NULL;
806 	ssize_t ret = 0;
807 	dhd_info_t *dhd = (dhd_info_t *)dev;
808 	struct net_device *ndev = dhd_linux_get_primary_netdev(&dhd->pub);
809 	char *iovar_buf = NULL;
810 	wl_pwrstats_query_t *p_query = NULL;
811 	wl_pwrstats_sysfs_t pwrstats_sysfs = {0, };
812 	wl_pwrstats_t *pwrstats;
813 	uint len, taglen, i;
814 	uint16 type;
815 	uint64 ts_sec, ts_usec, time_delta;
816 
817 	ASSERT(g_dhd_pub);
818 
819 	len = PWRSTATS_IOV_BUF_LEN;
820 	iovar_buf = (char *)MALLOCZ(g_dhd_pub->osh, len);
821 	if (iovar_buf == NULL) {
822 		DHD_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
823 		goto done;
824 	}
825 
826 	/* Alloc req buffer */
827 	len = OFFSETOF(wl_pwrstats_query_t, type) +
828 		PWRSTATS_REQ_TYPE_NUM * sizeof(uint16);
829 	p_query = (wl_pwrstats_query_t *)MALLOCZ(g_dhd_pub->osh, len);
830 	if (p_query == NULL) {
831 		DHD_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
832 		goto done;
833 	}
834 
835 	/* Build a list of types */
836 	p_query->length = PWRSTATS_REQ_TYPE_NUM;
837 	for (i = 0; i < PWRSTATS_REQ_TYPE_NUM; i++) {
838 		p_query->type[i] = pwrstats_req_type[i];
839 	}
840 
841 	/* Query with desired type list */
842 	err = wldev_iovar_getbuf(ndev, "pwrstats", p_query, len,
843 		iovar_buf, PWRSTATS_IOV_BUF_LEN, NULL);
844 	if (err != BCME_OK) {
845 		DHD_ERROR(("error (%d) - size = %zu\n", err, sizeof(wl_pwrstats_t)));
846 		goto done;
847 	}
848 
849 	/* Check version */
850 	pwrstats = (wl_pwrstats_t *) iovar_buf;
851 	if (dtoh16(pwrstats->version) != WL_PWRSTATS_VERSION) {
852 		DHD_ERROR(("PWRSTATS Version mismatch\n"));
853 		goto done;
854 	}
855 
856 	/* Parse TLVs */
857 	len = dtoh16(pwrstats->length) - WL_PWR_STATS_HDRLEN;
858 	p_data = pwrstats->data;
859 	do {
860 		type = dtoh16(((uint16*)p_data)[0]);
861 		taglen = dtoh16(((uint16*)p_data)[1]);
862 
863 		if ((taglen < BCM_XTLV_HDR_SIZE) || (taglen > len)) {
864 			DHD_ERROR(("Bad len %d for tag %d, remaining len %d\n",
865 					taglen, type, len));
866 			goto done;
867 		}
868 
869 		if (taglen & 0xF000) {
870 			DHD_ERROR(("Resrved bits in len %d for tag %d, remaining len %d\n",
871 					taglen, type, len));
872 			goto done;
873 		}
874 
875 		switch (type) {
876 		case WL_PWRSTATS_TYPE_PCIE:
877 		{
878 			wl_pwr_pcie_stats_t *stats =
879 				(wl_pwr_pcie_stats_t *)p_data;
880 
881 			if (taglen < sizeof(wl_pwr_pcie_stats_t)) {
882 				DHD_ERROR(("Short len for %d: %d < %d\n",
883 					type, taglen, (int)sizeof(wl_pwr_pcie_stats_t)));
884 				goto done;
885 			}
886 
887 			if (dtoh32(stats->pcie.l0_cnt) == 0) {
888 				DHD_ERROR(("link stats are not supported for this pcie core\n"));
889 			}
890 
891 			pwrstats_sysfs.l0_cnt = dtoh32(stats->pcie.l0_cnt);
892 			pwrstats_sysfs.l0_dur_us = dtoh32(stats->pcie.l0_usecs);
893 			pwrstats_sysfs.l1_cnt = dtoh32(stats->pcie.l1_cnt);
894 			pwrstats_sysfs.l1_dur_us = dtoh32(stats->pcie.l1_usecs);
895 			pwrstats_sysfs.l1_1_cnt = dtoh32(stats->pcie.l1_1_cnt);
896 			pwrstats_sysfs.l1_1_dur_us = dtoh32(stats->pcie.l1_1_usecs);
897 			pwrstats_sysfs.l1_2_cnt = dtoh32(stats->pcie.l1_2_cnt);
898 			pwrstats_sysfs.l1_2_dur_us = dtoh32(stats->pcie.l1_2_usecs);
899 			pwrstats_sysfs.l2_cnt = dtoh32(stats->pcie.l2_cnt);
900 			pwrstats_sysfs.l2_dur_us = dtoh32(stats->pcie.l2_usecs);
901 		}
902 		break;
903 
904 		case WL_PWRSTATS_TYPE_PM_ACCUMUL:
905 		{
906 			wl_pwr_pm_accum_stats_v1_t *stats =
907 				(wl_pwr_pm_accum_stats_v1_t *)p_data;
908 
909 			if (taglen < sizeof(wl_pwr_pm_accum_stats_v1_t)) {
910 				DHD_ERROR(("Short len for %d: %d < %d\n", type,
911 					taglen, (int)sizeof(wl_pwr_pm_accum_stats_v1_t)));
912 				goto done;
913 			}
914 
915 			pwrstats_sysfs.current_ts =
916 				dtoh64(stats->accum_data.current_ts);
917 			pwrstats_sysfs.pm_cnt =
918 				dtoh64(stats->accum_data.pm_cnt);
919 			pwrstats_sysfs.pm_dur =
920 				dtoh64(stats->accum_data.pm_dur);
921 			pwrstats_sysfs.pm_last_entry_us =
922 				dtoh64(stats->accum_data.pm_last_entry_us);
923 			pwrstats_sysfs.awake_cnt =
924 				dtoh64(stats->accum_data.awake_cnt);
925 			pwrstats_sysfs.awake_dur =
926 				dtoh64(stats->accum_data.awake_dur);
927 			pwrstats_sysfs.awake_last_entry_us =
928 				dtoh64(stats->accum_data.awake_last_entry_us);
929 		}
930 		break;
931 
932 		default:
933 			DHD_ERROR(("Skipping uknown %d-byte tag %d\n", taglen, type));
934 			break;
935 		}
936 
937 		/* Adjust length to account for padding, but don't exceed total len */
938 		taglen = (ROUNDUP(taglen, 4) > len) ? len : ROUNDUP(taglen, 4);
939 		len -= taglen;
940 		*(uint8**)&p_data += taglen;
941 	} while (len >= BCM_XTLV_HDR_SIZE);
942 
943 	OSL_GET_LOCALTIME(&ts_sec, &ts_usec);
944 	time_delta = ts_sec * USEC_PER_SEC + ts_usec - pwrstats_sysfs.current_ts;
945 	if ((time_delta > last_delta) &&
946 			((time_delta - last_delta) > USEC_PER_SEC)) {
947 		last_delta = time_delta;
948 	}
949 
950 	update_pwrstats_cum(&accumstats.awake_cnt, &laststats.awake_cnt,
951 			&pwrstats_sysfs.awake_cnt, TRUE);
952 	update_pwrstats_cum(&accumstats.awake_dur, &laststats.awake_dur,
953 			&pwrstats_sysfs.awake_dur, FALSE);
954 	update_pwrstats_cum(&accumstats.pm_cnt, &laststats.pm_cnt, &pwrstats_sysfs.pm_cnt,
955 			TRUE);
956 	update_pwrstats_cum(&accumstats.pm_dur, &laststats.pm_dur, &pwrstats_sysfs.pm_dur,
957 			FALSE);
958 	update_pwrstats_cum(NULL, &laststats.awake_last_entry_us,
959 			&pwrstats_sysfs.awake_last_entry_us, TRUE);
960 	update_pwrstats_cum(NULL, &laststats.pm_last_entry_us,
961 			&pwrstats_sysfs.pm_last_entry_us, TRUE);
962 
963 	ret += scnprintf(buf, PAGE_SIZE - 1, "AWAKE:\n");
964 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_cnt,
965 			accumstats.awake_cnt);
966 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_dur,
967 			accumstats.awake_dur);
968 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_ts,
969 			laststats.awake_last_entry_us);
970 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "ASLEEP:\n");
971 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_cnt,
972 			accumstats.pm_cnt);
973 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_dur,
974 			accumstats.pm_dur);
975 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_ts,
976 			laststats.pm_last_entry_us);
977 
978 	update_pwrstats_cum(&accumstats.l0_cnt, &laststats.l0_cnt, &pwrstats_sysfs.l0_cnt,
979 			TRUE);
980 	update_pwrstats_cum(&accumstats.l0_dur_us, &laststats.l0_dur_us,
981 			&pwrstats_sysfs.l0_dur_us, TRUE);
982 	update_pwrstats_cum(&accumstats.l1_cnt, &laststats.l1_cnt, &pwrstats_sysfs.l1_cnt,
983 			TRUE);
984 	update_pwrstats_cum(&accumstats.l1_dur_us, &laststats.l1_dur_us,
985 			&pwrstats_sysfs.l1_dur_us, TRUE);
986 	update_pwrstats_cum(&accumstats.l1_1_cnt, &laststats.l1_1_cnt,
987 			&pwrstats_sysfs.l1_1_cnt, TRUE);
988 	update_pwrstats_cum(&accumstats.l1_1_dur_us, &laststats.l1_1_dur_us,
989 			&pwrstats_sysfs.l1_1_dur_us, TRUE);
990 	update_pwrstats_cum(&accumstats.l1_2_cnt, &laststats.l1_2_cnt,
991 			&pwrstats_sysfs.l1_2_cnt, TRUE);
992 	update_pwrstats_cum(&accumstats.l1_2_dur_us, &laststats.l1_2_dur_us,
993 			&pwrstats_sysfs.l1_2_dur_us, TRUE);
994 	update_pwrstats_cum(&accumstats.l2_cnt, &laststats.l2_cnt, &pwrstats_sysfs.l2_cnt,
995 			TRUE);
996 	update_pwrstats_cum(&accumstats.l2_dur_us, &laststats.l2_dur_us,
997 			&pwrstats_sysfs.l2_dur_us, TRUE);
998 
999 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "L0:\n");
1000 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_cnt,
1001 			accumstats.l0_cnt);
1002 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_dur,
1003 			accumstats.l0_dur_us);
1004 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "L1:\n");
1005 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_cnt,
1006 			accumstats.l1_cnt);
1007 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_dur,
1008 			accumstats.l1_dur_us);
1009 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "L1_1:\n");
1010 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_cnt,
1011 			accumstats.l1_1_cnt);
1012 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_dur,
1013 			accumstats.l1_1_dur_us);
1014 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "L1_2:\n");
1015 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_cnt,
1016 			accumstats.l1_2_cnt);
1017 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_dur,
1018 			accumstats.l1_2_dur_us);
1019 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "L2:\n");
1020 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_cnt,
1021 			accumstats.l2_cnt);
1022 	ret += scnprintf(buf + ret, PAGE_SIZE - 1 - ret, "%s 0x%0llx\n", pwrstr_dur,
1023 			accumstats.l2_dur_us);
1024 
1025 done:
1026 	if (p_query) {
1027 		MFREE(g_dhd_pub->osh, p_query, len);
1028 	}
1029 	if (iovar_buf) {
1030 		MFREE(g_dhd_pub->osh, iovar_buf, PWRSTATS_IOV_BUF_LEN);
1031 	}
1032 
1033 	return ret;
1034 }
1035 #endif /* PWRSTATS_SYSFS */
1036 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
1037 
1038 /*
1039  * Generic Attribute Structure for DHD.
1040  * If we have to add a new sysfs entry under /sys/bcm-dhd/, we have
1041  * to instantiate an object of type dhd_attr,  populate it with
1042  * the required show/store functions (ex:- dhd_attr_cpumask_primary)
1043  * and add the object to default_attrs[] array, that gets registered
1044  * to the kobject of dhd (named bcm-dhd).
1045  */
1046 
1047 struct dhd_attr {
1048 	struct attribute attr;
1049 	ssize_t(*show)(struct dhd_info *, char *);
1050 	ssize_t(*store)(struct dhd_info *, const char *, size_t count);
1051 };
1052 
1053 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
1054 #if defined(DHD_TRACE_WAKE_LOCK)
1055 static struct dhd_attr dhd_attr_wklock =
1056 	__ATTR(wklock_trace, 0660, show_wklock_trace, wklock_trace_onoff);
1057 #endif /* defined(DHD_TRACE_WAKE_LOCK */
1058 
1059 #ifdef DHD_LOG_DUMP
1060 static struct dhd_attr dhd_attr_logdump_periodic_flush =
1061      __ATTR(logdump_periodic_flush, 0660, show_logdump_periodic_flush,
1062 		logdump_periodic_flush_onoff);
1063 static struct dhd_attr dhd_attr_logdump_ecntr =
1064 	__ATTR(logdump_ecntr_enable, 0660, show_logdump_ecntr,
1065 		logdump_ecntr_onoff);
1066 #endif /* DHD_LOG_DUMP */
1067 
1068 static struct dhd_attr dhd_attr_ecounters =
1069 	__ATTR(ecounters, 0660, show_enable_ecounter, ecounter_onoff);
1070 
1071 #if defined(DHD_QOS_ON_SOCK_FLOW)
1072 static struct dhd_attr dhd_attr_sock_qos_onoff =
1073 	__ATTR(sock_qos_onoff, 0660, show_sock_qos_onoff, update_sock_qos_onoff);
1074 
1075 static struct dhd_attr dhd_attr_sock_qos_stats =
1076 	__ATTR(sock_qos_stats, 0660, show_sock_qos_stats, clear_sock_qos_stats);
1077 
1078 static struct dhd_attr dhd_attr_sock_qos_upgrade =
1079 	__ATTR(sock_qos_upgrade, 0660, show_sock_qos_upgrade, update_sock_qos_upgrade);
1080 
1081 static struct dhd_attr dhd_attr_sock_qos_numfl_upgrd_thresh =
1082 	__ATTR(sock_qos_numfl_upgrd_thresh, 0660, show_sock_qos_numfl_upgrd_thresh,
1083 	update_sock_qos_numfl_upgrd_thresh);
1084 
1085 static struct dhd_attr dhd_attr_sock_qos_avgpktsize_thresh =
1086 	__ATTR(sock_qos_avgpktsize_thresh, 0660, show_sock_qos_avgpktsize_thresh,
1087 	update_sock_qos_avgpktsize_thresh);
1088 
1089 static struct dhd_attr dhd_attr_sock_qos_numpkts_thresh =
1090 	__ATTR(sock_qos_numpkts_thresh, 0660, show_sock_qos_numpkts_thresh,
1091 	update_sock_qos_numpkts_thresh);
1092 
1093 static struct dhd_attr dhd_attr_sock_qos_detectcnt_thresh =
1094 	__ATTR(sock_qos_detectcnt_thresh, 0660, show_sock_qos_detectcnt_thresh,
1095 	update_sock_qos_detectcnt_thresh);
1096 
1097 static struct dhd_attr dhd_attr_sock_qos_detectcnt_upgrd_thresh =
1098 	__ATTR(sock_qos_detectcnt_upgrd_thresh, 0660, show_sock_qos_detectcnt_upgrd_thresh,
1099 	update_sock_qos_detectcnt_upgrd_thresh);
1100 
1101 static struct dhd_attr dhd_attr_sock_qos_maxfl =
1102 	__ATTR(sock_qos_maxfl, 0660, show_sock_qos_maxfl,
1103 	update_sock_qos_maxfl);
1104 #if defined(DHD_QOS_ON_SOCK_FLOW_UT)
1105 static struct dhd_attr dhd_attr_sock_qos_unit_test =
1106 	__ATTR(sock_qos_unit_test, 0660, NULL, do_sock_qos_unit_test);
1107 #endif
1108 #endif /* DHD_QOS_ON_SOCK_FLOW */
1109 
1110 #ifdef DHD_SSSR_DUMP
1111 static struct dhd_attr dhd_attr_sssr_enab =
1112 	__ATTR(sssr_enab, 0660, show_sssr_enab, set_sssr_enab);
1113 static struct dhd_attr dhd_attr_fis_enab =
1114 	__ATTR(fis_enab, 0660, show_fis_enab, set_fis_enab);
1115 #endif /* DHD_SSSR_DUMP */
1116 
1117 static struct dhd_attr dhd_attr_firmware_path =
1118 	__ATTR(firmware_path, 0660, show_firmware_path, store_firmware_path);
1119 
1120 static struct dhd_attr dhd_attr_nvram_path =
1121 	__ATTR(nvram_path, 0660, show_nvram_path, store_nvram_path);
1122 
1123 #ifdef PWRSTATS_SYSFS
1124 static struct dhd_attr dhd_attr_pwrstats_path =
1125 	__ATTR(power_stats, 0660, show_pwrstats_path, NULL);
1126 #endif /* PWRSTATS_SYSFS */
1127 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
1128 
1129 #define to_dhd(k) container_of(k, struct dhd_info, dhd_kobj)
1130 #define to_attr(a) container_of(a, struct dhd_attr, attr)
1131 
1132 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
1133 #ifdef DHD_MAC_ADDR_EXPORT
1134 struct ether_addr sysfs_mac_addr;
1135 static ssize_t
show_mac_addr(struct dhd_info * dev,char * buf)1136 show_mac_addr(struct dhd_info *dev, char *buf)
1137 {
1138 	ssize_t ret = 0;
1139 
1140 	ret = scnprintf(buf, PAGE_SIZE - 1, MACF,
1141 		(uint32)sysfs_mac_addr.octet[0], (uint32)sysfs_mac_addr.octet[1],
1142 		(uint32)sysfs_mac_addr.octet[2], (uint32)sysfs_mac_addr.octet[3],
1143 		(uint32)sysfs_mac_addr.octet[4], (uint32)sysfs_mac_addr.octet[5]);
1144 
1145 	return ret;
1146 }
1147 
1148 static ssize_t
set_mac_addr(struct dhd_info * dev,const char * buf,size_t count)1149 set_mac_addr(struct dhd_info *dev, const char *buf, size_t count)
1150 {
1151 	if (!bcm_ether_atoe(buf, &sysfs_mac_addr)) {
1152 		DHD_ERROR(("Invalid Mac Address \n"));
1153 		return -EINVAL;
1154 	}
1155 
1156 	DHD_ERROR(("Mac Address set with "MACDBG"\n", MAC2STRDBG(&sysfs_mac_addr)));
1157 
1158 	return count;
1159 }
1160 
1161 static struct dhd_attr dhd_attr_macaddr =
1162 	__ATTR(mac_addr, 0660, show_mac_addr, set_mac_addr);
1163 #endif /* DHD_MAC_ADDR_EXPORT */
1164 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
1165 
1166 #ifdef DHD_FW_COREDUMP
1167 /*
1168  * XXX The filename to store memdump is defined for each platform.
1169  * - The default path of CUSTOMER_HW4 device is "PLATFORM_PATH/.memdump.info"
1170  * - Brix platform will take default path "/installmedia/.memdump.info"
1171  * New platforms can add their ifdefs accordingly below.
1172  */
1173 
1174 #ifdef CONFIG_X86
1175 #if defined(OEM_ANDROID)
1176 #define MEMDUMPINFO_LIVE PLATFORM_PATH".memdump.info"
1177 #define MEMDUMPINFO_INST "/data/.memdump.info"
1178 #define MEMDUMPINFO MEMDUMPINFO_LIVE
1179 #else /* FC19 and Others */
1180 #define MEMDUMPINFO PLATFORM_PATH".memdump.info"
1181 #endif /* OEM_ANDROID */
1182 #else /* For non x86 platforms */
1183 #define MEMDUMPINFO PLATFORM_PATH".memdump.info"
1184 #endif /* CONFIG_X86 */
1185 
1186 uint32
get_mem_val_from_file(void)1187 get_mem_val_from_file(void)
1188 {
1189 	struct file *fp = NULL;
1190 	uint32 mem_val = DUMP_MEMFILE_MAX;
1191 	char *p_mem_val = NULL;
1192 	char *filepath = MEMDUMPINFO;
1193 	int ret = 0;
1194 
1195 	/* Read memdump info from the file */
1196 	fp = dhd_filp_open(filepath, O_RDONLY, 0);
1197 	if (IS_ERR(fp) || (fp == NULL)) {
1198 		DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
1199 #if defined(CONFIG_X86) && defined(OEM_ANDROID)
1200 		/* Check if it is Live Brix Image */
1201 		if (strcmp(filepath, MEMDUMPINFO_LIVE) != 0) {
1202 			goto done;
1203 		}
1204 		/* Try if it is Installed Brix Image */
1205 		filepath = MEMDUMPINFO_INST;
1206 		DHD_ERROR(("%s: Try File [%s]\n", __FUNCTION__, filepath));
1207 		fp = dhd_filp_open(filepath, O_RDONLY, 0);
1208 		if (IS_ERR(fp) || (fp == NULL)) {
1209 			DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
1210 			goto done;
1211 		}
1212 #else /* Non Brix Android platform */
1213 		goto done;
1214 #endif /* CONFIG_X86 && OEM_ANDROID */
1215 	}
1216 
1217 	/* Handle success case */
1218 	ret = dhd_kernel_read_compat(fp, 0, (char *)&mem_val, sizeof(uint32));
1219 	if (ret < 0) {
1220 		DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret));
1221 		dhd_filp_close(fp, NULL);
1222 		goto done;
1223 	}
1224 
1225 	p_mem_val = (char*)&mem_val;
1226 	p_mem_val[sizeof(uint32) - 1] = '\0';
1227 	mem_val = bcm_atoi(p_mem_val);
1228 
1229 	dhd_filp_close(fp, NULL);
1230 
1231 done:
1232 	return mem_val;
1233 }
1234 
dhd_get_memdump_info(dhd_pub_t * dhd)1235 void dhd_get_memdump_info(dhd_pub_t *dhd)
1236 {
1237 #ifndef DHD_EXPORT_CNTL_FILE
1238 	uint32 mem_val = DUMP_MEMFILE_MAX;
1239 
1240 	mem_val = get_mem_val_from_file();
1241 	if (mem_val != DUMP_MEMFILE_MAX)
1242 		dhd->memdump_enabled = mem_val;
1243 #ifdef DHD_INIT_DEFAULT_MEMDUMP
1244 	if (mem_val == 0 || mem_val == DUMP_MEMFILE_MAX)
1245 		mem_val = DUMP_MEMFILE_BUGON;
1246 #endif /* DHD_INIT_DEFAULT_MEMDUMP */
1247 #else
1248 #ifdef DHD_INIT_DEFAULT_MEMDUMP
1249 	if (dhd->memdump_enabled == 0 || dhd->memdump_enabled == DUMP_MEMFILE_MAX)
1250 		dhd->memdump_enabled = DUMP_MEMFILE;
1251 #endif /* DHD_INIT_DEFAULT_MEMDUMP */
1252 #endif /* !DHD_EXPORT_CNTL_FILE */
1253 #ifdef BCMQT
1254 	/* In QT environment collecting memdump on FW TRAP, IOVAR timeouts,
1255 	 * is taking more time and makes system unresponsive so disabling it.
1256 	 * if needed memdump can be collected through 'dhd upload' command.
1257 	*/
1258 	dhd->memdump_enabled = DUMP_DISABLED;
1259 #endif
1260 #ifdef DHD_DETECT_CONSECUTIVE_MFG_HANG
1261 	/* override memdump_enabled value to avoid once trap issues */
1262 	if (dhd_bus_get_fw_mode(dhd) == DHD_FLAG_MFG_MODE &&
1263 			(dhd->memdump_enabled == DUMP_MEMONLY ||
1264 			dhd->memdump_enabled == DUMP_MEMFILE_BUGON)) {
1265 		dhd->memdump_enabled = DUMP_MEMFILE;
1266 		DHD_ERROR(("%s : Override memdump_value to %d\n",
1267 				__FUNCTION__, dhd->memdump_enabled));
1268 	}
1269 #endif /* DHD_DETECT_CONSECUTIVE_MFG_HANG */
1270 	DHD_ERROR(("%s: MEMDUMP ENABLED = %u\n", __FUNCTION__, dhd->memdump_enabled));
1271 }
1272 
1273 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
1274 #ifdef DHD_EXPORT_CNTL_FILE
1275 static ssize_t
show_memdump_info(struct dhd_info * dev,char * buf)1276 show_memdump_info(struct dhd_info *dev, char *buf)
1277 {
1278 	ssize_t ret = 0;
1279 	dhd_pub_t *dhdp;
1280 
1281 	if (!dev) {
1282 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
1283 		return ret;
1284 	}
1285 
1286 	dhdp = &dev->pub;
1287 	ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", dhdp->memdump_enabled);
1288 	return ret;
1289 }
1290 
1291 static ssize_t
set_memdump_info(struct dhd_info * dev,const char * buf,size_t count)1292 set_memdump_info(struct dhd_info *dev, const char *buf, size_t count)
1293 {
1294 	unsigned long memval;
1295 	dhd_pub_t *dhdp;
1296 
1297 	if (!dev) {
1298 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
1299 		return count;
1300 	}
1301 	dhdp = &dev->pub;
1302 
1303 	memval = bcm_strtoul(buf, NULL, 10);
1304 	sscanf(buf, "%lu", &memval);
1305 
1306 	dhdp->memdump_enabled = (uint32)memval;
1307 
1308 	DHD_ERROR(("%s: MEMDUMP ENABLED = %u\n", __FUNCTION__, dhdp->memdump_enabled));
1309 	return count;
1310 }
1311 
1312 static struct dhd_attr dhd_attr_memdump =
1313 	__ATTR(memdump, 0660, show_memdump_info, set_memdump_info);
1314 #endif /* DHD_EXPORT_CNTL_FILE */
1315 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
1316 #endif /* DHD_FW_COREDUMP */
1317 
1318 #ifdef BCMASSERT_LOG
1319 /*
1320  * XXX The filename to store assert type is defined for each platform.
1321  * New platforms can add their ifdefs accordingly below.
1322  */
1323 #define ASSERTINFO PLATFORM_PATH".assert.info"
1324 
1325 int
get_assert_val_from_file(void)1326 get_assert_val_from_file(void)
1327 {
1328 	struct file *fp = NULL;
1329 	char *filepath = ASSERTINFO;
1330 	char *p_mem_val = NULL;
1331 	int mem_val = -1;
1332 
1333 	/*
1334 	 * Read assert info from the file
1335 	 * 0: Trigger Kernel crash by panic()
1336 	 * 1: Print out the logs and don't trigger Kernel panic. (default)
1337 	 * 2: Trigger Kernel crash by BUG()
1338 	 * File doesn't exist: Keep default value (1).
1339 	 */
1340 	fp = dhd_filp_open(filepath, O_RDONLY, 0);
1341 	if (IS_ERR(fp) || (fp == NULL)) {
1342 		DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
1343 	} else {
1344 		int ret = dhd_kernel_read_compat(fp, 0, (char *)&mem_val, sizeof(uint32));
1345 		if (ret < 0) {
1346 			DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret));
1347 		} else {
1348 			p_mem_val = (char *)&mem_val;
1349 			p_mem_val[sizeof(uint32) - 1] = '\0';
1350 			mem_val = bcm_atoi(p_mem_val);
1351 			DHD_ERROR(("%s: ASSERT ENABLED = %d\n", __FUNCTION__, mem_val));
1352 		}
1353 		dhd_filp_close(fp, NULL);
1354 	}
1355 
1356 #ifdef CUSTOMER_HW4_DEBUG
1357 	mem_val = (mem_val >= 0) ? mem_val : 1;
1358 #else
1359 	mem_val = (mem_val >= 0) ? mem_val : 0;
1360 #endif /* CUSTOMER_HW4_DEBUG */
1361 	return mem_val;
1362 }
1363 
dhd_get_assert_info(dhd_pub_t * dhd)1364 void dhd_get_assert_info(dhd_pub_t *dhd)
1365 {
1366 #ifndef DHD_EXPORT_CNTL_FILE
1367 	int mem_val = -1;
1368 
1369 	mem_val = get_assert_val_from_file();
1370 
1371 	g_assert_type = mem_val;
1372 #endif /* !DHD_EXPORT_CNTL_FILE */
1373 }
1374 
1375 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
1376 #ifdef DHD_EXPORT_CNTL_FILE
1377 static ssize_t
show_assert_info(struct dhd_info * dev,char * buf)1378 show_assert_info(struct dhd_info *dev, char *buf)
1379 {
1380 	ssize_t ret = 0;
1381 
1382 	if (!dev) {
1383 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
1384 		return ret;
1385 	}
1386 
1387 	ret = scnprintf(buf, PAGE_SIZE -1, "%d\n", g_assert_type);
1388 	return ret;
1389 
1390 }
1391 
1392 static ssize_t
set_assert_info(struct dhd_info * dev,const char * buf,size_t count)1393 set_assert_info(struct dhd_info *dev, const char *buf, size_t count)
1394 {
1395 	unsigned long assert_val;
1396 
1397 	assert_val = bcm_strtoul(buf, NULL, 10);
1398 	sscanf(buf, "%lu", &assert_val);
1399 
1400 	g_assert_type = (uint32)assert_val;
1401 
1402 	DHD_ERROR(("%s: ASSERT ENABLED = %lu\n", __FUNCTION__, assert_val));
1403 	return count;
1404 
1405 }
1406 
1407 static struct dhd_attr dhd_attr_assert =
1408 	__ATTR(assert, 0660, show_assert_info, set_assert_info);
1409 #endif /* DHD_EXPORT_CNTL_FILE */
1410 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
1411 #endif /* BCMASSERT_LOG */
1412 
1413 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
1414 #ifdef DHD_EXPORT_CNTL_FILE
1415 #if defined(WRITE_WLANINFO)
1416 static ssize_t
show_wifiver_info(struct dhd_info * dev,char * buf)1417 show_wifiver_info(struct dhd_info *dev, char *buf)
1418 {
1419 	ssize_t ret = 0;
1420 
1421 	ret = scnprintf(buf, PAGE_SIZE -1, "%s", version_info);
1422 	return ret;
1423 }
1424 
1425 static ssize_t
set_wifiver_info(struct dhd_info * dev,const char * buf,size_t count)1426 set_wifiver_info(struct dhd_info *dev, const char *buf, size_t count)
1427 {
1428 	DHD_ERROR(("Do not set version info\n"));
1429 	return -EINVAL;
1430 }
1431 
1432 static struct dhd_attr dhd_attr_wifiver =
1433 	__ATTR(wifiver, 0660, show_wifiver_info, set_wifiver_info);
1434 #endif /* WRITE_WLANINFO */
1435 
1436 #if defined(USE_CID_CHECK) || defined(USE_DIRECT_VID_TAG)
1437 char cidinfostr[MAX_VNAME_LEN];
1438 
1439 static ssize_t
show_cid_info(struct dhd_info * dev,char * buf)1440 show_cid_info(struct dhd_info *dev, char *buf)
1441 {
1442 	ssize_t ret = 0;
1443 
1444 #ifdef USE_DIRECT_VID_TAG
1445 	ret = scnprintf(buf, PAGE_SIZE -1, "%x%x", cidinfostr[VENDOR_OFF], cidinfostr[MD_REV_OFF]);
1446 #endif /* USE_DIRECT_VID_TAG */
1447 #ifdef USE_CID_CHECK
1448 	ret = scnprintf(buf, PAGE_SIZE -1, "%s", cidinfostr);
1449 #endif /* USE_CID_CHECK */
1450 	return ret;
1451 }
1452 
1453 static ssize_t
set_cid_info(struct dhd_info * dev,const char * buf,size_t count)1454 set_cid_info(struct dhd_info *dev, const char *buf, size_t count)
1455 {
1456 #ifdef USE_DIRECT_VID_TAG
1457 	uint32 stored_vid = 0, md_rev = 0, vendor = 0;
1458 	uint32 vendor_mask = 0x00FF;
1459 
1460 	stored_vid = bcm_strtoul(buf, NULL, 16);
1461 
1462 	DHD_ERROR(("%s : stored_vid : 0x%x\n", __FUNCTION__, stored_vid));
1463 	md_rev = stored_vid & vendor_mask;
1464 	vendor = stored_vid >> 8;
1465 
1466 	memset(cidinfostr, 0, sizeof(cidinfostr));
1467 
1468 	cidinfostr[MD_REV_OFF] = (char)md_rev;
1469 	cidinfostr[VENDOR_OFF] = (char)vendor;
1470 	DHD_INFO(("CID string %x%x\n", cidinfostr[VENDOR_OFF], cidinfostr[MD_REV_OFF]));
1471 #endif /* USE_DIRECT_VID_TAG */
1472 #ifdef USE_CID_CHECK
1473 	int len = strlen(buf) + 1;
1474 	int maxstrsz;
1475 	maxstrsz = MAX_VNAME_LEN;
1476 
1477 	scnprintf(cidinfostr, ((len > maxstrsz) ? maxstrsz : len), "%s", buf);
1478 	DHD_INFO(("%s : CID info string\n", cidinfostr));
1479 #endif /* USE_CID_CHECK */
1480 	return count;
1481 }
1482 
1483 static struct dhd_attr dhd_attr_cidinfo =
1484 	__ATTR(cid, 0660, show_cid_info, set_cid_info);
1485 #endif /* USE_CID_CHECK || USE_DIRECT_VID_TAG */
1486 
1487 #if defined(GEN_SOFTAP_INFO_FILE)
1488 char softapinfostr[SOFTAP_INFO_BUF_SZ];
1489 static ssize_t
show_softap_info(struct dhd_info * dev,char * buf)1490 show_softap_info(struct dhd_info *dev, char *buf)
1491 {
1492 	ssize_t ret = 0;
1493 
1494 	ret = scnprintf(buf, PAGE_SIZE -1, "%s", softapinfostr);
1495 	return ret;
1496 }
1497 
1498 static ssize_t
set_softap_info(struct dhd_info * dev,const char * buf,size_t count)1499 set_softap_info(struct dhd_info *dev, const char *buf, size_t count)
1500 {
1501 	DHD_ERROR(("Do not set sofap related info\n"));
1502 	return -EINVAL;
1503 }
1504 
1505 static struct dhd_attr dhd_attr_softapinfo =
1506 	__ATTR(softap, 0660, show_softap_info, set_softap_info);
1507 #endif /* GEN_SOFTAP_INFO_FILE */
1508 
1509 #if defined(MIMO_ANT_SETTING)
1510 unsigned long antsel;
1511 
1512 static ssize_t
show_ant_info(struct dhd_info * dev,char * buf)1513 show_ant_info(struct dhd_info *dev, char *buf)
1514 {
1515 	ssize_t ret = 0;
1516 
1517 	ret = scnprintf(buf, PAGE_SIZE -1, "%lu\n", antsel);
1518 	return ret;
1519 }
1520 
1521 static ssize_t
set_ant_info(struct dhd_info * dev,const char * buf,size_t count)1522 set_ant_info(struct dhd_info *dev, const char *buf, size_t count)
1523 {
1524 	unsigned long ant_val;
1525 
1526 	ant_val = bcm_strtoul(buf, NULL, 10);
1527 	sscanf(buf, "%lu", &ant_val);
1528 
1529 	/*
1530 	 * Check value
1531 	 * 0 - Not set, handle same as file not exist
1532 	 */
1533 	if (ant_val > 3) {
1534 		DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %lu \n",
1535 			__FUNCTION__, ant_val));
1536 		return -EINVAL;
1537 	}
1538 
1539 	antsel = ant_val;
1540 	DHD_ERROR(("[WIFI_SEC] %s: Set Antinfo val = %lu \n", __FUNCTION__, antsel));
1541 	return count;
1542 }
1543 
1544 static struct dhd_attr dhd_attr_antinfo =
1545 	__ATTR(ant, 0660, show_ant_info, set_ant_info);
1546 #endif /* MIMO_ANT_SETTING */
1547 
1548 #ifdef DHD_PM_CONTROL_FROM_FILE
1549 extern uint32 pmmode_val;
1550 static ssize_t
show_pm_info(struct dhd_info * dev,char * buf)1551 show_pm_info(struct dhd_info *dev, char *buf)
1552 {
1553 	ssize_t ret = 0;
1554 
1555 	if (pmmode_val == 0xFF) {
1556 		ret = scnprintf(buf, PAGE_SIZE -1, "PM mode is not set\n");
1557 	} else {
1558 		ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", pmmode_val);
1559 	}
1560 	return ret;
1561 }
1562 
1563 static ssize_t
set_pm_info(struct dhd_info * dev,const char * buf,size_t count)1564 set_pm_info(struct dhd_info *dev, const char *buf, size_t count)
1565 {
1566 	unsigned long pm_val;
1567 
1568 	pm_val = bcm_strtoul(buf, NULL, 10);
1569 	sscanf(buf, "%lu", &pm_val);
1570 
1571 	if (pm_val > 2) {
1572 		DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %lu \n",
1573 			__FUNCTION__, pm_val));
1574 		return -EINVAL;
1575 	}
1576 
1577 	pmmode_val = (uint32)pm_val;
1578 	DHD_ERROR(("[WIFI_SEC] %s: Set pminfo val = %u\n", __FUNCTION__, pmmode_val));
1579 	return count;
1580 }
1581 
1582 static struct dhd_attr dhd_attr_pminfo =
1583 	__ATTR(pm, 0660, show_pm_info, set_pm_info);
1584 #endif /* DHD_PM_CONTROL_FROM_FILE */
1585 
1586 #ifdef LOGTRACE_FROM_FILE
1587 unsigned long logtrace_val = 1;
1588 
1589 static ssize_t
show_logtrace_info(struct dhd_info * dev,char * buf)1590 show_logtrace_info(struct dhd_info *dev, char *buf)
1591 {
1592 	ssize_t ret = 0;
1593 
1594 	ret = scnprintf(buf, PAGE_SIZE -1, "%lu\n", logtrace_val);
1595 	return ret;
1596 }
1597 
1598 static ssize_t
set_logtrace_info(struct dhd_info * dev,const char * buf,size_t count)1599 set_logtrace_info(struct dhd_info *dev, const char *buf, size_t count)
1600 {
1601 	unsigned long onoff;
1602 
1603 	onoff = bcm_strtoul(buf, NULL, 10);
1604 	sscanf(buf, "%lu", &onoff);
1605 
1606 	if (onoff > 2) {
1607 		DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %lu \n",
1608 			__FUNCTION__, onoff));
1609 		return -EINVAL;
1610 	}
1611 
1612 	logtrace_val = onoff;
1613 	DHD_ERROR(("[WIFI_SEC] %s: LOGTRACE On/Off from sysfs = %lu\n",
1614 		__FUNCTION__, logtrace_val));
1615 	return count;
1616 }
1617 
1618 static struct dhd_attr dhd_attr_logtraceinfo =
1619 	__ATTR(logtrace, 0660, show_logtrace_info, set_logtrace_info);
1620 #endif /* LOGTRACE_FROM_FILE */
1621 
1622 #ifdef  USE_WFA_CERT_CONF
1623 #ifdef BCMSDIO
1624 uint32 bus_txglom = VALUENOTSET;
1625 
1626 static ssize_t
show_bustxglom(struct dhd_info * dev,char * buf)1627 show_bustxglom(struct dhd_info *dev, char *buf)
1628 {
1629 	ssize_t ret = 0;
1630 
1631 	if (bus_txglom == VALUENOTSET) {
1632 		ret = scnprintf(buf, PAGE_SIZE - 1, "%s\n", "bustxglom not set from sysfs");
1633 	} else {
1634 		ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", bus_txglom);
1635 	}
1636 	return ret;
1637 }
1638 
1639 static ssize_t
set_bustxglom(struct dhd_info * dev,const char * buf,size_t count)1640 set_bustxglom(struct dhd_info *dev, const char *buf, size_t count)
1641 {
1642 	uint32 onoff;
1643 
1644 	onoff = (uint32)bcm_atoi(buf);
1645 	sscanf(buf, "%u", &onoff);
1646 
1647 	if (onoff > 2) {
1648 		DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
1649 			__FUNCTION__, onoff));
1650 		return -EINVAL;
1651 	}
1652 
1653 	bus_txglom = onoff;
1654 	DHD_ERROR(("[WIFI_SEC] %s: BUS TXGLOM On/Off from sysfs = %u\n",
1655 			__FUNCTION__, bus_txglom));
1656 	return count;
1657 }
1658 
1659 static struct dhd_attr dhd_attr_bustxglom =
1660 	__ATTR(bustxglom, 0660, show_bustxglom, set_bustxglom);
1661 #endif /* BCMSDIO */
1662 
1663 #if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM)
1664 uint32 roam_off = VALUENOTSET;
1665 
1666 static ssize_t
show_roamoff(struct dhd_info * dev,char * buf)1667 show_roamoff(struct dhd_info *dev, char *buf)
1668 {
1669 	ssize_t ret = 0;
1670 
1671 	if (roam_off == VALUENOTSET) {
1672 		ret = scnprintf(buf, PAGE_SIZE -1, "%s\n", "roam_off not set from sysfs");
1673 	} else {
1674 		ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", roam_off);
1675 	}
1676 	return ret;
1677 }
1678 
1679 static ssize_t
set_roamoff(struct dhd_info * dev,const char * buf,size_t count)1680 set_roamoff(struct dhd_info *dev, const char *buf, size_t count)
1681 {
1682 	uint32 onoff;
1683 
1684 	onoff = bcm_atoi(buf);
1685 	sscanf(buf, "%u", &onoff);
1686 
1687 	if (onoff > 2) {
1688 		DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
1689 			__FUNCTION__, onoff));
1690 		return -EINVAL;
1691 	}
1692 
1693 	roam_off = onoff;
1694 	DHD_ERROR(("[WIFI_SEC] %s: ROAM On/Off from sysfs = %u\n",
1695 		__FUNCTION__, roam_off));
1696 	return count;
1697 }
1698 
1699 static struct dhd_attr dhd_attr_roamoff =
1700 	__ATTR(roamoff, 0660, show_roamoff, set_roamoff);
1701 #endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */
1702 
1703 #ifdef USE_WL_FRAMEBURST
1704 uint32 frameburst = VALUENOTSET;
1705 
1706 static ssize_t
show_frameburst(struct dhd_info * dev,char * buf)1707 show_frameburst(struct dhd_info *dev, char *buf)
1708 {
1709 	ssize_t ret = 0;
1710 
1711 	if (frameburst == VALUENOTSET) {
1712 		ret = scnprintf(buf, PAGE_SIZE -1, "%s\n", "frameburst not set from sysfs");
1713 	} else {
1714 		ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", frameburst);
1715 	}
1716 	return ret;
1717 }
1718 
1719 static ssize_t
set_frameburst(struct dhd_info * dev,const char * buf,size_t count)1720 set_frameburst(struct dhd_info *dev, const char *buf, size_t count)
1721 {
1722 	uint32 onoff;
1723 
1724 	onoff = bcm_atoi(buf);
1725 	sscanf(buf, "%u", &onoff);
1726 
1727 	if (onoff > 2) {
1728 		DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
1729 			__FUNCTION__, onoff));
1730 		return -EINVAL;
1731 	}
1732 
1733 	frameburst = onoff;
1734 	DHD_ERROR(("[WIFI_SEC] %s: FRAMEBURST On/Off from sysfs = %u\n",
1735 		__FUNCTION__, frameburst));
1736 	return count;
1737 }
1738 
1739 static struct dhd_attr dhd_attr_frameburst =
1740 	__ATTR(frameburst, 0660, show_frameburst, set_frameburst);
1741 #endif /* USE_WL_FRAMEBURST */
1742 
1743 #ifdef USE_WL_TXBF
1744 uint32 txbf = VALUENOTSET;
1745 
1746 static ssize_t
show_txbf(struct dhd_info * dev,char * buf)1747 show_txbf(struct dhd_info *dev, char *buf)
1748 {
1749 	ssize_t ret = 0;
1750 
1751 	if (txbf == VALUENOTSET) {
1752 		ret = scnprintf(buf, PAGE_SIZE -1, "%s\n", "txbf not set from sysfs");
1753 	} else {
1754 		ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", txbf);
1755 	}
1756 	return ret;
1757 }
1758 
1759 static ssize_t
set_txbf(struct dhd_info * dev,const char * buf,size_t count)1760 set_txbf(struct dhd_info *dev, const char *buf, size_t count)
1761 {
1762 	uint32 onoff;
1763 
1764 	onoff = bcm_atoi(buf);
1765 	sscanf(buf, "%u", &onoff);
1766 
1767 	if (onoff > 2) {
1768 		DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
1769 			__FUNCTION__, onoff));
1770 		return -EINVAL;
1771 	}
1772 
1773 	txbf = onoff;
1774 	DHD_ERROR(("[WIFI_SEC] %s: FRAMEBURST On/Off from sysfs = %u\n",
1775 		__FUNCTION__, txbf));
1776 	return count;
1777 }
1778 
1779 static struct dhd_attr dhd_attr_txbf =
1780 	__ATTR(txbf, 0660, show_txbf, set_txbf);
1781 #endif /* USE_WL_TXBF */
1782 
1783 #ifdef PROP_TXSTATUS
1784 uint32 proptx = VALUENOTSET;
1785 
1786 static ssize_t
show_proptx(struct dhd_info * dev,char * buf)1787 show_proptx(struct dhd_info *dev, char *buf)
1788 {
1789 	ssize_t ret = 0;
1790 
1791 	if (proptx == VALUENOTSET) {
1792 		ret = scnprintf(buf, PAGE_SIZE -1, "%s\n", "proptx not set from sysfs");
1793 	} else {
1794 		ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", proptx);
1795 	}
1796 	return ret;
1797 }
1798 
1799 static ssize_t
set_proptx(struct dhd_info * dev,const char * buf,size_t count)1800 set_proptx(struct dhd_info *dev, const char *buf, size_t count)
1801 {
1802 	uint32 onoff;
1803 
1804 	onoff = bcm_strtoul(buf, NULL, 10);
1805 	sscanf(buf, "%u", &onoff);
1806 
1807 	if (onoff > 2) {
1808 		DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
1809 			__FUNCTION__, onoff));
1810 		return -EINVAL;
1811 	}
1812 
1813 	proptx = onoff;
1814 	DHD_ERROR(("[WIFI_SEC] %s: FRAMEBURST On/Off from sysfs = %u\n",
1815 		__FUNCTION__, txbf));
1816 	return count;
1817 }
1818 
1819 static struct dhd_attr dhd_attr_proptx =
1820 	__ATTR(proptx, 0660, show_proptx, set_proptx);
1821 
1822 #endif /* PROP_TXSTATUS */
1823 #endif /* USE_WFA_CERT_CONF */
1824 #endif /* DHD_EXPORT_CNTL_FILE */
1825 
1826 #if defined(DHD_ADPS_BAM_EXPORT) && defined(WL_BAM)
1827 #define BAD_AP_MAC_ADDR_ELEMENT_NUM	6
1828 wl_bad_ap_mngr_t *g_bad_ap_mngr = NULL;
1829 
1830 static ssize_t
show_adps_bam_list(struct dhd_info * dev,char * buf)1831 show_adps_bam_list(struct dhd_info *dev, char *buf)
1832 {
1833 	int offset = 0;
1834 	ssize_t ret = 0;
1835 
1836 	wl_bad_ap_info_t *bad_ap;
1837 	wl_bad_ap_info_entry_t *entry;
1838 
1839 	if (g_bad_ap_mngr == NULL)
1840 		return ret;
1841 
1842 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1843 	list_for_each_entry(entry, &g_bad_ap_mngr->list, list) {
1844 		bad_ap = &entry->bad_ap;
1845 
1846 		ret = scnprintf(buf + offset, PAGE_SIZE - 1, MACF"\n",
1847 			bad_ap->bssid.octet[0], bad_ap->bssid.octet[1],
1848 			bad_ap->bssid.octet[2], bad_ap->bssid.octet[3],
1849 			bad_ap->bssid.octet[4], bad_ap->bssid.octet[5]);
1850 
1851 		offset += ret;
1852 	}
1853 	GCC_DIAGNOSTIC_POP();
1854 
1855 	return offset;
1856 }
1857 
1858 static ssize_t
store_adps_bam_list(struct dhd_info * dev,const char * buf,size_t count)1859 store_adps_bam_list(struct dhd_info *dev, const char *buf, size_t count)
1860 {
1861 	int ret;
1862 	size_t len;
1863 	int offset;
1864 	char tmp[128];
1865 	wl_bad_ap_info_t bad_ap;
1866 
1867 	if (g_bad_ap_mngr == NULL)
1868 		return count;
1869 
1870 	len = count;
1871 	offset = 0;
1872 	do {
1873 		ret = sscanf(buf + offset, MACF"\n",
1874 			(uint32 *)&bad_ap.bssid.octet[0], (uint32 *)&bad_ap.bssid.octet[1],
1875 			(uint32 *)&bad_ap.bssid.octet[2], (uint32 *)&bad_ap.bssid.octet[3],
1876 			(uint32 *)&bad_ap.bssid.octet[4], (uint32 *)&bad_ap.bssid.octet[5]);
1877 		if (ret != BAD_AP_MAC_ADDR_ELEMENT_NUM) {
1878 			DHD_ERROR(("%s - fail to parse bad ap data\n", __FUNCTION__));
1879 			return -EINVAL;
1880 		}
1881 
1882 		ret = wl_bad_ap_mngr_add(g_bad_ap_mngr, &bad_ap);
1883 		if (ret < 0)
1884 			return ret;
1885 
1886 		ret = snprintf(tmp, ARRAYSIZE(tmp), MACF"\n",
1887 			bad_ap.bssid.octet[0], bad_ap.bssid.octet[1],
1888 			bad_ap.bssid.octet[2], bad_ap.bssid.octet[3],
1889 			bad_ap.bssid.octet[4], bad_ap.bssid.octet[5]);
1890 		if (ret < 0) {
1891 			DHD_ERROR(("%s - fail to get bad ap data length(%d)\n", __FUNCTION__, ret));
1892 			return ret;
1893 		}
1894 
1895 		len -= ret;
1896 		offset += ret;
1897 	} while (len > 0);
1898 
1899 	return count;
1900 }
1901 
1902 static struct dhd_attr dhd_attr_adps_bam =
1903 	__ATTR(bad_ap_list, 0660, show_adps_bam_list, store_adps_bam_list);
1904 #endif	/* DHD_ADPS_BAM_EXPORT && WL_BAM */
1905 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
1906 
1907 uint32 report_hang_privcmd_err = 1;
1908 
1909 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
1910 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
1911 static ssize_t
show_hang_privcmd_err(struct dhd_info * dev,char * buf)1912 show_hang_privcmd_err(struct dhd_info *dev, char *buf)
1913 {
1914 	ssize_t ret = 0;
1915 
1916 	ret = scnprintf(buf, PAGE_SIZE - 1, "%u\n", report_hang_privcmd_err);
1917 	return ret;
1918 }
1919 
1920 static ssize_t
set_hang_privcmd_err(struct dhd_info * dev,const char * buf,size_t count)1921 set_hang_privcmd_err(struct dhd_info *dev, const char *buf, size_t count)
1922 {
1923 	uint32 val;
1924 
1925 	val = bcm_atoi(buf);
1926 	sscanf(buf, "%u", &val);
1927 
1928 	report_hang_privcmd_err = val ? 1 : 0;
1929 	DHD_INFO(("%s: Set report HANG for private cmd error: %d\n",
1930 		__FUNCTION__, report_hang_privcmd_err));
1931 	return count;
1932 }
1933 
1934 static struct dhd_attr dhd_attr_hang_privcmd_err =
1935 	__ATTR(hang_privcmd_err, 0660, show_hang_privcmd_err, set_hang_privcmd_err);
1936 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
1937 
1938 #if defined(SHOW_LOGTRACE)
1939 static ssize_t
show_control_logtrace(struct dhd_info * dev,char * buf)1940 show_control_logtrace(struct dhd_info *dev, char *buf)
1941 {
1942 	ssize_t ret = 0;
1943 
1944 	ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", control_logtrace);
1945 	return ret;
1946 }
1947 
1948 static ssize_t
set_control_logtrace(struct dhd_info * dev,const char * buf,size_t count)1949 set_control_logtrace(struct dhd_info *dev, const char *buf, size_t count)
1950 {
1951 	uint32 val;
1952 
1953 	val = bcm_atoi(buf);
1954 
1955 	control_logtrace = val;
1956 	DHD_ERROR(("%s: Set control logtrace: %d\n", __FUNCTION__, control_logtrace));
1957 	return count;
1958 }
1959 
1960 static struct dhd_attr dhd_attr_control_logtrace =
1961 __ATTR(control_logtrace, 0660, show_control_logtrace, set_control_logtrace);
1962 #endif /* SHOW_LOGTRACE */
1963 
1964 #if defined(DISABLE_HE_ENAB) || defined(CUSTOM_CONTROL_HE_ENAB)
1965 uint8 control_he_enab = 1;
1966 #endif /* DISABLE_HE_ENAB || CUSTOM_CONTROL_HE_ENAB */
1967 
1968 #if defined(CUSTOM_CONTROL_HE_ENAB)
1969 static ssize_t
show_control_he_enab(struct dhd_info * dev,char * buf)1970 show_control_he_enab(struct dhd_info *dev, char *buf)
1971 {
1972 	ssize_t ret = 0;
1973 
1974 	ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", control_he_enab);
1975 	return ret;
1976 }
1977 
1978 static ssize_t
set_control_he_enab(struct dhd_info * dev,const char * buf,size_t count)1979 set_control_he_enab(struct dhd_info *dev, const char *buf, size_t count)
1980 {
1981 	uint32 val;
1982 
1983 	val = bcm_atoi(buf);
1984 
1985 	control_he_enab = val ? 1 : 0;
1986 	DHD_ERROR(("%s: Set control he enab: %d\n", __FUNCTION__, control_he_enab));
1987 	return count;
1988 }
1989 
1990 static struct dhd_attr dhd_attr_control_he_enab=
1991 __ATTR(control_he_enab, 0660, show_control_he_enab, set_control_he_enab);
1992 #endif /* CUSTOM_CONTROL_HE_ENAB */
1993 
1994 #if defined(WLAN_ACCEL_BOOT)
1995 static ssize_t
show_wl_accel_force_reg_on(struct dhd_info * dhd,char * buf)1996 show_wl_accel_force_reg_on(struct dhd_info *dhd, char *buf)
1997 {
1998 	ssize_t ret = 0;
1999 	if (!dhd) {
2000 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
2001 		return ret;
2002 	}
2003 
2004 	ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", dhd->wl_accel_force_reg_on);
2005 	return ret;
2006 }
2007 
2008 static ssize_t
set_wl_accel_force_reg_on(struct dhd_info * dhd,const char * buf,size_t count)2009 set_wl_accel_force_reg_on(struct dhd_info *dhd, const char *buf, size_t count)
2010 {
2011 	uint32 val;
2012 
2013 	if (!dhd) {
2014 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
2015 		return count;
2016 	}
2017 
2018 	val = bcm_atoi(buf);
2019 
2020 	dhd->wl_accel_force_reg_on = val ? 1 : 0;
2021 	DHD_ERROR(("%s: wl_accel_force_reg_on: %d\n", __FUNCTION__, dhd->wl_accel_force_reg_on));
2022 	return count;
2023 }
2024 
2025 static struct dhd_attr dhd_attr_wl_accel_force_reg_on=
2026 __ATTR(wl_accel_force_reg_on, 0660, show_wl_accel_force_reg_on, set_wl_accel_force_reg_on);
2027 #endif /* WLAN_ACCEL_BOOT */
2028 
2029 #if defined(AGG_H2D_DB)
2030 extern bool agg_h2d_db_enab;
2031 extern uint32 agg_h2d_db_timeout;
2032 extern uint32 agg_h2d_db_inflight_thresh;
2033 
2034 static ssize_t
show_agg_h2d_db_enab(struct dhd_info * dhd,char * buf)2035 show_agg_h2d_db_enab(struct dhd_info *dhd, char *buf)
2036 {
2037 	ssize_t ret = 0;
2038 	if (!dhd) {
2039 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
2040 		return ret;
2041 	}
2042 
2043 	ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", agg_h2d_db_enab);
2044 	return ret;
2045 }
2046 
2047 static ssize_t
set_agg_h2d_db_enab(struct dhd_info * dhd,const char * buf,size_t count)2048 set_agg_h2d_db_enab(struct dhd_info *dhd, const char *buf, size_t count)
2049 {
2050 	uint32 val;
2051 
2052 	if (!dhd) {
2053 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
2054 		return count;
2055 	}
2056 
2057 	val = bcm_atoi(buf);
2058 
2059 	agg_h2d_db_enab = val ? TRUE : FALSE;
2060 	DHD_ERROR(("%s: agg_h2d_db_timeout: %d\n", __FUNCTION__, agg_h2d_db_enab));
2061 	return count;
2062 }
2063 
2064 static struct dhd_attr dhd_attr_agg_h2d_db_enab =
2065 __ATTR(agg_h2d_db_enab, 0660, show_agg_h2d_db_enab, set_agg_h2d_db_enab);
2066 
2067 static ssize_t
show_agg_h2d_db_inflight_thresh(struct dhd_info * dhd,char * buf)2068 show_agg_h2d_db_inflight_thresh(struct dhd_info *dhd, char *buf)
2069 {
2070 	ssize_t ret = 0;
2071 	if (!dhd) {
2072 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
2073 		return ret;
2074 	}
2075 
2076 	ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", agg_h2d_db_inflight_thresh);
2077 	return ret;
2078 }
2079 
2080 static ssize_t
set_agg_h2d_db_inflight_thresh(struct dhd_info * dhd,const char * buf,size_t count)2081 set_agg_h2d_db_inflight_thresh(struct dhd_info *dhd, const char *buf, size_t count)
2082 {
2083 	uint32 val;
2084 
2085 	if (!dhd) {
2086 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
2087 		return count;
2088 	}
2089 
2090 	val = bcm_atoi(buf);
2091 
2092 	agg_h2d_db_inflight_thresh = val;
2093 	DHD_ERROR(("%s: agg_h2d_db_timeout: %d\n", __FUNCTION__, agg_h2d_db_inflight_thresh));
2094 	return count;
2095 }
2096 
2097 static struct dhd_attr dhd_attr_agg_h2d_db_inflight_thresh =
2098 __ATTR(agg_h2d_db_inflight_thresh, 0660, show_agg_h2d_db_inflight_thresh,
2099 	set_agg_h2d_db_inflight_thresh);
2100 
2101 static ssize_t
show_agg_h2d_db_timeout(struct dhd_info * dhd,char * buf)2102 show_agg_h2d_db_timeout(struct dhd_info *dhd, char *buf)
2103 {
2104 	ssize_t ret = 0;
2105 	if (!dhd) {
2106 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
2107 		return ret;
2108 	}
2109 
2110 	ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", agg_h2d_db_timeout);
2111 	return ret;
2112 }
2113 
2114 static ssize_t
set_agg_h2d_db_timeout(struct dhd_info * dhd,const char * buf,size_t count)2115 set_agg_h2d_db_timeout(struct dhd_info *dhd, const char *buf, size_t count)
2116 {
2117 	uint32 val;
2118 
2119 	if (!dhd) {
2120 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
2121 		return count;
2122 	}
2123 
2124 	val = bcm_atoi(buf);
2125 
2126 	agg_h2d_db_timeout = val;
2127 	DHD_ERROR(("%s: agg_h2d_db_timeout: %d\n", __FUNCTION__, agg_h2d_db_timeout));
2128 	return count;
2129 }
2130 
2131 static struct dhd_attr dhd_attr_agg_h2d_db_timeout =
2132 __ATTR(agg_h2d_db_timeout, 0660, show_agg_h2d_db_timeout, set_agg_h2d_db_timeout);
2133 #endif /* WLAN_ACCEL_BOOT */
2134 /*
2135  * Dumps the lock and other state information useful for debug
2136  *
2137  */
2138 static ssize_t
dhd_debug_dump_stateinfo(struct dhd_info * dhd,char * buf)2139 dhd_debug_dump_stateinfo(struct dhd_info *dhd, char *buf)
2140 {
2141 	u32 buf_size = PAGE_SIZE - 1;
2142 	u8 *ptr = buf;
2143 	ssize_t len = 0;
2144 
2145 	len += scnprintf(ptr, buf_size, "[DHD]\nlock info:\n");
2146 #ifdef BT_OVER_SDIO
2147 	len += scnprintf((ptr+len), (buf_size-len), "bus_user_lock:\n",
2148 			mutex_is_locked(&dhd->bus_user_lock));
2149 #endif /* BT_OVER_SDIO */
2150 
2151 #ifdef WL_CFG80211
2152 	len += wl_cfg80211_debug_data_dump(dhd_linux_get_primary_netdev(&dhd->pub),
2153 			(ptr + len), (buf_size - len));
2154 #endif /* WL_CFG80211 */
2155 
2156 	/* Ensure buffer ends with null char */
2157 	buf[len] = '\0';
2158 	return len + 1;
2159 }
2160 static struct dhd_attr dhd_attr_dhd_debug_data =
2161 __ATTR(dump_stateinfo, 0660, dhd_debug_dump_stateinfo, NULL);
2162 
2163 #ifdef WL_CFG80211
2164 #define _S(x) #x
2165 #define S(x) _S(x)
2166 #define SUBLOGLEVEL 20
2167 #define SUBLOGLEVELZ ((SUBLOGLEVEL) + (1))
2168 static const struct {
2169 	u32 log_level;
2170 	char *sublogname;
2171 } sublogname_map[] = {
2172 	{WL_DBG_ERR, "ERR"},
2173 	{WL_DBG_INFO, "INFO"},
2174 	{WL_DBG_DBG, "DBG"},
2175 	{WL_DBG_SCAN, "SCAN"},
2176 	{WL_DBG_TRACE, "TRACE"},
2177 	{WL_DBG_P2P_ACTION, "P2PACTION"}
2178 };
2179 
2180 /**
2181 * Format : echo "SCAN:1 DBG:1" > /sys/wifi/wl_dbg_level
2182 * to turn on SCAN and DBG log.
2183 * To turn off SCAN partially, echo "SCAN:0" > /sys/wifi/wl_dbg_level
2184 * To see current setting of debug level,
2185 * cat /sys/wifi/wl_dbg_level
2186 */
2187 static ssize_t
show_wl_debug_level(struct dhd_info * dhd,char * buf)2188 show_wl_debug_level(struct dhd_info *dhd, char *buf)
2189 {
2190 	char *param;
2191 	char tbuf[SUBLOGLEVELZ * ARRAYSIZE(sublogname_map)];
2192 	uint i;
2193 	ssize_t ret = 0;
2194 
2195 	bzero(tbuf, sizeof(tbuf));
2196 	param = &tbuf[0];
2197 	for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
2198 		param += snprintf(param, sizeof(tbuf) - 1, "%s:%d ",
2199 			sublogname_map[i].sublogname,
2200 			(wl_dbg_level & sublogname_map[i].log_level) ? 1 : 0);
2201 	}
2202 	ret = scnprintf(buf, PAGE_SIZE - 1, "%s \n", tbuf);
2203 	return ret;
2204 }
2205 
2206 static ssize_t
set_wl_debug_level(struct dhd_info * dhd,const char * buf,size_t count)2207 set_wl_debug_level(struct dhd_info *dhd, const char *buf, size_t count)
2208 {
2209 	char tbuf[SUBLOGLEVELZ * ARRAYSIZE(sublogname_map)], sublog[SUBLOGLEVELZ];
2210 	char *params, *token, *colon;
2211 	uint i, tokens, log_on = 0;
2212 	size_t minsize = min_t(size_t, (sizeof(tbuf) - 1), count);
2213 
2214 	bzero(tbuf, sizeof(tbuf));
2215 	bzero(sublog, sizeof(sublog));
2216 	strlcpy(tbuf, buf, minsize);
2217 
2218 	DHD_INFO(("current wl_dbg_level %d \n", wl_dbg_level));
2219 
2220 	tbuf[minsize] = '\0';
2221 	params = &tbuf[0];
2222 	colon = strchr(params, '\n');
2223 	if (colon != NULL)
2224 		*colon = '\0';
2225 	while ((token = strsep(&params, " ")) != NULL) {
2226 		bzero(sublog, sizeof(sublog));
2227 		if (token == NULL || !*token)
2228 			break;
2229 		if (*token == '\0')
2230 			continue;
2231 		colon = strchr(token, ':');
2232 		if (colon != NULL) {
2233 			*colon = ' ';
2234 		}
2235 		tokens = sscanf(token, "%"S(SUBLOGLEVEL)"s %u", sublog, &log_on);
2236 		if (colon != NULL)
2237 			*colon = ':';
2238 
2239 		if (tokens == 2) {
2240 				for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
2241 					if (!strncmp(sublog, sublogname_map[i].sublogname,
2242 						strlen(sublogname_map[i].sublogname))) {
2243 						if (log_on)
2244 							wl_dbg_level |=
2245 							(sublogname_map[i].log_level);
2246 						else
2247 							wl_dbg_level &=
2248 							~(sublogname_map[i].log_level);
2249 					}
2250 				}
2251 		} else
2252 			WL_ERR(("%s: can't parse '%s' as a "
2253 			       "SUBMODULE:LEVEL (%d tokens)\n",
2254 			       tbuf, token, tokens));
2255 
2256 	}
2257 	DHD_INFO(("changed wl_dbg_level %d \n", wl_dbg_level));
2258 	return count;
2259 }
2260 
2261 static struct dhd_attr dhd_attr_wl_dbg_level =
2262 __ATTR(wl_dbg_level, 0660, show_wl_debug_level, set_wl_debug_level);
2263 #endif /* WL_CFG80211 */
2264 
2265 /* Attribute object that gets registered with "wifi" kobject tree */
2266 static struct attribute *default_file_attrs[] = {
2267 #ifdef DHD_MAC_ADDR_EXPORT
2268 	&dhd_attr_macaddr.attr,
2269 #endif /* DHD_MAC_ADDR_EXPORT */
2270 #ifdef DHD_EXPORT_CNTL_FILE
2271 #ifdef DHD_FW_COREDUMP
2272 	&dhd_attr_memdump.attr,
2273 #endif /* DHD_FW_COREDUMP */
2274 #ifdef BCMASSERT_LOG
2275 	&dhd_attr_assert.attr,
2276 #endif /* BCMASSERT_LOG */
2277 #ifdef WRITE_WLANINFO
2278 	&dhd_attr_wifiver.attr,
2279 #endif /* WRITE_WLANINFO */
2280 #if defined(USE_CID_CHECK) || defined(USE_DIRECT_VID_TAG)
2281 	&dhd_attr_cidinfo.attr,
2282 #endif /* USE_CID_CHECK || USE_DIRECT_VID_TAG */
2283 #ifdef GEN_SOFTAP_INFO_FILE
2284 	&dhd_attr_softapinfo.attr,
2285 #endif /* GEN_SOFTAP_INFO_FILE */
2286 #ifdef MIMO_ANT_SETTING
2287 	&dhd_attr_antinfo.attr,
2288 #endif /* MIMO_ANT_SETTING */
2289 #ifdef DHD_PM_CONTROL_FROM_FILE
2290 	&dhd_attr_pminfo.attr,
2291 #endif /* DHD_PM_CONTROL_FROM_FILE */
2292 #ifdef LOGTRACE_FROM_FILE
2293 	&dhd_attr_logtraceinfo.attr,
2294 #endif /* LOGTRACE_FROM_FILE */
2295 #ifdef USE_WFA_CERT_CONF
2296 #ifdef BCMSDIO
2297 	&dhd_attr_bustxglom.attr,
2298 #endif /* BCMSDIO */
2299 	&dhd_attr_roamoff.attr,
2300 #ifdef USE_WL_FRAMEBURST
2301 	&dhd_attr_frameburst.attr,
2302 #endif /* USE_WL_FRAMEBURST */
2303 #ifdef USE_WL_TXBF
2304 	&dhd_attr_txbf.attr,
2305 #endif /* USE_WL_TXBF */
2306 #ifdef PROP_TXSTATUS
2307 	&dhd_attr_proptx.attr,
2308 #endif /* PROP_TXSTATUS */
2309 #endif /* USE_WFA_CERT_CONF */
2310 #endif /* DHD_EXPORT_CNTL_FILE */
2311 #if defined(DHD_ADPS_BAM_EXPORT) && defined(WL_BAM)
2312 	&dhd_attr_adps_bam.attr,
2313 #endif	/* DHD_ADPS_BAM_EXPORT && WL_BAM */
2314 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
2315 	&dhd_attr_hang_privcmd_err.attr,
2316 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
2317 #if defined(SHOW_LOGTRACE)
2318 	&dhd_attr_control_logtrace.attr,
2319 #endif /* SHOW_LOGTRACE */
2320 #if defined(DHD_TRACE_WAKE_LOCK)
2321 	&dhd_attr_wklock.attr,
2322 #endif
2323 #ifdef DHD_LOG_DUMP
2324 	&dhd_attr_logdump_periodic_flush.attr,
2325 	&dhd_attr_logdump_ecntr.attr,
2326 #endif
2327 	&dhd_attr_ecounters.attr,
2328 #ifdef DHD_QOS_ON_SOCK_FLOW
2329 	&dhd_attr_sock_qos_onoff.attr,
2330 	&dhd_attr_sock_qos_stats.attr,
2331 	&dhd_attr_sock_qos_upgrade.attr,
2332 	&dhd_attr_sock_qos_numfl_upgrd_thresh.attr,
2333 	&dhd_attr_sock_qos_avgpktsize_thresh.attr,
2334 	&dhd_attr_sock_qos_numpkts_thresh.attr,
2335 	&dhd_attr_sock_qos_detectcnt_thresh.attr,
2336 	&dhd_attr_sock_qos_detectcnt_upgrd_thresh.attr,
2337 	&dhd_attr_sock_qos_maxfl.attr,
2338 #ifdef DHD_QOS_ON_SOCK_FLOW_UT
2339 	&dhd_attr_sock_qos_unit_test.attr,
2340 #endif /* DHD_QOS_ON_SOCK_FLOW_UT */
2341 #endif /* DHD_QOS_ON_SOCK_FLOW */
2342 #ifdef DHD_SSSR_DUMP
2343 	&dhd_attr_sssr_enab.attr,
2344 	&dhd_attr_fis_enab.attr,
2345 #endif /* DHD_SSSR_DUMP */
2346 	&dhd_attr_firmware_path.attr,
2347 	&dhd_attr_nvram_path.attr,
2348 #if defined(CUSTOM_CONTROL_HE_ENAB)
2349 	&dhd_attr_control_he_enab.attr,
2350 #endif /* CUSTOM_CONTROL_HE_ENAB */
2351 #if defined(WLAN_ACCEL_BOOT)
2352 	&dhd_attr_wl_accel_force_reg_on.attr,
2353 #endif /* WLAN_ACCEL_BOOT */
2354 #ifdef PWRSTATS_SYSFS
2355 	&dhd_attr_pwrstats_path.attr,
2356 #endif /* PWRSTATS_SYSFS */
2357 #if defined(WL_CFG80211)
2358 	&dhd_attr_wl_dbg_level.attr,
2359 #endif /* WL_CFG80211 */
2360 	&dhd_attr_dhd_debug_data.attr,
2361 #if defined(AGG_H2D_DB)
2362 	&dhd_attr_agg_h2d_db_enab.attr,
2363 	&dhd_attr_agg_h2d_db_inflight_thresh.attr,
2364 	&dhd_attr_agg_h2d_db_timeout.attr,
2365 #endif /* AGG_H2D_DB */
2366 	NULL
2367 };
2368 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
2369 
2370 /*
2371  * wifi kobject show function, the "attr" attribute specifices to which
2372  * node under "sys/wifi" the show function is called.
2373  */
dhd_show(struct kobject * kobj,struct attribute * attr,char * buf)2374 static ssize_t dhd_show(struct kobject *kobj, struct attribute *attr, char *buf)
2375 {
2376 	dhd_info_t *dhd;
2377 	struct dhd_attr *d_attr;
2378 	int ret;
2379 
2380 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2381 	dhd = to_dhd(kobj);
2382 	d_attr = to_attr(attr);
2383 	GCC_DIAGNOSTIC_POP();
2384 
2385 	if (d_attr->show)
2386 		ret = d_attr->show(dhd, buf);
2387 	else
2388 		ret = -EIO;
2389 
2390 	return ret;
2391 }
2392 
2393 /*
2394  * wifi kobject show function, the "attr" attribute specifices to which
2395  * node under "sys/wifi" the store function is called.
2396  */
dhd_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t count)2397 static ssize_t dhd_store(struct kobject *kobj, struct attribute *attr,
2398 	const char *buf, size_t count)
2399 {
2400 	dhd_info_t *dhd;
2401 	struct dhd_attr *d_attr;
2402 	int ret;
2403 
2404 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2405 	dhd = to_dhd(kobj);
2406 	d_attr = to_attr(attr);
2407 	GCC_DIAGNOSTIC_POP();
2408 
2409 	if (d_attr->store)
2410 		ret = d_attr->store(dhd, buf, count);
2411 	else
2412 		ret = -EIO;
2413 
2414 	return ret;
2415 
2416 }
2417 
2418 static struct sysfs_ops dhd_sysfs_ops = {
2419 	.show = dhd_show,
2420 	.store = dhd_store,
2421 };
2422 
2423 static struct kobj_type dhd_ktype = {
2424 	.sysfs_ops = &dhd_sysfs_ops,
2425 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
2426 	.default_attrs = default_file_attrs,
2427 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
2428 };
2429 
2430 #ifdef CSI_SUPPORT
2431 /* Function to show current ccode */
read_csi_data(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)2432 static ssize_t read_csi_data(struct file *filp, struct kobject *kobj,
2433 	struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count)
2434 {
2435 	dhd_info_t *dhd = to_dhd(kobj);
2436 	int n = 0;
2437 
2438 	n = dhd_csi_dump_list(&dhd->pub, buf);
2439 	DHD_INFO(("Dump data to file, size %d\n", n));
2440 	dhd_csi_clean_list(&dhd->pub);
2441 
2442 	return n;
2443 }
2444 
2445 static struct bin_attribute dhd_attr_csi = {
2446 	.attr = { .name = "csi" BUS_TYPE,
2447 		  .mode = 0660, },
2448 	.size = MAX_CSI_FILESZ,
2449 	.read = read_csi_data,
2450 };
2451 #endif /* CSI_SUPPORT */
2452 
2453 /*
2454  * sysfs for dhd_lb
2455  */
2456 #ifdef DHD_LB
2457 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
2458 #if defined(DHD_LB_TXP)
2459 static ssize_t
show_lbtxp(struct dhd_info * dev,char * buf)2460 show_lbtxp(struct dhd_info *dev, char *buf)
2461 {
2462 	ssize_t ret = 0;
2463 	unsigned long onoff;
2464 	dhd_info_t *dhd = (dhd_info_t *)dev;
2465 
2466 	onoff = atomic_read(&dhd->lb_txp_active);
2467 	ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n",
2468 		onoff);
2469 	return ret;
2470 }
2471 
2472 static ssize_t
lbtxp_onoff(struct dhd_info * dev,const char * buf,size_t count)2473 lbtxp_onoff(struct dhd_info *dev, const char *buf, size_t count)
2474 {
2475 	unsigned long onoff;
2476 	dhd_info_t *dhd = (dhd_info_t *)dev;
2477 	int i;
2478 
2479 	onoff = bcm_strtoul(buf, NULL, 10);
2480 
2481 	sscanf(buf, "%lu", &onoff);
2482 	if (onoff != 0 && onoff != 1) {
2483 		return -EINVAL;
2484 	}
2485 	atomic_set(&dhd->lb_txp_active, onoff);
2486 
2487 	/* Since the scheme is changed clear the counters */
2488 	for (i = 0; i < NR_CPUS; i++) {
2489 		DHD_LB_STATS_CLR(dhd->txp_percpu_run_cnt[i]);
2490 		DHD_LB_STATS_CLR(dhd->tx_start_percpu_run_cnt[i]);
2491 	}
2492 
2493 	return count;
2494 }
2495 
2496 static struct dhd_attr dhd_attr_lbtxp =
2497 	__ATTR(lbtxp, 0660, show_lbtxp, lbtxp_onoff);
2498 #endif /* DHD_LB_TXP */
2499 
2500 #if defined(DHD_LB_RXP)
2501 static ssize_t
show_lbrxp(struct dhd_info * dev,char * buf)2502 show_lbrxp(struct dhd_info *dev, char *buf)
2503 {
2504 	ssize_t ret = 0;
2505 	unsigned long onoff;
2506 	dhd_info_t *dhd = (dhd_info_t *)dev;
2507 
2508 	onoff = atomic_read(&dhd->lb_rxp_active);
2509 	ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n",
2510 		onoff);
2511 	return ret;
2512 }
2513 
2514 static ssize_t
lbrxp_onoff(struct dhd_info * dev,const char * buf,size_t count)2515 lbrxp_onoff(struct dhd_info *dev, const char *buf, size_t count)
2516 {
2517 	unsigned long onoff;
2518 	dhd_info_t *dhd = (dhd_info_t *)dev;
2519 
2520 	onoff = bcm_strtoul(buf, NULL, 10);
2521 
2522 	sscanf(buf, "%lu", &onoff);
2523 	if (onoff != 0 && onoff != 1) {
2524 		return -EINVAL;
2525 	}
2526 	atomic_set(&dhd->lb_rxp_active, onoff);
2527 
2528 	return count;
2529 }
2530 static struct dhd_attr dhd_attr_lbrxp =
2531 	__ATTR(lbrxp, 0660, show_lbrxp, lbrxp_onoff);
2532 
2533 static ssize_t
get_lb_rxp_stop_thr(struct dhd_info * dev,char * buf)2534 get_lb_rxp_stop_thr(struct dhd_info *dev, char *buf)
2535 {
2536 	dhd_info_t *dhd = (dhd_info_t *)dev;
2537 	dhd_pub_t *dhdp;
2538 	ssize_t ret = 0;
2539 
2540 	if (!dhd) {
2541 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
2542 		return -EINVAL;
2543 	}
2544 	dhdp = &dhd->pub;
2545 
2546 	ret = scnprintf(buf, PAGE_SIZE - 1, "%u \n",
2547 		(dhdp->lb_rxp_stop_thr / D2HRING_RXCMPLT_MAX_ITEM));
2548 	return ret;
2549 }
2550 
2551 #define ONE_GB (1024 * 1024 * 1024)
2552 
2553 static ssize_t
set_lb_rxp_stop_thr(struct dhd_info * dev,const char * buf,size_t count)2554 set_lb_rxp_stop_thr(struct dhd_info *dev, const char *buf, size_t count)
2555 {
2556 	dhd_info_t *dhd = (dhd_info_t *)dev;
2557 	dhd_pub_t *dhdp;
2558 	uint32 lb_rxp_stop_thr;
2559 
2560 	if (!dhd) {
2561 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
2562 		return -EINVAL;
2563 	}
2564 	dhdp = &dhd->pub;
2565 
2566 	lb_rxp_stop_thr = bcm_strtoul(buf, NULL, 10);
2567 	sscanf(buf, "%u", &lb_rxp_stop_thr);
2568 
2569 	/* disable lb_rxp flow ctrl */
2570 	if (lb_rxp_stop_thr == 0) {
2571 		dhdp->lb_rxp_stop_thr = 0;
2572 		dhdp->lb_rxp_strt_thr = 0;
2573 		atomic_set(&dhd->pub.lb_rxp_flow_ctrl, FALSE);
2574 		return count;
2575 	}
2576 	/* 1. by the time lb_rxp_stop_thr gets into picture,
2577 	 * DHD RX path should not consume more than 1GB
2578 	 * 2. lb_rxp_stop_thr should always be more than dhdp->lb_rxp_strt_thr
2579 	 */
2580 	if (((lb_rxp_stop_thr *
2581 		D2HRING_RXCMPLT_MAX_ITEM *
2582 		dhd_prot_get_rxbufpost_sz(dhdp)) > ONE_GB) ||
2583 		(lb_rxp_stop_thr <= (dhdp->lb_rxp_strt_thr / D2HRING_RXCMPLT_MAX_ITEM))) {
2584 		return -EINVAL;
2585 	}
2586 
2587 	dhdp->lb_rxp_stop_thr = (D2HRING_RXCMPLT_MAX_ITEM * lb_rxp_stop_thr);
2588 	return count;
2589 }
2590 
2591 static struct dhd_attr dhd_attr_lb_rxp_stop_thr =
2592 	__ATTR(lbrxp_stop_thr, 0660, get_lb_rxp_stop_thr, set_lb_rxp_stop_thr);
2593 
2594 static ssize_t
get_lb_rxp_strt_thr(struct dhd_info * dev,char * buf)2595 get_lb_rxp_strt_thr(struct dhd_info *dev, char *buf)
2596 {
2597 	dhd_info_t *dhd = (dhd_info_t *)dev;
2598 	dhd_pub_t *dhdp;
2599 	ssize_t ret = 0;
2600 
2601 	if (!dhd) {
2602 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
2603 		return -EINVAL;
2604 	}
2605 	dhdp = &dhd->pub;
2606 
2607 	ret = scnprintf(buf, PAGE_SIZE - 1, "%u \n",
2608 		(dhdp->lb_rxp_strt_thr / D2HRING_RXCMPLT_MAX_ITEM));
2609 	return ret;
2610 }
2611 
2612 static ssize_t
set_lb_rxp_strt_thr(struct dhd_info * dev,const char * buf,size_t count)2613 set_lb_rxp_strt_thr(struct dhd_info *dev, const char *buf, size_t count)
2614 {
2615 	dhd_info_t *dhd = (dhd_info_t *)dev;
2616 	dhd_pub_t *dhdp;
2617 	uint32 lb_rxp_strt_thr;
2618 
2619 	if (!dhd) {
2620 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
2621 		return -EINVAL;
2622 	}
2623 	dhdp = &dhd->pub;
2624 
2625 	lb_rxp_strt_thr = bcm_strtoul(buf, NULL, 10);
2626 	sscanf(buf, "%u", &lb_rxp_strt_thr);
2627 
2628 	/* disable lb_rxp flow ctrl */
2629 	if (lb_rxp_strt_thr == 0) {
2630 		dhdp->lb_rxp_strt_thr = 0;
2631 		dhdp->lb_rxp_stop_thr = 0;
2632 		atomic_set(&dhd->pub.lb_rxp_flow_ctrl, FALSE);
2633 		return count;
2634 	}
2635 	/* should be less than dhdp->lb_rxp_stop_thr */
2636 	if ((lb_rxp_strt_thr <= 0) ||
2637 		(lb_rxp_strt_thr >= (dhdp->lb_rxp_stop_thr / D2HRING_RXCMPLT_MAX_ITEM))) {
2638 		return -EINVAL;
2639 	}
2640 	dhdp->lb_rxp_strt_thr = (D2HRING_RXCMPLT_MAX_ITEM * lb_rxp_strt_thr);
2641 	return count;
2642 }
2643 static struct dhd_attr dhd_attr_lb_rxp_strt_thr =
2644 	__ATTR(lbrxp_strt_thr, 0660, get_lb_rxp_strt_thr, set_lb_rxp_strt_thr);
2645 
2646 #endif /* DHD_LB_RXP */
2647 
2648 static ssize_t
show_candidacy_override(struct dhd_info * dev,char * buf)2649 show_candidacy_override(struct dhd_info *dev, char *buf)
2650 {
2651 	ssize_t ret = 0;
2652 
2653 	ret = scnprintf(buf, PAGE_SIZE - 1,
2654 			"%d\n", (int)dev->dhd_lb_candidacy_override);
2655 	return ret;
2656 }
2657 
2658 static ssize_t
set_candidacy_override(struct dhd_info * dev,const char * buf,size_t count)2659 set_candidacy_override(struct dhd_info *dev, const char *buf, size_t count)
2660 {
2661 
2662 	int val = 0;
2663 	val = bcm_atoi(buf);
2664 
2665 	if (val > 0) {
2666 		dev->dhd_lb_candidacy_override = TRUE;
2667 	} else {
2668 		dev->dhd_lb_candidacy_override = FALSE;
2669 	}
2670 
2671 	DHD_ERROR(("set dhd_lb_candidacy_override %d\n", dev->dhd_lb_candidacy_override));
2672 	return count;
2673 }
2674 
2675 static struct dhd_attr dhd_candidacy_override =
2676 __ATTR(candidacy_override, 0660, show_candidacy_override, set_candidacy_override);
2677 
2678 static ssize_t
show_primary_mask(struct dhd_info * dev,char * buf)2679 show_primary_mask(struct dhd_info *dev, char *buf)
2680 {
2681 	ssize_t ret = 0;
2682 
2683 	ret = scnprintf(buf, PAGE_SIZE - 1,
2684 			"%02lx\n", *cpumask_bits(dev->cpumask_primary));
2685 	return ret;
2686 }
2687 
2688 static ssize_t
set_primary_mask(struct dhd_info * dev,const char * buf,size_t count)2689 set_primary_mask(struct dhd_info *dev, const char *buf, size_t count)
2690 {
2691 	int ret;
2692 
2693 	cpumask_var_t primary_mask;
2694 
2695 	if (!alloc_cpumask_var(&primary_mask, GFP_KERNEL)) {
2696 		DHD_ERROR(("Can't allocate cpumask vars\n"));
2697 		return count;
2698 	}
2699 
2700 	cpumask_clear(primary_mask);
2701 	ret = cpumask_parse(buf, primary_mask);
2702 	if (ret < 0) {
2703 		DHD_ERROR(("Setting cpumask failed ret = %d\n", ret));
2704 		return count;
2705 	}
2706 
2707 	cpumask_clear(dev->cpumask_primary);
2708 	cpumask_or(dev->cpumask_primary, dev->cpumask_primary, primary_mask);
2709 
2710 	DHD_ERROR(("set cpumask results cpumask_primary 0x%2lx\n",
2711 		*cpumask_bits(dev->cpumask_primary)));
2712 
2713 	dhd_select_cpu_candidacy(dev);
2714 	return count;
2715 }
2716 
2717 static struct dhd_attr dhd_primary_mask =
2718 __ATTR(primary_mask, 0660, show_primary_mask, set_primary_mask);
2719 
2720 static ssize_t
show_secondary_mask(struct dhd_info * dev,char * buf)2721 show_secondary_mask(struct dhd_info *dev, char *buf)
2722 {
2723 	ssize_t ret = 0;
2724 
2725 	ret = scnprintf(buf, PAGE_SIZE - 1,
2726 			"%02lx\n", *cpumask_bits(dev->cpumask_secondary));
2727 	return ret;
2728 }
2729 
2730 static ssize_t
set_secondary_mask(struct dhd_info * dev,const char * buf,size_t count)2731 set_secondary_mask(struct dhd_info *dev, const char *buf, size_t count)
2732 {
2733 	int ret;
2734 
2735 	cpumask_var_t secondary_mask;
2736 
2737 	if (!alloc_cpumask_var(&secondary_mask, GFP_KERNEL)) {
2738 		DHD_ERROR(("Can't allocate cpumask vars\n"));
2739 		return count;
2740 	}
2741 
2742 	cpumask_clear(secondary_mask);
2743 
2744 	ret = cpumask_parse(buf, secondary_mask);
2745 
2746 	if (ret < 0) {
2747 		DHD_ERROR(("Setting cpumask failed ret = %d\n", ret));
2748 		return count;
2749 	}
2750 
2751 	cpumask_clear(dev->cpumask_secondary);
2752 	cpumask_or(dev->cpumask_secondary, dev->cpumask_secondary, secondary_mask);
2753 
2754 	DHD_ERROR(("set cpumask results cpumask_secondary 0x%2lx\n",
2755 		*cpumask_bits(dev->cpumask_secondary)));
2756 
2757 	dhd_select_cpu_candidacy(dev);
2758 
2759 	return count;
2760 }
2761 
2762 static struct dhd_attr dhd_secondary_mask =
2763 __ATTR(secondary_mask, 0660, show_secondary_mask, set_secondary_mask);
2764 
2765 static ssize_t
show_rx_cpu(struct dhd_info * dev,char * buf)2766 show_rx_cpu(struct dhd_info *dev, char *buf)
2767 {
2768 	ssize_t ret = 0;
2769 
2770 	ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", atomic_read(&dev->rx_napi_cpu));
2771 	return ret;
2772 }
2773 
2774 static ssize_t
set_rx_cpu(struct dhd_info * dev,const char * buf,size_t count)2775 set_rx_cpu(struct dhd_info *dev, const char *buf, size_t count)
2776 {
2777 	uint32 val;
2778 
2779 	if (!dev->dhd_lb_candidacy_override) {
2780 		DHD_ERROR(("dhd_lb_candidacy_override is required %d\n",
2781 			dev->dhd_lb_candidacy_override));
2782 		return count;
2783 	}
2784 
2785 	val = (uint32)bcm_atoi(buf);
2786 	if (val >= nr_cpu_ids)
2787 	{
2788 		DHD_ERROR(("%s : can't set the value out of number of cpus, val = %u\n",
2789 			__FUNCTION__, val));
2790 	}
2791 
2792 	atomic_set(&dev->rx_napi_cpu, val);
2793 	DHD_ERROR(("%s: rx_napi_cpu = %d\n", __FUNCTION__, atomic_read(&dev->rx_napi_cpu)));
2794 	return count;
2795 }
2796 
2797 static struct dhd_attr dhd_rx_cpu =
2798 __ATTR(rx_cpu, 0660, show_rx_cpu, set_rx_cpu);
2799 
2800 static ssize_t
show_tx_cpu(struct dhd_info * dev,char * buf)2801 show_tx_cpu(struct dhd_info *dev, char *buf)
2802 {
2803 	ssize_t ret = 0;
2804 
2805 	ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", atomic_read(&dev->tx_cpu));
2806 	return ret;
2807 }
2808 
2809 static ssize_t
set_tx_cpu(struct dhd_info * dev,const char * buf,size_t count)2810 set_tx_cpu(struct dhd_info *dev, const char *buf, size_t count)
2811 {
2812 	uint32 val;
2813 
2814 	if (!dev->dhd_lb_candidacy_override) {
2815 		DHD_ERROR(("dhd_lb_candidacy_override is required %d\n",
2816 			dev->dhd_lb_candidacy_override));
2817 		return count;
2818 	}
2819 
2820 	val = (uint32)bcm_atoi(buf);
2821 	if (val >= nr_cpu_ids)
2822 	{
2823 		DHD_ERROR(("%s : can't set the value out of number of cpus, val = %u\n",
2824 			__FUNCTION__, val));
2825 		return count;
2826 	}
2827 
2828 	atomic_set(&dev->tx_cpu, val);
2829 	DHD_ERROR(("%s: tx_cpu = %d\n", __FUNCTION__, atomic_read(&dev->tx_cpu)));
2830 	return count;
2831 }
2832 
2833 static struct dhd_attr dhd_tx_cpu =
2834 __ATTR(tx_cpu, 0660, show_tx_cpu, set_tx_cpu);
2835 
2836 static struct attribute *debug_lb_attrs[] = {
2837 #if defined(DHD_LB_TXP)
2838 	&dhd_attr_lbtxp.attr,
2839 #endif /* DHD_LB_TXP */
2840 #if defined(DHD_LB_RXP)
2841 	&dhd_attr_lbrxp.attr,
2842 	&dhd_attr_lb_rxp_stop_thr.attr,
2843 	&dhd_attr_lb_rxp_strt_thr.attr,
2844 #endif /* DHD_LB_RXP */
2845 	&dhd_candidacy_override.attr,
2846 	&dhd_primary_mask.attr,
2847 	&dhd_secondary_mask.attr,
2848 	&dhd_rx_cpu.attr,
2849 	&dhd_tx_cpu.attr,
2850 	NULL
2851 };
2852 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
2853 
2854 #define to_dhd_lb(k) container_of(k, struct dhd_info, dhd_lb_kobj)
2855 
2856 /*
2857  * wifi/lb kobject show function, the "attr" attribute specifices to which
2858  * node under "sys/wifi/lb" the show function is called.
2859  */
dhd_lb_show(struct kobject * kobj,struct attribute * attr,char * buf)2860 static ssize_t dhd_lb_show(struct kobject *kobj, struct attribute *attr, char *buf)
2861 {
2862 	dhd_info_t *dhd;
2863 	struct dhd_attr *d_attr;
2864 	int ret;
2865 
2866 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2867 	dhd = to_dhd_lb(kobj);
2868 	d_attr = to_attr(attr);
2869 	GCC_DIAGNOSTIC_POP();
2870 
2871 	if (d_attr->show)
2872 		ret = d_attr->show(dhd, buf);
2873 	else
2874 		ret = -EIO;
2875 
2876 	return ret;
2877 }
2878 
2879 /*
2880  * wifi kobject show function, the "attr" attribute specifices to which
2881  * node under "sys/wifi/lb" the store function is called.
2882  */
dhd_lb_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t count)2883 static ssize_t dhd_lb_store(struct kobject *kobj, struct attribute *attr,
2884 		const char *buf, size_t count)
2885 {
2886 	dhd_info_t *dhd;
2887 	struct dhd_attr *d_attr;
2888 	int ret;
2889 
2890 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2891 	dhd = to_dhd_lb(kobj);
2892 	d_attr = to_attr(attr);
2893 	GCC_DIAGNOSTIC_POP();
2894 
2895 	if (d_attr->store)
2896 		ret = d_attr->store(dhd, buf, count);
2897 	else
2898 		ret = -EIO;
2899 
2900 	return ret;
2901 
2902 }
2903 
2904 static struct sysfs_ops dhd_sysfs_lb_ops = {
2905 	.show = dhd_lb_show,
2906 	.store = dhd_lb_store,
2907 };
2908 
2909 static struct kobj_type dhd_lb_ktype = {
2910 	.sysfs_ops = &dhd_sysfs_lb_ops,
2911 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
2912 	.default_attrs = debug_lb_attrs,
2913 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
2914 };
2915 #endif /* DHD_LB */
2916 
2917 /* Create a kobject and attach to sysfs interface */
dhd_sysfs_init(dhd_info_t * dhd)2918 int dhd_sysfs_init(dhd_info_t *dhd)
2919 {
2920 	int ret = -1;
2921 
2922 	if (dhd == NULL) {
2923 		DHD_ERROR(("%s(): dhd is NULL \r\n", __FUNCTION__));
2924 		return ret;
2925 	}
2926 
2927 	/* Initialize the kobject */
2928 	ret = kobject_init_and_add(&dhd->dhd_kobj, &dhd_ktype, NULL, "wifi" BUS_TYPE);
2929 	if (ret) {
2930 		kobject_put(&dhd->dhd_kobj);
2931 		DHD_ERROR(("%s(): Unable to allocate kobject \r\n", __FUNCTION__));
2932 		return ret;
2933 	}
2934 
2935 #ifdef CSI_SUPPORT
2936 	ret = sysfs_create_bin_file(&dhd->dhd_kobj, &dhd_attr_csi);
2937 	if (ret) {
2938 		DHD_ERROR(("%s: can't create %s\n", __FUNCTION__, dhd_attr_csi.attr.name));
2939 		kobject_put(&dhd->dhd_kobj);
2940 		return ret;
2941 	}
2942 #endif /* CSI_SUPPORT */
2943 
2944 	/*
2945 	 * We are always responsible for sending the uevent that the kobject
2946 	 * was added to the system.
2947 	 */
2948 	kobject_uevent(&dhd->dhd_kobj, KOBJ_ADD);
2949 
2950 #ifdef DHD_LB
2951 	ret  = kobject_init_and_add(&dhd->dhd_lb_kobj,
2952 			&dhd_lb_ktype, &dhd->dhd_kobj, "lb");
2953 	if (ret) {
2954 		kobject_put(&dhd->dhd_lb_kobj);
2955 		DHD_ERROR(("%s(): Unable to allocate kobject \r\n", __FUNCTION__));
2956 		return ret;
2957 	}
2958 
2959 	kobject_uevent(&dhd->dhd_lb_kobj, KOBJ_ADD);
2960 #endif /* DHD_LB */
2961 
2962 	return ret;
2963 }
2964 
2965 /* Done with the kobject and detach the sysfs interface */
dhd_sysfs_exit(dhd_info_t * dhd)2966 void dhd_sysfs_exit(dhd_info_t *dhd)
2967 {
2968 	if (dhd == NULL) {
2969 		DHD_ERROR(("%s(): dhd is NULL \r\n", __FUNCTION__));
2970 		return;
2971 	}
2972 
2973 #ifdef DHD_LB
2974 	kobject_put(&dhd->dhd_lb_kobj);
2975 #endif /* DHD_LB */
2976 
2977 	/* Releae the kobject */
2978 	if (dhd->dhd_kobj.state_initialized)
2979 		kobject_put(&dhd->dhd_kobj);
2980 }
2981 
2982 #ifdef DHD_SUPPORT_HDM
2983 static ssize_t
hdm_load_module(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)2984 hdm_load_module(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
2985 {
2986 	int val = bcm_atoi(buf);
2987 
2988 	if (val == 1) {
2989 		DHD_ERROR(("%s : Load module from the hdm %d\n", __FUNCTION__, val));
2990 		dhd_module_init_hdm();
2991 	} else {
2992 		DHD_ERROR(("Module load triggered with invalid value : %d\n", val));
2993 	}
2994 
2995 	return count;
2996 }
2997 
2998 static struct kobj_attribute hdm_wlan_attr =
2999 	__ATTR(hdm_wlan_loader, 0660, NULL, hdm_load_module);
3000 
3001 void
dhd_hdm_wlan_sysfs_init()3002 dhd_hdm_wlan_sysfs_init()
3003 {
3004 	DHD_ERROR(("export hdm_wlan_loader\n"));
3005 	if (sysfs_create_file(kernel_kobj, &hdm_wlan_attr.attr)) {
3006 		DHD_ERROR(("export hdm_load failed\n"));
3007 	}
3008 }
3009 
3010 void
dhd_hdm_wlan_sysfs_deinit(struct work_struct * work)3011 dhd_hdm_wlan_sysfs_deinit(struct work_struct *work)
3012 {
3013 	sysfs_remove_file(kernel_kobj,  &hdm_wlan_attr.attr);
3014 
3015 }
3016 #endif /* DHD_SUPPORT_HDM */
3017