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