1256778Snwhitehorn/*- 2256778Snwhitehorn * Copyright 2013 Nathan Whitehorn 3256778Snwhitehorn * All rights reserved. 4256778Snwhitehorn * 5256778Snwhitehorn * Redistribution and use in source and binary forms, with or without 6256778Snwhitehorn * modification, are permitted provided that the following conditions 7256778Snwhitehorn * are met: 8256778Snwhitehorn * 1. Redistributions of source code must retain the above copyright 9256778Snwhitehorn * notice, this list of conditions and the following disclaimer. 10256778Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 11256778Snwhitehorn * notice, this list of conditions and the following disclaimer in the 12256778Snwhitehorn * documentation and/or other materials provided with the distribution. 13256778Snwhitehorn * 14256778Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15256778Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16256778Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17256778Snwhitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18256778Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19256778Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20256778Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21256778Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22256778Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23256778Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24256778Snwhitehorn * SUCH DAMAGE. 25256778Snwhitehorn */ 26256778Snwhitehorn 27256778Snwhitehorn#include <sys/cdefs.h> 28256778Snwhitehorn__FBSDID("$FreeBSD: releng/10.2/sys/powerpc/pseries/phyp_llan.c 257292 2013-10-28 23:47:52Z nwhitehorn $"); 29256778Snwhitehorn 30256778Snwhitehorn#include <sys/param.h> 31256778Snwhitehorn#include <sys/systm.h> 32256778Snwhitehorn#include <sys/sockio.h> 33256778Snwhitehorn#include <sys/endian.h> 34256778Snwhitehorn#include <sys/mbuf.h> 35256778Snwhitehorn#include <sys/module.h> 36256778Snwhitehorn#include <sys/malloc.h> 37256778Snwhitehorn#include <sys/kernel.h> 38256778Snwhitehorn#include <sys/socket.h> 39256778Snwhitehorn 40256778Snwhitehorn#include <net/bpf.h> 41256778Snwhitehorn#include <net/if.h> 42256778Snwhitehorn#include <net/if_arp.h> 43256778Snwhitehorn#include <net/ethernet.h> 44256778Snwhitehorn#include <net/if_dl.h> 45256778Snwhitehorn#include <net/if_media.h> 46256778Snwhitehorn#include <net/if_types.h> 47256778Snwhitehorn#include <net/if_vlan_var.h> 48256778Snwhitehorn 49256778Snwhitehorn#include <dev/ofw/openfirm.h> 50256778Snwhitehorn#include <dev/ofw/ofw_bus.h> 51256778Snwhitehorn#include <dev/ofw/ofw_bus_subr.h> 52256778Snwhitehorn#include <machine/bus.h> 53256778Snwhitehorn#include <machine/resource.h> 54256778Snwhitehorn#include <sys/bus.h> 55256778Snwhitehorn#include <sys/rman.h> 56256778Snwhitehorn 57256778Snwhitehorn#include <powerpc/pseries/phyp-hvcall.h> 58256778Snwhitehorn 59256778Snwhitehorn#define LLAN_MAX_RX_PACKETS 100 60256778Snwhitehorn#define LLAN_MAX_TX_PACKETS 100 61256778Snwhitehorn#define LLAN_RX_BUF_LEN 8*PAGE_SIZE 62256778Snwhitehorn 63257292Snwhitehorn#define LLAN_BUFDESC_VALID (1ULL << 63) 64257292Snwhitehorn#define LLAN_ADD_MULTICAST 0x1 65257292Snwhitehorn#define LLAN_DEL_MULTICAST 0x2 66257292Snwhitehorn#define LLAN_CLEAR_MULTICAST 0x3 67257292Snwhitehorn 68256778Snwhitehornstruct llan_xfer { 69256778Snwhitehorn struct mbuf *rx_mbuf; 70256778Snwhitehorn bus_dmamap_t rx_dmamap; 71256778Snwhitehorn uint64_t rx_bufdesc; 72256778Snwhitehorn}; 73256778Snwhitehorn 74256778Snwhitehornstruct llan_receive_queue_entry { /* PAPR page 539 */ 75256778Snwhitehorn uint8_t control; 76256778Snwhitehorn uint8_t reserved; 77256778Snwhitehorn uint16_t offset; 78256778Snwhitehorn uint32_t length; 79256778Snwhitehorn uint64_t handle; 80256778Snwhitehorn} __packed; 81256778Snwhitehorn 82256778Snwhitehornstruct llan_softc { 83256778Snwhitehorn device_t dev; 84256778Snwhitehorn struct mtx io_lock; 85256778Snwhitehorn 86256778Snwhitehorn cell_t unit; 87256778Snwhitehorn uint8_t mac_address[8]; 88256778Snwhitehorn 89256778Snwhitehorn int irqid; 90256778Snwhitehorn struct resource *irq; 91256778Snwhitehorn void *irq_cookie; 92256778Snwhitehorn 93256778Snwhitehorn bus_dma_tag_t rx_dma_tag; 94256778Snwhitehorn bus_dma_tag_t rxbuf_dma_tag; 95256778Snwhitehorn bus_dma_tag_t tx_dma_tag; 96256778Snwhitehorn 97256778Snwhitehorn bus_dmamap_t tx_dma_map; 98256778Snwhitehorn 99256778Snwhitehorn struct llan_receive_queue_entry *rx_buf; 100256778Snwhitehorn int rx_dma_slot; 101256778Snwhitehorn int rx_valid_val; 102256778Snwhitehorn bus_dmamap_t rx_buf_map; 103256778Snwhitehorn bus_addr_t rx_buf_phys; 104256778Snwhitehorn bus_size_t rx_buf_len; 105256778Snwhitehorn bus_addr_t input_buf_phys; 106256778Snwhitehorn bus_addr_t filter_buf_phys; 107256778Snwhitehorn struct llan_xfer rx_xfer[LLAN_MAX_RX_PACKETS]; 108256778Snwhitehorn 109256778Snwhitehorn struct ifnet *ifp; 110256778Snwhitehorn}; 111256778Snwhitehorn 112256778Snwhitehornstatic int llan_probe(device_t); 113256778Snwhitehornstatic int llan_attach(device_t); 114256778Snwhitehornstatic void llan_intr(void *xsc); 115256778Snwhitehornstatic void llan_init(void *xsc); 116256778Snwhitehornstatic void llan_start(struct ifnet *ifp); 117256778Snwhitehornstatic int llan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 118256778Snwhitehornstatic void llan_rx_load_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, 119256778Snwhitehorn int err); 120256778Snwhitehornstatic int llan_add_rxbuf(struct llan_softc *sc, struct llan_xfer *rx); 121257292Snwhitehornstatic int llan_set_multicast(struct llan_softc *sc); 122256778Snwhitehorn 123256778Snwhitehornstatic devclass_t llan_devclass; 124256778Snwhitehornstatic device_method_t llan_methods[] = { 125256778Snwhitehorn DEVMETHOD(device_probe, llan_probe), 126256778Snwhitehorn DEVMETHOD(device_attach, llan_attach), 127256778Snwhitehorn 128256778Snwhitehorn DEVMETHOD_END 129256778Snwhitehorn}; 130256778Snwhitehornstatic driver_t llan_driver = { 131256778Snwhitehorn "llan", 132256778Snwhitehorn llan_methods, 133256778Snwhitehorn sizeof(struct llan_softc) 134256778Snwhitehorn}; 135256778SnwhitehornDRIVER_MODULE(llan, vdevice, llan_driver, llan_devclass, 0, 0); 136256778Snwhitehorn 137256778Snwhitehornstatic int 138256778Snwhitehornllan_probe(device_t dev) 139256778Snwhitehorn{ 140256778Snwhitehorn if (!ofw_bus_is_compatible(dev,"IBM,l-lan")) 141256778Snwhitehorn return (ENXIO); 142256778Snwhitehorn 143256778Snwhitehorn device_set_desc(dev, "POWER Hypervisor Virtual Ethernet"); 144256778Snwhitehorn return (0); 145256778Snwhitehorn} 146256778Snwhitehorn 147256778Snwhitehornstatic int 148256778Snwhitehornllan_attach(device_t dev) 149256778Snwhitehorn{ 150256778Snwhitehorn struct llan_softc *sc; 151256778Snwhitehorn phandle_t node; 152256778Snwhitehorn int error, i; 153256778Snwhitehorn 154256778Snwhitehorn sc = device_get_softc(dev); 155256778Snwhitehorn sc->dev = dev; 156256778Snwhitehorn 157256778Snwhitehorn /* Get firmware properties */ 158256778Snwhitehorn node = ofw_bus_get_node(dev); 159256778Snwhitehorn OF_getprop(node, "local-mac-address", sc->mac_address, 160256778Snwhitehorn sizeof(sc->mac_address)); 161256778Snwhitehorn OF_getprop(node, "reg", &sc->unit, sizeof(sc->unit)); 162256778Snwhitehorn 163256778Snwhitehorn mtx_init(&sc->io_lock, "llan", NULL, MTX_DEF); 164256778Snwhitehorn 165256778Snwhitehorn /* Setup interrupt */ 166256778Snwhitehorn sc->irqid = 0; 167256778Snwhitehorn sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 168256778Snwhitehorn RF_ACTIVE); 169256778Snwhitehorn 170256778Snwhitehorn if (!sc->irq) { 171256778Snwhitehorn device_printf(dev, "Could not allocate IRQ\n"); 172256778Snwhitehorn mtx_destroy(&sc->io_lock); 173256778Snwhitehorn return (ENXIO); 174256778Snwhitehorn } 175256778Snwhitehorn 176256778Snwhitehorn bus_setup_intr(dev, sc->irq, INTR_TYPE_MISC | INTR_MPSAFE | 177256778Snwhitehorn INTR_ENTROPY, NULL, llan_intr, sc, &sc->irq_cookie); 178256778Snwhitehorn 179256778Snwhitehorn /* Setup DMA */ 180256778Snwhitehorn error = bus_dma_tag_create(bus_get_dma_tag(dev), 16, 0, 181256778Snwhitehorn BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 182256778Snwhitehorn LLAN_RX_BUF_LEN, 1, BUS_SPACE_MAXSIZE_32BIT, 183256778Snwhitehorn 0, NULL, NULL, &sc->rx_dma_tag); 184256778Snwhitehorn error = bus_dma_tag_create(bus_get_dma_tag(dev), 4, 0, 185256778Snwhitehorn BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 186256778Snwhitehorn BUS_SPACE_MAXSIZE, 1, BUS_SPACE_MAXSIZE_32BIT, 187256778Snwhitehorn 0, NULL, NULL, &sc->rxbuf_dma_tag); 188256778Snwhitehorn error = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, 189256778Snwhitehorn BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 190256778Snwhitehorn BUS_SPACE_MAXSIZE, 6, BUS_SPACE_MAXSIZE_32BIT, 0, 191256778Snwhitehorn busdma_lock_mutex, &sc->io_lock, &sc->tx_dma_tag); 192256778Snwhitehorn 193256778Snwhitehorn error = bus_dmamem_alloc(sc->rx_dma_tag, (void **)&sc->rx_buf, 194256778Snwhitehorn BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->rx_buf_map); 195256778Snwhitehorn error = bus_dmamap_load(sc->rx_dma_tag, sc->rx_buf_map, sc->rx_buf, 196256778Snwhitehorn LLAN_RX_BUF_LEN, llan_rx_load_cb, sc, 0); 197256778Snwhitehorn 198256778Snwhitehorn /* TX DMA maps */ 199256778Snwhitehorn bus_dmamap_create(sc->tx_dma_tag, 0, &sc->tx_dma_map); 200256778Snwhitehorn 201256778Snwhitehorn /* RX DMA */ 202256778Snwhitehorn for (i = 0; i < LLAN_MAX_RX_PACKETS; i++) { 203256778Snwhitehorn error = bus_dmamap_create(sc->rxbuf_dma_tag, 0, 204256778Snwhitehorn &sc->rx_xfer[i].rx_dmamap); 205256778Snwhitehorn sc->rx_xfer[i].rx_mbuf = NULL; 206256778Snwhitehorn } 207256778Snwhitehorn 208256778Snwhitehorn /* Attach to network stack */ 209256778Snwhitehorn sc->ifp = if_alloc(IFT_ETHER); 210256778Snwhitehorn sc->ifp->if_softc = sc; 211256778Snwhitehorn 212256778Snwhitehorn if_initname(sc->ifp, device_get_name(dev), device_get_unit(dev)); 213256778Snwhitehorn sc->ifp->if_mtu = ETHERMTU; /* XXX max-frame-size from OF? */ 214256778Snwhitehorn sc->ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 215256778Snwhitehorn sc->ifp->if_hwassist = 0; /* XXX: ibm,illan-options */ 216256778Snwhitehorn sc->ifp->if_capabilities = 0; 217256778Snwhitehorn sc->ifp->if_capenable = 0; 218256778Snwhitehorn sc->ifp->if_start = llan_start; 219256778Snwhitehorn sc->ifp->if_ioctl = llan_ioctl; 220256778Snwhitehorn sc->ifp->if_init = llan_init; 221256778Snwhitehorn 222256778Snwhitehorn IFQ_SET_MAXLEN(&sc->ifp->if_snd, LLAN_MAX_TX_PACKETS); 223256778Snwhitehorn sc->ifp->if_snd.ifq_drv_maxlen = LLAN_MAX_TX_PACKETS; 224256778Snwhitehorn IFQ_SET_READY(&sc->ifp->if_snd); 225256778Snwhitehorn 226256778Snwhitehorn ether_ifattach(sc->ifp, &sc->mac_address[2]); 227256778Snwhitehorn 228256778Snwhitehorn return (0); 229256778Snwhitehorn} 230256778Snwhitehorn 231256778Snwhitehornstatic void 232256778Snwhitehornllan_rx_load_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int err) 233256778Snwhitehorn{ 234256778Snwhitehorn struct llan_softc *sc = xsc; 235256778Snwhitehorn 236256778Snwhitehorn sc->rx_buf_phys = segs[0].ds_addr; 237256778Snwhitehorn sc->rx_buf_len = segs[0].ds_len - 2*PAGE_SIZE; 238256778Snwhitehorn sc->input_buf_phys = segs[0].ds_addr + segs[0].ds_len - PAGE_SIZE; 239256778Snwhitehorn sc->filter_buf_phys = segs[0].ds_addr + segs[0].ds_len - 2*PAGE_SIZE; 240256778Snwhitehorn} 241256778Snwhitehorn 242256778Snwhitehornstatic void 243256778Snwhitehornllan_init(void *xsc) 244256778Snwhitehorn{ 245256778Snwhitehorn struct llan_softc *sc = xsc; 246256778Snwhitehorn uint64_t rx_buf_desc; 247256778Snwhitehorn uint64_t macaddr; 248256778Snwhitehorn int err, i; 249256778Snwhitehorn 250256778Snwhitehorn mtx_lock(&sc->io_lock); 251256778Snwhitehorn 252256778Snwhitehorn phyp_hcall(H_FREE_LOGICAL_LAN, sc->unit); 253256778Snwhitehorn 254256778Snwhitehorn /* Create buffers (page 539) */ 255256778Snwhitehorn sc->rx_dma_slot = 0; 256256778Snwhitehorn sc->rx_valid_val = 1; 257256778Snwhitehorn 258257292Snwhitehorn rx_buf_desc = LLAN_BUFDESC_VALID; 259256778Snwhitehorn rx_buf_desc |= (sc->rx_buf_len << 32); 260256778Snwhitehorn rx_buf_desc |= sc->rx_buf_phys; 261256778Snwhitehorn memcpy(&macaddr, sc->mac_address, 8); 262256778Snwhitehorn err = phyp_hcall(H_REGISTER_LOGICAL_LAN, sc->unit, sc->input_buf_phys, 263256778Snwhitehorn rx_buf_desc, sc->filter_buf_phys, macaddr); 264256778Snwhitehorn 265256778Snwhitehorn for (i = 0; i < LLAN_MAX_RX_PACKETS; i++) 266256778Snwhitehorn llan_add_rxbuf(sc, &sc->rx_xfer[i]); 267256778Snwhitehorn 268256778Snwhitehorn phyp_hcall(H_VIO_SIGNAL, sc->unit, 1); /* Enable interrupts */ 269256778Snwhitehorn 270256778Snwhitehorn /* Tell stack we're up */ 271256778Snwhitehorn sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 272256778Snwhitehorn sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 273256778Snwhitehorn 274256778Snwhitehorn mtx_unlock(&sc->io_lock); 275256778Snwhitehorn} 276256778Snwhitehorn 277256778Snwhitehornstatic int 278256778Snwhitehornllan_add_rxbuf(struct llan_softc *sc, struct llan_xfer *rx) 279256778Snwhitehorn{ 280256778Snwhitehorn struct mbuf *m; 281256778Snwhitehorn bus_dma_segment_t segs[1]; 282256778Snwhitehorn int error, nsegs; 283256778Snwhitehorn 284256778Snwhitehorn mtx_assert(&sc->io_lock, MA_OWNED); 285256778Snwhitehorn 286256778Snwhitehorn m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 287256778Snwhitehorn if (m == NULL) 288256778Snwhitehorn return (ENOBUFS); 289256778Snwhitehorn 290256778Snwhitehorn m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; 291256778Snwhitehorn if (rx->rx_mbuf != NULL) { 292256778Snwhitehorn bus_dmamap_sync(sc->rxbuf_dma_tag, rx->rx_dmamap, 293256778Snwhitehorn BUS_DMASYNC_POSTREAD); 294256778Snwhitehorn bus_dmamap_unload(sc->rxbuf_dma_tag, rx->rx_dmamap); 295256778Snwhitehorn } 296256778Snwhitehorn 297256778Snwhitehorn /* Save pointer to buffer structure */ 298256778Snwhitehorn m_copyback(m, 0, 8, (void *)&rx); 299256778Snwhitehorn 300256778Snwhitehorn error = bus_dmamap_load_mbuf_sg(sc->rxbuf_dma_tag, rx->rx_dmamap, m, 301256778Snwhitehorn segs, &nsegs, BUS_DMA_NOWAIT); 302256778Snwhitehorn if (error != 0) { 303256778Snwhitehorn device_printf(sc->dev, 304256778Snwhitehorn "cannot load RX DMA map %p, error = %d\n", rx, error); 305256778Snwhitehorn m_freem(m); 306256778Snwhitehorn return (error); 307256778Snwhitehorn } 308256778Snwhitehorn 309256778Snwhitehorn /* If nsegs is wrong then the stack is corrupt. */ 310256778Snwhitehorn KASSERT(nsegs == 1, 311256778Snwhitehorn ("%s: too many DMA segments (%d)", __func__, nsegs)); 312256778Snwhitehorn rx->rx_mbuf = m; 313256778Snwhitehorn 314256778Snwhitehorn bus_dmamap_sync(sc->rxbuf_dma_tag, rx->rx_dmamap, BUS_DMASYNC_PREREAD); 315256778Snwhitehorn 316257292Snwhitehorn rx->rx_bufdesc = LLAN_BUFDESC_VALID; 317256778Snwhitehorn rx->rx_bufdesc |= (((uint64_t)segs[0].ds_len) << 32); 318256778Snwhitehorn rx->rx_bufdesc |= segs[0].ds_addr; 319256778Snwhitehorn error = phyp_hcall(H_ADD_LOGICAL_LAN_BUFFER, sc->unit, rx->rx_bufdesc); 320256778Snwhitehorn if (error != 0) { 321256778Snwhitehorn m_freem(m); 322256778Snwhitehorn rx->rx_mbuf = NULL; 323256778Snwhitehorn return (ENOBUFS); 324256778Snwhitehorn } 325256778Snwhitehorn 326256778Snwhitehorn return (0); 327256778Snwhitehorn} 328256778Snwhitehorn 329256778Snwhitehornstatic void 330256778Snwhitehornllan_intr(void *xsc) 331256778Snwhitehorn{ 332256778Snwhitehorn struct llan_softc *sc = xsc; 333256778Snwhitehorn struct llan_xfer *rx; 334256778Snwhitehorn struct mbuf *m; 335256778Snwhitehorn 336256778Snwhitehorn mtx_lock(&sc->io_lock); 337256778Snwhitehorn phyp_hcall(H_VIO_SIGNAL, sc->unit, 0); 338256778Snwhitehorn 339256778Snwhitehorn while ((sc->rx_buf[sc->rx_dma_slot].control >> 7) == sc->rx_valid_val) { 340256778Snwhitehorn rx = (struct llan_xfer *)sc->rx_buf[sc->rx_dma_slot].handle; 341256778Snwhitehorn m = rx->rx_mbuf; 342256778Snwhitehorn m_adj(m, sc->rx_buf[sc->rx_dma_slot].offset - 8); 343256778Snwhitehorn m->m_len = sc->rx_buf[sc->rx_dma_slot].length; 344256778Snwhitehorn 345256778Snwhitehorn /* llan_add_rxbuf does DMA sync and unload as well as requeue */ 346256778Snwhitehorn if (llan_add_rxbuf(sc, rx) != 0) { 347256778Snwhitehorn sc->ifp->if_ierrors++; 348256778Snwhitehorn phyp_hcall(H_ADD_LOGICAL_LAN_BUFFER, sc->unit, 349256778Snwhitehorn rx->rx_bufdesc); 350256778Snwhitehorn continue; 351256778Snwhitehorn } 352256778Snwhitehorn 353256778Snwhitehorn sc->ifp->if_ipackets++; 354256778Snwhitehorn m_adj(m, sc->rx_buf[sc->rx_dma_slot].offset); 355256778Snwhitehorn m->m_len = sc->rx_buf[sc->rx_dma_slot].length; 356256778Snwhitehorn m->m_pkthdr.rcvif = sc->ifp; 357256778Snwhitehorn m->m_pkthdr.len = m->m_len; 358256778Snwhitehorn sc->rx_dma_slot++; 359256778Snwhitehorn 360256778Snwhitehorn if (sc->rx_dma_slot >= sc->rx_buf_len/sizeof(sc->rx_buf[0])) { 361256778Snwhitehorn sc->rx_dma_slot = 0; 362256778Snwhitehorn sc->rx_valid_val = !sc->rx_valid_val; 363256778Snwhitehorn } 364256778Snwhitehorn 365256778Snwhitehorn mtx_unlock(&sc->io_lock); 366256778Snwhitehorn (*sc->ifp->if_input)(sc->ifp, m); 367256778Snwhitehorn mtx_lock(&sc->io_lock); 368256778Snwhitehorn } 369256778Snwhitehorn 370256778Snwhitehorn phyp_hcall(H_VIO_SIGNAL, sc->unit, 1); 371256778Snwhitehorn mtx_unlock(&sc->io_lock); 372256778Snwhitehorn} 373256778Snwhitehorn 374256778Snwhitehornstatic void 375256778Snwhitehornllan_send_packet(void *xsc, bus_dma_segment_t *segs, int nsegs, 376256778Snwhitehorn bus_size_t mapsize, int error) 377256778Snwhitehorn{ 378256778Snwhitehorn struct llan_softc *sc = xsc; 379256778Snwhitehorn uint64_t bufdescs[6]; 380256778Snwhitehorn int i; 381256778Snwhitehorn 382256778Snwhitehorn bzero(bufdescs, sizeof(bufdescs)); 383256778Snwhitehorn 384256778Snwhitehorn for (i = 0; i < nsegs; i++) { 385257292Snwhitehorn bufdescs[i] = LLAN_BUFDESC_VALID; 386256778Snwhitehorn bufdescs[i] |= (((uint64_t)segs[i].ds_len) << 32); 387256778Snwhitehorn bufdescs[i] |= segs[i].ds_addr; 388256778Snwhitehorn } 389256778Snwhitehorn 390257292Snwhitehorn phyp_hcall(H_SEND_LOGICAL_LAN, sc->unit, bufdescs[0], 391256778Snwhitehorn bufdescs[1], bufdescs[2], bufdescs[3], bufdescs[4], bufdescs[5], 0); 392257292Snwhitehorn /* 393257292Snwhitehorn * The hypercall returning implies completion -- or that the call will 394257292Snwhitehorn * not complete. In principle, we should try a few times if we get back 395257292Snwhitehorn * H_BUSY based on the continuation token in R4. For now, just drop 396257292Snwhitehorn * the packet in such cases. 397257292Snwhitehorn */ 398256778Snwhitehorn} 399256778Snwhitehorn 400256778Snwhitehornstatic void 401256778Snwhitehornllan_start_locked(struct ifnet *ifp) 402256778Snwhitehorn{ 403256778Snwhitehorn struct llan_softc *sc = ifp->if_softc; 404256778Snwhitehorn bus_addr_t first; 405256778Snwhitehorn int nsegs; 406256778Snwhitehorn struct mbuf *mb_head, *m; 407256778Snwhitehorn 408256778Snwhitehorn mtx_assert(&sc->io_lock, MA_OWNED); 409256778Snwhitehorn first = 0; 410256778Snwhitehorn 411256778Snwhitehorn if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 412256778Snwhitehorn IFF_DRV_RUNNING) 413256778Snwhitehorn return; 414256778Snwhitehorn 415256778Snwhitehorn while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 416256778Snwhitehorn IFQ_DRV_DEQUEUE(&ifp->if_snd, mb_head); 417256778Snwhitehorn 418256778Snwhitehorn if (mb_head == NULL) 419256778Snwhitehorn break; 420256778Snwhitehorn 421256778Snwhitehorn BPF_MTAP(ifp, mb_head); 422256778Snwhitehorn 423256778Snwhitehorn for (m = mb_head, nsegs = 0; m != NULL; m = m->m_next) 424256778Snwhitehorn nsegs++; 425256778Snwhitehorn if (nsegs > 6) { 426256778Snwhitehorn m = m_collapse(mb_head, M_NOWAIT, 6); 427256778Snwhitehorn if (m == NULL) { 428256778Snwhitehorn m_freem(mb_head); 429256778Snwhitehorn continue; 430256778Snwhitehorn } 431256778Snwhitehorn } 432256778Snwhitehorn 433257292Snwhitehorn bus_dmamap_load_mbuf(sc->tx_dma_tag, sc->tx_dma_map, 434256778Snwhitehorn mb_head, llan_send_packet, sc, 0); 435257292Snwhitehorn bus_dmamap_unload(sc->tx_dma_tag, sc->tx_dma_map); 436256778Snwhitehorn m_freem(mb_head); 437256778Snwhitehorn } 438256778Snwhitehorn} 439256778Snwhitehorn 440256778Snwhitehornstatic void 441256778Snwhitehornllan_start(struct ifnet *ifp) 442256778Snwhitehorn{ 443256778Snwhitehorn struct llan_softc *sc = ifp->if_softc; 444256778Snwhitehorn 445256778Snwhitehorn mtx_lock(&sc->io_lock); 446256778Snwhitehorn llan_start_locked(ifp); 447256778Snwhitehorn mtx_unlock(&sc->io_lock); 448256778Snwhitehorn} 449256778Snwhitehorn 450256778Snwhitehornstatic int 451257292Snwhitehornllan_set_multicast(struct llan_softc *sc) 452257292Snwhitehorn{ 453257292Snwhitehorn struct ifnet *ifp = sc->ifp; 454257292Snwhitehorn struct ifmultiaddr *inm; 455257292Snwhitehorn uint64_t macaddr; 456257292Snwhitehorn 457257292Snwhitehorn mtx_assert(&sc->io_lock, MA_OWNED); 458257292Snwhitehorn 459257292Snwhitehorn phyp_hcall(H_MULTICAST_CTRL, sc->unit, LLAN_CLEAR_MULTICAST, 0); 460257292Snwhitehorn 461257292Snwhitehorn if_maddr_rlock(ifp); 462257292Snwhitehorn TAILQ_FOREACH(inm, &ifp->if_multiaddrs, ifma_link) { 463257292Snwhitehorn if (inm->ifma_addr->sa_family != AF_LINK) 464257292Snwhitehorn continue; 465257292Snwhitehorn 466257292Snwhitehorn memcpy((uint8_t *)&macaddr + 2, 467257292Snwhitehorn LLADDR((struct sockaddr_dl *)inm->ifma_addr), 6); 468257292Snwhitehorn phyp_hcall(H_MULTICAST_CTRL, sc->unit, LLAN_ADD_MULTICAST, 469257292Snwhitehorn macaddr); 470257292Snwhitehorn } 471257292Snwhitehorn if_maddr_runlock(ifp); 472257292Snwhitehorn 473257292Snwhitehorn return (0); 474257292Snwhitehorn} 475257292Snwhitehorn 476257292Snwhitehornstatic int 477256778Snwhitehornllan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 478256778Snwhitehorn{ 479257292Snwhitehorn int err = 0; 480257292Snwhitehorn struct llan_softc *sc = ifp->if_softc; 481256778Snwhitehorn 482257292Snwhitehorn switch (cmd) { 483257292Snwhitehorn case SIOCADDMULTI: 484257292Snwhitehorn case SIOCDELMULTI: 485257292Snwhitehorn mtx_lock(&sc->io_lock); 486257292Snwhitehorn if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 487257292Snwhitehorn llan_set_multicast(sc); 488257292Snwhitehorn mtx_unlock(&sc->io_lock); 489257292Snwhitehorn break; 490257292Snwhitehorn case SIOCSIFFLAGS: 491257292Snwhitehorn default: 492257292Snwhitehorn err = ether_ioctl(ifp, cmd, data); 493257292Snwhitehorn break; 494257292Snwhitehorn } 495256778Snwhitehorn 496256778Snwhitehorn return (err); 497256778Snwhitehorn} 498256778Snwhitehorn 499