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