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