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