• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&ether_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(&param, 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 *)&param,
2009                               sizeof(param), TRUE);
2010     }
2011 
2012     if (dhd->conf->bw_cap[1] >= 0) {
2013         memset(&param, 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 *)&param,
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, &ether_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(&ether_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(&ether_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(&ether_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