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