diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/staging/brcm80211/brcmfmac | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'drivers/staging/brcm80211/brcmfmac')
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/Makefile | 39 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/bcmchip.h | 32 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/bcmsdh.c | 642 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 1196 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/dhd.h | 904 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/dhd_bus.h | 78 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/dhd_cdc.c | 502 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/dhd_common.c | 1196 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/dhd_dbg.h | 70 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 1736 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/dhd_proto.h | 75 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/dhd_sdio.c | 6772 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/sdio_host.h | 347 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c | 4152 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h | 356 |
15 files changed, 18097 insertions, 0 deletions
diff --git a/drivers/staging/brcm80211/brcmfmac/Makefile b/drivers/staging/brcm80211/brcmfmac/Makefile new file mode 100644 index 00000000000..da3c8057590 --- /dev/null +++ b/drivers/staging/brcm80211/brcmfmac/Makefile | |||
@@ -0,0 +1,39 @@ | |||
1 | # | ||
2 | # Makefile fragment for Broadcom 802.11n Networking Device Driver | ||
3 | # | ||
4 | # Copyright (c) 2010 Broadcom Corporation | ||
5 | # | ||
6 | # Permission to use, copy, modify, and/or distribute this software for any | ||
7 | # purpose with or without fee is hereby granted, provided that the above | ||
8 | # copyright notice and this permission notice appear in all copies. | ||
9 | # | ||
10 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
11 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
12 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
13 | # SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
14 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
15 | # OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
16 | # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
17 | |||
18 | ccflags-y := \ | ||
19 | -DBRCMF_FIRSTREAD=64 \ | ||
20 | -DBRCMF_SDALIGN=64 \ | ||
21 | -DMAX_HDR_READ=64 | ||
22 | |||
23 | ccflags-$(CONFIG_BRCMDBG) += -DSHOW_EVENTS | ||
24 | |||
25 | ccflags-y += \ | ||
26 | -Idrivers/staging/brcm80211/brcmfmac \ | ||
27 | -Idrivers/staging/brcm80211/include | ||
28 | |||
29 | DHDOFILES = \ | ||
30 | wl_cfg80211.o \ | ||
31 | dhd_cdc.o \ | ||
32 | dhd_common.o \ | ||
33 | dhd_sdio.o \ | ||
34 | dhd_linux.o \ | ||
35 | bcmsdh.o \ | ||
36 | bcmsdh_sdmmc.o | ||
37 | |||
38 | obj-$(CONFIG_BRCMFMAC) += brcmfmac.o | ||
39 | brcmfmac-objs += $(DHDOFILES) | ||
diff --git a/drivers/staging/brcm80211/brcmfmac/bcmchip.h b/drivers/staging/brcm80211/brcmfmac/bcmchip.h new file mode 100644 index 00000000000..d7d3afd5a10 --- /dev/null +++ b/drivers/staging/brcm80211/brcmfmac/bcmchip.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #ifndef _bcmchip_h_ | ||
18 | #define _bcmchip_h_ | ||
19 | |||
20 | /* bcm4329 */ | ||
21 | /* SDIO device core, ID 0x829 */ | ||
22 | #define BCM4329_CORE_BUS_BASE 0x18011000 | ||
23 | /* internal memory core, ID 0x80e */ | ||
24 | #define BCM4329_CORE_SOCRAM_BASE 0x18003000 | ||
25 | /* ARM Cortex M3 core, ID 0x82a */ | ||
26 | #define BCM4329_CORE_ARM_BASE 0x18002000 | ||
27 | #define BCM4329_RAMSIZE 0x48000 | ||
28 | /* firmware name */ | ||
29 | #define BCM4329_FW_NAME "brcm/bcm4329-fullmac-4.bin" | ||
30 | #define BCM4329_NV_NAME "brcm/bcm4329-fullmac-4.txt" | ||
31 | |||
32 | #endif /* _bcmchip_h_ */ | ||
diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh.c new file mode 100644 index 00000000000..f4e72ed126b --- /dev/null +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh.c | |||
@@ -0,0 +1,642 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | /* ****************** SDIO CARD Interface Functions **************************/ | ||
17 | |||
18 | #include <linux/types.h> | ||
19 | #include <linux/netdevice.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include <linux/pci_ids.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/completion.h> | ||
24 | |||
25 | #include <defs.h> | ||
26 | #include <brcm_hw_ids.h> | ||
27 | #include <brcmu_utils.h> | ||
28 | #include <brcmu_wifi.h> | ||
29 | #include <soc.h> | ||
30 | #include "dhd.h" | ||
31 | #include "dhd_bus.h" | ||
32 | #include "sdio_host.h" | ||
33 | |||
34 | #define SDIOH_API_ACCESS_RETRY_LIMIT 2 | ||
35 | |||
36 | #define BRCMF_SD_ERROR_VAL 0x0001 /* Error */ | ||
37 | #define BRCMF_SD_INFO_VAL 0x0002 /* Info */ | ||
38 | |||
39 | |||
40 | #ifdef BCMDBG | ||
41 | #define BRCMF_SD_ERROR(x) \ | ||
42 | do { \ | ||
43 | if ((brcmf_sdio_msglevel & BRCMF_SD_ERROR_VAL) && \ | ||
44 | net_ratelimit()) \ | ||
45 | printk x; \ | ||
46 | } while (0) | ||
47 | #define BRCMF_SD_INFO(x) \ | ||
48 | do { \ | ||
49 | if ((brcmf_sdio_msglevel & BRCMF_SD_INFO_VAL) && \ | ||
50 | net_ratelimit()) \ | ||
51 | printk x; \ | ||
52 | } while (0) | ||
53 | #else /* BCMDBG */ | ||
54 | #define BRCMF_SD_ERROR(x) | ||
55 | #define BRCMF_SD_INFO(x) | ||
56 | #endif /* BCMDBG */ | ||
57 | |||
58 | /* debugging macros */ | ||
59 | #define SDLX_MSG(x) | ||
60 | |||
61 | #define SDIOH_CMD_TYPE_NORMAL 0 /* Normal command */ | ||
62 | #define SDIOH_CMD_TYPE_APPEND 1 /* Append command */ | ||
63 | #define SDIOH_CMD_TYPE_CUTTHRU 2 /* Cut-through command */ | ||
64 | |||
65 | #define SDIOH_DATA_PIO 0 /* PIO mode */ | ||
66 | #define SDIOH_DATA_DMA 1 /* DMA mode */ | ||
67 | |||
68 | struct brcmf_sdio_card { | ||
69 | bool init_success; /* underlying driver successfully attached */ | ||
70 | void *sdioh; /* handler for sdioh */ | ||
71 | u32 vendevid; /* Target Vendor and Device ID on SD bus */ | ||
72 | bool regfail; /* Save status of last | ||
73 | reg_read/reg_write call */ | ||
74 | u32 sbwad; /* Save backplane window address */ | ||
75 | }; | ||
76 | |||
77 | /** | ||
78 | * SDIO Host Controller info | ||
79 | */ | ||
80 | struct sdio_hc { | ||
81 | struct sdio_hc *next; | ||
82 | struct device *dev; /* platform device handle */ | ||
83 | void *regs; /* SDIO Host Controller address */ | ||
84 | struct brcmf_sdio_card *card; | ||
85 | void *ch; | ||
86 | unsigned int oob_irq; | ||
87 | unsigned long oob_flags; /* OOB Host specifiction | ||
88 | as edge and etc */ | ||
89 | bool oob_irq_registered; | ||
90 | }; | ||
91 | |||
92 | /* local copy of bcm sd handler */ | ||
93 | static struct brcmf_sdio_card *l_card; | ||
94 | |||
95 | const uint brcmf_sdio_msglevel = BRCMF_SD_ERROR_VAL; | ||
96 | |||
97 | static struct sdio_hc *sdhcinfo; | ||
98 | |||
99 | /* driver info, initialized when brcmf_sdio_register is called */ | ||
100 | static struct brcmf_sdioh_driver drvinfo = { NULL, NULL }; | ||
101 | |||
102 | /* Module parameters specific to each host-controller driver */ | ||
103 | |||
104 | module_param(sd_msglevel, uint, 0); | ||
105 | |||
106 | extern uint sd_f2_blocksize; | ||
107 | module_param(sd_f2_blocksize, int, 0); | ||
108 | |||
109 | /* forward declarations */ | ||
110 | int brcmf_sdio_probe(struct device *dev); | ||
111 | EXPORT_SYMBOL(brcmf_sdio_probe); | ||
112 | |||
113 | int brcmf_sdio_remove(struct device *dev); | ||
114 | EXPORT_SYMBOL(brcmf_sdio_remove); | ||
115 | |||
116 | struct brcmf_sdio_card* | ||
117 | brcmf_sdcard_attach(void *cfghdl, u32 *regsva, uint irq) | ||
118 | { | ||
119 | struct brcmf_sdio_card *card; | ||
120 | |||
121 | card = kzalloc(sizeof(struct brcmf_sdio_card), GFP_ATOMIC); | ||
122 | if (card == NULL) { | ||
123 | BRCMF_SD_ERROR(("sdcard_attach: out of memory")); | ||
124 | return NULL; | ||
125 | } | ||
126 | |||
127 | /* save the handler locally */ | ||
128 | l_card = card; | ||
129 | |||
130 | card->sdioh = brcmf_sdioh_attach(cfghdl, irq); | ||
131 | if (!card->sdioh) { | ||
132 | brcmf_sdcard_detach(card); | ||
133 | return NULL; | ||
134 | } | ||
135 | |||
136 | card->init_success = true; | ||
137 | |||
138 | *regsva = SI_ENUM_BASE; | ||
139 | |||
140 | /* Report the BAR, to fix if needed */ | ||
141 | card->sbwad = SI_ENUM_BASE; | ||
142 | return card; | ||
143 | } | ||
144 | |||
145 | int brcmf_sdcard_detach(struct brcmf_sdio_card *card) | ||
146 | { | ||
147 | if (card != NULL) { | ||
148 | if (card->sdioh) { | ||
149 | brcmf_sdioh_detach(card->sdioh); | ||
150 | card->sdioh = NULL; | ||
151 | } | ||
152 | kfree(card); | ||
153 | } | ||
154 | |||
155 | l_card = NULL; | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | int | ||
160 | brcmf_sdcard_iovar_op(struct brcmf_sdio_card *card, const char *name, | ||
161 | void *params, int plen, void *arg, int len, bool set) | ||
162 | { | ||
163 | return brcmf_sdioh_iovar_op(card->sdioh, name, params, plen, arg, | ||
164 | len, set); | ||
165 | } | ||
166 | |||
167 | int brcmf_sdcard_intr_enable(struct brcmf_sdio_card *card) | ||
168 | { | ||
169 | return brcmf_sdioh_interrupt_set(card->sdioh, true); | ||
170 | } | ||
171 | |||
172 | int brcmf_sdcard_intr_disable(struct brcmf_sdio_card *card) | ||
173 | { | ||
174 | return brcmf_sdioh_interrupt_set(card->sdioh, false); | ||
175 | } | ||
176 | |||
177 | int brcmf_sdcard_intr_reg(struct brcmf_sdio_card *card, | ||
178 | void (*fn)(void *), void *argh) | ||
179 | { | ||
180 | return brcmf_sdioh_interrupt_register(card->sdioh, fn, argh); | ||
181 | } | ||
182 | |||
183 | int brcmf_sdcard_intr_dereg(struct brcmf_sdio_card *card) | ||
184 | { | ||
185 | return brcmf_sdioh_interrupt_deregister(card->sdioh); | ||
186 | } | ||
187 | |||
188 | u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_card *card, uint fnc_num, u32 addr, | ||
189 | int *err) | ||
190 | { | ||
191 | int status; | ||
192 | s32 retry = 0; | ||
193 | u8 data = 0; | ||
194 | |||
195 | if (!card) | ||
196 | card = l_card; | ||
197 | |||
198 | do { | ||
199 | if (retry) /* wait for 1 ms till bus get settled down */ | ||
200 | udelay(1000); | ||
201 | status = | ||
202 | brcmf_sdioh_cfg_read(card->sdioh, fnc_num, addr, | ||
203 | (u8 *) &data); | ||
204 | } while (status != 0 | ||
205 | && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); | ||
206 | if (err) | ||
207 | *err = status; | ||
208 | |||
209 | BRCMF_SD_INFO(("%s:fun = %d, addr = 0x%x, u8data = 0x%x\n", | ||
210 | __func__, fnc_num, addr, data)); | ||
211 | |||
212 | return data; | ||
213 | } | ||
214 | |||
215 | void | ||
216 | brcmf_sdcard_cfg_write(struct brcmf_sdio_card *card, uint fnc_num, u32 addr, | ||
217 | u8 data, int *err) | ||
218 | { | ||
219 | int status; | ||
220 | s32 retry = 0; | ||
221 | |||
222 | if (!card) | ||
223 | card = l_card; | ||
224 | |||
225 | do { | ||
226 | if (retry) /* wait for 1 ms till bus get settled down */ | ||
227 | udelay(1000); | ||
228 | status = | ||
229 | brcmf_sdioh_cfg_write(card->sdioh, fnc_num, addr, | ||
230 | (u8 *) &data); | ||
231 | } while (status != 0 | ||
232 | && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); | ||
233 | if (err) | ||
234 | *err = status; | ||
235 | |||
236 | BRCMF_SD_INFO(("%s:fun = %d, addr = 0x%x, u8data = 0x%x\n", | ||
237 | __func__, fnc_num, addr, data)); | ||
238 | } | ||
239 | |||
240 | u32 brcmf_sdcard_cfg_read_word(struct brcmf_sdio_card *card, uint fnc_num, | ||
241 | u32 addr, int *err) | ||
242 | { | ||
243 | int status; | ||
244 | u32 data = 0; | ||
245 | |||
246 | if (!card) | ||
247 | card = l_card; | ||
248 | |||
249 | status = brcmf_sdioh_request_word(card->sdioh, SDIOH_CMD_TYPE_NORMAL, | ||
250 | SDIOH_READ, fnc_num, addr, &data, 4); | ||
251 | |||
252 | if (err) | ||
253 | *err = status; | ||
254 | |||
255 | BRCMF_SD_INFO(("%s:fun = %d, addr = 0x%x, u32data = 0x%x\n", | ||
256 | __func__, fnc_num, addr, data)); | ||
257 | |||
258 | return data; | ||
259 | } | ||
260 | |||
261 | void | ||
262 | brcmf_sdcard_cfg_write_word(struct brcmf_sdio_card *card, uint fnc_num, | ||
263 | u32 addr, u32 data, int *err) | ||
264 | { | ||
265 | int status; | ||
266 | |||
267 | if (!card) | ||
268 | card = l_card; | ||
269 | |||
270 | status = | ||
271 | brcmf_sdioh_request_word(card->sdioh, SDIOH_CMD_TYPE_NORMAL, | ||
272 | SDIOH_WRITE, fnc_num, addr, &data, 4); | ||
273 | |||
274 | if (err) | ||
275 | *err = status; | ||
276 | |||
277 | BRCMF_SD_INFO(("%s:fun = %d, addr = 0x%x, u32data = 0x%x\n", | ||
278 | __func__, fnc_num, addr, data)); | ||
279 | } | ||
280 | |||
281 | int brcmf_sdcard_cis_read(struct brcmf_sdio_card *card, uint func, u8 * cis, | ||
282 | uint length) | ||
283 | { | ||
284 | int status; | ||
285 | |||
286 | u8 *tmp_buf, *tmp_ptr; | ||
287 | u8 *ptr; | ||
288 | bool ascii = func & ~0xf; | ||
289 | func &= 0x7; | ||
290 | |||
291 | if (!card) | ||
292 | card = l_card; | ||
293 | |||
294 | status = brcmf_sdioh_cis_read(card->sdioh, func, cis, length); | ||
295 | |||
296 | if (ascii) { | ||
297 | /* Move binary bits to tmp and format them | ||
298 | into the provided buffer. */ | ||
299 | tmp_buf = kmalloc(length, GFP_ATOMIC); | ||
300 | if (tmp_buf == NULL) { | ||
301 | BRCMF_SD_ERROR(("%s: out of memory\n", __func__)); | ||
302 | return -ENOMEM; | ||
303 | } | ||
304 | memcpy(tmp_buf, cis, length); | ||
305 | for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4); | ||
306 | tmp_ptr++) { | ||
307 | ptr += sprintf((char *)ptr, "%.2x ", *tmp_ptr & 0xff); | ||
308 | if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0) | ||
309 | ptr += sprintf((char *)ptr, "\n"); | ||
310 | } | ||
311 | kfree(tmp_buf); | ||
312 | } | ||
313 | |||
314 | return status; | ||
315 | } | ||
316 | |||
317 | static int | ||
318 | brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_card *card, u32 address) | ||
319 | { | ||
320 | int err = 0; | ||
321 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, | ||
322 | (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); | ||
323 | if (!err) | ||
324 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, | ||
325 | SBSDIO_FUNC1_SBADDRMID, | ||
326 | (address >> 16) & SBSDIO_SBADDRMID_MASK, | ||
327 | &err); | ||
328 | if (!err) | ||
329 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, | ||
330 | SBSDIO_FUNC1_SBADDRHIGH, | ||
331 | (address >> 24) & SBSDIO_SBADDRHIGH_MASK, | ||
332 | &err); | ||
333 | |||
334 | return err; | ||
335 | } | ||
336 | |||
337 | u32 brcmf_sdcard_reg_read(struct brcmf_sdio_card *card, u32 addr, uint size) | ||
338 | { | ||
339 | int status; | ||
340 | u32 word = 0; | ||
341 | uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; | ||
342 | |||
343 | BRCMF_SD_INFO(("%s:fun = 1, addr = 0x%x, ", __func__, addr)); | ||
344 | |||
345 | if (!card) | ||
346 | card = l_card; | ||
347 | |||
348 | if (bar0 != card->sbwad) { | ||
349 | if (brcmf_sdcard_set_sbaddr_window(card, bar0)) | ||
350 | return 0xFFFFFFFF; | ||
351 | |||
352 | card->sbwad = bar0; | ||
353 | } | ||
354 | |||
355 | addr &= SBSDIO_SB_OFT_ADDR_MASK; | ||
356 | if (size == 4) | ||
357 | addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; | ||
358 | |||
359 | status = brcmf_sdioh_request_word(card->sdioh, SDIOH_CMD_TYPE_NORMAL, | ||
360 | SDIOH_READ, SDIO_FUNC_1, addr, &word, size); | ||
361 | |||
362 | card->regfail = (status != 0); | ||
363 | |||
364 | BRCMF_SD_INFO(("u32data = 0x%x\n", word)); | ||
365 | |||
366 | /* if ok, return appropriately masked word */ | ||
367 | if (status == 0) { | ||
368 | switch (size) { | ||
369 | case sizeof(u8): | ||
370 | return word & 0xff; | ||
371 | case sizeof(u16): | ||
372 | return word & 0xffff; | ||
373 | case sizeof(u32): | ||
374 | return word; | ||
375 | default: | ||
376 | card->regfail = true; | ||
377 | |||
378 | } | ||
379 | } | ||
380 | |||
381 | /* otherwise, bad sdio access or invalid size */ | ||
382 | BRCMF_SD_ERROR(("%s: error reading addr 0x%04x size %d\n", __func__, | ||
383 | addr, size)); | ||
384 | return 0xFFFFFFFF; | ||
385 | } | ||
386 | |||
387 | u32 brcmf_sdcard_reg_write(struct brcmf_sdio_card *card, u32 addr, uint size, | ||
388 | u32 data) | ||
389 | { | ||
390 | int status; | ||
391 | uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; | ||
392 | int err = 0; | ||
393 | |||
394 | BRCMF_SD_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n", | ||
395 | __func__, addr, size * 8, data)); | ||
396 | |||
397 | if (!card) | ||
398 | card = l_card; | ||
399 | |||
400 | if (bar0 != card->sbwad) { | ||
401 | err = brcmf_sdcard_set_sbaddr_window(card, bar0); | ||
402 | if (err) | ||
403 | return err; | ||
404 | |||
405 | card->sbwad = bar0; | ||
406 | } | ||
407 | |||
408 | addr &= SBSDIO_SB_OFT_ADDR_MASK; | ||
409 | if (size == 4) | ||
410 | addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; | ||
411 | status = | ||
412 | brcmf_sdioh_request_word(card->sdioh, SDIOH_CMD_TYPE_NORMAL, | ||
413 | SDIOH_WRITE, SDIO_FUNC_1, addr, &data, size); | ||
414 | card->regfail = (status != 0); | ||
415 | |||
416 | if (status == 0) | ||
417 | return 0; | ||
418 | |||
419 | BRCMF_SD_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n", | ||
420 | __func__, data, addr, size)); | ||
421 | return 0xFFFFFFFF; | ||
422 | } | ||
423 | |||
424 | bool brcmf_sdcard_regfail(struct brcmf_sdio_card *card) | ||
425 | { | ||
426 | return card->regfail; | ||
427 | } | ||
428 | |||
429 | int | ||
430 | brcmf_sdcard_recv_buf(struct brcmf_sdio_card *card, u32 addr, uint fn, | ||
431 | uint flags, | ||
432 | u8 *buf, uint nbytes, struct sk_buff *pkt, | ||
433 | void (*complete)(void *handle, int status, | ||
434 | bool sync_waiting), | ||
435 | void *handle) | ||
436 | { | ||
437 | int status; | ||
438 | uint incr_fix; | ||
439 | uint width; | ||
440 | uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; | ||
441 | int err = 0; | ||
442 | |||
443 | BRCMF_SD_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", | ||
444 | __func__, fn, addr, nbytes)); | ||
445 | |||
446 | /* Async not implemented yet */ | ||
447 | if (flags & SDIO_REQ_ASYNC) | ||
448 | return -ENOTSUPP; | ||
449 | |||
450 | if (bar0 != card->sbwad) { | ||
451 | err = brcmf_sdcard_set_sbaddr_window(card, bar0); | ||
452 | if (err) | ||
453 | return err; | ||
454 | |||
455 | card->sbwad = bar0; | ||
456 | } | ||
457 | |||
458 | addr &= SBSDIO_SB_OFT_ADDR_MASK; | ||
459 | |||
460 | incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; | ||
461 | width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; | ||
462 | if (width == 4) | ||
463 | addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; | ||
464 | |||
465 | status = brcmf_sdioh_request_buffer(card->sdioh, SDIOH_DATA_PIO, | ||
466 | incr_fix, SDIOH_READ, fn, addr, width, nbytes, buf, pkt); | ||
467 | |||
468 | return status; | ||
469 | } | ||
470 | |||
471 | int | ||
472 | brcmf_sdcard_send_buf(struct brcmf_sdio_card *card, u32 addr, uint fn, | ||
473 | uint flags, u8 *buf, uint nbytes, void *pkt, | ||
474 | void (*complete)(void *handle, int status, | ||
475 | bool sync_waiting), | ||
476 | void *handle) | ||
477 | { | ||
478 | uint incr_fix; | ||
479 | uint width; | ||
480 | uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; | ||
481 | int err = 0; | ||
482 | |||
483 | BRCMF_SD_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", | ||
484 | __func__, fn, addr, nbytes)); | ||
485 | |||
486 | /* Async not implemented yet */ | ||
487 | if (flags & SDIO_REQ_ASYNC) | ||
488 | return -ENOTSUPP; | ||
489 | |||
490 | if (bar0 != card->sbwad) { | ||
491 | err = brcmf_sdcard_set_sbaddr_window(card, bar0); | ||
492 | if (err) | ||
493 | return err; | ||
494 | |||
495 | card->sbwad = bar0; | ||
496 | } | ||
497 | |||
498 | addr &= SBSDIO_SB_OFT_ADDR_MASK; | ||
499 | |||
500 | incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; | ||
501 | width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; | ||
502 | if (width == 4) | ||
503 | addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; | ||
504 | |||
505 | return brcmf_sdioh_request_buffer(card->sdioh, SDIOH_DATA_PIO, | ||
506 | incr_fix, SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt); | ||
507 | } | ||
508 | |||
509 | int brcmf_sdcard_rwdata(struct brcmf_sdio_card *card, uint rw, u32 addr, | ||
510 | u8 *buf, uint nbytes) | ||
511 | { | ||
512 | addr &= SBSDIO_SB_OFT_ADDR_MASK; | ||
513 | addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; | ||
514 | |||
515 | return brcmf_sdioh_request_buffer(card->sdioh, SDIOH_DATA_PIO, | ||
516 | SDIOH_DATA_INC, (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1, | ||
517 | addr, 4, nbytes, buf, NULL); | ||
518 | } | ||
519 | |||
520 | int brcmf_sdcard_abort(struct brcmf_sdio_card *card, uint fn) | ||
521 | { | ||
522 | return brcmf_sdioh_abort(card->sdioh, fn); | ||
523 | } | ||
524 | |||
525 | int brcmf_sdcard_query_device(struct brcmf_sdio_card *card) | ||
526 | { | ||
527 | card->vendevid = (PCI_VENDOR_ID_BROADCOM << 16) | 0; | ||
528 | return card->vendevid; | ||
529 | } | ||
530 | |||
531 | u32 brcmf_sdcard_cur_sbwad(struct brcmf_sdio_card *card) | ||
532 | { | ||
533 | if (!card) | ||
534 | card = l_card; | ||
535 | |||
536 | return card->sbwad; | ||
537 | } | ||
538 | |||
539 | int brcmf_sdio_probe(struct device *dev) | ||
540 | { | ||
541 | struct sdio_hc *sdhc = NULL; | ||
542 | u32 regs = 0; | ||
543 | struct brcmf_sdio_card *card = NULL; | ||
544 | int irq = 0; | ||
545 | u32 vendevid; | ||
546 | unsigned long irq_flags = 0; | ||
547 | |||
548 | /* allocate SDIO Host Controller state info */ | ||
549 | sdhc = kzalloc(sizeof(struct sdio_hc), GFP_ATOMIC); | ||
550 | if (!sdhc) { | ||
551 | SDLX_MSG(("%s: out of memory\n", __func__)); | ||
552 | goto err; | ||
553 | } | ||
554 | sdhc->dev = (void *)dev; | ||
555 | |||
556 | card = brcmf_sdcard_attach((void *)0, ®s, irq); | ||
557 | if (!card) { | ||
558 | SDLX_MSG(("%s: attach failed\n", __func__)); | ||
559 | goto err; | ||
560 | } | ||
561 | |||
562 | sdhc->card = card; | ||
563 | sdhc->oob_irq = irq; | ||
564 | sdhc->oob_flags = irq_flags; | ||
565 | sdhc->oob_irq_registered = false; /* to make sure.. */ | ||
566 | |||
567 | /* chain SDIO Host Controller info together */ | ||
568 | sdhc->next = sdhcinfo; | ||
569 | sdhcinfo = sdhc; | ||
570 | /* Read the vendor/device ID from the CIS */ | ||
571 | vendevid = brcmf_sdcard_query_device(card); | ||
572 | |||
573 | /* try to attach to the target device */ | ||
574 | sdhc->ch = drvinfo.attach((vendevid >> 16), (vendevid & 0xFFFF), | ||
575 | 0, 0, 0, 0, regs, card); | ||
576 | if (!sdhc->ch) { | ||
577 | SDLX_MSG(("%s: device attach failed\n", __func__)); | ||
578 | goto err; | ||
579 | } | ||
580 | |||
581 | return 0; | ||
582 | |||
583 | /* error handling */ | ||
584 | err: | ||
585 | if (sdhc) { | ||
586 | if (sdhc->card) | ||
587 | brcmf_sdcard_detach(sdhc->card); | ||
588 | kfree(sdhc); | ||
589 | } | ||
590 | |||
591 | return -ENODEV; | ||
592 | } | ||
593 | |||
594 | int brcmf_sdio_remove(struct device *dev) | ||
595 | { | ||
596 | struct sdio_hc *sdhc, *prev; | ||
597 | |||
598 | sdhc = sdhcinfo; | ||
599 | drvinfo.detach(sdhc->ch); | ||
600 | brcmf_sdcard_detach(sdhc->card); | ||
601 | /* find the SDIO Host Controller state for this pdev | ||
602 | and take it out from the list */ | ||
603 | for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) { | ||
604 | if (sdhc->dev == (void *)dev) { | ||
605 | if (prev) | ||
606 | prev->next = sdhc->next; | ||
607 | else | ||
608 | sdhcinfo = NULL; | ||
609 | break; | ||
610 | } | ||
611 | prev = sdhc; | ||
612 | } | ||
613 | if (!sdhc) { | ||
614 | SDLX_MSG(("%s: failed\n", __func__)); | ||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | /* release SDIO Host Controller info */ | ||
619 | kfree(sdhc); | ||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | int brcmf_sdio_register(struct brcmf_sdioh_driver *driver) | ||
624 | { | ||
625 | drvinfo = *driver; | ||
626 | |||
627 | SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n")); | ||
628 | return brcmf_sdio_function_init(); | ||
629 | } | ||
630 | |||
631 | void brcmf_sdio_unregister(void) | ||
632 | { | ||
633 | brcmf_sdio_function_cleanup(); | ||
634 | } | ||
635 | |||
636 | void brcmf_sdio_wdtmr_enable(bool enable) | ||
637 | { | ||
638 | if (enable) | ||
639 | brcmf_sdbrcm_wd_timer(sdhcinfo->ch, brcmf_watchdog_ms); | ||
640 | else | ||
641 | brcmf_sdbrcm_wd_timer(sdhcinfo->ch, 0); | ||
642 | } | ||
diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c new file mode 100644 index 00000000000..38bd9ba3096 --- /dev/null +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c | |||
@@ -0,0 +1,1196 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/netdevice.h> | ||
18 | #include <linux/mmc/sdio.h> | ||
19 | #include <linux/mmc/core.h> | ||
20 | #include <linux/mmc/sdio_func.h> | ||
21 | #include <linux/mmc/sdio_ids.h> | ||
22 | #include <linux/mmc/card.h> | ||
23 | #include <linux/suspend.h> | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/sched.h> /* request_irq() */ | ||
26 | #include <net/cfg80211.h> | ||
27 | |||
28 | #include <defs.h> | ||
29 | #include <brcm_hw_ids.h> | ||
30 | #include <brcmu_utils.h> | ||
31 | #include <brcmu_wifi.h> | ||
32 | #include "sdio_host.h" | ||
33 | #include "dhd.h" | ||
34 | #include "dhd_dbg.h" | ||
35 | #include "wl_cfg80211.h" | ||
36 | |||
37 | #define BLOCK_SIZE_64 64 | ||
38 | #define BLOCK_SIZE_512 512 | ||
39 | #define BLOCK_SIZE_4318 64 | ||
40 | #define BLOCK_SIZE_4328 512 | ||
41 | |||
42 | /* private bus modes */ | ||
43 | #define SDIOH_MODE_SD4 2 | ||
44 | |||
45 | #define CLIENT_INTR 0x100 /* Get rid of this! */ | ||
46 | |||
47 | #if !defined(SDIO_VENDOR_ID_BROADCOM) | ||
48 | #define SDIO_VENDOR_ID_BROADCOM 0x02d0 | ||
49 | #endif /* !defined(SDIO_VENDOR_ID_BROADCOM) */ | ||
50 | |||
51 | #define SDIO_DEVICE_ID_BROADCOM_DEFAULT 0x0000 | ||
52 | |||
53 | #define DMA_ALIGN_MASK 0x03 | ||
54 | |||
55 | #if !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) | ||
56 | #define SDIO_DEVICE_ID_BROADCOM_4325_SDGWB 0x0492 /* BCM94325SDGWB */ | ||
57 | #endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) */ | ||
58 | #if !defined(SDIO_DEVICE_ID_BROADCOM_4325) | ||
59 | #define SDIO_DEVICE_ID_BROADCOM_4325 0x0493 | ||
60 | #endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */ | ||
61 | #if !defined(SDIO_DEVICE_ID_BROADCOM_4329) | ||
62 | #define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 | ||
63 | #endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */ | ||
64 | #if !defined(SDIO_DEVICE_ID_BROADCOM_4319) | ||
65 | #define SDIO_DEVICE_ID_BROADCOM_4319 0x4319 | ||
66 | #endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */ | ||
67 | |||
68 | /* Common msglevel constants */ | ||
69 | #define SDH_ERROR_VAL 0x0001 /* Error */ | ||
70 | #define SDH_TRACE_VAL 0x0002 /* Trace */ | ||
71 | #define SDH_INFO_VAL 0x0004 /* Info */ | ||
72 | #define SDH_DEBUG_VAL 0x0008 /* Debug */ | ||
73 | #define SDH_DATA_VAL 0x0010 /* Data */ | ||
74 | #define SDH_CTRL_VAL 0x0020 /* Control Regs */ | ||
75 | #define SDH_LOG_VAL 0x0040 /* Enable bcmlog */ | ||
76 | #define SDH_DMA_VAL 0x0080 /* DMA */ | ||
77 | |||
78 | #ifdef BCMDBG | ||
79 | #define sd_err(x) \ | ||
80 | do { \ | ||
81 | if ((sd_msglevel & SDH_ERROR_VAL) && net_ratelimit()) \ | ||
82 | printk x; \ | ||
83 | } while (0) | ||
84 | #define sd_trace(x) \ | ||
85 | do { \ | ||
86 | if ((sd_msglevel & SDH_TRACE_VAL) && net_ratelimit()) \ | ||
87 | printk x; \ | ||
88 | } while (0) | ||
89 | #define sd_info(x) \ | ||
90 | do { \ | ||
91 | if ((sd_msglevel & SDH_INFO_VAL) && net_ratelimit()) \ | ||
92 | printk x; \ | ||
93 | } while (0) | ||
94 | #define sd_debug(x) \ | ||
95 | do { \ | ||
96 | if ((sd_msglevel & SDH_DEBUG_VAL) && net_ratelimit()) \ | ||
97 | printk x; \ | ||
98 | } while (0) | ||
99 | #define sd_data(x) \ | ||
100 | do { \ | ||
101 | if ((sd_msglevel & SDH_DATA_VAL) && net_ratelimit()) \ | ||
102 | printk x; \ | ||
103 | } while (0) | ||
104 | #define sd_ctrl(x) \ | ||
105 | do { \ | ||
106 | if ((sd_msglevel & SDH_CTRL_VAL) && net_ratelimit()) \ | ||
107 | printk x; \ | ||
108 | } while (0) | ||
109 | #else | ||
110 | #define sd_err(x) | ||
111 | #define sd_trace(x) | ||
112 | #define sd_info(x) | ||
113 | #define sd_debug(x) | ||
114 | #define sd_data(x) | ||
115 | #define sd_ctrl(x) | ||
116 | #endif | ||
117 | |||
118 | struct sdos_info { | ||
119 | struct sdioh_info *sd; | ||
120 | spinlock_t lock; | ||
121 | }; | ||
122 | |||
123 | static void brcmf_sdioh_irqhandler(struct sdio_func *func); | ||
124 | static void brcmf_sdioh_irqhandler_f2(struct sdio_func *func); | ||
125 | static int brcmf_sdioh_get_cisaddr(struct sdioh_info *sd, u32 regaddr); | ||
126 | static int brcmf_ops_sdio_probe(struct sdio_func *func, | ||
127 | const struct sdio_device_id *id); | ||
128 | static void brcmf_ops_sdio_remove(struct sdio_func *func); | ||
129 | |||
130 | #ifdef CONFIG_PM | ||
131 | static int brcmf_sdio_suspend(struct device *dev); | ||
132 | static int brcmf_sdio_resume(struct device *dev); | ||
133 | #endif /* CONFIG_PM */ | ||
134 | |||
135 | uint sd_f2_blocksize = 512; /* Default blocksize */ | ||
136 | |||
137 | uint sd_msglevel = 0x01; | ||
138 | |||
139 | /* module param defaults */ | ||
140 | static int clockoverride; | ||
141 | |||
142 | module_param(clockoverride, int, 0644); | ||
143 | MODULE_PARM_DESC(clockoverride, "SDIO card clock override"); | ||
144 | |||
145 | struct brcmf_sdmmc_instance *gInstance; | ||
146 | |||
147 | struct device sdmmc_dev; | ||
148 | |||
149 | /* devices we support, null terminated */ | ||
150 | static const struct sdio_device_id brcmf_sdmmc_ids[] = { | ||
151 | {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT)}, | ||
152 | {SDIO_DEVICE | ||
153 | (SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB)}, | ||
154 | {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325)}, | ||
155 | {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)}, | ||
156 | {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319)}, | ||
157 | { /* end: all zeroes */ }, | ||
158 | }; | ||
159 | |||
160 | #ifdef CONFIG_PM | ||
161 | static const struct dev_pm_ops brcmf_sdio_pm_ops = { | ||
162 | .suspend = brcmf_sdio_suspend, | ||
163 | .resume = brcmf_sdio_resume, | ||
164 | }; | ||
165 | #endif /* CONFIG_PM */ | ||
166 | |||
167 | static struct sdio_driver brcmf_sdmmc_driver = { | ||
168 | .probe = brcmf_ops_sdio_probe, | ||
169 | .remove = brcmf_ops_sdio_remove, | ||
170 | .name = "brcmfmac", | ||
171 | .id_table = brcmf_sdmmc_ids, | ||
172 | #ifdef CONFIG_PM | ||
173 | .drv = { | ||
174 | .pm = &brcmf_sdio_pm_ops, | ||
175 | }, | ||
176 | #endif /* CONFIG_PM */ | ||
177 | }; | ||
178 | |||
179 | MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); | ||
180 | |||
181 | BRCMF_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait); | ||
182 | BRCMF_PM_RESUME_WAIT_INIT(sdioh_request_word_wait); | ||
183 | BRCMF_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait); | ||
184 | BRCMF_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait); | ||
185 | |||
186 | static int | ||
187 | brcmf_sdioh_card_regread(struct sdioh_info *sd, int func, u32 regaddr, | ||
188 | int regsize, u32 *data); | ||
189 | |||
190 | static int brcmf_sdioh_enablefuncs(struct sdioh_info *sd) | ||
191 | { | ||
192 | int err_ret; | ||
193 | u32 fbraddr; | ||
194 | u8 func; | ||
195 | |||
196 | sd_trace(("%s\n", __func__)); | ||
197 | |||
198 | /* Get the Card's common CIS address */ | ||
199 | sd->com_cis_ptr = brcmf_sdioh_get_cisaddr(sd, SDIO_CCCR_CIS); | ||
200 | sd->func_cis_ptr[0] = sd->com_cis_ptr; | ||
201 | sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __func__, | ||
202 | sd->com_cis_ptr)); | ||
203 | |||
204 | /* Get the Card's function CIS (for each function) */ | ||
205 | for (fbraddr = SDIO_FBR_BASE(1), func = 1; | ||
206 | func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { | ||
207 | sd->func_cis_ptr[func] = | ||
208 | brcmf_sdioh_get_cisaddr(sd, SDIO_FBR_CIS + fbraddr); | ||
209 | sd_info(("%s: Function %d CIS Ptr = 0x%x\n", __func__, func, | ||
210 | sd->func_cis_ptr[func])); | ||
211 | } | ||
212 | |||
213 | sd->func_cis_ptr[0] = sd->com_cis_ptr; | ||
214 | sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __func__, | ||
215 | sd->com_cis_ptr)); | ||
216 | |||
217 | /* Enable Function 1 */ | ||
218 | sdio_claim_host(gInstance->func[1]); | ||
219 | err_ret = sdio_enable_func(gInstance->func[1]); | ||
220 | sdio_release_host(gInstance->func[1]); | ||
221 | if (err_ret) { | ||
222 | sd_err(("brcmf_sdioh_enablefuncs: Failed to enable F1 " | ||
223 | "Err: 0x%08x\n", err_ret)); | ||
224 | } | ||
225 | |||
226 | return false; | ||
227 | } | ||
228 | |||
229 | /* | ||
230 | * Public entry points & extern's | ||
231 | */ | ||
232 | struct sdioh_info *brcmf_sdioh_attach(void *bar0, uint irq) | ||
233 | { | ||
234 | struct sdioh_info *sd; | ||
235 | int err_ret; | ||
236 | |||
237 | sd_trace(("%s\n", __func__)); | ||
238 | |||
239 | if (gInstance == NULL) { | ||
240 | sd_err(("%s: SDIO Device not present\n", __func__)); | ||
241 | return NULL; | ||
242 | } | ||
243 | |||
244 | sd = kzalloc(sizeof(struct sdioh_info), GFP_ATOMIC); | ||
245 | if (sd == NULL) { | ||
246 | sd_err(("sdioh_attach: out of memory\n")); | ||
247 | return NULL; | ||
248 | } | ||
249 | if (brcmf_sdioh_osinit(sd) != 0) { | ||
250 | sd_err(("%s:sdioh_sdmmc_osinit() failed\n", __func__)); | ||
251 | kfree(sd); | ||
252 | return NULL; | ||
253 | } | ||
254 | |||
255 | sd->num_funcs = 2; | ||
256 | sd->use_client_ints = true; | ||
257 | sd->client_block_size[0] = 64; | ||
258 | |||
259 | gInstance->sd = sd; | ||
260 | |||
261 | /* Claim host controller */ | ||
262 | sdio_claim_host(gInstance->func[1]); | ||
263 | |||
264 | sd->client_block_size[1] = 64; | ||
265 | err_ret = sdio_set_block_size(gInstance->func[1], 64); | ||
266 | if (err_ret) | ||
267 | sd_err(("brcmf_sdioh_attach: Failed to set F1 blocksize\n")); | ||
268 | |||
269 | /* Release host controller F1 */ | ||
270 | sdio_release_host(gInstance->func[1]); | ||
271 | |||
272 | if (gInstance->func[2]) { | ||
273 | /* Claim host controller F2 */ | ||
274 | sdio_claim_host(gInstance->func[2]); | ||
275 | |||
276 | sd->client_block_size[2] = sd_f2_blocksize; | ||
277 | err_ret = | ||
278 | sdio_set_block_size(gInstance->func[2], sd_f2_blocksize); | ||
279 | if (err_ret) | ||
280 | sd_err(("brcmf_sdioh_attach: Failed to set F2 blocksize" | ||
281 | " to %d\n", sd_f2_blocksize)); | ||
282 | |||
283 | /* Release host controller F2 */ | ||
284 | sdio_release_host(gInstance->func[2]); | ||
285 | } | ||
286 | |||
287 | brcmf_sdioh_enablefuncs(sd); | ||
288 | |||
289 | sd_trace(("%s: Done\n", __func__)); | ||
290 | return sd; | ||
291 | } | ||
292 | |||
293 | extern int brcmf_sdioh_detach(struct sdioh_info *sd) | ||
294 | { | ||
295 | sd_trace(("%s\n", __func__)); | ||
296 | |||
297 | if (sd) { | ||
298 | |||
299 | /* Disable Function 2 */ | ||
300 | sdio_claim_host(gInstance->func[2]); | ||
301 | sdio_disable_func(gInstance->func[2]); | ||
302 | sdio_release_host(gInstance->func[2]); | ||
303 | |||
304 | /* Disable Function 1 */ | ||
305 | sdio_claim_host(gInstance->func[1]); | ||
306 | sdio_disable_func(gInstance->func[1]); | ||
307 | sdio_release_host(gInstance->func[1]); | ||
308 | |||
309 | /* deregister irq */ | ||
310 | brcmf_sdioh_osfree(sd); | ||
311 | |||
312 | kfree(sd); | ||
313 | } | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | /* Configure callback to client when we receive client interrupt */ | ||
318 | extern int | ||
319 | brcmf_sdioh_interrupt_register(struct sdioh_info *sd, void (*fn)(void *), | ||
320 | void *argh) | ||
321 | { | ||
322 | sd_trace(("%s: Entering\n", __func__)); | ||
323 | if (fn == NULL) { | ||
324 | sd_err(("%s: interrupt handler is NULL, not registering\n", | ||
325 | __func__)); | ||
326 | return -EINVAL; | ||
327 | } | ||
328 | |||
329 | sd->intr_handler = fn; | ||
330 | sd->intr_handler_arg = argh; | ||
331 | sd->intr_handler_valid = true; | ||
332 | |||
333 | /* register and unmask irq */ | ||
334 | if (gInstance->func[2]) { | ||
335 | sdio_claim_host(gInstance->func[2]); | ||
336 | sdio_claim_irq(gInstance->func[2], brcmf_sdioh_irqhandler_f2); | ||
337 | sdio_release_host(gInstance->func[2]); | ||
338 | } | ||
339 | |||
340 | if (gInstance->func[1]) { | ||
341 | sdio_claim_host(gInstance->func[1]); | ||
342 | sdio_claim_irq(gInstance->func[1], brcmf_sdioh_irqhandler); | ||
343 | sdio_release_host(gInstance->func[1]); | ||
344 | } | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | extern int brcmf_sdioh_interrupt_deregister(struct sdioh_info *sd) | ||
350 | { | ||
351 | sd_trace(("%s: Entering\n", __func__)); | ||
352 | |||
353 | if (gInstance->func[1]) { | ||
354 | /* register and unmask irq */ | ||
355 | sdio_claim_host(gInstance->func[1]); | ||
356 | sdio_release_irq(gInstance->func[1]); | ||
357 | sdio_release_host(gInstance->func[1]); | ||
358 | } | ||
359 | |||
360 | if (gInstance->func[2]) { | ||
361 | /* Claim host controller F2 */ | ||
362 | sdio_claim_host(gInstance->func[2]); | ||
363 | sdio_release_irq(gInstance->func[2]); | ||
364 | /* Release host controller F2 */ | ||
365 | sdio_release_host(gInstance->func[2]); | ||
366 | } | ||
367 | |||
368 | sd->intr_handler_valid = false; | ||
369 | sd->intr_handler = NULL; | ||
370 | sd->intr_handler_arg = NULL; | ||
371 | |||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | /* IOVar table */ | ||
376 | enum { | ||
377 | IOV_MSGLEVEL = 1, | ||
378 | IOV_BLOCKSIZE, | ||
379 | IOV_USEINTS, | ||
380 | IOV_NUMINTS, | ||
381 | IOV_DEVREG, | ||
382 | IOV_HCIREGS, | ||
383 | IOV_RXCHAIN | ||
384 | }; | ||
385 | |||
386 | const struct brcmu_iovar sdioh_iovars[] = { | ||
387 | {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0}, | ||
388 | {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0},/* ((fn << 16) | | ||
389 | size) */ | ||
390 | {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0}, | ||
391 | {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0}, | ||
392 | {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(struct brcmf_sdreg)} | ||
393 | , | ||
394 | {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0} | ||
395 | , | ||
396 | {NULL, 0, 0, 0, 0} | ||
397 | }; | ||
398 | |||
399 | int | ||
400 | brcmf_sdioh_iovar_op(struct sdioh_info *si, const char *name, | ||
401 | void *params, int plen, void *arg, int len, bool set) | ||
402 | { | ||
403 | const struct brcmu_iovar *vi = NULL; | ||
404 | int bcmerror = 0; | ||
405 | int val_size; | ||
406 | s32 int_val = 0; | ||
407 | bool bool_val; | ||
408 | u32 actionid; | ||
409 | |||
410 | if (name == NULL || len <= 0) | ||
411 | return -EINVAL; | ||
412 | |||
413 | /* Set does not take qualifiers */ | ||
414 | if (set && (params || plen)) | ||
415 | return -EINVAL; | ||
416 | |||
417 | /* Get must have return space;*/ | ||
418 | if (!set && !(arg && len)) | ||
419 | return -EINVAL; | ||
420 | |||
421 | sd_trace(("%s: Enter (%s %s)\n", __func__, (set ? "set" : "get"), | ||
422 | name)); | ||
423 | |||
424 | vi = brcmu_iovar_lookup(sdioh_iovars, name); | ||
425 | if (vi == NULL) { | ||
426 | bcmerror = -ENOTSUPP; | ||
427 | goto exit; | ||
428 | } | ||
429 | |||
430 | bcmerror = brcmu_iovar_lencheck(vi, arg, len, set); | ||
431 | if (bcmerror != 0) | ||
432 | goto exit; | ||
433 | |||
434 | /* Set up params so get and set can share the convenience variables */ | ||
435 | if (params == NULL) { | ||
436 | params = arg; | ||
437 | plen = len; | ||
438 | } | ||
439 | |||
440 | if (vi->type == IOVT_VOID) | ||
441 | val_size = 0; | ||
442 | else if (vi->type == IOVT_BUFFER) | ||
443 | val_size = len; | ||
444 | else | ||
445 | val_size = sizeof(int); | ||
446 | |||
447 | if (plen >= (int)sizeof(int_val)) | ||
448 | memcpy(&int_val, params, sizeof(int_val)); | ||
449 | |||
450 | bool_val = (int_val != 0) ? true : false; | ||
451 | |||
452 | actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); | ||
453 | switch (actionid) { | ||
454 | case IOV_GVAL(IOV_MSGLEVEL): | ||
455 | int_val = (s32) sd_msglevel; | ||
456 | memcpy(arg, &int_val, val_size); | ||
457 | break; | ||
458 | |||
459 | case IOV_SVAL(IOV_MSGLEVEL): | ||
460 | sd_msglevel = int_val; | ||
461 | break; | ||
462 | |||
463 | case IOV_GVAL(IOV_BLOCKSIZE): | ||
464 | if ((u32) int_val > si->num_funcs) { | ||
465 | bcmerror = -EINVAL; | ||
466 | break; | ||
467 | } | ||
468 | int_val = (s32) si->client_block_size[int_val]; | ||
469 | memcpy(arg, &int_val, val_size); | ||
470 | break; | ||
471 | |||
472 | case IOV_SVAL(IOV_BLOCKSIZE): | ||
473 | { | ||
474 | uint func = ((u32) int_val >> 16); | ||
475 | uint blksize = (u16) int_val; | ||
476 | uint maxsize; | ||
477 | |||
478 | if (func > si->num_funcs) { | ||
479 | bcmerror = -EINVAL; | ||
480 | break; | ||
481 | } | ||
482 | |||
483 | switch (func) { | ||
484 | case 0: | ||
485 | maxsize = 32; | ||
486 | break; | ||
487 | case 1: | ||
488 | maxsize = BLOCK_SIZE_4318; | ||
489 | break; | ||
490 | case 2: | ||
491 | maxsize = BLOCK_SIZE_4328; | ||
492 | break; | ||
493 | default: | ||
494 | maxsize = 0; | ||
495 | } | ||
496 | if (blksize > maxsize) { | ||
497 | bcmerror = -EINVAL; | ||
498 | break; | ||
499 | } | ||
500 | if (!blksize) | ||
501 | blksize = maxsize; | ||
502 | |||
503 | /* Now set it */ | ||
504 | si->client_block_size[func] = blksize; | ||
505 | |||
506 | break; | ||
507 | } | ||
508 | |||
509 | case IOV_GVAL(IOV_RXCHAIN): | ||
510 | int_val = false; | ||
511 | memcpy(arg, &int_val, val_size); | ||
512 | break; | ||
513 | |||
514 | case IOV_GVAL(IOV_USEINTS): | ||
515 | int_val = (s32) si->use_client_ints; | ||
516 | memcpy(arg, &int_val, val_size); | ||
517 | break; | ||
518 | |||
519 | case IOV_SVAL(IOV_USEINTS): | ||
520 | si->use_client_ints = (bool) int_val; | ||
521 | if (si->use_client_ints) | ||
522 | si->intmask |= CLIENT_INTR; | ||
523 | else | ||
524 | si->intmask &= ~CLIENT_INTR; | ||
525 | |||
526 | break; | ||
527 | |||
528 | case IOV_GVAL(IOV_NUMINTS): | ||
529 | int_val = (s32) si->intrcount; | ||
530 | memcpy(arg, &int_val, val_size); | ||
531 | break; | ||
532 | |||
533 | case IOV_GVAL(IOV_DEVREG): | ||
534 | { | ||
535 | struct brcmf_sdreg *sd_ptr = | ||
536 | (struct brcmf_sdreg *) params; | ||
537 | u8 data = 0; | ||
538 | |||
539 | if (brcmf_sdioh_cfg_read | ||
540 | (si, sd_ptr->func, sd_ptr->offset, &data)) { | ||
541 | bcmerror = -EIO; | ||
542 | break; | ||
543 | } | ||
544 | |||
545 | int_val = (int)data; | ||
546 | memcpy(arg, &int_val, sizeof(int_val)); | ||
547 | break; | ||
548 | } | ||
549 | |||
550 | case IOV_SVAL(IOV_DEVREG): | ||
551 | { | ||
552 | struct brcmf_sdreg *sd_ptr = | ||
553 | (struct brcmf_sdreg *) params; | ||
554 | u8 data = (u8) sd_ptr->value; | ||
555 | |||
556 | if (brcmf_sdioh_cfg_write | ||
557 | (si, sd_ptr->func, sd_ptr->offset, &data)) { | ||
558 | bcmerror = -EIO; | ||
559 | break; | ||
560 | } | ||
561 | break; | ||
562 | } | ||
563 | |||
564 | default: | ||
565 | bcmerror = -ENOTSUPP; | ||
566 | break; | ||
567 | } | ||
568 | exit: | ||
569 | |||
570 | return bcmerror; | ||
571 | } | ||
572 | |||
573 | extern int | ||
574 | brcmf_sdioh_cfg_read(struct sdioh_info *sd, uint fnc_num, u32 addr, u8 *data) | ||
575 | { | ||
576 | int status; | ||
577 | /* No lock needed since brcmf_sdioh_request_byte does locking */ | ||
578 | status = brcmf_sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); | ||
579 | return status; | ||
580 | } | ||
581 | |||
582 | extern int | ||
583 | brcmf_sdioh_cfg_write(struct sdioh_info *sd, uint fnc_num, u32 addr, u8 *data) | ||
584 | { | ||
585 | /* No lock needed since brcmf_sdioh_request_byte does locking */ | ||
586 | int status; | ||
587 | status = brcmf_sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); | ||
588 | return status; | ||
589 | } | ||
590 | |||
591 | static int brcmf_sdioh_get_cisaddr(struct sdioh_info *sd, u32 regaddr) | ||
592 | { | ||
593 | /* read 24 bits and return valid 17 bit addr */ | ||
594 | int i; | ||
595 | u32 scratch, regdata; | ||
596 | u8 *ptr = (u8 *)&scratch; | ||
597 | for (i = 0; i < 3; i++) { | ||
598 | if ((brcmf_sdioh_card_regread(sd, 0, regaddr, 1, ®data)) != | ||
599 | SUCCESS) | ||
600 | sd_err(("%s: Can't read!\n", __func__)); | ||
601 | |||
602 | *ptr++ = (u8) regdata; | ||
603 | regaddr++; | ||
604 | } | ||
605 | |||
606 | /* Only the lower 17-bits are valid */ | ||
607 | scratch = le32_to_cpu(scratch); | ||
608 | scratch &= 0x0001FFFF; | ||
609 | return scratch; | ||
610 | } | ||
611 | |||
612 | extern int | ||
613 | brcmf_sdioh_cis_read(struct sdioh_info *sd, uint func, u8 *cisd, u32 length) | ||
614 | { | ||
615 | u32 count; | ||
616 | int offset; | ||
617 | u32 foo; | ||
618 | u8 *cis = cisd; | ||
619 | |||
620 | sd_trace(("%s: Func = %d\n", __func__, func)); | ||
621 | |||
622 | if (!sd->func_cis_ptr[func]) { | ||
623 | memset(cis, 0, length); | ||
624 | sd_err(("%s: no func_cis_ptr[%d]\n", __func__, func)); | ||
625 | return -ENOTSUPP; | ||
626 | } | ||
627 | |||
628 | sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __func__, func, | ||
629 | sd->func_cis_ptr[func])); | ||
630 | |||
631 | for (count = 0; count < length; count++) { | ||
632 | offset = sd->func_cis_ptr[func] + count; | ||
633 | if (brcmf_sdioh_card_regread(sd, 0, offset, 1, &foo) < 0) { | ||
634 | sd_err(("%s: regread failed: Can't read CIS\n", | ||
635 | __func__)); | ||
636 | return -EIO; | ||
637 | } | ||
638 | |||
639 | *cis = (u8) (foo & 0xff); | ||
640 | cis++; | ||
641 | } | ||
642 | |||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | extern int | ||
647 | brcmf_sdioh_request_byte(struct sdioh_info *sd, uint rw, uint func, | ||
648 | uint regaddr, u8 *byte) | ||
649 | { | ||
650 | int err_ret; | ||
651 | |||
652 | sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __func__, rw, func, | ||
653 | regaddr)); | ||
654 | |||
655 | BRCMF_PM_RESUME_WAIT(sdioh_request_byte_wait); | ||
656 | BRCMF_PM_RESUME_RETURN_ERROR(-EIO); | ||
657 | if (rw) { /* CMD52 Write */ | ||
658 | if (func == 0) { | ||
659 | /* Can only directly write to some F0 registers. | ||
660 | * Handle F2 enable | ||
661 | * as a special case. | ||
662 | */ | ||
663 | if (regaddr == SDIO_CCCR_IOEx) { | ||
664 | if (gInstance->func[2]) { | ||
665 | sdio_claim_host(gInstance->func[2]); | ||
666 | if (*byte & SDIO_FUNC_ENABLE_2) { | ||
667 | /* Enable Function 2 */ | ||
668 | err_ret = | ||
669 | sdio_enable_func | ||
670 | (gInstance->func[2]); | ||
671 | if (err_ret) | ||
672 | sd_err(("request_byte: " | ||
673 | "enable F2 " | ||
674 | "failed:%d\n", | ||
675 | err_ret)); | ||
676 | } else { | ||
677 | /* Disable Function 2 */ | ||
678 | err_ret = | ||
679 | sdio_disable_func | ||
680 | (gInstance->func[2]); | ||
681 | if (err_ret) | ||
682 | sd_err(("request_byte: " | ||
683 | "Disab F2 " | ||
684 | "failed:%d\n", | ||
685 | err_ret)); | ||
686 | } | ||
687 | sdio_release_host(gInstance->func[2]); | ||
688 | } | ||
689 | } | ||
690 | /* to allow abort command through F1 */ | ||
691 | else if (regaddr == SDIO_CCCR_ABORT) { | ||
692 | sdio_claim_host(gInstance->func[func]); | ||
693 | /* | ||
694 | * this sdio_f0_writeb() can be replaced | ||
695 | * with another api | ||
696 | * depending upon MMC driver change. | ||
697 | * As of this time, this is temporaray one | ||
698 | */ | ||
699 | sdio_writeb(gInstance->func[func], *byte, | ||
700 | regaddr, &err_ret); | ||
701 | sdio_release_host(gInstance->func[func]); | ||
702 | } else if (regaddr < 0xF0) { | ||
703 | sd_err(("brcmf: F0 Wr:0x%02x: write " | ||
704 | "disallowed\n", regaddr)); | ||
705 | } else { | ||
706 | /* Claim host controller, perform F0 write, | ||
707 | and release */ | ||
708 | sdio_claim_host(gInstance->func[func]); | ||
709 | sdio_f0_writeb(gInstance->func[func], *byte, | ||
710 | regaddr, &err_ret); | ||
711 | sdio_release_host(gInstance->func[func]); | ||
712 | } | ||
713 | } else { | ||
714 | /* Claim host controller, perform Fn write, | ||
715 | and release */ | ||
716 | sdio_claim_host(gInstance->func[func]); | ||
717 | sdio_writeb(gInstance->func[func], *byte, regaddr, | ||
718 | &err_ret); | ||
719 | sdio_release_host(gInstance->func[func]); | ||
720 | } | ||
721 | } else { /* CMD52 Read */ | ||
722 | /* Claim host controller, perform Fn read, and release */ | ||
723 | sdio_claim_host(gInstance->func[func]); | ||
724 | |||
725 | if (func == 0) { | ||
726 | *byte = | ||
727 | sdio_f0_readb(gInstance->func[func], regaddr, | ||
728 | &err_ret); | ||
729 | } else { | ||
730 | *byte = | ||
731 | sdio_readb(gInstance->func[func], regaddr, | ||
732 | &err_ret); | ||
733 | } | ||
734 | |||
735 | sdio_release_host(gInstance->func[func]); | ||
736 | } | ||
737 | |||
738 | if (err_ret) | ||
739 | sd_err(("brcmf: Failed to %s byte F%d:@0x%05x=%02x, " | ||
740 | "Err: %d\n", rw ? "Write" : "Read", func, regaddr, | ||
741 | *byte, err_ret)); | ||
742 | |||
743 | return err_ret; | ||
744 | } | ||
745 | |||
746 | extern int | ||
747 | brcmf_sdioh_request_word(struct sdioh_info *sd, uint cmd_type, uint rw, | ||
748 | uint func, uint addr, u32 *word, uint nbytes) | ||
749 | { | ||
750 | int err_ret = -EIO; | ||
751 | |||
752 | if (func == 0) { | ||
753 | sd_err(("%s: Only CMD52 allowed to F0.\n", __func__)); | ||
754 | return -EINVAL; | ||
755 | } | ||
756 | |||
757 | sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", | ||
758 | __func__, cmd_type, rw, func, addr, nbytes)); | ||
759 | |||
760 | BRCMF_PM_RESUME_WAIT(sdioh_request_word_wait); | ||
761 | BRCMF_PM_RESUME_RETURN_ERROR(-EIO); | ||
762 | /* Claim host controller */ | ||
763 | sdio_claim_host(gInstance->func[func]); | ||
764 | |||
765 | if (rw) { /* CMD52 Write */ | ||
766 | if (nbytes == 4) { | ||
767 | sdio_writel(gInstance->func[func], *word, addr, | ||
768 | &err_ret); | ||
769 | } else if (nbytes == 2) { | ||
770 | sdio_writew(gInstance->func[func], (*word & 0xFFFF), | ||
771 | addr, &err_ret); | ||
772 | } else { | ||
773 | sd_err(("%s: Invalid nbytes: %d\n", __func__, nbytes)); | ||
774 | } | ||
775 | } else { /* CMD52 Read */ | ||
776 | if (nbytes == 4) { | ||
777 | *word = | ||
778 | sdio_readl(gInstance->func[func], addr, &err_ret); | ||
779 | } else if (nbytes == 2) { | ||
780 | *word = | ||
781 | sdio_readw(gInstance->func[func], addr, | ||
782 | &err_ret) & 0xFFFF; | ||
783 | } else { | ||
784 | sd_err(("%s: Invalid nbytes: %d\n", __func__, nbytes)); | ||
785 | } | ||
786 | } | ||
787 | |||
788 | /* Release host controller */ | ||
789 | sdio_release_host(gInstance->func[func]); | ||
790 | |||
791 | if (err_ret) { | ||
792 | sd_err(("brcmf: Failed to %s word, Err: 0x%08x\n", | ||
793 | rw ? "Write" : "Read", err_ret)); | ||
794 | } | ||
795 | |||
796 | return err_ret; | ||
797 | } | ||
798 | |||
799 | static int | ||
800 | brcmf_sdioh_request_packet(struct sdioh_info *sd, uint fix_inc, uint write, | ||
801 | uint func, uint addr, struct sk_buff *pkt) | ||
802 | { | ||
803 | bool fifo = (fix_inc == SDIOH_DATA_FIX); | ||
804 | u32 SGCount = 0; | ||
805 | int err_ret = 0; | ||
806 | |||
807 | struct sk_buff *pnext; | ||
808 | |||
809 | sd_trace(("%s: Enter\n", __func__)); | ||
810 | |||
811 | BRCMF_PM_RESUME_WAIT(sdioh_request_packet_wait); | ||
812 | BRCMF_PM_RESUME_RETURN_ERROR(-EIO); | ||
813 | |||
814 | /* Claim host controller */ | ||
815 | sdio_claim_host(gInstance->func[func]); | ||
816 | for (pnext = pkt; pnext; pnext = pnext->next) { | ||
817 | uint pkt_len = pnext->len; | ||
818 | pkt_len += 3; | ||
819 | pkt_len &= 0xFFFFFFFC; | ||
820 | |||
821 | if ((write) && (!fifo)) { | ||
822 | err_ret = sdio_memcpy_toio(gInstance->func[func], addr, | ||
823 | ((u8 *) (pnext->data)), | ||
824 | pkt_len); | ||
825 | } else if (write) { | ||
826 | err_ret = sdio_memcpy_toio(gInstance->func[func], addr, | ||
827 | ((u8 *) (pnext->data)), | ||
828 | pkt_len); | ||
829 | } else if (fifo) { | ||
830 | err_ret = sdio_readsb(gInstance->func[func], | ||
831 | ((u8 *) (pnext->data)), | ||
832 | addr, pkt_len); | ||
833 | } else { | ||
834 | err_ret = sdio_memcpy_fromio(gInstance->func[func], | ||
835 | ((u8 *) (pnext->data)), | ||
836 | addr, pkt_len); | ||
837 | } | ||
838 | |||
839 | if (err_ret) { | ||
840 | sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d," | ||
841 | "ERR=0x%08x\n", __func__, | ||
842 | (write) ? "TX" : "RX", | ||
843 | pnext, SGCount, addr, pkt_len, err_ret)); | ||
844 | } else { | ||
845 | sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n", | ||
846 | __func__, | ||
847 | (write) ? "TX" : "RX", | ||
848 | pnext, SGCount, addr, pkt_len)); | ||
849 | } | ||
850 | |||
851 | if (!fifo) | ||
852 | addr += pkt_len; | ||
853 | SGCount++; | ||
854 | |||
855 | } | ||
856 | |||
857 | /* Release host controller */ | ||
858 | sdio_release_host(gInstance->func[func]); | ||
859 | |||
860 | sd_trace(("%s: Exit\n", __func__)); | ||
861 | return err_ret; | ||
862 | } | ||
863 | |||
864 | /* | ||
865 | * This function takes a buffer or packet, and fixes everything up | ||
866 | * so that in the end, a DMA-able packet is created. | ||
867 | * | ||
868 | * A buffer does not have an associated packet pointer, | ||
869 | * and may or may not be aligned. | ||
870 | * A packet may consist of a single packet, or a packet chain. | ||
871 | * If it is a packet chain, then all the packets in the chain | ||
872 | * must be properly aligned. | ||
873 | * | ||
874 | * If the packet data is not aligned, then there may only be | ||
875 | * one packet, and in this case, it is copied to a new | ||
876 | * aligned packet. | ||
877 | * | ||
878 | */ | ||
879 | extern int | ||
880 | brcmf_sdioh_request_buffer(struct sdioh_info *sd, uint pio_dma, uint fix_inc, | ||
881 | uint write, uint func, uint addr, uint reg_width, | ||
882 | uint buflen_u, u8 *buffer, struct sk_buff *pkt) | ||
883 | { | ||
884 | int Status; | ||
885 | struct sk_buff *mypkt = NULL; | ||
886 | |||
887 | sd_trace(("%s: Enter\n", __func__)); | ||
888 | |||
889 | BRCMF_PM_RESUME_WAIT(sdioh_request_buffer_wait); | ||
890 | BRCMF_PM_RESUME_RETURN_ERROR(-EIO); | ||
891 | /* Case 1: we don't have a packet. */ | ||
892 | if (pkt == NULL) { | ||
893 | sd_data(("%s: Creating new %s Packet, len=%d\n", | ||
894 | __func__, write ? "TX" : "RX", buflen_u)); | ||
895 | mypkt = brcmu_pkt_buf_get_skb(buflen_u); | ||
896 | if (!mypkt) { | ||
897 | sd_err(("%s: brcmu_pkt_buf_get_skb failed: len %d\n", | ||
898 | __func__, buflen_u)); | ||
899 | return -EIO; | ||
900 | } | ||
901 | |||
902 | /* For a write, copy the buffer data into the packet. */ | ||
903 | if (write) | ||
904 | memcpy(mypkt->data, buffer, buflen_u); | ||
905 | |||
906 | Status = brcmf_sdioh_request_packet(sd, fix_inc, write, func, | ||
907 | addr, mypkt); | ||
908 | |||
909 | /* For a read, copy the packet data back to the buffer. */ | ||
910 | if (!write) | ||
911 | memcpy(buffer, mypkt->data, buflen_u); | ||
912 | |||
913 | brcmu_pkt_buf_free_skb(mypkt); | ||
914 | } else if (((ulong) (pkt->data) & DMA_ALIGN_MASK) != 0) { | ||
915 | /* | ||
916 | * Case 2: We have a packet, but it is unaligned. | ||
917 | * In this case, we cannot have a chain (pkt->next == NULL) | ||
918 | */ | ||
919 | sd_data(("%s: Creating aligned %s Packet, len=%d\n", | ||
920 | __func__, write ? "TX" : "RX", pkt->len)); | ||
921 | mypkt = brcmu_pkt_buf_get_skb(pkt->len); | ||
922 | if (!mypkt) { | ||
923 | sd_err(("%s: brcmu_pkt_buf_get_skb failed: len %d\n", | ||
924 | __func__, pkt->len)); | ||
925 | return -EIO; | ||
926 | } | ||
927 | |||
928 | /* For a write, copy the buffer data into the packet. */ | ||
929 | if (write) | ||
930 | memcpy(mypkt->data, pkt->data, pkt->len); | ||
931 | |||
932 | Status = brcmf_sdioh_request_packet(sd, fix_inc, write, func, | ||
933 | addr, mypkt); | ||
934 | |||
935 | /* For a read, copy the packet data back to the buffer. */ | ||
936 | if (!write) | ||
937 | memcpy(pkt->data, mypkt->data, mypkt->len); | ||
938 | |||
939 | brcmu_pkt_buf_free_skb(mypkt); | ||
940 | } else { /* case 3: We have a packet and | ||
941 | it is aligned. */ | ||
942 | sd_data(("%s: Aligned %s Packet, direct DMA\n", | ||
943 | __func__, write ? "Tx" : "Rx")); | ||
944 | Status = brcmf_sdioh_request_packet(sd, fix_inc, write, func, | ||
945 | addr, pkt); | ||
946 | } | ||
947 | |||
948 | return Status; | ||
949 | } | ||
950 | |||
951 | /* this function performs "abort" for both of host & device */ | ||
952 | extern int brcmf_sdioh_abort(struct sdioh_info *sd, uint func) | ||
953 | { | ||
954 | char t_func = (char)func; | ||
955 | sd_trace(("%s: Enter\n", __func__)); | ||
956 | |||
957 | /* issue abort cmd52 command through F0 */ | ||
958 | brcmf_sdioh_request_byte(sd, SDIOH_WRITE, SDIO_FUNC_0, SDIO_CCCR_ABORT, | ||
959 | &t_func); | ||
960 | |||
961 | sd_trace(("%s: Exit\n", __func__)); | ||
962 | return 0; | ||
963 | } | ||
964 | |||
965 | /* Disable device interrupt */ | ||
966 | void brcmf_sdioh_dev_intr_off(struct sdioh_info *sd) | ||
967 | { | ||
968 | sd_trace(("%s: %d\n", __func__, sd->use_client_ints)); | ||
969 | sd->intmask &= ~CLIENT_INTR; | ||
970 | } | ||
971 | |||
972 | /* Enable device interrupt */ | ||
973 | void brcmf_sdioh_dev_intr_on(struct sdioh_info *sd) | ||
974 | { | ||
975 | sd_trace(("%s: %d\n", __func__, sd->use_client_ints)); | ||
976 | sd->intmask |= CLIENT_INTR; | ||
977 | } | ||
978 | |||
979 | /* Read client card reg */ | ||
980 | int | ||
981 | brcmf_sdioh_card_regread(struct sdioh_info *sd, int func, u32 regaddr, | ||
982 | int regsize, u32 *data) | ||
983 | { | ||
984 | |||
985 | if ((func == 0) || (regsize == 1)) { | ||
986 | u8 temp = 0; | ||
987 | |||
988 | brcmf_sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); | ||
989 | *data = temp; | ||
990 | *data &= 0xff; | ||
991 | sd_data(("%s: byte read data=0x%02x\n", __func__, *data)); | ||
992 | } else { | ||
993 | brcmf_sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, | ||
994 | regsize); | ||
995 | if (regsize == 2) | ||
996 | *data &= 0xffff; | ||
997 | |||
998 | sd_data(("%s: word read data=0x%08x\n", __func__, *data)); | ||
999 | } | ||
1000 | |||
1001 | return SUCCESS; | ||
1002 | } | ||
1003 | |||
1004 | static void brcmf_sdioh_irqhandler(struct sdio_func *func) | ||
1005 | { | ||
1006 | struct sdioh_info *sd; | ||
1007 | |||
1008 | sd_trace(("brcmf: ***IRQHandler\n")); | ||
1009 | sd = gInstance->sd; | ||
1010 | |||
1011 | sdio_release_host(gInstance->func[0]); | ||
1012 | |||
1013 | if (sd->use_client_ints) { | ||
1014 | sd->intrcount++; | ||
1015 | (sd->intr_handler) (sd->intr_handler_arg); | ||
1016 | } else { | ||
1017 | sd_err(("brcmf: ***IRQHandler\n")); | ||
1018 | |||
1019 | sd_err(("%s: Not ready for intr: enabled %d, handler %p\n", | ||
1020 | __func__, sd->client_intr_enabled, sd->intr_handler)); | ||
1021 | } | ||
1022 | |||
1023 | sdio_claim_host(gInstance->func[0]); | ||
1024 | } | ||
1025 | |||
1026 | /* interrupt handler for F2 (dummy handler) */ | ||
1027 | static void brcmf_sdioh_irqhandler_f2(struct sdio_func *func) | ||
1028 | { | ||
1029 | struct sdioh_info *sd; | ||
1030 | |||
1031 | sd_trace(("brcmf: ***IRQHandlerF2\n")); | ||
1032 | |||
1033 | sd = gInstance->sd; | ||
1034 | } | ||
1035 | |||
1036 | static int brcmf_ops_sdio_probe(struct sdio_func *func, | ||
1037 | const struct sdio_device_id *id) | ||
1038 | { | ||
1039 | int ret = 0; | ||
1040 | static struct sdio_func sdio_func_0; | ||
1041 | sd_trace(("sdio_probe: %s Enter\n", __func__)); | ||
1042 | sd_trace(("sdio_probe: func->class=%x\n", func->class)); | ||
1043 | sd_trace(("sdio_vendor: 0x%04x\n", func->vendor)); | ||
1044 | sd_trace(("sdio_device: 0x%04x\n", func->device)); | ||
1045 | sd_trace(("Function#: 0x%04x\n", func->num)); | ||
1046 | |||
1047 | if (func->num == 1) { | ||
1048 | sdio_func_0.num = 0; | ||
1049 | sdio_func_0.card = func->card; | ||
1050 | gInstance->func[0] = &sdio_func_0; | ||
1051 | if (func->device == 0x4) { /* 4318 */ | ||
1052 | gInstance->func[2] = NULL; | ||
1053 | sd_trace(("NIC found, calling brcmf_sdio_probe...\n")); | ||
1054 | ret = brcmf_sdio_probe(&sdmmc_dev); | ||
1055 | } | ||
1056 | } | ||
1057 | |||
1058 | gInstance->func[func->num] = func; | ||
1059 | |||
1060 | if (func->num == 2) { | ||
1061 | brcmf_cfg80211_sdio_func(func); | ||
1062 | sd_trace(("F2 found, calling brcmf_sdio_probe...\n")); | ||
1063 | ret = brcmf_sdio_probe(&sdmmc_dev); | ||
1064 | } | ||
1065 | |||
1066 | return ret; | ||
1067 | } | ||
1068 | |||
1069 | static void brcmf_ops_sdio_remove(struct sdio_func *func) | ||
1070 | { | ||
1071 | sd_trace(("%s Enter\n", __func__)); | ||
1072 | sd_info(("func->class=%x\n", func->class)); | ||
1073 | sd_info(("sdio_vendor: 0x%04x\n", func->vendor)); | ||
1074 | sd_info(("sdio_device: 0x%04x\n", func->device)); | ||
1075 | sd_info(("Function#: 0x%04x\n", func->num)); | ||
1076 | |||
1077 | if (func->num == 2) { | ||
1078 | sd_trace(("F2 found, calling brcmf_sdio_remove...\n")); | ||
1079 | brcmf_sdio_remove(&sdmmc_dev); | ||
1080 | } | ||
1081 | } | ||
1082 | |||
1083 | |||
1084 | #ifdef CONFIG_PM | ||
1085 | static int brcmf_sdio_suspend(struct device *dev) | ||
1086 | { | ||
1087 | mmc_pm_flag_t sdio_flags; | ||
1088 | int ret = 0; | ||
1089 | |||
1090 | sd_trace(("%s\n", __func__)); | ||
1091 | |||
1092 | sdio_flags = sdio_get_host_pm_caps(gInstance->func[1]); | ||
1093 | if (!(sdio_flags & MMC_PM_KEEP_POWER)) { | ||
1094 | sd_err(("Host can't keep power while suspended\n")); | ||
1095 | return -EINVAL; | ||
1096 | } | ||
1097 | |||
1098 | ret = sdio_set_host_pm_flags(gInstance->func[1], MMC_PM_KEEP_POWER); | ||
1099 | if (ret) { | ||
1100 | sd_err(("Failed to set pm_flags\n")); | ||
1101 | return ret; | ||
1102 | } | ||
1103 | |||
1104 | brcmf_sdio_wdtmr_enable(false); | ||
1105 | |||
1106 | return ret; | ||
1107 | } | ||
1108 | |||
1109 | static int brcmf_sdio_resume(struct device *dev) | ||
1110 | { | ||
1111 | brcmf_sdio_wdtmr_enable(true); | ||
1112 | return 0; | ||
1113 | } | ||
1114 | #endif /* CONFIG_PM */ | ||
1115 | |||
1116 | int brcmf_sdioh_osinit(struct sdioh_info *sd) | ||
1117 | { | ||
1118 | struct sdos_info *sdos; | ||
1119 | |||
1120 | sdos = kmalloc(sizeof(struct sdos_info), GFP_ATOMIC); | ||
1121 | sd->sdos_info = (void *)sdos; | ||
1122 | if (sdos == NULL) | ||
1123 | return -ENOMEM; | ||
1124 | |||
1125 | sdos->sd = sd; | ||
1126 | spin_lock_init(&sdos->lock); | ||
1127 | return 0; | ||
1128 | } | ||
1129 | |||
1130 | void brcmf_sdioh_osfree(struct sdioh_info *sd) | ||
1131 | { | ||
1132 | struct sdos_info *sdos; | ||
1133 | |||
1134 | sdos = (struct sdos_info *)sd->sdos_info; | ||
1135 | kfree(sdos); | ||
1136 | } | ||
1137 | |||
1138 | /* Interrupt enable/disable */ | ||
1139 | int brcmf_sdioh_interrupt_set(struct sdioh_info *sd, bool enable) | ||
1140 | { | ||
1141 | unsigned long flags; | ||
1142 | struct sdos_info *sdos; | ||
1143 | |||
1144 | sd_trace(("%s: %s\n", __func__, enable ? "Enabling" : "Disabling")); | ||
1145 | |||
1146 | sdos = (struct sdos_info *)sd->sdos_info; | ||
1147 | |||
1148 | if (enable && !(sd->intr_handler && sd->intr_handler_arg)) { | ||
1149 | sd_err(("%s: no handler registered, will not enable\n", | ||
1150 | __func__)); | ||
1151 | return -EINVAL; | ||
1152 | } | ||
1153 | |||
1154 | /* Ensure atomicity for enable/disable calls */ | ||
1155 | spin_lock_irqsave(&sdos->lock, flags); | ||
1156 | |||
1157 | sd->client_intr_enabled = enable; | ||
1158 | if (enable) | ||
1159 | brcmf_sdioh_dev_intr_on(sd); | ||
1160 | else | ||
1161 | brcmf_sdioh_dev_intr_off(sd); | ||
1162 | |||
1163 | spin_unlock_irqrestore(&sdos->lock, flags); | ||
1164 | |||
1165 | return 0; | ||
1166 | } | ||
1167 | |||
1168 | /* | ||
1169 | * module init | ||
1170 | */ | ||
1171 | int brcmf_sdio_function_init(void) | ||
1172 | { | ||
1173 | int error = 0; | ||
1174 | sd_trace(("brcmf_sdio_function_init: %s Enter\n", __func__)); | ||
1175 | |||
1176 | gInstance = kzalloc(sizeof(struct brcmf_sdmmc_instance), GFP_KERNEL); | ||
1177 | if (!gInstance) | ||
1178 | return -ENOMEM; | ||
1179 | |||
1180 | memset(&sdmmc_dev, 0, sizeof(sdmmc_dev)); | ||
1181 | error = sdio_register_driver(&brcmf_sdmmc_driver); | ||
1182 | |||
1183 | return error; | ||
1184 | } | ||
1185 | |||
1186 | /* | ||
1187 | * module cleanup | ||
1188 | */ | ||
1189 | void brcmf_sdio_function_cleanup(void) | ||
1190 | { | ||
1191 | sd_trace(("%s Enter\n", __func__)); | ||
1192 | |||
1193 | sdio_unregister_driver(&brcmf_sdmmc_driver); | ||
1194 | |||
1195 | kfree(gInstance); | ||
1196 | } | ||
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd.h b/drivers/staging/brcm80211/brcmfmac/dhd.h new file mode 100644 index 00000000000..82bf04df16d --- /dev/null +++ b/drivers/staging/brcm80211/brcmfmac/dhd.h | |||
@@ -0,0 +1,904 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | /**************** | ||
18 | * Common types * | ||
19 | */ | ||
20 | |||
21 | #ifndef _BRCMF_H_ | ||
22 | #define _BRCMF_H_ | ||
23 | |||
24 | #define BRCMF_VERSION_STR "4.218.248.5" | ||
25 | |||
26 | #define BRCMF_C_IOCTL_SMLEN 256 /* "small" ioctl buffer required */ | ||
27 | #define BRCMF_C_IOCTL_MEDLEN 1536 /* "med" ioctl buffer required */ | ||
28 | #define BRCMF_C_IOCTL_MAXLEN 8192 | ||
29 | |||
30 | #define BRCMF_C_UP 2 | ||
31 | #define BRCMF_C_SET_PROMISC 10 | ||
32 | #define BRCMF_C_GET_RATE 12 | ||
33 | #define BRCMF_C_GET_INFRA 19 | ||
34 | #define BRCMF_C_SET_INFRA 20 | ||
35 | #define BRCMF_C_GET_AUTH 21 | ||
36 | #define BRCMF_C_SET_AUTH 22 | ||
37 | #define BRCMF_C_GET_BSSID 23 | ||
38 | #define BRCMF_C_GET_SSID 25 | ||
39 | #define BRCMF_C_SET_SSID 26 | ||
40 | #define BRCMF_C_GET_CHANNEL 29 | ||
41 | #define BRCMF_C_GET_SRL 31 | ||
42 | #define BRCMF_C_GET_LRL 33 | ||
43 | #define BRCMF_C_GET_RADIO 37 | ||
44 | #define BRCMF_C_SET_RADIO 38 | ||
45 | #define BRCMF_C_GET_PHYTYPE 39 | ||
46 | #define BRCMF_C_SET_KEY 45 | ||
47 | #define BRCMF_C_SET_PASSIVE_SCAN 49 | ||
48 | #define BRCMF_C_SCAN 50 | ||
49 | #define BRCMF_C_SCAN_RESULTS 51 | ||
50 | #define BRCMF_C_DISASSOC 52 | ||
51 | #define BRCMF_C_REASSOC 53 | ||
52 | #define BRCMF_C_SET_ROAM_TRIGGER 55 | ||
53 | #define BRCMF_C_SET_ROAM_DELTA 57 | ||
54 | #define BRCMF_C_GET_DTIMPRD 77 | ||
55 | #define BRCMF_C_SET_COUNTRY 84 | ||
56 | #define BRCMF_C_GET_PM 85 | ||
57 | #define BRCMF_C_SET_PM 86 | ||
58 | #define BRCMF_C_GET_AP 117 | ||
59 | #define BRCMF_C_SET_AP 118 | ||
60 | #define BRCMF_C_GET_RSSI 127 | ||
61 | #define BRCMF_C_GET_WSEC 133 | ||
62 | #define BRCMF_C_SET_WSEC 134 | ||
63 | #define BRCMF_C_GET_PHY_NOISE 135 | ||
64 | #define BRCMF_C_GET_BSS_INFO 136 | ||
65 | #define BRCMF_C_SET_SCAN_CHANNEL_TIME 185 | ||
66 | #define BRCMF_C_SET_SCAN_UNASSOC_TIME 187 | ||
67 | #define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON 201 | ||
68 | #define BRCMF_C_GET_VALID_CHANNELS 217 | ||
69 | #define BRCMF_C_GET_KEY_PRIMARY 235 | ||
70 | #define BRCMF_C_SET_KEY_PRIMARY 236 | ||
71 | #define BRCMF_C_SET_SCAN_PASSIVE_TIME 258 | ||
72 | #define BRCMF_C_GET_VAR 262 | ||
73 | #define BRCMF_C_SET_VAR 263 | ||
74 | |||
75 | /* phy types (returned by WLC_GET_PHYTPE) */ | ||
76 | #define WLC_PHY_TYPE_A 0 | ||
77 | #define WLC_PHY_TYPE_B 1 | ||
78 | #define WLC_PHY_TYPE_G 2 | ||
79 | #define WLC_PHY_TYPE_N 4 | ||
80 | #define WLC_PHY_TYPE_LP 5 | ||
81 | #define WLC_PHY_TYPE_SSN 6 | ||
82 | #define WLC_PHY_TYPE_HT 7 | ||
83 | #define WLC_PHY_TYPE_LCN 8 | ||
84 | #define WLC_PHY_TYPE_NULL 0xf | ||
85 | |||
86 | #define BRCMF_PKT_FILTER_FIXED_LEN offsetof(struct brcmf_pkt_filter, u) | ||
87 | #define BRCMF_PKT_FILTER_PATTERN_FIXED_LEN \ | ||
88 | offsetof(struct brcmf_pkt_filter_pattern, mask_and_pattern) | ||
89 | |||
90 | #define BRCMF_EVENTING_MASK_LEN 16 | ||
91 | |||
92 | #define TOE_TX_CSUM_OL 0x00000001 | ||
93 | #define TOE_RX_CSUM_OL 0x00000002 | ||
94 | |||
95 | /* maximum channels returned by the get valid channels iovar */ | ||
96 | #define WL_NUMCHANNELS 64 | ||
97 | |||
98 | #define BRCMF_BSS_INFO_VERSION 108 /* current ver of brcmf_bss_info struct */ | ||
99 | |||
100 | /* size of brcmf_scan_params not including variable length array */ | ||
101 | #define BRCMF_SCAN_PARAMS_FIXED_SIZE 64 | ||
102 | |||
103 | /* masks for channel and ssid count */ | ||
104 | #define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff | ||
105 | #define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16 | ||
106 | |||
107 | #define BRCMF_SCAN_ACTION_START 1 | ||
108 | #define BRCMF_SCAN_ACTION_CONTINUE 2 | ||
109 | #define WL_SCAN_ACTION_ABORT 3 | ||
110 | |||
111 | #define BRCMF_ISCAN_REQ_VERSION 1 | ||
112 | |||
113 | /* brcmf_iscan_results status values */ | ||
114 | #define BRCMF_SCAN_RESULTS_SUCCESS 0 | ||
115 | #define BRCMF_SCAN_RESULTS_PARTIAL 1 | ||
116 | #define BRCMF_SCAN_RESULTS_PENDING 2 | ||
117 | #define BRCMF_SCAN_RESULTS_ABORTED 3 | ||
118 | #define BRCMF_SCAN_RESULTS_NO_MEM 4 | ||
119 | |||
120 | #define WL_SOFT_KEY (1 << 0) /* Indicates this key is using soft encrypt */ | ||
121 | #define BRCMF_PRIMARY_KEY (1 << 1) /* primary (ie tx) key */ | ||
122 | #define WL_KF_RES_4 (1 << 4) /* Reserved for backward compat */ | ||
123 | #define WL_KF_RES_5 (1 << 5) /* Reserved for backward compat */ | ||
124 | #define WL_IBSS_PEER_GROUP_KEY (1 << 6) /* Indicates a group key for a IBSS PEER */ | ||
125 | |||
126 | /* For supporting multiple interfaces */ | ||
127 | #define BRCMF_MAX_IFS 16 | ||
128 | #define BRCMF_DEL_IF -0xe | ||
129 | #define BRCMF_BAD_IF -0xf | ||
130 | |||
131 | #define DOT11_BSSTYPE_ANY 2 | ||
132 | #define DOT11_MAX_DEFAULT_KEYS 4 | ||
133 | |||
134 | #define BRCMF_EVENT_MSG_LINK 0x01 | ||
135 | #define BRCMF_EVENT_MSG_FLUSHTXQ 0x02 | ||
136 | #define BRCMF_EVENT_MSG_GROUP 0x04 | ||
137 | |||
138 | struct brcmf_event_msg { | ||
139 | u16 version; | ||
140 | u16 flags; | ||
141 | u32 event_type; | ||
142 | u32 status; | ||
143 | u32 reason; | ||
144 | u32 auth_type; | ||
145 | u32 datalen; | ||
146 | u8 addr[ETH_ALEN]; | ||
147 | char ifname[IFNAMSIZ]; | ||
148 | } __packed; | ||
149 | |||
150 | struct brcm_ethhdr { | ||
151 | u16 subtype; | ||
152 | u16 length; | ||
153 | u8 version; | ||
154 | u8 oui[3]; | ||
155 | u16 usr_subtype; | ||
156 | } __packed; | ||
157 | |||
158 | struct brcmf_event { | ||
159 | struct ethhdr eth; | ||
160 | struct brcm_ethhdr hdr; | ||
161 | struct brcmf_event_msg msg; | ||
162 | } __packed; | ||
163 | |||
164 | struct dngl_stats { | ||
165 | unsigned long rx_packets; /* total packets received */ | ||
166 | unsigned long tx_packets; /* total packets transmitted */ | ||
167 | unsigned long rx_bytes; /* total bytes received */ | ||
168 | unsigned long tx_bytes; /* total bytes transmitted */ | ||
169 | unsigned long rx_errors; /* bad packets received */ | ||
170 | unsigned long tx_errors; /* packet transmit problems */ | ||
171 | unsigned long rx_dropped; /* packets dropped by dongle */ | ||
172 | unsigned long tx_dropped; /* packets dropped by dongle */ | ||
173 | unsigned long multicast; /* multicast packets received */ | ||
174 | }; | ||
175 | |||
176 | #define BRCMF_E_SET_SSID 0 | ||
177 | #define BRCMF_E_JOIN 1 | ||
178 | #define BRCMF_E_START 2 | ||
179 | #define BRCMF_E_AUTH 3 | ||
180 | #define BRCMF_E_AUTH_IND 4 | ||
181 | #define BRCMF_E_DEAUTH 5 | ||
182 | #define BRCMF_E_DEAUTH_IND 6 | ||
183 | #define BRCMF_E_ASSOC 7 | ||
184 | #define BRCMF_E_ASSOC_IND 8 | ||
185 | #define BRCMF_E_REASSOC 9 | ||
186 | #define BRCMF_E_REASSOC_IND 10 | ||
187 | #define BRCMF_E_DISASSOC 11 | ||
188 | #define BRCMF_E_DISASSOC_IND 12 | ||
189 | #define BRCMF_E_QUIET_START 13 | ||
190 | #define BRCMF_E_QUIET_END 14 | ||
191 | #define BRCMF_E_BEACON_RX 15 | ||
192 | #define BRCMF_E_LINK 16 | ||
193 | #define BRCMF_E_MIC_ERROR 17 | ||
194 | #define BRCMF_E_NDIS_LINK 18 | ||
195 | #define BRCMF_E_ROAM 19 | ||
196 | #define BRCMF_E_TXFAIL 20 | ||
197 | #define BRCMF_E_PMKID_CACHE 21 | ||
198 | #define BRCMF_E_RETROGRADE_TSF 22 | ||
199 | #define BRCMF_E_PRUNE 23 | ||
200 | #define BRCMF_E_AUTOAUTH 24 | ||
201 | #define BRCMF_E_EAPOL_MSG 25 | ||
202 | #define BRCMF_E_SCAN_COMPLETE 26 | ||
203 | #define BRCMF_E_ADDTS_IND 27 | ||
204 | #define BRCMF_E_DELTS_IND 28 | ||
205 | #define BRCMF_E_BCNSENT_IND 29 | ||
206 | #define BRCMF_E_BCNRX_MSG 30 | ||
207 | #define BRCMF_E_BCNLOST_MSG 31 | ||
208 | #define BRCMF_E_ROAM_PREP 32 | ||
209 | #define BRCMF_E_PFN_NET_FOUND 33 | ||
210 | #define BRCMF_E_PFN_NET_LOST 34 | ||
211 | #define BRCMF_E_RESET_COMPLETE 35 | ||
212 | #define BRCMF_E_JOIN_START 36 | ||
213 | #define BRCMF_E_ROAM_START 37 | ||
214 | #define BRCMF_E_ASSOC_START 38 | ||
215 | #define BRCMF_E_IBSS_ASSOC 39 | ||
216 | #define BRCMF_E_RADIO 40 | ||
217 | #define BRCMF_E_PSM_WATCHDOG 41 | ||
218 | #define BRCMF_E_PROBREQ_MSG 44 | ||
219 | #define BRCMF_E_SCAN_CONFIRM_IND 45 | ||
220 | #define BRCMF_E_PSK_SUP 46 | ||
221 | #define BRCMF_E_COUNTRY_CODE_CHANGED 47 | ||
222 | #define BRCMF_E_EXCEEDED_MEDIUM_TIME 48 | ||
223 | #define BRCMF_E_ICV_ERROR 49 | ||
224 | #define BRCMF_E_UNICAST_DECODE_ERROR 50 | ||
225 | #define BRCMF_E_MULTICAST_DECODE_ERROR 51 | ||
226 | #define BRCMF_E_TRACE 52 | ||
227 | #define BRCMF_E_IF 54 | ||
228 | #define BRCMF_E_RSSI 56 | ||
229 | #define BRCMF_E_PFN_SCAN_COMPLETE 57 | ||
230 | #define BRCMF_E_EXTLOG_MSG 58 | ||
231 | #define BRCMF_E_ACTION_FRAME 59 | ||
232 | #define BRCMF_E_ACTION_FRAME_COMPLETE 60 | ||
233 | #define BRCMF_E_PRE_ASSOC_IND 61 | ||
234 | #define BRCMF_E_PRE_REASSOC_IND 62 | ||
235 | #define BRCMF_E_CHANNEL_ADOPTED 63 | ||
236 | #define BRCMF_E_AP_STARTED 64 | ||
237 | #define BRCMF_E_DFS_AP_STOP 65 | ||
238 | #define BRCMF_E_DFS_AP_RESUME 66 | ||
239 | #define BRCMF_E_RESERVED1 67 | ||
240 | #define BRCMF_E_RESERVED2 68 | ||
241 | #define BRCMF_E_ESCAN_RESULT 69 | ||
242 | #define BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 | ||
243 | #define BRCMF_E_DCS_REQUEST 73 | ||
244 | |||
245 | #define BRCMF_E_FIFO_CREDIT_MAP 74 | ||
246 | |||
247 | #define BRCMF_E_LAST 75 | ||
248 | |||
249 | #define BRCMF_E_STATUS_SUCCESS 0 | ||
250 | #define BRCMF_E_STATUS_FAIL 1 | ||
251 | #define BRCMF_E_STATUS_TIMEOUT 2 | ||
252 | #define BRCMF_E_STATUS_NO_NETWORKS 3 | ||
253 | #define BRCMF_E_STATUS_ABORT 4 | ||
254 | #define BRCMF_E_STATUS_NO_ACK 5 | ||
255 | #define BRCMF_E_STATUS_UNSOLICITED 6 | ||
256 | #define BRCMF_E_STATUS_ATTEMPT 7 | ||
257 | #define BRCMF_E_STATUS_PARTIAL 8 | ||
258 | #define BRCMF_E_STATUS_NEWSCAN 9 | ||
259 | #define BRCMF_E_STATUS_NEWASSOC 10 | ||
260 | #define BRCMF_E_STATUS_11HQUIET 11 | ||
261 | #define BRCMF_E_STATUS_SUPPRESS 12 | ||
262 | #define BRCMF_E_STATUS_NOCHANS 13 | ||
263 | #define BRCMF_E_STATUS_CS_ABORT 15 | ||
264 | #define BRCMF_E_STATUS_ERROR 16 | ||
265 | |||
266 | #define BRCMF_E_REASON_INITIAL_ASSOC 0 | ||
267 | #define BRCMF_E_REASON_LOW_RSSI 1 | ||
268 | #define BRCMF_E_REASON_DEAUTH 2 | ||
269 | #define BRCMF_E_REASON_DISASSOC 3 | ||
270 | #define BRCMF_E_REASON_BCNS_LOST 4 | ||
271 | #define BRCMF_E_REASON_MINTXRATE 9 | ||
272 | #define BRCMF_E_REASON_TXFAIL 10 | ||
273 | |||
274 | #define BRCMF_E_REASON_FAST_ROAM_FAILED 5 | ||
275 | #define BRCMF_E_REASON_DIRECTED_ROAM 6 | ||
276 | #define BRCMF_E_REASON_TSPEC_REJECTED 7 | ||
277 | #define BRCMF_E_REASON_BETTER_AP 8 | ||
278 | |||
279 | #define BRCMF_E_PRUNE_ENCR_MISMATCH 1 | ||
280 | #define BRCMF_E_PRUNE_BCAST_BSSID 2 | ||
281 | #define BRCMF_E_PRUNE_MAC_DENY 3 | ||
282 | #define BRCMF_E_PRUNE_MAC_NA 4 | ||
283 | #define BRCMF_E_PRUNE_REG_PASSV 5 | ||
284 | #define BRCMF_E_PRUNE_SPCT_MGMT 6 | ||
285 | #define BRCMF_E_PRUNE_RADAR 7 | ||
286 | #define BRCMF_E_RSN_MISMATCH 8 | ||
287 | #define BRCMF_E_PRUNE_NO_COMMON_RATES 9 | ||
288 | #define BRCMF_E_PRUNE_BASIC_RATES 10 | ||
289 | #define BRCMF_E_PRUNE_CIPHER_NA 12 | ||
290 | #define BRCMF_E_PRUNE_KNOWN_STA 13 | ||
291 | #define BRCMF_E_PRUNE_WDS_PEER 15 | ||
292 | #define BRCMF_E_PRUNE_QBSS_LOAD 16 | ||
293 | #define BRCMF_E_PRUNE_HOME_AP 17 | ||
294 | |||
295 | #define BRCMF_E_SUP_OTHER 0 | ||
296 | #define BRCMF_E_SUP_DECRYPT_KEY_DATA 1 | ||
297 | #define BRCMF_E_SUP_BAD_UCAST_WEP128 2 | ||
298 | #define BRCMF_E_SUP_BAD_UCAST_WEP40 3 | ||
299 | #define BRCMF_E_SUP_UNSUP_KEY_LEN 4 | ||
300 | #define BRCMF_E_SUP_PW_KEY_CIPHER 5 | ||
301 | #define BRCMF_E_SUP_MSG3_TOO_MANY_IE 6 | ||
302 | #define BRCMF_E_SUP_MSG3_IE_MISMATCH 7 | ||
303 | #define BRCMF_E_SUP_NO_INSTALL_FLAG 8 | ||
304 | #define BRCMF_E_SUP_MSG3_NO_GTK 9 | ||
305 | #define BRCMF_E_SUP_GRP_KEY_CIPHER 10 | ||
306 | #define BRCMF_E_SUP_GRP_MSG1_NO_GTK 11 | ||
307 | #define BRCMF_E_SUP_GTK_DECRYPT_FAIL 12 | ||
308 | #define BRCMF_E_SUP_SEND_FAIL 13 | ||
309 | #define BRCMF_E_SUP_DEAUTH 14 | ||
310 | |||
311 | #define BRCMF_E_IF_ADD 1 | ||
312 | #define BRCMF_E_IF_DEL 2 | ||
313 | #define BRCMF_E_IF_CHANGE 3 | ||
314 | |||
315 | #define BRCMF_E_IF_ROLE_STA 0 | ||
316 | #define BRCMF_E_IF_ROLE_AP 1 | ||
317 | #define BRCMF_E_IF_ROLE_WDS 2 | ||
318 | |||
319 | #define BRCMF_E_LINK_BCN_LOSS 1 | ||
320 | #define BRCMF_E_LINK_DISASSOC 2 | ||
321 | #define BRCMF_E_LINK_ASSOC_REC 3 | ||
322 | #define BRCMF_E_LINK_BSSCFG_DIS 4 | ||
323 | |||
324 | /* The level of bus communication with the dongle */ | ||
325 | enum brcmf_bus_state { | ||
326 | BRCMF_BUS_DOWN, /* Not ready for frame transfers */ | ||
327 | BRCMF_BUS_LOAD, /* Download access only (CPU reset) */ | ||
328 | BRCMF_BUS_DATA /* Ready for frame transfers */ | ||
329 | }; | ||
330 | |||
331 | /* Pattern matching filter. Specifies an offset within received packets to | ||
332 | * start matching, the pattern to match, the size of the pattern, and a bitmask | ||
333 | * that indicates which bits within the pattern should be matched. | ||
334 | */ | ||
335 | struct brcmf_pkt_filter_pattern { | ||
336 | u32 offset; /* Offset within received packet to start pattern matching. | ||
337 | * Offset '0' is the first byte of the ethernet header. | ||
338 | */ | ||
339 | u32 size_bytes; /* Size of the pattern. Bitmask must be the same size. */ | ||
340 | u8 mask_and_pattern[1]; /* Variable length mask and pattern data. mask starts | ||
341 | * at offset 0. Pattern immediately follows mask. | ||
342 | */ | ||
343 | }; | ||
344 | |||
345 | /* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */ | ||
346 | struct brcmf_pkt_filter { | ||
347 | u32 id; /* Unique filter id, specified by app. */ | ||
348 | u32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */ | ||
349 | u32 negate_match; /* Negate the result of filter matches */ | ||
350 | union { /* Filter definitions */ | ||
351 | struct brcmf_pkt_filter_pattern pattern; /* Filter pattern */ | ||
352 | } u; | ||
353 | }; | ||
354 | |||
355 | /* IOVAR "pkt_filter_enable" parameter. */ | ||
356 | struct brcmf_pkt_filter_enable { | ||
357 | u32 id; /* Unique filter id */ | ||
358 | u32 enable; /* Enable/disable bool */ | ||
359 | }; | ||
360 | |||
361 | /* BSS info structure | ||
362 | * Applications MUST CHECK ie_offset field and length field to access IEs and | ||
363 | * next bss_info structure in a vector (in struct brcmf_scan_results) | ||
364 | */ | ||
365 | struct brcmf_bss_info { | ||
366 | u32 version; /* version field */ | ||
367 | u32 length; /* byte length of data in this record, | ||
368 | * starting at version and including IEs | ||
369 | */ | ||
370 | u8 BSSID[ETH_ALEN]; | ||
371 | u16 beacon_period; /* units are Kusec */ | ||
372 | u16 capability; /* Capability information */ | ||
373 | u8 SSID_len; | ||
374 | u8 SSID[32]; | ||
375 | struct { | ||
376 | uint count; /* # rates in this set */ | ||
377 | u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ | ||
378 | } rateset; /* supported rates */ | ||
379 | chanspec_t chanspec; /* chanspec for bss */ | ||
380 | u16 atim_window; /* units are Kusec */ | ||
381 | u8 dtim_period; /* DTIM period */ | ||
382 | s16 RSSI; /* receive signal strength (in dBm) */ | ||
383 | s8 phy_noise; /* noise (in dBm) */ | ||
384 | |||
385 | u8 n_cap; /* BSS is 802.11N Capable */ | ||
386 | u32 nbss_cap; /* 802.11N BSS Capabilities (based on HT_CAP_*) */ | ||
387 | u8 ctl_ch; /* 802.11N BSS control channel number */ | ||
388 | u32 reserved32[1]; /* Reserved for expansion of BSS properties */ | ||
389 | u8 flags; /* flags */ | ||
390 | u8 reserved[3]; /* Reserved for expansion of BSS properties */ | ||
391 | u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ | ||
392 | |||
393 | u16 ie_offset; /* offset at which IEs start, from beginning */ | ||
394 | u32 ie_length; /* byte length of Information Elements */ | ||
395 | s16 SNR; /* average SNR of during frame reception */ | ||
396 | /* Add new fields here */ | ||
397 | /* variable length Information Elements */ | ||
398 | }; | ||
399 | |||
400 | struct brcmf_ssid { | ||
401 | u32 SSID_len; | ||
402 | unsigned char SSID[32]; | ||
403 | }; | ||
404 | |||
405 | struct brcmf_scan_params { | ||
406 | struct brcmf_ssid ssid; /* default: {0, ""} */ | ||
407 | u8 bssid[ETH_ALEN]; /* default: bcast */ | ||
408 | s8 bss_type; /* default: any, | ||
409 | * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT | ||
410 | */ | ||
411 | u8 scan_type; /* flags, 0 use default */ | ||
412 | s32 nprobes; /* -1 use default, number of probes per channel */ | ||
413 | s32 active_time; /* -1 use default, dwell time per channel for | ||
414 | * active scanning | ||
415 | */ | ||
416 | s32 passive_time; /* -1 use default, dwell time per channel | ||
417 | * for passive scanning | ||
418 | */ | ||
419 | s32 home_time; /* -1 use default, dwell time for the home channel | ||
420 | * between channel scans | ||
421 | */ | ||
422 | s32 channel_num; /* count of channels and ssids that follow | ||
423 | * | ||
424 | * low half is count of channels in | ||
425 | * channel_list, 0 means default (use all | ||
426 | * available channels) | ||
427 | * | ||
428 | * high half is entries in struct brcmf_ssid | ||
429 | * array that follows channel_list, aligned for | ||
430 | * s32 (4 bytes) meaning an odd channel count | ||
431 | * implies a 2-byte pad between end of | ||
432 | * channel_list and first ssid | ||
433 | * | ||
434 | * if ssid count is zero, single ssid in the | ||
435 | * fixed parameter portion is assumed, otherwise | ||
436 | * ssid in the fixed portion is ignored | ||
437 | */ | ||
438 | u16 channel_list[1]; /* list of chanspecs */ | ||
439 | }; | ||
440 | |||
441 | /* incremental scan struct */ | ||
442 | struct brcmf_iscan_params { | ||
443 | u32 version; | ||
444 | u16 action; | ||
445 | u16 scan_duration; | ||
446 | struct brcmf_scan_params params; | ||
447 | }; | ||
448 | |||
449 | /* 3 fields + size of brcmf_scan_params, not including variable length array */ | ||
450 | #define BRCMF_ISCAN_PARAMS_FIXED_SIZE \ | ||
451 | (offsetof(struct brcmf_iscan_params, params) + \ | ||
452 | sizeof(struct brcmf_ssid)) | ||
453 | |||
454 | struct brcmf_scan_results { | ||
455 | u32 buflen; | ||
456 | u32 version; | ||
457 | u32 count; | ||
458 | struct brcmf_bss_info bss_info[1]; | ||
459 | }; | ||
460 | |||
461 | /* used for association with a specific BSSID and chanspec list */ | ||
462 | struct brcmf_assoc_params { | ||
463 | u8 bssid[ETH_ALEN]; /* 00:00:00:00:00:00: broadcast scan */ | ||
464 | s32 chanspec_num; /* 0: all available channels, | ||
465 | * otherwise count of chanspecs in chanspec_list | ||
466 | */ | ||
467 | chanspec_t chanspec_list[1]; /* list of chanspecs */ | ||
468 | }; | ||
469 | #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ | ||
470 | (sizeof(struct brcmf_assoc_params) - sizeof(chanspec_t)) | ||
471 | |||
472 | /* used for join with or without a specific bssid and channel list */ | ||
473 | struct brcmf_join_params { | ||
474 | struct brcmf_ssid ssid; | ||
475 | struct brcmf_assoc_params params; | ||
476 | }; | ||
477 | |||
478 | /* size of brcmf_scan_results not including variable length array */ | ||
479 | #define BRCMF_SCAN_RESULTS_FIXED_SIZE \ | ||
480 | (sizeof(struct brcmf_scan_results) - sizeof(struct brcmf_bss_info)) | ||
481 | |||
482 | /* incremental scan results struct */ | ||
483 | struct brcmf_iscan_results { | ||
484 | u32 status; | ||
485 | struct brcmf_scan_results results; | ||
486 | }; | ||
487 | |||
488 | /* size of brcmf_iscan_results not including variable length array */ | ||
489 | #define BRCMF_ISCAN_RESULTS_FIXED_SIZE \ | ||
490 | (BRCMF_SCAN_RESULTS_FIXED_SIZE + \ | ||
491 | offsetof(struct brcmf_iscan_results, results)) | ||
492 | |||
493 | struct brcmf_wsec_key { | ||
494 | u32 index; /* key index */ | ||
495 | u32 len; /* key length */ | ||
496 | u8 data[WLAN_MAX_KEY_LEN]; /* key data */ | ||
497 | u32 pad_1[18]; | ||
498 | u32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ | ||
499 | u32 flags; /* misc flags */ | ||
500 | u32 pad_2[2]; | ||
501 | int pad_3; | ||
502 | int iv_initialized; /* has IV been initialized already? */ | ||
503 | int pad_4; | ||
504 | /* Rx IV */ | ||
505 | struct { | ||
506 | u32 hi; /* upper 32 bits of IV */ | ||
507 | u16 lo; /* lower 16 bits of IV */ | ||
508 | } rxiv; | ||
509 | u32 pad_5[2]; | ||
510 | u8 ea[ETH_ALEN]; /* per station */ | ||
511 | }; | ||
512 | |||
513 | /* Used to get specific STA parameters */ | ||
514 | struct brcmf_scb_val { | ||
515 | u32 val; | ||
516 | u8 ea[ETH_ALEN]; | ||
517 | }; | ||
518 | |||
519 | /* channel encoding */ | ||
520 | struct brcmf_channel_info { | ||
521 | int hw_channel; | ||
522 | int target_channel; | ||
523 | int scan_channel; | ||
524 | }; | ||
525 | |||
526 | /* Linux network driver ioctl encoding */ | ||
527 | struct brcmf_ioctl { | ||
528 | uint cmd; /* common ioctl definition */ | ||
529 | void *buf; /* pointer to user buffer */ | ||
530 | uint len; /* length of user buffer */ | ||
531 | u8 set; /* get or set request (optional) */ | ||
532 | uint used; /* bytes read or written (optional) */ | ||
533 | uint needed; /* bytes needed (optional) */ | ||
534 | }; | ||
535 | |||
536 | /* Forward decls for struct brcmf_pub (see below) */ | ||
537 | struct brcmf_bus; /* device bus info */ | ||
538 | struct brcmf_proto; /* device communication protocol info */ | ||
539 | struct brcmf_info; /* device driver info */ | ||
540 | |||
541 | /* Common structure for module and instance linkage */ | ||
542 | struct brcmf_pub { | ||
543 | /* Linkage ponters */ | ||
544 | struct brcmf_bus *bus; | ||
545 | struct brcmf_proto *prot; | ||
546 | struct brcmf_info *info; | ||
547 | |||
548 | /* Internal brcmf items */ | ||
549 | bool up; /* Driver up/down (to OS) */ | ||
550 | bool txoff; /* Transmit flow-controlled */ | ||
551 | bool dongle_reset; /* true = DEVRESET put dongle into reset */ | ||
552 | enum brcmf_bus_state busstate; | ||
553 | uint hdrlen; /* Total BRCMF header length (proto + bus) */ | ||
554 | uint maxctl; /* Max size rxctl request from proto to bus */ | ||
555 | uint rxsz; /* Rx buffer size bus module should use */ | ||
556 | u8 wme_dp; /* wme discard priority */ | ||
557 | |||
558 | /* Dongle media info */ | ||
559 | bool iswl; /* Dongle-resident driver is wl */ | ||
560 | unsigned long drv_version; /* Version of dongle-resident driver */ | ||
561 | u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */ | ||
562 | struct dngl_stats dstats; /* Stats for dongle-based data */ | ||
563 | |||
564 | /* Additional stats for the bus level */ | ||
565 | unsigned long tx_packets; /* Data packets sent to dongle */ | ||
566 | unsigned long tx_multicast; /* Multicast data packets sent to dongle */ | ||
567 | unsigned long tx_errors; /* Errors in sending data to dongle */ | ||
568 | unsigned long tx_ctlpkts; /* Control packets sent to dongle */ | ||
569 | unsigned long tx_ctlerrs; /* Errors sending control frames to dongle */ | ||
570 | unsigned long rx_packets; /* Packets sent up the network interface */ | ||
571 | unsigned long rx_multicast; /* Multicast packets sent up the network | ||
572 | interface */ | ||
573 | unsigned long rx_errors; /* Errors processing rx data packets */ | ||
574 | unsigned long rx_ctlpkts; /* Control frames processed from dongle */ | ||
575 | unsigned long rx_ctlerrs; /* Errors in processing rx control frames */ | ||
576 | unsigned long rx_dropped; /* Packets dropped locally (no memory) */ | ||
577 | unsigned long rx_flushed; /* Packets flushed due to | ||
578 | unscheduled sendup thread */ | ||
579 | unsigned long wd_dpc_sched; /* Number of times dpc scheduled by | ||
580 | watchdog timer */ | ||
581 | |||
582 | unsigned long rx_readahead_cnt; /* Number of packets where header read-ahead | ||
583 | was used. */ | ||
584 | unsigned long tx_realloc; /* Number of tx packets we had to realloc for | ||
585 | headroom */ | ||
586 | unsigned long fc_packets; /* Number of flow control pkts recvd */ | ||
587 | |||
588 | /* Last error return */ | ||
589 | int bcmerror; | ||
590 | uint tickcnt; | ||
591 | |||
592 | /* Last error from dongle */ | ||
593 | int dongle_error; | ||
594 | |||
595 | /* Suspend disable flag flag */ | ||
596 | int suspend_disable_flag; /* "1" to disable all extra powersaving | ||
597 | during suspend */ | ||
598 | int in_suspend; /* flag set to 1 when early suspend called */ | ||
599 | int dtim_skip; /* dtim skip , default 0 means wake each dtim */ | ||
600 | |||
601 | /* Pkt filter defination */ | ||
602 | char *pktfilter[100]; | ||
603 | int pktfilter_count; | ||
604 | |||
605 | u8 country_code[BRCM_CNTRY_BUF_SZ]; | ||
606 | char eventmask[BRCMF_EVENTING_MASK_LEN]; | ||
607 | |||
608 | }; | ||
609 | |||
610 | struct brcmf_if_event { | ||
611 | u8 ifidx; | ||
612 | u8 action; | ||
613 | u8 flags; | ||
614 | u8 bssidx; | ||
615 | }; | ||
616 | |||
617 | struct brcmf_timeout { | ||
618 | u32 limit; /* Expiration time (usec) */ | ||
619 | u32 increment; /* Current expiration increment (usec) */ | ||
620 | u32 elapsed; /* Current elapsed time (usec) */ | ||
621 | u32 tick; /* O/S tick time (usec) */ | ||
622 | }; | ||
623 | |||
624 | struct bcmevent_name { | ||
625 | uint event; | ||
626 | const char *name; | ||
627 | }; | ||
628 | |||
629 | #if defined(CONFIG_PM_SLEEP) | ||
630 | extern atomic_t brcmf_mmc_suspend; | ||
631 | #define BRCMF_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); | ||
632 | #define _BRCMF_PM_RESUME_WAIT(a, b) do { \ | ||
633 | int retry = 0; \ | ||
634 | while (atomic_read(&brcmf_mmc_suspend) && retry++ != b) { \ | ||
635 | wait_event_timeout(a, false, HZ/100); \ | ||
636 | } \ | ||
637 | } while (0) | ||
638 | #define BRCMF_PM_RESUME_WAIT(a) _BRCMF_PM_RESUME_WAIT(a, 30) | ||
639 | #define BRCMF_PM_RESUME_RETURN_ERROR(a) \ | ||
640 | do { if (atomic_read(&brcmf_mmc_suspend)) return a; } while (0) | ||
641 | |||
642 | #define BRCMF_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); | ||
643 | #define BRCMF_SPINWAIT_SLEEP(a, exp, us) do { \ | ||
644 | uint countdown = (us) + 9999; \ | ||
645 | while ((exp) && (countdown >= 10000)) { \ | ||
646 | wait_event_timeout(a, false, HZ/100); \ | ||
647 | countdown -= 10000; \ | ||
648 | } \ | ||
649 | } while (0) | ||
650 | |||
651 | #else | ||
652 | |||
653 | #define BRCMF_PM_RESUME_WAIT_INIT(a) | ||
654 | #define BRCMF_PM_RESUME_WAIT(a) | ||
655 | #define BRCMF_PM_RESUME_RETURN_ERROR(a) | ||
656 | |||
657 | #define BRCMF_SPINWAIT_SLEEP_INIT(a) | ||
658 | #define BRCMF_SPINWAIT_SLEEP(a, exp, us) do { \ | ||
659 | uint countdown = (us) + 9; \ | ||
660 | while ((exp) && (countdown >= 10)) { \ | ||
661 | udelay(10); \ | ||
662 | countdown -= 10; \ | ||
663 | } \ | ||
664 | } while (0) | ||
665 | |||
666 | #endif /* defined(CONFIG_PM_SLEEP) */ | ||
667 | |||
668 | /* | ||
669 | * Insmod parameters for debug/test | ||
670 | */ | ||
671 | |||
672 | /* Use interrupts */ | ||
673 | extern uint brcmf_intr; | ||
674 | |||
675 | /* Use polling */ | ||
676 | extern uint brcmf_poll; | ||
677 | |||
678 | /* ARP offload agent mode */ | ||
679 | extern uint brcmf_arp_mode; | ||
680 | |||
681 | /* ARP offload enable */ | ||
682 | extern uint brcmf_arp_enable; | ||
683 | |||
684 | /* Pkt filte enable control */ | ||
685 | extern uint brcmf_pkt_filter_enable; | ||
686 | |||
687 | /* Pkt filter init setup */ | ||
688 | extern uint brcmf_pkt_filter_init; | ||
689 | |||
690 | /* Pkt filter mode control */ | ||
691 | extern uint brcmf_master_mode; | ||
692 | |||
693 | /* Roaming mode control */ | ||
694 | extern uint brcmf_roam; | ||
695 | |||
696 | /* Roaming mode control */ | ||
697 | extern uint brcmf_radio_up; | ||
698 | |||
699 | /* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */ | ||
700 | extern int brcmf_idletime; | ||
701 | #define BRCMF_IDLETIME_TICKS 1 | ||
702 | |||
703 | /* SDIO Drive Strength */ | ||
704 | extern uint brcmf_sdiod_drive_strength; | ||
705 | |||
706 | /* Override to force tx queueing all the time */ | ||
707 | extern uint brcmf_force_tx_queueing; | ||
708 | |||
709 | #ifdef SDTEST | ||
710 | /* Echo packet generator (SDIO), pkts/s */ | ||
711 | extern uint brcmf_pktgen; | ||
712 | |||
713 | /* Echo packet len (0 => sawtooth, max 1800) */ | ||
714 | extern uint brcmf_pktgen_len; | ||
715 | #define BRCMF_MAX_PKTGEN_LEN 1800 | ||
716 | #endif | ||
717 | |||
718 | extern const struct bcmevent_name bcmevent_names[]; | ||
719 | extern const int bcmevent_names_size; | ||
720 | |||
721 | |||
722 | static inline void MUTEX_LOCK_INIT(struct brcmf_pub *drvr) | ||
723 | { | ||
724 | } | ||
725 | |||
726 | static inline void MUTEX_LOCK(struct brcmf_pub *drvr) | ||
727 | { | ||
728 | } | ||
729 | |||
730 | static inline void MUTEX_UNLOCK(struct brcmf_pub *drvr) | ||
731 | { | ||
732 | } | ||
733 | |||
734 | static inline void MUTEX_LOCK_SOFTAP_SET_INIT(struct brcmf_pub *drvr) | ||
735 | { | ||
736 | } | ||
737 | |||
738 | static inline void MUTEX_LOCK_SOFTAP_SET(struct brcmf_pub *drvr) | ||
739 | { | ||
740 | } | ||
741 | |||
742 | static inline void MUTEX_UNLOCK_SOFTAP_SET(struct brcmf_pub *drvr) | ||
743 | { | ||
744 | } | ||
745 | |||
746 | static inline void MUTEX_LOCK_WL_SCAN_SET_INIT(void) | ||
747 | { | ||
748 | } | ||
749 | |||
750 | static inline void MUTEX_LOCK_WL_SCAN_SET(void) | ||
751 | { | ||
752 | } | ||
753 | |||
754 | static inline void MUTEX_UNLOCK_WL_SCAN_SET(void) | ||
755 | { | ||
756 | } | ||
757 | |||
758 | /* Indication from bus module regarding presence/insertion of dongle. | ||
759 | * Return struct brcmf_pub pointer, used as handle to OS module in later calls. | ||
760 | * Returned structure should have bus and prot pointers filled in. | ||
761 | * bus_hdrlen specifies required headroom for bus module header. | ||
762 | */ | ||
763 | extern struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, | ||
764 | uint bus_hdrlen); | ||
765 | extern int brcmf_net_attach(struct brcmf_pub *drvr, int idx); | ||
766 | extern int brcmf_netdev_wait_pend8021x(struct net_device *dev); | ||
767 | |||
768 | /* Indication from bus module regarding removal/absence of dongle */ | ||
769 | extern void brcmf_detach(struct brcmf_pub *drvr); | ||
770 | |||
771 | /* Indication from bus module to change flow-control state */ | ||
772 | extern void brcmf_txflowcontrol(struct brcmf_pub *drvr, int ifidx, bool on); | ||
773 | |||
774 | extern bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q, | ||
775 | struct sk_buff *pkt, int prec); | ||
776 | |||
777 | /* Receive frame for delivery to OS. Callee disposes of rxp. */ | ||
778 | extern void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, | ||
779 | struct sk_buff *rxp, int numpkt); | ||
780 | |||
781 | /* Return pointer to interface name */ | ||
782 | extern char *brcmf_ifname(struct brcmf_pub *drvr, int idx); | ||
783 | |||
784 | /* Notify tx completion */ | ||
785 | extern void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, | ||
786 | bool success); | ||
787 | |||
788 | /* Query ioctl */ | ||
789 | extern int brcmf_proto_cdc_query_ioctl(struct brcmf_pub *drvr, int ifidx, | ||
790 | uint cmd, void *buf, uint len); | ||
791 | |||
792 | /* OS independent layer functions */ | ||
793 | extern int brcmf_os_proto_block(struct brcmf_pub *drvr); | ||
794 | extern int brcmf_os_proto_unblock(struct brcmf_pub *drvr); | ||
795 | extern int brcmf_os_ioctl_resp_wait(struct brcmf_pub *drvr, uint *condition, | ||
796 | bool *pending); | ||
797 | extern int brcmf_os_ioctl_resp_wake(struct brcmf_pub *drvr); | ||
798 | extern unsigned int brcmf_os_get_ioctl_resp_timeout(void); | ||
799 | extern void brcmf_os_set_ioctl_resp_timeout(unsigned int timeout_msec); | ||
800 | #ifdef BCMDBG | ||
801 | extern int brcmf_write_to_file(struct brcmf_pub *drvr, u8 *buf, int size); | ||
802 | #endif /* BCMDBG */ | ||
803 | |||
804 | extern void brcmf_timeout_start(struct brcmf_timeout *tmo, uint usec); | ||
805 | extern int brcmf_timeout_expired(struct brcmf_timeout *tmo); | ||
806 | |||
807 | extern int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name); | ||
808 | extern int brcmf_c_host_event(struct brcmf_info *drvr_priv, int *idx, | ||
809 | void *pktdata, struct brcmf_event_msg *, | ||
810 | void **data_ptr); | ||
811 | |||
812 | extern void brcmf_c_init(void); | ||
813 | |||
814 | extern int brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, void *handle, | ||
815 | char *name, u8 *mac_addr, u32 flags, u8 bssidx); | ||
816 | extern void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx); | ||
817 | |||
818 | /* Send packet to dongle via data channel */ | ||
819 | extern int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx,\ | ||
820 | struct sk_buff *pkt); | ||
821 | |||
822 | extern int brcmf_bus_devreset(struct brcmf_pub *drvr, u8 flag); | ||
823 | extern int brcmf_bus_start(struct brcmf_pub *drvr); | ||
824 | |||
825 | extern void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg); | ||
826 | extern void brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, | ||
827 | int enable, int master_mode); | ||
828 | |||
829 | /* Linux network driver ioctl encoding */ | ||
830 | struct brcmf_c_ioctl { | ||
831 | uint cmd; /* common ioctl definition */ | ||
832 | void *buf; /* pointer to user buffer */ | ||
833 | uint len; /* length of user buffer */ | ||
834 | bool set; /* get or set request (optional) */ | ||
835 | uint used; /* bytes read or written (optional) */ | ||
836 | uint needed; /* bytes needed (optional) */ | ||
837 | uint driver; /* to identify target driver */ | ||
838 | }; | ||
839 | |||
840 | /* per-driver magic numbers */ | ||
841 | #define BRCMF_IOCTL_MAGIC 0x00444944 | ||
842 | |||
843 | /* bump this number if you change the ioctl interface */ | ||
844 | #define BRCMF_IOCTL_VERSION 1 | ||
845 | #define BRCMF_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ | ||
846 | |||
847 | /* common ioctl definitions */ | ||
848 | #define BRCMF_GET_MAGIC 0 | ||
849 | #define BRCMF_GET_VERSION 1 | ||
850 | #define BRCMF_GET_VAR 2 | ||
851 | #define BRCMF_SET_VAR 3 | ||
852 | |||
853 | /* message levels */ | ||
854 | #define BRCMF_ERROR_VAL 0x0001 | ||
855 | #define BRCMF_TRACE_VAL 0x0002 | ||
856 | #define BRCMF_INFO_VAL 0x0004 | ||
857 | #define BRCMF_DATA_VAL 0x0008 | ||
858 | #define BRCMF_CTL_VAL 0x0010 | ||
859 | #define BRCMF_TIMER_VAL 0x0020 | ||
860 | #define BRCMF_HDRS_VAL 0x0040 | ||
861 | #define BRCMF_BYTES_VAL 0x0080 | ||
862 | #define BRCMF_INTR_VAL 0x0100 | ||
863 | #define BRCMF_GLOM_VAL 0x0400 | ||
864 | #define BRCMF_EVENT_VAL 0x0800 | ||
865 | #define BRCMF_BTA_VAL 0x1000 | ||
866 | #define BRCMF_ISCAN_VAL 0x2000 | ||
867 | |||
868 | #ifdef SDTEST | ||
869 | /* For pktgen iovar */ | ||
870 | struct brcmf_pktgen { | ||
871 | uint version; /* To allow structure change tracking */ | ||
872 | uint freq; /* Max ticks between tx/rx attempts */ | ||
873 | uint count; /* Test packets to send/rcv each attempt */ | ||
874 | uint print; /* Print counts every <print> attempts */ | ||
875 | uint total; /* Total packets (or bursts) */ | ||
876 | uint minlen; /* Minimum length of packets to send */ | ||
877 | uint maxlen; /* Maximum length of packets to send */ | ||
878 | uint numsent; /* Count of test packets sent */ | ||
879 | uint numrcvd; /* Count of test packets received */ | ||
880 | uint numfail; /* Count of test send failures */ | ||
881 | uint mode; /* Test mode (type of test packets) */ | ||
882 | uint stop; /* Stop after this many tx failures */ | ||
883 | }; | ||
884 | |||
885 | /* Version in case structure changes */ | ||
886 | #define BRCMF_PKTGEN_VERSION 2 | ||
887 | |||
888 | /* Type of test packets to use */ | ||
889 | #define BRCMF_PKTGEN_ECHO 1 /* Send echo requests */ | ||
890 | #define BRCMF_PKTGEN_SEND 2 /* Send discard packets */ | ||
891 | #define BRCMF_PKTGEN_RXBURST 3 /* Request dongle send N packets */ | ||
892 | #define BRCMF_PKTGEN_RECV 4 /* Continuous rx from continuous | ||
893 | tx dongle */ | ||
894 | #endif /* SDTEST */ | ||
895 | |||
896 | /* Enter idle immediately (no timeout) */ | ||
897 | #define BRCMF_IDLE_IMMEDIATE (-1) | ||
898 | |||
899 | /* Values for idleclock iovar: other values are the sd_divisor to use | ||
900 | when idle */ | ||
901 | #define BRCMF_IDLE_ACTIVE 0 /* Do not request any SD clock change | ||
902 | when idle */ | ||
903 | |||
904 | #endif /* _BRCMF_H_ */ | ||
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_bus.h b/drivers/staging/brcm80211/brcmfmac/dhd_bus.h new file mode 100644 index 00000000000..653cf0daa0e --- /dev/null +++ b/drivers/staging/brcm80211/brcmfmac/dhd_bus.h | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #ifndef _BRCMF_BUS_H_ | ||
18 | #define _BRCMF_BUS_H_ | ||
19 | |||
20 | /* Packet alignment for most efficient SDIO (can change based on platform) */ | ||
21 | #ifndef BRCMF_SDALIGN | ||
22 | #define BRCMF_SDALIGN 32 | ||
23 | #endif | ||
24 | #if !ISPOWEROF2(BRCMF_SDALIGN) | ||
25 | #error BRCMF_SDALIGN is not a power of 2! | ||
26 | #endif | ||
27 | |||
28 | /* | ||
29 | * Exported from brcmf bus module (brcmf_usb, brcmf_sdio) | ||
30 | */ | ||
31 | |||
32 | /* dongle ram module parameter */ | ||
33 | extern int brcmf_dongle_memsize; | ||
34 | |||
35 | /* Tx/Rx bounds module parameters */ | ||
36 | extern uint brcmf_txbound; | ||
37 | extern uint brcmf_rxbound; | ||
38 | |||
39 | /* Watchdog timer interval */ | ||
40 | extern uint brcmf_watchdog_ms; | ||
41 | |||
42 | /* Indicate (dis)interest in finding dongles. */ | ||
43 | extern int brcmf_bus_register(void); | ||
44 | extern void brcmf_bus_unregister(void); | ||
45 | |||
46 | /* Stop bus module: clear pending frames, disable data flow */ | ||
47 | extern void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus, bool enforce_mutex); | ||
48 | |||
49 | /* Initialize bus module: prepare for communication w/dongle */ | ||
50 | extern int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr, bool enforce_mutex); | ||
51 | |||
52 | /* Send a data frame to the dongle. Callee disposes of txp. */ | ||
53 | extern int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *txp); | ||
54 | |||
55 | /* Send/receive a control message to/from the dongle. | ||
56 | * Expects caller to enforce a single outstanding transaction. | ||
57 | */ | ||
58 | extern int | ||
59 | brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen); | ||
60 | |||
61 | extern int | ||
62 | brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen); | ||
63 | |||
64 | /* Check for and handle local prot-specific iovar commands */ | ||
65 | extern int brcmf_sdbrcm_bus_iovar_op(struct brcmf_pub *drvr, const char *name, | ||
66 | void *params, int plen, void *arg, int len, | ||
67 | bool set); | ||
68 | |||
69 | /* Add bus dump output to a buffer */ | ||
70 | extern void brcmf_sdbrcm_bus_dump(struct brcmf_pub *drvr, | ||
71 | struct brcmu_strbuf *strbuf); | ||
72 | |||
73 | /* Clear any bus counters */ | ||
74 | extern void brcmf_bus_clearcounts(struct brcmf_pub *drvr); | ||
75 | |||
76 | extern void brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick); | ||
77 | |||
78 | #endif /* _BRCMF_BUS_H_ */ | ||
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c new file mode 100644 index 00000000000..345acabe935 --- /dev/null +++ b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c | |||
@@ -0,0 +1,502 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/types.h> | ||
18 | #include <linux/netdevice.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <defs.h> | ||
21 | |||
22 | #include <brcmu_utils.h> | ||
23 | #include <brcmu_wifi.h> | ||
24 | |||
25 | #include "dhd.h" | ||
26 | #include "dhd_proto.h" | ||
27 | #include "dhd_bus.h" | ||
28 | #include "dhd_dbg.h" | ||
29 | |||
30 | struct brcmf_proto_cdc_ioctl { | ||
31 | u32 cmd; /* ioctl command value */ | ||
32 | u32 len; /* lower 16: output buflen; | ||
33 | * upper 16: input buflen (excludes header) */ | ||
34 | u32 flags; /* flag defns given below */ | ||
35 | u32 status; /* status code returned from the device */ | ||
36 | }; | ||
37 | |||
38 | /* Max valid buffer size that can be sent to the dongle */ | ||
39 | #define CDC_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN) | ||
40 | |||
41 | /* CDC flag definitions */ | ||
42 | #define CDCF_IOC_ERROR 0x01 /* 1=ioctl cmd failed */ | ||
43 | #define CDCF_IOC_SET 0x02 /* 0=get, 1=set cmd */ | ||
44 | #define CDCF_IOC_IF_MASK 0xF000 /* I/F index */ | ||
45 | #define CDCF_IOC_IF_SHIFT 12 | ||
46 | #define CDCF_IOC_ID_MASK 0xFFFF0000 /* id an ioctl pairing */ | ||
47 | #define CDCF_IOC_ID_SHIFT 16 /* ID Mask shift bits */ | ||
48 | #define CDC_IOC_ID(flags) \ | ||
49 | (((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT) | ||
50 | #define CDC_SET_IF_IDX(hdr, idx) \ | ||
51 | ((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | \ | ||
52 | ((idx) << CDCF_IOC_IF_SHIFT))) | ||
53 | |||
54 | /* | ||
55 | * BDC header - Broadcom specific extension of CDC. | ||
56 | * Used on data packets to convey priority across USB. | ||
57 | */ | ||
58 | #define BDC_HEADER_LEN 4 | ||
59 | #define BDC_PROTO_VER 1 /* Protocol version */ | ||
60 | #define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ | ||
61 | #define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ | ||
62 | #define BDC_FLAG_SUM_GOOD 0x04 /* Good RX checksums */ | ||
63 | #define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */ | ||
64 | #define BDC_PRIORITY_MASK 0x7 | ||
65 | #define BDC_FLAG2_IF_MASK 0x0f /* packet rx interface in APSTA */ | ||
66 | #define BDC_FLAG2_IF_SHIFT 0 | ||
67 | |||
68 | #define BDC_GET_IF_IDX(hdr) \ | ||
69 | ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT)) | ||
70 | #define BDC_SET_IF_IDX(hdr, idx) \ | ||
71 | ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | \ | ||
72 | ((idx) << BDC_FLAG2_IF_SHIFT))) | ||
73 | |||
74 | struct brcmf_proto_bdc_header { | ||
75 | u8 flags; | ||
76 | u8 priority; /* 802.1d Priority, 4:7 flow control info for usb */ | ||
77 | u8 flags2; | ||
78 | u8 rssi; | ||
79 | }; | ||
80 | |||
81 | |||
82 | #define RETRIES 2 /* # of retries to retrieve matching ioctl response */ | ||
83 | #define BUS_HEADER_LEN (16+BRCMF_SDALIGN) /* Must be atleast SDPCM_RESERVE | ||
84 | * (amount of header tha might be added) | ||
85 | * plus any space that might be needed | ||
86 | * for alignment padding. | ||
87 | */ | ||
88 | #define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for | ||
89 | * round off at the end of buffer | ||
90 | */ | ||
91 | |||
92 | struct brcmf_proto { | ||
93 | u16 reqid; | ||
94 | u8 pending; | ||
95 | u32 lastcmd; | ||
96 | u8 bus_header[BUS_HEADER_LEN]; | ||
97 | struct brcmf_proto_cdc_ioctl msg; | ||
98 | unsigned char buf[BRCMF_C_IOCTL_MAXLEN + ROUND_UP_MARGIN]; | ||
99 | }; | ||
100 | |||
101 | static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr) | ||
102 | { | ||
103 | struct brcmf_proto *prot = drvr->prot; | ||
104 | int len = le32_to_cpu(prot->msg.len) + | ||
105 | sizeof(struct brcmf_proto_cdc_ioctl); | ||
106 | |||
107 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
108 | |||
109 | /* NOTE : cdc->msg.len holds the desired length of the buffer to be | ||
110 | * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area | ||
111 | * is actually sent to the dongle | ||
112 | */ | ||
113 | if (len > CDC_MAX_MSG_SIZE) | ||
114 | len = CDC_MAX_MSG_SIZE; | ||
115 | |||
116 | /* Send request */ | ||
117 | return brcmf_sdbrcm_bus_txctl(drvr->bus, (unsigned char *)&prot->msg, | ||
118 | len); | ||
119 | } | ||
120 | |||
121 | static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) | ||
122 | { | ||
123 | int ret; | ||
124 | struct brcmf_proto *prot = drvr->prot; | ||
125 | |||
126 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
127 | |||
128 | do { | ||
129 | ret = brcmf_sdbrcm_bus_rxctl(drvr->bus, | ||
130 | (unsigned char *)&prot->msg, | ||
131 | len + sizeof(struct brcmf_proto_cdc_ioctl)); | ||
132 | if (ret < 0) | ||
133 | break; | ||
134 | } while (CDC_IOC_ID(le32_to_cpu(prot->msg.flags)) != id); | ||
135 | |||
136 | return ret; | ||
137 | } | ||
138 | |||
139 | int | ||
140 | brcmf_proto_cdc_query_ioctl(struct brcmf_pub *drvr, int ifidx, uint cmd, | ||
141 | void *buf, uint len) | ||
142 | { | ||
143 | struct brcmf_proto *prot = drvr->prot; | ||
144 | struct brcmf_proto_cdc_ioctl *msg = &prot->msg; | ||
145 | void *info; | ||
146 | int ret = 0, retries = 0; | ||
147 | u32 id, flags = 0; | ||
148 | |||
149 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
150 | BRCMF_CTL(("%s: cmd %d len %d\n", __func__, cmd, len)); | ||
151 | |||
152 | /* Respond "bcmerror" and "bcmerrorstr" with local cache */ | ||
153 | if (cmd == BRCMF_C_GET_VAR && buf) { | ||
154 | if (!strcmp((char *)buf, "bcmerrorstr")) { | ||
155 | strncpy((char *)buf, "bcm_error", | ||
156 | BCME_STRLEN); | ||
157 | goto done; | ||
158 | } else if (!strcmp((char *)buf, "bcmerror")) { | ||
159 | *(int *)buf = drvr->dongle_error; | ||
160 | goto done; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | memset(msg, 0, sizeof(struct brcmf_proto_cdc_ioctl)); | ||
165 | |||
166 | msg->cmd = cpu_to_le32(cmd); | ||
167 | msg->len = cpu_to_le32(len); | ||
168 | msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); | ||
169 | CDC_SET_IF_IDX(msg, ifidx); | ||
170 | msg->flags = cpu_to_le32(msg->flags); | ||
171 | |||
172 | if (buf) | ||
173 | memcpy(prot->buf, buf, len); | ||
174 | |||
175 | ret = brcmf_proto_cdc_msg(drvr); | ||
176 | if (ret < 0) { | ||
177 | BRCMF_ERROR(("brcmf_proto_cdc_query_ioctl: brcmf_proto_cdc_msg " | ||
178 | "failed w/status %d\n", ret)); | ||
179 | goto done; | ||
180 | } | ||
181 | |||
182 | retry: | ||
183 | /* wait for interrupt and get first fragment */ | ||
184 | ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len); | ||
185 | if (ret < 0) | ||
186 | goto done; | ||
187 | |||
188 | flags = le32_to_cpu(msg->flags); | ||
189 | id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; | ||
190 | |||
191 | if ((id < prot->reqid) && (++retries < RETRIES)) | ||
192 | goto retry; | ||
193 | if (id != prot->reqid) { | ||
194 | BRCMF_ERROR(("%s: %s: unexpected request id %d (expected %d)\n", | ||
195 | brcmf_ifname(drvr, ifidx), __func__, id, | ||
196 | prot->reqid)); | ||
197 | ret = -EINVAL; | ||
198 | goto done; | ||
199 | } | ||
200 | |||
201 | /* Check info buffer */ | ||
202 | info = (void *)&msg[1]; | ||
203 | |||
204 | /* Copy info buffer */ | ||
205 | if (buf) { | ||
206 | if (ret < (int)len) | ||
207 | len = ret; | ||
208 | memcpy(buf, info, len); | ||
209 | } | ||
210 | |||
211 | /* Check the ERROR flag */ | ||
212 | if (flags & CDCF_IOC_ERROR) { | ||
213 | ret = le32_to_cpu(msg->status); | ||
214 | /* Cache error from dongle */ | ||
215 | drvr->dongle_error = ret; | ||
216 | } | ||
217 | |||
218 | done: | ||
219 | return ret; | ||
220 | } | ||
221 | |||
222 | int brcmf_proto_cdc_set_ioctl(struct brcmf_pub *drvr, int ifidx, uint cmd, | ||
223 | void *buf, uint len) | ||
224 | { | ||
225 | struct brcmf_proto *prot = drvr->prot; | ||
226 | struct brcmf_proto_cdc_ioctl *msg = &prot->msg; | ||
227 | int ret = 0; | ||
228 | u32 flags, id; | ||
229 | |||
230 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
231 | BRCMF_CTL(("%s: cmd %d len %d\n", __func__, cmd, len)); | ||
232 | |||
233 | memset(msg, 0, sizeof(struct brcmf_proto_cdc_ioctl)); | ||
234 | |||
235 | msg->cmd = cpu_to_le32(cmd); | ||
236 | msg->len = cpu_to_le32(len); | ||
237 | msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT) | CDCF_IOC_SET; | ||
238 | CDC_SET_IF_IDX(msg, ifidx); | ||
239 | msg->flags = cpu_to_le32(msg->flags); | ||
240 | |||
241 | if (buf) | ||
242 | memcpy(prot->buf, buf, len); | ||
243 | |||
244 | ret = brcmf_proto_cdc_msg(drvr); | ||
245 | if (ret < 0) | ||
246 | goto done; | ||
247 | |||
248 | ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len); | ||
249 | if (ret < 0) | ||
250 | goto done; | ||
251 | |||
252 | flags = le32_to_cpu(msg->flags); | ||
253 | id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; | ||
254 | |||
255 | if (id != prot->reqid) { | ||
256 | BRCMF_ERROR(("%s: %s: unexpected request id %d (expected %d)\n", | ||
257 | brcmf_ifname(drvr, ifidx), __func__, id, | ||
258 | prot->reqid)); | ||
259 | ret = -EINVAL; | ||
260 | goto done; | ||
261 | } | ||
262 | |||
263 | /* Check the ERROR flag */ | ||
264 | if (flags & CDCF_IOC_ERROR) { | ||
265 | ret = le32_to_cpu(msg->status); | ||
266 | /* Cache error from dongle */ | ||
267 | drvr->dongle_error = ret; | ||
268 | } | ||
269 | |||
270 | done: | ||
271 | return ret; | ||
272 | } | ||
273 | |||
274 | int | ||
275 | brcmf_proto_ioctl(struct brcmf_pub *drvr, int ifidx, struct brcmf_ioctl *ioc, | ||
276 | void *buf, int len) | ||
277 | { | ||
278 | struct brcmf_proto *prot = drvr->prot; | ||
279 | int ret = -1; | ||
280 | |||
281 | if (drvr->busstate == BRCMF_BUS_DOWN) { | ||
282 | BRCMF_ERROR(("%s : bus is down. we have nothing to do\n", | ||
283 | __func__)); | ||
284 | return ret; | ||
285 | } | ||
286 | brcmf_os_proto_block(drvr); | ||
287 | |||
288 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
289 | |||
290 | if (len > BRCMF_C_IOCTL_MAXLEN) | ||
291 | goto done; | ||
292 | |||
293 | if (prot->pending == true) { | ||
294 | BRCMF_TRACE(("CDC packet is pending!!!! cmd=0x%x (%lu) " | ||
295 | "lastcmd=0x%x (%lu)\n", | ||
296 | ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd, | ||
297 | (unsigned long)prot->lastcmd)); | ||
298 | if ((ioc->cmd == BRCMF_C_SET_VAR) || | ||
299 | (ioc->cmd == BRCMF_C_GET_VAR)) | ||
300 | BRCMF_TRACE(("iovar cmd=%s\n", (char *)buf)); | ||
301 | |||
302 | goto done; | ||
303 | } | ||
304 | |||
305 | prot->pending = true; | ||
306 | prot->lastcmd = ioc->cmd; | ||
307 | if (ioc->set) | ||
308 | ret = brcmf_proto_cdc_set_ioctl(drvr, ifidx, ioc->cmd, | ||
309 | buf, len); | ||
310 | else { | ||
311 | ret = brcmf_proto_cdc_query_ioctl(drvr, ifidx, ioc->cmd, | ||
312 | buf, len); | ||
313 | if (ret > 0) | ||
314 | ioc->used = ret - sizeof(struct brcmf_proto_cdc_ioctl); | ||
315 | } | ||
316 | |||
317 | /* Too many programs assume ioctl() returns 0 on success */ | ||
318 | if (ret >= 0) | ||
319 | ret = 0; | ||
320 | else { | ||
321 | struct brcmf_proto_cdc_ioctl *msg = &prot->msg; | ||
322 | /* len == needed when set/query fails from dongle */ | ||
323 | ioc->needed = le32_to_cpu(msg->len); | ||
324 | } | ||
325 | |||
326 | /* Intercept the wme_dp ioctl here */ | ||
327 | if (!ret && ioc->cmd == BRCMF_C_SET_VAR && | ||
328 | !strcmp(buf, "wme_dp")) { | ||
329 | int slen, val = 0; | ||
330 | |||
331 | slen = strlen("wme_dp") + 1; | ||
332 | if (len >= (int)(slen + sizeof(int))) | ||
333 | memcpy(&val, (char *)buf + slen, sizeof(int)); | ||
334 | drvr->wme_dp = (u8) le32_to_cpu(val); | ||
335 | } | ||
336 | |||
337 | prot->pending = false; | ||
338 | |||
339 | done: | ||
340 | brcmf_os_proto_unblock(drvr); | ||
341 | |||
342 | return ret; | ||
343 | } | ||
344 | |||
345 | #define PKTSUMNEEDED(skb) \ | ||
346 | (((struct sk_buff *)(skb))->ip_summed == CHECKSUM_PARTIAL) | ||
347 | #define PKTSETSUMGOOD(skb, x) \ | ||
348 | (((struct sk_buff *)(skb))->ip_summed = \ | ||
349 | ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE)) | ||
350 | |||
351 | void brcmf_proto_dump(struct brcmf_pub *drvr, struct brcmu_strbuf *strbuf) | ||
352 | { | ||
353 | brcmu_bprintf(strbuf, "Protocol CDC: reqid %d\n", drvr->prot->reqid); | ||
354 | } | ||
355 | |||
356 | void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, | ||
357 | struct sk_buff *pktbuf) | ||
358 | { | ||
359 | struct brcmf_proto_bdc_header *h; | ||
360 | |||
361 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
362 | |||
363 | /* Push BDC header used to convey priority for buses that don't */ | ||
364 | |||
365 | skb_push(pktbuf, BDC_HEADER_LEN); | ||
366 | |||
367 | h = (struct brcmf_proto_bdc_header *)(pktbuf->data); | ||
368 | |||
369 | h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); | ||
370 | if (PKTSUMNEEDED(pktbuf)) | ||
371 | h->flags |= BDC_FLAG_SUM_NEEDED; | ||
372 | |||
373 | h->priority = (pktbuf->priority & BDC_PRIORITY_MASK); | ||
374 | h->flags2 = 0; | ||
375 | h->rssi = 0; | ||
376 | BDC_SET_IF_IDX(h, ifidx); | ||
377 | } | ||
378 | |||
379 | int brcmf_proto_hdrpull(struct brcmf_pub *drvr, int *ifidx, | ||
380 | struct sk_buff *pktbuf) | ||
381 | { | ||
382 | struct brcmf_proto_bdc_header *h; | ||
383 | |||
384 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
385 | |||
386 | /* Pop BDC header used to convey priority for buses that don't */ | ||
387 | |||
388 | if (pktbuf->len < BDC_HEADER_LEN) { | ||
389 | BRCMF_ERROR(("%s: rx data too short (%d < %d)\n", __func__, | ||
390 | pktbuf->len, BDC_HEADER_LEN)); | ||
391 | return -EBADE; | ||
392 | } | ||
393 | |||
394 | h = (struct brcmf_proto_bdc_header *)(pktbuf->data); | ||
395 | |||
396 | *ifidx = BDC_GET_IF_IDX(h); | ||
397 | if (*ifidx >= BRCMF_MAX_IFS) { | ||
398 | BRCMF_ERROR(("%s: rx data ifnum out of range (%d)\n", | ||
399 | __func__, *ifidx)); | ||
400 | return -EBADE; | ||
401 | } | ||
402 | |||
403 | if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != | ||
404 | BDC_PROTO_VER) { | ||
405 | BRCMF_ERROR(("%s: non-BDC packet received, flags 0x%x\n", | ||
406 | brcmf_ifname(drvr, *ifidx), h->flags)); | ||
407 | return -EBADE; | ||
408 | } | ||
409 | |||
410 | if (h->flags & BDC_FLAG_SUM_GOOD) { | ||
411 | BRCMF_INFO(("%s: BDC packet received with good rx-csum, " | ||
412 | "flags 0x%x\n", | ||
413 | brcmf_ifname(drvr, *ifidx), h->flags)); | ||
414 | PKTSETSUMGOOD(pktbuf, true); | ||
415 | } | ||
416 | |||
417 | pktbuf->priority = h->priority & BDC_PRIORITY_MASK; | ||
418 | |||
419 | skb_pull(pktbuf, BDC_HEADER_LEN); | ||
420 | |||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | int brcmf_proto_attach(struct brcmf_pub *drvr) | ||
425 | { | ||
426 | struct brcmf_proto *cdc; | ||
427 | |||
428 | cdc = kzalloc(sizeof(struct brcmf_proto), GFP_ATOMIC); | ||
429 | if (!cdc) { | ||
430 | BRCMF_ERROR(("%s: kmalloc failed\n", __func__)); | ||
431 | goto fail; | ||
432 | } | ||
433 | |||
434 | /* ensure that the msg buf directly follows the cdc msg struct */ | ||
435 | if ((unsigned long)(&cdc->msg + 1) != (unsigned long)cdc->buf) { | ||
436 | BRCMF_ERROR(("struct brcmf_proto is not correctly defined\n")); | ||
437 | goto fail; | ||
438 | } | ||
439 | |||
440 | drvr->prot = cdc; | ||
441 | drvr->hdrlen += BDC_HEADER_LEN; | ||
442 | drvr->maxctl = BRCMF_C_IOCTL_MAXLEN + | ||
443 | sizeof(struct brcmf_proto_cdc_ioctl) + ROUND_UP_MARGIN; | ||
444 | return 0; | ||
445 | |||
446 | fail: | ||
447 | kfree(cdc); | ||
448 | return -ENOMEM; | ||
449 | } | ||
450 | |||
451 | /* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */ | ||
452 | void brcmf_proto_detach(struct brcmf_pub *drvr) | ||
453 | { | ||
454 | kfree(drvr->prot); | ||
455 | drvr->prot = NULL; | ||
456 | } | ||
457 | |||
458 | void brcmf_proto_dstats(struct brcmf_pub *drvr) | ||
459 | { | ||
460 | /* No stats from dongle added yet, copy bus stats */ | ||
461 | drvr->dstats.tx_packets = drvr->tx_packets; | ||
462 | drvr->dstats.tx_errors = drvr->tx_errors; | ||
463 | drvr->dstats.rx_packets = drvr->rx_packets; | ||
464 | drvr->dstats.rx_errors = drvr->rx_errors; | ||
465 | drvr->dstats.rx_dropped = drvr->rx_dropped; | ||
466 | drvr->dstats.multicast = drvr->rx_multicast; | ||
467 | return; | ||
468 | } | ||
469 | |||
470 | int brcmf_proto_init(struct brcmf_pub *drvr) | ||
471 | { | ||
472 | int ret = 0; | ||
473 | char buf[128]; | ||
474 | |||
475 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
476 | |||
477 | brcmf_os_proto_block(drvr); | ||
478 | |||
479 | /* Get the device MAC address */ | ||
480 | strcpy(buf, "cur_etheraddr"); | ||
481 | ret = brcmf_proto_cdc_query_ioctl(drvr, 0, BRCMF_C_GET_VAR, | ||
482 | buf, sizeof(buf)); | ||
483 | if (ret < 0) { | ||
484 | brcmf_os_proto_unblock(drvr); | ||
485 | return ret; | ||
486 | } | ||
487 | memcpy(drvr->mac, buf, ETH_ALEN); | ||
488 | |||
489 | brcmf_os_proto_unblock(drvr); | ||
490 | |||
491 | ret = brcmf_c_preinit_ioctls(drvr); | ||
492 | |||
493 | /* Always assumes wl for now */ | ||
494 | drvr->iswl = true; | ||
495 | |||
496 | return ret; | ||
497 | } | ||
498 | |||
499 | void brcmf_proto_stop(struct brcmf_pub *drvr) | ||
500 | { | ||
501 | /* Nothing to do for CDC */ | ||
502 | } | ||
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_common.c b/drivers/staging/brcm80211/brcmfmac/dhd_common.c new file mode 100644 index 00000000000..fdec4683c42 --- /dev/null +++ b/drivers/staging/brcm80211/brcmfmac/dhd_common.c | |||
@@ -0,0 +1,1196 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/string.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/netdevice.h> | ||
20 | #include <asm/unaligned.h> | ||
21 | #include <defs.h> | ||
22 | #include <brcmu_wifi.h> | ||
23 | #include <brcmu_utils.h> | ||
24 | #include "dhd.h" | ||
25 | #include "dhd_bus.h" | ||
26 | #include "dhd_proto.h" | ||
27 | #include "dhd_dbg.h" | ||
28 | |||
29 | #define BRCM_OUI "\x00\x10\x18" | ||
30 | #define DOT11_OUI_LEN 3 | ||
31 | #define BCMILCP_BCM_SUBTYPE_EVENT 1 | ||
32 | #define PKTFILTER_BUF_SIZE 2048 | ||
33 | |||
34 | int brcmf_msg_level; | ||
35 | |||
36 | #define MSGTRACE_VERSION 1 | ||
37 | |||
38 | #ifdef BCMDBG | ||
39 | const char brcmf_version[] = | ||
40 | "Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on " __DATE__ | ||
41 | " at " __TIME__; | ||
42 | #else | ||
43 | const char brcmf_version[] = "Dongle Host Driver, version " BRCMF_VERSION_STR; | ||
44 | #endif | ||
45 | |||
46 | /* IOVar table */ | ||
47 | enum { | ||
48 | IOV_VERSION = 1, | ||
49 | IOV_MSGLEVEL, | ||
50 | IOV_BCMERRORSTR, | ||
51 | IOV_BCMERROR, | ||
52 | IOV_DUMP, | ||
53 | IOV_CLEARCOUNTS, | ||
54 | IOV_LOGDUMP, | ||
55 | IOV_LOGCAL, | ||
56 | IOV_LOGSTAMP, | ||
57 | IOV_GPIOOB, | ||
58 | IOV_IOCTLTIMEOUT, | ||
59 | IOV_LAST | ||
60 | }; | ||
61 | |||
62 | const struct brcmu_iovar brcmf_iovars[] = { | ||
63 | {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(brcmf_version)} | ||
64 | , | ||
65 | #ifdef BCMDBG | ||
66 | {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0} | ||
67 | , | ||
68 | #endif /* BCMDBG */ | ||
69 | {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN} | ||
70 | , | ||
71 | {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0} | ||
72 | , | ||
73 | {"dump", IOV_DUMP, 0, IOVT_BUFFER, BRCMF_IOCTL_MAXLEN} | ||
74 | , | ||
75 | {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0} | ||
76 | , | ||
77 | {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0} | ||
78 | , | ||
79 | {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0} | ||
80 | , | ||
81 | {NULL, 0, 0, 0, 0} | ||
82 | }; | ||
83 | |||
84 | /* Message trace header */ | ||
85 | struct msgtrace_hdr { | ||
86 | u8 version; | ||
87 | u8 spare; | ||
88 | u16 len; /* Len of the trace */ | ||
89 | u32 seqnum; /* Sequence number of message. Useful | ||
90 | * if the messsage has been lost | ||
91 | * because of DMA error or a bus reset | ||
92 | * (ex: SDIO Func2) | ||
93 | */ | ||
94 | u32 discarded_bytes; /* Number of discarded bytes because of | ||
95 | trace overflow */ | ||
96 | u32 discarded_printf; /* Number of discarded printf | ||
97 | because of trace overflow */ | ||
98 | } __packed; | ||
99 | |||
100 | void brcmf_c_init(void) | ||
101 | { | ||
102 | /* Init global variables at run-time, not as part of the declaration. | ||
103 | * This is required to support init/de-init of the driver. | ||
104 | * Initialization | ||
105 | * of globals as part of the declaration results in non-deterministic | ||
106 | * behaviour since the value of the globals may be different on the | ||
107 | * first time that the driver is initialized vs subsequent | ||
108 | * initializations. | ||
109 | */ | ||
110 | brcmf_msg_level = BRCMF_ERROR_VAL; | ||
111 | } | ||
112 | |||
113 | static int brcmf_c_dump(struct brcmf_pub *drvr, char *buf, int buflen) | ||
114 | { | ||
115 | struct brcmu_strbuf b; | ||
116 | struct brcmu_strbuf *strbuf = &b; | ||
117 | |||
118 | brcmu_binit(strbuf, buf, buflen); | ||
119 | |||
120 | /* Base info */ | ||
121 | brcmu_bprintf(strbuf, "%s\n", brcmf_version); | ||
122 | brcmu_bprintf(strbuf, "\n"); | ||
123 | brcmu_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n", | ||
124 | drvr->up, drvr->txoff, drvr->busstate); | ||
125 | brcmu_bprintf(strbuf, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n", | ||
126 | drvr->hdrlen, drvr->maxctl, drvr->rxsz); | ||
127 | brcmu_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %pM\n", | ||
128 | drvr->iswl, drvr->drv_version, &drvr->mac); | ||
129 | brcmu_bprintf(strbuf, "pub.bcmerror %d tickcnt %d\n", drvr->bcmerror, | ||
130 | drvr->tickcnt); | ||
131 | |||
132 | brcmu_bprintf(strbuf, "dongle stats:\n"); | ||
133 | brcmu_bprintf(strbuf, | ||
134 | "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n", | ||
135 | drvr->dstats.tx_packets, drvr->dstats.tx_bytes, | ||
136 | drvr->dstats.tx_errors, drvr->dstats.tx_dropped); | ||
137 | brcmu_bprintf(strbuf, | ||
138 | "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n", | ||
139 | drvr->dstats.rx_packets, drvr->dstats.rx_bytes, | ||
140 | drvr->dstats.rx_errors, drvr->dstats.rx_dropped); | ||
141 | brcmu_bprintf(strbuf, "multicast %ld\n", drvr->dstats.multicast); | ||
142 | |||
143 | brcmu_bprintf(strbuf, "bus stats:\n"); | ||
144 | brcmu_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n", | ||
145 | drvr->tx_packets, drvr->tx_multicast, drvr->tx_errors); | ||
146 | brcmu_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n", | ||
147 | drvr->tx_ctlpkts, drvr->tx_ctlerrs); | ||
148 | brcmu_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld\n", | ||
149 | drvr->rx_packets, drvr->rx_multicast, drvr->rx_errors); | ||
150 | brcmu_bprintf(strbuf, | ||
151 | "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld rx_flushed %ld\n", | ||
152 | drvr->rx_ctlpkts, drvr->rx_ctlerrs, drvr->rx_dropped, | ||
153 | drvr->rx_flushed); | ||
154 | brcmu_bprintf(strbuf, | ||
155 | "rx_readahead_cnt %ld tx_realloc %ld fc_packets %ld\n", | ||
156 | drvr->rx_readahead_cnt, drvr->tx_realloc, drvr->fc_packets); | ||
157 | brcmu_bprintf(strbuf, "wd_dpc_sched %ld\n", drvr->wd_dpc_sched); | ||
158 | brcmu_bprintf(strbuf, "\n"); | ||
159 | |||
160 | /* Add any prot info */ | ||
161 | brcmf_proto_dump(drvr, strbuf); | ||
162 | brcmu_bprintf(strbuf, "\n"); | ||
163 | |||
164 | /* Add any bus info */ | ||
165 | brcmf_sdbrcm_bus_dump(drvr, strbuf); | ||
166 | |||
167 | return !strbuf->size ? -EOVERFLOW : 0; | ||
168 | } | ||
169 | |||
170 | static int | ||
171 | brcmf_c_doiovar(struct brcmf_pub *drvr, const struct brcmu_iovar *vi, | ||
172 | u32 actionid, const char *name, void *params, int plen, | ||
173 | void *arg, int len, int val_size) | ||
174 | { | ||
175 | int bcmerror = 0; | ||
176 | s32 int_val = 0; | ||
177 | |||
178 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
179 | |||
180 | bcmerror = brcmu_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid)); | ||
181 | if (bcmerror != 0) | ||
182 | goto exit; | ||
183 | |||
184 | if (plen >= (int)sizeof(int_val)) | ||
185 | memcpy(&int_val, params, sizeof(int_val)); | ||
186 | |||
187 | switch (actionid) { | ||
188 | case IOV_GVAL(IOV_VERSION): | ||
189 | /* Need to have checked buffer length */ | ||
190 | strncpy((char *)arg, brcmf_version, len); | ||
191 | break; | ||
192 | |||
193 | case IOV_GVAL(IOV_MSGLEVEL): | ||
194 | int_val = (s32) brcmf_msg_level; | ||
195 | memcpy(arg, &int_val, val_size); | ||
196 | break; | ||
197 | |||
198 | case IOV_SVAL(IOV_MSGLEVEL): | ||
199 | brcmf_msg_level = int_val; | ||
200 | break; | ||
201 | |||
202 | case IOV_GVAL(IOV_BCMERRORSTR): | ||
203 | strncpy((char *)arg, "bcm_error", | ||
204 | BCME_STRLEN); | ||
205 | ((char *)arg)[BCME_STRLEN - 1] = 0x00; | ||
206 | break; | ||
207 | |||
208 | case IOV_GVAL(IOV_BCMERROR): | ||
209 | int_val = (s32) drvr->bcmerror; | ||
210 | memcpy(arg, &int_val, val_size); | ||
211 | break; | ||
212 | |||
213 | case IOV_GVAL(IOV_DUMP): | ||
214 | bcmerror = brcmf_c_dump(drvr, arg, len); | ||
215 | break; | ||
216 | |||
217 | case IOV_SVAL(IOV_CLEARCOUNTS): | ||
218 | drvr->tx_packets = drvr->rx_packets = 0; | ||
219 | drvr->tx_errors = drvr->rx_errors = 0; | ||
220 | drvr->tx_ctlpkts = drvr->rx_ctlpkts = 0; | ||
221 | drvr->tx_ctlerrs = drvr->rx_ctlerrs = 0; | ||
222 | drvr->rx_dropped = 0; | ||
223 | drvr->rx_readahead_cnt = 0; | ||
224 | drvr->tx_realloc = 0; | ||
225 | drvr->wd_dpc_sched = 0; | ||
226 | memset(&drvr->dstats, 0, sizeof(drvr->dstats)); | ||
227 | brcmf_bus_clearcounts(drvr); | ||
228 | break; | ||
229 | |||
230 | case IOV_GVAL(IOV_IOCTLTIMEOUT):{ | ||
231 | int_val = (s32) brcmf_os_get_ioctl_resp_timeout(); | ||
232 | memcpy(arg, &int_val, sizeof(int_val)); | ||
233 | break; | ||
234 | } | ||
235 | |||
236 | case IOV_SVAL(IOV_IOCTLTIMEOUT):{ | ||
237 | if (int_val <= 0) | ||
238 | bcmerror = -EINVAL; | ||
239 | else | ||
240 | brcmf_os_set_ioctl_resp_timeout((unsigned int) | ||
241 | int_val); | ||
242 | break; | ||
243 | } | ||
244 | |||
245 | default: | ||
246 | bcmerror = -ENOTSUPP; | ||
247 | break; | ||
248 | } | ||
249 | |||
250 | exit: | ||
251 | return bcmerror; | ||
252 | } | ||
253 | |||
254 | bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q, | ||
255 | struct sk_buff *pkt, int prec) | ||
256 | { | ||
257 | struct sk_buff *p; | ||
258 | int eprec = -1; /* precedence to evict from */ | ||
259 | bool discard_oldest; | ||
260 | |||
261 | /* Fast case, precedence queue is not full and we are also not | ||
262 | * exceeding total queue length | ||
263 | */ | ||
264 | if (!pktq_pfull(q, prec) && !pktq_full(q)) { | ||
265 | brcmu_pktq_penq(q, prec, pkt); | ||
266 | return true; | ||
267 | } | ||
268 | |||
269 | /* Determine precedence from which to evict packet, if any */ | ||
270 | if (pktq_pfull(q, prec)) | ||
271 | eprec = prec; | ||
272 | else if (pktq_full(q)) { | ||
273 | p = brcmu_pktq_peek_tail(q, &eprec); | ||
274 | if (eprec > prec) | ||
275 | return false; | ||
276 | } | ||
277 | |||
278 | /* Evict if needed */ | ||
279 | if (eprec >= 0) { | ||
280 | /* Detect queueing to unconfigured precedence */ | ||
281 | discard_oldest = AC_BITMAP_TST(drvr->wme_dp, eprec); | ||
282 | if (eprec == prec && !discard_oldest) | ||
283 | return false; /* refuse newer (incoming) packet */ | ||
284 | /* Evict packet according to discard policy */ | ||
285 | p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) : | ||
286 | brcmu_pktq_pdeq_tail(q, eprec); | ||
287 | if (p == NULL) { | ||
288 | BRCMF_ERROR(("%s: brcmu_pktq_penq() failed, oldest %d.", | ||
289 | __func__, discard_oldest)); | ||
290 | } | ||
291 | brcmu_pkt_buf_free_skb(p); | ||
292 | } | ||
293 | |||
294 | /* Enqueue */ | ||
295 | p = brcmu_pktq_penq(q, prec, pkt); | ||
296 | if (p == NULL) { | ||
297 | BRCMF_ERROR(("%s: brcmu_pktq_penq() failed.", __func__)); | ||
298 | } | ||
299 | |||
300 | return p != NULL; | ||
301 | } | ||
302 | |||
303 | static int | ||
304 | brcmf_c_iovar_op(struct brcmf_pub *drvr, const char *name, | ||
305 | void *params, int plen, void *arg, int len, bool set) | ||
306 | { | ||
307 | int bcmerror = 0; | ||
308 | int val_size; | ||
309 | const struct brcmu_iovar *vi = NULL; | ||
310 | u32 actionid; | ||
311 | |||
312 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
313 | |||
314 | if (name == NULL || len <= 0) | ||
315 | return -EINVAL; | ||
316 | |||
317 | /* Set does not take qualifiers */ | ||
318 | if (set && (params || plen)) | ||
319 | return -EINVAL; | ||
320 | |||
321 | /* Get must have return space;*/ | ||
322 | if (!set && !(arg && len)) | ||
323 | return -EINVAL; | ||
324 | |||
325 | vi = brcmu_iovar_lookup(brcmf_iovars, name); | ||
326 | if (vi == NULL) { | ||
327 | bcmerror = -ENOTSUPP; | ||
328 | goto exit; | ||
329 | } | ||
330 | |||
331 | BRCMF_CTL(("%s: %s %s, len %d plen %d\n", __func__, | ||
332 | name, (set ? "set" : "get"), len, plen)); | ||
333 | |||
334 | /* set up 'params' pointer in case this is a set command so that | ||
335 | * the convenience int and bool code can be common to set and get | ||
336 | */ | ||
337 | if (params == NULL) { | ||
338 | params = arg; | ||
339 | plen = len; | ||
340 | } | ||
341 | |||
342 | if (vi->type == IOVT_VOID) | ||
343 | val_size = 0; | ||
344 | else if (vi->type == IOVT_BUFFER) | ||
345 | val_size = len; | ||
346 | else | ||
347 | /* all other types are integer sized */ | ||
348 | val_size = sizeof(int); | ||
349 | |||
350 | actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); | ||
351 | bcmerror = | ||
352 | brcmf_c_doiovar(drvr, vi, actionid, name, params, plen, arg, len, | ||
353 | val_size); | ||
354 | |||
355 | exit: | ||
356 | return bcmerror; | ||
357 | } | ||
358 | |||
359 | int brcmf_c_ioctl(struct brcmf_pub *drvr, struct brcmf_c_ioctl *ioc, void *buf, | ||
360 | uint buflen) | ||
361 | { | ||
362 | int bcmerror = 0; | ||
363 | |||
364 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
365 | |||
366 | if (!buf) | ||
367 | return -EINVAL; | ||
368 | |||
369 | switch (ioc->cmd) { | ||
370 | case BRCMF_GET_MAGIC: | ||
371 | if (buflen < sizeof(int)) | ||
372 | bcmerror = -EOVERFLOW; | ||
373 | else | ||
374 | *(int *)buf = BRCMF_IOCTL_MAGIC; | ||
375 | break; | ||
376 | |||
377 | case BRCMF_GET_VERSION: | ||
378 | if (buflen < sizeof(int)) | ||
379 | bcmerror = -EOVERFLOW; | ||
380 | else | ||
381 | *(int *)buf = BRCMF_IOCTL_VERSION; | ||
382 | break; | ||
383 | |||
384 | case BRCMF_GET_VAR: | ||
385 | case BRCMF_SET_VAR:{ | ||
386 | char *arg; | ||
387 | uint arglen; | ||
388 | |||
389 | /* scan past the name to any arguments */ | ||
390 | for (arg = buf, arglen = buflen; *arg && arglen; | ||
391 | arg++, arglen--) | ||
392 | ; | ||
393 | |||
394 | if (*arg) { | ||
395 | bcmerror = -EOVERFLOW; | ||
396 | break; | ||
397 | } | ||
398 | |||
399 | /* account for the NUL terminator */ | ||
400 | arg++, arglen--; | ||
401 | |||
402 | /* call with the appropriate arguments */ | ||
403 | if (ioc->cmd == BRCMF_GET_VAR) | ||
404 | bcmerror = brcmf_c_iovar_op(drvr, buf, arg, | ||
405 | arglen, buf, buflen, IOV_GET); | ||
406 | else | ||
407 | bcmerror = | ||
408 | brcmf_c_iovar_op(drvr, buf, NULL, 0, arg, | ||
409 | arglen, IOV_SET); | ||
410 | if (bcmerror != -ENOTSUPP) | ||
411 | break; | ||
412 | |||
413 | /* if still not found, try bus module */ | ||
414 | if (ioc->cmd == BRCMF_GET_VAR) | ||
415 | bcmerror = brcmf_sdbrcm_bus_iovar_op(drvr, | ||
416 | buf, arg, arglen, buf, buflen, | ||
417 | IOV_GET); | ||
418 | else | ||
419 | bcmerror = brcmf_sdbrcm_bus_iovar_op(drvr, | ||
420 | buf, NULL, 0, arg, arglen, | ||
421 | IOV_SET); | ||
422 | |||
423 | break; | ||
424 | } | ||
425 | |||
426 | default: | ||
427 | bcmerror = -ENOTSUPP; | ||
428 | } | ||
429 | |||
430 | return bcmerror; | ||
431 | } | ||
432 | |||
433 | #ifdef SHOW_EVENTS | ||
434 | static void | ||
435 | brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data) | ||
436 | { | ||
437 | uint i, status, reason; | ||
438 | bool group = false, flush_txq = false, link = false; | ||
439 | char *auth_str, *event_name; | ||
440 | unsigned char *buf; | ||
441 | char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; | ||
442 | static struct { | ||
443 | uint event; | ||
444 | char *event_name; | ||
445 | } event_names[] = { | ||
446 | { | ||
447 | BRCMF_E_SET_SSID, "SET_SSID"}, { | ||
448 | BRCMF_E_JOIN, "JOIN"}, { | ||
449 | BRCMF_E_START, "START"}, { | ||
450 | BRCMF_E_AUTH, "AUTH"}, { | ||
451 | BRCMF_E_AUTH_IND, "AUTH_IND"}, { | ||
452 | BRCMF_E_DEAUTH, "DEAUTH"}, { | ||
453 | BRCMF_E_DEAUTH_IND, "DEAUTH_IND"}, { | ||
454 | BRCMF_E_ASSOC, "ASSOC"}, { | ||
455 | BRCMF_E_ASSOC_IND, "ASSOC_IND"}, { | ||
456 | BRCMF_E_REASSOC, "REASSOC"}, { | ||
457 | BRCMF_E_REASSOC_IND, "REASSOC_IND"}, { | ||
458 | BRCMF_E_DISASSOC, "DISASSOC"}, { | ||
459 | BRCMF_E_DISASSOC_IND, "DISASSOC_IND"}, { | ||
460 | BRCMF_E_QUIET_START, "START_QUIET"}, { | ||
461 | BRCMF_E_QUIET_END, "END_QUIET"}, { | ||
462 | BRCMF_E_BEACON_RX, "BEACON_RX"}, { | ||
463 | BRCMF_E_LINK, "LINK"}, { | ||
464 | BRCMF_E_MIC_ERROR, "MIC_ERROR"}, { | ||
465 | BRCMF_E_NDIS_LINK, "NDIS_LINK"}, { | ||
466 | BRCMF_E_ROAM, "ROAM"}, { | ||
467 | BRCMF_E_TXFAIL, "TXFAIL"}, { | ||
468 | BRCMF_E_PMKID_CACHE, "PMKID_CACHE"}, { | ||
469 | BRCMF_E_RETROGRADE_TSF, "RETROGRADE_TSF"}, { | ||
470 | BRCMF_E_PRUNE, "PRUNE"}, { | ||
471 | BRCMF_E_AUTOAUTH, "AUTOAUTH"}, { | ||
472 | BRCMF_E_EAPOL_MSG, "EAPOL_MSG"}, { | ||
473 | BRCMF_E_SCAN_COMPLETE, "SCAN_COMPLETE"}, { | ||
474 | BRCMF_E_ADDTS_IND, "ADDTS_IND"}, { | ||
475 | BRCMF_E_DELTS_IND, "DELTS_IND"}, { | ||
476 | BRCMF_E_BCNSENT_IND, "BCNSENT_IND"}, { | ||
477 | BRCMF_E_BCNRX_MSG, "BCNRX_MSG"}, { | ||
478 | BRCMF_E_BCNLOST_MSG, "BCNLOST_MSG"}, { | ||
479 | BRCMF_E_ROAM_PREP, "ROAM_PREP"}, { | ||
480 | BRCMF_E_PFN_NET_FOUND, "PNO_NET_FOUND"}, { | ||
481 | BRCMF_E_PFN_NET_LOST, "PNO_NET_LOST"}, { | ||
482 | BRCMF_E_RESET_COMPLETE, "RESET_COMPLETE"}, { | ||
483 | BRCMF_E_JOIN_START, "JOIN_START"}, { | ||
484 | BRCMF_E_ROAM_START, "ROAM_START"}, { | ||
485 | BRCMF_E_ASSOC_START, "ASSOC_START"}, { | ||
486 | BRCMF_E_IBSS_ASSOC, "IBSS_ASSOC"}, { | ||
487 | BRCMF_E_RADIO, "RADIO"}, { | ||
488 | BRCMF_E_PSM_WATCHDOG, "PSM_WATCHDOG"}, { | ||
489 | BRCMF_E_PROBREQ_MSG, "PROBREQ_MSG"}, { | ||
490 | BRCMF_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"}, { | ||
491 | BRCMF_E_PSK_SUP, "PSK_SUP"}, { | ||
492 | BRCMF_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"}, { | ||
493 | BRCMF_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"}, { | ||
494 | BRCMF_E_ICV_ERROR, "ICV_ERROR"}, { | ||
495 | BRCMF_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"}, { | ||
496 | BRCMF_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"}, { | ||
497 | BRCMF_E_TRACE, "TRACE"}, { | ||
498 | BRCMF_E_ACTION_FRAME, "ACTION FRAME"}, { | ||
499 | BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"}, { | ||
500 | BRCMF_E_IF, "IF"}, { | ||
501 | BRCMF_E_RSSI, "RSSI"}, { | ||
502 | BRCMF_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"} | ||
503 | }; | ||
504 | uint event_type, flags, auth_type, datalen; | ||
505 | event_type = be32_to_cpu(event->event_type); | ||
506 | flags = be16_to_cpu(event->flags); | ||
507 | status = be32_to_cpu(event->status); | ||
508 | reason = be32_to_cpu(event->reason); | ||
509 | auth_type = be32_to_cpu(event->auth_type); | ||
510 | datalen = be32_to_cpu(event->datalen); | ||
511 | /* debug dump of event messages */ | ||
512 | sprintf(eabuf, "%pM", event->addr); | ||
513 | |||
514 | event_name = "UNKNOWN"; | ||
515 | for (i = 0; i < ARRAY_SIZE(event_names); i++) { | ||
516 | if (event_names[i].event == event_type) | ||
517 | event_name = event_names[i].event_name; | ||
518 | } | ||
519 | |||
520 | BRCMF_EVENT(("EVENT: %s, event ID = %d\n", event_name, event_type)); | ||
521 | BRCMF_EVENT(("flags 0x%04x, status %d, reason %d, auth_type %d" | ||
522 | " MAC %s\n", flags, status, reason, auth_type, eabuf)); | ||
523 | |||
524 | if (flags & BRCMF_EVENT_MSG_LINK) | ||
525 | link = true; | ||
526 | if (flags & BRCMF_EVENT_MSG_GROUP) | ||
527 | group = true; | ||
528 | if (flags & BRCMF_EVENT_MSG_FLUSHTXQ) | ||
529 | flush_txq = true; | ||
530 | |||
531 | switch (event_type) { | ||
532 | case BRCMF_E_START: | ||
533 | case BRCMF_E_DEAUTH: | ||
534 | case BRCMF_E_DISASSOC: | ||
535 | BRCMF_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); | ||
536 | break; | ||
537 | |||
538 | case BRCMF_E_ASSOC_IND: | ||
539 | case BRCMF_E_REASSOC_IND: | ||
540 | BRCMF_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); | ||
541 | break; | ||
542 | |||
543 | case BRCMF_E_ASSOC: | ||
544 | case BRCMF_E_REASSOC: | ||
545 | if (status == BRCMF_E_STATUS_SUCCESS) { | ||
546 | BRCMF_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", | ||
547 | event_name, eabuf)); | ||
548 | } else if (status == BRCMF_E_STATUS_TIMEOUT) { | ||
549 | BRCMF_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", | ||
550 | event_name, eabuf)); | ||
551 | } else if (status == BRCMF_E_STATUS_FAIL) { | ||
552 | BRCMF_EVENT(("MACEVENT: %s, MAC %s, FAILURE," | ||
553 | " reason %d\n", event_name, eabuf, | ||
554 | (int)reason)); | ||
555 | } else { | ||
556 | BRCMF_EVENT(("MACEVENT: %s, MAC %s, unexpected status " | ||
557 | "%d\n", event_name, eabuf, (int)status)); | ||
558 | } | ||
559 | break; | ||
560 | |||
561 | case BRCMF_E_DEAUTH_IND: | ||
562 | case BRCMF_E_DISASSOC_IND: | ||
563 | BRCMF_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, | ||
564 | eabuf, (int)reason)); | ||
565 | break; | ||
566 | |||
567 | case BRCMF_E_AUTH: | ||
568 | case BRCMF_E_AUTH_IND: | ||
569 | if (auth_type == WLAN_AUTH_OPEN) | ||
570 | auth_str = "Open System"; | ||
571 | else if (auth_type == WLAN_AUTH_SHARED_KEY) | ||
572 | auth_str = "Shared Key"; | ||
573 | else { | ||
574 | sprintf(err_msg, "AUTH unknown: %d", (int)auth_type); | ||
575 | auth_str = err_msg; | ||
576 | } | ||
577 | if (event_type == BRCMF_E_AUTH_IND) { | ||
578 | BRCMF_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, | ||
579 | eabuf, auth_str)); | ||
580 | } else if (status == BRCMF_E_STATUS_SUCCESS) { | ||
581 | BRCMF_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n", | ||
582 | event_name, eabuf, auth_str)); | ||
583 | } else if (status == BRCMF_E_STATUS_TIMEOUT) { | ||
584 | BRCMF_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n", | ||
585 | event_name, eabuf, auth_str)); | ||
586 | } else if (status == BRCMF_E_STATUS_FAIL) { | ||
587 | BRCMF_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, " | ||
588 | "reason %d\n", | ||
589 | event_name, eabuf, auth_str, (int)reason)); | ||
590 | } | ||
591 | |||
592 | break; | ||
593 | |||
594 | case BRCMF_E_JOIN: | ||
595 | case BRCMF_E_ROAM: | ||
596 | case BRCMF_E_SET_SSID: | ||
597 | if (status == BRCMF_E_STATUS_SUCCESS) { | ||
598 | BRCMF_EVENT(("MACEVENT: %s, MAC %s\n", event_name, | ||
599 | eabuf)); | ||
600 | } else if (status == BRCMF_E_STATUS_FAIL) { | ||
601 | BRCMF_EVENT(("MACEVENT: %s, failed\n", event_name)); | ||
602 | } else if (status == BRCMF_E_STATUS_NO_NETWORKS) { | ||
603 | BRCMF_EVENT(("MACEVENT: %s, no networks found\n", | ||
604 | event_name)); | ||
605 | } else { | ||
606 | BRCMF_EVENT(("MACEVENT: %s, unexpected status %d\n", | ||
607 | event_name, (int)status)); | ||
608 | } | ||
609 | break; | ||
610 | |||
611 | case BRCMF_E_BEACON_RX: | ||
612 | if (status == BRCMF_E_STATUS_SUCCESS) { | ||
613 | BRCMF_EVENT(("MACEVENT: %s, SUCCESS\n", event_name)); | ||
614 | } else if (status == BRCMF_E_STATUS_FAIL) { | ||
615 | BRCMF_EVENT(("MACEVENT: %s, FAIL\n", event_name)); | ||
616 | } else { | ||
617 | BRCMF_EVENT(("MACEVENT: %s, status %d\n", event_name, | ||
618 | status)); | ||
619 | } | ||
620 | break; | ||
621 | |||
622 | case BRCMF_E_LINK: | ||
623 | BRCMF_EVENT(("MACEVENT: %s %s\n", event_name, | ||
624 | link ? "UP" : "DOWN")); | ||
625 | break; | ||
626 | |||
627 | case BRCMF_E_MIC_ERROR: | ||
628 | BRCMF_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n", | ||
629 | event_name, eabuf, group, flush_txq)); | ||
630 | break; | ||
631 | |||
632 | case BRCMF_E_ICV_ERROR: | ||
633 | case BRCMF_E_UNICAST_DECODE_ERROR: | ||
634 | case BRCMF_E_MULTICAST_DECODE_ERROR: | ||
635 | BRCMF_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); | ||
636 | break; | ||
637 | |||
638 | case BRCMF_E_TXFAIL: | ||
639 | BRCMF_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf)); | ||
640 | break; | ||
641 | |||
642 | case BRCMF_E_SCAN_COMPLETE: | ||
643 | case BRCMF_E_PMKID_CACHE: | ||
644 | BRCMF_EVENT(("MACEVENT: %s\n", event_name)); | ||
645 | break; | ||
646 | |||
647 | case BRCMF_E_PFN_NET_FOUND: | ||
648 | case BRCMF_E_PFN_NET_LOST: | ||
649 | case BRCMF_E_PFN_SCAN_COMPLETE: | ||
650 | BRCMF_EVENT(("PNOEVENT: %s\n", event_name)); | ||
651 | break; | ||
652 | |||
653 | case BRCMF_E_PSK_SUP: | ||
654 | case BRCMF_E_PRUNE: | ||
655 | BRCMF_EVENT(("MACEVENT: %s, status %d, reason %d\n", | ||
656 | event_name, (int)status, (int)reason)); | ||
657 | break; | ||
658 | |||
659 | case BRCMF_E_TRACE: | ||
660 | { | ||
661 | static u32 seqnum_prev; | ||
662 | struct msgtrace_hdr hdr; | ||
663 | u32 nblost; | ||
664 | char *s, *p; | ||
665 | |||
666 | buf = (unsigned char *) event_data; | ||
667 | memcpy(&hdr, buf, sizeof(struct msgtrace_hdr)); | ||
668 | |||
669 | if (hdr.version != MSGTRACE_VERSION) { | ||
670 | BRCMF_ERROR( | ||
671 | ("\nMACEVENT: %s [unsupported version --> " | ||
672 | "brcmf version:%d dongle version:%d]\n", | ||
673 | event_name, MSGTRACE_VERSION, hdr.version) | ||
674 | ); | ||
675 | /* Reset datalen to avoid display below */ | ||
676 | datalen = 0; | ||
677 | break; | ||
678 | } | ||
679 | |||
680 | /* There are 2 bytes available at the end of data */ | ||
681 | *(buf + sizeof(struct msgtrace_hdr) | ||
682 | + be16_to_cpu(hdr.len)) = '\0'; | ||
683 | |||
684 | if (be32_to_cpu(hdr.discarded_bytes) | ||
685 | || be32_to_cpu(hdr.discarded_printf)) { | ||
686 | BRCMF_ERROR( | ||
687 | ("\nWLC_E_TRACE: [Discarded traces in dongle -->" | ||
688 | "discarded_bytes %d discarded_printf %d]\n", | ||
689 | be32_to_cpu(hdr.discarded_bytes), | ||
690 | be32_to_cpu(hdr.discarded_printf))); | ||
691 | } | ||
692 | |||
693 | nblost = be32_to_cpu(hdr.seqnum) - seqnum_prev - 1; | ||
694 | if (nblost > 0) { | ||
695 | BRCMF_ERROR( | ||
696 | ("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n", | ||
697 | be32_to_cpu(hdr.seqnum), nblost)); | ||
698 | } | ||
699 | seqnum_prev = be32_to_cpu(hdr.seqnum); | ||
700 | |||
701 | /* Display the trace buffer. Advance from \n to \n to | ||
702 | * avoid display big | ||
703 | * printf (issue with Linux printk ) | ||
704 | */ | ||
705 | p = (char *)&buf[sizeof(struct msgtrace_hdr)]; | ||
706 | while ((s = strstr(p, "\n")) != NULL) { | ||
707 | *s = '\0'; | ||
708 | printk(KERN_DEBUG"%s\n", p); | ||
709 | p = s + 1; | ||
710 | } | ||
711 | printk(KERN_DEBUG "%s\n", p); | ||
712 | |||
713 | /* Reset datalen to avoid display below */ | ||
714 | datalen = 0; | ||
715 | } | ||
716 | break; | ||
717 | |||
718 | case BRCMF_E_RSSI: | ||
719 | BRCMF_EVENT(("MACEVENT: %s %d\n", event_name, | ||
720 | be32_to_cpu(*((int *)event_data)))); | ||
721 | break; | ||
722 | |||
723 | default: | ||
724 | BRCMF_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, " | ||
725 | "auth %d\n", event_name, event_type, eabuf, | ||
726 | (int)status, (int)reason, (int)auth_type)); | ||
727 | break; | ||
728 | } | ||
729 | |||
730 | /* show any appended data */ | ||
731 | if (datalen) { | ||
732 | buf = (unsigned char *) event_data; | ||
733 | BRCMF_EVENT((" data (%d) : ", datalen)); | ||
734 | for (i = 0; i < datalen; i++) | ||
735 | BRCMF_EVENT((" 0x%02x ", *buf++)); | ||
736 | BRCMF_EVENT(("\n")); | ||
737 | } | ||
738 | } | ||
739 | #endif /* SHOW_EVENTS */ | ||
740 | |||
741 | int | ||
742 | brcmf_c_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata, | ||
743 | struct brcmf_event_msg *event, void **data_ptr) | ||
744 | { | ||
745 | /* check whether packet is a BRCM event pkt */ | ||
746 | struct brcmf_event *pvt_data = (struct brcmf_event *) pktdata; | ||
747 | char *event_data; | ||
748 | u32 type, status; | ||
749 | u16 flags; | ||
750 | int evlen; | ||
751 | |||
752 | if (memcmp(BRCM_OUI, &pvt_data->hdr.oui[0], DOT11_OUI_LEN)) { | ||
753 | BRCMF_ERROR(("%s: mismatched OUI, bailing\n", __func__)); | ||
754 | return -EBADE; | ||
755 | } | ||
756 | |||
757 | /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */ | ||
758 | if (get_unaligned_be16(&pvt_data->hdr.usr_subtype) != | ||
759 | BCMILCP_BCM_SUBTYPE_EVENT) { | ||
760 | BRCMF_ERROR(("%s: mismatched subtype, bailing\n", __func__)); | ||
761 | return -EBADE; | ||
762 | } | ||
763 | |||
764 | *data_ptr = &pvt_data[1]; | ||
765 | event_data = *data_ptr; | ||
766 | |||
767 | /* memcpy since BRCM event pkt may be unaligned. */ | ||
768 | memcpy(event, &pvt_data->msg, sizeof(struct brcmf_event_msg)); | ||
769 | |||
770 | type = get_unaligned_be32(&event->event_type); | ||
771 | flags = get_unaligned_be16(&event->flags); | ||
772 | status = get_unaligned_be32(&event->status); | ||
773 | evlen = get_unaligned_be32(&event->datalen) + | ||
774 | sizeof(struct brcmf_event); | ||
775 | |||
776 | switch (type) { | ||
777 | case BRCMF_E_IF: | ||
778 | { | ||
779 | struct brcmf_if_event *ifevent = | ||
780 | (struct brcmf_if_event *) event_data; | ||
781 | BRCMF_TRACE(("%s: if event\n", __func__)); | ||
782 | |||
783 | if (ifevent->ifidx > 0 && | ||
784 | ifevent->ifidx < BRCMF_MAX_IFS) { | ||
785 | if (ifevent->action == BRCMF_E_IF_ADD) | ||
786 | brcmf_add_if(drvr_priv, ifevent->ifidx, | ||
787 | NULL, event->ifname, | ||
788 | pvt_data->eth.h_dest, | ||
789 | ifevent->flags, | ||
790 | ifevent->bssidx); | ||
791 | else | ||
792 | brcmf_del_if(drvr_priv, ifevent->ifidx); | ||
793 | } else { | ||
794 | BRCMF_ERROR(("%s: Invalid ifidx %d for %s\n", | ||
795 | __func__, ifevent->ifidx, | ||
796 | event->ifname)); | ||
797 | } | ||
798 | } | ||
799 | /* send up the if event: btamp user needs it */ | ||
800 | *ifidx = brcmf_ifname2idx(drvr_priv, event->ifname); | ||
801 | break; | ||
802 | |||
803 | /* These are what external supplicant/authenticator wants */ | ||
804 | case BRCMF_E_LINK: | ||
805 | case BRCMF_E_ASSOC_IND: | ||
806 | case BRCMF_E_REASSOC_IND: | ||
807 | case BRCMF_E_DISASSOC_IND: | ||
808 | case BRCMF_E_MIC_ERROR: | ||
809 | default: | ||
810 | /* Fall through: this should get _everything_ */ | ||
811 | |||
812 | *ifidx = brcmf_ifname2idx(drvr_priv, event->ifname); | ||
813 | BRCMF_TRACE(("%s: MAC event %d, flags %x, status %x\n", | ||
814 | __func__, type, flags, status)); | ||
815 | |||
816 | /* put it back to BRCMF_E_NDIS_LINK */ | ||
817 | if (type == BRCMF_E_NDIS_LINK) { | ||
818 | u32 temp; | ||
819 | |||
820 | temp = get_unaligned_be32(&event->event_type); | ||
821 | BRCMF_TRACE(("Converted to WLC_E_LINK type %d\n", | ||
822 | temp)); | ||
823 | |||
824 | temp = be32_to_cpu(BRCMF_E_NDIS_LINK); | ||
825 | memcpy((void *)(&pvt_data->msg.event_type), &temp, | ||
826 | sizeof(pvt_data->msg.event_type)); | ||
827 | } | ||
828 | break; | ||
829 | } | ||
830 | |||
831 | #ifdef SHOW_EVENTS | ||
832 | brcmf_c_show_host_event(event, event_data); | ||
833 | #endif /* SHOW_EVENTS */ | ||
834 | |||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | /* Convert user's input in hex pattern to byte-size mask */ | ||
839 | static int brcmf_c_pattern_atoh(char *src, char *dst) | ||
840 | { | ||
841 | int i; | ||
842 | if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) { | ||
843 | BRCMF_ERROR(("Mask invalid format. Needs to start with 0x\n")); | ||
844 | return -1; | ||
845 | } | ||
846 | src = src + 2; /* Skip past 0x */ | ||
847 | if (strlen(src) % 2 != 0) { | ||
848 | BRCMF_ERROR(("Mask invalid format. Length must be even.\n")); | ||
849 | return -1; | ||
850 | } | ||
851 | for (i = 0; *src != '\0'; i++) { | ||
852 | char num[3]; | ||
853 | strncpy(num, src, 2); | ||
854 | num[2] = '\0'; | ||
855 | dst[i] = (u8) simple_strtoul(num, NULL, 16); | ||
856 | src += 2; | ||
857 | } | ||
858 | return i; | ||
859 | } | ||
860 | |||
861 | void | ||
862 | brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, int enable, | ||
863 | int master_mode) | ||
864 | { | ||
865 | char *argv[8]; | ||
866 | int i = 0; | ||
867 | const char *str; | ||
868 | int buf_len; | ||
869 | int str_len; | ||
870 | char *arg_save = 0, *arg_org = 0; | ||
871 | int rc; | ||
872 | char buf[128]; | ||
873 | struct brcmf_pkt_filter_enable enable_parm; | ||
874 | struct brcmf_pkt_filter_enable *pkt_filterp; | ||
875 | |||
876 | arg_save = kmalloc(strlen(arg) + 1, GFP_ATOMIC); | ||
877 | if (!arg_save) { | ||
878 | BRCMF_ERROR(("%s: kmalloc failed\n", __func__)); | ||
879 | goto fail; | ||
880 | } | ||
881 | arg_org = arg_save; | ||
882 | memcpy(arg_save, arg, strlen(arg) + 1); | ||
883 | |||
884 | argv[i] = strsep(&arg_save, " "); | ||
885 | |||
886 | i = 0; | ||
887 | if (NULL == argv[i]) { | ||
888 | BRCMF_ERROR(("No args provided\n")); | ||
889 | goto fail; | ||
890 | } | ||
891 | |||
892 | str = "pkt_filter_enable"; | ||
893 | str_len = strlen(str); | ||
894 | strncpy(buf, str, str_len); | ||
895 | buf[str_len] = '\0'; | ||
896 | buf_len = str_len + 1; | ||
897 | |||
898 | pkt_filterp = (struct brcmf_pkt_filter_enable *) (buf + str_len + 1); | ||
899 | |||
900 | /* Parse packet filter id. */ | ||
901 | enable_parm.id = simple_strtoul(argv[i], NULL, 0); | ||
902 | |||
903 | /* Parse enable/disable value. */ | ||
904 | enable_parm.enable = enable; | ||
905 | |||
906 | buf_len += sizeof(enable_parm); | ||
907 | memcpy((char *)pkt_filterp, &enable_parm, sizeof(enable_parm)); | ||
908 | |||
909 | /* Enable/disable the specified filter. */ | ||
910 | rc = brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len); | ||
911 | rc = rc >= 0 ? 0 : rc; | ||
912 | if (rc) | ||
913 | BRCMF_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", | ||
914 | __func__, arg, rc)); | ||
915 | else | ||
916 | BRCMF_TRACE(("%s: successfully added pktfilter %s\n", | ||
917 | __func__, arg)); | ||
918 | |||
919 | /* Contorl the master mode */ | ||
920 | brcmu_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, | ||
921 | sizeof(buf)); | ||
922 | rc = brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, buf, | ||
923 | sizeof(buf)); | ||
924 | rc = rc >= 0 ? 0 : rc; | ||
925 | if (rc) | ||
926 | BRCMF_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", | ||
927 | __func__, arg, rc)); | ||
928 | |||
929 | fail: | ||
930 | kfree(arg_org); | ||
931 | } | ||
932 | |||
933 | void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg) | ||
934 | { | ||
935 | const char *str; | ||
936 | struct brcmf_pkt_filter pkt_filter; | ||
937 | struct brcmf_pkt_filter *pkt_filterp; | ||
938 | int buf_len; | ||
939 | int str_len; | ||
940 | int rc; | ||
941 | u32 mask_size; | ||
942 | u32 pattern_size; | ||
943 | char *argv[8], *buf = 0; | ||
944 | int i = 0; | ||
945 | char *arg_save = 0, *arg_org = 0; | ||
946 | |||
947 | arg_save = kmalloc(strlen(arg) + 1, GFP_ATOMIC); | ||
948 | if (!arg_save) { | ||
949 | BRCMF_ERROR(("%s: kmalloc failed\n", __func__)); | ||
950 | goto fail; | ||
951 | } | ||
952 | |||
953 | arg_org = arg_save; | ||
954 | |||
955 | buf = kmalloc(PKTFILTER_BUF_SIZE, GFP_ATOMIC); | ||
956 | if (!buf) { | ||
957 | BRCMF_ERROR(("%s: kmalloc failed\n", __func__)); | ||
958 | goto fail; | ||
959 | } | ||
960 | |||
961 | strcpy(arg_save, arg); | ||
962 | |||
963 | argv[i] = strsep(&arg_save, " "); | ||
964 | while (argv[i++]) | ||
965 | argv[i] = strsep(&arg_save, " "); | ||
966 | |||
967 | i = 0; | ||
968 | if (NULL == argv[i]) { | ||
969 | BRCMF_ERROR(("No args provided\n")); | ||
970 | goto fail; | ||
971 | } | ||
972 | |||
973 | str = "pkt_filter_add"; | ||
974 | strcpy(buf, str); | ||
975 | str_len = strlen(str); | ||
976 | buf_len = str_len + 1; | ||
977 | |||
978 | pkt_filterp = (struct brcmf_pkt_filter *) (buf + str_len + 1); | ||
979 | |||
980 | /* Parse packet filter id. */ | ||
981 | pkt_filter.id = simple_strtoul(argv[i], NULL, 0); | ||
982 | |||
983 | if (NULL == argv[++i]) { | ||
984 | BRCMF_ERROR(("Polarity not provided\n")); | ||
985 | goto fail; | ||
986 | } | ||
987 | |||
988 | /* Parse filter polarity. */ | ||
989 | pkt_filter.negate_match = simple_strtoul(argv[i], NULL, 0); | ||
990 | |||
991 | if (NULL == argv[++i]) { | ||
992 | BRCMF_ERROR(("Filter type not provided\n")); | ||
993 | goto fail; | ||
994 | } | ||
995 | |||
996 | /* Parse filter type. */ | ||
997 | pkt_filter.type = simple_strtoul(argv[i], NULL, 0); | ||
998 | |||
999 | if (NULL == argv[++i]) { | ||
1000 | BRCMF_ERROR(("Offset not provided\n")); | ||
1001 | goto fail; | ||
1002 | } | ||
1003 | |||
1004 | /* Parse pattern filter offset. */ | ||
1005 | pkt_filter.u.pattern.offset = simple_strtoul(argv[i], NULL, 0); | ||
1006 | |||
1007 | if (NULL == argv[++i]) { | ||
1008 | BRCMF_ERROR(("Bitmask not provided\n")); | ||
1009 | goto fail; | ||
1010 | } | ||
1011 | |||
1012 | /* Parse pattern filter mask. */ | ||
1013 | mask_size = | ||
1014 | brcmf_c_pattern_atoh | ||
1015 | (argv[i], (char *)pkt_filterp->u.pattern.mask_and_pattern); | ||
1016 | |||
1017 | if (NULL == argv[++i]) { | ||
1018 | BRCMF_ERROR(("Pattern not provided\n")); | ||
1019 | goto fail; | ||
1020 | } | ||
1021 | |||
1022 | /* Parse pattern filter pattern. */ | ||
1023 | pattern_size = | ||
1024 | brcmf_c_pattern_atoh(argv[i], | ||
1025 | (char *)&pkt_filterp->u.pattern. | ||
1026 | mask_and_pattern[mask_size]); | ||
1027 | |||
1028 | if (mask_size != pattern_size) { | ||
1029 | BRCMF_ERROR(("Mask and pattern not the same size\n")); | ||
1030 | goto fail; | ||
1031 | } | ||
1032 | |||
1033 | pkt_filter.u.pattern.size_bytes = mask_size; | ||
1034 | buf_len += BRCMF_PKT_FILTER_FIXED_LEN; | ||
1035 | buf_len += (BRCMF_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); | ||
1036 | |||
1037 | /* Keep-alive attributes are set in local | ||
1038 | * variable (keep_alive_pkt), and | ||
1039 | ** then memcpy'ed into buffer (keep_alive_pktp) since there is no | ||
1040 | ** guarantee that the buffer is properly aligned. | ||
1041 | */ | ||
1042 | memcpy((char *)pkt_filterp, | ||
1043 | &pkt_filter, | ||
1044 | BRCMF_PKT_FILTER_FIXED_LEN + BRCMF_PKT_FILTER_PATTERN_FIXED_LEN); | ||
1045 | |||
1046 | rc = brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len); | ||
1047 | rc = rc >= 0 ? 0 : rc; | ||
1048 | |||
1049 | if (rc) | ||
1050 | BRCMF_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", | ||
1051 | __func__, arg, rc)); | ||
1052 | else | ||
1053 | BRCMF_TRACE(("%s: successfully added pktfilter %s\n", | ||
1054 | __func__, arg)); | ||
1055 | |||
1056 | fail: | ||
1057 | kfree(arg_org); | ||
1058 | |||
1059 | kfree(buf); | ||
1060 | } | ||
1061 | |||
1062 | void brcmf_c_arp_offload_set(struct brcmf_pub *drvr, int arp_mode) | ||
1063 | { | ||
1064 | char iovbuf[32]; | ||
1065 | int retcode; | ||
1066 | |||
1067 | brcmu_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf)); | ||
1068 | retcode = brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, | ||
1069 | iovbuf, sizeof(iovbuf)); | ||
1070 | retcode = retcode >= 0 ? 0 : retcode; | ||
1071 | if (retcode) | ||
1072 | BRCMF_TRACE(("%s: failed to set ARP offload mode to 0x%x, " | ||
1073 | "retcode = %d\n", __func__, arp_mode, retcode)); | ||
1074 | else | ||
1075 | BRCMF_TRACE(("%s: successfully set ARP offload mode to 0x%x\n", | ||
1076 | __func__, arp_mode)); | ||
1077 | } | ||
1078 | |||
1079 | void brcmf_c_arp_offload_enable(struct brcmf_pub *drvr, int arp_enable) | ||
1080 | { | ||
1081 | char iovbuf[32]; | ||
1082 | int retcode; | ||
1083 | |||
1084 | brcmu_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf)); | ||
1085 | retcode = brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, | ||
1086 | iovbuf, sizeof(iovbuf)); | ||
1087 | retcode = retcode >= 0 ? 0 : retcode; | ||
1088 | if (retcode) | ||
1089 | BRCMF_TRACE(("%s: failed to enabe ARP offload to %d, " | ||
1090 | "retcode = %d\n", __func__, arp_enable, retcode)); | ||
1091 | else | ||
1092 | BRCMF_TRACE(("%s: successfully enabed ARP offload to %d\n", | ||
1093 | __func__, arp_enable)); | ||
1094 | } | ||
1095 | |||
1096 | int brcmf_c_preinit_ioctls(struct brcmf_pub *drvr) | ||
1097 | { | ||
1098 | char iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; /* Room for | ||
1099 | "event_msgs" + '\0' + bitvec */ | ||
1100 | uint up = 0; | ||
1101 | char buf[128], *ptr; | ||
1102 | uint power_mode = PM_FAST; | ||
1103 | u32 dongle_align = BRCMF_SDALIGN; | ||
1104 | u32 glom = 0; | ||
1105 | uint bcn_timeout = 3; | ||
1106 | int scan_assoc_time = 40; | ||
1107 | int scan_unassoc_time = 40; | ||
1108 | int i; | ||
1109 | |||
1110 | brcmf_os_proto_block(drvr); | ||
1111 | |||
1112 | /* Set Country code */ | ||
1113 | if (drvr->country_code[0] != 0) { | ||
1114 | if (brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_COUNTRY, | ||
1115 | drvr->country_code, | ||
1116 | sizeof(drvr->country_code)) < 0) { | ||
1117 | BRCMF_ERROR(("%s: country code setting failed\n", | ||
1118 | __func__)); | ||
1119 | } | ||
1120 | } | ||
1121 | |||
1122 | /* query for 'ver' to get version info from firmware */ | ||
1123 | memset(buf, 0, sizeof(buf)); | ||
1124 | ptr = buf; | ||
1125 | brcmu_mkiovar("ver", 0, 0, buf, sizeof(buf)); | ||
1126 | brcmf_proto_cdc_query_ioctl(drvr, 0, BRCMF_C_GET_VAR, buf, sizeof(buf)); | ||
1127 | strsep(&ptr, "\n"); | ||
1128 | /* Print fw version info */ | ||
1129 | BRCMF_ERROR(("Firmware version = %s\n", buf)); | ||
1130 | |||
1131 | /* Set PowerSave mode */ | ||
1132 | brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_PM, (char *)&power_mode, | ||
1133 | sizeof(power_mode)); | ||
1134 | |||
1135 | /* Match Host and Dongle rx alignment */ | ||
1136 | brcmu_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, | ||
1137 | sizeof(iovbuf)); | ||
1138 | brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, iovbuf, | ||
1139 | sizeof(iovbuf)); | ||
1140 | |||
1141 | /* disable glom option per default */ | ||
1142 | brcmu_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); | ||
1143 | brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, iovbuf, | ||
1144 | sizeof(iovbuf)); | ||
1145 | |||
1146 | /* Setup timeout if Beacons are lost and roam is off to report | ||
1147 | link down */ | ||
1148 | brcmu_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, | ||
1149 | sizeof(iovbuf)); | ||
1150 | brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, iovbuf, | ||
1151 | sizeof(iovbuf)); | ||
1152 | |||
1153 | /* Enable/Disable build-in roaming to allowed ext supplicant to take | ||
1154 | of romaing */ | ||
1155 | brcmu_mkiovar("roam_off", (char *)&brcmf_roam, 4, | ||
1156 | iovbuf, sizeof(iovbuf)); | ||
1157 | brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, iovbuf, | ||
1158 | sizeof(iovbuf)); | ||
1159 | |||
1160 | /* Force STA UP */ | ||
1161 | if (brcmf_radio_up) | ||
1162 | brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_UP, (char *)&up, | ||
1163 | sizeof(up)); | ||
1164 | |||
1165 | /* Setup event_msgs */ | ||
1166 | brcmu_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN, | ||
1167 | iovbuf, sizeof(iovbuf)); | ||
1168 | brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, iovbuf, | ||
1169 | sizeof(iovbuf)); | ||
1170 | |||
1171 | brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_SCAN_CHANNEL_TIME, | ||
1172 | (char *)&scan_assoc_time, sizeof(scan_assoc_time)); | ||
1173 | brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_SCAN_UNASSOC_TIME, | ||
1174 | (char *)&scan_unassoc_time, sizeof(scan_unassoc_time)); | ||
1175 | |||
1176 | /* Set and enable ARP offload feature */ | ||
1177 | if (brcmf_arp_enable) | ||
1178 | brcmf_c_arp_offload_set(drvr, brcmf_arp_mode); | ||
1179 | brcmf_c_arp_offload_enable(drvr, brcmf_arp_enable); | ||
1180 | |||
1181 | /* Set up pkt filter */ | ||
1182 | if (brcmf_pkt_filter_enable) { | ||
1183 | for (i = 0; i < drvr->pktfilter_count; i++) { | ||
1184 | brcmf_c_pktfilter_offload_set(drvr, | ||
1185 | drvr->pktfilter[i]); | ||
1186 | brcmf_c_pktfilter_offload_enable(drvr, | ||
1187 | drvr->pktfilter[i], | ||
1188 | brcmf_pkt_filter_init, | ||
1189 | brcmf_master_mode); | ||
1190 | } | ||
1191 | } | ||
1192 | |||
1193 | brcmf_os_proto_unblock(drvr); | ||
1194 | |||
1195 | return 0; | ||
1196 | } | ||
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_dbg.h b/drivers/staging/brcm80211/brcmfmac/dhd_dbg.h new file mode 100644 index 00000000000..5be4d7a609c --- /dev/null +++ b/drivers/staging/brcm80211/brcmfmac/dhd_dbg.h | |||
@@ -0,0 +1,70 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #ifndef _BRCMF_DBG_H_ | ||
18 | #define _BRCMF_DBG_H_ | ||
19 | |||
20 | #if defined(BCMDBG) | ||
21 | |||
22 | #define BRCMF_ERROR(args) \ | ||
23 | do {if ((brcmf_msg_level & BRCMF_ERROR_VAL) && (net_ratelimit())) \ | ||
24 | printk args; } while (0) | ||
25 | #define BRCMF_TRACE(args) do {if (brcmf_msg_level & BRCMF_TRACE_VAL) \ | ||
26 | printk args; } while (0) | ||
27 | #define BRCMF_INFO(args) do {if (brcmf_msg_level & BRCMF_INFO_VAL) \ | ||
28 | printk args; } while (0) | ||
29 | #define BRCMF_DATA(args) do {if (brcmf_msg_level & BRCMF_DATA_VAL) \ | ||
30 | printk args; } while (0) | ||
31 | #define BRCMF_CTL(args) do {if (brcmf_msg_level & BRCMF_CTL_VAL) \ | ||
32 | printk args; } while (0) | ||
33 | #define BRCMF_TIMER(args) do {if (brcmf_msg_level & BRCMF_TIMER_VAL) \ | ||
34 | printk args; } while (0) | ||
35 | #define BRCMF_INTR(args) do {if (brcmf_msg_level & BRCMF_INTR_VAL) \ | ||
36 | printk args; } while (0) | ||
37 | #define BRCMF_GLOM(args) do {if (brcmf_msg_level & BRCMF_GLOM_VAL) \ | ||
38 | printk args; } while (0) | ||
39 | #define BRCMF_EVENT(args) do {if (brcmf_msg_level & BRCMF_EVENT_VAL) \ | ||
40 | printk args; } while (0) | ||
41 | |||
42 | #define BRCMF_DATA_ON() (brcmf_msg_level & BRCMF_DATA_VAL) | ||
43 | #define BRCMF_CTL_ON() (brcmf_msg_level & BRCMF_CTL_VAL) | ||
44 | #define BRCMF_HDRS_ON() (brcmf_msg_level & BRCMF_HDRS_VAL) | ||
45 | #define BRCMF_BYTES_ON() (brcmf_msg_level & BRCMF_BYTES_VAL) | ||
46 | #define BRCMF_GLOM_ON() (brcmf_msg_level & BRCMF_GLOM_VAL) | ||
47 | |||
48 | #else /* (defined BCMDBG) || (defined BCMDBG) */ | ||
49 | |||
50 | #define BRCMF_ERROR(args) do {if (net_ratelimit()) printk args; } while (0) | ||
51 | #define BRCMF_TRACE(args) | ||
52 | #define BRCMF_INFO(args) | ||
53 | #define BRCMF_DATA(args) | ||
54 | #define BRCMF_CTL(args) | ||
55 | #define BRCMF_TIMER(args) | ||
56 | #define BRCMF_INTR(args) | ||
57 | #define BRCMF_GLOM(args) | ||
58 | #define BRCMF_EVENT(args) | ||
59 | |||
60 | #define BRCMF_DATA_ON() 0 | ||
61 | #define BRCMF_CTL_ON() 0 | ||
62 | #define BRCMF_HDRS_ON() 0 | ||
63 | #define BRCMF_BYTES_ON() 0 | ||
64 | #define BRCMF_GLOM_ON() 0 | ||
65 | |||
66 | #endif /* defined(BCMDBG) */ | ||
67 | |||
68 | extern int brcmf_msg_level; | ||
69 | |||
70 | #endif /* _BRCMF_DBG_H_ */ | ||
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c new file mode 100644 index 00000000000..05dada98eb6 --- /dev/null +++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c | |||
@@ -0,0 +1,1736 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/kthread.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/skbuff.h> | ||
22 | #include <linux/netdevice.h> | ||
23 | #include <linux/etherdevice.h> | ||
24 | #include <linux/mmc/sdio_func.h> | ||
25 | #include <linux/random.h> | ||
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/ethtool.h> | ||
28 | #include <linux/fcntl.h> | ||
29 | #include <linux/fs.h> | ||
30 | #include <linux/uaccess.h> | ||
31 | #include <linux/interrupt.h> | ||
32 | #include <linux/hardirq.h> | ||
33 | #include <net/cfg80211.h> | ||
34 | #include <defs.h> | ||
35 | #include <brcmu_utils.h> | ||
36 | #include <brcmu_wifi.h> | ||
37 | |||
38 | #include "dhd.h" | ||
39 | #include "dhd_bus.h" | ||
40 | #include "dhd_proto.h" | ||
41 | #include "dhd_dbg.h" | ||
42 | #include "wl_cfg80211.h" | ||
43 | #include "bcmchip.h" | ||
44 | |||
45 | #if defined(CONFIG_PM_SLEEP) | ||
46 | #include <linux/suspend.h> | ||
47 | atomic_t brcmf_mmc_suspend; | ||
48 | #endif /* defined(CONFIG_PM_SLEEP) */ | ||
49 | |||
50 | MODULE_AUTHOR("Broadcom Corporation"); | ||
51 | MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver."); | ||
52 | MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac cards"); | ||
53 | MODULE_LICENSE("Dual BSD/GPL"); | ||
54 | |||
55 | |||
56 | /* Interface control information */ | ||
57 | struct brcmf_if { | ||
58 | struct brcmf_info *info; /* back pointer to brcmf_info */ | ||
59 | /* OS/stack specifics */ | ||
60 | struct net_device *net; | ||
61 | struct net_device_stats stats; | ||
62 | int idx; /* iface idx in dongle */ | ||
63 | int state; /* interface state */ | ||
64 | uint subunit; /* subunit */ | ||
65 | u8 mac_addr[ETH_ALEN]; /* assigned MAC address */ | ||
66 | bool attached; /* Delayed attachment when unset */ | ||
67 | bool txflowcontrol; /* Per interface flow control indicator */ | ||
68 | char name[IFNAMSIZ]; /* linux interface name */ | ||
69 | }; | ||
70 | |||
71 | /* Local private structure (extension of pub) */ | ||
72 | struct brcmf_info { | ||
73 | struct brcmf_pub pub; | ||
74 | |||
75 | /* OS/stack specifics */ | ||
76 | struct brcmf_if *iflist[BRCMF_MAX_IFS]; | ||
77 | |||
78 | struct semaphore proto_sem; | ||
79 | wait_queue_head_t ioctl_resp_wait; | ||
80 | |||
81 | /* Thread to issue ioctl for multicast */ | ||
82 | struct task_struct *sysioc_tsk; | ||
83 | struct semaphore sysioc_sem; | ||
84 | bool set_multicast; | ||
85 | bool set_macaddress; | ||
86 | u8 macvalue[ETH_ALEN]; | ||
87 | atomic_t pend_8021x_cnt; | ||
88 | }; | ||
89 | |||
90 | /* Error bits */ | ||
91 | module_param(brcmf_msg_level, int, 0); | ||
92 | |||
93 | /* Spawn a thread for system ioctls (set mac, set mcast) */ | ||
94 | uint brcmf_sysioc = true; | ||
95 | module_param(brcmf_sysioc, uint, 0); | ||
96 | |||
97 | /* ARP offload agent mode : Enable ARP Host Auto-Reply | ||
98 | and ARP Peer Auto-Reply */ | ||
99 | uint brcmf_arp_mode = 0xb; | ||
100 | module_param(brcmf_arp_mode, uint, 0); | ||
101 | |||
102 | /* ARP offload enable */ | ||
103 | uint brcmf_arp_enable = true; | ||
104 | module_param(brcmf_arp_enable, uint, 0); | ||
105 | |||
106 | /* Global Pkt filter enable control */ | ||
107 | uint brcmf_pkt_filter_enable = true; | ||
108 | module_param(brcmf_pkt_filter_enable, uint, 0); | ||
109 | |||
110 | /* Pkt filter init setup */ | ||
111 | uint brcmf_pkt_filter_init; | ||
112 | module_param(brcmf_pkt_filter_init, uint, 0); | ||
113 | |||
114 | /* Pkt filter mode control */ | ||
115 | uint brcmf_master_mode = true; | ||
116 | module_param(brcmf_master_mode, uint, 0); | ||
117 | |||
118 | module_param(brcmf_dongle_memsize, int, 0); | ||
119 | |||
120 | /* Contorl fw roaming */ | ||
121 | uint brcmf_roam = 1; | ||
122 | |||
123 | /* Control radio state */ | ||
124 | uint brcmf_radio_up = 1; | ||
125 | |||
126 | /* Network inteface name */ | ||
127 | char iface_name[IFNAMSIZ] = "wlan"; | ||
128 | module_param_string(iface_name, iface_name, IFNAMSIZ, 0); | ||
129 | |||
130 | /* The following are specific to the SDIO dongle */ | ||
131 | |||
132 | /* IOCTL response timeout */ | ||
133 | int brcmf_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT; | ||
134 | |||
135 | /* Idle timeout for backplane clock */ | ||
136 | int brcmf_idletime = BRCMF_IDLETIME_TICKS; | ||
137 | module_param(brcmf_idletime, int, 0); | ||
138 | |||
139 | /* Use polling */ | ||
140 | uint brcmf_poll; | ||
141 | module_param(brcmf_poll, uint, 0); | ||
142 | |||
143 | /* Use interrupts */ | ||
144 | uint brcmf_intr = true; | ||
145 | module_param(brcmf_intr, uint, 0); | ||
146 | |||
147 | /* SDIO Drive Strength (in milliamps) */ | ||
148 | uint brcmf_sdiod_drive_strength = 6; | ||
149 | module_param(brcmf_sdiod_drive_strength, uint, 0); | ||
150 | |||
151 | /* Tx/Rx bounds */ | ||
152 | module_param(brcmf_txbound, uint, 0); | ||
153 | module_param(brcmf_rxbound, uint, 0); | ||
154 | |||
155 | #ifdef SDTEST | ||
156 | /* Echo packet generator (pkts/s) */ | ||
157 | uint brcmf_pktgen; | ||
158 | module_param(brcmf_pktgen, uint, 0); | ||
159 | |||
160 | /* Echo packet len (0 => sawtooth, max 2040) */ | ||
161 | uint brcmf_pktgen_len; | ||
162 | module_param(brcmf_pktgen_len, uint, 0); | ||
163 | #endif | ||
164 | |||
165 | static int brcmf_toe_get(struct brcmf_info *drvr_priv, int idx, u32 *toe_ol); | ||
166 | static int brcmf_toe_set(struct brcmf_info *drvr_priv, int idx, u32 toe_ol); | ||
167 | static int brcmf_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata, | ||
168 | struct brcmf_event_msg *event_ptr, | ||
169 | void **data_ptr); | ||
170 | |||
171 | /* | ||
172 | * Generalized timeout mechanism. Uses spin sleep with exponential | ||
173 | * back-off until | ||
174 | * the sleep time reaches one jiffy, then switches over to task delay. Usage: | ||
175 | * | ||
176 | * brcmf_timeout_start(&tmo, usec); | ||
177 | * while (!brcmf_timeout_expired(&tmo)) | ||
178 | * if (poll_something()) | ||
179 | * break; | ||
180 | * if (brcmf_timeout_expired(&tmo)) | ||
181 | * fatal(); | ||
182 | */ | ||
183 | |||
184 | void brcmf_timeout_start(struct brcmf_timeout *tmo, uint usec) | ||
185 | { | ||
186 | tmo->limit = usec; | ||
187 | tmo->increment = 0; | ||
188 | tmo->elapsed = 0; | ||
189 | tmo->tick = 1000000 / HZ; | ||
190 | } | ||
191 | |||
192 | int brcmf_timeout_expired(struct brcmf_timeout *tmo) | ||
193 | { | ||
194 | /* Does nothing the first call */ | ||
195 | if (tmo->increment == 0) { | ||
196 | tmo->increment = 1; | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | if (tmo->elapsed >= tmo->limit) | ||
201 | return 1; | ||
202 | |||
203 | /* Add the delay that's about to take place */ | ||
204 | tmo->elapsed += tmo->increment; | ||
205 | |||
206 | if (tmo->increment < tmo->tick) { | ||
207 | udelay(tmo->increment); | ||
208 | tmo->increment *= 2; | ||
209 | if (tmo->increment > tmo->tick) | ||
210 | tmo->increment = tmo->tick; | ||
211 | } else { | ||
212 | wait_queue_head_t delay_wait; | ||
213 | DECLARE_WAITQUEUE(wait, current); | ||
214 | int pending; | ||
215 | init_waitqueue_head(&delay_wait); | ||
216 | add_wait_queue(&delay_wait, &wait); | ||
217 | set_current_state(TASK_INTERRUPTIBLE); | ||
218 | schedule_timeout(1); | ||
219 | pending = signal_pending(current); | ||
220 | remove_wait_queue(&delay_wait, &wait); | ||
221 | set_current_state(TASK_RUNNING); | ||
222 | if (pending) | ||
223 | return 1; /* Interrupted */ | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int brcmf_net2idx(struct brcmf_info *drvr_priv, struct net_device *net) | ||
230 | { | ||
231 | int i = 0; | ||
232 | |||
233 | while (i < BRCMF_MAX_IFS) { | ||
234 | if (drvr_priv->iflist[i] && (drvr_priv->iflist[i]->net == net)) | ||
235 | return i; | ||
236 | i++; | ||
237 | } | ||
238 | |||
239 | return BRCMF_BAD_IF; | ||
240 | } | ||
241 | |||
242 | int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name) | ||
243 | { | ||
244 | int i = BRCMF_MAX_IFS; | ||
245 | |||
246 | if (name == NULL || *name == '\0') | ||
247 | return 0; | ||
248 | |||
249 | while (--i > 0) | ||
250 | if (drvr_priv->iflist[i] | ||
251 | && !strncmp(drvr_priv->iflist[i]->name, name, IFNAMSIZ)) | ||
252 | break; | ||
253 | |||
254 | BRCMF_TRACE(("%s: return idx %d for \"%s\"\n", __func__, i, name)); | ||
255 | |||
256 | return i; /* default - the primary interface */ | ||
257 | } | ||
258 | |||
259 | char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx) | ||
260 | { | ||
261 | struct brcmf_info *drvr_priv = drvr->info; | ||
262 | |||
263 | if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) { | ||
264 | BRCMF_ERROR(("%s: ifidx %d out of range\n", __func__, ifidx)); | ||
265 | return "<if_bad>"; | ||
266 | } | ||
267 | |||
268 | if (drvr_priv->iflist[ifidx] == NULL) { | ||
269 | BRCMF_ERROR(("%s: null i/f %d\n", __func__, ifidx)); | ||
270 | return "<if_null>"; | ||
271 | } | ||
272 | |||
273 | if (drvr_priv->iflist[ifidx]->net) | ||
274 | return drvr_priv->iflist[ifidx]->net->name; | ||
275 | |||
276 | return "<if_none>"; | ||
277 | } | ||
278 | |||
279 | static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx) | ||
280 | { | ||
281 | struct net_device *dev; | ||
282 | struct netdev_hw_addr *ha; | ||
283 | u32 allmulti, cnt; | ||
284 | |||
285 | struct brcmf_ioctl ioc; | ||
286 | char *buf, *bufp; | ||
287 | uint buflen; | ||
288 | int ret; | ||
289 | |||
290 | dev = drvr_priv->iflist[ifidx]->net; | ||
291 | cnt = netdev_mc_count(dev); | ||
292 | |||
293 | /* Determine initial value of allmulti flag */ | ||
294 | allmulti = (dev->flags & IFF_ALLMULTI) ? true : false; | ||
295 | |||
296 | /* Send down the multicast list first. */ | ||
297 | |||
298 | buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETH_ALEN); | ||
299 | bufp = buf = kmalloc(buflen, GFP_ATOMIC); | ||
300 | if (!bufp) { | ||
301 | BRCMF_ERROR(("%s: out of memory for mcast_list, cnt %d\n", | ||
302 | brcmf_ifname(&drvr_priv->pub, ifidx), cnt)); | ||
303 | return; | ||
304 | } | ||
305 | |||
306 | strcpy(bufp, "mcast_list"); | ||
307 | bufp += strlen("mcast_list") + 1; | ||
308 | |||
309 | cnt = cpu_to_le32(cnt); | ||
310 | memcpy(bufp, &cnt, sizeof(cnt)); | ||
311 | bufp += sizeof(cnt); | ||
312 | |||
313 | netdev_for_each_mc_addr(ha, dev) { | ||
314 | if (!cnt) | ||
315 | break; | ||
316 | memcpy(bufp, ha->addr, ETH_ALEN); | ||
317 | bufp += ETH_ALEN; | ||
318 | cnt--; | ||
319 | } | ||
320 | |||
321 | memset(&ioc, 0, sizeof(ioc)); | ||
322 | ioc.cmd = BRCMF_C_SET_VAR; | ||
323 | ioc.buf = buf; | ||
324 | ioc.len = buflen; | ||
325 | ioc.set = true; | ||
326 | |||
327 | ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len); | ||
328 | if (ret < 0) { | ||
329 | BRCMF_ERROR(("%s: set mcast_list failed, cnt %d\n", | ||
330 | brcmf_ifname(&drvr_priv->pub, ifidx), cnt)); | ||
331 | allmulti = cnt ? true : allmulti; | ||
332 | } | ||
333 | |||
334 | kfree(buf); | ||
335 | |||
336 | /* Now send the allmulti setting. This is based on the setting in the | ||
337 | * net_device flags, but might be modified above to be turned on if we | ||
338 | * were trying to set some addresses and dongle rejected it... | ||
339 | */ | ||
340 | |||
341 | buflen = sizeof("allmulti") + sizeof(allmulti); | ||
342 | buf = kmalloc(buflen, GFP_ATOMIC); | ||
343 | if (!buf) { | ||
344 | BRCMF_ERROR(("%s: out of memory for allmulti\n", | ||
345 | brcmf_ifname(&drvr_priv->pub, ifidx))); | ||
346 | return; | ||
347 | } | ||
348 | allmulti = cpu_to_le32(allmulti); | ||
349 | |||
350 | if (!brcmu_mkiovar | ||
351 | ("allmulti", (void *)&allmulti, sizeof(allmulti), buf, buflen)) { | ||
352 | BRCMF_ERROR(("%s: mkiovar failed for allmulti, datalen %d " | ||
353 | "buflen %u\n", | ||
354 | brcmf_ifname(&drvr_priv->pub, ifidx), | ||
355 | (int)sizeof(allmulti), buflen)); | ||
356 | kfree(buf); | ||
357 | return; | ||
358 | } | ||
359 | |||
360 | memset(&ioc, 0, sizeof(ioc)); | ||
361 | ioc.cmd = BRCMF_C_SET_VAR; | ||
362 | ioc.buf = buf; | ||
363 | ioc.len = buflen; | ||
364 | ioc.set = true; | ||
365 | |||
366 | ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len); | ||
367 | if (ret < 0) { | ||
368 | BRCMF_ERROR(("%s: set allmulti %d failed\n", | ||
369 | brcmf_ifname(&drvr_priv->pub, ifidx), | ||
370 | le32_to_cpu(allmulti))); | ||
371 | } | ||
372 | |||
373 | kfree(buf); | ||
374 | |||
375 | /* Finally, pick up the PROMISC flag as well, like the NIC | ||
376 | driver does */ | ||
377 | |||
378 | allmulti = (dev->flags & IFF_PROMISC) ? true : false; | ||
379 | allmulti = cpu_to_le32(allmulti); | ||
380 | |||
381 | memset(&ioc, 0, sizeof(ioc)); | ||
382 | ioc.cmd = BRCMF_C_SET_PROMISC; | ||
383 | ioc.buf = &allmulti; | ||
384 | ioc.len = sizeof(allmulti); | ||
385 | ioc.set = true; | ||
386 | |||
387 | ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len); | ||
388 | if (ret < 0) { | ||
389 | BRCMF_ERROR(("%s: set promisc %d failed\n", | ||
390 | brcmf_ifname(&drvr_priv->pub, ifidx), | ||
391 | le32_to_cpu(allmulti))); | ||
392 | } | ||
393 | } | ||
394 | |||
395 | static int _brcmf_set_mac_address(struct brcmf_info *drvr_priv, int ifidx, u8 *addr) | ||
396 | { | ||
397 | char buf[32]; | ||
398 | struct brcmf_ioctl ioc; | ||
399 | int ret; | ||
400 | |||
401 | BRCMF_TRACE(("%s enter\n", __func__)); | ||
402 | if (!brcmu_mkiovar | ||
403 | ("cur_etheraddr", (char *)addr, ETH_ALEN, buf, 32)) { | ||
404 | BRCMF_ERROR(("%s: mkiovar failed for cur_etheraddr\n", | ||
405 | brcmf_ifname(&drvr_priv->pub, ifidx))); | ||
406 | return -1; | ||
407 | } | ||
408 | memset(&ioc, 0, sizeof(ioc)); | ||
409 | ioc.cmd = BRCMF_C_SET_VAR; | ||
410 | ioc.buf = buf; | ||
411 | ioc.len = 32; | ||
412 | ioc.set = true; | ||
413 | |||
414 | ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len); | ||
415 | if (ret < 0) { | ||
416 | BRCMF_ERROR(("%s: set cur_etheraddr failed\n", | ||
417 | brcmf_ifname(&drvr_priv->pub, ifidx))); | ||
418 | } else { | ||
419 | memcpy(drvr_priv->iflist[ifidx]->net->dev_addr, addr, ETH_ALEN); | ||
420 | } | ||
421 | |||
422 | return ret; | ||
423 | } | ||
424 | |||
425 | #ifdef SOFTAP | ||
426 | extern struct net_device *ap_net_dev; | ||
427 | #endif | ||
428 | |||
429 | /* Virtual interfaces only ((ifp && ifp->info && ifp->idx == true) */ | ||
430 | static void brcmf_op_if(struct brcmf_if *ifp) | ||
431 | { | ||
432 | struct brcmf_info *drvr_priv; | ||
433 | int ret = 0, err = 0; | ||
434 | |||
435 | drvr_priv = ifp->info; | ||
436 | |||
437 | BRCMF_TRACE(("%s: idx %d, state %d\n", __func__, ifp->idx, ifp->state)); | ||
438 | |||
439 | switch (ifp->state) { | ||
440 | case BRCMF_E_IF_ADD: | ||
441 | /* | ||
442 | * Delete the existing interface before overwriting it | ||
443 | * in case we missed the BRCMF_E_IF_DEL event. | ||
444 | */ | ||
445 | if (ifp->net != NULL) { | ||
446 | BRCMF_ERROR(("%s: ERROR: netdev:%s already exists, " | ||
447 | "try free & unregister\n", | ||
448 | __func__, ifp->net->name)); | ||
449 | netif_stop_queue(ifp->net); | ||
450 | unregister_netdev(ifp->net); | ||
451 | free_netdev(ifp->net); | ||
452 | } | ||
453 | /* Allocate etherdev, including space for private structure */ | ||
454 | ifp->net = alloc_etherdev(sizeof(drvr_priv)); | ||
455 | if (!ifp->net) { | ||
456 | BRCMF_ERROR(("%s: OOM - alloc_etherdev\n", __func__)); | ||
457 | ret = -ENOMEM; | ||
458 | } | ||
459 | if (ret == 0) { | ||
460 | strcpy(ifp->net->name, ifp->name); | ||
461 | memcpy(netdev_priv(ifp->net), &drvr_priv, sizeof(drvr_priv)); | ||
462 | err = brcmf_net_attach(&drvr_priv->pub, ifp->idx); | ||
463 | if (err != 0) { | ||
464 | BRCMF_ERROR(("%s: brcmf_net_attach failed, " | ||
465 | "err %d\n", | ||
466 | __func__, err)); | ||
467 | ret = -EOPNOTSUPP; | ||
468 | } else { | ||
469 | #ifdef SOFTAP | ||
470 | /* semaphore that the soft AP CODE | ||
471 | waits on */ | ||
472 | extern struct semaphore ap_eth_sema; | ||
473 | |||
474 | /* save ptr to wl0.1 netdev for use | ||
475 | in wl_iw.c */ | ||
476 | ap_net_dev = ifp->net; | ||
477 | /* signal to the SOFTAP 'sleeper' thread, | ||
478 | wl0.1 is ready */ | ||
479 | up(&ap_eth_sema); | ||
480 | #endif | ||
481 | BRCMF_TRACE(("\n ==== pid:%x, net_device for " | ||
482 | "if:%s created ===\n\n", | ||
483 | current->pid, ifp->net->name)); | ||
484 | ifp->state = 0; | ||
485 | } | ||
486 | } | ||
487 | break; | ||
488 | case BRCMF_E_IF_DEL: | ||
489 | if (ifp->net != NULL) { | ||
490 | BRCMF_TRACE(("\n%s: got 'WLC_E_IF_DEL' state\n", | ||
491 | __func__)); | ||
492 | netif_stop_queue(ifp->net); | ||
493 | unregister_netdev(ifp->net); | ||
494 | ret = BRCMF_DEL_IF; /* Make sure the free_netdev() | ||
495 | is called */ | ||
496 | } | ||
497 | break; | ||
498 | default: | ||
499 | BRCMF_ERROR(("%s: bad op %d\n", __func__, ifp->state)); | ||
500 | break; | ||
501 | } | ||
502 | |||
503 | if (ret < 0) { | ||
504 | if (ifp->net) | ||
505 | free_netdev(ifp->net); | ||
506 | |||
507 | drvr_priv->iflist[ifp->idx] = NULL; | ||
508 | kfree(ifp); | ||
509 | #ifdef SOFTAP | ||
510 | if (ifp->net == ap_net_dev) | ||
511 | ap_net_dev = NULL; /* NULL SOFTAP global | ||
512 | wl0.1 as well */ | ||
513 | #endif /* SOFTAP */ | ||
514 | } | ||
515 | } | ||
516 | |||
517 | static int _brcmf_sysioc_thread(void *data) | ||
518 | { | ||
519 | struct brcmf_info *drvr_priv = (struct brcmf_info *) data; | ||
520 | int i; | ||
521 | #ifdef SOFTAP | ||
522 | bool in_ap = false; | ||
523 | #endif | ||
524 | |||
525 | allow_signal(SIGTERM); | ||
526 | |||
527 | while (down_interruptible(&drvr_priv->sysioc_sem) == 0) { | ||
528 | if (kthread_should_stop()) | ||
529 | break; | ||
530 | for (i = 0; i < BRCMF_MAX_IFS; i++) { | ||
531 | struct brcmf_if *ifentry = drvr_priv->iflist[i]; | ||
532 | if (ifentry) { | ||
533 | #ifdef SOFTAP | ||
534 | in_ap = (ap_net_dev != NULL); | ||
535 | #endif /* SOFTAP */ | ||
536 | if (ifentry->state) | ||
537 | brcmf_op_if(ifentry); | ||
538 | #ifdef SOFTAP | ||
539 | if (drvr_priv->iflist[i] == NULL) { | ||
540 | BRCMF_TRACE(("\n\n %s: interface %d " | ||
541 | "removed!\n", __func__, | ||
542 | i)); | ||
543 | continue; | ||
544 | } | ||
545 | |||
546 | if (in_ap && drvr_priv->set_macaddress) { | ||
547 | BRCMF_TRACE(("attempt to set MAC for" | ||
548 | " %s in AP Mode," | ||
549 | " blocked.\n", | ||
550 | ifentry->net->name)); | ||
551 | drvr_priv->set_macaddress = false; | ||
552 | continue; | ||
553 | } | ||
554 | |||
555 | if (in_ap && drvr_priv->set_multicast) { | ||
556 | BRCMF_TRACE(("attempt to set MULTICAST " | ||
557 | "list for %s in AP Mode, " | ||
558 | "blocked.\n", | ||
559 | ifentry->net->name)); | ||
560 | drvr_priv->set_multicast = false; | ||
561 | continue; | ||
562 | } | ||
563 | #endif /* SOFTAP */ | ||
564 | if (drvr_priv->set_multicast) { | ||
565 | drvr_priv->set_multicast = false; | ||
566 | _brcmf_set_multicast_list(drvr_priv, i); | ||
567 | } | ||
568 | if (drvr_priv->set_macaddress) { | ||
569 | drvr_priv->set_macaddress = false; | ||
570 | _brcmf_set_mac_address(drvr_priv, i, | ||
571 | drvr_priv->macvalue); | ||
572 | } | ||
573 | } | ||
574 | } | ||
575 | } | ||
576 | return 0; | ||
577 | } | ||
578 | |||
579 | static int brcmf_netdev_set_mac_address(struct net_device *dev, void *addr) | ||
580 | { | ||
581 | int ret = 0; | ||
582 | |||
583 | struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(dev); | ||
584 | struct sockaddr *sa = (struct sockaddr *)addr; | ||
585 | int ifidx; | ||
586 | |||
587 | ifidx = brcmf_net2idx(drvr_priv, dev); | ||
588 | if (ifidx == BRCMF_BAD_IF) | ||
589 | return -1; | ||
590 | |||
591 | memcpy(&drvr_priv->macvalue, sa->sa_data, ETH_ALEN); | ||
592 | drvr_priv->set_macaddress = true; | ||
593 | up(&drvr_priv->sysioc_sem); | ||
594 | |||
595 | return ret; | ||
596 | } | ||
597 | |||
598 | static void brcmf_netdev_set_multicast_list(struct net_device *dev) | ||
599 | { | ||
600 | struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(dev); | ||
601 | int ifidx; | ||
602 | |||
603 | ifidx = brcmf_net2idx(drvr_priv, dev); | ||
604 | if (ifidx == BRCMF_BAD_IF) | ||
605 | return; | ||
606 | |||
607 | drvr_priv->set_multicast = true; | ||
608 | up(&drvr_priv->sysioc_sem); | ||
609 | } | ||
610 | |||
611 | int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf) | ||
612 | { | ||
613 | struct brcmf_info *drvr_priv = drvr->info; | ||
614 | |||
615 | /* Reject if down */ | ||
616 | if (!drvr->up || (drvr->busstate == BRCMF_BUS_DOWN)) | ||
617 | return -ENODEV; | ||
618 | |||
619 | /* Update multicast statistic */ | ||
620 | if (pktbuf->len >= ETH_ALEN) { | ||
621 | u8 *pktdata = (u8 *) (pktbuf->data); | ||
622 | struct ethhdr *eh = (struct ethhdr *)pktdata; | ||
623 | |||
624 | if (is_multicast_ether_addr(eh->h_dest)) | ||
625 | drvr->tx_multicast++; | ||
626 | if (ntohs(eh->h_proto) == ETH_P_PAE) | ||
627 | atomic_inc(&drvr_priv->pend_8021x_cnt); | ||
628 | } | ||
629 | |||
630 | /* If the protocol uses a data header, apply it */ | ||
631 | brcmf_proto_hdrpush(drvr, ifidx, pktbuf); | ||
632 | |||
633 | /* Use bus module to send data frame */ | ||
634 | return brcmf_sdbrcm_bus_txdata(drvr->bus, pktbuf); | ||
635 | } | ||
636 | |||
637 | static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *net) | ||
638 | { | ||
639 | int ret; | ||
640 | struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net); | ||
641 | int ifidx; | ||
642 | |||
643 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
644 | |||
645 | /* Reject if down */ | ||
646 | if (!drvr_priv->pub.up || (drvr_priv->pub.busstate == BRCMF_BUS_DOWN)) { | ||
647 | BRCMF_ERROR(("%s: xmit rejected pub.up=%d busstate=%d\n", | ||
648 | __func__, drvr_priv->pub.up, | ||
649 | drvr_priv->pub.busstate)); | ||
650 | netif_stop_queue(net); | ||
651 | return -ENODEV; | ||
652 | } | ||
653 | |||
654 | ifidx = brcmf_net2idx(drvr_priv, net); | ||
655 | if (ifidx == BRCMF_BAD_IF) { | ||
656 | BRCMF_ERROR(("%s: bad ifidx %d\n", __func__, ifidx)); | ||
657 | netif_stop_queue(net); | ||
658 | return -ENODEV; | ||
659 | } | ||
660 | |||
661 | /* Make sure there's enough room for any header */ | ||
662 | if (skb_headroom(skb) < drvr_priv->pub.hdrlen) { | ||
663 | struct sk_buff *skb2; | ||
664 | |||
665 | BRCMF_INFO(("%s: insufficient headroom\n", | ||
666 | brcmf_ifname(&drvr_priv->pub, ifidx))); | ||
667 | drvr_priv->pub.tx_realloc++; | ||
668 | skb2 = skb_realloc_headroom(skb, drvr_priv->pub.hdrlen); | ||
669 | dev_kfree_skb(skb); | ||
670 | skb = skb2; | ||
671 | if (skb == NULL) { | ||
672 | BRCMF_ERROR(("%s: skb_realloc_headroom failed\n", | ||
673 | brcmf_ifname(&drvr_priv->pub, ifidx))); | ||
674 | ret = -ENOMEM; | ||
675 | goto done; | ||
676 | } | ||
677 | } | ||
678 | |||
679 | ret = brcmf_sendpkt(&drvr_priv->pub, ifidx, skb); | ||
680 | |||
681 | done: | ||
682 | if (ret) | ||
683 | drvr_priv->pub.dstats.tx_dropped++; | ||
684 | else | ||
685 | drvr_priv->pub.tx_packets++; | ||
686 | |||
687 | /* Return ok: we always eat the packet */ | ||
688 | return 0; | ||
689 | } | ||
690 | |||
691 | void brcmf_txflowcontrol(struct brcmf_pub *drvr, int ifidx, bool state) | ||
692 | { | ||
693 | struct net_device *net; | ||
694 | struct brcmf_info *drvr_priv = drvr->info; | ||
695 | |||
696 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
697 | |||
698 | drvr->txoff = state; | ||
699 | net = drvr_priv->iflist[ifidx]->net; | ||
700 | if (state == ON) | ||
701 | netif_stop_queue(net); | ||
702 | else | ||
703 | netif_wake_queue(net); | ||
704 | } | ||
705 | |||
706 | void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb, | ||
707 | int numpkt) | ||
708 | { | ||
709 | struct brcmf_info *drvr_priv = drvr->info; | ||
710 | unsigned char *eth; | ||
711 | uint len; | ||
712 | void *data; | ||
713 | struct sk_buff *pnext, *save_pktbuf; | ||
714 | int i; | ||
715 | struct brcmf_if *ifp; | ||
716 | struct brcmf_event_msg event; | ||
717 | |||
718 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
719 | |||
720 | save_pktbuf = skb; | ||
721 | |||
722 | for (i = 0; skb && i < numpkt; i++, skb = pnext) { | ||
723 | |||
724 | pnext = skb->next; | ||
725 | skb->next = NULL; | ||
726 | |||
727 | /* Get the protocol, maintain skb around eth_type_trans() | ||
728 | * The main reason for this hack is for the limitation of | ||
729 | * Linux 2.4 where 'eth_type_trans' uses the | ||
730 | * 'net->hard_header_len' | ||
731 | * to perform skb_pull inside vs ETH_HLEN. Since to avoid | ||
732 | * coping of the packet coming from the network stack to add | ||
733 | * BDC, Hardware header etc, during network interface | ||
734 | * registration | ||
735 | * we set the 'net->hard_header_len' to ETH_HLEN + extra space | ||
736 | * required | ||
737 | * for BDC, Hardware header etc. and not just the ETH_HLEN | ||
738 | */ | ||
739 | eth = skb->data; | ||
740 | len = skb->len; | ||
741 | |||
742 | ifp = drvr_priv->iflist[ifidx]; | ||
743 | if (ifp == NULL) | ||
744 | ifp = drvr_priv->iflist[0]; | ||
745 | |||
746 | skb->dev = ifp->net; | ||
747 | skb->protocol = eth_type_trans(skb, skb->dev); | ||
748 | |||
749 | if (skb->pkt_type == PACKET_MULTICAST) | ||
750 | drvr_priv->pub.rx_multicast++; | ||
751 | |||
752 | skb->data = eth; | ||
753 | skb->len = len; | ||
754 | |||
755 | /* Strip header, count, deliver upward */ | ||
756 | skb_pull(skb, ETH_HLEN); | ||
757 | |||
758 | /* Process special event packets and then discard them */ | ||
759 | if (ntohs(skb->protocol) == ETH_P_LINK_CTL) | ||
760 | brcmf_host_event(drvr_priv, &ifidx, | ||
761 | skb_mac_header(skb), | ||
762 | &event, &data); | ||
763 | |||
764 | if (drvr_priv->iflist[ifidx] && | ||
765 | !drvr_priv->iflist[ifidx]->state) | ||
766 | ifp = drvr_priv->iflist[ifidx]; | ||
767 | |||
768 | if (ifp->net) | ||
769 | ifp->net->last_rx = jiffies; | ||
770 | |||
771 | drvr->dstats.rx_bytes += skb->len; | ||
772 | drvr->rx_packets++; /* Local count */ | ||
773 | |||
774 | if (in_interrupt()) { | ||
775 | netif_rx(skb); | ||
776 | } else { | ||
777 | /* If the receive is not processed inside an ISR, | ||
778 | * the softirqd must be woken explicitly to service | ||
779 | * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled | ||
780 | * by netif_rx_ni(), but in earlier kernels, we need | ||
781 | * to do it manually. | ||
782 | */ | ||
783 | netif_rx_ni(skb); | ||
784 | } | ||
785 | } | ||
786 | } | ||
787 | |||
788 | void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, bool success) | ||
789 | { | ||
790 | uint ifidx; | ||
791 | struct brcmf_info *drvr_priv = drvr->info; | ||
792 | struct ethhdr *eh; | ||
793 | u16 type; | ||
794 | |||
795 | brcmf_proto_hdrpull(drvr, &ifidx, txp); | ||
796 | |||
797 | eh = (struct ethhdr *)(txp->data); | ||
798 | type = ntohs(eh->h_proto); | ||
799 | |||
800 | if (type == ETH_P_PAE) | ||
801 | atomic_dec(&drvr_priv->pend_8021x_cnt); | ||
802 | |||
803 | } | ||
804 | |||
805 | static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *net) | ||
806 | { | ||
807 | struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net); | ||
808 | struct brcmf_if *ifp; | ||
809 | int ifidx; | ||
810 | |||
811 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
812 | |||
813 | ifidx = brcmf_net2idx(drvr_priv, net); | ||
814 | if (ifidx == BRCMF_BAD_IF) | ||
815 | return NULL; | ||
816 | |||
817 | ifp = drvr_priv->iflist[ifidx]; | ||
818 | |||
819 | if (drvr_priv->pub.up) { | ||
820 | /* Use the protocol to get dongle stats */ | ||
821 | brcmf_proto_dstats(&drvr_priv->pub); | ||
822 | } | ||
823 | |||
824 | /* Copy dongle stats to net device stats */ | ||
825 | ifp->stats.rx_packets = drvr_priv->pub.dstats.rx_packets; | ||
826 | ifp->stats.tx_packets = drvr_priv->pub.dstats.tx_packets; | ||
827 | ifp->stats.rx_bytes = drvr_priv->pub.dstats.rx_bytes; | ||
828 | ifp->stats.tx_bytes = drvr_priv->pub.dstats.tx_bytes; | ||
829 | ifp->stats.rx_errors = drvr_priv->pub.dstats.rx_errors; | ||
830 | ifp->stats.tx_errors = drvr_priv->pub.dstats.tx_errors; | ||
831 | ifp->stats.rx_dropped = drvr_priv->pub.dstats.rx_dropped; | ||
832 | ifp->stats.tx_dropped = drvr_priv->pub.dstats.tx_dropped; | ||
833 | ifp->stats.multicast = drvr_priv->pub.dstats.multicast; | ||
834 | |||
835 | return &ifp->stats; | ||
836 | } | ||
837 | |||
838 | /* Retrieve current toe component enables, which are kept | ||
839 | as a bitmap in toe_ol iovar */ | ||
840 | static int brcmf_toe_get(struct brcmf_info *drvr_priv, int ifidx, u32 *toe_ol) | ||
841 | { | ||
842 | struct brcmf_ioctl ioc; | ||
843 | char buf[32]; | ||
844 | int ret; | ||
845 | |||
846 | memset(&ioc, 0, sizeof(ioc)); | ||
847 | |||
848 | ioc.cmd = BRCMF_C_GET_VAR; | ||
849 | ioc.buf = buf; | ||
850 | ioc.len = (uint) sizeof(buf); | ||
851 | ioc.set = false; | ||
852 | |||
853 | strcpy(buf, "toe_ol"); | ||
854 | ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len); | ||
855 | if (ret < 0) { | ||
856 | /* Check for older dongle image that doesn't support toe_ol */ | ||
857 | if (ret == -EIO) { | ||
858 | BRCMF_ERROR(("%s: toe not supported by device\n", | ||
859 | brcmf_ifname(&drvr_priv->pub, ifidx))); | ||
860 | return -EOPNOTSUPP; | ||
861 | } | ||
862 | |||
863 | BRCMF_INFO(("%s: could not get toe_ol: ret=%d\n", | ||
864 | brcmf_ifname(&drvr_priv->pub, ifidx), ret)); | ||
865 | return ret; | ||
866 | } | ||
867 | |||
868 | memcpy(toe_ol, buf, sizeof(u32)); | ||
869 | return 0; | ||
870 | } | ||
871 | |||
872 | /* Set current toe component enables in toe_ol iovar, | ||
873 | and set toe global enable iovar */ | ||
874 | static int brcmf_toe_set(struct brcmf_info *drvr_priv, int ifidx, u32 toe_ol) | ||
875 | { | ||
876 | struct brcmf_ioctl ioc; | ||
877 | char buf[32]; | ||
878 | int toe, ret; | ||
879 | |||
880 | memset(&ioc, 0, sizeof(ioc)); | ||
881 | |||
882 | ioc.cmd = BRCMF_C_SET_VAR; | ||
883 | ioc.buf = buf; | ||
884 | ioc.len = (uint) sizeof(buf); | ||
885 | ioc.set = true; | ||
886 | |||
887 | /* Set toe_ol as requested */ | ||
888 | |||
889 | strcpy(buf, "toe_ol"); | ||
890 | memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(u32)); | ||
891 | |||
892 | ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len); | ||
893 | if (ret < 0) { | ||
894 | BRCMF_ERROR(("%s: could not set toe_ol: ret=%d\n", | ||
895 | brcmf_ifname(&drvr_priv->pub, ifidx), ret)); | ||
896 | return ret; | ||
897 | } | ||
898 | |||
899 | /* Enable toe globally only if any components are enabled. */ | ||
900 | |||
901 | toe = (toe_ol != 0); | ||
902 | |||
903 | strcpy(buf, "toe"); | ||
904 | memcpy(&buf[sizeof("toe")], &toe, sizeof(u32)); | ||
905 | |||
906 | ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len); | ||
907 | if (ret < 0) { | ||
908 | BRCMF_ERROR(("%s: could not set toe: ret=%d\n", | ||
909 | brcmf_ifname(&drvr_priv->pub, ifidx), ret)); | ||
910 | return ret; | ||
911 | } | ||
912 | |||
913 | return 0; | ||
914 | } | ||
915 | |||
916 | static void brcmf_ethtool_get_drvinfo(struct net_device *net, | ||
917 | struct ethtool_drvinfo *info) | ||
918 | { | ||
919 | struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net); | ||
920 | |||
921 | sprintf(info->driver, KBUILD_MODNAME); | ||
922 | sprintf(info->version, "%lu", drvr_priv->pub.drv_version); | ||
923 | sprintf(info->fw_version, "%s", BCM4329_FW_NAME); | ||
924 | sprintf(info->bus_info, "%s", | ||
925 | dev_name(&brcmf_cfg80211_get_sdio_func()->dev)); | ||
926 | } | ||
927 | |||
928 | struct ethtool_ops brcmf_ethtool_ops = { | ||
929 | .get_drvinfo = brcmf_ethtool_get_drvinfo | ||
930 | }; | ||
931 | |||
932 | static int brcmf_ethtool(struct brcmf_info *drvr_priv, void *uaddr) | ||
933 | { | ||
934 | struct ethtool_drvinfo info; | ||
935 | char drvname[sizeof(info.driver)]; | ||
936 | u32 cmd; | ||
937 | struct ethtool_value edata; | ||
938 | u32 toe_cmpnt, csum_dir; | ||
939 | int ret; | ||
940 | |||
941 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
942 | |||
943 | /* all ethtool calls start with a cmd word */ | ||
944 | if (copy_from_user(&cmd, uaddr, sizeof(u32))) | ||
945 | return -EFAULT; | ||
946 | |||
947 | switch (cmd) { | ||
948 | case ETHTOOL_GDRVINFO: | ||
949 | /* Copy out any request driver name */ | ||
950 | if (copy_from_user(&info, uaddr, sizeof(info))) | ||
951 | return -EFAULT; | ||
952 | strncpy(drvname, info.driver, sizeof(info.driver)); | ||
953 | drvname[sizeof(info.driver) - 1] = '\0'; | ||
954 | |||
955 | /* clear struct for return */ | ||
956 | memset(&info, 0, sizeof(info)); | ||
957 | info.cmd = cmd; | ||
958 | |||
959 | /* if requested, identify ourselves */ | ||
960 | if (strcmp(drvname, "?dhd") == 0) { | ||
961 | sprintf(info.driver, "dhd"); | ||
962 | strcpy(info.version, BRCMF_VERSION_STR); | ||
963 | } | ||
964 | |||
965 | /* otherwise, require dongle to be up */ | ||
966 | else if (!drvr_priv->pub.up) { | ||
967 | BRCMF_ERROR(("%s: dongle is not up\n", __func__)); | ||
968 | return -ENODEV; | ||
969 | } | ||
970 | |||
971 | /* finally, report dongle driver type */ | ||
972 | else if (drvr_priv->pub.iswl) | ||
973 | sprintf(info.driver, "wl"); | ||
974 | else | ||
975 | sprintf(info.driver, "xx"); | ||
976 | |||
977 | sprintf(info.version, "%lu", drvr_priv->pub.drv_version); | ||
978 | if (copy_to_user(uaddr, &info, sizeof(info))) | ||
979 | return -EFAULT; | ||
980 | BRCMF_CTL(("%s: given %*s, returning %s\n", __func__, | ||
981 | (int)sizeof(drvname), drvname, info.driver)); | ||
982 | break; | ||
983 | |||
984 | /* Get toe offload components from dongle */ | ||
985 | case ETHTOOL_GRXCSUM: | ||
986 | case ETHTOOL_GTXCSUM: | ||
987 | ret = brcmf_toe_get(drvr_priv, 0, &toe_cmpnt); | ||
988 | if (ret < 0) | ||
989 | return ret; | ||
990 | |||
991 | csum_dir = | ||
992 | (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; | ||
993 | |||
994 | edata.cmd = cmd; | ||
995 | edata.data = (toe_cmpnt & csum_dir) ? 1 : 0; | ||
996 | |||
997 | if (copy_to_user(uaddr, &edata, sizeof(edata))) | ||
998 | return -EFAULT; | ||
999 | break; | ||
1000 | |||
1001 | /* Set toe offload components in dongle */ | ||
1002 | case ETHTOOL_SRXCSUM: | ||
1003 | case ETHTOOL_STXCSUM: | ||
1004 | if (copy_from_user(&edata, uaddr, sizeof(edata))) | ||
1005 | return -EFAULT; | ||
1006 | |||
1007 | /* Read the current settings, update and write back */ | ||
1008 | ret = brcmf_toe_get(drvr_priv, 0, &toe_cmpnt); | ||
1009 | if (ret < 0) | ||
1010 | return ret; | ||
1011 | |||
1012 | csum_dir = | ||
1013 | (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; | ||
1014 | |||
1015 | if (edata.data != 0) | ||
1016 | toe_cmpnt |= csum_dir; | ||
1017 | else | ||
1018 | toe_cmpnt &= ~csum_dir; | ||
1019 | |||
1020 | ret = brcmf_toe_set(drvr_priv, 0, toe_cmpnt); | ||
1021 | if (ret < 0) | ||
1022 | return ret; | ||
1023 | |||
1024 | /* If setting TX checksum mode, tell Linux the new mode */ | ||
1025 | if (cmd == ETHTOOL_STXCSUM) { | ||
1026 | if (edata.data) | ||
1027 | drvr_priv->iflist[0]->net->features |= | ||
1028 | NETIF_F_IP_CSUM; | ||
1029 | else | ||
1030 | drvr_priv->iflist[0]->net->features &= | ||
1031 | ~NETIF_F_IP_CSUM; | ||
1032 | } | ||
1033 | |||
1034 | break; | ||
1035 | |||
1036 | default: | ||
1037 | return -EOPNOTSUPP; | ||
1038 | } | ||
1039 | |||
1040 | return 0; | ||
1041 | } | ||
1042 | |||
1043 | static int brcmf_netdev_ioctl_entry(struct net_device *net, struct ifreq *ifr, | ||
1044 | int cmd) | ||
1045 | { | ||
1046 | struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net); | ||
1047 | struct brcmf_c_ioctl ioc; | ||
1048 | int bcmerror = 0; | ||
1049 | int buflen = 0; | ||
1050 | void *buf = NULL; | ||
1051 | uint driver = 0; | ||
1052 | int ifidx; | ||
1053 | bool is_set_key_cmd; | ||
1054 | |||
1055 | ifidx = brcmf_net2idx(drvr_priv, net); | ||
1056 | BRCMF_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __func__, ifidx, cmd)); | ||
1057 | |||
1058 | if (ifidx == BRCMF_BAD_IF) | ||
1059 | return -1; | ||
1060 | |||
1061 | if (cmd == SIOCETHTOOL) | ||
1062 | return brcmf_ethtool(drvr_priv, (void *)ifr->ifr_data); | ||
1063 | |||
1064 | if (cmd != SIOCDEVPRIVATE) | ||
1065 | return -EOPNOTSUPP; | ||
1066 | |||
1067 | memset(&ioc, 0, sizeof(ioc)); | ||
1068 | |||
1069 | /* Copy the ioc control structure part of ioctl request */ | ||
1070 | if (copy_from_user(&ioc, ifr->ifr_data, sizeof(struct brcmf_ioctl))) { | ||
1071 | bcmerror = -EINVAL; | ||
1072 | goto done; | ||
1073 | } | ||
1074 | |||
1075 | /* Copy out any buffer passed */ | ||
1076 | if (ioc.buf) { | ||
1077 | buflen = min_t(int, ioc.len, BRCMF_IOCTL_MAXLEN); | ||
1078 | /* optimization for direct ioctl calls from kernel */ | ||
1079 | /* | ||
1080 | if (segment_eq(get_fs(), KERNEL_DS)) { | ||
1081 | buf = ioc.buf; | ||
1082 | } else { | ||
1083 | */ | ||
1084 | { | ||
1085 | buf = kmalloc(buflen, GFP_ATOMIC); | ||
1086 | if (!buf) { | ||
1087 | bcmerror = -ENOMEM; | ||
1088 | goto done; | ||
1089 | } | ||
1090 | if (copy_from_user(buf, ioc.buf, buflen)) { | ||
1091 | bcmerror = -EINVAL; | ||
1092 | goto done; | ||
1093 | } | ||
1094 | } | ||
1095 | } | ||
1096 | |||
1097 | /* To differentiate read 4 more byes */ | ||
1098 | if ((copy_from_user(&driver, (char *)ifr->ifr_data + | ||
1099 | sizeof(struct brcmf_ioctl), sizeof(uint)) != 0)) { | ||
1100 | bcmerror = -EINVAL; | ||
1101 | goto done; | ||
1102 | } | ||
1103 | |||
1104 | if (!capable(CAP_NET_ADMIN)) { | ||
1105 | bcmerror = -EPERM; | ||
1106 | goto done; | ||
1107 | } | ||
1108 | |||
1109 | /* check for local brcmf ioctl and handle it */ | ||
1110 | if (driver == BRCMF_IOCTL_MAGIC) { | ||
1111 | bcmerror = brcmf_c_ioctl((void *)&drvr_priv->pub, &ioc, buf, buflen); | ||
1112 | if (bcmerror) | ||
1113 | drvr_priv->pub.bcmerror = bcmerror; | ||
1114 | goto done; | ||
1115 | } | ||
1116 | |||
1117 | /* send to dongle (must be up, and wl) */ | ||
1118 | if ((drvr_priv->pub.busstate != BRCMF_BUS_DATA)) { | ||
1119 | BRCMF_ERROR(("%s DONGLE_DOWN,__func__\n", __func__)); | ||
1120 | bcmerror = -EIO; | ||
1121 | goto done; | ||
1122 | } | ||
1123 | |||
1124 | if (!drvr_priv->pub.iswl) { | ||
1125 | bcmerror = -EIO; | ||
1126 | goto done; | ||
1127 | } | ||
1128 | |||
1129 | /* | ||
1130 | * Intercept BRCMF_C_SET_KEY IOCTL - serialize M4 send and | ||
1131 | * set key IOCTL to prevent M4 encryption. | ||
1132 | */ | ||
1133 | is_set_key_cmd = ((ioc.cmd == BRCMF_C_SET_KEY) || | ||
1134 | ((ioc.cmd == BRCMF_C_SET_VAR) && | ||
1135 | !(strncmp("wsec_key", ioc.buf, 9))) || | ||
1136 | ((ioc.cmd == BRCMF_C_SET_VAR) && | ||
1137 | !(strncmp("bsscfg:wsec_key", ioc.buf, 15)))); | ||
1138 | if (is_set_key_cmd) | ||
1139 | brcmf_netdev_wait_pend8021x(net); | ||
1140 | |||
1141 | bcmerror = | ||
1142 | brcmf_proto_ioctl(&drvr_priv->pub, ifidx, (struct brcmf_ioctl *)&ioc, | ||
1143 | buf, buflen); | ||
1144 | |||
1145 | done: | ||
1146 | if (!bcmerror && buf && ioc.buf) { | ||
1147 | if (copy_to_user(ioc.buf, buf, buflen)) | ||
1148 | bcmerror = -EFAULT; | ||
1149 | } | ||
1150 | |||
1151 | kfree(buf); | ||
1152 | |||
1153 | if (bcmerror > 0) | ||
1154 | bcmerror = 0; | ||
1155 | |||
1156 | return bcmerror; | ||
1157 | } | ||
1158 | |||
1159 | static int brcmf_netdev_stop(struct net_device *net) | ||
1160 | { | ||
1161 | #if !defined(IGNORE_ETH0_DOWN) | ||
1162 | struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net); | ||
1163 | |||
1164 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
1165 | brcmf_cfg80211_down(); | ||
1166 | if (drvr_priv->pub.up == 0) | ||
1167 | return 0; | ||
1168 | |||
1169 | /* Set state and stop OS transmissions */ | ||
1170 | drvr_priv->pub.up = 0; | ||
1171 | netif_stop_queue(net); | ||
1172 | #else | ||
1173 | BRCMF_ERROR(("BYPASS %s:due to BRCM compilation: under investigation\n", | ||
1174 | __func__)); | ||
1175 | #endif /* !defined(IGNORE_ETH0_DOWN) */ | ||
1176 | |||
1177 | return 0; | ||
1178 | } | ||
1179 | |||
1180 | static int brcmf_netdev_open(struct net_device *net) | ||
1181 | { | ||
1182 | struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net); | ||
1183 | u32 toe_ol; | ||
1184 | int ifidx = brcmf_net2idx(drvr_priv, net); | ||
1185 | s32 ret = 0; | ||
1186 | |||
1187 | BRCMF_TRACE(("%s: ifidx %d\n", __func__, ifidx)); | ||
1188 | |||
1189 | if (ifidx == 0) { /* do it only for primary eth0 */ | ||
1190 | |||
1191 | /* try to bring up bus */ | ||
1192 | ret = brcmf_bus_start(&drvr_priv->pub); | ||
1193 | if (ret != 0) { | ||
1194 | BRCMF_ERROR(("%s: failed with code %d\n", | ||
1195 | __func__, ret)); | ||
1196 | return -1; | ||
1197 | } | ||
1198 | atomic_set(&drvr_priv->pend_8021x_cnt, 0); | ||
1199 | |||
1200 | memcpy(net->dev_addr, drvr_priv->pub.mac, ETH_ALEN); | ||
1201 | |||
1202 | /* Get current TOE mode from dongle */ | ||
1203 | if (brcmf_toe_get(drvr_priv, ifidx, &toe_ol) >= 0 | ||
1204 | && (toe_ol & TOE_TX_CSUM_OL) != 0) | ||
1205 | drvr_priv->iflist[ifidx]->net->features |= | ||
1206 | NETIF_F_IP_CSUM; | ||
1207 | else | ||
1208 | drvr_priv->iflist[ifidx]->net->features &= | ||
1209 | ~NETIF_F_IP_CSUM; | ||
1210 | } | ||
1211 | /* Allow transmit calls */ | ||
1212 | netif_start_queue(net); | ||
1213 | drvr_priv->pub.up = 1; | ||
1214 | if (unlikely(brcmf_cfg80211_up())) { | ||
1215 | BRCMF_ERROR(("%s: failed to bring up cfg80211\n", | ||
1216 | __func__)); | ||
1217 | return -1; | ||
1218 | } | ||
1219 | |||
1220 | return ret; | ||
1221 | } | ||
1222 | |||
1223 | int | ||
1224 | brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, void *handle, char *name, | ||
1225 | u8 *mac_addr, u32 flags, u8 bssidx) | ||
1226 | { | ||
1227 | struct brcmf_if *ifp; | ||
1228 | |||
1229 | BRCMF_TRACE(("%s: idx %d, handle->%p\n", __func__, ifidx, handle)); | ||
1230 | |||
1231 | ifp = drvr_priv->iflist[ifidx]; | ||
1232 | if (!ifp) { | ||
1233 | ifp = kmalloc(sizeof(struct brcmf_if), GFP_ATOMIC); | ||
1234 | if (!ifp) { | ||
1235 | BRCMF_ERROR(("%s: OOM - struct brcmf_if\n", __func__)); | ||
1236 | return -ENOMEM; | ||
1237 | } | ||
1238 | } | ||
1239 | |||
1240 | memset(ifp, 0, sizeof(struct brcmf_if)); | ||
1241 | ifp->info = drvr_priv; | ||
1242 | drvr_priv->iflist[ifidx] = ifp; | ||
1243 | strlcpy(ifp->name, name, IFNAMSIZ); | ||
1244 | if (mac_addr != NULL) | ||
1245 | memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN); | ||
1246 | |||
1247 | if (handle == NULL) { | ||
1248 | ifp->state = BRCMF_E_IF_ADD; | ||
1249 | ifp->idx = ifidx; | ||
1250 | up(&drvr_priv->sysioc_sem); | ||
1251 | } else | ||
1252 | ifp->net = (struct net_device *)handle; | ||
1253 | |||
1254 | return 0; | ||
1255 | } | ||
1256 | |||
1257 | void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx) | ||
1258 | { | ||
1259 | struct brcmf_if *ifp; | ||
1260 | |||
1261 | BRCMF_TRACE(("%s: idx %d\n", __func__, ifidx)); | ||
1262 | |||
1263 | ifp = drvr_priv->iflist[ifidx]; | ||
1264 | if (!ifp) { | ||
1265 | BRCMF_ERROR(("%s: Null interface\n", __func__)); | ||
1266 | return; | ||
1267 | } | ||
1268 | |||
1269 | ifp->state = BRCMF_E_IF_DEL; | ||
1270 | ifp->idx = ifidx; | ||
1271 | up(&drvr_priv->sysioc_sem); | ||
1272 | } | ||
1273 | |||
1274 | struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen) | ||
1275 | { | ||
1276 | struct brcmf_info *drvr_priv = NULL; | ||
1277 | struct net_device *net; | ||
1278 | |||
1279 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
1280 | |||
1281 | /* Allocate etherdev, including space for private structure */ | ||
1282 | net = alloc_etherdev(sizeof(drvr_priv)); | ||
1283 | if (!net) { | ||
1284 | BRCMF_ERROR(("%s: OOM - alloc_etherdev\n", __func__)); | ||
1285 | goto fail; | ||
1286 | } | ||
1287 | |||
1288 | /* Allocate primary brcmf_info */ | ||
1289 | drvr_priv = kzalloc(sizeof(struct brcmf_info), GFP_ATOMIC); | ||
1290 | if (!drvr_priv) { | ||
1291 | BRCMF_ERROR(("%s: OOM - alloc brcmf_info\n", __func__)); | ||
1292 | goto fail; | ||
1293 | } | ||
1294 | |||
1295 | /* | ||
1296 | * Save the brcmf_info into the priv | ||
1297 | */ | ||
1298 | memcpy(netdev_priv(net), &drvr_priv, sizeof(drvr_priv)); | ||
1299 | |||
1300 | /* Set network interface name if it was provided as module parameter */ | ||
1301 | if (iface_name[0]) { | ||
1302 | int len; | ||
1303 | char ch; | ||
1304 | strncpy(net->name, iface_name, IFNAMSIZ); | ||
1305 | net->name[IFNAMSIZ - 1] = 0; | ||
1306 | len = strlen(net->name); | ||
1307 | ch = net->name[len - 1]; | ||
1308 | if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2)) | ||
1309 | strcat(net->name, "%d"); | ||
1310 | } | ||
1311 | |||
1312 | if (brcmf_add_if(drvr_priv, 0, (void *)net, net->name, NULL, 0, 0) == | ||
1313 | BRCMF_BAD_IF) | ||
1314 | goto fail; | ||
1315 | |||
1316 | net->netdev_ops = NULL; | ||
1317 | sema_init(&drvr_priv->proto_sem, 1); | ||
1318 | /* Initialize other structure content */ | ||
1319 | init_waitqueue_head(&drvr_priv->ioctl_resp_wait); | ||
1320 | |||
1321 | /* Link to info module */ | ||
1322 | drvr_priv->pub.info = drvr_priv; | ||
1323 | |||
1324 | /* Link to bus module */ | ||
1325 | drvr_priv->pub.bus = bus; | ||
1326 | drvr_priv->pub.hdrlen = bus_hdrlen; | ||
1327 | |||
1328 | /* Attach and link in the protocol */ | ||
1329 | if (brcmf_proto_attach(&drvr_priv->pub) != 0) { | ||
1330 | BRCMF_ERROR(("brcmf_prot_attach failed\n")); | ||
1331 | goto fail; | ||
1332 | } | ||
1333 | |||
1334 | /* Attach and link in the cfg80211 */ | ||
1335 | if (unlikely(brcmf_cfg80211_attach(net, &drvr_priv->pub))) { | ||
1336 | BRCMF_ERROR(("wl_cfg80211_attach failed\n")); | ||
1337 | goto fail; | ||
1338 | } | ||
1339 | |||
1340 | if (brcmf_sysioc) { | ||
1341 | sema_init(&drvr_priv->sysioc_sem, 0); | ||
1342 | drvr_priv->sysioc_tsk = kthread_run(_brcmf_sysioc_thread, drvr_priv, | ||
1343 | "_brcmf_sysioc"); | ||
1344 | if (IS_ERR(drvr_priv->sysioc_tsk)) { | ||
1345 | printk(KERN_WARNING | ||
1346 | "_brcmf_sysioc thread failed to start\n"); | ||
1347 | drvr_priv->sysioc_tsk = NULL; | ||
1348 | } | ||
1349 | } else | ||
1350 | drvr_priv->sysioc_tsk = NULL; | ||
1351 | |||
1352 | /* | ||
1353 | * Save the brcmf_info into the priv | ||
1354 | */ | ||
1355 | memcpy(netdev_priv(net), &drvr_priv, sizeof(drvr_priv)); | ||
1356 | |||
1357 | #if defined(CONFIG_PM_SLEEP) | ||
1358 | atomic_set(&brcmf_mmc_suspend, false); | ||
1359 | #endif /* defined(CONFIG_PM_SLEEP) */ | ||
1360 | return &drvr_priv->pub; | ||
1361 | |||
1362 | fail: | ||
1363 | if (net) | ||
1364 | free_netdev(net); | ||
1365 | if (drvr_priv) | ||
1366 | brcmf_detach(&drvr_priv->pub); | ||
1367 | |||
1368 | return NULL; | ||
1369 | } | ||
1370 | |||
1371 | int brcmf_bus_start(struct brcmf_pub *drvr) | ||
1372 | { | ||
1373 | int ret = -1; | ||
1374 | struct brcmf_info *drvr_priv = drvr->info; | ||
1375 | /* Room for "event_msgs" + '\0' + bitvec */ | ||
1376 | char iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; | ||
1377 | |||
1378 | BRCMF_TRACE(("%s:\n", __func__)); | ||
1379 | |||
1380 | /* Bring up the bus */ | ||
1381 | ret = brcmf_sdbrcm_bus_init(&drvr_priv->pub, true); | ||
1382 | if (ret != 0) { | ||
1383 | BRCMF_ERROR(("%s, brcmf_sdbrcm_bus_init failed %d\n", __func__, | ||
1384 | ret)); | ||
1385 | return ret; | ||
1386 | } | ||
1387 | |||
1388 | /* If bus is not ready, can't come up */ | ||
1389 | if (drvr_priv->pub.busstate != BRCMF_BUS_DATA) { | ||
1390 | BRCMF_ERROR(("%s failed bus is not ready\n", __func__)); | ||
1391 | return -ENODEV; | ||
1392 | } | ||
1393 | |||
1394 | brcmu_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN, | ||
1395 | iovbuf, sizeof(iovbuf)); | ||
1396 | brcmf_proto_cdc_query_ioctl(drvr, 0, BRCMF_C_GET_VAR, iovbuf, | ||
1397 | sizeof(iovbuf)); | ||
1398 | memcpy(drvr->eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN); | ||
1399 | |||
1400 | setbit(drvr->eventmask, BRCMF_E_SET_SSID); | ||
1401 | setbit(drvr->eventmask, BRCMF_E_PRUNE); | ||
1402 | setbit(drvr->eventmask, BRCMF_E_AUTH); | ||
1403 | setbit(drvr->eventmask, BRCMF_E_REASSOC); | ||
1404 | setbit(drvr->eventmask, BRCMF_E_REASSOC_IND); | ||
1405 | setbit(drvr->eventmask, BRCMF_E_DEAUTH_IND); | ||
1406 | setbit(drvr->eventmask, BRCMF_E_DISASSOC_IND); | ||
1407 | setbit(drvr->eventmask, BRCMF_E_DISASSOC); | ||
1408 | setbit(drvr->eventmask, BRCMF_E_JOIN); | ||
1409 | setbit(drvr->eventmask, BRCMF_E_ASSOC_IND); | ||
1410 | setbit(drvr->eventmask, BRCMF_E_PSK_SUP); | ||
1411 | setbit(drvr->eventmask, BRCMF_E_LINK); | ||
1412 | setbit(drvr->eventmask, BRCMF_E_NDIS_LINK); | ||
1413 | setbit(drvr->eventmask, BRCMF_E_MIC_ERROR); | ||
1414 | setbit(drvr->eventmask, BRCMF_E_PMKID_CACHE); | ||
1415 | setbit(drvr->eventmask, BRCMF_E_TXFAIL); | ||
1416 | setbit(drvr->eventmask, BRCMF_E_JOIN_START); | ||
1417 | setbit(drvr->eventmask, BRCMF_E_SCAN_COMPLETE); | ||
1418 | |||
1419 | /* enable dongle roaming event */ | ||
1420 | |||
1421 | drvr->pktfilter_count = 1; | ||
1422 | /* Setup filter to allow only unicast */ | ||
1423 | drvr->pktfilter[0] = "100 0 0 0 0x01 0x00"; | ||
1424 | |||
1425 | /* Bus is ready, do any protocol initialization */ | ||
1426 | ret = brcmf_proto_init(&drvr_priv->pub); | ||
1427 | if (ret < 0) | ||
1428 | return ret; | ||
1429 | |||
1430 | return 0; | ||
1431 | } | ||
1432 | |||
1433 | static struct net_device_ops brcmf_netdev_ops_pri = { | ||
1434 | .ndo_open = brcmf_netdev_open, | ||
1435 | .ndo_stop = brcmf_netdev_stop, | ||
1436 | .ndo_get_stats = brcmf_netdev_get_stats, | ||
1437 | .ndo_do_ioctl = brcmf_netdev_ioctl_entry, | ||
1438 | .ndo_start_xmit = brcmf_netdev_start_xmit, | ||
1439 | .ndo_set_mac_address = brcmf_netdev_set_mac_address, | ||
1440 | .ndo_set_multicast_list = brcmf_netdev_set_multicast_list | ||
1441 | }; | ||
1442 | |||
1443 | int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx) | ||
1444 | { | ||
1445 | struct brcmf_info *drvr_priv = drvr->info; | ||
1446 | struct net_device *net; | ||
1447 | u8 temp_addr[ETH_ALEN] = { | ||
1448 | 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33}; | ||
1449 | |||
1450 | BRCMF_TRACE(("%s: ifidx %d\n", __func__, ifidx)); | ||
1451 | |||
1452 | net = drvr_priv->iflist[ifidx]->net; | ||
1453 | net->netdev_ops = &brcmf_netdev_ops_pri; | ||
1454 | |||
1455 | /* | ||
1456 | * We have to use the primary MAC for virtual interfaces | ||
1457 | */ | ||
1458 | if (ifidx != 0) { | ||
1459 | /* for virtual interfaces use the primary MAC */ | ||
1460 | memcpy(temp_addr, drvr_priv->pub.mac, ETH_ALEN); | ||
1461 | |||
1462 | } | ||
1463 | |||
1464 | if (ifidx == 1) { | ||
1465 | BRCMF_TRACE(("%s ACCESS POINT MAC:\n", __func__)); | ||
1466 | /* ACCESSPOINT INTERFACE CASE */ | ||
1467 | temp_addr[0] |= 0X02; /* set bit 2 , | ||
1468 | - Locally Administered address */ | ||
1469 | |||
1470 | } | ||
1471 | net->hard_header_len = ETH_HLEN + drvr_priv->pub.hdrlen; | ||
1472 | net->ethtool_ops = &brcmf_ethtool_ops; | ||
1473 | |||
1474 | drvr_priv->pub.rxsz = net->mtu + net->hard_header_len + | ||
1475 | drvr_priv->pub.hdrlen; | ||
1476 | |||
1477 | memcpy(net->dev_addr, temp_addr, ETH_ALEN); | ||
1478 | |||
1479 | if (register_netdev(net) != 0) { | ||
1480 | BRCMF_ERROR(("%s: couldn't register the net device\n", | ||
1481 | __func__)); | ||
1482 | goto fail; | ||
1483 | } | ||
1484 | |||
1485 | BRCMF_INFO(("%s: Broadcom Dongle Host Driver\n", net->name)); | ||
1486 | |||
1487 | return 0; | ||
1488 | |||
1489 | fail: | ||
1490 | net->netdev_ops = NULL; | ||
1491 | return -EBADE; | ||
1492 | } | ||
1493 | |||
1494 | static void brcmf_bus_detach(struct brcmf_pub *drvr) | ||
1495 | { | ||
1496 | struct brcmf_info *drvr_priv; | ||
1497 | |||
1498 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
1499 | |||
1500 | if (drvr) { | ||
1501 | drvr_priv = drvr->info; | ||
1502 | if (drvr_priv) { | ||
1503 | /* Stop the protocol module */ | ||
1504 | brcmf_proto_stop(&drvr_priv->pub); | ||
1505 | |||
1506 | /* Stop the bus module */ | ||
1507 | brcmf_sdbrcm_bus_stop(drvr_priv->pub.bus, true); | ||
1508 | } | ||
1509 | } | ||
1510 | } | ||
1511 | |||
1512 | void brcmf_detach(struct brcmf_pub *drvr) | ||
1513 | { | ||
1514 | struct brcmf_info *drvr_priv; | ||
1515 | |||
1516 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
1517 | |||
1518 | if (drvr) { | ||
1519 | drvr_priv = drvr->info; | ||
1520 | if (drvr_priv) { | ||
1521 | struct brcmf_if *ifp; | ||
1522 | int i; | ||
1523 | |||
1524 | for (i = 1; i < BRCMF_MAX_IFS; i++) | ||
1525 | if (drvr_priv->iflist[i]) | ||
1526 | brcmf_del_if(drvr_priv, i); | ||
1527 | |||
1528 | ifp = drvr_priv->iflist[0]; | ||
1529 | if (ifp->net->netdev_ops == &brcmf_netdev_ops_pri) { | ||
1530 | brcmf_netdev_stop(ifp->net); | ||
1531 | unregister_netdev(ifp->net); | ||
1532 | } | ||
1533 | |||
1534 | if (drvr_priv->sysioc_tsk) { | ||
1535 | send_sig(SIGTERM, drvr_priv->sysioc_tsk, 1); | ||
1536 | kthread_stop(drvr_priv->sysioc_tsk); | ||
1537 | drvr_priv->sysioc_tsk = NULL; | ||
1538 | } | ||
1539 | |||
1540 | brcmf_bus_detach(drvr); | ||
1541 | |||
1542 | if (drvr->prot) | ||
1543 | brcmf_proto_detach(drvr); | ||
1544 | |||
1545 | brcmf_cfg80211_detach(); | ||
1546 | |||
1547 | free_netdev(ifp->net); | ||
1548 | kfree(ifp); | ||
1549 | kfree(drvr_priv); | ||
1550 | } | ||
1551 | } | ||
1552 | } | ||
1553 | |||
1554 | static void __exit brcmf_module_cleanup(void) | ||
1555 | { | ||
1556 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
1557 | |||
1558 | brcmf_bus_unregister(); | ||
1559 | } | ||
1560 | |||
1561 | static int __init brcmf_module_init(void) | ||
1562 | { | ||
1563 | int error; | ||
1564 | |||
1565 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
1566 | |||
1567 | error = brcmf_bus_register(); | ||
1568 | |||
1569 | if (error) { | ||
1570 | BRCMF_ERROR(("%s: brcmf_bus_register failed\n", __func__)); | ||
1571 | goto failed; | ||
1572 | } | ||
1573 | return 0; | ||
1574 | |||
1575 | failed: | ||
1576 | return -EINVAL; | ||
1577 | } | ||
1578 | |||
1579 | module_init(brcmf_module_init); | ||
1580 | module_exit(brcmf_module_cleanup); | ||
1581 | |||
1582 | int brcmf_os_proto_block(struct brcmf_pub *drvr) | ||
1583 | { | ||
1584 | struct brcmf_info *drvr_priv = drvr->info; | ||
1585 | |||
1586 | if (drvr_priv) { | ||
1587 | down(&drvr_priv->proto_sem); | ||
1588 | return 1; | ||
1589 | } | ||
1590 | return 0; | ||
1591 | } | ||
1592 | |||
1593 | int brcmf_os_proto_unblock(struct brcmf_pub *drvr) | ||
1594 | { | ||
1595 | struct brcmf_info *drvr_priv = drvr->info; | ||
1596 | |||
1597 | if (drvr_priv) { | ||
1598 | up(&drvr_priv->proto_sem); | ||
1599 | return 1; | ||
1600 | } | ||
1601 | |||
1602 | return 0; | ||
1603 | } | ||
1604 | |||
1605 | unsigned int brcmf_os_get_ioctl_resp_timeout(void) | ||
1606 | { | ||
1607 | return (unsigned int)brcmf_ioctl_timeout_msec; | ||
1608 | } | ||
1609 | |||
1610 | void brcmf_os_set_ioctl_resp_timeout(unsigned int timeout_msec) | ||
1611 | { | ||
1612 | brcmf_ioctl_timeout_msec = (int)timeout_msec; | ||
1613 | } | ||
1614 | |||
1615 | int brcmf_os_ioctl_resp_wait(struct brcmf_pub *drvr, uint *condition, | ||
1616 | bool *pending) | ||
1617 | { | ||
1618 | struct brcmf_info *drvr_priv = drvr->info; | ||
1619 | DECLARE_WAITQUEUE(wait, current); | ||
1620 | int timeout = brcmf_ioctl_timeout_msec; | ||
1621 | |||
1622 | /* Convert timeout in millsecond to jiffies */ | ||
1623 | timeout = timeout * HZ / 1000; | ||
1624 | |||
1625 | /* Wait until control frame is available */ | ||
1626 | add_wait_queue(&drvr_priv->ioctl_resp_wait, &wait); | ||
1627 | set_current_state(TASK_INTERRUPTIBLE); | ||
1628 | |||
1629 | while (!(*condition) && (!signal_pending(current) && timeout)) | ||
1630 | timeout = schedule_timeout(timeout); | ||
1631 | |||
1632 | if (signal_pending(current)) | ||
1633 | *pending = true; | ||
1634 | |||
1635 | set_current_state(TASK_RUNNING); | ||
1636 | remove_wait_queue(&drvr_priv->ioctl_resp_wait, &wait); | ||
1637 | |||
1638 | return timeout; | ||
1639 | } | ||
1640 | |||
1641 | int brcmf_os_ioctl_resp_wake(struct brcmf_pub *drvr) | ||
1642 | { | ||
1643 | struct brcmf_info *drvr_priv = drvr->info; | ||
1644 | |||
1645 | if (waitqueue_active(&drvr_priv->ioctl_resp_wait)) | ||
1646 | wake_up_interruptible(&drvr_priv->ioctl_resp_wait); | ||
1647 | |||
1648 | return 0; | ||
1649 | } | ||
1650 | |||
1651 | static int brcmf_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata, | ||
1652 | struct brcmf_event_msg *event, void **data) | ||
1653 | { | ||
1654 | int bcmerror = 0; | ||
1655 | |||
1656 | bcmerror = brcmf_c_host_event(drvr_priv, ifidx, pktdata, event, data); | ||
1657 | if (bcmerror != 0) | ||
1658 | return bcmerror; | ||
1659 | |||
1660 | if (drvr_priv->iflist[*ifidx]->net) | ||
1661 | brcmf_cfg80211_event(drvr_priv->iflist[*ifidx]->net, | ||
1662 | event, *data); | ||
1663 | |||
1664 | return bcmerror; | ||
1665 | } | ||
1666 | |||
1667 | int brcmf_netdev_reset(struct net_device *dev, u8 flag) | ||
1668 | { | ||
1669 | struct brcmf_info *drvr_priv = *(struct brcmf_info **)netdev_priv(dev); | ||
1670 | |||
1671 | brcmf_bus_devreset(&drvr_priv->pub, flag); | ||
1672 | |||
1673 | return 1; | ||
1674 | } | ||
1675 | |||
1676 | static int brcmf_get_pend_8021x_cnt(struct brcmf_info *drvr_priv) | ||
1677 | { | ||
1678 | return atomic_read(&drvr_priv->pend_8021x_cnt); | ||
1679 | } | ||
1680 | |||
1681 | #define MAX_WAIT_FOR_8021X_TX 10 | ||
1682 | |||
1683 | int brcmf_netdev_wait_pend8021x(struct net_device *dev) | ||
1684 | { | ||
1685 | struct brcmf_info *drvr_priv = *(struct brcmf_info **)netdev_priv(dev); | ||
1686 | int timeout = 10 * HZ / 1000; | ||
1687 | int ntimes = MAX_WAIT_FOR_8021X_TX; | ||
1688 | int pend = brcmf_get_pend_8021x_cnt(drvr_priv); | ||
1689 | |||
1690 | while (ntimes && pend) { | ||
1691 | if (pend) { | ||
1692 | set_current_state(TASK_INTERRUPTIBLE); | ||
1693 | schedule_timeout(timeout); | ||
1694 | set_current_state(TASK_RUNNING); | ||
1695 | ntimes--; | ||
1696 | } | ||
1697 | pend = brcmf_get_pend_8021x_cnt(drvr_priv); | ||
1698 | } | ||
1699 | return pend; | ||
1700 | } | ||
1701 | |||
1702 | #ifdef BCMDBG | ||
1703 | int brcmf_write_to_file(struct brcmf_pub *drvr, u8 *buf, int size) | ||
1704 | { | ||
1705 | int ret = 0; | ||
1706 | struct file *fp; | ||
1707 | mm_segment_t old_fs; | ||
1708 | loff_t pos = 0; | ||
1709 | |||
1710 | /* change to KERNEL_DS address limit */ | ||
1711 | old_fs = get_fs(); | ||
1712 | set_fs(KERNEL_DS); | ||
1713 | |||
1714 | /* open file to write */ | ||
1715 | fp = filp_open("/tmp/mem_dump", O_WRONLY | O_CREAT, 0640); | ||
1716 | if (!fp) { | ||
1717 | BRCMF_ERROR(("%s: open file error\n", __func__)); | ||
1718 | ret = -1; | ||
1719 | goto exit; | ||
1720 | } | ||
1721 | |||
1722 | /* Write buf to file */ | ||
1723 | fp->f_op->write(fp, buf, size, &pos); | ||
1724 | |||
1725 | exit: | ||
1726 | /* free buf before return */ | ||
1727 | kfree(buf); | ||
1728 | /* close file before return */ | ||
1729 | if (fp) | ||
1730 | filp_close(fp, current->files); | ||
1731 | /* restore previous address limit */ | ||
1732 | set_fs(old_fs); | ||
1733 | |||
1734 | return ret; | ||
1735 | } | ||
1736 | #endif /* BCMDBG */ | ||
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_proto.h b/drivers/staging/brcm80211/brcmfmac/dhd_proto.h new file mode 100644 index 00000000000..ff788b37afd --- /dev/null +++ b/drivers/staging/brcm80211/brcmfmac/dhd_proto.h | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #ifndef _BRCMF_PROTO_H_ | ||
18 | #define _BRCMF_PROTO_H_ | ||
19 | |||
20 | #ifndef IOCTL_RESP_TIMEOUT | ||
21 | #define IOCTL_RESP_TIMEOUT 2000 /* In milli second */ | ||
22 | #endif | ||
23 | |||
24 | #ifndef IOCTL_CHIP_ACTIVE_TIMEOUT | ||
25 | #define IOCTL_CHIP_ACTIVE_TIMEOUT 10 /* In milli second */ | ||
26 | #endif | ||
27 | |||
28 | /* | ||
29 | * Exported from the brcmf protocol module (brcmf_cdc) | ||
30 | */ | ||
31 | |||
32 | /* Linkage, sets prot link and updates hdrlen in pub */ | ||
33 | extern int brcmf_proto_attach(struct brcmf_pub *drvr); | ||
34 | |||
35 | /* Unlink, frees allocated protocol memory (including brcmf_proto) */ | ||
36 | extern void brcmf_proto_detach(struct brcmf_pub *drvr); | ||
37 | |||
38 | /* Initialize protocol: sync w/dongle state. | ||
39 | * Sets dongle media info (iswl, drv_version, mac address). | ||
40 | */ | ||
41 | extern int brcmf_proto_init(struct brcmf_pub *drvr); | ||
42 | |||
43 | /* Stop protocol: sync w/dongle state. */ | ||
44 | extern void brcmf_proto_stop(struct brcmf_pub *drvr); | ||
45 | |||
46 | /* Add any protocol-specific data header. | ||
47 | * Caller must reserve prot_hdrlen prepend space. | ||
48 | */ | ||
49 | extern void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx, | ||
50 | struct sk_buff *txp); | ||
51 | |||
52 | /* Remove any protocol-specific data header. */ | ||
53 | extern int brcmf_proto_hdrpull(struct brcmf_pub *, int *ifidx, | ||
54 | struct sk_buff *rxp); | ||
55 | |||
56 | /* Use protocol to issue ioctl to dongle */ | ||
57 | extern int brcmf_proto_ioctl(struct brcmf_pub *drvr, int ifidx, | ||
58 | struct brcmf_ioctl *ioc, void *buf, int len); | ||
59 | |||
60 | /* Add prot dump output to a buffer */ | ||
61 | extern void brcmf_proto_dump(struct brcmf_pub *drvr, | ||
62 | struct brcmu_strbuf *strbuf); | ||
63 | |||
64 | /* Update local copy of dongle statistics */ | ||
65 | extern void brcmf_proto_dstats(struct brcmf_pub *drvr); | ||
66 | |||
67 | extern int brcmf_c_ioctl(struct brcmf_pub *drvr, struct brcmf_c_ioctl *ioc, | ||
68 | void *buf, uint buflen); | ||
69 | |||
70 | extern int brcmf_c_preinit_ioctls(struct brcmf_pub *drvr); | ||
71 | |||
72 | extern int brcmf_proto_cdc_set_ioctl(struct brcmf_pub *drvr, int ifidx, | ||
73 | uint cmd, void *buf, uint len); | ||
74 | |||
75 | #endif /* _BRCMF_PROTO_H_ */ | ||
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c new file mode 100644 index 00000000000..7fa95b6213c --- /dev/null +++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c | |||
@@ -0,0 +1,6772 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/types.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/kthread.h> | ||
20 | #include <linux/printk.h> | ||
21 | #include <linux/pci_ids.h> | ||
22 | #include <linux/netdevice.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/mmc/sdio.h> | ||
26 | #include <linux/mmc/sdio_func.h> | ||
27 | #include <linux/semaphore.h> | ||
28 | #include <linux/firmware.h> | ||
29 | #include <asm/unaligned.h> | ||
30 | #include <defs.h> | ||
31 | #include <brcmu_wifi.h> | ||
32 | #include <brcmu_utils.h> | ||
33 | #include <brcm_hw_ids.h> | ||
34 | #include <soc.h> | ||
35 | #include "sdio_host.h" | ||
36 | |||
37 | /* register access macros */ | ||
38 | #ifndef __BIG_ENDIAN | ||
39 | #ifndef __mips__ | ||
40 | #define R_REG(r, typ) \ | ||
41 | brcmf_sdcard_reg_read(NULL, (r), sizeof(typ)) | ||
42 | #else /* __mips__ */ | ||
43 | #define R_REG(r, typ) \ | ||
44 | ({ \ | ||
45 | __typeof(*(r)) __osl_v; \ | ||
46 | __asm__ __volatile__("sync"); \ | ||
47 | __osl_v = brcmf_sdcard_reg_read(NULL, (r),\ | ||
48 | sizeof(typ)); \ | ||
49 | __asm__ __volatile__("sync"); \ | ||
50 | __osl_v; \ | ||
51 | }) | ||
52 | #endif /* __mips__ */ | ||
53 | |||
54 | #else /* __BIG_ENDIAN */ | ||
55 | #define R_REG(r, typ) \ | ||
56 | brcmf_sdcard_reg_read(NULL, (r), sizeof(typ)) | ||
57 | #endif /* __BIG_ENDIAN */ | ||
58 | |||
59 | #define OR_REG(r, v, typ) \ | ||
60 | brcmf_sdcard_reg_write(NULL, (r), sizeof(typ), R_REG(r, typ) | (v)) | ||
61 | |||
62 | #ifdef BCMDBG | ||
63 | |||
64 | /* ARM trap handling */ | ||
65 | |||
66 | /* Trap types defined by ARM (see arminc.h) */ | ||
67 | |||
68 | #if defined(__ARM_ARCH_4T__) | ||
69 | #define MAX_TRAP_TYPE (TR_FIQ + 1) | ||
70 | #elif defined(__ARM_ARCH_7M__) | ||
71 | #define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS) | ||
72 | #endif /* __ARM_ARCH_7M__ */ | ||
73 | |||
74 | /* The trap structure is defined here as offsets for assembly */ | ||
75 | #define TR_TYPE 0x00 | ||
76 | #define TR_EPC 0x04 | ||
77 | #define TR_CPSR 0x08 | ||
78 | #define TR_SPSR 0x0c | ||
79 | #define TR_REGS 0x10 | ||
80 | #define TR_REG(n) (TR_REGS + (n) * 4) | ||
81 | #define TR_SP TR_REG(13) | ||
82 | #define TR_LR TR_REG(14) | ||
83 | #define TR_PC TR_REG(15) | ||
84 | |||
85 | #define TRAP_T_SIZE 80 | ||
86 | |||
87 | struct brcmf_trap { | ||
88 | u32 type; | ||
89 | u32 epc; | ||
90 | u32 cpsr; | ||
91 | u32 spsr; | ||
92 | u32 r0; | ||
93 | u32 r1; | ||
94 | u32 r2; | ||
95 | u32 r3; | ||
96 | u32 r4; | ||
97 | u32 r5; | ||
98 | u32 r6; | ||
99 | u32 r7; | ||
100 | u32 r8; | ||
101 | u32 r9; | ||
102 | u32 r10; | ||
103 | u32 r11; | ||
104 | u32 r12; | ||
105 | u32 r13; | ||
106 | u32 r14; | ||
107 | u32 pc; | ||
108 | }; | ||
109 | |||
110 | #define CBUF_LEN (128) | ||
111 | |||
112 | struct rte_log { | ||
113 | u32 buf; /* Can't be pointer on (64-bit) hosts */ | ||
114 | uint buf_size; | ||
115 | uint idx; | ||
116 | char *_buf_compat; /* Redundant pointer for backward compat. */ | ||
117 | }; | ||
118 | |||
119 | struct rte_console { | ||
120 | /* Virtual UART | ||
121 | * When there is no UART (e.g. Quickturn), | ||
122 | * the host should write a complete | ||
123 | * input line directly into cbuf and then write | ||
124 | * the length into vcons_in. | ||
125 | * This may also be used when there is a real UART | ||
126 | * (at risk of conflicting with | ||
127 | * the real UART). vcons_out is currently unused. | ||
128 | */ | ||
129 | volatile uint vcons_in; | ||
130 | volatile uint vcons_out; | ||
131 | |||
132 | /* Output (logging) buffer | ||
133 | * Console output is written to a ring buffer log_buf at index log_idx. | ||
134 | * The host may read the output when it sees log_idx advance. | ||
135 | * Output will be lost if the output wraps around faster than the host | ||
136 | * polls. | ||
137 | */ | ||
138 | struct rte_log log; | ||
139 | |||
140 | /* Console input line buffer | ||
141 | * Characters are read one at a time into cbuf | ||
142 | * until <CR> is received, then | ||
143 | * the buffer is processed as a command line. | ||
144 | * Also used for virtual UART. | ||
145 | */ | ||
146 | uint cbuf_idx; | ||
147 | char cbuf[CBUF_LEN]; | ||
148 | }; | ||
149 | |||
150 | #endif /* BCMDBG */ | ||
151 | #include <chipcommon.h> | ||
152 | |||
153 | #include "dhd.h" | ||
154 | #include "dhd_bus.h" | ||
155 | #include "dhd_proto.h" | ||
156 | #include "dhd_dbg.h" | ||
157 | #include <bcmchip.h> | ||
158 | |||
159 | #define TXQLEN 2048 /* bulk tx queue length */ | ||
160 | #define TXHI (TXQLEN - 256) /* turn on flow control above TXHI */ | ||
161 | #define TXLOW (TXHI - 256) /* turn off flow control below TXLOW */ | ||
162 | #define PRIOMASK 7 | ||
163 | |||
164 | #define TXRETRIES 2 /* # of retries for tx frames */ | ||
165 | |||
166 | #define BRCMF_RXBOUND 50 /* Default for max rx frames in | ||
167 | one scheduling */ | ||
168 | |||
169 | #define BRCMF_TXBOUND 20 /* Default for max tx frames in | ||
170 | one scheduling */ | ||
171 | |||
172 | #define BRCMF_TXMINMAX 1 /* Max tx frames if rx still pending */ | ||
173 | |||
174 | #define MEMBLOCK 2048 /* Block size used for downloading | ||
175 | of dongle image */ | ||
176 | #define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold | ||
177 | biggest possible glom */ | ||
178 | |||
179 | #ifndef BRCMF_FIRSTREAD | ||
180 | #define BRCMF_FIRSTREAD 32 | ||
181 | #endif | ||
182 | |||
183 | #if !ISPOWEROF2(BRCMF_FIRSTREAD) | ||
184 | #error BRCMF_FIRSTREAD is not a power of 2! | ||
185 | #endif | ||
186 | |||
187 | /* SBSDIO_DEVICE_CTL */ | ||
188 | #define SBSDIO_DEVCTL_SETBUSY 0x01 /* 1: device will assert busy signal when | ||
189 | * receiving CMD53 | ||
190 | */ | ||
191 | #define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02 /* 1: assertion of sdio interrupt is | ||
192 | * synchronous to the sdio clock | ||
193 | */ | ||
194 | #define SBSDIO_DEVCTL_CA_INT_ONLY 0x04 /* 1: mask all interrupts to host | ||
195 | * except the chipActive (rev 8) | ||
196 | */ | ||
197 | #define SBSDIO_DEVCTL_PADS_ISO 0x08 /* 1: isolate internal sdio signals, put | ||
198 | * external pads in tri-state; requires | ||
199 | * sdio bus power cycle to clear (rev 9) | ||
200 | */ | ||
201 | #define SBSDIO_DEVCTL_SB_RST_CTL 0x30 /* Force SD->SB reset mapping (rev 11) */ | ||
202 | #define SBSDIO_DEVCTL_RST_CORECTL 0x00 /* Determined by CoreControl bit */ | ||
203 | #define SBSDIO_DEVCTL_RST_BPRESET 0x10 /* Force backplane reset */ | ||
204 | #define SBSDIO_DEVCTL_RST_NOBPRESET 0x20 /* Force no backplane reset */ | ||
205 | |||
206 | /* SBSDIO_FUNC1_CHIPCLKCSR */ | ||
207 | #define SBSDIO_FORCE_ALP 0x01 /* Force ALP request to backplane */ | ||
208 | #define SBSDIO_FORCE_HT 0x02 /* Force HT request to backplane */ | ||
209 | #define SBSDIO_FORCE_ILP 0x04 /* Force ILP request to backplane */ | ||
210 | #define SBSDIO_ALP_AVAIL_REQ 0x08 /* Make ALP ready (power up xtal) */ | ||
211 | #define SBSDIO_HT_AVAIL_REQ 0x10 /* Make HT ready (power up PLL) */ | ||
212 | #define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20 /* Squelch clock requests from HW */ | ||
213 | #define SBSDIO_ALP_AVAIL 0x40 /* Status: ALP is ready */ | ||
214 | #define SBSDIO_HT_AVAIL 0x80 /* Status: HT is ready */ | ||
215 | |||
216 | #define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL) | ||
217 | #define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS) | ||
218 | #define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS) | ||
219 | #define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval)) | ||
220 | #define SBSDIO_CLKAV(regval, alponly) (SBSDIO_ALPAV(regval) && \ | ||
221 | (alponly ? 1 : SBSDIO_HTAV(regval))) | ||
222 | /* direct(mapped) cis space */ | ||
223 | #define SBSDIO_CIS_BASE_COMMON 0x1000 /* MAPPED common CIS address */ | ||
224 | #define SBSDIO_CIS_SIZE_LIMIT 0x200 /* maximum bytes in one CIS */ | ||
225 | #define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF /* cis offset addr is < 17 bits */ | ||
226 | |||
227 | #define SBSDIO_CIS_MANFID_TUPLE_LEN 6 /* manfid tuple length, include tuple, | ||
228 | * link bytes | ||
229 | */ | ||
230 | |||
231 | /* intstatus */ | ||
232 | #define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */ | ||
233 | #define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */ | ||
234 | #define I_SMB_SW2 (1 << 2) /* To SB Mail S/W interrupt 2 */ | ||
235 | #define I_SMB_SW3 (1 << 3) /* To SB Mail S/W interrupt 3 */ | ||
236 | #define I_SMB_SW_MASK 0x0000000f /* To SB Mail S/W interrupts mask */ | ||
237 | #define I_SMB_SW_SHIFT 0 /* To SB Mail S/W interrupts shift */ | ||
238 | #define I_HMB_SW0 (1 << 4) /* To Host Mail S/W interrupt 0 */ | ||
239 | #define I_HMB_SW1 (1 << 5) /* To Host Mail S/W interrupt 1 */ | ||
240 | #define I_HMB_SW2 (1 << 6) /* To Host Mail S/W interrupt 2 */ | ||
241 | #define I_HMB_SW3 (1 << 7) /* To Host Mail S/W interrupt 3 */ | ||
242 | #define I_HMB_SW_MASK 0x000000f0 /* To Host Mail S/W interrupts mask */ | ||
243 | #define I_HMB_SW_SHIFT 4 /* To Host Mail S/W interrupts shift */ | ||
244 | #define I_WR_OOSYNC (1 << 8) /* Write Frame Out Of Sync */ | ||
245 | #define I_RD_OOSYNC (1 << 9) /* Read Frame Out Of Sync */ | ||
246 | #define I_PC (1 << 10) /* descriptor error */ | ||
247 | #define I_PD (1 << 11) /* data error */ | ||
248 | #define I_DE (1 << 12) /* Descriptor protocol Error */ | ||
249 | #define I_RU (1 << 13) /* Receive descriptor Underflow */ | ||
250 | #define I_RO (1 << 14) /* Receive fifo Overflow */ | ||
251 | #define I_XU (1 << 15) /* Transmit fifo Underflow */ | ||
252 | #define I_RI (1 << 16) /* Receive Interrupt */ | ||
253 | #define I_BUSPWR (1 << 17) /* SDIO Bus Power Change (rev 9) */ | ||
254 | #define I_XMTDATA_AVAIL (1 << 23) /* bits in fifo */ | ||
255 | #define I_XI (1 << 24) /* Transmit Interrupt */ | ||
256 | #define I_RF_TERM (1 << 25) /* Read Frame Terminate */ | ||
257 | #define I_WF_TERM (1 << 26) /* Write Frame Terminate */ | ||
258 | #define I_PCMCIA_XU (1 << 27) /* PCMCIA Transmit FIFO Underflow */ | ||
259 | #define I_SBINT (1 << 28) /* sbintstatus Interrupt */ | ||
260 | #define I_CHIPACTIVE (1 << 29) /* chip from doze to active state */ | ||
261 | #define I_SRESET (1 << 30) /* CCCR RES interrupt */ | ||
262 | #define I_IOE2 (1U << 31) /* CCCR IOE2 Bit Changed */ | ||
263 | #define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU) | ||
264 | #define I_DMA (I_RI | I_XI | I_ERRORS) | ||
265 | |||
266 | /* corecontrol */ | ||
267 | #define CC_CISRDY (1 << 0) /* CIS Ready */ | ||
268 | #define CC_BPRESEN (1 << 1) /* CCCR RES signal */ | ||
269 | #define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */ | ||
270 | #define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation */ | ||
271 | #define CC_XMTDATAAVAIL_MODE (1 << 4) | ||
272 | #define CC_XMTDATAAVAIL_CTRL (1 << 5) | ||
273 | |||
274 | /* SDA_FRAMECTRL */ | ||
275 | #define SFC_RF_TERM (1 << 0) /* Read Frame Terminate */ | ||
276 | #define SFC_WF_TERM (1 << 1) /* Write Frame Terminate */ | ||
277 | #define SFC_CRC4WOOS (1 << 2) /* CRC error for write out of sync */ | ||
278 | #define SFC_ABORTALL (1 << 3) /* Abort all in-progress frames */ | ||
279 | |||
280 | /* HW frame tag */ | ||
281 | #define SDPCM_FRAMETAG_LEN 4 /* 2 bytes len, 2 bytes check val */ | ||
282 | |||
283 | /* Total length of frame header for dongle protocol */ | ||
284 | #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) | ||
285 | #ifdef SDTEST | ||
286 | #define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + BRCMF_SDALIGN) | ||
287 | #else | ||
288 | #define SDPCM_RESERVE (SDPCM_HDRLEN + BRCMF_SDALIGN) | ||
289 | #endif | ||
290 | |||
291 | /* | ||
292 | * Software allocation of To SB Mailbox resources | ||
293 | */ | ||
294 | |||
295 | /* tosbmailbox bits corresponding to intstatus bits */ | ||
296 | #define SMB_NAK (1 << 0) /* Frame NAK */ | ||
297 | #define SMB_INT_ACK (1 << 1) /* Host Interrupt ACK */ | ||
298 | #define SMB_USE_OOB (1 << 2) /* Use OOB Wakeup */ | ||
299 | #define SMB_DEV_INT (1 << 3) /* Miscellaneous Interrupt */ | ||
300 | |||
301 | /* tosbmailboxdata */ | ||
302 | #define SMB_DATA_VERSION_SHIFT 16 /* host protocol version */ | ||
303 | |||
304 | /* | ||
305 | * Software allocation of To Host Mailbox resources | ||
306 | */ | ||
307 | |||
308 | /* intstatus bits */ | ||
309 | #define I_HMB_FC_STATE I_HMB_SW0 /* Flow Control State */ | ||
310 | #define I_HMB_FC_CHANGE I_HMB_SW1 /* Flow Control State Changed */ | ||
311 | #define I_HMB_FRAME_IND I_HMB_SW2 /* Frame Indication */ | ||
312 | #define I_HMB_HOST_INT I_HMB_SW3 /* Miscellaneous Interrupt */ | ||
313 | |||
314 | /* tohostmailboxdata */ | ||
315 | #define HMB_DATA_NAKHANDLED 1 /* retransmit NAK'd frame */ | ||
316 | #define HMB_DATA_DEVREADY 2 /* talk to host after enable */ | ||
317 | #define HMB_DATA_FC 4 /* per prio flowcontrol update flag */ | ||
318 | #define HMB_DATA_FWREADY 8 /* fw ready for protocol activity */ | ||
319 | |||
320 | #define HMB_DATA_FCDATA_MASK 0xff000000 | ||
321 | #define HMB_DATA_FCDATA_SHIFT 24 | ||
322 | |||
323 | #define HMB_DATA_VERSION_MASK 0x00ff0000 | ||
324 | #define HMB_DATA_VERSION_SHIFT 16 | ||
325 | |||
326 | /* | ||
327 | * Software-defined protocol header | ||
328 | */ | ||
329 | |||
330 | /* Current protocol version */ | ||
331 | #define SDPCM_PROT_VERSION 4 | ||
332 | |||
333 | /* SW frame header */ | ||
334 | #define SDPCM_PACKET_SEQUENCE(p) (((u8 *)p)[0] & 0xff) | ||
335 | |||
336 | #define SDPCM_CHANNEL_MASK 0x00000f00 | ||
337 | #define SDPCM_CHANNEL_SHIFT 8 | ||
338 | #define SDPCM_PACKET_CHANNEL(p) (((u8 *)p)[1] & 0x0f) | ||
339 | |||
340 | #define SDPCM_NEXTLEN_OFFSET 2 | ||
341 | |||
342 | /* Data Offset from SOF (HW Tag, SW Tag, Pad) */ | ||
343 | #define SDPCM_DOFFSET_OFFSET 3 /* Data Offset */ | ||
344 | #define SDPCM_DOFFSET_VALUE(p) (((u8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff) | ||
345 | #define SDPCM_DOFFSET_MASK 0xff000000 | ||
346 | #define SDPCM_DOFFSET_SHIFT 24 | ||
347 | #define SDPCM_FCMASK_OFFSET 4 /* Flow control */ | ||
348 | #define SDPCM_FCMASK_VALUE(p) (((u8 *)p)[SDPCM_FCMASK_OFFSET] & 0xff) | ||
349 | #define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */ | ||
350 | #define SDPCM_WINDOW_VALUE(p) (((u8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff) | ||
351 | |||
352 | #define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */ | ||
353 | |||
354 | /* logical channel numbers */ | ||
355 | #define SDPCM_CONTROL_CHANNEL 0 /* Control channel Id */ | ||
356 | #define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication Channel Id */ | ||
357 | #define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv Channel Id */ | ||
358 | #define SDPCM_GLOM_CHANNEL 3 /* For coalesced packets */ | ||
359 | #define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */ | ||
360 | |||
361 | #define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for 8bit frame seq */ | ||
362 | |||
363 | #define SDPCM_GLOMDESC(p) (((u8 *)p)[1] & 0x80) | ||
364 | |||
365 | /* For TEST_CHANNEL packets, define another 4-byte header */ | ||
366 | #define SDPCM_TEST_HDRLEN 4 /* | ||
367 | * Generally: Cmd(1), Ext(1), Len(2); | ||
368 | * Semantics of Ext byte depend on | ||
369 | * command. Len is current or requested | ||
370 | * frame length, not including test | ||
371 | * header; sent little-endian. | ||
372 | */ | ||
373 | #define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext:pattern id. */ | ||
374 | #define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext:pattern id. */ | ||
375 | #define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext:pattern id. */ | ||
376 | #define SDPCM_TEST_BURST 0x04 /* | ||
377 | * Receiver to send a burst. | ||
378 | * Ext is a frame count | ||
379 | */ | ||
380 | #define SDPCM_TEST_SEND 0x05 /* | ||
381 | * Receiver sets send mode. | ||
382 | * Ext is boolean on/off | ||
383 | */ | ||
384 | |||
385 | /* Handy macro for filling in datagen packets with a pattern */ | ||
386 | #define SDPCM_TEST_FILL(byteno, id) ((u8)(id + byteno)) | ||
387 | |||
388 | /* | ||
389 | * Shared structure between dongle and the host. | ||
390 | * The structure contains pointers to trap or assert information. | ||
391 | */ | ||
392 | #define SDPCM_SHARED_VERSION 0x0002 | ||
393 | #define SDPCM_SHARED_VERSION_MASK 0x00FF | ||
394 | #define SDPCM_SHARED_ASSERT_BUILT 0x0100 | ||
395 | #define SDPCM_SHARED_ASSERT 0x0200 | ||
396 | #define SDPCM_SHARED_TRAP 0x0400 | ||
397 | |||
398 | |||
399 | /* Space for header read, limit for data packets */ | ||
400 | #ifndef MAX_HDR_READ | ||
401 | #define MAX_HDR_READ 32 | ||
402 | #endif | ||
403 | #if !ISPOWEROF2(MAX_HDR_READ) | ||
404 | #error MAX_HDR_READ is not a power of 2! | ||
405 | #endif | ||
406 | |||
407 | #define MAX_RX_DATASZ 2048 | ||
408 | |||
409 | /* Maximum milliseconds to wait for F2 to come up */ | ||
410 | #define BRCMF_WAIT_F2RDY 3000 | ||
411 | |||
412 | /* Bump up limit on waiting for HT to account for first startup; | ||
413 | * if the image is doing a CRC calculation before programming the PMU | ||
414 | * for HT availability, it could take a couple hundred ms more, so | ||
415 | * max out at a 1 second (1000000us). | ||
416 | */ | ||
417 | #if (PMU_MAX_TRANSITION_DLY <= 1000000) | ||
418 | #undef PMU_MAX_TRANSITION_DLY | ||
419 | #define PMU_MAX_TRANSITION_DLY 1000000 | ||
420 | #endif | ||
421 | |||
422 | /* Value for ChipClockCSR during initial setup */ | ||
423 | #define BRCMF_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | \ | ||
424 | SBSDIO_ALP_AVAIL_REQ) | ||
425 | |||
426 | /* Flags for SDH calls */ | ||
427 | #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) | ||
428 | |||
429 | /* sbimstate */ | ||
430 | #define SBIM_IBE 0x20000 /* inbanderror */ | ||
431 | #define SBIM_TO 0x40000 /* timeout */ | ||
432 | #define SBIM_BY 0x01800000 /* busy (sonics >= 2.3) */ | ||
433 | #define SBIM_RJ 0x02000000 /* reject (sonics >= 2.3) */ | ||
434 | |||
435 | /* sbtmstatelow */ | ||
436 | #define SBTML_RESET 0x0001 /* reset */ | ||
437 | #define SBTML_REJ_MASK 0x0006 /* reject field */ | ||
438 | #define SBTML_REJ 0x0002 /* reject */ | ||
439 | #define SBTML_TMPREJ 0x0004 /* temporary reject, for error recovery */ | ||
440 | |||
441 | #define SBTML_SICF_SHIFT 16 /* Shift to locate the SI control flags in sbtml */ | ||
442 | |||
443 | /* sbtmstatehigh */ | ||
444 | #define SBTMH_SERR 0x0001 /* serror */ | ||
445 | #define SBTMH_INT 0x0002 /* interrupt */ | ||
446 | #define SBTMH_BUSY 0x0004 /* busy */ | ||
447 | #define SBTMH_TO 0x0020 /* timeout (sonics >= 2.3) */ | ||
448 | |||
449 | #define SBTMH_SISF_SHIFT 16 /* Shift to locate the SI status flags in sbtmh */ | ||
450 | |||
451 | /* sbidlow */ | ||
452 | #define SBIDL_INIT 0x80 /* initiator */ | ||
453 | |||
454 | /* sbidhigh */ | ||
455 | #define SBIDH_RC_MASK 0x000f /* revision code */ | ||
456 | #define SBIDH_RCE_MASK 0x7000 /* revision code extension field */ | ||
457 | #define SBIDH_RCE_SHIFT 8 | ||
458 | #define SBCOREREV(sbidh) \ | ||
459 | ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | ((sbidh) & SBIDH_RC_MASK)) | ||
460 | #define SBIDH_CC_MASK 0x8ff0 /* core code */ | ||
461 | #define SBIDH_CC_SHIFT 4 | ||
462 | #define SBIDH_VC_MASK 0xffff0000 /* vendor code */ | ||
463 | #define SBIDH_VC_SHIFT 16 | ||
464 | |||
465 | /* | ||
466 | * Conversion of 802.1D priority to precedence level | ||
467 | */ | ||
468 | #define PRIO2PREC(prio) \ | ||
469 | (((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? \ | ||
470 | ((prio^2)) : (prio)) | ||
471 | |||
472 | BRCMF_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep); | ||
473 | |||
474 | /* | ||
475 | * Core reg address translation. | ||
476 | * Both macro's returns a 32 bits byte address on the backplane bus. | ||
477 | */ | ||
478 | #define CORE_CC_REG(base, field) (base + offsetof(chipcregs_t, field)) | ||
479 | #define CORE_BUS_REG(base, field) \ | ||
480 | (base + offsetof(struct sdpcmd_regs, field)) | ||
481 | #define CORE_SB(base, field) \ | ||
482 | (base + SBCONFIGOFF + offsetof(struct sbconfig, field)) | ||
483 | |||
484 | /* core registers */ | ||
485 | struct sdpcmd_regs { | ||
486 | u32 corecontrol; /* 0x00, rev8 */ | ||
487 | u32 corestatus; /* rev8 */ | ||
488 | u32 PAD[1]; | ||
489 | u32 biststatus; /* rev8 */ | ||
490 | |||
491 | /* PCMCIA access */ | ||
492 | u16 pcmciamesportaladdr; /* 0x010, rev8 */ | ||
493 | u16 PAD[1]; | ||
494 | u16 pcmciamesportalmask; /* rev8 */ | ||
495 | u16 PAD[1]; | ||
496 | u16 pcmciawrframebc; /* rev8 */ | ||
497 | u16 PAD[1]; | ||
498 | u16 pcmciaunderflowtimer; /* rev8 */ | ||
499 | u16 PAD[1]; | ||
500 | |||
501 | /* interrupt */ | ||
502 | u32 intstatus; /* 0x020, rev8 */ | ||
503 | u32 hostintmask; /* rev8 */ | ||
504 | u32 intmask; /* rev8 */ | ||
505 | u32 sbintstatus; /* rev8 */ | ||
506 | u32 sbintmask; /* rev8 */ | ||
507 | u32 funcintmask; /* rev4 */ | ||
508 | u32 PAD[2]; | ||
509 | u32 tosbmailbox; /* 0x040, rev8 */ | ||
510 | u32 tohostmailbox; /* rev8 */ | ||
511 | u32 tosbmailboxdata; /* rev8 */ | ||
512 | u32 tohostmailboxdata; /* rev8 */ | ||
513 | |||
514 | /* synchronized access to registers in SDIO clock domain */ | ||
515 | u32 sdioaccess; /* 0x050, rev8 */ | ||
516 | u32 PAD[3]; | ||
517 | |||
518 | /* PCMCIA frame control */ | ||
519 | u8 pcmciaframectrl; /* 0x060, rev8 */ | ||
520 | u8 PAD[3]; | ||
521 | u8 pcmciawatermark; /* rev8 */ | ||
522 | u8 PAD[155]; | ||
523 | |||
524 | /* interrupt batching control */ | ||
525 | u32 intrcvlazy; /* 0x100, rev8 */ | ||
526 | u32 PAD[3]; | ||
527 | |||
528 | /* counters */ | ||
529 | u32 cmd52rd; /* 0x110, rev8 */ | ||
530 | u32 cmd52wr; /* rev8 */ | ||
531 | u32 cmd53rd; /* rev8 */ | ||
532 | u32 cmd53wr; /* rev8 */ | ||
533 | u32 abort; /* rev8 */ | ||
534 | u32 datacrcerror; /* rev8 */ | ||
535 | u32 rdoutofsync; /* rev8 */ | ||
536 | u32 wroutofsync; /* rev8 */ | ||
537 | u32 writebusy; /* rev8 */ | ||
538 | u32 readwait; /* rev8 */ | ||
539 | u32 readterm; /* rev8 */ | ||
540 | u32 writeterm; /* rev8 */ | ||
541 | u32 PAD[40]; | ||
542 | u32 clockctlstatus; /* rev8 */ | ||
543 | u32 PAD[7]; | ||
544 | |||
545 | u32 PAD[128]; /* DMA engines */ | ||
546 | |||
547 | /* SDIO/PCMCIA CIS region */ | ||
548 | char cis[512]; /* 0x400-0x5ff, rev6 */ | ||
549 | |||
550 | /* PCMCIA function control registers */ | ||
551 | char pcmciafcr[256]; /* 0x600-6ff, rev6 */ | ||
552 | u16 PAD[55]; | ||
553 | |||
554 | /* PCMCIA backplane access */ | ||
555 | u16 backplanecsr; /* 0x76E, rev6 */ | ||
556 | u16 backplaneaddr0; /* rev6 */ | ||
557 | u16 backplaneaddr1; /* rev6 */ | ||
558 | u16 backplaneaddr2; /* rev6 */ | ||
559 | u16 backplaneaddr3; /* rev6 */ | ||
560 | u16 backplanedata0; /* rev6 */ | ||
561 | u16 backplanedata1; /* rev6 */ | ||
562 | u16 backplanedata2; /* rev6 */ | ||
563 | u16 backplanedata3; /* rev6 */ | ||
564 | u16 PAD[31]; | ||
565 | |||
566 | /* sprom "size" & "blank" info */ | ||
567 | u16 spromstatus; /* 0x7BE, rev2 */ | ||
568 | u32 PAD[464]; | ||
569 | |||
570 | u16 PAD[0x80]; | ||
571 | }; | ||
572 | |||
573 | #ifdef BCMDBG | ||
574 | /* Device console log buffer state */ | ||
575 | struct brcmf_console { | ||
576 | uint count; /* Poll interval msec counter */ | ||
577 | uint log_addr; /* Log struct address (fixed) */ | ||
578 | struct rte_log log; /* Log struct (host copy) */ | ||
579 | uint bufsize; /* Size of log buffer */ | ||
580 | u8 *buf; /* Log buffer (host copy) */ | ||
581 | uint last; /* Last buffer read index */ | ||
582 | }; | ||
583 | #endif /* BCMDBG */ | ||
584 | |||
585 | struct sdpcm_shared { | ||
586 | u32 flags; | ||
587 | u32 trap_addr; | ||
588 | u32 assert_exp_addr; | ||
589 | u32 assert_file_addr; | ||
590 | u32 assert_line; | ||
591 | u32 console_addr; /* Address of struct rte_console */ | ||
592 | u32 msgtrace_addr; | ||
593 | u8 tag[32]; | ||
594 | }; | ||
595 | |||
596 | |||
597 | /* misc chip info needed by some of the routines */ | ||
598 | struct chip_info { | ||
599 | u32 chip; | ||
600 | u32 chiprev; | ||
601 | u32 cccorebase; | ||
602 | u32 ccrev; | ||
603 | u32 cccaps; | ||
604 | u32 buscorebase; /* 32 bits backplane bus address */ | ||
605 | u32 buscorerev; | ||
606 | u32 buscoretype; | ||
607 | u32 ramcorebase; | ||
608 | u32 armcorebase; | ||
609 | u32 pmurev; | ||
610 | u32 ramsize; | ||
611 | }; | ||
612 | |||
613 | /* Private data for SDIO bus interaction */ | ||
614 | struct brcmf_bus { | ||
615 | struct brcmf_pub *drvr; | ||
616 | |||
617 | struct brcmf_sdio_card *card; /* Handle for sdio card calls */ | ||
618 | struct chip_info *ci; /* Chip info struct */ | ||
619 | char *vars; /* Variables (from CIS and/or other) */ | ||
620 | uint varsz; /* Size of variables buffer */ | ||
621 | |||
622 | u32 ramsize; /* Size of RAM in SOCRAM (bytes) */ | ||
623 | u32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */ | ||
624 | |||
625 | u32 bus; /* gSPI or SDIO bus */ | ||
626 | u32 hostintmask; /* Copy of Host Interrupt Mask */ | ||
627 | u32 intstatus; /* Intstatus bits (events) pending */ | ||
628 | bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ | ||
629 | bool fcstate; /* State of dongle flow-control */ | ||
630 | |||
631 | u16 cl_devid; /* cached devid for brcmf_sdio_probe_attach() */ | ||
632 | |||
633 | uint blocksize; /* Block size of SDIO transfers */ | ||
634 | uint roundup; /* Max roundup limit */ | ||
635 | |||
636 | struct pktq txq; /* Queue length used for flow-control */ | ||
637 | u8 flowcontrol; /* per prio flow control bitmask */ | ||
638 | u8 tx_seq; /* Transmit sequence number (next) */ | ||
639 | u8 tx_max; /* Maximum transmit sequence allowed */ | ||
640 | |||
641 | u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN]; | ||
642 | u8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ | ||
643 | u16 nextlen; /* Next Read Len from last header */ | ||
644 | u8 rx_seq; /* Receive sequence number (expected) */ | ||
645 | bool rxskip; /* Skip receive (awaiting NAK ACK) */ | ||
646 | |||
647 | struct sk_buff *glomd; /* Packet containing glomming descriptor */ | ||
648 | struct sk_buff *glom; /* Packet chain for glommed superframe */ | ||
649 | uint glomerr; /* Glom packet read errors */ | ||
650 | |||
651 | u8 *rxbuf; /* Buffer for receiving control packets */ | ||
652 | uint rxblen; /* Allocated length of rxbuf */ | ||
653 | u8 *rxctl; /* Aligned pointer into rxbuf */ | ||
654 | u8 *databuf; /* Buffer for receiving big glom packet */ | ||
655 | u8 *dataptr; /* Aligned pointer into databuf */ | ||
656 | uint rxlen; /* Length of valid data in buffer */ | ||
657 | |||
658 | u8 sdpcm_ver; /* Bus protocol reported by dongle */ | ||
659 | |||
660 | bool intr; /* Use interrupts */ | ||
661 | bool poll; /* Use polling */ | ||
662 | bool ipend; /* Device interrupt is pending */ | ||
663 | bool intdis; /* Interrupts disabled by isr */ | ||
664 | uint intrcount; /* Count of device interrupt callbacks */ | ||
665 | uint lastintrs; /* Count as of last watchdog timer */ | ||
666 | uint spurious; /* Count of spurious interrupts */ | ||
667 | uint pollrate; /* Ticks between device polls */ | ||
668 | uint polltick; /* Tick counter */ | ||
669 | uint pollcnt; /* Count of active polls */ | ||
670 | |||
671 | #ifdef BCMDBG | ||
672 | struct brcmf_console console; /* Console output polling support */ | ||
673 | uint console_addr; /* Console address from shared struct */ | ||
674 | #endif /* BCMDBG */ | ||
675 | |||
676 | uint regfails; /* Count of R_REG failures */ | ||
677 | |||
678 | uint clkstate; /* State of sd and backplane clock(s) */ | ||
679 | bool activity; /* Activity flag for clock down */ | ||
680 | s32 idletime; /* Control for activity timeout */ | ||
681 | s32 idlecount; /* Activity timeout counter */ | ||
682 | s32 idleclock; /* How to set bus driver when idle */ | ||
683 | s32 sd_rxchain; | ||
684 | bool use_rxchain; /* If brcmf should use PKT chains */ | ||
685 | bool sleeping; /* Is SDIO bus sleeping? */ | ||
686 | bool rxflow_mode; /* Rx flow control mode */ | ||
687 | bool rxflow; /* Is rx flow control on */ | ||
688 | bool alp_only; /* Don't use HT clock (ALP only) */ | ||
689 | /* Field to decide if rx of control frames happen in rxbuf or lb-pool */ | ||
690 | bool usebufpool; | ||
691 | |||
692 | #ifdef SDTEST | ||
693 | /* external loopback */ | ||
694 | bool ext_loop; | ||
695 | u8 loopid; | ||
696 | |||
697 | /* pktgen configuration */ | ||
698 | uint pktgen_freq; /* Ticks between bursts */ | ||
699 | uint pktgen_count; /* Packets to send each burst */ | ||
700 | uint pktgen_print; /* Bursts between count displays */ | ||
701 | uint pktgen_total; /* Stop after this many */ | ||
702 | uint pktgen_minlen; /* Minimum packet data len */ | ||
703 | uint pktgen_maxlen; /* Maximum packet data len */ | ||
704 | uint pktgen_mode; /* Configured mode: tx, rx, or echo */ | ||
705 | uint pktgen_stop; /* Number of tx failures causing stop */ | ||
706 | |||
707 | /* active pktgen fields */ | ||
708 | uint pktgen_tick; /* Tick counter for bursts */ | ||
709 | uint pktgen_ptick; /* Burst counter for printing */ | ||
710 | uint pktgen_sent; /* Number of test packets generated */ | ||
711 | uint pktgen_rcvd; /* Number of test packets received */ | ||
712 | uint pktgen_fail; /* Number of failed send attempts */ | ||
713 | u16 pktgen_len; /* Length of next packet to send */ | ||
714 | #endif /* SDTEST */ | ||
715 | |||
716 | /* Some additional counters */ | ||
717 | uint tx_sderrs; /* Count of tx attempts with sd errors */ | ||
718 | uint fcqueued; /* Tx packets that got queued */ | ||
719 | uint rxrtx; /* Count of rtx requests (NAK to dongle) */ | ||
720 | uint rx_toolong; /* Receive frames too long to receive */ | ||
721 | uint rxc_errors; /* SDIO errors when reading control frames */ | ||
722 | uint rx_hdrfail; /* SDIO errors on header reads */ | ||
723 | uint rx_badhdr; /* Bad received headers (roosync?) */ | ||
724 | uint rx_badseq; /* Mismatched rx sequence number */ | ||
725 | uint fc_rcvd; /* Number of flow-control events received */ | ||
726 | uint fc_xoff; /* Number which turned on flow-control */ | ||
727 | uint fc_xon; /* Number which turned off flow-control */ | ||
728 | uint rxglomfail; /* Failed deglom attempts */ | ||
729 | uint rxglomframes; /* Number of glom frames (superframes) */ | ||
730 | uint rxglompkts; /* Number of packets from glom frames */ | ||
731 | uint f2rxhdrs; /* Number of header reads */ | ||
732 | uint f2rxdata; /* Number of frame data reads */ | ||
733 | uint f2txdata; /* Number of f2 frame writes */ | ||
734 | uint f1regdata; /* Number of f1 register accesses */ | ||
735 | |||
736 | u8 *ctrl_frame_buf; | ||
737 | u32 ctrl_frame_len; | ||
738 | bool ctrl_frame_stat; | ||
739 | |||
740 | spinlock_t txqlock; | ||
741 | wait_queue_head_t ctrl_wait; | ||
742 | |||
743 | struct timer_list timer; | ||
744 | struct completion watchdog_wait; | ||
745 | struct task_struct *watchdog_tsk; | ||
746 | bool wd_timer_valid; | ||
747 | |||
748 | struct tasklet_struct tasklet; | ||
749 | struct task_struct *dpc_tsk; | ||
750 | struct completion dpc_wait; | ||
751 | |||
752 | bool threads_only; | ||
753 | struct semaphore sdsem; | ||
754 | spinlock_t sdlock; | ||
755 | |||
756 | const char *fw_name; | ||
757 | const struct firmware *firmware; | ||
758 | const char *nv_name; | ||
759 | u32 fw_ptr; | ||
760 | }; | ||
761 | |||
762 | struct sbconfig { | ||
763 | u32 PAD[2]; | ||
764 | u32 sbipsflag; /* initiator port ocp slave flag */ | ||
765 | u32 PAD[3]; | ||
766 | u32 sbtpsflag; /* target port ocp slave flag */ | ||
767 | u32 PAD[11]; | ||
768 | u32 sbtmerrloga; /* (sonics >= 2.3) */ | ||
769 | u32 PAD; | ||
770 | u32 sbtmerrlog; /* (sonics >= 2.3) */ | ||
771 | u32 PAD[3]; | ||
772 | u32 sbadmatch3; /* address match3 */ | ||
773 | u32 PAD; | ||
774 | u32 sbadmatch2; /* address match2 */ | ||
775 | u32 PAD; | ||
776 | u32 sbadmatch1; /* address match1 */ | ||
777 | u32 PAD[7]; | ||
778 | u32 sbimstate; /* initiator agent state */ | ||
779 | u32 sbintvec; /* interrupt mask */ | ||
780 | u32 sbtmstatelow; /* target state */ | ||
781 | u32 sbtmstatehigh; /* target state */ | ||
782 | u32 sbbwa0; /* bandwidth allocation table0 */ | ||
783 | u32 PAD; | ||
784 | u32 sbimconfiglow; /* initiator configuration */ | ||
785 | u32 sbimconfighigh; /* initiator configuration */ | ||
786 | u32 sbadmatch0; /* address match0 */ | ||
787 | u32 PAD; | ||
788 | u32 sbtmconfiglow; /* target configuration */ | ||
789 | u32 sbtmconfighigh; /* target configuration */ | ||
790 | u32 sbbconfig; /* broadcast configuration */ | ||
791 | u32 PAD; | ||
792 | u32 sbbstate; /* broadcast state */ | ||
793 | u32 PAD[3]; | ||
794 | u32 sbactcnfg; /* activate configuration */ | ||
795 | u32 PAD[3]; | ||
796 | u32 sbflagst; /* current sbflags */ | ||
797 | u32 PAD[3]; | ||
798 | u32 sbidlow; /* identification */ | ||
799 | u32 sbidhigh; /* identification */ | ||
800 | }; | ||
801 | |||
802 | /* clkstate */ | ||
803 | #define CLK_NONE 0 | ||
804 | #define CLK_SDONLY 1 | ||
805 | #define CLK_PENDING 2 /* Not used yet */ | ||
806 | #define CLK_AVAIL 3 | ||
807 | |||
808 | #define BRCMF_NOPMU(brcmf) (false) | ||
809 | |||
810 | #ifdef BCMDBG | ||
811 | static int qcount[NUMPRIO]; | ||
812 | static int tx_packets[NUMPRIO]; | ||
813 | #endif /* BCMDBG */ | ||
814 | |||
815 | /* Deferred transmit */ | ||
816 | uint brcmf_deferred_tx = 1; | ||
817 | module_param(brcmf_deferred_tx, uint, 0); | ||
818 | |||
819 | /* Watchdog thread priority, -1 to use kernel timer */ | ||
820 | int brcmf_watchdog_prio = 97; | ||
821 | module_param(brcmf_watchdog_prio, int, 0); | ||
822 | |||
823 | /* Watchdog interval */ | ||
824 | uint brcmf_watchdog_ms = 10; | ||
825 | module_param(brcmf_watchdog_ms, uint, 0); | ||
826 | |||
827 | /* DPC thread priority, -1 to use tasklet */ | ||
828 | int brcmf_dpc_prio = 98; | ||
829 | module_param(brcmf_dpc_prio, int, 0); | ||
830 | |||
831 | #ifdef BCMDBG | ||
832 | /* Console poll interval */ | ||
833 | uint brcmf_console_ms; | ||
834 | module_param(brcmf_console_ms, uint, 0); | ||
835 | #endif /* BCMDBG */ | ||
836 | |||
837 | /* Tx/Rx bounds */ | ||
838 | uint brcmf_txbound; | ||
839 | uint brcmf_rxbound; | ||
840 | uint brcmf_txminmax; | ||
841 | |||
842 | /* override the RAM size if possible */ | ||
843 | #define DONGLE_MIN_MEMSIZE (128 * 1024) | ||
844 | int brcmf_dongle_memsize; | ||
845 | |||
846 | static bool brcmf_alignctl; | ||
847 | |||
848 | static bool sd1idle; | ||
849 | |||
850 | static bool retrydata; | ||
851 | #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata) | ||
852 | |||
853 | static const uint watermark = 8; | ||
854 | static const uint firstread = BRCMF_FIRSTREAD; | ||
855 | |||
856 | /* Retry count for register access failures */ | ||
857 | static const uint retry_limit = 2; | ||
858 | |||
859 | /* Force even SD lengths (some host controllers mess up on odd bytes) */ | ||
860 | static bool forcealign; | ||
861 | |||
862 | #define ALIGNMENT 4 | ||
863 | |||
864 | #define PKTALIGN(_p, _len, _align) \ | ||
865 | do { \ | ||
866 | uint datalign; \ | ||
867 | datalign = (unsigned long)((_p)->data); \ | ||
868 | datalign = roundup(datalign, (_align)) - datalign; \ | ||
869 | if (datalign) \ | ||
870 | skb_pull((_p), datalign); \ | ||
871 | __skb_trim((_p), (_len)); \ | ||
872 | } while (0) | ||
873 | |||
874 | /* Limit on rounding up frames */ | ||
875 | static const uint max_roundup = 512; | ||
876 | |||
877 | /* Try doing readahead */ | ||
878 | static bool brcmf_readahead; | ||
879 | |||
880 | /* To check if there's window offered */ | ||
881 | #define DATAOK(bus) \ | ||
882 | (((u8)(bus->tx_max - bus->tx_seq) != 0) && \ | ||
883 | (((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) | ||
884 | |||
885 | /* | ||
886 | * Reads a register in the SDIO hardware block. This block occupies a series of | ||
887 | * adresses on the 32 bit backplane bus. | ||
888 | */ | ||
889 | static void | ||
890 | r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar) | ||
891 | { | ||
892 | *retryvar = 0; | ||
893 | do { | ||
894 | *regvar = R_REG(bus->ci->buscorebase + reg_offset, u32); | ||
895 | } while (brcmf_sdcard_regfail(bus->card) && | ||
896 | (++(*retryvar) <= retry_limit)); | ||
897 | if (*retryvar) { | ||
898 | bus->regfails += (*retryvar-1); | ||
899 | if (*retryvar > retry_limit) { | ||
900 | BRCMF_ERROR(("FAILED READ %Xh\n", reg_offset)); | ||
901 | *regvar = 0; | ||
902 | } | ||
903 | } | ||
904 | } | ||
905 | |||
906 | static void | ||
907 | w_sdreg32(struct brcmf_bus *bus, u32 regval, u32 reg_offset, u32 *retryvar) | ||
908 | { | ||
909 | *retryvar = 0; | ||
910 | do { | ||
911 | brcmf_sdcard_reg_write(NULL, bus->ci->buscorebase + reg_offset, | ||
912 | sizeof(u32), regval); | ||
913 | } while (brcmf_sdcard_regfail(bus->card) && | ||
914 | (++(*retryvar) <= retry_limit)); | ||
915 | if (*retryvar) { | ||
916 | bus->regfails += (*retryvar-1); | ||
917 | if (*retryvar > retry_limit) | ||
918 | BRCMF_ERROR(("FAILED REGISTER WRITE" | ||
919 | " %Xh\n", reg_offset)); | ||
920 | } | ||
921 | } | ||
922 | |||
923 | #define BRCMF_BUS SDIO_BUS | ||
924 | |||
925 | #define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND) | ||
926 | |||
927 | #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) | ||
928 | |||
929 | #ifdef SDTEST | ||
930 | static void brcmf_sdbrcm_checkdied(struct brcmf_bus *bus, void *pkt, uint seq); | ||
931 | static void brcmf_sdbrcm_sdtest_set(struct brcmf_bus *bus, bool start); | ||
932 | #endif | ||
933 | |||
934 | #ifdef BCMDBG | ||
935 | static int brcmf_sdbrcm_bus_console_in(struct brcmf_pub *drvr, | ||
936 | unsigned char *msg, uint msglen); | ||
937 | static int brcmf_sdbrcm_checkdied(struct brcmf_bus *bus, u8 *data, uint size); | ||
938 | static int brcmf_sdbrcm_mem_dump(struct brcmf_bus *bus); | ||
939 | #endif /* BCMDBG */ | ||
940 | static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter); | ||
941 | |||
942 | static void brcmf_sdbrcm_release(struct brcmf_bus *bus); | ||
943 | static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus); | ||
944 | static void brcmf_sdbrcm_disconnect(void *ptr); | ||
945 | static bool brcmf_sdbrcm_chipmatch(u16 chipid); | ||
946 | static bool brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, void *card, | ||
947 | u32 regsva, u16 devid); | ||
948 | static bool brcmf_sdbrcm_probe_malloc(struct brcmf_bus *bus, void *card); | ||
949 | static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus, void *card); | ||
950 | static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus); | ||
951 | |||
952 | static uint brcmf_process_nvram_vars(char *varbuf, uint len); | ||
953 | |||
954 | static void brcmf_sdbrcm_setmemsize(struct brcmf_bus *bus, int mem_size); | ||
955 | static int brcmf_sdbrcm_send_buf(struct brcmf_bus *bus, u32 addr, uint fn, | ||
956 | uint flags, u8 *buf, uint nbytes, | ||
957 | struct sk_buff *pkt, | ||
958 | void (*complete)(void *handle, int status, | ||
959 | bool sync_waiting), | ||
960 | void *handle); | ||
961 | |||
962 | static bool brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus, void *card); | ||
963 | static int _brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus); | ||
964 | |||
965 | static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus); | ||
966 | static int brcmf_sdbrcm_download_nvram(struct brcmf_bus *bus); | ||
967 | |||
968 | static void | ||
969 | brcmf_sdbrcm_chip_disablecore(struct brcmf_sdio_card *card, u32 corebase); | ||
970 | |||
971 | static int brcmf_sdbrcm_chip_attach(struct brcmf_bus *bus, u32 regs); | ||
972 | |||
973 | static void | ||
974 | brcmf_sdbrcm_chip_resetcore(struct brcmf_sdio_card *card, u32 corebase); | ||
975 | |||
976 | static void brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus, | ||
977 | u32 drivestrength); | ||
978 | static void brcmf_sdbrcm_chip_detach(struct brcmf_bus *bus); | ||
979 | static void brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar); | ||
980 | static void brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus); | ||
981 | static void brcmf_sdbrcm_watchdog(unsigned long data); | ||
982 | static int brcmf_sdbrcm_watchdog_thread(void *data); | ||
983 | static int brcmf_sdbrcm_dpc_thread(void *data); | ||
984 | static void brcmf_sdbrcm_dpc_tasklet(unsigned long data); | ||
985 | static void brcmf_sdbrcm_sched_dpc(struct brcmf_bus *bus); | ||
986 | static void brcmf_sdbrcm_sdlock(struct brcmf_bus *bus); | ||
987 | static void brcmf_sdbrcm_sdunlock(struct brcmf_bus *bus); | ||
988 | static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus); | ||
989 | |||
990 | /* Packet free applicable unconditionally for sdio and sdspi. | ||
991 | * Conditional if bufpool was present for gspi bus. | ||
992 | */ | ||
993 | static void brcmf_sdbrcm_pktfree2(struct brcmf_bus *bus, struct sk_buff *pkt) | ||
994 | { | ||
995 | if ((bus->bus != SPI_BUS) || bus->usebufpool) | ||
996 | brcmu_pkt_buf_free_skb(pkt); | ||
997 | } | ||
998 | |||
999 | static void brcmf_sdbrcm_setmemsize(struct brcmf_bus *bus, int mem_size) | ||
1000 | { | ||
1001 | s32 min_size = DONGLE_MIN_MEMSIZE; | ||
1002 | /* Restrict the memsize to user specified limit */ | ||
1003 | BRCMF_ERROR(("user: Restrict the dongle ram size to %d, min %d\n", | ||
1004 | brcmf_dongle_memsize, min_size)); | ||
1005 | if ((brcmf_dongle_memsize > min_size) && | ||
1006 | (brcmf_dongle_memsize < (s32) bus->orig_ramsize)) | ||
1007 | bus->ramsize = brcmf_dongle_memsize; | ||
1008 | } | ||
1009 | |||
1010 | static int brcmf_sdbrcm_set_siaddr_window(struct brcmf_bus *bus, u32 address) | ||
1011 | { | ||
1012 | int err = 0; | ||
1013 | brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, | ||
1014 | (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); | ||
1015 | if (!err) | ||
1016 | brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, | ||
1017 | SBSDIO_FUNC1_SBADDRMID, | ||
1018 | (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); | ||
1019 | if (!err) | ||
1020 | brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, | ||
1021 | SBSDIO_FUNC1_SBADDRHIGH, | ||
1022 | (address >> 24) & SBSDIO_SBADDRHIGH_MASK, | ||
1023 | &err); | ||
1024 | return err; | ||
1025 | } | ||
1026 | |||
1027 | /* Turn backplane clock on or off */ | ||
1028 | static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok) | ||
1029 | { | ||
1030 | int err; | ||
1031 | u8 clkctl, clkreq, devctl; | ||
1032 | struct brcmf_sdio_card *card; | ||
1033 | |||
1034 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
1035 | |||
1036 | clkctl = 0; | ||
1037 | card = bus->card; | ||
1038 | |||
1039 | if (on) { | ||
1040 | /* Request HT Avail */ | ||
1041 | clkreq = | ||
1042 | bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; | ||
1043 | |||
1044 | if ((bus->ci->chip == BCM4329_CHIP_ID) | ||
1045 | && (bus->ci->chiprev == 0)) | ||
1046 | clkreq |= SBSDIO_FORCE_ALP; | ||
1047 | |||
1048 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, | ||
1049 | SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); | ||
1050 | if (err) { | ||
1051 | BRCMF_ERROR(("%s: HT Avail request error: %d\n", | ||
1052 | __func__, err)); | ||
1053 | return -EBADE; | ||
1054 | } | ||
1055 | |||
1056 | if (pendok && ((bus->ci->buscoretype == PCMCIA_CORE_ID) | ||
1057 | && (bus->ci->buscorerev == 9))) { | ||
1058 | u32 dummy, retries; | ||
1059 | r_sdreg32(bus, &dummy, | ||
1060 | offsetof(struct sdpcmd_regs, clockctlstatus), | ||
1061 | &retries); | ||
1062 | } | ||
1063 | |||
1064 | /* Check current status */ | ||
1065 | clkctl = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1, | ||
1066 | SBSDIO_FUNC1_CHIPCLKCSR, &err); | ||
1067 | if (err) { | ||
1068 | BRCMF_ERROR(("%s: HT Avail read error: %d\n", | ||
1069 | __func__, err)); | ||
1070 | return -EBADE; | ||
1071 | } | ||
1072 | |||
1073 | /* Go to pending and await interrupt if appropriate */ | ||
1074 | if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { | ||
1075 | /* Allow only clock-available interrupt */ | ||
1076 | devctl = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1, | ||
1077 | SBSDIO_DEVICE_CTL, &err); | ||
1078 | if (err) { | ||
1079 | BRCMF_ERROR(("%s: Devctl error setting CA:" | ||
1080 | " %d\n", __func__, err)); | ||
1081 | return -EBADE; | ||
1082 | } | ||
1083 | |||
1084 | devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; | ||
1085 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, | ||
1086 | SBSDIO_DEVICE_CTL, devctl, &err); | ||
1087 | BRCMF_INFO(("CLKCTL: set PENDING\n")); | ||
1088 | bus->clkstate = CLK_PENDING; | ||
1089 | |||
1090 | return 0; | ||
1091 | } else if (bus->clkstate == CLK_PENDING) { | ||
1092 | /* Cancel CA-only interrupt filter */ | ||
1093 | devctl = | ||
1094 | brcmf_sdcard_cfg_read(card, SDIO_FUNC_1, | ||
1095 | SBSDIO_DEVICE_CTL, &err); | ||
1096 | devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; | ||
1097 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, | ||
1098 | SBSDIO_DEVICE_CTL, devctl, &err); | ||
1099 | } | ||
1100 | |||
1101 | /* Otherwise, wait here (polling) for HT Avail */ | ||
1102 | if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { | ||
1103 | BRCMF_SPINWAIT_SLEEP(sdioh_spinwait_sleep, | ||
1104 | ((clkctl = | ||
1105 | brcmf_sdcard_cfg_read(card, SDIO_FUNC_1, | ||
1106 | SBSDIO_FUNC1_CHIPCLKCSR, | ||
1107 | &err)), | ||
1108 | !SBSDIO_CLKAV(clkctl, bus->alp_only)), | ||
1109 | PMU_MAX_TRANSITION_DLY); | ||
1110 | } | ||
1111 | if (err) { | ||
1112 | BRCMF_ERROR(("%s: HT Avail request error: %d\n", | ||
1113 | __func__, err)); | ||
1114 | return -EBADE; | ||
1115 | } | ||
1116 | if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { | ||
1117 | BRCMF_ERROR(("%s: HT Avail timeout (%d): " | ||
1118 | "clkctl 0x%02x\n", __func__, | ||
1119 | PMU_MAX_TRANSITION_DLY, clkctl)); | ||
1120 | return -EBADE; | ||
1121 | } | ||
1122 | |||
1123 | /* Mark clock available */ | ||
1124 | bus->clkstate = CLK_AVAIL; | ||
1125 | BRCMF_INFO(("CLKCTL: turned ON\n")); | ||
1126 | |||
1127 | #if defined(BCMDBG) | ||
1128 | if (bus->alp_only != true) { | ||
1129 | if (SBSDIO_ALPONLY(clkctl)) { | ||
1130 | BRCMF_ERROR(("%s: HT Clock should be on.\n", | ||
1131 | __func__)); | ||
1132 | } | ||
1133 | } | ||
1134 | #endif /* defined (BCMDBG) */ | ||
1135 | |||
1136 | bus->activity = true; | ||
1137 | } else { | ||
1138 | clkreq = 0; | ||
1139 | |||
1140 | if (bus->clkstate == CLK_PENDING) { | ||
1141 | /* Cancel CA-only interrupt filter */ | ||
1142 | devctl = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1, | ||
1143 | SBSDIO_DEVICE_CTL, &err); | ||
1144 | devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; | ||
1145 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, | ||
1146 | SBSDIO_DEVICE_CTL, devctl, &err); | ||
1147 | } | ||
1148 | |||
1149 | bus->clkstate = CLK_SDONLY; | ||
1150 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, | ||
1151 | SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); | ||
1152 | BRCMF_INFO(("CLKCTL: turned OFF\n")); | ||
1153 | if (err) { | ||
1154 | BRCMF_ERROR(("%s: Failed access turning clock off:" | ||
1155 | " %d\n", __func__, err)); | ||
1156 | return -EBADE; | ||
1157 | } | ||
1158 | } | ||
1159 | return 0; | ||
1160 | } | ||
1161 | |||
1162 | /* Change idle/active SD state */ | ||
1163 | static int brcmf_sdbrcm_sdclk(struct brcmf_bus *bus, bool on) | ||
1164 | { | ||
1165 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
1166 | |||
1167 | if (on) | ||
1168 | bus->clkstate = CLK_SDONLY; | ||
1169 | else | ||
1170 | bus->clkstate = CLK_NONE; | ||
1171 | |||
1172 | return 0; | ||
1173 | } | ||
1174 | |||
1175 | /* Transition SD and backplane clock readiness */ | ||
1176 | static int brcmf_sdbrcm_clkctl(struct brcmf_bus *bus, uint target, bool pendok) | ||
1177 | { | ||
1178 | #ifdef BCMDBG | ||
1179 | uint oldstate = bus->clkstate; | ||
1180 | #endif /* BCMDBG */ | ||
1181 | |||
1182 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
1183 | |||
1184 | /* Early exit if we're already there */ | ||
1185 | if (bus->clkstate == target) { | ||
1186 | if (target == CLK_AVAIL) { | ||
1187 | brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms); | ||
1188 | bus->activity = true; | ||
1189 | } | ||
1190 | return 0; | ||
1191 | } | ||
1192 | |||
1193 | switch (target) { | ||
1194 | case CLK_AVAIL: | ||
1195 | /* Make sure SD clock is available */ | ||
1196 | if (bus->clkstate == CLK_NONE) | ||
1197 | brcmf_sdbrcm_sdclk(bus, true); | ||
1198 | /* Now request HT Avail on the backplane */ | ||
1199 | brcmf_sdbrcm_htclk(bus, true, pendok); | ||
1200 | brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms); | ||
1201 | bus->activity = true; | ||
1202 | break; | ||
1203 | |||
1204 | case CLK_SDONLY: | ||
1205 | /* Remove HT request, or bring up SD clock */ | ||
1206 | if (bus->clkstate == CLK_NONE) | ||
1207 | brcmf_sdbrcm_sdclk(bus, true); | ||
1208 | else if (bus->clkstate == CLK_AVAIL) | ||
1209 | brcmf_sdbrcm_htclk(bus, false, false); | ||
1210 | else | ||
1211 | BRCMF_ERROR(("brcmf_sdbrcm_clkctl: request for %d -> %d" | ||
1212 | "\n", bus->clkstate, target)); | ||
1213 | brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms); | ||
1214 | break; | ||
1215 | |||
1216 | case CLK_NONE: | ||
1217 | /* Make sure to remove HT request */ | ||
1218 | if (bus->clkstate == CLK_AVAIL) | ||
1219 | brcmf_sdbrcm_htclk(bus, false, false); | ||
1220 | /* Now remove the SD clock */ | ||
1221 | brcmf_sdbrcm_sdclk(bus, false); | ||
1222 | brcmf_sdbrcm_wd_timer(bus, 0); | ||
1223 | break; | ||
1224 | } | ||
1225 | #ifdef BCMDBG | ||
1226 | BRCMF_INFO(("brcmf_sdbrcm_clkctl: %d -> %d\n", | ||
1227 | oldstate, bus->clkstate)); | ||
1228 | #endif /* BCMDBG */ | ||
1229 | |||
1230 | return 0; | ||
1231 | } | ||
1232 | |||
1233 | int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep) | ||
1234 | { | ||
1235 | struct brcmf_sdio_card *card = bus->card; | ||
1236 | uint retries = 0; | ||
1237 | |||
1238 | BRCMF_INFO(("brcmf_sdbrcm_bussleep: request %s (currently %s)\n", | ||
1239 | (sleep ? "SLEEP" : "WAKE"), | ||
1240 | (bus->sleeping ? "SLEEP" : "WAKE"))); | ||
1241 | |||
1242 | /* Done if we're already in the requested state */ | ||
1243 | if (sleep == bus->sleeping) | ||
1244 | return 0; | ||
1245 | |||
1246 | /* Going to sleep: set the alarm and turn off the lights... */ | ||
1247 | if (sleep) { | ||
1248 | /* Don't sleep if something is pending */ | ||
1249 | if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq)) | ||
1250 | return -EBUSY; | ||
1251 | |||
1252 | /* Disable SDIO interrupts (no longer interested) */ | ||
1253 | brcmf_sdcard_intr_disable(bus->card); | ||
1254 | |||
1255 | /* Make sure the controller has the bus up */ | ||
1256 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | ||
1257 | |||
1258 | /* Tell device to start using OOB wakeup */ | ||
1259 | w_sdreg32(bus, SMB_USE_OOB, | ||
1260 | offsetof(struct sdpcmd_regs, tosbmailbox), &retries); | ||
1261 | if (retries > retry_limit) | ||
1262 | BRCMF_ERROR(("CANNOT SIGNAL CHIP, " | ||
1263 | "WILL NOT WAKE UP!!\n")); | ||
1264 | |||
1265 | /* Turn off our contribution to the HT clock request */ | ||
1266 | brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); | ||
1267 | |||
1268 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, | ||
1269 | SBSDIO_FUNC1_CHIPCLKCSR, | ||
1270 | SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); | ||
1271 | |||
1272 | /* Isolate the bus */ | ||
1273 | if (bus->ci->chip != BCM4329_CHIP_ID | ||
1274 | && bus->ci->chip != BCM4319_CHIP_ID) { | ||
1275 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, | ||
1276 | SBSDIO_DEVICE_CTL, | ||
1277 | SBSDIO_DEVCTL_PADS_ISO, NULL); | ||
1278 | } | ||
1279 | |||
1280 | /* Change state */ | ||
1281 | bus->sleeping = true; | ||
1282 | |||
1283 | } else { | ||
1284 | /* Waking up: bus power up is ok, set local state */ | ||
1285 | |||
1286 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, | ||
1287 | SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); | ||
1288 | |||
1289 | /* Force pad isolation off if possible | ||
1290 | (in case power never toggled) */ | ||
1291 | if ((bus->ci->buscoretype == PCMCIA_CORE_ID) | ||
1292 | && (bus->ci->buscorerev >= 10)) | ||
1293 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, | ||
1294 | SBSDIO_DEVICE_CTL, 0, NULL); | ||
1295 | |||
1296 | /* Make sure the controller has the bus up */ | ||
1297 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | ||
1298 | |||
1299 | /* Send misc interrupt to indicate OOB not needed */ | ||
1300 | w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, tosbmailboxdata), | ||
1301 | &retries); | ||
1302 | if (retries <= retry_limit) | ||
1303 | w_sdreg32(bus, SMB_DEV_INT, | ||
1304 | offsetof(struct sdpcmd_regs, tosbmailbox), | ||
1305 | &retries); | ||
1306 | |||
1307 | if (retries > retry_limit) | ||
1308 | BRCMF_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n")); | ||
1309 | |||
1310 | /* Make sure we have SD bus access */ | ||
1311 | brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); | ||
1312 | |||
1313 | /* Change state */ | ||
1314 | bus->sleeping = false; | ||
1315 | |||
1316 | /* Enable interrupts again */ | ||
1317 | if (bus->intr && (bus->drvr->busstate == BRCMF_BUS_DATA)) { | ||
1318 | bus->intdis = false; | ||
1319 | brcmf_sdcard_intr_enable(bus->card); | ||
1320 | } | ||
1321 | } | ||
1322 | |||
1323 | return 0; | ||
1324 | } | ||
1325 | |||
1326 | #define BUS_WAKE(bus) \ | ||
1327 | do { \ | ||
1328 | if ((bus)->sleeping) \ | ||
1329 | brcmf_sdbrcm_bussleep((bus), false); \ | ||
1330 | } while (0); | ||
1331 | |||
1332 | /* Writes a HW/SW header into the packet and sends it. */ | ||
1333 | /* Assumes: (a) header space already there, (b) caller holds lock */ | ||
1334 | static int brcmf_sdbrcm_txpkt(struct brcmf_bus *bus, struct sk_buff *pkt, uint chan, | ||
1335 | bool free_pkt) | ||
1336 | { | ||
1337 | int ret; | ||
1338 | u8 *frame; | ||
1339 | u16 len, pad = 0; | ||
1340 | u32 swheader; | ||
1341 | uint retries = 0; | ||
1342 | struct brcmf_sdio_card *card; | ||
1343 | struct sk_buff *new; | ||
1344 | int i; | ||
1345 | |||
1346 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
1347 | |||
1348 | card = bus->card; | ||
1349 | |||
1350 | if (bus->drvr->dongle_reset) { | ||
1351 | ret = -EPERM; | ||
1352 | goto done; | ||
1353 | } | ||
1354 | |||
1355 | frame = (u8 *) (pkt->data); | ||
1356 | |||
1357 | /* Add alignment padding, allocate new packet if needed */ | ||
1358 | pad = ((unsigned long)frame % BRCMF_SDALIGN); | ||
1359 | if (pad) { | ||
1360 | if (skb_headroom(pkt) < pad) { | ||
1361 | BRCMF_INFO(("%s: insufficient headroom %d for %d pad\n", | ||
1362 | __func__, skb_headroom(pkt), pad)); | ||
1363 | bus->drvr->tx_realloc++; | ||
1364 | new = brcmu_pkt_buf_get_skb(pkt->len + BRCMF_SDALIGN); | ||
1365 | if (!new) { | ||
1366 | BRCMF_ERROR(("%s: couldn't allocate new " | ||
1367 | "%d-byte packet\n", __func__, | ||
1368 | pkt->len + BRCMF_SDALIGN)); | ||
1369 | ret = -ENOMEM; | ||
1370 | goto done; | ||
1371 | } | ||
1372 | |||
1373 | PKTALIGN(new, pkt->len, BRCMF_SDALIGN); | ||
1374 | memcpy(new->data, pkt->data, pkt->len); | ||
1375 | if (free_pkt) | ||
1376 | brcmu_pkt_buf_free_skb(pkt); | ||
1377 | /* free the pkt if canned one is not used */ | ||
1378 | free_pkt = true; | ||
1379 | pkt = new; | ||
1380 | frame = (u8 *) (pkt->data); | ||
1381 | /* precondition: (frame % BRCMF_SDALIGN) == 0) */ | ||
1382 | pad = 0; | ||
1383 | } else { | ||
1384 | skb_push(pkt, pad); | ||
1385 | frame = (u8 *) (pkt->data); | ||
1386 | /* precondition: pad + SDPCM_HDRLEN <= pkt->len */ | ||
1387 | memset(frame, 0, pad + SDPCM_HDRLEN); | ||
1388 | } | ||
1389 | } | ||
1390 | /* precondition: pad < BRCMF_SDALIGN */ | ||
1391 | |||
1392 | /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ | ||
1393 | len = (u16) (pkt->len); | ||
1394 | *(u16 *) frame = cpu_to_le16(len); | ||
1395 | *(((u16 *) frame) + 1) = cpu_to_le16(~len); | ||
1396 | |||
1397 | /* Software tag: channel, sequence number, data offset */ | ||
1398 | swheader = | ||
1399 | ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq | | ||
1400 | (((pad + | ||
1401 | SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); | ||
1402 | |||
1403 | put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN); | ||
1404 | put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); | ||
1405 | |||
1406 | #ifdef BCMDBG | ||
1407 | tx_packets[pkt->priority]++; | ||
1408 | if (BRCMF_BYTES_ON() && | ||
1409 | (((BRCMF_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) || | ||
1410 | (BRCMF_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) { | ||
1411 | printk(KERN_DEBUG "Tx Frame:\n"); | ||
1412 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, frame, len); | ||
1413 | } else if (BRCMF_HDRS_ON()) { | ||
1414 | printk(KERN_DEBUG "TxHdr:\n"); | ||
1415 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, | ||
1416 | frame, min_t(u16, len, 16)); | ||
1417 | } | ||
1418 | #endif | ||
1419 | |||
1420 | /* Raise len to next SDIO block to eliminate tail command */ | ||
1421 | if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { | ||
1422 | u16 pad = bus->blocksize - (len % bus->blocksize); | ||
1423 | if ((pad <= bus->roundup) && (pad < bus->blocksize)) | ||
1424 | len += pad; | ||
1425 | } else if (len % BRCMF_SDALIGN) { | ||
1426 | len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN); | ||
1427 | } | ||
1428 | |||
1429 | /* Some controllers have trouble with odd bytes -- round to even */ | ||
1430 | if (forcealign && (len & (ALIGNMENT - 1))) { | ||
1431 | len = roundup(len, ALIGNMENT); | ||
1432 | } | ||
1433 | |||
1434 | do { | ||
1435 | ret = brcmf_sdbrcm_send_buf(bus, brcmf_sdcard_cur_sbwad(card), | ||
1436 | SDIO_FUNC_2, F2SYNC, frame, len, pkt, NULL, NULL); | ||
1437 | bus->f2txdata++; | ||
1438 | |||
1439 | if (ret < 0) { | ||
1440 | /* On failure, abort the command | ||
1441 | and terminate the frame */ | ||
1442 | BRCMF_INFO(("%s: sdio error %d, abort command and " | ||
1443 | "terminate frame.\n", __func__, ret)); | ||
1444 | bus->tx_sderrs++; | ||
1445 | |||
1446 | brcmf_sdcard_abort(card, SDIO_FUNC_2); | ||
1447 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, | ||
1448 | SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, | ||
1449 | NULL); | ||
1450 | bus->f1regdata++; | ||
1451 | |||
1452 | for (i = 0; i < 3; i++) { | ||
1453 | u8 hi, lo; | ||
1454 | hi = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1, | ||
1455 | SBSDIO_FUNC1_WFRAMEBCHI, | ||
1456 | NULL); | ||
1457 | lo = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1, | ||
1458 | SBSDIO_FUNC1_WFRAMEBCLO, | ||
1459 | NULL); | ||
1460 | bus->f1regdata += 2; | ||
1461 | if ((hi == 0) && (lo == 0)) | ||
1462 | break; | ||
1463 | } | ||
1464 | |||
1465 | } | ||
1466 | if (ret == 0) | ||
1467 | bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; | ||
1468 | |||
1469 | } while ((ret < 0) && retrydata && retries++ < TXRETRIES); | ||
1470 | |||
1471 | done: | ||
1472 | /* restore pkt buffer pointer before calling tx complete routine */ | ||
1473 | skb_pull(pkt, SDPCM_HDRLEN + pad); | ||
1474 | brcmf_sdbrcm_sdunlock(bus); | ||
1475 | brcmf_txcomplete(bus->drvr, pkt, ret != 0); | ||
1476 | brcmf_sdbrcm_sdlock(bus); | ||
1477 | |||
1478 | if (free_pkt) | ||
1479 | brcmu_pkt_buf_free_skb(pkt); | ||
1480 | |||
1481 | return ret; | ||
1482 | } | ||
1483 | |||
1484 | int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *pkt) | ||
1485 | { | ||
1486 | int ret = -EBADE; | ||
1487 | uint datalen, prec; | ||
1488 | |||
1489 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
1490 | |||
1491 | datalen = pkt->len; | ||
1492 | |||
1493 | #ifdef SDTEST | ||
1494 | /* Push the test header if doing loopback */ | ||
1495 | if (bus->ext_loop) { | ||
1496 | u8 *data; | ||
1497 | skb_push(pkt, SDPCM_TEST_HDRLEN); | ||
1498 | data = pkt->data; | ||
1499 | *data++ = SDPCM_TEST_ECHOREQ; | ||
1500 | *data++ = (u8) bus->loopid++; | ||
1501 | *data++ = (datalen >> 0); | ||
1502 | *data++ = (datalen >> 8); | ||
1503 | datalen += SDPCM_TEST_HDRLEN; | ||
1504 | } | ||
1505 | #endif /* SDTEST */ | ||
1506 | |||
1507 | /* Add space for the header */ | ||
1508 | skb_push(pkt, SDPCM_HDRLEN); | ||
1509 | /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */ | ||
1510 | |||
1511 | prec = PRIO2PREC((pkt->priority & PRIOMASK)); | ||
1512 | |||
1513 | /* Check for existing queue, current flow-control, | ||
1514 | pending event, or pending clock */ | ||
1515 | if (brcmf_deferred_tx || bus->fcstate || pktq_len(&bus->txq) | ||
1516 | || bus->dpc_sched || (!DATAOK(bus)) | ||
1517 | || (bus->flowcontrol & NBITVAL(prec)) | ||
1518 | || (bus->clkstate != CLK_AVAIL)) { | ||
1519 | BRCMF_TRACE(("%s: deferring pktq len %d\n", __func__, | ||
1520 | pktq_len(&bus->txq))); | ||
1521 | bus->fcqueued++; | ||
1522 | |||
1523 | /* Priority based enq */ | ||
1524 | spin_lock_bh(&bus->txqlock); | ||
1525 | if (brcmf_c_prec_enq(bus->drvr, &bus->txq, pkt, prec) == false) { | ||
1526 | skb_pull(pkt, SDPCM_HDRLEN); | ||
1527 | brcmf_txcomplete(bus->drvr, pkt, false); | ||
1528 | brcmu_pkt_buf_free_skb(pkt); | ||
1529 | BRCMF_ERROR(("%s: out of bus->txq !!!\n", __func__)); | ||
1530 | ret = -ENOSR; | ||
1531 | } else { | ||
1532 | ret = 0; | ||
1533 | } | ||
1534 | spin_unlock_bh(&bus->txqlock); | ||
1535 | |||
1536 | if (pktq_len(&bus->txq) >= TXHI) | ||
1537 | brcmf_txflowcontrol(bus->drvr, 0, ON); | ||
1538 | |||
1539 | #ifdef BCMDBG | ||
1540 | if (pktq_plen(&bus->txq, prec) > qcount[prec]) | ||
1541 | qcount[prec] = pktq_plen(&bus->txq, prec); | ||
1542 | #endif | ||
1543 | /* Schedule DPC if needed to send queued packet(s) */ | ||
1544 | if (brcmf_deferred_tx && !bus->dpc_sched) { | ||
1545 | bus->dpc_sched = true; | ||
1546 | brcmf_sdbrcm_sched_dpc(bus); | ||
1547 | } | ||
1548 | } else { | ||
1549 | /* Lock: we're about to use shared data/code (and SDIO) */ | ||
1550 | brcmf_sdbrcm_sdlock(bus); | ||
1551 | |||
1552 | /* Otherwise, send it now */ | ||
1553 | BUS_WAKE(bus); | ||
1554 | /* Make sure back plane ht clk is on, no pending allowed */ | ||
1555 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true); | ||
1556 | |||
1557 | #ifndef SDTEST | ||
1558 | BRCMF_TRACE(("%s: calling txpkt\n", __func__)); | ||
1559 | ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true); | ||
1560 | #else | ||
1561 | ret = brcmf_sdbrcm_txpkt(bus, pkt, | ||
1562 | (bus->ext_loop ? SDPCM_TEST_CHANNEL : | ||
1563 | SDPCM_DATA_CHANNEL), true); | ||
1564 | #endif | ||
1565 | if (ret) | ||
1566 | bus->drvr->tx_errors++; | ||
1567 | else | ||
1568 | bus->drvr->dstats.tx_bytes += datalen; | ||
1569 | |||
1570 | if (bus->idletime == BRCMF_IDLE_IMMEDIATE && | ||
1571 | !bus->dpc_sched) { | ||
1572 | bus->activity = false; | ||
1573 | brcmf_sdbrcm_clkctl(bus, CLK_NONE, true); | ||
1574 | } | ||
1575 | |||
1576 | brcmf_sdbrcm_sdunlock(bus); | ||
1577 | } | ||
1578 | |||
1579 | return ret; | ||
1580 | } | ||
1581 | |||
1582 | static uint brcmf_sdbrcm_sendfromq(struct brcmf_bus *bus, uint maxframes) | ||
1583 | { | ||
1584 | struct sk_buff *pkt; | ||
1585 | u32 intstatus = 0; | ||
1586 | uint retries = 0; | ||
1587 | int ret = 0, prec_out; | ||
1588 | uint cnt = 0; | ||
1589 | uint datalen; | ||
1590 | u8 tx_prec_map; | ||
1591 | |||
1592 | struct brcmf_pub *drvr = bus->drvr; | ||
1593 | |||
1594 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
1595 | |||
1596 | tx_prec_map = ~bus->flowcontrol; | ||
1597 | |||
1598 | /* Send frames until the limit or some other event */ | ||
1599 | for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) { | ||
1600 | spin_lock_bh(&bus->txqlock); | ||
1601 | pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out); | ||
1602 | if (pkt == NULL) { | ||
1603 | spin_unlock_bh(&bus->txqlock); | ||
1604 | break; | ||
1605 | } | ||
1606 | spin_unlock_bh(&bus->txqlock); | ||
1607 | datalen = pkt->len - SDPCM_HDRLEN; | ||
1608 | |||
1609 | #ifndef SDTEST | ||
1610 | ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true); | ||
1611 | #else | ||
1612 | ret = brcmf_sdbrcm_txpkt(bus, pkt, | ||
1613 | (bus->ext_loop ? SDPCM_TEST_CHANNEL : | ||
1614 | SDPCM_DATA_CHANNEL), true); | ||
1615 | #endif | ||
1616 | if (ret) | ||
1617 | bus->drvr->tx_errors++; | ||
1618 | else | ||
1619 | bus->drvr->dstats.tx_bytes += datalen; | ||
1620 | |||
1621 | /* In poll mode, need to check for other events */ | ||
1622 | if (!bus->intr && cnt) { | ||
1623 | /* Check device status, signal pending interrupt */ | ||
1624 | r_sdreg32(bus, &intstatus, | ||
1625 | offsetof(struct sdpcmd_regs, intstatus), | ||
1626 | &retries); | ||
1627 | bus->f2txdata++; | ||
1628 | if (brcmf_sdcard_regfail(bus->card)) | ||
1629 | break; | ||
1630 | if (intstatus & bus->hostintmask) | ||
1631 | bus->ipend = true; | ||
1632 | } | ||
1633 | } | ||
1634 | |||
1635 | /* Deflow-control stack if needed */ | ||
1636 | if (drvr->up && (drvr->busstate == BRCMF_BUS_DATA) && | ||
1637 | drvr->txoff && (pktq_len(&bus->txq) < TXLOW)) | ||
1638 | brcmf_txflowcontrol(drvr, 0, OFF); | ||
1639 | |||
1640 | return cnt; | ||
1641 | } | ||
1642 | |||
1643 | int | ||
1644 | brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen) | ||
1645 | { | ||
1646 | u8 *frame; | ||
1647 | u16 len; | ||
1648 | u32 swheader; | ||
1649 | uint retries = 0; | ||
1650 | struct brcmf_sdio_card *card = bus->card; | ||
1651 | u8 doff = 0; | ||
1652 | int ret = -1; | ||
1653 | int i; | ||
1654 | |||
1655 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
1656 | |||
1657 | if (bus->drvr->dongle_reset) | ||
1658 | return -EIO; | ||
1659 | |||
1660 | /* Back the pointer to make a room for bus header */ | ||
1661 | frame = msg - SDPCM_HDRLEN; | ||
1662 | len = (msglen += SDPCM_HDRLEN); | ||
1663 | |||
1664 | /* Add alignment padding (optional for ctl frames) */ | ||
1665 | if (brcmf_alignctl) { | ||
1666 | doff = ((unsigned long)frame % BRCMF_SDALIGN); | ||
1667 | if (doff) { | ||
1668 | frame -= doff; | ||
1669 | len += doff; | ||
1670 | msglen += doff; | ||
1671 | memset(frame, 0, doff + SDPCM_HDRLEN); | ||
1672 | } | ||
1673 | /* precondition: doff < BRCMF_SDALIGN */ | ||
1674 | } | ||
1675 | doff += SDPCM_HDRLEN; | ||
1676 | |||
1677 | /* Round send length to next SDIO block */ | ||
1678 | if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { | ||
1679 | u16 pad = bus->blocksize - (len % bus->blocksize); | ||
1680 | if ((pad <= bus->roundup) && (pad < bus->blocksize)) | ||
1681 | len += pad; | ||
1682 | } else if (len % BRCMF_SDALIGN) { | ||
1683 | len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN); | ||
1684 | } | ||
1685 | |||
1686 | /* Satisfy length-alignment requirements */ | ||
1687 | if (forcealign && (len & (ALIGNMENT - 1))) | ||
1688 | len = roundup(len, ALIGNMENT); | ||
1689 | |||
1690 | /* precondition: IS_ALIGNED((unsigned long)frame, 2) */ | ||
1691 | |||
1692 | /* Need to lock here to protect txseq and SDIO tx calls */ | ||
1693 | brcmf_sdbrcm_sdlock(bus); | ||
1694 | |||
1695 | BUS_WAKE(bus); | ||
1696 | |||
1697 | /* Make sure backplane clock is on */ | ||
1698 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | ||
1699 | |||
1700 | /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ | ||
1701 | *(u16 *) frame = cpu_to_le16((u16) msglen); | ||
1702 | *(((u16 *) frame) + 1) = cpu_to_le16(~msglen); | ||
1703 | |||
1704 | /* Software tag: channel, sequence number, data offset */ | ||
1705 | swheader = | ||
1706 | ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & | ||
1707 | SDPCM_CHANNEL_MASK) | ||
1708 | | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & | ||
1709 | SDPCM_DOFFSET_MASK); | ||
1710 | put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN); | ||
1711 | put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); | ||
1712 | |||
1713 | if (!DATAOK(bus)) { | ||
1714 | BRCMF_INFO(("%s: No bus credit bus->tx_max %d," | ||
1715 | " bus->tx_seq %d\n", __func__, | ||
1716 | bus->tx_max, bus->tx_seq)); | ||
1717 | bus->ctrl_frame_stat = true; | ||
1718 | /* Send from dpc */ | ||
1719 | bus->ctrl_frame_buf = frame; | ||
1720 | bus->ctrl_frame_len = len; | ||
1721 | |||
1722 | brcmf_sdbrcm_wait_for_event(bus, &bus->ctrl_frame_stat); | ||
1723 | |||
1724 | if (bus->ctrl_frame_stat == false) { | ||
1725 | BRCMF_INFO(("%s: ctrl_frame_stat == false\n", | ||
1726 | __func__)); | ||
1727 | ret = 0; | ||
1728 | } else { | ||
1729 | BRCMF_INFO(("%s: ctrl_frame_stat == true\n", __func__)); | ||
1730 | ret = -1; | ||
1731 | } | ||
1732 | } | ||
1733 | |||
1734 | if (ret == -1) { | ||
1735 | #ifdef BCMDBG | ||
1736 | if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) { | ||
1737 | printk(KERN_DEBUG "Tx Frame:\n"); | ||
1738 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, | ||
1739 | frame, len); | ||
1740 | } else if (BRCMF_HDRS_ON()) { | ||
1741 | printk(KERN_DEBUG "TxHdr:\n"); | ||
1742 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, | ||
1743 | frame, min_t(u16, len, 16)); | ||
1744 | } | ||
1745 | #endif | ||
1746 | |||
1747 | do { | ||
1748 | bus->ctrl_frame_stat = false; | ||
1749 | ret = brcmf_sdbrcm_send_buf(bus, | ||
1750 | brcmf_sdcard_cur_sbwad(card), SDIO_FUNC_2, | ||
1751 | F2SYNC, frame, len, NULL, NULL, NULL); | ||
1752 | |||
1753 | if (ret < 0) { | ||
1754 | /* On failure, abort the command and | ||
1755 | terminate the frame */ | ||
1756 | BRCMF_INFO(("%s: sdio error %d, abort command " | ||
1757 | "and terminate frame.\n", | ||
1758 | __func__, ret)); | ||
1759 | bus->tx_sderrs++; | ||
1760 | |||
1761 | brcmf_sdcard_abort(card, SDIO_FUNC_2); | ||
1762 | |||
1763 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, | ||
1764 | SBSDIO_FUNC1_FRAMECTRL, | ||
1765 | SFC_WF_TERM, NULL); | ||
1766 | bus->f1regdata++; | ||
1767 | |||
1768 | for (i = 0; i < 3; i++) { | ||
1769 | u8 hi, lo; | ||
1770 | hi = brcmf_sdcard_cfg_read(card, | ||
1771 | SDIO_FUNC_1, | ||
1772 | SBSDIO_FUNC1_WFRAMEBCHI, | ||
1773 | NULL); | ||
1774 | lo = brcmf_sdcard_cfg_read(card, | ||
1775 | SDIO_FUNC_1, | ||
1776 | SBSDIO_FUNC1_WFRAMEBCLO, | ||
1777 | NULL); | ||
1778 | bus->f1regdata += 2; | ||
1779 | if ((hi == 0) && (lo == 0)) | ||
1780 | break; | ||
1781 | } | ||
1782 | |||
1783 | } | ||
1784 | if (ret == 0) { | ||
1785 | bus->tx_seq = | ||
1786 | (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; | ||
1787 | } | ||
1788 | } while ((ret < 0) && retries++ < TXRETRIES); | ||
1789 | } | ||
1790 | |||
1791 | if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && !bus->dpc_sched) { | ||
1792 | bus->activity = false; | ||
1793 | brcmf_sdbrcm_clkctl(bus, CLK_NONE, true); | ||
1794 | } | ||
1795 | |||
1796 | brcmf_sdbrcm_sdunlock(bus); | ||
1797 | |||
1798 | if (ret) | ||
1799 | bus->drvr->tx_ctlerrs++; | ||
1800 | else | ||
1801 | bus->drvr->tx_ctlpkts++; | ||
1802 | |||
1803 | return ret ? -EIO : 0; | ||
1804 | } | ||
1805 | |||
1806 | int brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen) | ||
1807 | { | ||
1808 | int timeleft; | ||
1809 | uint rxlen = 0; | ||
1810 | bool pending; | ||
1811 | |||
1812 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
1813 | |||
1814 | if (bus->drvr->dongle_reset) | ||
1815 | return -EIO; | ||
1816 | |||
1817 | /* Wait until control frame is available */ | ||
1818 | timeleft = brcmf_os_ioctl_resp_wait(bus->drvr, &bus->rxlen, &pending); | ||
1819 | |||
1820 | brcmf_sdbrcm_sdlock(bus); | ||
1821 | rxlen = bus->rxlen; | ||
1822 | memcpy(msg, bus->rxctl, min(msglen, rxlen)); | ||
1823 | bus->rxlen = 0; | ||
1824 | brcmf_sdbrcm_sdunlock(bus); | ||
1825 | |||
1826 | if (rxlen) { | ||
1827 | BRCMF_CTL(("%s: resumed on rxctl frame, got %d expected %d\n", | ||
1828 | __func__, rxlen, msglen)); | ||
1829 | } else if (timeleft == 0) { | ||
1830 | BRCMF_ERROR(("%s: resumed on timeout\n", __func__)); | ||
1831 | #ifdef BCMDBG | ||
1832 | brcmf_sdbrcm_sdlock(bus); | ||
1833 | brcmf_sdbrcm_checkdied(bus, NULL, 0); | ||
1834 | brcmf_sdbrcm_sdunlock(bus); | ||
1835 | #endif /* BCMDBG */ | ||
1836 | } else if (pending == true) { | ||
1837 | BRCMF_CTL(("%s: cancelled\n", __func__)); | ||
1838 | return -ERESTARTSYS; | ||
1839 | } else { | ||
1840 | BRCMF_CTL(("%s: resumed for unknown reason?\n", __func__)); | ||
1841 | #ifdef BCMDBG | ||
1842 | brcmf_sdbrcm_sdlock(bus); | ||
1843 | brcmf_sdbrcm_checkdied(bus, NULL, 0); | ||
1844 | brcmf_sdbrcm_sdunlock(bus); | ||
1845 | #endif /* BCMDBG */ | ||
1846 | } | ||
1847 | |||
1848 | if (rxlen) | ||
1849 | bus->drvr->rx_ctlpkts++; | ||
1850 | else | ||
1851 | bus->drvr->rx_ctlerrs++; | ||
1852 | |||
1853 | return rxlen ? (int)rxlen : -ETIMEDOUT; | ||
1854 | } | ||
1855 | |||
1856 | /* IOVar table */ | ||
1857 | enum { | ||
1858 | IOV_INTR = 1, | ||
1859 | IOV_POLLRATE, | ||
1860 | IOV_SDREG, | ||
1861 | IOV_SBREG, | ||
1862 | IOV_SDCIS, | ||
1863 | IOV_MEMBYTES, | ||
1864 | IOV_MEMSIZE, | ||
1865 | #ifdef BCMDBG | ||
1866 | IOV_CHECKDIED, | ||
1867 | IOV_CONS, | ||
1868 | IOV_DCONSOLE_POLL, | ||
1869 | #endif | ||
1870 | IOV_DOWNLOAD, | ||
1871 | IOV_FORCEEVEN, | ||
1872 | IOV_SDIOD_DRIVE, | ||
1873 | IOV_READAHEAD, | ||
1874 | IOV_SDRXCHAIN, | ||
1875 | IOV_ALIGNCTL, | ||
1876 | IOV_SDALIGN, | ||
1877 | IOV_DEVRESET, | ||
1878 | IOV_CPU, | ||
1879 | #ifdef SDTEST | ||
1880 | IOV_PKTGEN, | ||
1881 | IOV_EXTLOOP, | ||
1882 | #endif /* SDTEST */ | ||
1883 | IOV_SPROM, | ||
1884 | IOV_TXBOUND, | ||
1885 | IOV_RXBOUND, | ||
1886 | IOV_TXMINMAX, | ||
1887 | IOV_IDLETIME, | ||
1888 | IOV_IDLECLOCK, | ||
1889 | IOV_SD1IDLE, | ||
1890 | IOV_SLEEP, | ||
1891 | IOV_WDTICK, | ||
1892 | IOV_VARS | ||
1893 | }; | ||
1894 | |||
1895 | const struct brcmu_iovar brcmf_sdio_iovars[] = { | ||
1896 | {"intr", IOV_INTR, 0, IOVT_BOOL, 0}, | ||
1897 | {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0}, | ||
1898 | {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0}, | ||
1899 | {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0}, | ||
1900 | {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0}, | ||
1901 | {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0}, | ||
1902 | {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int)}, | ||
1903 | {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0}, | ||
1904 | {"download", IOV_DOWNLOAD, 0, IOVT_BOOL, 0}, | ||
1905 | {"vars", IOV_VARS, 0, IOVT_BUFFER, 0}, | ||
1906 | {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0}, | ||
1907 | {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0}, | ||
1908 | {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0}, | ||
1909 | {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0}, | ||
1910 | {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0}, | ||
1911 | {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0}, | ||
1912 | {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0}, | ||
1913 | #ifdef BCMDBG | ||
1914 | {"cons", IOV_CONS, 0, IOVT_BUFFER, 0} | ||
1915 | , | ||
1916 | {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0} | ||
1917 | , | ||
1918 | {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(struct brcmf_sdreg)} | ||
1919 | , | ||
1920 | {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(struct brcmf_sdreg)} | ||
1921 | , | ||
1922 | {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, BRCMF_IOCTL_MAXLEN} | ||
1923 | , | ||
1924 | {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0} | ||
1925 | , | ||
1926 | {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0} | ||
1927 | , | ||
1928 | {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0} | ||
1929 | , | ||
1930 | {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0} | ||
1931 | , | ||
1932 | {"cpu", IOV_CPU, 0, IOVT_BOOL, 0} | ||
1933 | , | ||
1934 | {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0} | ||
1935 | , | ||
1936 | #endif /* BCMDBG */ | ||
1937 | #ifdef SDTEST | ||
1938 | {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0} | ||
1939 | , | ||
1940 | {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(struct brcmf_pktgen)} | ||
1941 | , | ||
1942 | #endif /* SDTEST */ | ||
1943 | |||
1944 | {NULL, 0, 0, 0, 0} | ||
1945 | }; | ||
1946 | |||
1947 | static void | ||
1948 | brcmf_dump_pct(struct brcmu_strbuf *strbuf, char *desc, uint num, uint div) | ||
1949 | { | ||
1950 | uint q1, q2; | ||
1951 | |||
1952 | if (!div) { | ||
1953 | brcmu_bprintf(strbuf, "%s N/A", desc); | ||
1954 | } else { | ||
1955 | q1 = num / div; | ||
1956 | q2 = (100 * (num - (q1 * div))) / div; | ||
1957 | brcmu_bprintf(strbuf, "%s %d.%02d", desc, q1, q2); | ||
1958 | } | ||
1959 | } | ||
1960 | |||
1961 | void brcmf_sdbrcm_bus_dump(struct brcmf_pub *drvr, struct brcmu_strbuf *strbuf) | ||
1962 | { | ||
1963 | struct brcmf_bus *bus = drvr->bus; | ||
1964 | |||
1965 | brcmu_bprintf(strbuf, "Bus SDIO structure:\n"); | ||
1966 | brcmu_bprintf(strbuf, | ||
1967 | "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n", | ||
1968 | bus->hostintmask, bus->intstatus, bus->sdpcm_ver); | ||
1969 | brcmu_bprintf(strbuf, | ||
1970 | "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n", | ||
1971 | bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, | ||
1972 | bus->rxskip, bus->rxlen, bus->rx_seq); | ||
1973 | brcmu_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n", | ||
1974 | bus->intr, bus->intrcount, bus->lastintrs, bus->spurious); | ||
1975 | brcmu_bprintf(strbuf, "pollrate %d pollcnt %d regfails %d\n", | ||
1976 | bus->pollrate, bus->pollcnt, bus->regfails); | ||
1977 | |||
1978 | brcmu_bprintf(strbuf, "\nAdditional counters:\n"); | ||
1979 | brcmu_bprintf(strbuf, | ||
1980 | "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n", | ||
1981 | bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong, | ||
1982 | bus->rxc_errors); | ||
1983 | brcmu_bprintf(strbuf, "rx_hdrfail %d badhdr %d badseq %d\n", | ||
1984 | bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq); | ||
1985 | brcmu_bprintf(strbuf, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n", | ||
1986 | bus->fc_rcvd, bus->fc_xoff, bus->fc_xon); | ||
1987 | brcmu_bprintf(strbuf, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n", | ||
1988 | bus->rxglomfail, bus->rxglomframes, bus->rxglompkts); | ||
1989 | brcmu_bprintf(strbuf, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs" | ||
1990 | " %d\n", | ||
1991 | (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, | ||
1992 | bus->f2rxdata, bus->f2txdata, bus->f1regdata); | ||
1993 | { | ||
1994 | brcmf_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->drvr->rx_packets, | ||
1995 | (bus->f2rxhdrs + bus->f2rxdata)); | ||
1996 | brcmf_dump_pct(strbuf, ", pkts/f1sd", bus->drvr->rx_packets, | ||
1997 | bus->f1regdata); | ||
1998 | brcmf_dump_pct(strbuf, ", pkts/sd", bus->drvr->rx_packets, | ||
1999 | (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); | ||
2000 | brcmf_dump_pct(strbuf, ", pkts/int", bus->drvr->rx_packets, | ||
2001 | bus->intrcount); | ||
2002 | brcmu_bprintf(strbuf, "\n"); | ||
2003 | |||
2004 | brcmf_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts), | ||
2005 | bus->drvr->rx_packets); | ||
2006 | brcmf_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, | ||
2007 | bus->rxglomframes); | ||
2008 | brcmu_bprintf(strbuf, "\n"); | ||
2009 | |||
2010 | brcmf_dump_pct(strbuf, "Tx: pkts/f2wr", bus->drvr->tx_packets, | ||
2011 | bus->f2txdata); | ||
2012 | brcmf_dump_pct(strbuf, ", pkts/f1sd", bus->drvr->tx_packets, | ||
2013 | bus->f1regdata); | ||
2014 | brcmf_dump_pct(strbuf, ", pkts/sd", bus->drvr->tx_packets, | ||
2015 | (bus->f2txdata + bus->f1regdata)); | ||
2016 | brcmf_dump_pct(strbuf, ", pkts/int", bus->drvr->tx_packets, | ||
2017 | bus->intrcount); | ||
2018 | brcmu_bprintf(strbuf, "\n"); | ||
2019 | |||
2020 | brcmf_dump_pct(strbuf, "Total: pkts/f2rw", | ||
2021 | (bus->drvr->tx_packets + bus->drvr->rx_packets), | ||
2022 | (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata)); | ||
2023 | brcmf_dump_pct(strbuf, ", pkts/f1sd", | ||
2024 | (bus->drvr->tx_packets + bus->drvr->rx_packets), | ||
2025 | bus->f1regdata); | ||
2026 | brcmf_dump_pct(strbuf, ", pkts/sd", | ||
2027 | (bus->drvr->tx_packets + bus->drvr->rx_packets), | ||
2028 | (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + | ||
2029 | bus->f1regdata)); | ||
2030 | brcmf_dump_pct(strbuf, ", pkts/int", | ||
2031 | (bus->drvr->tx_packets + bus->drvr->rx_packets), | ||
2032 | bus->intrcount); | ||
2033 | brcmu_bprintf(strbuf, "\n\n"); | ||
2034 | } | ||
2035 | |||
2036 | #ifdef SDTEST | ||
2037 | if (bus->pktgen_count) { | ||
2038 | brcmu_bprintf(strbuf, "pktgen config and count:\n"); | ||
2039 | brcmu_bprintf(strbuf, | ||
2040 | "freq %d count %d print %d total %d min %d len %d\n", | ||
2041 | bus->pktgen_freq, bus->pktgen_count, | ||
2042 | bus->pktgen_print, bus->pktgen_total, | ||
2043 | bus->pktgen_minlen, bus->pktgen_maxlen); | ||
2044 | brcmu_bprintf(strbuf, "send attempts %d rcvd %d fail %d\n", | ||
2045 | bus->pktgen_sent, bus->pktgen_rcvd, | ||
2046 | bus->pktgen_fail); | ||
2047 | } | ||
2048 | #endif /* SDTEST */ | ||
2049 | #ifdef BCMDBG | ||
2050 | brcmu_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n", | ||
2051 | bus->dpc_sched, " not "); | ||
2052 | brcmu_bprintf(strbuf, "blocksize %d roundup %d\n", bus->blocksize, | ||
2053 | bus->roundup); | ||
2054 | #endif /* BCMDBG */ | ||
2055 | brcmu_bprintf(strbuf, | ||
2056 | "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n", | ||
2057 | bus->clkstate, bus->activity, bus->idletime, bus->idlecount, | ||
2058 | bus->sleeping); | ||
2059 | } | ||
2060 | |||
2061 | void brcmf_bus_clearcounts(struct brcmf_pub *drvr) | ||
2062 | { | ||
2063 | struct brcmf_bus *bus = (struct brcmf_bus *) drvr->bus; | ||
2064 | |||
2065 | bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0; | ||
2066 | bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0; | ||
2067 | bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0; | ||
2068 | bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0; | ||
2069 | bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0; | ||
2070 | bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0; | ||
2071 | } | ||
2072 | |||
2073 | #ifdef SDTEST | ||
2074 | static int brcmf_sdbrcm_pktgen_get(struct brcmf_bus *bus, u8 *arg) | ||
2075 | { | ||
2076 | struct brcmf_pktgen pktgen; | ||
2077 | |||
2078 | pktgen.version = BRCMF_PKTGEN_VERSION; | ||
2079 | pktgen.freq = bus->pktgen_freq; | ||
2080 | pktgen.count = bus->pktgen_count; | ||
2081 | pktgen.print = bus->pktgen_print; | ||
2082 | pktgen.total = bus->pktgen_total; | ||
2083 | pktgen.minlen = bus->pktgen_minlen; | ||
2084 | pktgen.maxlen = bus->pktgen_maxlen; | ||
2085 | pktgen.numsent = bus->pktgen_sent; | ||
2086 | pktgen.numrcvd = bus->pktgen_rcvd; | ||
2087 | pktgen.numfail = bus->pktgen_fail; | ||
2088 | pktgen.mode = bus->pktgen_mode; | ||
2089 | pktgen.stop = bus->pktgen_stop; | ||
2090 | |||
2091 | memcpy(arg, &pktgen, sizeof(pktgen)); | ||
2092 | |||
2093 | return 0; | ||
2094 | } | ||
2095 | |||
2096 | static int brcmf_sdbrcm_pktgen_set(struct brcmf_bus *bus, u8 *arg) | ||
2097 | { | ||
2098 | struct brcmf_pktgen pktgen; | ||
2099 | uint oldcnt, oldmode; | ||
2100 | |||
2101 | memcpy(&pktgen, arg, sizeof(pktgen)); | ||
2102 | if (pktgen.version != BRCMF_PKTGEN_VERSION) | ||
2103 | return -EINVAL; | ||
2104 | |||
2105 | oldcnt = bus->pktgen_count; | ||
2106 | oldmode = bus->pktgen_mode; | ||
2107 | |||
2108 | bus->pktgen_freq = pktgen.freq; | ||
2109 | bus->pktgen_count = pktgen.count; | ||
2110 | bus->pktgen_print = pktgen.print; | ||
2111 | bus->pktgen_total = pktgen.total; | ||
2112 | bus->pktgen_minlen = pktgen.minlen; | ||
2113 | bus->pktgen_maxlen = pktgen.maxlen; | ||
2114 | bus->pktgen_mode = pktgen.mode; | ||
2115 | bus->pktgen_stop = pktgen.stop; | ||
2116 | |||
2117 | bus->pktgen_tick = bus->pktgen_ptick = 0; | ||
2118 | bus->pktgen_len = max(bus->pktgen_len, bus->pktgen_minlen); | ||
2119 | bus->pktgen_len = min(bus->pktgen_len, bus->pktgen_maxlen); | ||
2120 | |||
2121 | /* Clear counts for a new pktgen (mode change, or was stopped) */ | ||
2122 | if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) | ||
2123 | bus->pktgen_sent = bus->pktgen_rcvd = bus->pktgen_fail = 0; | ||
2124 | |||
2125 | return 0; | ||
2126 | } | ||
2127 | #endif /* SDTEST */ | ||
2128 | |||
2129 | static int | ||
2130 | brcmf_sdbrcm_membytes(struct brcmf_bus *bus, bool write, u32 address, u8 *data, | ||
2131 | uint size) | ||
2132 | { | ||
2133 | int bcmerror = 0; | ||
2134 | u32 sdaddr; | ||
2135 | uint dsize; | ||
2136 | |||
2137 | /* Determine initial transfer parameters */ | ||
2138 | sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK; | ||
2139 | if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK) | ||
2140 | dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr); | ||
2141 | else | ||
2142 | dsize = size; | ||
2143 | |||
2144 | /* Set the backplane window to include the start address */ | ||
2145 | bcmerror = brcmf_sdbrcm_set_siaddr_window(bus, address); | ||
2146 | if (bcmerror) { | ||
2147 | BRCMF_ERROR(("%s: window change failed\n", __func__)); | ||
2148 | goto xfer_done; | ||
2149 | } | ||
2150 | |||
2151 | /* Do the transfer(s) */ | ||
2152 | while (size) { | ||
2153 | BRCMF_INFO(("%s: %s %d bytes at offset 0x%08x in window" | ||
2154 | " 0x%08x\n", __func__, (write ? "write" : "read"), | ||
2155 | dsize, sdaddr, (address & SBSDIO_SBWINDOW_MASK))); | ||
2156 | bcmerror = | ||
2157 | brcmf_sdcard_rwdata(bus->card, write, sdaddr, data, dsize); | ||
2158 | if (bcmerror) { | ||
2159 | BRCMF_ERROR(("%s: membytes transfer failed\n", | ||
2160 | __func__)); | ||
2161 | break; | ||
2162 | } | ||
2163 | |||
2164 | /* Adjust for next transfer (if any) */ | ||
2165 | size -= dsize; | ||
2166 | if (size) { | ||
2167 | data += dsize; | ||
2168 | address += dsize; | ||
2169 | bcmerror = brcmf_sdbrcm_set_siaddr_window(bus, address); | ||
2170 | if (bcmerror) { | ||
2171 | BRCMF_ERROR(("%s: window change failed\n", | ||
2172 | __func__)); | ||
2173 | break; | ||
2174 | } | ||
2175 | sdaddr = 0; | ||
2176 | dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size); | ||
2177 | } | ||
2178 | } | ||
2179 | |||
2180 | xfer_done: | ||
2181 | /* Return the window to backplane enumeration space for core access */ | ||
2182 | if (brcmf_sdbrcm_set_siaddr_window(bus, | ||
2183 | brcmf_sdcard_cur_sbwad(bus->card))) { | ||
2184 | BRCMF_ERROR(("%s: FAILED to set window back to 0x%x\n", | ||
2185 | __func__, brcmf_sdcard_cur_sbwad(bus->card))); | ||
2186 | } | ||
2187 | |||
2188 | return bcmerror; | ||
2189 | } | ||
2190 | |||
2191 | #ifdef BCMDBG | ||
2192 | static int brcmf_sdbrcm_readshared(struct brcmf_bus *bus, struct sdpcm_shared *sh) | ||
2193 | { | ||
2194 | u32 addr; | ||
2195 | int rv; | ||
2196 | |||
2197 | /* Read last word in memory to determine address of | ||
2198 | sdpcm_shared structure */ | ||
2199 | rv = brcmf_sdbrcm_membytes(bus, false, bus->ramsize - 4, (u8 *)&addr, | ||
2200 | 4); | ||
2201 | if (rv < 0) | ||
2202 | return rv; | ||
2203 | |||
2204 | addr = le32_to_cpu(addr); | ||
2205 | |||
2206 | BRCMF_INFO(("sdpcm_shared address 0x%08X\n", addr)); | ||
2207 | |||
2208 | /* | ||
2209 | * Check if addr is valid. | ||
2210 | * NVRAM length at the end of memory should have been overwritten. | ||
2211 | */ | ||
2212 | if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) { | ||
2213 | BRCMF_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", | ||
2214 | __func__, addr)); | ||
2215 | return -EBADE; | ||
2216 | } | ||
2217 | |||
2218 | /* Read rte_shared structure */ | ||
2219 | rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *) sh, | ||
2220 | sizeof(struct sdpcm_shared)); | ||
2221 | if (rv < 0) | ||
2222 | return rv; | ||
2223 | |||
2224 | /* Endianness */ | ||
2225 | sh->flags = le32_to_cpu(sh->flags); | ||
2226 | sh->trap_addr = le32_to_cpu(sh->trap_addr); | ||
2227 | sh->assert_exp_addr = le32_to_cpu(sh->assert_exp_addr); | ||
2228 | sh->assert_file_addr = le32_to_cpu(sh->assert_file_addr); | ||
2229 | sh->assert_line = le32_to_cpu(sh->assert_line); | ||
2230 | sh->console_addr = le32_to_cpu(sh->console_addr); | ||
2231 | sh->msgtrace_addr = le32_to_cpu(sh->msgtrace_addr); | ||
2232 | |||
2233 | if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) { | ||
2234 | BRCMF_ERROR(("%s: sdpcm_shared version %d in brcmf " | ||
2235 | "is different than sdpcm_shared version %d in dongle\n", | ||
2236 | __func__, SDPCM_SHARED_VERSION, | ||
2237 | sh->flags & SDPCM_SHARED_VERSION_MASK)); | ||
2238 | return -EBADE; | ||
2239 | } | ||
2240 | |||
2241 | return 0; | ||
2242 | } | ||
2243 | |||
2244 | static int brcmf_sdbrcm_checkdied(struct brcmf_bus *bus, u8 *data, uint size) | ||
2245 | { | ||
2246 | int bcmerror = 0; | ||
2247 | uint msize = 512; | ||
2248 | char *mbuffer = NULL; | ||
2249 | uint maxstrlen = 256; | ||
2250 | char *str = NULL; | ||
2251 | struct brcmf_trap tr; | ||
2252 | struct sdpcm_shared sdpcm_shared; | ||
2253 | struct brcmu_strbuf strbuf; | ||
2254 | |||
2255 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
2256 | |||
2257 | if (data == NULL) { | ||
2258 | /* | ||
2259 | * Called after a rx ctrl timeout. "data" is NULL. | ||
2260 | * allocate memory to trace the trap or assert. | ||
2261 | */ | ||
2262 | size = msize; | ||
2263 | mbuffer = data = kmalloc(msize, GFP_ATOMIC); | ||
2264 | if (mbuffer == NULL) { | ||
2265 | BRCMF_ERROR(("%s: kmalloc(%d) failed\n", __func__, | ||
2266 | msize)); | ||
2267 | bcmerror = -ENOMEM; | ||
2268 | goto done; | ||
2269 | } | ||
2270 | } | ||
2271 | |||
2272 | str = kmalloc(maxstrlen, GFP_ATOMIC); | ||
2273 | if (str == NULL) { | ||
2274 | BRCMF_ERROR(("%s: kmalloc(%d) failed\n", __func__, maxstrlen)); | ||
2275 | bcmerror = -ENOMEM; | ||
2276 | goto done; | ||
2277 | } | ||
2278 | |||
2279 | bcmerror = brcmf_sdbrcm_readshared(bus, &sdpcm_shared); | ||
2280 | if (bcmerror < 0) | ||
2281 | goto done; | ||
2282 | |||
2283 | brcmu_binit(&strbuf, data, size); | ||
2284 | |||
2285 | brcmu_bprintf(&strbuf, | ||
2286 | "msgtrace address : 0x%08X\nconsole address : 0x%08X\n", | ||
2287 | sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr); | ||
2288 | |||
2289 | if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) { | ||
2290 | /* NOTE: Misspelled assert is intentional - DO NOT FIX. | ||
2291 | * (Avoids conflict with real asserts for programmatic | ||
2292 | * parsing of output.) | ||
2293 | */ | ||
2294 | brcmu_bprintf(&strbuf, "Assrt not built in dongle\n"); | ||
2295 | } | ||
2296 | |||
2297 | if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) == | ||
2298 | 0) { | ||
2299 | /* NOTE: Misspelled assert is intentional - DO NOT FIX. | ||
2300 | * (Avoids conflict with real asserts for programmatic | ||
2301 | * parsing of output.) | ||
2302 | */ | ||
2303 | brcmu_bprintf(&strbuf, "No trap%s in dongle", | ||
2304 | (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) | ||
2305 | ? "/assrt" : ""); | ||
2306 | } else { | ||
2307 | if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) { | ||
2308 | /* Download assert */ | ||
2309 | brcmu_bprintf(&strbuf, "Dongle assert"); | ||
2310 | if (sdpcm_shared.assert_exp_addr != 0) { | ||
2311 | str[0] = '\0'; | ||
2312 | bcmerror = brcmf_sdbrcm_membytes(bus, false, | ||
2313 | sdpcm_shared.assert_exp_addr, | ||
2314 | (u8 *) str, maxstrlen); | ||
2315 | if (bcmerror < 0) | ||
2316 | goto done; | ||
2317 | |||
2318 | str[maxstrlen - 1] = '\0'; | ||
2319 | brcmu_bprintf(&strbuf, " expr \"%s\"", str); | ||
2320 | } | ||
2321 | |||
2322 | if (sdpcm_shared.assert_file_addr != 0) { | ||
2323 | str[0] = '\0'; | ||
2324 | bcmerror = brcmf_sdbrcm_membytes(bus, false, | ||
2325 | sdpcm_shared.assert_file_addr, | ||
2326 | (u8 *) str, maxstrlen); | ||
2327 | if (bcmerror < 0) | ||
2328 | goto done; | ||
2329 | |||
2330 | str[maxstrlen - 1] = '\0'; | ||
2331 | brcmu_bprintf(&strbuf, " file \"%s\"", str); | ||
2332 | } | ||
2333 | |||
2334 | brcmu_bprintf(&strbuf, " line %d ", | ||
2335 | sdpcm_shared.assert_line); | ||
2336 | } | ||
2337 | |||
2338 | if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { | ||
2339 | bcmerror = brcmf_sdbrcm_membytes(bus, false, | ||
2340 | sdpcm_shared.trap_addr, (u8 *)&tr, | ||
2341 | sizeof(struct brcmf_trap)); | ||
2342 | if (bcmerror < 0) | ||
2343 | goto done; | ||
2344 | |||
2345 | brcmu_bprintf(&strbuf, | ||
2346 | "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," | ||
2347 | "lp 0x%x, rpc 0x%x Trap offset 0x%x, " | ||
2348 | "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n", | ||
2349 | tr.type, tr.epc, tr.cpsr, tr.spsr, tr.r13, | ||
2350 | tr.r14, tr.pc, sdpcm_shared.trap_addr, | ||
2351 | tr.r0, tr.r1, tr.r2, tr.r3, tr.r4, tr.r5, | ||
2352 | tr.r6, tr.r7); | ||
2353 | } | ||
2354 | } | ||
2355 | |||
2356 | if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) | ||
2357 | BRCMF_ERROR(("%s: %s\n", __func__, strbuf.origbuf)); | ||
2358 | |||
2359 | #ifdef BCMDBG | ||
2360 | if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { | ||
2361 | /* Mem dump to a file on device */ | ||
2362 | brcmf_sdbrcm_mem_dump(bus); | ||
2363 | } | ||
2364 | #endif /* BCMDBG */ | ||
2365 | |||
2366 | done: | ||
2367 | kfree(mbuffer); | ||
2368 | kfree(str); | ||
2369 | |||
2370 | return bcmerror; | ||
2371 | } | ||
2372 | |||
2373 | static int brcmf_sdbrcm_mem_dump(struct brcmf_bus *bus) | ||
2374 | { | ||
2375 | int ret = 0; | ||
2376 | int size; /* Full mem size */ | ||
2377 | int start = 0; /* Start address */ | ||
2378 | int read_size = 0; /* Read size of each iteration */ | ||
2379 | u8 *buf = NULL, *databuf = NULL; | ||
2380 | |||
2381 | /* Get full mem size */ | ||
2382 | size = bus->ramsize; | ||
2383 | buf = kmalloc(size, GFP_ATOMIC); | ||
2384 | if (!buf) { | ||
2385 | BRCMF_ERROR(("%s: Out of memory (%d bytes)\n", __func__, size)); | ||
2386 | return -1; | ||
2387 | } | ||
2388 | |||
2389 | /* Read mem content */ | ||
2390 | printk(KERN_DEBUG "Dump dongle memory"); | ||
2391 | databuf = buf; | ||
2392 | while (size) { | ||
2393 | read_size = min(MEMBLOCK, size); | ||
2394 | ret = brcmf_sdbrcm_membytes(bus, false, start, databuf, | ||
2395 | read_size); | ||
2396 | if (ret) { | ||
2397 | BRCMF_ERROR(("%s: Error membytes %d\n", __func__, ret)); | ||
2398 | kfree(buf); | ||
2399 | return -1; | ||
2400 | } | ||
2401 | printk("."); | ||
2402 | |||
2403 | /* Decrement size and increment start address */ | ||
2404 | size -= read_size; | ||
2405 | start += read_size; | ||
2406 | databuf += read_size; | ||
2407 | } | ||
2408 | printk(KERN_DEBUG "Done\n"); | ||
2409 | |||
2410 | /* free buf before return !!! */ | ||
2411 | if (brcmf_write_to_file(bus->drvr, buf, bus->ramsize)) { | ||
2412 | BRCMF_ERROR(("%s: Error writing to files\n", __func__)); | ||
2413 | return -1; | ||
2414 | } | ||
2415 | |||
2416 | /* buf free handled in brcmf_write_to_file, not here */ | ||
2417 | return 0; | ||
2418 | } | ||
2419 | |||
2420 | #define CONSOLE_LINE_MAX 192 | ||
2421 | |||
2422 | static int brcmf_sdbrcm_readconsole(struct brcmf_bus *bus) | ||
2423 | { | ||
2424 | struct brcmf_console *c = &bus->console; | ||
2425 | u8 line[CONSOLE_LINE_MAX], ch; | ||
2426 | u32 n, idx, addr; | ||
2427 | int rv; | ||
2428 | |||
2429 | /* Don't do anything until FWREADY updates console address */ | ||
2430 | if (bus->console_addr == 0) | ||
2431 | return 0; | ||
2432 | |||
2433 | /* Read console log struct */ | ||
2434 | addr = bus->console_addr + offsetof(struct rte_console, log); | ||
2435 | rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&c->log, | ||
2436 | sizeof(c->log)); | ||
2437 | if (rv < 0) | ||
2438 | return rv; | ||
2439 | |||
2440 | /* Allocate console buffer (one time only) */ | ||
2441 | if (c->buf == NULL) { | ||
2442 | c->bufsize = le32_to_cpu(c->log.buf_size); | ||
2443 | c->buf = kmalloc(c->bufsize, GFP_ATOMIC); | ||
2444 | if (c->buf == NULL) | ||
2445 | return -ENOMEM; | ||
2446 | } | ||
2447 | |||
2448 | idx = le32_to_cpu(c->log.idx); | ||
2449 | |||
2450 | /* Protect against corrupt value */ | ||
2451 | if (idx > c->bufsize) | ||
2452 | return -EBADE; | ||
2453 | |||
2454 | /* Skip reading the console buffer if the index pointer | ||
2455 | has not moved */ | ||
2456 | if (idx == c->last) | ||
2457 | return 0; | ||
2458 | |||
2459 | /* Read the console buffer */ | ||
2460 | addr = le32_to_cpu(c->log.buf); | ||
2461 | rv = brcmf_sdbrcm_membytes(bus, false, addr, c->buf, c->bufsize); | ||
2462 | if (rv < 0) | ||
2463 | return rv; | ||
2464 | |||
2465 | while (c->last != idx) { | ||
2466 | for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { | ||
2467 | if (c->last == idx) { | ||
2468 | /* This would output a partial line. | ||
2469 | * Instead, back up | ||
2470 | * the buffer pointer and output this | ||
2471 | * line next time around. | ||
2472 | */ | ||
2473 | if (c->last >= n) | ||
2474 | c->last -= n; | ||
2475 | else | ||
2476 | c->last = c->bufsize - n; | ||
2477 | goto break2; | ||
2478 | } | ||
2479 | ch = c->buf[c->last]; | ||
2480 | c->last = (c->last + 1) % c->bufsize; | ||
2481 | if (ch == '\n') | ||
2482 | break; | ||
2483 | line[n] = ch; | ||
2484 | } | ||
2485 | |||
2486 | if (n > 0) { | ||
2487 | if (line[n - 1] == '\r') | ||
2488 | n--; | ||
2489 | line[n] = 0; | ||
2490 | printk(KERN_DEBUG "CONSOLE: %s\n", line); | ||
2491 | } | ||
2492 | } | ||
2493 | break2: | ||
2494 | |||
2495 | return 0; | ||
2496 | } | ||
2497 | #endif /* BCMDBG */ | ||
2498 | |||
2499 | int brcmf_sdbrcm_downloadvars(struct brcmf_bus *bus, void *arg, int len) | ||
2500 | { | ||
2501 | int bcmerror = 0; | ||
2502 | |||
2503 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
2504 | |||
2505 | /* Basic sanity checks */ | ||
2506 | if (bus->drvr->up) { | ||
2507 | bcmerror = -EISCONN; | ||
2508 | goto err; | ||
2509 | } | ||
2510 | if (!len) { | ||
2511 | bcmerror = -EOVERFLOW; | ||
2512 | goto err; | ||
2513 | } | ||
2514 | |||
2515 | /* Free the old ones and replace with passed variables */ | ||
2516 | kfree(bus->vars); | ||
2517 | |||
2518 | bus->vars = kmalloc(len, GFP_ATOMIC); | ||
2519 | bus->varsz = bus->vars ? len : 0; | ||
2520 | if (bus->vars == NULL) { | ||
2521 | bcmerror = -ENOMEM; | ||
2522 | goto err; | ||
2523 | } | ||
2524 | |||
2525 | /* Copy the passed variables, which should include the | ||
2526 | terminating double-null */ | ||
2527 | memcpy(bus->vars, arg, bus->varsz); | ||
2528 | err: | ||
2529 | return bcmerror; | ||
2530 | } | ||
2531 | |||
2532 | static int | ||
2533 | brcmf_sdbrcm_doiovar(struct brcmf_bus *bus, const struct brcmu_iovar *vi, u32 actionid, | ||
2534 | const char *name, void *params, int plen, void *arg, int len, | ||
2535 | int val_size) | ||
2536 | { | ||
2537 | int bcmerror = 0; | ||
2538 | s32 int_val = 0; | ||
2539 | bool bool_val = 0; | ||
2540 | |||
2541 | BRCMF_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p " | ||
2542 | "len %d val_size %d\n", __func__, actionid, name, params, | ||
2543 | plen, arg, len, val_size)); | ||
2544 | |||
2545 | bcmerror = brcmu_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid)); | ||
2546 | if (bcmerror != 0) | ||
2547 | goto exit; | ||
2548 | |||
2549 | if (plen >= (int)sizeof(int_val)) | ||
2550 | memcpy(&int_val, params, sizeof(int_val)); | ||
2551 | |||
2552 | bool_val = (int_val != 0) ? true : false; | ||
2553 | |||
2554 | /* Some ioctls use the bus */ | ||
2555 | brcmf_sdbrcm_sdlock(bus); | ||
2556 | |||
2557 | /* Check if dongle is in reset. If so, only allow DEVRESET iovars */ | ||
2558 | if (bus->drvr->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) || | ||
2559 | actionid == IOV_GVAL(IOV_DEVRESET))) { | ||
2560 | bcmerror = -EPERM; | ||
2561 | goto exit; | ||
2562 | } | ||
2563 | |||
2564 | /* Handle sleep stuff before any clock mucking */ | ||
2565 | if (vi->varid == IOV_SLEEP) { | ||
2566 | if (IOV_ISSET(actionid)) { | ||
2567 | bcmerror = brcmf_sdbrcm_bussleep(bus, bool_val); | ||
2568 | } else { | ||
2569 | int_val = (s32) bus->sleeping; | ||
2570 | memcpy(arg, &int_val, val_size); | ||
2571 | } | ||
2572 | goto exit; | ||
2573 | } | ||
2574 | |||
2575 | /* Request clock to allow SDIO accesses */ | ||
2576 | if (!bus->drvr->dongle_reset) { | ||
2577 | BUS_WAKE(bus); | ||
2578 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | ||
2579 | } | ||
2580 | |||
2581 | switch (actionid) { | ||
2582 | case IOV_GVAL(IOV_INTR): | ||
2583 | int_val = (s32) bus->intr; | ||
2584 | memcpy(arg, &int_val, val_size); | ||
2585 | break; | ||
2586 | |||
2587 | case IOV_SVAL(IOV_INTR): | ||
2588 | bus->intr = bool_val; | ||
2589 | bus->intdis = false; | ||
2590 | if (bus->drvr->up) { | ||
2591 | BRCMF_INTR(("%s: %s SDIO interrupts\n", __func__, | ||
2592 | bus->intr ? "enable" : "disable")); | ||
2593 | if (bus->intr) { | ||
2594 | brcmf_sdcard_intr_enable(bus->card); | ||
2595 | } else { | ||
2596 | brcmf_sdcard_intr_disable(bus->card); | ||
2597 | } | ||
2598 | } | ||
2599 | break; | ||
2600 | |||
2601 | case IOV_GVAL(IOV_POLLRATE): | ||
2602 | int_val = (s32) bus->pollrate; | ||
2603 | memcpy(arg, &int_val, val_size); | ||
2604 | break; | ||
2605 | |||
2606 | case IOV_SVAL(IOV_POLLRATE): | ||
2607 | bus->pollrate = (uint) int_val; | ||
2608 | bus->poll = (bus->pollrate != 0); | ||
2609 | break; | ||
2610 | |||
2611 | case IOV_GVAL(IOV_IDLETIME): | ||
2612 | int_val = bus->idletime; | ||
2613 | memcpy(arg, &int_val, val_size); | ||
2614 | break; | ||
2615 | |||
2616 | case IOV_SVAL(IOV_IDLETIME): | ||
2617 | if ((int_val < 0) && (int_val != BRCMF_IDLE_IMMEDIATE)) | ||
2618 | bcmerror = -EINVAL; | ||
2619 | else | ||
2620 | bus->idletime = int_val; | ||
2621 | break; | ||
2622 | |||
2623 | case IOV_GVAL(IOV_IDLECLOCK): | ||
2624 | int_val = (s32) bus->idleclock; | ||
2625 | memcpy(arg, &int_val, val_size); | ||
2626 | break; | ||
2627 | |||
2628 | case IOV_SVAL(IOV_IDLECLOCK): | ||
2629 | bus->idleclock = int_val; | ||
2630 | break; | ||
2631 | |||
2632 | case IOV_GVAL(IOV_SD1IDLE): | ||
2633 | int_val = (s32) sd1idle; | ||
2634 | memcpy(arg, &int_val, val_size); | ||
2635 | break; | ||
2636 | |||
2637 | case IOV_SVAL(IOV_SD1IDLE): | ||
2638 | sd1idle = bool_val; | ||
2639 | break; | ||
2640 | |||
2641 | case IOV_SVAL(IOV_MEMBYTES): | ||
2642 | case IOV_GVAL(IOV_MEMBYTES): | ||
2643 | { | ||
2644 | u32 address; | ||
2645 | uint size, dsize; | ||
2646 | u8 *data; | ||
2647 | |||
2648 | bool set = (actionid == IOV_SVAL(IOV_MEMBYTES)); | ||
2649 | |||
2650 | address = (u32) int_val; | ||
2651 | memcpy(&int_val, (char *)params + sizeof(int_val), | ||
2652 | sizeof(int_val)); | ||
2653 | size = (uint) int_val; | ||
2654 | |||
2655 | /* Do some validation */ | ||
2656 | dsize = set ? plen - (2 * sizeof(int)) : len; | ||
2657 | if (dsize < size) { | ||
2658 | BRCMF_ERROR(("%s: error on %s membytes, addr " | ||
2659 | "0x%08x size %d dsize %d\n", | ||
2660 | __func__, (set ? "set" : "get"), | ||
2661 | address, size, dsize)); | ||
2662 | bcmerror = -EINVAL; | ||
2663 | break; | ||
2664 | } | ||
2665 | |||
2666 | BRCMF_INFO(("%s: Request to %s %d bytes at address " | ||
2667 | "0x%08x\n", __func__, | ||
2668 | (set ? "write" : "read"), size, address)); | ||
2669 | |||
2670 | /* If we know about SOCRAM, check for a fit */ | ||
2671 | if ((bus->orig_ramsize) && | ||
2672 | ((address > bus->orig_ramsize) | ||
2673 | || (address + size > bus->orig_ramsize))) { | ||
2674 | BRCMF_ERROR(("%s: ramsize 0x%08x doesn't have" | ||
2675 | " %d bytes at 0x%08x\n", __func__, | ||
2676 | bus->orig_ramsize, size, address)); | ||
2677 | bcmerror = -EINVAL; | ||
2678 | break; | ||
2679 | } | ||
2680 | |||
2681 | /* Generate the actual data pointer */ | ||
2682 | data = | ||
2683 | set ? (u8 *) params + | ||
2684 | 2 * sizeof(int) : (u8 *) arg; | ||
2685 | |||
2686 | /* Call to do the transfer */ | ||
2687 | bcmerror = brcmf_sdbrcm_membytes(bus, set, address, | ||
2688 | data, size); | ||
2689 | |||
2690 | break; | ||
2691 | } | ||
2692 | |||
2693 | case IOV_GVAL(IOV_MEMSIZE): | ||
2694 | int_val = (s32) bus->ramsize; | ||
2695 | memcpy(arg, &int_val, val_size); | ||
2696 | break; | ||
2697 | |||
2698 | case IOV_GVAL(IOV_SDIOD_DRIVE): | ||
2699 | int_val = (s32) brcmf_sdiod_drive_strength; | ||
2700 | memcpy(arg, &int_val, val_size); | ||
2701 | break; | ||
2702 | |||
2703 | case IOV_SVAL(IOV_SDIOD_DRIVE): | ||
2704 | brcmf_sdiod_drive_strength = int_val; | ||
2705 | brcmf_sdbrcm_sdiod_drive_strength_init(bus, | ||
2706 | brcmf_sdiod_drive_strength); | ||
2707 | break; | ||
2708 | |||
2709 | case IOV_SVAL(IOV_DOWNLOAD): | ||
2710 | bcmerror = brcmf_sdbrcm_download_state(bus, bool_val); | ||
2711 | break; | ||
2712 | |||
2713 | case IOV_SVAL(IOV_VARS): | ||
2714 | bcmerror = brcmf_sdbrcm_downloadvars(bus, arg, len); | ||
2715 | break; | ||
2716 | |||
2717 | case IOV_GVAL(IOV_READAHEAD): | ||
2718 | int_val = (s32) brcmf_readahead; | ||
2719 | memcpy(arg, &int_val, val_size); | ||
2720 | break; | ||
2721 | |||
2722 | case IOV_SVAL(IOV_READAHEAD): | ||
2723 | if (bool_val && !brcmf_readahead) | ||
2724 | bus->nextlen = 0; | ||
2725 | brcmf_readahead = bool_val; | ||
2726 | break; | ||
2727 | |||
2728 | case IOV_GVAL(IOV_SDRXCHAIN): | ||
2729 | int_val = (s32) bus->use_rxchain; | ||
2730 | memcpy(arg, &int_val, val_size); | ||
2731 | break; | ||
2732 | |||
2733 | case IOV_SVAL(IOV_SDRXCHAIN): | ||
2734 | if (bool_val && !bus->sd_rxchain) | ||
2735 | bcmerror = -ENOTSUPP; | ||
2736 | else | ||
2737 | bus->use_rxchain = bool_val; | ||
2738 | break; | ||
2739 | case IOV_GVAL(IOV_ALIGNCTL): | ||
2740 | int_val = (s32) brcmf_alignctl; | ||
2741 | memcpy(arg, &int_val, val_size); | ||
2742 | break; | ||
2743 | |||
2744 | case IOV_SVAL(IOV_ALIGNCTL): | ||
2745 | brcmf_alignctl = bool_val; | ||
2746 | break; | ||
2747 | |||
2748 | case IOV_GVAL(IOV_SDALIGN): | ||
2749 | int_val = BRCMF_SDALIGN; | ||
2750 | memcpy(arg, &int_val, val_size); | ||
2751 | break; | ||
2752 | |||
2753 | #ifdef BCMDBG | ||
2754 | case IOV_GVAL(IOV_VARS): | ||
2755 | if (bus->varsz < (uint) len) | ||
2756 | memcpy(arg, bus->vars, bus->varsz); | ||
2757 | else | ||
2758 | bcmerror = -EOVERFLOW; | ||
2759 | break; | ||
2760 | #endif /* BCMDBG */ | ||
2761 | |||
2762 | #ifdef BCMDBG | ||
2763 | case IOV_GVAL(IOV_DCONSOLE_POLL): | ||
2764 | int_val = (s32) brcmf_console_ms; | ||
2765 | memcpy(arg, &int_val, val_size); | ||
2766 | break; | ||
2767 | |||
2768 | case IOV_SVAL(IOV_DCONSOLE_POLL): | ||
2769 | brcmf_console_ms = (uint) int_val; | ||
2770 | break; | ||
2771 | |||
2772 | case IOV_SVAL(IOV_CONS): | ||
2773 | if (len > 0) | ||
2774 | bcmerror = brcmf_sdbrcm_bus_console_in(bus->drvr, | ||
2775 | arg, len - 1); | ||
2776 | break; | ||
2777 | |||
2778 | case IOV_GVAL(IOV_SDREG): | ||
2779 | { | ||
2780 | struct brcmf_sdreg *sd_ptr; | ||
2781 | u32 addr, size; | ||
2782 | |||
2783 | sd_ptr = (struct brcmf_sdreg *) params; | ||
2784 | |||
2785 | addr = bus->ci->buscorebase + sd_ptr->offset; | ||
2786 | size = sd_ptr->func; | ||
2787 | int_val = (s32) brcmf_sdcard_reg_read(bus->card, addr, | ||
2788 | size); | ||
2789 | if (brcmf_sdcard_regfail(bus->card)) | ||
2790 | bcmerror = -EIO; | ||
2791 | memcpy(arg, &int_val, sizeof(s32)); | ||
2792 | break; | ||
2793 | } | ||
2794 | |||
2795 | case IOV_SVAL(IOV_SDREG): | ||
2796 | { | ||
2797 | struct brcmf_sdreg *sd_ptr; | ||
2798 | u32 addr, size; | ||
2799 | |||
2800 | sd_ptr = (struct brcmf_sdreg *) params; | ||
2801 | |||
2802 | addr = bus->ci->buscorebase + sd_ptr->offset; | ||
2803 | size = sd_ptr->func; | ||
2804 | brcmf_sdcard_reg_write(bus->card, addr, size, | ||
2805 | sd_ptr->value); | ||
2806 | if (brcmf_sdcard_regfail(bus->card)) | ||
2807 | bcmerror = -EIO; | ||
2808 | break; | ||
2809 | } | ||
2810 | |||
2811 | /* Same as above, but offset is not backplane | ||
2812 | (not SDIO core) */ | ||
2813 | case IOV_GVAL(IOV_SBREG): | ||
2814 | { | ||
2815 | struct brcmf_sdreg sdreg; | ||
2816 | u32 addr, size; | ||
2817 | |||
2818 | memcpy(&sdreg, params, sizeof(sdreg)); | ||
2819 | |||
2820 | addr = SI_ENUM_BASE + sdreg.offset; | ||
2821 | size = sdreg.func; | ||
2822 | int_val = (s32) brcmf_sdcard_reg_read(bus->card, addr, | ||
2823 | size); | ||
2824 | if (brcmf_sdcard_regfail(bus->card)) | ||
2825 | bcmerror = -EIO; | ||
2826 | memcpy(arg, &int_val, sizeof(s32)); | ||
2827 | break; | ||
2828 | } | ||
2829 | |||
2830 | case IOV_SVAL(IOV_SBREG): | ||
2831 | { | ||
2832 | struct brcmf_sdreg sdreg; | ||
2833 | u32 addr, size; | ||
2834 | |||
2835 | memcpy(&sdreg, params, sizeof(sdreg)); | ||
2836 | |||
2837 | addr = SI_ENUM_BASE + sdreg.offset; | ||
2838 | size = sdreg.func; | ||
2839 | brcmf_sdcard_reg_write(bus->card, addr, size, | ||
2840 | sdreg.value); | ||
2841 | if (brcmf_sdcard_regfail(bus->card)) | ||
2842 | bcmerror = -EIO; | ||
2843 | break; | ||
2844 | } | ||
2845 | |||
2846 | case IOV_GVAL(IOV_SDCIS): | ||
2847 | { | ||
2848 | *(char *)arg = 0; | ||
2849 | |||
2850 | strcat(arg, "\nFunc 0\n"); | ||
2851 | brcmf_sdcard_cis_read(bus->card, 0x10, | ||
2852 | (u8 *) arg + strlen(arg), | ||
2853 | SBSDIO_CIS_SIZE_LIMIT); | ||
2854 | strcat(arg, "\nFunc 1\n"); | ||
2855 | brcmf_sdcard_cis_read(bus->card, 0x11, | ||
2856 | (u8 *) arg + strlen(arg), | ||
2857 | SBSDIO_CIS_SIZE_LIMIT); | ||
2858 | strcat(arg, "\nFunc 2\n"); | ||
2859 | brcmf_sdcard_cis_read(bus->card, 0x12, | ||
2860 | (u8 *) arg + strlen(arg), | ||
2861 | SBSDIO_CIS_SIZE_LIMIT); | ||
2862 | break; | ||
2863 | } | ||
2864 | |||
2865 | case IOV_GVAL(IOV_FORCEEVEN): | ||
2866 | int_val = (s32) forcealign; | ||
2867 | memcpy(arg, &int_val, val_size); | ||
2868 | break; | ||
2869 | |||
2870 | case IOV_SVAL(IOV_FORCEEVEN): | ||
2871 | forcealign = bool_val; | ||
2872 | break; | ||
2873 | |||
2874 | case IOV_GVAL(IOV_TXBOUND): | ||
2875 | int_val = (s32) brcmf_txbound; | ||
2876 | memcpy(arg, &int_val, val_size); | ||
2877 | break; | ||
2878 | |||
2879 | case IOV_SVAL(IOV_TXBOUND): | ||
2880 | brcmf_txbound = (uint) int_val; | ||
2881 | break; | ||
2882 | |||
2883 | case IOV_GVAL(IOV_RXBOUND): | ||
2884 | int_val = (s32) brcmf_rxbound; | ||
2885 | memcpy(arg, &int_val, val_size); | ||
2886 | break; | ||
2887 | |||
2888 | case IOV_SVAL(IOV_RXBOUND): | ||
2889 | brcmf_rxbound = (uint) int_val; | ||
2890 | break; | ||
2891 | |||
2892 | case IOV_GVAL(IOV_TXMINMAX): | ||
2893 | int_val = (s32) brcmf_txminmax; | ||
2894 | memcpy(arg, &int_val, val_size); | ||
2895 | break; | ||
2896 | |||
2897 | case IOV_SVAL(IOV_TXMINMAX): | ||
2898 | brcmf_txminmax = (uint) int_val; | ||
2899 | break; | ||
2900 | #endif /* BCMDBG */ | ||
2901 | |||
2902 | #ifdef SDTEST | ||
2903 | case IOV_GVAL(IOV_EXTLOOP): | ||
2904 | int_val = (s32) bus->ext_loop; | ||
2905 | memcpy(arg, &int_val, val_size); | ||
2906 | break; | ||
2907 | |||
2908 | case IOV_SVAL(IOV_EXTLOOP): | ||
2909 | bus->ext_loop = bool_val; | ||
2910 | break; | ||
2911 | |||
2912 | case IOV_GVAL(IOV_PKTGEN): | ||
2913 | bcmerror = brcmf_sdbrcm_pktgen_get(bus, arg); | ||
2914 | break; | ||
2915 | |||
2916 | case IOV_SVAL(IOV_PKTGEN): | ||
2917 | bcmerror = brcmf_sdbrcm_pktgen_set(bus, arg); | ||
2918 | break; | ||
2919 | #endif /* SDTEST */ | ||
2920 | |||
2921 | case IOV_SVAL(IOV_DEVRESET): | ||
2922 | BRCMF_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d " | ||
2923 | "busstate=%d\n", | ||
2924 | __func__, bool_val, bus->drvr->dongle_reset, | ||
2925 | bus->drvr->busstate)); | ||
2926 | |||
2927 | brcmf_bus_devreset(bus->drvr, (u8) bool_val); | ||
2928 | |||
2929 | break; | ||
2930 | |||
2931 | case IOV_GVAL(IOV_DEVRESET): | ||
2932 | BRCMF_TRACE(("%s: Called get IOV_DEVRESET\n", __func__)); | ||
2933 | |||
2934 | /* Get its status */ | ||
2935 | int_val = (bool) bus->drvr->dongle_reset; | ||
2936 | memcpy(arg, &int_val, val_size); | ||
2937 | |||
2938 | break; | ||
2939 | |||
2940 | case IOV_GVAL(IOV_WDTICK): | ||
2941 | int_val = (s32) brcmf_watchdog_ms; | ||
2942 | memcpy(arg, &int_val, val_size); | ||
2943 | break; | ||
2944 | |||
2945 | case IOV_SVAL(IOV_WDTICK): | ||
2946 | if (!bus->drvr->up) { | ||
2947 | bcmerror = -ENOLINK; | ||
2948 | break; | ||
2949 | } | ||
2950 | brcmf_sdbrcm_wd_timer(bus, (uint) int_val); | ||
2951 | break; | ||
2952 | |||
2953 | default: | ||
2954 | bcmerror = -ENOTSUPP; | ||
2955 | break; | ||
2956 | } | ||
2957 | |||
2958 | exit: | ||
2959 | if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && !bus->dpc_sched) { | ||
2960 | bus->activity = false; | ||
2961 | brcmf_sdbrcm_clkctl(bus, CLK_NONE, true); | ||
2962 | } | ||
2963 | |||
2964 | brcmf_sdbrcm_sdunlock(bus); | ||
2965 | |||
2966 | if (actionid == IOV_SVAL(IOV_DEVRESET) && bool_val == false) | ||
2967 | brcmf_c_preinit_ioctls(bus->drvr); | ||
2968 | |||
2969 | return bcmerror; | ||
2970 | } | ||
2971 | |||
2972 | static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus) | ||
2973 | { | ||
2974 | int bcmerror = 0; | ||
2975 | u32 varsize; | ||
2976 | u32 varaddr; | ||
2977 | u8 *vbuffer; | ||
2978 | u32 varsizew; | ||
2979 | #ifdef BCMDBG | ||
2980 | char *nvram_ularray; | ||
2981 | #endif /* BCMDBG */ | ||
2982 | |||
2983 | /* Even if there are no vars are to be written, we still | ||
2984 | need to set the ramsize. */ | ||
2985 | varsize = bus->varsz ? roundup(bus->varsz, 4) : 0; | ||
2986 | varaddr = (bus->ramsize - 4) - varsize; | ||
2987 | |||
2988 | if (bus->vars) { | ||
2989 | vbuffer = kzalloc(varsize, GFP_ATOMIC); | ||
2990 | if (!vbuffer) | ||
2991 | return -ENOMEM; | ||
2992 | |||
2993 | memcpy(vbuffer, bus->vars, bus->varsz); | ||
2994 | |||
2995 | /* Write the vars list */ | ||
2996 | bcmerror = | ||
2997 | brcmf_sdbrcm_membytes(bus, true, varaddr, vbuffer, varsize); | ||
2998 | #ifdef BCMDBG | ||
2999 | /* Verify NVRAM bytes */ | ||
3000 | BRCMF_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize)); | ||
3001 | nvram_ularray = kmalloc(varsize, GFP_ATOMIC); | ||
3002 | if (!nvram_ularray) | ||
3003 | return -ENOMEM; | ||
3004 | |||
3005 | /* Upload image to verify downloaded contents. */ | ||
3006 | memset(nvram_ularray, 0xaa, varsize); | ||
3007 | |||
3008 | /* Read the vars list to temp buffer for comparison */ | ||
3009 | bcmerror = | ||
3010 | brcmf_sdbrcm_membytes(bus, false, varaddr, nvram_ularray, | ||
3011 | varsize); | ||
3012 | if (bcmerror) { | ||
3013 | BRCMF_ERROR(("%s: error %d on reading %d nvram bytes" | ||
3014 | " at 0x%08x\n", __func__, bcmerror, | ||
3015 | varsize, varaddr)); | ||
3016 | } | ||
3017 | /* Compare the org NVRAM with the one read from RAM */ | ||
3018 | if (memcmp(vbuffer, nvram_ularray, varsize)) { | ||
3019 | BRCMF_ERROR(("%s: Downloaded NVRAM image is " | ||
3020 | "corrupted.\n", __func__)); | ||
3021 | } else | ||
3022 | BRCMF_ERROR(("%s: Download/Upload/Compare of" | ||
3023 | " NVRAM ok.\n", __func__)); | ||
3024 | |||
3025 | kfree(nvram_ularray); | ||
3026 | #endif /* BCMDBG */ | ||
3027 | |||
3028 | kfree(vbuffer); | ||
3029 | } | ||
3030 | |||
3031 | /* adjust to the user specified RAM */ | ||
3032 | BRCMF_INFO(("Physical memory size: %d, usable memory size: %d\n", | ||
3033 | bus->orig_ramsize, bus->ramsize)); | ||
3034 | BRCMF_INFO(("Vars are at %d, orig varsize is %d\n", varaddr, varsize)); | ||
3035 | varsize = ((bus->orig_ramsize - 4) - varaddr); | ||
3036 | |||
3037 | /* | ||
3038 | * Determine the length token: | ||
3039 | * Varsize, converted to words, in lower 16-bits, checksum | ||
3040 | * in upper 16-bits. | ||
3041 | */ | ||
3042 | if (bcmerror) { | ||
3043 | varsizew = 0; | ||
3044 | } else { | ||
3045 | varsizew = varsize / 4; | ||
3046 | varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); | ||
3047 | varsizew = cpu_to_le32(varsizew); | ||
3048 | } | ||
3049 | |||
3050 | BRCMF_INFO(("New varsize is %d, length token=0x%08x\n", varsize, | ||
3051 | varsizew)); | ||
3052 | |||
3053 | /* Write the length token to the last word */ | ||
3054 | bcmerror = brcmf_sdbrcm_membytes(bus, true, (bus->orig_ramsize - 4), | ||
3055 | (u8 *)&varsizew, 4); | ||
3056 | |||
3057 | return bcmerror; | ||
3058 | } | ||
3059 | |||
3060 | static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter) | ||
3061 | { | ||
3062 | uint retries; | ||
3063 | u32 regdata; | ||
3064 | int bcmerror = 0; | ||
3065 | |||
3066 | /* To enter download state, disable ARM and reset SOCRAM. | ||
3067 | * To exit download state, simply reset ARM (default is RAM boot). | ||
3068 | */ | ||
3069 | if (enter) { | ||
3070 | bus->alp_only = true; | ||
3071 | |||
3072 | brcmf_sdbrcm_chip_disablecore(bus->card, bus->ci->armcorebase); | ||
3073 | |||
3074 | brcmf_sdbrcm_chip_resetcore(bus->card, bus->ci->ramcorebase); | ||
3075 | |||
3076 | /* Clear the top bit of memory */ | ||
3077 | if (bus->ramsize) { | ||
3078 | u32 zeros = 0; | ||
3079 | brcmf_sdbrcm_membytes(bus, true, bus->ramsize - 4, | ||
3080 | (u8 *)&zeros, 4); | ||
3081 | } | ||
3082 | } else { | ||
3083 | regdata = brcmf_sdcard_reg_read(bus->card, | ||
3084 | CORE_SB(bus->ci->ramcorebase, sbtmstatelow), 4); | ||
3085 | regdata &= (SBTML_RESET | SBTML_REJ_MASK | | ||
3086 | (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); | ||
3087 | if ((SICF_CLOCK_EN << SBTML_SICF_SHIFT) != regdata) { | ||
3088 | BRCMF_ERROR(("%s: SOCRAM core is down after reset?\n", | ||
3089 | __func__)); | ||
3090 | bcmerror = -EBADE; | ||
3091 | goto fail; | ||
3092 | } | ||
3093 | |||
3094 | bcmerror = brcmf_sdbrcm_write_vars(bus); | ||
3095 | if (bcmerror) { | ||
3096 | BRCMF_ERROR(("%s: no vars written to RAM\n", __func__)); | ||
3097 | bcmerror = 0; | ||
3098 | } | ||
3099 | |||
3100 | w_sdreg32(bus, 0xFFFFFFFF, | ||
3101 | offsetof(struct sdpcmd_regs, intstatus), &retries); | ||
3102 | |||
3103 | brcmf_sdbrcm_chip_resetcore(bus->card, bus->ci->armcorebase); | ||
3104 | |||
3105 | /* Allow HT Clock now that the ARM is running. */ | ||
3106 | bus->alp_only = false; | ||
3107 | |||
3108 | bus->drvr->busstate = BRCMF_BUS_LOAD; | ||
3109 | } | ||
3110 | fail: | ||
3111 | return bcmerror; | ||
3112 | } | ||
3113 | |||
3114 | int | ||
3115 | brcmf_sdbrcm_bus_iovar_op(struct brcmf_pub *drvr, const char *name, | ||
3116 | void *params, int plen, void *arg, int len, bool set) | ||
3117 | { | ||
3118 | struct brcmf_bus *bus = drvr->bus; | ||
3119 | const struct brcmu_iovar *vi = NULL; | ||
3120 | int bcmerror = 0; | ||
3121 | int val_size; | ||
3122 | u32 actionid; | ||
3123 | |||
3124 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
3125 | |||
3126 | if (name == NULL || len <= 0) | ||
3127 | return -EINVAL; | ||
3128 | |||
3129 | /* Set does not take qualifiers */ | ||
3130 | if (set && (params || plen)) | ||
3131 | return -EINVAL; | ||
3132 | |||
3133 | /* Get must have return space;*/ | ||
3134 | if (!set && !(arg && len)) | ||
3135 | return -EINVAL; | ||
3136 | |||
3137 | /* Look up var locally; if not found pass to host driver */ | ||
3138 | vi = brcmu_iovar_lookup(brcmf_sdio_iovars, name); | ||
3139 | if (vi == NULL) { | ||
3140 | brcmf_sdbrcm_sdlock(bus); | ||
3141 | |||
3142 | BUS_WAKE(bus); | ||
3143 | |||
3144 | /* Turn on clock in case SD command needs backplane */ | ||
3145 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | ||
3146 | |||
3147 | bcmerror = brcmf_sdcard_iovar_op(bus->card, name, params, plen, | ||
3148 | arg, len, set); | ||
3149 | |||
3150 | /* Similar check for blocksize change */ | ||
3151 | if (set && strcmp(name, "sd_blocksize") == 0) { | ||
3152 | s32 fnum = 2; | ||
3153 | if (brcmf_sdcard_iovar_op | ||
3154 | (bus->card, "sd_blocksize", &fnum, sizeof(s32), | ||
3155 | &bus->blocksize, sizeof(s32), | ||
3156 | false) != 0) { | ||
3157 | bus->blocksize = 0; | ||
3158 | BRCMF_ERROR(("%s: fail on %s get\n", __func__, | ||
3159 | "sd_blocksize")); | ||
3160 | } else { | ||
3161 | BRCMF_INFO(("%s: noted sd_blocksize update," | ||
3162 | " value now %d\n", __func__, | ||
3163 | bus->blocksize)); | ||
3164 | } | ||
3165 | } | ||
3166 | bus->roundup = min(max_roundup, bus->blocksize); | ||
3167 | |||
3168 | if (bus->idletime == BRCMF_IDLE_IMMEDIATE && | ||
3169 | !bus->dpc_sched) { | ||
3170 | bus->activity = false; | ||
3171 | brcmf_sdbrcm_clkctl(bus, CLK_NONE, true); | ||
3172 | } | ||
3173 | |||
3174 | brcmf_sdbrcm_sdunlock(bus); | ||
3175 | goto exit; | ||
3176 | } | ||
3177 | |||
3178 | BRCMF_CTL(("%s: %s %s, len %d plen %d\n", __func__, | ||
3179 | name, (set ? "set" : "get"), len, plen)); | ||
3180 | |||
3181 | /* set up 'params' pointer in case this is a set command so that | ||
3182 | * the convenience int and bool code can be common to set and get | ||
3183 | */ | ||
3184 | if (params == NULL) { | ||
3185 | params = arg; | ||
3186 | plen = len; | ||
3187 | } | ||
3188 | |||
3189 | if (vi->type == IOVT_VOID) | ||
3190 | val_size = 0; | ||
3191 | else if (vi->type == IOVT_BUFFER) | ||
3192 | val_size = len; | ||
3193 | else | ||
3194 | /* all other types are integer sized */ | ||
3195 | val_size = sizeof(int); | ||
3196 | |||
3197 | actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); | ||
3198 | bcmerror = brcmf_sdbrcm_doiovar(bus, vi, actionid, name, params, plen, | ||
3199 | arg, len, val_size); | ||
3200 | |||
3201 | exit: | ||
3202 | return bcmerror; | ||
3203 | } | ||
3204 | |||
3205 | void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus, bool enforce_mutex) | ||
3206 | { | ||
3207 | u32 local_hostintmask; | ||
3208 | u8 saveclk; | ||
3209 | uint retries; | ||
3210 | int err; | ||
3211 | |||
3212 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
3213 | |||
3214 | if (enforce_mutex) | ||
3215 | brcmf_sdbrcm_sdlock(bus); | ||
3216 | |||
3217 | BUS_WAKE(bus); | ||
3218 | |||
3219 | /* Enable clock for device interrupts */ | ||
3220 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | ||
3221 | |||
3222 | if (bus->watchdog_tsk) { | ||
3223 | send_sig(SIGTERM, bus->watchdog_tsk, 1); | ||
3224 | kthread_stop(bus->watchdog_tsk); | ||
3225 | bus->watchdog_tsk = NULL; | ||
3226 | } | ||
3227 | |||
3228 | if (bus->dpc_tsk) { | ||
3229 | send_sig(SIGTERM, bus->dpc_tsk, 1); | ||
3230 | kthread_stop(bus->dpc_tsk); | ||
3231 | bus->dpc_tsk = NULL; | ||
3232 | } else | ||
3233 | tasklet_kill(&bus->tasklet); | ||
3234 | |||
3235 | /* Disable and clear interrupts at the chip level also */ | ||
3236 | w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries); | ||
3237 | local_hostintmask = bus->hostintmask; | ||
3238 | bus->hostintmask = 0; | ||
3239 | |||
3240 | /* Change our idea of bus state */ | ||
3241 | bus->drvr->busstate = BRCMF_BUS_DOWN; | ||
3242 | |||
3243 | /* Force clocks on backplane to be sure F2 interrupt propagates */ | ||
3244 | saveclk = brcmf_sdcard_cfg_read(bus->card, SDIO_FUNC_1, | ||
3245 | SBSDIO_FUNC1_CHIPCLKCSR, &err); | ||
3246 | if (!err) { | ||
3247 | brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, | ||
3248 | SBSDIO_FUNC1_CHIPCLKCSR, | ||
3249 | (saveclk | SBSDIO_FORCE_HT), &err); | ||
3250 | } | ||
3251 | if (err) { | ||
3252 | BRCMF_ERROR(("%s: Failed to force clock for F2: err %d\n", | ||
3253 | __func__, err)); | ||
3254 | } | ||
3255 | |||
3256 | /* Turn off the bus (F2), free any pending packets */ | ||
3257 | BRCMF_INTR(("%s: disable SDIO interrupts\n", __func__)); | ||
3258 | brcmf_sdcard_intr_disable(bus->card); | ||
3259 | brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_0, SDIO_CCCR_IOEx, | ||
3260 | SDIO_FUNC_ENABLE_1, NULL); | ||
3261 | |||
3262 | /* Clear any pending interrupts now that F2 is disabled */ | ||
3263 | w_sdreg32(bus, local_hostintmask, | ||
3264 | offsetof(struct sdpcmd_regs, intstatus), &retries); | ||
3265 | |||
3266 | /* Turn off the backplane clock (only) */ | ||
3267 | brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); | ||
3268 | |||
3269 | /* Clear the data packet queues */ | ||
3270 | brcmu_pktq_flush(&bus->txq, true, NULL, NULL); | ||
3271 | |||
3272 | /* Clear any held glomming stuff */ | ||
3273 | if (bus->glomd) | ||
3274 | brcmu_pkt_buf_free_skb(bus->glomd); | ||
3275 | |||
3276 | if (bus->glom) | ||
3277 | brcmu_pkt_buf_free_skb(bus->glom); | ||
3278 | |||
3279 | bus->glom = bus->glomd = NULL; | ||
3280 | |||
3281 | /* Clear rx control and wake any waiters */ | ||
3282 | bus->rxlen = 0; | ||
3283 | brcmf_os_ioctl_resp_wake(bus->drvr); | ||
3284 | |||
3285 | /* Reset some F2 state stuff */ | ||
3286 | bus->rxskip = false; | ||
3287 | bus->tx_seq = bus->rx_seq = 0; | ||
3288 | |||
3289 | if (enforce_mutex) | ||
3290 | brcmf_sdbrcm_sdunlock(bus); | ||
3291 | } | ||
3292 | |||
3293 | int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr, bool enforce_mutex) | ||
3294 | { | ||
3295 | struct brcmf_bus *bus = drvr->bus; | ||
3296 | struct brcmf_timeout tmo; | ||
3297 | uint retries = 0; | ||
3298 | u8 ready, enable; | ||
3299 | int err, ret = 0; | ||
3300 | u8 saveclk; | ||
3301 | |||
3302 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
3303 | |||
3304 | /* try to download image and nvram to the dongle */ | ||
3305 | if (drvr->busstate == BRCMF_BUS_DOWN) { | ||
3306 | if (!(brcmf_sdbrcm_download_firmware(bus, bus->card))) | ||
3307 | return -1; | ||
3308 | } | ||
3309 | |||
3310 | if (!bus->drvr) | ||
3311 | return 0; | ||
3312 | |||
3313 | /* Start the watchdog timer */ | ||
3314 | bus->drvr->tickcnt = 0; | ||
3315 | brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms); | ||
3316 | |||
3317 | if (enforce_mutex) | ||
3318 | brcmf_sdbrcm_sdlock(bus); | ||
3319 | |||
3320 | /* Make sure backplane clock is on, needed to generate F2 interrupt */ | ||
3321 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | ||
3322 | if (bus->clkstate != CLK_AVAIL) | ||
3323 | goto exit; | ||
3324 | |||
3325 | /* Force clocks on backplane to be sure F2 interrupt propagates */ | ||
3326 | saveclk = | ||
3327 | brcmf_sdcard_cfg_read(bus->card, SDIO_FUNC_1, | ||
3328 | SBSDIO_FUNC1_CHIPCLKCSR, &err); | ||
3329 | if (!err) { | ||
3330 | brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, | ||
3331 | SBSDIO_FUNC1_CHIPCLKCSR, | ||
3332 | (saveclk | SBSDIO_FORCE_HT), &err); | ||
3333 | } | ||
3334 | if (err) { | ||
3335 | BRCMF_ERROR(("%s: Failed to force clock for F2: err %d\n", | ||
3336 | __func__, err)); | ||
3337 | goto exit; | ||
3338 | } | ||
3339 | |||
3340 | /* Enable function 2 (frame transfers) */ | ||
3341 | w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT, | ||
3342 | offsetof(struct sdpcmd_regs, tosbmailboxdata), &retries); | ||
3343 | enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); | ||
3344 | |||
3345 | brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_0, SDIO_CCCR_IOEx, enable, | ||
3346 | NULL); | ||
3347 | |||
3348 | /* Give the dongle some time to do its thing and set IOR2 */ | ||
3349 | brcmf_timeout_start(&tmo, BRCMF_WAIT_F2RDY * 1000); | ||
3350 | |||
3351 | ready = 0; | ||
3352 | while (ready != enable && !brcmf_timeout_expired(&tmo)) | ||
3353 | ready = brcmf_sdcard_cfg_read(bus->card, SDIO_FUNC_0, | ||
3354 | SDIO_CCCR_IORx, NULL); | ||
3355 | |||
3356 | BRCMF_INFO(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n", | ||
3357 | __func__, enable, ready, tmo.elapsed)); | ||
3358 | |||
3359 | /* If F2 successfully enabled, set core and enable interrupts */ | ||
3360 | if (ready == enable) { | ||
3361 | /* Set up the interrupt mask and enable interrupts */ | ||
3362 | bus->hostintmask = HOSTINTMASK; | ||
3363 | w_sdreg32(bus, bus->hostintmask, | ||
3364 | offsetof(struct sdpcmd_regs, hostintmask), &retries); | ||
3365 | |||
3366 | brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, SBSDIO_WATERMARK, | ||
3367 | (u8) watermark, &err); | ||
3368 | |||
3369 | /* Set bus state according to enable result */ | ||
3370 | drvr->busstate = BRCMF_BUS_DATA; | ||
3371 | |||
3372 | bus->intdis = false; | ||
3373 | if (bus->intr) { | ||
3374 | BRCMF_INTR(("%s: enable SDIO device interrupts\n", | ||
3375 | __func__)); | ||
3376 | brcmf_sdcard_intr_enable(bus->card); | ||
3377 | } else { | ||
3378 | BRCMF_INTR(("%s: disable SDIO interrupts\n", __func__)); | ||
3379 | brcmf_sdcard_intr_disable(bus->card); | ||
3380 | } | ||
3381 | |||
3382 | } | ||
3383 | |||
3384 | else { | ||
3385 | /* Disable F2 again */ | ||
3386 | enable = SDIO_FUNC_ENABLE_1; | ||
3387 | brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_0, SDIO_CCCR_IOEx, | ||
3388 | enable, NULL); | ||
3389 | } | ||
3390 | |||
3391 | /* Restore previous clock setting */ | ||
3392 | brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, | ||
3393 | saveclk, &err); | ||
3394 | |||
3395 | #if defined(OOB_INTR_ONLY) | ||
3396 | /* Host registration for OOB interrupt */ | ||
3397 | if (brcmf_sdio_register_oob_intr(bus->dhd)) { | ||
3398 | brcmf_sdbrcm_wd_timer(bus, 0); | ||
3399 | BRCMF_ERROR(("%s Host failed to resgister for OOB\n", | ||
3400 | __func__)); | ||
3401 | ret = -ENODEV; | ||
3402 | goto exit; | ||
3403 | } | ||
3404 | |||
3405 | /* Enable oob at firmware */ | ||
3406 | brcmf_sdbrcm_enable_oob_intr(bus, true); | ||
3407 | #endif /* defined(OOB_INTR_ONLY) */ | ||
3408 | |||
3409 | /* If we didn't come up, turn off backplane clock */ | ||
3410 | if (drvr->busstate != BRCMF_BUS_DATA) | ||
3411 | brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); | ||
3412 | |||
3413 | exit: | ||
3414 | if (enforce_mutex) | ||
3415 | brcmf_sdbrcm_sdunlock(bus); | ||
3416 | |||
3417 | return ret; | ||
3418 | } | ||
3419 | |||
3420 | static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx) | ||
3421 | { | ||
3422 | struct brcmf_sdio_card *card = bus->card; | ||
3423 | uint retries = 0; | ||
3424 | u16 lastrbc; | ||
3425 | u8 hi, lo; | ||
3426 | int err; | ||
3427 | |||
3428 | BRCMF_ERROR(("%s: %sterminate frame%s\n", __func__, | ||
3429 | (abort ? "abort command, " : ""), | ||
3430 | (rtx ? ", send NAK" : ""))); | ||
3431 | |||
3432 | if (abort) | ||
3433 | brcmf_sdcard_abort(card, SDIO_FUNC_2); | ||
3434 | |||
3435 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, | ||
3436 | SFC_RF_TERM, &err); | ||
3437 | bus->f1regdata++; | ||
3438 | |||
3439 | /* Wait until the packet has been flushed (device/FIFO stable) */ | ||
3440 | for (lastrbc = retries = 0xffff; retries > 0; retries--) { | ||
3441 | hi = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1, | ||
3442 | SBSDIO_FUNC1_RFRAMEBCHI, NULL); | ||
3443 | lo = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1, | ||
3444 | SBSDIO_FUNC1_RFRAMEBCLO, NULL); | ||
3445 | bus->f1regdata += 2; | ||
3446 | |||
3447 | if ((hi == 0) && (lo == 0)) | ||
3448 | break; | ||
3449 | |||
3450 | if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) { | ||
3451 | BRCMF_ERROR(("%s: count growing: last 0x%04x now " | ||
3452 | "0x%04x\n", | ||
3453 | __func__, lastrbc, ((hi << 8) + lo))); | ||
3454 | } | ||
3455 | lastrbc = (hi << 8) + lo; | ||
3456 | } | ||
3457 | |||
3458 | if (!retries) { | ||
3459 | BRCMF_ERROR(("%s: count never zeroed: last 0x%04x\n", | ||
3460 | __func__, lastrbc)); | ||
3461 | } else { | ||
3462 | BRCMF_INFO(("%s: flush took %d iterations\n", __func__, | ||
3463 | (0xffff - retries))); | ||
3464 | } | ||
3465 | |||
3466 | if (rtx) { | ||
3467 | bus->rxrtx++; | ||
3468 | w_sdreg32(bus, SMB_NAK, | ||
3469 | offsetof(struct sdpcmd_regs, tosbmailbox), &retries); | ||
3470 | |||
3471 | bus->f1regdata++; | ||
3472 | if (retries <= retry_limit) | ||
3473 | bus->rxskip = true; | ||
3474 | } | ||
3475 | |||
3476 | /* Clear partial in any case */ | ||
3477 | bus->nextlen = 0; | ||
3478 | |||
3479 | /* If we can't reach the device, signal failure */ | ||
3480 | if (err || brcmf_sdcard_regfail(card)) | ||
3481 | bus->drvr->busstate = BRCMF_BUS_DOWN; | ||
3482 | } | ||
3483 | |||
3484 | static void | ||
3485 | brcmf_sdbrcm_read_control(struct brcmf_bus *bus, u8 *hdr, uint len, uint doff) | ||
3486 | { | ||
3487 | struct brcmf_sdio_card *card = bus->card; | ||
3488 | uint rdlen, pad; | ||
3489 | |||
3490 | int sdret; | ||
3491 | |||
3492 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
3493 | |||
3494 | /* Control data already received in aligned rxctl */ | ||
3495 | if ((bus->bus == SPI_BUS) && (!bus->usebufpool)) | ||
3496 | goto gotpkt; | ||
3497 | |||
3498 | /* Set rxctl for frame (w/optional alignment) */ | ||
3499 | bus->rxctl = bus->rxbuf; | ||
3500 | if (brcmf_alignctl) { | ||
3501 | bus->rxctl += firstread; | ||
3502 | pad = ((unsigned long)bus->rxctl % BRCMF_SDALIGN); | ||
3503 | if (pad) | ||
3504 | bus->rxctl += (BRCMF_SDALIGN - pad); | ||
3505 | bus->rxctl -= firstread; | ||
3506 | } | ||
3507 | |||
3508 | /* Copy the already-read portion over */ | ||
3509 | memcpy(bus->rxctl, hdr, firstread); | ||
3510 | if (len <= firstread) | ||
3511 | goto gotpkt; | ||
3512 | |||
3513 | /* Copy the full data pkt in gSPI case and process ioctl. */ | ||
3514 | if (bus->bus == SPI_BUS) { | ||
3515 | memcpy(bus->rxctl, hdr, len); | ||
3516 | goto gotpkt; | ||
3517 | } | ||
3518 | |||
3519 | /* Raise rdlen to next SDIO block to avoid tail command */ | ||
3520 | rdlen = len - firstread; | ||
3521 | if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { | ||
3522 | pad = bus->blocksize - (rdlen % bus->blocksize); | ||
3523 | if ((pad <= bus->roundup) && (pad < bus->blocksize) && | ||
3524 | ((len + pad) < bus->drvr->maxctl)) | ||
3525 | rdlen += pad; | ||
3526 | } else if (rdlen % BRCMF_SDALIGN) { | ||
3527 | rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN); | ||
3528 | } | ||
3529 | |||
3530 | /* Satisfy length-alignment requirements */ | ||
3531 | if (forcealign && (rdlen & (ALIGNMENT - 1))) | ||
3532 | rdlen = roundup(rdlen, ALIGNMENT); | ||
3533 | |||
3534 | /* Drop if the read is too big or it exceeds our maximum */ | ||
3535 | if ((rdlen + firstread) > bus->drvr->maxctl) { | ||
3536 | BRCMF_ERROR(("%s: %d-byte control read exceeds %d-byte" | ||
3537 | " buffer\n", __func__, rdlen, bus->drvr->maxctl)); | ||
3538 | bus->drvr->rx_errors++; | ||
3539 | brcmf_sdbrcm_rxfail(bus, false, false); | ||
3540 | goto done; | ||
3541 | } | ||
3542 | |||
3543 | if ((len - doff) > bus->drvr->maxctl) { | ||
3544 | BRCMF_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds " | ||
3545 | "%d-byte limit\n", | ||
3546 | __func__, len, (len - doff), bus->drvr->maxctl)); | ||
3547 | bus->drvr->rx_errors++; | ||
3548 | bus->rx_toolong++; | ||
3549 | brcmf_sdbrcm_rxfail(bus, false, false); | ||
3550 | goto done; | ||
3551 | } | ||
3552 | |||
3553 | /* Read remainder of frame body into the rxctl buffer */ | ||
3554 | sdret = brcmf_sdcard_recv_buf(card, brcmf_sdcard_cur_sbwad(card), | ||
3555 | SDIO_FUNC_2, | ||
3556 | F2SYNC, (bus->rxctl + firstread), rdlen, | ||
3557 | NULL, NULL, NULL); | ||
3558 | bus->f2rxdata++; | ||
3559 | |||
3560 | /* Control frame failures need retransmission */ | ||
3561 | if (sdret < 0) { | ||
3562 | BRCMF_ERROR(("%s: read %d control bytes failed: %d\n", | ||
3563 | __func__, rdlen, sdret)); | ||
3564 | bus->rxc_errors++; | ||
3565 | brcmf_sdbrcm_rxfail(bus, true, true); | ||
3566 | goto done; | ||
3567 | } | ||
3568 | |||
3569 | gotpkt: | ||
3570 | |||
3571 | #ifdef BCMDBG | ||
3572 | if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) { | ||
3573 | printk(KERN_DEBUG "RxCtrl:\n"); | ||
3574 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, bus->rxctl, len); | ||
3575 | } | ||
3576 | #endif | ||
3577 | |||
3578 | /* Point to valid data and indicate its length */ | ||
3579 | bus->rxctl += doff; | ||
3580 | bus->rxlen = len - doff; | ||
3581 | |||
3582 | done: | ||
3583 | /* Awake any waiters */ | ||
3584 | brcmf_os_ioctl_resp_wake(bus->drvr); | ||
3585 | } | ||
3586 | |||
3587 | static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) | ||
3588 | { | ||
3589 | u16 dlen, totlen; | ||
3590 | u8 *dptr, num = 0; | ||
3591 | |||
3592 | u16 sublen, check; | ||
3593 | struct sk_buff *pfirst, *plast, *pnext, *save_pfirst; | ||
3594 | |||
3595 | int errcode; | ||
3596 | u8 chan, seq, doff, sfdoff; | ||
3597 | u8 txmax; | ||
3598 | |||
3599 | int ifidx = 0; | ||
3600 | bool usechain = bus->use_rxchain; | ||
3601 | |||
3602 | /* If packets, issue read(s) and send up packet chain */ | ||
3603 | /* Return sequence numbers consumed? */ | ||
3604 | |||
3605 | BRCMF_TRACE(("brcmf_sdbrcm_rxglom: start: glomd %p glom %p\n", | ||
3606 | bus->glomd, bus->glom)); | ||
3607 | |||
3608 | /* If there's a descriptor, generate the packet chain */ | ||
3609 | if (bus->glomd) { | ||
3610 | pfirst = plast = pnext = NULL; | ||
3611 | dlen = (u16) (bus->glomd->len); | ||
3612 | dptr = bus->glomd->data; | ||
3613 | if (!dlen || (dlen & 1)) { | ||
3614 | BRCMF_ERROR(("%s: bad glomd len(%d)," | ||
3615 | " ignore descriptor\n", | ||
3616 | __func__, dlen)); | ||
3617 | dlen = 0; | ||
3618 | } | ||
3619 | |||
3620 | for (totlen = num = 0; dlen; num++) { | ||
3621 | /* Get (and move past) next length */ | ||
3622 | sublen = get_unaligned_le16(dptr); | ||
3623 | dlen -= sizeof(u16); | ||
3624 | dptr += sizeof(u16); | ||
3625 | if ((sublen < SDPCM_HDRLEN) || | ||
3626 | ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) { | ||
3627 | BRCMF_ERROR(("%s: descriptor len %d bad: %d\n", | ||
3628 | __func__, num, sublen)); | ||
3629 | pnext = NULL; | ||
3630 | break; | ||
3631 | } | ||
3632 | if (sublen % BRCMF_SDALIGN) { | ||
3633 | BRCMF_ERROR(("%s: sublen %d not multiple of" | ||
3634 | " %d\n", __func__, sublen, | ||
3635 | BRCMF_SDALIGN)); | ||
3636 | usechain = false; | ||
3637 | } | ||
3638 | totlen += sublen; | ||
3639 | |||
3640 | /* For last frame, adjust read len so total | ||
3641 | is a block multiple */ | ||
3642 | if (!dlen) { | ||
3643 | sublen += | ||
3644 | (roundup(totlen, bus->blocksize) - totlen); | ||
3645 | totlen = roundup(totlen, bus->blocksize); | ||
3646 | } | ||
3647 | |||
3648 | /* Allocate/chain packet for next subframe */ | ||
3649 | pnext = brcmu_pkt_buf_get_skb(sublen + BRCMF_SDALIGN); | ||
3650 | if (pnext == NULL) { | ||
3651 | BRCMF_ERROR(("%s: bcm_pkt_buf_get_skb failed, " | ||
3652 | "num %d len %d\n", __func__, | ||
3653 | num, sublen)); | ||
3654 | break; | ||
3655 | } | ||
3656 | if (!pfirst) { | ||
3657 | pfirst = plast = pnext; | ||
3658 | } else { | ||
3659 | plast->next = pnext; | ||
3660 | plast = pnext; | ||
3661 | } | ||
3662 | |||
3663 | /* Adhere to start alignment requirements */ | ||
3664 | PKTALIGN(pnext, sublen, BRCMF_SDALIGN); | ||
3665 | } | ||
3666 | |||
3667 | /* If all allocations succeeded, save packet chain | ||
3668 | in bus structure */ | ||
3669 | if (pnext) { | ||
3670 | BRCMF_GLOM(("%s: allocated %d-byte packet chain for %d " | ||
3671 | "subframes\n", __func__, totlen, num)); | ||
3672 | if (BRCMF_GLOM_ON() && bus->nextlen) { | ||
3673 | if (totlen != bus->nextlen) { | ||
3674 | BRCMF_GLOM(("%s: glomdesc mismatch: " | ||
3675 | "nextlen %d glomdesc %d " | ||
3676 | "rxseq %d\n", __func__, | ||
3677 | bus->nextlen, | ||
3678 | totlen, rxseq)); | ||
3679 | } | ||
3680 | } | ||
3681 | bus->glom = pfirst; | ||
3682 | pfirst = pnext = NULL; | ||
3683 | } else { | ||
3684 | if (pfirst) | ||
3685 | brcmu_pkt_buf_free_skb(pfirst); | ||
3686 | bus->glom = NULL; | ||
3687 | num = 0; | ||
3688 | } | ||
3689 | |||
3690 | /* Done with descriptor packet */ | ||
3691 | brcmu_pkt_buf_free_skb(bus->glomd); | ||
3692 | bus->glomd = NULL; | ||
3693 | bus->nextlen = 0; | ||
3694 | } | ||
3695 | |||
3696 | /* Ok -- either we just generated a packet chain, | ||
3697 | or had one from before */ | ||
3698 | if (bus->glom) { | ||
3699 | if (BRCMF_GLOM_ON()) { | ||
3700 | BRCMF_GLOM(("%s: try superframe read, packet chain:\n", | ||
3701 | __func__)); | ||
3702 | for (pnext = bus->glom; pnext; pnext = pnext->next) { | ||
3703 | BRCMF_GLOM((" %p: %p len 0x%04x (%d)\n", | ||
3704 | pnext, (u8 *) (pnext->data), | ||
3705 | pnext->len, pnext->len)); | ||
3706 | } | ||
3707 | } | ||
3708 | |||
3709 | pfirst = bus->glom; | ||
3710 | dlen = (u16) brcmu_pkttotlen(pfirst); | ||
3711 | |||
3712 | /* Do an SDIO read for the superframe. Configurable iovar to | ||
3713 | * read directly into the chained packet, or allocate a large | ||
3714 | * packet and and copy into the chain. | ||
3715 | */ | ||
3716 | if (usechain) { | ||
3717 | errcode = brcmf_sdcard_recv_buf(bus->card, | ||
3718 | brcmf_sdcard_cur_sbwad(bus->card), | ||
3719 | SDIO_FUNC_2, | ||
3720 | F2SYNC, (u8 *) pfirst->data, dlen, | ||
3721 | pfirst, NULL, NULL); | ||
3722 | } else if (bus->dataptr) { | ||
3723 | errcode = brcmf_sdcard_recv_buf(bus->card, | ||
3724 | brcmf_sdcard_cur_sbwad(bus->card), | ||
3725 | SDIO_FUNC_2, | ||
3726 | F2SYNC, bus->dataptr, dlen, | ||
3727 | NULL, NULL, NULL); | ||
3728 | sublen = (u16) brcmu_pktfrombuf(pfirst, 0, dlen, | ||
3729 | bus->dataptr); | ||
3730 | if (sublen != dlen) { | ||
3731 | BRCMF_ERROR(("%s: FAILED TO COPY, dlen %d " | ||
3732 | "sublen %d\n", | ||
3733 | __func__, dlen, sublen)); | ||
3734 | errcode = -1; | ||
3735 | } | ||
3736 | pnext = NULL; | ||
3737 | } else { | ||
3738 | BRCMF_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, " | ||
3739 | "FORCE FAILURE\n", dlen)); | ||
3740 | errcode = -1; | ||
3741 | } | ||
3742 | bus->f2rxdata++; | ||
3743 | |||
3744 | /* On failure, kill the superframe, allow a couple retries */ | ||
3745 | if (errcode < 0) { | ||
3746 | BRCMF_ERROR(("%s: glom read of %d bytes failed: %d\n", | ||
3747 | __func__, dlen, errcode)); | ||
3748 | bus->drvr->rx_errors++; | ||
3749 | |||
3750 | if (bus->glomerr++ < 3) { | ||
3751 | brcmf_sdbrcm_rxfail(bus, true, true); | ||
3752 | } else { | ||
3753 | bus->glomerr = 0; | ||
3754 | brcmf_sdbrcm_rxfail(bus, true, false); | ||
3755 | brcmu_pkt_buf_free_skb(bus->glom); | ||
3756 | bus->rxglomfail++; | ||
3757 | bus->glom = NULL; | ||
3758 | } | ||
3759 | return 0; | ||
3760 | } | ||
3761 | #ifdef BCMDBG | ||
3762 | if (BRCMF_GLOM_ON()) { | ||
3763 | printk(KERN_DEBUG "SUPERFRAME:\n"); | ||
3764 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, | ||
3765 | pfirst->data, min_t(int, pfirst->len, 48)); | ||
3766 | } | ||
3767 | #endif | ||
3768 | |||
3769 | /* Validate the superframe header */ | ||
3770 | dptr = (u8 *) (pfirst->data); | ||
3771 | sublen = get_unaligned_le16(dptr); | ||
3772 | check = get_unaligned_le16(dptr + sizeof(u16)); | ||
3773 | |||
3774 | chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); | ||
3775 | seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); | ||
3776 | bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; | ||
3777 | if ((bus->nextlen << 4) > MAX_RX_DATASZ) { | ||
3778 | BRCMF_INFO(("%s: nextlen too large (%d) seq %d\n", | ||
3779 | __func__, bus->nextlen, seq)); | ||
3780 | bus->nextlen = 0; | ||
3781 | } | ||
3782 | doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); | ||
3783 | txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); | ||
3784 | |||
3785 | errcode = 0; | ||
3786 | if ((u16)~(sublen ^ check)) { | ||
3787 | BRCMF_ERROR(("%s (superframe): HW hdr error: len/check " | ||
3788 | "0x%04x/0x%04x\n", __func__, sublen, | ||
3789 | check)); | ||
3790 | errcode = -1; | ||
3791 | } else if (roundup(sublen, bus->blocksize) != dlen) { | ||
3792 | BRCMF_ERROR(("%s (superframe): len 0x%04x, rounded " | ||
3793 | "0x%04x, expect 0x%04x\n", | ||
3794 | __func__, sublen, | ||
3795 | roundup(sublen, bus->blocksize), dlen)); | ||
3796 | errcode = -1; | ||
3797 | } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != | ||
3798 | SDPCM_GLOM_CHANNEL) { | ||
3799 | BRCMF_ERROR(("%s (superframe): bad channel %d\n", | ||
3800 | __func__, | ||
3801 | SDPCM_PACKET_CHANNEL(&dptr | ||
3802 | [SDPCM_FRAMETAG_LEN]))); | ||
3803 | errcode = -1; | ||
3804 | } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) { | ||
3805 | BRCMF_ERROR(("%s (superframe): got 2nd descriptor?\n", | ||
3806 | __func__)); | ||
3807 | errcode = -1; | ||
3808 | } else if ((doff < SDPCM_HDRLEN) || | ||
3809 | (doff > (pfirst->len - SDPCM_HDRLEN))) { | ||
3810 | BRCMF_ERROR(("%s (superframe): Bad data offset %d: " | ||
3811 | "HW %d pkt %d min %d\n", | ||
3812 | __func__, doff, sublen, | ||
3813 | pfirst->len, SDPCM_HDRLEN)); | ||
3814 | errcode = -1; | ||
3815 | } | ||
3816 | |||
3817 | /* Check sequence number of superframe SW header */ | ||
3818 | if (rxseq != seq) { | ||
3819 | BRCMF_INFO(("%s: (superframe) rx_seq %d, expected %d\n", | ||
3820 | __func__, seq, rxseq)); | ||
3821 | bus->rx_badseq++; | ||
3822 | rxseq = seq; | ||
3823 | } | ||
3824 | |||
3825 | /* Check window for sanity */ | ||
3826 | if ((u8) (txmax - bus->tx_seq) > 0x40) { | ||
3827 | BRCMF_ERROR(("%s: unlikely tx max %d with tx_seq %d\n", | ||
3828 | __func__, txmax, bus->tx_seq)); | ||
3829 | txmax = bus->tx_seq + 2; | ||
3830 | } | ||
3831 | bus->tx_max = txmax; | ||
3832 | |||
3833 | /* Remove superframe header, remember offset */ | ||
3834 | skb_pull(pfirst, doff); | ||
3835 | sfdoff = doff; | ||
3836 | |||
3837 | /* Validate all the subframe headers */ | ||
3838 | for (num = 0, pnext = pfirst; pnext && !errcode; | ||
3839 | num++, pnext = pnext->next) { | ||
3840 | dptr = (u8 *) (pnext->data); | ||
3841 | dlen = (u16) (pnext->len); | ||
3842 | sublen = get_unaligned_le16(dptr); | ||
3843 | check = get_unaligned_le16(dptr + sizeof(u16)); | ||
3844 | chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); | ||
3845 | doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); | ||
3846 | #ifdef BCMDBG | ||
3847 | if (BRCMF_GLOM_ON()) { | ||
3848 | printk(KERN_DEBUG "subframe:\n"); | ||
3849 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, | ||
3850 | dptr, 32); | ||
3851 | } | ||
3852 | #endif | ||
3853 | |||
3854 | if ((u16)~(sublen ^ check)) { | ||
3855 | BRCMF_ERROR(("%s (subframe %d): HW hdr error: " | ||
3856 | "len/check 0x%04x/0x%04x\n", | ||
3857 | __func__, num, sublen, check)); | ||
3858 | errcode = -1; | ||
3859 | } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) { | ||
3860 | BRCMF_ERROR(("%s (subframe %d): length mismatch" | ||
3861 | ": len 0x%04x, expect 0x%04x\n", | ||
3862 | __func__, num, sublen, dlen)); | ||
3863 | errcode = -1; | ||
3864 | } else if ((chan != SDPCM_DATA_CHANNEL) && | ||
3865 | (chan != SDPCM_EVENT_CHANNEL)) { | ||
3866 | BRCMF_ERROR(("%s (subframe %d): bad channel" | ||
3867 | " %d\n", __func__, num, chan)); | ||
3868 | errcode = -1; | ||
3869 | } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) { | ||
3870 | BRCMF_ERROR(("%s (subframe %d): Bad data offset" | ||
3871 | " %d: HW %d min %d\n", | ||
3872 | __func__, num, doff, sublen, | ||
3873 | SDPCM_HDRLEN)); | ||
3874 | errcode = -1; | ||
3875 | } | ||
3876 | } | ||
3877 | |||
3878 | if (errcode) { | ||
3879 | /* Terminate frame on error, request | ||
3880 | a couple retries */ | ||
3881 | if (bus->glomerr++ < 3) { | ||
3882 | /* Restore superframe header space */ | ||
3883 | skb_push(pfirst, sfdoff); | ||
3884 | brcmf_sdbrcm_rxfail(bus, true, true); | ||
3885 | } else { | ||
3886 | bus->glomerr = 0; | ||
3887 | brcmf_sdbrcm_rxfail(bus, true, false); | ||
3888 | brcmu_pkt_buf_free_skb(bus->glom); | ||
3889 | bus->rxglomfail++; | ||
3890 | bus->glom = NULL; | ||
3891 | } | ||
3892 | bus->nextlen = 0; | ||
3893 | return 0; | ||
3894 | } | ||
3895 | |||
3896 | /* Basic SD framing looks ok - process each packet (header) */ | ||
3897 | save_pfirst = pfirst; | ||
3898 | bus->glom = NULL; | ||
3899 | plast = NULL; | ||
3900 | |||
3901 | for (num = 0; pfirst; rxseq++, pfirst = pnext) { | ||
3902 | pnext = pfirst->next; | ||
3903 | pfirst->next = NULL; | ||
3904 | |||
3905 | dptr = (u8 *) (pfirst->data); | ||
3906 | sublen = get_unaligned_le16(dptr); | ||
3907 | chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); | ||
3908 | seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); | ||
3909 | doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); | ||
3910 | |||
3911 | BRCMF_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d " | ||
3912 | "chan %d seq %d\n", | ||
3913 | __func__, num, pfirst, pfirst->data, | ||
3914 | pfirst->len, sublen, chan, seq)); | ||
3915 | |||
3916 | /* precondition: chan == SDPCM_DATA_CHANNEL || | ||
3917 | chan == SDPCM_EVENT_CHANNEL */ | ||
3918 | |||
3919 | if (rxseq != seq) { | ||
3920 | BRCMF_GLOM(("%s: rx_seq %d, expected %d\n", | ||
3921 | __func__, seq, rxseq)); | ||
3922 | bus->rx_badseq++; | ||
3923 | rxseq = seq; | ||
3924 | } | ||
3925 | #ifdef BCMDBG | ||
3926 | if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { | ||
3927 | printk(KERN_DEBUG "Rx Subframe Data:\n"); | ||
3928 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, | ||
3929 | dptr, dlen); | ||
3930 | } | ||
3931 | #endif | ||
3932 | |||
3933 | __skb_trim(pfirst, sublen); | ||
3934 | skb_pull(pfirst, doff); | ||
3935 | |||
3936 | if (pfirst->len == 0) { | ||
3937 | brcmu_pkt_buf_free_skb(pfirst); | ||
3938 | if (plast) { | ||
3939 | plast->next = pnext; | ||
3940 | } else { | ||
3941 | save_pfirst = pnext; | ||
3942 | } | ||
3943 | continue; | ||
3944 | } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx, pfirst) | ||
3945 | != 0) { | ||
3946 | BRCMF_ERROR(("%s: rx protocol error\n", | ||
3947 | __func__)); | ||
3948 | bus->drvr->rx_errors++; | ||
3949 | brcmu_pkt_buf_free_skb(pfirst); | ||
3950 | if (plast) { | ||
3951 | plast->next = pnext; | ||
3952 | } else { | ||
3953 | save_pfirst = pnext; | ||
3954 | } | ||
3955 | continue; | ||
3956 | } | ||
3957 | |||
3958 | /* this packet will go up, link back into | ||
3959 | chain and count it */ | ||
3960 | pfirst->next = pnext; | ||
3961 | plast = pfirst; | ||
3962 | num++; | ||
3963 | |||
3964 | #ifdef BCMDBG | ||
3965 | if (BRCMF_GLOM_ON()) { | ||
3966 | BRCMF_GLOM(("%s subframe %d to stack, %p" | ||
3967 | "(%p/%d) nxt/lnk %p/%p\n", | ||
3968 | __func__, num, pfirst, pfirst->data, | ||
3969 | pfirst->len, pfirst->next, | ||
3970 | pfirst->prev)); | ||
3971 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, | ||
3972 | pfirst->data, | ||
3973 | min_t(int, pfirst->len, 32)); | ||
3974 | } | ||
3975 | #endif /* BCMDBG */ | ||
3976 | } | ||
3977 | if (num) { | ||
3978 | brcmf_sdbrcm_sdunlock(bus); | ||
3979 | brcmf_rx_frame(bus->drvr, ifidx, save_pfirst, num); | ||
3980 | brcmf_sdbrcm_sdlock(bus); | ||
3981 | } | ||
3982 | |||
3983 | bus->rxglomframes++; | ||
3984 | bus->rxglompkts += num; | ||
3985 | } | ||
3986 | return num; | ||
3987 | } | ||
3988 | |||
3989 | /* Return true if there may be more frames to read */ | ||
3990 | static uint | ||
3991 | brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished) | ||
3992 | { | ||
3993 | struct brcmf_sdio_card *card = bus->card; | ||
3994 | |||
3995 | u16 len, check; /* Extracted hardware header fields */ | ||
3996 | u8 chan, seq, doff; /* Extracted software header fields */ | ||
3997 | u8 fcbits; /* Extracted fcbits from software header */ | ||
3998 | |||
3999 | struct sk_buff *pkt; /* Packet for event or data frames */ | ||
4000 | u16 pad; /* Number of pad bytes to read */ | ||
4001 | u16 rdlen; /* Total number of bytes to read */ | ||
4002 | u8 rxseq; /* Next sequence number to expect */ | ||
4003 | uint rxleft = 0; /* Remaining number of frames allowed */ | ||
4004 | int sdret; /* Return code from calls */ | ||
4005 | u8 txmax; /* Maximum tx sequence offered */ | ||
4006 | bool len_consistent; /* Result of comparing readahead len and | ||
4007 | len from hw-hdr */ | ||
4008 | u8 *rxbuf; | ||
4009 | int ifidx = 0; | ||
4010 | uint rxcount = 0; /* Total frames read */ | ||
4011 | |||
4012 | #if defined(BCMDBG) || defined(SDTEST) | ||
4013 | bool sdtest = false; /* To limit message spew from test mode */ | ||
4014 | #endif | ||
4015 | |||
4016 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
4017 | |||
4018 | #ifdef SDTEST | ||
4019 | /* Allow pktgen to override maxframes */ | ||
4020 | if (bus->pktgen_count && (bus->pktgen_mode == BRCMF_PKTGEN_RECV)) { | ||
4021 | maxframes = bus->pktgen_count; | ||
4022 | sdtest = true; | ||
4023 | } | ||
4024 | #endif | ||
4025 | |||
4026 | /* Not finished unless we encounter no more frames indication */ | ||
4027 | *finished = false; | ||
4028 | |||
4029 | for (rxseq = bus->rx_seq, rxleft = maxframes; | ||
4030 | !bus->rxskip && rxleft && bus->drvr->busstate != BRCMF_BUS_DOWN; | ||
4031 | rxseq++, rxleft--) { | ||
4032 | |||
4033 | /* Handle glomming separately */ | ||
4034 | if (bus->glom || bus->glomd) { | ||
4035 | u8 cnt; | ||
4036 | BRCMF_GLOM(("%s: calling rxglom: glomd %p, glom %p\n", | ||
4037 | __func__, bus->glomd, bus->glom)); | ||
4038 | cnt = brcmf_sdbrcm_rxglom(bus, rxseq); | ||
4039 | BRCMF_GLOM(("%s: rxglom returned %d\n", __func__, cnt)); | ||
4040 | rxseq += cnt - 1; | ||
4041 | rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; | ||
4042 | continue; | ||
4043 | } | ||
4044 | |||
4045 | /* Try doing single read if we can */ | ||
4046 | if (brcmf_readahead && bus->nextlen) { | ||
4047 | u16 nextlen = bus->nextlen; | ||
4048 | bus->nextlen = 0; | ||
4049 | |||
4050 | if (bus->bus == SPI_BUS) { | ||
4051 | rdlen = len = nextlen; | ||
4052 | } else { | ||
4053 | rdlen = len = nextlen << 4; | ||
4054 | |||
4055 | /* Pad read to blocksize for efficiency */ | ||
4056 | if (bus->roundup && bus->blocksize | ||
4057 | && (rdlen > bus->blocksize)) { | ||
4058 | pad = | ||
4059 | bus->blocksize - | ||
4060 | (rdlen % bus->blocksize); | ||
4061 | if ((pad <= bus->roundup) | ||
4062 | && (pad < bus->blocksize) | ||
4063 | && ((rdlen + pad + firstread) < | ||
4064 | MAX_RX_DATASZ)) | ||
4065 | rdlen += pad; | ||
4066 | } else if (rdlen % BRCMF_SDALIGN) { | ||
4067 | rdlen += | ||
4068 | BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN); | ||
4069 | } | ||
4070 | } | ||
4071 | |||
4072 | /* We use bus->rxctl buffer in WinXP for initial | ||
4073 | * control pkt receives. | ||
4074 | * Later we use buffer-poll for data as well | ||
4075 | * as control packets. | ||
4076 | * This is required because dhd receives full | ||
4077 | * frame in gSPI unlike SDIO. | ||
4078 | * After the frame is received we have to | ||
4079 | * distinguish whether it is data | ||
4080 | * or non-data frame. | ||
4081 | */ | ||
4082 | /* Allocate a packet buffer */ | ||
4083 | pkt = brcmu_pkt_buf_get_skb(rdlen + BRCMF_SDALIGN); | ||
4084 | if (!pkt) { | ||
4085 | if (bus->bus == SPI_BUS) { | ||
4086 | bus->usebufpool = false; | ||
4087 | bus->rxctl = bus->rxbuf; | ||
4088 | if (brcmf_alignctl) { | ||
4089 | bus->rxctl += firstread; | ||
4090 | pad = ((unsigned long)bus->rxctl % | ||
4091 | BRCMF_SDALIGN); | ||
4092 | if (pad) | ||
4093 | bus->rxctl += | ||
4094 | (BRCMF_SDALIGN - pad); | ||
4095 | bus->rxctl -= firstread; | ||
4096 | } | ||
4097 | rxbuf = bus->rxctl; | ||
4098 | /* Read the entire frame */ | ||
4099 | sdret = brcmf_sdcard_recv_buf(card, | ||
4100 | brcmf_sdcard_cur_sbwad(card), | ||
4101 | SDIO_FUNC_2, F2SYNC, | ||
4102 | rxbuf, rdlen, | ||
4103 | NULL, NULL, NULL); | ||
4104 | bus->f2rxdata++; | ||
4105 | |||
4106 | /* Control frame failures need | ||
4107 | retransmission */ | ||
4108 | if (sdret < 0) { | ||
4109 | BRCMF_ERROR(("%s: read %d " | ||
4110 | "control bytes " | ||
4111 | "failed: %d\n", | ||
4112 | __func__, | ||
4113 | rdlen, sdret)); | ||
4114 | /* dhd.rx_ctlerrs is higher */ | ||
4115 | bus->rxc_errors++; | ||
4116 | brcmf_sdbrcm_rxfail(bus, true, | ||
4117 | (bus->bus == | ||
4118 | SPI_BUS) ? false | ||
4119 | : true); | ||
4120 | continue; | ||
4121 | } | ||
4122 | } else { | ||
4123 | /* Give up on data, | ||
4124 | request rtx of events */ | ||
4125 | BRCMF_ERROR(("%s (nextlen): " | ||
4126 | "brcmu_pkt_buf_get_skb " | ||
4127 | "failed:" | ||
4128 | " len %d rdlen %d expected" | ||
4129 | " rxseq %d\n", __func__, | ||
4130 | len, rdlen, rxseq)); | ||
4131 | continue; | ||
4132 | } | ||
4133 | } else { | ||
4134 | if (bus->bus == SPI_BUS) | ||
4135 | bus->usebufpool = true; | ||
4136 | |||
4137 | PKTALIGN(pkt, rdlen, BRCMF_SDALIGN); | ||
4138 | rxbuf = (u8 *) (pkt->data); | ||
4139 | /* Read the entire frame */ | ||
4140 | sdret = brcmf_sdcard_recv_buf(card, | ||
4141 | brcmf_sdcard_cur_sbwad(card), | ||
4142 | SDIO_FUNC_2, F2SYNC, | ||
4143 | rxbuf, rdlen, | ||
4144 | pkt, NULL, NULL); | ||
4145 | bus->f2rxdata++; | ||
4146 | |||
4147 | if (sdret < 0) { | ||
4148 | BRCMF_ERROR(("%s (nextlen): read %d" | ||
4149 | " bytes failed: %d\n", | ||
4150 | __func__, rdlen, sdret)); | ||
4151 | brcmu_pkt_buf_free_skb(pkt); | ||
4152 | bus->drvr->rx_errors++; | ||
4153 | /* Force retry w/normal header read. | ||
4154 | * Don't attempt NAK for | ||
4155 | * gSPI | ||
4156 | */ | ||
4157 | brcmf_sdbrcm_rxfail(bus, true, | ||
4158 | (bus->bus == | ||
4159 | SPI_BUS) ? false : | ||
4160 | true); | ||
4161 | continue; | ||
4162 | } | ||
4163 | } | ||
4164 | |||
4165 | /* Now check the header */ | ||
4166 | memcpy(bus->rxhdr, rxbuf, SDPCM_HDRLEN); | ||
4167 | |||
4168 | /* Extract hardware header fields */ | ||
4169 | len = get_unaligned_le16(bus->rxhdr); | ||
4170 | check = get_unaligned_le16(bus->rxhdr + sizeof(u16)); | ||
4171 | |||
4172 | /* All zeros means readahead info was bad */ | ||
4173 | if (!(len | check)) { | ||
4174 | BRCMF_INFO(("%s (nextlen): read zeros in HW " | ||
4175 | "header???\n", __func__)); | ||
4176 | brcmf_sdbrcm_pktfree2(bus, pkt); | ||
4177 | continue; | ||
4178 | } | ||
4179 | |||
4180 | /* Validate check bytes */ | ||
4181 | if ((u16)~(len ^ check)) { | ||
4182 | BRCMF_ERROR(("%s (nextlen): HW hdr error:" | ||
4183 | " nextlen/len/check" | ||
4184 | " 0x%04x/0x%04x/0x%04x\n", | ||
4185 | __func__, nextlen, len, check)); | ||
4186 | bus->rx_badhdr++; | ||
4187 | brcmf_sdbrcm_rxfail(bus, false, false); | ||
4188 | brcmf_sdbrcm_pktfree2(bus, pkt); | ||
4189 | continue; | ||
4190 | } | ||
4191 | |||
4192 | /* Validate frame length */ | ||
4193 | if (len < SDPCM_HDRLEN) { | ||
4194 | BRCMF_ERROR(("%s (nextlen): HW hdr length " | ||
4195 | "invalid: %d\n", __func__, len)); | ||
4196 | brcmf_sdbrcm_pktfree2(bus, pkt); | ||
4197 | continue; | ||
4198 | } | ||
4199 | |||
4200 | /* Check for consistency withreadahead info */ | ||
4201 | len_consistent = (nextlen != (roundup(len, 16) >> 4)); | ||
4202 | if (len_consistent) { | ||
4203 | /* Mismatch, force retry w/normal | ||
4204 | header (may be >4K) */ | ||
4205 | BRCMF_ERROR(("%s (nextlen): mismatch, " | ||
4206 | "nextlen %d len %d rnd %d; " | ||
4207 | "expected rxseq %d\n", | ||
4208 | __func__, nextlen, | ||
4209 | len, roundup(len, 16), rxseq)); | ||
4210 | brcmf_sdbrcm_rxfail(bus, true, | ||
4211 | bus->bus != SPI_BUS); | ||
4212 | brcmf_sdbrcm_pktfree2(bus, pkt); | ||
4213 | continue; | ||
4214 | } | ||
4215 | |||
4216 | /* Extract software header fields */ | ||
4217 | chan = SDPCM_PACKET_CHANNEL( | ||
4218 | &bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
4219 | seq = SDPCM_PACKET_SEQUENCE( | ||
4220 | &bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
4221 | doff = SDPCM_DOFFSET_VALUE( | ||
4222 | &bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
4223 | txmax = SDPCM_WINDOW_VALUE( | ||
4224 | &bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
4225 | |||
4226 | bus->nextlen = | ||
4227 | bus->rxhdr[SDPCM_FRAMETAG_LEN + | ||
4228 | SDPCM_NEXTLEN_OFFSET]; | ||
4229 | if ((bus->nextlen << 4) > MAX_RX_DATASZ) { | ||
4230 | BRCMF_INFO(("%s (nextlen): got frame w/nextlen" | ||
4231 | " too large (%d), seq %d\n", | ||
4232 | __func__, bus->nextlen, seq)); | ||
4233 | bus->nextlen = 0; | ||
4234 | } | ||
4235 | |||
4236 | bus->drvr->rx_readahead_cnt++; | ||
4237 | |||
4238 | /* Handle Flow Control */ | ||
4239 | fcbits = SDPCM_FCMASK_VALUE( | ||
4240 | &bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
4241 | |||
4242 | if (bus->flowcontrol != fcbits) { | ||
4243 | if (~bus->flowcontrol & fcbits) | ||
4244 | bus->fc_xoff++; | ||
4245 | |||
4246 | if (bus->flowcontrol & ~fcbits) | ||
4247 | bus->fc_xon++; | ||
4248 | |||
4249 | bus->fc_rcvd++; | ||
4250 | bus->flowcontrol = fcbits; | ||
4251 | } | ||
4252 | |||
4253 | /* Check and update sequence number */ | ||
4254 | if (rxseq != seq) { | ||
4255 | BRCMF_INFO(("%s (nextlen): rx_seq %d, expected " | ||
4256 | "%d\n", __func__, seq, rxseq)); | ||
4257 | bus->rx_badseq++; | ||
4258 | rxseq = seq; | ||
4259 | } | ||
4260 | |||
4261 | /* Check window for sanity */ | ||
4262 | if ((u8) (txmax - bus->tx_seq) > 0x40) { | ||
4263 | BRCMF_ERROR(("%s: got unlikely tx max %d with " | ||
4264 | "tx_seq %d\n", | ||
4265 | __func__, txmax, bus->tx_seq)); | ||
4266 | txmax = bus->tx_seq + 2; | ||
4267 | } | ||
4268 | bus->tx_max = txmax; | ||
4269 | |||
4270 | #ifdef BCMDBG | ||
4271 | if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { | ||
4272 | printk(KERN_DEBUG "Rx Data:\n"); | ||
4273 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, | ||
4274 | rxbuf, len); | ||
4275 | } else if (BRCMF_HDRS_ON()) { | ||
4276 | printk(KERN_DEBUG "RxHdr:\n"); | ||
4277 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, | ||
4278 | bus->rxhdr, SDPCM_HDRLEN); | ||
4279 | } | ||
4280 | #endif | ||
4281 | |||
4282 | if (chan == SDPCM_CONTROL_CHANNEL) { | ||
4283 | if (bus->bus == SPI_BUS) { | ||
4284 | brcmf_sdbrcm_read_control(bus, rxbuf, | ||
4285 | len, doff); | ||
4286 | } else { | ||
4287 | BRCMF_ERROR(("%s (nextlen): readahead" | ||
4288 | " on control packet %d?\n", | ||
4289 | __func__, seq)); | ||
4290 | /* Force retry w/normal header read */ | ||
4291 | bus->nextlen = 0; | ||
4292 | brcmf_sdbrcm_rxfail(bus, false, true); | ||
4293 | } | ||
4294 | brcmf_sdbrcm_pktfree2(bus, pkt); | ||
4295 | continue; | ||
4296 | } | ||
4297 | |||
4298 | if ((bus->bus == SPI_BUS) && !bus->usebufpool) { | ||
4299 | BRCMF_ERROR(("Received %d bytes on %d channel." | ||
4300 | " Running out of " "rx pktbuf's or" | ||
4301 | " not yet malloced.\n", | ||
4302 | len, chan)); | ||
4303 | continue; | ||
4304 | } | ||
4305 | |||
4306 | /* Validate data offset */ | ||
4307 | if ((doff < SDPCM_HDRLEN) || (doff > len)) { | ||
4308 | BRCMF_ERROR(("%s (nextlen): bad data offset %d:" | ||
4309 | " HW len %d min %d\n", __func__, | ||
4310 | doff, len, SDPCM_HDRLEN)); | ||
4311 | brcmf_sdbrcm_rxfail(bus, false, false); | ||
4312 | brcmf_sdbrcm_pktfree2(bus, pkt); | ||
4313 | continue; | ||
4314 | } | ||
4315 | |||
4316 | /* All done with this one -- now deliver the packet */ | ||
4317 | goto deliver; | ||
4318 | } | ||
4319 | /* gSPI frames should not be handled in fractions */ | ||
4320 | if (bus->bus == SPI_BUS) | ||
4321 | break; | ||
4322 | |||
4323 | /* Read frame header (hardware and software) */ | ||
4324 | sdret = brcmf_sdcard_recv_buf(card, | ||
4325 | brcmf_sdcard_cur_sbwad(card), | ||
4326 | SDIO_FUNC_2, F2SYNC, bus->rxhdr, firstread, | ||
4327 | NULL, NULL, NULL); | ||
4328 | bus->f2rxhdrs++; | ||
4329 | |||
4330 | if (sdret < 0) { | ||
4331 | BRCMF_ERROR(("%s: RXHEADER FAILED: %d\n", __func__, | ||
4332 | sdret)); | ||
4333 | bus->rx_hdrfail++; | ||
4334 | brcmf_sdbrcm_rxfail(bus, true, true); | ||
4335 | continue; | ||
4336 | } | ||
4337 | #ifdef BCMDBG | ||
4338 | if (BRCMF_BYTES_ON() || BRCMF_HDRS_ON()) { | ||
4339 | printk(KERN_DEBUG "RxHdr:\n"); | ||
4340 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, | ||
4341 | bus->rxhdr, SDPCM_HDRLEN); | ||
4342 | } | ||
4343 | #endif | ||
4344 | |||
4345 | /* Extract hardware header fields */ | ||
4346 | len = get_unaligned_le16(bus->rxhdr); | ||
4347 | check = get_unaligned_le16(bus->rxhdr + sizeof(u16)); | ||
4348 | |||
4349 | /* All zeros means no more frames */ | ||
4350 | if (!(len | check)) { | ||
4351 | *finished = true; | ||
4352 | break; | ||
4353 | } | ||
4354 | |||
4355 | /* Validate check bytes */ | ||
4356 | if ((u16) ~(len ^ check)) { | ||
4357 | BRCMF_ERROR(("%s: HW hdr err: len/check " | ||
4358 | "0x%04x/0x%04x\n", __func__, len, check)); | ||
4359 | bus->rx_badhdr++; | ||
4360 | brcmf_sdbrcm_rxfail(bus, false, false); | ||
4361 | continue; | ||
4362 | } | ||
4363 | |||
4364 | /* Validate frame length */ | ||
4365 | if (len < SDPCM_HDRLEN) { | ||
4366 | BRCMF_ERROR(("%s: HW hdr length invalid: %d\n", | ||
4367 | __func__, len)); | ||
4368 | continue; | ||
4369 | } | ||
4370 | |||
4371 | /* Extract software header fields */ | ||
4372 | chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
4373 | seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
4374 | doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
4375 | txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
4376 | |||
4377 | /* Validate data offset */ | ||
4378 | if ((doff < SDPCM_HDRLEN) || (doff > len)) { | ||
4379 | BRCMF_ERROR(("%s: Bad data offset %d: HW len %d," | ||
4380 | " min %d seq %d\n", __func__, doff, | ||
4381 | len, SDPCM_HDRLEN, seq)); | ||
4382 | bus->rx_badhdr++; | ||
4383 | brcmf_sdbrcm_rxfail(bus, false, false); | ||
4384 | continue; | ||
4385 | } | ||
4386 | |||
4387 | /* Save the readahead length if there is one */ | ||
4388 | bus->nextlen = | ||
4389 | bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; | ||
4390 | if ((bus->nextlen << 4) > MAX_RX_DATASZ) { | ||
4391 | BRCMF_INFO(("%s (nextlen): got frame w/nextlen too" | ||
4392 | " large (%d), seq %d\n", | ||
4393 | __func__, bus->nextlen, seq)); | ||
4394 | bus->nextlen = 0; | ||
4395 | } | ||
4396 | |||
4397 | /* Handle Flow Control */ | ||
4398 | fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
4399 | |||
4400 | if (bus->flowcontrol != fcbits) { | ||
4401 | if (~bus->flowcontrol & fcbits) | ||
4402 | bus->fc_xoff++; | ||
4403 | |||
4404 | if (bus->flowcontrol & ~fcbits) | ||
4405 | bus->fc_xon++; | ||
4406 | |||
4407 | bus->fc_rcvd++; | ||
4408 | bus->flowcontrol = fcbits; | ||
4409 | } | ||
4410 | |||
4411 | /* Check and update sequence number */ | ||
4412 | if (rxseq != seq) { | ||
4413 | BRCMF_INFO(("%s: rx_seq %d, expected %d\n", __func__, | ||
4414 | seq, rxseq)); | ||
4415 | bus->rx_badseq++; | ||
4416 | rxseq = seq; | ||
4417 | } | ||
4418 | |||
4419 | /* Check window for sanity */ | ||
4420 | if ((u8) (txmax - bus->tx_seq) > 0x40) { | ||
4421 | BRCMF_ERROR(("%s: unlikely tx max %d with tx_seq %d\n", | ||
4422 | __func__, txmax, bus->tx_seq)); | ||
4423 | txmax = bus->tx_seq + 2; | ||
4424 | } | ||
4425 | bus->tx_max = txmax; | ||
4426 | |||
4427 | /* Call a separate function for control frames */ | ||
4428 | if (chan == SDPCM_CONTROL_CHANNEL) { | ||
4429 | brcmf_sdbrcm_read_control(bus, bus->rxhdr, len, doff); | ||
4430 | continue; | ||
4431 | } | ||
4432 | |||
4433 | /* precondition: chan is either SDPCM_DATA_CHANNEL, | ||
4434 | SDPCM_EVENT_CHANNEL, SDPCM_TEST_CHANNEL or | ||
4435 | SDPCM_GLOM_CHANNEL */ | ||
4436 | |||
4437 | /* Length to read */ | ||
4438 | rdlen = (len > firstread) ? (len - firstread) : 0; | ||
4439 | |||
4440 | /* May pad read to blocksize for efficiency */ | ||
4441 | if (bus->roundup && bus->blocksize && | ||
4442 | (rdlen > bus->blocksize)) { | ||
4443 | pad = bus->blocksize - (rdlen % bus->blocksize); | ||
4444 | if ((pad <= bus->roundup) && (pad < bus->blocksize) && | ||
4445 | ((rdlen + pad + firstread) < MAX_RX_DATASZ)) | ||
4446 | rdlen += pad; | ||
4447 | } else if (rdlen % BRCMF_SDALIGN) { | ||
4448 | rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN); | ||
4449 | } | ||
4450 | |||
4451 | /* Satisfy length-alignment requirements */ | ||
4452 | if (forcealign && (rdlen & (ALIGNMENT - 1))) | ||
4453 | rdlen = roundup(rdlen, ALIGNMENT); | ||
4454 | |||
4455 | if ((rdlen + firstread) > MAX_RX_DATASZ) { | ||
4456 | /* Too long -- skip this frame */ | ||
4457 | BRCMF_ERROR(("%s: too long: len %d rdlen %d\n", | ||
4458 | __func__, len, rdlen)); | ||
4459 | bus->drvr->rx_errors++; | ||
4460 | bus->rx_toolong++; | ||
4461 | brcmf_sdbrcm_rxfail(bus, false, false); | ||
4462 | continue; | ||
4463 | } | ||
4464 | |||
4465 | pkt = brcmu_pkt_buf_get_skb(rdlen + firstread + BRCMF_SDALIGN); | ||
4466 | if (!pkt) { | ||
4467 | /* Give up on data, request rtx of events */ | ||
4468 | BRCMF_ERROR(("%s: brcmu_pkt_buf_get_skb failed:" | ||
4469 | " rdlen %d chan %d\n", __func__, rdlen, | ||
4470 | chan)); | ||
4471 | bus->drvr->rx_dropped++; | ||
4472 | brcmf_sdbrcm_rxfail(bus, false, RETRYCHAN(chan)); | ||
4473 | continue; | ||
4474 | } | ||
4475 | |||
4476 | /* Leave room for what we already read, and align remainder */ | ||
4477 | skb_pull(pkt, firstread); | ||
4478 | PKTALIGN(pkt, rdlen, BRCMF_SDALIGN); | ||
4479 | |||
4480 | /* Read the remaining frame data */ | ||
4481 | sdret = brcmf_sdcard_recv_buf(card, | ||
4482 | brcmf_sdcard_cur_sbwad(card), | ||
4483 | SDIO_FUNC_2, F2SYNC, ((u8 *) (pkt->data)), | ||
4484 | rdlen, pkt, NULL, NULL); | ||
4485 | bus->f2rxdata++; | ||
4486 | |||
4487 | if (sdret < 0) { | ||
4488 | BRCMF_ERROR(("%s: read %d %s bytes failed: %d\n", | ||
4489 | __func__, rdlen, | ||
4490 | ((chan == SDPCM_EVENT_CHANNEL) ? "event" | ||
4491 | : ((chan == SDPCM_DATA_CHANNEL) ? "data" | ||
4492 | : "test")), sdret)); | ||
4493 | brcmu_pkt_buf_free_skb(pkt); | ||
4494 | bus->drvr->rx_errors++; | ||
4495 | brcmf_sdbrcm_rxfail(bus, true, RETRYCHAN(chan)); | ||
4496 | continue; | ||
4497 | } | ||
4498 | |||
4499 | /* Copy the already-read portion */ | ||
4500 | skb_push(pkt, firstread); | ||
4501 | memcpy(pkt->data, bus->rxhdr, firstread); | ||
4502 | |||
4503 | #ifdef BCMDBG | ||
4504 | if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { | ||
4505 | printk(KERN_DEBUG "Rx Data:\n"); | ||
4506 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, | ||
4507 | pkt->data, len); | ||
4508 | } | ||
4509 | #endif | ||
4510 | |||
4511 | deliver: | ||
4512 | /* Save superframe descriptor and allocate packet frame */ | ||
4513 | if (chan == SDPCM_GLOM_CHANNEL) { | ||
4514 | if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { | ||
4515 | BRCMF_GLOM(("%s: glom descriptor, %d bytes:\n", | ||
4516 | __func__, len)); | ||
4517 | #ifdef BCMDBG | ||
4518 | if (BRCMF_GLOM_ON()) { | ||
4519 | printk(KERN_DEBUG "Glom Data:\n"); | ||
4520 | print_hex_dump_bytes("", | ||
4521 | DUMP_PREFIX_OFFSET, | ||
4522 | pkt->data, len); | ||
4523 | } | ||
4524 | #endif | ||
4525 | __skb_trim(pkt, len); | ||
4526 | skb_pull(pkt, SDPCM_HDRLEN); | ||
4527 | bus->glomd = pkt; | ||
4528 | } else { | ||
4529 | BRCMF_ERROR(("%s: glom superframe w/o " | ||
4530 | "descriptor!\n", __func__)); | ||
4531 | brcmf_sdbrcm_rxfail(bus, false, false); | ||
4532 | } | ||
4533 | continue; | ||
4534 | } | ||
4535 | |||
4536 | /* Fill in packet len and prio, deliver upward */ | ||
4537 | __skb_trim(pkt, len); | ||
4538 | skb_pull(pkt, doff); | ||
4539 | |||
4540 | #ifdef SDTEST | ||
4541 | /* Test channel packets are processed separately */ | ||
4542 | if (chan == SDPCM_TEST_CHANNEL) { | ||
4543 | brcmf_sdbrcm_checkdied(bus, pkt, seq); | ||
4544 | continue; | ||
4545 | } | ||
4546 | #endif /* SDTEST */ | ||
4547 | |||
4548 | if (pkt->len == 0) { | ||
4549 | brcmu_pkt_buf_free_skb(pkt); | ||
4550 | continue; | ||
4551 | } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx, pkt) != 0) { | ||
4552 | BRCMF_ERROR(("%s: rx protocol error\n", __func__)); | ||
4553 | brcmu_pkt_buf_free_skb(pkt); | ||
4554 | bus->drvr->rx_errors++; | ||
4555 | continue; | ||
4556 | } | ||
4557 | |||
4558 | /* Unlock during rx call */ | ||
4559 | brcmf_sdbrcm_sdunlock(bus); | ||
4560 | brcmf_rx_frame(bus->drvr, ifidx, pkt, 1); | ||
4561 | brcmf_sdbrcm_sdlock(bus); | ||
4562 | } | ||
4563 | rxcount = maxframes - rxleft; | ||
4564 | #ifdef BCMDBG | ||
4565 | /* Message if we hit the limit */ | ||
4566 | if (!rxleft && !sdtest) | ||
4567 | BRCMF_DATA(("%s: hit rx limit of %d frames\n", __func__, | ||
4568 | maxframes)); | ||
4569 | else | ||
4570 | #endif /* BCMDBG */ | ||
4571 | BRCMF_DATA(("%s: processed %d frames\n", __func__, rxcount)); | ||
4572 | /* Back off rxseq if awaiting rtx, update rx_seq */ | ||
4573 | if (bus->rxskip) | ||
4574 | rxseq--; | ||
4575 | bus->rx_seq = rxseq; | ||
4576 | |||
4577 | return rxcount; | ||
4578 | } | ||
4579 | |||
4580 | static u32 brcmf_sdbrcm_hostmail(struct brcmf_bus *bus) | ||
4581 | { | ||
4582 | u32 intstatus = 0; | ||
4583 | u32 hmb_data; | ||
4584 | u8 fcbits; | ||
4585 | uint retries = 0; | ||
4586 | |||
4587 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
4588 | |||
4589 | /* Read mailbox data and ack that we did so */ | ||
4590 | r_sdreg32(bus, &hmb_data, | ||
4591 | offsetof(struct sdpcmd_regs, tohostmailboxdata), &retries); | ||
4592 | |||
4593 | if (retries <= retry_limit) | ||
4594 | w_sdreg32(bus, SMB_INT_ACK, | ||
4595 | offsetof(struct sdpcmd_regs, tosbmailbox), &retries); | ||
4596 | bus->f1regdata += 2; | ||
4597 | |||
4598 | /* Dongle recomposed rx frames, accept them again */ | ||
4599 | if (hmb_data & HMB_DATA_NAKHANDLED) { | ||
4600 | BRCMF_INFO(("Dongle reports NAK handled, expect rtx of %d\n", | ||
4601 | bus->rx_seq)); | ||
4602 | if (!bus->rxskip) | ||
4603 | BRCMF_ERROR(("%s: unexpected NAKHANDLED!\n", __func__)); | ||
4604 | |||
4605 | bus->rxskip = false; | ||
4606 | intstatus |= I_HMB_FRAME_IND; | ||
4607 | } | ||
4608 | |||
4609 | /* | ||
4610 | * DEVREADY does not occur with gSPI. | ||
4611 | */ | ||
4612 | if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) { | ||
4613 | bus->sdpcm_ver = | ||
4614 | (hmb_data & HMB_DATA_VERSION_MASK) >> | ||
4615 | HMB_DATA_VERSION_SHIFT; | ||
4616 | if (bus->sdpcm_ver != SDPCM_PROT_VERSION) | ||
4617 | BRCMF_ERROR(("Version mismatch, dongle reports %d, " | ||
4618 | "expecting %d\n", | ||
4619 | bus->sdpcm_ver, SDPCM_PROT_VERSION)); | ||
4620 | else | ||
4621 | BRCMF_INFO(("Dongle ready, protocol version %d\n", | ||
4622 | bus->sdpcm_ver)); | ||
4623 | } | ||
4624 | |||
4625 | /* | ||
4626 | * Flow Control has been moved into the RX headers and this out of band | ||
4627 | * method isn't used any more. | ||
4628 | * remaining backward compatible with older dongles. | ||
4629 | */ | ||
4630 | if (hmb_data & HMB_DATA_FC) { | ||
4631 | fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> | ||
4632 | HMB_DATA_FCDATA_SHIFT; | ||
4633 | |||
4634 | if (fcbits & ~bus->flowcontrol) | ||
4635 | bus->fc_xoff++; | ||
4636 | |||
4637 | if (bus->flowcontrol & ~fcbits) | ||
4638 | bus->fc_xon++; | ||
4639 | |||
4640 | bus->fc_rcvd++; | ||
4641 | bus->flowcontrol = fcbits; | ||
4642 | } | ||
4643 | |||
4644 | /* Shouldn't be any others */ | ||
4645 | if (hmb_data & ~(HMB_DATA_DEVREADY | | ||
4646 | HMB_DATA_NAKHANDLED | | ||
4647 | HMB_DATA_FC | | ||
4648 | HMB_DATA_FWREADY | | ||
4649 | HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK)) { | ||
4650 | BRCMF_ERROR(("Unknown mailbox data content: 0x%02x\n", | ||
4651 | hmb_data)); | ||
4652 | } | ||
4653 | |||
4654 | return intstatus; | ||
4655 | } | ||
4656 | |||
4657 | static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus) | ||
4658 | { | ||
4659 | struct brcmf_sdio_card *card = bus->card; | ||
4660 | u32 intstatus, newstatus = 0; | ||
4661 | uint retries = 0; | ||
4662 | uint rxlimit = brcmf_rxbound; /* Rx frames to read before resched */ | ||
4663 | uint txlimit = brcmf_txbound; /* Tx frames to send before resched */ | ||
4664 | uint framecnt = 0; /* Temporary counter of tx/rx frames */ | ||
4665 | bool rxdone = true; /* Flag for no more read data */ | ||
4666 | bool resched = false; /* Flag indicating resched wanted */ | ||
4667 | |||
4668 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
4669 | |||
4670 | /* Start with leftover status bits */ | ||
4671 | intstatus = bus->intstatus; | ||
4672 | |||
4673 | brcmf_sdbrcm_sdlock(bus); | ||
4674 | |||
4675 | /* If waiting for HTAVAIL, check status */ | ||
4676 | if (bus->clkstate == CLK_PENDING) { | ||
4677 | int err; | ||
4678 | u8 clkctl, devctl = 0; | ||
4679 | |||
4680 | #ifdef BCMDBG | ||
4681 | /* Check for inconsistent device control */ | ||
4682 | devctl = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1, | ||
4683 | SBSDIO_DEVICE_CTL, &err); | ||
4684 | if (err) { | ||
4685 | BRCMF_ERROR(("%s: error reading DEVCTL: %d\n", | ||
4686 | __func__, err)); | ||
4687 | bus->drvr->busstate = BRCMF_BUS_DOWN; | ||
4688 | } | ||
4689 | #endif /* BCMDBG */ | ||
4690 | |||
4691 | /* Read CSR, if clock on switch to AVAIL, else ignore */ | ||
4692 | clkctl = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1, | ||
4693 | SBSDIO_FUNC1_CHIPCLKCSR, &err); | ||
4694 | if (err) { | ||
4695 | BRCMF_ERROR(("%s: error reading CSR: %d\n", __func__, | ||
4696 | err)); | ||
4697 | bus->drvr->busstate = BRCMF_BUS_DOWN; | ||
4698 | } | ||
4699 | |||
4700 | BRCMF_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", | ||
4701 | devctl, clkctl)); | ||
4702 | |||
4703 | if (SBSDIO_HTAV(clkctl)) { | ||
4704 | devctl = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1, | ||
4705 | SBSDIO_DEVICE_CTL, &err); | ||
4706 | if (err) { | ||
4707 | BRCMF_ERROR(("%s: error reading DEVCTL: %d\n", | ||
4708 | __func__, err)); | ||
4709 | bus->drvr->busstate = BRCMF_BUS_DOWN; | ||
4710 | } | ||
4711 | devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; | ||
4712 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, | ||
4713 | SBSDIO_DEVICE_CTL, devctl, &err); | ||
4714 | if (err) { | ||
4715 | BRCMF_ERROR(("%s: error writing DEVCTL: %d\n", | ||
4716 | __func__, err)); | ||
4717 | bus->drvr->busstate = BRCMF_BUS_DOWN; | ||
4718 | } | ||
4719 | bus->clkstate = CLK_AVAIL; | ||
4720 | } else { | ||
4721 | goto clkwait; | ||
4722 | } | ||
4723 | } | ||
4724 | |||
4725 | BUS_WAKE(bus); | ||
4726 | |||
4727 | /* Make sure backplane clock is on */ | ||
4728 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true); | ||
4729 | if (bus->clkstate == CLK_PENDING) | ||
4730 | goto clkwait; | ||
4731 | |||
4732 | /* Pending interrupt indicates new device status */ | ||
4733 | if (bus->ipend) { | ||
4734 | bus->ipend = false; | ||
4735 | r_sdreg32(bus, &newstatus, | ||
4736 | offsetof(struct sdpcmd_regs, intstatus), &retries); | ||
4737 | bus->f1regdata++; | ||
4738 | if (brcmf_sdcard_regfail(bus->card)) | ||
4739 | newstatus = 0; | ||
4740 | newstatus &= bus->hostintmask; | ||
4741 | bus->fcstate = !!(newstatus & I_HMB_FC_STATE); | ||
4742 | if (newstatus) { | ||
4743 | w_sdreg32(bus, newstatus, | ||
4744 | offsetof(struct sdpcmd_regs, intstatus), | ||
4745 | &retries); | ||
4746 | bus->f1regdata++; | ||
4747 | } | ||
4748 | } | ||
4749 | |||
4750 | /* Merge new bits with previous */ | ||
4751 | intstatus |= newstatus; | ||
4752 | bus->intstatus = 0; | ||
4753 | |||
4754 | /* Handle flow-control change: read new state in case our ack | ||
4755 | * crossed another change interrupt. If change still set, assume | ||
4756 | * FC ON for safety, let next loop through do the debounce. | ||
4757 | */ | ||
4758 | if (intstatus & I_HMB_FC_CHANGE) { | ||
4759 | intstatus &= ~I_HMB_FC_CHANGE; | ||
4760 | w_sdreg32(bus, I_HMB_FC_CHANGE, | ||
4761 | offsetof(struct sdpcmd_regs, intstatus), &retries); | ||
4762 | |||
4763 | r_sdreg32(bus, &newstatus, | ||
4764 | offsetof(struct sdpcmd_regs, intstatus), &retries); | ||
4765 | bus->f1regdata += 2; | ||
4766 | bus->fcstate = | ||
4767 | !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); | ||
4768 | intstatus |= (newstatus & bus->hostintmask); | ||
4769 | } | ||
4770 | |||
4771 | /* Handle host mailbox indication */ | ||
4772 | if (intstatus & I_HMB_HOST_INT) { | ||
4773 | intstatus &= ~I_HMB_HOST_INT; | ||
4774 | intstatus |= brcmf_sdbrcm_hostmail(bus); | ||
4775 | } | ||
4776 | |||
4777 | /* Generally don't ask for these, can get CRC errors... */ | ||
4778 | if (intstatus & I_WR_OOSYNC) { | ||
4779 | BRCMF_ERROR(("Dongle reports WR_OOSYNC\n")); | ||
4780 | intstatus &= ~I_WR_OOSYNC; | ||
4781 | } | ||
4782 | |||
4783 | if (intstatus & I_RD_OOSYNC) { | ||
4784 | BRCMF_ERROR(("Dongle reports RD_OOSYNC\n")); | ||
4785 | intstatus &= ~I_RD_OOSYNC; | ||
4786 | } | ||
4787 | |||
4788 | if (intstatus & I_SBINT) { | ||
4789 | BRCMF_ERROR(("Dongle reports SBINT\n")); | ||
4790 | intstatus &= ~I_SBINT; | ||
4791 | } | ||
4792 | |||
4793 | /* Would be active due to wake-wlan in gSPI */ | ||
4794 | if (intstatus & I_CHIPACTIVE) { | ||
4795 | BRCMF_INFO(("Dongle reports CHIPACTIVE\n")); | ||
4796 | intstatus &= ~I_CHIPACTIVE; | ||
4797 | } | ||
4798 | |||
4799 | /* Ignore frame indications if rxskip is set */ | ||
4800 | if (bus->rxskip) | ||
4801 | intstatus &= ~I_HMB_FRAME_IND; | ||
4802 | |||
4803 | /* On frame indication, read available frames */ | ||
4804 | if (PKT_AVAILABLE()) { | ||
4805 | framecnt = brcmf_sdbrcm_readframes(bus, rxlimit, &rxdone); | ||
4806 | if (rxdone || bus->rxskip) | ||
4807 | intstatus &= ~I_HMB_FRAME_IND; | ||
4808 | rxlimit -= min(framecnt, rxlimit); | ||
4809 | } | ||
4810 | |||
4811 | /* Keep still-pending events for next scheduling */ | ||
4812 | bus->intstatus = intstatus; | ||
4813 | |||
4814 | clkwait: | ||
4815 | /* Re-enable interrupts to detect new device events (mailbox, rx frame) | ||
4816 | * or clock availability. (Allows tx loop to check ipend if desired.) | ||
4817 | * (Unless register access seems hosed, as we may not be able to ACK...) | ||
4818 | */ | ||
4819 | if (bus->intr && bus->intdis && !brcmf_sdcard_regfail(card)) { | ||
4820 | BRCMF_INTR(("%s: enable SDIO interrupts, rxdone %d" | ||
4821 | " framecnt %d\n", __func__, rxdone, framecnt)); | ||
4822 | bus->intdis = false; | ||
4823 | brcmf_sdcard_intr_enable(card); | ||
4824 | } | ||
4825 | |||
4826 | if (DATAOK(bus) && bus->ctrl_frame_stat && | ||
4827 | (bus->clkstate == CLK_AVAIL)) { | ||
4828 | int ret, i; | ||
4829 | |||
4830 | ret = brcmf_sdbrcm_send_buf(bus, brcmf_sdcard_cur_sbwad(card), | ||
4831 | SDIO_FUNC_2, F2SYNC, (u8 *) bus->ctrl_frame_buf, | ||
4832 | (u32) bus->ctrl_frame_len, NULL, NULL, NULL); | ||
4833 | |||
4834 | if (ret < 0) { | ||
4835 | /* On failure, abort the command and | ||
4836 | terminate the frame */ | ||
4837 | BRCMF_INFO(("%s: sdio error %d, abort command and " | ||
4838 | "terminate frame.\n", __func__, ret)); | ||
4839 | bus->tx_sderrs++; | ||
4840 | |||
4841 | brcmf_sdcard_abort(card, SDIO_FUNC_2); | ||
4842 | |||
4843 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, | ||
4844 | SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, | ||
4845 | NULL); | ||
4846 | bus->f1regdata++; | ||
4847 | |||
4848 | for (i = 0; i < 3; i++) { | ||
4849 | u8 hi, lo; | ||
4850 | hi = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1, | ||
4851 | SBSDIO_FUNC1_WFRAMEBCHI, | ||
4852 | NULL); | ||
4853 | lo = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1, | ||
4854 | SBSDIO_FUNC1_WFRAMEBCLO, | ||
4855 | NULL); | ||
4856 | bus->f1regdata += 2; | ||
4857 | if ((hi == 0) && (lo == 0)) | ||
4858 | break; | ||
4859 | } | ||
4860 | |||
4861 | } | ||
4862 | if (ret == 0) | ||
4863 | bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; | ||
4864 | |||
4865 | BRCMF_INFO(("Return_dpc value is : %d\n", ret)); | ||
4866 | bus->ctrl_frame_stat = false; | ||
4867 | brcmf_sdbrcm_wait_event_wakeup(bus); | ||
4868 | } | ||
4869 | /* Send queued frames (limit 1 if rx may still be pending) */ | ||
4870 | else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && | ||
4871 | brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit | ||
4872 | && DATAOK(bus)) { | ||
4873 | framecnt = rxdone ? txlimit : min(txlimit, brcmf_txminmax); | ||
4874 | framecnt = brcmf_sdbrcm_sendfromq(bus, framecnt); | ||
4875 | txlimit -= framecnt; | ||
4876 | } | ||
4877 | |||
4878 | /* Resched if events or tx frames are pending, | ||
4879 | else await next interrupt */ | ||
4880 | /* On failed register access, all bets are off: | ||
4881 | no resched or interrupts */ | ||
4882 | if ((bus->drvr->busstate == BRCMF_BUS_DOWN) || | ||
4883 | brcmf_sdcard_regfail(card)) { | ||
4884 | BRCMF_ERROR(("%s: failed backplane access over SDIO, halting " | ||
4885 | "operation %d\n", __func__, | ||
4886 | brcmf_sdcard_regfail(card))); | ||
4887 | bus->drvr->busstate = BRCMF_BUS_DOWN; | ||
4888 | bus->intstatus = 0; | ||
4889 | } else if (bus->clkstate == CLK_PENDING) { | ||
4890 | BRCMF_INFO(("%s: rescheduled due to CLK_PENDING awaiting " | ||
4891 | "I_CHIPACTIVE interrupt\n", __func__)); | ||
4892 | resched = true; | ||
4893 | } else if (bus->intstatus || bus->ipend || | ||
4894 | (!bus->fcstate && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) | ||
4895 | && DATAOK(bus)) || PKT_AVAILABLE()) { | ||
4896 | resched = true; | ||
4897 | } | ||
4898 | |||
4899 | bus->dpc_sched = resched; | ||
4900 | |||
4901 | /* If we're done for now, turn off clock request. */ | ||
4902 | if ((bus->clkstate != CLK_PENDING) | ||
4903 | && bus->idletime == BRCMF_IDLE_IMMEDIATE) { | ||
4904 | bus->activity = false; | ||
4905 | brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); | ||
4906 | } | ||
4907 | |||
4908 | brcmf_sdbrcm_sdunlock(bus); | ||
4909 | |||
4910 | return resched; | ||
4911 | } | ||
4912 | |||
4913 | void brcmf_sdbrcm_isr(void *arg) | ||
4914 | { | ||
4915 | struct brcmf_bus *bus = (struct brcmf_bus *) arg; | ||
4916 | struct brcmf_sdio_card *card; | ||
4917 | |||
4918 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
4919 | |||
4920 | if (!bus) { | ||
4921 | BRCMF_ERROR(("%s : bus is null pointer , exit\n", __func__)); | ||
4922 | return; | ||
4923 | } | ||
4924 | card = bus->card; | ||
4925 | |||
4926 | if (bus->drvr->busstate == BRCMF_BUS_DOWN) { | ||
4927 | BRCMF_ERROR(("%s : bus is down. we have nothing to do\n", | ||
4928 | __func__)); | ||
4929 | return; | ||
4930 | } | ||
4931 | /* Count the interrupt call */ | ||
4932 | bus->intrcount++; | ||
4933 | bus->ipend = true; | ||
4934 | |||
4935 | /* Shouldn't get this interrupt if we're sleeping? */ | ||
4936 | if (bus->sleeping) { | ||
4937 | BRCMF_ERROR(("INTERRUPT WHILE SLEEPING??\n")); | ||
4938 | return; | ||
4939 | } | ||
4940 | |||
4941 | /* Disable additional interrupts (is this needed now)? */ | ||
4942 | if (bus->intr) | ||
4943 | BRCMF_INTR(("%s: disable SDIO interrupts\n", __func__)); | ||
4944 | else | ||
4945 | BRCMF_ERROR(("brcmf_sdbrcm_isr() w/o interrupt configured!\n")); | ||
4946 | |||
4947 | brcmf_sdcard_intr_disable(card); | ||
4948 | bus->intdis = true; | ||
4949 | |||
4950 | #if defined(SDIO_ISR_THREAD) | ||
4951 | BRCMF_TRACE(("Calling brcmf_sdbrcm_dpc() from %s\n", __func__)); | ||
4952 | while (brcmf_sdbrcm_dpc(bus)) | ||
4953 | ; | ||
4954 | #else | ||
4955 | bus->dpc_sched = true; | ||
4956 | brcmf_sdbrcm_sched_dpc(bus); | ||
4957 | #endif | ||
4958 | |||
4959 | } | ||
4960 | |||
4961 | #ifdef SDTEST | ||
4962 | static void brcmf_sdbrcm_pktgen_init(struct brcmf_bus *bus) | ||
4963 | { | ||
4964 | /* Default to specified length, or full range */ | ||
4965 | if (brcmf_pktgen_len) { | ||
4966 | bus->pktgen_maxlen = min(brcmf_pktgen_len, | ||
4967 | BRCMF_MAX_PKTGEN_LEN); | ||
4968 | bus->pktgen_minlen = bus->pktgen_maxlen; | ||
4969 | } else { | ||
4970 | bus->pktgen_maxlen = BRCMF_MAX_PKTGEN_LEN; | ||
4971 | bus->pktgen_minlen = 0; | ||
4972 | } | ||
4973 | bus->pktgen_len = (u16) bus->pktgen_minlen; | ||
4974 | |||
4975 | /* Default to per-watchdog burst with 10s print time */ | ||
4976 | bus->pktgen_freq = 1; | ||
4977 | bus->pktgen_print = 10000 / brcmf_watchdog_ms; | ||
4978 | bus->pktgen_count = (brcmf_pktgen * brcmf_watchdog_ms + 999) / 1000; | ||
4979 | |||
4980 | /* Default to echo mode */ | ||
4981 | bus->pktgen_mode = BRCMF_PKTGEN_ECHO; | ||
4982 | bus->pktgen_stop = 1; | ||
4983 | } | ||
4984 | |||
4985 | static void brcmf_sdbrcm_pktgen(struct brcmf_bus *bus) | ||
4986 | { | ||
4987 | struct sk_buff *pkt; | ||
4988 | u8 *data; | ||
4989 | uint pktcount; | ||
4990 | uint fillbyte; | ||
4991 | u16 len; | ||
4992 | |||
4993 | /* Display current count if appropriate */ | ||
4994 | if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) { | ||
4995 | bus->pktgen_ptick = 0; | ||
4996 | printk(KERN_DEBUG "%s: send attempts %d rcvd %d\n", | ||
4997 | __func__, bus->pktgen_sent, bus->pktgen_rcvd); | ||
4998 | } | ||
4999 | |||
5000 | /* For recv mode, just make sure dongle has started sending */ | ||
5001 | if (bus->pktgen_mode == BRCMF_PKTGEN_RECV) { | ||
5002 | if (!bus->pktgen_rcvd) | ||
5003 | brcmf_sdbrcm_sdtest_set(bus, true); | ||
5004 | return; | ||
5005 | } | ||
5006 | |||
5007 | /* Otherwise, generate or request the specified number of packets */ | ||
5008 | for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) { | ||
5009 | /* Stop if total has been reached */ | ||
5010 | if (bus->pktgen_total | ||
5011 | && (bus->pktgen_sent >= bus->pktgen_total)) { | ||
5012 | bus->pktgen_count = 0; | ||
5013 | break; | ||
5014 | } | ||
5015 | |||
5016 | /* Allocate an appropriate-sized packet */ | ||
5017 | len = bus->pktgen_len; | ||
5018 | pkt = brcmu_pkt_buf_get_skb( | ||
5019 | len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + BRCMF_SDALIGN, | ||
5020 | true); | ||
5021 | if (!pkt) { | ||
5022 | BRCMF_ERROR(("%s: brcmu_pkt_buf_get_skb failed!\n", | ||
5023 | __func__)); | ||
5024 | break; | ||
5025 | } | ||
5026 | PKTALIGN(pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), | ||
5027 | BRCMF_SDALIGN); | ||
5028 | data = (u8 *) (pkt->data) + SDPCM_HDRLEN; | ||
5029 | |||
5030 | /* Write test header cmd and extra based on mode */ | ||
5031 | switch (bus->pktgen_mode) { | ||
5032 | case BRCMF_PKTGEN_ECHO: | ||
5033 | *data++ = SDPCM_TEST_ECHOREQ; | ||
5034 | *data++ = (u8) bus->pktgen_sent; | ||
5035 | break; | ||
5036 | |||
5037 | case BRCMF_PKTGEN_SEND: | ||
5038 | *data++ = SDPCM_TEST_DISCARD; | ||
5039 | *data++ = (u8) bus->pktgen_sent; | ||
5040 | break; | ||
5041 | |||
5042 | case BRCMF_PKTGEN_RXBURST: | ||
5043 | *data++ = SDPCM_TEST_BURST; | ||
5044 | *data++ = (u8) bus->pktgen_count; | ||
5045 | break; | ||
5046 | |||
5047 | default: | ||
5048 | BRCMF_ERROR(("Unrecognized pktgen mode %d\n", | ||
5049 | bus->pktgen_mode)); | ||
5050 | brcmu_pkt_buf_free_skb(pkt, true); | ||
5051 | bus->pktgen_count = 0; | ||
5052 | return; | ||
5053 | } | ||
5054 | |||
5055 | /* Write test header length field */ | ||
5056 | *data++ = (len >> 0); | ||
5057 | *data++ = (len >> 8); | ||
5058 | |||
5059 | /* Then fill in the remainder -- N/A for burst, | ||
5060 | but who cares... */ | ||
5061 | for (fillbyte = 0; fillbyte < len; fillbyte++) | ||
5062 | *data++ = | ||
5063 | SDPCM_TEST_FILL(fillbyte, (u8) bus->pktgen_sent); | ||
5064 | |||
5065 | #ifdef BCMDBG | ||
5066 | if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { | ||
5067 | data = (u8 *) (pkt->data) + SDPCM_HDRLEN; | ||
5068 | printk(KERN_DEBUG "brcmf_sdbrcm_pktgen: Tx Data:\n"); | ||
5069 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, data, | ||
5070 | pkt->len - SDPCM_HDRLEN); | ||
5071 | } | ||
5072 | #endif | ||
5073 | |||
5074 | /* Send it */ | ||
5075 | if (brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, true)) { | ||
5076 | bus->pktgen_fail++; | ||
5077 | if (bus->pktgen_stop | ||
5078 | && bus->pktgen_stop == bus->pktgen_fail) | ||
5079 | bus->pktgen_count = 0; | ||
5080 | } | ||
5081 | bus->pktgen_sent++; | ||
5082 | |||
5083 | /* Bump length if not fixed, wrap at max */ | ||
5084 | if (++bus->pktgen_len > bus->pktgen_maxlen) | ||
5085 | bus->pktgen_len = (u16) bus->pktgen_minlen; | ||
5086 | |||
5087 | /* Special case for burst mode: just send one request! */ | ||
5088 | if (bus->pktgen_mode == BRCMF_PKTGEN_RXBURST) | ||
5089 | break; | ||
5090 | } | ||
5091 | } | ||
5092 | |||
5093 | static void brcmf_sdbrcm_sdtest_set(struct brcmf_bus *bus, bool start) | ||
5094 | { | ||
5095 | struct sk_buff *pkt; | ||
5096 | u8 *data; | ||
5097 | |||
5098 | /* Allocate the packet */ | ||
5099 | pkt = brcmu_pkt_buf_get_skb(SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + | ||
5100 | BRCMF_SDALIGN, true); | ||
5101 | if (!pkt) { | ||
5102 | BRCMF_ERROR(("%s: brcmu_pkt_buf_get_skb failed!\n", __func__)); | ||
5103 | return; | ||
5104 | } | ||
5105 | PKTALIGN(pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), BRCMF_SDALIGN); | ||
5106 | data = (u8 *) (pkt->data) + SDPCM_HDRLEN; | ||
5107 | |||
5108 | /* Fill in the test header */ | ||
5109 | *data++ = SDPCM_TEST_SEND; | ||
5110 | *data++ = start; | ||
5111 | *data++ = (bus->pktgen_maxlen >> 0); | ||
5112 | *data++ = (bus->pktgen_maxlen >> 8); | ||
5113 | |||
5114 | /* Send it */ | ||
5115 | if (brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, true)) | ||
5116 | bus->pktgen_fail++; | ||
5117 | } | ||
5118 | |||
5119 | static void | ||
5120 | brcmf_sdbrcm_checkdied(struct brcmf_bus *bus, struct sk_buff *pkt, uint seq) | ||
5121 | { | ||
5122 | u8 *data; | ||
5123 | uint pktlen; | ||
5124 | |||
5125 | u8 cmd; | ||
5126 | u8 extra; | ||
5127 | u16 len; | ||
5128 | u16 offset; | ||
5129 | |||
5130 | /* Check for min length */ | ||
5131 | pktlen = pkt->len; | ||
5132 | if (pktlen < SDPCM_TEST_HDRLEN) { | ||
5133 | BRCMF_ERROR(("brcmf_sdbrcm_checkdied: toss runt frame, pktlen " | ||
5134 | "%d\n", pktlen)); | ||
5135 | brcmu_pkt_buf_free_skb(pkt, false); | ||
5136 | return; | ||
5137 | } | ||
5138 | |||
5139 | /* Extract header fields */ | ||
5140 | data = pkt->data; | ||
5141 | cmd = *data++; | ||
5142 | extra = *data++; | ||
5143 | len = *data++; | ||
5144 | len += *data++ << 8; | ||
5145 | |||
5146 | /* Check length for relevant commands */ | ||
5147 | if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ | ||
5148 | || cmd == SDPCM_TEST_ECHORSP) { | ||
5149 | if (pktlen != len + SDPCM_TEST_HDRLEN) { | ||
5150 | BRCMF_ERROR(("brcmf_sdbrcm_checkdied: frame length " | ||
5151 | "mismatch, pktlen %d seq %d" | ||
5152 | " cmd %d extra %d len %d\n", | ||
5153 | pktlen, seq, cmd, extra, len)); | ||
5154 | brcmu_pkt_buf_free_skb(pkt, false); | ||
5155 | return; | ||
5156 | } | ||
5157 | } | ||
5158 | |||
5159 | /* Process as per command */ | ||
5160 | switch (cmd) { | ||
5161 | case SDPCM_TEST_ECHOREQ: | ||
5162 | /* Rx->Tx turnaround ok (even on NDIS w/current | ||
5163 | implementation) */ | ||
5164 | *(u8 *) (pkt->data) = SDPCM_TEST_ECHORSP; | ||
5165 | if (brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, true) == 0) | ||
5166 | bus->pktgen_sent++; | ||
5167 | else { | ||
5168 | bus->pktgen_fail++; | ||
5169 | brcmu_pkt_buf_free_skb(pkt, false); | ||
5170 | } | ||
5171 | bus->pktgen_rcvd++; | ||
5172 | break; | ||
5173 | |||
5174 | case SDPCM_TEST_ECHORSP: | ||
5175 | if (bus->ext_loop) { | ||
5176 | brcmu_pkt_buf_free_skb(pkt, false); | ||
5177 | bus->pktgen_rcvd++; | ||
5178 | break; | ||
5179 | } | ||
5180 | |||
5181 | for (offset = 0; offset < len; offset++, data++) { | ||
5182 | if (*data != SDPCM_TEST_FILL(offset, extra)) { | ||
5183 | BRCMF_ERROR(("brcmf_sdbrcm_checkdied: echo" | ||
5184 | " data mismatch: " | ||
5185 | "offset %d (len %d) " | ||
5186 | "expect 0x%02x rcvd 0x%02x\n", | ||
5187 | offset, len, | ||
5188 | SDPCM_TEST_FILL(offset, extra), | ||
5189 | *data)); | ||
5190 | break; | ||
5191 | } | ||
5192 | } | ||
5193 | brcmu_pkt_buf_free_skb(pkt, false); | ||
5194 | bus->pktgen_rcvd++; | ||
5195 | break; | ||
5196 | |||
5197 | case SDPCM_TEST_DISCARD: | ||
5198 | brcmu_pkt_buf_free_skb(pkt, false); | ||
5199 | bus->pktgen_rcvd++; | ||
5200 | break; | ||
5201 | |||
5202 | case SDPCM_TEST_BURST: | ||
5203 | case SDPCM_TEST_SEND: | ||
5204 | default: | ||
5205 | BRCMF_INFO(("brcmf_sdbrcm_checkdied: unsupported or unknown " | ||
5206 | "command, pktlen %d seq %d" " cmd %d extra %d" | ||
5207 | " len %d\n", pktlen, seq, cmd, extra, len)); | ||
5208 | brcmu_pkt_buf_free_skb(pkt, false); | ||
5209 | break; | ||
5210 | } | ||
5211 | |||
5212 | /* For recv mode, stop at limie (and tell dongle to stop sending) */ | ||
5213 | if (bus->pktgen_mode == BRCMF_PKTGEN_RECV) { | ||
5214 | if (bus->pktgen_total | ||
5215 | && (bus->pktgen_rcvd >= bus->pktgen_total)) { | ||
5216 | bus->pktgen_count = 0; | ||
5217 | brcmf_sdbrcm_sdtest_set(bus, false); | ||
5218 | } | ||
5219 | } | ||
5220 | } | ||
5221 | #endif /* SDTEST */ | ||
5222 | |||
5223 | extern bool brcmf_sdbrcm_bus_watchdog(struct brcmf_pub *drvr) | ||
5224 | { | ||
5225 | struct brcmf_bus *bus; | ||
5226 | |||
5227 | BRCMF_TIMER(("%s: Enter\n", __func__)); | ||
5228 | |||
5229 | bus = drvr->bus; | ||
5230 | |||
5231 | if (bus->drvr->dongle_reset) | ||
5232 | return false; | ||
5233 | |||
5234 | /* Ignore the timer if simulating bus down */ | ||
5235 | if (bus->sleeping) | ||
5236 | return false; | ||
5237 | |||
5238 | brcmf_sdbrcm_sdlock(bus); | ||
5239 | |||
5240 | /* Poll period: check device if appropriate. */ | ||
5241 | if (bus->poll && (++bus->polltick >= bus->pollrate)) { | ||
5242 | u32 intstatus = 0; | ||
5243 | |||
5244 | /* Reset poll tick */ | ||
5245 | bus->polltick = 0; | ||
5246 | |||
5247 | /* Check device if no interrupts */ | ||
5248 | if (!bus->intr || (bus->intrcount == bus->lastintrs)) { | ||
5249 | |||
5250 | if (!bus->dpc_sched) { | ||
5251 | u8 devpend; | ||
5252 | devpend = brcmf_sdcard_cfg_read(bus->card, | ||
5253 | SDIO_FUNC_0, SDIO_CCCR_INTx, | ||
5254 | NULL); | ||
5255 | intstatus = | ||
5256 | devpend & (INTR_STATUS_FUNC1 | | ||
5257 | INTR_STATUS_FUNC2); | ||
5258 | } | ||
5259 | |||
5260 | /* If there is something, make like the ISR and | ||
5261 | schedule the DPC */ | ||
5262 | if (intstatus) { | ||
5263 | bus->pollcnt++; | ||
5264 | bus->ipend = true; | ||
5265 | if (bus->intr) | ||
5266 | brcmf_sdcard_intr_disable(bus->card); | ||
5267 | |||
5268 | bus->dpc_sched = true; | ||
5269 | brcmf_sdbrcm_sched_dpc(bus); | ||
5270 | |||
5271 | } | ||
5272 | } | ||
5273 | |||
5274 | /* Update interrupt tracking */ | ||
5275 | bus->lastintrs = bus->intrcount; | ||
5276 | } | ||
5277 | #ifdef BCMDBG | ||
5278 | /* Poll for console output periodically */ | ||
5279 | if (drvr->busstate == BRCMF_BUS_DATA && brcmf_console_ms != 0) { | ||
5280 | bus->console.count += brcmf_watchdog_ms; | ||
5281 | if (bus->console.count >= brcmf_console_ms) { | ||
5282 | bus->console.count -= brcmf_console_ms; | ||
5283 | /* Make sure backplane clock is on */ | ||
5284 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | ||
5285 | if (brcmf_sdbrcm_readconsole(bus) < 0) | ||
5286 | brcmf_console_ms = 0; /* On error, | ||
5287 | stop trying */ | ||
5288 | } | ||
5289 | } | ||
5290 | #endif /* BCMDBG */ | ||
5291 | |||
5292 | #ifdef SDTEST | ||
5293 | /* Generate packets if configured */ | ||
5294 | if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) { | ||
5295 | /* Make sure backplane clock is on */ | ||
5296 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | ||
5297 | bus->pktgen_tick = 0; | ||
5298 | brcmf_sdbrcm_pktgen(bus); | ||
5299 | } | ||
5300 | #endif | ||
5301 | |||
5302 | /* On idle timeout clear activity flag and/or turn off clock */ | ||
5303 | if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { | ||
5304 | if (++bus->idlecount >= bus->idletime) { | ||
5305 | bus->idlecount = 0; | ||
5306 | if (bus->activity) { | ||
5307 | bus->activity = false; | ||
5308 | brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms); | ||
5309 | } else { | ||
5310 | brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); | ||
5311 | } | ||
5312 | } | ||
5313 | } | ||
5314 | |||
5315 | brcmf_sdbrcm_sdunlock(bus); | ||
5316 | |||
5317 | return bus->ipend; | ||
5318 | } | ||
5319 | |||
5320 | #ifdef BCMDBG | ||
5321 | static int brcmf_sdbrcm_bus_console_in(struct brcmf_pub *drvr, | ||
5322 | unsigned char *msg, uint msglen) | ||
5323 | { | ||
5324 | struct brcmf_bus *bus = drvr->bus; | ||
5325 | u32 addr, val; | ||
5326 | int rv; | ||
5327 | struct sk_buff *pkt; | ||
5328 | |||
5329 | /* Address could be zero if CONSOLE := 0 in dongle Makefile */ | ||
5330 | if (bus->console_addr == 0) | ||
5331 | return -ENOTSUPP; | ||
5332 | |||
5333 | /* Exclusive bus access */ | ||
5334 | brcmf_sdbrcm_sdlock(bus); | ||
5335 | |||
5336 | /* Don't allow input if dongle is in reset */ | ||
5337 | if (bus->drvr->dongle_reset) { | ||
5338 | brcmf_sdbrcm_sdunlock(bus); | ||
5339 | return -EPERM; | ||
5340 | } | ||
5341 | |||
5342 | /* Request clock to allow SDIO accesses */ | ||
5343 | BUS_WAKE(bus); | ||
5344 | /* No pend allowed since txpkt is called later, ht clk has to be on */ | ||
5345 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | ||
5346 | |||
5347 | /* Zero cbuf_index */ | ||
5348 | addr = bus->console_addr + offsetof(struct rte_console, cbuf_idx); | ||
5349 | val = cpu_to_le32(0); | ||
5350 | rv = brcmf_sdbrcm_membytes(bus, true, addr, (u8 *)&val, sizeof(val)); | ||
5351 | if (rv < 0) | ||
5352 | goto done; | ||
5353 | |||
5354 | /* Write message into cbuf */ | ||
5355 | addr = bus->console_addr + offsetof(struct rte_console, cbuf); | ||
5356 | rv = brcmf_sdbrcm_membytes(bus, true, addr, (u8 *)msg, msglen); | ||
5357 | if (rv < 0) | ||
5358 | goto done; | ||
5359 | |||
5360 | /* Write length into vcons_in */ | ||
5361 | addr = bus->console_addr + offsetof(struct rte_console, vcons_in); | ||
5362 | val = cpu_to_le32(msglen); | ||
5363 | rv = brcmf_sdbrcm_membytes(bus, true, addr, (u8 *)&val, sizeof(val)); | ||
5364 | if (rv < 0) | ||
5365 | goto done; | ||
5366 | |||
5367 | /* Bump dongle by sending an empty event pkt. | ||
5368 | * sdpcm_sendup (RX) checks for virtual console input. | ||
5369 | */ | ||
5370 | pkt = brcmu_pkt_buf_get_skb(4 + SDPCM_RESERVE); | ||
5371 | if ((pkt != NULL) && bus->clkstate == CLK_AVAIL) | ||
5372 | brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, true); | ||
5373 | |||
5374 | done: | ||
5375 | if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && !bus->dpc_sched) { | ||
5376 | bus->activity = false; | ||
5377 | brcmf_sdbrcm_clkctl(bus, CLK_NONE, true); | ||
5378 | } | ||
5379 | |||
5380 | brcmf_sdbrcm_sdunlock(bus); | ||
5381 | |||
5382 | return rv; | ||
5383 | } | ||
5384 | #endif /* BCMDBG */ | ||
5385 | |||
5386 | static bool brcmf_sdbrcm_chipmatch(u16 chipid) | ||
5387 | { | ||
5388 | if (chipid == BCM4325_CHIP_ID) | ||
5389 | return true; | ||
5390 | if (chipid == BCM4329_CHIP_ID) | ||
5391 | return true; | ||
5392 | if (chipid == BCM4319_CHIP_ID) | ||
5393 | return true; | ||
5394 | return false; | ||
5395 | } | ||
5396 | |||
5397 | static void *brcmf_sdbrcm_probe(u16 venid, u16 devid, u16 bus_no, | ||
5398 | u16 slot, u16 func, uint bustype, u32 regsva, | ||
5399 | void *card) | ||
5400 | { | ||
5401 | int ret; | ||
5402 | struct brcmf_bus *bus; | ||
5403 | |||
5404 | /* Init global variables at run-time, not as part of the declaration. | ||
5405 | * This is required to support init/de-init of the driver. | ||
5406 | * Initialization | ||
5407 | * of globals as part of the declaration results in non-deterministic | ||
5408 | * behavior since the value of the globals may be different on the | ||
5409 | * first time that the driver is initialized vs subsequent | ||
5410 | * initializations. | ||
5411 | */ | ||
5412 | brcmf_txbound = BRCMF_TXBOUND; | ||
5413 | brcmf_rxbound = BRCMF_RXBOUND; | ||
5414 | brcmf_alignctl = true; | ||
5415 | sd1idle = true; | ||
5416 | brcmf_readahead = true; | ||
5417 | retrydata = false; | ||
5418 | brcmf_dongle_memsize = 0; | ||
5419 | brcmf_txminmax = BRCMF_TXMINMAX; | ||
5420 | |||
5421 | forcealign = true; | ||
5422 | |||
5423 | brcmf_c_init(); | ||
5424 | |||
5425 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
5426 | BRCMF_INFO(("%s: venid 0x%04x devid 0x%04x\n", __func__, venid, devid)); | ||
5427 | |||
5428 | /* We make an assumption about address window mappings: | ||
5429 | * regsva == SI_ENUM_BASE*/ | ||
5430 | |||
5431 | /* SDIO car passes venid and devid based on CIS parsing -- but | ||
5432 | * low-power start | ||
5433 | * means early parse could fail, so here we should get either an ID | ||
5434 | * we recognize OR (-1) indicating we must request power first. | ||
5435 | */ | ||
5436 | /* Check the Vendor ID */ | ||
5437 | switch (venid) { | ||
5438 | case 0x0000: | ||
5439 | case PCI_VENDOR_ID_BROADCOM: | ||
5440 | break; | ||
5441 | default: | ||
5442 | BRCMF_ERROR(("%s: unknown vendor: 0x%04x\n", __func__, venid)); | ||
5443 | return NULL; | ||
5444 | } | ||
5445 | |||
5446 | /* Check the Device ID and make sure it's one that we support */ | ||
5447 | switch (devid) { | ||
5448 | case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */ | ||
5449 | case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */ | ||
5450 | case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */ | ||
5451 | BRCMF_INFO(("%s: found 4325 Dongle\n", __func__)); | ||
5452 | break; | ||
5453 | case BCM4329_D11NDUAL_ID: /* 4329 802.11n dualband device */ | ||
5454 | case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */ | ||
5455 | case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */ | ||
5456 | case 0x4329: | ||
5457 | BRCMF_INFO(("%s: found 4329 Dongle\n", __func__)); | ||
5458 | break; | ||
5459 | case BCM4319_D11N_ID: /* 4319 802.11n id */ | ||
5460 | case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */ | ||
5461 | case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */ | ||
5462 | BRCMF_INFO(("%s: found 4319 Dongle\n", __func__)); | ||
5463 | break; | ||
5464 | case 0: | ||
5465 | BRCMF_INFO(("%s: allow device id 0, will check chip" | ||
5466 | " internals\n", __func__)); | ||
5467 | break; | ||
5468 | |||
5469 | default: | ||
5470 | BRCMF_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n", | ||
5471 | __func__, venid, devid)); | ||
5472 | return NULL; | ||
5473 | } | ||
5474 | |||
5475 | /* Allocate private bus interface state */ | ||
5476 | bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC); | ||
5477 | if (!bus) { | ||
5478 | BRCMF_ERROR(("%s: kmalloc of struct dhd_bus failed\n", | ||
5479 | __func__)); | ||
5480 | goto fail; | ||
5481 | } | ||
5482 | bus->card = card; | ||
5483 | bus->cl_devid = (u16) devid; | ||
5484 | bus->bus = BRCMF_BUS; | ||
5485 | bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; | ||
5486 | bus->usebufpool = false; /* Use bufpool if allocated, | ||
5487 | else use locally malloced rxbuf */ | ||
5488 | |||
5489 | /* attempt to attach to the dongle */ | ||
5490 | if (!(brcmf_sdbrcm_probe_attach(bus, card, regsva, devid))) { | ||
5491 | BRCMF_ERROR(("%s: brcmf_sdbrcm_probe_attach failed\n", | ||
5492 | __func__)); | ||
5493 | goto fail; | ||
5494 | } | ||
5495 | |||
5496 | spin_lock_init(&bus->txqlock); | ||
5497 | init_waitqueue_head(&bus->ctrl_wait); | ||
5498 | |||
5499 | /* Set up the watchdog timer */ | ||
5500 | init_timer(&bus->timer); | ||
5501 | bus->timer.data = (unsigned long)bus; | ||
5502 | bus->timer.function = brcmf_sdbrcm_watchdog; | ||
5503 | |||
5504 | /* Initialize thread based operation and lock */ | ||
5505 | if ((brcmf_watchdog_prio >= 0) && (brcmf_dpc_prio >= 0)) { | ||
5506 | bus->threads_only = true; | ||
5507 | sema_init(&bus->sdsem, 1); | ||
5508 | } else { | ||
5509 | bus->threads_only = false; | ||
5510 | spin_lock_init(&bus->sdlock); | ||
5511 | } | ||
5512 | |||
5513 | if (brcmf_dpc_prio >= 0) { | ||
5514 | /* Initialize watchdog thread */ | ||
5515 | init_completion(&bus->watchdog_wait); | ||
5516 | bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread, | ||
5517 | bus, "brcmf_watchdog"); | ||
5518 | if (IS_ERR(bus->watchdog_tsk)) { | ||
5519 | printk(KERN_WARNING | ||
5520 | "brcmf_watchdog thread failed to start\n"); | ||
5521 | bus->watchdog_tsk = NULL; | ||
5522 | } | ||
5523 | } else | ||
5524 | bus->watchdog_tsk = NULL; | ||
5525 | |||
5526 | /* Set up the bottom half handler */ | ||
5527 | if (brcmf_dpc_prio >= 0) { | ||
5528 | /* Initialize DPC thread */ | ||
5529 | init_completion(&bus->dpc_wait); | ||
5530 | bus->dpc_tsk = kthread_run(brcmf_sdbrcm_dpc_thread, | ||
5531 | bus, "brcmf_dpc"); | ||
5532 | if (IS_ERR(bus->dpc_tsk)) { | ||
5533 | printk(KERN_WARNING | ||
5534 | "brcmf_dpc thread failed to start\n"); | ||
5535 | bus->dpc_tsk = NULL; | ||
5536 | } | ||
5537 | } else { | ||
5538 | tasklet_init(&bus->tasklet, brcmf_sdbrcm_dpc_tasklet, | ||
5539 | (unsigned long)bus); | ||
5540 | bus->dpc_tsk = NULL; | ||
5541 | } | ||
5542 | |||
5543 | /* Attach to the brcmf/OS/network interface */ | ||
5544 | bus->drvr = brcmf_attach(bus, SDPCM_RESERVE); | ||
5545 | if (!bus->drvr) { | ||
5546 | BRCMF_ERROR(("%s: brcmf_attach failed\n", __func__)); | ||
5547 | goto fail; | ||
5548 | } | ||
5549 | |||
5550 | /* Allocate buffers */ | ||
5551 | if (!(brcmf_sdbrcm_probe_malloc(bus, card))) { | ||
5552 | BRCMF_ERROR(("%s: brcmf_sdbrcm_probe_malloc failed\n", | ||
5553 | __func__)); | ||
5554 | goto fail; | ||
5555 | } | ||
5556 | |||
5557 | if (!(brcmf_sdbrcm_probe_init(bus, card))) { | ||
5558 | BRCMF_ERROR(("%s: brcmf_sdbrcm_probe_init failed\n", __func__)); | ||
5559 | goto fail; | ||
5560 | } | ||
5561 | |||
5562 | /* Register interrupt callback, but mask it (not operational yet). */ | ||
5563 | BRCMF_INTR(("%s: disable SDIO interrupts (not interested yet)\n", | ||
5564 | __func__)); | ||
5565 | brcmf_sdcard_intr_disable(card); | ||
5566 | ret = brcmf_sdcard_intr_reg(card, brcmf_sdbrcm_isr, bus); | ||
5567 | if (ret != 0) { | ||
5568 | BRCMF_ERROR(("%s: FAILED: sdcard_intr_reg returned %d\n", | ||
5569 | __func__, ret)); | ||
5570 | goto fail; | ||
5571 | } | ||
5572 | BRCMF_INTR(("%s: registered SDIO interrupt function ok\n", __func__)); | ||
5573 | |||
5574 | BRCMF_INFO(("%s: completed!!\n", __func__)); | ||
5575 | |||
5576 | /* if firmware path present try to download and bring up bus */ | ||
5577 | ret = brcmf_bus_start(bus->drvr); | ||
5578 | if (ret != 0) { | ||
5579 | if (ret == -ENOLINK) { | ||
5580 | BRCMF_ERROR(("%s: dongle is not responding\n", | ||
5581 | __func__)); | ||
5582 | goto fail; | ||
5583 | } | ||
5584 | } | ||
5585 | /* Ok, have the per-port tell the stack we're open for business */ | ||
5586 | if (brcmf_net_attach(bus->drvr, 0) != 0) { | ||
5587 | BRCMF_ERROR(("%s: Net attach failed!!\n", __func__)); | ||
5588 | goto fail; | ||
5589 | } | ||
5590 | |||
5591 | return bus; | ||
5592 | |||
5593 | fail: | ||
5594 | brcmf_sdbrcm_release(bus); | ||
5595 | return NULL; | ||
5596 | } | ||
5597 | |||
5598 | static bool | ||
5599 | brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, void *card, u32 regsva, | ||
5600 | u16 devid) | ||
5601 | { | ||
5602 | u8 clkctl = 0; | ||
5603 | int err = 0; | ||
5604 | |||
5605 | bus->alp_only = true; | ||
5606 | |||
5607 | /* Return the window to backplane enumeration space for core access */ | ||
5608 | if (brcmf_sdbrcm_set_siaddr_window(bus, SI_ENUM_BASE)) | ||
5609 | BRCMF_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", | ||
5610 | __func__)); | ||
5611 | |||
5612 | #ifdef BCMDBG | ||
5613 | printk(KERN_DEBUG "F1 signature read @0x18000000=0x%4x\n", | ||
5614 | brcmf_sdcard_reg_read(bus->card, SI_ENUM_BASE, 4)); | ||
5615 | |||
5616 | #endif /* BCMDBG */ | ||
5617 | |||
5618 | /* | ||
5619 | * Force PLL off until brcmf_sdbrcm_chip_attach() | ||
5620 | * programs PLL control regs | ||
5621 | */ | ||
5622 | |||
5623 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, | ||
5624 | BRCMF_INIT_CLKCTL1, &err); | ||
5625 | if (!err) | ||
5626 | clkctl = | ||
5627 | brcmf_sdcard_cfg_read(card, SDIO_FUNC_1, | ||
5628 | SBSDIO_FUNC1_CHIPCLKCSR, &err); | ||
5629 | |||
5630 | if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) { | ||
5631 | BRCMF_ERROR(("brcmf_sdbrcm_probe: ChipClkCSR access: err %d" | ||
5632 | " wrote 0x%02x read 0x%02x\n", | ||
5633 | err, BRCMF_INIT_CLKCTL1, clkctl)); | ||
5634 | goto fail; | ||
5635 | } | ||
5636 | |||
5637 | if (brcmf_sdbrcm_chip_attach(bus, regsva)) { | ||
5638 | BRCMF_ERROR(("%s: brcmf_sdbrcm_chip_attach failed!\n", | ||
5639 | __func__)); | ||
5640 | goto fail; | ||
5641 | } | ||
5642 | |||
5643 | if (!brcmf_sdbrcm_chipmatch((u16) bus->ci->chip)) { | ||
5644 | BRCMF_ERROR(("%s: unsupported chip: 0x%04x\n", | ||
5645 | __func__, bus->ci->chip)); | ||
5646 | goto fail; | ||
5647 | } | ||
5648 | |||
5649 | brcmf_sdbrcm_sdiod_drive_strength_init(bus, brcmf_sdiod_drive_strength); | ||
5650 | |||
5651 | /* Get info on the ARM and SOCRAM cores... */ | ||
5652 | if (!BRCMF_NOPMU(bus)) { | ||
5653 | brcmf_sdcard_reg_read(bus->card, | ||
5654 | CORE_SB(bus->ci->armcorebase, sbidhigh), 4); | ||
5655 | bus->orig_ramsize = bus->ci->ramsize; | ||
5656 | if (!(bus->orig_ramsize)) { | ||
5657 | BRCMF_ERROR(("%s: failed to find SOCRAM memory!\n", | ||
5658 | __func__)); | ||
5659 | goto fail; | ||
5660 | } | ||
5661 | bus->ramsize = bus->orig_ramsize; | ||
5662 | if (brcmf_dongle_memsize) | ||
5663 | brcmf_sdbrcm_setmemsize(bus, brcmf_dongle_memsize); | ||
5664 | |||
5665 | BRCMF_ERROR(("DHD: dongle ram size is set to %d(orig %d)\n", | ||
5666 | bus->ramsize, bus->orig_ramsize)); | ||
5667 | } | ||
5668 | |||
5669 | /* Set core control so an SDIO reset does a backplane reset */ | ||
5670 | OR_REG(bus->ci->buscorebase + offsetof(struct sdpcmd_regs, | ||
5671 | corecontrol), | ||
5672 | CC_BPRESEN, u32); | ||
5673 | |||
5674 | brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN); | ||
5675 | |||
5676 | /* Locate an appropriately-aligned portion of hdrbuf */ | ||
5677 | bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0], | ||
5678 | BRCMF_SDALIGN); | ||
5679 | |||
5680 | /* Set the poll and/or interrupt flags */ | ||
5681 | bus->intr = (bool) brcmf_intr; | ||
5682 | bus->poll = (bool) brcmf_poll; | ||
5683 | if (bus->poll) | ||
5684 | bus->pollrate = 1; | ||
5685 | |||
5686 | return true; | ||
5687 | |||
5688 | fail: | ||
5689 | return false; | ||
5690 | } | ||
5691 | |||
5692 | static bool brcmf_sdbrcm_probe_malloc(struct brcmf_bus *bus, void *card) | ||
5693 | { | ||
5694 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
5695 | |||
5696 | if (bus->drvr->maxctl) { | ||
5697 | bus->rxblen = | ||
5698 | roundup((bus->drvr->maxctl + SDPCM_HDRLEN), | ||
5699 | ALIGNMENT) + BRCMF_SDALIGN; | ||
5700 | bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC); | ||
5701 | if (!(bus->rxbuf)) { | ||
5702 | BRCMF_ERROR(("%s: kmalloc of %d-byte rxbuf failed\n", | ||
5703 | __func__, bus->rxblen)); | ||
5704 | goto fail; | ||
5705 | } | ||
5706 | } | ||
5707 | |||
5708 | /* Allocate buffer to receive glomed packet */ | ||
5709 | bus->databuf = kmalloc(MAX_DATA_BUF, GFP_ATOMIC); | ||
5710 | if (!(bus->databuf)) { | ||
5711 | BRCMF_ERROR(("%s: kmalloc of %d-byte databuf failed\n", | ||
5712 | __func__, MAX_DATA_BUF)); | ||
5713 | /* release rxbuf which was already located as above */ | ||
5714 | if (!bus->rxblen) | ||
5715 | kfree(bus->rxbuf); | ||
5716 | goto fail; | ||
5717 | } | ||
5718 | |||
5719 | /* Align the buffer */ | ||
5720 | if ((unsigned long)bus->databuf % BRCMF_SDALIGN) | ||
5721 | bus->dataptr = bus->databuf + (BRCMF_SDALIGN - | ||
5722 | ((unsigned long)bus->databuf % BRCMF_SDALIGN)); | ||
5723 | else | ||
5724 | bus->dataptr = bus->databuf; | ||
5725 | |||
5726 | return true; | ||
5727 | |||
5728 | fail: | ||
5729 | return false; | ||
5730 | } | ||
5731 | |||
5732 | static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus, void *card) | ||
5733 | { | ||
5734 | s32 fnum; | ||
5735 | |||
5736 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
5737 | |||
5738 | #ifdef SDTEST | ||
5739 | brcmf_sdbrcm_pktgen_init(bus); | ||
5740 | #endif /* SDTEST */ | ||
5741 | |||
5742 | /* Disable F2 to clear any intermediate frame state on the dongle */ | ||
5743 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_0, SDIO_CCCR_IOEx, | ||
5744 | SDIO_FUNC_ENABLE_1, NULL); | ||
5745 | |||
5746 | bus->drvr->busstate = BRCMF_BUS_DOWN; | ||
5747 | bus->sleeping = false; | ||
5748 | bus->rxflow = false; | ||
5749 | |||
5750 | /* Done with backplane-dependent accesses, can drop clock... */ | ||
5751 | brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, | ||
5752 | NULL); | ||
5753 | |||
5754 | /* ...and initialize clock/power states */ | ||
5755 | bus->clkstate = CLK_SDONLY; | ||
5756 | bus->idletime = (s32) brcmf_idletime; | ||
5757 | bus->idleclock = BRCMF_IDLE_ACTIVE; | ||
5758 | |||
5759 | /* Query the F2 block size, set roundup accordingly */ | ||
5760 | fnum = 2; | ||
5761 | if (brcmf_sdcard_iovar_op(card, "sd_blocksize", &fnum, sizeof(s32), | ||
5762 | &bus->blocksize, sizeof(s32), false) != 0) { | ||
5763 | bus->blocksize = 0; | ||
5764 | BRCMF_ERROR(("%s: fail on %s get\n", __func__, "sd_blocksize")); | ||
5765 | } else { | ||
5766 | BRCMF_INFO(("%s: Initial value for %s is %d\n", | ||
5767 | __func__, "sd_blocksize", bus->blocksize)); | ||
5768 | } | ||
5769 | bus->roundup = min(max_roundup, bus->blocksize); | ||
5770 | |||
5771 | /* Query if bus module supports packet chaining, | ||
5772 | default to use if supported */ | ||
5773 | if (brcmf_sdcard_iovar_op(card, "sd_rxchain", NULL, 0, | ||
5774 | &bus->sd_rxchain, sizeof(s32), | ||
5775 | false) != 0) { | ||
5776 | bus->sd_rxchain = false; | ||
5777 | } else { | ||
5778 | BRCMF_INFO(("%s: bus module (through sdiocard API) %s" | ||
5779 | " chaining\n", __func__, bus->sd_rxchain | ||
5780 | ? "supports" : "does not support")); | ||
5781 | } | ||
5782 | bus->use_rxchain = (bool) bus->sd_rxchain; | ||
5783 | |||
5784 | return true; | ||
5785 | } | ||
5786 | |||
5787 | static bool | ||
5788 | brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus, void *card) | ||
5789 | { | ||
5790 | bool ret; | ||
5791 | |||
5792 | /* Download the firmware */ | ||
5793 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | ||
5794 | |||
5795 | ret = _brcmf_sdbrcm_download_firmware(bus) == 0; | ||
5796 | |||
5797 | brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); | ||
5798 | |||
5799 | return ret; | ||
5800 | } | ||
5801 | |||
5802 | /* Detach and free everything */ | ||
5803 | static void brcmf_sdbrcm_release(struct brcmf_bus *bus) | ||
5804 | { | ||
5805 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
5806 | |||
5807 | if (bus) { | ||
5808 | /* De-register interrupt handler */ | ||
5809 | brcmf_sdcard_intr_disable(bus->card); | ||
5810 | brcmf_sdcard_intr_dereg(bus->card); | ||
5811 | |||
5812 | if (bus->drvr) { | ||
5813 | brcmf_detach(bus->drvr); | ||
5814 | brcmf_sdbrcm_release_dongle(bus); | ||
5815 | bus->drvr = NULL; | ||
5816 | } | ||
5817 | |||
5818 | brcmf_sdbrcm_release_malloc(bus); | ||
5819 | |||
5820 | kfree(bus); | ||
5821 | } | ||
5822 | |||
5823 | BRCMF_TRACE(("%s: Disconnected\n", __func__)); | ||
5824 | } | ||
5825 | |||
5826 | static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus) | ||
5827 | { | ||
5828 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
5829 | |||
5830 | if (bus->drvr && bus->drvr->dongle_reset) | ||
5831 | return; | ||
5832 | |||
5833 | kfree(bus->rxbuf); | ||
5834 | bus->rxctl = bus->rxbuf = NULL; | ||
5835 | bus->rxlen = 0; | ||
5836 | |||
5837 | kfree(bus->databuf); | ||
5838 | bus->databuf = NULL; | ||
5839 | } | ||
5840 | |||
5841 | static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus) | ||
5842 | { | ||
5843 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
5844 | |||
5845 | if (bus->drvr && bus->drvr->dongle_reset) | ||
5846 | return; | ||
5847 | |||
5848 | if (bus->ci) { | ||
5849 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | ||
5850 | brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); | ||
5851 | brcmf_sdbrcm_chip_detach(bus); | ||
5852 | if (bus->vars && bus->varsz) | ||
5853 | kfree(bus->vars); | ||
5854 | bus->vars = NULL; | ||
5855 | } | ||
5856 | |||
5857 | BRCMF_TRACE(("%s: Disconnected\n", __func__)); | ||
5858 | } | ||
5859 | |||
5860 | static void brcmf_sdbrcm_disconnect(void *ptr) | ||
5861 | { | ||
5862 | struct brcmf_bus *bus = (struct brcmf_bus *)ptr; | ||
5863 | |||
5864 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
5865 | |||
5866 | if (bus) { | ||
5867 | brcmf_sdbrcm_release(bus); | ||
5868 | } | ||
5869 | |||
5870 | BRCMF_TRACE(("%s: Disconnected\n", __func__)); | ||
5871 | } | ||
5872 | |||
5873 | /* Register/Unregister functions are called by the main DHD entry | ||
5874 | * point (e.g. module insertion) to link with the bus driver, in | ||
5875 | * order to look for or await the device. | ||
5876 | */ | ||
5877 | |||
5878 | static struct brcmf_sdioh_driver brcmf_sdio = { | ||
5879 | brcmf_sdbrcm_probe, | ||
5880 | brcmf_sdbrcm_disconnect | ||
5881 | }; | ||
5882 | |||
5883 | int brcmf_bus_register(void) | ||
5884 | { | ||
5885 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
5886 | |||
5887 | /* Sanity check on the module parameters */ | ||
5888 | do { | ||
5889 | /* Both watchdog and DPC as tasklets are ok */ | ||
5890 | if ((brcmf_watchdog_prio < 0) && (brcmf_dpc_prio < 0)) | ||
5891 | break; | ||
5892 | |||
5893 | /* If both watchdog and DPC are threads, TX must be deferred */ | ||
5894 | if ((brcmf_watchdog_prio >= 0) && (brcmf_dpc_prio >= 0) | ||
5895 | && brcmf_deferred_tx) | ||
5896 | break; | ||
5897 | |||
5898 | BRCMF_ERROR(("Invalid module parameters.\n")); | ||
5899 | return -EINVAL; | ||
5900 | } while (0); | ||
5901 | |||
5902 | return brcmf_sdio_register(&brcmf_sdio); | ||
5903 | } | ||
5904 | |||
5905 | void brcmf_bus_unregister(void) | ||
5906 | { | ||
5907 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
5908 | |||
5909 | brcmf_sdio_unregister(); | ||
5910 | } | ||
5911 | |||
5912 | static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus) | ||
5913 | { | ||
5914 | int offset = 0; | ||
5915 | uint len; | ||
5916 | u8 *memblock = NULL, *memptr; | ||
5917 | int ret; | ||
5918 | |||
5919 | BRCMF_INFO(("%s: Enter\n", __func__)); | ||
5920 | |||
5921 | bus->fw_name = BCM4329_FW_NAME; | ||
5922 | ret = request_firmware(&bus->firmware, bus->fw_name, | ||
5923 | &gInstance->func[2]->dev); | ||
5924 | if (ret) { | ||
5925 | BRCMF_ERROR(("%s: Fail to request firmware %d\n", | ||
5926 | __func__, ret)); | ||
5927 | return ret; | ||
5928 | } | ||
5929 | bus->fw_ptr = 0; | ||
5930 | |||
5931 | memptr = memblock = kmalloc(MEMBLOCK + BRCMF_SDALIGN, GFP_ATOMIC); | ||
5932 | if (memblock == NULL) { | ||
5933 | BRCMF_ERROR(("%s: Failed to allocate memory %d bytes\n", | ||
5934 | __func__, MEMBLOCK)); | ||
5935 | ret = -ENOMEM; | ||
5936 | goto err; | ||
5937 | } | ||
5938 | if ((u32)(unsigned long)memblock % BRCMF_SDALIGN) | ||
5939 | memptr += (BRCMF_SDALIGN - | ||
5940 | ((u32)(unsigned long)memblock % BRCMF_SDALIGN)); | ||
5941 | |||
5942 | /* Download image */ | ||
5943 | while ((len = | ||
5944 | brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus))) { | ||
5945 | ret = brcmf_sdbrcm_membytes(bus, true, offset, memptr, len); | ||
5946 | if (ret) { | ||
5947 | BRCMF_ERROR(("%s: error %d on writing %d membytes at " | ||
5948 | "0x%08x\n", __func__, ret, MEMBLOCK, | ||
5949 | offset)); | ||
5950 | goto err; | ||
5951 | } | ||
5952 | |||
5953 | offset += MEMBLOCK; | ||
5954 | } | ||
5955 | |||
5956 | err: | ||
5957 | kfree(memblock); | ||
5958 | |||
5959 | release_firmware(bus->firmware); | ||
5960 | bus->fw_ptr = 0; | ||
5961 | |||
5962 | return ret; | ||
5963 | } | ||
5964 | |||
5965 | /* | ||
5966 | * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file | ||
5967 | * and ending in a NUL. | ||
5968 | * Removes carriage returns, empty lines, comment lines, and converts | ||
5969 | * newlines to NULs. | ||
5970 | * Shortens buffer as needed and pads with NULs. End of buffer is marked | ||
5971 | * by two NULs. | ||
5972 | */ | ||
5973 | |||
5974 | static uint brcmf_process_nvram_vars(char *varbuf, uint len) | ||
5975 | { | ||
5976 | char *dp; | ||
5977 | bool findNewline; | ||
5978 | int column; | ||
5979 | uint buf_len, n; | ||
5980 | |||
5981 | dp = varbuf; | ||
5982 | |||
5983 | findNewline = false; | ||
5984 | column = 0; | ||
5985 | |||
5986 | for (n = 0; n < len; n++) { | ||
5987 | if (varbuf[n] == 0) | ||
5988 | break; | ||
5989 | if (varbuf[n] == '\r') | ||
5990 | continue; | ||
5991 | if (findNewline && varbuf[n] != '\n') | ||
5992 | continue; | ||
5993 | findNewline = false; | ||
5994 | if (varbuf[n] == '#') { | ||
5995 | findNewline = true; | ||
5996 | continue; | ||
5997 | } | ||
5998 | if (varbuf[n] == '\n') { | ||
5999 | if (column == 0) | ||
6000 | continue; | ||
6001 | *dp++ = 0; | ||
6002 | column = 0; | ||
6003 | continue; | ||
6004 | } | ||
6005 | *dp++ = varbuf[n]; | ||
6006 | column++; | ||
6007 | } | ||
6008 | buf_len = dp - varbuf; | ||
6009 | |||
6010 | while (dp < varbuf + n) | ||
6011 | *dp++ = 0; | ||
6012 | |||
6013 | return buf_len; | ||
6014 | } | ||
6015 | |||
6016 | static int brcmf_sdbrcm_download_nvram(struct brcmf_bus *bus) | ||
6017 | { | ||
6018 | uint len; | ||
6019 | char *memblock = NULL; | ||
6020 | char *bufp; | ||
6021 | int ret; | ||
6022 | |||
6023 | bus->nv_name = BCM4329_NV_NAME; | ||
6024 | ret = request_firmware(&bus->firmware, bus->nv_name, | ||
6025 | &gInstance->func[2]->dev); | ||
6026 | if (ret) { | ||
6027 | BRCMF_ERROR(("%s: Fail to request nvram %d\n", __func__, ret)); | ||
6028 | return ret; | ||
6029 | } | ||
6030 | bus->fw_ptr = 0; | ||
6031 | |||
6032 | memblock = kmalloc(MEMBLOCK, GFP_ATOMIC); | ||
6033 | if (memblock == NULL) { | ||
6034 | BRCMF_ERROR(("%s: Failed to allocate memory %d bytes\n", | ||
6035 | __func__, MEMBLOCK)); | ||
6036 | ret = -ENOMEM; | ||
6037 | goto err; | ||
6038 | } | ||
6039 | |||
6040 | len = brcmf_sdbrcm_get_image(memblock, MEMBLOCK, bus); | ||
6041 | |||
6042 | if (len > 0 && len < MEMBLOCK) { | ||
6043 | bufp = (char *)memblock; | ||
6044 | bufp[len] = 0; | ||
6045 | len = brcmf_process_nvram_vars(bufp, len); | ||
6046 | bufp += len; | ||
6047 | *bufp++ = 0; | ||
6048 | if (len) | ||
6049 | ret = brcmf_sdbrcm_downloadvars(bus, memblock, len + 1); | ||
6050 | if (ret) | ||
6051 | BRCMF_ERROR(("%s: error downloading vars: %d\n", | ||
6052 | __func__, ret)); | ||
6053 | } else { | ||
6054 | BRCMF_ERROR(("%s: error reading nvram file: %d\n", | ||
6055 | __func__, len)); | ||
6056 | ret = -EIO; | ||
6057 | } | ||
6058 | |||
6059 | err: | ||
6060 | kfree(memblock); | ||
6061 | |||
6062 | release_firmware(bus->firmware); | ||
6063 | bus->fw_ptr = 0; | ||
6064 | |||
6065 | return ret; | ||
6066 | } | ||
6067 | |||
6068 | static int _brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus) | ||
6069 | { | ||
6070 | int bcmerror = -1; | ||
6071 | |||
6072 | /* Keep arm in reset */ | ||
6073 | if (brcmf_sdbrcm_download_state(bus, true)) { | ||
6074 | BRCMF_ERROR(("%s: error placing ARM core in reset\n", | ||
6075 | __func__)); | ||
6076 | goto err; | ||
6077 | } | ||
6078 | |||
6079 | /* External image takes precedence if specified */ | ||
6080 | if (brcmf_sdbrcm_download_code_file(bus)) { | ||
6081 | BRCMF_ERROR(("%s: dongle image file download failed\n", | ||
6082 | __func__)); | ||
6083 | goto err; | ||
6084 | } | ||
6085 | |||
6086 | /* External nvram takes precedence if specified */ | ||
6087 | if (brcmf_sdbrcm_download_nvram(bus)) { | ||
6088 | BRCMF_ERROR(("%s: dongle nvram file download failed\n", | ||
6089 | __func__)); | ||
6090 | } | ||
6091 | |||
6092 | /* Take arm out of reset */ | ||
6093 | if (brcmf_sdbrcm_download_state(bus, false)) { | ||
6094 | BRCMF_ERROR(("%s: error getting out of ARM core reset\n", | ||
6095 | __func__)); | ||
6096 | goto err; | ||
6097 | } | ||
6098 | |||
6099 | bcmerror = 0; | ||
6100 | |||
6101 | err: | ||
6102 | return bcmerror; | ||
6103 | } | ||
6104 | |||
6105 | |||
6106 | static int | ||
6107 | brcmf_sdbrcm_send_buf(struct brcmf_bus *bus, u32 addr, uint fn, uint flags, | ||
6108 | u8 *buf, uint nbytes, struct sk_buff *pkt, | ||
6109 | void (*complete)(void *handle, int status, | ||
6110 | bool sync_waiting), | ||
6111 | void *handle) | ||
6112 | { | ||
6113 | return brcmf_sdcard_send_buf | ||
6114 | (bus->card, addr, fn, flags, buf, nbytes, pkt, complete, | ||
6115 | handle); | ||
6116 | } | ||
6117 | |||
6118 | int brcmf_bus_devreset(struct brcmf_pub *drvr, u8 flag) | ||
6119 | { | ||
6120 | int bcmerror = 0; | ||
6121 | struct brcmf_bus *bus; | ||
6122 | |||
6123 | bus = drvr->bus; | ||
6124 | |||
6125 | if (flag == true) { | ||
6126 | brcmf_sdbrcm_wd_timer(bus, 0); | ||
6127 | if (!bus->drvr->dongle_reset) { | ||
6128 | /* Expect app to have torn down any | ||
6129 | connection before calling */ | ||
6130 | /* Stop the bus, disable F2 */ | ||
6131 | brcmf_sdbrcm_bus_stop(bus, false); | ||
6132 | |||
6133 | /* Clean tx/rx buffer pointers, | ||
6134 | detach from the dongle */ | ||
6135 | brcmf_sdbrcm_release_dongle(bus); | ||
6136 | |||
6137 | bus->drvr->dongle_reset = true; | ||
6138 | bus->drvr->up = false; | ||
6139 | |||
6140 | BRCMF_TRACE(("%s: WLAN OFF DONE\n", __func__)); | ||
6141 | /* App can now remove power from device */ | ||
6142 | } else | ||
6143 | bcmerror = -EIO; | ||
6144 | } else { | ||
6145 | /* App must have restored power to device before calling */ | ||
6146 | |||
6147 | BRCMF_TRACE(("\n\n%s: == WLAN ON ==\n", __func__)); | ||
6148 | |||
6149 | if (bus->drvr->dongle_reset) { | ||
6150 | /* Turn on WLAN */ | ||
6151 | |||
6152 | /* Attempt to re-attach & download */ | ||
6153 | if (brcmf_sdbrcm_probe_attach(bus, bus->card, | ||
6154 | SI_ENUM_BASE, | ||
6155 | bus->cl_devid)) { | ||
6156 | /* Attempt to download binary to the dongle */ | ||
6157 | if (brcmf_sdbrcm_probe_init(bus, bus->card)) { | ||
6158 | /* Re-init bus, enable F2 transfer */ | ||
6159 | brcmf_sdbrcm_bus_init(bus->drvr, false); | ||
6160 | |||
6161 | bus->drvr->dongle_reset = false; | ||
6162 | bus->drvr->up = true; | ||
6163 | |||
6164 | BRCMF_TRACE(("%s: WLAN ON DONE\n", | ||
6165 | __func__)); | ||
6166 | } else | ||
6167 | bcmerror = -EIO; | ||
6168 | } else | ||
6169 | bcmerror = -EIO; | ||
6170 | } else { | ||
6171 | bcmerror = -EISCONN; | ||
6172 | BRCMF_ERROR(("%s: Set DEVRESET=false invoked when" | ||
6173 | " device is on\n", __func__)); | ||
6174 | bcmerror = -EIO; | ||
6175 | } | ||
6176 | brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms); | ||
6177 | } | ||
6178 | return bcmerror; | ||
6179 | } | ||
6180 | |||
6181 | static int | ||
6182 | brcmf_sdbrcm_chip_recognition(struct brcmf_sdio_card *card, | ||
6183 | struct chip_info *ci, u32 regs) | ||
6184 | { | ||
6185 | u32 regdata; | ||
6186 | |||
6187 | /* | ||
6188 | * Get CC core rev | ||
6189 | * Chipid is assume to be at offset 0 from regs arg | ||
6190 | * For different chiptypes or old sdio hosts w/o chipcommon, | ||
6191 | * other ways of recognition should be added here. | ||
6192 | */ | ||
6193 | ci->cccorebase = regs; | ||
6194 | regdata = brcmf_sdcard_reg_read(card, | ||
6195 | CORE_CC_REG(ci->cccorebase, chipid), 4); | ||
6196 | ci->chip = regdata & CID_ID_MASK; | ||
6197 | ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT; | ||
6198 | |||
6199 | BRCMF_INFO(("%s: chipid=0x%x chiprev=%d\n", | ||
6200 | __func__, ci->chip, ci->chiprev)); | ||
6201 | |||
6202 | /* Address of cores for new chips should be added here */ | ||
6203 | switch (ci->chip) { | ||
6204 | case BCM4329_CHIP_ID: | ||
6205 | ci->buscorebase = BCM4329_CORE_BUS_BASE; | ||
6206 | ci->ramcorebase = BCM4329_CORE_SOCRAM_BASE; | ||
6207 | ci->armcorebase = BCM4329_CORE_ARM_BASE; | ||
6208 | ci->ramsize = BCM4329_RAMSIZE; | ||
6209 | break; | ||
6210 | default: | ||
6211 | BRCMF_ERROR(("%s: chipid 0x%x is not supported\n", | ||
6212 | __func__, ci->chip)); | ||
6213 | return -ENODEV; | ||
6214 | } | ||
6215 | |||
6216 | regdata = brcmf_sdcard_reg_read(card, | ||
6217 | CORE_SB(ci->cccorebase, sbidhigh), 4); | ||
6218 | ci->ccrev = SBCOREREV(regdata); | ||
6219 | |||
6220 | regdata = brcmf_sdcard_reg_read(card, | ||
6221 | CORE_CC_REG(ci->cccorebase, pmucapabilities), 4); | ||
6222 | ci->pmurev = regdata & PCAP_REV_MASK; | ||
6223 | |||
6224 | regdata = brcmf_sdcard_reg_read(card, | ||
6225 | CORE_SB(ci->buscorebase, sbidhigh), 4); | ||
6226 | ci->buscorerev = SBCOREREV(regdata); | ||
6227 | ci->buscoretype = (regdata & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT; | ||
6228 | |||
6229 | BRCMF_INFO(("%s: ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n", | ||
6230 | __func__, ci->ccrev, ci->pmurev, | ||
6231 | ci->buscorerev, ci->buscoretype)); | ||
6232 | |||
6233 | /* get chipcommon capabilites */ | ||
6234 | ci->cccaps = brcmf_sdcard_reg_read(card, | ||
6235 | CORE_CC_REG(ci->cccorebase, capabilities), 4); | ||
6236 | |||
6237 | return 0; | ||
6238 | } | ||
6239 | |||
6240 | static void | ||
6241 | brcmf_sdbrcm_chip_disablecore(struct brcmf_sdio_card *card, u32 corebase) | ||
6242 | { | ||
6243 | u32 regdata; | ||
6244 | |||
6245 | regdata = brcmf_sdcard_reg_read(card, | ||
6246 | CORE_SB(corebase, sbtmstatelow), 4); | ||
6247 | if (regdata & SBTML_RESET) | ||
6248 | return; | ||
6249 | |||
6250 | regdata = brcmf_sdcard_reg_read(card, | ||
6251 | CORE_SB(corebase, sbtmstatelow), 4); | ||
6252 | if ((regdata & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) != 0) { | ||
6253 | /* | ||
6254 | * set target reject and spin until busy is clear | ||
6255 | * (preserve core-specific bits) | ||
6256 | */ | ||
6257 | regdata = brcmf_sdcard_reg_read(card, | ||
6258 | CORE_SB(corebase, sbtmstatelow), 4); | ||
6259 | brcmf_sdcard_reg_write(card, CORE_SB(corebase, sbtmstatelow), 4, | ||
6260 | regdata | SBTML_REJ); | ||
6261 | |||
6262 | regdata = brcmf_sdcard_reg_read(card, | ||
6263 | CORE_SB(corebase, sbtmstatelow), 4); | ||
6264 | udelay(1); | ||
6265 | SPINWAIT((brcmf_sdcard_reg_read(card, | ||
6266 | CORE_SB(corebase, sbtmstatehigh), 4) & | ||
6267 | SBTMH_BUSY), 100000); | ||
6268 | |||
6269 | regdata = brcmf_sdcard_reg_read(card, | ||
6270 | CORE_SB(corebase, sbtmstatehigh), 4); | ||
6271 | if (regdata & SBTMH_BUSY) | ||
6272 | BRCMF_ERROR(("%s: ARM core still busy\n", __func__)); | ||
6273 | |||
6274 | regdata = brcmf_sdcard_reg_read(card, | ||
6275 | CORE_SB(corebase, sbidlow), 4); | ||
6276 | if (regdata & SBIDL_INIT) { | ||
6277 | regdata = brcmf_sdcard_reg_read(card, | ||
6278 | CORE_SB(corebase, sbimstate), 4) | | ||
6279 | SBIM_RJ; | ||
6280 | brcmf_sdcard_reg_write(card, | ||
6281 | CORE_SB(corebase, sbimstate), 4, | ||
6282 | regdata); | ||
6283 | regdata = brcmf_sdcard_reg_read(card, | ||
6284 | CORE_SB(corebase, sbimstate), 4); | ||
6285 | udelay(1); | ||
6286 | SPINWAIT((brcmf_sdcard_reg_read(card, | ||
6287 | CORE_SB(corebase, sbimstate), 4) & | ||
6288 | SBIM_BY), 100000); | ||
6289 | } | ||
6290 | |||
6291 | /* set reset and reject while enabling the clocks */ | ||
6292 | brcmf_sdcard_reg_write(card, | ||
6293 | CORE_SB(corebase, sbtmstatelow), 4, | ||
6294 | (((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | | ||
6295 | SBTML_REJ | SBTML_RESET)); | ||
6296 | regdata = brcmf_sdcard_reg_read(card, | ||
6297 | CORE_SB(corebase, sbtmstatelow), 4); | ||
6298 | udelay(10); | ||
6299 | |||
6300 | /* clear the initiator reject bit */ | ||
6301 | regdata = brcmf_sdcard_reg_read(card, | ||
6302 | CORE_SB(corebase, sbidlow), 4); | ||
6303 | if (regdata & SBIDL_INIT) { | ||
6304 | regdata = brcmf_sdcard_reg_read(card, | ||
6305 | CORE_SB(corebase, sbimstate), 4) & | ||
6306 | ~SBIM_RJ; | ||
6307 | brcmf_sdcard_reg_write(card, | ||
6308 | CORE_SB(corebase, sbimstate), 4, | ||
6309 | regdata); | ||
6310 | } | ||
6311 | } | ||
6312 | |||
6313 | /* leave reset and reject asserted */ | ||
6314 | brcmf_sdcard_reg_write(card, CORE_SB(corebase, sbtmstatelow), 4, | ||
6315 | (SBTML_REJ | SBTML_RESET)); | ||
6316 | udelay(1); | ||
6317 | } | ||
6318 | |||
6319 | static int | ||
6320 | brcmf_sdbrcm_chip_attach(struct brcmf_bus *bus, u32 regs) | ||
6321 | { | ||
6322 | struct chip_info *ci; | ||
6323 | int err; | ||
6324 | u8 clkval, clkset; | ||
6325 | |||
6326 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
6327 | |||
6328 | /* alloc chip_info_t */ | ||
6329 | ci = kmalloc(sizeof(struct chip_info), GFP_ATOMIC); | ||
6330 | if (NULL == ci) { | ||
6331 | BRCMF_ERROR(("%s: malloc failed!\n", __func__)); | ||
6332 | return -ENOMEM; | ||
6333 | } | ||
6334 | |||
6335 | memset((unsigned char *)ci, 0, sizeof(struct chip_info)); | ||
6336 | |||
6337 | /* bus/core/clk setup for register access */ | ||
6338 | /* Try forcing SDIO core to do ALPAvail request only */ | ||
6339 | clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; | ||
6340 | brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, | ||
6341 | clkset, &err); | ||
6342 | if (err) { | ||
6343 | BRCMF_ERROR(("%s: error writing for HT off\n", __func__)); | ||
6344 | goto fail; | ||
6345 | } | ||
6346 | |||
6347 | /* If register supported, wait for ALPAvail and then force ALP */ | ||
6348 | /* This may take up to 15 milliseconds */ | ||
6349 | clkval = brcmf_sdcard_cfg_read(bus->card, SDIO_FUNC_1, | ||
6350 | SBSDIO_FUNC1_CHIPCLKCSR, NULL); | ||
6351 | if ((clkval & ~SBSDIO_AVBITS) == clkset) { | ||
6352 | SPINWAIT(((clkval = | ||
6353 | brcmf_sdcard_cfg_read(bus->card, SDIO_FUNC_1, | ||
6354 | SBSDIO_FUNC1_CHIPCLKCSR, | ||
6355 | NULL)), | ||
6356 | !SBSDIO_ALPAV(clkval)), | ||
6357 | PMU_MAX_TRANSITION_DLY); | ||
6358 | if (!SBSDIO_ALPAV(clkval)) { | ||
6359 | BRCMF_ERROR(("%s: timeout on ALPAV wait," | ||
6360 | " clkval 0x%02x\n", __func__, clkval)); | ||
6361 | err = -EBUSY; | ||
6362 | goto fail; | ||
6363 | } | ||
6364 | clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | | ||
6365 | SBSDIO_FORCE_ALP; | ||
6366 | brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, | ||
6367 | SBSDIO_FUNC1_CHIPCLKCSR, | ||
6368 | clkset, &err); | ||
6369 | udelay(65); | ||
6370 | } else { | ||
6371 | BRCMF_ERROR(("%s: ChipClkCSR access: wrote 0x%02x" | ||
6372 | " read 0x%02x\n", __func__, clkset, clkval)); | ||
6373 | err = -EACCES; | ||
6374 | goto fail; | ||
6375 | } | ||
6376 | |||
6377 | /* Also, disable the extra SDIO pull-ups */ | ||
6378 | brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, | ||
6379 | 0, NULL); | ||
6380 | |||
6381 | err = brcmf_sdbrcm_chip_recognition(bus->card, ci, regs); | ||
6382 | if (err) | ||
6383 | goto fail; | ||
6384 | |||
6385 | /* | ||
6386 | * Make sure any on-chip ARM is off (in case strapping is wrong), | ||
6387 | * or downloaded code was already running. | ||
6388 | */ | ||
6389 | brcmf_sdbrcm_chip_disablecore(bus->card, ci->armcorebase); | ||
6390 | |||
6391 | brcmf_sdcard_reg_write(bus->card, | ||
6392 | CORE_CC_REG(ci->cccorebase, gpiopullup), 4, 0); | ||
6393 | brcmf_sdcard_reg_write(bus->card, | ||
6394 | CORE_CC_REG(ci->cccorebase, gpiopulldown), 4, 0); | ||
6395 | |||
6396 | /* Disable F2 to clear any intermediate frame state on the dongle */ | ||
6397 | brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_0, SDIO_CCCR_IOEx, | ||
6398 | SDIO_FUNC_ENABLE_1, NULL); | ||
6399 | |||
6400 | /* WAR: cmd52 backplane read so core HW will drop ALPReq */ | ||
6401 | clkval = brcmf_sdcard_cfg_read(bus->card, SDIO_FUNC_1, | ||
6402 | 0, NULL); | ||
6403 | |||
6404 | /* Done with backplane-dependent accesses, can drop clock... */ | ||
6405 | brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, | ||
6406 | 0, NULL); | ||
6407 | |||
6408 | bus->ci = ci; | ||
6409 | return 0; | ||
6410 | fail: | ||
6411 | bus->ci = NULL; | ||
6412 | kfree(ci); | ||
6413 | return err; | ||
6414 | } | ||
6415 | |||
6416 | static void | ||
6417 | brcmf_sdbrcm_chip_resetcore(struct brcmf_sdio_card *card, u32 corebase) | ||
6418 | { | ||
6419 | u32 regdata; | ||
6420 | |||
6421 | /* | ||
6422 | * Must do the disable sequence first to work for | ||
6423 | * arbitrary current core state. | ||
6424 | */ | ||
6425 | brcmf_sdbrcm_chip_disablecore(card, corebase); | ||
6426 | |||
6427 | /* | ||
6428 | * Now do the initialization sequence. | ||
6429 | * set reset while enabling the clock and | ||
6430 | * forcing them on throughout the core | ||
6431 | */ | ||
6432 | brcmf_sdcard_reg_write(card, CORE_SB(corebase, sbtmstatelow), 4, | ||
6433 | ((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | | ||
6434 | SBTML_RESET); | ||
6435 | udelay(1); | ||
6436 | |||
6437 | regdata = brcmf_sdcard_reg_read(card, CORE_SB(corebase, sbtmstatehigh), | ||
6438 | 4); | ||
6439 | if (regdata & SBTMH_SERR) | ||
6440 | brcmf_sdcard_reg_write(card, CORE_SB(corebase, sbtmstatehigh), | ||
6441 | 4, 0); | ||
6442 | |||
6443 | regdata = brcmf_sdcard_reg_read(card, CORE_SB(corebase, sbimstate), 4); | ||
6444 | if (regdata & (SBIM_IBE | SBIM_TO)) | ||
6445 | brcmf_sdcard_reg_write(card, CORE_SB(corebase, sbimstate), 4, | ||
6446 | regdata & ~(SBIM_IBE | SBIM_TO)); | ||
6447 | |||
6448 | /* clear reset and allow it to propagate throughout the core */ | ||
6449 | brcmf_sdcard_reg_write(card, CORE_SB(corebase, sbtmstatelow), 4, | ||
6450 | (SICF_FGC << SBTML_SICF_SHIFT) | | ||
6451 | (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); | ||
6452 | udelay(1); | ||
6453 | |||
6454 | /* leave clock enabled */ | ||
6455 | brcmf_sdcard_reg_write(card, CORE_SB(corebase, sbtmstatelow), 4, | ||
6456 | (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); | ||
6457 | udelay(1); | ||
6458 | } | ||
6459 | |||
6460 | /* SDIO Pad drive strength to select value mappings */ | ||
6461 | struct sdiod_drive_str { | ||
6462 | u8 strength; /* Pad Drive Strength in mA */ | ||
6463 | u8 sel; /* Chip-specific select value */ | ||
6464 | }; | ||
6465 | |||
6466 | /* SDIO Drive Strength to sel value table for PMU Rev 1 */ | ||
6467 | static const struct sdiod_drive_str sdiod_drive_strength_tab1[] = { | ||
6468 | { | ||
6469 | 4, 0x2}, { | ||
6470 | 2, 0x3}, { | ||
6471 | 1, 0x0}, { | ||
6472 | 0, 0x0} | ||
6473 | }; | ||
6474 | |||
6475 | /* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */ | ||
6476 | static const struct sdiod_drive_str sdiod_drive_strength_tab2[] = { | ||
6477 | { | ||
6478 | 12, 0x7}, { | ||
6479 | 10, 0x6}, { | ||
6480 | 8, 0x5}, { | ||
6481 | 6, 0x4}, { | ||
6482 | 4, 0x2}, { | ||
6483 | 2, 0x1}, { | ||
6484 | 0, 0x0} | ||
6485 | }; | ||
6486 | |||
6487 | /* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */ | ||
6488 | static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = { | ||
6489 | { | ||
6490 | 32, 0x7}, { | ||
6491 | 26, 0x6}, { | ||
6492 | 22, 0x5}, { | ||
6493 | 16, 0x4}, { | ||
6494 | 12, 0x3}, { | ||
6495 | 8, 0x2}, { | ||
6496 | 4, 0x1}, { | ||
6497 | 0, 0x0} | ||
6498 | }; | ||
6499 | |||
6500 | #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) | ||
6501 | |||
6502 | static void | ||
6503 | brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus, u32 drivestrength) { | ||
6504 | struct sdiod_drive_str *str_tab = NULL; | ||
6505 | u32 str_mask = 0; | ||
6506 | u32 str_shift = 0; | ||
6507 | char chn[8]; | ||
6508 | |||
6509 | if (!(bus->ci->cccaps & CC_CAP_PMU)) | ||
6510 | return; | ||
6511 | |||
6512 | switch (SDIOD_DRVSTR_KEY(bus->ci->chip, bus->ci->pmurev)) { | ||
6513 | case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): | ||
6514 | str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1; | ||
6515 | str_mask = 0x30000000; | ||
6516 | str_shift = 28; | ||
6517 | break; | ||
6518 | case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2): | ||
6519 | case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3): | ||
6520 | str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2; | ||
6521 | str_mask = 0x00003800; | ||
6522 | str_shift = 11; | ||
6523 | break; | ||
6524 | case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): | ||
6525 | str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3; | ||
6526 | str_mask = 0x00003800; | ||
6527 | str_shift = 11; | ||
6528 | break; | ||
6529 | default: | ||
6530 | BRCMF_ERROR(("No SDIO Drive strength init" | ||
6531 | "done for chip %s rev %d pmurev %d\n", | ||
6532 | brcmu_chipname(bus->ci->chip, chn, 8), | ||
6533 | bus->ci->chiprev, bus->ci->pmurev)); | ||
6534 | break; | ||
6535 | } | ||
6536 | |||
6537 | if (str_tab != NULL) { | ||
6538 | u32 drivestrength_sel = 0; | ||
6539 | u32 cc_data_temp; | ||
6540 | int i; | ||
6541 | |||
6542 | for (i = 0; str_tab[i].strength != 0; i++) { | ||
6543 | if (drivestrength >= str_tab[i].strength) { | ||
6544 | drivestrength_sel = str_tab[i].sel; | ||
6545 | break; | ||
6546 | } | ||
6547 | } | ||
6548 | |||
6549 | brcmf_sdcard_reg_write(bus->card, | ||
6550 | CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), | ||
6551 | 4, 1); | ||
6552 | cc_data_temp = brcmf_sdcard_reg_read(bus->card, | ||
6553 | CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), 4); | ||
6554 | cc_data_temp &= ~str_mask; | ||
6555 | drivestrength_sel <<= str_shift; | ||
6556 | cc_data_temp |= drivestrength_sel; | ||
6557 | brcmf_sdcard_reg_write(bus->card, | ||
6558 | CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), | ||
6559 | 4, cc_data_temp); | ||
6560 | |||
6561 | BRCMF_INFO(("SDIO: %dmA drive strength selected, " | ||
6562 | "set to 0x%08x\n", drivestrength, cc_data_temp)); | ||
6563 | } | ||
6564 | } | ||
6565 | |||
6566 | static void | ||
6567 | brcmf_sdbrcm_chip_detach(struct brcmf_bus *bus) | ||
6568 | { | ||
6569 | BRCMF_TRACE(("%s: Enter\n", __func__)); | ||
6570 | |||
6571 | kfree(bus->ci); | ||
6572 | bus->ci = NULL; | ||
6573 | } | ||
6574 | |||
6575 | static void | ||
6576 | brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar) | ||
6577 | { | ||
6578 | brcmf_sdbrcm_sdunlock(bus); | ||
6579 | wait_event_interruptible_timeout(bus->ctrl_wait, | ||
6580 | (*lockvar == false), HZ * 2); | ||
6581 | brcmf_sdbrcm_sdlock(bus); | ||
6582 | return; | ||
6583 | } | ||
6584 | |||
6585 | static void | ||
6586 | brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus) | ||
6587 | { | ||
6588 | if (waitqueue_active(&bus->ctrl_wait)) | ||
6589 | wake_up_interruptible(&bus->ctrl_wait); | ||
6590 | return; | ||
6591 | } | ||
6592 | |||
6593 | static int | ||
6594 | brcmf_sdbrcm_watchdog_thread(void *data) | ||
6595 | { | ||
6596 | struct brcmf_bus *bus = (struct brcmf_bus *)data; | ||
6597 | |||
6598 | /* This thread doesn't need any user-level access, | ||
6599 | * so get rid of all our resources | ||
6600 | */ | ||
6601 | if (brcmf_watchdog_prio > 0) { | ||
6602 | struct sched_param param; | ||
6603 | param.sched_priority = (brcmf_watchdog_prio < MAX_RT_PRIO) ? | ||
6604 | brcmf_watchdog_prio : (MAX_RT_PRIO - 1); | ||
6605 | sched_setscheduler(current, SCHED_FIFO, ¶m); | ||
6606 | } | ||
6607 | |||
6608 | allow_signal(SIGTERM); | ||
6609 | /* Run until signal received */ | ||
6610 | while (1) { | ||
6611 | if (kthread_should_stop()) | ||
6612 | break; | ||
6613 | if (!wait_for_completion_interruptible(&bus->watchdog_wait)) { | ||
6614 | if (bus->drvr->dongle_reset == false) | ||
6615 | brcmf_sdbrcm_bus_watchdog(bus->drvr); | ||
6616 | /* Count the tick for reference */ | ||
6617 | bus->drvr->tickcnt++; | ||
6618 | } else | ||
6619 | break; | ||
6620 | } | ||
6621 | return 0; | ||
6622 | } | ||
6623 | |||
6624 | static void | ||
6625 | brcmf_sdbrcm_watchdog(unsigned long data) | ||
6626 | { | ||
6627 | struct brcmf_bus *bus = (struct brcmf_bus *)data; | ||
6628 | |||
6629 | if (brcmf_watchdog_prio >= 0) { | ||
6630 | if (bus->watchdog_tsk) | ||
6631 | complete(&bus->watchdog_wait); | ||
6632 | else | ||
6633 | return; | ||
6634 | } else { | ||
6635 | brcmf_sdbrcm_bus_watchdog(bus->drvr); | ||
6636 | |||
6637 | /* Count the tick for reference */ | ||
6638 | bus->drvr->tickcnt++; | ||
6639 | } | ||
6640 | |||
6641 | /* Reschedule the watchdog */ | ||
6642 | if (bus->wd_timer_valid) | ||
6643 | mod_timer(&bus->timer, jiffies + brcmf_watchdog_ms * HZ / 1000); | ||
6644 | } | ||
6645 | |||
6646 | void | ||
6647 | brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick) | ||
6648 | { | ||
6649 | static uint save_ms; | ||
6650 | |||
6651 | /* don't start the wd until fw is loaded */ | ||
6652 | if (bus->drvr->busstate == BRCMF_BUS_DOWN) | ||
6653 | return; | ||
6654 | |||
6655 | /* Totally stop the timer */ | ||
6656 | if (!wdtick && bus->wd_timer_valid == true) { | ||
6657 | del_timer_sync(&bus->timer); | ||
6658 | bus->wd_timer_valid = false; | ||
6659 | save_ms = wdtick; | ||
6660 | return; | ||
6661 | } | ||
6662 | |||
6663 | if (wdtick) { | ||
6664 | brcmf_watchdog_ms = (uint) wdtick; | ||
6665 | |||
6666 | if (save_ms != brcmf_watchdog_ms) { | ||
6667 | if (bus->wd_timer_valid == true) | ||
6668 | /* Stop timer and restart at new value */ | ||
6669 | del_timer_sync(&bus->timer); | ||
6670 | |||
6671 | /* Create timer again when watchdog period is | ||
6672 | dynamically changed or in the first instance | ||
6673 | */ | ||
6674 | bus->timer.expires = | ||
6675 | jiffies + brcmf_watchdog_ms * HZ / 1000; | ||
6676 | add_timer(&bus->timer); | ||
6677 | |||
6678 | } else { | ||
6679 | /* Re arm the timer, at last watchdog period */ | ||
6680 | mod_timer(&bus->timer, | ||
6681 | jiffies + brcmf_watchdog_ms * HZ / 1000); | ||
6682 | } | ||
6683 | |||
6684 | bus->wd_timer_valid = true; | ||
6685 | save_ms = wdtick; | ||
6686 | } | ||
6687 | } | ||
6688 | |||
6689 | static int brcmf_sdbrcm_dpc_thread(void *data) | ||
6690 | { | ||
6691 | struct brcmf_bus *bus = (struct brcmf_bus *) data; | ||
6692 | |||
6693 | /* This thread doesn't need any user-level access, | ||
6694 | * so get rid of all our resources | ||
6695 | */ | ||
6696 | if (brcmf_dpc_prio > 0) { | ||
6697 | struct sched_param param; | ||
6698 | param.sched_priority = (brcmf_dpc_prio < MAX_RT_PRIO) ? | ||
6699 | brcmf_dpc_prio : (MAX_RT_PRIO - 1); | ||
6700 | sched_setscheduler(current, SCHED_FIFO, ¶m); | ||
6701 | } | ||
6702 | |||
6703 | allow_signal(SIGTERM); | ||
6704 | /* Run until signal received */ | ||
6705 | while (1) { | ||
6706 | if (kthread_should_stop()) | ||
6707 | break; | ||
6708 | if (!wait_for_completion_interruptible(&bus->dpc_wait)) { | ||
6709 | /* Call bus dpc unless it indicated down | ||
6710 | (then clean stop) */ | ||
6711 | if (bus->drvr->busstate != BRCMF_BUS_DOWN) { | ||
6712 | if (brcmf_sdbrcm_dpc(bus)) | ||
6713 | complete(&bus->dpc_wait); | ||
6714 | } else { | ||
6715 | brcmf_sdbrcm_bus_stop(bus, true); | ||
6716 | } | ||
6717 | } else | ||
6718 | break; | ||
6719 | } | ||
6720 | return 0; | ||
6721 | } | ||
6722 | |||
6723 | static void brcmf_sdbrcm_dpc_tasklet(unsigned long data) | ||
6724 | { | ||
6725 | struct brcmf_bus *bus = (struct brcmf_bus *) data; | ||
6726 | |||
6727 | /* Call bus dpc unless it indicated down (then clean stop) */ | ||
6728 | if (bus->drvr->busstate != BRCMF_BUS_DOWN) { | ||
6729 | if (brcmf_sdbrcm_dpc(bus)) | ||
6730 | tasklet_schedule(&bus->tasklet); | ||
6731 | } else | ||
6732 | brcmf_sdbrcm_bus_stop(bus, true); | ||
6733 | } | ||
6734 | |||
6735 | static void brcmf_sdbrcm_sched_dpc(struct brcmf_bus *bus) | ||
6736 | { | ||
6737 | if (bus->dpc_tsk) { | ||
6738 | complete(&bus->dpc_wait); | ||
6739 | return; | ||
6740 | } | ||
6741 | |||
6742 | tasklet_schedule(&bus->tasklet); | ||
6743 | } | ||
6744 | |||
6745 | static void brcmf_sdbrcm_sdlock(struct brcmf_bus *bus) | ||
6746 | { | ||
6747 | if (bus->threads_only) | ||
6748 | down(&bus->sdsem); | ||
6749 | else | ||
6750 | spin_lock_bh(&bus->sdlock); | ||
6751 | } | ||
6752 | |||
6753 | static void brcmf_sdbrcm_sdunlock(struct brcmf_bus *bus) | ||
6754 | { | ||
6755 | if (bus->threads_only) | ||
6756 | up(&bus->sdsem); | ||
6757 | else | ||
6758 | spin_unlock_bh(&bus->sdlock); | ||
6759 | } | ||
6760 | |||
6761 | static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus) | ||
6762 | { | ||
6763 | if (bus->firmware->size < bus->fw_ptr + len) | ||
6764 | len = bus->firmware->size - bus->fw_ptr; | ||
6765 | |||
6766 | memcpy(buf, &bus->firmware->data[bus->fw_ptr], len); | ||
6767 | bus->fw_ptr += len; | ||
6768 | return len; | ||
6769 | } | ||
6770 | |||
6771 | MODULE_FIRMWARE(BCM4329_FW_NAME); | ||
6772 | MODULE_FIRMWARE(BCM4329_NV_NAME); | ||
diff --git a/drivers/staging/brcm80211/brcmfmac/sdio_host.h b/drivers/staging/brcm80211/brcmfmac/sdio_host.h new file mode 100644 index 00000000000..d3454721506 --- /dev/null +++ b/drivers/staging/brcm80211/brcmfmac/sdio_host.h | |||
@@ -0,0 +1,347 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #ifndef _BRCM_SDH_H_ | ||
18 | #define _BRCM_SDH_H_ | ||
19 | |||
20 | #include <linux/skbuff.h> | ||
21 | extern const uint brcmf_sdio_msglevel; | ||
22 | |||
23 | #define SDIO_FUNC_0 0 | ||
24 | #define SDIO_FUNC_1 1 | ||
25 | #define SDIO_FUNC_2 2 | ||
26 | |||
27 | #define SDIOD_FBR_SIZE 0x100 | ||
28 | |||
29 | /* io_en */ | ||
30 | #define SDIO_FUNC_ENABLE_1 0x02 | ||
31 | #define SDIO_FUNC_ENABLE_2 0x04 | ||
32 | |||
33 | /* io_rdys */ | ||
34 | #define SDIO_FUNC_READY_1 0x02 | ||
35 | #define SDIO_FUNC_READY_2 0x04 | ||
36 | |||
37 | /* intr_status */ | ||
38 | #define INTR_STATUS_FUNC1 0x2 | ||
39 | #define INTR_STATUS_FUNC2 0x4 | ||
40 | |||
41 | /* Maximum number of I/O funcs */ | ||
42 | #define SDIOD_MAX_IOFUNCS 7 | ||
43 | |||
44 | #define SBSDIO_NUM_FUNCTION 3 /* as of sdiod rev 0, supports 3 functions */ | ||
45 | |||
46 | /* function 1 miscellaneous registers */ | ||
47 | #define SBSDIO_SPROM_CS 0x10000 /* sprom command and status */ | ||
48 | #define SBSDIO_SPROM_INFO 0x10001 /* sprom info register */ | ||
49 | #define SBSDIO_SPROM_DATA_LOW 0x10002 /* sprom indirect access data byte 0 */ | ||
50 | #define SBSDIO_SPROM_DATA_HIGH 0x10003 /* sprom indirect access data byte 1 */ | ||
51 | #define SBSDIO_SPROM_ADDR_LOW 0x10004 /* sprom indirect access addr byte 0 */ | ||
52 | #define SBSDIO_SPROM_ADDR_HIGH 0x10005 /* sprom indirect access addr byte 0 */ | ||
53 | #define SBSDIO_CHIP_CTRL_DATA 0x10006 /* xtal_pu (gpio) output */ | ||
54 | #define SBSDIO_CHIP_CTRL_EN 0x10007 /* xtal_pu (gpio) enable */ | ||
55 | #define SBSDIO_WATERMARK 0x10008 /* rev < 7, watermark for sdio device */ | ||
56 | #define SBSDIO_DEVICE_CTL 0x10009 /* control busy signal generation */ | ||
57 | |||
58 | /* registers introduced in rev 8, some content (mask/bits) defs in sbsdpcmdev.h */ | ||
59 | #define SBSDIO_FUNC1_SBADDRLOW 0x1000A /* SB Address Window Low (b15) */ | ||
60 | #define SBSDIO_FUNC1_SBADDRMID 0x1000B /* SB Address Window Mid (b23:b16) */ | ||
61 | #define SBSDIO_FUNC1_SBADDRHIGH 0x1000C /* SB Address Window High (b31:b24) */ | ||
62 | #define SBSDIO_FUNC1_FRAMECTRL 0x1000D /* Frame Control (frame term/abort) */ | ||
63 | #define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E /* ChipClockCSR (ALP/HT ctl/status) */ | ||
64 | #define SBSDIO_FUNC1_SDIOPULLUP 0x1000F /* SdioPullUp (on cmd, d0-d2) */ | ||
65 | #define SBSDIO_FUNC1_WFRAMEBCLO 0x10019 /* Write Frame Byte Count Low */ | ||
66 | #define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A /* Write Frame Byte Count High */ | ||
67 | #define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B /* Read Frame Byte Count Low */ | ||
68 | #define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C /* Read Frame Byte Count High */ | ||
69 | |||
70 | #define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */ | ||
71 | #define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001C /* f1 misc register end */ | ||
72 | |||
73 | /* function 1 OCP space */ | ||
74 | #define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF /* sb offset addr is <= 15 bits, 32k */ | ||
75 | #define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000 | ||
76 | #define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000 /* with b15, maps to 32-bit SB access */ | ||
77 | |||
78 | /* some duplication with sbsdpcmdev.h here */ | ||
79 | /* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */ | ||
80 | #define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid bits in SBADDRLOW */ | ||
81 | #define SBSDIO_SBADDRMID_MASK 0xff /* Valid bits in SBADDRMID */ | ||
82 | #define SBSDIO_SBADDRHIGH_MASK 0xffU /* Valid bits in SBADDRHIGH */ | ||
83 | #define SBSDIO_SBWINDOW_MASK 0xffff8000 /* Address bits from SBADDR regs */ | ||
84 | |||
85 | #define SDIOH_READ 0 /* Read request */ | ||
86 | #define SDIOH_WRITE 1 /* Write request */ | ||
87 | |||
88 | #define SDIOH_DATA_FIX 0 /* Fixed addressing */ | ||
89 | #define SDIOH_DATA_INC 1 /* Incremental addressing */ | ||
90 | |||
91 | /* internal return code */ | ||
92 | #define SUCCESS 0 | ||
93 | #define ERROR 1 | ||
94 | |||
95 | /* forward declarations */ | ||
96 | struct brcmf_sdio_card; | ||
97 | |||
98 | struct brcmf_sdreg { | ||
99 | int func; | ||
100 | int offset; | ||
101 | int value; | ||
102 | }; | ||
103 | |||
104 | struct sdioh_info { | ||
105 | struct osl_info *osh; /* osh handler */ | ||
106 | bool client_intr_enabled; /* interrupt connnected flag */ | ||
107 | bool intr_handler_valid; /* client driver interrupt handler valid */ | ||
108 | void (*intr_handler)(void *); /* registered interrupt handler */ | ||
109 | void *intr_handler_arg; /* argument to call interrupt handler */ | ||
110 | u16 intmask; /* Current active interrupts */ | ||
111 | void *sdos_info; /* Pointer to per-OS private data */ | ||
112 | |||
113 | uint irq; /* Client irq */ | ||
114 | int intrcount; /* Client interrupts */ | ||
115 | bool sd_blockmode; /* sd_blockmode == false => 64 Byte Cmd 53s. */ | ||
116 | /* Must be on for sd_multiblock to be effective */ | ||
117 | bool use_client_ints; /* If this is false, make sure to restore */ | ||
118 | int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ | ||
119 | u8 num_funcs; /* Supported funcs on client */ | ||
120 | u32 com_cis_ptr; | ||
121 | u32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; | ||
122 | uint max_dma_len; | ||
123 | uint max_dma_descriptors; /* DMA Descriptors supported by this controller. */ | ||
124 | /* SDDMA_DESCRIPTOR SGList[32]; *//* Scatter/Gather DMA List */ | ||
125 | }; | ||
126 | |||
127 | struct brcmf_sdmmc_instance { | ||
128 | struct sdioh_info *sd; | ||
129 | struct sdio_func *func[SDIOD_MAX_IOFUNCS]; | ||
130 | u32 host_claimed; | ||
131 | }; | ||
132 | |||
133 | /* Attach and build an interface to the underlying SD host driver. | ||
134 | * - Allocates resources (structs, arrays, mem, OS handles, etc) needed by | ||
135 | * brcmf_sdcard. | ||
136 | * - Returns the sdio card handle and virtual address base for register access. | ||
137 | * The returned handle should be used in all subsequent calls, but the bcmsh | ||
138 | * implementation may maintain a single "default" handle (e.g. the first or | ||
139 | * most recent one) to enable single-instance implementations to pass NULL. | ||
140 | */ | ||
141 | extern struct brcmf_sdio_card* | ||
142 | brcmf_sdcard_attach(void *cfghdl, u32 *regsva, uint irq); | ||
143 | |||
144 | /* Detach - freeup resources allocated in attach */ | ||
145 | extern int brcmf_sdcard_detach(struct brcmf_sdio_card *card); | ||
146 | |||
147 | /* Enable/disable SD interrupt */ | ||
148 | extern int brcmf_sdcard_intr_enable(struct brcmf_sdio_card *card); | ||
149 | extern int brcmf_sdcard_intr_disable(struct brcmf_sdio_card *card); | ||
150 | |||
151 | /* Register/deregister device interrupt handler. */ | ||
152 | extern int | ||
153 | brcmf_sdcard_intr_reg(struct brcmf_sdio_card *card, | ||
154 | void (*fn)(void *), void *argh); | ||
155 | |||
156 | extern int brcmf_sdcard_intr_dereg(struct brcmf_sdio_card *card); | ||
157 | |||
158 | /* Access SDIO address space (e.g. CCCR) using CMD52 (single-byte interface). | ||
159 | * fn: function number | ||
160 | * addr: unmodified SDIO-space address | ||
161 | * data: data byte to write | ||
162 | * err: pointer to error code (or NULL) | ||
163 | */ | ||
164 | extern u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_card *card, uint func, | ||
165 | u32 addr, int *err); | ||
166 | extern void brcmf_sdcard_cfg_write(struct brcmf_sdio_card *card, uint func, | ||
167 | u32 addr, u8 data, int *err); | ||
168 | |||
169 | /* Read/Write 4bytes from/to cfg space */ | ||
170 | extern u32 | ||
171 | brcmf_sdcard_cfg_read_word(struct brcmf_sdio_card *card, uint fnc_num, | ||
172 | u32 addr, int *err); | ||
173 | |||
174 | extern void brcmf_sdcard_cfg_write_word(struct brcmf_sdio_card *card, | ||
175 | uint fnc_num, u32 addr, | ||
176 | u32 data, int *err); | ||
177 | |||
178 | /* Read CIS content for specified function. | ||
179 | * fn: function whose CIS is being requested (0 is common CIS) | ||
180 | * cis: pointer to memory location to place results | ||
181 | * length: number of bytes to read | ||
182 | * Internally, this routine uses the values from the cis base regs (0x9-0xB) | ||
183 | * to form an SDIO-space address to read the data from. | ||
184 | */ | ||
185 | extern int brcmf_sdcard_cis_read(struct brcmf_sdio_card *card, uint func, | ||
186 | u8 *cis, uint length); | ||
187 | |||
188 | /* Synchronous access to device (client) core registers via CMD53 to F1. | ||
189 | * addr: backplane address (i.e. >= regsva from attach) | ||
190 | * size: register width in bytes (2 or 4) | ||
191 | * data: data for register write | ||
192 | */ | ||
193 | extern u32 | ||
194 | brcmf_sdcard_reg_read(struct brcmf_sdio_card *card, u32 addr, uint size); | ||
195 | |||
196 | extern u32 | ||
197 | brcmf_sdcard_reg_write(struct brcmf_sdio_card *card, u32 addr, uint size, | ||
198 | u32 data); | ||
199 | |||
200 | /* Indicate if last reg read/write failed */ | ||
201 | extern bool brcmf_sdcard_regfail(struct brcmf_sdio_card *card); | ||
202 | |||
203 | /* Buffer transfer to/from device (client) core via cmd53. | ||
204 | * fn: function number | ||
205 | * addr: backplane address (i.e. >= regsva from attach) | ||
206 | * flags: backplane width, address increment, sync/async | ||
207 | * buf: pointer to memory data buffer | ||
208 | * nbytes: number of bytes to transfer to/from buf | ||
209 | * pkt: pointer to packet associated with buf (if any) | ||
210 | * complete: callback function for command completion (async only) | ||
211 | * handle: handle for completion callback (first arg in callback) | ||
212 | * Returns 0 or error code. | ||
213 | * NOTE: Async operation is not currently supported. | ||
214 | */ | ||
215 | extern int | ||
216 | brcmf_sdcard_send_buf(struct brcmf_sdio_card *card, u32 addr, uint fn, | ||
217 | uint flags, u8 *buf, uint nbytes, void *pkt, | ||
218 | void (*complete)(void *handle, int status, | ||
219 | bool sync_waiting), | ||
220 | void *handle); | ||
221 | extern int | ||
222 | brcmf_sdcard_recv_buf(struct brcmf_sdio_card *card, u32 addr, uint fn, | ||
223 | uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt, | ||
224 | void (*complete)(void *handle, int status, | ||
225 | bool sync_waiting), | ||
226 | void *handle); | ||
227 | |||
228 | /* Flags bits */ | ||
229 | #define SDIO_REQ_4BYTE 0x1 /* Four-byte target (backplane) width (vs. two-byte) */ | ||
230 | #define SDIO_REQ_FIXED 0x2 /* Fixed address (FIFO) (vs. incrementing address) */ | ||
231 | #define SDIO_REQ_ASYNC 0x4 /* Async request (vs. sync request) */ | ||
232 | |||
233 | /* Pending (non-error) return code */ | ||
234 | #define BCME_PENDING 1 | ||
235 | |||
236 | /* Read/write to memory block (F1, no FIFO) via CMD53 (sync only). | ||
237 | * rw: read or write (0/1) | ||
238 | * addr: direct SDIO address | ||
239 | * buf: pointer to memory data buffer | ||
240 | * nbytes: number of bytes to transfer to/from buf | ||
241 | * Returns 0 or error code. | ||
242 | */ | ||
243 | extern int brcmf_sdcard_rwdata(struct brcmf_sdio_card *card, uint rw, u32 addr, | ||
244 | u8 *buf, uint nbytes); | ||
245 | |||
246 | /* Issue an abort to the specified function */ | ||
247 | extern int brcmf_sdcard_abort(struct brcmf_sdio_card *card, uint fn); | ||
248 | |||
249 | /* Returns the "Device ID" of target device on the SDIO bus. */ | ||
250 | extern int brcmf_sdcard_query_device(struct brcmf_sdio_card *card); | ||
251 | |||
252 | /* Miscellaneous knob tweaker. */ | ||
253 | extern int brcmf_sdcard_iovar_op(struct brcmf_sdio_card *card, const char *name, | ||
254 | void *params, int plen, void *arg, int len, | ||
255 | bool set); | ||
256 | |||
257 | /* helper functions */ | ||
258 | |||
259 | /* callback functions */ | ||
260 | struct brcmf_sdioh_driver { | ||
261 | /* attach to device */ | ||
262 | void *(*attach) (u16 vend_id, u16 dev_id, u16 bus, u16 slot, | ||
263 | u16 func, uint bustype, u32 regsva, void *param); | ||
264 | /* detach from device */ | ||
265 | void (*detach) (void *ch); | ||
266 | }; | ||
267 | |||
268 | struct sdioh_info; | ||
269 | |||
270 | /* platform specific/high level functions */ | ||
271 | extern int brcmf_sdio_function_init(void); | ||
272 | extern int brcmf_sdio_register(struct brcmf_sdioh_driver *driver); | ||
273 | extern void brcmf_sdio_unregister(void); | ||
274 | extern void brcmf_sdio_function_cleanup(void); | ||
275 | extern int brcmf_sdio_probe(struct device *dev); | ||
276 | extern int brcmf_sdio_remove(struct device *dev); | ||
277 | |||
278 | /* Function to return current window addr */ | ||
279 | extern u32 brcmf_sdcard_cur_sbwad(struct brcmf_sdio_card *card); | ||
280 | |||
281 | /* Allocate/init/free per-OS private data */ | ||
282 | extern int brcmf_sdioh_osinit(struct sdioh_info *sd); | ||
283 | extern void brcmf_sdioh_osfree(struct sdioh_info *sd); | ||
284 | |||
285 | /* Core interrupt enable/disable of device interrupts */ | ||
286 | extern void brcmf_sdioh_dev_intr_on(struct sdioh_info *sd); | ||
287 | extern void brcmf_sdioh_dev_intr_off(struct sdioh_info *sd); | ||
288 | |||
289 | /* attach, return handler on success, NULL if failed. | ||
290 | * The handler shall be provided by all subsequent calls. No local cache | ||
291 | * cfghdl points to the starting address of pci device mapped memory | ||
292 | */ | ||
293 | extern struct sdioh_info *brcmf_sdioh_attach(void *cfghdl, uint irq); | ||
294 | extern int brcmf_sdioh_detach(struct sdioh_info *si); | ||
295 | |||
296 | extern int | ||
297 | brcmf_sdioh_interrupt_register(struct sdioh_info *si, | ||
298 | void (*sdioh_cb_fn)(void *), void *argh); | ||
299 | |||
300 | extern int brcmf_sdioh_interrupt_deregister(struct sdioh_info *si); | ||
301 | |||
302 | /* enable or disable SD interrupt */ | ||
303 | extern int | ||
304 | brcmf_sdioh_interrupt_set(struct sdioh_info *si, bool enable_disable); | ||
305 | |||
306 | /* read or write one byte using cmd52 */ | ||
307 | extern int | ||
308 | brcmf_sdioh_request_byte(struct sdioh_info *si, uint rw, uint fnc, uint addr, | ||
309 | u8 *byte); | ||
310 | |||
311 | /* read or write 2/4 bytes using cmd53 */ | ||
312 | extern int | ||
313 | brcmf_sdioh_request_word(struct sdioh_info *si, uint cmd_type, | ||
314 | uint rw, uint fnc, uint addr, | ||
315 | u32 *word, uint nbyte); | ||
316 | |||
317 | /* read or write any buffer using cmd53 */ | ||
318 | extern int | ||
319 | brcmf_sdioh_request_buffer(struct sdioh_info *si, uint pio_dma, | ||
320 | uint fix_inc, uint rw, uint fnc_num, | ||
321 | u32 addr, uint regwidth, | ||
322 | u32 buflen, u8 *buffer, struct sk_buff *pkt); | ||
323 | |||
324 | /* get cis data */ | ||
325 | extern int | ||
326 | brcmf_sdioh_cis_read(struct sdioh_info *si, uint fuc, u8 *cis, u32 length); | ||
327 | |||
328 | extern int | ||
329 | brcmf_sdioh_cfg_read(struct sdioh_info *si, uint fuc, u32 addr, u8 *data); | ||
330 | extern int | ||
331 | brcmf_sdioh_cfg_write(struct sdioh_info *si, uint fuc, u32 addr, u8 *data); | ||
332 | |||
333 | /* handle iovars */ | ||
334 | extern int brcmf_sdioh_iovar_op(struct sdioh_info *si, const char *name, | ||
335 | void *params, int plen, void *arg, int len, bool set); | ||
336 | |||
337 | /* Issue abort to the specified function and clear controller as needed */ | ||
338 | extern int brcmf_sdioh_abort(struct sdioh_info *si, uint fnc); | ||
339 | |||
340 | /* Watchdog timer interface for pm ops */ | ||
341 | extern void brcmf_sdio_wdtmr_enable(bool enable); | ||
342 | |||
343 | extern uint sd_msglevel; /* Debug message level */ | ||
344 | |||
345 | extern struct brcmf_sdmmc_instance *gInstance; | ||
346 | |||
347 | #endif /* _BRCM_SDH_H_ */ | ||
diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c new file mode 100644 index 00000000000..821206d3e53 --- /dev/null +++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c | |||
@@ -0,0 +1,4152 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/if_arp.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/kthread.h> | ||
21 | #include <linux/netdevice.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/etherdevice.h> | ||
24 | #include <linux/wireless.h> | ||
25 | #include <linux/ieee80211.h> | ||
26 | #include <linux/mmc/sdio_func.h> | ||
27 | #include <linux/uaccess.h> | ||
28 | #include <net/cfg80211.h> | ||
29 | #include <net/rtnetlink.h> | ||
30 | |||
31 | #include <brcmu_utils.h> | ||
32 | #include <defs.h> | ||
33 | #include <brcmu_wifi.h> | ||
34 | #include "dhd.h" | ||
35 | #include "wl_cfg80211.h" | ||
36 | |||
37 | static struct sdio_func *cfg80211_sdio_func; | ||
38 | static struct brcmf_cfg80211_dev *cfg80211_dev; | ||
39 | static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255}; | ||
40 | |||
41 | u32 brcmf_dbg_level = WL_DBG_ERR; | ||
42 | |||
43 | /* | ||
44 | ** cfg80211_ops api/callback list | ||
45 | */ | ||
46 | static s32 brcmf_cfg80211_change_iface(struct wiphy *wiphy, | ||
47 | struct net_device *ndev, | ||
48 | enum nl80211_iftype type, u32 *flags, | ||
49 | struct vif_params *params); | ||
50 | static s32 __brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, | ||
51 | struct cfg80211_scan_request *request, | ||
52 | struct cfg80211_ssid *this_ssid); | ||
53 | static s32 brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, | ||
54 | struct cfg80211_scan_request *request); | ||
55 | static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); | ||
56 | static s32 brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, | ||
57 | struct cfg80211_ibss_params *params); | ||
58 | static s32 brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, | ||
59 | struct net_device *dev); | ||
60 | static s32 brcmf_cfg80211_get_station(struct wiphy *wiphy, | ||
61 | struct net_device *dev, u8 *mac, | ||
62 | struct station_info *sinfo); | ||
63 | static s32 brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, | ||
64 | struct net_device *dev, bool enabled, | ||
65 | s32 timeout); | ||
66 | static s32 brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, | ||
67 | struct net_device *dev, | ||
68 | const u8 *addr, | ||
69 | const struct cfg80211_bitrate_mask | ||
70 | *mask); | ||
71 | static int brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | ||
72 | struct cfg80211_connect_params *sme); | ||
73 | static s32 brcmf_cfg80211_disconnect(struct wiphy *wiphy, | ||
74 | struct net_device *dev, | ||
75 | u16 reason_code); | ||
76 | static s32 brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, | ||
77 | enum nl80211_tx_power_setting type, | ||
78 | s32 dbm); | ||
79 | static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm); | ||
80 | static s32 brcmf_cfg80211_config_default_key(struct wiphy *wiphy, | ||
81 | struct net_device *dev, u8 key_idx, | ||
82 | bool unicast, bool multicast); | ||
83 | static s32 brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, | ||
84 | u8 key_idx, bool pairwise, const u8 *mac_addr, | ||
85 | struct key_params *params); | ||
86 | static s32 brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, | ||
87 | u8 key_idx, bool pairwise, const u8 *mac_addr); | ||
88 | static s32 brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, | ||
89 | u8 key_idx, bool pairwise, const u8 *mac_addr, | ||
90 | void *cookie, void (*callback) (void *cookie, | ||
91 | struct | ||
92 | key_params * | ||
93 | params)); | ||
94 | static s32 brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, | ||
95 | struct net_device *dev, | ||
96 | u8 key_idx); | ||
97 | static s32 brcmf_cfg80211_resume(struct wiphy *wiphy); | ||
98 | static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, | ||
99 | struct cfg80211_wowlan *wow); | ||
100 | static s32 brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, | ||
101 | struct cfg80211_pmksa *pmksa); | ||
102 | static s32 brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, | ||
103 | struct cfg80211_pmksa *pmksa); | ||
104 | static s32 brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, | ||
105 | struct net_device *dev); | ||
106 | /* | ||
107 | ** event & event Q handlers for cfg80211 interfaces | ||
108 | */ | ||
109 | static s32 brcmf_create_event_handler(struct brcmf_cfg80211_priv *cfg_priv); | ||
110 | static void brcmf_destroy_event_handler(struct brcmf_cfg80211_priv *cfg_priv); | ||
111 | static s32 brcmf_event_handler(void *data); | ||
112 | static void brcmf_init_eq(struct brcmf_cfg80211_priv *cfg_priv); | ||
113 | static void brcmf_flush_eq(struct brcmf_cfg80211_priv *cfg_priv); | ||
114 | static void brcmf_lock_eq(struct brcmf_cfg80211_priv *cfg_priv); | ||
115 | static void brcmf_unlock_eq(struct brcmf_cfg80211_priv *cfg_priv); | ||
116 | static void brcmf_init_eq_lock(struct brcmf_cfg80211_priv *cfg_priv); | ||
117 | static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el); | ||
118 | static struct brcmf_cfg80211_event_q * | ||
119 | brcmf_deq_event(struct brcmf_cfg80211_priv *cfg_priv); | ||
120 | static s32 brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 type, | ||
121 | const struct brcmf_event_msg *msg, void *data); | ||
122 | static void brcmf_put_event(struct brcmf_cfg80211_event_q *e); | ||
123 | static void brcmf_wakeup_event(struct brcmf_cfg80211_priv *cfg_priv); | ||
124 | static s32 brcmf_notify_connect_status(struct brcmf_cfg80211_priv *cfg_priv, | ||
125 | struct net_device *ndev, | ||
126 | const struct brcmf_event_msg *e, | ||
127 | void *data); | ||
128 | static s32 brcmf_notify_roaming_status(struct brcmf_cfg80211_priv *cfg_priv, | ||
129 | struct net_device *ndev, | ||
130 | const struct brcmf_event_msg *e, | ||
131 | void *data); | ||
132 | static s32 brcmf_notify_scan_status(struct brcmf_cfg80211_priv *cfg_priv, | ||
133 | struct net_device *ndev, | ||
134 | const struct brcmf_event_msg *e, | ||
135 | void *data); | ||
136 | static s32 brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv, | ||
137 | struct net_device *ndev, | ||
138 | const struct brcmf_event_msg *e, void *data, | ||
139 | bool completed); | ||
140 | static s32 brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv, | ||
141 | struct net_device *ndev, | ||
142 | const struct brcmf_event_msg *e, void *data); | ||
143 | static s32 brcmf_notify_mic_status(struct brcmf_cfg80211_priv *cfg_priv, | ||
144 | struct net_device *ndev, | ||
145 | const struct brcmf_event_msg *e, void *data); | ||
146 | |||
147 | /* | ||
148 | ** register/deregister sdio function | ||
149 | */ | ||
150 | static void brcmf_clear_sdio_func(void); | ||
151 | |||
152 | /* | ||
153 | ** ioctl utilites | ||
154 | */ | ||
155 | static s32 brcmf_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf, | ||
156 | s32 buf_len); | ||
157 | static __used s32 brcmf_dev_bufvar_set(struct net_device *dev, s8 *name, | ||
158 | s8 *buf, s32 len); | ||
159 | static s32 brcmf_dev_intvar_set(struct net_device *dev, s8 *name, s32 val); | ||
160 | static s32 brcmf_dev_intvar_get(struct net_device *dev, s8 *name, | ||
161 | s32 *retval); | ||
162 | static s32 brcmf_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, | ||
163 | u32 len); | ||
164 | |||
165 | /* | ||
166 | ** cfg80211 set_wiphy_params utilities | ||
167 | */ | ||
168 | static s32 brcmf_set_frag(struct net_device *dev, u32 frag_threshold); | ||
169 | static s32 brcmf_set_rts(struct net_device *dev, u32 frag_threshold); | ||
170 | static s32 brcmf_set_retry(struct net_device *dev, u32 retry, bool l); | ||
171 | |||
172 | /* | ||
173 | ** wl profile utilities | ||
174 | */ | ||
175 | static s32 brcmf_update_prof(struct brcmf_cfg80211_priv *cfg_priv, | ||
176 | const struct brcmf_event_msg *e, | ||
177 | void *data, s32 item); | ||
178 | static void *brcmf_read_prof(struct brcmf_cfg80211_priv *cfg_priv, s32 item); | ||
179 | static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof); | ||
180 | |||
181 | /* | ||
182 | ** cfg80211 connect utilites | ||
183 | */ | ||
184 | static s32 brcmf_set_wpa_version(struct net_device *dev, | ||
185 | struct cfg80211_connect_params *sme); | ||
186 | static s32 brcmf_set_auth_type(struct net_device *dev, | ||
187 | struct cfg80211_connect_params *sme); | ||
188 | static s32 brcmf_set_set_cipher(struct net_device *dev, | ||
189 | struct cfg80211_connect_params *sme); | ||
190 | static s32 brcmf_set_key_mgmt(struct net_device *dev, | ||
191 | struct cfg80211_connect_params *sme); | ||
192 | static s32 brcmf_set_set_sharedkey(struct net_device *dev, | ||
193 | struct cfg80211_connect_params *sme); | ||
194 | static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv); | ||
195 | static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv); | ||
196 | static void brcmf_ch_to_chanspec(int ch, | ||
197 | struct brcmf_join_params *join_params, size_t *join_params_size); | ||
198 | |||
199 | /* | ||
200 | ** information element utilities | ||
201 | */ | ||
202 | static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv, | ||
203 | u8 t, u8 l, u8 *v); | ||
204 | static s32 brcmf_mode_to_nl80211_iftype(s32 mode); | ||
205 | static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface, | ||
206 | struct device *dev); | ||
207 | static void brcmf_free_wdev(struct brcmf_cfg80211_priv *cfg_priv); | ||
208 | static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv); | ||
209 | static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv, | ||
210 | struct brcmf_bss_info *bi); | ||
211 | static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv); | ||
212 | static s32 brcmf_add_keyext(struct wiphy *wiphy, struct net_device *dev, | ||
213 | u8 key_idx, const u8 *mac_addr, | ||
214 | struct key_params *params); | ||
215 | |||
216 | /* | ||
217 | ** key indianess swap utilities | ||
218 | */ | ||
219 | static void swap_key_from_BE(struct brcmf_wsec_key *key); | ||
220 | static void swap_key_to_BE(struct brcmf_wsec_key *key); | ||
221 | |||
222 | /* | ||
223 | ** brcmf_cfg80211_priv memory init/deinit utilities | ||
224 | */ | ||
225 | static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_priv *cfg_priv); | ||
226 | static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv); | ||
227 | |||
228 | static void brcmf_delay(u32 ms); | ||
229 | |||
230 | /* | ||
231 | ** store/restore cfg80211 instance data | ||
232 | */ | ||
233 | static void brcmf_set_drvdata(struct brcmf_cfg80211_dev *dev, void *data); | ||
234 | static void *brcmf_get_drvdata(struct brcmf_cfg80211_dev *dev); | ||
235 | |||
236 | /* | ||
237 | ** ibss mode utilities | ||
238 | */ | ||
239 | static bool brcmf_is_ibssmode(struct brcmf_cfg80211_priv *cfg_priv); | ||
240 | |||
241 | /* | ||
242 | ** dongle up/down , default configuration utilities | ||
243 | */ | ||
244 | static bool brcmf_is_linkdown(struct brcmf_cfg80211_priv *cfg_priv, | ||
245 | const struct brcmf_event_msg *e); | ||
246 | static bool brcmf_is_linkup(struct brcmf_cfg80211_priv *cfg_priv, | ||
247 | const struct brcmf_event_msg *e); | ||
248 | static bool brcmf_is_nonetwork(struct brcmf_cfg80211_priv *cfg_priv, | ||
249 | const struct brcmf_event_msg *e); | ||
250 | static void brcmf_link_down(struct brcmf_cfg80211_priv *cfg_priv); | ||
251 | static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype); | ||
252 | static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_priv *cfg_priv); | ||
253 | static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_priv *cfg_priv); | ||
254 | static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_priv *cfg_priv); | ||
255 | static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf); | ||
256 | |||
257 | /* | ||
258 | ** dongle configuration utilities | ||
259 | */ | ||
260 | static s32 brcmf_dongle_eventmsg(struct net_device *ndev); | ||
261 | static s32 brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, | ||
262 | s32 scan_unassoc_time, s32 scan_passive_time); | ||
263 | static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv, | ||
264 | bool need_lock); | ||
265 | static s32 brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, | ||
266 | u32 bcn_timeout); | ||
267 | |||
268 | /* | ||
269 | ** iscan handler | ||
270 | */ | ||
271 | static void brcmf_iscan_timer(unsigned long data); | ||
272 | static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv); | ||
273 | static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv); | ||
274 | static s32 brcmf_iscan_thread(void *data); | ||
275 | static s32 brcmf_dev_iovar_setbuf(struct net_device *dev, s8 *iovar, | ||
276 | void *param, s32 paramlen, void *bufptr, | ||
277 | s32 buflen); | ||
278 | static s32 brcmf_dev_iovar_getbuf(struct net_device *dev, s8 *iovar, | ||
279 | void *param, s32 paramlen, void *bufptr, | ||
280 | s32 buflen); | ||
281 | static s32 brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan, | ||
282 | struct brcmf_ssid *ssid, u16 action); | ||
283 | static s32 brcmf_do_iscan(struct brcmf_cfg80211_priv *cfg_priv); | ||
284 | static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan); | ||
285 | static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_priv *cfg_priv); | ||
286 | static s32 brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, | ||
287 | u32 *status, | ||
288 | struct brcmf_scan_results **bss_list); | ||
289 | static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan, | ||
290 | bool aborted); | ||
291 | static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el); | ||
292 | static s32 brcmf_iscan_done(struct brcmf_cfg80211_priv *cfg_priv); | ||
293 | static s32 brcmf_iscan_pending(struct brcmf_cfg80211_priv *cfg_priv); | ||
294 | static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_priv *cfg_priv); | ||
295 | static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_priv *cfg_priv); | ||
296 | |||
297 | /* | ||
298 | * find most significant bit set | ||
299 | */ | ||
300 | static __used u32 brcmf_find_msb(u16 bit16); | ||
301 | |||
302 | /* | ||
303 | * update pmklist to dongle | ||
304 | */ | ||
305 | static __used s32 brcmf_update_pmklist(struct net_device *dev, | ||
306 | struct brcmf_cfg80211_pmk_list *pmk_list, | ||
307 | s32 err); | ||
308 | |||
309 | static void brcmf_set_mpc(struct net_device *ndev, int mpc); | ||
310 | |||
311 | /* | ||
312 | * debufs support | ||
313 | */ | ||
314 | static int | ||
315 | brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_priv *cfg_priv); | ||
316 | static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_priv *cfg_priv); | ||
317 | |||
318 | #define WL_PRIV_GET() \ | ||
319 | ({ \ | ||
320 | struct brcmf_cfg80211_iface *ci = brcmf_get_drvdata(cfg80211_dev); \ | ||
321 | if (unlikely(!ci)) { \ | ||
322 | WL_ERR("wl_cfg80211_dev is unavailable\n"); \ | ||
323 | BUG(); \ | ||
324 | } \ | ||
325 | ci->cfg_priv; \ | ||
326 | }) | ||
327 | |||
328 | #define CHECK_SYS_UP() \ | ||
329 | do { \ | ||
330 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); \ | ||
331 | if (unlikely(!test_bit(WL_STATUS_READY, &cfg_priv->status))) { \ | ||
332 | WL_INFO("device is not ready : status (%d)\n", \ | ||
333 | (int)cfg_priv->status); \ | ||
334 | return -EIO; \ | ||
335 | } \ | ||
336 | } while (0) | ||
337 | |||
338 | #define CHAN2G(_channel, _freq, _flags) { \ | ||
339 | .band = IEEE80211_BAND_2GHZ, \ | ||
340 | .center_freq = (_freq), \ | ||
341 | .hw_value = (_channel), \ | ||
342 | .flags = (_flags), \ | ||
343 | .max_antenna_gain = 0, \ | ||
344 | .max_power = 30, \ | ||
345 | } | ||
346 | |||
347 | #define CHAN5G(_channel, _flags) { \ | ||
348 | .band = IEEE80211_BAND_5GHZ, \ | ||
349 | .center_freq = 5000 + (5 * (_channel)), \ | ||
350 | .hw_value = (_channel), \ | ||
351 | .flags = (_flags), \ | ||
352 | .max_antenna_gain = 0, \ | ||
353 | .max_power = 30, \ | ||
354 | } | ||
355 | |||
356 | #define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2) | ||
357 | #define RATETAB_ENT(_rateid, _flags) \ | ||
358 | { \ | ||
359 | .bitrate = RATE_TO_BASE100KBPS(_rateid), \ | ||
360 | .hw_value = (_rateid), \ | ||
361 | .flags = (_flags), \ | ||
362 | } | ||
363 | |||
364 | static struct ieee80211_rate __wl_rates[] = { | ||
365 | RATETAB_ENT(BRCM_RATE_1M, 0), | ||
366 | RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE), | ||
367 | RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE), | ||
368 | RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE), | ||
369 | RATETAB_ENT(BRCM_RATE_6M, 0), | ||
370 | RATETAB_ENT(BRCM_RATE_9M, 0), | ||
371 | RATETAB_ENT(BRCM_RATE_12M, 0), | ||
372 | RATETAB_ENT(BRCM_RATE_18M, 0), | ||
373 | RATETAB_ENT(BRCM_RATE_24M, 0), | ||
374 | RATETAB_ENT(BRCM_RATE_36M, 0), | ||
375 | RATETAB_ENT(BRCM_RATE_48M, 0), | ||
376 | RATETAB_ENT(BRCM_RATE_54M, 0), | ||
377 | }; | ||
378 | |||
379 | #define wl_a_rates (__wl_rates + 4) | ||
380 | #define wl_a_rates_size 8 | ||
381 | #define wl_g_rates (__wl_rates + 0) | ||
382 | #define wl_g_rates_size 12 | ||
383 | |||
384 | static struct ieee80211_channel __wl_2ghz_channels[] = { | ||
385 | CHAN2G(1, 2412, 0), | ||
386 | CHAN2G(2, 2417, 0), | ||
387 | CHAN2G(3, 2422, 0), | ||
388 | CHAN2G(4, 2427, 0), | ||
389 | CHAN2G(5, 2432, 0), | ||
390 | CHAN2G(6, 2437, 0), | ||
391 | CHAN2G(7, 2442, 0), | ||
392 | CHAN2G(8, 2447, 0), | ||
393 | CHAN2G(9, 2452, 0), | ||
394 | CHAN2G(10, 2457, 0), | ||
395 | CHAN2G(11, 2462, 0), | ||
396 | CHAN2G(12, 2467, 0), | ||
397 | CHAN2G(13, 2472, 0), | ||
398 | CHAN2G(14, 2484, 0), | ||
399 | }; | ||
400 | |||
401 | static struct ieee80211_channel __wl_5ghz_a_channels[] = { | ||
402 | CHAN5G(34, 0), CHAN5G(36, 0), | ||
403 | CHAN5G(38, 0), CHAN5G(40, 0), | ||
404 | CHAN5G(42, 0), CHAN5G(44, 0), | ||
405 | CHAN5G(46, 0), CHAN5G(48, 0), | ||
406 | CHAN5G(52, 0), CHAN5G(56, 0), | ||
407 | CHAN5G(60, 0), CHAN5G(64, 0), | ||
408 | CHAN5G(100, 0), CHAN5G(104, 0), | ||
409 | CHAN5G(108, 0), CHAN5G(112, 0), | ||
410 | CHAN5G(116, 0), CHAN5G(120, 0), | ||
411 | CHAN5G(124, 0), CHAN5G(128, 0), | ||
412 | CHAN5G(132, 0), CHAN5G(136, 0), | ||
413 | CHAN5G(140, 0), CHAN5G(149, 0), | ||
414 | CHAN5G(153, 0), CHAN5G(157, 0), | ||
415 | CHAN5G(161, 0), CHAN5G(165, 0), | ||
416 | CHAN5G(184, 0), CHAN5G(188, 0), | ||
417 | CHAN5G(192, 0), CHAN5G(196, 0), | ||
418 | CHAN5G(200, 0), CHAN5G(204, 0), | ||
419 | CHAN5G(208, 0), CHAN5G(212, 0), | ||
420 | CHAN5G(216, 0), | ||
421 | }; | ||
422 | |||
423 | static struct ieee80211_channel __wl_5ghz_n_channels[] = { | ||
424 | CHAN5G(32, 0), CHAN5G(34, 0), | ||
425 | CHAN5G(36, 0), CHAN5G(38, 0), | ||
426 | CHAN5G(40, 0), CHAN5G(42, 0), | ||
427 | CHAN5G(44, 0), CHAN5G(46, 0), | ||
428 | CHAN5G(48, 0), CHAN5G(50, 0), | ||
429 | CHAN5G(52, 0), CHAN5G(54, 0), | ||
430 | CHAN5G(56, 0), CHAN5G(58, 0), | ||
431 | CHAN5G(60, 0), CHAN5G(62, 0), | ||
432 | CHAN5G(64, 0), CHAN5G(66, 0), | ||
433 | CHAN5G(68, 0), CHAN5G(70, 0), | ||
434 | CHAN5G(72, 0), CHAN5G(74, 0), | ||
435 | CHAN5G(76, 0), CHAN5G(78, 0), | ||
436 | CHAN5G(80, 0), CHAN5G(82, 0), | ||
437 | CHAN5G(84, 0), CHAN5G(86, 0), | ||
438 | CHAN5G(88, 0), CHAN5G(90, 0), | ||
439 | CHAN5G(92, 0), CHAN5G(94, 0), | ||
440 | CHAN5G(96, 0), CHAN5G(98, 0), | ||
441 | CHAN5G(100, 0), CHAN5G(102, 0), | ||
442 | CHAN5G(104, 0), CHAN5G(106, 0), | ||
443 | CHAN5G(108, 0), CHAN5G(110, 0), | ||
444 | CHAN5G(112, 0), CHAN5G(114, 0), | ||
445 | CHAN5G(116, 0), CHAN5G(118, 0), | ||
446 | CHAN5G(120, 0), CHAN5G(122, 0), | ||
447 | CHAN5G(124, 0), CHAN5G(126, 0), | ||
448 | CHAN5G(128, 0), CHAN5G(130, 0), | ||
449 | CHAN5G(132, 0), CHAN5G(134, 0), | ||
450 | CHAN5G(136, 0), CHAN5G(138, 0), | ||
451 | CHAN5G(140, 0), CHAN5G(142, 0), | ||
452 | CHAN5G(144, 0), CHAN5G(145, 0), | ||
453 | CHAN5G(146, 0), CHAN5G(147, 0), | ||
454 | CHAN5G(148, 0), CHAN5G(149, 0), | ||
455 | CHAN5G(150, 0), CHAN5G(151, 0), | ||
456 | CHAN5G(152, 0), CHAN5G(153, 0), | ||
457 | CHAN5G(154, 0), CHAN5G(155, 0), | ||
458 | CHAN5G(156, 0), CHAN5G(157, 0), | ||
459 | CHAN5G(158, 0), CHAN5G(159, 0), | ||
460 | CHAN5G(160, 0), CHAN5G(161, 0), | ||
461 | CHAN5G(162, 0), CHAN5G(163, 0), | ||
462 | CHAN5G(164, 0), CHAN5G(165, 0), | ||
463 | CHAN5G(166, 0), CHAN5G(168, 0), | ||
464 | CHAN5G(170, 0), CHAN5G(172, 0), | ||
465 | CHAN5G(174, 0), CHAN5G(176, 0), | ||
466 | CHAN5G(178, 0), CHAN5G(180, 0), | ||
467 | CHAN5G(182, 0), CHAN5G(184, 0), | ||
468 | CHAN5G(186, 0), CHAN5G(188, 0), | ||
469 | CHAN5G(190, 0), CHAN5G(192, 0), | ||
470 | CHAN5G(194, 0), CHAN5G(196, 0), | ||
471 | CHAN5G(198, 0), CHAN5G(200, 0), | ||
472 | CHAN5G(202, 0), CHAN5G(204, 0), | ||
473 | CHAN5G(206, 0), CHAN5G(208, 0), | ||
474 | CHAN5G(210, 0), CHAN5G(212, 0), | ||
475 | CHAN5G(214, 0), CHAN5G(216, 0), | ||
476 | CHAN5G(218, 0), CHAN5G(220, 0), | ||
477 | CHAN5G(222, 0), CHAN5G(224, 0), | ||
478 | CHAN5G(226, 0), CHAN5G(228, 0), | ||
479 | }; | ||
480 | |||
481 | static struct ieee80211_supported_band __wl_band_2ghz = { | ||
482 | .band = IEEE80211_BAND_2GHZ, | ||
483 | .channels = __wl_2ghz_channels, | ||
484 | .n_channels = ARRAY_SIZE(__wl_2ghz_channels), | ||
485 | .bitrates = wl_g_rates, | ||
486 | .n_bitrates = wl_g_rates_size, | ||
487 | }; | ||
488 | |||
489 | static struct ieee80211_supported_band __wl_band_5ghz_a = { | ||
490 | .band = IEEE80211_BAND_5GHZ, | ||
491 | .channels = __wl_5ghz_a_channels, | ||
492 | .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels), | ||
493 | .bitrates = wl_a_rates, | ||
494 | .n_bitrates = wl_a_rates_size, | ||
495 | }; | ||
496 | |||
497 | static struct ieee80211_supported_band __wl_band_5ghz_n = { | ||
498 | .band = IEEE80211_BAND_5GHZ, | ||
499 | .channels = __wl_5ghz_n_channels, | ||
500 | .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels), | ||
501 | .bitrates = wl_a_rates, | ||
502 | .n_bitrates = wl_a_rates_size, | ||
503 | }; | ||
504 | |||
505 | static const u32 __wl_cipher_suites[] = { | ||
506 | WLAN_CIPHER_SUITE_WEP40, | ||
507 | WLAN_CIPHER_SUITE_WEP104, | ||
508 | WLAN_CIPHER_SUITE_TKIP, | ||
509 | WLAN_CIPHER_SUITE_CCMP, | ||
510 | WLAN_CIPHER_SUITE_AES_CMAC, | ||
511 | }; | ||
512 | |||
513 | static void swap_key_from_BE(struct brcmf_wsec_key *key) | ||
514 | { | ||
515 | key->index = cpu_to_le32(key->index); | ||
516 | key->len = cpu_to_le32(key->len); | ||
517 | key->algo = cpu_to_le32(key->algo); | ||
518 | key->flags = cpu_to_le32(key->flags); | ||
519 | key->rxiv.hi = cpu_to_le32(key->rxiv.hi); | ||
520 | key->rxiv.lo = cpu_to_le16(key->rxiv.lo); | ||
521 | key->iv_initialized = cpu_to_le32(key->iv_initialized); | ||
522 | } | ||
523 | |||
524 | static void swap_key_to_BE(struct brcmf_wsec_key *key) | ||
525 | { | ||
526 | key->index = le32_to_cpu(key->index); | ||
527 | key->len = le32_to_cpu(key->len); | ||
528 | key->algo = le32_to_cpu(key->algo); | ||
529 | key->flags = le32_to_cpu(key->flags); | ||
530 | key->rxiv.hi = le32_to_cpu(key->rxiv.hi); | ||
531 | key->rxiv.lo = le16_to_cpu(key->rxiv.lo); | ||
532 | key->iv_initialized = le32_to_cpu(key->iv_initialized); | ||
533 | } | ||
534 | |||
535 | static s32 | ||
536 | brcmf_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len) | ||
537 | { | ||
538 | struct ifreq ifr; | ||
539 | struct brcmf_ioctl ioc; | ||
540 | mm_segment_t fs; | ||
541 | s32 err = 0; | ||
542 | |||
543 | memset(&ioc, 0, sizeof(ioc)); | ||
544 | ioc.cmd = cmd; | ||
545 | ioc.buf = arg; | ||
546 | ioc.len = len; | ||
547 | strcpy(ifr.ifr_name, dev->name); | ||
548 | ifr.ifr_data = (caddr_t)&ioc; | ||
549 | |||
550 | fs = get_fs(); | ||
551 | set_fs(get_ds()); | ||
552 | err = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); | ||
553 | set_fs(fs); | ||
554 | |||
555 | return err; | ||
556 | } | ||
557 | |||
558 | static s32 | ||
559 | brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, | ||
560 | enum nl80211_iftype type, u32 *flags, | ||
561 | struct vif_params *params) | ||
562 | { | ||
563 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); | ||
564 | struct wireless_dev *wdev; | ||
565 | s32 infra = 0; | ||
566 | s32 err = 0; | ||
567 | |||
568 | WL_TRACE("Enter\n"); | ||
569 | CHECK_SYS_UP(); | ||
570 | |||
571 | switch (type) { | ||
572 | case NL80211_IFTYPE_MONITOR: | ||
573 | case NL80211_IFTYPE_WDS: | ||
574 | WL_ERR("type (%d) : currently we do not support this type\n", | ||
575 | type); | ||
576 | return -EOPNOTSUPP; | ||
577 | case NL80211_IFTYPE_ADHOC: | ||
578 | cfg_priv->conf->mode = WL_MODE_IBSS; | ||
579 | infra = 0; | ||
580 | break; | ||
581 | case NL80211_IFTYPE_STATION: | ||
582 | cfg_priv->conf->mode = WL_MODE_BSS; | ||
583 | infra = 1; | ||
584 | break; | ||
585 | default: | ||
586 | err = -EINVAL; | ||
587 | goto done; | ||
588 | } | ||
589 | |||
590 | infra = cpu_to_le32(infra); | ||
591 | err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_INFRA, &infra, sizeof(infra)); | ||
592 | if (unlikely(err)) { | ||
593 | WL_ERR("WLC_SET_INFRA error (%d)\n", err); | ||
594 | err = -EAGAIN; | ||
595 | } else { | ||
596 | wdev = ndev->ieee80211_ptr; | ||
597 | wdev->iftype = type; | ||
598 | } | ||
599 | |||
600 | WL_INFO("IF Type = %s\n", | ||
601 | (cfg_priv->conf->mode == WL_MODE_IBSS) ? "Adhoc" : "Infra"); | ||
602 | |||
603 | done: | ||
604 | WL_TRACE("Exit\n"); | ||
605 | |||
606 | return err; | ||
607 | } | ||
608 | |||
609 | static void wl_iscan_prep(struct brcmf_scan_params *params, | ||
610 | struct brcmf_ssid *ssid) | ||
611 | { | ||
612 | memcpy(params->bssid, ether_bcast, ETH_ALEN); | ||
613 | params->bss_type = DOT11_BSSTYPE_ANY; | ||
614 | params->scan_type = 0; | ||
615 | params->nprobes = -1; | ||
616 | params->active_time = -1; | ||
617 | params->passive_time = -1; | ||
618 | params->home_time = -1; | ||
619 | params->channel_num = 0; | ||
620 | |||
621 | params->nprobes = cpu_to_le32(params->nprobes); | ||
622 | params->active_time = cpu_to_le32(params->active_time); | ||
623 | params->passive_time = cpu_to_le32(params->passive_time); | ||
624 | params->home_time = cpu_to_le32(params->home_time); | ||
625 | if (ssid && ssid->SSID_len) | ||
626 | memcpy(¶ms->ssid, ssid, sizeof(struct brcmf_ssid)); | ||
627 | |||
628 | } | ||
629 | |||
630 | static s32 | ||
631 | brcmf_dev_iovar_setbuf(struct net_device *dev, s8 * iovar, void *param, | ||
632 | s32 paramlen, void *bufptr, s32 buflen) | ||
633 | { | ||
634 | s32 iolen; | ||
635 | |||
636 | iolen = brcmu_mkiovar(iovar, param, paramlen, bufptr, buflen); | ||
637 | BUG_ON(!iolen); | ||
638 | |||
639 | return brcmf_dev_ioctl(dev, BRCMF_C_SET_VAR, bufptr, iolen); | ||
640 | } | ||
641 | |||
642 | static s32 | ||
643 | brcmf_dev_iovar_getbuf(struct net_device *dev, s8 * iovar, void *param, | ||
644 | s32 paramlen, void *bufptr, s32 buflen) | ||
645 | { | ||
646 | s32 iolen; | ||
647 | |||
648 | iolen = brcmu_mkiovar(iovar, param, paramlen, bufptr, buflen); | ||
649 | BUG_ON(!iolen); | ||
650 | |||
651 | return brcmf_dev_ioctl(dev, BRCMF_C_GET_VAR, bufptr, buflen); | ||
652 | } | ||
653 | |||
654 | static s32 | ||
655 | brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan, | ||
656 | struct brcmf_ssid *ssid, u16 action) | ||
657 | { | ||
658 | s32 params_size = (BRCMF_SCAN_PARAMS_FIXED_SIZE + | ||
659 | offsetof(struct brcmf_iscan_params, params)); | ||
660 | struct brcmf_iscan_params *params; | ||
661 | s32 err = 0; | ||
662 | |||
663 | if (ssid && ssid->SSID_len) | ||
664 | params_size += sizeof(struct brcmf_ssid); | ||
665 | params = kzalloc(params_size, GFP_KERNEL); | ||
666 | if (unlikely(!params)) | ||
667 | return -ENOMEM; | ||
668 | BUG_ON(params_size >= BRCMF_C_IOCTL_SMLEN); | ||
669 | |||
670 | wl_iscan_prep(¶ms->params, ssid); | ||
671 | |||
672 | params->version = cpu_to_le32(BRCMF_ISCAN_REQ_VERSION); | ||
673 | params->action = cpu_to_le16(action); | ||
674 | params->scan_duration = cpu_to_le16(0); | ||
675 | |||
676 | /* params_size += offsetof(struct brcmf_iscan_params, params); */ | ||
677 | err = brcmf_dev_iovar_setbuf(iscan->dev, "iscan", params, params_size, | ||
678 | iscan->ioctl_buf, BRCMF_C_IOCTL_SMLEN); | ||
679 | if (unlikely(err)) { | ||
680 | if (err == -EBUSY) { | ||
681 | WL_INFO("system busy : iscan canceled\n"); | ||
682 | } else { | ||
683 | WL_ERR("error (%d)\n", err); | ||
684 | } | ||
685 | } | ||
686 | kfree(params); | ||
687 | return err; | ||
688 | } | ||
689 | |||
690 | static s32 brcmf_do_iscan(struct brcmf_cfg80211_priv *cfg_priv) | ||
691 | { | ||
692 | struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); | ||
693 | struct net_device *ndev = cfg_to_ndev(cfg_priv); | ||
694 | struct brcmf_ssid ssid; | ||
695 | s32 passive_scan; | ||
696 | s32 err = 0; | ||
697 | |||
698 | /* Broadcast scan by default */ | ||
699 | memset(&ssid, 0, sizeof(ssid)); | ||
700 | |||
701 | iscan->state = WL_ISCAN_STATE_SCANING; | ||
702 | |||
703 | passive_scan = cfg_priv->active_scan ? 0 : 1; | ||
704 | err = brcmf_dev_ioctl(cfg_to_ndev(cfg_priv), BRCMF_C_SET_PASSIVE_SCAN, | ||
705 | &passive_scan, sizeof(passive_scan)); | ||
706 | if (unlikely(err)) { | ||
707 | WL_ERR("error (%d)\n", err); | ||
708 | return err; | ||
709 | } | ||
710 | brcmf_set_mpc(ndev, 0); | ||
711 | cfg_priv->iscan_kickstart = true; | ||
712 | brcmf_run_iscan(iscan, &ssid, BRCMF_SCAN_ACTION_START); | ||
713 | mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); | ||
714 | iscan->timer_on = 1; | ||
715 | |||
716 | return err; | ||
717 | } | ||
718 | |||
719 | static s32 | ||
720 | __brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, | ||
721 | struct cfg80211_scan_request *request, | ||
722 | struct cfg80211_ssid *this_ssid) | ||
723 | { | ||
724 | struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); | ||
725 | struct cfg80211_ssid *ssids; | ||
726 | struct brcmf_cfg80211_scan_req *sr = cfg_priv->scan_req_int; | ||
727 | s32 passive_scan; | ||
728 | bool iscan_req; | ||
729 | bool spec_scan; | ||
730 | s32 err = 0; | ||
731 | |||
732 | if (unlikely(test_bit(WL_STATUS_SCANNING, &cfg_priv->status))) { | ||
733 | WL_ERR("Scanning already : status (%lu)\n", cfg_priv->status); | ||
734 | return -EAGAIN; | ||
735 | } | ||
736 | if (unlikely(test_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status))) { | ||
737 | WL_ERR("Scanning being aborted : status (%lu)\n", | ||
738 | cfg_priv->status); | ||
739 | return -EAGAIN; | ||
740 | } | ||
741 | if (test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) { | ||
742 | WL_ERR("Connecting : status (%lu)\n", | ||
743 | cfg_priv->status); | ||
744 | return -EAGAIN; | ||
745 | } | ||
746 | |||
747 | iscan_req = false; | ||
748 | spec_scan = false; | ||
749 | if (request) { | ||
750 | /* scan bss */ | ||
751 | ssids = request->ssids; | ||
752 | if (cfg_priv->iscan_on && (!ssids || !ssids->ssid_len)) | ||
753 | iscan_req = true; | ||
754 | } else { | ||
755 | /* scan in ibss */ | ||
756 | /* we don't do iscan in ibss */ | ||
757 | ssids = this_ssid; | ||
758 | } | ||
759 | |||
760 | cfg_priv->scan_request = request; | ||
761 | set_bit(WL_STATUS_SCANNING, &cfg_priv->status); | ||
762 | if (iscan_req) { | ||
763 | err = brcmf_do_iscan(cfg_priv); | ||
764 | if (likely(!err)) | ||
765 | return err; | ||
766 | else | ||
767 | goto scan_out; | ||
768 | } else { | ||
769 | WL_SCAN("ssid \"%s\", ssid_len (%d)\n", | ||
770 | ssids->ssid, ssids->ssid_len); | ||
771 | memset(&sr->ssid, 0, sizeof(sr->ssid)); | ||
772 | sr->ssid.SSID_len = | ||
773 | min_t(u8, sizeof(sr->ssid.SSID), ssids->ssid_len); | ||
774 | if (sr->ssid.SSID_len) { | ||
775 | memcpy(sr->ssid.SSID, ssids->ssid, sr->ssid.SSID_len); | ||
776 | sr->ssid.SSID_len = cpu_to_le32(sr->ssid.SSID_len); | ||
777 | spec_scan = true; | ||
778 | } else { | ||
779 | WL_SCAN("Broadcast scan\n"); | ||
780 | } | ||
781 | |||
782 | passive_scan = cfg_priv->active_scan ? 0 : 1; | ||
783 | err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_PASSIVE_SCAN, | ||
784 | &passive_scan, sizeof(passive_scan)); | ||
785 | if (unlikely(err)) { | ||
786 | WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err); | ||
787 | goto scan_out; | ||
788 | } | ||
789 | brcmf_set_mpc(ndev, 0); | ||
790 | err = brcmf_dev_ioctl(ndev, BRCMF_C_SCAN, &sr->ssid, | ||
791 | sizeof(sr->ssid)); | ||
792 | if (err) { | ||
793 | if (err == -EBUSY) { | ||
794 | WL_INFO("system busy : scan for \"%s\" canceled\n", | ||
795 | sr->ssid.SSID); | ||
796 | } else { | ||
797 | WL_ERR("WLC_SCAN error (%d)\n", err); | ||
798 | } | ||
799 | brcmf_set_mpc(ndev, 1); | ||
800 | goto scan_out; | ||
801 | } | ||
802 | } | ||
803 | |||
804 | return 0; | ||
805 | |||
806 | scan_out: | ||
807 | clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); | ||
808 | cfg_priv->scan_request = NULL; | ||
809 | return err; | ||
810 | } | ||
811 | |||
812 | static s32 | ||
813 | brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, | ||
814 | struct cfg80211_scan_request *request) | ||
815 | { | ||
816 | s32 err = 0; | ||
817 | |||
818 | WL_TRACE("Enter\n"); | ||
819 | |||
820 | CHECK_SYS_UP(); | ||
821 | |||
822 | err = __brcmf_cfg80211_scan(wiphy, ndev, request, NULL); | ||
823 | if (unlikely(err)) | ||
824 | WL_ERR("scan error (%d)\n", err); | ||
825 | |||
826 | WL_TRACE("Exit\n"); | ||
827 | return err; | ||
828 | } | ||
829 | |||
830 | static s32 brcmf_dev_intvar_set(struct net_device *dev, s8 *name, s32 val) | ||
831 | { | ||
832 | s8 buf[BRCMF_C_IOCTL_SMLEN]; | ||
833 | u32 len; | ||
834 | s32 err = 0; | ||
835 | |||
836 | val = cpu_to_le32(val); | ||
837 | len = brcmu_mkiovar(name, (char *)(&val), sizeof(val), buf, | ||
838 | sizeof(buf)); | ||
839 | BUG_ON(!len); | ||
840 | |||
841 | err = brcmf_dev_ioctl(dev, BRCMF_C_SET_VAR, buf, len); | ||
842 | if (unlikely(err)) | ||
843 | WL_ERR("error (%d)\n", err); | ||
844 | |||
845 | return err; | ||
846 | } | ||
847 | |||
848 | static s32 | ||
849 | brcmf_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval) | ||
850 | { | ||
851 | union { | ||
852 | s8 buf[BRCMF_C_IOCTL_SMLEN]; | ||
853 | s32 val; | ||
854 | } var; | ||
855 | u32 len; | ||
856 | u32 data_null; | ||
857 | s32 err = 0; | ||
858 | |||
859 | len = | ||
860 | brcmu_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), | ||
861 | sizeof(var.buf)); | ||
862 | BUG_ON(!len); | ||
863 | err = brcmf_dev_ioctl(dev, BRCMF_C_GET_VAR, &var, len); | ||
864 | if (unlikely(err)) | ||
865 | WL_ERR("error (%d)\n", err); | ||
866 | |||
867 | *retval = le32_to_cpu(var.val); | ||
868 | |||
869 | return err; | ||
870 | } | ||
871 | |||
872 | static s32 brcmf_set_rts(struct net_device *dev, u32 rts_threshold) | ||
873 | { | ||
874 | s32 err = 0; | ||
875 | |||
876 | err = brcmf_dev_intvar_set(dev, "rtsthresh", rts_threshold); | ||
877 | if (unlikely(err)) | ||
878 | WL_ERR("Error (%d)\n", err); | ||
879 | |||
880 | return err; | ||
881 | } | ||
882 | |||
883 | static s32 brcmf_set_frag(struct net_device *dev, u32 frag_threshold) | ||
884 | { | ||
885 | s32 err = 0; | ||
886 | |||
887 | err = brcmf_dev_intvar_set(dev, "fragthresh", frag_threshold); | ||
888 | if (unlikely(err)) | ||
889 | WL_ERR("Error (%d)\n", err); | ||
890 | |||
891 | return err; | ||
892 | } | ||
893 | |||
894 | static s32 brcmf_set_retry(struct net_device *dev, u32 retry, bool l) | ||
895 | { | ||
896 | s32 err = 0; | ||
897 | u32 cmd = (l ? BRCM_SET_LRL : BRCM_SET_SRL); | ||
898 | |||
899 | retry = cpu_to_le32(retry); | ||
900 | err = brcmf_dev_ioctl(dev, cmd, &retry, sizeof(retry)); | ||
901 | if (unlikely(err)) { | ||
902 | WL_ERR("cmd (%d) , error (%d)\n", cmd, err); | ||
903 | return err; | ||
904 | } | ||
905 | return err; | ||
906 | } | ||
907 | |||
908 | static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | ||
909 | { | ||
910 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); | ||
911 | struct net_device *ndev = cfg_to_ndev(cfg_priv); | ||
912 | s32 err = 0; | ||
913 | |||
914 | WL_TRACE("Enter\n"); | ||
915 | CHECK_SYS_UP(); | ||
916 | |||
917 | if (changed & WIPHY_PARAM_RTS_THRESHOLD && | ||
918 | (cfg_priv->conf->rts_threshold != wiphy->rts_threshold)) { | ||
919 | cfg_priv->conf->rts_threshold = wiphy->rts_threshold; | ||
920 | err = brcmf_set_rts(ndev, cfg_priv->conf->rts_threshold); | ||
921 | if (!err) | ||
922 | goto done; | ||
923 | } | ||
924 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD && | ||
925 | (cfg_priv->conf->frag_threshold != wiphy->frag_threshold)) { | ||
926 | cfg_priv->conf->frag_threshold = wiphy->frag_threshold; | ||
927 | err = brcmf_set_frag(ndev, cfg_priv->conf->frag_threshold); | ||
928 | if (!err) | ||
929 | goto done; | ||
930 | } | ||
931 | if (changed & WIPHY_PARAM_RETRY_LONG | ||
932 | && (cfg_priv->conf->retry_long != wiphy->retry_long)) { | ||
933 | cfg_priv->conf->retry_long = wiphy->retry_long; | ||
934 | err = brcmf_set_retry(ndev, cfg_priv->conf->retry_long, true); | ||
935 | if (!err) | ||
936 | goto done; | ||
937 | } | ||
938 | if (changed & WIPHY_PARAM_RETRY_SHORT | ||
939 | && (cfg_priv->conf->retry_short != wiphy->retry_short)) { | ||
940 | cfg_priv->conf->retry_short = wiphy->retry_short; | ||
941 | err = brcmf_set_retry(ndev, cfg_priv->conf->retry_short, false); | ||
942 | if (!err) | ||
943 | goto done; | ||
944 | } | ||
945 | |||
946 | done: | ||
947 | WL_TRACE("Exit\n"); | ||
948 | return err; | ||
949 | } | ||
950 | |||
951 | static s32 | ||
952 | brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, | ||
953 | struct cfg80211_ibss_params *params) | ||
954 | { | ||
955 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); | ||
956 | struct brcmf_join_params join_params; | ||
957 | size_t join_params_size = 0; | ||
958 | s32 err = 0; | ||
959 | s32 wsec = 0; | ||
960 | s32 bcnprd; | ||
961 | |||
962 | WL_TRACE("Enter\n"); | ||
963 | CHECK_SYS_UP(); | ||
964 | |||
965 | if (params->ssid) | ||
966 | WL_CONN("SSID: %s\n", params->ssid); | ||
967 | else { | ||
968 | WL_CONN("SSID: NULL, Not supported\n"); | ||
969 | return -EOPNOTSUPP; | ||
970 | } | ||
971 | |||
972 | set_bit(WL_STATUS_CONNECTING, &cfg_priv->status); | ||
973 | |||
974 | if (params->bssid) | ||
975 | WL_CONN("BSSID: %02X %02X %02X %02X %02X %02X\n", | ||
976 | params->bssid[0], params->bssid[1], params->bssid[2], | ||
977 | params->bssid[3], params->bssid[4], params->bssid[5]); | ||
978 | else | ||
979 | WL_CONN("No BSSID specified\n"); | ||
980 | |||
981 | if (params->channel) | ||
982 | WL_CONN("channel: %d\n", params->channel->center_freq); | ||
983 | else | ||
984 | WL_CONN("no channel specified\n"); | ||
985 | |||
986 | if (params->channel_fixed) | ||
987 | WL_CONN("fixed channel required\n"); | ||
988 | else | ||
989 | WL_CONN("no fixed channel required\n"); | ||
990 | |||
991 | if (params->ie && params->ie_len) | ||
992 | WL_CONN("ie len: %d\n", params->ie_len); | ||
993 | else | ||
994 | WL_CONN("no ie specified\n"); | ||
995 | |||
996 | if (params->beacon_interval) | ||
997 | WL_CONN("beacon interval: %d\n", params->beacon_interval); | ||
998 | else | ||
999 | WL_CONN("no beacon interval specified\n"); | ||
1000 | |||
1001 | if (params->basic_rates) | ||
1002 | WL_CONN("basic rates: %08X\n", params->basic_rates); | ||
1003 | else | ||
1004 | WL_CONN("no basic rates specified\n"); | ||
1005 | |||
1006 | if (params->privacy) | ||
1007 | WL_CONN("privacy required\n"); | ||
1008 | else | ||
1009 | WL_CONN("no privacy required\n"); | ||
1010 | |||
1011 | /* Configure Privacy for starter */ | ||
1012 | if (params->privacy) | ||
1013 | wsec |= WEP_ENABLED; | ||
1014 | |||
1015 | err = brcmf_dev_intvar_set(dev, "wsec", wsec); | ||
1016 | if (unlikely(err)) { | ||
1017 | WL_ERR("wsec failed (%d)\n", err); | ||
1018 | goto done; | ||
1019 | } | ||
1020 | |||
1021 | /* Configure Beacon Interval for starter */ | ||
1022 | if (params->beacon_interval) | ||
1023 | bcnprd = cpu_to_le32(params->beacon_interval); | ||
1024 | else | ||
1025 | bcnprd = cpu_to_le32(100); | ||
1026 | |||
1027 | err = brcmf_dev_ioctl(dev, BRCM_SET_BCNPRD, &bcnprd, sizeof(bcnprd)); | ||
1028 | if (unlikely(err)) { | ||
1029 | WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err); | ||
1030 | goto done; | ||
1031 | } | ||
1032 | |||
1033 | /* Configure required join parameter */ | ||
1034 | memset(&join_params, 0, sizeof(struct brcmf_join_params)); | ||
1035 | |||
1036 | /* SSID */ | ||
1037 | join_params.ssid.SSID_len = | ||
1038 | (params->ssid_len > 32) ? 32 : params->ssid_len; | ||
1039 | memcpy(join_params.ssid.SSID, params->ssid, join_params.ssid.SSID_len); | ||
1040 | join_params.ssid.SSID_len = cpu_to_le32(join_params.ssid.SSID_len); | ||
1041 | join_params_size = sizeof(join_params.ssid); | ||
1042 | brcmf_update_prof(cfg_priv, NULL, &join_params.ssid, WL_PROF_SSID); | ||
1043 | |||
1044 | /* BSSID */ | ||
1045 | if (params->bssid) { | ||
1046 | memcpy(join_params.params.bssid, params->bssid, ETH_ALEN); | ||
1047 | join_params_size = sizeof(join_params.ssid) + | ||
1048 | BRCMF_ASSOC_PARAMS_FIXED_SIZE; | ||
1049 | } else { | ||
1050 | memcpy(join_params.params.bssid, ether_bcast, ETH_ALEN); | ||
1051 | } | ||
1052 | brcmf_update_prof(cfg_priv, NULL, | ||
1053 | &join_params.params.bssid, WL_PROF_BSSID); | ||
1054 | |||
1055 | /* Channel */ | ||
1056 | if (params->channel) { | ||
1057 | u32 target_channel; | ||
1058 | |||
1059 | cfg_priv->channel = | ||
1060 | ieee80211_frequency_to_channel( | ||
1061 | params->channel->center_freq); | ||
1062 | if (params->channel_fixed) { | ||
1063 | /* adding chanspec */ | ||
1064 | brcmf_ch_to_chanspec(cfg_priv->channel, | ||
1065 | &join_params, &join_params_size); | ||
1066 | } | ||
1067 | |||
1068 | /* set channel for starter */ | ||
1069 | target_channel = cpu_to_le32(cfg_priv->channel); | ||
1070 | err = brcmf_dev_ioctl(dev, BRCM_SET_CHANNEL, | ||
1071 | &target_channel, sizeof(target_channel)); | ||
1072 | if (unlikely(err)) { | ||
1073 | WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err); | ||
1074 | goto done; | ||
1075 | } | ||
1076 | } else | ||
1077 | cfg_priv->channel = 0; | ||
1078 | |||
1079 | cfg_priv->ibss_starter = false; | ||
1080 | |||
1081 | |||
1082 | err = brcmf_dev_ioctl(dev, BRCMF_C_SET_SSID, | ||
1083 | &join_params, join_params_size); | ||
1084 | if (unlikely(err)) { | ||
1085 | WL_ERR("WLC_SET_SSID failed (%d)\n", err); | ||
1086 | goto done; | ||
1087 | } | ||
1088 | |||
1089 | done: | ||
1090 | if (err) | ||
1091 | clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); | ||
1092 | WL_TRACE("Exit\n"); | ||
1093 | return err; | ||
1094 | } | ||
1095 | |||
1096 | static s32 brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | ||
1097 | { | ||
1098 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); | ||
1099 | s32 err = 0; | ||
1100 | |||
1101 | WL_TRACE("Enter\n"); | ||
1102 | CHECK_SYS_UP(); | ||
1103 | |||
1104 | brcmf_link_down(cfg_priv); | ||
1105 | |||
1106 | WL_TRACE("Exit\n"); | ||
1107 | |||
1108 | return err; | ||
1109 | } | ||
1110 | |||
1111 | static s32 | ||
1112 | brcmf_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) | ||
1113 | { | ||
1114 | struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev); | ||
1115 | struct brcmf_cfg80211_security *sec; | ||
1116 | s32 val = 0; | ||
1117 | s32 err = 0; | ||
1118 | |||
1119 | if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) | ||
1120 | val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; | ||
1121 | else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) | ||
1122 | val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; | ||
1123 | else | ||
1124 | val = WPA_AUTH_DISABLED; | ||
1125 | WL_CONN("setting wpa_auth to 0x%0x\n", val); | ||
1126 | err = brcmf_dev_intvar_set(dev, "wpa_auth", val); | ||
1127 | if (unlikely(err)) { | ||
1128 | WL_ERR("set wpa_auth failed (%d)\n", err); | ||
1129 | return err; | ||
1130 | } | ||
1131 | sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); | ||
1132 | sec->wpa_versions = sme->crypto.wpa_versions; | ||
1133 | return err; | ||
1134 | } | ||
1135 | |||
1136 | static s32 | ||
1137 | brcmf_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) | ||
1138 | { | ||
1139 | struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev); | ||
1140 | struct brcmf_cfg80211_security *sec; | ||
1141 | s32 val = 0; | ||
1142 | s32 err = 0; | ||
1143 | |||
1144 | switch (sme->auth_type) { | ||
1145 | case NL80211_AUTHTYPE_OPEN_SYSTEM: | ||
1146 | val = 0; | ||
1147 | WL_CONN("open system\n"); | ||
1148 | break; | ||
1149 | case NL80211_AUTHTYPE_SHARED_KEY: | ||
1150 | val = 1; | ||
1151 | WL_CONN("shared key\n"); | ||
1152 | break; | ||
1153 | case NL80211_AUTHTYPE_AUTOMATIC: | ||
1154 | val = 2; | ||
1155 | WL_CONN("automatic\n"); | ||
1156 | break; | ||
1157 | case NL80211_AUTHTYPE_NETWORK_EAP: | ||
1158 | WL_CONN("network eap\n"); | ||
1159 | default: | ||
1160 | val = 2; | ||
1161 | WL_ERR("invalid auth type (%d)\n", sme->auth_type); | ||
1162 | break; | ||
1163 | } | ||
1164 | |||
1165 | err = brcmf_dev_intvar_set(dev, "auth", val); | ||
1166 | if (unlikely(err)) { | ||
1167 | WL_ERR("set auth failed (%d)\n", err); | ||
1168 | return err; | ||
1169 | } | ||
1170 | sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); | ||
1171 | sec->auth_type = sme->auth_type; | ||
1172 | return err; | ||
1173 | } | ||
1174 | |||
1175 | static s32 | ||
1176 | brcmf_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) | ||
1177 | { | ||
1178 | struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev); | ||
1179 | struct brcmf_cfg80211_security *sec; | ||
1180 | s32 pval = 0; | ||
1181 | s32 gval = 0; | ||
1182 | s32 err = 0; | ||
1183 | |||
1184 | if (sme->crypto.n_ciphers_pairwise) { | ||
1185 | switch (sme->crypto.ciphers_pairwise[0]) { | ||
1186 | case WLAN_CIPHER_SUITE_WEP40: | ||
1187 | case WLAN_CIPHER_SUITE_WEP104: | ||
1188 | pval = WEP_ENABLED; | ||
1189 | break; | ||
1190 | case WLAN_CIPHER_SUITE_TKIP: | ||
1191 | pval = TKIP_ENABLED; | ||
1192 | break; | ||
1193 | case WLAN_CIPHER_SUITE_CCMP: | ||
1194 | pval = AES_ENABLED; | ||
1195 | break; | ||
1196 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
1197 | pval = AES_ENABLED; | ||
1198 | break; | ||
1199 | default: | ||
1200 | WL_ERR("invalid cipher pairwise (%d)\n", | ||
1201 | sme->crypto.ciphers_pairwise[0]); | ||
1202 | return -EINVAL; | ||
1203 | } | ||
1204 | } | ||
1205 | if (sme->crypto.cipher_group) { | ||
1206 | switch (sme->crypto.cipher_group) { | ||
1207 | case WLAN_CIPHER_SUITE_WEP40: | ||
1208 | case WLAN_CIPHER_SUITE_WEP104: | ||
1209 | gval = WEP_ENABLED; | ||
1210 | break; | ||
1211 | case WLAN_CIPHER_SUITE_TKIP: | ||
1212 | gval = TKIP_ENABLED; | ||
1213 | break; | ||
1214 | case WLAN_CIPHER_SUITE_CCMP: | ||
1215 | gval = AES_ENABLED; | ||
1216 | break; | ||
1217 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
1218 | gval = AES_ENABLED; | ||
1219 | break; | ||
1220 | default: | ||
1221 | WL_ERR("invalid cipher group (%d)\n", | ||
1222 | sme->crypto.cipher_group); | ||
1223 | return -EINVAL; | ||
1224 | } | ||
1225 | } | ||
1226 | |||
1227 | WL_CONN("pval (%d) gval (%d)\n", pval, gval); | ||
1228 | err = brcmf_dev_intvar_set(dev, "wsec", pval | gval); | ||
1229 | if (unlikely(err)) { | ||
1230 | WL_ERR("error (%d)\n", err); | ||
1231 | return err; | ||
1232 | } | ||
1233 | |||
1234 | sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); | ||
1235 | sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0]; | ||
1236 | sec->cipher_group = sme->crypto.cipher_group; | ||
1237 | |||
1238 | return err; | ||
1239 | } | ||
1240 | |||
1241 | static s32 | ||
1242 | brcmf_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) | ||
1243 | { | ||
1244 | struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev); | ||
1245 | struct brcmf_cfg80211_security *sec; | ||
1246 | s32 val = 0; | ||
1247 | s32 err = 0; | ||
1248 | |||
1249 | if (sme->crypto.n_akm_suites) { | ||
1250 | err = brcmf_dev_intvar_get(dev, "wpa_auth", &val); | ||
1251 | if (unlikely(err)) { | ||
1252 | WL_ERR("could not get wpa_auth (%d)\n", err); | ||
1253 | return err; | ||
1254 | } | ||
1255 | if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { | ||
1256 | switch (sme->crypto.akm_suites[0]) { | ||
1257 | case WLAN_AKM_SUITE_8021X: | ||
1258 | val = WPA_AUTH_UNSPECIFIED; | ||
1259 | break; | ||
1260 | case WLAN_AKM_SUITE_PSK: | ||
1261 | val = WPA_AUTH_PSK; | ||
1262 | break; | ||
1263 | default: | ||
1264 | WL_ERR("invalid cipher group (%d)\n", | ||
1265 | sme->crypto.cipher_group); | ||
1266 | return -EINVAL; | ||
1267 | } | ||
1268 | } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { | ||
1269 | switch (sme->crypto.akm_suites[0]) { | ||
1270 | case WLAN_AKM_SUITE_8021X: | ||
1271 | val = WPA2_AUTH_UNSPECIFIED; | ||
1272 | break; | ||
1273 | case WLAN_AKM_SUITE_PSK: | ||
1274 | val = WPA2_AUTH_PSK; | ||
1275 | break; | ||
1276 | default: | ||
1277 | WL_ERR("invalid cipher group (%d)\n", | ||
1278 | sme->crypto.cipher_group); | ||
1279 | return -EINVAL; | ||
1280 | } | ||
1281 | } | ||
1282 | |||
1283 | WL_CONN("setting wpa_auth to %d\n", val); | ||
1284 | err = brcmf_dev_intvar_set(dev, "wpa_auth", val); | ||
1285 | if (unlikely(err)) { | ||
1286 | WL_ERR("could not set wpa_auth (%d)\n", err); | ||
1287 | return err; | ||
1288 | } | ||
1289 | } | ||
1290 | sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); | ||
1291 | sec->wpa_auth = sme->crypto.akm_suites[0]; | ||
1292 | |||
1293 | return err; | ||
1294 | } | ||
1295 | |||
1296 | static s32 | ||
1297 | brcmf_set_set_sharedkey(struct net_device *dev, | ||
1298 | struct cfg80211_connect_params *sme) | ||
1299 | { | ||
1300 | struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev); | ||
1301 | struct brcmf_cfg80211_security *sec; | ||
1302 | struct brcmf_wsec_key key; | ||
1303 | s32 val; | ||
1304 | s32 err = 0; | ||
1305 | |||
1306 | WL_CONN("key len (%d)\n", sme->key_len); | ||
1307 | if (sme->key_len) { | ||
1308 | sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); | ||
1309 | WL_CONN("wpa_versions 0x%x cipher_pairwise 0x%x\n", | ||
1310 | sec->wpa_versions, sec->cipher_pairwise); | ||
1311 | if (! | ||
1312 | (sec->wpa_versions & (NL80211_WPA_VERSION_1 | | ||
1313 | NL80211_WPA_VERSION_2)) | ||
1314 | && (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 | | ||
1315 | WLAN_CIPHER_SUITE_WEP104))) { | ||
1316 | memset(&key, 0, sizeof(key)); | ||
1317 | key.len = (u32) sme->key_len; | ||
1318 | key.index = (u32) sme->key_idx; | ||
1319 | if (unlikely(key.len > sizeof(key.data))) { | ||
1320 | WL_ERR("Too long key length (%u)\n", key.len); | ||
1321 | return -EINVAL; | ||
1322 | } | ||
1323 | memcpy(key.data, sme->key, key.len); | ||
1324 | key.flags = BRCMF_PRIMARY_KEY; | ||
1325 | switch (sec->cipher_pairwise) { | ||
1326 | case WLAN_CIPHER_SUITE_WEP40: | ||
1327 | key.algo = CRYPTO_ALGO_WEP1; | ||
1328 | break; | ||
1329 | case WLAN_CIPHER_SUITE_WEP104: | ||
1330 | key.algo = CRYPTO_ALGO_WEP128; | ||
1331 | break; | ||
1332 | default: | ||
1333 | WL_ERR("Invalid algorithm (%d)\n", | ||
1334 | sme->crypto.ciphers_pairwise[0]); | ||
1335 | return -EINVAL; | ||
1336 | } | ||
1337 | /* Set the new key/index */ | ||
1338 | WL_CONN("key length (%d) key index (%d) algo (%d)\n", | ||
1339 | key.len, key.index, key.algo); | ||
1340 | WL_CONN("key \"%s\"\n", key.data); | ||
1341 | swap_key_from_BE(&key); | ||
1342 | err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY, &key, | ||
1343 | sizeof(key)); | ||
1344 | if (unlikely(err)) { | ||
1345 | WL_ERR("WLC_SET_KEY error (%d)\n", err); | ||
1346 | return err; | ||
1347 | } | ||
1348 | if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) { | ||
1349 | WL_CONN("set auth_type to shared key\n"); | ||
1350 | val = 1; /* shared key */ | ||
1351 | err = brcmf_dev_intvar_set(dev, "auth", val); | ||
1352 | if (unlikely(err)) { | ||
1353 | WL_ERR("set auth failed (%d)\n", err); | ||
1354 | return err; | ||
1355 | } | ||
1356 | } | ||
1357 | } | ||
1358 | } | ||
1359 | return err; | ||
1360 | } | ||
1361 | |||
1362 | static s32 | ||
1363 | brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | ||
1364 | struct cfg80211_connect_params *sme) | ||
1365 | { | ||
1366 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); | ||
1367 | struct ieee80211_channel *chan = sme->channel; | ||
1368 | struct brcmf_join_params join_params; | ||
1369 | size_t join_params_size; | ||
1370 | |||
1371 | s32 err = 0; | ||
1372 | |||
1373 | WL_TRACE("Enter\n"); | ||
1374 | CHECK_SYS_UP(); | ||
1375 | |||
1376 | if (unlikely(!sme->ssid)) { | ||
1377 | WL_ERR("Invalid ssid\n"); | ||
1378 | return -EOPNOTSUPP; | ||
1379 | } | ||
1380 | |||
1381 | set_bit(WL_STATUS_CONNECTING, &cfg_priv->status); | ||
1382 | |||
1383 | if (chan) { | ||
1384 | cfg_priv->channel = | ||
1385 | ieee80211_frequency_to_channel(chan->center_freq); | ||
1386 | WL_CONN("channel (%d), center_req (%d)\n", | ||
1387 | cfg_priv->channel, chan->center_freq); | ||
1388 | } else | ||
1389 | cfg_priv->channel = 0; | ||
1390 | |||
1391 | WL_INFO("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len); | ||
1392 | |||
1393 | err = brcmf_set_wpa_version(dev, sme); | ||
1394 | if (err) { | ||
1395 | WL_ERR("wl_set_wpa_version failed (%d)\n", err); | ||
1396 | goto done; | ||
1397 | } | ||
1398 | |||
1399 | err = brcmf_set_auth_type(dev, sme); | ||
1400 | if (err) { | ||
1401 | WL_ERR("wl_set_auth_type failed (%d)\n", err); | ||
1402 | goto done; | ||
1403 | } | ||
1404 | |||
1405 | err = brcmf_set_set_cipher(dev, sme); | ||
1406 | if (err) { | ||
1407 | WL_ERR("wl_set_set_cipher failed (%d)\n", err); | ||
1408 | goto done; | ||
1409 | } | ||
1410 | |||
1411 | err = brcmf_set_key_mgmt(dev, sme); | ||
1412 | if (err) { | ||
1413 | WL_ERR("wl_set_key_mgmt failed (%d)\n", err); | ||
1414 | goto done; | ||
1415 | } | ||
1416 | |||
1417 | err = brcmf_set_set_sharedkey(dev, sme); | ||
1418 | if (err) { | ||
1419 | WL_ERR("wl_set_set_sharedkey failed (%d)\n", err); | ||
1420 | goto done; | ||
1421 | } | ||
1422 | |||
1423 | brcmf_update_prof(cfg_priv, NULL, sme->bssid, WL_PROF_BSSID); | ||
1424 | /* | ||
1425 | ** Join with specific BSSID and cached SSID | ||
1426 | ** If SSID is zero join based on BSSID only | ||
1427 | */ | ||
1428 | memset(&join_params, 0, sizeof(join_params)); | ||
1429 | join_params_size = sizeof(join_params.ssid); | ||
1430 | |||
1431 | join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len); | ||
1432 | memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len); | ||
1433 | join_params.ssid.SSID_len = cpu_to_le32(join_params.ssid.SSID_len); | ||
1434 | brcmf_update_prof(cfg_priv, NULL, &join_params.ssid, WL_PROF_SSID); | ||
1435 | |||
1436 | if (sme->bssid) | ||
1437 | memcpy(join_params.params.bssid, sme->bssid, ETH_ALEN); | ||
1438 | else | ||
1439 | memcpy(join_params.params.bssid, ether_bcast, ETH_ALEN); | ||
1440 | |||
1441 | if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { | ||
1442 | WL_CONN("ssid \"%s\", len (%d)\n", | ||
1443 | join_params.ssid.SSID, join_params.ssid.SSID_len); | ||
1444 | } | ||
1445 | |||
1446 | brcmf_ch_to_chanspec(cfg_priv->channel, | ||
1447 | &join_params, &join_params_size); | ||
1448 | err = brcmf_dev_ioctl(dev, BRCMF_C_SET_SSID, | ||
1449 | &join_params, join_params_size); | ||
1450 | if (err) | ||
1451 | WL_ERR("WLC_SET_SSID failed (%d)\n", err); | ||
1452 | |||
1453 | done: | ||
1454 | if (err) | ||
1455 | clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); | ||
1456 | WL_TRACE("Exit\n"); | ||
1457 | return err; | ||
1458 | } | ||
1459 | |||
1460 | static s32 | ||
1461 | brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, | ||
1462 | u16 reason_code) | ||
1463 | { | ||
1464 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); | ||
1465 | struct brcmf_scb_val scbval; | ||
1466 | s32 err = 0; | ||
1467 | |||
1468 | WL_TRACE("Enter. Reason code = %d\n", reason_code); | ||
1469 | CHECK_SYS_UP(); | ||
1470 | |||
1471 | clear_bit(WL_STATUS_CONNECTED, &cfg_priv->status); | ||
1472 | |||
1473 | scbval.val = reason_code; | ||
1474 | memcpy(&scbval.ea, brcmf_read_prof(cfg_priv, WL_PROF_BSSID), ETH_ALEN); | ||
1475 | scbval.val = cpu_to_le32(scbval.val); | ||
1476 | err = brcmf_dev_ioctl(dev, BRCMF_C_DISASSOC, &scbval, | ||
1477 | sizeof(struct brcmf_scb_val)); | ||
1478 | if (unlikely(err)) | ||
1479 | WL_ERR("error (%d)\n", err); | ||
1480 | |||
1481 | cfg_priv->link_up = false; | ||
1482 | |||
1483 | WL_TRACE("Exit\n"); | ||
1484 | return err; | ||
1485 | } | ||
1486 | |||
1487 | static s32 | ||
1488 | brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, | ||
1489 | enum nl80211_tx_power_setting type, s32 dbm) | ||
1490 | { | ||
1491 | |||
1492 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); | ||
1493 | struct net_device *ndev = cfg_to_ndev(cfg_priv); | ||
1494 | u16 txpwrmw; | ||
1495 | s32 err = 0; | ||
1496 | s32 disable = 0; | ||
1497 | |||
1498 | WL_TRACE("Enter\n"); | ||
1499 | CHECK_SYS_UP(); | ||
1500 | |||
1501 | switch (type) { | ||
1502 | case NL80211_TX_POWER_AUTOMATIC: | ||
1503 | break; | ||
1504 | case NL80211_TX_POWER_LIMITED: | ||
1505 | if (dbm < 0) { | ||
1506 | WL_ERR("TX_POWER_LIMITED - dbm is negative\n"); | ||
1507 | err = -EINVAL; | ||
1508 | goto done; | ||
1509 | } | ||
1510 | break; | ||
1511 | case NL80211_TX_POWER_FIXED: | ||
1512 | if (dbm < 0) { | ||
1513 | WL_ERR("TX_POWER_FIXED - dbm is negative\n"); | ||
1514 | err = -EINVAL; | ||
1515 | goto done; | ||
1516 | } | ||
1517 | break; | ||
1518 | } | ||
1519 | /* Make sure radio is off or on as far as software is concerned */ | ||
1520 | disable = WL_RADIO_SW_DISABLE << 16; | ||
1521 | disable = cpu_to_le32(disable); | ||
1522 | err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_RADIO, &disable, sizeof(disable)); | ||
1523 | if (unlikely(err)) | ||
1524 | WL_ERR("WLC_SET_RADIO error (%d)\n", err); | ||
1525 | |||
1526 | if (dbm > 0xffff) | ||
1527 | txpwrmw = 0xffff; | ||
1528 | else | ||
1529 | txpwrmw = (u16) dbm; | ||
1530 | err = brcmf_dev_intvar_set(ndev, "qtxpower", | ||
1531 | (s32) (brcmu_mw_to_qdbm(txpwrmw))); | ||
1532 | if (unlikely(err)) | ||
1533 | WL_ERR("qtxpower error (%d)\n", err); | ||
1534 | cfg_priv->conf->tx_power = dbm; | ||
1535 | |||
1536 | done: | ||
1537 | WL_TRACE("Exit\n"); | ||
1538 | return err; | ||
1539 | } | ||
1540 | |||
1541 | static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) | ||
1542 | { | ||
1543 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); | ||
1544 | struct net_device *ndev = cfg_to_ndev(cfg_priv); | ||
1545 | s32 txpwrdbm; | ||
1546 | u8 result; | ||
1547 | s32 err = 0; | ||
1548 | |||
1549 | WL_TRACE("Enter\n"); | ||
1550 | CHECK_SYS_UP(); | ||
1551 | |||
1552 | err = brcmf_dev_intvar_get(ndev, "qtxpower", &txpwrdbm); | ||
1553 | if (unlikely(err)) { | ||
1554 | WL_ERR("error (%d)\n", err); | ||
1555 | goto done; | ||
1556 | } | ||
1557 | |||
1558 | result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE); | ||
1559 | *dbm = (s32) brcmu_qdbm_to_mw(result); | ||
1560 | |||
1561 | done: | ||
1562 | WL_TRACE("Exit\n"); | ||
1563 | return err; | ||
1564 | } | ||
1565 | |||
1566 | static s32 | ||
1567 | brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, | ||
1568 | u8 key_idx, bool unicast, bool multicast) | ||
1569 | { | ||
1570 | u32 index; | ||
1571 | s32 wsec; | ||
1572 | s32 err = 0; | ||
1573 | |||
1574 | WL_TRACE("Enter\n"); | ||
1575 | WL_CONN("key index (%d)\n", key_idx); | ||
1576 | CHECK_SYS_UP(); | ||
1577 | |||
1578 | err = brcmf_dev_ioctl(dev, BRCMF_C_GET_WSEC, &wsec, sizeof(wsec)); | ||
1579 | if (unlikely(err)) { | ||
1580 | WL_ERR("WLC_GET_WSEC error (%d)\n", err); | ||
1581 | goto done; | ||
1582 | } | ||
1583 | |||
1584 | wsec = le32_to_cpu(wsec); | ||
1585 | if (wsec & WEP_ENABLED) { | ||
1586 | /* Just select a new current key */ | ||
1587 | index = (u32) key_idx; | ||
1588 | index = cpu_to_le32(index); | ||
1589 | err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY_PRIMARY, &index, | ||
1590 | sizeof(index)); | ||
1591 | if (unlikely(err)) | ||
1592 | WL_ERR("error (%d)\n", err); | ||
1593 | } | ||
1594 | done: | ||
1595 | WL_TRACE("Exit\n"); | ||
1596 | return err; | ||
1597 | } | ||
1598 | |||
1599 | static s32 | ||
1600 | brcmf_add_keyext(struct wiphy *wiphy, struct net_device *dev, | ||
1601 | u8 key_idx, const u8 *mac_addr, struct key_params *params) | ||
1602 | { | ||
1603 | struct brcmf_wsec_key key; | ||
1604 | s32 err = 0; | ||
1605 | |||
1606 | memset(&key, 0, sizeof(key)); | ||
1607 | key.index = (u32) key_idx; | ||
1608 | /* Instead of bcast for ea address for default wep keys, | ||
1609 | driver needs it to be Null */ | ||
1610 | if (!is_multicast_ether_addr(mac_addr)) | ||
1611 | memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN); | ||
1612 | key.len = (u32) params->key_len; | ||
1613 | /* check for key index change */ | ||
1614 | if (key.len == 0) { | ||
1615 | /* key delete */ | ||
1616 | swap_key_from_BE(&key); | ||
1617 | err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY, &key, sizeof(key)); | ||
1618 | if (unlikely(err)) { | ||
1619 | WL_ERR("key delete error (%d)\n", err); | ||
1620 | return err; | ||
1621 | } | ||
1622 | } else { | ||
1623 | if (key.len > sizeof(key.data)) { | ||
1624 | WL_ERR("Invalid key length (%d)\n", key.len); | ||
1625 | return -EINVAL; | ||
1626 | } | ||
1627 | |||
1628 | WL_CONN("Setting the key index %d\n", key.index); | ||
1629 | memcpy(key.data, params->key, key.len); | ||
1630 | |||
1631 | if (params->cipher == WLAN_CIPHER_SUITE_TKIP) { | ||
1632 | u8 keybuf[8]; | ||
1633 | memcpy(keybuf, &key.data[24], sizeof(keybuf)); | ||
1634 | memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); | ||
1635 | memcpy(&key.data[16], keybuf, sizeof(keybuf)); | ||
1636 | } | ||
1637 | |||
1638 | /* if IW_ENCODE_EXT_RX_SEQ_VALID set */ | ||
1639 | if (params->seq && params->seq_len == 6) { | ||
1640 | /* rx iv */ | ||
1641 | u8 *ivptr; | ||
1642 | ivptr = (u8 *) params->seq; | ||
1643 | key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | | ||
1644 | (ivptr[3] << 8) | ivptr[2]; | ||
1645 | key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; | ||
1646 | key.iv_initialized = true; | ||
1647 | } | ||
1648 | |||
1649 | switch (params->cipher) { | ||
1650 | case WLAN_CIPHER_SUITE_WEP40: | ||
1651 | key.algo = CRYPTO_ALGO_WEP1; | ||
1652 | WL_CONN("WLAN_CIPHER_SUITE_WEP40\n"); | ||
1653 | break; | ||
1654 | case WLAN_CIPHER_SUITE_WEP104: | ||
1655 | key.algo = CRYPTO_ALGO_WEP128; | ||
1656 | WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); | ||
1657 | break; | ||
1658 | case WLAN_CIPHER_SUITE_TKIP: | ||
1659 | key.algo = CRYPTO_ALGO_TKIP; | ||
1660 | WL_CONN("WLAN_CIPHER_SUITE_TKIP\n"); | ||
1661 | break; | ||
1662 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
1663 | key.algo = CRYPTO_ALGO_AES_CCM; | ||
1664 | WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n"); | ||
1665 | break; | ||
1666 | case WLAN_CIPHER_SUITE_CCMP: | ||
1667 | key.algo = CRYPTO_ALGO_AES_CCM; | ||
1668 | WL_CONN("WLAN_CIPHER_SUITE_CCMP\n"); | ||
1669 | break; | ||
1670 | default: | ||
1671 | WL_ERR("Invalid cipher (0x%x)\n", params->cipher); | ||
1672 | return -EINVAL; | ||
1673 | } | ||
1674 | swap_key_from_BE(&key); | ||
1675 | |||
1676 | brcmf_netdev_wait_pend8021x(dev); | ||
1677 | err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY, &key, sizeof(key)); | ||
1678 | if (unlikely(err)) { | ||
1679 | WL_ERR("WLC_SET_KEY error (%d)\n", err); | ||
1680 | return err; | ||
1681 | } | ||
1682 | } | ||
1683 | return err; | ||
1684 | } | ||
1685 | |||
1686 | static s32 | ||
1687 | brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, | ||
1688 | u8 key_idx, bool pairwise, const u8 *mac_addr, | ||
1689 | struct key_params *params) | ||
1690 | { | ||
1691 | struct brcmf_wsec_key key; | ||
1692 | s32 val; | ||
1693 | s32 wsec; | ||
1694 | s32 err = 0; | ||
1695 | u8 keybuf[8]; | ||
1696 | |||
1697 | WL_TRACE("Enter\n"); | ||
1698 | WL_CONN("key index (%d)\n", key_idx); | ||
1699 | CHECK_SYS_UP(); | ||
1700 | |||
1701 | if (mac_addr) { | ||
1702 | WL_TRACE("Exit"); | ||
1703 | return brcmf_add_keyext(wiphy, dev, key_idx, mac_addr, params); | ||
1704 | } | ||
1705 | memset(&key, 0, sizeof(key)); | ||
1706 | |||
1707 | key.len = (u32) params->key_len; | ||
1708 | key.index = (u32) key_idx; | ||
1709 | |||
1710 | if (unlikely(key.len > sizeof(key.data))) { | ||
1711 | WL_ERR("Too long key length (%u)\n", key.len); | ||
1712 | err = -EINVAL; | ||
1713 | goto done; | ||
1714 | } | ||
1715 | memcpy(key.data, params->key, key.len); | ||
1716 | |||
1717 | key.flags = BRCMF_PRIMARY_KEY; | ||
1718 | switch (params->cipher) { | ||
1719 | case WLAN_CIPHER_SUITE_WEP40: | ||
1720 | key.algo = CRYPTO_ALGO_WEP1; | ||
1721 | WL_CONN("WLAN_CIPHER_SUITE_WEP40\n"); | ||
1722 | break; | ||
1723 | case WLAN_CIPHER_SUITE_WEP104: | ||
1724 | key.algo = CRYPTO_ALGO_WEP128; | ||
1725 | WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); | ||
1726 | break; | ||
1727 | case WLAN_CIPHER_SUITE_TKIP: | ||
1728 | memcpy(keybuf, &key.data[24], sizeof(keybuf)); | ||
1729 | memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); | ||
1730 | memcpy(&key.data[16], keybuf, sizeof(keybuf)); | ||
1731 | key.algo = CRYPTO_ALGO_TKIP; | ||
1732 | WL_CONN("WLAN_CIPHER_SUITE_TKIP\n"); | ||
1733 | break; | ||
1734 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
1735 | key.algo = CRYPTO_ALGO_AES_CCM; | ||
1736 | WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n"); | ||
1737 | break; | ||
1738 | case WLAN_CIPHER_SUITE_CCMP: | ||
1739 | key.algo = CRYPTO_ALGO_AES_CCM; | ||
1740 | WL_CONN("WLAN_CIPHER_SUITE_CCMP\n"); | ||
1741 | break; | ||
1742 | default: | ||
1743 | WL_ERR("Invalid cipher (0x%x)\n", params->cipher); | ||
1744 | err = -EINVAL; | ||
1745 | goto done; | ||
1746 | } | ||
1747 | |||
1748 | /* Set the new key/index */ | ||
1749 | swap_key_from_BE(&key); | ||
1750 | err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY, &key, sizeof(key)); | ||
1751 | if (unlikely(err)) { | ||
1752 | WL_ERR("WLC_SET_KEY error (%d)\n", err); | ||
1753 | goto done; | ||
1754 | } | ||
1755 | |||
1756 | val = WEP_ENABLED; | ||
1757 | err = brcmf_dev_intvar_get(dev, "wsec", &wsec); | ||
1758 | if (unlikely(err)) { | ||
1759 | WL_ERR("get wsec error (%d)\n", err); | ||
1760 | goto done; | ||
1761 | } | ||
1762 | wsec &= ~(WEP_ENABLED); | ||
1763 | wsec |= val; | ||
1764 | err = brcmf_dev_intvar_set(dev, "wsec", wsec); | ||
1765 | if (unlikely(err)) { | ||
1766 | WL_ERR("set wsec error (%d)\n", err); | ||
1767 | goto done; | ||
1768 | } | ||
1769 | |||
1770 | val = 1; /* assume shared key. otherwise 0 */ | ||
1771 | val = cpu_to_le32(val); | ||
1772 | err = brcmf_dev_ioctl(dev, BRCMF_C_SET_AUTH, &val, sizeof(val)); | ||
1773 | if (unlikely(err)) | ||
1774 | WL_ERR("WLC_SET_AUTH error (%d)\n", err); | ||
1775 | done: | ||
1776 | WL_TRACE("Exit\n"); | ||
1777 | return err; | ||
1778 | } | ||
1779 | |||
1780 | static s32 | ||
1781 | brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, | ||
1782 | u8 key_idx, bool pairwise, const u8 *mac_addr) | ||
1783 | { | ||
1784 | struct brcmf_wsec_key key; | ||
1785 | s32 err = 0; | ||
1786 | s32 val; | ||
1787 | s32 wsec; | ||
1788 | |||
1789 | WL_TRACE("Enter\n"); | ||
1790 | CHECK_SYS_UP(); | ||
1791 | memset(&key, 0, sizeof(key)); | ||
1792 | |||
1793 | key.index = (u32) key_idx; | ||
1794 | key.flags = BRCMF_PRIMARY_KEY; | ||
1795 | key.algo = CRYPTO_ALGO_OFF; | ||
1796 | |||
1797 | WL_CONN("key index (%d)\n", key_idx); | ||
1798 | /* Set the new key/index */ | ||
1799 | swap_key_from_BE(&key); | ||
1800 | err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY, &key, sizeof(key)); | ||
1801 | if (unlikely(err)) { | ||
1802 | if (err == -EINVAL) { | ||
1803 | if (key.index >= DOT11_MAX_DEFAULT_KEYS) | ||
1804 | /* we ignore this key index in this case */ | ||
1805 | WL_ERR("invalid key index (%d)\n", key_idx); | ||
1806 | } else | ||
1807 | WL_ERR("WLC_SET_KEY error (%d)\n", err); | ||
1808 | |||
1809 | /* Ignore this error, may happen during DISASSOC */ | ||
1810 | err = -EAGAIN; | ||
1811 | goto done; | ||
1812 | } | ||
1813 | |||
1814 | val = 0; | ||
1815 | err = brcmf_dev_intvar_get(dev, "wsec", &wsec); | ||
1816 | if (unlikely(err)) { | ||
1817 | WL_ERR("get wsec error (%d)\n", err); | ||
1818 | /* Ignore this error, may happen during DISASSOC */ | ||
1819 | err = -EAGAIN; | ||
1820 | goto done; | ||
1821 | } | ||
1822 | wsec &= ~(WEP_ENABLED); | ||
1823 | wsec |= val; | ||
1824 | err = brcmf_dev_intvar_set(dev, "wsec", wsec); | ||
1825 | if (unlikely(err)) { | ||
1826 | WL_ERR("set wsec error (%d)\n", err); | ||
1827 | /* Ignore this error, may happen during DISASSOC */ | ||
1828 | err = -EAGAIN; | ||
1829 | goto done; | ||
1830 | } | ||
1831 | |||
1832 | val = 0; /* assume open key. otherwise 1 */ | ||
1833 | val = cpu_to_le32(val); | ||
1834 | err = brcmf_dev_ioctl(dev, BRCMF_C_SET_AUTH, &val, sizeof(val)); | ||
1835 | if (unlikely(err)) { | ||
1836 | WL_ERR("WLC_SET_AUTH error (%d)\n", err); | ||
1837 | /* Ignore this error, may happen during DISASSOC */ | ||
1838 | err = -EAGAIN; | ||
1839 | } | ||
1840 | done: | ||
1841 | WL_TRACE("Exit\n"); | ||
1842 | return err; | ||
1843 | } | ||
1844 | |||
1845 | static s32 | ||
1846 | brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, | ||
1847 | u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, | ||
1848 | void (*callback) (void *cookie, struct key_params * params)) | ||
1849 | { | ||
1850 | struct key_params params; | ||
1851 | struct brcmf_wsec_key key; | ||
1852 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); | ||
1853 | struct brcmf_cfg80211_security *sec; | ||
1854 | s32 wsec; | ||
1855 | s32 err = 0; | ||
1856 | |||
1857 | WL_TRACE("Enter\n"); | ||
1858 | WL_CONN("key index (%d)\n", key_idx); | ||
1859 | CHECK_SYS_UP(); | ||
1860 | |||
1861 | memset(&key, 0, sizeof(key)); | ||
1862 | key.index = key_idx; | ||
1863 | swap_key_to_BE(&key); | ||
1864 | memset(¶ms, 0, sizeof(params)); | ||
1865 | params.key_len = (u8) min_t(u8, WLAN_MAX_KEY_LEN, key.len); | ||
1866 | memcpy(params.key, key.data, params.key_len); | ||
1867 | |||
1868 | err = brcmf_dev_ioctl(dev, BRCMF_C_GET_WSEC, &wsec, sizeof(wsec)); | ||
1869 | if (unlikely(err)) { | ||
1870 | WL_ERR("WLC_GET_WSEC error (%d)\n", err); | ||
1871 | /* Ignore this error, may happen during DISASSOC */ | ||
1872 | err = -EAGAIN; | ||
1873 | goto done; | ||
1874 | } | ||
1875 | wsec = le32_to_cpu(wsec); | ||
1876 | switch (wsec) { | ||
1877 | case WEP_ENABLED: | ||
1878 | sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); | ||
1879 | if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { | ||
1880 | params.cipher = WLAN_CIPHER_SUITE_WEP40; | ||
1881 | WL_CONN("WLAN_CIPHER_SUITE_WEP40\n"); | ||
1882 | } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) { | ||
1883 | params.cipher = WLAN_CIPHER_SUITE_WEP104; | ||
1884 | WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); | ||
1885 | } | ||
1886 | break; | ||
1887 | case TKIP_ENABLED: | ||
1888 | params.cipher = WLAN_CIPHER_SUITE_TKIP; | ||
1889 | WL_CONN("WLAN_CIPHER_SUITE_TKIP\n"); | ||
1890 | break; | ||
1891 | case AES_ENABLED: | ||
1892 | params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; | ||
1893 | WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n"); | ||
1894 | break; | ||
1895 | default: | ||
1896 | WL_ERR("Invalid algo (0x%x)\n", wsec); | ||
1897 | err = -EINVAL; | ||
1898 | goto done; | ||
1899 | } | ||
1900 | callback(cookie, ¶ms); | ||
1901 | |||
1902 | done: | ||
1903 | WL_TRACE("Exit\n"); | ||
1904 | return err; | ||
1905 | } | ||
1906 | |||
1907 | static s32 | ||
1908 | brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, | ||
1909 | struct net_device *dev, u8 key_idx) | ||
1910 | { | ||
1911 | WL_INFO("Not supported\n"); | ||
1912 | |||
1913 | CHECK_SYS_UP(); | ||
1914 | return -EOPNOTSUPP; | ||
1915 | } | ||
1916 | |||
1917 | static s32 | ||
1918 | brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, | ||
1919 | u8 *mac, struct station_info *sinfo) | ||
1920 | { | ||
1921 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); | ||
1922 | struct brcmf_scb_val scb_val; | ||
1923 | int rssi; | ||
1924 | s32 rate; | ||
1925 | s32 err = 0; | ||
1926 | u8 *bssid = brcmf_read_prof(cfg_priv, WL_PROF_BSSID); | ||
1927 | |||
1928 | WL_TRACE("Enter\n"); | ||
1929 | CHECK_SYS_UP(); | ||
1930 | |||
1931 | if (unlikely | ||
1932 | (memcmp(mac, bssid, ETH_ALEN))) { | ||
1933 | WL_ERR("Wrong Mac address cfg_mac-%X:%X:%X:%X:%X:%X" | ||
1934 | "wl_bssid-%X:%X:%X:%X:%X:%X\n", | ||
1935 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], | ||
1936 | bssid[0], bssid[1], bssid[2], bssid[3], | ||
1937 | bssid[4], bssid[5]); | ||
1938 | err = -ENOENT; | ||
1939 | goto done; | ||
1940 | } | ||
1941 | |||
1942 | /* Report the current tx rate */ | ||
1943 | err = brcmf_dev_ioctl(dev, BRCMF_C_GET_RATE, &rate, sizeof(rate)); | ||
1944 | if (err) { | ||
1945 | WL_ERR("Could not get rate (%d)\n", err); | ||
1946 | } else { | ||
1947 | rate = le32_to_cpu(rate); | ||
1948 | sinfo->filled |= STATION_INFO_TX_BITRATE; | ||
1949 | sinfo->txrate.legacy = rate * 5; | ||
1950 | WL_CONN("Rate %d Mbps\n", rate / 2); | ||
1951 | } | ||
1952 | |||
1953 | if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) { | ||
1954 | scb_val.val = 0; | ||
1955 | err = brcmf_dev_ioctl(dev, BRCMF_C_GET_RSSI, &scb_val, | ||
1956 | sizeof(struct brcmf_scb_val)); | ||
1957 | if (unlikely(err)) { | ||
1958 | WL_ERR("Could not get rssi (%d)\n", err); | ||
1959 | } | ||
1960 | rssi = le32_to_cpu(scb_val.val); | ||
1961 | sinfo->filled |= STATION_INFO_SIGNAL; | ||
1962 | sinfo->signal = rssi; | ||
1963 | WL_CONN("RSSI %d dBm\n", rssi); | ||
1964 | } | ||
1965 | |||
1966 | done: | ||
1967 | WL_TRACE("Exit\n"); | ||
1968 | return err; | ||
1969 | } | ||
1970 | |||
1971 | static s32 | ||
1972 | brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, | ||
1973 | bool enabled, s32 timeout) | ||
1974 | { | ||
1975 | s32 pm; | ||
1976 | s32 err = 0; | ||
1977 | |||
1978 | WL_TRACE("Enter\n"); | ||
1979 | CHECK_SYS_UP(); | ||
1980 | |||
1981 | pm = enabled ? PM_FAST : PM_OFF; | ||
1982 | pm = cpu_to_le32(pm); | ||
1983 | WL_INFO("power save %s\n", (pm ? "enabled" : "disabled")); | ||
1984 | |||
1985 | err = brcmf_dev_ioctl(dev, BRCMF_C_SET_PM, &pm, sizeof(pm)); | ||
1986 | if (unlikely(err)) { | ||
1987 | if (err == -ENODEV) | ||
1988 | WL_ERR("net_device is not ready yet\n"); | ||
1989 | else | ||
1990 | WL_ERR("error (%d)\n", err); | ||
1991 | } | ||
1992 | WL_TRACE("Exit\n"); | ||
1993 | return err; | ||
1994 | } | ||
1995 | |||
1996 | static __used u32 brcmf_find_msb(u16 bit16) | ||
1997 | { | ||
1998 | u32 ret = 0; | ||
1999 | |||
2000 | if (bit16 & 0xff00) { | ||
2001 | ret += 8; | ||
2002 | bit16 >>= 8; | ||
2003 | } | ||
2004 | |||
2005 | if (bit16 & 0xf0) { | ||
2006 | ret += 4; | ||
2007 | bit16 >>= 4; | ||
2008 | } | ||
2009 | |||
2010 | if (bit16 & 0xc) { | ||
2011 | ret += 2; | ||
2012 | bit16 >>= 2; | ||
2013 | } | ||
2014 | |||
2015 | if (bit16 & 2) | ||
2016 | ret += bit16 & 2; | ||
2017 | else if (bit16) | ||
2018 | ret += bit16; | ||
2019 | |||
2020 | return ret; | ||
2021 | } | ||
2022 | |||
2023 | static s32 | ||
2024 | brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, | ||
2025 | const u8 *addr, | ||
2026 | const struct cfg80211_bitrate_mask *mask) | ||
2027 | { | ||
2028 | struct wl_rateset rateset; | ||
2029 | s32 rate; | ||
2030 | s32 val; | ||
2031 | s32 err_bg; | ||
2032 | s32 err_a; | ||
2033 | u32 legacy; | ||
2034 | s32 err = 0; | ||
2035 | |||
2036 | WL_TRACE("Enter\n"); | ||
2037 | CHECK_SYS_UP(); | ||
2038 | |||
2039 | /* addr param is always NULL. ignore it */ | ||
2040 | /* Get current rateset */ | ||
2041 | err = brcmf_dev_ioctl(dev, BRCM_GET_CURR_RATESET, &rateset, | ||
2042 | sizeof(rateset)); | ||
2043 | if (unlikely(err)) { | ||
2044 | WL_ERR("could not get current rateset (%d)\n", err); | ||
2045 | goto done; | ||
2046 | } | ||
2047 | |||
2048 | rateset.count = le32_to_cpu(rateset.count); | ||
2049 | |||
2050 | legacy = brcmf_find_msb(mask->control[IEEE80211_BAND_2GHZ].legacy); | ||
2051 | if (!legacy) | ||
2052 | legacy = brcmf_find_msb(mask->control[IEEE80211_BAND_5GHZ].legacy); | ||
2053 | |||
2054 | val = wl_g_rates[legacy - 1].bitrate * 100000; | ||
2055 | |||
2056 | if (val < rateset.count) | ||
2057 | /* Select rate by rateset index */ | ||
2058 | rate = rateset.rates[val] & 0x7f; | ||
2059 | else | ||
2060 | /* Specified rate in bps */ | ||
2061 | rate = val / 500000; | ||
2062 | |||
2063 | WL_CONN("rate %d mbps\n", rate / 2); | ||
2064 | |||
2065 | /* | ||
2066 | * | ||
2067 | * Set rate override, | ||
2068 | * Since the is a/b/g-blind, both a/bg_rate are enforced. | ||
2069 | */ | ||
2070 | err_bg = brcmf_dev_intvar_set(dev, "bg_rate", rate); | ||
2071 | err_a = brcmf_dev_intvar_set(dev, "a_rate", rate); | ||
2072 | if (unlikely(err_bg && err_a)) { | ||
2073 | WL_ERR("could not set fixed rate (%d) (%d)\n", err_bg, err_a); | ||
2074 | err = err_bg | err_a; | ||
2075 | } | ||
2076 | |||
2077 | done: | ||
2078 | WL_TRACE("Exit\n"); | ||
2079 | return err; | ||
2080 | } | ||
2081 | |||
2082 | static s32 brcmf_cfg80211_resume(struct wiphy *wiphy) | ||
2083 | { | ||
2084 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); | ||
2085 | |||
2086 | /* | ||
2087 | * Check for WL_STATUS_READY before any function call which | ||
2088 | * could result is bus access. Don't block the resume for | ||
2089 | * any driver error conditions | ||
2090 | */ | ||
2091 | WL_TRACE("Enter\n"); | ||
2092 | |||
2093 | #if defined(CONFIG_PM_SLEEP) | ||
2094 | atomic_set(&brcmf_mmc_suspend, false); | ||
2095 | #endif /* defined(CONFIG_PM_SLEEP) */ | ||
2096 | |||
2097 | if (test_bit(WL_STATUS_READY, &cfg_priv->status)) | ||
2098 | brcmf_invoke_iscan(wiphy_to_cfg(wiphy)); | ||
2099 | |||
2100 | WL_TRACE("Exit\n"); | ||
2101 | return 0; | ||
2102 | } | ||
2103 | |||
2104 | static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, | ||
2105 | struct cfg80211_wowlan *wow) | ||
2106 | { | ||
2107 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); | ||
2108 | struct net_device *ndev = cfg_to_ndev(cfg_priv); | ||
2109 | |||
2110 | WL_TRACE("Enter\n"); | ||
2111 | |||
2112 | /* | ||
2113 | * Check for WL_STATUS_READY before any function call which | ||
2114 | * could result is bus access. Don't block the suspend for | ||
2115 | * any driver error conditions | ||
2116 | */ | ||
2117 | |||
2118 | /* | ||
2119 | * While going to suspend if associated with AP disassociate | ||
2120 | * from AP to save power while system is in suspended state | ||
2121 | */ | ||
2122 | if ((test_bit(WL_STATUS_CONNECTED, &cfg_priv->status) || | ||
2123 | test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) && | ||
2124 | test_bit(WL_STATUS_READY, &cfg_priv->status)) { | ||
2125 | WL_INFO("Disassociating from AP" | ||
2126 | " while entering suspend state\n"); | ||
2127 | brcmf_link_down(cfg_priv); | ||
2128 | |||
2129 | /* | ||
2130 | * Make sure WPA_Supplicant receives all the event | ||
2131 | * generated due to DISASSOC call to the fw to keep | ||
2132 | * the state fw and WPA_Supplicant state consistent | ||
2133 | */ | ||
2134 | rtnl_unlock(); | ||
2135 | brcmf_delay(500); | ||
2136 | rtnl_lock(); | ||
2137 | } | ||
2138 | |||
2139 | set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); | ||
2140 | if (test_bit(WL_STATUS_READY, &cfg_priv->status)) | ||
2141 | brcmf_term_iscan(cfg_priv); | ||
2142 | |||
2143 | if (cfg_priv->scan_request) { | ||
2144 | /* Indidate scan abort to cfg80211 layer */ | ||
2145 | WL_INFO("Terminating scan in progress\n"); | ||
2146 | cfg80211_scan_done(cfg_priv->scan_request, true); | ||
2147 | cfg_priv->scan_request = NULL; | ||
2148 | } | ||
2149 | clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); | ||
2150 | clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); | ||
2151 | |||
2152 | /* Turn off watchdog timer */ | ||
2153 | if (test_bit(WL_STATUS_READY, &cfg_priv->status)) { | ||
2154 | WL_INFO("Enable MPC\n"); | ||
2155 | brcmf_set_mpc(ndev, 1); | ||
2156 | } | ||
2157 | |||
2158 | #if defined(CONFIG_PM_SLEEP) | ||
2159 | atomic_set(&brcmf_mmc_suspend, true); | ||
2160 | #endif /* defined(CONFIG_PM_SLEEP) */ | ||
2161 | |||
2162 | WL_TRACE("Exit\n"); | ||
2163 | |||
2164 | return 0; | ||
2165 | } | ||
2166 | |||
2167 | static __used s32 | ||
2168 | brcmf_update_pmklist(struct net_device *dev, | ||
2169 | struct brcmf_cfg80211_pmk_list *pmk_list, s32 err) | ||
2170 | { | ||
2171 | int i, j; | ||
2172 | |||
2173 | WL_CONN("No of elements %d\n", pmk_list->pmkids.npmkid); | ||
2174 | for (i = 0; i < pmk_list->pmkids.npmkid; i++) { | ||
2175 | WL_CONN("PMKID[%d]: %pM =\n", i, | ||
2176 | &pmk_list->pmkids.pmkid[i].BSSID); | ||
2177 | for (j = 0; j < WLAN_PMKID_LEN; j++) | ||
2178 | WL_CONN("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]); | ||
2179 | } | ||
2180 | |||
2181 | if (likely(!err)) | ||
2182 | brcmf_dev_bufvar_set(dev, "pmkid_info", (char *)pmk_list, | ||
2183 | sizeof(*pmk_list)); | ||
2184 | |||
2185 | return err; | ||
2186 | } | ||
2187 | |||
2188 | static s32 | ||
2189 | brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, | ||
2190 | struct cfg80211_pmksa *pmksa) | ||
2191 | { | ||
2192 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); | ||
2193 | struct _pmkid_list *pmkids = &cfg_priv->pmk_list->pmkids; | ||
2194 | s32 err = 0; | ||
2195 | int i; | ||
2196 | |||
2197 | WL_TRACE("Enter\n"); | ||
2198 | CHECK_SYS_UP(); | ||
2199 | |||
2200 | for (i = 0; i < pmkids->npmkid; i++) | ||
2201 | if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN)) | ||
2202 | break; | ||
2203 | if (i < WL_NUM_PMKIDS_MAX) { | ||
2204 | memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN); | ||
2205 | memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN); | ||
2206 | if (i == pmkids->npmkid) | ||
2207 | pmkids->npmkid++; | ||
2208 | } else | ||
2209 | err = -EINVAL; | ||
2210 | |||
2211 | WL_CONN("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", | ||
2212 | pmkids->pmkid[pmkids->npmkid].BSSID); | ||
2213 | for (i = 0; i < WLAN_PMKID_LEN; i++) | ||
2214 | WL_CONN("%02x\n", pmkids->pmkid[pmkids->npmkid].PMKID[i]); | ||
2215 | |||
2216 | err = brcmf_update_pmklist(dev, cfg_priv->pmk_list, err); | ||
2217 | |||
2218 | WL_TRACE("Exit\n"); | ||
2219 | return err; | ||
2220 | } | ||
2221 | |||
2222 | static s32 | ||
2223 | brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, | ||
2224 | struct cfg80211_pmksa *pmksa) | ||
2225 | { | ||
2226 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); | ||
2227 | struct _pmkid_list pmkid; | ||
2228 | s32 err = 0; | ||
2229 | int i; | ||
2230 | |||
2231 | WL_TRACE("Enter\n"); | ||
2232 | CHECK_SYS_UP(); | ||
2233 | memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN); | ||
2234 | memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN); | ||
2235 | |||
2236 | WL_CONN("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", | ||
2237 | &pmkid.pmkid[0].BSSID); | ||
2238 | for (i = 0; i < WLAN_PMKID_LEN; i++) | ||
2239 | WL_CONN("%02x\n", pmkid.pmkid[0].PMKID[i]); | ||
2240 | |||
2241 | for (i = 0; i < cfg_priv->pmk_list->pmkids.npmkid; i++) | ||
2242 | if (!memcmp | ||
2243 | (pmksa->bssid, &cfg_priv->pmk_list->pmkids.pmkid[i].BSSID, | ||
2244 | ETH_ALEN)) | ||
2245 | break; | ||
2246 | |||
2247 | if ((cfg_priv->pmk_list->pmkids.npmkid > 0) | ||
2248 | && (i < cfg_priv->pmk_list->pmkids.npmkid)) { | ||
2249 | memset(&cfg_priv->pmk_list->pmkids.pmkid[i], 0, | ||
2250 | sizeof(pmkid_t)); | ||
2251 | for (; i < (cfg_priv->pmk_list->pmkids.npmkid - 1); i++) { | ||
2252 | memcpy(&cfg_priv->pmk_list->pmkids.pmkid[i].BSSID, | ||
2253 | &cfg_priv->pmk_list->pmkids.pmkid[i + 1].BSSID, | ||
2254 | ETH_ALEN); | ||
2255 | memcpy(&cfg_priv->pmk_list->pmkids.pmkid[i].PMKID, | ||
2256 | &cfg_priv->pmk_list->pmkids.pmkid[i + 1].PMKID, | ||
2257 | WLAN_PMKID_LEN); | ||
2258 | } | ||
2259 | cfg_priv->pmk_list->pmkids.npmkid--; | ||
2260 | } else | ||
2261 | err = -EINVAL; | ||
2262 | |||
2263 | err = brcmf_update_pmklist(dev, cfg_priv->pmk_list, err); | ||
2264 | |||
2265 | WL_TRACE("Exit\n"); | ||
2266 | return err; | ||
2267 | |||
2268 | } | ||
2269 | |||
2270 | static s32 | ||
2271 | brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev) | ||
2272 | { | ||
2273 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); | ||
2274 | s32 err = 0; | ||
2275 | |||
2276 | WL_TRACE("Enter\n"); | ||
2277 | CHECK_SYS_UP(); | ||
2278 | |||
2279 | memset(cfg_priv->pmk_list, 0, sizeof(*cfg_priv->pmk_list)); | ||
2280 | err = brcmf_update_pmklist(dev, cfg_priv->pmk_list, err); | ||
2281 | |||
2282 | WL_TRACE("Exit\n"); | ||
2283 | return err; | ||
2284 | |||
2285 | } | ||
2286 | |||
2287 | static struct cfg80211_ops wl_cfg80211_ops = { | ||
2288 | .change_virtual_intf = brcmf_cfg80211_change_iface, | ||
2289 | .scan = brcmf_cfg80211_scan, | ||
2290 | .set_wiphy_params = brcmf_cfg80211_set_wiphy_params, | ||
2291 | .join_ibss = brcmf_cfg80211_join_ibss, | ||
2292 | .leave_ibss = brcmf_cfg80211_leave_ibss, | ||
2293 | .get_station = brcmf_cfg80211_get_station, | ||
2294 | .set_tx_power = brcmf_cfg80211_set_tx_power, | ||
2295 | .get_tx_power = brcmf_cfg80211_get_tx_power, | ||
2296 | .add_key = brcmf_cfg80211_add_key, | ||
2297 | .del_key = brcmf_cfg80211_del_key, | ||
2298 | .get_key = brcmf_cfg80211_get_key, | ||
2299 | .set_default_key = brcmf_cfg80211_config_default_key, | ||
2300 | .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key, | ||
2301 | .set_power_mgmt = brcmf_cfg80211_set_power_mgmt, | ||
2302 | .set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask, | ||
2303 | .connect = brcmf_cfg80211_connect, | ||
2304 | .disconnect = brcmf_cfg80211_disconnect, | ||
2305 | .suspend = brcmf_cfg80211_suspend, | ||
2306 | .resume = brcmf_cfg80211_resume, | ||
2307 | .set_pmksa = brcmf_cfg80211_set_pmksa, | ||
2308 | .del_pmksa = brcmf_cfg80211_del_pmksa, | ||
2309 | .flush_pmksa = brcmf_cfg80211_flush_pmksa | ||
2310 | }; | ||
2311 | |||
2312 | static s32 brcmf_mode_to_nl80211_iftype(s32 mode) | ||
2313 | { | ||
2314 | s32 err = 0; | ||
2315 | |||
2316 | switch (mode) { | ||
2317 | case WL_MODE_BSS: | ||
2318 | return NL80211_IFTYPE_STATION; | ||
2319 | case WL_MODE_IBSS: | ||
2320 | return NL80211_IFTYPE_ADHOC; | ||
2321 | default: | ||
2322 | return NL80211_IFTYPE_UNSPECIFIED; | ||
2323 | } | ||
2324 | |||
2325 | return err; | ||
2326 | } | ||
2327 | |||
2328 | static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface, | ||
2329 | struct device *dev) | ||
2330 | { | ||
2331 | struct wireless_dev *wdev; | ||
2332 | s32 err = 0; | ||
2333 | |||
2334 | wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); | ||
2335 | if (unlikely(!wdev)) { | ||
2336 | WL_ERR("Could not allocate wireless device\n"); | ||
2337 | return ERR_PTR(-ENOMEM); | ||
2338 | } | ||
2339 | wdev->wiphy = | ||
2340 | wiphy_new(&wl_cfg80211_ops, | ||
2341 | sizeof(struct brcmf_cfg80211_priv) + sizeof_iface); | ||
2342 | if (unlikely(!wdev->wiphy)) { | ||
2343 | WL_ERR("Couldn not allocate wiphy device\n"); | ||
2344 | err = -ENOMEM; | ||
2345 | goto wiphy_new_out; | ||
2346 | } | ||
2347 | set_wiphy_dev(wdev->wiphy, dev); | ||
2348 | wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; | ||
2349 | wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; | ||
2350 | wdev->wiphy->interface_modes = | ||
2351 | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); | ||
2352 | wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; | ||
2353 | wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set | ||
2354 | * it as 11a by default. | ||
2355 | * This will be updated with | ||
2356 | * 11n phy tables in | ||
2357 | * "ifconfig up" | ||
2358 | * if phy has 11n capability | ||
2359 | */ | ||
2360 | wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | ||
2361 | wdev->wiphy->cipher_suites = __wl_cipher_suites; | ||
2362 | wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); | ||
2363 | #ifndef WL_POWERSAVE_DISABLED | ||
2364 | wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power | ||
2365 | * save mode | ||
2366 | * by default | ||
2367 | */ | ||
2368 | #else | ||
2369 | wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; | ||
2370 | #endif /* !WL_POWERSAVE_DISABLED */ | ||
2371 | err = wiphy_register(wdev->wiphy); | ||
2372 | if (unlikely(err < 0)) { | ||
2373 | WL_ERR("Couldn not register wiphy device (%d)\n", err); | ||
2374 | goto wiphy_register_out; | ||
2375 | } | ||
2376 | return wdev; | ||
2377 | |||
2378 | wiphy_register_out: | ||
2379 | wiphy_free(wdev->wiphy); | ||
2380 | |||
2381 | wiphy_new_out: | ||
2382 | kfree(wdev); | ||
2383 | |||
2384 | return ERR_PTR(err); | ||
2385 | } | ||
2386 | |||
2387 | static void brcmf_free_wdev(struct brcmf_cfg80211_priv *cfg_priv) | ||
2388 | { | ||
2389 | struct wireless_dev *wdev = cfg_to_wdev(cfg_priv); | ||
2390 | |||
2391 | if (unlikely(!wdev)) { | ||
2392 | WL_ERR("wdev is invalid\n"); | ||
2393 | return; | ||
2394 | } | ||
2395 | wiphy_unregister(wdev->wiphy); | ||
2396 | wiphy_free(wdev->wiphy); | ||
2397 | kfree(wdev); | ||
2398 | cfg_to_wdev(cfg_priv) = NULL; | ||
2399 | } | ||
2400 | |||
2401 | static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv) | ||
2402 | { | ||
2403 | struct brcmf_scan_results *bss_list; | ||
2404 | struct brcmf_bss_info *bi = NULL; /* must be initialized */ | ||
2405 | s32 err = 0; | ||
2406 | int i; | ||
2407 | |||
2408 | bss_list = cfg_priv->bss_list; | ||
2409 | if (unlikely(bss_list->version != BRCMF_BSS_INFO_VERSION)) { | ||
2410 | WL_ERR("Version %d != WL_BSS_INFO_VERSION\n", | ||
2411 | bss_list->version); | ||
2412 | return -EOPNOTSUPP; | ||
2413 | } | ||
2414 | WL_SCAN("scanned AP count (%d)\n", bss_list->count); | ||
2415 | bi = next_bss(bss_list, bi); | ||
2416 | for_each_bss(bss_list, bi, i) { | ||
2417 | err = brcmf_inform_single_bss(cfg_priv, bi); | ||
2418 | if (unlikely(err)) | ||
2419 | break; | ||
2420 | } | ||
2421 | return err; | ||
2422 | } | ||
2423 | |||
2424 | |||
2425 | static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv, | ||
2426 | struct brcmf_bss_info *bi) | ||
2427 | { | ||
2428 | struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); | ||
2429 | struct ieee80211_channel *notify_channel; | ||
2430 | struct cfg80211_bss *bss; | ||
2431 | struct ieee80211_supported_band *band; | ||
2432 | s32 err = 0; | ||
2433 | u16 channel; | ||
2434 | u32 freq; | ||
2435 | u64 notify_timestamp; | ||
2436 | u16 notify_capability; | ||
2437 | u16 notify_interval; | ||
2438 | u8 *notify_ie; | ||
2439 | size_t notify_ielen; | ||
2440 | s32 notify_signal; | ||
2441 | |||
2442 | if (unlikely(le32_to_cpu(bi->length) > WL_BSS_INFO_MAX)) { | ||
2443 | WL_ERR("Bss info is larger than buffer. Discarding\n"); | ||
2444 | return 0; | ||
2445 | } | ||
2446 | |||
2447 | channel = bi->ctl_ch ? bi->ctl_ch : | ||
2448 | CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); | ||
2449 | |||
2450 | if (channel <= CH_MAX_2G_CHANNEL) | ||
2451 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
2452 | else | ||
2453 | band = wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
2454 | |||
2455 | freq = ieee80211_channel_to_frequency(channel, band->band); | ||
2456 | notify_channel = ieee80211_get_channel(wiphy, freq); | ||
2457 | |||
2458 | notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */ | ||
2459 | notify_capability = le16_to_cpu(bi->capability); | ||
2460 | notify_interval = le16_to_cpu(bi->beacon_period); | ||
2461 | notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset); | ||
2462 | notify_ielen = le16_to_cpu(bi->ie_length); | ||
2463 | notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; | ||
2464 | |||
2465 | WL_CONN("bssid: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", | ||
2466 | bi->BSSID[0], bi->BSSID[1], bi->BSSID[2], | ||
2467 | bi->BSSID[3], bi->BSSID[4], bi->BSSID[5]); | ||
2468 | WL_CONN("Channel: %d(%d)\n", channel, freq); | ||
2469 | WL_CONN("Capability: %X\n", notify_capability); | ||
2470 | WL_CONN("Beacon interval: %d\n", notify_interval); | ||
2471 | WL_CONN("Signal: %d\n", notify_signal); | ||
2472 | WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp); | ||
2473 | |||
2474 | bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID, | ||
2475 | notify_timestamp, notify_capability, notify_interval, notify_ie, | ||
2476 | notify_ielen, notify_signal, GFP_KERNEL); | ||
2477 | |||
2478 | if (unlikely(!bss)) { | ||
2479 | WL_ERR("cfg80211_inform_bss_frame error\n"); | ||
2480 | return -EINVAL; | ||
2481 | } | ||
2482 | |||
2483 | return err; | ||
2484 | } | ||
2485 | |||
2486 | static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv, | ||
2487 | struct net_device *dev, const u8 *bssid) | ||
2488 | { | ||
2489 | struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); | ||
2490 | struct ieee80211_channel *notify_channel; | ||
2491 | struct brcmf_bss_info *bi = NULL; | ||
2492 | struct ieee80211_supported_band *band; | ||
2493 | u8 *buf = NULL; | ||
2494 | s32 err = 0; | ||
2495 | u16 channel; | ||
2496 | u32 freq; | ||
2497 | u64 notify_timestamp; | ||
2498 | u16 notify_capability; | ||
2499 | u16 notify_interval; | ||
2500 | u8 *notify_ie; | ||
2501 | size_t notify_ielen; | ||
2502 | s32 notify_signal; | ||
2503 | |||
2504 | WL_TRACE("Enter\n"); | ||
2505 | |||
2506 | buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); | ||
2507 | if (buf == NULL) { | ||
2508 | WL_ERR("kzalloc() failed\n"); | ||
2509 | err = -ENOMEM; | ||
2510 | goto CleanUp; | ||
2511 | } | ||
2512 | |||
2513 | *(u32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX); | ||
2514 | |||
2515 | err = brcmf_dev_ioctl(dev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX); | ||
2516 | if (unlikely(err)) { | ||
2517 | WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err); | ||
2518 | goto CleanUp; | ||
2519 | } | ||
2520 | |||
2521 | bi = (struct brcmf_bss_info *)(buf + 4); | ||
2522 | |||
2523 | channel = bi->ctl_ch ? bi->ctl_ch : | ||
2524 | CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); | ||
2525 | |||
2526 | if (channel <= CH_MAX_2G_CHANNEL) | ||
2527 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
2528 | else | ||
2529 | band = wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
2530 | |||
2531 | freq = ieee80211_channel_to_frequency(channel, band->band); | ||
2532 | notify_channel = ieee80211_get_channel(wiphy, freq); | ||
2533 | |||
2534 | notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */ | ||
2535 | notify_capability = le16_to_cpu(bi->capability); | ||
2536 | notify_interval = le16_to_cpu(bi->beacon_period); | ||
2537 | notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset); | ||
2538 | notify_ielen = le16_to_cpu(bi->ie_length); | ||
2539 | notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; | ||
2540 | |||
2541 | WL_CONN("channel: %d(%d)\n", channel, freq); | ||
2542 | WL_CONN("capability: %X\n", notify_capability); | ||
2543 | WL_CONN("beacon interval: %d\n", notify_interval); | ||
2544 | WL_CONN("signal: %d\n", notify_signal); | ||
2545 | WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp); | ||
2546 | |||
2547 | cfg80211_inform_bss(wiphy, notify_channel, bssid, | ||
2548 | notify_timestamp, notify_capability, notify_interval, | ||
2549 | notify_ie, notify_ielen, notify_signal, GFP_KERNEL); | ||
2550 | |||
2551 | CleanUp: | ||
2552 | |||
2553 | kfree(buf); | ||
2554 | |||
2555 | WL_TRACE("Exit\n"); | ||
2556 | |||
2557 | return err; | ||
2558 | } | ||
2559 | |||
2560 | static bool brcmf_is_linkup(struct brcmf_cfg80211_priv *cfg_priv, | ||
2561 | const struct brcmf_event_msg *e) | ||
2562 | { | ||
2563 | u32 event = be32_to_cpu(e->event_type); | ||
2564 | u32 status = be32_to_cpu(e->status); | ||
2565 | |||
2566 | if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) { | ||
2567 | WL_CONN("Processing set ssid\n"); | ||
2568 | cfg_priv->link_up = true; | ||
2569 | return true; | ||
2570 | } | ||
2571 | |||
2572 | return false; | ||
2573 | } | ||
2574 | |||
2575 | static bool brcmf_is_linkdown(struct brcmf_cfg80211_priv *cfg_priv, | ||
2576 | const struct brcmf_event_msg *e) | ||
2577 | { | ||
2578 | u32 event = be32_to_cpu(e->event_type); | ||
2579 | u16 flags = be16_to_cpu(e->flags); | ||
2580 | |||
2581 | if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) { | ||
2582 | WL_CONN("Processing link down\n"); | ||
2583 | return true; | ||
2584 | } | ||
2585 | return false; | ||
2586 | } | ||
2587 | |||
2588 | static bool brcmf_is_nonetwork(struct brcmf_cfg80211_priv *cfg_priv, | ||
2589 | const struct brcmf_event_msg *e) | ||
2590 | { | ||
2591 | u32 event = be32_to_cpu(e->event_type); | ||
2592 | u32 status = be32_to_cpu(e->status); | ||
2593 | |||
2594 | if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) { | ||
2595 | WL_CONN("Processing Link %s & no network found\n", | ||
2596 | be16_to_cpu(e->flags) & BRCMF_EVENT_MSG_LINK ? | ||
2597 | "up" : "down"); | ||
2598 | return true; | ||
2599 | } | ||
2600 | |||
2601 | if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) { | ||
2602 | WL_CONN("Processing connecting & no network found\n"); | ||
2603 | return true; | ||
2604 | } | ||
2605 | |||
2606 | return false; | ||
2607 | } | ||
2608 | |||
2609 | static s32 | ||
2610 | brcmf_notify_connect_status(struct brcmf_cfg80211_priv *cfg_priv, | ||
2611 | struct net_device *ndev, | ||
2612 | const struct brcmf_event_msg *e, void *data) | ||
2613 | { | ||
2614 | s32 err = 0; | ||
2615 | |||
2616 | if (brcmf_is_linkup(cfg_priv, e)) { | ||
2617 | WL_CONN("Linkup\n"); | ||
2618 | if (brcmf_is_ibssmode(cfg_priv)) { | ||
2619 | brcmf_update_prof(cfg_priv, NULL, (void *)e->addr, | ||
2620 | WL_PROF_BSSID); | ||
2621 | wl_inform_ibss(cfg_priv, ndev, e->addr); | ||
2622 | cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL); | ||
2623 | clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); | ||
2624 | set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); | ||
2625 | } else | ||
2626 | brcmf_bss_connect_done(cfg_priv, ndev, e, data, true); | ||
2627 | } else if (brcmf_is_linkdown(cfg_priv, e)) { | ||
2628 | WL_CONN("Linkdown\n"); | ||
2629 | if (brcmf_is_ibssmode(cfg_priv)) { | ||
2630 | clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); | ||
2631 | if (test_and_clear_bit(WL_STATUS_CONNECTED, | ||
2632 | &cfg_priv->status)) | ||
2633 | brcmf_link_down(cfg_priv); | ||
2634 | } else { | ||
2635 | brcmf_bss_connect_done(cfg_priv, ndev, e, data, false); | ||
2636 | if (test_and_clear_bit(WL_STATUS_CONNECTED, | ||
2637 | &cfg_priv->status)) { | ||
2638 | cfg80211_disconnected(ndev, 0, NULL, 0, | ||
2639 | GFP_KERNEL); | ||
2640 | brcmf_link_down(cfg_priv); | ||
2641 | } | ||
2642 | } | ||
2643 | brcmf_init_prof(cfg_priv->profile); | ||
2644 | } else if (brcmf_is_nonetwork(cfg_priv, e)) { | ||
2645 | if (brcmf_is_ibssmode(cfg_priv)) | ||
2646 | clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); | ||
2647 | else | ||
2648 | brcmf_bss_connect_done(cfg_priv, ndev, e, data, false); | ||
2649 | } | ||
2650 | |||
2651 | return err; | ||
2652 | } | ||
2653 | |||
2654 | static s32 | ||
2655 | brcmf_notify_roaming_status(struct brcmf_cfg80211_priv *cfg_priv, | ||
2656 | struct net_device *ndev, | ||
2657 | const struct brcmf_event_msg *e, void *data) | ||
2658 | { | ||
2659 | s32 err = 0; | ||
2660 | u32 event = be32_to_cpu(e->event_type); | ||
2661 | u32 status = be32_to_cpu(e->status); | ||
2662 | |||
2663 | if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) { | ||
2664 | if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) | ||
2665 | brcmf_bss_roaming_done(cfg_priv, ndev, e, data); | ||
2666 | else | ||
2667 | brcmf_bss_connect_done(cfg_priv, ndev, e, data, true); | ||
2668 | } | ||
2669 | |||
2670 | return err; | ||
2671 | } | ||
2672 | |||
2673 | static __used s32 | ||
2674 | brcmf_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len) | ||
2675 | { | ||
2676 | struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev); | ||
2677 | u32 buflen; | ||
2678 | |||
2679 | buflen = brcmu_mkiovar(name, buf, len, cfg_priv->ioctl_buf, | ||
2680 | WL_IOCTL_LEN_MAX); | ||
2681 | BUG_ON(!buflen); | ||
2682 | |||
2683 | return brcmf_dev_ioctl(dev, BRCMF_C_SET_VAR, cfg_priv->ioctl_buf, | ||
2684 | buflen); | ||
2685 | } | ||
2686 | |||
2687 | static s32 | ||
2688 | brcmf_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf, | ||
2689 | s32 buf_len) | ||
2690 | { | ||
2691 | struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev); | ||
2692 | u32 len; | ||
2693 | s32 err = 0; | ||
2694 | |||
2695 | len = brcmu_mkiovar(name, NULL, 0, cfg_priv->ioctl_buf, | ||
2696 | WL_IOCTL_LEN_MAX); | ||
2697 | BUG_ON(!len); | ||
2698 | err = brcmf_dev_ioctl(dev, BRCMF_C_GET_VAR, (void *)cfg_priv->ioctl_buf, | ||
2699 | WL_IOCTL_LEN_MAX); | ||
2700 | if (unlikely(err)) { | ||
2701 | WL_ERR("error (%d)\n", err); | ||
2702 | return err; | ||
2703 | } | ||
2704 | memcpy(buf, cfg_priv->ioctl_buf, buf_len); | ||
2705 | |||
2706 | return err; | ||
2707 | } | ||
2708 | |||
2709 | static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) | ||
2710 | { | ||
2711 | struct net_device *ndev = cfg_to_ndev(cfg_priv); | ||
2712 | struct brcmf_cfg80211_assoc_ielen *assoc_info; | ||
2713 | struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); | ||
2714 | u32 req_len; | ||
2715 | u32 resp_len; | ||
2716 | s32 err = 0; | ||
2717 | |||
2718 | brcmf_clear_assoc_ies(cfg_priv); | ||
2719 | |||
2720 | err = brcmf_dev_bufvar_get(ndev, "assoc_info", cfg_priv->extra_buf, | ||
2721 | WL_ASSOC_INFO_MAX); | ||
2722 | if (unlikely(err)) { | ||
2723 | WL_ERR("could not get assoc info (%d)\n", err); | ||
2724 | return err; | ||
2725 | } | ||
2726 | assoc_info = (struct brcmf_cfg80211_assoc_ielen *)cfg_priv->extra_buf; | ||
2727 | req_len = assoc_info->req_len; | ||
2728 | resp_len = assoc_info->resp_len; | ||
2729 | if (req_len) { | ||
2730 | err = brcmf_dev_bufvar_get(ndev, "assoc_req_ies", | ||
2731 | cfg_priv->extra_buf, | ||
2732 | WL_ASSOC_INFO_MAX); | ||
2733 | if (unlikely(err)) { | ||
2734 | WL_ERR("could not get assoc req (%d)\n", err); | ||
2735 | return err; | ||
2736 | } | ||
2737 | conn_info->req_ie_len = req_len; | ||
2738 | conn_info->req_ie = | ||
2739 | kmemdup(cfg_priv->extra_buf, conn_info->req_ie_len, | ||
2740 | GFP_KERNEL); | ||
2741 | } else { | ||
2742 | conn_info->req_ie_len = 0; | ||
2743 | conn_info->req_ie = NULL; | ||
2744 | } | ||
2745 | if (resp_len) { | ||
2746 | err = brcmf_dev_bufvar_get(ndev, "assoc_resp_ies", | ||
2747 | cfg_priv->extra_buf, | ||
2748 | WL_ASSOC_INFO_MAX); | ||
2749 | if (unlikely(err)) { | ||
2750 | WL_ERR("could not get assoc resp (%d)\n", err); | ||
2751 | return err; | ||
2752 | } | ||
2753 | conn_info->resp_ie_len = resp_len; | ||
2754 | conn_info->resp_ie = | ||
2755 | kmemdup(cfg_priv->extra_buf, conn_info->resp_ie_len, | ||
2756 | GFP_KERNEL); | ||
2757 | } else { | ||
2758 | conn_info->resp_ie_len = 0; | ||
2759 | conn_info->resp_ie = NULL; | ||
2760 | } | ||
2761 | WL_CONN("req len (%d) resp len (%d)\n", | ||
2762 | conn_info->req_ie_len, conn_info->resp_ie_len); | ||
2763 | |||
2764 | return err; | ||
2765 | } | ||
2766 | |||
2767 | static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) | ||
2768 | { | ||
2769 | struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); | ||
2770 | |||
2771 | kfree(conn_info->req_ie); | ||
2772 | conn_info->req_ie = NULL; | ||
2773 | conn_info->req_ie_len = 0; | ||
2774 | kfree(conn_info->resp_ie); | ||
2775 | conn_info->resp_ie = NULL; | ||
2776 | conn_info->resp_ie_len = 0; | ||
2777 | } | ||
2778 | |||
2779 | |||
2780 | static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params, | ||
2781 | size_t *join_params_size) | ||
2782 | { | ||
2783 | chanspec_t chanspec = 0; | ||
2784 | |||
2785 | if (ch != 0) { | ||
2786 | join_params->params.chanspec_num = 1; | ||
2787 | join_params->params.chanspec_list[0] = ch; | ||
2788 | |||
2789 | if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL) | ||
2790 | chanspec |= WL_CHANSPEC_BAND_2G; | ||
2791 | else | ||
2792 | chanspec |= WL_CHANSPEC_BAND_5G; | ||
2793 | |||
2794 | chanspec |= WL_CHANSPEC_BW_20; | ||
2795 | chanspec |= WL_CHANSPEC_CTL_SB_NONE; | ||
2796 | |||
2797 | *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE + | ||
2798 | join_params->params.chanspec_num * sizeof(chanspec_t); | ||
2799 | |||
2800 | join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; | ||
2801 | join_params->params.chanspec_list[0] |= chanspec; | ||
2802 | join_params->params.chanspec_list[0] = | ||
2803 | cpu_to_le16(join_params->params.chanspec_list[0]); | ||
2804 | |||
2805 | join_params->params.chanspec_num = | ||
2806 | cpu_to_le32(join_params->params.chanspec_num); | ||
2807 | |||
2808 | WL_CONN("join_params->params.chanspec_list[0]= %#X," | ||
2809 | "channel %d, chanspec %#X\n", | ||
2810 | join_params->params.chanspec_list[0], ch, chanspec); | ||
2811 | } | ||
2812 | } | ||
2813 | |||
2814 | static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv) | ||
2815 | { | ||
2816 | struct brcmf_bss_info *bi; | ||
2817 | struct brcmf_ssid *ssid; | ||
2818 | struct brcmu_tlv *tim; | ||
2819 | u16 beacon_interval; | ||
2820 | u8 dtim_period; | ||
2821 | size_t ie_len; | ||
2822 | u8 *ie; | ||
2823 | s32 err = 0; | ||
2824 | |||
2825 | WL_TRACE("Enter\n"); | ||
2826 | if (brcmf_is_ibssmode(cfg_priv)) | ||
2827 | return err; | ||
2828 | |||
2829 | ssid = (struct brcmf_ssid *)brcmf_read_prof(cfg_priv, WL_PROF_SSID); | ||
2830 | |||
2831 | *(u32 *)cfg_priv->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX); | ||
2832 | err = brcmf_dev_ioctl(cfg_to_ndev(cfg_priv), BRCMF_C_GET_BSS_INFO, | ||
2833 | cfg_priv->extra_buf, WL_EXTRA_BUF_MAX); | ||
2834 | if (unlikely(err)) { | ||
2835 | WL_ERR("Could not get bss info %d\n", err); | ||
2836 | goto update_bss_info_out; | ||
2837 | } | ||
2838 | |||
2839 | bi = (struct brcmf_bss_info *)(cfg_priv->extra_buf + 4); | ||
2840 | err = brcmf_inform_single_bss(cfg_priv, bi); | ||
2841 | if (unlikely(err)) | ||
2842 | goto update_bss_info_out; | ||
2843 | |||
2844 | ie = ((u8 *)bi) + bi->ie_offset; | ||
2845 | ie_len = bi->ie_length; | ||
2846 | beacon_interval = cpu_to_le16(bi->beacon_period); | ||
2847 | |||
2848 | tim = brcmu_parse_tlvs(ie, ie_len, WLAN_EID_TIM); | ||
2849 | if (tim) | ||
2850 | dtim_period = tim->data[1]; | ||
2851 | else { | ||
2852 | /* | ||
2853 | * active scan was done so we could not get dtim | ||
2854 | * information out of probe response. | ||
2855 | * so we speficially query dtim information to dongle. | ||
2856 | */ | ||
2857 | u32 var; | ||
2858 | err = brcmf_dev_intvar_get(cfg_to_ndev(cfg_priv), | ||
2859 | "dtim_assoc", &var); | ||
2860 | if (unlikely(err)) { | ||
2861 | WL_ERR("wl dtim_assoc failed (%d)\n", err); | ||
2862 | goto update_bss_info_out; | ||
2863 | } | ||
2864 | dtim_period = (u8)var; | ||
2865 | } | ||
2866 | |||
2867 | brcmf_update_prof(cfg_priv, NULL, &beacon_interval, WL_PROF_BEACONINT); | ||
2868 | brcmf_update_prof(cfg_priv, NULL, &dtim_period, WL_PROF_DTIMPERIOD); | ||
2869 | |||
2870 | update_bss_info_out: | ||
2871 | WL_TRACE("Exit"); | ||
2872 | return err; | ||
2873 | } | ||
2874 | |||
2875 | static s32 | ||
2876 | brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv, | ||
2877 | struct net_device *ndev, | ||
2878 | const struct brcmf_event_msg *e, void *data) | ||
2879 | { | ||
2880 | struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); | ||
2881 | s32 err = 0; | ||
2882 | |||
2883 | WL_TRACE("Enter\n"); | ||
2884 | |||
2885 | brcmf_get_assoc_ies(cfg_priv); | ||
2886 | brcmf_update_prof(cfg_priv, NULL, &e->addr, WL_PROF_BSSID); | ||
2887 | brcmf_update_bss_info(cfg_priv); | ||
2888 | |||
2889 | cfg80211_roamed(ndev, NULL, | ||
2890 | (u8 *)brcmf_read_prof(cfg_priv, WL_PROF_BSSID), | ||
2891 | conn_info->req_ie, conn_info->req_ie_len, | ||
2892 | conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); | ||
2893 | WL_CONN("Report roaming result\n"); | ||
2894 | |||
2895 | set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); | ||
2896 | WL_TRACE("Exit\n"); | ||
2897 | return err; | ||
2898 | } | ||
2899 | |||
2900 | static s32 | ||
2901 | brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv, | ||
2902 | struct net_device *ndev, const struct brcmf_event_msg *e, | ||
2903 | void *data, bool completed) | ||
2904 | { | ||
2905 | struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); | ||
2906 | s32 err = 0; | ||
2907 | |||
2908 | WL_TRACE("Enter\n"); | ||
2909 | |||
2910 | if (test_and_clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) { | ||
2911 | if (completed) { | ||
2912 | brcmf_get_assoc_ies(cfg_priv); | ||
2913 | brcmf_update_prof(cfg_priv, NULL, &e->addr, | ||
2914 | WL_PROF_BSSID); | ||
2915 | brcmf_update_bss_info(cfg_priv); | ||
2916 | } | ||
2917 | cfg80211_connect_result(ndev, | ||
2918 | (u8 *)brcmf_read_prof(cfg_priv, | ||
2919 | WL_PROF_BSSID), | ||
2920 | conn_info->req_ie, | ||
2921 | conn_info->req_ie_len, | ||
2922 | conn_info->resp_ie, | ||
2923 | conn_info->resp_ie_len, | ||
2924 | completed ? WLAN_STATUS_SUCCESS : | ||
2925 | WLAN_STATUS_AUTH_TIMEOUT, | ||
2926 | GFP_KERNEL); | ||
2927 | if (completed) | ||
2928 | set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); | ||
2929 | WL_CONN("Report connect result - connection %s\n", | ||
2930 | completed ? "succeeded" : "failed"); | ||
2931 | } | ||
2932 | WL_TRACE("Exit\n"); | ||
2933 | return err; | ||
2934 | } | ||
2935 | |||
2936 | static s32 | ||
2937 | brcmf_notify_mic_status(struct brcmf_cfg80211_priv *cfg_priv, | ||
2938 | struct net_device *ndev, | ||
2939 | const struct brcmf_event_msg *e, void *data) | ||
2940 | { | ||
2941 | u16 flags = be16_to_cpu(e->flags); | ||
2942 | enum nl80211_key_type key_type; | ||
2943 | |||
2944 | rtnl_lock(); | ||
2945 | if (flags & BRCMF_EVENT_MSG_GROUP) | ||
2946 | key_type = NL80211_KEYTYPE_GROUP; | ||
2947 | else | ||
2948 | key_type = NL80211_KEYTYPE_PAIRWISE; | ||
2949 | |||
2950 | cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1, | ||
2951 | NULL, GFP_KERNEL); | ||
2952 | rtnl_unlock(); | ||
2953 | |||
2954 | return 0; | ||
2955 | } | ||
2956 | |||
2957 | static s32 | ||
2958 | brcmf_notify_scan_status(struct brcmf_cfg80211_priv *cfg_priv, | ||
2959 | struct net_device *ndev, | ||
2960 | const struct brcmf_event_msg *e, void *data) | ||
2961 | { | ||
2962 | struct brcmf_channel_info channel_inform; | ||
2963 | struct brcmf_scan_results *bss_list; | ||
2964 | u32 len = WL_SCAN_BUF_MAX; | ||
2965 | s32 err = 0; | ||
2966 | bool scan_abort = false; | ||
2967 | |||
2968 | WL_TRACE("Enter\n"); | ||
2969 | |||
2970 | if (cfg_priv->iscan_on && cfg_priv->iscan_kickstart) { | ||
2971 | WL_TRACE("Exit\n"); | ||
2972 | return brcmf_wakeup_iscan(cfg_to_iscan(cfg_priv)); | ||
2973 | } | ||
2974 | |||
2975 | if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, | ||
2976 | &cfg_priv->status))) { | ||
2977 | WL_ERR("Scan complete while device not scanning\n"); | ||
2978 | scan_abort = true; | ||
2979 | err = -EINVAL; | ||
2980 | goto scan_done_out; | ||
2981 | } | ||
2982 | |||
2983 | err = brcmf_dev_ioctl(ndev, BRCMF_C_GET_CHANNEL, &channel_inform, | ||
2984 | sizeof(channel_inform)); | ||
2985 | if (unlikely(err)) { | ||
2986 | WL_ERR("scan busy (%d)\n", err); | ||
2987 | scan_abort = true; | ||
2988 | goto scan_done_out; | ||
2989 | } | ||
2990 | channel_inform.scan_channel = le32_to_cpu(channel_inform.scan_channel); | ||
2991 | if (unlikely(channel_inform.scan_channel)) { | ||
2992 | |||
2993 | WL_CONN("channel_inform.scan_channel (%d)\n", | ||
2994 | channel_inform.scan_channel); | ||
2995 | } | ||
2996 | cfg_priv->bss_list = cfg_priv->scan_results; | ||
2997 | bss_list = cfg_priv->bss_list; | ||
2998 | memset(bss_list, 0, len); | ||
2999 | bss_list->buflen = cpu_to_le32(len); | ||
3000 | |||
3001 | err = brcmf_dev_ioctl(ndev, BRCMF_C_SCAN_RESULTS, bss_list, len); | ||
3002 | if (unlikely(err)) { | ||
3003 | WL_ERR("%s Scan_results error (%d)\n", ndev->name, err); | ||
3004 | err = -EINVAL; | ||
3005 | scan_abort = true; | ||
3006 | goto scan_done_out; | ||
3007 | } | ||
3008 | bss_list->buflen = le32_to_cpu(bss_list->buflen); | ||
3009 | bss_list->version = le32_to_cpu(bss_list->version); | ||
3010 | bss_list->count = le32_to_cpu(bss_list->count); | ||
3011 | |||
3012 | err = brcmf_inform_bss(cfg_priv); | ||
3013 | if (err) { | ||
3014 | scan_abort = true; | ||
3015 | goto scan_done_out; | ||
3016 | } | ||
3017 | |||
3018 | scan_done_out: | ||
3019 | if (cfg_priv->scan_request) { | ||
3020 | WL_SCAN("calling cfg80211_scan_done\n"); | ||
3021 | cfg80211_scan_done(cfg_priv->scan_request, scan_abort); | ||
3022 | brcmf_set_mpc(ndev, 1); | ||
3023 | cfg_priv->scan_request = NULL; | ||
3024 | } | ||
3025 | |||
3026 | WL_TRACE("Exit\n"); | ||
3027 | |||
3028 | return err; | ||
3029 | } | ||
3030 | |||
3031 | static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) | ||
3032 | { | ||
3033 | conf->mode = (u32)-1; | ||
3034 | conf->frag_threshold = (u32)-1; | ||
3035 | conf->rts_threshold = (u32)-1; | ||
3036 | conf->retry_short = (u32)-1; | ||
3037 | conf->retry_long = (u32)-1; | ||
3038 | conf->tx_power = -1; | ||
3039 | } | ||
3040 | |||
3041 | static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof) | ||
3042 | { | ||
3043 | memset(prof, 0, sizeof(*prof)); | ||
3044 | } | ||
3045 | |||
3046 | static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el) | ||
3047 | { | ||
3048 | memset(el, 0, sizeof(*el)); | ||
3049 | el->handler[BRCMF_E_SCAN_COMPLETE] = brcmf_notify_scan_status; | ||
3050 | el->handler[BRCMF_E_LINK] = brcmf_notify_connect_status; | ||
3051 | el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status; | ||
3052 | el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status; | ||
3053 | el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status; | ||
3054 | } | ||
3055 | |||
3056 | static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_priv *cfg_priv) | ||
3057 | { | ||
3058 | cfg_priv->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); | ||
3059 | if (unlikely(!cfg_priv->scan_results)) { | ||
3060 | WL_ERR("Scan results alloc failed\n"); | ||
3061 | goto init_priv_mem_out; | ||
3062 | } | ||
3063 | cfg_priv->conf = kzalloc(sizeof(*cfg_priv->conf), GFP_KERNEL); | ||
3064 | if (unlikely(!cfg_priv->conf)) { | ||
3065 | WL_ERR("wl_conf alloc failed\n"); | ||
3066 | goto init_priv_mem_out; | ||
3067 | } | ||
3068 | cfg_priv->profile = kzalloc(sizeof(*cfg_priv->profile), GFP_KERNEL); | ||
3069 | if (unlikely(!cfg_priv->profile)) { | ||
3070 | WL_ERR("wl_profile alloc failed\n"); | ||
3071 | goto init_priv_mem_out; | ||
3072 | } | ||
3073 | cfg_priv->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); | ||
3074 | if (unlikely(!cfg_priv->bss_info)) { | ||
3075 | WL_ERR("Bss information alloc failed\n"); | ||
3076 | goto init_priv_mem_out; | ||
3077 | } | ||
3078 | cfg_priv->scan_req_int = kzalloc(sizeof(*cfg_priv->scan_req_int), | ||
3079 | GFP_KERNEL); | ||
3080 | if (unlikely(!cfg_priv->scan_req_int)) { | ||
3081 | WL_ERR("Scan req alloc failed\n"); | ||
3082 | goto init_priv_mem_out; | ||
3083 | } | ||
3084 | cfg_priv->ioctl_buf = kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL); | ||
3085 | if (unlikely(!cfg_priv->ioctl_buf)) { | ||
3086 | WL_ERR("Ioctl buf alloc failed\n"); | ||
3087 | goto init_priv_mem_out; | ||
3088 | } | ||
3089 | cfg_priv->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); | ||
3090 | if (unlikely(!cfg_priv->extra_buf)) { | ||
3091 | WL_ERR("Extra buf alloc failed\n"); | ||
3092 | goto init_priv_mem_out; | ||
3093 | } | ||
3094 | cfg_priv->iscan = kzalloc(sizeof(*cfg_priv->iscan), GFP_KERNEL); | ||
3095 | if (unlikely(!cfg_priv->iscan)) { | ||
3096 | WL_ERR("Iscan buf alloc failed\n"); | ||
3097 | goto init_priv_mem_out; | ||
3098 | } | ||
3099 | cfg_priv->pmk_list = kzalloc(sizeof(*cfg_priv->pmk_list), GFP_KERNEL); | ||
3100 | if (unlikely(!cfg_priv->pmk_list)) { | ||
3101 | WL_ERR("pmk list alloc failed\n"); | ||
3102 | goto init_priv_mem_out; | ||
3103 | } | ||
3104 | |||
3105 | return 0; | ||
3106 | |||
3107 | init_priv_mem_out: | ||
3108 | brcmf_deinit_priv_mem(cfg_priv); | ||
3109 | |||
3110 | return -ENOMEM; | ||
3111 | } | ||
3112 | |||
3113 | static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv) | ||
3114 | { | ||
3115 | kfree(cfg_priv->scan_results); | ||
3116 | cfg_priv->scan_results = NULL; | ||
3117 | kfree(cfg_priv->bss_info); | ||
3118 | cfg_priv->bss_info = NULL; | ||
3119 | kfree(cfg_priv->conf); | ||
3120 | cfg_priv->conf = NULL; | ||
3121 | kfree(cfg_priv->profile); | ||
3122 | cfg_priv->profile = NULL; | ||
3123 | kfree(cfg_priv->scan_req_int); | ||
3124 | cfg_priv->scan_req_int = NULL; | ||
3125 | kfree(cfg_priv->ioctl_buf); | ||
3126 | cfg_priv->ioctl_buf = NULL; | ||
3127 | kfree(cfg_priv->extra_buf); | ||
3128 | cfg_priv->extra_buf = NULL; | ||
3129 | kfree(cfg_priv->iscan); | ||
3130 | cfg_priv->iscan = NULL; | ||
3131 | kfree(cfg_priv->pmk_list); | ||
3132 | cfg_priv->pmk_list = NULL; | ||
3133 | } | ||
3134 | |||
3135 | static s32 brcmf_create_event_handler(struct brcmf_cfg80211_priv *cfg_priv) | ||
3136 | { | ||
3137 | sema_init(&cfg_priv->event_sync, 0); | ||
3138 | cfg_priv->event_tsk = kthread_run(brcmf_event_handler, cfg_priv, | ||
3139 | "wl_event_handler"); | ||
3140 | if (IS_ERR(cfg_priv->event_tsk)) { | ||
3141 | cfg_priv->event_tsk = NULL; | ||
3142 | WL_ERR("failed to create event thread\n"); | ||
3143 | return -ENOMEM; | ||
3144 | } | ||
3145 | return 0; | ||
3146 | } | ||
3147 | |||
3148 | static void brcmf_destroy_event_handler(struct brcmf_cfg80211_priv *cfg_priv) | ||
3149 | { | ||
3150 | if (cfg_priv->event_tsk) { | ||
3151 | send_sig(SIGTERM, cfg_priv->event_tsk, 1); | ||
3152 | kthread_stop(cfg_priv->event_tsk); | ||
3153 | cfg_priv->event_tsk = NULL; | ||
3154 | } | ||
3155 | } | ||
3156 | |||
3157 | static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv) | ||
3158 | { | ||
3159 | struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); | ||
3160 | |||
3161 | if (cfg_priv->iscan_on && iscan->tsk) { | ||
3162 | iscan->state = WL_ISCAN_STATE_IDLE; | ||
3163 | send_sig(SIGTERM, iscan->tsk, 1); | ||
3164 | kthread_stop(iscan->tsk); | ||
3165 | iscan->tsk = NULL; | ||
3166 | } | ||
3167 | } | ||
3168 | |||
3169 | static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan, | ||
3170 | bool aborted) | ||
3171 | { | ||
3172 | struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan); | ||
3173 | struct net_device *ndev = cfg_to_ndev(cfg_priv); | ||
3174 | |||
3175 | if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, | ||
3176 | &cfg_priv->status))) { | ||
3177 | WL_ERR("Scan complete while device not scanning\n"); | ||
3178 | return; | ||
3179 | } | ||
3180 | if (likely(cfg_priv->scan_request)) { | ||
3181 | WL_SCAN("ISCAN Completed scan: %s\n", | ||
3182 | aborted ? "Aborted" : "Done"); | ||
3183 | cfg80211_scan_done(cfg_priv->scan_request, aborted); | ||
3184 | brcmf_set_mpc(ndev, 1); | ||
3185 | cfg_priv->scan_request = NULL; | ||
3186 | } | ||
3187 | cfg_priv->iscan_kickstart = false; | ||
3188 | } | ||
3189 | |||
3190 | static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan) | ||
3191 | { | ||
3192 | if (likely(iscan->state != WL_ISCAN_STATE_IDLE)) { | ||
3193 | WL_SCAN("wake up iscan\n"); | ||
3194 | up(&iscan->sync); | ||
3195 | return 0; | ||
3196 | } | ||
3197 | |||
3198 | return -EIO; | ||
3199 | } | ||
3200 | |||
3201 | static s32 | ||
3202 | brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status, | ||
3203 | struct brcmf_scan_results **bss_list) | ||
3204 | { | ||
3205 | struct brcmf_iscan_results list; | ||
3206 | struct brcmf_scan_results *results; | ||
3207 | struct brcmf_iscan_results *list_buf; | ||
3208 | s32 err = 0; | ||
3209 | |||
3210 | memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX); | ||
3211 | list_buf = (struct brcmf_iscan_results *)iscan->scan_buf; | ||
3212 | results = &list_buf->results; | ||
3213 | results->buflen = BRCMF_ISCAN_RESULTS_FIXED_SIZE; | ||
3214 | results->version = 0; | ||
3215 | results->count = 0; | ||
3216 | |||
3217 | memset(&list, 0, sizeof(list)); | ||
3218 | list.results.buflen = cpu_to_le32(WL_ISCAN_BUF_MAX); | ||
3219 | err = brcmf_dev_iovar_getbuf(iscan->dev, "iscanresults", &list, | ||
3220 | BRCMF_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf, | ||
3221 | WL_ISCAN_BUF_MAX); | ||
3222 | if (unlikely(err)) { | ||
3223 | WL_ERR("error (%d)\n", err); | ||
3224 | return err; | ||
3225 | } | ||
3226 | results->buflen = le32_to_cpu(results->buflen); | ||
3227 | results->version = le32_to_cpu(results->version); | ||
3228 | results->count = le32_to_cpu(results->count); | ||
3229 | WL_SCAN("results->count = %d\n", results->count); | ||
3230 | WL_SCAN("results->buflen = %d\n", results->buflen); | ||
3231 | *status = le32_to_cpu(list_buf->status); | ||
3232 | *bss_list = results; | ||
3233 | |||
3234 | return err; | ||
3235 | } | ||
3236 | |||
3237 | static s32 brcmf_iscan_done(struct brcmf_cfg80211_priv *cfg_priv) | ||
3238 | { | ||
3239 | struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; | ||
3240 | s32 err = 0; | ||
3241 | |||
3242 | iscan->state = WL_ISCAN_STATE_IDLE; | ||
3243 | rtnl_lock(); | ||
3244 | brcmf_inform_bss(cfg_priv); | ||
3245 | brcmf_notify_iscan_complete(iscan, false); | ||
3246 | rtnl_unlock(); | ||
3247 | |||
3248 | return err; | ||
3249 | } | ||
3250 | |||
3251 | static s32 brcmf_iscan_pending(struct brcmf_cfg80211_priv *cfg_priv) | ||
3252 | { | ||
3253 | struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; | ||
3254 | s32 err = 0; | ||
3255 | |||
3256 | /* Reschedule the timer */ | ||
3257 | mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); | ||
3258 | iscan->timer_on = 1; | ||
3259 | |||
3260 | return err; | ||
3261 | } | ||
3262 | |||
3263 | static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_priv *cfg_priv) | ||
3264 | { | ||
3265 | struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; | ||
3266 | s32 err = 0; | ||
3267 | |||
3268 | rtnl_lock(); | ||
3269 | brcmf_inform_bss(cfg_priv); | ||
3270 | brcmf_run_iscan(iscan, NULL, BRCMF_SCAN_ACTION_CONTINUE); | ||
3271 | rtnl_unlock(); | ||
3272 | /* Reschedule the timer */ | ||
3273 | mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); | ||
3274 | iscan->timer_on = 1; | ||
3275 | |||
3276 | return err; | ||
3277 | } | ||
3278 | |||
3279 | static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_priv *cfg_priv) | ||
3280 | { | ||
3281 | struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; | ||
3282 | s32 err = 0; | ||
3283 | |||
3284 | iscan->state = WL_ISCAN_STATE_IDLE; | ||
3285 | rtnl_lock(); | ||
3286 | brcmf_notify_iscan_complete(iscan, true); | ||
3287 | rtnl_unlock(); | ||
3288 | |||
3289 | return err; | ||
3290 | } | ||
3291 | |||
3292 | static s32 brcmf_iscan_thread(void *data) | ||
3293 | { | ||
3294 | struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 }; | ||
3295 | struct brcmf_cfg80211_iscan_ctrl *iscan = | ||
3296 | (struct brcmf_cfg80211_iscan_ctrl *)data; | ||
3297 | struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan); | ||
3298 | struct brcmf_cfg80211_iscan_eloop *el = &iscan->el; | ||
3299 | u32 status; | ||
3300 | int err = 0; | ||
3301 | |||
3302 | sched_setscheduler(current, SCHED_FIFO, ¶m); | ||
3303 | allow_signal(SIGTERM); | ||
3304 | status = BRCMF_SCAN_RESULTS_PARTIAL; | ||
3305 | while (likely(!down_interruptible(&iscan->sync))) { | ||
3306 | if (kthread_should_stop()) | ||
3307 | break; | ||
3308 | if (iscan->timer_on) { | ||
3309 | del_timer_sync(&iscan->timer); | ||
3310 | iscan->timer_on = 0; | ||
3311 | } | ||
3312 | rtnl_lock(); | ||
3313 | err = brcmf_get_iscan_results(iscan, &status, | ||
3314 | &cfg_priv->bss_list); | ||
3315 | if (unlikely(err)) { | ||
3316 | status = BRCMF_SCAN_RESULTS_ABORTED; | ||
3317 | WL_ERR("Abort iscan\n"); | ||
3318 | } | ||
3319 | rtnl_unlock(); | ||
3320 | el->handler[status](cfg_priv); | ||
3321 | } | ||
3322 | if (iscan->timer_on) { | ||
3323 | del_timer_sync(&iscan->timer); | ||
3324 | iscan->timer_on = 0; | ||
3325 | } | ||
3326 | WL_SCAN("ISCAN thread terminated\n"); | ||
3327 | |||
3328 | return 0; | ||
3329 | } | ||
3330 | |||
3331 | static void brcmf_iscan_timer(unsigned long data) | ||
3332 | { | ||
3333 | struct brcmf_cfg80211_iscan_ctrl *iscan = | ||
3334 | (struct brcmf_cfg80211_iscan_ctrl *)data; | ||
3335 | |||
3336 | if (iscan) { | ||
3337 | iscan->timer_on = 0; | ||
3338 | WL_SCAN("timer expired\n"); | ||
3339 | brcmf_wakeup_iscan(iscan); | ||
3340 | } | ||
3341 | } | ||
3342 | |||
3343 | static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_priv *cfg_priv) | ||
3344 | { | ||
3345 | struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); | ||
3346 | int err = 0; | ||
3347 | |||
3348 | if (cfg_priv->iscan_on && !iscan->tsk) { | ||
3349 | iscan->state = WL_ISCAN_STATE_IDLE; | ||
3350 | sema_init(&iscan->sync, 0); | ||
3351 | iscan->tsk = kthread_run(brcmf_iscan_thread, iscan, "wl_iscan"); | ||
3352 | if (IS_ERR(iscan->tsk)) { | ||
3353 | WL_ERR("Could not create iscan thread\n"); | ||
3354 | iscan->tsk = NULL; | ||
3355 | return -ENOMEM; | ||
3356 | } | ||
3357 | } | ||
3358 | |||
3359 | return err; | ||
3360 | } | ||
3361 | |||
3362 | static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el) | ||
3363 | { | ||
3364 | memset(el, 0, sizeof(*el)); | ||
3365 | el->handler[BRCMF_SCAN_RESULTS_SUCCESS] = brcmf_iscan_done; | ||
3366 | el->handler[BRCMF_SCAN_RESULTS_PARTIAL] = brcmf_iscan_inprogress; | ||
3367 | el->handler[BRCMF_SCAN_RESULTS_PENDING] = brcmf_iscan_pending; | ||
3368 | el->handler[BRCMF_SCAN_RESULTS_ABORTED] = brcmf_iscan_aborted; | ||
3369 | el->handler[BRCMF_SCAN_RESULTS_NO_MEM] = brcmf_iscan_aborted; | ||
3370 | } | ||
3371 | |||
3372 | static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv) | ||
3373 | { | ||
3374 | struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); | ||
3375 | int err = 0; | ||
3376 | |||
3377 | if (cfg_priv->iscan_on) { | ||
3378 | iscan->dev = cfg_to_ndev(cfg_priv); | ||
3379 | iscan->state = WL_ISCAN_STATE_IDLE; | ||
3380 | brcmf_init_iscan_eloop(&iscan->el); | ||
3381 | iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS; | ||
3382 | init_timer(&iscan->timer); | ||
3383 | iscan->timer.data = (unsigned long) iscan; | ||
3384 | iscan->timer.function = brcmf_iscan_timer; | ||
3385 | sema_init(&iscan->sync, 0); | ||
3386 | iscan->tsk = kthread_run(brcmf_iscan_thread, iscan, "wl_iscan"); | ||
3387 | if (IS_ERR(iscan->tsk)) { | ||
3388 | WL_ERR("Could not create iscan thread\n"); | ||
3389 | iscan->tsk = NULL; | ||
3390 | return -ENOMEM; | ||
3391 | } | ||
3392 | iscan->data = cfg_priv; | ||
3393 | } | ||
3394 | |||
3395 | return err; | ||
3396 | } | ||
3397 | |||
3398 | static s32 wl_init_priv(struct brcmf_cfg80211_priv *cfg_priv) | ||
3399 | { | ||
3400 | struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); | ||
3401 | s32 err = 0; | ||
3402 | |||
3403 | cfg_priv->scan_request = NULL; | ||
3404 | cfg_priv->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT); | ||
3405 | cfg_priv->iscan_on = true; /* iscan on & off switch. | ||
3406 | we enable iscan per default */ | ||
3407 | cfg_priv->roam_on = false; /* roam on & off switch. | ||
3408 | we enable roam per default */ | ||
3409 | |||
3410 | cfg_priv->iscan_kickstart = false; | ||
3411 | cfg_priv->active_scan = true; /* we do active scan for | ||
3412 | specific scan per default */ | ||
3413 | cfg_priv->dongle_up = false; /* dongle is not up yet */ | ||
3414 | brcmf_init_eq(cfg_priv); | ||
3415 | err = brcmf_init_priv_mem(cfg_priv); | ||
3416 | if (unlikely(err)) | ||
3417 | return err; | ||
3418 | if (unlikely(brcmf_create_event_handler(cfg_priv))) | ||
3419 | return -ENOMEM; | ||
3420 | brcmf_init_eloop_handler(&cfg_priv->el); | ||
3421 | mutex_init(&cfg_priv->usr_sync); | ||
3422 | err = brcmf_init_iscan(cfg_priv); | ||
3423 | if (unlikely(err)) | ||
3424 | return err; | ||
3425 | brcmf_init_conf(cfg_priv->conf); | ||
3426 | brcmf_init_prof(cfg_priv->profile); | ||
3427 | brcmf_link_down(cfg_priv); | ||
3428 | |||
3429 | return err; | ||
3430 | } | ||
3431 | |||
3432 | static void wl_deinit_priv(struct brcmf_cfg80211_priv *cfg_priv) | ||
3433 | { | ||
3434 | brcmf_destroy_event_handler(cfg_priv); | ||
3435 | cfg_priv->dongle_up = false; /* dongle down */ | ||
3436 | brcmf_flush_eq(cfg_priv); | ||
3437 | brcmf_link_down(cfg_priv); | ||
3438 | brcmf_term_iscan(cfg_priv); | ||
3439 | brcmf_deinit_priv_mem(cfg_priv); | ||
3440 | } | ||
3441 | |||
3442 | s32 brcmf_cfg80211_attach(struct net_device *ndev, void *data) | ||
3443 | { | ||
3444 | struct wireless_dev *wdev; | ||
3445 | struct brcmf_cfg80211_priv *cfg_priv; | ||
3446 | struct brcmf_cfg80211_iface *ci; | ||
3447 | s32 err = 0; | ||
3448 | |||
3449 | if (unlikely(!ndev)) { | ||
3450 | WL_ERR("ndev is invalid\n"); | ||
3451 | return -ENODEV; | ||
3452 | } | ||
3453 | cfg80211_dev = kzalloc(sizeof(struct brcmf_cfg80211_dev), GFP_KERNEL); | ||
3454 | if (unlikely(!cfg80211_dev)) { | ||
3455 | WL_ERR("wl_cfg80211_dev is invalid\n"); | ||
3456 | return -ENOMEM; | ||
3457 | } | ||
3458 | WL_INFO("func %p\n", brcmf_cfg80211_get_sdio_func()); | ||
3459 | wdev = brcmf_alloc_wdev(sizeof(struct brcmf_cfg80211_iface), | ||
3460 | &brcmf_cfg80211_get_sdio_func()->dev); | ||
3461 | if (IS_ERR(wdev)) | ||
3462 | return -ENOMEM; | ||
3463 | |||
3464 | wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS); | ||
3465 | cfg_priv = wdev_to_cfg(wdev); | ||
3466 | cfg_priv->wdev = wdev; | ||
3467 | cfg_priv->pub = data; | ||
3468 | ci = (struct brcmf_cfg80211_iface *)&cfg_priv->ci; | ||
3469 | ci->cfg_priv = cfg_priv; | ||
3470 | ndev->ieee80211_ptr = wdev; | ||
3471 | SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); | ||
3472 | wdev->netdev = ndev; | ||
3473 | err = wl_init_priv(cfg_priv); | ||
3474 | if (unlikely(err)) { | ||
3475 | WL_ERR("Failed to init iwm_priv (%d)\n", err); | ||
3476 | goto cfg80211_attach_out; | ||
3477 | } | ||
3478 | brcmf_set_drvdata(cfg80211_dev, ci); | ||
3479 | |||
3480 | return err; | ||
3481 | |||
3482 | cfg80211_attach_out: | ||
3483 | brcmf_free_wdev(cfg_priv); | ||
3484 | return err; | ||
3485 | } | ||
3486 | |||
3487 | void brcmf_cfg80211_detach(void) | ||
3488 | { | ||
3489 | struct brcmf_cfg80211_priv *cfg_priv; | ||
3490 | |||
3491 | cfg_priv = WL_PRIV_GET(); | ||
3492 | |||
3493 | wl_deinit_priv(cfg_priv); | ||
3494 | brcmf_free_wdev(cfg_priv); | ||
3495 | brcmf_set_drvdata(cfg80211_dev, NULL); | ||
3496 | kfree(cfg80211_dev); | ||
3497 | cfg80211_dev = NULL; | ||
3498 | brcmf_clear_sdio_func(); | ||
3499 | } | ||
3500 | |||
3501 | static void brcmf_wakeup_event(struct brcmf_cfg80211_priv *cfg_priv) | ||
3502 | { | ||
3503 | up(&cfg_priv->event_sync); | ||
3504 | } | ||
3505 | |||
3506 | static s32 brcmf_event_handler(void *data) | ||
3507 | { | ||
3508 | struct brcmf_cfg80211_priv *cfg_priv = | ||
3509 | (struct brcmf_cfg80211_priv *)data; | ||
3510 | struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 }; | ||
3511 | struct brcmf_cfg80211_event_q *e; | ||
3512 | |||
3513 | sched_setscheduler(current, SCHED_FIFO, ¶m); | ||
3514 | allow_signal(SIGTERM); | ||
3515 | while (likely(!down_interruptible(&cfg_priv->event_sync))) { | ||
3516 | if (kthread_should_stop()) | ||
3517 | break; | ||
3518 | e = brcmf_deq_event(cfg_priv); | ||
3519 | if (unlikely(!e)) { | ||
3520 | WL_ERR("event queue empty...\n"); | ||
3521 | BUG(); | ||
3522 | } | ||
3523 | WL_INFO("event type (%d)\n", e->etype); | ||
3524 | if (cfg_priv->el.handler[e->etype]) { | ||
3525 | cfg_priv->el.handler[e->etype](cfg_priv, | ||
3526 | cfg_to_ndev(cfg_priv), | ||
3527 | &e->emsg, e->edata); | ||
3528 | } else { | ||
3529 | WL_INFO("Unknown Event (%d): ignoring\n", e->etype); | ||
3530 | } | ||
3531 | brcmf_put_event(e); | ||
3532 | } | ||
3533 | WL_INFO("was terminated\n"); | ||
3534 | return 0; | ||
3535 | } | ||
3536 | |||
3537 | void | ||
3538 | brcmf_cfg80211_event(struct net_device *ndev, | ||
3539 | const struct brcmf_event_msg *e, void *data) | ||
3540 | { | ||
3541 | u32 event_type = be32_to_cpu(e->event_type); | ||
3542 | struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); | ||
3543 | |||
3544 | if (likely(!brcmf_enq_event(cfg_priv, event_type, e, data))) | ||
3545 | brcmf_wakeup_event(cfg_priv); | ||
3546 | } | ||
3547 | |||
3548 | static void brcmf_init_eq(struct brcmf_cfg80211_priv *cfg_priv) | ||
3549 | { | ||
3550 | brcmf_init_eq_lock(cfg_priv); | ||
3551 | INIT_LIST_HEAD(&cfg_priv->eq_list); | ||
3552 | } | ||
3553 | |||
3554 | static void brcmf_flush_eq(struct brcmf_cfg80211_priv *cfg_priv) | ||
3555 | { | ||
3556 | struct brcmf_cfg80211_event_q *e; | ||
3557 | |||
3558 | brcmf_lock_eq(cfg_priv); | ||
3559 | while (!list_empty(&cfg_priv->eq_list)) { | ||
3560 | e = list_first_entry(&cfg_priv->eq_list, | ||
3561 | struct brcmf_cfg80211_event_q, eq_list); | ||
3562 | list_del(&e->eq_list); | ||
3563 | kfree(e); | ||
3564 | } | ||
3565 | brcmf_unlock_eq(cfg_priv); | ||
3566 | } | ||
3567 | |||
3568 | /* | ||
3569 | * retrieve first queued event from head | ||
3570 | */ | ||
3571 | |||
3572 | static struct brcmf_cfg80211_event_q *brcmf_deq_event( | ||
3573 | struct brcmf_cfg80211_priv *cfg_priv) | ||
3574 | { | ||
3575 | struct brcmf_cfg80211_event_q *e = NULL; | ||
3576 | |||
3577 | brcmf_lock_eq(cfg_priv); | ||
3578 | if (likely(!list_empty(&cfg_priv->eq_list))) { | ||
3579 | e = list_first_entry(&cfg_priv->eq_list, | ||
3580 | struct brcmf_cfg80211_event_q, eq_list); | ||
3581 | list_del(&e->eq_list); | ||
3582 | } | ||
3583 | brcmf_unlock_eq(cfg_priv); | ||
3584 | |||
3585 | return e; | ||
3586 | } | ||
3587 | |||
3588 | /* | ||
3589 | ** push event to tail of the queue | ||
3590 | */ | ||
3591 | |||
3592 | static s32 | ||
3593 | brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 event, | ||
3594 | const struct brcmf_event_msg *msg, void *data) | ||
3595 | { | ||
3596 | struct brcmf_cfg80211_event_q *e; | ||
3597 | s32 err = 0; | ||
3598 | |||
3599 | e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_KERNEL); | ||
3600 | if (unlikely(!e)) { | ||
3601 | WL_ERR("event alloc failed\n"); | ||
3602 | return -ENOMEM; | ||
3603 | } | ||
3604 | |||
3605 | e->etype = event; | ||
3606 | memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg)); | ||
3607 | |||
3608 | brcmf_lock_eq(cfg_priv); | ||
3609 | list_add_tail(&e->eq_list, &cfg_priv->eq_list); | ||
3610 | brcmf_unlock_eq(cfg_priv); | ||
3611 | |||
3612 | return err; | ||
3613 | } | ||
3614 | |||
3615 | static void brcmf_put_event(struct brcmf_cfg80211_event_q *e) | ||
3616 | { | ||
3617 | kfree(e); | ||
3618 | } | ||
3619 | |||
3620 | void brcmf_cfg80211_sdio_func(void *func) | ||
3621 | { | ||
3622 | cfg80211_sdio_func = (struct sdio_func *)func; | ||
3623 | } | ||
3624 | |||
3625 | static void brcmf_clear_sdio_func(void) | ||
3626 | { | ||
3627 | cfg80211_sdio_func = NULL; | ||
3628 | } | ||
3629 | |||
3630 | struct sdio_func *brcmf_cfg80211_get_sdio_func(void) | ||
3631 | { | ||
3632 | return cfg80211_sdio_func; | ||
3633 | } | ||
3634 | |||
3635 | static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype) | ||
3636 | { | ||
3637 | s32 infra = 0; | ||
3638 | s32 err = 0; | ||
3639 | |||
3640 | switch (iftype) { | ||
3641 | case NL80211_IFTYPE_MONITOR: | ||
3642 | case NL80211_IFTYPE_WDS: | ||
3643 | WL_ERR("type (%d) : currently we do not support this mode\n", | ||
3644 | iftype); | ||
3645 | err = -EINVAL; | ||
3646 | return err; | ||
3647 | case NL80211_IFTYPE_ADHOC: | ||
3648 | infra = 0; | ||
3649 | break; | ||
3650 | case NL80211_IFTYPE_STATION: | ||
3651 | infra = 1; | ||
3652 | break; | ||
3653 | default: | ||
3654 | err = -EINVAL; | ||
3655 | WL_ERR("invalid type (%d)\n", iftype); | ||
3656 | return err; | ||
3657 | } | ||
3658 | infra = cpu_to_le32(infra); | ||
3659 | err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_INFRA, &infra, sizeof(infra)); | ||
3660 | if (unlikely(err)) { | ||
3661 | WL_ERR("WLC_SET_INFRA error (%d)\n", err); | ||
3662 | return err; | ||
3663 | } | ||
3664 | |||
3665 | return 0; | ||
3666 | } | ||
3667 | |||
3668 | static s32 brcmf_dongle_eventmsg(struct net_device *ndev) | ||
3669 | { | ||
3670 | /* Room for "event_msgs" + '\0' + bitvec */ | ||
3671 | s8 iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; | ||
3672 | s8 eventmask[BRCMF_EVENTING_MASK_LEN]; | ||
3673 | s32 err = 0; | ||
3674 | |||
3675 | WL_TRACE("Enter\n"); | ||
3676 | |||
3677 | /* Setup event_msgs */ | ||
3678 | brcmu_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, iovbuf, | ||
3679 | sizeof(iovbuf)); | ||
3680 | err = brcmf_dev_ioctl(ndev, BRCMF_C_GET_VAR, iovbuf, sizeof(iovbuf)); | ||
3681 | if (unlikely(err)) { | ||
3682 | WL_ERR("Get event_msgs error (%d)\n", err); | ||
3683 | goto dongle_eventmsg_out; | ||
3684 | } | ||
3685 | memcpy(eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN); | ||
3686 | |||
3687 | setbit(eventmask, BRCMF_E_SET_SSID); | ||
3688 | setbit(eventmask, BRCMF_E_ROAM); | ||
3689 | setbit(eventmask, BRCMF_E_PRUNE); | ||
3690 | setbit(eventmask, BRCMF_E_AUTH); | ||
3691 | setbit(eventmask, BRCMF_E_REASSOC); | ||
3692 | setbit(eventmask, BRCMF_E_REASSOC_IND); | ||
3693 | setbit(eventmask, BRCMF_E_DEAUTH_IND); | ||
3694 | setbit(eventmask, BRCMF_E_DISASSOC_IND); | ||
3695 | setbit(eventmask, BRCMF_E_DISASSOC); | ||
3696 | setbit(eventmask, BRCMF_E_JOIN); | ||
3697 | setbit(eventmask, BRCMF_E_ASSOC_IND); | ||
3698 | setbit(eventmask, BRCMF_E_PSK_SUP); | ||
3699 | setbit(eventmask, BRCMF_E_LINK); | ||
3700 | setbit(eventmask, BRCMF_E_NDIS_LINK); | ||
3701 | setbit(eventmask, BRCMF_E_MIC_ERROR); | ||
3702 | setbit(eventmask, BRCMF_E_PMKID_CACHE); | ||
3703 | setbit(eventmask, BRCMF_E_TXFAIL); | ||
3704 | setbit(eventmask, BRCMF_E_JOIN_START); | ||
3705 | setbit(eventmask, BRCMF_E_SCAN_COMPLETE); | ||
3706 | |||
3707 | brcmu_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, iovbuf, | ||
3708 | sizeof(iovbuf)); | ||
3709 | err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf)); | ||
3710 | if (unlikely(err)) { | ||
3711 | WL_ERR("Set event_msgs error (%d)\n", err); | ||
3712 | goto dongle_eventmsg_out; | ||
3713 | } | ||
3714 | |||
3715 | dongle_eventmsg_out: | ||
3716 | WL_TRACE("Exit\n"); | ||
3717 | return err; | ||
3718 | } | ||
3719 | |||
3720 | static s32 | ||
3721 | brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) | ||
3722 | { | ||
3723 | s8 iovbuf[32]; | ||
3724 | s32 roamtrigger[2]; | ||
3725 | s32 roam_delta[2]; | ||
3726 | s32 err = 0; | ||
3727 | |||
3728 | /* | ||
3729 | * Setup timeout if Beacons are lost and roam is | ||
3730 | * off to report link down | ||
3731 | */ | ||
3732 | if (roamvar) { | ||
3733 | brcmu_mkiovar("bcn_timeout", (char *)&bcn_timeout, | ||
3734 | sizeof(bcn_timeout), iovbuf, sizeof(iovbuf)); | ||
3735 | err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_VAR, | ||
3736 | iovbuf, sizeof(iovbuf)); | ||
3737 | if (unlikely(err)) { | ||
3738 | WL_ERR("bcn_timeout error (%d)\n", err); | ||
3739 | goto dongle_rom_out; | ||
3740 | } | ||
3741 | } | ||
3742 | |||
3743 | /* | ||
3744 | * Enable/Disable built-in roaming to allow supplicant | ||
3745 | * to take care of roaming | ||
3746 | */ | ||
3747 | WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On"); | ||
3748 | brcmu_mkiovar("roam_off", (char *)&roamvar, | ||
3749 | sizeof(roamvar), iovbuf, sizeof(iovbuf)); | ||
3750 | err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf)); | ||
3751 | if (unlikely(err)) { | ||
3752 | WL_ERR("roam_off error (%d)\n", err); | ||
3753 | goto dongle_rom_out; | ||
3754 | } | ||
3755 | |||
3756 | roamtrigger[0] = WL_ROAM_TRIGGER_LEVEL; | ||
3757 | roamtrigger[1] = BRCM_BAND_ALL; | ||
3758 | err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_ROAM_TRIGGER, | ||
3759 | (void *)roamtrigger, sizeof(roamtrigger)); | ||
3760 | if (unlikely(err)) { | ||
3761 | WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err); | ||
3762 | goto dongle_rom_out; | ||
3763 | } | ||
3764 | |||
3765 | roam_delta[0] = WL_ROAM_DELTA; | ||
3766 | roam_delta[1] = BRCM_BAND_ALL; | ||
3767 | err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_ROAM_DELTA, | ||
3768 | (void *)roam_delta, sizeof(roam_delta)); | ||
3769 | if (unlikely(err)) { | ||
3770 | WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err); | ||
3771 | goto dongle_rom_out; | ||
3772 | } | ||
3773 | |||
3774 | dongle_rom_out: | ||
3775 | return err; | ||
3776 | } | ||
3777 | |||
3778 | static s32 | ||
3779 | brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, | ||
3780 | s32 scan_unassoc_time, s32 scan_passive_time) | ||
3781 | { | ||
3782 | s32 err = 0; | ||
3783 | |||
3784 | err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_SCAN_CHANNEL_TIME, | ||
3785 | &scan_assoc_time, sizeof(scan_assoc_time)); | ||
3786 | if (err) { | ||
3787 | if (err == -EOPNOTSUPP) | ||
3788 | WL_INFO("Scan assoc time is not supported\n"); | ||
3789 | else | ||
3790 | WL_ERR("Scan assoc time error (%d)\n", err); | ||
3791 | goto dongle_scantime_out; | ||
3792 | } | ||
3793 | err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_SCAN_UNASSOC_TIME, | ||
3794 | &scan_unassoc_time, sizeof(scan_unassoc_time)); | ||
3795 | if (err) { | ||
3796 | if (err == -EOPNOTSUPP) | ||
3797 | WL_INFO("Scan unassoc time is not supported\n"); | ||
3798 | else | ||
3799 | WL_ERR("Scan unassoc time error (%d)\n", err); | ||
3800 | goto dongle_scantime_out; | ||
3801 | } | ||
3802 | |||
3803 | err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_SCAN_PASSIVE_TIME, | ||
3804 | &scan_passive_time, sizeof(scan_passive_time)); | ||
3805 | if (err) { | ||
3806 | if (err == -EOPNOTSUPP) | ||
3807 | WL_INFO("Scan passive time is not supported\n"); | ||
3808 | else | ||
3809 | WL_ERR("Scan passive time error (%d)\n", err); | ||
3810 | goto dongle_scantime_out; | ||
3811 | } | ||
3812 | |||
3813 | dongle_scantime_out: | ||
3814 | return err; | ||
3815 | } | ||
3816 | |||
3817 | s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv, bool need_lock) | ||
3818 | { | ||
3819 | struct net_device *ndev; | ||
3820 | struct wireless_dev *wdev; | ||
3821 | s32 err = 0; | ||
3822 | |||
3823 | if (cfg_priv->dongle_up) | ||
3824 | return err; | ||
3825 | |||
3826 | ndev = cfg_to_ndev(cfg_priv); | ||
3827 | wdev = ndev->ieee80211_ptr; | ||
3828 | if (need_lock) | ||
3829 | rtnl_lock(); | ||
3830 | |||
3831 | brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME, | ||
3832 | WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME); | ||
3833 | |||
3834 | err = brcmf_dongle_eventmsg(ndev); | ||
3835 | if (unlikely(err)) | ||
3836 | goto default_conf_out; | ||
3837 | err = brcmf_dongle_roam(ndev, (cfg_priv->roam_on ? 0 : 1), | ||
3838 | WL_BEACON_TIMEOUT); | ||
3839 | if (unlikely(err)) | ||
3840 | goto default_conf_out; | ||
3841 | err = brcmf_dongle_mode(ndev, wdev->iftype); | ||
3842 | if (unlikely(err && err != -EINPROGRESS)) | ||
3843 | goto default_conf_out; | ||
3844 | err = brcmf_dongle_probecap(cfg_priv); | ||
3845 | if (unlikely(err)) | ||
3846 | goto default_conf_out; | ||
3847 | |||
3848 | /* -EINPROGRESS: Call commit handler */ | ||
3849 | |||
3850 | default_conf_out: | ||
3851 | if (need_lock) | ||
3852 | rtnl_unlock(); | ||
3853 | |||
3854 | cfg_priv->dongle_up = true; | ||
3855 | |||
3856 | return err; | ||
3857 | |||
3858 | } | ||
3859 | |||
3860 | static s32 wl_update_wiphybands(struct brcmf_cfg80211_priv *cfg_priv) | ||
3861 | { | ||
3862 | struct wiphy *wiphy; | ||
3863 | s32 phy_list; | ||
3864 | s8 phy; | ||
3865 | s32 err = 0; | ||
3866 | |||
3867 | err = brcmf_dev_ioctl(cfg_to_ndev(cfg_priv), BRCM_GET_PHYLIST, | ||
3868 | &phy_list, sizeof(phy_list)); | ||
3869 | if (unlikely(err)) { | ||
3870 | WL_ERR("error (%d)\n", err); | ||
3871 | return err; | ||
3872 | } | ||
3873 | |||
3874 | phy = ((char *)&phy_list)[1]; | ||
3875 | WL_INFO("%c phy\n", phy); | ||
3876 | if (phy == 'n' || phy == 'a') { | ||
3877 | wiphy = cfg_to_wiphy(cfg_priv); | ||
3878 | wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n; | ||
3879 | } | ||
3880 | |||
3881 | return err; | ||
3882 | } | ||
3883 | |||
3884 | static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_priv *cfg_priv) | ||
3885 | { | ||
3886 | s32 err = 0; | ||
3887 | |||
3888 | set_bit(WL_STATUS_READY, &cfg_priv->status); | ||
3889 | |||
3890 | brcmf_debugfs_add_netdev_params(cfg_priv); | ||
3891 | |||
3892 | err = brcmf_config_dongle(cfg_priv, false); | ||
3893 | if (unlikely(err)) | ||
3894 | return err; | ||
3895 | |||
3896 | brcmf_invoke_iscan(cfg_priv); | ||
3897 | |||
3898 | return err; | ||
3899 | } | ||
3900 | |||
3901 | static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_priv *cfg_priv) | ||
3902 | { | ||
3903 | /* | ||
3904 | * While going down, if associated with AP disassociate | ||
3905 | * from AP to save power | ||
3906 | */ | ||
3907 | if ((test_bit(WL_STATUS_CONNECTED, &cfg_priv->status) || | ||
3908 | test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) && | ||
3909 | test_bit(WL_STATUS_READY, &cfg_priv->status)) { | ||
3910 | WL_INFO("Disassociating from AP"); | ||
3911 | brcmf_link_down(cfg_priv); | ||
3912 | |||
3913 | /* Make sure WPA_Supplicant receives all the event | ||
3914 | generated due to DISASSOC call to the fw to keep | ||
3915 | the state fw and WPA_Supplicant state consistent | ||
3916 | */ | ||
3917 | rtnl_unlock(); | ||
3918 | brcmf_delay(500); | ||
3919 | rtnl_lock(); | ||
3920 | } | ||
3921 | |||
3922 | set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); | ||
3923 | brcmf_term_iscan(cfg_priv); | ||
3924 | if (cfg_priv->scan_request) { | ||
3925 | cfg80211_scan_done(cfg_priv->scan_request, true); | ||
3926 | /* May need to perform this to cover rmmod */ | ||
3927 | /* wl_set_mpc(cfg_to_ndev(wl), 1); */ | ||
3928 | cfg_priv->scan_request = NULL; | ||
3929 | } | ||
3930 | clear_bit(WL_STATUS_READY, &cfg_priv->status); | ||
3931 | clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); | ||
3932 | clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); | ||
3933 | |||
3934 | brcmf_debugfs_remove_netdev(cfg_priv); | ||
3935 | |||
3936 | return 0; | ||
3937 | } | ||
3938 | |||
3939 | s32 brcmf_cfg80211_up(void) | ||
3940 | { | ||
3941 | struct brcmf_cfg80211_priv *cfg_priv; | ||
3942 | s32 err = 0; | ||
3943 | |||
3944 | cfg_priv = WL_PRIV_GET(); | ||
3945 | mutex_lock(&cfg_priv->usr_sync); | ||
3946 | err = __brcmf_cfg80211_up(cfg_priv); | ||
3947 | mutex_unlock(&cfg_priv->usr_sync); | ||
3948 | |||
3949 | return err; | ||
3950 | } | ||
3951 | |||
3952 | s32 brcmf_cfg80211_down(void) | ||
3953 | { | ||
3954 | struct brcmf_cfg80211_priv *cfg_priv; | ||
3955 | s32 err = 0; | ||
3956 | |||
3957 | cfg_priv = WL_PRIV_GET(); | ||
3958 | mutex_lock(&cfg_priv->usr_sync); | ||
3959 | err = __brcmf_cfg80211_down(cfg_priv); | ||
3960 | mutex_unlock(&cfg_priv->usr_sync); | ||
3961 | |||
3962 | return err; | ||
3963 | } | ||
3964 | |||
3965 | static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_priv *cfg_priv) | ||
3966 | { | ||
3967 | return wl_update_wiphybands(cfg_priv); | ||
3968 | } | ||
3969 | |||
3970 | static void *brcmf_read_prof(struct brcmf_cfg80211_priv *cfg_priv, s32 item) | ||
3971 | { | ||
3972 | switch (item) { | ||
3973 | case WL_PROF_SEC: | ||
3974 | return &cfg_priv->profile->sec; | ||
3975 | case WL_PROF_BSSID: | ||
3976 | return &cfg_priv->profile->bssid; | ||
3977 | case WL_PROF_SSID: | ||
3978 | return &cfg_priv->profile->ssid; | ||
3979 | } | ||
3980 | WL_ERR("invalid item (%d)\n", item); | ||
3981 | return NULL; | ||
3982 | } | ||
3983 | |||
3984 | static s32 | ||
3985 | brcmf_update_prof(struct brcmf_cfg80211_priv *cfg_priv, | ||
3986 | const struct brcmf_event_msg *e, void *data, s32 item) | ||
3987 | { | ||
3988 | s32 err = 0; | ||
3989 | struct brcmf_ssid *ssid; | ||
3990 | |||
3991 | switch (item) { | ||
3992 | case WL_PROF_SSID: | ||
3993 | ssid = (struct brcmf_ssid *) data; | ||
3994 | memset(cfg_priv->profile->ssid.SSID, 0, | ||
3995 | sizeof(cfg_priv->profile->ssid.SSID)); | ||
3996 | memcpy(cfg_priv->profile->ssid.SSID, | ||
3997 | ssid->SSID, ssid->SSID_len); | ||
3998 | cfg_priv->profile->ssid.SSID_len = ssid->SSID_len; | ||
3999 | break; | ||
4000 | case WL_PROF_BSSID: | ||
4001 | if (data) | ||
4002 | memcpy(cfg_priv->profile->bssid, data, ETH_ALEN); | ||
4003 | else | ||
4004 | memset(cfg_priv->profile->bssid, 0, ETH_ALEN); | ||
4005 | break; | ||
4006 | case WL_PROF_SEC: | ||
4007 | memcpy(&cfg_priv->profile->sec, data, | ||
4008 | sizeof(cfg_priv->profile->sec)); | ||
4009 | break; | ||
4010 | case WL_PROF_BEACONINT: | ||
4011 | cfg_priv->profile->beacon_interval = *(u16 *)data; | ||
4012 | break; | ||
4013 | case WL_PROF_DTIMPERIOD: | ||
4014 | cfg_priv->profile->dtim_period = *(u8 *)data; | ||
4015 | break; | ||
4016 | default: | ||
4017 | WL_ERR("unsupported item (%d)\n", item); | ||
4018 | err = -EOPNOTSUPP; | ||
4019 | break; | ||
4020 | } | ||
4021 | |||
4022 | return err; | ||
4023 | } | ||
4024 | |||
4025 | static bool brcmf_is_ibssmode(struct brcmf_cfg80211_priv *cfg_priv) | ||
4026 | { | ||
4027 | return cfg_priv->conf->mode == WL_MODE_IBSS; | ||
4028 | } | ||
4029 | |||
4030 | static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv, | ||
4031 | u8 t, u8 l, u8 *v) | ||
4032 | { | ||
4033 | struct brcmf_cfg80211_ie *ie = &cfg_priv->ie; | ||
4034 | s32 err = 0; | ||
4035 | |||
4036 | if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) { | ||
4037 | WL_ERR("ei crosses buffer boundary\n"); | ||
4038 | return -ENOSPC; | ||
4039 | } | ||
4040 | ie->buf[ie->offset] = t; | ||
4041 | ie->buf[ie->offset + 1] = l; | ||
4042 | memcpy(&ie->buf[ie->offset + 2], v, l); | ||
4043 | ie->offset += l + 2; | ||
4044 | |||
4045 | return err; | ||
4046 | } | ||
4047 | |||
4048 | static void brcmf_link_down(struct brcmf_cfg80211_priv *cfg_priv) | ||
4049 | { | ||
4050 | struct net_device *dev = NULL; | ||
4051 | s32 err = 0; | ||
4052 | |||
4053 | WL_TRACE("Enter\n"); | ||
4054 | |||
4055 | if (cfg_priv->link_up) { | ||
4056 | dev = cfg_to_ndev(cfg_priv); | ||
4057 | WL_INFO("Call WLC_DISASSOC to stop excess roaming\n "); | ||
4058 | err = brcmf_dev_ioctl(dev, BRCMF_C_DISASSOC, NULL, 0); | ||
4059 | if (unlikely(err)) | ||
4060 | WL_ERR("WLC_DISASSOC failed (%d)\n", err); | ||
4061 | cfg_priv->link_up = false; | ||
4062 | } | ||
4063 | WL_TRACE("Exit\n"); | ||
4064 | } | ||
4065 | |||
4066 | static void brcmf_lock_eq(struct brcmf_cfg80211_priv *cfg_priv) | ||
4067 | { | ||
4068 | spin_lock_irq(&cfg_priv->eq_lock); | ||
4069 | } | ||
4070 | |||
4071 | static void brcmf_unlock_eq(struct brcmf_cfg80211_priv *cfg_priv) | ||
4072 | { | ||
4073 | spin_unlock_irq(&cfg_priv->eq_lock); | ||
4074 | } | ||
4075 | |||
4076 | static void brcmf_init_eq_lock(struct brcmf_cfg80211_priv *cfg_priv) | ||
4077 | { | ||
4078 | spin_lock_init(&cfg_priv->eq_lock); | ||
4079 | } | ||
4080 | |||
4081 | static void brcmf_delay(u32 ms) | ||
4082 | { | ||
4083 | if (ms < 1000 / HZ) { | ||
4084 | cond_resched(); | ||
4085 | mdelay(ms); | ||
4086 | } else { | ||
4087 | msleep(ms); | ||
4088 | } | ||
4089 | } | ||
4090 | |||
4091 | static void brcmf_set_drvdata(struct brcmf_cfg80211_dev *dev, void *data) | ||
4092 | { | ||
4093 | dev->driver_data = data; | ||
4094 | } | ||
4095 | |||
4096 | static void *brcmf_get_drvdata(struct brcmf_cfg80211_dev *dev) | ||
4097 | { | ||
4098 | void *data = NULL; | ||
4099 | |||
4100 | if (dev) | ||
4101 | data = dev->driver_data; | ||
4102 | return data; | ||
4103 | } | ||
4104 | |||
4105 | static void brcmf_set_mpc(struct net_device *ndev, int mpc) | ||
4106 | { | ||
4107 | s32 err = 0; | ||
4108 | struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); | ||
4109 | |||
4110 | if (test_bit(WL_STATUS_READY, &cfg_priv->status)) { | ||
4111 | err = brcmf_dev_intvar_set(ndev, "mpc", mpc); | ||
4112 | if (unlikely(err)) { | ||
4113 | WL_ERR("fail to set mpc\n"); | ||
4114 | return; | ||
4115 | } | ||
4116 | WL_INFO("MPC : %d\n", mpc); | ||
4117 | } | ||
4118 | } | ||
4119 | |||
4120 | static int brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_priv *cfg_priv) | ||
4121 | { | ||
4122 | char buf[10+IFNAMSIZ]; | ||
4123 | struct dentry *fd; | ||
4124 | s32 err = 0; | ||
4125 | |||
4126 | sprintf(buf, "netdev:%s", cfg_to_ndev(cfg_priv)->name); | ||
4127 | cfg_priv->debugfsdir = debugfs_create_dir(buf, | ||
4128 | cfg_to_wiphy(cfg_priv)->debugfsdir); | ||
4129 | |||
4130 | fd = debugfs_create_u16("beacon_int", S_IRUGO, cfg_priv->debugfsdir, | ||
4131 | (u16 *)&cfg_priv->profile->beacon_interval); | ||
4132 | if (!fd) { | ||
4133 | err = -ENOMEM; | ||
4134 | goto err_out; | ||
4135 | } | ||
4136 | |||
4137 | fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg_priv->debugfsdir, | ||
4138 | (u8 *)&cfg_priv->profile->dtim_period); | ||
4139 | if (!fd) { | ||
4140 | err = -ENOMEM; | ||
4141 | goto err_out; | ||
4142 | } | ||
4143 | |||
4144 | err_out: | ||
4145 | return err; | ||
4146 | } | ||
4147 | |||
4148 | static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_priv *cfg_priv) | ||
4149 | { | ||
4150 | debugfs_remove_recursive(cfg_priv->debugfsdir); | ||
4151 | cfg_priv->debugfsdir = NULL; | ||
4152 | } | ||
diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h new file mode 100644 index 00000000000..f26d08793ca --- /dev/null +++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h | |||
@@ -0,0 +1,356 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #ifndef _wl_cfg80211_h_ | ||
18 | #define _wl_cfg80211_h_ | ||
19 | |||
20 | struct brcmf_cfg80211_conf; | ||
21 | struct brcmf_cfg80211_iface; | ||
22 | struct brcmf_cfg80211_priv; | ||
23 | struct brcmf_cfg80211_security; | ||
24 | struct brcmf_cfg80211_ibss; | ||
25 | |||
26 | #define WL_DBG_NONE 0 | ||
27 | #define WL_DBG_CONN (1 << 5) | ||
28 | #define WL_DBG_SCAN (1 << 4) | ||
29 | #define WL_DBG_TRACE (1 << 3) | ||
30 | #define WL_DBG_INFO (1 << 1) | ||
31 | #define WL_DBG_ERR (1 << 0) | ||
32 | #define WL_DBG_MASK ((WL_DBG_INFO | WL_DBG_ERR | WL_DBG_TRACE) | \ | ||
33 | (WL_DBG_SCAN) | (WL_DBG_CONN)) | ||
34 | |||
35 | #define WL_ERR(fmt, args...) \ | ||
36 | do { \ | ||
37 | if (brcmf_dbg_level & WL_DBG_ERR) { \ | ||
38 | if (net_ratelimit()) { \ | ||
39 | printk(KERN_ERR "ERROR @%s : " fmt, \ | ||
40 | __func__, ##args); \ | ||
41 | } \ | ||
42 | } \ | ||
43 | } while (0) | ||
44 | |||
45 | #if (defined BCMDBG) | ||
46 | #define WL_INFO(fmt, args...) \ | ||
47 | do { \ | ||
48 | if (brcmf_dbg_level & WL_DBG_INFO) { \ | ||
49 | if (net_ratelimit()) { \ | ||
50 | printk(KERN_ERR "INFO @%s : " fmt, \ | ||
51 | __func__, ##args); \ | ||
52 | } \ | ||
53 | } \ | ||
54 | } while (0) | ||
55 | |||
56 | #define WL_TRACE(fmt, args...) \ | ||
57 | do { \ | ||
58 | if (brcmf_dbg_level & WL_DBG_TRACE) { \ | ||
59 | if (net_ratelimit()) { \ | ||
60 | printk(KERN_ERR "TRACE @%s : " fmt, \ | ||
61 | __func__, ##args); \ | ||
62 | } \ | ||
63 | } \ | ||
64 | } while (0) | ||
65 | |||
66 | #define WL_SCAN(fmt, args...) \ | ||
67 | do { \ | ||
68 | if (brcmf_dbg_level & WL_DBG_SCAN) { \ | ||
69 | if (net_ratelimit()) { \ | ||
70 | printk(KERN_ERR "SCAN @%s : " fmt, \ | ||
71 | __func__, ##args); \ | ||
72 | } \ | ||
73 | } \ | ||
74 | } while (0) | ||
75 | |||
76 | #define WL_CONN(fmt, args...) \ | ||
77 | do { \ | ||
78 | if (brcmf_dbg_level & WL_DBG_CONN) { \ | ||
79 | if (net_ratelimit()) { \ | ||
80 | printk(KERN_ERR "CONN @%s : " fmt, \ | ||
81 | __func__, ##args); \ | ||
82 | } \ | ||
83 | } \ | ||
84 | } while (0) | ||
85 | |||
86 | #else /* (defined BCMDBG) */ | ||
87 | #define WL_INFO(fmt, args...) | ||
88 | #define WL_TRACE(fmt, args...) | ||
89 | #define WL_SCAN(fmt, args...) | ||
90 | #define WL_CONN(fmt, args...) | ||
91 | #endif /* (defined BCMDBG) */ | ||
92 | |||
93 | #define WL_NUM_SCAN_MAX 1 | ||
94 | #define WL_NUM_PMKIDS_MAX MAXPMKID /* will be used | ||
95 | * for 2.6.33 kernel | ||
96 | * or later | ||
97 | */ | ||
98 | #define WL_SCAN_BUF_MAX (1024 * 8) | ||
99 | #define WL_TLV_INFO_MAX 1024 | ||
100 | #define WL_BSS_INFO_MAX 2048 | ||
101 | #define WL_ASSOC_INFO_MAX 512 /* | ||
102 | * needs to grab assoc info from dongle to | ||
103 | * report it to cfg80211 through "connect" | ||
104 | * event | ||
105 | */ | ||
106 | #define WL_IOCTL_LEN_MAX 1024 | ||
107 | #define WL_EXTRA_BUF_MAX 2048 | ||
108 | #define WL_ISCAN_BUF_MAX 2048 /* | ||
109 | * the buf length can be BRCMF_C_IOCTL_MAXLEN | ||
110 | * to reduce iteration | ||
111 | */ | ||
112 | #define WL_ISCAN_TIMER_INTERVAL_MS 3000 | ||
113 | #define WL_SCAN_ERSULTS_LAST (BRCMF_SCAN_RESULTS_NO_MEM+1) | ||
114 | #define WL_AP_MAX 256 /* virtually unlimitted as long | ||
115 | * as kernel memory allows | ||
116 | */ | ||
117 | |||
118 | #define WL_ROAM_TRIGGER_LEVEL -75 | ||
119 | #define WL_ROAM_DELTA 20 | ||
120 | #define WL_BEACON_TIMEOUT 3 | ||
121 | |||
122 | #define WL_SCAN_CHANNEL_TIME 40 | ||
123 | #define WL_SCAN_UNASSOC_TIME 40 | ||
124 | #define WL_SCAN_PASSIVE_TIME 120 | ||
125 | |||
126 | /* dongle status */ | ||
127 | enum wl_status { | ||
128 | WL_STATUS_READY, | ||
129 | WL_STATUS_SCANNING, | ||
130 | WL_STATUS_SCAN_ABORTING, | ||
131 | WL_STATUS_CONNECTING, | ||
132 | WL_STATUS_CONNECTED | ||
133 | }; | ||
134 | |||
135 | /* wi-fi mode */ | ||
136 | enum wl_mode { | ||
137 | WL_MODE_BSS, | ||
138 | WL_MODE_IBSS, | ||
139 | WL_MODE_AP | ||
140 | }; | ||
141 | |||
142 | /* dongle profile list */ | ||
143 | enum wl_prof_list { | ||
144 | WL_PROF_MODE, | ||
145 | WL_PROF_SSID, | ||
146 | WL_PROF_SEC, | ||
147 | WL_PROF_IBSS, | ||
148 | WL_PROF_BAND, | ||
149 | WL_PROF_BSSID, | ||
150 | WL_PROF_ACT, | ||
151 | WL_PROF_BEACONINT, | ||
152 | WL_PROF_DTIMPERIOD | ||
153 | }; | ||
154 | |||
155 | /* dongle iscan state */ | ||
156 | enum wl_iscan_state { | ||
157 | WL_ISCAN_STATE_IDLE, | ||
158 | WL_ISCAN_STATE_SCANING | ||
159 | }; | ||
160 | |||
161 | /* dongle configuration */ | ||
162 | struct brcmf_cfg80211_conf { | ||
163 | u32 mode; /* adhoc , infrastructure or ap */ | ||
164 | u32 frag_threshold; | ||
165 | u32 rts_threshold; | ||
166 | u32 retry_short; | ||
167 | u32 retry_long; | ||
168 | s32 tx_power; | ||
169 | struct ieee80211_channel channel; | ||
170 | }; | ||
171 | |||
172 | /* cfg80211 main event loop */ | ||
173 | struct brcmf_cfg80211_event_loop { | ||
174 | s32(*handler[BRCMF_E_LAST]) (struct brcmf_cfg80211_priv *cfg_priv, | ||
175 | struct net_device *ndev, | ||
176 | const struct brcmf_event_msg *e, | ||
177 | void *data); | ||
178 | }; | ||
179 | |||
180 | /* representing interface of cfg80211 plane */ | ||
181 | struct brcmf_cfg80211_iface { | ||
182 | struct brcmf_cfg80211_priv *cfg_priv; | ||
183 | }; | ||
184 | |||
185 | struct brcmf_cfg80211_dev { | ||
186 | void *driver_data; /* to store cfg80211 object information */ | ||
187 | }; | ||
188 | |||
189 | /* basic structure of scan request */ | ||
190 | struct brcmf_cfg80211_scan_req { | ||
191 | struct brcmf_ssid ssid; | ||
192 | }; | ||
193 | |||
194 | /* basic structure of information element */ | ||
195 | struct brcmf_cfg80211_ie { | ||
196 | u16 offset; | ||
197 | u8 buf[WL_TLV_INFO_MAX]; | ||
198 | }; | ||
199 | |||
200 | /* event queue for cfg80211 main event */ | ||
201 | struct brcmf_cfg80211_event_q { | ||
202 | struct list_head eq_list; | ||
203 | u32 etype; | ||
204 | struct brcmf_event_msg emsg; | ||
205 | s8 edata[1]; | ||
206 | }; | ||
207 | |||
208 | /* security information with currently associated ap */ | ||
209 | struct brcmf_cfg80211_security { | ||
210 | u32 wpa_versions; | ||
211 | u32 auth_type; | ||
212 | u32 cipher_pairwise; | ||
213 | u32 cipher_group; | ||
214 | u32 wpa_auth; | ||
215 | }; | ||
216 | |||
217 | /* ibss information for currently joined ibss network */ | ||
218 | struct brcmf_cfg80211_ibss { | ||
219 | u8 beacon_interval; /* in millisecond */ | ||
220 | u8 atim; /* in millisecond */ | ||
221 | s8 join_only; | ||
222 | u8 band; | ||
223 | u8 channel; | ||
224 | }; | ||
225 | |||
226 | /* dongle profile */ | ||
227 | struct brcmf_cfg80211_profile { | ||
228 | u32 mode; | ||
229 | struct brcmf_ssid ssid; | ||
230 | u8 bssid[ETH_ALEN]; | ||
231 | u16 beacon_interval; | ||
232 | u8 dtim_period; | ||
233 | struct brcmf_cfg80211_security sec; | ||
234 | struct brcmf_cfg80211_ibss ibss; | ||
235 | s32 band; | ||
236 | }; | ||
237 | |||
238 | /* dongle iscan event loop */ | ||
239 | struct brcmf_cfg80211_iscan_eloop { | ||
240 | s32 (*handler[WL_SCAN_ERSULTS_LAST]) | ||
241 | (struct brcmf_cfg80211_priv *cfg_priv); | ||
242 | }; | ||
243 | |||
244 | /* dongle iscan controller */ | ||
245 | struct brcmf_cfg80211_iscan_ctrl { | ||
246 | struct net_device *dev; | ||
247 | struct timer_list timer; | ||
248 | u32 timer_ms; | ||
249 | u32 timer_on; | ||
250 | s32 state; | ||
251 | struct task_struct *tsk; | ||
252 | struct semaphore sync; | ||
253 | struct brcmf_cfg80211_iscan_eloop el; | ||
254 | void *data; | ||
255 | s8 ioctl_buf[BRCMF_C_IOCTL_SMLEN]; | ||
256 | s8 scan_buf[WL_ISCAN_BUF_MAX]; | ||
257 | }; | ||
258 | |||
259 | /* association inform */ | ||
260 | struct brcmf_cfg80211_connect_info { | ||
261 | u8 *req_ie; | ||
262 | s32 req_ie_len; | ||
263 | u8 *resp_ie; | ||
264 | s32 resp_ie_len; | ||
265 | }; | ||
266 | |||
267 | /* assoc ie length */ | ||
268 | struct brcmf_cfg80211_assoc_ielen { | ||
269 | u32 req_len; | ||
270 | u32 resp_len; | ||
271 | }; | ||
272 | |||
273 | /* wpa2 pmk list */ | ||
274 | struct brcmf_cfg80211_pmk_list { | ||
275 | pmkid_list_t pmkids; | ||
276 | pmkid_t foo[MAXPMKID - 1]; | ||
277 | }; | ||
278 | |||
279 | /* dongle private data of cfg80211 interface */ | ||
280 | struct brcmf_cfg80211_priv { | ||
281 | struct wireless_dev *wdev; /* representing wl cfg80211 device */ | ||
282 | struct brcmf_cfg80211_conf *conf; /* dongle configuration */ | ||
283 | struct cfg80211_scan_request *scan_request; /* scan request | ||
284 | object */ | ||
285 | struct brcmf_cfg80211_event_loop el; /* main event loop */ | ||
286 | struct list_head eq_list; /* used for event queue */ | ||
287 | spinlock_t eq_lock; /* for event queue synchronization */ | ||
288 | struct mutex usr_sync; /* maily for dongle up/down synchronization */ | ||
289 | struct brcmf_scan_results *bss_list; /* bss_list holding scanned | ||
290 | ap information */ | ||
291 | struct brcmf_scan_results *scan_results; | ||
292 | struct brcmf_cfg80211_scan_req *scan_req_int; /* scan request object | ||
293 | for internal purpose */ | ||
294 | struct wl_cfg80211_bss_info *bss_info; /* bss information for | ||
295 | cfg80211 layer */ | ||
296 | struct brcmf_cfg80211_ie ie; /* information element object for | ||
297 | internal purpose */ | ||
298 | struct semaphore event_sync; /* for synchronization of main event | ||
299 | thread */ | ||
300 | struct brcmf_cfg80211_profile *profile; /* holding dongle profile */ | ||
301 | struct brcmf_cfg80211_iscan_ctrl *iscan; /* iscan controller */ | ||
302 | struct brcmf_cfg80211_connect_info conn_info; /* association info */ | ||
303 | struct brcmf_cfg80211_pmk_list *pmk_list; /* wpa2 pmk list */ | ||
304 | struct task_struct *event_tsk; /* task of main event handler thread */ | ||
305 | unsigned long status; /* current dongle status */ | ||
306 | void *pub; | ||
307 | u32 channel; /* current channel */ | ||
308 | bool iscan_on; /* iscan on/off switch */ | ||
309 | bool iscan_kickstart; /* indicate iscan already started */ | ||
310 | bool active_scan; /* current scan mode */ | ||
311 | bool ibss_starter; /* indicates this sta is ibss starter */ | ||
312 | bool link_up; /* link/connection up flag */ | ||
313 | bool pwr_save; /* indicate whether dongle to support | ||
314 | power save mode */ | ||
315 | bool dongle_up; /* indicate whether dongle up or not */ | ||
316 | bool roam_on; /* on/off switch for dongle self-roaming */ | ||
317 | bool scan_tried; /* indicates if first scan attempted */ | ||
318 | u8 *ioctl_buf; /* ioctl buffer */ | ||
319 | u8 *extra_buf; /* maily to grab assoc information */ | ||
320 | struct dentry *debugfsdir; | ||
321 | u8 ci[0] __attribute__ ((__aligned__(NETDEV_ALIGN))); | ||
322 | }; | ||
323 | |||
324 | #define cfg_to_wiphy(w) (w->wdev->wiphy) | ||
325 | #define wiphy_to_cfg(w) ((struct brcmf_cfg80211_priv *)(wiphy_priv(w))) | ||
326 | #define cfg_to_wdev(w) (w->wdev) | ||
327 | #define wdev_to_cfg(w) ((struct brcmf_cfg80211_priv *)(wdev_priv(w))) | ||
328 | #define cfg_to_ndev(w) (w->wdev->netdev) | ||
329 | #define ndev_to_cfg(n) (wdev_to_cfg(n->ieee80211_ptr)) | ||
330 | #define iscan_to_cfg(i) ((struct brcmf_cfg80211_priv *)(i->data)) | ||
331 | #define cfg_to_iscan(w) (w->iscan) | ||
332 | #define cfg_to_conn(w) (&w->conn_info) | ||
333 | |||
334 | static inline struct brcmf_bss_info *next_bss(struct brcmf_scan_results *list, | ||
335 | struct brcmf_bss_info *bss) | ||
336 | { | ||
337 | return bss = bss ? | ||
338 | (struct brcmf_bss_info *)((unsigned long)bss + | ||
339 | le32_to_cpu(bss->length)) : | ||
340 | list->bss_info; | ||
341 | } | ||
342 | |||
343 | #define for_each_bss(list, bss, __i) \ | ||
344 | for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss)) | ||
345 | |||
346 | extern s32 brcmf_cfg80211_attach(struct net_device *ndev, void *data); | ||
347 | extern void brcmf_cfg80211_detach(void); | ||
348 | /* event handler from dongle */ | ||
349 | extern void brcmf_cfg80211_event(struct net_device *ndev, | ||
350 | const struct brcmf_event_msg *e, void *data); | ||
351 | extern void brcmf_cfg80211_sdio_func(void *func); /* set sdio function info */ | ||
352 | extern struct sdio_func *brcmf_cfg80211_get_sdio_func(void); | ||
353 | extern s32 brcmf_cfg80211_up(void); /* dongle up */ | ||
354 | extern s32 brcmf_cfg80211_down(void); /* dongle down */ | ||
355 | |||
356 | #endif /* _wl_cfg80211_h_ */ | ||