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