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