1d217d4d9SSepherosa Ziehau /* 2d217d4d9SSepherosa Ziehau * Copyright (c) 2007 The DragonFly Project. All rights reserved. 3d217d4d9SSepherosa Ziehau * 4d217d4d9SSepherosa Ziehau * This code is derived from software contributed to The DragonFly Project 5d217d4d9SSepherosa Ziehau * by Sepherosa Ziehau <sepherosa@gmail.com> 6d217d4d9SSepherosa Ziehau * 7d217d4d9SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 8d217d4d9SSepherosa Ziehau * modification, are permitted provided that the following conditions 9d217d4d9SSepherosa Ziehau * are met: 10d217d4d9SSepherosa Ziehau * 11d217d4d9SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 12d217d4d9SSepherosa Ziehau * notice, this list of conditions and the following disclaimer. 13d217d4d9SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 14d217d4d9SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in 15d217d4d9SSepherosa Ziehau * the documentation and/or other materials provided with the 16d217d4d9SSepherosa Ziehau * distribution. 17d217d4d9SSepherosa Ziehau * 3. Neither the name of The DragonFly Project nor the names of its 18d217d4d9SSepherosa Ziehau * contributors may be used to endorse or promote products derived 19d217d4d9SSepherosa Ziehau * from this software without specific, prior written permission. 20d217d4d9SSepherosa Ziehau * 21d217d4d9SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22d217d4d9SSepherosa Ziehau * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23d217d4d9SSepherosa Ziehau * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24d217d4d9SSepherosa Ziehau * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25d217d4d9SSepherosa Ziehau * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26d217d4d9SSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27d217d4d9SSepherosa Ziehau * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28d217d4d9SSepherosa Ziehau * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29d217d4d9SSepherosa Ziehau * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30d217d4d9SSepherosa Ziehau * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31d217d4d9SSepherosa Ziehau * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32d217d4d9SSepherosa Ziehau * SUCH DAMAGE. 33d217d4d9SSepherosa Ziehau */ 34d217d4d9SSepherosa Ziehau 35d217d4d9SSepherosa Ziehau #include <sys/param.h> 36b5b6e4f4SSepherosa Ziehau #include <sys/bitops.h> 37d217d4d9SSepherosa Ziehau #include <sys/endian.h> 38d217d4d9SSepherosa Ziehau #include <sys/kernel.h> 39d217d4d9SSepherosa Ziehau #include <sys/bus.h> 409db4b353SSepherosa Ziehau #include <sys/interrupt.h> 41d217d4d9SSepherosa Ziehau #include <sys/malloc.h> 42d217d4d9SSepherosa Ziehau #include <sys/proc.h> 43d217d4d9SSepherosa Ziehau #include <sys/rman.h> 44d217d4d9SSepherosa Ziehau #include <sys/serialize.h> 45d217d4d9SSepherosa Ziehau #include <sys/socket.h> 46d217d4d9SSepherosa Ziehau #include <sys/sockio.h> 47d217d4d9SSepherosa Ziehau #include <sys/sysctl.h> 48d217d4d9SSepherosa Ziehau 49d217d4d9SSepherosa Ziehau #include <net/ethernet.h> 50d217d4d9SSepherosa Ziehau #include <net/if.h> 51d217d4d9SSepherosa Ziehau #include <net/bpf.h> 52d217d4d9SSepherosa Ziehau #include <net/if_arp.h> 53d217d4d9SSepherosa Ziehau #include <net/if_dl.h> 54d217d4d9SSepherosa Ziehau #include <net/if_media.h> 55d217d4d9SSepherosa Ziehau #include <net/ifq_var.h> 56d217d4d9SSepherosa Ziehau #include <net/vlan/if_vlan_var.h> 57d217d4d9SSepherosa Ziehau 58d217d4d9SSepherosa Ziehau #include <dev/netif/mii_layer/miivar.h> 59d217d4d9SSepherosa Ziehau 60d217d4d9SSepherosa Ziehau #include <bus/pci/pcireg.h> 61d217d4d9SSepherosa Ziehau #include <bus/pci/pcivar.h> 62d217d4d9SSepherosa Ziehau #include <bus/pci/pcidevs.h> 63d217d4d9SSepherosa Ziehau 64b5b6e4f4SSepherosa Ziehau #include <dev/netif/et/if_etreg.h> 65b5b6e4f4SSepherosa Ziehau #include <dev/netif/et/if_etvar.h> 66d217d4d9SSepherosa Ziehau 67b5b6e4f4SSepherosa Ziehau #include "miibus_if.h" 68d217d4d9SSepherosa Ziehau 69d217d4d9SSepherosa Ziehau static int et_probe(device_t); 70d217d4d9SSepherosa Ziehau static int et_attach(device_t); 71d217d4d9SSepherosa Ziehau static int et_detach(device_t); 72d217d4d9SSepherosa Ziehau static int et_shutdown(device_t); 73d217d4d9SSepherosa Ziehau 74d217d4d9SSepherosa Ziehau static int et_miibus_readreg(device_t, int, int); 75d217d4d9SSepherosa Ziehau static int et_miibus_writereg(device_t, int, int, int); 76d217d4d9SSepherosa Ziehau static void et_miibus_statchg(device_t); 77d217d4d9SSepherosa Ziehau 78d217d4d9SSepherosa Ziehau static void et_init(void *); 79d217d4d9SSepherosa Ziehau static int et_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *); 80f0a26983SSepherosa Ziehau static void et_start(struct ifnet *, struct ifaltq_subque *); 81d217d4d9SSepherosa Ziehau static void et_watchdog(struct ifnet *); 82d217d4d9SSepherosa Ziehau static int et_ifmedia_upd(struct ifnet *); 83d217d4d9SSepherosa Ziehau static void et_ifmedia_sts(struct ifnet *, struct ifmediareq *); 84d217d4d9SSepherosa Ziehau 85d217d4d9SSepherosa Ziehau static int et_sysctl_rx_intr_npkts(SYSCTL_HANDLER_ARGS); 86d217d4d9SSepherosa Ziehau static int et_sysctl_rx_intr_delay(SYSCTL_HANDLER_ARGS); 87d217d4d9SSepherosa Ziehau 88d217d4d9SSepherosa Ziehau static void et_intr(void *); 89d217d4d9SSepherosa Ziehau static void et_enable_intrs(struct et_softc *, uint32_t); 90d217d4d9SSepherosa Ziehau static void et_disable_intrs(struct et_softc *); 91d217d4d9SSepherosa Ziehau static void et_rxeof(struct et_softc *); 92136e59ffSSepherosa Ziehau static void et_txeof(struct et_softc *, int); 93d217d4d9SSepherosa Ziehau 94d217d4d9SSepherosa Ziehau static int et_dma_alloc(device_t); 95d217d4d9SSepherosa Ziehau static void et_dma_free(device_t); 96d217d4d9SSepherosa Ziehau static void et_dma_mem_destroy(bus_dma_tag_t, void *, bus_dmamap_t); 97d217d4d9SSepherosa Ziehau static int et_dma_mbuf_create(device_t); 98d217d4d9SSepherosa Ziehau static void et_dma_mbuf_destroy(device_t, int, const int[]); 993effc1bfSSepherosa Ziehau static int et_jumbo_mem_alloc(device_t); 1003effc1bfSSepherosa Ziehau static void et_jumbo_mem_free(device_t); 101d217d4d9SSepherosa Ziehau static int et_init_tx_ring(struct et_softc *); 102d217d4d9SSepherosa Ziehau static int et_init_rx_ring(struct et_softc *); 103d217d4d9SSepherosa Ziehau static void et_free_tx_ring(struct et_softc *); 104d217d4d9SSepherosa Ziehau static void et_free_rx_ring(struct et_softc *); 105d217d4d9SSepherosa Ziehau static int et_encap(struct et_softc *, struct mbuf **); 1063effc1bfSSepherosa Ziehau static struct et_jslot * 1073effc1bfSSepherosa Ziehau et_jalloc(struct et_jumbo_data *); 1083effc1bfSSepherosa Ziehau static void et_jfree(void *); 1093effc1bfSSepherosa Ziehau static void et_jref(void *); 110d217d4d9SSepherosa Ziehau static int et_newbuf(struct et_rxbuf_data *, int, int, int); 111d217d4d9SSepherosa Ziehau static int et_newbuf_cluster(struct et_rxbuf_data *, int, int); 112d217d4d9SSepherosa Ziehau static int et_newbuf_hdr(struct et_rxbuf_data *, int, int); 1133effc1bfSSepherosa Ziehau static int et_newbuf_jumbo(struct et_rxbuf_data *, int, int); 114d217d4d9SSepherosa Ziehau 115d217d4d9SSepherosa Ziehau static void et_stop(struct et_softc *); 116d217d4d9SSepherosa Ziehau static int et_chip_init(struct et_softc *); 117d217d4d9SSepherosa Ziehau static void et_chip_attach(struct et_softc *); 118d217d4d9SSepherosa Ziehau static void et_init_mac(struct et_softc *); 119d217d4d9SSepherosa Ziehau static void et_init_rxmac(struct et_softc *); 120d217d4d9SSepherosa Ziehau static void et_init_txmac(struct et_softc *); 121d217d4d9SSepherosa Ziehau static int et_init_rxdma(struct et_softc *); 122d217d4d9SSepherosa Ziehau static int et_init_txdma(struct et_softc *); 123d217d4d9SSepherosa Ziehau static int et_start_rxdma(struct et_softc *); 124d217d4d9SSepherosa Ziehau static int et_start_txdma(struct et_softc *); 125d217d4d9SSepherosa Ziehau static int et_stop_rxdma(struct et_softc *); 126d217d4d9SSepherosa Ziehau static int et_stop_txdma(struct et_softc *); 12760d2de1fSSepherosa Ziehau static int et_enable_txrx(struct et_softc *, int); 128d217d4d9SSepherosa Ziehau static void et_reset(struct et_softc *); 129d217d4d9SSepherosa Ziehau static int et_bus_config(device_t); 130d217d4d9SSepherosa Ziehau static void et_get_eaddr(device_t, uint8_t[]); 131d217d4d9SSepherosa Ziehau static void et_setmulti(struct et_softc *); 132d217d4d9SSepherosa Ziehau static void et_tick(void *); 13360d2de1fSSepherosa Ziehau static void et_setmedia(struct et_softc *); 1343effc1bfSSepherosa Ziehau static void et_setup_rxdesc(struct et_rxbuf_data *, int, bus_addr_t); 135d217d4d9SSepherosa Ziehau 136d217d4d9SSepherosa Ziehau static const struct et_dev { 137d217d4d9SSepherosa Ziehau uint16_t vid; 138d217d4d9SSepherosa Ziehau uint16_t did; 139d217d4d9SSepherosa Ziehau const char *desc; 140d217d4d9SSepherosa Ziehau } et_devices[] = { 141d217d4d9SSepherosa Ziehau { PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_ET1310, 142d217d4d9SSepherosa Ziehau "Agere ET1310 Gigabit Ethernet" }, 143d217d4d9SSepherosa Ziehau { PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_ET1310_FAST, 144d217d4d9SSepherosa Ziehau "Agere ET1310 Fast Ethernet" }, 145d217d4d9SSepherosa Ziehau { 0, 0, NULL } 146d217d4d9SSepherosa Ziehau }; 147d217d4d9SSepherosa Ziehau 148d217d4d9SSepherosa Ziehau static device_method_t et_methods[] = { 149d217d4d9SSepherosa Ziehau DEVMETHOD(device_probe, et_probe), 150d217d4d9SSepherosa Ziehau DEVMETHOD(device_attach, et_attach), 151d217d4d9SSepherosa Ziehau DEVMETHOD(device_detach, et_detach), 152d217d4d9SSepherosa Ziehau DEVMETHOD(device_shutdown, et_shutdown), 153d217d4d9SSepherosa Ziehau #if 0 154d217d4d9SSepherosa Ziehau DEVMETHOD(device_suspend, et_suspend), 155d217d4d9SSepherosa Ziehau DEVMETHOD(device_resume, et_resume), 156d217d4d9SSepherosa Ziehau #endif 157d217d4d9SSepherosa Ziehau 158d217d4d9SSepherosa Ziehau DEVMETHOD(bus_print_child, bus_generic_print_child), 159d217d4d9SSepherosa Ziehau DEVMETHOD(bus_driver_added, bus_generic_driver_added), 160d217d4d9SSepherosa Ziehau 161d217d4d9SSepherosa Ziehau DEVMETHOD(miibus_readreg, et_miibus_readreg), 162d217d4d9SSepherosa Ziehau DEVMETHOD(miibus_writereg, et_miibus_writereg), 163d217d4d9SSepherosa Ziehau DEVMETHOD(miibus_statchg, et_miibus_statchg), 164d217d4d9SSepherosa Ziehau 165d3c9c58eSSascha Wildner DEVMETHOD_END 166d217d4d9SSepherosa Ziehau }; 167d217d4d9SSepherosa Ziehau 168d217d4d9SSepherosa Ziehau static driver_t et_driver = { 169d217d4d9SSepherosa Ziehau "et", 170d217d4d9SSepherosa Ziehau et_methods, 171d217d4d9SSepherosa Ziehau sizeof(struct et_softc) 172d217d4d9SSepherosa Ziehau }; 173d217d4d9SSepherosa Ziehau 174d217d4d9SSepherosa Ziehau static devclass_t et_devclass; 175d217d4d9SSepherosa Ziehau 176d217d4d9SSepherosa Ziehau DECLARE_DUMMY_MODULE(if_et); 177d217d4d9SSepherosa Ziehau MODULE_DEPEND(if_et, miibus, 1, 1, 1); 178aa2b9d05SSascha Wildner DRIVER_MODULE(if_et, pci, et_driver, et_devclass, NULL, NULL); 179aa2b9d05SSascha Wildner DRIVER_MODULE(miibus, et, miibus_driver, miibus_devclass, NULL, NULL); 180d217d4d9SSepherosa Ziehau 1811ebf7512SSepherosa Ziehau static int et_rx_intr_npkts = 129; 1821ebf7512SSepherosa Ziehau static int et_rx_intr_delay = 25; /* x4 usec */ 183136e59ffSSepherosa Ziehau static int et_tx_intr_nsegs = 256; 184d217d4d9SSepherosa Ziehau static uint32_t et_timer = 1000 * 1000 * 1000; /* nanosec */ 185d217d4d9SSepherosa Ziehau 186*7f28a608SSepherosa Ziehau static int et_msi_enable = 1; 187*7f28a608SSepherosa Ziehau 188d217d4d9SSepherosa Ziehau TUNABLE_INT("hw.et.timer", &et_timer); 189d217d4d9SSepherosa Ziehau TUNABLE_INT("hw.et.rx_intr_npkts", &et_rx_intr_npkts); 190f285c685SSascha Wildner TUNABLE_INT("hw.et.rx_intr_delay", &et_rx_intr_delay); 191af6a2c2aSSascha Wildner TUNABLE_INT("hw.et.tx_intr_nsegs", &et_tx_intr_nsegs); 192*7f28a608SSepherosa Ziehau TUNABLE_INT("hw.et.msi.enable", &et_msi_enable); 193d217d4d9SSepherosa Ziehau 194d217d4d9SSepherosa Ziehau struct et_bsize { 195d217d4d9SSepherosa Ziehau int bufsize; 1963effc1bfSSepherosa Ziehau int jumbo; 197d217d4d9SSepherosa Ziehau et_newbuf_t newbuf; 198d217d4d9SSepherosa Ziehau }; 199d217d4d9SSepherosa Ziehau 2003effc1bfSSepherosa Ziehau static const struct et_bsize et_bufsize_std[ET_RX_NRING] = { 2013effc1bfSSepherosa Ziehau { .bufsize = ET_RXDMA_CTRL_RING0_128, .jumbo = 0, 2023effc1bfSSepherosa Ziehau .newbuf = et_newbuf_hdr }, 2033effc1bfSSepherosa Ziehau { .bufsize = ET_RXDMA_CTRL_RING1_2048, .jumbo = 0, 2043effc1bfSSepherosa Ziehau .newbuf = et_newbuf_cluster }, 2053effc1bfSSepherosa Ziehau }; 2063effc1bfSSepherosa Ziehau 2073effc1bfSSepherosa Ziehau static const struct et_bsize et_bufsize_jumbo[ET_RX_NRING] = { 2083effc1bfSSepherosa Ziehau { .bufsize = ET_RXDMA_CTRL_RING0_128, .jumbo = 0, 2093effc1bfSSepherosa Ziehau .newbuf = et_newbuf_hdr }, 2103effc1bfSSepherosa Ziehau { .bufsize = ET_RXDMA_CTRL_RING1_16384, .jumbo = 1, 2113effc1bfSSepherosa Ziehau .newbuf = et_newbuf_jumbo }, 212d217d4d9SSepherosa Ziehau }; 213d217d4d9SSepherosa Ziehau 214d217d4d9SSepherosa Ziehau static int 215d217d4d9SSepherosa Ziehau et_probe(device_t dev) 216d217d4d9SSepherosa Ziehau { 217d217d4d9SSepherosa Ziehau const struct et_dev *d; 218d217d4d9SSepherosa Ziehau uint16_t did, vid; 219d217d4d9SSepherosa Ziehau 220d217d4d9SSepherosa Ziehau vid = pci_get_vendor(dev); 221d217d4d9SSepherosa Ziehau did = pci_get_device(dev); 222d217d4d9SSepherosa Ziehau 223d217d4d9SSepherosa Ziehau for (d = et_devices; d->desc != NULL; ++d) { 224d217d4d9SSepherosa Ziehau if (vid == d->vid && did == d->did) { 225d217d4d9SSepherosa Ziehau device_set_desc(dev, d->desc); 226d217d4d9SSepherosa Ziehau return 0; 227d217d4d9SSepherosa Ziehau } 228d217d4d9SSepherosa Ziehau } 229d217d4d9SSepherosa Ziehau return ENXIO; 230d217d4d9SSepherosa Ziehau } 231d217d4d9SSepherosa Ziehau 232d217d4d9SSepherosa Ziehau static int 233d217d4d9SSepherosa Ziehau et_attach(device_t dev) 234d217d4d9SSepherosa Ziehau { 235d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 236d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 237d217d4d9SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN]; 238d217d4d9SSepherosa Ziehau int error; 239*7f28a608SSepherosa Ziehau u_int irq_flags; 240d217d4d9SSepherosa Ziehau 241d217d4d9SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 242d217d4d9SSepherosa Ziehau callout_init(&sc->sc_tick); 243d217d4d9SSepherosa Ziehau 244d217d4d9SSepherosa Ziehau /* 245d217d4d9SSepherosa Ziehau * Initialize tunables 246d217d4d9SSepherosa Ziehau */ 247d217d4d9SSepherosa Ziehau sc->sc_rx_intr_npkts = et_rx_intr_npkts; 248d217d4d9SSepherosa Ziehau sc->sc_rx_intr_delay = et_rx_intr_delay; 249d217d4d9SSepherosa Ziehau sc->sc_tx_intr_nsegs = et_tx_intr_nsegs; 250d217d4d9SSepherosa Ziehau sc->sc_timer = et_timer; 251d217d4d9SSepherosa Ziehau 252d217d4d9SSepherosa Ziehau #ifndef BURN_BRIDGES 253d217d4d9SSepherosa Ziehau if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 254d217d4d9SSepherosa Ziehau uint32_t irq, mem; 255d217d4d9SSepherosa Ziehau 256d217d4d9SSepherosa Ziehau irq = pci_read_config(dev, PCIR_INTLINE, 4); 257d217d4d9SSepherosa Ziehau mem = pci_read_config(dev, ET_PCIR_BAR, 4); 258d217d4d9SSepherosa Ziehau 259d217d4d9SSepherosa Ziehau device_printf(dev, "chip is in D%d power mode " 260d217d4d9SSepherosa Ziehau "-- setting to D0\n", pci_get_powerstate(dev)); 261d217d4d9SSepherosa Ziehau 262d217d4d9SSepherosa Ziehau pci_set_powerstate(dev, PCI_POWERSTATE_D0); 263d217d4d9SSepherosa Ziehau 264d217d4d9SSepherosa Ziehau pci_write_config(dev, PCIR_INTLINE, irq, 4); 265d217d4d9SSepherosa Ziehau pci_write_config(dev, ET_PCIR_BAR, mem, 4); 266d217d4d9SSepherosa Ziehau } 267d217d4d9SSepherosa Ziehau #endif /* !BURN_BRIDGE */ 268d217d4d9SSepherosa Ziehau 269d217d4d9SSepherosa Ziehau /* Enable bus mastering */ 270d217d4d9SSepherosa Ziehau pci_enable_busmaster(dev); 271d217d4d9SSepherosa Ziehau 272d217d4d9SSepherosa Ziehau /* 273d217d4d9SSepherosa Ziehau * Allocate IO memory 274d217d4d9SSepherosa Ziehau */ 275d217d4d9SSepherosa Ziehau sc->sc_mem_rid = ET_PCIR_BAR; 276d217d4d9SSepherosa Ziehau sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 277d217d4d9SSepherosa Ziehau &sc->sc_mem_rid, RF_ACTIVE); 278d217d4d9SSepherosa Ziehau if (sc->sc_mem_res == NULL) { 279d217d4d9SSepherosa Ziehau device_printf(dev, "can't allocate IO memory\n"); 280d217d4d9SSepherosa Ziehau return ENXIO; 281d217d4d9SSepherosa Ziehau } 282d217d4d9SSepherosa Ziehau sc->sc_mem_bt = rman_get_bustag(sc->sc_mem_res); 283d217d4d9SSepherosa Ziehau sc->sc_mem_bh = rman_get_bushandle(sc->sc_mem_res); 284d217d4d9SSepherosa Ziehau 285d217d4d9SSepherosa Ziehau /* 286d217d4d9SSepherosa Ziehau * Allocate IRQ 287d217d4d9SSepherosa Ziehau */ 288*7f28a608SSepherosa Ziehau sc->sc_irq_type = pci_alloc_1intr(dev, et_msi_enable, 289*7f28a608SSepherosa Ziehau &sc->sc_irq_rid, &irq_flags); 290d217d4d9SSepherosa Ziehau sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 291*7f28a608SSepherosa Ziehau &sc->sc_irq_rid, irq_flags); 292d217d4d9SSepherosa Ziehau if (sc->sc_irq_res == NULL) { 293d217d4d9SSepherosa Ziehau device_printf(dev, "can't allocate irq\n"); 294d217d4d9SSepherosa Ziehau error = ENXIO; 295d217d4d9SSepherosa Ziehau goto fail; 296d217d4d9SSepherosa Ziehau } 297d217d4d9SSepherosa Ziehau 298d217d4d9SSepherosa Ziehau /* 299d217d4d9SSepherosa Ziehau * Create sysctl tree 300d217d4d9SSepherosa Ziehau */ 301d217d4d9SSepherosa Ziehau sysctl_ctx_init(&sc->sc_sysctl_ctx); 302d217d4d9SSepherosa Ziehau sc->sc_sysctl_tree = SYSCTL_ADD_NODE(&sc->sc_sysctl_ctx, 303d217d4d9SSepherosa Ziehau SYSCTL_STATIC_CHILDREN(_hw), 304d217d4d9SSepherosa Ziehau OID_AUTO, 305d217d4d9SSepherosa Ziehau device_get_nameunit(dev), 306d217d4d9SSepherosa Ziehau CTLFLAG_RD, 0, ""); 307d217d4d9SSepherosa Ziehau if (sc->sc_sysctl_tree == NULL) { 308d217d4d9SSepherosa Ziehau device_printf(dev, "can't add sysctl node\n"); 309d217d4d9SSepherosa Ziehau error = ENXIO; 310d217d4d9SSepherosa Ziehau goto fail; 311d217d4d9SSepherosa Ziehau } 312d217d4d9SSepherosa Ziehau 313d217d4d9SSepherosa Ziehau SYSCTL_ADD_PROC(&sc->sc_sysctl_ctx, 314d217d4d9SSepherosa Ziehau SYSCTL_CHILDREN(sc->sc_sysctl_tree), 315d217d4d9SSepherosa Ziehau OID_AUTO, "rx_intr_npkts", CTLTYPE_INT | CTLFLAG_RW, 316d217d4d9SSepherosa Ziehau sc, 0, et_sysctl_rx_intr_npkts, "I", 317d217d4d9SSepherosa Ziehau "RX IM, # packets per RX interrupt"); 318d217d4d9SSepherosa Ziehau SYSCTL_ADD_PROC(&sc->sc_sysctl_ctx, 319d217d4d9SSepherosa Ziehau SYSCTL_CHILDREN(sc->sc_sysctl_tree), 320d217d4d9SSepherosa Ziehau OID_AUTO, "rx_intr_delay", CTLTYPE_INT | CTLFLAG_RW, 321d217d4d9SSepherosa Ziehau sc, 0, et_sysctl_rx_intr_delay, "I", 322d217d4d9SSepherosa Ziehau "RX IM, RX interrupt delay (x10 usec)"); 323d217d4d9SSepherosa Ziehau SYSCTL_ADD_INT(&sc->sc_sysctl_ctx, 324d217d4d9SSepherosa Ziehau SYSCTL_CHILDREN(sc->sc_sysctl_tree), OID_AUTO, 325d217d4d9SSepherosa Ziehau "tx_intr_nsegs", CTLFLAG_RW, &sc->sc_tx_intr_nsegs, 0, 326d217d4d9SSepherosa Ziehau "TX IM, # segments per TX interrupt"); 327d217d4d9SSepherosa Ziehau SYSCTL_ADD_UINT(&sc->sc_sysctl_ctx, 328d217d4d9SSepherosa Ziehau SYSCTL_CHILDREN(sc->sc_sysctl_tree), OID_AUTO, 329d217d4d9SSepherosa Ziehau "timer", CTLFLAG_RW, &sc->sc_timer, 0, 330d217d4d9SSepherosa Ziehau "TX timer"); 331d217d4d9SSepherosa Ziehau 332d217d4d9SSepherosa Ziehau error = et_bus_config(dev); 333d217d4d9SSepherosa Ziehau if (error) 334d217d4d9SSepherosa Ziehau goto fail; 335d217d4d9SSepherosa Ziehau 336d217d4d9SSepherosa Ziehau et_get_eaddr(dev, eaddr); 337d217d4d9SSepherosa Ziehau 338d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_PM, 339d217d4d9SSepherosa Ziehau ET_PM_SYSCLK_GATE | ET_PM_TXCLK_GATE | ET_PM_RXCLK_GATE); 340d217d4d9SSepherosa Ziehau 341d217d4d9SSepherosa Ziehau et_reset(sc); 342d217d4d9SSepherosa Ziehau 343d217d4d9SSepherosa Ziehau et_disable_intrs(sc); 344d217d4d9SSepherosa Ziehau 345d217d4d9SSepherosa Ziehau error = et_dma_alloc(dev); 346d217d4d9SSepherosa Ziehau if (error) 347d217d4d9SSepherosa Ziehau goto fail; 348d217d4d9SSepherosa Ziehau 349d217d4d9SSepherosa Ziehau ifp->if_softc = sc; 350d217d4d9SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 351d217d4d9SSepherosa Ziehau ifp->if_init = et_init; 352d217d4d9SSepherosa Ziehau ifp->if_ioctl = et_ioctl; 353d217d4d9SSepherosa Ziehau ifp->if_start = et_start; 354d217d4d9SSepherosa Ziehau ifp->if_watchdog = et_watchdog; 355d217d4d9SSepherosa Ziehau ifp->if_mtu = ETHERMTU; 35639fdb7b3SSepherosa Ziehau ifp->if_capabilities = IFCAP_VLAN_MTU; 35739fdb7b3SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 358d217d4d9SSepherosa Ziehau ifq_set_maxlen(&ifp->if_snd, ET_TX_NDESC); 359d217d4d9SSepherosa Ziehau ifq_set_ready(&ifp->if_snd); 360d217d4d9SSepherosa Ziehau 361d217d4d9SSepherosa Ziehau et_chip_attach(sc); 362d217d4d9SSepherosa Ziehau 363d217d4d9SSepherosa Ziehau error = mii_phy_probe(dev, &sc->sc_miibus, 364d217d4d9SSepherosa Ziehau et_ifmedia_upd, et_ifmedia_sts); 365d217d4d9SSepherosa Ziehau if (error) { 366d217d4d9SSepherosa Ziehau device_printf(dev, "can't probe any PHY\n"); 367d217d4d9SSepherosa Ziehau goto fail; 368d217d4d9SSepherosa Ziehau } 369d217d4d9SSepherosa Ziehau 370d217d4d9SSepherosa Ziehau ether_ifattach(ifp, eaddr, NULL); 371d217d4d9SSepherosa Ziehau 3724c77af2dSSepherosa Ziehau ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->sc_irq_res)); 3734c77af2dSSepherosa Ziehau 374d217d4d9SSepherosa Ziehau error = bus_setup_intr(dev, sc->sc_irq_res, INTR_MPSAFE, et_intr, sc, 375d217d4d9SSepherosa Ziehau &sc->sc_irq_handle, ifp->if_serializer); 376d217d4d9SSepherosa Ziehau if (error) { 377d217d4d9SSepherosa Ziehau ether_ifdetach(ifp); 378d217d4d9SSepherosa Ziehau device_printf(dev, "can't setup intr\n"); 379d217d4d9SSepherosa Ziehau goto fail; 380d217d4d9SSepherosa Ziehau } 3819db4b353SSepherosa Ziehau 382d217d4d9SSepherosa Ziehau return 0; 383d217d4d9SSepherosa Ziehau fail: 384d217d4d9SSepherosa Ziehau et_detach(dev); 385d217d4d9SSepherosa Ziehau return error; 386d217d4d9SSepherosa Ziehau } 387d217d4d9SSepherosa Ziehau 388d217d4d9SSepherosa Ziehau static int 389d217d4d9SSepherosa Ziehau et_detach(device_t dev) 390d217d4d9SSepherosa Ziehau { 391d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 392d217d4d9SSepherosa Ziehau 393d217d4d9SSepherosa Ziehau if (device_is_attached(dev)) { 394d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 395d217d4d9SSepherosa Ziehau 396d217d4d9SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 397d217d4d9SSepherosa Ziehau et_stop(sc); 398d217d4d9SSepherosa Ziehau bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_handle); 399d217d4d9SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 400d217d4d9SSepherosa Ziehau 401d217d4d9SSepherosa Ziehau ether_ifdetach(ifp); 402d217d4d9SSepherosa Ziehau } 403d217d4d9SSepherosa Ziehau 404d217d4d9SSepherosa Ziehau if (sc->sc_sysctl_tree != NULL) 405d217d4d9SSepherosa Ziehau sysctl_ctx_free(&sc->sc_sysctl_ctx); 406d217d4d9SSepherosa Ziehau 407d217d4d9SSepherosa Ziehau if (sc->sc_miibus != NULL) 408d217d4d9SSepherosa Ziehau device_delete_child(dev, sc->sc_miibus); 409d217d4d9SSepherosa Ziehau bus_generic_detach(dev); 410d217d4d9SSepherosa Ziehau 411d217d4d9SSepherosa Ziehau if (sc->sc_irq_res != NULL) { 412d217d4d9SSepherosa Ziehau bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_rid, 413d217d4d9SSepherosa Ziehau sc->sc_irq_res); 414d217d4d9SSepherosa Ziehau } 415*7f28a608SSepherosa Ziehau if (sc->sc_irq_type == PCI_INTR_TYPE_MSI) 416*7f28a608SSepherosa Ziehau pci_release_msi(dev); 417d217d4d9SSepherosa Ziehau 418d217d4d9SSepherosa Ziehau if (sc->sc_mem_res != NULL) { 419d217d4d9SSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, 420d217d4d9SSepherosa Ziehau sc->sc_mem_res); 421d217d4d9SSepherosa Ziehau } 422d217d4d9SSepherosa Ziehau 423d217d4d9SSepherosa Ziehau et_dma_free(dev); 424d217d4d9SSepherosa Ziehau 425d217d4d9SSepherosa Ziehau return 0; 426d217d4d9SSepherosa Ziehau } 427d217d4d9SSepherosa Ziehau 428d217d4d9SSepherosa Ziehau static int 429d217d4d9SSepherosa Ziehau et_shutdown(device_t dev) 430d217d4d9SSepherosa Ziehau { 431d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 432d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 433d217d4d9SSepherosa Ziehau 434d217d4d9SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 435d217d4d9SSepherosa Ziehau et_stop(sc); 436d217d4d9SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 437d217d4d9SSepherosa Ziehau return 0; 438d217d4d9SSepherosa Ziehau } 439d217d4d9SSepherosa Ziehau 440d217d4d9SSepherosa Ziehau static int 441d217d4d9SSepherosa Ziehau et_miibus_readreg(device_t dev, int phy, int reg) 442d217d4d9SSepherosa Ziehau { 443d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 444d217d4d9SSepherosa Ziehau uint32_t val; 445d217d4d9SSepherosa Ziehau int i, ret; 446d217d4d9SSepherosa Ziehau 447d217d4d9SSepherosa Ziehau /* Stop any pending operations */ 448d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_CMD, 0); 449d217d4d9SSepherosa Ziehau 450d217d4d9SSepherosa Ziehau val = __SHIFTIN(phy, ET_MII_ADDR_PHY) | 451d217d4d9SSepherosa Ziehau __SHIFTIN(reg, ET_MII_ADDR_REG); 452d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_ADDR, val); 453d217d4d9SSepherosa Ziehau 454d217d4d9SSepherosa Ziehau /* Start reading */ 455d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_CMD, ET_MII_CMD_READ); 456d217d4d9SSepherosa Ziehau 457d217d4d9SSepherosa Ziehau #define NRETRY 50 458d217d4d9SSepherosa Ziehau 459d217d4d9SSepherosa Ziehau for (i = 0; i < NRETRY; ++i) { 460d217d4d9SSepherosa Ziehau val = CSR_READ_4(sc, ET_MII_IND); 461d217d4d9SSepherosa Ziehau if ((val & (ET_MII_IND_BUSY | ET_MII_IND_INVALID)) == 0) 462d217d4d9SSepherosa Ziehau break; 463d217d4d9SSepherosa Ziehau DELAY(50); 464d217d4d9SSepherosa Ziehau } 465d217d4d9SSepherosa Ziehau if (i == NRETRY) { 466d217d4d9SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 467d217d4d9SSepherosa Ziehau "read phy %d, reg %d timed out\n", phy, reg); 468d217d4d9SSepherosa Ziehau ret = 0; 469d217d4d9SSepherosa Ziehau goto back; 470d217d4d9SSepherosa Ziehau } 471d217d4d9SSepherosa Ziehau 472d217d4d9SSepherosa Ziehau #undef NRETRY 473d217d4d9SSepherosa Ziehau 474d217d4d9SSepherosa Ziehau val = CSR_READ_4(sc, ET_MII_STAT); 475d217d4d9SSepherosa Ziehau ret = __SHIFTOUT(val, ET_MII_STAT_VALUE); 476d217d4d9SSepherosa Ziehau 477d217d4d9SSepherosa Ziehau back: 478d217d4d9SSepherosa Ziehau /* Make sure that the current operation is stopped */ 479d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_CMD, 0); 480d217d4d9SSepherosa Ziehau return ret; 481d217d4d9SSepherosa Ziehau } 482d217d4d9SSepherosa Ziehau 483d217d4d9SSepherosa Ziehau static int 484d217d4d9SSepherosa Ziehau et_miibus_writereg(device_t dev, int phy, int reg, int val0) 485d217d4d9SSepherosa Ziehau { 486d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 487d217d4d9SSepherosa Ziehau uint32_t val; 488d217d4d9SSepherosa Ziehau int i; 489d217d4d9SSepherosa Ziehau 490d217d4d9SSepherosa Ziehau /* Stop any pending operations */ 491d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_CMD, 0); 492d217d4d9SSepherosa Ziehau 493d217d4d9SSepherosa Ziehau val = __SHIFTIN(phy, ET_MII_ADDR_PHY) | 494d217d4d9SSepherosa Ziehau __SHIFTIN(reg, ET_MII_ADDR_REG); 495d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_ADDR, val); 496d217d4d9SSepherosa Ziehau 497d217d4d9SSepherosa Ziehau /* Start writing */ 498d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_CTRL, __SHIFTIN(val0, ET_MII_CTRL_VALUE)); 499d217d4d9SSepherosa Ziehau 500d217d4d9SSepherosa Ziehau #define NRETRY 100 501d217d4d9SSepherosa Ziehau 502d217d4d9SSepherosa Ziehau for (i = 0; i < NRETRY; ++i) { 503d217d4d9SSepherosa Ziehau val = CSR_READ_4(sc, ET_MII_IND); 504d217d4d9SSepherosa Ziehau if ((val & ET_MII_IND_BUSY) == 0) 505d217d4d9SSepherosa Ziehau break; 506d217d4d9SSepherosa Ziehau DELAY(50); 507d217d4d9SSepherosa Ziehau } 508d217d4d9SSepherosa Ziehau if (i == NRETRY) { 509d217d4d9SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 510d217d4d9SSepherosa Ziehau "write phy %d, reg %d timed out\n", phy, reg); 511d217d4d9SSepherosa Ziehau et_miibus_readreg(dev, phy, reg); 512d217d4d9SSepherosa Ziehau } 513d217d4d9SSepherosa Ziehau 514d217d4d9SSepherosa Ziehau #undef NRETRY 515d217d4d9SSepherosa Ziehau 516d217d4d9SSepherosa Ziehau /* Make sure that the current operation is stopped */ 517d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_CMD, 0); 518d217d4d9SSepherosa Ziehau return 0; 519d217d4d9SSepherosa Ziehau } 520d217d4d9SSepherosa Ziehau 521d217d4d9SSepherosa Ziehau static void 522d217d4d9SSepherosa Ziehau et_miibus_statchg(device_t dev) 523d217d4d9SSepherosa Ziehau { 52460d2de1fSSepherosa Ziehau et_setmedia(device_get_softc(dev)); 525d217d4d9SSepherosa Ziehau } 526d217d4d9SSepherosa Ziehau 527d217d4d9SSepherosa Ziehau static int 528d217d4d9SSepherosa Ziehau et_ifmedia_upd(struct ifnet *ifp) 529d217d4d9SSepherosa Ziehau { 530d217d4d9SSepherosa Ziehau struct et_softc *sc = ifp->if_softc; 531d217d4d9SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->sc_miibus); 532d217d4d9SSepherosa Ziehau 533d217d4d9SSepherosa Ziehau if (mii->mii_instance != 0) { 534d217d4d9SSepherosa Ziehau struct mii_softc *miisc; 535d217d4d9SSepherosa Ziehau 536d217d4d9SSepherosa Ziehau LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 537d217d4d9SSepherosa Ziehau mii_phy_reset(miisc); 538d217d4d9SSepherosa Ziehau } 539d217d4d9SSepherosa Ziehau mii_mediachg(mii); 540d217d4d9SSepherosa Ziehau 541d217d4d9SSepherosa Ziehau return 0; 542d217d4d9SSepherosa Ziehau } 543d217d4d9SSepherosa Ziehau 544d217d4d9SSepherosa Ziehau static void 545d217d4d9SSepherosa Ziehau et_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 546d217d4d9SSepherosa Ziehau { 547d217d4d9SSepherosa Ziehau struct et_softc *sc = ifp->if_softc; 548d217d4d9SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->sc_miibus); 549d217d4d9SSepherosa Ziehau 550d217d4d9SSepherosa Ziehau mii_pollstat(mii); 551d217d4d9SSepherosa Ziehau ifmr->ifm_active = mii->mii_media_active; 552d217d4d9SSepherosa Ziehau ifmr->ifm_status = mii->mii_media_status; 553d217d4d9SSepherosa Ziehau } 554d217d4d9SSepherosa Ziehau 555d217d4d9SSepherosa Ziehau static void 556d217d4d9SSepherosa Ziehau et_stop(struct et_softc *sc) 557d217d4d9SSepherosa Ziehau { 558d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 559d217d4d9SSepherosa Ziehau 560d217d4d9SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 561d217d4d9SSepherosa Ziehau 562d217d4d9SSepherosa Ziehau callout_stop(&sc->sc_tick); 563d217d4d9SSepherosa Ziehau 564d217d4d9SSepherosa Ziehau et_stop_rxdma(sc); 565d217d4d9SSepherosa Ziehau et_stop_txdma(sc); 566d217d4d9SSepherosa Ziehau 567d217d4d9SSepherosa Ziehau et_disable_intrs(sc); 568d217d4d9SSepherosa Ziehau 569d217d4d9SSepherosa Ziehau et_free_tx_ring(sc); 570d217d4d9SSepherosa Ziehau et_free_rx_ring(sc); 571d217d4d9SSepherosa Ziehau 572d217d4d9SSepherosa Ziehau et_reset(sc); 573d217d4d9SSepherosa Ziehau 574d217d4d9SSepherosa Ziehau sc->sc_tx = 0; 575d217d4d9SSepherosa Ziehau sc->sc_tx_intr = 0; 5763effc1bfSSepherosa Ziehau sc->sc_flags &= ~ET_FLAG_TXRX_ENABLED; 577d217d4d9SSepherosa Ziehau 578d217d4d9SSepherosa Ziehau ifp->if_timer = 0; 5799ed293e0SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING; 5809ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 581d217d4d9SSepherosa Ziehau } 582d217d4d9SSepherosa Ziehau 583d217d4d9SSepherosa Ziehau static int 584d217d4d9SSepherosa Ziehau et_bus_config(device_t dev) 585d217d4d9SSepherosa Ziehau { 586d217d4d9SSepherosa Ziehau uint32_t val, max_plsz; 587d217d4d9SSepherosa Ziehau uint16_t ack_latency, replay_timer; 588d217d4d9SSepherosa Ziehau 589d217d4d9SSepherosa Ziehau /* 590d217d4d9SSepherosa Ziehau * Test whether EEPROM is valid 591d217d4d9SSepherosa Ziehau * NOTE: Read twice to get the correct value 592d217d4d9SSepherosa Ziehau */ 593d217d4d9SSepherosa Ziehau pci_read_config(dev, ET_PCIR_EEPROM_STATUS, 1); 594d217d4d9SSepherosa Ziehau val = pci_read_config(dev, ET_PCIR_EEPROM_STATUS, 1); 595d217d4d9SSepherosa Ziehau if (val & ET_PCIM_EEPROM_STATUS_ERROR) { 596d217d4d9SSepherosa Ziehau device_printf(dev, "EEPROM status error 0x%02x\n", val); 597d217d4d9SSepherosa Ziehau return ENXIO; 598d217d4d9SSepherosa Ziehau } 599d217d4d9SSepherosa Ziehau 600d217d4d9SSepherosa Ziehau /* TODO: LED */ 601d217d4d9SSepherosa Ziehau 602d217d4d9SSepherosa Ziehau /* 603d217d4d9SSepherosa Ziehau * Configure ACK latency and replay timer according to 604d217d4d9SSepherosa Ziehau * max playload size 605d217d4d9SSepherosa Ziehau */ 606d217d4d9SSepherosa Ziehau val = pci_read_config(dev, ET_PCIR_DEVICE_CAPS, 4); 607d217d4d9SSepherosa Ziehau max_plsz = val & ET_PCIM_DEVICE_CAPS_MAX_PLSZ; 608d217d4d9SSepherosa Ziehau 609d217d4d9SSepherosa Ziehau switch (max_plsz) { 610d217d4d9SSepherosa Ziehau case ET_PCIV_DEVICE_CAPS_PLSZ_128: 611d217d4d9SSepherosa Ziehau ack_latency = ET_PCIV_ACK_LATENCY_128; 612d217d4d9SSepherosa Ziehau replay_timer = ET_PCIV_REPLAY_TIMER_128; 613d217d4d9SSepherosa Ziehau break; 614d217d4d9SSepherosa Ziehau 615d217d4d9SSepherosa Ziehau case ET_PCIV_DEVICE_CAPS_PLSZ_256: 616d217d4d9SSepherosa Ziehau ack_latency = ET_PCIV_ACK_LATENCY_256; 617d217d4d9SSepherosa Ziehau replay_timer = ET_PCIV_REPLAY_TIMER_256; 618d217d4d9SSepherosa Ziehau break; 619d217d4d9SSepherosa Ziehau 620d217d4d9SSepherosa Ziehau default: 621d217d4d9SSepherosa Ziehau ack_latency = pci_read_config(dev, ET_PCIR_ACK_LATENCY, 2); 622d217d4d9SSepherosa Ziehau replay_timer = pci_read_config(dev, ET_PCIR_REPLAY_TIMER, 2); 623d217d4d9SSepherosa Ziehau device_printf(dev, "ack latency %u, replay timer %u\n", 624d217d4d9SSepherosa Ziehau ack_latency, replay_timer); 625d217d4d9SSepherosa Ziehau break; 626d217d4d9SSepherosa Ziehau } 627d217d4d9SSepherosa Ziehau if (ack_latency != 0) { 628d217d4d9SSepherosa Ziehau pci_write_config(dev, ET_PCIR_ACK_LATENCY, ack_latency, 2); 629d217d4d9SSepherosa Ziehau pci_write_config(dev, ET_PCIR_REPLAY_TIMER, replay_timer, 2); 630d217d4d9SSepherosa Ziehau } 631d217d4d9SSepherosa Ziehau 632d217d4d9SSepherosa Ziehau /* 633d217d4d9SSepherosa Ziehau * Set L0s and L1 latency timer to 2us 634d217d4d9SSepherosa Ziehau */ 635d217d4d9SSepherosa Ziehau val = ET_PCIV_L0S_LATENCY(2) | ET_PCIV_L1_LATENCY(2); 636d217d4d9SSepherosa Ziehau pci_write_config(dev, ET_PCIR_L0S_L1_LATENCY, val, 1); 637d217d4d9SSepherosa Ziehau 638d217d4d9SSepherosa Ziehau /* 639d217d4d9SSepherosa Ziehau * Set max read request size to 2048 bytes 640d217d4d9SSepherosa Ziehau */ 641d217d4d9SSepherosa Ziehau val = pci_read_config(dev, ET_PCIR_DEVICE_CTRL, 2); 642d217d4d9SSepherosa Ziehau val &= ~ET_PCIM_DEVICE_CTRL_MAX_RRSZ; 643d217d4d9SSepherosa Ziehau val |= ET_PCIV_DEVICE_CTRL_RRSZ_2K; 644d217d4d9SSepherosa Ziehau pci_write_config(dev, ET_PCIR_DEVICE_CTRL, val, 2); 645d217d4d9SSepherosa Ziehau 646d217d4d9SSepherosa Ziehau return 0; 647d217d4d9SSepherosa Ziehau } 648d217d4d9SSepherosa Ziehau 649d217d4d9SSepherosa Ziehau static void 650d217d4d9SSepherosa Ziehau et_get_eaddr(device_t dev, uint8_t eaddr[]) 651d217d4d9SSepherosa Ziehau { 652d217d4d9SSepherosa Ziehau uint32_t val; 653d217d4d9SSepherosa Ziehau int i; 654d217d4d9SSepherosa Ziehau 655d217d4d9SSepherosa Ziehau val = pci_read_config(dev, ET_PCIR_MAC_ADDR0, 4); 656d217d4d9SSepherosa Ziehau for (i = 0; i < 4; ++i) 657d217d4d9SSepherosa Ziehau eaddr[i] = (val >> (8 * i)) & 0xff; 658d217d4d9SSepherosa Ziehau 659d217d4d9SSepherosa Ziehau val = pci_read_config(dev, ET_PCIR_MAC_ADDR1, 2); 660d217d4d9SSepherosa Ziehau for (; i < ETHER_ADDR_LEN; ++i) 661d217d4d9SSepherosa Ziehau eaddr[i] = (val >> (8 * (i - 4))) & 0xff; 662d217d4d9SSepherosa Ziehau } 663d217d4d9SSepherosa Ziehau 664d217d4d9SSepherosa Ziehau static void 665d217d4d9SSepherosa Ziehau et_reset(struct et_softc *sc) 666d217d4d9SSepherosa Ziehau { 667d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG1, 668d217d4d9SSepherosa Ziehau ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 669d217d4d9SSepherosa Ziehau ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | 670d217d4d9SSepherosa Ziehau ET_MAC_CFG1_SIM_RST | ET_MAC_CFG1_SOFT_RST); 671d217d4d9SSepherosa Ziehau 672d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_SWRST, 673d217d4d9SSepherosa Ziehau ET_SWRST_TXDMA | ET_SWRST_RXDMA | 674d217d4d9SSepherosa Ziehau ET_SWRST_TXMAC | ET_SWRST_RXMAC | 675d217d4d9SSepherosa Ziehau ET_SWRST_MAC | ET_SWRST_MAC_STAT | ET_SWRST_MMC); 676d217d4d9SSepherosa Ziehau 677d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG1, 678d217d4d9SSepherosa Ziehau ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 679d217d4d9SSepherosa Ziehau ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC); 680d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG1, 0); 681d217d4d9SSepherosa Ziehau } 682d217d4d9SSepherosa Ziehau 683d217d4d9SSepherosa Ziehau static void 684d217d4d9SSepherosa Ziehau et_disable_intrs(struct et_softc *sc) 685d217d4d9SSepherosa Ziehau { 686d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_INTR_MASK, 0xffffffff); 687d217d4d9SSepherosa Ziehau } 688d217d4d9SSepherosa Ziehau 689d217d4d9SSepherosa Ziehau static void 690d217d4d9SSepherosa Ziehau et_enable_intrs(struct et_softc *sc, uint32_t intrs) 691d217d4d9SSepherosa Ziehau { 692d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_INTR_MASK, ~intrs); 693d217d4d9SSepherosa Ziehau } 694d217d4d9SSepherosa Ziehau 695d217d4d9SSepherosa Ziehau static int 696d217d4d9SSepherosa Ziehau et_dma_alloc(device_t dev) 697d217d4d9SSepherosa Ziehau { 698d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 699d217d4d9SSepherosa Ziehau struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 700d217d4d9SSepherosa Ziehau struct et_txstatus_data *txsd = &sc->sc_tx_status; 701d217d4d9SSepherosa Ziehau struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring; 702d217d4d9SSepherosa Ziehau struct et_rxstatus_data *rxsd = &sc->sc_rx_status; 703d217d4d9SSepherosa Ziehau int i, error; 704d217d4d9SSepherosa Ziehau 705d217d4d9SSepherosa Ziehau /* 706d217d4d9SSepherosa Ziehau * Create top level DMA tag 707d217d4d9SSepherosa Ziehau */ 708d217d4d9SSepherosa Ziehau error = bus_dma_tag_create(NULL, 1, 0, 7094c749635SSepherosa Ziehau BUS_SPACE_MAXADDR, 710d217d4d9SSepherosa Ziehau BUS_SPACE_MAXADDR, 711d217d4d9SSepherosa Ziehau NULL, NULL, 7124c749635SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, 7134c749635SSepherosa Ziehau 0, 714d217d4d9SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, 715d217d4d9SSepherosa Ziehau 0, &sc->sc_dtag); 716d217d4d9SSepherosa Ziehau if (error) { 717d217d4d9SSepherosa Ziehau device_printf(dev, "can't create DMA tag\n"); 718d217d4d9SSepherosa Ziehau return error; 719d217d4d9SSepherosa Ziehau } 720d217d4d9SSepherosa Ziehau 721d217d4d9SSepherosa Ziehau /* 722d217d4d9SSepherosa Ziehau * Create TX ring DMA stuffs 723d217d4d9SSepherosa Ziehau */ 724c7f73cc7SSepherosa Ziehau tx_ring->tr_desc = bus_dmamem_coherent_any(sc->sc_dtag, 725c7f73cc7SSepherosa Ziehau ET_ALIGN, ET_TX_RING_SIZE, 726c7f73cc7SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 727c7f73cc7SSepherosa Ziehau &tx_ring->tr_dtag, &tx_ring->tr_dmap, 728c7f73cc7SSepherosa Ziehau &tx_ring->tr_paddr); 729c7f73cc7SSepherosa Ziehau if (tx_ring->tr_desc == NULL) { 730d217d4d9SSepherosa Ziehau device_printf(dev, "can't create TX ring DMA stuffs\n"); 731c7f73cc7SSepherosa Ziehau return ENOMEM; 732d217d4d9SSepherosa Ziehau } 733d217d4d9SSepherosa Ziehau 734d217d4d9SSepherosa Ziehau /* 735d217d4d9SSepherosa Ziehau * Create TX status DMA stuffs 736d217d4d9SSepherosa Ziehau */ 737c7f73cc7SSepherosa Ziehau txsd->txsd_status = bus_dmamem_coherent_any(sc->sc_dtag, 738c7f73cc7SSepherosa Ziehau ET_ALIGN, sizeof(uint32_t), 739c7f73cc7SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 740c7f73cc7SSepherosa Ziehau &txsd->txsd_dtag, &txsd->txsd_dmap, 741c7f73cc7SSepherosa Ziehau &txsd->txsd_paddr); 742c7f73cc7SSepherosa Ziehau if (txsd->txsd_status == NULL) { 743d217d4d9SSepherosa Ziehau device_printf(dev, "can't create TX status DMA stuffs\n"); 744c7f73cc7SSepherosa Ziehau return ENOMEM; 745d217d4d9SSepherosa Ziehau } 746d217d4d9SSepherosa Ziehau 747d217d4d9SSepherosa Ziehau /* 748d217d4d9SSepherosa Ziehau * Create DMA stuffs for RX rings 749d217d4d9SSepherosa Ziehau */ 750d217d4d9SSepherosa Ziehau for (i = 0; i < ET_RX_NRING; ++i) { 751d217d4d9SSepherosa Ziehau static const uint32_t rx_ring_posreg[ET_RX_NRING] = 752d217d4d9SSepherosa Ziehau { ET_RX_RING0_POS, ET_RX_RING1_POS }; 753d217d4d9SSepherosa Ziehau 754d217d4d9SSepherosa Ziehau struct et_rxdesc_ring *rx_ring = &sc->sc_rx_ring[i]; 755d217d4d9SSepherosa Ziehau 756c7f73cc7SSepherosa Ziehau rx_ring->rr_desc = bus_dmamem_coherent_any(sc->sc_dtag, 757c7f73cc7SSepherosa Ziehau ET_ALIGN, ET_RX_RING_SIZE, 758c7f73cc7SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 759c7f73cc7SSepherosa Ziehau &rx_ring->rr_dtag, &rx_ring->rr_dmap, 760c7f73cc7SSepherosa Ziehau &rx_ring->rr_paddr); 761c7f73cc7SSepherosa Ziehau if (rx_ring->rr_desc == NULL) { 762d217d4d9SSepherosa Ziehau device_printf(dev, "can't create DMA stuffs for " 763d217d4d9SSepherosa Ziehau "the %d RX ring\n", i); 764c7f73cc7SSepherosa Ziehau return ENOMEM; 765d217d4d9SSepherosa Ziehau } 766d217d4d9SSepherosa Ziehau rx_ring->rr_posreg = rx_ring_posreg[i]; 767d217d4d9SSepherosa Ziehau } 768d217d4d9SSepherosa Ziehau 769d217d4d9SSepherosa Ziehau /* 770d217d4d9SSepherosa Ziehau * Create RX stat ring DMA stuffs 771d217d4d9SSepherosa Ziehau */ 772c7f73cc7SSepherosa Ziehau rxst_ring->rsr_stat = bus_dmamem_coherent_any(sc->sc_dtag, 773c7f73cc7SSepherosa Ziehau ET_ALIGN, ET_RXSTAT_RING_SIZE, 774c7f73cc7SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 775c7f73cc7SSepherosa Ziehau &rxst_ring->rsr_dtag, &rxst_ring->rsr_dmap, 776c7f73cc7SSepherosa Ziehau &rxst_ring->rsr_paddr); 777c7f73cc7SSepherosa Ziehau if (rxst_ring->rsr_stat == NULL) { 778d217d4d9SSepherosa Ziehau device_printf(dev, "can't create RX stat ring DMA stuffs\n"); 779c7f73cc7SSepherosa Ziehau return ENOMEM; 780d217d4d9SSepherosa Ziehau } 781d217d4d9SSepherosa Ziehau 782d217d4d9SSepherosa Ziehau /* 783d217d4d9SSepherosa Ziehau * Create RX status DMA stuffs 784d217d4d9SSepherosa Ziehau */ 785c7f73cc7SSepherosa Ziehau rxsd->rxsd_status = bus_dmamem_coherent_any(sc->sc_dtag, 786c7f73cc7SSepherosa Ziehau ET_ALIGN, sizeof(struct et_rxstatus), 787c7f73cc7SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 788c7f73cc7SSepherosa Ziehau &rxsd->rxsd_dtag, &rxsd->rxsd_dmap, 789c7f73cc7SSepherosa Ziehau &rxsd->rxsd_paddr); 790c7f73cc7SSepherosa Ziehau if (rxsd->rxsd_status == NULL) { 791d217d4d9SSepherosa Ziehau device_printf(dev, "can't create RX status DMA stuffs\n"); 792c7f73cc7SSepherosa Ziehau return ENOMEM; 793d217d4d9SSepherosa Ziehau } 794d217d4d9SSepherosa Ziehau 795d217d4d9SSepherosa Ziehau /* 796d217d4d9SSepherosa Ziehau * Create mbuf DMA stuffs 797d217d4d9SSepherosa Ziehau */ 798d217d4d9SSepherosa Ziehau error = et_dma_mbuf_create(dev); 799d217d4d9SSepherosa Ziehau if (error) 800d217d4d9SSepherosa Ziehau return error; 801d217d4d9SSepherosa Ziehau 8023effc1bfSSepherosa Ziehau /* 8033effc1bfSSepherosa Ziehau * Create jumbo buffer DMA stuffs 8043effc1bfSSepherosa Ziehau * NOTE: Allow it to fail 8053effc1bfSSepherosa Ziehau */ 8063effc1bfSSepherosa Ziehau if (et_jumbo_mem_alloc(dev) == 0) 8073effc1bfSSepherosa Ziehau sc->sc_flags |= ET_FLAG_JUMBO; 8083effc1bfSSepherosa Ziehau 809d217d4d9SSepherosa Ziehau return 0; 810d217d4d9SSepherosa Ziehau } 811d217d4d9SSepherosa Ziehau 812d217d4d9SSepherosa Ziehau static void 813d217d4d9SSepherosa Ziehau et_dma_free(device_t dev) 814d217d4d9SSepherosa Ziehau { 815d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 816d217d4d9SSepherosa Ziehau struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 817d217d4d9SSepherosa Ziehau struct et_txstatus_data *txsd = &sc->sc_tx_status; 818d217d4d9SSepherosa Ziehau struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring; 819d217d4d9SSepherosa Ziehau struct et_rxstatus_data *rxsd = &sc->sc_rx_status; 820d217d4d9SSepherosa Ziehau int i, rx_done[ET_RX_NRING]; 821d217d4d9SSepherosa Ziehau 822d217d4d9SSepherosa Ziehau /* 823d217d4d9SSepherosa Ziehau * Destroy TX ring DMA stuffs 824d217d4d9SSepherosa Ziehau */ 825d217d4d9SSepherosa Ziehau et_dma_mem_destroy(tx_ring->tr_dtag, tx_ring->tr_desc, 826d217d4d9SSepherosa Ziehau tx_ring->tr_dmap); 827d217d4d9SSepherosa Ziehau 828d217d4d9SSepherosa Ziehau /* 829d217d4d9SSepherosa Ziehau * Destroy TX status DMA stuffs 830d217d4d9SSepherosa Ziehau */ 831d217d4d9SSepherosa Ziehau et_dma_mem_destroy(txsd->txsd_dtag, txsd->txsd_status, 832d217d4d9SSepherosa Ziehau txsd->txsd_dmap); 833d217d4d9SSepherosa Ziehau 834d217d4d9SSepherosa Ziehau /* 835d217d4d9SSepherosa Ziehau * Destroy DMA stuffs for RX rings 836d217d4d9SSepherosa Ziehau */ 837d217d4d9SSepherosa Ziehau for (i = 0; i < ET_RX_NRING; ++i) { 838d217d4d9SSepherosa Ziehau struct et_rxdesc_ring *rx_ring = &sc->sc_rx_ring[i]; 839d217d4d9SSepherosa Ziehau 840d217d4d9SSepherosa Ziehau et_dma_mem_destroy(rx_ring->rr_dtag, rx_ring->rr_desc, 841d217d4d9SSepherosa Ziehau rx_ring->rr_dmap); 842d217d4d9SSepherosa Ziehau } 843d217d4d9SSepherosa Ziehau 844d217d4d9SSepherosa Ziehau /* 845d217d4d9SSepherosa Ziehau * Destroy RX stat ring DMA stuffs 846d217d4d9SSepherosa Ziehau */ 847d217d4d9SSepherosa Ziehau et_dma_mem_destroy(rxst_ring->rsr_dtag, rxst_ring->rsr_stat, 848d217d4d9SSepherosa Ziehau rxst_ring->rsr_dmap); 849d217d4d9SSepherosa Ziehau 850d217d4d9SSepherosa Ziehau /* 851d217d4d9SSepherosa Ziehau * Destroy RX status DMA stuffs 852d217d4d9SSepherosa Ziehau */ 853d217d4d9SSepherosa Ziehau et_dma_mem_destroy(rxsd->rxsd_dtag, rxsd->rxsd_status, 854d217d4d9SSepherosa Ziehau rxsd->rxsd_dmap); 855d217d4d9SSepherosa Ziehau 856d217d4d9SSepherosa Ziehau /* 857d217d4d9SSepherosa Ziehau * Destroy mbuf DMA stuffs 858d217d4d9SSepherosa Ziehau */ 859d217d4d9SSepherosa Ziehau for (i = 0; i < ET_RX_NRING; ++i) 860d217d4d9SSepherosa Ziehau rx_done[i] = ET_RX_NDESC; 861d217d4d9SSepherosa Ziehau et_dma_mbuf_destroy(dev, ET_TX_NDESC, rx_done); 862d217d4d9SSepherosa Ziehau 863d217d4d9SSepherosa Ziehau /* 8643effc1bfSSepherosa Ziehau * Destroy jumbo buffer DMA stuffs 8653effc1bfSSepherosa Ziehau */ 8663effc1bfSSepherosa Ziehau if (sc->sc_flags & ET_FLAG_JUMBO) 8673effc1bfSSepherosa Ziehau et_jumbo_mem_free(dev); 8683effc1bfSSepherosa Ziehau 8693effc1bfSSepherosa Ziehau /* 870d217d4d9SSepherosa Ziehau * Destroy top level DMA tag 871d217d4d9SSepherosa Ziehau */ 872d217d4d9SSepherosa Ziehau if (sc->sc_dtag != NULL) 873d217d4d9SSepherosa Ziehau bus_dma_tag_destroy(sc->sc_dtag); 874d217d4d9SSepherosa Ziehau } 875d217d4d9SSepherosa Ziehau 876d217d4d9SSepherosa Ziehau static int 877d217d4d9SSepherosa Ziehau et_dma_mbuf_create(device_t dev) 878d217d4d9SSepherosa Ziehau { 879d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 880d217d4d9SSepherosa Ziehau struct et_txbuf_data *tbd = &sc->sc_tx_data; 881d217d4d9SSepherosa Ziehau int i, error, rx_done[ET_RX_NRING]; 882d217d4d9SSepherosa Ziehau 883d217d4d9SSepherosa Ziehau /* 8840fe5209eSSepherosa Ziehau * Create RX mbuf DMA tag 885d217d4d9SSepherosa Ziehau */ 886d217d4d9SSepherosa Ziehau error = bus_dma_tag_create(sc->sc_dtag, 1, 0, 887d217d4d9SSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 888d217d4d9SSepherosa Ziehau NULL, NULL, 8890fe5209eSSepherosa Ziehau MCLBYTES, 1, MCLBYTES, 8904c749635SSepherosa Ziehau BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK, 8910fe5209eSSepherosa Ziehau &sc->sc_rxbuf_dtag); 892d217d4d9SSepherosa Ziehau if (error) { 8930fe5209eSSepherosa Ziehau device_printf(dev, "can't create RX mbuf DMA tag\n"); 894d217d4d9SSepherosa Ziehau return error; 895d217d4d9SSepherosa Ziehau } 896d217d4d9SSepherosa Ziehau 897d217d4d9SSepherosa Ziehau /* 898d217d4d9SSepherosa Ziehau * Create spare DMA map for RX mbufs 899d217d4d9SSepherosa Ziehau */ 9000fe5209eSSepherosa Ziehau error = bus_dmamap_create(sc->sc_rxbuf_dtag, BUS_DMA_WAITOK, 9010fe5209eSSepherosa Ziehau &sc->sc_rxbuf_tmp_dmap); 902d217d4d9SSepherosa Ziehau if (error) { 903d217d4d9SSepherosa Ziehau device_printf(dev, "can't create spare mbuf DMA map\n"); 9040fe5209eSSepherosa Ziehau bus_dma_tag_destroy(sc->sc_rxbuf_dtag); 9050fe5209eSSepherosa Ziehau sc->sc_rxbuf_dtag = NULL; 906d217d4d9SSepherosa Ziehau return error; 907d217d4d9SSepherosa Ziehau } 908d217d4d9SSepherosa Ziehau 909d217d4d9SSepherosa Ziehau /* 910d217d4d9SSepherosa Ziehau * Create DMA maps for RX mbufs 911d217d4d9SSepherosa Ziehau */ 912d217d4d9SSepherosa Ziehau bzero(rx_done, sizeof(rx_done)); 913d217d4d9SSepherosa Ziehau for (i = 0; i < ET_RX_NRING; ++i) { 914d217d4d9SSepherosa Ziehau struct et_rxbuf_data *rbd = &sc->sc_rx_data[i]; 915d217d4d9SSepherosa Ziehau int j; 916d217d4d9SSepherosa Ziehau 917d217d4d9SSepherosa Ziehau for (j = 0; j < ET_RX_NDESC; ++j) { 9180fe5209eSSepherosa Ziehau error = bus_dmamap_create(sc->sc_rxbuf_dtag, 9194c749635SSepherosa Ziehau BUS_DMA_WAITOK, 920d217d4d9SSepherosa Ziehau &rbd->rbd_buf[j].rb_dmap); 921d217d4d9SSepherosa Ziehau if (error) { 922d217d4d9SSepherosa Ziehau device_printf(dev, "can't create %d RX mbuf " 923d217d4d9SSepherosa Ziehau "for %d RX ring\n", j, i); 924d217d4d9SSepherosa Ziehau rx_done[i] = j; 925d217d4d9SSepherosa Ziehau et_dma_mbuf_destroy(dev, 0, rx_done); 926d217d4d9SSepherosa Ziehau return error; 927d217d4d9SSepherosa Ziehau } 928d217d4d9SSepherosa Ziehau } 929d217d4d9SSepherosa Ziehau rx_done[i] = ET_RX_NDESC; 930d217d4d9SSepherosa Ziehau 931d217d4d9SSepherosa Ziehau rbd->rbd_softc = sc; 932d217d4d9SSepherosa Ziehau rbd->rbd_ring = &sc->sc_rx_ring[i]; 933d217d4d9SSepherosa Ziehau } 934d217d4d9SSepherosa Ziehau 935d217d4d9SSepherosa Ziehau /* 9360fe5209eSSepherosa Ziehau * Create TX mbuf DMA tag 9370fe5209eSSepherosa Ziehau */ 9380fe5209eSSepherosa Ziehau error = bus_dma_tag_create(sc->sc_dtag, 1, 0, 9390fe5209eSSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 9400fe5209eSSepherosa Ziehau NULL, NULL, 9410fe5209eSSepherosa Ziehau ET_JUMBO_FRAMELEN, ET_NSEG_MAX, MCLBYTES, 9420fe5209eSSepherosa Ziehau BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK | 9430fe5209eSSepherosa Ziehau BUS_DMA_ONEBPAGE, 9440fe5209eSSepherosa Ziehau &sc->sc_txbuf_dtag); 9450fe5209eSSepherosa Ziehau if (error) { 9460fe5209eSSepherosa Ziehau device_printf(dev, "can't create TX mbuf DMA tag\n"); 9470fe5209eSSepherosa Ziehau return error; 9480fe5209eSSepherosa Ziehau } 9490fe5209eSSepherosa Ziehau 9500fe5209eSSepherosa Ziehau /* 951d217d4d9SSepherosa Ziehau * Create DMA maps for TX mbufs 952d217d4d9SSepherosa Ziehau */ 953d217d4d9SSepherosa Ziehau for (i = 0; i < ET_TX_NDESC; ++i) { 9540fe5209eSSepherosa Ziehau error = bus_dmamap_create(sc->sc_txbuf_dtag, 9550fe5209eSSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE, 956d217d4d9SSepherosa Ziehau &tbd->tbd_buf[i].tb_dmap); 957d217d4d9SSepherosa Ziehau if (error) { 958d217d4d9SSepherosa Ziehau device_printf(dev, "can't create %d TX mbuf " 959d217d4d9SSepherosa Ziehau "DMA map\n", i); 960d217d4d9SSepherosa Ziehau et_dma_mbuf_destroy(dev, i, rx_done); 961d217d4d9SSepherosa Ziehau return error; 962d217d4d9SSepherosa Ziehau } 963d217d4d9SSepherosa Ziehau } 964d217d4d9SSepherosa Ziehau 965d217d4d9SSepherosa Ziehau return 0; 966d217d4d9SSepherosa Ziehau } 967d217d4d9SSepherosa Ziehau 968d217d4d9SSepherosa Ziehau static void 969d217d4d9SSepherosa Ziehau et_dma_mbuf_destroy(device_t dev, int tx_done, const int rx_done[]) 970d217d4d9SSepherosa Ziehau { 971d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 972d217d4d9SSepherosa Ziehau struct et_txbuf_data *tbd = &sc->sc_tx_data; 973d217d4d9SSepherosa Ziehau int i; 974d217d4d9SSepherosa Ziehau 975d217d4d9SSepherosa Ziehau /* 9760fe5209eSSepherosa Ziehau * Destroy DMA tag and maps for RX mbufs 977d217d4d9SSepherosa Ziehau */ 9780fe5209eSSepherosa Ziehau if (sc->sc_rxbuf_dtag) { 979d217d4d9SSepherosa Ziehau for (i = 0; i < ET_RX_NRING; ++i) { 980d217d4d9SSepherosa Ziehau struct et_rxbuf_data *rbd = &sc->sc_rx_data[i]; 981d217d4d9SSepherosa Ziehau int j; 982d217d4d9SSepherosa Ziehau 983d217d4d9SSepherosa Ziehau for (j = 0; j < rx_done[i]; ++j) { 984d217d4d9SSepherosa Ziehau struct et_rxbuf *rb = &rbd->rbd_buf[j]; 985d217d4d9SSepherosa Ziehau 986d217d4d9SSepherosa Ziehau KASSERT(rb->rb_mbuf == NULL, 9870fe5209eSSepherosa Ziehau ("RX mbuf in %d RX ring is " 988ed20d0e3SSascha Wildner "not freed yet", i)); 9890fe5209eSSepherosa Ziehau bus_dmamap_destroy(sc->sc_rxbuf_dtag, 9900fe5209eSSepherosa Ziehau rb->rb_dmap); 991d217d4d9SSepherosa Ziehau } 992d217d4d9SSepherosa Ziehau } 9930fe5209eSSepherosa Ziehau bus_dmamap_destroy(sc->sc_rxbuf_dtag, sc->sc_rxbuf_tmp_dmap); 9940fe5209eSSepherosa Ziehau bus_dma_tag_destroy(sc->sc_rxbuf_dtag); 9950fe5209eSSepherosa Ziehau sc->sc_rxbuf_dtag = NULL; 9960fe5209eSSepherosa Ziehau } 997d217d4d9SSepherosa Ziehau 998d217d4d9SSepherosa Ziehau /* 9990fe5209eSSepherosa Ziehau * Destroy DMA tag and maps for TX mbufs 1000d217d4d9SSepherosa Ziehau */ 10010fe5209eSSepherosa Ziehau if (sc->sc_txbuf_dtag) { 1002d217d4d9SSepherosa Ziehau for (i = 0; i < tx_done; ++i) { 1003d217d4d9SSepherosa Ziehau struct et_txbuf *tb = &tbd->tbd_buf[i]; 1004d217d4d9SSepherosa Ziehau 10050fe5209eSSepherosa Ziehau KASSERT(tb->tb_mbuf == NULL, 1006ed20d0e3SSascha Wildner ("TX mbuf is not freed yet")); 10070fe5209eSSepherosa Ziehau bus_dmamap_destroy(sc->sc_txbuf_dtag, tb->tb_dmap); 1008d217d4d9SSepherosa Ziehau } 10090fe5209eSSepherosa Ziehau bus_dma_tag_destroy(sc->sc_txbuf_dtag); 10100fe5209eSSepherosa Ziehau sc->sc_txbuf_dtag = NULL; 10110fe5209eSSepherosa Ziehau } 1012d217d4d9SSepherosa Ziehau } 1013d217d4d9SSepherosa Ziehau 1014d217d4d9SSepherosa Ziehau static void 1015d217d4d9SSepherosa Ziehau et_dma_mem_destroy(bus_dma_tag_t dtag, void *addr, bus_dmamap_t dmap) 1016d217d4d9SSepherosa Ziehau { 1017d217d4d9SSepherosa Ziehau if (dtag != NULL) { 1018d217d4d9SSepherosa Ziehau bus_dmamap_unload(dtag, dmap); 1019d217d4d9SSepherosa Ziehau bus_dmamem_free(dtag, addr, dmap); 1020d217d4d9SSepherosa Ziehau bus_dma_tag_destroy(dtag); 1021d217d4d9SSepherosa Ziehau } 1022d217d4d9SSepherosa Ziehau } 1023d217d4d9SSepherosa Ziehau 1024d217d4d9SSepherosa Ziehau static void 1025d217d4d9SSepherosa Ziehau et_chip_attach(struct et_softc *sc) 1026d217d4d9SSepherosa Ziehau { 1027d217d4d9SSepherosa Ziehau uint32_t val; 1028d217d4d9SSepherosa Ziehau 1029d217d4d9SSepherosa Ziehau /* 1030d217d4d9SSepherosa Ziehau * Perform minimal initialization 1031d217d4d9SSepherosa Ziehau */ 1032d217d4d9SSepherosa Ziehau 1033d217d4d9SSepherosa Ziehau /* Disable loopback */ 1034d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_LOOPBACK, 0); 1035d217d4d9SSepherosa Ziehau 1036d217d4d9SSepherosa Ziehau /* Reset MAC */ 1037d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG1, 1038d217d4d9SSepherosa Ziehau ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 1039d217d4d9SSepherosa Ziehau ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | 1040d217d4d9SSepherosa Ziehau ET_MAC_CFG1_SIM_RST | ET_MAC_CFG1_SOFT_RST); 1041d217d4d9SSepherosa Ziehau 1042d217d4d9SSepherosa Ziehau /* 1043d217d4d9SSepherosa Ziehau * Setup half duplex mode 1044d217d4d9SSepherosa Ziehau */ 1045d217d4d9SSepherosa Ziehau val = __SHIFTIN(10, ET_MAC_HDX_ALT_BEB_TRUNC) | 1046d217d4d9SSepherosa Ziehau __SHIFTIN(15, ET_MAC_HDX_REXMIT_MAX) | 1047d217d4d9SSepherosa Ziehau __SHIFTIN(55, ET_MAC_HDX_COLLWIN) | 1048d217d4d9SSepherosa Ziehau ET_MAC_HDX_EXC_DEFER; 1049d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_HDX, val); 1050d217d4d9SSepherosa Ziehau 1051d217d4d9SSepherosa Ziehau /* Clear MAC control */ 1052d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CTRL, 0); 1053d217d4d9SSepherosa Ziehau 1054d217d4d9SSepherosa Ziehau /* Reset MII */ 1055d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_CFG, ET_MII_CFG_CLKRST); 1056d217d4d9SSepherosa Ziehau 1057d217d4d9SSepherosa Ziehau /* Bring MAC out of reset state */ 1058d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG1, 0); 1059d217d4d9SSepherosa Ziehau 1060d217d4d9SSepherosa Ziehau /* Enable memory controllers */ 1061d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MMC_CTRL, ET_MMC_CTRL_ENABLE); 1062d217d4d9SSepherosa Ziehau } 1063d217d4d9SSepherosa Ziehau 1064d217d4d9SSepherosa Ziehau static void 1065d217d4d9SSepherosa Ziehau et_intr(void *xsc) 1066d217d4d9SSepherosa Ziehau { 1067d217d4d9SSepherosa Ziehau struct et_softc *sc = xsc; 1068d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1069d217d4d9SSepherosa Ziehau uint32_t intrs; 1070d217d4d9SSepherosa Ziehau 1071d217d4d9SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1072d217d4d9SSepherosa Ziehau 1073d217d4d9SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0) 1074d217d4d9SSepherosa Ziehau return; 1075d217d4d9SSepherosa Ziehau 1076d217d4d9SSepherosa Ziehau et_disable_intrs(sc); 1077d217d4d9SSepherosa Ziehau 1078d217d4d9SSepherosa Ziehau intrs = CSR_READ_4(sc, ET_INTR_STATUS); 1079d217d4d9SSepherosa Ziehau intrs &= ET_INTRS; 1080d217d4d9SSepherosa Ziehau if (intrs == 0) /* Not interested */ 1081d217d4d9SSepherosa Ziehau goto back; 1082d217d4d9SSepherosa Ziehau 1083d217d4d9SSepherosa Ziehau if (intrs & ET_INTR_RXEOF) 1084d217d4d9SSepherosa Ziehau et_rxeof(sc); 1085d217d4d9SSepherosa Ziehau if (intrs & (ET_INTR_TXEOF | ET_INTR_TIMER)) 1086136e59ffSSepherosa Ziehau et_txeof(sc, 1); 1087d217d4d9SSepherosa Ziehau if (intrs & ET_INTR_TIMER) 1088d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TIMER, sc->sc_timer); 1089d217d4d9SSepherosa Ziehau back: 1090d217d4d9SSepherosa Ziehau et_enable_intrs(sc, ET_INTRS); 1091d217d4d9SSepherosa Ziehau } 1092d217d4d9SSepherosa Ziehau 1093d217d4d9SSepherosa Ziehau static void 1094d217d4d9SSepherosa Ziehau et_init(void *xsc) 1095d217d4d9SSepherosa Ziehau { 1096d217d4d9SSepherosa Ziehau struct et_softc *sc = xsc; 1097d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1098d217d4d9SSepherosa Ziehau const struct et_bsize *arr; 1099d217d4d9SSepherosa Ziehau int error, i; 1100d217d4d9SSepherosa Ziehau 1101d217d4d9SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1102d217d4d9SSepherosa Ziehau 1103d217d4d9SSepherosa Ziehau et_stop(sc); 1104d217d4d9SSepherosa Ziehau 11053effc1bfSSepherosa Ziehau arr = ET_FRAMELEN(ifp->if_mtu) < MCLBYTES ? 11063effc1bfSSepherosa Ziehau et_bufsize_std : et_bufsize_jumbo; 1107d217d4d9SSepherosa Ziehau for (i = 0; i < ET_RX_NRING; ++i) { 1108d217d4d9SSepherosa Ziehau sc->sc_rx_data[i].rbd_bufsize = arr[i].bufsize; 1109d217d4d9SSepherosa Ziehau sc->sc_rx_data[i].rbd_newbuf = arr[i].newbuf; 11103effc1bfSSepherosa Ziehau sc->sc_rx_data[i].rbd_jumbo = arr[i].jumbo; 1111d217d4d9SSepherosa Ziehau } 1112d217d4d9SSepherosa Ziehau 1113d217d4d9SSepherosa Ziehau error = et_init_tx_ring(sc); 1114d217d4d9SSepherosa Ziehau if (error) 1115d217d4d9SSepherosa Ziehau goto back; 1116d217d4d9SSepherosa Ziehau 1117d217d4d9SSepherosa Ziehau error = et_init_rx_ring(sc); 1118d217d4d9SSepherosa Ziehau if (error) 1119d217d4d9SSepherosa Ziehau goto back; 1120d217d4d9SSepherosa Ziehau 1121d217d4d9SSepherosa Ziehau error = et_chip_init(sc); 1122d217d4d9SSepherosa Ziehau if (error) 1123d217d4d9SSepherosa Ziehau goto back; 1124d217d4d9SSepherosa Ziehau 112560d2de1fSSepherosa Ziehau error = et_enable_txrx(sc, 1); 1126d217d4d9SSepherosa Ziehau if (error) 1127d217d4d9SSepherosa Ziehau goto back; 1128d217d4d9SSepherosa Ziehau 1129d217d4d9SSepherosa Ziehau et_enable_intrs(sc, ET_INTRS); 1130d217d4d9SSepherosa Ziehau 1131d217d4d9SSepherosa Ziehau callout_reset(&sc->sc_tick, hz, et_tick, sc); 1132d217d4d9SSepherosa Ziehau 1133d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TIMER, sc->sc_timer); 1134d217d4d9SSepherosa Ziehau 1135d217d4d9SSepherosa Ziehau ifp->if_flags |= IFF_RUNNING; 11369ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 1137d217d4d9SSepherosa Ziehau back: 1138d217d4d9SSepherosa Ziehau if (error) 1139d217d4d9SSepherosa Ziehau et_stop(sc); 1140d217d4d9SSepherosa Ziehau } 1141d217d4d9SSepherosa Ziehau 1142d217d4d9SSepherosa Ziehau static int 1143d217d4d9SSepherosa Ziehau et_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) 1144d217d4d9SSepherosa Ziehau { 1145d217d4d9SSepherosa Ziehau struct et_softc *sc = ifp->if_softc; 1146d217d4d9SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->sc_miibus); 1147d217d4d9SSepherosa Ziehau struct ifreq *ifr = (struct ifreq *)data; 11483effc1bfSSepherosa Ziehau int error = 0, max_framelen; 1149d217d4d9SSepherosa Ziehau 1150d217d4d9SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1151d217d4d9SSepherosa Ziehau 1152d217d4d9SSepherosa Ziehau switch (cmd) { 1153d217d4d9SSepherosa Ziehau case SIOCSIFFLAGS: 1154d217d4d9SSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 1155d217d4d9SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 1156d217d4d9SSepherosa Ziehau if ((ifp->if_flags ^ sc->sc_if_flags) & 11575a5f28f3SSepherosa Ziehau (IFF_ALLMULTI | IFF_PROMISC)) 1158d217d4d9SSepherosa Ziehau et_setmulti(sc); 1159d217d4d9SSepherosa Ziehau } else { 1160d217d4d9SSepherosa Ziehau et_init(sc); 1161d217d4d9SSepherosa Ziehau } 1162d217d4d9SSepherosa Ziehau } else { 1163d217d4d9SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 1164d217d4d9SSepherosa Ziehau et_stop(sc); 1165d217d4d9SSepherosa Ziehau } 1166d217d4d9SSepherosa Ziehau sc->sc_if_flags = ifp->if_flags; 1167d217d4d9SSepherosa Ziehau break; 1168d217d4d9SSepherosa Ziehau 1169d217d4d9SSepherosa Ziehau case SIOCSIFMEDIA: 1170d217d4d9SSepherosa Ziehau case SIOCGIFMEDIA: 1171d217d4d9SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1172d217d4d9SSepherosa Ziehau break; 1173d217d4d9SSepherosa Ziehau 1174d217d4d9SSepherosa Ziehau case SIOCADDMULTI: 1175d217d4d9SSepherosa Ziehau case SIOCDELMULTI: 1176d217d4d9SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 1177d217d4d9SSepherosa Ziehau et_setmulti(sc); 1178d217d4d9SSepherosa Ziehau break; 1179d217d4d9SSepherosa Ziehau 1180d217d4d9SSepherosa Ziehau case SIOCSIFMTU: 11813effc1bfSSepherosa Ziehau if (sc->sc_flags & ET_FLAG_JUMBO) 11823effc1bfSSepherosa Ziehau max_framelen = ET_JUMBO_FRAMELEN; 11833effc1bfSSepherosa Ziehau else 11843effc1bfSSepherosa Ziehau max_framelen = MCLBYTES - 1; 11853effc1bfSSepherosa Ziehau 11863effc1bfSSepherosa Ziehau if (ET_FRAMELEN(ifr->ifr_mtu) > max_framelen) { 1187d217d4d9SSepherosa Ziehau error = EOPNOTSUPP; 1188d217d4d9SSepherosa Ziehau break; 11890fd7469eSSepherosa Ziehau } 11900fd7469eSSepherosa Ziehau 11910fd7469eSSepherosa Ziehau ifp->if_mtu = ifr->ifr_mtu; 11920fd7469eSSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 11930fd7469eSSepherosa Ziehau et_init(sc); 11940fd7469eSSepherosa Ziehau break; 1195d217d4d9SSepherosa Ziehau 1196d217d4d9SSepherosa Ziehau default: 1197d217d4d9SSepherosa Ziehau error = ether_ioctl(ifp, cmd, data); 1198d217d4d9SSepherosa Ziehau break; 1199d217d4d9SSepherosa Ziehau } 1200d217d4d9SSepherosa Ziehau return error; 1201d217d4d9SSepherosa Ziehau } 1202d217d4d9SSepherosa Ziehau 1203d217d4d9SSepherosa Ziehau static void 1204f0a26983SSepherosa Ziehau et_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) 1205d217d4d9SSepherosa Ziehau { 1206d217d4d9SSepherosa Ziehau struct et_softc *sc = ifp->if_softc; 1207d217d4d9SSepherosa Ziehau struct et_txbuf_data *tbd = &sc->sc_tx_data; 1208136e59ffSSepherosa Ziehau int trans, oactive; 1209d217d4d9SSepherosa Ziehau 1210f0a26983SSepherosa Ziehau ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq); 1211d217d4d9SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1212d217d4d9SSepherosa Ziehau 12139db4b353SSepherosa Ziehau if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0) { 12149db4b353SSepherosa Ziehau ifq_purge(&ifp->if_snd); 121560d2de1fSSepherosa Ziehau return; 12169db4b353SSepherosa Ziehau } 121760d2de1fSSepherosa Ziehau 12189ed293e0SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0 || ifq_is_oactive(&ifp->if_snd)) 1219d217d4d9SSepherosa Ziehau return; 1220d217d4d9SSepherosa Ziehau 1221136e59ffSSepherosa Ziehau oactive = 0; 1222d217d4d9SSepherosa Ziehau trans = 0; 1223d217d4d9SSepherosa Ziehau for (;;) { 1224d217d4d9SSepherosa Ziehau struct mbuf *m; 1225136e59ffSSepherosa Ziehau int error; 1226d217d4d9SSepherosa Ziehau 1227d217d4d9SSepherosa Ziehau if ((tbd->tbd_used + ET_NSEG_SPARE) > ET_TX_NDESC) { 1228136e59ffSSepherosa Ziehau if (oactive) { 12299ed293e0SSepherosa Ziehau ifq_set_oactive(&ifp->if_snd); 1230d217d4d9SSepherosa Ziehau break; 1231d217d4d9SSepherosa Ziehau } 1232d217d4d9SSepherosa Ziehau 1233136e59ffSSepherosa Ziehau et_txeof(sc, 0); 1234136e59ffSSepherosa Ziehau oactive = 1; 1235136e59ffSSepherosa Ziehau continue; 1236136e59ffSSepherosa Ziehau } 1237136e59ffSSepherosa Ziehau 1238d217d4d9SSepherosa Ziehau m = ifq_dequeue(&ifp->if_snd, NULL); 1239d217d4d9SSepherosa Ziehau if (m == NULL) 1240d217d4d9SSepherosa Ziehau break; 1241d217d4d9SSepherosa Ziehau 1242136e59ffSSepherosa Ziehau error = et_encap(sc, &m); 1243136e59ffSSepherosa Ziehau if (error) { 1244d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 1245136e59ffSSepherosa Ziehau KKASSERT(m == NULL); 1246136e59ffSSepherosa Ziehau 1247136e59ffSSepherosa Ziehau if (error == EFBIG) { 1248136e59ffSSepherosa Ziehau /* 1249136e59ffSSepherosa Ziehau * Excessive fragmented packets 1250136e59ffSSepherosa Ziehau */ 1251136e59ffSSepherosa Ziehau if (oactive) { 12529ed293e0SSepherosa Ziehau ifq_set_oactive(&ifp->if_snd); 1253d217d4d9SSepherosa Ziehau break; 1254d217d4d9SSepherosa Ziehau } 1255136e59ffSSepherosa Ziehau et_txeof(sc, 0); 1256136e59ffSSepherosa Ziehau oactive = 1; 1257136e59ffSSepherosa Ziehau } 1258136e59ffSSepherosa Ziehau continue; 1259136e59ffSSepherosa Ziehau } else { 1260136e59ffSSepherosa Ziehau oactive = 0; 1261136e59ffSSepherosa Ziehau } 1262d217d4d9SSepherosa Ziehau trans = 1; 1263d217d4d9SSepherosa Ziehau 1264d217d4d9SSepherosa Ziehau BPF_MTAP(ifp, m); 1265d217d4d9SSepherosa Ziehau } 1266d217d4d9SSepherosa Ziehau 1267d217d4d9SSepherosa Ziehau if (trans) 1268d217d4d9SSepherosa Ziehau ifp->if_timer = 5; 1269d217d4d9SSepherosa Ziehau } 1270d217d4d9SSepherosa Ziehau 1271d217d4d9SSepherosa Ziehau static void 1272d217d4d9SSepherosa Ziehau et_watchdog(struct ifnet *ifp) 1273d217d4d9SSepherosa Ziehau { 1274d217d4d9SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1275d217d4d9SSepherosa Ziehau 1276d217d4d9SSepherosa Ziehau if_printf(ifp, "watchdog timed out\n"); 1277d217d4d9SSepherosa Ziehau 1278d217d4d9SSepherosa Ziehau ifp->if_init(ifp->if_softc); 12799db4b353SSepherosa Ziehau if_devstart(ifp); 1280d217d4d9SSepherosa Ziehau } 1281d217d4d9SSepherosa Ziehau 1282d217d4d9SSepherosa Ziehau static int 1283d217d4d9SSepherosa Ziehau et_stop_rxdma(struct et_softc *sc) 1284d217d4d9SSepherosa Ziehau { 1285d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXDMA_CTRL, 1286d217d4d9SSepherosa Ziehau ET_RXDMA_CTRL_HALT | ET_RXDMA_CTRL_RING1_ENABLE); 1287d217d4d9SSepherosa Ziehau 1288d217d4d9SSepherosa Ziehau DELAY(5); 1289d217d4d9SSepherosa Ziehau if ((CSR_READ_4(sc, ET_RXDMA_CTRL) & ET_RXDMA_CTRL_HALTED) == 0) { 1290d217d4d9SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "can't stop RX DMA engine\n"); 1291d217d4d9SSepherosa Ziehau return ETIMEDOUT; 1292d217d4d9SSepherosa Ziehau } 1293d217d4d9SSepherosa Ziehau return 0; 1294d217d4d9SSepherosa Ziehau } 1295d217d4d9SSepherosa Ziehau 1296d217d4d9SSepherosa Ziehau static int 1297d217d4d9SSepherosa Ziehau et_stop_txdma(struct et_softc *sc) 1298d217d4d9SSepherosa Ziehau { 1299d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TXDMA_CTRL, 1300d217d4d9SSepherosa Ziehau ET_TXDMA_CTRL_HALT | ET_TXDMA_CTRL_SINGLE_EPKT); 1301d217d4d9SSepherosa Ziehau return 0; 1302d217d4d9SSepherosa Ziehau } 1303d217d4d9SSepherosa Ziehau 1304d217d4d9SSepherosa Ziehau static void 1305d217d4d9SSepherosa Ziehau et_free_tx_ring(struct et_softc *sc) 1306d217d4d9SSepherosa Ziehau { 1307d217d4d9SSepherosa Ziehau struct et_txbuf_data *tbd = &sc->sc_tx_data; 1308d217d4d9SSepherosa Ziehau struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 1309d217d4d9SSepherosa Ziehau int i; 1310d217d4d9SSepherosa Ziehau 1311d217d4d9SSepherosa Ziehau for (i = 0; i < ET_TX_NDESC; ++i) { 1312d217d4d9SSepherosa Ziehau struct et_txbuf *tb = &tbd->tbd_buf[i]; 1313d217d4d9SSepherosa Ziehau 1314d217d4d9SSepherosa Ziehau if (tb->tb_mbuf != NULL) { 13150fe5209eSSepherosa Ziehau bus_dmamap_unload(sc->sc_txbuf_dtag, tb->tb_dmap); 1316d217d4d9SSepherosa Ziehau m_freem(tb->tb_mbuf); 1317d217d4d9SSepherosa Ziehau tb->tb_mbuf = NULL; 1318d217d4d9SSepherosa Ziehau } 1319d217d4d9SSepherosa Ziehau } 1320d217d4d9SSepherosa Ziehau bzero(tx_ring->tr_desc, ET_TX_RING_SIZE); 1321d217d4d9SSepherosa Ziehau } 1322d217d4d9SSepherosa Ziehau 1323d217d4d9SSepherosa Ziehau static void 1324d217d4d9SSepherosa Ziehau et_free_rx_ring(struct et_softc *sc) 1325d217d4d9SSepherosa Ziehau { 1326d217d4d9SSepherosa Ziehau int n; 1327d217d4d9SSepherosa Ziehau 1328d217d4d9SSepherosa Ziehau for (n = 0; n < ET_RX_NRING; ++n) { 1329d217d4d9SSepherosa Ziehau struct et_rxbuf_data *rbd = &sc->sc_rx_data[n]; 1330d217d4d9SSepherosa Ziehau struct et_rxdesc_ring *rx_ring = &sc->sc_rx_ring[n]; 1331d217d4d9SSepherosa Ziehau int i; 1332d217d4d9SSepherosa Ziehau 1333d217d4d9SSepherosa Ziehau for (i = 0; i < ET_RX_NDESC; ++i) { 1334d217d4d9SSepherosa Ziehau struct et_rxbuf *rb = &rbd->rbd_buf[i]; 1335d217d4d9SSepherosa Ziehau 1336d217d4d9SSepherosa Ziehau if (rb->rb_mbuf != NULL) { 13373effc1bfSSepherosa Ziehau if (!rbd->rbd_jumbo) { 13380fe5209eSSepherosa Ziehau bus_dmamap_unload(sc->sc_rxbuf_dtag, 1339d217d4d9SSepherosa Ziehau rb->rb_dmap); 13403effc1bfSSepherosa Ziehau } 1341d217d4d9SSepherosa Ziehau m_freem(rb->rb_mbuf); 1342d217d4d9SSepherosa Ziehau rb->rb_mbuf = NULL; 1343d217d4d9SSepherosa Ziehau } 1344d217d4d9SSepherosa Ziehau } 1345d217d4d9SSepherosa Ziehau bzero(rx_ring->rr_desc, ET_RX_RING_SIZE); 1346d217d4d9SSepherosa Ziehau } 1347d217d4d9SSepherosa Ziehau } 1348d217d4d9SSepherosa Ziehau 1349d217d4d9SSepherosa Ziehau static void 1350d217d4d9SSepherosa Ziehau et_setmulti(struct et_softc *sc) 1351d217d4d9SSepherosa Ziehau { 1352d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1353d217d4d9SSepherosa Ziehau uint32_t hash[4] = { 0, 0, 0, 0 }; 1354d217d4d9SSepherosa Ziehau uint32_t rxmac_ctrl, pktfilt; 1355d217d4d9SSepherosa Ziehau struct ifmultiaddr *ifma; 1356d217d4d9SSepherosa Ziehau int i, count; 1357d217d4d9SSepherosa Ziehau 1358d217d4d9SSepherosa Ziehau pktfilt = CSR_READ_4(sc, ET_PKTFILT); 1359d217d4d9SSepherosa Ziehau rxmac_ctrl = CSR_READ_4(sc, ET_RXMAC_CTRL); 1360d217d4d9SSepherosa Ziehau 1361d217d4d9SSepherosa Ziehau pktfilt &= ~(ET_PKTFILT_BCAST | ET_PKTFILT_MCAST | ET_PKTFILT_UCAST); 1362d217d4d9SSepherosa Ziehau if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) { 1363d217d4d9SSepherosa Ziehau rxmac_ctrl |= ET_RXMAC_CTRL_NO_PKTFILT; 1364d217d4d9SSepherosa Ziehau goto back; 1365d217d4d9SSepherosa Ziehau } 1366d217d4d9SSepherosa Ziehau 1367d217d4d9SSepherosa Ziehau count = 0; 1368441d34b2SSascha Wildner TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1369d217d4d9SSepherosa Ziehau uint32_t *hp, h; 1370d217d4d9SSepherosa Ziehau 1371d217d4d9SSepherosa Ziehau if (ifma->ifma_addr->sa_family != AF_LINK) 1372d217d4d9SSepherosa Ziehau continue; 1373d217d4d9SSepherosa Ziehau 1374d217d4d9SSepherosa Ziehau h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 1375d217d4d9SSepherosa Ziehau ifma->ifma_addr), ETHER_ADDR_LEN); 1376d217d4d9SSepherosa Ziehau h = (h & 0x3f800000) >> 23; 1377d217d4d9SSepherosa Ziehau 1378d217d4d9SSepherosa Ziehau hp = &hash[0]; 1379d217d4d9SSepherosa Ziehau if (h >= 32 && h < 64) { 1380d217d4d9SSepherosa Ziehau h -= 32; 1381d217d4d9SSepherosa Ziehau hp = &hash[1]; 1382d217d4d9SSepherosa Ziehau } else if (h >= 64 && h < 96) { 1383d217d4d9SSepherosa Ziehau h -= 64; 1384d217d4d9SSepherosa Ziehau hp = &hash[2]; 1385d217d4d9SSepherosa Ziehau } else if (h >= 96) { 1386d217d4d9SSepherosa Ziehau h -= 96; 1387d217d4d9SSepherosa Ziehau hp = &hash[3]; 1388d217d4d9SSepherosa Ziehau } 1389d217d4d9SSepherosa Ziehau *hp |= (1 << h); 1390d217d4d9SSepherosa Ziehau 1391d217d4d9SSepherosa Ziehau ++count; 1392d217d4d9SSepherosa Ziehau } 1393d217d4d9SSepherosa Ziehau 1394d217d4d9SSepherosa Ziehau for (i = 0; i < 4; ++i) 1395d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MULTI_HASH + (i * 4), hash[i]); 1396d217d4d9SSepherosa Ziehau 1397d217d4d9SSepherosa Ziehau if (count > 0) 1398d217d4d9SSepherosa Ziehau pktfilt |= ET_PKTFILT_MCAST; 1399d217d4d9SSepherosa Ziehau rxmac_ctrl &= ~ET_RXMAC_CTRL_NO_PKTFILT; 1400d217d4d9SSepherosa Ziehau back: 1401d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_PKTFILT, pktfilt); 1402d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXMAC_CTRL, rxmac_ctrl); 1403d217d4d9SSepherosa Ziehau } 1404d217d4d9SSepherosa Ziehau 1405d217d4d9SSepherosa Ziehau static int 1406d217d4d9SSepherosa Ziehau et_chip_init(struct et_softc *sc) 1407d217d4d9SSepherosa Ziehau { 1408d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1409d217d4d9SSepherosa Ziehau uint32_t rxq_end; 14103effc1bfSSepherosa Ziehau int error, frame_len, rxmem_size; 1411d217d4d9SSepherosa Ziehau 1412d217d4d9SSepherosa Ziehau /* 14133effc1bfSSepherosa Ziehau * Split 16Kbytes internal memory between TX and RX 14143effc1bfSSepherosa Ziehau * according to frame length. 1415d217d4d9SSepherosa Ziehau */ 14163effc1bfSSepherosa Ziehau frame_len = ET_FRAMELEN(ifp->if_mtu); 14173effc1bfSSepherosa Ziehau if (frame_len < 2048) { 14183effc1bfSSepherosa Ziehau rxmem_size = ET_MEM_RXSIZE_DEFAULT; 14193effc1bfSSepherosa Ziehau } else if (frame_len <= ET_RXMAC_CUT_THRU_FRMLEN) { 14203effc1bfSSepherosa Ziehau rxmem_size = ET_MEM_SIZE / 2; 14213effc1bfSSepherosa Ziehau } else { 14223effc1bfSSepherosa Ziehau rxmem_size = ET_MEM_SIZE - 14233effc1bfSSepherosa Ziehau roundup(frame_len + ET_MEM_TXSIZE_EX, ET_MEM_UNIT); 14243effc1bfSSepherosa Ziehau } 14253effc1bfSSepherosa Ziehau rxq_end = ET_QUEUE_ADDR(rxmem_size); 14263effc1bfSSepherosa Ziehau 14273effc1bfSSepherosa Ziehau CSR_WRITE_4(sc, ET_RXQUEUE_START, ET_QUEUE_ADDR_START); 14283effc1bfSSepherosa Ziehau CSR_WRITE_4(sc, ET_RXQUEUE_END, rxq_end); 14293effc1bfSSepherosa Ziehau CSR_WRITE_4(sc, ET_TXQUEUE_START, rxq_end + 1); 14303effc1bfSSepherosa Ziehau CSR_WRITE_4(sc, ET_TXQUEUE_END, ET_QUEUE_ADDR_END); 1431d217d4d9SSepherosa Ziehau 1432d217d4d9SSepherosa Ziehau /* No loopback */ 1433d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_LOOPBACK, 0); 1434d217d4d9SSepherosa Ziehau 1435d217d4d9SSepherosa Ziehau /* Clear MSI configure */ 1436d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MSI_CFG, 0); 1437d217d4d9SSepherosa Ziehau 1438d217d4d9SSepherosa Ziehau /* Disable timer */ 1439d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TIMER, 0); 1440d217d4d9SSepherosa Ziehau 1441d217d4d9SSepherosa Ziehau /* Initialize MAC */ 1442d217d4d9SSepherosa Ziehau et_init_mac(sc); 1443d217d4d9SSepherosa Ziehau 1444d217d4d9SSepherosa Ziehau /* Enable memory controllers */ 1445d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MMC_CTRL, ET_MMC_CTRL_ENABLE); 1446d217d4d9SSepherosa Ziehau 1447d217d4d9SSepherosa Ziehau /* Initialize RX MAC */ 1448d217d4d9SSepherosa Ziehau et_init_rxmac(sc); 1449d217d4d9SSepherosa Ziehau 1450d217d4d9SSepherosa Ziehau /* Initialize TX MAC */ 1451d217d4d9SSepherosa Ziehau et_init_txmac(sc); 1452d217d4d9SSepherosa Ziehau 1453d217d4d9SSepherosa Ziehau /* Initialize RX DMA engine */ 1454d217d4d9SSepherosa Ziehau error = et_init_rxdma(sc); 1455d217d4d9SSepherosa Ziehau if (error) 1456d217d4d9SSepherosa Ziehau return error; 1457d217d4d9SSepherosa Ziehau 1458d217d4d9SSepherosa Ziehau /* Initialize TX DMA engine */ 1459d217d4d9SSepherosa Ziehau error = et_init_txdma(sc); 1460d217d4d9SSepherosa Ziehau if (error) 1461d217d4d9SSepherosa Ziehau return error; 1462d217d4d9SSepherosa Ziehau 1463d217d4d9SSepherosa Ziehau return 0; 1464d217d4d9SSepherosa Ziehau } 1465d217d4d9SSepherosa Ziehau 1466d217d4d9SSepherosa Ziehau static int 1467d217d4d9SSepherosa Ziehau et_init_tx_ring(struct et_softc *sc) 1468d217d4d9SSepherosa Ziehau { 1469d217d4d9SSepherosa Ziehau struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 1470d217d4d9SSepherosa Ziehau struct et_txstatus_data *txsd = &sc->sc_tx_status; 1471d217d4d9SSepherosa Ziehau struct et_txbuf_data *tbd = &sc->sc_tx_data; 1472d217d4d9SSepherosa Ziehau 1473d217d4d9SSepherosa Ziehau bzero(tx_ring->tr_desc, ET_TX_RING_SIZE); 1474d217d4d9SSepherosa Ziehau 1475d217d4d9SSepherosa Ziehau tbd->tbd_start_index = 0; 1476d217d4d9SSepherosa Ziehau tbd->tbd_start_wrap = 0; 1477d217d4d9SSepherosa Ziehau tbd->tbd_used = 0; 1478d217d4d9SSepherosa Ziehau 1479d217d4d9SSepherosa Ziehau bzero(txsd->txsd_status, sizeof(uint32_t)); 1480c2ebe33eSSepherosa Ziehau 1481d217d4d9SSepherosa Ziehau return 0; 1482d217d4d9SSepherosa Ziehau } 1483d217d4d9SSepherosa Ziehau 1484d217d4d9SSepherosa Ziehau static int 1485d217d4d9SSepherosa Ziehau et_init_rx_ring(struct et_softc *sc) 1486d217d4d9SSepherosa Ziehau { 1487d217d4d9SSepherosa Ziehau struct et_rxstatus_data *rxsd = &sc->sc_rx_status; 1488d217d4d9SSepherosa Ziehau struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring; 1489d217d4d9SSepherosa Ziehau int n; 1490d217d4d9SSepherosa Ziehau 1491d217d4d9SSepherosa Ziehau for (n = 0; n < ET_RX_NRING; ++n) { 1492d217d4d9SSepherosa Ziehau struct et_rxbuf_data *rbd = &sc->sc_rx_data[n]; 1493d217d4d9SSepherosa Ziehau int i, error; 1494d217d4d9SSepherosa Ziehau 1495d217d4d9SSepherosa Ziehau for (i = 0; i < ET_RX_NDESC; ++i) { 1496d217d4d9SSepherosa Ziehau error = rbd->rbd_newbuf(rbd, i, 1); 1497d217d4d9SSepherosa Ziehau if (error) { 1498d217d4d9SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "%d ring %d buf, " 1499d217d4d9SSepherosa Ziehau "newbuf failed: %d\n", n, i, error); 1500d217d4d9SSepherosa Ziehau return error; 1501d217d4d9SSepherosa Ziehau } 1502d217d4d9SSepherosa Ziehau } 1503d217d4d9SSepherosa Ziehau } 1504d217d4d9SSepherosa Ziehau 1505d217d4d9SSepherosa Ziehau bzero(rxsd->rxsd_status, sizeof(struct et_rxstatus)); 1506d217d4d9SSepherosa Ziehau bzero(rxst_ring->rsr_stat, ET_RXSTAT_RING_SIZE); 1507d217d4d9SSepherosa Ziehau 1508d217d4d9SSepherosa Ziehau return 0; 1509d217d4d9SSepherosa Ziehau } 1510d217d4d9SSepherosa Ziehau 1511d217d4d9SSepherosa Ziehau static int 1512d217d4d9SSepherosa Ziehau et_init_rxdma(struct et_softc *sc) 1513d217d4d9SSepherosa Ziehau { 1514d217d4d9SSepherosa Ziehau struct et_rxstatus_data *rxsd = &sc->sc_rx_status; 1515d217d4d9SSepherosa Ziehau struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring; 1516d217d4d9SSepherosa Ziehau struct et_rxdesc_ring *rx_ring; 1517d217d4d9SSepherosa Ziehau int error; 1518d217d4d9SSepherosa Ziehau 1519d217d4d9SSepherosa Ziehau error = et_stop_rxdma(sc); 1520d217d4d9SSepherosa Ziehau if (error) { 1521d217d4d9SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "can't init RX DMA engine\n"); 1522d217d4d9SSepherosa Ziehau return error; 1523d217d4d9SSepherosa Ziehau } 1524d217d4d9SSepherosa Ziehau 1525d217d4d9SSepherosa Ziehau /* 1526d217d4d9SSepherosa Ziehau * Install RX status 1527d217d4d9SSepherosa Ziehau */ 1528d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_STATUS_HI, ET_ADDR_HI(rxsd->rxsd_paddr)); 1529d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_STATUS_LO, ET_ADDR_LO(rxsd->rxsd_paddr)); 1530d217d4d9SSepherosa Ziehau 1531d217d4d9SSepherosa Ziehau /* 1532d217d4d9SSepherosa Ziehau * Install RX stat ring 1533d217d4d9SSepherosa Ziehau */ 1534d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXSTAT_HI, ET_ADDR_HI(rxst_ring->rsr_paddr)); 1535d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXSTAT_LO, ET_ADDR_LO(rxst_ring->rsr_paddr)); 1536d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXSTAT_CNT, ET_RX_NSTAT - 1); 1537d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXSTAT_POS, 0); 1538d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXSTAT_MINCNT, ((ET_RX_NSTAT * 15) / 100) - 1); 1539d217d4d9SSepherosa Ziehau 1540d217d4d9SSepherosa Ziehau /* Match ET_RXSTAT_POS */ 1541d217d4d9SSepherosa Ziehau rxst_ring->rsr_index = 0; 1542d217d4d9SSepherosa Ziehau rxst_ring->rsr_wrap = 0; 1543d217d4d9SSepherosa Ziehau 1544d217d4d9SSepherosa Ziehau /* 1545d217d4d9SSepherosa Ziehau * Install the 2nd RX descriptor ring 1546d217d4d9SSepherosa Ziehau */ 1547d217d4d9SSepherosa Ziehau rx_ring = &sc->sc_rx_ring[1]; 1548d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING1_HI, ET_ADDR_HI(rx_ring->rr_paddr)); 1549d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING1_LO, ET_ADDR_LO(rx_ring->rr_paddr)); 1550d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING1_CNT, ET_RX_NDESC - 1); 1551d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING1_POS, ET_RX_RING1_POS_WRAP); 1552d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING1_MINCNT, ((ET_RX_NDESC * 15) / 100) - 1); 1553d217d4d9SSepherosa Ziehau 1554d217d4d9SSepherosa Ziehau /* Match ET_RX_RING1_POS */ 1555d217d4d9SSepherosa Ziehau rx_ring->rr_index = 0; 1556d217d4d9SSepherosa Ziehau rx_ring->rr_wrap = 1; 1557d217d4d9SSepherosa Ziehau 1558d217d4d9SSepherosa Ziehau /* 1559d217d4d9SSepherosa Ziehau * Install the 1st RX descriptor ring 1560d217d4d9SSepherosa Ziehau */ 1561d217d4d9SSepherosa Ziehau rx_ring = &sc->sc_rx_ring[0]; 1562d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING0_HI, ET_ADDR_HI(rx_ring->rr_paddr)); 1563d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING0_LO, ET_ADDR_LO(rx_ring->rr_paddr)); 1564d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING0_CNT, ET_RX_NDESC - 1); 1565d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING0_POS, ET_RX_RING0_POS_WRAP); 1566d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING0_MINCNT, ((ET_RX_NDESC * 15) / 100) - 1); 1567d217d4d9SSepherosa Ziehau 1568d217d4d9SSepherosa Ziehau /* Match ET_RX_RING0_POS */ 1569d217d4d9SSepherosa Ziehau rx_ring->rr_index = 0; 1570d217d4d9SSepherosa Ziehau rx_ring->rr_wrap = 1; 1571d217d4d9SSepherosa Ziehau 1572d217d4d9SSepherosa Ziehau /* 1573d217d4d9SSepherosa Ziehau * RX intr moderation 1574d217d4d9SSepherosa Ziehau */ 1575d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_INTR_NPKTS, sc->sc_rx_intr_npkts); 1576d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_INTR_DELAY, sc->sc_rx_intr_delay); 1577d217d4d9SSepherosa Ziehau 1578d217d4d9SSepherosa Ziehau return 0; 1579d217d4d9SSepherosa Ziehau } 1580d217d4d9SSepherosa Ziehau 1581d217d4d9SSepherosa Ziehau static int 1582d217d4d9SSepherosa Ziehau et_init_txdma(struct et_softc *sc) 1583d217d4d9SSepherosa Ziehau { 1584d217d4d9SSepherosa Ziehau struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 1585d217d4d9SSepherosa Ziehau struct et_txstatus_data *txsd = &sc->sc_tx_status; 1586d217d4d9SSepherosa Ziehau int error; 1587d217d4d9SSepherosa Ziehau 1588d217d4d9SSepherosa Ziehau error = et_stop_txdma(sc); 1589d217d4d9SSepherosa Ziehau if (error) { 1590d217d4d9SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "can't init TX DMA engine\n"); 1591d217d4d9SSepherosa Ziehau return error; 1592d217d4d9SSepherosa Ziehau } 1593d217d4d9SSepherosa Ziehau 1594d217d4d9SSepherosa Ziehau /* 1595d217d4d9SSepherosa Ziehau * Install TX descriptor ring 1596d217d4d9SSepherosa Ziehau */ 1597d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TX_RING_HI, ET_ADDR_HI(tx_ring->tr_paddr)); 1598d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TX_RING_LO, ET_ADDR_LO(tx_ring->tr_paddr)); 1599d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TX_RING_CNT, ET_TX_NDESC - 1); 1600d217d4d9SSepherosa Ziehau 1601d217d4d9SSepherosa Ziehau /* 1602d217d4d9SSepherosa Ziehau * Install TX status 1603d217d4d9SSepherosa Ziehau */ 1604d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TX_STATUS_HI, ET_ADDR_HI(txsd->txsd_paddr)); 1605d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TX_STATUS_LO, ET_ADDR_LO(txsd->txsd_paddr)); 1606d217d4d9SSepherosa Ziehau 1607d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TX_READY_POS, 0); 1608d217d4d9SSepherosa Ziehau 1609d217d4d9SSepherosa Ziehau /* Match ET_TX_READY_POS */ 1610d217d4d9SSepherosa Ziehau tx_ring->tr_ready_index = 0; 1611d217d4d9SSepherosa Ziehau tx_ring->tr_ready_wrap = 0; 1612d217d4d9SSepherosa Ziehau 1613d217d4d9SSepherosa Ziehau return 0; 1614d217d4d9SSepherosa Ziehau } 1615d217d4d9SSepherosa Ziehau 1616d217d4d9SSepherosa Ziehau static void 1617d217d4d9SSepherosa Ziehau et_init_mac(struct et_softc *sc) 1618d217d4d9SSepherosa Ziehau { 1619d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1620d217d4d9SSepherosa Ziehau const uint8_t *eaddr = IF_LLADDR(ifp); 1621d217d4d9SSepherosa Ziehau uint32_t val; 1622d217d4d9SSepherosa Ziehau 1623d217d4d9SSepherosa Ziehau /* Reset MAC */ 1624d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG1, 1625d217d4d9SSepherosa Ziehau ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 1626d217d4d9SSepherosa Ziehau ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | 1627d217d4d9SSepherosa Ziehau ET_MAC_CFG1_SIM_RST | ET_MAC_CFG1_SOFT_RST); 1628d217d4d9SSepherosa Ziehau 1629d217d4d9SSepherosa Ziehau /* 1630d217d4d9SSepherosa Ziehau * Setup inter packet gap 1631d217d4d9SSepherosa Ziehau */ 1632d217d4d9SSepherosa Ziehau val = __SHIFTIN(56, ET_IPG_NONB2B_1) | 1633d217d4d9SSepherosa Ziehau __SHIFTIN(88, ET_IPG_NONB2B_2) | 1634d217d4d9SSepherosa Ziehau __SHIFTIN(80, ET_IPG_MINIFG) | 1635d217d4d9SSepherosa Ziehau __SHIFTIN(96, ET_IPG_B2B); 1636d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_IPG, val); 1637d217d4d9SSepherosa Ziehau 1638d217d4d9SSepherosa Ziehau /* 1639d217d4d9SSepherosa Ziehau * Setup half duplex mode 1640d217d4d9SSepherosa Ziehau */ 1641d217d4d9SSepherosa Ziehau val = __SHIFTIN(10, ET_MAC_HDX_ALT_BEB_TRUNC) | 1642d217d4d9SSepherosa Ziehau __SHIFTIN(15, ET_MAC_HDX_REXMIT_MAX) | 1643d217d4d9SSepherosa Ziehau __SHIFTIN(55, ET_MAC_HDX_COLLWIN) | 1644d217d4d9SSepherosa Ziehau ET_MAC_HDX_EXC_DEFER; 1645d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_HDX, val); 1646d217d4d9SSepherosa Ziehau 1647d217d4d9SSepherosa Ziehau /* Clear MAC control */ 1648d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CTRL, 0); 1649d217d4d9SSepherosa Ziehau 1650d217d4d9SSepherosa Ziehau /* Reset MII */ 1651d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_CFG, ET_MII_CFG_CLKRST); 1652d217d4d9SSepherosa Ziehau 1653d217d4d9SSepherosa Ziehau /* 1654d217d4d9SSepherosa Ziehau * Set MAC address 1655d217d4d9SSepherosa Ziehau */ 1656d217d4d9SSepherosa Ziehau val = eaddr[2] | (eaddr[3] << 8) | (eaddr[4] << 16) | (eaddr[5] << 24); 1657d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_ADDR1, val); 1658d217d4d9SSepherosa Ziehau val = (eaddr[0] << 16) | (eaddr[1] << 24); 1659d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_ADDR2, val); 1660d217d4d9SSepherosa Ziehau 1661d217d4d9SSepherosa Ziehau /* Set max frame length */ 16620fd7469eSSepherosa Ziehau CSR_WRITE_4(sc, ET_MAX_FRMLEN, ET_FRAMELEN(ifp->if_mtu)); 1663d217d4d9SSepherosa Ziehau 1664d217d4d9SSepherosa Ziehau /* Bring MAC out of reset state */ 1665d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG1, 0); 1666d217d4d9SSepherosa Ziehau } 1667d217d4d9SSepherosa Ziehau 1668d217d4d9SSepherosa Ziehau static void 1669d217d4d9SSepherosa Ziehau et_init_rxmac(struct et_softc *sc) 1670d217d4d9SSepherosa Ziehau { 1671d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1672d217d4d9SSepherosa Ziehau const uint8_t *eaddr = IF_LLADDR(ifp); 1673d217d4d9SSepherosa Ziehau uint32_t val; 1674d217d4d9SSepherosa Ziehau int i; 1675d217d4d9SSepherosa Ziehau 1676d217d4d9SSepherosa Ziehau /* Disable RX MAC and WOL */ 1677d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXMAC_CTRL, ET_RXMAC_CTRL_WOL_DISABLE); 1678d217d4d9SSepherosa Ziehau 1679d217d4d9SSepherosa Ziehau /* 1680d217d4d9SSepherosa Ziehau * Clear all WOL related registers 1681d217d4d9SSepherosa Ziehau */ 1682d217d4d9SSepherosa Ziehau for (i = 0; i < 3; ++i) 1683d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_WOL_CRC + (i * 4), 0); 1684d217d4d9SSepherosa Ziehau for (i = 0; i < 20; ++i) 1685d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_WOL_MASK + (i * 4), 0); 1686d217d4d9SSepherosa Ziehau 1687d217d4d9SSepherosa Ziehau /* 1688d217d4d9SSepherosa Ziehau * Set WOL source address. XXX is this necessary? 1689d217d4d9SSepherosa Ziehau */ 1690d217d4d9SSepherosa Ziehau val = (eaddr[2] << 24) | (eaddr[3] << 16) | (eaddr[4] << 8) | eaddr[5]; 1691d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_WOL_SA_LO, val); 1692d217d4d9SSepherosa Ziehau val = (eaddr[0] << 8) | eaddr[1]; 1693d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_WOL_SA_HI, val); 1694d217d4d9SSepherosa Ziehau 1695d217d4d9SSepherosa Ziehau /* Clear packet filters */ 1696d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_PKTFILT, 0); 1697d217d4d9SSepherosa Ziehau 1698d217d4d9SSepherosa Ziehau /* No ucast filtering */ 1699d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_UCAST_FILTADDR1, 0); 1700d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_UCAST_FILTADDR2, 0); 1701d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_UCAST_FILTADDR3, 0); 1702d217d4d9SSepherosa Ziehau 17033effc1bfSSepherosa Ziehau if (ET_FRAMELEN(ifp->if_mtu) > ET_RXMAC_CUT_THRU_FRMLEN) { 1704d217d4d9SSepherosa Ziehau /* 17053effc1bfSSepherosa Ziehau * In order to transmit jumbo packets greater than 17063effc1bfSSepherosa Ziehau * ET_RXMAC_CUT_THRU_FRMLEN bytes, the FIFO between 17073effc1bfSSepherosa Ziehau * RX MAC and RX DMA needs to be reduced in size to 17083effc1bfSSepherosa Ziehau * (ET_MEM_SIZE - ET_MEM_TXSIZE_EX - framelen). In 17093effc1bfSSepherosa Ziehau * order to implement this, we must use "cut through" 17103effc1bfSSepherosa Ziehau * mode in the RX MAC, which chops packets down into 17113effc1bfSSepherosa Ziehau * segments. In this case we selected 256 bytes, 17123effc1bfSSepherosa Ziehau * since this is the size of the PCI-Express TLP's 17133effc1bfSSepherosa Ziehau * that the ET1310 uses. 1714d217d4d9SSepherosa Ziehau */ 17153effc1bfSSepherosa Ziehau val = __SHIFTIN(ET_RXMAC_SEGSZ(256), ET_RXMAC_MC_SEGSZ_MAX) | 1716d217d4d9SSepherosa Ziehau ET_RXMAC_MC_SEGSZ_ENABLE; 1717d217d4d9SSepherosa Ziehau } else { 1718d217d4d9SSepherosa Ziehau val = 0; 1719d217d4d9SSepherosa Ziehau } 1720d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXMAC_MC_SEGSZ, val); 1721d217d4d9SSepherosa Ziehau 1722d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXMAC_MC_WATERMARK, 0); 1723d217d4d9SSepherosa Ziehau 1724d217d4d9SSepherosa Ziehau /* Initialize RX MAC management register */ 1725d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXMAC_MGT, 0); 1726d217d4d9SSepherosa Ziehau 1727d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXMAC_SPACE_AVL, 0); 1728d217d4d9SSepherosa Ziehau 1729d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXMAC_MGT, 1730d217d4d9SSepherosa Ziehau ET_RXMAC_MGT_PASS_ECRC | 1731d217d4d9SSepherosa Ziehau ET_RXMAC_MGT_PASS_ELEN | 1732d217d4d9SSepherosa Ziehau ET_RXMAC_MGT_PASS_ETRUNC | 1733d217d4d9SSepherosa Ziehau ET_RXMAC_MGT_CHECK_PKT); 1734d217d4d9SSepherosa Ziehau 1735d217d4d9SSepherosa Ziehau /* 1736d217d4d9SSepherosa Ziehau * Configure runt filtering (may not work on certain chip generation) 1737d217d4d9SSepherosa Ziehau */ 1738d217d4d9SSepherosa Ziehau val = __SHIFTIN(ETHER_MIN_LEN, ET_PKTFILT_MINLEN) | ET_PKTFILT_FRAG; 1739d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_PKTFILT, val); 1740d217d4d9SSepherosa Ziehau 1741d217d4d9SSepherosa Ziehau /* Enable RX MAC but leave WOL disabled */ 1742d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXMAC_CTRL, 1743d217d4d9SSepherosa Ziehau ET_RXMAC_CTRL_WOL_DISABLE | ET_RXMAC_CTRL_ENABLE); 1744d217d4d9SSepherosa Ziehau 1745d217d4d9SSepherosa Ziehau /* 1746d217d4d9SSepherosa Ziehau * Setup multicast hash and allmulti/promisc mode 1747d217d4d9SSepherosa Ziehau */ 1748d217d4d9SSepherosa Ziehau et_setmulti(sc); 1749d217d4d9SSepherosa Ziehau } 1750d217d4d9SSepherosa Ziehau 1751d217d4d9SSepherosa Ziehau static void 1752d217d4d9SSepherosa Ziehau et_init_txmac(struct et_softc *sc) 1753d217d4d9SSepherosa Ziehau { 1754d217d4d9SSepherosa Ziehau /* Disable TX MAC and FC(?) */ 1755d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TXMAC_CTRL, ET_TXMAC_CTRL_FC_DISABLE); 1756d217d4d9SSepherosa Ziehau 1757d217d4d9SSepherosa Ziehau /* No flow control yet */ 1758d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TXMAC_FLOWCTRL, 0); 1759d217d4d9SSepherosa Ziehau 1760d217d4d9SSepherosa Ziehau /* Enable TX MAC but leave FC(?) diabled */ 1761d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TXMAC_CTRL, 1762d217d4d9SSepherosa Ziehau ET_TXMAC_CTRL_ENABLE | ET_TXMAC_CTRL_FC_DISABLE); 1763d217d4d9SSepherosa Ziehau } 1764d217d4d9SSepherosa Ziehau 1765d217d4d9SSepherosa Ziehau static int 1766d217d4d9SSepherosa Ziehau et_start_rxdma(struct et_softc *sc) 1767d217d4d9SSepherosa Ziehau { 1768d217d4d9SSepherosa Ziehau uint32_t val = 0; 1769d217d4d9SSepherosa Ziehau 1770d217d4d9SSepherosa Ziehau val |= __SHIFTIN(sc->sc_rx_data[0].rbd_bufsize, 1771d217d4d9SSepherosa Ziehau ET_RXDMA_CTRL_RING0_SIZE) | 1772d217d4d9SSepherosa Ziehau ET_RXDMA_CTRL_RING0_ENABLE; 1773d217d4d9SSepherosa Ziehau val |= __SHIFTIN(sc->sc_rx_data[1].rbd_bufsize, 1774d217d4d9SSepherosa Ziehau ET_RXDMA_CTRL_RING1_SIZE) | 1775d217d4d9SSepherosa Ziehau ET_RXDMA_CTRL_RING1_ENABLE; 1776d217d4d9SSepherosa Ziehau 1777d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXDMA_CTRL, val); 1778d217d4d9SSepherosa Ziehau 1779d217d4d9SSepherosa Ziehau DELAY(5); 1780d217d4d9SSepherosa Ziehau 1781d217d4d9SSepherosa Ziehau if (CSR_READ_4(sc, ET_RXDMA_CTRL) & ET_RXDMA_CTRL_HALTED) { 1782d217d4d9SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "can't start RX DMA engine\n"); 1783d217d4d9SSepherosa Ziehau return ETIMEDOUT; 1784d217d4d9SSepherosa Ziehau } 1785d217d4d9SSepherosa Ziehau return 0; 1786d217d4d9SSepherosa Ziehau } 1787d217d4d9SSepherosa Ziehau 1788d217d4d9SSepherosa Ziehau static int 1789d217d4d9SSepherosa Ziehau et_start_txdma(struct et_softc *sc) 1790d217d4d9SSepherosa Ziehau { 1791d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TXDMA_CTRL, ET_TXDMA_CTRL_SINGLE_EPKT); 1792d217d4d9SSepherosa Ziehau return 0; 1793d217d4d9SSepherosa Ziehau } 1794d217d4d9SSepherosa Ziehau 1795d217d4d9SSepherosa Ziehau static int 179660d2de1fSSepherosa Ziehau et_enable_txrx(struct et_softc *sc, int media_upd) 1797d217d4d9SSepherosa Ziehau { 1798d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1799d217d4d9SSepherosa Ziehau uint32_t val; 180060d2de1fSSepherosa Ziehau int i, error; 1801d217d4d9SSepherosa Ziehau 1802d217d4d9SSepherosa Ziehau val = CSR_READ_4(sc, ET_MAC_CFG1); 1803d217d4d9SSepherosa Ziehau val |= ET_MAC_CFG1_TXEN | ET_MAC_CFG1_RXEN; 1804d217d4d9SSepherosa Ziehau val &= ~(ET_MAC_CFG1_TXFLOW | ET_MAC_CFG1_RXFLOW | 1805d217d4d9SSepherosa Ziehau ET_MAC_CFG1_LOOPBACK); 1806d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG1, val); 1807d217d4d9SSepherosa Ziehau 180860d2de1fSSepherosa Ziehau if (media_upd) 1809d217d4d9SSepherosa Ziehau et_ifmedia_upd(ifp); 181060d2de1fSSepherosa Ziehau else 181160d2de1fSSepherosa Ziehau et_setmedia(sc); 1812d217d4d9SSepherosa Ziehau 1813d217d4d9SSepherosa Ziehau #define NRETRY 100 1814d217d4d9SSepherosa Ziehau 1815d217d4d9SSepherosa Ziehau for (i = 0; i < NRETRY; ++i) { 1816d217d4d9SSepherosa Ziehau val = CSR_READ_4(sc, ET_MAC_CFG1); 1817d217d4d9SSepherosa Ziehau if ((val & (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) == 1818d217d4d9SSepherosa Ziehau (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) 1819d217d4d9SSepherosa Ziehau break; 1820d217d4d9SSepherosa Ziehau 1821d217d4d9SSepherosa Ziehau DELAY(10); 1822d217d4d9SSepherosa Ziehau } 1823d217d4d9SSepherosa Ziehau if (i == NRETRY) { 1824d217d4d9SSepherosa Ziehau if_printf(ifp, "can't enable RX/TX\n"); 182560d2de1fSSepherosa Ziehau return 0; 1826d217d4d9SSepherosa Ziehau } 18273effc1bfSSepherosa Ziehau sc->sc_flags |= ET_FLAG_TXRX_ENABLED; 1828d217d4d9SSepherosa Ziehau 1829d217d4d9SSepherosa Ziehau #undef NRETRY 183060d2de1fSSepherosa Ziehau 183160d2de1fSSepherosa Ziehau /* 183260d2de1fSSepherosa Ziehau * Start TX/RX DMA engine 183360d2de1fSSepherosa Ziehau */ 183460d2de1fSSepherosa Ziehau error = et_start_rxdma(sc); 183560d2de1fSSepherosa Ziehau if (error) 183660d2de1fSSepherosa Ziehau return error; 183760d2de1fSSepherosa Ziehau 183860d2de1fSSepherosa Ziehau error = et_start_txdma(sc); 183960d2de1fSSepherosa Ziehau if (error) 184060d2de1fSSepherosa Ziehau return error; 184160d2de1fSSepherosa Ziehau 1842d217d4d9SSepherosa Ziehau return 0; 1843d217d4d9SSepherosa Ziehau } 1844d217d4d9SSepherosa Ziehau 1845d217d4d9SSepherosa Ziehau static void 1846d217d4d9SSepherosa Ziehau et_rxeof(struct et_softc *sc) 1847d217d4d9SSepherosa Ziehau { 1848d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1849d217d4d9SSepherosa Ziehau struct et_rxstatus_data *rxsd = &sc->sc_rx_status; 1850d217d4d9SSepherosa Ziehau struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring; 1851d217d4d9SSepherosa Ziehau uint32_t rxs_stat_ring; 1852d217d4d9SSepherosa Ziehau int rxst_wrap, rxst_index; 1853d217d4d9SSepherosa Ziehau 18543effc1bfSSepherosa Ziehau if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0) 185560d2de1fSSepherosa Ziehau return; 185660d2de1fSSepherosa Ziehau 1857d217d4d9SSepherosa Ziehau rxs_stat_ring = rxsd->rxsd_status->rxs_stat_ring; 1858d217d4d9SSepherosa Ziehau rxst_wrap = (rxs_stat_ring & ET_RXS_STATRING_WRAP) ? 1 : 0; 1859d217d4d9SSepherosa Ziehau rxst_index = __SHIFTOUT(rxs_stat_ring, ET_RXS_STATRING_INDEX); 1860d217d4d9SSepherosa Ziehau 1861d217d4d9SSepherosa Ziehau while (rxst_index != rxst_ring->rsr_index || 1862d217d4d9SSepherosa Ziehau rxst_wrap != rxst_ring->rsr_wrap) { 1863d217d4d9SSepherosa Ziehau struct et_rxbuf_data *rbd; 1864d217d4d9SSepherosa Ziehau struct et_rxdesc_ring *rx_ring; 1865d217d4d9SSepherosa Ziehau struct et_rxstat *st; 1866d217d4d9SSepherosa Ziehau struct mbuf *m; 1867d217d4d9SSepherosa Ziehau int buflen, buf_idx, ring_idx; 1868d217d4d9SSepherosa Ziehau uint32_t rxstat_pos, rxring_pos; 1869d217d4d9SSepherosa Ziehau 1870d217d4d9SSepherosa Ziehau KKASSERT(rxst_ring->rsr_index < ET_RX_NSTAT); 1871d217d4d9SSepherosa Ziehau st = &rxst_ring->rsr_stat[rxst_ring->rsr_index]; 1872d217d4d9SSepherosa Ziehau 1873d217d4d9SSepherosa Ziehau buflen = __SHIFTOUT(st->rxst_info2, ET_RXST_INFO2_LEN); 1874d217d4d9SSepherosa Ziehau buf_idx = __SHIFTOUT(st->rxst_info2, ET_RXST_INFO2_BUFIDX); 1875d217d4d9SSepherosa Ziehau ring_idx = __SHIFTOUT(st->rxst_info2, ET_RXST_INFO2_RINGIDX); 1876d217d4d9SSepherosa Ziehau 1877d217d4d9SSepherosa Ziehau if (++rxst_ring->rsr_index == ET_RX_NSTAT) { 1878d217d4d9SSepherosa Ziehau rxst_ring->rsr_index = 0; 1879d217d4d9SSepherosa Ziehau rxst_ring->rsr_wrap ^= 1; 1880d217d4d9SSepherosa Ziehau } 1881d217d4d9SSepherosa Ziehau rxstat_pos = __SHIFTIN(rxst_ring->rsr_index, 1882d217d4d9SSepherosa Ziehau ET_RXSTAT_POS_INDEX); 1883d217d4d9SSepherosa Ziehau if (rxst_ring->rsr_wrap) 1884d217d4d9SSepherosa Ziehau rxstat_pos |= ET_RXSTAT_POS_WRAP; 1885d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXSTAT_POS, rxstat_pos); 1886d217d4d9SSepherosa Ziehau 1887d217d4d9SSepherosa Ziehau if (ring_idx >= ET_RX_NRING) { 1888d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 1889d217d4d9SSepherosa Ziehau if_printf(ifp, "invalid ring index %d\n", ring_idx); 1890d217d4d9SSepherosa Ziehau continue; 1891d217d4d9SSepherosa Ziehau } 1892d217d4d9SSepherosa Ziehau if (buf_idx >= ET_RX_NDESC) { 1893d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 1894d217d4d9SSepherosa Ziehau if_printf(ifp, "invalid buf index %d\n", buf_idx); 1895d217d4d9SSepherosa Ziehau continue; 1896d217d4d9SSepherosa Ziehau } 1897d217d4d9SSepherosa Ziehau 1898d217d4d9SSepherosa Ziehau rbd = &sc->sc_rx_data[ring_idx]; 18993effc1bfSSepherosa Ziehau m = rbd->rbd_buf[buf_idx].rb_mbuf; 1900d217d4d9SSepherosa Ziehau 1901d217d4d9SSepherosa Ziehau if (rbd->rbd_newbuf(rbd, buf_idx, 0) == 0) { 19020fd7469eSSepherosa Ziehau if (buflen < ETHER_CRC_LEN) { 19030fd7469eSSepherosa Ziehau m_freem(m); 1904d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 19050fd7469eSSepherosa Ziehau } else { 1906d217d4d9SSepherosa Ziehau m->m_pkthdr.len = m->m_len = buflen; 1907d217d4d9SSepherosa Ziehau m->m_pkthdr.rcvif = ifp; 1908d217d4d9SSepherosa Ziehau 19090fd7469eSSepherosa Ziehau m_adj(m, -ETHER_CRC_LEN); 19100fd7469eSSepherosa Ziehau 1911d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ipackets, 1); 1912eda7db08SSepherosa Ziehau ifp->if_input(ifp, m); 19130fd7469eSSepherosa Ziehau } 1914d217d4d9SSepherosa Ziehau } else { 1915d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 1916d217d4d9SSepherosa Ziehau } 19170fd7469eSSepherosa Ziehau m = NULL; /* Catch invalid reference */ 1918d217d4d9SSepherosa Ziehau 1919d217d4d9SSepherosa Ziehau rx_ring = &sc->sc_rx_ring[ring_idx]; 1920d217d4d9SSepherosa Ziehau 1921d217d4d9SSepherosa Ziehau if (buf_idx != rx_ring->rr_index) { 1922d217d4d9SSepherosa Ziehau if_printf(ifp, "WARNING!! ring %d, " 1923d217d4d9SSepherosa Ziehau "buf_idx %d, rr_idx %d\n", 1924d217d4d9SSepherosa Ziehau ring_idx, buf_idx, rx_ring->rr_index); 1925d217d4d9SSepherosa Ziehau } 1926d217d4d9SSepherosa Ziehau 1927d217d4d9SSepherosa Ziehau KKASSERT(rx_ring->rr_index < ET_RX_NDESC); 1928d217d4d9SSepherosa Ziehau if (++rx_ring->rr_index == ET_RX_NDESC) { 1929d217d4d9SSepherosa Ziehau rx_ring->rr_index = 0; 1930d217d4d9SSepherosa Ziehau rx_ring->rr_wrap ^= 1; 1931d217d4d9SSepherosa Ziehau } 1932d217d4d9SSepherosa Ziehau rxring_pos = __SHIFTIN(rx_ring->rr_index, ET_RX_RING_POS_INDEX); 1933d217d4d9SSepherosa Ziehau if (rx_ring->rr_wrap) 1934d217d4d9SSepherosa Ziehau rxring_pos |= ET_RX_RING_POS_WRAP; 1935d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, rx_ring->rr_posreg, rxring_pos); 1936d217d4d9SSepherosa Ziehau } 1937d217d4d9SSepherosa Ziehau } 1938d217d4d9SSepherosa Ziehau 1939d217d4d9SSepherosa Ziehau static int 1940d217d4d9SSepherosa Ziehau et_encap(struct et_softc *sc, struct mbuf **m0) 1941d217d4d9SSepherosa Ziehau { 1942d217d4d9SSepherosa Ziehau bus_dma_segment_t segs[ET_NSEG_MAX]; 1943d217d4d9SSepherosa Ziehau struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 1944d217d4d9SSepherosa Ziehau struct et_txbuf_data *tbd = &sc->sc_tx_data; 1945d217d4d9SSepherosa Ziehau struct et_txdesc *td; 1946d217d4d9SSepherosa Ziehau bus_dmamap_t map; 19477479ff0bSSepherosa Ziehau int error, maxsegs, nsegs, first_idx, last_idx, i; 1948d217d4d9SSepherosa Ziehau uint32_t tx_ready_pos, last_td_ctrl2; 1949d217d4d9SSepherosa Ziehau 1950d217d4d9SSepherosa Ziehau maxsegs = ET_TX_NDESC - tbd->tbd_used; 1951d217d4d9SSepherosa Ziehau if (maxsegs > ET_NSEG_MAX) 1952d217d4d9SSepherosa Ziehau maxsegs = ET_NSEG_MAX; 1953d217d4d9SSepherosa Ziehau KASSERT(maxsegs >= ET_NSEG_SPARE, 1954ed20d0e3SSascha Wildner ("not enough spare TX desc (%d)", maxsegs)); 1955d217d4d9SSepherosa Ziehau 1956d217d4d9SSepherosa Ziehau KKASSERT(tx_ring->tr_ready_index < ET_TX_NDESC); 1957d217d4d9SSepherosa Ziehau first_idx = tx_ring->tr_ready_index; 1958d217d4d9SSepherosa Ziehau map = tbd->tbd_buf[first_idx].tb_dmap; 1959d217d4d9SSepherosa Ziehau 19607479ff0bSSepherosa Ziehau error = bus_dmamap_load_mbuf_defrag(sc->sc_txbuf_dtag, map, m0, 19617479ff0bSSepherosa Ziehau segs, maxsegs, &nsegs, BUS_DMA_NOWAIT); 19627479ff0bSSepherosa Ziehau if (error) 1963d217d4d9SSepherosa Ziehau goto back; 19640fe5209eSSepherosa Ziehau bus_dmamap_sync(sc->sc_txbuf_dtag, map, BUS_DMASYNC_PREWRITE); 1965d217d4d9SSepherosa Ziehau 1966d217d4d9SSepherosa Ziehau last_td_ctrl2 = ET_TDCTRL2_LAST_FRAG; 19677479ff0bSSepherosa Ziehau sc->sc_tx += nsegs; 1968d217d4d9SSepherosa Ziehau if (sc->sc_tx / sc->sc_tx_intr_nsegs != sc->sc_tx_intr) { 1969d217d4d9SSepherosa Ziehau sc->sc_tx_intr = sc->sc_tx / sc->sc_tx_intr_nsegs; 1970d217d4d9SSepherosa Ziehau last_td_ctrl2 |= ET_TDCTRL2_INTR; 1971d217d4d9SSepherosa Ziehau } 1972d217d4d9SSepherosa Ziehau 1973d217d4d9SSepherosa Ziehau last_idx = -1; 19747479ff0bSSepherosa Ziehau for (i = 0; i < nsegs; ++i) { 1975d217d4d9SSepherosa Ziehau int idx; 1976d217d4d9SSepherosa Ziehau 1977d217d4d9SSepherosa Ziehau idx = (first_idx + i) % ET_TX_NDESC; 1978d217d4d9SSepherosa Ziehau td = &tx_ring->tr_desc[idx]; 1979d217d4d9SSepherosa Ziehau td->td_addr_hi = ET_ADDR_HI(segs[i].ds_addr); 1980d217d4d9SSepherosa Ziehau td->td_addr_lo = ET_ADDR_LO(segs[i].ds_addr); 1981d217d4d9SSepherosa Ziehau td->td_ctrl1 = __SHIFTIN(segs[i].ds_len, ET_TDCTRL1_LEN); 1982d217d4d9SSepherosa Ziehau 19837479ff0bSSepherosa Ziehau if (i == nsegs - 1) { /* Last frag */ 1984d217d4d9SSepherosa Ziehau td->td_ctrl2 = last_td_ctrl2; 1985d217d4d9SSepherosa Ziehau last_idx = idx; 1986d217d4d9SSepherosa Ziehau } 1987d217d4d9SSepherosa Ziehau 1988d217d4d9SSepherosa Ziehau KKASSERT(tx_ring->tr_ready_index < ET_TX_NDESC); 1989d217d4d9SSepherosa Ziehau if (++tx_ring->tr_ready_index == ET_TX_NDESC) { 1990d217d4d9SSepherosa Ziehau tx_ring->tr_ready_index = 0; 1991d217d4d9SSepherosa Ziehau tx_ring->tr_ready_wrap ^= 1; 1992d217d4d9SSepherosa Ziehau } 1993d217d4d9SSepherosa Ziehau } 1994d217d4d9SSepherosa Ziehau td = &tx_ring->tr_desc[first_idx]; 1995d217d4d9SSepherosa Ziehau td->td_ctrl2 |= ET_TDCTRL2_FIRST_FRAG; /* First frag */ 1996d217d4d9SSepherosa Ziehau 1997d217d4d9SSepherosa Ziehau KKASSERT(last_idx >= 0); 1998d217d4d9SSepherosa Ziehau tbd->tbd_buf[first_idx].tb_dmap = tbd->tbd_buf[last_idx].tb_dmap; 1999d217d4d9SSepherosa Ziehau tbd->tbd_buf[last_idx].tb_dmap = map; 20007479ff0bSSepherosa Ziehau tbd->tbd_buf[last_idx].tb_mbuf = *m0; 2001d217d4d9SSepherosa Ziehau 20027479ff0bSSepherosa Ziehau tbd->tbd_used += nsegs; 2003d217d4d9SSepherosa Ziehau KKASSERT(tbd->tbd_used <= ET_TX_NDESC); 2004d217d4d9SSepherosa Ziehau 2005d217d4d9SSepherosa Ziehau tx_ready_pos = __SHIFTIN(tx_ring->tr_ready_index, 2006d217d4d9SSepherosa Ziehau ET_TX_READY_POS_INDEX); 2007d217d4d9SSepherosa Ziehau if (tx_ring->tr_ready_wrap) 2008d217d4d9SSepherosa Ziehau tx_ready_pos |= ET_TX_READY_POS_WRAP; 2009d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TX_READY_POS, tx_ready_pos); 2010d217d4d9SSepherosa Ziehau 2011d217d4d9SSepherosa Ziehau error = 0; 2012d217d4d9SSepherosa Ziehau back: 2013d217d4d9SSepherosa Ziehau if (error) { 20147479ff0bSSepherosa Ziehau m_freem(*m0); 2015d217d4d9SSepherosa Ziehau *m0 = NULL; 2016d217d4d9SSepherosa Ziehau } 2017d217d4d9SSepherosa Ziehau return error; 2018d217d4d9SSepherosa Ziehau } 2019d217d4d9SSepherosa Ziehau 2020d217d4d9SSepherosa Ziehau static void 2021136e59ffSSepherosa Ziehau et_txeof(struct et_softc *sc, int start) 2022d217d4d9SSepherosa Ziehau { 2023d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 2024d217d4d9SSepherosa Ziehau struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 2025d217d4d9SSepherosa Ziehau struct et_txbuf_data *tbd = &sc->sc_tx_data; 2026d217d4d9SSepherosa Ziehau uint32_t tx_done; 2027d217d4d9SSepherosa Ziehau int end, wrap; 2028d217d4d9SSepherosa Ziehau 20293effc1bfSSepherosa Ziehau if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0) 203060d2de1fSSepherosa Ziehau return; 203160d2de1fSSepherosa Ziehau 2032d217d4d9SSepherosa Ziehau if (tbd->tbd_used == 0) 2033d217d4d9SSepherosa Ziehau return; 2034d217d4d9SSepherosa Ziehau 2035d217d4d9SSepherosa Ziehau tx_done = CSR_READ_4(sc, ET_TX_DONE_POS); 2036d217d4d9SSepherosa Ziehau end = __SHIFTOUT(tx_done, ET_TX_DONE_POS_INDEX); 2037d217d4d9SSepherosa Ziehau wrap = (tx_done & ET_TX_DONE_POS_WRAP) ? 1 : 0; 2038d217d4d9SSepherosa Ziehau 2039d217d4d9SSepherosa Ziehau while (tbd->tbd_start_index != end || tbd->tbd_start_wrap != wrap) { 2040d217d4d9SSepherosa Ziehau struct et_txbuf *tb; 2041d217d4d9SSepherosa Ziehau 2042d217d4d9SSepherosa Ziehau KKASSERT(tbd->tbd_start_index < ET_TX_NDESC); 2043d217d4d9SSepherosa Ziehau tb = &tbd->tbd_buf[tbd->tbd_start_index]; 2044d217d4d9SSepherosa Ziehau 2045d217d4d9SSepherosa Ziehau bzero(&tx_ring->tr_desc[tbd->tbd_start_index], 2046d217d4d9SSepherosa Ziehau sizeof(struct et_txdesc)); 2047d217d4d9SSepherosa Ziehau 2048d217d4d9SSepherosa Ziehau if (tb->tb_mbuf != NULL) { 20490fe5209eSSepherosa Ziehau bus_dmamap_unload(sc->sc_txbuf_dtag, tb->tb_dmap); 2050d217d4d9SSepherosa Ziehau m_freem(tb->tb_mbuf); 2051d217d4d9SSepherosa Ziehau tb->tb_mbuf = NULL; 2052d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, opackets, 1); 2053d217d4d9SSepherosa Ziehau } 2054d217d4d9SSepherosa Ziehau 2055d217d4d9SSepherosa Ziehau if (++tbd->tbd_start_index == ET_TX_NDESC) { 2056d217d4d9SSepherosa Ziehau tbd->tbd_start_index = 0; 2057d217d4d9SSepherosa Ziehau tbd->tbd_start_wrap ^= 1; 2058d217d4d9SSepherosa Ziehau } 2059d217d4d9SSepherosa Ziehau 2060d217d4d9SSepherosa Ziehau KKASSERT(tbd->tbd_used > 0); 2061d217d4d9SSepherosa Ziehau tbd->tbd_used--; 2062d217d4d9SSepherosa Ziehau } 2063d217d4d9SSepherosa Ziehau 2064d217d4d9SSepherosa Ziehau if (tbd->tbd_used == 0) 2065d217d4d9SSepherosa Ziehau ifp->if_timer = 0; 2066d217d4d9SSepherosa Ziehau if (tbd->tbd_used + ET_NSEG_SPARE <= ET_TX_NDESC) 20679ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 2068d217d4d9SSepherosa Ziehau 2069136e59ffSSepherosa Ziehau if (start) 20709db4b353SSepherosa Ziehau if_devstart(ifp); 2071d217d4d9SSepherosa Ziehau } 2072d217d4d9SSepherosa Ziehau 2073d217d4d9SSepherosa Ziehau static void 2074d217d4d9SSepherosa Ziehau et_tick(void *xsc) 2075d217d4d9SSepherosa Ziehau { 2076d217d4d9SSepherosa Ziehau struct et_softc *sc = xsc; 2077d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 207860d2de1fSSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->sc_miibus); 2079d217d4d9SSepherosa Ziehau 2080d217d4d9SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 2081d217d4d9SSepherosa Ziehau 208260d2de1fSSepherosa Ziehau mii_tick(mii); 20833effc1bfSSepherosa Ziehau if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0 && 20843effc1bfSSepherosa Ziehau (mii->mii_media_status & IFM_ACTIVE) && 208560d2de1fSSepherosa Ziehau IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 208660d2de1fSSepherosa Ziehau if_printf(ifp, "Link up, enable TX/RX\n"); 208760d2de1fSSepherosa Ziehau if (et_enable_txrx(sc, 0) == 0) 20889db4b353SSepherosa Ziehau if_devstart(ifp); 208960d2de1fSSepherosa Ziehau } 2090d217d4d9SSepherosa Ziehau callout_reset(&sc->sc_tick, hz, et_tick, sc); 2091d217d4d9SSepherosa Ziehau 2092d217d4d9SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 2093d217d4d9SSepherosa Ziehau } 2094d217d4d9SSepherosa Ziehau 2095d217d4d9SSepherosa Ziehau static int 2096d217d4d9SSepherosa Ziehau et_newbuf_cluster(struct et_rxbuf_data *rbd, int buf_idx, int init) 2097d217d4d9SSepherosa Ziehau { 2098d217d4d9SSepherosa Ziehau return et_newbuf(rbd, buf_idx, init, MCLBYTES); 2099d217d4d9SSepherosa Ziehau } 2100d217d4d9SSepherosa Ziehau 2101d217d4d9SSepherosa Ziehau static int 2102d217d4d9SSepherosa Ziehau et_newbuf_hdr(struct et_rxbuf_data *rbd, int buf_idx, int init) 2103d217d4d9SSepherosa Ziehau { 2104d217d4d9SSepherosa Ziehau return et_newbuf(rbd, buf_idx, init, MHLEN); 2105d217d4d9SSepherosa Ziehau } 2106d217d4d9SSepherosa Ziehau 2107d217d4d9SSepherosa Ziehau static int 2108d217d4d9SSepherosa Ziehau et_newbuf(struct et_rxbuf_data *rbd, int buf_idx, int init, int len0) 2109d217d4d9SSepherosa Ziehau { 2110d217d4d9SSepherosa Ziehau struct et_softc *sc = rbd->rbd_softc; 2111d217d4d9SSepherosa Ziehau struct et_rxbuf *rb; 2112d217d4d9SSepherosa Ziehau struct mbuf *m; 2113d217d4d9SSepherosa Ziehau bus_dma_segment_t seg; 2114d217d4d9SSepherosa Ziehau bus_dmamap_t dmap; 21157479ff0bSSepherosa Ziehau int error, len, nseg; 2116d217d4d9SSepherosa Ziehau 2117ed20d0e3SSascha Wildner KASSERT(!rbd->rbd_jumbo, ("calling %s with jumbo ring", __func__)); 21183effc1bfSSepherosa Ziehau 2119d217d4d9SSepherosa Ziehau KKASSERT(buf_idx < ET_RX_NDESC); 2120d217d4d9SSepherosa Ziehau rb = &rbd->rbd_buf[buf_idx]; 2121d217d4d9SSepherosa Ziehau 2122d217d4d9SSepherosa Ziehau m = m_getl(len0, init ? MB_WAIT : MB_DONTWAIT, MT_DATA, M_PKTHDR, &len); 2123d217d4d9SSepherosa Ziehau if (m == NULL) { 2124d217d4d9SSepherosa Ziehau error = ENOBUFS; 2125d217d4d9SSepherosa Ziehau 21260fd7469eSSepherosa Ziehau if (init) { 2127d217d4d9SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 2128d217d4d9SSepherosa Ziehau "m_getl failed, size %d\n", len0); 2129d217d4d9SSepherosa Ziehau return error; 2130d217d4d9SSepherosa Ziehau } else { 2131d217d4d9SSepherosa Ziehau goto back; 2132d217d4d9SSepherosa Ziehau } 2133d217d4d9SSepherosa Ziehau } 2134d217d4d9SSepherosa Ziehau m->m_len = m->m_pkthdr.len = len; 2135d217d4d9SSepherosa Ziehau 2136d217d4d9SSepherosa Ziehau /* 2137d217d4d9SSepherosa Ziehau * Try load RX mbuf into temporary DMA tag 2138d217d4d9SSepherosa Ziehau */ 21397479ff0bSSepherosa Ziehau error = bus_dmamap_load_mbuf_segment(sc->sc_rxbuf_dtag, 21407479ff0bSSepherosa Ziehau sc->sc_rxbuf_tmp_dmap, m, &seg, 1, &nseg, 21417479ff0bSSepherosa Ziehau BUS_DMA_NOWAIT); 21427479ff0bSSepherosa Ziehau if (error) { 2143d217d4d9SSepherosa Ziehau m_freem(m); 2144d217d4d9SSepherosa Ziehau if (init) { 21450fd7469eSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "can't load RX mbuf\n"); 2146d217d4d9SSepherosa Ziehau return error; 2147d217d4d9SSepherosa Ziehau } else { 2148d217d4d9SSepherosa Ziehau goto back; 2149d217d4d9SSepherosa Ziehau } 2150d217d4d9SSepherosa Ziehau } 2151d217d4d9SSepherosa Ziehau 21523effc1bfSSepherosa Ziehau if (!init) { 21530fe5209eSSepherosa Ziehau bus_dmamap_sync(sc->sc_rxbuf_dtag, rb->rb_dmap, 21543effc1bfSSepherosa Ziehau BUS_DMASYNC_POSTREAD); 21550fe5209eSSepherosa Ziehau bus_dmamap_unload(sc->sc_rxbuf_dtag, rb->rb_dmap); 21563effc1bfSSepherosa Ziehau } 2157d217d4d9SSepherosa Ziehau rb->rb_mbuf = m; 2158d217d4d9SSepherosa Ziehau rb->rb_paddr = seg.ds_addr; 2159d217d4d9SSepherosa Ziehau 2160d217d4d9SSepherosa Ziehau /* 2161d217d4d9SSepherosa Ziehau * Swap RX buf's DMA map with the loaded temporary one 2162d217d4d9SSepherosa Ziehau */ 2163d217d4d9SSepherosa Ziehau dmap = rb->rb_dmap; 21640fe5209eSSepherosa Ziehau rb->rb_dmap = sc->sc_rxbuf_tmp_dmap; 21650fe5209eSSepherosa Ziehau sc->sc_rxbuf_tmp_dmap = dmap; 2166d217d4d9SSepherosa Ziehau 2167d217d4d9SSepherosa Ziehau error = 0; 2168d217d4d9SSepherosa Ziehau back: 21693effc1bfSSepherosa Ziehau et_setup_rxdesc(rbd, buf_idx, rb->rb_paddr); 2170d217d4d9SSepherosa Ziehau return error; 2171d217d4d9SSepherosa Ziehau } 2172d217d4d9SSepherosa Ziehau 2173d217d4d9SSepherosa Ziehau static int 2174d217d4d9SSepherosa Ziehau et_sysctl_rx_intr_npkts(SYSCTL_HANDLER_ARGS) 2175d217d4d9SSepherosa Ziehau { 2176d217d4d9SSepherosa Ziehau struct et_softc *sc = arg1; 2177d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 2178d217d4d9SSepherosa Ziehau int error = 0, v; 2179d217d4d9SSepherosa Ziehau 2180d217d4d9SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 2181d217d4d9SSepherosa Ziehau 2182d217d4d9SSepherosa Ziehau v = sc->sc_rx_intr_npkts; 2183d217d4d9SSepherosa Ziehau error = sysctl_handle_int(oidp, &v, 0, req); 2184d217d4d9SSepherosa Ziehau if (error || req->newptr == NULL) 2185d217d4d9SSepherosa Ziehau goto back; 2186d217d4d9SSepherosa Ziehau if (v <= 0) { 2187d217d4d9SSepherosa Ziehau error = EINVAL; 2188d217d4d9SSepherosa Ziehau goto back; 2189d217d4d9SSepherosa Ziehau } 2190d217d4d9SSepherosa Ziehau 2191d217d4d9SSepherosa Ziehau if (sc->sc_rx_intr_npkts != v) { 2192d217d4d9SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 2193d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_INTR_NPKTS, v); 2194d217d4d9SSepherosa Ziehau sc->sc_rx_intr_npkts = v; 2195d217d4d9SSepherosa Ziehau } 2196d217d4d9SSepherosa Ziehau back: 2197d217d4d9SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 2198d217d4d9SSepherosa Ziehau return error; 2199d217d4d9SSepherosa Ziehau } 2200d217d4d9SSepherosa Ziehau 2201d217d4d9SSepherosa Ziehau static int 2202d217d4d9SSepherosa Ziehau et_sysctl_rx_intr_delay(SYSCTL_HANDLER_ARGS) 2203d217d4d9SSepherosa Ziehau { 2204d217d4d9SSepherosa Ziehau struct et_softc *sc = arg1; 2205d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 2206d217d4d9SSepherosa Ziehau int error = 0, v; 2207d217d4d9SSepherosa Ziehau 2208d217d4d9SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 2209d217d4d9SSepherosa Ziehau 2210d217d4d9SSepherosa Ziehau v = sc->sc_rx_intr_delay; 2211d217d4d9SSepherosa Ziehau error = sysctl_handle_int(oidp, &v, 0, req); 2212d217d4d9SSepherosa Ziehau if (error || req->newptr == NULL) 2213d217d4d9SSepherosa Ziehau goto back; 2214d217d4d9SSepherosa Ziehau if (v <= 0) { 2215d217d4d9SSepherosa Ziehau error = EINVAL; 2216d217d4d9SSepherosa Ziehau goto back; 2217d217d4d9SSepherosa Ziehau } 2218d217d4d9SSepherosa Ziehau 2219d217d4d9SSepherosa Ziehau if (sc->sc_rx_intr_delay != v) { 2220d217d4d9SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 2221d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_INTR_DELAY, v); 2222d217d4d9SSepherosa Ziehau sc->sc_rx_intr_delay = v; 2223d217d4d9SSepherosa Ziehau } 2224d217d4d9SSepherosa Ziehau back: 2225d217d4d9SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 2226d217d4d9SSepherosa Ziehau return error; 2227d217d4d9SSepherosa Ziehau } 222860d2de1fSSepherosa Ziehau 222960d2de1fSSepherosa Ziehau static void 223060d2de1fSSepherosa Ziehau et_setmedia(struct et_softc *sc) 223160d2de1fSSepherosa Ziehau { 223260d2de1fSSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->sc_miibus); 223360d2de1fSSepherosa Ziehau uint32_t cfg2, ctrl; 223460d2de1fSSepherosa Ziehau 223560d2de1fSSepherosa Ziehau cfg2 = CSR_READ_4(sc, ET_MAC_CFG2); 223660d2de1fSSepherosa Ziehau cfg2 &= ~(ET_MAC_CFG2_MODE_MII | ET_MAC_CFG2_MODE_GMII | 223760d2de1fSSepherosa Ziehau ET_MAC_CFG2_FDX | ET_MAC_CFG2_BIGFRM); 223860d2de1fSSepherosa Ziehau cfg2 |= ET_MAC_CFG2_LENCHK | ET_MAC_CFG2_CRC | ET_MAC_CFG2_PADCRC | 223960d2de1fSSepherosa Ziehau __SHIFTIN(7, ET_MAC_CFG2_PREAMBLE_LEN); 224060d2de1fSSepherosa Ziehau 224160d2de1fSSepherosa Ziehau ctrl = CSR_READ_4(sc, ET_MAC_CTRL); 224260d2de1fSSepherosa Ziehau ctrl &= ~(ET_MAC_CTRL_GHDX | ET_MAC_CTRL_MODE_MII); 224360d2de1fSSepherosa Ziehau 224460d2de1fSSepherosa Ziehau if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { 224560d2de1fSSepherosa Ziehau cfg2 |= ET_MAC_CFG2_MODE_GMII; 224660d2de1fSSepherosa Ziehau } else { 224760d2de1fSSepherosa Ziehau cfg2 |= ET_MAC_CFG2_MODE_MII; 224860d2de1fSSepherosa Ziehau ctrl |= ET_MAC_CTRL_MODE_MII; 224960d2de1fSSepherosa Ziehau } 225060d2de1fSSepherosa Ziehau 225160d2de1fSSepherosa Ziehau if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) 225260d2de1fSSepherosa Ziehau cfg2 |= ET_MAC_CFG2_FDX; 225360d2de1fSSepherosa Ziehau else 225460d2de1fSSepherosa Ziehau ctrl |= ET_MAC_CTRL_GHDX; 225560d2de1fSSepherosa Ziehau 225660d2de1fSSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CTRL, ctrl); 225760d2de1fSSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG2, cfg2); 225860d2de1fSSepherosa Ziehau } 22593effc1bfSSepherosa Ziehau 22603effc1bfSSepherosa Ziehau static int 22613effc1bfSSepherosa Ziehau et_jumbo_mem_alloc(device_t dev) 22623effc1bfSSepherosa Ziehau { 22633effc1bfSSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 22643effc1bfSSepherosa Ziehau struct et_jumbo_data *jd = &sc->sc_jumbo_data; 22653effc1bfSSepherosa Ziehau bus_addr_t paddr; 22663effc1bfSSepherosa Ziehau uint8_t *buf; 2267c7f73cc7SSepherosa Ziehau int i; 22683effc1bfSSepherosa Ziehau 2269c7f73cc7SSepherosa Ziehau jd->jd_buf = bus_dmamem_coherent_any(sc->sc_dtag, 2270c2ebe33eSSepherosa Ziehau ET_JUMBO_ALIGN, ET_JUMBO_MEM_SIZE, BUS_DMA_WAITOK, 2271c7f73cc7SSepherosa Ziehau &jd->jd_dtag, &jd->jd_dmap, &paddr); 2272c7f73cc7SSepherosa Ziehau if (jd->jd_buf == NULL) { 22733effc1bfSSepherosa Ziehau device_printf(dev, "can't create jumbo DMA stuffs\n"); 2274c7f73cc7SSepherosa Ziehau return ENOMEM; 22753effc1bfSSepherosa Ziehau } 22763effc1bfSSepherosa Ziehau 22773effc1bfSSepherosa Ziehau jd->jd_slots = kmalloc(sizeof(*jd->jd_slots) * ET_JSLOTS, M_DEVBUF, 22783effc1bfSSepherosa Ziehau M_WAITOK | M_ZERO); 22793effc1bfSSepherosa Ziehau lwkt_serialize_init(&jd->jd_serializer); 22803effc1bfSSepherosa Ziehau SLIST_INIT(&jd->jd_free_slots); 22813effc1bfSSepherosa Ziehau 22823effc1bfSSepherosa Ziehau buf = jd->jd_buf; 22833effc1bfSSepherosa Ziehau for (i = 0; i < ET_JSLOTS; ++i) { 22843effc1bfSSepherosa Ziehau struct et_jslot *jslot = &jd->jd_slots[i]; 22853effc1bfSSepherosa Ziehau 22863effc1bfSSepherosa Ziehau jslot->jslot_data = jd; 22873effc1bfSSepherosa Ziehau jslot->jslot_buf = buf; 22883effc1bfSSepherosa Ziehau jslot->jslot_paddr = paddr; 22893effc1bfSSepherosa Ziehau jslot->jslot_inuse = 0; 22903effc1bfSSepherosa Ziehau jslot->jslot_index = i; 22913effc1bfSSepherosa Ziehau SLIST_INSERT_HEAD(&jd->jd_free_slots, jslot, jslot_link); 22923effc1bfSSepherosa Ziehau 22933effc1bfSSepherosa Ziehau buf += ET_JLEN; 22943effc1bfSSepherosa Ziehau paddr += ET_JLEN; 22953effc1bfSSepherosa Ziehau } 22963effc1bfSSepherosa Ziehau return 0; 22973effc1bfSSepherosa Ziehau } 22983effc1bfSSepherosa Ziehau 22993effc1bfSSepherosa Ziehau static void 23003effc1bfSSepherosa Ziehau et_jumbo_mem_free(device_t dev) 23013effc1bfSSepherosa Ziehau { 23023effc1bfSSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 23033effc1bfSSepherosa Ziehau struct et_jumbo_data *jd = &sc->sc_jumbo_data; 23043effc1bfSSepherosa Ziehau 23053effc1bfSSepherosa Ziehau KKASSERT(sc->sc_flags & ET_FLAG_JUMBO); 23063effc1bfSSepherosa Ziehau 23073effc1bfSSepherosa Ziehau kfree(jd->jd_slots, M_DEVBUF); 23083effc1bfSSepherosa Ziehau et_dma_mem_destroy(jd->jd_dtag, jd->jd_buf, jd->jd_dmap); 23093effc1bfSSepherosa Ziehau } 23103effc1bfSSepherosa Ziehau 23113effc1bfSSepherosa Ziehau static struct et_jslot * 23123effc1bfSSepherosa Ziehau et_jalloc(struct et_jumbo_data *jd) 23133effc1bfSSepherosa Ziehau { 23143effc1bfSSepherosa Ziehau struct et_jslot *jslot; 23153effc1bfSSepherosa Ziehau 23163effc1bfSSepherosa Ziehau lwkt_serialize_enter(&jd->jd_serializer); 23173effc1bfSSepherosa Ziehau 23183effc1bfSSepherosa Ziehau jslot = SLIST_FIRST(&jd->jd_free_slots); 23193effc1bfSSepherosa Ziehau if (jslot) { 23203effc1bfSSepherosa Ziehau SLIST_REMOVE_HEAD(&jd->jd_free_slots, jslot_link); 23213effc1bfSSepherosa Ziehau jslot->jslot_inuse = 1; 23223effc1bfSSepherosa Ziehau } 23233effc1bfSSepherosa Ziehau 23243effc1bfSSepherosa Ziehau lwkt_serialize_exit(&jd->jd_serializer); 23253effc1bfSSepherosa Ziehau return jslot; 23263effc1bfSSepherosa Ziehau } 23273effc1bfSSepherosa Ziehau 23283effc1bfSSepherosa Ziehau static void 23293effc1bfSSepherosa Ziehau et_jfree(void *xjslot) 23303effc1bfSSepherosa Ziehau { 23313effc1bfSSepherosa Ziehau struct et_jslot *jslot = xjslot; 23323effc1bfSSepherosa Ziehau struct et_jumbo_data *jd = jslot->jslot_data; 23333effc1bfSSepherosa Ziehau 23343effc1bfSSepherosa Ziehau if (&jd->jd_slots[jslot->jslot_index] != jslot) { 2335ed20d0e3SSascha Wildner panic("%s wrong jslot!?", __func__); 23363effc1bfSSepherosa Ziehau } else if (jslot->jslot_inuse == 0) { 2337ed20d0e3SSascha Wildner panic("%s jslot already freed", __func__); 23383effc1bfSSepherosa Ziehau } else { 23393effc1bfSSepherosa Ziehau lwkt_serialize_enter(&jd->jd_serializer); 23403effc1bfSSepherosa Ziehau 23413effc1bfSSepherosa Ziehau atomic_subtract_int(&jslot->jslot_inuse, 1); 23423effc1bfSSepherosa Ziehau if (jslot->jslot_inuse == 0) { 23433effc1bfSSepherosa Ziehau SLIST_INSERT_HEAD(&jd->jd_free_slots, jslot, 23443effc1bfSSepherosa Ziehau jslot_link); 23453effc1bfSSepherosa Ziehau } 23463effc1bfSSepherosa Ziehau 23473effc1bfSSepherosa Ziehau lwkt_serialize_exit(&jd->jd_serializer); 23483effc1bfSSepherosa Ziehau } 23493effc1bfSSepherosa Ziehau } 23503effc1bfSSepherosa Ziehau 23513effc1bfSSepherosa Ziehau static void 23523effc1bfSSepherosa Ziehau et_jref(void *xjslot) 23533effc1bfSSepherosa Ziehau { 23543effc1bfSSepherosa Ziehau struct et_jslot *jslot = xjslot; 23553effc1bfSSepherosa Ziehau struct et_jumbo_data *jd = jslot->jslot_data; 23563effc1bfSSepherosa Ziehau 23573effc1bfSSepherosa Ziehau if (&jd->jd_slots[jslot->jslot_index] != jslot) 2358ed20d0e3SSascha Wildner panic("%s wrong jslot!?", __func__); 23593effc1bfSSepherosa Ziehau else if (jslot->jslot_inuse == 0) 2360ed20d0e3SSascha Wildner panic("%s jslot already freed", __func__); 23613effc1bfSSepherosa Ziehau else 23623effc1bfSSepherosa Ziehau atomic_add_int(&jslot->jslot_inuse, 1); 23633effc1bfSSepherosa Ziehau } 23643effc1bfSSepherosa Ziehau 23653effc1bfSSepherosa Ziehau static int 23663effc1bfSSepherosa Ziehau et_newbuf_jumbo(struct et_rxbuf_data *rbd, int buf_idx, int init) 23673effc1bfSSepherosa Ziehau { 23683effc1bfSSepherosa Ziehau struct et_softc *sc = rbd->rbd_softc; 23693effc1bfSSepherosa Ziehau struct et_rxbuf *rb; 23703effc1bfSSepherosa Ziehau struct mbuf *m; 23713effc1bfSSepherosa Ziehau struct et_jslot *jslot; 23723effc1bfSSepherosa Ziehau int error; 23733effc1bfSSepherosa Ziehau 2374ed20d0e3SSascha Wildner KASSERT(rbd->rbd_jumbo, ("calling %s with non-jumbo ring", __func__)); 23753effc1bfSSepherosa Ziehau 23763effc1bfSSepherosa Ziehau KKASSERT(buf_idx < ET_RX_NDESC); 23773effc1bfSSepherosa Ziehau rb = &rbd->rbd_buf[buf_idx]; 23783effc1bfSSepherosa Ziehau 23793effc1bfSSepherosa Ziehau error = ENOBUFS; 23803effc1bfSSepherosa Ziehau 23813effc1bfSSepherosa Ziehau MGETHDR(m, init ? MB_WAIT : MB_DONTWAIT, MT_DATA); 23823effc1bfSSepherosa Ziehau if (m == NULL) { 23833effc1bfSSepherosa Ziehau if (init) { 23843effc1bfSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "MGETHDR failed\n"); 23853effc1bfSSepherosa Ziehau return error; 23863effc1bfSSepherosa Ziehau } else { 23873effc1bfSSepherosa Ziehau goto back; 23883effc1bfSSepherosa Ziehau } 23893effc1bfSSepherosa Ziehau } 23903effc1bfSSepherosa Ziehau 23913effc1bfSSepherosa Ziehau jslot = et_jalloc(&sc->sc_jumbo_data); 23923effc1bfSSepherosa Ziehau if (jslot == NULL) { 23933effc1bfSSepherosa Ziehau m_freem(m); 23943effc1bfSSepherosa Ziehau 23953effc1bfSSepherosa Ziehau if (init) { 23963effc1bfSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 23973effc1bfSSepherosa Ziehau "jslot allocation failed\n"); 23983effc1bfSSepherosa Ziehau return error; 23993effc1bfSSepherosa Ziehau } else { 24003effc1bfSSepherosa Ziehau goto back; 24013effc1bfSSepherosa Ziehau } 24023effc1bfSSepherosa Ziehau } 24033effc1bfSSepherosa Ziehau 24043effc1bfSSepherosa Ziehau m->m_ext.ext_arg = jslot; 24053effc1bfSSepherosa Ziehau m->m_ext.ext_buf = jslot->jslot_buf; 24063effc1bfSSepherosa Ziehau m->m_ext.ext_free = et_jfree; 24073effc1bfSSepherosa Ziehau m->m_ext.ext_ref = et_jref; 24083effc1bfSSepherosa Ziehau m->m_ext.ext_size = ET_JUMBO_FRAMELEN; 24093effc1bfSSepherosa Ziehau m->m_flags |= M_EXT; 24103effc1bfSSepherosa Ziehau m->m_data = m->m_ext.ext_buf; 24113effc1bfSSepherosa Ziehau m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; 24123effc1bfSSepherosa Ziehau 24133effc1bfSSepherosa Ziehau rb->rb_mbuf = m; 24143effc1bfSSepherosa Ziehau rb->rb_paddr = jslot->jslot_paddr; 24153effc1bfSSepherosa Ziehau 24163effc1bfSSepherosa Ziehau error = 0; 24173effc1bfSSepherosa Ziehau back: 24183effc1bfSSepherosa Ziehau et_setup_rxdesc(rbd, buf_idx, rb->rb_paddr); 24193effc1bfSSepherosa Ziehau return error; 24203effc1bfSSepherosa Ziehau } 24213effc1bfSSepherosa Ziehau 24223effc1bfSSepherosa Ziehau static void 24233effc1bfSSepherosa Ziehau et_setup_rxdesc(struct et_rxbuf_data *rbd, int buf_idx, bus_addr_t paddr) 24243effc1bfSSepherosa Ziehau { 24253effc1bfSSepherosa Ziehau struct et_rxdesc_ring *rx_ring = rbd->rbd_ring; 24263effc1bfSSepherosa Ziehau struct et_rxdesc *desc; 24273effc1bfSSepherosa Ziehau 24283effc1bfSSepherosa Ziehau KKASSERT(buf_idx < ET_RX_NDESC); 24293effc1bfSSepherosa Ziehau desc = &rx_ring->rr_desc[buf_idx]; 24303effc1bfSSepherosa Ziehau 24313effc1bfSSepherosa Ziehau desc->rd_addr_hi = ET_ADDR_HI(paddr); 24323effc1bfSSepherosa Ziehau desc->rd_addr_lo = ET_ADDR_LO(paddr); 24333effc1bfSSepherosa Ziehau desc->rd_ctrl = __SHIFTIN(buf_idx, ET_RDCTRL_BUFIDX); 24343effc1bfSSepherosa Ziehau } 2435