xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_config.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #include <typedefs.h>
3 #include <osl.h>
4 
5 #include <bcmendian.h>
6 #include <bcmutils.h>
7 #include <hndsoc.h>
8 #include <bcmsdbus.h>
9 #if defined(HW_OOB) || defined(FORCE_WOWLAN)
10 #include <bcmdefs.h>
11 #include <bcmsdh.h>
12 #include <sdio.h>
13 #include <sbchipc.h>
14 #endif
15 #ifdef DHDTCPACK_SUPPRESS
16 #include <dhd_ip.h>
17 #endif /* DHDTCPACK_SUPPRESS */
18 #ifdef WL_CFG80211
19 #include <wl_cfg80211.h>
20 #endif
21 
22 #include <dhd_config.h>
23 #include <dhd_dbg.h>
24 #include <wl_android.h>
25 #ifdef BCMPCIE
26 #include <dhd_flowring.h>
27 #endif
28 
29 #if defined(BCMSDIO) || defined(BCMPCIE)
30 #include <dhd_linux.h>
31 #include <dhd_bus.h>
32 #ifdef BCMSDIO
33 #include <linux/mmc/core.h>
34 #include <linux/mmc/card.h>
35 #include <linux/mmc/host.h>
36 #include <linux/mmc/sdio_func.h>
37 #endif /* defined(BCMSDIO) */
38 #endif
39 
40 /* message levels */
41 #define CONFIG_ERROR_LEVEL	(1 << 0)
42 #define CONFIG_TRACE_LEVEL	(1 << 1)
43 #define CONFIG_MSG_LEVEL	(1 << 0)
44 
45 uint config_msg_level = CONFIG_ERROR_LEVEL | CONFIG_MSG_LEVEL;
46 uint dump_msg_level = 0;
47 
48 #define CONFIG_MSG(x, args...) \
49 	do { \
50 		if (config_msg_level & CONFIG_MSG_LEVEL) { \
51 			printf("%s : " x, __func__, ## args); \
52 		} \
53 	} while (0)
54 #define CONFIG_ERROR(x, args...) \
55 	do { \
56 		if (config_msg_level & CONFIG_ERROR_LEVEL) { \
57 			printf("CONFIG-ERROR) %s : " x, __func__, ## args); \
58 		} \
59 	} while (0)
60 #define CONFIG_TRACE(x, args...) \
61 	do { \
62 		if (config_msg_level & CONFIG_TRACE_LEVEL) { \
63 			printf("CONFIG-TRACE) %s : " x, __func__, ## args); \
64 		} \
65 	} while (0)
66 
67 #define MAXSZ_BUF		4096
68 #define MAXSZ_CONFIG	8192
69 
70 #if defined(BCMSDIO) && defined(DYNAMIC_MAX_HDR_READ)
71 extern uint firstread;
72 #endif
73 
74 #if defined(PROP_TXSTATUS)
75 #include <dhd_wlfc.h>
76 #endif /* PROP_TXSTATUS */
77 
78 #define MAX_EVENT_BUF_NUM 16
79 typedef struct eventmsg_buf {
80 	u16 num;
81 	struct {
82 		u16 type;
83 		bool set;
84 	} event [MAX_EVENT_BUF_NUM];
85 } eventmsg_buf_t;
86 
87 typedef struct chip_name_map_t {
88 	uint chip;
89 	uint chiprev;
90 	uint ag_type;
91 	char *chip_name;
92 	char *module_name;
93 } chip_name_map_t;
94 
95 /* Map of WLC_E events to connection failure strings */
96 #define DONT_CARE	9999
97 const chip_name_map_t chip_name_map[] = {
98 	/* ChipID			Chiprev	AG	 	ChipName	ModuleName  */
99 #ifdef BCMSDIO
100 	{BCM43362_CHIP_ID,	0,	DONT_CARE,	"bcm40181a0",		""},
101 	{BCM43362_CHIP_ID,	1,	DONT_CARE,	"bcm40181a2",		"ap6181"},
102 	{BCM4330_CHIP_ID,	4,	FW_TYPE_G,	"RK903b2",			""},
103 	{BCM4330_CHIP_ID,	4,	FW_TYPE_AG,	"RK903_ag",			"AP6330"},
104 	{BCM43430_CHIP_ID,	0,	DONT_CARE,	"bcm43438a0",		"ap6212"},
105 	{BCM43430_CHIP_ID,	1,	DONT_CARE,	"bcm43438a1",		"ap6212a"},
106 	{BCM43430_CHIP_ID,	2,	DONT_CARE,	"bcm43436b0",		"ap6236"},
107 	{BCM43012_CHIP_ID,	1,	FW_TYPE_G,	"bcm43013b0",		""},
108 	{BCM43012_CHIP_ID,	1,	FW_TYPE_AG,	"bcm43013c0_ag",	""},
109 	{BCM43012_CHIP_ID,	2,	DONT_CARE,	"bcm43013c1_ag",	""},
110 	{BCM4334_CHIP_ID,	3,	DONT_CARE,	"bcm4334b1_ag",		""},
111 	{BCM43340_CHIP_ID,	2,	DONT_CARE,	"bcm43341b0_ag",	""},
112 	{BCM43341_CHIP_ID,	2,	DONT_CARE,	"bcm43341b0_ag",	""},
113 	{BCM4324_CHIP_ID,	5,	DONT_CARE,	"bcm43241b4_ag",	"ap62x2"},
114 	{BCM4335_CHIP_ID,	2,	DONT_CARE,	"bcm4339a0_ag",		"AP6335"},
115 	{BCM4339_CHIP_ID,	1,	DONT_CARE,	"bcm4339a0_ag",		"AP6335"},
116 	{BCM4345_CHIP_ID,	6,	DONT_CARE,	"bcm43455c0_ag",	"ap6255"},
117 	{BCM43454_CHIP_ID,	6,	DONT_CARE,	"bcm43455c0_ag",	""},
118 	{BCM4345_CHIP_ID,	9,	DONT_CARE,	"bcm43456c5_ag",	"ap6256"},
119 	{BCM43454_CHIP_ID,	9,	DONT_CARE,	"bcm43456c5_ag",	""},
120 	{BCM4354_CHIP_ID,	1,	DONT_CARE,	"bcm4354a1_ag",		"ap6354"},
121 	{BCM4354_CHIP_ID,	2,	DONT_CARE,	"bcm4356a2_ag",		"ap6356"},
122 	{BCM4356_CHIP_ID,	2,	DONT_CARE,	"bcm4356a2_ag",		"ap6356"},
123 	{BCM4371_CHIP_ID,	2,	DONT_CARE,	"bcm4356a2_ag",		""},
124 	{BCM43569_CHIP_ID,	3,	DONT_CARE,	"bcm4358a3_ag",		""},
125 	{BCM4359_CHIP_ID,	5,	DONT_CARE,	"bcm4359b1_ag",		""},
126 	{BCM4359_CHIP_ID,	9,	DONT_CARE,	"bcm4359c0_ag",		"ap6398s"},
127 	{BCM43751_CHIP_ID,	1,	DONT_CARE,	"bcm43751a1_ag",	""},
128 	{BCM43751_CHIP_ID,	2,	DONT_CARE,	"bcm43751a2_ag",	""},
129 	{BCM43752_CHIP_ID,	1,	DONT_CARE,	"bcm43752a1_ag",	""},
130 	{BCM43752_CHIP_ID,	2,	DONT_CARE,	"bcm43752a2_ag",	"ap6275s"},
131 #endif
132 #ifdef BCMPCIE
133 	{BCM4354_CHIP_ID,	2,	DONT_CARE,	"bcm4356a2_pcie_ag",	""},
134 	{BCM4356_CHIP_ID,	2,	DONT_CARE,	"bcm4356a2_pcie_ag",	""},
135 	{BCM4359_CHIP_ID,	9,	DONT_CARE,	"bcm4359c0_pcie_ag",	""},
136 	{BCM43751_CHIP_ID,	1,	DONT_CARE,	"bcm43751a1_pcie_ag",	""},
137 	{BCM43751_CHIP_ID,	2,	DONT_CARE,	"bcm43751a2_pcie_ag",	""},
138 	{BCM43752_CHIP_ID,	1,	DONT_CARE,	"bcm43752a1_pcie_ag",	""},
139 	{BCM43752_CHIP_ID,	2,	DONT_CARE,	"bcm43752a2_pcie_ag",	"AP6275P"},
140 	{BCM4375_CHIP_ID,	5,	DONT_CARE,	"bcm4375b4_pcie_ag",	""},
141 #endif
142 #ifdef BCMDBUS
143 	{BCM43143_CHIP_ID,	2,	DONT_CARE,	"bcm43143b0",		""},
144 	{BCM43242_CHIP_ID,	1,	DONT_CARE,	"bcm43242a1_ag",	""},
145 	{BCM43569_CHIP_ID,	2,	DONT_CARE,	"bcm4358u_ag",		""},
146 #endif
147 };
148 
149 #ifdef UPDATE_MODULE_NAME
150 typedef void (compat_func_t)(dhd_pub_t *dhd);
151 typedef struct module_name_map_t {
152 	uint devid;
153 	uint chip;
154 	uint chiprev;
155 	uint svid;
156 	uint ssid;
157 	char *module_name;
158 	char *chip_name;
159 	compat_func_t *compat_func;
160 } module_name_map_t;
161 
162 #if defined(BCMSDIO) || defined(BCMPCIE)
163 static void dhd_conf_compat_vht(dhd_pub_t *dhd);
164 #endif
165 
166 const module_name_map_t module_name_map[] = {
167 	/* Devce ID			Chip ID			Chiprev	SVID	SSID
168 	 *  ModuleName		ChipName			Compat function
169 	 */
170 #ifdef BCMSDIO
171 	{BCM43751_CHIP_ID,	BCM43752_CHIP_ID,	2,	0, 0,
172 		"ap6398s2",		"bcm4359c51a2_ag",	dhd_conf_compat_vht},
173 	{BCM43751_CHIP_ID,	BCM43752_CHIP_ID,	2,	0, 0,
174 		"ap6398sr32",	"bcm4359c51a2_ag",	dhd_conf_compat_vht},
175 	{BCM43751_CHIP_ID,	BCM43752_CHIP_ID,	2,	0, 0,
176 		"ap6398sv",		"bcm4359c51a2_ag",	dhd_conf_compat_vht},
177 	{BCM43751_CHIP_ID,	BCM43752_CHIP_ID,	2,	0, 0,
178 		"ap6398sv3",	"bcm4359c51a2_ag",	dhd_conf_compat_vht},
179 #endif
180 #ifdef BCMPCIE
181 	{BCM43751_D11AX_ID,	BCM43752_CHIP_ID,	2,	0x179F, 0x003C,
182 		"ap6398p2",		"bcm4359c51a2_pcie_ag",	dhd_conf_compat_vht},
183 	{BCM43751_D11AX_ID,	BCM43752_CHIP_ID,	2,	0x17F9, 0x003C,
184 		"ap6398p2",		"bcm4359c51a2_pcie_ag",	dhd_conf_compat_vht},
185 	{BCM43751_D11AX_ID,	BCM43752_CHIP_ID,	2,	0x17F9, 0x003D,
186 		"ap6398pr32",	"bcm4359c51a2_pcie_ag",	dhd_conf_compat_vht},
187 	{BCM43751_D11AX_ID,	BCM43752_CHIP_ID,	2,	0x17F9, 0x003E,
188 		"ap6398pv",		"bcm4359c51a2_pcie_ag",	dhd_conf_compat_vht},
189 	{BCM43751_D11AX_ID,	BCM43752_CHIP_ID,	2,	0x17F9, 0x003F,
190 		"ap6398pv3",	"bcm4359c51a2_pcie_ag",	dhd_conf_compat_vht},
191 #endif
192 };
193 #endif
194 
195 #ifdef BCMPCIE
196 typedef struct chip_cisaddr_map_t {
197 	uint chip;
198 	uint chiprev;
199 	uint start_addr;
200 	uint end_addr;
201 } chip_cisaddr_map_t;
202 const chip_cisaddr_map_t chip_cisaddr_map[] = {
203 	/* ChipID			Chiprev	Start	 	End  */
204 	{BCM4354_CHIP_ID,	2,		0x0,		0x0},
205 	{BCM4356_CHIP_ID,	2,		0x0,		0x0},
206 	{BCM4359_CHIP_ID,	9,		0x0,		0x0},
207 //	{BCM43752_CHIP_ID,	2,		0x18011120,	0x18011177},
208 //	{BCM4375_CHIP_ID,	5,		0x18011120,	0x18011177},
209 };
210 #endif
211 
212 #ifdef DHD_TPUT_PATCH
213 extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx);
214 #endif
215 
216 void
dhd_conf_free_chip_nv_path_list(wl_chip_nv_path_list_ctrl_t * chip_nv_list)217 dhd_conf_free_chip_nv_path_list(wl_chip_nv_path_list_ctrl_t *chip_nv_list)
218 {
219 	CONFIG_TRACE("called\n");
220 
221 	if (chip_nv_list->m_chip_nv_path_head) {
222 		CONFIG_TRACE("Free %p\n", chip_nv_list->m_chip_nv_path_head);
223 		kfree(chip_nv_list->m_chip_nv_path_head);
224 		chip_nv_list->m_chip_nv_path_head = NULL;
225 	}
226 	chip_nv_list->count = 0;
227 }
228 
229 #if defined(BCMSDIO) || defined(BCMPCIE)
230 typedef struct cis_tuple_format {
231 	uint8	id;
232 	uint8	len;	/* total length of tag and data */
233 	uint8	tag;
234 	uint8	data[1];
235 } cis_tuple_format_t;
236 #define SBSDIO_CIS_SIZE_LIMIT		0x200
237 #define SBSDIO_TUPLE_SIZE_LIMIT		0xff
238 #define CIS_TUPLE_ID_BRCM			0x80
239 #define CIS_TUPLE_TAG_MACADDR		0x19
240 #define CIS_TUPLE_ID_AMPAK			0x8e
241 #define CIS_TUPLE_TAG_MODULE		0x41
242 #define CIS_TUPLE_LENGTH		1
243 #define CIS_TUPLE_HDR_LEN		2
244 #endif
245 
246 #ifdef BCMSDIO
247 #if defined(HW_OOB) || defined(FORCE_WOWLAN)
248 void
dhd_conf_set_hw_oob_intr(bcmsdh_info_t * sdh,struct si_pub * sih)249 dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, struct si_pub *sih)
250 {
251 	uint32 gpiocontrol, addr;
252 
253 	if (CHIPID(sih->chip) == BCM43362_CHIP_ID) {
254 		CONFIG_MSG("Enable HW OOB for 43362\n");
255 		addr = SI_ENUM_BASE(sih) + OFFSETOF(chipcregs_t, gpiocontrol);
256 		gpiocontrol = bcmsdh_reg_read(sdh, addr, 4);
257 		gpiocontrol |= 0x2;
258 		bcmsdh_reg_write(sdh, addr, 4, gpiocontrol);
259 		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10005, 0xf, NULL);
260 		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10006, 0x0, NULL);
261 		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10007, 0x2, NULL);
262 	}
263 }
264 #endif
265 
266 void
dhd_conf_get_otp(dhd_pub_t * dhd,bcmsdh_info_t * sdh,si_t * sih)267 dhd_conf_get_otp(dhd_pub_t *dhd, bcmsdh_info_t *sdh, si_t *sih)
268 {
269 	int i, err = -1;
270 	uint8 *cis, *ptr = 0;
271 	uint8 mac_header[3] = {0x80, 0x07, 0x19};
272 	cis_tuple_format_t *tuple;
273 	int totlen, len;
274 
275 	if (!(cis = MALLOC(dhd->osh, SBSDIO_CIS_SIZE_LIMIT))) {
276 		CONFIG_ERROR("cis malloc failed\n");
277 	}
278 	bzero(cis, SBSDIO_CIS_SIZE_LIMIT);
279 
280 	if ((err = bcmsdh_cis_read(sdh, 0, cis, SBSDIO_CIS_SIZE_LIMIT))) {
281 		CONFIG_ERROR("cis read err %d\n", err);
282 		MFREE(dhd->osh, cis, SBSDIO_CIS_SIZE_LIMIT);
283 		return;
284 	}
285 	tuple = (cis_tuple_format_t *)cis;
286 	totlen = SBSDIO_CIS_SIZE_LIMIT;
287 	if (config_msg_level & CONFIG_TRACE_LEVEL) {
288 		prhex("CIS", &tuple->id, totlen);
289 	}
290 	while (totlen >= (tuple->len + CIS_TUPLE_HDR_LEN)) {
291 		len = tuple->len;
292 		if ((config_msg_level & CONFIG_TRACE_LEVEL) && tuple->id) {
293 			prhex("TPL", &tuple->id, tuple->len + CIS_TUPLE_HDR_LEN);
294 		}
295 		if (tuple->id == 0xff || tuple->len == 0xff)
296 			break;
297 		if ((tuple->id == CIS_TUPLE_ID_BRCM) &&
298 				(tuple->tag == CIS_TUPLE_TAG_MACADDR) &&
299 				(totlen >= (int)(len + CIS_TUPLE_HDR_LEN))) {
300 			memcpy(&dhd->conf->otp_mac, tuple->data, ETHER_ADDR_LEN);
301 		}
302 #ifdef GET_OTP_MODULE_NAME
303 		else if (tuple->id == CIS_TUPLE_ID_AMPAK && (tuple->len) &&
304 				tuple->tag == CIS_TUPLE_TAG_MODULE) {
305 			int len = tuple->len - 1;
306 			if (len <= sizeof(dhd->conf->module_name) - 1) {
307 				strncpy(dhd->conf->module_name, tuple->data, len);
308 				CONFIG_MSG("module_name=%s\n", dhd->conf->module_name);
309 			} else {
310 				CONFIG_ERROR("len is too long %d >= %d\n",
311 					len, (int)sizeof(dhd->conf->module_name) - 1);
312 			}
313 		}
314 #endif
315 		tuple = (cis_tuple_format_t*)((uint8*)tuple + (len + CIS_TUPLE_HDR_LEN));
316 		totlen -= (len + CIS_TUPLE_HDR_LEN);
317 	}
318 
319 	if (!memcmp(&ether_null, &dhd->conf->otp_mac, ETHER_ADDR_LEN)) {
320 		ptr = cis;
321 		/* Special OTP */
322 		if (bcmsdh_reg_read(sdh, SI_ENUM_BASE(sih), 4) == 0x16044330) {
323 			for (i=0; i<SBSDIO_CIS_SIZE_LIMIT; i++) {
324 				if (!memcmp(mac_header, ptr, 3)) {
325 					memcpy(&dhd->conf->otp_mac, ptr+3, ETHER_ADDR_LEN);
326 					break;
327 				}
328 				ptr++;
329 			}
330 		}
331 	}
332 
333 	ASSERT(cis);
334 	MFREE(dhd->osh, cis, SBSDIO_CIS_SIZE_LIMIT);
335 }
336 
337 #ifdef SET_FWNV_BY_MAC
338 void
dhd_conf_free_mac_list(wl_mac_list_ctrl_t * mac_list)339 dhd_conf_free_mac_list(wl_mac_list_ctrl_t *mac_list)
340 {
341 	int i;
342 
343 	CONFIG_TRACE("called\n");
344 	if (mac_list->m_mac_list_head) {
345 		for (i=0; i<mac_list->count; i++) {
346 			if (mac_list->m_mac_list_head[i].mac) {
347 				CONFIG_TRACE("Free mac %p\n", mac_list->m_mac_list_head[i].mac);
348 				kfree(mac_list->m_mac_list_head[i].mac);
349 			}
350 		}
351 		CONFIG_TRACE("Free m_mac_list_head %p\n", mac_list->m_mac_list_head);
352 		kfree(mac_list->m_mac_list_head);
353 	}
354 	mac_list->count = 0;
355 }
356 
357 void
dhd_conf_set_fw_name_by_mac(dhd_pub_t * dhd,char * fw_path)358 dhd_conf_set_fw_name_by_mac(dhd_pub_t *dhd, char *fw_path)
359 {
360 	int i, j;
361 	uint8 *mac = (uint8 *)&dhd->conf->otp_mac;
362 	int fw_num=0, mac_num=0;
363 	uint32 oui, nic;
364 	wl_mac_list_t *mac_list;
365 	wl_mac_range_t *mac_range;
366 	int fw_type, fw_type_new;
367 	char *name_ptr;
368 
369 	mac_list = dhd->conf->fw_by_mac.m_mac_list_head;
370 	fw_num = dhd->conf->fw_by_mac.count;
371 	if (!mac_list || !fw_num)
372 		return;
373 
374 	oui = (mac[0] << 16) | (mac[1] << 8) | (mac[2]);
375 	nic = (mac[3] << 16) | (mac[4] << 8) | (mac[5]);
376 
377 	/* find out the last '/' */
378 	i = strlen(fw_path);
379 	while (i > 0) {
380 		if (fw_path[i] == '/') {
381 			i++;
382 			break;
383 		}
384 		i--;
385 	}
386 	name_ptr = &fw_path[i];
387 
388 	if (strstr(name_ptr, "_apsta"))
389 		fw_type = FW_TYPE_APSTA;
390 	else if (strstr(name_ptr, "_p2p"))
391 		fw_type = FW_TYPE_P2P;
392 	else if (strstr(name_ptr, "_mesh"))
393 		fw_type = FW_TYPE_MESH;
394 	else if (strstr(name_ptr, "_ezmesh"))
395 		fw_type = FW_TYPE_EZMESH;
396 	else if (strstr(name_ptr, "_es"))
397 		fw_type = FW_TYPE_ES;
398 	else if (strstr(name_ptr, "_mfg"))
399 		fw_type = FW_TYPE_MFG;
400 	else
401 		fw_type = FW_TYPE_STA;
402 
403 	for (i=0; i<fw_num; i++) {
404 		mac_num = mac_list[i].count;
405 		mac_range = mac_list[i].mac;
406 		if (strstr(mac_list[i].name, "_apsta"))
407 			fw_type_new = FW_TYPE_APSTA;
408 		else if (strstr(mac_list[i].name, "_p2p"))
409 			fw_type_new = FW_TYPE_P2P;
410 		else if (strstr(mac_list[i].name, "_mesh"))
411 			fw_type_new = FW_TYPE_MESH;
412 		else if (strstr(mac_list[i].name, "_ezmesh"))
413 			fw_type_new = FW_TYPE_EZMESH;
414 		else if (strstr(mac_list[i].name, "_es"))
415 			fw_type_new = FW_TYPE_ES;
416 		else if (strstr(mac_list[i].name, "_mfg"))
417 			fw_type_new = FW_TYPE_MFG;
418 		else
419 			fw_type_new = FW_TYPE_STA;
420 		if (fw_type != fw_type_new) {
421 			CONFIG_MSG("fw_typ=%d != fw_type_new=%d\n", fw_type, fw_type_new);
422 			continue;
423 		}
424 		for (j=0; j<mac_num; j++) {
425 			if (oui == mac_range[j].oui) {
426 				if (nic >= mac_range[j].nic_start && nic <= mac_range[j].nic_end) {
427 					strcpy(name_ptr, mac_list[i].name);
428 					CONFIG_MSG("matched oui=0x%06X, nic=0x%06X\n", oui, nic);
429 					CONFIG_MSG("fw_path=%s\n", fw_path);
430 					return;
431 				}
432 			}
433 		}
434 	}
435 }
436 
437 void
dhd_conf_set_nv_name_by_mac(dhd_pub_t * dhd,char * nv_path)438 dhd_conf_set_nv_name_by_mac(dhd_pub_t *dhd, char *nv_path)
439 {
440 	int i, j;
441 	uint8 *mac = (uint8 *)&dhd->conf->otp_mac;
442 	int nv_num=0, mac_num=0;
443 	uint32 oui, nic;
444 	wl_mac_list_t *mac_list;
445 	wl_mac_range_t *mac_range;
446 	char *pnv_name;
447 
448 	mac_list = dhd->conf->nv_by_mac.m_mac_list_head;
449 	nv_num = dhd->conf->nv_by_mac.count;
450 	if (!mac_list || !nv_num)
451 		return;
452 
453 	oui = (mac[0] << 16) | (mac[1] << 8) | (mac[2]);
454 	nic = (mac[3] << 16) | (mac[4] << 8) | (mac[5]);
455 
456 	/* find out the last '/' */
457 	i = strlen(nv_path);
458 	while (i > 0) {
459 		if (nv_path[i] == '/') break;
460 		i--;
461 	}
462 	pnv_name = &nv_path[i+1];
463 
464 	for (i=0; i<nv_num; i++) {
465 		mac_num = mac_list[i].count;
466 		mac_range = mac_list[i].mac;
467 		for (j=0; j<mac_num; j++) {
468 			if (oui == mac_range[j].oui) {
469 				if (nic >= mac_range[j].nic_start && nic <= mac_range[j].nic_end) {
470 					strcpy(pnv_name, mac_list[i].name);
471 					CONFIG_MSG("matched oui=0x%06X, nic=0x%06X\n", oui, nic);
472 					CONFIG_MSG("nv_path=%s\n", nv_path);
473 					return;
474 				}
475 			}
476 		}
477 	}
478 }
479 #endif
480 #endif
481 
482 #ifdef BCMPCIE
483 static int
dhd_conf_read_otp_from_bp(si_t * sih,uint32 * data_buf,uint32 cis_start_addr,uint32 cis_max_cnt)484 dhd_conf_read_otp_from_bp(si_t *sih, uint32 *data_buf,
485 	uint32 cis_start_addr, uint32 cis_max_cnt)
486 {
487 	int int_val = 0, i = 0, bp_idx = 0;
488 	int boardtype_backplane_addr[] = {
489 		0x18010324, /* OTP Control 1 */
490 		0x18012618, /* PMU min resource mask */
491 	};
492 	int boardtype_backplane_data[] = {
493 		0x00fa0000,
494 		0x0e4fffff /* Keep on ARMHTAVAIL */
495 	};
496 	uint32 org_boardtype_backplane_data[] = {
497 		0,
498 		0
499 	};
500 
501 	for (bp_idx=0; bp_idx<ARRAYSIZE(boardtype_backplane_addr); bp_idx++) {
502 		/* Read OTP Control 1 and PMU min_rsrc_mask before writing */
503 		if (si_backplane_access(sih, boardtype_backplane_addr[bp_idx], sizeof(int),
504 				&org_boardtype_backplane_data[bp_idx], TRUE) != BCME_OK) {
505 			CONFIG_ERROR("invalid size/addr combination\n");
506 			return BCME_ERROR;
507 		}
508 
509 		/* Write new OTP and PMU configuration */
510 		if (si_backplane_access(sih, boardtype_backplane_addr[bp_idx], sizeof(int),
511 				&boardtype_backplane_data[bp_idx], FALSE) != BCME_OK) {
512 			CONFIG_ERROR("invalid size/addr combination\n");
513 			return BCME_ERROR;
514 		}
515 
516 		if (si_backplane_access(sih, boardtype_backplane_addr[bp_idx], sizeof(int),
517 				&int_val, TRUE) != BCME_OK) {
518 			CONFIG_ERROR("invalid size/addr combination\n");
519 			return BCME_ERROR;
520 		}
521 
522 		CONFIG_TRACE("boardtype_backplane_addr 0x%08x rdata 0x%04x\n",
523 			boardtype_backplane_addr[bp_idx], int_val);
524 	}
525 
526 	/* read tuple raw data */
527 	for (i=0; i<cis_max_cnt; i++) {
528 		if (si_backplane_access(sih, cis_start_addr + i * sizeof(uint32),
529 				sizeof(uint32),	&data_buf[i], TRUE) != BCME_OK) {
530 			break;
531 		}
532 		CONFIG_TRACE("tuple index %d, raw data 0x%08x\n", i,  data_buf[i]);
533 	}
534 
535 	for (bp_idx=0; bp_idx<ARRAYSIZE(boardtype_backplane_addr); bp_idx++) {
536 		/* Write original OTP and PMU configuration */
537 		if (si_backplane_access(sih, boardtype_backplane_addr[bp_idx], sizeof(int),
538 				&org_boardtype_backplane_data[bp_idx], FALSE) != BCME_OK) {
539 			CONFIG_ERROR("invalid size/addr combination\n");
540 			return BCME_ERROR;
541 		}
542 
543 		if (si_backplane_access(sih, boardtype_backplane_addr[bp_idx], sizeof(int),
544 				&int_val, TRUE) != BCME_OK) {
545 			CONFIG_ERROR("invalid size/addr combination\n");
546 			return BCME_ERROR;
547 		}
548 
549 		CONFIG_TRACE("boardtype_backplane_addr 0x%08x rdata 0x%04x\n",
550 			boardtype_backplane_addr[bp_idx], int_val);
551 	}
552 
553 	return i * sizeof(uint32);
554 }
555 
556 int
dhd_conf_get_otp(dhd_pub_t * dhd,si_t * sih)557 dhd_conf_get_otp(dhd_pub_t *dhd, si_t *sih)
558 {
559 	int totlen, len;
560 	uint32 *raw_data = NULL;
561 	cis_tuple_format_t *tuple;
562 	uint32 cis_start_addr = 0, cis_end_addr = 0, cis_max_cnt;
563 	uint chip, chiprev;
564 	int i, ret = BCME_OK;
565 
566 	chip = dhd->conf->chip;
567 	chiprev = dhd->conf->chiprev;
568 
569 	for (i=0; i<sizeof(chip_cisaddr_map)/sizeof(chip_cisaddr_map[0]); i++) {
570 		const chip_cisaddr_map_t* row = &chip_cisaddr_map[i];
571 		if (row->chip == chip && row->chiprev == chiprev) {
572 			cis_start_addr = row->start_addr;
573 			cis_end_addr = row->end_addr;
574 		}
575 	}
576 
577 	if (!cis_start_addr || !cis_end_addr) {
578 		CONFIG_TRACE("no matched chip\n");
579 		goto exit;
580 	}
581 	cis_max_cnt = (cis_end_addr - cis_start_addr + 1) / sizeof(uint32);
582 
583 	raw_data = kmalloc(cis_max_cnt, GFP_KERNEL);
584 	if (raw_data == NULL) {
585 		CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", cis_max_cnt);
586 		goto exit;
587 	}
588 
589 	totlen = dhd_conf_read_otp_from_bp(sih, raw_data, cis_start_addr, cis_max_cnt);
590 	if (totlen == BCME_ERROR || totlen == 0) {
591 		CONFIG_ERROR("Can't read the OTP\n");
592 		ret = BCME_ERROR;
593 		goto exit;
594 	}
595 
596 	tuple = (cis_tuple_format_t *)raw_data;
597 
598 	if (config_msg_level & CONFIG_TRACE_LEVEL) {
599 		CONFIG_TRACE("start: 0x%x, end: 0x%x, totlen: %d\n",
600 			cis_start_addr, cis_end_addr, totlen);
601 		prhex("CIS", &tuple->id, totlen);
602 	}
603 
604 	/* check the first tuple has tag 'start' */
605 	if (tuple->id != CIS_TUPLE_ID_BRCM) {
606 		CONFIG_ERROR("Can not find the TAG\n");
607 		ret = BCME_ERROR;
608 		goto exit;
609 	}
610 
611 	/* find tagged parameter */
612 	while (totlen >= (tuple->len + CIS_TUPLE_HDR_LEN)) {
613 		len = tuple->len;
614 		if ((config_msg_level & CONFIG_TRACE_LEVEL) && tuple->id) {
615 			prhex("TPL", &tuple->id, tuple->len+CIS_TUPLE_HDR_LEN);
616 		}
617 		if ((tuple->id == CIS_TUPLE_ID_BRCM) &&
618 				(tuple->tag == CIS_TUPLE_TAG_MACADDR) &&
619 				(totlen >= (int)(len + CIS_TUPLE_HDR_LEN))) {
620 			memcpy(&dhd->conf->otp_mac, tuple->data, ETHER_ADDR_LEN);
621 		}
622 		tuple = (cis_tuple_format_t*)((uint8*)tuple + (len + CIS_TUPLE_HDR_LEN));
623 		totlen -= (len + CIS_TUPLE_HDR_LEN);
624 	}
625 
626 exit:
627 	if(raw_data)
628 		kfree(raw_data);
629 	return ret;
630 }
631 
632 bool
dhd_conf_legacy_msi_chip(dhd_pub_t * dhd)633 dhd_conf_legacy_msi_chip(dhd_pub_t *dhd)
634 {
635 	uint chip;
636 
637 	chip = dhd->conf->chip;
638 
639 	if (chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID ||
640 		chip == BCM4371_CHIP_ID ||
641 		chip == BCM4359_CHIP_ID) {
642 		return true;
643 	}
644 
645 	return false;
646 }
647 #endif
648 
649 void
dhd_conf_free_country_list(struct dhd_conf * conf)650 dhd_conf_free_country_list(struct dhd_conf *conf)
651 {
652 	country_list_t *country = conf->country_head;
653 	int count = 0;
654 
655 	CONFIG_TRACE("called\n");
656 	while (country) {
657 		CONFIG_TRACE("Free cspec %s\n", country->cspec.country_abbrev);
658 		conf->country_head = country->next;
659 		kfree(country);
660 		country = conf->country_head;
661 		count++;
662 	}
663 	CONFIG_TRACE("%d country released\n", count);
664 }
665 
666 void
dhd_conf_free_mchan_list(struct dhd_conf * conf)667 dhd_conf_free_mchan_list(struct dhd_conf *conf)
668 {
669 	mchan_params_t *mchan = conf->mchan;
670 	int count = 0;
671 
672 	CONFIG_TRACE("called\n");
673 	while (mchan) {
674 		CONFIG_TRACE("Free cspec %p\n", mchan);
675 		conf->mchan = mchan->next;
676 		kfree(mchan);
677 		mchan = conf->mchan;
678 		count++;
679 	}
680 	CONFIG_TRACE("%d mchan released\n", count);
681 }
682 
683 const chip_name_map_t*
dhd_conf_match_chip(dhd_pub_t * dhd,uint ag_type)684 dhd_conf_match_chip(dhd_pub_t *dhd, uint ag_type)
685 {
686 	uint chip, chiprev;
687 	int i;
688 
689 	chip = dhd->conf->chip;
690 	chiprev = dhd->conf->chiprev;
691 
692 	for (i=0; i<sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) {
693 		const chip_name_map_t* row = &chip_name_map[i];
694 		if (row->chip == chip && row->chiprev == chiprev &&
695 				(row->ag_type == ag_type ||
696 					ag_type == DONT_CARE || row->ag_type == DONT_CARE)) {
697 			return row;
698 		}
699 	}
700 
701 	return NULL;
702 }
703 
704 #ifdef UPDATE_MODULE_NAME
705 const module_name_map_t*
dhd_conf_match_module(dhd_pub_t * dhd)706 dhd_conf_match_module(dhd_pub_t *dhd)
707 {
708 	uint devid, chip, chiprev;
709 #ifdef BCMPCIE
710 	uint svid, ssid;
711 #endif
712 #if defined(BCMSDIO) || defined(BCMPCIE)
713 	int i;
714 #endif
715 
716 	devid = dhd->conf->devid;
717 	chip = dhd->conf->chip;
718 	chiprev = dhd->conf->chiprev;
719 #ifdef BCMPCIE
720 	svid = dhd->conf->svid;
721 	ssid = dhd->conf->ssid;
722 #endif
723 
724 #ifdef BCMSDIO
725 	for (i=0; i<sizeof(module_name_map)/sizeof(module_name_map[0]); i++) {
726 		const module_name_map_t* row = &module_name_map[i];
727 		if (row->devid == devid && row->chip == chip && row->chiprev == chiprev &&
728 				!strcmp(row->module_name, dhd->conf->module_name)) {
729 			return row;
730 		}
731 	}
732 #endif
733 
734 #ifdef BCMPCIE
735 	for (i=0; i<sizeof(module_name_map)/sizeof(module_name_map[0]); i++) {
736 		const module_name_map_t* row = &module_name_map[i];
737 		if (row->devid == devid && row->chip == chip && row->chiprev == chiprev &&
738 				row->svid == svid && row->ssid == ssid) {
739 			return row;
740 		}
741 	}
742 #endif
743 
744 	return NULL;
745 }
746 #endif
747 
748 int
dhd_conf_set_fw_name_by_chip(dhd_pub_t * dhd,char * fw_path)749 dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path)
750 {
751 #ifdef UPDATE_MODULE_NAME
752 	const module_name_map_t* row_module = NULL;
753 #endif
754 	const chip_name_map_t* row_chip = NULL;
755 	int fw_type, ag_type;
756 	uint chip, chiprev;
757 	char *name_ptr;
758 	int i;
759 
760 	chip = dhd->conf->chip;
761 	chiprev = dhd->conf->chiprev;
762 
763 	if (fw_path[0] == '\0') {
764 #ifdef CONFIG_BCMDHD_FW_PATH
765 		bcm_strncpy_s(fw_path, MOD_PARAM_PATHLEN-1, CONFIG_BCMDHD_FW_PATH, MOD_PARAM_PATHLEN-1);
766 		if (fw_path[0] == '\0')
767 #endif
768 		{
769 			CONFIG_MSG("firmware path is null\n");
770 			return 0;
771 		}
772 	}
773 #ifndef FW_PATH_AUTO_SELECT
774 	return DONT_CARE;
775 #endif
776 
777 	/* find out the last '/' */
778 	i = strlen(fw_path);
779 	while (i > 0) {
780 		if (fw_path[i] == '/') {
781 			i++;
782 			break;
783 		}
784 		i--;
785 	}
786 	name_ptr = &fw_path[i];
787 #ifdef BAND_AG
788 	ag_type = FW_TYPE_AG;
789 #else
790 	ag_type = strstr(name_ptr, "_ag") ? FW_TYPE_AG : FW_TYPE_G;
791 #endif
792 	if (strstr(name_ptr, "_apsta"))
793 		fw_type = FW_TYPE_APSTA;
794 	else if (strstr(name_ptr, "_p2p"))
795 		fw_type = FW_TYPE_P2P;
796 	else if (strstr(name_ptr, "_mesh"))
797 		fw_type = FW_TYPE_MESH;
798 	else if (strstr(name_ptr, "_ezmesh"))
799 		fw_type = FW_TYPE_EZMESH;
800 	else if (strstr(name_ptr, "_es"))
801 		fw_type = FW_TYPE_ES;
802 	else if (strstr(name_ptr, "_mfg"))
803 		fw_type = FW_TYPE_MFG;
804 	else if (strstr(name_ptr, "_minime"))
805 		fw_type = FW_TYPE_MINIME;
806 	else
807 		fw_type = FW_TYPE_STA;
808 #ifdef WLEASYMESH
809 	if (dhd->conf->fw_type == FW_TYPE_EZMESH)
810 		fw_type = FW_TYPE_EZMESH;
811 #endif /* WLEASYMESH */
812 
813 	row_chip = dhd_conf_match_chip(dhd, ag_type);
814 	if (row_chip && strlen(row_chip->chip_name)) {
815 		strcpy(name_ptr, "fw_");
816 		strcat(name_ptr, row_chip->chip_name);
817 #ifdef BCMUSBDEV_COMPOSITE
818 		strcat(name_ptr, "_cusb");
819 #endif
820 		if (fw_type == FW_TYPE_APSTA)
821 			strcat(name_ptr, "_apsta.bin");
822 		else if (fw_type == FW_TYPE_P2P)
823 			strcat(name_ptr, "_p2p.bin");
824 		else if (fw_type == FW_TYPE_MESH)
825 			strcat(name_ptr, "_mesh.bin");
826 		else if (fw_type == FW_TYPE_EZMESH)
827 			strcat(name_ptr, "_ezmesh.bin");
828 		else if (fw_type == FW_TYPE_ES)
829 			strcat(name_ptr, "_es.bin");
830 		else if (fw_type == FW_TYPE_MFG)
831 			strcat(name_ptr, "_mfg.bin");
832 		else if (fw_type == FW_TYPE_MINIME)
833 			strcat(name_ptr, "_minime.bin");
834 		else
835 			strcat(name_ptr, ".bin");
836 	}
837 
838 #ifdef UPDATE_MODULE_NAME
839 	row_module = dhd_conf_match_module(dhd);
840 	if (row_module && strlen(row_module->chip_name)) {
841 		strcpy(name_ptr, "fw_");
842 		strcat(name_ptr, row_module->chip_name);
843 #ifdef BCMUSBDEV_COMPOSITE
844 		strcat(name_ptr, "_cusb");
845 #endif
846 		if (fw_type == FW_TYPE_APSTA)
847 			strcat(name_ptr, "_apsta.bin");
848 		else if (fw_type == FW_TYPE_P2P)
849 			strcat(name_ptr, "_p2p.bin");
850 		else if (fw_type == FW_TYPE_MESH)
851 			strcat(name_ptr, "_mesh.bin");
852 		else if (fw_type == FW_TYPE_EZMESH)
853 			strcat(name_ptr, "_ezmesh.bin");
854 		else if (fw_type == FW_TYPE_ES)
855 			strcat(name_ptr, "_es.bin");
856 		else if (fw_type == FW_TYPE_MFG)
857 			strcat(name_ptr, "_mfg.bin");
858 		else if (fw_type == FW_TYPE_MINIME)
859 			strcat(name_ptr, "_minime.bin");
860 		else
861 			strcat(name_ptr, ".bin");
862 	}
863 #endif
864 
865 	dhd->conf->fw_type = fw_type;
866 
867 #ifndef MINIME
868 	if (fw_type == FW_TYPE_MINIME)
869 		CONFIG_ERROR("***** Please enable MINIME in Makefile *****\n");
870 #endif
871 
872 	CONFIG_TRACE("firmware_path=%s\n", fw_path);
873 	return ag_type;
874 }
875 
876 void
dhd_conf_set_clm_name_by_chip(dhd_pub_t * dhd,char * clm_path,int ag_type)877 dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path, int ag_type)
878 {
879 #ifdef UPDATE_MODULE_NAME
880 	const module_name_map_t* row_module = NULL;
881 #endif
882 	const chip_name_map_t* row_chip = NULL;
883 	uint chip, chiprev;
884 	char *name_ptr;
885 	int i;
886 
887 	chip = dhd->conf->chip;
888 	chiprev = dhd->conf->chiprev;
889 
890 	if (clm_path[0] == '\0') {
891 		CONFIG_MSG("clm path is null\n");
892 		return;
893 	}
894 
895 	/* find out the last '/' */
896 	i = strlen(clm_path);
897 	while (i > 0) {
898 		if (clm_path[i] == '/') {
899 			i++;
900 			break;
901 		}
902 		i--;
903 	}
904 	name_ptr = &clm_path[i];
905 
906 	row_chip = dhd_conf_match_chip(dhd, ag_type);
907 	if (row_chip && strlen(row_chip->chip_name)) {
908 		strcpy(name_ptr, "clm_");
909 		strcat(name_ptr, row_chip->chip_name);
910 		strcat(name_ptr, ".blob");
911 	}
912 
913 #ifdef UPDATE_MODULE_NAME
914 	row_module = dhd_conf_match_module(dhd);
915 	if (row_module && strlen(row_module->chip_name)) {
916 		strcpy(name_ptr, "clm_");
917 		strcat(name_ptr, row_module->chip_name);
918 		strcat(name_ptr, ".blob");
919 	}
920 #endif
921 
922 	CONFIG_TRACE("clm_path=%s\n", clm_path);
923 }
924 
925 void
dhd_conf_set_nv_name_by_chip(dhd_pub_t * dhd,char * nv_path,int ag_type)926 dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path, int ag_type)
927 {
928 #if defined(BCMPCIE) && defined(UPDATE_MODULE_NAME)
929 	const module_name_map_t* row_module = NULL;
930 #endif
931 	const chip_name_map_t* row_chip = NULL;
932 	uint chip, chiprev;
933 	char *name_ptr, nv_name[32];
934 	int i;
935 
936 	chip = dhd->conf->chip;
937 	chiprev = dhd->conf->chiprev;
938 
939 	if (nv_path[0] == '\0') {
940 #ifdef CONFIG_BCMDHD_NVRAM_PATH
941 		bcm_strncpy_s(nv_path, MOD_PARAM_PATHLEN-1, CONFIG_BCMDHD_NVRAM_PATH, MOD_PARAM_PATHLEN-1);
942 		if (nv_path[0] == '\0')
943 #endif
944 		{
945 			CONFIG_MSG("nvram path is null\n");
946 			return;
947 		}
948 	}
949 
950 	/* find out the last '/' */
951 	i = strlen(nv_path);
952 	while (i > 0) {
953 		if (nv_path[i] == '/') {
954 			i++;
955 			break;
956 		}
957 		i--;
958 	}
959 	name_ptr = &nv_path[i];
960 
961 	row_chip = dhd_conf_match_chip(dhd, ag_type);
962 	if (row_chip && strlen(row_chip->module_name)) {
963 		strcpy(name_ptr, "nvram_");
964 		strcat(name_ptr, row_chip->module_name);
965 #ifdef BCMUSBDEV_COMPOSITE
966 		strcat(name_ptr, "_cusb");
967 #endif
968 		strcat(name_ptr, ".txt");
969 	}
970 	strcpy(nv_name, name_ptr);
971 
972 #if defined(BCMSDIO) && defined(GET_OTP_MODULE_NAME)
973 	if (strlen(dhd->conf->module_name)) {
974 		strcpy(name_ptr, "nvram_");
975 		strcat(name_ptr, dhd->conf->module_name);
976 		strcat(name_ptr, ".txt");
977 #ifdef COMPAT_OLD_MODULE
978 		if (dhd->conf->chip == BCM4359_CHIP_ID) {
979 			struct file *fp;
980 			// compatible for AP6398S and AP6398SA
981 			fp = filp_open(nv_path, O_RDONLY, 0);
982 			if (IS_ERR(fp)) {
983 				strcpy(name_ptr, nv_name);
984 			} else {
985 				filp_close((struct file *)fp, NULL);
986 			}
987 		}
988 #endif
989 	}
990 #endif
991 
992 #if defined(BCMPCIE) && defined(UPDATE_MODULE_NAME)
993 	row_module = dhd_conf_match_module(dhd);
994 	if (row_module && strlen(row_module->module_name)) {
995 		strcpy(name_ptr, "nvram_");
996 		strcat(name_ptr, row_module->module_name);
997 		strcat(name_ptr, ".txt");
998 	}
999 #endif
1000 
1001 	for (i=0; i<dhd->conf->nv_by_chip.count; i++) {
1002 		if (chip==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chip &&
1003 				chiprev==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chiprev) {
1004 			strcpy(name_ptr, dhd->conf->nv_by_chip.m_chip_nv_path_head[i].name);
1005 			break;
1006 		}
1007 	}
1008 
1009 	CONFIG_TRACE("nvram_path=%s\n", nv_path);
1010 }
1011 
1012 void
dhd_conf_copy_path(dhd_pub_t * dhd,char * dst_name,char * dst_path,char * src_path)1013 dhd_conf_copy_path(dhd_pub_t *dhd, char *dst_name, char *dst_path, char *src_path)
1014 {
1015 	int i;
1016 
1017 	if (src_path[0] == '\0') {
1018 		CONFIG_MSG("src_path is null\n");
1019 		return;
1020 	} else
1021 		strcpy(dst_path, src_path);
1022 
1023 	/* find out the last '/' */
1024 	i = strlen(dst_path);
1025 	while (i > 0) {
1026 		if (dst_path[i] == '/') {
1027 			i++;
1028 			break;
1029 		}
1030 		i--;
1031 	}
1032 	strcpy(&dst_path[i], dst_name);
1033 
1034 	CONFIG_TRACE("dst_path=%s\n", dst_path);
1035 }
1036 
1037 #ifdef CONFIG_PATH_AUTO_SELECT
1038 void
dhd_conf_set_conf_name_by_chip(dhd_pub_t * dhd,char * conf_path)1039 dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path)
1040 {
1041 #ifdef UPDATE_MODULE_NAME
1042 	const module_name_map_t* row_module = NULL;
1043 #endif
1044 	const chip_name_map_t* row_chip = NULL;
1045 	uint chip, chiprev;
1046 	char *name_ptr;
1047 	int i;
1048 
1049 	chip = dhd->conf->chip;
1050 	chiprev = dhd->conf->chiprev;
1051 
1052 	if (conf_path[0] == '\0') {
1053 		CONFIG_MSG("config path is null\n");
1054 		return;
1055 	}
1056 
1057 	/* find out the last '/' */
1058 	i = strlen(conf_path);
1059 	while (i > 0) {
1060 		if (conf_path[i] == '/') {
1061 			i++;
1062 			break;
1063 		}
1064 		i--;
1065 	}
1066 	name_ptr = &conf_path[i];
1067 
1068 	row_chip = dhd_conf_match_chip(dhd, DONT_CARE);
1069 	if (row_chip && strlen(row_chip->chip_name)) {
1070 		strcpy(name_ptr, "config_");
1071 		strcat(name_ptr, row_chip->chip_name);
1072 		strcat(name_ptr, ".txt");
1073 	}
1074 
1075 #ifdef UPDATE_MODULE_NAME
1076 	row_module = dhd_conf_match_module(dhd);
1077 	if (row_module && strlen(row_module->chip_name)) {
1078 		strcpy(name_ptr, "config_");
1079 		strcat(name_ptr, row_module->chip_name);
1080 		strcat(name_ptr, ".txt");
1081 	}
1082 #endif
1083 
1084 	CONFIG_TRACE("config_path=%s\n", conf_path);
1085 }
1086 #endif
1087 
1088 #ifdef TPUT_MONITOR
1089 void
dhd_conf_tput_monitor(dhd_pub_t * dhd)1090 dhd_conf_tput_monitor(dhd_pub_t *dhd)
1091 {
1092 	struct dhd_conf *conf = dhd->conf;
1093 
1094 	if (conf->tput_monitor_ms && conf->data_drop_mode >= FW_DROP) {
1095 		if (conf->tput_ts.tv_sec == 0 && conf->tput_ts.tv_nsec == 0) {
1096 			osl_do_gettimeofday(&conf->tput_ts);
1097 		} else {
1098 			struct osl_timespec cur_ts;
1099 			int32 tput_tx = 0, tput_rx = 0, tput_tx_kb = 0,
1100 				tput_rx_kb = 0, tput_net = 0, tput_net_kb = 0;
1101 			uint32 diff_ms;
1102 			unsigned long diff_bytes;
1103 			osl_do_gettimeofday(&cur_ts);
1104 			diff_ms = osl_do_gettimediff(&cur_ts, &conf->tput_ts)/1000;
1105 			if (diff_ms >= conf->tput_monitor_ms) {
1106 				diff_bytes = dhd->dstats.tx_bytes - conf->last_tx;
1107 				tput_tx = (int32)((diff_bytes/1024/1024)*8)*1000/diff_ms;
1108 				if (tput_tx == 0) {
1109 					tput_tx = (int32)(diff_bytes*8/1024/1024)*1000/diff_ms;
1110 					tput_tx_kb = (int32)(diff_bytes*8*1000/1024)/diff_ms;
1111 					tput_tx_kb = tput_tx_kb % 1000;
1112 				}
1113 				diff_bytes = dhd->dstats.rx_bytes - conf->last_rx;
1114 				tput_rx = (int32)((diff_bytes/1024/1024)*8)*1000/diff_ms;
1115 				if (tput_rx == 0) {
1116 					tput_rx = (int32)(diff_bytes*8/1024/1024)*1000/diff_ms;
1117 					tput_rx_kb = (int32)(diff_bytes*8*1000/1024)/diff_ms;
1118 					tput_rx_kb = tput_tx_kb % 1000;
1119 				}
1120 				diff_bytes = conf->net_len - conf->last_net_tx;
1121 				tput_net = (int32)((diff_bytes/1024/1024)*8)*1000/diff_ms;
1122 				if (tput_net == 0) {
1123 					tput_net = (int32)(diff_bytes*8/1024/1024)*1000/diff_ms;
1124 					tput_net_kb = (int32)(diff_bytes*8*1000/1024)/diff_ms;
1125 					tput_net_kb = tput_net_kb % 1000;
1126 				}
1127 				conf->last_tx = dhd->dstats.tx_bytes;
1128 				conf->last_rx = dhd->dstats.rx_bytes;
1129 				conf->last_net_tx = conf->net_len;
1130 				memcpy(&conf->tput_ts, &cur_ts, sizeof(struct osl_timespec));
1131 				CONFIG_TRACE("xmit=%3d.%d%d%d Mbps, tx=%3d.%d%d%d Mbps, rx=%3d.%d%d%d Mbps\n",
1132 					tput_net, (tput_net_kb/100)%10, (tput_net_kb/10)%10, (tput_net_kb)%10,
1133 					tput_tx, (tput_tx_kb/100)%10, (tput_tx_kb/10)%10, (tput_tx_kb)%10,
1134 					tput_rx, (tput_rx_kb/100)%10, (tput_rx_kb/10)%10, (tput_rx_kb)%10);
1135 			}
1136 		}
1137 	}
1138 }
1139 #endif
1140 
1141 #ifdef DHD_TPUT_PATCH
1142 void
dhd_conf_set_tput_patch(dhd_pub_t * dhd)1143 dhd_conf_set_tput_patch(dhd_pub_t *dhd)
1144 {
1145 	struct dhd_conf *conf = dhd->conf;
1146 
1147 	if (conf->tput_patch) {
1148 		conf->mtu = 1500;
1149 /* set pktsetsum false by default since this will cause to
1150   * the checksum is wrong of downloaded file
1151 */
1152 		conf->pktsetsum = FALSE;
1153 #ifdef BCMSDIO
1154 		conf->dhd_dpc_prio = 98;
1155 /* need to check if CPU can support multi-core first,
1156  * so don't enable it by default.
1157  */
1158 //		conf->dpc_cpucore = 2;
1159 //		conf->rxf_cpucore = 3;
1160 //		conf->disable_proptx = 1;
1161 		conf->frameburst = 1;
1162 #ifdef DYNAMIC_MAX_HDR_READ
1163 		conf->max_hdr_read = 256;
1164 		firstread = 256;
1165 #endif /* DYNAMIC_MAX_HDR_READ */
1166 		dhd_rxbound = 512;
1167 #endif /* BCMSDIO */
1168 #ifdef BCMPCIE
1169 #if defined(SET_XPS_CPUS)
1170 		conf->xps_cpus = TRUE;
1171 #endif /* SET_XPS_CPUS */
1172 #if defined(SET_RPS_CPUS)
1173 		conf->rps_cpus = TRUE;
1174 #endif /* SET_RPS_CPUS */
1175 		conf->orphan_move = 3;
1176 		conf->flow_ring_queue_threshold = 2048;
1177 #endif /* BCMPCIE */
1178 #ifdef DHDTCPACK_SUPPRESS
1179 		conf->tcpack_sup_ratio = 15;
1180 		conf->tcpack_sup_delay = 10;
1181 #endif /* DHDTCPACK_SUPPRESS */
1182 	}
1183 	else {
1184 		conf->mtu = 0;
1185 		conf->pktsetsum = FALSE;
1186 #ifdef BCMSDIO
1187 		conf->dhd_dpc_prio = -1;
1188 		conf->disable_proptx = -1;
1189 		conf->frameburst = 1;
1190 #ifdef DYNAMIC_MAX_HDR_READ
1191 		conf->max_hdr_read = 0;
1192 		firstread = 32;
1193 #endif /* DYNAMIC_MAX_HDR_READ */
1194 		dhd_rxbound = 128;
1195 #endif /* BCMSDIO */
1196 #ifdef BCMPCIE
1197 #if defined(SET_XPS_CPUS)
1198 		conf->xps_cpus = FALSE;
1199 #endif /* SET_XPS_CPUS */
1200 #if defined(SET_RPS_CPUS)
1201 		conf->rps_cpus = FALSE;
1202 #endif /* SET_RPS_CPUS */
1203 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
1204 		conf->orphan_move = 1;
1205 #else
1206 		conf->orphan_move = 0;
1207 #endif
1208 		conf->flow_ring_queue_threshold = 2048;
1209 #endif /* BCMPCIE */
1210 #ifdef DHDTCPACK_SUPPRESS
1211 		conf->tcpack_sup_ratio = CUSTOM_TCPACK_SUPP_RATIO;
1212 		conf->tcpack_sup_delay = CUSTOM_TCPACK_DELAY_TIME;
1213 #endif /* DHDTCPACK_SUPPRESS */
1214 	}
1215 }
1216 
1217 void
dhd_conf_dump_tput_patch(dhd_pub_t * dhd)1218 dhd_conf_dump_tput_patch(dhd_pub_t *dhd)
1219 {
1220 	struct dhd_conf *conf = dhd->conf;
1221 
1222 	CONFIG_TRACE("tput_patch=%d\n", conf->tput_patch);
1223 	CONFIG_TRACE("mtu=%d\n", conf->mtu);
1224 	CONFIG_TRACE("pktsetsum=%d\n", conf->pktsetsum);
1225 	CONFIG_TRACE("orphan_move=%d\n", conf->orphan_move);
1226 #ifdef DHDTCPACK_SUPPRESS
1227 	CONFIG_TRACE("tcpack_sup_ratio=%d\n", conf->tcpack_sup_ratio);
1228 	CONFIG_TRACE("tcpack_sup_delay=%d\n", conf->tcpack_sup_delay);
1229 #endif
1230 
1231 #ifdef BCMSDIO
1232 	CONFIG_TRACE("dhd_dpc_prio=%d\n", conf->dhd_dpc_prio);
1233 	CONFIG_TRACE("dhd_poll=%d\n", conf->dhd_poll);
1234 	CONFIG_TRACE("disable_proptx=%d\n", conf->disable_proptx);
1235 	CONFIG_TRACE("frameburst=%d\n", conf->frameburst);
1236 #ifdef DYNAMIC_MAX_HDR_READ
1237 	CONFIG_TRACE("max_hdr_read=%d\n", conf->max_hdr_read);
1238 	CONFIG_TRACE("firstread=%d\n", firstread);
1239 #endif
1240 	CONFIG_TRACE("dhd_rxbound=%d\n", dhd_rxbound);
1241 #endif
1242 
1243 #ifdef BCMPCIE
1244 	CONFIG_TRACE("flow_ring_queue_threshold=%d\n", conf->flow_ring_queue_threshold);
1245 #endif
1246 
1247 #if defined(SET_XPS_CPUS)
1248 	CONFIG_TRACE("xps_cpus=%d\n", conf->xps_cpus);
1249 #endif
1250 #if defined(SET_RPS_CPUS)
1251 	CONFIG_TRACE("rps_cpus=%d\n", conf->rps_cpus);
1252 #endif
1253 
1254 }
1255 #endif /* DHD_TPUT_PATCH */
1256 
1257 #ifdef DHD_LINUX_STD_FW_API
1258 #define FIRMWARE_CLASS_PATH "/sys/module/firmware_class/parameters/path"
1259 static int
dhd_conf_get_fw_path(char * path,int len)1260 dhd_conf_get_fw_path(char *path, int len)
1261 {
1262 	char *pch;
1263 	int err, path_len = 0;
1264 
1265 	err = dhd_read_file(FIRMWARE_CLASS_PATH, path, len);
1266 	if(err < 0){
1267 		CONFIG_ERROR("firmware path can not read %d\n", err);
1268 	} else {
1269 		pch = strchr(path, '\n');
1270 		if (pch)
1271 			*pch = '\0';
1272 		CONFIG_TRACE("path = %s\n", path);
1273 		path_len = strlen(path);
1274 	}
1275 
1276 	return path_len;
1277 }
1278 
1279 static void
dhd_conf_get_filename(char * pFilename)1280 dhd_conf_get_filename(char *pFilename)
1281 {
1282 	const char *pName = NULL;
1283 
1284 	if ((pFilename) && (*pFilename)) {
1285 		// back/reverse search the '/'
1286 		pName = strrchr(pFilename, '/');
1287 		if (NULL == pName) {
1288 			pName = pFilename;
1289 		} else {
1290 			if (pName[1]) {
1291 				pName++;
1292 			} else {
1293 				pName = NULL;
1294 			}
1295 		}
1296 	}
1297 
1298 	if (pName)
1299 		strcpy(pFilename, pName);
1300 	return;
1301 }
1302 #endif /* DHD_LINUX_STD_FW_API */
1303 
1304 void
dhd_conf_set_path_params(dhd_pub_t * dhd,char * fw_path,char * nv_path)1305 dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path)
1306 {
1307 	int ag_type;
1308 #ifdef DHD_LINUX_STD_FW_API
1309 	char path[WLC_IOCTL_SMLEN];
1310 	int path_len;
1311 #endif
1312 
1313 	/* External conf takes precedence if specified */
1314 	dhd_conf_preinit(dhd);
1315 
1316 #ifdef DHD_LINUX_STD_FW_API
1317 	// preprocess the filename to only left 'name'
1318 	dhd_conf_get_filename(fw_path);
1319 	dhd_conf_get_filename(nv_path);
1320 	dhd_conf_get_filename(dhd->clm_path);
1321 	dhd_conf_get_filename(dhd->conf_path);
1322 #endif
1323 
1324 	if (dhd->conf_path[0] == '\0') {
1325 		dhd_conf_copy_path(dhd, "config.txt", dhd->conf_path, nv_path);
1326 	}
1327 	if (dhd->clm_path[0] == '\0') {
1328 		dhd_conf_copy_path(dhd, "clm.blob", dhd->clm_path, fw_path);
1329 	}
1330 #ifdef CONFIG_PATH_AUTO_SELECT
1331 	dhd_conf_set_conf_name_by_chip(dhd, dhd->conf_path);
1332 #endif
1333 
1334 	ag_type = dhd_conf_set_fw_name_by_chip(dhd, fw_path);
1335 	dhd_conf_set_nv_name_by_chip(dhd, nv_path, ag_type);
1336 	dhd_conf_set_clm_name_by_chip(dhd, dhd->clm_path, ag_type);
1337 #ifdef SET_FWNV_BY_MAC
1338 	dhd_conf_set_fw_name_by_mac(dhd, fw_path);
1339 	dhd_conf_set_nv_name_by_mac(dhd, nv_path);
1340 #endif
1341 
1342 #ifdef DHD_LINUX_STD_FW_API
1343 	memset(path, 0, sizeof(path));
1344 	path_len = dhd_conf_get_fw_path(path, sizeof(path));
1345 	snprintf(path+path_len, WLC_IOCTL_SMLEN, "%s", fw_path);
1346 	CONFIG_MSG("Final fw_path=%s\n", path);
1347 	snprintf(path+path_len, WLC_IOCTL_SMLEN, "%s", nv_path);
1348 	CONFIG_MSG("Final nv_path=%s\n", path);
1349 	snprintf(path+path_len, WLC_IOCTL_SMLEN, "%s", dhd->clm_path);
1350 	CONFIG_MSG("Final clm_path=%s\n", path);
1351 	snprintf(path+path_len, WLC_IOCTL_SMLEN, "%s", dhd->conf_path);
1352 	CONFIG_MSG("Final conf_path=%s\n", path);
1353 #else
1354 	CONFIG_MSG("Final fw_path=%s\n", fw_path);
1355 	CONFIG_MSG("Final nv_path=%s\n", nv_path);
1356 	CONFIG_MSG("Final clm_path=%s\n", dhd->clm_path);
1357 	CONFIG_MSG("Final conf_path=%s\n", dhd->conf_path);
1358 #endif
1359 
1360 	dhd_conf_read_config(dhd, dhd->conf_path);
1361 #ifdef DHD_TPUT_PATCH
1362 	dhd_conf_dump_tput_patch(dhd);
1363 #endif
1364 }
1365 
1366 int
dhd_conf_set_intiovar(dhd_pub_t * dhd,int ifidx,uint cmd,char * name,int val,int def,bool down)1367 dhd_conf_set_intiovar(dhd_pub_t *dhd, int ifidx, uint cmd, char *name, int val,
1368 	int def, bool down)
1369 {
1370 	int ret = -1;
1371 	char iovbuf[WL_EVENTING_MASK_LEN + 12];	/*  Room for "event_msgs" + '\0' + bitvec  */
1372 
1373 	if (val >= def) {
1374 		if (down) {
1375 			if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0)) < 0)
1376 				CONFIG_ERROR("WLC_DOWN setting failed %d\n", ret);
1377 		}
1378 		if (cmd == WLC_SET_VAR) {
1379 			CONFIG_TRACE("set %s %d\n", name, val);
1380 			bcm_mkiovar(name, (char *)&val, sizeof(val), iovbuf, sizeof(iovbuf));
1381 			if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
1382 				CONFIG_ERROR("%s setting failed %d\n", name, ret);
1383 		} else {
1384 			CONFIG_TRACE("set %s %d %d\n", name, cmd, val);
1385 			if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, &val, sizeof(val), TRUE, 0)) < 0)
1386 				CONFIG_ERROR("%s setting failed %d\n", name, ret);
1387 		}
1388 	}
1389 
1390 	return ret;
1391 }
1392 
1393 static int
dhd_conf_set_bufiovar(dhd_pub_t * dhd,int ifidx,uint cmd,char * name,char * buf,int len,bool down)1394 dhd_conf_set_bufiovar(dhd_pub_t *dhd, int ifidx, uint cmd, char *name,
1395 	char *buf, int len, bool down)
1396 {
1397 	char iovbuf[WLC_IOCTL_SMLEN];
1398 	s32 iovar_len;
1399 	int ret = -1;
1400 
1401 	if (down) {
1402 		if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, ifidx)) < 0)
1403 			CONFIG_ERROR("WLC_DOWN setting failed %d\n", ret);
1404 	}
1405 
1406 	if (cmd == WLC_SET_VAR) {
1407 		iovar_len = bcm_mkiovar(name, buf, len, iovbuf, sizeof(iovbuf));
1408 		if (iovar_len > 0)
1409 			ret = dhd_wl_ioctl_cmd(dhd, cmd, iovbuf, iovar_len, TRUE, ifidx);
1410 		else
1411 			ret = BCME_BUFTOOSHORT;
1412 		if (ret < 0)
1413 			CONFIG_ERROR("%s setting failed %d, len=%d\n", name, ret, len);
1414 	} else {
1415 		if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, buf, len, TRUE, ifidx)) < 0)
1416 			CONFIG_ERROR("%s setting failed %d\n", name, ret);
1417 	}
1418 
1419 	return ret;
1420 }
1421 
1422 static int
dhd_conf_iovar_buf(dhd_pub_t * dhd,int ifidx,int cmd,char * name,char * buf,int len)1423 dhd_conf_iovar_buf(dhd_pub_t *dhd, int ifidx, int cmd, char *name,
1424 	char *buf, int len)
1425 {
1426 	char *iovbuf = NULL;
1427 	int ret = -1, iovbuf_len = WLC_IOCTL_MEDLEN;
1428 	s32 iovar_len;
1429 
1430 	iovbuf = kmalloc(iovbuf_len, GFP_KERNEL);
1431 	if (iovbuf == NULL) {
1432 		CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", iovbuf_len);
1433 		goto exit;
1434 	}
1435 
1436 	if (cmd == WLC_GET_VAR) {
1437 		if (bcm_mkiovar(name, buf, len, iovbuf, iovbuf_len)) {
1438 			ret = dhd_wl_ioctl_cmd(dhd, cmd, iovbuf, iovbuf_len, FALSE, ifidx);
1439 			if (!ret) {
1440 				memcpy(buf, iovbuf, len);
1441 			} else {
1442 				CONFIG_ERROR("get iovar %s failed %d\n", name, ret);
1443 			}
1444 		} else {
1445 			CONFIG_ERROR("mkiovar %s failed\n", name);
1446 		}
1447 	} else if (cmd == WLC_SET_VAR) {
1448 		iovar_len = bcm_mkiovar(name, buf, len, iovbuf, iovbuf_len);
1449 		if (iovar_len > 0)
1450 			ret = dhd_wl_ioctl_cmd(dhd, cmd, iovbuf, iovar_len, TRUE, ifidx);
1451 		else
1452 			ret = BCME_BUFTOOSHORT;
1453 		if (ret < 0)
1454 			CONFIG_ERROR("%s setting failed %d, len=%d\n", name, ret, len);
1455 	}
1456 
1457 exit:
1458 	if (iovbuf)
1459 		kfree(iovbuf);
1460 	return ret;
1461 }
1462 
1463 static int
dhd_conf_get_iovar(dhd_pub_t * dhd,int ifidx,int cmd,char * name,char * buf,int len)1464 dhd_conf_get_iovar(dhd_pub_t *dhd, int ifidx, int cmd, char *name,
1465 	char *buf, int len)
1466 {
1467 	char iovbuf[WLC_IOCTL_SMLEN];
1468 	int ret = -1;
1469 
1470 	if (cmd == WLC_GET_VAR) {
1471 		if (bcm_mkiovar(name, NULL, 0, iovbuf, sizeof(iovbuf))) {
1472 			ret = dhd_wl_ioctl_cmd(dhd, cmd, iovbuf, sizeof(iovbuf), FALSE, ifidx);
1473 			if (!ret) {
1474 				memcpy(buf, iovbuf, len);
1475 			} else {
1476 				CONFIG_ERROR("get iovar %s failed %d\n", name, ret);
1477 			}
1478 		} else {
1479 			CONFIG_ERROR("mkiovar %s failed\n", name);
1480 		}
1481 	} else {
1482 		ret = dhd_wl_ioctl_cmd(dhd, cmd, buf, len, FALSE, 0);
1483 		if (ret < 0)
1484 			CONFIG_ERROR("get iovar %s failed %d\n", name, ret);
1485 	}
1486 
1487 	return ret;
1488 }
1489 
1490 static int
dhd_conf_rsdb_mode(dhd_pub_t * dhd,char * cmd,char * buf)1491 dhd_conf_rsdb_mode(dhd_pub_t *dhd, char *cmd, char *buf)
1492 {
1493 	wl_config_t rsdb_mode_cfg = {1, 0};
1494 
1495 	if (buf) {
1496 		rsdb_mode_cfg.config = (int)simple_strtol(buf, NULL, 0);
1497 		CONFIG_MSG("rsdb_mode %d\n", rsdb_mode_cfg.config);
1498 		dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, cmd, (char *)&rsdb_mode_cfg,
1499 			sizeof(rsdb_mode_cfg), TRUE);
1500 	}
1501 
1502 	return 0;
1503 }
1504 
1505 int
dhd_conf_reg2args(dhd_pub_t * dhd,char * cmd,bool set,uint32 index,uint32 * val)1506 dhd_conf_reg2args(dhd_pub_t *dhd, char *cmd, bool set, uint32 index, uint32 *val)
1507 {
1508 	char var[WLC_IOCTL_SMLEN];
1509 	uint32 int_val, len;
1510 	void *ptr = NULL;
1511 	int ret = 0;
1512 
1513 	len = sizeof(int_val);
1514 	int_val = htod32(index);
1515 	memset(var, 0, sizeof(var));
1516 	memcpy(var, (char *)&int_val, sizeof(int_val));
1517 
1518 	if (set) {
1519 		int_val = htod32(*val);
1520 		memcpy(&var[len], (char *)&int_val, sizeof(int_val));
1521 		len += sizeof(int_val);
1522 		dhd_conf_iovar_buf(dhd, 0, WLC_SET_VAR, cmd, var, sizeof(var));
1523 	} else {
1524 		ret = dhd_conf_iovar_buf(dhd, 0, WLC_GET_VAR, cmd, var, sizeof(var));
1525 		if (ret < 0)
1526 			return ret;
1527 		ptr = var;
1528 		*val = dtoh32(*(int *)ptr);
1529 	}
1530 
1531 	return ret;
1532 }
1533 
1534 static int
dhd_conf_btc_params(dhd_pub_t * dhd,char * cmd,char * buf)1535 dhd_conf_btc_params(dhd_pub_t *dhd, char *cmd, char *buf)
1536 {
1537 	int ret = BCME_OK;
1538 	uint32 cur_val;
1539 	int index = 0, mask = 0, value = 0;
1540 	// btc_params=[index] [mask] [value]
1541 	// Ex: btc_params=82 0x0021 0x0001
1542 
1543 	if (buf) {
1544 		sscanf(buf, "%d %x %x", &index, &mask, &value);
1545 	}
1546 
1547 	CONFIG_TRACE("%s%d mask=0x%04x value=0x%04x\n", cmd, index, mask, value);
1548 
1549 	ret = dhd_conf_reg2args(dhd, cmd, FALSE, index, &cur_val);
1550 	CONFIG_TRACE("%s%d = 0x%04x\n", cmd, index, cur_val);
1551 	cur_val &= (~mask);
1552 	cur_val |= value;
1553 
1554 	// need to WLC_UP before btc_params
1555 	dhd_conf_set_intiovar(dhd, 0, WLC_UP, "WLC_UP", 0, 0, FALSE);
1556 
1557 	CONFIG_TRACE("wl %s%d 0x%04x\n", cmd, index, cur_val);
1558 	ret = dhd_conf_reg2args(dhd, cmd, TRUE, index, &cur_val);
1559 
1560 	ret = dhd_conf_reg2args(dhd, cmd, FALSE, index, &cur_val);
1561 	CONFIG_MSG("%s%d = 0x%04x\n", cmd, index, cur_val);
1562 
1563 	return ret;
1564 }
1565 
1566 typedef struct sub_cmd_t {
1567 	char *name;
1568 	uint16 id;		/* id for the dongle f/w switch/case  */
1569 	uint16 type;		/* base type of argument IOVT_XXXX */
1570 } sub_cmd_t;
1571 
1572 /* wl he sub cmd list */
1573 static const sub_cmd_t he_cmd_list[] = {
1574 	{"enab", WL_HE_CMD_ENAB, IOVT_UINT8},
1575 	{"features", WL_HE_CMD_FEATURES, IOVT_UINT32},
1576 	{"bsscolor", WL_HE_CMD_BSSCOLOR, IOVT_UINT8},
1577 	{"partialbsscolor", WL_HE_CMD_PARTIAL_BSSCOLOR, IOVT_UINT8},
1578 	{"cap", WL_HE_CMD_CAP, IOVT_UINT8},
1579 	{"staid", WL_HE_CMD_STAID, IOVT_UINT16},
1580 	{"rtsdurthresh", WL_HE_CMD_RTSDURTHRESH, IOVT_UINT16},
1581 	{"peduration", WL_HE_CMD_PEDURATION, IOVT_UINT8},
1582 	{"testbed_mode", WL_HE_CMD_TESTBED_MODE, IOVT_UINT32},
1583 	{"omi_ulmu_throttle", WL_HE_CMD_OMI_ULMU_THROTTLE, IOVT_UINT16},
1584 	{"omi_dlmu_rr_mpf_map", WL_HE_CMD_OMI_DLMU_RSD_RCM_MPF_MAP, IOVT_UINT32},
1585 	{"ulmu_disable_policy", WL_HE_CMD_ULMU_DISABLE_POLICY, IOVT_UINT8},
1586 	{"sr_prohibit", WL_HE_CMD_SR_PROHIBIT, IOVT_UINT8},
1587 };
1588 
1589 static uint
wl_he_iovt2len(uint iovt)1590 wl_he_iovt2len(uint iovt)
1591 {
1592 	switch (iovt) {
1593 	case IOVT_BOOL:
1594 	case IOVT_INT8:
1595 	case IOVT_UINT8:
1596 		return sizeof(uint8);
1597 	case IOVT_INT16:
1598 	case IOVT_UINT16:
1599 		return sizeof(uint16);
1600 	case IOVT_INT32:
1601 	case IOVT_UINT32:
1602 		return sizeof(uint32);
1603 	default:
1604 		/* ASSERT(0); */
1605 		return 0;
1606 	}
1607 }
1608 
1609 static int
dhd_conf_he_cmd(dhd_pub_t * dhd,char * cmd,char * buf)1610 dhd_conf_he_cmd(dhd_pub_t * dhd, char *cmd, char *buf)
1611 {
1612 	int ret = BCME_OK, i;
1613 	bcm_xtlv_t *pxtlv = NULL;
1614 	uint8 mybuf[128];
1615 	uint16 he_id = -1, he_len = 0, mybuf_len = sizeof(mybuf);
1616 	uint32 he_val;
1617 	const sub_cmd_t *tpl = he_cmd_list;
1618 	char sub_cmd[32], he_val_str[10];
1619 
1620 	if (buf) {
1621 		sscanf(buf, "%s %s", sub_cmd, he_val_str);
1622 	}
1623 
1624 	for (i=0; i<ARRAY_SIZE(he_cmd_list); i++, tpl++) {
1625 		if (!strcmp(tpl->name, sub_cmd)) {
1626 			he_id = tpl->id;
1627 			he_len = wl_he_iovt2len(tpl->type);
1628 			break;
1629 		}
1630 	}
1631 	if (he_id < 0) {
1632 		CONFIG_ERROR("No he id found for %s\n", sub_cmd);
1633 		return 0;
1634 	}
1635 
1636 	pxtlv = (bcm_xtlv_t *)mybuf;
1637 
1638 	if (strlen(he_val_str)) {
1639 		he_val = simple_strtol(he_val_str, NULL, 0);
1640 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &mybuf_len, he_id,
1641 			he_len, (uint8 *)&he_val, BCM_XTLV_OPTION_ALIGN32);
1642 		if (ret != BCME_OK) {
1643 			CONFIG_ERROR("failed to pack he enab, err: %s\n", bcmerrorstr(ret));
1644 			return 0;
1645 		}
1646 		CONFIG_TRACE("he %s 0x%x\n", sub_cmd, he_val);
1647 		dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, cmd, (char *)&mybuf,
1648 			sizeof(mybuf), TRUE);
1649 	}
1650 
1651 	return 0;
1652 }
1653 
1654 #ifndef SUPPORT_RANDOM_MAC_SCAN
1655 int
dhd_conf_scan_mac(dhd_pub_t * dhd,char * cmd,char * buf)1656 dhd_conf_scan_mac(dhd_pub_t * dhd, char *cmd, char *buf)
1657 {
1658 	uint8 buffer[WLC_IOCTL_SMLEN] = {0, };
1659 	wl_scanmac_t *sm = NULL;
1660 	wl_scanmac_enable_t *sm_enable = NULL;
1661 	int enable = 0, len = 0, ret = -1;
1662 	char sub_cmd[32], iovbuf[WLC_IOCTL_SMLEN];
1663 	s32 iovar_len;
1664 
1665 	memset(sub_cmd, 0, sizeof(sub_cmd));
1666 	if (buf) {
1667 		sscanf(buf, "%s %d", sub_cmd, &enable);
1668 	}
1669 
1670 	if (!strcmp(sub_cmd, "enable")) {
1671 		sm = (wl_scanmac_t *)buffer;
1672 		sm_enable = (wl_scanmac_enable_t *)sm->data;
1673 		sm->len = sizeof(*sm_enable);
1674 		sm_enable->enable = enable;
1675 		len = OFFSETOF(wl_scanmac_t, data) + sm->len;
1676 		sm->subcmd_id = WL_SCANMAC_SUBCMD_ENABLE;
1677 		CONFIG_TRACE("scanmac enable %d\n", sm_enable->enable);
1678 
1679 		iovar_len = bcm_mkiovar("scanmac", buffer, len, iovbuf, sizeof(iovbuf));
1680 		if (iovar_len > 0)
1681 			ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iovar_len, TRUE, 0);
1682 		else
1683 			ret = BCME_BUFTOOSHORT;
1684 		if (ret == BCME_UNSUPPORTED)
1685 			CONFIG_TRACE("scanmac, UNSUPPORTED\n");
1686 		else if (ret != BCME_OK)
1687 			CONFIG_ERROR("%s setting failed %d, len=%d\n", "scanmac", ret, len);
1688 	}
1689 	else {
1690 		CONFIG_ERROR("wrong cmd \"%s %d\"\n", sub_cmd, enable);
1691 	}
1692 
1693 	return 0;
1694 }
1695 #endif
1696 
1697 typedef int (tpl_parse_t)(dhd_pub_t *dhd, char *name, char *buf);
1698 
1699 typedef struct iovar_tpl_t {
1700 	int cmd;
1701 	char *name;
1702 	tpl_parse_t *parse;
1703 } iovar_tpl_t;
1704 
1705 const iovar_tpl_t iovar_tpl_list[] = {
1706 	{WLC_SET_VAR,	"rsdb_mode",	dhd_conf_rsdb_mode},
1707 	{WLC_SET_VAR,	"he",		dhd_conf_he_cmd},
1708 	{WLC_SET_VAR,	"btc_params",	dhd_conf_btc_params},
1709 #ifndef SUPPORT_RANDOM_MAC_SCAN
1710 	{WLC_SET_VAR,	"scanmac",		dhd_conf_scan_mac},
1711 #endif
1712 };
1713 
iovar_tpl_parse(const iovar_tpl_t * tpl,int tpl_count,dhd_pub_t * dhd,int cmd,char * name,char * buf)1714 static int iovar_tpl_parse(const iovar_tpl_t *tpl, int tpl_count,
1715 	dhd_pub_t *dhd, int cmd, char *name, char *buf)
1716 {
1717 	int i, ret = 0;
1718 
1719 	/* look for a matching code in the table */
1720 	for (i = 0; i < tpl_count; i++, tpl++) {
1721 		if (tpl->cmd == cmd && !strcmp(tpl->name, name))
1722 			break;
1723 	}
1724 	if (i < tpl_count && tpl->parse) {
1725 		ret = tpl->parse(dhd, name, buf);
1726 	} else {
1727 		ret = -1;
1728 	}
1729 
1730 	return ret;
1731 }
1732 
1733 static bool
dhd_conf_set_wl_cmd(dhd_pub_t * dhd,char * data,bool down)1734 dhd_conf_set_wl_cmd(dhd_pub_t *dhd, char *data, bool down)
1735 {
1736 	int cmd, val, ret = 0, len;
1737 	char name[32], *pch, *pick_tmp, *pick_tmp2, *pdata = NULL;
1738 
1739 	/* Process wl_preinit:
1740 	 * wl_preinit=[cmd]=[val], [cmd]=[val]
1741 	 * Ex: wl_preinit=86=0, mpc=0
1742 	 */
1743 
1744 	if (data == NULL)
1745 		return FALSE;
1746 
1747 	len = strlen(data);
1748 	pdata = kmalloc(len+1, GFP_KERNEL);
1749 	if (pdata == NULL) {
1750 		CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", len+1);
1751 		goto exit;
1752 	}
1753 	memset(pdata, 0, len+1);
1754 	strcpy(pdata, data);
1755 
1756 	pick_tmp = pdata;
1757 	while (pick_tmp && (pick_tmp2 = bcmstrtok(&pick_tmp, ",", 0)) != NULL) {
1758 		char *pEnd;
1759 		pch = bcmstrtok(&pick_tmp2, "=", 0);
1760 		if (!pch)
1761 			break;
1762 		if (*pch == ' ') {
1763 			pch++;
1764 		}
1765 		memset(name, 0 , sizeof (name));
1766 		cmd = bcm_strtoul(pch, &pEnd, 0);
1767 		if (cmd == 0 || strlen(pEnd)) {
1768 			cmd = WLC_SET_VAR;
1769 			strcpy(name, pch);
1770 		}
1771 		pch = bcmstrtok(&pick_tmp2, ",", 0);
1772 		if (!pch) {
1773 			break;
1774 		}
1775 		ret = iovar_tpl_parse(iovar_tpl_list, ARRAY_SIZE(iovar_tpl_list),
1776 			dhd, cmd, name, pch);
1777 		if (ret) {
1778 			val = (int)simple_strtol(pch, NULL, 0);
1779 			dhd_conf_set_intiovar(dhd, 0, cmd, name, val, -1, down);
1780 		}
1781 	}
1782 
1783 exit:
1784 	if (pdata)
1785 		kfree(pdata);
1786 	return true;
1787 }
1788 
1789 int
dhd_conf_get_band(dhd_pub_t * dhd)1790 dhd_conf_get_band(dhd_pub_t *dhd)
1791 {
1792 	int band = -1;
1793 
1794 	if (dhd && dhd->conf)
1795 		band = dhd->conf->band;
1796 	else
1797 		CONFIG_ERROR("dhd or conf is NULL\n");
1798 
1799 	return band;
1800 }
1801 
1802 int
dhd_conf_get_country(dhd_pub_t * dhd,wl_country_t * cspec)1803 dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec)
1804 {
1805 	int bcmerror = -1;
1806 
1807 	memset(cspec, 0, sizeof(wl_country_t));
1808 	bcm_mkiovar("country", NULL, 0, (char*)cspec, sizeof(wl_country_t));
1809 	if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cspec, sizeof(wl_country_t),
1810 			FALSE, 0)) < 0)
1811 		CONFIG_ERROR("country code getting failed %d\n", bcmerror);
1812 
1813 	return bcmerror;
1814 }
1815 
1816 int
dhd_conf_map_country_list(dhd_pub_t * dhd,wl_country_t * cspec)1817 dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec)
1818 {
1819 	int bcmerror = -1;
1820 	struct dhd_conf *conf = dhd->conf;
1821 	country_list_t *country = conf->country_head;
1822 
1823 #ifdef CCODE_LIST
1824 	bcmerror = dhd_ccode_map_country_list(dhd, cspec);
1825 #endif
1826 	// **:XZ/11 => return XZ/11 if not found
1827 	// **:**/0 => return user specified ccode if not found, but set regrev 0
1828 	while (country != NULL) {
1829 		if (!strncmp("**", country->cspec.country_abbrev, 2)) {
1830 			if (!strncmp("**", country->cspec.ccode, 2)) {
1831 				cspec->rev = 0;
1832 				bcmerror = 0;
1833 				break;
1834 			}
1835 			memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ);
1836 			cspec->rev = country->cspec.rev;
1837 			bcmerror = 0;
1838 			break;
1839 		} else if (!strncmp(cspec->country_abbrev,
1840 				country->cspec.country_abbrev, 2)) {
1841 			memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ);
1842 			cspec->rev = country->cspec.rev;
1843 			bcmerror = 0;
1844 			break;
1845 		}
1846 		country = country->next;
1847 	}
1848 
1849 	if (!bcmerror)
1850 		CONFIG_MSG("%s/%d\n", cspec->ccode, cspec->rev);
1851 
1852 	return bcmerror;
1853 }
1854 
1855 int
dhd_conf_set_country(dhd_pub_t * dhd,wl_country_t * cspec)1856 dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec)
1857 {
1858 	int bcmerror = -1;
1859 
1860 	memset(&dhd->dhd_cspec, 0, sizeof(wl_country_t));
1861 
1862 	CONFIG_MSG("set country %s, revision %d\n", cspec->ccode, cspec->rev);
1863 	bcmerror = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "country", (char *)cspec,
1864 		sizeof(wl_country_t), FALSE);
1865 	dhd_conf_get_country(dhd, cspec);
1866 	CONFIG_MSG("Country code: %s (%s/%d)\n",
1867 		cspec->country_abbrev, cspec->ccode, cspec->rev);
1868 
1869 	return bcmerror;
1870 }
1871 
1872 int
dhd_conf_fix_country(dhd_pub_t * dhd)1873 dhd_conf_fix_country(dhd_pub_t *dhd)
1874 {
1875 	int bcmerror = -1;
1876 	int band;
1877 	wl_uint32_list_t *list;
1878 	u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
1879 	wl_country_t cspec;
1880 
1881 	if (!(dhd && dhd->conf)) {
1882 		return bcmerror;
1883 	}
1884 
1885 	memset(valid_chan_list, 0, sizeof(valid_chan_list));
1886 	list = (wl_uint32_list_t *)(void *) valid_chan_list;
1887 	list->count = htod32(WL_NUMCHANNELS);
1888 	if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, valid_chan_list,
1889 			sizeof(valid_chan_list), FALSE, 0)) < 0) {
1890 		CONFIG_ERROR("get channels failed with %d\n", bcmerror);
1891 	}
1892 
1893 	band = dhd_conf_get_band(dhd);
1894 
1895 	if (bcmerror || ((band==WLC_BAND_AUTO || band==WLC_BAND_2G || band==-1) &&
1896 			dtoh32(list->count)<11)) {
1897 		CONFIG_ERROR("bcmerror=%d, # of channels %d\n",
1898 			bcmerror, dtoh32(list->count));
1899 		dhd_conf_map_country_list(dhd, &dhd->conf->cspec);
1900 		if ((bcmerror = dhd_conf_set_country(dhd, &dhd->conf->cspec)) < 0) {
1901 			strcpy(cspec.country_abbrev, "US");
1902 			cspec.rev = 0;
1903 			strcpy(cspec.ccode, "US");
1904 			dhd_conf_map_country_list(dhd, &cspec);
1905 			dhd_conf_set_country(dhd, &cspec);
1906 		}
1907 	}
1908 
1909 	return bcmerror;
1910 }
1911 
1912 bool
dhd_conf_match_channel(dhd_pub_t * dhd,uint32 channel)1913 dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel)
1914 {
1915 	int i;
1916 	bool match = false;
1917 
1918 	if (dhd && dhd->conf) {
1919 		if (dhd->conf->channels.count == 0)
1920 			return true;
1921 		for (i=0; i<dhd->conf->channels.count; i++) {
1922 			if (channel == dhd->conf->channels.channel[i])
1923 				match = true;
1924 		}
1925 	} else {
1926 		match = true;
1927 		CONFIG_ERROR("dhd or conf is NULL\n");
1928 	}
1929 
1930 	return match;
1931 }
1932 
1933 int
dhd_conf_set_roam(dhd_pub_t * dhd)1934 dhd_conf_set_roam(dhd_pub_t *dhd)
1935 {
1936 	int bcmerror = -1;
1937 	struct dhd_conf *conf = dhd->conf;
1938 	uint wnm_bsstrans_resp = 0;
1939 
1940 	if (dhd->conf->chip == BCM4359_CHIP_ID) {
1941 		dhd_conf_get_iovar(dhd, 0, WLC_GET_VAR, "wnm_bsstrans_resp",
1942 			(char *)&wnm_bsstrans_resp, sizeof(wnm_bsstrans_resp));
1943 		if (wnm_bsstrans_resp == WL_BSSTRANS_POLICY_PRODUCT) {
1944 			dhd->wbtext_policy = WL_BSSTRANS_POLICY_ROAM_ALWAYS;
1945 			dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "wnm_bsstrans_resp",
1946 				WL_BSSTRANS_POLICY_ROAM_ALWAYS, 0, FALSE);
1947 		}
1948 	}
1949 
1950 	dhd_roam_disable = conf->roam_off;
1951 	dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "roam_off", dhd->conf->roam_off, 0, FALSE);
1952 
1953 	if (!conf->roam_off || !conf->roam_off_suspend) {
1954 		CONFIG_MSG("set roam_trigger %d\n", conf->roam_trigger[0]);
1955 		dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_TRIGGER, "WLC_SET_ROAM_TRIGGER",
1956 			(char *)conf->roam_trigger, sizeof(conf->roam_trigger), FALSE);
1957 
1958 		CONFIG_MSG("set roam_scan_period %d\n", conf->roam_scan_period[0]);
1959 		dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_SCAN_PERIOD, "WLC_SET_ROAM_SCAN_PERIOD",
1960 			(char *)conf->roam_scan_period, sizeof(conf->roam_scan_period), FALSE);
1961 
1962 		CONFIG_MSG("set roam_delta %d\n", conf->roam_delta[0]);
1963 		dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_DELTA, "WLC_SET_ROAM_DELTA",
1964 			(char *)conf->roam_delta, sizeof(conf->roam_delta), FALSE);
1965 
1966 		dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "fullroamperiod",
1967 			dhd->conf->fullroamperiod, 1, FALSE);
1968 	}
1969 
1970 	return bcmerror;
1971 }
1972 
1973 void
dhd_conf_add_to_eventbuffer(struct eventmsg_buf * ev,u16 event,bool set)1974 dhd_conf_add_to_eventbuffer(struct eventmsg_buf *ev, u16 event, bool set)
1975 {
1976 	if (!ev || (event > WLC_E_LAST))
1977 		return;
1978 
1979 	if (ev->num < MAX_EVENT_BUF_NUM) {
1980 		ev->event[ev->num].type = event;
1981 		ev->event[ev->num].set = set;
1982 		ev->num++;
1983 	} else {
1984 		CONFIG_ERROR("evenbuffer doesn't support > %u events. Update"
1985 			" the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM);
1986 		ASSERT(0);
1987 	}
1988 }
1989 
1990 s32
dhd_conf_apply_eventbuffer(dhd_pub_t * dhd,eventmsg_buf_t * ev)1991 dhd_conf_apply_eventbuffer(dhd_pub_t *dhd, eventmsg_buf_t *ev)
1992 {
1993 	char eventmask[WL_EVENTING_MASK_LEN];
1994 	int i, ret = 0;
1995 
1996 	if (!ev || (!ev->num))
1997 		return -EINVAL;
1998 
1999 	/* Read event_msgs mask */
2000 	ret = dhd_conf_get_iovar(dhd, 0, WLC_GET_VAR, "event_msgs", eventmask,
2001 		sizeof(eventmask));
2002 	if (unlikely(ret)) {
2003 		CONFIG_ERROR("Get event_msgs error (%d)\n", ret);
2004 		goto exit;
2005 	}
2006 
2007 	/* apply the set bits */
2008 	for (i = 0; i < ev->num; i++) {
2009 		if (ev->event[i].set)
2010 			setbit(eventmask, ev->event[i].type);
2011 		else
2012 			clrbit(eventmask, ev->event[i].type);
2013 	}
2014 
2015 	/* Write updated Event mask */
2016 	ret = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "event_msgs", eventmask,
2017 		sizeof(eventmask), FALSE);
2018 	if (unlikely(ret)) {
2019 		CONFIG_ERROR("Set event_msgs error (%d)\n", ret);
2020 	}
2021 
2022 exit:
2023 	return ret;
2024 }
2025 
2026 static int
dhd_conf_enable_roam_offload(dhd_pub_t * dhd,int enable)2027 dhd_conf_enable_roam_offload(dhd_pub_t *dhd, int enable)
2028 {
2029 	int err;
2030 	eventmsg_buf_t ev_buf;
2031 
2032 	if (dhd->conf->roam_off_suspend)
2033 		return 0;
2034 
2035 	err = dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "roam_offload", enable, 0, FALSE);
2036 	if (err)
2037 		return err;
2038 
2039 	bzero(&ev_buf, sizeof(eventmsg_buf_t));
2040 	dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_PSK_SUP, !enable);
2041 	dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_REQ_IE, !enable);
2042 	dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_RESP_IE, !enable);
2043 	dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable);
2044 	dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable);
2045 	dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable);
2046 	err = dhd_conf_apply_eventbuffer(dhd, &ev_buf);
2047 
2048 	CONFIG_TRACE("roam_offload %d\n", enable);
2049 
2050 	return err;
2051 }
2052 
2053 void
dhd_conf_set_bw_cap(dhd_pub_t * dhd)2054 dhd_conf_set_bw_cap(dhd_pub_t *dhd)
2055 {
2056 	struct {
2057 		u32 band;
2058 		u32 bw_cap;
2059 	} param = {0, 0};
2060 
2061 	if (dhd->conf->bw_cap[0] >= 0) {
2062 		memset(&param, 0, sizeof(param));
2063 		param.band = WLC_BAND_2G;
2064 		param.bw_cap = (uint)dhd->conf->bw_cap[0];
2065 		CONFIG_MSG("set bw_cap 2g 0x%x\n", param.bw_cap);
2066 		dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "bw_cap", (char *)&param,
2067 			sizeof(param), TRUE);
2068 	}
2069 
2070 	if (dhd->conf->bw_cap[1] >= 0) {
2071 		memset(&param, 0, sizeof(param));
2072 		param.band = WLC_BAND_5G;
2073 		param.bw_cap = (uint)dhd->conf->bw_cap[1];
2074 		CONFIG_MSG("set bw_cap 5g 0x%x\n", param.bw_cap);
2075 		dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "bw_cap", (char *)&param,
2076 			sizeof(param), TRUE);
2077 	}
2078 }
2079 
2080 void
dhd_conf_get_wme(dhd_pub_t * dhd,int ifidx,int mode,edcf_acparam_t * acp)2081 dhd_conf_get_wme(dhd_pub_t *dhd, int ifidx, int mode, edcf_acparam_t *acp)
2082 {
2083 	int bcmerror = -1;
2084 	char iovbuf[WLC_IOCTL_SMLEN];
2085 	edcf_acparam_t *acparam;
2086 
2087 	bzero(iovbuf, sizeof(iovbuf));
2088 
2089 	/*
2090 	 * Get current acparams, using buf as an input buffer.
2091 	 * Return data is array of 4 ACs of wme params.
2092 	 */
2093 	if (mode == 0)
2094 		bcm_mkiovar("wme_ac_sta", NULL, 0, iovbuf, sizeof(iovbuf));
2095 	else
2096 		bcm_mkiovar("wme_ac_ap", NULL, 0, iovbuf, sizeof(iovbuf));
2097 	if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf),
2098 			FALSE, ifidx)) < 0) {
2099 		CONFIG_ERROR("wme_ac_sta getting failed %d\n", bcmerror);
2100 		return;
2101 	}
2102 	memcpy((char*)acp, iovbuf, sizeof(edcf_acparam_t)*AC_COUNT);
2103 
2104 	acparam = &acp[AC_BK];
2105 	CONFIG_TRACE("BK: aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n",
2106 		acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK,
2107 		acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT,
2108 		acparam->TXOP);
2109 	acparam = &acp[AC_BE];
2110 	CONFIG_TRACE("BE: aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n",
2111 		acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK,
2112 		acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT,
2113 		acparam->TXOP);
2114 	acparam = &acp[AC_VI];
2115 	CONFIG_TRACE("VI: aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n",
2116 		acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK,
2117 		acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT,
2118 		acparam->TXOP);
2119 	acparam = &acp[AC_VO];
2120 	CONFIG_TRACE("VO: aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n",
2121 		acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK,
2122 		acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT,
2123 		acparam->TXOP);
2124 
2125 	return;
2126 }
2127 
2128 void
dhd_conf_update_wme(dhd_pub_t * dhd,int ifidx,int mode,edcf_acparam_t * acparam_cur,int aci)2129 dhd_conf_update_wme(dhd_pub_t *dhd, int ifidx, int mode,
2130 	edcf_acparam_t *acparam_cur, int aci)
2131 {
2132 	int aifsn, ecwmin, ecwmax, txop;
2133 	edcf_acparam_t *acp;
2134 	struct dhd_conf *conf = dhd->conf;
2135 	wme_param_t *wme;
2136 
2137 	if (mode == 0)
2138 		wme = &conf->wme_sta;
2139 	else
2140 		wme = &conf->wme_ap;
2141 
2142 	/* Default value */
2143 	aifsn = acparam_cur->ACI&EDCF_AIFSN_MASK;
2144 	ecwmin = acparam_cur->ECW&EDCF_ECWMIN_MASK;
2145 	ecwmax = (acparam_cur->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT;
2146 	txop = acparam_cur->TXOP;
2147 
2148 	/* Modified value */
2149 	if (wme->aifsn[aci] > 0)
2150 		aifsn = wme->aifsn[aci];
2151 	if (wme->ecwmin[aci] > 0)
2152 		ecwmin = wme->ecwmin[aci];
2153 	if (wme->ecwmax[aci] > 0)
2154 		ecwmax = wme->ecwmax[aci];
2155 	if (wme->txop[aci] > 0)
2156 		txop = wme->txop[aci];
2157 
2158 	if (!(wme->aifsn[aci] || wme->ecwmin[aci] ||
2159 			wme->ecwmax[aci] || wme->txop[aci]))
2160 		return;
2161 
2162 	/* Update */
2163 	acp = acparam_cur;
2164 	acp->ACI = (acp->ACI & ~EDCF_AIFSN_MASK) | (aifsn & EDCF_AIFSN_MASK);
2165 	acp->ECW = ((ecwmax << EDCF_ECWMAX_SHIFT) & EDCF_ECWMAX_MASK) | (acp->ECW & EDCF_ECWMIN_MASK);
2166 	acp->ECW = ((acp->ECW & EDCF_ECWMAX_MASK) | (ecwmin & EDCF_ECWMIN_MASK));
2167 	acp->TXOP = txop;
2168 
2169 	CONFIG_MSG("wme_ac %s aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n",
2170 		mode?"ap":"sta", acp->ACI, acp->ACI&EDCF_AIFSN_MASK,
2171 		acp->ECW&EDCF_ECWMIN_MASK, (acp->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT,
2172 		acp->TXOP);
2173 
2174 	/*
2175 	* Now use buf as an output buffer.
2176 	* Put WME acparams after "wme_ac\0" in buf.
2177 	* NOTE: only one of the four ACs can be set at a time.
2178 	*/
2179 	if (mode == 0)
2180 		dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_VAR, "wme_ac_sta", (char *)acp,
2181 			sizeof(edcf_acparam_t), FALSE);
2182 	else
2183 		dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_VAR, "wme_ac_ap", (char *)acp,
2184 			sizeof(edcf_acparam_t), FALSE);
2185 
2186 }
2187 
2188 void
dhd_conf_set_wme(dhd_pub_t * dhd,int ifidx,int mode)2189 dhd_conf_set_wme(dhd_pub_t *dhd, int ifidx, int mode)
2190 {
2191 	edcf_acparam_t acparam_cur[AC_COUNT];
2192 
2193 	if (dhd && dhd->conf) {
2194 		if (!dhd->conf->force_wme_ac) {
2195 			CONFIG_TRACE("force_wme_ac is not enabled %d\n",
2196 				dhd->conf->force_wme_ac);
2197 			return;
2198 		}
2199 
2200 		CONFIG_TRACE("Before change:\n");
2201 		dhd_conf_get_wme(dhd, ifidx, mode, acparam_cur);
2202 
2203 		dhd_conf_update_wme(dhd, ifidx, mode, &acparam_cur[AC_BK], AC_BK);
2204 		dhd_conf_update_wme(dhd, ifidx, mode, &acparam_cur[AC_BE], AC_BE);
2205 		dhd_conf_update_wme(dhd, ifidx, mode, &acparam_cur[AC_VI], AC_VI);
2206 		dhd_conf_update_wme(dhd, ifidx, mode, &acparam_cur[AC_VO], AC_VO);
2207 
2208 		CONFIG_TRACE("After change:\n");
2209 		dhd_conf_get_wme(dhd, ifidx, mode, acparam_cur);
2210 	} else {
2211 		CONFIG_ERROR("dhd or conf is NULL\n");
2212 	}
2213 
2214 	return;
2215 }
2216 
2217 void
dhd_conf_set_mchan_bw(dhd_pub_t * dhd,int p2p_mode,int miracast_mode)2218 dhd_conf_set_mchan_bw(dhd_pub_t *dhd, int p2p_mode, int miracast_mode)
2219 {
2220 	struct dhd_conf *conf = dhd->conf;
2221 	mchan_params_t *mchan = conf->mchan;
2222 	bool set = true;
2223 
2224 	while (mchan != NULL) {
2225 		set = true;
2226 		set &= (mchan->bw >= 0);
2227 		set &= ((mchan->p2p_mode == -1) | (mchan->p2p_mode == p2p_mode));
2228 		set &= ((mchan->miracast_mode == -1) | (mchan->miracast_mode == miracast_mode));
2229 		if (set) {
2230 			dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "mchan_bw", mchan->bw, 0, FALSE);
2231 		}
2232 		mchan = mchan->next;
2233 	}
2234 
2235 	return;
2236 }
2237 
2238 #ifdef PKT_FILTER_SUPPORT
2239 void
dhd_conf_add_pkt_filter(dhd_pub_t * dhd)2240 dhd_conf_add_pkt_filter(dhd_pub_t *dhd)
2241 {
2242 	int i, j;
2243 	char str[16];
2244 #define MACS "%02x%02x%02x%02x%02x%02x"
2245 
2246 	/*  0) suspend_mode=1
2247 	 * Case 0: default is unicast pkt and event wake up
2248 	 * Case 1: no connection in suspend
2249 	 *   1) wl_suspend=3=0
2250 	 *   2) wl_resume=2=0
2251 	 *   3) insuspend=0x7
2252 	 * Case 2: keep connection in suspend, but no pkt and event wake up
2253 	 *   1) dhd_master_mode=1
2254 	 *   2) pkt_filter_delete=100, 102, 103, 104, 105, 106, 107
2255 	 *   3) pkt_filter_add=141 0 0 0 0xFFFFFFFFFFFF 0x000000000000
2256 	 *   4) insuspend=0x7
2257 	 *   5) rekey_offload=1
2258 	 * Case 3: magic pkt and event wake up
2259 	 *   1) dhd_master_mode=1
2260 	 *   2) pkt_filter_delete=100, 102, 103, 104, 105, 106, 107
2261 	 *   3) pkt_filter_add=141 0 0 0 0xFFFFFFFFFFFF 0x000000000000
2262 	 *   4) magic_pkt_filter_add=141 0 1 12
2263 	 *   5) rekey_offload=1
2264 	 */
2265 	for(i=0; i<dhd->conf->pkt_filter_add.count; i++) {
2266 		dhd->pktfilter[i+dhd->pktfilter_count] = dhd->conf->pkt_filter_add.filter[i];
2267 		CONFIG_MSG("%s\n", dhd->pktfilter[i+dhd->pktfilter_count]);
2268 	}
2269 	dhd->pktfilter_count += i;
2270 
2271 	if (dhd->conf->magic_pkt_filter_add) {
2272 		strcat(dhd->conf->magic_pkt_filter_add, " 0x");
2273 		strcat(dhd->conf->magic_pkt_filter_add, "FFFFFFFFFFFF");
2274 		for (j=0; j<16; j++)
2275 			strcat(dhd->conf->magic_pkt_filter_add, "FFFFFFFFFFFF");
2276 		strcat(dhd->conf->magic_pkt_filter_add, " 0x");
2277 		strcat(dhd->conf->magic_pkt_filter_add, "FFFFFFFFFFFF");
2278 		sprintf(str, MACS, MAC2STRDBG(dhd->mac.octet));
2279 		for (j=0; j<16; j++)
2280 			strncat(dhd->conf->magic_pkt_filter_add, str, 12);
2281 		dhd->pktfilter[dhd->pktfilter_count] = dhd->conf->magic_pkt_filter_add;
2282 		dhd->pktfilter_count += 1;
2283 	}
2284 }
2285 
2286 bool
dhd_conf_del_pkt_filter(dhd_pub_t * dhd,uint32 id)2287 dhd_conf_del_pkt_filter(dhd_pub_t *dhd, uint32 id)
2288 {
2289 	int i;
2290 
2291 	if (dhd && dhd->conf) {
2292 		for (i=0; i<dhd->conf->pkt_filter_del.count; i++) {
2293 			if (id == dhd->conf->pkt_filter_del.id[i]) {
2294 				CONFIG_MSG("%d\n", dhd->conf->pkt_filter_del.id[i]);
2295 				return true;
2296 			}
2297 		}
2298 		return false;
2299 	}
2300 	return false;
2301 }
2302 
2303 void
dhd_conf_discard_pkt_filter(dhd_pub_t * dhd)2304 dhd_conf_discard_pkt_filter(dhd_pub_t *dhd)
2305 {
2306 	dhd->pktfilter_count = 6;
2307 	dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = NULL;
2308 	dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF";
2309 	dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = "102 0 0 0 0xFFFFFF 0x01005E";
2310 	dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = "103 0 0 0 0xFFFF 0x3333";
2311 	dhd->pktfilter[DHD_MDNS_FILTER_NUM] = NULL;
2312 	/* Do not enable ARP to pkt filter if dhd_master_mode is false.*/
2313 	dhd->pktfilter[DHD_ARP_FILTER_NUM] = NULL;
2314 
2315 	/* IPv4 broadcast address XXX.XXX.XXX.255 */
2316 	dhd->pktfilter[dhd->pktfilter_count] = "110 0 0 12 0xFFFF00000000000000000000000000000000000000FF 0x080000000000000000000000000000000000000000FF";
2317 	dhd->pktfilter_count++;
2318 	/* discard IPv4 multicast address 224.0.0.0/4 */
2319 	dhd->pktfilter[dhd->pktfilter_count] = "111 0 0 12 0xFFFF00000000000000000000000000000000F0 0x080000000000000000000000000000000000E0";
2320 	dhd->pktfilter_count++;
2321 	/* discard IPv6 multicast address FF00::/8 */
2322 	dhd->pktfilter[dhd->pktfilter_count] = "112 0 0 12 0xFFFF000000000000000000000000000000000000000000000000FF 0x86DD000000000000000000000000000000000000000000000000FF";
2323 	dhd->pktfilter_count++;
2324 	/* discard Netbios pkt */
2325 	dhd->pktfilter[dhd->pktfilter_count] = "121 0 0 12 0xFFFF000000000000000000FF000000000000000000000000FFFF 0x0800000000000000000000110000000000000000000000000089";
2326 	dhd->pktfilter_count++;
2327 
2328 }
2329 #endif /* PKT_FILTER_SUPPORT */
2330 
2331 int
dhd_conf_get_pm(dhd_pub_t * dhd)2332 dhd_conf_get_pm(dhd_pub_t *dhd)
2333 {
2334 	if (dhd && dhd->conf) {
2335 		return dhd->conf->pm;
2336 	}
2337 	return -1;
2338 }
2339 
2340 int
dhd_conf_check_hostsleep(dhd_pub_t * dhd,int cmd,void * buf,int len,int * hostsleep_set,int * hostsleep_val,int * ret)2341 dhd_conf_check_hostsleep(dhd_pub_t *dhd, int cmd, void *buf, int len,
2342 	int *hostsleep_set, int *hostsleep_val, int *ret)
2343 {
2344 	if (dhd->conf->insuspend & (NO_TXCTL_IN_SUSPEND | WOWL_IN_SUSPEND)) {
2345 		if (cmd == WLC_SET_VAR) {
2346 			char *psleep = NULL;
2347 			psleep = strstr(buf, "hostsleep");
2348 			if (psleep) {
2349 				*hostsleep_set = 1;
2350 				memcpy(hostsleep_val, psleep+strlen("hostsleep")+1, sizeof(int));
2351 			}
2352 		}
2353 		if (dhd->hostsleep && (!*hostsleep_set || *hostsleep_val)) {
2354 			CONFIG_TRACE("block all none hostsleep clr cmd\n");
2355 			*ret = BCME_EPERM;
2356 			goto exit;
2357 		} else if (*hostsleep_set && *hostsleep_val) {
2358 			CONFIG_TRACE("hostsleep %d => %d\n", dhd->hostsleep, *hostsleep_val);
2359 			dhd->hostsleep = *hostsleep_val;
2360 			if (dhd->conf->insuspend & NO_TXDATA_IN_SUSPEND) {
2361 				dhd_txflowcontrol(dhd, ALL_INTERFACES, ON);
2362 			}
2363 			if (dhd->hostsleep == 2) {
2364 				*ret = 0;
2365 				goto exit;
2366 			}
2367 		} else if (dhd->hostsleep == 2 && !*hostsleep_val) {
2368 			CONFIG_TRACE("hostsleep %d => %d\n", dhd->hostsleep, *hostsleep_val);
2369 			dhd->hostsleep = *hostsleep_val;
2370 			if (dhd->conf->insuspend & NO_TXDATA_IN_SUSPEND) {
2371 				dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
2372 			}
2373 			*ret = 0;
2374 			goto exit;
2375 		}
2376 	}
2377 #ifdef NO_POWER_SAVE
2378 	if (cmd == WLC_SET_PM) {
2379 		if (*(const u32*)buf != 0) {
2380 			CONFIG_TRACE("skip PM\n");
2381 			*ret = BCME_OK;
2382 			goto exit;
2383 		}
2384 	} else if (cmd == WLC_SET_VAR) {
2385 		int cmd_len = strlen("mpc");
2386 		if (!strncmp(buf, "mpc", cmd_len)) {
2387 			if (*((u32 *)((u8*)buf+cmd_len+1)) != 0) {
2388 				CONFIG_TRACE("skip mpc\n");
2389 				*ret = BCME_OK;
2390 				goto exit;
2391 			}
2392 		}
2393 	}
2394 #endif
2395 
2396 	return 0;
2397 exit:
2398 	return -1;
2399 }
2400 
2401 void
dhd_conf_get_hostsleep(dhd_pub_t * dhd,int hostsleep_set,int hostsleep_val,int ret)2402 dhd_conf_get_hostsleep(dhd_pub_t *dhd,
2403 	int hostsleep_set, int hostsleep_val, int ret)
2404 {
2405 	if (dhd->conf->insuspend & (NO_TXCTL_IN_SUSPEND | WOWL_IN_SUSPEND)) {
2406 		if (hostsleep_set) {
2407 			if (hostsleep_val && ret) {
2408 				CONFIG_TRACE("reset hostsleep %d => 0\n", dhd->hostsleep);
2409 				dhd->hostsleep = 0;
2410 				if (dhd->conf->insuspend & NO_TXDATA_IN_SUSPEND) {
2411 					dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
2412 				}
2413 			} else if (!hostsleep_val && !ret) {
2414 				CONFIG_TRACE("set hostsleep %d => 0\n", dhd->hostsleep);
2415 				dhd->hostsleep = 0;
2416 				if (dhd->conf->insuspend & NO_TXDATA_IN_SUSPEND) {
2417 					dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
2418 				}
2419 			}
2420 		}
2421 	}
2422 }
2423 
2424 #ifdef WL_EXT_WOWL
2425 #define WL_WOWL_TCPFIN	(1 << 26)
2426 typedef struct wl_wowl_pattern2 {
2427 	char cmd[4];
2428 	wl_wowl_pattern_t wowl_pattern;
2429 } wl_wowl_pattern2_t;
2430 static int
dhd_conf_wowl_pattern(dhd_pub_t * dhd,int ifidx,bool add,char * data)2431 dhd_conf_wowl_pattern(dhd_pub_t *dhd, int ifidx, bool add, char *data)
2432 {
2433 	uint buf_len = 0;
2434 	int	id, type, polarity, offset;
2435 	char cmd[4]="\0", mask[128]="\0", pattern[128]="\0", mask_tmp[128]="\0", *pmask_tmp;
2436 	uint32 masksize, patternsize, pad_len = 0;
2437 	wl_wowl_pattern2_t *wowl_pattern2 = NULL;
2438 	char *mask_and_pattern;
2439 	int ret = 0, i, j, v;
2440 
2441 	if (data) {
2442 		if (add)
2443 			strcpy(cmd, "add");
2444 		else
2445 			strcpy(cmd, "clr");
2446 		if (!strcmp(cmd, "clr")) {
2447 			CONFIG_TRACE("wowl_pattern clr\n");
2448 			ret = dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_VAR, "wowl_pattern", cmd,
2449 				sizeof(cmd), FALSE);
2450 			goto exit;
2451 		}
2452 		sscanf(data, "%d %d %d %d %s %s", &id, &type, &polarity, &offset,
2453 			mask_tmp, pattern);
2454 		masksize = strlen(mask_tmp) -2;
2455 		CONFIG_TRACE("0 mask_tmp=%s, masksize=%d\n", mask_tmp, masksize);
2456 
2457 		// add pading
2458 		if (masksize % 16)
2459 			pad_len = (16 - masksize % 16);
2460 		for (i=0; i<pad_len; i++)
2461 			strcat(mask_tmp, "0");
2462 		masksize += pad_len;
2463 		CONFIG_TRACE("1 mask_tmp=%s, masksize=%d\n", mask_tmp, masksize);
2464 
2465 		// translate 0x00 to 0, others to 1
2466 		j = 0;
2467 		pmask_tmp = &mask_tmp[2];
2468 		for (i=0; i<masksize/2; i++) {
2469 			if(strncmp(&pmask_tmp[i*2], "00", 2))
2470 				pmask_tmp[j] = '1';
2471 			else
2472 				pmask_tmp[j] = '0';
2473 			j++;
2474 		}
2475 		pmask_tmp[j] = '\0';
2476 		masksize = masksize / 2;
2477 		CONFIG_TRACE("2 mask_tmp=%s, masksize=%d\n", mask_tmp, masksize);
2478 
2479 		// reorder per 8bits
2480 		pmask_tmp = &mask_tmp[2];
2481 		for (i=0; i<masksize/8; i++) {
2482 			char c;
2483 			for (j=0; j<4; j++) {
2484 				c = pmask_tmp[i*8+j];
2485 				pmask_tmp[i*8+j] = pmask_tmp[(i+1)*8-j-1];
2486 				pmask_tmp[(i+1)*8-j-1] = c;
2487 			}
2488 		}
2489 		CONFIG_TRACE("3 mask_tmp=%s, masksize=%d\n", mask_tmp, masksize);
2490 
2491 		// translate 8bits to 1byte
2492 		j = 0; v = 0;
2493 		pmask_tmp = &mask_tmp[2];
2494 		strcpy(mask, "0x");
2495 		for (i=0; i<masksize; i++) {
2496 			v = (v<<1) | (pmask_tmp[i]=='1');
2497 			if (((i+1)%4) == 0) {
2498 				if (v < 10)
2499 					mask[j+2] = v + '0';
2500 				else
2501 					mask[j+2] = (v-10) + 'a';
2502 				j++;
2503 				v = 0;
2504 			}
2505 		}
2506 		mask[j+2] = '\0';
2507 		masksize = j/2;
2508 		CONFIG_TRACE("4 mask=%s, masksize=%d\n", mask, masksize);
2509 
2510 		patternsize = (strlen(pattern)-2)/2;
2511 		buf_len = sizeof(wl_wowl_pattern2_t) + patternsize + masksize;
2512 		wowl_pattern2 = kmalloc(buf_len, GFP_KERNEL);
2513 		if (wowl_pattern2 == NULL) {
2514 			CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", buf_len);
2515 			goto exit;
2516 		}
2517 		memset(wowl_pattern2, 0, sizeof(wl_wowl_pattern2_t));
2518 
2519 		strncpy(wowl_pattern2->cmd, cmd, sizeof(cmd));
2520 		wowl_pattern2->wowl_pattern.id = id;
2521 		wowl_pattern2->wowl_pattern.type = 0;
2522 		wowl_pattern2->wowl_pattern.offset = offset;
2523 		mask_and_pattern = (char*)wowl_pattern2 + sizeof(wl_wowl_pattern2_t);
2524 
2525 		wowl_pattern2->wowl_pattern.masksize = masksize;
2526 		ret = wl_pattern_atoh(mask, mask_and_pattern);
2527 		if (ret == -1) {
2528 			CONFIG_ERROR("rejecting mask=%s\n", mask);
2529 			goto exit;
2530 		}
2531 
2532 		mask_and_pattern += wowl_pattern2->wowl_pattern.masksize;
2533 		wowl_pattern2->wowl_pattern.patternoffset = sizeof(wl_wowl_pattern_t) +
2534 			wowl_pattern2->wowl_pattern.masksize;
2535 
2536 		wowl_pattern2->wowl_pattern.patternsize = patternsize;
2537 		ret = wl_pattern_atoh(pattern, mask_and_pattern);
2538 		if (ret == -1) {
2539 			CONFIG_ERROR("rejecting pattern=%s\n", pattern);
2540 			goto exit;
2541 		}
2542 
2543 		CONFIG_TRACE("%s %d %s %s\n", cmd, offset, mask, pattern);
2544 
2545 		ret = dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_VAR, "wowl_pattern",
2546 			(char *)wowl_pattern2, buf_len, FALSE);
2547 	}
2548 
2549 exit:
2550 	if (wowl_pattern2)
2551 		kfree(wowl_pattern2);
2552 	return ret;
2553 }
2554 
2555 static int
dhd_conf_wowl_wakeind(dhd_pub_t * dhd,int ifidx,bool clear)2556 dhd_conf_wowl_wakeind(dhd_pub_t *dhd, int ifidx, bool clear)
2557 {
2558 	s8 iovar_buf[WLC_IOCTL_SMLEN];
2559 	wl_wowl_wakeind_t *wake = NULL;
2560 	int ret = -1;
2561 	char clr[6]="clear", wakeind_str[32]="\0";
2562 
2563 	if (clear) {
2564 		CONFIG_TRACE("wowl_wakeind clear\n");
2565 		ret = dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_VAR, "wowl_wakeind",
2566 			clr, sizeof(clr), 0);
2567 	} else {
2568 		ret = dhd_conf_get_iovar(dhd, ifidx, WLC_GET_VAR, "wowl_wakeind",
2569 			iovar_buf, sizeof(iovar_buf));
2570 		if (!ret) {
2571 			wake = (wl_wowl_wakeind_t *) iovar_buf;
2572 			if (wake->ucode_wakeind & WL_WOWL_MAGIC)
2573 				strcpy(wakeind_str, "(MAGIC packet)");
2574 			if (wake->ucode_wakeind & WL_WOWL_NET)
2575 				strcpy(wakeind_str, "(Netpattern)");
2576 			if (wake->ucode_wakeind & WL_WOWL_DIS)
2577 				strcpy(wakeind_str, "(Disassoc/Deauth)");
2578 			if (wake->ucode_wakeind & WL_WOWL_BCN)
2579 				strcpy(wakeind_str, "(Loss of beacon)");
2580 			if (wake->ucode_wakeind & WL_WOWL_TCPKEEP_TIME)
2581 				strcpy(wakeind_str, "(TCPKA timeout)");
2582 			if (wake->ucode_wakeind & WL_WOWL_TCPKEEP_DATA)
2583 				strcpy(wakeind_str, "(TCPKA data)");
2584 			if (wake->ucode_wakeind & WL_WOWL_TCPFIN)
2585 				strcpy(wakeind_str, "(TCP FIN)");
2586 			CONFIG_MSG("wakeind=0x%x %s\n", wake->ucode_wakeind, wakeind_str);
2587 		}
2588 	}
2589 
2590 	return ret;
2591 }
2592 #endif
2593 
2594 int
dhd_conf_mkeep_alive(dhd_pub_t * dhd,int ifidx,int id,int period,char * packet,bool bcast)2595 dhd_conf_mkeep_alive(dhd_pub_t *dhd, int ifidx, int id, int period,
2596 	char *packet, bool bcast)
2597 {
2598 	wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
2599 	int ret = 0, len_bytes=0, buf_len=0;
2600 	char *buf = NULL, *iovar_buf = NULL;
2601 	uint8 *pdata;
2602 
2603 	CONFIG_TRACE("id=%d, period=%d, packet=%s\n", id, period, packet);
2604 	if (period >= 0) {
2605 		buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
2606 		if (buf == NULL) {
2607 			CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN);
2608 			goto exit;
2609 		}
2610 		iovar_buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
2611 		if (iovar_buf == NULL) {
2612 			CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN);
2613 			goto exit;
2614 		}
2615 		mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *)buf;
2616 		mkeep_alive_pktp->version = htod16(WL_MKEEP_ALIVE_VERSION);
2617 		mkeep_alive_pktp->length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
2618 		mkeep_alive_pktp->keep_alive_id = id;
2619 		buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
2620 		mkeep_alive_pktp->period_msec = period;
2621 		if (packet && strlen(packet)) {
2622 			len_bytes = wl_pattern_atoh(packet, (char *)mkeep_alive_pktp->data);
2623 			buf_len += len_bytes;
2624 			if (bcast) {
2625 				memcpy(mkeep_alive_pktp->data, &ether_bcast, ETHER_ADDR_LEN);
2626 			}
2627 			ret = dhd_conf_get_iovar(dhd, ifidx, WLC_GET_VAR, "cur_etheraddr",
2628 				iovar_buf, WLC_IOCTL_SMLEN);
2629 			if (!ret) {
2630 				pdata = mkeep_alive_pktp->data;
2631 				memcpy(pdata+6, iovar_buf, ETHER_ADDR_LEN);
2632 			}
2633 		}
2634 		mkeep_alive_pktp->len_bytes = htod16(len_bytes);
2635 		ret = dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_VAR, "mkeep_alive",
2636 			buf, buf_len, FALSE);
2637 	}
2638 
2639 exit:
2640 	if (buf)
2641 		kfree(buf);
2642 	if (iovar_buf)
2643 		kfree(iovar_buf);
2644 	return ret;
2645 }
2646 
2647 #ifdef ARP_OFFLOAD_SUPPORT
2648 void
dhd_conf_set_garp(dhd_pub_t * dhd,int ifidx,uint32 ipa,bool enable)2649 dhd_conf_set_garp(dhd_pub_t *dhd, int ifidx, uint32 ipa, bool enable)
2650 {
2651 	int i, len = 0, total_len = WLC_IOCTL_SMLEN;
2652 	char *iovar_buf = NULL, *packet = NULL;
2653 
2654 	if (!dhd->conf->garp || ifidx != 0 || !(dhd->op_mode & DHD_FLAG_STA_MODE))
2655 		return;
2656 
2657 	CONFIG_TRACE("enable=%d\n", enable);
2658 
2659 	if (enable) {
2660 		iovar_buf = kmalloc(total_len, GFP_KERNEL);
2661 		if (iovar_buf == NULL) {
2662 			CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", total_len);
2663 			goto exit;
2664 		}
2665 		packet = kmalloc(total_len, GFP_KERNEL);
2666 		if (packet == NULL) {
2667 			CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", total_len);
2668 			goto exit;
2669 		}
2670 		dhd_conf_get_iovar(dhd, ifidx, WLC_GET_VAR, "cur_etheraddr", iovar_buf, total_len);
2671 
2672 		len += snprintf(packet+len, total_len, "0xffffffffffff");
2673 		for (i=0; i<ETHER_ADDR_LEN; i++)
2674 			len += snprintf(packet+len, total_len, "%02x", iovar_buf[i]);
2675 		len += snprintf(packet+len, total_len, "08060001080006040001");
2676 		 // Sender Hardware Addr.
2677 		for (i=0; i<ETHER_ADDR_LEN; i++)
2678 			len += snprintf(packet+len, total_len, "%02x", iovar_buf[i]);
2679 		 // Sender IP Addr.
2680 		len += snprintf(packet+len, total_len, "%02x%02x%02x%02x",
2681 			ipa&0xff, (ipa>>8)&0xff, (ipa>>16)&0xff, (ipa>>24)&0xff);
2682 		 // Target Hardware Addr.
2683 		len += snprintf(packet+len, total_len, "ffffffffffff");
2684 		 // Target IP Addr.
2685 		len += snprintf(packet+len, total_len, "%02x%02x%02x%02x",
2686 			ipa&0xff, (ipa>>8)&0xff, (ipa>>16)&0xff, (ipa>>24)&0xff);
2687 		len += snprintf(packet+len, total_len, "000000000000000000000000000000000000");
2688 	}
2689 
2690 	dhd_conf_mkeep_alive(dhd, ifidx, 0, dhd->conf->keep_alive_period, packet, TRUE);
2691 
2692 exit:
2693 	if (iovar_buf)
2694 		kfree(iovar_buf);
2695 	if (packet)
2696 		kfree(packet);
2697 	return;
2698 }
2699 #endif
2700 
2701 uint
dhd_conf_get_insuspend(dhd_pub_t * dhd,uint mask)2702 dhd_conf_get_insuspend(dhd_pub_t *dhd, uint mask)
2703 {
2704 	uint insuspend = 0;
2705 
2706 	if (dhd->op_mode & DHD_FLAG_STA_MODE) {
2707 		insuspend = dhd->conf->insuspend &
2708 			(NO_EVENT_IN_SUSPEND | NO_TXDATA_IN_SUSPEND | NO_TXCTL_IN_SUSPEND |
2709 			ROAM_OFFLOAD_IN_SUSPEND | WOWL_IN_SUSPEND);
2710 	} else if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
2711 		insuspend = dhd->conf->insuspend &
2712 			(NO_EVENT_IN_SUSPEND | NO_TXDATA_IN_SUSPEND | NO_TXCTL_IN_SUSPEND |
2713 			AP_DOWN_IN_SUSPEND | AP_FILTER_IN_SUSPEND);
2714 	}
2715 
2716 	return (insuspend & mask);
2717 }
2718 
2719 static void
dhd_conf_check_connection(dhd_pub_t * dhd,int ifidx,int suspend)2720 dhd_conf_check_connection(dhd_pub_t *dhd, int ifidx, int suspend)
2721 {
2722 	struct dhd_conf *conf = dhd->conf;
2723 	struct ether_addr bssid;
2724 	wl_event_msg_t msg;
2725 	int pm;
2726 #ifdef WL_CFG80211
2727 	struct net_device *net;
2728 	unsigned long flags = 0;
2729 #endif /* defined(WL_CFG80211) */
2730 
2731 	if (suspend) {
2732 		memset(&bssid, 0, ETHER_ADDR_LEN);
2733 		dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, FALSE, ifidx);
2734 		if (memcmp(&ether_null, &bssid, ETHER_ADDR_LEN))
2735 			memcpy(&conf->bssid_insuspend, &bssid, ETHER_ADDR_LEN);
2736 		else
2737 			memset(&conf->bssid_insuspend, 0, ETHER_ADDR_LEN);
2738 	}
2739 	else {
2740 		if (memcmp(&ether_null, &conf->bssid_insuspend, ETHER_ADDR_LEN)) {
2741 			memset(&bssid, 0, ETHER_ADDR_LEN);
2742 			dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, FALSE, ifidx);
2743 			if (memcmp(&ether_null, &bssid, ETHER_ADDR_LEN)) {
2744 				dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_PM, "WLC_SET_PM", 0, 0, FALSE);
2745 				dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_VAR, "send_nulldata",
2746 					(char *)&bssid, ETHER_ADDR_LEN, FALSE);
2747 				OSL_SLEEP(100);
2748 				if (conf->pm >= 0)
2749 					pm = conf->pm;
2750 				else
2751 					pm = PM_FAST;
2752 				dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_PM, "WLC_SET_PM", pm, 0, FALSE);
2753 			} else {
2754 				CONFIG_TRACE("send WLC_E_DEAUTH_IND event\n");
2755 				bzero(&msg, sizeof(wl_event_msg_t));
2756 				msg.ifidx = ifidx;
2757 				memcpy(&msg.addr, &conf->bssid_insuspend, ETHER_ADDR_LEN);
2758 				msg.event_type = hton32(WLC_E_DEAUTH_IND);
2759 				msg.status = 0;
2760 				msg.reason = hton32(DOT11_RC_DEAUTH_LEAVING);
2761 #ifdef WL_EVENT
2762 				wl_ext_event_send(dhd->event_params, &msg, NULL);
2763 #endif
2764 #ifdef WL_CFG80211
2765 				spin_lock_irqsave(&dhd->up_lock, flags);
2766 				net = dhd_idx2net(dhd, ifidx);
2767 				if (net && dhd->up) {
2768 					wl_cfg80211_event(net, &msg, NULL);
2769 				}
2770 				spin_unlock_irqrestore(&dhd->up_lock, flags);
2771 #endif /* defined(WL_CFG80211) */
2772 			}
2773 		}
2774 	}
2775 }
2776 
2777 #ifdef SUSPEND_EVENT
2778 static void
dhd_conf_set_suspend_event(dhd_pub_t * dhd,int suspend)2779 dhd_conf_set_suspend_event(dhd_pub_t *dhd, int suspend)
2780 {
2781 	struct dhd_conf *conf = dhd->conf;
2782 	char suspend_eventmask[WL_EVENTING_MASK_LEN];
2783 
2784 	CONFIG_TRACE("Enter\n");
2785 	if (suspend) {
2786 #ifdef PROP_TXSTATUS
2787 #if defined(BCMSDIO) || defined(BCMDBUS)
2788 		if (dhd->wlfc_enabled) {
2789 			dhd_wlfc_deinit(dhd);
2790 			conf->wlfc = TRUE;
2791 		} else {
2792 			conf->wlfc = FALSE;
2793 		}
2794 #endif /* BCMSDIO || BCMDBUS */
2795 #endif /* PROP_TXSTATUS */
2796 		dhd_conf_get_iovar(dhd, 0, WLC_GET_VAR, "event_msgs",
2797 			conf->resume_eventmask, sizeof(conf->resume_eventmask));
2798 		memset(suspend_eventmask, 0, sizeof(suspend_eventmask));
2799 		setbit(suspend_eventmask, WLC_E_ESCAN_RESULT);
2800 		dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "event_msgs",
2801 			suspend_eventmask, sizeof(suspend_eventmask), FALSE);
2802 	}
2803 	else {
2804 		dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "event_msgs",
2805 			conf->resume_eventmask, sizeof(conf->resume_eventmask), FALSE);
2806 #ifdef PROP_TXSTATUS
2807 #if defined(BCMSDIO) || defined(BCMDBUS)
2808 		if (conf->wlfc) {
2809 			dhd_wlfc_init(dhd);
2810 			dhd_conf_set_intiovar(dhd, 0, WLC_UP, "WLC_UP", 0, 0, FALSE);
2811 		}
2812 #endif
2813 #endif /* PROP_TXSTATUS */
2814 	}
2815 
2816 }
2817 #endif
2818 
2819 int
dhd_conf_suspend_resume_sta(dhd_pub_t * dhd,int ifidx,int suspend)2820 dhd_conf_suspend_resume_sta(dhd_pub_t *dhd, int ifidx, int suspend)
2821 {
2822 	struct dhd_conf *conf = dhd->conf;
2823 	uint insuspend = 0;
2824 	int pm;
2825 #ifdef WL_EXT_WOWL
2826 	int i;
2827 #endif
2828 
2829 	insuspend = dhd_conf_get_insuspend(dhd, ALL_IN_SUSPEND);
2830 	if (insuspend)
2831 		WL_MSG(dhd_ifname(dhd, ifidx), "suspend %d\n", suspend);
2832 
2833 	if (suspend) {
2834 		dhd_conf_check_connection(dhd, ifidx, suspend);
2835 		dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "roam_off",
2836 			conf->roam_off_suspend, 0, FALSE);
2837 		dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "bcn_li_dtim",
2838 			conf->suspend_bcn_li_dtim, 0, FALSE);
2839 		if (conf->pm_in_suspend >= 0)
2840 			pm = conf->pm_in_suspend;
2841 		else if (conf->pm >= 0)
2842 			pm = conf->pm;
2843 		else
2844 			pm = PM_FAST;
2845 		dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_PM, "WLC_SET_PM", pm, 0, FALSE);
2846 #ifdef WL_EXT_WOWL
2847 		if ((insuspend & WOWL_IN_SUSPEND) && dhd_master_mode) {
2848 			dhd_conf_wowl_pattern(dhd, ifidx, FALSE, "clr");
2849 			for(i=0; i<conf->pkt_filter_add.count; i++) {
2850 				dhd_conf_wowl_pattern(dhd, ifidx, TRUE, conf->pkt_filter_add.filter[i]);
2851 			}
2852 			dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "wowl", conf->wowl, 0, FALSE);
2853 			dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "wowl_activate", 1, 0, FALSE);
2854 			dhd_conf_wowl_wakeind(dhd, ifidx, TRUE);
2855 		}
2856 #endif
2857 	}
2858 	else {
2859 		dhd_conf_get_iovar(dhd, 0, WLC_GET_PM, "WLC_GET_PM", (char *)&pm, sizeof(pm));
2860 		CONFIG_TRACE("PM in suspend = %d\n", pm);
2861 		if (conf->pm >= 0)
2862 			pm = conf->pm;
2863 		else
2864 			pm = PM_FAST;
2865 		dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_PM, "WLC_SET_PM", pm, 0, FALSE);
2866 #ifdef WL_EXT_WOWL
2867 		if (insuspend & WOWL_IN_SUSPEND) {
2868 			dhd_conf_wowl_wakeind(dhd, ifidx, FALSE);
2869 			dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "wowl_activate", 0, 0, FALSE);
2870 			dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "wowl", 0, 0, FALSE);
2871 			dhd_conf_wowl_pattern(dhd, ifidx, FALSE, "clr");
2872 		}
2873 #endif
2874 		dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "bcn_li_dtim", 0, 0, FALSE);
2875 		dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "roam_off",
2876 			conf->roam_off, 0, FALSE);
2877 		dhd_conf_check_connection(dhd, ifidx, suspend);
2878 	}
2879 
2880 	return 0;
2881 }
2882 
2883 #ifndef WL_EXT_IAPSTA
2884 static int
dhd_conf_suspend_resume_ap(dhd_pub_t * dhd,int ifidx,int suspend)2885 dhd_conf_suspend_resume_ap(dhd_pub_t *dhd, int ifidx, int suspend)
2886 {
2887 	struct dhd_conf *conf = dhd->conf;
2888 	uint insuspend = 0;
2889 
2890 	insuspend = dhd_conf_get_insuspend(dhd, ALL_IN_SUSPEND);
2891 	if (insuspend)
2892 		WL_MSG(dhd_ifname(dhd, ifidx), "suspend %d\n", suspend);
2893 
2894 	if (suspend) {
2895 		if (insuspend & AP_DOWN_IN_SUSPEND) {
2896 			dhd_conf_set_intiovar(dhd, ifidx, WLC_DOWN, "WLC_DOWN", 1, 0, FALSE);
2897 		}
2898 	} else {
2899 		if (insuspend & AP_DOWN_IN_SUSPEND) {
2900 			dhd_conf_set_intiovar(dhd, ifidx, WLC_UP, "WLC_UP", 0, 0, FALSE);
2901 		}
2902 	}
2903 
2904 	return 0;
2905 }
2906 #endif /* !WL_EXT_IAPSTA */
2907 
2908 static int
dhd_conf_suspend_resume_bus(dhd_pub_t * dhd,int suspend)2909 dhd_conf_suspend_resume_bus(dhd_pub_t *dhd, int suspend)
2910 {
2911 	uint insuspend = 0;
2912 
2913 	insuspend = dhd_conf_get_insuspend(dhd, ALL_IN_SUSPEND);
2914 	if (insuspend)
2915 		CONFIG_MSG("suspend %d\n", suspend);
2916 
2917 	if (suspend) {
2918 		if (insuspend & (WOWL_IN_SUSPEND | NO_TXCTL_IN_SUSPEND)) {
2919 #ifdef BCMSDIO
2920 			uint32 intstatus = 0;
2921 			int ret = 0;
2922 #endif
2923 			int hostsleep = 2;
2924 #ifdef WL_EXT_WOWL
2925 			hostsleep = 1;
2926 #endif
2927 			dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "hostsleep", hostsleep, 0, FALSE);
2928 #ifdef BCMSDIO
2929 			ret = dhd_bus_sleep(dhd, TRUE, &intstatus);
2930 			CONFIG_TRACE("ret = %d, intstatus = 0x%x\n", ret, intstatus);
2931 #endif
2932 		}
2933 	} else {
2934 		if (insuspend & (WOWL_IN_SUSPEND | NO_TXCTL_IN_SUSPEND)) {
2935 			dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "hostsleep", 0, 0, FALSE);
2936 		}
2937 	}
2938 
2939 	return 0;
2940 }
2941 
2942 int
dhd_conf_set_suspend_resume(dhd_pub_t * dhd,int suspend)2943 dhd_conf_set_suspend_resume(dhd_pub_t *dhd, int suspend)
2944 {
2945 	struct dhd_conf *conf = dhd->conf;
2946 	uint insuspend = 0;
2947 
2948 	insuspend = dhd_conf_get_insuspend(dhd, ALL_IN_SUSPEND);
2949 	if (insuspend)
2950 		CONFIG_MSG("op_mode %d, suspend %d, suspended %d, insuspend 0x%x, suspend_mode=%d\n",
2951 			dhd->op_mode, suspend, conf->suspended, insuspend, conf->suspend_mode);
2952 
2953 	if (conf->suspended == suspend || !dhd->up) {
2954 		return 0;
2955 	}
2956 
2957 	if (suspend) {
2958 		if (insuspend & (NO_EVENT_IN_SUSPEND|NO_TXCTL_IN_SUSPEND|WOWL_IN_SUSPEND)) {
2959 			if (conf->suspend_mode == PM_NOTIFIER)
2960 #ifdef WL_EXT_IAPSTA
2961 				wl_iapsta_wait_event_complete(dhd);
2962 #else
2963 				wl_ext_wait_event_complete(dhd, 0);
2964 #endif /* WL_EXT_IAPSTA */
2965 		}
2966 		if (insuspend & NO_TXDATA_IN_SUSPEND) {
2967 			dhd_txflowcontrol(dhd, ALL_INTERFACES, ON);
2968 		}
2969 #if defined(WL_CFG80211) || defined(WL_ESCAN)
2970 		if (insuspend & (NO_EVENT_IN_SUSPEND|NO_TXCTL_IN_SUSPEND|WOWL_IN_SUSPEND)) {
2971 			if (conf->suspend_mode == PM_NOTIFIER)
2972 				wl_ext_user_sync(dhd, 0, TRUE);
2973 		}
2974 #endif
2975 		if (insuspend & ROAM_OFFLOAD_IN_SUSPEND)
2976 			dhd_conf_enable_roam_offload(dhd, 2);
2977 #ifdef SUSPEND_EVENT
2978 		if (insuspend & NO_EVENT_IN_SUSPEND) {
2979 			dhd_conf_set_suspend_event(dhd, suspend);
2980 		}
2981 #endif
2982 #ifdef WL_EXT_IAPSTA
2983 		wl_iapsta_suspend_resume(dhd, suspend);
2984 #else
2985 		if (dhd->op_mode & DHD_FLAG_STA_MODE) {
2986 			dhd_conf_suspend_resume_sta(dhd, 0, suspend);
2987 		} else if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
2988 			dhd_conf_suspend_resume_ap(dhd, 0, suspend);
2989 		}
2990 #endif /* WL_EXT_IAPSTA */
2991 		dhd_conf_set_wl_cmd(dhd, conf->wl_suspend, FALSE);
2992 		dhd_conf_suspend_resume_bus(dhd, suspend);
2993 		conf->suspended = TRUE;
2994 	}
2995 	else {
2996 		dhd_conf_suspend_resume_bus(dhd, suspend);
2997 #ifdef SUSPEND_EVENT
2998 		if (insuspend & NO_EVENT_IN_SUSPEND) {
2999 			dhd_conf_set_suspend_event(dhd, suspend);
3000 		}
3001 #endif
3002 		if (insuspend & ROAM_OFFLOAD_IN_SUSPEND)
3003 			dhd_conf_enable_roam_offload(dhd, 0);
3004 		dhd_conf_set_wl_cmd(dhd, conf->wl_resume, FALSE);
3005 #ifdef WL_EXT_IAPSTA
3006 		wl_iapsta_suspend_resume(dhd, suspend);
3007 #else
3008 		if (dhd->op_mode & DHD_FLAG_STA_MODE) {
3009 			dhd_conf_suspend_resume_sta(dhd, 0, suspend);
3010 		} else if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
3011 			dhd_conf_suspend_resume_ap(dhd, 0, suspend);
3012 		}
3013 #endif /* WL_EXT_IAPSTA */
3014 #if defined(WL_CFG80211) || defined(WL_ESCAN)
3015 		if (insuspend & (NO_EVENT_IN_SUSPEND|NO_TXCTL_IN_SUSPEND|WOWL_IN_SUSPEND)) {
3016 			if (conf->suspend_mode == PM_NOTIFIER)
3017 				wl_ext_user_sync(dhd, 0, FALSE);
3018 		}
3019 #endif
3020 		if (insuspend & NO_TXDATA_IN_SUSPEND) {
3021 			dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
3022 		}
3023 		conf->suspended = FALSE;
3024 	}
3025 
3026 	return 0;
3027 }
3028 
3029 #ifdef PROP_TXSTATUS
3030 int
dhd_conf_get_disable_proptx(dhd_pub_t * dhd)3031 dhd_conf_get_disable_proptx(dhd_pub_t *dhd)
3032 {
3033 	struct dhd_conf *conf = dhd->conf;
3034 	int disable_proptx = -1;
3035 	int fw_proptx = 0;
3036 
3037 	/* check fw proptx priority:
3038 	  * 1st: check fw support by wl cap
3039 	  * 2nd: 4334/43340/43341/43241 support proptx but not show in wl cap, so enable it by default
3040 	  * 	   if you would like to disable it, please set disable_proptx=1 in config.txt
3041 	  * 3th: disable when proptxstatus not support in wl cap
3042 	  */
3043 	if (FW_SUPPORTED(dhd, proptxstatus)) {
3044 		fw_proptx = 1;
3045 	} else if (conf->chip == BCM4334_CHIP_ID || conf->chip == BCM43340_CHIP_ID ||
3046 			dhd->conf->chip == BCM43340_CHIP_ID || conf->chip == BCM4324_CHIP_ID) {
3047 		fw_proptx = 1;
3048 	} else {
3049 		fw_proptx = 0;
3050 	}
3051 
3052 	/* returned disable_proptx value:
3053 	  * -1: disable in STA and enable in P2P(follow original dhd settings when PROP_TXSTATUS_VSDB enabled)
3054 	  * 0: depend on fw support
3055 	  * 1: always disable proptx
3056 	  */
3057 	if (conf->disable_proptx == 0) {
3058 		// check fw support as well
3059 		if (fw_proptx)
3060 			disable_proptx = 0;
3061 		else
3062 			disable_proptx = 1;
3063 	} else if (conf->disable_proptx >= 1) {
3064 		disable_proptx = 1;
3065 	} else {
3066 		// check fw support as well
3067 		if (fw_proptx)
3068 			disable_proptx = -1;
3069 		else
3070 			disable_proptx = 1;
3071 	}
3072 
3073 	CONFIG_MSG("fw_proptx=%d, disable_proptx=%d\n", fw_proptx, disable_proptx);
3074 
3075 	return disable_proptx;
3076 }
3077 #endif
3078 
3079 uint
pick_config_vars(char * varbuf,uint len,uint start_pos,char * pickbuf,int picklen)3080 pick_config_vars(char *varbuf, uint len, uint start_pos, char *pickbuf, int picklen)
3081 {
3082 	bool findNewline, changenewline=FALSE, pick=FALSE;
3083 	int column;
3084 	uint n, pick_column=0;
3085 
3086 	findNewline = FALSE;
3087 	column = 0;
3088 
3089 	if (start_pos >= len) {
3090 		CONFIG_ERROR("wrong start pos\n");
3091 		return 0;
3092 	}
3093 
3094 	for (n = start_pos; n < len; n++) {
3095 		if (varbuf[n] == '\r')
3096 			continue;
3097 		if ((findNewline || changenewline) && varbuf[n] != '\n')
3098 			continue;
3099 		findNewline = FALSE;
3100 		if (varbuf[n] == '#') {
3101 			findNewline = TRUE;
3102 			continue;
3103 		}
3104 		if (varbuf[n] == '\\') {
3105 			changenewline = TRUE;
3106 			continue;
3107 		}
3108 		if (!changenewline && varbuf[n] == '\n') {
3109 			if (column == 0)
3110 				continue;
3111 			column = 0;
3112 			continue;
3113 		}
3114 		if (changenewline && varbuf[n] == '\n') {
3115 			changenewline = FALSE;
3116 			continue;
3117 		}
3118 
3119 		if (column==0 && !pick) { // start to pick
3120 			pick = TRUE;
3121 			column++;
3122 			pick_column = 0;
3123 		} else {
3124 			if (pick && column==0) { // stop to pick
3125 				pick = FALSE;
3126 				break;
3127 			} else
3128 				column++;
3129 		}
3130 		if (pick) {
3131 			if (varbuf[n] == 0x9)
3132 				continue;
3133 			if (pick_column >= picklen)
3134 				break;
3135 			pickbuf[pick_column] = varbuf[n];
3136 			pick_column++;
3137 		}
3138 	}
3139 
3140 	return n; // return current position
3141 }
3142 
3143 bool
dhd_conf_read_chiprev(dhd_pub_t * dhd,int * chip_match,char * full_param,uint len_param)3144 dhd_conf_read_chiprev(dhd_pub_t *dhd, int *chip_match,
3145 	char *full_param, uint len_param)
3146 {
3147 	char *data = full_param+len_param, *pick_tmp, *pch;
3148 	uint chip = 0, rev = 0;
3149 
3150 	/* Process chip, regrev:
3151 	 * chip=[chipid], rev==[rev]
3152 	 * Ex: chip=0x4359, rev=9
3153 	 */
3154 	if (!strncmp("chip=", full_param, len_param)) {
3155 		chip = (int)simple_strtol(data, NULL, 0);
3156 		pick_tmp = data;
3157 		pch = bcmstrstr(pick_tmp, "rev=");
3158 		if (pch) {
3159 			rev = (int)simple_strtol(pch+strlen("rev="), NULL, 0);
3160 		}
3161 		if (chip == dhd->conf->chip && rev == dhd->conf->chiprev)
3162 			*chip_match = 1;
3163 		else
3164 			*chip_match = 0;
3165 		CONFIG_MSG("chip=0x%x, rev=%d, chip_match=%d\n", chip, rev, *chip_match);
3166 	}
3167 
3168 	return TRUE;
3169 }
3170 
3171 bool
dhd_conf_read_log_level(dhd_pub_t * dhd,char * full_param,uint len_param)3172 dhd_conf_read_log_level(dhd_pub_t *dhd, char *full_param, uint len_param)
3173 {
3174 	char *data = full_param+len_param;
3175 
3176 	if (!strncmp("dhd_msg_level=", full_param, len_param)) {
3177 		dhd_msg_level = (int)simple_strtol(data, NULL, 0);
3178 		CONFIG_MSG("dhd_msg_level = 0x%X\n", dhd_msg_level);
3179 	}
3180 	else if (!strncmp("dump_msg_level=", full_param, len_param)) {
3181 		dump_msg_level = (int)simple_strtol(data, NULL, 0);
3182 		CONFIG_MSG("dump_msg_level = 0x%X\n", dump_msg_level);
3183 	}
3184 #ifdef BCMSDIO
3185 	else if (!strncmp("sd_msglevel=", full_param, len_param)) {
3186 		sd_msglevel = (int)simple_strtol(data, NULL, 0);
3187 		CONFIG_MSG("sd_msglevel = 0x%X\n", sd_msglevel);
3188 	}
3189 #endif
3190 #ifdef BCMDBUS
3191 	else if (!strncmp("dbus_msglevel=", full_param, len_param)) {
3192 		dbus_msglevel = (int)simple_strtol(data, NULL, 0);
3193 		CONFIG_MSG("dbus_msglevel = 0x%X\n", dbus_msglevel);
3194 	}
3195 #endif
3196 	else if (!strncmp("android_msg_level=", full_param, len_param)) {
3197 		android_msg_level = (int)simple_strtol(data, NULL, 0);
3198 		CONFIG_MSG("android_msg_level = 0x%X\n", android_msg_level);
3199 	}
3200 	else if (!strncmp("config_msg_level=", full_param, len_param)) {
3201 		config_msg_level = (int)simple_strtol(data, NULL, 0);
3202 		CONFIG_MSG("config_msg_level = 0x%X\n", config_msg_level);
3203 	}
3204 #ifdef WL_CFG80211
3205 	else if (!strncmp("wl_dbg_level=", full_param, len_param)) {
3206 		wl_dbg_level = (int)simple_strtol(data, NULL, 0);
3207 		CONFIG_MSG("wl_dbg_level = 0x%X\n", wl_dbg_level);
3208 	}
3209 #endif
3210 #if defined(WL_WIRELESS_EXT)
3211 	else if (!strncmp("iw_msg_level=", full_param, len_param)) {
3212 		iw_msg_level = (int)simple_strtol(data, NULL, 0);
3213 		CONFIG_MSG("iw_msg_level = 0x%X\n", iw_msg_level);
3214 	}
3215 #endif
3216 #if defined(DHD_DEBUG)
3217 	else if (!strncmp("dhd_console_ms=", full_param, len_param)) {
3218 		dhd->dhd_console_ms = (int)simple_strtol(data, NULL, 0);
3219 		CONFIG_MSG("dhd_console_ms = %d\n", dhd->dhd_console_ms);
3220 	}
3221 #endif
3222 	else
3223 		return false;
3224 
3225 	return true;
3226 }
3227 
3228 void
dhd_conf_read_wme_ac_value(wme_param_t * wme,char * pick,int ac_val)3229 dhd_conf_read_wme_ac_value(wme_param_t *wme, char *pick, int ac_val)
3230 {
3231 	char *pick_tmp, *pch;
3232 
3233 	pick_tmp = pick;
3234 	pch = bcmstrstr(pick_tmp, "aifsn ");
3235 	if (pch) {
3236 		wme->aifsn[ac_val] = (int)simple_strtol(pch+strlen("aifsn "), NULL, 0);
3237 		CONFIG_MSG("ac_val=%d, aifsn=%d\n", ac_val, wme->aifsn[ac_val]);
3238 	}
3239 	pick_tmp = pick;
3240 	pch = bcmstrstr(pick_tmp, "ecwmin ");
3241 	if (pch) {
3242 		wme->ecwmin[ac_val] = (int)simple_strtol(pch+strlen("ecwmin "), NULL, 0);
3243 		CONFIG_MSG("ac_val=%d, ecwmin=%d\n", ac_val, wme->ecwmin[ac_val]);
3244 	}
3245 	pick_tmp = pick;
3246 	pch = bcmstrstr(pick_tmp, "ecwmax ");
3247 	if (pch) {
3248 		wme->ecwmax[ac_val] = (int)simple_strtol(pch+strlen("ecwmax "), NULL, 0);
3249 		CONFIG_MSG("ac_val=%d, ecwmax=%d\n", ac_val, wme->ecwmax[ac_val]);
3250 	}
3251 	pick_tmp = pick;
3252 	pch = bcmstrstr(pick_tmp, "txop ");
3253 	if (pch) {
3254 		wme->txop[ac_val] = (int)simple_strtol(pch+strlen("txop "), NULL, 0);
3255 		CONFIG_MSG("ac_val=%d, txop=0x%x\n", ac_val, wme->txop[ac_val]);
3256 	}
3257 
3258 }
3259 
3260 bool
dhd_conf_read_wme_ac_params(dhd_pub_t * dhd,char * full_param,uint len_param)3261 dhd_conf_read_wme_ac_params(dhd_pub_t *dhd, char *full_param, uint len_param)
3262 {
3263 	struct dhd_conf *conf = dhd->conf;
3264 	char *data = full_param+len_param;
3265 
3266 	// wme_ac_sta_be=aifsn 1 ecwmin 2 ecwmax 3 txop 0x5e
3267 	// wme_ac_sta_vo=aifsn 1 ecwmin 1 ecwmax 1 txop 0x5e
3268 
3269 	if (!strncmp("force_wme_ac=", full_param, len_param)) {
3270 		conf->force_wme_ac = (int)simple_strtol(data, NULL, 10);
3271 		CONFIG_MSG("force_wme_ac = %d\n", conf->force_wme_ac);
3272 	}
3273 	else if (!strncmp("wme_ac_sta_be=", full_param, len_param)) {
3274 		dhd_conf_read_wme_ac_value(&conf->wme_sta, data, AC_BE);
3275 	}
3276 	else if (!strncmp("wme_ac_sta_bk=", full_param, len_param)) {
3277 		dhd_conf_read_wme_ac_value(&conf->wme_sta, data, AC_BK);
3278 	}
3279 	else if (!strncmp("wme_ac_sta_vi=", full_param, len_param)) {
3280 		dhd_conf_read_wme_ac_value(&conf->wme_sta, data, AC_VI);
3281 	}
3282 	else if (!strncmp("wme_ac_sta_vo=", full_param, len_param)) {
3283 		dhd_conf_read_wme_ac_value(&conf->wme_sta, data, AC_VO);
3284 	}
3285 	else if (!strncmp("wme_ac_ap_be=", full_param, len_param)) {
3286 		dhd_conf_read_wme_ac_value(&conf->wme_ap, data, AC_BE);
3287 	}
3288 	else if (!strncmp("wme_ac_ap_bk=", full_param, len_param)) {
3289 		dhd_conf_read_wme_ac_value(&conf->wme_ap, data, AC_BK);
3290 	}
3291 	else if (!strncmp("wme_ac_ap_vi=", full_param, len_param)) {
3292 		dhd_conf_read_wme_ac_value(&conf->wme_ap, data, AC_VI);
3293 	}
3294 	else if (!strncmp("wme_ac_ap_vo=", full_param, len_param)) {
3295 		dhd_conf_read_wme_ac_value(&conf->wme_ap, data, AC_VO);
3296 	}
3297 	else
3298 		return false;
3299 
3300 	return true;
3301 }
3302 
3303 #ifdef SET_FWNV_BY_MAC
3304 bool
dhd_conf_read_fw_by_mac(dhd_pub_t * dhd,char * full_param,uint len_param)3305 dhd_conf_read_fw_by_mac(dhd_pub_t *dhd, char *full_param, uint len_param)
3306 {
3307 	int i, j;
3308 	char *pch, *pick_tmp;
3309 	wl_mac_list_t *mac_list;
3310 	wl_mac_range_t *mac_range;
3311 	struct dhd_conf *conf = dhd->conf;
3312 	char *data = full_param+len_param;
3313 
3314 	/* Process fw_by_mac:
3315 	 * fw_by_mac=[fw_mac_num] \
3316 	 *  [fw_name1] [mac_num1] [oui1-1] [nic_start1-1] [nic_end1-1] \
3317 	 *                                    [oui1-1] [nic_start1-1] [nic_end1-1]... \
3318 	 *                                    [oui1-n] [nic_start1-n] [nic_end1-n] \
3319 	 *  [fw_name2] [mac_num2] [oui2-1] [nic_start2-1] [nic_end2-1] \
3320 	 *                                    [oui2-1] [nic_start2-1] [nic_end2-1]... \
3321 	 *                                    [oui2-n] [nic_start2-n] [nic_end2-n] \
3322 	 * Ex: fw_by_mac=2 \
3323 	 *  fw_bcmdhd1.bin 2 0x0022F4 0xE85408 0xE8549D 0x983B16 0x3557A9 0x35582A \
3324 	 *  fw_bcmdhd2.bin 3 0x0022F4 0xE85408 0xE8549D 0x983B16 0x3557A9 0x35582A \
3325 	 *                           0x983B16 0x916157 0x916487
3326 	 */
3327 
3328 	if (!strncmp("fw_by_mac=", full_param, len_param)) {
3329 		dhd_conf_free_mac_list(&conf->fw_by_mac);
3330 		pick_tmp = data;
3331 		pch = bcmstrtok(&pick_tmp, " ", 0);
3332 		conf->fw_by_mac.count = (uint32)simple_strtol(pch, NULL, 0);
3333 		if (!(mac_list = kmalloc(sizeof(wl_mac_list_t)*conf->fw_by_mac.count,
3334 				GFP_KERNEL))) {
3335 			conf->fw_by_mac.count = 0;
3336 			CONFIG_ERROR("kmalloc failed\n");
3337 		}
3338 		CONFIG_MSG("fw_count=%d\n", conf->fw_by_mac.count);
3339 		conf->fw_by_mac.m_mac_list_head = mac_list;
3340 		for (i=0; i<conf->fw_by_mac.count; i++) {
3341 			pch = bcmstrtok(&pick_tmp, " ", 0);
3342 			strcpy(mac_list[i].name, pch);
3343 			pch = bcmstrtok(&pick_tmp, " ", 0);
3344 			mac_list[i].count = (uint32)simple_strtol(pch, NULL, 0);
3345 			CONFIG_MSG("name=%s, mac_count=%d\n",
3346 				mac_list[i].name, mac_list[i].count);
3347 			if (!(mac_range = kmalloc(sizeof(wl_mac_range_t)*mac_list[i].count,
3348 					GFP_KERNEL))) {
3349 				mac_list[i].count = 0;
3350 				CONFIG_ERROR("kmalloc failed\n");
3351 				break;
3352 			}
3353 			mac_list[i].mac = mac_range;
3354 			for (j=0; j<mac_list[i].count; j++) {
3355 				pch = bcmstrtok(&pick_tmp, " ", 0);
3356 				mac_range[j].oui = (uint32)simple_strtol(pch, NULL, 0);
3357 				pch = bcmstrtok(&pick_tmp, " ", 0);
3358 				mac_range[j].nic_start = (uint32)simple_strtol(pch, NULL, 0);
3359 				pch = bcmstrtok(&pick_tmp, " ", 0);
3360 				mac_range[j].nic_end = (uint32)simple_strtol(pch, NULL, 0);
3361 				CONFIG_MSG("oui=0x%06X, nic_start=0x%06X, nic_end=0x%06X\n",
3362 					mac_range[j].oui, mac_range[j].nic_start, mac_range[j].nic_end);
3363 			}
3364 		}
3365 	}
3366 	else
3367 		return false;
3368 
3369 	return true;
3370 }
3371 
3372 bool
dhd_conf_read_nv_by_mac(dhd_pub_t * dhd,char * full_param,uint len_param)3373 dhd_conf_read_nv_by_mac(dhd_pub_t *dhd, char *full_param, uint len_param)
3374 {
3375 	int i, j;
3376 	char *pch, *pick_tmp;
3377 	wl_mac_list_t *mac_list;
3378 	wl_mac_range_t *mac_range;
3379 	struct dhd_conf *conf = dhd->conf;
3380 	char *data = full_param+len_param;
3381 
3382 	/* Process nv_by_mac:
3383 	 * [nv_by_mac]: The same format as fw_by_mac
3384 	 */
3385 	if (!strncmp("nv_by_mac=", full_param, len_param)) {
3386 		dhd_conf_free_mac_list(&conf->nv_by_mac);
3387 		pick_tmp = data;
3388 		pch = bcmstrtok(&pick_tmp, " ", 0);
3389 		conf->nv_by_mac.count = (uint32)simple_strtol(pch, NULL, 0);
3390 		if (!(mac_list = kmalloc(sizeof(wl_mac_list_t)*conf->nv_by_mac.count,
3391 				GFP_KERNEL))) {
3392 			conf->nv_by_mac.count = 0;
3393 			CONFIG_ERROR("kmalloc failed\n");
3394 		}
3395 		CONFIG_MSG("nv_count=%d\n", conf->nv_by_mac.count);
3396 		conf->nv_by_mac.m_mac_list_head = mac_list;
3397 		for (i=0; i<conf->nv_by_mac.count; i++) {
3398 			pch = bcmstrtok(&pick_tmp, " ", 0);
3399 			strcpy(mac_list[i].name, pch);
3400 			pch = bcmstrtok(&pick_tmp, " ", 0);
3401 			mac_list[i].count = (uint32)simple_strtol(pch, NULL, 0);
3402 			CONFIG_MSG("name=%s, mac_count=%d\n",
3403 				mac_list[i].name, mac_list[i].count);
3404 			if (!(mac_range = kmalloc(sizeof(wl_mac_range_t)*mac_list[i].count,
3405 					GFP_KERNEL))) {
3406 				mac_list[i].count = 0;
3407 				CONFIG_ERROR("kmalloc failed\n");
3408 				break;
3409 			}
3410 			mac_list[i].mac = mac_range;
3411 			for (j=0; j<mac_list[i].count; j++) {
3412 				pch = bcmstrtok(&pick_tmp, " ", 0);
3413 				mac_range[j].oui = (uint32)simple_strtol(pch, NULL, 0);
3414 				pch = bcmstrtok(&pick_tmp, " ", 0);
3415 				mac_range[j].nic_start = (uint32)simple_strtol(pch, NULL, 0);
3416 				pch = bcmstrtok(&pick_tmp, " ", 0);
3417 				mac_range[j].nic_end = (uint32)simple_strtol(pch, NULL, 0);
3418 				CONFIG_MSG("oui=0x%06X, nic_start=0x%06X, nic_end=0x%06X\n",
3419 					mac_range[j].oui, mac_range[j].nic_start, mac_range[j].nic_end);
3420 			}
3421 		}
3422 	}
3423 	else
3424 		return false;
3425 
3426 	return true;
3427 }
3428 #endif
3429 
3430 bool
dhd_conf_read_nv_by_chip(dhd_pub_t * dhd,char * full_param,uint len_param)3431 dhd_conf_read_nv_by_chip(dhd_pub_t *dhd, char *full_param, uint len_param)
3432 {
3433 	int i;
3434 	char *pch, *pick_tmp;
3435 	wl_chip_nv_path_t *chip_nv_path;
3436 	struct dhd_conf *conf = dhd->conf;
3437 	char *data = full_param+len_param;
3438 
3439 	/* Process nv_by_chip:
3440 	 * nv_by_chip=[nv_chip_num] \
3441 	 *  [chip1] [chiprev1] [nv_name1] [chip2] [chiprev2] [nv_name2] \
3442 	 * Ex: nv_by_chip=2 \
3443 	 *  43430 0 nvram_ap6212.txt 43430 1 nvram_ap6212a.txt \
3444 	 */
3445 	if (!strncmp("nv_by_chip=", full_param, len_param)) {
3446 		dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip);
3447 		pick_tmp = data;
3448 		pch = bcmstrtok(&pick_tmp, " ", 0);
3449 		conf->nv_by_chip.count = (uint32)simple_strtol(pch, NULL, 0);
3450 		if (!(chip_nv_path = kmalloc(sizeof(wl_chip_nv_path_t)*conf->nv_by_chip.count,
3451 				GFP_KERNEL))) {
3452 			conf->nv_by_chip.count = 0;
3453 			CONFIG_ERROR("kmalloc failed\n");
3454 		}
3455 		CONFIG_MSG("nv_by_chip_count=%d\n", conf->nv_by_chip.count);
3456 		conf->nv_by_chip.m_chip_nv_path_head = chip_nv_path;
3457 		for (i=0; i<conf->nv_by_chip.count; i++) {
3458 			pch = bcmstrtok(&pick_tmp, " ", 0);
3459 			chip_nv_path[i].chip = (uint32)simple_strtol(pch, NULL, 0);
3460 			pch = bcmstrtok(&pick_tmp, " ", 0);
3461 			chip_nv_path[i].chiprev = (uint32)simple_strtol(pch, NULL, 0);
3462 			pch = bcmstrtok(&pick_tmp, " ", 0);
3463 			strcpy(chip_nv_path[i].name, pch);
3464 			CONFIG_MSG("chip=0x%x, chiprev=%d, name=%s\n",
3465 				chip_nv_path[i].chip, chip_nv_path[i].chiprev, chip_nv_path[i].name);
3466 		}
3467 	}
3468 	else
3469 		return false;
3470 
3471 	return true;
3472 }
3473 
3474 bool
dhd_conf_read_roam_params(dhd_pub_t * dhd,char * full_param,uint len_param)3475 dhd_conf_read_roam_params(dhd_pub_t *dhd, char *full_param, uint len_param)
3476 {
3477 	struct dhd_conf *conf = dhd->conf;
3478 	char *data = full_param+len_param;
3479 
3480 	if (!strncmp("roam_off=", full_param, len_param)) {
3481 		if (!strncmp(data, "0", 1))
3482 			conf->roam_off = 0;
3483 		else
3484 			conf->roam_off = 1;
3485 		CONFIG_MSG("roam_off = %d\n", conf->roam_off);
3486 	}
3487 	else if (!strncmp("roam_off_suspend=", full_param, len_param)) {
3488 		if (!strncmp(data, "0", 1))
3489 			conf->roam_off_suspend = 0;
3490 		else
3491 			conf->roam_off_suspend = 1;
3492 		CONFIG_MSG("roam_off_suspend = %d\n", conf->roam_off_suspend);
3493 	}
3494 	else if (!strncmp("roam_trigger=", full_param, len_param)) {
3495 		conf->roam_trigger[0] = (int)simple_strtol(data, NULL, 10);
3496 		CONFIG_MSG("roam_trigger = %d\n", conf->roam_trigger[0]);
3497 	}
3498 	else if (!strncmp("roam_scan_period=", full_param, len_param)) {
3499 		conf->roam_scan_period[0] = (int)simple_strtol(data, NULL, 10);
3500 		CONFIG_MSG("roam_scan_period = %d\n", conf->roam_scan_period[0]);
3501 	}
3502 	else if (!strncmp("roam_delta=", full_param, len_param)) {
3503 		conf->roam_delta[0] = (int)simple_strtol(data, NULL, 10);
3504 		CONFIG_MSG("roam_delta = %d\n", conf->roam_delta[0]);
3505 	}
3506 	else if (!strncmp("fullroamperiod=", full_param, len_param)) {
3507 		conf->fullroamperiod = (int)simple_strtol(data, NULL, 10);
3508 		CONFIG_MSG("fullroamperiod = %d\n", conf->fullroamperiod);
3509 	} else
3510 		return false;
3511 
3512 	return true;
3513 }
3514 
3515 bool
dhd_conf_read_country(dhd_pub_t * dhd,char * full_param,uint len_param)3516 dhd_conf_read_country(dhd_pub_t *dhd, char *full_param, uint len_param)
3517 {
3518 	struct dhd_conf *conf = dhd->conf;
3519 	country_list_t *country_next = NULL, *country;
3520 	int i, count = 0;
3521 	char *pch, *pick_tmp, *pick_tmp2;
3522 	char *data = full_param+len_param;
3523 	uint len_data = strlen(data);
3524 
3525 	/* Process country_list:
3526 	 * country_list=[country1]:[ccode1]/[regrev1],
3527 	 * [country2]:[ccode2]/[regrev2] \
3528 	 * Ex: country_list=US:US/0, TW:TW/1
3529 	 */
3530 	if (!strncmp("ccode=", full_param, len_param)) {
3531 		len_data = min((uint)WLC_CNTRY_BUF_SZ, len_data);
3532 		memset(&conf->cspec, 0, sizeof(wl_country_t));
3533 		memcpy(conf->cspec.country_abbrev, data, len_data);
3534 		memcpy(conf->cspec.ccode, data, len_data);
3535 		CONFIG_MSG("ccode = %s\n", conf->cspec.ccode);
3536 	}
3537 	else if (!strncmp("regrev=", full_param, len_param)) {
3538 		conf->cspec.rev = (int32)simple_strtol(data, NULL, 10);
3539 		CONFIG_MSG("regrev = %d\n", conf->cspec.rev);
3540 	}
3541 	else if (!strncmp("country_list=", full_param, len_param)) {
3542 		dhd_conf_free_country_list(conf);
3543 		pick_tmp = data;
3544 		for (i=0; i<CONFIG_COUNTRY_LIST_SIZE; i++) {
3545 			pick_tmp2 = bcmstrtok(&pick_tmp, ", ", 0);
3546 			if (!pick_tmp2)
3547 				break;
3548 			pch = bcmstrtok(&pick_tmp2, ":", 0);
3549 			if (!pch)
3550 				break;
3551 			country = NULL;
3552 			if (!(country = kmalloc(sizeof(country_list_t), GFP_KERNEL))) {
3553 				CONFIG_ERROR("kmalloc failed\n");
3554 				break;
3555 			}
3556 			memset(country, 0, sizeof(country_list_t));
3557 
3558 			memcpy(country->cspec.country_abbrev, pch, 2);
3559 			pch = bcmstrtok(&pick_tmp2, "/", 0);
3560 			if (!pch) {
3561 				kfree(country);
3562 				break;
3563 			}
3564 			memcpy(country->cspec.ccode, pch, 2);
3565 			pch = bcmstrtok(&pick_tmp2, "/", 0);
3566 			if (!pch) {
3567 				kfree(country);
3568 				break;
3569 			}
3570 			country->cspec.rev = (int32)simple_strtol(pch, NULL, 10);
3571 			count++;
3572 			if (!conf->country_head) {
3573 				conf->country_head = country;
3574 				country_next = country;
3575 			} else {
3576 				country_next->next = country;
3577 				country_next = country;
3578 			}
3579 			CONFIG_TRACE("abbrev=%s, ccode=%s, regrev=%d\n",
3580 				country->cspec.country_abbrev, country->cspec.ccode, country->cspec.rev);
3581 		}
3582 		CONFIG_MSG("%d country in list\n", count);
3583 	}
3584 	else
3585 		return false;
3586 
3587 	return true;
3588 }
3589 
3590 bool
dhd_conf_read_mchan_params(dhd_pub_t * dhd,char * full_param,uint len_param)3591 dhd_conf_read_mchan_params(dhd_pub_t *dhd, char *full_param, uint len_param)
3592 {
3593 	int i;
3594 	char *pch, *pick_tmp, *pick_tmp2;
3595 	struct dhd_conf *conf = dhd->conf;
3596 	mchan_params_t *mchan_next = NULL, *mchan;
3597 	char *data = full_param+len_param;
3598 
3599 	/* Process mchan_bw:
3600 	 * mchan_bw=[val]/[any/go/gc]/[any/source/sink]
3601 	 * Ex: mchan_bw=80/go/source, 30/gc/sink
3602 	 */
3603 	if (!strncmp("mchan_bw=", full_param, len_param)) {
3604 		dhd_conf_free_mchan_list(conf);
3605 		pick_tmp = data;
3606 		for (i=0; i<MCHAN_MAX_NUM; i++) {
3607 			pick_tmp2 = bcmstrtok(&pick_tmp, ", ", 0);
3608 			if (!pick_tmp2)
3609 				break;
3610 			pch = bcmstrtok(&pick_tmp2, "/", 0);
3611 			if (!pch)
3612 				break;
3613 
3614 			mchan = NULL;
3615 			if (!(mchan = kmalloc(sizeof(mchan_params_t), GFP_KERNEL))) {
3616 				CONFIG_ERROR("kmalloc failed\n");
3617 				break;
3618 			}
3619 			memset(mchan, 0, sizeof(mchan_params_t));
3620 
3621 			mchan->bw = (int)simple_strtol(pch, NULL, 0);
3622 			if (mchan->bw < 0 || mchan->bw > 100) {
3623 				CONFIG_ERROR("wrong bw %d\n", mchan->bw);
3624 				kfree(mchan);
3625 				break;
3626 			}
3627 
3628 			pch = bcmstrtok(&pick_tmp2, "/", 0);
3629 			if (!pch) {
3630 				kfree(mchan);
3631 				break;
3632 			} else {
3633 				if (bcmstrstr(pch, "any")) {
3634 					mchan->p2p_mode = -1;
3635 				} else if (bcmstrstr(pch, "go")) {
3636 					mchan->p2p_mode = WL_P2P_IF_GO;
3637 				} else if (bcmstrstr(pch, "gc")) {
3638 					mchan->p2p_mode = WL_P2P_IF_CLIENT;
3639 				}
3640 			}
3641 			pch = bcmstrtok(&pick_tmp2, "/", 0);
3642 			if (!pch) {
3643 				kfree(mchan);
3644 				break;
3645 			} else {
3646 				if (bcmstrstr(pch, "any")) {
3647 					mchan->miracast_mode = -1;
3648 				} else if (bcmstrstr(pch, "source")) {
3649 					mchan->miracast_mode = MIRACAST_SOURCE;
3650 				} else if (bcmstrstr(pch, "sink")) {
3651 					mchan->miracast_mode = MIRACAST_SINK;
3652 				}
3653 			}
3654 			if (!conf->mchan) {
3655 				conf->mchan = mchan;
3656 				mchan_next = mchan;
3657 			} else {
3658 				mchan_next->next = mchan;
3659 				mchan_next = mchan;
3660 			}
3661 			CONFIG_TRACE("mchan_bw=%d/%d/%d\n", mchan->bw,mchan->p2p_mode,
3662 				mchan->miracast_mode);
3663 		}
3664 	}
3665 	else
3666 		return false;
3667 
3668 	return true;
3669 }
3670 
3671 #ifdef PKT_FILTER_SUPPORT
3672 bool
dhd_conf_read_pkt_filter(dhd_pub_t * dhd,char * full_param,uint len_param)3673 dhd_conf_read_pkt_filter(dhd_pub_t *dhd, char *full_param, uint len_param)
3674 {
3675 	struct dhd_conf *conf = dhd->conf;
3676 	char *data = full_param+len_param;
3677 	char *pch, *pick_tmp;
3678 	int i;
3679 
3680 	/* Process pkt filter:
3681 	 * 1) pkt_filter_add=99 0 0 0 0x000000000000 0x000000000000
3682 	 * 2) pkt_filter_delete=100, 102, 103, 104, 105
3683 	 * 3) magic_pkt_filter_add=141 0 1 12
3684 	 */
3685 	if (!strncmp("dhd_master_mode=", full_param, len_param)) {
3686 		if (!strncmp(data, "0", 1))
3687 			dhd_master_mode = FALSE;
3688 		else
3689 			dhd_master_mode = TRUE;
3690 		CONFIG_MSG("dhd_master_mode = %d\n", dhd_master_mode);
3691 	}
3692 	else if (!strncmp("pkt_filter_add=", full_param, len_param)) {
3693 		pick_tmp = data;
3694 		pch = bcmstrtok(&pick_tmp, ",.-", 0);
3695 		i=0;
3696 		while (pch != NULL && i<DHD_CONF_FILTER_MAX) {
3697 			strcpy(&conf->pkt_filter_add.filter[i][0], pch);
3698 			CONFIG_MSG("pkt_filter_add[%d][] = %s\n",
3699 				i, &conf->pkt_filter_add.filter[i][0]);
3700 			pch = bcmstrtok(&pick_tmp, ",.-", 0);
3701 			i++;
3702 		}
3703 		conf->pkt_filter_add.count = i;
3704 	}
3705 	else if (!strncmp("pkt_filter_delete=", full_param, len_param) ||
3706 			!strncmp("pkt_filter_del=", full_param, len_param)) {
3707 		pick_tmp = data;
3708 		pch = bcmstrtok(&pick_tmp, " ,.-", 0);
3709 		i=0;
3710 		while (pch != NULL && i<DHD_CONF_FILTER_MAX) {
3711 			conf->pkt_filter_del.id[i] = (uint32)simple_strtol(pch, NULL, 10);
3712 			pch = bcmstrtok(&pick_tmp, " ,.-", 0);
3713 			i++;
3714 		}
3715 		conf->pkt_filter_del.count = i;
3716 		CONFIG_MSG("pkt_filter_del id = ");
3717 		for (i=0; i<conf->pkt_filter_del.count; i++)
3718 			printk(KERN_CONT "%d ", conf->pkt_filter_del.id[i]);
3719 		printk(KERN_CONT "\n");
3720 	}
3721 	else if (!strncmp("magic_pkt_filter_add=", full_param, len_param)) {
3722 		if (conf->magic_pkt_filter_add) {
3723 			kfree(conf->magic_pkt_filter_add);
3724 			conf->magic_pkt_filter_add = NULL;
3725 		}
3726 		if (!(conf->magic_pkt_filter_add = kmalloc(MAGIC_PKT_FILTER_LEN, GFP_KERNEL))) {
3727 			CONFIG_ERROR("kmalloc failed\n");
3728 		} else {
3729 			memset(conf->magic_pkt_filter_add, 0, MAGIC_PKT_FILTER_LEN);
3730 			strcpy(conf->magic_pkt_filter_add, data);
3731 			CONFIG_MSG("magic_pkt_filter_add = %s\n", conf->magic_pkt_filter_add);
3732 		}
3733 	}
3734 	else
3735 		return false;
3736 
3737 	return true;
3738 }
3739 #endif
3740 
3741 #ifdef ISAM_PREINIT
3742 #if !defined(WL_EXT_IAPSTA)
3743 #error "WL_EXT_IAPSTA should be defined to enable ISAM_PREINIT"
3744 #endif /* !WL_EXT_IAPSTA */
3745 /*
3746  * isam_init=mode [sta|ap|apsta|dualap] vifname [wlan1]
3747  * isam_config=ifname [wlan0|wlan1] ssid [xxx] chan [x]
3748 		 hidden [y|n] maxassoc [x]
3749 		 amode [open|shared|wpapsk|wpa2psk|wpawpa2psk]
3750 		 emode [none|wep|tkip|aes|tkipaes]
3751 		 key [xxxxx]
3752  * isam_enable=ifname [wlan0|wlan1]
3753 */
3754 bool
dhd_conf_read_isam(dhd_pub_t * dhd,char * full_param,uint len_param)3755 dhd_conf_read_isam(dhd_pub_t *dhd, char *full_param, uint len_param)
3756 {
3757 	struct dhd_conf *conf = dhd->conf;
3758 	char *data = full_param+len_param;
3759 
3760 	if (!strncmp("isam_init=", full_param, len_param)) {
3761 		sprintf(conf->isam_init, "isam_init %s", data);
3762 		CONFIG_MSG("isam_init=%s\n", conf->isam_init);
3763 	}
3764 	else if (!strncmp("isam_config=", full_param, len_param)) {
3765 		sprintf(conf->isam_config, "isam_config %s", data);
3766 		CONFIG_MSG("isam_config=%s\n", conf->isam_config);
3767 	}
3768 	else if (!strncmp("isam_enable=", full_param, len_param)) {
3769 		sprintf(conf->isam_enable, "isam_enable %s", data);
3770 		CONFIG_MSG("isam_enable=%s\n", conf->isam_enable);
3771 	}
3772 	else
3773 		return false;
3774 
3775 	return true;
3776 }
3777 #endif
3778 
3779 #ifdef IDHCP
3780 bool
dhd_conf_read_dhcp_params(dhd_pub_t * dhd,char * full_param,uint len_param)3781 dhd_conf_read_dhcp_params(dhd_pub_t *dhd, char *full_param, uint len_param)
3782 {
3783 	struct dhd_conf *conf = dhd->conf;
3784 	char *data = full_param+len_param;
3785 	struct ipv4_addr ipa_set;
3786 
3787 	if (!strncmp("dhcpc_enable=", full_param, len_param)) {
3788 		conf->dhcpc_enable = (int)simple_strtol(data, NULL, 10);
3789 		CONFIG_MSG("dhcpc_enable = %d\n", conf->dhcpc_enable);
3790 	}
3791 	else if (!strncmp("dhcpd_enable=", full_param, len_param)) {
3792 		conf->dhcpd_enable = (int)simple_strtol(data, NULL, 10);
3793 		CONFIG_MSG("dhcpd_enable = %d\n", conf->dhcpd_enable);
3794 	}
3795 	else if (!strncmp("dhcpd_ip_addr=", full_param, len_param)) {
3796 		if (!bcm_atoipv4(data, &ipa_set)) {
3797 			CONFIG_ERROR("dhcpd_ip_addr adress setting failed.n");
3798 			return false;
3799 		}
3800 		memcpy(&conf->dhcpd_ip_addr, &ipa_set, sizeof(struct ipv4_addr));
3801 		CONFIG_MSG("dhcpd_ip_addr = %s\n", data);
3802 	}
3803 	else if (!strncmp("dhcpd_ip_mask=", full_param, len_param)) {
3804 		if (!bcm_atoipv4(data, &ipa_set)) {
3805 			CONFIG_ERROR("dhcpd_ip_mask adress setting failed\n");
3806 			return false;
3807 		}
3808 		memcpy(&conf->dhcpd_ip_mask, &ipa_set, sizeof(struct ipv4_addr));
3809 		CONFIG_MSG("dhcpd_ip_mask = %s\n", data);
3810 	}
3811 	else if (!strncmp("dhcpd_ip_start=", full_param, len_param)) {
3812 		if (!bcm_atoipv4(data, &ipa_set)) {
3813 			CONFIG_ERROR("dhcpd_ip_start adress setting failed\n");
3814 			return false;
3815 		}
3816 		memcpy(&conf->dhcpd_ip_start, &ipa_set, sizeof(struct ipv4_addr));
3817 		CONFIG_MSG("dhcpd_ip_start = %s\n", data);
3818 	}
3819 	else if (!strncmp("dhcpd_ip_end=", full_param, len_param)) {
3820 		if (!bcm_atoipv4(data, &ipa_set)) {
3821 			CONFIG_ERROR("dhcpd_ip_end adress setting failed\n");
3822 			return false;
3823 		}
3824 		memcpy(&conf->dhcpd_ip_end, &ipa_set, sizeof(struct ipv4_addr));
3825 		CONFIG_MSG("dhcpd_ip_end = %s\n", data);
3826 	}
3827 	else
3828 		return false;
3829 
3830 	return true;
3831 }
3832 #endif
3833 
3834 #ifdef BCMSDIO
3835 bool
dhd_conf_read_sdio_params(dhd_pub_t * dhd,char * full_param,uint len_param)3836 dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param)
3837 {
3838 	struct dhd_conf *conf = dhd->conf;
3839 	char *data = full_param+len_param;
3840 
3841 	if (!strncmp("dhd_doflow=", full_param, len_param)) {
3842 		if (!strncmp(data, "0", 1))
3843 			dhd_doflow = FALSE;
3844 		else
3845 			dhd_doflow = TRUE;
3846 		CONFIG_MSG("dhd_doflow = %d\n", dhd_doflow);
3847 	}
3848 	else if (!strncmp("dhd_slpauto=", full_param, len_param) ||
3849 			!strncmp("kso_enable=", full_param, len_param)) {
3850 		if (!strncmp(data, "0", 1))
3851 			dhd_slpauto = FALSE;
3852 		else
3853 			dhd_slpauto = TRUE;
3854 		CONFIG_MSG("dhd_slpauto = %d\n", dhd_slpauto);
3855 	}
3856 	else if (!strncmp("use_rxchain=", full_param, len_param)) {
3857 		conf->use_rxchain = (int)simple_strtol(data, NULL, 10);
3858 		CONFIG_MSG("use_rxchain = %d\n", conf->use_rxchain);
3859 	}
3860 	else if (!strncmp("dhd_txminmax=", full_param, len_param)) {
3861 		conf->dhd_txminmax = (uint)simple_strtol(data, NULL, 10);
3862 		CONFIG_MSG("dhd_txminmax = %d\n", conf->dhd_txminmax);
3863 	}
3864 	else if (!strncmp("txinrx_thres=", full_param, len_param)) {
3865 		conf->txinrx_thres = (int)simple_strtol(data, NULL, 10);
3866 		CONFIG_MSG("txinrx_thres = %d\n", conf->txinrx_thres);
3867 	}
3868 #ifdef DYNAMIC_MAX_HDR_READ
3869 	else if (!strncmp("max_hdr_read=", full_param, len_param)) {
3870 		conf->max_hdr_read = (int)simple_strtol(data, NULL, 10);
3871 		CONFIG_MSG("max_hdr_read = %d\n", conf->max_hdr_read);
3872 	}
3873 	else if (!strncmp("dhd_firstread=", full_param, len_param)) {
3874 		firstread = (int)simple_strtol(data, NULL, 10);
3875 		CONFIG_MSG("dhd_firstread = %d\n", firstread);
3876 	}
3877 #endif
3878 #if defined(HW_OOB)
3879 	else if (!strncmp("oob_enabled_later=", full_param, len_param)) {
3880 		if (!strncmp(data, "0", 1))
3881 			conf->oob_enabled_later = FALSE;
3882 		else
3883 			conf->oob_enabled_later = TRUE;
3884 		CONFIG_MSG("oob_enabled_later = %d\n", conf->oob_enabled_later);
3885 	}
3886 #endif
3887 	else if (!strncmp("dpc_cpucore=", full_param, len_param)) {
3888 		conf->dpc_cpucore = (int)simple_strtol(data, NULL, 10);
3889 		CONFIG_MSG("dpc_cpucore = %d\n", conf->dpc_cpucore);
3890 	}
3891 	else if (!strncmp("rxf_cpucore=", full_param, len_param)) {
3892 		conf->rxf_cpucore = (int)simple_strtol(data, NULL, 10);
3893 		CONFIG_MSG("rxf_cpucore = %d\n", conf->rxf_cpucore);
3894 	}
3895 	else if (!strncmp("dhd_dpc_prio=", full_param, len_param)) {
3896 		conf->dhd_dpc_prio = (int)simple_strtol(data, NULL, 10);
3897 		CONFIG_MSG("dhd_dpc_prio = %d\n", conf->dhd_dpc_prio);
3898 	}
3899 #if defined(BCMSDIOH_TXGLOM)
3900 	else if (!strncmp("txglomsize=", full_param, len_param)) {
3901 		conf->txglomsize = (uint)simple_strtol(data, NULL, 10);
3902 		if (conf->txglomsize > SDPCM_MAXGLOM_SIZE)
3903 			conf->txglomsize = SDPCM_MAXGLOM_SIZE;
3904 		CONFIG_MSG("txglomsize = %d\n", conf->txglomsize);
3905 	}
3906 	else if (!strncmp("txglom_ext=", full_param, len_param)) {
3907 		if (!strncmp(data, "0", 1))
3908 			conf->txglom_ext = FALSE;
3909 		else
3910 			conf->txglom_ext = TRUE;
3911 		CONFIG_MSG("txglom_ext = %d\n", conf->txglom_ext);
3912 		if (conf->txglom_ext) {
3913 			if ((conf->chip == BCM43362_CHIP_ID) || (conf->chip == BCM4330_CHIP_ID))
3914 				conf->txglom_bucket_size = 1680;
3915 			else if (conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID ||
3916 					conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID)
3917 				conf->txglom_bucket_size = 1684;
3918 		}
3919 		CONFIG_MSG("txglom_bucket_size = %d\n", conf->txglom_bucket_size);
3920 	}
3921 	else if (!strncmp("bus:rxglom=", full_param, len_param)) {
3922 		if (!strncmp(data, "0", 1))
3923 			conf->bus_rxglom = FALSE;
3924 		else
3925 			conf->bus_rxglom = TRUE;
3926 		CONFIG_MSG("bus:rxglom = %d\n", conf->bus_rxglom);
3927 	}
3928 	else if (!strncmp("deferred_tx_len=", full_param, len_param)) {
3929 		conf->deferred_tx_len = (int)simple_strtol(data, NULL, 10);
3930 		CONFIG_MSG("deferred_tx_len = %d\n", conf->deferred_tx_len);
3931 	}
3932 	else if (!strncmp("txctl_tmo_fix=", full_param, len_param)) {
3933 		conf->txctl_tmo_fix = (int)simple_strtol(data, NULL, 0);
3934 		CONFIG_MSG("txctl_tmo_fix = %d\n", conf->txctl_tmo_fix);
3935 	}
3936 	else if (!strncmp("tx_max_offset=", full_param, len_param)) {
3937 		conf->tx_max_offset = (int)simple_strtol(data, NULL, 10);
3938 		CONFIG_MSG("tx_max_offset = %d\n", conf->tx_max_offset);
3939 	}
3940 	else if (!strncmp("txglom_mode=", full_param, len_param)) {
3941 		if (!strncmp(data, "0", 1))
3942 			conf->txglom_mode = FALSE;
3943 		else
3944 			conf->txglom_mode = TRUE;
3945 		CONFIG_MSG("txglom_mode = %d\n", conf->txglom_mode);
3946 	}
3947 #if defined(SDIO_ISR_THREAD)
3948 	else if (!strncmp("intr_extn=", full_param, len_param)) {
3949 		if (!strncmp(data, "0", 1))
3950 			conf->intr_extn = FALSE;
3951 		else
3952 			conf->intr_extn = TRUE;
3953 		CONFIG_MSG("intr_extn = %d\n", conf->intr_extn);
3954 	}
3955 #endif
3956 #ifdef BCMSDIO_RXLIM_POST
3957 	else if (!strncmp("rxlim_en=", full_param, len_param)) {
3958 		if (!strncmp(data, "0", 1))
3959 			conf->rxlim_en = FALSE;
3960 		else
3961 			conf->rxlim_en = TRUE;
3962 		CONFIG_MSG("rxlim_en = %d\n", conf->rxlim_en);
3963 	}
3964 #endif
3965 #ifdef BCMSDIO_TXSEQ_SYNC
3966 	else if (!strncmp("txseq_sync=", full_param, len_param)) {
3967 		if (!strncmp(data, "0", 1))
3968 			conf->txseq_sync = FALSE;
3969 		else
3970 			conf->txseq_sync = TRUE;
3971 		CONFIG_MSG("txseq_sync = %d\n", conf->txseq_sync);
3972 	}
3973 #endif
3974 #endif
3975 #ifdef MINIME
3976 	else if (!strncmp("ramsize=", full_param, len_param)) {
3977 		conf->ramsize = (uint32)simple_strtol(data, NULL, 0);
3978 		CONFIG_MSG("ramsize = %d\n", conf->ramsize);
3979 	}
3980 #endif
3981 #ifdef BCMSDIO_INTSTATUS_WAR
3982 	else if (!strncmp("read_intr_mode=", full_param, len_param)) {
3983 		conf->read_intr_mode = (int)simple_strtol(data, NULL, 0);
3984 		CONFIG_MSG("read_intr_mode = %d\n", conf->read_intr_mode);
3985 	}
3986 #endif
3987 	else if (!strncmp("kso_try_max=", full_param, len_param)) {
3988 		conf->kso_try_max = (int)simple_strtol(data, NULL, 0);
3989 		CONFIG_MSG("kso_try_max = %d\n", conf->kso_try_max);
3990 	}
3991 	else
3992 		return false;
3993 
3994 	return true;
3995 }
3996 #endif
3997 
3998 #ifdef BCMPCIE
3999 bool
dhd_conf_read_pcie_params(dhd_pub_t * dhd,char * full_param,uint len_param)4000 dhd_conf_read_pcie_params(dhd_pub_t *dhd, char *full_param, uint len_param)
4001 {
4002 	struct dhd_conf *conf = dhd->conf;
4003 	char *data = full_param+len_param;
4004 
4005 	if (!strncmp("bus:deepsleep_disable=", full_param, len_param)) {
4006 		if (!strncmp(data, "0", 1))
4007 			conf->bus_deepsleep_disable = 0;
4008 		else
4009 			conf->bus_deepsleep_disable = 1;
4010 		CONFIG_MSG("bus:deepsleep_disable = %d\n", conf->bus_deepsleep_disable);
4011 	}
4012 	else if (!strncmp("flow_ring_queue_threshold=", full_param, len_param)) {
4013 		conf->flow_ring_queue_threshold = (int)simple_strtol(data, NULL, 10);
4014 		CONFIG_MSG("flow_ring_queue_threshold = %d\n", conf->flow_ring_queue_threshold);
4015 	}
4016 	else if (!strncmp("d2h_intr_control=", full_param, len_param)) {
4017 		conf->d2h_intr_control = (int)simple_strtol(data, NULL, 10);
4018 		CONFIG_MSG("d2h_intr_control = %d\n", conf->d2h_intr_control);
4019 	}
4020 	else if (!strncmp("enq_hdr_pkt=", full_param, len_param)) {
4021 		conf->enq_hdr_pkt = (int)simple_strtol(data, NULL, 0);
4022 		CONFIG_MSG("enq_hdr_pkt = 0x%x\n", conf->enq_hdr_pkt);
4023 	}
4024 	else
4025 		return false;
4026 
4027 	return true;
4028 }
4029 #endif
4030 
4031 bool
dhd_conf_read_pm_params(dhd_pub_t * dhd,char * full_param,uint len_param)4032 dhd_conf_read_pm_params(dhd_pub_t *dhd, char *full_param, uint len_param)
4033 {
4034 	struct dhd_conf *conf = dhd->conf;
4035 	char *data = full_param+len_param;
4036 
4037 	if (!strncmp("deepsleep=", full_param, len_param)) {
4038 		if (!strncmp(data, "1", 1))
4039 			conf->deepsleep = TRUE;
4040 		else
4041 			conf->deepsleep = FALSE;
4042 		CONFIG_MSG("deepsleep = %d\n", conf->deepsleep);
4043 	}
4044 	else if (!strncmp("PM=", full_param, len_param)) {
4045 		conf->pm = (int)simple_strtol(data, NULL, 10);
4046 		CONFIG_MSG("PM = %d\n", conf->pm);
4047 	}
4048 	else if (!strncmp("pm_in_suspend=", full_param, len_param)) {
4049 		conf->pm_in_suspend = (int)simple_strtol(data, NULL, 10);
4050 		CONFIG_MSG("pm_in_suspend = %d\n", conf->pm_in_suspend);
4051 	}
4052 	else if (!strncmp("suspend_mode=", full_param, len_param)) {
4053 		conf->suspend_mode = (int)simple_strtol(data, NULL, 0);
4054 		CONFIG_MSG("suspend_mode = %d\n", conf->suspend_mode);
4055 		if (conf->suspend_mode == EARLY_SUSPEND)
4056 			conf->insuspend &= ~(NO_TXDATA_IN_SUSPEND | NO_TXCTL_IN_SUSPEND);
4057 		else if (conf->suspend_mode == PM_NOTIFIER ||
4058 				conf->suspend_mode == SUSPEND_MODE_2)
4059 			conf->insuspend |= (NO_TXDATA_IN_SUSPEND | NO_TXCTL_IN_SUSPEND);
4060 		CONFIG_MSG("insuspend = 0x%x\n", conf->insuspend);
4061 	}
4062 	else if (!strncmp("suspend_bcn_li_dtim=", full_param, len_param)) {
4063 		conf->suspend_bcn_li_dtim = (int)simple_strtol(data, NULL, 10);
4064 		CONFIG_MSG("suspend_bcn_li_dtim = %d\n", conf->suspend_bcn_li_dtim);
4065 	}
4066 	else if (!strncmp("xmit_in_suspend=", full_param, len_param)) {
4067 		if (!strncmp(data, "1", 1))
4068 			conf->insuspend &= ~NO_TXDATA_IN_SUSPEND;
4069 		else
4070 			conf->insuspend |= NO_TXDATA_IN_SUSPEND;
4071 		CONFIG_MSG("insuspend = 0x%x\n", conf->insuspend);
4072 	}
4073 	else if (!strncmp("insuspend=", full_param, len_param)) {
4074 		conf->insuspend = (int)simple_strtol(data, NULL, 0);
4075 		CONFIG_MSG("insuspend = 0x%x\n", conf->insuspend);
4076 	}
4077 #ifdef WL_EXT_WOWL
4078 	else if (!strncmp("wowl=", full_param, len_param)) {
4079 		conf->wowl = (int)simple_strtol(data, NULL, 0);
4080 		CONFIG_MSG("wowl = 0x%x\n", conf->wowl);
4081 	}
4082 #endif
4083 	else if (!strncmp("rekey_offload=", full_param, len_param)) {
4084 		if (!strncmp(data, "1", 1))
4085 			conf->rekey_offload = TRUE;
4086 		else
4087 			conf->rekey_offload = FALSE;
4088 		CONFIG_MSG("rekey_offload = %d\n", conf->rekey_offload);
4089 	}
4090 	else
4091 		return false;
4092 
4093 	return true;
4094 }
4095 
4096 #ifdef GET_CUSTOM_MAC_FROM_CONFIG
4097 int
bcm_str2hex(const char * p,char * ea,int size)4098 bcm_str2hex(const char *p, char *ea, int size)
4099 {
4100 	int i = 0;
4101 	char *ep;
4102 
4103 	for (;;) {
4104 		ea[i++] = (char) bcm_strtoul(p, &ep, 16);
4105 		p = ep;
4106 		if (!*p++ || i == size)
4107 			break;
4108 	}
4109 
4110 	return (i == size);
4111 }
4112 #endif
4113 
4114 bool
dhd_conf_read_others(dhd_pub_t * dhd,char * full_param,uint len_param)4115 dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param)
4116 {
4117 	struct dhd_conf *conf = dhd->conf;
4118 	char *data = full_param+len_param;
4119 	char *pch, *pick_tmp;
4120 	int i;
4121 #ifdef GET_CUSTOM_MAC_FROM_CONFIG
4122 	struct ether_addr ea_addr;
4123 	char macpad[56];
4124 #endif
4125 
4126 	if (!strncmp("dhd_poll=", full_param, len_param)) {
4127 		if (!strncmp(data, "0", 1))
4128 			conf->dhd_poll = 0;
4129 		else
4130 			conf->dhd_poll = 1;
4131 		CONFIG_MSG("dhd_poll = %d\n", conf->dhd_poll);
4132 	}
4133 	else if (!strncmp("dhd_watchdog_ms=", full_param, len_param)) {
4134 		dhd_watchdog_ms = (int)simple_strtol(data, NULL, 10);
4135 		CONFIG_MSG("dhd_watchdog_ms = %d\n", dhd_watchdog_ms);
4136 	}
4137 	else if (!strncmp("band=", full_param, len_param)) {
4138 		/* Process band:
4139 		 * band=a for 5GHz only and band=b for 2.4GHz only
4140 		 */
4141 		if (!strcmp(data, "b"))
4142 			conf->band = WLC_BAND_2G;
4143 		else if (!strcmp(data, "a"))
4144 			conf->band = WLC_BAND_5G;
4145 		else
4146 			conf->band = WLC_BAND_AUTO;
4147 		CONFIG_MSG("band = %d\n", conf->band);
4148 	}
4149 	else if (!strncmp("bw_cap_2g=", full_param, len_param)) {
4150 		conf->bw_cap[0] = (uint)simple_strtol(data, NULL, 0);
4151 		CONFIG_MSG("bw_cap_2g = %d\n", conf->bw_cap[0]);
4152 	}
4153 	else if (!strncmp("bw_cap_5g=", full_param, len_param)) {
4154 		conf->bw_cap[1] = (uint)simple_strtol(data, NULL, 0);
4155 		CONFIG_MSG("bw_cap_5g = %d\n", conf->bw_cap[1]);
4156 	}
4157 	else if (!strncmp("bw_cap=", full_param, len_param)) {
4158 		pick_tmp = data;
4159 		pch = bcmstrtok(&pick_tmp, " ,.-", 0);
4160 		if (pch != NULL) {
4161 			conf->bw_cap[0] = (uint32)simple_strtol(pch, NULL, 0);
4162 			CONFIG_MSG("bw_cap 2g = %d\n", conf->bw_cap[0]);
4163 		}
4164 		pch = bcmstrtok(&pick_tmp, " ,.-", 0);
4165 		if (pch != NULL) {
4166 			conf->bw_cap[1] = (uint32)simple_strtol(pch, NULL, 0);
4167 			CONFIG_MSG("bw_cap 5g = %d\n", conf->bw_cap[1]);
4168 		}
4169 	}
4170 	else if (!strncmp("channels=", full_param, len_param)) {
4171 		pick_tmp = data;
4172 		pch = bcmstrtok(&pick_tmp, " ,.-", 0);
4173 		i=0;
4174 		while (pch != NULL && i<WL_NUMCHANNELS) {
4175 			conf->channels.channel[i] = (uint32)simple_strtol(pch, NULL, 10);
4176 			pch = bcmstrtok(&pick_tmp, " ,.-", 0);
4177 			i++;
4178 		}
4179 		conf->channels.count = i;
4180 		CONFIG_MSG("channels = ");
4181 		for (i=0; i<conf->channels.count; i++)
4182 			printk(KERN_CONT "%d ", conf->channels.channel[i]);
4183 		printk(KERN_CONT "\n");
4184 	}
4185 	else if (!strncmp("keep_alive_period=", full_param, len_param)) {
4186 		conf->keep_alive_period = (uint)simple_strtol(data, NULL, 10);
4187 		CONFIG_MSG("keep_alive_period = %d\n", conf->keep_alive_period);
4188 	}
4189 #ifdef ARP_OFFLOAD_SUPPORT
4190 	else if (!strncmp("garp=", full_param, len_param)) {
4191 		if (!strncmp(data, "0", 1))
4192 			conf->garp = FALSE;
4193 		else
4194 			conf->garp = TRUE;
4195 		CONFIG_MSG("garp = %d\n", conf->garp);
4196 	}
4197 #endif
4198 	else if (!strncmp("srl=", full_param, len_param)) {
4199 		conf->srl = (int)simple_strtol(data, NULL, 10);
4200 		CONFIG_MSG("srl = %d\n", conf->srl);
4201 	}
4202 	else if (!strncmp("lrl=", full_param, len_param)) {
4203 		conf->lrl = (int)simple_strtol(data, NULL, 10);
4204 		CONFIG_MSG("lrl = %d\n", conf->lrl);
4205 	}
4206 	else if (!strncmp("bcn_timeout=", full_param, len_param)) {
4207 		conf->bcn_timeout= (uint)simple_strtol(data, NULL, 10);
4208 		CONFIG_MSG("bcn_timeout = %d\n", conf->bcn_timeout);
4209 	}
4210 	else if (!strncmp("frameburst=", full_param, len_param)) {
4211 		conf->frameburst = (int)simple_strtol(data, NULL, 10);
4212 		CONFIG_MSG("frameburst = %d\n", conf->frameburst);
4213 	}
4214 	else if (!strncmp("disable_proptx=", full_param, len_param)) {
4215 		conf->disable_proptx = (int)simple_strtol(data, NULL, 10);
4216 		CONFIG_MSG("disable_proptx = %d\n", conf->disable_proptx);
4217 	}
4218 #ifdef DHDTCPACK_SUPPRESS
4219 	else if (!strncmp("tcpack_sup_mode=", full_param, len_param)) {
4220 		conf->tcpack_sup_mode = (uint)simple_strtol(data, NULL, 10);
4221 		CONFIG_MSG("tcpack_sup_mode = %d\n", conf->tcpack_sup_mode);
4222 	}
4223 	else if (!strncmp("tcpack_sup_ratio=", full_param, len_param)) {
4224 		conf->tcpack_sup_ratio = (uint)simple_strtol(data, NULL, 10);
4225 		CONFIG_MSG("tcpack_sup_ratio = %d\n", conf->tcpack_sup_ratio);
4226 	}
4227 	else if (!strncmp("tcpack_sup_delay=", full_param, len_param)) {
4228 		conf->tcpack_sup_delay = (uint)simple_strtol(data, NULL, 10);
4229 		CONFIG_MSG("tcpack_sup_delay = %d\n", conf->tcpack_sup_delay);
4230 	}
4231 #endif
4232 	else if (!strncmp("pktprio8021x=", full_param, len_param)) {
4233 		conf->pktprio8021x = (int)simple_strtol(data, NULL, 10);
4234 		CONFIG_MSG("pktprio8021x = %d\n", conf->pktprio8021x);
4235 	}
4236 #if defined(BCMSDIO) || defined(BCMPCIE)
4237 	else if (!strncmp("dhd_txbound=", full_param, len_param)) {
4238 		dhd_txbound = (uint)simple_strtol(data, NULL, 10);
4239 		CONFIG_MSG("dhd_txbound = %d\n", dhd_txbound);
4240 	}
4241 	else if (!strncmp("dhd_rxbound=", full_param, len_param)) {
4242 		dhd_rxbound = (uint)simple_strtol(data, NULL, 10);
4243 		CONFIG_MSG("dhd_rxbound = %d\n", dhd_rxbound);
4244 	}
4245 #endif
4246 	else if (!strncmp("orphan_move=", full_param, len_param)) {
4247 		conf->orphan_move = (int)simple_strtol(data, NULL, 10);
4248 		CONFIG_MSG("orphan_move = %d\n", conf->orphan_move);
4249 	}
4250 	else if (!strncmp("tsq=", full_param, len_param)) {
4251 		conf->tsq = (int)simple_strtol(data, NULL, 10);
4252 		CONFIG_MSG("tsq = %d\n", conf->tsq);
4253 	}
4254 	else if (!strncmp("ctrl_resched=", full_param, len_param)) {
4255 		conf->ctrl_resched = (int)simple_strtol(data, NULL, 10);
4256 		CONFIG_MSG("ctrl_resched = %d\n", conf->ctrl_resched);
4257 	}
4258 	else if (!strncmp("rxcnt_timeout=", full_param, len_param)) {
4259 		conf->rxcnt_timeout = (int)simple_strtol(data, NULL, 10);
4260 		CONFIG_MSG("rxcnt_timeout = %d\n", conf->rxcnt_timeout);
4261 	}
4262 	else if (!strncmp("in4way=", full_param, len_param)) {
4263 		conf->in4way = (int)simple_strtol(data, NULL, 0);
4264 		CONFIG_MSG("in4way = 0x%x\n", conf->in4way);
4265 	}
4266 	else if (!strncmp("war=", full_param, len_param)) {
4267 		conf->war = (int)simple_strtol(data, NULL, 0);
4268 		CONFIG_MSG("war = 0x%x\n", conf->war);
4269 	}
4270 	else if (!strncmp("wl_preinit=", full_param, len_param)) {
4271 		if (conf->wl_preinit) {
4272 			kfree(conf->wl_preinit);
4273 			conf->wl_preinit = NULL;
4274 		}
4275 		if (!(conf->wl_preinit = kmalloc(strlen(data)+1, GFP_KERNEL))) {
4276 			CONFIG_ERROR("kmalloc failed\n");
4277 		} else {
4278 			memset(conf->wl_preinit, 0, strlen(data)+1);
4279 			strcpy(conf->wl_preinit, data);
4280 			CONFIG_MSG("wl_preinit = %s\n", conf->wl_preinit);
4281 		}
4282 	}
4283 	else if (!strncmp("wl_suspend=", full_param, len_param)) {
4284 		if (conf->wl_suspend) {
4285 			kfree(conf->wl_suspend);
4286 			conf->wl_suspend = NULL;
4287 		}
4288 		if (!(conf->wl_suspend = kmalloc(strlen(data)+1, GFP_KERNEL))) {
4289 			CONFIG_ERROR("kmalloc failed\n");
4290 		} else {
4291 			memset(conf->wl_suspend, 0, strlen(data)+1);
4292 			strcpy(conf->wl_suspend, data);
4293 			CONFIG_MSG("wl_suspend = %s\n", conf->wl_suspend);
4294 		}
4295 	}
4296 	else if (!strncmp("wl_resume=", full_param, len_param)) {
4297 		if (conf->wl_resume) {
4298 			kfree(conf->wl_resume);
4299 			conf->wl_resume = NULL;
4300 		}
4301 		if (!(conf->wl_resume = kmalloc(strlen(data)+1, GFP_KERNEL))) {
4302 			CONFIG_ERROR("kmalloc failed\n");
4303 		} else {
4304 			memset(conf->wl_resume, 0, strlen(data)+1);
4305 			strcpy(conf->wl_resume, data);
4306 			CONFIG_MSG("wl_resume = %s\n", conf->wl_resume);
4307 		}
4308 	}
4309 #ifdef GET_CUSTOM_MAC_FROM_CONFIG
4310 	else if (!strncmp("mac=", full_param, len_param)) {
4311 		if (!bcm_ether_atoe(data, &ea_addr)) {
4312 			CONFIG_ERROR("mac adress read error");
4313 			return false;
4314 		}
4315 		memcpy(&conf->hw_ether, &ea_addr, ETHER_ADDR_LEN);
4316 		CONFIG_MSG("mac = %s\n", data);
4317 	}
4318 	else if (!strncmp("macpad=", full_param, len_param)) {
4319 		if (!bcm_str2hex(data, macpad, sizeof(macpad))) {
4320 			CONFIG_ERROR("macpad adress read error");
4321 			return false;
4322 		}
4323 		memcpy(&conf->hw_ether[ETHER_ADDR_LEN], macpad, sizeof(macpad));
4324 		if (config_msg_level & CONFIG_TRACE_LEVEL) {
4325 			CONFIG_MSG("macpad =\n");
4326 			for (i=0; i<sizeof(macpad); i++) {
4327 				printk(KERN_CONT "0x%02x, ", conf->hw_ether[ETHER_ADDR_LEN+i]);
4328 				if ((i+1)%8 == 0)
4329 					printk(KERN_CONT "\n");
4330 			}
4331 		}
4332 	}
4333 #endif
4334 #ifdef PROPTX_MAXCOUNT
4335 	else if (!strncmp("proptx_maxcnt_2g=", full_param, len_param)) {
4336 		conf->proptx_maxcnt_2g = (int)simple_strtol(data, NULL, 0);
4337 		CONFIG_MSG("proptx_maxcnt_2g = %d\n", conf->proptx_maxcnt_2g);
4338 	}
4339 	else if (!strncmp("proptx_maxcnt_5g=", full_param, len_param)) {
4340 		conf->proptx_maxcnt_5g = (int)simple_strtol(data, NULL, 0);
4341 		CONFIG_MSG("proptx_maxcnt_5g = %d\n", conf->proptx_maxcnt_5g);
4342 	}
4343 #endif
4344 #ifdef TPUT_MONITOR
4345 	else if (!strncmp("data_drop_mode=", full_param, len_param)) {
4346 		conf->data_drop_mode = (int)simple_strtol(data, NULL, 0);
4347 		CONFIG_MSG("data_drop_mode = %d\n", conf->data_drop_mode);
4348 	}
4349 	else if (!strncmp("tput_monitor_ms=", full_param, len_param)) {
4350 		conf->tput_monitor_ms = (int)simple_strtol(data, NULL, 0);
4351 		CONFIG_MSG("tput_monitor_ms = %d\n", conf->tput_monitor_ms);
4352 	}
4353 #ifdef BCMSDIO
4354 	else if (!strncmp("doflow_tput_thresh=", full_param, len_param)) {
4355 		conf->doflow_tput_thresh = (int)simple_strtol(data, NULL, 0);
4356 		CONFIG_MSG("doflow_tput_thresh = %d\n", conf->doflow_tput_thresh);
4357 		if (conf->doflow_tput_thresh > 0)
4358 			conf->tput_monitor_ms = 1000;
4359 	}
4360 #endif
4361 #endif
4362 #ifdef SCAN_SUPPRESS
4363 	else if (!strncmp("scan_intput=", full_param, len_param)) {
4364 		conf->scan_intput = (int)simple_strtol(data, NULL, 0);
4365 		CONFIG_MSG("scan_intput = 0x%x\n", conf->scan_intput);
4366 	}
4367 	else if (!strncmp("scan_tput_thresh=", full_param, len_param)) {
4368 		conf->scan_tput_thresh = (int)simple_strtol(data, NULL, 0);
4369 		CONFIG_MSG("scan_tput_thresh = %d\n", conf->scan_tput_thresh);
4370 		if (conf->scan_tput_thresh > 0)
4371 			conf->tput_monitor_ms = 1000;
4372 	}
4373 	else if (!strncmp("scan_busy_tmo=", full_param, len_param)) {
4374 		conf->scan_busy_tmo = (int)simple_strtol(data, NULL, 0);
4375 		CONFIG_MSG("scan_busy_tmo = %d\n", conf->scan_busy_tmo);
4376 	}
4377 	else if (!strncmp("scan_busy_thresh=", full_param, len_param)) {
4378 		conf->scan_busy_thresh = (int)simple_strtol(data, NULL, 0);
4379 		CONFIG_MSG("scan_busy_thresh = %d\n", conf->scan_busy_thresh);
4380 	}
4381 #endif
4382 #ifdef DHD_TPUT_PATCH
4383 	else if (!strncmp("tput_patch=", full_param, len_param)) {
4384 		if (!strncmp(data, "1", 1))
4385 			conf->tput_patch = TRUE;
4386 		else
4387 			conf->tput_patch = FALSE;
4388 		CONFIG_MSG("tput_patch = %d\n", conf->tput_patch);
4389 		dhd_conf_set_tput_patch(dhd);
4390 	}
4391 	else if (!strncmp("mtu=", full_param, len_param)) {
4392 		conf->mtu = (int)simple_strtol(data, NULL, 0);
4393 		CONFIG_MSG("mtu = %d\n", conf->mtu);
4394 	}
4395 	else if (!strncmp("pktsetsum=", full_param, len_param)) {
4396 		if (!strncmp(data, "1", 1))
4397 			conf->pktsetsum = TRUE;
4398 		else
4399 			conf->pktsetsum = FALSE;
4400 		CONFIG_MSG("pktsetsum = %d\n", conf->pktsetsum);
4401 	}
4402 #endif
4403 #ifdef SET_XPS_CPUS
4404 	else if (!strncmp("xps_cpus=", full_param, len_param)) {
4405 		if (!strncmp(data, "1", 1))
4406 			conf->xps_cpus = TRUE;
4407 		else
4408 			conf->xps_cpus = FALSE;
4409 		CONFIG_MSG("xps_cpus = %d\n", conf->xps_cpus);
4410 	}
4411 #endif
4412 #ifdef SET_RPS_CPUS
4413 	else if (!strncmp("rps_cpus=", full_param, len_param)) {
4414 		if (!strncmp(data, "1", 1))
4415 			conf->rps_cpus = TRUE;
4416 		else
4417 			conf->rps_cpus = FALSE;
4418 		CONFIG_MSG("rps_cpus = %d\n", conf->rps_cpus);
4419 	}
4420 #endif
4421 #ifdef CHECK_DOWNLOAD_FW
4422 	else if (!strncmp("fwchk=", full_param, len_param)) {
4423 		if (!strncmp(data, "1", 1))
4424 			conf->fwchk = TRUE;
4425 		else
4426 			conf->fwchk = FALSE;
4427 		CONFIG_MSG("fwchk = %d\n", conf->fwchk);
4428 	}
4429 #endif
4430 	else if (!strncmp("vndr_ie_assocreq=", full_param, len_param)) {
4431 		if (conf->vndr_ie_assocreq) {
4432 			kfree(conf->vndr_ie_assocreq);
4433 			conf->vndr_ie_assocreq = NULL;
4434 		}
4435 		if (!(conf->vndr_ie_assocreq = kmalloc(strlen(data)+1, GFP_KERNEL))) {
4436 			CONFIG_ERROR("kmalloc failed\n");
4437 		} else {
4438 			memset(conf->vndr_ie_assocreq, 0, strlen(data)+1);
4439 			strcpy(conf->vndr_ie_assocreq, data);
4440 			CONFIG_MSG("vndr_ie_assocreq = %s\n", conf->vndr_ie_assocreq);
4441 		}
4442 	}
4443 	else
4444 		return false;
4445 
4446 	return true;
4447 }
4448 
4449 int
dhd_conf_read_config(dhd_pub_t * dhd,char * conf_path)4450 dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path)
4451 {
4452 	int bcmerror = -1, chip_match = -1;
4453 	uint len = 0, memblock_len = 0, start_pos=0, end_pos=0;
4454 	char *memblock = NULL;
4455 	char *bufp, *pick = NULL, *pch;
4456 	bool conf_file_exists;
4457 	uint len_param;
4458 
4459 	len = MAXSZ_CONFIG;
4460 
4461 	conf_file_exists = ((conf_path != NULL) && (conf_path[0] != '\0'));
4462 	if (!conf_file_exists) {
4463 		CONFIG_MSG("config path %s\n", conf_path);
4464 		return (0);
4465 	}
4466 
4467 	if (conf_file_exists)
4468 		bcmerror = dhd_get_download_buffer(dhd, conf_path, NVRAM, &memblock,
4469 			(int *)&len);
4470 	else
4471 		bcmerror = dhd_get_download_buffer(dhd, NULL, NVRAM, &memblock, (int *)&len);
4472 
4473 	if (bcmerror != BCME_OK) {
4474 		CONFIG_MSG("Ignore config file %s\n", conf_path);
4475 		goto err;
4476 	}
4477 
4478 #ifdef DHD_LINUX_STD_FW_API
4479 	memblock_len = len;
4480 #else
4481 	memblock_len = MAXSZ_CONFIG;
4482 #endif /* DHD_LINUX_STD_FW_API */
4483 
4484 	pick = MALLOC(dhd->osh, MAXSZ_BUF);
4485 	if (!pick) {
4486 		CONFIG_ERROR("Failed to allocate memory %d bytes\n", MAXSZ_BUF);
4487 		goto err;
4488 	}
4489 
4490 	/* Read variables */
4491 	if (len > 0 && len < MAXSZ_CONFIG) {
4492 		bufp = (char *)memblock;
4493 		bufp[len] = 0;
4494 
4495 		while (start_pos < len) {
4496 			memset(pick, 0, MAXSZ_BUF);
4497 			end_pos = pick_config_vars(bufp, len, start_pos, pick, MAXSZ_BUF);
4498 			if (end_pos - start_pos >= MAXSZ_BUF)
4499 				CONFIG_ERROR("out of buf to read MAXSIZ_BUF=%d\n", MAXSZ_BUF);
4500 			start_pos = end_pos;
4501 			pch = strchr(pick, '=');
4502 			if (pch != NULL) {
4503 				len_param = pch-pick+1;
4504 				if (len_param == strlen(pick)) {
4505 					CONFIG_ERROR("not a right parameter %s\n", pick);
4506 					continue;
4507 				}
4508 			} else {
4509 				CONFIG_ERROR("not a right parameter %s\n", pick);
4510 				continue;
4511 			}
4512 
4513 			dhd_conf_read_chiprev(dhd, &chip_match, pick, len_param);
4514 			if (!chip_match)
4515 				continue;
4516 
4517 			if (dhd_conf_read_log_level(dhd, pick, len_param))
4518 				continue;
4519 			else if (dhd_conf_read_roam_params(dhd, pick, len_param))
4520 				continue;
4521 			else if (dhd_conf_read_wme_ac_params(dhd, pick, len_param))
4522 				continue;
4523 #ifdef SET_FWNV_BY_MAC
4524 			else if (dhd_conf_read_fw_by_mac(dhd, pick, len_param))
4525 				continue;
4526 			else if (dhd_conf_read_nv_by_mac(dhd, pick, len_param))
4527 				continue;
4528 #endif
4529 			else if (dhd_conf_read_nv_by_chip(dhd, pick, len_param))
4530 				continue;
4531 			else if (dhd_conf_read_country(dhd, pick, len_param))
4532 				continue;
4533 			else if (dhd_conf_read_mchan_params(dhd, pick, len_param))
4534 				continue;
4535 #ifdef PKT_FILTER_SUPPORT
4536 			else if (dhd_conf_read_pkt_filter(dhd, pick, len_param))
4537 				continue;
4538 #endif /* PKT_FILTER_SUPPORT */
4539 #ifdef ISAM_PREINIT
4540 			else if (dhd_conf_read_isam(dhd, pick, len_param))
4541 				continue;
4542 #endif /* ISAM_PREINIT */
4543 #ifdef IDHCP
4544 			else if (dhd_conf_read_dhcp_params(dhd, pick, len_param))
4545 				continue;
4546 #endif /* IDHCP */
4547 #ifdef BCMSDIO
4548 			else if (dhd_conf_read_sdio_params(dhd, pick, len_param))
4549 				continue;
4550 #endif /* BCMSDIO */
4551 #ifdef BCMPCIE
4552 			else if (dhd_conf_read_pcie_params(dhd, pick, len_param))
4553 				continue;
4554 #endif /* BCMPCIE */
4555 			else if (dhd_conf_read_pm_params(dhd, pick, len_param))
4556 				continue;
4557 			else if (dhd_conf_read_others(dhd, pick, len_param))
4558 				continue;
4559 			else
4560 				continue;
4561 		}
4562 
4563 		bcmerror = 0;
4564 	} else {
4565 		CONFIG_ERROR("error reading config file: %d\n", len);
4566 		bcmerror = BCME_SDIO_ERROR;
4567 	}
4568 
4569 err:
4570 	if (pick)
4571 		MFREE(dhd->osh, pick, MAXSZ_BUF);
4572 
4573 	if (memblock)
4574 		dhd_free_download_buffer(dhd, memblock, memblock_len);
4575 
4576 	return bcmerror;
4577 }
4578 
4579 #if defined(BCMSDIO) || defined(BCMPCIE)
4580 void
dhd_conf_set_devid(dhd_pub_t * dhd)4581 dhd_conf_set_devid(dhd_pub_t *dhd)
4582 {
4583 	wifi_adapter_info_t *adapter = NULL;
4584 	uint32 bus_type = -1;
4585 	uint32 bus_num = -1;
4586 	uint32 slot_num = -1;
4587 
4588 	dhd_bus_get_ids(dhd->bus, &bus_type, &bus_num, &slot_num);
4589 	adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num);
4590 	if (adapter) {
4591 #if defined(BCMSDIO)
4592 		dhd->conf->devid = adapter->sdio_func->device;
4593 #endif
4594 #if defined(BCMPCIE)
4595 		dhd->conf->devid = adapter->pci_dev->device;
4596 		dhd->conf->svid = adapter->pci_dev->subsystem_vendor;
4597 		dhd->conf->ssid = adapter->pci_dev->subsystem_device;
4598 #endif
4599 	} else {
4600 		CONFIG_ERROR("can't find adapter\n");
4601 	}
4602 
4603 	return;
4604 }
4605 #endif
4606 
4607 int
dhd_conf_set_chiprev(dhd_pub_t * dhd,uint chip,uint chiprev)4608 dhd_conf_set_chiprev(dhd_pub_t *dhd, uint chip, uint chiprev)
4609 {
4610 #if defined(BCMSDIO) || defined(BCMPCIE)
4611 	dhd_conf_set_devid(dhd);
4612 #endif
4613 	dhd->conf->chip = chip;
4614 	dhd->conf->chiprev = chiprev;
4615 
4616 #if defined(BCMSDIO)
4617 	CONFIG_MSG("devid=0x%x, chip=0x%x, chiprev=%d\n",
4618 		dhd->conf->devid, dhd->conf->chip, dhd->conf->chiprev);
4619 #endif
4620 #if defined(BCMPCIE)
4621 	CONFIG_MSG("devid=0x%x, chip=0x%x, chiprev=%d, svid=0x%04x, ssid=0x%04x\n",
4622 		dhd->conf->devid, dhd->conf->chip, dhd->conf->chiprev,
4623 		dhd->conf->svid, dhd->conf->ssid);
4624 #endif
4625 #if defined(BCMDBUS)
4626 	CONFIG_MSG("chip=0x%x, chiprev=%d\n", dhd->conf->chip, dhd->conf->chiprev);
4627 #endif
4628 
4629 	return 0;
4630 }
4631 
4632 uint
dhd_conf_get_chip(void * context)4633 dhd_conf_get_chip(void *context)
4634 {
4635 	dhd_pub_t *dhd = context;
4636 
4637 	if (dhd && dhd->conf)
4638 		return dhd->conf->chip;
4639 	return 0;
4640 }
4641 
4642 uint
dhd_conf_get_chiprev(void * context)4643 dhd_conf_get_chiprev(void *context)
4644 {
4645 	dhd_pub_t *dhd = context;
4646 
4647 	if (dhd && dhd->conf)
4648 		return dhd->conf->chiprev;
4649 	return 0;
4650 }
4651 
4652 #ifdef BCMSDIO
4653 void
dhd_conf_set_txglom_params(dhd_pub_t * dhd,bool enable)4654 dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable)
4655 {
4656 	struct dhd_conf *conf = dhd->conf;
4657 
4658 	if (enable) {
4659 #if defined(BCMSDIOH_TXGLOM_EXT)
4660 		if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID ||
4661 				conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID ||
4662 				conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID) {
4663 			conf->txglom_mode = SDPCM_TXGLOM_CPY;
4664 		}
4665 #endif
4666 		// other parameters set in preinit or config.txt
4667 		if (conf->txglom_ext)
4668 			CONFIG_MSG("txglom_ext=%d, txglom_bucket_size=%d\n",
4669 				conf->txglom_ext, conf->txglom_bucket_size);
4670 		CONFIG_MSG("txglom_mode=%s\n",
4671 			conf->txglom_mode==SDPCM_TXGLOM_MDESC?"multi-desc":"copy");
4672 		CONFIG_MSG("txglomsize=%d, deferred_tx_len=%d\n",
4673 			conf->txglomsize, conf->deferred_tx_len);
4674 		CONFIG_MSG("txinrx_thres=%d, dhd_txminmax=%d\n",
4675 			conf->txinrx_thres, conf->dhd_txminmax);
4676 		CONFIG_MSG("tx_max_offset=%d, txctl_tmo_fix=%d\n",
4677 			conf->tx_max_offset, conf->txctl_tmo_fix);
4678 	} else {
4679 		// clear txglom parameters
4680 		conf->txglom_ext = FALSE;
4681 		conf->txglom_bucket_size = 0;
4682 		conf->txglomsize = 0;
4683 		conf->deferred_tx_len = 0;
4684 	}
4685 
4686 }
4687 #endif
4688 
4689 #ifdef UPDATE_MODULE_NAME
4690 #if defined(BCMSDIO) || defined(BCMPCIE)
4691 static void
dhd_conf_compat_vht(dhd_pub_t * dhd)4692 dhd_conf_compat_vht(dhd_pub_t *dhd)
4693 {
4694 	char vht_features[] = "vht_features=0";
4695 
4696 	CONFIG_TRACE("Enter\n");
4697 
4698 	dhd_conf_set_wl_cmd(dhd, vht_features, TRUE);
4699 }
4700 #endif
4701 
4702 int
dhd_conf_compat_func(dhd_pub_t * dhd)4703 dhd_conf_compat_func(dhd_pub_t *dhd)
4704 {
4705 	const module_name_map_t* row = NULL;
4706 
4707 	row = dhd_conf_match_module(dhd);
4708 	if (row && row->compat_func) {
4709 		row->compat_func(dhd);
4710 	}
4711 
4712 	return 0;
4713 }
4714 #endif
4715 
4716 void
dhd_conf_postinit_ioctls(dhd_pub_t * dhd)4717 dhd_conf_postinit_ioctls(dhd_pub_t *dhd)
4718 {
4719 	struct dhd_conf *conf = dhd->conf;
4720 	char wl_preinit[] = "assoc_retry_max=10";
4721 #ifdef NO_POWER_SAVE
4722 	char wl_no_power_save[] = "mpc=0, 86=0";
4723 	dhd_conf_set_wl_cmd(dhd, wl_no_power_save, FALSE);
4724 #endif
4725 
4726 	dhd_conf_set_intiovar(dhd, 0, WLC_UP, "WLC_UP", 0, 0, FALSE);
4727 	dhd_conf_map_country_list(dhd, &conf->cspec);
4728 	dhd_conf_set_country(dhd, &conf->cspec);
4729 	dhd_conf_fix_country(dhd);
4730 	dhd_conf_get_country(dhd, &dhd->dhd_cspec);
4731 
4732 	dhd_conf_set_intiovar(dhd, 0, WLC_SET_BAND, "WLC_SET_BAND", conf->band, 0, FALSE);
4733 	dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "bcn_timeout", conf->bcn_timeout, 0, FALSE);
4734 	dhd_conf_set_intiovar(dhd, 0, WLC_SET_PM, "WLC_SET_PM", conf->pm, 0, FALSE);
4735 	dhd_conf_set_intiovar(dhd, 0, WLC_SET_SRL, "WLC_SET_SRL", conf->srl, 0, FALSE);
4736 	dhd_conf_set_intiovar(dhd, 0, WLC_SET_LRL, "WLC_SET_LRL", conf->lrl, 0, FALSE);
4737 	dhd_conf_set_bw_cap(dhd);
4738 	dhd_conf_set_roam(dhd);
4739 
4740 #if defined(BCMPCIE)
4741 	dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "bus:deepsleep_disable",
4742 		conf->bus_deepsleep_disable, 0, FALSE);
4743 #endif /* defined(BCMPCIE) */
4744 
4745 #ifdef IDHCP
4746 	dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "dhcpc_enable", conf->dhcpc_enable,
4747 		0, FALSE);
4748 	if (conf->dhcpd_enable >= 0) {
4749 		dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "dhcpd_ip_addr",
4750 			(char *)&conf->dhcpd_ip_addr, sizeof(conf->dhcpd_ip_addr), FALSE);
4751 		dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "dhcpd_ip_mask",
4752 			(char *)&conf->dhcpd_ip_mask, sizeof(conf->dhcpd_ip_mask), FALSE);
4753 		dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "dhcpd_ip_start",
4754 			(char *)&conf->dhcpd_ip_start, sizeof(conf->dhcpd_ip_start), FALSE);
4755 		dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "dhcpd_ip_end",
4756 			(char *)&conf->dhcpd_ip_end, sizeof(conf->dhcpd_ip_end), FALSE);
4757 		dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "dhcpd_enable",
4758 			conf->dhcpd_enable, 0, FALSE);
4759 	}
4760 #endif
4761 	dhd_conf_set_intiovar(dhd, 0, WLC_SET_FAKEFRAG, "WLC_SET_FAKEFRAG",
4762 		conf->frameburst, 0, FALSE);
4763 
4764 	dhd_conf_set_wl_cmd(dhd, wl_preinit, TRUE);
4765 #if defined(BCMSDIO)
4766 	if (conf->chip == BCM43751_CHIP_ID || conf->chip == BCM43752_CHIP_ID) {
4767 		char ampdu_mpdu[] = "ampdu_mpdu=32";
4768 		dhd_conf_set_wl_cmd(dhd, ampdu_mpdu, TRUE);
4769 	} else {
4770 		char ampdu_mpdu[] = "ampdu_mpdu=16";
4771 		dhd_conf_set_wl_cmd(dhd, ampdu_mpdu, TRUE);
4772 	}
4773 #endif
4774 
4775 #ifdef DHD_TPUT_PATCH
4776 	if (dhd->conf->mtu)
4777 		dhd_change_mtu(dhd, dhd->conf->mtu, 0);
4778 #endif
4779 	if (conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID ||
4780 			conf->chip == BCM4371_CHIP_ID || conf->chip == BCM4359_CHIP_ID ||
4781 			conf->chip == BCM43569_CHIP_ID ||
4782 			conf->chip == BCM43751_CHIP_ID || conf->chip == BCM43752_CHIP_ID ||
4783 			conf->chip == BCM4375_CHIP_ID) {
4784 		dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "txbf", 1, 0, FALSE);
4785 	}
4786 	if (conf->chip == BCM4375_CHIP_ID) {
4787 		char he_cmd[] = "110=1, nmode=1, vhtmode=1, he=enab 1";
4788 		dhd_conf_set_wl_cmd(dhd, he_cmd, TRUE);
4789 	}
4790 	if (conf->chip == BCM43752_CHIP_ID || conf->chip == BCM4359_CHIP_ID) {
4791 		char txack_alive[] = "txack_alive=0";
4792 		dhd_conf_set_wl_cmd(dhd, txack_alive, TRUE);
4793 	}
4794 #ifdef WLDWDS
4795 	{
4796 		char dwds[] = "dwds=1";
4797 		dhd_conf_set_wl_cmd(dhd, dwds, TRUE);
4798 	}
4799 #endif /* WLDWDS */
4800 #if defined(WLEASYMESH)
4801 	if (conf->fw_type == FW_TYPE_EZMESH) {
4802 		if (conf->chip == BCM4359_CHIP_ID) {
4803 			char ezmesh[] = "mbss=1, rsdb_mode=0";
4804 			dhd_conf_set_wl_cmd(dhd, ezmesh, TRUE);
4805 		} else {
4806 			char ezmesh[] = "mbss=1";
4807 			dhd_conf_set_wl_cmd(dhd, ezmesh, TRUE);
4808 		}
4809 	}
4810 #endif /* WLEASYMESH */
4811 #if defined(BCMSDIO)
4812 	if (conf->devid == BCM43751_CHIP_ID)
4813 #elif defined(BCMPCIE)
4814 	if (conf->devid == BCM43751_D11AX_ID)
4815 #endif
4816 	{
4817 		if (FW_SUPPORTED(dhd, mbo)) {
4818 			char he_features[] = "he=enab 0,he=features 0";
4819 			dhd_conf_set_wl_cmd(dhd, he_features, TRUE);
4820 		}
4821 	}
4822 #ifdef UPDATE_MODULE_NAME
4823 	dhd_conf_compat_func(dhd);
4824 #endif
4825 #ifndef SUPPORT_RANDOM_MAC_SCAN
4826 	{
4827 		char scanmac[] = "scanmac=enable 0";
4828 		dhd_conf_set_wl_cmd(dhd, scanmac, TRUE);
4829 	}
4830 #endif
4831 	dhd_conf_set_wl_cmd(dhd, conf->wl_preinit, TRUE);
4832 
4833 #ifndef WL_CFG80211
4834 	dhd_conf_set_intiovar(dhd, 0, WLC_UP, "WLC_UP", 0, 0, FALSE);
4835 #endif
4836 
4837 }
4838 
4839 int
dhd_conf_preinit(dhd_pub_t * dhd)4840 dhd_conf_preinit(dhd_pub_t *dhd)
4841 {
4842 	struct dhd_conf *conf = dhd->conf;
4843 
4844 	CONFIG_TRACE("Enter\n");
4845 
4846 #ifdef SET_FWNV_BY_MAC
4847 	dhd_conf_free_mac_list(&conf->fw_by_mac);
4848 	dhd_conf_free_mac_list(&conf->nv_by_mac);
4849 #endif
4850 	dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip);
4851 	dhd_conf_free_country_list(conf);
4852 	dhd_conf_free_mchan_list(conf);
4853 #ifdef PKT_FILTER_SUPPORT
4854 	if (conf->magic_pkt_filter_add) {
4855 		kfree(conf->magic_pkt_filter_add);
4856 		conf->magic_pkt_filter_add = NULL;
4857 	}
4858 #endif
4859 	if (conf->wl_preinit) {
4860 		kfree(conf->wl_preinit);
4861 		conf->wl_preinit = NULL;
4862 	}
4863 	if (conf->wl_suspend) {
4864 		kfree(conf->wl_suspend);
4865 		conf->wl_suspend = NULL;
4866 	}
4867 	if (conf->wl_resume) {
4868 		kfree(conf->wl_resume);
4869 		conf->wl_resume = NULL;
4870 	}
4871 	if (conf->vndr_ie_assocreq) {
4872 		kfree(conf->vndr_ie_assocreq);
4873 		conf->vndr_ie_assocreq = NULL;
4874 	}
4875 	conf->band = -1;
4876 	memset(&conf->bw_cap, -1, sizeof(conf->bw_cap));
4877 	if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID) {
4878 		strcpy(conf->cspec.country_abbrev, "ALL");
4879 		strcpy(conf->cspec.ccode, "ALL");
4880 		conf->cspec.rev = 0;
4881 	}
4882 	else if (conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID ||
4883 			conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID ||
4884 			conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID ||
4885 			conf->chip == BCM43569_CHIP_ID || conf->chip == BCM4359_CHIP_ID ||
4886 			conf->chip == BCM4375_CHIP_ID) {
4887 		strcpy(conf->cspec.country_abbrev, "CN");
4888 		strcpy(conf->cspec.ccode, "CN");
4889 		conf->cspec.rev = 38;
4890 	}
4891 	else {
4892 		strcpy(conf->cspec.country_abbrev, "CN");
4893 		strcpy(conf->cspec.ccode, "CN");
4894 		conf->cspec.rev = 0;
4895 	}
4896 	memset(&conf->channels, 0, sizeof(wl_channel_list_t));
4897 	conf->roam_off = 1;
4898 	conf->roam_off_suspend = 1;
4899 	conf->roam_trigger[0] = -65;
4900 	conf->roam_trigger[1] = WLC_BAND_ALL;
4901 	conf->roam_scan_period[0] = 10;
4902 	conf->roam_scan_period[1] = WLC_BAND_ALL;
4903 	conf->roam_delta[0] = 10;
4904 	conf->roam_delta[1] = WLC_BAND_ALL;
4905 	conf->fullroamperiod = 20;
4906 	conf->keep_alive_period = 30000;
4907 #ifdef ARP_OFFLOAD_SUPPORT
4908 	conf->garp = FALSE;
4909 #endif
4910 	conf->force_wme_ac = 0;
4911 	memset(&conf->wme_sta, 0, sizeof(wme_param_t));
4912 	memset(&conf->wme_ap, 0, sizeof(wme_param_t));
4913 #ifdef PKT_FILTER_SUPPORT
4914 	memset(&conf->pkt_filter_add, 0, sizeof(conf_pkt_filter_add_t));
4915 	memset(&conf->pkt_filter_del, 0, sizeof(conf_pkt_filter_del_t));
4916 #endif
4917 	conf->srl = -1;
4918 	conf->lrl = -1;
4919 	conf->bcn_timeout = 16;
4920 	conf->disable_proptx = -1;
4921 	conf->dhd_poll = -1;
4922 #ifdef BCMSDIO
4923 	conf->use_rxchain = 0;
4924 	conf->bus_rxglom = TRUE;
4925 	conf->txglom_ext = FALSE;
4926 	conf->tx_max_offset = 0;
4927 	conf->txglomsize = SDPCM_DEFGLOM_SIZE;
4928 	conf->txctl_tmo_fix = 300;
4929 	conf->txglom_mode = SDPCM_TXGLOM_CPY;
4930 	conf->deferred_tx_len = 0;
4931 	conf->dhd_txminmax = 1;
4932 	conf->txinrx_thres = -1;
4933 #ifdef MINIME
4934 	conf->ramsize = 0x80000;
4935 #endif
4936 #if defined(SDIO_ISR_THREAD)
4937 	conf->intr_extn = FALSE;
4938 #endif
4939 #ifdef BCMSDIO_RXLIM_POST
4940 	conf->rxlim_en = FALSE;
4941 #endif
4942 #ifdef BCMSDIO_TXSEQ_SYNC
4943 	conf->txseq_sync = FALSE;
4944 #endif
4945 #if defined(HW_OOB)
4946 	conf->oob_enabled_later = FALSE;
4947 #endif
4948 #ifdef BCMSDIO_INTSTATUS_WAR
4949 	conf->read_intr_mode = 0;
4950 #endif
4951 	conf->kso_try_max = 0;
4952 #ifdef KSO_DEBUG
4953 	memset(&conf->kso_try_array, 0, sizeof(conf->kso_try_array));
4954 #endif
4955 #endif
4956 #ifdef BCMPCIE
4957 	conf->bus_deepsleep_disable = 1;
4958 	conf->flow_ring_queue_threshold = FLOW_RING_QUEUE_THRESHOLD;
4959 	conf->d2h_intr_method = -1;
4960 	conf->d2h_intr_control = -1;
4961 	conf->enq_hdr_pkt = 0;
4962 #endif
4963 	conf->dpc_cpucore = -1;
4964 	conf->rxf_cpucore = -1;
4965 	conf->dhd_dpc_prio = -1;
4966 	conf->frameburst = -1;
4967 	conf->deepsleep = FALSE;
4968 	conf->pm = -1;
4969 	conf->pm_in_suspend = -1;
4970 	conf->insuspend = 0;
4971 	conf->suspend_mode = PM_NOTIFIER;
4972 	conf->suspend_bcn_li_dtim = -1;
4973 	conf->rekey_offload = FALSE;
4974 #ifdef WL_EXT_WOWL
4975 	dhd_master_mode = TRUE;
4976 	conf->wowl = WL_WOWL_NET|WL_WOWL_DIS|WL_WOWL_BCN;
4977 	conf->insuspend |= (WOWL_IN_SUSPEND | NO_TXDATA_IN_SUSPEND);
4978 #endif
4979 	if (conf->suspend_mode == PM_NOTIFIER || conf->suspend_mode == SUSPEND_MODE_2)
4980 		conf->insuspend |= (NO_TXDATA_IN_SUSPEND | NO_TXCTL_IN_SUSPEND);
4981 	conf->suspended = FALSE;
4982 	memset(&conf->bssid_insuspend, 0, ETHER_ADDR_LEN);
4983 #ifdef SUSPEND_EVENT
4984 	memset(&conf->resume_eventmask, 0, sizeof(conf->resume_eventmask));
4985 	conf->wlfc = FALSE;
4986 #endif
4987 #ifdef GET_CUSTOM_MAC_FROM_CONFIG
4988 	memset(&conf->hw_ether, 0, sizeof(conf->hw_ether));
4989 #endif
4990 #ifdef IDHCP
4991 	conf->dhcpc_enable = -1;
4992 	conf->dhcpd_enable = -1;
4993 #endif
4994 	conf->orphan_move = 0;
4995 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
4996 	conf->tsq = 10;
4997 #else
4998 	conf->tsq = 0;
4999 #endif
5000 #ifdef DHDTCPACK_SUPPRESS
5001 #ifdef BCMPCIE
5002 	conf->tcpack_sup_mode = TCPACK_SUP_HOLD;
5003 #else
5004 	conf->tcpack_sup_mode = TCPACK_SUP_OFF;
5005 #endif
5006 	conf->tcpack_sup_ratio = CUSTOM_TCPACK_SUPP_RATIO;
5007 	conf->tcpack_sup_delay = CUSTOM_TCPACK_DELAY_TIME;
5008 #endif
5009 	conf->pktprio8021x = -1;
5010 	conf->ctrl_resched = 2;
5011 	conf->rxcnt_timeout = 3;
5012 	conf->in4way = STA_NO_SCAN_IN4WAY | STA_WAIT_DISCONNECTED |
5013 		AP_WAIT_STA_RECONNECT;
5014 	if (conf->chip == BCM43752_CHIP_ID)
5015 		conf->war = SET_CHAN_INCONN | FW_REINIT_INCSA | FW_REINIT_EMPTY_SCAN;
5016 	else
5017 		conf->war = 0;
5018 #ifdef P2P_AP_CONCURRENT
5019 	conf->war |= P2P_AP_MAC_CONFLICT;
5020 #endif
5021 #ifdef PROPTX_MAXCOUNT
5022 	conf->proptx_maxcnt_2g = 46;
5023 	conf->proptx_maxcnt_5g = WL_TXSTATUS_FREERUNCTR_MASK;
5024 #endif /* DYNAMIC_PROPTX_MAXCOUNT */
5025 #ifdef TPUT_MONITOR
5026 	conf->data_drop_mode = NO_DATA_DROP;
5027 	conf->tput_monitor_ms = 0;
5028 #ifdef BCMSDIO
5029 	if (conf->chip == BCM43752_CHIP_ID || conf->chip == BCM4375_CHIP_ID)
5030 		conf->doflow_tput_thresh = 200;
5031 	else
5032 		conf->doflow_tput_thresh = 9999;
5033 	if (conf->doflow_tput_thresh > 0 && conf->doflow_tput_thresh < 9999)
5034 		conf->tput_monitor_ms = 1000;
5035 #endif
5036 #endif
5037 #ifdef SCAN_SUPPRESS
5038 	conf->scan_intput = SCAN_CURCHAN_INTPUT;
5039 	conf->scan_busy_thresh = 10;
5040 	conf->scan_busy_tmo = 120;
5041 	if (conf->chip == BCM43752_CHIP_ID || conf->chip == BCM4375_CHIP_ID)
5042 		conf->scan_tput_thresh = 100;
5043 	else
5044 		conf->scan_tput_thresh = 9999;
5045 	if (conf->scan_tput_thresh > 0 && conf->scan_tput_thresh < 9999)
5046 		conf->tput_monitor_ms = 1000;
5047 #endif
5048 #ifdef DHD_TPUT_PATCH
5049 	conf->tput_patch = FALSE;
5050 	conf->mtu = 0;
5051 	conf->pktsetsum = FALSE;
5052 #endif
5053 #ifdef SET_XPS_CPUS
5054 	conf->xps_cpus = FALSE;
5055 #endif
5056 #ifdef SET_RPS_CPUS
5057 	conf->rps_cpus = FALSE;
5058 #endif
5059 #ifdef CHECK_DOWNLOAD_FW
5060 	conf->fwchk = FALSE;
5061 #endif
5062 #ifdef ISAM_PREINIT
5063 	memset(conf->isam_init, 0, sizeof(conf->isam_init));
5064 	memset(conf->isam_config, 0, sizeof(conf->isam_config));
5065 	memset(conf->isam_enable, 0, sizeof(conf->isam_enable));
5066 #endif
5067 #if defined(SDIO_ISR_THREAD)
5068 	if (conf->chip == BCM43012_CHIP_ID ||
5069 			conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID ||
5070 			conf->chip == BCM43454_CHIP_ID || conf->chip == BCM4345_CHIP_ID ||
5071 			conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID ||
5072 			conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID ||
5073 			conf->chip == BCM4359_CHIP_ID ||
5074 			conf->chip == BCM43751_CHIP_ID || conf->chip == BCM43752_CHIP_ID ||
5075 			conf->chip == BCM4375_CHIP_ID) {
5076 		conf->intr_extn = TRUE;
5077 	}
5078 #endif
5079 	if ((conf->chip == BCM43430_CHIP_ID && conf->chiprev == 2) ||
5080 			conf->chip == BCM43012_CHIP_ID ||
5081 			conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID ||
5082 			conf->chip == BCM43454_CHIP_ID || conf->chip == BCM4345_CHIP_ID ||
5083 			conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID ||
5084 			conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID ||
5085 			conf->chip == BCM43569_CHIP_ID || conf->chip == BCM4359_CHIP_ID ||
5086 			conf->chip == BCM43751_CHIP_ID || conf->chip == BCM43752_CHIP_ID ||
5087 			conf->chip == BCM4375_CHIP_ID) {
5088 #ifdef DHDTCPACK_SUPPRESS
5089 #ifdef BCMSDIO
5090 		conf->tcpack_sup_mode = TCPACK_SUP_REPLACE;
5091 #endif
5092 #endif
5093 #if defined(BCMSDIO) || defined(BCMPCIE)
5094 		dhd_rxbound = 128;
5095 		dhd_txbound = 64;
5096 #endif
5097 		conf->frameburst = 1;
5098 #ifdef BCMSDIO
5099 		conf->dhd_txminmax = -1;
5100 		conf->txinrx_thres = 128;
5101 #endif
5102 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
5103 		conf->orphan_move = 1;
5104 #else
5105 		conf->orphan_move = 0;
5106 #endif
5107 	}
5108 #ifdef DHD_TPUT_PATCH
5109 	if (conf->chip == BCM43751_CHIP_ID || conf->chip == BCM43752_CHIP_ID ||
5110 			conf->chip == BCM4375_CHIP_ID) {
5111 		conf->tput_patch = TRUE;
5112 		dhd_conf_set_tput_patch(dhd);
5113 	}
5114 #endif
5115 
5116 #ifdef BCMSDIO
5117 #if defined(BCMSDIOH_TXGLOM_EXT)
5118 	if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID ||
5119 			conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID ||
5120 			conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID) {
5121 		conf->txglom_ext = TRUE;
5122 	} else {
5123 		conf->txglom_ext = FALSE;
5124 	}
5125 	if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID) {
5126 		conf->txglom_bucket_size = 1680; // fixed value, don't change
5127 		conf->txglomsize = 6;
5128 	}
5129 	if (conf->chip == BCM4334_CHIP_ID || conf->chip == BCM43340_CHIP_ID ||
5130 			conf->chip == BCM43341_CHIP_ID || conf->chip == BCM4324_CHIP_ID) {
5131 		conf->txglom_bucket_size = 1684; // fixed value, don't change
5132 		conf->txglomsize = 16;
5133 	}
5134 #endif
5135 	if (conf->txglomsize > SDPCM_MAXGLOM_SIZE)
5136 		conf->txglomsize = SDPCM_MAXGLOM_SIZE;
5137 #endif
5138 	init_waitqueue_head(&conf->event_complete);
5139 #ifdef CUSTOMER_HW_ROCKCHIP
5140 #ifdef BCMPCIE
5141 	conf->d2h_intr_control = 0;
5142 #endif
5143 #endif
5144 
5145 	return 0;
5146 }
5147 
5148 int
dhd_conf_reset(dhd_pub_t * dhd)5149 dhd_conf_reset(dhd_pub_t *dhd)
5150 {
5151 	struct dhd_conf *conf = dhd->conf;
5152 
5153 #ifdef SET_FWNV_BY_MAC
5154 	dhd_conf_free_mac_list(&conf->fw_by_mac);
5155 	dhd_conf_free_mac_list(&conf->nv_by_mac);
5156 #endif
5157 	dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip);
5158 	dhd_conf_free_country_list(conf);
5159 	dhd_conf_free_mchan_list(conf);
5160 #ifdef PKT_FILTER_SUPPORT
5161 	if (conf->magic_pkt_filter_add) {
5162 		kfree(conf->magic_pkt_filter_add);
5163 		conf->magic_pkt_filter_add = NULL;
5164 	}
5165 #endif
5166 	if (conf->wl_preinit) {
5167 		kfree(conf->wl_preinit);
5168 		conf->wl_preinit = NULL;
5169 	}
5170 	if (conf->wl_suspend) {
5171 		kfree(conf->wl_suspend);
5172 		conf->wl_suspend = NULL;
5173 	}
5174 	if (conf->wl_resume) {
5175 		kfree(conf->wl_resume);
5176 		conf->wl_resume = NULL;
5177 	}
5178 	if (conf->vndr_ie_assocreq) {
5179 		kfree(conf->vndr_ie_assocreq);
5180 		conf->vndr_ie_assocreq = NULL;
5181 	}
5182 	memset(conf, 0, sizeof(dhd_conf_t));
5183 	return 0;
5184 }
5185 
5186 int
dhd_conf_attach(dhd_pub_t * dhd)5187 dhd_conf_attach(dhd_pub_t *dhd)
5188 {
5189 	dhd_conf_t *conf;
5190 
5191 	CONFIG_TRACE("Enter\n");
5192 
5193 	if (dhd->conf != NULL) {
5194 		CONFIG_MSG("config is attached before!\n");
5195 		return 0;
5196 	}
5197 	/* Allocate private bus interface state */
5198 	if (!(conf = MALLOC(dhd->osh, sizeof(dhd_conf_t)))) {
5199 		CONFIG_ERROR("MALLOC failed\n");
5200 		goto fail;
5201 	}
5202 	memset(conf, 0, sizeof(dhd_conf_t));
5203 
5204 	dhd->conf = conf;
5205 
5206 	return 0;
5207 
5208 fail:
5209 	if (conf != NULL)
5210 		MFREE(dhd->osh, conf, sizeof(dhd_conf_t));
5211 	return BCME_NOMEM;
5212 }
5213 
5214 void
dhd_conf_detach(dhd_pub_t * dhd)5215 dhd_conf_detach(dhd_pub_t *dhd)
5216 {
5217 	struct dhd_conf *conf = dhd->conf;
5218 
5219 	CONFIG_TRACE("Enter\n");
5220 	if (dhd->conf) {
5221 #ifdef SET_FWNV_BY_MAC
5222 		dhd_conf_free_mac_list(&conf->fw_by_mac);
5223 		dhd_conf_free_mac_list(&conf->nv_by_mac);
5224 #endif
5225 		dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip);
5226 		dhd_conf_free_country_list(conf);
5227 		dhd_conf_free_mchan_list(conf);
5228 #ifdef PKT_FILTER_SUPPORT
5229 		if (conf->magic_pkt_filter_add) {
5230 			kfree(conf->magic_pkt_filter_add);
5231 			conf->magic_pkt_filter_add = NULL;
5232 		}
5233 #endif
5234 		if (conf->wl_preinit) {
5235 			kfree(conf->wl_preinit);
5236 			conf->wl_preinit = NULL;
5237 		}
5238 		if (conf->wl_suspend) {
5239 			kfree(conf->wl_suspend);
5240 			conf->wl_suspend = NULL;
5241 		}
5242 		if (conf->wl_resume) {
5243 			kfree(conf->wl_resume);
5244 			conf->wl_resume = NULL;
5245 		}
5246 		if (conf->vndr_ie_assocreq) {
5247 			kfree(conf->vndr_ie_assocreq);
5248 			conf->vndr_ie_assocreq = NULL;
5249 		}
5250 		MFREE(dhd->osh, conf, sizeof(dhd_conf_t));
5251 	}
5252 	dhd->conf = NULL;
5253 }
5254