14d52a575SXin LI /*- 24d52a575SXin LI * Copyright (c) 2007 The DragonFly Project. 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 * $FreeBSD$ 364d52a575SXin LI */ 374d52a575SXin LI 384d52a575SXin LI #include <sys/param.h> 394d52a575SXin LI #include <sys/systm.h> 404d52a575SXin LI #include <sys/endian.h> 414d52a575SXin LI #include <sys/kernel.h> 424d52a575SXin LI #include <sys/bus.h> 434d52a575SXin LI #include <sys/malloc.h> 444d52a575SXin LI #include <sys/mbuf.h> 454d52a575SXin LI #include <sys/proc.h> 464d52a575SXin LI #include <sys/rman.h> 474d52a575SXin LI #include <sys/module.h> 484d52a575SXin LI #include <sys/socket.h> 494d52a575SXin LI #include <sys/sockio.h> 504d52a575SXin LI #include <sys/sysctl.h> 514d52a575SXin LI 524d52a575SXin LI #include <net/ethernet.h> 534d52a575SXin LI #include <net/if.h> 544d52a575SXin LI #include <net/if_dl.h> 554d52a575SXin LI #include <net/if_types.h> 564d52a575SXin LI #include <net/bpf.h> 574d52a575SXin LI #include <net/if_arp.h> 584d52a575SXin LI #include <net/if_dl.h> 594d52a575SXin LI #include <net/if_media.h> 604d52a575SXin LI #include <net/if_vlan_var.h> 614d52a575SXin LI 624d52a575SXin LI #include <machine/bus.h> 634d52a575SXin LI 644d52a575SXin LI #include <dev/mii/miivar.h> 654d52a575SXin LI #include <dev/mii/truephyreg.h> 664d52a575SXin LI 674d52a575SXin LI #include <dev/pci/pcireg.h> 684d52a575SXin LI #include <dev/pci/pcivar.h> 694d52a575SXin LI 704d52a575SXin LI #include <dev/et/if_etreg.h> 714d52a575SXin LI #include <dev/et/if_etvar.h> 724d52a575SXin LI 734d52a575SXin LI #include "miibus_if.h" 744d52a575SXin LI 754d52a575SXin LI MODULE_DEPEND(et, pci, 1, 1, 1); 764d52a575SXin LI MODULE_DEPEND(et, ether, 1, 1, 1); 774d52a575SXin LI MODULE_DEPEND(et, miibus, 1, 1, 1); 784d52a575SXin LI 79cc3c3b4eSPyun YongHyeon /* Tunables. */ 80cc3c3b4eSPyun YongHyeon static int msi_disable = 0; 81cc3c3b4eSPyun YongHyeon TUNABLE_INT("hw.re.msi_disable", &msi_disable); 82cc3c3b4eSPyun YongHyeon 834d52a575SXin LI static int et_probe(device_t); 844d52a575SXin LI static int et_attach(device_t); 854d52a575SXin LI static int et_detach(device_t); 864d52a575SXin LI static int et_shutdown(device_t); 874d52a575SXin LI 884d52a575SXin LI static int et_miibus_readreg(device_t, int, int); 894d52a575SXin LI static int et_miibus_writereg(device_t, int, int, int); 904d52a575SXin LI static void et_miibus_statchg(device_t); 914d52a575SXin LI 924d52a575SXin LI static void et_init_locked(struct et_softc *); 934d52a575SXin LI static void et_init(void *); 944d52a575SXin LI static int et_ioctl(struct ifnet *, u_long, caddr_t); 954d52a575SXin LI static void et_start_locked(struct ifnet *); 964d52a575SXin LI static void et_start(struct ifnet *); 974d52a575SXin LI static void et_watchdog(struct et_softc *); 984d52a575SXin LI static int et_ifmedia_upd_locked(struct ifnet *); 994d52a575SXin LI static int et_ifmedia_upd(struct ifnet *); 1004d52a575SXin LI static void et_ifmedia_sts(struct ifnet *, struct ifmediareq *); 1014d52a575SXin LI 1024d52a575SXin LI static void et_add_sysctls(struct et_softc *); 1034d52a575SXin LI static int et_sysctl_rx_intr_npkts(SYSCTL_HANDLER_ARGS); 1044d52a575SXin LI static int et_sysctl_rx_intr_delay(SYSCTL_HANDLER_ARGS); 1054d52a575SXin LI 1064d52a575SXin LI static void et_intr(void *); 1074d52a575SXin LI static void et_enable_intrs(struct et_softc *, uint32_t); 1084d52a575SXin LI static void et_disable_intrs(struct et_softc *); 1094d52a575SXin LI static void et_rxeof(struct et_softc *); 1104d52a575SXin LI static void et_txeof(struct et_softc *); 1114d52a575SXin LI 1124d52a575SXin LI static int et_dma_alloc(device_t); 1134d52a575SXin LI static void et_dma_free(device_t); 1144d52a575SXin LI static int et_dma_mem_create(device_t, bus_size_t, bus_dma_tag_t *, 1154d52a575SXin LI void **, bus_addr_t *, bus_dmamap_t *); 1164d52a575SXin LI static void et_dma_mem_destroy(bus_dma_tag_t, void *, bus_dmamap_t); 1174d52a575SXin LI static int et_dma_mbuf_create(device_t); 1184d52a575SXin LI static void et_dma_mbuf_destroy(device_t, int, const int[]); 1194d52a575SXin LI static void et_dma_ring_addr(void *, bus_dma_segment_t *, int, int); 1204d52a575SXin LI static void et_dma_buf_addr(void *, bus_dma_segment_t *, int, 1214d52a575SXin LI bus_size_t, int); 1224d52a575SXin LI static int et_init_tx_ring(struct et_softc *); 1234d52a575SXin LI static int et_init_rx_ring(struct et_softc *); 1244d52a575SXin LI static void et_free_tx_ring(struct et_softc *); 1254d52a575SXin LI static void et_free_rx_ring(struct et_softc *); 1264d52a575SXin LI static int et_encap(struct et_softc *, struct mbuf **); 1274d52a575SXin LI static int et_newbuf(struct et_rxbuf_data *, int, int, int); 1284d52a575SXin LI static int et_newbuf_cluster(struct et_rxbuf_data *, int, int); 1294d52a575SXin LI static int et_newbuf_hdr(struct et_rxbuf_data *, int, int); 1304d52a575SXin LI 1314d52a575SXin LI static void et_stop(struct et_softc *); 1324d52a575SXin LI static int et_chip_init(struct et_softc *); 1334d52a575SXin LI static void et_chip_attach(struct et_softc *); 1344d52a575SXin LI static void et_init_mac(struct et_softc *); 1354d52a575SXin LI static void et_init_rxmac(struct et_softc *); 1364d52a575SXin LI static void et_init_txmac(struct et_softc *); 1374d52a575SXin LI static int et_init_rxdma(struct et_softc *); 1384d52a575SXin LI static int et_init_txdma(struct et_softc *); 1394d52a575SXin LI static int et_start_rxdma(struct et_softc *); 1404d52a575SXin LI static int et_start_txdma(struct et_softc *); 1414d52a575SXin LI static int et_stop_rxdma(struct et_softc *); 1424d52a575SXin LI static int et_stop_txdma(struct et_softc *); 1434d52a575SXin LI static int et_enable_txrx(struct et_softc *, int); 1444d52a575SXin LI static void et_reset(struct et_softc *); 1458b3c6496SPyun YongHyeon static int et_bus_config(struct et_softc *); 1464d52a575SXin LI static void et_get_eaddr(device_t, uint8_t[]); 1474d52a575SXin LI static void et_setmulti(struct et_softc *); 1484d52a575SXin LI static void et_tick(void *); 1494d52a575SXin LI static void et_setmedia(struct et_softc *); 1504d52a575SXin LI static void et_setup_rxdesc(struct et_rxbuf_data *, int, bus_addr_t); 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), 1694d52a575SXin LI 1704d52a575SXin LI DEVMETHOD(bus_print_child, bus_generic_print_child), 1714d52a575SXin LI DEVMETHOD(bus_driver_added, bus_generic_driver_added), 1724d52a575SXin LI 1734d52a575SXin LI DEVMETHOD(miibus_readreg, et_miibus_readreg), 1744d52a575SXin LI DEVMETHOD(miibus_writereg, et_miibus_writereg), 1754d52a575SXin LI DEVMETHOD(miibus_statchg, et_miibus_statchg), 1764d52a575SXin LI 1774d52a575SXin LI { 0, 0 } 1784d52a575SXin LI }; 1794d52a575SXin LI 1804d52a575SXin LI static driver_t et_driver = { 1814d52a575SXin LI "et", 1824d52a575SXin LI et_methods, 1834d52a575SXin LI sizeof(struct et_softc) 1844d52a575SXin LI }; 1854d52a575SXin LI 1864d52a575SXin LI static devclass_t et_devclass; 1874d52a575SXin LI 1884d52a575SXin LI DRIVER_MODULE(et, pci, et_driver, et_devclass, 0, 0); 1894d52a575SXin LI DRIVER_MODULE(miibus, et, miibus_driver, miibus_devclass, 0, 0); 1904d52a575SXin LI 1914d52a575SXin LI static int et_rx_intr_npkts = 32; 1924d52a575SXin LI static int et_rx_intr_delay = 20; /* x10 usec */ 1934d52a575SXin LI static int et_tx_intr_nsegs = 126; 1944d52a575SXin LI static uint32_t et_timer = 1000 * 1000 * 1000; /* nanosec */ 1954d52a575SXin LI 1964d52a575SXin LI TUNABLE_INT("hw.et.timer", &et_timer); 1974d52a575SXin LI TUNABLE_INT("hw.et.rx_intr_npkts", &et_rx_intr_npkts); 1984d52a575SXin LI TUNABLE_INT("hw.et.rx_intr_delay", &et_rx_intr_delay); 1994d52a575SXin LI TUNABLE_INT("hw.et.tx_intr_nsegs", &et_tx_intr_nsegs); 2004d52a575SXin LI 2014d52a575SXin LI struct et_bsize { 2024d52a575SXin LI int bufsize; 2034d52a575SXin LI et_newbuf_t newbuf; 2044d52a575SXin LI }; 2054d52a575SXin LI 2064d52a575SXin LI static const struct et_bsize et_bufsize_std[ET_RX_NRING] = { 2074d52a575SXin LI { .bufsize = ET_RXDMA_CTRL_RING0_128, 2084d52a575SXin LI .newbuf = et_newbuf_hdr }, 2094d52a575SXin LI { .bufsize = ET_RXDMA_CTRL_RING1_2048, 2104d52a575SXin LI .newbuf = et_newbuf_cluster }, 2114d52a575SXin LI }; 2124d52a575SXin LI 2134d52a575SXin LI static int 2144d52a575SXin LI et_probe(device_t dev) 2154d52a575SXin LI { 2164d52a575SXin LI const struct et_dev *d; 2174d52a575SXin LI uint16_t did, vid; 2184d52a575SXin LI 2194d52a575SXin LI vid = pci_get_vendor(dev); 2204d52a575SXin LI did = pci_get_device(dev); 2214d52a575SXin LI 2224d52a575SXin LI for (d = et_devices; d->desc != NULL; ++d) { 2234d52a575SXin LI if (vid == d->vid && did == d->did) { 2244d52a575SXin LI device_set_desc(dev, d->desc); 225398f1b65SPyun YongHyeon return (0); 2264d52a575SXin LI } 2274d52a575SXin LI } 228398f1b65SPyun YongHyeon return (ENXIO); 2294d52a575SXin LI } 2304d52a575SXin LI 2314d52a575SXin LI static int 2324d52a575SXin LI et_attach(device_t dev) 2334d52a575SXin LI { 2344d52a575SXin LI struct et_softc *sc; 2354d52a575SXin LI struct ifnet *ifp; 2364d52a575SXin LI uint8_t eaddr[ETHER_ADDR_LEN]; 237cc3c3b4eSPyun YongHyeon int cap, error, msic; 2384d52a575SXin LI 2394d52a575SXin LI sc = device_get_softc(dev); 2404d52a575SXin LI sc->dev = dev; 2414d52a575SXin LI mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 2424d52a575SXin LI MTX_DEF); 2434d52a575SXin LI 2444d52a575SXin LI ifp = sc->ifp = if_alloc(IFT_ETHER); 2454d52a575SXin LI if (ifp == NULL) { 2464d52a575SXin LI device_printf(dev, "can not if_alloc()\n"); 2474d52a575SXin LI error = ENOSPC; 2484d52a575SXin LI goto fail; 2494d52a575SXin LI } 2504d52a575SXin LI 2514d52a575SXin LI /* 2524d52a575SXin LI * Initialize tunables 2534d52a575SXin LI */ 2544d52a575SXin LI sc->sc_rx_intr_npkts = et_rx_intr_npkts; 2554d52a575SXin LI sc->sc_rx_intr_delay = et_rx_intr_delay; 2564d52a575SXin LI sc->sc_tx_intr_nsegs = et_tx_intr_nsegs; 2574d52a575SXin LI sc->sc_timer = et_timer; 2584d52a575SXin LI 2594d52a575SXin LI /* Enable bus mastering */ 2604d52a575SXin LI pci_enable_busmaster(dev); 2614d52a575SXin LI 2624d52a575SXin LI /* 2634d52a575SXin LI * Allocate IO memory 2644d52a575SXin LI */ 2654d52a575SXin LI sc->sc_mem_rid = ET_PCIR_BAR; 2664d52a575SXin LI sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 2674d52a575SXin LI &sc->sc_mem_rid, RF_ACTIVE); 2684d52a575SXin LI if (sc->sc_mem_res == NULL) { 2694d52a575SXin LI device_printf(dev, "can't allocate IO memory\n"); 270398f1b65SPyun YongHyeon return (ENXIO); 2714d52a575SXin LI } 2724d52a575SXin LI 273cc3c3b4eSPyun YongHyeon msic = 0; 274cc3c3b4eSPyun YongHyeon if (pci_find_extcap(dev, PCIY_EXPRESS, &cap) == 0) { 275cc3c3b4eSPyun YongHyeon sc->sc_expcap = cap; 276cc3c3b4eSPyun YongHyeon sc->sc_flags |= ET_FLAG_PCIE; 277cc3c3b4eSPyun YongHyeon msic = pci_msi_count(dev); 278cc3c3b4eSPyun YongHyeon if (bootverbose) 279cc3c3b4eSPyun YongHyeon device_printf(dev, "MSI count : %d\n", msic); 280cc3c3b4eSPyun YongHyeon } 281cc3c3b4eSPyun YongHyeon if (msic > 0 && msi_disable == 0) { 282cc3c3b4eSPyun YongHyeon msic = 1; 283cc3c3b4eSPyun YongHyeon if (pci_alloc_msi(dev, &msic) == 0) { 284cc3c3b4eSPyun YongHyeon if (msic == 1) { 285cc3c3b4eSPyun YongHyeon device_printf(dev, "Using %d MSI message\n", 286cc3c3b4eSPyun YongHyeon msic); 287cc3c3b4eSPyun YongHyeon sc->sc_flags |= ET_FLAG_MSI; 288cc3c3b4eSPyun YongHyeon } else 289cc3c3b4eSPyun YongHyeon pci_release_msi(dev); 290cc3c3b4eSPyun YongHyeon } 291cc3c3b4eSPyun YongHyeon } 292cc3c3b4eSPyun YongHyeon 2934d52a575SXin LI /* 2944d52a575SXin LI * Allocate IRQ 2954d52a575SXin LI */ 296cc3c3b4eSPyun YongHyeon if ((sc->sc_flags & ET_FLAG_MSI) == 0) { 2974d52a575SXin LI sc->sc_irq_rid = 0; 2984d52a575SXin LI sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 299cc3c3b4eSPyun YongHyeon &sc->sc_irq_rid, RF_SHAREABLE | RF_ACTIVE); 300cc3c3b4eSPyun YongHyeon } else { 301cc3c3b4eSPyun YongHyeon sc->sc_irq_rid = 1; 302cc3c3b4eSPyun YongHyeon sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 303cc3c3b4eSPyun YongHyeon &sc->sc_irq_rid, RF_ACTIVE); 304cc3c3b4eSPyun YongHyeon } 3054d52a575SXin LI if (sc->sc_irq_res == NULL) { 3064d52a575SXin LI device_printf(dev, "can't allocate irq\n"); 3074d52a575SXin LI error = ENXIO; 3084d52a575SXin LI goto fail; 3094d52a575SXin LI } 3104d52a575SXin LI 3118b3c6496SPyun YongHyeon error = et_bus_config(sc); 3124d52a575SXin LI if (error) 3134d52a575SXin LI goto fail; 3144d52a575SXin LI 3154d52a575SXin LI et_get_eaddr(dev, eaddr); 3164d52a575SXin LI 3174d52a575SXin LI CSR_WRITE_4(sc, ET_PM, 3184d52a575SXin LI ET_PM_SYSCLK_GATE | ET_PM_TXCLK_GATE | ET_PM_RXCLK_GATE); 3194d52a575SXin LI 3204d52a575SXin LI et_reset(sc); 3214d52a575SXin LI 3224d52a575SXin LI et_disable_intrs(sc); 3234d52a575SXin LI 3244d52a575SXin LI error = et_dma_alloc(dev); 3254d52a575SXin LI if (error) 3264d52a575SXin LI goto fail; 3274d52a575SXin LI 3284d52a575SXin LI ifp->if_softc = sc; 3294d52a575SXin LI if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 3304d52a575SXin LI ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 3314d52a575SXin LI ifp->if_init = et_init; 3324d52a575SXin LI ifp->if_ioctl = et_ioctl; 3334d52a575SXin LI ifp->if_start = et_start; 3344d52a575SXin LI ifp->if_mtu = ETHERMTU; 3354d52a575SXin LI ifp->if_capabilities = IFCAP_VLAN_MTU; 3364d52a575SXin LI ifp->if_capenable = ifp->if_capabilities; 3374d52a575SXin LI IFQ_SET_MAXLEN(&ifp->if_snd, ET_TX_NDESC); 3384d52a575SXin LI IFQ_SET_READY(&ifp->if_snd); 3394d52a575SXin LI 3404d52a575SXin LI et_chip_attach(sc); 3414d52a575SXin LI 3424d52a575SXin LI error = mii_phy_probe(dev, &sc->sc_miibus, 3434d52a575SXin LI et_ifmedia_upd, et_ifmedia_sts); 3444d52a575SXin LI if (error) { 3454d52a575SXin LI device_printf(dev, "can't probe any PHY\n"); 3464d52a575SXin LI goto fail; 3474d52a575SXin LI } 3484d52a575SXin LI 3494d52a575SXin LI ether_ifattach(ifp, eaddr); 3504d52a575SXin LI callout_init_mtx(&sc->sc_tick, &sc->sc_mtx, 0); 3514d52a575SXin LI 3524d52a575SXin LI error = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_NET | INTR_MPSAFE, 3534d52a575SXin LI NULL, et_intr, sc, &sc->sc_irq_handle); 3544d52a575SXin LI if (error) { 3554d52a575SXin LI ether_ifdetach(ifp); 3564d52a575SXin LI device_printf(dev, "can't setup intr\n"); 3574d52a575SXin LI goto fail; 3584d52a575SXin LI } 3594d52a575SXin LI 3604d52a575SXin LI et_add_sysctls(sc); 3614d52a575SXin LI 362398f1b65SPyun YongHyeon return (0); 3634d52a575SXin LI fail: 3644d52a575SXin LI et_detach(dev); 365398f1b65SPyun YongHyeon return (error); 3664d52a575SXin LI } 3674d52a575SXin LI 3684d52a575SXin LI static int 3694d52a575SXin LI et_detach(device_t dev) 3704d52a575SXin LI { 3714d52a575SXin LI struct et_softc *sc = device_get_softc(dev); 3724d52a575SXin LI 3734d52a575SXin LI if (device_is_attached(dev)) { 3744d52a575SXin LI struct ifnet *ifp = sc->ifp; 3754d52a575SXin LI 3764d52a575SXin LI ET_LOCK(sc); 3774d52a575SXin LI et_stop(sc); 3784d52a575SXin LI bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_handle); 3794d52a575SXin LI ET_UNLOCK(sc); 3804d52a575SXin LI 3814d52a575SXin LI ether_ifdetach(ifp); 3824d52a575SXin LI } 3834d52a575SXin LI 3844d52a575SXin LI if (sc->sc_miibus != NULL) 3854d52a575SXin LI device_delete_child(dev, sc->sc_miibus); 3864d52a575SXin LI bus_generic_detach(dev); 3874d52a575SXin LI 3884d52a575SXin LI if (sc->sc_irq_res != NULL) { 3894d52a575SXin LI bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_rid, 3904d52a575SXin LI sc->sc_irq_res); 3914d52a575SXin LI } 392cc3c3b4eSPyun YongHyeon if ((sc->sc_flags & ET_FLAG_MSI) != 0) 393cc3c3b4eSPyun YongHyeon pci_release_msi(dev); 3944d52a575SXin LI 3954d52a575SXin LI if (sc->sc_mem_res != NULL) { 3964d52a575SXin LI bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, 3974d52a575SXin LI sc->sc_mem_res); 3984d52a575SXin LI } 3994d52a575SXin LI 4004d52a575SXin LI if (sc->ifp != NULL) 4014d52a575SXin LI if_free(sc->ifp); 4024d52a575SXin LI 4034d52a575SXin LI et_dma_free(dev); 4045b8f4900SPyun YongHyeon 4055b8f4900SPyun YongHyeon mtx_destroy(&sc->sc_mtx); 4064d52a575SXin LI 407398f1b65SPyun YongHyeon return (0); 4084d52a575SXin LI } 4094d52a575SXin LI 4104d52a575SXin LI static int 4114d52a575SXin LI et_shutdown(device_t dev) 4124d52a575SXin LI { 4134d52a575SXin LI struct et_softc *sc = device_get_softc(dev); 4144d52a575SXin LI 4154d52a575SXin LI ET_LOCK(sc); 4164d52a575SXin LI et_stop(sc); 4174d52a575SXin LI ET_UNLOCK(sc); 418398f1b65SPyun YongHyeon return (0); 4194d52a575SXin LI } 4204d52a575SXin LI 4214d52a575SXin LI static int 4224d52a575SXin LI et_miibus_readreg(device_t dev, int phy, int reg) 4234d52a575SXin LI { 4244d52a575SXin LI struct et_softc *sc = device_get_softc(dev); 4254d52a575SXin LI uint32_t val; 4264d52a575SXin LI int i, ret; 4274d52a575SXin LI 4284d52a575SXin LI /* Stop any pending operations */ 4294d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CMD, 0); 4304d52a575SXin LI 43123263665SPyun YongHyeon val = (phy << ET_MII_ADDR_PHY_SHIFT) & ET_MII_ADDR_PHY_MASK; 43223263665SPyun YongHyeon val |= (reg << ET_MII_ADDR_REG_SHIFT) & ET_MII_ADDR_REG_MASK; 4334d52a575SXin LI CSR_WRITE_4(sc, ET_MII_ADDR, val); 4344d52a575SXin LI 4354d52a575SXin LI /* Start reading */ 4364d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CMD, ET_MII_CMD_READ); 4374d52a575SXin LI 4384d52a575SXin LI #define NRETRY 50 4394d52a575SXin LI 4404d52a575SXin LI for (i = 0; i < NRETRY; ++i) { 4414d52a575SXin LI val = CSR_READ_4(sc, ET_MII_IND); 4424d52a575SXin LI if ((val & (ET_MII_IND_BUSY | ET_MII_IND_INVALID)) == 0) 4434d52a575SXin LI break; 4444d52a575SXin LI DELAY(50); 4454d52a575SXin LI } 4464d52a575SXin LI if (i == NRETRY) { 4474d52a575SXin LI if_printf(sc->ifp, 4484d52a575SXin LI "read phy %d, reg %d timed out\n", phy, reg); 4494d52a575SXin LI ret = 0; 4504d52a575SXin LI goto back; 4514d52a575SXin LI } 4524d52a575SXin LI 4534d52a575SXin LI #undef NRETRY 4544d52a575SXin LI 4554d52a575SXin LI val = CSR_READ_4(sc, ET_MII_STAT); 45623263665SPyun YongHyeon ret = val & ET_MII_STAT_VALUE_MASK; 4574d52a575SXin LI 4584d52a575SXin LI back: 4594d52a575SXin LI /* Make sure that the current operation is stopped */ 4604d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CMD, 0); 461398f1b65SPyun YongHyeon return (ret); 4624d52a575SXin LI } 4634d52a575SXin LI 4644d52a575SXin LI static int 4654d52a575SXin LI et_miibus_writereg(device_t dev, int phy, int reg, int val0) 4664d52a575SXin LI { 4674d52a575SXin LI struct et_softc *sc = device_get_softc(dev); 4684d52a575SXin LI uint32_t val; 4694d52a575SXin LI int i; 4704d52a575SXin LI 4714d52a575SXin LI /* Stop any pending operations */ 4724d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CMD, 0); 4734d52a575SXin LI 47423263665SPyun YongHyeon val = (phy << ET_MII_ADDR_PHY_SHIFT) & ET_MII_ADDR_PHY_MASK; 47523263665SPyun YongHyeon val |= (reg << ET_MII_ADDR_REG_SHIFT) & ET_MII_ADDR_REG_MASK; 4764d52a575SXin LI CSR_WRITE_4(sc, ET_MII_ADDR, val); 4774d52a575SXin LI 4784d52a575SXin LI /* Start writing */ 47923263665SPyun YongHyeon CSR_WRITE_4(sc, ET_MII_CTRL, 48023263665SPyun YongHyeon (val0 << ET_MII_CTRL_VALUE_SHIFT) & ET_MII_CTRL_VALUE_MASK); 4814d52a575SXin LI 4824d52a575SXin LI #define NRETRY 100 4834d52a575SXin LI 4844d52a575SXin LI for (i = 0; i < NRETRY; ++i) { 4854d52a575SXin LI val = CSR_READ_4(sc, ET_MII_IND); 4864d52a575SXin LI if ((val & ET_MII_IND_BUSY) == 0) 4874d52a575SXin LI break; 4884d52a575SXin LI DELAY(50); 4894d52a575SXin LI } 4904d52a575SXin LI if (i == NRETRY) { 4914d52a575SXin LI if_printf(sc->ifp, 4924d52a575SXin LI "write phy %d, reg %d timed out\n", phy, reg); 4934d52a575SXin LI et_miibus_readreg(dev, phy, reg); 4944d52a575SXin LI } 4954d52a575SXin LI 4964d52a575SXin LI #undef NRETRY 4974d52a575SXin LI 4984d52a575SXin LI /* Make sure that the current operation is stopped */ 4994d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CMD, 0); 500398f1b65SPyun YongHyeon return (0); 5014d52a575SXin LI } 5024d52a575SXin LI 5034d52a575SXin LI static void 5044d52a575SXin LI et_miibus_statchg(device_t dev) 5054d52a575SXin LI { 5064d52a575SXin LI et_setmedia(device_get_softc(dev)); 5074d52a575SXin LI } 5084d52a575SXin LI 5094d52a575SXin LI static int 5104d52a575SXin LI et_ifmedia_upd_locked(struct ifnet *ifp) 5114d52a575SXin LI { 5124d52a575SXin LI struct et_softc *sc = ifp->if_softc; 5134d52a575SXin LI struct mii_data *mii = device_get_softc(sc->sc_miibus); 5144d52a575SXin LI 5154d52a575SXin LI if (mii->mii_instance != 0) { 5164d52a575SXin LI struct mii_softc *miisc; 5174d52a575SXin LI 5184d52a575SXin LI LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 5194d52a575SXin LI mii_phy_reset(miisc); 5204d52a575SXin LI } 5214d52a575SXin LI mii_mediachg(mii); 5224d52a575SXin LI 523398f1b65SPyun YongHyeon return (0); 5244d52a575SXin LI } 5254d52a575SXin LI 5264d52a575SXin LI static int 5274d52a575SXin LI et_ifmedia_upd(struct ifnet *ifp) 5284d52a575SXin LI { 5294d52a575SXin LI struct et_softc *sc = ifp->if_softc; 5304d52a575SXin LI int res; 5314d52a575SXin LI 5324d52a575SXin LI ET_LOCK(sc); 5334d52a575SXin LI res = et_ifmedia_upd_locked(ifp); 5344d52a575SXin LI ET_UNLOCK(sc); 5354d52a575SXin LI 536398f1b65SPyun YongHyeon return (res); 5374d52a575SXin LI } 5384d52a575SXin LI 5394d52a575SXin LI static void 5404d52a575SXin LI et_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 5414d52a575SXin LI { 5424d52a575SXin LI struct et_softc *sc = ifp->if_softc; 5434d52a575SXin LI struct mii_data *mii = device_get_softc(sc->sc_miibus); 5444d52a575SXin LI 5454d52a575SXin LI mii_pollstat(mii); 5464d52a575SXin LI ifmr->ifm_active = mii->mii_media_active; 5474d52a575SXin LI ifmr->ifm_status = mii->mii_media_status; 5484d52a575SXin LI } 5494d52a575SXin LI 5504d52a575SXin LI static void 5514d52a575SXin LI et_stop(struct et_softc *sc) 5524d52a575SXin LI { 5534d52a575SXin LI struct ifnet *ifp = sc->ifp; 5544d52a575SXin LI 5554d52a575SXin LI ET_LOCK_ASSERT(sc); 5564d52a575SXin LI 5574d52a575SXin LI callout_stop(&sc->sc_tick); 5584d52a575SXin LI 5594d52a575SXin LI et_stop_rxdma(sc); 5604d52a575SXin LI et_stop_txdma(sc); 5614d52a575SXin LI 5624d52a575SXin LI et_disable_intrs(sc); 5634d52a575SXin LI 5644d52a575SXin LI et_free_tx_ring(sc); 5654d52a575SXin LI et_free_rx_ring(sc); 5664d52a575SXin LI 5674d52a575SXin LI et_reset(sc); 5684d52a575SXin LI 5694d52a575SXin LI sc->sc_tx = 0; 5704d52a575SXin LI sc->sc_tx_intr = 0; 5714d52a575SXin LI sc->sc_flags &= ~ET_FLAG_TXRX_ENABLED; 5724d52a575SXin LI 5734d52a575SXin LI sc->watchdog_timer = 0; 5744d52a575SXin LI ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 5754d52a575SXin LI } 5764d52a575SXin LI 5774d52a575SXin LI static int 5788b3c6496SPyun YongHyeon et_bus_config(struct et_softc *sc) 5794d52a575SXin LI { 5804d52a575SXin LI uint32_t val, max_plsz; 5814d52a575SXin LI uint16_t ack_latency, replay_timer; 5824d52a575SXin LI 5834d52a575SXin LI /* 5844d52a575SXin LI * Test whether EEPROM is valid 5854d52a575SXin LI * NOTE: Read twice to get the correct value 5864d52a575SXin LI */ 5878b3c6496SPyun YongHyeon pci_read_config(sc->dev, ET_PCIR_EEPROM_STATUS, 1); 5888b3c6496SPyun YongHyeon val = pci_read_config(sc->dev, ET_PCIR_EEPROM_STATUS, 1); 5894d52a575SXin LI if (val & ET_PCIM_EEPROM_STATUS_ERROR) { 5908b3c6496SPyun YongHyeon device_printf(sc->dev, "EEPROM status error 0x%02x\n", val); 591398f1b65SPyun YongHyeon return (ENXIO); 5924d52a575SXin LI } 5934d52a575SXin LI 5944d52a575SXin LI /* TODO: LED */ 5954d52a575SXin LI 5968b3c6496SPyun YongHyeon if ((sc->sc_flags & ET_FLAG_PCIE) == 0) 5978b3c6496SPyun YongHyeon return (0); 5988b3c6496SPyun YongHyeon 5994d52a575SXin LI /* 6004d52a575SXin LI * Configure ACK latency and replay timer according to 6014d52a575SXin LI * max playload size 6024d52a575SXin LI */ 6038b3c6496SPyun YongHyeon val = pci_read_config(sc->dev, 6048b3c6496SPyun YongHyeon sc->sc_expcap + PCIR_EXPRESS_DEVICE_CAP, 4); 6058b3c6496SPyun YongHyeon max_plsz = val & PCIM_EXP_CAP_MAX_PAYLOAD; 6064d52a575SXin LI 6074d52a575SXin LI switch (max_plsz) { 6084d52a575SXin LI case ET_PCIV_DEVICE_CAPS_PLSZ_128: 6094d52a575SXin LI ack_latency = ET_PCIV_ACK_LATENCY_128; 6104d52a575SXin LI replay_timer = ET_PCIV_REPLAY_TIMER_128; 6114d52a575SXin LI break; 6124d52a575SXin LI 6134d52a575SXin LI case ET_PCIV_DEVICE_CAPS_PLSZ_256: 6144d52a575SXin LI ack_latency = ET_PCIV_ACK_LATENCY_256; 6154d52a575SXin LI replay_timer = ET_PCIV_REPLAY_TIMER_256; 6164d52a575SXin LI break; 6174d52a575SXin LI 6184d52a575SXin LI default: 6198b3c6496SPyun YongHyeon ack_latency = pci_read_config(sc->dev, ET_PCIR_ACK_LATENCY, 2); 6208b3c6496SPyun YongHyeon replay_timer = pci_read_config(sc->dev, 6218b3c6496SPyun YongHyeon ET_PCIR_REPLAY_TIMER, 2); 6228b3c6496SPyun YongHyeon device_printf(sc->dev, "ack latency %u, replay timer %u\n", 6234d52a575SXin LI ack_latency, replay_timer); 6244d52a575SXin LI break; 6254d52a575SXin LI } 6264d52a575SXin LI if (ack_latency != 0) { 6278b3c6496SPyun YongHyeon pci_write_config(sc->dev, ET_PCIR_ACK_LATENCY, ack_latency, 2); 6288b3c6496SPyun YongHyeon pci_write_config(sc->dev, ET_PCIR_REPLAY_TIMER, replay_timer, 6298b3c6496SPyun YongHyeon 2); 6304d52a575SXin LI } 6314d52a575SXin LI 6324d52a575SXin LI /* 6334d52a575SXin LI * Set L0s and L1 latency timer to 2us 6344d52a575SXin LI */ 6358b3c6496SPyun YongHyeon val = pci_read_config(sc->dev, ET_PCIR_L0S_L1_LATENCY, 4); 63623263665SPyun YongHyeon val &= ~(PCIM_LINK_CAP_L0S_EXIT | PCIM_LINK_CAP_L1_EXIT); 63723263665SPyun YongHyeon /* L0s exit latency : 2us */ 63823263665SPyun YongHyeon val |= 0x00005000; 63923263665SPyun YongHyeon /* L1 exit latency : 2us */ 64023263665SPyun YongHyeon val |= 0x00028000; 6418b3c6496SPyun YongHyeon pci_write_config(sc->dev, ET_PCIR_L0S_L1_LATENCY, val, 4); 6424d52a575SXin LI 6434d52a575SXin LI /* 6444d52a575SXin LI * Set max read request size to 2048 bytes 6454d52a575SXin LI */ 6468b3c6496SPyun YongHyeon val = pci_read_config(sc->dev, 6478b3c6496SPyun YongHyeon sc->sc_expcap + PCIR_EXPRESS_DEVICE_CTL, 2); 6488b3c6496SPyun YongHyeon val &= ~PCIM_EXP_CTL_MAX_READ_REQUEST; 6494d52a575SXin LI val |= ET_PCIV_DEVICE_CTRL_RRSZ_2K; 6508b3c6496SPyun YongHyeon pci_write_config(sc->dev, 6518b3c6496SPyun YongHyeon sc->sc_expcap + PCIR_EXPRESS_DEVICE_CTL, val, 2); 6524d52a575SXin LI 653398f1b65SPyun YongHyeon return (0); 6544d52a575SXin LI } 6554d52a575SXin LI 6564d52a575SXin LI static void 6574d52a575SXin LI et_get_eaddr(device_t dev, uint8_t eaddr[]) 6584d52a575SXin LI { 6594d52a575SXin LI uint32_t val; 6604d52a575SXin LI int i; 6614d52a575SXin LI 6624d52a575SXin LI val = pci_read_config(dev, ET_PCIR_MAC_ADDR0, 4); 6634d52a575SXin LI for (i = 0; i < 4; ++i) 6644d52a575SXin LI eaddr[i] = (val >> (8 * i)) & 0xff; 6654d52a575SXin LI 6664d52a575SXin LI val = pci_read_config(dev, ET_PCIR_MAC_ADDR1, 2); 6674d52a575SXin LI for (; i < ETHER_ADDR_LEN; ++i) 6684d52a575SXin LI eaddr[i] = (val >> (8 * (i - 4))) & 0xff; 6694d52a575SXin LI } 6704d52a575SXin LI 6714d52a575SXin LI static void 6724d52a575SXin LI et_reset(struct et_softc *sc) 6734d52a575SXin LI { 6744d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 6754d52a575SXin LI ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 6764d52a575SXin LI ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | 6774d52a575SXin LI ET_MAC_CFG1_SIM_RST | ET_MAC_CFG1_SOFT_RST); 6784d52a575SXin LI 6794d52a575SXin LI CSR_WRITE_4(sc, ET_SWRST, 6804d52a575SXin LI ET_SWRST_TXDMA | ET_SWRST_RXDMA | 6814d52a575SXin LI ET_SWRST_TXMAC | ET_SWRST_RXMAC | 6824d52a575SXin LI ET_SWRST_MAC | ET_SWRST_MAC_STAT | ET_SWRST_MMC); 6834d52a575SXin LI 6844d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 6854d52a575SXin LI ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 6864d52a575SXin LI ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC); 6874d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 0); 6884d52a575SXin LI } 6894d52a575SXin LI 6904d52a575SXin LI static void 6914d52a575SXin LI et_disable_intrs(struct et_softc *sc) 6924d52a575SXin LI { 6934d52a575SXin LI CSR_WRITE_4(sc, ET_INTR_MASK, 0xffffffff); 6944d52a575SXin LI } 6954d52a575SXin LI 6964d52a575SXin LI static void 6974d52a575SXin LI et_enable_intrs(struct et_softc *sc, uint32_t intrs) 6984d52a575SXin LI { 6994d52a575SXin LI CSR_WRITE_4(sc, ET_INTR_MASK, ~intrs); 7004d52a575SXin LI } 7014d52a575SXin LI 7024d52a575SXin LI static int 7034d52a575SXin LI et_dma_alloc(device_t dev) 7044d52a575SXin LI { 7054d52a575SXin LI struct et_softc *sc = device_get_softc(dev); 7064d52a575SXin LI struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 7074d52a575SXin LI struct et_txstatus_data *txsd = &sc->sc_tx_status; 7084d52a575SXin LI struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring; 7094d52a575SXin LI struct et_rxstatus_data *rxsd = &sc->sc_rx_status; 7104d52a575SXin LI int i, error; 7114d52a575SXin LI 7124d52a575SXin LI /* 7134d52a575SXin LI * Create top level DMA tag 7144d52a575SXin LI */ 7154d52a575SXin LI error = bus_dma_tag_create(NULL, 1, 0, 7164d52a575SXin LI BUS_SPACE_MAXADDR_32BIT, 7174d52a575SXin LI BUS_SPACE_MAXADDR, 7184d52a575SXin LI NULL, NULL, 7194d52a575SXin LI MAXBSIZE, 7204d52a575SXin LI BUS_SPACE_UNRESTRICTED, 7214d52a575SXin LI BUS_SPACE_MAXSIZE_32BIT, 7224d52a575SXin LI 0, NULL, NULL, &sc->sc_dtag); 7234d52a575SXin LI if (error) { 7244d52a575SXin LI device_printf(dev, "can't create DMA tag\n"); 725398f1b65SPyun YongHyeon return (error); 7264d52a575SXin LI } 7274d52a575SXin LI 7284d52a575SXin LI /* 7294d52a575SXin LI * Create TX ring DMA stuffs 7304d52a575SXin LI */ 7314d52a575SXin LI error = et_dma_mem_create(dev, ET_TX_RING_SIZE, &tx_ring->tr_dtag, 7324d52a575SXin LI (void **)&tx_ring->tr_desc, 7334d52a575SXin LI &tx_ring->tr_paddr, &tx_ring->tr_dmap); 7344d52a575SXin LI if (error) { 7354d52a575SXin LI device_printf(dev, "can't create TX ring DMA stuffs\n"); 736398f1b65SPyun YongHyeon return (error); 7374d52a575SXin LI } 7384d52a575SXin LI 7394d52a575SXin LI /* 7404d52a575SXin LI * Create TX status DMA stuffs 7414d52a575SXin LI */ 7424d52a575SXin LI error = et_dma_mem_create(dev, sizeof(uint32_t), &txsd->txsd_dtag, 7434d52a575SXin LI (void **)&txsd->txsd_status, 7444d52a575SXin LI &txsd->txsd_paddr, &txsd->txsd_dmap); 7454d52a575SXin LI if (error) { 7464d52a575SXin LI device_printf(dev, "can't create TX status DMA stuffs\n"); 747398f1b65SPyun YongHyeon return (error); 7484d52a575SXin LI } 7494d52a575SXin LI 7504d52a575SXin LI /* 7514d52a575SXin LI * Create DMA stuffs for RX rings 7524d52a575SXin LI */ 7534d52a575SXin LI for (i = 0; i < ET_RX_NRING; ++i) { 7544d52a575SXin LI static const uint32_t rx_ring_posreg[ET_RX_NRING] = 7554d52a575SXin LI { ET_RX_RING0_POS, ET_RX_RING1_POS }; 7564d52a575SXin LI 7574d52a575SXin LI struct et_rxdesc_ring *rx_ring = &sc->sc_rx_ring[i]; 7584d52a575SXin LI 7594d52a575SXin LI error = et_dma_mem_create(dev, ET_RX_RING_SIZE, 7604d52a575SXin LI &rx_ring->rr_dtag, 7614d52a575SXin LI (void **)&rx_ring->rr_desc, 7624d52a575SXin LI &rx_ring->rr_paddr, 7634d52a575SXin LI &rx_ring->rr_dmap); 7644d52a575SXin LI if (error) { 7654d52a575SXin LI device_printf(dev, "can't create DMA stuffs for " 7664d52a575SXin LI "the %d RX ring\n", i); 767398f1b65SPyun YongHyeon return (error); 7684d52a575SXin LI } 7694d52a575SXin LI rx_ring->rr_posreg = rx_ring_posreg[i]; 7704d52a575SXin LI } 7714d52a575SXin LI 7724d52a575SXin LI /* 7734d52a575SXin LI * Create RX stat ring DMA stuffs 7744d52a575SXin LI */ 7754d52a575SXin LI error = et_dma_mem_create(dev, ET_RXSTAT_RING_SIZE, 7764d52a575SXin LI &rxst_ring->rsr_dtag, 7774d52a575SXin LI (void **)&rxst_ring->rsr_stat, 7784d52a575SXin LI &rxst_ring->rsr_paddr, &rxst_ring->rsr_dmap); 7794d52a575SXin LI if (error) { 7804d52a575SXin LI device_printf(dev, "can't create RX stat ring DMA stuffs\n"); 781398f1b65SPyun YongHyeon return (error); 7824d52a575SXin LI } 7834d52a575SXin LI 7844d52a575SXin LI /* 7854d52a575SXin LI * Create RX status DMA stuffs 7864d52a575SXin LI */ 7874d52a575SXin LI error = et_dma_mem_create(dev, sizeof(struct et_rxstatus), 7884d52a575SXin LI &rxsd->rxsd_dtag, 7894d52a575SXin LI (void **)&rxsd->rxsd_status, 7904d52a575SXin LI &rxsd->rxsd_paddr, &rxsd->rxsd_dmap); 7914d52a575SXin LI if (error) { 7924d52a575SXin LI device_printf(dev, "can't create RX status DMA stuffs\n"); 793398f1b65SPyun YongHyeon return (error); 7944d52a575SXin LI } 7954d52a575SXin LI 7964d52a575SXin LI /* 7974d52a575SXin LI * Create mbuf DMA stuffs 7984d52a575SXin LI */ 7994d52a575SXin LI error = et_dma_mbuf_create(dev); 8004d52a575SXin LI if (error) 801398f1b65SPyun YongHyeon return (error); 8024d52a575SXin LI 803398f1b65SPyun YongHyeon return (0); 8044d52a575SXin LI } 8054d52a575SXin LI 8064d52a575SXin LI static void 8074d52a575SXin LI et_dma_free(device_t dev) 8084d52a575SXin LI { 8094d52a575SXin LI struct et_softc *sc = device_get_softc(dev); 8104d52a575SXin LI struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 8114d52a575SXin LI struct et_txstatus_data *txsd = &sc->sc_tx_status; 8124d52a575SXin LI struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring; 8134d52a575SXin LI struct et_rxstatus_data *rxsd = &sc->sc_rx_status; 8144d52a575SXin LI int i, rx_done[ET_RX_NRING]; 8154d52a575SXin LI 8164d52a575SXin LI /* 8174d52a575SXin LI * Destroy TX ring DMA stuffs 8184d52a575SXin LI */ 8194d52a575SXin LI et_dma_mem_destroy(tx_ring->tr_dtag, tx_ring->tr_desc, 8204d52a575SXin LI tx_ring->tr_dmap); 8214d52a575SXin LI 8224d52a575SXin LI /* 8234d52a575SXin LI * Destroy TX status DMA stuffs 8244d52a575SXin LI */ 8254d52a575SXin LI et_dma_mem_destroy(txsd->txsd_dtag, txsd->txsd_status, 8264d52a575SXin LI txsd->txsd_dmap); 8274d52a575SXin LI 8284d52a575SXin LI /* 8294d52a575SXin LI * Destroy DMA stuffs for RX rings 8304d52a575SXin LI */ 8314d52a575SXin LI for (i = 0; i < ET_RX_NRING; ++i) { 8324d52a575SXin LI struct et_rxdesc_ring *rx_ring = &sc->sc_rx_ring[i]; 8334d52a575SXin LI 8344d52a575SXin LI et_dma_mem_destroy(rx_ring->rr_dtag, rx_ring->rr_desc, 8354d52a575SXin LI rx_ring->rr_dmap); 8364d52a575SXin LI } 8374d52a575SXin LI 8384d52a575SXin LI /* 8394d52a575SXin LI * Destroy RX stat ring DMA stuffs 8404d52a575SXin LI */ 8414d52a575SXin LI et_dma_mem_destroy(rxst_ring->rsr_dtag, rxst_ring->rsr_stat, 8424d52a575SXin LI rxst_ring->rsr_dmap); 8434d52a575SXin LI 8444d52a575SXin LI /* 8454d52a575SXin LI * Destroy RX status DMA stuffs 8464d52a575SXin LI */ 8474d52a575SXin LI et_dma_mem_destroy(rxsd->rxsd_dtag, rxsd->rxsd_status, 8484d52a575SXin LI rxsd->rxsd_dmap); 8494d52a575SXin LI 8504d52a575SXin LI /* 8514d52a575SXin LI * Destroy mbuf DMA stuffs 8524d52a575SXin LI */ 8534d52a575SXin LI for (i = 0; i < ET_RX_NRING; ++i) 8544d52a575SXin LI rx_done[i] = ET_RX_NDESC; 8554d52a575SXin LI et_dma_mbuf_destroy(dev, ET_TX_NDESC, rx_done); 8564d52a575SXin LI 8574d52a575SXin LI /* 8584d52a575SXin LI * Destroy top level DMA tag 8594d52a575SXin LI */ 8604d52a575SXin LI if (sc->sc_dtag != NULL) 8614d52a575SXin LI bus_dma_tag_destroy(sc->sc_dtag); 8624d52a575SXin LI } 8634d52a575SXin LI 8644d52a575SXin LI static int 8654d52a575SXin LI et_dma_mbuf_create(device_t dev) 8664d52a575SXin LI { 8674d52a575SXin LI struct et_softc *sc = device_get_softc(dev); 8684d52a575SXin LI struct et_txbuf_data *tbd = &sc->sc_tx_data; 8694d52a575SXin LI int i, error, rx_done[ET_RX_NRING]; 8704d52a575SXin LI 8714d52a575SXin LI /* 8724d52a575SXin LI * Create mbuf DMA tag 8734d52a575SXin LI */ 8744d52a575SXin LI error = bus_dma_tag_create(sc->sc_dtag, 1, 0, 8754d52a575SXin LI BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 8764d52a575SXin LI NULL, NULL, 8774d52a575SXin LI ET_JUMBO_FRAMELEN, ET_NSEG_MAX, 8784d52a575SXin LI BUS_SPACE_MAXSIZE_32BIT, 8794d52a575SXin LI BUS_DMA_ALLOCNOW, NULL, NULL, &sc->sc_mbuf_dtag); 8804d52a575SXin LI if (error) { 8814d52a575SXin LI device_printf(dev, "can't create mbuf DMA tag\n"); 882398f1b65SPyun YongHyeon return (error); 8834d52a575SXin LI } 8844d52a575SXin LI 8854d52a575SXin LI /* 8864d52a575SXin LI * Create spare DMA map for RX mbufs 8874d52a575SXin LI */ 8884d52a575SXin LI error = bus_dmamap_create(sc->sc_mbuf_dtag, 0, &sc->sc_mbuf_tmp_dmap); 8894d52a575SXin LI if (error) { 8904d52a575SXin LI device_printf(dev, "can't create spare mbuf DMA map\n"); 8914d52a575SXin LI bus_dma_tag_destroy(sc->sc_mbuf_dtag); 8924d52a575SXin LI sc->sc_mbuf_dtag = NULL; 893398f1b65SPyun YongHyeon return (error); 8944d52a575SXin LI } 8954d52a575SXin LI 8964d52a575SXin LI /* 8974d52a575SXin LI * Create DMA maps for RX mbufs 8984d52a575SXin LI */ 8994d52a575SXin LI bzero(rx_done, sizeof(rx_done)); 9004d52a575SXin LI for (i = 0; i < ET_RX_NRING; ++i) { 9014d52a575SXin LI struct et_rxbuf_data *rbd = &sc->sc_rx_data[i]; 9024d52a575SXin LI int j; 9034d52a575SXin LI 9044d52a575SXin LI for (j = 0; j < ET_RX_NDESC; ++j) { 9054d52a575SXin LI error = bus_dmamap_create(sc->sc_mbuf_dtag, 0, 9064d52a575SXin LI &rbd->rbd_buf[j].rb_dmap); 9074d52a575SXin LI if (error) { 9084d52a575SXin LI device_printf(dev, "can't create %d RX mbuf " 9094d52a575SXin LI "for %d RX ring\n", j, i); 9104d52a575SXin LI rx_done[i] = j; 9114d52a575SXin LI et_dma_mbuf_destroy(dev, 0, rx_done); 912398f1b65SPyun YongHyeon return (error); 9134d52a575SXin LI } 9144d52a575SXin LI } 9154d52a575SXin LI rx_done[i] = ET_RX_NDESC; 9164d52a575SXin LI 9174d52a575SXin LI rbd->rbd_softc = sc; 9184d52a575SXin LI rbd->rbd_ring = &sc->sc_rx_ring[i]; 9194d52a575SXin LI } 9204d52a575SXin LI 9214d52a575SXin LI /* 9224d52a575SXin LI * Create DMA maps for TX mbufs 9234d52a575SXin LI */ 9244d52a575SXin LI for (i = 0; i < ET_TX_NDESC; ++i) { 9254d52a575SXin LI error = bus_dmamap_create(sc->sc_mbuf_dtag, 0, 9264d52a575SXin LI &tbd->tbd_buf[i].tb_dmap); 9274d52a575SXin LI if (error) { 9284d52a575SXin LI device_printf(dev, "can't create %d TX mbuf " 9294d52a575SXin LI "DMA map\n", i); 9304d52a575SXin LI et_dma_mbuf_destroy(dev, i, rx_done); 931398f1b65SPyun YongHyeon return (error); 9324d52a575SXin LI } 9334d52a575SXin LI } 9344d52a575SXin LI 935398f1b65SPyun YongHyeon return (0); 9364d52a575SXin LI } 9374d52a575SXin LI 9384d52a575SXin LI static void 9394d52a575SXin LI et_dma_mbuf_destroy(device_t dev, int tx_done, const int rx_done[]) 9404d52a575SXin LI { 9414d52a575SXin LI struct et_softc *sc = device_get_softc(dev); 9424d52a575SXin LI struct et_txbuf_data *tbd = &sc->sc_tx_data; 9434d52a575SXin LI int i; 9444d52a575SXin LI 9454d52a575SXin LI if (sc->sc_mbuf_dtag == NULL) 9464d52a575SXin LI return; 9474d52a575SXin LI 9484d52a575SXin LI /* 9494d52a575SXin LI * Destroy DMA maps for RX mbufs 9504d52a575SXin LI */ 9514d52a575SXin LI for (i = 0; i < ET_RX_NRING; ++i) { 9524d52a575SXin LI struct et_rxbuf_data *rbd = &sc->sc_rx_data[i]; 9534d52a575SXin LI int j; 9544d52a575SXin LI 9554d52a575SXin LI for (j = 0; j < rx_done[i]; ++j) { 9564d52a575SXin LI struct et_rxbuf *rb = &rbd->rbd_buf[j]; 9574d52a575SXin LI 9584d52a575SXin LI KASSERT(rb->rb_mbuf == NULL, 9594d52a575SXin LI ("RX mbuf in %d RX ring is not freed yet\n", i)); 9604d52a575SXin LI bus_dmamap_destroy(sc->sc_mbuf_dtag, rb->rb_dmap); 9614d52a575SXin LI } 9624d52a575SXin LI } 9634d52a575SXin LI 9644d52a575SXin LI /* 9654d52a575SXin LI * Destroy DMA maps for TX mbufs 9664d52a575SXin LI */ 9674d52a575SXin LI for (i = 0; i < tx_done; ++i) { 9684d52a575SXin LI struct et_txbuf *tb = &tbd->tbd_buf[i]; 9694d52a575SXin LI 9704d52a575SXin LI KASSERT(tb->tb_mbuf == NULL, ("TX mbuf is not freed yet\n")); 9714d52a575SXin LI bus_dmamap_destroy(sc->sc_mbuf_dtag, tb->tb_dmap); 9724d52a575SXin LI } 9734d52a575SXin LI 9744d52a575SXin LI /* 9754d52a575SXin LI * Destroy spare mbuf DMA map 9764d52a575SXin LI */ 9774d52a575SXin LI bus_dmamap_destroy(sc->sc_mbuf_dtag, sc->sc_mbuf_tmp_dmap); 9784d52a575SXin LI 9794d52a575SXin LI /* 9804d52a575SXin LI * Destroy mbuf DMA tag 9814d52a575SXin LI */ 9824d52a575SXin LI bus_dma_tag_destroy(sc->sc_mbuf_dtag); 9834d52a575SXin LI sc->sc_mbuf_dtag = NULL; 9844d52a575SXin LI } 9854d52a575SXin LI 9864d52a575SXin LI static int 9874d52a575SXin LI et_dma_mem_create(device_t dev, bus_size_t size, bus_dma_tag_t *dtag, 9884d52a575SXin LI void **addr, bus_addr_t *paddr, bus_dmamap_t *dmap) 9894d52a575SXin LI { 9904d52a575SXin LI struct et_softc *sc = device_get_softc(dev); 9914d52a575SXin LI int error; 9924d52a575SXin LI 9934d52a575SXin LI error = bus_dma_tag_create(sc->sc_dtag, ET_ALIGN, 0, 9944d52a575SXin LI BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 9954d52a575SXin LI NULL, NULL, 9964d52a575SXin LI size, 1, BUS_SPACE_MAXSIZE_32BIT, 9974d52a575SXin LI 0, NULL, NULL, dtag); 9984d52a575SXin LI if (error) { 9994d52a575SXin LI device_printf(dev, "can't create DMA tag\n"); 1000398f1b65SPyun YongHyeon return (error); 10014d52a575SXin LI } 10024d52a575SXin LI 10034d52a575SXin LI error = bus_dmamem_alloc(*dtag, addr, BUS_DMA_WAITOK | BUS_DMA_ZERO, 10044d52a575SXin LI dmap); 10054d52a575SXin LI if (error) { 10064d52a575SXin LI device_printf(dev, "can't allocate DMA mem\n"); 10074d52a575SXin LI bus_dma_tag_destroy(*dtag); 10084d52a575SXin LI *dtag = NULL; 1009398f1b65SPyun YongHyeon return (error); 10104d52a575SXin LI } 10114d52a575SXin LI 10124d52a575SXin LI error = bus_dmamap_load(*dtag, *dmap, *addr, size, 10134d52a575SXin LI et_dma_ring_addr, paddr, BUS_DMA_WAITOK); 10144d52a575SXin LI if (error) { 10154d52a575SXin LI device_printf(dev, "can't load DMA mem\n"); 10164d52a575SXin LI bus_dmamem_free(*dtag, *addr, *dmap); 10174d52a575SXin LI bus_dma_tag_destroy(*dtag); 10184d52a575SXin LI *dtag = NULL; 1019398f1b65SPyun YongHyeon return (error); 10204d52a575SXin LI } 1021398f1b65SPyun YongHyeon return (0); 10224d52a575SXin LI } 10234d52a575SXin LI 10244d52a575SXin LI static void 10254d52a575SXin LI et_dma_mem_destroy(bus_dma_tag_t dtag, void *addr, bus_dmamap_t dmap) 10264d52a575SXin LI { 10274d52a575SXin LI if (dtag != NULL) { 10284d52a575SXin LI bus_dmamap_unload(dtag, dmap); 10294d52a575SXin LI bus_dmamem_free(dtag, addr, dmap); 10304d52a575SXin LI bus_dma_tag_destroy(dtag); 10314d52a575SXin LI } 10324d52a575SXin LI } 10334d52a575SXin LI 10344d52a575SXin LI static void 10354d52a575SXin LI et_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error) 10364d52a575SXin LI { 10374d52a575SXin LI KASSERT(nseg == 1, ("too many segments\n")); 10384d52a575SXin LI *((bus_addr_t *)arg) = seg->ds_addr; 10394d52a575SXin LI } 10404d52a575SXin LI 10414d52a575SXin LI static void 10424d52a575SXin LI et_chip_attach(struct et_softc *sc) 10434d52a575SXin LI { 10444d52a575SXin LI uint32_t val; 10454d52a575SXin LI 10464d52a575SXin LI /* 10474d52a575SXin LI * Perform minimal initialization 10484d52a575SXin LI */ 10494d52a575SXin LI 10504d52a575SXin LI /* Disable loopback */ 10514d52a575SXin LI CSR_WRITE_4(sc, ET_LOOPBACK, 0); 10524d52a575SXin LI 10534d52a575SXin LI /* Reset MAC */ 10544d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 10554d52a575SXin LI ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 10564d52a575SXin LI ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | 10574d52a575SXin LI ET_MAC_CFG1_SIM_RST | ET_MAC_CFG1_SOFT_RST); 10584d52a575SXin LI 10594d52a575SXin LI /* 10604d52a575SXin LI * Setup half duplex mode 10614d52a575SXin LI */ 106223263665SPyun YongHyeon val = (10 << ET_MAC_HDX_ALT_BEB_TRUNC_SHIFT) | 106323263665SPyun YongHyeon (15 << ET_MAC_HDX_REXMIT_MAX_SHIFT) | 106423263665SPyun YongHyeon (55 << ET_MAC_HDX_COLLWIN_SHIFT) | 10654d52a575SXin LI ET_MAC_HDX_EXC_DEFER; 10664d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_HDX, val); 10674d52a575SXin LI 10684d52a575SXin LI /* Clear MAC control */ 10694d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CTRL, 0); 10704d52a575SXin LI 10714d52a575SXin LI /* Reset MII */ 10724d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CFG, ET_MII_CFG_CLKRST); 10734d52a575SXin LI 10744d52a575SXin LI /* Bring MAC out of reset state */ 10754d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 0); 10764d52a575SXin LI 10774d52a575SXin LI /* Enable memory controllers */ 10784d52a575SXin LI CSR_WRITE_4(sc, ET_MMC_CTRL, ET_MMC_CTRL_ENABLE); 10794d52a575SXin LI } 10804d52a575SXin LI 10814d52a575SXin LI static void 10824d52a575SXin LI et_intr(void *xsc) 10834d52a575SXin LI { 10844d52a575SXin LI struct et_softc *sc = xsc; 10854d52a575SXin LI struct ifnet *ifp; 10864d52a575SXin LI uint32_t intrs; 10874d52a575SXin LI 10884d52a575SXin LI ET_LOCK(sc); 10894d52a575SXin LI ifp = sc->ifp; 10904d52a575SXin LI if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 10914d52a575SXin LI ET_UNLOCK(sc); 10924d52a575SXin LI return; 10934d52a575SXin LI } 10944d52a575SXin LI 10954d52a575SXin LI et_disable_intrs(sc); 10964d52a575SXin LI 10974d52a575SXin LI intrs = CSR_READ_4(sc, ET_INTR_STATUS); 10984d52a575SXin LI intrs &= ET_INTRS; 10994d52a575SXin LI if (intrs == 0) /* Not interested */ 11004d52a575SXin LI goto back; 11014d52a575SXin LI 11024d52a575SXin LI if (intrs & ET_INTR_RXEOF) 11034d52a575SXin LI et_rxeof(sc); 11044d52a575SXin LI if (intrs & (ET_INTR_TXEOF | ET_INTR_TIMER)) 11054d52a575SXin LI et_txeof(sc); 11064d52a575SXin LI if (intrs & ET_INTR_TIMER) 11074d52a575SXin LI CSR_WRITE_4(sc, ET_TIMER, sc->sc_timer); 11084d52a575SXin LI back: 11094d52a575SXin LI et_enable_intrs(sc, ET_INTRS); 11104d52a575SXin LI ET_UNLOCK(sc); 11114d52a575SXin LI } 11124d52a575SXin LI 11134d52a575SXin LI static void 11144d52a575SXin LI et_init_locked(struct et_softc *sc) 11154d52a575SXin LI { 11164d52a575SXin LI struct ifnet *ifp = sc->ifp; 11174d52a575SXin LI const struct et_bsize *arr; 11184d52a575SXin LI int error, i; 11194d52a575SXin LI 11204d52a575SXin LI ET_LOCK_ASSERT(sc); 11214d52a575SXin LI 11224d52a575SXin LI if (ifp->if_drv_flags & IFF_DRV_RUNNING) 11234d52a575SXin LI return; 11244d52a575SXin LI 11254d52a575SXin LI et_stop(sc); 11264d52a575SXin LI 11274d52a575SXin LI arr = et_bufsize_std; 11284d52a575SXin LI for (i = 0; i < ET_RX_NRING; ++i) { 11294d52a575SXin LI sc->sc_rx_data[i].rbd_bufsize = arr[i].bufsize; 11304d52a575SXin LI sc->sc_rx_data[i].rbd_newbuf = arr[i].newbuf; 11314d52a575SXin LI } 11324d52a575SXin LI 11334d52a575SXin LI error = et_init_tx_ring(sc); 11344d52a575SXin LI if (error) 11354d52a575SXin LI goto back; 11364d52a575SXin LI 11374d52a575SXin LI error = et_init_rx_ring(sc); 11384d52a575SXin LI if (error) 11394d52a575SXin LI goto back; 11404d52a575SXin LI 11414d52a575SXin LI error = et_chip_init(sc); 11424d52a575SXin LI if (error) 11434d52a575SXin LI goto back; 11444d52a575SXin LI 11454d52a575SXin LI error = et_enable_txrx(sc, 1); 11464d52a575SXin LI if (error) 11474d52a575SXin LI goto back; 11484d52a575SXin LI 11494d52a575SXin LI et_enable_intrs(sc, ET_INTRS); 11504d52a575SXin LI 11514d52a575SXin LI callout_reset(&sc->sc_tick, hz, et_tick, sc); 11524d52a575SXin LI 11534d52a575SXin LI CSR_WRITE_4(sc, ET_TIMER, sc->sc_timer); 11544d52a575SXin LI 11554d52a575SXin LI ifp->if_drv_flags |= IFF_DRV_RUNNING; 11564d52a575SXin LI ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 11574d52a575SXin LI back: 11584d52a575SXin LI if (error) 11594d52a575SXin LI et_stop(sc); 11604d52a575SXin LI } 11614d52a575SXin LI 11624d52a575SXin LI static void 11634d52a575SXin LI et_init(void *xsc) 11644d52a575SXin LI { 11654d52a575SXin LI struct et_softc *sc = xsc; 11664d52a575SXin LI 11674d52a575SXin LI ET_LOCK(sc); 11684d52a575SXin LI et_init_locked(sc); 11694d52a575SXin LI ET_UNLOCK(sc); 11704d52a575SXin LI } 11714d52a575SXin LI 11724d52a575SXin LI static int 11734d52a575SXin LI et_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 11744d52a575SXin LI { 11754d52a575SXin LI struct et_softc *sc = ifp->if_softc; 11764d52a575SXin LI struct mii_data *mii = device_get_softc(sc->sc_miibus); 11774d52a575SXin LI struct ifreq *ifr = (struct ifreq *)data; 11784d52a575SXin LI int error = 0, max_framelen; 11794d52a575SXin LI 11804d52a575SXin LI /* XXX LOCKSUSED */ 11814d52a575SXin LI switch (cmd) { 11824d52a575SXin LI case SIOCSIFFLAGS: 11834d52a575SXin LI ET_LOCK(sc); 11844d52a575SXin LI if (ifp->if_flags & IFF_UP) { 11854d52a575SXin LI if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 11864d52a575SXin LI if ((ifp->if_flags ^ sc->sc_if_flags) & 11874d52a575SXin LI (IFF_ALLMULTI | IFF_PROMISC | IFF_BROADCAST)) 11884d52a575SXin LI et_setmulti(sc); 11894d52a575SXin LI } else { 11904d52a575SXin LI et_init_locked(sc); 11914d52a575SXin LI } 11924d52a575SXin LI } else { 11934d52a575SXin LI if (ifp->if_drv_flags & IFF_DRV_RUNNING) 11944d52a575SXin LI et_stop(sc); 11954d52a575SXin LI } 11964d52a575SXin LI sc->sc_if_flags = ifp->if_flags; 11974d52a575SXin LI ET_UNLOCK(sc); 11984d52a575SXin LI break; 11994d52a575SXin LI 12004d52a575SXin LI case SIOCSIFMEDIA: 12014d52a575SXin LI case SIOCGIFMEDIA: 12024d52a575SXin LI error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 12034d52a575SXin LI break; 12044d52a575SXin LI 12054d52a575SXin LI case SIOCADDMULTI: 12064d52a575SXin LI case SIOCDELMULTI: 12074d52a575SXin LI if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 12084d52a575SXin LI ET_LOCK(sc); 12094d52a575SXin LI et_setmulti(sc); 12104d52a575SXin LI ET_UNLOCK(sc); 12114d52a575SXin LI error = 0; 12124d52a575SXin LI } 12134d52a575SXin LI break; 12144d52a575SXin LI 12154d52a575SXin LI case SIOCSIFMTU: 12164d52a575SXin LI #if 0 12174d52a575SXin LI if (sc->sc_flags & ET_FLAG_JUMBO) 12184d52a575SXin LI max_framelen = ET_JUMBO_FRAMELEN; 12194d52a575SXin LI else 12204d52a575SXin LI #endif 12214d52a575SXin LI max_framelen = MCLBYTES - 1; 12224d52a575SXin LI 12234d52a575SXin LI if (ET_FRAMELEN(ifr->ifr_mtu) > max_framelen) { 12244d52a575SXin LI error = EOPNOTSUPP; 12254d52a575SXin LI break; 12264d52a575SXin LI } 12274d52a575SXin LI 12284d52a575SXin LI if (ifp->if_mtu != ifr->ifr_mtu) { 12294d52a575SXin LI ifp->if_mtu = ifr->ifr_mtu; 12304d52a575SXin LI ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 12314d52a575SXin LI et_init(sc); 12324d52a575SXin LI } 12334d52a575SXin LI break; 12344d52a575SXin LI 12354d52a575SXin LI default: 12364d52a575SXin LI error = ether_ioctl(ifp, cmd, data); 12374d52a575SXin LI break; 12384d52a575SXin LI } 1239398f1b65SPyun YongHyeon return (error); 12404d52a575SXin LI } 12414d52a575SXin LI 12424d52a575SXin LI static void 12434d52a575SXin LI et_start_locked(struct ifnet *ifp) 12444d52a575SXin LI { 12454d52a575SXin LI struct et_softc *sc = ifp->if_softc; 12464d52a575SXin LI struct et_txbuf_data *tbd; 12474d52a575SXin LI int trans; 12484d52a575SXin LI 12494d52a575SXin LI ET_LOCK_ASSERT(sc); 12504d52a575SXin LI tbd = &sc->sc_tx_data; 12514d52a575SXin LI 12524d52a575SXin LI if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0) 12534d52a575SXin LI return; 12544d52a575SXin LI 12554d52a575SXin LI if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING) 12564d52a575SXin LI return; 12574d52a575SXin LI 12584d52a575SXin LI trans = 0; 12594d52a575SXin LI for (;;) { 12604d52a575SXin LI struct mbuf *m; 12614d52a575SXin LI 12624d52a575SXin LI if ((tbd->tbd_used + ET_NSEG_SPARE) > ET_TX_NDESC) { 12634d52a575SXin LI ifp->if_drv_flags |= IFF_DRV_OACTIVE; 12644d52a575SXin LI break; 12654d52a575SXin LI } 12664d52a575SXin LI 12674d52a575SXin LI IFQ_DEQUEUE(&ifp->if_snd, m); 12684d52a575SXin LI if (m == NULL) 12694d52a575SXin LI break; 12704d52a575SXin LI 12714d52a575SXin LI if (et_encap(sc, &m)) { 12724d52a575SXin LI ifp->if_oerrors++; 12734d52a575SXin LI ifp->if_drv_flags |= IFF_DRV_OACTIVE; 12744d52a575SXin LI break; 12754d52a575SXin LI } 12764d52a575SXin LI trans = 1; 12774d52a575SXin LI 12784d52a575SXin LI BPF_MTAP(ifp, m); 12794d52a575SXin LI } 12804d52a575SXin LI 12814d52a575SXin LI if (trans) 12824d52a575SXin LI sc->watchdog_timer = 5; 12834d52a575SXin LI } 12844d52a575SXin LI 12854d52a575SXin LI static void 12864d52a575SXin LI et_start(struct ifnet *ifp) 12874d52a575SXin LI { 12884d52a575SXin LI struct et_softc *sc = ifp->if_softc; 12894d52a575SXin LI 12904d52a575SXin LI ET_LOCK(sc); 12914d52a575SXin LI et_start_locked(ifp); 12924d52a575SXin LI ET_UNLOCK(sc); 12934d52a575SXin LI } 12944d52a575SXin LI 12954d52a575SXin LI static void 12964d52a575SXin LI et_watchdog(struct et_softc *sc) 12974d52a575SXin LI { 12984d52a575SXin LI ET_LOCK_ASSERT(sc); 12994d52a575SXin LI 13004d52a575SXin LI if (sc->watchdog_timer == 0 || --sc->watchdog_timer) 13014d52a575SXin LI return; 13024d52a575SXin LI 13034d52a575SXin LI if_printf(sc->ifp, "watchdog timed out\n"); 13044d52a575SXin LI 13054d52a575SXin LI et_init_locked(sc); 13064d52a575SXin LI et_start_locked(sc->ifp); 13074d52a575SXin LI } 13084d52a575SXin LI 13094d52a575SXin LI static int 13104d52a575SXin LI et_stop_rxdma(struct et_softc *sc) 13114d52a575SXin LI { 13124d52a575SXin LI CSR_WRITE_4(sc, ET_RXDMA_CTRL, 13134d52a575SXin LI ET_RXDMA_CTRL_HALT | ET_RXDMA_CTRL_RING1_ENABLE); 13144d52a575SXin LI 13154d52a575SXin LI DELAY(5); 13164d52a575SXin LI if ((CSR_READ_4(sc, ET_RXDMA_CTRL) & ET_RXDMA_CTRL_HALTED) == 0) { 13174d52a575SXin LI if_printf(sc->ifp, "can't stop RX DMA engine\n"); 1318398f1b65SPyun YongHyeon return (ETIMEDOUT); 13194d52a575SXin LI } 1320398f1b65SPyun YongHyeon return (0); 13214d52a575SXin LI } 13224d52a575SXin LI 13234d52a575SXin LI static int 13244d52a575SXin LI et_stop_txdma(struct et_softc *sc) 13254d52a575SXin LI { 13264d52a575SXin LI CSR_WRITE_4(sc, ET_TXDMA_CTRL, 13274d52a575SXin LI ET_TXDMA_CTRL_HALT | ET_TXDMA_CTRL_SINGLE_EPKT); 1328398f1b65SPyun YongHyeon return (0); 13294d52a575SXin LI } 13304d52a575SXin LI 13314d52a575SXin LI static void 13324d52a575SXin LI et_free_tx_ring(struct et_softc *sc) 13334d52a575SXin LI { 13344d52a575SXin LI struct et_txbuf_data *tbd = &sc->sc_tx_data; 13354d52a575SXin LI struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 13364d52a575SXin LI int i; 13374d52a575SXin LI 13384d52a575SXin LI for (i = 0; i < ET_TX_NDESC; ++i) { 13394d52a575SXin LI struct et_txbuf *tb = &tbd->tbd_buf[i]; 13404d52a575SXin LI 13414d52a575SXin LI if (tb->tb_mbuf != NULL) { 13424d52a575SXin LI bus_dmamap_unload(sc->sc_mbuf_dtag, tb->tb_dmap); 13434d52a575SXin LI m_freem(tb->tb_mbuf); 13444d52a575SXin LI tb->tb_mbuf = NULL; 13454d52a575SXin LI } 13464d52a575SXin LI } 13474d52a575SXin LI 13484d52a575SXin LI bzero(tx_ring->tr_desc, ET_TX_RING_SIZE); 13494d52a575SXin LI bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap, 13504d52a575SXin LI BUS_DMASYNC_PREWRITE); 13514d52a575SXin LI } 13524d52a575SXin LI 13534d52a575SXin LI static void 13544d52a575SXin LI et_free_rx_ring(struct et_softc *sc) 13554d52a575SXin LI { 13564d52a575SXin LI int n; 13574d52a575SXin LI 13584d52a575SXin LI for (n = 0; n < ET_RX_NRING; ++n) { 13594d52a575SXin LI struct et_rxbuf_data *rbd = &sc->sc_rx_data[n]; 13604d52a575SXin LI struct et_rxdesc_ring *rx_ring = &sc->sc_rx_ring[n]; 13614d52a575SXin LI int i; 13624d52a575SXin LI 13634d52a575SXin LI for (i = 0; i < ET_RX_NDESC; ++i) { 13644d52a575SXin LI struct et_rxbuf *rb = &rbd->rbd_buf[i]; 13654d52a575SXin LI 13664d52a575SXin LI if (rb->rb_mbuf != NULL) { 1367b4b98624SXin LI bus_dmamap_unload(sc->sc_mbuf_dtag, 1368b4b98624SXin LI rb->rb_dmap); 13694d52a575SXin LI m_freem(rb->rb_mbuf); 13704d52a575SXin LI rb->rb_mbuf = NULL; 13714d52a575SXin LI } 13724d52a575SXin LI } 13734d52a575SXin LI 13744d52a575SXin LI bzero(rx_ring->rr_desc, ET_RX_RING_SIZE); 13754d52a575SXin LI bus_dmamap_sync(rx_ring->rr_dtag, rx_ring->rr_dmap, 13764d52a575SXin LI BUS_DMASYNC_PREWRITE); 13774d52a575SXin LI } 13784d52a575SXin LI } 13794d52a575SXin LI 13804d52a575SXin LI static void 13814d52a575SXin LI et_setmulti(struct et_softc *sc) 13824d52a575SXin LI { 13834d52a575SXin LI struct ifnet *ifp; 13844d52a575SXin LI uint32_t hash[4] = { 0, 0, 0, 0 }; 13854d52a575SXin LI uint32_t rxmac_ctrl, pktfilt; 13864d52a575SXin LI struct ifmultiaddr *ifma; 13874d52a575SXin LI int i, count; 13884d52a575SXin LI 13894d52a575SXin LI ET_LOCK_ASSERT(sc); 13904d52a575SXin LI ifp = sc->ifp; 13914d52a575SXin LI 13924d52a575SXin LI pktfilt = CSR_READ_4(sc, ET_PKTFILT); 13934d52a575SXin LI rxmac_ctrl = CSR_READ_4(sc, ET_RXMAC_CTRL); 13944d52a575SXin LI 13954d52a575SXin LI pktfilt &= ~(ET_PKTFILT_BCAST | ET_PKTFILT_MCAST | ET_PKTFILT_UCAST); 13964d52a575SXin LI if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) { 13974d52a575SXin LI rxmac_ctrl |= ET_RXMAC_CTRL_NO_PKTFILT; 13984d52a575SXin LI goto back; 13994d52a575SXin LI } 14004d52a575SXin LI 14014d52a575SXin LI count = 0; 1402eb956cd0SRobert Watson if_maddr_rlock(ifp); 14034d52a575SXin LI TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 14044d52a575SXin LI uint32_t *hp, h; 14054d52a575SXin LI 14064d52a575SXin LI if (ifma->ifma_addr->sa_family != AF_LINK) 14074d52a575SXin LI continue; 14084d52a575SXin LI 14094d52a575SXin LI h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 14104d52a575SXin LI ifma->ifma_addr), ETHER_ADDR_LEN); 14114d52a575SXin LI h = (h & 0x3f800000) >> 23; 14124d52a575SXin LI 14134d52a575SXin LI hp = &hash[0]; 14144d52a575SXin LI if (h >= 32 && h < 64) { 14154d52a575SXin LI h -= 32; 14164d52a575SXin LI hp = &hash[1]; 14174d52a575SXin LI } else if (h >= 64 && h < 96) { 14184d52a575SXin LI h -= 64; 14194d52a575SXin LI hp = &hash[2]; 14204d52a575SXin LI } else if (h >= 96) { 14214d52a575SXin LI h -= 96; 14224d52a575SXin LI hp = &hash[3]; 14234d52a575SXin LI } 14244d52a575SXin LI *hp |= (1 << h); 14254d52a575SXin LI 14264d52a575SXin LI ++count; 14274d52a575SXin LI } 1428eb956cd0SRobert Watson if_maddr_runlock(ifp); 14294d52a575SXin LI 14304d52a575SXin LI for (i = 0; i < 4; ++i) 14314d52a575SXin LI CSR_WRITE_4(sc, ET_MULTI_HASH + (i * 4), hash[i]); 14324d52a575SXin LI 14334d52a575SXin LI if (count > 0) 14344d52a575SXin LI pktfilt |= ET_PKTFILT_MCAST; 14354d52a575SXin LI rxmac_ctrl &= ~ET_RXMAC_CTRL_NO_PKTFILT; 14364d52a575SXin LI back: 14374d52a575SXin LI CSR_WRITE_4(sc, ET_PKTFILT, pktfilt); 14384d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_CTRL, rxmac_ctrl); 14394d52a575SXin LI } 14404d52a575SXin LI 14414d52a575SXin LI static int 14424d52a575SXin LI et_chip_init(struct et_softc *sc) 14434d52a575SXin LI { 14444d52a575SXin LI struct ifnet *ifp = sc->ifp; 14454d52a575SXin LI uint32_t rxq_end; 14464d52a575SXin LI int error, frame_len, rxmem_size; 14474d52a575SXin LI 14484d52a575SXin LI /* 14494d52a575SXin LI * Split 16Kbytes internal memory between TX and RX 14504d52a575SXin LI * according to frame length. 14514d52a575SXin LI */ 14524d52a575SXin LI frame_len = ET_FRAMELEN(ifp->if_mtu); 14534d52a575SXin LI if (frame_len < 2048) { 14544d52a575SXin LI rxmem_size = ET_MEM_RXSIZE_DEFAULT; 14554d52a575SXin LI } else if (frame_len <= ET_RXMAC_CUT_THRU_FRMLEN) { 14564d52a575SXin LI rxmem_size = ET_MEM_SIZE / 2; 14574d52a575SXin LI } else { 14584d52a575SXin LI rxmem_size = ET_MEM_SIZE - 14594d52a575SXin LI roundup(frame_len + ET_MEM_TXSIZE_EX, ET_MEM_UNIT); 14604d52a575SXin LI } 14614d52a575SXin LI rxq_end = ET_QUEUE_ADDR(rxmem_size); 14624d52a575SXin LI 14634d52a575SXin LI CSR_WRITE_4(sc, ET_RXQUEUE_START, ET_QUEUE_ADDR_START); 14644d52a575SXin LI CSR_WRITE_4(sc, ET_RXQUEUE_END, rxq_end); 14654d52a575SXin LI CSR_WRITE_4(sc, ET_TXQUEUE_START, rxq_end + 1); 14664d52a575SXin LI CSR_WRITE_4(sc, ET_TXQUEUE_END, ET_QUEUE_ADDR_END); 14674d52a575SXin LI 14684d52a575SXin LI /* No loopback */ 14694d52a575SXin LI CSR_WRITE_4(sc, ET_LOOPBACK, 0); 14704d52a575SXin LI 14714d52a575SXin LI /* Clear MSI configure */ 1472cc3c3b4eSPyun YongHyeon if ((sc->sc_flags & ET_FLAG_MSI) == 0) 14734d52a575SXin LI CSR_WRITE_4(sc, ET_MSI_CFG, 0); 14744d52a575SXin LI 14754d52a575SXin LI /* Disable timer */ 14764d52a575SXin LI CSR_WRITE_4(sc, ET_TIMER, 0); 14774d52a575SXin LI 14784d52a575SXin LI /* Initialize MAC */ 14794d52a575SXin LI et_init_mac(sc); 14804d52a575SXin LI 14814d52a575SXin LI /* Enable memory controllers */ 14824d52a575SXin LI CSR_WRITE_4(sc, ET_MMC_CTRL, ET_MMC_CTRL_ENABLE); 14834d52a575SXin LI 14844d52a575SXin LI /* Initialize RX MAC */ 14854d52a575SXin LI et_init_rxmac(sc); 14864d52a575SXin LI 14874d52a575SXin LI /* Initialize TX MAC */ 14884d52a575SXin LI et_init_txmac(sc); 14894d52a575SXin LI 14904d52a575SXin LI /* Initialize RX DMA engine */ 14914d52a575SXin LI error = et_init_rxdma(sc); 14924d52a575SXin LI if (error) 1493398f1b65SPyun YongHyeon return (error); 14944d52a575SXin LI 14954d52a575SXin LI /* Initialize TX DMA engine */ 14964d52a575SXin LI error = et_init_txdma(sc); 14974d52a575SXin LI if (error) 1498398f1b65SPyun YongHyeon return (error); 14994d52a575SXin LI 1500398f1b65SPyun YongHyeon return (0); 15014d52a575SXin LI } 15024d52a575SXin LI 15034d52a575SXin LI static int 15044d52a575SXin LI et_init_tx_ring(struct et_softc *sc) 15054d52a575SXin LI { 15064d52a575SXin LI struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 15074d52a575SXin LI struct et_txstatus_data *txsd = &sc->sc_tx_status; 15084d52a575SXin LI struct et_txbuf_data *tbd = &sc->sc_tx_data; 15094d52a575SXin LI 15104d52a575SXin LI bzero(tx_ring->tr_desc, ET_TX_RING_SIZE); 15114d52a575SXin LI bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap, 15124d52a575SXin LI BUS_DMASYNC_PREWRITE); 15134d52a575SXin LI 15144d52a575SXin LI tbd->tbd_start_index = 0; 15154d52a575SXin LI tbd->tbd_start_wrap = 0; 15164d52a575SXin LI tbd->tbd_used = 0; 15174d52a575SXin LI 15184d52a575SXin LI bzero(txsd->txsd_status, sizeof(uint32_t)); 15194d52a575SXin LI bus_dmamap_sync(txsd->txsd_dtag, txsd->txsd_dmap, 15204d52a575SXin LI BUS_DMASYNC_PREWRITE); 1521398f1b65SPyun YongHyeon return (0); 15224d52a575SXin LI } 15234d52a575SXin LI 15244d52a575SXin LI static int 15254d52a575SXin LI et_init_rx_ring(struct et_softc *sc) 15264d52a575SXin LI { 15274d52a575SXin LI struct et_rxstatus_data *rxsd = &sc->sc_rx_status; 15284d52a575SXin LI struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring; 15294d52a575SXin LI int n; 15304d52a575SXin LI 15314d52a575SXin LI for (n = 0; n < ET_RX_NRING; ++n) { 15324d52a575SXin LI struct et_rxbuf_data *rbd = &sc->sc_rx_data[n]; 15334d52a575SXin LI int i, error; 15344d52a575SXin LI 15354d52a575SXin LI for (i = 0; i < ET_RX_NDESC; ++i) { 15364d52a575SXin LI error = rbd->rbd_newbuf(rbd, i, 1); 15374d52a575SXin LI if (error) { 15384d52a575SXin LI if_printf(sc->ifp, "%d ring %d buf, " 15394d52a575SXin LI "newbuf failed: %d\n", n, i, error); 1540398f1b65SPyun YongHyeon return (error); 15414d52a575SXin LI } 15424d52a575SXin LI } 15434d52a575SXin LI } 15444d52a575SXin LI 15454d52a575SXin LI bzero(rxsd->rxsd_status, sizeof(struct et_rxstatus)); 15464d52a575SXin LI bus_dmamap_sync(rxsd->rxsd_dtag, rxsd->rxsd_dmap, 15474d52a575SXin LI BUS_DMASYNC_PREWRITE); 15484d52a575SXin LI 15494d52a575SXin LI bzero(rxst_ring->rsr_stat, ET_RXSTAT_RING_SIZE); 15504d52a575SXin LI bus_dmamap_sync(rxst_ring->rsr_dtag, rxst_ring->rsr_dmap, 15514d52a575SXin LI BUS_DMASYNC_PREWRITE); 15524d52a575SXin LI 1553398f1b65SPyun YongHyeon return (0); 15544d52a575SXin LI } 15554d52a575SXin LI 15564d52a575SXin LI static void 15574d52a575SXin LI et_dma_buf_addr(void *xctx, bus_dma_segment_t *segs, int nsegs, 15584d52a575SXin LI bus_size_t mapsz __unused, int error) 15594d52a575SXin LI { 15604d52a575SXin LI struct et_dmamap_ctx *ctx = xctx; 15614d52a575SXin LI int i; 15624d52a575SXin LI 15634d52a575SXin LI if (error) 15644d52a575SXin LI return; 15654d52a575SXin LI 15664d52a575SXin LI if (nsegs > ctx->nsegs) { 15674d52a575SXin LI ctx->nsegs = 0; 15684d52a575SXin LI return; 15694d52a575SXin LI } 15704d52a575SXin LI 15714d52a575SXin LI ctx->nsegs = nsegs; 15724d52a575SXin LI for (i = 0; i < nsegs; ++i) 15734d52a575SXin LI ctx->segs[i] = segs[i]; 15744d52a575SXin LI } 15754d52a575SXin LI 15764d52a575SXin LI static int 15774d52a575SXin LI et_init_rxdma(struct et_softc *sc) 15784d52a575SXin LI { 15794d52a575SXin LI struct et_rxstatus_data *rxsd = &sc->sc_rx_status; 15804d52a575SXin LI struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring; 15814d52a575SXin LI struct et_rxdesc_ring *rx_ring; 15824d52a575SXin LI int error; 15834d52a575SXin LI 15844d52a575SXin LI error = et_stop_rxdma(sc); 15854d52a575SXin LI if (error) { 15864d52a575SXin LI if_printf(sc->ifp, "can't init RX DMA engine\n"); 1587398f1b65SPyun YongHyeon return (error); 15884d52a575SXin LI } 15894d52a575SXin LI 15904d52a575SXin LI /* 15914d52a575SXin LI * Install RX status 15924d52a575SXin LI */ 15934d52a575SXin LI CSR_WRITE_4(sc, ET_RX_STATUS_HI, ET_ADDR_HI(rxsd->rxsd_paddr)); 15944d52a575SXin LI CSR_WRITE_4(sc, ET_RX_STATUS_LO, ET_ADDR_LO(rxsd->rxsd_paddr)); 15954d52a575SXin LI 15964d52a575SXin LI /* 15974d52a575SXin LI * Install RX stat ring 15984d52a575SXin LI */ 15994d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_HI, ET_ADDR_HI(rxst_ring->rsr_paddr)); 16004d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_LO, ET_ADDR_LO(rxst_ring->rsr_paddr)); 16014d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_CNT, ET_RX_NSTAT - 1); 16024d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_POS, 0); 16034d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_MINCNT, ((ET_RX_NSTAT * 15) / 100) - 1); 16044d52a575SXin LI 16054d52a575SXin LI /* Match ET_RXSTAT_POS */ 16064d52a575SXin LI rxst_ring->rsr_index = 0; 16074d52a575SXin LI rxst_ring->rsr_wrap = 0; 16084d52a575SXin LI 16094d52a575SXin LI /* 16104d52a575SXin LI * Install the 2nd RX descriptor ring 16114d52a575SXin LI */ 16124d52a575SXin LI rx_ring = &sc->sc_rx_ring[1]; 16134d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING1_HI, ET_ADDR_HI(rx_ring->rr_paddr)); 16144d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING1_LO, ET_ADDR_LO(rx_ring->rr_paddr)); 16154d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING1_CNT, ET_RX_NDESC - 1); 16164d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING1_POS, ET_RX_RING1_POS_WRAP); 16174d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING1_MINCNT, ((ET_RX_NDESC * 15) / 100) - 1); 16184d52a575SXin LI 16194d52a575SXin LI /* Match ET_RX_RING1_POS */ 16204d52a575SXin LI rx_ring->rr_index = 0; 16214d52a575SXin LI rx_ring->rr_wrap = 1; 16224d52a575SXin LI 16234d52a575SXin LI /* 16244d52a575SXin LI * Install the 1st RX descriptor ring 16254d52a575SXin LI */ 16264d52a575SXin LI rx_ring = &sc->sc_rx_ring[0]; 16274d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING0_HI, ET_ADDR_HI(rx_ring->rr_paddr)); 16284d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING0_LO, ET_ADDR_LO(rx_ring->rr_paddr)); 16294d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING0_CNT, ET_RX_NDESC - 1); 16304d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING0_POS, ET_RX_RING0_POS_WRAP); 16314d52a575SXin LI CSR_WRITE_4(sc, ET_RX_RING0_MINCNT, ((ET_RX_NDESC * 15) / 100) - 1); 16324d52a575SXin LI 16334d52a575SXin LI /* Match ET_RX_RING0_POS */ 16344d52a575SXin LI rx_ring->rr_index = 0; 16354d52a575SXin LI rx_ring->rr_wrap = 1; 16364d52a575SXin LI 16374d52a575SXin LI /* 16384d52a575SXin LI * RX intr moderation 16394d52a575SXin LI */ 16404d52a575SXin LI CSR_WRITE_4(sc, ET_RX_INTR_NPKTS, sc->sc_rx_intr_npkts); 16414d52a575SXin LI CSR_WRITE_4(sc, ET_RX_INTR_DELAY, sc->sc_rx_intr_delay); 16424d52a575SXin LI 1643398f1b65SPyun YongHyeon return (0); 16444d52a575SXin LI } 16454d52a575SXin LI 16464d52a575SXin LI static int 16474d52a575SXin LI et_init_txdma(struct et_softc *sc) 16484d52a575SXin LI { 16494d52a575SXin LI struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 16504d52a575SXin LI struct et_txstatus_data *txsd = &sc->sc_tx_status; 16514d52a575SXin LI int error; 16524d52a575SXin LI 16534d52a575SXin LI error = et_stop_txdma(sc); 16544d52a575SXin LI if (error) { 16554d52a575SXin LI if_printf(sc->ifp, "can't init TX DMA engine\n"); 1656398f1b65SPyun YongHyeon return (error); 16574d52a575SXin LI } 16584d52a575SXin LI 16594d52a575SXin LI /* 16604d52a575SXin LI * Install TX descriptor ring 16614d52a575SXin LI */ 16624d52a575SXin LI CSR_WRITE_4(sc, ET_TX_RING_HI, ET_ADDR_HI(tx_ring->tr_paddr)); 16634d52a575SXin LI CSR_WRITE_4(sc, ET_TX_RING_LO, ET_ADDR_LO(tx_ring->tr_paddr)); 16644d52a575SXin LI CSR_WRITE_4(sc, ET_TX_RING_CNT, ET_TX_NDESC - 1); 16654d52a575SXin LI 16664d52a575SXin LI /* 16674d52a575SXin LI * Install TX status 16684d52a575SXin LI */ 16694d52a575SXin LI CSR_WRITE_4(sc, ET_TX_STATUS_HI, ET_ADDR_HI(txsd->txsd_paddr)); 16704d52a575SXin LI CSR_WRITE_4(sc, ET_TX_STATUS_LO, ET_ADDR_LO(txsd->txsd_paddr)); 16714d52a575SXin LI 16724d52a575SXin LI CSR_WRITE_4(sc, ET_TX_READY_POS, 0); 16734d52a575SXin LI 16744d52a575SXin LI /* Match ET_TX_READY_POS */ 16754d52a575SXin LI tx_ring->tr_ready_index = 0; 16764d52a575SXin LI tx_ring->tr_ready_wrap = 0; 16774d52a575SXin LI 1678398f1b65SPyun YongHyeon return (0); 16794d52a575SXin LI } 16804d52a575SXin LI 16814d52a575SXin LI static void 16824d52a575SXin LI et_init_mac(struct et_softc *sc) 16834d52a575SXin LI { 16844d52a575SXin LI struct ifnet *ifp = sc->ifp; 16854d52a575SXin LI const uint8_t *eaddr = IF_LLADDR(ifp); 16864d52a575SXin LI uint32_t val; 16874d52a575SXin LI 16884d52a575SXin LI /* Reset MAC */ 16894d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 16904d52a575SXin LI ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | 16914d52a575SXin LI ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | 16924d52a575SXin LI ET_MAC_CFG1_SIM_RST | ET_MAC_CFG1_SOFT_RST); 16934d52a575SXin LI 16944d52a575SXin LI /* 16954d52a575SXin LI * Setup inter packet gap 16964d52a575SXin LI */ 169723263665SPyun YongHyeon val = (56 << ET_IPG_NONB2B_1_SHIFT) | 169823263665SPyun YongHyeon (88 << ET_IPG_NONB2B_2_SHIFT) | 169923263665SPyun YongHyeon (80 << ET_IPG_MINIFG_SHIFT) | 170023263665SPyun YongHyeon (96 << ET_IPG_B2B_SHIFT); 17014d52a575SXin LI CSR_WRITE_4(sc, ET_IPG, val); 17024d52a575SXin LI 17034d52a575SXin LI /* 17044d52a575SXin LI * Setup half duplex mode 17054d52a575SXin LI */ 170623263665SPyun YongHyeon val = (10 << ET_MAC_HDX_ALT_BEB_TRUNC_SHIFT) | 170723263665SPyun YongHyeon (15 << ET_MAC_HDX_REXMIT_MAX_SHIFT) | 170823263665SPyun YongHyeon (55 << ET_MAC_HDX_COLLWIN_SHIFT) | 17094d52a575SXin LI ET_MAC_HDX_EXC_DEFER; 17104d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_HDX, val); 17114d52a575SXin LI 17124d52a575SXin LI /* Clear MAC control */ 17134d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CTRL, 0); 17144d52a575SXin LI 17154d52a575SXin LI /* Reset MII */ 17164d52a575SXin LI CSR_WRITE_4(sc, ET_MII_CFG, ET_MII_CFG_CLKRST); 17174d52a575SXin LI 17184d52a575SXin LI /* 17194d52a575SXin LI * Set MAC address 17204d52a575SXin LI */ 17214d52a575SXin LI val = eaddr[2] | (eaddr[3] << 8) | (eaddr[4] << 16) | (eaddr[5] << 24); 17224d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_ADDR1, val); 17234d52a575SXin LI val = (eaddr[0] << 16) | (eaddr[1] << 24); 17244d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_ADDR2, val); 17254d52a575SXin LI 17264d52a575SXin LI /* Set max frame length */ 17274d52a575SXin LI CSR_WRITE_4(sc, ET_MAX_FRMLEN, ET_FRAMELEN(ifp->if_mtu)); 17284d52a575SXin LI 17294d52a575SXin LI /* Bring MAC out of reset state */ 17304d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, 0); 17314d52a575SXin LI } 17324d52a575SXin LI 17334d52a575SXin LI static void 17344d52a575SXin LI et_init_rxmac(struct et_softc *sc) 17354d52a575SXin LI { 17364d52a575SXin LI struct ifnet *ifp = sc->ifp; 17374d52a575SXin LI const uint8_t *eaddr = IF_LLADDR(ifp); 17384d52a575SXin LI uint32_t val; 17394d52a575SXin LI int i; 17404d52a575SXin LI 17414d52a575SXin LI /* Disable RX MAC and WOL */ 17424d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_CTRL, ET_RXMAC_CTRL_WOL_DISABLE); 17434d52a575SXin LI 17444d52a575SXin LI /* 17454d52a575SXin LI * Clear all WOL related registers 17464d52a575SXin LI */ 17474d52a575SXin LI for (i = 0; i < 3; ++i) 17484d52a575SXin LI CSR_WRITE_4(sc, ET_WOL_CRC + (i * 4), 0); 17494d52a575SXin LI for (i = 0; i < 20; ++i) 17504d52a575SXin LI CSR_WRITE_4(sc, ET_WOL_MASK + (i * 4), 0); 17514d52a575SXin LI 17524d52a575SXin LI /* 17534d52a575SXin LI * Set WOL source address. XXX is this necessary? 17544d52a575SXin LI */ 17554d52a575SXin LI val = (eaddr[2] << 24) | (eaddr[3] << 16) | (eaddr[4] << 8) | eaddr[5]; 17564d52a575SXin LI CSR_WRITE_4(sc, ET_WOL_SA_LO, val); 17574d52a575SXin LI val = (eaddr[0] << 8) | eaddr[1]; 17584d52a575SXin LI CSR_WRITE_4(sc, ET_WOL_SA_HI, val); 17594d52a575SXin LI 17604d52a575SXin LI /* Clear packet filters */ 17614d52a575SXin LI CSR_WRITE_4(sc, ET_PKTFILT, 0); 17624d52a575SXin LI 17634d52a575SXin LI /* No ucast filtering */ 17644d52a575SXin LI CSR_WRITE_4(sc, ET_UCAST_FILTADDR1, 0); 17654d52a575SXin LI CSR_WRITE_4(sc, ET_UCAST_FILTADDR2, 0); 17664d52a575SXin LI CSR_WRITE_4(sc, ET_UCAST_FILTADDR3, 0); 17674d52a575SXin LI 17684d52a575SXin LI if (ET_FRAMELEN(ifp->if_mtu) > ET_RXMAC_CUT_THRU_FRMLEN) { 17694d52a575SXin LI /* 17704d52a575SXin LI * In order to transmit jumbo packets greater than 17714d52a575SXin LI * ET_RXMAC_CUT_THRU_FRMLEN bytes, the FIFO between 17724d52a575SXin LI * RX MAC and RX DMA needs to be reduced in size to 17734d52a575SXin LI * (ET_MEM_SIZE - ET_MEM_TXSIZE_EX - framelen). In 17744d52a575SXin LI * order to implement this, we must use "cut through" 17754d52a575SXin LI * mode in the RX MAC, which chops packets down into 17764d52a575SXin LI * segments. In this case we selected 256 bytes, 17774d52a575SXin LI * since this is the size of the PCI-Express TLP's 17784d52a575SXin LI * that the ET1310 uses. 17794d52a575SXin LI */ 178023263665SPyun YongHyeon val = (ET_RXMAC_SEGSZ(256) & ET_RXMAC_MC_SEGSZ_MAX_MASK) | 17814d52a575SXin LI ET_RXMAC_MC_SEGSZ_ENABLE; 17824d52a575SXin LI } else { 17834d52a575SXin LI val = 0; 17844d52a575SXin LI } 17854d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_MC_SEGSZ, val); 17864d52a575SXin LI 17874d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_MC_WATERMARK, 0); 17884d52a575SXin LI 17894d52a575SXin LI /* Initialize RX MAC management register */ 17904d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_MGT, 0); 17914d52a575SXin LI 17924d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_SPACE_AVL, 0); 17934d52a575SXin LI 17944d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_MGT, 17954d52a575SXin LI ET_RXMAC_MGT_PASS_ECRC | 17964d52a575SXin LI ET_RXMAC_MGT_PASS_ELEN | 17974d52a575SXin LI ET_RXMAC_MGT_PASS_ETRUNC | 17984d52a575SXin LI ET_RXMAC_MGT_CHECK_PKT); 17994d52a575SXin LI 18004d52a575SXin LI /* 18014d52a575SXin LI * Configure runt filtering (may not work on certain chip generation) 18024d52a575SXin LI */ 180323263665SPyun YongHyeon val = (ETHER_MIN_LEN << ET_PKTFILT_MINLEN_SHIFT) & 180423263665SPyun YongHyeon ET_PKTFILT_MINLEN_MASK; 180523263665SPyun YongHyeon val |= ET_PKTFILT_FRAG; 18064d52a575SXin LI CSR_WRITE_4(sc, ET_PKTFILT, val); 18074d52a575SXin LI 18084d52a575SXin LI /* Enable RX MAC but leave WOL disabled */ 18094d52a575SXin LI CSR_WRITE_4(sc, ET_RXMAC_CTRL, 18104d52a575SXin LI ET_RXMAC_CTRL_WOL_DISABLE | ET_RXMAC_CTRL_ENABLE); 18114d52a575SXin LI 18124d52a575SXin LI /* 18134d52a575SXin LI * Setup multicast hash and allmulti/promisc mode 18144d52a575SXin LI */ 18154d52a575SXin LI et_setmulti(sc); 18164d52a575SXin LI } 18174d52a575SXin LI 18184d52a575SXin LI static void 18194d52a575SXin LI et_init_txmac(struct et_softc *sc) 18204d52a575SXin LI { 18214d52a575SXin LI /* Disable TX MAC and FC(?) */ 18224d52a575SXin LI CSR_WRITE_4(sc, ET_TXMAC_CTRL, ET_TXMAC_CTRL_FC_DISABLE); 18234d52a575SXin LI 18244d52a575SXin LI /* No flow control yet */ 18254d52a575SXin LI CSR_WRITE_4(sc, ET_TXMAC_FLOWCTRL, 0); 18264d52a575SXin LI 18274d52a575SXin LI /* Enable TX MAC but leave FC(?) diabled */ 18284d52a575SXin LI CSR_WRITE_4(sc, ET_TXMAC_CTRL, 18294d52a575SXin LI ET_TXMAC_CTRL_ENABLE | ET_TXMAC_CTRL_FC_DISABLE); 18304d52a575SXin LI } 18314d52a575SXin LI 18324d52a575SXin LI static int 18334d52a575SXin LI et_start_rxdma(struct et_softc *sc) 18344d52a575SXin LI { 18354d52a575SXin LI uint32_t val = 0; 18364d52a575SXin LI 183723263665SPyun YongHyeon val |= (sc->sc_rx_data[0].rbd_bufsize & ET_RXDMA_CTRL_RING0_SIZE_MASK) | 18384d52a575SXin LI ET_RXDMA_CTRL_RING0_ENABLE; 183923263665SPyun YongHyeon val |= (sc->sc_rx_data[1].rbd_bufsize & ET_RXDMA_CTRL_RING1_SIZE_MASK) | 18404d52a575SXin LI ET_RXDMA_CTRL_RING1_ENABLE; 18414d52a575SXin LI 18424d52a575SXin LI CSR_WRITE_4(sc, ET_RXDMA_CTRL, val); 18434d52a575SXin LI 18444d52a575SXin LI DELAY(5); 18454d52a575SXin LI 18464d52a575SXin LI if (CSR_READ_4(sc, ET_RXDMA_CTRL) & ET_RXDMA_CTRL_HALTED) { 18474d52a575SXin LI if_printf(sc->ifp, "can't start RX DMA engine\n"); 1848398f1b65SPyun YongHyeon return (ETIMEDOUT); 18494d52a575SXin LI } 1850398f1b65SPyun YongHyeon return (0); 18514d52a575SXin LI } 18524d52a575SXin LI 18534d52a575SXin LI static int 18544d52a575SXin LI et_start_txdma(struct et_softc *sc) 18554d52a575SXin LI { 18564d52a575SXin LI CSR_WRITE_4(sc, ET_TXDMA_CTRL, ET_TXDMA_CTRL_SINGLE_EPKT); 1857398f1b65SPyun YongHyeon return (0); 18584d52a575SXin LI } 18594d52a575SXin LI 18604d52a575SXin LI static int 18614d52a575SXin LI et_enable_txrx(struct et_softc *sc, int media_upd) 18624d52a575SXin LI { 18634d52a575SXin LI struct ifnet *ifp = sc->ifp; 18644d52a575SXin LI uint32_t val; 18654d52a575SXin LI int i, error; 18664d52a575SXin LI 18674d52a575SXin LI val = CSR_READ_4(sc, ET_MAC_CFG1); 18684d52a575SXin LI val |= ET_MAC_CFG1_TXEN | ET_MAC_CFG1_RXEN; 18694d52a575SXin LI val &= ~(ET_MAC_CFG1_TXFLOW | ET_MAC_CFG1_RXFLOW | 18704d52a575SXin LI ET_MAC_CFG1_LOOPBACK); 18714d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG1, val); 18724d52a575SXin LI 18734d52a575SXin LI if (media_upd) 18744d52a575SXin LI et_ifmedia_upd_locked(ifp); 18754d52a575SXin LI else 18764d52a575SXin LI et_setmedia(sc); 18774d52a575SXin LI 18784d52a575SXin LI #define NRETRY 50 18794d52a575SXin LI 18804d52a575SXin LI for (i = 0; i < NRETRY; ++i) { 18814d52a575SXin LI val = CSR_READ_4(sc, ET_MAC_CFG1); 18824d52a575SXin LI if ((val & (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) == 18834d52a575SXin LI (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) 18844d52a575SXin LI break; 18854d52a575SXin LI 18864d52a575SXin LI DELAY(100); 18874d52a575SXin LI } 18884d52a575SXin LI if (i == NRETRY) { 18894d52a575SXin LI if_printf(ifp, "can't enable RX/TX\n"); 1890398f1b65SPyun YongHyeon return (0); 18914d52a575SXin LI } 18924d52a575SXin LI sc->sc_flags |= ET_FLAG_TXRX_ENABLED; 18934d52a575SXin LI 18944d52a575SXin LI #undef NRETRY 18954d52a575SXin LI 18964d52a575SXin LI /* 18974d52a575SXin LI * Start TX/RX DMA engine 18984d52a575SXin LI */ 18994d52a575SXin LI error = et_start_rxdma(sc); 19004d52a575SXin LI if (error) 1901398f1b65SPyun YongHyeon return (error); 19024d52a575SXin LI 19034d52a575SXin LI error = et_start_txdma(sc); 19044d52a575SXin LI if (error) 1905398f1b65SPyun YongHyeon return (error); 19064d52a575SXin LI 1907398f1b65SPyun YongHyeon return (0); 19084d52a575SXin LI } 19094d52a575SXin LI 19104d52a575SXin LI static void 19114d52a575SXin LI et_rxeof(struct et_softc *sc) 19124d52a575SXin LI { 19134d52a575SXin LI struct ifnet *ifp; 19144d52a575SXin LI struct et_rxstatus_data *rxsd; 19154d52a575SXin LI struct et_rxstat_ring *rxst_ring; 19164d52a575SXin LI uint32_t rxs_stat_ring; 19174d52a575SXin LI int rxst_wrap, rxst_index; 19184d52a575SXin LI 19194d52a575SXin LI ET_LOCK_ASSERT(sc); 19204d52a575SXin LI ifp = sc->ifp; 19214d52a575SXin LI rxsd = &sc->sc_rx_status; 19224d52a575SXin LI rxst_ring = &sc->sc_rxstat_ring; 19234d52a575SXin LI 19244d52a575SXin LI if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0) 19254d52a575SXin LI return; 19264d52a575SXin LI 19274d52a575SXin LI bus_dmamap_sync(rxsd->rxsd_dtag, rxsd->rxsd_dmap, 19284d52a575SXin LI BUS_DMASYNC_POSTREAD); 19294d52a575SXin LI bus_dmamap_sync(rxst_ring->rsr_dtag, rxst_ring->rsr_dmap, 19304d52a575SXin LI BUS_DMASYNC_POSTREAD); 19314d52a575SXin LI 19324d52a575SXin LI rxs_stat_ring = rxsd->rxsd_status->rxs_stat_ring; 19334d52a575SXin LI rxst_wrap = (rxs_stat_ring & ET_RXS_STATRING_WRAP) ? 1 : 0; 193423263665SPyun YongHyeon rxst_index = (rxs_stat_ring & ET_RXS_STATRING_INDEX_MASK) >> 193523263665SPyun YongHyeon ET_RXS_STATRING_INDEX_SHIFT; 19364d52a575SXin LI 19374d52a575SXin LI while (rxst_index != rxst_ring->rsr_index || 19384d52a575SXin LI rxst_wrap != rxst_ring->rsr_wrap) { 19394d52a575SXin LI struct et_rxbuf_data *rbd; 19404d52a575SXin LI struct et_rxdesc_ring *rx_ring; 19414d52a575SXin LI struct et_rxstat *st; 19424d52a575SXin LI struct mbuf *m; 19434d52a575SXin LI int buflen, buf_idx, ring_idx; 19444d52a575SXin LI uint32_t rxstat_pos, rxring_pos; 19454d52a575SXin LI 19464d52a575SXin LI MPASS(rxst_ring->rsr_index < ET_RX_NSTAT); 19474d52a575SXin LI st = &rxst_ring->rsr_stat[rxst_ring->rsr_index]; 19484d52a575SXin LI 194923263665SPyun YongHyeon buflen = (st->rxst_info2 & ET_RXST_INFO2_LEN_MASK) >> 195023263665SPyun YongHyeon ET_RXST_INFO2_LEN_SHIFT; 195123263665SPyun YongHyeon buf_idx = (st->rxst_info2 & ET_RXST_INFO2_BUFIDX_MASK) >> 195223263665SPyun YongHyeon ET_RXST_INFO2_BUFIDX_SHIFT; 195323263665SPyun YongHyeon ring_idx = (st->rxst_info2 & ET_RXST_INFO2_RINGIDX_MASK) >> 195423263665SPyun YongHyeon ET_RXST_INFO2_RINGIDX_SHIFT; 19554d52a575SXin LI 19564d52a575SXin LI if (++rxst_ring->rsr_index == ET_RX_NSTAT) { 19574d52a575SXin LI rxst_ring->rsr_index = 0; 19584d52a575SXin LI rxst_ring->rsr_wrap ^= 1; 19594d52a575SXin LI } 196023263665SPyun YongHyeon rxstat_pos = rxst_ring->rsr_index & ET_RXSTAT_POS_INDEX_MASK; 19614d52a575SXin LI if (rxst_ring->rsr_wrap) 19624d52a575SXin LI rxstat_pos |= ET_RXSTAT_POS_WRAP; 19634d52a575SXin LI CSR_WRITE_4(sc, ET_RXSTAT_POS, rxstat_pos); 19644d52a575SXin LI 19654d52a575SXin LI if (ring_idx >= ET_RX_NRING) { 19664d52a575SXin LI ifp->if_ierrors++; 19674d52a575SXin LI if_printf(ifp, "invalid ring index %d\n", ring_idx); 19684d52a575SXin LI continue; 19694d52a575SXin LI } 19704d52a575SXin LI if (buf_idx >= ET_RX_NDESC) { 19714d52a575SXin LI ifp->if_ierrors++; 19724d52a575SXin LI if_printf(ifp, "invalid buf index %d\n", buf_idx); 19734d52a575SXin LI continue; 19744d52a575SXin LI } 19754d52a575SXin LI 19764d52a575SXin LI rbd = &sc->sc_rx_data[ring_idx]; 19774d52a575SXin LI m = rbd->rbd_buf[buf_idx].rb_mbuf; 19784d52a575SXin LI 19794d52a575SXin LI if (rbd->rbd_newbuf(rbd, buf_idx, 0) == 0) { 19804d52a575SXin LI if (buflen < ETHER_CRC_LEN) { 19814d52a575SXin LI m_freem(m); 19824d52a575SXin LI m = NULL; 19834d52a575SXin LI ifp->if_ierrors++; 19844d52a575SXin LI } else { 19854d52a575SXin LI m->m_pkthdr.len = m->m_len = buflen; 19864d52a575SXin LI m->m_pkthdr.rcvif = ifp; 19874d52a575SXin LI 19884d52a575SXin LI m_adj(m, -ETHER_CRC_LEN); 19894d52a575SXin LI 19904d52a575SXin LI ifp->if_ipackets++; 19914d52a575SXin LI ET_UNLOCK(sc); 19924d52a575SXin LI ifp->if_input(ifp, m); 19934d52a575SXin LI ET_LOCK(sc); 19944d52a575SXin LI } 19954d52a575SXin LI } else { 19964d52a575SXin LI ifp->if_ierrors++; 19974d52a575SXin LI } 19984d52a575SXin LI m = NULL; /* Catch invalid reference */ 19994d52a575SXin LI 20004d52a575SXin LI rx_ring = &sc->sc_rx_ring[ring_idx]; 20014d52a575SXin LI 20024d52a575SXin LI if (buf_idx != rx_ring->rr_index) { 20034d52a575SXin LI if_printf(ifp, "WARNING!! ring %d, " 20044d52a575SXin LI "buf_idx %d, rr_idx %d\n", 20054d52a575SXin LI ring_idx, buf_idx, rx_ring->rr_index); 20064d52a575SXin LI } 20074d52a575SXin LI 20084d52a575SXin LI MPASS(rx_ring->rr_index < ET_RX_NDESC); 20094d52a575SXin LI if (++rx_ring->rr_index == ET_RX_NDESC) { 20104d52a575SXin LI rx_ring->rr_index = 0; 20114d52a575SXin LI rx_ring->rr_wrap ^= 1; 20124d52a575SXin LI } 201323263665SPyun YongHyeon rxring_pos = rx_ring->rr_index & ET_RX_RING_POS_INDEX_MASK; 20144d52a575SXin LI if (rx_ring->rr_wrap) 20154d52a575SXin LI rxring_pos |= ET_RX_RING_POS_WRAP; 20164d52a575SXin LI CSR_WRITE_4(sc, rx_ring->rr_posreg, rxring_pos); 20174d52a575SXin LI } 20184d52a575SXin LI } 20194d52a575SXin LI 20204d52a575SXin LI static int 20214d52a575SXin LI et_encap(struct et_softc *sc, struct mbuf **m0) 20224d52a575SXin LI { 20234d52a575SXin LI struct mbuf *m = *m0; 20244d52a575SXin LI bus_dma_segment_t segs[ET_NSEG_MAX]; 20254d52a575SXin LI struct et_dmamap_ctx ctx; 20264d52a575SXin LI struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring; 20274d52a575SXin LI struct et_txbuf_data *tbd = &sc->sc_tx_data; 20284d52a575SXin LI struct et_txdesc *td; 20294d52a575SXin LI bus_dmamap_t map; 20304d52a575SXin LI int error, maxsegs, first_idx, last_idx, i; 20314d52a575SXin LI uint32_t tx_ready_pos, last_td_ctrl2; 20324d52a575SXin LI 20334d52a575SXin LI maxsegs = ET_TX_NDESC - tbd->tbd_used; 20344d52a575SXin LI if (maxsegs > ET_NSEG_MAX) 20354d52a575SXin LI maxsegs = ET_NSEG_MAX; 20364d52a575SXin LI KASSERT(maxsegs >= ET_NSEG_SPARE, 20374d52a575SXin LI ("not enough spare TX desc (%d)\n", maxsegs)); 20384d52a575SXin LI 20394d52a575SXin LI MPASS(tx_ring->tr_ready_index < ET_TX_NDESC); 20404d52a575SXin LI first_idx = tx_ring->tr_ready_index; 20414d52a575SXin LI map = tbd->tbd_buf[first_idx].tb_dmap; 20424d52a575SXin LI 20434d52a575SXin LI ctx.nsegs = maxsegs; 20444d52a575SXin LI ctx.segs = segs; 20454d52a575SXin LI error = bus_dmamap_load_mbuf(sc->sc_mbuf_dtag, map, m, 20464d52a575SXin LI et_dma_buf_addr, &ctx, BUS_DMA_NOWAIT); 20474d52a575SXin LI if (!error && ctx.nsegs == 0) { 20484d52a575SXin LI bus_dmamap_unload(sc->sc_mbuf_dtag, map); 20494d52a575SXin LI error = EFBIG; 20504d52a575SXin LI } 20514d52a575SXin LI if (error && error != EFBIG) { 20524d52a575SXin LI if_printf(sc->ifp, "can't load TX mbuf, error %d\n", 20534d52a575SXin LI error); 20544d52a575SXin LI goto back; 20554d52a575SXin LI } 20564d52a575SXin LI if (error) { /* error == EFBIG */ 20574d52a575SXin LI struct mbuf *m_new; 20584d52a575SXin LI 20594d52a575SXin LI m_new = m_defrag(m, M_DONTWAIT); 20604d52a575SXin LI if (m_new == NULL) { 20614d52a575SXin LI if_printf(sc->ifp, "can't defrag TX mbuf\n"); 20624d52a575SXin LI error = ENOBUFS; 20634d52a575SXin LI goto back; 20644d52a575SXin LI } else { 20654d52a575SXin LI *m0 = m = m_new; 20664d52a575SXin LI } 20674d52a575SXin LI 20684d52a575SXin LI ctx.nsegs = maxsegs; 20694d52a575SXin LI ctx.segs = segs; 20704d52a575SXin LI error = bus_dmamap_load_mbuf(sc->sc_mbuf_dtag, map, m, 20714d52a575SXin LI et_dma_buf_addr, &ctx, 20724d52a575SXin LI BUS_DMA_NOWAIT); 20734d52a575SXin LI if (error || ctx.nsegs == 0) { 20744d52a575SXin LI if (ctx.nsegs == 0) { 20754d52a575SXin LI bus_dmamap_unload(sc->sc_mbuf_dtag, map); 20764d52a575SXin LI error = EFBIG; 20774d52a575SXin LI } 20784d52a575SXin LI if_printf(sc->ifp, 20794d52a575SXin LI "can't load defraged TX mbuf\n"); 20804d52a575SXin LI goto back; 20814d52a575SXin LI } 20824d52a575SXin LI } 20834d52a575SXin LI 20844d52a575SXin LI bus_dmamap_sync(sc->sc_mbuf_dtag, map, BUS_DMASYNC_PREWRITE); 20854d52a575SXin LI 20864d52a575SXin LI last_td_ctrl2 = ET_TDCTRL2_LAST_FRAG; 20874d52a575SXin LI sc->sc_tx += ctx.nsegs; 20884d52a575SXin LI if (sc->sc_tx / sc->sc_tx_intr_nsegs != sc->sc_tx_intr) { 20894d52a575SXin LI sc->sc_tx_intr = sc->sc_tx / sc->sc_tx_intr_nsegs; 20904d52a575SXin LI last_td_ctrl2 |= ET_TDCTRL2_INTR; 20914d52a575SXin LI } 20924d52a575SXin LI 20934d52a575SXin LI last_idx = -1; 20944d52a575SXin LI for (i = 0; i < ctx.nsegs; ++i) { 20954d52a575SXin LI int idx; 20964d52a575SXin LI 20974d52a575SXin LI idx = (first_idx + i) % ET_TX_NDESC; 20984d52a575SXin LI td = &tx_ring->tr_desc[idx]; 20994d52a575SXin LI td->td_addr_hi = ET_ADDR_HI(segs[i].ds_addr); 21004d52a575SXin LI td->td_addr_lo = ET_ADDR_LO(segs[i].ds_addr); 210123263665SPyun YongHyeon td->td_ctrl1 = segs[i].ds_len & ET_TDCTRL1_LEN_MASK; 21024d52a575SXin LI 21034d52a575SXin LI if (i == ctx.nsegs - 1) { /* Last frag */ 21044d52a575SXin LI td->td_ctrl2 = last_td_ctrl2; 21054d52a575SXin LI last_idx = idx; 21064d52a575SXin LI } 21074d52a575SXin LI 21084d52a575SXin LI MPASS(tx_ring->tr_ready_index < ET_TX_NDESC); 21094d52a575SXin LI if (++tx_ring->tr_ready_index == ET_TX_NDESC) { 21104d52a575SXin LI tx_ring->tr_ready_index = 0; 21114d52a575SXin LI tx_ring->tr_ready_wrap ^= 1; 21124d52a575SXin LI } 21134d52a575SXin LI } 21144d52a575SXin LI td = &tx_ring->tr_desc[first_idx]; 21154d52a575SXin LI td->td_ctrl2 |= ET_TDCTRL2_FIRST_FRAG; /* First frag */ 21164d52a575SXin LI 21174d52a575SXin LI MPASS(last_idx >= 0); 21184d52a575SXin LI tbd->tbd_buf[first_idx].tb_dmap = tbd->tbd_buf[last_idx].tb_dmap; 21194d52a575SXin LI tbd->tbd_buf[last_idx].tb_dmap = map; 21204d52a575SXin LI tbd->tbd_buf[last_idx].tb_mbuf = m; 21214d52a575SXin LI 21224d52a575SXin LI tbd->tbd_used += ctx.nsegs; 21234d52a575SXin LI MPASS(tbd->tbd_used <= ET_TX_NDESC); 21244d52a575SXin LI 21254d52a575SXin LI bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap, 21264d52a575SXin LI BUS_DMASYNC_PREWRITE); 21274d52a575SXin LI 212823263665SPyun YongHyeon tx_ready_pos = tx_ring->tr_ready_index & ET_TX_READY_POS_INDEX_MASK; 21294d52a575SXin LI if (tx_ring->tr_ready_wrap) 21304d52a575SXin LI tx_ready_pos |= ET_TX_READY_POS_WRAP; 21314d52a575SXin LI CSR_WRITE_4(sc, ET_TX_READY_POS, tx_ready_pos); 21324d52a575SXin LI 21334d52a575SXin LI error = 0; 21344d52a575SXin LI back: 21354d52a575SXin LI if (error) { 21364d52a575SXin LI m_freem(m); 21374d52a575SXin LI *m0 = NULL; 21384d52a575SXin LI } 2139398f1b65SPyun YongHyeon return (error); 21404d52a575SXin LI } 21414d52a575SXin LI 21424d52a575SXin LI static void 21434d52a575SXin LI et_txeof(struct et_softc *sc) 21444d52a575SXin LI { 21454d52a575SXin LI struct ifnet *ifp; 21464d52a575SXin LI struct et_txdesc_ring *tx_ring; 21474d52a575SXin LI struct et_txbuf_data *tbd; 21484d52a575SXin LI uint32_t tx_done; 21494d52a575SXin LI int end, wrap; 21504d52a575SXin LI 21514d52a575SXin LI ET_LOCK_ASSERT(sc); 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 21624d52a575SXin LI tx_done = CSR_READ_4(sc, ET_TX_DONE_POS); 216323263665SPyun YongHyeon end = tx_done & ET_TX_DONE_POS_INDEX_MASK; 21644d52a575SXin LI wrap = (tx_done & ET_TX_DONE_POS_WRAP) ? 1 : 0; 21654d52a575SXin LI 21664d52a575SXin LI while (tbd->tbd_start_index != end || tbd->tbd_start_wrap != wrap) { 21674d52a575SXin LI struct et_txbuf *tb; 21684d52a575SXin LI 21694d52a575SXin LI MPASS(tbd->tbd_start_index < ET_TX_NDESC); 21704d52a575SXin LI tb = &tbd->tbd_buf[tbd->tbd_start_index]; 21714d52a575SXin LI 21724d52a575SXin LI bzero(&tx_ring->tr_desc[tbd->tbd_start_index], 21734d52a575SXin LI sizeof(struct et_txdesc)); 21744d52a575SXin LI bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap, 21754d52a575SXin LI BUS_DMASYNC_PREWRITE); 21764d52a575SXin LI 21774d52a575SXin LI if (tb->tb_mbuf != NULL) { 21784d52a575SXin LI bus_dmamap_unload(sc->sc_mbuf_dtag, tb->tb_dmap); 21794d52a575SXin LI m_freem(tb->tb_mbuf); 21804d52a575SXin LI tb->tb_mbuf = NULL; 21814d52a575SXin LI ifp->if_opackets++; 21824d52a575SXin LI } 21834d52a575SXin LI 21844d52a575SXin LI if (++tbd->tbd_start_index == ET_TX_NDESC) { 21854d52a575SXin LI tbd->tbd_start_index = 0; 21864d52a575SXin LI tbd->tbd_start_wrap ^= 1; 21874d52a575SXin LI } 21884d52a575SXin LI 21894d52a575SXin LI MPASS(tbd->tbd_used > 0); 21904d52a575SXin LI tbd->tbd_used--; 21914d52a575SXin LI } 21924d52a575SXin LI 21934d52a575SXin LI if (tbd->tbd_used == 0) 21944d52a575SXin LI sc->watchdog_timer = 0; 21954d52a575SXin LI if (tbd->tbd_used + ET_NSEG_SPARE <= ET_TX_NDESC) 21964d52a575SXin LI ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 21974d52a575SXin LI 21984d52a575SXin LI et_start_locked(ifp); 21994d52a575SXin LI } 22004d52a575SXin LI 22014d52a575SXin LI static void 22024d52a575SXin LI et_tick(void *xsc) 22034d52a575SXin LI { 22044d52a575SXin LI struct et_softc *sc = xsc; 22054d52a575SXin LI struct ifnet *ifp; 22064d52a575SXin LI struct mii_data *mii; 22074d52a575SXin LI 22084d52a575SXin LI ET_LOCK_ASSERT(sc); 22094d52a575SXin LI ifp = sc->ifp; 22104d52a575SXin LI mii = device_get_softc(sc->sc_miibus); 22114d52a575SXin LI 22124d52a575SXin LI mii_tick(mii); 22134d52a575SXin LI if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0 && 22144d52a575SXin LI (mii->mii_media_status & IFM_ACTIVE) && 22154d52a575SXin LI IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 22164d52a575SXin LI if_printf(ifp, "Link up, enable TX/RX\n"); 22174d52a575SXin LI if (et_enable_txrx(sc, 0) == 0) 22184d52a575SXin LI et_start_locked(ifp); 22194d52a575SXin LI } 22204d52a575SXin LI et_watchdog(sc); 22214d52a575SXin LI callout_reset(&sc->sc_tick, hz, et_tick, sc); 22224d52a575SXin LI } 22234d52a575SXin LI 22244d52a575SXin LI static int 22254d52a575SXin LI et_newbuf_cluster(struct et_rxbuf_data *rbd, int buf_idx, int init) 22264d52a575SXin LI { 2227398f1b65SPyun YongHyeon return (et_newbuf(rbd, buf_idx, init, MCLBYTES)); 22284d52a575SXin LI } 22294d52a575SXin LI 22304d52a575SXin LI static int 22314d52a575SXin LI et_newbuf_hdr(struct et_rxbuf_data *rbd, int buf_idx, int init) 22324d52a575SXin LI { 2233398f1b65SPyun YongHyeon return (et_newbuf(rbd, buf_idx, init, MHLEN)); 22344d52a575SXin LI } 22354d52a575SXin LI 22364d52a575SXin LI static int 22374d52a575SXin LI et_newbuf(struct et_rxbuf_data *rbd, int buf_idx, int init, int len0) 22384d52a575SXin LI { 22394d52a575SXin LI struct et_softc *sc = rbd->rbd_softc; 22404d52a575SXin LI struct et_rxbuf *rb; 22414d52a575SXin LI struct mbuf *m; 22424d52a575SXin LI struct et_dmamap_ctx ctx; 22434d52a575SXin LI bus_dma_segment_t seg; 22444d52a575SXin LI bus_dmamap_t dmap; 22454d52a575SXin LI int error, len; 22464d52a575SXin LI 22474d52a575SXin LI MPASS(buf_idx < ET_RX_NDESC); 22484d52a575SXin LI rb = &rbd->rbd_buf[buf_idx]; 22494d52a575SXin LI 22504d52a575SXin LI m = m_getl(len0, /* init ? M_WAIT :*/ M_DONTWAIT, MT_DATA, M_PKTHDR, &len); 22514d52a575SXin LI if (m == NULL) { 22524d52a575SXin LI error = ENOBUFS; 22534d52a575SXin LI 22544d52a575SXin LI if (init) { 22554d52a575SXin LI if_printf(sc->ifp, 22564d52a575SXin LI "m_getl failed, size %d\n", len0); 2257398f1b65SPyun YongHyeon return (error); 22584d52a575SXin LI } else { 22594d52a575SXin LI goto back; 22604d52a575SXin LI } 22614d52a575SXin LI } 22624d52a575SXin LI m->m_len = m->m_pkthdr.len = len; 22634d52a575SXin LI 22644d52a575SXin LI /* 22654d52a575SXin LI * Try load RX mbuf into temporary DMA tag 22664d52a575SXin LI */ 22674d52a575SXin LI ctx.nsegs = 1; 22684d52a575SXin LI ctx.segs = &seg; 22694d52a575SXin LI error = bus_dmamap_load_mbuf(sc->sc_mbuf_dtag, sc->sc_mbuf_tmp_dmap, m, 22704d52a575SXin LI et_dma_buf_addr, &ctx, 22714d52a575SXin LI init ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT); 22724d52a575SXin LI if (error || ctx.nsegs == 0) { 22734d52a575SXin LI if (!error) { 22744d52a575SXin LI bus_dmamap_unload(sc->sc_mbuf_dtag, 22754d52a575SXin LI sc->sc_mbuf_tmp_dmap); 22764d52a575SXin LI error = EFBIG; 22774d52a575SXin LI if_printf(sc->ifp, "too many segments?!\n"); 22784d52a575SXin LI } 22794d52a575SXin LI m_freem(m); 22804d52a575SXin LI m = NULL; 22814d52a575SXin LI 22824d52a575SXin LI if (init) { 22834d52a575SXin LI if_printf(sc->ifp, "can't load RX mbuf\n"); 2284398f1b65SPyun YongHyeon return (error); 22854d52a575SXin LI } else { 22864d52a575SXin LI goto back; 22874d52a575SXin LI } 22884d52a575SXin LI } 22894d52a575SXin LI 22904d52a575SXin LI if (!init) { 22914d52a575SXin LI bus_dmamap_sync(sc->sc_mbuf_dtag, rb->rb_dmap, 22924d52a575SXin LI BUS_DMASYNC_POSTREAD); 22934d52a575SXin LI bus_dmamap_unload(sc->sc_mbuf_dtag, rb->rb_dmap); 22944d52a575SXin LI } 22954d52a575SXin LI rb->rb_mbuf = m; 22964d52a575SXin LI rb->rb_paddr = seg.ds_addr; 22974d52a575SXin LI 22984d52a575SXin LI /* 22994d52a575SXin LI * Swap RX buf's DMA map with the loaded temporary one 23004d52a575SXin LI */ 23014d52a575SXin LI dmap = rb->rb_dmap; 23024d52a575SXin LI rb->rb_dmap = sc->sc_mbuf_tmp_dmap; 23034d52a575SXin LI sc->sc_mbuf_tmp_dmap = dmap; 23044d52a575SXin LI 23054d52a575SXin LI error = 0; 23064d52a575SXin LI back: 23074d52a575SXin LI et_setup_rxdesc(rbd, buf_idx, rb->rb_paddr); 2308398f1b65SPyun YongHyeon return (error); 23094d52a575SXin LI } 23104d52a575SXin LI 23114d52a575SXin LI /* 23124d52a575SXin LI * Create sysctl tree 23134d52a575SXin LI */ 23144d52a575SXin LI static void 23154d52a575SXin LI et_add_sysctls(struct et_softc * sc) 23164d52a575SXin LI { 23174d52a575SXin LI struct sysctl_ctx_list *ctx; 23184d52a575SXin LI struct sysctl_oid_list *children; 23194d52a575SXin LI 23204d52a575SXin LI ctx = device_get_sysctl_ctx(sc->dev); 23214d52a575SXin LI children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); 23224d52a575SXin LI 23234d52a575SXin LI SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_intr_npkts", 23244d52a575SXin LI CTLTYPE_INT | CTLFLAG_RW, sc, 0, et_sysctl_rx_intr_npkts, "I", 23254d52a575SXin LI "RX IM, # packets per RX interrupt"); 23264d52a575SXin LI SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_intr_delay", 23274d52a575SXin LI CTLTYPE_INT | CTLFLAG_RW, sc, 0, et_sysctl_rx_intr_delay, "I", 23284d52a575SXin LI "RX IM, RX interrupt delay (x10 usec)"); 23294d52a575SXin LI SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_intr_nsegs", 23304d52a575SXin LI CTLFLAG_RW, &sc->sc_tx_intr_nsegs, 0, 23314d52a575SXin LI "TX IM, # segments per TX interrupt"); 23324d52a575SXin LI SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "timer", 23334d52a575SXin LI CTLFLAG_RW, &sc->sc_timer, 0, "TX timer"); 23344d52a575SXin LI } 23354d52a575SXin LI 23364d52a575SXin LI static int 23374d52a575SXin LI et_sysctl_rx_intr_npkts(SYSCTL_HANDLER_ARGS) 23384d52a575SXin LI { 23394d52a575SXin LI struct et_softc *sc = arg1; 23404d52a575SXin LI struct ifnet *ifp = sc->ifp; 23414d52a575SXin LI int error = 0, v; 23424d52a575SXin LI 23434d52a575SXin LI v = sc->sc_rx_intr_npkts; 23444d52a575SXin LI error = sysctl_handle_int(oidp, &v, 0, req); 23454d52a575SXin LI if (error || req->newptr == NULL) 23464d52a575SXin LI goto back; 23474d52a575SXin LI if (v <= 0) { 23484d52a575SXin LI error = EINVAL; 23494d52a575SXin LI goto back; 23504d52a575SXin LI } 23514d52a575SXin LI 23524d52a575SXin LI if (sc->sc_rx_intr_npkts != v) { 23534d52a575SXin LI if (ifp->if_drv_flags & IFF_DRV_RUNNING) 23544d52a575SXin LI CSR_WRITE_4(sc, ET_RX_INTR_NPKTS, v); 23554d52a575SXin LI sc->sc_rx_intr_npkts = v; 23564d52a575SXin LI } 23574d52a575SXin LI back: 2358398f1b65SPyun YongHyeon return (error); 23594d52a575SXin LI } 23604d52a575SXin LI 23614d52a575SXin LI static int 23624d52a575SXin LI et_sysctl_rx_intr_delay(SYSCTL_HANDLER_ARGS) 23634d52a575SXin LI { 23644d52a575SXin LI struct et_softc *sc = arg1; 23654d52a575SXin LI struct ifnet *ifp = sc->ifp; 23664d52a575SXin LI int error = 0, v; 23674d52a575SXin LI 23684d52a575SXin LI v = sc->sc_rx_intr_delay; 23694d52a575SXin LI error = sysctl_handle_int(oidp, &v, 0, req); 23704d52a575SXin LI if (error || req->newptr == NULL) 23714d52a575SXin LI goto back; 23724d52a575SXin LI if (v <= 0) { 23734d52a575SXin LI error = EINVAL; 23744d52a575SXin LI goto back; 23754d52a575SXin LI } 23764d52a575SXin LI 23774d52a575SXin LI if (sc->sc_rx_intr_delay != v) { 23784d52a575SXin LI if (ifp->if_drv_flags & IFF_DRV_RUNNING) 23794d52a575SXin LI CSR_WRITE_4(sc, ET_RX_INTR_DELAY, v); 23804d52a575SXin LI sc->sc_rx_intr_delay = v; 23814d52a575SXin LI } 23824d52a575SXin LI back: 2383398f1b65SPyun YongHyeon return (error); 23844d52a575SXin LI } 23854d52a575SXin LI 23864d52a575SXin LI static void 23874d52a575SXin LI et_setmedia(struct et_softc *sc) 23884d52a575SXin LI { 23894d52a575SXin LI struct mii_data *mii = device_get_softc(sc->sc_miibus); 23904d52a575SXin LI uint32_t cfg2, ctrl; 23914d52a575SXin LI 23924d52a575SXin LI cfg2 = CSR_READ_4(sc, ET_MAC_CFG2); 23934d52a575SXin LI cfg2 &= ~(ET_MAC_CFG2_MODE_MII | ET_MAC_CFG2_MODE_GMII | 23944d52a575SXin LI ET_MAC_CFG2_FDX | ET_MAC_CFG2_BIGFRM); 23954d52a575SXin LI cfg2 |= ET_MAC_CFG2_LENCHK | ET_MAC_CFG2_CRC | ET_MAC_CFG2_PADCRC | 239623263665SPyun YongHyeon ((7 << ET_MAC_CFG2_PREAMBLE_LEN_SHIFT) & 239723263665SPyun YongHyeon ET_MAC_CFG2_PREAMBLE_LEN_MASK); 23984d52a575SXin LI 23994d52a575SXin LI ctrl = CSR_READ_4(sc, ET_MAC_CTRL); 24004d52a575SXin LI ctrl &= ~(ET_MAC_CTRL_GHDX | ET_MAC_CTRL_MODE_MII); 24014d52a575SXin LI 24024d52a575SXin LI if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { 24034d52a575SXin LI cfg2 |= ET_MAC_CFG2_MODE_GMII; 24044d52a575SXin LI } else { 24054d52a575SXin LI cfg2 |= ET_MAC_CFG2_MODE_MII; 24064d52a575SXin LI ctrl |= ET_MAC_CTRL_MODE_MII; 24074d52a575SXin LI } 24084d52a575SXin LI 24094d52a575SXin LI if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) 24104d52a575SXin LI cfg2 |= ET_MAC_CFG2_FDX; 24114d52a575SXin LI else 24124d52a575SXin LI ctrl |= ET_MAC_CTRL_GHDX; 24134d52a575SXin LI 24144d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CTRL, ctrl); 24154d52a575SXin LI CSR_WRITE_4(sc, ET_MAC_CFG2, cfg2); 24164d52a575SXin LI } 24174d52a575SXin LI 24184d52a575SXin LI static void 24194d52a575SXin LI et_setup_rxdesc(struct et_rxbuf_data *rbd, int buf_idx, bus_addr_t paddr) 24204d52a575SXin LI { 24214d52a575SXin LI struct et_rxdesc_ring *rx_ring = rbd->rbd_ring; 24224d52a575SXin LI struct et_rxdesc *desc; 24234d52a575SXin LI 24244d52a575SXin LI MPASS(buf_idx < ET_RX_NDESC); 24254d52a575SXin LI desc = &rx_ring->rr_desc[buf_idx]; 24264d52a575SXin LI 24274d52a575SXin LI desc->rd_addr_hi = ET_ADDR_HI(paddr); 24284d52a575SXin LI desc->rd_addr_lo = ET_ADDR_LO(paddr); 242923263665SPyun YongHyeon desc->rd_ctrl = buf_idx & ET_RDCTRL_BUFIDX_MASK; 24304d52a575SXin LI 24314d52a575SXin LI bus_dmamap_sync(rx_ring->rr_dtag, rx_ring->rr_dmap, 24324d52a575SXin LI BUS_DMASYNC_PREWRITE); 24334d52a575SXin LI } 2434