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