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