1*8bad4727Spatrick /* $OpenBSD: if_bwfm_pci.c,v 1.64 2021/12/27 17:56:03 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; 1871a93a9bdSpatrick 1881a93a9bdSpatrick uint8_t sc_mbdata_done; 189*8bad4727Spatrick uint8_t sc_pcireg64; 190e5ec1e72Spatrick }; 191e5ec1e72Spatrick 192e5ec1e72Spatrick struct bwfm_pci_dmamem { 193e5ec1e72Spatrick bus_dmamap_t bdm_map; 194e5ec1e72Spatrick bus_dma_segment_t bdm_seg; 195e5ec1e72Spatrick size_t bdm_size; 196e5ec1e72Spatrick caddr_t bdm_kva; 197e5ec1e72Spatrick }; 198e5ec1e72Spatrick 199e5ec1e72Spatrick #define BWFM_PCI_DMA_MAP(_bdm) ((_bdm)->bdm_map) 200e5ec1e72Spatrick #define BWFM_PCI_DMA_LEN(_bdm) ((_bdm)->bdm_size) 201e4dae658Spatrick #define BWFM_PCI_DMA_DVA(_bdm) ((uint64_t)(_bdm)->bdm_map->dm_segs[0].ds_addr) 202e5ec1e72Spatrick #define BWFM_PCI_DMA_KVA(_bdm) ((void *)(_bdm)->bdm_kva) 203e5ec1e72Spatrick 204e5ec1e72Spatrick int bwfm_pci_match(struct device *, void *, void *); 205e5ec1e72Spatrick void bwfm_pci_attach(struct device *, struct device *, void *); 206e5ec1e72Spatrick int bwfm_pci_detach(struct device *, int); 2071a93a9bdSpatrick int bwfm_pci_activate(struct device *, int); 2081a93a9bdSpatrick void bwfm_pci_cleanup(struct bwfm_pci_softc *); 209e5ec1e72Spatrick 210ed6d4272Spatrick #if defined(__HAVE_FDT) 211ed6d4272Spatrick int bwfm_pci_read_otp(struct bwfm_pci_softc *); 212ed6d4272Spatrick void bwfm_pci_process_otp_tuple(struct bwfm_pci_softc *, uint8_t, 213ed6d4272Spatrick uint8_t, uint8_t *); 214ed6d4272Spatrick #endif 215ed6d4272Spatrick 216e5ec1e72Spatrick int bwfm_pci_intr(void *); 217e5ec1e72Spatrick void bwfm_pci_intr_enable(struct bwfm_pci_softc *); 218e5ec1e72Spatrick void bwfm_pci_intr_disable(struct bwfm_pci_softc *); 219bb813cf8Spatrick uint32_t bwfm_pci_intr_status(struct bwfm_pci_softc *); 220bb813cf8Spatrick void bwfm_pci_intr_ack(struct bwfm_pci_softc *, uint32_t); 2211a93a9bdSpatrick uint32_t bwfm_pci_intmask(struct bwfm_pci_softc *); 222156d2677Spatrick void bwfm_pci_hostready(struct bwfm_pci_softc *); 223e5ec1e72Spatrick int bwfm_pci_load_microcode(struct bwfm_pci_softc *, const u_char *, 2246aad491fSpatrick size_t, const u_char *, size_t); 225e5ec1e72Spatrick void bwfm_pci_select_core(struct bwfm_pci_softc *, int ); 226e5ec1e72Spatrick 227e5ec1e72Spatrick struct bwfm_pci_dmamem * 228e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *, bus_size_t, 229e5ec1e72Spatrick bus_size_t); 230e5ec1e72Spatrick void bwfm_pci_dmamem_free(struct bwfm_pci_softc *, struct bwfm_pci_dmamem *); 23102ee7d07Spatrick int bwfm_pci_pktid_avail(struct bwfm_pci_softc *, 23202ee7d07Spatrick struct bwfm_pci_pkts *); 233e5ec1e72Spatrick int bwfm_pci_pktid_new(struct bwfm_pci_softc *, 234e5ec1e72Spatrick struct bwfm_pci_pkts *, struct mbuf *, 235e5ec1e72Spatrick uint32_t *, paddr_t *); 236e5ec1e72Spatrick struct mbuf * bwfm_pci_pktid_free(struct bwfm_pci_softc *, 237e5ec1e72Spatrick struct bwfm_pci_pkts *, uint32_t); 238e5ec1e72Spatrick void bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *, 239e5ec1e72Spatrick struct if_rxring *, uint32_t); 240e5ec1e72Spatrick void bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *); 241e5ec1e72Spatrick void bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *); 242e5ec1e72Spatrick int bwfm_pci_setup_ring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *, 243e5ec1e72Spatrick int, size_t, uint32_t, uint32_t, int, uint32_t, uint32_t *); 244518be5f3Spatrick int bwfm_pci_setup_flowring(struct bwfm_pci_softc *, struct bwfm_pci_msgring *, 245518be5f3Spatrick int, size_t); 246e5ec1e72Spatrick 247e5ec1e72Spatrick void bwfm_pci_ring_bell(struct bwfm_pci_softc *, 248e5ec1e72Spatrick struct bwfm_pci_msgring *); 249e5ec1e72Spatrick void bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *, 250e5ec1e72Spatrick struct bwfm_pci_msgring *); 251e5ec1e72Spatrick void bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *, 252e5ec1e72Spatrick struct bwfm_pci_msgring *); 253e5ec1e72Spatrick void bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *, 254e5ec1e72Spatrick struct bwfm_pci_msgring *); 255e5ec1e72Spatrick void bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *, 256e5ec1e72Spatrick struct bwfm_pci_msgring *); 257e5ec1e72Spatrick void * bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *, 258e5ec1e72Spatrick struct bwfm_pci_msgring *); 259e5ec1e72Spatrick void * bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *, 260e5ec1e72Spatrick struct bwfm_pci_msgring *, int, int *); 261e5ec1e72Spatrick void * bwfm_pci_ring_read_avail(struct bwfm_pci_softc *, 262e5ec1e72Spatrick struct bwfm_pci_msgring *, int *); 263e5ec1e72Spatrick void bwfm_pci_ring_read_commit(struct bwfm_pci_softc *, 264e5ec1e72Spatrick struct bwfm_pci_msgring *, int); 265e5ec1e72Spatrick void bwfm_pci_ring_write_commit(struct bwfm_pci_softc *, 266e5ec1e72Spatrick struct bwfm_pci_msgring *); 267e5ec1e72Spatrick void bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *, 268e5ec1e72Spatrick struct bwfm_pci_msgring *, int); 269e5ec1e72Spatrick 270e5ec1e72Spatrick void bwfm_pci_ring_rx(struct bwfm_pci_softc *, 2716f241297Spatrick struct bwfm_pci_msgring *, struct mbuf_list *); 2726f241297Spatrick void bwfm_pci_msg_rx(struct bwfm_pci_softc *, void *, 2736f241297Spatrick struct mbuf_list *); 274e5ec1e72Spatrick 275e5ec1e72Spatrick uint32_t bwfm_pci_buscore_read(struct bwfm_softc *, uint32_t); 276e5ec1e72Spatrick void bwfm_pci_buscore_write(struct bwfm_softc *, uint32_t, 277e5ec1e72Spatrick uint32_t); 278e5ec1e72Spatrick int bwfm_pci_buscore_prepare(struct bwfm_softc *); 279e5ec1e72Spatrick int bwfm_pci_buscore_reset(struct bwfm_softc *); 280e5ec1e72Spatrick void bwfm_pci_buscore_activate(struct bwfm_softc *, uint32_t); 281e5ec1e72Spatrick 282f67437f3Spatrick int bwfm_pci_flowring_lookup(struct bwfm_pci_softc *, 283f67437f3Spatrick struct mbuf *); 284f67437f3Spatrick void bwfm_pci_flowring_create(struct bwfm_pci_softc *, 285518be5f3Spatrick struct mbuf *); 286518be5f3Spatrick void bwfm_pci_flowring_create_cb(struct bwfm_softc *, void *); 287a2c6ff8bSpatrick void bwfm_pci_flowring_delete(struct bwfm_pci_softc *, int); 288b5553ee6Spatrick void bwfm_pci_flowring_delete_cb(struct bwfm_softc *, void *); 289518be5f3Spatrick 290972218f3Spatrick int bwfm_pci_preinit(struct bwfm_softc *); 291a2c6ff8bSpatrick void bwfm_pci_stop(struct bwfm_softc *); 29202ee7d07Spatrick int bwfm_pci_txcheck(struct bwfm_softc *); 293e5ec1e72Spatrick int bwfm_pci_txdata(struct bwfm_softc *, struct mbuf *); 294bbd71b0bSpatrick 2951a93a9bdSpatrick int bwfm_pci_send_mb_data(struct bwfm_pci_softc *, uint32_t); 2961a93a9bdSpatrick void bwfm_pci_handle_mb_data(struct bwfm_pci_softc *); 2971a93a9bdSpatrick 298bbd71b0bSpatrick #ifdef BWFM_DEBUG 299cadf5fcfSpatrick void bwfm_pci_debug_console(struct bwfm_pci_softc *); 300bbd71b0bSpatrick #endif 301e5ec1e72Spatrick 302e5ec1e72Spatrick int bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *, int, 303e5ec1e72Spatrick int, char *, size_t *); 304e5ec1e72Spatrick int bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *, int, 305e5ec1e72Spatrick int, char *, size_t); 3062eeba925Spatrick void bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *, 3072eeba925Spatrick struct msgbuf_ioctl_resp_hdr *); 308e5ec1e72Spatrick 309e5ec1e72Spatrick struct bwfm_buscore_ops bwfm_pci_buscore_ops = { 310e5ec1e72Spatrick .bc_read = bwfm_pci_buscore_read, 311e5ec1e72Spatrick .bc_write = bwfm_pci_buscore_write, 312e5ec1e72Spatrick .bc_prepare = bwfm_pci_buscore_prepare, 313e5ec1e72Spatrick .bc_reset = bwfm_pci_buscore_reset, 314e5ec1e72Spatrick .bc_setup = NULL, 315e5ec1e72Spatrick .bc_activate = bwfm_pci_buscore_activate, 316e5ec1e72Spatrick }; 317e5ec1e72Spatrick 318e5ec1e72Spatrick struct bwfm_bus_ops bwfm_pci_bus_ops = { 319972218f3Spatrick .bs_preinit = bwfm_pci_preinit, 320a2c6ff8bSpatrick .bs_stop = bwfm_pci_stop, 32102ee7d07Spatrick .bs_txcheck = bwfm_pci_txcheck, 322e5ec1e72Spatrick .bs_txdata = bwfm_pci_txdata, 323e5ec1e72Spatrick .bs_txctl = NULL, 324e5ec1e72Spatrick }; 325e5ec1e72Spatrick 326e5ec1e72Spatrick struct bwfm_proto_ops bwfm_pci_msgbuf_ops = { 327e5ec1e72Spatrick .proto_query_dcmd = bwfm_pci_msgbuf_query_dcmd, 328e5ec1e72Spatrick .proto_set_dcmd = bwfm_pci_msgbuf_set_dcmd, 32914c74651Spatrick .proto_rx = NULL, 330029d6dd5Spatrick .proto_rxctl = NULL, 331e5ec1e72Spatrick }; 332e5ec1e72Spatrick 333e5ec1e72Spatrick struct cfattach bwfm_pci_ca = { 334e5ec1e72Spatrick sizeof(struct bwfm_pci_softc), 335e5ec1e72Spatrick bwfm_pci_match, 336e5ec1e72Spatrick bwfm_pci_attach, 337e5ec1e72Spatrick bwfm_pci_detach, 3381a93a9bdSpatrick bwfm_pci_activate, 339e5ec1e72Spatrick }; 340e5ec1e72Spatrick 341e5ec1e72Spatrick static const struct pci_matchid bwfm_pci_devices[] = { 34282f0e660Sjcs { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4350 }, 34341d93ac2Spatrick { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4356 }, 34441d93ac2Spatrick { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43602 }, 345821fc986Spatrick { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4371 }, 3468e234c40Spatrick { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4378 }, 347e5ec1e72Spatrick }; 348e5ec1e72Spatrick 349e5ec1e72Spatrick int 350e5ec1e72Spatrick bwfm_pci_match(struct device *parent, void *match, void *aux) 351e5ec1e72Spatrick { 352e5ec1e72Spatrick return (pci_matchbyid(aux, bwfm_pci_devices, 353e5ec1e72Spatrick nitems(bwfm_pci_devices))); 354e5ec1e72Spatrick } 355e5ec1e72Spatrick 356e5ec1e72Spatrick void 357e5ec1e72Spatrick bwfm_pci_attach(struct device *parent, struct device *self, void *aux) 358e5ec1e72Spatrick { 359e5ec1e72Spatrick struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self; 360e5ec1e72Spatrick struct pci_attach_args *pa = (struct pci_attach_args *)aux; 361e5ec1e72Spatrick const char *intrstr; 362e5ec1e72Spatrick pci_intr_handle_t ih; 363e5ec1e72Spatrick 364e5ec1e72Spatrick if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x08, 365e5ec1e72Spatrick PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_tcm_iot, &sc->sc_tcm_ioh, 366e5ec1e72Spatrick NULL, &sc->sc_tcm_ios, 0)) { 367e5ec1e72Spatrick printf(": can't map bar1\n"); 368a08e9144Spatrick return; 369a08e9144Spatrick } 370a08e9144Spatrick 371a08e9144Spatrick if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x00, 372a08e9144Spatrick PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->sc_reg_iot, &sc->sc_reg_ioh, 373a08e9144Spatrick NULL, &sc->sc_reg_ios, 0)) { 374a08e9144Spatrick printf(": can't map bar0\n"); 375a08e9144Spatrick goto bar1; 376e5ec1e72Spatrick } 377e5ec1e72Spatrick 378e5ec1e72Spatrick sc->sc_pc = pa->pa_pc; 379e5ec1e72Spatrick sc->sc_tag = pa->pa_tag; 380e5ec1e72Spatrick sc->sc_id = pa->pa_id; 381e5ec1e72Spatrick sc->sc_dmat = pa->pa_dmat; 382e5ec1e72Spatrick 383e5ec1e72Spatrick /* Map and establish the interrupt. */ 384e5ec1e72Spatrick if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) { 385e5ec1e72Spatrick printf(": couldn't map interrupt\n"); 386a08e9144Spatrick goto bar0; 387e5ec1e72Spatrick } 388e5ec1e72Spatrick intrstr = pci_intr_string(pa->pa_pc, ih); 389e5ec1e72Spatrick 39014484acaSpatrick sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET, 391e5ec1e72Spatrick bwfm_pci_intr, sc, DEVNAME(sc)); 392e5ec1e72Spatrick if (sc->sc_ih == NULL) { 393e5ec1e72Spatrick printf(": couldn't establish interrupt"); 394e5ec1e72Spatrick if (intrstr != NULL) 395e5ec1e72Spatrick printf(" at %s", intrstr); 396e5ec1e72Spatrick printf("\n"); 397e5ec1e72Spatrick goto bar1; 398e5ec1e72Spatrick } 399e5ec1e72Spatrick printf(": %s\n", intrstr); 400e5ec1e72Spatrick 401db31205aSkettenis #if defined(__HAVE_FDT) 402db31205aSkettenis sc->sc_sc.sc_node = PCITAG_NODE(pa->pa_tag); 403da5a4af2Spatrick if (sc->sc_sc.sc_node) { 404da5a4af2Spatrick if (OF_getproplen(sc->sc_sc.sc_node, "brcm,cal-blob") > 0) { 405da5a4af2Spatrick sc->sc_sc.sc_calsize = OF_getproplen(sc->sc_sc.sc_node, 406da5a4af2Spatrick "brcm,cal-blob"); 407da5a4af2Spatrick sc->sc_sc.sc_cal = malloc(sc->sc_sc.sc_calsize, 408da5a4af2Spatrick M_DEVBUF, M_WAITOK); 409da5a4af2Spatrick OF_getprop(sc->sc_sc.sc_node, "brcm,cal-blob", 410da5a4af2Spatrick sc->sc_sc.sc_cal, sc->sc_sc.sc_calsize); 411da5a4af2Spatrick } 412da5a4af2Spatrick } 413db31205aSkettenis #endif 414db31205aSkettenis 415972218f3Spatrick sc->sc_sc.sc_bus_ops = &bwfm_pci_bus_ops; 416972218f3Spatrick sc->sc_sc.sc_proto_ops = &bwfm_pci_msgbuf_ops; 417972218f3Spatrick bwfm_attach(&sc->sc_sc); 418972218f3Spatrick config_mountroot(self, bwfm_attachhook); 419e5ec1e72Spatrick return; 420e5ec1e72Spatrick 421e5ec1e72Spatrick bar0: 422e5ec1e72Spatrick bus_space_unmap(sc->sc_reg_iot, sc->sc_reg_ioh, sc->sc_reg_ios); 423a08e9144Spatrick bar1: 424a08e9144Spatrick bus_space_unmap(sc->sc_tcm_iot, sc->sc_tcm_ioh, sc->sc_tcm_ios); 425e5ec1e72Spatrick } 426e5ec1e72Spatrick 427972218f3Spatrick int 428972218f3Spatrick bwfm_pci_preinit(struct bwfm_softc *bwfm) 429e5ec1e72Spatrick { 430972218f3Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 431e5ec1e72Spatrick struct bwfm_pci_ringinfo ringinfo; 4329ead8393Spatrick const char *chip = NULL; 43394e4747cSpatrick u_char *ucode, *nvram; 43494e4747cSpatrick size_t size, nvsize, nvlen; 435e5ec1e72Spatrick uint32_t d2h_w_idx_ptr, d2h_r_idx_ptr; 436e5ec1e72Spatrick uint32_t h2d_w_idx_ptr, h2d_r_idx_ptr; 437e5ec1e72Spatrick uint32_t idx_offset, reg; 438e5ec1e72Spatrick int i; 439e5ec1e72Spatrick 440972218f3Spatrick if (sc->sc_initialized) 441972218f3Spatrick return 0; 442972218f3Spatrick 443e5ec1e72Spatrick sc->sc_sc.sc_buscore_ops = &bwfm_pci_buscore_ops; 444e5ec1e72Spatrick if (bwfm_chip_attach(&sc->sc_sc) != 0) { 445e5ec1e72Spatrick printf("%s: cannot attach chip\n", DEVNAME(sc)); 446972218f3Spatrick return 1; 447e5ec1e72Spatrick } 448e5ec1e72Spatrick 449ed6d4272Spatrick #if defined(__HAVE_FDT) 450ed6d4272Spatrick if (bwfm_pci_read_otp(sc)) { 451ed6d4272Spatrick printf("%s: cannot read OTP\n", DEVNAME(sc)); 452ed6d4272Spatrick return 1; 453ed6d4272Spatrick } 454ed6d4272Spatrick #endif 455ed6d4272Spatrick 456e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2); 457e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 458e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGADDR, 0x4e0); 459e5ec1e72Spatrick reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 460e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA); 461e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 462e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA, reg); 463e5ec1e72Spatrick 464bb818c30Spatrick switch (bwfm->sc_chip.ch_chip) { 46518b3a1dcSpatrick case BRCM_CC_4350_CHIP_ID: 466bb818c30Spatrick if (bwfm->sc_chip.ch_chiprev <= 7) 4679ead8393Spatrick chip = "4350c2"; 468bb818c30Spatrick else 469bb818c30Spatrick chip = "4350"; 470bb818c30Spatrick break; 471bb818c30Spatrick case BRCM_CC_4355_CHIP_ID: 472bb818c30Spatrick chip = "4355c1"; 47318b3a1dcSpatrick break; 47441d93ac2Spatrick case BRCM_CC_4356_CHIP_ID: 4759ead8393Spatrick chip = "4356"; 47641d93ac2Spatrick break; 477bb818c30Spatrick case BRCM_CC_4364_CHIP_ID: 478bb818c30Spatrick if (bwfm->sc_chip.ch_chiprev <= 3) 479bb818c30Spatrick chip = "4364b2"; 480bb818c30Spatrick else 481bb818c30Spatrick chip = "4364b3"; 482bb818c30Spatrick break; 483e5ec1e72Spatrick case BRCM_CC_43602_CHIP_ID: 4849ead8393Spatrick chip = "43602"; 485e5ec1e72Spatrick break; 486821fc986Spatrick case BRCM_CC_4371_CHIP_ID: 4879ead8393Spatrick chip = "4371"; 488821fc986Spatrick break; 489bb818c30Spatrick case BRCM_CC_4377_CHIP_ID: 490bb818c30Spatrick chip = "4377b3"; 491bb818c30Spatrick break; 492c38a9bc9Spatrick case BRCM_CC_4378_CHIP_ID: 493c38a9bc9Spatrick chip = "4378"; 494c38a9bc9Spatrick break; 495bb818c30Spatrick case BRCM_CC_4387_CHIP_ID: 496bb818c30Spatrick chip = "4387c2"; 497bb818c30Spatrick break; 498e5ec1e72Spatrick default: 49918b3a1dcSpatrick printf("%s: unknown firmware for chip %s\n", 50018b3a1dcSpatrick DEVNAME(sc), bwfm->sc_chip.ch_name); 501972218f3Spatrick return 1; 502e5ec1e72Spatrick } 503e5ec1e72Spatrick 50494e4747cSpatrick if (bwfm_loadfirmware(bwfm, chip, "-pcie", &ucode, &size, 50594e4747cSpatrick &nvram, &nvsize, &nvlen) != 0) 506972218f3Spatrick return 1; 5076aad491fSpatrick 508e5ec1e72Spatrick /* Retrieve RAM size from firmware. */ 509e5ec1e72Spatrick if (size >= BWFM_RAMSIZE + 8) { 510e5ec1e72Spatrick uint32_t *ramsize = (uint32_t *)&ucode[BWFM_RAMSIZE]; 511e5ec1e72Spatrick if (letoh32(ramsize[0]) == BWFM_RAMSIZE_MAGIC) 512e5ec1e72Spatrick bwfm->sc_chip.ch_ramsize = letoh32(ramsize[1]); 513e5ec1e72Spatrick } 514e5ec1e72Spatrick 5156aad491fSpatrick if (bwfm_pci_load_microcode(sc, ucode, size, nvram, nvlen) != 0) { 516e5ec1e72Spatrick printf("%s: could not load microcode\n", 517e5ec1e72Spatrick DEVNAME(sc)); 518e5ec1e72Spatrick free(ucode, M_DEVBUF, size); 519b4e85b06Spatrick free(nvram, M_DEVBUF, nvsize); 520972218f3Spatrick return 1; 521e5ec1e72Spatrick } 522e5ec1e72Spatrick free(ucode, M_DEVBUF, size); 523b4e85b06Spatrick free(nvram, M_DEVBUF, nvsize); 524e5ec1e72Spatrick 525e5ec1e72Spatrick sc->sc_shared_flags = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 526e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_INFO); 527e5ec1e72Spatrick sc->sc_shared_version = sc->sc_shared_flags; 528e5ec1e72Spatrick if (sc->sc_shared_version > BWFM_SHARED_INFO_MAX_VERSION || 529e5ec1e72Spatrick sc->sc_shared_version < BWFM_SHARED_INFO_MIN_VERSION) { 530e5ec1e72Spatrick printf("%s: PCIe version %d unsupported\n", 531e5ec1e72Spatrick DEVNAME(sc), sc->sc_shared_version); 532972218f3Spatrick return 1; 533e5ec1e72Spatrick } 534e5ec1e72Spatrick 535c794abf2Spatrick sc->sc_dma_idx_sz = 0; 536e5ec1e72Spatrick if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_INDEX) { 537e5ec1e72Spatrick if (sc->sc_shared_flags & BWFM_SHARED_INFO_DMA_2B_IDX) 538e5ec1e72Spatrick sc->sc_dma_idx_sz = sizeof(uint16_t); 539e5ec1e72Spatrick else 540e5ec1e72Spatrick sc->sc_dma_idx_sz = sizeof(uint32_t); 541e5ec1e72Spatrick } 542e5ec1e72Spatrick 543e5ec1e72Spatrick /* Maximum RX data buffers in the ring. */ 544e5ec1e72Spatrick sc->sc_max_rxbufpost = bus_space_read_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 545e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_MAX_RXBUFPOST); 546e5ec1e72Spatrick if (sc->sc_max_rxbufpost == 0) 547e5ec1e72Spatrick sc->sc_max_rxbufpost = BWFM_SHARED_MAX_RXBUFPOST_DEFAULT; 548e5ec1e72Spatrick 549e5ec1e72Spatrick /* Alternative offset of data in a packet */ 550e5ec1e72Spatrick sc->sc_rx_dataoffset = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 551e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_RX_DATAOFFSET); 552e5ec1e72Spatrick 553e5ec1e72Spatrick /* For Power Management */ 554e5ec1e72Spatrick sc->sc_htod_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 555e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_HTOD_MB_DATA_ADDR); 556e5ec1e72Spatrick sc->sc_dtoh_mb_data_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 557e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DTOH_MB_DATA_ADDR); 558e5ec1e72Spatrick 559e5ec1e72Spatrick /* Ring information */ 560e5ec1e72Spatrick sc->sc_ring_info_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 561e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_RING_INFO_ADDR); 562e5ec1e72Spatrick 563e5ec1e72Spatrick /* Firmware's "dmesg" */ 564e5ec1e72Spatrick sc->sc_console_base_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 565e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_CONSOLE_ADDR); 566e5ec1e72Spatrick sc->sc_console_buf_addr = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 567e5ec1e72Spatrick sc->sc_console_base_addr + BWFM_CONSOLE_BUFADDR); 568e5ec1e72Spatrick sc->sc_console_buf_size = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 569e5ec1e72Spatrick sc->sc_console_base_addr + BWFM_CONSOLE_BUFSIZE); 570e5ec1e72Spatrick 571e5ec1e72Spatrick /* Read ring information. */ 572e5ec1e72Spatrick bus_space_read_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 573e5ec1e72Spatrick sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo)); 574e5ec1e72Spatrick 575e5ec1e72Spatrick if (sc->sc_shared_version >= 6) { 576e5ec1e72Spatrick sc->sc_max_submissionrings = le16toh(ringinfo.max_submissionrings); 577e5ec1e72Spatrick sc->sc_max_flowrings = le16toh(ringinfo.max_flowrings); 578e5ec1e72Spatrick sc->sc_max_completionrings = le16toh(ringinfo.max_completionrings); 579e5ec1e72Spatrick } else { 580e5ec1e72Spatrick sc->sc_max_submissionrings = le16toh(ringinfo.max_flowrings); 581e5ec1e72Spatrick sc->sc_max_flowrings = sc->sc_max_submissionrings - 582e5ec1e72Spatrick BWFM_NUM_TX_MSGRINGS; 583e5ec1e72Spatrick sc->sc_max_completionrings = BWFM_NUM_RX_MSGRINGS; 584e5ec1e72Spatrick } 585e5ec1e72Spatrick 586e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 587e5ec1e72Spatrick d2h_w_idx_ptr = letoh32(ringinfo.d2h_w_idx_ptr); 588e5ec1e72Spatrick d2h_r_idx_ptr = letoh32(ringinfo.d2h_r_idx_ptr); 589e5ec1e72Spatrick h2d_w_idx_ptr = letoh32(ringinfo.h2d_w_idx_ptr); 590e5ec1e72Spatrick h2d_r_idx_ptr = letoh32(ringinfo.h2d_r_idx_ptr); 591e5ec1e72Spatrick idx_offset = sizeof(uint32_t); 592e5ec1e72Spatrick } else { 593e5ec1e72Spatrick uint64_t address; 594e5ec1e72Spatrick 595e5ec1e72Spatrick /* Each TX/RX Ring has a Read and Write Ptr */ 596e5ec1e72Spatrick sc->sc_dma_idx_bufsz = (sc->sc_max_submissionrings + 597e5ec1e72Spatrick sc->sc_max_completionrings) * sc->sc_dma_idx_sz * 2; 598e5ec1e72Spatrick sc->sc_dma_idx_buf = bwfm_pci_dmamem_alloc(sc, 599e5ec1e72Spatrick sc->sc_dma_idx_bufsz, 8); 600e5ec1e72Spatrick if (sc->sc_dma_idx_buf == NULL) { 601e5ec1e72Spatrick /* XXX: Fallback to TCM? */ 602e5ec1e72Spatrick printf("%s: cannot allocate idx buf\n", 603e5ec1e72Spatrick DEVNAME(sc)); 604972218f3Spatrick return 1; 605e5ec1e72Spatrick } 606e5ec1e72Spatrick 607e5ec1e72Spatrick idx_offset = sc->sc_dma_idx_sz; 608e5ec1e72Spatrick h2d_w_idx_ptr = 0; 609e5ec1e72Spatrick address = BWFM_PCI_DMA_DVA(sc->sc_dma_idx_buf); 610e5ec1e72Spatrick ringinfo.h2d_w_idx_hostaddr_low = 611e5ec1e72Spatrick htole32(address & 0xffffffff); 612e5ec1e72Spatrick ringinfo.h2d_w_idx_hostaddr_high = 613e5ec1e72Spatrick htole32(address >> 32); 614e5ec1e72Spatrick 615e5ec1e72Spatrick h2d_r_idx_ptr = h2d_w_idx_ptr + 616e5ec1e72Spatrick sc->sc_max_submissionrings * idx_offset; 617e5ec1e72Spatrick address += sc->sc_max_submissionrings * idx_offset; 618e5ec1e72Spatrick ringinfo.h2d_r_idx_hostaddr_low = 619e5ec1e72Spatrick htole32(address & 0xffffffff); 620e5ec1e72Spatrick ringinfo.h2d_r_idx_hostaddr_high = 621e5ec1e72Spatrick htole32(address >> 32); 622e5ec1e72Spatrick 623e5ec1e72Spatrick d2h_w_idx_ptr = h2d_r_idx_ptr + 624e5ec1e72Spatrick sc->sc_max_submissionrings * idx_offset; 625e5ec1e72Spatrick address += sc->sc_max_submissionrings * idx_offset; 626e5ec1e72Spatrick ringinfo.d2h_w_idx_hostaddr_low = 627e5ec1e72Spatrick htole32(address & 0xffffffff); 628e5ec1e72Spatrick ringinfo.d2h_w_idx_hostaddr_high = 629e5ec1e72Spatrick htole32(address >> 32); 630e5ec1e72Spatrick 631e5ec1e72Spatrick d2h_r_idx_ptr = d2h_w_idx_ptr + 632e5ec1e72Spatrick sc->sc_max_completionrings * idx_offset; 633e5ec1e72Spatrick address += sc->sc_max_completionrings * idx_offset; 634e5ec1e72Spatrick ringinfo.d2h_r_idx_hostaddr_low = 635e5ec1e72Spatrick htole32(address & 0xffffffff); 636e5ec1e72Spatrick ringinfo.d2h_r_idx_hostaddr_high = 637e5ec1e72Spatrick htole32(address >> 32); 638e5ec1e72Spatrick 639e5ec1e72Spatrick bus_space_write_region_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 640e5ec1e72Spatrick sc->sc_ring_info_addr, (void *)&ringinfo, sizeof(ringinfo)); 641e5ec1e72Spatrick } 642e5ec1e72Spatrick 643e5ec1e72Spatrick uint32_t ring_mem_ptr = letoh32(ringinfo.ringmem); 644e5ec1e72Spatrick /* TX ctrl ring: Send ctrl buffers, send IOCTLs */ 645e5ec1e72Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_submit, 64, 40, 646e5ec1e72Spatrick h2d_w_idx_ptr, h2d_r_idx_ptr, 0, idx_offset, 647e5ec1e72Spatrick &ring_mem_ptr)) 648e5ec1e72Spatrick goto cleanup; 649e5ec1e72Spatrick /* TX rxpost ring: Send clean data mbufs for RX */ 6501c0efb8bSpatrick if (bwfm_pci_setup_ring(sc, &sc->sc_rxpost_submit, 1024, 32, 651e5ec1e72Spatrick h2d_w_idx_ptr, h2d_r_idx_ptr, 1, idx_offset, 652e5ec1e72Spatrick &ring_mem_ptr)) 653e5ec1e72Spatrick goto cleanup; 654e5ec1e72Spatrick /* RX completion rings: recv our filled buffers back */ 655e5ec1e72Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_ctrl_complete, 64, 24, 656e5ec1e72Spatrick d2h_w_idx_ptr, d2h_r_idx_ptr, 0, idx_offset, 657e5ec1e72Spatrick &ring_mem_ptr)) 658e5ec1e72Spatrick goto cleanup; 659095b0c44Spatrick if (bwfm_pci_setup_ring(sc, &sc->sc_tx_complete, 1024, 660095b0c44Spatrick sc->sc_shared_version >= 7 ? 24 : 16, 661e5ec1e72Spatrick d2h_w_idx_ptr, d2h_r_idx_ptr, 1, idx_offset, 662e5ec1e72Spatrick &ring_mem_ptr)) 663e5ec1e72Spatrick goto cleanup; 6641c0efb8bSpatrick if (bwfm_pci_setup_ring(sc, &sc->sc_rx_complete, 1024, 665095b0c44Spatrick sc->sc_shared_version >= 7 ? 40 : 32, 666e5ec1e72Spatrick d2h_w_idx_ptr, d2h_r_idx_ptr, 2, idx_offset, 667e5ec1e72Spatrick &ring_mem_ptr)) 668e5ec1e72Spatrick goto cleanup; 669e5ec1e72Spatrick 670e5ec1e72Spatrick /* Dynamic TX rings for actual data */ 671e5ec1e72Spatrick sc->sc_flowrings = malloc(sc->sc_max_flowrings * 672e5ec1e72Spatrick sizeof(struct bwfm_pci_msgring), M_DEVBUF, M_WAITOK | M_ZERO); 673518be5f3Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 674518be5f3Spatrick struct bwfm_pci_msgring *ring = &sc->sc_flowrings[i]; 675518be5f3Spatrick ring->w_idx_addr = h2d_w_idx_ptr + (i + 2) * idx_offset; 676518be5f3Spatrick ring->r_idx_addr = h2d_r_idx_ptr + (i + 2) * idx_offset; 677518be5f3Spatrick } 678e5ec1e72Spatrick 679e5ec1e72Spatrick /* Scratch and ring update buffers for firmware */ 680e5ec1e72Spatrick if ((sc->sc_scratch_buf = bwfm_pci_dmamem_alloc(sc, 681e5ec1e72Spatrick BWFM_DMA_D2H_SCRATCH_BUF_LEN, 8)) == NULL) 682e5ec1e72Spatrick goto cleanup; 683e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 684e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_LOW, 685e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) & 0xffffffff); 686e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 687e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_ADDR_HIGH, 688e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_scratch_buf) >> 32); 689e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 690e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_SCRATCH_LEN, 691e5ec1e72Spatrick BWFM_DMA_D2H_SCRATCH_BUF_LEN); 692e5ec1e72Spatrick 693e5ec1e72Spatrick if ((sc->sc_ringupd_buf = bwfm_pci_dmamem_alloc(sc, 694e5ec1e72Spatrick BWFM_DMA_D2H_RINGUPD_BUF_LEN, 8)) == NULL) 695e5ec1e72Spatrick goto cleanup; 696e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 697e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_LOW, 698e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) & 0xffffffff); 699e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 700e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_ADDR_HIGH, 701e5ec1e72Spatrick BWFM_PCI_DMA_DVA(sc->sc_ringupd_buf) >> 32); 702e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 703e5ec1e72Spatrick sc->sc_shared_address + BWFM_SHARED_DMA_RINGUPD_LEN, 704e5ec1e72Spatrick BWFM_DMA_D2H_RINGUPD_BUF_LEN); 705e5ec1e72Spatrick 706e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2); 707e5ec1e72Spatrick bwfm_pci_intr_enable(sc); 708156d2677Spatrick bwfm_pci_hostready(sc); 709e5ec1e72Spatrick 710e5ec1e72Spatrick /* Maps RX mbufs to a packet id and back. */ 711e5ec1e72Spatrick sc->sc_rx_pkts.npkt = BWFM_NUM_RX_PKTIDS; 712e5ec1e72Spatrick sc->sc_rx_pkts.pkts = malloc(BWFM_NUM_RX_PKTIDS * 713e5ec1e72Spatrick sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO); 714e5ec1e72Spatrick for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++) 7151950c5c5Spatrick bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_CTL_PKT_SIZE, 7161950c5c5Spatrick BWFM_NUM_RX_DESCS, MSGBUF_MAX_CTL_PKT_SIZE, 0, BUS_DMA_WAITOK, 717e5ec1e72Spatrick &sc->sc_rx_pkts.pkts[i].bb_map); 718e5ec1e72Spatrick 719e5ec1e72Spatrick /* Maps TX mbufs to a packet id and back. */ 720f416501bSpatrick sc->sc_tx_pkts.npkt = BWFM_NUM_TX_PKTIDS; 721e5ec1e72Spatrick sc->sc_tx_pkts.pkts = malloc(BWFM_NUM_TX_PKTIDS 722e5ec1e72Spatrick * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO); 723e5ec1e72Spatrick for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++) 724e5ec1e72Spatrick bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE, 725e5ec1e72Spatrick BWFM_NUM_TX_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK, 726e5ec1e72Spatrick &sc->sc_tx_pkts.pkts[i].bb_map); 727c794abf2Spatrick sc->sc_tx_pkts_full = 0; 728e5ec1e72Spatrick 7292eeba925Spatrick /* Maps IOCTL mbufs to a packet id and back. */ 7302eeba925Spatrick sc->sc_ioctl_pkts.npkt = BWFM_NUM_IOCTL_PKTIDS; 7312eeba925Spatrick sc->sc_ioctl_pkts.pkts = malloc(BWFM_NUM_IOCTL_PKTIDS 7322eeba925Spatrick * sizeof(struct bwfm_pci_buf), M_DEVBUF, M_WAITOK | M_ZERO); 7332eeba925Spatrick for (i = 0; i < BWFM_NUM_IOCTL_PKTIDS; i++) 7342eeba925Spatrick bus_dmamap_create(sc->sc_dmat, MSGBUF_MAX_PKT_SIZE, 7352eeba925Spatrick BWFM_NUM_IOCTL_DESCS, MSGBUF_MAX_PKT_SIZE, 0, BUS_DMA_WAITOK, 7362eeba925Spatrick &sc->sc_ioctl_pkts.pkts[i].bb_map); 7372eeba925Spatrick 73818722113Spatrick /* 73918722113Spatrick * For whatever reason, could also be a bug somewhere in this 74018722113Spatrick * driver, the firmware needs a bunch of RX buffers otherwise 7414ef2dd0fSpatrick * it won't send any RX complete messages. 74218722113Spatrick */ 7434ef2dd0fSpatrick if_rxr_init(&sc->sc_rxbuf_ring, min(256, sc->sc_max_rxbufpost), 7444ef2dd0fSpatrick sc->sc_max_rxbufpost); 745e5ec1e72Spatrick if_rxr_init(&sc->sc_ioctl_ring, 8, 8); 746e5ec1e72Spatrick if_rxr_init(&sc->sc_event_ring, 8, 8); 747e5ec1e72Spatrick bwfm_pci_fill_rx_rings(sc); 748e5ec1e72Spatrick 7492eeba925Spatrick TAILQ_INIT(&sc->sc_ioctlq); 7502eeba925Spatrick 751cadf5fcfSpatrick #ifdef BWFM_DEBUG 752cadf5fcfSpatrick sc->sc_console_readidx = 0; 753cadf5fcfSpatrick bwfm_pci_debug_console(sc); 754cadf5fcfSpatrick #endif 755cadf5fcfSpatrick 756972218f3Spatrick sc->sc_initialized = 1; 757972218f3Spatrick return 0; 758e5ec1e72Spatrick 759e5ec1e72Spatrick cleanup: 760e5ec1e72Spatrick if (sc->sc_ringupd_buf) 761e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf); 762e5ec1e72Spatrick if (sc->sc_scratch_buf) 763e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf); 764e5ec1e72Spatrick if (sc->sc_rx_complete.ring) 765e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring); 766e5ec1e72Spatrick if (sc->sc_tx_complete.ring) 767e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring); 768e5ec1e72Spatrick if (sc->sc_ctrl_complete.ring) 769e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring); 770e5ec1e72Spatrick if (sc->sc_rxpost_submit.ring) 771e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring); 772e5ec1e72Spatrick if (sc->sc_ctrl_submit.ring) 773e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring); 774e5ec1e72Spatrick if (sc->sc_dma_idx_buf) 775e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf); 776972218f3Spatrick return 1; 777e5ec1e72Spatrick } 778e5ec1e72Spatrick 779e5ec1e72Spatrick int 7806aad491fSpatrick bwfm_pci_load_microcode(struct bwfm_pci_softc *sc, const u_char *ucode, size_t size, 7816aad491fSpatrick const u_char *nvram, size_t nvlen) 782e5ec1e72Spatrick { 783e5ec1e72Spatrick struct bwfm_softc *bwfm = (void *)sc; 784e5ec1e72Spatrick struct bwfm_core *core; 7856aad491fSpatrick uint32_t shared, written; 786e5ec1e72Spatrick int i; 787e5ec1e72Spatrick 788e5ec1e72Spatrick if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) { 789e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_ARM_CR4); 790e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 791e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKIDX, 5); 792e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 793e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKPDA, 0); 794e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 795e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKIDX, 7); 796e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 797e5ec1e72Spatrick BWFM_PCI_ARMCR4REG_BANKPDA, 0); 798e5ec1e72Spatrick } 799e5ec1e72Spatrick 800e5ec1e72Spatrick for (i = 0; i < size; i++) 801e5ec1e72Spatrick bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 802e5ec1e72Spatrick bwfm->sc_chip.ch_rambase + i, ucode[i]); 803e5ec1e72Spatrick 804e5ec1e72Spatrick /* Firmware replaces this with a pointer once up. */ 805e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 806e5ec1e72Spatrick bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4, 0); 807e5ec1e72Spatrick 8086aad491fSpatrick if (nvram) { 8096aad491fSpatrick for (i = 0; i < nvlen; i++) 8106aad491fSpatrick bus_space_write_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 8116aad491fSpatrick bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize 8126aad491fSpatrick - nvlen + i, nvram[i]); 8136aad491fSpatrick } 8146aad491fSpatrick 8156aad491fSpatrick written = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 8166aad491fSpatrick bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4); 817e5ec1e72Spatrick 818e5ec1e72Spatrick /* Load reset vector from firmware and kickstart core. */ 819b0cd4990Spatrick if (bwfm->sc_chip.ch_chip == BRCM_CC_43602_CHIP_ID) { 820e5ec1e72Spatrick core = bwfm_chip_get_core(bwfm, BWFM_AGENT_INTERNAL_MEM); 821e5ec1e72Spatrick bwfm->sc_chip.ch_core_reset(bwfm, core, 0, 0, 0); 822b0cd4990Spatrick } 823e5ec1e72Spatrick bwfm_chip_set_active(bwfm, *(uint32_t *)ucode); 824e5ec1e72Spatrick 8253c53ddefSpatrick for (i = 0; i < 100; i++) { 826e5ec1e72Spatrick delay(50 * 1000); 827e5ec1e72Spatrick shared = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 828e5ec1e72Spatrick bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize - 4); 8296aad491fSpatrick if (shared != written) 830e5ec1e72Spatrick break; 831e5ec1e72Spatrick } 83219871452Spatrick if (shared == written) { 833e5ec1e72Spatrick printf("%s: firmware did not come up\n", DEVNAME(sc)); 834e5ec1e72Spatrick return 1; 835e5ec1e72Spatrick } 83619871452Spatrick if (shared < bwfm->sc_chip.ch_rambase || 83719871452Spatrick shared >= bwfm->sc_chip.ch_rambase + bwfm->sc_chip.ch_ramsize) { 83819871452Spatrick printf("%s: invalid shared RAM address 0x%08x\n", DEVNAME(sc), 83919871452Spatrick shared); 84019871452Spatrick return 1; 84119871452Spatrick } 842e5ec1e72Spatrick 843e5ec1e72Spatrick sc->sc_shared_address = shared; 844e5ec1e72Spatrick return 0; 845e5ec1e72Spatrick } 846e5ec1e72Spatrick 847e5ec1e72Spatrick int 848e5ec1e72Spatrick bwfm_pci_detach(struct device *self, int flags) 849e5ec1e72Spatrick { 850e5ec1e72Spatrick struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self; 851e5ec1e72Spatrick 852e5ec1e72Spatrick bwfm_detach(&sc->sc_sc, flags); 8531a93a9bdSpatrick bwfm_pci_cleanup(sc); 8541a93a9bdSpatrick 8551a93a9bdSpatrick return 0; 8561a93a9bdSpatrick } 8571a93a9bdSpatrick 8581a93a9bdSpatrick void 8591a93a9bdSpatrick bwfm_pci_cleanup(struct bwfm_pci_softc *sc) 8601a93a9bdSpatrick { 8611a93a9bdSpatrick int i; 862e5ec1e72Spatrick 86364ae3612Spatrick for (i = 0; i < BWFM_NUM_RX_PKTIDS; i++) { 86464ae3612Spatrick bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_pkts.pkts[i].bb_map); 86564ae3612Spatrick if (sc->sc_rx_pkts.pkts[i].bb_m) 86664ae3612Spatrick m_freem(sc->sc_rx_pkts.pkts[i].bb_m); 86764ae3612Spatrick } 86864ae3612Spatrick free(sc->sc_rx_pkts.pkts, M_DEVBUF, BWFM_NUM_RX_PKTIDS * 86964ae3612Spatrick sizeof(struct bwfm_pci_buf)); 87064ae3612Spatrick 87164ae3612Spatrick for (i = 0; i < BWFM_NUM_TX_PKTIDS; i++) { 87264ae3612Spatrick bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_pkts.pkts[i].bb_map); 87364ae3612Spatrick if (sc->sc_tx_pkts.pkts[i].bb_m) 87464ae3612Spatrick m_freem(sc->sc_tx_pkts.pkts[i].bb_m); 87564ae3612Spatrick } 87664ae3612Spatrick free(sc->sc_tx_pkts.pkts, M_DEVBUF, BWFM_NUM_TX_PKTIDS * 87764ae3612Spatrick sizeof(struct bwfm_pci_buf)); 87864ae3612Spatrick 87964ae3612Spatrick for (i = 0; i < BWFM_NUM_IOCTL_PKTIDS; i++) { 88064ae3612Spatrick bus_dmamap_destroy(sc->sc_dmat, sc->sc_ioctl_pkts.pkts[i].bb_map); 88164ae3612Spatrick if (sc->sc_ioctl_pkts.pkts[i].bb_m) 88264ae3612Spatrick m_freem(sc->sc_ioctl_pkts.pkts[i].bb_m); 88364ae3612Spatrick } 88464ae3612Spatrick free(sc->sc_ioctl_pkts.pkts, M_DEVBUF, BWFM_NUM_IOCTL_PKTIDS * 88564ae3612Spatrick sizeof(struct bwfm_pci_buf)); 88664ae3612Spatrick 88764ae3612Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 88864ae3612Spatrick if (sc->sc_flowrings[i].status >= RING_OPEN) 88964ae3612Spatrick bwfm_pci_dmamem_free(sc, sc->sc_flowrings[i].ring); 89064ae3612Spatrick } 89164ae3612Spatrick free(sc->sc_flowrings, M_DEVBUF, sc->sc_max_flowrings * 89264ae3612Spatrick sizeof(struct bwfm_pci_msgring)); 893e5ec1e72Spatrick 894e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ringupd_buf); 895e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_scratch_buf); 896e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rx_complete.ring); 897e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_tx_complete.ring); 898e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_complete.ring); 899e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_rxpost_submit.ring); 900e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_ctrl_submit.ring); 90164ae3612Spatrick if (sc->sc_dma_idx_buf) { 902e5ec1e72Spatrick bwfm_pci_dmamem_free(sc, sc->sc_dma_idx_buf); 90364ae3612Spatrick sc->sc_dma_idx_buf = NULL; 90464ae3612Spatrick } 90564ae3612Spatrick 90664ae3612Spatrick sc->sc_initialized = 0; 9071a93a9bdSpatrick } 9081a93a9bdSpatrick 9091a93a9bdSpatrick int 9101a93a9bdSpatrick bwfm_pci_activate(struct device *self, int act) 9111a93a9bdSpatrick { 9121a93a9bdSpatrick struct bwfm_pci_softc *sc = (struct bwfm_pci_softc *)self; 9131a93a9bdSpatrick struct bwfm_softc *bwfm = (void *)sc; 9141a93a9bdSpatrick int error = 0; 9151a93a9bdSpatrick 9161a93a9bdSpatrick switch (act) { 9171a93a9bdSpatrick case DVACT_QUIESCE: 9181a93a9bdSpatrick error = bwfm_activate(bwfm, act); 9191a93a9bdSpatrick if (error) 9201a93a9bdSpatrick return error; 9211a93a9bdSpatrick if (sc->sc_initialized) { 9221a93a9bdSpatrick sc->sc_mbdata_done = 0; 9231a93a9bdSpatrick error = bwfm_pci_send_mb_data(sc, 9241a93a9bdSpatrick BWFM_PCI_H2D_HOST_D3_INFORM); 9251a93a9bdSpatrick if (error) 9261a93a9bdSpatrick return error; 9271a93a9bdSpatrick tsleep_nsec(&sc->sc_mbdata_done, PCATCH, 9281a93a9bdSpatrick DEVNAME(sc), SEC_TO_NSEC(2)); 9291a93a9bdSpatrick if (!sc->sc_mbdata_done) 9301a93a9bdSpatrick return ETIMEDOUT; 9311a93a9bdSpatrick } 9321a93a9bdSpatrick break; 9331a93a9bdSpatrick case DVACT_WAKEUP: 9341a93a9bdSpatrick if (sc->sc_initialized) { 9351a93a9bdSpatrick /* If device can't be resumed, re-init. */ 9361a93a9bdSpatrick if (bwfm_pci_intmask(sc) == 0 || 9371a93a9bdSpatrick bwfm_pci_send_mb_data(sc, 9381a93a9bdSpatrick BWFM_PCI_H2D_HOST_D0_INFORM) != 0) { 9391a93a9bdSpatrick bwfm_cleanup(bwfm); 9401a93a9bdSpatrick bwfm_pci_cleanup(sc); 9411a93a9bdSpatrick } 9421a93a9bdSpatrick } 9431a93a9bdSpatrick error = bwfm_activate(bwfm, act); 9441a93a9bdSpatrick if (error) 9451a93a9bdSpatrick return error; 9461a93a9bdSpatrick break; 9471a93a9bdSpatrick default: 9481a93a9bdSpatrick break; 9491a93a9bdSpatrick } 9501a93a9bdSpatrick 951e5ec1e72Spatrick return 0; 952e5ec1e72Spatrick } 953e5ec1e72Spatrick 954ed6d4272Spatrick #if defined(__HAVE_FDT) 955ed6d4272Spatrick int 956ed6d4272Spatrick bwfm_pci_read_otp(struct bwfm_pci_softc *sc) 957ed6d4272Spatrick { 958ed6d4272Spatrick struct bwfm_softc *bwfm = (void *)sc; 959ed6d4272Spatrick struct bwfm_core *core; 960ea92f6c3Spatrick uint32_t coreid, base, words; 961ea92f6c3Spatrick uint32_t page, offset, sromctl; 962ea92f6c3Spatrick uint8_t *otp; 963ed6d4272Spatrick int i; 964ed6d4272Spatrick 965ea92f6c3Spatrick switch (bwfm->sc_chip.ch_chip) { 966ea92f6c3Spatrick case BRCM_CC_4355_CHIP_ID: 967ea92f6c3Spatrick coreid = BWFM_AGENT_CORE_CHIPCOMMON; 968ea92f6c3Spatrick base = 0x8c0; 969ea92f6c3Spatrick words = 0xb2; 970ea92f6c3Spatrick break; 971ea92f6c3Spatrick case BRCM_CC_4364_CHIP_ID: 972ea92f6c3Spatrick coreid = BWFM_AGENT_CORE_CHIPCOMMON; 973ea92f6c3Spatrick base = 0x8c0; 974ea92f6c3Spatrick words = 0x1a0; 975ea92f6c3Spatrick break; 976ea92f6c3Spatrick case BRCM_CC_4377_CHIP_ID: 977ea92f6c3Spatrick case BRCM_CC_4378_CHIP_ID: 978ea92f6c3Spatrick coreid = BWFM_AGENT_CORE_GCI; 979ea92f6c3Spatrick base = 0x1120; 980ea92f6c3Spatrick words = 0x170; 981ea92f6c3Spatrick break; 982ea92f6c3Spatrick case BRCM_CC_4387_CHIP_ID: 983ea92f6c3Spatrick coreid = BWFM_AGENT_CORE_GCI; 984ea92f6c3Spatrick base = 0x113c; 985ea92f6c3Spatrick words = 0x170; 986ea92f6c3Spatrick break; 987ea92f6c3Spatrick default: 988ed6d4272Spatrick return 0; 989ea92f6c3Spatrick } 990ed6d4272Spatrick 991ea92f6c3Spatrick core = bwfm_chip_get_core(bwfm, coreid); 992ed6d4272Spatrick if (core == NULL) 993ed6d4272Spatrick return 1; 994ed6d4272Spatrick 995ea92f6c3Spatrick /* Map OTP to shadow area */ 996ea92f6c3Spatrick if (coreid == BWFM_AGENT_CORE_CHIPCOMMON) { 997ea92f6c3Spatrick bwfm_pci_select_core(sc, coreid); 998ea92f6c3Spatrick sromctl = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 999ea92f6c3Spatrick BWFM_CHIP_REG_SROMCONTROL); 1000ed6d4272Spatrick 1001ea92f6c3Spatrick if (!(sromctl & BWFM_CHIP_REG_SROMCONTROL_OTP_PRESENT)) 1002ea92f6c3Spatrick return 0; 1003ea92f6c3Spatrick 1004ea92f6c3Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1005ea92f6c3Spatrick BWFM_CHIP_REG_SROMCONTROL, sromctl | 1006ea92f6c3Spatrick BWFM_CHIP_REG_SROMCONTROL_OTPSEL); 1007ed6d4272Spatrick } 1008ea92f6c3Spatrick 1009ea92f6c3Spatrick /* Map bus window to SROM/OTP shadow area */ 1010ea92f6c3Spatrick page = (core->co_base + base) & ~(BWFM_PCI_BAR0_REG_SIZE - 1); 1011ea92f6c3Spatrick offset = (core->co_base + base) & (BWFM_PCI_BAR0_REG_SIZE - 1); 1012ea92f6c3Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page); 1013ea92f6c3Spatrick 1014ea92f6c3Spatrick otp = mallocarray(words, sizeof(uint16_t), M_TEMP, M_WAITOK); 1015ea92f6c3Spatrick for (i = 0; i < words; i++) 1016ea92f6c3Spatrick ((uint16_t *)otp)[i] = bus_space_read_2(sc->sc_reg_iot, 1017ea92f6c3Spatrick sc->sc_reg_ioh, offset + i * sizeof(uint16_t)); 1018ea92f6c3Spatrick 1019ea92f6c3Spatrick /* Unmap OTP */ 1020ea92f6c3Spatrick if (coreid == BWFM_AGENT_CORE_CHIPCOMMON) { 1021ea92f6c3Spatrick bwfm_pci_select_core(sc, coreid); 1022ea92f6c3Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1023ea92f6c3Spatrick BWFM_CHIP_REG_SROMCONTROL, sromctl); 1024ea92f6c3Spatrick } 1025ea92f6c3Spatrick 1026ea92f6c3Spatrick for (i = 0; i < (words * sizeof(uint16_t)) - 1; i += otp[i + 1]) { 1027ea92f6c3Spatrick if (otp[i + 0] == 0) 1028ea92f6c3Spatrick break; 1029ea92f6c3Spatrick if (i + otp[i + 1] > words * sizeof(uint16_t)) 1030ed6d4272Spatrick break; 1031ed6d4272Spatrick bwfm_pci_process_otp_tuple(sc, otp[i + 0], otp[i + 1], 1032ed6d4272Spatrick &otp[i + 2]); 1033ed6d4272Spatrick } 1034ed6d4272Spatrick 1035ea92f6c3Spatrick free(otp, M_TEMP, words * sizeof(uint16_t)); 1036ed6d4272Spatrick return 0; 1037ed6d4272Spatrick } 1038ed6d4272Spatrick 1039ed6d4272Spatrick void 1040ed6d4272Spatrick bwfm_pci_process_otp_tuple(struct bwfm_pci_softc *sc, uint8_t type, uint8_t size, 1041ed6d4272Spatrick uint8_t *data) 1042ed6d4272Spatrick { 1043ed6d4272Spatrick struct bwfm_softc *bwfm = (void *)sc; 1044ed6d4272Spatrick char chiprev[8] = "", module[8] = "", modrev[8] = "", vendor[8] = "", chip[8] = ""; 1045ed6d4272Spatrick char product[16] = "unknown"; 104692fbeeb7Spatrick int len; 1047ed6d4272Spatrick 1048ed6d4272Spatrick switch (type) { 1049ed6d4272Spatrick case 0x15: /* system vendor OTP */ 1050ed6d4272Spatrick DPRINTF(("%s: system vendor OTP\n", DEVNAME(sc))); 1051ed6d4272Spatrick if (size < sizeof(uint32_t)) 1052ed6d4272Spatrick return; 1053ed6d4272Spatrick if (data[0] != 0x08 || data[1] != 0x00 || 1054ed6d4272Spatrick data[2] != 0x00 || data[3] != 0x00) 1055ed6d4272Spatrick return; 1056ed6d4272Spatrick size -= sizeof(uint32_t); 1057ed6d4272Spatrick data += sizeof(uint32_t); 1058ed6d4272Spatrick while (size) { 1059ed6d4272Spatrick /* reached end */ 1060ed6d4272Spatrick if (data[0] == 0xff) 1061ed6d4272Spatrick break; 1062ed6d4272Spatrick for (len = 0; len < size; len++) 1063ed6d4272Spatrick if (data[len] == 0x00 || data[len] == ' ' || 1064ed6d4272Spatrick data[len] == 0xff) 1065ed6d4272Spatrick break; 1066ed6d4272Spatrick if (len < 3 || len > 9) /* X=abcdef */ 1067ed6d4272Spatrick goto next; 1068ed6d4272Spatrick if (data[1] != '=') 1069ed6d4272Spatrick goto next; 1070ed6d4272Spatrick /* NULL-terminate string */ 1071ed6d4272Spatrick if (data[len] == ' ') 1072ed6d4272Spatrick data[len] = '\0'; 1073ed6d4272Spatrick switch (data[0]) { 1074ed6d4272Spatrick case 's': 1075ed6d4272Spatrick strlcpy(chiprev, &data[2], sizeof(chiprev)); 1076ed6d4272Spatrick break; 1077ed6d4272Spatrick case 'M': 1078ed6d4272Spatrick strlcpy(module, &data[2], sizeof(module)); 1079ed6d4272Spatrick break; 1080ed6d4272Spatrick case 'm': 1081ed6d4272Spatrick strlcpy(modrev, &data[2], sizeof(modrev)); 1082ed6d4272Spatrick break; 1083ed6d4272Spatrick case 'V': 1084ed6d4272Spatrick strlcpy(vendor, &data[2], sizeof(vendor)); 1085ed6d4272Spatrick break; 1086ed6d4272Spatrick } 1087ed6d4272Spatrick next: 1088ed6d4272Spatrick /* skip content */ 1089ed6d4272Spatrick data += len; 1090ed6d4272Spatrick size -= len; 1091ed6d4272Spatrick /* skip spacer tag */ 1092ed6d4272Spatrick if (size) { 1093ed6d4272Spatrick data++; 1094ed6d4272Spatrick size--; 1095ed6d4272Spatrick } 1096ed6d4272Spatrick } 1097ed6d4272Spatrick snprintf(chip, sizeof(chip), 1098ed6d4272Spatrick bwfm->sc_chip.ch_chip > 40000 ? "%05d" : "%04x", 1099ed6d4272Spatrick bwfm->sc_chip.ch_chip); 110092fbeeb7Spatrick if (sc->sc_sc.sc_node) 110192fbeeb7Spatrick OF_getprop(sc->sc_sc.sc_node, "apple,module-instance", 110292fbeeb7Spatrick product, sizeof(product)); 1103ed6d4272Spatrick printf("%s: firmware C-%s%s%s/P-%s_M-%s_V-%s__m-%s\n", 1104ed6d4272Spatrick DEVNAME(sc), chip, 1105ed6d4272Spatrick *chiprev ? "__s-" : "", *chiprev ? chiprev : "", 1106ed6d4272Spatrick product, module, vendor, modrev); 1107ed6d4272Spatrick break; 1108ed6d4272Spatrick case 0x80: /* Broadcom CIS */ 1109ed6d4272Spatrick DPRINTF(("%s: Broadcom CIS\n", DEVNAME(sc))); 1110ed6d4272Spatrick break; 1111ed6d4272Spatrick default: 1112ed6d4272Spatrick DPRINTF(("%s: unknown OTP tuple\n", DEVNAME(sc))); 1113ed6d4272Spatrick break; 1114ed6d4272Spatrick } 1115ed6d4272Spatrick } 1116ed6d4272Spatrick #endif 1117ed6d4272Spatrick 1118e5ec1e72Spatrick /* DMA code */ 1119e5ec1e72Spatrick struct bwfm_pci_dmamem * 1120e5ec1e72Spatrick bwfm_pci_dmamem_alloc(struct bwfm_pci_softc *sc, bus_size_t size, bus_size_t align) 1121e5ec1e72Spatrick { 1122e5ec1e72Spatrick struct bwfm_pci_dmamem *bdm; 1123e5ec1e72Spatrick int nsegs; 1124e5ec1e72Spatrick 1125e5ec1e72Spatrick bdm = malloc(sizeof(*bdm), M_DEVBUF, M_WAITOK | M_ZERO); 1126e5ec1e72Spatrick bdm->bdm_size = size; 1127e5ec1e72Spatrick 1128e5ec1e72Spatrick if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 1129e5ec1e72Spatrick BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &bdm->bdm_map) != 0) 1130e5ec1e72Spatrick goto bdmfree; 1131e5ec1e72Spatrick 1132e5ec1e72Spatrick if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &bdm->bdm_seg, 1, 1133e5ec1e72Spatrick &nsegs, BUS_DMA_WAITOK) != 0) 1134e5ec1e72Spatrick goto destroy; 1135e5ec1e72Spatrick 1136e5ec1e72Spatrick if (bus_dmamem_map(sc->sc_dmat, &bdm->bdm_seg, nsegs, size, 1137e5ec1e72Spatrick &bdm->bdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0) 1138e5ec1e72Spatrick goto free; 1139e5ec1e72Spatrick 1140e5ec1e72Spatrick if (bus_dmamap_load(sc->sc_dmat, bdm->bdm_map, bdm->bdm_kva, size, 1141e5ec1e72Spatrick NULL, BUS_DMA_WAITOK) != 0) 1142e5ec1e72Spatrick goto unmap; 1143e5ec1e72Spatrick 1144e5ec1e72Spatrick bzero(bdm->bdm_kva, size); 1145e5ec1e72Spatrick 1146e5ec1e72Spatrick return (bdm); 1147e5ec1e72Spatrick 1148e5ec1e72Spatrick unmap: 1149e5ec1e72Spatrick bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, size); 1150e5ec1e72Spatrick free: 1151e5ec1e72Spatrick bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1); 1152e5ec1e72Spatrick destroy: 1153e5ec1e72Spatrick bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map); 1154e5ec1e72Spatrick bdmfree: 115565046b40Spatrick free(bdm, M_DEVBUF, sizeof(*bdm)); 1156e5ec1e72Spatrick 1157e5ec1e72Spatrick return (NULL); 1158e5ec1e72Spatrick } 1159e5ec1e72Spatrick 1160e5ec1e72Spatrick void 1161e5ec1e72Spatrick bwfm_pci_dmamem_free(struct bwfm_pci_softc *sc, struct bwfm_pci_dmamem *bdm) 1162e5ec1e72Spatrick { 1163e5ec1e72Spatrick bus_dmamem_unmap(sc->sc_dmat, bdm->bdm_kva, bdm->bdm_size); 1164e5ec1e72Spatrick bus_dmamem_free(sc->sc_dmat, &bdm->bdm_seg, 1); 1165e5ec1e72Spatrick bus_dmamap_destroy(sc->sc_dmat, bdm->bdm_map); 116665046b40Spatrick free(bdm, M_DEVBUF, sizeof(*bdm)); 1167e5ec1e72Spatrick } 1168e5ec1e72Spatrick 1169e5ec1e72Spatrick /* 1170e5ec1e72Spatrick * We need a simple mapping from a packet ID to mbufs, because when 1171e5ec1e72Spatrick * a transfer completed, we only know the ID so we have to look up 1172e5ec1e72Spatrick * the memory for the ID. This simply looks for an empty slot. 1173e5ec1e72Spatrick */ 1174e5ec1e72Spatrick int 117502ee7d07Spatrick bwfm_pci_pktid_avail(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts) 117602ee7d07Spatrick { 117702ee7d07Spatrick int i, idx; 117802ee7d07Spatrick 117902ee7d07Spatrick idx = pkts->last + 1; 118002ee7d07Spatrick for (i = 0; i < pkts->npkt; i++) { 118102ee7d07Spatrick if (idx == pkts->npkt) 118202ee7d07Spatrick idx = 0; 118302ee7d07Spatrick if (pkts->pkts[idx].bb_m == NULL) 118402ee7d07Spatrick return 0; 118502ee7d07Spatrick idx++; 118602ee7d07Spatrick } 118702ee7d07Spatrick return ENOBUFS; 118802ee7d07Spatrick } 118902ee7d07Spatrick 119002ee7d07Spatrick int 1191e5ec1e72Spatrick bwfm_pci_pktid_new(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts, 1192e5ec1e72Spatrick struct mbuf *m, uint32_t *pktid, paddr_t *paddr) 1193e5ec1e72Spatrick { 1194e5ec1e72Spatrick int i, idx; 1195e5ec1e72Spatrick 1196e5ec1e72Spatrick idx = pkts->last + 1; 1197e5ec1e72Spatrick for (i = 0; i < pkts->npkt; i++) { 1198e5ec1e72Spatrick if (idx == pkts->npkt) 1199e5ec1e72Spatrick idx = 0; 1200e5ec1e72Spatrick if (pkts->pkts[idx].bb_m == NULL) { 1201e5ec1e72Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat, 1202e5ec1e72Spatrick pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) { 1203518be5f3Spatrick if (m_defrag(m, M_DONTWAIT)) 1204518be5f3Spatrick return EFBIG; 1205518be5f3Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat, 1206518be5f3Spatrick pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) 1207518be5f3Spatrick return EFBIG; 1208e5ec1e72Spatrick } 1209dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, pkts->pkts[idx].bb_map, 1210dcb67343Spatrick 0, pkts->pkts[idx].bb_map->dm_mapsize, 1211dcb67343Spatrick BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1212e5ec1e72Spatrick pkts->last = idx; 1213e5ec1e72Spatrick pkts->pkts[idx].bb_m = m; 1214e5ec1e72Spatrick *pktid = idx; 1215e5ec1e72Spatrick *paddr = pkts->pkts[idx].bb_map->dm_segs[0].ds_addr; 1216e5ec1e72Spatrick return 0; 1217e5ec1e72Spatrick } 1218e5ec1e72Spatrick idx++; 1219e5ec1e72Spatrick } 1220518be5f3Spatrick return ENOBUFS; 1221e5ec1e72Spatrick } 1222e5ec1e72Spatrick 1223e5ec1e72Spatrick struct mbuf * 1224e5ec1e72Spatrick bwfm_pci_pktid_free(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts, 1225e5ec1e72Spatrick uint32_t pktid) 1226e5ec1e72Spatrick { 1227e5ec1e72Spatrick struct mbuf *m; 1228e5ec1e72Spatrick 1229e5ec1e72Spatrick if (pktid >= pkts->npkt || pkts->pkts[pktid].bb_m == NULL) 1230e5ec1e72Spatrick return NULL; 1231dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, pkts->pkts[pktid].bb_map, 0, 1232dcb67343Spatrick pkts->pkts[pktid].bb_map->dm_mapsize, 1233dcb67343Spatrick BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1234e5ec1e72Spatrick bus_dmamap_unload(sc->sc_dmat, pkts->pkts[pktid].bb_map); 1235e5ec1e72Spatrick m = pkts->pkts[pktid].bb_m; 1236e5ec1e72Spatrick pkts->pkts[pktid].bb_m = NULL; 1237e5ec1e72Spatrick return m; 1238e5ec1e72Spatrick } 1239e5ec1e72Spatrick 1240e5ec1e72Spatrick void 1241e5ec1e72Spatrick bwfm_pci_fill_rx_rings(struct bwfm_pci_softc *sc) 1242e5ec1e72Spatrick { 124318722113Spatrick bwfm_pci_fill_rx_buf_ring(sc); 1244e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_ioctl_ring, 1245e5ec1e72Spatrick MSGBUF_TYPE_IOCTLRESP_BUF_POST); 1246e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(sc, &sc->sc_event_ring, 1247e5ec1e72Spatrick MSGBUF_TYPE_EVENT_BUF_POST); 1248e5ec1e72Spatrick } 1249e5ec1e72Spatrick 1250e5ec1e72Spatrick void 1251e5ec1e72Spatrick bwfm_pci_fill_rx_ioctl_ring(struct bwfm_pci_softc *sc, struct if_rxring *rxring, 1252e5ec1e72Spatrick uint32_t msgtype) 1253e5ec1e72Spatrick { 1254e5ec1e72Spatrick struct msgbuf_rx_ioctl_resp_or_event *req; 1255e5ec1e72Spatrick struct mbuf *m; 1256e5ec1e72Spatrick uint32_t pktid; 1257e5ec1e72Spatrick paddr_t paddr; 1258e5ec1e72Spatrick int s, slots; 1259e5ec1e72Spatrick 1260e5ec1e72Spatrick s = splnet(); 1261e5ec1e72Spatrick for (slots = if_rxr_get(rxring, 8); slots > 0; slots--) { 126202ee7d07Spatrick if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts)) 126302ee7d07Spatrick break; 1264e5ec1e72Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit); 1265e5ec1e72Spatrick if (req == NULL) 1266e5ec1e72Spatrick break; 12671950c5c5Spatrick m = MCLGETL(NULL, M_DONTWAIT, MSGBUF_MAX_CTL_PKT_SIZE); 1268e5ec1e72Spatrick if (m == NULL) { 1269e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1); 1270e5ec1e72Spatrick break; 1271e5ec1e72Spatrick } 12721950c5c5Spatrick m->m_len = m->m_pkthdr.len = MSGBUF_MAX_CTL_PKT_SIZE; 1273e5ec1e72Spatrick if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) { 1274e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1); 1275e5ec1e72Spatrick m_freem(m); 1276e5ec1e72Spatrick break; 1277e5ec1e72Spatrick } 1278e5ec1e72Spatrick memset(req, 0, sizeof(*req)); 1279e5ec1e72Spatrick req->msg.msgtype = msgtype; 1280e5ec1e72Spatrick req->msg.request_id = htole32(pktid); 12811950c5c5Spatrick req->host_buf_len = htole16(MSGBUF_MAX_CTL_PKT_SIZE); 1282e4dae658Spatrick req->host_buf_addr.high_addr = htole32((uint64_t)paddr >> 32); 1283e5ec1e72Spatrick req->host_buf_addr.low_addr = htole32(paddr & 0xffffffff); 1284e5ec1e72Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit); 1285e5ec1e72Spatrick } 1286e5ec1e72Spatrick if_rxr_put(rxring, slots); 1287e5ec1e72Spatrick splx(s); 1288e5ec1e72Spatrick } 1289e5ec1e72Spatrick 1290e5ec1e72Spatrick void 1291e5ec1e72Spatrick bwfm_pci_fill_rx_buf_ring(struct bwfm_pci_softc *sc) 1292e5ec1e72Spatrick { 1293e5ec1e72Spatrick struct msgbuf_rx_bufpost *req; 1294e5ec1e72Spatrick struct mbuf *m; 1295e5ec1e72Spatrick uint32_t pktid; 1296e5ec1e72Spatrick paddr_t paddr; 1297e5ec1e72Spatrick int s, slots; 1298e5ec1e72Spatrick 1299e5ec1e72Spatrick s = splnet(); 1300e5ec1e72Spatrick for (slots = if_rxr_get(&sc->sc_rxbuf_ring, sc->sc_max_rxbufpost); 1301e5ec1e72Spatrick slots > 0; slots--) { 130202ee7d07Spatrick if (bwfm_pci_pktid_avail(sc, &sc->sc_rx_pkts)) 130302ee7d07Spatrick break; 1304e5ec1e72Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_rxpost_submit); 1305e5ec1e72Spatrick if (req == NULL) 1306e5ec1e72Spatrick break; 1307471f2571Sjan m = MCLGETL(NULL, M_DONTWAIT, MSGBUF_MAX_PKT_SIZE); 1308e5ec1e72Spatrick if (m == NULL) { 1309e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1); 1310e5ec1e72Spatrick break; 1311e5ec1e72Spatrick } 1312e5ec1e72Spatrick m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE; 1313e5ec1e72Spatrick if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) { 1314e5ec1e72Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1); 1315e5ec1e72Spatrick m_freem(m); 1316e5ec1e72Spatrick break; 1317e5ec1e72Spatrick } 1318e5ec1e72Spatrick memset(req, 0, sizeof(*req)); 1319e5ec1e72Spatrick req->msg.msgtype = MSGBUF_TYPE_RXBUF_POST; 1320e5ec1e72Spatrick req->msg.request_id = htole32(pktid); 1321e5ec1e72Spatrick req->data_buf_len = htole16(MSGBUF_MAX_PKT_SIZE); 1322e4dae658Spatrick req->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32); 1323e5ec1e72Spatrick req->data_buf_addr.low_addr = htole32(paddr & 0xffffffff); 1324e5ec1e72Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_rxpost_submit); 1325e5ec1e72Spatrick } 1326e5ec1e72Spatrick if_rxr_put(&sc->sc_rxbuf_ring, slots); 1327e5ec1e72Spatrick splx(s); 1328e5ec1e72Spatrick } 1329e5ec1e72Spatrick 1330e5ec1e72Spatrick int 1331e5ec1e72Spatrick bwfm_pci_setup_ring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring, 1332e5ec1e72Spatrick int nitem, size_t itemsz, uint32_t w_idx, uint32_t r_idx, 1333e5ec1e72Spatrick int idx, uint32_t idx_off, uint32_t *ring_mem) 1334e5ec1e72Spatrick { 1335e5ec1e72Spatrick ring->w_idx_addr = w_idx + idx * idx_off; 1336e5ec1e72Spatrick ring->r_idx_addr = r_idx + idx * idx_off; 133713f544a8Spatrick ring->w_ptr = 0; 133813f544a8Spatrick ring->r_ptr = 0; 1339e5ec1e72Spatrick ring->nitem = nitem; 1340e5ec1e72Spatrick ring->itemsz = itemsz; 1341e5ec1e72Spatrick bwfm_pci_ring_write_rptr(sc, ring); 1342e5ec1e72Spatrick bwfm_pci_ring_write_wptr(sc, ring); 1343e5ec1e72Spatrick 1344e5ec1e72Spatrick ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8); 1345e5ec1e72Spatrick if (ring->ring == NULL) 1346e5ec1e72Spatrick return ENOMEM; 1347e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1348e5ec1e72Spatrick *ring_mem + BWFM_RING_MEM_BASE_ADDR_LOW, 1349e5ec1e72Spatrick BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff); 1350e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1351e5ec1e72Spatrick *ring_mem + BWFM_RING_MEM_BASE_ADDR_HIGH, 1352e5ec1e72Spatrick BWFM_PCI_DMA_DVA(ring->ring) >> 32); 1353e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1354e5ec1e72Spatrick *ring_mem + BWFM_RING_MAX_ITEM, nitem); 1355e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1356e5ec1e72Spatrick *ring_mem + BWFM_RING_LEN_ITEMS, itemsz); 1357e5ec1e72Spatrick *ring_mem = *ring_mem + BWFM_RING_MEM_SZ; 1358e5ec1e72Spatrick return 0; 1359e5ec1e72Spatrick } 1360e5ec1e72Spatrick 1361518be5f3Spatrick int 1362518be5f3Spatrick bwfm_pci_setup_flowring(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring, 1363518be5f3Spatrick int nitem, size_t itemsz) 1364518be5f3Spatrick { 1365518be5f3Spatrick ring->w_ptr = 0; 1366518be5f3Spatrick ring->r_ptr = 0; 1367518be5f3Spatrick ring->nitem = nitem; 1368518be5f3Spatrick ring->itemsz = itemsz; 1369518be5f3Spatrick bwfm_pci_ring_write_rptr(sc, ring); 1370518be5f3Spatrick bwfm_pci_ring_write_wptr(sc, ring); 1371518be5f3Spatrick 1372518be5f3Spatrick ring->ring = bwfm_pci_dmamem_alloc(sc, nitem * itemsz, 8); 1373518be5f3Spatrick if (ring->ring == NULL) 1374518be5f3Spatrick return ENOMEM; 1375518be5f3Spatrick return 0; 1376518be5f3Spatrick } 1377518be5f3Spatrick 1378e5ec1e72Spatrick /* Ring helpers */ 1379e5ec1e72Spatrick void 1380e5ec1e72Spatrick bwfm_pci_ring_bell(struct bwfm_pci_softc *sc, 1381e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1382e5ec1e72Spatrick { 1383*8bad4727Spatrick if (sc->sc_pcireg64) 1384bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1385bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_H2D_MAILBOX_0, 1); 1386bb813cf8Spatrick else 1387e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1388156d2677Spatrick BWFM_PCI_PCIE2REG_H2D_MAILBOX_0, 1); 1389e5ec1e72Spatrick } 1390e5ec1e72Spatrick 1391e5ec1e72Spatrick void 1392e5ec1e72Spatrick bwfm_pci_ring_update_rptr(struct bwfm_pci_softc *sc, 1393e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1394e5ec1e72Spatrick { 1395e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 1396e5ec1e72Spatrick ring->r_ptr = bus_space_read_2(sc->sc_tcm_iot, 1397e5ec1e72Spatrick sc->sc_tcm_ioh, ring->r_idx_addr); 1398e5ec1e72Spatrick } else { 1399dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, 1400dcb67343Spatrick BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr, 1401dcb67343Spatrick sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1402e5ec1e72Spatrick ring->r_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf) 1403e5ec1e72Spatrick + ring->r_idx_addr); 1404e5ec1e72Spatrick } 1405e5ec1e72Spatrick } 1406e5ec1e72Spatrick 1407e5ec1e72Spatrick void 1408e5ec1e72Spatrick bwfm_pci_ring_update_wptr(struct bwfm_pci_softc *sc, 1409e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1410e5ec1e72Spatrick { 1411e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 1412e5ec1e72Spatrick ring->w_ptr = bus_space_read_2(sc->sc_tcm_iot, 1413e5ec1e72Spatrick sc->sc_tcm_ioh, ring->w_idx_addr); 1414e5ec1e72Spatrick } else { 1415dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, 1416dcb67343Spatrick BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr, 1417dcb67343Spatrick sizeof(uint16_t), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1418e5ec1e72Spatrick ring->w_ptr = *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf) 1419e5ec1e72Spatrick + ring->w_idx_addr); 1420e5ec1e72Spatrick } 1421e5ec1e72Spatrick } 1422e5ec1e72Spatrick 1423e5ec1e72Spatrick void 1424e5ec1e72Spatrick bwfm_pci_ring_write_rptr(struct bwfm_pci_softc *sc, 1425e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1426e5ec1e72Spatrick { 1427e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 1428e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1429e5ec1e72Spatrick ring->r_idx_addr, ring->r_ptr); 1430e5ec1e72Spatrick } else { 1431e5ec1e72Spatrick *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf) 1432e5ec1e72Spatrick + ring->r_idx_addr) = ring->r_ptr; 1433dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, 1434dcb67343Spatrick BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->r_idx_addr, 1435dcb67343Spatrick sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1436e5ec1e72Spatrick } 1437e5ec1e72Spatrick } 1438e5ec1e72Spatrick 1439e5ec1e72Spatrick void 1440e5ec1e72Spatrick bwfm_pci_ring_write_wptr(struct bwfm_pci_softc *sc, 1441e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1442e5ec1e72Spatrick { 1443e5ec1e72Spatrick if (sc->sc_dma_idx_sz == 0) { 1444e5ec1e72Spatrick bus_space_write_2(sc->sc_tcm_iot, sc->sc_tcm_ioh, 1445e5ec1e72Spatrick ring->w_idx_addr, ring->w_ptr); 1446e5ec1e72Spatrick } else { 1447e5ec1e72Spatrick *(uint16_t *)(BWFM_PCI_DMA_KVA(sc->sc_dma_idx_buf) 1448e5ec1e72Spatrick + ring->w_idx_addr) = ring->w_ptr; 1449dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, 1450dcb67343Spatrick BWFM_PCI_DMA_MAP(sc->sc_dma_idx_buf), ring->w_idx_addr, 1451dcb67343Spatrick sizeof(uint16_t), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1452e5ec1e72Spatrick } 1453e5ec1e72Spatrick } 1454e5ec1e72Spatrick 1455e5ec1e72Spatrick /* 1456e5ec1e72Spatrick * Retrieve a free descriptor to put new stuff in, but don't commit 1457e5ec1e72Spatrick * to it yet so we can rollback later if any error occurs. 1458e5ec1e72Spatrick */ 1459e5ec1e72Spatrick void * 1460e5ec1e72Spatrick bwfm_pci_ring_write_reserve(struct bwfm_pci_softc *sc, 1461e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1462e5ec1e72Spatrick { 1463e5ec1e72Spatrick int available; 1464e5ec1e72Spatrick char *ret; 1465e5ec1e72Spatrick 1466e5ec1e72Spatrick bwfm_pci_ring_update_rptr(sc, ring); 1467e5ec1e72Spatrick 1468e5ec1e72Spatrick if (ring->r_ptr > ring->w_ptr) 1469e5ec1e72Spatrick available = ring->r_ptr - ring->w_ptr; 1470e5ec1e72Spatrick else 1471e5ec1e72Spatrick available = ring->r_ptr + (ring->nitem - ring->w_ptr); 1472e5ec1e72Spatrick 147330f5ada0Spatrick if (available <= 1) 1474e5ec1e72Spatrick return NULL; 1475e5ec1e72Spatrick 1476e5ec1e72Spatrick ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz); 1477e5ec1e72Spatrick ring->w_ptr += 1; 1478e5ec1e72Spatrick if (ring->w_ptr == ring->nitem) 1479e5ec1e72Spatrick ring->w_ptr = 0; 1480e5ec1e72Spatrick return ret; 1481e5ec1e72Spatrick } 1482e5ec1e72Spatrick 1483e5ec1e72Spatrick void * 1484e5ec1e72Spatrick bwfm_pci_ring_write_reserve_multi(struct bwfm_pci_softc *sc, 1485e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int count, int *avail) 1486e5ec1e72Spatrick { 1487e5ec1e72Spatrick int available; 1488e5ec1e72Spatrick char *ret; 1489e5ec1e72Spatrick 1490e5ec1e72Spatrick bwfm_pci_ring_update_rptr(sc, ring); 1491e5ec1e72Spatrick 1492e5ec1e72Spatrick if (ring->r_ptr > ring->w_ptr) 1493e5ec1e72Spatrick available = ring->r_ptr - ring->w_ptr; 1494e5ec1e72Spatrick else 1495e5ec1e72Spatrick available = ring->r_ptr + (ring->nitem - ring->w_ptr); 1496e5ec1e72Spatrick 149730f5ada0Spatrick if (available <= 1) 1498e5ec1e72Spatrick return NULL; 1499e5ec1e72Spatrick 1500e5ec1e72Spatrick ret = BWFM_PCI_DMA_KVA(ring->ring) + (ring->w_ptr * ring->itemsz); 1501e5ec1e72Spatrick *avail = min(count, available - 1); 1502e5ec1e72Spatrick if (*avail + ring->w_ptr > ring->nitem) 1503e5ec1e72Spatrick *avail = ring->nitem - ring->w_ptr; 1504e5ec1e72Spatrick ring->w_ptr += *avail; 1505e5ec1e72Spatrick if (ring->w_ptr == ring->nitem) 1506e5ec1e72Spatrick ring->w_ptr = 0; 1507e5ec1e72Spatrick return ret; 1508e5ec1e72Spatrick } 1509e5ec1e72Spatrick 1510e5ec1e72Spatrick /* 1511e5ec1e72Spatrick * Read number of descriptors available (submitted by the firmware) 1512e5ec1e72Spatrick * and retrieve pointer to first descriptor. 1513e5ec1e72Spatrick */ 1514e5ec1e72Spatrick void * 1515e5ec1e72Spatrick bwfm_pci_ring_read_avail(struct bwfm_pci_softc *sc, 1516e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int *avail) 1517e5ec1e72Spatrick { 1518e5ec1e72Spatrick bwfm_pci_ring_update_wptr(sc, ring); 1519e5ec1e72Spatrick 1520e5ec1e72Spatrick if (ring->w_ptr >= ring->r_ptr) 1521e5ec1e72Spatrick *avail = ring->w_ptr - ring->r_ptr; 1522e5ec1e72Spatrick else 1523e5ec1e72Spatrick *avail = ring->nitem - ring->r_ptr; 1524e5ec1e72Spatrick 1525e5ec1e72Spatrick if (*avail == 0) 1526e5ec1e72Spatrick return NULL; 1527e5ec1e72Spatrick 1528dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring), 1529dcb67343Spatrick ring->r_ptr * ring->itemsz, *avail * ring->itemsz, 1530dcb67343Spatrick BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1531e5ec1e72Spatrick return BWFM_PCI_DMA_KVA(ring->ring) + (ring->r_ptr * ring->itemsz); 1532e5ec1e72Spatrick } 1533e5ec1e72Spatrick 1534e5ec1e72Spatrick /* 1535e5ec1e72Spatrick * Let firmware know we read N descriptors. 1536e5ec1e72Spatrick */ 1537e5ec1e72Spatrick void 1538e5ec1e72Spatrick bwfm_pci_ring_read_commit(struct bwfm_pci_softc *sc, 1539e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int nitem) 1540e5ec1e72Spatrick { 1541e5ec1e72Spatrick ring->r_ptr += nitem; 1542e5ec1e72Spatrick if (ring->r_ptr == ring->nitem) 1543e5ec1e72Spatrick ring->r_ptr = 0; 1544e5ec1e72Spatrick bwfm_pci_ring_write_rptr(sc, ring); 1545e5ec1e72Spatrick } 1546e5ec1e72Spatrick 1547e5ec1e72Spatrick /* 1548e5ec1e72Spatrick * Let firmware know that we submitted some descriptors. 1549e5ec1e72Spatrick */ 1550e5ec1e72Spatrick void 1551e5ec1e72Spatrick bwfm_pci_ring_write_commit(struct bwfm_pci_softc *sc, 1552e5ec1e72Spatrick struct bwfm_pci_msgring *ring) 1553e5ec1e72Spatrick { 1554dcb67343Spatrick bus_dmamap_sync(sc->sc_dmat, BWFM_PCI_DMA_MAP(ring->ring), 1555dcb67343Spatrick 0, BWFM_PCI_DMA_LEN(ring->ring), BUS_DMASYNC_PREREAD | 1556dcb67343Spatrick BUS_DMASYNC_PREWRITE); 1557e5ec1e72Spatrick bwfm_pci_ring_write_wptr(sc, ring); 1558e5ec1e72Spatrick bwfm_pci_ring_bell(sc, ring); 1559e5ec1e72Spatrick } 1560e5ec1e72Spatrick 1561e5ec1e72Spatrick /* 1562e5ec1e72Spatrick * Rollback N descriptors in case we don't actually want 1563e5ec1e72Spatrick * to commit to it. 1564e5ec1e72Spatrick */ 1565e5ec1e72Spatrick void 1566e5ec1e72Spatrick bwfm_pci_ring_write_cancel(struct bwfm_pci_softc *sc, 1567e5ec1e72Spatrick struct bwfm_pci_msgring *ring, int nitem) 1568e5ec1e72Spatrick { 1569e5ec1e72Spatrick if (ring->w_ptr == 0) 1570e5ec1e72Spatrick ring->w_ptr = ring->nitem - nitem; 1571e5ec1e72Spatrick else 1572e5ec1e72Spatrick ring->w_ptr -= nitem; 1573e5ec1e72Spatrick } 1574e5ec1e72Spatrick 1575e5ec1e72Spatrick /* 1576e5ec1e72Spatrick * Foreach written descriptor on the ring, pass the descriptor to 1577e5ec1e72Spatrick * a message handler and let the firmware know we handled it. 1578e5ec1e72Spatrick */ 1579e5ec1e72Spatrick void 15806f241297Spatrick bwfm_pci_ring_rx(struct bwfm_pci_softc *sc, struct bwfm_pci_msgring *ring, 15816f241297Spatrick struct mbuf_list *ml) 1582e5ec1e72Spatrick { 1583e5ec1e72Spatrick void *buf; 1584e5ec1e72Spatrick int avail, processed; 1585e5ec1e72Spatrick 1586e5ec1e72Spatrick again: 1587e5ec1e72Spatrick buf = bwfm_pci_ring_read_avail(sc, ring, &avail); 1588e5ec1e72Spatrick if (buf == NULL) 1589e5ec1e72Spatrick return; 1590e5ec1e72Spatrick 1591e5ec1e72Spatrick processed = 0; 1592e5ec1e72Spatrick while (avail) { 15936f241297Spatrick bwfm_pci_msg_rx(sc, buf + sc->sc_rx_dataoffset, ml); 1594e5ec1e72Spatrick buf += ring->itemsz; 1595e5ec1e72Spatrick processed++; 1596e5ec1e72Spatrick if (processed == 48) { 1597e5ec1e72Spatrick bwfm_pci_ring_read_commit(sc, ring, processed); 1598e5ec1e72Spatrick processed = 0; 1599e5ec1e72Spatrick } 1600e5ec1e72Spatrick avail--; 1601e5ec1e72Spatrick } 1602e5ec1e72Spatrick if (processed) 1603e5ec1e72Spatrick bwfm_pci_ring_read_commit(sc, ring, processed); 1604e5ec1e72Spatrick if (ring->r_ptr == 0) 1605e5ec1e72Spatrick goto again; 1606e5ec1e72Spatrick } 1607e5ec1e72Spatrick 1608e5ec1e72Spatrick void 16096f241297Spatrick bwfm_pci_msg_rx(struct bwfm_pci_softc *sc, void *buf, struct mbuf_list *ml) 1610e5ec1e72Spatrick { 1611518be5f3Spatrick struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if; 1612e5ec1e72Spatrick struct msgbuf_ioctl_resp_hdr *resp; 1613518be5f3Spatrick struct msgbuf_tx_status *tx; 161418722113Spatrick struct msgbuf_rx_complete *rx; 1615e5ec1e72Spatrick struct msgbuf_rx_event *event; 1616e5ec1e72Spatrick struct msgbuf_common_hdr *msg; 1617518be5f3Spatrick struct msgbuf_flowring_create_resp *fcr; 1618a2c6ff8bSpatrick struct msgbuf_flowring_delete_resp *fdr; 1619b5553ee6Spatrick struct bwfm_cmd_flowring_create fdcmd; 1620518be5f3Spatrick struct bwfm_pci_msgring *ring; 1621e5ec1e72Spatrick struct mbuf *m; 1622518be5f3Spatrick int flowid; 1623e5ec1e72Spatrick 1624e5ec1e72Spatrick msg = (struct msgbuf_common_hdr *)buf; 1625e5ec1e72Spatrick switch (msg->msgtype) 1626e5ec1e72Spatrick { 1627518be5f3Spatrick case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT: 1628518be5f3Spatrick fcr = (struct msgbuf_flowring_create_resp *)buf; 1629518be5f3Spatrick flowid = letoh16(fcr->compl_hdr.flow_ring_id); 1630518be5f3Spatrick if (flowid < 2) 1631518be5f3Spatrick break; 1632518be5f3Spatrick flowid -= 2; 1633518be5f3Spatrick if (flowid >= sc->sc_max_flowrings) 1634518be5f3Spatrick break; 1635518be5f3Spatrick ring = &sc->sc_flowrings[flowid]; 1636518be5f3Spatrick if (ring->status != RING_OPENING) 1637518be5f3Spatrick break; 1638518be5f3Spatrick if (fcr->compl_hdr.status) { 1639518be5f3Spatrick printf("%s: failed to open flowring %d\n", 1640518be5f3Spatrick DEVNAME(sc), flowid); 1641518be5f3Spatrick ring->status = RING_CLOSED; 164202ee7d07Spatrick if (ring->m) { 164302ee7d07Spatrick m_freem(ring->m); 164402ee7d07Spatrick ring->m = NULL; 164502ee7d07Spatrick } 1646518be5f3Spatrick ifq_restart(&ifp->if_snd); 1647518be5f3Spatrick break; 1648518be5f3Spatrick } 1649518be5f3Spatrick ring->status = RING_OPEN; 165002ee7d07Spatrick if (ring->m != NULL) { 165102ee7d07Spatrick m = ring->m; 165202ee7d07Spatrick ring->m = NULL; 165302ee7d07Spatrick if (bwfm_pci_txdata(&sc->sc_sc, m)) 165402ee7d07Spatrick m_freem(ring->m); 165502ee7d07Spatrick } 1656518be5f3Spatrick ifq_restart(&ifp->if_snd); 1657518be5f3Spatrick break; 1658a2c6ff8bSpatrick case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT: 1659a2c6ff8bSpatrick fdr = (struct msgbuf_flowring_delete_resp *)buf; 1660a2c6ff8bSpatrick flowid = letoh16(fdr->compl_hdr.flow_ring_id); 1661a2c6ff8bSpatrick if (flowid < 2) 1662a2c6ff8bSpatrick break; 1663a2c6ff8bSpatrick flowid -= 2; 1664a2c6ff8bSpatrick if (flowid >= sc->sc_max_flowrings) 1665a2c6ff8bSpatrick break; 1666a2c6ff8bSpatrick ring = &sc->sc_flowrings[flowid]; 1667a2c6ff8bSpatrick if (ring->status != RING_CLOSING) 1668a2c6ff8bSpatrick break; 1669a2c6ff8bSpatrick if (fdr->compl_hdr.status) { 1670a2c6ff8bSpatrick printf("%s: failed to delete flowring %d\n", 1671a2c6ff8bSpatrick DEVNAME(sc), flowid); 1672a2c6ff8bSpatrick break; 1673a2c6ff8bSpatrick } 1674b5553ee6Spatrick fdcmd.flowid = flowid; 1675b5553ee6Spatrick bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_delete_cb, 1676b5553ee6Spatrick &fdcmd, sizeof(fdcmd)); 1677a2c6ff8bSpatrick break; 1678e5ec1e72Spatrick case MSGBUF_TYPE_IOCTLPTR_REQ_ACK: 16792eeba925Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_ioctl_pkts, 16802eeba925Spatrick letoh32(msg->request_id)); 16812eeba925Spatrick if (m == NULL) 16822eeba925Spatrick break; 16832eeba925Spatrick m_freem(m); 1684e5ec1e72Spatrick break; 1685e5ec1e72Spatrick case MSGBUF_TYPE_IOCTL_CMPLT: 1686e5ec1e72Spatrick resp = (struct msgbuf_ioctl_resp_hdr *)buf; 16872eeba925Spatrick bwfm_pci_msgbuf_rxioctl(sc, resp); 1688e5ec1e72Spatrick if_rxr_put(&sc->sc_ioctl_ring, 1); 1689e5ec1e72Spatrick bwfm_pci_fill_rx_rings(sc); 1690e5ec1e72Spatrick break; 1691e5ec1e72Spatrick case MSGBUF_TYPE_WL_EVENT: 1692e5ec1e72Spatrick event = (struct msgbuf_rx_event *)buf; 1693e5ec1e72Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts, 1694e5ec1e72Spatrick letoh32(event->msg.request_id)); 1695e5ec1e72Spatrick if (m == NULL) 1696e5ec1e72Spatrick break; 1697e5ec1e72Spatrick m_adj(m, sc->sc_rx_dataoffset); 1698f37fc236Spatrick m->m_len = m->m_pkthdr.len = letoh16(event->event_data_len); 16996f241297Spatrick bwfm_rx(&sc->sc_sc, m, ml); 1700e5ec1e72Spatrick if_rxr_put(&sc->sc_event_ring, 1); 1701e5ec1e72Spatrick bwfm_pci_fill_rx_rings(sc); 1702e5ec1e72Spatrick break; 1703518be5f3Spatrick case MSGBUF_TYPE_TX_STATUS: 1704518be5f3Spatrick tx = (struct msgbuf_tx_status *)buf; 1705518be5f3Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_tx_pkts, 1706f9ee104fSpatrick letoh32(tx->msg.request_id) - 1); 1707518be5f3Spatrick if (m == NULL) 1708518be5f3Spatrick break; 1709518be5f3Spatrick m_freem(m); 1710c6f1636dSpatrick if (sc->sc_tx_pkts_full) { 1711c6f1636dSpatrick sc->sc_tx_pkts_full = 0; 1712c6f1636dSpatrick ifq_restart(&ifp->if_snd); 1713c6f1636dSpatrick } 1714518be5f3Spatrick break; 171518722113Spatrick case MSGBUF_TYPE_RX_CMPLT: 171618722113Spatrick rx = (struct msgbuf_rx_complete *)buf; 171718722113Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts, 171818722113Spatrick letoh32(rx->msg.request_id)); 171918722113Spatrick if (m == NULL) 172018722113Spatrick break; 172118722113Spatrick if (letoh16(rx->data_offset)) 172218722113Spatrick m_adj(m, letoh16(rx->data_offset)); 172318722113Spatrick else if (sc->sc_rx_dataoffset) 172418722113Spatrick m_adj(m, sc->sc_rx_dataoffset); 1725f37fc236Spatrick m->m_len = m->m_pkthdr.len = letoh16(rx->data_len); 17266f241297Spatrick bwfm_rx(&sc->sc_sc, m, ml); 172718722113Spatrick if_rxr_put(&sc->sc_rxbuf_ring, 1); 172818722113Spatrick bwfm_pci_fill_rx_rings(sc); 172918722113Spatrick break; 1730e5ec1e72Spatrick default: 1731e5ec1e72Spatrick printf("%s: msgtype 0x%08x\n", __func__, msg->msgtype); 1732e5ec1e72Spatrick break; 1733e5ec1e72Spatrick } 1734e5ec1e72Spatrick } 1735e5ec1e72Spatrick 1736e5ec1e72Spatrick /* Bus core helpers */ 1737e5ec1e72Spatrick void 1738e5ec1e72Spatrick bwfm_pci_select_core(struct bwfm_pci_softc *sc, int id) 1739e5ec1e72Spatrick { 1740e5ec1e72Spatrick struct bwfm_softc *bwfm = (void *)sc; 1741e5ec1e72Spatrick struct bwfm_core *core; 1742e5ec1e72Spatrick 1743e5ec1e72Spatrick core = bwfm_chip_get_core(bwfm, id); 1744e5ec1e72Spatrick if (core == NULL) { 1745e5ec1e72Spatrick printf("%s: could not find core to select", DEVNAME(sc)); 1746e5ec1e72Spatrick return; 1747e5ec1e72Spatrick } 1748e5ec1e72Spatrick 1749e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, 1750e5ec1e72Spatrick BWFM_PCI_BAR0_WINDOW, core->co_base); 1751e5ec1e72Spatrick if (pci_conf_read(sc->sc_pc, sc->sc_tag, 1752e5ec1e72Spatrick BWFM_PCI_BAR0_WINDOW) != core->co_base) 1753e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, 1754e5ec1e72Spatrick BWFM_PCI_BAR0_WINDOW, core->co_base); 1755e5ec1e72Spatrick } 1756e5ec1e72Spatrick 1757e5ec1e72Spatrick uint32_t 1758e5ec1e72Spatrick bwfm_pci_buscore_read(struct bwfm_softc *bwfm, uint32_t reg) 1759e5ec1e72Spatrick { 1760e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1761e5ec1e72Spatrick uint32_t page, offset; 1762e5ec1e72Spatrick 1763e5ec1e72Spatrick page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1); 1764e5ec1e72Spatrick offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1); 1765e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page); 1766e5ec1e72Spatrick return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset); 1767e5ec1e72Spatrick } 1768e5ec1e72Spatrick 1769e5ec1e72Spatrick void 1770e5ec1e72Spatrick bwfm_pci_buscore_write(struct bwfm_softc *bwfm, uint32_t reg, uint32_t val) 1771e5ec1e72Spatrick { 1772e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1773e5ec1e72Spatrick uint32_t page, offset; 1774e5ec1e72Spatrick 1775e5ec1e72Spatrick page = reg & ~(BWFM_PCI_BAR0_REG_SIZE - 1); 1776e5ec1e72Spatrick offset = reg & (BWFM_PCI_BAR0_REG_SIZE - 1); 1777e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_BAR0_WINDOW, page); 1778e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, offset, val); 1779e5ec1e72Spatrick } 1780e5ec1e72Spatrick 1781e5ec1e72Spatrick int 1782e5ec1e72Spatrick bwfm_pci_buscore_prepare(struct bwfm_softc *bwfm) 1783e5ec1e72Spatrick { 1784e5ec1e72Spatrick return 0; 1785e5ec1e72Spatrick } 1786e5ec1e72Spatrick 1787e5ec1e72Spatrick int 1788e5ec1e72Spatrick bwfm_pci_buscore_reset(struct bwfm_softc *bwfm) 1789e5ec1e72Spatrick { 1790e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1791e5ec1e72Spatrick struct bwfm_core *core; 1792e5ec1e72Spatrick uint32_t reg; 1793e5ec1e72Spatrick int i; 1794e5ec1e72Spatrick 1795e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2); 1796e5ec1e72Spatrick reg = pci_conf_read(sc->sc_pc, sc->sc_tag, 1797e5ec1e72Spatrick BWFM_PCI_CFGREG_LINK_STATUS_CTRL); 1798e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_CFGREG_LINK_STATUS_CTRL, 1799e5ec1e72Spatrick reg & ~BWFM_PCI_CFGREG_LINK_STATUS_CTRL_ASPM_ENAB); 1800e5ec1e72Spatrick 1801e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); 1802e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1803e5ec1e72Spatrick BWFM_CHIP_REG_WATCHDOG, 4); 1804e5ec1e72Spatrick delay(100 * 1000); 1805e5ec1e72Spatrick 1806e5ec1e72Spatrick bwfm_pci_select_core(sc, BWFM_AGENT_CORE_PCIE2); 1807e5ec1e72Spatrick pci_conf_write(sc->sc_pc, sc->sc_tag, 1808e5ec1e72Spatrick BWFM_PCI_CFGREG_LINK_STATUS_CTRL, reg); 1809e5ec1e72Spatrick 1810e5ec1e72Spatrick core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2); 1811e5ec1e72Spatrick if (core->co_rev <= 13) { 1812e5ec1e72Spatrick uint16_t cfg_offset[] = { 1813e5ec1e72Spatrick BWFM_PCI_CFGREG_STATUS_CMD, 1814e5ec1e72Spatrick BWFM_PCI_CFGREG_PM_CSR, 1815e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_CAP, 1816e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_ADDR_L, 1817e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_ADDR_H, 1818e5ec1e72Spatrick BWFM_PCI_CFGREG_MSI_DATA, 1819e5ec1e72Spatrick BWFM_PCI_CFGREG_LINK_STATUS_CTRL2, 1820e5ec1e72Spatrick BWFM_PCI_CFGREG_RBAR_CTRL, 1821e5ec1e72Spatrick BWFM_PCI_CFGREG_PML1_SUB_CTRL1, 1822e5ec1e72Spatrick BWFM_PCI_CFGREG_REG_BAR2_CONFIG, 1823e5ec1e72Spatrick BWFM_PCI_CFGREG_REG_BAR3_CONFIG, 1824e5ec1e72Spatrick }; 1825e5ec1e72Spatrick 1826e5ec1e72Spatrick for (i = 0; i < nitems(cfg_offset); i++) { 1827e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1828e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGADDR, cfg_offset[i]); 1829e5ec1e72Spatrick reg = bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1830e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA); 1831e5ec1e72Spatrick DPRINTFN(3, ("%s: config offset 0x%04x, value 0x%04x\n", 1832e5ec1e72Spatrick DEVNAME(sc), cfg_offset[i], reg)); 1833e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 1834e5ec1e72Spatrick BWFM_PCI_PCIE2REG_CONFIGDATA, reg); 1835e5ec1e72Spatrick } 1836e5ec1e72Spatrick } 1837*8bad4727Spatrick if (core->co_rev >= 64) 1838*8bad4727Spatrick sc->sc_pcireg64 = 1; 1839e5ec1e72Spatrick 1840bb813cf8Spatrick reg = bwfm_pci_intr_status(sc); 1841e5ec1e72Spatrick if (reg != 0xffffffff) 1842bb813cf8Spatrick bwfm_pci_intr_ack(sc, reg); 1843e5ec1e72Spatrick 1844e5ec1e72Spatrick return 0; 1845e5ec1e72Spatrick } 1846e5ec1e72Spatrick 1847e5ec1e72Spatrick void 1848e5ec1e72Spatrick bwfm_pci_buscore_activate(struct bwfm_softc *bwfm, uint32_t rstvec) 1849e5ec1e72Spatrick { 1850e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1851e5ec1e72Spatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 0, rstvec); 1852e5ec1e72Spatrick } 1853e5ec1e72Spatrick 1854f67437f3Spatrick static int bwfm_pci_prio2fifo[8] = { 18559e2c067eSpatrick 0, /* best effort */ 18569e2c067eSpatrick 1, /* IPTOS_PREC_IMMEDIATE */ 18579e2c067eSpatrick 1, /* IPTOS_PREC_PRIORITY */ 18589e2c067eSpatrick 0, /* IPTOS_PREC_FLASH */ 1859f67437f3Spatrick 2, /* IPTOS_PREC_FLASHOVERRIDE */ 1860f67437f3Spatrick 2, /* IPTOS_PREC_CRITIC_ECP */ 1861f67437f3Spatrick 3, /* IPTOS_PREC_INTERNETCONTROL */ 1862f67437f3Spatrick 3, /* IPTOS_PREC_NETCONTROL */ 1863f67437f3Spatrick }; 1864f67437f3Spatrick 1865f67437f3Spatrick int 1866f67437f3Spatrick bwfm_pci_flowring_lookup(struct bwfm_pci_softc *sc, struct mbuf *m) 1867518be5f3Spatrick { 1868f67437f3Spatrick struct ieee80211com *ic = &sc->sc_sc.sc_ic; 1869e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY 1870f67437f3Spatrick uint8_t *da = mtod(m, uint8_t *); 1871e6abcda3Smlarkin #endif 1872f67437f3Spatrick int flowid, prio, fifo; 1873f67437f3Spatrick int i, found; 1874f67437f3Spatrick 1875f67437f3Spatrick prio = ieee80211_classify(ic, m); 1876f67437f3Spatrick fifo = bwfm_pci_prio2fifo[prio]; 1877f67437f3Spatrick 1878f67437f3Spatrick switch (ic->ic_opmode) 1879f67437f3Spatrick { 1880f67437f3Spatrick case IEEE80211_M_STA: 1881f67437f3Spatrick flowid = fifo; 1882f67437f3Spatrick break; 1883f67437f3Spatrick #ifndef IEEE80211_STA_ONLY 1884f67437f3Spatrick case IEEE80211_M_HOSTAP: 18852b7bea7eSpatrick if (ETHER_IS_MULTICAST(da)) 18862b7bea7eSpatrick da = etherbroadcastaddr; 1887f67437f3Spatrick flowid = da[5] * 2 + fifo; 1888f67437f3Spatrick break; 1889f67437f3Spatrick #endif 1890f67437f3Spatrick default: 1891f67437f3Spatrick printf("%s: state not supported\n", DEVNAME(sc)); 1892f67437f3Spatrick return ENOBUFS; 1893f67437f3Spatrick } 1894f67437f3Spatrick 1895f67437f3Spatrick found = 0; 1896f67437f3Spatrick flowid = flowid % sc->sc_max_flowrings; 1897f67437f3Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 1898f67437f3Spatrick if (ic->ic_opmode == IEEE80211_M_STA && 1899f67437f3Spatrick sc->sc_flowrings[flowid].status >= RING_OPEN && 1900f67437f3Spatrick sc->sc_flowrings[flowid].fifo == fifo) { 1901f67437f3Spatrick found = 1; 1902f67437f3Spatrick break; 1903f67437f3Spatrick } 1904f67437f3Spatrick #ifndef IEEE80211_STA_ONLY 1905f67437f3Spatrick if (ic->ic_opmode == IEEE80211_M_HOSTAP && 1906f67437f3Spatrick sc->sc_flowrings[flowid].status >= RING_OPEN && 1907f67437f3Spatrick sc->sc_flowrings[flowid].fifo == fifo && 1908a2c6ff8bSpatrick !memcmp(sc->sc_flowrings[flowid].mac, da, ETHER_ADDR_LEN)) { 1909f67437f3Spatrick found = 1; 1910f67437f3Spatrick break; 1911f67437f3Spatrick } 1912f67437f3Spatrick #endif 1913f67437f3Spatrick flowid = (flowid + 1) % sc->sc_max_flowrings; 1914f67437f3Spatrick } 1915f67437f3Spatrick 1916f67437f3Spatrick if (found) 1917f67437f3Spatrick return flowid; 1918f67437f3Spatrick 1919f67437f3Spatrick return -1; 1920f67437f3Spatrick } 1921f67437f3Spatrick 1922f67437f3Spatrick void 1923f67437f3Spatrick bwfm_pci_flowring_create(struct bwfm_pci_softc *sc, struct mbuf *m) 1924f67437f3Spatrick { 1925f67437f3Spatrick struct ieee80211com *ic = &sc->sc_sc.sc_ic; 1926518be5f3Spatrick struct bwfm_cmd_flowring_create cmd; 1927e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY 1928f67437f3Spatrick uint8_t *da = mtod(m, uint8_t *); 1929e6abcda3Smlarkin #endif 193002ee7d07Spatrick struct bwfm_pci_msgring *ring; 1931f67437f3Spatrick int flowid, prio, fifo; 1932f67437f3Spatrick int i, found; 1933f67437f3Spatrick 1934f67437f3Spatrick prio = ieee80211_classify(ic, m); 1935f67437f3Spatrick fifo = bwfm_pci_prio2fifo[prio]; 1936f67437f3Spatrick 1937f67437f3Spatrick switch (ic->ic_opmode) 1938f67437f3Spatrick { 1939f67437f3Spatrick case IEEE80211_M_STA: 1940f67437f3Spatrick flowid = fifo; 1941f67437f3Spatrick break; 1942f67437f3Spatrick #ifndef IEEE80211_STA_ONLY 1943f67437f3Spatrick case IEEE80211_M_HOSTAP: 19442b7bea7eSpatrick if (ETHER_IS_MULTICAST(da)) 19452b7bea7eSpatrick da = etherbroadcastaddr; 1946f67437f3Spatrick flowid = da[5] * 2 + fifo; 1947f67437f3Spatrick break; 1948f67437f3Spatrick #endif 1949f67437f3Spatrick default: 1950f67437f3Spatrick printf("%s: state not supported\n", DEVNAME(sc)); 1951f67437f3Spatrick return; 1952f67437f3Spatrick } 1953f67437f3Spatrick 1954f67437f3Spatrick found = 0; 1955f67437f3Spatrick flowid = flowid % sc->sc_max_flowrings; 1956f67437f3Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 195702ee7d07Spatrick ring = &sc->sc_flowrings[flowid]; 195802ee7d07Spatrick if (ring->status == RING_CLOSED) { 195902ee7d07Spatrick ring->status = RING_OPENING; 1960f67437f3Spatrick found = 1; 1961f67437f3Spatrick break; 1962f67437f3Spatrick } 1963f67437f3Spatrick flowid = (flowid + 1) % sc->sc_max_flowrings; 1964f67437f3Spatrick } 1965f67437f3Spatrick 196602ee7d07Spatrick /* 196702ee7d07Spatrick * We cannot recover from that so far. Only a stop/init 196802ee7d07Spatrick * cycle can revive this if it ever happens at all. 196902ee7d07Spatrick */ 1970f67437f3Spatrick if (!found) { 1971f67437f3Spatrick printf("%s: no flowring available\n", DEVNAME(sc)); 1972f67437f3Spatrick return; 1973f67437f3Spatrick } 1974f67437f3Spatrick 197502ee7d07Spatrick cmd.m = m; 1976f67437f3Spatrick cmd.prio = prio; 1977518be5f3Spatrick cmd.flowid = flowid; 1978518be5f3Spatrick bwfm_do_async(&sc->sc_sc, bwfm_pci_flowring_create_cb, &cmd, sizeof(cmd)); 1979518be5f3Spatrick } 1980518be5f3Spatrick 1981518be5f3Spatrick void 1982518be5f3Spatrick bwfm_pci_flowring_create_cb(struct bwfm_softc *bwfm, void *arg) 1983518be5f3Spatrick { 1984518be5f3Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 1985e6abcda3Smlarkin #ifndef IEEE80211_STA_ONLY 19862b7bea7eSpatrick struct ieee80211com *ic = &sc->sc_sc.sc_ic; 1987e6abcda3Smlarkin #endif 1988518be5f3Spatrick struct bwfm_cmd_flowring_create *cmd = arg; 1989518be5f3Spatrick struct msgbuf_tx_flowring_create_req *req; 1990518be5f3Spatrick struct bwfm_pci_msgring *ring; 199102ee7d07Spatrick uint8_t *da, *sa; 1992e272db29Spatrick int s; 1993518be5f3Spatrick 199402ee7d07Spatrick da = mtod(cmd->m, char *) + 0 * ETHER_ADDR_LEN; 199502ee7d07Spatrick sa = mtod(cmd->m, char *) + 1 * ETHER_ADDR_LEN; 1996518be5f3Spatrick 199702ee7d07Spatrick ring = &sc->sc_flowrings[cmd->flowid]; 199802ee7d07Spatrick if (ring->status != RING_OPENING) { 199902ee7d07Spatrick printf("%s: flowring not opening\n", DEVNAME(sc)); 2000518be5f3Spatrick return; 2001f67437f3Spatrick } 2002f67437f3Spatrick 2003f67437f3Spatrick if (bwfm_pci_setup_flowring(sc, ring, 512, 48)) { 2004f67437f3Spatrick printf("%s: cannot setup flowring\n", DEVNAME(sc)); 2005f67437f3Spatrick return; 2006f67437f3Spatrick } 2007518be5f3Spatrick 2008e272db29Spatrick s = splnet(); 2009518be5f3Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit); 2010f67437f3Spatrick if (req == NULL) { 2011f67437f3Spatrick printf("%s: cannot reserve for flowring\n", DEVNAME(sc)); 2012e272db29Spatrick splx(s); 2013518be5f3Spatrick return; 2014f67437f3Spatrick } 2015518be5f3Spatrick 2016518be5f3Spatrick ring->status = RING_OPENING; 201702ee7d07Spatrick ring->fifo = bwfm_pci_prio2fifo[cmd->prio]; 201802ee7d07Spatrick ring->m = cmd->m; 201902ee7d07Spatrick memcpy(ring->mac, da, ETHER_ADDR_LEN); 20202b7bea7eSpatrick #ifndef IEEE80211_STA_ONLY 202102ee7d07Spatrick if (ic->ic_opmode == IEEE80211_M_HOSTAP && ETHER_IS_MULTICAST(da)) 20222b7bea7eSpatrick memcpy(ring->mac, etherbroadcastaddr, ETHER_ADDR_LEN); 20232b7bea7eSpatrick #endif 2024f67437f3Spatrick 2025518be5f3Spatrick req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE; 2026518be5f3Spatrick req->msg.ifidx = 0; 2027518be5f3Spatrick req->msg.request_id = 0; 202802ee7d07Spatrick req->tid = bwfm_pci_prio2fifo[cmd->prio]; 202902ee7d07Spatrick req->flow_ring_id = letoh16(cmd->flowid + 2); 203002ee7d07Spatrick memcpy(req->da, da, ETHER_ADDR_LEN); 203102ee7d07Spatrick memcpy(req->sa, sa, ETHER_ADDR_LEN); 2032518be5f3Spatrick req->flow_ring_addr.high_addr = 2033518be5f3Spatrick letoh32(BWFM_PCI_DMA_DVA(ring->ring) >> 32); 2034518be5f3Spatrick req->flow_ring_addr.low_addr = 2035518be5f3Spatrick letoh32(BWFM_PCI_DMA_DVA(ring->ring) & 0xffffffff); 2036518be5f3Spatrick req->max_items = letoh16(512); 2037518be5f3Spatrick req->len_item = letoh16(48); 2038518be5f3Spatrick 2039518be5f3Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit); 2040e272db29Spatrick splx(s); 2041518be5f3Spatrick } 2042518be5f3Spatrick 2043a2c6ff8bSpatrick void 2044a2c6ff8bSpatrick bwfm_pci_flowring_delete(struct bwfm_pci_softc *sc, int flowid) 2045a2c6ff8bSpatrick { 2046a2c6ff8bSpatrick struct msgbuf_tx_flowring_delete_req *req; 2047a2c6ff8bSpatrick struct bwfm_pci_msgring *ring; 2048e272db29Spatrick int s; 2049a2c6ff8bSpatrick 2050a2c6ff8bSpatrick ring = &sc->sc_flowrings[flowid]; 2051a2c6ff8bSpatrick if (ring->status != RING_OPEN) { 2052a2c6ff8bSpatrick printf("%s: flowring not open\n", DEVNAME(sc)); 2053a2c6ff8bSpatrick return; 2054a2c6ff8bSpatrick } 2055a2c6ff8bSpatrick 2056e272db29Spatrick s = splnet(); 2057a2c6ff8bSpatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit); 2058a2c6ff8bSpatrick if (req == NULL) { 2059a2c6ff8bSpatrick printf("%s: cannot reserve for flowring\n", DEVNAME(sc)); 2060e272db29Spatrick splx(s); 2061a2c6ff8bSpatrick return; 2062a2c6ff8bSpatrick } 2063a2c6ff8bSpatrick 2064a2c6ff8bSpatrick ring->status = RING_CLOSING; 2065a2c6ff8bSpatrick 2066a2c6ff8bSpatrick req->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE; 2067a2c6ff8bSpatrick req->msg.ifidx = 0; 2068a2c6ff8bSpatrick req->msg.request_id = 0; 2069a2c6ff8bSpatrick req->flow_ring_id = letoh16(flowid + 2); 2070a2c6ff8bSpatrick req->reason = 0; 2071a2c6ff8bSpatrick 2072a2c6ff8bSpatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit); 2073e272db29Spatrick splx(s); 2074a2c6ff8bSpatrick } 2075a2c6ff8bSpatrick 2076a2c6ff8bSpatrick void 2077b5553ee6Spatrick bwfm_pci_flowring_delete_cb(struct bwfm_softc *bwfm, void *arg) 2078b5553ee6Spatrick { 2079b5553ee6Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 2080b5553ee6Spatrick struct bwfm_cmd_flowring_create *cmd = arg; 2081b5553ee6Spatrick struct bwfm_pci_msgring *ring; 2082b5553ee6Spatrick 2083b5553ee6Spatrick ring = &sc->sc_flowrings[cmd->flowid]; 2084b5553ee6Spatrick bwfm_pci_dmamem_free(sc, ring->ring); 2085b5553ee6Spatrick ring->status = RING_CLOSED; 2086b5553ee6Spatrick } 2087b5553ee6Spatrick 2088b5553ee6Spatrick void 2089a2c6ff8bSpatrick bwfm_pci_stop(struct bwfm_softc *bwfm) 2090a2c6ff8bSpatrick { 2091a2c6ff8bSpatrick struct bwfm_pci_softc *sc = (void *)bwfm; 2092a2c6ff8bSpatrick struct bwfm_pci_msgring *ring; 2093a2c6ff8bSpatrick int i; 2094a2c6ff8bSpatrick 2095a2c6ff8bSpatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 2096a2c6ff8bSpatrick ring = &sc->sc_flowrings[i]; 2097a2c6ff8bSpatrick if (ring->status == RING_OPEN) 2098a2c6ff8bSpatrick bwfm_pci_flowring_delete(sc, i); 2099a2c6ff8bSpatrick } 2100a2c6ff8bSpatrick } 2101a2c6ff8bSpatrick 2102e5ec1e72Spatrick int 210302ee7d07Spatrick bwfm_pci_txcheck(struct bwfm_softc *bwfm) 210402ee7d07Spatrick { 210502ee7d07Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 210602ee7d07Spatrick struct bwfm_pci_msgring *ring; 210702ee7d07Spatrick int i; 210802ee7d07Spatrick 210902ee7d07Spatrick /* If we are transitioning, we cannot send. */ 211002ee7d07Spatrick for (i = 0; i < sc->sc_max_flowrings; i++) { 211102ee7d07Spatrick ring = &sc->sc_flowrings[i]; 211202ee7d07Spatrick if (ring->status == RING_OPENING) 211302ee7d07Spatrick return ENOBUFS; 211402ee7d07Spatrick } 211502ee7d07Spatrick 211602ee7d07Spatrick if (bwfm_pci_pktid_avail(sc, &sc->sc_tx_pkts)) { 211702ee7d07Spatrick sc->sc_tx_pkts_full = 1; 211802ee7d07Spatrick return ENOBUFS; 211902ee7d07Spatrick } 212002ee7d07Spatrick 212102ee7d07Spatrick return 0; 212202ee7d07Spatrick } 212302ee7d07Spatrick 212402ee7d07Spatrick int 2125e5ec1e72Spatrick bwfm_pci_txdata(struct bwfm_softc *bwfm, struct mbuf *m) 2126e5ec1e72Spatrick { 2127e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 2128518be5f3Spatrick struct bwfm_pci_msgring *ring; 2129518be5f3Spatrick struct msgbuf_tx_msghdr *tx; 2130518be5f3Spatrick uint32_t pktid; 2131518be5f3Spatrick paddr_t paddr; 2132518be5f3Spatrick int flowid, ret; 2133518be5f3Spatrick 2134f67437f3Spatrick flowid = bwfm_pci_flowring_lookup(sc, m); 2135f67437f3Spatrick if (flowid < 0) { 213602ee7d07Spatrick /* 213702ee7d07Spatrick * We cannot send the packet right now as there is 213802ee7d07Spatrick * no flowring yet. The flowring will be created 213902ee7d07Spatrick * asynchronously. While the ring is transitioning 214002ee7d07Spatrick * the TX check will tell the upper layers that we 214102ee7d07Spatrick * cannot send packets right now. When the flowring 214202ee7d07Spatrick * is created the queue will be restarted and this 214302ee7d07Spatrick * mbuf will be transmitted. 214402ee7d07Spatrick */ 2145f67437f3Spatrick bwfm_pci_flowring_create(sc, m); 214602ee7d07Spatrick return 0; 2147f67437f3Spatrick } 2148518be5f3Spatrick 2149518be5f3Spatrick ring = &sc->sc_flowrings[flowid]; 2150518be5f3Spatrick if (ring->status == RING_OPENING || 2151f67437f3Spatrick ring->status == RING_CLOSING) { 2152f67437f3Spatrick printf("%s: tried to use a flow that was " 2153f67437f3Spatrick "transitioning in status %d\n", 2154f67437f3Spatrick DEVNAME(sc), ring->status); 2155518be5f3Spatrick return ENOBUFS; 2156518be5f3Spatrick } 2157518be5f3Spatrick 2158518be5f3Spatrick tx = bwfm_pci_ring_write_reserve(sc, ring); 2159518be5f3Spatrick if (tx == NULL) 2160518be5f3Spatrick return ENOBUFS; 2161518be5f3Spatrick 2162518be5f3Spatrick memset(tx, 0, sizeof(*tx)); 2163518be5f3Spatrick tx->msg.msgtype = MSGBUF_TYPE_TX_POST; 2164518be5f3Spatrick tx->msg.ifidx = 0; 2165518be5f3Spatrick tx->flags = BWFM_MSGBUF_PKT_FLAGS_FRAME_802_3; 2166518be5f3Spatrick tx->flags |= ieee80211_classify(&sc->sc_sc.sc_ic, m) << 2167518be5f3Spatrick BWFM_MSGBUF_PKT_FLAGS_PRIO_SHIFT; 2168518be5f3Spatrick tx->seg_cnt = 1; 2169518be5f3Spatrick memcpy(tx->txhdr, mtod(m, char *), ETHER_HDR_LEN); 2170518be5f3Spatrick 2171518be5f3Spatrick ret = bwfm_pci_pktid_new(sc, &sc->sc_tx_pkts, m, &pktid, &paddr); 2172518be5f3Spatrick if (ret) { 217302ee7d07Spatrick if (ret == ENOBUFS) { 217402ee7d07Spatrick printf("%s: no pktid available for TX\n", 217502ee7d07Spatrick DEVNAME(sc)); 2176c6f1636dSpatrick sc->sc_tx_pkts_full = 1; 217702ee7d07Spatrick } 2178518be5f3Spatrick bwfm_pci_ring_write_cancel(sc, ring, 1); 2179518be5f3Spatrick return ret; 2180518be5f3Spatrick } 2181518be5f3Spatrick paddr += ETHER_HDR_LEN; 2182518be5f3Spatrick 2183f9ee104fSpatrick tx->msg.request_id = htole32(pktid + 1); 21844ff787bcSpatrick tx->data_len = htole16(m->m_len - ETHER_HDR_LEN); 2185e4dae658Spatrick tx->data_buf_addr.high_addr = htole32((uint64_t)paddr >> 32); 2186518be5f3Spatrick tx->data_buf_addr.low_addr = htole32(paddr & 0xffffffff); 2187518be5f3Spatrick 2188518be5f3Spatrick bwfm_pci_ring_write_commit(sc, ring); 2189518be5f3Spatrick return 0; 2190e5ec1e72Spatrick } 2191e5ec1e72Spatrick 21921a93a9bdSpatrick int 21931a93a9bdSpatrick bwfm_pci_send_mb_data(struct bwfm_pci_softc *sc, uint32_t htod_mb_data) 21941a93a9bdSpatrick { 21951a93a9bdSpatrick struct bwfm_softc *bwfm = (void *)sc; 21961a93a9bdSpatrick struct bwfm_core *core; 21971a93a9bdSpatrick uint32_t reg; 21981a93a9bdSpatrick int i; 21991a93a9bdSpatrick 22001a93a9bdSpatrick for (i = 0; i < 100; i++) { 22011a93a9bdSpatrick reg = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 22021a93a9bdSpatrick sc->sc_htod_mb_data_addr); 22031a93a9bdSpatrick if (reg == 0) 22041a93a9bdSpatrick break; 22051a93a9bdSpatrick delay(10 * 1000); 22061a93a9bdSpatrick } 22071a93a9bdSpatrick if (i == 100) { 22081a93a9bdSpatrick DPRINTF(("%s: MB transaction already pending\n", DEVNAME(sc))); 22091a93a9bdSpatrick return EIO; 22101a93a9bdSpatrick } 22111a93a9bdSpatrick 22121a93a9bdSpatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 22131a93a9bdSpatrick sc->sc_htod_mb_data_addr, htod_mb_data); 22141a93a9bdSpatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_REG_SBMBX, 1); 22151a93a9bdSpatrick 22161a93a9bdSpatrick core = bwfm_chip_get_core(bwfm, BWFM_AGENT_CORE_PCIE2); 22171a93a9bdSpatrick if (core->co_rev <= 13) 22181a93a9bdSpatrick pci_conf_write(sc->sc_pc, sc->sc_tag, BWFM_PCI_REG_SBMBX, 1); 22191a93a9bdSpatrick 22201a93a9bdSpatrick return 0; 22211a93a9bdSpatrick } 22221a93a9bdSpatrick 22231a93a9bdSpatrick void 22241a93a9bdSpatrick bwfm_pci_handle_mb_data(struct bwfm_pci_softc *sc) 22251a93a9bdSpatrick { 22261a93a9bdSpatrick uint32_t reg; 22271a93a9bdSpatrick 22281a93a9bdSpatrick reg = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 22291a93a9bdSpatrick sc->sc_dtoh_mb_data_addr); 22301a93a9bdSpatrick if (reg == 0) 22311a93a9bdSpatrick return; 22321a93a9bdSpatrick 22331a93a9bdSpatrick bus_space_write_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 22341a93a9bdSpatrick sc->sc_dtoh_mb_data_addr, 0); 22351a93a9bdSpatrick 22361a93a9bdSpatrick if (reg & BWFM_PCI_D2H_DEV_D3_ACK) { 22371a93a9bdSpatrick sc->sc_mbdata_done = 1; 22381a93a9bdSpatrick wakeup(&sc->sc_mbdata_done); 22391a93a9bdSpatrick } 22401a93a9bdSpatrick 22411a93a9bdSpatrick /* TODO: support more events */ 22421a93a9bdSpatrick if (reg & ~BWFM_PCI_D2H_DEV_D3_ACK) 22431a93a9bdSpatrick printf("%s: handle MB data 0x%08x\n", DEVNAME(sc), reg); 22441a93a9bdSpatrick } 22451a93a9bdSpatrick 2246bbd71b0bSpatrick #ifdef BWFM_DEBUG 2247cadf5fcfSpatrick void 2248cadf5fcfSpatrick bwfm_pci_debug_console(struct bwfm_pci_softc *sc) 2249cadf5fcfSpatrick { 2250cadf5fcfSpatrick uint32_t newidx = bus_space_read_4(sc->sc_tcm_iot, sc->sc_tcm_ioh, 2251cadf5fcfSpatrick sc->sc_console_base_addr + BWFM_CONSOLE_WRITEIDX); 2252cadf5fcfSpatrick 2253cadf5fcfSpatrick if (newidx != sc->sc_console_readidx) 2254bbd71b0bSpatrick DPRINTFN(3, ("BWFM CONSOLE: ")); 2255cadf5fcfSpatrick while (newidx != sc->sc_console_readidx) { 2256cadf5fcfSpatrick uint8_t ch = bus_space_read_1(sc->sc_tcm_iot, sc->sc_tcm_ioh, 2257cadf5fcfSpatrick sc->sc_console_buf_addr + sc->sc_console_readidx); 2258cadf5fcfSpatrick sc->sc_console_readidx++; 2259cadf5fcfSpatrick if (sc->sc_console_readidx == sc->sc_console_buf_size) 2260cadf5fcfSpatrick sc->sc_console_readidx = 0; 2261cadf5fcfSpatrick if (ch == '\r') 2262cadf5fcfSpatrick continue; 2263bbd71b0bSpatrick DPRINTFN(3, ("%c", ch)); 2264cadf5fcfSpatrick } 2265cadf5fcfSpatrick } 2266bbd71b0bSpatrick #endif 2267cadf5fcfSpatrick 2268e5ec1e72Spatrick int 2269e5ec1e72Spatrick bwfm_pci_intr(void *v) 2270e5ec1e72Spatrick { 2271e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)v; 22726f241297Spatrick struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if; 22736f241297Spatrick struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 2274bb813cf8Spatrick uint32_t status, mask; 2275e5ec1e72Spatrick 2276bb813cf8Spatrick if (!sc->sc_initialized) 2277bb813cf8Spatrick return 0; 2278bb813cf8Spatrick 2279bb813cf8Spatrick status = bwfm_pci_intr_status(sc); 2280bb813cf8Spatrick /* FIXME: interrupt status seems to be zero? */ 2281*8bad4727Spatrick if (status == 0 && sc->sc_pcireg64) 2282bb813cf8Spatrick status |= BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB; 2283bb813cf8Spatrick if (status == 0) 2284e5ec1e72Spatrick return 0; 2285e5ec1e72Spatrick 2286e5ec1e72Spatrick bwfm_pci_intr_disable(sc); 2287bb813cf8Spatrick bwfm_pci_intr_ack(sc, status); 2288e5ec1e72Spatrick 2289*8bad4727Spatrick if (!sc->sc_pcireg64 && 2290bb813cf8Spatrick (status & (BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 | 2291bb813cf8Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1))) 22921a93a9bdSpatrick bwfm_pci_handle_mb_data(sc); 2293e5ec1e72Spatrick 2294bb813cf8Spatrick mask = BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB; 2295*8bad4727Spatrick if (sc->sc_pcireg64) 2296bb813cf8Spatrick mask = BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB; 2297bb813cf8Spatrick 2298bb813cf8Spatrick if (status & mask) { 22996f241297Spatrick bwfm_pci_ring_rx(sc, &sc->sc_rx_complete, &ml); 23006f241297Spatrick bwfm_pci_ring_rx(sc, &sc->sc_tx_complete, &ml); 23016f241297Spatrick bwfm_pci_ring_rx(sc, &sc->sc_ctrl_complete, &ml); 2302447a2df6Sdlg 2303447a2df6Sdlg if (ifiq_input(&ifp->if_rcv, &ml)) 2304447a2df6Sdlg if_rxr_livelocked(&sc->sc_rxbuf_ring); 2305e5ec1e72Spatrick } 2306e5ec1e72Spatrick 2307cadf5fcfSpatrick #ifdef BWFM_DEBUG 2308cadf5fcfSpatrick bwfm_pci_debug_console(sc); 2309e5ec1e72Spatrick #endif 2310e5ec1e72Spatrick 2311e5ec1e72Spatrick bwfm_pci_intr_enable(sc); 2312e5ec1e72Spatrick return 1; 2313e5ec1e72Spatrick } 2314e5ec1e72Spatrick 2315e5ec1e72Spatrick void 2316e5ec1e72Spatrick bwfm_pci_intr_enable(struct bwfm_pci_softc *sc) 2317e5ec1e72Spatrick { 2318*8bad4727Spatrick if (sc->sc_pcireg64) 2319bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2320bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_MAILBOXMASK, 2321bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_MAILBOXMASK_INT_D2H_DB); 2322bb813cf8Spatrick else 2323e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2324e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK, 2325e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_0 | 2326e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_FN0_1 | 2327e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK_INT_D2H_DB); 2328e5ec1e72Spatrick } 2329e5ec1e72Spatrick 2330e5ec1e72Spatrick void 2331e5ec1e72Spatrick bwfm_pci_intr_disable(struct bwfm_pci_softc *sc) 2332e5ec1e72Spatrick { 2333*8bad4727Spatrick if (sc->sc_pcireg64) 2334bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2335bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_MAILBOXMASK, 0); 2336bb813cf8Spatrick else 2337e5ec1e72Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2338e5ec1e72Spatrick BWFM_PCI_PCIE2REG_MAILBOXMASK, 0); 2339e5ec1e72Spatrick } 2340e5ec1e72Spatrick 2341bb813cf8Spatrick uint32_t 2342bb813cf8Spatrick bwfm_pci_intr_status(struct bwfm_pci_softc *sc) 2343bb813cf8Spatrick { 2344*8bad4727Spatrick if (sc->sc_pcireg64) 2345bb813cf8Spatrick return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2346bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_MAILBOXINT); 2347bb813cf8Spatrick else 2348bb813cf8Spatrick return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2349bb813cf8Spatrick BWFM_PCI_PCIE2REG_MAILBOXINT); 2350bb813cf8Spatrick } 2351bb813cf8Spatrick 2352bb813cf8Spatrick void 2353bb813cf8Spatrick bwfm_pci_intr_ack(struct bwfm_pci_softc *sc, uint32_t status) 2354bb813cf8Spatrick { 2355*8bad4727Spatrick if (sc->sc_pcireg64) 2356bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2357bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_MAILBOXINT, status); 2358bb813cf8Spatrick else 2359bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2360bb813cf8Spatrick BWFM_PCI_PCIE2REG_MAILBOXINT, status); 2361bb813cf8Spatrick } 2362bb813cf8Spatrick 23631a93a9bdSpatrick uint32_t 23641a93a9bdSpatrick bwfm_pci_intmask(struct bwfm_pci_softc *sc) 23651a93a9bdSpatrick { 2366*8bad4727Spatrick if (sc->sc_pcireg64) 23671a93a9bdSpatrick return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 23681a93a9bdSpatrick BWFM_PCI_64_PCIE2REG_INTMASK); 23691a93a9bdSpatrick else 23701a93a9bdSpatrick return bus_space_read_4(sc->sc_reg_iot, sc->sc_reg_ioh, 23711a93a9bdSpatrick BWFM_PCI_PCIE2REG_INTMASK); 23721a93a9bdSpatrick } 23731a93a9bdSpatrick 2374156d2677Spatrick void 2375156d2677Spatrick bwfm_pci_hostready(struct bwfm_pci_softc *sc) 2376156d2677Spatrick { 2377156d2677Spatrick if ((sc->sc_shared_flags & BWFM_SHARED_INFO_HOSTRDY_DB1) == 0) 2378156d2677Spatrick return; 2379156d2677Spatrick 2380*8bad4727Spatrick if (sc->sc_pcireg64) 2381bb813cf8Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2382bb813cf8Spatrick BWFM_PCI_64_PCIE2REG_H2D_MAILBOX_1, 1); 2383bb813cf8Spatrick else 2384156d2677Spatrick bus_space_write_4(sc->sc_reg_iot, sc->sc_reg_ioh, 2385156d2677Spatrick BWFM_PCI_PCIE2REG_H2D_MAILBOX_1, 1); 2386156d2677Spatrick } 2387156d2677Spatrick 2388e5ec1e72Spatrick /* Msgbuf protocol implementation */ 2389e5ec1e72Spatrick int 2390e5ec1e72Spatrick bwfm_pci_msgbuf_query_dcmd(struct bwfm_softc *bwfm, int ifidx, 2391e5ec1e72Spatrick int cmd, char *buf, size_t *len) 2392e5ec1e72Spatrick { 2393e5ec1e72Spatrick struct bwfm_pci_softc *sc = (void *)bwfm; 2394e5ec1e72Spatrick struct msgbuf_ioctl_req_hdr *req; 23952eeba925Spatrick struct bwfm_pci_ioctl *ctl; 2396e5ec1e72Spatrick struct mbuf *m; 23972eeba925Spatrick uint32_t pktid; 23982eeba925Spatrick paddr_t paddr; 2399e5ec1e72Spatrick size_t buflen; 2400e272db29Spatrick int s; 2401e5ec1e72Spatrick 24022eeba925Spatrick buflen = min(*len, BWFM_DMA_H2D_IOCTL_BUF_LEN); 2403471f2571Sjan m = MCLGETL(NULL, M_DONTWAIT, buflen); 24042eeba925Spatrick if (m == NULL) 24052eeba925Spatrick return 1; 24062eeba925Spatrick m->m_len = m->m_pkthdr.len = buflen; 24072eeba925Spatrick 24082eeba925Spatrick if (buf) 24092eeba925Spatrick memcpy(mtod(m, char *), buf, buflen); 24102eeba925Spatrick else 24112eeba925Spatrick memset(mtod(m, char *), 0, buflen); 24122eeba925Spatrick 2413e272db29Spatrick s = splnet(); 2414e5ec1e72Spatrick req = bwfm_pci_ring_write_reserve(sc, &sc->sc_ctrl_submit); 2415e5ec1e72Spatrick if (req == NULL) { 2416e272db29Spatrick splx(s); 24172eeba925Spatrick m_freem(m); 2418e5ec1e72Spatrick return 1; 2419e5ec1e72Spatrick } 24202eeba925Spatrick 24212eeba925Spatrick if (bwfm_pci_pktid_new(sc, &sc->sc_ioctl_pkts, m, &pktid, &paddr)) { 24222eeba925Spatrick bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1); 2423e272db29Spatrick splx(s); 24242eeba925Spatrick m_freem(m); 24252eeba925Spatrick return 1; 24262eeba925Spatrick } 24272eeba925Spatrick 24282eeba925Spatrick ctl = malloc(sizeof(*ctl), M_TEMP, M_WAITOK|M_ZERO); 24292eeba925Spatrick ctl->transid = sc->sc_ioctl_transid++; 24302eeba925Spatrick TAILQ_INSERT_TAIL(&sc->sc_ioctlq, ctl, next); 24312eeba925Spatrick 2432e5ec1e72Spatrick req->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ; 2433e5ec1e72Spatrick req->msg.ifidx = 0; 2434e5ec1e72Spatrick req->msg.flags = 0; 24352eeba925Spatrick req->msg.request_id = htole32(pktid); 2436e5ec1e72Spatrick req->cmd = htole32(cmd); 2437e5ec1e72Spatrick req->output_buf_len = htole16(*len); 24382eeba925Spatrick req->trans_id = htole16(ctl->transid); 2439e5ec1e72Spatrick 24402eeba925Spatrick req->input_buf_len = htole16(m->m_len); 24412eeba925Spatrick req->req_buf_addr.high_addr = htole32((uint64_t)paddr >> 32); 24422eeba925Spatrick req->req_buf_addr.low_addr = htole32(paddr & 0xffffffff); 2443dcb67343Spatrick 2444e5ec1e72Spatrick bwfm_pci_ring_write_commit(sc, &sc->sc_ctrl_submit); 2445e272db29Spatrick splx(s); 2446e5ec1e72Spatrick 24478544fed6Smpi tsleep_nsec(ctl, PWAIT, "bwfm", SEC_TO_NSEC(1)); 24482eeba925Spatrick TAILQ_REMOVE(&sc->sc_ioctlq, ctl, next); 24492eeba925Spatrick 24502eeba925Spatrick if (ctl->m == NULL) { 24512eeba925Spatrick free(ctl, M_TEMP, sizeof(*ctl)); 2452e5ec1e72Spatrick return 1; 2453e5ec1e72Spatrick } 2454e5ec1e72Spatrick 24552eeba925Spatrick *len = min(ctl->retlen, m->m_len); 24562eeba925Spatrick *len = min(*len, buflen); 2457e5ec1e72Spatrick if (buf) 24585c7fed39Sdlg m_copydata(ctl->m, 0, *len, buf); 24592eeba925Spatrick m_freem(ctl->m); 2460e5ec1e72Spatrick 24612eeba925Spatrick if (ctl->status < 0) { 24622eeba925Spatrick free(ctl, M_TEMP, sizeof(*ctl)); 24632eeba925Spatrick return 1; 24642eeba925Spatrick } 24652eeba925Spatrick 24662eeba925Spatrick free(ctl, M_TEMP, sizeof(*ctl)); 2467e5ec1e72Spatrick return 0; 2468e5ec1e72Spatrick } 2469e5ec1e72Spatrick 2470e5ec1e72Spatrick int 2471e5ec1e72Spatrick bwfm_pci_msgbuf_set_dcmd(struct bwfm_softc *bwfm, int ifidx, 2472e5ec1e72Spatrick int cmd, char *buf, size_t len) 2473e5ec1e72Spatrick { 2474e5ec1e72Spatrick return bwfm_pci_msgbuf_query_dcmd(bwfm, ifidx, cmd, buf, &len); 2475e5ec1e72Spatrick } 24762eeba925Spatrick 24772eeba925Spatrick void 24782eeba925Spatrick bwfm_pci_msgbuf_rxioctl(struct bwfm_pci_softc *sc, 24792eeba925Spatrick struct msgbuf_ioctl_resp_hdr *resp) 24802eeba925Spatrick { 24812eeba925Spatrick struct bwfm_pci_ioctl *ctl, *tmp; 24822eeba925Spatrick struct mbuf *m; 24832eeba925Spatrick 24842eeba925Spatrick m = bwfm_pci_pktid_free(sc, &sc->sc_rx_pkts, 24852eeba925Spatrick letoh32(resp->msg.request_id)); 24862eeba925Spatrick 24872eeba925Spatrick TAILQ_FOREACH_SAFE(ctl, &sc->sc_ioctlq, next, tmp) { 24882eeba925Spatrick if (ctl->transid != letoh16(resp->trans_id)) 24892eeba925Spatrick continue; 24902eeba925Spatrick ctl->m = m; 24912eeba925Spatrick ctl->retlen = letoh16(resp->resp_len); 24922eeba925Spatrick ctl->status = letoh16(resp->compl_hdr.status); 24932eeba925Spatrick wakeup(ctl); 24942eeba925Spatrick return; 24952eeba925Spatrick } 24962eeba925Spatrick 2497cb2afc74Spatrick m_freem(m); 24982eeba925Spatrick } 2499