14d52a575SXin LI /*- 27282444bSPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 37282444bSPedro F. Giffuni * 4e5fdd9deSXin LI * Copyright (c) 2007 Sepherosa Ziehau. All rights reserved. 54d52a575SXin LI * 64d52a575SXin LI * This code is derived from software contributed to The DragonFly Project 74d52a575SXin LI * by Sepherosa Ziehau <sepherosa@gmail.com> 84d52a575SXin LI * 94d52a575SXin LI * Redistribution and use in source and binary forms, with or without 104d52a575SXin LI * modification, are permitted provided that the following conditions 114d52a575SXin LI * are met: 124d52a575SXin LI * 134d52a575SXin LI * 1. Redistributions of source code must retain the above copyright 144d52a575SXin LI * notice, this list of conditions and the following disclaimer. 154d52a575SXin LI * 2. Redistributions in binary form must reproduce the above copyright 164d52a575SXin LI * notice, this list of conditions and the following disclaimer in 174d52a575SXin LI * the documentation and/or other materials provided with the 184d52a575SXin LI * distribution. 194d52a575SXin LI * 3. Neither the name of The DragonFly Project nor the names of its 204d52a575SXin LI * contributors may be used to endorse or promote products derived 214d52a575SXin LI * from this software without specific, prior written permission. 224d52a575SXin LI * 234d52a575SXin LI * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 244d52a575SXin LI * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 254d52a575SXin LI * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 264d52a575SXin LI * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 274d52a575SXin LI * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 284d52a575SXin LI * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 294d52a575SXin LI * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 304d52a575SXin LI * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 314d52a575SXin LI * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 324d52a575SXin LI * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 334d52a575SXin LI * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 344d52a575SXin LI * SUCH DAMAGE. 354d52a575SXin LI * 364d52a575SXin LI * $DragonFly: src/sys/dev/netif/et/if_et.c,v 1.10 2008/05/18 07:47:14 sephe Exp $ 374d52a575SXin LI */ 384d52a575SXin LI 39fe42b04dSPyun YongHyeon #include <sys/cdefs.h> 40fe42b04dSPyun YongHyeon __FBSDID("$FreeBSD$"); 41fe42b04dSPyun YongHyeon 424d52a575SXin LI #include <sys/param.h> 434d52a575SXin LI #include <sys/systm.h> 444d52a575SXin LI #include <sys/endian.h> 454d52a575SXin LI #include <sys/kernel.h> 464d52a575SXin LI #include <sys/bus.h> 474d52a575SXin LI #include <sys/malloc.h> 484d52a575SXin LI #include <sys/mbuf.h> 494d52a575SXin LI #include <sys/proc.h> 504d52a575SXin LI #include <sys/rman.h> 514d52a575SXin LI #include <sys/module.h> 524d52a575SXin LI #include <sys/socket.h> 534d52a575SXin LI #include <sys/sockio.h> 544d52a575SXin LI #include <sys/sysctl.h> 554d52a575SXin LI 564d52a575SXin LI #include <net/ethernet.h> 574d52a575SXin LI #include <net/if.h> 5876039bc8SGleb Smirnoff #include <net/if_var.h> 594d52a575SXin LI #include <net/if_dl.h> 604d52a575SXin LI #include <net/if_types.h> 614d52a575SXin LI #include <net/bpf.h> 624d52a575SXin LI #include <net/if_arp.h> 634d52a575SXin LI #include <net/if_media.h> 644d52a575SXin LI #include <net/if_vlan_var.h> 654d52a575SXin LI 664d52a575SXin LI #include <machine/bus.h> 674d52a575SXin LI 68d6c65d27SMarius Strobl #include <dev/mii/mii.h> 694d52a575SXin LI #include <dev/mii/miivar.h> 704d52a575SXin LI 714d52a575SXin LI #include <dev/pci/pcireg.h> 724d52a575SXin LI #include <dev/pci/pcivar.h> 734d52a575SXin LI 744d52a575SXin LI #include <dev/et/if_etreg.h> 754d52a575SXin LI #include <dev/et/if_etvar.h> 764d52a575SXin LI 774d52a575SXin LI #include "miibus_if.h" 784d52a575SXin LI 794d52a575SXin LI MODULE_DEPEND(et, pci, 1, 1, 1); 804d52a575SXin LI MODULE_DEPEND(et, ether, 1, 1, 1); 814d52a575SXin LI MODULE_DEPEND(et, miibus, 1, 1, 1); 824d52a575SXin LI 83cc3c3b4eSPyun YongHyeon /* Tunables. */ 84cc3c3b4eSPyun YongHyeon static int msi_disable = 0; 85accb4fcdSPyun YongHyeon TUNABLE_INT("hw.et.msi_disable", &msi_disable); 86cc3c3b4eSPyun YongHyeon 879955274cSPyun YongHyeon #define ET_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) 889955274cSPyun YongHyeon 894d52a575SXin LI static int et_probe(device_t); 904d52a575SXin LI static int et_attach(device_t); 914d52a575SXin LI static int et_detach(device_t); 924d52a575SXin LI static int et_shutdown(device_t); 930442028aSPyun YongHyeon static int et_suspend(device_t); 940442028aSPyun YongHyeon static int et_resume(device_t); 954d52a575SXin LI 964d52a575SXin LI static int et_miibus_readreg(device_t, int, int); 974d52a575SXin LI static int et_miibus_writereg(device_t, int, int, int); 984d52a575SXin LI static void et_miibus_statchg(device_t); 994d52a575SXin LI 1004d52a575SXin LI static void et_init_locked(struct et_softc *); 1014d52a575SXin LI static void et_init(void *); 102*7c509be1SJustin Hibbits static int et_ioctl(if_t, u_long, caddr_t); 103*7c509be1SJustin Hibbits static void et_start_locked(if_t); 104*7c509be1SJustin Hibbits static void et_start(if_t); 10505884511SPyun YongHyeon static int et_watchdog(struct et_softc *); 106*7c509be1SJustin Hibbits static int et_ifmedia_upd_locked(if_t); 107*7c509be1SJustin Hibbits static int et_ifmedia_upd(if_t); 108*7c509be1SJustin Hibbits static void et_ifmedia_sts(if_t, struct ifmediareq *); 109*7c509be1SJustin Hibbits static uint64_t et_get_counter(if_t, ift_counter); 1104d52a575SXin LI 1114d52a575SXin LI static void et_add_sysctls(struct et_softc *); 1124d52a575SXin LI static int et_sysctl_rx_intr_npkts(SYSCTL_HANDLER_ARGS); 1134d52a575SXin LI static int et_sysctl_rx_intr_delay(SYSCTL_HANDLER_ARGS); 1144d52a575SXin LI 1154d52a575SXin LI static void et_intr(void *); 1164d52a575SXin LI static void et_rxeof(struct et_softc *); 1174d52a575SXin LI static void et_txeof(struct et_softc *); 1184d52a575SXin LI 11905884511SPyun YongHyeon static int et_dma_alloc(struct et_softc *); 12005884511SPyun YongHyeon static void et_dma_free(struct et_softc *); 12105884511SPyun YongHyeon static void et_dma_map_addr(void *, bus_dma_segment_t *, int, int); 12205884511SPyun YongHyeon static int et_dma_ring_alloc(struct et_softc *, bus_size_t, bus_size_t, 12305884511SPyun YongHyeon bus_dma_tag_t *, uint8_t **, bus_dmamap_t *, bus_addr_t *, 12405884511SPyun YongHyeon const char *); 12505884511SPyun YongHyeon static void et_dma_ring_free(struct et_softc *, bus_dma_tag_t *, uint8_t **, 126c34f1a08SJohn Baldwin bus_dmamap_t, bus_addr_t *); 12705884511SPyun YongHyeon static void et_init_tx_ring(struct et_softc *); 1284d52a575SXin LI static int et_init_rx_ring(struct et_softc *); 1294d52a575SXin LI static void et_free_tx_ring(struct et_softc *); 1304d52a575SXin LI static void et_free_rx_ring(struct et_softc *); 1314d52a575SXin LI static int et_encap(struct et_softc *, struct mbuf **); 13205884511SPyun YongHyeon static int et_newbuf_cluster(struct et_rxbuf_data *, int); 13305884511SPyun YongHyeon static int et_newbuf_hdr(struct et_rxbuf_data *, int); 13405884511SPyun YongHyeon static void et_rxbuf_discard(struct et_rxbuf_data *, int); 1354d52a575SXin LI 1364d52a575SXin LI static void et_stop(struct et_softc *); 1374d52a575SXin LI static int et_chip_init(struct et_softc *); 1384d52a575SXin LI static void et_chip_attach(struct et_softc *); 1394d52a575SXin LI static void et_init_mac(struct et_softc *); 1404d52a575SXin LI static void et_init_rxmac(struct et_softc *); 1414d52a575SXin LI static void et_init_txmac(struct et_softc *); 1424d52a575SXin LI static int et_init_rxdma(struct et_softc *); 1434d52a575SXin LI static int et_init_txdma(struct et_softc *); 1444d52a575SXin LI static int et_start_rxdma(struct et_softc *); 1454d52a575SXin LI static int et_start_txdma(struct et_softc *); 1464d52a575SXin LI static int et_stop_rxdma(struct et_softc *); 1474d52a575SXin LI static int et_stop_txdma(struct et_softc *); 1484d52a575SXin LI static void et_reset(struct et_softc *); 1498b3c6496SPyun YongHyeon static int et_bus_config(struct et_softc *); 1504d52a575SXin LI static void et_get_eaddr(device_t, uint8_t[]); 1514d52a575SXin LI static void et_setmulti(struct et_softc *); 1524d52a575SXin LI static void et_tick(void *); 153e0b5ac02SPyun YongHyeon static void et_stats_update(struct et_softc *); 1544d52a575SXin LI 1554d52a575SXin LI static const struct et_dev { 1564d52a575SXin LI uint16_t vid; 1574d52a575SXin LI uint16_t did; 1584d52a575SXin LI const char *desc; 1594d52a575SXin LI } et_devices[] = { 1604d52a575SXin LI { PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_ET1310, 1614d52a575SXin LI "Agere ET1310 Gigabit Ethernet" }, 1624d52a575SXin LI { PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_ET1310_FAST, 1634d52a575SXin LI "Agere ET1310 Fast Ethernet" }, 1644d52a575SXin LI { 0, 0, NULL } 1654d52a575SXin LI }; 1664d52a575SXin LI 1674d52a575SXin LI static device_method_t et_methods[] = { 1684d52a575SXin LI DEVMETHOD(device_probe, et_probe), 1694d52a575SXin LI DEVMETHOD(device_attach, et_attach), 1704d52a575SXin LI DEVMETHOD(device_detach, et_detach), 1714d52a575SXin LI DEVMETHOD(device_shutdown, et_shutdown), 1720442028aSPyun YongHyeon DEVMETHOD(device_suspend, et_suspend), 1730442028aSPyun YongHyeon DEVMETHOD(device_resume, et_resume), 1744d52a575SXin LI 1754d52a575SXin LI DEVMETHOD(miibus_readreg, et_miibus_readreg), 1764d52a575SXin LI DEVMETHOD(miibus_writereg, et_miibus_writereg), 1774d52a575SXin LI DEVMETHOD(miibus_statchg, et_miibus_statchg), 1784d52a575SXin LI 1794b7ec270SMarius Strobl DEVMETHOD_END 1804d52a575SXin LI }; 1814d52a575SXin LI 1824d52a575SXin LI static driver_t et_driver = { 1834d52a575SXin LI "et", 1844d52a575SXin LI et_methods, 1854d52a575SXin LI sizeof(struct et_softc) 1864d52a575SXin LI }; 1874d52a575SXin LI 188413e6d9dSJohn Baldwin DRIVER_MODULE(et, pci, et_driver, 0, 0); 1896ea57aa2SWarner Losh MODULE_PNP_INFO("U16:vendor;U16:device;D:#", pci, et, et_devices, 190329e817fSWarner Losh nitems(et_devices) - 1); 1913e38757dSJohn Baldwin DRIVER_MODULE(miibus, et, miibus_driver, 0, 0); 1924d52a575SXin LI 1934d52a575SXin LI static int et_rx_intr_npkts = 32; 1944d52a575SXin LI static int et_rx_intr_delay = 20; /* x10 usec */ 1954d52a575SXin LI static int et_tx_intr_nsegs = 126; 1964d52a575SXin LI static uint32_t et_timer = 1000 * 1000 * 1000; /* nanosec */ 1974d52a575SXin LI 1984d52a575SXin LI TUNABLE_INT("hw.et.timer", &et_timer); 1994d52a575SXin LI TUNABLE_INT("hw.et.rx_intr_npkts", &et_rx_intr_npkts); 2004d52a575SXin LI TUNABLE_INT("hw.et.rx_intr_delay", &et_rx_intr_delay); 2014d52a575SXin LI TUNABLE_INT("hw.et.tx_intr_nsegs", &et_tx_intr_nsegs); 2024d52a575SXin LI 2034d52a575SXin LI static int 2044d52a575SXin LI et_probe(device_t dev) 2054d52a575SXin LI { 2064d52a575SXin LI const struct et_dev *d; 2074d52a575SXin LI uint16_t did, vid; 2084d52a575SXin LI 2094d52a575SXin LI vid = pci_get_vendor(dev); 2104d52a575SXin LI did = pci_get_device(dev); 2114d52a575SXin LI 2124d52a575SXin LI for (d = et_devices; d->desc != NULL; ++d) { 2134d52a575SXin LI if (vid == d->vid && did == d->did) { 2144d52a575SXin LI device_set_desc(dev, d->desc); 215a64788d1SPyun YongHyeon return (BUS_PROBE_DEFAULT); 2164d52a575SXin LI } 2174d52a575SXin LI } 218398f1b65SPyun YongHyeon return (ENXIO); 2194d52a575SXin LI } 2204d52a575SXin LI 2214d52a575SXin LI static int 2224d52a575SXin LI et_attach(device_t dev) 2234d52a575SXin LI { 2244d52a575SXin LI struct et_softc *sc; 225*7c509be1SJustin Hibbits if_t ifp; 2264d52a575SXin LI uint8_t eaddr[ETHER_ADDR_LEN]; 22738953bb0SPyun YongHyeon uint32_t pmcfg; 228cc3c3b4eSPyun YongHyeon int cap, error, msic; 2294d52a575SXin LI 2304d52a575SXin LI sc = device_get_softc(dev); 2314d52a575SXin LI sc->dev = dev; 2324d52a575SXin LI mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 2334d52a575SXin LI MTX_DEF); 234d2f7028cSPyun YongHyeon callout_init_mtx(&sc->sc_tick, &sc->sc_mtx, 0); 2354d52a575SXin LI 2364d52a575SXin LI ifp = sc->ifp = if_alloc(IFT_ETHER); 2374d52a575SXin LI if (ifp == NULL) { 2384d52a575SXin LI device_printf(dev, "can not if_alloc()\n"); 2394d52a575SXin LI error = ENOSPC; 2404d52a575SXin LI goto fail; 2414d52a575SXin LI } 2424d52a575SXin LI 2434d52a575SXin LI /* 2444d52a575SXin LI * Initialize tunables 2454d52a575SXin LI */ 2464d52a575SXin LI sc->sc_rx_intr_npkts = et_rx_intr_npkts; 2474d52a575SXin LI sc->sc_rx_intr_delay = et_rx_intr_delay; 2484d52a575SXin LI sc->sc_tx_intr_nsegs = et_tx_intr_nsegs; 2494d52a575SXin LI sc->sc_timer = et_timer; 2504d52a575SXin LI 2514d52a575SXin LI /* Enable bus mastering */ 2524d52a575SXin LI pci_enable_busmaster(dev); 2534d52a575SXin LI 2544d52a575SXin LI /* 2554d52a575SXin LI * Allocate IO memory 2564d52a575SXin LI */ 25739bea5ddSPyun YongHyeon sc->sc_mem_rid = PCIR_BAR(0); 2584d52a575SXin LI sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 2594d52a575SXin LI &sc->sc_mem_rid, RF_ACTIVE); 2604d52a575SXin LI if (sc->sc_mem_res == NULL) { 2614d52a575SXin LI device_printf(dev, "can't allocate IO memory\n"); 262398f1b65SPyun YongHyeon return (ENXIO); 2634d52a575SXin LI } 2644d52a575SXin LI 265cc3c3b4eSPyun YongHyeon msic = 0; 2663b0a4aefSJohn Baldwin if (pci_find_cap(dev, PCIY_EXPRESS, &cap) == 0) { 267cc3c3b4eSPyun YongHyeon sc->sc_expcap = cap; 268cc3c3b4eSPyun YongHyeon sc->sc_flags |= ET_FLAG_PCIE; 269cc3c3b4eSPyun YongHyeon msic = pci_msi_count(dev); 270cc3c3b4eSPyun YongHyeon if (bootverbose) 271cc3c3b4eSPyun YongHyeon device_printf(dev, "MSI count: %d\n", msic); 272cc3c3b4eSPyun YongHyeon } 273cc3c3b4eSPyun YongHyeon if (msic > 0 && msi_disable == 0) { 274cc3c3b4eSPyun YongHyeon msic = 1; 275cc3c3b4eSPyun YongHyeon if (pci_alloc_msi(dev, &msic) == 0) { 276cc3c3b4eSPyun YongHyeon if (msic == 1) { 277cc3c3b4eSPyun YongHyeon device_printf(dev, "Using %d MSI message\n", 278cc3c3b4eSPyun YongHyeon msic); 279cc3c3b4eSPyun YongHyeon sc->sc_flags |= ET_FLAG_MSI; 280cc3c3b4eSPyun YongHyeon } else 281cc3c3b4eSPyun YongHyeon pci_release_msi(dev); 282cc3c3b4eSPyun YongHyeon } 283cc3c3b4eSPyun YongHyeon } 284cc3c3b4eSPyun YongHyeon 2854d52a575SXin LI /* 2864d52a575SXin LI * Allocate IRQ 2874d52a575SXin LI */ 288cc3c3b4eSPyun YongHyeon if ((sc->sc_flags & ET_FLAG_MSI) == 0) { 2894d52a575SXin LI sc->sc_irq_rid = 0; 2904d52a575SXin LI sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 291cc3c3b4eSPyun YongHyeon &sc->sc_irq_rid, RF_SHAREABLE | RF_ACTIVE); 292cc3c3b4eSPyun YongHyeon } else { 293cc3c3b4eSPyun YongHyeon sc->sc_irq_rid = 1; 294cc3c3b4eSPyun YongHyeon sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 295cc3c3b4eSPyun YongHyeon &sc->sc_irq_rid, RF_ACTIVE); 296cc3c3b4eSPyun YongHyeon } 2974d52a575SXin LI if (sc->sc_irq_res == NULL) { 2984d52a575SXin LI device_printf(dev, "can't allocate irq\n"); 2994d52a575SXin LI error = ENXIO; 3004d52a575SXin LI goto fail; 3014d52a575SXin LI } 3024d52a575SXin LI 3031f009e2fSPyun YongHyeon if (pci_get_device(dev) == PCI_PRODUCT_LUCENT_ET1310_FAST) 3041f009e2fSPyun YongHyeon sc->sc_flags |= ET_FLAG_FASTETHER; 3051f009e2fSPyun YongHyeon 3068b3c6496SPyun YongHyeon error = et_bus_config(sc); 3074d52a575SXin LI if (error) 3084d52a575SXin LI goto fail; 3094d52a575SXin LI 3104d52a575SXin LI et_get_eaddr(dev, eaddr); 3114d52a575SXin LI 31238953bb0SPyun YongHyeon /* Take PHY out of COMA and enable clocks. */ 31338953bb0SPyun YongHyeon pmcfg = ET_PM_SYSCLK_GATE | ET_PM_TXCLK_GATE | ET_PM_RXCLK_GATE; 31438953bb0SPyun YongHyeon if ((sc->sc_flags & ET_FLAG_FASTETHER) == 0) 31538953bb0SPyun YongHyeon pmcfg |= EM_PM_GIGEPHY_ENB; 31638953bb0SPyun YongHyeon CSR_WRITE_4(sc, ET_PM, pmcfg); 3174d52a575SXin LI 3184d52a575SXin LI et_reset(sc); 3194d52a575SXin LI 32005884511SPyun YongHyeon error = et_dma_alloc(sc); 3214d52a575SXin LI if (error) 3224d52a575SXin LI goto fail; 3234d52a575SXin LI 324*7c509be1SJustin Hibbits if_setsoftc(ifp, sc); 3254d52a575SXin LI if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 326*7c509be1SJustin Hibbits if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 327*7c509be1SJustin Hibbits if_setinitfn(ifp, et_init); 328*7c509be1SJustin Hibbits if_setioctlfn(ifp, et_ioctl); 329*7c509be1SJustin Hibbits if_setstartfn(ifp, et_start); 330*7c509be1SJustin Hibbits if_setgetcounterfn(ifp, et_get_counter); 331*7c509be1SJustin Hibbits if_setcapabilities(ifp, IFCAP_TXCSUM | IFCAP_VLAN_MTU); 332*7c509be1SJustin Hibbits if_setcapenable(ifp, if_getcapabilities(ifp)); 333*7c509be1SJustin Hibbits if_setsendqlen(ifp, ET_TX_NDESC - 1); 334*7c509be1SJustin Hibbits if_setsendqready(ifp); 3354d52a575SXin LI 3364d52a575SXin LI et_chip_attach(sc); 3374d52a575SXin LI 338d6c65d27SMarius Strobl error = mii_attach(dev, &sc->sc_miibus, ifp, et_ifmedia_upd, 3395d384a0dSPyun YongHyeon et_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 3405d384a0dSPyun YongHyeon MIIF_DOPAUSE); 3414d52a575SXin LI if (error) { 342d6c65d27SMarius Strobl device_printf(dev, "attaching PHYs failed\n"); 3434d52a575SXin LI goto fail; 3444d52a575SXin LI } 3454d52a575SXin LI 3464d52a575SXin LI ether_ifattach(ifp, eaddr); 347d2f7028cSPyun YongHyeon 348d2f7028cSPyun YongHyeon /* Tell the upper layer(s) we support long frames. */ 349*7c509be1SJustin Hibbits if_setifheaderlen(ifp, sizeof(struct ether_vlan_header)); 3504d52a575SXin LI 3514d52a575SXin LI error = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_NET | INTR_MPSAFE, 3524d52a575SXin LI NULL, et_intr, sc, &sc->sc_irq_handle); 3534d52a575SXin LI if (error) { 3544d52a575SXin LI ether_ifdetach(ifp); 3554d52a575SXin LI device_printf(dev, "can't setup intr\n"); 3564d52a575SXin LI goto fail; 3574d52a575SXin LI } 3584d52a575SXin LI 3594d52a575SXin LI et_add_sysctls(sc); 3604d52a575SXin LI 361398f1b65SPyun YongHyeon return (0); 3624d52a575SXin LI fail: 3634d52a575SXin LI et_detach(dev); 364398f1b65SPyun YongHyeon return (error); 3654d52a575SXin LI } 3664d52a575SXin LI 3674d52a575SXin LI static int 3684d52a575SXin LI et_detach(device_t dev) 3694d52a575SXin LI { 3700b699044SPyun YongHyeon struct et_softc *sc; 3714d52a575SXin LI 3720b699044SPyun YongHyeon sc = device_get_softc(dev); 3734d52a575SXin LI if (device_is_attached(dev)) { 374a64788d1SPyun YongHyeon ether_ifdetach(sc->ifp); 3754d52a575SXin LI ET_LOCK(sc); 3764d52a575SXin LI et_stop(sc); 3774d52a575SXin LI ET_UNLOCK(sc); 378a64788d1SPyun YongHyeon callout_drain(&sc->sc_tick); 3794d52a575SXin LI } 3804d52a575SXin LI 3814d52a575SXin LI if (sc->sc_miibus != NULL) 3824d52a575SXin LI device_delete_child(dev, sc->sc_miibus); 3834d52a575SXin LI bus_generic_detach(dev); 3844d52a575SXin LI 385a64788d1SPyun YongHyeon if (sc->sc_irq_handle != NULL) 386a64788d1SPyun YongHyeon bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_handle); 387a64788d1SPyun YongHyeon if (sc->sc_irq_res != NULL) 388a64788d1SPyun YongHyeon bus_release_resource(dev, SYS_RES_IRQ, 389a64788d1SPyun YongHyeon rman_get_rid(sc->sc_irq_res), sc->sc_irq_res); 390cc3c3b4eSPyun YongHyeon if ((sc->sc_flags & ET_FLAG_MSI) != 0) 391cc3c3b4eSPyun YongHyeon pci_release_msi(dev); 392a64788d1SPyun YongHyeon if (sc->sc_mem_res != NULL) 393a64788d1SPyun YongHyeon bus_release_resource(dev, SYS_RES_MEMORY, 394a64788d1SPyun YongHyeon rman_get_rid(sc->sc_mem_res), sc->sc_mem_res); 3954d52a575SXin LI 3964d52a575SXin LI if (sc->ifp != NULL) 3974d52a575SXin LI if_free(sc->ifp); 3984d52a575SXin LI 39905884511SPyun YongHyeon et_dma_free(sc); 4005b8f4900SPyun YongHyeon 4015b8f4900SPyun YongHyeon mtx_destroy(&sc->sc_mtx); 4024d52a575SXin LI 403398f1b65SPyun YongHyeon return (0); 4044d52a575SXin LI } 4054d52a575SXin LI 4064d52a575SXin LI static int 4074d52a575SXin LI et_shutdown(device_t dev) 4084d52a575SXin LI { 4090b699044SPyun YongHyeon struct et_softc *sc; 4104d52a575SXin LI 4110b699044SPyun YongHyeon sc = device_get_softc(dev); 4124d52a575SXin LI ET_LOCK(sc); 4134d52a575SXin LI et_stop(sc); 4144d52a575SXin LI ET_UNLOCK(sc); 415398f1b65SPyun YongHyeon return (0); 4164d52a575SXin LI } 4174d52a575SXin LI 4184d52a575SXin LI static int 4194d52a575SXin LI et_miibus_readreg(device_t dev, int phy, int reg) 4204d52a575SXin LI { 4210b699044SPyun YongHyeon struct et_softc *sc; 4224d52a575SXin LI uint32_t val; 4234d52a575SXin LI int i, ret; 4244d52a575SXin LI 4250b699044SPyun YongHyeon sc = device_get_softc(dev); 4264d52a575SXin LI /* Stop any pending operations */ 4274d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CMD, 0); 4284d52a575SXin LI 42923263665SPyun YongHyeon val = (phy << ET_MII_ADDR_PHY_SHIFT) & ET_MII_ADDR_PHY_MASK; 43023263665SPyun YongHyeon val |= (reg << ET_MII_ADDR_REG_SHIFT) & ET_MII_ADDR_REG_MASK; 4314d52a575SXin LI CSR_WRITE_4(sc, ET_MII_ADDR, val); 4324d52a575SXin LI 4334d52a575SXin LI /* Start reading */ 4344d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CMD, ET_MII_CMD_READ); 4354d52a575SXin LI 4364d52a575SXin LI #define NRETRY 50 4374d52a575SXin LI 4384d52a575SXin LI for (i = 0; i < NRETRY; ++i) { 4394d52a575SXin LI val = CSR_READ_4(sc, ET_MII_IND); 4404d52a575SXin LI if ((val & (ET_MII_IND_BUSY | ET_MII_IND_INVALID)) == 0) 4414d52a575SXin LI break; 4424d52a575SXin LI DELAY(50); 4434d52a575SXin LI } 4444d52a575SXin LI if (i == NRETRY) { 4454d52a575SXin LI if_printf(sc->ifp, 4464d52a575SXin LI "read phy %d, reg %d timed out\n", phy, reg); 4474d52a575SXin LI ret = 0; 4484d52a575SXin LI goto back; 4494d52a575SXin LI } 4504d52a575SXin LI 4514d52a575SXin LI #undef NRETRY 4524d52a575SXin LI 4534d52a575SXin LI val = CSR_READ_4(sc, ET_MII_STAT); 45423263665SPyun YongHyeon ret = val & ET_MII_STAT_VALUE_MASK; 4554d52a575SXin LI 4564d52a575SXin LI back: 4574d52a575SXin LI /* Make sure that the current operation is stopped */ 4584d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CMD, 0); 459398f1b65SPyun YongHyeon return (ret); 4604d52a575SXin LI } 4614d52a575SXin LI 4624d52a575SXin LI static int 4634d52a575SXin LI et_miibus_writereg(device_t dev, int phy, int reg, int val0) 4644d52a575SXin LI { 4650b699044SPyun YongHyeon struct et_softc *sc; 4664d52a575SXin LI uint32_t val; 4674d52a575SXin LI int i; 4684d52a575SXin LI 4690b699044SPyun YongHyeon sc = device_get_softc(dev); 4704d52a575SXin LI /* Stop any pending operations */ 4714d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CMD, 0); 4724d52a575SXin LI 47323263665SPyun YongHyeon val = (phy << ET_MII_ADDR_PHY_SHIFT) & ET_MII_ADDR_PHY_MASK; 47423263665SPyun YongHyeon val |= (reg << ET_MII_ADDR_REG_SHIFT) & ET_MII_ADDR_REG_MASK; 4754d52a575SXin LI CSR_WRITE_4(sc, ET_MII_ADDR, val); 4764d52a575SXin LI 4774d52a575SXin LI /* Start writing */ 47823263665SPyun YongHyeon CSR_WRITE_4(sc, ET_MII_CTRL, 47923263665SPyun YongHyeon (val0 << ET_MII_CTRL_VALUE_SHIFT) & ET_MII_CTRL_VALUE_MASK); 4804d52a575SXin LI 4814d52a575SXin LI #define NRETRY 100 4824d52a575SXin LI 4834d52a575SXin LI for (i = 0; i < NRETRY; ++i) { 4844d52a575SXin LI val = CSR_READ_4(sc, ET_MII_IND); 4854d52a575SXin LI if ((val & ET_MII_IND_BUSY) == 0) 4864d52a575SXin LI break; 4874d52a575SXin LI DELAY(50); 4884d52a575SXin LI } 4894d52a575SXin LI if (i == NRETRY) { 4904d52a575SXin LI if_printf(sc->ifp, 4914d52a575SXin LI "write phy %d, reg %d timed out\n", phy, reg); 4924d52a575SXin LI et_miibus_readreg(dev, phy, reg); 4934d52a575SXin LI } 4944d52a575SXin LI 4954d52a575SXin LI #undef NRETRY 4964d52a575SXin LI 4974d52a575SXin LI /* Make sure that the current operation is stopped */ 4984d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CMD, 0); 499398f1b65SPyun YongHyeon return (0); 5004d52a575SXin LI } 5014d52a575SXin LI 5024d52a575SXin LI static void 5034d52a575SXin LI et_miibus_statchg(device_t dev) 5044d52a575SXin LI { 5051f009e2fSPyun YongHyeon struct et_softc *sc; 5061f009e2fSPyun YongHyeon struct mii_data *mii; 507*7c509be1SJustin Hibbits if_t ifp; 5081f009e2fSPyun YongHyeon uint32_t cfg1, cfg2, ctrl; 5091f009e2fSPyun YongHyeon int i; 5101f009e2fSPyun YongHyeon 5111f009e2fSPyun YongHyeon sc = device_get_softc(dev); 5121f009e2fSPyun YongHyeon 5131f009e2fSPyun YongHyeon mii = device_get_softc(sc->sc_miibus); 5141f009e2fSPyun YongHyeon ifp = sc->ifp; 5151f009e2fSPyun YongHyeon if (mii == NULL || ifp == NULL || 516*7c509be1SJustin Hibbits (if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) 5171f009e2fSPyun YongHyeon return; 5181f009e2fSPyun YongHyeon 5191f009e2fSPyun YongHyeon sc->sc_flags &= ~ET_FLAG_LINK; 5201f009e2fSPyun YongHyeon if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 5211f009e2fSPyun YongHyeon (IFM_ACTIVE | IFM_AVALID)) { 5221f009e2fSPyun YongHyeon switch (IFM_SUBTYPE(mii->mii_media_active)) { 5231f009e2fSPyun YongHyeon case IFM_10_T: 5241f009e2fSPyun YongHyeon case IFM_100_TX: 5251f009e2fSPyun YongHyeon sc->sc_flags |= ET_FLAG_LINK; 5261f009e2fSPyun YongHyeon break; 5271f009e2fSPyun YongHyeon case IFM_1000_T: 5281f009e2fSPyun YongHyeon if ((sc->sc_flags & ET_FLAG_FASTETHER) == 0) 5291f009e2fSPyun YongHyeon sc->sc_flags |= ET_FLAG_LINK; 5301f009e2fSPyun YongHyeon break; 5311f009e2fSPyun YongHyeon } 5321f009e2fSPyun YongHyeon } 5331f009e2fSPyun YongHyeon 5341f009e2fSPyun YongHyeon /* XXX Stop TX/RX MAC? */ 5351f009e2fSPyun YongHyeon if ((sc->sc_flags & ET_FLAG_LINK) == 0) 5361f009e2fSPyun YongHyeon return; 5371f009e2fSPyun YongHyeon 5381f009e2fSPyun YongHyeon /* Program MACs with resolved speed/duplex/flow-control. */ 5391f009e2fSPyun YongHyeon ctrl = CSR_READ_4(sc, ET_MAC_CTRL); 5401f009e2fSPyun YongHyeon ctrl &= ~(ET_MAC_CTRL_GHDX | ET_MAC_CTRL_MODE_MII); 5411f009e2fSPyun YongHyeon cfg1 = CSR_READ_4(sc, ET_MAC_CFG1); 5421f009e2fSPyun YongHyeon cfg1 &= ~(ET_MAC_CFG1_TXFLOW | ET_MAC_CFG1_RXFLOW | 5431f009e2fSPyun YongHyeon ET_MAC_CFG1_LOOPBACK); 5441f009e2fSPyun YongHyeon cfg2 = CSR_READ_4(sc, ET_MAC_CFG2); 5451f009e2fSPyun YongHyeon cfg2 &= ~(ET_MAC_CFG2_MODE_MII | ET_MAC_CFG2_MODE_GMII | 5461f009e2fSPyun YongHyeon ET_MAC_CFG2_FDX | ET_MAC_CFG2_BIGFRM); 5471f009e2fSPyun YongHyeon cfg2 |= ET_MAC_CFG2_LENCHK | ET_MAC_CFG2_CRC | ET_MAC_CFG2_PADCRC | 5481f009e2fSPyun YongHyeon ((7 << ET_MAC_CFG2_PREAMBLE_LEN_SHIFT) & 5491f009e2fSPyun YongHyeon ET_MAC_CFG2_PREAMBLE_LEN_MASK); 5501f009e2fSPyun YongHyeon 5511f009e2fSPyun YongHyeon if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) 5521f009e2fSPyun YongHyeon cfg2 |= ET_MAC_CFG2_MODE_GMII; 5531f009e2fSPyun YongHyeon else { 5541f009e2fSPyun YongHyeon cfg2 |= ET_MAC_CFG2_MODE_MII; 5551f009e2fSPyun YongHyeon ctrl |= ET_MAC_CTRL_MODE_MII; 5561f009e2fSPyun YongHyeon } 5571f009e2fSPyun YongHyeon 5581f009e2fSPyun YongHyeon if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) { 5591f009e2fSPyun YongHyeon cfg2 |= ET_MAC_CFG2_FDX; 5605d384a0dSPyun YongHyeon /* 5615d384a0dSPyun YongHyeon * Controller lacks automatic TX pause frame 5625d384a0dSPyun YongHyeon * generation so it should be handled by driver. 5635d384a0dSPyun YongHyeon * Even though driver can send pause frame with 5645d384a0dSPyun YongHyeon * arbitrary pause time, controller does not 5655d384a0dSPyun YongHyeon * provide a way that tells how many free RX 5665d384a0dSPyun YongHyeon * buffers are available in controller. This 5675d384a0dSPyun YongHyeon * limitation makes it hard to generate XON frame 5685d384a0dSPyun YongHyeon * in time on driver side so don't enable TX flow 5695d384a0dSPyun YongHyeon * control. 5705d384a0dSPyun YongHyeon */ 5711f009e2fSPyun YongHyeon #ifdef notyet 5721f009e2fSPyun YongHyeon if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) 5731f009e2fSPyun YongHyeon cfg1 |= ET_MAC_CFG1_TXFLOW; 5745d384a0dSPyun YongHyeon #endif 5751f009e2fSPyun YongHyeon if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) 5761f009e2fSPyun YongHyeon cfg1 |= ET_MAC_CFG1_RXFLOW; 5771f009e2fSPyun YongHyeon } else 5781f009e2fSPyun YongHyeon ctrl |= ET_MAC_CTRL_GHDX; 5791f009e2fSPyun YongHyeon 5801f009e2fSPyun YongHyeon CSR_WRITE_4(sc, ET_MAC_CTRL, ctrl); 5811f009e2fSPyun YongHyeon CSR_WRITE_4(sc, ET_MAC_CFG2, cfg2); 5821f009e2fSPyun YongHyeon cfg1 |= ET_MAC_CFG1_TXEN | ET_MAC_CFG1_RXEN; 5831f009e2fSPyun YongHyeon CSR_WRITE_4(sc, ET_MAC_CFG1, cfg1); 5841f009e2fSPyun YongHyeon 5851f009e2fSPyun YongHyeon #define NRETRY 50 5861f009e2fSPyun YongHyeon 5871f009e2fSPyun YongHyeon for (i = 0; i < NRETRY; ++i) { 5881f009e2fSPyun YongHyeon cfg1 = CSR_READ_4(sc, ET_MAC_CFG1); 5891f009e2fSPyun YongHyeon if ((cfg1 & (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) == 5901f009e2fSPyun YongHyeon (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) 5911f009e2fSPyun YongHyeon break; 5921f009e2fSPyun YongHyeon DELAY(100); 5931f009e2fSPyun YongHyeon } 5941f009e2fSPyun YongHyeon if (i == NRETRY) 5951f009e2fSPyun YongHyeon if_printf(ifp, "can't enable RX/TX\n"); 5961f009e2fSPyun YongHyeon sc->sc_flags |= ET_FLAG_TXRX_ENABLED; 5971f009e2fSPyun YongHyeon 5981f009e2fSPyun YongHyeon #undef NRETRY 5994d52a575SXin LI } 6004d52a575SXin LI 6014d52a575SXin LI static int 602*7c509be1SJustin Hibbits et_ifmedia_upd_locked(if_t ifp) 6034d52a575SXin LI { 6040b699044SPyun YongHyeon struct et_softc *sc; 6050b699044SPyun YongHyeon struct mii_data *mii; 6064d52a575SXin LI struct mii_softc *miisc; 6074d52a575SXin LI 608*7c509be1SJustin Hibbits sc = if_getsoftc(ifp); 6090b699044SPyun YongHyeon mii = device_get_softc(sc->sc_miibus); 6104d52a575SXin LI LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 6113fcb7a53SMarius Strobl PHY_RESET(miisc); 61296570638SPyun YongHyeon return (mii_mediachg(mii)); 6134d52a575SXin LI } 6144d52a575SXin LI 6154d52a575SXin LI static int 616*7c509be1SJustin Hibbits et_ifmedia_upd(if_t ifp) 6174d52a575SXin LI { 6180b699044SPyun YongHyeon struct et_softc *sc; 6194d52a575SXin LI int res; 6204d52a575SXin LI 621*7c509be1SJustin Hibbits sc = if_getsoftc(ifp); 6224d52a575SXin LI ET_LOCK(sc); 6234d52a575SXin LI res = et_ifmedia_upd_locked(ifp); 6244d52a575SXin LI ET_UNLOCK(sc); 6254d52a575SXin LI 626398f1b65SPyun YongHyeon return (res); 6274d52a575SXin LI } 6284d52a575SXin LI 6294d52a575SXin LI static void 630*7c509be1SJustin Hibbits et_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr) 6314d52a575SXin LI { 6321f009e2fSPyun YongHyeon struct et_softc *sc; 6331f009e2fSPyun YongHyeon struct mii_data *mii; 6344d52a575SXin LI 635*7c509be1SJustin Hibbits sc = if_getsoftc(ifp); 6360ae9f6a9SPyun YongHyeon ET_LOCK(sc); 637*7c509be1SJustin Hibbits if ((if_getflags(ifp) & IFF_UP) == 0) { 6381f009e2fSPyun YongHyeon ET_UNLOCK(sc); 6391f009e2fSPyun YongHyeon return; 6401f009e2fSPyun YongHyeon } 6411f009e2fSPyun YongHyeon 6421f009e2fSPyun YongHyeon mii = device_get_softc(sc->sc_miibus); 6434d52a575SXin LI mii_pollstat(mii); 6444d52a575SXin LI ifmr->ifm_active = mii->mii_media_active; 6454d52a575SXin LI ifmr->ifm_status = mii->mii_media_status; 6460ae9f6a9SPyun YongHyeon ET_UNLOCK(sc); 6474d52a575SXin LI } 6484d52a575SXin LI 6494d52a575SXin LI static void 6504d52a575SXin LI et_stop(struct et_softc *sc) 6514d52a575SXin LI { 652*7c509be1SJustin Hibbits if_t ifp; 6534d52a575SXin LI 6544d52a575SXin LI ET_LOCK_ASSERT(sc); 6554d52a575SXin LI 6560b699044SPyun YongHyeon ifp = sc->ifp; 6574d52a575SXin LI callout_stop(&sc->sc_tick); 6586537ffa6SPyun YongHyeon /* Disable interrupts. */ 6596537ffa6SPyun YongHyeon CSR_WRITE_4(sc, ET_INTR_MASK, 0xffffffff); 6604d52a575SXin LI 6611f009e2fSPyun YongHyeon CSR_WRITE_4(sc, ET_MAC_CFG1, CSR_READ_4(sc, ET_MAC_CFG1) & ~( 6621f009e2fSPyun YongHyeon ET_MAC_CFG1_TXEN | ET_MAC_CFG1_RXEN)); 6631f009e2fSPyun YongHyeon DELAY(100); 6641f009e2fSPyun YongHyeon 6654d52a575SXin LI et_stop_rxdma(sc); 6664d52a575SXin LI et_stop_txdma(sc); 667e0b5ac02SPyun YongHyeon et_stats_update(sc); 6684d52a575SXin LI 6694d52a575SXin LI et_free_tx_ring(sc); 6704d52a575SXin LI et_free_rx_ring(sc); 6714d52a575SXin LI 6724d52a575SXin LI sc->sc_tx = 0; 6734d52a575SXin LI sc->sc_tx_intr = 0; 6744d52a575SXin LI sc->sc_flags &= ~ET_FLAG_TXRX_ENABLED; 6754d52a575SXin LI 6764d52a575SXin LI sc->watchdog_timer = 0; 677*7c509be1SJustin Hibbits if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)); 6784d52a575SXin LI } 6794d52a575SXin LI 6804d52a575SXin LI static int 6818b3c6496SPyun YongHyeon et_bus_config(struct et_softc *sc) 6824d52a575SXin LI { 6834d52a575SXin LI uint32_t val, max_plsz; 6844d52a575SXin LI uint16_t ack_latency, replay_timer; 6854d52a575SXin LI 6864d52a575SXin LI /* 6874d52a575SXin LI * Test whether EEPROM is valid 6884d52a575SXin LI * NOTE: Read twice to get the correct value 6894d52a575SXin LI */ 6908b3c6496SPyun YongHyeon pci_read_config(sc->dev, ET_PCIR_EEPROM_STATUS, 1); 6918b3c6496SPyun YongHyeon val = pci_read_config(sc->dev, ET_PCIR_EEPROM_STATUS, 1); 6924d52a575SXin LI if (val & ET_PCIM_EEPROM_STATUS_ERROR) { 6938b3c6496SPyun YongHyeon device_printf(sc->dev, "EEPROM status error 0x%02x\n", val); 694398f1b65SPyun YongHyeon return (ENXIO); 6954d52a575SXin LI } 6964d52a575SXin LI 6974d52a575SXin LI /* TODO: LED */ 6984d52a575SXin LI 6998b3c6496SPyun YongHyeon if ((sc->sc_flags & ET_FLAG_PCIE) == 0) 7008b3c6496SPyun YongHyeon return (0); 7018b3c6496SPyun YongHyeon 7024d52a575SXin LI /* 7034d52a575SXin LI * Configure ACK latency and replay timer according to 7044d52a575SXin LI * max playload size 7054d52a575SXin LI */ 7068b3c6496SPyun YongHyeon val = pci_read_config(sc->dev, 707389c8bd5SGavin Atkinson sc->sc_expcap + PCIER_DEVICE_CAP, 4); 708389c8bd5SGavin Atkinson max_plsz = val & PCIEM_CAP_MAX_PAYLOAD; 7094d52a575SXin LI 7104d52a575SXin LI switch (max_plsz) { 7114d52a575SXin LI case ET_PCIV_DEVICE_CAPS_PLSZ_128: 7124d52a575SXin LI ack_latency = ET_PCIV_ACK_LATENCY_128; 7134d52a575SXin LI replay_timer = ET_PCIV_REPLAY_TIMER_128; 7144d52a575SXin LI break; 7154d52a575SXin LI 7164d52a575SXin LI case ET_PCIV_DEVICE_CAPS_PLSZ_256: 7174d52a575SXin LI ack_latency = ET_PCIV_ACK_LATENCY_256; 7184d52a575SXin LI replay_timer = ET_PCIV_REPLAY_TIMER_256; 7194d52a575SXin LI break; 7204d52a575SXin LI 7214d52a575SXin LI default: 7228b3c6496SPyun YongHyeon ack_latency = pci_read_config(sc->dev, ET_PCIR_ACK_LATENCY, 2); 7238b3c6496SPyun YongHyeon replay_timer = pci_read_config(sc->dev, 7248b3c6496SPyun YongHyeon ET_PCIR_REPLAY_TIMER, 2); 7258b3c6496SPyun YongHyeon device_printf(sc->dev, "ack latency %u, replay timer %u\n", 7264d52a575SXin LI ack_latency, replay_timer); 7274d52a575SXin LI break; 7284d52a575SXin LI } 7294d52a575SXin LI if (ack_latency != 0) { 7308b3c6496SPyun YongHyeon pci_write_config(sc->dev, ET_PCIR_ACK_LATENCY, ack_latency, 2); 7318b3c6496SPyun YongHyeon pci_write_config(sc->dev, ET_PCIR_REPLAY_TIMER, replay_timer, 7328b3c6496SPyun YongHyeon 2); 7334d52a575SXin LI } 7344d52a575SXin LI 7354d52a575SXin LI /* 7364d52a575SXin LI * Set L0s and L1 latency timer to 2us 7374d52a575SXin LI */ 7388b3c6496SPyun YongHyeon val = pci_read_config(sc->dev, ET_PCIR_L0S_L1_LATENCY, 4); 739389c8bd5SGavin Atkinson val &= ~(PCIEM_LINK_CAP_L0S_EXIT | PCIEM_LINK_CAP_L1_EXIT); 74023263665SPyun YongHyeon /* L0s exit latency : 2us */ 74123263665SPyun YongHyeon val |= 0x00005000; 74223263665SPyun YongHyeon /* L1 exit latency : 2us */ 74323263665SPyun YongHyeon val |= 0x00028000; 7448b3c6496SPyun YongHyeon pci_write_config(sc->dev, ET_PCIR_L0S_L1_LATENCY, val, 4); 7454d52a575SXin LI 7464d52a575SXin LI /* 7474d52a575SXin LI * Set max read request size to 2048 bytes 7484d52a575SXin LI */ 74939bea5ddSPyun YongHyeon pci_set_max_read_req(sc->dev, 2048); 7504d52a575SXin LI 751398f1b65SPyun YongHyeon return (0); 7524d52a575SXin LI } 7534d52a575SXin LI 7544d52a575SXin LI static void 7554d52a575SXin LI et_get_eaddr(device_t dev, uint8_t eaddr[]) 7564d52a575SXin LI { 7574d52a575SXin LI uint32_t val; 7584d52a575SXin LI int i; 7594d52a575SXin LI 7604d52a575SXin LI val = pci_read_config(dev, ET_PCIR_MAC_ADDR0, 4); 7614d52a575SXin LI for (i = 0; i < 4; ++i) 7624d52a575SXin LI eaddr[i] = (val >> (8 * i)) & 0xff; 7634d52a575SXin LI 7644d52a575SXin LI val = pci_read_config(dev, ET_PCIR_MAC_ADDR1, 2); 7654d52a575SXin LI for (; i < ETHER_ADDR_LEN; ++i) 7664d52a575SXin LI eaddr[i] = (val >> (8 * (i - 4))) & 0xff; 7674d52a575SXin LI } 7684d52a575SXin LI 7694d52a575SXin LI static void 7704d52a575SXin LI et_reset(struct et_softc *sc) 7714d52a575SXin LI { 7720b699044SPyun YongHyeon 7734d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 7744d52a575SXin LI ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 7754d52a575SXin LI ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | 7764d52a575SXin LI ET_MAC_CFG1_SIM_RST | ET_MAC_CFG1_SOFT_RST); 7774d52a575SXin LI 7784d52a575SXin LI CSR_WRITE_4(sc, ET_SWRST, 7794d52a575SXin LI ET_SWRST_TXDMA | ET_SWRST_RXDMA | 7804d52a575SXin LI ET_SWRST_TXMAC | ET_SWRST_RXMAC | 7814d52a575SXin LI ET_SWRST_MAC | ET_SWRST_MAC_STAT | ET_SWRST_MMC); 7824d52a575SXin LI 7834d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 7844d52a575SXin LI ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 7854d52a575SXin LI ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC); 7864d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 0); 7876537ffa6SPyun YongHyeon /* Disable interrupts. */ 7884d52a575SXin LI CSR_WRITE_4(sc, ET_INTR_MASK, 0xffffffff); 7894d52a575SXin LI } 7904d52a575SXin LI 79105884511SPyun YongHyeon struct et_dmamap_arg { 79205884511SPyun YongHyeon bus_addr_t et_busaddr; 79305884511SPyun YongHyeon }; 79405884511SPyun YongHyeon 79505884511SPyun YongHyeon static void 79605884511SPyun YongHyeon et_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 7974d52a575SXin LI { 79805884511SPyun YongHyeon struct et_dmamap_arg *ctx; 79905884511SPyun YongHyeon 80005884511SPyun YongHyeon if (error) 80105884511SPyun YongHyeon return; 80205884511SPyun YongHyeon 80305884511SPyun YongHyeon KASSERT(nseg == 1, ("%s: %d segments returned!", __func__, nseg)); 80405884511SPyun YongHyeon 80505884511SPyun YongHyeon ctx = arg; 80605884511SPyun YongHyeon ctx->et_busaddr = segs->ds_addr; 80705884511SPyun YongHyeon } 80805884511SPyun YongHyeon 80905884511SPyun YongHyeon static int 81005884511SPyun YongHyeon et_dma_ring_alloc(struct et_softc *sc, bus_size_t alignment, bus_size_t maxsize, 81105884511SPyun YongHyeon bus_dma_tag_t *tag, uint8_t **ring, bus_dmamap_t *map, bus_addr_t *paddr, 81205884511SPyun YongHyeon const char *msg) 81305884511SPyun YongHyeon { 81405884511SPyun YongHyeon struct et_dmamap_arg ctx; 81505884511SPyun YongHyeon int error; 81605884511SPyun YongHyeon 81705884511SPyun YongHyeon error = bus_dma_tag_create(sc->sc_dtag, alignment, 0, BUS_SPACE_MAXADDR, 81805884511SPyun YongHyeon BUS_SPACE_MAXADDR, NULL, NULL, maxsize, 1, maxsize, 0, NULL, NULL, 81905884511SPyun YongHyeon tag); 82005884511SPyun YongHyeon if (error != 0) { 82105884511SPyun YongHyeon device_printf(sc->dev, "could not create %s dma tag\n", msg); 82205884511SPyun YongHyeon return (error); 82305884511SPyun YongHyeon } 82405884511SPyun YongHyeon /* Allocate DMA'able memory for ring. */ 82505884511SPyun YongHyeon error = bus_dmamem_alloc(*tag, (void **)ring, 82605884511SPyun YongHyeon BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, map); 82705884511SPyun YongHyeon if (error != 0) { 82805884511SPyun YongHyeon device_printf(sc->dev, 82905884511SPyun YongHyeon "could not allocate DMA'able memory for %s\n", msg); 83005884511SPyun YongHyeon return (error); 83105884511SPyun YongHyeon } 83205884511SPyun YongHyeon /* Load the address of the ring. */ 83305884511SPyun YongHyeon ctx.et_busaddr = 0; 83405884511SPyun YongHyeon error = bus_dmamap_load(*tag, *map, *ring, maxsize, et_dma_map_addr, 83505884511SPyun YongHyeon &ctx, BUS_DMA_NOWAIT); 83605884511SPyun YongHyeon if (error != 0) { 83705884511SPyun YongHyeon device_printf(sc->dev, 83805884511SPyun YongHyeon "could not load DMA'able memory for %s\n", msg); 83905884511SPyun YongHyeon return (error); 84005884511SPyun YongHyeon } 84105884511SPyun YongHyeon *paddr = ctx.et_busaddr; 84205884511SPyun YongHyeon return (0); 84305884511SPyun YongHyeon } 84405884511SPyun YongHyeon 84505884511SPyun YongHyeon static void 84605884511SPyun YongHyeon et_dma_ring_free(struct et_softc *sc, bus_dma_tag_t *tag, uint8_t **ring, 847c34f1a08SJohn Baldwin bus_dmamap_t map, bus_addr_t *paddr) 84805884511SPyun YongHyeon { 84905884511SPyun YongHyeon 850c34f1a08SJohn Baldwin if (*paddr != 0) { 851c34f1a08SJohn Baldwin bus_dmamap_unload(*tag, map); 852c34f1a08SJohn Baldwin *paddr = 0; 853c34f1a08SJohn Baldwin } 854c34f1a08SJohn Baldwin if (*ring != NULL) { 855c34f1a08SJohn Baldwin bus_dmamem_free(*tag, *ring, map); 85605884511SPyun YongHyeon *ring = NULL; 85705884511SPyun YongHyeon } 85805884511SPyun YongHyeon if (*tag) { 85905884511SPyun YongHyeon bus_dma_tag_destroy(*tag); 86005884511SPyun YongHyeon *tag = NULL; 86105884511SPyun YongHyeon } 86205884511SPyun YongHyeon } 86305884511SPyun YongHyeon 86405884511SPyun YongHyeon static int 86505884511SPyun YongHyeon et_dma_alloc(struct et_softc *sc) 86605884511SPyun YongHyeon { 86705884511SPyun YongHyeon struct et_txdesc_ring *tx_ring; 86805884511SPyun YongHyeon struct et_rxdesc_ring *rx_ring; 86905884511SPyun YongHyeon struct et_rxstat_ring *rxst_ring; 87005884511SPyun YongHyeon struct et_rxstatus_data *rxsd; 87105884511SPyun YongHyeon struct et_rxbuf_data *rbd; 87205884511SPyun YongHyeon struct et_txbuf_data *tbd; 87305884511SPyun YongHyeon struct et_txstatus_data *txsd; 8744d52a575SXin LI int i, error; 8754d52a575SXin LI 87605884511SPyun YongHyeon error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1, 0, 87705884511SPyun YongHyeon BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 87805884511SPyun YongHyeon BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL, 87905884511SPyun YongHyeon &sc->sc_dtag); 88005884511SPyun YongHyeon if (error != 0) { 88105884511SPyun YongHyeon device_printf(sc->dev, "could not allocate parent dma tag\n"); 882398f1b65SPyun YongHyeon return (error); 8834d52a575SXin LI } 8844d52a575SXin LI 88505884511SPyun YongHyeon /* TX ring. */ 88605884511SPyun YongHyeon tx_ring = &sc->sc_tx_ring; 88705884511SPyun YongHyeon error = et_dma_ring_alloc(sc, ET_RING_ALIGN, ET_TX_RING_SIZE, 88805884511SPyun YongHyeon &tx_ring->tr_dtag, (uint8_t **)&tx_ring->tr_desc, &tx_ring->tr_dmap, 88905884511SPyun YongHyeon &tx_ring->tr_paddr, "TX ring"); 8904d52a575SXin LI if (error) 891398f1b65SPyun YongHyeon return (error); 8924d52a575SXin LI 89305884511SPyun YongHyeon /* TX status block. */ 89405884511SPyun YongHyeon txsd = &sc->sc_tx_status; 89505884511SPyun YongHyeon error = et_dma_ring_alloc(sc, ET_STATUS_ALIGN, sizeof(uint32_t), 89605884511SPyun YongHyeon &txsd->txsd_dtag, (uint8_t **)&txsd->txsd_status, &txsd->txsd_dmap, 89705884511SPyun YongHyeon &txsd->txsd_paddr, "TX status block"); 89805884511SPyun YongHyeon if (error) 89905884511SPyun YongHyeon return (error); 9004d52a575SXin LI 90105884511SPyun YongHyeon /* RX ring 0, used as to recive small sized frames. */ 90205884511SPyun YongHyeon rx_ring = &sc->sc_rx_ring[0]; 90305884511SPyun YongHyeon error = et_dma_ring_alloc(sc, ET_RING_ALIGN, ET_RX_RING_SIZE, 90405884511SPyun YongHyeon &rx_ring->rr_dtag, (uint8_t **)&rx_ring->rr_desc, &rx_ring->rr_dmap, 90505884511SPyun YongHyeon &rx_ring->rr_paddr, "RX ring 0"); 90605884511SPyun YongHyeon rx_ring->rr_posreg = ET_RX_RING0_POS; 90705884511SPyun YongHyeon if (error) 90805884511SPyun YongHyeon return (error); 9094d52a575SXin LI 91005884511SPyun YongHyeon /* RX ring 1, used as to store normal sized frames. */ 91105884511SPyun YongHyeon rx_ring = &sc->sc_rx_ring[1]; 91205884511SPyun YongHyeon error = et_dma_ring_alloc(sc, ET_RING_ALIGN, ET_RX_RING_SIZE, 91305884511SPyun YongHyeon &rx_ring->rr_dtag, (uint8_t **)&rx_ring->rr_desc, &rx_ring->rr_dmap, 91405884511SPyun YongHyeon &rx_ring->rr_paddr, "RX ring 1"); 91505884511SPyun YongHyeon rx_ring->rr_posreg = ET_RX_RING1_POS; 91605884511SPyun YongHyeon if (error) 91705884511SPyun YongHyeon return (error); 9184d52a575SXin LI 91905884511SPyun YongHyeon /* RX stat ring. */ 92005884511SPyun YongHyeon rxst_ring = &sc->sc_rxstat_ring; 92105884511SPyun YongHyeon error = et_dma_ring_alloc(sc, ET_RING_ALIGN, ET_RXSTAT_RING_SIZE, 92205884511SPyun YongHyeon &rxst_ring->rsr_dtag, (uint8_t **)&rxst_ring->rsr_stat, 92305884511SPyun YongHyeon &rxst_ring->rsr_dmap, &rxst_ring->rsr_paddr, "RX stat ring"); 92405884511SPyun YongHyeon if (error) 92505884511SPyun YongHyeon return (error); 9264d52a575SXin LI 92705884511SPyun YongHyeon /* RX status block. */ 92805884511SPyun YongHyeon rxsd = &sc->sc_rx_status; 92905884511SPyun YongHyeon error = et_dma_ring_alloc(sc, ET_STATUS_ALIGN, 93005884511SPyun YongHyeon sizeof(struct et_rxstatus), &rxsd->rxsd_dtag, 93105884511SPyun YongHyeon (uint8_t **)&rxsd->rxsd_status, &rxsd->rxsd_dmap, 93205884511SPyun YongHyeon &rxsd->rxsd_paddr, "RX status block"); 93305884511SPyun YongHyeon if (error) 93405884511SPyun YongHyeon return (error); 9354d52a575SXin LI 93605884511SPyun YongHyeon /* Create parent DMA tag for mbufs. */ 93705884511SPyun YongHyeon error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1, 0, 93805884511SPyun YongHyeon BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 93905884511SPyun YongHyeon BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL, 94005884511SPyun YongHyeon &sc->sc_mbuf_dtag); 94105884511SPyun YongHyeon if (error != 0) { 94205884511SPyun YongHyeon device_printf(sc->dev, 94305884511SPyun YongHyeon "could not allocate parent dma tag for mbuf\n"); 944398f1b65SPyun YongHyeon return (error); 9454d52a575SXin LI } 9464d52a575SXin LI 94705884511SPyun YongHyeon /* Create DMA tag for mini RX mbufs to use RX ring 0. */ 94805884511SPyun YongHyeon error = bus_dma_tag_create(sc->sc_mbuf_dtag, 1, 0, 94905884511SPyun YongHyeon BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MHLEN, 1, 95005884511SPyun YongHyeon MHLEN, 0, NULL, NULL, &sc->sc_rx_mini_tag); 9514d52a575SXin LI if (error) { 95205884511SPyun YongHyeon device_printf(sc->dev, "could not create mini RX dma tag\n"); 953398f1b65SPyun YongHyeon return (error); 9544d52a575SXin LI } 9554d52a575SXin LI 95605884511SPyun YongHyeon /* Create DMA tag for standard RX mbufs to use RX ring 1. */ 95705884511SPyun YongHyeon error = bus_dma_tag_create(sc->sc_mbuf_dtag, 1, 0, 95805884511SPyun YongHyeon BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, 95905884511SPyun YongHyeon MCLBYTES, 0, NULL, NULL, &sc->sc_rx_tag); 9604d52a575SXin LI if (error) { 96105884511SPyun YongHyeon device_printf(sc->dev, "could not create RX dma tag\n"); 962398f1b65SPyun YongHyeon return (error); 9634d52a575SXin LI } 9644d52a575SXin LI 96505884511SPyun YongHyeon /* Create DMA tag for TX mbufs. */ 96605884511SPyun YongHyeon error = bus_dma_tag_create(sc->sc_mbuf_dtag, 1, 0, 96705884511SPyun YongHyeon BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 96805884511SPyun YongHyeon MCLBYTES * ET_NSEG_MAX, ET_NSEG_MAX, MCLBYTES, 0, NULL, NULL, 96905884511SPyun YongHyeon &sc->sc_tx_tag); 97005884511SPyun YongHyeon if (error) { 97105884511SPyun YongHyeon device_printf(sc->dev, "could not create TX dma tag\n"); 97205884511SPyun YongHyeon return (error); 97305884511SPyun YongHyeon } 97405884511SPyun YongHyeon 97505884511SPyun YongHyeon /* Initialize RX ring 0. */ 97605884511SPyun YongHyeon rbd = &sc->sc_rx_data[0]; 97705884511SPyun YongHyeon rbd->rbd_bufsize = ET_RXDMA_CTRL_RING0_128; 97805884511SPyun YongHyeon rbd->rbd_newbuf = et_newbuf_hdr; 97905884511SPyun YongHyeon rbd->rbd_discard = et_rxbuf_discard; 9804d52a575SXin LI rbd->rbd_softc = sc; 98105884511SPyun YongHyeon rbd->rbd_ring = &sc->sc_rx_ring[0]; 98205884511SPyun YongHyeon /* Create DMA maps for mini RX buffers, ring 0. */ 98305884511SPyun YongHyeon for (i = 0; i < ET_RX_NDESC; i++) { 98405884511SPyun YongHyeon error = bus_dmamap_create(sc->sc_rx_mini_tag, 0, 98505884511SPyun YongHyeon &rbd->rbd_buf[i].rb_dmap); 98605884511SPyun YongHyeon if (error) { 98705884511SPyun YongHyeon device_printf(sc->dev, 98805884511SPyun YongHyeon "could not create DMA map for mini RX mbufs\n"); 98905884511SPyun YongHyeon return (error); 99005884511SPyun YongHyeon } 9914d52a575SXin LI } 9924d52a575SXin LI 99305884511SPyun YongHyeon /* Create a spare DMA map for mini RX buffers, ring 0. */ 99405884511SPyun YongHyeon error = bus_dmamap_create(sc->sc_rx_mini_tag, 0, 99505884511SPyun YongHyeon &sc->sc_rx_mini_sparemap); 99605884511SPyun YongHyeon if (error) { 99705884511SPyun YongHyeon device_printf(sc->dev, 99805884511SPyun YongHyeon "could not create spare DMA map for mini RX mbuf\n"); 99905884511SPyun YongHyeon return (error); 100005884511SPyun YongHyeon } 100105884511SPyun YongHyeon 100205884511SPyun YongHyeon /* Initialize RX ring 1. */ 100305884511SPyun YongHyeon rbd = &sc->sc_rx_data[1]; 100405884511SPyun YongHyeon rbd->rbd_bufsize = ET_RXDMA_CTRL_RING1_2048; 100505884511SPyun YongHyeon rbd->rbd_newbuf = et_newbuf_cluster; 100605884511SPyun YongHyeon rbd->rbd_discard = et_rxbuf_discard; 100705884511SPyun YongHyeon rbd->rbd_softc = sc; 100805884511SPyun YongHyeon rbd->rbd_ring = &sc->sc_rx_ring[1]; 100905884511SPyun YongHyeon /* Create DMA maps for standard RX buffers, ring 1. */ 101005884511SPyun YongHyeon for (i = 0; i < ET_RX_NDESC; i++) { 101105884511SPyun YongHyeon error = bus_dmamap_create(sc->sc_rx_tag, 0, 101205884511SPyun YongHyeon &rbd->rbd_buf[i].rb_dmap); 101305884511SPyun YongHyeon if (error) { 101405884511SPyun YongHyeon device_printf(sc->dev, 101505884511SPyun YongHyeon "could not create DMA map for mini RX mbufs\n"); 101605884511SPyun YongHyeon return (error); 101705884511SPyun YongHyeon } 101805884511SPyun YongHyeon } 101905884511SPyun YongHyeon 102005884511SPyun YongHyeon /* Create a spare DMA map for standard RX buffers, ring 1. */ 102105884511SPyun YongHyeon error = bus_dmamap_create(sc->sc_rx_tag, 0, &sc->sc_rx_sparemap); 102205884511SPyun YongHyeon if (error) { 102305884511SPyun YongHyeon device_printf(sc->dev, 102405884511SPyun YongHyeon "could not create spare DMA map for RX mbuf\n"); 102505884511SPyun YongHyeon return (error); 102605884511SPyun YongHyeon } 102705884511SPyun YongHyeon 102805884511SPyun YongHyeon /* Create DMA maps for TX buffers. */ 102905884511SPyun YongHyeon tbd = &sc->sc_tx_data; 103005884511SPyun YongHyeon for (i = 0; i < ET_TX_NDESC; i++) { 103105884511SPyun YongHyeon error = bus_dmamap_create(sc->sc_tx_tag, 0, 10324d52a575SXin LI &tbd->tbd_buf[i].tb_dmap); 10334d52a575SXin LI if (error) { 103405884511SPyun YongHyeon device_printf(sc->dev, 103505884511SPyun YongHyeon "could not create DMA map for TX mbufs\n"); 1036398f1b65SPyun YongHyeon return (error); 10374d52a575SXin LI } 10384d52a575SXin LI } 10394d52a575SXin LI 1040398f1b65SPyun YongHyeon return (0); 10414d52a575SXin LI } 10424d52a575SXin LI 10434d52a575SXin LI static void 104405884511SPyun YongHyeon et_dma_free(struct et_softc *sc) 10454d52a575SXin LI { 104605884511SPyun YongHyeon struct et_txdesc_ring *tx_ring; 104705884511SPyun YongHyeon struct et_rxdesc_ring *rx_ring; 104805884511SPyun YongHyeon struct et_txstatus_data *txsd; 104905884511SPyun YongHyeon struct et_rxstat_ring *rxst_ring; 105005884511SPyun YongHyeon struct et_rxbuf_data *rbd; 105105884511SPyun YongHyeon struct et_txbuf_data *tbd; 10524d52a575SXin LI int i; 10534d52a575SXin LI 105405884511SPyun YongHyeon /* Destroy DMA maps for mini RX buffers, ring 0. */ 105505884511SPyun YongHyeon rbd = &sc->sc_rx_data[0]; 105605884511SPyun YongHyeon for (i = 0; i < ET_RX_NDESC; i++) { 105705884511SPyun YongHyeon if (rbd->rbd_buf[i].rb_dmap) { 105805884511SPyun YongHyeon bus_dmamap_destroy(sc->sc_rx_mini_tag, 105905884511SPyun YongHyeon rbd->rbd_buf[i].rb_dmap); 106005884511SPyun YongHyeon rbd->rbd_buf[i].rb_dmap = NULL; 10614d52a575SXin LI } 10624d52a575SXin LI } 106305884511SPyun YongHyeon if (sc->sc_rx_mini_sparemap) { 106405884511SPyun YongHyeon bus_dmamap_destroy(sc->sc_rx_mini_tag, sc->sc_rx_mini_sparemap); 106505884511SPyun YongHyeon sc->sc_rx_mini_sparemap = NULL; 106605884511SPyun YongHyeon } 106705884511SPyun YongHyeon if (sc->sc_rx_mini_tag) { 106805884511SPyun YongHyeon bus_dma_tag_destroy(sc->sc_rx_mini_tag); 106905884511SPyun YongHyeon sc->sc_rx_mini_tag = NULL; 10704d52a575SXin LI } 10714d52a575SXin LI 107205884511SPyun YongHyeon /* Destroy DMA maps for standard RX buffers, ring 1. */ 107305884511SPyun YongHyeon rbd = &sc->sc_rx_data[1]; 107405884511SPyun YongHyeon for (i = 0; i < ET_RX_NDESC; i++) { 107505884511SPyun YongHyeon if (rbd->rbd_buf[i].rb_dmap) { 107605884511SPyun YongHyeon bus_dmamap_destroy(sc->sc_rx_tag, 107705884511SPyun YongHyeon rbd->rbd_buf[i].rb_dmap); 107805884511SPyun YongHyeon rbd->rbd_buf[i].rb_dmap = NULL; 10794d52a575SXin LI } 10804d52a575SXin LI } 108105884511SPyun YongHyeon if (sc->sc_rx_sparemap) { 108205884511SPyun YongHyeon bus_dmamap_destroy(sc->sc_rx_tag, sc->sc_rx_sparemap); 108305884511SPyun YongHyeon sc->sc_rx_sparemap = NULL; 108405884511SPyun YongHyeon } 108505884511SPyun YongHyeon if (sc->sc_rx_tag) { 108605884511SPyun YongHyeon bus_dma_tag_destroy(sc->sc_rx_tag); 108705884511SPyun YongHyeon sc->sc_rx_tag = NULL; 108805884511SPyun YongHyeon } 10894d52a575SXin LI 109005884511SPyun YongHyeon /* Destroy DMA maps for TX buffers. */ 109105884511SPyun YongHyeon tbd = &sc->sc_tx_data; 109205884511SPyun YongHyeon for (i = 0; i < ET_TX_NDESC; i++) { 109305884511SPyun YongHyeon if (tbd->tbd_buf[i].tb_dmap) { 109405884511SPyun YongHyeon bus_dmamap_destroy(sc->sc_tx_tag, 109505884511SPyun YongHyeon tbd->tbd_buf[i].tb_dmap); 109605884511SPyun YongHyeon tbd->tbd_buf[i].tb_dmap = NULL; 109705884511SPyun YongHyeon } 109805884511SPyun YongHyeon } 109905884511SPyun YongHyeon if (sc->sc_tx_tag) { 110005884511SPyun YongHyeon bus_dma_tag_destroy(sc->sc_tx_tag); 110105884511SPyun YongHyeon sc->sc_tx_tag = NULL; 110205884511SPyun YongHyeon } 110305884511SPyun YongHyeon 110405884511SPyun YongHyeon /* Destroy mini RX ring, ring 0. */ 110505884511SPyun YongHyeon rx_ring = &sc->sc_rx_ring[0]; 110605884511SPyun YongHyeon et_dma_ring_free(sc, &rx_ring->rr_dtag, (void *)&rx_ring->rr_desc, 1107c34f1a08SJohn Baldwin rx_ring->rr_dmap, &rx_ring->rr_paddr); 110805884511SPyun YongHyeon /* Destroy standard RX ring, ring 1. */ 110905884511SPyun YongHyeon rx_ring = &sc->sc_rx_ring[1]; 111005884511SPyun YongHyeon et_dma_ring_free(sc, &rx_ring->rr_dtag, (void *)&rx_ring->rr_desc, 1111c34f1a08SJohn Baldwin rx_ring->rr_dmap, &rx_ring->rr_paddr); 111205884511SPyun YongHyeon /* Destroy RX stat ring. */ 111305884511SPyun YongHyeon rxst_ring = &sc->sc_rxstat_ring; 111405884511SPyun YongHyeon et_dma_ring_free(sc, &rxst_ring->rsr_dtag, (void *)&rxst_ring->rsr_stat, 1115c34f1a08SJohn Baldwin rxst_ring->rsr_dmap, &rxst_ring->rsr_paddr); 111605884511SPyun YongHyeon /* Destroy RX status block. */ 111705884511SPyun YongHyeon et_dma_ring_free(sc, &rxst_ring->rsr_dtag, (void *)&rxst_ring->rsr_stat, 1118c34f1a08SJohn Baldwin rxst_ring->rsr_dmap, &rxst_ring->rsr_paddr); 111905884511SPyun YongHyeon /* Destroy TX ring. */ 112005884511SPyun YongHyeon tx_ring = &sc->sc_tx_ring; 112105884511SPyun YongHyeon et_dma_ring_free(sc, &tx_ring->tr_dtag, (void *)&tx_ring->tr_desc, 1122c34f1a08SJohn Baldwin tx_ring->tr_dmap, &tx_ring->tr_paddr); 112305884511SPyun YongHyeon /* Destroy TX status block. */ 112405884511SPyun YongHyeon txsd = &sc->sc_tx_status; 112505884511SPyun YongHyeon et_dma_ring_free(sc, &txsd->txsd_dtag, (void *)&txsd->txsd_status, 1126c34f1a08SJohn Baldwin txsd->txsd_dmap, &txsd->txsd_paddr); 112705884511SPyun YongHyeon 112805884511SPyun YongHyeon /* Destroy the parent tag. */ 112905884511SPyun YongHyeon if (sc->sc_dtag) { 113005884511SPyun YongHyeon bus_dma_tag_destroy(sc->sc_dtag); 113105884511SPyun YongHyeon sc->sc_dtag = NULL; 113205884511SPyun YongHyeon } 11334d52a575SXin LI } 11344d52a575SXin LI 11354d52a575SXin LI static void 11364d52a575SXin LI et_chip_attach(struct et_softc *sc) 11374d52a575SXin LI { 11384d52a575SXin LI uint32_t val; 11394d52a575SXin LI 11404d52a575SXin LI /* 11414d52a575SXin LI * Perform minimal initialization 11424d52a575SXin LI */ 11434d52a575SXin LI 11444d52a575SXin LI /* Disable loopback */ 11454d52a575SXin LI CSR_WRITE_4(sc, ET_LOOPBACK, 0); 11464d52a575SXin LI 11474d52a575SXin LI /* Reset MAC */ 11484d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 11494d52a575SXin LI ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 11504d52a575SXin LI ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | 11514d52a575SXin LI ET_MAC_CFG1_SIM_RST | ET_MAC_CFG1_SOFT_RST); 11524d52a575SXin LI 11534d52a575SXin LI /* 11544d52a575SXin LI * Setup half duplex mode 11554d52a575SXin LI */ 115623263665SPyun YongHyeon val = (10 << ET_MAC_HDX_ALT_BEB_TRUNC_SHIFT) | 115723263665SPyun YongHyeon (15 << ET_MAC_HDX_REXMIT_MAX_SHIFT) | 115823263665SPyun YongHyeon (55 << ET_MAC_HDX_COLLWIN_SHIFT) | 11594d52a575SXin LI ET_MAC_HDX_EXC_DEFER; 11604d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_HDX, val); 11614d52a575SXin LI 11624d52a575SXin LI /* Clear MAC control */ 11634d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CTRL, 0); 11644d52a575SXin LI 11654d52a575SXin LI /* Reset MII */ 11664d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CFG, ET_MII_CFG_CLKRST); 11674d52a575SXin LI 11684d52a575SXin LI /* Bring MAC out of reset state */ 11694d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 0); 11704d52a575SXin LI 11714d52a575SXin LI /* Enable memory controllers */ 11724d52a575SXin LI CSR_WRITE_4(sc, ET_MMC_CTRL, ET_MMC_CTRL_ENABLE); 11734d52a575SXin LI } 11744d52a575SXin LI 11754d52a575SXin LI static void 11764d52a575SXin LI et_intr(void *xsc) 11774d52a575SXin LI { 11780b699044SPyun YongHyeon struct et_softc *sc; 1179*7c509be1SJustin Hibbits if_t ifp; 1180fa1483ddSPyun YongHyeon uint32_t status; 11814d52a575SXin LI 11820b699044SPyun YongHyeon sc = xsc; 11834d52a575SXin LI ET_LOCK(sc); 11844d52a575SXin LI ifp = sc->ifp; 1185*7c509be1SJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) 1186fa1483ddSPyun YongHyeon goto done; 1187fa1483ddSPyun YongHyeon 1188fa1483ddSPyun YongHyeon status = CSR_READ_4(sc, ET_INTR_STATUS); 1189fa1483ddSPyun YongHyeon if ((status & ET_INTRS) == 0) 1190fa1483ddSPyun YongHyeon goto done; 11914d52a575SXin LI 11926537ffa6SPyun YongHyeon /* Disable further interrupts. */ 11936537ffa6SPyun YongHyeon CSR_WRITE_4(sc, ET_INTR_MASK, 0xffffffff); 11944d52a575SXin LI 1195fa1483ddSPyun YongHyeon if (status & (ET_INTR_RXDMA_ERROR | ET_INTR_TXDMA_ERROR)) { 1196fa1483ddSPyun YongHyeon device_printf(sc->dev, "DMA error(0x%08x) -- resetting\n", 1197fa1483ddSPyun YongHyeon status); 1198*7c509be1SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 1199fa1483ddSPyun YongHyeon et_init_locked(sc); 1200fa1483ddSPyun YongHyeon ET_UNLOCK(sc); 1201fa1483ddSPyun YongHyeon return; 1202fa1483ddSPyun YongHyeon } 1203fa1483ddSPyun YongHyeon if (status & ET_INTR_RXDMA) 12044d52a575SXin LI et_rxeof(sc); 1205fa1483ddSPyun YongHyeon if (status & (ET_INTR_TXDMA | ET_INTR_TIMER)) 12064d52a575SXin LI et_txeof(sc); 1207fa1483ddSPyun YongHyeon if (status & ET_INTR_TIMER) 12084d52a575SXin LI CSR_WRITE_4(sc, ET_TIMER, sc->sc_timer); 1209*7c509be1SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 12106537ffa6SPyun YongHyeon CSR_WRITE_4(sc, ET_INTR_MASK, ~ET_INTRS); 1211*7c509be1SJustin Hibbits if (!if_sendq_empty(ifp)) 1212244fd28bSPyun YongHyeon et_start_locked(ifp); 1213244fd28bSPyun YongHyeon } 1214fa1483ddSPyun YongHyeon done: 12154d52a575SXin LI ET_UNLOCK(sc); 12164d52a575SXin LI } 12174d52a575SXin LI 12184d52a575SXin LI static void 12194d52a575SXin LI et_init_locked(struct et_softc *sc) 12204d52a575SXin LI { 1221*7c509be1SJustin Hibbits if_t ifp; 122205884511SPyun YongHyeon int error; 12234d52a575SXin LI 12244d52a575SXin LI ET_LOCK_ASSERT(sc); 12254d52a575SXin LI 122605884511SPyun YongHyeon ifp = sc->ifp; 1227*7c509be1SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 12284d52a575SXin LI return; 12294d52a575SXin LI 12304d52a575SXin LI et_stop(sc); 12311f009e2fSPyun YongHyeon et_reset(sc); 12324d52a575SXin LI 123305884511SPyun YongHyeon et_init_tx_ring(sc); 12344d52a575SXin LI error = et_init_rx_ring(sc); 12354d52a575SXin LI if (error) 123605884511SPyun YongHyeon return; 12374d52a575SXin LI 12384d52a575SXin LI error = et_chip_init(sc); 12394d52a575SXin LI if (error) 12401f009e2fSPyun YongHyeon goto fail; 12414d52a575SXin LI 12421f009e2fSPyun YongHyeon /* 12431f009e2fSPyun YongHyeon * Start TX/RX DMA engine 12441f009e2fSPyun YongHyeon */ 12451f009e2fSPyun YongHyeon error = et_start_rxdma(sc); 12464d52a575SXin LI if (error) 12471f009e2fSPyun YongHyeon return; 12481f009e2fSPyun YongHyeon 12491f009e2fSPyun YongHyeon error = et_start_txdma(sc); 12501f009e2fSPyun YongHyeon if (error) 12511f009e2fSPyun YongHyeon return; 12524d52a575SXin LI 12536537ffa6SPyun YongHyeon /* Enable interrupts. */ 12546537ffa6SPyun YongHyeon CSR_WRITE_4(sc, ET_INTR_MASK, ~ET_INTRS); 12554d52a575SXin LI 12564d52a575SXin LI CSR_WRITE_4(sc, ET_TIMER, sc->sc_timer); 12574d52a575SXin LI 1258*7c509be1SJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); 1259*7c509be1SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 12601f009e2fSPyun YongHyeon 12611f009e2fSPyun YongHyeon sc->sc_flags &= ~ET_FLAG_LINK; 12621f009e2fSPyun YongHyeon et_ifmedia_upd_locked(ifp); 12631f009e2fSPyun YongHyeon 12641f009e2fSPyun YongHyeon callout_reset(&sc->sc_tick, hz, et_tick, sc); 12651f009e2fSPyun YongHyeon 12661f009e2fSPyun YongHyeon fail: 12674d52a575SXin LI if (error) 12684d52a575SXin LI et_stop(sc); 12694d52a575SXin LI } 12704d52a575SXin LI 12714d52a575SXin LI static void 12724d52a575SXin LI et_init(void *xsc) 12734d52a575SXin LI { 12744d52a575SXin LI struct et_softc *sc = xsc; 12754d52a575SXin LI 12764d52a575SXin LI ET_LOCK(sc); 12774d52a575SXin LI et_init_locked(sc); 12784d52a575SXin LI ET_UNLOCK(sc); 12794d52a575SXin LI } 12804d52a575SXin LI 12814d52a575SXin LI static int 1282*7c509be1SJustin Hibbits et_ioctl(if_t ifp, u_long cmd, caddr_t data) 12834d52a575SXin LI { 12840b699044SPyun YongHyeon struct et_softc *sc; 12850b699044SPyun YongHyeon struct mii_data *mii; 12860b699044SPyun YongHyeon struct ifreq *ifr; 12870b699044SPyun YongHyeon int error, mask, max_framelen; 12880b699044SPyun YongHyeon 1289*7c509be1SJustin Hibbits sc = if_getsoftc(ifp); 12900b699044SPyun YongHyeon ifr = (struct ifreq *)data; 12910b699044SPyun YongHyeon error = 0; 12924d52a575SXin LI 12934d52a575SXin LI /* XXX LOCKSUSED */ 12944d52a575SXin LI switch (cmd) { 12954d52a575SXin LI case SIOCSIFFLAGS: 12964d52a575SXin LI ET_LOCK(sc); 1297*7c509be1SJustin Hibbits if (if_getflags(ifp) & IFF_UP) { 1298*7c509be1SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 1299*7c509be1SJustin Hibbits if ((if_getflags(ifp) ^ sc->sc_if_flags) & 13004d52a575SXin LI (IFF_ALLMULTI | IFF_PROMISC | IFF_BROADCAST)) 13014d52a575SXin LI et_setmulti(sc); 13024d52a575SXin LI } else { 13034d52a575SXin LI et_init_locked(sc); 13044d52a575SXin LI } 13054d52a575SXin LI } else { 1306*7c509be1SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 13074d52a575SXin LI et_stop(sc); 13084d52a575SXin LI } 1309*7c509be1SJustin Hibbits sc->sc_if_flags = if_getflags(ifp); 13104d52a575SXin LI ET_UNLOCK(sc); 13114d52a575SXin LI break; 13124d52a575SXin LI 13134d52a575SXin LI case SIOCSIFMEDIA: 13144d52a575SXin LI case SIOCGIFMEDIA: 13150b699044SPyun YongHyeon mii = device_get_softc(sc->sc_miibus); 13164d52a575SXin LI error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 13174d52a575SXin LI break; 13184d52a575SXin LI 13194d52a575SXin LI case SIOCADDMULTI: 13204d52a575SXin LI case SIOCDELMULTI: 1321*7c509be1SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 13224d52a575SXin LI ET_LOCK(sc); 13234d52a575SXin LI et_setmulti(sc); 13244d52a575SXin LI ET_UNLOCK(sc); 13254d52a575SXin LI } 13264d52a575SXin LI break; 13274d52a575SXin LI 13284d52a575SXin LI case SIOCSIFMTU: 13298e5ad990SPyun YongHyeon ET_LOCK(sc); 13304d52a575SXin LI #if 0 13314d52a575SXin LI if (sc->sc_flags & ET_FLAG_JUMBO) 13324d52a575SXin LI max_framelen = ET_JUMBO_FRAMELEN; 13334d52a575SXin LI else 13344d52a575SXin LI #endif 13354d52a575SXin LI max_framelen = MCLBYTES - 1; 13364d52a575SXin LI 13374d52a575SXin LI if (ET_FRAMELEN(ifr->ifr_mtu) > max_framelen) { 13384d52a575SXin LI error = EOPNOTSUPP; 13398e5ad990SPyun YongHyeon ET_UNLOCK(sc); 13404d52a575SXin LI break; 13414d52a575SXin LI } 13424d52a575SXin LI 1343*7c509be1SJustin Hibbits if (if_getmtu(ifp) != ifr->ifr_mtu) { 1344*7c509be1SJustin Hibbits if_setmtu(ifp, ifr->ifr_mtu); 1345*7c509be1SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 1346*7c509be1SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 13478e5ad990SPyun YongHyeon et_init_locked(sc); 13484d52a575SXin LI } 13498e5ad990SPyun YongHyeon } 13508e5ad990SPyun YongHyeon ET_UNLOCK(sc); 13514d52a575SXin LI break; 13524d52a575SXin LI 13539955274cSPyun YongHyeon case SIOCSIFCAP: 13549955274cSPyun YongHyeon ET_LOCK(sc); 1355*7c509be1SJustin Hibbits mask = ifr->ifr_reqcap ^ if_getcapenable(ifp); 13569955274cSPyun YongHyeon if ((mask & IFCAP_TXCSUM) != 0 && 1357*7c509be1SJustin Hibbits (IFCAP_TXCSUM & if_getcapabilities(ifp)) != 0) { 1358*7c509be1SJustin Hibbits if_togglecapenable(ifp, IFCAP_TXCSUM); 1359*7c509be1SJustin Hibbits if ((IFCAP_TXCSUM & if_getcapenable(ifp)) != 0) 1360*7c509be1SJustin Hibbits if_sethwassistbits(ifp, ET_CSUM_FEATURES, 0); 13619955274cSPyun YongHyeon else 1362*7c509be1SJustin Hibbits if_sethwassistbits(ifp, 0, ET_CSUM_FEATURES); 13639955274cSPyun YongHyeon } 13649955274cSPyun YongHyeon ET_UNLOCK(sc); 13659955274cSPyun YongHyeon break; 13669955274cSPyun YongHyeon 13674d52a575SXin LI default: 13684d52a575SXin LI error = ether_ioctl(ifp, cmd, data); 13694d52a575SXin LI break; 13704d52a575SXin LI } 1371398f1b65SPyun YongHyeon return (error); 13724d52a575SXin LI } 13734d52a575SXin LI 13744d52a575SXin LI static void 1375*7c509be1SJustin Hibbits et_start_locked(if_t ifp) 13764d52a575SXin LI { 1377c8b727ceSPyun YongHyeon struct et_softc *sc; 1378c8b727ceSPyun YongHyeon struct mbuf *m_head = NULL; 1379244fd28bSPyun YongHyeon struct et_txdesc_ring *tx_ring; 13804d52a575SXin LI struct et_txbuf_data *tbd; 1381244fd28bSPyun YongHyeon uint32_t tx_ready_pos; 1382c8b727ceSPyun YongHyeon int enq; 13834d52a575SXin LI 1384*7c509be1SJustin Hibbits sc = if_getsoftc(ifp); 13854d52a575SXin LI ET_LOCK_ASSERT(sc); 13864d52a575SXin LI 1387*7c509be1SJustin Hibbits if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 13881f009e2fSPyun YongHyeon IFF_DRV_RUNNING || 13891f009e2fSPyun YongHyeon (sc->sc_flags & (ET_FLAG_LINK | ET_FLAG_TXRX_ENABLED)) != 13901f009e2fSPyun YongHyeon (ET_FLAG_LINK | ET_FLAG_TXRX_ENABLED)) 13914d52a575SXin LI return; 13924d52a575SXin LI 1393244fd28bSPyun YongHyeon /* 1394244fd28bSPyun YongHyeon * Driver does not request TX completion interrupt for every 1395244fd28bSPyun YongHyeon * queued frames to prevent generating excessive interrupts. 1396244fd28bSPyun YongHyeon * This means driver may wait for TX completion interrupt even 1397453130d9SPedro F. Giffuni * though some frames were successfully transmitted. Reclaiming 1398244fd28bSPyun YongHyeon * transmitted frames will ensure driver see all available 1399244fd28bSPyun YongHyeon * descriptors. 1400244fd28bSPyun YongHyeon */ 1401c8b727ceSPyun YongHyeon tbd = &sc->sc_tx_data; 1402244fd28bSPyun YongHyeon if (tbd->tbd_used > (ET_TX_NDESC * 2) / 3) 1403244fd28bSPyun YongHyeon et_txeof(sc); 1404244fd28bSPyun YongHyeon 1405*7c509be1SJustin Hibbits for (enq = 0; !if_sendq_empty(ifp); ) { 1406c8b727ceSPyun YongHyeon if (tbd->tbd_used + ET_NSEG_SPARE >= ET_TX_NDESC) { 1407*7c509be1SJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); 14084d52a575SXin LI break; 14094d52a575SXin LI } 14104d52a575SXin LI 1411*7c509be1SJustin Hibbits m_head = if_dequeue(ifp); 1412c8b727ceSPyun YongHyeon if (m_head == NULL) 14134d52a575SXin LI break; 14144d52a575SXin LI 1415c8b727ceSPyun YongHyeon if (et_encap(sc, &m_head)) { 1416c8b727ceSPyun YongHyeon if (m_head == NULL) { 1417c13dc687SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 1418c8b727ceSPyun YongHyeon break; 1419c8b727ceSPyun YongHyeon } 1420*7c509be1SJustin Hibbits if_sendq_prepend(ifp, m_head); 1421c8b727ceSPyun YongHyeon if (tbd->tbd_used > 0) 1422*7c509be1SJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); 14234d52a575SXin LI break; 14244d52a575SXin LI } 1425c8b727ceSPyun YongHyeon enq++; 1426c8b727ceSPyun YongHyeon ETHER_BPF_MTAP(ifp, m_head); 14274d52a575SXin LI } 14284d52a575SXin LI 1429244fd28bSPyun YongHyeon if (enq > 0) { 1430244fd28bSPyun YongHyeon tx_ring = &sc->sc_tx_ring; 1431244fd28bSPyun YongHyeon bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap, 1432244fd28bSPyun YongHyeon BUS_DMASYNC_PREWRITE); 1433244fd28bSPyun YongHyeon tx_ready_pos = tx_ring->tr_ready_index & 1434244fd28bSPyun YongHyeon ET_TX_READY_POS_INDEX_MASK; 1435244fd28bSPyun YongHyeon if (tx_ring->tr_ready_wrap) 1436244fd28bSPyun YongHyeon tx_ready_pos |= ET_TX_READY_POS_WRAP; 1437244fd28bSPyun YongHyeon CSR_WRITE_4(sc, ET_TX_READY_POS, tx_ready_pos); 14384d52a575SXin LI sc->watchdog_timer = 5; 14394d52a575SXin LI } 1440244fd28bSPyun YongHyeon } 14414d52a575SXin LI 14424d52a575SXin LI static void 1443*7c509be1SJustin Hibbits et_start(if_t ifp) 14444d52a575SXin LI { 14450b699044SPyun YongHyeon struct et_softc *sc; 14464d52a575SXin LI 1447*7c509be1SJustin Hibbits sc = if_getsoftc(ifp); 14484d52a575SXin LI ET_LOCK(sc); 14494d52a575SXin LI et_start_locked(ifp); 14504d52a575SXin LI ET_UNLOCK(sc); 14514d52a575SXin LI } 14524d52a575SXin LI 145305884511SPyun YongHyeon static int 14544d52a575SXin LI et_watchdog(struct et_softc *sc) 14554d52a575SXin LI { 145605884511SPyun YongHyeon uint32_t status; 145705884511SPyun YongHyeon 14584d52a575SXin LI ET_LOCK_ASSERT(sc); 14594d52a575SXin LI 14604d52a575SXin LI if (sc->watchdog_timer == 0 || --sc->watchdog_timer) 146105884511SPyun YongHyeon return (0); 14624d52a575SXin LI 146305884511SPyun YongHyeon bus_dmamap_sync(sc->sc_tx_status.txsd_dtag, sc->sc_tx_status.txsd_dmap, 146405884511SPyun YongHyeon BUS_DMASYNC_POSTREAD); 146505884511SPyun YongHyeon status = le32toh(*(sc->sc_tx_status.txsd_status)); 146605884511SPyun YongHyeon if_printf(sc->ifp, "watchdog timed out (0x%08x) -- resetting\n", 146705884511SPyun YongHyeon status); 14684d52a575SXin LI 1469c13dc687SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1); 1470*7c509be1SJustin Hibbits if_setdrvflagbits(sc->ifp, 0, IFF_DRV_RUNNING); 14714d52a575SXin LI et_init_locked(sc); 147205884511SPyun YongHyeon return (EJUSTRETURN); 14734d52a575SXin LI } 14744d52a575SXin LI 14754d52a575SXin LI static int 14764d52a575SXin LI et_stop_rxdma(struct et_softc *sc) 14774d52a575SXin LI { 14780b699044SPyun YongHyeon 14794d52a575SXin LI CSR_WRITE_4(sc, ET_RXDMA_CTRL, 14804d52a575SXin LI ET_RXDMA_CTRL_HALT | ET_RXDMA_CTRL_RING1_ENABLE); 14814d52a575SXin LI 14824d52a575SXin LI DELAY(5); 14834d52a575SXin LI if ((CSR_READ_4(sc, ET_RXDMA_CTRL) & ET_RXDMA_CTRL_HALTED) == 0) { 14844d52a575SXin LI if_printf(sc->ifp, "can't stop RX DMA engine\n"); 1485398f1b65SPyun YongHyeon return (ETIMEDOUT); 14864d52a575SXin LI } 1487398f1b65SPyun YongHyeon return (0); 14884d52a575SXin LI } 14894d52a575SXin LI 14904d52a575SXin LI static int 14914d52a575SXin LI et_stop_txdma(struct et_softc *sc) 14924d52a575SXin LI { 14930b699044SPyun YongHyeon 14944d52a575SXin LI CSR_WRITE_4(sc, ET_TXDMA_CTRL, 14954d52a575SXin LI ET_TXDMA_CTRL_HALT | ET_TXDMA_CTRL_SINGLE_EPKT); 1496398f1b65SPyun YongHyeon return (0); 14974d52a575SXin LI } 14984d52a575SXin LI 14994d52a575SXin LI static void 15004d52a575SXin LI et_free_tx_ring(struct et_softc *sc) 15014d52a575SXin LI { 150205884511SPyun YongHyeon struct et_txbuf_data *tbd; 150305884511SPyun YongHyeon struct et_txbuf *tb; 15044d52a575SXin LI int i; 15054d52a575SXin LI 150605884511SPyun YongHyeon tbd = &sc->sc_tx_data; 15074d52a575SXin LI for (i = 0; i < ET_TX_NDESC; ++i) { 150805884511SPyun YongHyeon tb = &tbd->tbd_buf[i]; 15094d52a575SXin LI if (tb->tb_mbuf != NULL) { 151005884511SPyun YongHyeon bus_dmamap_sync(sc->sc_tx_tag, tb->tb_dmap, 151105884511SPyun YongHyeon BUS_DMASYNC_POSTWRITE); 15124d52a575SXin LI bus_dmamap_unload(sc->sc_mbuf_dtag, tb->tb_dmap); 15134d52a575SXin LI m_freem(tb->tb_mbuf); 15144d52a575SXin LI tb->tb_mbuf = NULL; 15154d52a575SXin LI } 15164d52a575SXin LI } 15174d52a575SXin LI } 15184d52a575SXin LI 15194d52a575SXin LI static void 15204d52a575SXin LI et_free_rx_ring(struct et_softc *sc) 15214d52a575SXin LI { 152205884511SPyun YongHyeon struct et_rxbuf_data *rbd; 152305884511SPyun YongHyeon struct et_rxdesc_ring *rx_ring; 152405884511SPyun YongHyeon struct et_rxbuf *rb; 15254d52a575SXin LI int i; 15264d52a575SXin LI 152705884511SPyun YongHyeon /* Ring 0 */ 152805884511SPyun YongHyeon rx_ring = &sc->sc_rx_ring[0]; 152905884511SPyun YongHyeon rbd = &sc->sc_rx_data[0]; 15304d52a575SXin LI for (i = 0; i < ET_RX_NDESC; ++i) { 153105884511SPyun YongHyeon rb = &rbd->rbd_buf[i]; 15324d52a575SXin LI if (rb->rb_mbuf != NULL) { 153305884511SPyun YongHyeon bus_dmamap_sync(sc->sc_rx_mini_tag, rx_ring->rr_dmap, 153405884511SPyun YongHyeon BUS_DMASYNC_POSTREAD); 153505884511SPyun YongHyeon bus_dmamap_unload(sc->sc_rx_mini_tag, rb->rb_dmap); 15364d52a575SXin LI m_freem(rb->rb_mbuf); 15374d52a575SXin LI rb->rb_mbuf = NULL; 15384d52a575SXin LI } 15394d52a575SXin LI } 15404d52a575SXin LI 154105884511SPyun YongHyeon /* Ring 1 */ 154205884511SPyun YongHyeon rx_ring = &sc->sc_rx_ring[1]; 154305884511SPyun YongHyeon rbd = &sc->sc_rx_data[1]; 154405884511SPyun YongHyeon for (i = 0; i < ET_RX_NDESC; ++i) { 154505884511SPyun YongHyeon rb = &rbd->rbd_buf[i]; 154605884511SPyun YongHyeon if (rb->rb_mbuf != NULL) { 154705884511SPyun YongHyeon bus_dmamap_sync(sc->sc_rx_tag, rx_ring->rr_dmap, 154805884511SPyun YongHyeon BUS_DMASYNC_POSTREAD); 154905884511SPyun YongHyeon bus_dmamap_unload(sc->sc_rx_tag, rb->rb_dmap); 155005884511SPyun YongHyeon m_freem(rb->rb_mbuf); 155105884511SPyun YongHyeon rb->rb_mbuf = NULL; 155205884511SPyun YongHyeon } 15534d52a575SXin LI } 15544d52a575SXin LI } 15554d52a575SXin LI 155636581f82SGleb Smirnoff static u_int 155736581f82SGleb Smirnoff et_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 15584d52a575SXin LI { 155936581f82SGleb Smirnoff uint32_t h, *hp, *hash = arg; 15604d52a575SXin LI 156136581f82SGleb Smirnoff h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN); 15624d52a575SXin LI h = (h & 0x3f800000) >> 23; 15634d52a575SXin LI 15644d52a575SXin LI hp = &hash[0]; 15654d52a575SXin LI if (h >= 32 && h < 64) { 15664d52a575SXin LI h -= 32; 15674d52a575SXin LI hp = &hash[1]; 15684d52a575SXin LI } else if (h >= 64 && h < 96) { 15694d52a575SXin LI h -= 64; 15704d52a575SXin LI hp = &hash[2]; 15714d52a575SXin LI } else if (h >= 96) { 15724d52a575SXin LI h -= 96; 15734d52a575SXin LI hp = &hash[3]; 15744d52a575SXin LI } 15754d52a575SXin LI *hp |= (1 << h); 15764d52a575SXin LI 157736581f82SGleb Smirnoff return (1); 15784d52a575SXin LI } 157936581f82SGleb Smirnoff 158036581f82SGleb Smirnoff static void 158136581f82SGleb Smirnoff et_setmulti(struct et_softc *sc) 158236581f82SGleb Smirnoff { 1583*7c509be1SJustin Hibbits if_t ifp; 158436581f82SGleb Smirnoff uint32_t hash[4] = { 0, 0, 0, 0 }; 158536581f82SGleb Smirnoff uint32_t rxmac_ctrl, pktfilt; 158636581f82SGleb Smirnoff int i, count; 158736581f82SGleb Smirnoff 158836581f82SGleb Smirnoff ET_LOCK_ASSERT(sc); 158936581f82SGleb Smirnoff ifp = sc->ifp; 159036581f82SGleb Smirnoff 159136581f82SGleb Smirnoff pktfilt = CSR_READ_4(sc, ET_PKTFILT); 159236581f82SGleb Smirnoff rxmac_ctrl = CSR_READ_4(sc, ET_RXMAC_CTRL); 159336581f82SGleb Smirnoff 159436581f82SGleb Smirnoff pktfilt &= ~(ET_PKTFILT_BCAST | ET_PKTFILT_MCAST | ET_PKTFILT_UCAST); 1595*7c509be1SJustin Hibbits if (if_getflags(ifp) & (IFF_PROMISC | IFF_ALLMULTI)) { 159636581f82SGleb Smirnoff rxmac_ctrl |= ET_RXMAC_CTRL_NO_PKTFILT; 159736581f82SGleb Smirnoff goto back; 159836581f82SGleb Smirnoff } 159936581f82SGleb Smirnoff 160036581f82SGleb Smirnoff count = if_foreach_llmaddr(ifp, et_hash_maddr, &hash); 16014d52a575SXin LI 16024d52a575SXin LI for (i = 0; i < 4; ++i) 16034d52a575SXin LI CSR_WRITE_4(sc, ET_MULTI_HASH + (i * 4), hash[i]); 16044d52a575SXin LI 16054d52a575SXin LI if (count > 0) 16064d52a575SXin LI pktfilt |= ET_PKTFILT_MCAST; 16074d52a575SXin LI rxmac_ctrl &= ~ET_RXMAC_CTRL_NO_PKTFILT; 16084d52a575SXin LI back: 16094d52a575SXin LI CSR_WRITE_4(sc, ET_PKTFILT, pktfilt); 16104d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_CTRL, rxmac_ctrl); 16114d52a575SXin LI } 16124d52a575SXin LI 16134d52a575SXin LI static int 16144d52a575SXin LI et_chip_init(struct et_softc *sc) 16154d52a575SXin LI { 1616*7c509be1SJustin Hibbits if_t ifp; 16174d52a575SXin LI uint32_t rxq_end; 16184d52a575SXin LI int error, frame_len, rxmem_size; 16194d52a575SXin LI 16200b699044SPyun YongHyeon ifp = sc->ifp; 16214d52a575SXin LI /* 16224d52a575SXin LI * Split 16Kbytes internal memory between TX and RX 16234d52a575SXin LI * according to frame length. 16244d52a575SXin LI */ 1625*7c509be1SJustin Hibbits frame_len = ET_FRAMELEN(if_getmtu(ifp)); 16264d52a575SXin LI if (frame_len < 2048) { 16274d52a575SXin LI rxmem_size = ET_MEM_RXSIZE_DEFAULT; 16284d52a575SXin LI } else if (frame_len <= ET_RXMAC_CUT_THRU_FRMLEN) { 16294d52a575SXin LI rxmem_size = ET_MEM_SIZE / 2; 16304d52a575SXin LI } else { 16314d52a575SXin LI rxmem_size = ET_MEM_SIZE - 16324d52a575SXin LI roundup(frame_len + ET_MEM_TXSIZE_EX, ET_MEM_UNIT); 16334d52a575SXin LI } 16344d52a575SXin LI rxq_end = ET_QUEUE_ADDR(rxmem_size); 16354d52a575SXin LI 16364d52a575SXin LI CSR_WRITE_4(sc, ET_RXQUEUE_START, ET_QUEUE_ADDR_START); 16374d52a575SXin LI CSR_WRITE_4(sc, ET_RXQUEUE_END, rxq_end); 16384d52a575SXin LI CSR_WRITE_4(sc, ET_TXQUEUE_START, rxq_end + 1); 16394d52a575SXin LI CSR_WRITE_4(sc, ET_TXQUEUE_END, ET_QUEUE_ADDR_END); 16404d52a575SXin LI 16414d52a575SXin LI /* No loopback */ 16424d52a575SXin LI CSR_WRITE_4(sc, ET_LOOPBACK, 0); 16434d52a575SXin LI 16444d52a575SXin LI /* Clear MSI configure */ 1645cc3c3b4eSPyun YongHyeon if ((sc->sc_flags & ET_FLAG_MSI) == 0) 16464d52a575SXin LI CSR_WRITE_4(sc, ET_MSI_CFG, 0); 16474d52a575SXin LI 16484d52a575SXin LI /* Disable timer */ 16494d52a575SXin LI CSR_WRITE_4(sc, ET_TIMER, 0); 16504d52a575SXin LI 16514d52a575SXin LI /* Initialize MAC */ 16524d52a575SXin LI et_init_mac(sc); 16534d52a575SXin LI 16544d52a575SXin LI /* Enable memory controllers */ 16554d52a575SXin LI CSR_WRITE_4(sc, ET_MMC_CTRL, ET_MMC_CTRL_ENABLE); 16564d52a575SXin LI 16574d52a575SXin LI /* Initialize RX MAC */ 16584d52a575SXin LI et_init_rxmac(sc); 16594d52a575SXin LI 16604d52a575SXin LI /* Initialize TX MAC */ 16614d52a575SXin LI et_init_txmac(sc); 16624d52a575SXin LI 16634d52a575SXin LI /* Initialize RX DMA engine */ 16644d52a575SXin LI error = et_init_rxdma(sc); 16654d52a575SXin LI if (error) 1666398f1b65SPyun YongHyeon return (error); 16674d52a575SXin LI 16684d52a575SXin LI /* Initialize TX DMA engine */ 16694d52a575SXin LI error = et_init_txdma(sc); 16704d52a575SXin LI if (error) 1671398f1b65SPyun YongHyeon return (error); 16724d52a575SXin LI 1673398f1b65SPyun YongHyeon return (0); 16744d52a575SXin LI } 16754d52a575SXin LI 167605884511SPyun YongHyeon static void 16774d52a575SXin LI et_init_tx_ring(struct et_softc *sc) 16784d52a575SXin LI { 167905884511SPyun YongHyeon struct et_txdesc_ring *tx_ring; 168005884511SPyun YongHyeon struct et_txbuf_data *tbd; 168105884511SPyun YongHyeon struct et_txstatus_data *txsd; 16824d52a575SXin LI 168305884511SPyun YongHyeon tx_ring = &sc->sc_tx_ring; 16844d52a575SXin LI bzero(tx_ring->tr_desc, ET_TX_RING_SIZE); 16854d52a575SXin LI bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap, 16864d52a575SXin LI BUS_DMASYNC_PREWRITE); 16874d52a575SXin LI 168805884511SPyun YongHyeon tbd = &sc->sc_tx_data; 16894d52a575SXin LI tbd->tbd_start_index = 0; 16904d52a575SXin LI tbd->tbd_start_wrap = 0; 16914d52a575SXin LI tbd->tbd_used = 0; 16924d52a575SXin LI 169305884511SPyun YongHyeon txsd = &sc->sc_tx_status; 16944d52a575SXin LI bzero(txsd->txsd_status, sizeof(uint32_t)); 16954d52a575SXin LI bus_dmamap_sync(txsd->txsd_dtag, txsd->txsd_dmap, 169605884511SPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 16974d52a575SXin LI } 16984d52a575SXin LI 16994d52a575SXin LI static int 17004d52a575SXin LI et_init_rx_ring(struct et_softc *sc) 17014d52a575SXin LI { 170205884511SPyun YongHyeon struct et_rxstatus_data *rxsd; 170305884511SPyun YongHyeon struct et_rxstat_ring *rxst_ring; 170405884511SPyun YongHyeon struct et_rxbuf_data *rbd; 170505884511SPyun YongHyeon int i, error, n; 17064d52a575SXin LI 17074d52a575SXin LI for (n = 0; n < ET_RX_NRING; ++n) { 170805884511SPyun YongHyeon rbd = &sc->sc_rx_data[n]; 17094d52a575SXin LI for (i = 0; i < ET_RX_NDESC; ++i) { 171005884511SPyun YongHyeon error = rbd->rbd_newbuf(rbd, i); 17114d52a575SXin LI if (error) { 17124d52a575SXin LI if_printf(sc->ifp, "%d ring %d buf, " 17134d52a575SXin LI "newbuf failed: %d\n", n, i, error); 1714398f1b65SPyun YongHyeon return (error); 17154d52a575SXin LI } 17164d52a575SXin LI } 17174d52a575SXin LI } 17184d52a575SXin LI 171905884511SPyun YongHyeon rxsd = &sc->sc_rx_status; 17204d52a575SXin LI bzero(rxsd->rxsd_status, sizeof(struct et_rxstatus)); 17214d52a575SXin LI bus_dmamap_sync(rxsd->rxsd_dtag, rxsd->rxsd_dmap, 172205884511SPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 17234d52a575SXin LI 172405884511SPyun YongHyeon rxst_ring = &sc->sc_rxstat_ring; 17254d52a575SXin LI bzero(rxst_ring->rsr_stat, ET_RXSTAT_RING_SIZE); 17264d52a575SXin LI bus_dmamap_sync(rxst_ring->rsr_dtag, rxst_ring->rsr_dmap, 172705884511SPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 17284d52a575SXin LI 1729398f1b65SPyun YongHyeon return (0); 17304d52a575SXin LI } 17314d52a575SXin LI 17324d52a575SXin LI static int 17334d52a575SXin LI et_init_rxdma(struct et_softc *sc) 17344d52a575SXin LI { 17350b699044SPyun YongHyeon struct et_rxstatus_data *rxsd; 17360b699044SPyun YongHyeon struct et_rxstat_ring *rxst_ring; 17374d52a575SXin LI struct et_rxdesc_ring *rx_ring; 17384d52a575SXin LI int error; 17394d52a575SXin LI 17404d52a575SXin LI error = et_stop_rxdma(sc); 17414d52a575SXin LI if (error) { 17424d52a575SXin LI if_printf(sc->ifp, "can't init RX DMA engine\n"); 1743398f1b65SPyun YongHyeon return (error); 17444d52a575SXin LI } 17454d52a575SXin LI 17464d52a575SXin LI /* 17474d52a575SXin LI * Install RX status 17484d52a575SXin LI */ 17490b699044SPyun YongHyeon rxsd = &sc->sc_rx_status; 17504d52a575SXin LI CSR_WRITE_4(sc, ET_RX_STATUS_HI, ET_ADDR_HI(rxsd->rxsd_paddr)); 17514d52a575SXin LI CSR_WRITE_4(sc, ET_RX_STATUS_LO, ET_ADDR_LO(rxsd->rxsd_paddr)); 17524d52a575SXin LI 17534d52a575SXin LI /* 17544d52a575SXin LI * Install RX stat ring 17554d52a575SXin LI */ 17560b699044SPyun YongHyeon rxst_ring = &sc->sc_rxstat_ring; 17574d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_HI, ET_ADDR_HI(rxst_ring->rsr_paddr)); 17584d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_LO, ET_ADDR_LO(rxst_ring->rsr_paddr)); 17594d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_CNT, ET_RX_NSTAT - 1); 17604d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_POS, 0); 17614d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_MINCNT, ((ET_RX_NSTAT * 15) / 100) - 1); 17624d52a575SXin LI 17634d52a575SXin LI /* Match ET_RXSTAT_POS */ 17644d52a575SXin LI rxst_ring->rsr_index = 0; 17654d52a575SXin LI rxst_ring->rsr_wrap = 0; 17664d52a575SXin LI 17674d52a575SXin LI /* 17684d52a575SXin LI * Install the 2nd RX descriptor ring 17694d52a575SXin LI */ 17704d52a575SXin LI rx_ring = &sc->sc_rx_ring[1]; 17714d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING1_HI, ET_ADDR_HI(rx_ring->rr_paddr)); 17724d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING1_LO, ET_ADDR_LO(rx_ring->rr_paddr)); 17734d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING1_CNT, ET_RX_NDESC - 1); 17744d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING1_POS, ET_RX_RING1_POS_WRAP); 17754d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING1_MINCNT, ((ET_RX_NDESC * 15) / 100) - 1); 17764d52a575SXin LI 17774d52a575SXin LI /* Match ET_RX_RING1_POS */ 17784d52a575SXin LI rx_ring->rr_index = 0; 17794d52a575SXin LI rx_ring->rr_wrap = 1; 17804d52a575SXin LI 17814d52a575SXin LI /* 17824d52a575SXin LI * Install the 1st RX descriptor ring 17834d52a575SXin LI */ 17844d52a575SXin LI rx_ring = &sc->sc_rx_ring[0]; 17854d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING0_HI, ET_ADDR_HI(rx_ring->rr_paddr)); 17864d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING0_LO, ET_ADDR_LO(rx_ring->rr_paddr)); 17874d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING0_CNT, ET_RX_NDESC - 1); 17884d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING0_POS, ET_RX_RING0_POS_WRAP); 17894d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING0_MINCNT, ((ET_RX_NDESC * 15) / 100) - 1); 17904d52a575SXin LI 17914d52a575SXin LI /* Match ET_RX_RING0_POS */ 17924d52a575SXin LI rx_ring->rr_index = 0; 17934d52a575SXin LI rx_ring->rr_wrap = 1; 17944d52a575SXin LI 17954d52a575SXin LI /* 17964d52a575SXin LI * RX intr moderation 17974d52a575SXin LI */ 17984d52a575SXin LI CSR_WRITE_4(sc, ET_RX_INTR_NPKTS, sc->sc_rx_intr_npkts); 17994d52a575SXin LI CSR_WRITE_4(sc, ET_RX_INTR_DELAY, sc->sc_rx_intr_delay); 18004d52a575SXin LI 1801398f1b65SPyun YongHyeon return (0); 18024d52a575SXin LI } 18034d52a575SXin LI 18044d52a575SXin LI static int 18054d52a575SXin LI et_init_txdma(struct et_softc *sc) 18064d52a575SXin LI { 18070b699044SPyun YongHyeon struct et_txdesc_ring *tx_ring; 18080b699044SPyun YongHyeon struct et_txstatus_data *txsd; 18094d52a575SXin LI int error; 18104d52a575SXin LI 18114d52a575SXin LI error = et_stop_txdma(sc); 18124d52a575SXin LI if (error) { 18134d52a575SXin LI if_printf(sc->ifp, "can't init TX DMA engine\n"); 1814398f1b65SPyun YongHyeon return (error); 18154d52a575SXin LI } 18164d52a575SXin LI 18174d52a575SXin LI /* 18184d52a575SXin LI * Install TX descriptor ring 18194d52a575SXin LI */ 18200b699044SPyun YongHyeon tx_ring = &sc->sc_tx_ring; 18214d52a575SXin LI CSR_WRITE_4(sc, ET_TX_RING_HI, ET_ADDR_HI(tx_ring->tr_paddr)); 18224d52a575SXin LI CSR_WRITE_4(sc, ET_TX_RING_LO, ET_ADDR_LO(tx_ring->tr_paddr)); 18234d52a575SXin LI CSR_WRITE_4(sc, ET_TX_RING_CNT, ET_TX_NDESC - 1); 18244d52a575SXin LI 18254d52a575SXin LI /* 18264d52a575SXin LI * Install TX status 18274d52a575SXin LI */ 18280b699044SPyun YongHyeon txsd = &sc->sc_tx_status; 18294d52a575SXin LI CSR_WRITE_4(sc, ET_TX_STATUS_HI, ET_ADDR_HI(txsd->txsd_paddr)); 18304d52a575SXin LI CSR_WRITE_4(sc, ET_TX_STATUS_LO, ET_ADDR_LO(txsd->txsd_paddr)); 18314d52a575SXin LI 18324d52a575SXin LI CSR_WRITE_4(sc, ET_TX_READY_POS, 0); 18334d52a575SXin LI 18344d52a575SXin LI /* Match ET_TX_READY_POS */ 18354d52a575SXin LI tx_ring->tr_ready_index = 0; 18364d52a575SXin LI tx_ring->tr_ready_wrap = 0; 18374d52a575SXin LI 1838398f1b65SPyun YongHyeon return (0); 18394d52a575SXin LI } 18404d52a575SXin LI 18414d52a575SXin LI static void 18424d52a575SXin LI et_init_mac(struct et_softc *sc) 18434d52a575SXin LI { 1844*7c509be1SJustin Hibbits if_t ifp; 18450b699044SPyun YongHyeon const uint8_t *eaddr; 18464d52a575SXin LI uint32_t val; 18474d52a575SXin LI 18484d52a575SXin LI /* Reset MAC */ 18494d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 18504d52a575SXin LI ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 18514d52a575SXin LI ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | 18524d52a575SXin LI ET_MAC_CFG1_SIM_RST | ET_MAC_CFG1_SOFT_RST); 18534d52a575SXin LI 18544d52a575SXin LI /* 18554d52a575SXin LI * Setup inter packet gap 18564d52a575SXin LI */ 185723263665SPyun YongHyeon val = (56 << ET_IPG_NONB2B_1_SHIFT) | 185823263665SPyun YongHyeon (88 << ET_IPG_NONB2B_2_SHIFT) | 185923263665SPyun YongHyeon (80 << ET_IPG_MINIFG_SHIFT) | 186023263665SPyun YongHyeon (96 << ET_IPG_B2B_SHIFT); 18614d52a575SXin LI CSR_WRITE_4(sc, ET_IPG, val); 18624d52a575SXin LI 18634d52a575SXin LI /* 18644d52a575SXin LI * Setup half duplex mode 18654d52a575SXin LI */ 186623263665SPyun YongHyeon val = (10 << ET_MAC_HDX_ALT_BEB_TRUNC_SHIFT) | 186723263665SPyun YongHyeon (15 << ET_MAC_HDX_REXMIT_MAX_SHIFT) | 186823263665SPyun YongHyeon (55 << ET_MAC_HDX_COLLWIN_SHIFT) | 18694d52a575SXin LI ET_MAC_HDX_EXC_DEFER; 18704d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_HDX, val); 18714d52a575SXin LI 18724d52a575SXin LI /* Clear MAC control */ 18734d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CTRL, 0); 18744d52a575SXin LI 18754d52a575SXin LI /* Reset MII */ 18764d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CFG, ET_MII_CFG_CLKRST); 18774d52a575SXin LI 18784d52a575SXin LI /* 18794d52a575SXin LI * Set MAC address 18804d52a575SXin LI */ 18810b699044SPyun YongHyeon ifp = sc->ifp; 1882*7c509be1SJustin Hibbits eaddr = if_getlladdr(ifp); 18834d52a575SXin LI val = eaddr[2] | (eaddr[3] << 8) | (eaddr[4] << 16) | (eaddr[5] << 24); 18844d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_ADDR1, val); 18854d52a575SXin LI val = (eaddr[0] << 16) | (eaddr[1] << 24); 18864d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_ADDR2, val); 18874d52a575SXin LI 18884d52a575SXin LI /* Set max frame length */ 1889*7c509be1SJustin Hibbits CSR_WRITE_4(sc, ET_MAX_FRMLEN, ET_FRAMELEN(if_getmtu(ifp))); 18904d52a575SXin LI 18914d52a575SXin LI /* Bring MAC out of reset state */ 18924d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 0); 18934d52a575SXin LI } 18944d52a575SXin LI 18954d52a575SXin LI static void 18964d52a575SXin LI et_init_rxmac(struct et_softc *sc) 18974d52a575SXin LI { 1898*7c509be1SJustin Hibbits if_t ifp; 18990b699044SPyun YongHyeon const uint8_t *eaddr; 19004d52a575SXin LI uint32_t val; 19014d52a575SXin LI int i; 19024d52a575SXin LI 19034d52a575SXin LI /* Disable RX MAC and WOL */ 19044d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_CTRL, ET_RXMAC_CTRL_WOL_DISABLE); 19054d52a575SXin LI 19064d52a575SXin LI /* 19074d52a575SXin LI * Clear all WOL related registers 19084d52a575SXin LI */ 19094d52a575SXin LI for (i = 0; i < 3; ++i) 19104d52a575SXin LI CSR_WRITE_4(sc, ET_WOL_CRC + (i * 4), 0); 19114d52a575SXin LI for (i = 0; i < 20; ++i) 19124d52a575SXin LI CSR_WRITE_4(sc, ET_WOL_MASK + (i * 4), 0); 19134d52a575SXin LI 19144d52a575SXin LI /* 19154d52a575SXin LI * Set WOL source address. XXX is this necessary? 19164d52a575SXin LI */ 19170b699044SPyun YongHyeon ifp = sc->ifp; 1918*7c509be1SJustin Hibbits eaddr = if_getlladdr(ifp); 19194d52a575SXin LI val = (eaddr[2] << 24) | (eaddr[3] << 16) | (eaddr[4] << 8) | eaddr[5]; 19204d52a575SXin LI CSR_WRITE_4(sc, ET_WOL_SA_LO, val); 19214d52a575SXin LI val = (eaddr[0] << 8) | eaddr[1]; 19224d52a575SXin LI CSR_WRITE_4(sc, ET_WOL_SA_HI, val); 19234d52a575SXin LI 19244d52a575SXin LI /* Clear packet filters */ 19254d52a575SXin LI CSR_WRITE_4(sc, ET_PKTFILT, 0); 19264d52a575SXin LI 19274d52a575SXin LI /* No ucast filtering */ 19284d52a575SXin LI CSR_WRITE_4(sc, ET_UCAST_FILTADDR1, 0); 19294d52a575SXin LI CSR_WRITE_4(sc, ET_UCAST_FILTADDR2, 0); 19304d52a575SXin LI CSR_WRITE_4(sc, ET_UCAST_FILTADDR3, 0); 19314d52a575SXin LI 1932*7c509be1SJustin Hibbits if (ET_FRAMELEN(if_getmtu(ifp)) > ET_RXMAC_CUT_THRU_FRMLEN) { 19334d52a575SXin LI /* 19344d52a575SXin LI * In order to transmit jumbo packets greater than 19354d52a575SXin LI * ET_RXMAC_CUT_THRU_FRMLEN bytes, the FIFO between 19364d52a575SXin LI * RX MAC and RX DMA needs to be reduced in size to 19374d52a575SXin LI * (ET_MEM_SIZE - ET_MEM_TXSIZE_EX - framelen). In 19384d52a575SXin LI * order to implement this, we must use "cut through" 19394d52a575SXin LI * mode in the RX MAC, which chops packets down into 19404d52a575SXin LI * segments. In this case we selected 256 bytes, 19414d52a575SXin LI * since this is the size of the PCI-Express TLP's 19424d52a575SXin LI * that the ET1310 uses. 19434d52a575SXin LI */ 194423263665SPyun YongHyeon val = (ET_RXMAC_SEGSZ(256) & ET_RXMAC_MC_SEGSZ_MAX_MASK) | 19454d52a575SXin LI ET_RXMAC_MC_SEGSZ_ENABLE; 19464d52a575SXin LI } else { 19474d52a575SXin LI val = 0; 19484d52a575SXin LI } 19494d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_MC_SEGSZ, val); 19504d52a575SXin LI 19514d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_MC_WATERMARK, 0); 19524d52a575SXin LI 19534d52a575SXin LI /* Initialize RX MAC management register */ 19544d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_MGT, 0); 19554d52a575SXin LI 19564d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_SPACE_AVL, 0); 19574d52a575SXin LI 19584d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_MGT, 19594d52a575SXin LI ET_RXMAC_MGT_PASS_ECRC | 19604d52a575SXin LI ET_RXMAC_MGT_PASS_ELEN | 19614d52a575SXin LI ET_RXMAC_MGT_PASS_ETRUNC | 19624d52a575SXin LI ET_RXMAC_MGT_CHECK_PKT); 19634d52a575SXin LI 19644d52a575SXin LI /* 19654d52a575SXin LI * Configure runt filtering (may not work on certain chip generation) 19664d52a575SXin LI */ 196723263665SPyun YongHyeon val = (ETHER_MIN_LEN << ET_PKTFILT_MINLEN_SHIFT) & 196823263665SPyun YongHyeon ET_PKTFILT_MINLEN_MASK; 196923263665SPyun YongHyeon val |= ET_PKTFILT_FRAG; 19704d52a575SXin LI CSR_WRITE_4(sc, ET_PKTFILT, val); 19714d52a575SXin LI 19724d52a575SXin LI /* Enable RX MAC but leave WOL disabled */ 19734d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_CTRL, 19744d52a575SXin LI ET_RXMAC_CTRL_WOL_DISABLE | ET_RXMAC_CTRL_ENABLE); 19754d52a575SXin LI 19764d52a575SXin LI /* 19774d52a575SXin LI * Setup multicast hash and allmulti/promisc mode 19784d52a575SXin LI */ 19794d52a575SXin LI et_setmulti(sc); 19804d52a575SXin LI } 19814d52a575SXin LI 19824d52a575SXin LI static void 19834d52a575SXin LI et_init_txmac(struct et_softc *sc) 19844d52a575SXin LI { 19850b699044SPyun YongHyeon 19864d52a575SXin LI /* Disable TX MAC and FC(?) */ 19874d52a575SXin LI CSR_WRITE_4(sc, ET_TXMAC_CTRL, ET_TXMAC_CTRL_FC_DISABLE); 19884d52a575SXin LI 19895d384a0dSPyun YongHyeon /* 19905d384a0dSPyun YongHyeon * Initialize pause time. 19915d384a0dSPyun YongHyeon * This register should be set before XON/XOFF frame is 19925d384a0dSPyun YongHyeon * sent by driver. 19935d384a0dSPyun YongHyeon */ 19945d384a0dSPyun YongHyeon CSR_WRITE_4(sc, ET_TXMAC_FLOWCTRL, 0 << ET_TXMAC_FLOWCTRL_CFPT_SHIFT); 19954d52a575SXin LI 19964d52a575SXin LI /* Enable TX MAC but leave FC(?) diabled */ 19974d52a575SXin LI CSR_WRITE_4(sc, ET_TXMAC_CTRL, 19984d52a575SXin LI ET_TXMAC_CTRL_ENABLE | ET_TXMAC_CTRL_FC_DISABLE); 19994d52a575SXin LI } 20004d52a575SXin LI 20014d52a575SXin LI static int 20024d52a575SXin LI et_start_rxdma(struct et_softc *sc) 20034d52a575SXin LI { 20040b699044SPyun YongHyeon uint32_t val; 20054d52a575SXin LI 20060b699044SPyun YongHyeon val = (sc->sc_rx_data[0].rbd_bufsize & ET_RXDMA_CTRL_RING0_SIZE_MASK) | 20074d52a575SXin LI ET_RXDMA_CTRL_RING0_ENABLE; 200823263665SPyun YongHyeon val |= (sc->sc_rx_data[1].rbd_bufsize & ET_RXDMA_CTRL_RING1_SIZE_MASK) | 20094d52a575SXin LI ET_RXDMA_CTRL_RING1_ENABLE; 20104d52a575SXin LI 20114d52a575SXin LI CSR_WRITE_4(sc, ET_RXDMA_CTRL, val); 20124d52a575SXin LI 20134d52a575SXin LI DELAY(5); 20144d52a575SXin LI 20154d52a575SXin LI if (CSR_READ_4(sc, ET_RXDMA_CTRL) & ET_RXDMA_CTRL_HALTED) { 20164d52a575SXin LI if_printf(sc->ifp, "can't start RX DMA engine\n"); 2017398f1b65SPyun YongHyeon return (ETIMEDOUT); 20184d52a575SXin LI } 2019398f1b65SPyun YongHyeon return (0); 20204d52a575SXin LI } 20214d52a575SXin LI 20224d52a575SXin LI static int 20234d52a575SXin LI et_start_txdma(struct et_softc *sc) 20244d52a575SXin LI { 20250b699044SPyun YongHyeon 20264d52a575SXin LI CSR_WRITE_4(sc, ET_TXDMA_CTRL, ET_TXDMA_CTRL_SINGLE_EPKT); 2027398f1b65SPyun YongHyeon return (0); 20284d52a575SXin LI } 20294d52a575SXin LI 20304d52a575SXin LI static void 20314d52a575SXin LI et_rxeof(struct et_softc *sc) 20324d52a575SXin LI { 20334d52a575SXin LI struct et_rxstatus_data *rxsd; 20344d52a575SXin LI struct et_rxstat_ring *rxst_ring; 203505884511SPyun YongHyeon struct et_rxbuf_data *rbd; 203605884511SPyun YongHyeon struct et_rxdesc_ring *rx_ring; 203705884511SPyun YongHyeon struct et_rxstat *st; 2038*7c509be1SJustin Hibbits if_t ifp; 203905884511SPyun YongHyeon struct mbuf *m; 204005884511SPyun YongHyeon uint32_t rxstat_pos, rxring_pos; 204105884511SPyun YongHyeon uint32_t rxst_info1, rxst_info2, rxs_stat_ring; 204205884511SPyun YongHyeon int buflen, buf_idx, npost[2], ring_idx; 204305884511SPyun YongHyeon int rxst_index, rxst_wrap; 20444d52a575SXin LI 20454d52a575SXin LI ET_LOCK_ASSERT(sc); 204605884511SPyun YongHyeon 20474d52a575SXin LI ifp = sc->ifp; 20484d52a575SXin LI rxsd = &sc->sc_rx_status; 20494d52a575SXin LI rxst_ring = &sc->sc_rxstat_ring; 20504d52a575SXin LI 20514d52a575SXin LI if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0) 20524d52a575SXin LI return; 20534d52a575SXin LI 20544d52a575SXin LI bus_dmamap_sync(rxsd->rxsd_dtag, rxsd->rxsd_dmap, 20554d52a575SXin LI BUS_DMASYNC_POSTREAD); 20564d52a575SXin LI bus_dmamap_sync(rxst_ring->rsr_dtag, rxst_ring->rsr_dmap, 20574d52a575SXin LI BUS_DMASYNC_POSTREAD); 20584d52a575SXin LI 205905884511SPyun YongHyeon npost[0] = npost[1] = 0; 206026e07b50SPyun YongHyeon rxs_stat_ring = le32toh(rxsd->rxsd_status->rxs_stat_ring); 20614d52a575SXin LI rxst_wrap = (rxs_stat_ring & ET_RXS_STATRING_WRAP) ? 1 : 0; 206223263665SPyun YongHyeon rxst_index = (rxs_stat_ring & ET_RXS_STATRING_INDEX_MASK) >> 206323263665SPyun YongHyeon ET_RXS_STATRING_INDEX_SHIFT; 20644d52a575SXin LI 20654d52a575SXin LI while (rxst_index != rxst_ring->rsr_index || 20664d52a575SXin LI rxst_wrap != rxst_ring->rsr_wrap) { 2067*7c509be1SJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) 206805884511SPyun YongHyeon break; 20694d52a575SXin LI 20704d52a575SXin LI MPASS(rxst_ring->rsr_index < ET_RX_NSTAT); 20714d52a575SXin LI st = &rxst_ring->rsr_stat[rxst_ring->rsr_index]; 207205884511SPyun YongHyeon rxst_info1 = le32toh(st->rxst_info1); 207326e07b50SPyun YongHyeon rxst_info2 = le32toh(st->rxst_info2); 207426e07b50SPyun YongHyeon buflen = (rxst_info2 & ET_RXST_INFO2_LEN_MASK) >> 207523263665SPyun YongHyeon ET_RXST_INFO2_LEN_SHIFT; 207626e07b50SPyun YongHyeon buf_idx = (rxst_info2 & ET_RXST_INFO2_BUFIDX_MASK) >> 207723263665SPyun YongHyeon ET_RXST_INFO2_BUFIDX_SHIFT; 207826e07b50SPyun YongHyeon ring_idx = (rxst_info2 & ET_RXST_INFO2_RINGIDX_MASK) >> 207923263665SPyun YongHyeon ET_RXST_INFO2_RINGIDX_SHIFT; 20804d52a575SXin LI 20814d52a575SXin LI if (++rxst_ring->rsr_index == ET_RX_NSTAT) { 20824d52a575SXin LI rxst_ring->rsr_index = 0; 20834d52a575SXin LI rxst_ring->rsr_wrap ^= 1; 20844d52a575SXin LI } 208523263665SPyun YongHyeon rxstat_pos = rxst_ring->rsr_index & ET_RXSTAT_POS_INDEX_MASK; 20864d52a575SXin LI if (rxst_ring->rsr_wrap) 20874d52a575SXin LI rxstat_pos |= ET_RXSTAT_POS_WRAP; 20884d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_POS, rxstat_pos); 20894d52a575SXin LI 20904d52a575SXin LI if (ring_idx >= ET_RX_NRING) { 2091c13dc687SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 20924d52a575SXin LI if_printf(ifp, "invalid ring index %d\n", ring_idx); 20934d52a575SXin LI continue; 20944d52a575SXin LI } 20954d52a575SXin LI if (buf_idx >= ET_RX_NDESC) { 2096c13dc687SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 20974d52a575SXin LI if_printf(ifp, "invalid buf index %d\n", buf_idx); 20984d52a575SXin LI continue; 20994d52a575SXin LI } 21004d52a575SXin LI 21014d52a575SXin LI rbd = &sc->sc_rx_data[ring_idx]; 21024d52a575SXin LI m = rbd->rbd_buf[buf_idx].rb_mbuf; 210305884511SPyun YongHyeon if ((rxst_info1 & ET_RXST_INFO1_OK) == 0){ 210405884511SPyun YongHyeon /* Discard errored frame. */ 210505884511SPyun YongHyeon rbd->rbd_discard(rbd, buf_idx); 210605884511SPyun YongHyeon } else if (rbd->rbd_newbuf(rbd, buf_idx) != 0) { 210705884511SPyun YongHyeon /* No available mbufs, discard it. */ 2108c13dc687SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 210905884511SPyun YongHyeon rbd->rbd_discard(rbd, buf_idx); 211005884511SPyun YongHyeon } else { 211105884511SPyun YongHyeon buflen -= ETHER_CRC_LEN; 211205884511SPyun YongHyeon if (buflen < ETHER_HDR_LEN) { 21134d52a575SXin LI m_freem(m); 2114c13dc687SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 21154d52a575SXin LI } else { 211605884511SPyun YongHyeon m->m_pkthdr.len = m->m_len = buflen; 21174d52a575SXin LI m->m_pkthdr.rcvif = ifp; 21184d52a575SXin LI ET_UNLOCK(sc); 2119*7c509be1SJustin Hibbits if_input(ifp, m); 21204d52a575SXin LI ET_LOCK(sc); 21214d52a575SXin LI } 21224d52a575SXin LI } 21234d52a575SXin LI 21244d52a575SXin LI rx_ring = &sc->sc_rx_ring[ring_idx]; 21254d52a575SXin LI if (buf_idx != rx_ring->rr_index) { 212605884511SPyun YongHyeon if_printf(ifp, 212705884511SPyun YongHyeon "WARNING!! ring %d, buf_idx %d, rr_idx %d\n", 21284d52a575SXin LI ring_idx, buf_idx, rx_ring->rr_index); 21294d52a575SXin LI } 21304d52a575SXin LI 21314d52a575SXin LI MPASS(rx_ring->rr_index < ET_RX_NDESC); 21324d52a575SXin LI if (++rx_ring->rr_index == ET_RX_NDESC) { 21334d52a575SXin LI rx_ring->rr_index = 0; 21344d52a575SXin LI rx_ring->rr_wrap ^= 1; 21354d52a575SXin LI } 213623263665SPyun YongHyeon rxring_pos = rx_ring->rr_index & ET_RX_RING_POS_INDEX_MASK; 21374d52a575SXin LI if (rx_ring->rr_wrap) 21384d52a575SXin LI rxring_pos |= ET_RX_RING_POS_WRAP; 21394d52a575SXin LI CSR_WRITE_4(sc, rx_ring->rr_posreg, rxring_pos); 21404d52a575SXin LI } 214105884511SPyun YongHyeon 214205884511SPyun YongHyeon bus_dmamap_sync(rxsd->rxsd_dtag, rxsd->rxsd_dmap, 214305884511SPyun YongHyeon BUS_DMASYNC_PREREAD); 214405884511SPyun YongHyeon bus_dmamap_sync(rxst_ring->rsr_dtag, rxst_ring->rsr_dmap, 214505884511SPyun YongHyeon BUS_DMASYNC_PREREAD); 21464d52a575SXin LI } 21474d52a575SXin LI 21484d52a575SXin LI static int 21494d52a575SXin LI et_encap(struct et_softc *sc, struct mbuf **m0) 21504d52a575SXin LI { 215105884511SPyun YongHyeon struct et_txdesc_ring *tx_ring; 215205884511SPyun YongHyeon struct et_txbuf_data *tbd; 21534d52a575SXin LI struct et_txdesc *td; 215405884511SPyun YongHyeon struct mbuf *m; 215505884511SPyun YongHyeon bus_dma_segment_t segs[ET_NSEG_MAX]; 21564d52a575SXin LI bus_dmamap_t map; 2157244fd28bSPyun YongHyeon uint32_t csum_flags, last_td_ctrl2; 215805884511SPyun YongHyeon int error, i, idx, first_idx, last_idx, nsegs; 21594d52a575SXin LI 216005884511SPyun YongHyeon tx_ring = &sc->sc_tx_ring; 21614d52a575SXin LI MPASS(tx_ring->tr_ready_index < ET_TX_NDESC); 216205884511SPyun YongHyeon tbd = &sc->sc_tx_data; 21634d52a575SXin LI first_idx = tx_ring->tr_ready_index; 21644d52a575SXin LI map = tbd->tbd_buf[first_idx].tb_dmap; 21654d52a575SXin LI 216605884511SPyun YongHyeon error = bus_dmamap_load_mbuf_sg(sc->sc_tx_tag, map, *m0, segs, &nsegs, 216705884511SPyun YongHyeon 0); 216805884511SPyun YongHyeon if (error == EFBIG) { 2169c6499eccSGleb Smirnoff m = m_collapse(*m0, M_NOWAIT, ET_NSEG_MAX); 217005884511SPyun YongHyeon if (m == NULL) { 217105884511SPyun YongHyeon m_freem(*m0); 217205884511SPyun YongHyeon *m0 = NULL; 217305884511SPyun YongHyeon return (ENOMEM); 21744d52a575SXin LI } 217505884511SPyun YongHyeon *m0 = m; 217605884511SPyun YongHyeon error = bus_dmamap_load_mbuf_sg(sc->sc_tx_tag, map, *m0, segs, 217705884511SPyun YongHyeon &nsegs, 0); 217805884511SPyun YongHyeon if (error != 0) { 217905884511SPyun YongHyeon m_freem(*m0); 218005884511SPyun YongHyeon *m0 = NULL; 218105884511SPyun YongHyeon return (error); 21824d52a575SXin LI } 218305884511SPyun YongHyeon } else if (error != 0) 218405884511SPyun YongHyeon return (error); 21854d52a575SXin LI 218605884511SPyun YongHyeon /* Check for descriptor overruns. */ 218705884511SPyun YongHyeon if (tbd->tbd_used + nsegs > ET_TX_NDESC - 1) { 218805884511SPyun YongHyeon bus_dmamap_unload(sc->sc_tx_tag, map); 218905884511SPyun YongHyeon return (ENOBUFS); 21904d52a575SXin LI } 219105884511SPyun YongHyeon bus_dmamap_sync(sc->sc_tx_tag, map, BUS_DMASYNC_PREWRITE); 21924d52a575SXin LI 21934d52a575SXin LI last_td_ctrl2 = ET_TDCTRL2_LAST_FRAG; 219405884511SPyun YongHyeon sc->sc_tx += nsegs; 21954d52a575SXin LI if (sc->sc_tx / sc->sc_tx_intr_nsegs != sc->sc_tx_intr) { 21964d52a575SXin LI sc->sc_tx_intr = sc->sc_tx / sc->sc_tx_intr_nsegs; 21974d52a575SXin LI last_td_ctrl2 |= ET_TDCTRL2_INTR; 21984d52a575SXin LI } 21994d52a575SXin LI 220005884511SPyun YongHyeon m = *m0; 22019955274cSPyun YongHyeon csum_flags = 0; 22029955274cSPyun YongHyeon if ((m->m_pkthdr.csum_flags & ET_CSUM_FEATURES) != 0) { 22039955274cSPyun YongHyeon if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) 22049955274cSPyun YongHyeon csum_flags |= ET_TDCTRL2_CSUM_IP; 22059955274cSPyun YongHyeon if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) 22069955274cSPyun YongHyeon csum_flags |= ET_TDCTRL2_CSUM_UDP; 22079955274cSPyun YongHyeon else if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0) 22089955274cSPyun YongHyeon csum_flags |= ET_TDCTRL2_CSUM_TCP; 22099955274cSPyun YongHyeon } 22104d52a575SXin LI last_idx = -1; 221105884511SPyun YongHyeon for (i = 0; i < nsegs; ++i) { 22124d52a575SXin LI idx = (first_idx + i) % ET_TX_NDESC; 22134d52a575SXin LI td = &tx_ring->tr_desc[idx]; 221426e07b50SPyun YongHyeon td->td_addr_hi = htole32(ET_ADDR_HI(segs[i].ds_addr)); 221526e07b50SPyun YongHyeon td->td_addr_lo = htole32(ET_ADDR_LO(segs[i].ds_addr)); 221626e07b50SPyun YongHyeon td->td_ctrl1 = htole32(segs[i].ds_len & ET_TDCTRL1_LEN_MASK); 221705884511SPyun YongHyeon if (i == nsegs - 1) { 221805884511SPyun YongHyeon /* Last frag */ 22199955274cSPyun YongHyeon td->td_ctrl2 = htole32(last_td_ctrl2 | csum_flags); 22204d52a575SXin LI last_idx = idx; 22219955274cSPyun YongHyeon } else 22229955274cSPyun YongHyeon td->td_ctrl2 = htole32(csum_flags); 22234d52a575SXin LI 22244d52a575SXin LI MPASS(tx_ring->tr_ready_index < ET_TX_NDESC); 22254d52a575SXin LI if (++tx_ring->tr_ready_index == ET_TX_NDESC) { 22264d52a575SXin LI tx_ring->tr_ready_index = 0; 22274d52a575SXin LI tx_ring->tr_ready_wrap ^= 1; 22284d52a575SXin LI } 22294d52a575SXin LI } 22304d52a575SXin LI td = &tx_ring->tr_desc[first_idx]; 223105884511SPyun YongHyeon /* First frag */ 223205884511SPyun YongHyeon td->td_ctrl2 |= htole32(ET_TDCTRL2_FIRST_FRAG); 22334d52a575SXin LI 22344d52a575SXin LI MPASS(last_idx >= 0); 22354d52a575SXin LI tbd->tbd_buf[first_idx].tb_dmap = tbd->tbd_buf[last_idx].tb_dmap; 22364d52a575SXin LI tbd->tbd_buf[last_idx].tb_dmap = map; 22374d52a575SXin LI tbd->tbd_buf[last_idx].tb_mbuf = m; 22384d52a575SXin LI 223905884511SPyun YongHyeon tbd->tbd_used += nsegs; 22404d52a575SXin LI MPASS(tbd->tbd_used <= ET_TX_NDESC); 22414d52a575SXin LI 224205884511SPyun YongHyeon return (0); 22434d52a575SXin LI } 22444d52a575SXin LI 22454d52a575SXin LI static void 22464d52a575SXin LI et_txeof(struct et_softc *sc) 22474d52a575SXin LI { 22484d52a575SXin LI struct et_txdesc_ring *tx_ring; 22494d52a575SXin LI struct et_txbuf_data *tbd; 225005884511SPyun YongHyeon struct et_txbuf *tb; 2251*7c509be1SJustin Hibbits if_t ifp; 22524d52a575SXin LI uint32_t tx_done; 22534d52a575SXin LI int end, wrap; 22544d52a575SXin LI 22554d52a575SXin LI ET_LOCK_ASSERT(sc); 225605884511SPyun YongHyeon 22574d52a575SXin LI ifp = sc->ifp; 22584d52a575SXin LI tx_ring = &sc->sc_tx_ring; 22594d52a575SXin LI tbd = &sc->sc_tx_data; 22604d52a575SXin LI 22614d52a575SXin LI if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0) 22624d52a575SXin LI return; 22634d52a575SXin LI 22644d52a575SXin LI if (tbd->tbd_used == 0) 22654d52a575SXin LI return; 22664d52a575SXin LI 226705884511SPyun YongHyeon bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap, 226805884511SPyun YongHyeon BUS_DMASYNC_POSTWRITE); 226905884511SPyun YongHyeon 22704d52a575SXin LI tx_done = CSR_READ_4(sc, ET_TX_DONE_POS); 227123263665SPyun YongHyeon end = tx_done & ET_TX_DONE_POS_INDEX_MASK; 22724d52a575SXin LI wrap = (tx_done & ET_TX_DONE_POS_WRAP) ? 1 : 0; 22734d52a575SXin LI 22744d52a575SXin LI while (tbd->tbd_start_index != end || tbd->tbd_start_wrap != wrap) { 22754d52a575SXin LI MPASS(tbd->tbd_start_index < ET_TX_NDESC); 22764d52a575SXin LI tb = &tbd->tbd_buf[tbd->tbd_start_index]; 22774d52a575SXin LI if (tb->tb_mbuf != NULL) { 227805884511SPyun YongHyeon bus_dmamap_sync(sc->sc_tx_tag, tb->tb_dmap, 227905884511SPyun YongHyeon BUS_DMASYNC_POSTWRITE); 228005884511SPyun YongHyeon bus_dmamap_unload(sc->sc_tx_tag, tb->tb_dmap); 22814d52a575SXin LI m_freem(tb->tb_mbuf); 22824d52a575SXin LI tb->tb_mbuf = NULL; 22834d52a575SXin LI } 22844d52a575SXin LI 22854d52a575SXin LI if (++tbd->tbd_start_index == ET_TX_NDESC) { 22864d52a575SXin LI tbd->tbd_start_index = 0; 22874d52a575SXin LI tbd->tbd_start_wrap ^= 1; 22884d52a575SXin LI } 22894d52a575SXin LI 22904d52a575SXin LI MPASS(tbd->tbd_used > 0); 22914d52a575SXin LI tbd->tbd_used--; 22924d52a575SXin LI } 22934d52a575SXin LI 22944d52a575SXin LI if (tbd->tbd_used == 0) 22954d52a575SXin LI sc->watchdog_timer = 0; 229605884511SPyun YongHyeon if (tbd->tbd_used + ET_NSEG_SPARE < ET_TX_NDESC) 2297*7c509be1SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 22984d52a575SXin LI } 22991f009e2fSPyun YongHyeon 23004d52a575SXin LI static void 23014d52a575SXin LI et_tick(void *xsc) 23024d52a575SXin LI { 23030b699044SPyun YongHyeon struct et_softc *sc; 23044d52a575SXin LI struct mii_data *mii; 23054d52a575SXin LI 23060b699044SPyun YongHyeon sc = xsc; 23074d52a575SXin LI ET_LOCK_ASSERT(sc); 23084d52a575SXin LI mii = device_get_softc(sc->sc_miibus); 23094d52a575SXin LI 23104d52a575SXin LI mii_tick(mii); 2311e0b5ac02SPyun YongHyeon et_stats_update(sc); 231205884511SPyun YongHyeon if (et_watchdog(sc) == EJUSTRETURN) 231305884511SPyun YongHyeon return; 23144d52a575SXin LI callout_reset(&sc->sc_tick, hz, et_tick, sc); 23154d52a575SXin LI } 23164d52a575SXin LI 23174d52a575SXin LI static int 231805884511SPyun YongHyeon et_newbuf_cluster(struct et_rxbuf_data *rbd, int buf_idx) 23194d52a575SXin LI { 232005884511SPyun YongHyeon struct et_softc *sc; 232105884511SPyun YongHyeon struct et_rxdesc *desc; 23224d52a575SXin LI struct et_rxbuf *rb; 23234d52a575SXin LI struct mbuf *m; 232405884511SPyun YongHyeon bus_dma_segment_t segs[1]; 23254d52a575SXin LI bus_dmamap_t dmap; 232605884511SPyun YongHyeon int nsegs; 23274d52a575SXin LI 23284d52a575SXin LI MPASS(buf_idx < ET_RX_NDESC); 2329c6499eccSGleb Smirnoff m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 233005884511SPyun YongHyeon if (m == NULL) 233105884511SPyun YongHyeon return (ENOBUFS); 233205884511SPyun YongHyeon m->m_len = m->m_pkthdr.len = MCLBYTES; 233305884511SPyun YongHyeon m_adj(m, ETHER_ALIGN); 233405884511SPyun YongHyeon 233505884511SPyun YongHyeon sc = rbd->rbd_softc; 23364d52a575SXin LI rb = &rbd->rbd_buf[buf_idx]; 23374d52a575SXin LI 233805884511SPyun YongHyeon if (bus_dmamap_load_mbuf_sg(sc->sc_rx_tag, sc->sc_rx_sparemap, m, 233905884511SPyun YongHyeon segs, &nsegs, 0) != 0) { 23404d52a575SXin LI m_freem(m); 234105884511SPyun YongHyeon return (ENOBUFS); 23424d52a575SXin LI } 234305884511SPyun YongHyeon KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 23444d52a575SXin LI 234505884511SPyun YongHyeon if (rb->rb_mbuf != NULL) { 234605884511SPyun YongHyeon bus_dmamap_sync(sc->sc_rx_tag, rb->rb_dmap, 23474d52a575SXin LI BUS_DMASYNC_POSTREAD); 234805884511SPyun YongHyeon bus_dmamap_unload(sc->sc_rx_tag, rb->rb_dmap); 23494d52a575SXin LI } 23504d52a575SXin LI dmap = rb->rb_dmap; 235105884511SPyun YongHyeon rb->rb_dmap = sc->sc_rx_sparemap; 235205884511SPyun YongHyeon sc->sc_rx_sparemap = dmap; 235305884511SPyun YongHyeon bus_dmamap_sync(sc->sc_rx_tag, rb->rb_dmap, BUS_DMASYNC_PREREAD); 23544d52a575SXin LI 235505884511SPyun YongHyeon rb->rb_mbuf = m; 235605884511SPyun YongHyeon desc = &rbd->rbd_ring->rr_desc[buf_idx]; 235705884511SPyun YongHyeon desc->rd_addr_hi = htole32(ET_ADDR_HI(segs[0].ds_addr)); 235805884511SPyun YongHyeon desc->rd_addr_lo = htole32(ET_ADDR_LO(segs[0].ds_addr)); 235905884511SPyun YongHyeon desc->rd_ctrl = htole32(buf_idx & ET_RDCTRL_BUFIDX_MASK); 236005884511SPyun YongHyeon bus_dmamap_sync(rbd->rbd_ring->rr_dtag, rbd->rbd_ring->rr_dmap, 236105884511SPyun YongHyeon BUS_DMASYNC_PREWRITE); 236205884511SPyun YongHyeon return (0); 236305884511SPyun YongHyeon } 236405884511SPyun YongHyeon 236505884511SPyun YongHyeon static void 236605884511SPyun YongHyeon et_rxbuf_discard(struct et_rxbuf_data *rbd, int buf_idx) 236705884511SPyun YongHyeon { 236805884511SPyun YongHyeon struct et_rxdesc *desc; 236905884511SPyun YongHyeon 237005884511SPyun YongHyeon desc = &rbd->rbd_ring->rr_desc[buf_idx]; 237105884511SPyun YongHyeon desc->rd_ctrl = htole32(buf_idx & ET_RDCTRL_BUFIDX_MASK); 237205884511SPyun YongHyeon bus_dmamap_sync(rbd->rbd_ring->rr_dtag, rbd->rbd_ring->rr_dmap, 237305884511SPyun YongHyeon BUS_DMASYNC_PREWRITE); 237405884511SPyun YongHyeon } 237505884511SPyun YongHyeon 237605884511SPyun YongHyeon static int 237705884511SPyun YongHyeon et_newbuf_hdr(struct et_rxbuf_data *rbd, int buf_idx) 237805884511SPyun YongHyeon { 237905884511SPyun YongHyeon struct et_softc *sc; 238005884511SPyun YongHyeon struct et_rxdesc *desc; 238105884511SPyun YongHyeon struct et_rxbuf *rb; 238205884511SPyun YongHyeon struct mbuf *m; 238305884511SPyun YongHyeon bus_dma_segment_t segs[1]; 238405884511SPyun YongHyeon bus_dmamap_t dmap; 238505884511SPyun YongHyeon int nsegs; 238605884511SPyun YongHyeon 238705884511SPyun YongHyeon MPASS(buf_idx < ET_RX_NDESC); 2388c6499eccSGleb Smirnoff MGETHDR(m, M_NOWAIT, MT_DATA); 238905884511SPyun YongHyeon if (m == NULL) 239005884511SPyun YongHyeon return (ENOBUFS); 239105884511SPyun YongHyeon m->m_len = m->m_pkthdr.len = MHLEN; 239205884511SPyun YongHyeon m_adj(m, ETHER_ALIGN); 239305884511SPyun YongHyeon 239405884511SPyun YongHyeon sc = rbd->rbd_softc; 239505884511SPyun YongHyeon rb = &rbd->rbd_buf[buf_idx]; 239605884511SPyun YongHyeon 239705884511SPyun YongHyeon if (bus_dmamap_load_mbuf_sg(sc->sc_rx_mini_tag, sc->sc_rx_mini_sparemap, 239805884511SPyun YongHyeon m, segs, &nsegs, 0) != 0) { 239905884511SPyun YongHyeon m_freem(m); 240005884511SPyun YongHyeon return (ENOBUFS); 240105884511SPyun YongHyeon } 240205884511SPyun YongHyeon KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 240305884511SPyun YongHyeon 240405884511SPyun YongHyeon if (rb->rb_mbuf != NULL) { 240505884511SPyun YongHyeon bus_dmamap_sync(sc->sc_rx_mini_tag, rb->rb_dmap, 240605884511SPyun YongHyeon BUS_DMASYNC_POSTREAD); 240705884511SPyun YongHyeon bus_dmamap_unload(sc->sc_rx_mini_tag, rb->rb_dmap); 240805884511SPyun YongHyeon } 240905884511SPyun YongHyeon dmap = rb->rb_dmap; 241005884511SPyun YongHyeon rb->rb_dmap = sc->sc_rx_mini_sparemap; 241105884511SPyun YongHyeon sc->sc_rx_mini_sparemap = dmap; 241205884511SPyun YongHyeon bus_dmamap_sync(sc->sc_rx_mini_tag, rb->rb_dmap, BUS_DMASYNC_PREREAD); 241305884511SPyun YongHyeon 241405884511SPyun YongHyeon rb->rb_mbuf = m; 241505884511SPyun YongHyeon desc = &rbd->rbd_ring->rr_desc[buf_idx]; 241605884511SPyun YongHyeon desc->rd_addr_hi = htole32(ET_ADDR_HI(segs[0].ds_addr)); 241705884511SPyun YongHyeon desc->rd_addr_lo = htole32(ET_ADDR_LO(segs[0].ds_addr)); 241805884511SPyun YongHyeon desc->rd_ctrl = htole32(buf_idx & ET_RDCTRL_BUFIDX_MASK); 241905884511SPyun YongHyeon bus_dmamap_sync(rbd->rbd_ring->rr_dtag, rbd->rbd_ring->rr_dmap, 242005884511SPyun YongHyeon BUS_DMASYNC_PREWRITE); 242105884511SPyun YongHyeon return (0); 24224d52a575SXin LI } 24234d52a575SXin LI 2424e0b5ac02SPyun YongHyeon #define ET_SYSCTL_STAT_ADD32(c, h, n, p, d) \ 2425e0b5ac02SPyun YongHyeon SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d) 2426e0b5ac02SPyun YongHyeon #define ET_SYSCTL_STAT_ADD64(c, h, n, p, d) \ 2427e0b5ac02SPyun YongHyeon SYSCTL_ADD_UQUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d) 2428e0b5ac02SPyun YongHyeon 24294d52a575SXin LI /* 24304d52a575SXin LI * Create sysctl tree 24314d52a575SXin LI */ 24324d52a575SXin LI static void 24334d52a575SXin LI et_add_sysctls(struct et_softc * sc) 24344d52a575SXin LI { 24354d52a575SXin LI struct sysctl_ctx_list *ctx; 2436e0b5ac02SPyun YongHyeon struct sysctl_oid_list *children, *parent; 2437e0b5ac02SPyun YongHyeon struct sysctl_oid *tree; 2438e0b5ac02SPyun YongHyeon struct et_hw_stats *stats; 24394d52a575SXin LI 24404d52a575SXin LI ctx = device_get_sysctl_ctx(sc->dev); 24414d52a575SXin LI children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); 24424d52a575SXin LI 24434d52a575SXin LI SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_intr_npkts", 24447029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, 24457029da5cSPawel Biernacki et_sysctl_rx_intr_npkts, "I", "RX IM, # packets per RX interrupt"); 24464d52a575SXin LI SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_intr_delay", 24477029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, 24487029da5cSPawel Biernacki et_sysctl_rx_intr_delay, "I", 24494d52a575SXin LI "RX IM, RX interrupt delay (x10 usec)"); 24504d52a575SXin LI SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_intr_nsegs", 24514d52a575SXin LI CTLFLAG_RW, &sc->sc_tx_intr_nsegs, 0, 24524d52a575SXin LI "TX IM, # segments per TX interrupt"); 24534d52a575SXin LI SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "timer", 24544d52a575SXin LI CTLFLAG_RW, &sc->sc_timer, 0, "TX timer"); 2455e0b5ac02SPyun YongHyeon 24567029da5cSPawel Biernacki tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", 24577029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "ET statistics"); 2458e0b5ac02SPyun YongHyeon parent = SYSCTL_CHILDREN(tree); 2459e0b5ac02SPyun YongHyeon 2460e0b5ac02SPyun YongHyeon /* TX/RX statistics. */ 2461e0b5ac02SPyun YongHyeon stats = &sc->sc_stats; 2462e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_64", &stats->pkts_64, 2463e0b5ac02SPyun YongHyeon "0 to 64 bytes frames"); 2464e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_65_127", &stats->pkts_65, 2465e0b5ac02SPyun YongHyeon "65 to 127 bytes frames"); 2466e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_128_255", &stats->pkts_128, 2467e0b5ac02SPyun YongHyeon "128 to 255 bytes frames"); 2468e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_256_511", &stats->pkts_256, 2469e0b5ac02SPyun YongHyeon "256 to 511 bytes frames"); 2470e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_512_1023", &stats->pkts_512, 2471e0b5ac02SPyun YongHyeon "512 to 1023 bytes frames"); 2472e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_1024_1518", &stats->pkts_1024, 2473e0b5ac02SPyun YongHyeon "1024 to 1518 bytes frames"); 2474e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_1519_1522", &stats->pkts_1519, 2475e0b5ac02SPyun YongHyeon "1519 to 1522 bytes frames"); 2476e0b5ac02SPyun YongHyeon 2477e0b5ac02SPyun YongHyeon /* RX statistics. */ 24787029da5cSPawel Biernacki tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", 24797029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "RX MAC statistics"); 2480e0b5ac02SPyun YongHyeon children = SYSCTL_CHILDREN(tree); 2481e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD64(ctx, children, "bytes", 2482e0b5ac02SPyun YongHyeon &stats->rx_bytes, "Good bytes"); 2483e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD64(ctx, children, "frames", 2484e0b5ac02SPyun YongHyeon &stats->rx_frames, "Good frames"); 2485e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "crc_errs", 2486e0b5ac02SPyun YongHyeon &stats->rx_crcerrs, "CRC errors"); 2487e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD64(ctx, children, "mcast_frames", 2488e0b5ac02SPyun YongHyeon &stats->rx_mcast, "Multicast frames"); 2489e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD64(ctx, children, "bcast_frames", 2490e0b5ac02SPyun YongHyeon &stats->rx_bcast, "Broadcast frames"); 2491e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "control", 2492e0b5ac02SPyun YongHyeon &stats->rx_control, "Control frames"); 2493e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "pause", 2494e0b5ac02SPyun YongHyeon &stats->rx_pause, "Pause frames"); 2495e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "unknown_control", 2496e0b5ac02SPyun YongHyeon &stats->rx_unknown_control, "Unknown control frames"); 2497e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "align_errs", 2498e0b5ac02SPyun YongHyeon &stats->rx_alignerrs, "Alignment errors"); 2499e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "len_errs", 2500e0b5ac02SPyun YongHyeon &stats->rx_lenerrs, "Frames with length mismatched"); 2501e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "code_errs", 2502e0b5ac02SPyun YongHyeon &stats->rx_codeerrs, "Frames with code error"); 2503e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "cs_errs", 2504e0b5ac02SPyun YongHyeon &stats->rx_cserrs, "Frames with carrier sense error"); 2505e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "runts", 2506e0b5ac02SPyun YongHyeon &stats->rx_runts, "Too short frames"); 2507e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD64(ctx, children, "oversize", 2508e0b5ac02SPyun YongHyeon &stats->rx_oversize, "Oversized frames"); 2509e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "fragments", 2510e0b5ac02SPyun YongHyeon &stats->rx_fragments, "Fragmented frames"); 2511e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "jabbers", 2512e0b5ac02SPyun YongHyeon &stats->rx_jabbers, "Frames with jabber error"); 2513e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "drop", 2514e0b5ac02SPyun YongHyeon &stats->rx_drop, "Dropped frames"); 2515e0b5ac02SPyun YongHyeon 2516e0b5ac02SPyun YongHyeon /* TX statistics. */ 25177029da5cSPawel Biernacki tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", 25187029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "TX MAC statistics"); 2519e0b5ac02SPyun YongHyeon children = SYSCTL_CHILDREN(tree); 2520e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD64(ctx, children, "bytes", 2521e0b5ac02SPyun YongHyeon &stats->tx_bytes, "Good bytes"); 2522e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD64(ctx, children, "frames", 2523e0b5ac02SPyun YongHyeon &stats->tx_frames, "Good frames"); 2524e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD64(ctx, children, "mcast_frames", 2525e0b5ac02SPyun YongHyeon &stats->tx_mcast, "Multicast frames"); 2526e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD64(ctx, children, "bcast_frames", 2527e0b5ac02SPyun YongHyeon &stats->tx_bcast, "Broadcast frames"); 2528e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "pause", 2529e0b5ac02SPyun YongHyeon &stats->tx_pause, "Pause frames"); 2530e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "deferred", 2531e0b5ac02SPyun YongHyeon &stats->tx_deferred, "Deferred frames"); 2532e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "excess_deferred", 2533e0b5ac02SPyun YongHyeon &stats->tx_excess_deferred, "Excessively deferred frames"); 2534e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "single_colls", 2535e0b5ac02SPyun YongHyeon &stats->tx_single_colls, "Single collisions"); 2536e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "multi_colls", 2537e0b5ac02SPyun YongHyeon &stats->tx_multi_colls, "Multiple collisions"); 2538e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "late_colls", 2539e0b5ac02SPyun YongHyeon &stats->tx_late_colls, "Late collisions"); 2540e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "excess_colls", 2541e0b5ac02SPyun YongHyeon &stats->tx_excess_colls, "Excess collisions"); 2542e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "total_colls", 2543e0b5ac02SPyun YongHyeon &stats->tx_total_colls, "Total collisions"); 2544e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "pause_honored", 2545e0b5ac02SPyun YongHyeon &stats->tx_pause_honored, "Honored pause frames"); 2546e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "drop", 2547e0b5ac02SPyun YongHyeon &stats->tx_drop, "Dropped frames"); 2548e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "jabbers", 2549e0b5ac02SPyun YongHyeon &stats->tx_jabbers, "Frames with jabber errors"); 2550e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "crc_errs", 2551e0b5ac02SPyun YongHyeon &stats->tx_crcerrs, "Frames with CRC errors"); 2552e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "control", 2553e0b5ac02SPyun YongHyeon &stats->tx_control, "Control frames"); 2554e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD64(ctx, children, "oversize", 2555e0b5ac02SPyun YongHyeon &stats->tx_oversize, "Oversized frames"); 2556e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "undersize", 2557e0b5ac02SPyun YongHyeon &stats->tx_undersize, "Undersized frames"); 2558e0b5ac02SPyun YongHyeon ET_SYSCTL_STAT_ADD32(ctx, children, "fragments", 2559e0b5ac02SPyun YongHyeon &stats->tx_fragments, "Fragmented frames"); 25604d52a575SXin LI } 25614d52a575SXin LI 2562e0b5ac02SPyun YongHyeon #undef ET_SYSCTL_STAT_ADD32 2563e0b5ac02SPyun YongHyeon #undef ET_SYSCTL_STAT_ADD64 2564e0b5ac02SPyun YongHyeon 25654d52a575SXin LI static int 25664d52a575SXin LI et_sysctl_rx_intr_npkts(SYSCTL_HANDLER_ARGS) 25674d52a575SXin LI { 25680b699044SPyun YongHyeon struct et_softc *sc; 2569*7c509be1SJustin Hibbits if_t ifp; 25700b699044SPyun YongHyeon int error, v; 25714d52a575SXin LI 25720b699044SPyun YongHyeon sc = arg1; 25730b699044SPyun YongHyeon ifp = sc->ifp; 25744d52a575SXin LI v = sc->sc_rx_intr_npkts; 25754d52a575SXin LI error = sysctl_handle_int(oidp, &v, 0, req); 25764d52a575SXin LI if (error || req->newptr == NULL) 25774d52a575SXin LI goto back; 25784d52a575SXin LI if (v <= 0) { 25794d52a575SXin LI error = EINVAL; 25804d52a575SXin LI goto back; 25814d52a575SXin LI } 25824d52a575SXin LI 25834d52a575SXin LI if (sc->sc_rx_intr_npkts != v) { 2584*7c509be1SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 25854d52a575SXin LI CSR_WRITE_4(sc, ET_RX_INTR_NPKTS, v); 25864d52a575SXin LI sc->sc_rx_intr_npkts = v; 25874d52a575SXin LI } 25884d52a575SXin LI back: 2589398f1b65SPyun YongHyeon return (error); 25904d52a575SXin LI } 25914d52a575SXin LI 25924d52a575SXin LI static int 25934d52a575SXin LI et_sysctl_rx_intr_delay(SYSCTL_HANDLER_ARGS) 25944d52a575SXin LI { 25950b699044SPyun YongHyeon struct et_softc *sc; 2596*7c509be1SJustin Hibbits if_t ifp; 25970b699044SPyun YongHyeon int error, v; 25984d52a575SXin LI 25990b699044SPyun YongHyeon sc = arg1; 26000b699044SPyun YongHyeon ifp = sc->ifp; 26014d52a575SXin LI v = sc->sc_rx_intr_delay; 26024d52a575SXin LI error = sysctl_handle_int(oidp, &v, 0, req); 26034d52a575SXin LI if (error || req->newptr == NULL) 26044d52a575SXin LI goto back; 26054d52a575SXin LI if (v <= 0) { 26064d52a575SXin LI error = EINVAL; 26074d52a575SXin LI goto back; 26084d52a575SXin LI } 26094d52a575SXin LI 26104d52a575SXin LI if (sc->sc_rx_intr_delay != v) { 2611*7c509be1SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 26124d52a575SXin LI CSR_WRITE_4(sc, ET_RX_INTR_DELAY, v); 26134d52a575SXin LI sc->sc_rx_intr_delay = v; 26144d52a575SXin LI } 26154d52a575SXin LI back: 2616398f1b65SPyun YongHyeon return (error); 26174d52a575SXin LI } 26184d52a575SXin LI 2619e0b5ac02SPyun YongHyeon static void 2620e0b5ac02SPyun YongHyeon et_stats_update(struct et_softc *sc) 2621e0b5ac02SPyun YongHyeon { 2622e0b5ac02SPyun YongHyeon struct et_hw_stats *stats; 2623e0b5ac02SPyun YongHyeon 2624e0b5ac02SPyun YongHyeon stats = &sc->sc_stats; 2625e0b5ac02SPyun YongHyeon stats->pkts_64 += CSR_READ_4(sc, ET_STAT_PKTS_64); 2626e0b5ac02SPyun YongHyeon stats->pkts_65 += CSR_READ_4(sc, ET_STAT_PKTS_65_127); 2627e0b5ac02SPyun YongHyeon stats->pkts_128 += CSR_READ_4(sc, ET_STAT_PKTS_128_255); 2628e0b5ac02SPyun YongHyeon stats->pkts_256 += CSR_READ_4(sc, ET_STAT_PKTS_256_511); 2629e0b5ac02SPyun YongHyeon stats->pkts_512 += CSR_READ_4(sc, ET_STAT_PKTS_512_1023); 2630e0b5ac02SPyun YongHyeon stats->pkts_1024 += CSR_READ_4(sc, ET_STAT_PKTS_1024_1518); 2631e0b5ac02SPyun YongHyeon stats->pkts_1519 += CSR_READ_4(sc, ET_STAT_PKTS_1519_1522); 2632e0b5ac02SPyun YongHyeon 2633e0b5ac02SPyun YongHyeon stats->rx_bytes += CSR_READ_4(sc, ET_STAT_RX_BYTES); 2634e0b5ac02SPyun YongHyeon stats->rx_frames += CSR_READ_4(sc, ET_STAT_RX_FRAMES); 2635e0b5ac02SPyun YongHyeon stats->rx_crcerrs += CSR_READ_4(sc, ET_STAT_RX_CRC_ERR); 2636e0b5ac02SPyun YongHyeon stats->rx_mcast += CSR_READ_4(sc, ET_STAT_RX_MCAST); 2637e0b5ac02SPyun YongHyeon stats->rx_bcast += CSR_READ_4(sc, ET_STAT_RX_BCAST); 2638e0b5ac02SPyun YongHyeon stats->rx_control += CSR_READ_4(sc, ET_STAT_RX_CTL); 2639e0b5ac02SPyun YongHyeon stats->rx_pause += CSR_READ_4(sc, ET_STAT_RX_PAUSE); 2640e0b5ac02SPyun YongHyeon stats->rx_unknown_control += CSR_READ_4(sc, ET_STAT_RX_UNKNOWN_CTL); 2641e0b5ac02SPyun YongHyeon stats->rx_alignerrs += CSR_READ_4(sc, ET_STAT_RX_ALIGN_ERR); 2642e0b5ac02SPyun YongHyeon stats->rx_lenerrs += CSR_READ_4(sc, ET_STAT_RX_LEN_ERR); 2643e0b5ac02SPyun YongHyeon stats->rx_codeerrs += CSR_READ_4(sc, ET_STAT_RX_CODE_ERR); 2644e0b5ac02SPyun YongHyeon stats->rx_cserrs += CSR_READ_4(sc, ET_STAT_RX_CS_ERR); 2645e0b5ac02SPyun YongHyeon stats->rx_runts += CSR_READ_4(sc, ET_STAT_RX_RUNT); 2646e0b5ac02SPyun YongHyeon stats->rx_oversize += CSR_READ_4(sc, ET_STAT_RX_OVERSIZE); 2647e0b5ac02SPyun YongHyeon stats->rx_fragments += CSR_READ_4(sc, ET_STAT_RX_FRAG); 2648e0b5ac02SPyun YongHyeon stats->rx_jabbers += CSR_READ_4(sc, ET_STAT_RX_JABBER); 2649e0b5ac02SPyun YongHyeon stats->rx_drop += CSR_READ_4(sc, ET_STAT_RX_DROP); 2650e0b5ac02SPyun YongHyeon 2651e0b5ac02SPyun YongHyeon stats->tx_bytes += CSR_READ_4(sc, ET_STAT_TX_BYTES); 2652e0b5ac02SPyun YongHyeon stats->tx_frames += CSR_READ_4(sc, ET_STAT_TX_FRAMES); 2653e0b5ac02SPyun YongHyeon stats->tx_mcast += CSR_READ_4(sc, ET_STAT_TX_MCAST); 2654e0b5ac02SPyun YongHyeon stats->tx_bcast += CSR_READ_4(sc, ET_STAT_TX_BCAST); 2655e0b5ac02SPyun YongHyeon stats->tx_pause += CSR_READ_4(sc, ET_STAT_TX_PAUSE); 2656e0b5ac02SPyun YongHyeon stats->tx_deferred += CSR_READ_4(sc, ET_STAT_TX_DEFER); 2657e0b5ac02SPyun YongHyeon stats->tx_excess_deferred += CSR_READ_4(sc, ET_STAT_TX_EXCESS_DEFER); 2658e0b5ac02SPyun YongHyeon stats->tx_single_colls += CSR_READ_4(sc, ET_STAT_TX_SINGLE_COL); 2659e0b5ac02SPyun YongHyeon stats->tx_multi_colls += CSR_READ_4(sc, ET_STAT_TX_MULTI_COL); 2660e0b5ac02SPyun YongHyeon stats->tx_late_colls += CSR_READ_4(sc, ET_STAT_TX_LATE_COL); 2661e0b5ac02SPyun YongHyeon stats->tx_excess_colls += CSR_READ_4(sc, ET_STAT_TX_EXCESS_COL); 2662e0b5ac02SPyun YongHyeon stats->tx_total_colls += CSR_READ_4(sc, ET_STAT_TX_TOTAL_COL); 2663e0b5ac02SPyun YongHyeon stats->tx_pause_honored += CSR_READ_4(sc, ET_STAT_TX_PAUSE_HONOR); 2664e0b5ac02SPyun YongHyeon stats->tx_drop += CSR_READ_4(sc, ET_STAT_TX_DROP); 2665e0b5ac02SPyun YongHyeon stats->tx_jabbers += CSR_READ_4(sc, ET_STAT_TX_JABBER); 2666e0b5ac02SPyun YongHyeon stats->tx_crcerrs += CSR_READ_4(sc, ET_STAT_TX_CRC_ERR); 2667e0b5ac02SPyun YongHyeon stats->tx_control += CSR_READ_4(sc, ET_STAT_TX_CTL); 2668e0b5ac02SPyun YongHyeon stats->tx_oversize += CSR_READ_4(sc, ET_STAT_TX_OVERSIZE); 2669e0b5ac02SPyun YongHyeon stats->tx_undersize += CSR_READ_4(sc, ET_STAT_TX_UNDERSIZE); 2670e0b5ac02SPyun YongHyeon stats->tx_fragments += CSR_READ_4(sc, ET_STAT_TX_FRAG); 2671c13dc687SGleb Smirnoff } 2672e0b5ac02SPyun YongHyeon 2673c13dc687SGleb Smirnoff static uint64_t 2674*7c509be1SJustin Hibbits et_get_counter(if_t ifp, ift_counter cnt) 2675c13dc687SGleb Smirnoff { 2676c13dc687SGleb Smirnoff struct et_softc *sc; 2677c13dc687SGleb Smirnoff struct et_hw_stats *stats; 2678c13dc687SGleb Smirnoff 2679c13dc687SGleb Smirnoff sc = if_getsoftc(ifp); 2680c13dc687SGleb Smirnoff stats = &sc->sc_stats; 2681c13dc687SGleb Smirnoff 2682c13dc687SGleb Smirnoff switch (cnt) { 2683c13dc687SGleb Smirnoff case IFCOUNTER_OPACKETS: 2684c13dc687SGleb Smirnoff return (stats->tx_frames); 2685c13dc687SGleb Smirnoff case IFCOUNTER_COLLISIONS: 2686c13dc687SGleb Smirnoff return (stats->tx_total_colls); 2687c13dc687SGleb Smirnoff case IFCOUNTER_OERRORS: 2688c13dc687SGleb Smirnoff return (stats->tx_drop + stats->tx_jabbers + 2689e0b5ac02SPyun YongHyeon stats->tx_crcerrs + stats->tx_excess_deferred + 2690c13dc687SGleb Smirnoff stats->tx_late_colls); 2691c13dc687SGleb Smirnoff case IFCOUNTER_IPACKETS: 2692c13dc687SGleb Smirnoff return (stats->rx_frames); 2693c13dc687SGleb Smirnoff case IFCOUNTER_IERRORS: 2694c13dc687SGleb Smirnoff return (stats->rx_crcerrs + stats->rx_alignerrs + 2695e0b5ac02SPyun YongHyeon stats->rx_lenerrs + stats->rx_codeerrs + stats->rx_cserrs + 2696c13dc687SGleb Smirnoff stats->rx_runts + stats->rx_jabbers + stats->rx_drop); 2697c13dc687SGleb Smirnoff default: 2698c13dc687SGleb Smirnoff return (if_get_counter_default(ifp, cnt)); 2699c13dc687SGleb Smirnoff } 2700e0b5ac02SPyun YongHyeon } 2701e0b5ac02SPyun YongHyeon 27020442028aSPyun YongHyeon static int 27030442028aSPyun YongHyeon et_suspend(device_t dev) 27040442028aSPyun YongHyeon { 27050442028aSPyun YongHyeon struct et_softc *sc; 270638953bb0SPyun YongHyeon uint32_t pmcfg; 27070442028aSPyun YongHyeon 27080442028aSPyun YongHyeon sc = device_get_softc(dev); 27090442028aSPyun YongHyeon ET_LOCK(sc); 2710*7c509be1SJustin Hibbits if ((if_getdrvflags(sc->ifp) & IFF_DRV_RUNNING) != 0) 27110442028aSPyun YongHyeon et_stop(sc); 271238953bb0SPyun YongHyeon /* Diable all clocks and put PHY into COMA. */ 271338953bb0SPyun YongHyeon pmcfg = CSR_READ_4(sc, ET_PM); 271438953bb0SPyun YongHyeon pmcfg &= ~(EM_PM_GIGEPHY_ENB | ET_PM_SYSCLK_GATE | ET_PM_TXCLK_GATE | 271538953bb0SPyun YongHyeon ET_PM_RXCLK_GATE); 271638953bb0SPyun YongHyeon pmcfg |= ET_PM_PHY_SW_COMA; 271738953bb0SPyun YongHyeon CSR_WRITE_4(sc, ET_PM, pmcfg); 27180442028aSPyun YongHyeon ET_UNLOCK(sc); 27190442028aSPyun YongHyeon return (0); 27200442028aSPyun YongHyeon } 27210442028aSPyun YongHyeon 27220442028aSPyun YongHyeon static int 27230442028aSPyun YongHyeon et_resume(device_t dev) 27240442028aSPyun YongHyeon { 27250442028aSPyun YongHyeon struct et_softc *sc; 272638953bb0SPyun YongHyeon uint32_t pmcfg; 27270442028aSPyun YongHyeon 27280442028aSPyun YongHyeon sc = device_get_softc(dev); 27290442028aSPyun YongHyeon ET_LOCK(sc); 273038953bb0SPyun YongHyeon /* Take PHY out of COMA and enable clocks. */ 273138953bb0SPyun YongHyeon pmcfg = ET_PM_SYSCLK_GATE | ET_PM_TXCLK_GATE | ET_PM_RXCLK_GATE; 273238953bb0SPyun YongHyeon if ((sc->sc_flags & ET_FLAG_FASTETHER) == 0) 273338953bb0SPyun YongHyeon pmcfg |= EM_PM_GIGEPHY_ENB; 273438953bb0SPyun YongHyeon CSR_WRITE_4(sc, ET_PM, pmcfg); 2735*7c509be1SJustin Hibbits if ((if_getflags(sc->ifp) & IFF_UP) != 0) 27360442028aSPyun YongHyeon et_init_locked(sc); 27370442028aSPyun YongHyeon ET_UNLOCK(sc); 27380442028aSPyun YongHyeon return (0); 27390442028aSPyun YongHyeon } 2740