1*156d2677Spatrick /* $OpenBSD: if_bwfm_pci.c,v 1.46 2021/02/26 00:14:28 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 592eeba925Spatrick #define BWFM_NUM_IOCTL_PKTIDS 8 60e5ec1e72Spatrick #define BWFM_NUM_TX_PKTIDS 2048 61e5ec1e72Spatrick #define BWFM_NUM_RX_PKTIDS 1024 62e5ec1e72Spatrick 632eeba925Spatrick #define BWFM_NUM_IOCTL_DESCS 1 64e5ec1e72Spatrick #define BWFM_NUM_TX_DESCS 1 65e5ec1e72Spatrick #define BWFM_NUM_RX_DESCS 1 66e5ec1e72Spatrick 67e5ec1e72Spatrick #ifdef BWFM_DEBUG 68e5ec1e72Spatrick #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0) 69e5ec1e72Spatrick #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0) 70e5ec1e72Spatrick static int bwfm_debug = 2; 71e5ec1e72Spatrick #else 72e5ec1e72Spatrick #define DPRINTF(x) do { ; } while (0) 73e5ec1e72Spatrick #define DPRINTFN(n, x) do { ; } while (0) 74e5ec1e72Spatrick #endif 75e5ec1e72Spatrick 76e5ec1e72Spatrick #define DEVNAME(sc) ((sc)->sc_sc.sc_dev.dv_xname) 77e5ec1e72Spatrick 78518be5f3Spatrick enum ring_status { 79518be5f3Spatrick RING_CLOSED, 80518be5f3Spatrick RING_CLOSING, 81518be5f3Spatrick RING_OPEN, 82518be5f3Spatrick RING_OPENING, 83518be5f3Spatrick }; 84518be5f3Spatrick 85e5ec1e72Spatrick struct bwfm_pci_msgring { 86e5ec1e72Spatrick uint32_t w_idx_addr; 87e5ec1e72Spatrick uint32_t r_idx_addr; 88e5ec1e72Spatrick uint32_t w_ptr; 89e5ec1e72Spatrick uint32_t r_ptr; 90e5ec1e72Spatrick int nitem; 91e5ec1e72Spatrick int itemsz; 92518be5f3Spatrick enum ring_status status; 93e5ec1e72Spatrick struct bwfm_pci_dmamem *ring; 9402ee7d07Spatrick struct mbuf *m; 95f67437f3Spatrick 96f67437f3Spatrick int fifo; 97f67437f3Spatrick uint8_t mac[ETHER_ADDR_LEN]; 98e5ec1e72Spatrick }; 99e5ec1e72Spatrick 1002eeba925Spatrick struct bwfm_pci_ioctl { 1012eeba925Spatrick uint16_t transid; 1022eeba925Spatrick uint16_t retlen; 1032eeba925Spatrick int16_t status; 1042eeba925Spatrick struct mbuf *m; 1052eeba925Spatrick TAILQ_ENTRY(bwfm_pci_ioctl) next; 1062eeba925Spatrick }; 1072eeba925Spatrick 108e5ec1e72Spatrick struct bwfm_pci_buf { 109e5ec1e72Spatrick bus_dmamap_t bb_map; 110e5ec1e72Spatrick struct mbuf *bb_m; 111e5ec1e72Spatrick }; 112e5ec1e72Spatrick 113e5ec1e72Spatrick struct bwfm_pci_pkts { 114e5ec1e72Spatrick struct bwfm_pci_buf *pkts; 115e5ec1e72Spatrick uint32_t npkt; 116e5ec1e72Spatrick int last; 117e5ec1e72Spatrick }; 118e5ec1e72Spatrick 119e5ec1e72Spatrick struct bwfm_pci_softc { 120e5ec1e72Spatrick struct bwfm_softc sc_sc; 121e5ec1e72Spatrick pci_chipset_tag_t sc_pc; 122e5ec1e72Spatrick pcitag_t sc_tag; 123e5ec1e72Spatrick pcireg_t sc_id; 124e5ec1e72Spatrick void *sc_ih; 125e5ec1e72Spatrick 126972218f3Spatrick int sc_initialized; 127972218f3Spatrick 128e5ec1e72Spatrick bus_space_tag_t sc_reg_iot; 129e5ec1e72Spatrick bus_space_handle_t sc_reg_ioh; 130e5ec1e72Spatrick bus_size_t sc_reg_ios; 131e5ec1e72Spatrick 132e5ec1e72Spatrick bus_space_tag_t sc_tcm_iot; 133e5ec1e72Spatrick bus_space_handle_t sc_tcm_ioh; 134e5ec1e72Spatrick bus_size_t sc_tcm_ios; 135e5ec1e72Spatrick 136e5ec1e72Spatrick bus_dma_tag_t sc_dmat; 137e5ec1e72Spatrick 138e5ec1e72Spatrick uint32_t sc_shared_address; 139e5ec1e72Spatrick uint32_t sc_shared_flags; 140e5ec1e72Spatrick uint8_t sc_shared_version; 141e5ec1e72Spatrick 142e5ec1e72Spatrick uint8_t sc_dma_idx_sz; 143e5ec1e72Spatrick struct bwfm_pci_dmamem *sc_dma_idx_buf; 144e5ec1e72Spatrick size_t sc_dma_idx_bufsz; 145e5ec1e72Spatrick 146e5ec1e72Spatrick uint16_t sc_max_rxbufpost; 147e5ec1e72Spatrick uint32_t sc_rx_dataoffset; 148e5ec1e72Spatrick uint32_t sc_htod_mb_data_addr; 149e5ec1e72Spatrick uint32_t sc_dtoh_mb_data_addr; 150e5ec1e72Spatrick uint32_t sc_ring_info_addr; 151e5ec1e72Spatrick 152e5ec1e72Spatrick uint32_t sc_console_base_addr; 153e5ec1e72Spatrick uint32_t sc_console_buf_addr; 154e5ec1e72Spatrick uint32_t sc_console_buf_size; 155cadf5fcfSpatrick uint32_t sc_console_readidx; 156e5ec1e72Spatrick 157e5ec1e72Spatrick uint16_t sc_max_flowrings; 158e5ec1e72Spatrick uint16_t sc_max_submissionrings; 159e5ec1e72Spatrick uint16_t sc_max_completionrings; 160e5ec1e72Spatrick 161e5ec1e72Spatrick struct bwfm_pci_msgring sc_ctrl_submit; 162e5ec1e72Spatrick struct bwfm_pci_msgring sc_rxpost_submit; 163e5ec1e72Spatrick struct bwfm_pci_msgring sc_ctrl_complete; 164e5ec1e72Spatrick struct bwfm_pci_msgring sc_tx_complete; 165e5ec1e72Spatrick struct bwfm_pci_msgring sc_rx_complete; 166e5ec1e72Spatrick struct bwfm_pci_msgring *sc_flowrings; 167e5ec1e72Spatrick 168e5ec1e72Spatrick struct bwfm_pci_dmamem *sc_scratch_buf; 169e5ec1e72Spatrick struct bwfm_pci_dmamem *sc_ringupd_buf; 170e5ec1e72Spatrick 1712eeba925Spatrick TAILQ_HEAD(, bwfm_pci_ioctl) sc_ioctlq; 1722eeba925Spatrick uint16_t sc_ioctl_transid; 173e5ec1e72Spatrick 174e5ec1e72Spatrick struct if_rxring sc_ioctl_ring; 175e5ec1e72Spatrick struct if_rxring sc_event_ring; 176e5ec1e72Spatrick struct if_rxring sc_rxbuf_ring; 177e5ec1e72Spatrick 1782eeba925Spatrick struct bwfm_pci_pkts sc_ioctl_pkts; 179e5ec1e72Spatrick struct bwfm_pci_pkts sc_rx_pkts; 180c6f1636dSpatrick struct bwfm_pci_pkts sc_tx_pkts; 181c6f1636dSpatrick int sc_tx_pkts_full; 182e5ec1e72Spatrick }; 183e5ec1e72Spatrick 184e5ec1e72Spatrick struct bwfm_pci_dmamem { 185e5ec1e72Spatrick bus_dmamap_t bdm_map; 186e5ec1e72Spatrick bus_dma_segment_t bdm_seg; 187e5ec1e72Spatrick size_t bdm_size; 188e5ec1e72Spatrick caddr_t bdm_kva; 189e5ec1e72Spatrick }; 190e5ec1e72Spatrick 191e5ec1e72Spatrick #define BWFM_PCI_DMA_MAP(_bdm) ((_bdm)->bdm_map) 192e5ec1e72Spatrick #define BWFM_PCI_DMA_LEN(_bdm) ((_bdm)->bdm_size) 193e4dae658Spatrick #define BWFM_PCI_DMA_DVA(_bdm) ((uint64_t)(_bdm)->bdm_map->dm_segs[0].ds_addr) 194e5ec1e72Spatrick #define BWFM_PCI_DMA_KVA(_bdm) ((void *)(_bdm)->bdm_kva) 195e5ec1e72Spatrick 196e5ec1e72Spatrick int bwfm_pci_match(struct device *, void *, void *); 197e5ec1e72Spatrick void bwfm_pci_attach(struct device *, struct device *, void *); 198e5ec1e72Spatrick int bwfm_pci_detach(struct device *, int); 199e5ec1e72Spatrick 200e5ec1e72Spatrick int bwfm_pci_intr(void *); 201e5ec1e72Spatrick void bwfm_pci_intr_enable(struct bwfm_pci_softc *); 202e5ec1e72Spatrick void bwfm_pci_intr_disable(struct bwfm_pci_softc *); 203*156d2677Spatrick void bwfm_pci_hostready(struct bwfm_pci_softc *); 204e5ec1e72Spatrick int bwfm_pci_load_microcode(struct bwfm_pci_softc *, const u_char *, 2056aad491fSpatrick size_t, const u_char *, size_t); 206e5ec1e72Spatrick void bwfm_pci_select_core(struct bwfm_pci_softc *, int ); 207e5ec1e72Spatrick 208e5ec1e72Spatrick struct bwfm_pci_dmamem * 209e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *, bus_size_t, 210e5ec1e72Spatrick bus_size_t); 211e5ec1e72Spatrick void bwfm_pci_dmamem_free(struct bwfm_pci_softc *, struct bwfm_pci_dmamem *); 21202ee7d07Spatrick int bwfm_pci_pktid_avail(struct bwfm_pci_softc *, 21302ee7d07Spatrick struct bwfm_pci_pkts *); 214e5ec1e72Spatrick int bwfm_pci_pktid_new(struct bwfm_pci_softc *, 215e5ec1e72Spatrick struct bwfm_pci_pkts *, struct mbuf *, 216e5ec1e72Spatrick uint32_t *, paddr_t *); 217e5ec1e72Spatrick struct mbuf * bwfm_pci_pktid_free(struct bwfm_pci_softc *, 218e5ec1e72Spatrick struct bwfm_pci_pkts *, uint32_t); 219e5ec1e72Spatrick void bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *, 220e5ec1e72Spatrick struct if_rxring *, uint32_t); 221e5ec1e72Spatrick void bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *); 222e5ec1e72Spatrick void bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *); 223e5ec1e72Spatrick int bwfm_pci_setup_ring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *, 224e5ec1e72Spatrick int, size_t, uint32_t, uint32_t, int, uint32_t, uint32_t *); 225518be5f3Spatrick int bwfm_pci_setup_flowring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *, 226518be5f3Spatrick int, size_t); 227e5ec1e72Spatrick 228e5ec1e72Spatrick void bwfm_pci_ring_bell(struct bwfm_pci_softc *, 229e5ec1e72Spatrick struct bwfm_pci_msgring *); 230e5ec1e72Spatrick void bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *, 231e5ec1e72Spatrick struct bwfm_pci_msgring *); 232e5ec1e72Spatrick void bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *, 233e5ec1e72Spatrick struct bwfm_pci_msgring *); 234e5ec1e72Spatrick void bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *, 235e5ec1e72Spatrick struct bwfm_pci_msgring *); 236e5ec1e72Spatrick void bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *, 237e5ec1e72Spatrick struct bwfm_pci_msgring *); 238e5ec1e72Spatrick void * bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *, 239e5ec1e72Spatrick struct bwfm_pci_msgring *); 240e5ec1e72Spatrick void * bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *, 241e5ec1e72Spatrick struct bwfm_pci_msgring *, int, int *); 242e5ec1e72Spatrick void * bwfm_pci_ring_read_avail(struct bwfm_pci_softc *, 243e5ec1e72Spatrick struct bwfm_pci_msgring *, int *); 244e5ec1e72Spatrick void bwfm_pci_ring_read_commit(struct bwfm_pci_softc *, 245e5ec1e72Spatrick struct bwfm_pci_msgring *, int); 246e5ec1e72Spatrick void bwfm_pci_ring_write_commit(struct bwfm_pci_softc *, 247e5ec1e72Spatrick struct bwfm_pci_msgring *); 248e5ec1e72Spatrick void bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *, 249e5ec1e72Spatrick struct bwfm_pci_msgring *, int); 250e5ec1e72Spatrick 251e5ec1e72Spatrick void bwfm_pci_ring_rx(struct bwfm_pci_softc *, 2526f241297Spatrick struct bwfm_pci_msgring *, struct mbuf_list *); 2536f241297Spatrick void bwfm_pci_msg_rx(struct bwfm_pci_softc *, void *, 2546f241297Spatrick struct mbuf_list *); 255e5ec1e72Spatrick 256e5ec1e72Spatrick uint32_t bwfm_pci_buscore_read(struct bwfm_softc *, uint32_t); 257e5ec1e72Spatrick void bwfm_pci_buscore_write(struct bwfm_softc *, uint32_t, 258e5ec1e72Spatrick uint32_t); 259e5ec1e72Spatrick int bwfm_pci_buscore_prepare(struct bwfm_softc *); 260e5ec1e72Spatrick int bwfm_pci_buscore_reset(struct bwfm_softc *); 261e5ec1e72Spatrick void bwfm_pci_buscore_activate(struct bwfm_softc *, uint32_t); 262e5ec1e72Spatrick 263f67437f3Spatrick int bwfm_pci_flowring_lookup(struct bwfm_pci_softc *, 264f67437f3Spatrick struct mbuf *); 265f67437f3Spatrick void bwfm_pci_flowring_create(struct bwfm_pci_softc *, 266518be5f3Spatrick struct mbuf *); 267518be5f3Spatrick void bwfm_pci_flowring_create_cb(struct bwfm_softc *, void *); 268a2c6ff8bSpatrick void bwfm_pci_flowring_delete(struct bwfm_pci_softc *, int); 269518be5f3Spatrick 270972218f3Spatrick int bwfm_pci_preinit(struct bwfm_softc *); 271a2c6ff8bSpatrick void bwfm_pci_stop(struct bwfm_softc *); 27202ee7d07Spatrick int bwfm_pci_txcheck(struct bwfm_softc *); 273e5ec1e72Spatrick int bwfm_pci_txdata(struct bwfm_softc *, struct mbuf *); 274bbd71b0bSpatrick 275bbd71b0bSpatrick #ifdef BWFM_DEBUG 276cadf5fcfSpatrick void bwfm_pci_debug_console(struct bwfm_pci_softc *); 277bbd71b0bSpatrick #endif 278e5ec1e72Spatrick 279e5ec1e72Spatrick int bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *, int, 280e5ec1e72Spatrick int, char *, size_t *); 281e5ec1e72Spatrick int bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *, int, 282e5ec1e72Spatrick int, char *, size_t); 2832eeba925Spatrick void bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *, 2842eeba925Spatrick struct msgbuf_ioctl_resp_hdr *); 285e5ec1e72Spatrick 286e5ec1e72Spatrick struct bwfm_buscore_ops bwfm_pci_buscore_ops = { 287e5ec1e72Spatrick .bc_read = bwfm_pci_buscore_read, 288e5ec1e72Spatrick .bc_write = bwfm_pci_buscore_write, 289e5ec1e72Spatrick .bc_prepare = bwfm_pci_buscore_prepare, 290e5ec1e72Spatrick .bc_reset = bwfm_pci_buscore_reset, 291e5ec1e72Spatrick .bc_setup = NULL, 292e5ec1e72Spatrick .bc_activate = bwfm_pci_buscore_activate, 293e5ec1e72Spatrick }; 294e5ec1e72Spatrick 295e5ec1e72Spatrick struct bwfm_bus_ops bwfm_pci_bus_ops = { 296972218f3Spatrick .bs_preinit = bwfm_pci_preinit, 297a2c6ff8bSpatrick .bs_stop = bwfm_pci_stop, 29802ee7d07Spatrick .bs_txcheck = bwfm_pci_txcheck, 299e5ec1e72Spatrick .bs_txdata = bwfm_pci_txdata, 300e5ec1e72Spatrick .bs_txctl = NULL, 301e5ec1e72Spatrick }; 302e5ec1e72Spatrick 303e5ec1e72Spatrick struct bwfm_proto_ops bwfm_pci_msgbuf_ops = { 304e5ec1e72Spatrick .proto_query_dcmd = bwfm_pci_msgbuf_query_dcmd, 305e5ec1e72Spatrick .proto_set_dcmd = bwfm_pci_msgbuf_set_dcmd, 30614c74651Spatrick .proto_rx = NULL, 307029d6dd5Spatrick .proto_rxctl = NULL, 308e5ec1e72Spatrick }; 309e5ec1e72Spatrick 310e5ec1e72Spatrick struct cfattach bwfm_pci_ca = { 311e5ec1e72Spatrick sizeof(struct bwfm_pci_softc), 312e5ec1e72Spatrick bwfm_pci_match, 313e5ec1e72Spatrick bwfm_pci_attach, 314e5ec1e72Spatrick bwfm_pci_detach, 315e5ec1e72Spatrick }; 316e5ec1e72Spatrick 317e5ec1e72Spatrick static const struct pci_matchid bwfm_pci_devices[] = { 31882f0e660Sjcs { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4350 }, 31941d93ac2Spatrick { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4356 }, 32041d93ac2Spatrick { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43602 }, 321821fc986Spatrick { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4371 }, 322e5ec1e72Spatrick }; 323e5ec1e72Spatrick 324e5ec1e72Spatrick int 325e5ec1e72Spatrick bwfm_pci_match(struct device *parent, void *match, void *aux) 326e5ec1e72Spatrick { 327e5ec1e72Spatrick return (pci_matchbyid(aux, bwfm_pci_devices, 328e5ec1e72Spatrick nitems(bwfm_pci_devices))); 329e5ec1e72Spatrick } 330e5ec1e72Spatrick 331e5ec1e72Spatrick void 332e5ec1e72Spatrick bwfm_pci_attach(struct device *parent, struct device *self, void *aux) 333e5ec1e72Spatrick { 334e5ec1e72Spatrick struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self; 335e5ec1e72Spatrick struct pci_attach_args *pa = (struct pci_attach_args *)aux; 336e5ec1e72Spatrick const char *intrstr; 337e5ec1e72Spatrick pci_intr_handle_t ih; 338e5ec1e72Spatrick 339e5ec1e72Spatrick if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x08, 340e5ec1e72Spatrick PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_tcm_iot, &sc->sc_tcm_ioh, 341e5ec1e72Spatrick NULL, &sc->sc_tcm_ios, 0)) { 342e5ec1e72Spatrick printf(": can't map bar1\n"); 343a08e9144Spatrick return; 344a08e9144Spatrick } 345a08e9144Spatrick 346a08e9144Spatrick if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x00, 347a08e9144Spatrick PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_reg_iot, &sc->sc_reg_ioh, 348a08e9144Spatrick NULL, &sc->sc_reg_ios, 0)) { 349a08e9144Spatrick printf(": can't map bar0\n"); 350a08e9144Spatrick goto bar1; 351e5ec1e72Spatrick } 352e5ec1e72Spatrick 353e5ec1e72Spatrick sc->sc_pc = pa->pa_pc; 354e5ec1e72Spatrick sc->sc_tag = pa->pa_tag; 355e5ec1e72Spatrick sc->sc_id = pa->pa_id; 356e5ec1e72Spatrick sc->sc_dmat = pa->pa_dmat; 357e5ec1e72Spatrick 358e5ec1e72Spatrick /* Map and establish the interrupt. */ 359e5ec1e72Spatrick if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) { 360e5ec1e72Spatrick printf(": couldn't map interrupt\n"); 361a08e9144Spatrick goto bar0; 362e5ec1e72Spatrick } 363e5ec1e72Spatrick intrstr = pci_intr_string(pa->pa_pc, ih); 364e5ec1e72Spatrick 365e5ec1e72Spatrick sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET | IPL_MPSAFE, 366e5ec1e72Spatrick bwfm_pci_intr, sc, DEVNAME(sc)); 367e5ec1e72Spatrick if (sc->sc_ih == NULL) { 368e5ec1e72Spatrick printf(": couldn't establish interrupt"); 369e5ec1e72Spatrick if (intrstr != NULL) 370e5ec1e72Spatrick printf(" at %s", intrstr); 371e5ec1e72Spatrick printf("\n"); 372e5ec1e72Spatrick goto bar1; 373e5ec1e72Spatrick } 374e5ec1e72Spatrick printf(": %s\n", intrstr); 375e5ec1e72Spatrick 376972218f3Spatrick sc->sc_sc.sc_bus_ops = &bwfm_pci_bus_ops; 377972218f3Spatrick sc->sc_sc.sc_proto_ops = &bwfm_pci_msgbuf_ops; 378972218f3Spatrick bwfm_attach(&sc->sc_sc); 379972218f3Spatrick config_mountroot(self, bwfm_attachhook); 380e5ec1e72Spatrick return; 381e5ec1e72Spatrick 382e5ec1e72Spatrick bar0: 383e5ec1e72Spatrick bus_space_unmap(sc->sc_reg_iot, sc->sc_reg_ioh, sc->sc_reg_ios); 384a08e9144Spatrick bar1: 385a08e9144Spatrick bus_space_unmap(sc->sc_tcm_iot, sc->sc_tcm_ioh, sc->sc_tcm_ios); 386e5ec1e72Spatrick } 387e5ec1e72Spatrick 388972218f3Spatrick int 389972218f3Spatrick bwfm_pci_preinit(struct bwfm_softc *bwfm) 390e5ec1e72Spatrick { 391972218f3Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 392e5ec1e72Spatrick struct bwfm_pci_ringinfo ringinfo; 3939ead8393Spatrick const char *chip = NULL; 39494e4747cSpatrick u_char *ucode, *nvram; 39594e4747cSpatrick size_t size, nvsize, nvlen; 396e5ec1e72Spatrick uint32_t d2h_w_idx_ptr, d2h_r_idx_ptr; 397e5ec1e72Spatrick uint32_t h2d_w_idx_ptr, h2d_r_idx_ptr; 398e5ec1e72Spatrick uint32_t idx_offset, reg; 399e5ec1e72Spatrick int i; 400e5ec1e72Spatrick 401972218f3Spatrick if (sc->sc_initialized) 402972218f3Spatrick return 0; 403972218f3Spatrick 404e5ec1e72Spatrick sc->sc_sc.sc_buscore_ops = &bwfm_pci_buscore_ops; 405e5ec1e72Spatrick if (bwfm_chip_attach(&sc->sc_sc) != 0) { 406e5ec1e72Spatrick printf("%s: cannot attach chip\n", DEVNAME(sc)); 407972218f3Spatrick return 1; 408e5ec1e72Spatrick } 409e5ec1e72Spatrick 410e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2); 411e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 412e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGADDR, 0x4e0); 413e5ec1e72Spatrick reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 414e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA); 415e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 416e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA, reg); 417e5ec1e72Spatrick 418e5ec1e72Spatrick switch (bwfm->sc_chip.ch_chip) 419e5ec1e72Spatrick { 42018b3a1dcSpatrick case BRCM_CC_4350_CHIP_ID: 4219ead8393Spatrick if (bwfm->sc_chip.ch_chiprev > 7) 4229ead8393Spatrick chip = "4350"; 4239ead8393Spatrick else 4249ead8393Spatrick chip = "4350c2"; 42518b3a1dcSpatrick break; 42641d93ac2Spatrick case BRCM_CC_4356_CHIP_ID: 4279ead8393Spatrick chip = "4356"; 42841d93ac2Spatrick break; 429e5ec1e72Spatrick case BRCM_CC_43602_CHIP_ID: 4309ead8393Spatrick chip = "43602"; 431e5ec1e72Spatrick break; 432821fc986Spatrick case BRCM_CC_4371_CHIP_ID: 4339ead8393Spatrick chip = "4371"; 434821fc986Spatrick break; 435c38a9bc9Spatrick case BRCM_CC_4378_CHIP_ID: 436c38a9bc9Spatrick chip = "4378"; 437c38a9bc9Spatrick break; 438e5ec1e72Spatrick default: 43918b3a1dcSpatrick printf("%s: unknown firmware for chip %s\n", 44018b3a1dcSpatrick DEVNAME(sc), bwfm->sc_chip.ch_name); 441972218f3Spatrick return 1; 442e5ec1e72Spatrick } 443e5ec1e72Spatrick 44494e4747cSpatrick if (bwfm_loadfirmware(bwfm, chip, "-pcie", &ucode, &size, 44594e4747cSpatrick &nvram, &nvsize, &nvlen) != 0) 446972218f3Spatrick return 1; 4476aad491fSpatrick 448e5ec1e72Spatrick /* Retrieve RAM size from firmware. */ 449e5ec1e72Spatrick if (size >= BWFM_RAMSIZE + 8) { 450e5ec1e72Spatrick uint32_t *ramsize = (uint32_t *)&ucode[BWFM_RAMSIZE]; 451e5ec1e72Spatrick if (letoh32(ramsize[0]) == BWFM_RAMSIZE_MAGIC) 452e5ec1e72Spatrick bwfm->sc_chip.ch_ramsize = letoh32(ramsize[1]); 453e5ec1e72Spatrick } 454e5ec1e72Spatrick 4556aad491fSpatrick if (bwfm_pci_load_microcode(sc, ucode, size, nvram, nvlen) != 0) { 456e5ec1e72Spatrick printf("%s: could not load microcode\n", 457e5ec1e72Spatrick DEVNAME(sc)); 458e5ec1e72Spatrick free(ucode, M_DEVBUF, size); 459b4e85b06Spatrick free(nvram, M_DEVBUF, nvsize); 460972218f3Spatrick return 1; 461e5ec1e72Spatrick } 462e5ec1e72Spatrick free(ucode, M_DEVBUF, size); 463b4e85b06Spatrick free(nvram, M_DEVBUF, nvsize); 464e5ec1e72Spatrick 465e5ec1e72Spatrick sc->sc_shared_flags = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 466e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_INFO); 467e5ec1e72Spatrick sc->sc_shared_version = sc->sc_shared_flags; 468e5ec1e72Spatrick if (sc->sc_shared_version > BWFM_SHARED_INFO_MAX_VERSION || 469e5ec1e72Spatrick sc->sc_shared_version < BWFM_SHARED_INFO_MIN_VERSION) { 470e5ec1e72Spatrick printf("%s: PCIe version %d unsupported\n", 471e5ec1e72Spatrick DEVNAME(sc), sc->sc_shared_version); 472972218f3Spatrick return 1; 473e5ec1e72Spatrick } 474e5ec1e72Spatrick 475e5ec1e72Spatrick if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_INDEX) { 476e5ec1e72Spatrick if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_2B_IDX) 477e5ec1e72Spatrick sc->sc_dma_idx_sz = sizeof(uint16_t); 478e5ec1e72Spatrick else 479e5ec1e72Spatrick sc->sc_dma_idx_sz = sizeof(uint32_t); 480e5ec1e72Spatrick } 481e5ec1e72Spatrick 482e5ec1e72Spatrick /* Maximum RX data buffers in the ring. */ 483e5ec1e72Spatrick sc->sc_max_rxbufpost = bus_space_read_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 484e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_MAX_RXBUFPOST); 485e5ec1e72Spatrick if (sc->sc_max_rxbufpost == 0) 486e5ec1e72Spatrick sc->sc_max_rxbufpost = BWFM_SHARED_MAX_RXBUFPOST_DEFAULT; 487e5ec1e72Spatrick 488e5ec1e72Spatrick /* Alternative offset of data in a packet */ 489e5ec1e72Spatrick sc->sc_rx_dataoffset = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 490e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_RX_DATAOFFSET); 491e5ec1e72Spatrick 492e5ec1e72Spatrick /* For Power Management */ 493e5ec1e72Spatrick sc->sc_htod_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 494e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_HTOD_MB_DATA_ADDR); 495e5ec1e72Spatrick sc->sc_dtoh_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 496e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DTOH_MB_DATA_ADDR); 497e5ec1e72Spatrick 498e5ec1e72Spatrick /* Ring information */ 499e5ec1e72Spatrick sc->sc_ring_info_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 500e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_RING_INFO_ADDR); 501e5ec1e72Spatrick 502e5ec1e72Spatrick /* Firmware's "dmesg" */ 503e5ec1e72Spatrick sc->sc_console_base_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 504e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_CONSOLE_ADDR); 505e5ec1e72Spatrick sc->sc_console_buf_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 506e5ec1e72Spatrick sc->sc_console_base_addr + BWFM_CONSOLE_BUFADDR); 507e5ec1e72Spatrick sc->sc_console_buf_size = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 508e5ec1e72Spatrick sc->sc_console_base_addr + BWFM_CONSOLE_BUFSIZE); 509e5ec1e72Spatrick 510e5ec1e72Spatrick /* Read ring information. */ 511e5ec1e72Spatrick bus_space_read_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 512e5ec1e72Spatrick sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo)); 513e5ec1e72Spatrick 514e5ec1e72Spatrick if (sc->sc_shared_version >= 6) { 515e5ec1e72Spatrick sc->sc_max_submissionrings = le16toh(ringinfo.max_submissionrings); 516e5ec1e72Spatrick sc->sc_max_flowrings = le16toh(ringinfo.max_flowrings); 517e5ec1e72Spatrick sc->sc_max_completionrings = le16toh(ringinfo.max_completionrings); 518e5ec1e72Spatrick } else { 519e5ec1e72Spatrick sc->sc_max_submissionrings = le16toh(ringinfo.max_flowrings); 520e5ec1e72Spatrick sc->sc_max_flowrings = sc->sc_max_submissionrings - 521e5ec1e72Spatrick BWFM_NUM_TX_MSGRINGS; 522e5ec1e72Spatrick sc->sc_max_completionrings = BWFM_NUM_RX_MSGRINGS; 523e5ec1e72Spatrick } 524e5ec1e72Spatrick 525e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 526e5ec1e72Spatrick d2h_w_idx_ptr = letoh32(ringinfo.d2h_w_idx_ptr); 527e5ec1e72Spatrick d2h_r_idx_ptr = letoh32(ringinfo.d2h_r_idx_ptr); 528e5ec1e72Spatrick h2d_w_idx_ptr = letoh32(ringinfo.h2d_w_idx_ptr); 529e5ec1e72Spatrick h2d_r_idx_ptr = letoh32(ringinfo.h2d_r_idx_ptr); 530e5ec1e72Spatrick idx_offset = sizeof(uint32_t); 531e5ec1e72Spatrick } else { 532e5ec1e72Spatrick uint64_t address; 533e5ec1e72Spatrick 534e5ec1e72Spatrick /* Each TX/RX Ring has a Read and Write Ptr */ 535e5ec1e72Spatrick sc->sc_dma_idx_bufsz = (sc->sc_max_submissionrings + 536e5ec1e72Spatrick sc->sc_max_completionrings) * sc->sc_dma_idx_sz * 2; 537e5ec1e72Spatrick sc->sc_dma_idx_buf = bwfm_pci_dmamem_alloc(sc, 538e5ec1e72Spatrick sc->sc_dma_idx_bufsz, 8); 539e5ec1e72Spatrick if (sc->sc_dma_idx_buf == NULL) { 540e5ec1e72Spatrick /* XXX: Fallback to TCM? */ 541e5ec1e72Spatrick printf("%s: cannot allocate idx buf\n", 542e5ec1e72Spatrick DEVNAME(sc)); 543972218f3Spatrick return 1; 544e5ec1e72Spatrick } 545e5ec1e72Spatrick 546e5ec1e72Spatrick idx_offset = sc->sc_dma_idx_sz; 547e5ec1e72Spatrick h2d_w_idx_ptr = 0; 548e5ec1e72Spatrick address = BWFM_PCI_DMA_DVA(sc->sc_dma_idx_buf); 549e5ec1e72Spatrick ringinfo.h2d_w_idx_hostaddr_low = 550e5ec1e72Spatrick htole32(address & 0xffffffff); 551e5ec1e72Spatrick ringinfo.h2d_w_idx_hostaddr_high = 552e5ec1e72Spatrick htole32(address >> 32); 553e5ec1e72Spatrick 554e5ec1e72Spatrick h2d_r_idx_ptr = h2d_w_idx_ptr + 555e5ec1e72Spatrick sc->sc_max_submissionrings * idx_offset; 556e5ec1e72Spatrick address += sc->sc_max_submissionrings * idx_offset; 557e5ec1e72Spatrick ringinfo.h2d_r_idx_hostaddr_low = 558e5ec1e72Spatrick htole32(address & 0xffffffff); 559e5ec1e72Spatrick ringinfo.h2d_r_idx_hostaddr_high = 560e5ec1e72Spatrick htole32(address >> 32); 561e5ec1e72Spatrick 562e5ec1e72Spatrick d2h_w_idx_ptr = h2d_r_idx_ptr + 563e5ec1e72Spatrick sc->sc_max_submissionrings * idx_offset; 564e5ec1e72Spatrick address += sc->sc_max_submissionrings * idx_offset; 565e5ec1e72Spatrick ringinfo.d2h_w_idx_hostaddr_low = 566e5ec1e72Spatrick htole32(address & 0xffffffff); 567e5ec1e72Spatrick ringinfo.d2h_w_idx_hostaddr_high = 568e5ec1e72Spatrick htole32(address >> 32); 569e5ec1e72Spatrick 570e5ec1e72Spatrick d2h_r_idx_ptr = d2h_w_idx_ptr + 571e5ec1e72Spatrick sc->sc_max_completionrings * idx_offset; 572e5ec1e72Spatrick address += sc->sc_max_completionrings * idx_offset; 573e5ec1e72Spatrick ringinfo.d2h_r_idx_hostaddr_low = 574e5ec1e72Spatrick htole32(address & 0xffffffff); 575e5ec1e72Spatrick ringinfo.d2h_r_idx_hostaddr_high = 576e5ec1e72Spatrick htole32(address >> 32); 577e5ec1e72Spatrick 578e5ec1e72Spatrick bus_space_write_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 579e5ec1e72Spatrick sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo)); 580e5ec1e72Spatrick } 581e5ec1e72Spatrick 582e5ec1e72Spatrick uint32_t ring_mem_ptr = letoh32(ringinfo.ringmem); 583e5ec1e72Spatrick /* TX ctrl ring: Send ctrl buffers, send IOCTLs */ 584e5ec1e72Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_submit, 64, 40, 585e5ec1e72Spatrick h2d_w_idx_ptr, h2d_r_idx_ptr, 0, idx_offset, 586e5ec1e72Spatrick &ring_mem_ptr)) 587e5ec1e72Spatrick goto cleanup; 588e5ec1e72Spatrick /* TX rxpost ring: Send clean data mbufs for RX */ 589e5ec1e72Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_rxpost_submit, 512, 32, 590e5ec1e72Spatrick h2d_w_idx_ptr, h2d_r_idx_ptr, 1, idx_offset, 591e5ec1e72Spatrick &ring_mem_ptr)) 592e5ec1e72Spatrick goto cleanup; 593e5ec1e72Spatrick /* RX completion rings: recv our filled buffers back */ 594e5ec1e72Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_complete, 64, 24, 595e5ec1e72Spatrick d2h_w_idx_ptr, d2h_r_idx_ptr, 0, idx_offset, 596e5ec1e72Spatrick &ring_mem_ptr)) 597e5ec1e72Spatrick goto cleanup; 598095b0c44Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_tx_complete, 1024, 599095b0c44Spatrick sc->sc_shared_version >= 7 ? 24 : 16, 600e5ec1e72Spatrick d2h_w_idx_ptr, d2h_r_idx_ptr, 1, idx_offset, 601e5ec1e72Spatrick &ring_mem_ptr)) 602e5ec1e72Spatrick goto cleanup; 603095b0c44Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_rx_complete, 512, 604095b0c44Spatrick sc->sc_shared_version >= 7 ? 40 : 32, 605e5ec1e72Spatrick d2h_w_idx_ptr, d2h_r_idx_ptr, 2, idx_offset, 606e5ec1e72Spatrick &ring_mem_ptr)) 607e5ec1e72Spatrick goto cleanup; 608e5ec1e72Spatrick 609e5ec1e72Spatrick /* Dynamic TX rings for actual data */ 610e5ec1e72Spatrick sc->sc_flowrings = malloc(sc->sc_max_flowrings * 611e5ec1e72Spatrick sizeof(struct bwfm_pci_msgring), M_DEVBUF, M_WAITOK | M_ZERO); 612518be5f3Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 613518be5f3Spatrick struct bwfm_pci_msgring *ring = &sc->sc_flowrings[i]; 614518be5f3Spatrick ring->w_idx_addr = h2d_w_idx_ptr + (i + 2) * idx_offset; 615518be5f3Spatrick ring->r_idx_addr = h2d_r_idx_ptr + (i + 2) * idx_offset; 616518be5f3Spatrick } 617e5ec1e72Spatrick 618e5ec1e72Spatrick /* Scratch and ring update buffers for firmware */ 619e5ec1e72Spatrick if ((sc->sc_scratch_buf = bwfm_pci_dmamem_alloc(sc, 620e5ec1e72Spatrick BWFM_DMA_D2H_SCRATCH_BUF_LEN, 8)) == NULL) 621e5ec1e72Spatrick goto cleanup; 622e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 623e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_LOW, 624e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) & 0xffffffff); 625e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 626e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_HIGH, 627e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) >> 32); 628e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 629e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_LEN, 630e5ec1e72Spatrick BWFM_DMA_D2H_SCRATCH_BUF_LEN); 631e5ec1e72Spatrick 632e5ec1e72Spatrick if ((sc->sc_ringupd_buf = bwfm_pci_dmamem_alloc(sc, 633e5ec1e72Spatrick BWFM_DMA_D2H_RINGUPD_BUF_LEN, 8)) == NULL) 634e5ec1e72Spatrick goto cleanup; 635e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 636e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_LOW, 637e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) & 0xffffffff); 638e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 639e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_HIGH, 640e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) >> 32); 641e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 642e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_LEN, 643e5ec1e72Spatrick BWFM_DMA_D2H_RINGUPD_BUF_LEN); 644e5ec1e72Spatrick 645e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2); 646e5ec1e72Spatrick bwfm_pci_intr_enable(sc); 647*156d2677Spatrick bwfm_pci_hostready(sc); 648e5ec1e72Spatrick 649e5ec1e72Spatrick /* Maps RX mbufs to a packet id and back. */ 650e5ec1e72Spatrick sc->sc_rx_pkts.npkt = BWFM_NUM_RX_PKTIDS; 651e5ec1e72Spatrick sc->sc_rx_pkts.pkts = malloc(BWFM_NUM_RX_PKTIDS * 652e5ec1e72Spatrick sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO); 653e5ec1e72Spatrick for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++) 654e5ec1e72Spatrick bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE, 655e5ec1e72Spatrick BWFM_NUM_RX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK, 656e5ec1e72Spatrick &sc->sc_rx_pkts.pkts[i].bb_map); 657e5ec1e72Spatrick 658e5ec1e72Spatrick /* Maps TX mbufs to a packet id and back. */ 659f416501bSpatrick sc->sc_tx_pkts.npkt = BWFM_NUM_TX_PKTIDS; 660e5ec1e72Spatrick sc->sc_tx_pkts.pkts = malloc(BWFM_NUM_TX_PKTIDS 661e5ec1e72Spatrick * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO); 662e5ec1e72Spatrick for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++) 663e5ec1e72Spatrick bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE, 664e5ec1e72Spatrick BWFM_NUM_TX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK, 665e5ec1e72Spatrick &sc->sc_tx_pkts.pkts[i].bb_map); 666e5ec1e72Spatrick 6672eeba925Spatrick /* Maps IOCTL mbufs to a packet id and back. */ 6682eeba925Spatrick sc->sc_ioctl_pkts.npkt = BWFM_NUM_IOCTL_PKTIDS; 6692eeba925Spatrick sc->sc_ioctl_pkts.pkts = malloc(BWFM_NUM_IOCTL_PKTIDS 6702eeba925Spatrick * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO); 6712eeba925Spatrick for (i = 0; i < BWFM_NUM_IOCTL_PKTIDS; i++) 6722eeba925Spatrick bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE, 6732eeba925Spatrick BWFM_NUM_IOCTL_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK, 6742eeba925Spatrick &sc->sc_ioctl_pkts.pkts[i].bb_map); 6752eeba925Spatrick 67618722113Spatrick /* 67718722113Spatrick * For whatever reason, could also be a bug somewhere in this 67818722113Spatrick * driver, the firmware needs a bunch of RX buffers otherwise 67918722113Spatrick * it won't send any RX complete messages. 64 buffers don't 68018722113Spatrick * suffice, but 128 buffers are enough. 68118722113Spatrick */ 68218722113Spatrick if_rxr_init(&sc->sc_rxbuf_ring, 128, sc->sc_max_rxbufpost); 683e5ec1e72Spatrick if_rxr_init(&sc->sc_ioctl_ring, 8, 8); 684e5ec1e72Spatrick if_rxr_init(&sc->sc_event_ring, 8, 8); 685e5ec1e72Spatrick bwfm_pci_fill_rx_rings(sc); 686e5ec1e72Spatrick 6872eeba925Spatrick TAILQ_INIT(&sc->sc_ioctlq); 6882eeba925Spatrick 689cadf5fcfSpatrick #ifdef BWFM_DEBUG 690cadf5fcfSpatrick sc->sc_console_readidx = 0; 691cadf5fcfSpatrick bwfm_pci_debug_console(sc); 692cadf5fcfSpatrick #endif 693cadf5fcfSpatrick 694972218f3Spatrick sc->sc_initialized = 1; 695972218f3Spatrick return 0; 696e5ec1e72Spatrick 697e5ec1e72Spatrick cleanup: 698e5ec1e72Spatrick if (sc->sc_ringupd_buf) 699e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf); 700e5ec1e72Spatrick if (sc->sc_scratch_buf) 701e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf); 702e5ec1e72Spatrick if (sc->sc_rx_complete.ring) 703e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring); 704e5ec1e72Spatrick if (sc->sc_tx_complete.ring) 705e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring); 706e5ec1e72Spatrick if (sc->sc_ctrl_complete.ring) 707e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring); 708e5ec1e72Spatrick if (sc->sc_rxpost_submit.ring) 709e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring); 710e5ec1e72Spatrick if (sc->sc_ctrl_submit.ring) 711e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring); 712e5ec1e72Spatrick if (sc->sc_dma_idx_buf) 713e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf); 714972218f3Spatrick return 1; 715e5ec1e72Spatrick } 716e5ec1e72Spatrick 717e5ec1e72Spatrick int 7186aad491fSpatrick bwfm_pci_load_microcode(struct bwfm_pci_softc *sc, const u_char *ucode, size_t size, 7196aad491fSpatrick const u_char *nvram, size_t nvlen) 720e5ec1e72Spatrick { 721e5ec1e72Spatrick struct bwfm_softc *bwfm = (void *)sc; 722e5ec1e72Spatrick struct bwfm_core *core; 7236aad491fSpatrick uint32_t shared, written; 724e5ec1e72Spatrick int i; 725e5ec1e72Spatrick 726e5ec1e72Spatrick if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) { 727e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_ARM_CR4); 728e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 729e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKIDX, 5); 730e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 731e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKPDA, 0); 732e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 733e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKIDX, 7); 734e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 735e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKPDA, 0); 736e5ec1e72Spatrick } 737e5ec1e72Spatrick 738e5ec1e72Spatrick for (i = 0; i < size; i++) 739e5ec1e72Spatrick bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 740e5ec1e72Spatrick bwfm->sc_chip.ch_rambase + i, ucode[i]); 741e5ec1e72Spatrick 742e5ec1e72Spatrick /* Firmware replaces this with a pointer once up. */ 743e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 744e5ec1e72Spatrick bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4, 0); 745e5ec1e72Spatrick 7466aad491fSpatrick if (nvram) { 7476aad491fSpatrick for (i = 0; i < nvlen; i++) 7486aad491fSpatrick bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 7496aad491fSpatrick bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize 7506aad491fSpatrick - nvlen + i, nvram[i]); 7516aad491fSpatrick } 7526aad491fSpatrick 7536aad491fSpatrick written = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 7546aad491fSpatrick bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4); 755e5ec1e72Spatrick 756e5ec1e72Spatrick /* Load reset vector from firmware and kickstart core. */ 757b0cd4990Spatrick if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) { 758e5ec1e72Spatrick core = bwfm_chip_get_core(bwfm, BWFM_AGENT_INTERNAL_MEM); 759e5ec1e72Spatrick bwfm->sc_chip.ch_core_reset(bwfm, core, 0, 0, 0); 760b0cd4990Spatrick } 761e5ec1e72Spatrick bwfm_chip_set_active(bwfm, *(uint32_t *)ucode); 762e5ec1e72Spatrick 7633c53ddefSpatrick for (i = 0; i < 100; i++) { 764e5ec1e72Spatrick delay(50 * 1000); 765e5ec1e72Spatrick shared = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 766e5ec1e72Spatrick bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4); 7676aad491fSpatrick if (shared != written) 768e5ec1e72Spatrick break; 769e5ec1e72Spatrick } 77019871452Spatrick if (shared == written) { 771e5ec1e72Spatrick printf("%s: firmware did not come up\n", DEVNAME(sc)); 772e5ec1e72Spatrick return 1; 773e5ec1e72Spatrick } 77419871452Spatrick if (shared < bwfm->sc_chip.ch_rambase || 77519871452Spatrick shared >= bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize) { 77619871452Spatrick printf("%s: invalid shared RAM address 0x%08x\n", DEVNAME(sc), 77719871452Spatrick shared); 77819871452Spatrick return 1; 77919871452Spatrick } 780e5ec1e72Spatrick 781e5ec1e72Spatrick sc->sc_shared_address = shared; 782e5ec1e72Spatrick return 0; 783e5ec1e72Spatrick } 784e5ec1e72Spatrick 785e5ec1e72Spatrick int 786e5ec1e72Spatrick bwfm_pci_detach(struct device *self, int flags) 787e5ec1e72Spatrick { 788e5ec1e72Spatrick struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self; 789e5ec1e72Spatrick 790e5ec1e72Spatrick bwfm_detach(&sc->sc_sc, flags); 791e5ec1e72Spatrick 792e5ec1e72Spatrick /* FIXME: free RX buffers */ 793e5ec1e72Spatrick /* FIXME: free TX buffers */ 794e5ec1e72Spatrick /* FIXME: free more memory */ 795e5ec1e72Spatrick 796e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf); 797e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf); 798e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring); 799e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring); 800e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring); 801e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring); 802e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring); 803e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf); 804e5ec1e72Spatrick return 0; 805e5ec1e72Spatrick } 806e5ec1e72Spatrick 807e5ec1e72Spatrick /* DMA code */ 808e5ec1e72Spatrick struct bwfm_pci_dmamem * 809e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *sc, bus_size_t size, bus_size_t align) 810e5ec1e72Spatrick { 811e5ec1e72Spatrick struct bwfm_pci_dmamem *bdm; 812e5ec1e72Spatrick int nsegs; 813e5ec1e72Spatrick 814e5ec1e72Spatrick bdm = malloc(sizeof(*bdm), M_DEVBUF, M_WAITOK | M_ZERO); 815e5ec1e72Spatrick bdm->bdm_size = size; 816e5ec1e72Spatrick 817e5ec1e72Spatrick if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 818e5ec1e72Spatrick BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &bdm->bdm_map) != 0) 819e5ec1e72Spatrick goto bdmfree; 820e5ec1e72Spatrick 821e5ec1e72Spatrick if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &bdm->bdm_seg, 1, 822e5ec1e72Spatrick &nsegs, BUS_DMA_WAITOK) != 0) 823e5ec1e72Spatrick goto destroy; 824e5ec1e72Spatrick 825e5ec1e72Spatrick if (bus_dmamem_map(sc->sc_dmat, &bdm->bdm_seg, nsegs, size, 826e5ec1e72Spatrick &bdm->bdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0) 827e5ec1e72Spatrick goto free; 828e5ec1e72Spatrick 829e5ec1e72Spatrick if (bus_dmamap_load(sc->sc_dmat, bdm->bdm_map, bdm->bdm_kva, size, 830e5ec1e72Spatrick NULL, BUS_DMA_WAITOK) != 0) 831e5ec1e72Spatrick goto unmap; 832e5ec1e72Spatrick 833e5ec1e72Spatrick bzero(bdm->bdm_kva, size); 834e5ec1e72Spatrick 835e5ec1e72Spatrick return (bdm); 836e5ec1e72Spatrick 837e5ec1e72Spatrick unmap: 838e5ec1e72Spatrick bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, size); 839e5ec1e72Spatrick free: 840e5ec1e72Spatrick bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1); 841e5ec1e72Spatrick destroy: 842e5ec1e72Spatrick bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map); 843e5ec1e72Spatrick bdmfree: 84465046b40Spatrick free(bdm, M_DEVBUF, sizeof(*bdm)); 845e5ec1e72Spatrick 846e5ec1e72Spatrick return (NULL); 847e5ec1e72Spatrick } 848e5ec1e72Spatrick 849e5ec1e72Spatrick void 850e5ec1e72Spatrick bwfm_pci_dmamem_free(struct bwfm_pci_softc *sc, struct bwfm_pci_dmamem *bdm) 851e5ec1e72Spatrick { 852e5ec1e72Spatrick bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, bdm->bdm_size); 853e5ec1e72Spatrick bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1); 854e5ec1e72Spatrick bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map); 85565046b40Spatrick free(bdm, M_DEVBUF, sizeof(*bdm)); 856e5ec1e72Spatrick } 857e5ec1e72Spatrick 858e5ec1e72Spatrick /* 859e5ec1e72Spatrick * We need a simple mapping from a packet ID to mbufs, because when 860e5ec1e72Spatrick * a transfer completed, we only know the ID so we have to look up 861e5ec1e72Spatrick * the memory for the ID. This simply looks for an empty slot. 862e5ec1e72Spatrick */ 863e5ec1e72Spatrick int 86402ee7d07Spatrick bwfm_pci_pktid_avail(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts) 86502ee7d07Spatrick { 86602ee7d07Spatrick int i, idx; 86702ee7d07Spatrick 86802ee7d07Spatrick idx = pkts->last + 1; 86902ee7d07Spatrick for (i = 0; i < pkts->npkt; i++) { 87002ee7d07Spatrick if (idx == pkts->npkt) 87102ee7d07Spatrick idx = 0; 87202ee7d07Spatrick if (pkts->pkts[idx].bb_m == NULL) 87302ee7d07Spatrick return 0; 87402ee7d07Spatrick idx++; 87502ee7d07Spatrick } 87602ee7d07Spatrick return ENOBUFS; 87702ee7d07Spatrick } 87802ee7d07Spatrick 87902ee7d07Spatrick int 880e5ec1e72Spatrick bwfm_pci_pktid_new(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts, 881e5ec1e72Spatrick struct mbuf *m, uint32_t *pktid, paddr_t *paddr) 882e5ec1e72Spatrick { 883e5ec1e72Spatrick int i, idx; 884e5ec1e72Spatrick 885e5ec1e72Spatrick idx = pkts->last + 1; 886e5ec1e72Spatrick for (i = 0; i < pkts->npkt; i++) { 887e5ec1e72Spatrick if (idx == pkts->npkt) 888e5ec1e72Spatrick idx = 0; 889e5ec1e72Spatrick if (pkts->pkts[idx].bb_m == NULL) { 890e5ec1e72Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat, 891e5ec1e72Spatrick pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) { 892518be5f3Spatrick if (m_defrag(m, M_DONTWAIT)) 893518be5f3Spatrick return EFBIG; 894518be5f3Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat, 895518be5f3Spatrick pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) 896518be5f3Spatrick return EFBIG; 897e5ec1e72Spatrick } 898dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, pkts->pkts[idx].bb_map, 899dcb67343Spatrick 0, pkts->pkts[idx].bb_map->dm_mapsize, 900dcb67343Spatrick BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 901e5ec1e72Spatrick pkts->last = idx; 902e5ec1e72Spatrick pkts->pkts[idx].bb_m = m; 903e5ec1e72Spatrick *pktid = idx; 904e5ec1e72Spatrick *paddr = pkts->pkts[idx].bb_map->dm_segs[0].ds_addr; 905e5ec1e72Spatrick return 0; 906e5ec1e72Spatrick } 907e5ec1e72Spatrick idx++; 908e5ec1e72Spatrick } 909518be5f3Spatrick return ENOBUFS; 910e5ec1e72Spatrick } 911e5ec1e72Spatrick 912e5ec1e72Spatrick struct mbuf * 913e5ec1e72Spatrick bwfm_pci_pktid_free(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts, 914e5ec1e72Spatrick uint32_t pktid) 915e5ec1e72Spatrick { 916e5ec1e72Spatrick struct mbuf *m; 917e5ec1e72Spatrick 918e5ec1e72Spatrick if (pktid >= pkts->npkt || pkts->pkts[pktid].bb_m == NULL) 919e5ec1e72Spatrick return NULL; 920dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, pkts->pkts[pktid].bb_map, 0, 921dcb67343Spatrick pkts->pkts[pktid].bb_map->dm_mapsize, 922dcb67343Spatrick BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 923e5ec1e72Spatrick bus_dmamap_unload(sc->sc_dmat, pkts->pkts[pktid].bb_map); 924e5ec1e72Spatrick m = pkts->pkts[pktid].bb_m; 925e5ec1e72Spatrick pkts->pkts[pktid].bb_m = NULL; 926e5ec1e72Spatrick return m; 927e5ec1e72Spatrick } 928e5ec1e72Spatrick 929e5ec1e72Spatrick void 930e5ec1e72Spatrick bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *sc) 931e5ec1e72Spatrick { 93218722113Spatrick bwfm_pci_fill_rx_buf_ring(sc); 933e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_ioctl_ring, 934e5ec1e72Spatrick MSGBUF_TYPE_IOCTLRESP_BUF_POST); 935e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_event_ring, 936e5ec1e72Spatrick MSGBUF_TYPE_EVENT_BUF_POST); 937e5ec1e72Spatrick } 938e5ec1e72Spatrick 939e5ec1e72Spatrick void 940e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *sc, struct if_rxring *rxring, 941e5ec1e72Spatrick uint32_t msgtype) 942e5ec1e72Spatrick { 943e5ec1e72Spatrick struct msgbuf_rx_ioctl_resp_or_event *req; 944e5ec1e72Spatrick struct mbuf *m; 945e5ec1e72Spatrick uint32_t pktid; 946e5ec1e72Spatrick paddr_t paddr; 947e5ec1e72Spatrick int s, slots; 948e5ec1e72Spatrick 949e5ec1e72Spatrick s = splnet(); 950e5ec1e72Spatrick for (slots = if_rxr_get(rxring, 8); slots > 0; slots--) { 95102ee7d07Spatrick if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts)) 95202ee7d07Spatrick break; 953e5ec1e72Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit); 954e5ec1e72Spatrick if (req == NULL) 955e5ec1e72Spatrick break; 956471f2571Sjan m = MCLGETL(NULL, M_DONTWAIT, MSGBUF_MAX_PKT_SIZE); 957e5ec1e72Spatrick if (m == NULL) { 958e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1); 959e5ec1e72Spatrick break; 960e5ec1e72Spatrick } 961e5ec1e72Spatrick m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE; 962e5ec1e72Spatrick if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) { 963e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1); 964e5ec1e72Spatrick m_freem(m); 965e5ec1e72Spatrick break; 966e5ec1e72Spatrick } 967e5ec1e72Spatrick memset(req, 0, sizeof(*req)); 968e5ec1e72Spatrick req->msg.msgtype = msgtype; 969e5ec1e72Spatrick req->msg.request_id = htole32(pktid); 970e5ec1e72Spatrick req->host_buf_len = htole16(MSGBUF_MAX_PKT_SIZE); 971e4dae658Spatrick req->host_buf_addr.high_addr = htole32((uint64_t)paddr >> 32); 972e5ec1e72Spatrick req->host_buf_addr.low_addr = htole32(paddr & 0xffffffff); 973e5ec1e72Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit); 974e5ec1e72Spatrick } 975e5ec1e72Spatrick if_rxr_put(rxring, slots); 976e5ec1e72Spatrick splx(s); 977e5ec1e72Spatrick } 978e5ec1e72Spatrick 979e5ec1e72Spatrick void 980e5ec1e72Spatrick bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *sc) 981e5ec1e72Spatrick { 982e5ec1e72Spatrick struct msgbuf_rx_bufpost *req; 983e5ec1e72Spatrick struct mbuf *m; 984e5ec1e72Spatrick uint32_t pktid; 985e5ec1e72Spatrick paddr_t paddr; 986e5ec1e72Spatrick int s, slots; 987e5ec1e72Spatrick 988e5ec1e72Spatrick s = splnet(); 989e5ec1e72Spatrick for (slots = if_rxr_get(&sc->sc_rxbuf_ring, sc->sc_max_rxbufpost); 990e5ec1e72Spatrick slots > 0; slots--) { 99102ee7d07Spatrick if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts)) 99202ee7d07Spatrick break; 993e5ec1e72Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_rxpost_submit); 994e5ec1e72Spatrick if (req == NULL) 995e5ec1e72Spatrick break; 996471f2571Sjan m = MCLGETL(NULL, M_DONTWAIT, MSGBUF_MAX_PKT_SIZE); 997e5ec1e72Spatrick if (m == NULL) { 998e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1); 999e5ec1e72Spatrick break; 1000e5ec1e72Spatrick } 1001e5ec1e72Spatrick m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE; 1002e5ec1e72Spatrick if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) { 1003e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1); 1004e5ec1e72Spatrick m_freem(m); 1005e5ec1e72Spatrick break; 1006e5ec1e72Spatrick } 1007e5ec1e72Spatrick memset(req, 0, sizeof(*req)); 1008e5ec1e72Spatrick req->msg.msgtype = MSGBUF_TYPE_RXBUF_POST; 1009e5ec1e72Spatrick req->msg.request_id = htole32(pktid); 1010e5ec1e72Spatrick req->data_buf_len = htole16(MSGBUF_MAX_PKT_SIZE); 1011e4dae658Spatrick req->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32); 1012e5ec1e72Spatrick req->data_buf_addr.low_addr = htole32(paddr & 0xffffffff); 1013e5ec1e72Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_rxpost_submit); 1014e5ec1e72Spatrick } 1015e5ec1e72Spatrick if_rxr_put(&sc->sc_rxbuf_ring, slots); 1016e5ec1e72Spatrick splx(s); 1017e5ec1e72Spatrick } 1018e5ec1e72Spatrick 1019e5ec1e72Spatrick int 1020e5ec1e72Spatrick bwfm_pci_setup_ring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring, 1021e5ec1e72Spatrick int nitem, size_t itemsz, uint32_t w_idx, uint32_t r_idx, 1022e5ec1e72Spatrick int idx, uint32_t idx_off, uint32_t *ring_mem) 1023e5ec1e72Spatrick { 1024e5ec1e72Spatrick ring->w_idx_addr = w_idx + idx * idx_off; 1025e5ec1e72Spatrick ring->r_idx_addr = r_idx + idx * idx_off; 1026e5ec1e72Spatrick ring->nitem = nitem; 1027e5ec1e72Spatrick ring->itemsz = itemsz; 1028e5ec1e72Spatrick bwfm_pci_ring_write_rptr(sc, ring); 1029e5ec1e72Spatrick bwfm_pci_ring_write_wptr(sc, ring); 1030e5ec1e72Spatrick 1031e5ec1e72Spatrick ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8); 1032e5ec1e72Spatrick if (ring->ring == NULL) 1033e5ec1e72Spatrick return ENOMEM; 1034e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1035e5ec1e72Spatrick *ring_mem + BWFM_RING_MEM_BASE_ADDR_LOW, 1036e5ec1e72Spatrick BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff); 1037e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1038e5ec1e72Spatrick *ring_mem + BWFM_RING_MEM_BASE_ADDR_HIGH, 1039e5ec1e72Spatrick BWFM_PCI_DMA_DVA(ring->ring) >> 32); 1040e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1041e5ec1e72Spatrick *ring_mem + BWFM_RING_MAX_ITEM, nitem); 1042e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1043e5ec1e72Spatrick *ring_mem + BWFM_RING_LEN_ITEMS, itemsz); 1044e5ec1e72Spatrick *ring_mem = *ring_mem + BWFM_RING_MEM_SZ; 1045e5ec1e72Spatrick return 0; 1046e5ec1e72Spatrick } 1047e5ec1e72Spatrick 1048518be5f3Spatrick int 1049518be5f3Spatrick bwfm_pci_setup_flowring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring, 1050518be5f3Spatrick int nitem, size_t itemsz) 1051518be5f3Spatrick { 1052518be5f3Spatrick ring->w_ptr = 0; 1053518be5f3Spatrick ring->r_ptr = 0; 1054518be5f3Spatrick ring->nitem = nitem; 1055518be5f3Spatrick ring->itemsz = itemsz; 1056518be5f3Spatrick bwfm_pci_ring_write_rptr(sc, ring); 1057518be5f3Spatrick bwfm_pci_ring_write_wptr(sc, ring); 1058518be5f3Spatrick 1059518be5f3Spatrick ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8); 1060518be5f3Spatrick if (ring->ring == NULL) 1061518be5f3Spatrick return ENOMEM; 1062518be5f3Spatrick return 0; 1063518be5f3Spatrick } 1064518be5f3Spatrick 1065e5ec1e72Spatrick /* Ring helpers */ 1066e5ec1e72Spatrick void 1067e5ec1e72Spatrick bwfm_pci_ring_bell(struct bwfm_pci_softc *sc, 1068e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1069e5ec1e72Spatrick { 1070e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1071*156d2677Spatrick BWFM_PCI_PCIE2REG_H2D_MAILBOX_0, 1); 1072e5ec1e72Spatrick } 1073e5ec1e72Spatrick 1074e5ec1e72Spatrick void 1075e5ec1e72Spatrick bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *sc, 1076e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1077e5ec1e72Spatrick { 1078e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 1079e5ec1e72Spatrick ring->r_ptr = bus_space_read_2(sc->sc_tcm_iot, 1080e5ec1e72Spatrick sc->sc_tcm_ioh, ring->r_idx_addr); 1081e5ec1e72Spatrick } else { 1082dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, 1083dcb67343Spatrick BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr, 1084dcb67343Spatrick sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1085e5ec1e72Spatrick ring->r_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf) 1086e5ec1e72Spatrick + ring->r_idx_addr); 1087e5ec1e72Spatrick } 1088e5ec1e72Spatrick } 1089e5ec1e72Spatrick 1090e5ec1e72Spatrick void 1091e5ec1e72Spatrick bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *sc, 1092e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1093e5ec1e72Spatrick { 1094e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 1095e5ec1e72Spatrick ring->w_ptr = bus_space_read_2(sc->sc_tcm_iot, 1096e5ec1e72Spatrick sc->sc_tcm_ioh, ring->w_idx_addr); 1097e5ec1e72Spatrick } else { 1098dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, 1099dcb67343Spatrick BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr, 1100dcb67343Spatrick sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1101e5ec1e72Spatrick ring->w_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf) 1102e5ec1e72Spatrick + ring->w_idx_addr); 1103e5ec1e72Spatrick } 1104e5ec1e72Spatrick } 1105e5ec1e72Spatrick 1106e5ec1e72Spatrick void 1107e5ec1e72Spatrick bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *sc, 1108e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1109e5ec1e72Spatrick { 1110e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 1111e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1112e5ec1e72Spatrick ring->r_idx_addr, ring->r_ptr); 1113e5ec1e72Spatrick } else { 1114e5ec1e72Spatrick *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf) 1115e5ec1e72Spatrick + ring->r_idx_addr) = ring->r_ptr; 1116dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, 1117dcb67343Spatrick BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr, 1118dcb67343Spatrick sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1119e5ec1e72Spatrick } 1120e5ec1e72Spatrick } 1121e5ec1e72Spatrick 1122e5ec1e72Spatrick void 1123e5ec1e72Spatrick bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *sc, 1124e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1125e5ec1e72Spatrick { 1126e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 1127e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1128e5ec1e72Spatrick ring->w_idx_addr, ring->w_ptr); 1129e5ec1e72Spatrick } else { 1130e5ec1e72Spatrick *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf) 1131e5ec1e72Spatrick + ring->w_idx_addr) = ring->w_ptr; 1132dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, 1133dcb67343Spatrick BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr, 1134dcb67343Spatrick sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1135e5ec1e72Spatrick } 1136e5ec1e72Spatrick } 1137e5ec1e72Spatrick 1138e5ec1e72Spatrick /* 1139e5ec1e72Spatrick * Retrieve a free descriptor to put new stuff in, but don't commit 1140e5ec1e72Spatrick * to it yet so we can rollback later if any error occurs. 1141e5ec1e72Spatrick */ 1142e5ec1e72Spatrick void * 1143e5ec1e72Spatrick bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *sc, 1144e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1145e5ec1e72Spatrick { 1146e5ec1e72Spatrick int available; 1147e5ec1e72Spatrick char *ret; 1148e5ec1e72Spatrick 1149e5ec1e72Spatrick bwfm_pci_ring_update_rptr(sc, ring); 1150e5ec1e72Spatrick 1151e5ec1e72Spatrick if (ring->r_ptr > ring->w_ptr) 1152e5ec1e72Spatrick available = ring->r_ptr - ring->w_ptr; 1153e5ec1e72Spatrick else 1154e5ec1e72Spatrick available = ring->r_ptr + (ring->nitem - ring->w_ptr); 1155e5ec1e72Spatrick 115630f5ada0Spatrick if (available <= 1) 1157e5ec1e72Spatrick return NULL; 1158e5ec1e72Spatrick 1159e5ec1e72Spatrick ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz); 1160e5ec1e72Spatrick ring->w_ptr += 1; 1161e5ec1e72Spatrick if (ring->w_ptr == ring->nitem) 1162e5ec1e72Spatrick ring->w_ptr = 0; 1163e5ec1e72Spatrick return ret; 1164e5ec1e72Spatrick } 1165e5ec1e72Spatrick 1166e5ec1e72Spatrick void * 1167e5ec1e72Spatrick bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *sc, 1168e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int count, int *avail) 1169e5ec1e72Spatrick { 1170e5ec1e72Spatrick int available; 1171e5ec1e72Spatrick char *ret; 1172e5ec1e72Spatrick 1173e5ec1e72Spatrick bwfm_pci_ring_update_rptr(sc, ring); 1174e5ec1e72Spatrick 1175e5ec1e72Spatrick if (ring->r_ptr > ring->w_ptr) 1176e5ec1e72Spatrick available = ring->r_ptr - ring->w_ptr; 1177e5ec1e72Spatrick else 1178e5ec1e72Spatrick available = ring->r_ptr + (ring->nitem - ring->w_ptr); 1179e5ec1e72Spatrick 118030f5ada0Spatrick if (available <= 1) 1181e5ec1e72Spatrick return NULL; 1182e5ec1e72Spatrick 1183e5ec1e72Spatrick ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz); 1184e5ec1e72Spatrick *avail = min(count, available - 1); 1185e5ec1e72Spatrick if (*avail + ring->w_ptr > ring->nitem) 1186e5ec1e72Spatrick *avail = ring->nitem - ring->w_ptr; 1187e5ec1e72Spatrick ring->w_ptr += *avail; 1188e5ec1e72Spatrick if (ring->w_ptr == ring->nitem) 1189e5ec1e72Spatrick ring->w_ptr = 0; 1190e5ec1e72Spatrick return ret; 1191e5ec1e72Spatrick } 1192e5ec1e72Spatrick 1193e5ec1e72Spatrick /* 1194e5ec1e72Spatrick * Read number of descriptors available (submitted by the firmware) 1195e5ec1e72Spatrick * and retrieve pointer to first descriptor. 1196e5ec1e72Spatrick */ 1197e5ec1e72Spatrick void * 1198e5ec1e72Spatrick bwfm_pci_ring_read_avail(struct bwfm_pci_softc *sc, 1199e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int *avail) 1200e5ec1e72Spatrick { 1201e5ec1e72Spatrick bwfm_pci_ring_update_wptr(sc, ring); 1202e5ec1e72Spatrick 1203e5ec1e72Spatrick if (ring->w_ptr >= ring->r_ptr) 1204e5ec1e72Spatrick *avail = ring->w_ptr - ring->r_ptr; 1205e5ec1e72Spatrick else 1206e5ec1e72Spatrick *avail = ring->nitem - ring->r_ptr; 1207e5ec1e72Spatrick 1208e5ec1e72Spatrick if (*avail == 0) 1209e5ec1e72Spatrick return NULL; 1210e5ec1e72Spatrick 1211dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring), 1212dcb67343Spatrick ring->r_ptr * ring->itemsz, *avail * ring->itemsz, 1213dcb67343Spatrick BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1214e5ec1e72Spatrick return BWFM_PCI_DMA_KVA(ring->ring) + (ring->r_ptr * ring->itemsz); 1215e5ec1e72Spatrick } 1216e5ec1e72Spatrick 1217e5ec1e72Spatrick /* 1218e5ec1e72Spatrick * Let firmware know we read N descriptors. 1219e5ec1e72Spatrick */ 1220e5ec1e72Spatrick void 1221e5ec1e72Spatrick bwfm_pci_ring_read_commit(struct bwfm_pci_softc *sc, 1222e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int nitem) 1223e5ec1e72Spatrick { 1224e5ec1e72Spatrick ring->r_ptr += nitem; 1225e5ec1e72Spatrick if (ring->r_ptr == ring->nitem) 1226e5ec1e72Spatrick ring->r_ptr = 0; 1227e5ec1e72Spatrick bwfm_pci_ring_write_rptr(sc, ring); 1228e5ec1e72Spatrick } 1229e5ec1e72Spatrick 1230e5ec1e72Spatrick /* 1231e5ec1e72Spatrick * Let firmware know that we submitted some descriptors. 1232e5ec1e72Spatrick */ 1233e5ec1e72Spatrick void 1234e5ec1e72Spatrick bwfm_pci_ring_write_commit(struct bwfm_pci_softc *sc, 1235e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1236e5ec1e72Spatrick { 1237dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring), 1238dcb67343Spatrick 0, BWFM_PCI_DMA_LEN(ring->ring), BUS_DMASYNC_PREREAD | 1239dcb67343Spatrick BUS_DMASYNC_PREWRITE); 1240e5ec1e72Spatrick bwfm_pci_ring_write_wptr(sc, ring); 1241e5ec1e72Spatrick bwfm_pci_ring_bell(sc, ring); 1242e5ec1e72Spatrick } 1243e5ec1e72Spatrick 1244e5ec1e72Spatrick /* 1245e5ec1e72Spatrick * Rollback N descriptors in case we don't actually want 1246e5ec1e72Spatrick * to commit to it. 1247e5ec1e72Spatrick */ 1248e5ec1e72Spatrick void 1249e5ec1e72Spatrick bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *sc, 1250e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int nitem) 1251e5ec1e72Spatrick { 1252e5ec1e72Spatrick if (ring->w_ptr == 0) 1253e5ec1e72Spatrick ring->w_ptr = ring->nitem - nitem; 1254e5ec1e72Spatrick else 1255e5ec1e72Spatrick ring->w_ptr -= nitem; 1256e5ec1e72Spatrick } 1257e5ec1e72Spatrick 1258e5ec1e72Spatrick /* 1259e5ec1e72Spatrick * Foreach written descriptor on the ring, pass the descriptor to 1260e5ec1e72Spatrick * a message handler and let the firmware know we handled it. 1261e5ec1e72Spatrick */ 1262e5ec1e72Spatrick void 12636f241297Spatrick bwfm_pci_ring_rx(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring, 12646f241297Spatrick struct mbuf_list *ml) 1265e5ec1e72Spatrick { 1266e5ec1e72Spatrick void *buf; 1267e5ec1e72Spatrick int avail, processed; 1268e5ec1e72Spatrick 1269e5ec1e72Spatrick again: 1270e5ec1e72Spatrick buf = bwfm_pci_ring_read_avail(sc, ring, &avail); 1271e5ec1e72Spatrick if (buf == NULL) 1272e5ec1e72Spatrick return; 1273e5ec1e72Spatrick 1274e5ec1e72Spatrick processed = 0; 1275e5ec1e72Spatrick while (avail) { 12766f241297Spatrick bwfm_pci_msg_rx(sc, buf + sc->sc_rx_dataoffset, ml); 1277e5ec1e72Spatrick buf += ring->itemsz; 1278e5ec1e72Spatrick processed++; 1279e5ec1e72Spatrick if (processed == 48) { 1280e5ec1e72Spatrick bwfm_pci_ring_read_commit(sc, ring, processed); 1281e5ec1e72Spatrick processed = 0; 1282e5ec1e72Spatrick } 1283e5ec1e72Spatrick avail--; 1284e5ec1e72Spatrick } 1285e5ec1e72Spatrick if (processed) 1286e5ec1e72Spatrick bwfm_pci_ring_read_commit(sc, ring, processed); 1287e5ec1e72Spatrick if (ring->r_ptr == 0) 1288e5ec1e72Spatrick goto again; 1289e5ec1e72Spatrick } 1290e5ec1e72Spatrick 1291e5ec1e72Spatrick void 12926f241297Spatrick bwfm_pci_msg_rx(struct bwfm_pci_softc *sc, void *buf, struct mbuf_list *ml) 1293e5ec1e72Spatrick { 1294518be5f3Spatrick struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if; 1295e5ec1e72Spatrick struct msgbuf_ioctl_resp_hdr *resp; 1296518be5f3Spatrick struct msgbuf_tx_status *tx; 129718722113Spatrick struct msgbuf_rx_complete *rx; 1298e5ec1e72Spatrick struct msgbuf_rx_event *event; 1299e5ec1e72Spatrick struct msgbuf_common_hdr *msg; 1300518be5f3Spatrick struct msgbuf_flowring_create_resp *fcr; 1301a2c6ff8bSpatrick struct msgbuf_flowring_delete_resp *fdr; 1302518be5f3Spatrick struct bwfm_pci_msgring *ring; 1303e5ec1e72Spatrick struct mbuf *m; 1304518be5f3Spatrick int flowid; 1305e5ec1e72Spatrick 1306e5ec1e72Spatrick msg = (struct msgbuf_common_hdr *)buf; 1307e5ec1e72Spatrick switch (msg->msgtype) 1308e5ec1e72Spatrick { 1309518be5f3Spatrick case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT: 1310518be5f3Spatrick fcr = (struct msgbuf_flowring_create_resp *)buf; 1311518be5f3Spatrick flowid = letoh16(fcr->compl_hdr.flow_ring_id); 1312518be5f3Spatrick if (flowid < 2) 1313518be5f3Spatrick break; 1314518be5f3Spatrick flowid -= 2; 1315518be5f3Spatrick if (flowid >= sc->sc_max_flowrings) 1316518be5f3Spatrick break; 1317518be5f3Spatrick ring = &sc->sc_flowrings[flowid]; 1318518be5f3Spatrick if (ring->status != RING_OPENING) 1319518be5f3Spatrick break; 1320518be5f3Spatrick if (fcr->compl_hdr.status) { 1321518be5f3Spatrick printf("%s: failed to open flowring %d\n", 1322518be5f3Spatrick DEVNAME(sc), flowid); 1323518be5f3Spatrick ring->status = RING_CLOSED; 132402ee7d07Spatrick if (ring->m) { 132502ee7d07Spatrick m_freem(ring->m); 132602ee7d07Spatrick ring->m = NULL; 132702ee7d07Spatrick } 1328518be5f3Spatrick ifq_restart(&ifp->if_snd); 1329518be5f3Spatrick break; 1330518be5f3Spatrick } 1331518be5f3Spatrick ring->status = RING_OPEN; 133202ee7d07Spatrick if (ring->m != NULL) { 133302ee7d07Spatrick m = ring->m; 133402ee7d07Spatrick ring->m = NULL; 133502ee7d07Spatrick if (bwfm_pci_txdata(&sc->sc_sc, m)) 133602ee7d07Spatrick m_freem(ring->m); 133702ee7d07Spatrick } 1338518be5f3Spatrick ifq_restart(&ifp->if_snd); 1339518be5f3Spatrick break; 1340a2c6ff8bSpatrick case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT: 1341a2c6ff8bSpatrick fdr = (struct msgbuf_flowring_delete_resp *)buf; 1342a2c6ff8bSpatrick flowid = letoh16(fdr->compl_hdr.flow_ring_id); 1343a2c6ff8bSpatrick if (flowid < 2) 1344a2c6ff8bSpatrick break; 1345a2c6ff8bSpatrick flowid -= 2; 1346a2c6ff8bSpatrick if (flowid >= sc->sc_max_flowrings) 1347a2c6ff8bSpatrick break; 1348a2c6ff8bSpatrick ring = &sc->sc_flowrings[flowid]; 1349a2c6ff8bSpatrick if (ring->status != RING_CLOSING) 1350a2c6ff8bSpatrick break; 1351a2c6ff8bSpatrick if (fdr->compl_hdr.status) { 1352a2c6ff8bSpatrick printf("%s: failed to delete flowring %d\n", 1353a2c6ff8bSpatrick DEVNAME(sc), flowid); 1354a2c6ff8bSpatrick break; 1355a2c6ff8bSpatrick } 1356a2c6ff8bSpatrick bwfm_pci_dmamem_free(sc, ring->ring); 1357a2c6ff8bSpatrick ring->status = RING_CLOSED; 1358a2c6ff8bSpatrick break; 1359e5ec1e72Spatrick case MSGBUF_TYPE_IOCTLPTR_REQ_ACK: 13602eeba925Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_ioctl_pkts, 13612eeba925Spatrick letoh32(msg->request_id)); 13622eeba925Spatrick if (m == NULL) 13632eeba925Spatrick break; 13642eeba925Spatrick m_freem(m); 1365e5ec1e72Spatrick break; 1366e5ec1e72Spatrick case MSGBUF_TYPE_IOCTL_CMPLT: 1367e5ec1e72Spatrick resp = (struct msgbuf_ioctl_resp_hdr *)buf; 13682eeba925Spatrick bwfm_pci_msgbuf_rxioctl(sc, resp); 1369e5ec1e72Spatrick if_rxr_put(&sc->sc_ioctl_ring, 1); 1370e5ec1e72Spatrick bwfm_pci_fill_rx_rings(sc); 1371e5ec1e72Spatrick break; 1372e5ec1e72Spatrick case MSGBUF_TYPE_WL_EVENT: 1373e5ec1e72Spatrick event = (struct msgbuf_rx_event *)buf; 1374e5ec1e72Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts, 1375e5ec1e72Spatrick letoh32(event->msg.request_id)); 1376e5ec1e72Spatrick if (m == NULL) 1377e5ec1e72Spatrick break; 1378e5ec1e72Spatrick m_adj(m, sc->sc_rx_dataoffset); 1379f37fc236Spatrick m->m_len = m->m_pkthdr.len = letoh16(event->event_data_len); 13806f241297Spatrick bwfm_rx(&sc->sc_sc, m, ml); 1381e5ec1e72Spatrick if_rxr_put(&sc->sc_event_ring, 1); 1382e5ec1e72Spatrick bwfm_pci_fill_rx_rings(sc); 1383e5ec1e72Spatrick break; 1384518be5f3Spatrick case MSGBUF_TYPE_TX_STATUS: 1385518be5f3Spatrick tx = (struct msgbuf_tx_status *)buf; 1386518be5f3Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_tx_pkts, 1387f9ee104fSpatrick letoh32(tx->msg.request_id) - 1); 1388518be5f3Spatrick if (m == NULL) 1389518be5f3Spatrick break; 1390518be5f3Spatrick m_freem(m); 1391c6f1636dSpatrick if (sc->sc_tx_pkts_full) { 1392c6f1636dSpatrick sc->sc_tx_pkts_full = 0; 1393c6f1636dSpatrick ifq_restart(&ifp->if_snd); 1394c6f1636dSpatrick } 1395518be5f3Spatrick break; 139618722113Spatrick case MSGBUF_TYPE_RX_CMPLT: 139718722113Spatrick rx = (struct msgbuf_rx_complete *)buf; 139818722113Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts, 139918722113Spatrick letoh32(rx->msg.request_id)); 140018722113Spatrick if (m == NULL) 140118722113Spatrick break; 140218722113Spatrick if (letoh16(rx->data_offset)) 140318722113Spatrick m_adj(m, letoh16(rx->data_offset)); 140418722113Spatrick else if (sc->sc_rx_dataoffset) 140518722113Spatrick m_adj(m, sc->sc_rx_dataoffset); 1406f37fc236Spatrick m->m_len = m->m_pkthdr.len = letoh16(rx->data_len); 14076f241297Spatrick bwfm_rx(&sc->sc_sc, m, ml); 140818722113Spatrick if_rxr_put(&sc->sc_rxbuf_ring, 1); 140918722113Spatrick bwfm_pci_fill_rx_rings(sc); 141018722113Spatrick break; 1411e5ec1e72Spatrick default: 1412e5ec1e72Spatrick printf("%s: msgtype 0x%08x\n", __func__, msg->msgtype); 1413e5ec1e72Spatrick break; 1414e5ec1e72Spatrick } 1415e5ec1e72Spatrick } 1416e5ec1e72Spatrick 1417e5ec1e72Spatrick /* Bus core helpers */ 1418e5ec1e72Spatrick void 1419e5ec1e72Spatrick bwfm_pci_select_core(struct bwfm_pci_softc *sc, int id) 1420e5ec1e72Spatrick { 1421e5ec1e72Spatrick struct bwfm_softc *bwfm = (void *)sc; 1422e5ec1e72Spatrick struct bwfm_core *core; 1423e5ec1e72Spatrick 1424e5ec1e72Spatrick core = bwfm_chip_get_core(bwfm, id); 1425e5ec1e72Spatrick if (core == NULL) { 1426e5ec1e72Spatrick printf("%s: could not find core to select", DEVNAME(sc)); 1427e5ec1e72Spatrick return; 1428e5ec1e72Spatrick } 1429e5ec1e72Spatrick 1430e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, 1431e5ec1e72Spatrick BWFM_PCI_BAR0_WINDOW, core->co_base); 1432e5ec1e72Spatrick if (pci_conf_read(sc->sc_pc, sc->sc_tag, 1433e5ec1e72Spatrick BWFM_PCI_BAR0_WINDOW) != core->co_base) 1434e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, 1435e5ec1e72Spatrick BWFM_PCI_BAR0_WINDOW, core->co_base); 1436e5ec1e72Spatrick } 1437e5ec1e72Spatrick 1438e5ec1e72Spatrick uint32_t 1439e5ec1e72Spatrick bwfm_pci_buscore_read(struct bwfm_softc *bwfm, uint32_t reg) 1440e5ec1e72Spatrick { 1441e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1442e5ec1e72Spatrick uint32_t page, offset; 1443e5ec1e72Spatrick 1444e5ec1e72Spatrick page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1); 1445e5ec1e72Spatrick offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1); 1446e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page); 1447e5ec1e72Spatrick return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset); 1448e5ec1e72Spatrick } 1449e5ec1e72Spatrick 1450e5ec1e72Spatrick void 1451e5ec1e72Spatrick bwfm_pci_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val) 1452e5ec1e72Spatrick { 1453e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1454e5ec1e72Spatrick uint32_t page, offset; 1455e5ec1e72Spatrick 1456e5ec1e72Spatrick page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1); 1457e5ec1e72Spatrick offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1); 1458e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page); 1459e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset, val); 1460e5ec1e72Spatrick } 1461e5ec1e72Spatrick 1462e5ec1e72Spatrick int 1463e5ec1e72Spatrick bwfm_pci_buscore_prepare(struct bwfm_softc *bwfm) 1464e5ec1e72Spatrick { 1465e5ec1e72Spatrick return 0; 1466e5ec1e72Spatrick } 1467e5ec1e72Spatrick 1468e5ec1e72Spatrick int 1469e5ec1e72Spatrick bwfm_pci_buscore_reset(struct bwfm_softc *bwfm) 1470e5ec1e72Spatrick { 1471e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1472e5ec1e72Spatrick struct bwfm_core *core; 1473e5ec1e72Spatrick uint32_t reg; 1474e5ec1e72Spatrick int i; 1475e5ec1e72Spatrick 1476e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2); 1477e5ec1e72Spatrick reg = pci_conf_read(sc->sc_pc, sc->sc_tag, 1478e5ec1e72Spatrick BWFM_PCI_CFGREG_LINK_STATUS_CTRL); 1479e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_CFGREG_LINK_STATUS_CTRL, 1480e5ec1e72Spatrick reg & ~BWFM_PCI_CFGREG_LINK_STATUS_CTRL_ASPM_ENAB); 1481e5ec1e72Spatrick 1482e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); 1483e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1484e5ec1e72Spatrick BWFM_CHIP_REG_WATCHDOG, 4); 1485e5ec1e72Spatrick delay(100 * 1000); 1486e5ec1e72Spatrick 1487e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2); 1488e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, 1489e5ec1e72Spatrick BWFM_PCI_CFGREG_LINK_STATUS_CTRL, reg); 1490e5ec1e72Spatrick 1491e5ec1e72Spatrick core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2); 1492e5ec1e72Spatrick if (core->co_rev <= 13) { 1493e5ec1e72Spatrick uint16_t cfg_offset[] = { 1494e5ec1e72Spatrick BWFM_PCI_CFGREG_STATUS_CMD, 1495e5ec1e72Spatrick BWFM_PCI_CFGREG_PM_CSR, 1496e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_CAP, 1497e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_ADDR_L, 1498e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_ADDR_H, 1499e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_DATA, 1500e5ec1e72Spatrick BWFM_PCI_CFGREG_LINK_STATUS_CTRL2, 1501e5ec1e72Spatrick BWFM_PCI_CFGREG_RBAR_CTRL, 1502e5ec1e72Spatrick BWFM_PCI_CFGREG_PML1_SUB_CTRL1, 1503e5ec1e72Spatrick BWFM_PCI_CFGREG_REG_BAR2_CONFIG, 1504e5ec1e72Spatrick BWFM_PCI_CFGREG_REG_BAR3_CONFIG, 1505e5ec1e72Spatrick }; 1506e5ec1e72Spatrick 1507e5ec1e72Spatrick for (i = 0; i < nitems(cfg_offset); i++) { 1508e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1509e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGADDR, cfg_offset[i]); 1510e5ec1e72Spatrick reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1511e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA); 1512e5ec1e72Spatrick DPRINTFN(3, ("%s: config offset 0x%04x, value 0x%04x\n", 1513e5ec1e72Spatrick DEVNAME(sc), cfg_offset[i], reg)); 1514e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1515e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA, reg); 1516e5ec1e72Spatrick } 1517e5ec1e72Spatrick } 1518e5ec1e72Spatrick 1519e5ec1e72Spatrick reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1520e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXINT); 1521e5ec1e72Spatrick if (reg != 0xffffffff) 1522e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1523e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXINT, reg); 1524e5ec1e72Spatrick 1525e5ec1e72Spatrick return 0; 1526e5ec1e72Spatrick } 1527e5ec1e72Spatrick 1528e5ec1e72Spatrick void 1529e5ec1e72Spatrick bwfm_pci_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec) 1530e5ec1e72Spatrick { 1531e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1532e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 0, rstvec); 1533e5ec1e72Spatrick } 1534e5ec1e72Spatrick 1535f67437f3Spatrick static int bwfm_pci_prio2fifo[8] = { 15369e2c067eSpatrick 0, /* best effort */ 15379e2c067eSpatrick 1, /* IPTOS_PREC_IMMEDIATE */ 15389e2c067eSpatrick 1, /* IPTOS_PREC_PRIORITY */ 15399e2c067eSpatrick 0, /* IPTOS_PREC_FLASH */ 1540f67437f3Spatrick 2, /* IPTOS_PREC_FLASHOVERRIDE */ 1541f67437f3Spatrick 2, /* IPTOS_PREC_CRITIC_ECP */ 1542f67437f3Spatrick 3, /* IPTOS_PREC_INTERNETCONTROL */ 1543f67437f3Spatrick 3, /* IPTOS_PREC_NETCONTROL */ 1544f67437f3Spatrick }; 1545f67437f3Spatrick 1546f67437f3Spatrick int 1547f67437f3Spatrick bwfm_pci_flowring_lookup(struct bwfm_pci_softc *sc, struct mbuf *m) 1548518be5f3Spatrick { 1549f67437f3Spatrick struct ieee80211com *ic = &sc->sc_sc.sc_ic; 1550e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY 1551f67437f3Spatrick uint8_t *da = mtod(m, uint8_t *); 1552e6abcda3Smlarkin #endif 1553f67437f3Spatrick int flowid, prio, fifo; 1554f67437f3Spatrick int i, found; 1555f67437f3Spatrick 1556f67437f3Spatrick prio = ieee80211_classify(ic, m); 1557f67437f3Spatrick fifo = bwfm_pci_prio2fifo[prio]; 1558f67437f3Spatrick 1559f67437f3Spatrick switch (ic->ic_opmode) 1560f67437f3Spatrick { 1561f67437f3Spatrick case IEEE80211_M_STA: 1562f67437f3Spatrick flowid = fifo; 1563f67437f3Spatrick break; 1564f67437f3Spatrick #ifndef IEEE80211_STA_ONLY 1565f67437f3Spatrick case IEEE80211_M_HOSTAP: 15662b7bea7eSpatrick if (ETHER_IS_MULTICAST(da)) 15672b7bea7eSpatrick da = etherbroadcastaddr; 1568f67437f3Spatrick flowid = da[5] * 2 + fifo; 1569f67437f3Spatrick break; 1570f67437f3Spatrick #endif 1571f67437f3Spatrick default: 1572f67437f3Spatrick printf("%s: state not supported\n", DEVNAME(sc)); 1573f67437f3Spatrick return ENOBUFS; 1574f67437f3Spatrick } 1575f67437f3Spatrick 1576f67437f3Spatrick found = 0; 1577f67437f3Spatrick flowid = flowid % sc->sc_max_flowrings; 1578f67437f3Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 1579f67437f3Spatrick if (ic->ic_opmode == IEEE80211_M_STA && 1580f67437f3Spatrick sc->sc_flowrings[flowid].status >= RING_OPEN && 1581f67437f3Spatrick sc->sc_flowrings[flowid].fifo == fifo) { 1582f67437f3Spatrick found = 1; 1583f67437f3Spatrick break; 1584f67437f3Spatrick } 1585f67437f3Spatrick #ifndef IEEE80211_STA_ONLY 1586f67437f3Spatrick if (ic->ic_opmode == IEEE80211_M_HOSTAP && 1587f67437f3Spatrick sc->sc_flowrings[flowid].status >= RING_OPEN && 1588f67437f3Spatrick sc->sc_flowrings[flowid].fifo == fifo && 1589a2c6ff8bSpatrick !memcmp(sc->sc_flowrings[flowid].mac, da, ETHER_ADDR_LEN)) { 1590f67437f3Spatrick found = 1; 1591f67437f3Spatrick break; 1592f67437f3Spatrick } 1593f67437f3Spatrick #endif 1594f67437f3Spatrick flowid = (flowid + 1) % sc->sc_max_flowrings; 1595f67437f3Spatrick } 1596f67437f3Spatrick 1597f67437f3Spatrick if (found) 1598f67437f3Spatrick return flowid; 1599f67437f3Spatrick 1600f67437f3Spatrick return -1; 1601f67437f3Spatrick } 1602f67437f3Spatrick 1603f67437f3Spatrick void 1604f67437f3Spatrick bwfm_pci_flowring_create(struct bwfm_pci_softc *sc, struct mbuf *m) 1605f67437f3Spatrick { 1606f67437f3Spatrick struct ieee80211com *ic = &sc->sc_sc.sc_ic; 1607518be5f3Spatrick struct bwfm_cmd_flowring_create cmd; 1608e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY 1609f67437f3Spatrick uint8_t *da = mtod(m, uint8_t *); 1610e6abcda3Smlarkin #endif 161102ee7d07Spatrick struct bwfm_pci_msgring *ring; 1612f67437f3Spatrick int flowid, prio, fifo; 1613f67437f3Spatrick int i, found; 1614f67437f3Spatrick 1615f67437f3Spatrick prio = ieee80211_classify(ic, m); 1616f67437f3Spatrick fifo = bwfm_pci_prio2fifo[prio]; 1617f67437f3Spatrick 1618f67437f3Spatrick switch (ic->ic_opmode) 1619f67437f3Spatrick { 1620f67437f3Spatrick case IEEE80211_M_STA: 1621f67437f3Spatrick flowid = fifo; 1622f67437f3Spatrick break; 1623f67437f3Spatrick #ifndef IEEE80211_STA_ONLY 1624f67437f3Spatrick case IEEE80211_M_HOSTAP: 16252b7bea7eSpatrick if (ETHER_IS_MULTICAST(da)) 16262b7bea7eSpatrick da = etherbroadcastaddr; 1627f67437f3Spatrick flowid = da[5] * 2 + fifo; 1628f67437f3Spatrick break; 1629f67437f3Spatrick #endif 1630f67437f3Spatrick default: 1631f67437f3Spatrick printf("%s: state not supported\n", DEVNAME(sc)); 1632f67437f3Spatrick return; 1633f67437f3Spatrick } 1634f67437f3Spatrick 1635f67437f3Spatrick found = 0; 1636f67437f3Spatrick flowid = flowid % sc->sc_max_flowrings; 1637f67437f3Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 163802ee7d07Spatrick ring = &sc->sc_flowrings[flowid]; 163902ee7d07Spatrick if (ring->status == RING_CLOSED) { 164002ee7d07Spatrick ring->status = RING_OPENING; 1641f67437f3Spatrick found = 1; 1642f67437f3Spatrick break; 1643f67437f3Spatrick } 1644f67437f3Spatrick flowid = (flowid + 1) % sc->sc_max_flowrings; 1645f67437f3Spatrick } 1646f67437f3Spatrick 164702ee7d07Spatrick /* 164802ee7d07Spatrick * We cannot recover from that so far. Only a stop/init 164902ee7d07Spatrick * cycle can revive this if it ever happens at all. 165002ee7d07Spatrick */ 1651f67437f3Spatrick if (!found) { 1652f67437f3Spatrick printf("%s: no flowring available\n", DEVNAME(sc)); 1653f67437f3Spatrick return; 1654f67437f3Spatrick } 1655f67437f3Spatrick 165602ee7d07Spatrick cmd.m = m; 1657f67437f3Spatrick cmd.prio = prio; 1658518be5f3Spatrick cmd.flowid = flowid; 1659518be5f3Spatrick bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_create_cb, &cmd, sizeof(cmd)); 1660518be5f3Spatrick } 1661518be5f3Spatrick 1662518be5f3Spatrick void 1663518be5f3Spatrick bwfm_pci_flowring_create_cb(struct bwfm_softc *bwfm, void *arg) 1664518be5f3Spatrick { 1665518be5f3Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1666e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY 16672b7bea7eSpatrick struct ieee80211com *ic = &sc->sc_sc.sc_ic; 1668e6abcda3Smlarkin #endif 1669518be5f3Spatrick struct bwfm_cmd_flowring_create *cmd = arg; 1670518be5f3Spatrick struct msgbuf_tx_flowring_create_req *req; 1671518be5f3Spatrick struct bwfm_pci_msgring *ring; 167202ee7d07Spatrick uint8_t *da, *sa; 1673e272db29Spatrick int s; 1674518be5f3Spatrick 167502ee7d07Spatrick da = mtod(cmd->m, char *) + 0 * ETHER_ADDR_LEN; 167602ee7d07Spatrick sa = mtod(cmd->m, char *) + 1 * ETHER_ADDR_LEN; 1677518be5f3Spatrick 167802ee7d07Spatrick ring = &sc->sc_flowrings[cmd->flowid]; 167902ee7d07Spatrick if (ring->status != RING_OPENING) { 168002ee7d07Spatrick printf("%s: flowring not opening\n", DEVNAME(sc)); 1681518be5f3Spatrick return; 1682f67437f3Spatrick } 1683f67437f3Spatrick 1684f67437f3Spatrick if (bwfm_pci_setup_flowring(sc, ring, 512, 48)) { 1685f67437f3Spatrick printf("%s: cannot setup flowring\n", DEVNAME(sc)); 1686f67437f3Spatrick return; 1687f67437f3Spatrick } 1688518be5f3Spatrick 1689e272db29Spatrick s = splnet(); 1690518be5f3Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit); 1691f67437f3Spatrick if (req == NULL) { 1692f67437f3Spatrick printf("%s: cannot reserve for flowring\n", DEVNAME(sc)); 1693e272db29Spatrick splx(s); 1694518be5f3Spatrick return; 1695f67437f3Spatrick } 1696518be5f3Spatrick 1697518be5f3Spatrick ring->status = RING_OPENING; 169802ee7d07Spatrick ring->fifo = bwfm_pci_prio2fifo[cmd->prio]; 169902ee7d07Spatrick ring->m = cmd->m; 170002ee7d07Spatrick memcpy(ring->mac, da, ETHER_ADDR_LEN); 17012b7bea7eSpatrick #ifndef IEEE80211_STA_ONLY 170202ee7d07Spatrick if (ic->ic_opmode == IEEE80211_M_HOSTAP && ETHER_IS_MULTICAST(da)) 17032b7bea7eSpatrick memcpy(ring->mac, etherbroadcastaddr, ETHER_ADDR_LEN); 17042b7bea7eSpatrick #endif 1705f67437f3Spatrick 1706518be5f3Spatrick req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE; 1707518be5f3Spatrick req->msg.ifidx = 0; 1708518be5f3Spatrick req->msg.request_id = 0; 170902ee7d07Spatrick req->tid = bwfm_pci_prio2fifo[cmd->prio]; 171002ee7d07Spatrick req->flow_ring_id = letoh16(cmd->flowid + 2); 171102ee7d07Spatrick memcpy(req->da, da, ETHER_ADDR_LEN); 171202ee7d07Spatrick memcpy(req->sa, sa, ETHER_ADDR_LEN); 1713518be5f3Spatrick req->flow_ring_addr.high_addr = 1714518be5f3Spatrick letoh32(BWFM_PCI_DMA_DVA(ring->ring) >> 32); 1715518be5f3Spatrick req->flow_ring_addr.low_addr = 1716518be5f3Spatrick letoh32(BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff); 1717518be5f3Spatrick req->max_items = letoh16(512); 1718518be5f3Spatrick req->len_item = letoh16(48); 1719518be5f3Spatrick 1720518be5f3Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit); 1721e272db29Spatrick splx(s); 1722518be5f3Spatrick } 1723518be5f3Spatrick 1724a2c6ff8bSpatrick void 1725a2c6ff8bSpatrick bwfm_pci_flowring_delete(struct bwfm_pci_softc *sc, int flowid) 1726a2c6ff8bSpatrick { 1727a2c6ff8bSpatrick struct msgbuf_tx_flowring_delete_req *req; 1728a2c6ff8bSpatrick struct bwfm_pci_msgring *ring; 1729e272db29Spatrick int s; 1730a2c6ff8bSpatrick 1731a2c6ff8bSpatrick ring = &sc->sc_flowrings[flowid]; 1732a2c6ff8bSpatrick if (ring->status != RING_OPEN) { 1733a2c6ff8bSpatrick printf("%s: flowring not open\n", DEVNAME(sc)); 1734a2c6ff8bSpatrick return; 1735a2c6ff8bSpatrick } 1736a2c6ff8bSpatrick 1737e272db29Spatrick s = splnet(); 1738a2c6ff8bSpatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit); 1739a2c6ff8bSpatrick if (req == NULL) { 1740a2c6ff8bSpatrick printf("%s: cannot reserve for flowring\n", DEVNAME(sc)); 1741e272db29Spatrick splx(s); 1742a2c6ff8bSpatrick return; 1743a2c6ff8bSpatrick } 1744a2c6ff8bSpatrick 1745a2c6ff8bSpatrick ring->status = RING_CLOSING; 1746a2c6ff8bSpatrick 1747a2c6ff8bSpatrick req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE; 1748a2c6ff8bSpatrick req->msg.ifidx = 0; 1749a2c6ff8bSpatrick req->msg.request_id = 0; 1750a2c6ff8bSpatrick req->flow_ring_id = letoh16(flowid + 2); 1751a2c6ff8bSpatrick req->reason = 0; 1752a2c6ff8bSpatrick 1753a2c6ff8bSpatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit); 1754e272db29Spatrick splx(s); 1755a2c6ff8bSpatrick } 1756a2c6ff8bSpatrick 1757a2c6ff8bSpatrick void 1758a2c6ff8bSpatrick bwfm_pci_stop(struct bwfm_softc *bwfm) 1759a2c6ff8bSpatrick { 1760a2c6ff8bSpatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1761a2c6ff8bSpatrick struct bwfm_pci_msgring *ring; 1762a2c6ff8bSpatrick int i; 1763a2c6ff8bSpatrick 1764a2c6ff8bSpatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 1765a2c6ff8bSpatrick ring = &sc->sc_flowrings[i]; 1766a2c6ff8bSpatrick if (ring->status == RING_OPEN) 1767a2c6ff8bSpatrick bwfm_pci_flowring_delete(sc, i); 1768a2c6ff8bSpatrick } 1769a2c6ff8bSpatrick } 1770a2c6ff8bSpatrick 1771e5ec1e72Spatrick int 177202ee7d07Spatrick bwfm_pci_txcheck(struct bwfm_softc *bwfm) 177302ee7d07Spatrick { 177402ee7d07Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 177502ee7d07Spatrick struct bwfm_pci_msgring *ring; 177602ee7d07Spatrick int i; 177702ee7d07Spatrick 177802ee7d07Spatrick /* If we are transitioning, we cannot send. */ 177902ee7d07Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 178002ee7d07Spatrick ring = &sc->sc_flowrings[i]; 178102ee7d07Spatrick if (ring->status == RING_OPENING) 178202ee7d07Spatrick return ENOBUFS; 178302ee7d07Spatrick } 178402ee7d07Spatrick 178502ee7d07Spatrick if (bwfm_pci_pktid_avail(sc, &sc->sc_tx_pkts)) { 178602ee7d07Spatrick sc->sc_tx_pkts_full = 1; 178702ee7d07Spatrick return ENOBUFS; 178802ee7d07Spatrick } 178902ee7d07Spatrick 179002ee7d07Spatrick return 0; 179102ee7d07Spatrick } 179202ee7d07Spatrick 179302ee7d07Spatrick int 1794e5ec1e72Spatrick bwfm_pci_txdata(struct bwfm_softc *bwfm, struct mbuf *m) 1795e5ec1e72Spatrick { 1796e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1797518be5f3Spatrick struct bwfm_pci_msgring *ring; 1798518be5f3Spatrick struct msgbuf_tx_msghdr *tx; 1799518be5f3Spatrick uint32_t pktid; 1800518be5f3Spatrick paddr_t paddr; 1801518be5f3Spatrick int flowid, ret; 1802518be5f3Spatrick 1803f67437f3Spatrick flowid = bwfm_pci_flowring_lookup(sc, m); 1804f67437f3Spatrick if (flowid < 0) { 180502ee7d07Spatrick /* 180602ee7d07Spatrick * We cannot send the packet right now as there is 180702ee7d07Spatrick * no flowring yet. The flowring will be created 180802ee7d07Spatrick * asynchronously. While the ring is transitioning 180902ee7d07Spatrick * the TX check will tell the upper layers that we 181002ee7d07Spatrick * cannot send packets right now. When the flowring 181102ee7d07Spatrick * is created the queue will be restarted and this 181202ee7d07Spatrick * mbuf will be transmitted. 181302ee7d07Spatrick */ 1814f67437f3Spatrick bwfm_pci_flowring_create(sc, m); 181502ee7d07Spatrick return 0; 1816f67437f3Spatrick } 1817518be5f3Spatrick 1818518be5f3Spatrick ring = &sc->sc_flowrings[flowid]; 1819518be5f3Spatrick if (ring->status == RING_OPENING || 1820f67437f3Spatrick ring->status == RING_CLOSING) { 1821f67437f3Spatrick printf("%s: tried to use a flow that was " 1822f67437f3Spatrick "transitioning in status %d\n", 1823f67437f3Spatrick DEVNAME(sc), ring->status); 1824518be5f3Spatrick return ENOBUFS; 1825518be5f3Spatrick } 1826518be5f3Spatrick 1827518be5f3Spatrick tx = bwfm_pci_ring_write_reserve(sc, ring); 1828518be5f3Spatrick if (tx == NULL) 1829518be5f3Spatrick return ENOBUFS; 1830518be5f3Spatrick 1831518be5f3Spatrick memset(tx, 0, sizeof(*tx)); 1832518be5f3Spatrick tx->msg.msgtype = MSGBUF_TYPE_TX_POST; 1833518be5f3Spatrick tx->msg.ifidx = 0; 1834518be5f3Spatrick tx->flags = BWFM_MSGBUF_PKT_FLAGS_FRAME_802_3; 1835518be5f3Spatrick tx->flags |= ieee80211_classify(&sc->sc_sc.sc_ic, m) << 1836518be5f3Spatrick BWFM_MSGBUF_PKT_FLAGS_PRIO_SHIFT; 1837518be5f3Spatrick tx->seg_cnt = 1; 1838518be5f3Spatrick memcpy(tx->txhdr, mtod(m, char *), ETHER_HDR_LEN); 1839518be5f3Spatrick 1840518be5f3Spatrick ret = bwfm_pci_pktid_new(sc, &sc->sc_tx_pkts, m, &pktid, &paddr); 1841518be5f3Spatrick if (ret) { 184202ee7d07Spatrick if (ret == ENOBUFS) { 184302ee7d07Spatrick printf("%s: no pktid available for TX\n", 184402ee7d07Spatrick DEVNAME(sc)); 1845c6f1636dSpatrick sc->sc_tx_pkts_full = 1; 184602ee7d07Spatrick } 1847518be5f3Spatrick bwfm_pci_ring_write_cancel(sc, ring, 1); 1848518be5f3Spatrick return ret; 1849518be5f3Spatrick } 1850518be5f3Spatrick paddr += ETHER_HDR_LEN; 1851518be5f3Spatrick 1852f9ee104fSpatrick tx->msg.request_id = htole32(pktid + 1); 18534ff787bcSpatrick tx->data_len = htole16(m->m_len - ETHER_HDR_LEN); 1854e4dae658Spatrick tx->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32); 1855518be5f3Spatrick tx->data_buf_addr.low_addr = htole32(paddr & 0xffffffff); 1856518be5f3Spatrick 1857518be5f3Spatrick bwfm_pci_ring_write_commit(sc, ring); 1858518be5f3Spatrick return 0; 1859e5ec1e72Spatrick } 1860e5ec1e72Spatrick 1861bbd71b0bSpatrick #ifdef BWFM_DEBUG 1862cadf5fcfSpatrick void 1863cadf5fcfSpatrick bwfm_pci_debug_console(struct bwfm_pci_softc *sc) 1864cadf5fcfSpatrick { 1865cadf5fcfSpatrick uint32_t newidx = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1866cadf5fcfSpatrick sc->sc_console_base_addr + BWFM_CONSOLE_WRITEIDX); 1867cadf5fcfSpatrick 1868cadf5fcfSpatrick if (newidx != sc->sc_console_readidx) 1869bbd71b0bSpatrick DPRINTFN(3, ("BWFM CONSOLE: ")); 1870cadf5fcfSpatrick while (newidx != sc->sc_console_readidx) { 1871cadf5fcfSpatrick uint8_t ch = bus_space_read_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1872cadf5fcfSpatrick sc->sc_console_buf_addr + sc->sc_console_readidx); 1873cadf5fcfSpatrick sc->sc_console_readidx++; 1874cadf5fcfSpatrick if (sc->sc_console_readidx == sc->sc_console_buf_size) 1875cadf5fcfSpatrick sc->sc_console_readidx = 0; 1876cadf5fcfSpatrick if (ch == '\r') 1877cadf5fcfSpatrick continue; 1878bbd71b0bSpatrick DPRINTFN(3, ("%c", ch)); 1879cadf5fcfSpatrick } 1880cadf5fcfSpatrick } 1881bbd71b0bSpatrick #endif 1882cadf5fcfSpatrick 1883e5ec1e72Spatrick int 1884e5ec1e72Spatrick bwfm_pci_intr(void *v) 1885e5ec1e72Spatrick { 1886e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)v; 18876f241297Spatrick struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if; 18886f241297Spatrick struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 1889e5ec1e72Spatrick uint32_t status; 1890e5ec1e72Spatrick 1891e5ec1e72Spatrick if ((status = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1892e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXINT)) == 0) 1893e5ec1e72Spatrick return 0; 1894e5ec1e72Spatrick 1895e5ec1e72Spatrick bwfm_pci_intr_disable(sc); 1896e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1897e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXINT, status); 1898e5ec1e72Spatrick 1899e5ec1e72Spatrick if (status & (BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 | 1900e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1)) 1901e5ec1e72Spatrick printf("%s: handle MB data\n", __func__); 1902e5ec1e72Spatrick 1903e5ec1e72Spatrick if (status & BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB) { 19046f241297Spatrick bwfm_pci_ring_rx(sc, &sc->sc_rx_complete, &ml); 19056f241297Spatrick bwfm_pci_ring_rx(sc, &sc->sc_tx_complete, &ml); 19066f241297Spatrick bwfm_pci_ring_rx(sc, &sc->sc_ctrl_complete, &ml); 1907447a2df6Sdlg 1908447a2df6Sdlg if (ifiq_input(&ifp->if_rcv, &ml)) 1909447a2df6Sdlg if_rxr_livelocked(&sc->sc_rxbuf_ring); 1910e5ec1e72Spatrick } 1911e5ec1e72Spatrick 1912cadf5fcfSpatrick #ifdef BWFM_DEBUG 1913cadf5fcfSpatrick bwfm_pci_debug_console(sc); 1914e5ec1e72Spatrick #endif 1915e5ec1e72Spatrick 1916e5ec1e72Spatrick bwfm_pci_intr_enable(sc); 1917e5ec1e72Spatrick return 1; 1918e5ec1e72Spatrick } 1919e5ec1e72Spatrick 1920e5ec1e72Spatrick void 1921e5ec1e72Spatrick bwfm_pci_intr_enable(struct bwfm_pci_softc *sc) 1922e5ec1e72Spatrick { 1923e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1924e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK, 1925e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 | 1926e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1 | 1927e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB); 1928e5ec1e72Spatrick } 1929e5ec1e72Spatrick 1930e5ec1e72Spatrick void 1931e5ec1e72Spatrick bwfm_pci_intr_disable(struct bwfm_pci_softc *sc) 1932e5ec1e72Spatrick { 1933e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1934e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK, 0); 1935e5ec1e72Spatrick } 1936e5ec1e72Spatrick 1937*156d2677Spatrick void 1938*156d2677Spatrick bwfm_pci_hostready(struct bwfm_pci_softc *sc) 1939*156d2677Spatrick { 1940*156d2677Spatrick if ((sc->sc_shared_flags & BWFM_SHARED_INFO_HOSTRDY_DB1) == 0) 1941*156d2677Spatrick return; 1942*156d2677Spatrick 1943*156d2677Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1944*156d2677Spatrick BWFM_PCI_PCIE2REG_H2D_MAILBOX_1, 1); 1945*156d2677Spatrick } 1946*156d2677Spatrick 1947e5ec1e72Spatrick /* Msgbuf protocol implementation */ 1948e5ec1e72Spatrick int 1949e5ec1e72Spatrick bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *bwfm, int ifidx, 1950e5ec1e72Spatrick int cmd, char *buf, size_t *len) 1951e5ec1e72Spatrick { 1952e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1953e5ec1e72Spatrick struct msgbuf_ioctl_req_hdr *req; 19542eeba925Spatrick struct bwfm_pci_ioctl *ctl; 1955e5ec1e72Spatrick struct mbuf *m; 19562eeba925Spatrick uint32_t pktid; 19572eeba925Spatrick paddr_t paddr; 1958e5ec1e72Spatrick size_t buflen; 1959e272db29Spatrick int s; 1960e5ec1e72Spatrick 19612eeba925Spatrick buflen = min(*len, BWFM_DMA_H2D_IOCTL_BUF_LEN); 1962471f2571Sjan m = MCLGETL(NULL, M_DONTWAIT, buflen); 19632eeba925Spatrick if (m == NULL) 19642eeba925Spatrick return 1; 19652eeba925Spatrick m->m_len = m->m_pkthdr.len = buflen; 19662eeba925Spatrick 19672eeba925Spatrick if (buf) 19682eeba925Spatrick memcpy(mtod(m, char *), buf, buflen); 19692eeba925Spatrick else 19702eeba925Spatrick memset(mtod(m, char *), 0, buflen); 19712eeba925Spatrick 1972e272db29Spatrick s = splnet(); 1973e5ec1e72Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit); 1974e5ec1e72Spatrick if (req == NULL) { 1975e272db29Spatrick splx(s); 19762eeba925Spatrick m_freem(m); 1977e5ec1e72Spatrick return 1; 1978e5ec1e72Spatrick } 19792eeba925Spatrick 19802eeba925Spatrick if (bwfm_pci_pktid_new(sc, &sc->sc_ioctl_pkts, m, &pktid, &paddr)) { 19812eeba925Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1); 1982e272db29Spatrick splx(s); 19832eeba925Spatrick m_freem(m); 19842eeba925Spatrick return 1; 19852eeba925Spatrick } 19862eeba925Spatrick 19872eeba925Spatrick ctl = malloc(sizeof(*ctl), M_TEMP, M_WAITOK|M_ZERO); 19882eeba925Spatrick ctl->transid = sc->sc_ioctl_transid++; 19892eeba925Spatrick TAILQ_INSERT_TAIL(&sc->sc_ioctlq, ctl, next); 19902eeba925Spatrick 1991e5ec1e72Spatrick req->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ; 1992e5ec1e72Spatrick req->msg.ifidx = 0; 1993e5ec1e72Spatrick req->msg.flags = 0; 19942eeba925Spatrick req->msg.request_id = htole32(pktid); 1995e5ec1e72Spatrick req->cmd = htole32(cmd); 1996e5ec1e72Spatrick req->output_buf_len = htole16(*len); 19972eeba925Spatrick req->trans_id = htole16(ctl->transid); 1998e5ec1e72Spatrick 19992eeba925Spatrick req->input_buf_len = htole16(m->m_len); 20002eeba925Spatrick req->req_buf_addr.high_addr = htole32((uint64_t)paddr >> 32); 20012eeba925Spatrick req->req_buf_addr.low_addr = htole32(paddr & 0xffffffff); 2002dcb67343Spatrick 2003e5ec1e72Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit); 2004e272db29Spatrick splx(s); 2005e5ec1e72Spatrick 20068544fed6Smpi tsleep_nsec(ctl, PWAIT, "bwfm", SEC_TO_NSEC(1)); 20072eeba925Spatrick TAILQ_REMOVE(&sc->sc_ioctlq, ctl, next); 20082eeba925Spatrick 20092eeba925Spatrick if (ctl->m == NULL) { 20102eeba925Spatrick free(ctl, M_TEMP, sizeof(*ctl)); 2011e5ec1e72Spatrick return 1; 2012e5ec1e72Spatrick } 2013e5ec1e72Spatrick 20142eeba925Spatrick *len = min(ctl->retlen, m->m_len); 20152eeba925Spatrick *len = min(*len, buflen); 2016e5ec1e72Spatrick if (buf) 20175c7fed39Sdlg m_copydata(ctl->m, 0, *len, buf); 20182eeba925Spatrick m_freem(ctl->m); 2019e5ec1e72Spatrick 20202eeba925Spatrick if (ctl->status < 0) { 20212eeba925Spatrick free(ctl, M_TEMP, sizeof(*ctl)); 20222eeba925Spatrick return 1; 20232eeba925Spatrick } 20242eeba925Spatrick 20252eeba925Spatrick free(ctl, M_TEMP, sizeof(*ctl)); 2026e5ec1e72Spatrick return 0; 2027e5ec1e72Spatrick } 2028e5ec1e72Spatrick 2029e5ec1e72Spatrick int 2030e5ec1e72Spatrick bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *bwfm, int ifidx, 2031e5ec1e72Spatrick int cmd, char *buf, size_t len) 2032e5ec1e72Spatrick { 2033e5ec1e72Spatrick return bwfm_pci_msgbuf_query_dcmd(bwfm, ifidx, cmd, buf, &len); 2034e5ec1e72Spatrick } 20352eeba925Spatrick 20362eeba925Spatrick void 20372eeba925Spatrick bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *sc, 20382eeba925Spatrick struct msgbuf_ioctl_resp_hdr *resp) 20392eeba925Spatrick { 20402eeba925Spatrick struct bwfm_pci_ioctl *ctl, *tmp; 20412eeba925Spatrick struct mbuf *m; 20422eeba925Spatrick 20432eeba925Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts, 20442eeba925Spatrick letoh32(resp->msg.request_id)); 20452eeba925Spatrick 20462eeba925Spatrick TAILQ_FOREACH_SAFE(ctl, &sc->sc_ioctlq, next, tmp) { 20472eeba925Spatrick if (ctl->transid != letoh16(resp->trans_id)) 20482eeba925Spatrick continue; 20492eeba925Spatrick ctl->m = m; 20502eeba925Spatrick ctl->retlen = letoh16(resp->resp_len); 20512eeba925Spatrick ctl->status = letoh16(resp->compl_hdr.status); 20522eeba925Spatrick wakeup(ctl); 20532eeba925Spatrick return; 20542eeba925Spatrick } 20552eeba925Spatrick 2056cb2afc74Spatrick m_freem(m); 20572eeba925Spatrick } 2058