LCOV - code coverage report
Current view: top level - dev/sdmmc - if_bwfm_sdio.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 639 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 35 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* $OpenBSD: if_bwfm_sdio.c,v 1.25 2018/08/09 14:23:50 patrick Exp $ */
       2             : /*
       3             :  * Copyright (c) 2010-2016 Broadcom Corporation
       4             :  * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
       5             :  *
       6             :  * Permission to use, copy, modify, and/or distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : #include "bpfilter.h"
      20             : 
      21             : #include <sys/param.h>
      22             : #include <sys/systm.h>
      23             : #include <sys/buf.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/pool.h>
      30             : 
      31             : #if defined(__HAVE_FDT)
      32             : #include <machine/fdt.h>
      33             : #endif
      34             : 
      35             : #if NBPFILTER > 0
      36             : #include <net/bpf.h>
      37             : #endif
      38             : #include <net/if.h>
      39             : #include <net/if_dl.h>
      40             : #include <net/if_media.h>
      41             : 
      42             : #include <netinet/in.h>
      43             : #include <netinet/if_ether.h>
      44             : 
      45             : #include <net80211/ieee80211_var.h>
      46             : 
      47             : #include <dev/sdmmc/sdmmcvar.h>
      48             : 
      49             : #include <dev/ic/bwfmvar.h>
      50             : #include <dev/ic/bwfmreg.h>
      51             : #include <dev/sdmmc/if_bwfm_sdio.h>
      52             : 
      53             : #define BWFM_SDIO_CCCR_BRCM_CARDCAP                     0xf0
      54             : #define  BWFM_SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT      0x02
      55             : #define  BWFM_SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT          0x04
      56             : #define  BWFM_SDIO_CCCR_BRCM_CARDCAP_CMD_NODEC          0x08
      57             : #define BWFM_SDIO_CCCR_BRCM_CARDCTRL                    0xf1
      58             : #define  BWFM_SDIO_CCCR_BRCM_CARDCTRL_WLANRESET         0x02
      59             : #define BWFM_SDIO_CCCR_BRCM_SEPINT                      0xf2
      60             : 
      61             : /* #define BWFM_DEBUG */
      62             : #ifdef BWFM_DEBUG
      63             : #define DPRINTF(x)      do { if (bwfm_debug > 0) printf x; } while (0)
      64             : #define DPRINTFN(n, x)  do { if (bwfm_debug >= (n)) printf x; } while (0)
      65             : static int bwfm_debug = 1;
      66             : #else
      67             : #define DPRINTF(x)      do { ; } while (0)
      68             : #define DPRINTFN(n, x)  do { ; } while (0)
      69             : #endif
      70             : 
      71             : #undef DEVNAME
      72             : #define DEVNAME(sc)     ((sc)->sc_sc.sc_dev.dv_xname)
      73             : 
      74             : enum bwfm_sdio_clkstate {
      75             :         CLK_NONE,
      76             :         CLK_SDONLY,
      77             :         CLK_PENDING,
      78             :         CLK_AVAIL,
      79             : };
      80             : 
      81             : struct bwfm_sdio_softc {
      82             :         struct bwfm_softc         sc_sc;
      83             :         struct sdmmc_function   **sc_sf;
      84             :         struct rwlock            *sc_lock;
      85             :         void                     *sc_ih;
      86             :         int                       sc_node;
      87             :         int                       sc_oob;
      88             : 
      89             :         int                       sc_initialized;
      90             : 
      91             :         uint32_t                  sc_bar0;
      92             :         int                       sc_clkstate;
      93             :         int                       sc_alp_only;
      94             :         int                       sc_sr_enabled;
      95             :         uint32_t                  sc_console_addr;
      96             : 
      97             :         char                     *sc_bounce_buf;
      98             :         size_t                    sc_bounce_size;
      99             : 
     100             :         char                     *sc_console_buf;
     101             :         size_t                    sc_console_buf_size;
     102             :         uint32_t                  sc_console_readidx;
     103             : 
     104             :         struct bwfm_core         *sc_cc;
     105             : 
     106             :         uint8_t                   sc_tx_seq;
     107             :         uint8_t                   sc_tx_max_seq;
     108             :         struct mbuf_list          sc_tx_queue;
     109             :         int                       sc_tx_count;
     110             : 
     111             :         struct task               sc_task;
     112             : };
     113             : 
     114             : int              bwfm_sdio_match(struct device *, void *, void *);
     115             : void             bwfm_sdio_attach(struct device *, struct device *, void *);
     116             : int              bwfm_sdio_preinit(struct bwfm_softc *);
     117             : int              bwfm_sdio_detach(struct device *, int);
     118             : 
     119             : int              bwfm_sdio_intr(void *);
     120             : int              bwfm_sdio_oob_intr(void *);
     121             : void             bwfm_sdio_task(void *);
     122             : int              bwfm_sdio_load_microcode(struct bwfm_sdio_softc *,
     123             :                     u_char *, size_t, u_char *, size_t);
     124             : 
     125             : void             bwfm_sdio_clkctl(struct bwfm_sdio_softc *,
     126             :                     enum bwfm_sdio_clkstate, int);
     127             : void             bwfm_sdio_htclk(struct bwfm_sdio_softc *, int, int);
     128             : void             bwfm_sdio_readshared(struct bwfm_sdio_softc *);
     129             : 
     130             : void             bwfm_sdio_backplane(struct bwfm_sdio_softc *, uint32_t);
     131             : uint8_t          bwfm_sdio_read_1(struct bwfm_sdio_softc *, uint32_t);
     132             : uint32_t         bwfm_sdio_read_4(struct bwfm_sdio_softc *, uint32_t);
     133             : void             bwfm_sdio_write_1(struct bwfm_sdio_softc *, uint32_t,
     134             :                     uint8_t);
     135             : void             bwfm_sdio_write_4(struct bwfm_sdio_softc *, uint32_t,
     136             :                     uint32_t);
     137             : int              bwfm_sdio_buf_read(struct bwfm_sdio_softc *,
     138             :                     struct sdmmc_function *, uint32_t, char *, size_t);
     139             : int              bwfm_sdio_buf_write(struct bwfm_sdio_softc *,
     140             :                     struct sdmmc_function *, uint32_t, char *, size_t);
     141             : uint32_t         bwfm_sdio_ram_read_write(struct bwfm_sdio_softc *,
     142             :                     uint32_t, char *, size_t, int);
     143             : uint32_t         bwfm_sdio_frame_read_write(struct bwfm_sdio_softc *,
     144             :                     char *, size_t, int);
     145             : 
     146             : uint32_t         bwfm_sdio_dev_read(struct bwfm_sdio_softc *, uint32_t);
     147             : void             bwfm_sdio_dev_write(struct bwfm_sdio_softc *, uint32_t,
     148             :                     uint32_t);
     149             : 
     150             : uint32_t         bwfm_sdio_buscore_read(struct bwfm_softc *, uint32_t);
     151             : void             bwfm_sdio_buscore_write(struct bwfm_softc *, uint32_t,
     152             :                     uint32_t);
     153             : int              bwfm_sdio_buscore_prepare(struct bwfm_softc *);
     154             : void             bwfm_sdio_buscore_activate(struct bwfm_softc *, uint32_t);
     155             : 
     156             : struct mbuf *    bwfm_sdio_newbuf(void);
     157             : int              bwfm_sdio_tx_ok(struct bwfm_sdio_softc *);
     158             : void             bwfm_sdio_tx_frames(struct bwfm_sdio_softc *);
     159             : void             bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *, struct mbuf *);
     160             : void             bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *, struct mbuf *);
     161             : void             bwfm_sdio_rx_frames(struct bwfm_sdio_softc *);
     162             : void             bwfm_sdio_rx_glom(struct bwfm_sdio_softc *, uint16_t *, int,
     163             :                     uint16_t *);
     164             : 
     165             : int              bwfm_sdio_txcheck(struct bwfm_softc *);
     166             : int              bwfm_sdio_txdata(struct bwfm_softc *, struct mbuf *);
     167             : int              bwfm_sdio_txctl(struct bwfm_softc *, void *);
     168             : 
     169             : #ifdef BWFM_DEBUG
     170             : void             bwfm_sdio_debug_console(struct bwfm_sdio_softc *);
     171             : #endif
     172             : 
     173             : struct bwfm_bus_ops bwfm_sdio_bus_ops = {
     174             :         .bs_preinit = bwfm_sdio_preinit,
     175             :         .bs_stop = NULL,
     176             :         .bs_txcheck = bwfm_sdio_txcheck,
     177             :         .bs_txdata = bwfm_sdio_txdata,
     178             :         .bs_txctl = bwfm_sdio_txctl,
     179             : };
     180             : 
     181             : struct bwfm_buscore_ops bwfm_sdio_buscore_ops = {
     182             :         .bc_read = bwfm_sdio_buscore_read,
     183             :         .bc_write = bwfm_sdio_buscore_write,
     184             :         .bc_prepare = bwfm_sdio_buscore_prepare,
     185             :         .bc_reset = NULL,
     186             :         .bc_setup = NULL,
     187             :         .bc_activate = bwfm_sdio_buscore_activate,
     188             : };
     189             : 
     190             : struct cfattach bwfm_sdio_ca = {
     191             :         sizeof(struct bwfm_sdio_softc),
     192             :         bwfm_sdio_match,
     193             :         bwfm_sdio_attach,
     194             :         bwfm_sdio_detach,
     195             : };
     196             : 
     197             : int
     198           0 : bwfm_sdio_match(struct device *parent, void *match, void *aux)
     199             : {
     200           0 :         struct sdmmc_attach_args *saa = aux;
     201           0 :         struct sdmmc_function *sf = saa->sf;
     202             :         struct sdmmc_cis *cis;
     203             : 
     204             :         /* Not SDIO. */
     205           0 :         if (sf == NULL)
     206           0 :                 return 0;
     207             : 
     208             :         /* Look for Broadcom. */
     209           0 :         cis = &sf->sc->sc_fn0->cis;
     210           0 :         if (cis->manufacturer != 0x02d0)
     211           0 :                 return 0;
     212             : 
     213             :         /* Look for supported chips. */
     214           0 :         switch (cis->product) {
     215             :         case 0x4324:
     216             :         case 0x4330:
     217             :         case 0x4334:
     218             :         case 0x4329:
     219             :         case 0x4335:
     220             :         case 0x4339:
     221             :         case 0x4345:
     222             :         case 0x4354:
     223             :         case 0x4356:
     224             :         case 0xa887:
     225             :         case 0xa94c:
     226             :         case 0xa94d:
     227             :         case 0xa962:
     228             :         case 0xa9a6:
     229             :         case 0xa9bf:
     230             :                 break;
     231             :         default:
     232           0 :                 return 0;
     233             :         }
     234             : 
     235             :         /* We need both functions, but ... */
     236           0 :         if (sf->sc->sc_function_count <= 1)
     237           0 :                 return 0;
     238             : 
     239             :         /* ... only attach for one. */
     240           0 :         if (sf->number != 1)
     241           0 :                 return 0;
     242             : 
     243           0 :         return 1;
     244           0 : }
     245             : 
     246             : void
     247           0 : bwfm_sdio_attach(struct device *parent, struct device *self, void *aux)
     248             : {
     249           0 :         struct bwfm_sdio_softc *sc = (struct bwfm_sdio_softc *)self;
     250           0 :         struct sdmmc_attach_args *saa = aux;
     251           0 :         struct sdmmc_function *sf = saa->sf;
     252             :         struct bwfm_core *core;
     253             :         uint32_t reg;
     254             : 
     255           0 :         printf("\n");
     256             : 
     257             : #if defined(__HAVE_FDT)
     258             :         if (sf->cookie)
     259             :                 sc->sc_node = *(int *)sf->cookie;
     260             : #endif
     261             : 
     262           0 :         task_set(&sc->sc_task, bwfm_sdio_task, sc);
     263           0 :         ml_init(&sc->sc_tx_queue);
     264           0 :         sc->sc_bounce_size = 64 * 1024;
     265           0 :         sc->sc_bounce_buf = dma_alloc(sc->sc_bounce_size, PR_WAITOK);
     266           0 :         sc->sc_tx_seq = 0xff;
     267             : 
     268           0 :         rw_assert_wrlock(&sf->sc->sc_lock);
     269           0 :         sc->sc_lock = &sf->sc->sc_lock;
     270             : 
     271           0 :         sc->sc_sf = mallocarray(sf->sc->sc_function_count + 1,
     272             :             sizeof(struct sdmmc_function *), M_DEVBUF, M_WAITOK);
     273             : 
     274             :         /* Copy all function pointers. */
     275           0 :         SIMPLEQ_FOREACH(sf, &saa->sf->sc->sf_head, sf_list) {
     276           0 :                 sc->sc_sf[sf->number] = sf;
     277             :         }
     278             :         sf = saa->sf;
     279             : 
     280           0 :         sdmmc_io_set_blocklen(sc->sc_sf[1], 64);
     281           0 :         sdmmc_io_set_blocklen(sc->sc_sf[2], 512);
     282             : 
     283             :         /* Enable Function 1. */
     284           0 :         if (sdmmc_io_function_enable(sc->sc_sf[1]) != 0) {
     285           0 :                 printf("%s: cannot enable function 1\n", DEVNAME(sc));
     286           0 :                 goto err;
     287             :         }
     288             : 
     289             :         DPRINTF(("%s: F1 signature read @0x18000000=%x\n", DEVNAME(sc),
     290             :             bwfm_sdio_read_4(sc, 0x18000000)));
     291             : 
     292             :         /* Force PLL off */
     293           0 :         bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR,
     294             :             BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF |
     295             :             BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ);
     296             : 
     297           0 :         sc->sc_sc.sc_buscore_ops = &bwfm_sdio_buscore_ops;
     298           0 :         if (bwfm_chip_attach(&sc->sc_sc) != 0) {
     299           0 :                 printf("%s: cannot attach chip\n", DEVNAME(sc));
     300           0 :                 goto err;
     301             :         }
     302             : 
     303           0 :         sc->sc_cc = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_CHIPCOMMON);
     304           0 :         if (sc->sc_cc == NULL) {
     305           0 :                 printf("%s: cannot find chipcommon core\n", DEVNAME(sc));
     306           0 :                 goto err;
     307             :         }
     308             : 
     309           0 :         core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV);
     310           0 :         if (core->co_rev >= 12) {
     311           0 :                 reg = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_SLEEPCSR);
     312           0 :                 if (!(reg & BWFM_SDIO_FUNC1_SLEEPCSR_KSO)) {
     313           0 :                         reg |= BWFM_SDIO_FUNC1_SLEEPCSR_KSO;
     314           0 :                         bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SLEEPCSR, reg);
     315           0 :                 }
     316             :         }
     317             : 
     318             :         /* TODO: drive strength */
     319             : 
     320           0 :         bwfm_sdio_write_1(sc, BWFM_SDIO_CCCR_BRCM_CARDCTRL,
     321           0 :             bwfm_sdio_read_1(sc, BWFM_SDIO_CCCR_BRCM_CARDCTRL) |
     322             :             BWFM_SDIO_CCCR_BRCM_CARDCTRL_WLANRESET);
     323             : 
     324           0 :         core = bwfm_chip_get_pmu(&sc->sc_sc);
     325           0 :         bwfm_sdio_write_4(sc, core->co_base + BWFM_CHIP_REG_PMUCONTROL,
     326           0 :             bwfm_sdio_read_4(sc, core->co_base + BWFM_CHIP_REG_PMUCONTROL) |
     327             :             (BWFM_CHIP_REG_PMUCONTROL_RES_RELOAD <<
     328             :              BWFM_CHIP_REG_PMUCONTROL_RES_SHIFT));
     329             : 
     330           0 :         sdmmc_io_function_disable(sc->sc_sf[2]);
     331             : 
     332           0 :         bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, 0);
     333           0 :         sc->sc_clkstate = CLK_SDONLY;
     334             : 
     335           0 :         sc->sc_sc.sc_bus_ops = &bwfm_sdio_bus_ops;
     336           0 :         sc->sc_sc.sc_proto_ops = &bwfm_proto_bcdc_ops;
     337           0 :         bwfm_attach(&sc->sc_sc);
     338           0 :         config_mountroot(self, bwfm_attachhook);
     339           0 :         return;
     340             : 
     341             : err:
     342           0 :         free(sc->sc_sf, M_DEVBUF, 0);
     343           0 : }
     344             : 
     345             : int
     346           0 : bwfm_sdio_preinit(struct bwfm_softc *bwfm)
     347             : {
     348           0 :         struct bwfm_sdio_softc *sc = (void *)bwfm;
     349             :         const char *name = NULL;
     350             :         const char *nvname = NULL;
     351             :         uint32_t clk, reg;
     352           0 :         u_char *ucode, *nvram;
     353           0 :         size_t size, nvlen;
     354             : 
     355           0 :         if (sc->sc_initialized)
     356           0 :                 return 0;
     357             : 
     358           0 :         rw_enter_write(sc->sc_lock);
     359             : 
     360           0 :         switch (bwfm->sc_chip.ch_chip)
     361             :         {
     362             :         case BRCM_CC_4330_CHIP_ID:
     363             :                 name = "brcmfmac4330-sdio.bin";
     364             :                 nvname = "brcmfmac4330-sdio.nvram";
     365           0 :                 break;
     366             :         case BRCM_CC_4334_CHIP_ID:
     367             :                 name = "brcmfmac4334-sdio.bin";
     368             :                 nvname = "brcmfmac4334-sdio.nvram";
     369           0 :                 break;
     370             :         case BRCM_CC_4345_CHIP_ID:
     371             :                 name = "brcmfmac43455-sdio.bin";
     372             :                 nvname = "brcmfmac43455-sdio.nvram";
     373           0 :                 break;
     374             :         case BRCM_CC_43340_CHIP_ID:
     375             :                 name = "brcmfmac43340-sdio.bin";
     376             :                 nvname = "brcmfmac43340-sdio.nvram";
     377           0 :                 break;
     378             :         case BRCM_CC_4335_CHIP_ID:
     379           0 :                 if (bwfm->sc_chip.ch_chiprev < 2) {
     380             :                         name = "brcmfmac4335-sdio.bin";
     381             :                         nvname = "brcmfmac4335-sdio.nvram";
     382           0 :                 } else {
     383             :                         name = "brcmfmac4339-sdio.bin";
     384             :                         nvname = "brcmfmac4339-sdio.nvram";
     385             :                 }
     386             :                 break;
     387             :         case BRCM_CC_4339_CHIP_ID:
     388             :                 name = "brcmfmac4339-sdio.bin";
     389             :                 nvname = "brcmfmac4339-sdio.nvram";
     390           0 :                 break;
     391             :         case BRCM_CC_43430_CHIP_ID:
     392           0 :                 if (bwfm->sc_chip.ch_chiprev == 0) {
     393             :                         name = "brcmfmac43430a0-sdio.bin";
     394             :                         nvname = "brcmfmac43430a0-sdio.nvram";
     395           0 :                 } else {
     396             :                         name = "brcmfmac43430-sdio.bin";
     397             :                         nvname = "brcmfmac43430-sdio.nvram";
     398             :                 }
     399             :                 break;
     400             :         case BRCM_CC_4356_CHIP_ID:
     401             :                 name = "brcmfmac4356-sdio.bin";
     402             :                 nvname = "brcmfmac4356-sdio.nvram";
     403           0 :                 break;
     404             :         default:
     405           0 :                 printf("%s: unknown firmware for chip %s\n",
     406           0 :                     DEVNAME(sc), bwfm->sc_chip.ch_name);
     407           0 :                 goto err;
     408             :         }
     409             : 
     410           0 :         if (loadfirmware(name, &ucode, &size) != 0) {
     411           0 :                 printf("%s: failed loadfirmware of file %s\n",
     412           0 :                     DEVNAME(sc), name);
     413           0 :                 goto err;
     414             :         }
     415             : 
     416           0 :         if (loadfirmware(nvname, &nvram, &nvlen) != 0) {
     417           0 :                 printf("%s: failed loadfirmware of file %s\n",
     418           0 :                     DEVNAME(sc), nvname);
     419           0 :                 free(ucode, M_DEVBUF, size);
     420           0 :                 goto err;
     421             :         }
     422             : 
     423           0 :         sc->sc_alp_only = 1;
     424           0 :         if (bwfm_sdio_load_microcode(sc, ucode, size,
     425           0 :             nvram, nvlen) != 0) {
     426           0 :                 printf("%s: could not load microcode\n",
     427           0 :                     DEVNAME(sc));
     428           0 :                 free(ucode, M_DEVBUF, size);
     429           0 :                 free(nvram, M_DEVBUF, nvlen);
     430           0 :                 goto err;
     431             :         }
     432           0 :         sc->sc_alp_only = 0;
     433           0 :         free(ucode, M_DEVBUF, size);
     434           0 :         free(nvram, M_DEVBUF, nvlen);
     435             : 
     436           0 :         bwfm_sdio_clkctl(sc, CLK_AVAIL, 0);
     437           0 :         if (sc->sc_clkstate != CLK_AVAIL)
     438             :                 goto err;
     439             : 
     440           0 :         clk = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR);
     441           0 :         bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR,
     442           0 :             clk | BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HT);
     443             : 
     444           0 :         bwfm_sdio_dev_write(sc, SDPCMD_TOSBMAILBOXDATA,
     445             :             SDPCM_PROT_VERSION << SDPCM_PROT_VERSION_SHIFT);
     446           0 :         if (sdmmc_io_function_enable(sc->sc_sf[2]) != 0) {
     447           0 :                 printf("%s: cannot enable function 2\n", DEVNAME(sc));
     448           0 :                 goto err;
     449             :         }
     450             : 
     451           0 :         bwfm_sdio_dev_write(sc, SDPCMD_HOSTINTMASK,
     452             :             SDPCMD_INTSTATUS_HMB_SW_MASK|SDPCMD_INTSTATUS_CHIPACTIVE);
     453           0 :         bwfm_sdio_write_1(sc, BWFM_SDIO_WATERMARK, 8);
     454             : 
     455           0 :         if (bwfm_chip_sr_capable(bwfm)) {
     456           0 :                 reg = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_WAKEUPCTRL);
     457           0 :                 reg |= BWFM_SDIO_FUNC1_WAKEUPCTRL_HTWAIT;
     458           0 :                 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_WAKEUPCTRL, reg);
     459           0 :                 bwfm_sdio_write_1(sc, BWFM_SDIO_CCCR_CARDCAP,
     460             :                     BWFM_SDIO_CCCR_CARDCAP_CMD14_SUPPORT |
     461             :                     BWFM_SDIO_CCCR_CARDCAP_CMD14_EXT);
     462           0 :                 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR,
     463             :                     BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HT);
     464           0 :                 sc->sc_sr_enabled = 1;
     465           0 :         } else {
     466           0 :                 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clk);
     467             :         }
     468             : 
     469             : #if defined(__HAVE_FDT)
     470             :         if (sc->sc_node) {
     471             :                 sc->sc_ih = fdt_intr_establish(sc->sc_node,
     472             :                     IPL_NET, bwfm_sdio_oob_intr, sc, DEVNAME(sc));
     473             :                 if (sc->sc_ih != NULL) {
     474             :                         bwfm_sdio_write_1(sc, BWFM_SDIO_CCCR_SEPINT,
     475             :                             BWFM_SDIO_CCCR_SEPINT_MASK |
     476             :                             BWFM_SDIO_CCCR_SEPINT_OE |
     477             :                             BWFM_SDIO_CCCR_SEPINT_ACT_HI);
     478             :                         sc->sc_oob = 1;
     479             :                 }
     480             :         }
     481             :         if (sc->sc_ih == NULL)
     482             : #endif
     483           0 :         sc->sc_ih = sdmmc_intr_establish(bwfm->sc_dev.dv_parent,
     484           0 :             bwfm_sdio_intr, sc, DEVNAME(sc));
     485           0 :         if (sc->sc_ih == NULL) {
     486           0 :                 printf("%s: can't establish interrupt\n", DEVNAME(sc));
     487           0 :                 bwfm_sdio_clkctl(sc, CLK_NONE, 0);
     488           0 :                 goto err;
     489             :         }
     490           0 :         sdmmc_intr_enable(sc->sc_sf[1]);
     491           0 :         rw_exit(sc->sc_lock);
     492             : 
     493           0 :         sc->sc_initialized = 1;
     494           0 :         return 0;
     495             : 
     496             : err:
     497           0 :         rw_exit(sc->sc_lock);
     498           0 :         return 1;
     499           0 : }
     500             : 
     501             : int
     502           0 : bwfm_sdio_load_microcode(struct bwfm_sdio_softc *sc, u_char *ucode, size_t size,
     503             :     u_char *nvram, size_t nvlen)
     504             : {
     505           0 :         struct bwfm_softc *bwfm = (void *)sc;
     506             :         char *verify = NULL;
     507             :         int err = 0;
     508             : 
     509           0 :         bwfm_sdio_clkctl(sc, CLK_AVAIL, 0);
     510             : 
     511             :         /* Upload firmware */
     512           0 :         err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase,
     513             :             ucode, size, 1);
     514           0 :         if (err)
     515             :                 goto out;
     516             : 
     517             :         /* Verify firmware */
     518           0 :         verify = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
     519           0 :         err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase,
     520             :             verify, size, 0);
     521           0 :         if (err || memcmp(verify, ucode, size)) {
     522           0 :                 printf("%s: firmware verification failed\n",
     523           0 :                     DEVNAME(sc));
     524           0 :                 free(verify, M_TEMP, size);
     525           0 :                 goto out;
     526             :         }
     527           0 :         free(verify, M_TEMP, size);
     528             : 
     529             :         /* Upload nvram */
     530           0 :         err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase +
     531           0 :             bwfm->sc_chip.ch_ramsize - nvlen, nvram, nvlen, 1);
     532           0 :         if (err)
     533             :                 goto out;
     534             : 
     535             :         /* Verify nvram */
     536           0 :         verify = malloc(nvlen, M_TEMP, M_WAITOK | M_ZERO);
     537           0 :         err = bwfm_sdio_ram_read_write(sc, bwfm->sc_chip.ch_rambase +
     538           0 :             bwfm->sc_chip.ch_ramsize - nvlen, verify, nvlen, 0);
     539           0 :         if (err || memcmp(verify, nvram, nvlen)) {
     540           0 :                 printf("%s: nvram verification failed\n",
     541           0 :                     DEVNAME(sc));
     542           0 :                 free(verify, M_TEMP, nvlen);
     543           0 :                 goto out;
     544             :         }
     545           0 :         free(verify, M_TEMP, nvlen);
     546             : 
     547             :         /* Load reset vector from firmware and kickstart core. */
     548           0 :         bwfm_chip_set_active(bwfm, *(uint32_t *)ucode);
     549             : 
     550             : out:
     551           0 :         bwfm_sdio_clkctl(sc, CLK_SDONLY, 0);
     552           0 :         return err;
     553             : }
     554             : 
     555             : void
     556           0 : bwfm_sdio_clkctl(struct bwfm_sdio_softc *sc, enum bwfm_sdio_clkstate newstate,
     557             :     int pendok)
     558             : {
     559             :         enum bwfm_sdio_clkstate oldstate;
     560             : 
     561           0 :         oldstate = sc->sc_clkstate;
     562           0 :         if (sc->sc_clkstate == newstate)
     563           0 :                 return;
     564             : 
     565           0 :         switch (newstate) {
     566             :         case CLK_AVAIL:
     567           0 :                 if (sc->sc_clkstate == CLK_NONE)
     568           0 :                         sc->sc_clkstate = CLK_SDONLY;
     569           0 :                 bwfm_sdio_htclk(sc, 1, pendok);
     570           0 :                 break;
     571             :         case CLK_SDONLY:
     572           0 :                 if (sc->sc_clkstate == CLK_NONE)
     573           0 :                         sc->sc_clkstate = CLK_SDONLY;
     574           0 :                 else if (sc->sc_clkstate == CLK_AVAIL)
     575           0 :                         bwfm_sdio_htclk(sc, 0, 0);
     576             :                 else
     577           0 :                         printf("%s: request for %d -> %d\n",
     578           0 :                             DEVNAME(sc), sc->sc_clkstate, newstate);
     579             :                 break;
     580             :         case CLK_NONE:
     581           0 :                 if (sc->sc_clkstate == CLK_AVAIL)
     582           0 :                         bwfm_sdio_htclk(sc, 0, 0);
     583           0 :                 sc->sc_clkstate = CLK_NONE;
     584           0 :                 break;
     585             :         default:
     586             :                 break;
     587             :         }
     588             : 
     589             :         DPRINTF(("%s: %d -> %d = %d\n", DEVNAME(sc), oldstate, newstate,
     590             :             sc->sc_clkstate));
     591           0 : }
     592             : 
     593             : void
     594           0 : bwfm_sdio_htclk(struct bwfm_sdio_softc *sc, int on, int pendok)
     595             : {
     596             :         uint32_t clkctl, devctl, req;
     597             :         int i;
     598             : 
     599           0 :         if (sc->sc_sr_enabled) {
     600           0 :                 if (on)
     601           0 :                         sc->sc_clkstate = CLK_AVAIL;
     602             :                 else
     603           0 :                         sc->sc_clkstate = CLK_SDONLY;
     604           0 :                 return;
     605             :         }
     606             : 
     607           0 :         if (on) {
     608           0 :                 if (sc->sc_alp_only)
     609           0 :                         req = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ;
     610             :                 else
     611             :                         req = BWFM_SDIO_FUNC1_CHIPCLKCSR_HT_AVAIL_REQ;
     612           0 :                 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, req);
     613             : 
     614           0 :                 clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR);
     615           0 :                 if (!BWFM_SDIO_FUNC1_CHIPCLKCSR_CLKAV(clkctl, sc->sc_alp_only)
     616           0 :                     && pendok) {
     617           0 :                         devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL);
     618           0 :                         devctl |= BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY;
     619           0 :                         bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl);
     620           0 :                         sc->sc_clkstate = CLK_PENDING;
     621           0 :                         return;
     622           0 :                 } else if (sc->sc_clkstate == CLK_PENDING) {
     623           0 :                         devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL);
     624           0 :                         devctl &= ~BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY;
     625           0 :                         bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl);
     626           0 :                 }
     627             : 
     628           0 :                 for (i = 0; i < 5000; i++) {
     629           0 :                         if (BWFM_SDIO_FUNC1_CHIPCLKCSR_CLKAV(clkctl,
     630             :                             sc->sc_alp_only))
     631             :                                 break;
     632           0 :                         clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR);
     633           0 :                         delay(1000);
     634             :                 }
     635           0 :                 if (!BWFM_SDIO_FUNC1_CHIPCLKCSR_CLKAV(clkctl, sc->sc_alp_only)) {
     636           0 :                         printf("%s: HT avail timeout\n", DEVNAME(sc));
     637           0 :                         return;
     638             :                 }
     639             : 
     640           0 :                 sc->sc_clkstate = CLK_AVAIL;
     641           0 :         } else {
     642           0 :                 if (sc->sc_clkstate == CLK_PENDING) {
     643           0 :                         devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL);
     644           0 :                         devctl &= ~BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY;
     645           0 :                         bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl);
     646           0 :                 }
     647           0 :                 sc->sc_clkstate = CLK_SDONLY;
     648           0 :                 bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, 0);
     649             :         }
     650           0 : }
     651             : 
     652             : void
     653           0 : bwfm_sdio_readshared(struct bwfm_sdio_softc *sc)
     654             : {
     655           0 :         struct bwfm_softc *bwfm = (void *)sc;
     656           0 :         struct bwfm_sdio_sdpcm sdpcm;
     657           0 :         uint32_t addr, shaddr;
     658             :         int err;
     659             : 
     660           0 :         shaddr = bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4;
     661           0 :         if (!bwfm->sc_chip.ch_rambase && bwfm_chip_sr_capable(bwfm))
     662           0 :                 shaddr -= bwfm->sc_chip.ch_srsize;
     663             : 
     664           0 :         err = bwfm_sdio_ram_read_write(sc, shaddr, (char *)&addr,
     665             :             sizeof(addr), 0);
     666           0 :         if (err)
     667           0 :                 return;
     668             : 
     669           0 :         addr = letoh32(addr);
     670           0 :         if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff))
     671           0 :                 return;
     672             : 
     673           0 :         err = bwfm_sdio_ram_read_write(sc, addr, (char *)&sdpcm,
     674             :             sizeof(sdpcm), 0);
     675           0 :         if (err)
     676           0 :                 return;
     677             : 
     678           0 :         sc->sc_console_addr = letoh32(sdpcm.console_addr);
     679           0 : }
     680             : 
     681             : int
     682           0 : bwfm_sdio_intr(void *v)
     683             : {
     684           0 :         bwfm_sdio_task(v);
     685           0 :         return 1;
     686             : }
     687             : 
     688             : #if defined(__HAVE_FDT)
     689             : int
     690             : bwfm_sdio_oob_intr(void *v)
     691             : {
     692             :         struct bwfm_sdio_softc *sc = (void *)v;
     693             :         if (!sc->sc_oob)
     694             :                 return 0;
     695             :         fdt_intr_disable(sc->sc_ih);
     696             :         task_add(systq, &sc->sc_task);
     697             :         return 1;
     698             : }
     699             : #endif
     700             : 
     701             : void
     702           0 : bwfm_sdio_task(void *v)
     703             : {
     704           0 :         struct bwfm_sdio_softc *sc = (void *)v;
     705             :         uint32_t clkctl, devctl, intstat, hostint;
     706             : 
     707           0 :         rw_enter_write(sc->sc_lock);
     708             : 
     709           0 :         if (!sc->sc_sr_enabled && sc->sc_clkstate == CLK_PENDING) {
     710           0 :                 clkctl = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR);
     711           0 :                 if (BWFM_SDIO_FUNC1_CHIPCLKCSR_HTAV(clkctl)) {
     712           0 :                         devctl = bwfm_sdio_read_1(sc, BWFM_SDIO_DEVICE_CTL);
     713           0 :                         devctl &= ~BWFM_SDIO_DEVICE_CTL_CA_INT_ONLY;
     714           0 :                         bwfm_sdio_write_1(sc, BWFM_SDIO_DEVICE_CTL, devctl);
     715           0 :                         sc->sc_clkstate = CLK_AVAIL;
     716           0 :                 }
     717             :         }
     718             : 
     719           0 :         intstat = bwfm_sdio_dev_read(sc, BWFM_SDPCMD_INTSTATUS);
     720           0 :         intstat &= (SDPCMD_INTSTATUS_HMB_SW_MASK|SDPCMD_INTSTATUS_CHIPACTIVE);
     721             :         /* XXX fc state */
     722           0 :         if (intstat)
     723           0 :                 bwfm_sdio_dev_write(sc, BWFM_SDPCMD_INTSTATUS, intstat);
     724             : 
     725           0 :         if (intstat & SDPCMD_INTSTATUS_HMB_HOST_INT) {
     726           0 :                 hostint = bwfm_sdio_dev_read(sc, SDPCMD_TOHOSTMAILBOXDATA);
     727           0 :                 bwfm_sdio_dev_write(sc, SDPCMD_TOSBMAILBOX,
     728             :                     SDPCMD_TOSBMAILBOX_INT_ACK);
     729           0 :                 if (hostint & SDPCMD_TOHOSTMAILBOXDATA_NAKHANDLED)
     730           0 :                         intstat |= SDPCMD_INTSTATUS_HMB_FRAME_IND;
     731           0 :                 if (hostint & SDPCMD_TOHOSTMAILBOXDATA_DEVREADY ||
     732           0 :                     hostint & SDPCMD_TOHOSTMAILBOXDATA_FWREADY)
     733           0 :                         bwfm_sdio_readshared(sc);
     734             :         }
     735             : 
     736             :         /* FIXME: Might stall if we don't when not set. */
     737             :         if (1 || intstat & SDPCMD_INTSTATUS_HMB_FRAME_IND) {
     738           0 :                 bwfm_sdio_rx_frames(sc);
     739             :         }
     740             : 
     741           0 :         if (!ml_empty(&sc->sc_tx_queue)) {
     742           0 :                 bwfm_sdio_tx_frames(sc);
     743           0 :         }
     744             : 
     745             : #ifdef BWFM_DEBUG
     746             :         bwfm_sdio_debug_console(sc);
     747             : #endif
     748             : 
     749           0 :         rw_exit(sc->sc_lock);
     750             : 
     751             : #if defined(__HAVE_FDT)
     752             :         if (sc->sc_oob)
     753             :                 fdt_intr_enable(sc->sc_ih);
     754             : #endif
     755           0 : }
     756             : 
     757             : int
     758           0 : bwfm_sdio_detach(struct device *self, int flags)
     759             : {
     760           0 :         struct bwfm_sdio_softc *sc = (struct bwfm_sdio_softc *)self;
     761             : 
     762           0 :         bwfm_detach(&sc->sc_sc, flags);
     763             : 
     764           0 :         dma_free(sc->sc_bounce_buf, sc->sc_bounce_size);
     765           0 :         free(sc->sc_sf, M_DEVBUF, 0);
     766             : 
     767           0 :         return 0;
     768             : }
     769             : 
     770             : void
     771           0 : bwfm_sdio_backplane(struct bwfm_sdio_softc *sc, uint32_t bar0)
     772             : {
     773           0 :         if (sc->sc_bar0 == bar0)
     774             :                 return;
     775             : 
     776           0 :         bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRLOW,
     777           0 :             (bar0 >>  8) & 0x80);
     778           0 :         bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRMID,
     779           0 :             (bar0 >> 16) & 0xff);
     780           0 :         bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SBADDRHIGH,
     781           0 :             (bar0 >> 24) & 0xff);
     782           0 :         sc->sc_bar0 = bar0;
     783           0 : }
     784             : 
     785             : uint8_t
     786           0 : bwfm_sdio_read_1(struct bwfm_sdio_softc *sc, uint32_t addr)
     787             : {
     788             :         struct sdmmc_function *sf;
     789             :         uint8_t rv;
     790             : 
     791             :         /*
     792             :          * figure out how to read the register based on address range
     793             :          * 0x00 ~ 0x7FF: function 0 CCCR and FBR
     794             :          * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
     795             :          * The rest: function 1 silicon backplane core registers
     796             :          */
     797           0 :         if ((addr & ~0x7ff) == 0)
     798           0 :                 sf = sc->sc_sf[0];
     799             :         else
     800           0 :                 sf = sc->sc_sf[1];
     801             : 
     802           0 :         rv = sdmmc_io_read_1(sf, addr);
     803           0 :         return rv;
     804             : }
     805             : 
     806             : uint32_t
     807           0 : bwfm_sdio_read_4(struct bwfm_sdio_softc *sc, uint32_t addr)
     808             : {
     809             :         struct sdmmc_function *sf;
     810           0 :         uint32_t bar0 = addr & ~BWFM_SDIO_SB_OFT_ADDR_MASK;
     811             :         uint32_t rv;
     812             : 
     813           0 :         bwfm_sdio_backplane(sc, bar0);
     814             : 
     815           0 :         addr &= BWFM_SDIO_SB_OFT_ADDR_MASK;
     816           0 :         addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG;
     817             : 
     818             :         /*
     819             :          * figure out how to read the register based on address range
     820             :          * 0x00 ~ 0x7FF: function 0 CCCR and FBR
     821             :          * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
     822             :          * The rest: function 1 silicon backplane core registers
     823             :          */
     824           0 :         if ((addr & ~0x7ff) == 0)
     825           0 :                 sf = sc->sc_sf[0];
     826             :         else
     827           0 :                 sf = sc->sc_sf[1];
     828             : 
     829           0 :         rv = sdmmc_io_read_4(sf, addr);
     830           0 :         return rv;
     831             : }
     832             : 
     833             : void
     834           0 : bwfm_sdio_write_1(struct bwfm_sdio_softc *sc, uint32_t addr, uint8_t data)
     835             : {
     836             :         struct sdmmc_function *sf;
     837             : 
     838             :         /*
     839             :          * figure out how to read the register based on address range
     840             :          * 0x00 ~ 0x7FF: function 0 CCCR and FBR
     841             :          * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
     842             :          * The rest: function 1 silicon backplane core registers
     843             :          */
     844           0 :         if ((addr & ~0x7ff) == 0)
     845           0 :                 sf = sc->sc_sf[0];
     846             :         else
     847           0 :                 sf = sc->sc_sf[1];
     848             : 
     849           0 :         sdmmc_io_write_1(sf, addr, data);
     850           0 : }
     851             : 
     852             : void
     853           0 : bwfm_sdio_write_4(struct bwfm_sdio_softc *sc, uint32_t addr, uint32_t data)
     854             : {
     855             :         struct sdmmc_function *sf;
     856           0 :         uint32_t bar0 = addr & ~BWFM_SDIO_SB_OFT_ADDR_MASK;
     857             : 
     858           0 :         bwfm_sdio_backplane(sc, bar0);
     859             : 
     860           0 :         addr &= BWFM_SDIO_SB_OFT_ADDR_MASK;
     861           0 :         addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG;
     862             : 
     863             :         /*
     864             :          * figure out how to read the register based on address range
     865             :          * 0x00 ~ 0x7FF: function 0 CCCR and FBR
     866             :          * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
     867             :          * The rest: function 1 silicon backplane core registers
     868             :          */
     869           0 :         if ((addr & ~0x7ff) == 0)
     870           0 :                 sf = sc->sc_sf[0];
     871             :         else
     872           0 :                 sf = sc->sc_sf[1];
     873             : 
     874           0 :         sdmmc_io_write_4(sf, addr, data);
     875           0 : }
     876             : 
     877             : int
     878           0 : bwfm_sdio_buf_read(struct bwfm_sdio_softc *sc, struct sdmmc_function *sf,
     879             :     uint32_t reg, char *data, size_t size)
     880             : {
     881             :         int err;
     882             : 
     883           0 :         KASSERT(((vaddr_t)data & 0x3) == 0);
     884           0 :         KASSERT((size & 0x3) == 0);
     885             : 
     886           0 :         if (sf == sc->sc_sf[1])
     887           0 :                 err = sdmmc_io_read_region_1(sf, reg, data, size);
     888             :         else
     889           0 :                 err = sdmmc_io_read_multi_1(sf, reg, data, size);
     890             : 
     891           0 :         if (err)
     892           0 :                 printf("%s: error %d\n", __func__, err);
     893             : 
     894           0 :         return err;
     895             : }
     896             : 
     897             : int
     898           0 : bwfm_sdio_buf_write(struct bwfm_sdio_softc *sc, struct sdmmc_function *sf,
     899             :     uint32_t reg, char *data, size_t size)
     900             : {
     901             :         int err;
     902             : 
     903           0 :         KASSERT(((vaddr_t)data & 0x3) == 0);
     904           0 :         KASSERT((size & 0x3) == 0);
     905             : 
     906           0 :         err = sdmmc_io_write_region_1(sf, reg, data, size);
     907             : 
     908           0 :         if (err)
     909           0 :                 printf("%s: error %d\n", __func__, err);
     910             : 
     911           0 :         return err;
     912             : }
     913             : 
     914             : uint32_t
     915           0 : bwfm_sdio_ram_read_write(struct bwfm_sdio_softc *sc, uint32_t reg,
     916             :     char *data, size_t left, int write)
     917             : {
     918             :         uint32_t sbaddr, sdaddr, off;
     919             :         size_t size;
     920             :         int err;
     921             : 
     922             :         err = off = 0;
     923           0 :         while (left > 0) {
     924           0 :                 sbaddr = reg + off;
     925           0 :                 bwfm_sdio_backplane(sc, sbaddr);
     926             : 
     927           0 :                 sdaddr = sbaddr & BWFM_SDIO_SB_OFT_ADDR_MASK;
     928           0 :                 size = min(left, (BWFM_SDIO_SB_OFT_ADDR_PAGE - sdaddr));
     929           0 :                 sdaddr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG;
     930             : 
     931           0 :                 if (write) {
     932           0 :                         memcpy(sc->sc_bounce_buf, data + off, size);
     933           0 :                         if (roundup(size, 4) != size)
     934           0 :                                 memset(sc->sc_bounce_buf + size, 0,
     935             :                                     roundup(size, 4) - size);
     936           0 :                         err = bwfm_sdio_buf_write(sc, sc->sc_sf[1], sdaddr,
     937           0 :                             sc->sc_bounce_buf, roundup(size, 4));
     938           0 :                 } else {
     939           0 :                         err = bwfm_sdio_buf_read(sc, sc->sc_sf[1], sdaddr,
     940           0 :                             sc->sc_bounce_buf, roundup(size, 4));
     941           0 :                         memcpy(data + off, sc->sc_bounce_buf, size);
     942             :                 }
     943           0 :                 if (err)
     944             :                         break;
     945             : 
     946           0 :                 off += size;
     947           0 :                 left -= size;
     948             :         }
     949             : 
     950           0 :         return err;
     951             : }
     952             : 
     953             : uint32_t
     954           0 : bwfm_sdio_frame_read_write(struct bwfm_sdio_softc *sc,
     955             :     char *data, size_t size, int write)
     956             : {
     957             :         uint32_t addr;
     958             :         int err;
     959             : 
     960           0 :         addr = sc->sc_cc->co_base;
     961           0 :         bwfm_sdio_backplane(sc, addr);
     962             : 
     963           0 :         addr &= BWFM_SDIO_SB_OFT_ADDR_MASK;
     964           0 :         addr |= BWFM_SDIO_SB_ACCESS_2_4B_FLAG;
     965             : 
     966           0 :         if (write)
     967           0 :                 err = bwfm_sdio_buf_write(sc, sc->sc_sf[2], addr, data, size);
     968             :         else
     969           0 :                 err = bwfm_sdio_buf_read(sc, sc->sc_sf[2], addr, data, size);
     970             : 
     971           0 :         return err;
     972             : }
     973             : 
     974             : uint32_t
     975           0 : bwfm_sdio_dev_read(struct bwfm_sdio_softc *sc, uint32_t reg)
     976             : {
     977             :         struct bwfm_core *core;
     978           0 :         core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV);
     979           0 :         return bwfm_sdio_read_4(sc, core->co_base + reg);
     980             : }
     981             : 
     982             : void
     983           0 : bwfm_sdio_dev_write(struct bwfm_sdio_softc *sc, uint32_t reg, uint32_t val)
     984             : {
     985             :         struct bwfm_core *core;
     986           0 :         core = bwfm_chip_get_core(&sc->sc_sc, BWFM_AGENT_CORE_SDIO_DEV);
     987           0 :         bwfm_sdio_write_4(sc, core->co_base + reg, val);
     988           0 : }
     989             : 
     990             : uint32_t
     991           0 : bwfm_sdio_buscore_read(struct bwfm_softc *bwfm, uint32_t reg)
     992             : {
     993           0 :         struct bwfm_sdio_softc *sc = (void *)bwfm;
     994           0 :         return bwfm_sdio_read_4(sc, reg);
     995             : }
     996             : 
     997             : void
     998           0 : bwfm_sdio_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val)
     999             : {
    1000           0 :         struct bwfm_sdio_softc *sc = (void *)bwfm;
    1001           0 :         bwfm_sdio_write_4(sc, reg, val);
    1002           0 : }
    1003             : 
    1004             : int
    1005           0 : bwfm_sdio_buscore_prepare(struct bwfm_softc *bwfm)
    1006             : {
    1007           0 :         struct bwfm_sdio_softc *sc = (void *)bwfm;
    1008             :         uint8_t clkval, clkset, clkmask;
    1009             :         int i;
    1010             : 
    1011             :         clkset = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL_REQ |
    1012             :             BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF;
    1013           0 :         bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clkset);
    1014             : 
    1015             :         clkmask = BWFM_SDIO_FUNC1_CHIPCLKCSR_ALP_AVAIL |
    1016             :             BWFM_SDIO_FUNC1_CHIPCLKCSR_HT_AVAIL;
    1017           0 :         clkval = bwfm_sdio_read_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR);
    1018             : 
    1019           0 :         if ((clkval & ~clkmask) != clkset) {
    1020           0 :                 printf("%s: wrote 0x%02x read 0x%02x\n", DEVNAME(sc),
    1021             :                     clkset, clkval);
    1022           0 :                 return 1;
    1023             :         }
    1024             : 
    1025           0 :         for (i = 1000; i > 0; i--) {
    1026           0 :                 clkval = bwfm_sdio_read_1(sc,
    1027             :                     BWFM_SDIO_FUNC1_CHIPCLKCSR);
    1028           0 :                 if (clkval & clkmask)
    1029             :                         break;
    1030             :         }
    1031           0 :         if (i == 0) {
    1032           0 :                 printf("%s: timeout on ALPAV wait, clkval 0x%02x\n",
    1033           0 :                     DEVNAME(sc), clkval);
    1034           0 :                 return 1;
    1035             :         }
    1036             : 
    1037             :         clkset = BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_HW_CLKREQ_OFF |
    1038             :             BWFM_SDIO_FUNC1_CHIPCLKCSR_FORCE_ALP;
    1039           0 :         bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_CHIPCLKCSR, clkset);
    1040           0 :         delay(65);
    1041             : 
    1042           0 :         bwfm_sdio_write_1(sc, BWFM_SDIO_FUNC1_SDIOPULLUP, 0);
    1043             : 
    1044           0 :         return 0;
    1045           0 : }
    1046             : 
    1047             : void
    1048           0 : bwfm_sdio_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec)
    1049             : {
    1050           0 :         struct bwfm_sdio_softc *sc = (void *)bwfm;
    1051             : 
    1052           0 :         bwfm_sdio_dev_write(sc, BWFM_SDPCMD_INTSTATUS, 0xFFFFFFFF);
    1053             : 
    1054           0 :         if (rstvec)
    1055           0 :                 bwfm_sdio_ram_read_write(sc, 0, (char *)&rstvec,
    1056             :                     sizeof(rstvec), 1);
    1057           0 : }
    1058             : 
    1059             : struct mbuf *
    1060           0 : bwfm_sdio_newbuf(void)
    1061             : {
    1062             :         struct mbuf *m;
    1063             : 
    1064           0 :         MGETHDR(m, M_DONTWAIT, MT_DATA);
    1065           0 :         if (m == NULL)
    1066           0 :                 return (NULL);
    1067             : 
    1068           0 :         MCLGET(m, M_DONTWAIT);
    1069           0 :         if (!(m->m_flags & M_EXT)) {
    1070           0 :                 m_freem(m);
    1071           0 :                 return (NULL);
    1072             :         }
    1073             : 
    1074           0 :         m->m_len = m->m_pkthdr.len = MCLBYTES;
    1075             : 
    1076           0 :         return (m);
    1077           0 : }
    1078             : 
    1079             : int
    1080           0 : bwfm_sdio_tx_ok(struct bwfm_sdio_softc *sc)
    1081             : {
    1082           0 :         return (uint8_t)(sc->sc_tx_max_seq - sc->sc_tx_seq) != 0 &&
    1083           0 :             ((uint8_t)(sc->sc_tx_max_seq - sc->sc_tx_seq) & 0x80) == 0;
    1084             : }
    1085             : 
    1086             : void
    1087           0 : bwfm_sdio_tx_frames(struct bwfm_sdio_softc *sc)
    1088             : {
    1089           0 :         struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if;
    1090             :         struct mbuf *m;
    1091             :         int i;
    1092             : 
    1093           0 :         if (!bwfm_sdio_tx_ok(sc))
    1094           0 :                 return;
    1095             : 
    1096           0 :         i = min((uint8_t)(sc->sc_tx_max_seq - sc->sc_tx_seq), 32);
    1097           0 :         while (i--) {
    1098           0 :                 m = ml_dequeue(&sc->sc_tx_queue);
    1099           0 :                 if (m == NULL)
    1100             :                         break;
    1101             : 
    1102           0 :                 if (m->m_type == MT_CONTROL)
    1103           0 :                         bwfm_sdio_tx_ctrlframe(sc, m);
    1104             :                 else
    1105           0 :                         bwfm_sdio_tx_dataframe(sc, m);
    1106             : 
    1107           0 :                 m_freem(m);
    1108             :         }
    1109             : 
    1110           0 :         if (sc->sc_tx_count < 64)
    1111           0 :                 ifq_restart(&ifp->if_snd);
    1112           0 : }
    1113             : 
    1114             : void
    1115           0 : bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *sc, struct mbuf *m)
    1116             : {
    1117             :         struct bwfm_sdio_hwhdr *hwhdr;
    1118             :         struct bwfm_sdio_swhdr *swhdr;
    1119             :         size_t len, roundto;
    1120             : 
    1121           0 :         len = sizeof(*hwhdr) + sizeof(*swhdr) + m->m_len;
    1122             : 
    1123             :         /* Zero-pad to either block-size or 4-byte alignment. */
    1124           0 :         if (len > 512 && (len % 512) != 0)
    1125           0 :                 roundto = 512;
    1126             :         else
    1127             :                 roundto = 4;
    1128             : 
    1129           0 :         KASSERT(roundup(len, roundto) <= sc->sc_bounce_size);
    1130             : 
    1131           0 :         hwhdr = (void *)sc->sc_bounce_buf;
    1132           0 :         hwhdr->frmlen = htole16(len);
    1133           0 :         hwhdr->cksum = htole16(~len);
    1134             : 
    1135           0 :         swhdr = (void *)&hwhdr[1];
    1136           0 :         swhdr->seqnr = sc->sc_tx_seq++;
    1137           0 :         swhdr->chanflag = BWFM_SDIO_SWHDR_CHANNEL_CONTROL;
    1138           0 :         swhdr->nextlen = 0;
    1139           0 :         swhdr->dataoff = sizeof(*hwhdr) + sizeof(*swhdr);
    1140           0 :         swhdr->maxseqnr = 0;
    1141             : 
    1142           0 :         m_copydata(m, 0, m->m_len, (caddr_t)&swhdr[1]);
    1143             : 
    1144           0 :         if (roundup(len, roundto) != len)
    1145           0 :                 memset(sc->sc_bounce_buf + len, 0,
    1146             :                     roundup(len, roundto) - len);
    1147             : 
    1148           0 :         bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf,
    1149             :             roundup(len, roundto), 1);
    1150           0 : }
    1151             : 
    1152             : void
    1153           0 : bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *sc, struct mbuf *m)
    1154             : {
    1155             :         struct bwfm_sdio_hwhdr *hwhdr;
    1156             :         struct bwfm_sdio_swhdr *swhdr;
    1157             :         struct bwfm_proto_bcdc_hdr *bcdc;
    1158             :         size_t len, roundto;
    1159             : 
    1160             :         len = sizeof(*hwhdr) + sizeof(*swhdr) + sizeof(*bcdc)
    1161           0 :             + m->m_pkthdr.len;
    1162             : 
    1163             :         /* Zero-pad to either block-size or 4-byte alignment. */
    1164           0 :         if (len > 512 && (len % 512) != 0)
    1165           0 :                 roundto = 512;
    1166             :         else
    1167             :                 roundto = 4;
    1168             : 
    1169           0 :         KASSERT(roundup(len, roundto) <= sc->sc_bounce_size);
    1170             : 
    1171           0 :         hwhdr = (void *)sc->sc_bounce_buf;
    1172           0 :         hwhdr->frmlen = htole16(len);
    1173           0 :         hwhdr->cksum = htole16(~len);
    1174             : 
    1175           0 :         swhdr = (void *)&hwhdr[1];
    1176           0 :         swhdr->seqnr = sc->sc_tx_seq++;
    1177           0 :         swhdr->chanflag = BWFM_SDIO_SWHDR_CHANNEL_DATA;
    1178           0 :         swhdr->nextlen = 0;
    1179           0 :         swhdr->dataoff = sizeof(*hwhdr) + sizeof(*swhdr);
    1180           0 :         swhdr->maxseqnr = 0;
    1181             : 
    1182           0 :         bcdc = (void *)&swhdr[1];
    1183           0 :         bcdc->data_offset = 0;
    1184           0 :         bcdc->priority = ieee80211_classify(&sc->sc_sc.sc_ic, m);
    1185           0 :         bcdc->flags = BWFM_BCDC_FLAG_VER(BWFM_BCDC_FLAG_PROTO_VER);
    1186           0 :         bcdc->flags2 = 0;
    1187             : 
    1188           0 :         m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&bcdc[1]);
    1189             : 
    1190           0 :         if (roundup(len, roundto) != len)
    1191           0 :                 memset(sc->sc_bounce_buf + len, 0,
    1192             :                     roundup(len, roundto) - len);
    1193             : 
    1194           0 :         bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf,
    1195             :             roundup(len, roundto), 1);
    1196             : 
    1197           0 :         sc->sc_tx_count--;
    1198           0 : }
    1199             : 
    1200             : void
    1201           0 : bwfm_sdio_rx_frames(struct bwfm_sdio_softc *sc)
    1202             : {
    1203             :         struct bwfm_sdio_hwhdr *hwhdr;
    1204             :         struct bwfm_sdio_swhdr *swhdr;
    1205           0 :         uint16_t *sublen, nextlen = 0;
    1206             :         struct mbuf *m;
    1207             :         size_t flen;
    1208             :         char *data;
    1209             :         off_t off;
    1210             :         int nsub;
    1211             : 
    1212           0 :         hwhdr = (struct bwfm_sdio_hwhdr *)sc->sc_bounce_buf;
    1213           0 :         swhdr = (struct bwfm_sdio_swhdr *)&hwhdr[1];
    1214           0 :         data = (char *)&swhdr[1];
    1215             : 
    1216           0 :         for (;;) {
    1217             :                 /* If we know the next size, just read ahead. */
    1218           0 :                 if (nextlen) {
    1219           0 :                         if (bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf,
    1220           0 :                             nextlen, 0))
    1221             :                                 break;
    1222             :                 } else {
    1223           0 :                         if (bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf,
    1224             :                             sizeof(*hwhdr) + sizeof(*swhdr), 0))
    1225             :                                 break;
    1226             :                 }
    1227             : 
    1228           0 :                 hwhdr->frmlen = letoh16(hwhdr->frmlen);
    1229           0 :                 hwhdr->cksum = letoh16(hwhdr->cksum);
    1230             : 
    1231           0 :                 if (hwhdr->frmlen == 0 && hwhdr->cksum == 0)
    1232             :                         break;
    1233             : 
    1234           0 :                 if ((hwhdr->frmlen ^ hwhdr->cksum) != 0xffff) {
    1235           0 :                         printf("%s: checksum error\n", DEVNAME(sc));
    1236           0 :                         break;
    1237             :                 }
    1238             : 
    1239           0 :                 if (hwhdr->frmlen < sizeof(*hwhdr) + sizeof(*swhdr)) {
    1240           0 :                         printf("%s: length error\n", DEVNAME(sc));
    1241           0 :                         break;
    1242             :                 }
    1243             : 
    1244           0 :                 if (nextlen && hwhdr->frmlen > nextlen) {
    1245           0 :                         printf("%s: read ahead length error (%u > %u)\n",
    1246           0 :                             DEVNAME(sc), hwhdr->frmlen, nextlen);
    1247           0 :                         break;
    1248             :                 }
    1249             : 
    1250           0 :                 sc->sc_tx_max_seq = swhdr->maxseqnr;
    1251             : 
    1252           0 :                 flen = hwhdr->frmlen - (sizeof(*hwhdr) + sizeof(*swhdr));
    1253           0 :                 if (flen == 0) {
    1254           0 :                         nextlen = swhdr->nextlen << 4;
    1255           0 :                         continue;
    1256             :                 }
    1257             : 
    1258           0 :                 if (!nextlen) {
    1259           0 :                         KASSERT(roundup(flen, 4) <= sc->sc_bounce_size -
    1260             :                             (sizeof(*hwhdr) + sizeof(*swhdr)));
    1261           0 :                         if (bwfm_sdio_frame_read_write(sc, data,
    1262             :                             roundup(flen, 4), 0))
    1263             :                                 break;
    1264             :                 }
    1265             : 
    1266           0 :                 if (swhdr->dataoff < (sizeof(*hwhdr) + sizeof(*swhdr)))
    1267             :                         break;
    1268             : 
    1269           0 :                 off = swhdr->dataoff - (sizeof(*hwhdr) + sizeof(*swhdr));
    1270           0 :                 if (off > flen)
    1271             :                         break;
    1272             : 
    1273           0 :                 switch (swhdr->chanflag & BWFM_SDIO_SWHDR_CHANNEL_MASK) {
    1274             :                 case BWFM_SDIO_SWHDR_CHANNEL_CONTROL:
    1275           0 :                         sc->sc_sc.sc_proto_ops->proto_rxctl(&sc->sc_sc,
    1276           0 :                             data + off, flen - off);
    1277           0 :                         nextlen = swhdr->nextlen << 4;
    1278           0 :                         break;
    1279             :                 case BWFM_SDIO_SWHDR_CHANNEL_EVENT:
    1280             :                 case BWFM_SDIO_SWHDR_CHANNEL_DATA:
    1281           0 :                         m = bwfm_sdio_newbuf();
    1282           0 :                         if (m == NULL)
    1283             :                                 break;
    1284           0 :                         if (flen - off > m->m_len) {
    1285           0 :                                 printf("%s: frame bigger than anticipated\n",
    1286           0 :                                     DEVNAME(sc));
    1287           0 :                                 m_free(m);
    1288           0 :                                 break;
    1289             :                         }
    1290           0 :                         m->m_len = m->m_pkthdr.len = flen - off;
    1291           0 :                         memcpy(mtod(m, char *), data + off, flen - off);
    1292           0 :                         sc->sc_sc.sc_proto_ops->proto_rx(&sc->sc_sc, m);
    1293           0 :                         nextlen = swhdr->nextlen << 4;
    1294           0 :                         break;
    1295             :                 case BWFM_SDIO_SWHDR_CHANNEL_GLOM:
    1296           0 :                         if ((flen % sizeof(uint16_t)) != 0)
    1297             :                                 break;
    1298           0 :                         nsub = flen / sizeof(uint16_t);
    1299           0 :                         sublen = mallocarray(nsub, sizeof(uint16_t),
    1300             :                             M_DEVBUF, M_WAITOK | M_ZERO);
    1301           0 :                         memcpy(sublen, data, nsub * sizeof(uint16_t));
    1302           0 :                         bwfm_sdio_rx_glom(sc, sublen, nsub, &nextlen);
    1303           0 :                         free(sublen, M_DEVBUF, nsub * sizeof(uint16_t));
    1304           0 :                         break;
    1305             :                 default:
    1306           0 :                         printf("%s: unknown channel\n", DEVNAME(sc));
    1307           0 :                         break;
    1308             :                 }
    1309             :         }
    1310           0 : }
    1311             : 
    1312             : void
    1313           0 : bwfm_sdio_rx_glom(struct bwfm_sdio_softc *sc, uint16_t *sublen, int nsub,
    1314             :     uint16_t *nextlen)
    1315             : {
    1316           0 :         struct bwfm_sdio_hwhdr hwhdr;
    1317           0 :         struct bwfm_sdio_swhdr swhdr;
    1318           0 :         struct mbuf_list ml, drop;
    1319             :         struct mbuf *m;
    1320             :         size_t flen;
    1321             :         off_t off;
    1322             :         int i;
    1323             : 
    1324           0 :         ml_init(&ml);
    1325           0 :         ml_init(&drop);
    1326             : 
    1327           0 :         if (nsub == 0)
    1328           0 :                 return;
    1329             : 
    1330           0 :         for (i = 0; i < nsub; i++) {
    1331           0 :                 m = bwfm_sdio_newbuf();
    1332           0 :                 if (m == NULL) {
    1333           0 :                         ml_purge(&ml);
    1334           0 :                         return;
    1335             :                 }
    1336           0 :                 ml_enqueue(&ml, m);
    1337           0 :                 if (letoh16(sublen[i]) > m->m_len) {
    1338           0 :                         ml_purge(&ml);
    1339           0 :                         return;
    1340             :                 }
    1341           0 :                 if (bwfm_sdio_frame_read_write(sc, mtod(m, char *),
    1342           0 :                     letoh16(sublen[i]), 0)) {
    1343           0 :                         ml_purge(&ml);
    1344           0 :                         return;
    1345             :                 }
    1346           0 :                 m->m_len = m->m_pkthdr.len = letoh16(sublen[i]);
    1347             :         }
    1348             : 
    1349             :         /* TODO: Verify actual superframe header */
    1350           0 :         m = MBUF_LIST_FIRST(&ml);
    1351           0 :         if (m->m_len >= sizeof(hwhdr) + sizeof(swhdr)) {
    1352           0 :                 m_copydata(m, 0, sizeof(hwhdr), (caddr_t)&hwhdr);
    1353           0 :                 m_copydata(m, sizeof(hwhdr), sizeof(swhdr), (caddr_t)&swhdr);
    1354           0 :                 *nextlen = swhdr.nextlen << 4;
    1355           0 :                 m_adj(m, sizeof(struct bwfm_sdio_hwhdr) +
    1356             :                     sizeof(struct bwfm_sdio_swhdr));
    1357           0 :         }
    1358             : 
    1359           0 :         while ((m = ml_dequeue(&ml)) != NULL) {
    1360           0 :                 if (m->m_len < sizeof(hwhdr) + sizeof(swhdr))
    1361             :                         goto drop;
    1362             : 
    1363           0 :                 m_copydata(m, 0, sizeof(hwhdr), (caddr_t)&hwhdr);
    1364           0 :                 m_copydata(m, sizeof(hwhdr), sizeof(swhdr), (caddr_t)&swhdr);
    1365             : 
    1366           0 :                 hwhdr.frmlen = letoh16(hwhdr.frmlen);
    1367           0 :                 hwhdr.cksum = letoh16(hwhdr.cksum);
    1368             : 
    1369           0 :                 if (hwhdr.frmlen == 0 && hwhdr.cksum == 0)
    1370             :                         goto drop;
    1371             : 
    1372           0 :                 if ((hwhdr.frmlen ^ hwhdr.cksum) != 0xffff) {
    1373           0 :                         printf("%s: checksum error\n", DEVNAME(sc));
    1374           0 :                         goto drop;
    1375             :                 }
    1376             : 
    1377           0 :                 if (hwhdr.frmlen < sizeof(hwhdr) + sizeof(swhdr)) {
    1378           0 :                         printf("%s: length error\n", DEVNAME(sc));
    1379           0 :                         goto drop;
    1380             :                 }
    1381             : 
    1382           0 :                 flen = hwhdr.frmlen - (sizeof(hwhdr) + sizeof(swhdr));
    1383           0 :                 if (flen == 0)
    1384             :                         goto drop;
    1385           0 :                 if (m->m_len < flen)
    1386             :                         goto drop;
    1387             : 
    1388           0 :                 if (swhdr.dataoff < (sizeof(hwhdr) + sizeof(swhdr)))
    1389             :                         goto drop;
    1390             : 
    1391           0 :                 off = swhdr.dataoff - (sizeof(hwhdr) + sizeof(swhdr));
    1392           0 :                 if (off > flen)
    1393             :                         goto drop;
    1394             : 
    1395           0 :                 switch (swhdr.chanflag & BWFM_SDIO_SWHDR_CHANNEL_MASK) {
    1396             :                 case BWFM_SDIO_SWHDR_CHANNEL_CONTROL:
    1397           0 :                         printf("%s: control channel not allowed in glom\n",
    1398           0 :                             DEVNAME(sc));
    1399           0 :                         goto drop;
    1400             :                 case BWFM_SDIO_SWHDR_CHANNEL_EVENT:
    1401             :                 case BWFM_SDIO_SWHDR_CHANNEL_DATA:
    1402           0 :                         m_adj(m, swhdr.dataoff);
    1403           0 :                         sc->sc_sc.sc_proto_ops->proto_rx(&sc->sc_sc, m);
    1404             :                         break;
    1405             :                 case BWFM_SDIO_SWHDR_CHANNEL_GLOM:
    1406           0 :                         printf("%s: glom not allowed in glom\n",
    1407           0 :                             DEVNAME(sc));
    1408           0 :                         goto drop;
    1409             :                 default:
    1410           0 :                         printf("%s: unknown channel\n", DEVNAME(sc));
    1411           0 :                         goto drop;
    1412             :                 }
    1413             : 
    1414           0 :                 continue;
    1415             : drop:
    1416           0 :                 ml_enqueue(&drop, m);
    1417             :         }
    1418             : 
    1419           0 :         ml_purge(&drop);
    1420           0 : }
    1421             : 
    1422             : int
    1423           0 : bwfm_sdio_txcheck(struct bwfm_softc *bwfm)
    1424             : {
    1425           0 :         struct bwfm_sdio_softc *sc = (void *)bwfm;
    1426             : 
    1427           0 :         if (sc->sc_tx_count >= 64)
    1428           0 :                 return ENOBUFS;
    1429             : 
    1430           0 :         return 0;
    1431           0 : }
    1432             : 
    1433             : int
    1434           0 : bwfm_sdio_txdata(struct bwfm_softc *bwfm, struct mbuf *m)
    1435             : {
    1436           0 :         struct bwfm_sdio_softc *sc = (void *)bwfm;
    1437             : 
    1438           0 :         if (sc->sc_tx_count >= 64)
    1439           0 :                 return ENOBUFS;
    1440             : 
    1441           0 :         sc->sc_tx_count++;
    1442           0 :         ml_enqueue(&sc->sc_tx_queue, m);
    1443           0 :         task_add(systq, &sc->sc_task);
    1444           0 :         return 0;
    1445           0 : }
    1446             : 
    1447             : int
    1448           0 : bwfm_sdio_txctl(struct bwfm_softc *bwfm, void *arg)
    1449             : {
    1450           0 :         struct bwfm_sdio_softc *sc = (void *)bwfm;
    1451           0 :         struct bwfm_proto_bcdc_ctl *ctl = arg;
    1452             :         struct mbuf *m;
    1453             : 
    1454           0 :         MGET(m, M_DONTWAIT, MT_CONTROL);
    1455           0 :         if (m == NULL || M_TRAILINGSPACE(m) < ctl->len) {
    1456           0 :                 free(ctl->buf, M_TEMP, ctl->len);
    1457           0 :                 free(ctl, M_TEMP, sizeof(*ctl));
    1458           0 :                 return 1;
    1459             :         }
    1460           0 :         memcpy(mtod(m, char *), ctl->buf, ctl->len);
    1461           0 :         m->m_len = ctl->len;
    1462             : 
    1463           0 :         TAILQ_INSERT_TAIL(&sc->sc_sc.sc_bcdc_rxctlq, ctl, next);
    1464           0 :         ml_enqueue(&sc->sc_tx_queue, m);
    1465           0 :         task_add(systq, &sc->sc_task);
    1466           0 :         return 0;
    1467           0 : }
    1468             : 
    1469             : #ifdef BWFM_DEBUG
    1470             : void
    1471             : bwfm_sdio_debug_console(struct bwfm_sdio_softc *sc)
    1472             : {
    1473             :         struct bwfm_sdio_console c;
    1474             :         uint32_t newidx;
    1475             :         int err;
    1476             : 
    1477             :         if (!sc->sc_console_addr)
    1478             :                 return;
    1479             : 
    1480             :         err = bwfm_sdio_ram_read_write(sc, sc->sc_console_addr,
    1481             :             (char *)&c, sizeof(c), 0);
    1482             :         if (err)
    1483             :                 return;
    1484             : 
    1485             :         c.log_buf = letoh32(c.log_buf);
    1486             :         c.log_bufsz = letoh32(c.log_bufsz);
    1487             :         c.log_idx = letoh32(c.log_idx);
    1488             : 
    1489             :         if (sc->sc_console_buf == NULL) {
    1490             :                 sc->sc_console_buf = malloc(c.log_bufsz, M_DEVBUF,
    1491             :                     M_WAITOK|M_ZERO);
    1492             :                 sc->sc_console_buf_size = c.log_bufsz;
    1493             :         }
    1494             : 
    1495             :         newidx = c.log_idx;
    1496             :         if (newidx >= sc->sc_console_buf_size)
    1497             :                 return;
    1498             : 
    1499             :         err = bwfm_sdio_ram_read_write(sc, c.log_buf, sc->sc_console_buf,
    1500             :             sc->sc_console_buf_size, 0);
    1501             :         if (err)
    1502             :                 return;
    1503             : 
    1504             :         if (newidx != sc->sc_console_readidx)
    1505             :                 DPRINTFN(3, ("BWFM CONSOLE: "));
    1506             :         while (newidx != sc->sc_console_readidx) {
    1507             :                 uint8_t ch = sc->sc_console_buf[sc->sc_console_readidx];
    1508             :                 sc->sc_console_readidx++;
    1509             :                 if (sc->sc_console_readidx == sc->sc_console_buf_size)
    1510             :                         sc->sc_console_readidx = 0;
    1511             :                 if (ch == '\r')
    1512             :                         continue;
    1513             :                 DPRINTFN(3, ("%c", ch));
    1514             :         }
    1515             : }
    1516             : #endif

Generated by: LCOV version 1.13