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