1*2b7bea7eSpatrick /* $OpenBSD: if_bwfm_pci.c,v 1.11 2018/01/08 17:57:48 patrick Exp $ */ 2e5ec1e72Spatrick /* 3e5ec1e72Spatrick * Copyright (c) 2010-2016 Broadcom Corporation 4e5ec1e72Spatrick * Copyright (c) 2017 Patrick Wildt <patrick@blueri.se> 5e5ec1e72Spatrick * 6e5ec1e72Spatrick * Permission to use, copy, modify, and/or distribute this software for any 7e5ec1e72Spatrick * purpose with or without fee is hereby granted, provided that the above 8e5ec1e72Spatrick * copyright notice and this permission notice appear in all copies. 9e5ec1e72Spatrick * 10e5ec1e72Spatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11e5ec1e72Spatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12e5ec1e72Spatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13e5ec1e72Spatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14e5ec1e72Spatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15e5ec1e72Spatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16e5ec1e72Spatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17e5ec1e72Spatrick */ 18e5ec1e72Spatrick 19e5ec1e72Spatrick #include "bpfilter.h" 20e5ec1e72Spatrick 21e5ec1e72Spatrick #include <sys/param.h> 22e5ec1e72Spatrick #include <sys/systm.h> 23e5ec1e72Spatrick #include <sys/buf.h> 24e5ec1e72Spatrick #include <sys/kernel.h> 25e5ec1e72Spatrick #include <sys/malloc.h> 26e5ec1e72Spatrick #include <sys/device.h> 27e5ec1e72Spatrick #include <sys/queue.h> 28e5ec1e72Spatrick #include <sys/socket.h> 29e5ec1e72Spatrick 30e5ec1e72Spatrick #if NBPFILTER > 0 31e5ec1e72Spatrick #include <net/bpf.h> 32e5ec1e72Spatrick #endif 33e5ec1e72Spatrick #include <net/if.h> 34e5ec1e72Spatrick #include <net/if_dl.h> 35e5ec1e72Spatrick #include <net/if_media.h> 36e5ec1e72Spatrick 37e5ec1e72Spatrick #include <netinet/in.h> 38e5ec1e72Spatrick #include <netinet/if_ether.h> 39e5ec1e72Spatrick 40e5ec1e72Spatrick #include <net80211/ieee80211_var.h> 41e5ec1e72Spatrick 42e5ec1e72Spatrick #include <machine/bus.h> 43e5ec1e72Spatrick 44e5ec1e72Spatrick #include <dev/pci/pcireg.h> 45e5ec1e72Spatrick #include <dev/pci/pcivar.h> 46e5ec1e72Spatrick #include <dev/pci/pcidevs.h> 47e5ec1e72Spatrick 48e5ec1e72Spatrick #include <dev/ic/bwfmvar.h> 49e5ec1e72Spatrick #include <dev/ic/bwfmreg.h> 50e5ec1e72Spatrick #include <dev/pci/if_bwfm_pci.h> 51e5ec1e72Spatrick 52e5ec1e72Spatrick #define BWFM_DMA_D2H_SCRATCH_BUF_LEN 8 53e5ec1e72Spatrick #define BWFM_DMA_D2H_RINGUPD_BUF_LEN 1024 54e5ec1e72Spatrick #define BWFM_DMA_H2D_IOCTL_BUF_LEN ETHER_MAX_LEN 55e5ec1e72Spatrick 56e5ec1e72Spatrick #define BWFM_NUM_TX_MSGRINGS 2 57e5ec1e72Spatrick #define BWFM_NUM_RX_MSGRINGS 3 58e5ec1e72Spatrick 59e5ec1e72Spatrick #define BWFM_NUM_TX_PKTIDS 2048 60e5ec1e72Spatrick #define BWFM_NUM_RX_PKTIDS 1024 61e5ec1e72Spatrick 62e5ec1e72Spatrick #define BWFM_NUM_TX_DESCS 1 63e5ec1e72Spatrick #define BWFM_NUM_RX_DESCS 1 64e5ec1e72Spatrick 65e5ec1e72Spatrick #ifdef BWFM_DEBUG 66e5ec1e72Spatrick #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0) 67e5ec1e72Spatrick #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0) 68e5ec1e72Spatrick static int bwfm_debug = 2; 69e5ec1e72Spatrick #else 70e5ec1e72Spatrick #define DPRINTF(x) do { ; } while (0) 71e5ec1e72Spatrick #define DPRINTFN(n, x) do { ; } while (0) 72e5ec1e72Spatrick #endif 73e5ec1e72Spatrick 74e5ec1e72Spatrick #define DEVNAME(sc) ((sc)->sc_sc.sc_dev.dv_xname) 75e5ec1e72Spatrick 76518be5f3Spatrick enum ring_status { 77518be5f3Spatrick RING_CLOSED, 78518be5f3Spatrick RING_CLOSING, 79518be5f3Spatrick RING_OPEN, 80518be5f3Spatrick RING_OPENING, 81518be5f3Spatrick }; 82518be5f3Spatrick 83e5ec1e72Spatrick struct bwfm_pci_msgring { 84e5ec1e72Spatrick uint32_t w_idx_addr; 85e5ec1e72Spatrick uint32_t r_idx_addr; 86e5ec1e72Spatrick uint32_t w_ptr; 87e5ec1e72Spatrick uint32_t r_ptr; 88e5ec1e72Spatrick int nitem; 89e5ec1e72Spatrick int itemsz; 90518be5f3Spatrick enum ring_status status; 91e5ec1e72Spatrick struct bwfm_pci_dmamem *ring; 92f67437f3Spatrick 93f67437f3Spatrick int fifo; 94f67437f3Spatrick uint8_t mac[ETHER_ADDR_LEN]; 95e5ec1e72Spatrick }; 96e5ec1e72Spatrick 97e5ec1e72Spatrick struct bwfm_pci_buf { 98e5ec1e72Spatrick bus_dmamap_t bb_map; 99e5ec1e72Spatrick struct mbuf *bb_m; 100e5ec1e72Spatrick }; 101e5ec1e72Spatrick 102e5ec1e72Spatrick struct bwfm_pci_pkts { 103e5ec1e72Spatrick struct bwfm_pci_buf *pkts; 104e5ec1e72Spatrick uint32_t npkt; 105e5ec1e72Spatrick int last; 106e5ec1e72Spatrick }; 107e5ec1e72Spatrick 108e5ec1e72Spatrick struct bwfm_pci_softc { 109e5ec1e72Spatrick struct bwfm_softc sc_sc; 110e5ec1e72Spatrick pci_chipset_tag_t sc_pc; 111e5ec1e72Spatrick pcitag_t sc_tag; 112e5ec1e72Spatrick pcireg_t sc_id; 113e5ec1e72Spatrick void *sc_ih; 114e5ec1e72Spatrick 115e5ec1e72Spatrick bus_space_tag_t sc_reg_iot; 116e5ec1e72Spatrick bus_space_handle_t sc_reg_ioh; 117e5ec1e72Spatrick bus_size_t sc_reg_ios; 118e5ec1e72Spatrick 119e5ec1e72Spatrick bus_space_tag_t sc_tcm_iot; 120e5ec1e72Spatrick bus_space_handle_t sc_tcm_ioh; 121e5ec1e72Spatrick bus_size_t sc_tcm_ios; 122e5ec1e72Spatrick 123e5ec1e72Spatrick bus_dma_tag_t sc_dmat; 124e5ec1e72Spatrick 125e5ec1e72Spatrick uint32_t sc_shared_address; 126e5ec1e72Spatrick uint32_t sc_shared_flags; 127e5ec1e72Spatrick uint8_t sc_shared_version; 128e5ec1e72Spatrick 129e5ec1e72Spatrick uint8_t sc_dma_idx_sz; 130e5ec1e72Spatrick struct bwfm_pci_dmamem *sc_dma_idx_buf; 131e5ec1e72Spatrick size_t sc_dma_idx_bufsz; 132e5ec1e72Spatrick 133e5ec1e72Spatrick uint16_t sc_max_rxbufpost; 134e5ec1e72Spatrick uint32_t sc_rx_dataoffset; 135e5ec1e72Spatrick uint32_t sc_htod_mb_data_addr; 136e5ec1e72Spatrick uint32_t sc_dtoh_mb_data_addr; 137e5ec1e72Spatrick uint32_t sc_ring_info_addr; 138e5ec1e72Spatrick 139e5ec1e72Spatrick uint32_t sc_console_base_addr; 140e5ec1e72Spatrick uint32_t sc_console_buf_addr; 141e5ec1e72Spatrick uint32_t sc_console_buf_size; 142cadf5fcfSpatrick uint32_t sc_console_readidx; 143e5ec1e72Spatrick 144e5ec1e72Spatrick uint16_t sc_max_flowrings; 145e5ec1e72Spatrick uint16_t sc_max_submissionrings; 146e5ec1e72Spatrick uint16_t sc_max_completionrings; 147e5ec1e72Spatrick 148e5ec1e72Spatrick struct bwfm_pci_msgring sc_ctrl_submit; 149e5ec1e72Spatrick struct bwfm_pci_msgring sc_rxpost_submit; 150e5ec1e72Spatrick struct bwfm_pci_msgring sc_ctrl_complete; 151e5ec1e72Spatrick struct bwfm_pci_msgring sc_tx_complete; 152e5ec1e72Spatrick struct bwfm_pci_msgring sc_rx_complete; 153e5ec1e72Spatrick struct bwfm_pci_msgring *sc_flowrings; 154e5ec1e72Spatrick 155e5ec1e72Spatrick struct bwfm_pci_dmamem *sc_scratch_buf; 156e5ec1e72Spatrick struct bwfm_pci_dmamem *sc_ringupd_buf; 157e5ec1e72Spatrick 158e5ec1e72Spatrick struct bwfm_pci_dmamem *sc_ioctl_buf; 159e5ec1e72Spatrick int sc_ioctl_reqid; 160e5ec1e72Spatrick uint32_t sc_ioctl_resp_pktid; 161e5ec1e72Spatrick uint32_t sc_ioctl_resp_ret_len; 162e5ec1e72Spatrick uint32_t sc_ioctl_resp_status; 163e5ec1e72Spatrick int sc_ioctl_poll; 164e5ec1e72Spatrick 165e5ec1e72Spatrick struct if_rxring sc_ioctl_ring; 166e5ec1e72Spatrick struct if_rxring sc_event_ring; 167e5ec1e72Spatrick struct if_rxring sc_rxbuf_ring; 168e5ec1e72Spatrick 169e5ec1e72Spatrick struct bwfm_pci_pkts sc_tx_pkts; 170e5ec1e72Spatrick struct bwfm_pci_pkts sc_rx_pkts; 171e5ec1e72Spatrick }; 172e5ec1e72Spatrick 173e5ec1e72Spatrick struct bwfm_pci_dmamem { 174e5ec1e72Spatrick bus_dmamap_t bdm_map; 175e5ec1e72Spatrick bus_dma_segment_t bdm_seg; 176e5ec1e72Spatrick size_t bdm_size; 177e5ec1e72Spatrick caddr_t bdm_kva; 178e5ec1e72Spatrick }; 179e5ec1e72Spatrick 180e5ec1e72Spatrick #define BWFM_PCI_DMA_MAP(_bdm) ((_bdm)->bdm_map) 181e5ec1e72Spatrick #define BWFM_PCI_DMA_LEN(_bdm) ((_bdm)->bdm_size) 182e5ec1e72Spatrick #define BWFM_PCI_DMA_DVA(_bdm) ((_bdm)->bdm_map->dm_segs[0].ds_addr) 183e5ec1e72Spatrick #define BWFM_PCI_DMA_KVA(_bdm) ((void *)(_bdm)->bdm_kva) 184e5ec1e72Spatrick 185e5ec1e72Spatrick int bwfm_pci_match(struct device *, void *, void *); 186e5ec1e72Spatrick void bwfm_pci_attachhook(struct device *); 187e5ec1e72Spatrick void bwfm_pci_attach(struct device *, struct device *, void *); 188e5ec1e72Spatrick int bwfm_pci_detach(struct device *, int); 189e5ec1e72Spatrick 190e5ec1e72Spatrick int bwfm_pci_intr(void *); 191e5ec1e72Spatrick void bwfm_pci_intr_enable(struct bwfm_pci_softc *); 192e5ec1e72Spatrick void bwfm_pci_intr_disable(struct bwfm_pci_softc *); 193e5ec1e72Spatrick int bwfm_pci_load_microcode(struct bwfm_pci_softc *, const u_char *, 194e5ec1e72Spatrick size_t); 195e5ec1e72Spatrick void bwfm_pci_select_core(struct bwfm_pci_softc *, int ); 196e5ec1e72Spatrick 197e5ec1e72Spatrick struct bwfm_pci_dmamem * 198e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *, bus_size_t, 199e5ec1e72Spatrick bus_size_t); 200e5ec1e72Spatrick void bwfm_pci_dmamem_free(struct bwfm_pci_softc *, struct bwfm_pci_dmamem *); 201e5ec1e72Spatrick int bwfm_pci_pktid_new(struct bwfm_pci_softc *, 202e5ec1e72Spatrick struct bwfm_pci_pkts *, struct mbuf *, 203e5ec1e72Spatrick uint32_t *, paddr_t *); 204e5ec1e72Spatrick struct mbuf * bwfm_pci_pktid_free(struct bwfm_pci_softc *, 205e5ec1e72Spatrick struct bwfm_pci_pkts *, uint32_t); 206e5ec1e72Spatrick void bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *, 207e5ec1e72Spatrick struct if_rxring *, uint32_t); 208e5ec1e72Spatrick void bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *); 209e5ec1e72Spatrick void bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *); 210e5ec1e72Spatrick int bwfm_pci_setup_ring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *, 211e5ec1e72Spatrick int, size_t, uint32_t, uint32_t, int, uint32_t, uint32_t *); 212518be5f3Spatrick int bwfm_pci_setup_flowring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *, 213518be5f3Spatrick int, size_t); 214e5ec1e72Spatrick 215e5ec1e72Spatrick void bwfm_pci_ring_bell(struct bwfm_pci_softc *, 216e5ec1e72Spatrick struct bwfm_pci_msgring *); 217e5ec1e72Spatrick void bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *, 218e5ec1e72Spatrick struct bwfm_pci_msgring *); 219e5ec1e72Spatrick void bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *, 220e5ec1e72Spatrick struct bwfm_pci_msgring *); 221e5ec1e72Spatrick void bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *, 222e5ec1e72Spatrick struct bwfm_pci_msgring *); 223e5ec1e72Spatrick void bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *, 224e5ec1e72Spatrick struct bwfm_pci_msgring *); 225e5ec1e72Spatrick void * bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *, 226e5ec1e72Spatrick struct bwfm_pci_msgring *); 227e5ec1e72Spatrick void * bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *, 228e5ec1e72Spatrick struct bwfm_pci_msgring *, int, int *); 229e5ec1e72Spatrick void * bwfm_pci_ring_read_avail(struct bwfm_pci_softc *, 230e5ec1e72Spatrick struct bwfm_pci_msgring *, int *); 231e5ec1e72Spatrick void bwfm_pci_ring_read_commit(struct bwfm_pci_softc *, 232e5ec1e72Spatrick struct bwfm_pci_msgring *, int); 233e5ec1e72Spatrick void bwfm_pci_ring_write_commit(struct bwfm_pci_softc *, 234e5ec1e72Spatrick struct bwfm_pci_msgring *); 235e5ec1e72Spatrick void bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *, 236e5ec1e72Spatrick struct bwfm_pci_msgring *, int); 237e5ec1e72Spatrick 238e5ec1e72Spatrick void bwfm_pci_ring_rx(struct bwfm_pci_softc *, 239e5ec1e72Spatrick struct bwfm_pci_msgring *); 240e5ec1e72Spatrick void bwfm_pci_msg_rx(struct bwfm_pci_softc *, void *); 241e5ec1e72Spatrick 242e5ec1e72Spatrick uint32_t bwfm_pci_buscore_read(struct bwfm_softc *, uint32_t); 243e5ec1e72Spatrick void bwfm_pci_buscore_write(struct bwfm_softc *, uint32_t, 244e5ec1e72Spatrick uint32_t); 245e5ec1e72Spatrick int bwfm_pci_buscore_prepare(struct bwfm_softc *); 246e5ec1e72Spatrick int bwfm_pci_buscore_reset(struct bwfm_softc *); 247e5ec1e72Spatrick void bwfm_pci_buscore_activate(struct bwfm_softc *, uint32_t); 248e5ec1e72Spatrick 249f67437f3Spatrick int bwfm_pci_flowring_lookup(struct bwfm_pci_softc *, 250f67437f3Spatrick struct mbuf *); 251f67437f3Spatrick void bwfm_pci_flowring_create(struct bwfm_pci_softc *, 252518be5f3Spatrick struct mbuf *); 253518be5f3Spatrick void bwfm_pci_flowring_create_cb(struct bwfm_softc *, void *); 254a2c6ff8bSpatrick void bwfm_pci_flowring_delete(struct bwfm_pci_softc *, int); 255518be5f3Spatrick 256a2c6ff8bSpatrick void bwfm_pci_stop(struct bwfm_softc *); 257e5ec1e72Spatrick int bwfm_pci_txdata(struct bwfm_softc *, struct mbuf *); 258bbd71b0bSpatrick 259bbd71b0bSpatrick #ifdef BWFM_DEBUG 260cadf5fcfSpatrick void bwfm_pci_debug_console(struct bwfm_pci_softc *); 261bbd71b0bSpatrick #endif 262e5ec1e72Spatrick 263e5ec1e72Spatrick int bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *, int, 264e5ec1e72Spatrick int, char *, size_t *); 265e5ec1e72Spatrick int bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *, int, 266e5ec1e72Spatrick int, char *, size_t); 267e5ec1e72Spatrick 268e5ec1e72Spatrick struct bwfm_buscore_ops bwfm_pci_buscore_ops = { 269e5ec1e72Spatrick .bc_read = bwfm_pci_buscore_read, 270e5ec1e72Spatrick .bc_write = bwfm_pci_buscore_write, 271e5ec1e72Spatrick .bc_prepare = bwfm_pci_buscore_prepare, 272e5ec1e72Spatrick .bc_reset = bwfm_pci_buscore_reset, 273e5ec1e72Spatrick .bc_setup = NULL, 274e5ec1e72Spatrick .bc_activate = bwfm_pci_buscore_activate, 275e5ec1e72Spatrick }; 276e5ec1e72Spatrick 277e5ec1e72Spatrick struct bwfm_bus_ops bwfm_pci_bus_ops = { 278e5ec1e72Spatrick .bs_init = NULL, 279a2c6ff8bSpatrick .bs_stop = bwfm_pci_stop, 280e5ec1e72Spatrick .bs_txdata = bwfm_pci_txdata, 281e5ec1e72Spatrick .bs_txctl = NULL, 282e5ec1e72Spatrick .bs_rxctl = NULL, 283e5ec1e72Spatrick }; 284e5ec1e72Spatrick 285e5ec1e72Spatrick struct bwfm_proto_ops bwfm_pci_msgbuf_ops = { 286e5ec1e72Spatrick .proto_query_dcmd = bwfm_pci_msgbuf_query_dcmd, 287e5ec1e72Spatrick .proto_set_dcmd = bwfm_pci_msgbuf_set_dcmd, 288e5ec1e72Spatrick }; 289e5ec1e72Spatrick 290e5ec1e72Spatrick struct cfattach bwfm_pci_ca = { 291e5ec1e72Spatrick sizeof(struct bwfm_pci_softc), 292e5ec1e72Spatrick bwfm_pci_match, 293e5ec1e72Spatrick bwfm_pci_attach, 294e5ec1e72Spatrick bwfm_pci_detach, 295e5ec1e72Spatrick }; 296e5ec1e72Spatrick 297e5ec1e72Spatrick static const struct pci_matchid bwfm_pci_devices[] = { 298e5ec1e72Spatrick { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43602 }, 299e5ec1e72Spatrick }; 300e5ec1e72Spatrick 301e5ec1e72Spatrick int 302e5ec1e72Spatrick bwfm_pci_match(struct device *parent, void *match, void *aux) 303e5ec1e72Spatrick { 304e5ec1e72Spatrick return (pci_matchbyid(aux, bwfm_pci_devices, 305e5ec1e72Spatrick nitems(bwfm_pci_devices))); 306e5ec1e72Spatrick } 307e5ec1e72Spatrick 308e5ec1e72Spatrick void 309e5ec1e72Spatrick bwfm_pci_attach(struct device *parent, struct device *self, void *aux) 310e5ec1e72Spatrick { 311e5ec1e72Spatrick struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self; 312e5ec1e72Spatrick struct pci_attach_args *pa = (struct pci_attach_args *)aux; 313e5ec1e72Spatrick const char *intrstr; 314e5ec1e72Spatrick pci_intr_handle_t ih; 315e5ec1e72Spatrick 316e5ec1e72Spatrick if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x00, 317e5ec1e72Spatrick PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_reg_iot, &sc->sc_reg_ioh, 318e5ec1e72Spatrick NULL, &sc->sc_reg_ios, 0)) { 319e5ec1e72Spatrick printf(": can't map bar0\n"); 320e5ec1e72Spatrick return; 321e5ec1e72Spatrick } 322e5ec1e72Spatrick 323e5ec1e72Spatrick if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x08, 324e5ec1e72Spatrick PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_tcm_iot, &sc->sc_tcm_ioh, 325e5ec1e72Spatrick NULL, &sc->sc_tcm_ios, 0)) { 326e5ec1e72Spatrick printf(": can't map bar1\n"); 327e5ec1e72Spatrick goto bar0; 328e5ec1e72Spatrick } 329e5ec1e72Spatrick 330e5ec1e72Spatrick sc->sc_pc = pa->pa_pc; 331e5ec1e72Spatrick sc->sc_tag = pa->pa_tag; 332e5ec1e72Spatrick sc->sc_id = pa->pa_id; 333e5ec1e72Spatrick sc->sc_dmat = pa->pa_dmat; 334e5ec1e72Spatrick 335e5ec1e72Spatrick /* Map and establish the interrupt. */ 336e5ec1e72Spatrick if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) { 337e5ec1e72Spatrick printf(": couldn't map interrupt\n"); 338e5ec1e72Spatrick goto bar1; 339e5ec1e72Spatrick } 340e5ec1e72Spatrick intrstr = pci_intr_string(pa->pa_pc, ih); 341e5ec1e72Spatrick 342e5ec1e72Spatrick sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET | IPL_MPSAFE, 343e5ec1e72Spatrick bwfm_pci_intr, sc, DEVNAME(sc)); 344e5ec1e72Spatrick if (sc->sc_ih == NULL) { 345e5ec1e72Spatrick printf(": couldn't establish interrupt"); 346e5ec1e72Spatrick if (intrstr != NULL) 347e5ec1e72Spatrick printf(" at %s", intrstr); 348e5ec1e72Spatrick printf("\n"); 349e5ec1e72Spatrick goto bar1; 350e5ec1e72Spatrick } 351e5ec1e72Spatrick printf(": %s\n", intrstr); 352e5ec1e72Spatrick 353e5ec1e72Spatrick config_mountroot(self, bwfm_pci_attachhook); 354e5ec1e72Spatrick return; 355e5ec1e72Spatrick 356e5ec1e72Spatrick bar1: 357e5ec1e72Spatrick bus_space_unmap(sc->sc_tcm_iot, sc->sc_tcm_ioh, sc->sc_tcm_ios); 358e5ec1e72Spatrick bar0: 359e5ec1e72Spatrick bus_space_unmap(sc->sc_reg_iot, sc->sc_reg_ioh, sc->sc_reg_ios); 360e5ec1e72Spatrick } 361e5ec1e72Spatrick 362e5ec1e72Spatrick void 363e5ec1e72Spatrick bwfm_pci_attachhook(struct device *self) 364e5ec1e72Spatrick { 365e5ec1e72Spatrick struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self; 366e5ec1e72Spatrick struct bwfm_softc *bwfm = (void *)sc; 367e5ec1e72Spatrick struct bwfm_pci_ringinfo ringinfo; 368e5ec1e72Spatrick const char *name = NULL; 369e5ec1e72Spatrick u_char *ucode; size_t size; 370e5ec1e72Spatrick uint32_t d2h_w_idx_ptr, d2h_r_idx_ptr; 371e5ec1e72Spatrick uint32_t h2d_w_idx_ptr, h2d_r_idx_ptr; 372e5ec1e72Spatrick uint32_t idx_offset, reg; 373e5ec1e72Spatrick int i; 374e5ec1e72Spatrick 375e5ec1e72Spatrick sc->sc_sc.sc_buscore_ops = &bwfm_pci_buscore_ops; 376e5ec1e72Spatrick if (bwfm_chip_attach(&sc->sc_sc) != 0) { 377e5ec1e72Spatrick printf("%s: cannot attach chip\n", DEVNAME(sc)); 378e5ec1e72Spatrick return; 379e5ec1e72Spatrick } 380e5ec1e72Spatrick 381e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2); 382e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 383e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGADDR, 0x4e0); 384e5ec1e72Spatrick reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 385e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA); 386e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 387e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA, reg); 388e5ec1e72Spatrick 389e5ec1e72Spatrick switch (bwfm->sc_chip.ch_chip) 390e5ec1e72Spatrick { 391e5ec1e72Spatrick case BRCM_CC_43602_CHIP_ID: 392e5ec1e72Spatrick name = "brcmfmac43602-pcie.bin"; 393e5ec1e72Spatrick break; 394e5ec1e72Spatrick default: 395e5ec1e72Spatrick break; 396e5ec1e72Spatrick } 397e5ec1e72Spatrick 398e5ec1e72Spatrick if (name == NULL) { 399e5ec1e72Spatrick printf("%s: unknown firmware\n", DEVNAME(sc)); 400e5ec1e72Spatrick return; 401e5ec1e72Spatrick } 402e5ec1e72Spatrick 403e5ec1e72Spatrick if (loadfirmware(name, &ucode, &size) != 0) { 404e5ec1e72Spatrick printf("%s: failed loadfirmware of file %s\n", 405e5ec1e72Spatrick DEVNAME(sc), name); 406e5ec1e72Spatrick return; 407e5ec1e72Spatrick } 408e5ec1e72Spatrick 409e5ec1e72Spatrick /* Retrieve RAM size from firmware. */ 410e5ec1e72Spatrick if (size >= BWFM_RAMSIZE + 8) { 411e5ec1e72Spatrick uint32_t *ramsize = (uint32_t *)&ucode[BWFM_RAMSIZE]; 412e5ec1e72Spatrick if (letoh32(ramsize[0]) == BWFM_RAMSIZE_MAGIC) 413e5ec1e72Spatrick bwfm->sc_chip.ch_ramsize = letoh32(ramsize[1]); 414e5ec1e72Spatrick } 415e5ec1e72Spatrick 416e5ec1e72Spatrick if (bwfm_pci_load_microcode(sc, ucode, size) != 0) { 417e5ec1e72Spatrick printf("%s: could not load microcode\n", 418e5ec1e72Spatrick DEVNAME(sc)); 419e5ec1e72Spatrick free(ucode, M_DEVBUF, size); 420e5ec1e72Spatrick return; 421e5ec1e72Spatrick } 422e5ec1e72Spatrick free(ucode, M_DEVBUF, size); 423e5ec1e72Spatrick 424e5ec1e72Spatrick sc->sc_shared_flags = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 425e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_INFO); 426e5ec1e72Spatrick sc->sc_shared_version = sc->sc_shared_flags; 427e5ec1e72Spatrick if (sc->sc_shared_version > BWFM_SHARED_INFO_MAX_VERSION || 428e5ec1e72Spatrick sc->sc_shared_version < BWFM_SHARED_INFO_MIN_VERSION) { 429e5ec1e72Spatrick printf("%s: PCIe version %d unsupported\n", 430e5ec1e72Spatrick DEVNAME(sc), sc->sc_shared_version); 431e5ec1e72Spatrick return; 432e5ec1e72Spatrick } 433e5ec1e72Spatrick 434e5ec1e72Spatrick if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_INDEX) { 435e5ec1e72Spatrick if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_2B_IDX) 436e5ec1e72Spatrick sc->sc_dma_idx_sz = sizeof(uint16_t); 437e5ec1e72Spatrick else 438e5ec1e72Spatrick sc->sc_dma_idx_sz = sizeof(uint32_t); 439e5ec1e72Spatrick } 440e5ec1e72Spatrick 441e5ec1e72Spatrick /* Maximum RX data buffers in the ring. */ 442e5ec1e72Spatrick sc->sc_max_rxbufpost = bus_space_read_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 443e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_MAX_RXBUFPOST); 444e5ec1e72Spatrick if (sc->sc_max_rxbufpost == 0) 445e5ec1e72Spatrick sc->sc_max_rxbufpost = BWFM_SHARED_MAX_RXBUFPOST_DEFAULT; 446e5ec1e72Spatrick 447e5ec1e72Spatrick /* Alternative offset of data in a packet */ 448e5ec1e72Spatrick sc->sc_rx_dataoffset = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 449e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_RX_DATAOFFSET); 450e5ec1e72Spatrick 451e5ec1e72Spatrick /* For Power Management */ 452e5ec1e72Spatrick sc->sc_htod_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 453e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_HTOD_MB_DATA_ADDR); 454e5ec1e72Spatrick sc->sc_dtoh_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 455e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DTOH_MB_DATA_ADDR); 456e5ec1e72Spatrick 457e5ec1e72Spatrick /* Ring information */ 458e5ec1e72Spatrick sc->sc_ring_info_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 459e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_RING_INFO_ADDR); 460e5ec1e72Spatrick 461e5ec1e72Spatrick /* Firmware's "dmesg" */ 462e5ec1e72Spatrick sc->sc_console_base_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 463e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_CONSOLE_ADDR); 464e5ec1e72Spatrick sc->sc_console_buf_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 465e5ec1e72Spatrick sc->sc_console_base_addr + BWFM_CONSOLE_BUFADDR); 466e5ec1e72Spatrick sc->sc_console_buf_size = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 467e5ec1e72Spatrick sc->sc_console_base_addr + BWFM_CONSOLE_BUFSIZE); 468e5ec1e72Spatrick 469e5ec1e72Spatrick /* Read ring information. */ 470e5ec1e72Spatrick bus_space_read_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 471e5ec1e72Spatrick sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo)); 472e5ec1e72Spatrick 473e5ec1e72Spatrick if (sc->sc_shared_version >= 6) { 474e5ec1e72Spatrick sc->sc_max_submissionrings = le16toh(ringinfo.max_submissionrings); 475e5ec1e72Spatrick sc->sc_max_flowrings = le16toh(ringinfo.max_flowrings); 476e5ec1e72Spatrick sc->sc_max_completionrings = le16toh(ringinfo.max_completionrings); 477e5ec1e72Spatrick } else { 478e5ec1e72Spatrick sc->sc_max_submissionrings = le16toh(ringinfo.max_flowrings); 479e5ec1e72Spatrick sc->sc_max_flowrings = sc->sc_max_submissionrings - 480e5ec1e72Spatrick BWFM_NUM_TX_MSGRINGS; 481e5ec1e72Spatrick sc->sc_max_completionrings = BWFM_NUM_RX_MSGRINGS; 482e5ec1e72Spatrick } 483e5ec1e72Spatrick 484e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 485e5ec1e72Spatrick d2h_w_idx_ptr = letoh32(ringinfo.d2h_w_idx_ptr); 486e5ec1e72Spatrick d2h_r_idx_ptr = letoh32(ringinfo.d2h_r_idx_ptr); 487e5ec1e72Spatrick h2d_w_idx_ptr = letoh32(ringinfo.h2d_w_idx_ptr); 488e5ec1e72Spatrick h2d_r_idx_ptr = letoh32(ringinfo.h2d_r_idx_ptr); 489e5ec1e72Spatrick idx_offset = sizeof(uint32_t); 490e5ec1e72Spatrick } else { 491e5ec1e72Spatrick uint64_t address; 492e5ec1e72Spatrick 493e5ec1e72Spatrick /* Each TX/RX Ring has a Read and Write Ptr */ 494e5ec1e72Spatrick sc->sc_dma_idx_bufsz = (sc->sc_max_submissionrings + 495e5ec1e72Spatrick sc->sc_max_completionrings) * sc->sc_dma_idx_sz * 2; 496e5ec1e72Spatrick sc->sc_dma_idx_buf = bwfm_pci_dmamem_alloc(sc, 497e5ec1e72Spatrick sc->sc_dma_idx_bufsz, 8); 498e5ec1e72Spatrick if (sc->sc_dma_idx_buf == NULL) { 499e5ec1e72Spatrick /* XXX: Fallback to TCM? */ 500e5ec1e72Spatrick printf("%s: cannot allocate idx buf\n", 501e5ec1e72Spatrick DEVNAME(sc)); 502e5ec1e72Spatrick return; 503e5ec1e72Spatrick } 504e5ec1e72Spatrick 505e5ec1e72Spatrick idx_offset = sc->sc_dma_idx_sz; 506e5ec1e72Spatrick h2d_w_idx_ptr = 0; 507e5ec1e72Spatrick address = BWFM_PCI_DMA_DVA(sc->sc_dma_idx_buf); 508e5ec1e72Spatrick ringinfo.h2d_w_idx_hostaddr_low = 509e5ec1e72Spatrick htole32(address & 0xffffffff); 510e5ec1e72Spatrick ringinfo.h2d_w_idx_hostaddr_high = 511e5ec1e72Spatrick htole32(address >> 32); 512e5ec1e72Spatrick 513e5ec1e72Spatrick h2d_r_idx_ptr = h2d_w_idx_ptr + 514e5ec1e72Spatrick sc->sc_max_submissionrings * idx_offset; 515e5ec1e72Spatrick address += sc->sc_max_submissionrings * idx_offset; 516e5ec1e72Spatrick ringinfo.h2d_r_idx_hostaddr_low = 517e5ec1e72Spatrick htole32(address & 0xffffffff); 518e5ec1e72Spatrick ringinfo.h2d_r_idx_hostaddr_high = 519e5ec1e72Spatrick htole32(address >> 32); 520e5ec1e72Spatrick 521e5ec1e72Spatrick d2h_w_idx_ptr = h2d_r_idx_ptr + 522e5ec1e72Spatrick sc->sc_max_submissionrings * idx_offset; 523e5ec1e72Spatrick address += sc->sc_max_submissionrings * idx_offset; 524e5ec1e72Spatrick ringinfo.d2h_w_idx_hostaddr_low = 525e5ec1e72Spatrick htole32(address & 0xffffffff); 526e5ec1e72Spatrick ringinfo.d2h_w_idx_hostaddr_high = 527e5ec1e72Spatrick htole32(address >> 32); 528e5ec1e72Spatrick 529e5ec1e72Spatrick d2h_r_idx_ptr = d2h_w_idx_ptr + 530e5ec1e72Spatrick sc->sc_max_completionrings * idx_offset; 531e5ec1e72Spatrick address += sc->sc_max_completionrings * idx_offset; 532e5ec1e72Spatrick ringinfo.d2h_r_idx_hostaddr_low = 533e5ec1e72Spatrick htole32(address & 0xffffffff); 534e5ec1e72Spatrick ringinfo.d2h_r_idx_hostaddr_high = 535e5ec1e72Spatrick htole32(address >> 32); 536e5ec1e72Spatrick 537e5ec1e72Spatrick bus_space_write_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 538e5ec1e72Spatrick sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo)); 539e5ec1e72Spatrick } 540e5ec1e72Spatrick 541e5ec1e72Spatrick uint32_t ring_mem_ptr = letoh32(ringinfo.ringmem); 542e5ec1e72Spatrick /* TX ctrl ring: Send ctrl buffers, send IOCTLs */ 543e5ec1e72Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_submit, 64, 40, 544e5ec1e72Spatrick h2d_w_idx_ptr, h2d_r_idx_ptr, 0, idx_offset, 545e5ec1e72Spatrick &ring_mem_ptr)) 546e5ec1e72Spatrick goto cleanup; 547e5ec1e72Spatrick /* TX rxpost ring: Send clean data mbufs for RX */ 548e5ec1e72Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_rxpost_submit, 512, 32, 549e5ec1e72Spatrick h2d_w_idx_ptr, h2d_r_idx_ptr, 1, idx_offset, 550e5ec1e72Spatrick &ring_mem_ptr)) 551e5ec1e72Spatrick goto cleanup; 552e5ec1e72Spatrick /* RX completion rings: recv our filled buffers back */ 553e5ec1e72Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_complete, 64, 24, 554e5ec1e72Spatrick d2h_w_idx_ptr, d2h_r_idx_ptr, 0, idx_offset, 555e5ec1e72Spatrick &ring_mem_ptr)) 556e5ec1e72Spatrick goto cleanup; 557e5ec1e72Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_tx_complete, 1024, 16, 558e5ec1e72Spatrick d2h_w_idx_ptr, d2h_r_idx_ptr, 1, idx_offset, 559e5ec1e72Spatrick &ring_mem_ptr)) 560e5ec1e72Spatrick goto cleanup; 561e5ec1e72Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_rx_complete, 512, 32, 562e5ec1e72Spatrick d2h_w_idx_ptr, d2h_r_idx_ptr, 2, idx_offset, 563e5ec1e72Spatrick &ring_mem_ptr)) 564e5ec1e72Spatrick goto cleanup; 565e5ec1e72Spatrick 566e5ec1e72Spatrick /* Dynamic TX rings for actual data */ 567e5ec1e72Spatrick sc->sc_flowrings = malloc(sc->sc_max_flowrings * 568e5ec1e72Spatrick sizeof(struct bwfm_pci_msgring), M_DEVBUF, M_WAITOK | M_ZERO); 569518be5f3Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 570518be5f3Spatrick struct bwfm_pci_msgring *ring = &sc->sc_flowrings[i]; 571518be5f3Spatrick ring->w_idx_addr = h2d_w_idx_ptr + (i + 2) * idx_offset; 572518be5f3Spatrick ring->r_idx_addr = h2d_r_idx_ptr + (i + 2) * idx_offset; 573518be5f3Spatrick } 574e5ec1e72Spatrick 575e5ec1e72Spatrick /* Scratch and ring update buffers for firmware */ 576e5ec1e72Spatrick if ((sc->sc_scratch_buf = bwfm_pci_dmamem_alloc(sc, 577e5ec1e72Spatrick BWFM_DMA_D2H_SCRATCH_BUF_LEN, 8)) == NULL) 578e5ec1e72Spatrick goto cleanup; 579e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 580e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_LOW, 581e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) & 0xffffffff); 582e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 583e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_HIGH, 584e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) >> 32); 585e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 586e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_LEN, 587e5ec1e72Spatrick BWFM_DMA_D2H_SCRATCH_BUF_LEN); 588e5ec1e72Spatrick 589e5ec1e72Spatrick if ((sc->sc_ringupd_buf = bwfm_pci_dmamem_alloc(sc, 590e5ec1e72Spatrick BWFM_DMA_D2H_RINGUPD_BUF_LEN, 8)) == NULL) 591e5ec1e72Spatrick goto cleanup; 592e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 593e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_LOW, 594e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) & 0xffffffff); 595e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 596e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_HIGH, 597e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) >> 32); 598e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 599e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_LEN, 600e5ec1e72Spatrick BWFM_DMA_D2H_RINGUPD_BUF_LEN); 601e5ec1e72Spatrick 602e5ec1e72Spatrick if ((sc->sc_ioctl_buf = bwfm_pci_dmamem_alloc(sc, 603e5ec1e72Spatrick BWFM_DMA_H2D_IOCTL_BUF_LEN, 8)) == NULL) 604e5ec1e72Spatrick goto cleanup; 605e5ec1e72Spatrick 606e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2); 607e5ec1e72Spatrick bwfm_pci_intr_enable(sc); 608e5ec1e72Spatrick 609e5ec1e72Spatrick /* Maps RX mbufs to a packet id and back. */ 610e5ec1e72Spatrick sc->sc_rx_pkts.npkt = BWFM_NUM_RX_PKTIDS; 611e5ec1e72Spatrick sc->sc_rx_pkts.pkts = malloc(BWFM_NUM_RX_PKTIDS * 612e5ec1e72Spatrick sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO); 613e5ec1e72Spatrick for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++) 614e5ec1e72Spatrick bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE, 615e5ec1e72Spatrick BWFM_NUM_RX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK, 616e5ec1e72Spatrick &sc->sc_rx_pkts.pkts[i].bb_map); 617e5ec1e72Spatrick sc->sc_tx_pkts.npkt = BWFM_NUM_TX_PKTIDS; 618e5ec1e72Spatrick 619e5ec1e72Spatrick /* Maps TX mbufs to a packet id and back. */ 620e5ec1e72Spatrick sc->sc_tx_pkts.pkts = malloc(BWFM_NUM_TX_PKTIDS 621e5ec1e72Spatrick * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO); 622e5ec1e72Spatrick for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++) 623e5ec1e72Spatrick bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE, 624e5ec1e72Spatrick BWFM_NUM_TX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK, 625e5ec1e72Spatrick &sc->sc_tx_pkts.pkts[i].bb_map); 626e5ec1e72Spatrick 62718722113Spatrick /* 62818722113Spatrick * For whatever reason, could also be a bug somewhere in this 62918722113Spatrick * driver, the firmware needs a bunch of RX buffers otherwise 63018722113Spatrick * it won't send any RX complete messages. 64 buffers don't 63118722113Spatrick * suffice, but 128 buffers are enough. 63218722113Spatrick */ 63318722113Spatrick if_rxr_init(&sc->sc_rxbuf_ring, 128, sc->sc_max_rxbufpost); 634e5ec1e72Spatrick if_rxr_init(&sc->sc_ioctl_ring, 8, 8); 635e5ec1e72Spatrick if_rxr_init(&sc->sc_event_ring, 8, 8); 636e5ec1e72Spatrick bwfm_pci_fill_rx_rings(sc); 637e5ec1e72Spatrick 638cadf5fcfSpatrick #ifdef BWFM_DEBUG 639cadf5fcfSpatrick sc->sc_console_readidx = 0; 640cadf5fcfSpatrick bwfm_pci_debug_console(sc); 641cadf5fcfSpatrick #endif 642cadf5fcfSpatrick 643e5ec1e72Spatrick sc->sc_ioctl_poll = 1; 644e5ec1e72Spatrick sc->sc_sc.sc_bus_ops = &bwfm_pci_bus_ops; 645e5ec1e72Spatrick sc->sc_sc.sc_proto_ops = &bwfm_pci_msgbuf_ops; 646e5ec1e72Spatrick bwfm_attach(&sc->sc_sc); 647e5ec1e72Spatrick sc->sc_ioctl_poll = 0; 648e5ec1e72Spatrick return; 649e5ec1e72Spatrick 650e5ec1e72Spatrick cleanup: 651e5ec1e72Spatrick if (sc->sc_ioctl_buf) 652e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ioctl_buf); 653e5ec1e72Spatrick if (sc->sc_ringupd_buf) 654e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf); 655e5ec1e72Spatrick if (sc->sc_scratch_buf) 656e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf); 657e5ec1e72Spatrick if (sc->sc_rx_complete.ring) 658e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring); 659e5ec1e72Spatrick if (sc->sc_tx_complete.ring) 660e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring); 661e5ec1e72Spatrick if (sc->sc_ctrl_complete.ring) 662e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring); 663e5ec1e72Spatrick if (sc->sc_rxpost_submit.ring) 664e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring); 665e5ec1e72Spatrick if (sc->sc_ctrl_submit.ring) 666e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring); 667e5ec1e72Spatrick if (sc->sc_dma_idx_buf) 668e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf); 669e5ec1e72Spatrick } 670e5ec1e72Spatrick 671e5ec1e72Spatrick int 672e5ec1e72Spatrick bwfm_pci_load_microcode(struct bwfm_pci_softc *sc, const u_char *ucode, size_t size) 673e5ec1e72Spatrick { 674e5ec1e72Spatrick struct bwfm_softc *bwfm = (void *)sc; 675e5ec1e72Spatrick struct bwfm_core *core; 676e5ec1e72Spatrick uint32_t shared; 677e5ec1e72Spatrick int i; 678e5ec1e72Spatrick 679e5ec1e72Spatrick if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) { 680e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_ARM_CR4); 681e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 682e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKIDX, 5); 683e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 684e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKPDA, 0); 685e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 686e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKIDX, 7); 687e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 688e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKPDA, 0); 689e5ec1e72Spatrick } 690e5ec1e72Spatrick 691e5ec1e72Spatrick for (i = 0; i < size; i++) 692e5ec1e72Spatrick bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 693e5ec1e72Spatrick bwfm->sc_chip.ch_rambase + i, ucode[i]); 694e5ec1e72Spatrick 695e5ec1e72Spatrick /* Firmware replaces this with a pointer once up. */ 696e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 697e5ec1e72Spatrick bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4, 0); 698e5ec1e72Spatrick 699e5ec1e72Spatrick /* TODO: restore NVRAM */ 700e5ec1e72Spatrick 701e5ec1e72Spatrick /* Load reset vector from firmware and kickstart core. */ 702e5ec1e72Spatrick core = bwfm_chip_get_core(bwfm, BWFM_AGENT_INTERNAL_MEM); 703e5ec1e72Spatrick bwfm->sc_chip.ch_core_reset(bwfm, core, 0, 0, 0); 704e5ec1e72Spatrick bwfm_chip_set_active(bwfm, *(uint32_t *)ucode); 705e5ec1e72Spatrick 706e5ec1e72Spatrick for (i = 0; i < 40; i++) { 707e5ec1e72Spatrick delay(50 * 1000); 708e5ec1e72Spatrick shared = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 709e5ec1e72Spatrick bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4); 710e5ec1e72Spatrick if (shared) 711e5ec1e72Spatrick break; 712e5ec1e72Spatrick } 713e5ec1e72Spatrick if (!shared) { 714e5ec1e72Spatrick printf("%s: firmware did not come up\n", DEVNAME(sc)); 715e5ec1e72Spatrick return 1; 716e5ec1e72Spatrick } 717e5ec1e72Spatrick 718e5ec1e72Spatrick sc->sc_shared_address = shared; 719e5ec1e72Spatrick return 0; 720e5ec1e72Spatrick } 721e5ec1e72Spatrick 722e5ec1e72Spatrick int 723e5ec1e72Spatrick bwfm_pci_detach(struct device *self, int flags) 724e5ec1e72Spatrick { 725e5ec1e72Spatrick struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self; 726e5ec1e72Spatrick 727e5ec1e72Spatrick bwfm_detach(&sc->sc_sc, flags); 728e5ec1e72Spatrick 729e5ec1e72Spatrick /* FIXME: free RX buffers */ 730e5ec1e72Spatrick /* FIXME: free TX buffers */ 731e5ec1e72Spatrick /* FIXME: free more memory */ 732e5ec1e72Spatrick 733e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ioctl_buf); 734e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf); 735e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf); 736e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring); 737e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring); 738e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring); 739e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring); 740e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring); 741e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf); 742e5ec1e72Spatrick return 0; 743e5ec1e72Spatrick } 744e5ec1e72Spatrick 745e5ec1e72Spatrick /* DMA code */ 746e5ec1e72Spatrick struct bwfm_pci_dmamem * 747e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *sc, bus_size_t size, bus_size_t align) 748e5ec1e72Spatrick { 749e5ec1e72Spatrick struct bwfm_pci_dmamem *bdm; 750e5ec1e72Spatrick int nsegs; 751e5ec1e72Spatrick 752e5ec1e72Spatrick bdm = malloc(sizeof(*bdm), M_DEVBUF, M_WAITOK | M_ZERO); 753e5ec1e72Spatrick bdm->bdm_size = size; 754e5ec1e72Spatrick 755e5ec1e72Spatrick if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 756e5ec1e72Spatrick BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &bdm->bdm_map) != 0) 757e5ec1e72Spatrick goto bdmfree; 758e5ec1e72Spatrick 759e5ec1e72Spatrick if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &bdm->bdm_seg, 1, 760e5ec1e72Spatrick &nsegs, BUS_DMA_WAITOK) != 0) 761e5ec1e72Spatrick goto destroy; 762e5ec1e72Spatrick 763e5ec1e72Spatrick if (bus_dmamem_map(sc->sc_dmat, &bdm->bdm_seg, nsegs, size, 764e5ec1e72Spatrick &bdm->bdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0) 765e5ec1e72Spatrick goto free; 766e5ec1e72Spatrick 767e5ec1e72Spatrick if (bus_dmamap_load(sc->sc_dmat, bdm->bdm_map, bdm->bdm_kva, size, 768e5ec1e72Spatrick NULL, BUS_DMA_WAITOK) != 0) 769e5ec1e72Spatrick goto unmap; 770e5ec1e72Spatrick 771e5ec1e72Spatrick bzero(bdm->bdm_kva, size); 772e5ec1e72Spatrick 773e5ec1e72Spatrick return (bdm); 774e5ec1e72Spatrick 775e5ec1e72Spatrick unmap: 776e5ec1e72Spatrick bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, size); 777e5ec1e72Spatrick free: 778e5ec1e72Spatrick bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1); 779e5ec1e72Spatrick destroy: 780e5ec1e72Spatrick bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map); 781e5ec1e72Spatrick bdmfree: 78265046b40Spatrick free(bdm, M_DEVBUF, sizeof(*bdm)); 783e5ec1e72Spatrick 784e5ec1e72Spatrick return (NULL); 785e5ec1e72Spatrick } 786e5ec1e72Spatrick 787e5ec1e72Spatrick void 788e5ec1e72Spatrick bwfm_pci_dmamem_free(struct bwfm_pci_softc *sc, struct bwfm_pci_dmamem *bdm) 789e5ec1e72Spatrick { 790e5ec1e72Spatrick bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, bdm->bdm_size); 791e5ec1e72Spatrick bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1); 792e5ec1e72Spatrick bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map); 79365046b40Spatrick free(bdm, M_DEVBUF, sizeof(*bdm)); 794e5ec1e72Spatrick } 795e5ec1e72Spatrick 796e5ec1e72Spatrick /* 797e5ec1e72Spatrick * We need a simple mapping from a packet ID to mbufs, because when 798e5ec1e72Spatrick * a transfer completed, we only know the ID so we have to look up 799e5ec1e72Spatrick * the memory for the ID. This simply looks for an empty slot. 800e5ec1e72Spatrick */ 801e5ec1e72Spatrick int 802e5ec1e72Spatrick bwfm_pci_pktid_new(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts, 803e5ec1e72Spatrick struct mbuf *m, uint32_t *pktid, paddr_t *paddr) 804e5ec1e72Spatrick { 805e5ec1e72Spatrick int i, idx; 806e5ec1e72Spatrick 807e5ec1e72Spatrick idx = pkts->last + 1; 808e5ec1e72Spatrick for (i = 0; i < pkts->npkt; i++) { 809e5ec1e72Spatrick if (idx == pkts->npkt) 810e5ec1e72Spatrick idx = 0; 811e5ec1e72Spatrick if (pkts->pkts[idx].bb_m == NULL) { 812e5ec1e72Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat, 813e5ec1e72Spatrick pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) { 814518be5f3Spatrick if (m_defrag(m, M_DONTWAIT)) 815518be5f3Spatrick return EFBIG; 816518be5f3Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat, 817518be5f3Spatrick pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) 818518be5f3Spatrick return EFBIG; 819e5ec1e72Spatrick } 820e5ec1e72Spatrick pkts->last = idx; 821e5ec1e72Spatrick pkts->pkts[idx].bb_m = m; 822e5ec1e72Spatrick *pktid = idx; 823e5ec1e72Spatrick *paddr = pkts->pkts[idx].bb_map->dm_segs[0].ds_addr; 824e5ec1e72Spatrick return 0; 825e5ec1e72Spatrick } 826e5ec1e72Spatrick idx++; 827e5ec1e72Spatrick } 828518be5f3Spatrick return ENOBUFS; 829e5ec1e72Spatrick } 830e5ec1e72Spatrick 831e5ec1e72Spatrick struct mbuf * 832e5ec1e72Spatrick bwfm_pci_pktid_free(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts, 833e5ec1e72Spatrick uint32_t pktid) 834e5ec1e72Spatrick { 835e5ec1e72Spatrick struct mbuf *m; 836e5ec1e72Spatrick 837e5ec1e72Spatrick if (pktid >= pkts->npkt || pkts->pkts[pktid].bb_m == NULL) 838e5ec1e72Spatrick return NULL; 839e5ec1e72Spatrick bus_dmamap_unload(sc->sc_dmat, pkts->pkts[pktid].bb_map); 840e5ec1e72Spatrick m = pkts->pkts[pktid].bb_m; 841e5ec1e72Spatrick pkts->pkts[pktid].bb_m = NULL; 842e5ec1e72Spatrick return m; 843e5ec1e72Spatrick } 844e5ec1e72Spatrick 845e5ec1e72Spatrick void 846e5ec1e72Spatrick bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *sc) 847e5ec1e72Spatrick { 84818722113Spatrick bwfm_pci_fill_rx_buf_ring(sc); 849e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_ioctl_ring, 850e5ec1e72Spatrick MSGBUF_TYPE_IOCTLRESP_BUF_POST); 851e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_event_ring, 852e5ec1e72Spatrick MSGBUF_TYPE_EVENT_BUF_POST); 853e5ec1e72Spatrick } 854e5ec1e72Spatrick 855e5ec1e72Spatrick void 856e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *sc, struct if_rxring *rxring, 857e5ec1e72Spatrick uint32_t msgtype) 858e5ec1e72Spatrick { 859e5ec1e72Spatrick struct msgbuf_rx_ioctl_resp_or_event *req; 860e5ec1e72Spatrick struct mbuf *m; 861e5ec1e72Spatrick uint32_t pktid; 862e5ec1e72Spatrick paddr_t paddr; 863e5ec1e72Spatrick int s, slots; 864e5ec1e72Spatrick 865e5ec1e72Spatrick s = splnet(); 866e5ec1e72Spatrick for (slots = if_rxr_get(rxring, 8); slots > 0; slots--) { 867e5ec1e72Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit); 868e5ec1e72Spatrick if (req == NULL) 869e5ec1e72Spatrick break; 870e5ec1e72Spatrick m = MCLGETI(NULL, M_DONTWAIT, NULL, MSGBUF_MAX_PKT_SIZE); 871e5ec1e72Spatrick if (m == NULL) { 872e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1); 873e5ec1e72Spatrick break; 874e5ec1e72Spatrick } 875e5ec1e72Spatrick m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE; 876e5ec1e72Spatrick if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) { 877e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1); 878e5ec1e72Spatrick m_freem(m); 879e5ec1e72Spatrick break; 880e5ec1e72Spatrick } 881e5ec1e72Spatrick memset(req, 0, sizeof(*req)); 882e5ec1e72Spatrick req->msg.msgtype = msgtype; 883e5ec1e72Spatrick req->msg.request_id = htole32(pktid); 884e5ec1e72Spatrick req->host_buf_len = htole16(MSGBUF_MAX_PKT_SIZE); 885e5ec1e72Spatrick req->host_buf_addr.high_addr = htole32(paddr >> 32); 886e5ec1e72Spatrick req->host_buf_addr.low_addr = htole32(paddr & 0xffffffff); 887e5ec1e72Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit); 888e5ec1e72Spatrick } 889e5ec1e72Spatrick if_rxr_put(rxring, slots); 890e5ec1e72Spatrick splx(s); 891e5ec1e72Spatrick } 892e5ec1e72Spatrick 893e5ec1e72Spatrick void 894e5ec1e72Spatrick bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *sc) 895e5ec1e72Spatrick { 896e5ec1e72Spatrick struct msgbuf_rx_bufpost *req; 897e5ec1e72Spatrick struct mbuf *m; 898e5ec1e72Spatrick uint32_t pktid; 899e5ec1e72Spatrick paddr_t paddr; 900e5ec1e72Spatrick int s, slots; 901e5ec1e72Spatrick 902e5ec1e72Spatrick s = splnet(); 903e5ec1e72Spatrick for (slots = if_rxr_get(&sc->sc_rxbuf_ring, sc->sc_max_rxbufpost); 904e5ec1e72Spatrick slots > 0; slots--) { 905e5ec1e72Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_rxpost_submit); 906e5ec1e72Spatrick if (req == NULL) 907e5ec1e72Spatrick break; 908e5ec1e72Spatrick m = MCLGETI(NULL, M_DONTWAIT, NULL, MSGBUF_MAX_PKT_SIZE); 909e5ec1e72Spatrick if (m == NULL) { 910e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1); 911e5ec1e72Spatrick break; 912e5ec1e72Spatrick } 913e5ec1e72Spatrick m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE; 914e5ec1e72Spatrick if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) { 915e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1); 916e5ec1e72Spatrick m_freem(m); 917e5ec1e72Spatrick break; 918e5ec1e72Spatrick } 919e5ec1e72Spatrick memset(req, 0, sizeof(*req)); 920e5ec1e72Spatrick req->msg.msgtype = MSGBUF_TYPE_RXBUF_POST; 921e5ec1e72Spatrick req->msg.request_id = htole32(pktid); 922e5ec1e72Spatrick req->data_buf_len = htole16(MSGBUF_MAX_PKT_SIZE); 923e5ec1e72Spatrick req->data_buf_addr.high_addr = htole32(paddr >> 32); 924e5ec1e72Spatrick req->data_buf_addr.low_addr = htole32(paddr & 0xffffffff); 925e5ec1e72Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_rxpost_submit); 926e5ec1e72Spatrick } 927e5ec1e72Spatrick if_rxr_put(&sc->sc_rxbuf_ring, slots); 928e5ec1e72Spatrick splx(s); 929e5ec1e72Spatrick } 930e5ec1e72Spatrick 931e5ec1e72Spatrick int 932e5ec1e72Spatrick bwfm_pci_setup_ring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring, 933e5ec1e72Spatrick int nitem, size_t itemsz, uint32_t w_idx, uint32_t r_idx, 934e5ec1e72Spatrick int idx, uint32_t idx_off, uint32_t *ring_mem) 935e5ec1e72Spatrick { 936e5ec1e72Spatrick ring->w_idx_addr = w_idx + idx * idx_off; 937e5ec1e72Spatrick ring->r_idx_addr = r_idx + idx * idx_off; 938e5ec1e72Spatrick ring->nitem = nitem; 939e5ec1e72Spatrick ring->itemsz = itemsz; 940e5ec1e72Spatrick bwfm_pci_ring_write_rptr(sc, ring); 941e5ec1e72Spatrick bwfm_pci_ring_write_wptr(sc, ring); 942e5ec1e72Spatrick 943e5ec1e72Spatrick ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8); 944e5ec1e72Spatrick if (ring->ring == NULL) 945e5ec1e72Spatrick return ENOMEM; 946e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 947e5ec1e72Spatrick *ring_mem + BWFM_RING_MEM_BASE_ADDR_LOW, 948e5ec1e72Spatrick BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff); 949e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 950e5ec1e72Spatrick *ring_mem + BWFM_RING_MEM_BASE_ADDR_HIGH, 951e5ec1e72Spatrick BWFM_PCI_DMA_DVA(ring->ring) >> 32); 952e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 953e5ec1e72Spatrick *ring_mem + BWFM_RING_MAX_ITEM, nitem); 954e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 955e5ec1e72Spatrick *ring_mem + BWFM_RING_LEN_ITEMS, itemsz); 956e5ec1e72Spatrick *ring_mem = *ring_mem + BWFM_RING_MEM_SZ; 957e5ec1e72Spatrick return 0; 958e5ec1e72Spatrick } 959e5ec1e72Spatrick 960518be5f3Spatrick int 961518be5f3Spatrick bwfm_pci_setup_flowring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring, 962518be5f3Spatrick int nitem, size_t itemsz) 963518be5f3Spatrick { 964518be5f3Spatrick ring->w_ptr = 0; 965518be5f3Spatrick ring->r_ptr = 0; 966518be5f3Spatrick ring->nitem = nitem; 967518be5f3Spatrick ring->itemsz = itemsz; 968518be5f3Spatrick bwfm_pci_ring_write_rptr(sc, ring); 969518be5f3Spatrick bwfm_pci_ring_write_wptr(sc, ring); 970518be5f3Spatrick 971518be5f3Spatrick ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8); 972518be5f3Spatrick if (ring->ring == NULL) 973518be5f3Spatrick return ENOMEM; 974518be5f3Spatrick return 0; 975518be5f3Spatrick } 976518be5f3Spatrick 977e5ec1e72Spatrick /* Ring helpers */ 978e5ec1e72Spatrick void 979e5ec1e72Spatrick bwfm_pci_ring_bell(struct bwfm_pci_softc *sc, 980e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 981e5ec1e72Spatrick { 982e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 983e5ec1e72Spatrick BWFM_PCI_PCIE2REG_H2D_MAILBOX, 1); 984e5ec1e72Spatrick } 985e5ec1e72Spatrick 986e5ec1e72Spatrick void 987e5ec1e72Spatrick bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *sc, 988e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 989e5ec1e72Spatrick { 990e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 991e5ec1e72Spatrick ring->r_ptr = bus_space_read_2(sc->sc_tcm_iot, 992e5ec1e72Spatrick sc->sc_tcm_ioh, ring->r_idx_addr); 993e5ec1e72Spatrick } else { 994e5ec1e72Spatrick ring->r_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf) 995e5ec1e72Spatrick + ring->r_idx_addr); 996e5ec1e72Spatrick } 997e5ec1e72Spatrick } 998e5ec1e72Spatrick 999e5ec1e72Spatrick void 1000e5ec1e72Spatrick bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *sc, 1001e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1002e5ec1e72Spatrick { 1003e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 1004e5ec1e72Spatrick ring->w_ptr = bus_space_read_2(sc->sc_tcm_iot, 1005e5ec1e72Spatrick sc->sc_tcm_ioh, ring->w_idx_addr); 1006e5ec1e72Spatrick } else { 1007e5ec1e72Spatrick ring->w_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf) 1008e5ec1e72Spatrick + ring->w_idx_addr); 1009e5ec1e72Spatrick } 1010e5ec1e72Spatrick } 1011e5ec1e72Spatrick 1012e5ec1e72Spatrick void 1013e5ec1e72Spatrick bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *sc, 1014e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1015e5ec1e72Spatrick { 1016e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 1017e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1018e5ec1e72Spatrick ring->r_idx_addr, ring->r_ptr); 1019e5ec1e72Spatrick } else { 1020e5ec1e72Spatrick *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf) 1021e5ec1e72Spatrick + ring->r_idx_addr) = ring->r_ptr; 1022e5ec1e72Spatrick } 1023e5ec1e72Spatrick } 1024e5ec1e72Spatrick 1025e5ec1e72Spatrick void 1026e5ec1e72Spatrick bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *sc, 1027e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1028e5ec1e72Spatrick { 1029e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 1030e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1031e5ec1e72Spatrick ring->w_idx_addr, ring->w_ptr); 1032e5ec1e72Spatrick } else { 1033e5ec1e72Spatrick *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf) 1034e5ec1e72Spatrick + ring->w_idx_addr) = ring->w_ptr; 1035e5ec1e72Spatrick } 1036e5ec1e72Spatrick } 1037e5ec1e72Spatrick 1038e5ec1e72Spatrick /* 1039e5ec1e72Spatrick * Retrieve a free descriptor to put new stuff in, but don't commit 1040e5ec1e72Spatrick * to it yet so we can rollback later if any error occurs. 1041e5ec1e72Spatrick */ 1042e5ec1e72Spatrick void * 1043e5ec1e72Spatrick bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *sc, 1044e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1045e5ec1e72Spatrick { 1046e5ec1e72Spatrick int available; 1047e5ec1e72Spatrick char *ret; 1048e5ec1e72Spatrick 1049e5ec1e72Spatrick bwfm_pci_ring_update_rptr(sc, ring); 1050e5ec1e72Spatrick 1051e5ec1e72Spatrick if (ring->r_ptr > ring->w_ptr) 1052e5ec1e72Spatrick available = ring->r_ptr - ring->w_ptr; 1053e5ec1e72Spatrick else 1054e5ec1e72Spatrick available = ring->r_ptr + (ring->nitem - ring->w_ptr); 1055e5ec1e72Spatrick 1056e5ec1e72Spatrick if (available < 1) 1057e5ec1e72Spatrick return NULL; 1058e5ec1e72Spatrick 1059e5ec1e72Spatrick ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz); 1060e5ec1e72Spatrick ring->w_ptr += 1; 1061e5ec1e72Spatrick if (ring->w_ptr == ring->nitem) 1062e5ec1e72Spatrick ring->w_ptr = 0; 1063e5ec1e72Spatrick return ret; 1064e5ec1e72Spatrick } 1065e5ec1e72Spatrick 1066e5ec1e72Spatrick void * 1067e5ec1e72Spatrick bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *sc, 1068e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int count, int *avail) 1069e5ec1e72Spatrick { 1070e5ec1e72Spatrick int available; 1071e5ec1e72Spatrick char *ret; 1072e5ec1e72Spatrick 1073e5ec1e72Spatrick bwfm_pci_ring_update_rptr(sc, ring); 1074e5ec1e72Spatrick 1075e5ec1e72Spatrick if (ring->r_ptr > ring->w_ptr) 1076e5ec1e72Spatrick available = ring->r_ptr - ring->w_ptr; 1077e5ec1e72Spatrick else 1078e5ec1e72Spatrick available = ring->r_ptr + (ring->nitem - ring->w_ptr); 1079e5ec1e72Spatrick 1080e5ec1e72Spatrick if (available < 1) 1081e5ec1e72Spatrick return NULL; 1082e5ec1e72Spatrick 1083e5ec1e72Spatrick ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz); 1084e5ec1e72Spatrick *avail = min(count, available - 1); 1085e5ec1e72Spatrick if (*avail + ring->w_ptr > ring->nitem) 1086e5ec1e72Spatrick *avail = ring->nitem - ring->w_ptr; 1087e5ec1e72Spatrick ring->w_ptr += *avail; 1088e5ec1e72Spatrick if (ring->w_ptr == ring->nitem) 1089e5ec1e72Spatrick ring->w_ptr = 0; 1090e5ec1e72Spatrick return ret; 1091e5ec1e72Spatrick } 1092e5ec1e72Spatrick 1093e5ec1e72Spatrick /* 1094e5ec1e72Spatrick * Read number of descriptors available (submitted by the firmware) 1095e5ec1e72Spatrick * and retrieve pointer to first descriptor. 1096e5ec1e72Spatrick */ 1097e5ec1e72Spatrick void * 1098e5ec1e72Spatrick bwfm_pci_ring_read_avail(struct bwfm_pci_softc *sc, 1099e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int *avail) 1100e5ec1e72Spatrick { 1101e5ec1e72Spatrick bwfm_pci_ring_update_wptr(sc, ring); 1102e5ec1e72Spatrick 1103e5ec1e72Spatrick if (ring->w_ptr >= ring->r_ptr) 1104e5ec1e72Spatrick *avail = ring->w_ptr - ring->r_ptr; 1105e5ec1e72Spatrick else 1106e5ec1e72Spatrick *avail = ring->nitem - ring->r_ptr; 1107e5ec1e72Spatrick 1108e5ec1e72Spatrick if (*avail == 0) 1109e5ec1e72Spatrick return NULL; 1110e5ec1e72Spatrick 1111e5ec1e72Spatrick return BWFM_PCI_DMA_KVA(ring->ring) + (ring->r_ptr * ring->itemsz); 1112e5ec1e72Spatrick } 1113e5ec1e72Spatrick 1114e5ec1e72Spatrick /* 1115e5ec1e72Spatrick * Let firmware know we read N descriptors. 1116e5ec1e72Spatrick */ 1117e5ec1e72Spatrick void 1118e5ec1e72Spatrick bwfm_pci_ring_read_commit(struct bwfm_pci_softc *sc, 1119e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int nitem) 1120e5ec1e72Spatrick { 1121e5ec1e72Spatrick ring->r_ptr += nitem; 1122e5ec1e72Spatrick if (ring->r_ptr == ring->nitem) 1123e5ec1e72Spatrick ring->r_ptr = 0; 1124e5ec1e72Spatrick bwfm_pci_ring_write_rptr(sc, ring); 1125e5ec1e72Spatrick } 1126e5ec1e72Spatrick 1127e5ec1e72Spatrick /* 1128e5ec1e72Spatrick * Let firmware know that we submitted some descriptors. 1129e5ec1e72Spatrick */ 1130e5ec1e72Spatrick void 1131e5ec1e72Spatrick bwfm_pci_ring_write_commit(struct bwfm_pci_softc *sc, 1132e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1133e5ec1e72Spatrick { 1134e5ec1e72Spatrick bwfm_pci_ring_write_wptr(sc, ring); 1135e5ec1e72Spatrick bwfm_pci_ring_bell(sc, ring); 1136e5ec1e72Spatrick } 1137e5ec1e72Spatrick 1138e5ec1e72Spatrick /* 1139e5ec1e72Spatrick * Rollback N descriptors in case we don't actually want 1140e5ec1e72Spatrick * to commit to it. 1141e5ec1e72Spatrick */ 1142e5ec1e72Spatrick void 1143e5ec1e72Spatrick bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *sc, 1144e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int nitem) 1145e5ec1e72Spatrick { 1146e5ec1e72Spatrick if (ring->w_ptr == 0) 1147e5ec1e72Spatrick ring->w_ptr = ring->nitem - nitem; 1148e5ec1e72Spatrick else 1149e5ec1e72Spatrick ring->w_ptr -= nitem; 1150e5ec1e72Spatrick } 1151e5ec1e72Spatrick 1152e5ec1e72Spatrick /* 1153e5ec1e72Spatrick * Foreach written descriptor on the ring, pass the descriptor to 1154e5ec1e72Spatrick * a message handler and let the firmware know we handled it. 1155e5ec1e72Spatrick */ 1156e5ec1e72Spatrick void 1157e5ec1e72Spatrick bwfm_pci_ring_rx(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring) 1158e5ec1e72Spatrick { 1159e5ec1e72Spatrick void *buf; 1160e5ec1e72Spatrick int avail, processed; 1161e5ec1e72Spatrick 1162e5ec1e72Spatrick again: 1163e5ec1e72Spatrick buf = bwfm_pci_ring_read_avail(sc, ring, &avail); 1164e5ec1e72Spatrick if (buf == NULL) 1165e5ec1e72Spatrick return; 1166e5ec1e72Spatrick 1167e5ec1e72Spatrick processed = 0; 1168e5ec1e72Spatrick while (avail) { 1169e5ec1e72Spatrick bwfm_pci_msg_rx(sc, buf + sc->sc_rx_dataoffset); 1170e5ec1e72Spatrick buf += ring->itemsz; 1171e5ec1e72Spatrick processed++; 1172e5ec1e72Spatrick if (processed == 48) { 1173e5ec1e72Spatrick bwfm_pci_ring_read_commit(sc, ring, processed); 1174e5ec1e72Spatrick processed = 0; 1175e5ec1e72Spatrick } 1176e5ec1e72Spatrick avail--; 1177e5ec1e72Spatrick } 1178e5ec1e72Spatrick if (processed) 1179e5ec1e72Spatrick bwfm_pci_ring_read_commit(sc, ring, processed); 1180e5ec1e72Spatrick if (ring->r_ptr == 0) 1181e5ec1e72Spatrick goto again; 1182e5ec1e72Spatrick } 1183e5ec1e72Spatrick 1184e5ec1e72Spatrick void 1185e5ec1e72Spatrick bwfm_pci_msg_rx(struct bwfm_pci_softc *sc, void *buf) 1186e5ec1e72Spatrick { 1187518be5f3Spatrick struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if; 1188e5ec1e72Spatrick struct msgbuf_ioctl_resp_hdr *resp; 1189518be5f3Spatrick struct msgbuf_tx_status *tx; 119018722113Spatrick struct msgbuf_rx_complete *rx; 1191e5ec1e72Spatrick struct msgbuf_rx_event *event; 1192e5ec1e72Spatrick struct msgbuf_common_hdr *msg; 1193518be5f3Spatrick struct msgbuf_flowring_create_resp *fcr; 1194a2c6ff8bSpatrick struct msgbuf_flowring_delete_resp *fdr; 1195518be5f3Spatrick struct bwfm_pci_msgring *ring; 1196e5ec1e72Spatrick struct mbuf *m; 1197518be5f3Spatrick int flowid; 1198e5ec1e72Spatrick 1199e5ec1e72Spatrick msg = (struct msgbuf_common_hdr *)buf; 1200e5ec1e72Spatrick switch (msg->msgtype) 1201e5ec1e72Spatrick { 1202518be5f3Spatrick case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT: 1203518be5f3Spatrick fcr = (struct msgbuf_flowring_create_resp *)buf; 1204518be5f3Spatrick flowid = letoh16(fcr->compl_hdr.flow_ring_id); 1205518be5f3Spatrick if (flowid < 2) 1206518be5f3Spatrick break; 1207518be5f3Spatrick flowid -= 2; 1208518be5f3Spatrick if (flowid >= sc->sc_max_flowrings) 1209518be5f3Spatrick break; 1210518be5f3Spatrick ring = &sc->sc_flowrings[flowid]; 1211518be5f3Spatrick if (ring->status != RING_OPENING) 1212518be5f3Spatrick break; 1213518be5f3Spatrick if (fcr->compl_hdr.status) { 1214518be5f3Spatrick printf("%s: failed to open flowring %d\n", 1215518be5f3Spatrick DEVNAME(sc), flowid); 1216518be5f3Spatrick ring->status = RING_CLOSED; 1217518be5f3Spatrick ifq_restart(&ifp->if_snd); 1218518be5f3Spatrick break; 1219518be5f3Spatrick } 1220518be5f3Spatrick ring->status = RING_OPEN; 1221518be5f3Spatrick ifq_restart(&ifp->if_snd); 1222518be5f3Spatrick break; 1223a2c6ff8bSpatrick case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT: 1224a2c6ff8bSpatrick fdr = (struct msgbuf_flowring_delete_resp *)buf; 1225a2c6ff8bSpatrick flowid = letoh16(fdr->compl_hdr.flow_ring_id); 1226a2c6ff8bSpatrick if (flowid < 2) 1227a2c6ff8bSpatrick break; 1228a2c6ff8bSpatrick flowid -= 2; 1229a2c6ff8bSpatrick if (flowid >= sc->sc_max_flowrings) 1230a2c6ff8bSpatrick break; 1231a2c6ff8bSpatrick ring = &sc->sc_flowrings[flowid]; 1232a2c6ff8bSpatrick if (ring->status != RING_CLOSING) 1233a2c6ff8bSpatrick break; 1234a2c6ff8bSpatrick if (fdr->compl_hdr.status) { 1235a2c6ff8bSpatrick printf("%s: failed to delete flowring %d\n", 1236a2c6ff8bSpatrick DEVNAME(sc), flowid); 1237a2c6ff8bSpatrick break; 1238a2c6ff8bSpatrick } 1239a2c6ff8bSpatrick bwfm_pci_dmamem_free(sc, ring->ring); 1240a2c6ff8bSpatrick ring->status = RING_CLOSED; 1241a2c6ff8bSpatrick break; 1242e5ec1e72Spatrick case MSGBUF_TYPE_IOCTLPTR_REQ_ACK: 1243e5ec1e72Spatrick break; 1244e5ec1e72Spatrick case MSGBUF_TYPE_IOCTL_CMPLT: 1245e5ec1e72Spatrick resp = (struct msgbuf_ioctl_resp_hdr *)buf; 1246e5ec1e72Spatrick sc->sc_ioctl_resp_pktid = letoh32(resp->msg.request_id); 1247e5ec1e72Spatrick sc->sc_ioctl_resp_ret_len = letoh16(resp->resp_len); 1248e5ec1e72Spatrick sc->sc_ioctl_resp_status = letoh16(resp->compl_hdr.status); 1249e5ec1e72Spatrick if_rxr_put(&sc->sc_ioctl_ring, 1); 1250e5ec1e72Spatrick bwfm_pci_fill_rx_rings(sc); 1251e5ec1e72Spatrick wakeup(&sc->sc_ioctl_buf); 1252e5ec1e72Spatrick break; 1253e5ec1e72Spatrick case MSGBUF_TYPE_WL_EVENT: 1254e5ec1e72Spatrick event = (struct msgbuf_rx_event *)buf; 1255e5ec1e72Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts, 1256e5ec1e72Spatrick letoh32(event->msg.request_id)); 1257e5ec1e72Spatrick if (m == NULL) 1258e5ec1e72Spatrick break; 1259e5ec1e72Spatrick m_adj(m, sc->sc_rx_dataoffset); 1260f37fc236Spatrick m->m_len = m->m_pkthdr.len = letoh16(event->event_data_len); 1261f37fc236Spatrick bwfm_rx(&sc->sc_sc, m); 1262e5ec1e72Spatrick if_rxr_put(&sc->sc_event_ring, 1); 1263e5ec1e72Spatrick bwfm_pci_fill_rx_rings(sc); 1264e5ec1e72Spatrick break; 1265518be5f3Spatrick case MSGBUF_TYPE_TX_STATUS: 1266518be5f3Spatrick tx = (struct msgbuf_tx_status *)buf; 1267518be5f3Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_tx_pkts, 1268518be5f3Spatrick letoh32(tx->msg.request_id)); 1269518be5f3Spatrick if (m == NULL) 1270518be5f3Spatrick break; 1271518be5f3Spatrick m_freem(m); 1272518be5f3Spatrick break; 127318722113Spatrick case MSGBUF_TYPE_RX_CMPLT: 127418722113Spatrick rx = (struct msgbuf_rx_complete *)buf; 127518722113Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts, 127618722113Spatrick letoh32(rx->msg.request_id)); 127718722113Spatrick if (m == NULL) 127818722113Spatrick break; 127918722113Spatrick if (letoh16(rx->data_offset)) 128018722113Spatrick m_adj(m, letoh16(rx->data_offset)); 128118722113Spatrick else if (sc->sc_rx_dataoffset) 128218722113Spatrick m_adj(m, sc->sc_rx_dataoffset); 1283f37fc236Spatrick m->m_len = m->m_pkthdr.len = letoh16(rx->data_len); 1284f37fc236Spatrick bwfm_rx(&sc->sc_sc, m); 128518722113Spatrick if_rxr_put(&sc->sc_rxbuf_ring, 1); 128618722113Spatrick bwfm_pci_fill_rx_rings(sc); 128718722113Spatrick break; 1288e5ec1e72Spatrick default: 1289e5ec1e72Spatrick printf("%s: msgtype 0x%08x\n", __func__, msg->msgtype); 1290e5ec1e72Spatrick break; 1291e5ec1e72Spatrick } 1292e5ec1e72Spatrick } 1293e5ec1e72Spatrick 1294e5ec1e72Spatrick /* Bus core helpers */ 1295e5ec1e72Spatrick void 1296e5ec1e72Spatrick bwfm_pci_select_core(struct bwfm_pci_softc *sc, int id) 1297e5ec1e72Spatrick { 1298e5ec1e72Spatrick struct bwfm_softc *bwfm = (void *)sc; 1299e5ec1e72Spatrick struct bwfm_core *core; 1300e5ec1e72Spatrick 1301e5ec1e72Spatrick core = bwfm_chip_get_core(bwfm, id); 1302e5ec1e72Spatrick if (core == NULL) { 1303e5ec1e72Spatrick printf("%s: could not find core to select", DEVNAME(sc)); 1304e5ec1e72Spatrick return; 1305e5ec1e72Spatrick } 1306e5ec1e72Spatrick 1307e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, 1308e5ec1e72Spatrick BWFM_PCI_BAR0_WINDOW, core->co_base); 1309e5ec1e72Spatrick if (pci_conf_read(sc->sc_pc, sc->sc_tag, 1310e5ec1e72Spatrick BWFM_PCI_BAR0_WINDOW) != core->co_base) 1311e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, 1312e5ec1e72Spatrick BWFM_PCI_BAR0_WINDOW, core->co_base); 1313e5ec1e72Spatrick } 1314e5ec1e72Spatrick 1315e5ec1e72Spatrick uint32_t 1316e5ec1e72Spatrick bwfm_pci_buscore_read(struct bwfm_softc *bwfm, uint32_t reg) 1317e5ec1e72Spatrick { 1318e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1319e5ec1e72Spatrick uint32_t page, offset; 1320e5ec1e72Spatrick 1321e5ec1e72Spatrick page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1); 1322e5ec1e72Spatrick offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1); 1323e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page); 1324e5ec1e72Spatrick return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset); 1325e5ec1e72Spatrick } 1326e5ec1e72Spatrick 1327e5ec1e72Spatrick void 1328e5ec1e72Spatrick bwfm_pci_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val) 1329e5ec1e72Spatrick { 1330e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1331e5ec1e72Spatrick uint32_t page, offset; 1332e5ec1e72Spatrick 1333e5ec1e72Spatrick page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1); 1334e5ec1e72Spatrick offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1); 1335e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page); 1336e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset, val); 1337e5ec1e72Spatrick } 1338e5ec1e72Spatrick 1339e5ec1e72Spatrick int 1340e5ec1e72Spatrick bwfm_pci_buscore_prepare(struct bwfm_softc *bwfm) 1341e5ec1e72Spatrick { 1342e5ec1e72Spatrick return 0; 1343e5ec1e72Spatrick } 1344e5ec1e72Spatrick 1345e5ec1e72Spatrick int 1346e5ec1e72Spatrick bwfm_pci_buscore_reset(struct bwfm_softc *bwfm) 1347e5ec1e72Spatrick { 1348e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1349e5ec1e72Spatrick struct bwfm_core *core; 1350e5ec1e72Spatrick uint32_t reg; 1351e5ec1e72Spatrick int i; 1352e5ec1e72Spatrick 1353e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2); 1354e5ec1e72Spatrick reg = pci_conf_read(sc->sc_pc, sc->sc_tag, 1355e5ec1e72Spatrick BWFM_PCI_CFGREG_LINK_STATUS_CTRL); 1356e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_CFGREG_LINK_STATUS_CTRL, 1357e5ec1e72Spatrick reg & ~BWFM_PCI_CFGREG_LINK_STATUS_CTRL_ASPM_ENAB); 1358e5ec1e72Spatrick 1359e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); 1360e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1361e5ec1e72Spatrick BWFM_CHIP_REG_WATCHDOG, 4); 1362e5ec1e72Spatrick delay(100 * 1000); 1363e5ec1e72Spatrick 1364e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2); 1365e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, 1366e5ec1e72Spatrick BWFM_PCI_CFGREG_LINK_STATUS_CTRL, reg); 1367e5ec1e72Spatrick 1368e5ec1e72Spatrick core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2); 1369e5ec1e72Spatrick if (core->co_rev <= 13) { 1370e5ec1e72Spatrick uint16_t cfg_offset[] = { 1371e5ec1e72Spatrick BWFM_PCI_CFGREG_STATUS_CMD, 1372e5ec1e72Spatrick BWFM_PCI_CFGREG_PM_CSR, 1373e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_CAP, 1374e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_ADDR_L, 1375e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_ADDR_H, 1376e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_DATA, 1377e5ec1e72Spatrick BWFM_PCI_CFGREG_LINK_STATUS_CTRL2, 1378e5ec1e72Spatrick BWFM_PCI_CFGREG_RBAR_CTRL, 1379e5ec1e72Spatrick BWFM_PCI_CFGREG_PML1_SUB_CTRL1, 1380e5ec1e72Spatrick BWFM_PCI_CFGREG_REG_BAR2_CONFIG, 1381e5ec1e72Spatrick BWFM_PCI_CFGREG_REG_BAR3_CONFIG, 1382e5ec1e72Spatrick }; 1383e5ec1e72Spatrick 1384e5ec1e72Spatrick for (i = 0; i < nitems(cfg_offset); i++) { 1385e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1386e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGADDR, cfg_offset[i]); 1387e5ec1e72Spatrick reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1388e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA); 1389e5ec1e72Spatrick DPRINTFN(3, ("%s: config offset 0x%04x, value 0x%04x\n", 1390e5ec1e72Spatrick DEVNAME(sc), cfg_offset[i], reg)); 1391e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1392e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA, reg); 1393e5ec1e72Spatrick } 1394e5ec1e72Spatrick } 1395e5ec1e72Spatrick 1396e5ec1e72Spatrick reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1397e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXINT); 1398e5ec1e72Spatrick if (reg != 0xffffffff) 1399e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1400e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXINT, reg); 1401e5ec1e72Spatrick 1402e5ec1e72Spatrick return 0; 1403e5ec1e72Spatrick } 1404e5ec1e72Spatrick 1405e5ec1e72Spatrick void 1406e5ec1e72Spatrick bwfm_pci_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec) 1407e5ec1e72Spatrick { 1408e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1409e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 0, rstvec); 1410e5ec1e72Spatrick } 1411e5ec1e72Spatrick 1412f67437f3Spatrick static int bwfm_pci_prio2fifo[8] = { 1413f67437f3Spatrick 1, /* best effort */ 1414f67437f3Spatrick 0, /* IPTOS_PREC_IMMEDIATE */ 1415f67437f3Spatrick 0, /* IPTOS_PREC_PRIORITY */ 1416f67437f3Spatrick 1, /* IPTOS_PREC_FLASH */ 1417f67437f3Spatrick 2, /* IPTOS_PREC_FLASHOVERRIDE */ 1418f67437f3Spatrick 2, /* IPTOS_PREC_CRITIC_ECP */ 1419f67437f3Spatrick 3, /* IPTOS_PREC_INTERNETCONTROL */ 1420f67437f3Spatrick 3, /* IPTOS_PREC_NETCONTROL */ 1421f67437f3Spatrick }; 1422f67437f3Spatrick 1423f67437f3Spatrick int 1424f67437f3Spatrick bwfm_pci_flowring_lookup(struct bwfm_pci_softc *sc, struct mbuf *m) 1425518be5f3Spatrick { 1426f67437f3Spatrick struct ieee80211com *ic = &sc->sc_sc.sc_ic; 1427f67437f3Spatrick uint8_t *da = mtod(m, uint8_t *); 1428f67437f3Spatrick int flowid, prio, fifo; 1429f67437f3Spatrick int i, found; 1430f67437f3Spatrick 1431f67437f3Spatrick prio = ieee80211_classify(ic, m); 1432f67437f3Spatrick fifo = bwfm_pci_prio2fifo[prio]; 1433f67437f3Spatrick 1434f67437f3Spatrick switch (ic->ic_opmode) 1435f67437f3Spatrick { 1436f67437f3Spatrick case IEEE80211_M_STA: 1437f67437f3Spatrick flowid = fifo; 1438f67437f3Spatrick break; 1439f67437f3Spatrick #ifndef IEEE80211_STA_ONLY 1440f67437f3Spatrick case IEEE80211_M_HOSTAP: 1441*2b7bea7eSpatrick if (ETHER_IS_MULTICAST(da)) 1442*2b7bea7eSpatrick da = etherbroadcastaddr; 1443f67437f3Spatrick flowid = da[5] * 2 + fifo; 1444f67437f3Spatrick break; 1445f67437f3Spatrick #endif 1446f67437f3Spatrick default: 1447f67437f3Spatrick printf("%s: state not supported\n", DEVNAME(sc)); 1448f67437f3Spatrick return ENOBUFS; 1449f67437f3Spatrick } 1450f67437f3Spatrick 1451f67437f3Spatrick found = 0; 1452f67437f3Spatrick flowid = flowid % sc->sc_max_flowrings; 1453f67437f3Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 1454f67437f3Spatrick if (ic->ic_opmode == IEEE80211_M_STA && 1455f67437f3Spatrick sc->sc_flowrings[flowid].status >= RING_OPEN && 1456f67437f3Spatrick sc->sc_flowrings[flowid].fifo == fifo) { 1457f67437f3Spatrick found = 1; 1458f67437f3Spatrick break; 1459f67437f3Spatrick } 1460f67437f3Spatrick #ifndef IEEE80211_STA_ONLY 1461f67437f3Spatrick if (ic->ic_opmode == IEEE80211_M_HOSTAP && 1462f67437f3Spatrick sc->sc_flowrings[flowid].status >= RING_OPEN && 1463f67437f3Spatrick sc->sc_flowrings[flowid].fifo == fifo && 1464a2c6ff8bSpatrick !memcmp(sc->sc_flowrings[flowid].mac, da, ETHER_ADDR_LEN)) { 1465f67437f3Spatrick found = 1; 1466f67437f3Spatrick break; 1467f67437f3Spatrick } 1468f67437f3Spatrick #endif 1469f67437f3Spatrick flowid = (flowid + 1) % sc->sc_max_flowrings; 1470f67437f3Spatrick } 1471f67437f3Spatrick 1472f67437f3Spatrick if (found) 1473f67437f3Spatrick return flowid; 1474f67437f3Spatrick 1475f67437f3Spatrick return -1; 1476f67437f3Spatrick } 1477f67437f3Spatrick 1478f67437f3Spatrick void 1479f67437f3Spatrick bwfm_pci_flowring_create(struct bwfm_pci_softc *sc, struct mbuf *m) 1480f67437f3Spatrick { 1481f67437f3Spatrick struct ieee80211com *ic = &sc->sc_sc.sc_ic; 1482518be5f3Spatrick struct bwfm_cmd_flowring_create cmd; 1483f67437f3Spatrick uint8_t *da = mtod(m, uint8_t *); 1484f67437f3Spatrick int flowid, prio, fifo; 1485f67437f3Spatrick int i, found; 1486f67437f3Spatrick 1487f67437f3Spatrick prio = ieee80211_classify(ic, m); 1488f67437f3Spatrick fifo = bwfm_pci_prio2fifo[prio]; 1489f67437f3Spatrick 1490f67437f3Spatrick switch (ic->ic_opmode) 1491f67437f3Spatrick { 1492f67437f3Spatrick case IEEE80211_M_STA: 1493f67437f3Spatrick flowid = fifo; 1494f67437f3Spatrick break; 1495f67437f3Spatrick #ifndef IEEE80211_STA_ONLY 1496f67437f3Spatrick case IEEE80211_M_HOSTAP: 1497*2b7bea7eSpatrick if (ETHER_IS_MULTICAST(da)) 1498*2b7bea7eSpatrick da = etherbroadcastaddr; 1499f67437f3Spatrick flowid = da[5] * 2 + fifo; 1500f67437f3Spatrick break; 1501f67437f3Spatrick #endif 1502f67437f3Spatrick default: 1503f67437f3Spatrick printf("%s: state not supported\n", DEVNAME(sc)); 1504f67437f3Spatrick return; 1505f67437f3Spatrick } 1506f67437f3Spatrick 1507f67437f3Spatrick found = 0; 1508f67437f3Spatrick flowid = flowid % sc->sc_max_flowrings; 1509f67437f3Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 1510f67437f3Spatrick if (sc->sc_flowrings[flowid].status == RING_CLOSED) { 1511f67437f3Spatrick found = 1; 1512f67437f3Spatrick break; 1513f67437f3Spatrick } 1514f67437f3Spatrick flowid = (flowid + 1) % sc->sc_max_flowrings; 1515f67437f3Spatrick } 1516f67437f3Spatrick 1517f67437f3Spatrick if (!found) { 1518f67437f3Spatrick printf("%s: no flowring available\n", DEVNAME(sc)); 1519f67437f3Spatrick return; 1520f67437f3Spatrick } 1521f67437f3Spatrick 1522f67437f3Spatrick cmd.prio = prio; 1523518be5f3Spatrick cmd.flowid = flowid; 1524518be5f3Spatrick memcpy(cmd.da, mtod(m, char *) + 0 * ETHER_ADDR_LEN, ETHER_ADDR_LEN); 1525518be5f3Spatrick memcpy(cmd.sa, mtod(m, char *) + 1 * ETHER_ADDR_LEN, ETHER_ADDR_LEN); 1526518be5f3Spatrick bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_create_cb, &cmd, sizeof(cmd)); 1527518be5f3Spatrick } 1528518be5f3Spatrick 1529518be5f3Spatrick void 1530518be5f3Spatrick bwfm_pci_flowring_create_cb(struct bwfm_softc *bwfm, void *arg) 1531518be5f3Spatrick { 1532518be5f3Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1533*2b7bea7eSpatrick struct ieee80211com *ic = &sc->sc_sc.sc_ic; 1534518be5f3Spatrick struct bwfm_cmd_flowring_create *cmd = arg; 1535518be5f3Spatrick struct msgbuf_tx_flowring_create_req *req; 1536518be5f3Spatrick struct bwfm_pci_msgring *ring; 1537f67437f3Spatrick int flowid, prio; 1538518be5f3Spatrick 1539518be5f3Spatrick flowid = cmd->flowid; 1540f67437f3Spatrick prio = cmd->prio; 1541518be5f3Spatrick 1542f67437f3Spatrick ring = &sc->sc_flowrings[flowid]; 1543f67437f3Spatrick if (ring->status != RING_CLOSED) { 1544f67437f3Spatrick printf("%s: flowring not closed\n", DEVNAME(sc)); 1545518be5f3Spatrick return; 1546f67437f3Spatrick } 1547f67437f3Spatrick 1548f67437f3Spatrick if (bwfm_pci_setup_flowring(sc, ring, 512, 48)) { 1549f67437f3Spatrick printf("%s: cannot setup flowring\n", DEVNAME(sc)); 1550f67437f3Spatrick return; 1551f67437f3Spatrick } 1552518be5f3Spatrick 1553518be5f3Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit); 1554f67437f3Spatrick if (req == NULL) { 1555f67437f3Spatrick printf("%s: cannot reserve for flowring\n", DEVNAME(sc)); 1556518be5f3Spatrick return; 1557f67437f3Spatrick } 1558518be5f3Spatrick 1559518be5f3Spatrick ring->status = RING_OPENING; 1560f67437f3Spatrick ring->fifo = bwfm_pci_prio2fifo[prio]; 1561f67437f3Spatrick memcpy(ring->mac, cmd->da, ETHER_ADDR_LEN); 1562*2b7bea7eSpatrick #ifndef IEEE80211_STA_ONLY 1563*2b7bea7eSpatrick if (ic->ic_opmode == IEEE80211_M_HOSTAP && ETHER_IS_MULTICAST(cmd->da)) 1564*2b7bea7eSpatrick memcpy(ring->mac, etherbroadcastaddr, ETHER_ADDR_LEN); 1565*2b7bea7eSpatrick #endif 1566f67437f3Spatrick 1567518be5f3Spatrick req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE; 1568518be5f3Spatrick req->msg.ifidx = 0; 1569518be5f3Spatrick req->msg.request_id = 0; 1570f67437f3Spatrick req->tid = bwfm_pci_prio2fifo[prio]; 1571518be5f3Spatrick req->flow_ring_id = letoh16(flowid + 2); 1572518be5f3Spatrick memcpy(req->da, cmd->da, ETHER_ADDR_LEN); 1573518be5f3Spatrick memcpy(req->sa, cmd->sa, ETHER_ADDR_LEN); 1574518be5f3Spatrick req->flow_ring_addr.high_addr = 1575518be5f3Spatrick letoh32(BWFM_PCI_DMA_DVA(ring->ring) >> 32); 1576518be5f3Spatrick req->flow_ring_addr.low_addr = 1577518be5f3Spatrick letoh32(BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff); 1578518be5f3Spatrick req->max_items = letoh16(512); 1579518be5f3Spatrick req->len_item = letoh16(48); 1580518be5f3Spatrick 1581518be5f3Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit); 1582518be5f3Spatrick } 1583518be5f3Spatrick 1584a2c6ff8bSpatrick void 1585a2c6ff8bSpatrick bwfm_pci_flowring_delete(struct bwfm_pci_softc *sc, int flowid) 1586a2c6ff8bSpatrick { 1587a2c6ff8bSpatrick struct msgbuf_tx_flowring_delete_req *req; 1588a2c6ff8bSpatrick struct bwfm_pci_msgring *ring; 1589a2c6ff8bSpatrick 1590a2c6ff8bSpatrick ring = &sc->sc_flowrings[flowid]; 1591a2c6ff8bSpatrick if (ring->status != RING_OPEN) { 1592a2c6ff8bSpatrick printf("%s: flowring not open\n", DEVNAME(sc)); 1593a2c6ff8bSpatrick return; 1594a2c6ff8bSpatrick } 1595a2c6ff8bSpatrick 1596a2c6ff8bSpatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit); 1597a2c6ff8bSpatrick if (req == NULL) { 1598a2c6ff8bSpatrick printf("%s: cannot reserve for flowring\n", DEVNAME(sc)); 1599a2c6ff8bSpatrick return; 1600a2c6ff8bSpatrick } 1601a2c6ff8bSpatrick 1602a2c6ff8bSpatrick ring->status = RING_CLOSING; 1603a2c6ff8bSpatrick 1604a2c6ff8bSpatrick req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE; 1605a2c6ff8bSpatrick req->msg.ifidx = 0; 1606a2c6ff8bSpatrick req->msg.request_id = 0; 1607a2c6ff8bSpatrick req->flow_ring_id = letoh16(flowid + 2); 1608a2c6ff8bSpatrick req->reason = 0; 1609a2c6ff8bSpatrick 1610a2c6ff8bSpatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit); 1611a2c6ff8bSpatrick } 1612a2c6ff8bSpatrick 1613a2c6ff8bSpatrick void 1614a2c6ff8bSpatrick bwfm_pci_stop(struct bwfm_softc *bwfm) 1615a2c6ff8bSpatrick { 1616a2c6ff8bSpatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1617a2c6ff8bSpatrick struct bwfm_pci_msgring *ring; 1618a2c6ff8bSpatrick int i; 1619a2c6ff8bSpatrick 1620a2c6ff8bSpatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 1621a2c6ff8bSpatrick ring = &sc->sc_flowrings[i]; 1622a2c6ff8bSpatrick if (ring->status == RING_OPEN) 1623a2c6ff8bSpatrick bwfm_pci_flowring_delete(sc, i); 1624a2c6ff8bSpatrick } 1625a2c6ff8bSpatrick } 1626a2c6ff8bSpatrick 1627e5ec1e72Spatrick int 1628e5ec1e72Spatrick bwfm_pci_txdata(struct bwfm_softc *bwfm, struct mbuf *m) 1629e5ec1e72Spatrick { 1630e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1631518be5f3Spatrick struct bwfm_pci_msgring *ring; 1632518be5f3Spatrick struct msgbuf_tx_msghdr *tx; 1633518be5f3Spatrick uint32_t pktid; 1634518be5f3Spatrick paddr_t paddr; 1635518be5f3Spatrick int flowid, ret; 1636518be5f3Spatrick 1637f67437f3Spatrick flowid = bwfm_pci_flowring_lookup(sc, m); 1638f67437f3Spatrick if (flowid < 0) { 1639f67437f3Spatrick bwfm_pci_flowring_create(sc, m); 1640f67437f3Spatrick return ENOBUFS; 1641f67437f3Spatrick } 1642518be5f3Spatrick 1643518be5f3Spatrick ring = &sc->sc_flowrings[flowid]; 1644518be5f3Spatrick if (ring->status == RING_OPENING || 1645f67437f3Spatrick ring->status == RING_CLOSING) { 1646f67437f3Spatrick printf("%s: tried to use a flow that was " 1647f67437f3Spatrick "transitioning in status %d\n", 1648f67437f3Spatrick DEVNAME(sc), ring->status); 1649518be5f3Spatrick return ENOBUFS; 1650518be5f3Spatrick } 1651518be5f3Spatrick 1652518be5f3Spatrick tx = bwfm_pci_ring_write_reserve(sc, ring); 1653518be5f3Spatrick if (tx == NULL) 1654518be5f3Spatrick return ENOBUFS; 1655518be5f3Spatrick 1656518be5f3Spatrick memset(tx, 0, sizeof(*tx)); 1657518be5f3Spatrick tx->msg.msgtype = MSGBUF_TYPE_TX_POST; 1658518be5f3Spatrick tx->msg.ifidx = 0; 1659518be5f3Spatrick tx->flags = BWFM_MSGBUF_PKT_FLAGS_FRAME_802_3; 1660518be5f3Spatrick tx->flags |= ieee80211_classify(&sc->sc_sc.sc_ic, m) << 1661518be5f3Spatrick BWFM_MSGBUF_PKT_FLAGS_PRIO_SHIFT; 1662518be5f3Spatrick tx->seg_cnt = 1; 1663518be5f3Spatrick memcpy(tx->txhdr, mtod(m, char *), ETHER_HDR_LEN); 1664518be5f3Spatrick 1665518be5f3Spatrick ret = bwfm_pci_pktid_new(sc, &sc->sc_tx_pkts, m, &pktid, &paddr); 1666518be5f3Spatrick if (ret) { 1667518be5f3Spatrick bwfm_pci_ring_write_cancel(sc, ring, 1); 1668518be5f3Spatrick return ret; 1669518be5f3Spatrick } 1670518be5f3Spatrick paddr += ETHER_HDR_LEN; 1671518be5f3Spatrick 1672518be5f3Spatrick tx->msg.request_id = htole32(pktid); 16734ff787bcSpatrick tx->data_len = htole16(m->m_len - ETHER_HDR_LEN); 1674518be5f3Spatrick tx->data_buf_addr.high_addr = htole32(paddr >> 32); 1675518be5f3Spatrick tx->data_buf_addr.low_addr = htole32(paddr & 0xffffffff); 1676518be5f3Spatrick 1677518be5f3Spatrick bwfm_pci_ring_write_commit(sc, ring); 1678518be5f3Spatrick return 0; 1679e5ec1e72Spatrick } 1680e5ec1e72Spatrick 1681bbd71b0bSpatrick #ifdef BWFM_DEBUG 1682cadf5fcfSpatrick void 1683cadf5fcfSpatrick bwfm_pci_debug_console(struct bwfm_pci_softc *sc) 1684cadf5fcfSpatrick { 1685cadf5fcfSpatrick uint32_t newidx = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1686cadf5fcfSpatrick sc->sc_console_base_addr + BWFM_CONSOLE_WRITEIDX); 1687cadf5fcfSpatrick 1688cadf5fcfSpatrick if (newidx != sc->sc_console_readidx) 1689bbd71b0bSpatrick DPRINTFN(3, ("BWFM CONSOLE: ")); 1690cadf5fcfSpatrick while (newidx != sc->sc_console_readidx) { 1691cadf5fcfSpatrick uint8_t ch = bus_space_read_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1692cadf5fcfSpatrick sc->sc_console_buf_addr + sc->sc_console_readidx); 1693cadf5fcfSpatrick sc->sc_console_readidx++; 1694cadf5fcfSpatrick if (sc->sc_console_readidx == sc->sc_console_buf_size) 1695cadf5fcfSpatrick sc->sc_console_readidx = 0; 1696cadf5fcfSpatrick if (ch == '\r') 1697cadf5fcfSpatrick continue; 1698bbd71b0bSpatrick DPRINTFN(3, ("%c", ch)); 1699cadf5fcfSpatrick } 1700cadf5fcfSpatrick } 1701bbd71b0bSpatrick #endif 1702cadf5fcfSpatrick 1703e5ec1e72Spatrick int 1704e5ec1e72Spatrick bwfm_pci_intr(void *v) 1705e5ec1e72Spatrick { 1706e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)v; 1707e5ec1e72Spatrick uint32_t status; 1708e5ec1e72Spatrick 1709e5ec1e72Spatrick if ((status = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1710e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXINT)) == 0) 1711e5ec1e72Spatrick return 0; 1712e5ec1e72Spatrick 1713e5ec1e72Spatrick bwfm_pci_intr_disable(sc); 1714e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1715e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXINT, status); 1716e5ec1e72Spatrick 1717e5ec1e72Spatrick if (status & (BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 | 1718e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1)) 1719e5ec1e72Spatrick printf("%s: handle MB data\n", __func__); 1720e5ec1e72Spatrick 1721e5ec1e72Spatrick if (status & BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB) { 1722518be5f3Spatrick bwfm_pci_ring_rx(sc, &sc->sc_rx_complete); 1723*2b7bea7eSpatrick bwfm_pci_ring_rx(sc, &sc->sc_tx_complete); 1724*2b7bea7eSpatrick bwfm_pci_ring_rx(sc, &sc->sc_ctrl_complete); 1725e5ec1e72Spatrick } 1726e5ec1e72Spatrick 1727cadf5fcfSpatrick #ifdef BWFM_DEBUG 1728cadf5fcfSpatrick bwfm_pci_debug_console(sc); 1729e5ec1e72Spatrick #endif 1730e5ec1e72Spatrick 1731e5ec1e72Spatrick bwfm_pci_intr_enable(sc); 1732e5ec1e72Spatrick return 1; 1733e5ec1e72Spatrick } 1734e5ec1e72Spatrick 1735e5ec1e72Spatrick void 1736e5ec1e72Spatrick bwfm_pci_intr_enable(struct bwfm_pci_softc *sc) 1737e5ec1e72Spatrick { 1738e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1739e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK, 1740e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 | 1741e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1 | 1742e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB); 1743e5ec1e72Spatrick } 1744e5ec1e72Spatrick 1745e5ec1e72Spatrick void 1746e5ec1e72Spatrick bwfm_pci_intr_disable(struct bwfm_pci_softc *sc) 1747e5ec1e72Spatrick { 1748e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1749e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK, 0); 1750e5ec1e72Spatrick } 1751e5ec1e72Spatrick 1752e5ec1e72Spatrick /* Msgbuf protocol implementation */ 1753e5ec1e72Spatrick int 1754e5ec1e72Spatrick bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *bwfm, int ifidx, 1755e5ec1e72Spatrick int cmd, char *buf, size_t *len) 1756e5ec1e72Spatrick { 1757e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1758e5ec1e72Spatrick struct msgbuf_ioctl_req_hdr *req; 1759e5ec1e72Spatrick struct mbuf *m; 1760e5ec1e72Spatrick size_t buflen; 1761e5ec1e72Spatrick int s; 1762e5ec1e72Spatrick 1763e5ec1e72Spatrick s = splnet(); 1764e5ec1e72Spatrick sc->sc_ioctl_resp_pktid = -1; 1765e5ec1e72Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit); 1766e5ec1e72Spatrick if (req == NULL) { 1767e5ec1e72Spatrick printf("%s: cannot reserve for write\n", DEVNAME(sc)); 1768e5ec1e72Spatrick splx(s); 1769e5ec1e72Spatrick return 1; 1770e5ec1e72Spatrick } 1771e5ec1e72Spatrick req->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ; 1772e5ec1e72Spatrick req->msg.ifidx = 0; 1773e5ec1e72Spatrick req->msg.flags = 0; 1774e5ec1e72Spatrick req->msg.request_id = htole32(MSGBUF_IOCTL_REQ_PKTID); 1775e5ec1e72Spatrick req->cmd = htole32(cmd); 1776e5ec1e72Spatrick req->output_buf_len = htole16(*len); 1777e5ec1e72Spatrick req->trans_id = htole16(sc->sc_ioctl_reqid++); 1778e5ec1e72Spatrick 1779e5ec1e72Spatrick buflen = min(*len, BWFM_DMA_H2D_IOCTL_BUF_LEN); 1780e5ec1e72Spatrick req->input_buf_len = htole16(buflen); 1781e5ec1e72Spatrick req->req_buf_addr.high_addr = 1782e5ec1e72Spatrick htole32((uint64_t)BWFM_PCI_DMA_DVA(sc->sc_ioctl_buf) >> 32); 1783e5ec1e72Spatrick req->req_buf_addr.low_addr = 1784e5ec1e72Spatrick htole32((uint64_t)BWFM_PCI_DMA_DVA(sc->sc_ioctl_buf) & 0xffffffff); 1785e5ec1e72Spatrick if (buf) 1786e5ec1e72Spatrick memcpy(BWFM_PCI_DMA_KVA(sc->sc_ioctl_buf), buf, buflen); 1787e5ec1e72Spatrick else 1788e5ec1e72Spatrick memset(BWFM_PCI_DMA_KVA(sc->sc_ioctl_buf), 0, buflen); 1789e5ec1e72Spatrick 1790e5ec1e72Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit); 1791e5ec1e72Spatrick splx(s); 1792e5ec1e72Spatrick 1793e5ec1e72Spatrick if (sc->sc_ioctl_poll) { 1794e5ec1e72Spatrick int i; 1795e5ec1e72Spatrick for (i = 0; i < 100; i++) { 1796e5ec1e72Spatrick if (sc->sc_ioctl_resp_pktid != -1) 1797e5ec1e72Spatrick break; 1798e5ec1e72Spatrick delay(10 * 1000); 1799e5ec1e72Spatrick } 1800e5ec1e72Spatrick if (i == 100) { 1801e5ec1e72Spatrick printf("%s: timeout waiting for ioctl response\n", 1802e5ec1e72Spatrick DEVNAME(sc)); 1803e5ec1e72Spatrick return 1; 1804e5ec1e72Spatrick } 1805e5ec1e72Spatrick } else if (tsleep(&sc->sc_ioctl_buf, PCATCH, "bwfm", hz)) { 1806e5ec1e72Spatrick printf("%s: timeout waiting for ioctl response\n", 1807e5ec1e72Spatrick DEVNAME(sc)); 1808e5ec1e72Spatrick return 1; 1809e5ec1e72Spatrick } 1810e5ec1e72Spatrick 1811e5ec1e72Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts, sc->sc_ioctl_resp_pktid); 1812e5ec1e72Spatrick if (m == NULL) 1813e5ec1e72Spatrick return 1; 1814e5ec1e72Spatrick 1815e5ec1e72Spatrick *len = min(buflen, sc->sc_ioctl_resp_ret_len); 1816e5ec1e72Spatrick if (buf) 1817e5ec1e72Spatrick memcpy(buf, mtod(m, char *), *len); 1818e5ec1e72Spatrick m_freem(m); 1819e5ec1e72Spatrick splx(s); 1820e5ec1e72Spatrick 1821e5ec1e72Spatrick return 0; 1822e5ec1e72Spatrick } 1823e5ec1e72Spatrick 1824e5ec1e72Spatrick int 1825e5ec1e72Spatrick bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *bwfm, int ifidx, 1826e5ec1e72Spatrick int cmd, char *buf, size_t len) 1827e5ec1e72Spatrick { 1828e5ec1e72Spatrick return bwfm_pci_msgbuf_query_dcmd(bwfm, ifidx, cmd, buf, &len); 1829e5ec1e72Spatrick } 1830