1 /* $NetBSD: if_bwfm_sdio.c,v 1.30 2022/12/03 16:06:20 mlelstv Exp $ */
2 /* $OpenBSD: if_bwfm_sdio.c,v 1.1 2017/10/11 17:19:50 patrick Exp $ */
3 /*
4 * Copyright (c) 2010-2016 Broadcom Corporation
5 * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #ifdef _KERNEL_OPT
21 #include "opt_fdt.h"
22 #endif
23
24 #include <sys/param.h>
25 #include <sys/types.h>
26
27 #include <sys/buf.h>
28 #include <sys/device.h>
29 #include <sys/endian.h>
30 #include <sys/kernel.h>
31 #include <sys/kmem.h>
32 #include <sys/malloc.h>
33 #include <sys/mutex.h>
34 #include <sys/queue.h>
35 #include <sys/socket.h>
36 #include <sys/systm.h>
37
38 #include <net/bpf.h>
39 #include <net/if.h>
40 #include <net/if_dl.h>
41 #include <net/if_ether.h>
42 #include <net/if_media.h>
43
44 #include <netinet/in.h>
45
46 #include <net80211/ieee80211_var.h>
47
48 #ifdef FDT
49 #include <dev/fdt/fdtvar.h>
50 #endif
51 #include <dev/ic/bwfmreg.h>
52 #include <dev/ic/bwfmvar.h>
53 #include <dev/ofw/openfirm.h>
54 #include <dev/sdmmc/if_bwfm_sdio.h>
55 #include <dev/sdmmc/sdmmcdevs.h>
56 #include <dev/sdmmc/sdmmcvar.h>
57
58 #ifdef BWFM_DEBUG
59 #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0)
60 #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0)
61 static int bwfm_debug = 2;
62 #else
63 #define DPRINTF(x) do { ; } while (0)
64 #define DPRINTFN(n, x) do { ; } while (0)
65 #endif
66
67 #define DEVNAME(sc) device_xname((sc)->sc_sc.sc_dev)
68
69 enum bwfm_sdio_clkstate {
70 CLK_NONE,
71 CLK_SDONLY,
72 CLK_PENDING,
73 CLK_AVAIL
74 };
75
76 struct bwfm_sdio_softc {
77 struct bwfm_softc sc_sc;
78 kmutex_t sc_lock;
79
80 bool sc_bwfm_attached;
81
82 struct sdmmc_function **sc_sf;
83 size_t sc_sf_size;
84
85 uint32_t sc_bar0;
86 enum bwfm_sdio_clkstate sc_clkstate;
87 bool sc_sr_enabled;
88 bool sc_alp_only;
89 bool sc_sleeping;
90 bool sc_rxskip;
91
92 struct sdmmc_task sc_task;
93 bool sc_task_queued;
94
95 uint8_t sc_tx_seq;
96 uint8_t sc_tx_max_seq;
97 int sc_tx_count;
98 MBUFQ_HEAD() sc_tx_queue;
99
100 struct mbuf *sc_rxctl_queue;
101 kcondvar_t sc_rxctl_cv;
102
103 void *sc_ih;
104 struct bwfm_core *sc_cc;
105
106 char *sc_bounce_buf;
107 size_t sc_bounce_size;
108
109 uint32_t sc_console_addr;
110 char *sc_console_buf;
111 size_t sc_console_buf_size;
112 uint32_t sc_console_readidx;
113
114 int sc_phandle;
115 void *sc_fdtih;
116 };
117
118 static int bwfm_sdio_match(device_t, cfdata_t, void *);
119 static void bwfm_sdio_attach(device_t, device_t, void *);
120 static int bwfm_sdio_detach(device_t, int);
121 static void bwfm_sdio_attachhook(device_t);
122 #ifdef FDT
123 static int bwfm_fdt_find_phandle(device_t, device_t);
124 #endif
125 static const char *bwfm_get_model(void);
126
127 static void bwfm_sdio_backplane(struct bwfm_sdio_softc *, uint32_t);
128 static uint8_t bwfm_sdio_read_1(struct bwfm_sdio_softc *, uint32_t);
129 static uint32_t bwfm_sdio_read_4(struct bwfm_sdio_softc *, uint32_t);
130 static void bwfm_sdio_write_1(struct bwfm_sdio_softc *, uint32_t,
131 uint8_t);
132 static void bwfm_sdio_write_4(struct bwfm_sdio_softc *, uint32_t,
133 uint32_t);
134
135 static uint32_t bwfm_sdio_dev_read(struct bwfm_sdio_softc *, uint32_t);
136 static void bwfm_sdio_dev_write(struct bwfm_sdio_softc *, uint32_t,
137 uint32_t);
138
139 static uint32_t bwfm_sdio_buscore_read(struct bwfm_softc *, uint32_t);
140 static void bwfm_sdio_buscore_write(struct bwfm_softc *, uint32_t,
141 uint32_t);
142 static int bwfm_sdio_buscore_prepare(struct bwfm_softc *);
143 static void bwfm_sdio_buscore_activate(struct bwfm_softc *, uint32_t);
144
145 static int bwfm_sdio_buf_read(struct bwfm_sdio_softc *,
146 struct sdmmc_function *, uint32_t, char *, size_t);
147 static int bwfm_sdio_buf_write(struct bwfm_sdio_softc *,
148 struct sdmmc_function *, uint32_t, char *, size_t);
149
150 static struct mbuf *bwfm_sdio_newbuf(void);
151 static void bwfm_qput(struct mbuf **, struct mbuf *);
152 static struct mbuf *bwfm_qget(struct mbuf **);
153
154 static int bwfm_sdio_ram_read_write(struct bwfm_sdio_softc *,
155 uint32_t, char *, size_t, int);
156 static int bwfm_sdio_frame_read_write(struct bwfm_sdio_softc *,
157 char *, size_t, int);
158
159 static int bwfm_sdio_intr1(void *, const char *);
160 static int bwfm_sdio_intr(void *);
161 static void bwfm_sdio_task(void *);
162 static void bwfm_sdio_task1(struct bwfm_sdio_softc *);
163
164 static int bwfm_nvram_convert(u_char *, size_t, size_t *);
165 static int bwfm_sdio_load_microcode(struct bwfm_sdio_softc *,
166 u_char *, size_t, u_char *, size_t);
167 static void bwfm_sdio_clkctl(struct bwfm_sdio_softc *,
168 enum bwfm_sdio_clkstate, bool);
169 static void bwfm_sdio_htclk(struct bwfm_sdio_softc *, bool, bool);
170
171 #ifdef notyet
172 static int bwfm_sdio_bus_sleep(struct bwfm_sdio_softc *, bool, bool);
173 #endif
174 static void bwfm_sdio_drivestrength(struct bwfm_sdio_softc *, unsigned);
175 static void bwfm_sdio_readshared(struct bwfm_sdio_softc *);
176
177 static int bwfm_sdio_txcheck(struct bwfm_softc *);
178 static int bwfm_sdio_txdata(struct bwfm_softc *, struct mbuf **);
179 static int bwfm_sdio_txctl(struct bwfm_softc *, char *, size_t);
180 static int bwfm_sdio_rxctl(struct bwfm_softc *, char *, size_t *);
181
182 static int bwfm_sdio_tx_ok(struct bwfm_sdio_softc *);
183 static void bwfm_sdio_tx_frames(struct bwfm_sdio_softc *);
184 static void bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *,
185 struct mbuf *);
186 static void bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *,
187 struct mbuf *);
188
189 static void bwfm_sdio_rx_frames(struct bwfm_sdio_softc *);
190 static void bwfm_sdio_rx_glom(struct bwfm_sdio_softc *,
191 uint16_t *, int, uint16_t *);
192
193 #ifdef BWFM_DEBUG
194 static void bwfm_sdio_debug_console(struct bwfm_sdio_softc *);
195 #endif
196
197 static const struct bwfm_firmware_selector bwfm_sdio_fwtab[] = {
198 BWFM_FW_ENTRY(BRCM_CC_43143_CHIP_ID,
199 BWFM_FWSEL_ALLREVS, "brcmfmac43143-sdio"),
200
201 BWFM_FW_ENTRY(BRCM_CC_43241_CHIP_ID,
202 BWFM_FWSEL_REV_LE(4), "brcmfmac43241b0-sdio"),
203 BWFM_FW_ENTRY(BRCM_CC_43241_CHIP_ID,
204 BWFM_FWSEL_REV_EQ(5), "brcmfmac43241b4-sdio"),
205 BWFM_FW_ENTRY(BRCM_CC_43241_CHIP_ID,
206 BWFM_FWSEL_REV_GE(6), "brcmfmac43241b5-sdio"),
207
208 BWFM_FW_ENTRY(BRCM_CC_4329_CHIP_ID,
209 BWFM_FWSEL_ALLREVS, "brcmfmac4329-sdio"),
210
211 BWFM_FW_ENTRY(BRCM_CC_4330_CHIP_ID,
212 BWFM_FWSEL_ALLREVS, "brcmfmac4330-sdio"),
213
214 BWFM_FW_ENTRY(BRCM_CC_4334_CHIP_ID,
215 BWFM_FWSEL_ALLREVS, "brcmfmac4334-sdio"),
216
217 BWFM_FW_ENTRY(BRCM_CC_43340_CHIP_ID,
218 BWFM_FWSEL_ALLREVS, "brcmfmac43340-sdio"),
219 BWFM_FW_ENTRY(BRCM_CC_43341_CHIP_ID,
220 BWFM_FWSEL_ALLREVS, "brcmfmac43340-sdio"),
221
222 BWFM_FW_ENTRY(BRCM_CC_4335_CHIP_ID,
223 BWFM_FWSEL_ALLREVS, "brcmfmac4335-sdio"),
224
225 BWFM_FW_ENTRY(BRCM_CC_43362_CHIP_ID,
226 BWFM_FWSEL_REV_GE(1), "brcmfmac43362-sdio"),
227
228 BWFM_FW_ENTRY(BRCM_CC_4339_CHIP_ID,
229 BWFM_FWSEL_ALLREVS, "brcmfmac4339-sdio"),
230
231 BWFM_FW_ENTRY(BRCM_CC_43430_CHIP_ID,
232 BWFM_FWSEL_REV_EQ(0), "brcmfmac43430a0-sdio"),
233 BWFM_FW_ENTRY(BRCM_CC_43430_CHIP_ID,
234 BWFM_FWSEL_REV_GE(1), "brcmfmac43430-sdio"),
235
236 BWFM_FW_ENTRY(BRCM_CC_4345_CHIP_ID,
237 BWFM_FWSEL_REV_EQ(9), "brcmfmac43456-sdio"),
238 BWFM_FW_ENTRY(BRCM_CC_4345_CHIP_ID,
239 BWFM_FWSEL_REV_LE(8) + BWFM_FWSEL_REV_GE(10),
240 "brcmfmac43455-sdio"),
241
242 BWFM_FW_ENTRY(BRCM_CC_4354_CHIP_ID,
243 BWFM_FWSEL_ALLREVS, "brcmfmac4354-sdio"),
244
245 BWFM_FW_ENTRY(BRCM_CC_4356_CHIP_ID,
246 BWFM_FWSEL_ALLREVS, "brcmfmac4356-sdio"),
247
248 BWFM_FW_ENTRY(CY_CC_4373_CHIP_ID,
249 BWFM_FWSEL_ALLREVS, "brcmfmac4373-sdio"),
250
251 BWFM_FW_ENTRY(CY_CC_43012_CHIP_ID,
252 BWFM_FWSEL_ALLREVS, "brcmfmac43012-sdio"),
253
254 BWFM_FW_ENTRY_END
255 };
256
257 static const struct bwfm_bus_ops bwfm_sdio_bus_ops = {
258 .bs_init = NULL,
259 .bs_stop = NULL,
260 .bs_txcheck = bwfm_sdio_txcheck,
261 .bs_txdata = bwfm_sdio_txdata,
262 .bs_txctl = bwfm_sdio_txctl,
263 .bs_rxctl = bwfm_sdio_rxctl,
264 };
265
266 static const struct bwfm_buscore_ops bwfm_sdio_buscore_ops = {
267 .bc_read = bwfm_sdio_buscore_read,
268 .bc_write = bwfm_sdio_buscore_write,
269 .bc_prepare = bwfm_sdio_buscore_prepare,
270 .bc_reset = NULL,
271 .bc_setup = NULL,
272 .bc_activate = bwfm_sdio_buscore_activate,
273 };
274
275 CFATTACH_DECL_NEW(bwfm_sdio, sizeof(struct bwfm_sdio_softc),
276 bwfm_sdio_match, bwfm_sdio_attach, bwfm_sdio_detach, NULL);
277
278 static const struct bwfm_sdio_product {
279 uint32_t manufacturer;
280 uint32_t product;
281 const char *cisinfo[4];
282 } bwfm_sdio_products[] = {
283 {
284 SDMMC_VENDOR_BROADCOM,
285 SDMMC_PRODUCT_BROADCOM_BCM4330,
286 SDMMC_CIS_BROADCOM_BCM4330
287 },
288 {
289 SDMMC_VENDOR_BROADCOM,
290 SDMMC_PRODUCT_BROADCOM_BCM4334,
291 SDMMC_CIS_BROADCOM_BCM4334
292 },
293 {
294 SDMMC_VENDOR_BROADCOM,
295 SDMMC_PRODUCT_BROADCOM_BCM43143,
296 SDMMC_CIS_BROADCOM_BCM43143
297 },
298 {
299 SDMMC_VENDOR_BROADCOM,
300 SDMMC_PRODUCT_BROADCOM_BCM43430,
301 SDMMC_CIS_BROADCOM_BCM43430
302 },
303 {
304 SDMMC_VENDOR_BROADCOM,
305 SDMMC_PRODUCT_BROADCOM_BCM43455,
306 SDMMC_CIS_BROADCOM_BCM43455
307 },
308 {
309 SDMMC_VENDOR_BROADCOM,
310 SDMMC_PRODUCT_BROADCOM_BCM43362,
311 SDMMC_CIS_BROADCOM_BCM43362
312 },
313 };
314
315 #ifdef FDT
316 static const struct device_compatible_entry compat_data[] = {
317 { .compat = "brcm,bcm4329-fmac" },
318 DEVICE_COMPAT_EOL
319 };
320 #endif
321
322 static int
bwfm_sdio_match(device_t parent,cfdata_t match,void * aux)323 bwfm_sdio_match(device_t parent, cfdata_t match, void *aux)
324 {
325 struct sdmmc_attach_args *saa = aux;
326 struct sdmmc_function *sf = saa->sf;
327 struct sdmmc_cis *cis;
328 const struct bwfm_sdio_product *bsp;
329 int i;
330
331 /* Not SDIO. */
332 if (sf == NULL)
333 return 0;
334
335 cis = &sf->sc->sc_fn0->cis;
336 for (i = 0; i < __arraycount(bwfm_sdio_products); ++i) {
337 bsp = &bwfm_sdio_products[i];
338 if (cis->manufacturer == bsp->manufacturer &&
339 cis->product == bsp->product)
340 break;
341 }
342 if (i >= __arraycount(bwfm_sdio_products))
343 return 0;
344
345 /* We need both functions, but ... */
346 if (sf->sc->sc_function_count <= 1)
347 return 0;
348
349 /* ... only attach for one. */
350 if (sf->number != 1)
351 return 0;
352
353 return 1;
354 }
355
356 static void
bwfm_sdio_attach(device_t parent,device_t self,void * aux)357 bwfm_sdio_attach(device_t parent, device_t self, void *aux)
358 {
359 struct bwfm_sdio_softc *sc = device_private(self);
360 struct sdmmc_attach_args *saa = aux;
361 struct sdmmc_function *sf = saa->sf;
362 struct bwfm_core *core;
363 uint32_t reg;
364
365 sc->sc_sc.sc_dev = self;
366
367 aprint_naive("\n");
368 aprint_normal("\n");
369
370 #ifdef FDT
371 sc->sc_phandle = bwfm_fdt_find_phandle(self, parent);
372 #endif
373
374 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
375 cv_init(&sc->sc_rxctl_cv, "bwfmctl");
376
377 sdmmc_init_task(&sc->sc_task, bwfm_sdio_task, sc);
378
379 sc->sc_bounce_size = 64 * 1024;
380 sc->sc_bounce_buf = kmem_alloc(sc->sc_bounce_size, KM_SLEEP);
381 sc->sc_tx_seq = 0xff;
382 MBUFQ_INIT(&sc->sc_tx_queue);
383 sc->sc_rxctl_queue = NULL;
384
385 sc->sc_sf_size = (sf->sc->sc_function_count + 1)
386 * sizeof(struct sdmmc_function *);
387 sc->sc_sf = kmem_zalloc(sc->sc_sf_size, KM_SLEEP);
388
389 /* Copy all function pointers. */
390 SIMPLEQ_FOREACH(sf, &saa->sf->sc->sf_head, sf_list) {
391 sc->sc_sf[sf->number] = sf;
392 }
393
394 sdmmc_io_set_blocklen(sc->sc_sf[1], 64);
395 sdmmc_io_set_blocklen(sc->sc_sf[2], 512);
396
397 /* Enable Function 1. */
398 if (sdmmc_io_function_enable(sc->sc_sf[1]) != 0) {
399 printf("%s: cannot enable function 1\n", DEVNAME(sc));
400 goto err;
401 }
402
403 DPRINTF(("%s: F1 signature read @0x18000000=%x\n", DEVNAME(sc),
404 bwfm_sdio_read_4(sc, 0x18000000)));
405
406 /* Force PLL off */
407 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR,
408 BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF |
409 BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ);
410
411 sc->sc_sc.sc_buscore_ops = &bwfm_sdio_buscore_ops;
412 if (bwfm_chip_attach(&sc->sc_sc) != 0) {
413 aprint_error_dev(self, "cannot attach chip\n");
414 goto err;
415 }
416
417 sc->sc_cc = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_CHIPCOMMON);
418 if (sc->sc_cc == NULL) {
419 aprint_error_dev(self, "cannot find chipcommon core\n");
420 goto err;
421 }
422
423 core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV);
424 if (core->co_rev >= 12) {
425 reg = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_SLEEPCSR);
426 if ((reg & BWFM_SDIO_FUNC1_SLEEPCSR_KSO) == 0) {
427 reg |= BWFM_SDIO_FUNC1_SLEEPCSR_KSO;
428 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SLEEPCSR, reg);
429 }
430 }
431
432 /* Default, override from "brcm,drive-strength" */
433 bwfm_sdio_drivestrength(sc, 6);
434
435 bwfm_sdio_write_1(sc, BWFM_SDIO_CCCR_CARDCTRL,
436 bwfm_sdio_read_1(sc, BWFM_SDIO_CCCR_CARDCTRL) |
437 BWFM_SDIO_CCCR_CARDCTRL_WLANRESET);
438
439 core = bwfm_chip_get_pmu(&sc->sc_sc);
440 bwfm_sdio_write_4(sc, core->co_base + BWFM_CHIP_REG_PMUCONTROL,
441 bwfm_sdio_read_4(sc, core->co_base + BWFM_CHIP_REG_PMUCONTROL) |
442 (BWFM_CHIP_REG_PMUCONTROL_RES_RELOAD <<
443 BWFM_CHIP_REG_PMUCONTROL_RES_SHIFT));
444
445 sdmmc_io_function_disable(sc->sc_sf[2]);
446
447 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, 0);
448 sc->sc_clkstate = CLK_SDONLY;
449
450 config_mountroot(self, bwfm_sdio_attachhook);
451 return;
452
453 err:
454 kmem_free(sc->sc_sf, sc->sc_sf_size);
455 }
456
457 static void
bwfm_sdio_attachhook(device_t self)458 bwfm_sdio_attachhook(device_t self)
459 {
460 struct bwfm_sdio_softc *sc = device_private(self);
461 struct bwfm_softc *bwfm = &sc->sc_sc;
462 struct bwfm_firmware_context fwctx;
463 size_t ucsize = 0, nvlen = 0, nvsize = 0, clmsize = 0;
464 uint8_t *ucode, *nvram, *clm;
465 uint32_t reg, clk;
466
467 DPRINTF(("%s: chip 0x%08x rev %u\n", DEVNAME(sc),
468 bwfm->sc_chip.ch_chip, bwfm->sc_chip.ch_chiprev));
469
470 /*
471 * 4335s >= rev 2 are considered 4339s.
472 */
473 if (bwfm->sc_chip.ch_chip == BRCM_CC_4335_CHIP_ID &&
474 bwfm->sc_chip.ch_chiprev >= 2)
475 bwfm->sc_chip.ch_chip = BRCM_CC_4339_CHIP_ID;
476
477 bwfm_firmware_context_init(&fwctx,
478 bwfm->sc_chip.ch_chip, bwfm->sc_chip.ch_chiprev,
479 bwfm_get_model(),
480 BWFM_FWREQ(BWFM_FILETYPE_UCODE)
481 | BWFM_FWREQ(BWFM_FILETYPE_NVRAM)
482 | BWFM_FWOPT(BWFM_FILETYPE_CLM)
483 );
484
485 if (!bwfm_firmware_open(bwfm, bwfm_sdio_fwtab, &fwctx)) {
486 /* Error message already displayed. */
487 goto err;
488 }
489
490 ucode = bwfm_firmware_data(&fwctx, BWFM_FILETYPE_UCODE, &ucsize);
491 KASSERT(ucode != NULL);
492 nvram = bwfm_firmware_data(&fwctx, BWFM_FILETYPE_NVRAM, &nvlen);
493 KASSERT(nvram != NULL);
494 clm = bwfm_firmware_data(&fwctx, BWFM_FILETYPE_CLM, &clmsize);
495
496 if (bwfm_nvram_convert(nvram, nvlen, &nvsize)) {
497 aprint_error_dev(bwfm->sc_dev,
498 "unable to convert %s file\n",
499 bwfm_firmware_description(BWFM_FILETYPE_NVRAM));
500 goto err;
501 }
502
503 sc->sc_alp_only = true;
504 if (bwfm_sdio_load_microcode(sc, ucode, ucsize, nvram, nvsize) != 0) {
505 aprint_error_dev(bwfm->sc_dev, "could not load microcode\n");
506 goto err;
507 }
508 sc->sc_alp_only = false;
509
510 sdmmc_pause(hztoms(1)*1000, NULL);
511
512 bwfm_sdio_clkctl(sc, CLK_AVAIL, false);
513 if (sc->sc_clkstate != CLK_AVAIL) {
514 aprint_error_dev(bwfm->sc_dev, "could not access clock\n");
515 goto err;
516 }
517
518 clk = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR);
519 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR,
520 clk | BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HT);
521
522 bwfm_sdio_dev_write(sc, SDPCMD_TOSBMAILBOXDATA,
523 SDPCM_PROT_VERSION << SDPCM_PROT_VERSION_SHIFT);
524 if (sdmmc_io_function_enable(sc->sc_sf[2])) {
525 aprint_error_dev(bwfm->sc_dev, "cannot enable function 2\n");
526 goto err;
527 }
528
529 bwfm_sdio_dev_write(sc, SDPCMD_HOSTINTMASK,
530 SDPCMD_INTSTATUS_HMB_SW_MASK | SDPCMD_INTSTATUS_CHIPACTIVE);
531 bwfm_sdio_write_1(sc, BWFM_SDIO_WATERMARK, 8);
532
533 if (bwfm_chip_sr_capable(bwfm)) {
534 reg = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_WAKEUPCTRL);
535 reg |= BWFM_SDIO_FUNC1_WAKEUPCTRL_HTWAIT;
536 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_WAKEUPCTRL, reg);
537 bwfm_sdio_write_1(sc, BWFM_SDIO_CCCR_CARDCAP,
538 BWFM_SDIO_CCCR_CARDCAP_CMD14_SUPPORT |
539 BWFM_SDIO_CCCR_CARDCAP_CMD14_EXT);
540 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR,
541 BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HT);
542 sc->sc_sr_enabled = 1;
543 } else {
544 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clk);
545 }
546
547 #ifdef notyet
548 #ifdef FDT
549 if (sc->sc_phandle >= 0) {
550 sc->sc_fdtih = fdtbus_intr_establish(sc->sc_phandle,
551 0, IPL_SDMMC, IST_LEVEL, bwfm_sdio_intr, sc);
552 }
553 #endif
554 #endif
555 if (sc->sc_fdtih != NULL) {
556 aprint_normal_dev(self, "enabling GPIO interrupt\n");
557 } else {
558 sc->sc_ih = sdmmc_intr_establish(device_parent(self),
559 bwfm_sdio_intr, sc, DEVNAME(sc));
560 }
561
562 if (sc->sc_ih == NULL && sc->sc_fdtih == NULL) {
563 aprint_error_dev(self, "could not establish interrupt\n");
564 bwfm_sdio_clkctl(sc, CLK_NONE, false);
565 return;
566 }
567 sdmmc_intr_enable(sc->sc_sf[1]);
568
569 sdmmc_pause(100000, NULL);
570
571 sc->sc_sc.sc_bus_ops = &bwfm_sdio_bus_ops;
572 sc->sc_sc.sc_proto_ops = &bwfm_proto_bcdc_ops;
573
574 /* used and cleared by bwfm_attach */
575 sc->sc_sc.sc_clm = clm;
576 sc->sc_sc.sc_clmsize = clmsize;
577
578 bwfm_attach(&sc->sc_sc);
579 sc->sc_bwfm_attached = true;
580
581 err:
582 bwfm_firmware_close(&fwctx);
583 }
584
585 #ifdef FDT
586 static int
bwfm_fdt_find_phandle(device_t self,device_t parent)587 bwfm_fdt_find_phandle(device_t self, device_t parent)
588 {
589 prop_dictionary_t dict;
590 device_t dev;
591 const char *str;
592 int phandle;
593
594 /* locate in FDT */
595 dict = device_properties(self);
596 if (prop_dictionary_get_string(dict, "fdt-path", &str)) {
597 /* search in FDT */
598 phandle = OF_finddevice(str);
599 } else {
600
601 /* parent parent is sdhc controller */
602 dev = device_parent(parent);
603 if (dev == NULL)
604 return -1;
605 /* locate in FDT */
606 dict = device_properties(dev);
607 if (!prop_dictionary_get_string(dict, "fdt-path", &str))
608 return -1;
609
610 /* are we the only FDT child ? */
611 phandle = OF_child(OF_finddevice(str));
612 }
613
614 if (!of_compatible_match(phandle, compat_data))
615 return -1;
616
617 return phandle;
618 }
619 #endif
620
621 static const char *
bwfm_get_model(void)622 bwfm_get_model(void)
623 {
624 #ifdef FDT
625 const char *model;
626 int phandle;
627
628 phandle = OF_finddevice("/");
629 model = fdtbus_get_string_index(phandle, "compatible", 0);
630 if (model == NULL ||
631 (model != NULL && strcmp(model, "netbsd,generic-acpi") == 0)) {
632 model = pmf_get_platform("system-product");
633 }
634
635 return model;
636 #else
637 return NULL;
638 #endif
639 }
640
641 static int
bwfm_sdio_detach(device_t self,int flags)642 bwfm_sdio_detach(device_t self, int flags)
643 {
644 struct bwfm_sdio_softc *sc = device_private(self);
645
646 #ifdef BWFM_DEBUG
647 bwfm_sdio_debug_console(sc);
648 #endif
649
650 if (sc->sc_ih || sc->sc_fdtih) {
651 sdmmc_intr_disable(sc->sc_sf[1]);
652 if (sc->sc_ih)
653 sdmmc_intr_disestablish(sc->sc_ih);
654 #ifdef FDT
655 if (sc->sc_fdtih)
656 fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_fdtih);
657 #endif
658 }
659 if (sc->sc_bwfm_attached)
660 bwfm_detach(&sc->sc_sc, flags);
661
662 sdmmc_del_task(sc->sc_sf[1]->sc, &sc->sc_task, NULL);
663
664 kmem_free(sc->sc_sf, sc->sc_sf_size);
665 kmem_free(sc->sc_bounce_buf, sc->sc_bounce_size);
666
667 cv_destroy(&sc->sc_rxctl_cv);
668 mutex_destroy(&sc->sc_lock);
669
670 return 0;
671 }
672
673 static void
bwfm_sdio_backplane(struct bwfm_sdio_softc * sc,uint32_t addr)674 bwfm_sdio_backplane(struct bwfm_sdio_softc *sc, uint32_t addr)
675 {
676 uint32_t bar0 = addr & ~BWFM_SDIO_SB_OFT_ADDR_MASK;
677
678 if (sc->sc_bar0 == bar0)
679 return;
680
681 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRLOW,
682 (bar0 >> 8) & 0xff);
683 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRMID,
684 (bar0 >> 16) & 0xff);
685 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRHIGH,
686 (bar0 >> 24) & 0xff);
687 sc->sc_bar0 = bar0;
688 }
689
690 static uint8_t
bwfm_sdio_read_1(struct bwfm_sdio_softc * sc,uint32_t addr)691 bwfm_sdio_read_1(struct bwfm_sdio_softc *sc, uint32_t addr)
692 {
693 struct sdmmc_function *sf;
694 uint8_t rv;
695
696 /*
697 * figure out how to read the register based on address range
698 * 0x00 ~ 0x7FF: function 0 CCCR and FBR
699 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
700 * The rest: function 1 silicon backplane core registers
701 */
702 if ((addr & ~0x7ff) == 0)
703 sf = sc->sc_sf[0];
704 else
705 sf = sc->sc_sf[1];
706
707 rv = sdmmc_io_read_1(sf, addr);
708 return rv;
709 }
710
711 static uint32_t
bwfm_sdio_read_4(struct bwfm_sdio_softc * sc,uint32_t addr)712 bwfm_sdio_read_4(struct bwfm_sdio_softc *sc, uint32_t addr)
713 {
714 struct sdmmc_function *sf;
715 uint32_t rv;
716
717 bwfm_sdio_backplane(sc, addr);
718
719 addr &= BWFM_SDIO_SB_OFT_ADDR_MASK;
720 addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG;
721
722 /*
723 * figure out how to read the register based on address range
724 * 0x00 ~ 0x7FF: function 0 CCCR and FBR
725 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
726 * The rest: function 1 silicon backplane core registers
727 */
728 if ((addr & ~0x7ff) == 0)
729 sf = sc->sc_sf[0];
730 else
731 sf = sc->sc_sf[1];
732
733 rv = sdmmc_io_read_4(sf, addr);
734 return htole32(rv);
735 }
736
737 static void
bwfm_sdio_write_1(struct bwfm_sdio_softc * sc,uint32_t addr,uint8_t data)738 bwfm_sdio_write_1(struct bwfm_sdio_softc *sc, uint32_t addr, uint8_t data)
739 {
740 struct sdmmc_function *sf;
741
742 /*
743 * figure out how to read the register based on address range
744 * 0x00 ~ 0x7FF: function 0 CCCR and FBR
745 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
746 * The rest: function 1 silicon backplane core registers
747 */
748 if ((addr & ~0x7ff) == 0)
749 sf = sc->sc_sf[0];
750 else
751 sf = sc->sc_sf[1];
752
753 sdmmc_io_write_1(sf, addr, data);
754 }
755
756 static void
bwfm_sdio_write_4(struct bwfm_sdio_softc * sc,uint32_t addr,uint32_t data)757 bwfm_sdio_write_4(struct bwfm_sdio_softc *sc, uint32_t addr, uint32_t data)
758 {
759 struct sdmmc_function *sf;
760
761 bwfm_sdio_backplane(sc, addr);
762
763 addr &= BWFM_SDIO_SB_OFT_ADDR_MASK;
764 addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG;
765
766 /*
767 * figure out how to read the register based on address range
768 * 0x00 ~ 0x7FF: function 0 CCCR and FBR
769 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
770 * The rest: function 1 silicon backplane core registers
771 */
772 if ((addr & ~0x7ff) == 0)
773 sf = sc->sc_sf[0];
774 else
775 sf = sc->sc_sf[1];
776
777 sdmmc_io_write_4(sf, addr, htole32(data));
778 }
779
780 static int
bwfm_sdio_buf_read(struct bwfm_sdio_softc * sc,struct sdmmc_function * sf,uint32_t reg,char * data,size_t size)781 bwfm_sdio_buf_read(struct bwfm_sdio_softc *sc, struct sdmmc_function *sf,
782 uint32_t reg, char *data, size_t size)
783 {
784 int err;
785
786 KASSERT(((vaddr_t)data & 0x3) == 0);
787 KASSERT((size & 0x3) == 0);
788
789 if (sf == sc->sc_sf[1])
790 err = sdmmc_io_read_region_1(sf, reg, data, size);
791 else
792 err = sdmmc_io_read_multi_1(sf, reg, data, size);
793
794 if (err)
795 printf("%s: error %d\n", __func__, err);
796
797 return err;
798 }
799
800 static int
bwfm_sdio_buf_write(struct bwfm_sdio_softc * sc,struct sdmmc_function * sf,uint32_t reg,char * data,size_t size)801 bwfm_sdio_buf_write(struct bwfm_sdio_softc *sc, struct sdmmc_function *sf,
802 uint32_t reg, char *data, size_t size)
803 {
804 int err;
805
806 KASSERT(((vaddr_t)data & 0x3) == 0);
807 KASSERT((size & 0x3) == 0);
808
809 err = sdmmc_io_write_region_1(sf, reg, data, size);
810
811 if (err)
812 printf("%s: error %d\n", __func__, err);
813
814 return err;
815 }
816
817 static int
bwfm_sdio_ram_read_write(struct bwfm_sdio_softc * sc,uint32_t reg,char * data,size_t left,int write)818 bwfm_sdio_ram_read_write(struct bwfm_sdio_softc *sc, uint32_t reg,
819 char *data, size_t left, int write)
820 {
821 uint32_t sbaddr, sdaddr, off;
822 size_t size;
823 int err;
824
825 err = off = 0;
826 while (left > 0) {
827 sbaddr = reg + off;
828 bwfm_sdio_backplane(sc, sbaddr);
829
830 sdaddr = sbaddr & BWFM_SDIO_SB_OFT_ADDR_MASK;
831 size = ulmin(left, (BWFM_SDIO_SB_OFT_ADDR_PAGE - sdaddr));
832 sdaddr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG;
833
834 if (write) {
835 memcpy(sc->sc_bounce_buf, data + off, size);
836 if (roundup(size, 4) != size)
837 memset(sc->sc_bounce_buf + size, 0,
838 roundup(size, 4) - size);
839 err = bwfm_sdio_buf_write(sc, sc->sc_sf[1], sdaddr,
840 sc->sc_bounce_buf, roundup(size, 4));
841 } else {
842 err = bwfm_sdio_buf_read(sc, sc->sc_sf[1], sdaddr,
843 sc->sc_bounce_buf, roundup(size, 4));
844 memcpy(data + off, sc->sc_bounce_buf, size);
845 }
846 if (err)
847 break;
848
849 off += size;
850 left -= size;
851 }
852
853 if (err)
854 printf("%s: error %d\n", __func__, err);
855
856 return err;
857 }
858
859 static int
bwfm_sdio_frame_read_write(struct bwfm_sdio_softc * sc,char * data,size_t size,int write)860 bwfm_sdio_frame_read_write(struct bwfm_sdio_softc *sc,
861 char *data, size_t size, int write)
862 {
863 uint32_t addr;
864 int err;
865
866 addr = sc->sc_cc->co_base;
867 bwfm_sdio_backplane(sc, addr);
868
869 addr &= BWFM_SDIO_SB_OFT_ADDR_MASK;
870 addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG;
871
872 if (write) {
873 err = bwfm_sdio_buf_write(sc, sc->sc_sf[2], addr, data, size);
874 } else {
875 err = bwfm_sdio_buf_read(sc, sc->sc_sf[2], addr, data, size);
876 }
877
878 return err;
879 }
880
881 static uint32_t
bwfm_sdio_dev_read(struct bwfm_sdio_softc * sc,uint32_t reg)882 bwfm_sdio_dev_read(struct bwfm_sdio_softc *sc, uint32_t reg)
883 {
884 struct bwfm_core *core;
885 uint32_t val;
886
887 core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV);
888 val = bwfm_sdio_read_4(sc, core->co_base + reg);
889 /* TODO: Workaround for 4335/4339 */
890
891 return val;
892 }
893
894 static void
bwfm_sdio_dev_write(struct bwfm_sdio_softc * sc,uint32_t reg,uint32_t val)895 bwfm_sdio_dev_write(struct bwfm_sdio_softc *sc, uint32_t reg, uint32_t val)
896 {
897 struct bwfm_core *core;
898
899 core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV);
900 bwfm_sdio_write_4(sc, core->co_base + reg, val);
901 }
902
903 static uint32_t
bwfm_sdio_buscore_read(struct bwfm_softc * bwfm,uint32_t reg)904 bwfm_sdio_buscore_read(struct bwfm_softc *bwfm, uint32_t reg)
905 {
906 struct bwfm_sdio_softc *sc = (void *)bwfm;
907 uint32_t val;
908
909 mutex_enter(&sc->sc_lock);
910 val = bwfm_sdio_read_4(sc, reg);
911 /* TODO: Workaround for 4335/4339 */
912 mutex_exit(&sc->sc_lock);
913
914 return val;
915 }
916
917 static void
bwfm_sdio_buscore_write(struct bwfm_softc * bwfm,uint32_t reg,uint32_t val)918 bwfm_sdio_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val)
919 {
920 struct bwfm_sdio_softc *sc = (void *)bwfm;
921
922 mutex_enter(&sc->sc_lock);
923 bwfm_sdio_write_4(sc, reg, val);
924 mutex_exit(&sc->sc_lock);
925 }
926
927 static int
bwfm_sdio_buscore_prepare(struct bwfm_softc * bwfm)928 bwfm_sdio_buscore_prepare(struct bwfm_softc *bwfm)
929 {
930 struct bwfm_sdio_softc *sc = (void *)bwfm;
931 uint8_t clkval, clkset, clkmask;
932 int i, error = 0;
933
934 mutex_enter(&sc->sc_lock);
935
936 clkset = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ |
937 BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF;
938 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clkset);
939
940 clkmask = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL |
941 BWFM_SDIO_FUNC1_CHIPCLKCSR_HT_AVAIL;
942 clkval = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR);
943
944 if ((clkval & ~clkmask) != clkset) {
945 printf("%s: wrote 0x%02x read 0x%02x\n", DEVNAME(sc),
946 clkset, clkval);
947 error = 1;
948 goto done;
949 }
950
951 for (i = 1000; i > 0; i--) {
952 clkval = bwfm_sdio_read_1(sc,
953 BWFM_SDIO_FUNC1_CHIPCLKCSR);
954 if (clkval & clkmask)
955 break;
956 }
957 if (i == 0) {
958 printf("%s: timeout on ALPAV wait, clkval 0x%02x\n",
959 DEVNAME(sc), clkval);
960 error = 1;
961 goto done;
962 }
963
964 clkset = BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF |
965 BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_ALP;
966 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clkset);
967 delay(65);
968
969 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SDIOPULLUP, 0);
970
971 done:
972 mutex_exit(&sc->sc_lock);
973
974 return error;
975 }
976
977 static void
bwfm_sdio_buscore_activate(struct bwfm_softc * bwfm,uint32_t rstvec)978 bwfm_sdio_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec)
979 {
980 struct bwfm_sdio_softc *sc = (void *)bwfm;
981 struct bwfm_core *core;
982
983 core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV);
984 bwfm_sdio_buscore_write(&sc->sc_sc,
985 core->co_base + BWFM_SDPCMD_INTSTATUS, 0xFFFFFFFF);
986
987 mutex_enter(&sc->sc_lock);
988 if (rstvec)
989 bwfm_sdio_ram_read_write(sc, 0, (char *)&rstvec,
990 sizeof(rstvec), 1);
991 mutex_exit(&sc->sc_lock);
992 }
993
994 static struct mbuf *
bwfm_sdio_newbuf(void)995 bwfm_sdio_newbuf(void)
996 {
997 struct mbuf *m;
998
999 MGETHDR(m, M_DONTWAIT, MT_DATA);
1000 if (m == NULL)
1001 return NULL;
1002
1003 MCLGET(m, M_DONTWAIT);
1004 if (!(m->m_flags & M_EXT)) {
1005 m_freem(m);
1006 return NULL;
1007 }
1008
1009 m->m_len = m->m_pkthdr.len = MCLBYTES;
1010 return m;
1011 }
1012
1013 static struct mbuf *
bwfm_qget(struct mbuf ** q)1014 bwfm_qget(struct mbuf **q)
1015 {
1016 struct mbuf *m = NULL;
1017
1018 if (*q != NULL) {
1019 m = *q;
1020 *q = m->m_next;
1021 m->m_next = NULL;
1022 }
1023
1024 return m;
1025 }
1026
1027 static void
bwfm_qput(struct mbuf ** q,struct mbuf * m)1028 bwfm_qput(struct mbuf **q, struct mbuf *m)
1029 {
1030
1031 if (*q == NULL)
1032 *q = m;
1033 else
1034 m_cat(*q, m);
1035 }
1036
1037 static int
bwfm_sdio_txcheck(struct bwfm_softc * bwfm)1038 bwfm_sdio_txcheck(struct bwfm_softc *bwfm)
1039 {
1040 struct bwfm_sdio_softc *sc = (void *)bwfm;
1041 int error = 0;
1042
1043 mutex_enter(&sc->sc_lock);
1044 if (sc->sc_tx_count >= 64)
1045 error = ENOBUFS;
1046 mutex_exit(&sc->sc_lock);
1047
1048 return error;
1049 }
1050
1051
1052 static int
bwfm_sdio_txdata(struct bwfm_softc * bwfm,struct mbuf ** mp)1053 bwfm_sdio_txdata(struct bwfm_softc *bwfm, struct mbuf **mp)
1054 {
1055 struct bwfm_sdio_softc *sc = (void *)bwfm;
1056
1057 if (sc->sc_tx_count >= 64) {
1058 printf("%s: tx count limit reached\n",DEVNAME(sc));
1059 return ENOBUFS;
1060 }
1061
1062 mutex_enter(&sc->sc_lock);
1063 sc->sc_tx_count++;
1064 MBUFQ_ENQUEUE(&sc->sc_tx_queue, *mp);
1065 mutex_exit(&sc->sc_lock);
1066
1067 bwfm_sdio_intr1(sc, "sdio_txdata");
1068
1069 return 0;
1070 }
1071
1072 static int
bwfm_sdio_txctl(struct bwfm_softc * bwfm,char * buf,size_t len)1073 bwfm_sdio_txctl(struct bwfm_softc *bwfm, char *buf, size_t len)
1074 {
1075 struct bwfm_sdio_softc *sc = (void *)bwfm;
1076 struct mbuf *m;
1077
1078 KASSERT(len <= MCLBYTES);
1079
1080 MGET(m, M_DONTWAIT, MT_CONTROL);
1081 if (m == NULL)
1082 goto fail;
1083 if (len > MLEN) {
1084 MCLGET(m, M_DONTWAIT);
1085 if (!(m->m_flags & M_EXT)) {
1086 m_freem(m);
1087 goto fail;
1088 }
1089 }
1090 memcpy(mtod(m, char *), buf, len);
1091 m->m_len = len;
1092
1093 mutex_enter(&sc->sc_lock);
1094 MBUFQ_ENQUEUE(&sc->sc_tx_queue, m);
1095 mutex_exit(&sc->sc_lock);
1096
1097 bwfm_sdio_intr1(sc, "sdio_txctl");
1098
1099 return 0;
1100
1101 fail:
1102 return ENOBUFS;
1103 }
1104
1105 static int
bwfm_nvram_convert(u_char * buf,size_t len,size_t * newlenp)1106 bwfm_nvram_convert(u_char *buf, size_t len, size_t *newlenp)
1107 {
1108 u_char *src, *dst, *end = buf + len;
1109 bool skip = false;
1110 size_t count = 0, pad;
1111 uint32_t token;
1112
1113 for (src = buf, dst = buf; src != end; ++src) {
1114 if (*src == '\n') {
1115 if (count > 0)
1116 *dst++ = '\0';
1117 count = 0;
1118 skip = false;
1119 continue;
1120 }
1121 if (skip)
1122 continue;
1123 if (*src == '#' && count == 0) {
1124 skip = true;
1125 continue;
1126 }
1127 if (*src == '\r' || *src == ' ')
1128 continue;
1129 *dst++ = *src;
1130 ++count;
1131 }
1132
1133 count = dst - buf;
1134 pad = roundup(count + 1, 4) - count;
1135
1136 if (count + pad + sizeof(token) > len)
1137 return 1;
1138
1139 memset(dst, 0, pad);
1140 count += pad;
1141 dst += pad;
1142
1143 token = (count / 4) & 0xffff;
1144 token |= ~token << 16;
1145 token = htole32(token);
1146
1147 memcpy(dst, &token, sizeof(token));
1148 count += sizeof(token);
1149
1150 *newlenp = count;
1151
1152 return 0;
1153 }
1154
1155 static int
bwfm_sdio_load_microcode(struct bwfm_sdio_softc * sc,u_char * ucode,size_t size,u_char * nvram,size_t nvlen)1156 bwfm_sdio_load_microcode(struct bwfm_sdio_softc *sc, u_char *ucode, size_t size,
1157 u_char *nvram, size_t nvlen)
1158 {
1159 struct bwfm_softc *bwfm = &sc->sc_sc;
1160 char *verify = NULL;
1161 int err;
1162
1163 bwfm_sdio_clkctl(sc, CLK_AVAIL, false);
1164
1165 DPRINTF(("ucode %zu bytes to 0x%08lx\n", size,
1166 (u_long)bwfm->sc_chip.ch_rambase));
1167 /* Upload firmware */
1168 err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase,
1169 ucode, size, 1);
1170 if (err)
1171 goto out;
1172
1173 /* Verify firmware */
1174 verify = kmem_zalloc(size, KM_SLEEP);
1175 err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase,
1176 verify, size, 0);
1177 if (err || memcmp(verify, ucode, size)) {
1178 printf("%s: firmware verification failed\n",
1179 DEVNAME(sc));
1180 kmem_free(verify, size);
1181 goto out;
1182 }
1183 kmem_free(verify, size);
1184
1185 DPRINTF(("nvram %zu bytes to 0x%08lx\n", nvlen,
1186 (u_long)bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize
1187 - nvlen));
1188 /* Upload nvram */
1189 err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase +
1190 bwfm->sc_chip.ch_ramsize - nvlen, nvram, nvlen, 1);
1191 if (err)
1192 goto out;
1193
1194 /* Verify nvram */
1195 verify = kmem_zalloc(nvlen, KM_SLEEP);
1196 err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase +
1197 bwfm->sc_chip.ch_ramsize - nvlen, verify, nvlen, 0);
1198 if (err || memcmp(verify, nvram, nvlen)) {
1199 printf("%s: nvram verification failed\n",
1200 DEVNAME(sc));
1201 kmem_free(verify, nvlen);
1202 goto out;
1203 }
1204 kmem_free(verify, nvlen);
1205
1206 DPRINTF(("Reset core 0x%08x\n", *(uint32_t *)ucode));
1207 /* Load reset vector from firmware and kickstart core. */
1208 bwfm_chip_set_active(bwfm, *(uint32_t *)ucode);
1209
1210 out:
1211 bwfm_sdio_clkctl(sc, CLK_SDONLY, false);
1212 return err;
1213 }
1214
1215 static void
bwfm_sdio_clkctl(struct bwfm_sdio_softc * sc,enum bwfm_sdio_clkstate newstate,bool pendok)1216 bwfm_sdio_clkctl(struct bwfm_sdio_softc *sc, enum bwfm_sdio_clkstate newstate,
1217 bool pendok)
1218 {
1219 enum bwfm_sdio_clkstate oldstate;
1220
1221 oldstate = sc->sc_clkstate;
1222 if (oldstate == newstate)
1223 return;
1224
1225 switch (newstate) {
1226 case CLK_AVAIL:
1227 if (oldstate == CLK_NONE)
1228 sc->sc_clkstate = CLK_SDONLY; /* XXX */
1229 bwfm_sdio_htclk(sc, true, pendok);
1230 break;
1231 case CLK_SDONLY:
1232 if (oldstate == CLK_NONE)
1233 sc->sc_clkstate = newstate;
1234 else if (oldstate == CLK_AVAIL)
1235 bwfm_sdio_htclk(sc, false, false);
1236 else
1237 printf("%s: clkctl %d -> %d\n", DEVNAME(sc),
1238 sc->sc_clkstate, newstate);
1239 break;
1240 case CLK_NONE:
1241 if (oldstate == CLK_AVAIL)
1242 bwfm_sdio_htclk(sc, false, false);
1243 sc->sc_clkstate = newstate;
1244 break;
1245 default:
1246 break;
1247 }
1248
1249 DPRINTF(("%s: %d -> %d = %d\n", DEVNAME(sc), oldstate, newstate,
1250 sc->sc_clkstate));
1251 }
1252
1253 static void
bwfm_sdio_htclk(struct bwfm_sdio_softc * sc,bool on,bool pendok)1254 bwfm_sdio_htclk(struct bwfm_sdio_softc *sc, bool on, bool pendok)
1255 {
1256 uint32_t clkctl, devctl, req;
1257 int i;
1258
1259 if (sc->sc_sr_enabled) {
1260 if (on)
1261 sc->sc_clkstate = CLK_AVAIL;
1262 else
1263 sc->sc_clkstate = CLK_SDONLY;
1264 return;
1265 }
1266
1267 if (on) {
1268 if (sc->sc_alp_only)
1269 req = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ;
1270 else
1271 req = BWFM_SDIO_FUNC1_CHIPCLKCSR_HT_AVAIL_REQ;
1272 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, req);
1273
1274 clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR);
1275 if (!BWFM_SDIO_FUNC1_CHIPCLKCSR_CLKAV(clkctl, sc->sc_alp_only)
1276 && pendok) {
1277 devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL);
1278 devctl |= BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY;
1279 bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl);
1280 sc->sc_clkstate = CLK_PENDING;
1281 return;
1282 } else if (sc->sc_clkstate == CLK_PENDING) {
1283 devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL);
1284 devctl &= ~BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY;
1285 bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl);
1286 }
1287
1288 for (i = 0; i < 50; i++) {
1289 if (BWFM_SDIO_FUNC1_CHIPCLKCSR_CLKAV(clkctl,
1290 sc->sc_alp_only))
1291 break;
1292 clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR
1293 );
1294 sdmmc_pause(100000, NULL);
1295 }
1296 if (i >= 50) {
1297 printf("%s: HT avail timeout\n", DEVNAME(sc));
1298 return;
1299 }
1300
1301 sc->sc_clkstate = CLK_AVAIL;
1302 } else {
1303 if (sc->sc_clkstate == CLK_PENDING) {
1304 devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL);
1305 devctl &= ~BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY;
1306 bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl);
1307 }
1308 sc->sc_clkstate = CLK_SDONLY;
1309 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, 0);
1310 }
1311 }
1312
1313 struct bwfm_sdio_dstab {
1314 uint8_t milli;
1315 uint8_t val;
1316 };
1317
1318 static struct bwfm_sdio_dstab pmu11_1v8[] = {
1319 {32, 0x6},
1320 {26, 0x7},
1321 {22, 0x4},
1322 {16, 0x5},
1323 {12, 0x2},
1324 {8, 0x3},
1325 {4, 0x0},
1326 {0, 0x1}
1327 }, pmu13_1v8[] = {
1328 {6, 0x7},
1329 {5, 0x6},
1330 {4, 0x5},
1331 {3, 0x4},
1332 {2, 0x2},
1333 {1, 0x1},
1334 {0, 0x0}
1335 }, pmu17_1v8[] = {
1336 {3, 0x3},
1337 {2, 0x2},
1338 {1, 0x1},
1339 {0, 0x0}
1340 }, pmu17_3v3[] = {
1341 {16, 0x7},
1342 {12, 0x5},
1343 {8, 0x3},
1344 {4, 0x1},
1345 {0, 0x0}
1346 };
1347
1348 static void
bwfm_sdio_drivestrength(struct bwfm_sdio_softc * sc,unsigned milli)1349 bwfm_sdio_drivestrength(struct bwfm_sdio_softc *sc, unsigned milli)
1350 {
1351 struct bwfm_softc *bwfm = &sc->sc_sc;
1352 struct bwfm_core *core;
1353 struct bwfm_sdio_dstab *tab;
1354 uint32_t tmp, mask;
1355 unsigned i;
1356
1357 if ((bwfm->sc_chip.ch_cc_caps & BWFM_CHIP_REG_CAPABILITIES_PMU) == 0)
1358 return;
1359
1360 switch (bwfm->sc_chip.ch_chip) {
1361 case BRCM_CC_4330_CHIP_ID:
1362 tab = pmu11_1v8;
1363 mask = __BITS(11,13);
1364 break;
1365 case BRCM_CC_4334_CHIP_ID:
1366 tab = pmu17_1v8;
1367 mask = __BITS(11,12);
1368 break;
1369 case BRCM_CC_43143_CHIP_ID:
1370 tab = pmu17_3v3;
1371 mask = __BITS(0,3);
1372 break;
1373 case BRCM_CC_43362_CHIP_ID:
1374 tab = pmu13_1v8;
1375 mask = __BITS(11,13);
1376 break;
1377 default:
1378 return;
1379 }
1380
1381 for (i=0; tab[i].milli != 0; ++i) {
1382 if (milli >= tab[i].milli)
1383 break;
1384 }
1385 if (tab[i].milli == 0)
1386 return;
1387
1388 core = bwfm_chip_get_pmu(&sc->sc_sc);
1389 tmp = bwfm_sdio_read_4(sc, core->co_base + BWFM_CHIP_REG_CHIPCONTROL_ADDR);
1390 tmp &= mask;
1391 tmp |= __SHIFTIN(tab[i].val, mask);
1392 bwfm_sdio_write_4(sc, core->co_base + BWFM_CHIP_REG_CHIPCONTROL_ADDR, tmp);
1393 }
1394
1395
1396 #if notyet
1397 static int
bwfm_sdio_bus_sleep(struct bwfm_sdio_softc * sc,bool sleep,bool pendok)1398 bwfm_sdio_bus_sleep(struct bwfm_sdio_softc *sc, bool sleep, bool pendok)
1399 {
1400 uint32_t clkctl;
1401
1402 if (sc->sleeping == sleep)
1403 return 0;
1404
1405 if (sc->sc_sr_enabled) {
1406 if (sleep) {
1407 clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR);
1408 if ((clkctl & BWFM_SDIO_FUNC1_CHIPCLKCSR_CSR_MASK) == 0)
1409 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ);
1410 }
1411 /* kso_ctrl(sc, sleep) */
1412 }
1413
1414 if (sleep) {
1415 if (!sc->sc_sr_enabled)
1416 bwfm_sdio_clkctl(sc, CLK_NONE, pendok);
1417 } else {
1418 bwfm_sdio_clkctl(sc, CLK_AVAIL, pendok);
1419 }
1420
1421 sc->sleeping = sleep;
1422
1423 return 0;
1424 }
1425 #endif
1426
1427 static void
bwfm_sdio_readshared(struct bwfm_sdio_softc * sc)1428 bwfm_sdio_readshared(struct bwfm_sdio_softc *sc)
1429 {
1430 struct bwfm_softc *bwfm = &sc->sc_sc;
1431 struct bwfm_sdio_sdpcm sdpcm;
1432 uint32_t addr, shaddr;
1433 int err;
1434
1435 bwfm_sdio_clkctl(sc, CLK_AVAIL, false);
1436 if (sc->sc_clkstate != CLK_AVAIL)
1437 return;
1438
1439 shaddr = bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4;
1440 if (!bwfm->sc_chip.ch_rambase && sc->sc_sr_enabled)
1441 shaddr -= bwfm->sc_chip.ch_srsize;
1442
1443 err = bwfm_sdio_ram_read_write(sc, shaddr, (char *)&addr,
1444 sizeof(addr), 0);
1445 if (err)
1446 return;
1447
1448 addr = le32toh(addr);
1449 if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff))
1450 return;
1451
1452 err = bwfm_sdio_ram_read_write(sc, addr, (char *)&sdpcm,
1453 sizeof(sdpcm), 0);
1454 if (err)
1455 return;
1456
1457 sc->sc_console_addr = le32toh(sdpcm.console_addr);
1458 }
1459
1460 static int
bwfm_sdio_intr1(void * v,const char * name)1461 bwfm_sdio_intr1(void *v, const char *name)
1462 {
1463 struct bwfm_sdio_softc *sc = (void *)v;
1464
1465 DPRINTF(("%s: %s\n", DEVNAME(sc), name));
1466
1467 sdmmc_add_task(sc->sc_sf[1]->sc, &sc->sc_task);
1468 return 1;
1469 }
1470
1471 static int
bwfm_sdio_intr(void * v)1472 bwfm_sdio_intr(void *v)
1473 {
1474 return bwfm_sdio_intr1(v, "sdio_intr");
1475 }
1476
1477 static void
bwfm_sdio_task(void * v)1478 bwfm_sdio_task(void *v)
1479 {
1480 struct bwfm_sdio_softc *sc = (void *)v;
1481
1482 mutex_enter(&sc->sc_lock);
1483 bwfm_sdio_task1(sc);
1484 #ifdef BWFM_DEBUG
1485 bwfm_sdio_debug_console(sc);
1486 #endif
1487 mutex_exit(&sc->sc_lock);
1488 }
1489
1490 static void
bwfm_sdio_task1(struct bwfm_sdio_softc * sc)1491 bwfm_sdio_task1(struct bwfm_sdio_softc *sc)
1492 {
1493 uint32_t clkctl, devctl, intstat, hostint;
1494 bool dorecv, dosend;
1495
1496 if (!sc->sc_sr_enabled && sc->sc_clkstate == CLK_PENDING) {
1497 clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR);
1498 if (BWFM_SDIO_FUNC1_CHIPCLKCSR_HTAV(clkctl)) {
1499 devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL);
1500 devctl &= ~BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY;
1501 bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl);
1502 sc->sc_clkstate = CLK_AVAIL;
1503 }
1504 }
1505
1506 dorecv = dosend = sc->sc_clkstate == CLK_AVAIL;
1507
1508 intstat = bwfm_sdio_dev_read(sc, BWFM_SDPCMD_INTSTATUS);
1509 DPRINTF(("%s: intstat 0x%" PRIx32 "\n", DEVNAME(sc), intstat));
1510 if (intstat)
1511 bwfm_sdio_dev_write(sc, BWFM_SDPCMD_INTSTATUS, intstat);
1512
1513 if (intstat & SDPCMD_INTSTATUS_CHIPACTIVE)
1514 printf("%s: CHIPACTIVE\n", DEVNAME(sc));
1515
1516 if (intstat & SDPCMD_INTSTATUS_HMB_HOST_INT) {
1517 hostint = bwfm_sdio_dev_read(sc, SDPCMD_TOHOSTMAILBOXDATA);
1518 DPRINTF(("%s: hostint 0x%" PRIx32 "\n", DEVNAME(sc), hostint));
1519 bwfm_sdio_dev_write(sc, SDPCMD_TOSBMAILBOX,
1520 SDPCMD_TOSBMAILBOX_INT_ACK);
1521 if (hostint & SDPCMD_TOHOSTMAILBOXDATA_FWHALT)
1522 printf("%s: firmware halted\n", DEVNAME(sc));
1523 if (hostint & SDPCMD_TOHOSTMAILBOXDATA_NAKHANDLED)
1524 sc->sc_rxskip = false;
1525 if (hostint & SDPCMD_TOHOSTMAILBOXDATA_DEVREADY ||
1526 hostint & SDPCMD_TOHOSTMAILBOXDATA_FWREADY)
1527 bwfm_sdio_readshared(sc);
1528 }
1529
1530 if (intstat & SDPCMD_INTSTATUS_HMB_FRAME_IND) {
1531 /* ignore receive indications while recovering */
1532 if (dorecv && !sc->sc_rxskip) {
1533 DPRINTF(("%s: recv\n", DEVNAME(sc)));
1534 bwfm_sdio_rx_frames(sc);
1535 }
1536 }
1537
1538 if (intstat & SDPCMD_INTSTATUS_HMB_FC_STATE)
1539 dosend = false;
1540
1541 if (intstat & SDPCMD_INTSTATUS_HMB_FC_CHANGE) {
1542 if (dosend) {
1543 intstat = bwfm_sdio_dev_read(sc, BWFM_SDPCMD_INTSTATUS);
1544 DPRINTF(("%s: intstat2 0x%" PRIx32 "\n", DEVNAME(sc), intstat));
1545 if (intstat & (SDPCMD_INTSTATUS_HMB_FC_STATE | SDPCMD_INTSTATUS_HMB_FC_CHANGE))
1546 dosend = false;
1547 }
1548 }
1549
1550 if (!dosend && MBUFQ_FIRST(&sc->sc_tx_queue))
1551 printf("%s: pause\n", DEVNAME(sc));
1552
1553 if (dosend && MBUFQ_FIRST(&sc->sc_tx_queue)) {
1554 DPRINTF(("%s: xmit\n", DEVNAME(sc)));
1555 bwfm_sdio_tx_frames(sc);
1556 }
1557 }
1558
1559 static int
bwfm_sdio_tx_ok(struct bwfm_sdio_softc * sc)1560 bwfm_sdio_tx_ok(struct bwfm_sdio_softc *sc)
1561 {
1562 return (uint8_t)(sc->sc_tx_max_seq - sc->sc_tx_seq) != 0 &&
1563 ((uint8_t)(sc->sc_tx_max_seq - sc->sc_tx_seq) & 0x80) == 0;
1564 }
1565
1566 static void
bwfm_sdio_tx_frames(struct bwfm_sdio_softc * sc)1567 bwfm_sdio_tx_frames(struct bwfm_sdio_softc *sc)
1568 {
1569 struct mbuf *m;
1570 struct ifnet *ifp = sc->sc_sc.sc_ic.ic_ifp;
1571 bool ifstart = false;
1572 int i;
1573
1574 if (!bwfm_sdio_tx_ok(sc))
1575 return;
1576
1577 i = uimin((uint8_t)(sc->sc_tx_max_seq - sc->sc_tx_seq), 32);
1578 while (i--) {
1579 MBUFQ_DEQUEUE(&sc->sc_tx_queue, m);
1580 if (m == NULL)
1581 break;
1582
1583 if (m->m_type == MT_CONTROL)
1584 bwfm_sdio_tx_ctrlframe(sc, m);
1585 else {
1586 bwfm_sdio_tx_dataframe(sc, m);
1587 if_statinc(ifp, if_opackets);
1588 ifstart = true;
1589 }
1590
1591 m_freem(m);
1592 }
1593
1594 if (ifstart) {
1595 ifp->if_flags &= ~IFF_OACTIVE;
1596 if_schedule_deferred_start(ifp);
1597 }
1598 }
1599
1600 static void
bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc * sc,struct mbuf * m)1601 bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *sc, struct mbuf *m)
1602 {
1603 struct bwfm_sdio_hwhdr *hwhdr;
1604 struct bwfm_sdio_swhdr *swhdr;
1605 size_t len, roundto;
1606 int err;
1607
1608 len = sizeof(*hwhdr) + sizeof(*swhdr) + m->m_len;
1609
1610 /* Zero-pad to either block-size or 4-byte alignment. */
1611 if (len > 512 && (len % 512) != 0)
1612 roundto = 512;
1613 else
1614 roundto = 4;
1615
1616 KASSERT(roundup(len, roundto) <= sc->sc_bounce_size);
1617
1618 hwhdr = (void *)sc->sc_bounce_buf;
1619 hwhdr->frmlen = htole16(len);
1620 hwhdr->cksum = htole16(~len);
1621
1622 swhdr = (void *)&hwhdr[1];
1623 swhdr->seqnr = sc->sc_tx_seq++;
1624 swhdr->chanflag = BWFM_SDIO_SWHDR_CHANNEL_CONTROL;
1625 swhdr->nextlen = 0;
1626 swhdr->dataoff = sizeof(*hwhdr) + sizeof(*swhdr);
1627 swhdr->maxseqnr = 0;
1628
1629 m_copydata(m, 0, m->m_len, &swhdr[1]);
1630
1631 if (roundup(len, roundto) != len)
1632 memset(sc->sc_bounce_buf + len, 0,
1633 roundup(len, roundto) - len);
1634
1635 err = bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf,
1636 roundup(len, roundto), 1);
1637
1638 if (err)
1639 printf("%s: error %d\n",__func__,err);
1640 }
1641
1642 static void
bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc * sc,struct mbuf * m)1643 bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *sc, struct mbuf *m)
1644 {
1645 struct bwfm_sdio_hwhdr *hwhdr;
1646 struct bwfm_sdio_swhdr *swhdr;
1647 struct bwfm_proto_bcdc_hdr *bcdc;
1648 size_t len, roundto;
1649 int err;
1650
1651 len = sizeof(*hwhdr) + sizeof(*swhdr) + sizeof(*bcdc)
1652 + m->m_pkthdr.len;
1653
1654 /* Zero-pad to either block-size or 4-byte alignment. */
1655 if (len > 512 && (len % 512) != 0)
1656 roundto = 512;
1657 else
1658 roundto = 4;
1659
1660 KASSERT(roundup(len, roundto) <= sc->sc_bounce_size);
1661
1662 hwhdr = (void *)sc->sc_bounce_buf;
1663 hwhdr->frmlen = htole16(len);
1664 hwhdr->cksum = htole16(~len);
1665
1666 swhdr = (void *)&hwhdr[1];
1667 swhdr->seqnr = sc->sc_tx_seq++;
1668 swhdr->chanflag = BWFM_SDIO_SWHDR_CHANNEL_DATA;
1669 swhdr->nextlen = 0;
1670 swhdr->dataoff = sizeof(*hwhdr) + sizeof(*swhdr);
1671 swhdr->maxseqnr = 0;
1672
1673 bcdc = (void *)&swhdr[1];
1674 bcdc->data_offset = 0;
1675 bcdc->priority = WME_AC_BE;
1676 bcdc->flags = BWFM_BCDC_FLAG_VER(BWFM_BCDC_FLAG_PROTO_VER);
1677 bcdc->flags2 = 0;
1678
1679 m_copydata(m, 0, m->m_pkthdr.len, &bcdc[1]);
1680
1681 if (roundup(len, roundto) != len)
1682 memset(sc->sc_bounce_buf + len, 0,
1683 roundup(len, roundto) - len);
1684
1685 err = bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf,
1686 roundup(len, roundto), 1);
1687
1688 if (err)
1689 printf("%s: error %d\n",__func__,err);
1690
1691 sc->sc_tx_count--;
1692 }
1693
1694 static int
bwfm_sdio_rxctl(struct bwfm_softc * bwfm,char * buf,size_t * lenp)1695 bwfm_sdio_rxctl(struct bwfm_softc *bwfm, char *buf, size_t *lenp)
1696 {
1697 struct bwfm_sdio_softc *sc = (void *)bwfm;
1698 struct mbuf *m;
1699 int err = 0;
1700
1701 mutex_enter(&sc->sc_lock);
1702 while ((m = bwfm_qget(&sc->sc_rxctl_queue)) == NULL) {
1703 err = cv_timedwait(&sc->sc_rxctl_cv, &sc->sc_lock,
1704 mstohz(5000));
1705 if (err == EWOULDBLOCK)
1706 break;
1707 }
1708 mutex_exit(&sc->sc_lock);
1709
1710 if (err)
1711 return 1;
1712
1713 if (m->m_len > *lenp) {
1714 m_freem(m);
1715 return 1;
1716 }
1717
1718 *lenp = m->m_len;
1719 m_copydata(m, 0, m->m_len, buf);
1720 m_freem(m);
1721 return 0;
1722 }
1723
1724 static void
bwfm_sdio_rx_frames(struct bwfm_sdio_softc * sc)1725 bwfm_sdio_rx_frames(struct bwfm_sdio_softc *sc)
1726 {
1727 struct bwfm_sdio_hwhdr *hwhdr;
1728 struct bwfm_sdio_swhdr *swhdr;
1729 struct bwfm_proto_bcdc_hdr *bcdc;
1730 uint16_t *sublen, nextlen = 0;
1731 struct mbuf *m;
1732 size_t flen, off, hoff;
1733 char *data;
1734 int nsub;
1735 size_t subsize, len;
1736 const size_t hdrlen = sizeof(*hwhdr) + sizeof(*swhdr);
1737
1738 hwhdr = (struct bwfm_sdio_hwhdr *)sc->sc_bounce_buf;
1739 swhdr = (struct bwfm_sdio_swhdr *)&hwhdr[1];
1740 data = (char *)&swhdr[1];
1741
1742 for (;;) {
1743 /* If we know the next size, just read ahead. */
1744 if (nextlen) {
1745 len = nextlen;
1746 nextlen = 0;
1747 } else {
1748 len = hdrlen;
1749 }
1750
1751 if (bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf,
1752 len, 0)) {
1753 printf("%s: read error %zu bytes\n",
1754 DEVNAME(sc), len);
1755 break;
1756 }
1757
1758 hwhdr->frmlen = le16toh(hwhdr->frmlen);
1759 hwhdr->cksum = le16toh(hwhdr->cksum);
1760
1761 if (hwhdr->frmlen == 0 && hwhdr->cksum == 0) {
1762 /* printf("%s: null frame\n", DEVNAME(sc)); */
1763 break;
1764 }
1765
1766 if ((hwhdr->frmlen ^ hwhdr->cksum) != 0xffff) {
1767 printf("%s: checksum error\n", DEVNAME(sc));
1768 break;
1769 }
1770
1771 if (hwhdr->frmlen < hdrlen) {
1772 printf("%s: length error\n", DEVNAME(sc));
1773 break;
1774 }
1775
1776 if (len > hdrlen && hwhdr->frmlen > len) {
1777 printf("%s: length error (%u > %u)\n",
1778 DEVNAME(sc), hwhdr->frmlen, nextlen);
1779 break;
1780 }
1781
1782 sc->sc_tx_max_seq = swhdr->maxseqnr;
1783
1784 flen = hwhdr->frmlen - hdrlen;
1785 if (flen == 0) {
1786 DPRINTF(("%s: empty payload (frmlen=%u)\n",
1787 DEVNAME(sc), hwhdr->frmlen));
1788 nextlen = swhdr->nextlen << 4;
1789 continue;
1790 }
1791
1792 if (len <= hdrlen) {
1793 KASSERT(roundup(flen, 4) <= sc->sc_bounce_size -
1794 (sizeof(*hwhdr) + sizeof(*swhdr)));
1795 if (bwfm_sdio_frame_read_write(sc, data,
1796 roundup(flen, 4), 0)) {
1797 printf("%s: read error roundup(%zu, 4) bytes\n",
1798 DEVNAME(sc), flen);
1799 break;
1800 }
1801 }
1802
1803 if (swhdr->dataoff < hdrlen) {
1804 printf("%s: data offset %u in header\n",
1805 DEVNAME(sc), swhdr->dataoff);
1806 break;
1807 }
1808
1809 off = swhdr->dataoff - hdrlen;
1810 if (off > flen) {
1811 printf("%s: offset %zu beyond end %zu\n",
1812 DEVNAME(sc), off, flen);
1813 break;
1814 }
1815
1816 switch (swhdr->chanflag & BWFM_SDIO_SWHDR_CHANNEL_MASK) {
1817 case BWFM_SDIO_SWHDR_CHANNEL_CONTROL:
1818 m = bwfm_sdio_newbuf();
1819 if (m == NULL) {
1820 printf("%s: channel control: no buffer\n",
1821 DEVNAME(sc));
1822 break;
1823 }
1824 if (flen - off > m->m_len) {
1825 printf("%s: ctl bigger than anticipated\n",
1826 DEVNAME(sc));
1827 m_freem(m);
1828 break;
1829 }
1830 m->m_len = m->m_pkthdr.len = flen - off;
1831 memcpy(mtod(m, char *), data + off, flen - off);
1832 bwfm_qput(&sc->sc_rxctl_queue, m);
1833 cv_broadcast(&sc->sc_rxctl_cv);
1834 nextlen = swhdr->nextlen << 4;
1835 break;
1836 case BWFM_SDIO_SWHDR_CHANNEL_EVENT:
1837 case BWFM_SDIO_SWHDR_CHANNEL_DATA:
1838 m = bwfm_sdio_newbuf();
1839 if (m == NULL) {
1840 printf("%s: channel data: no buffer\n",
1841 DEVNAME(sc));
1842 break;
1843 }
1844 if (flen - off > m->m_len) {
1845 printf("%s: frame bigger than anticipated\n",
1846 DEVNAME(sc));
1847 m_freem(m);
1848 break;
1849 }
1850 m->m_len = m->m_pkthdr.len = flen - off;
1851 memcpy(mtod(m, char *), data + off, flen - off);
1852 bcdc = mtod(m, struct bwfm_proto_bcdc_hdr *);
1853 hoff = sizeof(*bcdc) + ((size_t)bcdc->data_offset << 2);
1854 if (m->m_len < hoff) {
1855 printf("%s: short bcdc packet %d < %zu\n",
1856 DEVNAME(sc), m->m_len, hoff);
1857 m_freem(m);
1858 break;
1859 }
1860 m_adj(m, hoff);
1861 /* don't pass empty packet to stack */
1862 if (m->m_len > 0)
1863 bwfm_rx(&sc->sc_sc, m);
1864 else
1865 m_freem(m);
1866 nextlen = swhdr->nextlen << 4;
1867 break;
1868 case BWFM_SDIO_SWHDR_CHANNEL_GLOM:
1869 if ((flen % sizeof(uint16_t)) != 0) {
1870 printf("%s: odd length (%zu) glom table\n",
1871 DEVNAME(sc), flen);
1872 break;
1873 }
1874 nsub = flen / sizeof(uint16_t);
1875 subsize = nsub * sizeof(uint16_t);
1876 sublen = NULL;
1877 nextlen = 0;
1878 if (subsize > 0)
1879 sublen = kmem_zalloc(subsize, KM_NOSLEEP);
1880 if (sublen != NULL) {
1881 memcpy(sublen, data, subsize);
1882 bwfm_sdio_rx_glom(sc, sublen, nsub, &nextlen);
1883 kmem_free(sublen, subsize);
1884 }
1885 break;
1886 default:
1887 printf("%s: unknown channel\n", DEVNAME(sc));
1888 break;
1889 }
1890 }
1891 }
1892
1893 static void
bwfm_sdio_rx_glom(struct bwfm_sdio_softc * sc,uint16_t * sublen,int nsub,uint16_t * nextlen)1894 bwfm_sdio_rx_glom(struct bwfm_sdio_softc *sc, uint16_t *sublen, int nsub,
1895 uint16_t *nextlen)
1896 {
1897 struct bwfm_sdio_hwhdr hwhdr;
1898 struct bwfm_sdio_swhdr swhdr;
1899 struct bwfm_proto_bcdc_hdr *bcdc;
1900 struct mbuf *m, *m0;
1901 size_t flen, off, hoff;
1902 int i;
1903 const size_t hdrlen = sizeof(hwhdr) + sizeof(swhdr);
1904
1905 if (nsub == 0) {
1906 printf("%s: rx_glom nsub == 0\n", DEVNAME(sc));
1907 return;
1908 }
1909
1910 m0 = NULL;
1911 for (i = 0; i < nsub; i++) {
1912 m = bwfm_sdio_newbuf();
1913 if (m == NULL) {
1914 printf("%s: rx_glom no buffer\n", DEVNAME(sc));
1915 m_freem(m0);
1916 return;
1917 }
1918 bwfm_qput(&m0, m);
1919 if (le16toh(sublen[i]) > m->m_len) {
1920 m_freem(m0);
1921 printf("%s: header larger than mbuf\n", DEVNAME(sc));
1922 return;
1923 }
1924 if (bwfm_sdio_frame_read_write(sc, mtod(m, char *),
1925 le16toh(sublen[i]), 0)) {
1926 m_freem(m0);
1927 printf("%s: frame I/O error\n", DEVNAME(sc));
1928 return;
1929 }
1930 m->m_len = m->m_pkthdr.len = le16toh(sublen[i]);
1931 }
1932
1933 if (m0->m_len >= hdrlen) {
1934 m_copydata(m0, 0, sizeof(hwhdr), &hwhdr);
1935 m_copydata(m0, sizeof(hwhdr), sizeof(swhdr), &swhdr);
1936
1937 /* TODO: Verify actual superframe header */
1938
1939 /* remove superframe header */
1940 if (m0->m_len >= swhdr.dataoff)
1941 m_adj(m0, swhdr.dataoff);
1942 }
1943
1944 *nextlen = 0;
1945 while ((m = bwfm_qget(&m0)) != NULL) {
1946 if (m->m_len < hdrlen) {
1947 printf("%s: tiny mbuf %d < %zu\n", DEVNAME(sc),
1948 m->m_len, sizeof(hwhdr) + sizeof(swhdr));
1949 goto drop;
1950 }
1951
1952 m_copydata(m, 0, sizeof(hwhdr), &hwhdr);
1953 m_copydata(m, sizeof(hwhdr), sizeof(swhdr), &swhdr);
1954
1955 hwhdr.frmlen = le16toh(hwhdr.frmlen);
1956 hwhdr.cksum = le16toh(hwhdr.cksum);
1957
1958 if (hwhdr.frmlen == 0 && hwhdr.cksum == 0) {
1959 printf("%s: rx_glom null frame\n", DEVNAME(sc));
1960 goto drop;
1961 }
1962
1963 if ((hwhdr.frmlen ^ hwhdr.cksum) != 0xffff) {
1964 printf("%s: checksum error\n", DEVNAME(sc));
1965 goto drop;
1966 }
1967
1968 if (hwhdr.frmlen < hdrlen) {
1969 printf("%s: length error\n", DEVNAME(sc));
1970 goto drop;
1971 }
1972
1973 flen = hwhdr.frmlen - hdrlen;
1974 if (flen == 0) {
1975 printf("%s: rx_glom empty payload\n", DEVNAME(sc));
1976 goto drop;
1977 }
1978
1979 if (hwhdr.frmlen > m->m_len) {
1980 printf("%s: short mbuf %d < %zu\n",
1981 DEVNAME(sc),m->m_len,flen);
1982 goto drop;
1983 }
1984
1985 if (swhdr.dataoff < hdrlen) {
1986 printf("%s: data offset %u in header\n",
1987 DEVNAME(sc), swhdr.dataoff);
1988 goto drop;
1989 }
1990
1991 off = swhdr.dataoff - hdrlen;
1992 if (off > flen) {
1993 printf("%s: offset %zu beyond end %zu\n",
1994 DEVNAME(sc), off, flen);
1995 goto drop;
1996 }
1997
1998 m_adj(m, (int)hwhdr.frmlen - m->m_len);
1999 *nextlen = swhdr.nextlen << 4;
2000
2001 switch (swhdr.chanflag & BWFM_SDIO_SWHDR_CHANNEL_MASK) {
2002 case BWFM_SDIO_SWHDR_CHANNEL_CONTROL:
2003 printf("%s: control channel not allowed in glom\n",
2004 DEVNAME(sc));
2005 goto drop;
2006 case BWFM_SDIO_SWHDR_CHANNEL_EVENT:
2007 case BWFM_SDIO_SWHDR_CHANNEL_DATA:
2008 m_adj(m, swhdr.dataoff);
2009 bcdc = mtod(m, struct bwfm_proto_bcdc_hdr *);
2010 hoff = sizeof(*bcdc) + ((size_t)bcdc->data_offset << 2);
2011 if (m->m_len < hoff) {
2012 printf("%s: short bcdc packet %d < %zu\n",
2013 DEVNAME(sc), m->m_len, hoff);
2014 m_freem(m);
2015 break;
2016 }
2017 m_adj(m, hoff);
2018 /* don't pass empty packet to stack */
2019 if (m->m_len == 0) {
2020 printf("%s: rx_glom empty packet\n", DEVNAME(sc));
2021 m_freem(m);
2022 break;
2023 }
2024 bwfm_rx(&sc->sc_sc, m);
2025 break;
2026 case BWFM_SDIO_SWHDR_CHANNEL_GLOM:
2027 printf("%s: glom not allowed in glom\n",
2028 DEVNAME(sc));
2029 goto drop;
2030 default:
2031 printf("%s: unknown channel\n", DEVNAME(sc));
2032 goto drop;
2033 }
2034
2035 continue;
2036 drop:
2037 printf("rx dropped %p len %d\n",mtod(m, char *),m->m_pkthdr.len);
2038 m_free(m);
2039 break;
2040 }
2041 }
2042
2043 #ifdef BWFM_DEBUG
2044 static void
bwfm_sdio_debug_console(struct bwfm_sdio_softc * sc)2045 bwfm_sdio_debug_console(struct bwfm_sdio_softc *sc)
2046 {
2047 struct bwfm_sdio_console c;
2048 uint32_t newidx;
2049 int err;
2050
2051 if (!sc->sc_console_addr)
2052 return;
2053
2054 err = bwfm_sdio_ram_read_write(sc, sc->sc_console_addr,
2055 (char *)&c, sizeof(c), 0);
2056 if (err)
2057 return;
2058
2059 c.log_buf = le32toh(c.log_buf);
2060 c.log_bufsz = le32toh(c.log_bufsz);
2061 c.log_idx = le32toh(c.log_idx);
2062
2063 if (sc->sc_console_buf == NULL) {
2064 sc->sc_console_buf = malloc(c.log_bufsz, M_DEVBUF,
2065 M_WAITOK|M_ZERO);
2066 sc->sc_console_buf_size = c.log_bufsz;
2067 }
2068
2069 newidx = c.log_idx;
2070 if (newidx >= sc->sc_console_buf_size)
2071 return;
2072
2073 err = bwfm_sdio_ram_read_write(sc, c.log_buf, sc->sc_console_buf,
2074 sc->sc_console_buf_size, 0);
2075 if (err)
2076 return;
2077
2078 if (newidx != sc->sc_console_readidx)
2079 DPRINTFN(3, ("BWFM CONSOLE: "));
2080 while (newidx != sc->sc_console_readidx) {
2081 uint8_t ch = sc->sc_console_buf[sc->sc_console_readidx];
2082 sc->sc_console_readidx++;
2083 if (sc->sc_console_readidx == sc->sc_console_buf_size)
2084 sc->sc_console_readidx = 0;
2085 if (ch == '\r')
2086 continue;
2087 DPRINTFN(3, ("%c", ch));
2088 }
2089 }
2090 #endif
2091