1*13f544a8Spatrick /* $OpenBSD: if_bwfm_pci.c,v 1.53 2021/08/31 20:58:51 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 30ed6d4272Spatrick #if defined(__HAVE_FDT) 31ed6d4272Spatrick #include <machine/fdt.h> 32ed6d4272Spatrick #include <dev/ofw/openfirm.h> 33ed6d4272Spatrick #endif 34ed6d4272Spatrick 35e5ec1e72Spatrick #if NBPFILTER > 0 36e5ec1e72Spatrick #include <net/bpf.h> 37e5ec1e72Spatrick #endif 38e5ec1e72Spatrick #include <net/if.h> 39e5ec1e72Spatrick #include <net/if_dl.h> 40e5ec1e72Spatrick #include <net/if_media.h> 41e5ec1e72Spatrick 42e5ec1e72Spatrick #include <netinet/in.h> 43e5ec1e72Spatrick #include <netinet/if_ether.h> 44e5ec1e72Spatrick 45e5ec1e72Spatrick #include <net80211/ieee80211_var.h> 46e5ec1e72Spatrick 47e5ec1e72Spatrick #include <machine/bus.h> 48e5ec1e72Spatrick 49e5ec1e72Spatrick #include <dev/pci/pcireg.h> 50e5ec1e72Spatrick #include <dev/pci/pcivar.h> 51e5ec1e72Spatrick #include <dev/pci/pcidevs.h> 52e5ec1e72Spatrick 53e5ec1e72Spatrick #include <dev/ic/bwfmvar.h> 54e5ec1e72Spatrick #include <dev/ic/bwfmreg.h> 55e5ec1e72Spatrick #include <dev/pci/if_bwfm_pci.h> 56e5ec1e72Spatrick 57e5ec1e72Spatrick #define BWFM_DMA_D2H_SCRATCH_BUF_LEN 8 58e5ec1e72Spatrick #define BWFM_DMA_D2H_RINGUPD_BUF_LEN 1024 59e5ec1e72Spatrick #define BWFM_DMA_H2D_IOCTL_BUF_LEN ETHER_MAX_LEN 60e5ec1e72Spatrick 61e5ec1e72Spatrick #define BWFM_NUM_TX_MSGRINGS 2 62e5ec1e72Spatrick #define BWFM_NUM_RX_MSGRINGS 3 63e5ec1e72Spatrick 642eeba925Spatrick #define BWFM_NUM_IOCTL_PKTIDS 8 65e5ec1e72Spatrick #define BWFM_NUM_TX_PKTIDS 2048 66e5ec1e72Spatrick #define BWFM_NUM_RX_PKTIDS 1024 67e5ec1e72Spatrick 682eeba925Spatrick #define BWFM_NUM_IOCTL_DESCS 1 69e5ec1e72Spatrick #define BWFM_NUM_TX_DESCS 1 70e5ec1e72Spatrick #define BWFM_NUM_RX_DESCS 1 71e5ec1e72Spatrick 72e5ec1e72Spatrick #ifdef BWFM_DEBUG 73e5ec1e72Spatrick #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0) 74e5ec1e72Spatrick #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0) 75e5ec1e72Spatrick static int bwfm_debug = 2; 76e5ec1e72Spatrick #else 77e5ec1e72Spatrick #define DPRINTF(x) do { ; } while (0) 78e5ec1e72Spatrick #define DPRINTFN(n, x) do { ; } while (0) 79e5ec1e72Spatrick #endif 80e5ec1e72Spatrick 81e5ec1e72Spatrick #define DEVNAME(sc) ((sc)->sc_sc.sc_dev.dv_xname) 82e5ec1e72Spatrick 83518be5f3Spatrick enum ring_status { 84518be5f3Spatrick RING_CLOSED, 85518be5f3Spatrick RING_CLOSING, 86518be5f3Spatrick RING_OPEN, 87518be5f3Spatrick RING_OPENING, 88518be5f3Spatrick }; 89518be5f3Spatrick 90e5ec1e72Spatrick struct bwfm_pci_msgring { 91e5ec1e72Spatrick uint32_t w_idx_addr; 92e5ec1e72Spatrick uint32_t r_idx_addr; 93e5ec1e72Spatrick uint32_t w_ptr; 94e5ec1e72Spatrick uint32_t r_ptr; 95e5ec1e72Spatrick int nitem; 96e5ec1e72Spatrick int itemsz; 97518be5f3Spatrick enum ring_status status; 98e5ec1e72Spatrick struct bwfm_pci_dmamem *ring; 9902ee7d07Spatrick struct mbuf *m; 100f67437f3Spatrick 101f67437f3Spatrick int fifo; 102f67437f3Spatrick uint8_t mac[ETHER_ADDR_LEN]; 103e5ec1e72Spatrick }; 104e5ec1e72Spatrick 1052eeba925Spatrick struct bwfm_pci_ioctl { 1062eeba925Spatrick uint16_t transid; 1072eeba925Spatrick uint16_t retlen; 1082eeba925Spatrick int16_t status; 1092eeba925Spatrick struct mbuf *m; 1102eeba925Spatrick TAILQ_ENTRY(bwfm_pci_ioctl) next; 1112eeba925Spatrick }; 1122eeba925Spatrick 113e5ec1e72Spatrick struct bwfm_pci_buf { 114e5ec1e72Spatrick bus_dmamap_t bb_map; 115e5ec1e72Spatrick struct mbuf *bb_m; 116e5ec1e72Spatrick }; 117e5ec1e72Spatrick 118e5ec1e72Spatrick struct bwfm_pci_pkts { 119e5ec1e72Spatrick struct bwfm_pci_buf *pkts; 120e5ec1e72Spatrick uint32_t npkt; 121e5ec1e72Spatrick int last; 122e5ec1e72Spatrick }; 123e5ec1e72Spatrick 124e5ec1e72Spatrick struct bwfm_pci_softc { 125e5ec1e72Spatrick struct bwfm_softc sc_sc; 126e5ec1e72Spatrick pci_chipset_tag_t sc_pc; 127e5ec1e72Spatrick pcitag_t sc_tag; 128e5ec1e72Spatrick pcireg_t sc_id; 129e5ec1e72Spatrick void *sc_ih; 130e5ec1e72Spatrick 131972218f3Spatrick int sc_initialized; 132972218f3Spatrick 133e5ec1e72Spatrick bus_space_tag_t sc_reg_iot; 134e5ec1e72Spatrick bus_space_handle_t sc_reg_ioh; 135e5ec1e72Spatrick bus_size_t sc_reg_ios; 136e5ec1e72Spatrick 137e5ec1e72Spatrick bus_space_tag_t sc_tcm_iot; 138e5ec1e72Spatrick bus_space_handle_t sc_tcm_ioh; 139e5ec1e72Spatrick bus_size_t sc_tcm_ios; 140e5ec1e72Spatrick 141e5ec1e72Spatrick bus_dma_tag_t sc_dmat; 142e5ec1e72Spatrick 143e5ec1e72Spatrick uint32_t sc_shared_address; 144e5ec1e72Spatrick uint32_t sc_shared_flags; 145e5ec1e72Spatrick uint8_t sc_shared_version; 146e5ec1e72Spatrick 147e5ec1e72Spatrick uint8_t sc_dma_idx_sz; 148e5ec1e72Spatrick struct bwfm_pci_dmamem *sc_dma_idx_buf; 149e5ec1e72Spatrick size_t sc_dma_idx_bufsz; 150e5ec1e72Spatrick 151e5ec1e72Spatrick uint16_t sc_max_rxbufpost; 152e5ec1e72Spatrick uint32_t sc_rx_dataoffset; 153e5ec1e72Spatrick uint32_t sc_htod_mb_data_addr; 154e5ec1e72Spatrick uint32_t sc_dtoh_mb_data_addr; 155e5ec1e72Spatrick uint32_t sc_ring_info_addr; 156e5ec1e72Spatrick 157e5ec1e72Spatrick uint32_t sc_console_base_addr; 158e5ec1e72Spatrick uint32_t sc_console_buf_addr; 159e5ec1e72Spatrick uint32_t sc_console_buf_size; 160cadf5fcfSpatrick uint32_t sc_console_readidx; 161e5ec1e72Spatrick 162e5ec1e72Spatrick uint16_t sc_max_flowrings; 163e5ec1e72Spatrick uint16_t sc_max_submissionrings; 164e5ec1e72Spatrick uint16_t sc_max_completionrings; 165e5ec1e72Spatrick 166e5ec1e72Spatrick struct bwfm_pci_msgring sc_ctrl_submit; 167e5ec1e72Spatrick struct bwfm_pci_msgring sc_rxpost_submit; 168e5ec1e72Spatrick struct bwfm_pci_msgring sc_ctrl_complete; 169e5ec1e72Spatrick struct bwfm_pci_msgring sc_tx_complete; 170e5ec1e72Spatrick struct bwfm_pci_msgring sc_rx_complete; 171e5ec1e72Spatrick struct bwfm_pci_msgring *sc_flowrings; 172e5ec1e72Spatrick 173e5ec1e72Spatrick struct bwfm_pci_dmamem *sc_scratch_buf; 174e5ec1e72Spatrick struct bwfm_pci_dmamem *sc_ringupd_buf; 175e5ec1e72Spatrick 1762eeba925Spatrick TAILQ_HEAD(, bwfm_pci_ioctl) sc_ioctlq; 1772eeba925Spatrick uint16_t sc_ioctl_transid; 178e5ec1e72Spatrick 179e5ec1e72Spatrick struct if_rxring sc_ioctl_ring; 180e5ec1e72Spatrick struct if_rxring sc_event_ring; 181e5ec1e72Spatrick struct if_rxring sc_rxbuf_ring; 182e5ec1e72Spatrick 1832eeba925Spatrick struct bwfm_pci_pkts sc_ioctl_pkts; 184e5ec1e72Spatrick struct bwfm_pci_pkts sc_rx_pkts; 185c6f1636dSpatrick struct bwfm_pci_pkts sc_tx_pkts; 186c6f1636dSpatrick int sc_tx_pkts_full; 187e5ec1e72Spatrick }; 188e5ec1e72Spatrick 189e5ec1e72Spatrick struct bwfm_pci_dmamem { 190e5ec1e72Spatrick bus_dmamap_t bdm_map; 191e5ec1e72Spatrick bus_dma_segment_t bdm_seg; 192e5ec1e72Spatrick size_t bdm_size; 193e5ec1e72Spatrick caddr_t bdm_kva; 194e5ec1e72Spatrick }; 195e5ec1e72Spatrick 196e5ec1e72Spatrick #define BWFM_PCI_DMA_MAP(_bdm) ((_bdm)->bdm_map) 197e5ec1e72Spatrick #define BWFM_PCI_DMA_LEN(_bdm) ((_bdm)->bdm_size) 198e4dae658Spatrick #define BWFM_PCI_DMA_DVA(_bdm) ((uint64_t)(_bdm)->bdm_map->dm_segs[0].ds_addr) 199e5ec1e72Spatrick #define BWFM_PCI_DMA_KVA(_bdm) ((void *)(_bdm)->bdm_kva) 200e5ec1e72Spatrick 201e5ec1e72Spatrick int bwfm_pci_match(struct device *, void *, void *); 202e5ec1e72Spatrick void bwfm_pci_attach(struct device *, struct device *, void *); 203e5ec1e72Spatrick int bwfm_pci_detach(struct device *, int); 204e5ec1e72Spatrick 205ed6d4272Spatrick #if defined(__HAVE_FDT) 206ed6d4272Spatrick int bwfm_pci_read_otp(struct bwfm_pci_softc *); 207ed6d4272Spatrick void bwfm_pci_process_otp_tuple(struct bwfm_pci_softc *, uint8_t, 208ed6d4272Spatrick uint8_t, uint8_t *); 209ed6d4272Spatrick #endif 210ed6d4272Spatrick 211e5ec1e72Spatrick int bwfm_pci_intr(void *); 212e5ec1e72Spatrick void bwfm_pci_intr_enable(struct bwfm_pci_softc *); 213e5ec1e72Spatrick void bwfm_pci_intr_disable(struct bwfm_pci_softc *); 214bb813cf8Spatrick uint32_t bwfm_pci_intr_status(struct bwfm_pci_softc *); 215bb813cf8Spatrick void bwfm_pci_intr_ack(struct bwfm_pci_softc *, uint32_t); 216156d2677Spatrick void bwfm_pci_hostready(struct bwfm_pci_softc *); 217e5ec1e72Spatrick int bwfm_pci_load_microcode(struct bwfm_pci_softc *, const u_char *, 2186aad491fSpatrick size_t, const u_char *, size_t); 219e5ec1e72Spatrick void bwfm_pci_select_core(struct bwfm_pci_softc *, int ); 220e5ec1e72Spatrick 221e5ec1e72Spatrick struct bwfm_pci_dmamem * 222e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *, bus_size_t, 223e5ec1e72Spatrick bus_size_t); 224e5ec1e72Spatrick void bwfm_pci_dmamem_free(struct bwfm_pci_softc *, struct bwfm_pci_dmamem *); 22502ee7d07Spatrick int bwfm_pci_pktid_avail(struct bwfm_pci_softc *, 22602ee7d07Spatrick struct bwfm_pci_pkts *); 227e5ec1e72Spatrick int bwfm_pci_pktid_new(struct bwfm_pci_softc *, 228e5ec1e72Spatrick struct bwfm_pci_pkts *, struct mbuf *, 229e5ec1e72Spatrick uint32_t *, paddr_t *); 230e5ec1e72Spatrick struct mbuf * bwfm_pci_pktid_free(struct bwfm_pci_softc *, 231e5ec1e72Spatrick struct bwfm_pci_pkts *, uint32_t); 232e5ec1e72Spatrick void bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *, 233e5ec1e72Spatrick struct if_rxring *, uint32_t); 234e5ec1e72Spatrick void bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *); 235e5ec1e72Spatrick void bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *); 236e5ec1e72Spatrick int bwfm_pci_setup_ring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *, 237e5ec1e72Spatrick int, size_t, uint32_t, uint32_t, int, uint32_t, uint32_t *); 238518be5f3Spatrick int bwfm_pci_setup_flowring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *, 239518be5f3Spatrick int, size_t); 240e5ec1e72Spatrick 241e5ec1e72Spatrick void bwfm_pci_ring_bell(struct bwfm_pci_softc *, 242e5ec1e72Spatrick struct bwfm_pci_msgring *); 243e5ec1e72Spatrick void bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *, 244e5ec1e72Spatrick struct bwfm_pci_msgring *); 245e5ec1e72Spatrick void bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *, 246e5ec1e72Spatrick struct bwfm_pci_msgring *); 247e5ec1e72Spatrick void bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *, 248e5ec1e72Spatrick struct bwfm_pci_msgring *); 249e5ec1e72Spatrick void bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *, 250e5ec1e72Spatrick struct bwfm_pci_msgring *); 251e5ec1e72Spatrick void * bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *, 252e5ec1e72Spatrick struct bwfm_pci_msgring *); 253e5ec1e72Spatrick void * bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *, 254e5ec1e72Spatrick struct bwfm_pci_msgring *, int, int *); 255e5ec1e72Spatrick void * bwfm_pci_ring_read_avail(struct bwfm_pci_softc *, 256e5ec1e72Spatrick struct bwfm_pci_msgring *, int *); 257e5ec1e72Spatrick void bwfm_pci_ring_read_commit(struct bwfm_pci_softc *, 258e5ec1e72Spatrick struct bwfm_pci_msgring *, int); 259e5ec1e72Spatrick void bwfm_pci_ring_write_commit(struct bwfm_pci_softc *, 260e5ec1e72Spatrick struct bwfm_pci_msgring *); 261e5ec1e72Spatrick void bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *, 262e5ec1e72Spatrick struct bwfm_pci_msgring *, int); 263e5ec1e72Spatrick 264e5ec1e72Spatrick void bwfm_pci_ring_rx(struct bwfm_pci_softc *, 2656f241297Spatrick struct bwfm_pci_msgring *, struct mbuf_list *); 2666f241297Spatrick void bwfm_pci_msg_rx(struct bwfm_pci_softc *, void *, 2676f241297Spatrick struct mbuf_list *); 268e5ec1e72Spatrick 269e5ec1e72Spatrick uint32_t bwfm_pci_buscore_read(struct bwfm_softc *, uint32_t); 270e5ec1e72Spatrick void bwfm_pci_buscore_write(struct bwfm_softc *, uint32_t, 271e5ec1e72Spatrick uint32_t); 272e5ec1e72Spatrick int bwfm_pci_buscore_prepare(struct bwfm_softc *); 273e5ec1e72Spatrick int bwfm_pci_buscore_reset(struct bwfm_softc *); 274e5ec1e72Spatrick void bwfm_pci_buscore_activate(struct bwfm_softc *, uint32_t); 275e5ec1e72Spatrick 276f67437f3Spatrick int bwfm_pci_flowring_lookup(struct bwfm_pci_softc *, 277f67437f3Spatrick struct mbuf *); 278f67437f3Spatrick void bwfm_pci_flowring_create(struct bwfm_pci_softc *, 279518be5f3Spatrick struct mbuf *); 280518be5f3Spatrick void bwfm_pci_flowring_create_cb(struct bwfm_softc *, void *); 281a2c6ff8bSpatrick void bwfm_pci_flowring_delete(struct bwfm_pci_softc *, int); 282518be5f3Spatrick 283972218f3Spatrick int bwfm_pci_preinit(struct bwfm_softc *); 284a2c6ff8bSpatrick void bwfm_pci_stop(struct bwfm_softc *); 28502ee7d07Spatrick int bwfm_pci_txcheck(struct bwfm_softc *); 286e5ec1e72Spatrick int bwfm_pci_txdata(struct bwfm_softc *, struct mbuf *); 287bbd71b0bSpatrick 288bbd71b0bSpatrick #ifdef BWFM_DEBUG 289cadf5fcfSpatrick void bwfm_pci_debug_console(struct bwfm_pci_softc *); 290bbd71b0bSpatrick #endif 291e5ec1e72Spatrick 292e5ec1e72Spatrick int bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *, int, 293e5ec1e72Spatrick int, char *, size_t *); 294e5ec1e72Spatrick int bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *, int, 295e5ec1e72Spatrick int, char *, size_t); 2962eeba925Spatrick void bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *, 2972eeba925Spatrick struct msgbuf_ioctl_resp_hdr *); 298e5ec1e72Spatrick 299e5ec1e72Spatrick struct bwfm_buscore_ops bwfm_pci_buscore_ops = { 300e5ec1e72Spatrick .bc_read = bwfm_pci_buscore_read, 301e5ec1e72Spatrick .bc_write = bwfm_pci_buscore_write, 302e5ec1e72Spatrick .bc_prepare = bwfm_pci_buscore_prepare, 303e5ec1e72Spatrick .bc_reset = bwfm_pci_buscore_reset, 304e5ec1e72Spatrick .bc_setup = NULL, 305e5ec1e72Spatrick .bc_activate = bwfm_pci_buscore_activate, 306e5ec1e72Spatrick }; 307e5ec1e72Spatrick 308e5ec1e72Spatrick struct bwfm_bus_ops bwfm_pci_bus_ops = { 309972218f3Spatrick .bs_preinit = bwfm_pci_preinit, 310a2c6ff8bSpatrick .bs_stop = bwfm_pci_stop, 31102ee7d07Spatrick .bs_txcheck = bwfm_pci_txcheck, 312e5ec1e72Spatrick .bs_txdata = bwfm_pci_txdata, 313e5ec1e72Spatrick .bs_txctl = NULL, 314e5ec1e72Spatrick }; 315e5ec1e72Spatrick 316e5ec1e72Spatrick struct bwfm_proto_ops bwfm_pci_msgbuf_ops = { 317e5ec1e72Spatrick .proto_query_dcmd = bwfm_pci_msgbuf_query_dcmd, 318e5ec1e72Spatrick .proto_set_dcmd = bwfm_pci_msgbuf_set_dcmd, 31914c74651Spatrick .proto_rx = NULL, 320029d6dd5Spatrick .proto_rxctl = NULL, 321e5ec1e72Spatrick }; 322e5ec1e72Spatrick 323e5ec1e72Spatrick struct cfattach bwfm_pci_ca = { 324e5ec1e72Spatrick sizeof(struct bwfm_pci_softc), 325e5ec1e72Spatrick bwfm_pci_match, 326e5ec1e72Spatrick bwfm_pci_attach, 327e5ec1e72Spatrick bwfm_pci_detach, 328e5ec1e72Spatrick }; 329e5ec1e72Spatrick 330e5ec1e72Spatrick static const struct pci_matchid bwfm_pci_devices[] = { 33182f0e660Sjcs { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4350 }, 33241d93ac2Spatrick { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4356 }, 33341d93ac2Spatrick { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43602 }, 334821fc986Spatrick { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4371 }, 3358e234c40Spatrick { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4378 }, 336e5ec1e72Spatrick }; 337e5ec1e72Spatrick 338e5ec1e72Spatrick int 339e5ec1e72Spatrick bwfm_pci_match(struct device *parent, void *match, void *aux) 340e5ec1e72Spatrick { 341e5ec1e72Spatrick return (pci_matchbyid(aux, bwfm_pci_devices, 342e5ec1e72Spatrick nitems(bwfm_pci_devices))); 343e5ec1e72Spatrick } 344e5ec1e72Spatrick 345e5ec1e72Spatrick void 346e5ec1e72Spatrick bwfm_pci_attach(struct device *parent, struct device *self, void *aux) 347e5ec1e72Spatrick { 348e5ec1e72Spatrick struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self; 349e5ec1e72Spatrick struct pci_attach_args *pa = (struct pci_attach_args *)aux; 350e5ec1e72Spatrick const char *intrstr; 351e5ec1e72Spatrick pci_intr_handle_t ih; 352e5ec1e72Spatrick 353e5ec1e72Spatrick if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x08, 354e5ec1e72Spatrick PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_tcm_iot, &sc->sc_tcm_ioh, 355e5ec1e72Spatrick NULL, &sc->sc_tcm_ios, 0)) { 356e5ec1e72Spatrick printf(": can't map bar1\n"); 357a08e9144Spatrick return; 358a08e9144Spatrick } 359a08e9144Spatrick 360a08e9144Spatrick if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x00, 361a08e9144Spatrick PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_reg_iot, &sc->sc_reg_ioh, 362a08e9144Spatrick NULL, &sc->sc_reg_ios, 0)) { 363a08e9144Spatrick printf(": can't map bar0\n"); 364a08e9144Spatrick goto bar1; 365e5ec1e72Spatrick } 366e5ec1e72Spatrick 367e5ec1e72Spatrick sc->sc_pc = pa->pa_pc; 368e5ec1e72Spatrick sc->sc_tag = pa->pa_tag; 369e5ec1e72Spatrick sc->sc_id = pa->pa_id; 370e5ec1e72Spatrick sc->sc_dmat = pa->pa_dmat; 371e5ec1e72Spatrick 372e5ec1e72Spatrick /* Map and establish the interrupt. */ 373e5ec1e72Spatrick if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) { 374e5ec1e72Spatrick printf(": couldn't map interrupt\n"); 375a08e9144Spatrick goto bar0; 376e5ec1e72Spatrick } 377e5ec1e72Spatrick intrstr = pci_intr_string(pa->pa_pc, ih); 378e5ec1e72Spatrick 37914484acaSpatrick sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET, 380e5ec1e72Spatrick bwfm_pci_intr, sc, DEVNAME(sc)); 381e5ec1e72Spatrick if (sc->sc_ih == NULL) { 382e5ec1e72Spatrick printf(": couldn't establish interrupt"); 383e5ec1e72Spatrick if (intrstr != NULL) 384e5ec1e72Spatrick printf(" at %s", intrstr); 385e5ec1e72Spatrick printf("\n"); 386e5ec1e72Spatrick goto bar1; 387e5ec1e72Spatrick } 388e5ec1e72Spatrick printf(": %s\n", intrstr); 389e5ec1e72Spatrick 390972218f3Spatrick sc->sc_sc.sc_bus_ops = &bwfm_pci_bus_ops; 391972218f3Spatrick sc->sc_sc.sc_proto_ops = &bwfm_pci_msgbuf_ops; 392972218f3Spatrick bwfm_attach(&sc->sc_sc); 393972218f3Spatrick config_mountroot(self, bwfm_attachhook); 394e5ec1e72Spatrick return; 395e5ec1e72Spatrick 396e5ec1e72Spatrick bar0: 397e5ec1e72Spatrick bus_space_unmap(sc->sc_reg_iot, sc->sc_reg_ioh, sc->sc_reg_ios); 398a08e9144Spatrick bar1: 399a08e9144Spatrick bus_space_unmap(sc->sc_tcm_iot, sc->sc_tcm_ioh, sc->sc_tcm_ios); 400e5ec1e72Spatrick } 401e5ec1e72Spatrick 402972218f3Spatrick int 403972218f3Spatrick bwfm_pci_preinit(struct bwfm_softc *bwfm) 404e5ec1e72Spatrick { 405972218f3Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 406e5ec1e72Spatrick struct bwfm_pci_ringinfo ringinfo; 4079ead8393Spatrick const char *chip = NULL; 40894e4747cSpatrick u_char *ucode, *nvram; 40994e4747cSpatrick size_t size, nvsize, nvlen; 410e5ec1e72Spatrick uint32_t d2h_w_idx_ptr, d2h_r_idx_ptr; 411e5ec1e72Spatrick uint32_t h2d_w_idx_ptr, h2d_r_idx_ptr; 412e5ec1e72Spatrick uint32_t idx_offset, reg; 413e5ec1e72Spatrick int i; 414e5ec1e72Spatrick 415972218f3Spatrick if (sc->sc_initialized) 416972218f3Spatrick return 0; 417972218f3Spatrick 418e5ec1e72Spatrick sc->sc_sc.sc_buscore_ops = &bwfm_pci_buscore_ops; 419e5ec1e72Spatrick if (bwfm_chip_attach(&sc->sc_sc) != 0) { 420e5ec1e72Spatrick printf("%s: cannot attach chip\n", DEVNAME(sc)); 421972218f3Spatrick return 1; 422e5ec1e72Spatrick } 423e5ec1e72Spatrick 424ed6d4272Spatrick #if defined(__HAVE_FDT) 425ed6d4272Spatrick if (bwfm_pci_read_otp(sc)) { 426ed6d4272Spatrick printf("%s: cannot read OTP\n", DEVNAME(sc)); 427ed6d4272Spatrick return 1; 428ed6d4272Spatrick } 429ed6d4272Spatrick #endif 430ed6d4272Spatrick 431e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2); 432e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 433e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGADDR, 0x4e0); 434e5ec1e72Spatrick reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 435e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA); 436e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 437e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA, reg); 438e5ec1e72Spatrick 439e5ec1e72Spatrick switch (bwfm->sc_chip.ch_chip) 440e5ec1e72Spatrick { 44118b3a1dcSpatrick case BRCM_CC_4350_CHIP_ID: 4429ead8393Spatrick if (bwfm->sc_chip.ch_chiprev > 7) 4439ead8393Spatrick chip = "4350"; 4449ead8393Spatrick else 4459ead8393Spatrick chip = "4350c2"; 44618b3a1dcSpatrick break; 44741d93ac2Spatrick case BRCM_CC_4356_CHIP_ID: 4489ead8393Spatrick chip = "4356"; 44941d93ac2Spatrick break; 450e5ec1e72Spatrick case BRCM_CC_43602_CHIP_ID: 4519ead8393Spatrick chip = "43602"; 452e5ec1e72Spatrick break; 453821fc986Spatrick case BRCM_CC_4371_CHIP_ID: 4549ead8393Spatrick chip = "4371"; 455821fc986Spatrick break; 456c38a9bc9Spatrick case BRCM_CC_4378_CHIP_ID: 457c38a9bc9Spatrick chip = "4378"; 458c38a9bc9Spatrick break; 459e5ec1e72Spatrick default: 46018b3a1dcSpatrick printf("%s: unknown firmware for chip %s\n", 46118b3a1dcSpatrick DEVNAME(sc), bwfm->sc_chip.ch_name); 462972218f3Spatrick return 1; 463e5ec1e72Spatrick } 464e5ec1e72Spatrick 46594e4747cSpatrick if (bwfm_loadfirmware(bwfm, chip, "-pcie", &ucode, &size, 46694e4747cSpatrick &nvram, &nvsize, &nvlen) != 0) 467972218f3Spatrick return 1; 4686aad491fSpatrick 469e5ec1e72Spatrick /* Retrieve RAM size from firmware. */ 470e5ec1e72Spatrick if (size >= BWFM_RAMSIZE + 8) { 471e5ec1e72Spatrick uint32_t *ramsize = (uint32_t *)&ucode[BWFM_RAMSIZE]; 472e5ec1e72Spatrick if (letoh32(ramsize[0]) == BWFM_RAMSIZE_MAGIC) 473e5ec1e72Spatrick bwfm->sc_chip.ch_ramsize = letoh32(ramsize[1]); 474e5ec1e72Spatrick } 475e5ec1e72Spatrick 4766aad491fSpatrick if (bwfm_pci_load_microcode(sc, ucode, size, nvram, nvlen) != 0) { 477e5ec1e72Spatrick printf("%s: could not load microcode\n", 478e5ec1e72Spatrick DEVNAME(sc)); 479e5ec1e72Spatrick free(ucode, M_DEVBUF, size); 480b4e85b06Spatrick free(nvram, M_DEVBUF, nvsize); 481972218f3Spatrick return 1; 482e5ec1e72Spatrick } 483e5ec1e72Spatrick free(ucode, M_DEVBUF, size); 484b4e85b06Spatrick free(nvram, M_DEVBUF, nvsize); 485e5ec1e72Spatrick 486e5ec1e72Spatrick sc->sc_shared_flags = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 487e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_INFO); 488e5ec1e72Spatrick sc->sc_shared_version = sc->sc_shared_flags; 489e5ec1e72Spatrick if (sc->sc_shared_version > BWFM_SHARED_INFO_MAX_VERSION || 490e5ec1e72Spatrick sc->sc_shared_version < BWFM_SHARED_INFO_MIN_VERSION) { 491e5ec1e72Spatrick printf("%s: PCIe version %d unsupported\n", 492e5ec1e72Spatrick DEVNAME(sc), sc->sc_shared_version); 493972218f3Spatrick return 1; 494e5ec1e72Spatrick } 495e5ec1e72Spatrick 496e5ec1e72Spatrick if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_INDEX) { 497e5ec1e72Spatrick if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_2B_IDX) 498e5ec1e72Spatrick sc->sc_dma_idx_sz = sizeof(uint16_t); 499e5ec1e72Spatrick else 500e5ec1e72Spatrick sc->sc_dma_idx_sz = sizeof(uint32_t); 501e5ec1e72Spatrick } 502e5ec1e72Spatrick 503e5ec1e72Spatrick /* Maximum RX data buffers in the ring. */ 504e5ec1e72Spatrick sc->sc_max_rxbufpost = bus_space_read_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 505e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_MAX_RXBUFPOST); 506e5ec1e72Spatrick if (sc->sc_max_rxbufpost == 0) 507e5ec1e72Spatrick sc->sc_max_rxbufpost = BWFM_SHARED_MAX_RXBUFPOST_DEFAULT; 508e5ec1e72Spatrick 509e5ec1e72Spatrick /* Alternative offset of data in a packet */ 510e5ec1e72Spatrick sc->sc_rx_dataoffset = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 511e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_RX_DATAOFFSET); 512e5ec1e72Spatrick 513e5ec1e72Spatrick /* For Power Management */ 514e5ec1e72Spatrick sc->sc_htod_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 515e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_HTOD_MB_DATA_ADDR); 516e5ec1e72Spatrick sc->sc_dtoh_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 517e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DTOH_MB_DATA_ADDR); 518e5ec1e72Spatrick 519e5ec1e72Spatrick /* Ring information */ 520e5ec1e72Spatrick sc->sc_ring_info_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 521e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_RING_INFO_ADDR); 522e5ec1e72Spatrick 523e5ec1e72Spatrick /* Firmware's "dmesg" */ 524e5ec1e72Spatrick sc->sc_console_base_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 525e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_CONSOLE_ADDR); 526e5ec1e72Spatrick sc->sc_console_buf_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 527e5ec1e72Spatrick sc->sc_console_base_addr + BWFM_CONSOLE_BUFADDR); 528e5ec1e72Spatrick sc->sc_console_buf_size = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 529e5ec1e72Spatrick sc->sc_console_base_addr + BWFM_CONSOLE_BUFSIZE); 530e5ec1e72Spatrick 531e5ec1e72Spatrick /* Read ring information. */ 532e5ec1e72Spatrick bus_space_read_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 533e5ec1e72Spatrick sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo)); 534e5ec1e72Spatrick 535e5ec1e72Spatrick if (sc->sc_shared_version >= 6) { 536e5ec1e72Spatrick sc->sc_max_submissionrings = le16toh(ringinfo.max_submissionrings); 537e5ec1e72Spatrick sc->sc_max_flowrings = le16toh(ringinfo.max_flowrings); 538e5ec1e72Spatrick sc->sc_max_completionrings = le16toh(ringinfo.max_completionrings); 539e5ec1e72Spatrick } else { 540e5ec1e72Spatrick sc->sc_max_submissionrings = le16toh(ringinfo.max_flowrings); 541e5ec1e72Spatrick sc->sc_max_flowrings = sc->sc_max_submissionrings - 542e5ec1e72Spatrick BWFM_NUM_TX_MSGRINGS; 543e5ec1e72Spatrick sc->sc_max_completionrings = BWFM_NUM_RX_MSGRINGS; 544e5ec1e72Spatrick } 545e5ec1e72Spatrick 546e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 547e5ec1e72Spatrick d2h_w_idx_ptr = letoh32(ringinfo.d2h_w_idx_ptr); 548e5ec1e72Spatrick d2h_r_idx_ptr = letoh32(ringinfo.d2h_r_idx_ptr); 549e5ec1e72Spatrick h2d_w_idx_ptr = letoh32(ringinfo.h2d_w_idx_ptr); 550e5ec1e72Spatrick h2d_r_idx_ptr = letoh32(ringinfo.h2d_r_idx_ptr); 551e5ec1e72Spatrick idx_offset = sizeof(uint32_t); 552e5ec1e72Spatrick } else { 553e5ec1e72Spatrick uint64_t address; 554e5ec1e72Spatrick 555e5ec1e72Spatrick /* Each TX/RX Ring has a Read and Write Ptr */ 556e5ec1e72Spatrick sc->sc_dma_idx_bufsz = (sc->sc_max_submissionrings + 557e5ec1e72Spatrick sc->sc_max_completionrings) * sc->sc_dma_idx_sz * 2; 558e5ec1e72Spatrick sc->sc_dma_idx_buf = bwfm_pci_dmamem_alloc(sc, 559e5ec1e72Spatrick sc->sc_dma_idx_bufsz, 8); 560e5ec1e72Spatrick if (sc->sc_dma_idx_buf == NULL) { 561e5ec1e72Spatrick /* XXX: Fallback to TCM? */ 562e5ec1e72Spatrick printf("%s: cannot allocate idx buf\n", 563e5ec1e72Spatrick DEVNAME(sc)); 564972218f3Spatrick return 1; 565e5ec1e72Spatrick } 566e5ec1e72Spatrick 567e5ec1e72Spatrick idx_offset = sc->sc_dma_idx_sz; 568e5ec1e72Spatrick h2d_w_idx_ptr = 0; 569e5ec1e72Spatrick address = BWFM_PCI_DMA_DVA(sc->sc_dma_idx_buf); 570e5ec1e72Spatrick ringinfo.h2d_w_idx_hostaddr_low = 571e5ec1e72Spatrick htole32(address & 0xffffffff); 572e5ec1e72Spatrick ringinfo.h2d_w_idx_hostaddr_high = 573e5ec1e72Spatrick htole32(address >> 32); 574e5ec1e72Spatrick 575e5ec1e72Spatrick h2d_r_idx_ptr = h2d_w_idx_ptr + 576e5ec1e72Spatrick sc->sc_max_submissionrings * idx_offset; 577e5ec1e72Spatrick address += sc->sc_max_submissionrings * idx_offset; 578e5ec1e72Spatrick ringinfo.h2d_r_idx_hostaddr_low = 579e5ec1e72Spatrick htole32(address & 0xffffffff); 580e5ec1e72Spatrick ringinfo.h2d_r_idx_hostaddr_high = 581e5ec1e72Spatrick htole32(address >> 32); 582e5ec1e72Spatrick 583e5ec1e72Spatrick d2h_w_idx_ptr = h2d_r_idx_ptr + 584e5ec1e72Spatrick sc->sc_max_submissionrings * idx_offset; 585e5ec1e72Spatrick address += sc->sc_max_submissionrings * idx_offset; 586e5ec1e72Spatrick ringinfo.d2h_w_idx_hostaddr_low = 587e5ec1e72Spatrick htole32(address & 0xffffffff); 588e5ec1e72Spatrick ringinfo.d2h_w_idx_hostaddr_high = 589e5ec1e72Spatrick htole32(address >> 32); 590e5ec1e72Spatrick 591e5ec1e72Spatrick d2h_r_idx_ptr = d2h_w_idx_ptr + 592e5ec1e72Spatrick sc->sc_max_completionrings * idx_offset; 593e5ec1e72Spatrick address += sc->sc_max_completionrings * idx_offset; 594e5ec1e72Spatrick ringinfo.d2h_r_idx_hostaddr_low = 595e5ec1e72Spatrick htole32(address & 0xffffffff); 596e5ec1e72Spatrick ringinfo.d2h_r_idx_hostaddr_high = 597e5ec1e72Spatrick htole32(address >> 32); 598e5ec1e72Spatrick 599e5ec1e72Spatrick bus_space_write_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 600e5ec1e72Spatrick sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo)); 601e5ec1e72Spatrick } 602e5ec1e72Spatrick 603e5ec1e72Spatrick uint32_t ring_mem_ptr = letoh32(ringinfo.ringmem); 604e5ec1e72Spatrick /* TX ctrl ring: Send ctrl buffers, send IOCTLs */ 605e5ec1e72Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_submit, 64, 40, 606e5ec1e72Spatrick h2d_w_idx_ptr, h2d_r_idx_ptr, 0, idx_offset, 607e5ec1e72Spatrick &ring_mem_ptr)) 608e5ec1e72Spatrick goto cleanup; 609e5ec1e72Spatrick /* TX rxpost ring: Send clean data mbufs for RX */ 610e5ec1e72Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_rxpost_submit, 512, 32, 611e5ec1e72Spatrick h2d_w_idx_ptr, h2d_r_idx_ptr, 1, idx_offset, 612e5ec1e72Spatrick &ring_mem_ptr)) 613e5ec1e72Spatrick goto cleanup; 614e5ec1e72Spatrick /* RX completion rings: recv our filled buffers back */ 615e5ec1e72Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_complete, 64, 24, 616e5ec1e72Spatrick d2h_w_idx_ptr, d2h_r_idx_ptr, 0, idx_offset, 617e5ec1e72Spatrick &ring_mem_ptr)) 618e5ec1e72Spatrick goto cleanup; 619095b0c44Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_tx_complete, 1024, 620095b0c44Spatrick sc->sc_shared_version >= 7 ? 24 : 16, 621e5ec1e72Spatrick d2h_w_idx_ptr, d2h_r_idx_ptr, 1, idx_offset, 622e5ec1e72Spatrick &ring_mem_ptr)) 623e5ec1e72Spatrick goto cleanup; 624095b0c44Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_rx_complete, 512, 625095b0c44Spatrick sc->sc_shared_version >= 7 ? 40 : 32, 626e5ec1e72Spatrick d2h_w_idx_ptr, d2h_r_idx_ptr, 2, idx_offset, 627e5ec1e72Spatrick &ring_mem_ptr)) 628e5ec1e72Spatrick goto cleanup; 629e5ec1e72Spatrick 630e5ec1e72Spatrick /* Dynamic TX rings for actual data */ 631e5ec1e72Spatrick sc->sc_flowrings = malloc(sc->sc_max_flowrings * 632e5ec1e72Spatrick sizeof(struct bwfm_pci_msgring), M_DEVBUF, M_WAITOK | M_ZERO); 633518be5f3Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 634518be5f3Spatrick struct bwfm_pci_msgring *ring = &sc->sc_flowrings[i]; 635518be5f3Spatrick ring->w_idx_addr = h2d_w_idx_ptr + (i + 2) * idx_offset; 636518be5f3Spatrick ring->r_idx_addr = h2d_r_idx_ptr + (i + 2) * idx_offset; 637518be5f3Spatrick } 638e5ec1e72Spatrick 639e5ec1e72Spatrick /* Scratch and ring update buffers for firmware */ 640e5ec1e72Spatrick if ((sc->sc_scratch_buf = bwfm_pci_dmamem_alloc(sc, 641e5ec1e72Spatrick BWFM_DMA_D2H_SCRATCH_BUF_LEN, 8)) == NULL) 642e5ec1e72Spatrick goto cleanup; 643e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 644e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_LOW, 645e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) & 0xffffffff); 646e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 647e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_HIGH, 648e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) >> 32); 649e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 650e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_LEN, 651e5ec1e72Spatrick BWFM_DMA_D2H_SCRATCH_BUF_LEN); 652e5ec1e72Spatrick 653e5ec1e72Spatrick if ((sc->sc_ringupd_buf = bwfm_pci_dmamem_alloc(sc, 654e5ec1e72Spatrick BWFM_DMA_D2H_RINGUPD_BUF_LEN, 8)) == NULL) 655e5ec1e72Spatrick goto cleanup; 656e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 657e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_LOW, 658e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) & 0xffffffff); 659e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 660e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_HIGH, 661e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) >> 32); 662e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 663e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_LEN, 664e5ec1e72Spatrick BWFM_DMA_D2H_RINGUPD_BUF_LEN); 665e5ec1e72Spatrick 666e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2); 667e5ec1e72Spatrick bwfm_pci_intr_enable(sc); 668156d2677Spatrick bwfm_pci_hostready(sc); 669e5ec1e72Spatrick 670e5ec1e72Spatrick /* Maps RX mbufs to a packet id and back. */ 671e5ec1e72Spatrick sc->sc_rx_pkts.npkt = BWFM_NUM_RX_PKTIDS; 672e5ec1e72Spatrick sc->sc_rx_pkts.pkts = malloc(BWFM_NUM_RX_PKTIDS * 673e5ec1e72Spatrick sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO); 674e5ec1e72Spatrick for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++) 6751950c5c5Spatrick bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_CTL_PKT_SIZE, 6761950c5c5Spatrick BWFM_NUM_RX_DESCS, MSGBUF_MAX_CTL_PKT_SIZE, 0, BUS_DMA_WAITOK, 677e5ec1e72Spatrick &sc->sc_rx_pkts.pkts[i].bb_map); 678e5ec1e72Spatrick 679e5ec1e72Spatrick /* Maps TX mbufs to a packet id and back. */ 680f416501bSpatrick sc->sc_tx_pkts.npkt = BWFM_NUM_TX_PKTIDS; 681e5ec1e72Spatrick sc->sc_tx_pkts.pkts = malloc(BWFM_NUM_TX_PKTIDS 682e5ec1e72Spatrick * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO); 683e5ec1e72Spatrick for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++) 684e5ec1e72Spatrick bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE, 685e5ec1e72Spatrick BWFM_NUM_TX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK, 686e5ec1e72Spatrick &sc->sc_tx_pkts.pkts[i].bb_map); 687e5ec1e72Spatrick 6882eeba925Spatrick /* Maps IOCTL mbufs to a packet id and back. */ 6892eeba925Spatrick sc->sc_ioctl_pkts.npkt = BWFM_NUM_IOCTL_PKTIDS; 6902eeba925Spatrick sc->sc_ioctl_pkts.pkts = malloc(BWFM_NUM_IOCTL_PKTIDS 6912eeba925Spatrick * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO); 6922eeba925Spatrick for (i = 0; i < BWFM_NUM_IOCTL_PKTIDS; i++) 6932eeba925Spatrick bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE, 6942eeba925Spatrick BWFM_NUM_IOCTL_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK, 6952eeba925Spatrick &sc->sc_ioctl_pkts.pkts[i].bb_map); 6962eeba925Spatrick 69718722113Spatrick /* 69818722113Spatrick * For whatever reason, could also be a bug somewhere in this 69918722113Spatrick * driver, the firmware needs a bunch of RX buffers otherwise 7004ef2dd0fSpatrick * it won't send any RX complete messages. 70118722113Spatrick */ 7024ef2dd0fSpatrick if_rxr_init(&sc->sc_rxbuf_ring, min(256, sc->sc_max_rxbufpost), 7034ef2dd0fSpatrick sc->sc_max_rxbufpost); 704e5ec1e72Spatrick if_rxr_init(&sc->sc_ioctl_ring, 8, 8); 705e5ec1e72Spatrick if_rxr_init(&sc->sc_event_ring, 8, 8); 706e5ec1e72Spatrick bwfm_pci_fill_rx_rings(sc); 707e5ec1e72Spatrick 7082eeba925Spatrick TAILQ_INIT(&sc->sc_ioctlq); 7092eeba925Spatrick 710cadf5fcfSpatrick #ifdef BWFM_DEBUG 711cadf5fcfSpatrick sc->sc_console_readidx = 0; 712cadf5fcfSpatrick bwfm_pci_debug_console(sc); 713cadf5fcfSpatrick #endif 714cadf5fcfSpatrick 715972218f3Spatrick sc->sc_initialized = 1; 716972218f3Spatrick return 0; 717e5ec1e72Spatrick 718e5ec1e72Spatrick cleanup: 719e5ec1e72Spatrick if (sc->sc_ringupd_buf) 720e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf); 721e5ec1e72Spatrick if (sc->sc_scratch_buf) 722e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf); 723e5ec1e72Spatrick if (sc->sc_rx_complete.ring) 724e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring); 725e5ec1e72Spatrick if (sc->sc_tx_complete.ring) 726e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring); 727e5ec1e72Spatrick if (sc->sc_ctrl_complete.ring) 728e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring); 729e5ec1e72Spatrick if (sc->sc_rxpost_submit.ring) 730e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring); 731e5ec1e72Spatrick if (sc->sc_ctrl_submit.ring) 732e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring); 733e5ec1e72Spatrick if (sc->sc_dma_idx_buf) 734e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf); 735972218f3Spatrick return 1; 736e5ec1e72Spatrick } 737e5ec1e72Spatrick 738e5ec1e72Spatrick int 7396aad491fSpatrick bwfm_pci_load_microcode(struct bwfm_pci_softc *sc, const u_char *ucode, size_t size, 7406aad491fSpatrick const u_char *nvram, size_t nvlen) 741e5ec1e72Spatrick { 742e5ec1e72Spatrick struct bwfm_softc *bwfm = (void *)sc; 743e5ec1e72Spatrick struct bwfm_core *core; 7446aad491fSpatrick uint32_t shared, written; 745e5ec1e72Spatrick int i; 746e5ec1e72Spatrick 747e5ec1e72Spatrick if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) { 748e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_ARM_CR4); 749e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 750e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKIDX, 5); 751e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 752e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKPDA, 0); 753e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 754e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKIDX, 7); 755e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 756e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKPDA, 0); 757e5ec1e72Spatrick } 758e5ec1e72Spatrick 759e5ec1e72Spatrick for (i = 0; i < size; i++) 760e5ec1e72Spatrick bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 761e5ec1e72Spatrick bwfm->sc_chip.ch_rambase + i, ucode[i]); 762e5ec1e72Spatrick 763e5ec1e72Spatrick /* Firmware replaces this with a pointer once up. */ 764e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 765e5ec1e72Spatrick bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4, 0); 766e5ec1e72Spatrick 7676aad491fSpatrick if (nvram) { 7686aad491fSpatrick for (i = 0; i < nvlen; i++) 7696aad491fSpatrick bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 7706aad491fSpatrick bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize 7716aad491fSpatrick - nvlen + i, nvram[i]); 7726aad491fSpatrick } 7736aad491fSpatrick 7746aad491fSpatrick written = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 7756aad491fSpatrick bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4); 776e5ec1e72Spatrick 777e5ec1e72Spatrick /* Load reset vector from firmware and kickstart core. */ 778b0cd4990Spatrick if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) { 779e5ec1e72Spatrick core = bwfm_chip_get_core(bwfm, BWFM_AGENT_INTERNAL_MEM); 780e5ec1e72Spatrick bwfm->sc_chip.ch_core_reset(bwfm, core, 0, 0, 0); 781b0cd4990Spatrick } 782e5ec1e72Spatrick bwfm_chip_set_active(bwfm, *(uint32_t *)ucode); 783e5ec1e72Spatrick 7843c53ddefSpatrick for (i = 0; i < 100; i++) { 785e5ec1e72Spatrick delay(50 * 1000); 786e5ec1e72Spatrick shared = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 787e5ec1e72Spatrick bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4); 7886aad491fSpatrick if (shared != written) 789e5ec1e72Spatrick break; 790e5ec1e72Spatrick } 79119871452Spatrick if (shared == written) { 792e5ec1e72Spatrick printf("%s: firmware did not come up\n", DEVNAME(sc)); 793e5ec1e72Spatrick return 1; 794e5ec1e72Spatrick } 79519871452Spatrick if (shared < bwfm->sc_chip.ch_rambase || 79619871452Spatrick shared >= bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize) { 79719871452Spatrick printf("%s: invalid shared RAM address 0x%08x\n", DEVNAME(sc), 79819871452Spatrick shared); 79919871452Spatrick return 1; 80019871452Spatrick } 801e5ec1e72Spatrick 802e5ec1e72Spatrick sc->sc_shared_address = shared; 803e5ec1e72Spatrick return 0; 804e5ec1e72Spatrick } 805e5ec1e72Spatrick 806e5ec1e72Spatrick int 807e5ec1e72Spatrick bwfm_pci_detach(struct device *self, int flags) 808e5ec1e72Spatrick { 809e5ec1e72Spatrick struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self; 810e5ec1e72Spatrick 811e5ec1e72Spatrick bwfm_detach(&sc->sc_sc, flags); 812e5ec1e72Spatrick 813e5ec1e72Spatrick /* FIXME: free RX buffers */ 814e5ec1e72Spatrick /* FIXME: free TX buffers */ 815e5ec1e72Spatrick /* FIXME: free more memory */ 816e5ec1e72Spatrick 817e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf); 818e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf); 819e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring); 820e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring); 821e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring); 822e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring); 823e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring); 824e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf); 825e5ec1e72Spatrick return 0; 826e5ec1e72Spatrick } 827e5ec1e72Spatrick 828ed6d4272Spatrick #if defined(__HAVE_FDT) 829ed6d4272Spatrick int 830ed6d4272Spatrick bwfm_pci_read_otp(struct bwfm_pci_softc *sc) 831ed6d4272Spatrick { 832ed6d4272Spatrick struct bwfm_softc *bwfm = (void *)sc; 833ed6d4272Spatrick struct bwfm_core *core; 834ed6d4272Spatrick uint8_t otp[BWFM_OTP_SIZE]; 835ed6d4272Spatrick int i; 836ed6d4272Spatrick 837ed6d4272Spatrick if (bwfm->sc_chip.ch_chip != BRCM_CC_4378_CHIP_ID) 838ed6d4272Spatrick return 0; 839ed6d4272Spatrick 840ed6d4272Spatrick core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_GCI); 841ed6d4272Spatrick if (core == NULL) 842ed6d4272Spatrick return 1; 843ed6d4272Spatrick 844ed6d4272Spatrick for (i = 0; i < (sizeof(otp) / sizeof(uint32_t)); i++) 845ed6d4272Spatrick ((uint32_t *)otp)[i] = bwfm_pci_buscore_read(bwfm, 846ed6d4272Spatrick core->co_base + BWFM_OTP_4378_BASE + i * sizeof(uint32_t)); 847ed6d4272Spatrick 848ed6d4272Spatrick for (i = 0; i < BWFM_OTP_SIZE - 1; ) { 849ed6d4272Spatrick if (otp[i + 0] == 0) { 850ed6d4272Spatrick i++; 851ed6d4272Spatrick continue; 852ed6d4272Spatrick } 853ed6d4272Spatrick if (i + otp[i + 1] > BWFM_OTP_SIZE) 854ed6d4272Spatrick break; 855ed6d4272Spatrick bwfm_pci_process_otp_tuple(sc, otp[i + 0], otp[i + 1], 856ed6d4272Spatrick &otp[i + 2]); 857ed6d4272Spatrick i += otp[i + 1]; 858ed6d4272Spatrick } 859ed6d4272Spatrick 860ed6d4272Spatrick return 0; 861ed6d4272Spatrick } 862ed6d4272Spatrick 863ed6d4272Spatrick void 864ed6d4272Spatrick bwfm_pci_process_otp_tuple(struct bwfm_pci_softc *sc, uint8_t type, uint8_t size, 865ed6d4272Spatrick uint8_t *data) 866ed6d4272Spatrick { 867ed6d4272Spatrick struct bwfm_softc *bwfm = (void *)sc; 868ed6d4272Spatrick char chiprev[8] = "", module[8] = "", modrev[8] = "", vendor[8] = "", chip[8] = ""; 869ed6d4272Spatrick char product[16] = "unknown"; 870ed6d4272Spatrick int node, len; 871ed6d4272Spatrick 872ed6d4272Spatrick switch (type) { 873ed6d4272Spatrick case 0x15: /* system vendor OTP */ 874ed6d4272Spatrick DPRINTF(("%s: system vendor OTP\n", DEVNAME(sc))); 875ed6d4272Spatrick if (size < sizeof(uint32_t)) 876ed6d4272Spatrick return; 877ed6d4272Spatrick if (data[0] != 0x08 || data[1] != 0x00 || 878ed6d4272Spatrick data[2] != 0x00 || data[3] != 0x00) 879ed6d4272Spatrick return; 880ed6d4272Spatrick size -= sizeof(uint32_t); 881ed6d4272Spatrick data += sizeof(uint32_t); 882ed6d4272Spatrick while (size) { 883ed6d4272Spatrick /* reached end */ 884ed6d4272Spatrick if (data[0] == 0xff) 885ed6d4272Spatrick break; 886ed6d4272Spatrick for (len = 0; len < size; len++) 887ed6d4272Spatrick if (data[len] == 0x00 || data[len] == ' ' || 888ed6d4272Spatrick data[len] == 0xff) 889ed6d4272Spatrick break; 890ed6d4272Spatrick if (len < 3 || len > 9) /* X=abcdef */ 891ed6d4272Spatrick goto next; 892ed6d4272Spatrick if (data[1] != '=') 893ed6d4272Spatrick goto next; 894ed6d4272Spatrick /* NULL-terminate string */ 895ed6d4272Spatrick if (data[len] == ' ') 896ed6d4272Spatrick data[len] = '\0'; 897ed6d4272Spatrick switch (data[0]) { 898ed6d4272Spatrick case 's': 899ed6d4272Spatrick strlcpy(chiprev, &data[2], sizeof(chiprev)); 900ed6d4272Spatrick break; 901ed6d4272Spatrick case 'M': 902ed6d4272Spatrick strlcpy(module, &data[2], sizeof(module)); 903ed6d4272Spatrick break; 904ed6d4272Spatrick case 'm': 905ed6d4272Spatrick strlcpy(modrev, &data[2], sizeof(modrev)); 906ed6d4272Spatrick break; 907ed6d4272Spatrick case 'V': 908ed6d4272Spatrick strlcpy(vendor, &data[2], sizeof(vendor)); 909ed6d4272Spatrick break; 910ed6d4272Spatrick } 911ed6d4272Spatrick next: 912ed6d4272Spatrick /* skip content */ 913ed6d4272Spatrick data += len; 914ed6d4272Spatrick size -= len; 915ed6d4272Spatrick /* skip spacer tag */ 916ed6d4272Spatrick if (size) { 917ed6d4272Spatrick data++; 918ed6d4272Spatrick size--; 919ed6d4272Spatrick } 920ed6d4272Spatrick } 921ed6d4272Spatrick snprintf(chip, sizeof(chip), 922ed6d4272Spatrick bwfm->sc_chip.ch_chip > 40000 ? "%05d" : "%04x", 923ed6d4272Spatrick bwfm->sc_chip.ch_chip); 924ed6d4272Spatrick node = OF_finddevice("/chosen"); 925ed6d4272Spatrick if (node != -1) 926ed6d4272Spatrick OF_getprop(node, "module-wlan0", product, sizeof(product)); 927ed6d4272Spatrick printf("%s: firmware C-%s%s%s/P-%s_M-%s_V-%s__m-%s\n", 928ed6d4272Spatrick DEVNAME(sc), chip, 929ed6d4272Spatrick *chiprev ? "__s-" : "", *chiprev ? chiprev : "", 930ed6d4272Spatrick product, module, vendor, modrev); 931ed6d4272Spatrick break; 932ed6d4272Spatrick case 0x80: /* Broadcom CIS */ 933ed6d4272Spatrick DPRINTF(("%s: Broadcom CIS\n", DEVNAME(sc))); 934ed6d4272Spatrick break; 935ed6d4272Spatrick default: 936ed6d4272Spatrick DPRINTF(("%s: unknown OTP tuple\n", DEVNAME(sc))); 937ed6d4272Spatrick break; 938ed6d4272Spatrick } 939ed6d4272Spatrick } 940ed6d4272Spatrick #endif 941ed6d4272Spatrick 942e5ec1e72Spatrick /* DMA code */ 943e5ec1e72Spatrick struct bwfm_pci_dmamem * 944e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *sc, bus_size_t size, bus_size_t align) 945e5ec1e72Spatrick { 946e5ec1e72Spatrick struct bwfm_pci_dmamem *bdm; 947e5ec1e72Spatrick int nsegs; 948e5ec1e72Spatrick 949e5ec1e72Spatrick bdm = malloc(sizeof(*bdm), M_DEVBUF, M_WAITOK | M_ZERO); 950e5ec1e72Spatrick bdm->bdm_size = size; 951e5ec1e72Spatrick 952e5ec1e72Spatrick if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 953e5ec1e72Spatrick BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &bdm->bdm_map) != 0) 954e5ec1e72Spatrick goto bdmfree; 955e5ec1e72Spatrick 956e5ec1e72Spatrick if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &bdm->bdm_seg, 1, 957e5ec1e72Spatrick &nsegs, BUS_DMA_WAITOK) != 0) 958e5ec1e72Spatrick goto destroy; 959e5ec1e72Spatrick 960e5ec1e72Spatrick if (bus_dmamem_map(sc->sc_dmat, &bdm->bdm_seg, nsegs, size, 961e5ec1e72Spatrick &bdm->bdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0) 962e5ec1e72Spatrick goto free; 963e5ec1e72Spatrick 964e5ec1e72Spatrick if (bus_dmamap_load(sc->sc_dmat, bdm->bdm_map, bdm->bdm_kva, size, 965e5ec1e72Spatrick NULL, BUS_DMA_WAITOK) != 0) 966e5ec1e72Spatrick goto unmap; 967e5ec1e72Spatrick 968e5ec1e72Spatrick bzero(bdm->bdm_kva, size); 969e5ec1e72Spatrick 970e5ec1e72Spatrick return (bdm); 971e5ec1e72Spatrick 972e5ec1e72Spatrick unmap: 973e5ec1e72Spatrick bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, size); 974e5ec1e72Spatrick free: 975e5ec1e72Spatrick bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1); 976e5ec1e72Spatrick destroy: 977e5ec1e72Spatrick bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map); 978e5ec1e72Spatrick bdmfree: 97965046b40Spatrick free(bdm, M_DEVBUF, sizeof(*bdm)); 980e5ec1e72Spatrick 981e5ec1e72Spatrick return (NULL); 982e5ec1e72Spatrick } 983e5ec1e72Spatrick 984e5ec1e72Spatrick void 985e5ec1e72Spatrick bwfm_pci_dmamem_free(struct bwfm_pci_softc *sc, struct bwfm_pci_dmamem *bdm) 986e5ec1e72Spatrick { 987e5ec1e72Spatrick bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, bdm->bdm_size); 988e5ec1e72Spatrick bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1); 989e5ec1e72Spatrick bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map); 99065046b40Spatrick free(bdm, M_DEVBUF, sizeof(*bdm)); 991e5ec1e72Spatrick } 992e5ec1e72Spatrick 993e5ec1e72Spatrick /* 994e5ec1e72Spatrick * We need a simple mapping from a packet ID to mbufs, because when 995e5ec1e72Spatrick * a transfer completed, we only know the ID so we have to look up 996e5ec1e72Spatrick * the memory for the ID. This simply looks for an empty slot. 997e5ec1e72Spatrick */ 998e5ec1e72Spatrick int 99902ee7d07Spatrick bwfm_pci_pktid_avail(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts) 100002ee7d07Spatrick { 100102ee7d07Spatrick int i, idx; 100202ee7d07Spatrick 100302ee7d07Spatrick idx = pkts->last + 1; 100402ee7d07Spatrick for (i = 0; i < pkts->npkt; i++) { 100502ee7d07Spatrick if (idx == pkts->npkt) 100602ee7d07Spatrick idx = 0; 100702ee7d07Spatrick if (pkts->pkts[idx].bb_m == NULL) 100802ee7d07Spatrick return 0; 100902ee7d07Spatrick idx++; 101002ee7d07Spatrick } 101102ee7d07Spatrick return ENOBUFS; 101202ee7d07Spatrick } 101302ee7d07Spatrick 101402ee7d07Spatrick int 1015e5ec1e72Spatrick bwfm_pci_pktid_new(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts, 1016e5ec1e72Spatrick struct mbuf *m, uint32_t *pktid, paddr_t *paddr) 1017e5ec1e72Spatrick { 1018e5ec1e72Spatrick int i, idx; 1019e5ec1e72Spatrick 1020e5ec1e72Spatrick idx = pkts->last + 1; 1021e5ec1e72Spatrick for (i = 0; i < pkts->npkt; i++) { 1022e5ec1e72Spatrick if (idx == pkts->npkt) 1023e5ec1e72Spatrick idx = 0; 1024e5ec1e72Spatrick if (pkts->pkts[idx].bb_m == NULL) { 1025e5ec1e72Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat, 1026e5ec1e72Spatrick pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) { 1027518be5f3Spatrick if (m_defrag(m, M_DONTWAIT)) 1028518be5f3Spatrick return EFBIG; 1029518be5f3Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat, 1030518be5f3Spatrick pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) 1031518be5f3Spatrick return EFBIG; 1032e5ec1e72Spatrick } 1033dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, pkts->pkts[idx].bb_map, 1034dcb67343Spatrick 0, pkts->pkts[idx].bb_map->dm_mapsize, 1035dcb67343Spatrick BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1036e5ec1e72Spatrick pkts->last = idx; 1037e5ec1e72Spatrick pkts->pkts[idx].bb_m = m; 1038e5ec1e72Spatrick *pktid = idx; 1039e5ec1e72Spatrick *paddr = pkts->pkts[idx].bb_map->dm_segs[0].ds_addr; 1040e5ec1e72Spatrick return 0; 1041e5ec1e72Spatrick } 1042e5ec1e72Spatrick idx++; 1043e5ec1e72Spatrick } 1044518be5f3Spatrick return ENOBUFS; 1045e5ec1e72Spatrick } 1046e5ec1e72Spatrick 1047e5ec1e72Spatrick struct mbuf * 1048e5ec1e72Spatrick bwfm_pci_pktid_free(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts, 1049e5ec1e72Spatrick uint32_t pktid) 1050e5ec1e72Spatrick { 1051e5ec1e72Spatrick struct mbuf *m; 1052e5ec1e72Spatrick 1053e5ec1e72Spatrick if (pktid >= pkts->npkt || pkts->pkts[pktid].bb_m == NULL) 1054e5ec1e72Spatrick return NULL; 1055dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, pkts->pkts[pktid].bb_map, 0, 1056dcb67343Spatrick pkts->pkts[pktid].bb_map->dm_mapsize, 1057dcb67343Spatrick BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1058e5ec1e72Spatrick bus_dmamap_unload(sc->sc_dmat, pkts->pkts[pktid].bb_map); 1059e5ec1e72Spatrick m = pkts->pkts[pktid].bb_m; 1060e5ec1e72Spatrick pkts->pkts[pktid].bb_m = NULL; 1061e5ec1e72Spatrick return m; 1062e5ec1e72Spatrick } 1063e5ec1e72Spatrick 1064e5ec1e72Spatrick void 1065e5ec1e72Spatrick bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *sc) 1066e5ec1e72Spatrick { 106718722113Spatrick bwfm_pci_fill_rx_buf_ring(sc); 1068e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_ioctl_ring, 1069e5ec1e72Spatrick MSGBUF_TYPE_IOCTLRESP_BUF_POST); 1070e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_event_ring, 1071e5ec1e72Spatrick MSGBUF_TYPE_EVENT_BUF_POST); 1072e5ec1e72Spatrick } 1073e5ec1e72Spatrick 1074e5ec1e72Spatrick void 1075e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *sc, struct if_rxring *rxring, 1076e5ec1e72Spatrick uint32_t msgtype) 1077e5ec1e72Spatrick { 1078e5ec1e72Spatrick struct msgbuf_rx_ioctl_resp_or_event *req; 1079e5ec1e72Spatrick struct mbuf *m; 1080e5ec1e72Spatrick uint32_t pktid; 1081e5ec1e72Spatrick paddr_t paddr; 1082e5ec1e72Spatrick int s, slots; 1083e5ec1e72Spatrick 1084e5ec1e72Spatrick s = splnet(); 1085e5ec1e72Spatrick for (slots = if_rxr_get(rxring, 8); slots > 0; slots--) { 108602ee7d07Spatrick if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts)) 108702ee7d07Spatrick break; 1088e5ec1e72Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit); 1089e5ec1e72Spatrick if (req == NULL) 1090e5ec1e72Spatrick break; 10911950c5c5Spatrick m = MCLGETL(NULL, M_DONTWAIT, MSGBUF_MAX_CTL_PKT_SIZE); 1092e5ec1e72Spatrick if (m == NULL) { 1093e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1); 1094e5ec1e72Spatrick break; 1095e5ec1e72Spatrick } 10961950c5c5Spatrick m->m_len = m->m_pkthdr.len = MSGBUF_MAX_CTL_PKT_SIZE; 1097e5ec1e72Spatrick if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) { 1098e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1); 1099e5ec1e72Spatrick m_freem(m); 1100e5ec1e72Spatrick break; 1101e5ec1e72Spatrick } 1102e5ec1e72Spatrick memset(req, 0, sizeof(*req)); 1103e5ec1e72Spatrick req->msg.msgtype = msgtype; 1104e5ec1e72Spatrick req->msg.request_id = htole32(pktid); 11051950c5c5Spatrick req->host_buf_len = htole16(MSGBUF_MAX_CTL_PKT_SIZE); 1106e4dae658Spatrick req->host_buf_addr.high_addr = htole32((uint64_t)paddr >> 32); 1107e5ec1e72Spatrick req->host_buf_addr.low_addr = htole32(paddr & 0xffffffff); 1108e5ec1e72Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit); 1109e5ec1e72Spatrick } 1110e5ec1e72Spatrick if_rxr_put(rxring, slots); 1111e5ec1e72Spatrick splx(s); 1112e5ec1e72Spatrick } 1113e5ec1e72Spatrick 1114e5ec1e72Spatrick void 1115e5ec1e72Spatrick bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *sc) 1116e5ec1e72Spatrick { 1117e5ec1e72Spatrick struct msgbuf_rx_bufpost *req; 1118e5ec1e72Spatrick struct mbuf *m; 1119e5ec1e72Spatrick uint32_t pktid; 1120e5ec1e72Spatrick paddr_t paddr; 1121e5ec1e72Spatrick int s, slots; 1122e5ec1e72Spatrick 1123e5ec1e72Spatrick s = splnet(); 1124e5ec1e72Spatrick for (slots = if_rxr_get(&sc->sc_rxbuf_ring, sc->sc_max_rxbufpost); 1125e5ec1e72Spatrick slots > 0; slots--) { 112602ee7d07Spatrick if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts)) 112702ee7d07Spatrick break; 1128e5ec1e72Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_rxpost_submit); 1129e5ec1e72Spatrick if (req == NULL) 1130e5ec1e72Spatrick break; 1131471f2571Sjan m = MCLGETL(NULL, M_DONTWAIT, MSGBUF_MAX_PKT_SIZE); 1132e5ec1e72Spatrick if (m == NULL) { 1133e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1); 1134e5ec1e72Spatrick break; 1135e5ec1e72Spatrick } 1136e5ec1e72Spatrick m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE; 1137e5ec1e72Spatrick if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) { 1138e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1); 1139e5ec1e72Spatrick m_freem(m); 1140e5ec1e72Spatrick break; 1141e5ec1e72Spatrick } 1142e5ec1e72Spatrick memset(req, 0, sizeof(*req)); 1143e5ec1e72Spatrick req->msg.msgtype = MSGBUF_TYPE_RXBUF_POST; 1144e5ec1e72Spatrick req->msg.request_id = htole32(pktid); 1145e5ec1e72Spatrick req->data_buf_len = htole16(MSGBUF_MAX_PKT_SIZE); 1146e4dae658Spatrick req->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32); 1147e5ec1e72Spatrick req->data_buf_addr.low_addr = htole32(paddr & 0xffffffff); 1148e5ec1e72Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_rxpost_submit); 1149e5ec1e72Spatrick } 1150e5ec1e72Spatrick if_rxr_put(&sc->sc_rxbuf_ring, slots); 1151e5ec1e72Spatrick splx(s); 1152e5ec1e72Spatrick } 1153e5ec1e72Spatrick 1154e5ec1e72Spatrick int 1155e5ec1e72Spatrick bwfm_pci_setup_ring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring, 1156e5ec1e72Spatrick int nitem, size_t itemsz, uint32_t w_idx, uint32_t r_idx, 1157e5ec1e72Spatrick int idx, uint32_t idx_off, uint32_t *ring_mem) 1158e5ec1e72Spatrick { 1159e5ec1e72Spatrick ring->w_idx_addr = w_idx + idx * idx_off; 1160e5ec1e72Spatrick ring->r_idx_addr = r_idx + idx * idx_off; 1161*13f544a8Spatrick ring->w_ptr = 0; 1162*13f544a8Spatrick ring->r_ptr = 0; 1163e5ec1e72Spatrick ring->nitem = nitem; 1164e5ec1e72Spatrick ring->itemsz = itemsz; 1165e5ec1e72Spatrick bwfm_pci_ring_write_rptr(sc, ring); 1166e5ec1e72Spatrick bwfm_pci_ring_write_wptr(sc, ring); 1167e5ec1e72Spatrick 1168e5ec1e72Spatrick ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8); 1169e5ec1e72Spatrick if (ring->ring == NULL) 1170e5ec1e72Spatrick return ENOMEM; 1171e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1172e5ec1e72Spatrick *ring_mem + BWFM_RING_MEM_BASE_ADDR_LOW, 1173e5ec1e72Spatrick BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff); 1174e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1175e5ec1e72Spatrick *ring_mem + BWFM_RING_MEM_BASE_ADDR_HIGH, 1176e5ec1e72Spatrick BWFM_PCI_DMA_DVA(ring->ring) >> 32); 1177e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1178e5ec1e72Spatrick *ring_mem + BWFM_RING_MAX_ITEM, nitem); 1179e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1180e5ec1e72Spatrick *ring_mem + BWFM_RING_LEN_ITEMS, itemsz); 1181e5ec1e72Spatrick *ring_mem = *ring_mem + BWFM_RING_MEM_SZ; 1182e5ec1e72Spatrick return 0; 1183e5ec1e72Spatrick } 1184e5ec1e72Spatrick 1185518be5f3Spatrick int 1186518be5f3Spatrick bwfm_pci_setup_flowring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring, 1187518be5f3Spatrick int nitem, size_t itemsz) 1188518be5f3Spatrick { 1189518be5f3Spatrick ring->w_ptr = 0; 1190518be5f3Spatrick ring->r_ptr = 0; 1191518be5f3Spatrick ring->nitem = nitem; 1192518be5f3Spatrick ring->itemsz = itemsz; 1193518be5f3Spatrick bwfm_pci_ring_write_rptr(sc, ring); 1194518be5f3Spatrick bwfm_pci_ring_write_wptr(sc, ring); 1195518be5f3Spatrick 1196518be5f3Spatrick ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8); 1197518be5f3Spatrick if (ring->ring == NULL) 1198518be5f3Spatrick return ENOMEM; 1199518be5f3Spatrick return 0; 1200518be5f3Spatrick } 1201518be5f3Spatrick 1202e5ec1e72Spatrick /* Ring helpers */ 1203e5ec1e72Spatrick void 1204e5ec1e72Spatrick bwfm_pci_ring_bell(struct bwfm_pci_softc *sc, 1205e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1206e5ec1e72Spatrick { 1207bb813cf8Spatrick struct bwfm_softc *bwfm = (void *)sc; 1208bb813cf8Spatrick 1209bb813cf8Spatrick if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID) 1210bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1211bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_H2D_MAILBOX_0, 1); 1212bb813cf8Spatrick else 1213e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1214156d2677Spatrick BWFM_PCI_PCIE2REG_H2D_MAILBOX_0, 1); 1215e5ec1e72Spatrick } 1216e5ec1e72Spatrick 1217e5ec1e72Spatrick void 1218e5ec1e72Spatrick bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *sc, 1219e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1220e5ec1e72Spatrick { 1221e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 1222e5ec1e72Spatrick ring->r_ptr = bus_space_read_2(sc->sc_tcm_iot, 1223e5ec1e72Spatrick sc->sc_tcm_ioh, ring->r_idx_addr); 1224e5ec1e72Spatrick } else { 1225dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, 1226dcb67343Spatrick BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr, 1227dcb67343Spatrick sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1228e5ec1e72Spatrick ring->r_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf) 1229e5ec1e72Spatrick + ring->r_idx_addr); 1230e5ec1e72Spatrick } 1231e5ec1e72Spatrick } 1232e5ec1e72Spatrick 1233e5ec1e72Spatrick void 1234e5ec1e72Spatrick bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *sc, 1235e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1236e5ec1e72Spatrick { 1237e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 1238e5ec1e72Spatrick ring->w_ptr = bus_space_read_2(sc->sc_tcm_iot, 1239e5ec1e72Spatrick sc->sc_tcm_ioh, ring->w_idx_addr); 1240e5ec1e72Spatrick } else { 1241dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, 1242dcb67343Spatrick BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr, 1243dcb67343Spatrick sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1244e5ec1e72Spatrick ring->w_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf) 1245e5ec1e72Spatrick + ring->w_idx_addr); 1246e5ec1e72Spatrick } 1247e5ec1e72Spatrick } 1248e5ec1e72Spatrick 1249e5ec1e72Spatrick void 1250e5ec1e72Spatrick bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *sc, 1251e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1252e5ec1e72Spatrick { 1253e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 1254e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1255e5ec1e72Spatrick ring->r_idx_addr, ring->r_ptr); 1256e5ec1e72Spatrick } else { 1257e5ec1e72Spatrick *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf) 1258e5ec1e72Spatrick + ring->r_idx_addr) = ring->r_ptr; 1259dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, 1260dcb67343Spatrick BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr, 1261dcb67343Spatrick sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1262e5ec1e72Spatrick } 1263e5ec1e72Spatrick } 1264e5ec1e72Spatrick 1265e5ec1e72Spatrick void 1266e5ec1e72Spatrick bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *sc, 1267e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1268e5ec1e72Spatrick { 1269e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 1270e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1271e5ec1e72Spatrick ring->w_idx_addr, ring->w_ptr); 1272e5ec1e72Spatrick } else { 1273e5ec1e72Spatrick *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf) 1274e5ec1e72Spatrick + ring->w_idx_addr) = ring->w_ptr; 1275dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, 1276dcb67343Spatrick BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr, 1277dcb67343Spatrick sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1278e5ec1e72Spatrick } 1279e5ec1e72Spatrick } 1280e5ec1e72Spatrick 1281e5ec1e72Spatrick /* 1282e5ec1e72Spatrick * Retrieve a free descriptor to put new stuff in, but don't commit 1283e5ec1e72Spatrick * to it yet so we can rollback later if any error occurs. 1284e5ec1e72Spatrick */ 1285e5ec1e72Spatrick void * 1286e5ec1e72Spatrick bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *sc, 1287e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1288e5ec1e72Spatrick { 1289e5ec1e72Spatrick int available; 1290e5ec1e72Spatrick char *ret; 1291e5ec1e72Spatrick 1292e5ec1e72Spatrick bwfm_pci_ring_update_rptr(sc, ring); 1293e5ec1e72Spatrick 1294e5ec1e72Spatrick if (ring->r_ptr > ring->w_ptr) 1295e5ec1e72Spatrick available = ring->r_ptr - ring->w_ptr; 1296e5ec1e72Spatrick else 1297e5ec1e72Spatrick available = ring->r_ptr + (ring->nitem - ring->w_ptr); 1298e5ec1e72Spatrick 129930f5ada0Spatrick if (available <= 1) 1300e5ec1e72Spatrick return NULL; 1301e5ec1e72Spatrick 1302e5ec1e72Spatrick ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz); 1303e5ec1e72Spatrick ring->w_ptr += 1; 1304e5ec1e72Spatrick if (ring->w_ptr == ring->nitem) 1305e5ec1e72Spatrick ring->w_ptr = 0; 1306e5ec1e72Spatrick return ret; 1307e5ec1e72Spatrick } 1308e5ec1e72Spatrick 1309e5ec1e72Spatrick void * 1310e5ec1e72Spatrick bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *sc, 1311e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int count, int *avail) 1312e5ec1e72Spatrick { 1313e5ec1e72Spatrick int available; 1314e5ec1e72Spatrick char *ret; 1315e5ec1e72Spatrick 1316e5ec1e72Spatrick bwfm_pci_ring_update_rptr(sc, ring); 1317e5ec1e72Spatrick 1318e5ec1e72Spatrick if (ring->r_ptr > ring->w_ptr) 1319e5ec1e72Spatrick available = ring->r_ptr - ring->w_ptr; 1320e5ec1e72Spatrick else 1321e5ec1e72Spatrick available = ring->r_ptr + (ring->nitem - ring->w_ptr); 1322e5ec1e72Spatrick 132330f5ada0Spatrick if (available <= 1) 1324e5ec1e72Spatrick return NULL; 1325e5ec1e72Spatrick 1326e5ec1e72Spatrick ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz); 1327e5ec1e72Spatrick *avail = min(count, available - 1); 1328e5ec1e72Spatrick if (*avail + ring->w_ptr > ring->nitem) 1329e5ec1e72Spatrick *avail = ring->nitem - ring->w_ptr; 1330e5ec1e72Spatrick ring->w_ptr += *avail; 1331e5ec1e72Spatrick if (ring->w_ptr == ring->nitem) 1332e5ec1e72Spatrick ring->w_ptr = 0; 1333e5ec1e72Spatrick return ret; 1334e5ec1e72Spatrick } 1335e5ec1e72Spatrick 1336e5ec1e72Spatrick /* 1337e5ec1e72Spatrick * Read number of descriptors available (submitted by the firmware) 1338e5ec1e72Spatrick * and retrieve pointer to first descriptor. 1339e5ec1e72Spatrick */ 1340e5ec1e72Spatrick void * 1341e5ec1e72Spatrick bwfm_pci_ring_read_avail(struct bwfm_pci_softc *sc, 1342e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int *avail) 1343e5ec1e72Spatrick { 1344e5ec1e72Spatrick bwfm_pci_ring_update_wptr(sc, ring); 1345e5ec1e72Spatrick 1346e5ec1e72Spatrick if (ring->w_ptr >= ring->r_ptr) 1347e5ec1e72Spatrick *avail = ring->w_ptr - ring->r_ptr; 1348e5ec1e72Spatrick else 1349e5ec1e72Spatrick *avail = ring->nitem - ring->r_ptr; 1350e5ec1e72Spatrick 1351e5ec1e72Spatrick if (*avail == 0) 1352e5ec1e72Spatrick return NULL; 1353e5ec1e72Spatrick 1354dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring), 1355dcb67343Spatrick ring->r_ptr * ring->itemsz, *avail * ring->itemsz, 1356dcb67343Spatrick BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1357e5ec1e72Spatrick return BWFM_PCI_DMA_KVA(ring->ring) + (ring->r_ptr * ring->itemsz); 1358e5ec1e72Spatrick } 1359e5ec1e72Spatrick 1360e5ec1e72Spatrick /* 1361e5ec1e72Spatrick * Let firmware know we read N descriptors. 1362e5ec1e72Spatrick */ 1363e5ec1e72Spatrick void 1364e5ec1e72Spatrick bwfm_pci_ring_read_commit(struct bwfm_pci_softc *sc, 1365e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int nitem) 1366e5ec1e72Spatrick { 1367e5ec1e72Spatrick ring->r_ptr += nitem; 1368e5ec1e72Spatrick if (ring->r_ptr == ring->nitem) 1369e5ec1e72Spatrick ring->r_ptr = 0; 1370e5ec1e72Spatrick bwfm_pci_ring_write_rptr(sc, ring); 1371e5ec1e72Spatrick } 1372e5ec1e72Spatrick 1373e5ec1e72Spatrick /* 1374e5ec1e72Spatrick * Let firmware know that we submitted some descriptors. 1375e5ec1e72Spatrick */ 1376e5ec1e72Spatrick void 1377e5ec1e72Spatrick bwfm_pci_ring_write_commit(struct bwfm_pci_softc *sc, 1378e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1379e5ec1e72Spatrick { 1380dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring), 1381dcb67343Spatrick 0, BWFM_PCI_DMA_LEN(ring->ring), BUS_DMASYNC_PREREAD | 1382dcb67343Spatrick BUS_DMASYNC_PREWRITE); 1383e5ec1e72Spatrick bwfm_pci_ring_write_wptr(sc, ring); 1384e5ec1e72Spatrick bwfm_pci_ring_bell(sc, ring); 1385e5ec1e72Spatrick } 1386e5ec1e72Spatrick 1387e5ec1e72Spatrick /* 1388e5ec1e72Spatrick * Rollback N descriptors in case we don't actually want 1389e5ec1e72Spatrick * to commit to it. 1390e5ec1e72Spatrick */ 1391e5ec1e72Spatrick void 1392e5ec1e72Spatrick bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *sc, 1393e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int nitem) 1394e5ec1e72Spatrick { 1395e5ec1e72Spatrick if (ring->w_ptr == 0) 1396e5ec1e72Spatrick ring->w_ptr = ring->nitem - nitem; 1397e5ec1e72Spatrick else 1398e5ec1e72Spatrick ring->w_ptr -= nitem; 1399e5ec1e72Spatrick } 1400e5ec1e72Spatrick 1401e5ec1e72Spatrick /* 1402e5ec1e72Spatrick * Foreach written descriptor on the ring, pass the descriptor to 1403e5ec1e72Spatrick * a message handler and let the firmware know we handled it. 1404e5ec1e72Spatrick */ 1405e5ec1e72Spatrick void 14066f241297Spatrick bwfm_pci_ring_rx(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring, 14076f241297Spatrick struct mbuf_list *ml) 1408e5ec1e72Spatrick { 1409e5ec1e72Spatrick void *buf; 1410e5ec1e72Spatrick int avail, processed; 1411e5ec1e72Spatrick 1412e5ec1e72Spatrick again: 1413e5ec1e72Spatrick buf = bwfm_pci_ring_read_avail(sc, ring, &avail); 1414e5ec1e72Spatrick if (buf == NULL) 1415e5ec1e72Spatrick return; 1416e5ec1e72Spatrick 1417e5ec1e72Spatrick processed = 0; 1418e5ec1e72Spatrick while (avail) { 14196f241297Spatrick bwfm_pci_msg_rx(sc, buf + sc->sc_rx_dataoffset, ml); 1420e5ec1e72Spatrick buf += ring->itemsz; 1421e5ec1e72Spatrick processed++; 1422e5ec1e72Spatrick if (processed == 48) { 1423e5ec1e72Spatrick bwfm_pci_ring_read_commit(sc, ring, processed); 1424e5ec1e72Spatrick processed = 0; 1425e5ec1e72Spatrick } 1426e5ec1e72Spatrick avail--; 1427e5ec1e72Spatrick } 1428e5ec1e72Spatrick if (processed) 1429e5ec1e72Spatrick bwfm_pci_ring_read_commit(sc, ring, processed); 1430e5ec1e72Spatrick if (ring->r_ptr == 0) 1431e5ec1e72Spatrick goto again; 1432e5ec1e72Spatrick } 1433e5ec1e72Spatrick 1434e5ec1e72Spatrick void 14356f241297Spatrick bwfm_pci_msg_rx(struct bwfm_pci_softc *sc, void *buf, struct mbuf_list *ml) 1436e5ec1e72Spatrick { 1437518be5f3Spatrick struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if; 1438e5ec1e72Spatrick struct msgbuf_ioctl_resp_hdr *resp; 1439518be5f3Spatrick struct msgbuf_tx_status *tx; 144018722113Spatrick struct msgbuf_rx_complete *rx; 1441e5ec1e72Spatrick struct msgbuf_rx_event *event; 1442e5ec1e72Spatrick struct msgbuf_common_hdr *msg; 1443518be5f3Spatrick struct msgbuf_flowring_create_resp *fcr; 1444a2c6ff8bSpatrick struct msgbuf_flowring_delete_resp *fdr; 1445518be5f3Spatrick struct bwfm_pci_msgring *ring; 1446e5ec1e72Spatrick struct mbuf *m; 1447518be5f3Spatrick int flowid; 1448e5ec1e72Spatrick 1449e5ec1e72Spatrick msg = (struct msgbuf_common_hdr *)buf; 1450e5ec1e72Spatrick switch (msg->msgtype) 1451e5ec1e72Spatrick { 1452518be5f3Spatrick case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT: 1453518be5f3Spatrick fcr = (struct msgbuf_flowring_create_resp *)buf; 1454518be5f3Spatrick flowid = letoh16(fcr->compl_hdr.flow_ring_id); 1455518be5f3Spatrick if (flowid < 2) 1456518be5f3Spatrick break; 1457518be5f3Spatrick flowid -= 2; 1458518be5f3Spatrick if (flowid >= sc->sc_max_flowrings) 1459518be5f3Spatrick break; 1460518be5f3Spatrick ring = &sc->sc_flowrings[flowid]; 1461518be5f3Spatrick if (ring->status != RING_OPENING) 1462518be5f3Spatrick break; 1463518be5f3Spatrick if (fcr->compl_hdr.status) { 1464518be5f3Spatrick printf("%s: failed to open flowring %d\n", 1465518be5f3Spatrick DEVNAME(sc), flowid); 1466518be5f3Spatrick ring->status = RING_CLOSED; 146702ee7d07Spatrick if (ring->m) { 146802ee7d07Spatrick m_freem(ring->m); 146902ee7d07Spatrick ring->m = NULL; 147002ee7d07Spatrick } 1471518be5f3Spatrick ifq_restart(&ifp->if_snd); 1472518be5f3Spatrick break; 1473518be5f3Spatrick } 1474518be5f3Spatrick ring->status = RING_OPEN; 147502ee7d07Spatrick if (ring->m != NULL) { 147602ee7d07Spatrick m = ring->m; 147702ee7d07Spatrick ring->m = NULL; 147802ee7d07Spatrick if (bwfm_pci_txdata(&sc->sc_sc, m)) 147902ee7d07Spatrick m_freem(ring->m); 148002ee7d07Spatrick } 1481518be5f3Spatrick ifq_restart(&ifp->if_snd); 1482518be5f3Spatrick break; 1483a2c6ff8bSpatrick case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT: 1484a2c6ff8bSpatrick fdr = (struct msgbuf_flowring_delete_resp *)buf; 1485a2c6ff8bSpatrick flowid = letoh16(fdr->compl_hdr.flow_ring_id); 1486a2c6ff8bSpatrick if (flowid < 2) 1487a2c6ff8bSpatrick break; 1488a2c6ff8bSpatrick flowid -= 2; 1489a2c6ff8bSpatrick if (flowid >= sc->sc_max_flowrings) 1490a2c6ff8bSpatrick break; 1491a2c6ff8bSpatrick ring = &sc->sc_flowrings[flowid]; 1492a2c6ff8bSpatrick if (ring->status != RING_CLOSING) 1493a2c6ff8bSpatrick break; 1494a2c6ff8bSpatrick if (fdr->compl_hdr.status) { 1495a2c6ff8bSpatrick printf("%s: failed to delete flowring %d\n", 1496a2c6ff8bSpatrick DEVNAME(sc), flowid); 1497a2c6ff8bSpatrick break; 1498a2c6ff8bSpatrick } 1499a2c6ff8bSpatrick bwfm_pci_dmamem_free(sc, ring->ring); 1500a2c6ff8bSpatrick ring->status = RING_CLOSED; 1501a2c6ff8bSpatrick break; 1502e5ec1e72Spatrick case MSGBUF_TYPE_IOCTLPTR_REQ_ACK: 15032eeba925Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_ioctl_pkts, 15042eeba925Spatrick letoh32(msg->request_id)); 15052eeba925Spatrick if (m == NULL) 15062eeba925Spatrick break; 15072eeba925Spatrick m_freem(m); 1508e5ec1e72Spatrick break; 1509e5ec1e72Spatrick case MSGBUF_TYPE_IOCTL_CMPLT: 1510e5ec1e72Spatrick resp = (struct msgbuf_ioctl_resp_hdr *)buf; 15112eeba925Spatrick bwfm_pci_msgbuf_rxioctl(sc, resp); 1512e5ec1e72Spatrick if_rxr_put(&sc->sc_ioctl_ring, 1); 1513e5ec1e72Spatrick bwfm_pci_fill_rx_rings(sc); 1514e5ec1e72Spatrick break; 1515e5ec1e72Spatrick case MSGBUF_TYPE_WL_EVENT: 1516e5ec1e72Spatrick event = (struct msgbuf_rx_event *)buf; 1517e5ec1e72Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts, 1518e5ec1e72Spatrick letoh32(event->msg.request_id)); 1519e5ec1e72Spatrick if (m == NULL) 1520e5ec1e72Spatrick break; 1521e5ec1e72Spatrick m_adj(m, sc->sc_rx_dataoffset); 1522f37fc236Spatrick m->m_len = m->m_pkthdr.len = letoh16(event->event_data_len); 15236f241297Spatrick bwfm_rx(&sc->sc_sc, m, ml); 1524e5ec1e72Spatrick if_rxr_put(&sc->sc_event_ring, 1); 1525e5ec1e72Spatrick bwfm_pci_fill_rx_rings(sc); 1526e5ec1e72Spatrick break; 1527518be5f3Spatrick case MSGBUF_TYPE_TX_STATUS: 1528518be5f3Spatrick tx = (struct msgbuf_tx_status *)buf; 1529518be5f3Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_tx_pkts, 1530f9ee104fSpatrick letoh32(tx->msg.request_id) - 1); 1531518be5f3Spatrick if (m == NULL) 1532518be5f3Spatrick break; 1533518be5f3Spatrick m_freem(m); 1534c6f1636dSpatrick if (sc->sc_tx_pkts_full) { 1535c6f1636dSpatrick sc->sc_tx_pkts_full = 0; 1536c6f1636dSpatrick ifq_restart(&ifp->if_snd); 1537c6f1636dSpatrick } 1538518be5f3Spatrick break; 153918722113Spatrick case MSGBUF_TYPE_RX_CMPLT: 154018722113Spatrick rx = (struct msgbuf_rx_complete *)buf; 154118722113Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts, 154218722113Spatrick letoh32(rx->msg.request_id)); 154318722113Spatrick if (m == NULL) 154418722113Spatrick break; 154518722113Spatrick if (letoh16(rx->data_offset)) 154618722113Spatrick m_adj(m, letoh16(rx->data_offset)); 154718722113Spatrick else if (sc->sc_rx_dataoffset) 154818722113Spatrick m_adj(m, sc->sc_rx_dataoffset); 1549f37fc236Spatrick m->m_len = m->m_pkthdr.len = letoh16(rx->data_len); 15506f241297Spatrick bwfm_rx(&sc->sc_sc, m, ml); 155118722113Spatrick if_rxr_put(&sc->sc_rxbuf_ring, 1); 155218722113Spatrick bwfm_pci_fill_rx_rings(sc); 155318722113Spatrick break; 1554e5ec1e72Spatrick default: 1555e5ec1e72Spatrick printf("%s: msgtype 0x%08x\n", __func__, msg->msgtype); 1556e5ec1e72Spatrick break; 1557e5ec1e72Spatrick } 1558e5ec1e72Spatrick } 1559e5ec1e72Spatrick 1560e5ec1e72Spatrick /* Bus core helpers */ 1561e5ec1e72Spatrick void 1562e5ec1e72Spatrick bwfm_pci_select_core(struct bwfm_pci_softc *sc, int id) 1563e5ec1e72Spatrick { 1564e5ec1e72Spatrick struct bwfm_softc *bwfm = (void *)sc; 1565e5ec1e72Spatrick struct bwfm_core *core; 1566e5ec1e72Spatrick 1567e5ec1e72Spatrick core = bwfm_chip_get_core(bwfm, id); 1568e5ec1e72Spatrick if (core == NULL) { 1569e5ec1e72Spatrick printf("%s: could not find core to select", DEVNAME(sc)); 1570e5ec1e72Spatrick return; 1571e5ec1e72Spatrick } 1572e5ec1e72Spatrick 1573e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, 1574e5ec1e72Spatrick BWFM_PCI_BAR0_WINDOW, core->co_base); 1575e5ec1e72Spatrick if (pci_conf_read(sc->sc_pc, sc->sc_tag, 1576e5ec1e72Spatrick BWFM_PCI_BAR0_WINDOW) != core->co_base) 1577e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, 1578e5ec1e72Spatrick BWFM_PCI_BAR0_WINDOW, core->co_base); 1579e5ec1e72Spatrick } 1580e5ec1e72Spatrick 1581e5ec1e72Spatrick uint32_t 1582e5ec1e72Spatrick bwfm_pci_buscore_read(struct bwfm_softc *bwfm, uint32_t reg) 1583e5ec1e72Spatrick { 1584e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1585e5ec1e72Spatrick uint32_t page, offset; 1586e5ec1e72Spatrick 1587e5ec1e72Spatrick page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1); 1588e5ec1e72Spatrick offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1); 1589e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page); 1590e5ec1e72Spatrick return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset); 1591e5ec1e72Spatrick } 1592e5ec1e72Spatrick 1593e5ec1e72Spatrick void 1594e5ec1e72Spatrick bwfm_pci_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val) 1595e5ec1e72Spatrick { 1596e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1597e5ec1e72Spatrick uint32_t page, offset; 1598e5ec1e72Spatrick 1599e5ec1e72Spatrick page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1); 1600e5ec1e72Spatrick offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1); 1601e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page); 1602e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset, val); 1603e5ec1e72Spatrick } 1604e5ec1e72Spatrick 1605e5ec1e72Spatrick int 1606e5ec1e72Spatrick bwfm_pci_buscore_prepare(struct bwfm_softc *bwfm) 1607e5ec1e72Spatrick { 1608e5ec1e72Spatrick return 0; 1609e5ec1e72Spatrick } 1610e5ec1e72Spatrick 1611e5ec1e72Spatrick int 1612e5ec1e72Spatrick bwfm_pci_buscore_reset(struct bwfm_softc *bwfm) 1613e5ec1e72Spatrick { 1614e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1615e5ec1e72Spatrick struct bwfm_core *core; 1616e5ec1e72Spatrick uint32_t reg; 1617e5ec1e72Spatrick int i; 1618e5ec1e72Spatrick 1619e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2); 1620e5ec1e72Spatrick reg = pci_conf_read(sc->sc_pc, sc->sc_tag, 1621e5ec1e72Spatrick BWFM_PCI_CFGREG_LINK_STATUS_CTRL); 1622e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_CFGREG_LINK_STATUS_CTRL, 1623e5ec1e72Spatrick reg & ~BWFM_PCI_CFGREG_LINK_STATUS_CTRL_ASPM_ENAB); 1624e5ec1e72Spatrick 1625e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); 1626e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1627e5ec1e72Spatrick BWFM_CHIP_REG_WATCHDOG, 4); 1628e5ec1e72Spatrick delay(100 * 1000); 1629e5ec1e72Spatrick 1630e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2); 1631e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, 1632e5ec1e72Spatrick BWFM_PCI_CFGREG_LINK_STATUS_CTRL, reg); 1633e5ec1e72Spatrick 1634e5ec1e72Spatrick core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2); 1635e5ec1e72Spatrick if (core->co_rev <= 13) { 1636e5ec1e72Spatrick uint16_t cfg_offset[] = { 1637e5ec1e72Spatrick BWFM_PCI_CFGREG_STATUS_CMD, 1638e5ec1e72Spatrick BWFM_PCI_CFGREG_PM_CSR, 1639e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_CAP, 1640e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_ADDR_L, 1641e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_ADDR_H, 1642e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_DATA, 1643e5ec1e72Spatrick BWFM_PCI_CFGREG_LINK_STATUS_CTRL2, 1644e5ec1e72Spatrick BWFM_PCI_CFGREG_RBAR_CTRL, 1645e5ec1e72Spatrick BWFM_PCI_CFGREG_PML1_SUB_CTRL1, 1646e5ec1e72Spatrick BWFM_PCI_CFGREG_REG_BAR2_CONFIG, 1647e5ec1e72Spatrick BWFM_PCI_CFGREG_REG_BAR3_CONFIG, 1648e5ec1e72Spatrick }; 1649e5ec1e72Spatrick 1650e5ec1e72Spatrick for (i = 0; i < nitems(cfg_offset); i++) { 1651e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1652e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGADDR, cfg_offset[i]); 1653e5ec1e72Spatrick reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1654e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA); 1655e5ec1e72Spatrick DPRINTFN(3, ("%s: config offset 0x%04x, value 0x%04x\n", 1656e5ec1e72Spatrick DEVNAME(sc), cfg_offset[i], reg)); 1657e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1658e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA, reg); 1659e5ec1e72Spatrick } 1660e5ec1e72Spatrick } 1661e5ec1e72Spatrick 1662bb813cf8Spatrick reg = bwfm_pci_intr_status(sc); 1663e5ec1e72Spatrick if (reg != 0xffffffff) 1664bb813cf8Spatrick bwfm_pci_intr_ack(sc, reg); 1665e5ec1e72Spatrick 1666e5ec1e72Spatrick return 0; 1667e5ec1e72Spatrick } 1668e5ec1e72Spatrick 1669e5ec1e72Spatrick void 1670e5ec1e72Spatrick bwfm_pci_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec) 1671e5ec1e72Spatrick { 1672e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1673e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 0, rstvec); 1674e5ec1e72Spatrick } 1675e5ec1e72Spatrick 1676f67437f3Spatrick static int bwfm_pci_prio2fifo[8] = { 16779e2c067eSpatrick 0, /* best effort */ 16789e2c067eSpatrick 1, /* IPTOS_PREC_IMMEDIATE */ 16799e2c067eSpatrick 1, /* IPTOS_PREC_PRIORITY */ 16809e2c067eSpatrick 0, /* IPTOS_PREC_FLASH */ 1681f67437f3Spatrick 2, /* IPTOS_PREC_FLASHOVERRIDE */ 1682f67437f3Spatrick 2, /* IPTOS_PREC_CRITIC_ECP */ 1683f67437f3Spatrick 3, /* IPTOS_PREC_INTERNETCONTROL */ 1684f67437f3Spatrick 3, /* IPTOS_PREC_NETCONTROL */ 1685f67437f3Spatrick }; 1686f67437f3Spatrick 1687f67437f3Spatrick int 1688f67437f3Spatrick bwfm_pci_flowring_lookup(struct bwfm_pci_softc *sc, struct mbuf *m) 1689518be5f3Spatrick { 1690f67437f3Spatrick struct ieee80211com *ic = &sc->sc_sc.sc_ic; 1691e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY 1692f67437f3Spatrick uint8_t *da = mtod(m, uint8_t *); 1693e6abcda3Smlarkin #endif 1694f67437f3Spatrick int flowid, prio, fifo; 1695f67437f3Spatrick int i, found; 1696f67437f3Spatrick 1697f67437f3Spatrick prio = ieee80211_classify(ic, m); 1698f67437f3Spatrick fifo = bwfm_pci_prio2fifo[prio]; 1699f67437f3Spatrick 1700f67437f3Spatrick switch (ic->ic_opmode) 1701f67437f3Spatrick { 1702f67437f3Spatrick case IEEE80211_M_STA: 1703f67437f3Spatrick flowid = fifo; 1704f67437f3Spatrick break; 1705f67437f3Spatrick #ifndef IEEE80211_STA_ONLY 1706f67437f3Spatrick case IEEE80211_M_HOSTAP: 17072b7bea7eSpatrick if (ETHER_IS_MULTICAST(da)) 17082b7bea7eSpatrick da = etherbroadcastaddr; 1709f67437f3Spatrick flowid = da[5] * 2 + fifo; 1710f67437f3Spatrick break; 1711f67437f3Spatrick #endif 1712f67437f3Spatrick default: 1713f67437f3Spatrick printf("%s: state not supported\n", DEVNAME(sc)); 1714f67437f3Spatrick return ENOBUFS; 1715f67437f3Spatrick } 1716f67437f3Spatrick 1717f67437f3Spatrick found = 0; 1718f67437f3Spatrick flowid = flowid % sc->sc_max_flowrings; 1719f67437f3Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 1720f67437f3Spatrick if (ic->ic_opmode == IEEE80211_M_STA && 1721f67437f3Spatrick sc->sc_flowrings[flowid].status >= RING_OPEN && 1722f67437f3Spatrick sc->sc_flowrings[flowid].fifo == fifo) { 1723f67437f3Spatrick found = 1; 1724f67437f3Spatrick break; 1725f67437f3Spatrick } 1726f67437f3Spatrick #ifndef IEEE80211_STA_ONLY 1727f67437f3Spatrick if (ic->ic_opmode == IEEE80211_M_HOSTAP && 1728f67437f3Spatrick sc->sc_flowrings[flowid].status >= RING_OPEN && 1729f67437f3Spatrick sc->sc_flowrings[flowid].fifo == fifo && 1730a2c6ff8bSpatrick !memcmp(sc->sc_flowrings[flowid].mac, da, ETHER_ADDR_LEN)) { 1731f67437f3Spatrick found = 1; 1732f67437f3Spatrick break; 1733f67437f3Spatrick } 1734f67437f3Spatrick #endif 1735f67437f3Spatrick flowid = (flowid + 1) % sc->sc_max_flowrings; 1736f67437f3Spatrick } 1737f67437f3Spatrick 1738f67437f3Spatrick if (found) 1739f67437f3Spatrick return flowid; 1740f67437f3Spatrick 1741f67437f3Spatrick return -1; 1742f67437f3Spatrick } 1743f67437f3Spatrick 1744f67437f3Spatrick void 1745f67437f3Spatrick bwfm_pci_flowring_create(struct bwfm_pci_softc *sc, struct mbuf *m) 1746f67437f3Spatrick { 1747f67437f3Spatrick struct ieee80211com *ic = &sc->sc_sc.sc_ic; 1748518be5f3Spatrick struct bwfm_cmd_flowring_create cmd; 1749e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY 1750f67437f3Spatrick uint8_t *da = mtod(m, uint8_t *); 1751e6abcda3Smlarkin #endif 175202ee7d07Spatrick struct bwfm_pci_msgring *ring; 1753f67437f3Spatrick int flowid, prio, fifo; 1754f67437f3Spatrick int i, found; 1755f67437f3Spatrick 1756f67437f3Spatrick prio = ieee80211_classify(ic, m); 1757f67437f3Spatrick fifo = bwfm_pci_prio2fifo[prio]; 1758f67437f3Spatrick 1759f67437f3Spatrick switch (ic->ic_opmode) 1760f67437f3Spatrick { 1761f67437f3Spatrick case IEEE80211_M_STA: 1762f67437f3Spatrick flowid = fifo; 1763f67437f3Spatrick break; 1764f67437f3Spatrick #ifndef IEEE80211_STA_ONLY 1765f67437f3Spatrick case IEEE80211_M_HOSTAP: 17662b7bea7eSpatrick if (ETHER_IS_MULTICAST(da)) 17672b7bea7eSpatrick da = etherbroadcastaddr; 1768f67437f3Spatrick flowid = da[5] * 2 + fifo; 1769f67437f3Spatrick break; 1770f67437f3Spatrick #endif 1771f67437f3Spatrick default: 1772f67437f3Spatrick printf("%s: state not supported\n", DEVNAME(sc)); 1773f67437f3Spatrick return; 1774f67437f3Spatrick } 1775f67437f3Spatrick 1776f67437f3Spatrick found = 0; 1777f67437f3Spatrick flowid = flowid % sc->sc_max_flowrings; 1778f67437f3Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 177902ee7d07Spatrick ring = &sc->sc_flowrings[flowid]; 178002ee7d07Spatrick if (ring->status == RING_CLOSED) { 178102ee7d07Spatrick ring->status = RING_OPENING; 1782f67437f3Spatrick found = 1; 1783f67437f3Spatrick break; 1784f67437f3Spatrick } 1785f67437f3Spatrick flowid = (flowid + 1) % sc->sc_max_flowrings; 1786f67437f3Spatrick } 1787f67437f3Spatrick 178802ee7d07Spatrick /* 178902ee7d07Spatrick * We cannot recover from that so far. Only a stop/init 179002ee7d07Spatrick * cycle can revive this if it ever happens at all. 179102ee7d07Spatrick */ 1792f67437f3Spatrick if (!found) { 1793f67437f3Spatrick printf("%s: no flowring available\n", DEVNAME(sc)); 1794f67437f3Spatrick return; 1795f67437f3Spatrick } 1796f67437f3Spatrick 179702ee7d07Spatrick cmd.m = m; 1798f67437f3Spatrick cmd.prio = prio; 1799518be5f3Spatrick cmd.flowid = flowid; 1800518be5f3Spatrick bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_create_cb, &cmd, sizeof(cmd)); 1801518be5f3Spatrick } 1802518be5f3Spatrick 1803518be5f3Spatrick void 1804518be5f3Spatrick bwfm_pci_flowring_create_cb(struct bwfm_softc *bwfm, void *arg) 1805518be5f3Spatrick { 1806518be5f3Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1807e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY 18082b7bea7eSpatrick struct ieee80211com *ic = &sc->sc_sc.sc_ic; 1809e6abcda3Smlarkin #endif 1810518be5f3Spatrick struct bwfm_cmd_flowring_create *cmd = arg; 1811518be5f3Spatrick struct msgbuf_tx_flowring_create_req *req; 1812518be5f3Spatrick struct bwfm_pci_msgring *ring; 181302ee7d07Spatrick uint8_t *da, *sa; 1814e272db29Spatrick int s; 1815518be5f3Spatrick 181602ee7d07Spatrick da = mtod(cmd->m, char *) + 0 * ETHER_ADDR_LEN; 181702ee7d07Spatrick sa = mtod(cmd->m, char *) + 1 * ETHER_ADDR_LEN; 1818518be5f3Spatrick 181902ee7d07Spatrick ring = &sc->sc_flowrings[cmd->flowid]; 182002ee7d07Spatrick if (ring->status != RING_OPENING) { 182102ee7d07Spatrick printf("%s: flowring not opening\n", DEVNAME(sc)); 1822518be5f3Spatrick return; 1823f67437f3Spatrick } 1824f67437f3Spatrick 1825f67437f3Spatrick if (bwfm_pci_setup_flowring(sc, ring, 512, 48)) { 1826f67437f3Spatrick printf("%s: cannot setup flowring\n", DEVNAME(sc)); 1827f67437f3Spatrick return; 1828f67437f3Spatrick } 1829518be5f3Spatrick 1830e272db29Spatrick s = splnet(); 1831518be5f3Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit); 1832f67437f3Spatrick if (req == NULL) { 1833f67437f3Spatrick printf("%s: cannot reserve for flowring\n", DEVNAME(sc)); 1834e272db29Spatrick splx(s); 1835518be5f3Spatrick return; 1836f67437f3Spatrick } 1837518be5f3Spatrick 1838518be5f3Spatrick ring->status = RING_OPENING; 183902ee7d07Spatrick ring->fifo = bwfm_pci_prio2fifo[cmd->prio]; 184002ee7d07Spatrick ring->m = cmd->m; 184102ee7d07Spatrick memcpy(ring->mac, da, ETHER_ADDR_LEN); 18422b7bea7eSpatrick #ifndef IEEE80211_STA_ONLY 184302ee7d07Spatrick if (ic->ic_opmode == IEEE80211_M_HOSTAP && ETHER_IS_MULTICAST(da)) 18442b7bea7eSpatrick memcpy(ring->mac, etherbroadcastaddr, ETHER_ADDR_LEN); 18452b7bea7eSpatrick #endif 1846f67437f3Spatrick 1847518be5f3Spatrick req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE; 1848518be5f3Spatrick req->msg.ifidx = 0; 1849518be5f3Spatrick req->msg.request_id = 0; 185002ee7d07Spatrick req->tid = bwfm_pci_prio2fifo[cmd->prio]; 185102ee7d07Spatrick req->flow_ring_id = letoh16(cmd->flowid + 2); 185202ee7d07Spatrick memcpy(req->da, da, ETHER_ADDR_LEN); 185302ee7d07Spatrick memcpy(req->sa, sa, ETHER_ADDR_LEN); 1854518be5f3Spatrick req->flow_ring_addr.high_addr = 1855518be5f3Spatrick letoh32(BWFM_PCI_DMA_DVA(ring->ring) >> 32); 1856518be5f3Spatrick req->flow_ring_addr.low_addr = 1857518be5f3Spatrick letoh32(BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff); 1858518be5f3Spatrick req->max_items = letoh16(512); 1859518be5f3Spatrick req->len_item = letoh16(48); 1860518be5f3Spatrick 1861518be5f3Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit); 1862e272db29Spatrick splx(s); 1863518be5f3Spatrick } 1864518be5f3Spatrick 1865a2c6ff8bSpatrick void 1866a2c6ff8bSpatrick bwfm_pci_flowring_delete(struct bwfm_pci_softc *sc, int flowid) 1867a2c6ff8bSpatrick { 1868a2c6ff8bSpatrick struct msgbuf_tx_flowring_delete_req *req; 1869a2c6ff8bSpatrick struct bwfm_pci_msgring *ring; 1870e272db29Spatrick int s; 1871a2c6ff8bSpatrick 1872a2c6ff8bSpatrick ring = &sc->sc_flowrings[flowid]; 1873a2c6ff8bSpatrick if (ring->status != RING_OPEN) { 1874a2c6ff8bSpatrick printf("%s: flowring not open\n", DEVNAME(sc)); 1875a2c6ff8bSpatrick return; 1876a2c6ff8bSpatrick } 1877a2c6ff8bSpatrick 1878e272db29Spatrick s = splnet(); 1879a2c6ff8bSpatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit); 1880a2c6ff8bSpatrick if (req == NULL) { 1881a2c6ff8bSpatrick printf("%s: cannot reserve for flowring\n", DEVNAME(sc)); 1882e272db29Spatrick splx(s); 1883a2c6ff8bSpatrick return; 1884a2c6ff8bSpatrick } 1885a2c6ff8bSpatrick 1886a2c6ff8bSpatrick ring->status = RING_CLOSING; 1887a2c6ff8bSpatrick 1888a2c6ff8bSpatrick req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE; 1889a2c6ff8bSpatrick req->msg.ifidx = 0; 1890a2c6ff8bSpatrick req->msg.request_id = 0; 1891a2c6ff8bSpatrick req->flow_ring_id = letoh16(flowid + 2); 1892a2c6ff8bSpatrick req->reason = 0; 1893a2c6ff8bSpatrick 1894a2c6ff8bSpatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit); 1895e272db29Spatrick splx(s); 1896a2c6ff8bSpatrick } 1897a2c6ff8bSpatrick 1898a2c6ff8bSpatrick void 1899a2c6ff8bSpatrick bwfm_pci_stop(struct bwfm_softc *bwfm) 1900a2c6ff8bSpatrick { 1901a2c6ff8bSpatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1902a2c6ff8bSpatrick struct bwfm_pci_msgring *ring; 1903a2c6ff8bSpatrick int i; 1904a2c6ff8bSpatrick 1905a2c6ff8bSpatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 1906a2c6ff8bSpatrick ring = &sc->sc_flowrings[i]; 1907a2c6ff8bSpatrick if (ring->status == RING_OPEN) 1908a2c6ff8bSpatrick bwfm_pci_flowring_delete(sc, i); 1909a2c6ff8bSpatrick } 1910a2c6ff8bSpatrick } 1911a2c6ff8bSpatrick 1912e5ec1e72Spatrick int 191302ee7d07Spatrick bwfm_pci_txcheck(struct bwfm_softc *bwfm) 191402ee7d07Spatrick { 191502ee7d07Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 191602ee7d07Spatrick struct bwfm_pci_msgring *ring; 191702ee7d07Spatrick int i; 191802ee7d07Spatrick 191902ee7d07Spatrick /* If we are transitioning, we cannot send. */ 192002ee7d07Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 192102ee7d07Spatrick ring = &sc->sc_flowrings[i]; 192202ee7d07Spatrick if (ring->status == RING_OPENING) 192302ee7d07Spatrick return ENOBUFS; 192402ee7d07Spatrick } 192502ee7d07Spatrick 192602ee7d07Spatrick if (bwfm_pci_pktid_avail(sc, &sc->sc_tx_pkts)) { 192702ee7d07Spatrick sc->sc_tx_pkts_full = 1; 192802ee7d07Spatrick return ENOBUFS; 192902ee7d07Spatrick } 193002ee7d07Spatrick 193102ee7d07Spatrick return 0; 193202ee7d07Spatrick } 193302ee7d07Spatrick 193402ee7d07Spatrick int 1935e5ec1e72Spatrick bwfm_pci_txdata(struct bwfm_softc *bwfm, struct mbuf *m) 1936e5ec1e72Spatrick { 1937e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1938518be5f3Spatrick struct bwfm_pci_msgring *ring; 1939518be5f3Spatrick struct msgbuf_tx_msghdr *tx; 1940518be5f3Spatrick uint32_t pktid; 1941518be5f3Spatrick paddr_t paddr; 1942518be5f3Spatrick int flowid, ret; 1943518be5f3Spatrick 1944f67437f3Spatrick flowid = bwfm_pci_flowring_lookup(sc, m); 1945f67437f3Spatrick if (flowid < 0) { 194602ee7d07Spatrick /* 194702ee7d07Spatrick * We cannot send the packet right now as there is 194802ee7d07Spatrick * no flowring yet. The flowring will be created 194902ee7d07Spatrick * asynchronously. While the ring is transitioning 195002ee7d07Spatrick * the TX check will tell the upper layers that we 195102ee7d07Spatrick * cannot send packets right now. When the flowring 195202ee7d07Spatrick * is created the queue will be restarted and this 195302ee7d07Spatrick * mbuf will be transmitted. 195402ee7d07Spatrick */ 1955f67437f3Spatrick bwfm_pci_flowring_create(sc, m); 195602ee7d07Spatrick return 0; 1957f67437f3Spatrick } 1958518be5f3Spatrick 1959518be5f3Spatrick ring = &sc->sc_flowrings[flowid]; 1960518be5f3Spatrick if (ring->status == RING_OPENING || 1961f67437f3Spatrick ring->status == RING_CLOSING) { 1962f67437f3Spatrick printf("%s: tried to use a flow that was " 1963f67437f3Spatrick "transitioning in status %d\n", 1964f67437f3Spatrick DEVNAME(sc), ring->status); 1965518be5f3Spatrick return ENOBUFS; 1966518be5f3Spatrick } 1967518be5f3Spatrick 1968518be5f3Spatrick tx = bwfm_pci_ring_write_reserve(sc, ring); 1969518be5f3Spatrick if (tx == NULL) 1970518be5f3Spatrick return ENOBUFS; 1971518be5f3Spatrick 1972518be5f3Spatrick memset(tx, 0, sizeof(*tx)); 1973518be5f3Spatrick tx->msg.msgtype = MSGBUF_TYPE_TX_POST; 1974518be5f3Spatrick tx->msg.ifidx = 0; 1975518be5f3Spatrick tx->flags = BWFM_MSGBUF_PKT_FLAGS_FRAME_802_3; 1976518be5f3Spatrick tx->flags |= ieee80211_classify(&sc->sc_sc.sc_ic, m) << 1977518be5f3Spatrick BWFM_MSGBUF_PKT_FLAGS_PRIO_SHIFT; 1978518be5f3Spatrick tx->seg_cnt = 1; 1979518be5f3Spatrick memcpy(tx->txhdr, mtod(m, char *), ETHER_HDR_LEN); 1980518be5f3Spatrick 1981518be5f3Spatrick ret = bwfm_pci_pktid_new(sc, &sc->sc_tx_pkts, m, &pktid, &paddr); 1982518be5f3Spatrick if (ret) { 198302ee7d07Spatrick if (ret == ENOBUFS) { 198402ee7d07Spatrick printf("%s: no pktid available for TX\n", 198502ee7d07Spatrick DEVNAME(sc)); 1986c6f1636dSpatrick sc->sc_tx_pkts_full = 1; 198702ee7d07Spatrick } 1988518be5f3Spatrick bwfm_pci_ring_write_cancel(sc, ring, 1); 1989518be5f3Spatrick return ret; 1990518be5f3Spatrick } 1991518be5f3Spatrick paddr += ETHER_HDR_LEN; 1992518be5f3Spatrick 1993f9ee104fSpatrick tx->msg.request_id = htole32(pktid + 1); 19944ff787bcSpatrick tx->data_len = htole16(m->m_len - ETHER_HDR_LEN); 1995e4dae658Spatrick tx->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32); 1996518be5f3Spatrick tx->data_buf_addr.low_addr = htole32(paddr & 0xffffffff); 1997518be5f3Spatrick 1998518be5f3Spatrick bwfm_pci_ring_write_commit(sc, ring); 1999518be5f3Spatrick return 0; 2000e5ec1e72Spatrick } 2001e5ec1e72Spatrick 2002bbd71b0bSpatrick #ifdef BWFM_DEBUG 2003cadf5fcfSpatrick void 2004cadf5fcfSpatrick bwfm_pci_debug_console(struct bwfm_pci_softc *sc) 2005cadf5fcfSpatrick { 2006cadf5fcfSpatrick uint32_t newidx = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 2007cadf5fcfSpatrick sc->sc_console_base_addr + BWFM_CONSOLE_WRITEIDX); 2008cadf5fcfSpatrick 2009cadf5fcfSpatrick if (newidx != sc->sc_console_readidx) 2010bbd71b0bSpatrick DPRINTFN(3, ("BWFM CONSOLE: ")); 2011cadf5fcfSpatrick while (newidx != sc->sc_console_readidx) { 2012cadf5fcfSpatrick uint8_t ch = bus_space_read_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 2013cadf5fcfSpatrick sc->sc_console_buf_addr + sc->sc_console_readidx); 2014cadf5fcfSpatrick sc->sc_console_readidx++; 2015cadf5fcfSpatrick if (sc->sc_console_readidx == sc->sc_console_buf_size) 2016cadf5fcfSpatrick sc->sc_console_readidx = 0; 2017cadf5fcfSpatrick if (ch == '\r') 2018cadf5fcfSpatrick continue; 2019bbd71b0bSpatrick DPRINTFN(3, ("%c", ch)); 2020cadf5fcfSpatrick } 2021cadf5fcfSpatrick } 2022bbd71b0bSpatrick #endif 2023cadf5fcfSpatrick 2024e5ec1e72Spatrick int 2025e5ec1e72Spatrick bwfm_pci_intr(void *v) 2026e5ec1e72Spatrick { 2027e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)v; 2028bb813cf8Spatrick struct bwfm_softc *bwfm = (void *)sc; 20296f241297Spatrick struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if; 20306f241297Spatrick struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 2031bb813cf8Spatrick uint32_t status, mask; 2032e5ec1e72Spatrick 2033bb813cf8Spatrick if (!sc->sc_initialized) 2034bb813cf8Spatrick return 0; 2035bb813cf8Spatrick 2036bb813cf8Spatrick status = bwfm_pci_intr_status(sc); 2037bb813cf8Spatrick /* FIXME: interrupt status seems to be zero? */ 2038bb813cf8Spatrick if (status == 0 && bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID) 2039bb813cf8Spatrick status |= BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB; 2040bb813cf8Spatrick if (status == 0) 2041e5ec1e72Spatrick return 0; 2042e5ec1e72Spatrick 2043e5ec1e72Spatrick bwfm_pci_intr_disable(sc); 2044bb813cf8Spatrick bwfm_pci_intr_ack(sc, status); 2045e5ec1e72Spatrick 2046bb813cf8Spatrick if (bwfm->sc_chip.ch_chip != BRCM_CC_4378_CHIP_ID && 2047bb813cf8Spatrick (status & (BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 | 2048bb813cf8Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1))) 2049e5ec1e72Spatrick printf("%s: handle MB data\n", __func__); 2050e5ec1e72Spatrick 2051bb813cf8Spatrick mask = BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB; 2052bb813cf8Spatrick if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID) 2053bb813cf8Spatrick mask = BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB; 2054bb813cf8Spatrick 2055bb813cf8Spatrick if (status & mask) { 20566f241297Spatrick bwfm_pci_ring_rx(sc, &sc->sc_rx_complete, &ml); 20576f241297Spatrick bwfm_pci_ring_rx(sc, &sc->sc_tx_complete, &ml); 20586f241297Spatrick bwfm_pci_ring_rx(sc, &sc->sc_ctrl_complete, &ml); 2059447a2df6Sdlg 2060447a2df6Sdlg if (ifiq_input(&ifp->if_rcv, &ml)) 2061447a2df6Sdlg if_rxr_livelocked(&sc->sc_rxbuf_ring); 2062e5ec1e72Spatrick } 2063e5ec1e72Spatrick 2064cadf5fcfSpatrick #ifdef BWFM_DEBUG 2065cadf5fcfSpatrick bwfm_pci_debug_console(sc); 2066e5ec1e72Spatrick #endif 2067e5ec1e72Spatrick 2068e5ec1e72Spatrick bwfm_pci_intr_enable(sc); 2069e5ec1e72Spatrick return 1; 2070e5ec1e72Spatrick } 2071e5ec1e72Spatrick 2072e5ec1e72Spatrick void 2073e5ec1e72Spatrick bwfm_pci_intr_enable(struct bwfm_pci_softc *sc) 2074e5ec1e72Spatrick { 2075bb813cf8Spatrick struct bwfm_softc *bwfm = (void *)sc; 2076bb813cf8Spatrick 2077bb813cf8Spatrick if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID) 2078bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2079bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_MAILBOXMASK, 2080bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB); 2081bb813cf8Spatrick else 2082e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2083e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK, 2084e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 | 2085e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1 | 2086e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB); 2087e5ec1e72Spatrick } 2088e5ec1e72Spatrick 2089e5ec1e72Spatrick void 2090e5ec1e72Spatrick bwfm_pci_intr_disable(struct bwfm_pci_softc *sc) 2091e5ec1e72Spatrick { 2092bb813cf8Spatrick struct bwfm_softc *bwfm = (void *)sc; 2093bb813cf8Spatrick 2094bb813cf8Spatrick if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID) 2095bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2096bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_MAILBOXMASK, 0); 2097bb813cf8Spatrick else 2098e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2099e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK, 0); 2100e5ec1e72Spatrick } 2101e5ec1e72Spatrick 2102bb813cf8Spatrick uint32_t 2103bb813cf8Spatrick bwfm_pci_intr_status(struct bwfm_pci_softc *sc) 2104bb813cf8Spatrick { 2105bb813cf8Spatrick struct bwfm_softc *bwfm = (void *)sc; 2106bb813cf8Spatrick 2107bb813cf8Spatrick if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID) 2108bb813cf8Spatrick return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2109bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_MAILBOXINT); 2110bb813cf8Spatrick else 2111bb813cf8Spatrick return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2112bb813cf8Spatrick BWFM_PCI_PCIE2REG_MAILBOXINT); 2113bb813cf8Spatrick } 2114bb813cf8Spatrick 2115bb813cf8Spatrick void 2116bb813cf8Spatrick bwfm_pci_intr_ack(struct bwfm_pci_softc *sc, uint32_t status) 2117bb813cf8Spatrick { 2118bb813cf8Spatrick struct bwfm_softc *bwfm = (void *)sc; 2119bb813cf8Spatrick 2120bb813cf8Spatrick if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID) 2121bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2122bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_MAILBOXINT, status); 2123bb813cf8Spatrick else 2124bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2125bb813cf8Spatrick BWFM_PCI_PCIE2REG_MAILBOXINT, status); 2126bb813cf8Spatrick } 2127bb813cf8Spatrick 2128156d2677Spatrick void 2129156d2677Spatrick bwfm_pci_hostready(struct bwfm_pci_softc *sc) 2130156d2677Spatrick { 2131bb813cf8Spatrick struct bwfm_softc *bwfm = (void *)sc; 2132bb813cf8Spatrick 2133156d2677Spatrick if ((sc->sc_shared_flags & BWFM_SHARED_INFO_HOSTRDY_DB1) == 0) 2134156d2677Spatrick return; 2135156d2677Spatrick 2136bb813cf8Spatrick if (bwfm->sc_chip.ch_chip == BRCM_CC_4378_CHIP_ID) 2137bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2138bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_H2D_MAILBOX_1, 1); 2139bb813cf8Spatrick else 2140156d2677Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2141156d2677Spatrick BWFM_PCI_PCIE2REG_H2D_MAILBOX_1, 1); 2142156d2677Spatrick } 2143156d2677Spatrick 2144e5ec1e72Spatrick /* Msgbuf protocol implementation */ 2145e5ec1e72Spatrick int 2146e5ec1e72Spatrick bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *bwfm, int ifidx, 2147e5ec1e72Spatrick int cmd, char *buf, size_t *len) 2148e5ec1e72Spatrick { 2149e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 2150e5ec1e72Spatrick struct msgbuf_ioctl_req_hdr *req; 21512eeba925Spatrick struct bwfm_pci_ioctl *ctl; 2152e5ec1e72Spatrick struct mbuf *m; 21532eeba925Spatrick uint32_t pktid; 21542eeba925Spatrick paddr_t paddr; 2155e5ec1e72Spatrick size_t buflen; 2156e272db29Spatrick int s; 2157e5ec1e72Spatrick 21582eeba925Spatrick buflen = min(*len, BWFM_DMA_H2D_IOCTL_BUF_LEN); 2159471f2571Sjan m = MCLGETL(NULL, M_DONTWAIT, buflen); 21602eeba925Spatrick if (m == NULL) 21612eeba925Spatrick return 1; 21622eeba925Spatrick m->m_len = m->m_pkthdr.len = buflen; 21632eeba925Spatrick 21642eeba925Spatrick if (buf) 21652eeba925Spatrick memcpy(mtod(m, char *), buf, buflen); 21662eeba925Spatrick else 21672eeba925Spatrick memset(mtod(m, char *), 0, buflen); 21682eeba925Spatrick 2169e272db29Spatrick s = splnet(); 2170e5ec1e72Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit); 2171e5ec1e72Spatrick if (req == NULL) { 2172e272db29Spatrick splx(s); 21732eeba925Spatrick m_freem(m); 2174e5ec1e72Spatrick return 1; 2175e5ec1e72Spatrick } 21762eeba925Spatrick 21772eeba925Spatrick if (bwfm_pci_pktid_new(sc, &sc->sc_ioctl_pkts, m, &pktid, &paddr)) { 21782eeba925Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1); 2179e272db29Spatrick splx(s); 21802eeba925Spatrick m_freem(m); 21812eeba925Spatrick return 1; 21822eeba925Spatrick } 21832eeba925Spatrick 21842eeba925Spatrick ctl = malloc(sizeof(*ctl), M_TEMP, M_WAITOK|M_ZERO); 21852eeba925Spatrick ctl->transid = sc->sc_ioctl_transid++; 21862eeba925Spatrick TAILQ_INSERT_TAIL(&sc->sc_ioctlq, ctl, next); 21872eeba925Spatrick 2188e5ec1e72Spatrick req->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ; 2189e5ec1e72Spatrick req->msg.ifidx = 0; 2190e5ec1e72Spatrick req->msg.flags = 0; 21912eeba925Spatrick req->msg.request_id = htole32(pktid); 2192e5ec1e72Spatrick req->cmd = htole32(cmd); 2193e5ec1e72Spatrick req->output_buf_len = htole16(*len); 21942eeba925Spatrick req->trans_id = htole16(ctl->transid); 2195e5ec1e72Spatrick 21962eeba925Spatrick req->input_buf_len = htole16(m->m_len); 21972eeba925Spatrick req->req_buf_addr.high_addr = htole32((uint64_t)paddr >> 32); 21982eeba925Spatrick req->req_buf_addr.low_addr = htole32(paddr & 0xffffffff); 2199dcb67343Spatrick 2200e5ec1e72Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit); 2201e272db29Spatrick splx(s); 2202e5ec1e72Spatrick 22038544fed6Smpi tsleep_nsec(ctl, PWAIT, "bwfm", SEC_TO_NSEC(1)); 22042eeba925Spatrick TAILQ_REMOVE(&sc->sc_ioctlq, ctl, next); 22052eeba925Spatrick 22062eeba925Spatrick if (ctl->m == NULL) { 22072eeba925Spatrick free(ctl, M_TEMP, sizeof(*ctl)); 2208e5ec1e72Spatrick return 1; 2209e5ec1e72Spatrick } 2210e5ec1e72Spatrick 22112eeba925Spatrick *len = min(ctl->retlen, m->m_len); 22122eeba925Spatrick *len = min(*len, buflen); 2213e5ec1e72Spatrick if (buf) 22145c7fed39Sdlg m_copydata(ctl->m, 0, *len, buf); 22152eeba925Spatrick m_freem(ctl->m); 2216e5ec1e72Spatrick 22172eeba925Spatrick if (ctl->status < 0) { 22182eeba925Spatrick free(ctl, M_TEMP, sizeof(*ctl)); 22192eeba925Spatrick return 1; 22202eeba925Spatrick } 22212eeba925Spatrick 22222eeba925Spatrick free(ctl, M_TEMP, sizeof(*ctl)); 2223e5ec1e72Spatrick return 0; 2224e5ec1e72Spatrick } 2225e5ec1e72Spatrick 2226e5ec1e72Spatrick int 2227e5ec1e72Spatrick bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *bwfm, int ifidx, 2228e5ec1e72Spatrick int cmd, char *buf, size_t len) 2229e5ec1e72Spatrick { 2230e5ec1e72Spatrick return bwfm_pci_msgbuf_query_dcmd(bwfm, ifidx, cmd, buf, &len); 2231e5ec1e72Spatrick } 22322eeba925Spatrick 22332eeba925Spatrick void 22342eeba925Spatrick bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *sc, 22352eeba925Spatrick struct msgbuf_ioctl_resp_hdr *resp) 22362eeba925Spatrick { 22372eeba925Spatrick struct bwfm_pci_ioctl *ctl, *tmp; 22382eeba925Spatrick struct mbuf *m; 22392eeba925Spatrick 22402eeba925Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts, 22412eeba925Spatrick letoh32(resp->msg.request_id)); 22422eeba925Spatrick 22432eeba925Spatrick TAILQ_FOREACH_SAFE(ctl, &sc->sc_ioctlq, next, tmp) { 22442eeba925Spatrick if (ctl->transid != letoh16(resp->trans_id)) 22452eeba925Spatrick continue; 22462eeba925Spatrick ctl->m = m; 22472eeba925Spatrick ctl->retlen = letoh16(resp->resp_len); 22482eeba925Spatrick ctl->status = letoh16(resp->compl_hdr.status); 22492eeba925Spatrick wakeup(ctl); 22502eeba925Spatrick return; 22512eeba925Spatrick } 22522eeba925Spatrick 2253cb2afc74Spatrick m_freem(m); 22542eeba925Spatrick } 2255