1757e5b29SNathan Whitehorn /*- 2757e5b29SNathan Whitehorn * Copyright 2013 Nathan Whitehorn 3757e5b29SNathan Whitehorn * All rights reserved. 4757e5b29SNathan Whitehorn * 5757e5b29SNathan Whitehorn * Redistribution and use in source and binary forms, with or without 6757e5b29SNathan Whitehorn * modification, are permitted provided that the following conditions 7757e5b29SNathan Whitehorn * are met: 8757e5b29SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 9757e5b29SNathan Whitehorn * notice, this list of conditions and the following disclaimer. 10757e5b29SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 11757e5b29SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 12757e5b29SNathan Whitehorn * documentation and/or other materials provided with the distribution. 13757e5b29SNathan Whitehorn * 14757e5b29SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15757e5b29SNathan Whitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16757e5b29SNathan Whitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17757e5b29SNathan Whitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18757e5b29SNathan Whitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19757e5b29SNathan Whitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20757e5b29SNathan Whitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21757e5b29SNathan Whitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22757e5b29SNathan Whitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23757e5b29SNathan Whitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24757e5b29SNathan Whitehorn * SUCH DAMAGE. 25757e5b29SNathan Whitehorn */ 26757e5b29SNathan Whitehorn 27757e5b29SNathan Whitehorn #include <sys/cdefs.h> 28757e5b29SNathan Whitehorn __FBSDID("$FreeBSD$"); 29757e5b29SNathan Whitehorn 30757e5b29SNathan Whitehorn #include <sys/param.h> 31757e5b29SNathan Whitehorn #include <sys/systm.h> 32757e5b29SNathan Whitehorn #include <sys/sockio.h> 33757e5b29SNathan Whitehorn #include <sys/endian.h> 34757e5b29SNathan Whitehorn #include <sys/mbuf.h> 35757e5b29SNathan Whitehorn #include <sys/module.h> 36757e5b29SNathan Whitehorn #include <sys/malloc.h> 37757e5b29SNathan Whitehorn #include <sys/kernel.h> 38757e5b29SNathan Whitehorn #include <sys/socket.h> 39757e5b29SNathan Whitehorn 40757e5b29SNathan Whitehorn #include <net/bpf.h> 41757e5b29SNathan Whitehorn #include <net/if.h> 42757e5b29SNathan Whitehorn #include <net/if_arp.h> 43757e5b29SNathan Whitehorn #include <net/ethernet.h> 44757e5b29SNathan Whitehorn #include <net/if_dl.h> 45757e5b29SNathan Whitehorn #include <net/if_media.h> 46757e5b29SNathan Whitehorn #include <net/if_types.h> 47757e5b29SNathan Whitehorn #include <net/if_vlan_var.h> 48757e5b29SNathan Whitehorn 49757e5b29SNathan Whitehorn #include <dev/ofw/openfirm.h> 50757e5b29SNathan Whitehorn #include <dev/ofw/ofw_bus.h> 51757e5b29SNathan Whitehorn #include <dev/ofw/ofw_bus_subr.h> 52757e5b29SNathan Whitehorn #include <machine/bus.h> 53757e5b29SNathan Whitehorn #include <machine/resource.h> 54757e5b29SNathan Whitehorn #include <sys/bus.h> 55757e5b29SNathan Whitehorn #include <sys/rman.h> 56757e5b29SNathan Whitehorn 57757e5b29SNathan Whitehorn #include <powerpc/pseries/phyp-hvcall.h> 58757e5b29SNathan Whitehorn 59757e5b29SNathan Whitehorn #define LLAN_MAX_RX_PACKETS 100 60757e5b29SNathan Whitehorn #define LLAN_MAX_TX_PACKETS 100 61757e5b29SNathan Whitehorn #define LLAN_RX_BUF_LEN 8*PAGE_SIZE 62757e5b29SNathan Whitehorn 63757e5b29SNathan Whitehorn struct llan_xfer { 64757e5b29SNathan Whitehorn struct mbuf *rx_mbuf; 65757e5b29SNathan Whitehorn bus_dmamap_t rx_dmamap; 66757e5b29SNathan Whitehorn uint64_t rx_bufdesc; 67757e5b29SNathan Whitehorn }; 68757e5b29SNathan Whitehorn 69757e5b29SNathan Whitehorn struct llan_receive_queue_entry { /* PAPR page 539 */ 70757e5b29SNathan Whitehorn uint8_t control; 71757e5b29SNathan Whitehorn uint8_t reserved; 72757e5b29SNathan Whitehorn uint16_t offset; 73757e5b29SNathan Whitehorn uint32_t length; 74757e5b29SNathan Whitehorn uint64_t handle; 75757e5b29SNathan Whitehorn } __packed; 76757e5b29SNathan Whitehorn 77757e5b29SNathan Whitehorn struct llan_softc { 78757e5b29SNathan Whitehorn device_t dev; 79757e5b29SNathan Whitehorn struct mtx io_lock; 80757e5b29SNathan Whitehorn 81757e5b29SNathan Whitehorn cell_t unit; 82757e5b29SNathan Whitehorn uint8_t mac_address[8]; 83757e5b29SNathan Whitehorn 84757e5b29SNathan Whitehorn int irqid; 85757e5b29SNathan Whitehorn struct resource *irq; 86757e5b29SNathan Whitehorn void *irq_cookie; 87757e5b29SNathan Whitehorn 88757e5b29SNathan Whitehorn bus_dma_tag_t rx_dma_tag; 89757e5b29SNathan Whitehorn bus_dma_tag_t rxbuf_dma_tag; 90757e5b29SNathan Whitehorn bus_dma_tag_t tx_dma_tag; 91757e5b29SNathan Whitehorn 92757e5b29SNathan Whitehorn bus_dmamap_t tx_dma_map; 93757e5b29SNathan Whitehorn 94757e5b29SNathan Whitehorn struct llan_receive_queue_entry *rx_buf; 95757e5b29SNathan Whitehorn int rx_dma_slot; 96757e5b29SNathan Whitehorn int rx_valid_val; 97757e5b29SNathan Whitehorn bus_dmamap_t rx_buf_map; 98757e5b29SNathan Whitehorn bus_addr_t rx_buf_phys; 99757e5b29SNathan Whitehorn bus_size_t rx_buf_len; 100757e5b29SNathan Whitehorn bus_addr_t input_buf_phys; 101757e5b29SNathan Whitehorn bus_addr_t filter_buf_phys; 102757e5b29SNathan Whitehorn struct llan_xfer rx_xfer[LLAN_MAX_RX_PACKETS]; 103757e5b29SNathan Whitehorn 104757e5b29SNathan Whitehorn struct ifnet *ifp; 105757e5b29SNathan Whitehorn }; 106757e5b29SNathan Whitehorn 107757e5b29SNathan Whitehorn static int llan_probe(device_t); 108757e5b29SNathan Whitehorn static int llan_attach(device_t); 109757e5b29SNathan Whitehorn static void llan_intr(void *xsc); 110757e5b29SNathan Whitehorn static void llan_init(void *xsc); 111757e5b29SNathan Whitehorn static void llan_start(struct ifnet *ifp); 112757e5b29SNathan Whitehorn static int llan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 113757e5b29SNathan Whitehorn static void llan_rx_load_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, 114757e5b29SNathan Whitehorn int err); 115757e5b29SNathan Whitehorn static int llan_add_rxbuf(struct llan_softc *sc, struct llan_xfer *rx); 116757e5b29SNathan Whitehorn 117757e5b29SNathan Whitehorn static devclass_t llan_devclass; 118757e5b29SNathan Whitehorn static device_method_t llan_methods[] = { 119757e5b29SNathan Whitehorn DEVMETHOD(device_probe, llan_probe), 120757e5b29SNathan Whitehorn DEVMETHOD(device_attach, llan_attach), 121757e5b29SNathan Whitehorn 122757e5b29SNathan Whitehorn DEVMETHOD_END 123757e5b29SNathan Whitehorn }; 124757e5b29SNathan Whitehorn static driver_t llan_driver = { 125757e5b29SNathan Whitehorn "llan", 126757e5b29SNathan Whitehorn llan_methods, 127757e5b29SNathan Whitehorn sizeof(struct llan_softc) 128757e5b29SNathan Whitehorn }; 129757e5b29SNathan Whitehorn DRIVER_MODULE(llan, vdevice, llan_driver, llan_devclass, 0, 0); 130757e5b29SNathan Whitehorn 131757e5b29SNathan Whitehorn static int 132757e5b29SNathan Whitehorn llan_probe(device_t dev) 133757e5b29SNathan Whitehorn { 134757e5b29SNathan Whitehorn if (!ofw_bus_is_compatible(dev,"IBM,l-lan")) 135757e5b29SNathan Whitehorn return (ENXIO); 136757e5b29SNathan Whitehorn 137757e5b29SNathan Whitehorn device_set_desc(dev, "POWER Hypervisor Virtual Ethernet"); 138757e5b29SNathan Whitehorn return (0); 139757e5b29SNathan Whitehorn } 140757e5b29SNathan Whitehorn 141757e5b29SNathan Whitehorn static int 142757e5b29SNathan Whitehorn llan_attach(device_t dev) 143757e5b29SNathan Whitehorn { 144757e5b29SNathan Whitehorn struct llan_softc *sc; 145757e5b29SNathan Whitehorn phandle_t node; 146757e5b29SNathan Whitehorn int error, i; 147757e5b29SNathan Whitehorn 148757e5b29SNathan Whitehorn sc = device_get_softc(dev); 149757e5b29SNathan Whitehorn sc->dev = dev; 150757e5b29SNathan Whitehorn 151757e5b29SNathan Whitehorn /* Get firmware properties */ 152757e5b29SNathan Whitehorn node = ofw_bus_get_node(dev); 153757e5b29SNathan Whitehorn OF_getprop(node, "local-mac-address", sc->mac_address, 154757e5b29SNathan Whitehorn sizeof(sc->mac_address)); 155757e5b29SNathan Whitehorn OF_getprop(node, "reg", &sc->unit, sizeof(sc->unit)); 156757e5b29SNathan Whitehorn 157757e5b29SNathan Whitehorn mtx_init(&sc->io_lock, "llan", NULL, MTX_DEF); 158757e5b29SNathan Whitehorn 159757e5b29SNathan Whitehorn /* Setup interrupt */ 160757e5b29SNathan Whitehorn sc->irqid = 0; 161757e5b29SNathan Whitehorn sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 162757e5b29SNathan Whitehorn RF_ACTIVE); 163757e5b29SNathan Whitehorn 164757e5b29SNathan Whitehorn if (!sc->irq) { 165757e5b29SNathan Whitehorn device_printf(dev, "Could not allocate IRQ\n"); 166757e5b29SNathan Whitehorn mtx_destroy(&sc->io_lock); 167757e5b29SNathan Whitehorn return (ENXIO); 168757e5b29SNathan Whitehorn } 169757e5b29SNathan Whitehorn 170757e5b29SNathan Whitehorn bus_setup_intr(dev, sc->irq, INTR_TYPE_MISC | INTR_MPSAFE | 171757e5b29SNathan Whitehorn INTR_ENTROPY, NULL, llan_intr, sc, &sc->irq_cookie); 172757e5b29SNathan Whitehorn 173757e5b29SNathan Whitehorn /* Setup DMA */ 174757e5b29SNathan Whitehorn error = bus_dma_tag_create(bus_get_dma_tag(dev), 16, 0, 175757e5b29SNathan Whitehorn BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 176757e5b29SNathan Whitehorn LLAN_RX_BUF_LEN, 1, BUS_SPACE_MAXSIZE_32BIT, 177757e5b29SNathan Whitehorn 0, NULL, NULL, &sc->rx_dma_tag); 178757e5b29SNathan Whitehorn error = bus_dma_tag_create(bus_get_dma_tag(dev), 4, 0, 179757e5b29SNathan Whitehorn BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 180757e5b29SNathan Whitehorn BUS_SPACE_MAXSIZE, 1, BUS_SPACE_MAXSIZE_32BIT, 181757e5b29SNathan Whitehorn 0, NULL, NULL, &sc->rxbuf_dma_tag); 182757e5b29SNathan Whitehorn error = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, 183757e5b29SNathan Whitehorn BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 184757e5b29SNathan Whitehorn BUS_SPACE_MAXSIZE, 6, BUS_SPACE_MAXSIZE_32BIT, 0, 185757e5b29SNathan Whitehorn busdma_lock_mutex, &sc->io_lock, &sc->tx_dma_tag); 186757e5b29SNathan Whitehorn 187757e5b29SNathan Whitehorn error = bus_dmamem_alloc(sc->rx_dma_tag, (void **)&sc->rx_buf, 188757e5b29SNathan Whitehorn BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->rx_buf_map); 189757e5b29SNathan Whitehorn error = bus_dmamap_load(sc->rx_dma_tag, sc->rx_buf_map, sc->rx_buf, 190757e5b29SNathan Whitehorn LLAN_RX_BUF_LEN, llan_rx_load_cb, sc, 0); 191757e5b29SNathan Whitehorn 192757e5b29SNathan Whitehorn /* TX DMA maps */ 193757e5b29SNathan Whitehorn bus_dmamap_create(sc->tx_dma_tag, 0, &sc->tx_dma_map); 194757e5b29SNathan Whitehorn 195757e5b29SNathan Whitehorn /* RX DMA */ 196757e5b29SNathan Whitehorn for (i = 0; i < LLAN_MAX_RX_PACKETS; i++) { 197757e5b29SNathan Whitehorn error = bus_dmamap_create(sc->rxbuf_dma_tag, 0, 198757e5b29SNathan Whitehorn &sc->rx_xfer[i].rx_dmamap); 199757e5b29SNathan Whitehorn sc->rx_xfer[i].rx_mbuf = NULL; 200757e5b29SNathan Whitehorn } 201757e5b29SNathan Whitehorn 202757e5b29SNathan Whitehorn /* Attach to network stack */ 203757e5b29SNathan Whitehorn sc->ifp = if_alloc(IFT_ETHER); 204757e5b29SNathan Whitehorn sc->ifp->if_softc = sc; 205757e5b29SNathan Whitehorn 206757e5b29SNathan Whitehorn if_initname(sc->ifp, device_get_name(dev), device_get_unit(dev)); 207757e5b29SNathan Whitehorn sc->ifp->if_mtu = ETHERMTU; /* XXX max-frame-size from OF? */ 208757e5b29SNathan Whitehorn sc->ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 209757e5b29SNathan Whitehorn sc->ifp->if_hwassist = 0; /* XXX: ibm,illan-options */ 210757e5b29SNathan Whitehorn sc->ifp->if_capabilities = 0; 211757e5b29SNathan Whitehorn sc->ifp->if_capenable = 0; 212757e5b29SNathan Whitehorn sc->ifp->if_start = llan_start; 213757e5b29SNathan Whitehorn sc->ifp->if_ioctl = llan_ioctl; 214757e5b29SNathan Whitehorn sc->ifp->if_init = llan_init; 215757e5b29SNathan Whitehorn 216757e5b29SNathan Whitehorn IFQ_SET_MAXLEN(&sc->ifp->if_snd, LLAN_MAX_TX_PACKETS); 217757e5b29SNathan Whitehorn sc->ifp->if_snd.ifq_drv_maxlen = LLAN_MAX_TX_PACKETS; 218757e5b29SNathan Whitehorn IFQ_SET_READY(&sc->ifp->if_snd); 219757e5b29SNathan Whitehorn 220757e5b29SNathan Whitehorn ether_ifattach(sc->ifp, &sc->mac_address[2]); 221757e5b29SNathan Whitehorn 222757e5b29SNathan Whitehorn return (0); 223757e5b29SNathan Whitehorn } 224757e5b29SNathan Whitehorn 225757e5b29SNathan Whitehorn static void 226757e5b29SNathan Whitehorn llan_rx_load_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int err) 227757e5b29SNathan Whitehorn { 228757e5b29SNathan Whitehorn struct llan_softc *sc = xsc; 229757e5b29SNathan Whitehorn 230757e5b29SNathan Whitehorn sc->rx_buf_phys = segs[0].ds_addr; 231757e5b29SNathan Whitehorn sc->rx_buf_len = segs[0].ds_len - 2*PAGE_SIZE; 232757e5b29SNathan Whitehorn sc->input_buf_phys = segs[0].ds_addr + segs[0].ds_len - PAGE_SIZE; 233757e5b29SNathan Whitehorn sc->filter_buf_phys = segs[0].ds_addr + segs[0].ds_len - 2*PAGE_SIZE; 234757e5b29SNathan Whitehorn } 235757e5b29SNathan Whitehorn 236757e5b29SNathan Whitehorn static void 237757e5b29SNathan Whitehorn llan_init(void *xsc) 238757e5b29SNathan Whitehorn { 239757e5b29SNathan Whitehorn struct llan_softc *sc = xsc; 240757e5b29SNathan Whitehorn uint64_t rx_buf_desc; 241757e5b29SNathan Whitehorn uint64_t macaddr; 242757e5b29SNathan Whitehorn int err, i; 243757e5b29SNathan Whitehorn 244757e5b29SNathan Whitehorn mtx_lock(&sc->io_lock); 245757e5b29SNathan Whitehorn 246757e5b29SNathan Whitehorn phyp_hcall(H_FREE_LOGICAL_LAN, sc->unit); 247757e5b29SNathan Whitehorn 248757e5b29SNathan Whitehorn /* Create buffers (page 539) */ 249757e5b29SNathan Whitehorn sc->rx_dma_slot = 0; 250757e5b29SNathan Whitehorn sc->rx_valid_val = 1; 251757e5b29SNathan Whitehorn 252757e5b29SNathan Whitehorn rx_buf_desc = (1UL << 63); /* valid */ 253757e5b29SNathan Whitehorn rx_buf_desc |= (sc->rx_buf_len << 32); 254757e5b29SNathan Whitehorn rx_buf_desc |= sc->rx_buf_phys; 255757e5b29SNathan Whitehorn memcpy(&macaddr, sc->mac_address, 8); 256757e5b29SNathan Whitehorn err = phyp_hcall(H_REGISTER_LOGICAL_LAN, sc->unit, sc->input_buf_phys, 257757e5b29SNathan Whitehorn rx_buf_desc, sc->filter_buf_phys, macaddr); 258757e5b29SNathan Whitehorn 259757e5b29SNathan Whitehorn for (i = 0; i < LLAN_MAX_RX_PACKETS; i++) 260757e5b29SNathan Whitehorn llan_add_rxbuf(sc, &sc->rx_xfer[i]); 261757e5b29SNathan Whitehorn 262757e5b29SNathan Whitehorn phyp_hcall(H_VIO_SIGNAL, sc->unit, 1); /* Enable interrupts */ 263757e5b29SNathan Whitehorn 264757e5b29SNathan Whitehorn /* Tell stack we're up */ 265757e5b29SNathan Whitehorn sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 266757e5b29SNathan Whitehorn sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 267757e5b29SNathan Whitehorn 268757e5b29SNathan Whitehorn mtx_unlock(&sc->io_lock); 269757e5b29SNathan Whitehorn } 270757e5b29SNathan Whitehorn 271757e5b29SNathan Whitehorn static int 272757e5b29SNathan Whitehorn llan_add_rxbuf(struct llan_softc *sc, struct llan_xfer *rx) 273757e5b29SNathan Whitehorn { 274757e5b29SNathan Whitehorn struct mbuf *m; 275757e5b29SNathan Whitehorn bus_dma_segment_t segs[1]; 276757e5b29SNathan Whitehorn int error, nsegs; 277757e5b29SNathan Whitehorn 278757e5b29SNathan Whitehorn mtx_assert(&sc->io_lock, MA_OWNED); 279757e5b29SNathan Whitehorn 280757e5b29SNathan Whitehorn m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 281757e5b29SNathan Whitehorn if (m == NULL) 282757e5b29SNathan Whitehorn return (ENOBUFS); 283757e5b29SNathan Whitehorn 284757e5b29SNathan Whitehorn m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; 285757e5b29SNathan Whitehorn if (rx->rx_mbuf != NULL) { 286757e5b29SNathan Whitehorn bus_dmamap_sync(sc->rxbuf_dma_tag, rx->rx_dmamap, 287757e5b29SNathan Whitehorn BUS_DMASYNC_POSTREAD); 288757e5b29SNathan Whitehorn bus_dmamap_unload(sc->rxbuf_dma_tag, rx->rx_dmamap); 289757e5b29SNathan Whitehorn } 290757e5b29SNathan Whitehorn 291757e5b29SNathan Whitehorn /* Save pointer to buffer structure */ 292757e5b29SNathan Whitehorn m_copyback(m, 0, 8, (void *)&rx); 293757e5b29SNathan Whitehorn 294757e5b29SNathan Whitehorn error = bus_dmamap_load_mbuf_sg(sc->rxbuf_dma_tag, rx->rx_dmamap, m, 295757e5b29SNathan Whitehorn segs, &nsegs, BUS_DMA_NOWAIT); 296757e5b29SNathan Whitehorn if (error != 0) { 297757e5b29SNathan Whitehorn device_printf(sc->dev, 298757e5b29SNathan Whitehorn "cannot load RX DMA map %p, error = %d\n", rx, error); 299757e5b29SNathan Whitehorn m_freem(m); 300757e5b29SNathan Whitehorn return (error); 301757e5b29SNathan Whitehorn } 302757e5b29SNathan Whitehorn 303757e5b29SNathan Whitehorn /* If nsegs is wrong then the stack is corrupt. */ 304757e5b29SNathan Whitehorn KASSERT(nsegs == 1, 305757e5b29SNathan Whitehorn ("%s: too many DMA segments (%d)", __func__, nsegs)); 306757e5b29SNathan Whitehorn rx->rx_mbuf = m; 307757e5b29SNathan Whitehorn 308757e5b29SNathan Whitehorn bus_dmamap_sync(sc->rxbuf_dma_tag, rx->rx_dmamap, BUS_DMASYNC_PREREAD); 309757e5b29SNathan Whitehorn 310757e5b29SNathan Whitehorn rx->rx_bufdesc = (1UL << 63); /* valid */ 311757e5b29SNathan Whitehorn rx->rx_bufdesc |= (((uint64_t)segs[0].ds_len) << 32); 312757e5b29SNathan Whitehorn rx->rx_bufdesc |= segs[0].ds_addr; 313757e5b29SNathan Whitehorn error = phyp_hcall(H_ADD_LOGICAL_LAN_BUFFER, sc->unit, rx->rx_bufdesc); 314757e5b29SNathan Whitehorn if (error != 0) { 315757e5b29SNathan Whitehorn m_freem(m); 316757e5b29SNathan Whitehorn rx->rx_mbuf = NULL; 317757e5b29SNathan Whitehorn return (ENOBUFS); 318757e5b29SNathan Whitehorn } 319757e5b29SNathan Whitehorn 320757e5b29SNathan Whitehorn return (0); 321757e5b29SNathan Whitehorn } 322757e5b29SNathan Whitehorn 323757e5b29SNathan Whitehorn static void 324757e5b29SNathan Whitehorn llan_intr(void *xsc) 325757e5b29SNathan Whitehorn { 326757e5b29SNathan Whitehorn struct llan_softc *sc = xsc; 327757e5b29SNathan Whitehorn struct llan_xfer *rx; 328757e5b29SNathan Whitehorn struct mbuf *m; 329757e5b29SNathan Whitehorn 330757e5b29SNathan Whitehorn mtx_lock(&sc->io_lock); 331757e5b29SNathan Whitehorn phyp_hcall(H_VIO_SIGNAL, sc->unit, 0); 332757e5b29SNathan Whitehorn 333757e5b29SNathan Whitehorn while ((sc->rx_buf[sc->rx_dma_slot].control >> 7) == sc->rx_valid_val) { 334757e5b29SNathan Whitehorn rx = (struct llan_xfer *)sc->rx_buf[sc->rx_dma_slot].handle; 335757e5b29SNathan Whitehorn m = rx->rx_mbuf; 336757e5b29SNathan Whitehorn m_adj(m, sc->rx_buf[sc->rx_dma_slot].offset - 8); 337757e5b29SNathan Whitehorn m->m_len = sc->rx_buf[sc->rx_dma_slot].length; 338757e5b29SNathan Whitehorn 339757e5b29SNathan Whitehorn /* llan_add_rxbuf does DMA sync and unload as well as requeue */ 340757e5b29SNathan Whitehorn if (llan_add_rxbuf(sc, rx) != 0) { 341757e5b29SNathan Whitehorn sc->ifp->if_ierrors++; 342757e5b29SNathan Whitehorn phyp_hcall(H_ADD_LOGICAL_LAN_BUFFER, sc->unit, 343757e5b29SNathan Whitehorn rx->rx_bufdesc); 344757e5b29SNathan Whitehorn continue; 345757e5b29SNathan Whitehorn } 346757e5b29SNathan Whitehorn 347757e5b29SNathan Whitehorn sc->ifp->if_ipackets++; 348757e5b29SNathan Whitehorn m_adj(m, sc->rx_buf[sc->rx_dma_slot].offset); 349757e5b29SNathan Whitehorn m->m_len = sc->rx_buf[sc->rx_dma_slot].length; 350757e5b29SNathan Whitehorn m->m_pkthdr.rcvif = sc->ifp; 351757e5b29SNathan Whitehorn m->m_pkthdr.len = m->m_len; 352757e5b29SNathan Whitehorn sc->rx_dma_slot++; 353757e5b29SNathan Whitehorn 354757e5b29SNathan Whitehorn if (sc->rx_dma_slot >= sc->rx_buf_len/sizeof(sc->rx_buf[0])) { 355757e5b29SNathan Whitehorn sc->rx_dma_slot = 0; 356757e5b29SNathan Whitehorn sc->rx_valid_val = !sc->rx_valid_val; 357757e5b29SNathan Whitehorn } 358757e5b29SNathan Whitehorn 359757e5b29SNathan Whitehorn mtx_unlock(&sc->io_lock); 360757e5b29SNathan Whitehorn (*sc->ifp->if_input)(sc->ifp, m); 361757e5b29SNathan Whitehorn mtx_lock(&sc->io_lock); 362757e5b29SNathan Whitehorn } 363757e5b29SNathan Whitehorn 364757e5b29SNathan Whitehorn phyp_hcall(H_VIO_SIGNAL, sc->unit, 1); 365757e5b29SNathan Whitehorn mtx_unlock(&sc->io_lock); 366757e5b29SNathan Whitehorn } 367757e5b29SNathan Whitehorn 368757e5b29SNathan Whitehorn static void 369757e5b29SNathan Whitehorn llan_send_packet(void *xsc, bus_dma_segment_t *segs, int nsegs, 370757e5b29SNathan Whitehorn bus_size_t mapsize, int error) 371757e5b29SNathan Whitehorn { 372757e5b29SNathan Whitehorn struct llan_softc *sc = xsc; 373757e5b29SNathan Whitehorn uint64_t bufdescs[6]; 374757e5b29SNathan Whitehorn int i; 375757e5b29SNathan Whitehorn 376757e5b29SNathan Whitehorn bzero(bufdescs, sizeof(bufdescs)); 377757e5b29SNathan Whitehorn 378757e5b29SNathan Whitehorn for (i = 0; i < nsegs; i++) { 379757e5b29SNathan Whitehorn bufdescs[i] = (1UL << 63); /* valid */ 380757e5b29SNathan Whitehorn bufdescs[i] |= (((uint64_t)segs[i].ds_len) << 32); 381757e5b29SNathan Whitehorn bufdescs[i] |= segs[i].ds_addr; 382757e5b29SNathan Whitehorn } 383757e5b29SNathan Whitehorn 384*af4c3211SNathan Whitehorn phyp_hcall(H_SEND_LOGICAL_LAN, sc->unit, bufdescs[0], 385757e5b29SNathan Whitehorn bufdescs[1], bufdescs[2], bufdescs[3], bufdescs[4], bufdescs[5], 0); 386*af4c3211SNathan Whitehorn /* 387*af4c3211SNathan Whitehorn * The hypercall returning implies completion -- or that the call will 388*af4c3211SNathan Whitehorn * not complete. In principle, we should try a few times if we get back 389*af4c3211SNathan Whitehorn * H_BUSY based on the continuation token in R4. For now, just drop 390*af4c3211SNathan Whitehorn * the packet in such cases. 391*af4c3211SNathan Whitehorn */ 392757e5b29SNathan Whitehorn } 393757e5b29SNathan Whitehorn 394757e5b29SNathan Whitehorn static void 395757e5b29SNathan Whitehorn llan_start_locked(struct ifnet *ifp) 396757e5b29SNathan Whitehorn { 397757e5b29SNathan Whitehorn struct llan_softc *sc = ifp->if_softc; 398757e5b29SNathan Whitehorn bus_addr_t first; 399757e5b29SNathan Whitehorn int nsegs; 400757e5b29SNathan Whitehorn struct mbuf *mb_head, *m; 401757e5b29SNathan Whitehorn 402757e5b29SNathan Whitehorn mtx_assert(&sc->io_lock, MA_OWNED); 403757e5b29SNathan Whitehorn first = 0; 404757e5b29SNathan Whitehorn 405757e5b29SNathan Whitehorn if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 406757e5b29SNathan Whitehorn IFF_DRV_RUNNING) 407757e5b29SNathan Whitehorn return; 408757e5b29SNathan Whitehorn 409757e5b29SNathan Whitehorn while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 410757e5b29SNathan Whitehorn IFQ_DRV_DEQUEUE(&ifp->if_snd, mb_head); 411757e5b29SNathan Whitehorn 412757e5b29SNathan Whitehorn if (mb_head == NULL) 413757e5b29SNathan Whitehorn break; 414757e5b29SNathan Whitehorn 415757e5b29SNathan Whitehorn BPF_MTAP(ifp, mb_head); 416757e5b29SNathan Whitehorn 417757e5b29SNathan Whitehorn for (m = mb_head, nsegs = 0; m != NULL; m = m->m_next) 418757e5b29SNathan Whitehorn nsegs++; 419757e5b29SNathan Whitehorn if (nsegs > 6) { 420757e5b29SNathan Whitehorn m = m_collapse(mb_head, M_NOWAIT, 6); 421757e5b29SNathan Whitehorn if (m == NULL) { 422757e5b29SNathan Whitehorn m_freem(mb_head); 423757e5b29SNathan Whitehorn continue; 424757e5b29SNathan Whitehorn } 425757e5b29SNathan Whitehorn } 426757e5b29SNathan Whitehorn 427*af4c3211SNathan Whitehorn bus_dmamap_load_mbuf(sc->tx_dma_tag, sc->tx_dma_map, 428757e5b29SNathan Whitehorn mb_head, llan_send_packet, sc, 0); 429*af4c3211SNathan Whitehorn bus_dmamap_unload(sc->tx_dma_tag, sc->tx_dma_map); 430757e5b29SNathan Whitehorn m_freem(mb_head); 431757e5b29SNathan Whitehorn } 432757e5b29SNathan Whitehorn } 433757e5b29SNathan Whitehorn 434757e5b29SNathan Whitehorn static void 435757e5b29SNathan Whitehorn llan_start(struct ifnet *ifp) 436757e5b29SNathan Whitehorn { 437757e5b29SNathan Whitehorn struct llan_softc *sc = ifp->if_softc; 438757e5b29SNathan Whitehorn 439757e5b29SNathan Whitehorn mtx_lock(&sc->io_lock); 440757e5b29SNathan Whitehorn llan_start_locked(ifp); 441757e5b29SNathan Whitehorn mtx_unlock(&sc->io_lock); 442757e5b29SNathan Whitehorn } 443757e5b29SNathan Whitehorn 444757e5b29SNathan Whitehorn static int 445757e5b29SNathan Whitehorn llan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 446757e5b29SNathan Whitehorn { 447757e5b29SNathan Whitehorn int err; 448757e5b29SNathan Whitehorn 449757e5b29SNathan Whitehorn err = ether_ioctl(ifp, cmd, data); 450757e5b29SNathan Whitehorn 451757e5b29SNathan Whitehorn return (err); 452757e5b29SNathan Whitehorn } 453757e5b29SNathan Whitehorn 454