14d52a575SXin LI /*- 2e5fdd9deSXin LI * Copyright (c) 2007 Sepherosa Ziehau. All rights reserved. 34d52a575SXin LI * 44d52a575SXin LI * This code is derived from software contributed to The DragonFly Project 54d52a575SXin LI * by Sepherosa Ziehau <sepherosa@gmail.com> 64d52a575SXin LI * 74d52a575SXin LI * Redistribution and use in source and binary forms, with or without 84d52a575SXin LI * modification, are permitted provided that the following conditions 94d52a575SXin LI * are met: 104d52a575SXin LI * 114d52a575SXin LI * 1. Redistributions of source code must retain the above copyright 124d52a575SXin LI * notice, this list of conditions and the following disclaimer. 134d52a575SXin LI * 2. Redistributions in binary form must reproduce the above copyright 144d52a575SXin LI * notice, this list of conditions and the following disclaimer in 154d52a575SXin LI * the documentation and/or other materials provided with the 164d52a575SXin LI * distribution. 174d52a575SXin LI * 3. Neither the name of The DragonFly Project nor the names of its 184d52a575SXin LI * contributors may be used to endorse or promote products derived 194d52a575SXin LI * from this software without specific, prior written permission. 204d52a575SXin LI * 214d52a575SXin LI * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 224d52a575SXin LI * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 234d52a575SXin LI * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 244d52a575SXin LI * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 254d52a575SXin LI * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 264d52a575SXin LI * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 274d52a575SXin LI * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 284d52a575SXin LI * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 294d52a575SXin LI * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 304d52a575SXin LI * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 314d52a575SXin LI * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 324d52a575SXin LI * SUCH DAMAGE. 334d52a575SXin LI * 344d52a575SXin LI * $DragonFly: src/sys/dev/netif/et/if_et.c,v 1.10 2008/05/18 07:47:14 sephe Exp $ 354d52a575SXin LI */ 364d52a575SXin LI 37fe42b04dSPyun YongHyeon #include <sys/cdefs.h> 38fe42b04dSPyun YongHyeon __FBSDID("$FreeBSD$"); 39fe42b04dSPyun YongHyeon 404d52a575SXin LI #include <sys/param.h> 414d52a575SXin LI #include <sys/systm.h> 424d52a575SXin LI #include <sys/endian.h> 434d52a575SXin LI #include <sys/kernel.h> 444d52a575SXin LI #include <sys/bus.h> 454d52a575SXin LI #include <sys/malloc.h> 464d52a575SXin LI #include <sys/mbuf.h> 474d52a575SXin LI #include <sys/proc.h> 484d52a575SXin LI #include <sys/rman.h> 494d52a575SXin LI #include <sys/module.h> 504d52a575SXin LI #include <sys/socket.h> 514d52a575SXin LI #include <sys/sockio.h> 524d52a575SXin LI #include <sys/sysctl.h> 534d52a575SXin LI 544d52a575SXin LI #include <net/ethernet.h> 554d52a575SXin LI #include <net/if.h> 564d52a575SXin LI #include <net/if_dl.h> 574d52a575SXin LI #include <net/if_types.h> 584d52a575SXin LI #include <net/bpf.h> 594d52a575SXin LI #include <net/if_arp.h> 604d52a575SXin LI #include <net/if_media.h> 614d52a575SXin LI #include <net/if_vlan_var.h> 624d52a575SXin LI 634d52a575SXin LI #include <machine/bus.h> 644d52a575SXin LI 65d6c65d27SMarius Strobl #include <dev/mii/mii.h> 664d52a575SXin LI #include <dev/mii/miivar.h> 674d52a575SXin LI 684d52a575SXin LI #include <dev/pci/pcireg.h> 694d52a575SXin LI #include <dev/pci/pcivar.h> 704d52a575SXin LI 714d52a575SXin LI #include <dev/et/if_etreg.h> 724d52a575SXin LI #include <dev/et/if_etvar.h> 734d52a575SXin LI 744d52a575SXin LI #include "miibus_if.h" 754d52a575SXin LI 764d52a575SXin LI MODULE_DEPEND(et, pci, 1, 1, 1); 774d52a575SXin LI MODULE_DEPEND(et, ether, 1, 1, 1); 784d52a575SXin LI MODULE_DEPEND(et, miibus, 1, 1, 1); 794d52a575SXin LI 80cc3c3b4eSPyun YongHyeon /* Tunables. */ 81cc3c3b4eSPyun YongHyeon static int msi_disable = 0; 82accb4fcdSPyun YongHyeon TUNABLE_INT("hw.et.msi_disable", &msi_disable); 83cc3c3b4eSPyun YongHyeon 849955274cSPyun YongHyeon #define ET_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) 859955274cSPyun YongHyeon 864d52a575SXin LI static int et_probe(device_t); 874d52a575SXin LI static int et_attach(device_t); 884d52a575SXin LI static int et_detach(device_t); 894d52a575SXin LI static int et_shutdown(device_t); 900442028aSPyun YongHyeon static int et_suspend(device_t); 910442028aSPyun YongHyeon static int et_resume(device_t); 924d52a575SXin LI 934d52a575SXin LI static int et_miibus_readreg(device_t, int, int); 944d52a575SXin LI static int et_miibus_writereg(device_t, int, int, int); 954d52a575SXin LI static void et_miibus_statchg(device_t); 964d52a575SXin LI 974d52a575SXin LI static void et_init_locked(struct et_softc *); 984d52a575SXin LI static void et_init(void *); 994d52a575SXin LI static int et_ioctl(struct ifnet *, u_long, caddr_t); 1004d52a575SXin LI static void et_start_locked(struct ifnet *); 1014d52a575SXin LI static void et_start(struct ifnet *); 10205884511SPyun YongHyeon static int et_watchdog(struct et_softc *); 1034d52a575SXin LI static int et_ifmedia_upd_locked(struct ifnet *); 1044d52a575SXin LI static int et_ifmedia_upd(struct ifnet *); 1054d52a575SXin LI static void et_ifmedia_sts(struct ifnet *, struct ifmediareq *); 1064d52a575SXin LI 1074d52a575SXin LI static void et_add_sysctls(struct et_softc *); 1084d52a575SXin LI static int et_sysctl_rx_intr_npkts(SYSCTL_HANDLER_ARGS); 1094d52a575SXin LI static int et_sysctl_rx_intr_delay(SYSCTL_HANDLER_ARGS); 1104d52a575SXin LI 1114d52a575SXin LI static void et_intr(void *); 1124d52a575SXin LI static void et_rxeof(struct et_softc *); 1134d52a575SXin LI static void et_txeof(struct et_softc *); 1144d52a575SXin LI 11505884511SPyun YongHyeon static int et_dma_alloc(struct et_softc *); 11605884511SPyun YongHyeon static void et_dma_free(struct et_softc *); 11705884511SPyun YongHyeon static void et_dma_map_addr(void *, bus_dma_segment_t *, int, int); 11805884511SPyun YongHyeon static int et_dma_ring_alloc(struct et_softc *, bus_size_t, bus_size_t, 11905884511SPyun YongHyeon bus_dma_tag_t *, uint8_t **, bus_dmamap_t *, bus_addr_t *, 12005884511SPyun YongHyeon const char *); 12105884511SPyun YongHyeon static void et_dma_ring_free(struct et_softc *, bus_dma_tag_t *, uint8_t **, 12205884511SPyun YongHyeon bus_dmamap_t *); 12305884511SPyun YongHyeon static void et_init_tx_ring(struct et_softc *); 1244d52a575SXin LI static int et_init_rx_ring(struct et_softc *); 1254d52a575SXin LI static void et_free_tx_ring(struct et_softc *); 1264d52a575SXin LI static void et_free_rx_ring(struct et_softc *); 1274d52a575SXin LI static int et_encap(struct et_softc *, struct mbuf **); 12805884511SPyun YongHyeon static int et_newbuf_cluster(struct et_rxbuf_data *, int); 12905884511SPyun YongHyeon static int et_newbuf_hdr(struct et_rxbuf_data *, int); 13005884511SPyun YongHyeon static void et_rxbuf_discard(struct et_rxbuf_data *, int); 1314d52a575SXin LI 1324d52a575SXin LI static void et_stop(struct et_softc *); 1334d52a575SXin LI static int et_chip_init(struct et_softc *); 1344d52a575SXin LI static void et_chip_attach(struct et_softc *); 1354d52a575SXin LI static void et_init_mac(struct et_softc *); 1364d52a575SXin LI static void et_init_rxmac(struct et_softc *); 1374d52a575SXin LI static void et_init_txmac(struct et_softc *); 1384d52a575SXin LI static int et_init_rxdma(struct et_softc *); 1394d52a575SXin LI static int et_init_txdma(struct et_softc *); 1404d52a575SXin LI static int et_start_rxdma(struct et_softc *); 1414d52a575SXin LI static int et_start_txdma(struct et_softc *); 1424d52a575SXin LI static int et_stop_rxdma(struct et_softc *); 1434d52a575SXin LI static int et_stop_txdma(struct et_softc *); 1444d52a575SXin LI static int et_enable_txrx(struct et_softc *, int); 1454d52a575SXin LI static void et_reset(struct et_softc *); 1468b3c6496SPyun YongHyeon static int et_bus_config(struct et_softc *); 1474d52a575SXin LI static void et_get_eaddr(device_t, uint8_t[]); 1484d52a575SXin LI static void et_setmulti(struct et_softc *); 1494d52a575SXin LI static void et_tick(void *); 1504d52a575SXin LI static void et_setmedia(struct et_softc *); 1514d52a575SXin LI 1524d52a575SXin LI static const struct et_dev { 1534d52a575SXin LI uint16_t vid; 1544d52a575SXin LI uint16_t did; 1554d52a575SXin LI const char *desc; 1564d52a575SXin LI } et_devices[] = { 1574d52a575SXin LI { PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_ET1310, 1584d52a575SXin LI "Agere ET1310 Gigabit Ethernet" }, 1594d52a575SXin LI { PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_ET1310_FAST, 1604d52a575SXin LI "Agere ET1310 Fast Ethernet" }, 1614d52a575SXin LI { 0, 0, NULL } 1624d52a575SXin LI }; 1634d52a575SXin LI 1644d52a575SXin LI static device_method_t et_methods[] = { 1654d52a575SXin LI DEVMETHOD(device_probe, et_probe), 1664d52a575SXin LI DEVMETHOD(device_attach, et_attach), 1674d52a575SXin LI DEVMETHOD(device_detach, et_detach), 1684d52a575SXin LI DEVMETHOD(device_shutdown, et_shutdown), 1690442028aSPyun YongHyeon DEVMETHOD(device_suspend, et_suspend), 1700442028aSPyun YongHyeon DEVMETHOD(device_resume, et_resume), 1714d52a575SXin LI 1724d52a575SXin LI DEVMETHOD(miibus_readreg, et_miibus_readreg), 1734d52a575SXin LI DEVMETHOD(miibus_writereg, et_miibus_writereg), 1744d52a575SXin LI DEVMETHOD(miibus_statchg, et_miibus_statchg), 1754d52a575SXin LI 1764b7ec270SMarius Strobl DEVMETHOD_END 1774d52a575SXin LI }; 1784d52a575SXin LI 1794d52a575SXin LI static driver_t et_driver = { 1804d52a575SXin LI "et", 1814d52a575SXin LI et_methods, 1824d52a575SXin LI sizeof(struct et_softc) 1834d52a575SXin LI }; 1844d52a575SXin LI 1854d52a575SXin LI static devclass_t et_devclass; 1864d52a575SXin LI 1874d52a575SXin LI DRIVER_MODULE(et, pci, et_driver, et_devclass, 0, 0); 1884d52a575SXin LI DRIVER_MODULE(miibus, et, miibus_driver, miibus_devclass, 0, 0); 1894d52a575SXin LI 1904d52a575SXin LI static int et_rx_intr_npkts = 32; 1914d52a575SXin LI static int et_rx_intr_delay = 20; /* x10 usec */ 1924d52a575SXin LI static int et_tx_intr_nsegs = 126; 1934d52a575SXin LI static uint32_t et_timer = 1000 * 1000 * 1000; /* nanosec */ 1944d52a575SXin LI 1954d52a575SXin LI TUNABLE_INT("hw.et.timer", &et_timer); 1964d52a575SXin LI TUNABLE_INT("hw.et.rx_intr_npkts", &et_rx_intr_npkts); 1974d52a575SXin LI TUNABLE_INT("hw.et.rx_intr_delay", &et_rx_intr_delay); 1984d52a575SXin LI TUNABLE_INT("hw.et.tx_intr_nsegs", &et_tx_intr_nsegs); 1994d52a575SXin LI 2004d52a575SXin LI static int 2014d52a575SXin LI et_probe(device_t dev) 2024d52a575SXin LI { 2034d52a575SXin LI const struct et_dev *d; 2044d52a575SXin LI uint16_t did, vid; 2054d52a575SXin LI 2064d52a575SXin LI vid = pci_get_vendor(dev); 2074d52a575SXin LI did = pci_get_device(dev); 2084d52a575SXin LI 2094d52a575SXin LI for (d = et_devices; d->desc != NULL; ++d) { 2104d52a575SXin LI if (vid == d->vid && did == d->did) { 2114d52a575SXin LI device_set_desc(dev, d->desc); 212a64788d1SPyun YongHyeon return (BUS_PROBE_DEFAULT); 2134d52a575SXin LI } 2144d52a575SXin LI } 215398f1b65SPyun YongHyeon return (ENXIO); 2164d52a575SXin LI } 2174d52a575SXin LI 2184d52a575SXin LI static int 2194d52a575SXin LI et_attach(device_t dev) 2204d52a575SXin LI { 2214d52a575SXin LI struct et_softc *sc; 2224d52a575SXin LI struct ifnet *ifp; 2234d52a575SXin LI uint8_t eaddr[ETHER_ADDR_LEN]; 224cc3c3b4eSPyun YongHyeon int cap, error, msic; 2254d52a575SXin LI 2264d52a575SXin LI sc = device_get_softc(dev); 2274d52a575SXin LI sc->dev = dev; 2284d52a575SXin LI mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 2294d52a575SXin LI MTX_DEF); 230d2f7028cSPyun YongHyeon callout_init_mtx(&sc->sc_tick, &sc->sc_mtx, 0); 2314d52a575SXin LI 2324d52a575SXin LI ifp = sc->ifp = if_alloc(IFT_ETHER); 2334d52a575SXin LI if (ifp == NULL) { 2344d52a575SXin LI device_printf(dev, "can not if_alloc()\n"); 2354d52a575SXin LI error = ENOSPC; 2364d52a575SXin LI goto fail; 2374d52a575SXin LI } 2384d52a575SXin LI 2394d52a575SXin LI /* 2404d52a575SXin LI * Initialize tunables 2414d52a575SXin LI */ 2424d52a575SXin LI sc->sc_rx_intr_npkts = et_rx_intr_npkts; 2434d52a575SXin LI sc->sc_rx_intr_delay = et_rx_intr_delay; 2444d52a575SXin LI sc->sc_tx_intr_nsegs = et_tx_intr_nsegs; 2454d52a575SXin LI sc->sc_timer = et_timer; 2464d52a575SXin LI 2474d52a575SXin LI /* Enable bus mastering */ 2484d52a575SXin LI pci_enable_busmaster(dev); 2494d52a575SXin LI 2504d52a575SXin LI /* 2514d52a575SXin LI * Allocate IO memory 2524d52a575SXin LI */ 2534d52a575SXin LI sc->sc_mem_rid = ET_PCIR_BAR; 2544d52a575SXin LI sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 2554d52a575SXin LI &sc->sc_mem_rid, RF_ACTIVE); 2564d52a575SXin LI if (sc->sc_mem_res == NULL) { 2574d52a575SXin LI device_printf(dev, "can't allocate IO memory\n"); 258398f1b65SPyun YongHyeon return (ENXIO); 2594d52a575SXin LI } 2604d52a575SXin LI 261cc3c3b4eSPyun YongHyeon msic = 0; 2623b0a4aefSJohn Baldwin if (pci_find_cap(dev, PCIY_EXPRESS, &cap) == 0) { 263cc3c3b4eSPyun YongHyeon sc->sc_expcap = cap; 264cc3c3b4eSPyun YongHyeon sc->sc_flags |= ET_FLAG_PCIE; 265cc3c3b4eSPyun YongHyeon msic = pci_msi_count(dev); 266cc3c3b4eSPyun YongHyeon if (bootverbose) 267cc3c3b4eSPyun YongHyeon device_printf(dev, "MSI count: %d\n", msic); 268cc3c3b4eSPyun YongHyeon } 269cc3c3b4eSPyun YongHyeon if (msic > 0 && msi_disable == 0) { 270cc3c3b4eSPyun YongHyeon msic = 1; 271cc3c3b4eSPyun YongHyeon if (pci_alloc_msi(dev, &msic) == 0) { 272cc3c3b4eSPyun YongHyeon if (msic == 1) { 273cc3c3b4eSPyun YongHyeon device_printf(dev, "Using %d MSI message\n", 274cc3c3b4eSPyun YongHyeon msic); 275cc3c3b4eSPyun YongHyeon sc->sc_flags |= ET_FLAG_MSI; 276cc3c3b4eSPyun YongHyeon } else 277cc3c3b4eSPyun YongHyeon pci_release_msi(dev); 278cc3c3b4eSPyun YongHyeon } 279cc3c3b4eSPyun YongHyeon } 280cc3c3b4eSPyun YongHyeon 2814d52a575SXin LI /* 2824d52a575SXin LI * Allocate IRQ 2834d52a575SXin LI */ 284cc3c3b4eSPyun YongHyeon if ((sc->sc_flags & ET_FLAG_MSI) == 0) { 2854d52a575SXin LI sc->sc_irq_rid = 0; 2864d52a575SXin LI sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 287cc3c3b4eSPyun YongHyeon &sc->sc_irq_rid, RF_SHAREABLE | RF_ACTIVE); 288cc3c3b4eSPyun YongHyeon } else { 289cc3c3b4eSPyun YongHyeon sc->sc_irq_rid = 1; 290cc3c3b4eSPyun YongHyeon sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 291cc3c3b4eSPyun YongHyeon &sc->sc_irq_rid, RF_ACTIVE); 292cc3c3b4eSPyun YongHyeon } 2934d52a575SXin LI if (sc->sc_irq_res == NULL) { 2944d52a575SXin LI device_printf(dev, "can't allocate irq\n"); 2954d52a575SXin LI error = ENXIO; 2964d52a575SXin LI goto fail; 2974d52a575SXin LI } 2984d52a575SXin LI 2998b3c6496SPyun YongHyeon error = et_bus_config(sc); 3004d52a575SXin LI if (error) 3014d52a575SXin LI goto fail; 3024d52a575SXin LI 3034d52a575SXin LI et_get_eaddr(dev, eaddr); 3044d52a575SXin LI 3054d52a575SXin LI CSR_WRITE_4(sc, ET_PM, 3064d52a575SXin LI ET_PM_SYSCLK_GATE | ET_PM_TXCLK_GATE | ET_PM_RXCLK_GATE); 3074d52a575SXin LI 3084d52a575SXin LI et_reset(sc); 3094d52a575SXin LI 31005884511SPyun YongHyeon error = et_dma_alloc(sc); 3114d52a575SXin LI if (error) 3124d52a575SXin LI goto fail; 3134d52a575SXin LI 3144d52a575SXin LI ifp->if_softc = sc; 3154d52a575SXin LI if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 3164d52a575SXin LI ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 3174d52a575SXin LI ifp->if_init = et_init; 3184d52a575SXin LI ifp->if_ioctl = et_ioctl; 3194d52a575SXin LI ifp->if_start = et_start; 320ed848e3aSPyun YongHyeon ifp->if_capabilities = IFCAP_TXCSUM | IFCAP_VLAN_MTU; 3214d52a575SXin LI ifp->if_capenable = ifp->if_capabilities; 322c8b727ceSPyun YongHyeon ifp->if_snd.ifq_drv_maxlen = ET_TX_NDESC - 1; 323c8b727ceSPyun YongHyeon IFQ_SET_MAXLEN(&ifp->if_snd, ET_TX_NDESC - 1); 3244d52a575SXin LI IFQ_SET_READY(&ifp->if_snd); 3254d52a575SXin LI 3264d52a575SXin LI et_chip_attach(sc); 3274d52a575SXin LI 328d6c65d27SMarius Strobl error = mii_attach(dev, &sc->sc_miibus, ifp, et_ifmedia_upd, 329d6c65d27SMarius Strobl et_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); 3304d52a575SXin LI if (error) { 331d6c65d27SMarius Strobl device_printf(dev, "attaching PHYs failed\n"); 3324d52a575SXin LI goto fail; 3334d52a575SXin LI } 3344d52a575SXin LI 3354d52a575SXin LI ether_ifattach(ifp, eaddr); 336d2f7028cSPyun YongHyeon 337d2f7028cSPyun YongHyeon /* Tell the upper layer(s) we support long frames. */ 338d2f7028cSPyun YongHyeon ifp->if_hdrlen = sizeof(struct ether_vlan_header); 3394d52a575SXin LI 3404d52a575SXin LI error = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_NET | INTR_MPSAFE, 3414d52a575SXin LI NULL, et_intr, sc, &sc->sc_irq_handle); 3424d52a575SXin LI if (error) { 3434d52a575SXin LI ether_ifdetach(ifp); 3444d52a575SXin LI device_printf(dev, "can't setup intr\n"); 3454d52a575SXin LI goto fail; 3464d52a575SXin LI } 3474d52a575SXin LI 3484d52a575SXin LI et_add_sysctls(sc); 3494d52a575SXin LI 350398f1b65SPyun YongHyeon return (0); 3514d52a575SXin LI fail: 3524d52a575SXin LI et_detach(dev); 353398f1b65SPyun YongHyeon return (error); 3544d52a575SXin LI } 3554d52a575SXin LI 3564d52a575SXin LI static int 3574d52a575SXin LI et_detach(device_t dev) 3584d52a575SXin LI { 3594d52a575SXin LI struct et_softc *sc = device_get_softc(dev); 3604d52a575SXin LI 3614d52a575SXin LI if (device_is_attached(dev)) { 362a64788d1SPyun YongHyeon ether_ifdetach(sc->ifp); 3634d52a575SXin LI ET_LOCK(sc); 3644d52a575SXin LI et_stop(sc); 3654d52a575SXin LI ET_UNLOCK(sc); 366a64788d1SPyun YongHyeon callout_drain(&sc->sc_tick); 3674d52a575SXin LI } 3684d52a575SXin LI 3694d52a575SXin LI if (sc->sc_miibus != NULL) 3704d52a575SXin LI device_delete_child(dev, sc->sc_miibus); 3714d52a575SXin LI bus_generic_detach(dev); 3724d52a575SXin LI 373a64788d1SPyun YongHyeon if (sc->sc_irq_handle != NULL) 374a64788d1SPyun YongHyeon bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_handle); 375a64788d1SPyun YongHyeon if (sc->sc_irq_res != NULL) 376a64788d1SPyun YongHyeon bus_release_resource(dev, SYS_RES_IRQ, 377a64788d1SPyun YongHyeon rman_get_rid(sc->sc_irq_res), sc->sc_irq_res); 378cc3c3b4eSPyun YongHyeon if ((sc->sc_flags & ET_FLAG_MSI) != 0) 379cc3c3b4eSPyun YongHyeon pci_release_msi(dev); 380a64788d1SPyun YongHyeon if (sc->sc_mem_res != NULL) 381a64788d1SPyun YongHyeon bus_release_resource(dev, SYS_RES_MEMORY, 382a64788d1SPyun YongHyeon rman_get_rid(sc->sc_mem_res), sc->sc_mem_res); 3834d52a575SXin LI 3844d52a575SXin LI if (sc->ifp != NULL) 3854d52a575SXin LI if_free(sc->ifp); 3864d52a575SXin LI 38705884511SPyun YongHyeon et_dma_free(sc); 3885b8f4900SPyun YongHyeon 3895b8f4900SPyun YongHyeon mtx_destroy(&sc->sc_mtx); 3904d52a575SXin LI 391398f1b65SPyun YongHyeon return (0); 3924d52a575SXin LI } 3934d52a575SXin LI 3944d52a575SXin LI static int 3954d52a575SXin LI et_shutdown(device_t dev) 3964d52a575SXin LI { 3974d52a575SXin LI struct et_softc *sc = device_get_softc(dev); 3984d52a575SXin LI 3994d52a575SXin LI ET_LOCK(sc); 4004d52a575SXin LI et_stop(sc); 4014d52a575SXin LI ET_UNLOCK(sc); 402398f1b65SPyun YongHyeon return (0); 4034d52a575SXin LI } 4044d52a575SXin LI 4054d52a575SXin LI static int 4064d52a575SXin LI et_miibus_readreg(device_t dev, int phy, int reg) 4074d52a575SXin LI { 4084d52a575SXin LI struct et_softc *sc = device_get_softc(dev); 4094d52a575SXin LI uint32_t val; 4104d52a575SXin LI int i, ret; 4114d52a575SXin LI 4124d52a575SXin LI /* Stop any pending operations */ 4134d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CMD, 0); 4144d52a575SXin LI 41523263665SPyun YongHyeon val = (phy << ET_MII_ADDR_PHY_SHIFT) & ET_MII_ADDR_PHY_MASK; 41623263665SPyun YongHyeon val |= (reg << ET_MII_ADDR_REG_SHIFT) & ET_MII_ADDR_REG_MASK; 4174d52a575SXin LI CSR_WRITE_4(sc, ET_MII_ADDR, val); 4184d52a575SXin LI 4194d52a575SXin LI /* Start reading */ 4204d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CMD, ET_MII_CMD_READ); 4214d52a575SXin LI 4224d52a575SXin LI #define NRETRY 50 4234d52a575SXin LI 4244d52a575SXin LI for (i = 0; i < NRETRY; ++i) { 4254d52a575SXin LI val = CSR_READ_4(sc, ET_MII_IND); 4264d52a575SXin LI if ((val & (ET_MII_IND_BUSY | ET_MII_IND_INVALID)) == 0) 4274d52a575SXin LI break; 4284d52a575SXin LI DELAY(50); 4294d52a575SXin LI } 4304d52a575SXin LI if (i == NRETRY) { 4314d52a575SXin LI if_printf(sc->ifp, 4324d52a575SXin LI "read phy %d, reg %d timed out\n", phy, reg); 4334d52a575SXin LI ret = 0; 4344d52a575SXin LI goto back; 4354d52a575SXin LI } 4364d52a575SXin LI 4374d52a575SXin LI #undef NRETRY 4384d52a575SXin LI 4394d52a575SXin LI val = CSR_READ_4(sc, ET_MII_STAT); 44023263665SPyun YongHyeon ret = val & ET_MII_STAT_VALUE_MASK; 4414d52a575SXin LI 4424d52a575SXin LI back: 4434d52a575SXin LI /* Make sure that the current operation is stopped */ 4444d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CMD, 0); 445398f1b65SPyun YongHyeon return (ret); 4464d52a575SXin LI } 4474d52a575SXin LI 4484d52a575SXin LI static int 4494d52a575SXin LI et_miibus_writereg(device_t dev, int phy, int reg, int val0) 4504d52a575SXin LI { 4514d52a575SXin LI struct et_softc *sc = device_get_softc(dev); 4524d52a575SXin LI uint32_t val; 4534d52a575SXin LI int i; 4544d52a575SXin LI 4554d52a575SXin LI /* Stop any pending operations */ 4564d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CMD, 0); 4574d52a575SXin LI 45823263665SPyun YongHyeon val = (phy << ET_MII_ADDR_PHY_SHIFT) & ET_MII_ADDR_PHY_MASK; 45923263665SPyun YongHyeon val |= (reg << ET_MII_ADDR_REG_SHIFT) & ET_MII_ADDR_REG_MASK; 4604d52a575SXin LI CSR_WRITE_4(sc, ET_MII_ADDR, val); 4614d52a575SXin LI 4624d52a575SXin LI /* Start writing */ 46323263665SPyun YongHyeon CSR_WRITE_4(sc, ET_MII_CTRL, 46423263665SPyun YongHyeon (val0 << ET_MII_CTRL_VALUE_SHIFT) & ET_MII_CTRL_VALUE_MASK); 4654d52a575SXin LI 4664d52a575SXin LI #define NRETRY 100 4674d52a575SXin LI 4684d52a575SXin LI for (i = 0; i < NRETRY; ++i) { 4694d52a575SXin LI val = CSR_READ_4(sc, ET_MII_IND); 4704d52a575SXin LI if ((val & ET_MII_IND_BUSY) == 0) 4714d52a575SXin LI break; 4724d52a575SXin LI DELAY(50); 4734d52a575SXin LI } 4744d52a575SXin LI if (i == NRETRY) { 4754d52a575SXin LI if_printf(sc->ifp, 4764d52a575SXin LI "write phy %d, reg %d timed out\n", phy, reg); 4774d52a575SXin LI et_miibus_readreg(dev, phy, reg); 4784d52a575SXin LI } 4794d52a575SXin LI 4804d52a575SXin LI #undef NRETRY 4814d52a575SXin LI 4824d52a575SXin LI /* Make sure that the current operation is stopped */ 4834d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CMD, 0); 484398f1b65SPyun YongHyeon return (0); 4854d52a575SXin LI } 4864d52a575SXin LI 4874d52a575SXin LI static void 4884d52a575SXin LI et_miibus_statchg(device_t dev) 4894d52a575SXin LI { 4904d52a575SXin LI et_setmedia(device_get_softc(dev)); 4914d52a575SXin LI } 4924d52a575SXin LI 4934d52a575SXin LI static int 4944d52a575SXin LI et_ifmedia_upd_locked(struct ifnet *ifp) 4954d52a575SXin LI { 4964d52a575SXin LI struct et_softc *sc = ifp->if_softc; 4974d52a575SXin LI struct mii_data *mii = device_get_softc(sc->sc_miibus); 4984d52a575SXin LI struct mii_softc *miisc; 4994d52a575SXin LI 5004d52a575SXin LI LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 5013fcb7a53SMarius Strobl PHY_RESET(miisc); 50296570638SPyun YongHyeon return (mii_mediachg(mii)); 5034d52a575SXin LI } 5044d52a575SXin LI 5054d52a575SXin LI static int 5064d52a575SXin LI et_ifmedia_upd(struct ifnet *ifp) 5074d52a575SXin LI { 5084d52a575SXin LI struct et_softc *sc = ifp->if_softc; 5094d52a575SXin LI int res; 5104d52a575SXin LI 5114d52a575SXin LI ET_LOCK(sc); 5124d52a575SXin LI res = et_ifmedia_upd_locked(ifp); 5134d52a575SXin LI ET_UNLOCK(sc); 5144d52a575SXin LI 515398f1b65SPyun YongHyeon return (res); 5164d52a575SXin LI } 5174d52a575SXin LI 5184d52a575SXin LI static void 5194d52a575SXin LI et_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 5204d52a575SXin LI { 5214d52a575SXin LI struct et_softc *sc = ifp->if_softc; 5224d52a575SXin LI struct mii_data *mii = device_get_softc(sc->sc_miibus); 5234d52a575SXin LI 5240ae9f6a9SPyun YongHyeon ET_LOCK(sc); 5254d52a575SXin LI mii_pollstat(mii); 5264d52a575SXin LI ifmr->ifm_active = mii->mii_media_active; 5274d52a575SXin LI ifmr->ifm_status = mii->mii_media_status; 5280ae9f6a9SPyun YongHyeon ET_UNLOCK(sc); 5294d52a575SXin LI } 5304d52a575SXin LI 5314d52a575SXin LI static void 5324d52a575SXin LI et_stop(struct et_softc *sc) 5334d52a575SXin LI { 5344d52a575SXin LI struct ifnet *ifp = sc->ifp; 5354d52a575SXin LI 5364d52a575SXin LI ET_LOCK_ASSERT(sc); 5374d52a575SXin LI 5384d52a575SXin LI callout_stop(&sc->sc_tick); 539*6537ffa6SPyun YongHyeon /* Disable interrupts. */ 540*6537ffa6SPyun YongHyeon CSR_WRITE_4(sc, ET_INTR_MASK, 0xffffffff); 5414d52a575SXin LI 5424d52a575SXin LI et_stop_rxdma(sc); 5434d52a575SXin LI et_stop_txdma(sc); 5444d52a575SXin LI 5454d52a575SXin LI et_free_tx_ring(sc); 5464d52a575SXin LI et_free_rx_ring(sc); 5474d52a575SXin LI 5484d52a575SXin LI et_reset(sc); 5494d52a575SXin LI 5504d52a575SXin LI sc->sc_tx = 0; 5514d52a575SXin LI sc->sc_tx_intr = 0; 5524d52a575SXin LI sc->sc_flags &= ~ET_FLAG_TXRX_ENABLED; 5534d52a575SXin LI 5544d52a575SXin LI sc->watchdog_timer = 0; 5554d52a575SXin LI ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 5564d52a575SXin LI } 5574d52a575SXin LI 5584d52a575SXin LI static int 5598b3c6496SPyun YongHyeon et_bus_config(struct et_softc *sc) 5604d52a575SXin LI { 5614d52a575SXin LI uint32_t val, max_plsz; 5624d52a575SXin LI uint16_t ack_latency, replay_timer; 5634d52a575SXin LI 5644d52a575SXin LI /* 5654d52a575SXin LI * Test whether EEPROM is valid 5664d52a575SXin LI * NOTE: Read twice to get the correct value 5674d52a575SXin LI */ 5688b3c6496SPyun YongHyeon pci_read_config(sc->dev, ET_PCIR_EEPROM_STATUS, 1); 5698b3c6496SPyun YongHyeon val = pci_read_config(sc->dev, ET_PCIR_EEPROM_STATUS, 1); 5704d52a575SXin LI if (val & ET_PCIM_EEPROM_STATUS_ERROR) { 5718b3c6496SPyun YongHyeon device_printf(sc->dev, "EEPROM status error 0x%02x\n", val); 572398f1b65SPyun YongHyeon return (ENXIO); 5734d52a575SXin LI } 5744d52a575SXin LI 5754d52a575SXin LI /* TODO: LED */ 5764d52a575SXin LI 5778b3c6496SPyun YongHyeon if ((sc->sc_flags & ET_FLAG_PCIE) == 0) 5788b3c6496SPyun YongHyeon return (0); 5798b3c6496SPyun YongHyeon 5804d52a575SXin LI /* 5814d52a575SXin LI * Configure ACK latency and replay timer according to 5824d52a575SXin LI * max playload size 5834d52a575SXin LI */ 5848b3c6496SPyun YongHyeon val = pci_read_config(sc->dev, 5858b3c6496SPyun YongHyeon sc->sc_expcap + PCIR_EXPRESS_DEVICE_CAP, 4); 5868b3c6496SPyun YongHyeon max_plsz = val & PCIM_EXP_CAP_MAX_PAYLOAD; 5874d52a575SXin LI 5884d52a575SXin LI switch (max_plsz) { 5894d52a575SXin LI case ET_PCIV_DEVICE_CAPS_PLSZ_128: 5904d52a575SXin LI ack_latency = ET_PCIV_ACK_LATENCY_128; 5914d52a575SXin LI replay_timer = ET_PCIV_REPLAY_TIMER_128; 5924d52a575SXin LI break; 5934d52a575SXin LI 5944d52a575SXin LI case ET_PCIV_DEVICE_CAPS_PLSZ_256: 5954d52a575SXin LI ack_latency = ET_PCIV_ACK_LATENCY_256; 5964d52a575SXin LI replay_timer = ET_PCIV_REPLAY_TIMER_256; 5974d52a575SXin LI break; 5984d52a575SXin LI 5994d52a575SXin LI default: 6008b3c6496SPyun YongHyeon ack_latency = pci_read_config(sc->dev, ET_PCIR_ACK_LATENCY, 2); 6018b3c6496SPyun YongHyeon replay_timer = pci_read_config(sc->dev, 6028b3c6496SPyun YongHyeon ET_PCIR_REPLAY_TIMER, 2); 6038b3c6496SPyun YongHyeon device_printf(sc->dev, "ack latency %u, replay timer %u\n", 6044d52a575SXin LI ack_latency, replay_timer); 6054d52a575SXin LI break; 6064d52a575SXin LI } 6074d52a575SXin LI if (ack_latency != 0) { 6088b3c6496SPyun YongHyeon pci_write_config(sc->dev, ET_PCIR_ACK_LATENCY, ack_latency, 2); 6098b3c6496SPyun YongHyeon pci_write_config(sc->dev, ET_PCIR_REPLAY_TIMER, replay_timer, 6108b3c6496SPyun YongHyeon 2); 6114d52a575SXin LI } 6124d52a575SXin LI 6134d52a575SXin LI /* 6144d52a575SXin LI * Set L0s and L1 latency timer to 2us 6154d52a575SXin LI */ 6168b3c6496SPyun YongHyeon val = pci_read_config(sc->dev, ET_PCIR_L0S_L1_LATENCY, 4); 61723263665SPyun YongHyeon val &= ~(PCIM_LINK_CAP_L0S_EXIT | PCIM_LINK_CAP_L1_EXIT); 61823263665SPyun YongHyeon /* L0s exit latency : 2us */ 61923263665SPyun YongHyeon val |= 0x00005000; 62023263665SPyun YongHyeon /* L1 exit latency : 2us */ 62123263665SPyun YongHyeon val |= 0x00028000; 6228b3c6496SPyun YongHyeon pci_write_config(sc->dev, ET_PCIR_L0S_L1_LATENCY, val, 4); 6234d52a575SXin LI 6244d52a575SXin LI /* 6254d52a575SXin LI * Set max read request size to 2048 bytes 6264d52a575SXin LI */ 6278b3c6496SPyun YongHyeon val = pci_read_config(sc->dev, 6288b3c6496SPyun YongHyeon sc->sc_expcap + PCIR_EXPRESS_DEVICE_CTL, 2); 6298b3c6496SPyun YongHyeon val &= ~PCIM_EXP_CTL_MAX_READ_REQUEST; 6304d52a575SXin LI val |= ET_PCIV_DEVICE_CTRL_RRSZ_2K; 6318b3c6496SPyun YongHyeon pci_write_config(sc->dev, 6328b3c6496SPyun YongHyeon sc->sc_expcap + PCIR_EXPRESS_DEVICE_CTL, val, 2); 6334d52a575SXin LI 634398f1b65SPyun YongHyeon return (0); 6354d52a575SXin LI } 6364d52a575SXin LI 6374d52a575SXin LI static void 6384d52a575SXin LI et_get_eaddr(device_t dev, uint8_t eaddr[]) 6394d52a575SXin LI { 6404d52a575SXin LI uint32_t val; 6414d52a575SXin LI int i; 6424d52a575SXin LI 6434d52a575SXin LI val = pci_read_config(dev, ET_PCIR_MAC_ADDR0, 4); 6444d52a575SXin LI for (i = 0; i < 4; ++i) 6454d52a575SXin LI eaddr[i] = (val >> (8 * i)) & 0xff; 6464d52a575SXin LI 6474d52a575SXin LI val = pci_read_config(dev, ET_PCIR_MAC_ADDR1, 2); 6484d52a575SXin LI for (; i < ETHER_ADDR_LEN; ++i) 6494d52a575SXin LI eaddr[i] = (val >> (8 * (i - 4))) & 0xff; 6504d52a575SXin LI } 6514d52a575SXin LI 6524d52a575SXin LI static void 6534d52a575SXin LI et_reset(struct et_softc *sc) 6544d52a575SXin LI { 6554d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 6564d52a575SXin LI ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 6574d52a575SXin LI ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | 6584d52a575SXin LI ET_MAC_CFG1_SIM_RST | ET_MAC_CFG1_SOFT_RST); 6594d52a575SXin LI 6604d52a575SXin LI CSR_WRITE_4(sc, ET_SWRST, 6614d52a575SXin LI ET_SWRST_TXDMA | ET_SWRST_RXDMA | 6624d52a575SXin LI ET_SWRST_TXMAC | ET_SWRST_RXMAC | 6634d52a575SXin LI ET_SWRST_MAC | ET_SWRST_MAC_STAT | ET_SWRST_MMC); 6644d52a575SXin LI 6654d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 6664d52a575SXin LI ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 6674d52a575SXin LI ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC); 6684d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 0); 669*6537ffa6SPyun YongHyeon /* Disable interrupts. */ 6704d52a575SXin LI CSR_WRITE_4(sc, ET_INTR_MASK, 0xffffffff); 6714d52a575SXin LI } 6724d52a575SXin LI 67305884511SPyun YongHyeon struct et_dmamap_arg { 67405884511SPyun YongHyeon bus_addr_t et_busaddr; 67505884511SPyun YongHyeon }; 67605884511SPyun YongHyeon 67705884511SPyun YongHyeon static void 67805884511SPyun YongHyeon et_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 6794d52a575SXin LI { 68005884511SPyun YongHyeon struct et_dmamap_arg *ctx; 68105884511SPyun YongHyeon 68205884511SPyun YongHyeon if (error) 68305884511SPyun YongHyeon return; 68405884511SPyun YongHyeon 68505884511SPyun YongHyeon KASSERT(nseg == 1, ("%s: %d segments returned!", __func__, nseg)); 68605884511SPyun YongHyeon 68705884511SPyun YongHyeon ctx = arg; 68805884511SPyun YongHyeon ctx->et_busaddr = segs->ds_addr; 68905884511SPyun YongHyeon } 69005884511SPyun YongHyeon 69105884511SPyun YongHyeon static int 69205884511SPyun YongHyeon et_dma_ring_alloc(struct et_softc *sc, bus_size_t alignment, bus_size_t maxsize, 69305884511SPyun YongHyeon bus_dma_tag_t *tag, uint8_t **ring, bus_dmamap_t *map, bus_addr_t *paddr, 69405884511SPyun YongHyeon const char *msg) 69505884511SPyun YongHyeon { 69605884511SPyun YongHyeon struct et_dmamap_arg ctx; 69705884511SPyun YongHyeon int error; 69805884511SPyun YongHyeon 69905884511SPyun YongHyeon error = bus_dma_tag_create(sc->sc_dtag, alignment, 0, BUS_SPACE_MAXADDR, 70005884511SPyun YongHyeon BUS_SPACE_MAXADDR, NULL, NULL, maxsize, 1, maxsize, 0, NULL, NULL, 70105884511SPyun YongHyeon tag); 70205884511SPyun YongHyeon if (error != 0) { 70305884511SPyun YongHyeon device_printf(sc->dev, "could not create %s dma tag\n", msg); 70405884511SPyun YongHyeon return (error); 70505884511SPyun YongHyeon } 70605884511SPyun YongHyeon /* Allocate DMA'able memory for ring. */ 70705884511SPyun YongHyeon error = bus_dmamem_alloc(*tag, (void **)ring, 70805884511SPyun YongHyeon BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, map); 70905884511SPyun YongHyeon if (error != 0) { 71005884511SPyun YongHyeon device_printf(sc->dev, 71105884511SPyun YongHyeon "could not allocate DMA'able memory for %s\n", msg); 71205884511SPyun YongHyeon return (error); 71305884511SPyun YongHyeon } 71405884511SPyun YongHyeon /* Load the address of the ring. */ 71505884511SPyun YongHyeon ctx.et_busaddr = 0; 71605884511SPyun YongHyeon error = bus_dmamap_load(*tag, *map, *ring, maxsize, et_dma_map_addr, 71705884511SPyun YongHyeon &ctx, BUS_DMA_NOWAIT); 71805884511SPyun YongHyeon if (error != 0) { 71905884511SPyun YongHyeon device_printf(sc->dev, 72005884511SPyun YongHyeon "could not load DMA'able memory for %s\n", msg); 72105884511SPyun YongHyeon return (error); 72205884511SPyun YongHyeon } 72305884511SPyun YongHyeon *paddr = ctx.et_busaddr; 72405884511SPyun YongHyeon return (0); 72505884511SPyun YongHyeon } 72605884511SPyun YongHyeon 72705884511SPyun YongHyeon static void 72805884511SPyun YongHyeon et_dma_ring_free(struct et_softc *sc, bus_dma_tag_t *tag, uint8_t **ring, 72905884511SPyun YongHyeon bus_dmamap_t *map) 73005884511SPyun YongHyeon { 73105884511SPyun YongHyeon 73205884511SPyun YongHyeon if (*map != NULL) 73305884511SPyun YongHyeon bus_dmamap_unload(*tag, *map); 73405884511SPyun YongHyeon if (*map != NULL && *ring != NULL) { 73505884511SPyun YongHyeon bus_dmamem_free(*tag, *ring, *map); 73605884511SPyun YongHyeon *ring = NULL; 73705884511SPyun YongHyeon *map = NULL; 73805884511SPyun YongHyeon } 73905884511SPyun YongHyeon if (*tag) { 74005884511SPyun YongHyeon bus_dma_tag_destroy(*tag); 74105884511SPyun YongHyeon *tag = NULL; 74205884511SPyun YongHyeon } 74305884511SPyun YongHyeon } 74405884511SPyun YongHyeon 74505884511SPyun YongHyeon static int 74605884511SPyun YongHyeon et_dma_alloc(struct et_softc *sc) 74705884511SPyun YongHyeon { 74805884511SPyun YongHyeon struct et_txdesc_ring *tx_ring; 74905884511SPyun YongHyeon struct et_rxdesc_ring *rx_ring; 75005884511SPyun YongHyeon struct et_rxstat_ring *rxst_ring; 75105884511SPyun YongHyeon struct et_rxstatus_data *rxsd; 75205884511SPyun YongHyeon struct et_rxbuf_data *rbd; 75305884511SPyun YongHyeon struct et_txbuf_data *tbd; 75405884511SPyun YongHyeon struct et_txstatus_data *txsd; 7554d52a575SXin LI int i, error; 7564d52a575SXin LI 75705884511SPyun YongHyeon error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1, 0, 75805884511SPyun YongHyeon BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 75905884511SPyun YongHyeon BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL, 76005884511SPyun YongHyeon &sc->sc_dtag); 76105884511SPyun YongHyeon if (error != 0) { 76205884511SPyun YongHyeon device_printf(sc->dev, "could not allocate parent dma tag\n"); 763398f1b65SPyun YongHyeon return (error); 7644d52a575SXin LI } 7654d52a575SXin LI 76605884511SPyun YongHyeon /* TX ring. */ 76705884511SPyun YongHyeon tx_ring = &sc->sc_tx_ring; 76805884511SPyun YongHyeon error = et_dma_ring_alloc(sc, ET_RING_ALIGN, ET_TX_RING_SIZE, 76905884511SPyun YongHyeon &tx_ring->tr_dtag, (uint8_t **)&tx_ring->tr_desc, &tx_ring->tr_dmap, 77005884511SPyun YongHyeon &tx_ring->tr_paddr, "TX ring"); 7714d52a575SXin LI if (error) 772398f1b65SPyun YongHyeon return (error); 7734d52a575SXin LI 77405884511SPyun YongHyeon /* TX status block. */ 77505884511SPyun YongHyeon txsd = &sc->sc_tx_status; 77605884511SPyun YongHyeon error = et_dma_ring_alloc(sc, ET_STATUS_ALIGN, sizeof(uint32_t), 77705884511SPyun YongHyeon &txsd->txsd_dtag, (uint8_t **)&txsd->txsd_status, &txsd->txsd_dmap, 77805884511SPyun YongHyeon &txsd->txsd_paddr, "TX status block"); 77905884511SPyun YongHyeon if (error) 78005884511SPyun YongHyeon return (error); 7814d52a575SXin LI 78205884511SPyun YongHyeon /* RX ring 0, used as to recive small sized frames. */ 78305884511SPyun YongHyeon rx_ring = &sc->sc_rx_ring[0]; 78405884511SPyun YongHyeon error = et_dma_ring_alloc(sc, ET_RING_ALIGN, ET_RX_RING_SIZE, 78505884511SPyun YongHyeon &rx_ring->rr_dtag, (uint8_t **)&rx_ring->rr_desc, &rx_ring->rr_dmap, 78605884511SPyun YongHyeon &rx_ring->rr_paddr, "RX ring 0"); 78705884511SPyun YongHyeon rx_ring->rr_posreg = ET_RX_RING0_POS; 78805884511SPyun YongHyeon if (error) 78905884511SPyun YongHyeon return (error); 7904d52a575SXin LI 79105884511SPyun YongHyeon /* RX ring 1, used as to store normal sized frames. */ 79205884511SPyun YongHyeon rx_ring = &sc->sc_rx_ring[1]; 79305884511SPyun YongHyeon error = et_dma_ring_alloc(sc, ET_RING_ALIGN, ET_RX_RING_SIZE, 79405884511SPyun YongHyeon &rx_ring->rr_dtag, (uint8_t **)&rx_ring->rr_desc, &rx_ring->rr_dmap, 79505884511SPyun YongHyeon &rx_ring->rr_paddr, "RX ring 1"); 79605884511SPyun YongHyeon rx_ring->rr_posreg = ET_RX_RING1_POS; 79705884511SPyun YongHyeon if (error) 79805884511SPyun YongHyeon return (error); 7994d52a575SXin LI 80005884511SPyun YongHyeon /* RX stat ring. */ 80105884511SPyun YongHyeon rxst_ring = &sc->sc_rxstat_ring; 80205884511SPyun YongHyeon error = et_dma_ring_alloc(sc, ET_RING_ALIGN, ET_RXSTAT_RING_SIZE, 80305884511SPyun YongHyeon &rxst_ring->rsr_dtag, (uint8_t **)&rxst_ring->rsr_stat, 80405884511SPyun YongHyeon &rxst_ring->rsr_dmap, &rxst_ring->rsr_paddr, "RX stat ring"); 80505884511SPyun YongHyeon if (error) 80605884511SPyun YongHyeon return (error); 8074d52a575SXin LI 80805884511SPyun YongHyeon /* RX status block. */ 80905884511SPyun YongHyeon rxsd = &sc->sc_rx_status; 81005884511SPyun YongHyeon error = et_dma_ring_alloc(sc, ET_STATUS_ALIGN, 81105884511SPyun YongHyeon sizeof(struct et_rxstatus), &rxsd->rxsd_dtag, 81205884511SPyun YongHyeon (uint8_t **)&rxsd->rxsd_status, &rxsd->rxsd_dmap, 81305884511SPyun YongHyeon &rxsd->rxsd_paddr, "RX status block"); 81405884511SPyun YongHyeon if (error) 81505884511SPyun YongHyeon return (error); 8164d52a575SXin LI 81705884511SPyun YongHyeon /* Create parent DMA tag for mbufs. */ 81805884511SPyun YongHyeon error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1, 0, 81905884511SPyun YongHyeon BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 82005884511SPyun YongHyeon BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL, 82105884511SPyun YongHyeon &sc->sc_mbuf_dtag); 82205884511SPyun YongHyeon if (error != 0) { 82305884511SPyun YongHyeon device_printf(sc->dev, 82405884511SPyun YongHyeon "could not allocate parent dma tag for mbuf\n"); 825398f1b65SPyun YongHyeon return (error); 8264d52a575SXin LI } 8274d52a575SXin LI 82805884511SPyun YongHyeon /* Create DMA tag for mini RX mbufs to use RX ring 0. */ 82905884511SPyun YongHyeon error = bus_dma_tag_create(sc->sc_mbuf_dtag, 1, 0, 83005884511SPyun YongHyeon BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MHLEN, 1, 83105884511SPyun YongHyeon MHLEN, 0, NULL, NULL, &sc->sc_rx_mini_tag); 8324d52a575SXin LI if (error) { 83305884511SPyun YongHyeon device_printf(sc->dev, "could not create mini RX dma tag\n"); 834398f1b65SPyun YongHyeon return (error); 8354d52a575SXin LI } 8364d52a575SXin LI 83705884511SPyun YongHyeon /* Create DMA tag for standard RX mbufs to use RX ring 1. */ 83805884511SPyun YongHyeon error = bus_dma_tag_create(sc->sc_mbuf_dtag, 1, 0, 83905884511SPyun YongHyeon BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, 84005884511SPyun YongHyeon MCLBYTES, 0, NULL, NULL, &sc->sc_rx_tag); 8414d52a575SXin LI if (error) { 84205884511SPyun YongHyeon device_printf(sc->dev, "could not create RX dma tag\n"); 843398f1b65SPyun YongHyeon return (error); 8444d52a575SXin LI } 8454d52a575SXin LI 84605884511SPyun YongHyeon /* Create DMA tag for TX mbufs. */ 84705884511SPyun YongHyeon error = bus_dma_tag_create(sc->sc_mbuf_dtag, 1, 0, 84805884511SPyun YongHyeon BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 84905884511SPyun YongHyeon MCLBYTES * ET_NSEG_MAX, ET_NSEG_MAX, MCLBYTES, 0, NULL, NULL, 85005884511SPyun YongHyeon &sc->sc_tx_tag); 85105884511SPyun YongHyeon if (error) { 85205884511SPyun YongHyeon device_printf(sc->dev, "could not create TX dma tag\n"); 85305884511SPyun YongHyeon return (error); 85405884511SPyun YongHyeon } 85505884511SPyun YongHyeon 85605884511SPyun YongHyeon /* Initialize RX ring 0. */ 85705884511SPyun YongHyeon rbd = &sc->sc_rx_data[0]; 85805884511SPyun YongHyeon rbd->rbd_bufsize = ET_RXDMA_CTRL_RING0_128; 85905884511SPyun YongHyeon rbd->rbd_newbuf = et_newbuf_hdr; 86005884511SPyun YongHyeon rbd->rbd_discard = et_rxbuf_discard; 8614d52a575SXin LI rbd->rbd_softc = sc; 86205884511SPyun YongHyeon rbd->rbd_ring = &sc->sc_rx_ring[0]; 86305884511SPyun YongHyeon /* Create DMA maps for mini RX buffers, ring 0. */ 86405884511SPyun YongHyeon for (i = 0; i < ET_RX_NDESC; i++) { 86505884511SPyun YongHyeon error = bus_dmamap_create(sc->sc_rx_mini_tag, 0, 86605884511SPyun YongHyeon &rbd->rbd_buf[i].rb_dmap); 86705884511SPyun YongHyeon if (error) { 86805884511SPyun YongHyeon device_printf(sc->dev, 86905884511SPyun YongHyeon "could not create DMA map for mini RX mbufs\n"); 87005884511SPyun YongHyeon return (error); 87105884511SPyun YongHyeon } 8724d52a575SXin LI } 8734d52a575SXin LI 87405884511SPyun YongHyeon /* Create a spare DMA map for mini RX buffers, ring 0. */ 87505884511SPyun YongHyeon error = bus_dmamap_create(sc->sc_rx_mini_tag, 0, 87605884511SPyun YongHyeon &sc->sc_rx_mini_sparemap); 87705884511SPyun YongHyeon if (error) { 87805884511SPyun YongHyeon device_printf(sc->dev, 87905884511SPyun YongHyeon "could not create spare DMA map for mini RX mbuf\n"); 88005884511SPyun YongHyeon return (error); 88105884511SPyun YongHyeon } 88205884511SPyun YongHyeon 88305884511SPyun YongHyeon /* Initialize RX ring 1. */ 88405884511SPyun YongHyeon rbd = &sc->sc_rx_data[1]; 88505884511SPyun YongHyeon rbd->rbd_bufsize = ET_RXDMA_CTRL_RING1_2048; 88605884511SPyun YongHyeon rbd->rbd_newbuf = et_newbuf_cluster; 88705884511SPyun YongHyeon rbd->rbd_discard = et_rxbuf_discard; 88805884511SPyun YongHyeon rbd->rbd_softc = sc; 88905884511SPyun YongHyeon rbd->rbd_ring = &sc->sc_rx_ring[1]; 89005884511SPyun YongHyeon /* Create DMA maps for standard RX buffers, ring 1. */ 89105884511SPyun YongHyeon for (i = 0; i < ET_RX_NDESC; i++) { 89205884511SPyun YongHyeon error = bus_dmamap_create(sc->sc_rx_tag, 0, 89305884511SPyun YongHyeon &rbd->rbd_buf[i].rb_dmap); 89405884511SPyun YongHyeon if (error) { 89505884511SPyun YongHyeon device_printf(sc->dev, 89605884511SPyun YongHyeon "could not create DMA map for mini RX mbufs\n"); 89705884511SPyun YongHyeon return (error); 89805884511SPyun YongHyeon } 89905884511SPyun YongHyeon } 90005884511SPyun YongHyeon 90105884511SPyun YongHyeon /* Create a spare DMA map for standard RX buffers, ring 1. */ 90205884511SPyun YongHyeon error = bus_dmamap_create(sc->sc_rx_tag, 0, &sc->sc_rx_sparemap); 90305884511SPyun YongHyeon if (error) { 90405884511SPyun YongHyeon device_printf(sc->dev, 90505884511SPyun YongHyeon "could not create spare DMA map for RX mbuf\n"); 90605884511SPyun YongHyeon return (error); 90705884511SPyun YongHyeon } 90805884511SPyun YongHyeon 90905884511SPyun YongHyeon /* Create DMA maps for TX buffers. */ 91005884511SPyun YongHyeon tbd = &sc->sc_tx_data; 91105884511SPyun YongHyeon for (i = 0; i < ET_TX_NDESC; i++) { 91205884511SPyun YongHyeon error = bus_dmamap_create(sc->sc_tx_tag, 0, 9134d52a575SXin LI &tbd->tbd_buf[i].tb_dmap); 9144d52a575SXin LI if (error) { 91505884511SPyun YongHyeon device_printf(sc->dev, 91605884511SPyun YongHyeon "could not create DMA map for TX mbufs\n"); 917398f1b65SPyun YongHyeon return (error); 9184d52a575SXin LI } 9194d52a575SXin LI } 9204d52a575SXin LI 921398f1b65SPyun YongHyeon return (0); 9224d52a575SXin LI } 9234d52a575SXin LI 9244d52a575SXin LI static void 92505884511SPyun YongHyeon et_dma_free(struct et_softc *sc) 9264d52a575SXin LI { 92705884511SPyun YongHyeon struct et_txdesc_ring *tx_ring; 92805884511SPyun YongHyeon struct et_rxdesc_ring *rx_ring; 92905884511SPyun YongHyeon struct et_txstatus_data *txsd; 93005884511SPyun YongHyeon struct et_rxstat_ring *rxst_ring; 93105884511SPyun YongHyeon struct et_rxstatus_data *rxsd; 93205884511SPyun YongHyeon struct et_rxbuf_data *rbd; 93305884511SPyun YongHyeon struct et_txbuf_data *tbd; 9344d52a575SXin LI int i; 9354d52a575SXin LI 93605884511SPyun YongHyeon /* Destroy DMA maps for mini RX buffers, ring 0. */ 93705884511SPyun YongHyeon rbd = &sc->sc_rx_data[0]; 93805884511SPyun YongHyeon for (i = 0; i < ET_RX_NDESC; i++) { 93905884511SPyun YongHyeon if (rbd->rbd_buf[i].rb_dmap) { 94005884511SPyun YongHyeon bus_dmamap_destroy(sc->sc_rx_mini_tag, 94105884511SPyun YongHyeon rbd->rbd_buf[i].rb_dmap); 94205884511SPyun YongHyeon rbd->rbd_buf[i].rb_dmap = NULL; 9434d52a575SXin LI } 9444d52a575SXin LI } 94505884511SPyun YongHyeon if (sc->sc_rx_mini_sparemap) { 94605884511SPyun YongHyeon bus_dmamap_destroy(sc->sc_rx_mini_tag, sc->sc_rx_mini_sparemap); 94705884511SPyun YongHyeon sc->sc_rx_mini_sparemap = NULL; 94805884511SPyun YongHyeon } 94905884511SPyun YongHyeon if (sc->sc_rx_mini_tag) { 95005884511SPyun YongHyeon bus_dma_tag_destroy(sc->sc_rx_mini_tag); 95105884511SPyun YongHyeon sc->sc_rx_mini_tag = NULL; 9524d52a575SXin LI } 9534d52a575SXin LI 95405884511SPyun YongHyeon /* Destroy DMA maps for standard RX buffers, ring 1. */ 95505884511SPyun YongHyeon rbd = &sc->sc_rx_data[1]; 95605884511SPyun YongHyeon for (i = 0; i < ET_RX_NDESC; i++) { 95705884511SPyun YongHyeon if (rbd->rbd_buf[i].rb_dmap) { 95805884511SPyun YongHyeon bus_dmamap_destroy(sc->sc_rx_tag, 95905884511SPyun YongHyeon rbd->rbd_buf[i].rb_dmap); 96005884511SPyun YongHyeon rbd->rbd_buf[i].rb_dmap = NULL; 9614d52a575SXin LI } 9624d52a575SXin LI } 96305884511SPyun YongHyeon if (sc->sc_rx_sparemap) { 96405884511SPyun YongHyeon bus_dmamap_destroy(sc->sc_rx_tag, sc->sc_rx_sparemap); 96505884511SPyun YongHyeon sc->sc_rx_sparemap = NULL; 96605884511SPyun YongHyeon } 96705884511SPyun YongHyeon if (sc->sc_rx_tag) { 96805884511SPyun YongHyeon bus_dma_tag_destroy(sc->sc_rx_tag); 96905884511SPyun YongHyeon sc->sc_rx_tag = NULL; 97005884511SPyun YongHyeon } 9714d52a575SXin LI 97205884511SPyun YongHyeon /* Destroy DMA maps for TX buffers. */ 97305884511SPyun YongHyeon tbd = &sc->sc_tx_data; 97405884511SPyun YongHyeon for (i = 0; i < ET_TX_NDESC; i++) { 97505884511SPyun YongHyeon if (tbd->tbd_buf[i].tb_dmap) { 97605884511SPyun YongHyeon bus_dmamap_destroy(sc->sc_tx_tag, 97705884511SPyun YongHyeon tbd->tbd_buf[i].tb_dmap); 97805884511SPyun YongHyeon tbd->tbd_buf[i].tb_dmap = NULL; 97905884511SPyun YongHyeon } 98005884511SPyun YongHyeon } 98105884511SPyun YongHyeon if (sc->sc_tx_tag) { 98205884511SPyun YongHyeon bus_dma_tag_destroy(sc->sc_tx_tag); 98305884511SPyun YongHyeon sc->sc_tx_tag = NULL; 98405884511SPyun YongHyeon } 98505884511SPyun YongHyeon 98605884511SPyun YongHyeon /* Destroy mini RX ring, ring 0. */ 98705884511SPyun YongHyeon rx_ring = &sc->sc_rx_ring[0]; 98805884511SPyun YongHyeon et_dma_ring_free(sc, &rx_ring->rr_dtag, (void *)&rx_ring->rr_desc, 98905884511SPyun YongHyeon &rx_ring->rr_dmap); 99005884511SPyun YongHyeon /* Destroy standard RX ring, ring 1. */ 99105884511SPyun YongHyeon rx_ring = &sc->sc_rx_ring[1]; 99205884511SPyun YongHyeon et_dma_ring_free(sc, &rx_ring->rr_dtag, (void *)&rx_ring->rr_desc, 99305884511SPyun YongHyeon &rx_ring->rr_dmap); 99405884511SPyun YongHyeon /* Destroy RX stat ring. */ 99505884511SPyun YongHyeon rxst_ring = &sc->sc_rxstat_ring; 99605884511SPyun YongHyeon et_dma_ring_free(sc, &rxst_ring->rsr_dtag, (void *)&rxst_ring->rsr_stat, 99705884511SPyun YongHyeon &rxst_ring->rsr_dmap); 99805884511SPyun YongHyeon /* Destroy RX status block. */ 99905884511SPyun YongHyeon rxsd = &sc->sc_rx_status; 100005884511SPyun YongHyeon et_dma_ring_free(sc, &rxst_ring->rsr_dtag, (void *)&rxst_ring->rsr_stat, 100105884511SPyun YongHyeon &rxst_ring->rsr_dmap); 100205884511SPyun YongHyeon /* Destroy TX ring. */ 100305884511SPyun YongHyeon tx_ring = &sc->sc_tx_ring; 100405884511SPyun YongHyeon et_dma_ring_free(sc, &tx_ring->tr_dtag, (void *)&tx_ring->tr_desc, 100505884511SPyun YongHyeon &tx_ring->tr_dmap); 100605884511SPyun YongHyeon /* Destroy TX status block. */ 100705884511SPyun YongHyeon txsd = &sc->sc_tx_status; 100805884511SPyun YongHyeon et_dma_ring_free(sc, &txsd->txsd_dtag, (void *)&txsd->txsd_status, 100905884511SPyun YongHyeon &txsd->txsd_dmap); 101005884511SPyun YongHyeon 101105884511SPyun YongHyeon /* Destroy the parent tag. */ 101205884511SPyun YongHyeon if (sc->sc_dtag) { 101305884511SPyun YongHyeon bus_dma_tag_destroy(sc->sc_dtag); 101405884511SPyun YongHyeon sc->sc_dtag = NULL; 101505884511SPyun YongHyeon } 10164d52a575SXin LI } 10174d52a575SXin LI 10184d52a575SXin LI static void 10194d52a575SXin LI et_chip_attach(struct et_softc *sc) 10204d52a575SXin LI { 10214d52a575SXin LI uint32_t val; 10224d52a575SXin LI 10234d52a575SXin LI /* 10244d52a575SXin LI * Perform minimal initialization 10254d52a575SXin LI */ 10264d52a575SXin LI 10274d52a575SXin LI /* Disable loopback */ 10284d52a575SXin LI CSR_WRITE_4(sc, ET_LOOPBACK, 0); 10294d52a575SXin LI 10304d52a575SXin LI /* Reset MAC */ 10314d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 10324d52a575SXin LI ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 10334d52a575SXin LI ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | 10344d52a575SXin LI ET_MAC_CFG1_SIM_RST | ET_MAC_CFG1_SOFT_RST); 10354d52a575SXin LI 10364d52a575SXin LI /* 10374d52a575SXin LI * Setup half duplex mode 10384d52a575SXin LI */ 103923263665SPyun YongHyeon val = (10 << ET_MAC_HDX_ALT_BEB_TRUNC_SHIFT) | 104023263665SPyun YongHyeon (15 << ET_MAC_HDX_REXMIT_MAX_SHIFT) | 104123263665SPyun YongHyeon (55 << ET_MAC_HDX_COLLWIN_SHIFT) | 10424d52a575SXin LI ET_MAC_HDX_EXC_DEFER; 10434d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_HDX, val); 10444d52a575SXin LI 10454d52a575SXin LI /* Clear MAC control */ 10464d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CTRL, 0); 10474d52a575SXin LI 10484d52a575SXin LI /* Reset MII */ 10494d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CFG, ET_MII_CFG_CLKRST); 10504d52a575SXin LI 10514d52a575SXin LI /* Bring MAC out of reset state */ 10524d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 0); 10534d52a575SXin LI 10544d52a575SXin LI /* Enable memory controllers */ 10554d52a575SXin LI CSR_WRITE_4(sc, ET_MMC_CTRL, ET_MMC_CTRL_ENABLE); 10564d52a575SXin LI } 10574d52a575SXin LI 10584d52a575SXin LI static void 10594d52a575SXin LI et_intr(void *xsc) 10604d52a575SXin LI { 10614d52a575SXin LI struct et_softc *sc = xsc; 10624d52a575SXin LI struct ifnet *ifp; 10634d52a575SXin LI uint32_t intrs; 10644d52a575SXin LI 10654d52a575SXin LI ET_LOCK(sc); 10664d52a575SXin LI ifp = sc->ifp; 10674d52a575SXin LI if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 10684d52a575SXin LI ET_UNLOCK(sc); 10694d52a575SXin LI return; 10704d52a575SXin LI } 10714d52a575SXin LI 1072*6537ffa6SPyun YongHyeon /* Disable further interrupts. */ 1073*6537ffa6SPyun YongHyeon CSR_WRITE_4(sc, ET_INTR_MASK, 0xffffffff); 10744d52a575SXin LI 10754d52a575SXin LI intrs = CSR_READ_4(sc, ET_INTR_STATUS); 1076*6537ffa6SPyun YongHyeon if ((intrs & ET_INTRS) == 0) 1077*6537ffa6SPyun YongHyeon goto done; 10784d52a575SXin LI 10794d52a575SXin LI if (intrs & ET_INTR_RXEOF) 10804d52a575SXin LI et_rxeof(sc); 10814d52a575SXin LI if (intrs & (ET_INTR_TXEOF | ET_INTR_TIMER)) 10824d52a575SXin LI et_txeof(sc); 10834d52a575SXin LI if (intrs & ET_INTR_TIMER) 10844d52a575SXin LI CSR_WRITE_4(sc, ET_TIMER, sc->sc_timer); 1085*6537ffa6SPyun YongHyeon done: 1086244fd28bSPyun YongHyeon if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1087*6537ffa6SPyun YongHyeon CSR_WRITE_4(sc, ET_INTR_MASK, ~ET_INTRS); 1088244fd28bSPyun YongHyeon if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1089244fd28bSPyun YongHyeon et_start_locked(ifp); 1090244fd28bSPyun YongHyeon } 10914d52a575SXin LI ET_UNLOCK(sc); 10924d52a575SXin LI } 10934d52a575SXin LI 10944d52a575SXin LI static void 10954d52a575SXin LI et_init_locked(struct et_softc *sc) 10964d52a575SXin LI { 109705884511SPyun YongHyeon struct ifnet *ifp; 109805884511SPyun YongHyeon int error; 10994d52a575SXin LI 11004d52a575SXin LI ET_LOCK_ASSERT(sc); 11014d52a575SXin LI 110205884511SPyun YongHyeon ifp = sc->ifp; 11034d52a575SXin LI if (ifp->if_drv_flags & IFF_DRV_RUNNING) 11044d52a575SXin LI return; 11054d52a575SXin LI 11064d52a575SXin LI et_stop(sc); 11074d52a575SXin LI 110805884511SPyun YongHyeon et_init_tx_ring(sc); 11094d52a575SXin LI error = et_init_rx_ring(sc); 11104d52a575SXin LI if (error) 111105884511SPyun YongHyeon return; 11124d52a575SXin LI 11134d52a575SXin LI error = et_chip_init(sc); 11144d52a575SXin LI if (error) 11154d52a575SXin LI goto back; 11164d52a575SXin LI 11174d52a575SXin LI error = et_enable_txrx(sc, 1); 11184d52a575SXin LI if (error) 11194d52a575SXin LI goto back; 11204d52a575SXin LI 1121*6537ffa6SPyun YongHyeon /* Enable interrupts. */ 1122*6537ffa6SPyun YongHyeon CSR_WRITE_4(sc, ET_INTR_MASK, ~ET_INTRS); 11234d52a575SXin LI 11244d52a575SXin LI callout_reset(&sc->sc_tick, hz, et_tick, sc); 11254d52a575SXin LI 11264d52a575SXin LI CSR_WRITE_4(sc, ET_TIMER, sc->sc_timer); 11274d52a575SXin LI 11284d52a575SXin LI ifp->if_drv_flags |= IFF_DRV_RUNNING; 11294d52a575SXin LI ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 11304d52a575SXin LI back: 11314d52a575SXin LI if (error) 11324d52a575SXin LI et_stop(sc); 11334d52a575SXin LI } 11344d52a575SXin LI 11354d52a575SXin LI static void 11364d52a575SXin LI et_init(void *xsc) 11374d52a575SXin LI { 11384d52a575SXin LI struct et_softc *sc = xsc; 11394d52a575SXin LI 11404d52a575SXin LI ET_LOCK(sc); 11414d52a575SXin LI et_init_locked(sc); 11424d52a575SXin LI ET_UNLOCK(sc); 11434d52a575SXin LI } 11444d52a575SXin LI 11454d52a575SXin LI static int 11464d52a575SXin LI et_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 11474d52a575SXin LI { 11484d52a575SXin LI struct et_softc *sc = ifp->if_softc; 11494d52a575SXin LI struct mii_data *mii = device_get_softc(sc->sc_miibus); 11504d52a575SXin LI struct ifreq *ifr = (struct ifreq *)data; 11519955274cSPyun YongHyeon int error = 0, mask, max_framelen; 11524d52a575SXin LI 11534d52a575SXin LI /* XXX LOCKSUSED */ 11544d52a575SXin LI switch (cmd) { 11554d52a575SXin LI case SIOCSIFFLAGS: 11564d52a575SXin LI ET_LOCK(sc); 11574d52a575SXin LI if (ifp->if_flags & IFF_UP) { 11584d52a575SXin LI if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 11594d52a575SXin LI if ((ifp->if_flags ^ sc->sc_if_flags) & 11604d52a575SXin LI (IFF_ALLMULTI | IFF_PROMISC | IFF_BROADCAST)) 11614d52a575SXin LI et_setmulti(sc); 11624d52a575SXin LI } else { 11634d52a575SXin LI et_init_locked(sc); 11644d52a575SXin LI } 11654d52a575SXin LI } else { 11664d52a575SXin LI if (ifp->if_drv_flags & IFF_DRV_RUNNING) 11674d52a575SXin LI et_stop(sc); 11684d52a575SXin LI } 11694d52a575SXin LI sc->sc_if_flags = ifp->if_flags; 11704d52a575SXin LI ET_UNLOCK(sc); 11714d52a575SXin LI break; 11724d52a575SXin LI 11734d52a575SXin LI case SIOCSIFMEDIA: 11744d52a575SXin LI case SIOCGIFMEDIA: 11754d52a575SXin LI error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 11764d52a575SXin LI break; 11774d52a575SXin LI 11784d52a575SXin LI case SIOCADDMULTI: 11794d52a575SXin LI case SIOCDELMULTI: 11804d52a575SXin LI if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 11814d52a575SXin LI ET_LOCK(sc); 11824d52a575SXin LI et_setmulti(sc); 11834d52a575SXin LI ET_UNLOCK(sc); 11844d52a575SXin LI error = 0; 11854d52a575SXin LI } 11864d52a575SXin LI break; 11874d52a575SXin LI 11884d52a575SXin LI case SIOCSIFMTU: 11894d52a575SXin LI #if 0 11904d52a575SXin LI if (sc->sc_flags & ET_FLAG_JUMBO) 11914d52a575SXin LI max_framelen = ET_JUMBO_FRAMELEN; 11924d52a575SXin LI else 11934d52a575SXin LI #endif 11944d52a575SXin LI max_framelen = MCLBYTES - 1; 11954d52a575SXin LI 11964d52a575SXin LI if (ET_FRAMELEN(ifr->ifr_mtu) > max_framelen) { 11974d52a575SXin LI error = EOPNOTSUPP; 11984d52a575SXin LI break; 11994d52a575SXin LI } 12004d52a575SXin LI 12014d52a575SXin LI if (ifp->if_mtu != ifr->ifr_mtu) { 12024d52a575SXin LI ifp->if_mtu = ifr->ifr_mtu; 12034d52a575SXin LI ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 12044d52a575SXin LI et_init(sc); 12054d52a575SXin LI } 12064d52a575SXin LI break; 12074d52a575SXin LI 12089955274cSPyun YongHyeon case SIOCSIFCAP: 12099955274cSPyun YongHyeon ET_LOCK(sc); 12109955274cSPyun YongHyeon mask = ifr->ifr_reqcap ^ ifp->if_capenable; 12119955274cSPyun YongHyeon if ((mask & IFCAP_TXCSUM) != 0 && 12129955274cSPyun YongHyeon (IFCAP_TXCSUM & ifp->if_capabilities) != 0) { 12139955274cSPyun YongHyeon ifp->if_capenable ^= IFCAP_TXCSUM; 12149955274cSPyun YongHyeon if ((IFCAP_TXCSUM & ifp->if_capenable) != 0) 12159955274cSPyun YongHyeon ifp->if_hwassist |= ET_CSUM_FEATURES; 12169955274cSPyun YongHyeon else 12179955274cSPyun YongHyeon ifp->if_hwassist &= ~ET_CSUM_FEATURES; 12189955274cSPyun YongHyeon } 12199955274cSPyun YongHyeon ET_UNLOCK(sc); 12209955274cSPyun YongHyeon break; 12219955274cSPyun YongHyeon 12224d52a575SXin LI default: 12234d52a575SXin LI error = ether_ioctl(ifp, cmd, data); 12244d52a575SXin LI break; 12254d52a575SXin LI } 1226398f1b65SPyun YongHyeon return (error); 12274d52a575SXin LI } 12284d52a575SXin LI 12294d52a575SXin LI static void 12304d52a575SXin LI et_start_locked(struct ifnet *ifp) 12314d52a575SXin LI { 1232c8b727ceSPyun YongHyeon struct et_softc *sc; 1233c8b727ceSPyun YongHyeon struct mbuf *m_head = NULL; 1234244fd28bSPyun YongHyeon struct et_txdesc_ring *tx_ring; 12354d52a575SXin LI struct et_txbuf_data *tbd; 1236244fd28bSPyun YongHyeon uint32_t tx_ready_pos; 1237c8b727ceSPyun YongHyeon int enq; 12384d52a575SXin LI 1239c8b727ceSPyun YongHyeon sc = ifp->if_softc; 12404d52a575SXin LI ET_LOCK_ASSERT(sc); 12414d52a575SXin LI 12424d52a575SXin LI if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0) 12434d52a575SXin LI return; 12444d52a575SXin LI 12454d52a575SXin LI if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING) 12464d52a575SXin LI return; 12474d52a575SXin LI 1248244fd28bSPyun YongHyeon /* 1249244fd28bSPyun YongHyeon * Driver does not request TX completion interrupt for every 1250244fd28bSPyun YongHyeon * queued frames to prevent generating excessive interrupts. 1251244fd28bSPyun YongHyeon * This means driver may wait for TX completion interrupt even 1252244fd28bSPyun YongHyeon * though some frames were sucessfully transmitted. Reclaiming 1253244fd28bSPyun YongHyeon * transmitted frames will ensure driver see all available 1254244fd28bSPyun YongHyeon * descriptors. 1255244fd28bSPyun YongHyeon */ 1256c8b727ceSPyun YongHyeon tbd = &sc->sc_tx_data; 1257244fd28bSPyun YongHyeon if (tbd->tbd_used > (ET_TX_NDESC * 2) / 3) 1258244fd28bSPyun YongHyeon et_txeof(sc); 1259244fd28bSPyun YongHyeon 1260c8b727ceSPyun YongHyeon for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd); ) { 1261c8b727ceSPyun YongHyeon if (tbd->tbd_used + ET_NSEG_SPARE >= ET_TX_NDESC) { 12624d52a575SXin LI ifp->if_drv_flags |= IFF_DRV_OACTIVE; 12634d52a575SXin LI break; 12644d52a575SXin LI } 12654d52a575SXin LI 1266c8b727ceSPyun YongHyeon IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 1267c8b727ceSPyun YongHyeon if (m_head == NULL) 12684d52a575SXin LI break; 12694d52a575SXin LI 1270c8b727ceSPyun YongHyeon if (et_encap(sc, &m_head)) { 1271c8b727ceSPyun YongHyeon if (m_head == NULL) { 12724d52a575SXin LI ifp->if_oerrors++; 1273c8b727ceSPyun YongHyeon break; 1274c8b727ceSPyun YongHyeon } 1275c8b727ceSPyun YongHyeon IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1276c8b727ceSPyun YongHyeon if (tbd->tbd_used > 0) 12774d52a575SXin LI ifp->if_drv_flags |= IFF_DRV_OACTIVE; 12784d52a575SXin LI break; 12794d52a575SXin LI } 1280c8b727ceSPyun YongHyeon enq++; 1281c8b727ceSPyun YongHyeon ETHER_BPF_MTAP(ifp, m_head); 12824d52a575SXin LI } 12834d52a575SXin LI 1284244fd28bSPyun YongHyeon if (enq > 0) { 1285244fd28bSPyun YongHyeon tx_ring = &sc->sc_tx_ring; 1286244fd28bSPyun YongHyeon bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap, 1287244fd28bSPyun YongHyeon BUS_DMASYNC_PREWRITE); 1288244fd28bSPyun YongHyeon tx_ready_pos = tx_ring->tr_ready_index & 1289244fd28bSPyun YongHyeon ET_TX_READY_POS_INDEX_MASK; 1290244fd28bSPyun YongHyeon if (tx_ring->tr_ready_wrap) 1291244fd28bSPyun YongHyeon tx_ready_pos |= ET_TX_READY_POS_WRAP; 1292244fd28bSPyun YongHyeon CSR_WRITE_4(sc, ET_TX_READY_POS, tx_ready_pos); 12934d52a575SXin LI sc->watchdog_timer = 5; 12944d52a575SXin LI } 1295244fd28bSPyun YongHyeon } 12964d52a575SXin LI 12974d52a575SXin LI static void 12984d52a575SXin LI et_start(struct ifnet *ifp) 12994d52a575SXin LI { 13004d52a575SXin LI struct et_softc *sc = ifp->if_softc; 13014d52a575SXin LI 13024d52a575SXin LI ET_LOCK(sc); 13034d52a575SXin LI et_start_locked(ifp); 13044d52a575SXin LI ET_UNLOCK(sc); 13054d52a575SXin LI } 13064d52a575SXin LI 130705884511SPyun YongHyeon static int 13084d52a575SXin LI et_watchdog(struct et_softc *sc) 13094d52a575SXin LI { 131005884511SPyun YongHyeon uint32_t status; 131105884511SPyun YongHyeon 13124d52a575SXin LI ET_LOCK_ASSERT(sc); 13134d52a575SXin LI 13144d52a575SXin LI if (sc->watchdog_timer == 0 || --sc->watchdog_timer) 131505884511SPyun YongHyeon return (0); 13164d52a575SXin LI 131705884511SPyun YongHyeon bus_dmamap_sync(sc->sc_tx_status.txsd_dtag, sc->sc_tx_status.txsd_dmap, 131805884511SPyun YongHyeon BUS_DMASYNC_POSTREAD); 131905884511SPyun YongHyeon status = le32toh(*(sc->sc_tx_status.txsd_status)); 132005884511SPyun YongHyeon if_printf(sc->ifp, "watchdog timed out (0x%08x) -- resetting\n", 132105884511SPyun YongHyeon status); 13224d52a575SXin LI 1323744ec7f2SPyun YongHyeon sc->ifp->if_oerrors++; 1324744ec7f2SPyun YongHyeon sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 13254d52a575SXin LI et_init_locked(sc); 132605884511SPyun YongHyeon return (EJUSTRETURN); 13274d52a575SXin LI } 13284d52a575SXin LI 13294d52a575SXin LI static int 13304d52a575SXin LI et_stop_rxdma(struct et_softc *sc) 13314d52a575SXin LI { 13324d52a575SXin LI CSR_WRITE_4(sc, ET_RXDMA_CTRL, 13334d52a575SXin LI ET_RXDMA_CTRL_HALT | ET_RXDMA_CTRL_RING1_ENABLE); 13344d52a575SXin LI 13354d52a575SXin LI DELAY(5); 13364d52a575SXin LI if ((CSR_READ_4(sc, ET_RXDMA_CTRL) & ET_RXDMA_CTRL_HALTED) == 0) { 13374d52a575SXin LI if_printf(sc->ifp, "can't stop RX DMA engine\n"); 1338398f1b65SPyun YongHyeon return (ETIMEDOUT); 13394d52a575SXin LI } 1340398f1b65SPyun YongHyeon return (0); 13414d52a575SXin LI } 13424d52a575SXin LI 13434d52a575SXin LI static int 13444d52a575SXin LI et_stop_txdma(struct et_softc *sc) 13454d52a575SXin LI { 13464d52a575SXin LI CSR_WRITE_4(sc, ET_TXDMA_CTRL, 13474d52a575SXin LI ET_TXDMA_CTRL_HALT | ET_TXDMA_CTRL_SINGLE_EPKT); 1348398f1b65SPyun YongHyeon return (0); 13494d52a575SXin LI } 13504d52a575SXin LI 13514d52a575SXin LI static void 13524d52a575SXin LI et_free_tx_ring(struct et_softc *sc) 13534d52a575SXin LI { 135405884511SPyun YongHyeon struct et_txdesc_ring *tx_ring; 135505884511SPyun YongHyeon struct et_txbuf_data *tbd; 135605884511SPyun YongHyeon struct et_txbuf *tb; 13574d52a575SXin LI int i; 13584d52a575SXin LI 135905884511SPyun YongHyeon tbd = &sc->sc_tx_data; 136005884511SPyun YongHyeon tx_ring = &sc->sc_tx_ring; 13614d52a575SXin LI for (i = 0; i < ET_TX_NDESC; ++i) { 136205884511SPyun YongHyeon tb = &tbd->tbd_buf[i]; 13634d52a575SXin LI if (tb->tb_mbuf != NULL) { 136405884511SPyun YongHyeon bus_dmamap_sync(sc->sc_tx_tag, tb->tb_dmap, 136505884511SPyun YongHyeon BUS_DMASYNC_POSTWRITE); 13664d52a575SXin LI bus_dmamap_unload(sc->sc_mbuf_dtag, tb->tb_dmap); 13674d52a575SXin LI m_freem(tb->tb_mbuf); 13684d52a575SXin LI tb->tb_mbuf = NULL; 13694d52a575SXin LI } 13704d52a575SXin LI } 13714d52a575SXin LI } 13724d52a575SXin LI 13734d52a575SXin LI static void 13744d52a575SXin LI et_free_rx_ring(struct et_softc *sc) 13754d52a575SXin LI { 137605884511SPyun YongHyeon struct et_rxbuf_data *rbd; 137705884511SPyun YongHyeon struct et_rxdesc_ring *rx_ring; 137805884511SPyun YongHyeon struct et_rxbuf *rb; 13794d52a575SXin LI int i; 13804d52a575SXin LI 138105884511SPyun YongHyeon /* Ring 0 */ 138205884511SPyun YongHyeon rx_ring = &sc->sc_rx_ring[0]; 138305884511SPyun YongHyeon rbd = &sc->sc_rx_data[0]; 13844d52a575SXin LI for (i = 0; i < ET_RX_NDESC; ++i) { 138505884511SPyun YongHyeon rb = &rbd->rbd_buf[i]; 13864d52a575SXin LI if (rb->rb_mbuf != NULL) { 138705884511SPyun YongHyeon bus_dmamap_sync(sc->sc_rx_mini_tag, rx_ring->rr_dmap, 138805884511SPyun YongHyeon BUS_DMASYNC_POSTREAD); 138905884511SPyun YongHyeon bus_dmamap_unload(sc->sc_rx_mini_tag, rb->rb_dmap); 13904d52a575SXin LI m_freem(rb->rb_mbuf); 13914d52a575SXin LI rb->rb_mbuf = NULL; 13924d52a575SXin LI } 13934d52a575SXin LI } 13944d52a575SXin LI 139505884511SPyun YongHyeon /* Ring 1 */ 139605884511SPyun YongHyeon rx_ring = &sc->sc_rx_ring[1]; 139705884511SPyun YongHyeon rbd = &sc->sc_rx_data[1]; 139805884511SPyun YongHyeon for (i = 0; i < ET_RX_NDESC; ++i) { 139905884511SPyun YongHyeon rb = &rbd->rbd_buf[i]; 140005884511SPyun YongHyeon if (rb->rb_mbuf != NULL) { 140105884511SPyun YongHyeon bus_dmamap_sync(sc->sc_rx_tag, rx_ring->rr_dmap, 140205884511SPyun YongHyeon BUS_DMASYNC_POSTREAD); 140305884511SPyun YongHyeon bus_dmamap_unload(sc->sc_rx_tag, rb->rb_dmap); 140405884511SPyun YongHyeon m_freem(rb->rb_mbuf); 140505884511SPyun YongHyeon rb->rb_mbuf = NULL; 140605884511SPyun YongHyeon } 14074d52a575SXin LI } 14084d52a575SXin LI } 14094d52a575SXin LI 14104d52a575SXin LI static void 14114d52a575SXin LI et_setmulti(struct et_softc *sc) 14124d52a575SXin LI { 14134d52a575SXin LI struct ifnet *ifp; 14144d52a575SXin LI uint32_t hash[4] = { 0, 0, 0, 0 }; 14154d52a575SXin LI uint32_t rxmac_ctrl, pktfilt; 14164d52a575SXin LI struct ifmultiaddr *ifma; 14174d52a575SXin LI int i, count; 14184d52a575SXin LI 14194d52a575SXin LI ET_LOCK_ASSERT(sc); 14204d52a575SXin LI ifp = sc->ifp; 14214d52a575SXin LI 14224d52a575SXin LI pktfilt = CSR_READ_4(sc, ET_PKTFILT); 14234d52a575SXin LI rxmac_ctrl = CSR_READ_4(sc, ET_RXMAC_CTRL); 14244d52a575SXin LI 14254d52a575SXin LI pktfilt &= ~(ET_PKTFILT_BCAST | ET_PKTFILT_MCAST | ET_PKTFILT_UCAST); 14264d52a575SXin LI if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) { 14274d52a575SXin LI rxmac_ctrl |= ET_RXMAC_CTRL_NO_PKTFILT; 14284d52a575SXin LI goto back; 14294d52a575SXin LI } 14304d52a575SXin LI 14314d52a575SXin LI count = 0; 1432eb956cd0SRobert Watson if_maddr_rlock(ifp); 14334d52a575SXin LI TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 14344d52a575SXin LI uint32_t *hp, h; 14354d52a575SXin LI 14364d52a575SXin LI if (ifma->ifma_addr->sa_family != AF_LINK) 14374d52a575SXin LI continue; 14384d52a575SXin LI 14394d52a575SXin LI h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 14404d52a575SXin LI ifma->ifma_addr), ETHER_ADDR_LEN); 14414d52a575SXin LI h = (h & 0x3f800000) >> 23; 14424d52a575SXin LI 14434d52a575SXin LI hp = &hash[0]; 14444d52a575SXin LI if (h >= 32 && h < 64) { 14454d52a575SXin LI h -= 32; 14464d52a575SXin LI hp = &hash[1]; 14474d52a575SXin LI } else if (h >= 64 && h < 96) { 14484d52a575SXin LI h -= 64; 14494d52a575SXin LI hp = &hash[2]; 14504d52a575SXin LI } else if (h >= 96) { 14514d52a575SXin LI h -= 96; 14524d52a575SXin LI hp = &hash[3]; 14534d52a575SXin LI } 14544d52a575SXin LI *hp |= (1 << h); 14554d52a575SXin LI 14564d52a575SXin LI ++count; 14574d52a575SXin LI } 1458eb956cd0SRobert Watson if_maddr_runlock(ifp); 14594d52a575SXin LI 14604d52a575SXin LI for (i = 0; i < 4; ++i) 14614d52a575SXin LI CSR_WRITE_4(sc, ET_MULTI_HASH + (i * 4), hash[i]); 14624d52a575SXin LI 14634d52a575SXin LI if (count > 0) 14644d52a575SXin LI pktfilt |= ET_PKTFILT_MCAST; 14654d52a575SXin LI rxmac_ctrl &= ~ET_RXMAC_CTRL_NO_PKTFILT; 14664d52a575SXin LI back: 14674d52a575SXin LI CSR_WRITE_4(sc, ET_PKTFILT, pktfilt); 14684d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_CTRL, rxmac_ctrl); 14694d52a575SXin LI } 14704d52a575SXin LI 14714d52a575SXin LI static int 14724d52a575SXin LI et_chip_init(struct et_softc *sc) 14734d52a575SXin LI { 14744d52a575SXin LI struct ifnet *ifp = sc->ifp; 14754d52a575SXin LI uint32_t rxq_end; 14764d52a575SXin LI int error, frame_len, rxmem_size; 14774d52a575SXin LI 14784d52a575SXin LI /* 14794d52a575SXin LI * Split 16Kbytes internal memory between TX and RX 14804d52a575SXin LI * according to frame length. 14814d52a575SXin LI */ 14824d52a575SXin LI frame_len = ET_FRAMELEN(ifp->if_mtu); 14834d52a575SXin LI if (frame_len < 2048) { 14844d52a575SXin LI rxmem_size = ET_MEM_RXSIZE_DEFAULT; 14854d52a575SXin LI } else if (frame_len <= ET_RXMAC_CUT_THRU_FRMLEN) { 14864d52a575SXin LI rxmem_size = ET_MEM_SIZE / 2; 14874d52a575SXin LI } else { 14884d52a575SXin LI rxmem_size = ET_MEM_SIZE - 14894d52a575SXin LI roundup(frame_len + ET_MEM_TXSIZE_EX, ET_MEM_UNIT); 14904d52a575SXin LI } 14914d52a575SXin LI rxq_end = ET_QUEUE_ADDR(rxmem_size); 14924d52a575SXin LI 14934d52a575SXin LI CSR_WRITE_4(sc, ET_RXQUEUE_START, ET_QUEUE_ADDR_START); 14944d52a575SXin LI CSR_WRITE_4(sc, ET_RXQUEUE_END, rxq_end); 14954d52a575SXin LI CSR_WRITE_4(sc, ET_TXQUEUE_START, rxq_end + 1); 14964d52a575SXin LI CSR_WRITE_4(sc, ET_TXQUEUE_END, ET_QUEUE_ADDR_END); 14974d52a575SXin LI 14984d52a575SXin LI /* No loopback */ 14994d52a575SXin LI CSR_WRITE_4(sc, ET_LOOPBACK, 0); 15004d52a575SXin LI 15014d52a575SXin LI /* Clear MSI configure */ 1502cc3c3b4eSPyun YongHyeon if ((sc->sc_flags & ET_FLAG_MSI) == 0) 15034d52a575SXin LI CSR_WRITE_4(sc, ET_MSI_CFG, 0); 15044d52a575SXin LI 15054d52a575SXin LI /* Disable timer */ 15064d52a575SXin LI CSR_WRITE_4(sc, ET_TIMER, 0); 15074d52a575SXin LI 15084d52a575SXin LI /* Initialize MAC */ 15094d52a575SXin LI et_init_mac(sc); 15104d52a575SXin LI 15114d52a575SXin LI /* Enable memory controllers */ 15124d52a575SXin LI CSR_WRITE_4(sc, ET_MMC_CTRL, ET_MMC_CTRL_ENABLE); 15134d52a575SXin LI 15144d52a575SXin LI /* Initialize RX MAC */ 15154d52a575SXin LI et_init_rxmac(sc); 15164d52a575SXin LI 15174d52a575SXin LI /* Initialize TX MAC */ 15184d52a575SXin LI et_init_txmac(sc); 15194d52a575SXin LI 15204d52a575SXin LI /* Initialize RX DMA engine */ 15214d52a575SXin LI error = et_init_rxdma(sc); 15224d52a575SXin LI if (error) 1523398f1b65SPyun YongHyeon return (error); 15244d52a575SXin LI 15254d52a575SXin LI /* Initialize TX DMA engine */ 15264d52a575SXin LI error = et_init_txdma(sc); 15274d52a575SXin LI if (error) 1528398f1b65SPyun YongHyeon return (error); 15294d52a575SXin LI 1530398f1b65SPyun YongHyeon return (0); 15314d52a575SXin LI } 15324d52a575SXin LI 153305884511SPyun YongHyeon static void 15344d52a575SXin LI et_init_tx_ring(struct et_softc *sc) 15354d52a575SXin LI { 153605884511SPyun YongHyeon struct et_txdesc_ring *tx_ring; 153705884511SPyun YongHyeon struct et_txbuf_data *tbd; 153805884511SPyun YongHyeon struct et_txstatus_data *txsd; 15394d52a575SXin LI 154005884511SPyun YongHyeon tx_ring = &sc->sc_tx_ring; 15414d52a575SXin LI bzero(tx_ring->tr_desc, ET_TX_RING_SIZE); 15424d52a575SXin LI bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap, 15434d52a575SXin LI BUS_DMASYNC_PREWRITE); 15444d52a575SXin LI 154505884511SPyun YongHyeon tbd = &sc->sc_tx_data; 15464d52a575SXin LI tbd->tbd_start_index = 0; 15474d52a575SXin LI tbd->tbd_start_wrap = 0; 15484d52a575SXin LI tbd->tbd_used = 0; 15494d52a575SXin LI 155005884511SPyun YongHyeon txsd = &sc->sc_tx_status; 15514d52a575SXin LI bzero(txsd->txsd_status, sizeof(uint32_t)); 15524d52a575SXin LI bus_dmamap_sync(txsd->txsd_dtag, txsd->txsd_dmap, 155305884511SPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 15544d52a575SXin LI } 15554d52a575SXin LI 15564d52a575SXin LI static int 15574d52a575SXin LI et_init_rx_ring(struct et_softc *sc) 15584d52a575SXin LI { 155905884511SPyun YongHyeon struct et_rxstatus_data *rxsd; 156005884511SPyun YongHyeon struct et_rxstat_ring *rxst_ring; 156105884511SPyun YongHyeon struct et_rxbuf_data *rbd; 156205884511SPyun YongHyeon int i, error, n; 15634d52a575SXin LI 15644d52a575SXin LI for (n = 0; n < ET_RX_NRING; ++n) { 156505884511SPyun YongHyeon rbd = &sc->sc_rx_data[n]; 15664d52a575SXin LI for (i = 0; i < ET_RX_NDESC; ++i) { 156705884511SPyun YongHyeon error = rbd->rbd_newbuf(rbd, i); 15684d52a575SXin LI if (error) { 15694d52a575SXin LI if_printf(sc->ifp, "%d ring %d buf, " 15704d52a575SXin LI "newbuf failed: %d\n", n, i, error); 1571398f1b65SPyun YongHyeon return (error); 15724d52a575SXin LI } 15734d52a575SXin LI } 15744d52a575SXin LI } 15754d52a575SXin LI 157605884511SPyun YongHyeon rxsd = &sc->sc_rx_status; 15774d52a575SXin LI bzero(rxsd->rxsd_status, sizeof(struct et_rxstatus)); 15784d52a575SXin LI bus_dmamap_sync(rxsd->rxsd_dtag, rxsd->rxsd_dmap, 157905884511SPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 15804d52a575SXin LI 158105884511SPyun YongHyeon rxst_ring = &sc->sc_rxstat_ring; 15824d52a575SXin LI bzero(rxst_ring->rsr_stat, ET_RXSTAT_RING_SIZE); 15834d52a575SXin LI bus_dmamap_sync(rxst_ring->rsr_dtag, rxst_ring->rsr_dmap, 158405884511SPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 15854d52a575SXin LI 1586398f1b65SPyun YongHyeon return (0); 15874d52a575SXin LI } 15884d52a575SXin LI 15894d52a575SXin LI static int 15904d52a575SXin LI et_init_rxdma(struct et_softc *sc) 15914d52a575SXin LI { 15924d52a575SXin LI struct et_rxstatus_data *rxsd = &sc->sc_rx_status; 15934d52a575SXin LI struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring; 15944d52a575SXin LI struct et_rxdesc_ring *rx_ring; 15954d52a575SXin LI int error; 15964d52a575SXin LI 15974d52a575SXin LI error = et_stop_rxdma(sc); 15984d52a575SXin LI if (error) { 15994d52a575SXin LI if_printf(sc->ifp, "can't init RX DMA engine\n"); 1600398f1b65SPyun YongHyeon return (error); 16014d52a575SXin LI } 16024d52a575SXin LI 16034d52a575SXin LI /* 16044d52a575SXin LI * Install RX status 16054d52a575SXin LI */ 16064d52a575SXin LI CSR_WRITE_4(sc, ET_RX_STATUS_HI, ET_ADDR_HI(rxsd->rxsd_paddr)); 16074d52a575SXin LI CSR_WRITE_4(sc, ET_RX_STATUS_LO, ET_ADDR_LO(rxsd->rxsd_paddr)); 16084d52a575SXin LI 16094d52a575SXin LI /* 16104d52a575SXin LI * Install RX stat ring 16114d52a575SXin LI */ 16124d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_HI, ET_ADDR_HI(rxst_ring->rsr_paddr)); 16134d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_LO, ET_ADDR_LO(rxst_ring->rsr_paddr)); 16144d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_CNT, ET_RX_NSTAT - 1); 16154d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_POS, 0); 16164d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_MINCNT, ((ET_RX_NSTAT * 15) / 100) - 1); 16174d52a575SXin LI 16184d52a575SXin LI /* Match ET_RXSTAT_POS */ 16194d52a575SXin LI rxst_ring->rsr_index = 0; 16204d52a575SXin LI rxst_ring->rsr_wrap = 0; 16214d52a575SXin LI 16224d52a575SXin LI /* 16234d52a575SXin LI * Install the 2nd RX descriptor ring 16244d52a575SXin LI */ 16254d52a575SXin LI rx_ring = &sc->sc_rx_ring[1]; 16264d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING1_HI, ET_ADDR_HI(rx_ring->rr_paddr)); 16274d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING1_LO, ET_ADDR_LO(rx_ring->rr_paddr)); 16284d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING1_CNT, ET_RX_NDESC - 1); 16294d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING1_POS, ET_RX_RING1_POS_WRAP); 16304d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING1_MINCNT, ((ET_RX_NDESC * 15) / 100) - 1); 16314d52a575SXin LI 16324d52a575SXin LI /* Match ET_RX_RING1_POS */ 16334d52a575SXin LI rx_ring->rr_index = 0; 16344d52a575SXin LI rx_ring->rr_wrap = 1; 16354d52a575SXin LI 16364d52a575SXin LI /* 16374d52a575SXin LI * Install the 1st RX descriptor ring 16384d52a575SXin LI */ 16394d52a575SXin LI rx_ring = &sc->sc_rx_ring[0]; 16404d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING0_HI, ET_ADDR_HI(rx_ring->rr_paddr)); 16414d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING0_LO, ET_ADDR_LO(rx_ring->rr_paddr)); 16424d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING0_CNT, ET_RX_NDESC - 1); 16434d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING0_POS, ET_RX_RING0_POS_WRAP); 16444d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING0_MINCNT, ((ET_RX_NDESC * 15) / 100) - 1); 16454d52a575SXin LI 16464d52a575SXin LI /* Match ET_RX_RING0_POS */ 16474d52a575SXin LI rx_ring->rr_index = 0; 16484d52a575SXin LI rx_ring->rr_wrap = 1; 16494d52a575SXin LI 16504d52a575SXin LI /* 16514d52a575SXin LI * RX intr moderation 16524d52a575SXin LI */ 16534d52a575SXin LI CSR_WRITE_4(sc, ET_RX_INTR_NPKTS, sc->sc_rx_intr_npkts); 16544d52a575SXin LI CSR_WRITE_4(sc, ET_RX_INTR_DELAY, sc->sc_rx_intr_delay); 16554d52a575SXin LI 1656398f1b65SPyun YongHyeon return (0); 16574d52a575SXin LI } 16584d52a575SXin LI 16594d52a575SXin LI static int 16604d52a575SXin LI et_init_txdma(struct et_softc *sc) 16614d52a575SXin LI { 16624d52a575SXin LI struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 16634d52a575SXin LI struct et_txstatus_data *txsd = &sc->sc_tx_status; 16644d52a575SXin LI int error; 16654d52a575SXin LI 16664d52a575SXin LI error = et_stop_txdma(sc); 16674d52a575SXin LI if (error) { 16684d52a575SXin LI if_printf(sc->ifp, "can't init TX DMA engine\n"); 1669398f1b65SPyun YongHyeon return (error); 16704d52a575SXin LI } 16714d52a575SXin LI 16724d52a575SXin LI /* 16734d52a575SXin LI * Install TX descriptor ring 16744d52a575SXin LI */ 16754d52a575SXin LI CSR_WRITE_4(sc, ET_TX_RING_HI, ET_ADDR_HI(tx_ring->tr_paddr)); 16764d52a575SXin LI CSR_WRITE_4(sc, ET_TX_RING_LO, ET_ADDR_LO(tx_ring->tr_paddr)); 16774d52a575SXin LI CSR_WRITE_4(sc, ET_TX_RING_CNT, ET_TX_NDESC - 1); 16784d52a575SXin LI 16794d52a575SXin LI /* 16804d52a575SXin LI * Install TX status 16814d52a575SXin LI */ 16824d52a575SXin LI CSR_WRITE_4(sc, ET_TX_STATUS_HI, ET_ADDR_HI(txsd->txsd_paddr)); 16834d52a575SXin LI CSR_WRITE_4(sc, ET_TX_STATUS_LO, ET_ADDR_LO(txsd->txsd_paddr)); 16844d52a575SXin LI 16854d52a575SXin LI CSR_WRITE_4(sc, ET_TX_READY_POS, 0); 16864d52a575SXin LI 16874d52a575SXin LI /* Match ET_TX_READY_POS */ 16884d52a575SXin LI tx_ring->tr_ready_index = 0; 16894d52a575SXin LI tx_ring->tr_ready_wrap = 0; 16904d52a575SXin LI 1691398f1b65SPyun YongHyeon return (0); 16924d52a575SXin LI } 16934d52a575SXin LI 16944d52a575SXin LI static void 16954d52a575SXin LI et_init_mac(struct et_softc *sc) 16964d52a575SXin LI { 16974d52a575SXin LI struct ifnet *ifp = sc->ifp; 16984d52a575SXin LI const uint8_t *eaddr = IF_LLADDR(ifp); 16994d52a575SXin LI uint32_t val; 17004d52a575SXin LI 17014d52a575SXin LI /* Reset MAC */ 17024d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 17034d52a575SXin LI ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 17044d52a575SXin LI ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | 17054d52a575SXin LI ET_MAC_CFG1_SIM_RST | ET_MAC_CFG1_SOFT_RST); 17064d52a575SXin LI 17074d52a575SXin LI /* 17084d52a575SXin LI * Setup inter packet gap 17094d52a575SXin LI */ 171023263665SPyun YongHyeon val = (56 << ET_IPG_NONB2B_1_SHIFT) | 171123263665SPyun YongHyeon (88 << ET_IPG_NONB2B_2_SHIFT) | 171223263665SPyun YongHyeon (80 << ET_IPG_MINIFG_SHIFT) | 171323263665SPyun YongHyeon (96 << ET_IPG_B2B_SHIFT); 17144d52a575SXin LI CSR_WRITE_4(sc, ET_IPG, val); 17154d52a575SXin LI 17164d52a575SXin LI /* 17174d52a575SXin LI * Setup half duplex mode 17184d52a575SXin LI */ 171923263665SPyun YongHyeon val = (10 << ET_MAC_HDX_ALT_BEB_TRUNC_SHIFT) | 172023263665SPyun YongHyeon (15 << ET_MAC_HDX_REXMIT_MAX_SHIFT) | 172123263665SPyun YongHyeon (55 << ET_MAC_HDX_COLLWIN_SHIFT) | 17224d52a575SXin LI ET_MAC_HDX_EXC_DEFER; 17234d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_HDX, val); 17244d52a575SXin LI 17254d52a575SXin LI /* Clear MAC control */ 17264d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CTRL, 0); 17274d52a575SXin LI 17284d52a575SXin LI /* Reset MII */ 17294d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CFG, ET_MII_CFG_CLKRST); 17304d52a575SXin LI 17314d52a575SXin LI /* 17324d52a575SXin LI * Set MAC address 17334d52a575SXin LI */ 17344d52a575SXin LI val = eaddr[2] | (eaddr[3] << 8) | (eaddr[4] << 16) | (eaddr[5] << 24); 17354d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_ADDR1, val); 17364d52a575SXin LI val = (eaddr[0] << 16) | (eaddr[1] << 24); 17374d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_ADDR2, val); 17384d52a575SXin LI 17394d52a575SXin LI /* Set max frame length */ 17404d52a575SXin LI CSR_WRITE_4(sc, ET_MAX_FRMLEN, ET_FRAMELEN(ifp->if_mtu)); 17414d52a575SXin LI 17424d52a575SXin LI /* Bring MAC out of reset state */ 17434d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 0); 17444d52a575SXin LI } 17454d52a575SXin LI 17464d52a575SXin LI static void 17474d52a575SXin LI et_init_rxmac(struct et_softc *sc) 17484d52a575SXin LI { 17494d52a575SXin LI struct ifnet *ifp = sc->ifp; 17504d52a575SXin LI const uint8_t *eaddr = IF_LLADDR(ifp); 17514d52a575SXin LI uint32_t val; 17524d52a575SXin LI int i; 17534d52a575SXin LI 17544d52a575SXin LI /* Disable RX MAC and WOL */ 17554d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_CTRL, ET_RXMAC_CTRL_WOL_DISABLE); 17564d52a575SXin LI 17574d52a575SXin LI /* 17584d52a575SXin LI * Clear all WOL related registers 17594d52a575SXin LI */ 17604d52a575SXin LI for (i = 0; i < 3; ++i) 17614d52a575SXin LI CSR_WRITE_4(sc, ET_WOL_CRC + (i * 4), 0); 17624d52a575SXin LI for (i = 0; i < 20; ++i) 17634d52a575SXin LI CSR_WRITE_4(sc, ET_WOL_MASK + (i * 4), 0); 17644d52a575SXin LI 17654d52a575SXin LI /* 17664d52a575SXin LI * Set WOL source address. XXX is this necessary? 17674d52a575SXin LI */ 17684d52a575SXin LI val = (eaddr[2] << 24) | (eaddr[3] << 16) | (eaddr[4] << 8) | eaddr[5]; 17694d52a575SXin LI CSR_WRITE_4(sc, ET_WOL_SA_LO, val); 17704d52a575SXin LI val = (eaddr[0] << 8) | eaddr[1]; 17714d52a575SXin LI CSR_WRITE_4(sc, ET_WOL_SA_HI, val); 17724d52a575SXin LI 17734d52a575SXin LI /* Clear packet filters */ 17744d52a575SXin LI CSR_WRITE_4(sc, ET_PKTFILT, 0); 17754d52a575SXin LI 17764d52a575SXin LI /* No ucast filtering */ 17774d52a575SXin LI CSR_WRITE_4(sc, ET_UCAST_FILTADDR1, 0); 17784d52a575SXin LI CSR_WRITE_4(sc, ET_UCAST_FILTADDR2, 0); 17794d52a575SXin LI CSR_WRITE_4(sc, ET_UCAST_FILTADDR3, 0); 17804d52a575SXin LI 17814d52a575SXin LI if (ET_FRAMELEN(ifp->if_mtu) > ET_RXMAC_CUT_THRU_FRMLEN) { 17824d52a575SXin LI /* 17834d52a575SXin LI * In order to transmit jumbo packets greater than 17844d52a575SXin LI * ET_RXMAC_CUT_THRU_FRMLEN bytes, the FIFO between 17854d52a575SXin LI * RX MAC and RX DMA needs to be reduced in size to 17864d52a575SXin LI * (ET_MEM_SIZE - ET_MEM_TXSIZE_EX - framelen). In 17874d52a575SXin LI * order to implement this, we must use "cut through" 17884d52a575SXin LI * mode in the RX MAC, which chops packets down into 17894d52a575SXin LI * segments. In this case we selected 256 bytes, 17904d52a575SXin LI * since this is the size of the PCI-Express TLP's 17914d52a575SXin LI * that the ET1310 uses. 17924d52a575SXin LI */ 179323263665SPyun YongHyeon val = (ET_RXMAC_SEGSZ(256) & ET_RXMAC_MC_SEGSZ_MAX_MASK) | 17944d52a575SXin LI ET_RXMAC_MC_SEGSZ_ENABLE; 17954d52a575SXin LI } else { 17964d52a575SXin LI val = 0; 17974d52a575SXin LI } 17984d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_MC_SEGSZ, val); 17994d52a575SXin LI 18004d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_MC_WATERMARK, 0); 18014d52a575SXin LI 18024d52a575SXin LI /* Initialize RX MAC management register */ 18034d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_MGT, 0); 18044d52a575SXin LI 18054d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_SPACE_AVL, 0); 18064d52a575SXin LI 18074d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_MGT, 18084d52a575SXin LI ET_RXMAC_MGT_PASS_ECRC | 18094d52a575SXin LI ET_RXMAC_MGT_PASS_ELEN | 18104d52a575SXin LI ET_RXMAC_MGT_PASS_ETRUNC | 18114d52a575SXin LI ET_RXMAC_MGT_CHECK_PKT); 18124d52a575SXin LI 18134d52a575SXin LI /* 18144d52a575SXin LI * Configure runt filtering (may not work on certain chip generation) 18154d52a575SXin LI */ 181623263665SPyun YongHyeon val = (ETHER_MIN_LEN << ET_PKTFILT_MINLEN_SHIFT) & 181723263665SPyun YongHyeon ET_PKTFILT_MINLEN_MASK; 181823263665SPyun YongHyeon val |= ET_PKTFILT_FRAG; 18194d52a575SXin LI CSR_WRITE_4(sc, ET_PKTFILT, val); 18204d52a575SXin LI 18214d52a575SXin LI /* Enable RX MAC but leave WOL disabled */ 18224d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_CTRL, 18234d52a575SXin LI ET_RXMAC_CTRL_WOL_DISABLE | ET_RXMAC_CTRL_ENABLE); 18244d52a575SXin LI 18254d52a575SXin LI /* 18264d52a575SXin LI * Setup multicast hash and allmulti/promisc mode 18274d52a575SXin LI */ 18284d52a575SXin LI et_setmulti(sc); 18294d52a575SXin LI } 18304d52a575SXin LI 18314d52a575SXin LI static void 18324d52a575SXin LI et_init_txmac(struct et_softc *sc) 18334d52a575SXin LI { 18344d52a575SXin LI /* Disable TX MAC and FC(?) */ 18354d52a575SXin LI CSR_WRITE_4(sc, ET_TXMAC_CTRL, ET_TXMAC_CTRL_FC_DISABLE); 18364d52a575SXin LI 18374d52a575SXin LI /* No flow control yet */ 18384d52a575SXin LI CSR_WRITE_4(sc, ET_TXMAC_FLOWCTRL, 0); 18394d52a575SXin LI 18404d52a575SXin LI /* Enable TX MAC but leave FC(?) diabled */ 18414d52a575SXin LI CSR_WRITE_4(sc, ET_TXMAC_CTRL, 18424d52a575SXin LI ET_TXMAC_CTRL_ENABLE | ET_TXMAC_CTRL_FC_DISABLE); 18434d52a575SXin LI } 18444d52a575SXin LI 18454d52a575SXin LI static int 18464d52a575SXin LI et_start_rxdma(struct et_softc *sc) 18474d52a575SXin LI { 18484d52a575SXin LI uint32_t val = 0; 18494d52a575SXin LI 185023263665SPyun YongHyeon val |= (sc->sc_rx_data[0].rbd_bufsize & ET_RXDMA_CTRL_RING0_SIZE_MASK) | 18514d52a575SXin LI ET_RXDMA_CTRL_RING0_ENABLE; 185223263665SPyun YongHyeon val |= (sc->sc_rx_data[1].rbd_bufsize & ET_RXDMA_CTRL_RING1_SIZE_MASK) | 18534d52a575SXin LI ET_RXDMA_CTRL_RING1_ENABLE; 18544d52a575SXin LI 18554d52a575SXin LI CSR_WRITE_4(sc, ET_RXDMA_CTRL, val); 18564d52a575SXin LI 18574d52a575SXin LI DELAY(5); 18584d52a575SXin LI 18594d52a575SXin LI if (CSR_READ_4(sc, ET_RXDMA_CTRL) & ET_RXDMA_CTRL_HALTED) { 18604d52a575SXin LI if_printf(sc->ifp, "can't start RX DMA engine\n"); 1861398f1b65SPyun YongHyeon return (ETIMEDOUT); 18624d52a575SXin LI } 1863398f1b65SPyun YongHyeon return (0); 18644d52a575SXin LI } 18654d52a575SXin LI 18664d52a575SXin LI static int 18674d52a575SXin LI et_start_txdma(struct et_softc *sc) 18684d52a575SXin LI { 18694d52a575SXin LI CSR_WRITE_4(sc, ET_TXDMA_CTRL, ET_TXDMA_CTRL_SINGLE_EPKT); 1870398f1b65SPyun YongHyeon return (0); 18714d52a575SXin LI } 18724d52a575SXin LI 18734d52a575SXin LI static int 18744d52a575SXin LI et_enable_txrx(struct et_softc *sc, int media_upd) 18754d52a575SXin LI { 18764d52a575SXin LI struct ifnet *ifp = sc->ifp; 18774d52a575SXin LI uint32_t val; 18784d52a575SXin LI int i, error; 18794d52a575SXin LI 18804d52a575SXin LI val = CSR_READ_4(sc, ET_MAC_CFG1); 18814d52a575SXin LI val |= ET_MAC_CFG1_TXEN | ET_MAC_CFG1_RXEN; 18824d52a575SXin LI val &= ~(ET_MAC_CFG1_TXFLOW | ET_MAC_CFG1_RXFLOW | 18834d52a575SXin LI ET_MAC_CFG1_LOOPBACK); 18844d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, val); 18854d52a575SXin LI 18864d52a575SXin LI if (media_upd) 18874d52a575SXin LI et_ifmedia_upd_locked(ifp); 18884d52a575SXin LI else 18894d52a575SXin LI et_setmedia(sc); 18904d52a575SXin LI 18914d52a575SXin LI #define NRETRY 50 18924d52a575SXin LI 18934d52a575SXin LI for (i = 0; i < NRETRY; ++i) { 18944d52a575SXin LI val = CSR_READ_4(sc, ET_MAC_CFG1); 18954d52a575SXin LI if ((val & (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) == 18964d52a575SXin LI (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) 18974d52a575SXin LI break; 18984d52a575SXin LI 18994d52a575SXin LI DELAY(100); 19004d52a575SXin LI } 19014d52a575SXin LI if (i == NRETRY) { 19024d52a575SXin LI if_printf(ifp, "can't enable RX/TX\n"); 1903398f1b65SPyun YongHyeon return (0); 19044d52a575SXin LI } 19054d52a575SXin LI sc->sc_flags |= ET_FLAG_TXRX_ENABLED; 19064d52a575SXin LI 19074d52a575SXin LI #undef NRETRY 19084d52a575SXin LI 19094d52a575SXin LI /* 19104d52a575SXin LI * Start TX/RX DMA engine 19114d52a575SXin LI */ 19124d52a575SXin LI error = et_start_rxdma(sc); 19134d52a575SXin LI if (error) 1914398f1b65SPyun YongHyeon return (error); 19154d52a575SXin LI 19164d52a575SXin LI error = et_start_txdma(sc); 19174d52a575SXin LI if (error) 1918398f1b65SPyun YongHyeon return (error); 19194d52a575SXin LI 1920398f1b65SPyun YongHyeon return (0); 19214d52a575SXin LI } 19224d52a575SXin LI 19234d52a575SXin LI static void 19244d52a575SXin LI et_rxeof(struct et_softc *sc) 19254d52a575SXin LI { 19264d52a575SXin LI struct et_rxstatus_data *rxsd; 19274d52a575SXin LI struct et_rxstat_ring *rxst_ring; 192805884511SPyun YongHyeon struct et_rxbuf_data *rbd; 192905884511SPyun YongHyeon struct et_rxdesc_ring *rx_ring; 193005884511SPyun YongHyeon struct et_rxstat *st; 193105884511SPyun YongHyeon struct ifnet *ifp; 193205884511SPyun YongHyeon struct mbuf *m; 193305884511SPyun YongHyeon uint32_t rxstat_pos, rxring_pos; 193405884511SPyun YongHyeon uint32_t rxst_info1, rxst_info2, rxs_stat_ring; 193505884511SPyun YongHyeon int buflen, buf_idx, npost[2], ring_idx; 193605884511SPyun YongHyeon int rxst_index, rxst_wrap; 19374d52a575SXin LI 19384d52a575SXin LI ET_LOCK_ASSERT(sc); 193905884511SPyun YongHyeon 19404d52a575SXin LI ifp = sc->ifp; 19414d52a575SXin LI rxsd = &sc->sc_rx_status; 19424d52a575SXin LI rxst_ring = &sc->sc_rxstat_ring; 19434d52a575SXin LI 19444d52a575SXin LI if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0) 19454d52a575SXin LI return; 19464d52a575SXin LI 19474d52a575SXin LI bus_dmamap_sync(rxsd->rxsd_dtag, rxsd->rxsd_dmap, 19484d52a575SXin LI BUS_DMASYNC_POSTREAD); 19494d52a575SXin LI bus_dmamap_sync(rxst_ring->rsr_dtag, rxst_ring->rsr_dmap, 19504d52a575SXin LI BUS_DMASYNC_POSTREAD); 19514d52a575SXin LI 195205884511SPyun YongHyeon npost[0] = npost[1] = 0; 195326e07b50SPyun YongHyeon rxs_stat_ring = le32toh(rxsd->rxsd_status->rxs_stat_ring); 19544d52a575SXin LI rxst_wrap = (rxs_stat_ring & ET_RXS_STATRING_WRAP) ? 1 : 0; 195523263665SPyun YongHyeon rxst_index = (rxs_stat_ring & ET_RXS_STATRING_INDEX_MASK) >> 195623263665SPyun YongHyeon ET_RXS_STATRING_INDEX_SHIFT; 19574d52a575SXin LI 19584d52a575SXin LI while (rxst_index != rxst_ring->rsr_index || 19594d52a575SXin LI rxst_wrap != rxst_ring->rsr_wrap) { 196005884511SPyun YongHyeon if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 196105884511SPyun YongHyeon break; 19624d52a575SXin LI 19634d52a575SXin LI MPASS(rxst_ring->rsr_index < ET_RX_NSTAT); 19644d52a575SXin LI st = &rxst_ring->rsr_stat[rxst_ring->rsr_index]; 196505884511SPyun YongHyeon rxst_info1 = le32toh(st->rxst_info1); 196626e07b50SPyun YongHyeon rxst_info2 = le32toh(st->rxst_info2); 196726e07b50SPyun YongHyeon buflen = (rxst_info2 & ET_RXST_INFO2_LEN_MASK) >> 196823263665SPyun YongHyeon ET_RXST_INFO2_LEN_SHIFT; 196926e07b50SPyun YongHyeon buf_idx = (rxst_info2 & ET_RXST_INFO2_BUFIDX_MASK) >> 197023263665SPyun YongHyeon ET_RXST_INFO2_BUFIDX_SHIFT; 197126e07b50SPyun YongHyeon ring_idx = (rxst_info2 & ET_RXST_INFO2_RINGIDX_MASK) >> 197223263665SPyun YongHyeon ET_RXST_INFO2_RINGIDX_SHIFT; 19734d52a575SXin LI 19744d52a575SXin LI if (++rxst_ring->rsr_index == ET_RX_NSTAT) { 19754d52a575SXin LI rxst_ring->rsr_index = 0; 19764d52a575SXin LI rxst_ring->rsr_wrap ^= 1; 19774d52a575SXin LI } 197823263665SPyun YongHyeon rxstat_pos = rxst_ring->rsr_index & ET_RXSTAT_POS_INDEX_MASK; 19794d52a575SXin LI if (rxst_ring->rsr_wrap) 19804d52a575SXin LI rxstat_pos |= ET_RXSTAT_POS_WRAP; 19814d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_POS, rxstat_pos); 19824d52a575SXin LI 19834d52a575SXin LI if (ring_idx >= ET_RX_NRING) { 19844d52a575SXin LI ifp->if_ierrors++; 19854d52a575SXin LI if_printf(ifp, "invalid ring index %d\n", ring_idx); 19864d52a575SXin LI continue; 19874d52a575SXin LI } 19884d52a575SXin LI if (buf_idx >= ET_RX_NDESC) { 19894d52a575SXin LI ifp->if_ierrors++; 19904d52a575SXin LI if_printf(ifp, "invalid buf index %d\n", buf_idx); 19914d52a575SXin LI continue; 19924d52a575SXin LI } 19934d52a575SXin LI 19944d52a575SXin LI rbd = &sc->sc_rx_data[ring_idx]; 19954d52a575SXin LI m = rbd->rbd_buf[buf_idx].rb_mbuf; 199605884511SPyun YongHyeon if ((rxst_info1 & ET_RXST_INFO1_OK) == 0){ 199705884511SPyun YongHyeon /* Discard errored frame. */ 199805884511SPyun YongHyeon ifp->if_ierrors++; 199905884511SPyun YongHyeon rbd->rbd_discard(rbd, buf_idx); 200005884511SPyun YongHyeon } else if (rbd->rbd_newbuf(rbd, buf_idx) != 0) { 200105884511SPyun YongHyeon /* No available mbufs, discard it. */ 200205884511SPyun YongHyeon ifp->if_iqdrops++; 200305884511SPyun YongHyeon rbd->rbd_discard(rbd, buf_idx); 200405884511SPyun YongHyeon } else { 200505884511SPyun YongHyeon buflen -= ETHER_CRC_LEN; 200605884511SPyun YongHyeon if (buflen < ETHER_HDR_LEN) { 20074d52a575SXin LI m_freem(m); 20084d52a575SXin LI ifp->if_ierrors++; 20094d52a575SXin LI } else { 201005884511SPyun YongHyeon m->m_pkthdr.len = m->m_len = buflen; 20114d52a575SXin LI m->m_pkthdr.rcvif = ifp; 20124d52a575SXin LI ifp->if_ipackets++; 20134d52a575SXin LI ET_UNLOCK(sc); 20144d52a575SXin LI ifp->if_input(ifp, m); 20154d52a575SXin LI ET_LOCK(sc); 20164d52a575SXin LI } 20174d52a575SXin LI } 20184d52a575SXin LI 20194d52a575SXin LI rx_ring = &sc->sc_rx_ring[ring_idx]; 20204d52a575SXin LI if (buf_idx != rx_ring->rr_index) { 202105884511SPyun YongHyeon if_printf(ifp, 202205884511SPyun YongHyeon "WARNING!! ring %d, buf_idx %d, rr_idx %d\n", 20234d52a575SXin LI ring_idx, buf_idx, rx_ring->rr_index); 20244d52a575SXin LI } 20254d52a575SXin LI 20264d52a575SXin LI MPASS(rx_ring->rr_index < ET_RX_NDESC); 20274d52a575SXin LI if (++rx_ring->rr_index == ET_RX_NDESC) { 20284d52a575SXin LI rx_ring->rr_index = 0; 20294d52a575SXin LI rx_ring->rr_wrap ^= 1; 20304d52a575SXin LI } 203123263665SPyun YongHyeon rxring_pos = rx_ring->rr_index & ET_RX_RING_POS_INDEX_MASK; 20324d52a575SXin LI if (rx_ring->rr_wrap) 20334d52a575SXin LI rxring_pos |= ET_RX_RING_POS_WRAP; 20344d52a575SXin LI CSR_WRITE_4(sc, rx_ring->rr_posreg, rxring_pos); 20354d52a575SXin LI } 203605884511SPyun YongHyeon 203705884511SPyun YongHyeon bus_dmamap_sync(rxsd->rxsd_dtag, rxsd->rxsd_dmap, 203805884511SPyun YongHyeon BUS_DMASYNC_PREREAD); 203905884511SPyun YongHyeon bus_dmamap_sync(rxst_ring->rsr_dtag, rxst_ring->rsr_dmap, 204005884511SPyun YongHyeon BUS_DMASYNC_PREREAD); 20414d52a575SXin LI } 20424d52a575SXin LI 20434d52a575SXin LI static int 20444d52a575SXin LI et_encap(struct et_softc *sc, struct mbuf **m0) 20454d52a575SXin LI { 204605884511SPyun YongHyeon struct et_txdesc_ring *tx_ring; 204705884511SPyun YongHyeon struct et_txbuf_data *tbd; 20484d52a575SXin LI struct et_txdesc *td; 204905884511SPyun YongHyeon struct mbuf *m; 205005884511SPyun YongHyeon bus_dma_segment_t segs[ET_NSEG_MAX]; 20514d52a575SXin LI bus_dmamap_t map; 2052244fd28bSPyun YongHyeon uint32_t csum_flags, last_td_ctrl2; 205305884511SPyun YongHyeon int error, i, idx, first_idx, last_idx, nsegs; 20544d52a575SXin LI 205505884511SPyun YongHyeon tx_ring = &sc->sc_tx_ring; 20564d52a575SXin LI MPASS(tx_ring->tr_ready_index < ET_TX_NDESC); 205705884511SPyun YongHyeon tbd = &sc->sc_tx_data; 20584d52a575SXin LI first_idx = tx_ring->tr_ready_index; 20594d52a575SXin LI map = tbd->tbd_buf[first_idx].tb_dmap; 20604d52a575SXin LI 206105884511SPyun YongHyeon error = bus_dmamap_load_mbuf_sg(sc->sc_tx_tag, map, *m0, segs, &nsegs, 206205884511SPyun YongHyeon 0); 206305884511SPyun YongHyeon if (error == EFBIG) { 206405884511SPyun YongHyeon m = m_collapse(*m0, M_DONTWAIT, ET_NSEG_MAX); 206505884511SPyun YongHyeon if (m == NULL) { 206605884511SPyun YongHyeon m_freem(*m0); 206705884511SPyun YongHyeon *m0 = NULL; 206805884511SPyun YongHyeon return (ENOMEM); 20694d52a575SXin LI } 207005884511SPyun YongHyeon *m0 = m; 207105884511SPyun YongHyeon error = bus_dmamap_load_mbuf_sg(sc->sc_tx_tag, map, *m0, segs, 207205884511SPyun YongHyeon &nsegs, 0); 207305884511SPyun YongHyeon if (error != 0) { 207405884511SPyun YongHyeon m_freem(*m0); 207505884511SPyun YongHyeon *m0 = NULL; 207605884511SPyun YongHyeon return (error); 20774d52a575SXin LI } 207805884511SPyun YongHyeon } else if (error != 0) 207905884511SPyun YongHyeon return (error); 20804d52a575SXin LI 208105884511SPyun YongHyeon /* Check for descriptor overruns. */ 208205884511SPyun YongHyeon if (tbd->tbd_used + nsegs > ET_TX_NDESC - 1) { 208305884511SPyun YongHyeon bus_dmamap_unload(sc->sc_tx_tag, map); 208405884511SPyun YongHyeon return (ENOBUFS); 20854d52a575SXin LI } 208605884511SPyun YongHyeon bus_dmamap_sync(sc->sc_tx_tag, map, BUS_DMASYNC_PREWRITE); 20874d52a575SXin LI 20884d52a575SXin LI last_td_ctrl2 = ET_TDCTRL2_LAST_FRAG; 208905884511SPyun YongHyeon sc->sc_tx += nsegs; 20904d52a575SXin LI if (sc->sc_tx / sc->sc_tx_intr_nsegs != sc->sc_tx_intr) { 20914d52a575SXin LI sc->sc_tx_intr = sc->sc_tx / sc->sc_tx_intr_nsegs; 20924d52a575SXin LI last_td_ctrl2 |= ET_TDCTRL2_INTR; 20934d52a575SXin LI } 20944d52a575SXin LI 209505884511SPyun YongHyeon m = *m0; 20969955274cSPyun YongHyeon csum_flags = 0; 20979955274cSPyun YongHyeon if ((m->m_pkthdr.csum_flags & ET_CSUM_FEATURES) != 0) { 20989955274cSPyun YongHyeon if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) 20999955274cSPyun YongHyeon csum_flags |= ET_TDCTRL2_CSUM_IP; 21009955274cSPyun YongHyeon if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) 21019955274cSPyun YongHyeon csum_flags |= ET_TDCTRL2_CSUM_UDP; 21029955274cSPyun YongHyeon else if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0) 21039955274cSPyun YongHyeon csum_flags |= ET_TDCTRL2_CSUM_TCP; 21049955274cSPyun YongHyeon } 21054d52a575SXin LI last_idx = -1; 210605884511SPyun YongHyeon for (i = 0; i < nsegs; ++i) { 21074d52a575SXin LI idx = (first_idx + i) % ET_TX_NDESC; 21084d52a575SXin LI td = &tx_ring->tr_desc[idx]; 210926e07b50SPyun YongHyeon td->td_addr_hi = htole32(ET_ADDR_HI(segs[i].ds_addr)); 211026e07b50SPyun YongHyeon td->td_addr_lo = htole32(ET_ADDR_LO(segs[i].ds_addr)); 211126e07b50SPyun YongHyeon td->td_ctrl1 = htole32(segs[i].ds_len & ET_TDCTRL1_LEN_MASK); 211205884511SPyun YongHyeon if (i == nsegs - 1) { 211305884511SPyun YongHyeon /* Last frag */ 21149955274cSPyun YongHyeon td->td_ctrl2 = htole32(last_td_ctrl2 | csum_flags); 21154d52a575SXin LI last_idx = idx; 21169955274cSPyun YongHyeon } else 21179955274cSPyun YongHyeon td->td_ctrl2 = htole32(csum_flags); 21184d52a575SXin LI 21194d52a575SXin LI MPASS(tx_ring->tr_ready_index < ET_TX_NDESC); 21204d52a575SXin LI if (++tx_ring->tr_ready_index == ET_TX_NDESC) { 21214d52a575SXin LI tx_ring->tr_ready_index = 0; 21224d52a575SXin LI tx_ring->tr_ready_wrap ^= 1; 21234d52a575SXin LI } 21244d52a575SXin LI } 21254d52a575SXin LI td = &tx_ring->tr_desc[first_idx]; 212605884511SPyun YongHyeon /* First frag */ 212705884511SPyun YongHyeon td->td_ctrl2 |= htole32(ET_TDCTRL2_FIRST_FRAG); 21284d52a575SXin LI 21294d52a575SXin LI MPASS(last_idx >= 0); 21304d52a575SXin LI tbd->tbd_buf[first_idx].tb_dmap = tbd->tbd_buf[last_idx].tb_dmap; 21314d52a575SXin LI tbd->tbd_buf[last_idx].tb_dmap = map; 21324d52a575SXin LI tbd->tbd_buf[last_idx].tb_mbuf = m; 21334d52a575SXin LI 213405884511SPyun YongHyeon tbd->tbd_used += nsegs; 21354d52a575SXin LI MPASS(tbd->tbd_used <= ET_TX_NDESC); 21364d52a575SXin LI 213705884511SPyun YongHyeon return (0); 21384d52a575SXin LI } 21394d52a575SXin LI 21404d52a575SXin LI static void 21414d52a575SXin LI et_txeof(struct et_softc *sc) 21424d52a575SXin LI { 21434d52a575SXin LI struct et_txdesc_ring *tx_ring; 21444d52a575SXin LI struct et_txbuf_data *tbd; 214505884511SPyun YongHyeon struct et_txbuf *tb; 214605884511SPyun YongHyeon struct ifnet *ifp; 21474d52a575SXin LI uint32_t tx_done; 21484d52a575SXin LI int end, wrap; 21494d52a575SXin LI 21504d52a575SXin LI ET_LOCK_ASSERT(sc); 215105884511SPyun YongHyeon 21524d52a575SXin LI ifp = sc->ifp; 21534d52a575SXin LI tx_ring = &sc->sc_tx_ring; 21544d52a575SXin LI tbd = &sc->sc_tx_data; 21554d52a575SXin LI 21564d52a575SXin LI if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0) 21574d52a575SXin LI return; 21584d52a575SXin LI 21594d52a575SXin LI if (tbd->tbd_used == 0) 21604d52a575SXin LI return; 21614d52a575SXin LI 216205884511SPyun YongHyeon bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap, 216305884511SPyun YongHyeon BUS_DMASYNC_POSTWRITE); 216405884511SPyun YongHyeon 21654d52a575SXin LI tx_done = CSR_READ_4(sc, ET_TX_DONE_POS); 216623263665SPyun YongHyeon end = tx_done & ET_TX_DONE_POS_INDEX_MASK; 21674d52a575SXin LI wrap = (tx_done & ET_TX_DONE_POS_WRAP) ? 1 : 0; 21684d52a575SXin LI 21694d52a575SXin LI while (tbd->tbd_start_index != end || tbd->tbd_start_wrap != wrap) { 21704d52a575SXin LI MPASS(tbd->tbd_start_index < ET_TX_NDESC); 21714d52a575SXin LI tb = &tbd->tbd_buf[tbd->tbd_start_index]; 21724d52a575SXin LI if (tb->tb_mbuf != NULL) { 217305884511SPyun YongHyeon bus_dmamap_sync(sc->sc_tx_tag, tb->tb_dmap, 217405884511SPyun YongHyeon BUS_DMASYNC_POSTWRITE); 217505884511SPyun YongHyeon bus_dmamap_unload(sc->sc_tx_tag, tb->tb_dmap); 21764d52a575SXin LI m_freem(tb->tb_mbuf); 21774d52a575SXin LI tb->tb_mbuf = NULL; 21784d52a575SXin LI ifp->if_opackets++; 21794d52a575SXin LI } 21804d52a575SXin LI 21814d52a575SXin LI if (++tbd->tbd_start_index == ET_TX_NDESC) { 21824d52a575SXin LI tbd->tbd_start_index = 0; 21834d52a575SXin LI tbd->tbd_start_wrap ^= 1; 21844d52a575SXin LI } 21854d52a575SXin LI 21864d52a575SXin LI MPASS(tbd->tbd_used > 0); 21874d52a575SXin LI tbd->tbd_used--; 21884d52a575SXin LI } 21894d52a575SXin LI 21904d52a575SXin LI if (tbd->tbd_used == 0) 21914d52a575SXin LI sc->watchdog_timer = 0; 219205884511SPyun YongHyeon if (tbd->tbd_used + ET_NSEG_SPARE < ET_TX_NDESC) 21934d52a575SXin LI ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 21944d52a575SXin LI } 21954d52a575SXin LI static void 21964d52a575SXin LI et_tick(void *xsc) 21974d52a575SXin LI { 21984d52a575SXin LI struct et_softc *sc = xsc; 21994d52a575SXin LI struct ifnet *ifp; 22004d52a575SXin LI struct mii_data *mii; 22014d52a575SXin LI 22024d52a575SXin LI ET_LOCK_ASSERT(sc); 22034d52a575SXin LI ifp = sc->ifp; 22044d52a575SXin LI mii = device_get_softc(sc->sc_miibus); 22054d52a575SXin LI 22064d52a575SXin LI mii_tick(mii); 22074d52a575SXin LI if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0 && 22084d52a575SXin LI (mii->mii_media_status & IFM_ACTIVE) && 22094d52a575SXin LI IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 22104d52a575SXin LI if_printf(ifp, "Link up, enable TX/RX\n"); 22114d52a575SXin LI if (et_enable_txrx(sc, 0) == 0) 22124d52a575SXin LI et_start_locked(ifp); 22134d52a575SXin LI } 221405884511SPyun YongHyeon if (et_watchdog(sc) == EJUSTRETURN) 221505884511SPyun YongHyeon return; 22164d52a575SXin LI callout_reset(&sc->sc_tick, hz, et_tick, sc); 22174d52a575SXin LI } 22184d52a575SXin LI 22194d52a575SXin LI static int 222005884511SPyun YongHyeon et_newbuf_cluster(struct et_rxbuf_data *rbd, int buf_idx) 22214d52a575SXin LI { 222205884511SPyun YongHyeon struct et_softc *sc; 222305884511SPyun YongHyeon struct et_rxdesc *desc; 22244d52a575SXin LI struct et_rxbuf *rb; 22254d52a575SXin LI struct mbuf *m; 222605884511SPyun YongHyeon bus_dma_segment_t segs[1]; 22274d52a575SXin LI bus_dmamap_t dmap; 222805884511SPyun YongHyeon int nsegs; 22294d52a575SXin LI 22304d52a575SXin LI MPASS(buf_idx < ET_RX_NDESC); 223105884511SPyun YongHyeon m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 223205884511SPyun YongHyeon if (m == NULL) 223305884511SPyun YongHyeon return (ENOBUFS); 223405884511SPyun YongHyeon m->m_len = m->m_pkthdr.len = MCLBYTES; 223505884511SPyun YongHyeon m_adj(m, ETHER_ALIGN); 223605884511SPyun YongHyeon 223705884511SPyun YongHyeon sc = rbd->rbd_softc; 22384d52a575SXin LI rb = &rbd->rbd_buf[buf_idx]; 22394d52a575SXin LI 224005884511SPyun YongHyeon if (bus_dmamap_load_mbuf_sg(sc->sc_rx_tag, sc->sc_rx_sparemap, m, 224105884511SPyun YongHyeon segs, &nsegs, 0) != 0) { 22424d52a575SXin LI m_freem(m); 224305884511SPyun YongHyeon return (ENOBUFS); 22444d52a575SXin LI } 224505884511SPyun YongHyeon KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 22464d52a575SXin LI 224705884511SPyun YongHyeon if (rb->rb_mbuf != NULL) { 224805884511SPyun YongHyeon bus_dmamap_sync(sc->sc_rx_tag, rb->rb_dmap, 22494d52a575SXin LI BUS_DMASYNC_POSTREAD); 225005884511SPyun YongHyeon bus_dmamap_unload(sc->sc_rx_tag, rb->rb_dmap); 22514d52a575SXin LI } 22524d52a575SXin LI dmap = rb->rb_dmap; 225305884511SPyun YongHyeon rb->rb_dmap = sc->sc_rx_sparemap; 225405884511SPyun YongHyeon sc->sc_rx_sparemap = dmap; 225505884511SPyun YongHyeon bus_dmamap_sync(sc->sc_rx_tag, rb->rb_dmap, BUS_DMASYNC_PREREAD); 22564d52a575SXin LI 225705884511SPyun YongHyeon rb->rb_mbuf = m; 225805884511SPyun YongHyeon desc = &rbd->rbd_ring->rr_desc[buf_idx]; 225905884511SPyun YongHyeon desc->rd_addr_hi = htole32(ET_ADDR_HI(segs[0].ds_addr)); 226005884511SPyun YongHyeon desc->rd_addr_lo = htole32(ET_ADDR_LO(segs[0].ds_addr)); 226105884511SPyun YongHyeon desc->rd_ctrl = htole32(buf_idx & ET_RDCTRL_BUFIDX_MASK); 226205884511SPyun YongHyeon bus_dmamap_sync(rbd->rbd_ring->rr_dtag, rbd->rbd_ring->rr_dmap, 226305884511SPyun YongHyeon BUS_DMASYNC_PREWRITE); 226405884511SPyun YongHyeon return (0); 226505884511SPyun YongHyeon } 226605884511SPyun YongHyeon 226705884511SPyun YongHyeon static void 226805884511SPyun YongHyeon et_rxbuf_discard(struct et_rxbuf_data *rbd, int buf_idx) 226905884511SPyun YongHyeon { 227005884511SPyun YongHyeon struct et_rxdesc *desc; 227105884511SPyun YongHyeon 227205884511SPyun YongHyeon desc = &rbd->rbd_ring->rr_desc[buf_idx]; 227305884511SPyun YongHyeon desc->rd_ctrl = htole32(buf_idx & ET_RDCTRL_BUFIDX_MASK); 227405884511SPyun YongHyeon bus_dmamap_sync(rbd->rbd_ring->rr_dtag, rbd->rbd_ring->rr_dmap, 227505884511SPyun YongHyeon BUS_DMASYNC_PREWRITE); 227605884511SPyun YongHyeon } 227705884511SPyun YongHyeon 227805884511SPyun YongHyeon static int 227905884511SPyun YongHyeon et_newbuf_hdr(struct et_rxbuf_data *rbd, int buf_idx) 228005884511SPyun YongHyeon { 228105884511SPyun YongHyeon struct et_softc *sc; 228205884511SPyun YongHyeon struct et_rxdesc *desc; 228305884511SPyun YongHyeon struct et_rxbuf *rb; 228405884511SPyun YongHyeon struct mbuf *m; 228505884511SPyun YongHyeon bus_dma_segment_t segs[1]; 228605884511SPyun YongHyeon bus_dmamap_t dmap; 228705884511SPyun YongHyeon int nsegs; 228805884511SPyun YongHyeon 228905884511SPyun YongHyeon MPASS(buf_idx < ET_RX_NDESC); 229005884511SPyun YongHyeon MGETHDR(m, M_DONTWAIT, MT_DATA); 229105884511SPyun YongHyeon if (m == NULL) 229205884511SPyun YongHyeon return (ENOBUFS); 229305884511SPyun YongHyeon m->m_len = m->m_pkthdr.len = MHLEN; 229405884511SPyun YongHyeon m_adj(m, ETHER_ALIGN); 229505884511SPyun YongHyeon 229605884511SPyun YongHyeon sc = rbd->rbd_softc; 229705884511SPyun YongHyeon rb = &rbd->rbd_buf[buf_idx]; 229805884511SPyun YongHyeon 229905884511SPyun YongHyeon if (bus_dmamap_load_mbuf_sg(sc->sc_rx_mini_tag, sc->sc_rx_mini_sparemap, 230005884511SPyun YongHyeon m, segs, &nsegs, 0) != 0) { 230105884511SPyun YongHyeon m_freem(m); 230205884511SPyun YongHyeon return (ENOBUFS); 230305884511SPyun YongHyeon } 230405884511SPyun YongHyeon KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 230505884511SPyun YongHyeon 230605884511SPyun YongHyeon if (rb->rb_mbuf != NULL) { 230705884511SPyun YongHyeon bus_dmamap_sync(sc->sc_rx_mini_tag, rb->rb_dmap, 230805884511SPyun YongHyeon BUS_DMASYNC_POSTREAD); 230905884511SPyun YongHyeon bus_dmamap_unload(sc->sc_rx_mini_tag, rb->rb_dmap); 231005884511SPyun YongHyeon } 231105884511SPyun YongHyeon dmap = rb->rb_dmap; 231205884511SPyun YongHyeon rb->rb_dmap = sc->sc_rx_mini_sparemap; 231305884511SPyun YongHyeon sc->sc_rx_mini_sparemap = dmap; 231405884511SPyun YongHyeon bus_dmamap_sync(sc->sc_rx_mini_tag, rb->rb_dmap, BUS_DMASYNC_PREREAD); 231505884511SPyun YongHyeon 231605884511SPyun YongHyeon rb->rb_mbuf = m; 231705884511SPyun YongHyeon desc = &rbd->rbd_ring->rr_desc[buf_idx]; 231805884511SPyun YongHyeon desc->rd_addr_hi = htole32(ET_ADDR_HI(segs[0].ds_addr)); 231905884511SPyun YongHyeon desc->rd_addr_lo = htole32(ET_ADDR_LO(segs[0].ds_addr)); 232005884511SPyun YongHyeon desc->rd_ctrl = htole32(buf_idx & ET_RDCTRL_BUFIDX_MASK); 232105884511SPyun YongHyeon bus_dmamap_sync(rbd->rbd_ring->rr_dtag, rbd->rbd_ring->rr_dmap, 232205884511SPyun YongHyeon BUS_DMASYNC_PREWRITE); 232305884511SPyun YongHyeon return (0); 23244d52a575SXin LI } 23254d52a575SXin LI 23264d52a575SXin LI /* 23274d52a575SXin LI * Create sysctl tree 23284d52a575SXin LI */ 23294d52a575SXin LI static void 23304d52a575SXin LI et_add_sysctls(struct et_softc * sc) 23314d52a575SXin LI { 23324d52a575SXin LI struct sysctl_ctx_list *ctx; 23334d52a575SXin LI struct sysctl_oid_list *children; 23344d52a575SXin LI 23354d52a575SXin LI ctx = device_get_sysctl_ctx(sc->dev); 23364d52a575SXin LI children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); 23374d52a575SXin LI 23384d52a575SXin LI SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_intr_npkts", 23394d52a575SXin LI CTLTYPE_INT | CTLFLAG_RW, sc, 0, et_sysctl_rx_intr_npkts, "I", 23404d52a575SXin LI "RX IM, # packets per RX interrupt"); 23414d52a575SXin LI SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_intr_delay", 23424d52a575SXin LI CTLTYPE_INT | CTLFLAG_RW, sc, 0, et_sysctl_rx_intr_delay, "I", 23434d52a575SXin LI "RX IM, RX interrupt delay (x10 usec)"); 23444d52a575SXin LI SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_intr_nsegs", 23454d52a575SXin LI CTLFLAG_RW, &sc->sc_tx_intr_nsegs, 0, 23464d52a575SXin LI "TX IM, # segments per TX interrupt"); 23474d52a575SXin LI SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "timer", 23484d52a575SXin LI CTLFLAG_RW, &sc->sc_timer, 0, "TX timer"); 23494d52a575SXin LI } 23504d52a575SXin LI 23514d52a575SXin LI static int 23524d52a575SXin LI et_sysctl_rx_intr_npkts(SYSCTL_HANDLER_ARGS) 23534d52a575SXin LI { 23544d52a575SXin LI struct et_softc *sc = arg1; 23554d52a575SXin LI struct ifnet *ifp = sc->ifp; 23564d52a575SXin LI int error = 0, v; 23574d52a575SXin LI 23584d52a575SXin LI v = sc->sc_rx_intr_npkts; 23594d52a575SXin LI error = sysctl_handle_int(oidp, &v, 0, req); 23604d52a575SXin LI if (error || req->newptr == NULL) 23614d52a575SXin LI goto back; 23624d52a575SXin LI if (v <= 0) { 23634d52a575SXin LI error = EINVAL; 23644d52a575SXin LI goto back; 23654d52a575SXin LI } 23664d52a575SXin LI 23674d52a575SXin LI if (sc->sc_rx_intr_npkts != v) { 23684d52a575SXin LI if (ifp->if_drv_flags & IFF_DRV_RUNNING) 23694d52a575SXin LI CSR_WRITE_4(sc, ET_RX_INTR_NPKTS, v); 23704d52a575SXin LI sc->sc_rx_intr_npkts = v; 23714d52a575SXin LI } 23724d52a575SXin LI back: 2373398f1b65SPyun YongHyeon return (error); 23744d52a575SXin LI } 23754d52a575SXin LI 23764d52a575SXin LI static int 23774d52a575SXin LI et_sysctl_rx_intr_delay(SYSCTL_HANDLER_ARGS) 23784d52a575SXin LI { 23794d52a575SXin LI struct et_softc *sc = arg1; 23804d52a575SXin LI struct ifnet *ifp = sc->ifp; 23814d52a575SXin LI int error = 0, v; 23824d52a575SXin LI 23834d52a575SXin LI v = sc->sc_rx_intr_delay; 23844d52a575SXin LI error = sysctl_handle_int(oidp, &v, 0, req); 23854d52a575SXin LI if (error || req->newptr == NULL) 23864d52a575SXin LI goto back; 23874d52a575SXin LI if (v <= 0) { 23884d52a575SXin LI error = EINVAL; 23894d52a575SXin LI goto back; 23904d52a575SXin LI } 23914d52a575SXin LI 23924d52a575SXin LI if (sc->sc_rx_intr_delay != v) { 23934d52a575SXin LI if (ifp->if_drv_flags & IFF_DRV_RUNNING) 23944d52a575SXin LI CSR_WRITE_4(sc, ET_RX_INTR_DELAY, v); 23954d52a575SXin LI sc->sc_rx_intr_delay = v; 23964d52a575SXin LI } 23974d52a575SXin LI back: 2398398f1b65SPyun YongHyeon return (error); 23994d52a575SXin LI } 24004d52a575SXin LI 24014d52a575SXin LI static void 24024d52a575SXin LI et_setmedia(struct et_softc *sc) 24034d52a575SXin LI { 24044d52a575SXin LI struct mii_data *mii = device_get_softc(sc->sc_miibus); 24054d52a575SXin LI uint32_t cfg2, ctrl; 24064d52a575SXin LI 24074d52a575SXin LI cfg2 = CSR_READ_4(sc, ET_MAC_CFG2); 24084d52a575SXin LI cfg2 &= ~(ET_MAC_CFG2_MODE_MII | ET_MAC_CFG2_MODE_GMII | 24094d52a575SXin LI ET_MAC_CFG2_FDX | ET_MAC_CFG2_BIGFRM); 24104d52a575SXin LI cfg2 |= ET_MAC_CFG2_LENCHK | ET_MAC_CFG2_CRC | ET_MAC_CFG2_PADCRC | 241123263665SPyun YongHyeon ((7 << ET_MAC_CFG2_PREAMBLE_LEN_SHIFT) & 241223263665SPyun YongHyeon ET_MAC_CFG2_PREAMBLE_LEN_MASK); 24134d52a575SXin LI 24144d52a575SXin LI ctrl = CSR_READ_4(sc, ET_MAC_CTRL); 24154d52a575SXin LI ctrl &= ~(ET_MAC_CTRL_GHDX | ET_MAC_CTRL_MODE_MII); 24164d52a575SXin LI 24174d52a575SXin LI if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { 24184d52a575SXin LI cfg2 |= ET_MAC_CFG2_MODE_GMII; 24194d52a575SXin LI } else { 24204d52a575SXin LI cfg2 |= ET_MAC_CFG2_MODE_MII; 24214d52a575SXin LI ctrl |= ET_MAC_CTRL_MODE_MII; 24224d52a575SXin LI } 24234d52a575SXin LI 24244d52a575SXin LI if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) 24254d52a575SXin LI cfg2 |= ET_MAC_CFG2_FDX; 24264d52a575SXin LI else 24274d52a575SXin LI ctrl |= ET_MAC_CTRL_GHDX; 24284d52a575SXin LI 24294d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CTRL, ctrl); 24304d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG2, cfg2); 24314d52a575SXin LI } 24324d52a575SXin LI 24330442028aSPyun YongHyeon static int 24340442028aSPyun YongHyeon et_suspend(device_t dev) 24350442028aSPyun YongHyeon { 24360442028aSPyun YongHyeon struct et_softc *sc; 24370442028aSPyun YongHyeon 24380442028aSPyun YongHyeon sc = device_get_softc(dev); 24390442028aSPyun YongHyeon ET_LOCK(sc); 24400442028aSPyun YongHyeon if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 24410442028aSPyun YongHyeon et_stop(sc); 24420442028aSPyun YongHyeon ET_UNLOCK(sc); 24430442028aSPyun YongHyeon return (0); 24440442028aSPyun YongHyeon } 24450442028aSPyun YongHyeon 24460442028aSPyun YongHyeon static int 24470442028aSPyun YongHyeon et_resume(device_t dev) 24480442028aSPyun YongHyeon { 24490442028aSPyun YongHyeon struct et_softc *sc; 24500442028aSPyun YongHyeon 24510442028aSPyun YongHyeon sc = device_get_softc(dev); 24520442028aSPyun YongHyeon ET_LOCK(sc); 24530442028aSPyun YongHyeon if ((sc->ifp->if_flags & IFF_UP) != 0) 24540442028aSPyun YongHyeon et_init_locked(sc); 24550442028aSPyun YongHyeon ET_UNLOCK(sc); 24560442028aSPyun YongHyeon return (0); 24570442028aSPyun YongHyeon } 2458