1217044Snwhitehorn/*- 2217044Snwhitehorn * Copyright (C) 2010 Nathan Whitehorn 3217044Snwhitehorn * All rights reserved. 4217044Snwhitehorn * 5217044Snwhitehorn * Redistribution and use in source and binary forms, with or without 6217044Snwhitehorn * modification, are permitted provided that the following conditions 7217044Snwhitehorn * are met: 8217044Snwhitehorn * 1. Redistributions of source code must retain the above copyright 9217044Snwhitehorn * notice, this list of conditions and the following disclaimer. 10217044Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 11217044Snwhitehorn * notice, this list of conditions and the following disclaimer in the 12217044Snwhitehorn * documentation and/or other materials provided with the distribution. 13217044Snwhitehorn * 14217044Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15217044Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16217044Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17217044Snwhitehorn * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18217044Snwhitehorn * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19217044Snwhitehorn * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20217044Snwhitehorn * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21217044Snwhitehorn * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22217044Snwhitehorn * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23217044Snwhitehorn * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24217044Snwhitehorn * 25217044Snwhitehorn * $FreeBSD$ 26217044Snwhitehorn */ 27217044Snwhitehorn 28217044Snwhitehorn#include <sys/param.h> 29217044Snwhitehorn#include <sys/systm.h> 30217044Snwhitehorn#include <sys/sockio.h> 31217044Snwhitehorn#include <sys/endian.h> 32257324Sglebius#include <sys/lock.h> 33217044Snwhitehorn#include <sys/mbuf.h> 34217044Snwhitehorn#include <sys/module.h> 35217044Snwhitehorn#include <sys/malloc.h> 36257324Sglebius#include <sys/mutex.h> 37217044Snwhitehorn#include <sys/kernel.h> 38217044Snwhitehorn#include <sys/socket.h> 39217044Snwhitehorn 40217044Snwhitehorn#include <vm/vm.h> 41217044Snwhitehorn#include <vm/pmap.h> 42217044Snwhitehorn 43217044Snwhitehorn#include <net/bpf.h> 44217044Snwhitehorn#include <net/if.h> 45257324Sglebius#include <net/if_var.h> 46217044Snwhitehorn#include <net/ethernet.h> 47217044Snwhitehorn#include <net/if_media.h> 48217044Snwhitehorn#include <net/if_types.h> 49257324Sglebius#include <net/if_dl.h> 50217044Snwhitehorn 51217044Snwhitehorn#include <machine/pio.h> 52217044Snwhitehorn#include <machine/bus.h> 53217044Snwhitehorn#include <machine/platform.h> 54217044Snwhitehorn#include <machine/resource.h> 55217044Snwhitehorn#include <sys/bus.h> 56217044Snwhitehorn#include <sys/rman.h> 57217044Snwhitehorn 58217044Snwhitehorn#include "ps3bus.h" 59217044Snwhitehorn#include "ps3-hvcall.h" 60217044Snwhitehorn#include "if_glcreg.h" 61217044Snwhitehorn 62217044Snwhitehornstatic int glc_probe(device_t); 63217044Snwhitehornstatic int glc_attach(device_t); 64217044Snwhitehornstatic void glc_init(void *xsc); 65217044Snwhitehornstatic void glc_start(struct ifnet *ifp); 66217044Snwhitehornstatic int glc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 67217044Snwhitehornstatic void glc_set_multicast(struct glc_softc *sc); 68217044Snwhitehornstatic int glc_add_rxbuf(struct glc_softc *sc, int idx); 69217044Snwhitehornstatic int glc_add_rxbuf_dma(struct glc_softc *sc, int idx); 70217044Snwhitehornstatic int glc_encap(struct glc_softc *sc, struct mbuf **m_head, 71217044Snwhitehorn bus_addr_t *pktdesc); 72217044Snwhitehornstatic int glc_intr_filter(void *xsc); 73217044Snwhitehornstatic void glc_intr(void *xsc); 74217044Snwhitehornstatic void glc_tick(void *xsc); 75217044Snwhitehornstatic void glc_media_status(struct ifnet *ifp, struct ifmediareq *ifmr); 76217044Snwhitehornstatic int glc_media_change(struct ifnet *ifp); 77217044Snwhitehorn 78217044Snwhitehornstatic MALLOC_DEFINE(M_GLC, "gelic", "PS3 GELIC ethernet"); 79217044Snwhitehorn 80217044Snwhitehornstatic device_method_t glc_methods[] = { 81217044Snwhitehorn /* Device interface */ 82217044Snwhitehorn DEVMETHOD(device_probe, glc_probe), 83217044Snwhitehorn DEVMETHOD(device_attach, glc_attach), 84217044Snwhitehorn 85217044Snwhitehorn { 0, 0 } 86217044Snwhitehorn}; 87217044Snwhitehorn 88217044Snwhitehornstatic driver_t glc_driver = { 89217044Snwhitehorn "glc", 90217044Snwhitehorn glc_methods, 91217044Snwhitehorn sizeof(struct glc_softc) 92217044Snwhitehorn}; 93217044Snwhitehorn 94217044Snwhitehornstatic devclass_t glc_devclass; 95217044Snwhitehorn 96217044SnwhitehornDRIVER_MODULE(glc, ps3bus, glc_driver, glc_devclass, 0, 0); 97217044Snwhitehorn 98217044Snwhitehornstatic int 99217044Snwhitehornglc_probe(device_t dev) 100217044Snwhitehorn{ 101217044Snwhitehorn 102217044Snwhitehorn if (ps3bus_get_bustype(dev) != PS3_BUSTYPE_SYSBUS || 103217044Snwhitehorn ps3bus_get_devtype(dev) != PS3_DEVTYPE_GELIC) 104217044Snwhitehorn return (ENXIO); 105217044Snwhitehorn 106217044Snwhitehorn device_set_desc(dev, "Playstation 3 GELIC Network Controller"); 107217044Snwhitehorn return (BUS_PROBE_SPECIFIC); 108217044Snwhitehorn} 109217044Snwhitehorn 110217044Snwhitehornstatic void 111217044Snwhitehornglc_getphys(void *xaddr, bus_dma_segment_t *segs, int nsegs, int error) 112217044Snwhitehorn{ 113217044Snwhitehorn if (error != 0) 114217044Snwhitehorn return; 115217044Snwhitehorn 116217044Snwhitehorn *(bus_addr_t *)xaddr = segs[0].ds_addr; 117217044Snwhitehorn} 118217044Snwhitehorn 119217044Snwhitehornstatic int 120217044Snwhitehornglc_attach(device_t dev) 121217044Snwhitehorn{ 122217044Snwhitehorn struct glc_softc *sc; 123217044Snwhitehorn struct glc_txsoft *txs; 124217044Snwhitehorn uint64_t mac64, val, junk; 125217044Snwhitehorn int i, err; 126217044Snwhitehorn 127217044Snwhitehorn sc = device_get_softc(dev); 128217044Snwhitehorn 129217044Snwhitehorn sc->sc_bus = ps3bus_get_bus(dev); 130217044Snwhitehorn sc->sc_dev = ps3bus_get_device(dev); 131217044Snwhitehorn sc->sc_self = dev; 132217044Snwhitehorn 133217044Snwhitehorn mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 134217044Snwhitehorn MTX_DEF); 135217044Snwhitehorn callout_init_mtx(&sc->sc_tick_ch, &sc->sc_mtx, 0); 136217044Snwhitehorn sc->next_txdma_slot = 0; 137217044Snwhitehorn sc->bsy_txdma_slots = 0; 138223324Snwhitehorn sc->sc_next_rxdma_slot = 0; 139217044Snwhitehorn sc->first_used_txdma_slot = -1; 140217044Snwhitehorn 141217044Snwhitehorn /* 142217044Snwhitehorn * Shut down existing tasks. 143217044Snwhitehorn */ 144217044Snwhitehorn 145217044Snwhitehorn lv1_net_stop_tx_dma(sc->sc_bus, sc->sc_dev, 0); 146217044Snwhitehorn lv1_net_stop_rx_dma(sc->sc_bus, sc->sc_dev, 0); 147217044Snwhitehorn 148217044Snwhitehorn sc->sc_ifp = if_alloc(IFT_ETHER); 149217044Snwhitehorn sc->sc_ifp->if_softc = sc; 150217044Snwhitehorn 151217044Snwhitehorn /* 152217044Snwhitehorn * Get MAC address and VLAN id 153217044Snwhitehorn */ 154217044Snwhitehorn 155217044Snwhitehorn lv1_net_control(sc->sc_bus, sc->sc_dev, GELIC_GET_MAC_ADDRESS, 156217044Snwhitehorn 0, 0, 0, &mac64, &junk); 157217044Snwhitehorn memcpy(sc->sc_enaddr, &((uint8_t *)&mac64)[2], sizeof(sc->sc_enaddr)); 158223792Snwhitehorn sc->sc_tx_vlan = sc->sc_rx_vlan = -1; 159217044Snwhitehorn err = lv1_net_control(sc->sc_bus, sc->sc_dev, GELIC_GET_VLAN_ID, 160217044Snwhitehorn GELIC_VLAN_TX_ETHERNET, 0, 0, &val, &junk); 161217044Snwhitehorn if (err == 0) 162217044Snwhitehorn sc->sc_tx_vlan = val; 163217044Snwhitehorn err = lv1_net_control(sc->sc_bus, sc->sc_dev, GELIC_GET_VLAN_ID, 164217044Snwhitehorn GELIC_VLAN_RX_ETHERNET, 0, 0, &val, &junk); 165217044Snwhitehorn if (err == 0) 166217044Snwhitehorn sc->sc_rx_vlan = val; 167217044Snwhitehorn 168217044Snwhitehorn /* 169217044Snwhitehorn * Set up interrupt handler 170217044Snwhitehorn */ 171217044Snwhitehorn sc->sc_irqid = 0; 172217044Snwhitehorn sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid, 173217044Snwhitehorn RF_ACTIVE); 174217044Snwhitehorn if (sc->sc_irq == NULL) { 175217044Snwhitehorn device_printf(dev, "Could not allocate IRQ!\n"); 176217044Snwhitehorn mtx_destroy(&sc->sc_mtx); 177217044Snwhitehorn return (ENXIO); 178217044Snwhitehorn } 179217044Snwhitehorn 180217044Snwhitehorn bus_setup_intr(dev, sc->sc_irq, 181223792Snwhitehorn INTR_TYPE_NET | INTR_MPSAFE | INTR_ENTROPY, 182217044Snwhitehorn glc_intr_filter, glc_intr, sc, &sc->sc_irqctx); 183217044Snwhitehorn sc->sc_hwirq_status = (uint64_t *)contigmalloc(8, M_GLC, M_ZERO, 0, 184217044Snwhitehorn BUS_SPACE_MAXADDR_32BIT, 8, PAGE_SIZE); 185217044Snwhitehorn lv1_net_set_interrupt_status_indicator(sc->sc_bus, sc->sc_dev, 186217044Snwhitehorn vtophys(sc->sc_hwirq_status), 0); 187217044Snwhitehorn lv1_net_set_interrupt_mask(sc->sc_bus, sc->sc_dev, 188217044Snwhitehorn GELIC_INT_RXDONE | GELIC_INT_RXFRAME | GELIC_INT_PHY | 189217044Snwhitehorn GELIC_INT_TX_CHAIN_END, 0); 190217044Snwhitehorn 191217044Snwhitehorn /* 192217044Snwhitehorn * Set up DMA. 193217044Snwhitehorn */ 194217044Snwhitehorn 195217044Snwhitehorn err = bus_dma_tag_create(bus_get_dma_tag(dev), 32, 0, 196217044Snwhitehorn BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 197217044Snwhitehorn 129*sizeof(struct glc_dmadesc), 1, 128*sizeof(struct glc_dmadesc), 198217044Snwhitehorn 0, NULL,NULL, &sc->sc_dmadesc_tag); 199217044Snwhitehorn 200217044Snwhitehorn err = bus_dmamem_alloc(sc->sc_dmadesc_tag, (void **)&sc->sc_txdmadesc, 201217044Snwhitehorn BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, 202217044Snwhitehorn &sc->sc_txdmadesc_map); 203217044Snwhitehorn err = bus_dmamap_load(sc->sc_dmadesc_tag, sc->sc_txdmadesc_map, 204217044Snwhitehorn sc->sc_txdmadesc, 128*sizeof(struct glc_dmadesc), glc_getphys, 205217044Snwhitehorn &sc->sc_txdmadesc_phys, 0); 206217044Snwhitehorn err = bus_dmamem_alloc(sc->sc_dmadesc_tag, (void **)&sc->sc_rxdmadesc, 207217044Snwhitehorn BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, 208217044Snwhitehorn &sc->sc_rxdmadesc_map); 209217044Snwhitehorn err = bus_dmamap_load(sc->sc_dmadesc_tag, sc->sc_rxdmadesc_map, 210217044Snwhitehorn sc->sc_rxdmadesc, 128*sizeof(struct glc_dmadesc), glc_getphys, 211217044Snwhitehorn &sc->sc_rxdmadesc_phys, 0); 212217044Snwhitehorn 213217044Snwhitehorn err = bus_dma_tag_create(bus_get_dma_tag(dev), 128, 0, 214217044Snwhitehorn BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 215217044Snwhitehorn BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0, NULL,NULL, 216217044Snwhitehorn &sc->sc_rxdma_tag); 217217044Snwhitehorn err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, 218217044Snwhitehorn BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 219217044Snwhitehorn BUS_SPACE_MAXSIZE_32BIT, 16, BUS_SPACE_MAXSIZE_32BIT, 0, NULL,NULL, 220217044Snwhitehorn &sc->sc_txdma_tag); 221217044Snwhitehorn 222217044Snwhitehorn /* init transmit descriptors */ 223217044Snwhitehorn STAILQ_INIT(&sc->sc_txfreeq); 224217044Snwhitehorn STAILQ_INIT(&sc->sc_txdirtyq); 225217044Snwhitehorn 226217044Snwhitehorn /* create TX DMA maps */ 227217044Snwhitehorn err = ENOMEM; 228217044Snwhitehorn for (i = 0; i < GLC_MAX_TX_PACKETS; i++) { 229217044Snwhitehorn txs = &sc->sc_txsoft[i]; 230217044Snwhitehorn txs->txs_mbuf = NULL; 231217044Snwhitehorn err = bus_dmamap_create(sc->sc_txdma_tag, 0, &txs->txs_dmamap); 232217044Snwhitehorn if (err) { 233217044Snwhitehorn device_printf(dev, 234217044Snwhitehorn "unable to create TX DMA map %d, error = %d\n", 235217044Snwhitehorn i, err); 236217044Snwhitehorn } 237217044Snwhitehorn STAILQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q); 238217044Snwhitehorn } 239217044Snwhitehorn 240217044Snwhitehorn /* Create the receive buffer DMA maps. */ 241217044Snwhitehorn for (i = 0; i < GLC_MAX_RX_PACKETS; i++) { 242217044Snwhitehorn err = bus_dmamap_create(sc->sc_rxdma_tag, 0, 243217044Snwhitehorn &sc->sc_rxsoft[i].rxs_dmamap); 244217044Snwhitehorn if (err) { 245217044Snwhitehorn device_printf(dev, 246217044Snwhitehorn "unable to create RX DMA map %d, error = %d\n", 247217044Snwhitehorn i, err); 248217044Snwhitehorn } 249217044Snwhitehorn sc->sc_rxsoft[i].rxs_mbuf = NULL; 250217044Snwhitehorn } 251217044Snwhitehorn 252217044Snwhitehorn /* 253217044Snwhitehorn * Attach to network stack 254217044Snwhitehorn */ 255217044Snwhitehorn 256217044Snwhitehorn if_initname(sc->sc_ifp, device_get_name(dev), device_get_unit(dev)); 257217044Snwhitehorn sc->sc_ifp->if_mtu = ETHERMTU; 258217044Snwhitehorn sc->sc_ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 259217044Snwhitehorn sc->sc_ifp->if_hwassist = CSUM_TCP | CSUM_UDP; 260217044Snwhitehorn sc->sc_ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_RXCSUM; 261217044Snwhitehorn sc->sc_ifp->if_capenable = IFCAP_HWCSUM | IFCAP_RXCSUM; 262217044Snwhitehorn sc->sc_ifp->if_start = glc_start; 263217044Snwhitehorn sc->sc_ifp->if_ioctl = glc_ioctl; 264217044Snwhitehorn sc->sc_ifp->if_init = glc_init; 265217044Snwhitehorn 266217044Snwhitehorn ifmedia_init(&sc->sc_media, IFM_IMASK, glc_media_change, 267217044Snwhitehorn glc_media_status); 268217044Snwhitehorn ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_T, 0, NULL); 269217044Snwhitehorn ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL); 270217044Snwhitehorn ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_TX, 0, NULL); 271217044Snwhitehorn ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL); 272217044Snwhitehorn ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); 273217044Snwhitehorn ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL); 274217044Snwhitehorn ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO); 275217044Snwhitehorn 276217044Snwhitehorn IFQ_SET_MAXLEN(&sc->sc_ifp->if_snd, GLC_MAX_TX_PACKETS); 277217044Snwhitehorn sc->sc_ifp->if_snd.ifq_drv_maxlen = GLC_MAX_TX_PACKETS; 278217044Snwhitehorn IFQ_SET_READY(&sc->sc_ifp->if_snd); 279217044Snwhitehorn 280217044Snwhitehorn ether_ifattach(sc->sc_ifp, sc->sc_enaddr); 281217044Snwhitehorn sc->sc_ifp->if_hwassist = 0; 282217044Snwhitehorn 283217044Snwhitehorn return (0); 284217044Snwhitehorn 285217044Snwhitehorn mtx_destroy(&sc->sc_mtx); 286217044Snwhitehorn if_free(sc->sc_ifp); 287217044Snwhitehorn return (ENXIO); 288217044Snwhitehorn} 289217044Snwhitehorn 290217044Snwhitehornstatic void 291217044Snwhitehornglc_init_locked(struct glc_softc *sc) 292217044Snwhitehorn{ 293217044Snwhitehorn int i, error; 294217044Snwhitehorn struct glc_rxsoft *rxs; 295217044Snwhitehorn struct glc_txsoft *txs; 296217044Snwhitehorn 297217044Snwhitehorn mtx_assert(&sc->sc_mtx, MA_OWNED); 298217044Snwhitehorn 299217044Snwhitehorn lv1_net_stop_tx_dma(sc->sc_bus, sc->sc_dev, 0); 300217044Snwhitehorn lv1_net_stop_rx_dma(sc->sc_bus, sc->sc_dev, 0); 301217044Snwhitehorn 302217044Snwhitehorn glc_set_multicast(sc); 303217044Snwhitehorn 304217044Snwhitehorn for (i = 0; i < GLC_MAX_RX_PACKETS; i++) { 305217044Snwhitehorn rxs = &sc->sc_rxsoft[i]; 306217044Snwhitehorn rxs->rxs_desc_slot = i; 307217044Snwhitehorn 308217044Snwhitehorn if (rxs->rxs_mbuf == NULL) { 309217044Snwhitehorn glc_add_rxbuf(sc, i); 310217044Snwhitehorn 311217044Snwhitehorn if (rxs->rxs_mbuf == NULL) { 312217044Snwhitehorn rxs->rxs_desc_slot = -1; 313217044Snwhitehorn break; 314217044Snwhitehorn } 315217044Snwhitehorn } 316217044Snwhitehorn 317217044Snwhitehorn glc_add_rxbuf_dma(sc, i); 318217044Snwhitehorn bus_dmamap_sync(sc->sc_dmadesc_tag, sc->sc_rxdmadesc_map, 319217044Snwhitehorn BUS_DMASYNC_PREREAD); 320217044Snwhitehorn } 321217044Snwhitehorn 322217044Snwhitehorn /* Clear TX dirty queue */ 323217044Snwhitehorn while ((txs = STAILQ_FIRST(&sc->sc_txdirtyq)) != NULL) { 324217044Snwhitehorn STAILQ_REMOVE_HEAD(&sc->sc_txdirtyq, txs_q); 325217044Snwhitehorn bus_dmamap_unload(sc->sc_txdma_tag, txs->txs_dmamap); 326217044Snwhitehorn 327217044Snwhitehorn if (txs->txs_mbuf != NULL) { 328217044Snwhitehorn m_freem(txs->txs_mbuf); 329217044Snwhitehorn txs->txs_mbuf = NULL; 330217044Snwhitehorn } 331217044Snwhitehorn 332217044Snwhitehorn STAILQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q); 333217044Snwhitehorn } 334217044Snwhitehorn sc->first_used_txdma_slot = -1; 335217044Snwhitehorn sc->bsy_txdma_slots = 0; 336217044Snwhitehorn 337217044Snwhitehorn error = lv1_net_start_rx_dma(sc->sc_bus, sc->sc_dev, 338217044Snwhitehorn sc->sc_rxsoft[0].rxs_desc, 0); 339217044Snwhitehorn if (error != 0) 340217044Snwhitehorn device_printf(sc->sc_self, 341217044Snwhitehorn "lv1_net_start_rx_dma error: %d\n", error); 342217044Snwhitehorn 343217044Snwhitehorn sc->sc_ifp->if_drv_flags |= IFF_DRV_RUNNING; 344217044Snwhitehorn sc->sc_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 345217044Snwhitehorn sc->sc_ifpflags = sc->sc_ifp->if_flags; 346217044Snwhitehorn 347217044Snwhitehorn sc->sc_wdog_timer = 0; 348217044Snwhitehorn callout_reset(&sc->sc_tick_ch, hz, glc_tick, sc); 349217044Snwhitehorn} 350217044Snwhitehorn 351217044Snwhitehornstatic void 352217044Snwhitehornglc_stop(void *xsc) 353217044Snwhitehorn{ 354217044Snwhitehorn struct glc_softc *sc = xsc; 355217044Snwhitehorn 356217044Snwhitehorn mtx_assert(&sc->sc_mtx, MA_OWNED); 357217044Snwhitehorn 358217044Snwhitehorn lv1_net_stop_tx_dma(sc->sc_bus, sc->sc_dev, 0); 359217044Snwhitehorn lv1_net_stop_rx_dma(sc->sc_bus, sc->sc_dev, 0); 360217044Snwhitehorn} 361217044Snwhitehorn 362217044Snwhitehornstatic void 363217044Snwhitehornglc_init(void *xsc) 364217044Snwhitehorn{ 365217044Snwhitehorn struct glc_softc *sc = xsc; 366217044Snwhitehorn 367217044Snwhitehorn mtx_lock(&sc->sc_mtx); 368217044Snwhitehorn glc_init_locked(sc); 369217044Snwhitehorn mtx_unlock(&sc->sc_mtx); 370217044Snwhitehorn} 371217044Snwhitehorn 372217044Snwhitehornstatic void 373217044Snwhitehornglc_tick(void *xsc) 374217044Snwhitehorn{ 375217044Snwhitehorn struct glc_softc *sc = xsc; 376217044Snwhitehorn 377217044Snwhitehorn mtx_assert(&sc->sc_mtx, MA_OWNED); 378217044Snwhitehorn 379223324Snwhitehorn /* 380223324Snwhitehorn * XXX: Sometimes the RX queue gets stuck. Poke it periodically until 381223324Snwhitehorn * we figure out why. This will fail harmlessly if the RX queue is 382223324Snwhitehorn * already running. 383223324Snwhitehorn */ 384223324Snwhitehorn lv1_net_start_rx_dma(sc->sc_bus, sc->sc_dev, 385223324Snwhitehorn sc->sc_rxsoft[sc->sc_next_rxdma_slot].rxs_desc, 0); 386223324Snwhitehorn 387217044Snwhitehorn if (sc->sc_wdog_timer == 0 || --sc->sc_wdog_timer != 0) { 388217044Snwhitehorn callout_reset(&sc->sc_tick_ch, hz, glc_tick, sc); 389217044Snwhitehorn return; 390217044Snwhitehorn } 391217044Snwhitehorn 392217044Snwhitehorn /* Problems */ 393217044Snwhitehorn device_printf(sc->sc_self, "device timeout\n"); 394217044Snwhitehorn 395217044Snwhitehorn glc_init_locked(sc); 396217044Snwhitehorn} 397217044Snwhitehorn 398217044Snwhitehornstatic void 399217044Snwhitehornglc_start_locked(struct ifnet *ifp) 400217044Snwhitehorn{ 401217044Snwhitehorn struct glc_softc *sc = ifp->if_softc; 402217044Snwhitehorn bus_addr_t first, pktdesc; 403217044Snwhitehorn int kickstart = 0; 404217044Snwhitehorn int error; 405217044Snwhitehorn struct mbuf *mb_head; 406217044Snwhitehorn 407217044Snwhitehorn mtx_assert(&sc->sc_mtx, MA_OWNED); 408217044Snwhitehorn first = 0; 409217044Snwhitehorn 410217044Snwhitehorn if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 411217044Snwhitehorn IFF_DRV_RUNNING) 412217044Snwhitehorn return; 413217044Snwhitehorn 414217044Snwhitehorn if (STAILQ_EMPTY(&sc->sc_txdirtyq)) 415217044Snwhitehorn kickstart = 1; 416217044Snwhitehorn 417217044Snwhitehorn while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 418217044Snwhitehorn IFQ_DRV_DEQUEUE(&ifp->if_snd, mb_head); 419217044Snwhitehorn 420217044Snwhitehorn if (mb_head == NULL) 421217044Snwhitehorn break; 422217044Snwhitehorn 423217044Snwhitehorn /* Check if the ring buffer is full */ 424217044Snwhitehorn if (sc->bsy_txdma_slots > 125) { 425217044Snwhitehorn /* Put the packet back and stop */ 426217044Snwhitehorn ifp->if_drv_flags |= IFF_DRV_OACTIVE; 427217044Snwhitehorn IFQ_DRV_PREPEND(&ifp->if_snd, mb_head); 428217044Snwhitehorn break; 429217044Snwhitehorn } 430217044Snwhitehorn 431217044Snwhitehorn BPF_MTAP(ifp, mb_head); 432217044Snwhitehorn 433217044Snwhitehorn if (sc->sc_tx_vlan >= 0) 434217044Snwhitehorn mb_head = ether_vlanencap(mb_head, sc->sc_tx_vlan); 435217044Snwhitehorn 436217044Snwhitehorn if (glc_encap(sc, &mb_head, &pktdesc)) { 437217044Snwhitehorn ifp->if_drv_flags |= IFF_DRV_OACTIVE; 438217044Snwhitehorn break; 439217044Snwhitehorn } 440217044Snwhitehorn 441217044Snwhitehorn if (first == 0) 442217044Snwhitehorn first = pktdesc; 443217044Snwhitehorn } 444217044Snwhitehorn 445217044Snwhitehorn if (kickstart && first != 0) { 446217044Snwhitehorn error = lv1_net_start_tx_dma(sc->sc_bus, sc->sc_dev, first, 0); 447217044Snwhitehorn if (error != 0) 448217044Snwhitehorn device_printf(sc->sc_self, 449217044Snwhitehorn "lv1_net_start_tx_dma error: %d\n", error); 450217044Snwhitehorn sc->sc_wdog_timer = 5; 451217044Snwhitehorn } 452217044Snwhitehorn} 453217044Snwhitehorn 454217044Snwhitehornstatic void 455217044Snwhitehornglc_start(struct ifnet *ifp) 456217044Snwhitehorn{ 457217044Snwhitehorn struct glc_softc *sc = ifp->if_softc; 458217044Snwhitehorn 459217044Snwhitehorn mtx_lock(&sc->sc_mtx); 460217044Snwhitehorn glc_start_locked(ifp); 461217044Snwhitehorn mtx_unlock(&sc->sc_mtx); 462217044Snwhitehorn} 463217044Snwhitehorn 464217044Snwhitehornstatic int 465217044Snwhitehornglc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 466217044Snwhitehorn{ 467217044Snwhitehorn struct glc_softc *sc = ifp->if_softc; 468217044Snwhitehorn struct ifreq *ifr = (struct ifreq *)data; 469217044Snwhitehorn int err = 0; 470217044Snwhitehorn 471217044Snwhitehorn switch (cmd) { 472217044Snwhitehorn case SIOCSIFFLAGS: 473217044Snwhitehorn mtx_lock(&sc->sc_mtx); 474217044Snwhitehorn if ((ifp->if_flags & IFF_UP) != 0) { 475217044Snwhitehorn if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 476217044Snwhitehorn ((ifp->if_flags ^ sc->sc_ifpflags) & 477217044Snwhitehorn (IFF_ALLMULTI | IFF_PROMISC)) != 0) 478217044Snwhitehorn glc_set_multicast(sc); 479217044Snwhitehorn else 480217044Snwhitehorn glc_init_locked(sc); 481217044Snwhitehorn } 482217044Snwhitehorn else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 483217044Snwhitehorn glc_stop(sc); 484217044Snwhitehorn sc->sc_ifpflags = ifp->if_flags; 485217044Snwhitehorn mtx_unlock(&sc->sc_mtx); 486217044Snwhitehorn break; 487217044Snwhitehorn case SIOCADDMULTI: 488217044Snwhitehorn case SIOCDELMULTI: 489217044Snwhitehorn mtx_lock(&sc->sc_mtx); 490217044Snwhitehorn glc_set_multicast(sc); 491217044Snwhitehorn mtx_unlock(&sc->sc_mtx); 492217044Snwhitehorn break; 493217044Snwhitehorn case SIOCGIFMEDIA: 494217044Snwhitehorn case SIOCSIFMEDIA: 495217044Snwhitehorn err = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 496217044Snwhitehorn break; 497217044Snwhitehorn default: 498217044Snwhitehorn err = ether_ioctl(ifp, cmd, data); 499217044Snwhitehorn break; 500217044Snwhitehorn } 501217044Snwhitehorn 502217044Snwhitehorn return (err); 503217044Snwhitehorn} 504217044Snwhitehorn 505217044Snwhitehornstatic void 506217044Snwhitehornglc_set_multicast(struct glc_softc *sc) 507217044Snwhitehorn{ 508217044Snwhitehorn struct ifnet *ifp = sc->sc_ifp; 509217044Snwhitehorn struct ifmultiaddr *inm; 510217044Snwhitehorn uint64_t addr; 511217044Snwhitehorn int naddrs; 512217044Snwhitehorn 513217044Snwhitehorn /* Clear multicast filter */ 514217044Snwhitehorn lv1_net_remove_multicast_address(sc->sc_bus, sc->sc_dev, 0, 1); 515217044Snwhitehorn 516217044Snwhitehorn /* Add broadcast */ 517217044Snwhitehorn lv1_net_add_multicast_address(sc->sc_bus, sc->sc_dev, 518217044Snwhitehorn 0xffffffffffffL, 0); 519217044Snwhitehorn 520217044Snwhitehorn if ((ifp->if_flags & IFF_ALLMULTI) != 0) { 521217044Snwhitehorn lv1_net_add_multicast_address(sc->sc_bus, sc->sc_dev, 0, 1); 522217044Snwhitehorn } else { 523217044Snwhitehorn if_maddr_rlock(ifp); 524217044Snwhitehorn naddrs = 1; /* Include broadcast */ 525217044Snwhitehorn TAILQ_FOREACH(inm, &ifp->if_multiaddrs, ifma_link) { 526217044Snwhitehorn if (inm->ifma_addr->sa_family != AF_LINK) 527217044Snwhitehorn continue; 528217044Snwhitehorn addr = 0; 529217044Snwhitehorn memcpy(&((uint8_t *)(&addr))[2], 530217044Snwhitehorn LLADDR((struct sockaddr_dl *)inm->ifma_addr), 531217044Snwhitehorn ETHER_ADDR_LEN); 532217044Snwhitehorn 533217044Snwhitehorn lv1_net_add_multicast_address(sc->sc_bus, sc->sc_dev, 534217044Snwhitehorn addr, 0); 535217044Snwhitehorn 536217044Snwhitehorn /* 537217044Snwhitehorn * Filter can only hold 32 addresses, so fall back to 538217044Snwhitehorn * the IFF_ALLMULTI case if we have too many. 539217044Snwhitehorn */ 540217044Snwhitehorn if (++naddrs >= 32) { 541217044Snwhitehorn lv1_net_add_multicast_address(sc->sc_bus, 542217044Snwhitehorn sc->sc_dev, 0, 1); 543217044Snwhitehorn break; 544217044Snwhitehorn } 545217044Snwhitehorn } 546217044Snwhitehorn if_maddr_runlock(ifp); 547217044Snwhitehorn } 548217044Snwhitehorn} 549217044Snwhitehorn 550217044Snwhitehornstatic int 551217044Snwhitehornglc_add_rxbuf(struct glc_softc *sc, int idx) 552217044Snwhitehorn{ 553217044Snwhitehorn struct glc_rxsoft *rxs = &sc->sc_rxsoft[idx]; 554217044Snwhitehorn struct mbuf *m; 555217044Snwhitehorn bus_dma_segment_t segs[1]; 556217044Snwhitehorn int error, nsegs; 557217044Snwhitehorn 558243882Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 559217044Snwhitehorn if (m == NULL) 560217044Snwhitehorn return (ENOBUFS); 561217044Snwhitehorn m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; 562217044Snwhitehorn 563217044Snwhitehorn if (rxs->rxs_mbuf != NULL) { 564217044Snwhitehorn bus_dmamap_sync(sc->sc_rxdma_tag, rxs->rxs_dmamap, 565217044Snwhitehorn BUS_DMASYNC_POSTREAD); 566217044Snwhitehorn bus_dmamap_unload(sc->sc_rxdma_tag, rxs->rxs_dmamap); 567217044Snwhitehorn } 568217044Snwhitehorn 569217044Snwhitehorn error = bus_dmamap_load_mbuf_sg(sc->sc_rxdma_tag, rxs->rxs_dmamap, m, 570217044Snwhitehorn segs, &nsegs, BUS_DMA_NOWAIT); 571217044Snwhitehorn if (error != 0) { 572217044Snwhitehorn device_printf(sc->sc_self, 573217044Snwhitehorn "cannot load RS DMA map %d, error = %d\n", idx, error); 574217044Snwhitehorn m_freem(m); 575217044Snwhitehorn return (error); 576217044Snwhitehorn } 577217044Snwhitehorn /* If nsegs is wrong then the stack is corrupt. */ 578217044Snwhitehorn KASSERT(nsegs == 1, 579217044Snwhitehorn ("%s: too many DMA segments (%d)", __func__, nsegs)); 580217044Snwhitehorn rxs->rxs_mbuf = m; 581217044Snwhitehorn rxs->segment = segs[0]; 582217044Snwhitehorn 583217044Snwhitehorn bus_dmamap_sync(sc->sc_rxdma_tag, rxs->rxs_dmamap, BUS_DMASYNC_PREREAD); 584217044Snwhitehorn 585217044Snwhitehorn return (0); 586217044Snwhitehorn} 587217044Snwhitehorn 588217044Snwhitehornstatic int 589217044Snwhitehornglc_add_rxbuf_dma(struct glc_softc *sc, int idx) 590217044Snwhitehorn{ 591217044Snwhitehorn struct glc_rxsoft *rxs = &sc->sc_rxsoft[idx]; 592217044Snwhitehorn 593217044Snwhitehorn bzero(&sc->sc_rxdmadesc[idx], sizeof(sc->sc_rxdmadesc[idx])); 594217044Snwhitehorn sc->sc_rxdmadesc[idx].paddr = rxs->segment.ds_addr; 595217044Snwhitehorn sc->sc_rxdmadesc[idx].len = rxs->segment.ds_len; 596217044Snwhitehorn sc->sc_rxdmadesc[idx].next = sc->sc_rxdmadesc_phys + 597217044Snwhitehorn ((idx + 1) % GLC_MAX_RX_PACKETS)*sizeof(sc->sc_rxdmadesc[idx]); 598217044Snwhitehorn sc->sc_rxdmadesc[idx].cmd_stat = GELIC_DESCR_OWNED; 599217044Snwhitehorn 600217044Snwhitehorn rxs->rxs_desc_slot = idx; 601217044Snwhitehorn rxs->rxs_desc = sc->sc_rxdmadesc_phys + idx*sizeof(struct glc_dmadesc); 602217044Snwhitehorn 603217044Snwhitehorn return (0); 604217044Snwhitehorn} 605217044Snwhitehorn 606217044Snwhitehornstatic int 607217044Snwhitehornglc_encap(struct glc_softc *sc, struct mbuf **m_head, bus_addr_t *pktdesc) 608217044Snwhitehorn{ 609217044Snwhitehorn bus_dma_segment_t segs[16]; 610217044Snwhitehorn struct glc_txsoft *txs; 611217044Snwhitehorn struct mbuf *m; 612217044Snwhitehorn bus_addr_t firstslotphys; 613217044Snwhitehorn int i, idx, nsegs, nsegs_max; 614217044Snwhitehorn int err = 0; 615217044Snwhitehorn 616217044Snwhitehorn /* Max number of segments is the number of free DMA slots */ 617217044Snwhitehorn nsegs_max = 128 - sc->bsy_txdma_slots; 618217044Snwhitehorn 619217044Snwhitehorn if (nsegs_max > 16 || sc->first_used_txdma_slot < 0) 620217044Snwhitehorn nsegs_max = 16; 621217044Snwhitehorn 622217044Snwhitehorn /* Get a work queue entry. */ 623217044Snwhitehorn if ((txs = STAILQ_FIRST(&sc->sc_txfreeq)) == NULL) { 624217044Snwhitehorn /* Ran out of descriptors. */ 625217044Snwhitehorn return (ENOBUFS); 626217044Snwhitehorn } 627217044Snwhitehorn 628217044Snwhitehorn nsegs = 0; 629217044Snwhitehorn for (m = *m_head; m != NULL; m = m->m_next) 630217044Snwhitehorn nsegs++; 631217044Snwhitehorn 632217044Snwhitehorn if (nsegs > nsegs_max) { 633243882Sglebius m = m_collapse(*m_head, M_NOWAIT, nsegs_max); 634217044Snwhitehorn if (m == NULL) { 635217044Snwhitehorn m_freem(*m_head); 636217044Snwhitehorn *m_head = NULL; 637217044Snwhitehorn return (ENOBUFS); 638217044Snwhitehorn } 639217044Snwhitehorn *m_head = m; 640217044Snwhitehorn } 641217044Snwhitehorn 642217044Snwhitehorn err = bus_dmamap_load_mbuf_sg(sc->sc_txdma_tag, txs->txs_dmamap, 643217044Snwhitehorn *m_head, segs, &nsegs, BUS_DMA_NOWAIT); 644217044Snwhitehorn if (err != 0) { 645217044Snwhitehorn m_freem(*m_head); 646217044Snwhitehorn *m_head = NULL; 647217044Snwhitehorn return (err); 648217044Snwhitehorn } 649217044Snwhitehorn 650217044Snwhitehorn KASSERT(nsegs <= 128 - sc->bsy_txdma_slots, 651217044Snwhitehorn ("GLC: Mapped too many (%d) DMA segments with %d available", 652217044Snwhitehorn nsegs, 128 - sc->bsy_txdma_slots)); 653217044Snwhitehorn 654217044Snwhitehorn if (nsegs == 0) { 655217044Snwhitehorn m_freem(*m_head); 656217044Snwhitehorn *m_head = NULL; 657217044Snwhitehorn return (EIO); 658217044Snwhitehorn } 659217044Snwhitehorn 660217044Snwhitehorn txs->txs_ndescs = nsegs; 661217044Snwhitehorn txs->txs_firstdesc = sc->next_txdma_slot; 662217044Snwhitehorn 663217044Snwhitehorn idx = txs->txs_firstdesc; 664217044Snwhitehorn firstslotphys = sc->sc_txdmadesc_phys + 665217044Snwhitehorn txs->txs_firstdesc*sizeof(struct glc_dmadesc); 666217044Snwhitehorn 667217044Snwhitehorn for (i = 0; i < nsegs; i++) { 668217044Snwhitehorn bzero(&sc->sc_txdmadesc[idx], sizeof(sc->sc_txdmadesc[idx])); 669217044Snwhitehorn sc->sc_txdmadesc[idx].paddr = segs[i].ds_addr; 670217044Snwhitehorn sc->sc_txdmadesc[idx].len = segs[i].ds_len; 671217044Snwhitehorn sc->sc_txdmadesc[idx].next = sc->sc_txdmadesc_phys + 672217044Snwhitehorn ((idx + 1) % GLC_MAX_TX_PACKETS)*sizeof(struct glc_dmadesc); 673217044Snwhitehorn sc->sc_txdmadesc[idx].cmd_stat |= GELIC_CMDSTAT_NOIPSEC; 674217044Snwhitehorn 675217044Snwhitehorn if (i+1 == nsegs) { 676217044Snwhitehorn txs->txs_lastdesc = idx; 677217044Snwhitehorn sc->sc_txdmadesc[idx].next = 0; 678217044Snwhitehorn sc->sc_txdmadesc[idx].cmd_stat |= GELIC_CMDSTAT_LAST; 679217044Snwhitehorn } 680217044Snwhitehorn 681217044Snwhitehorn if ((*m_head)->m_pkthdr.csum_flags & CSUM_TCP) 682217044Snwhitehorn sc->sc_txdmadesc[idx].cmd_stat |= GELIC_CMDSTAT_CSUM_TCP; 683217044Snwhitehorn if ((*m_head)->m_pkthdr.csum_flags & CSUM_UDP) 684217044Snwhitehorn sc->sc_txdmadesc[idx].cmd_stat |= GELIC_CMDSTAT_CSUM_UDP; 685217044Snwhitehorn sc->sc_txdmadesc[idx].cmd_stat |= GELIC_DESCR_OWNED; 686217044Snwhitehorn 687217044Snwhitehorn idx = (idx + 1) % GLC_MAX_TX_PACKETS; 688217044Snwhitehorn } 689217044Snwhitehorn sc->next_txdma_slot = idx; 690217044Snwhitehorn sc->bsy_txdma_slots += nsegs; 691217044Snwhitehorn if (txs->txs_firstdesc != 0) 692217044Snwhitehorn idx = txs->txs_firstdesc - 1; 693217044Snwhitehorn else 694217044Snwhitehorn idx = GLC_MAX_TX_PACKETS - 1; 695217044Snwhitehorn 696217044Snwhitehorn if (sc->first_used_txdma_slot < 0) 697217044Snwhitehorn sc->first_used_txdma_slot = txs->txs_firstdesc; 698217044Snwhitehorn 699217044Snwhitehorn bus_dmamap_sync(sc->sc_txdma_tag, txs->txs_dmamap, 700217044Snwhitehorn BUS_DMASYNC_PREWRITE); 701217044Snwhitehorn sc->sc_txdmadesc[idx].next = firstslotphys; 702217044Snwhitehorn 703217044Snwhitehorn STAILQ_REMOVE_HEAD(&sc->sc_txfreeq, txs_q); 704217044Snwhitehorn STAILQ_INSERT_TAIL(&sc->sc_txdirtyq, txs, txs_q); 705217044Snwhitehorn txs->txs_mbuf = *m_head; 706217044Snwhitehorn *pktdesc = firstslotphys; 707217044Snwhitehorn 708217044Snwhitehorn return (0); 709217044Snwhitehorn} 710217044Snwhitehorn 711217044Snwhitehornstatic void 712217044Snwhitehornglc_rxintr(struct glc_softc *sc) 713217044Snwhitehorn{ 714217044Snwhitehorn int i, restart_rxdma, error; 715217044Snwhitehorn struct mbuf *m; 716217044Snwhitehorn struct ifnet *ifp = sc->sc_ifp; 717217044Snwhitehorn 718217044Snwhitehorn bus_dmamap_sync(sc->sc_dmadesc_tag, sc->sc_rxdmadesc_map, 719223324Snwhitehorn BUS_DMASYNC_POSTREAD); 720217044Snwhitehorn 721217044Snwhitehorn restart_rxdma = 0; 722217044Snwhitehorn while ((sc->sc_rxdmadesc[sc->sc_next_rxdma_slot].cmd_stat & 723217044Snwhitehorn GELIC_DESCR_OWNED) == 0) { 724217044Snwhitehorn i = sc->sc_next_rxdma_slot; 725223324Snwhitehorn sc->sc_next_rxdma_slot++; 726223324Snwhitehorn if (sc->sc_next_rxdma_slot >= GLC_MAX_RX_PACKETS) 727223324Snwhitehorn sc->sc_next_rxdma_slot = 0; 728223324Snwhitehorn 729223324Snwhitehorn if (sc->sc_rxdmadesc[i].cmd_stat & GELIC_CMDSTAT_CHAIN_END) 730223324Snwhitehorn restart_rxdma = 1; 731223324Snwhitehorn 732217044Snwhitehorn if (sc->sc_rxdmadesc[i].rxerror & GELIC_RXERRORS) { 733271860Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 734217044Snwhitehorn goto requeue; 735217044Snwhitehorn } 736217044Snwhitehorn 737217044Snwhitehorn m = sc->sc_rxsoft[i].rxs_mbuf; 738217044Snwhitehorn if (sc->sc_rxdmadesc[i].data_stat & GELIC_RX_IPCSUM) { 739217044Snwhitehorn m->m_pkthdr.csum_flags |= 740217044Snwhitehorn CSUM_IP_CHECKED | CSUM_IP_VALID; 741217044Snwhitehorn } 742217044Snwhitehorn if (sc->sc_rxdmadesc[i].data_stat & GELIC_RX_TCPUDPCSUM) { 743217044Snwhitehorn m->m_pkthdr.csum_flags |= 744217044Snwhitehorn CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 745217044Snwhitehorn m->m_pkthdr.csum_data = 0xffff; 746217044Snwhitehorn } 747217044Snwhitehorn 748217044Snwhitehorn if (glc_add_rxbuf(sc, i)) { 749271860Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 750217044Snwhitehorn goto requeue; 751217044Snwhitehorn } 752217044Snwhitehorn 753271860Sglebius if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 754217044Snwhitehorn m->m_pkthdr.rcvif = ifp; 755217044Snwhitehorn m->m_len = sc->sc_rxdmadesc[i].valid_size; 756217044Snwhitehorn m->m_pkthdr.len = m->m_len; 757217044Snwhitehorn 758223792Snwhitehorn /* 759223792Snwhitehorn * Remove VLAN tag. Even on early firmwares that do not allow 760223792Snwhitehorn * multiple VLANs, the VLAN tag is still in place here. 761223792Snwhitehorn */ 762223792Snwhitehorn m_adj(m, 2); 763217044Snwhitehorn 764217044Snwhitehorn mtx_unlock(&sc->sc_mtx); 765217044Snwhitehorn (*ifp->if_input)(ifp, m); 766217044Snwhitehorn mtx_lock(&sc->sc_mtx); 767217044Snwhitehorn 768217044Snwhitehorn requeue: 769217044Snwhitehorn glc_add_rxbuf_dma(sc, i); 770217044Snwhitehorn } 771223324Snwhitehorn 772223324Snwhitehorn bus_dmamap_sync(sc->sc_dmadesc_tag, sc->sc_rxdmadesc_map, 773223324Snwhitehorn BUS_DMASYNC_PREWRITE); 774223324Snwhitehorn 775223324Snwhitehorn if (restart_rxdma) { 776223324Snwhitehorn error = lv1_net_start_rx_dma(sc->sc_bus, sc->sc_dev, 777223324Snwhitehorn sc->sc_rxsoft[sc->sc_next_rxdma_slot].rxs_desc, 0); 778223324Snwhitehorn if (error != 0) 779223324Snwhitehorn device_printf(sc->sc_self, 780223324Snwhitehorn "lv1_net_start_rx_dma error: %d\n", error); 781223324Snwhitehorn } 782217044Snwhitehorn} 783217044Snwhitehorn 784217044Snwhitehornstatic void 785217044Snwhitehornglc_txintr(struct glc_softc *sc) 786217044Snwhitehorn{ 787217044Snwhitehorn struct ifnet *ifp = sc->sc_ifp; 788217044Snwhitehorn struct glc_txsoft *txs; 789217044Snwhitehorn int progress = 0, kickstart = 0, error; 790217044Snwhitehorn 791223324Snwhitehorn bus_dmamap_sync(sc->sc_dmadesc_tag, sc->sc_txdmadesc_map, 792223324Snwhitehorn BUS_DMASYNC_POSTREAD); 793223324Snwhitehorn 794217044Snwhitehorn while ((txs = STAILQ_FIRST(&sc->sc_txdirtyq)) != NULL) { 795217044Snwhitehorn if (sc->sc_txdmadesc[txs->txs_lastdesc].cmd_stat 796217044Snwhitehorn & GELIC_DESCR_OWNED) 797217044Snwhitehorn break; 798217044Snwhitehorn 799217044Snwhitehorn STAILQ_REMOVE_HEAD(&sc->sc_txdirtyq, txs_q); 800217044Snwhitehorn bus_dmamap_unload(sc->sc_txdma_tag, txs->txs_dmamap); 801217044Snwhitehorn sc->bsy_txdma_slots -= txs->txs_ndescs; 802217044Snwhitehorn 803217044Snwhitehorn if (txs->txs_mbuf != NULL) { 804217044Snwhitehorn m_freem(txs->txs_mbuf); 805217044Snwhitehorn txs->txs_mbuf = NULL; 806217044Snwhitehorn } 807217044Snwhitehorn 808217044Snwhitehorn if ((sc->sc_txdmadesc[txs->txs_lastdesc].cmd_stat & 0xf0000000) 809217044Snwhitehorn != 0) { 810217044Snwhitehorn lv1_net_stop_tx_dma(sc->sc_bus, sc->sc_dev, 0); 811217044Snwhitehorn kickstart = 1; 812271860Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 813217044Snwhitehorn } 814217044Snwhitehorn 815217044Snwhitehorn if (sc->sc_txdmadesc[txs->txs_lastdesc].cmd_stat & 816217044Snwhitehorn GELIC_CMDSTAT_CHAIN_END) 817217044Snwhitehorn kickstart = 1; 818217044Snwhitehorn 819217044Snwhitehorn STAILQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q); 820271860Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 821217044Snwhitehorn progress = 1; 822217044Snwhitehorn } 823217044Snwhitehorn 824217044Snwhitehorn if (txs != NULL) 825217044Snwhitehorn sc->first_used_txdma_slot = txs->txs_firstdesc; 826217044Snwhitehorn else 827217044Snwhitehorn sc->first_used_txdma_slot = -1; 828217044Snwhitehorn 829223324Snwhitehorn if (kickstart || txs != NULL) { 830223324Snwhitehorn /* Speculatively (or necessarily) start the TX queue again */ 831217044Snwhitehorn error = lv1_net_start_tx_dma(sc->sc_bus, sc->sc_dev, 832217044Snwhitehorn sc->sc_txdmadesc_phys + 833217044Snwhitehorn txs->txs_firstdesc*sizeof(struct glc_dmadesc), 0); 834217044Snwhitehorn if (error != 0) 835217044Snwhitehorn device_printf(sc->sc_self, 836217044Snwhitehorn "lv1_net_start_tx_dma error: %d\n", error); 837217044Snwhitehorn } 838217044Snwhitehorn 839217044Snwhitehorn if (progress) { 840217044Snwhitehorn /* 841217044Snwhitehorn * We freed some descriptors, so reset IFF_DRV_OACTIVE 842217044Snwhitehorn * and restart. 843217044Snwhitehorn */ 844217044Snwhitehorn ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 845217044Snwhitehorn sc->sc_wdog_timer = STAILQ_EMPTY(&sc->sc_txdirtyq) ? 0 : 5; 846217044Snwhitehorn 847217044Snwhitehorn if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && 848217044Snwhitehorn !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 849217044Snwhitehorn glc_start_locked(ifp); 850217044Snwhitehorn } 851217044Snwhitehorn} 852217044Snwhitehorn 853217044Snwhitehornstatic int 854217044Snwhitehornglc_intr_filter(void *xsc) 855217044Snwhitehorn{ 856217044Snwhitehorn struct glc_softc *sc = xsc; 857217044Snwhitehorn 858217044Snwhitehorn powerpc_sync(); 859217044Snwhitehorn atomic_set_64(&sc->sc_interrupt_status, *sc->sc_hwirq_status); 860217044Snwhitehorn return (FILTER_SCHEDULE_THREAD); 861217044Snwhitehorn} 862217044Snwhitehorn 863217044Snwhitehornstatic void 864217044Snwhitehornglc_intr(void *xsc) 865217044Snwhitehorn{ 866217044Snwhitehorn struct glc_softc *sc = xsc; 867217044Snwhitehorn uint64_t status, linkstat, junk; 868217044Snwhitehorn 869217044Snwhitehorn mtx_lock(&sc->sc_mtx); 870217044Snwhitehorn 871217044Snwhitehorn status = atomic_readandclear_64(&sc->sc_interrupt_status); 872217044Snwhitehorn 873217044Snwhitehorn if (status == 0) { 874217044Snwhitehorn mtx_unlock(&sc->sc_mtx); 875217044Snwhitehorn return; 876217044Snwhitehorn } 877217044Snwhitehorn 878217044Snwhitehorn if (status & (GELIC_INT_RXDONE | GELIC_INT_RXFRAME)) 879217044Snwhitehorn glc_rxintr(sc); 880217044Snwhitehorn 881217044Snwhitehorn if (status & (GELIC_INT_TXDONE | GELIC_INT_TX_CHAIN_END)) 882217044Snwhitehorn glc_txintr(sc); 883217044Snwhitehorn 884217044Snwhitehorn if (status & GELIC_INT_PHY) { 885217044Snwhitehorn lv1_net_control(sc->sc_bus, sc->sc_dev, GELIC_GET_LINK_STATUS, 886217044Snwhitehorn GELIC_VLAN_TX_ETHERNET, 0, 0, &linkstat, &junk); 887217044Snwhitehorn 888217044Snwhitehorn linkstat = (linkstat & GELIC_LINK_UP) ? 889217044Snwhitehorn LINK_STATE_UP : LINK_STATE_DOWN; 890217044Snwhitehorn if (linkstat != sc->sc_ifp->if_link_state) 891217044Snwhitehorn if_link_state_change(sc->sc_ifp, linkstat); 892217044Snwhitehorn } 893217044Snwhitehorn 894217044Snwhitehorn mtx_unlock(&sc->sc_mtx); 895217044Snwhitehorn} 896217044Snwhitehorn 897217044Snwhitehornstatic void 898217044Snwhitehornglc_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 899217044Snwhitehorn{ 900217044Snwhitehorn struct glc_softc *sc = ifp->if_softc; 901217044Snwhitehorn uint64_t status, junk; 902217044Snwhitehorn 903217044Snwhitehorn ifmr->ifm_status = IFM_AVALID; 904217044Snwhitehorn ifmr->ifm_active = IFM_ETHER; 905217044Snwhitehorn 906217044Snwhitehorn lv1_net_control(sc->sc_bus, sc->sc_dev, GELIC_GET_LINK_STATUS, 907217044Snwhitehorn GELIC_VLAN_TX_ETHERNET, 0, 0, &status, &junk); 908217044Snwhitehorn 909217044Snwhitehorn if (status & GELIC_LINK_UP) 910217044Snwhitehorn ifmr->ifm_status |= IFM_ACTIVE; 911217044Snwhitehorn 912217044Snwhitehorn if (status & GELIC_SPEED_10) 913217044Snwhitehorn ifmr->ifm_active |= IFM_10_T; 914217044Snwhitehorn else if (status & GELIC_SPEED_100) 915217044Snwhitehorn ifmr->ifm_active |= IFM_100_TX; 916217044Snwhitehorn else if (status & GELIC_SPEED_1000) 917217044Snwhitehorn ifmr->ifm_active |= IFM_1000_T; 918217044Snwhitehorn 919217044Snwhitehorn if (status & GELIC_FULL_DUPLEX) 920217044Snwhitehorn ifmr->ifm_active |= IFM_FDX; 921217044Snwhitehorn else 922217044Snwhitehorn ifmr->ifm_active |= IFM_HDX; 923217044Snwhitehorn} 924217044Snwhitehorn 925217044Snwhitehornstatic int 926217044Snwhitehornglc_media_change(struct ifnet *ifp) 927217044Snwhitehorn{ 928217044Snwhitehorn struct glc_softc *sc = ifp->if_softc; 929217044Snwhitehorn uint64_t mode, junk; 930217044Snwhitehorn int result; 931217044Snwhitehorn 932217044Snwhitehorn if (IFM_TYPE(sc->sc_media.ifm_media) != IFM_ETHER) 933217044Snwhitehorn return (EINVAL); 934217044Snwhitehorn 935217044Snwhitehorn switch (IFM_SUBTYPE(sc->sc_media.ifm_media)) { 936217044Snwhitehorn case IFM_AUTO: 937217044Snwhitehorn mode = GELIC_AUTO_NEG; 938217044Snwhitehorn break; 939217044Snwhitehorn case IFM_10_T: 940217044Snwhitehorn mode = GELIC_SPEED_10; 941217044Snwhitehorn break; 942217044Snwhitehorn case IFM_100_TX: 943217044Snwhitehorn mode = GELIC_SPEED_100; 944217044Snwhitehorn break; 945217044Snwhitehorn case IFM_1000_T: 946217044Snwhitehorn mode = GELIC_SPEED_1000 | GELIC_FULL_DUPLEX; 947217044Snwhitehorn break; 948217044Snwhitehorn default: 949217044Snwhitehorn return (EINVAL); 950217044Snwhitehorn } 951217044Snwhitehorn 952217044Snwhitehorn if (IFM_OPTIONS(sc->sc_media.ifm_media) & IFM_FDX) 953217044Snwhitehorn mode |= GELIC_FULL_DUPLEX; 954217044Snwhitehorn 955217044Snwhitehorn result = lv1_net_control(sc->sc_bus, sc->sc_dev, GELIC_SET_LINK_MODE, 956217044Snwhitehorn GELIC_VLAN_TX_ETHERNET, mode, 0, &junk, &junk); 957217044Snwhitehorn 958217044Snwhitehorn return (result ? EIO : 0); 959217044Snwhitehorn} 960217044Snwhitehorn 961