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 *); 80d217d4d9SSepherosa Ziehau static void et_start(struct ifnet *); 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 165d217d4d9SSepherosa Ziehau { 0, 0 } 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 186d217d4d9SSepherosa Ziehau TUNABLE_INT("hw.et.timer", &et_timer); 187d217d4d9SSepherosa Ziehau TUNABLE_INT("hw.et.rx_intr_npkts", &et_rx_intr_npkts); 188f285c685SSascha Wildner TUNABLE_INT("hw.et.rx_intr_delay", &et_rx_intr_delay); 189af6a2c2aSSascha Wildner TUNABLE_INT("hw.et.tx_intr_nsegs", &et_tx_intr_nsegs); 190d217d4d9SSepherosa Ziehau 191d217d4d9SSepherosa Ziehau struct et_bsize { 192d217d4d9SSepherosa Ziehau int bufsize; 1933effc1bfSSepherosa Ziehau int jumbo; 194d217d4d9SSepherosa Ziehau et_newbuf_t newbuf; 195d217d4d9SSepherosa Ziehau }; 196d217d4d9SSepherosa Ziehau 1973effc1bfSSepherosa Ziehau static const struct et_bsize et_bufsize_std[ET_RX_NRING] = { 1983effc1bfSSepherosa Ziehau { .bufsize = ET_RXDMA_CTRL_RING0_128, .jumbo = 0, 1993effc1bfSSepherosa Ziehau .newbuf = et_newbuf_hdr }, 2003effc1bfSSepherosa Ziehau { .bufsize = ET_RXDMA_CTRL_RING1_2048, .jumbo = 0, 2013effc1bfSSepherosa Ziehau .newbuf = et_newbuf_cluster }, 2023effc1bfSSepherosa Ziehau }; 2033effc1bfSSepherosa Ziehau 2043effc1bfSSepherosa Ziehau static const struct et_bsize et_bufsize_jumbo[ET_RX_NRING] = { 2053effc1bfSSepherosa Ziehau { .bufsize = ET_RXDMA_CTRL_RING0_128, .jumbo = 0, 2063effc1bfSSepherosa Ziehau .newbuf = et_newbuf_hdr }, 2073effc1bfSSepherosa Ziehau { .bufsize = ET_RXDMA_CTRL_RING1_16384, .jumbo = 1, 2083effc1bfSSepherosa Ziehau .newbuf = et_newbuf_jumbo }, 209d217d4d9SSepherosa Ziehau }; 210d217d4d9SSepherosa Ziehau 211d217d4d9SSepherosa Ziehau static int 212d217d4d9SSepherosa Ziehau et_probe(device_t dev) 213d217d4d9SSepherosa Ziehau { 214d217d4d9SSepherosa Ziehau const struct et_dev *d; 215d217d4d9SSepherosa Ziehau uint16_t did, vid; 216d217d4d9SSepherosa Ziehau 217d217d4d9SSepherosa Ziehau vid = pci_get_vendor(dev); 218d217d4d9SSepherosa Ziehau did = pci_get_device(dev); 219d217d4d9SSepherosa Ziehau 220d217d4d9SSepherosa Ziehau for (d = et_devices; d->desc != NULL; ++d) { 221d217d4d9SSepherosa Ziehau if (vid == d->vid && did == d->did) { 222d217d4d9SSepherosa Ziehau device_set_desc(dev, d->desc); 223d217d4d9SSepherosa Ziehau return 0; 224d217d4d9SSepherosa Ziehau } 225d217d4d9SSepherosa Ziehau } 226d217d4d9SSepherosa Ziehau return ENXIO; 227d217d4d9SSepherosa Ziehau } 228d217d4d9SSepherosa Ziehau 229d217d4d9SSepherosa Ziehau static int 230d217d4d9SSepherosa Ziehau et_attach(device_t dev) 231d217d4d9SSepherosa Ziehau { 232d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 233d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 234d217d4d9SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN]; 235d217d4d9SSepherosa Ziehau int error; 236d217d4d9SSepherosa Ziehau 237d217d4d9SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 238d217d4d9SSepherosa Ziehau callout_init(&sc->sc_tick); 239d217d4d9SSepherosa Ziehau 240d217d4d9SSepherosa Ziehau /* 241d217d4d9SSepherosa Ziehau * Initialize tunables 242d217d4d9SSepherosa Ziehau */ 243d217d4d9SSepherosa Ziehau sc->sc_rx_intr_npkts = et_rx_intr_npkts; 244d217d4d9SSepherosa Ziehau sc->sc_rx_intr_delay = et_rx_intr_delay; 245d217d4d9SSepherosa Ziehau sc->sc_tx_intr_nsegs = et_tx_intr_nsegs; 246d217d4d9SSepherosa Ziehau sc->sc_timer = et_timer; 247d217d4d9SSepherosa Ziehau 248d217d4d9SSepherosa Ziehau #ifndef BURN_BRIDGES 249d217d4d9SSepherosa Ziehau if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 250d217d4d9SSepherosa Ziehau uint32_t irq, mem; 251d217d4d9SSepherosa Ziehau 252d217d4d9SSepherosa Ziehau irq = pci_read_config(dev, PCIR_INTLINE, 4); 253d217d4d9SSepherosa Ziehau mem = pci_read_config(dev, ET_PCIR_BAR, 4); 254d217d4d9SSepherosa Ziehau 255d217d4d9SSepherosa Ziehau device_printf(dev, "chip is in D%d power mode " 256d217d4d9SSepherosa Ziehau "-- setting to D0\n", pci_get_powerstate(dev)); 257d217d4d9SSepherosa Ziehau 258d217d4d9SSepherosa Ziehau pci_set_powerstate(dev, PCI_POWERSTATE_D0); 259d217d4d9SSepherosa Ziehau 260d217d4d9SSepherosa Ziehau pci_write_config(dev, PCIR_INTLINE, irq, 4); 261d217d4d9SSepherosa Ziehau pci_write_config(dev, ET_PCIR_BAR, mem, 4); 262d217d4d9SSepherosa Ziehau } 263d217d4d9SSepherosa Ziehau #endif /* !BURN_BRIDGE */ 264d217d4d9SSepherosa Ziehau 265d217d4d9SSepherosa Ziehau /* Enable bus mastering */ 266d217d4d9SSepherosa Ziehau pci_enable_busmaster(dev); 267d217d4d9SSepherosa Ziehau 268d217d4d9SSepherosa Ziehau /* 269d217d4d9SSepherosa Ziehau * Allocate IO memory 270d217d4d9SSepherosa Ziehau */ 271d217d4d9SSepherosa Ziehau sc->sc_mem_rid = ET_PCIR_BAR; 272d217d4d9SSepherosa Ziehau sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 273d217d4d9SSepherosa Ziehau &sc->sc_mem_rid, RF_ACTIVE); 274d217d4d9SSepherosa Ziehau if (sc->sc_mem_res == NULL) { 275d217d4d9SSepherosa Ziehau device_printf(dev, "can't allocate IO memory\n"); 276d217d4d9SSepherosa Ziehau return ENXIO; 277d217d4d9SSepherosa Ziehau } 278d217d4d9SSepherosa Ziehau sc->sc_mem_bt = rman_get_bustag(sc->sc_mem_res); 279d217d4d9SSepherosa Ziehau sc->sc_mem_bh = rman_get_bushandle(sc->sc_mem_res); 280d217d4d9SSepherosa Ziehau 281d217d4d9SSepherosa Ziehau /* 282d217d4d9SSepherosa Ziehau * Allocate IRQ 283d217d4d9SSepherosa Ziehau */ 284d217d4d9SSepherosa Ziehau sc->sc_irq_rid = 0; 285d217d4d9SSepherosa Ziehau sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 286d217d4d9SSepherosa Ziehau &sc->sc_irq_rid, 287d217d4d9SSepherosa Ziehau RF_SHAREABLE | RF_ACTIVE); 288d217d4d9SSepherosa Ziehau if (sc->sc_irq_res == NULL) { 289d217d4d9SSepherosa Ziehau device_printf(dev, "can't allocate irq\n"); 290d217d4d9SSepherosa Ziehau error = ENXIO; 291d217d4d9SSepherosa Ziehau goto fail; 292d217d4d9SSepherosa Ziehau } 293d217d4d9SSepherosa Ziehau 294d217d4d9SSepherosa Ziehau /* 295d217d4d9SSepherosa Ziehau * Create sysctl tree 296d217d4d9SSepherosa Ziehau */ 297d217d4d9SSepherosa Ziehau sysctl_ctx_init(&sc->sc_sysctl_ctx); 298d217d4d9SSepherosa Ziehau sc->sc_sysctl_tree = SYSCTL_ADD_NODE(&sc->sc_sysctl_ctx, 299d217d4d9SSepherosa Ziehau SYSCTL_STATIC_CHILDREN(_hw), 300d217d4d9SSepherosa Ziehau OID_AUTO, 301d217d4d9SSepherosa Ziehau device_get_nameunit(dev), 302d217d4d9SSepherosa Ziehau CTLFLAG_RD, 0, ""); 303d217d4d9SSepherosa Ziehau if (sc->sc_sysctl_tree == NULL) { 304d217d4d9SSepherosa Ziehau device_printf(dev, "can't add sysctl node\n"); 305d217d4d9SSepherosa Ziehau error = ENXIO; 306d217d4d9SSepherosa Ziehau goto fail; 307d217d4d9SSepherosa Ziehau } 308d217d4d9SSepherosa Ziehau 309d217d4d9SSepherosa Ziehau SYSCTL_ADD_PROC(&sc->sc_sysctl_ctx, 310d217d4d9SSepherosa Ziehau SYSCTL_CHILDREN(sc->sc_sysctl_tree), 311d217d4d9SSepherosa Ziehau OID_AUTO, "rx_intr_npkts", CTLTYPE_INT | CTLFLAG_RW, 312d217d4d9SSepherosa Ziehau sc, 0, et_sysctl_rx_intr_npkts, "I", 313d217d4d9SSepherosa Ziehau "RX IM, # packets per RX interrupt"); 314d217d4d9SSepherosa Ziehau SYSCTL_ADD_PROC(&sc->sc_sysctl_ctx, 315d217d4d9SSepherosa Ziehau SYSCTL_CHILDREN(sc->sc_sysctl_tree), 316d217d4d9SSepherosa Ziehau OID_AUTO, "rx_intr_delay", CTLTYPE_INT | CTLFLAG_RW, 317d217d4d9SSepherosa Ziehau sc, 0, et_sysctl_rx_intr_delay, "I", 318d217d4d9SSepherosa Ziehau "RX IM, RX interrupt delay (x10 usec)"); 319d217d4d9SSepherosa Ziehau SYSCTL_ADD_INT(&sc->sc_sysctl_ctx, 320d217d4d9SSepherosa Ziehau SYSCTL_CHILDREN(sc->sc_sysctl_tree), OID_AUTO, 321d217d4d9SSepherosa Ziehau "tx_intr_nsegs", CTLFLAG_RW, &sc->sc_tx_intr_nsegs, 0, 322d217d4d9SSepherosa Ziehau "TX IM, # segments per TX interrupt"); 323d217d4d9SSepherosa Ziehau SYSCTL_ADD_UINT(&sc->sc_sysctl_ctx, 324d217d4d9SSepherosa Ziehau SYSCTL_CHILDREN(sc->sc_sysctl_tree), OID_AUTO, 325d217d4d9SSepherosa Ziehau "timer", CTLFLAG_RW, &sc->sc_timer, 0, 326d217d4d9SSepherosa Ziehau "TX timer"); 327d217d4d9SSepherosa Ziehau 328d217d4d9SSepherosa Ziehau error = et_bus_config(dev); 329d217d4d9SSepherosa Ziehau if (error) 330d217d4d9SSepherosa Ziehau goto fail; 331d217d4d9SSepherosa Ziehau 332d217d4d9SSepherosa Ziehau et_get_eaddr(dev, eaddr); 333d217d4d9SSepherosa Ziehau 334d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_PM, 335d217d4d9SSepherosa Ziehau ET_PM_SYSCLK_GATE | ET_PM_TXCLK_GATE | ET_PM_RXCLK_GATE); 336d217d4d9SSepherosa Ziehau 337d217d4d9SSepherosa Ziehau et_reset(sc); 338d217d4d9SSepherosa Ziehau 339d217d4d9SSepherosa Ziehau et_disable_intrs(sc); 340d217d4d9SSepherosa Ziehau 341d217d4d9SSepherosa Ziehau error = et_dma_alloc(dev); 342d217d4d9SSepherosa Ziehau if (error) 343d217d4d9SSepherosa Ziehau goto fail; 344d217d4d9SSepherosa Ziehau 345d217d4d9SSepherosa Ziehau ifp->if_softc = sc; 346d217d4d9SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 347d217d4d9SSepherosa Ziehau ifp->if_init = et_init; 348d217d4d9SSepherosa Ziehau ifp->if_ioctl = et_ioctl; 349d217d4d9SSepherosa Ziehau ifp->if_start = et_start; 350d217d4d9SSepherosa Ziehau ifp->if_watchdog = et_watchdog; 351d217d4d9SSepherosa Ziehau ifp->if_mtu = ETHERMTU; 35239fdb7b3SSepherosa Ziehau ifp->if_capabilities = IFCAP_VLAN_MTU; 35339fdb7b3SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 354d217d4d9SSepherosa Ziehau ifq_set_maxlen(&ifp->if_snd, ET_TX_NDESC); 355d217d4d9SSepherosa Ziehau ifq_set_ready(&ifp->if_snd); 356d217d4d9SSepherosa Ziehau 357d217d4d9SSepherosa Ziehau et_chip_attach(sc); 358d217d4d9SSepherosa Ziehau 359d217d4d9SSepherosa Ziehau error = mii_phy_probe(dev, &sc->sc_miibus, 360d217d4d9SSepherosa Ziehau et_ifmedia_upd, et_ifmedia_sts); 361d217d4d9SSepherosa Ziehau if (error) { 362d217d4d9SSepherosa Ziehau device_printf(dev, "can't probe any PHY\n"); 363d217d4d9SSepherosa Ziehau goto fail; 364d217d4d9SSepherosa Ziehau } 365d217d4d9SSepherosa Ziehau 366d217d4d9SSepherosa Ziehau ether_ifattach(ifp, eaddr, NULL); 367d217d4d9SSepherosa Ziehau 368d217d4d9SSepherosa Ziehau error = bus_setup_intr(dev, sc->sc_irq_res, INTR_MPSAFE, et_intr, sc, 369d217d4d9SSepherosa Ziehau &sc->sc_irq_handle, ifp->if_serializer); 370d217d4d9SSepherosa Ziehau if (error) { 371d217d4d9SSepherosa Ziehau ether_ifdetach(ifp); 372d217d4d9SSepherosa Ziehau device_printf(dev, "can't setup intr\n"); 373d217d4d9SSepherosa Ziehau goto fail; 374d217d4d9SSepherosa Ziehau } 3759db4b353SSepherosa Ziehau 37628e81a28SSepherosa Ziehau ifp->if_cpuid = rman_get_cpuid(sc->sc_irq_res); 3779db4b353SSepherosa Ziehau KKASSERT(ifp->if_cpuid >= 0 && ifp->if_cpuid < ncpus); 3789db4b353SSepherosa Ziehau 379d217d4d9SSepherosa Ziehau return 0; 380d217d4d9SSepherosa Ziehau fail: 381d217d4d9SSepherosa Ziehau et_detach(dev); 382d217d4d9SSepherosa Ziehau return error; 383d217d4d9SSepherosa Ziehau } 384d217d4d9SSepherosa Ziehau 385d217d4d9SSepherosa Ziehau static int 386d217d4d9SSepherosa Ziehau et_detach(device_t dev) 387d217d4d9SSepherosa Ziehau { 388d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 389d217d4d9SSepherosa Ziehau 390d217d4d9SSepherosa Ziehau if (device_is_attached(dev)) { 391d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 392d217d4d9SSepherosa Ziehau 393d217d4d9SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 394d217d4d9SSepherosa Ziehau et_stop(sc); 395d217d4d9SSepherosa Ziehau bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_handle); 396d217d4d9SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 397d217d4d9SSepherosa Ziehau 398d217d4d9SSepherosa Ziehau ether_ifdetach(ifp); 399d217d4d9SSepherosa Ziehau } 400d217d4d9SSepherosa Ziehau 401d217d4d9SSepherosa Ziehau if (sc->sc_sysctl_tree != NULL) 402d217d4d9SSepherosa Ziehau sysctl_ctx_free(&sc->sc_sysctl_ctx); 403d217d4d9SSepherosa Ziehau 404d217d4d9SSepherosa Ziehau if (sc->sc_miibus != NULL) 405d217d4d9SSepherosa Ziehau device_delete_child(dev, sc->sc_miibus); 406d217d4d9SSepherosa Ziehau bus_generic_detach(dev); 407d217d4d9SSepherosa Ziehau 408d217d4d9SSepherosa Ziehau if (sc->sc_irq_res != NULL) { 409d217d4d9SSepherosa Ziehau bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_rid, 410d217d4d9SSepherosa Ziehau sc->sc_irq_res); 411d217d4d9SSepherosa Ziehau } 412d217d4d9SSepherosa Ziehau 413d217d4d9SSepherosa Ziehau if (sc->sc_mem_res != NULL) { 414d217d4d9SSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, 415d217d4d9SSepherosa Ziehau sc->sc_mem_res); 416d217d4d9SSepherosa Ziehau } 417d217d4d9SSepherosa Ziehau 418d217d4d9SSepherosa Ziehau et_dma_free(dev); 419d217d4d9SSepherosa Ziehau 420d217d4d9SSepherosa Ziehau return 0; 421d217d4d9SSepherosa Ziehau } 422d217d4d9SSepherosa Ziehau 423d217d4d9SSepherosa Ziehau static int 424d217d4d9SSepherosa Ziehau et_shutdown(device_t dev) 425d217d4d9SSepherosa Ziehau { 426d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 427d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 428d217d4d9SSepherosa Ziehau 429d217d4d9SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 430d217d4d9SSepherosa Ziehau et_stop(sc); 431d217d4d9SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 432d217d4d9SSepherosa Ziehau return 0; 433d217d4d9SSepherosa Ziehau } 434d217d4d9SSepherosa Ziehau 435d217d4d9SSepherosa Ziehau static int 436d217d4d9SSepherosa Ziehau et_miibus_readreg(device_t dev, int phy, int reg) 437d217d4d9SSepherosa Ziehau { 438d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 439d217d4d9SSepherosa Ziehau uint32_t val; 440d217d4d9SSepherosa Ziehau int i, ret; 441d217d4d9SSepherosa Ziehau 442d217d4d9SSepherosa Ziehau /* Stop any pending operations */ 443d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_CMD, 0); 444d217d4d9SSepherosa Ziehau 445d217d4d9SSepherosa Ziehau val = __SHIFTIN(phy, ET_MII_ADDR_PHY) | 446d217d4d9SSepherosa Ziehau __SHIFTIN(reg, ET_MII_ADDR_REG); 447d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_ADDR, val); 448d217d4d9SSepherosa Ziehau 449d217d4d9SSepherosa Ziehau /* Start reading */ 450d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_CMD, ET_MII_CMD_READ); 451d217d4d9SSepherosa Ziehau 452d217d4d9SSepherosa Ziehau #define NRETRY 50 453d217d4d9SSepherosa Ziehau 454d217d4d9SSepherosa Ziehau for (i = 0; i < NRETRY; ++i) { 455d217d4d9SSepherosa Ziehau val = CSR_READ_4(sc, ET_MII_IND); 456d217d4d9SSepherosa Ziehau if ((val & (ET_MII_IND_BUSY | ET_MII_IND_INVALID)) == 0) 457d217d4d9SSepherosa Ziehau break; 458d217d4d9SSepherosa Ziehau DELAY(50); 459d217d4d9SSepherosa Ziehau } 460d217d4d9SSepherosa Ziehau if (i == NRETRY) { 461d217d4d9SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 462d217d4d9SSepherosa Ziehau "read phy %d, reg %d timed out\n", phy, reg); 463d217d4d9SSepherosa Ziehau ret = 0; 464d217d4d9SSepherosa Ziehau goto back; 465d217d4d9SSepherosa Ziehau } 466d217d4d9SSepherosa Ziehau 467d217d4d9SSepherosa Ziehau #undef NRETRY 468d217d4d9SSepherosa Ziehau 469d217d4d9SSepherosa Ziehau val = CSR_READ_4(sc, ET_MII_STAT); 470d217d4d9SSepherosa Ziehau ret = __SHIFTOUT(val, ET_MII_STAT_VALUE); 471d217d4d9SSepherosa Ziehau 472d217d4d9SSepherosa Ziehau back: 473d217d4d9SSepherosa Ziehau /* Make sure that the current operation is stopped */ 474d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_CMD, 0); 475d217d4d9SSepherosa Ziehau return ret; 476d217d4d9SSepherosa Ziehau } 477d217d4d9SSepherosa Ziehau 478d217d4d9SSepherosa Ziehau static int 479d217d4d9SSepherosa Ziehau et_miibus_writereg(device_t dev, int phy, int reg, int val0) 480d217d4d9SSepherosa Ziehau { 481d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 482d217d4d9SSepherosa Ziehau uint32_t val; 483d217d4d9SSepherosa Ziehau int i; 484d217d4d9SSepherosa Ziehau 485d217d4d9SSepherosa Ziehau /* Stop any pending operations */ 486d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_CMD, 0); 487d217d4d9SSepherosa Ziehau 488d217d4d9SSepherosa Ziehau val = __SHIFTIN(phy, ET_MII_ADDR_PHY) | 489d217d4d9SSepherosa Ziehau __SHIFTIN(reg, ET_MII_ADDR_REG); 490d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_ADDR, val); 491d217d4d9SSepherosa Ziehau 492d217d4d9SSepherosa Ziehau /* Start writing */ 493d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_CTRL, __SHIFTIN(val0, ET_MII_CTRL_VALUE)); 494d217d4d9SSepherosa Ziehau 495d217d4d9SSepherosa Ziehau #define NRETRY 100 496d217d4d9SSepherosa Ziehau 497d217d4d9SSepherosa Ziehau for (i = 0; i < NRETRY; ++i) { 498d217d4d9SSepherosa Ziehau val = CSR_READ_4(sc, ET_MII_IND); 499d217d4d9SSepherosa Ziehau if ((val & ET_MII_IND_BUSY) == 0) 500d217d4d9SSepherosa Ziehau break; 501d217d4d9SSepherosa Ziehau DELAY(50); 502d217d4d9SSepherosa Ziehau } 503d217d4d9SSepherosa Ziehau if (i == NRETRY) { 504d217d4d9SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 505d217d4d9SSepherosa Ziehau "write phy %d, reg %d timed out\n", phy, reg); 506d217d4d9SSepherosa Ziehau et_miibus_readreg(dev, phy, reg); 507d217d4d9SSepherosa Ziehau } 508d217d4d9SSepherosa Ziehau 509d217d4d9SSepherosa Ziehau #undef NRETRY 510d217d4d9SSepherosa Ziehau 511d217d4d9SSepherosa Ziehau /* Make sure that the current operation is stopped */ 512d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_CMD, 0); 513d217d4d9SSepherosa Ziehau return 0; 514d217d4d9SSepherosa Ziehau } 515d217d4d9SSepherosa Ziehau 516d217d4d9SSepherosa Ziehau static void 517d217d4d9SSepherosa Ziehau et_miibus_statchg(device_t dev) 518d217d4d9SSepherosa Ziehau { 51960d2de1fSSepherosa Ziehau et_setmedia(device_get_softc(dev)); 520d217d4d9SSepherosa Ziehau } 521d217d4d9SSepherosa Ziehau 522d217d4d9SSepherosa Ziehau static int 523d217d4d9SSepherosa Ziehau et_ifmedia_upd(struct ifnet *ifp) 524d217d4d9SSepherosa Ziehau { 525d217d4d9SSepherosa Ziehau struct et_softc *sc = ifp->if_softc; 526d217d4d9SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->sc_miibus); 527d217d4d9SSepherosa Ziehau 528d217d4d9SSepherosa Ziehau if (mii->mii_instance != 0) { 529d217d4d9SSepherosa Ziehau struct mii_softc *miisc; 530d217d4d9SSepherosa Ziehau 531d217d4d9SSepherosa Ziehau LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 532d217d4d9SSepherosa Ziehau mii_phy_reset(miisc); 533d217d4d9SSepherosa Ziehau } 534d217d4d9SSepherosa Ziehau mii_mediachg(mii); 535d217d4d9SSepherosa Ziehau 536d217d4d9SSepherosa Ziehau return 0; 537d217d4d9SSepherosa Ziehau } 538d217d4d9SSepherosa Ziehau 539d217d4d9SSepherosa Ziehau static void 540d217d4d9SSepherosa Ziehau et_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 541d217d4d9SSepherosa Ziehau { 542d217d4d9SSepherosa Ziehau struct et_softc *sc = ifp->if_softc; 543d217d4d9SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->sc_miibus); 544d217d4d9SSepherosa Ziehau 545d217d4d9SSepherosa Ziehau mii_pollstat(mii); 546d217d4d9SSepherosa Ziehau ifmr->ifm_active = mii->mii_media_active; 547d217d4d9SSepherosa Ziehau ifmr->ifm_status = mii->mii_media_status; 548d217d4d9SSepherosa Ziehau } 549d217d4d9SSepherosa Ziehau 550d217d4d9SSepherosa Ziehau static void 551d217d4d9SSepherosa Ziehau et_stop(struct et_softc *sc) 552d217d4d9SSepherosa Ziehau { 553d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 554d217d4d9SSepherosa Ziehau 555d217d4d9SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 556d217d4d9SSepherosa Ziehau 557d217d4d9SSepherosa Ziehau callout_stop(&sc->sc_tick); 558d217d4d9SSepherosa Ziehau 559d217d4d9SSepherosa Ziehau et_stop_rxdma(sc); 560d217d4d9SSepherosa Ziehau et_stop_txdma(sc); 561d217d4d9SSepherosa Ziehau 562d217d4d9SSepherosa Ziehau et_disable_intrs(sc); 563d217d4d9SSepherosa Ziehau 564d217d4d9SSepherosa Ziehau et_free_tx_ring(sc); 565d217d4d9SSepherosa Ziehau et_free_rx_ring(sc); 566d217d4d9SSepherosa Ziehau 567d217d4d9SSepherosa Ziehau et_reset(sc); 568d217d4d9SSepherosa Ziehau 569d217d4d9SSepherosa Ziehau sc->sc_tx = 0; 570d217d4d9SSepherosa Ziehau sc->sc_tx_intr = 0; 5713effc1bfSSepherosa Ziehau sc->sc_flags &= ~ET_FLAG_TXRX_ENABLED; 572d217d4d9SSepherosa Ziehau 573d217d4d9SSepherosa Ziehau ifp->if_timer = 0; 574*9ed293e0SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING; 575*9ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 576d217d4d9SSepherosa Ziehau } 577d217d4d9SSepherosa Ziehau 578d217d4d9SSepherosa Ziehau static int 579d217d4d9SSepherosa Ziehau et_bus_config(device_t dev) 580d217d4d9SSepherosa Ziehau { 581d217d4d9SSepherosa Ziehau uint32_t val, max_plsz; 582d217d4d9SSepherosa Ziehau uint16_t ack_latency, replay_timer; 583d217d4d9SSepherosa Ziehau 584d217d4d9SSepherosa Ziehau /* 585d217d4d9SSepherosa Ziehau * Test whether EEPROM is valid 586d217d4d9SSepherosa Ziehau * NOTE: Read twice to get the correct value 587d217d4d9SSepherosa Ziehau */ 588d217d4d9SSepherosa Ziehau pci_read_config(dev, ET_PCIR_EEPROM_STATUS, 1); 589d217d4d9SSepherosa Ziehau val = pci_read_config(dev, ET_PCIR_EEPROM_STATUS, 1); 590d217d4d9SSepherosa Ziehau if (val & ET_PCIM_EEPROM_STATUS_ERROR) { 591d217d4d9SSepherosa Ziehau device_printf(dev, "EEPROM status error 0x%02x\n", val); 592d217d4d9SSepherosa Ziehau return ENXIO; 593d217d4d9SSepherosa Ziehau } 594d217d4d9SSepherosa Ziehau 595d217d4d9SSepherosa Ziehau /* TODO: LED */ 596d217d4d9SSepherosa Ziehau 597d217d4d9SSepherosa Ziehau /* 598d217d4d9SSepherosa Ziehau * Configure ACK latency and replay timer according to 599d217d4d9SSepherosa Ziehau * max playload size 600d217d4d9SSepherosa Ziehau */ 601d217d4d9SSepherosa Ziehau val = pci_read_config(dev, ET_PCIR_DEVICE_CAPS, 4); 602d217d4d9SSepherosa Ziehau max_plsz = val & ET_PCIM_DEVICE_CAPS_MAX_PLSZ; 603d217d4d9SSepherosa Ziehau 604d217d4d9SSepherosa Ziehau switch (max_plsz) { 605d217d4d9SSepherosa Ziehau case ET_PCIV_DEVICE_CAPS_PLSZ_128: 606d217d4d9SSepherosa Ziehau ack_latency = ET_PCIV_ACK_LATENCY_128; 607d217d4d9SSepherosa Ziehau replay_timer = ET_PCIV_REPLAY_TIMER_128; 608d217d4d9SSepherosa Ziehau break; 609d217d4d9SSepherosa Ziehau 610d217d4d9SSepherosa Ziehau case ET_PCIV_DEVICE_CAPS_PLSZ_256: 611d217d4d9SSepherosa Ziehau ack_latency = ET_PCIV_ACK_LATENCY_256; 612d217d4d9SSepherosa Ziehau replay_timer = ET_PCIV_REPLAY_TIMER_256; 613d217d4d9SSepherosa Ziehau break; 614d217d4d9SSepherosa Ziehau 615d217d4d9SSepherosa Ziehau default: 616d217d4d9SSepherosa Ziehau ack_latency = pci_read_config(dev, ET_PCIR_ACK_LATENCY, 2); 617d217d4d9SSepherosa Ziehau replay_timer = pci_read_config(dev, ET_PCIR_REPLAY_TIMER, 2); 618d217d4d9SSepherosa Ziehau device_printf(dev, "ack latency %u, replay timer %u\n", 619d217d4d9SSepherosa Ziehau ack_latency, replay_timer); 620d217d4d9SSepherosa Ziehau break; 621d217d4d9SSepherosa Ziehau } 622d217d4d9SSepherosa Ziehau if (ack_latency != 0) { 623d217d4d9SSepherosa Ziehau pci_write_config(dev, ET_PCIR_ACK_LATENCY, ack_latency, 2); 624d217d4d9SSepherosa Ziehau pci_write_config(dev, ET_PCIR_REPLAY_TIMER, replay_timer, 2); 625d217d4d9SSepherosa Ziehau } 626d217d4d9SSepherosa Ziehau 627d217d4d9SSepherosa Ziehau /* 628d217d4d9SSepherosa Ziehau * Set L0s and L1 latency timer to 2us 629d217d4d9SSepherosa Ziehau */ 630d217d4d9SSepherosa Ziehau val = ET_PCIV_L0S_LATENCY(2) | ET_PCIV_L1_LATENCY(2); 631d217d4d9SSepherosa Ziehau pci_write_config(dev, ET_PCIR_L0S_L1_LATENCY, val, 1); 632d217d4d9SSepherosa Ziehau 633d217d4d9SSepherosa Ziehau /* 634d217d4d9SSepherosa Ziehau * Set max read request size to 2048 bytes 635d217d4d9SSepherosa Ziehau */ 636d217d4d9SSepherosa Ziehau val = pci_read_config(dev, ET_PCIR_DEVICE_CTRL, 2); 637d217d4d9SSepherosa Ziehau val &= ~ET_PCIM_DEVICE_CTRL_MAX_RRSZ; 638d217d4d9SSepherosa Ziehau val |= ET_PCIV_DEVICE_CTRL_RRSZ_2K; 639d217d4d9SSepherosa Ziehau pci_write_config(dev, ET_PCIR_DEVICE_CTRL, val, 2); 640d217d4d9SSepherosa Ziehau 641d217d4d9SSepherosa Ziehau return 0; 642d217d4d9SSepherosa Ziehau } 643d217d4d9SSepherosa Ziehau 644d217d4d9SSepherosa Ziehau static void 645d217d4d9SSepherosa Ziehau et_get_eaddr(device_t dev, uint8_t eaddr[]) 646d217d4d9SSepherosa Ziehau { 647d217d4d9SSepherosa Ziehau uint32_t val; 648d217d4d9SSepherosa Ziehau int i; 649d217d4d9SSepherosa Ziehau 650d217d4d9SSepherosa Ziehau val = pci_read_config(dev, ET_PCIR_MAC_ADDR0, 4); 651d217d4d9SSepherosa Ziehau for (i = 0; i < 4; ++i) 652d217d4d9SSepherosa Ziehau eaddr[i] = (val >> (8 * i)) & 0xff; 653d217d4d9SSepherosa Ziehau 654d217d4d9SSepherosa Ziehau val = pci_read_config(dev, ET_PCIR_MAC_ADDR1, 2); 655d217d4d9SSepherosa Ziehau for (; i < ETHER_ADDR_LEN; ++i) 656d217d4d9SSepherosa Ziehau eaddr[i] = (val >> (8 * (i - 4))) & 0xff; 657d217d4d9SSepherosa Ziehau } 658d217d4d9SSepherosa Ziehau 659d217d4d9SSepherosa Ziehau static void 660d217d4d9SSepherosa Ziehau et_reset(struct et_softc *sc) 661d217d4d9SSepherosa Ziehau { 662d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG1, 663d217d4d9SSepherosa Ziehau ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 664d217d4d9SSepherosa Ziehau ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | 665d217d4d9SSepherosa Ziehau ET_MAC_CFG1_SIM_RST | ET_MAC_CFG1_SOFT_RST); 666d217d4d9SSepherosa Ziehau 667d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_SWRST, 668d217d4d9SSepherosa Ziehau ET_SWRST_TXDMA | ET_SWRST_RXDMA | 669d217d4d9SSepherosa Ziehau ET_SWRST_TXMAC | ET_SWRST_RXMAC | 670d217d4d9SSepherosa Ziehau ET_SWRST_MAC | ET_SWRST_MAC_STAT | ET_SWRST_MMC); 671d217d4d9SSepherosa Ziehau 672d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG1, 673d217d4d9SSepherosa Ziehau ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 674d217d4d9SSepherosa Ziehau ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC); 675d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG1, 0); 676d217d4d9SSepherosa Ziehau } 677d217d4d9SSepherosa Ziehau 678d217d4d9SSepherosa Ziehau static void 679d217d4d9SSepherosa Ziehau et_disable_intrs(struct et_softc *sc) 680d217d4d9SSepherosa Ziehau { 681d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_INTR_MASK, 0xffffffff); 682d217d4d9SSepherosa Ziehau } 683d217d4d9SSepherosa Ziehau 684d217d4d9SSepherosa Ziehau static void 685d217d4d9SSepherosa Ziehau et_enable_intrs(struct et_softc *sc, uint32_t intrs) 686d217d4d9SSepherosa Ziehau { 687d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_INTR_MASK, ~intrs); 688d217d4d9SSepherosa Ziehau } 689d217d4d9SSepherosa Ziehau 690d217d4d9SSepherosa Ziehau static int 691d217d4d9SSepherosa Ziehau et_dma_alloc(device_t dev) 692d217d4d9SSepherosa Ziehau { 693d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 694d217d4d9SSepherosa Ziehau struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 695d217d4d9SSepherosa Ziehau struct et_txstatus_data *txsd = &sc->sc_tx_status; 696d217d4d9SSepherosa Ziehau struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring; 697d217d4d9SSepherosa Ziehau struct et_rxstatus_data *rxsd = &sc->sc_rx_status; 698d217d4d9SSepherosa Ziehau int i, error; 699d217d4d9SSepherosa Ziehau 700d217d4d9SSepherosa Ziehau /* 701d217d4d9SSepherosa Ziehau * Create top level DMA tag 702d217d4d9SSepherosa Ziehau */ 703d217d4d9SSepherosa Ziehau error = bus_dma_tag_create(NULL, 1, 0, 7044c749635SSepherosa Ziehau BUS_SPACE_MAXADDR, 705d217d4d9SSepherosa Ziehau BUS_SPACE_MAXADDR, 706d217d4d9SSepherosa Ziehau NULL, NULL, 7074c749635SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, 7084c749635SSepherosa Ziehau 0, 709d217d4d9SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, 710d217d4d9SSepherosa Ziehau 0, &sc->sc_dtag); 711d217d4d9SSepherosa Ziehau if (error) { 712d217d4d9SSepherosa Ziehau device_printf(dev, "can't create DMA tag\n"); 713d217d4d9SSepherosa Ziehau return error; 714d217d4d9SSepherosa Ziehau } 715d217d4d9SSepherosa Ziehau 716d217d4d9SSepherosa Ziehau /* 717d217d4d9SSepherosa Ziehau * Create TX ring DMA stuffs 718d217d4d9SSepherosa Ziehau */ 719c7f73cc7SSepherosa Ziehau tx_ring->tr_desc = bus_dmamem_coherent_any(sc->sc_dtag, 720c7f73cc7SSepherosa Ziehau ET_ALIGN, ET_TX_RING_SIZE, 721c7f73cc7SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 722c7f73cc7SSepherosa Ziehau &tx_ring->tr_dtag, &tx_ring->tr_dmap, 723c7f73cc7SSepherosa Ziehau &tx_ring->tr_paddr); 724c7f73cc7SSepherosa Ziehau if (tx_ring->tr_desc == NULL) { 725d217d4d9SSepherosa Ziehau device_printf(dev, "can't create TX ring DMA stuffs\n"); 726c7f73cc7SSepherosa Ziehau return ENOMEM; 727d217d4d9SSepherosa Ziehau } 728d217d4d9SSepherosa Ziehau 729d217d4d9SSepherosa Ziehau /* 730d217d4d9SSepherosa Ziehau * Create TX status DMA stuffs 731d217d4d9SSepherosa Ziehau */ 732c7f73cc7SSepherosa Ziehau txsd->txsd_status = bus_dmamem_coherent_any(sc->sc_dtag, 733c7f73cc7SSepherosa Ziehau ET_ALIGN, sizeof(uint32_t), 734c7f73cc7SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 735c7f73cc7SSepherosa Ziehau &txsd->txsd_dtag, &txsd->txsd_dmap, 736c7f73cc7SSepherosa Ziehau &txsd->txsd_paddr); 737c7f73cc7SSepherosa Ziehau if (txsd->txsd_status == NULL) { 738d217d4d9SSepherosa Ziehau device_printf(dev, "can't create TX status DMA stuffs\n"); 739c7f73cc7SSepherosa Ziehau return ENOMEM; 740d217d4d9SSepherosa Ziehau } 741d217d4d9SSepherosa Ziehau 742d217d4d9SSepherosa Ziehau /* 743d217d4d9SSepherosa Ziehau * Create DMA stuffs for RX rings 744d217d4d9SSepherosa Ziehau */ 745d217d4d9SSepherosa Ziehau for (i = 0; i < ET_RX_NRING; ++i) { 746d217d4d9SSepherosa Ziehau static const uint32_t rx_ring_posreg[ET_RX_NRING] = 747d217d4d9SSepherosa Ziehau { ET_RX_RING0_POS, ET_RX_RING1_POS }; 748d217d4d9SSepherosa Ziehau 749d217d4d9SSepherosa Ziehau struct et_rxdesc_ring *rx_ring = &sc->sc_rx_ring[i]; 750d217d4d9SSepherosa Ziehau 751c7f73cc7SSepherosa Ziehau rx_ring->rr_desc = bus_dmamem_coherent_any(sc->sc_dtag, 752c7f73cc7SSepherosa Ziehau ET_ALIGN, ET_RX_RING_SIZE, 753c7f73cc7SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 754c7f73cc7SSepherosa Ziehau &rx_ring->rr_dtag, &rx_ring->rr_dmap, 755c7f73cc7SSepherosa Ziehau &rx_ring->rr_paddr); 756c7f73cc7SSepherosa Ziehau if (rx_ring->rr_desc == NULL) { 757d217d4d9SSepherosa Ziehau device_printf(dev, "can't create DMA stuffs for " 758d217d4d9SSepherosa Ziehau "the %d RX ring\n", i); 759c7f73cc7SSepherosa Ziehau return ENOMEM; 760d217d4d9SSepherosa Ziehau } 761d217d4d9SSepherosa Ziehau rx_ring->rr_posreg = rx_ring_posreg[i]; 762d217d4d9SSepherosa Ziehau } 763d217d4d9SSepherosa Ziehau 764d217d4d9SSepherosa Ziehau /* 765d217d4d9SSepherosa Ziehau * Create RX stat ring DMA stuffs 766d217d4d9SSepherosa Ziehau */ 767c7f73cc7SSepherosa Ziehau rxst_ring->rsr_stat = bus_dmamem_coherent_any(sc->sc_dtag, 768c7f73cc7SSepherosa Ziehau ET_ALIGN, ET_RXSTAT_RING_SIZE, 769c7f73cc7SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 770c7f73cc7SSepherosa Ziehau &rxst_ring->rsr_dtag, &rxst_ring->rsr_dmap, 771c7f73cc7SSepherosa Ziehau &rxst_ring->rsr_paddr); 772c7f73cc7SSepherosa Ziehau if (rxst_ring->rsr_stat == NULL) { 773d217d4d9SSepherosa Ziehau device_printf(dev, "can't create RX stat ring DMA stuffs\n"); 774c7f73cc7SSepherosa Ziehau return ENOMEM; 775d217d4d9SSepherosa Ziehau } 776d217d4d9SSepherosa Ziehau 777d217d4d9SSepherosa Ziehau /* 778d217d4d9SSepherosa Ziehau * Create RX status DMA stuffs 779d217d4d9SSepherosa Ziehau */ 780c7f73cc7SSepherosa Ziehau rxsd->rxsd_status = bus_dmamem_coherent_any(sc->sc_dtag, 781c7f73cc7SSepherosa Ziehau ET_ALIGN, sizeof(struct et_rxstatus), 782c7f73cc7SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 783c7f73cc7SSepherosa Ziehau &rxsd->rxsd_dtag, &rxsd->rxsd_dmap, 784c7f73cc7SSepherosa Ziehau &rxsd->rxsd_paddr); 785c7f73cc7SSepherosa Ziehau if (rxsd->rxsd_status == NULL) { 786d217d4d9SSepherosa Ziehau device_printf(dev, "can't create RX status DMA stuffs\n"); 787c7f73cc7SSepherosa Ziehau return ENOMEM; 788d217d4d9SSepherosa Ziehau } 789d217d4d9SSepherosa Ziehau 790d217d4d9SSepherosa Ziehau /* 791d217d4d9SSepherosa Ziehau * Create mbuf DMA stuffs 792d217d4d9SSepherosa Ziehau */ 793d217d4d9SSepherosa Ziehau error = et_dma_mbuf_create(dev); 794d217d4d9SSepherosa Ziehau if (error) 795d217d4d9SSepherosa Ziehau return error; 796d217d4d9SSepherosa Ziehau 7973effc1bfSSepherosa Ziehau /* 7983effc1bfSSepherosa Ziehau * Create jumbo buffer DMA stuffs 7993effc1bfSSepherosa Ziehau * NOTE: Allow it to fail 8003effc1bfSSepherosa Ziehau */ 8013effc1bfSSepherosa Ziehau if (et_jumbo_mem_alloc(dev) == 0) 8023effc1bfSSepherosa Ziehau sc->sc_flags |= ET_FLAG_JUMBO; 8033effc1bfSSepherosa Ziehau 804d217d4d9SSepherosa Ziehau return 0; 805d217d4d9SSepherosa Ziehau } 806d217d4d9SSepherosa Ziehau 807d217d4d9SSepherosa Ziehau static void 808d217d4d9SSepherosa Ziehau et_dma_free(device_t dev) 809d217d4d9SSepherosa Ziehau { 810d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 811d217d4d9SSepherosa Ziehau struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 812d217d4d9SSepherosa Ziehau struct et_txstatus_data *txsd = &sc->sc_tx_status; 813d217d4d9SSepherosa Ziehau struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring; 814d217d4d9SSepherosa Ziehau struct et_rxstatus_data *rxsd = &sc->sc_rx_status; 815d217d4d9SSepherosa Ziehau int i, rx_done[ET_RX_NRING]; 816d217d4d9SSepherosa Ziehau 817d217d4d9SSepherosa Ziehau /* 818d217d4d9SSepherosa Ziehau * Destroy TX ring DMA stuffs 819d217d4d9SSepherosa Ziehau */ 820d217d4d9SSepherosa Ziehau et_dma_mem_destroy(tx_ring->tr_dtag, tx_ring->tr_desc, 821d217d4d9SSepherosa Ziehau tx_ring->tr_dmap); 822d217d4d9SSepherosa Ziehau 823d217d4d9SSepherosa Ziehau /* 824d217d4d9SSepherosa Ziehau * Destroy TX status DMA stuffs 825d217d4d9SSepherosa Ziehau */ 826d217d4d9SSepherosa Ziehau et_dma_mem_destroy(txsd->txsd_dtag, txsd->txsd_status, 827d217d4d9SSepherosa Ziehau txsd->txsd_dmap); 828d217d4d9SSepherosa Ziehau 829d217d4d9SSepherosa Ziehau /* 830d217d4d9SSepherosa Ziehau * Destroy DMA stuffs for RX rings 831d217d4d9SSepherosa Ziehau */ 832d217d4d9SSepherosa Ziehau for (i = 0; i < ET_RX_NRING; ++i) { 833d217d4d9SSepherosa Ziehau struct et_rxdesc_ring *rx_ring = &sc->sc_rx_ring[i]; 834d217d4d9SSepherosa Ziehau 835d217d4d9SSepherosa Ziehau et_dma_mem_destroy(rx_ring->rr_dtag, rx_ring->rr_desc, 836d217d4d9SSepherosa Ziehau rx_ring->rr_dmap); 837d217d4d9SSepherosa Ziehau } 838d217d4d9SSepherosa Ziehau 839d217d4d9SSepherosa Ziehau /* 840d217d4d9SSepherosa Ziehau * Destroy RX stat ring DMA stuffs 841d217d4d9SSepherosa Ziehau */ 842d217d4d9SSepherosa Ziehau et_dma_mem_destroy(rxst_ring->rsr_dtag, rxst_ring->rsr_stat, 843d217d4d9SSepherosa Ziehau rxst_ring->rsr_dmap); 844d217d4d9SSepherosa Ziehau 845d217d4d9SSepherosa Ziehau /* 846d217d4d9SSepherosa Ziehau * Destroy RX status DMA stuffs 847d217d4d9SSepherosa Ziehau */ 848d217d4d9SSepherosa Ziehau et_dma_mem_destroy(rxsd->rxsd_dtag, rxsd->rxsd_status, 849d217d4d9SSepherosa Ziehau rxsd->rxsd_dmap); 850d217d4d9SSepherosa Ziehau 851d217d4d9SSepherosa Ziehau /* 852d217d4d9SSepherosa Ziehau * Destroy mbuf DMA stuffs 853d217d4d9SSepherosa Ziehau */ 854d217d4d9SSepherosa Ziehau for (i = 0; i < ET_RX_NRING; ++i) 855d217d4d9SSepherosa Ziehau rx_done[i] = ET_RX_NDESC; 856d217d4d9SSepherosa Ziehau et_dma_mbuf_destroy(dev, ET_TX_NDESC, rx_done); 857d217d4d9SSepherosa Ziehau 858d217d4d9SSepherosa Ziehau /* 8593effc1bfSSepherosa Ziehau * Destroy jumbo buffer DMA stuffs 8603effc1bfSSepherosa Ziehau */ 8613effc1bfSSepherosa Ziehau if (sc->sc_flags & ET_FLAG_JUMBO) 8623effc1bfSSepherosa Ziehau et_jumbo_mem_free(dev); 8633effc1bfSSepherosa Ziehau 8643effc1bfSSepherosa Ziehau /* 865d217d4d9SSepherosa Ziehau * Destroy top level DMA tag 866d217d4d9SSepherosa Ziehau */ 867d217d4d9SSepherosa Ziehau if (sc->sc_dtag != NULL) 868d217d4d9SSepherosa Ziehau bus_dma_tag_destroy(sc->sc_dtag); 869d217d4d9SSepherosa Ziehau } 870d217d4d9SSepherosa Ziehau 871d217d4d9SSepherosa Ziehau static int 872d217d4d9SSepherosa Ziehau et_dma_mbuf_create(device_t dev) 873d217d4d9SSepherosa Ziehau { 874d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 875d217d4d9SSepherosa Ziehau struct et_txbuf_data *tbd = &sc->sc_tx_data; 876d217d4d9SSepherosa Ziehau int i, error, rx_done[ET_RX_NRING]; 877d217d4d9SSepherosa Ziehau 878d217d4d9SSepherosa Ziehau /* 8790fe5209eSSepherosa Ziehau * Create RX mbuf DMA tag 880d217d4d9SSepherosa Ziehau */ 881d217d4d9SSepherosa Ziehau error = bus_dma_tag_create(sc->sc_dtag, 1, 0, 882d217d4d9SSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 883d217d4d9SSepherosa Ziehau NULL, NULL, 8840fe5209eSSepherosa Ziehau MCLBYTES, 1, MCLBYTES, 8854c749635SSepherosa Ziehau BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK, 8860fe5209eSSepherosa Ziehau &sc->sc_rxbuf_dtag); 887d217d4d9SSepherosa Ziehau if (error) { 8880fe5209eSSepherosa Ziehau device_printf(dev, "can't create RX mbuf DMA tag\n"); 889d217d4d9SSepherosa Ziehau return error; 890d217d4d9SSepherosa Ziehau } 891d217d4d9SSepherosa Ziehau 892d217d4d9SSepherosa Ziehau /* 893d217d4d9SSepherosa Ziehau * Create spare DMA map for RX mbufs 894d217d4d9SSepherosa Ziehau */ 8950fe5209eSSepherosa Ziehau error = bus_dmamap_create(sc->sc_rxbuf_dtag, BUS_DMA_WAITOK, 8960fe5209eSSepherosa Ziehau &sc->sc_rxbuf_tmp_dmap); 897d217d4d9SSepherosa Ziehau if (error) { 898d217d4d9SSepherosa Ziehau device_printf(dev, "can't create spare mbuf DMA map\n"); 8990fe5209eSSepherosa Ziehau bus_dma_tag_destroy(sc->sc_rxbuf_dtag); 9000fe5209eSSepherosa Ziehau sc->sc_rxbuf_dtag = NULL; 901d217d4d9SSepherosa Ziehau return error; 902d217d4d9SSepherosa Ziehau } 903d217d4d9SSepherosa Ziehau 904d217d4d9SSepherosa Ziehau /* 905d217d4d9SSepherosa Ziehau * Create DMA maps for RX mbufs 906d217d4d9SSepherosa Ziehau */ 907d217d4d9SSepherosa Ziehau bzero(rx_done, sizeof(rx_done)); 908d217d4d9SSepherosa Ziehau for (i = 0; i < ET_RX_NRING; ++i) { 909d217d4d9SSepherosa Ziehau struct et_rxbuf_data *rbd = &sc->sc_rx_data[i]; 910d217d4d9SSepherosa Ziehau int j; 911d217d4d9SSepherosa Ziehau 912d217d4d9SSepherosa Ziehau for (j = 0; j < ET_RX_NDESC; ++j) { 9130fe5209eSSepherosa Ziehau error = bus_dmamap_create(sc->sc_rxbuf_dtag, 9144c749635SSepherosa Ziehau BUS_DMA_WAITOK, 915d217d4d9SSepherosa Ziehau &rbd->rbd_buf[j].rb_dmap); 916d217d4d9SSepherosa Ziehau if (error) { 917d217d4d9SSepherosa Ziehau device_printf(dev, "can't create %d RX mbuf " 918d217d4d9SSepherosa Ziehau "for %d RX ring\n", j, i); 919d217d4d9SSepherosa Ziehau rx_done[i] = j; 920d217d4d9SSepherosa Ziehau et_dma_mbuf_destroy(dev, 0, rx_done); 921d217d4d9SSepherosa Ziehau return error; 922d217d4d9SSepherosa Ziehau } 923d217d4d9SSepherosa Ziehau } 924d217d4d9SSepherosa Ziehau rx_done[i] = ET_RX_NDESC; 925d217d4d9SSepherosa Ziehau 926d217d4d9SSepherosa Ziehau rbd->rbd_softc = sc; 927d217d4d9SSepherosa Ziehau rbd->rbd_ring = &sc->sc_rx_ring[i]; 928d217d4d9SSepherosa Ziehau } 929d217d4d9SSepherosa Ziehau 930d217d4d9SSepherosa Ziehau /* 9310fe5209eSSepherosa Ziehau * Create TX mbuf DMA tag 9320fe5209eSSepherosa Ziehau */ 9330fe5209eSSepherosa Ziehau error = bus_dma_tag_create(sc->sc_dtag, 1, 0, 9340fe5209eSSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 9350fe5209eSSepherosa Ziehau NULL, NULL, 9360fe5209eSSepherosa Ziehau ET_JUMBO_FRAMELEN, ET_NSEG_MAX, MCLBYTES, 9370fe5209eSSepherosa Ziehau BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK | 9380fe5209eSSepherosa Ziehau BUS_DMA_ONEBPAGE, 9390fe5209eSSepherosa Ziehau &sc->sc_txbuf_dtag); 9400fe5209eSSepherosa Ziehau if (error) { 9410fe5209eSSepherosa Ziehau device_printf(dev, "can't create TX mbuf DMA tag\n"); 9420fe5209eSSepherosa Ziehau return error; 9430fe5209eSSepherosa Ziehau } 9440fe5209eSSepherosa Ziehau 9450fe5209eSSepherosa Ziehau /* 946d217d4d9SSepherosa Ziehau * Create DMA maps for TX mbufs 947d217d4d9SSepherosa Ziehau */ 948d217d4d9SSepherosa Ziehau for (i = 0; i < ET_TX_NDESC; ++i) { 9490fe5209eSSepherosa Ziehau error = bus_dmamap_create(sc->sc_txbuf_dtag, 9500fe5209eSSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE, 951d217d4d9SSepherosa Ziehau &tbd->tbd_buf[i].tb_dmap); 952d217d4d9SSepherosa Ziehau if (error) { 953d217d4d9SSepherosa Ziehau device_printf(dev, "can't create %d TX mbuf " 954d217d4d9SSepherosa Ziehau "DMA map\n", i); 955d217d4d9SSepherosa Ziehau et_dma_mbuf_destroy(dev, i, rx_done); 956d217d4d9SSepherosa Ziehau return error; 957d217d4d9SSepherosa Ziehau } 958d217d4d9SSepherosa Ziehau } 959d217d4d9SSepherosa Ziehau 960d217d4d9SSepherosa Ziehau return 0; 961d217d4d9SSepherosa Ziehau } 962d217d4d9SSepherosa Ziehau 963d217d4d9SSepherosa Ziehau static void 964d217d4d9SSepherosa Ziehau et_dma_mbuf_destroy(device_t dev, int tx_done, const int rx_done[]) 965d217d4d9SSepherosa Ziehau { 966d217d4d9SSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 967d217d4d9SSepherosa Ziehau struct et_txbuf_data *tbd = &sc->sc_tx_data; 968d217d4d9SSepherosa Ziehau int i; 969d217d4d9SSepherosa Ziehau 970d217d4d9SSepherosa Ziehau /* 9710fe5209eSSepherosa Ziehau * Destroy DMA tag and maps for RX mbufs 972d217d4d9SSepherosa Ziehau */ 9730fe5209eSSepherosa Ziehau if (sc->sc_rxbuf_dtag) { 974d217d4d9SSepherosa Ziehau for (i = 0; i < ET_RX_NRING; ++i) { 975d217d4d9SSepherosa Ziehau struct et_rxbuf_data *rbd = &sc->sc_rx_data[i]; 976d217d4d9SSepherosa Ziehau int j; 977d217d4d9SSepherosa Ziehau 978d217d4d9SSepherosa Ziehau for (j = 0; j < rx_done[i]; ++j) { 979d217d4d9SSepherosa Ziehau struct et_rxbuf *rb = &rbd->rbd_buf[j]; 980d217d4d9SSepherosa Ziehau 981d217d4d9SSepherosa Ziehau KASSERT(rb->rb_mbuf == NULL, 9820fe5209eSSepherosa Ziehau ("RX mbuf in %d RX ring is " 983ed20d0e3SSascha Wildner "not freed yet", i)); 9840fe5209eSSepherosa Ziehau bus_dmamap_destroy(sc->sc_rxbuf_dtag, 9850fe5209eSSepherosa Ziehau rb->rb_dmap); 986d217d4d9SSepherosa Ziehau } 987d217d4d9SSepherosa Ziehau } 9880fe5209eSSepherosa Ziehau bus_dmamap_destroy(sc->sc_rxbuf_dtag, sc->sc_rxbuf_tmp_dmap); 9890fe5209eSSepherosa Ziehau bus_dma_tag_destroy(sc->sc_rxbuf_dtag); 9900fe5209eSSepherosa Ziehau sc->sc_rxbuf_dtag = NULL; 9910fe5209eSSepherosa Ziehau } 992d217d4d9SSepherosa Ziehau 993d217d4d9SSepherosa Ziehau /* 9940fe5209eSSepherosa Ziehau * Destroy DMA tag and maps for TX mbufs 995d217d4d9SSepherosa Ziehau */ 9960fe5209eSSepherosa Ziehau if (sc->sc_txbuf_dtag) { 997d217d4d9SSepherosa Ziehau for (i = 0; i < tx_done; ++i) { 998d217d4d9SSepherosa Ziehau struct et_txbuf *tb = &tbd->tbd_buf[i]; 999d217d4d9SSepherosa Ziehau 10000fe5209eSSepherosa Ziehau KASSERT(tb->tb_mbuf == NULL, 1001ed20d0e3SSascha Wildner ("TX mbuf is not freed yet")); 10020fe5209eSSepherosa Ziehau bus_dmamap_destroy(sc->sc_txbuf_dtag, tb->tb_dmap); 1003d217d4d9SSepherosa Ziehau } 10040fe5209eSSepherosa Ziehau bus_dma_tag_destroy(sc->sc_txbuf_dtag); 10050fe5209eSSepherosa Ziehau sc->sc_txbuf_dtag = NULL; 10060fe5209eSSepherosa Ziehau } 1007d217d4d9SSepherosa Ziehau } 1008d217d4d9SSepherosa Ziehau 1009d217d4d9SSepherosa Ziehau static void 1010d217d4d9SSepherosa Ziehau et_dma_mem_destroy(bus_dma_tag_t dtag, void *addr, bus_dmamap_t dmap) 1011d217d4d9SSepherosa Ziehau { 1012d217d4d9SSepherosa Ziehau if (dtag != NULL) { 1013d217d4d9SSepherosa Ziehau bus_dmamap_unload(dtag, dmap); 1014d217d4d9SSepherosa Ziehau bus_dmamem_free(dtag, addr, dmap); 1015d217d4d9SSepherosa Ziehau bus_dma_tag_destroy(dtag); 1016d217d4d9SSepherosa Ziehau } 1017d217d4d9SSepherosa Ziehau } 1018d217d4d9SSepherosa Ziehau 1019d217d4d9SSepherosa Ziehau static void 1020d217d4d9SSepherosa Ziehau et_chip_attach(struct et_softc *sc) 1021d217d4d9SSepherosa Ziehau { 1022d217d4d9SSepherosa Ziehau uint32_t val; 1023d217d4d9SSepherosa Ziehau 1024d217d4d9SSepherosa Ziehau /* 1025d217d4d9SSepherosa Ziehau * Perform minimal initialization 1026d217d4d9SSepherosa Ziehau */ 1027d217d4d9SSepherosa Ziehau 1028d217d4d9SSepherosa Ziehau /* Disable loopback */ 1029d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_LOOPBACK, 0); 1030d217d4d9SSepherosa Ziehau 1031d217d4d9SSepherosa Ziehau /* Reset MAC */ 1032d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG1, 1033d217d4d9SSepherosa Ziehau ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 1034d217d4d9SSepherosa Ziehau ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | 1035d217d4d9SSepherosa Ziehau ET_MAC_CFG1_SIM_RST | ET_MAC_CFG1_SOFT_RST); 1036d217d4d9SSepherosa Ziehau 1037d217d4d9SSepherosa Ziehau /* 1038d217d4d9SSepherosa Ziehau * Setup half duplex mode 1039d217d4d9SSepherosa Ziehau */ 1040d217d4d9SSepherosa Ziehau val = __SHIFTIN(10, ET_MAC_HDX_ALT_BEB_TRUNC) | 1041d217d4d9SSepherosa Ziehau __SHIFTIN(15, ET_MAC_HDX_REXMIT_MAX) | 1042d217d4d9SSepherosa Ziehau __SHIFTIN(55, ET_MAC_HDX_COLLWIN) | 1043d217d4d9SSepherosa Ziehau ET_MAC_HDX_EXC_DEFER; 1044d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_HDX, val); 1045d217d4d9SSepherosa Ziehau 1046d217d4d9SSepherosa Ziehau /* Clear MAC control */ 1047d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CTRL, 0); 1048d217d4d9SSepherosa Ziehau 1049d217d4d9SSepherosa Ziehau /* Reset MII */ 1050d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_CFG, ET_MII_CFG_CLKRST); 1051d217d4d9SSepherosa Ziehau 1052d217d4d9SSepherosa Ziehau /* Bring MAC out of reset state */ 1053d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG1, 0); 1054d217d4d9SSepherosa Ziehau 1055d217d4d9SSepherosa Ziehau /* Enable memory controllers */ 1056d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MMC_CTRL, ET_MMC_CTRL_ENABLE); 1057d217d4d9SSepherosa Ziehau } 1058d217d4d9SSepherosa Ziehau 1059d217d4d9SSepherosa Ziehau static void 1060d217d4d9SSepherosa Ziehau et_intr(void *xsc) 1061d217d4d9SSepherosa Ziehau { 1062d217d4d9SSepherosa Ziehau struct et_softc *sc = xsc; 1063d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1064d217d4d9SSepherosa Ziehau uint32_t intrs; 1065d217d4d9SSepherosa Ziehau 1066d217d4d9SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1067d217d4d9SSepherosa Ziehau 1068d217d4d9SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0) 1069d217d4d9SSepherosa Ziehau return; 1070d217d4d9SSepherosa Ziehau 1071d217d4d9SSepherosa Ziehau et_disable_intrs(sc); 1072d217d4d9SSepherosa Ziehau 1073d217d4d9SSepherosa Ziehau intrs = CSR_READ_4(sc, ET_INTR_STATUS); 1074d217d4d9SSepherosa Ziehau intrs &= ET_INTRS; 1075d217d4d9SSepherosa Ziehau if (intrs == 0) /* Not interested */ 1076d217d4d9SSepherosa Ziehau goto back; 1077d217d4d9SSepherosa Ziehau 1078d217d4d9SSepherosa Ziehau if (intrs & ET_INTR_RXEOF) 1079d217d4d9SSepherosa Ziehau et_rxeof(sc); 1080d217d4d9SSepherosa Ziehau if (intrs & (ET_INTR_TXEOF | ET_INTR_TIMER)) 1081136e59ffSSepherosa Ziehau et_txeof(sc, 1); 1082d217d4d9SSepherosa Ziehau if (intrs & ET_INTR_TIMER) 1083d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TIMER, sc->sc_timer); 1084d217d4d9SSepherosa Ziehau back: 1085d217d4d9SSepherosa Ziehau et_enable_intrs(sc, ET_INTRS); 1086d217d4d9SSepherosa Ziehau } 1087d217d4d9SSepherosa Ziehau 1088d217d4d9SSepherosa Ziehau static void 1089d217d4d9SSepherosa Ziehau et_init(void *xsc) 1090d217d4d9SSepherosa Ziehau { 1091d217d4d9SSepherosa Ziehau struct et_softc *sc = xsc; 1092d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1093d217d4d9SSepherosa Ziehau const struct et_bsize *arr; 1094d217d4d9SSepherosa Ziehau int error, i; 1095d217d4d9SSepherosa Ziehau 1096d217d4d9SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1097d217d4d9SSepherosa Ziehau 1098d217d4d9SSepherosa Ziehau et_stop(sc); 1099d217d4d9SSepherosa Ziehau 11003effc1bfSSepherosa Ziehau arr = ET_FRAMELEN(ifp->if_mtu) < MCLBYTES ? 11013effc1bfSSepherosa Ziehau et_bufsize_std : et_bufsize_jumbo; 1102d217d4d9SSepherosa Ziehau for (i = 0; i < ET_RX_NRING; ++i) { 1103d217d4d9SSepherosa Ziehau sc->sc_rx_data[i].rbd_bufsize = arr[i].bufsize; 1104d217d4d9SSepherosa Ziehau sc->sc_rx_data[i].rbd_newbuf = arr[i].newbuf; 11053effc1bfSSepherosa Ziehau sc->sc_rx_data[i].rbd_jumbo = arr[i].jumbo; 1106d217d4d9SSepherosa Ziehau } 1107d217d4d9SSepherosa Ziehau 1108d217d4d9SSepherosa Ziehau error = et_init_tx_ring(sc); 1109d217d4d9SSepherosa Ziehau if (error) 1110d217d4d9SSepherosa Ziehau goto back; 1111d217d4d9SSepherosa Ziehau 1112d217d4d9SSepherosa Ziehau error = et_init_rx_ring(sc); 1113d217d4d9SSepherosa Ziehau if (error) 1114d217d4d9SSepherosa Ziehau goto back; 1115d217d4d9SSepherosa Ziehau 1116d217d4d9SSepherosa Ziehau error = et_chip_init(sc); 1117d217d4d9SSepherosa Ziehau if (error) 1118d217d4d9SSepherosa Ziehau goto back; 1119d217d4d9SSepherosa Ziehau 112060d2de1fSSepherosa Ziehau error = et_enable_txrx(sc, 1); 1121d217d4d9SSepherosa Ziehau if (error) 1122d217d4d9SSepherosa Ziehau goto back; 1123d217d4d9SSepherosa Ziehau 1124d217d4d9SSepherosa Ziehau et_enable_intrs(sc, ET_INTRS); 1125d217d4d9SSepherosa Ziehau 1126d217d4d9SSepherosa Ziehau callout_reset(&sc->sc_tick, hz, et_tick, sc); 1127d217d4d9SSepherosa Ziehau 1128d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TIMER, sc->sc_timer); 1129d217d4d9SSepherosa Ziehau 1130d217d4d9SSepherosa Ziehau ifp->if_flags |= IFF_RUNNING; 1131*9ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 1132d217d4d9SSepherosa Ziehau back: 1133d217d4d9SSepherosa Ziehau if (error) 1134d217d4d9SSepherosa Ziehau et_stop(sc); 1135d217d4d9SSepherosa Ziehau } 1136d217d4d9SSepherosa Ziehau 1137d217d4d9SSepherosa Ziehau static int 1138d217d4d9SSepherosa Ziehau et_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) 1139d217d4d9SSepherosa Ziehau { 1140d217d4d9SSepherosa Ziehau struct et_softc *sc = ifp->if_softc; 1141d217d4d9SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->sc_miibus); 1142d217d4d9SSepherosa Ziehau struct ifreq *ifr = (struct ifreq *)data; 11433effc1bfSSepherosa Ziehau int error = 0, max_framelen; 1144d217d4d9SSepherosa Ziehau 1145d217d4d9SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1146d217d4d9SSepherosa Ziehau 1147d217d4d9SSepherosa Ziehau switch (cmd) { 1148d217d4d9SSepherosa Ziehau case SIOCSIFFLAGS: 1149d217d4d9SSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 1150d217d4d9SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 1151d217d4d9SSepherosa Ziehau if ((ifp->if_flags ^ sc->sc_if_flags) & 11525a5f28f3SSepherosa Ziehau (IFF_ALLMULTI | IFF_PROMISC)) 1153d217d4d9SSepherosa Ziehau et_setmulti(sc); 1154d217d4d9SSepherosa Ziehau } else { 1155d217d4d9SSepherosa Ziehau et_init(sc); 1156d217d4d9SSepherosa Ziehau } 1157d217d4d9SSepherosa Ziehau } else { 1158d217d4d9SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 1159d217d4d9SSepherosa Ziehau et_stop(sc); 1160d217d4d9SSepherosa Ziehau } 1161d217d4d9SSepherosa Ziehau sc->sc_if_flags = ifp->if_flags; 1162d217d4d9SSepherosa Ziehau break; 1163d217d4d9SSepherosa Ziehau 1164d217d4d9SSepherosa Ziehau case SIOCSIFMEDIA: 1165d217d4d9SSepherosa Ziehau case SIOCGIFMEDIA: 1166d217d4d9SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1167d217d4d9SSepherosa Ziehau break; 1168d217d4d9SSepherosa Ziehau 1169d217d4d9SSepherosa Ziehau case SIOCADDMULTI: 1170d217d4d9SSepherosa Ziehau case SIOCDELMULTI: 1171d217d4d9SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 1172d217d4d9SSepherosa Ziehau et_setmulti(sc); 1173d217d4d9SSepherosa Ziehau break; 1174d217d4d9SSepherosa Ziehau 1175d217d4d9SSepherosa Ziehau case SIOCSIFMTU: 11763effc1bfSSepherosa Ziehau if (sc->sc_flags & ET_FLAG_JUMBO) 11773effc1bfSSepherosa Ziehau max_framelen = ET_JUMBO_FRAMELEN; 11783effc1bfSSepherosa Ziehau else 11793effc1bfSSepherosa Ziehau max_framelen = MCLBYTES - 1; 11803effc1bfSSepherosa Ziehau 11813effc1bfSSepherosa Ziehau if (ET_FRAMELEN(ifr->ifr_mtu) > max_framelen) { 1182d217d4d9SSepherosa Ziehau error = EOPNOTSUPP; 1183d217d4d9SSepherosa Ziehau break; 11840fd7469eSSepherosa Ziehau } 11850fd7469eSSepherosa Ziehau 11860fd7469eSSepherosa Ziehau ifp->if_mtu = ifr->ifr_mtu; 11870fd7469eSSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 11880fd7469eSSepherosa Ziehau et_init(sc); 11890fd7469eSSepherosa Ziehau break; 1190d217d4d9SSepherosa Ziehau 1191d217d4d9SSepherosa Ziehau default: 1192d217d4d9SSepherosa Ziehau error = ether_ioctl(ifp, cmd, data); 1193d217d4d9SSepherosa Ziehau break; 1194d217d4d9SSepherosa Ziehau } 1195d217d4d9SSepherosa Ziehau return error; 1196d217d4d9SSepherosa Ziehau } 1197d217d4d9SSepherosa Ziehau 1198d217d4d9SSepherosa Ziehau static void 1199d217d4d9SSepherosa Ziehau et_start(struct ifnet *ifp) 1200d217d4d9SSepherosa Ziehau { 1201d217d4d9SSepherosa Ziehau struct et_softc *sc = ifp->if_softc; 1202d217d4d9SSepherosa Ziehau struct et_txbuf_data *tbd = &sc->sc_tx_data; 1203136e59ffSSepherosa Ziehau int trans, oactive; 1204d217d4d9SSepherosa Ziehau 1205d217d4d9SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1206d217d4d9SSepherosa Ziehau 12079db4b353SSepherosa Ziehau if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0) { 12089db4b353SSepherosa Ziehau ifq_purge(&ifp->if_snd); 120960d2de1fSSepherosa Ziehau return; 12109db4b353SSepherosa Ziehau } 121160d2de1fSSepherosa Ziehau 1212*9ed293e0SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0 || ifq_is_oactive(&ifp->if_snd)) 1213d217d4d9SSepherosa Ziehau return; 1214d217d4d9SSepherosa Ziehau 1215136e59ffSSepherosa Ziehau oactive = 0; 1216d217d4d9SSepherosa Ziehau trans = 0; 1217d217d4d9SSepherosa Ziehau for (;;) { 1218d217d4d9SSepherosa Ziehau struct mbuf *m; 1219136e59ffSSepherosa Ziehau int error; 1220d217d4d9SSepherosa Ziehau 1221d217d4d9SSepherosa Ziehau if ((tbd->tbd_used + ET_NSEG_SPARE) > ET_TX_NDESC) { 1222136e59ffSSepherosa Ziehau if (oactive) { 1223*9ed293e0SSepherosa Ziehau ifq_set_oactive(&ifp->if_snd); 1224d217d4d9SSepherosa Ziehau break; 1225d217d4d9SSepherosa Ziehau } 1226d217d4d9SSepherosa Ziehau 1227136e59ffSSepherosa Ziehau et_txeof(sc, 0); 1228136e59ffSSepherosa Ziehau oactive = 1; 1229136e59ffSSepherosa Ziehau continue; 1230136e59ffSSepherosa Ziehau } 1231136e59ffSSepherosa Ziehau 1232d217d4d9SSepherosa Ziehau m = ifq_dequeue(&ifp->if_snd, NULL); 1233d217d4d9SSepherosa Ziehau if (m == NULL) 1234d217d4d9SSepherosa Ziehau break; 1235d217d4d9SSepherosa Ziehau 1236136e59ffSSepherosa Ziehau error = et_encap(sc, &m); 1237136e59ffSSepherosa Ziehau if (error) { 1238d217d4d9SSepherosa Ziehau ifp->if_oerrors++; 1239136e59ffSSepherosa Ziehau KKASSERT(m == NULL); 1240136e59ffSSepherosa Ziehau 1241136e59ffSSepherosa Ziehau if (error == EFBIG) { 1242136e59ffSSepherosa Ziehau /* 1243136e59ffSSepherosa Ziehau * Excessive fragmented packets 1244136e59ffSSepherosa Ziehau */ 1245136e59ffSSepherosa Ziehau if (oactive) { 1246*9ed293e0SSepherosa Ziehau ifq_set_oactive(&ifp->if_snd); 1247d217d4d9SSepherosa Ziehau break; 1248d217d4d9SSepherosa Ziehau } 1249136e59ffSSepherosa Ziehau et_txeof(sc, 0); 1250136e59ffSSepherosa Ziehau oactive = 1; 1251136e59ffSSepherosa Ziehau } 1252136e59ffSSepherosa Ziehau continue; 1253136e59ffSSepherosa Ziehau } else { 1254136e59ffSSepherosa Ziehau oactive = 0; 1255136e59ffSSepherosa Ziehau } 1256d217d4d9SSepherosa Ziehau trans = 1; 1257d217d4d9SSepherosa Ziehau 1258d217d4d9SSepherosa Ziehau BPF_MTAP(ifp, m); 1259d217d4d9SSepherosa Ziehau } 1260d217d4d9SSepherosa Ziehau 1261d217d4d9SSepherosa Ziehau if (trans) 1262d217d4d9SSepherosa Ziehau ifp->if_timer = 5; 1263d217d4d9SSepherosa Ziehau } 1264d217d4d9SSepherosa Ziehau 1265d217d4d9SSepherosa Ziehau static void 1266d217d4d9SSepherosa Ziehau et_watchdog(struct ifnet *ifp) 1267d217d4d9SSepherosa Ziehau { 1268d217d4d9SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1269d217d4d9SSepherosa Ziehau 1270d217d4d9SSepherosa Ziehau if_printf(ifp, "watchdog timed out\n"); 1271d217d4d9SSepherosa Ziehau 1272d217d4d9SSepherosa Ziehau ifp->if_init(ifp->if_softc); 12739db4b353SSepherosa Ziehau if_devstart(ifp); 1274d217d4d9SSepherosa Ziehau } 1275d217d4d9SSepherosa Ziehau 1276d217d4d9SSepherosa Ziehau static int 1277d217d4d9SSepherosa Ziehau et_stop_rxdma(struct et_softc *sc) 1278d217d4d9SSepherosa Ziehau { 1279d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXDMA_CTRL, 1280d217d4d9SSepherosa Ziehau ET_RXDMA_CTRL_HALT | ET_RXDMA_CTRL_RING1_ENABLE); 1281d217d4d9SSepherosa Ziehau 1282d217d4d9SSepherosa Ziehau DELAY(5); 1283d217d4d9SSepherosa Ziehau if ((CSR_READ_4(sc, ET_RXDMA_CTRL) & ET_RXDMA_CTRL_HALTED) == 0) { 1284d217d4d9SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "can't stop RX DMA engine\n"); 1285d217d4d9SSepherosa Ziehau return ETIMEDOUT; 1286d217d4d9SSepherosa Ziehau } 1287d217d4d9SSepherosa Ziehau return 0; 1288d217d4d9SSepherosa Ziehau } 1289d217d4d9SSepherosa Ziehau 1290d217d4d9SSepherosa Ziehau static int 1291d217d4d9SSepherosa Ziehau et_stop_txdma(struct et_softc *sc) 1292d217d4d9SSepherosa Ziehau { 1293d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TXDMA_CTRL, 1294d217d4d9SSepherosa Ziehau ET_TXDMA_CTRL_HALT | ET_TXDMA_CTRL_SINGLE_EPKT); 1295d217d4d9SSepherosa Ziehau return 0; 1296d217d4d9SSepherosa Ziehau } 1297d217d4d9SSepherosa Ziehau 1298d217d4d9SSepherosa Ziehau static void 1299d217d4d9SSepherosa Ziehau et_free_tx_ring(struct et_softc *sc) 1300d217d4d9SSepherosa Ziehau { 1301d217d4d9SSepherosa Ziehau struct et_txbuf_data *tbd = &sc->sc_tx_data; 1302d217d4d9SSepherosa Ziehau struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 1303d217d4d9SSepherosa Ziehau int i; 1304d217d4d9SSepherosa Ziehau 1305d217d4d9SSepherosa Ziehau for (i = 0; i < ET_TX_NDESC; ++i) { 1306d217d4d9SSepherosa Ziehau struct et_txbuf *tb = &tbd->tbd_buf[i]; 1307d217d4d9SSepherosa Ziehau 1308d217d4d9SSepherosa Ziehau if (tb->tb_mbuf != NULL) { 13090fe5209eSSepherosa Ziehau bus_dmamap_unload(sc->sc_txbuf_dtag, tb->tb_dmap); 1310d217d4d9SSepherosa Ziehau m_freem(tb->tb_mbuf); 1311d217d4d9SSepherosa Ziehau tb->tb_mbuf = NULL; 1312d217d4d9SSepherosa Ziehau } 1313d217d4d9SSepherosa Ziehau } 1314d217d4d9SSepherosa Ziehau bzero(tx_ring->tr_desc, ET_TX_RING_SIZE); 1315d217d4d9SSepherosa Ziehau } 1316d217d4d9SSepherosa Ziehau 1317d217d4d9SSepherosa Ziehau static void 1318d217d4d9SSepherosa Ziehau et_free_rx_ring(struct et_softc *sc) 1319d217d4d9SSepherosa Ziehau { 1320d217d4d9SSepherosa Ziehau int n; 1321d217d4d9SSepherosa Ziehau 1322d217d4d9SSepherosa Ziehau for (n = 0; n < ET_RX_NRING; ++n) { 1323d217d4d9SSepherosa Ziehau struct et_rxbuf_data *rbd = &sc->sc_rx_data[n]; 1324d217d4d9SSepherosa Ziehau struct et_rxdesc_ring *rx_ring = &sc->sc_rx_ring[n]; 1325d217d4d9SSepherosa Ziehau int i; 1326d217d4d9SSepherosa Ziehau 1327d217d4d9SSepherosa Ziehau for (i = 0; i < ET_RX_NDESC; ++i) { 1328d217d4d9SSepherosa Ziehau struct et_rxbuf *rb = &rbd->rbd_buf[i]; 1329d217d4d9SSepherosa Ziehau 1330d217d4d9SSepherosa Ziehau if (rb->rb_mbuf != NULL) { 13313effc1bfSSepherosa Ziehau if (!rbd->rbd_jumbo) { 13320fe5209eSSepherosa Ziehau bus_dmamap_unload(sc->sc_rxbuf_dtag, 1333d217d4d9SSepherosa Ziehau rb->rb_dmap); 13343effc1bfSSepherosa Ziehau } 1335d217d4d9SSepherosa Ziehau m_freem(rb->rb_mbuf); 1336d217d4d9SSepherosa Ziehau rb->rb_mbuf = NULL; 1337d217d4d9SSepherosa Ziehau } 1338d217d4d9SSepherosa Ziehau } 1339d217d4d9SSepherosa Ziehau bzero(rx_ring->rr_desc, ET_RX_RING_SIZE); 1340d217d4d9SSepherosa Ziehau } 1341d217d4d9SSepherosa Ziehau } 1342d217d4d9SSepherosa Ziehau 1343d217d4d9SSepherosa Ziehau static void 1344d217d4d9SSepherosa Ziehau et_setmulti(struct et_softc *sc) 1345d217d4d9SSepherosa Ziehau { 1346d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1347d217d4d9SSepherosa Ziehau uint32_t hash[4] = { 0, 0, 0, 0 }; 1348d217d4d9SSepherosa Ziehau uint32_t rxmac_ctrl, pktfilt; 1349d217d4d9SSepherosa Ziehau struct ifmultiaddr *ifma; 1350d217d4d9SSepherosa Ziehau int i, count; 1351d217d4d9SSepherosa Ziehau 1352d217d4d9SSepherosa Ziehau pktfilt = CSR_READ_4(sc, ET_PKTFILT); 1353d217d4d9SSepherosa Ziehau rxmac_ctrl = CSR_READ_4(sc, ET_RXMAC_CTRL); 1354d217d4d9SSepherosa Ziehau 1355d217d4d9SSepherosa Ziehau pktfilt &= ~(ET_PKTFILT_BCAST | ET_PKTFILT_MCAST | ET_PKTFILT_UCAST); 1356d217d4d9SSepherosa Ziehau if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) { 1357d217d4d9SSepherosa Ziehau rxmac_ctrl |= ET_RXMAC_CTRL_NO_PKTFILT; 1358d217d4d9SSepherosa Ziehau goto back; 1359d217d4d9SSepherosa Ziehau } 1360d217d4d9SSepherosa Ziehau 1361d217d4d9SSepherosa Ziehau count = 0; 1362441d34b2SSascha Wildner TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1363d217d4d9SSepherosa Ziehau uint32_t *hp, h; 1364d217d4d9SSepherosa Ziehau 1365d217d4d9SSepherosa Ziehau if (ifma->ifma_addr->sa_family != AF_LINK) 1366d217d4d9SSepherosa Ziehau continue; 1367d217d4d9SSepherosa Ziehau 1368d217d4d9SSepherosa Ziehau h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 1369d217d4d9SSepherosa Ziehau ifma->ifma_addr), ETHER_ADDR_LEN); 1370d217d4d9SSepherosa Ziehau h = (h & 0x3f800000) >> 23; 1371d217d4d9SSepherosa Ziehau 1372d217d4d9SSepherosa Ziehau hp = &hash[0]; 1373d217d4d9SSepherosa Ziehau if (h >= 32 && h < 64) { 1374d217d4d9SSepherosa Ziehau h -= 32; 1375d217d4d9SSepherosa Ziehau hp = &hash[1]; 1376d217d4d9SSepherosa Ziehau } else if (h >= 64 && h < 96) { 1377d217d4d9SSepherosa Ziehau h -= 64; 1378d217d4d9SSepherosa Ziehau hp = &hash[2]; 1379d217d4d9SSepherosa Ziehau } else if (h >= 96) { 1380d217d4d9SSepherosa Ziehau h -= 96; 1381d217d4d9SSepherosa Ziehau hp = &hash[3]; 1382d217d4d9SSepherosa Ziehau } 1383d217d4d9SSepherosa Ziehau *hp |= (1 << h); 1384d217d4d9SSepherosa Ziehau 1385d217d4d9SSepherosa Ziehau ++count; 1386d217d4d9SSepherosa Ziehau } 1387d217d4d9SSepherosa Ziehau 1388d217d4d9SSepherosa Ziehau for (i = 0; i < 4; ++i) 1389d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MULTI_HASH + (i * 4), hash[i]); 1390d217d4d9SSepherosa Ziehau 1391d217d4d9SSepherosa Ziehau if (count > 0) 1392d217d4d9SSepherosa Ziehau pktfilt |= ET_PKTFILT_MCAST; 1393d217d4d9SSepherosa Ziehau rxmac_ctrl &= ~ET_RXMAC_CTRL_NO_PKTFILT; 1394d217d4d9SSepherosa Ziehau back: 1395d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_PKTFILT, pktfilt); 1396d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXMAC_CTRL, rxmac_ctrl); 1397d217d4d9SSepherosa Ziehau } 1398d217d4d9SSepherosa Ziehau 1399d217d4d9SSepherosa Ziehau static int 1400d217d4d9SSepherosa Ziehau et_chip_init(struct et_softc *sc) 1401d217d4d9SSepherosa Ziehau { 1402d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1403d217d4d9SSepherosa Ziehau uint32_t rxq_end; 14043effc1bfSSepherosa Ziehau int error, frame_len, rxmem_size; 1405d217d4d9SSepherosa Ziehau 1406d217d4d9SSepherosa Ziehau /* 14073effc1bfSSepherosa Ziehau * Split 16Kbytes internal memory between TX and RX 14083effc1bfSSepherosa Ziehau * according to frame length. 1409d217d4d9SSepherosa Ziehau */ 14103effc1bfSSepherosa Ziehau frame_len = ET_FRAMELEN(ifp->if_mtu); 14113effc1bfSSepherosa Ziehau if (frame_len < 2048) { 14123effc1bfSSepherosa Ziehau rxmem_size = ET_MEM_RXSIZE_DEFAULT; 14133effc1bfSSepherosa Ziehau } else if (frame_len <= ET_RXMAC_CUT_THRU_FRMLEN) { 14143effc1bfSSepherosa Ziehau rxmem_size = ET_MEM_SIZE / 2; 14153effc1bfSSepherosa Ziehau } else { 14163effc1bfSSepherosa Ziehau rxmem_size = ET_MEM_SIZE - 14173effc1bfSSepherosa Ziehau roundup(frame_len + ET_MEM_TXSIZE_EX, ET_MEM_UNIT); 14183effc1bfSSepherosa Ziehau } 14193effc1bfSSepherosa Ziehau rxq_end = ET_QUEUE_ADDR(rxmem_size); 14203effc1bfSSepherosa Ziehau 14213effc1bfSSepherosa Ziehau CSR_WRITE_4(sc, ET_RXQUEUE_START, ET_QUEUE_ADDR_START); 14223effc1bfSSepherosa Ziehau CSR_WRITE_4(sc, ET_RXQUEUE_END, rxq_end); 14233effc1bfSSepherosa Ziehau CSR_WRITE_4(sc, ET_TXQUEUE_START, rxq_end + 1); 14243effc1bfSSepherosa Ziehau CSR_WRITE_4(sc, ET_TXQUEUE_END, ET_QUEUE_ADDR_END); 1425d217d4d9SSepherosa Ziehau 1426d217d4d9SSepherosa Ziehau /* No loopback */ 1427d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_LOOPBACK, 0); 1428d217d4d9SSepherosa Ziehau 1429d217d4d9SSepherosa Ziehau /* Clear MSI configure */ 1430d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MSI_CFG, 0); 1431d217d4d9SSepherosa Ziehau 1432d217d4d9SSepherosa Ziehau /* Disable timer */ 1433d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TIMER, 0); 1434d217d4d9SSepherosa Ziehau 1435d217d4d9SSepherosa Ziehau /* Initialize MAC */ 1436d217d4d9SSepherosa Ziehau et_init_mac(sc); 1437d217d4d9SSepherosa Ziehau 1438d217d4d9SSepherosa Ziehau /* Enable memory controllers */ 1439d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MMC_CTRL, ET_MMC_CTRL_ENABLE); 1440d217d4d9SSepherosa Ziehau 1441d217d4d9SSepherosa Ziehau /* Initialize RX MAC */ 1442d217d4d9SSepherosa Ziehau et_init_rxmac(sc); 1443d217d4d9SSepherosa Ziehau 1444d217d4d9SSepherosa Ziehau /* Initialize TX MAC */ 1445d217d4d9SSepherosa Ziehau et_init_txmac(sc); 1446d217d4d9SSepherosa Ziehau 1447d217d4d9SSepherosa Ziehau /* Initialize RX DMA engine */ 1448d217d4d9SSepherosa Ziehau error = et_init_rxdma(sc); 1449d217d4d9SSepherosa Ziehau if (error) 1450d217d4d9SSepherosa Ziehau return error; 1451d217d4d9SSepherosa Ziehau 1452d217d4d9SSepherosa Ziehau /* Initialize TX DMA engine */ 1453d217d4d9SSepherosa Ziehau error = et_init_txdma(sc); 1454d217d4d9SSepherosa Ziehau if (error) 1455d217d4d9SSepherosa Ziehau return error; 1456d217d4d9SSepherosa Ziehau 1457d217d4d9SSepherosa Ziehau return 0; 1458d217d4d9SSepherosa Ziehau } 1459d217d4d9SSepherosa Ziehau 1460d217d4d9SSepherosa Ziehau static int 1461d217d4d9SSepherosa Ziehau et_init_tx_ring(struct et_softc *sc) 1462d217d4d9SSepherosa Ziehau { 1463d217d4d9SSepherosa Ziehau struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 1464d217d4d9SSepherosa Ziehau struct et_txstatus_data *txsd = &sc->sc_tx_status; 1465d217d4d9SSepherosa Ziehau struct et_txbuf_data *tbd = &sc->sc_tx_data; 1466d217d4d9SSepherosa Ziehau 1467d217d4d9SSepherosa Ziehau bzero(tx_ring->tr_desc, ET_TX_RING_SIZE); 1468d217d4d9SSepherosa Ziehau 1469d217d4d9SSepherosa Ziehau tbd->tbd_start_index = 0; 1470d217d4d9SSepherosa Ziehau tbd->tbd_start_wrap = 0; 1471d217d4d9SSepherosa Ziehau tbd->tbd_used = 0; 1472d217d4d9SSepherosa Ziehau 1473d217d4d9SSepherosa Ziehau bzero(txsd->txsd_status, sizeof(uint32_t)); 1474c2ebe33eSSepherosa Ziehau 1475d217d4d9SSepherosa Ziehau return 0; 1476d217d4d9SSepherosa Ziehau } 1477d217d4d9SSepherosa Ziehau 1478d217d4d9SSepherosa Ziehau static int 1479d217d4d9SSepherosa Ziehau et_init_rx_ring(struct et_softc *sc) 1480d217d4d9SSepherosa Ziehau { 1481d217d4d9SSepherosa Ziehau struct et_rxstatus_data *rxsd = &sc->sc_rx_status; 1482d217d4d9SSepherosa Ziehau struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring; 1483d217d4d9SSepherosa Ziehau int n; 1484d217d4d9SSepherosa Ziehau 1485d217d4d9SSepherosa Ziehau for (n = 0; n < ET_RX_NRING; ++n) { 1486d217d4d9SSepherosa Ziehau struct et_rxbuf_data *rbd = &sc->sc_rx_data[n]; 1487d217d4d9SSepherosa Ziehau int i, error; 1488d217d4d9SSepherosa Ziehau 1489d217d4d9SSepherosa Ziehau for (i = 0; i < ET_RX_NDESC; ++i) { 1490d217d4d9SSepherosa Ziehau error = rbd->rbd_newbuf(rbd, i, 1); 1491d217d4d9SSepherosa Ziehau if (error) { 1492d217d4d9SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "%d ring %d buf, " 1493d217d4d9SSepherosa Ziehau "newbuf failed: %d\n", n, i, error); 1494d217d4d9SSepherosa Ziehau return error; 1495d217d4d9SSepherosa Ziehau } 1496d217d4d9SSepherosa Ziehau } 1497d217d4d9SSepherosa Ziehau } 1498d217d4d9SSepherosa Ziehau 1499d217d4d9SSepherosa Ziehau bzero(rxsd->rxsd_status, sizeof(struct et_rxstatus)); 1500d217d4d9SSepherosa Ziehau bzero(rxst_ring->rsr_stat, ET_RXSTAT_RING_SIZE); 1501d217d4d9SSepherosa Ziehau 1502d217d4d9SSepherosa Ziehau return 0; 1503d217d4d9SSepherosa Ziehau } 1504d217d4d9SSepherosa Ziehau 1505d217d4d9SSepherosa Ziehau static int 1506d217d4d9SSepherosa Ziehau et_init_rxdma(struct et_softc *sc) 1507d217d4d9SSepherosa Ziehau { 1508d217d4d9SSepherosa Ziehau struct et_rxstatus_data *rxsd = &sc->sc_rx_status; 1509d217d4d9SSepherosa Ziehau struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring; 1510d217d4d9SSepherosa Ziehau struct et_rxdesc_ring *rx_ring; 1511d217d4d9SSepherosa Ziehau int error; 1512d217d4d9SSepherosa Ziehau 1513d217d4d9SSepherosa Ziehau error = et_stop_rxdma(sc); 1514d217d4d9SSepherosa Ziehau if (error) { 1515d217d4d9SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "can't init RX DMA engine\n"); 1516d217d4d9SSepherosa Ziehau return error; 1517d217d4d9SSepherosa Ziehau } 1518d217d4d9SSepherosa Ziehau 1519d217d4d9SSepherosa Ziehau /* 1520d217d4d9SSepherosa Ziehau * Install RX status 1521d217d4d9SSepherosa Ziehau */ 1522d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_STATUS_HI, ET_ADDR_HI(rxsd->rxsd_paddr)); 1523d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_STATUS_LO, ET_ADDR_LO(rxsd->rxsd_paddr)); 1524d217d4d9SSepherosa Ziehau 1525d217d4d9SSepherosa Ziehau /* 1526d217d4d9SSepherosa Ziehau * Install RX stat ring 1527d217d4d9SSepherosa Ziehau */ 1528d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXSTAT_HI, ET_ADDR_HI(rxst_ring->rsr_paddr)); 1529d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXSTAT_LO, ET_ADDR_LO(rxst_ring->rsr_paddr)); 1530d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXSTAT_CNT, ET_RX_NSTAT - 1); 1531d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXSTAT_POS, 0); 1532d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXSTAT_MINCNT, ((ET_RX_NSTAT * 15) / 100) - 1); 1533d217d4d9SSepherosa Ziehau 1534d217d4d9SSepherosa Ziehau /* Match ET_RXSTAT_POS */ 1535d217d4d9SSepherosa Ziehau rxst_ring->rsr_index = 0; 1536d217d4d9SSepherosa Ziehau rxst_ring->rsr_wrap = 0; 1537d217d4d9SSepherosa Ziehau 1538d217d4d9SSepherosa Ziehau /* 1539d217d4d9SSepherosa Ziehau * Install the 2nd RX descriptor ring 1540d217d4d9SSepherosa Ziehau */ 1541d217d4d9SSepherosa Ziehau rx_ring = &sc->sc_rx_ring[1]; 1542d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING1_HI, ET_ADDR_HI(rx_ring->rr_paddr)); 1543d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING1_LO, ET_ADDR_LO(rx_ring->rr_paddr)); 1544d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING1_CNT, ET_RX_NDESC - 1); 1545d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING1_POS, ET_RX_RING1_POS_WRAP); 1546d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING1_MINCNT, ((ET_RX_NDESC * 15) / 100) - 1); 1547d217d4d9SSepherosa Ziehau 1548d217d4d9SSepherosa Ziehau /* Match ET_RX_RING1_POS */ 1549d217d4d9SSepherosa Ziehau rx_ring->rr_index = 0; 1550d217d4d9SSepherosa Ziehau rx_ring->rr_wrap = 1; 1551d217d4d9SSepherosa Ziehau 1552d217d4d9SSepherosa Ziehau /* 1553d217d4d9SSepherosa Ziehau * Install the 1st RX descriptor ring 1554d217d4d9SSepherosa Ziehau */ 1555d217d4d9SSepherosa Ziehau rx_ring = &sc->sc_rx_ring[0]; 1556d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING0_HI, ET_ADDR_HI(rx_ring->rr_paddr)); 1557d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING0_LO, ET_ADDR_LO(rx_ring->rr_paddr)); 1558d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING0_CNT, ET_RX_NDESC - 1); 1559d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING0_POS, ET_RX_RING0_POS_WRAP); 1560d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_RING0_MINCNT, ((ET_RX_NDESC * 15) / 100) - 1); 1561d217d4d9SSepherosa Ziehau 1562d217d4d9SSepherosa Ziehau /* Match ET_RX_RING0_POS */ 1563d217d4d9SSepherosa Ziehau rx_ring->rr_index = 0; 1564d217d4d9SSepherosa Ziehau rx_ring->rr_wrap = 1; 1565d217d4d9SSepherosa Ziehau 1566d217d4d9SSepherosa Ziehau /* 1567d217d4d9SSepherosa Ziehau * RX intr moderation 1568d217d4d9SSepherosa Ziehau */ 1569d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_INTR_NPKTS, sc->sc_rx_intr_npkts); 1570d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_INTR_DELAY, sc->sc_rx_intr_delay); 1571d217d4d9SSepherosa Ziehau 1572d217d4d9SSepherosa Ziehau return 0; 1573d217d4d9SSepherosa Ziehau } 1574d217d4d9SSepherosa Ziehau 1575d217d4d9SSepherosa Ziehau static int 1576d217d4d9SSepherosa Ziehau et_init_txdma(struct et_softc *sc) 1577d217d4d9SSepherosa Ziehau { 1578d217d4d9SSepherosa Ziehau struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 1579d217d4d9SSepherosa Ziehau struct et_txstatus_data *txsd = &sc->sc_tx_status; 1580d217d4d9SSepherosa Ziehau int error; 1581d217d4d9SSepherosa Ziehau 1582d217d4d9SSepherosa Ziehau error = et_stop_txdma(sc); 1583d217d4d9SSepherosa Ziehau if (error) { 1584d217d4d9SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "can't init TX DMA engine\n"); 1585d217d4d9SSepherosa Ziehau return error; 1586d217d4d9SSepherosa Ziehau } 1587d217d4d9SSepherosa Ziehau 1588d217d4d9SSepherosa Ziehau /* 1589d217d4d9SSepherosa Ziehau * Install TX descriptor ring 1590d217d4d9SSepherosa Ziehau */ 1591d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TX_RING_HI, ET_ADDR_HI(tx_ring->tr_paddr)); 1592d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TX_RING_LO, ET_ADDR_LO(tx_ring->tr_paddr)); 1593d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TX_RING_CNT, ET_TX_NDESC - 1); 1594d217d4d9SSepherosa Ziehau 1595d217d4d9SSepherosa Ziehau /* 1596d217d4d9SSepherosa Ziehau * Install TX status 1597d217d4d9SSepherosa Ziehau */ 1598d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TX_STATUS_HI, ET_ADDR_HI(txsd->txsd_paddr)); 1599d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TX_STATUS_LO, ET_ADDR_LO(txsd->txsd_paddr)); 1600d217d4d9SSepherosa Ziehau 1601d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TX_READY_POS, 0); 1602d217d4d9SSepherosa Ziehau 1603d217d4d9SSepherosa Ziehau /* Match ET_TX_READY_POS */ 1604d217d4d9SSepherosa Ziehau tx_ring->tr_ready_index = 0; 1605d217d4d9SSepherosa Ziehau tx_ring->tr_ready_wrap = 0; 1606d217d4d9SSepherosa Ziehau 1607d217d4d9SSepherosa Ziehau return 0; 1608d217d4d9SSepherosa Ziehau } 1609d217d4d9SSepherosa Ziehau 1610d217d4d9SSepherosa Ziehau static void 1611d217d4d9SSepherosa Ziehau et_init_mac(struct et_softc *sc) 1612d217d4d9SSepherosa Ziehau { 1613d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1614d217d4d9SSepherosa Ziehau const uint8_t *eaddr = IF_LLADDR(ifp); 1615d217d4d9SSepherosa Ziehau uint32_t val; 1616d217d4d9SSepherosa Ziehau 1617d217d4d9SSepherosa Ziehau /* Reset MAC */ 1618d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG1, 1619d217d4d9SSepherosa Ziehau ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 1620d217d4d9SSepherosa Ziehau ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | 1621d217d4d9SSepherosa Ziehau ET_MAC_CFG1_SIM_RST | ET_MAC_CFG1_SOFT_RST); 1622d217d4d9SSepherosa Ziehau 1623d217d4d9SSepherosa Ziehau /* 1624d217d4d9SSepherosa Ziehau * Setup inter packet gap 1625d217d4d9SSepherosa Ziehau */ 1626d217d4d9SSepherosa Ziehau val = __SHIFTIN(56, ET_IPG_NONB2B_1) | 1627d217d4d9SSepherosa Ziehau __SHIFTIN(88, ET_IPG_NONB2B_2) | 1628d217d4d9SSepherosa Ziehau __SHIFTIN(80, ET_IPG_MINIFG) | 1629d217d4d9SSepherosa Ziehau __SHIFTIN(96, ET_IPG_B2B); 1630d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_IPG, val); 1631d217d4d9SSepherosa Ziehau 1632d217d4d9SSepherosa Ziehau /* 1633d217d4d9SSepherosa Ziehau * Setup half duplex mode 1634d217d4d9SSepherosa Ziehau */ 1635d217d4d9SSepherosa Ziehau val = __SHIFTIN(10, ET_MAC_HDX_ALT_BEB_TRUNC) | 1636d217d4d9SSepherosa Ziehau __SHIFTIN(15, ET_MAC_HDX_REXMIT_MAX) | 1637d217d4d9SSepherosa Ziehau __SHIFTIN(55, ET_MAC_HDX_COLLWIN) | 1638d217d4d9SSepherosa Ziehau ET_MAC_HDX_EXC_DEFER; 1639d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_HDX, val); 1640d217d4d9SSepherosa Ziehau 1641d217d4d9SSepherosa Ziehau /* Clear MAC control */ 1642d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CTRL, 0); 1643d217d4d9SSepherosa Ziehau 1644d217d4d9SSepherosa Ziehau /* Reset MII */ 1645d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MII_CFG, ET_MII_CFG_CLKRST); 1646d217d4d9SSepherosa Ziehau 1647d217d4d9SSepherosa Ziehau /* 1648d217d4d9SSepherosa Ziehau * Set MAC address 1649d217d4d9SSepherosa Ziehau */ 1650d217d4d9SSepherosa Ziehau val = eaddr[2] | (eaddr[3] << 8) | (eaddr[4] << 16) | (eaddr[5] << 24); 1651d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_ADDR1, val); 1652d217d4d9SSepherosa Ziehau val = (eaddr[0] << 16) | (eaddr[1] << 24); 1653d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_ADDR2, val); 1654d217d4d9SSepherosa Ziehau 1655d217d4d9SSepherosa Ziehau /* Set max frame length */ 16560fd7469eSSepherosa Ziehau CSR_WRITE_4(sc, ET_MAX_FRMLEN, ET_FRAMELEN(ifp->if_mtu)); 1657d217d4d9SSepherosa Ziehau 1658d217d4d9SSepherosa Ziehau /* Bring MAC out of reset state */ 1659d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG1, 0); 1660d217d4d9SSepherosa Ziehau } 1661d217d4d9SSepherosa Ziehau 1662d217d4d9SSepherosa Ziehau static void 1663d217d4d9SSepherosa Ziehau et_init_rxmac(struct et_softc *sc) 1664d217d4d9SSepherosa Ziehau { 1665d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1666d217d4d9SSepherosa Ziehau const uint8_t *eaddr = IF_LLADDR(ifp); 1667d217d4d9SSepherosa Ziehau uint32_t val; 1668d217d4d9SSepherosa Ziehau int i; 1669d217d4d9SSepherosa Ziehau 1670d217d4d9SSepherosa Ziehau /* Disable RX MAC and WOL */ 1671d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXMAC_CTRL, ET_RXMAC_CTRL_WOL_DISABLE); 1672d217d4d9SSepherosa Ziehau 1673d217d4d9SSepherosa Ziehau /* 1674d217d4d9SSepherosa Ziehau * Clear all WOL related registers 1675d217d4d9SSepherosa Ziehau */ 1676d217d4d9SSepherosa Ziehau for (i = 0; i < 3; ++i) 1677d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_WOL_CRC + (i * 4), 0); 1678d217d4d9SSepherosa Ziehau for (i = 0; i < 20; ++i) 1679d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_WOL_MASK + (i * 4), 0); 1680d217d4d9SSepherosa Ziehau 1681d217d4d9SSepherosa Ziehau /* 1682d217d4d9SSepherosa Ziehau * Set WOL source address. XXX is this necessary? 1683d217d4d9SSepherosa Ziehau */ 1684d217d4d9SSepherosa Ziehau val = (eaddr[2] << 24) | (eaddr[3] << 16) | (eaddr[4] << 8) | eaddr[5]; 1685d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_WOL_SA_LO, val); 1686d217d4d9SSepherosa Ziehau val = (eaddr[0] << 8) | eaddr[1]; 1687d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_WOL_SA_HI, val); 1688d217d4d9SSepherosa Ziehau 1689d217d4d9SSepherosa Ziehau /* Clear packet filters */ 1690d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_PKTFILT, 0); 1691d217d4d9SSepherosa Ziehau 1692d217d4d9SSepherosa Ziehau /* No ucast filtering */ 1693d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_UCAST_FILTADDR1, 0); 1694d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_UCAST_FILTADDR2, 0); 1695d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_UCAST_FILTADDR3, 0); 1696d217d4d9SSepherosa Ziehau 16973effc1bfSSepherosa Ziehau if (ET_FRAMELEN(ifp->if_mtu) > ET_RXMAC_CUT_THRU_FRMLEN) { 1698d217d4d9SSepherosa Ziehau /* 16993effc1bfSSepherosa Ziehau * In order to transmit jumbo packets greater than 17003effc1bfSSepherosa Ziehau * ET_RXMAC_CUT_THRU_FRMLEN bytes, the FIFO between 17013effc1bfSSepherosa Ziehau * RX MAC and RX DMA needs to be reduced in size to 17023effc1bfSSepherosa Ziehau * (ET_MEM_SIZE - ET_MEM_TXSIZE_EX - framelen). In 17033effc1bfSSepherosa Ziehau * order to implement this, we must use "cut through" 17043effc1bfSSepherosa Ziehau * mode in the RX MAC, which chops packets down into 17053effc1bfSSepherosa Ziehau * segments. In this case we selected 256 bytes, 17063effc1bfSSepherosa Ziehau * since this is the size of the PCI-Express TLP's 17073effc1bfSSepherosa Ziehau * that the ET1310 uses. 1708d217d4d9SSepherosa Ziehau */ 17093effc1bfSSepherosa Ziehau val = __SHIFTIN(ET_RXMAC_SEGSZ(256), ET_RXMAC_MC_SEGSZ_MAX) | 1710d217d4d9SSepherosa Ziehau ET_RXMAC_MC_SEGSZ_ENABLE; 1711d217d4d9SSepherosa Ziehau } else { 1712d217d4d9SSepherosa Ziehau val = 0; 1713d217d4d9SSepherosa Ziehau } 1714d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXMAC_MC_SEGSZ, val); 1715d217d4d9SSepherosa Ziehau 1716d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXMAC_MC_WATERMARK, 0); 1717d217d4d9SSepherosa Ziehau 1718d217d4d9SSepherosa Ziehau /* Initialize RX MAC management register */ 1719d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXMAC_MGT, 0); 1720d217d4d9SSepherosa Ziehau 1721d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXMAC_SPACE_AVL, 0); 1722d217d4d9SSepherosa Ziehau 1723d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXMAC_MGT, 1724d217d4d9SSepherosa Ziehau ET_RXMAC_MGT_PASS_ECRC | 1725d217d4d9SSepherosa Ziehau ET_RXMAC_MGT_PASS_ELEN | 1726d217d4d9SSepherosa Ziehau ET_RXMAC_MGT_PASS_ETRUNC | 1727d217d4d9SSepherosa Ziehau ET_RXMAC_MGT_CHECK_PKT); 1728d217d4d9SSepherosa Ziehau 1729d217d4d9SSepherosa Ziehau /* 1730d217d4d9SSepherosa Ziehau * Configure runt filtering (may not work on certain chip generation) 1731d217d4d9SSepherosa Ziehau */ 1732d217d4d9SSepherosa Ziehau val = __SHIFTIN(ETHER_MIN_LEN, ET_PKTFILT_MINLEN) | ET_PKTFILT_FRAG; 1733d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_PKTFILT, val); 1734d217d4d9SSepherosa Ziehau 1735d217d4d9SSepherosa Ziehau /* Enable RX MAC but leave WOL disabled */ 1736d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXMAC_CTRL, 1737d217d4d9SSepherosa Ziehau ET_RXMAC_CTRL_WOL_DISABLE | ET_RXMAC_CTRL_ENABLE); 1738d217d4d9SSepherosa Ziehau 1739d217d4d9SSepherosa Ziehau /* 1740d217d4d9SSepherosa Ziehau * Setup multicast hash and allmulti/promisc mode 1741d217d4d9SSepherosa Ziehau */ 1742d217d4d9SSepherosa Ziehau et_setmulti(sc); 1743d217d4d9SSepherosa Ziehau } 1744d217d4d9SSepherosa Ziehau 1745d217d4d9SSepherosa Ziehau static void 1746d217d4d9SSepherosa Ziehau et_init_txmac(struct et_softc *sc) 1747d217d4d9SSepherosa Ziehau { 1748d217d4d9SSepherosa Ziehau /* Disable TX MAC and FC(?) */ 1749d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TXMAC_CTRL, ET_TXMAC_CTRL_FC_DISABLE); 1750d217d4d9SSepherosa Ziehau 1751d217d4d9SSepherosa Ziehau /* No flow control yet */ 1752d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TXMAC_FLOWCTRL, 0); 1753d217d4d9SSepherosa Ziehau 1754d217d4d9SSepherosa Ziehau /* Enable TX MAC but leave FC(?) diabled */ 1755d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TXMAC_CTRL, 1756d217d4d9SSepherosa Ziehau ET_TXMAC_CTRL_ENABLE | ET_TXMAC_CTRL_FC_DISABLE); 1757d217d4d9SSepherosa Ziehau } 1758d217d4d9SSepherosa Ziehau 1759d217d4d9SSepherosa Ziehau static int 1760d217d4d9SSepherosa Ziehau et_start_rxdma(struct et_softc *sc) 1761d217d4d9SSepherosa Ziehau { 1762d217d4d9SSepherosa Ziehau uint32_t val = 0; 1763d217d4d9SSepherosa Ziehau 1764d217d4d9SSepherosa Ziehau val |= __SHIFTIN(sc->sc_rx_data[0].rbd_bufsize, 1765d217d4d9SSepherosa Ziehau ET_RXDMA_CTRL_RING0_SIZE) | 1766d217d4d9SSepherosa Ziehau ET_RXDMA_CTRL_RING0_ENABLE; 1767d217d4d9SSepherosa Ziehau val |= __SHIFTIN(sc->sc_rx_data[1].rbd_bufsize, 1768d217d4d9SSepherosa Ziehau ET_RXDMA_CTRL_RING1_SIZE) | 1769d217d4d9SSepherosa Ziehau ET_RXDMA_CTRL_RING1_ENABLE; 1770d217d4d9SSepherosa Ziehau 1771d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXDMA_CTRL, val); 1772d217d4d9SSepherosa Ziehau 1773d217d4d9SSepherosa Ziehau DELAY(5); 1774d217d4d9SSepherosa Ziehau 1775d217d4d9SSepherosa Ziehau if (CSR_READ_4(sc, ET_RXDMA_CTRL) & ET_RXDMA_CTRL_HALTED) { 1776d217d4d9SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "can't start RX DMA engine\n"); 1777d217d4d9SSepherosa Ziehau return ETIMEDOUT; 1778d217d4d9SSepherosa Ziehau } 1779d217d4d9SSepherosa Ziehau return 0; 1780d217d4d9SSepherosa Ziehau } 1781d217d4d9SSepherosa Ziehau 1782d217d4d9SSepherosa Ziehau static int 1783d217d4d9SSepherosa Ziehau et_start_txdma(struct et_softc *sc) 1784d217d4d9SSepherosa Ziehau { 1785d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TXDMA_CTRL, ET_TXDMA_CTRL_SINGLE_EPKT); 1786d217d4d9SSepherosa Ziehau return 0; 1787d217d4d9SSepherosa Ziehau } 1788d217d4d9SSepherosa Ziehau 1789d217d4d9SSepherosa Ziehau static int 179060d2de1fSSepherosa Ziehau et_enable_txrx(struct et_softc *sc, int media_upd) 1791d217d4d9SSepherosa Ziehau { 1792d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1793d217d4d9SSepherosa Ziehau uint32_t val; 179460d2de1fSSepherosa Ziehau int i, error; 1795d217d4d9SSepherosa Ziehau 1796d217d4d9SSepherosa Ziehau val = CSR_READ_4(sc, ET_MAC_CFG1); 1797d217d4d9SSepherosa Ziehau val |= ET_MAC_CFG1_TXEN | ET_MAC_CFG1_RXEN; 1798d217d4d9SSepherosa Ziehau val &= ~(ET_MAC_CFG1_TXFLOW | ET_MAC_CFG1_RXFLOW | 1799d217d4d9SSepherosa Ziehau ET_MAC_CFG1_LOOPBACK); 1800d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG1, val); 1801d217d4d9SSepherosa Ziehau 180260d2de1fSSepherosa Ziehau if (media_upd) 1803d217d4d9SSepherosa Ziehau et_ifmedia_upd(ifp); 180460d2de1fSSepherosa Ziehau else 180560d2de1fSSepherosa Ziehau et_setmedia(sc); 1806d217d4d9SSepherosa Ziehau 1807d217d4d9SSepherosa Ziehau #define NRETRY 100 1808d217d4d9SSepherosa Ziehau 1809d217d4d9SSepherosa Ziehau for (i = 0; i < NRETRY; ++i) { 1810d217d4d9SSepherosa Ziehau val = CSR_READ_4(sc, ET_MAC_CFG1); 1811d217d4d9SSepherosa Ziehau if ((val & (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) == 1812d217d4d9SSepherosa Ziehau (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) 1813d217d4d9SSepherosa Ziehau break; 1814d217d4d9SSepherosa Ziehau 1815d217d4d9SSepherosa Ziehau DELAY(10); 1816d217d4d9SSepherosa Ziehau } 1817d217d4d9SSepherosa Ziehau if (i == NRETRY) { 1818d217d4d9SSepherosa Ziehau if_printf(ifp, "can't enable RX/TX\n"); 181960d2de1fSSepherosa Ziehau return 0; 1820d217d4d9SSepherosa Ziehau } 18213effc1bfSSepherosa Ziehau sc->sc_flags |= ET_FLAG_TXRX_ENABLED; 1822d217d4d9SSepherosa Ziehau 1823d217d4d9SSepherosa Ziehau #undef NRETRY 182460d2de1fSSepherosa Ziehau 182560d2de1fSSepherosa Ziehau /* 182660d2de1fSSepherosa Ziehau * Start TX/RX DMA engine 182760d2de1fSSepherosa Ziehau */ 182860d2de1fSSepherosa Ziehau error = et_start_rxdma(sc); 182960d2de1fSSepherosa Ziehau if (error) 183060d2de1fSSepherosa Ziehau return error; 183160d2de1fSSepherosa Ziehau 183260d2de1fSSepherosa Ziehau error = et_start_txdma(sc); 183360d2de1fSSepherosa Ziehau if (error) 183460d2de1fSSepherosa Ziehau return error; 183560d2de1fSSepherosa Ziehau 1836d217d4d9SSepherosa Ziehau return 0; 1837d217d4d9SSepherosa Ziehau } 1838d217d4d9SSepherosa Ziehau 1839d217d4d9SSepherosa Ziehau static void 1840d217d4d9SSepherosa Ziehau et_rxeof(struct et_softc *sc) 1841d217d4d9SSepherosa Ziehau { 1842d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1843d217d4d9SSepherosa Ziehau struct et_rxstatus_data *rxsd = &sc->sc_rx_status; 1844d217d4d9SSepherosa Ziehau struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring; 1845d217d4d9SSepherosa Ziehau uint32_t rxs_stat_ring; 1846d217d4d9SSepherosa Ziehau int rxst_wrap, rxst_index; 1847d217d4d9SSepherosa Ziehau 18483effc1bfSSepherosa Ziehau if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0) 184960d2de1fSSepherosa Ziehau return; 185060d2de1fSSepherosa Ziehau 1851d217d4d9SSepherosa Ziehau rxs_stat_ring = rxsd->rxsd_status->rxs_stat_ring; 1852d217d4d9SSepherosa Ziehau rxst_wrap = (rxs_stat_ring & ET_RXS_STATRING_WRAP) ? 1 : 0; 1853d217d4d9SSepherosa Ziehau rxst_index = __SHIFTOUT(rxs_stat_ring, ET_RXS_STATRING_INDEX); 1854d217d4d9SSepherosa Ziehau 1855d217d4d9SSepherosa Ziehau while (rxst_index != rxst_ring->rsr_index || 1856d217d4d9SSepherosa Ziehau rxst_wrap != rxst_ring->rsr_wrap) { 1857d217d4d9SSepherosa Ziehau struct et_rxbuf_data *rbd; 1858d217d4d9SSepherosa Ziehau struct et_rxdesc_ring *rx_ring; 1859d217d4d9SSepherosa Ziehau struct et_rxstat *st; 1860d217d4d9SSepherosa Ziehau struct mbuf *m; 1861d217d4d9SSepherosa Ziehau int buflen, buf_idx, ring_idx; 1862d217d4d9SSepherosa Ziehau uint32_t rxstat_pos, rxring_pos; 1863d217d4d9SSepherosa Ziehau 1864d217d4d9SSepherosa Ziehau KKASSERT(rxst_ring->rsr_index < ET_RX_NSTAT); 1865d217d4d9SSepherosa Ziehau st = &rxst_ring->rsr_stat[rxst_ring->rsr_index]; 1866d217d4d9SSepherosa Ziehau 1867d217d4d9SSepherosa Ziehau buflen = __SHIFTOUT(st->rxst_info2, ET_RXST_INFO2_LEN); 1868d217d4d9SSepherosa Ziehau buf_idx = __SHIFTOUT(st->rxst_info2, ET_RXST_INFO2_BUFIDX); 1869d217d4d9SSepherosa Ziehau ring_idx = __SHIFTOUT(st->rxst_info2, ET_RXST_INFO2_RINGIDX); 1870d217d4d9SSepherosa Ziehau 1871d217d4d9SSepherosa Ziehau if (++rxst_ring->rsr_index == ET_RX_NSTAT) { 1872d217d4d9SSepherosa Ziehau rxst_ring->rsr_index = 0; 1873d217d4d9SSepherosa Ziehau rxst_ring->rsr_wrap ^= 1; 1874d217d4d9SSepherosa Ziehau } 1875d217d4d9SSepherosa Ziehau rxstat_pos = __SHIFTIN(rxst_ring->rsr_index, 1876d217d4d9SSepherosa Ziehau ET_RXSTAT_POS_INDEX); 1877d217d4d9SSepherosa Ziehau if (rxst_ring->rsr_wrap) 1878d217d4d9SSepherosa Ziehau rxstat_pos |= ET_RXSTAT_POS_WRAP; 1879d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RXSTAT_POS, rxstat_pos); 1880d217d4d9SSepherosa Ziehau 1881d217d4d9SSepherosa Ziehau if (ring_idx >= ET_RX_NRING) { 1882d217d4d9SSepherosa Ziehau ifp->if_ierrors++; 1883d217d4d9SSepherosa Ziehau if_printf(ifp, "invalid ring index %d\n", ring_idx); 1884d217d4d9SSepherosa Ziehau continue; 1885d217d4d9SSepherosa Ziehau } 1886d217d4d9SSepherosa Ziehau if (buf_idx >= ET_RX_NDESC) { 1887d217d4d9SSepherosa Ziehau ifp->if_ierrors++; 1888d217d4d9SSepherosa Ziehau if_printf(ifp, "invalid buf index %d\n", buf_idx); 1889d217d4d9SSepherosa Ziehau continue; 1890d217d4d9SSepherosa Ziehau } 1891d217d4d9SSepherosa Ziehau 1892d217d4d9SSepherosa Ziehau rbd = &sc->sc_rx_data[ring_idx]; 18933effc1bfSSepherosa Ziehau m = rbd->rbd_buf[buf_idx].rb_mbuf; 1894d217d4d9SSepherosa Ziehau 1895d217d4d9SSepherosa Ziehau if (rbd->rbd_newbuf(rbd, buf_idx, 0) == 0) { 18960fd7469eSSepherosa Ziehau if (buflen < ETHER_CRC_LEN) { 18970fd7469eSSepherosa Ziehau m_freem(m); 18980fd7469eSSepherosa Ziehau ifp->if_ierrors++; 18990fd7469eSSepherosa Ziehau } else { 1900d217d4d9SSepherosa Ziehau m->m_pkthdr.len = m->m_len = buflen; 1901d217d4d9SSepherosa Ziehau m->m_pkthdr.rcvif = ifp; 1902d217d4d9SSepherosa Ziehau 19030fd7469eSSepherosa Ziehau m_adj(m, -ETHER_CRC_LEN); 19040fd7469eSSepherosa Ziehau 1905d217d4d9SSepherosa Ziehau ifp->if_ipackets++; 1906eda7db08SSepherosa Ziehau ifp->if_input(ifp, m); 19070fd7469eSSepherosa Ziehau } 1908d217d4d9SSepherosa Ziehau } else { 1909d217d4d9SSepherosa Ziehau ifp->if_ierrors++; 1910d217d4d9SSepherosa Ziehau } 19110fd7469eSSepherosa Ziehau m = NULL; /* Catch invalid reference */ 1912d217d4d9SSepherosa Ziehau 1913d217d4d9SSepherosa Ziehau rx_ring = &sc->sc_rx_ring[ring_idx]; 1914d217d4d9SSepherosa Ziehau 1915d217d4d9SSepherosa Ziehau if (buf_idx != rx_ring->rr_index) { 1916d217d4d9SSepherosa Ziehau if_printf(ifp, "WARNING!! ring %d, " 1917d217d4d9SSepherosa Ziehau "buf_idx %d, rr_idx %d\n", 1918d217d4d9SSepherosa Ziehau ring_idx, buf_idx, rx_ring->rr_index); 1919d217d4d9SSepherosa Ziehau } 1920d217d4d9SSepherosa Ziehau 1921d217d4d9SSepherosa Ziehau KKASSERT(rx_ring->rr_index < ET_RX_NDESC); 1922d217d4d9SSepherosa Ziehau if (++rx_ring->rr_index == ET_RX_NDESC) { 1923d217d4d9SSepherosa Ziehau rx_ring->rr_index = 0; 1924d217d4d9SSepherosa Ziehau rx_ring->rr_wrap ^= 1; 1925d217d4d9SSepherosa Ziehau } 1926d217d4d9SSepherosa Ziehau rxring_pos = __SHIFTIN(rx_ring->rr_index, ET_RX_RING_POS_INDEX); 1927d217d4d9SSepherosa Ziehau if (rx_ring->rr_wrap) 1928d217d4d9SSepherosa Ziehau rxring_pos |= ET_RX_RING_POS_WRAP; 1929d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, rx_ring->rr_posreg, rxring_pos); 1930d217d4d9SSepherosa Ziehau } 1931d217d4d9SSepherosa Ziehau } 1932d217d4d9SSepherosa Ziehau 1933d217d4d9SSepherosa Ziehau static int 1934d217d4d9SSepherosa Ziehau et_encap(struct et_softc *sc, struct mbuf **m0) 1935d217d4d9SSepherosa Ziehau { 1936d217d4d9SSepherosa Ziehau bus_dma_segment_t segs[ET_NSEG_MAX]; 1937d217d4d9SSepherosa Ziehau struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 1938d217d4d9SSepherosa Ziehau struct et_txbuf_data *tbd = &sc->sc_tx_data; 1939d217d4d9SSepherosa Ziehau struct et_txdesc *td; 1940d217d4d9SSepherosa Ziehau bus_dmamap_t map; 19417479ff0bSSepherosa Ziehau int error, maxsegs, nsegs, first_idx, last_idx, i; 1942d217d4d9SSepherosa Ziehau uint32_t tx_ready_pos, last_td_ctrl2; 1943d217d4d9SSepherosa Ziehau 1944d217d4d9SSepherosa Ziehau maxsegs = ET_TX_NDESC - tbd->tbd_used; 1945d217d4d9SSepherosa Ziehau if (maxsegs > ET_NSEG_MAX) 1946d217d4d9SSepherosa Ziehau maxsegs = ET_NSEG_MAX; 1947d217d4d9SSepherosa Ziehau KASSERT(maxsegs >= ET_NSEG_SPARE, 1948ed20d0e3SSascha Wildner ("not enough spare TX desc (%d)", maxsegs)); 1949d217d4d9SSepherosa Ziehau 1950d217d4d9SSepherosa Ziehau KKASSERT(tx_ring->tr_ready_index < ET_TX_NDESC); 1951d217d4d9SSepherosa Ziehau first_idx = tx_ring->tr_ready_index; 1952d217d4d9SSepherosa Ziehau map = tbd->tbd_buf[first_idx].tb_dmap; 1953d217d4d9SSepherosa Ziehau 19547479ff0bSSepherosa Ziehau error = bus_dmamap_load_mbuf_defrag(sc->sc_txbuf_dtag, map, m0, 19557479ff0bSSepherosa Ziehau segs, maxsegs, &nsegs, BUS_DMA_NOWAIT); 19567479ff0bSSepherosa Ziehau if (error) 1957d217d4d9SSepherosa Ziehau goto back; 19580fe5209eSSepherosa Ziehau bus_dmamap_sync(sc->sc_txbuf_dtag, map, BUS_DMASYNC_PREWRITE); 1959d217d4d9SSepherosa Ziehau 1960d217d4d9SSepherosa Ziehau last_td_ctrl2 = ET_TDCTRL2_LAST_FRAG; 19617479ff0bSSepherosa Ziehau sc->sc_tx += nsegs; 1962d217d4d9SSepherosa Ziehau if (sc->sc_tx / sc->sc_tx_intr_nsegs != sc->sc_tx_intr) { 1963d217d4d9SSepherosa Ziehau sc->sc_tx_intr = sc->sc_tx / sc->sc_tx_intr_nsegs; 1964d217d4d9SSepherosa Ziehau last_td_ctrl2 |= ET_TDCTRL2_INTR; 1965d217d4d9SSepherosa Ziehau } 1966d217d4d9SSepherosa Ziehau 1967d217d4d9SSepherosa Ziehau last_idx = -1; 19687479ff0bSSepherosa Ziehau for (i = 0; i < nsegs; ++i) { 1969d217d4d9SSepherosa Ziehau int idx; 1970d217d4d9SSepherosa Ziehau 1971d217d4d9SSepherosa Ziehau idx = (first_idx + i) % ET_TX_NDESC; 1972d217d4d9SSepherosa Ziehau td = &tx_ring->tr_desc[idx]; 1973d217d4d9SSepherosa Ziehau td->td_addr_hi = ET_ADDR_HI(segs[i].ds_addr); 1974d217d4d9SSepherosa Ziehau td->td_addr_lo = ET_ADDR_LO(segs[i].ds_addr); 1975d217d4d9SSepherosa Ziehau td->td_ctrl1 = __SHIFTIN(segs[i].ds_len, ET_TDCTRL1_LEN); 1976d217d4d9SSepherosa Ziehau 19777479ff0bSSepherosa Ziehau if (i == nsegs - 1) { /* Last frag */ 1978d217d4d9SSepherosa Ziehau td->td_ctrl2 = last_td_ctrl2; 1979d217d4d9SSepherosa Ziehau last_idx = idx; 1980d217d4d9SSepherosa Ziehau } 1981d217d4d9SSepherosa Ziehau 1982d217d4d9SSepherosa Ziehau KKASSERT(tx_ring->tr_ready_index < ET_TX_NDESC); 1983d217d4d9SSepherosa Ziehau if (++tx_ring->tr_ready_index == ET_TX_NDESC) { 1984d217d4d9SSepherosa Ziehau tx_ring->tr_ready_index = 0; 1985d217d4d9SSepherosa Ziehau tx_ring->tr_ready_wrap ^= 1; 1986d217d4d9SSepherosa Ziehau } 1987d217d4d9SSepherosa Ziehau } 1988d217d4d9SSepherosa Ziehau td = &tx_ring->tr_desc[first_idx]; 1989d217d4d9SSepherosa Ziehau td->td_ctrl2 |= ET_TDCTRL2_FIRST_FRAG; /* First frag */ 1990d217d4d9SSepherosa Ziehau 1991d217d4d9SSepherosa Ziehau KKASSERT(last_idx >= 0); 1992d217d4d9SSepherosa Ziehau tbd->tbd_buf[first_idx].tb_dmap = tbd->tbd_buf[last_idx].tb_dmap; 1993d217d4d9SSepherosa Ziehau tbd->tbd_buf[last_idx].tb_dmap = map; 19947479ff0bSSepherosa Ziehau tbd->tbd_buf[last_idx].tb_mbuf = *m0; 1995d217d4d9SSepherosa Ziehau 19967479ff0bSSepherosa Ziehau tbd->tbd_used += nsegs; 1997d217d4d9SSepherosa Ziehau KKASSERT(tbd->tbd_used <= ET_TX_NDESC); 1998d217d4d9SSepherosa Ziehau 1999d217d4d9SSepherosa Ziehau tx_ready_pos = __SHIFTIN(tx_ring->tr_ready_index, 2000d217d4d9SSepherosa Ziehau ET_TX_READY_POS_INDEX); 2001d217d4d9SSepherosa Ziehau if (tx_ring->tr_ready_wrap) 2002d217d4d9SSepherosa Ziehau tx_ready_pos |= ET_TX_READY_POS_WRAP; 2003d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_TX_READY_POS, tx_ready_pos); 2004d217d4d9SSepherosa Ziehau 2005d217d4d9SSepherosa Ziehau error = 0; 2006d217d4d9SSepherosa Ziehau back: 2007d217d4d9SSepherosa Ziehau if (error) { 20087479ff0bSSepherosa Ziehau m_freem(*m0); 2009d217d4d9SSepherosa Ziehau *m0 = NULL; 2010d217d4d9SSepherosa Ziehau } 2011d217d4d9SSepherosa Ziehau return error; 2012d217d4d9SSepherosa Ziehau } 2013d217d4d9SSepherosa Ziehau 2014d217d4d9SSepherosa Ziehau static void 2015136e59ffSSepherosa Ziehau et_txeof(struct et_softc *sc, int start) 2016d217d4d9SSepherosa Ziehau { 2017d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 2018d217d4d9SSepherosa Ziehau struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 2019d217d4d9SSepherosa Ziehau struct et_txbuf_data *tbd = &sc->sc_tx_data; 2020d217d4d9SSepherosa Ziehau uint32_t tx_done; 2021d217d4d9SSepherosa Ziehau int end, wrap; 2022d217d4d9SSepherosa Ziehau 20233effc1bfSSepherosa Ziehau if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0) 202460d2de1fSSepherosa Ziehau return; 202560d2de1fSSepherosa Ziehau 2026d217d4d9SSepherosa Ziehau if (tbd->tbd_used == 0) 2027d217d4d9SSepherosa Ziehau return; 2028d217d4d9SSepherosa Ziehau 2029d217d4d9SSepherosa Ziehau tx_done = CSR_READ_4(sc, ET_TX_DONE_POS); 2030d217d4d9SSepherosa Ziehau end = __SHIFTOUT(tx_done, ET_TX_DONE_POS_INDEX); 2031d217d4d9SSepherosa Ziehau wrap = (tx_done & ET_TX_DONE_POS_WRAP) ? 1 : 0; 2032d217d4d9SSepherosa Ziehau 2033d217d4d9SSepherosa Ziehau while (tbd->tbd_start_index != end || tbd->tbd_start_wrap != wrap) { 2034d217d4d9SSepherosa Ziehau struct et_txbuf *tb; 2035d217d4d9SSepherosa Ziehau 2036d217d4d9SSepherosa Ziehau KKASSERT(tbd->tbd_start_index < ET_TX_NDESC); 2037d217d4d9SSepherosa Ziehau tb = &tbd->tbd_buf[tbd->tbd_start_index]; 2038d217d4d9SSepherosa Ziehau 2039d217d4d9SSepherosa Ziehau bzero(&tx_ring->tr_desc[tbd->tbd_start_index], 2040d217d4d9SSepherosa Ziehau sizeof(struct et_txdesc)); 2041d217d4d9SSepherosa Ziehau 2042d217d4d9SSepherosa Ziehau if (tb->tb_mbuf != NULL) { 20430fe5209eSSepherosa Ziehau bus_dmamap_unload(sc->sc_txbuf_dtag, tb->tb_dmap); 2044d217d4d9SSepherosa Ziehau m_freem(tb->tb_mbuf); 2045d217d4d9SSepherosa Ziehau tb->tb_mbuf = NULL; 20463d60df79SSepherosa Ziehau ifp->if_opackets++; 2047d217d4d9SSepherosa Ziehau } 2048d217d4d9SSepherosa Ziehau 2049d217d4d9SSepherosa Ziehau if (++tbd->tbd_start_index == ET_TX_NDESC) { 2050d217d4d9SSepherosa Ziehau tbd->tbd_start_index = 0; 2051d217d4d9SSepherosa Ziehau tbd->tbd_start_wrap ^= 1; 2052d217d4d9SSepherosa Ziehau } 2053d217d4d9SSepherosa Ziehau 2054d217d4d9SSepherosa Ziehau KKASSERT(tbd->tbd_used > 0); 2055d217d4d9SSepherosa Ziehau tbd->tbd_used--; 2056d217d4d9SSepherosa Ziehau } 2057d217d4d9SSepherosa Ziehau 2058d217d4d9SSepherosa Ziehau if (tbd->tbd_used == 0) 2059d217d4d9SSepherosa Ziehau ifp->if_timer = 0; 2060d217d4d9SSepherosa Ziehau if (tbd->tbd_used + ET_NSEG_SPARE <= ET_TX_NDESC) 2061*9ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 2062d217d4d9SSepherosa Ziehau 2063136e59ffSSepherosa Ziehau if (start) 20649db4b353SSepherosa Ziehau if_devstart(ifp); 2065d217d4d9SSepherosa Ziehau } 2066d217d4d9SSepherosa Ziehau 2067d217d4d9SSepherosa Ziehau static void 2068d217d4d9SSepherosa Ziehau et_tick(void *xsc) 2069d217d4d9SSepherosa Ziehau { 2070d217d4d9SSepherosa Ziehau struct et_softc *sc = xsc; 2071d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 207260d2de1fSSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->sc_miibus); 2073d217d4d9SSepherosa Ziehau 2074d217d4d9SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 2075d217d4d9SSepherosa Ziehau 207660d2de1fSSepherosa Ziehau mii_tick(mii); 20773effc1bfSSepherosa Ziehau if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0 && 20783effc1bfSSepherosa Ziehau (mii->mii_media_status & IFM_ACTIVE) && 207960d2de1fSSepherosa Ziehau IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 208060d2de1fSSepherosa Ziehau if_printf(ifp, "Link up, enable TX/RX\n"); 208160d2de1fSSepherosa Ziehau if (et_enable_txrx(sc, 0) == 0) 20829db4b353SSepherosa Ziehau if_devstart(ifp); 208360d2de1fSSepherosa Ziehau } 2084d217d4d9SSepherosa Ziehau callout_reset(&sc->sc_tick, hz, et_tick, sc); 2085d217d4d9SSepherosa Ziehau 2086d217d4d9SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 2087d217d4d9SSepherosa Ziehau } 2088d217d4d9SSepherosa Ziehau 2089d217d4d9SSepherosa Ziehau static int 2090d217d4d9SSepherosa Ziehau et_newbuf_cluster(struct et_rxbuf_data *rbd, int buf_idx, int init) 2091d217d4d9SSepherosa Ziehau { 2092d217d4d9SSepherosa Ziehau return et_newbuf(rbd, buf_idx, init, MCLBYTES); 2093d217d4d9SSepherosa Ziehau } 2094d217d4d9SSepherosa Ziehau 2095d217d4d9SSepherosa Ziehau static int 2096d217d4d9SSepherosa Ziehau et_newbuf_hdr(struct et_rxbuf_data *rbd, int buf_idx, int init) 2097d217d4d9SSepherosa Ziehau { 2098d217d4d9SSepherosa Ziehau return et_newbuf(rbd, buf_idx, init, MHLEN); 2099d217d4d9SSepherosa Ziehau } 2100d217d4d9SSepherosa Ziehau 2101d217d4d9SSepherosa Ziehau static int 2102d217d4d9SSepherosa Ziehau et_newbuf(struct et_rxbuf_data *rbd, int buf_idx, int init, int len0) 2103d217d4d9SSepherosa Ziehau { 2104d217d4d9SSepherosa Ziehau struct et_softc *sc = rbd->rbd_softc; 2105d217d4d9SSepherosa Ziehau struct et_rxbuf *rb; 2106d217d4d9SSepherosa Ziehau struct mbuf *m; 2107d217d4d9SSepherosa Ziehau bus_dma_segment_t seg; 2108d217d4d9SSepherosa Ziehau bus_dmamap_t dmap; 21097479ff0bSSepherosa Ziehau int error, len, nseg; 2110d217d4d9SSepherosa Ziehau 2111ed20d0e3SSascha Wildner KASSERT(!rbd->rbd_jumbo, ("calling %s with jumbo ring", __func__)); 21123effc1bfSSepherosa Ziehau 2113d217d4d9SSepherosa Ziehau KKASSERT(buf_idx < ET_RX_NDESC); 2114d217d4d9SSepherosa Ziehau rb = &rbd->rbd_buf[buf_idx]; 2115d217d4d9SSepherosa Ziehau 2116d217d4d9SSepherosa Ziehau m = m_getl(len0, init ? MB_WAIT : MB_DONTWAIT, MT_DATA, M_PKTHDR, &len); 2117d217d4d9SSepherosa Ziehau if (m == NULL) { 2118d217d4d9SSepherosa Ziehau error = ENOBUFS; 2119d217d4d9SSepherosa Ziehau 21200fd7469eSSepherosa Ziehau if (init) { 2121d217d4d9SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 2122d217d4d9SSepherosa Ziehau "m_getl failed, size %d\n", len0); 2123d217d4d9SSepherosa Ziehau return error; 2124d217d4d9SSepherosa Ziehau } else { 2125d217d4d9SSepherosa Ziehau goto back; 2126d217d4d9SSepherosa Ziehau } 2127d217d4d9SSepherosa Ziehau } 2128d217d4d9SSepherosa Ziehau m->m_len = m->m_pkthdr.len = len; 2129d217d4d9SSepherosa Ziehau 2130d217d4d9SSepherosa Ziehau /* 2131d217d4d9SSepherosa Ziehau * Try load RX mbuf into temporary DMA tag 2132d217d4d9SSepherosa Ziehau */ 21337479ff0bSSepherosa Ziehau error = bus_dmamap_load_mbuf_segment(sc->sc_rxbuf_dtag, 21347479ff0bSSepherosa Ziehau sc->sc_rxbuf_tmp_dmap, m, &seg, 1, &nseg, 21357479ff0bSSepherosa Ziehau BUS_DMA_NOWAIT); 21367479ff0bSSepherosa Ziehau if (error) { 2137d217d4d9SSepherosa Ziehau m_freem(m); 2138d217d4d9SSepherosa Ziehau if (init) { 21390fd7469eSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "can't load RX mbuf\n"); 2140d217d4d9SSepherosa Ziehau return error; 2141d217d4d9SSepherosa Ziehau } else { 2142d217d4d9SSepherosa Ziehau goto back; 2143d217d4d9SSepherosa Ziehau } 2144d217d4d9SSepherosa Ziehau } 2145d217d4d9SSepherosa Ziehau 21463effc1bfSSepherosa Ziehau if (!init) { 21470fe5209eSSepherosa Ziehau bus_dmamap_sync(sc->sc_rxbuf_dtag, rb->rb_dmap, 21483effc1bfSSepherosa Ziehau BUS_DMASYNC_POSTREAD); 21490fe5209eSSepherosa Ziehau bus_dmamap_unload(sc->sc_rxbuf_dtag, rb->rb_dmap); 21503effc1bfSSepherosa Ziehau } 2151d217d4d9SSepherosa Ziehau rb->rb_mbuf = m; 2152d217d4d9SSepherosa Ziehau rb->rb_paddr = seg.ds_addr; 2153d217d4d9SSepherosa Ziehau 2154d217d4d9SSepherosa Ziehau /* 2155d217d4d9SSepherosa Ziehau * Swap RX buf's DMA map with the loaded temporary one 2156d217d4d9SSepherosa Ziehau */ 2157d217d4d9SSepherosa Ziehau dmap = rb->rb_dmap; 21580fe5209eSSepherosa Ziehau rb->rb_dmap = sc->sc_rxbuf_tmp_dmap; 21590fe5209eSSepherosa Ziehau sc->sc_rxbuf_tmp_dmap = dmap; 2160d217d4d9SSepherosa Ziehau 2161d217d4d9SSepherosa Ziehau error = 0; 2162d217d4d9SSepherosa Ziehau back: 21633effc1bfSSepherosa Ziehau et_setup_rxdesc(rbd, buf_idx, rb->rb_paddr); 2164d217d4d9SSepherosa Ziehau return error; 2165d217d4d9SSepherosa Ziehau } 2166d217d4d9SSepherosa Ziehau 2167d217d4d9SSepherosa Ziehau static int 2168d217d4d9SSepherosa Ziehau et_sysctl_rx_intr_npkts(SYSCTL_HANDLER_ARGS) 2169d217d4d9SSepherosa Ziehau { 2170d217d4d9SSepherosa Ziehau struct et_softc *sc = arg1; 2171d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 2172d217d4d9SSepherosa Ziehau int error = 0, v; 2173d217d4d9SSepherosa Ziehau 2174d217d4d9SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 2175d217d4d9SSepherosa Ziehau 2176d217d4d9SSepherosa Ziehau v = sc->sc_rx_intr_npkts; 2177d217d4d9SSepherosa Ziehau error = sysctl_handle_int(oidp, &v, 0, req); 2178d217d4d9SSepherosa Ziehau if (error || req->newptr == NULL) 2179d217d4d9SSepherosa Ziehau goto back; 2180d217d4d9SSepherosa Ziehau if (v <= 0) { 2181d217d4d9SSepherosa Ziehau error = EINVAL; 2182d217d4d9SSepherosa Ziehau goto back; 2183d217d4d9SSepherosa Ziehau } 2184d217d4d9SSepherosa Ziehau 2185d217d4d9SSepherosa Ziehau if (sc->sc_rx_intr_npkts != v) { 2186d217d4d9SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 2187d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_INTR_NPKTS, v); 2188d217d4d9SSepherosa Ziehau sc->sc_rx_intr_npkts = v; 2189d217d4d9SSepherosa Ziehau } 2190d217d4d9SSepherosa Ziehau back: 2191d217d4d9SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 2192d217d4d9SSepherosa Ziehau return error; 2193d217d4d9SSepherosa Ziehau } 2194d217d4d9SSepherosa Ziehau 2195d217d4d9SSepherosa Ziehau static int 2196d217d4d9SSepherosa Ziehau et_sysctl_rx_intr_delay(SYSCTL_HANDLER_ARGS) 2197d217d4d9SSepherosa Ziehau { 2198d217d4d9SSepherosa Ziehau struct et_softc *sc = arg1; 2199d217d4d9SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 2200d217d4d9SSepherosa Ziehau int error = 0, v; 2201d217d4d9SSepherosa Ziehau 2202d217d4d9SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 2203d217d4d9SSepherosa Ziehau 2204d217d4d9SSepherosa Ziehau v = sc->sc_rx_intr_delay; 2205d217d4d9SSepherosa Ziehau error = sysctl_handle_int(oidp, &v, 0, req); 2206d217d4d9SSepherosa Ziehau if (error || req->newptr == NULL) 2207d217d4d9SSepherosa Ziehau goto back; 2208d217d4d9SSepherosa Ziehau if (v <= 0) { 2209d217d4d9SSepherosa Ziehau error = EINVAL; 2210d217d4d9SSepherosa Ziehau goto back; 2211d217d4d9SSepherosa Ziehau } 2212d217d4d9SSepherosa Ziehau 2213d217d4d9SSepherosa Ziehau if (sc->sc_rx_intr_delay != v) { 2214d217d4d9SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 2215d217d4d9SSepherosa Ziehau CSR_WRITE_4(sc, ET_RX_INTR_DELAY, v); 2216d217d4d9SSepherosa Ziehau sc->sc_rx_intr_delay = v; 2217d217d4d9SSepherosa Ziehau } 2218d217d4d9SSepherosa Ziehau back: 2219d217d4d9SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 2220d217d4d9SSepherosa Ziehau return error; 2221d217d4d9SSepherosa Ziehau } 222260d2de1fSSepherosa Ziehau 222360d2de1fSSepherosa Ziehau static void 222460d2de1fSSepherosa Ziehau et_setmedia(struct et_softc *sc) 222560d2de1fSSepherosa Ziehau { 222660d2de1fSSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->sc_miibus); 222760d2de1fSSepherosa Ziehau uint32_t cfg2, ctrl; 222860d2de1fSSepherosa Ziehau 222960d2de1fSSepherosa Ziehau cfg2 = CSR_READ_4(sc, ET_MAC_CFG2); 223060d2de1fSSepherosa Ziehau cfg2 &= ~(ET_MAC_CFG2_MODE_MII | ET_MAC_CFG2_MODE_GMII | 223160d2de1fSSepherosa Ziehau ET_MAC_CFG2_FDX | ET_MAC_CFG2_BIGFRM); 223260d2de1fSSepherosa Ziehau cfg2 |= ET_MAC_CFG2_LENCHK | ET_MAC_CFG2_CRC | ET_MAC_CFG2_PADCRC | 223360d2de1fSSepherosa Ziehau __SHIFTIN(7, ET_MAC_CFG2_PREAMBLE_LEN); 223460d2de1fSSepherosa Ziehau 223560d2de1fSSepherosa Ziehau ctrl = CSR_READ_4(sc, ET_MAC_CTRL); 223660d2de1fSSepherosa Ziehau ctrl &= ~(ET_MAC_CTRL_GHDX | ET_MAC_CTRL_MODE_MII); 223760d2de1fSSepherosa Ziehau 223860d2de1fSSepherosa Ziehau if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { 223960d2de1fSSepherosa Ziehau cfg2 |= ET_MAC_CFG2_MODE_GMII; 224060d2de1fSSepherosa Ziehau } else { 224160d2de1fSSepherosa Ziehau cfg2 |= ET_MAC_CFG2_MODE_MII; 224260d2de1fSSepherosa Ziehau ctrl |= ET_MAC_CTRL_MODE_MII; 224360d2de1fSSepherosa Ziehau } 224460d2de1fSSepherosa Ziehau 224560d2de1fSSepherosa Ziehau if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) 224660d2de1fSSepherosa Ziehau cfg2 |= ET_MAC_CFG2_FDX; 224760d2de1fSSepherosa Ziehau else 224860d2de1fSSepherosa Ziehau ctrl |= ET_MAC_CTRL_GHDX; 224960d2de1fSSepherosa Ziehau 225060d2de1fSSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CTRL, ctrl); 225160d2de1fSSepherosa Ziehau CSR_WRITE_4(sc, ET_MAC_CFG2, cfg2); 225260d2de1fSSepherosa Ziehau } 22533effc1bfSSepherosa Ziehau 22543effc1bfSSepherosa Ziehau static int 22553effc1bfSSepherosa Ziehau et_jumbo_mem_alloc(device_t dev) 22563effc1bfSSepherosa Ziehau { 22573effc1bfSSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 22583effc1bfSSepherosa Ziehau struct et_jumbo_data *jd = &sc->sc_jumbo_data; 22593effc1bfSSepherosa Ziehau bus_addr_t paddr; 22603effc1bfSSepherosa Ziehau uint8_t *buf; 2261c7f73cc7SSepherosa Ziehau int i; 22623effc1bfSSepherosa Ziehau 2263c7f73cc7SSepherosa Ziehau jd->jd_buf = bus_dmamem_coherent_any(sc->sc_dtag, 2264c2ebe33eSSepherosa Ziehau ET_JUMBO_ALIGN, ET_JUMBO_MEM_SIZE, BUS_DMA_WAITOK, 2265c7f73cc7SSepherosa Ziehau &jd->jd_dtag, &jd->jd_dmap, &paddr); 2266c7f73cc7SSepherosa Ziehau if (jd->jd_buf == NULL) { 22673effc1bfSSepherosa Ziehau device_printf(dev, "can't create jumbo DMA stuffs\n"); 2268c7f73cc7SSepherosa Ziehau return ENOMEM; 22693effc1bfSSepherosa Ziehau } 22703effc1bfSSepherosa Ziehau 22713effc1bfSSepherosa Ziehau jd->jd_slots = kmalloc(sizeof(*jd->jd_slots) * ET_JSLOTS, M_DEVBUF, 22723effc1bfSSepherosa Ziehau M_WAITOK | M_ZERO); 22733effc1bfSSepherosa Ziehau lwkt_serialize_init(&jd->jd_serializer); 22743effc1bfSSepherosa Ziehau SLIST_INIT(&jd->jd_free_slots); 22753effc1bfSSepherosa Ziehau 22763effc1bfSSepherosa Ziehau buf = jd->jd_buf; 22773effc1bfSSepherosa Ziehau for (i = 0; i < ET_JSLOTS; ++i) { 22783effc1bfSSepherosa Ziehau struct et_jslot *jslot = &jd->jd_slots[i]; 22793effc1bfSSepherosa Ziehau 22803effc1bfSSepherosa Ziehau jslot->jslot_data = jd; 22813effc1bfSSepherosa Ziehau jslot->jslot_buf = buf; 22823effc1bfSSepherosa Ziehau jslot->jslot_paddr = paddr; 22833effc1bfSSepherosa Ziehau jslot->jslot_inuse = 0; 22843effc1bfSSepherosa Ziehau jslot->jslot_index = i; 22853effc1bfSSepherosa Ziehau SLIST_INSERT_HEAD(&jd->jd_free_slots, jslot, jslot_link); 22863effc1bfSSepherosa Ziehau 22873effc1bfSSepherosa Ziehau buf += ET_JLEN; 22883effc1bfSSepherosa Ziehau paddr += ET_JLEN; 22893effc1bfSSepherosa Ziehau } 22903effc1bfSSepherosa Ziehau return 0; 22913effc1bfSSepherosa Ziehau } 22923effc1bfSSepherosa Ziehau 22933effc1bfSSepherosa Ziehau static void 22943effc1bfSSepherosa Ziehau et_jumbo_mem_free(device_t dev) 22953effc1bfSSepherosa Ziehau { 22963effc1bfSSepherosa Ziehau struct et_softc *sc = device_get_softc(dev); 22973effc1bfSSepherosa Ziehau struct et_jumbo_data *jd = &sc->sc_jumbo_data; 22983effc1bfSSepherosa Ziehau 22993effc1bfSSepherosa Ziehau KKASSERT(sc->sc_flags & ET_FLAG_JUMBO); 23003effc1bfSSepherosa Ziehau 23013effc1bfSSepherosa Ziehau kfree(jd->jd_slots, M_DEVBUF); 23023effc1bfSSepherosa Ziehau et_dma_mem_destroy(jd->jd_dtag, jd->jd_buf, jd->jd_dmap); 23033effc1bfSSepherosa Ziehau } 23043effc1bfSSepherosa Ziehau 23053effc1bfSSepherosa Ziehau static struct et_jslot * 23063effc1bfSSepherosa Ziehau et_jalloc(struct et_jumbo_data *jd) 23073effc1bfSSepherosa Ziehau { 23083effc1bfSSepherosa Ziehau struct et_jslot *jslot; 23093effc1bfSSepherosa Ziehau 23103effc1bfSSepherosa Ziehau lwkt_serialize_enter(&jd->jd_serializer); 23113effc1bfSSepherosa Ziehau 23123effc1bfSSepherosa Ziehau jslot = SLIST_FIRST(&jd->jd_free_slots); 23133effc1bfSSepherosa Ziehau if (jslot) { 23143effc1bfSSepherosa Ziehau SLIST_REMOVE_HEAD(&jd->jd_free_slots, jslot_link); 23153effc1bfSSepherosa Ziehau jslot->jslot_inuse = 1; 23163effc1bfSSepherosa Ziehau } 23173effc1bfSSepherosa Ziehau 23183effc1bfSSepherosa Ziehau lwkt_serialize_exit(&jd->jd_serializer); 23193effc1bfSSepherosa Ziehau return jslot; 23203effc1bfSSepherosa Ziehau } 23213effc1bfSSepherosa Ziehau 23223effc1bfSSepherosa Ziehau static void 23233effc1bfSSepherosa Ziehau et_jfree(void *xjslot) 23243effc1bfSSepherosa Ziehau { 23253effc1bfSSepherosa Ziehau struct et_jslot *jslot = xjslot; 23263effc1bfSSepherosa Ziehau struct et_jumbo_data *jd = jslot->jslot_data; 23273effc1bfSSepherosa Ziehau 23283effc1bfSSepherosa Ziehau if (&jd->jd_slots[jslot->jslot_index] != jslot) { 2329ed20d0e3SSascha Wildner panic("%s wrong jslot!?", __func__); 23303effc1bfSSepherosa Ziehau } else if (jslot->jslot_inuse == 0) { 2331ed20d0e3SSascha Wildner panic("%s jslot already freed", __func__); 23323effc1bfSSepherosa Ziehau } else { 23333effc1bfSSepherosa Ziehau lwkt_serialize_enter(&jd->jd_serializer); 23343effc1bfSSepherosa Ziehau 23353effc1bfSSepherosa Ziehau atomic_subtract_int(&jslot->jslot_inuse, 1); 23363effc1bfSSepherosa Ziehau if (jslot->jslot_inuse == 0) { 23373effc1bfSSepherosa Ziehau SLIST_INSERT_HEAD(&jd->jd_free_slots, jslot, 23383effc1bfSSepherosa Ziehau jslot_link); 23393effc1bfSSepherosa Ziehau } 23403effc1bfSSepherosa Ziehau 23413effc1bfSSepherosa Ziehau lwkt_serialize_exit(&jd->jd_serializer); 23423effc1bfSSepherosa Ziehau } 23433effc1bfSSepherosa Ziehau } 23443effc1bfSSepherosa Ziehau 23453effc1bfSSepherosa Ziehau static void 23463effc1bfSSepherosa Ziehau et_jref(void *xjslot) 23473effc1bfSSepherosa Ziehau { 23483effc1bfSSepherosa Ziehau struct et_jslot *jslot = xjslot; 23493effc1bfSSepherosa Ziehau struct et_jumbo_data *jd = jslot->jslot_data; 23503effc1bfSSepherosa Ziehau 23513effc1bfSSepherosa Ziehau if (&jd->jd_slots[jslot->jslot_index] != jslot) 2352ed20d0e3SSascha Wildner panic("%s wrong jslot!?", __func__); 23533effc1bfSSepherosa Ziehau else if (jslot->jslot_inuse == 0) 2354ed20d0e3SSascha Wildner panic("%s jslot already freed", __func__); 23553effc1bfSSepherosa Ziehau else 23563effc1bfSSepherosa Ziehau atomic_add_int(&jslot->jslot_inuse, 1); 23573effc1bfSSepherosa Ziehau } 23583effc1bfSSepherosa Ziehau 23593effc1bfSSepherosa Ziehau static int 23603effc1bfSSepherosa Ziehau et_newbuf_jumbo(struct et_rxbuf_data *rbd, int buf_idx, int init) 23613effc1bfSSepherosa Ziehau { 23623effc1bfSSepherosa Ziehau struct et_softc *sc = rbd->rbd_softc; 23633effc1bfSSepherosa Ziehau struct et_rxbuf *rb; 23643effc1bfSSepherosa Ziehau struct mbuf *m; 23653effc1bfSSepherosa Ziehau struct et_jslot *jslot; 23663effc1bfSSepherosa Ziehau int error; 23673effc1bfSSepherosa Ziehau 2368ed20d0e3SSascha Wildner KASSERT(rbd->rbd_jumbo, ("calling %s with non-jumbo ring", __func__)); 23693effc1bfSSepherosa Ziehau 23703effc1bfSSepherosa Ziehau KKASSERT(buf_idx < ET_RX_NDESC); 23713effc1bfSSepherosa Ziehau rb = &rbd->rbd_buf[buf_idx]; 23723effc1bfSSepherosa Ziehau 23733effc1bfSSepherosa Ziehau error = ENOBUFS; 23743effc1bfSSepherosa Ziehau 23753effc1bfSSepherosa Ziehau MGETHDR(m, init ? MB_WAIT : MB_DONTWAIT, MT_DATA); 23763effc1bfSSepherosa Ziehau if (m == NULL) { 23773effc1bfSSepherosa Ziehau if (init) { 23783effc1bfSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "MGETHDR failed\n"); 23793effc1bfSSepherosa Ziehau return error; 23803effc1bfSSepherosa Ziehau } else { 23813effc1bfSSepherosa Ziehau goto back; 23823effc1bfSSepherosa Ziehau } 23833effc1bfSSepherosa Ziehau } 23843effc1bfSSepherosa Ziehau 23853effc1bfSSepherosa Ziehau jslot = et_jalloc(&sc->sc_jumbo_data); 23863effc1bfSSepherosa Ziehau if (jslot == NULL) { 23873effc1bfSSepherosa Ziehau m_freem(m); 23883effc1bfSSepherosa Ziehau 23893effc1bfSSepherosa Ziehau if (init) { 23903effc1bfSSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 23913effc1bfSSepherosa Ziehau "jslot allocation failed\n"); 23923effc1bfSSepherosa Ziehau return error; 23933effc1bfSSepherosa Ziehau } else { 23943effc1bfSSepherosa Ziehau goto back; 23953effc1bfSSepherosa Ziehau } 23963effc1bfSSepherosa Ziehau } 23973effc1bfSSepherosa Ziehau 23983effc1bfSSepherosa Ziehau m->m_ext.ext_arg = jslot; 23993effc1bfSSepherosa Ziehau m->m_ext.ext_buf = jslot->jslot_buf; 24003effc1bfSSepherosa Ziehau m->m_ext.ext_free = et_jfree; 24013effc1bfSSepherosa Ziehau m->m_ext.ext_ref = et_jref; 24023effc1bfSSepherosa Ziehau m->m_ext.ext_size = ET_JUMBO_FRAMELEN; 24033effc1bfSSepherosa Ziehau m->m_flags |= M_EXT; 24043effc1bfSSepherosa Ziehau m->m_data = m->m_ext.ext_buf; 24053effc1bfSSepherosa Ziehau m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; 24063effc1bfSSepherosa Ziehau 24073effc1bfSSepherosa Ziehau rb->rb_mbuf = m; 24083effc1bfSSepherosa Ziehau rb->rb_paddr = jslot->jslot_paddr; 24093effc1bfSSepherosa Ziehau 24103effc1bfSSepherosa Ziehau error = 0; 24113effc1bfSSepherosa Ziehau back: 24123effc1bfSSepherosa Ziehau et_setup_rxdesc(rbd, buf_idx, rb->rb_paddr); 24133effc1bfSSepherosa Ziehau return error; 24143effc1bfSSepherosa Ziehau } 24153effc1bfSSepherosa Ziehau 24163effc1bfSSepherosa Ziehau static void 24173effc1bfSSepherosa Ziehau et_setup_rxdesc(struct et_rxbuf_data *rbd, int buf_idx, bus_addr_t paddr) 24183effc1bfSSepherosa Ziehau { 24193effc1bfSSepherosa Ziehau struct et_rxdesc_ring *rx_ring = rbd->rbd_ring; 24203effc1bfSSepherosa Ziehau struct et_rxdesc *desc; 24213effc1bfSSepherosa Ziehau 24223effc1bfSSepherosa Ziehau KKASSERT(buf_idx < ET_RX_NDESC); 24233effc1bfSSepherosa Ziehau desc = &rx_ring->rr_desc[buf_idx]; 24243effc1bfSSepherosa Ziehau 24253effc1bfSSepherosa Ziehau desc->rd_addr_hi = ET_ADDR_HI(paddr); 24263effc1bfSSepherosa Ziehau desc->rd_addr_lo = ET_ADDR_LO(paddr); 24273effc1bfSSepherosa Ziehau desc->rd_ctrl = __SHIFTIN(buf_idx, ET_RDCTRL_BUFIDX); 24283effc1bfSSepherosa Ziehau } 2429