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