xref: /OK3568_Linux_fs/external/rkwifibt/drivers/infineon/dhd_linux_exportfs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Broadcom Dongle Host Driver (DHD), Linux-specific network interface
3  * Basically selected code segments from usb-cdc.c and usb-rndis.c
4  *
5  * Portions of this code are copyright (c) 2021 Cypress Semiconductor Corporation
6  *
7  * Copyright (C) 1999-2017, Broadcom Corporation
8  *
9  *      Unless you and Broadcom execute a separate written software license
10  * agreement governing use of this software, this software is licensed to you
11  * under the terms of the GNU General Public License version 2 (the "GPL"),
12  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
13  * following added to such license:
14  *
15  *      As a special exception, the copyright holders of this software give you
16  * permission to link this software with independent modules, and to copy and
17  * distribute the resulting executable under terms of your choice, provided that
18  * you also meet, for each linked independent module, the terms and conditions of
19  * the license of that module.  An independent module is a module which is not
20  * derived from this software.  The special exception does not apply to any
21  * modifications of the software.
22  *
23  *      Notwithstanding the above, under no circumstances may you combine this
24  * software in any way with any other Broadcom software provided under a license
25  * other than the GPL, without Broadcom's express prior written consent.
26  *
27  *
28  * <<Broadcom-WL-IPTag/Open:>>
29  *
30  * $Id$
31  */
32 #include <linux/kobject.h>
33 #include <linux/proc_fs.h>
34 #include <linux/sysfs.h>
35 #include <osl.h>
36 #include <dhd_dbg.h>
37 #include <dhd_linux_priv.h>
38 #ifdef DHD_ADPS_BAM_EXPORT
39 #include <wl_bam.h>
40 #endif // endif
41 
42 #ifndef BCMDHDX
43 #define SYSFS_DIR_BCMDHD "bcmdhd"
44 #define SYSFS_DIR_WIFI "wifi0"
45 #define PROCFS_DIR_TRACE "dhd_trace"
46 #define PROCFS_DIR_ENCOUNTERS "dhd_ecounters"
47 #define PROCFS_DIR_RTT "dhd_rtt"
48 #else
49 #define SYSFS_DIR_BCMDHD "bcmdhdx"
50 #define SYSFS_DIR_WIFI "wifi1"
51 #define PROCFS_DIR_WIFI "dhdx_trace"
52 #define PROCFS_DIR_ENCOUNTERS "dhdx_ecounters"
53 #define PROCFS_DIR_RTT "dhdx_rtt"
54 #endif /* BCMDHDX */
55 
56 #ifdef SHOW_LOGTRACE
57 extern dhd_pub_t* g_dhd_pub;
58 static int dhd_ring_proc_open(struct inode *inode, struct file *file);
59 ssize_t dhd_ring_proc_read(struct file *file, char *buffer, size_t tt, loff_t *loff);
60 
61 static const struct file_operations dhd_ring_proc_fops = {
62 	.open = dhd_ring_proc_open,
63 	.read = dhd_ring_proc_read,
64 	.release = single_release,
65 };
66 
67 static int
dhd_ring_proc_open(struct inode * inode,struct file * file)68 dhd_ring_proc_open(struct inode *inode, struct file *file)
69 {
70 	int ret = BCME_ERROR;
71 	if (inode) {
72 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
73 		ret = single_open(file, 0, PDE_DATA(inode));
74 #else
75 		/* This feature is not supported for lower kernel versions */
76 		ret = single_open(file, 0, NULL);
77 #endif // endif
78 	} else {
79 		DHD_ERROR(("%s: inode is NULL\n", __FUNCTION__));
80 	}
81 	return ret;
82 }
83 
84 ssize_t
dhd_ring_proc_read(struct file * file,char __user * buffer,size_t tt,loff_t * loff)85 dhd_ring_proc_read(struct file *file, char __user *buffer, size_t tt, loff_t *loff)
86 {
87 	trace_buf_info_t *trace_buf_info;
88 	int ret = BCME_ERROR;
89 	dhd_dbg_ring_t *ring = (dhd_dbg_ring_t *)((struct seq_file *)(file->private_data))->private;
90 
91 	if (ring == NULL) {
92 		DHD_ERROR(("%s: ring is NULL\n", __FUNCTION__));
93 		return ret;
94 	}
95 
96 	ASSERT(g_dhd_pub);
97 
98 	trace_buf_info = (trace_buf_info_t *)MALLOCZ(g_dhd_pub->osh, sizeof(trace_buf_info_t));
99 	if (trace_buf_info) {
100 		dhd_dbg_read_ring_into_trace_buf(ring, trace_buf_info);
101 		if (copy_to_user(buffer, (void*)trace_buf_info->buf, MIN(trace_buf_info->size, tt)))
102 		{
103 			ret = -EFAULT;
104 			goto exit;
105 		}
106 		if (trace_buf_info->availability == BUF_NOT_AVAILABLE)
107 			ret = BUF_NOT_AVAILABLE;
108 		else
109 			ret = trace_buf_info->size;
110 	} else
111 		DHD_ERROR(("Memory allocation Failed\n"));
112 
113 exit:
114 	if (trace_buf_info) {
115 		MFREE(g_dhd_pub->osh, trace_buf_info, sizeof(trace_buf_info_t));
116 	}
117 	return ret;
118 }
119 
120 void
dhd_dbg_ring_proc_create(dhd_pub_t * dhdp)121 dhd_dbg_ring_proc_create(dhd_pub_t *dhdp)
122 {
123 #ifdef DEBUGABILITY
124 	dhd_dbg_ring_t *dbg_verbose_ring = NULL;
125 
126 	dbg_verbose_ring = dhd_dbg_get_ring_from_ring_id(dhdp, FW_VERBOSE_RING_ID);
127 	if (dbg_verbose_ring) {
128 		if (!proc_create_data(PROCFS_DIR_TRACE, S_IRUSR, NULL, &dhd_ring_proc_fops,
129 			dbg_verbose_ring)) {
130 			DHD_ERROR(("Failed to create /proc/dhd_trace procfs interface\n"));
131 		} else {
132 			DHD_ERROR(("Created /proc/dhd_trace procfs interface\n"));
133 		}
134 	} else {
135 		DHD_ERROR(("dbg_verbose_ring is NULL, /proc/dhd_trace not created\n"));
136 	}
137 #endif /* DEBUGABILITY */
138 
139 #ifdef EWP_ECNTRS_LOGGING
140 	if (!proc_create_data(PROCFS_DIR_ENCOUNTERS, S_IRUSR, NULL, &dhd_ring_proc_fops,
141 		dhdp->ecntr_dbg_ring)) {
142 		DHD_ERROR(("Failed to create /proc/dhd_ecounters procfs interface\n"));
143 	} else {
144 		DHD_ERROR(("Created /proc/dhd_ecounters procfs interface\n"));
145 	}
146 #endif /* EWP_ECNTRS_LOGGING */
147 
148 #ifdef EWP_RTT_LOGGING
149 	if (!proc_create_data(PROCFS_DIR_RTT, S_IRUSR, NULL, &dhd_ring_proc_fops,
150 		dhdp->rtt_dbg_ring)) {
151 		DHD_ERROR(("Failed to create /proc/dhd_rtt procfs interface\n"));
152 	} else {
153 		DHD_ERROR(("Created /proc/dhd_rtt procfs interface\n"));
154 	}
155 #endif /* EWP_RTT_LOGGING */
156 }
157 
158 void
dhd_dbg_ring_proc_destroy(dhd_pub_t * dhdp)159 dhd_dbg_ring_proc_destroy(dhd_pub_t *dhdp)
160 {
161 #ifdef DEBUGABILITY
162 	remove_proc_entry(PROCFS_DIR_TRACE, NULL);
163 #endif /* DEBUGABILITY */
164 
165 #ifdef EWP_ECNTRS_LOGGING
166 	remove_proc_entry(PROCFS_DIR_ENCOUNTERS, NULL);
167 #endif /* EWP_ECNTRS_LOGGING */
168 
169 #ifdef EWP_RTT_LOGGING
170 	remove_proc_entry(PROCFS_DIR_RTT, NULL);
171 #endif /* EWP_RTT_LOGGING */
172 
173 }
174 #endif /* SHOW_LOGTRACE */
175 
176 /* ----------------------------------------------------------------------------
177  * Infrastructure code for sysfs interface support for DHD
178  *
179  * What is sysfs interface?
180  * https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt
181  *
182  * Why sysfs interface?
183  * This is the Linux standard way of changing/configuring Run Time parameters
184  * for a driver. We can use this interface to control "linux" specific driver
185  * parameters.
186  *
187  * -----------------------------------------------------------------------------
188  */
189 
190 #if defined(DHD_TRACE_WAKE_LOCK)
191 extern atomic_t trace_wklock_onoff;
192 
193 /* Function to show the history buffer */
194 static ssize_t
show_wklock_trace(struct dhd_info * dev,char * buf)195 show_wklock_trace(struct dhd_info *dev, char *buf)
196 {
197 	ssize_t ret = 0;
198 	dhd_info_t *dhd = (dhd_info_t *)dev;
199 
200 	buf[ret] = '\n';
201 	buf[ret+1] = 0;
202 
203 	dhd_wk_lock_stats_dump(&dhd->pub);
204 	return ret+1;
205 }
206 
207 /* Function to enable/disable wakelock trace */
208 static ssize_t
wklock_trace_onoff(struct dhd_info * dev,const char * buf,size_t count)209 wklock_trace_onoff(struct dhd_info *dev, const char *buf, size_t count)
210 {
211 	unsigned long onoff;
212 	dhd_info_t *dhd = (dhd_info_t *)dev;
213 	BCM_REFERENCE(dhd);
214 
215 	onoff = bcm_strtoul(buf, NULL, 10);
216 	if (onoff != 0 && onoff != 1) {
217 		return -EINVAL;
218 	}
219 
220 	atomic_set(&trace_wklock_onoff, onoff);
221 	if (atomic_read(&trace_wklock_onoff)) {
222 		printk("ENABLE WAKLOCK TRACE\n");
223 	} else {
224 		printk("DISABLE WAKELOCK TRACE\n");
225 	}
226 
227 	return (ssize_t)(onoff+1);
228 }
229 #endif /* DHD_TRACE_WAKE_LOCK */
230 
231 #if defined(DHD_LB_TXP)
232 static ssize_t
show_lbtxp(struct dhd_info * dev,char * buf)233 show_lbtxp(struct dhd_info *dev, char *buf)
234 {
235 	ssize_t ret = 0;
236 	unsigned long onoff;
237 	dhd_info_t *dhd = (dhd_info_t *)dev;
238 
239 	onoff = atomic_read(&dhd->lb_txp_active);
240 	ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n",
241 		onoff);
242 	return ret;
243 }
244 
245 static ssize_t
lbtxp_onoff(struct dhd_info * dev,const char * buf,size_t count)246 lbtxp_onoff(struct dhd_info *dev, const char *buf, size_t count)
247 {
248 	unsigned long onoff;
249 	dhd_info_t *dhd = (dhd_info_t *)dev;
250 	int i;
251 
252 	onoff = bcm_strtoul(buf, NULL, 10);
253 
254 	sscanf(buf, "%lu", &onoff);
255 	if (onoff != 0 && onoff != 1) {
256 		return -EINVAL;
257 	}
258 	atomic_set(&dhd->lb_txp_active, onoff);
259 
260 	/* Since the scheme is changed clear the counters */
261 	for (i = 0; i < NR_CPUS; i++) {
262 		DHD_LB_STATS_CLR(dhd->txp_percpu_run_cnt[i]);
263 		DHD_LB_STATS_CLR(dhd->tx_start_percpu_run_cnt[i]);
264 	}
265 
266 	return count;
267 }
268 
269 #endif /* DHD_LB_TXP */
270 
271 #if defined(DHD_LB_RXP)
272 static ssize_t
show_lbrxp(struct dhd_info * dev,char * buf)273 show_lbrxp(struct dhd_info *dev, char *buf)
274 {
275 	ssize_t ret = 0;
276 	unsigned long onoff;
277 	dhd_info_t *dhd = (dhd_info_t *)dev;
278 
279 	onoff = atomic_read(&dhd->lb_rxp_active);
280 	ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n",
281 		onoff);
282 	return ret;
283 }
284 
285 static ssize_t
lbrxp_onoff(struct dhd_info * dev,const char * buf,size_t count)286 lbrxp_onoff(struct dhd_info *dev, const char *buf, size_t count)
287 {
288 	unsigned long onoff;
289 	dhd_info_t *dhd = (dhd_info_t *)dev;
290 	int i, j;
291 
292 	onoff = bcm_strtoul(buf, NULL, 10);
293 
294 	sscanf(buf, "%lu", &onoff);
295 	if (onoff != 0 && onoff != 1) {
296 		return -EINVAL;
297 	}
298 	atomic_set(&dhd->lb_rxp_active, onoff);
299 
300 	/* Since the scheme is changed clear the counters */
301 	for (i = 0; i < NR_CPUS; i++) {
302 		DHD_LB_STATS_CLR(dhd->napi_percpu_run_cnt[i]);
303 		for (j = 0; j < HIST_BIN_SIZE; j++) {
304 			DHD_LB_STATS_CLR(dhd->napi_rx_hist[j][i]);
305 		}
306 	}
307 
308 	return count;
309 }
310 #endif /* DHD_LB_RXP */
311 
312 #ifdef DHD_LOG_DUMP
313 extern int logdump_periodic_flush;
314 extern int logdump_ecntr_enable;
315 static ssize_t
show_logdump_periodic_flush(struct dhd_info * dev,char * buf)316 show_logdump_periodic_flush(struct dhd_info *dev, char *buf)
317 {
318 	ssize_t ret = 0;
319 	unsigned long val;
320 
321 	val = logdump_periodic_flush;
322 	ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n", val);
323 	return ret;
324 }
325 
326 static ssize_t
logdump_periodic_flush_onoff(struct dhd_info * dev,const char * buf,size_t count)327 logdump_periodic_flush_onoff(struct dhd_info *dev, const char *buf, size_t count)
328 {
329 	unsigned long val;
330 
331 	val = bcm_strtoul(buf, NULL, 10);
332 
333 	sscanf(buf, "%lu", &val);
334 	if (val != 0 && val != 1) {
335 		 return -EINVAL;
336 	}
337 	logdump_periodic_flush = val;
338 	return count;
339 }
340 
341 static ssize_t
show_logdump_ecntr(struct dhd_info * dev,char * buf)342 show_logdump_ecntr(struct dhd_info *dev, char *buf)
343 {
344 	ssize_t ret = 0;
345 	unsigned long val;
346 
347 	val = logdump_ecntr_enable;
348 	ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n", val);
349 	return ret;
350 }
351 
352 static ssize_t
logdump_ecntr_onoff(struct dhd_info * dev,const char * buf,size_t count)353 logdump_ecntr_onoff(struct dhd_info *dev, const char *buf, size_t count)
354 {
355 	unsigned long val;
356 
357 	val = bcm_strtoul(buf, NULL, 10);
358 
359 	sscanf(buf, "%lu", &val);
360 	if (val != 0 && val != 1) {
361 		 return -EINVAL;
362 	}
363 	logdump_ecntr_enable = val;
364 	return count;
365 }
366 
367 #endif /* DHD_LOG_DUMP */
368 
369 extern uint enable_ecounter;
370 static ssize_t
show_enable_ecounter(struct dhd_info * dev,char * buf)371 show_enable_ecounter(struct dhd_info *dev, char *buf)
372 {
373 	ssize_t ret = 0;
374 	unsigned long onoff;
375 
376 	onoff = enable_ecounter;
377 	ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n",
378 		onoff);
379 	return ret;
380 }
381 
382 static ssize_t
ecounter_onoff(struct dhd_info * dev,const char * buf,size_t count)383 ecounter_onoff(struct dhd_info *dev, const char *buf, size_t count)
384 {
385 	unsigned long onoff;
386 	dhd_info_t *dhd = (dhd_info_t *)dev;
387 	dhd_pub_t *dhdp;
388 
389 	if (!dhd) {
390 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
391 		return count;
392 	}
393 	dhdp = &dhd->pub;
394 	if (!FW_SUPPORTED(dhdp, ecounters)) {
395 		DHD_ERROR(("%s: ecounters not supported by FW\n", __FUNCTION__));
396 		return count;
397 	}
398 
399 	onoff = bcm_strtoul(buf, NULL, 10);
400 
401 	sscanf(buf, "%lu", &onoff);
402 	if (onoff != 0 && onoff != 1) {
403 		return -EINVAL;
404 	}
405 
406 	if (enable_ecounter == onoff) {
407 		DHD_ERROR(("%s: ecounters already %d\n", __FUNCTION__, enable_ecounter));
408 		return count;
409 	}
410 
411 	enable_ecounter = onoff;
412 	dhd_ecounter_configure(dhdp, enable_ecounter);
413 
414 	return count;
415 }
416 
417 /*
418  * Generic Attribute Structure for DHD.
419  * If we have to add a new sysfs entry under /sys/bcm-dhd/, we have
420  * to instantiate an object of type dhd_attr,  populate it with
421  * the required show/store functions (ex:- dhd_attr_cpumask_primary)
422  * and add the object to default_attrs[] array, that gets registered
423  * to the kobject of dhd (named bcm-dhd).
424  */
425 
426 struct dhd_attr {
427 	struct attribute attr;
428 	ssize_t(*show)(struct dhd_info *, char *);
429 	ssize_t(*store)(struct dhd_info *, const char *, size_t count);
430 };
431 
432 #if defined(DHD_TRACE_WAKE_LOCK)
433 static struct dhd_attr dhd_attr_wklock =
434 	__ATTR(wklock_trace, 0660, show_wklock_trace, wklock_trace_onoff);
435 #endif /* defined(DHD_TRACE_WAKE_LOCK */
436 
437 #if defined(DHD_LB_TXP)
438 static struct dhd_attr dhd_attr_lbtxp =
439 	__ATTR(lbtxp, 0660, show_lbtxp, lbtxp_onoff);
440 #endif /* DHD_LB_TXP */
441 
442 #if defined(DHD_LB_RXP)
443 static struct dhd_attr dhd_attr_lbrxp =
444 	__ATTR(lbrxp, 0660, show_lbrxp, lbrxp_onoff);
445 #endif /* DHD_LB_RXP */
446 
447 #ifdef DHD_LOG_DUMP
448 static struct dhd_attr dhd_attr_logdump_periodic_flush =
449      __ATTR(logdump_periodic_flush, 0660, show_logdump_periodic_flush,
450 		logdump_periodic_flush_onoff);
451 static struct dhd_attr dhd_attr_logdump_ecntr =
452 	__ATTR(logdump_ecntr_enable, 0660, show_logdump_ecntr,
453 		logdump_ecntr_onoff);
454 #endif /* DHD_LOG_DUMP */
455 
456 static struct dhd_attr dhd_attr_ecounters =
457 	__ATTR(ecounters, 0660, show_enable_ecounter, ecounter_onoff);
458 
459 /* Attribute object that gets registered with "bcm-dhd" kobject tree */
460 static struct attribute *default_attrs[] = {
461 #if defined(DHD_TRACE_WAKE_LOCK)
462 	&dhd_attr_wklock.attr,
463 #endif // endif
464 #if defined(DHD_LB_TXP)
465 	&dhd_attr_lbtxp.attr,
466 #endif /* DHD_LB_TXP */
467 #if defined(DHD_LB_RXP)
468 	&dhd_attr_lbrxp.attr,
469 #endif /* DHD_LB_RXP */
470 #ifdef DHD_LOG_DUMP
471 	&dhd_attr_logdump_periodic_flush.attr,
472 	&dhd_attr_logdump_ecntr.attr,
473 #endif // endif
474 	&dhd_attr_ecounters.attr,
475 	NULL
476 };
477 
478 #define to_dhd(k) container_of(k, struct dhd_info, dhd_kobj)
479 #define to_attr(a) container_of(a, struct dhd_attr, attr)
480 
481 /*
482  * bcm-dhd kobject show function, the "attr" attribute specifices to which
483  * node under "bcm-dhd" the show function is called.
484  */
dhd_show(struct kobject * kobj,struct attribute * attr,char * buf)485 static ssize_t dhd_show(struct kobject *kobj, struct attribute *attr, char *buf)
486 {
487 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
488 #pragma GCC diagnostic push
489 #pragma GCC diagnostic ignored "-Wcast-qual"
490 #endif // endif
491 	dhd_info_t *dhd = to_dhd(kobj);
492 	struct dhd_attr *d_attr = to_attr(attr);
493 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
494 #pragma GCC diagnostic pop
495 #endif // endif
496 	int ret;
497 
498 	if (d_attr->show)
499 		ret = d_attr->show(dhd, buf);
500 	else
501 		ret = -EIO;
502 
503 	return ret;
504 }
505 
506 /*
507  * bcm-dhd kobject show function, the "attr" attribute specifices to which
508  * node under "bcm-dhd" the store function is called.
509  */
dhd_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t count)510 static ssize_t dhd_store(struct kobject *kobj, struct attribute *attr,
511 	const char *buf, size_t count)
512 {
513 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
514 #pragma GCC diagnostic push
515 #pragma GCC diagnostic ignored "-Wcast-qual"
516 #endif // endif
517 	dhd_info_t *dhd = to_dhd(kobj);
518 	struct dhd_attr *d_attr = to_attr(attr);
519 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
520 #pragma GCC diagnostic pop
521 #endif // endif
522 	int ret;
523 
524 	if (d_attr->store)
525 		ret = d_attr->store(dhd, buf, count);
526 	else
527 		ret = -EIO;
528 
529 	return ret;
530 
531 }
532 
533 static struct sysfs_ops dhd_sysfs_ops = {
534 	.show = dhd_show,
535 	.store = dhd_store,
536 };
537 
538 static struct kobj_type dhd_ktype = {
539 	.sysfs_ops = &dhd_sysfs_ops,
540 	.default_attrs = default_attrs,
541 };
542 
543 #ifdef DHD_MAC_ADDR_EXPORT
544 struct ether_addr sysfs_mac_addr;
545 static ssize_t
show_mac_addr(struct dhd_info * dev,char * buf)546 show_mac_addr(struct dhd_info *dev, char *buf)
547 {
548 	ssize_t ret = 0;
549 
550 	ret = scnprintf(buf, PAGE_SIZE - 1, MACF,
551 		(uint32)sysfs_mac_addr.octet[0], (uint32)sysfs_mac_addr.octet[1],
552 		(uint32)sysfs_mac_addr.octet[2], (uint32)sysfs_mac_addr.octet[3],
553 		(uint32)sysfs_mac_addr.octet[4], (uint32)sysfs_mac_addr.octet[5]);
554 
555 	return ret;
556 }
557 
558 static ssize_t
set_mac_addr(struct dhd_info * dev,const char * buf,size_t count)559 set_mac_addr(struct dhd_info *dev, const char *buf, size_t count)
560 {
561 	if (!bcm_ether_atoe(buf, &sysfs_mac_addr)) {
562 		DHD_ERROR(("Invalid Mac Address \n"));
563 		return -EINVAL;
564 	}
565 
566 	DHD_ERROR(("Mac Address set with "MACDBG"\n", MAC2STRDBG(&sysfs_mac_addr)));
567 
568 	return count;
569 }
570 
571 static struct dhd_attr dhd_attr_cntl_macaddr =
572 	__ATTR(mac_addr, 0660, show_mac_addr, set_mac_addr);
573 #endif /* DHD_MAC_ADDR_EXPORT */
574 
575 #ifdef DHD_FW_COREDUMP
576 
577 #ifdef CUSTOMER_HW4_DEBUG
578 #define MEMDUMPINFO PLATFORM_PATH".memdump.info"
579 #elif defined(CUSTOMER_HW2) || defined(BOARD_HIKEY)
580 #define MEMDUMPINFO "/data/misc/wifi/.memdump.info"
581 #elif defined(OEM_ANDROID) && defined(CONFIG_DHD_PLAT_ROCKCHIP)
582 #define MEMDUMPINFO	"/data/misc/wifi/.memdump.info"
583 #elif defined(OEM_ANDROID) && (defined(BOARD_PANDA) || defined(__ARM_ARCH_7A__))
584 #define MEMDUMPINFO "/data/misc/wifi/.memdump.info"
585 #elif defined(OEM_ANDROID) && defined(DHD_FW_COREDUMP)
586 #define MEMDUMPINFO_LIVE "/installmedia/.memdump.info"
587 #define MEMDUMPINFO_INST "/data/.memdump.info"
588 #define MEMDUMPINFO MEMDUMPINFO_LIVE
589 #else /* FC19 and Others */
590 #define MEMDUMPINFO "/root/.memdump.info"
591 #endif /* CUSTOMER_HW4_DEBUG */
592 
593 uint32
get_mem_val_from_file(void)594 get_mem_val_from_file(void)
595 {
596 	struct file *fp = NULL;
597 	uint32 mem_val = DUMP_MEMFILE_MAX;
598 	char *p_mem_val = NULL;
599 	char *filepath = MEMDUMPINFO;
600 	int ret = 0;
601 
602 	/* Read memdump info from the file */
603 	fp = filp_open(filepath, O_RDONLY, 0);
604 	if (IS_ERR(fp)) {
605 		DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
606 #if defined(CONFIG_X86) && defined(OEM_ANDROID) && defined(DHD_FW_COREDUMP)
607 		/* Check if it is Live Brix Image */
608 		if (strcmp(filepath, MEMDUMPINFO_LIVE) != 0) {
609 			goto done;
610 		}
611 		/* Try if it is Installed Brix Image */
612 		filepath = MEMDUMPINFO_INST;
613 		DHD_ERROR(("%s: Try File [%s]\n", __FUNCTION__, filepath));
614 		fp = filp_open(filepath, O_RDONLY, 0);
615 		if (IS_ERR(fp)) {
616 			DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
617 			goto done;
618 		}
619 #else /* Non Brix Android platform */
620 		goto done;
621 #endif /* CONFIG_X86 && OEM_ANDROID */
622 	}
623 
624 	/* Handle success case */
625 	ret = compat_kernel_read(fp, 0, (char *)&mem_val, sizeof(uint32));
626 	if (ret < 0) {
627 		DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret));
628 		filp_close(fp, NULL);
629 		goto done;
630 	}
631 
632 	p_mem_val = (char*)&mem_val;
633 	p_mem_val[sizeof(uint32) - 1] = '\0';
634 	mem_val = bcm_atoi(p_mem_val);
635 
636 	filp_close(fp, NULL);
637 
638 done:
639 	return mem_val;
640 }
641 
dhd_get_memdump_info(dhd_pub_t * dhd)642 void dhd_get_memdump_info(dhd_pub_t *dhd)
643 {
644 #ifndef DHD_EXPORT_CNTL_FILE
645 	uint32 mem_val = DUMP_MEMFILE_MAX;
646 
647 	mem_val = get_mem_val_from_file();
648 	if (mem_val != DUMP_MEMFILE_MAX)
649 		dhd->memdump_enabled = mem_val;
650 #ifdef DHD_INIT_DEFAULT_MEMDUMP
651 	if (mem_val == 0 || mem_val == DUMP_MEMFILE_MAX)
652 		mem_val = DUMP_MEMFILE_BUGON;
653 #endif /* DHD_INIT_DEFAULT_MEMDUMP */
654 #else
655 #ifdef DHD_INIT_DEFAULT_MEMDUMP
656 	if (dhd->memdump_enabled == 0 || dhd->memdump_enabled == DUMP_MEMFILE_MAX)
657 		dhd->memdump_enabled = DUMP_MEMFILE_BUGON;
658 #endif /* DHD_INIT_DEFAULT_MEMDUMP */
659 #endif /* !DHD_EXPORT_CNTL_FILE */
660 #ifdef BCMQT
661 	/* In QT environment collecting memdump on FW TRAP, IOVAR timeouts,
662 	 * is taking more time and makes system unresponsive so disabling it.
663 	 * if needed memdump can be collected through 'dhd upload' command.
664 	*/
665 	dhd->memdump_enabled = DUMP_DISABLED;
666 #endif // endif
667 	DHD_ERROR(("%s: MEMDUMP ENABLED = %d\n", __FUNCTION__, dhd->memdump_enabled));
668 }
669 
670 #ifdef DHD_EXPORT_CNTL_FILE
671 static ssize_t
show_memdump_info(struct dhd_info * dev,char * buf)672 show_memdump_info(struct dhd_info *dev, char *buf)
673 {
674 	ssize_t ret = 0;
675 	dhd_pub_t *dhdp;
676 
677 	if (!dev) {
678 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
679 		return ret;
680 	}
681 
682 	dhdp = &dev->pub;
683 	ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", dhdp->memdump_enabled);
684 	return ret;
685 }
686 
687 static ssize_t
set_memdump_info(struct dhd_info * dev,const char * buf,size_t count)688 set_memdump_info(struct dhd_info *dev, const char *buf, size_t count)
689 {
690 	unsigned long memval;
691 	dhd_pub_t *dhdp;
692 
693 	if (!dev) {
694 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
695 		return count;
696 	}
697 	dhdp = &dev->pub;
698 
699 	memval = bcm_strtoul(buf, NULL, 10);
700 	sscanf(buf, "%lu", &memval);
701 
702 	dhdp->memdump_enabled = (uint32)memval;
703 
704 	DHD_ERROR(("%s: MEMDUMP ENABLED = %iu\n", __FUNCTION__, dhdp->memdump_enabled));
705 	return count;
706 }
707 
708 static struct dhd_attr dhd_attr_cntl_memdump =
709 	__ATTR(memdump, 0660, show_memdump_info, set_memdump_info);
710 #endif /* DHD_EXPORT_CNTL_FILE */
711 #endif /* DHD_FW_COREDUMP */
712 
713 #ifdef BCMASSERT_LOG
714 #ifdef CUSTOMER_HW4_DEBUG
715 #define ASSERTINFO PLATFORM_PATH".assert.info"
716 #elif defined(CUSTOMER_HW2) || defined(BOARD_HIKEY)
717 #define ASSERTINFO "/data/misc/wifi/.assert.info"
718 #elif defined(OEM_ANDROID) && defined(CONFIG_DHD_PLAT_ROCKCHIP)
719 #define ASSERTINFO "/data/misc/wifi/.assert.info"
720 #elif defined(OEM_ANDROID)
721 #define ASSERTINFO "/installmedia/.assert.info"
722 #else
723 #define ASSERTINFO "/root/.assert.info"
724 #endif /* CUSTOMER_HW4_DEBUG */
725 int
get_assert_val_from_file(void)726 get_assert_val_from_file(void)
727 {
728 	struct file *fp = NULL;
729 	char *filepath = ASSERTINFO;
730 	char *p_mem_val = NULL;
731 	int mem_val = -1;
732 
733 	/*
734 	 * Read assert info from the file
735 	 * 0: Trigger Kernel crash by panic()
736 	 * 1: Print out the logs and don't trigger Kernel panic. (default)
737 	 * 2: Trigger Kernel crash by BUG()
738 	 * File doesn't exist: Keep default value (1).
739 	 */
740 	fp = filp_open(filepath, O_RDONLY, 0);
741 	if (IS_ERR(fp)) {
742 		DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
743 	} else {
744 		int ret = compat_kernel_read(fp, 0, (char *)&mem_val, sizeof(uint32));
745 		if (ret < 0) {
746 			DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret));
747 		} else {
748 			p_mem_val = (char *)&mem_val;
749 			p_mem_val[sizeof(uint32) - 1] = '\0';
750 			mem_val = bcm_atoi(p_mem_val);
751 			DHD_ERROR(("%s: ASSERT ENABLED = %d\n", __FUNCTION__, mem_val));
752 		}
753 		filp_close(fp, NULL);
754 	}
755 
756 #ifdef CUSTOMER_HW4_DEBUG
757 	mem_val = (mem_val >= 0) ? mem_val : 1;
758 #else
759 	mem_val = (mem_val >= 0) ? mem_val : 0;
760 #endif /* CUSTOMER_HW4_DEBUG */
761 	return mem_val;
762 }
763 
dhd_get_assert_info(dhd_pub_t * dhd)764 void dhd_get_assert_info(dhd_pub_t *dhd)
765 {
766 #ifndef DHD_EXPORT_CNTL_FILE
767 	int mem_val = -1;
768 
769 	mem_val = get_assert_val_from_file();
770 
771 	g_assert_type = mem_val;
772 #endif /* !DHD_EXPORT_CNTL_FILE */
773 }
774 
775 #ifdef DHD_EXPORT_CNTL_FILE
776 static ssize_t
show_assert_info(struct dhd_info * dev,char * buf)777 show_assert_info(struct dhd_info *dev, char *buf)
778 {
779 	ssize_t ret = 0;
780 
781 	if (!dev) {
782 		DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__));
783 		return ret;
784 	}
785 
786 	ret = scnprintf(buf, PAGE_SIZE -1, "%d\n", g_assert_type);
787 	return ret;
788 
789 }
790 
791 static ssize_t
set_assert_info(struct dhd_info * dev,const char * buf,size_t count)792 set_assert_info(struct dhd_info *dev, const char *buf, size_t count)
793 {
794 	unsigned long assert_val;
795 
796 	assert_val = bcm_strtoul(buf, NULL, 10);
797 	sscanf(buf, "%lu", &assert_val);
798 
799 	g_assert_type = (uint32)assert_val;
800 
801 	DHD_ERROR(("%s: ASSERT ENABLED = %lu\n", __FUNCTION__, assert_val));
802 	return count;
803 
804 }
805 
806 static struct dhd_attr dhd_attr_cntl_assert =
807 	__ATTR(assert, 0660, show_assert_info, set_assert_info);
808 #endif /* DHD_EXPORT_CNTL_FILE */
809 #endif /* BCMASSERT_LOG */
810 
811 #ifdef DHD_EXPORT_CNTL_FILE
812 #if defined(WRITE_WLANINFO)
813 static ssize_t
show_wifiver_info(struct dhd_info * dev,char * buf)814 show_wifiver_info(struct dhd_info *dev, char *buf)
815 {
816 	ssize_t ret = 0;
817 
818 	ret = scnprintf(buf, PAGE_SIZE -1, "%s", version_info);
819 	return ret;
820 }
821 
822 static ssize_t
set_wifiver_info(struct dhd_info * dev,const char * buf,size_t count)823 set_wifiver_info(struct dhd_info *dev, const char *buf, size_t count)
824 {
825 	DHD_ERROR(("Do not set version info\n"));
826 	return -EINVAL;
827 }
828 
829 static struct dhd_attr dhd_attr_cntl_wifiver =
830 	__ATTR(wifiver, 0660, show_wifiver_info, set_wifiver_info);
831 #endif /* WRITE_WLANINFO */
832 
833 #if defined(USE_CID_CHECK)
834 char cidinfostr[MAX_VNAME_LEN];
835 
836 static ssize_t
show_cid_info(struct dhd_info * dev,char * buf)837 show_cid_info(struct dhd_info *dev, char *buf)
838 {
839 	ssize_t ret = 0;
840 
841 	ret = scnprintf(buf, PAGE_SIZE -1, "%s", cidinfostr);
842 	return ret;
843 }
844 
845 static ssize_t
set_cid_info(struct dhd_info * dev,const char * buf,size_t count)846 set_cid_info(struct dhd_info *dev, const char *buf, size_t count)
847 {
848 	int len = strlen(buf) + 1;
849 	int maxstrsz;
850 	maxstrsz = MAX_VNAME_LEN;
851 
852 	scnprintf(cidinfostr, ((len > maxstrsz) ? maxstrsz : len), "%s", buf);
853 	DHD_INFO(("%s : CID info string\n", cidinfostr));
854 	return count;
855 }
856 
857 static struct dhd_attr dhd_attr_cntl_cidinfo =
858 	__ATTR(cid, 0660, show_cid_info, set_cid_info);
859 #endif /* USE_CID_CHECK */
860 
861 #if defined(GEN_SOFTAP_INFO_FILE)
862 char softapinfostr[SOFTAP_INFO_BUF_SZ];
863 static ssize_t
show_softap_info(struct dhd_info * dev,char * buf)864 show_softap_info(struct dhd_info *dev, char *buf)
865 {
866 	ssize_t ret = 0;
867 
868 	ret = scnprintf(buf, PAGE_SIZE -1, "%s", softapinfostr);
869 	return ret;
870 }
871 
872 static ssize_t
set_softap_info(struct dhd_info * dev,const char * buf,size_t count)873 set_softap_info(struct dhd_info *dev, const char *buf, size_t count)
874 {
875 	DHD_ERROR(("Do not set sofap related info\n"));
876 	return -EINVAL;
877 }
878 
879 static struct dhd_attr dhd_attr_cntl_softapinfo =
880 	__ATTR(softap, 0660, show_softap_info, set_softap_info);
881 #endif /* GEN_SOFTAP_INFO_FILE */
882 
883 #if defined(MIMO_ANT_SETTING)
884 unsigned long antsel;
885 
886 static ssize_t
show_ant_info(struct dhd_info * dev,char * buf)887 show_ant_info(struct dhd_info *dev, char *buf)
888 {
889 	ssize_t ret = 0;
890 
891 	ret = scnprintf(buf, PAGE_SIZE -1, "%lu\n", antsel);
892 	return ret;
893 }
894 
895 static ssize_t
set_ant_info(struct dhd_info * dev,const char * buf,size_t count)896 set_ant_info(struct dhd_info *dev, const char *buf, size_t count)
897 {
898 	unsigned long ant_val;
899 
900 	ant_val = bcm_strtoul(buf, NULL, 10);
901 	sscanf(buf, "%lu", &ant_val);
902 
903 	/*
904 	 * Check value
905 	 * 0 - Not set, handle same as file not exist
906 	 */
907 	if (ant_val > 3) {
908 		DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %lu \n",
909 			__FUNCTION__, ant_val));
910 		return -EINVAL;
911 	}
912 
913 	antsel = ant_val;
914 	DHD_ERROR(("[WIFI_SEC] %s: Set Antinfo val = %lu \n", __FUNCTION__, antsel));
915 	return count;
916 }
917 
918 static struct dhd_attr dhd_attr_cntl_antinfo =
919 	__ATTR(ant, 0660, show_ant_info, set_ant_info);
920 #endif /* MIMO_ANT_SETTING */
921 
922 #ifdef DHD_PM_CONTROL_FROM_FILE
923 extern bool g_pm_control;
924 extern uint32 pmmode_val;
925 static ssize_t
show_pm_info(struct dhd_info * dev,char * buf)926 show_pm_info(struct dhd_info *dev, char *buf)
927 {
928 	ssize_t ret = 0;
929 
930 	if (!g_pm_control) {
931 		ret = scnprintf(buf, PAGE_SIZE -1, "PM mode is not set\n");
932 	} else {
933 		ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", pmmode_val);
934 	}
935 	return ret;
936 }
937 
938 static ssize_t
set_pm_info(struct dhd_info * dev,const char * buf,size_t count)939 set_pm_info(struct dhd_info *dev, const char *buf, size_t count)
940 {
941 	unsigned long pm_val;
942 
943 	pm_val = bcm_strtoul(buf, NULL, 10);
944 	sscanf(buf, "%lu", &pm_val);
945 
946 	if (pm_val > 2) {
947 		DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %lu \n",
948 			__FUNCTION__, pm_val));
949 		return -EINVAL;
950 	}
951 
952 	if (!pm_val) {
953 		g_pm_control = TRUE;
954 	} else {
955 		g_pm_control = FALSE;
956 	}
957 
958 	pmmode_val = (uint32)pm_val;
959 	DHD_ERROR(("[WIFI_SEC] %s: Set pminfo val = %u\n", __FUNCTION__, pmmode_val));
960 	return count;
961 }
962 
963 static struct dhd_attr dhd_attr_cntl_pminfo =
964 	__ATTR(pm, 0660, show_pm_info, set_pm_info);
965 #endif /* DHD_PM_CONTROL_FROM_FILE */
966 
967 #ifdef LOGTRACE_FROM_FILE
968 unsigned long logtrace_val = 1;
969 
970 static ssize_t
show_logtrace_info(struct dhd_info * dev,char * buf)971 show_logtrace_info(struct dhd_info *dev, char *buf)
972 {
973 	ssize_t ret = 0;
974 
975 	ret = scnprintf(buf, PAGE_SIZE -1, "%lu\n", logtrace_val);
976 	return ret;
977 }
978 
979 static ssize_t
set_logtrace_info(struct dhd_info * dev,const char * buf,size_t count)980 set_logtrace_info(struct dhd_info *dev, const char *buf, size_t count)
981 {
982 	unsigned long onoff;
983 
984 	onoff = bcm_strtoul(buf, NULL, 10);
985 	sscanf(buf, "%lu", &onoff);
986 
987 	if (onoff > 2) {
988 		DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %lu \n",
989 			__FUNCTION__, onoff));
990 		return -EINVAL;
991 	}
992 
993 	logtrace_val = onoff;
994 	DHD_ERROR(("[WIFI_SEC] %s: LOGTRACE On/Off from sysfs = %lu\n",
995 		__FUNCTION__, logtrace_val));
996 	return count;
997 }
998 
999 static struct dhd_attr dhd_attr_cntl_logtraceinfo =
1000 	__ATTR(logtrace, 0660, show_logtrace_info, set_logtrace_info);
1001 #endif /* LOGTRACE_FROM_FILE */
1002 
1003 #ifdef  USE_WFA_CERT_CONF
1004 #ifdef BCMSDIO
1005 uint32 bus_txglom = VALUENOTSET;
1006 
1007 static ssize_t
show_bustxglom(struct dhd_info * dev,char * buf)1008 show_bustxglom(struct dhd_info *dev, char *buf)
1009 {
1010 	ssize_t ret = 0;
1011 
1012 	if (bus_txglom == VALUENOTSET) {
1013 		ret = scnprintf(buf, PAGE_SIZE - 1, "%s\n", "bustxglom not set from sysfs");
1014 	} else {
1015 		ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", bus_txglom);
1016 	}
1017 	return ret;
1018 }
1019 
1020 static ssize_t
set_bustxglom(struct dhd_info * dev,const char * buf,size_t count)1021 set_bustxglom(struct dhd_info *dev, const char *buf, size_t count)
1022 {
1023 	uint32 onoff;
1024 
1025 	onoff = (uint32)bcm_atoi(buf);
1026 	sscanf(buf, "%u", &onoff);
1027 
1028 	if (onoff > 2) {
1029 		DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
1030 			__FUNCTION__, onoff));
1031 		return -EINVAL;
1032 	}
1033 
1034 	bus_txglom = onoff;
1035 	DHD_ERROR(("[WIFI_SEC] %s: BUS TXGLOM On/Off from sysfs = %u\n",
1036 			__FUNCTION__, bus_txglom));
1037 	return count;
1038 }
1039 
1040 static struct dhd_attr dhd_attr_cntl_bustxglom =
1041 	__ATTR(bustxglom, 0660, show_bustxglom, set_bustxglom);
1042 #endif /* BCMSDIO */
1043 
1044 #if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM)
1045 uint32 roam_off = VALUENOTSET;
1046 
1047 static ssize_t
show_roamoff(struct dhd_info * dev,char * buf)1048 show_roamoff(struct dhd_info *dev, char *buf)
1049 {
1050 	ssize_t ret = 0;
1051 
1052 	if (roam_off == VALUENOTSET) {
1053 		ret = scnprintf(buf, PAGE_SIZE -1, "%s\n", "roam_off not set from sysfs");
1054 	} else {
1055 		ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", roam_off);
1056 	}
1057 	return ret;
1058 }
1059 
1060 static ssize_t
set_roamoff(struct dhd_info * dev,const char * buf,size_t count)1061 set_roamoff(struct dhd_info *dev, const char *buf, size_t count)
1062 {
1063 	uint32 onoff;
1064 
1065 	onoff = bcm_atoi(buf);
1066 	sscanf(buf, "%u", &onoff);
1067 
1068 	if (onoff > 2) {
1069 		DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
1070 			__FUNCTION__, onoff));
1071 		return -EINVAL;
1072 	}
1073 
1074 	roam_off = onoff;
1075 	DHD_ERROR(("[WIFI_SEC] %s: ROAM On/Off from sysfs = %u\n",
1076 		__FUNCTION__, roam_off));
1077 	return count;
1078 }
1079 
1080 static struct dhd_attr dhd_attr_cntl_roamoff =
1081 	__ATTR(roamoff, 0660, show_roamoff, set_roamoff);
1082 #endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */
1083 
1084 #ifdef USE_WL_FRAMEBURST
1085 uint32 frameburst = VALUENOTSET;
1086 
1087 static ssize_t
show_frameburst(struct dhd_info * dev,char * buf)1088 show_frameburst(struct dhd_info *dev, char *buf)
1089 {
1090 	ssize_t ret = 0;
1091 
1092 	if (frameburst == VALUENOTSET) {
1093 		ret = scnprintf(buf, PAGE_SIZE -1, "%s\n", "frameburst not set from sysfs");
1094 	} else {
1095 		ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", frameburst);
1096 	}
1097 	return ret;
1098 }
1099 
1100 static ssize_t
set_frameburst(struct dhd_info * dev,const char * buf,size_t count)1101 set_frameburst(struct dhd_info *dev, const char *buf, size_t count)
1102 {
1103 	uint32 onoff;
1104 
1105 	onoff = bcm_atoi(buf);
1106 	sscanf(buf, "%u", &onoff);
1107 
1108 	if (onoff > 2) {
1109 		DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
1110 			__FUNCTION__, onoff));
1111 		return -EINVAL;
1112 	}
1113 
1114 	frameburst = onoff;
1115 	DHD_ERROR(("[WIFI_SEC] %s: FRAMEBURST On/Off from sysfs = %u\n",
1116 		__FUNCTION__, frameburst));
1117 	return count;
1118 }
1119 
1120 static struct dhd_attr dhd_attr_cntl_frameburst =
1121 	__ATTR(frameburst, 0660, show_frameburst, set_frameburst);
1122 #endif /* USE_WL_FRAMEBURST */
1123 
1124 #ifdef USE_WL_TXBF
1125 uint32 txbf = VALUENOTSET;
1126 
1127 static ssize_t
show_txbf(struct dhd_info * dev,char * buf)1128 show_txbf(struct dhd_info *dev, char *buf)
1129 {
1130 	ssize_t ret = 0;
1131 
1132 	if (txbf == VALUENOTSET) {
1133 		ret = scnprintf(buf, PAGE_SIZE -1, "%s\n", "txbf not set from sysfs");
1134 	} else {
1135 		ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", txbf);
1136 	}
1137 	return ret;
1138 }
1139 
1140 static ssize_t
set_txbf(struct dhd_info * dev,const char * buf,size_t count)1141 set_txbf(struct dhd_info *dev, const char *buf, size_t count)
1142 {
1143 	uint32 onoff;
1144 
1145 	onoff = bcm_atoi(buf);
1146 	sscanf(buf, "%u", &onoff);
1147 
1148 	if (onoff > 2) {
1149 		DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
1150 			__FUNCTION__, onoff));
1151 		return -EINVAL;
1152 	}
1153 
1154 	txbf = onoff;
1155 	DHD_ERROR(("[WIFI_SEC] %s: FRAMEBURST On/Off from sysfs = %u\n",
1156 		__FUNCTION__, txbf));
1157 	return count;
1158 }
1159 
1160 static struct dhd_attr dhd_attr_cntl_txbf =
1161 	__ATTR(txbf, 0660, show_txbf, set_txbf);
1162 #endif /* USE_WL_TXBF */
1163 
1164 #ifdef PROP_TXSTATUS
1165 uint32 proptx = VALUENOTSET;
1166 
1167 static ssize_t
show_proptx(struct dhd_info * dev,char * buf)1168 show_proptx(struct dhd_info *dev, char *buf)
1169 {
1170 	ssize_t ret = 0;
1171 
1172 	if (proptx == VALUENOTSET) {
1173 		ret = scnprintf(buf, PAGE_SIZE -1, "%s\n", "proptx not set from sysfs");
1174 	} else {
1175 		ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", proptx);
1176 	}
1177 	return ret;
1178 }
1179 
1180 static ssize_t
set_proptx(struct dhd_info * dev,const char * buf,size_t count)1181 set_proptx(struct dhd_info *dev, const char *buf, size_t count)
1182 {
1183 	uint32 onoff;
1184 
1185 	onoff = bcm_strtoul(buf, NULL, 10);
1186 	sscanf(buf, "%u", &onoff);
1187 
1188 	if (onoff > 2) {
1189 		DHD_ERROR(("[WIFI_SEC] %s: Set Invalid value %u \n",
1190 			__FUNCTION__, onoff));
1191 		return -EINVAL;
1192 	}
1193 
1194 	proptx = onoff;
1195 	DHD_ERROR(("[WIFI_SEC] %s: FRAMEBURST On/Off from sysfs = %u\n",
1196 		__FUNCTION__, txbf));
1197 	return count;
1198 }
1199 
1200 static struct dhd_attr dhd_attr_cntl_proptx =
1201 	__ATTR(proptx, 0660, show_proptx, set_proptx);
1202 
1203 #endif /* PROP_TXSTATUS */
1204 #endif /* USE_WFA_CERT_CONF */
1205 #endif /* DHD_EXPORT_CNTL_FILE */
1206 
1207 #if defined(DHD_ADPS_BAM_EXPORT) && defined(WL_BAM)
1208 #define BAD_AP_MAC_ADDR_ELEMENT_NUM	6
1209 wl_bad_ap_mngr_t *g_bad_ap_mngr = NULL;
1210 
1211 static ssize_t
show_adps_bam_list(struct dhd_info * dev,char * buf)1212 show_adps_bam_list(struct dhd_info *dev, char *buf)
1213 {
1214 	int offset = 0;
1215 	ssize_t ret = 0;
1216 
1217 	wl_bad_ap_info_t *bad_ap;
1218 	wl_bad_ap_info_entry_t *entry;
1219 
1220 	if (g_bad_ap_mngr == NULL)
1221 		return ret;
1222 
1223 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1224 #pragma GCC diagnostic push
1225 #pragma GCC diagnostic ignored "-Wcast-qual"
1226 #endif // endif
1227 	list_for_each_entry(entry, &g_bad_ap_mngr->list, list) {
1228 		bad_ap = &entry->bad_ap;
1229 
1230 		ret = scnprintf(buf + offset, PAGE_SIZE - 1, MACF"\n",
1231 			bad_ap->bssid.octet[0], bad_ap->bssid.octet[1],
1232 			bad_ap->bssid.octet[2], bad_ap->bssid.octet[3],
1233 			bad_ap->bssid.octet[4], bad_ap->bssid.octet[5]);
1234 
1235 		offset += ret;
1236 	}
1237 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1238 #pragma GCC diagnostic pop
1239 #endif // endif
1240 
1241 	return offset;
1242 }
1243 
1244 static ssize_t
store_adps_bam_list(struct dhd_info * dev,const char * buf,size_t count)1245 store_adps_bam_list(struct dhd_info *dev, const char *buf, size_t count)
1246 {
1247 	int ret;
1248 	size_t len;
1249 	int offset;
1250 	char tmp[128];
1251 	wl_bad_ap_info_t bad_ap;
1252 
1253 	if (g_bad_ap_mngr == NULL)
1254 		return count;
1255 
1256 	len = count;
1257 	offset = 0;
1258 	do {
1259 		ret = sscanf(buf + offset, MACF"\n",
1260 			(uint32 *)&bad_ap.bssid.octet[0], (uint32 *)&bad_ap.bssid.octet[1],
1261 			(uint32 *)&bad_ap.bssid.octet[2], (uint32 *)&bad_ap.bssid.octet[3],
1262 			(uint32 *)&bad_ap.bssid.octet[4], (uint32 *)&bad_ap.bssid.octet[5]);
1263 		if (ret != BAD_AP_MAC_ADDR_ELEMENT_NUM) {
1264 			DHD_ERROR(("%s - fail to parse bad ap data\n", __FUNCTION__));
1265 			return -EINVAL;
1266 		}
1267 
1268 		ret = wl_bad_ap_mngr_add(g_bad_ap_mngr, &bad_ap);
1269 		if (ret < 0)
1270 			return ret;
1271 
1272 		ret = snprintf(tmp, ARRAYSIZE(tmp), MACF"\n",
1273 			bad_ap.bssid.octet[0], bad_ap.bssid.octet[1],
1274 			bad_ap.bssid.octet[2], bad_ap.bssid.octet[3],
1275 			bad_ap.bssid.octet[4], bad_ap.bssid.octet[5]);
1276 		if (ret < 0) {
1277 			DHD_ERROR(("%s - fail to get bad ap data length(%d)\n", __FUNCTION__, ret));
1278 			return ret;
1279 		}
1280 
1281 		len -= ret;
1282 		offset += ret;
1283 	} while (len > 0);
1284 
1285 	return count;
1286 }
1287 
1288 static struct dhd_attr dhd_attr_adps_bam =
1289 	__ATTR(bad_ap_list, 0660, show_adps_bam_list, store_adps_bam_list);
1290 #endif	/* DHD_ADPS_BAM_EXPORT && WL_BAM */
1291 
1292 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
1293 uint32 report_hang_privcmd_err = 1;
1294 
1295 static ssize_t
show_hang_privcmd_err(struct dhd_info * dev,char * buf)1296 show_hang_privcmd_err(struct dhd_info *dev, char *buf)
1297 {
1298 	ssize_t ret = 0;
1299 
1300 	ret = scnprintf(buf, PAGE_SIZE - 1, "%u\n", report_hang_privcmd_err);
1301 	return ret;
1302 }
1303 
1304 static ssize_t
set_hang_privcmd_err(struct dhd_info * dev,const char * buf,size_t count)1305 set_hang_privcmd_err(struct dhd_info *dev, const char *buf, size_t count)
1306 {
1307 	uint32 val;
1308 
1309 	val = bcm_atoi(buf);
1310 	sscanf(buf, "%u", &val);
1311 
1312 	report_hang_privcmd_err = val ? 1 : 0;
1313 	DHD_INFO(("%s: Set report HANG for private cmd error: %d\n",
1314 		__FUNCTION__, report_hang_privcmd_err));
1315 	return count;
1316 }
1317 
1318 static struct dhd_attr dhd_attr_hang_privcmd_err =
1319 	__ATTR(hang_privcmd_err, 0660, show_hang_privcmd_err, set_hang_privcmd_err);
1320 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
1321 
1322 #if defined(DISABLE_HE_ENAB) || defined(CUSTOM_CONTROL_HE_ENAB)
1323 uint8 control_he_enab = 1;
1324 #endif /* DISABLE_HE_ENAB || CUSTOM_CONTROL_HE_ENAB */
1325 
1326 #if defined(CUSTOM_CONTROL_HE_ENAB)
1327 static ssize_t
show_control_he_enab(struct dhd_info * dev,char * buf)1328 show_control_he_enab(struct dhd_info *dev, char *buf)
1329 {
1330 	ssize_t ret = 0;
1331 
1332 	ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", control_he_enab);
1333 	return ret;
1334 }
1335 
1336 static ssize_t
set_control_he_enab(struct dhd_info * dev,const char * buf,size_t count)1337 set_control_he_enab(struct dhd_info *dev, const char *buf, size_t count)
1338 {
1339 	uint32 val;
1340 
1341 	val = bcm_atoi(buf);
1342 
1343 	control_he_enab = val ? 1 : 0;
1344 	DHD_ERROR(("%s: Set control he enab: %d\n", __FUNCTION__, control_he_enab));
1345 	return count;
1346 }
1347 
1348 static struct dhd_attr dhd_attr_control_he_enab=
1349 __ATTR(control_he_enab, 0660, show_control_he_enab, set_control_he_enab);
1350 #endif /* CUSTOM_CONTROL_HE_ENAB */
1351 /* Attribute object that gets registered with "wifi" kobject tree */
1352 static struct attribute *control_file_attrs[] = {
1353 #ifdef DHD_MAC_ADDR_EXPORT
1354 	&dhd_attr_cntl_macaddr.attr,
1355 #endif /* DHD_MAC_ADDR_EXPORT */
1356 #ifdef DHD_EXPORT_CNTL_FILE
1357 #ifdef DHD_FW_COREDUMP
1358 	&dhd_attr_cntl_memdump.attr,
1359 #endif /* DHD_FW_COREDUMP */
1360 #ifdef BCMASSERT_LOG
1361 	&dhd_attr_cntl_assert.attr,
1362 #endif /* BCMASSERT_LOG */
1363 #ifdef WRITE_WLANINFO
1364 	&dhd_attr_cntl_wifiver.attr,
1365 #endif /* WRITE_WLANINFO */
1366 #ifdef USE_CID_CHECK
1367 	&dhd_attr_cntl_cidinfo.attr,
1368 #endif /* USE_CID_CHECK */
1369 #ifdef GEN_SOFTAP_INFO_FILE
1370 	&dhd_attr_cntl_softapinfo.attr,
1371 #endif /* GEN_SOFTAP_INFO_FILE */
1372 #ifdef MIMO_ANT_SETTING
1373 	&dhd_attr_cntl_antinfo.attr,
1374 #endif /* MIMO_ANT_SETTING */
1375 #ifdef DHD_PM_CONTROL_FROM_FILE
1376 	&dhd_attr_cntl_pminfo.attr,
1377 #endif /* DHD_PM_CONTROL_FROM_FILE */
1378 #ifdef LOGTRACE_FROM_FILE
1379 	&dhd_attr_cntl_logtraceinfo.attr,
1380 #endif /* LOGTRACE_FROM_FILE */
1381 #ifdef USE_WFA_CERT_CONF
1382 #ifdef BCMSDIO
1383 	&dhd_attr_cntl_bustxglom.attr,
1384 #endif /* BCMSDIO */
1385 	&dhd_attr_cntl_roamoff.attr,
1386 #ifdef USE_WL_FRAMEBURST
1387 	&dhd_attr_cntl_frameburst.attr,
1388 #endif /* USE_WL_FRAMEBURST */
1389 #ifdef USE_WL_TXBF
1390 	&dhd_attr_cntl_txbf.attr,
1391 #endif /* USE_WL_TXBF */
1392 #ifdef PROP_TXSTATUS
1393 	&dhd_attr_cntl_proptx.attr,
1394 #endif /* PROP_TXSTATUS */
1395 #endif /* USE_WFA_CERT_CONF */
1396 #endif /* DHD_EXPORT_CNTL_FILE */
1397 #ifdef DHD_ADPS_BAM_EXPORT
1398 	&dhd_attr_adps_bam.attr,
1399 #endif	/* DHD_ADPS_BAM_EXPORT */
1400 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
1401 	&dhd_attr_hang_privcmd_err.attr,
1402 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
1403 #if defined(CUSTOM_CONTROL_HE_ENAB)
1404 	&dhd_attr_control_he_enab.attr,
1405 #endif /* CUSTOM_CONTROL_HE_ENAB */
1406 	NULL
1407 };
1408 
1409 #define to_cntl_dhd(k) container_of(k, struct dhd_info, dhd_conf_file_kobj)
1410 
1411 /*
1412  * wifi kobject show function, the "attr" attribute specifices to which
1413  * node under "sys/wifi" the show function is called.
1414  */
dhd_cntl_show(struct kobject * kobj,struct attribute * attr,char * buf)1415 static ssize_t dhd_cntl_show(struct kobject *kobj, struct attribute *attr, char *buf)
1416 {
1417 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1418 #pragma GCC diagnostic push
1419 #pragma GCC diagnostic ignored "-Wcast-qual"
1420 #endif // endif
1421 	dhd_info_t *dhd = to_cntl_dhd(kobj);
1422 	struct dhd_attr *d_attr = to_attr(attr);
1423 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1424 #pragma GCC diagnostic pop
1425 #endif // endif
1426 	int ret;
1427 
1428 	if (d_attr->show)
1429 		ret = d_attr->show(dhd, buf);
1430 	else
1431 		ret = -EIO;
1432 
1433 	return ret;
1434 }
1435 
1436 /*
1437  * wifi kobject show function, the "attr" attribute specifices to which
1438  * node under "sys/wifi" the store function is called.
1439  */
dhd_cntl_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t count)1440 static ssize_t dhd_cntl_store(struct kobject *kobj, struct attribute *attr,
1441 	const char *buf, size_t count)
1442 {
1443 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1444 #pragma GCC diagnostic push
1445 #pragma GCC diagnostic ignored "-Wcast-qual"
1446 #endif // endif
1447 	dhd_info_t *dhd = to_cntl_dhd(kobj);
1448 	struct dhd_attr *d_attr = to_attr(attr);
1449 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1450 #pragma GCC diagnostic pop
1451 #endif // endif
1452 	int ret;
1453 
1454 	if (d_attr->store)
1455 		ret = d_attr->store(dhd, buf, count);
1456 	else
1457 		ret = -EIO;
1458 
1459 	return ret;
1460 
1461 }
1462 
1463 static struct sysfs_ops dhd_sysfs_cntl_ops = {
1464 	.show = dhd_cntl_show,
1465 	.store = dhd_cntl_store,
1466 };
1467 
1468 static struct kobj_type dhd_cntl_file_ktype = {
1469 	.sysfs_ops = &dhd_sysfs_cntl_ops,
1470 	.default_attrs = control_file_attrs,
1471 };
1472 
1473 /* Create a kobject and attach to sysfs interface */
dhd_sysfs_init(dhd_info_t * dhd)1474 int dhd_sysfs_init(dhd_info_t *dhd)
1475 {
1476 	int ret = -1;
1477 
1478 	if (dhd == NULL) {
1479 		DHD_ERROR(("%s(): dhd is NULL \r\n", __FUNCTION__));
1480 		return ret;
1481 	}
1482 
1483 	/* Initialize the kobject */
1484 	ret = kobject_init_and_add(&dhd->dhd_kobj, &dhd_ktype, NULL, SYSFS_DIR_BCMDHD);
1485 	if (ret) {
1486 		kobject_put(&dhd->dhd_kobj);
1487 		DHD_ERROR(("%s(): Unable to allocate kobject \r\n", __FUNCTION__));
1488 		return ret;
1489 	}
1490 	ret = kobject_init_and_add(&dhd->dhd_conf_file_kobj,
1491 			&dhd_cntl_file_ktype, NULL, SYSFS_DIR_WIFI);
1492 	if (ret) {
1493 		kobject_put(&dhd->dhd_conf_file_kobj);
1494 		DHD_ERROR(("%s(): Unable to allocate kobject \r\n", __FUNCTION__));
1495 		return ret;
1496 	}
1497 
1498 	/*
1499 	 * We are always responsible for sending the uevent that the kobject
1500 	 * was added to the system.
1501 	 */
1502 	kobject_uevent(&dhd->dhd_kobj, KOBJ_ADD);
1503 	kobject_uevent(&dhd->dhd_conf_file_kobj, KOBJ_ADD);
1504 
1505 	return ret;
1506 }
1507 
1508 /* Done with the kobject and detach the sysfs interface */
dhd_sysfs_exit(dhd_info_t * dhd)1509 void dhd_sysfs_exit(dhd_info_t *dhd)
1510 {
1511 	if (dhd == NULL) {
1512 		DHD_ERROR(("%s(): dhd is NULL \r\n", __FUNCTION__));
1513 		return;
1514 	}
1515 
1516 	/* Releae the kobject */
1517 	kobject_put(&dhd->dhd_kobj);
1518 	kobject_put(&dhd->dhd_conf_file_kobj);
1519 }
1520