13b22dc82SSepherosa Ziehau /*- 23b22dc82SSepherosa Ziehau * Copyright (c) 2008, Pyun YongHyeon <yongari@FreeBSD.org> 33b22dc82SSepherosa Ziehau * All rights reserved. 43b22dc82SSepherosa Ziehau * 53b22dc82SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 63b22dc82SSepherosa Ziehau * modification, are permitted provided that the following conditions 73b22dc82SSepherosa Ziehau * are met: 83b22dc82SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 93b22dc82SSepherosa Ziehau * notice unmodified, this list of conditions, and the following 103b22dc82SSepherosa Ziehau * disclaimer. 113b22dc82SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 123b22dc82SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 133b22dc82SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 143b22dc82SSepherosa Ziehau * 153b22dc82SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 163b22dc82SSepherosa Ziehau * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 173b22dc82SSepherosa Ziehau * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 183b22dc82SSepherosa Ziehau * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 193b22dc82SSepherosa Ziehau * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 203b22dc82SSepherosa Ziehau * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 213b22dc82SSepherosa Ziehau * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 223b22dc82SSepherosa Ziehau * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 233b22dc82SSepherosa Ziehau * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 243b22dc82SSepherosa Ziehau * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 253b22dc82SSepherosa Ziehau * SUCH DAMAGE. 263b22dc82SSepherosa Ziehau * 273b22dc82SSepherosa Ziehau * $FreeBSD: src/sys/dev/age/if_age.c,v 1.6 2008/11/07 07:02:28 yongari Exp $ 283b22dc82SSepherosa Ziehau */ 293b22dc82SSepherosa Ziehau 303b22dc82SSepherosa Ziehau /* Driver for Attansic Technology Corp. L1 Gigabit Ethernet. */ 313b22dc82SSepherosa Ziehau 323b22dc82SSepherosa Ziehau #include <sys/param.h> 333b22dc82SSepherosa Ziehau #include <sys/endian.h> 343b22dc82SSepherosa Ziehau #include <sys/kernel.h> 353b22dc82SSepherosa Ziehau #include <sys/bus.h> 363b22dc82SSepherosa Ziehau #include <sys/interrupt.h> 373b22dc82SSepherosa Ziehau #include <sys/malloc.h> 383b22dc82SSepherosa Ziehau #include <sys/proc.h> 393b22dc82SSepherosa Ziehau #include <sys/rman.h> 403b22dc82SSepherosa Ziehau #include <sys/serialize.h> 413b22dc82SSepherosa Ziehau #include <sys/socket.h> 423b22dc82SSepherosa Ziehau #include <sys/sockio.h> 433b22dc82SSepherosa Ziehau #include <sys/sysctl.h> 443b22dc82SSepherosa Ziehau 453b22dc82SSepherosa Ziehau #include <net/ethernet.h> 463b22dc82SSepherosa Ziehau #include <net/if.h> 473b22dc82SSepherosa Ziehau #include <net/bpf.h> 483b22dc82SSepherosa Ziehau #include <net/if_arp.h> 493b22dc82SSepherosa Ziehau #include <net/if_dl.h> 503b22dc82SSepherosa Ziehau #include <net/if_media.h> 513b22dc82SSepherosa Ziehau #include <net/ifq_var.h> 523b22dc82SSepherosa Ziehau #include <net/vlan/if_vlan_var.h> 533b22dc82SSepherosa Ziehau #include <net/vlan/if_vlan_ether.h> 543b22dc82SSepherosa Ziehau 553b22dc82SSepherosa Ziehau #include <dev/netif/mii_layer/miivar.h> 563b22dc82SSepherosa Ziehau #include <dev/netif/mii_layer/jmphyreg.h> 573b22dc82SSepherosa Ziehau 583b22dc82SSepherosa Ziehau #include <bus/pci/pcireg.h> 593b22dc82SSepherosa Ziehau #include <bus/pci/pcivar.h> 60dcb4b80dSSascha Wildner #include "pcidevs.h" 613b22dc82SSepherosa Ziehau 623b22dc82SSepherosa Ziehau #include <dev/netif/age/if_agereg.h> 633b22dc82SSepherosa Ziehau #include <dev/netif/age/if_agevar.h> 643b22dc82SSepherosa Ziehau 653b22dc82SSepherosa Ziehau /* "device miibus" required. See GENERIC if you get errors here. */ 663b22dc82SSepherosa Ziehau #include "miibus_if.h" 673b22dc82SSepherosa Ziehau 683b22dc82SSepherosa Ziehau #define AGE_CSUM_FEATURES (CSUM_TCP | CSUM_UDP) 693b22dc82SSepherosa Ziehau 703b22dc82SSepherosa Ziehau struct age_dmamap_ctx { 713b22dc82SSepherosa Ziehau int nsegs; 723b22dc82SSepherosa Ziehau bus_dma_segment_t *segs; 733b22dc82SSepherosa Ziehau }; 743b22dc82SSepherosa Ziehau 753b22dc82SSepherosa Ziehau static int age_probe(device_t); 763b22dc82SSepherosa Ziehau static int age_attach(device_t); 773b22dc82SSepherosa Ziehau static int age_detach(device_t); 783b22dc82SSepherosa Ziehau static int age_shutdown(device_t); 793b22dc82SSepherosa Ziehau static int age_suspend(device_t); 803b22dc82SSepherosa Ziehau static int age_resume(device_t); 813b22dc82SSepherosa Ziehau 823b22dc82SSepherosa Ziehau static int age_miibus_readreg(device_t, int, int); 833b22dc82SSepherosa Ziehau static int age_miibus_writereg(device_t, int, int, int); 843b22dc82SSepherosa Ziehau static void age_miibus_statchg(device_t); 853b22dc82SSepherosa Ziehau 863b22dc82SSepherosa Ziehau static void age_init(void *); 873b22dc82SSepherosa Ziehau static int age_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *); 88f0a26983SSepherosa Ziehau static void age_start(struct ifnet *, struct ifaltq_subque *); 893b22dc82SSepherosa Ziehau static void age_watchdog(struct ifnet *); 903b22dc82SSepherosa Ziehau static void age_mediastatus(struct ifnet *, struct ifmediareq *); 913b22dc82SSepherosa Ziehau static int age_mediachange(struct ifnet *); 923b22dc82SSepherosa Ziehau 933b22dc82SSepherosa Ziehau static void age_intr(void *); 943b22dc82SSepherosa Ziehau static void age_txintr(struct age_softc *, int); 953b22dc82SSepherosa Ziehau static void age_rxintr(struct age_softc *, int); 963b22dc82SSepherosa Ziehau static void age_rxeof(struct age_softc *sc, struct rx_rdesc *); 973b22dc82SSepherosa Ziehau 983b22dc82SSepherosa Ziehau static int age_dma_alloc(struct age_softc *); 993b22dc82SSepherosa Ziehau static void age_dma_free(struct age_softc *); 1003b22dc82SSepherosa Ziehau static void age_dmamap_cb(void *, bus_dma_segment_t *, int, int); 1013b22dc82SSepherosa Ziehau static void age_dmamap_buf_cb(void *, bus_dma_segment_t *, int, 1023b22dc82SSepherosa Ziehau bus_size_t, int); 1033b22dc82SSepherosa Ziehau static int age_check_boundary(struct age_softc *); 1043b22dc82SSepherosa Ziehau static int age_newbuf(struct age_softc *, struct age_rxdesc *, int); 1053b22dc82SSepherosa Ziehau static int age_encap(struct age_softc *, struct mbuf **); 1063b22dc82SSepherosa Ziehau static void age_init_tx_ring(struct age_softc *); 1073b22dc82SSepherosa Ziehau static int age_init_rx_ring(struct age_softc *); 1083b22dc82SSepherosa Ziehau static void age_init_rr_ring(struct age_softc *); 1093b22dc82SSepherosa Ziehau static void age_init_cmb_block(struct age_softc *); 1103b22dc82SSepherosa Ziehau static void age_init_smb_block(struct age_softc *); 1113b22dc82SSepherosa Ziehau 1123b22dc82SSepherosa Ziehau static void age_tick(void *); 1133b22dc82SSepherosa Ziehau static void age_stop(struct age_softc *); 1143b22dc82SSepherosa Ziehau static void age_reset(struct age_softc *); 1153b22dc82SSepherosa Ziehau static int age_read_vpd_word(struct age_softc *, uint32_t, uint32_t, 1163b22dc82SSepherosa Ziehau uint32_t *); 1173b22dc82SSepherosa Ziehau static void age_get_macaddr(struct age_softc *); 1183b22dc82SSepherosa Ziehau static void age_phy_reset(struct age_softc *); 1193b22dc82SSepherosa Ziehau static void age_mac_config(struct age_softc *); 1203b22dc82SSepherosa Ziehau static void age_stats_update(struct age_softc *); 1213b22dc82SSepherosa Ziehau static void age_stop_txmac(struct age_softc *); 1223b22dc82SSepherosa Ziehau static void age_stop_rxmac(struct age_softc *); 1233b22dc82SSepherosa Ziehau static void age_rxvlan(struct age_softc *); 1243b22dc82SSepherosa Ziehau static void age_rxfilter(struct age_softc *); 1253b22dc82SSepherosa Ziehau #ifdef wol_notyet 1263b22dc82SSepherosa Ziehau static void age_setwol(struct age_softc *); 1273b22dc82SSepherosa Ziehau #endif 1283b22dc82SSepherosa Ziehau 1293b22dc82SSepherosa Ziehau static void age_sysctl_node(struct age_softc *); 1303b22dc82SSepherosa Ziehau static int sysctl_age_stats(SYSCTL_HANDLER_ARGS); 1313b22dc82SSepherosa Ziehau static int sysctl_hw_age_int_mod(SYSCTL_HANDLER_ARGS); 1323b22dc82SSepherosa Ziehau 1333b22dc82SSepherosa Ziehau /* 1343b22dc82SSepherosa Ziehau * Devices supported by this driver. 1353b22dc82SSepherosa Ziehau */ 1363b22dc82SSepherosa Ziehau static struct age_dev { 1373b22dc82SSepherosa Ziehau uint16_t age_vendorid; 1383b22dc82SSepherosa Ziehau uint16_t age_deviceid; 1393b22dc82SSepherosa Ziehau const char *age_name; 1403b22dc82SSepherosa Ziehau } age_devs[] = { 1413b22dc82SSepherosa Ziehau { VENDORID_ATTANSIC, DEVICEID_ATTANSIC_L1, 1423b22dc82SSepherosa Ziehau "Attansic Technology Corp, L1 Gigabit Ethernet" }, 1433b22dc82SSepherosa Ziehau }; 1443b22dc82SSepherosa Ziehau 1453b22dc82SSepherosa Ziehau static device_method_t age_methods[] = { 1463b22dc82SSepherosa Ziehau /* Device interface. */ 1473b22dc82SSepherosa Ziehau DEVMETHOD(device_probe, age_probe), 1483b22dc82SSepherosa Ziehau DEVMETHOD(device_attach, age_attach), 1493b22dc82SSepherosa Ziehau DEVMETHOD(device_detach, age_detach), 1503b22dc82SSepherosa Ziehau DEVMETHOD(device_shutdown, age_shutdown), 1513b22dc82SSepherosa Ziehau DEVMETHOD(device_suspend, age_suspend), 1523b22dc82SSepherosa Ziehau DEVMETHOD(device_resume, age_resume), 1533b22dc82SSepherosa Ziehau 1543b22dc82SSepherosa Ziehau /* Bus interface. */ 1553b22dc82SSepherosa Ziehau DEVMETHOD(bus_print_child, bus_generic_print_child), 1563b22dc82SSepherosa Ziehau DEVMETHOD(bus_driver_added, bus_generic_driver_added), 1573b22dc82SSepherosa Ziehau 1583b22dc82SSepherosa Ziehau /* MII interface. */ 1593b22dc82SSepherosa Ziehau DEVMETHOD(miibus_readreg, age_miibus_readreg), 1603b22dc82SSepherosa Ziehau DEVMETHOD(miibus_writereg, age_miibus_writereg), 1613b22dc82SSepherosa Ziehau DEVMETHOD(miibus_statchg, age_miibus_statchg), 1623b22dc82SSepherosa Ziehau 1633b22dc82SSepherosa Ziehau { NULL, NULL } 1643b22dc82SSepherosa Ziehau }; 1653b22dc82SSepherosa Ziehau 1663b22dc82SSepherosa Ziehau static driver_t age_driver = { 1673b22dc82SSepherosa Ziehau "age", 1683b22dc82SSepherosa Ziehau age_methods, 1693b22dc82SSepherosa Ziehau sizeof(struct age_softc) 1703b22dc82SSepherosa Ziehau }; 1713b22dc82SSepherosa Ziehau 1723b22dc82SSepherosa Ziehau static devclass_t age_devclass; 1733b22dc82SSepherosa Ziehau 1743b22dc82SSepherosa Ziehau DECLARE_DUMMY_MODULE(if_age); 1753b22dc82SSepherosa Ziehau MODULE_DEPEND(if_age, miibus, 1, 1, 1); 176aa2b9d05SSascha Wildner DRIVER_MODULE(if_age, pci, age_driver, age_devclass, NULL, NULL); 177aa2b9d05SSascha Wildner DRIVER_MODULE(miibus, age, miibus_driver, miibus_devclass, NULL, NULL); 1783b22dc82SSepherosa Ziehau 1793b22dc82SSepherosa Ziehau /* 1803b22dc82SSepherosa Ziehau * Read a PHY register on the MII of the L1. 1813b22dc82SSepherosa Ziehau */ 1823b22dc82SSepherosa Ziehau static int 1833b22dc82SSepherosa Ziehau age_miibus_readreg(device_t dev, int phy, int reg) 1843b22dc82SSepherosa Ziehau { 1853b22dc82SSepherosa Ziehau struct age_softc *sc; 1863b22dc82SSepherosa Ziehau uint32_t v; 1873b22dc82SSepherosa Ziehau int i; 1883b22dc82SSepherosa Ziehau 1893b22dc82SSepherosa Ziehau sc = device_get_softc(dev); 1903b22dc82SSepherosa Ziehau if (phy != sc->age_phyaddr) 1913b22dc82SSepherosa Ziehau return (0); 1923b22dc82SSepherosa Ziehau 1933b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MDIO, MDIO_OP_EXECUTE | MDIO_OP_READ | 1943b22dc82SSepherosa Ziehau MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg)); 1953b22dc82SSepherosa Ziehau for (i = AGE_PHY_TIMEOUT; i > 0; i--) { 1963b22dc82SSepherosa Ziehau DELAY(1); 1973b22dc82SSepherosa Ziehau v = CSR_READ_4(sc, AGE_MDIO); 1983b22dc82SSepherosa Ziehau if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0) 1993b22dc82SSepherosa Ziehau break; 2003b22dc82SSepherosa Ziehau } 2013b22dc82SSepherosa Ziehau 2023b22dc82SSepherosa Ziehau if (i == 0) { 2033b22dc82SSepherosa Ziehau device_printf(sc->age_dev, "phy read timeout : %d\n", reg); 2043b22dc82SSepherosa Ziehau return (0); 2053b22dc82SSepherosa Ziehau } 2063b22dc82SSepherosa Ziehau 2073b22dc82SSepherosa Ziehau return ((v & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT); 2083b22dc82SSepherosa Ziehau } 2093b22dc82SSepherosa Ziehau 2103b22dc82SSepherosa Ziehau /* 2113b22dc82SSepherosa Ziehau * Write a PHY register on the MII of the L1. 2123b22dc82SSepherosa Ziehau */ 2133b22dc82SSepherosa Ziehau static int 2143b22dc82SSepherosa Ziehau age_miibus_writereg(device_t dev, int phy, int reg, int val) 2153b22dc82SSepherosa Ziehau { 2163b22dc82SSepherosa Ziehau struct age_softc *sc; 2173b22dc82SSepherosa Ziehau uint32_t v; 2183b22dc82SSepherosa Ziehau int i; 2193b22dc82SSepherosa Ziehau 2203b22dc82SSepherosa Ziehau sc = device_get_softc(dev); 2213b22dc82SSepherosa Ziehau if (phy != sc->age_phyaddr) 2223b22dc82SSepherosa Ziehau return (0); 2233b22dc82SSepherosa Ziehau 2243b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE | 2253b22dc82SSepherosa Ziehau (val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT | 2263b22dc82SSepherosa Ziehau MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg)); 2273b22dc82SSepherosa Ziehau for (i = AGE_PHY_TIMEOUT; i > 0; i--) { 2283b22dc82SSepherosa Ziehau DELAY(1); 2293b22dc82SSepherosa Ziehau v = CSR_READ_4(sc, AGE_MDIO); 2303b22dc82SSepherosa Ziehau if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0) 2313b22dc82SSepherosa Ziehau break; 2323b22dc82SSepherosa Ziehau } 2333b22dc82SSepherosa Ziehau 2343b22dc82SSepherosa Ziehau if (i == 0) 2353b22dc82SSepherosa Ziehau device_printf(sc->age_dev, "phy write timeout : %d\n", reg); 2363b22dc82SSepherosa Ziehau 2373b22dc82SSepherosa Ziehau return (0); 2383b22dc82SSepherosa Ziehau } 2393b22dc82SSepherosa Ziehau 2403b22dc82SSepherosa Ziehau /* 2413b22dc82SSepherosa Ziehau * Callback from MII layer when media changes. 2423b22dc82SSepherosa Ziehau */ 2433b22dc82SSepherosa Ziehau static void 2443b22dc82SSepherosa Ziehau age_miibus_statchg(device_t dev) 2453b22dc82SSepherosa Ziehau { 2463b22dc82SSepherosa Ziehau struct age_softc *sc = device_get_softc(dev); 2473b22dc82SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 2483b22dc82SSepherosa Ziehau struct mii_data *mii; 2493b22dc82SSepherosa Ziehau 2503b22dc82SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 2513b22dc82SSepherosa Ziehau 2523b22dc82SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0) 2533b22dc82SSepherosa Ziehau return; 2543b22dc82SSepherosa Ziehau 2553b22dc82SSepherosa Ziehau mii = device_get_softc(sc->age_miibus); 2563b22dc82SSepherosa Ziehau 2573b22dc82SSepherosa Ziehau sc->age_flags &= ~AGE_FLAG_LINK; 2583b22dc82SSepherosa Ziehau if ((mii->mii_media_status & IFM_AVALID) != 0) { 2593b22dc82SSepherosa Ziehau switch (IFM_SUBTYPE(mii->mii_media_active)) { 2603b22dc82SSepherosa Ziehau case IFM_10_T: 2613b22dc82SSepherosa Ziehau case IFM_100_TX: 2623b22dc82SSepherosa Ziehau case IFM_1000_T: 2633b22dc82SSepherosa Ziehau sc->age_flags |= AGE_FLAG_LINK; 2643b22dc82SSepherosa Ziehau break; 2653b22dc82SSepherosa Ziehau default: 2663b22dc82SSepherosa Ziehau break; 2673b22dc82SSepherosa Ziehau } 2683b22dc82SSepherosa Ziehau } 2693b22dc82SSepherosa Ziehau 2703b22dc82SSepherosa Ziehau /* Stop Rx/Tx MACs. */ 2713b22dc82SSepherosa Ziehau age_stop_rxmac(sc); 2723b22dc82SSepherosa Ziehau age_stop_txmac(sc); 2733b22dc82SSepherosa Ziehau 2743b22dc82SSepherosa Ziehau /* Program MACs with resolved speed/duplex/flow-control. */ 2753b22dc82SSepherosa Ziehau if ((sc->age_flags & AGE_FLAG_LINK) != 0) { 2763b22dc82SSepherosa Ziehau uint32_t reg; 2773b22dc82SSepherosa Ziehau 2783b22dc82SSepherosa Ziehau age_mac_config(sc); 2793b22dc82SSepherosa Ziehau 2803b22dc82SSepherosa Ziehau reg = CSR_READ_4(sc, AGE_MAC_CFG); 2813b22dc82SSepherosa Ziehau /* Restart DMA engine and Tx/Rx MAC. */ 2823b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_DMA_CFG, CSR_READ_4(sc, AGE_DMA_CFG) | 2833b22dc82SSepherosa Ziehau DMA_CFG_RD_ENB | DMA_CFG_WR_ENB); 2843b22dc82SSepherosa Ziehau reg |= MAC_CFG_TX_ENB | MAC_CFG_RX_ENB; 2853b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MAC_CFG, reg); 2863b22dc82SSepherosa Ziehau } 2873b22dc82SSepherosa Ziehau } 2883b22dc82SSepherosa Ziehau 2893b22dc82SSepherosa Ziehau /* 2903b22dc82SSepherosa Ziehau * Get the current interface media status. 2913b22dc82SSepherosa Ziehau */ 2923b22dc82SSepherosa Ziehau static void 2933b22dc82SSepherosa Ziehau age_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 2943b22dc82SSepherosa Ziehau { 2953b22dc82SSepherosa Ziehau struct age_softc *sc = ifp->if_softc; 2963b22dc82SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->age_miibus); 2973b22dc82SSepherosa Ziehau 2983b22dc82SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 2993b22dc82SSepherosa Ziehau 3003b22dc82SSepherosa Ziehau mii_pollstat(mii); 3013b22dc82SSepherosa Ziehau ifmr->ifm_status = mii->mii_media_status; 3023b22dc82SSepherosa Ziehau ifmr->ifm_active = mii->mii_media_active; 3033b22dc82SSepherosa Ziehau } 3043b22dc82SSepherosa Ziehau 3053b22dc82SSepherosa Ziehau /* 3063b22dc82SSepherosa Ziehau * Set hardware to newly-selected media. 3073b22dc82SSepherosa Ziehau */ 3083b22dc82SSepherosa Ziehau static int 3093b22dc82SSepherosa Ziehau age_mediachange(struct ifnet *ifp) 3103b22dc82SSepherosa Ziehau { 3113b22dc82SSepherosa Ziehau struct age_softc *sc = ifp->if_softc; 3123b22dc82SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->age_miibus); 3133b22dc82SSepherosa Ziehau int error; 3143b22dc82SSepherosa Ziehau 3153b22dc82SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 3163b22dc82SSepherosa Ziehau 3173b22dc82SSepherosa Ziehau if (mii->mii_instance != 0) { 3183b22dc82SSepherosa Ziehau struct mii_softc *miisc; 3193b22dc82SSepherosa Ziehau 3203b22dc82SSepherosa Ziehau LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 3213b22dc82SSepherosa Ziehau mii_phy_reset(miisc); 3223b22dc82SSepherosa Ziehau } 3233b22dc82SSepherosa Ziehau error = mii_mediachg(mii); 3243b22dc82SSepherosa Ziehau 3253b22dc82SSepherosa Ziehau return (error); 3263b22dc82SSepherosa Ziehau } 3273b22dc82SSepherosa Ziehau 3283b22dc82SSepherosa Ziehau static int 3293b22dc82SSepherosa Ziehau age_read_vpd_word(struct age_softc *sc, uint32_t vpdc, uint32_t offset, 3303b22dc82SSepherosa Ziehau uint32_t *word) 3313b22dc82SSepherosa Ziehau { 3323b22dc82SSepherosa Ziehau int i; 3333b22dc82SSepherosa Ziehau 3343b22dc82SSepherosa Ziehau pci_write_config(sc->age_dev, vpdc + PCIR_VPD_ADDR, offset, 2); 3353b22dc82SSepherosa Ziehau for (i = AGE_TIMEOUT; i > 0; i--) { 3363b22dc82SSepherosa Ziehau DELAY(10); 3373b22dc82SSepherosa Ziehau if ((pci_read_config(sc->age_dev, vpdc + PCIR_VPD_ADDR, 2) & 3383b22dc82SSepherosa Ziehau 0x8000) == 0x8000) 3393b22dc82SSepherosa Ziehau break; 3403b22dc82SSepherosa Ziehau } 3413b22dc82SSepherosa Ziehau if (i == 0) { 3423b22dc82SSepherosa Ziehau device_printf(sc->age_dev, "VPD read timeout!\n"); 3433b22dc82SSepherosa Ziehau *word = 0; 3443b22dc82SSepherosa Ziehau return (ETIMEDOUT); 3453b22dc82SSepherosa Ziehau } 3463b22dc82SSepherosa Ziehau 3473b22dc82SSepherosa Ziehau *word = pci_read_config(sc->age_dev, vpdc + PCIR_VPD_DATA, 4); 3483b22dc82SSepherosa Ziehau return (0); 3493b22dc82SSepherosa Ziehau } 3503b22dc82SSepherosa Ziehau 3513b22dc82SSepherosa Ziehau static int 3523b22dc82SSepherosa Ziehau age_probe(device_t dev) 3533b22dc82SSepherosa Ziehau { 3543b22dc82SSepherosa Ziehau struct age_dev *sp; 3553b22dc82SSepherosa Ziehau int i; 3563b22dc82SSepherosa Ziehau uint16_t vendor, devid; 3573b22dc82SSepherosa Ziehau 3583b22dc82SSepherosa Ziehau vendor = pci_get_vendor(dev); 3593b22dc82SSepherosa Ziehau devid = pci_get_device(dev); 3603b22dc82SSepherosa Ziehau sp = age_devs; 361c157ff7aSSascha Wildner for (i = 0; i < NELEM(age_devs); i++, sp++) { 3623b22dc82SSepherosa Ziehau if (vendor == sp->age_vendorid && 3633b22dc82SSepherosa Ziehau devid == sp->age_deviceid) { 3643b22dc82SSepherosa Ziehau device_set_desc(dev, sp->age_name); 3653b22dc82SSepherosa Ziehau return (0); 3663b22dc82SSepherosa Ziehau } 3673b22dc82SSepherosa Ziehau } 3683b22dc82SSepherosa Ziehau return (ENXIO); 3693b22dc82SSepherosa Ziehau } 3703b22dc82SSepherosa Ziehau 3713b22dc82SSepherosa Ziehau static void 3723b22dc82SSepherosa Ziehau age_get_macaddr(struct age_softc *sc) 3733b22dc82SSepherosa Ziehau { 3743b22dc82SSepherosa Ziehau uint32_t ea[2], off, reg, word; 3753b22dc82SSepherosa Ziehau int vpd_error, match, vpdc; 3763b22dc82SSepherosa Ziehau 3773b22dc82SSepherosa Ziehau reg = CSR_READ_4(sc, AGE_SPI_CTRL); 3783b22dc82SSepherosa Ziehau if ((reg & SPI_VPD_ENB) != 0) { 3793b22dc82SSepherosa Ziehau /* Get VPD stored in TWSI EEPROM. */ 3803b22dc82SSepherosa Ziehau reg &= ~SPI_VPD_ENB; 3813b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_SPI_CTRL, reg); 3823b22dc82SSepherosa Ziehau } 3833b22dc82SSepherosa Ziehau 3843b22dc82SSepherosa Ziehau ea[0] = ea[1] = 0; 3853b22dc82SSepherosa Ziehau vpdc = pci_get_vpdcap_ptr(sc->age_dev); 3863b22dc82SSepherosa Ziehau if (vpdc) { 3873b22dc82SSepherosa Ziehau vpd_error = 0; 3883b22dc82SSepherosa Ziehau 3893b22dc82SSepherosa Ziehau /* 3903b22dc82SSepherosa Ziehau * PCI VPD capability exists, but it seems that it's 3913b22dc82SSepherosa Ziehau * not in the standard form as stated in PCI VPD 3923b22dc82SSepherosa Ziehau * specification such that driver could not use 3933b22dc82SSepherosa Ziehau * pci_get_vpd_readonly(9) with keyword 'NA'. 3943b22dc82SSepherosa Ziehau * Search VPD data starting at address 0x0100. The data 3953b22dc82SSepherosa Ziehau * should be used as initializers to set AGE_PAR0, 3963b22dc82SSepherosa Ziehau * AGE_PAR1 register including other PCI configuration 3973b22dc82SSepherosa Ziehau * registers. 3983b22dc82SSepherosa Ziehau */ 3993b22dc82SSepherosa Ziehau word = 0; 4003b22dc82SSepherosa Ziehau match = 0; 4013b22dc82SSepherosa Ziehau reg = 0; 4023b22dc82SSepherosa Ziehau for (off = AGE_VPD_REG_CONF_START; off < AGE_VPD_REG_CONF_END; 4033b22dc82SSepherosa Ziehau off += sizeof(uint32_t)) { 4043b22dc82SSepherosa Ziehau vpd_error = age_read_vpd_word(sc, vpdc, off, &word); 4053b22dc82SSepherosa Ziehau if (vpd_error != 0) 4063b22dc82SSepherosa Ziehau break; 4073b22dc82SSepherosa Ziehau if (match != 0) { 4083b22dc82SSepherosa Ziehau switch (reg) { 4093b22dc82SSepherosa Ziehau case AGE_PAR0: 4103b22dc82SSepherosa Ziehau ea[0] = word; 4113b22dc82SSepherosa Ziehau break; 4123b22dc82SSepherosa Ziehau case AGE_PAR1: 4133b22dc82SSepherosa Ziehau ea[1] = word; 4143b22dc82SSepherosa Ziehau break; 4153b22dc82SSepherosa Ziehau default: 4163b22dc82SSepherosa Ziehau break; 4173b22dc82SSepherosa Ziehau } 4183b22dc82SSepherosa Ziehau match = 0; 4193b22dc82SSepherosa Ziehau } else if ((word & 0xFF) == AGE_VPD_REG_CONF_SIG) { 4203b22dc82SSepherosa Ziehau match = 1; 4213b22dc82SSepherosa Ziehau reg = word >> 16; 4223b22dc82SSepherosa Ziehau } else 4233b22dc82SSepherosa Ziehau break; 4243b22dc82SSepherosa Ziehau } 4253b22dc82SSepherosa Ziehau if (off >= AGE_VPD_REG_CONF_END) 4263b22dc82SSepherosa Ziehau vpd_error = ENOENT; 4273b22dc82SSepherosa Ziehau if (vpd_error == 0) { 4283b22dc82SSepherosa Ziehau /* 4293b22dc82SSepherosa Ziehau * Don't blindly trust ethernet address obtained 4303b22dc82SSepherosa Ziehau * from VPD. Check whether ethernet address is 4313b22dc82SSepherosa Ziehau * valid one. Otherwise fall-back to reading 4323b22dc82SSepherosa Ziehau * PAR register. 4333b22dc82SSepherosa Ziehau */ 4343b22dc82SSepherosa Ziehau ea[1] &= 0xFFFF; 4353b22dc82SSepherosa Ziehau if ((ea[0] == 0 && ea[1] == 0) || 4363b22dc82SSepherosa Ziehau (ea[0] == 0xFFFFFFFF && ea[1] == 0xFFFF)) { 4373b22dc82SSepherosa Ziehau if (bootverbose) 4383b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 4393b22dc82SSepherosa Ziehau "invalid ethernet address " 4403b22dc82SSepherosa Ziehau "returned from VPD.\n"); 4413b22dc82SSepherosa Ziehau vpd_error = EINVAL; 4423b22dc82SSepherosa Ziehau } 4433b22dc82SSepherosa Ziehau } 4443b22dc82SSepherosa Ziehau if (vpd_error != 0 && (bootverbose)) 4453b22dc82SSepherosa Ziehau device_printf(sc->age_dev, "VPD access failure!\n"); 4463b22dc82SSepherosa Ziehau } else { 4473b22dc82SSepherosa Ziehau vpd_error = ENOENT; 4483b22dc82SSepherosa Ziehau if (bootverbose) 4493b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 4503b22dc82SSepherosa Ziehau "PCI VPD capability not found!\n"); 4513b22dc82SSepherosa Ziehau } 4523b22dc82SSepherosa Ziehau 4533b22dc82SSepherosa Ziehau /* 4543b22dc82SSepherosa Ziehau * It seems that L1 also provides a way to extract ethernet 4553b22dc82SSepherosa Ziehau * address via SPI flash interface. Because SPI flash memory 4563b22dc82SSepherosa Ziehau * device of different vendors vary in their instruction 4573b22dc82SSepherosa Ziehau * codes for read ID instruction, it's very hard to get 4583b22dc82SSepherosa Ziehau * instructions codes without detailed information for the 4593b22dc82SSepherosa Ziehau * flash memory device used on ethernet controller. To simplify 4603b22dc82SSepherosa Ziehau * code, just read AGE_PAR0/AGE_PAR1 register to get ethernet 4613b22dc82SSepherosa Ziehau * address which is supposed to be set by hardware during 4623b22dc82SSepherosa Ziehau * power on reset. 4633b22dc82SSepherosa Ziehau */ 4643b22dc82SSepherosa Ziehau if (vpd_error != 0) { 4653b22dc82SSepherosa Ziehau /* 4663b22dc82SSepherosa Ziehau * VPD is mapped to SPI flash memory or BIOS set it. 4673b22dc82SSepherosa Ziehau */ 4683b22dc82SSepherosa Ziehau ea[0] = CSR_READ_4(sc, AGE_PAR0); 4693b22dc82SSepherosa Ziehau ea[1] = CSR_READ_4(sc, AGE_PAR1); 4703b22dc82SSepherosa Ziehau } 4713b22dc82SSepherosa Ziehau 4723b22dc82SSepherosa Ziehau ea[1] &= 0xFFFF; 4733b22dc82SSepherosa Ziehau if ((ea[0] == 0 && ea[1] == 0) || 4743b22dc82SSepherosa Ziehau (ea[0] == 0xFFFFFFFF && ea[1] == 0xFFFF)) { 4753b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 4763b22dc82SSepherosa Ziehau "generating fake ethernet address.\n"); 4773b22dc82SSepherosa Ziehau ea[0] = karc4random(); 4783b22dc82SSepherosa Ziehau /* Set OUI to ASUSTek COMPUTER INC. */ 4793b22dc82SSepherosa Ziehau sc->age_eaddr[0] = 0x00; 4803b22dc82SSepherosa Ziehau sc->age_eaddr[1] = 0x1B; 4813b22dc82SSepherosa Ziehau sc->age_eaddr[2] = 0xFC; 4823b22dc82SSepherosa Ziehau sc->age_eaddr[3] = (ea[0] >> 16) & 0xFF; 4833b22dc82SSepherosa Ziehau sc->age_eaddr[4] = (ea[0] >> 8) & 0xFF; 4843b22dc82SSepherosa Ziehau sc->age_eaddr[5] = (ea[0] >> 0) & 0xFF; 4853b22dc82SSepherosa Ziehau } else { 4863b22dc82SSepherosa Ziehau sc->age_eaddr[0] = (ea[1] >> 8) & 0xFF; 4873b22dc82SSepherosa Ziehau sc->age_eaddr[1] = (ea[1] >> 0) & 0xFF; 4883b22dc82SSepherosa Ziehau sc->age_eaddr[2] = (ea[0] >> 24) & 0xFF; 4893b22dc82SSepherosa Ziehau sc->age_eaddr[3] = (ea[0] >> 16) & 0xFF; 4903b22dc82SSepherosa Ziehau sc->age_eaddr[4] = (ea[0] >> 8) & 0xFF; 4913b22dc82SSepherosa Ziehau sc->age_eaddr[5] = (ea[0] >> 0) & 0xFF; 4923b22dc82SSepherosa Ziehau } 4933b22dc82SSepherosa Ziehau } 4943b22dc82SSepherosa Ziehau 4953b22dc82SSepherosa Ziehau static void 4963b22dc82SSepherosa Ziehau age_phy_reset(struct age_softc *sc) 4973b22dc82SSepherosa Ziehau { 4983b22dc82SSepherosa Ziehau /* Reset PHY. */ 4993b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_GPHY_CTRL, GPHY_CTRL_RST); 5003b22dc82SSepherosa Ziehau DELAY(1000); 5013b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_GPHY_CTRL, GPHY_CTRL_CLR); 5023b22dc82SSepherosa Ziehau DELAY(1000); 5033b22dc82SSepherosa Ziehau } 5043b22dc82SSepherosa Ziehau 5053b22dc82SSepherosa Ziehau static int 5063b22dc82SSepherosa Ziehau age_attach(device_t dev) 5073b22dc82SSepherosa Ziehau { 5083b22dc82SSepherosa Ziehau struct age_softc *sc = device_get_softc(dev); 5093b22dc82SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 5103b22dc82SSepherosa Ziehau uint8_t pcie_ptr; 5113b22dc82SSepherosa Ziehau int error; 5123b22dc82SSepherosa Ziehau 5133b22dc82SSepherosa Ziehau error = 0; 5143b22dc82SSepherosa Ziehau sc->age_dev = dev; 5153b22dc82SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 5163b22dc82SSepherosa Ziehau 5173b22dc82SSepherosa Ziehau callout_init(&sc->age_tick_ch); 5183b22dc82SSepherosa Ziehau 5193b22dc82SSepherosa Ziehau #ifndef BURN_BRIDGES 5203b22dc82SSepherosa Ziehau if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 5213b22dc82SSepherosa Ziehau uint32_t irq, mem; 5223b22dc82SSepherosa Ziehau 5233b22dc82SSepherosa Ziehau irq = pci_read_config(dev, PCIR_INTLINE, 4); 5243b22dc82SSepherosa Ziehau mem = pci_read_config(dev, AGE_PCIR_BAR, 4); 5253b22dc82SSepherosa Ziehau 5263b22dc82SSepherosa Ziehau device_printf(dev, "chip is in D%d power mode " 5273b22dc82SSepherosa Ziehau "-- setting to D0\n", pci_get_powerstate(dev)); 5283b22dc82SSepherosa Ziehau 5293b22dc82SSepherosa Ziehau pci_set_powerstate(dev, PCI_POWERSTATE_D0); 5303b22dc82SSepherosa Ziehau 5313b22dc82SSepherosa Ziehau pci_write_config(dev, PCIR_INTLINE, irq, 4); 5323b22dc82SSepherosa Ziehau pci_write_config(dev, AGE_PCIR_BAR, mem, 4); 5333b22dc82SSepherosa Ziehau } 5343b22dc82SSepherosa Ziehau #endif /* !BURN_BRIDGE */ 5353b22dc82SSepherosa Ziehau 5363b22dc82SSepherosa Ziehau /* Enable bus mastering */ 5373b22dc82SSepherosa Ziehau pci_enable_busmaster(dev); 5383b22dc82SSepherosa Ziehau 5393b22dc82SSepherosa Ziehau /* 5403b22dc82SSepherosa Ziehau * Allocate memory mapped IO 5413b22dc82SSepherosa Ziehau */ 5423b22dc82SSepherosa Ziehau sc->age_mem_rid = AGE_PCIR_BAR; 5433b22dc82SSepherosa Ziehau sc->age_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 5443b22dc82SSepherosa Ziehau &sc->age_mem_rid, RF_ACTIVE); 5453b22dc82SSepherosa Ziehau if (sc->age_mem_res == NULL) { 5463b22dc82SSepherosa Ziehau device_printf(dev, "can't allocate IO memory\n"); 5473b22dc82SSepherosa Ziehau return ENXIO; 5483b22dc82SSepherosa Ziehau } 5493b22dc82SSepherosa Ziehau sc->age_mem_bt = rman_get_bustag(sc->age_mem_res); 5503b22dc82SSepherosa Ziehau sc->age_mem_bh = rman_get_bushandle(sc->age_mem_res); 5513b22dc82SSepherosa Ziehau 5523b22dc82SSepherosa Ziehau /* 5533b22dc82SSepherosa Ziehau * Allocate IRQ 5543b22dc82SSepherosa Ziehau */ 5553b22dc82SSepherosa Ziehau sc->age_irq_rid = 0; 5563b22dc82SSepherosa Ziehau sc->age_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 5573b22dc82SSepherosa Ziehau &sc->age_irq_rid, 5583b22dc82SSepherosa Ziehau RF_SHAREABLE | RF_ACTIVE); 5593b22dc82SSepherosa Ziehau if (sc->age_irq_res == NULL) { 5603b22dc82SSepherosa Ziehau device_printf(dev, "can't allocate irq\n"); 5613b22dc82SSepherosa Ziehau error = ENXIO; 5623b22dc82SSepherosa Ziehau goto fail; 5633b22dc82SSepherosa Ziehau } 5643b22dc82SSepherosa Ziehau 5653b22dc82SSepherosa Ziehau /* Set PHY address. */ 5663b22dc82SSepherosa Ziehau sc->age_phyaddr = AGE_PHY_ADDR; 5673b22dc82SSepherosa Ziehau 5683b22dc82SSepherosa Ziehau /* Reset PHY. */ 5693b22dc82SSepherosa Ziehau age_phy_reset(sc); 5703b22dc82SSepherosa Ziehau 5713b22dc82SSepherosa Ziehau /* Reset the ethernet controller. */ 5723b22dc82SSepherosa Ziehau age_reset(sc); 5733b22dc82SSepherosa Ziehau 5743b22dc82SSepherosa Ziehau /* Get PCI and chip id/revision. */ 5753b22dc82SSepherosa Ziehau sc->age_rev = pci_get_revid(dev); 5763b22dc82SSepherosa Ziehau sc->age_chip_rev = CSR_READ_4(sc, AGE_MASTER_CFG) >> 5773b22dc82SSepherosa Ziehau MASTER_CHIP_REV_SHIFT; 5783b22dc82SSepherosa Ziehau if (bootverbose) { 5793b22dc82SSepherosa Ziehau device_printf(dev, "PCI device revision : 0x%04x\n", sc->age_rev); 5803b22dc82SSepherosa Ziehau device_printf(dev, "Chip id/revision : 0x%04x\n", 5813b22dc82SSepherosa Ziehau sc->age_chip_rev); 5823b22dc82SSepherosa Ziehau } 5833b22dc82SSepherosa Ziehau 5843b22dc82SSepherosa Ziehau /* 5853b22dc82SSepherosa Ziehau * XXX 5863b22dc82SSepherosa Ziehau * Unintialized hardware returns an invalid chip id/revision 5873b22dc82SSepherosa Ziehau * as well as 0xFFFFFFFF for Tx/Rx fifo length. It seems that 5883b22dc82SSepherosa Ziehau * unplugged cable results in putting hardware into automatic 5893b22dc82SSepherosa Ziehau * power down mode which in turn returns invalld chip revision. 5903b22dc82SSepherosa Ziehau */ 5913b22dc82SSepherosa Ziehau if (sc->age_chip_rev == 0xFFFF) { 5923b22dc82SSepherosa Ziehau device_printf(dev,"invalid chip revision : 0x%04x -- " 5933b22dc82SSepherosa Ziehau "not initialized?\n", sc->age_chip_rev); 5943b22dc82SSepherosa Ziehau error = ENXIO; 5953b22dc82SSepherosa Ziehau goto fail; 5963b22dc82SSepherosa Ziehau } 5973b22dc82SSepherosa Ziehau device_printf(dev, "%d Tx FIFO, %d Rx FIFO\n", 5983b22dc82SSepherosa Ziehau CSR_READ_4(sc, AGE_SRAM_TX_FIFO_LEN), 5993b22dc82SSepherosa Ziehau CSR_READ_4(sc, AGE_SRAM_RX_FIFO_LEN)); 6003b22dc82SSepherosa Ziehau 6013b22dc82SSepherosa Ziehau /* Get DMA parameters from PCIe device control register. */ 6023b22dc82SSepherosa Ziehau pcie_ptr = pci_get_pciecap_ptr(dev); 6033b22dc82SSepherosa Ziehau if (pcie_ptr) { 6043b22dc82SSepherosa Ziehau uint16_t devctl; 6053b22dc82SSepherosa Ziehau 6063b22dc82SSepherosa Ziehau sc->age_flags |= AGE_FLAG_PCIE; 6073b22dc82SSepherosa Ziehau devctl = pci_read_config(dev, pcie_ptr + PCIER_DEVCTRL, 2); 6083b22dc82SSepherosa Ziehau /* Max read request size. */ 6093b22dc82SSepherosa Ziehau sc->age_dma_rd_burst = ((devctl >> 12) & 0x07) << 6103b22dc82SSepherosa Ziehau DMA_CFG_RD_BURST_SHIFT; 6113b22dc82SSepherosa Ziehau /* Max payload size. */ 6123b22dc82SSepherosa Ziehau sc->age_dma_wr_burst = ((devctl >> 5) & 0x07) << 6133b22dc82SSepherosa Ziehau DMA_CFG_WR_BURST_SHIFT; 6143b22dc82SSepherosa Ziehau if (bootverbose) { 6153b22dc82SSepherosa Ziehau device_printf(dev, "Read request size : %d bytes.\n", 6163b22dc82SSepherosa Ziehau 128 << ((devctl >> 12) & 0x07)); 6173b22dc82SSepherosa Ziehau device_printf(dev, "TLP payload size : %d bytes.\n", 6183b22dc82SSepherosa Ziehau 128 << ((devctl >> 5) & 0x07)); 6193b22dc82SSepherosa Ziehau } 6203b22dc82SSepherosa Ziehau } else { 6213b22dc82SSepherosa Ziehau sc->age_dma_rd_burst = DMA_CFG_RD_BURST_128; 6223b22dc82SSepherosa Ziehau sc->age_dma_wr_burst = DMA_CFG_WR_BURST_128; 6233b22dc82SSepherosa Ziehau } 6243b22dc82SSepherosa Ziehau 6253b22dc82SSepherosa Ziehau /* Create device sysctl node. */ 6263b22dc82SSepherosa Ziehau age_sysctl_node(sc); 6273b22dc82SSepherosa Ziehau 6283b22dc82SSepherosa Ziehau if ((error = age_dma_alloc(sc) != 0)) 6293b22dc82SSepherosa Ziehau goto fail; 6303b22dc82SSepherosa Ziehau 6313b22dc82SSepherosa Ziehau /* Load station address. */ 6323b22dc82SSepherosa Ziehau age_get_macaddr(sc); 6333b22dc82SSepherosa Ziehau 6343b22dc82SSepherosa Ziehau ifp->if_softc = sc; 6353b22dc82SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 6363b22dc82SSepherosa Ziehau ifp->if_ioctl = age_ioctl; 6373b22dc82SSepherosa Ziehau ifp->if_start = age_start; 6383b22dc82SSepherosa Ziehau ifp->if_init = age_init; 6393b22dc82SSepherosa Ziehau ifp->if_watchdog = age_watchdog; 6403b22dc82SSepherosa Ziehau ifq_set_maxlen(&ifp->if_snd, AGE_TX_RING_CNT - 1); 6413b22dc82SSepherosa Ziehau ifq_set_ready(&ifp->if_snd); 6423b22dc82SSepherosa Ziehau 6433b22dc82SSepherosa Ziehau ifp->if_capabilities = IFCAP_HWCSUM | 6443b22dc82SSepherosa Ziehau IFCAP_VLAN_MTU | 6453b22dc82SSepherosa Ziehau IFCAP_VLAN_HWTAGGING; 6463b22dc82SSepherosa Ziehau ifp->if_hwassist = AGE_CSUM_FEATURES; 6473b22dc82SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 6483b22dc82SSepherosa Ziehau 6493b22dc82SSepherosa Ziehau /* Set up MII bus. */ 6503b22dc82SSepherosa Ziehau if ((error = mii_phy_probe(dev, &sc->age_miibus, age_mediachange, 6513b22dc82SSepherosa Ziehau age_mediastatus)) != 0) { 6523b22dc82SSepherosa Ziehau device_printf(dev, "no PHY found!\n"); 6533b22dc82SSepherosa Ziehau goto fail; 6543b22dc82SSepherosa Ziehau } 6553b22dc82SSepherosa Ziehau 6563b22dc82SSepherosa Ziehau ether_ifattach(ifp, sc->age_eaddr, NULL); 6573b22dc82SSepherosa Ziehau 6583b22dc82SSepherosa Ziehau /* Tell the upper layer(s) we support long frames. */ 6593b22dc82SSepherosa Ziehau ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 6603b22dc82SSepherosa Ziehau 6614c77af2dSSepherosa Ziehau ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->age_irq_res)); 6624c77af2dSSepherosa Ziehau 6633b22dc82SSepherosa Ziehau error = bus_setup_intr(dev, sc->age_irq_res, INTR_MPSAFE, age_intr, sc, 6643b22dc82SSepherosa Ziehau &sc->age_irq_handle, ifp->if_serializer); 6653b22dc82SSepherosa Ziehau if (error) { 6663b22dc82SSepherosa Ziehau device_printf(dev, "could not set up interrupt handler.\n"); 6673b22dc82SSepherosa Ziehau ether_ifdetach(ifp); 6683b22dc82SSepherosa Ziehau goto fail; 6693b22dc82SSepherosa Ziehau } 6703b22dc82SSepherosa Ziehau 6713b22dc82SSepherosa Ziehau return 0; 6723b22dc82SSepherosa Ziehau fail: 6733b22dc82SSepherosa Ziehau age_detach(dev); 6743b22dc82SSepherosa Ziehau return (error); 6753b22dc82SSepherosa Ziehau } 6763b22dc82SSepherosa Ziehau 6773b22dc82SSepherosa Ziehau static int 6783b22dc82SSepherosa Ziehau age_detach(device_t dev) 6793b22dc82SSepherosa Ziehau { 6803b22dc82SSepherosa Ziehau struct age_softc *sc = device_get_softc(dev); 6813b22dc82SSepherosa Ziehau 6823b22dc82SSepherosa Ziehau if (device_is_attached(dev)) { 6833b22dc82SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 6843b22dc82SSepherosa Ziehau 6853b22dc82SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 6863b22dc82SSepherosa Ziehau sc->age_flags |= AGE_FLAG_DETACH; 6873b22dc82SSepherosa Ziehau age_stop(sc); 6883b22dc82SSepherosa Ziehau bus_teardown_intr(dev, sc->age_irq_res, sc->age_irq_handle); 6893b22dc82SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 6903b22dc82SSepherosa Ziehau 6913b22dc82SSepherosa Ziehau ether_ifdetach(ifp); 6923b22dc82SSepherosa Ziehau } 6933b22dc82SSepherosa Ziehau 6943b22dc82SSepherosa Ziehau if (sc->age_miibus != NULL) 6953b22dc82SSepherosa Ziehau device_delete_child(dev, sc->age_miibus); 6963b22dc82SSepherosa Ziehau bus_generic_detach(dev); 6973b22dc82SSepherosa Ziehau 6983b22dc82SSepherosa Ziehau if (sc->age_irq_res != NULL) { 6993b22dc82SSepherosa Ziehau bus_release_resource(dev, SYS_RES_IRQ, sc->age_irq_rid, 7003b22dc82SSepherosa Ziehau sc->age_irq_res); 7013b22dc82SSepherosa Ziehau } 7023b22dc82SSepherosa Ziehau if (sc->age_mem_res != NULL) { 7033b22dc82SSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, sc->age_mem_rid, 7043b22dc82SSepherosa Ziehau sc->age_mem_res); 7053b22dc82SSepherosa Ziehau } 7063b22dc82SSepherosa Ziehau 7073b22dc82SSepherosa Ziehau age_dma_free(sc); 7083b22dc82SSepherosa Ziehau 7093b22dc82SSepherosa Ziehau return (0); 7103b22dc82SSepherosa Ziehau } 7113b22dc82SSepherosa Ziehau 7123b22dc82SSepherosa Ziehau static void 7133b22dc82SSepherosa Ziehau age_sysctl_node(struct age_softc *sc) 7143b22dc82SSepherosa Ziehau { 715*26595b18SSascha Wildner struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->age_dev); 716*26595b18SSascha Wildner struct sysctl_oid *tree = device_get_sysctl_tree(sc->age_dev); 7173b22dc82SSepherosa Ziehau int error; 7183b22dc82SSepherosa Ziehau 719*26595b18SSascha Wildner SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 7203b22dc82SSepherosa Ziehau "stats", CTLTYPE_INT | CTLFLAG_RW, sc, 0, sysctl_age_stats, 7213b22dc82SSepherosa Ziehau "I", "Statistics"); 7223b22dc82SSepherosa Ziehau 723*26595b18SSascha Wildner SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 7243b22dc82SSepherosa Ziehau "int_mod", CTLTYPE_INT | CTLFLAG_RW, &sc->age_int_mod, 0, 7253b22dc82SSepherosa Ziehau sysctl_hw_age_int_mod, "I", "age interrupt moderation"); 7263b22dc82SSepherosa Ziehau 7273b22dc82SSepherosa Ziehau /* Pull in device tunables. */ 7283b22dc82SSepherosa Ziehau sc->age_int_mod = AGE_IM_TIMER_DEFAULT; 7293b22dc82SSepherosa Ziehau error = resource_int_value(device_get_name(sc->age_dev), 7303b22dc82SSepherosa Ziehau device_get_unit(sc->age_dev), "int_mod", &sc->age_int_mod); 7313b22dc82SSepherosa Ziehau if (error == 0) { 7323b22dc82SSepherosa Ziehau if (sc->age_int_mod < AGE_IM_TIMER_MIN || 7333b22dc82SSepherosa Ziehau sc->age_int_mod > AGE_IM_TIMER_MAX) { 7343b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 7353b22dc82SSepherosa Ziehau "int_mod value out of range; using default: %d\n", 7363b22dc82SSepherosa Ziehau AGE_IM_TIMER_DEFAULT); 7373b22dc82SSepherosa Ziehau sc->age_int_mod = AGE_IM_TIMER_DEFAULT; 7383b22dc82SSepherosa Ziehau } 7393b22dc82SSepherosa Ziehau } 7403b22dc82SSepherosa Ziehau } 7413b22dc82SSepherosa Ziehau 7423b22dc82SSepherosa Ziehau struct age_dmamap_arg { 7433b22dc82SSepherosa Ziehau bus_addr_t age_busaddr; 7443b22dc82SSepherosa Ziehau }; 7453b22dc82SSepherosa Ziehau 7463b22dc82SSepherosa Ziehau static void 7473b22dc82SSepherosa Ziehau age_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 7483b22dc82SSepherosa Ziehau { 7493b22dc82SSepherosa Ziehau struct age_dmamap_arg *ctx; 7503b22dc82SSepherosa Ziehau 7513b22dc82SSepherosa Ziehau if (error != 0) 7523b22dc82SSepherosa Ziehau return; 7533b22dc82SSepherosa Ziehau 7543b22dc82SSepherosa Ziehau KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 7553b22dc82SSepherosa Ziehau 7563b22dc82SSepherosa Ziehau ctx = (struct age_dmamap_arg *)arg; 7573b22dc82SSepherosa Ziehau ctx->age_busaddr = segs[0].ds_addr; 7583b22dc82SSepherosa Ziehau } 7593b22dc82SSepherosa Ziehau 7603b22dc82SSepherosa Ziehau /* 7613b22dc82SSepherosa Ziehau * Attansic L1 controller have single register to specify high 7623b22dc82SSepherosa Ziehau * address part of DMA blocks. So all descriptor structures and 7633b22dc82SSepherosa Ziehau * DMA memory blocks should have the same high address of given 7643b22dc82SSepherosa Ziehau * 4GB address space(i.e. crossing 4GB boundary is not allowed). 7653b22dc82SSepherosa Ziehau */ 7663b22dc82SSepherosa Ziehau static int 7673b22dc82SSepherosa Ziehau age_check_boundary(struct age_softc *sc) 7683b22dc82SSepherosa Ziehau { 7693b22dc82SSepherosa Ziehau bus_addr_t rx_ring_end, rr_ring_end, tx_ring_end; 7703b22dc82SSepherosa Ziehau bus_addr_t cmb_block_end, smb_block_end; 7713b22dc82SSepherosa Ziehau 7723b22dc82SSepherosa Ziehau /* Tx/Rx descriptor queue should reside within 4GB boundary. */ 7733b22dc82SSepherosa Ziehau tx_ring_end = sc->age_rdata.age_tx_ring_paddr + AGE_TX_RING_SZ; 7743b22dc82SSepherosa Ziehau rx_ring_end = sc->age_rdata.age_rx_ring_paddr + AGE_RX_RING_SZ; 7753b22dc82SSepherosa Ziehau rr_ring_end = sc->age_rdata.age_rr_ring_paddr + AGE_RR_RING_SZ; 7763b22dc82SSepherosa Ziehau cmb_block_end = sc->age_rdata.age_cmb_block_paddr + AGE_CMB_BLOCK_SZ; 7773b22dc82SSepherosa Ziehau smb_block_end = sc->age_rdata.age_smb_block_paddr + AGE_SMB_BLOCK_SZ; 7783b22dc82SSepherosa Ziehau 7793b22dc82SSepherosa Ziehau if ((AGE_ADDR_HI(tx_ring_end) != 7803b22dc82SSepherosa Ziehau AGE_ADDR_HI(sc->age_rdata.age_tx_ring_paddr)) || 7813b22dc82SSepherosa Ziehau (AGE_ADDR_HI(rx_ring_end) != 7823b22dc82SSepherosa Ziehau AGE_ADDR_HI(sc->age_rdata.age_rx_ring_paddr)) || 7833b22dc82SSepherosa Ziehau (AGE_ADDR_HI(rr_ring_end) != 7843b22dc82SSepherosa Ziehau AGE_ADDR_HI(sc->age_rdata.age_rr_ring_paddr)) || 7853b22dc82SSepherosa Ziehau (AGE_ADDR_HI(cmb_block_end) != 7863b22dc82SSepherosa Ziehau AGE_ADDR_HI(sc->age_rdata.age_cmb_block_paddr)) || 7873b22dc82SSepherosa Ziehau (AGE_ADDR_HI(smb_block_end) != 7883b22dc82SSepherosa Ziehau AGE_ADDR_HI(sc->age_rdata.age_smb_block_paddr))) 7893b22dc82SSepherosa Ziehau return (EFBIG); 7903b22dc82SSepherosa Ziehau 7913b22dc82SSepherosa Ziehau if ((AGE_ADDR_HI(tx_ring_end) != AGE_ADDR_HI(rx_ring_end)) || 7923b22dc82SSepherosa Ziehau (AGE_ADDR_HI(tx_ring_end) != AGE_ADDR_HI(rr_ring_end)) || 7933b22dc82SSepherosa Ziehau (AGE_ADDR_HI(tx_ring_end) != AGE_ADDR_HI(cmb_block_end)) || 7943b22dc82SSepherosa Ziehau (AGE_ADDR_HI(tx_ring_end) != AGE_ADDR_HI(smb_block_end))) 7953b22dc82SSepherosa Ziehau return (EFBIG); 7963b22dc82SSepherosa Ziehau 7973b22dc82SSepherosa Ziehau return (0); 7983b22dc82SSepherosa Ziehau } 7993b22dc82SSepherosa Ziehau 8003b22dc82SSepherosa Ziehau static int 8013b22dc82SSepherosa Ziehau age_dma_alloc(struct age_softc *sc) 8023b22dc82SSepherosa Ziehau { 8033b22dc82SSepherosa Ziehau struct age_txdesc *txd; 8043b22dc82SSepherosa Ziehau struct age_rxdesc *rxd; 8053b22dc82SSepherosa Ziehau bus_addr_t lowaddr; 8063b22dc82SSepherosa Ziehau struct age_dmamap_arg ctx; 8073b22dc82SSepherosa Ziehau int error, i; 8083b22dc82SSepherosa Ziehau 8093b22dc82SSepherosa Ziehau lowaddr = BUS_SPACE_MAXADDR; 8103b22dc82SSepherosa Ziehau again: 8113b22dc82SSepherosa Ziehau /* Create parent ring/DMA block tag. */ 8123b22dc82SSepherosa Ziehau error = bus_dma_tag_create( 8133b22dc82SSepherosa Ziehau NULL, /* parent */ 8143b22dc82SSepherosa Ziehau 1, 0, /* alignment, boundary */ 8153b22dc82SSepherosa Ziehau lowaddr, /* lowaddr */ 8163b22dc82SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 8173b22dc82SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 8183b22dc82SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 8193b22dc82SSepherosa Ziehau 0, /* nsegments */ 8203b22dc82SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 8213b22dc82SSepherosa Ziehau 0, /* flags */ 8223b22dc82SSepherosa Ziehau &sc->age_cdata.age_parent_tag); 8233b22dc82SSepherosa Ziehau if (error != 0) { 8243b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 8253b22dc82SSepherosa Ziehau "could not create parent DMA tag.\n"); 8263b22dc82SSepherosa Ziehau goto fail; 8273b22dc82SSepherosa Ziehau } 8283b22dc82SSepherosa Ziehau 8293b22dc82SSepherosa Ziehau /* Create tag for Tx ring. */ 8303b22dc82SSepherosa Ziehau error = bus_dma_tag_create( 8313b22dc82SSepherosa Ziehau sc->age_cdata.age_parent_tag, /* parent */ 8323b22dc82SSepherosa Ziehau AGE_TX_RING_ALIGN, 0, /* alignment, boundary */ 8333b22dc82SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 8343b22dc82SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 8353b22dc82SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 8363b22dc82SSepherosa Ziehau AGE_TX_RING_SZ, /* maxsize */ 8373b22dc82SSepherosa Ziehau 1, /* nsegments */ 8383b22dc82SSepherosa Ziehau AGE_TX_RING_SZ, /* maxsegsize */ 8393b22dc82SSepherosa Ziehau 0, /* flags */ 8403b22dc82SSepherosa Ziehau &sc->age_cdata.age_tx_ring_tag); 8413b22dc82SSepherosa Ziehau if (error != 0) { 8423b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 8433b22dc82SSepherosa Ziehau "could not create Tx ring DMA tag.\n"); 8443b22dc82SSepherosa Ziehau goto fail; 8453b22dc82SSepherosa Ziehau } 8463b22dc82SSepherosa Ziehau 8473b22dc82SSepherosa Ziehau /* Create tag for Rx ring. */ 8483b22dc82SSepherosa Ziehau error = bus_dma_tag_create( 8493b22dc82SSepherosa Ziehau sc->age_cdata.age_parent_tag, /* parent */ 8503b22dc82SSepherosa Ziehau AGE_RX_RING_ALIGN, 0, /* alignment, boundary */ 8513b22dc82SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 8523b22dc82SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 8533b22dc82SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 8543b22dc82SSepherosa Ziehau AGE_RX_RING_SZ, /* maxsize */ 8553b22dc82SSepherosa Ziehau 1, /* nsegments */ 8563b22dc82SSepherosa Ziehau AGE_RX_RING_SZ, /* maxsegsize */ 8573b22dc82SSepherosa Ziehau 0, /* flags */ 8583b22dc82SSepherosa Ziehau &sc->age_cdata.age_rx_ring_tag); 8593b22dc82SSepherosa Ziehau if (error != 0) { 8603b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 8613b22dc82SSepherosa Ziehau "could not create Rx ring DMA tag.\n"); 8623b22dc82SSepherosa Ziehau goto fail; 8633b22dc82SSepherosa Ziehau } 8643b22dc82SSepherosa Ziehau 8653b22dc82SSepherosa Ziehau /* Create tag for Rx return ring. */ 8663b22dc82SSepherosa Ziehau error = bus_dma_tag_create( 8673b22dc82SSepherosa Ziehau sc->age_cdata.age_parent_tag, /* parent */ 8683b22dc82SSepherosa Ziehau AGE_RR_RING_ALIGN, 0, /* alignment, boundary */ 8693b22dc82SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 8703b22dc82SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 8713b22dc82SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 8723b22dc82SSepherosa Ziehau AGE_RR_RING_SZ, /* maxsize */ 8733b22dc82SSepherosa Ziehau 1, /* nsegments */ 8743b22dc82SSepherosa Ziehau AGE_RR_RING_SZ, /* maxsegsize */ 8753b22dc82SSepherosa Ziehau 0, /* flags */ 8763b22dc82SSepherosa Ziehau &sc->age_cdata.age_rr_ring_tag); 8773b22dc82SSepherosa Ziehau if (error != 0) { 8783b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 8793b22dc82SSepherosa Ziehau "could not create Rx return ring DMA tag.\n"); 8803b22dc82SSepherosa Ziehau goto fail; 8813b22dc82SSepherosa Ziehau } 8823b22dc82SSepherosa Ziehau 8833b22dc82SSepherosa Ziehau /* Create tag for coalesing message block. */ 8843b22dc82SSepherosa Ziehau error = bus_dma_tag_create( 8853b22dc82SSepherosa Ziehau sc->age_cdata.age_parent_tag, /* parent */ 8863b22dc82SSepherosa Ziehau AGE_CMB_ALIGN, 0, /* alignment, boundary */ 8873b22dc82SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 8883b22dc82SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 8893b22dc82SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 8903b22dc82SSepherosa Ziehau AGE_CMB_BLOCK_SZ, /* maxsize */ 8913b22dc82SSepherosa Ziehau 1, /* nsegments */ 8923b22dc82SSepherosa Ziehau AGE_CMB_BLOCK_SZ, /* maxsegsize */ 8933b22dc82SSepherosa Ziehau 0, /* flags */ 8943b22dc82SSepherosa Ziehau &sc->age_cdata.age_cmb_block_tag); 8953b22dc82SSepherosa Ziehau if (error != 0) { 8963b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 8973b22dc82SSepherosa Ziehau "could not create CMB DMA tag.\n"); 8983b22dc82SSepherosa Ziehau goto fail; 8993b22dc82SSepherosa Ziehau } 9003b22dc82SSepherosa Ziehau 9013b22dc82SSepherosa Ziehau /* Create tag for statistics message block. */ 9023b22dc82SSepherosa Ziehau error = bus_dma_tag_create( 9033b22dc82SSepherosa Ziehau sc->age_cdata.age_parent_tag, /* parent */ 9043b22dc82SSepherosa Ziehau AGE_SMB_ALIGN, 0, /* alignment, boundary */ 9053b22dc82SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 9063b22dc82SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 9073b22dc82SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 9083b22dc82SSepherosa Ziehau AGE_SMB_BLOCK_SZ, /* maxsize */ 9093b22dc82SSepherosa Ziehau 1, /* nsegments */ 9103b22dc82SSepherosa Ziehau AGE_SMB_BLOCK_SZ, /* maxsegsize */ 9113b22dc82SSepherosa Ziehau 0, /* flags */ 9123b22dc82SSepherosa Ziehau &sc->age_cdata.age_smb_block_tag); 9133b22dc82SSepherosa Ziehau if (error != 0) { 9143b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 9153b22dc82SSepherosa Ziehau "could not create SMB DMA tag.\n"); 9163b22dc82SSepherosa Ziehau goto fail; 9173b22dc82SSepherosa Ziehau } 9183b22dc82SSepherosa Ziehau 9193b22dc82SSepherosa Ziehau /* Allocate DMA'able memory and load the DMA map. */ 9203b22dc82SSepherosa Ziehau error = bus_dmamem_alloc(sc->age_cdata.age_tx_ring_tag, 9213b22dc82SSepherosa Ziehau (void **)&sc->age_rdata.age_tx_ring, 9223b22dc82SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 9233b22dc82SSepherosa Ziehau &sc->age_cdata.age_tx_ring_map); 9243b22dc82SSepherosa Ziehau if (error != 0) { 9253b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 9263b22dc82SSepherosa Ziehau "could not allocate DMA'able memory for Tx ring.\n"); 9273b22dc82SSepherosa Ziehau goto fail; 9283b22dc82SSepherosa Ziehau } 9293b22dc82SSepherosa Ziehau ctx.age_busaddr = 0; 9303b22dc82SSepherosa Ziehau error = bus_dmamap_load(sc->age_cdata.age_tx_ring_tag, 9313b22dc82SSepherosa Ziehau sc->age_cdata.age_tx_ring_map, sc->age_rdata.age_tx_ring, 9323b22dc82SSepherosa Ziehau AGE_TX_RING_SZ, age_dmamap_cb, &ctx, 0); 9333b22dc82SSepherosa Ziehau if (error != 0 || ctx.age_busaddr == 0) { 9343b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 9353b22dc82SSepherosa Ziehau "could not load DMA'able memory for Tx ring.\n"); 9363b22dc82SSepherosa Ziehau goto fail; 9373b22dc82SSepherosa Ziehau } 9383b22dc82SSepherosa Ziehau sc->age_rdata.age_tx_ring_paddr = ctx.age_busaddr; 9393b22dc82SSepherosa Ziehau /* Rx ring */ 9403b22dc82SSepherosa Ziehau error = bus_dmamem_alloc(sc->age_cdata.age_rx_ring_tag, 9413b22dc82SSepherosa Ziehau (void **)&sc->age_rdata.age_rx_ring, 9423b22dc82SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 9433b22dc82SSepherosa Ziehau &sc->age_cdata.age_rx_ring_map); 9443b22dc82SSepherosa Ziehau if (error != 0) { 9453b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 9463b22dc82SSepherosa Ziehau "could not allocate DMA'able memory for Rx ring.\n"); 9473b22dc82SSepherosa Ziehau goto fail; 9483b22dc82SSepherosa Ziehau } 9493b22dc82SSepherosa Ziehau ctx.age_busaddr = 0; 9503b22dc82SSepherosa Ziehau error = bus_dmamap_load(sc->age_cdata.age_rx_ring_tag, 9513b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_ring_map, sc->age_rdata.age_rx_ring, 9523b22dc82SSepherosa Ziehau AGE_RX_RING_SZ, age_dmamap_cb, &ctx, 0); 9533b22dc82SSepherosa Ziehau if (error != 0 || ctx.age_busaddr == 0) { 9543b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 9553b22dc82SSepherosa Ziehau "could not load DMA'able memory for Rx ring.\n"); 9563b22dc82SSepherosa Ziehau goto fail; 9573b22dc82SSepherosa Ziehau } 9583b22dc82SSepherosa Ziehau sc->age_rdata.age_rx_ring_paddr = ctx.age_busaddr; 9593b22dc82SSepherosa Ziehau /* Rx return ring */ 9603b22dc82SSepherosa Ziehau error = bus_dmamem_alloc(sc->age_cdata.age_rr_ring_tag, 9613b22dc82SSepherosa Ziehau (void **)&sc->age_rdata.age_rr_ring, 9623b22dc82SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 9633b22dc82SSepherosa Ziehau &sc->age_cdata.age_rr_ring_map); 9643b22dc82SSepherosa Ziehau if (error != 0) { 9653b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 9663b22dc82SSepherosa Ziehau "could not allocate DMA'able memory for Rx return ring.\n"); 9673b22dc82SSepherosa Ziehau goto fail; 9683b22dc82SSepherosa Ziehau } 9693b22dc82SSepherosa Ziehau ctx.age_busaddr = 0; 9703b22dc82SSepherosa Ziehau error = bus_dmamap_load(sc->age_cdata.age_rr_ring_tag, 9713b22dc82SSepherosa Ziehau sc->age_cdata.age_rr_ring_map, sc->age_rdata.age_rr_ring, 9723b22dc82SSepherosa Ziehau AGE_RR_RING_SZ, age_dmamap_cb, &ctx, 0); 9733b22dc82SSepherosa Ziehau if (error != 0 || ctx.age_busaddr == 0) { 9743b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 9753b22dc82SSepherosa Ziehau "could not load DMA'able memory for Rx return ring.\n"); 9763b22dc82SSepherosa Ziehau goto fail; 9773b22dc82SSepherosa Ziehau } 9783b22dc82SSepherosa Ziehau sc->age_rdata.age_rr_ring_paddr = ctx.age_busaddr; 9793b22dc82SSepherosa Ziehau /* CMB block */ 9803b22dc82SSepherosa Ziehau error = bus_dmamem_alloc(sc->age_cdata.age_cmb_block_tag, 9813b22dc82SSepherosa Ziehau (void **)&sc->age_rdata.age_cmb_block, 9823b22dc82SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 9833b22dc82SSepherosa Ziehau &sc->age_cdata.age_cmb_block_map); 9843b22dc82SSepherosa Ziehau if (error != 0) { 9853b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 9863b22dc82SSepherosa Ziehau "could not allocate DMA'able memory for CMB block.\n"); 9873b22dc82SSepherosa Ziehau goto fail; 9883b22dc82SSepherosa Ziehau } 9893b22dc82SSepherosa Ziehau ctx.age_busaddr = 0; 9903b22dc82SSepherosa Ziehau error = bus_dmamap_load(sc->age_cdata.age_cmb_block_tag, 9913b22dc82SSepherosa Ziehau sc->age_cdata.age_cmb_block_map, sc->age_rdata.age_cmb_block, 9923b22dc82SSepherosa Ziehau AGE_CMB_BLOCK_SZ, age_dmamap_cb, &ctx, 0); 9933b22dc82SSepherosa Ziehau if (error != 0 || ctx.age_busaddr == 0) { 9943b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 9953b22dc82SSepherosa Ziehau "could not load DMA'able memory for CMB block.\n"); 9963b22dc82SSepherosa Ziehau goto fail; 9973b22dc82SSepherosa Ziehau } 9983b22dc82SSepherosa Ziehau sc->age_rdata.age_cmb_block_paddr = ctx.age_busaddr; 9993b22dc82SSepherosa Ziehau /* SMB block */ 10003b22dc82SSepherosa Ziehau error = bus_dmamem_alloc(sc->age_cdata.age_smb_block_tag, 10013b22dc82SSepherosa Ziehau (void **)&sc->age_rdata.age_smb_block, 10023b22dc82SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 10033b22dc82SSepherosa Ziehau &sc->age_cdata.age_smb_block_map); 10043b22dc82SSepherosa Ziehau if (error != 0) { 10053b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 10063b22dc82SSepherosa Ziehau "could not allocate DMA'able memory for SMB block.\n"); 10073b22dc82SSepherosa Ziehau goto fail; 10083b22dc82SSepherosa Ziehau } 10093b22dc82SSepherosa Ziehau ctx.age_busaddr = 0; 10103b22dc82SSepherosa Ziehau error = bus_dmamap_load(sc->age_cdata.age_smb_block_tag, 10113b22dc82SSepherosa Ziehau sc->age_cdata.age_smb_block_map, sc->age_rdata.age_smb_block, 10123b22dc82SSepherosa Ziehau AGE_SMB_BLOCK_SZ, age_dmamap_cb, &ctx, 0); 10133b22dc82SSepherosa Ziehau if (error != 0 || ctx.age_busaddr == 0) { 10143b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 10153b22dc82SSepherosa Ziehau "could not load DMA'able memory for SMB block.\n"); 10163b22dc82SSepherosa Ziehau goto fail; 10173b22dc82SSepherosa Ziehau } 10183b22dc82SSepherosa Ziehau sc->age_rdata.age_smb_block_paddr = ctx.age_busaddr; 10193b22dc82SSepherosa Ziehau 10203b22dc82SSepherosa Ziehau /* 10213b22dc82SSepherosa Ziehau * All ring buffer and DMA blocks should have the same 10223b22dc82SSepherosa Ziehau * high address part of 64bit DMA address space. 10233b22dc82SSepherosa Ziehau */ 10243b22dc82SSepherosa Ziehau if (lowaddr != BUS_SPACE_MAXADDR_32BIT && 10253b22dc82SSepherosa Ziehau (error = age_check_boundary(sc)) != 0) { 10263b22dc82SSepherosa Ziehau device_printf(sc->age_dev, "4GB boundary crossed, " 10273b22dc82SSepherosa Ziehau "switching to 32bit DMA addressing mode.\n"); 10283b22dc82SSepherosa Ziehau age_dma_free(sc); 10293b22dc82SSepherosa Ziehau /* Limit DMA address space to 32bit and try again. */ 10303b22dc82SSepherosa Ziehau lowaddr = BUS_SPACE_MAXADDR_32BIT; 10313b22dc82SSepherosa Ziehau goto again; 10323b22dc82SSepherosa Ziehau } 10333b22dc82SSepherosa Ziehau 10343b22dc82SSepherosa Ziehau /* 10353b22dc82SSepherosa Ziehau * Create Tx/Rx buffer parent tag. 10363b22dc82SSepherosa Ziehau * L1 supports full 64bit DMA addressing in Tx/Rx buffers 10373b22dc82SSepherosa Ziehau * so it needs separate parent DMA tag. 10383b22dc82SSepherosa Ziehau */ 10393b22dc82SSepherosa Ziehau error = bus_dma_tag_create( 10403b22dc82SSepherosa Ziehau NULL, /* parent */ 10413b22dc82SSepherosa Ziehau 1, 0, /* alignment, boundary */ 10423b22dc82SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 10433b22dc82SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 10443b22dc82SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 10453b22dc82SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 10463b22dc82SSepherosa Ziehau 0, /* nsegments */ 10473b22dc82SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 10483b22dc82SSepherosa Ziehau 0, /* flags */ 10493b22dc82SSepherosa Ziehau &sc->age_cdata.age_buffer_tag); 10503b22dc82SSepherosa Ziehau if (error != 0) { 10513b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 10523b22dc82SSepherosa Ziehau "could not create parent buffer DMA tag.\n"); 10533b22dc82SSepherosa Ziehau goto fail; 10543b22dc82SSepherosa Ziehau } 10553b22dc82SSepherosa Ziehau 10563b22dc82SSepherosa Ziehau /* Create tag for Tx buffers. */ 10573b22dc82SSepherosa Ziehau error = bus_dma_tag_create( 10583b22dc82SSepherosa Ziehau sc->age_cdata.age_buffer_tag, /* parent */ 10593b22dc82SSepherosa Ziehau 1, 0, /* alignment, boundary */ 10603b22dc82SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 10613b22dc82SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 10623b22dc82SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 10633b22dc82SSepherosa Ziehau AGE_TSO_MAXSIZE, /* maxsize */ 10643b22dc82SSepherosa Ziehau AGE_MAXTXSEGS, /* nsegments */ 10653b22dc82SSepherosa Ziehau AGE_TSO_MAXSEGSIZE, /* maxsegsize */ 10663b22dc82SSepherosa Ziehau 0, /* flags */ 10673b22dc82SSepherosa Ziehau &sc->age_cdata.age_tx_tag); 10683b22dc82SSepherosa Ziehau if (error != 0) { 10693b22dc82SSepherosa Ziehau device_printf(sc->age_dev, "could not create Tx DMA tag.\n"); 10703b22dc82SSepherosa Ziehau goto fail; 10713b22dc82SSepherosa Ziehau } 10723b22dc82SSepherosa Ziehau 10733b22dc82SSepherosa Ziehau /* Create tag for Rx buffers. */ 10743b22dc82SSepherosa Ziehau error = bus_dma_tag_create( 10753b22dc82SSepherosa Ziehau sc->age_cdata.age_buffer_tag, /* parent */ 10763b22dc82SSepherosa Ziehau 1, 0, /* alignment, boundary */ 10773b22dc82SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 10783b22dc82SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 10793b22dc82SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 10803b22dc82SSepherosa Ziehau MCLBYTES, /* maxsize */ 10813b22dc82SSepherosa Ziehau 1, /* nsegments */ 10823b22dc82SSepherosa Ziehau MCLBYTES, /* maxsegsize */ 10833b22dc82SSepherosa Ziehau 0, /* flags */ 10843b22dc82SSepherosa Ziehau &sc->age_cdata.age_rx_tag); 10853b22dc82SSepherosa Ziehau if (error != 0) { 10863b22dc82SSepherosa Ziehau device_printf(sc->age_dev, "could not create Rx DMA tag.\n"); 10873b22dc82SSepherosa Ziehau goto fail; 10883b22dc82SSepherosa Ziehau } 10893b22dc82SSepherosa Ziehau 10903b22dc82SSepherosa Ziehau /* Create DMA maps for Tx buffers. */ 10913b22dc82SSepherosa Ziehau for (i = 0; i < AGE_TX_RING_CNT; i++) { 10923b22dc82SSepherosa Ziehau txd = &sc->age_cdata.age_txdesc[i]; 10933b22dc82SSepherosa Ziehau txd->tx_m = NULL; 10943b22dc82SSepherosa Ziehau txd->tx_dmamap = NULL; 10953b22dc82SSepherosa Ziehau error = bus_dmamap_create(sc->age_cdata.age_tx_tag, 0, 10963b22dc82SSepherosa Ziehau &txd->tx_dmamap); 10973b22dc82SSepherosa Ziehau if (error != 0) { 10983b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 10993b22dc82SSepherosa Ziehau "could not create Tx dmamap.\n"); 11003b22dc82SSepherosa Ziehau goto fail; 11013b22dc82SSepherosa Ziehau } 11023b22dc82SSepherosa Ziehau } 11033b22dc82SSepherosa Ziehau /* Create DMA maps for Rx buffers. */ 11043b22dc82SSepherosa Ziehau if ((error = bus_dmamap_create(sc->age_cdata.age_rx_tag, 0, 11053b22dc82SSepherosa Ziehau &sc->age_cdata.age_rx_sparemap)) != 0) { 11063b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 11073b22dc82SSepherosa Ziehau "could not create spare Rx dmamap.\n"); 11083b22dc82SSepherosa Ziehau goto fail; 11093b22dc82SSepherosa Ziehau } 11103b22dc82SSepherosa Ziehau for (i = 0; i < AGE_RX_RING_CNT; i++) { 11113b22dc82SSepherosa Ziehau rxd = &sc->age_cdata.age_rxdesc[i]; 11123b22dc82SSepherosa Ziehau rxd->rx_m = NULL; 11133b22dc82SSepherosa Ziehau rxd->rx_dmamap = NULL; 11143b22dc82SSepherosa Ziehau error = bus_dmamap_create(sc->age_cdata.age_rx_tag, 0, 11153b22dc82SSepherosa Ziehau &rxd->rx_dmamap); 11163b22dc82SSepherosa Ziehau if (error != 0) { 11173b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 11183b22dc82SSepherosa Ziehau "could not create Rx dmamap.\n"); 11193b22dc82SSepherosa Ziehau goto fail; 11203b22dc82SSepherosa Ziehau } 11213b22dc82SSepherosa Ziehau } 11223b22dc82SSepherosa Ziehau fail: 11233b22dc82SSepherosa Ziehau return (error); 11243b22dc82SSepherosa Ziehau } 11253b22dc82SSepherosa Ziehau 11263b22dc82SSepherosa Ziehau static void 11273b22dc82SSepherosa Ziehau age_dma_free(struct age_softc *sc) 11283b22dc82SSepherosa Ziehau { 11293b22dc82SSepherosa Ziehau struct age_txdesc *txd; 11303b22dc82SSepherosa Ziehau struct age_rxdesc *rxd; 11313b22dc82SSepherosa Ziehau int i; 11323b22dc82SSepherosa Ziehau 11333b22dc82SSepherosa Ziehau /* Tx buffers */ 11343b22dc82SSepherosa Ziehau if (sc->age_cdata.age_tx_tag != NULL) { 11353b22dc82SSepherosa Ziehau for (i = 0; i < AGE_TX_RING_CNT; i++) { 11363b22dc82SSepherosa Ziehau txd = &sc->age_cdata.age_txdesc[i]; 11373b22dc82SSepherosa Ziehau if (txd->tx_dmamap != NULL) { 11383b22dc82SSepherosa Ziehau bus_dmamap_destroy(sc->age_cdata.age_tx_tag, 11393b22dc82SSepherosa Ziehau txd->tx_dmamap); 11403b22dc82SSepherosa Ziehau txd->tx_dmamap = NULL; 11413b22dc82SSepherosa Ziehau } 11423b22dc82SSepherosa Ziehau } 11433b22dc82SSepherosa Ziehau bus_dma_tag_destroy(sc->age_cdata.age_tx_tag); 11443b22dc82SSepherosa Ziehau sc->age_cdata.age_tx_tag = NULL; 11453b22dc82SSepherosa Ziehau } 11463b22dc82SSepherosa Ziehau /* Rx buffers */ 11473b22dc82SSepherosa Ziehau if (sc->age_cdata.age_rx_tag != NULL) { 11483b22dc82SSepherosa Ziehau for (i = 0; i < AGE_RX_RING_CNT; i++) { 11493b22dc82SSepherosa Ziehau rxd = &sc->age_cdata.age_rxdesc[i]; 11503b22dc82SSepherosa Ziehau if (rxd->rx_dmamap != NULL) { 11513b22dc82SSepherosa Ziehau bus_dmamap_destroy(sc->age_cdata.age_rx_tag, 11523b22dc82SSepherosa Ziehau rxd->rx_dmamap); 11533b22dc82SSepherosa Ziehau rxd->rx_dmamap = NULL; 11543b22dc82SSepherosa Ziehau } 11553b22dc82SSepherosa Ziehau } 11563b22dc82SSepherosa Ziehau if (sc->age_cdata.age_rx_sparemap != NULL) { 11573b22dc82SSepherosa Ziehau bus_dmamap_destroy(sc->age_cdata.age_rx_tag, 11583b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_sparemap); 11593b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_sparemap = NULL; 11603b22dc82SSepherosa Ziehau } 11613b22dc82SSepherosa Ziehau bus_dma_tag_destroy(sc->age_cdata.age_rx_tag); 11623b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_tag = NULL; 11633b22dc82SSepherosa Ziehau } 11643b22dc82SSepherosa Ziehau /* Tx ring. */ 11653b22dc82SSepherosa Ziehau if (sc->age_cdata.age_tx_ring_tag != NULL) { 11663b22dc82SSepherosa Ziehau if (sc->age_cdata.age_tx_ring_map != NULL) 11673b22dc82SSepherosa Ziehau bus_dmamap_unload(sc->age_cdata.age_tx_ring_tag, 11683b22dc82SSepherosa Ziehau sc->age_cdata.age_tx_ring_map); 11693b22dc82SSepherosa Ziehau if (sc->age_cdata.age_tx_ring_map != NULL && 11703b22dc82SSepherosa Ziehau sc->age_rdata.age_tx_ring != NULL) 11713b22dc82SSepherosa Ziehau bus_dmamem_free(sc->age_cdata.age_tx_ring_tag, 11723b22dc82SSepherosa Ziehau sc->age_rdata.age_tx_ring, 11733b22dc82SSepherosa Ziehau sc->age_cdata.age_tx_ring_map); 11743b22dc82SSepherosa Ziehau sc->age_rdata.age_tx_ring = NULL; 11753b22dc82SSepherosa Ziehau sc->age_cdata.age_tx_ring_map = NULL; 11763b22dc82SSepherosa Ziehau bus_dma_tag_destroy(sc->age_cdata.age_tx_ring_tag); 11773b22dc82SSepherosa Ziehau sc->age_cdata.age_tx_ring_tag = NULL; 11783b22dc82SSepherosa Ziehau } 11793b22dc82SSepherosa Ziehau /* Rx ring. */ 11803b22dc82SSepherosa Ziehau if (sc->age_cdata.age_rx_ring_tag != NULL) { 11813b22dc82SSepherosa Ziehau if (sc->age_cdata.age_rx_ring_map != NULL) 11823b22dc82SSepherosa Ziehau bus_dmamap_unload(sc->age_cdata.age_rx_ring_tag, 11833b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_ring_map); 11843b22dc82SSepherosa Ziehau if (sc->age_cdata.age_rx_ring_map != NULL && 11853b22dc82SSepherosa Ziehau sc->age_rdata.age_rx_ring != NULL) 11863b22dc82SSepherosa Ziehau bus_dmamem_free(sc->age_cdata.age_rx_ring_tag, 11873b22dc82SSepherosa Ziehau sc->age_rdata.age_rx_ring, 11883b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_ring_map); 11893b22dc82SSepherosa Ziehau sc->age_rdata.age_rx_ring = NULL; 11903b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_ring_map = NULL; 11913b22dc82SSepherosa Ziehau bus_dma_tag_destroy(sc->age_cdata.age_rx_ring_tag); 11923b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_ring_tag = NULL; 11933b22dc82SSepherosa Ziehau } 11943b22dc82SSepherosa Ziehau /* Rx return ring. */ 11953b22dc82SSepherosa Ziehau if (sc->age_cdata.age_rr_ring_tag != NULL) { 11963b22dc82SSepherosa Ziehau if (sc->age_cdata.age_rr_ring_map != NULL) 11973b22dc82SSepherosa Ziehau bus_dmamap_unload(sc->age_cdata.age_rr_ring_tag, 11983b22dc82SSepherosa Ziehau sc->age_cdata.age_rr_ring_map); 11993b22dc82SSepherosa Ziehau if (sc->age_cdata.age_rr_ring_map != NULL && 12003b22dc82SSepherosa Ziehau sc->age_rdata.age_rr_ring != NULL) 12013b22dc82SSepherosa Ziehau bus_dmamem_free(sc->age_cdata.age_rr_ring_tag, 12023b22dc82SSepherosa Ziehau sc->age_rdata.age_rr_ring, 12033b22dc82SSepherosa Ziehau sc->age_cdata.age_rr_ring_map); 12043b22dc82SSepherosa Ziehau sc->age_rdata.age_rr_ring = NULL; 12053b22dc82SSepherosa Ziehau sc->age_cdata.age_rr_ring_map = NULL; 12063b22dc82SSepherosa Ziehau bus_dma_tag_destroy(sc->age_cdata.age_rr_ring_tag); 12073b22dc82SSepherosa Ziehau sc->age_cdata.age_rr_ring_tag = NULL; 12083b22dc82SSepherosa Ziehau } 12093b22dc82SSepherosa Ziehau /* CMB block */ 12103b22dc82SSepherosa Ziehau if (sc->age_cdata.age_cmb_block_tag != NULL) { 12113b22dc82SSepherosa Ziehau if (sc->age_cdata.age_cmb_block_map != NULL) 12123b22dc82SSepherosa Ziehau bus_dmamap_unload(sc->age_cdata.age_cmb_block_tag, 12133b22dc82SSepherosa Ziehau sc->age_cdata.age_cmb_block_map); 12143b22dc82SSepherosa Ziehau if (sc->age_cdata.age_cmb_block_map != NULL && 12153b22dc82SSepherosa Ziehau sc->age_rdata.age_cmb_block != NULL) 12163b22dc82SSepherosa Ziehau bus_dmamem_free(sc->age_cdata.age_cmb_block_tag, 12173b22dc82SSepherosa Ziehau sc->age_rdata.age_cmb_block, 12183b22dc82SSepherosa Ziehau sc->age_cdata.age_cmb_block_map); 12193b22dc82SSepherosa Ziehau sc->age_rdata.age_cmb_block = NULL; 12203b22dc82SSepherosa Ziehau sc->age_cdata.age_cmb_block_map = NULL; 12213b22dc82SSepherosa Ziehau bus_dma_tag_destroy(sc->age_cdata.age_cmb_block_tag); 12223b22dc82SSepherosa Ziehau sc->age_cdata.age_cmb_block_tag = NULL; 12233b22dc82SSepherosa Ziehau } 12243b22dc82SSepherosa Ziehau /* SMB block */ 12253b22dc82SSepherosa Ziehau if (sc->age_cdata.age_smb_block_tag != NULL) { 12263b22dc82SSepherosa Ziehau if (sc->age_cdata.age_smb_block_map != NULL) 12273b22dc82SSepherosa Ziehau bus_dmamap_unload(sc->age_cdata.age_smb_block_tag, 12283b22dc82SSepherosa Ziehau sc->age_cdata.age_smb_block_map); 12293b22dc82SSepherosa Ziehau if (sc->age_cdata.age_smb_block_map != NULL && 12303b22dc82SSepherosa Ziehau sc->age_rdata.age_smb_block != NULL) 12313b22dc82SSepherosa Ziehau bus_dmamem_free(sc->age_cdata.age_smb_block_tag, 12323b22dc82SSepherosa Ziehau sc->age_rdata.age_smb_block, 12333b22dc82SSepherosa Ziehau sc->age_cdata.age_smb_block_map); 12343b22dc82SSepherosa Ziehau sc->age_rdata.age_smb_block = NULL; 12353b22dc82SSepherosa Ziehau sc->age_cdata.age_smb_block_map = NULL; 12363b22dc82SSepherosa Ziehau bus_dma_tag_destroy(sc->age_cdata.age_smb_block_tag); 12373b22dc82SSepherosa Ziehau sc->age_cdata.age_smb_block_tag = NULL; 12383b22dc82SSepherosa Ziehau } 12393b22dc82SSepherosa Ziehau 12403b22dc82SSepherosa Ziehau if (sc->age_cdata.age_buffer_tag != NULL) { 12413b22dc82SSepherosa Ziehau bus_dma_tag_destroy(sc->age_cdata.age_buffer_tag); 12423b22dc82SSepherosa Ziehau sc->age_cdata.age_buffer_tag = NULL; 12433b22dc82SSepherosa Ziehau } 12443b22dc82SSepherosa Ziehau if (sc->age_cdata.age_parent_tag != NULL) { 12453b22dc82SSepherosa Ziehau bus_dma_tag_destroy(sc->age_cdata.age_parent_tag); 12463b22dc82SSepherosa Ziehau sc->age_cdata.age_parent_tag = NULL; 12473b22dc82SSepherosa Ziehau } 12483b22dc82SSepherosa Ziehau } 12493b22dc82SSepherosa Ziehau 12503b22dc82SSepherosa Ziehau /* 12513b22dc82SSepherosa Ziehau * Make sure the interface is stopped at reboot time. 12523b22dc82SSepherosa Ziehau */ 12533b22dc82SSepherosa Ziehau static int 12543b22dc82SSepherosa Ziehau age_shutdown(device_t dev) 12553b22dc82SSepherosa Ziehau { 12563b22dc82SSepherosa Ziehau return age_suspend(dev); 12573b22dc82SSepherosa Ziehau } 12583b22dc82SSepherosa Ziehau 12593b22dc82SSepherosa Ziehau #ifdef wol_notyet 12603b22dc82SSepherosa Ziehau 12613b22dc82SSepherosa Ziehau static void 12623b22dc82SSepherosa Ziehau age_setwol(struct age_softc *sc) 12633b22dc82SSepherosa Ziehau { 12643b22dc82SSepherosa Ziehau struct ifnet *ifp; 12653b22dc82SSepherosa Ziehau struct mii_data *mii; 12663b22dc82SSepherosa Ziehau uint32_t reg, pmcs; 12673b22dc82SSepherosa Ziehau uint16_t pmstat; 12683b22dc82SSepherosa Ziehau int aneg, i, pmc; 12693b22dc82SSepherosa Ziehau 12703b22dc82SSepherosa Ziehau AGE_LOCK_ASSERT(sc); 12713b22dc82SSepherosa Ziehau 12723b22dc82SSepherosa Ziehau if (pci_find_extcap(sc->age_dev, PCIY_PMG, &pmc) == 0) { 12733b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_WOL_CFG, 0); 12743b22dc82SSepherosa Ziehau /* 12753b22dc82SSepherosa Ziehau * No PME capability, PHY power down. 12763b22dc82SSepherosa Ziehau * XXX 12773b22dc82SSepherosa Ziehau * Due to an unknown reason powering down PHY resulted 12783b22dc82SSepherosa Ziehau * in unexpected results such as inaccessbility of 12793b22dc82SSepherosa Ziehau * hardware of freshly rebooted system. Disable 12803b22dc82SSepherosa Ziehau * powering down PHY until I got more information for 12813b22dc82SSepherosa Ziehau * Attansic/Atheros PHY hardwares. 12823b22dc82SSepherosa Ziehau */ 12833b22dc82SSepherosa Ziehau #ifdef notyet 12843b22dc82SSepherosa Ziehau age_miibus_writereg(sc->age_dev, sc->age_phyaddr, 12853b22dc82SSepherosa Ziehau MII_BMCR, BMCR_PDOWN); 12863b22dc82SSepherosa Ziehau #endif 12873b22dc82SSepherosa Ziehau return; 12883b22dc82SSepherosa Ziehau } 12893b22dc82SSepherosa Ziehau 12903b22dc82SSepherosa Ziehau ifp = sc->age_ifp; 12913b22dc82SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_WOL) != 0) { 12923b22dc82SSepherosa Ziehau /* 12933b22dc82SSepherosa Ziehau * Note, this driver resets the link speed to 10/100Mbps with 12943b22dc82SSepherosa Ziehau * auto-negotiation but we don't know whether that operation 12953b22dc82SSepherosa Ziehau * would succeed or not as it have no control after powering 12963b22dc82SSepherosa Ziehau * off. If the renegotiation fail WOL may not work. Running 12973b22dc82SSepherosa Ziehau * at 1Gbps will draw more power than 375mA at 3.3V which is 12983b22dc82SSepherosa Ziehau * specified in PCI specification and that would result in 12993b22dc82SSepherosa Ziehau * complete shutdowning power to ethernet controller. 13003b22dc82SSepherosa Ziehau * 13013b22dc82SSepherosa Ziehau * TODO 13023b22dc82SSepherosa Ziehau * Save current negotiated media speed/duplex/flow-control 13033b22dc82SSepherosa Ziehau * to softc and restore the same link again after resuming. 13043b22dc82SSepherosa Ziehau * PHY handling such as power down/resetting to 100Mbps 13053b22dc82SSepherosa Ziehau * may be better handled in suspend method in phy driver. 13063b22dc82SSepherosa Ziehau */ 13073b22dc82SSepherosa Ziehau mii = device_get_softc(sc->age_miibus); 13083b22dc82SSepherosa Ziehau mii_pollstat(mii); 13093b22dc82SSepherosa Ziehau aneg = 0; 13103b22dc82SSepherosa Ziehau if ((mii->mii_media_status & IFM_AVALID) != 0) { 13113b22dc82SSepherosa Ziehau switch IFM_SUBTYPE(mii->mii_media_active) { 13123b22dc82SSepherosa Ziehau case IFM_10_T: 13133b22dc82SSepherosa Ziehau case IFM_100_TX: 13143b22dc82SSepherosa Ziehau goto got_link; 13153b22dc82SSepherosa Ziehau case IFM_1000_T: 13163b22dc82SSepherosa Ziehau aneg++; 13173b22dc82SSepherosa Ziehau default: 13183b22dc82SSepherosa Ziehau break; 13193b22dc82SSepherosa Ziehau } 13203b22dc82SSepherosa Ziehau } 13213b22dc82SSepherosa Ziehau age_miibus_writereg(sc->age_dev, sc->age_phyaddr, 13223b22dc82SSepherosa Ziehau MII_100T2CR, 0); 13233b22dc82SSepherosa Ziehau age_miibus_writereg(sc->age_dev, sc->age_phyaddr, 13243b22dc82SSepherosa Ziehau MII_ANAR, ANAR_TX_FD | ANAR_TX | ANAR_10_FD | 13253b22dc82SSepherosa Ziehau ANAR_10 | ANAR_CSMA); 13263b22dc82SSepherosa Ziehau age_miibus_writereg(sc->age_dev, sc->age_phyaddr, 13273b22dc82SSepherosa Ziehau MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); 13283b22dc82SSepherosa Ziehau DELAY(1000); 13293b22dc82SSepherosa Ziehau if (aneg != 0) { 13303b22dc82SSepherosa Ziehau /* Poll link state until age(4) get a 10/100 link. */ 13313b22dc82SSepherosa Ziehau for (i = 0; i < MII_ANEGTICKS_GIGE; i++) { 13323b22dc82SSepherosa Ziehau mii_pollstat(mii); 13333b22dc82SSepherosa Ziehau if ((mii->mii_media_status & IFM_AVALID) != 0) { 13343b22dc82SSepherosa Ziehau switch (IFM_SUBTYPE( 13353b22dc82SSepherosa Ziehau mii->mii_media_active)) { 13363b22dc82SSepherosa Ziehau case IFM_10_T: 13373b22dc82SSepherosa Ziehau case IFM_100_TX: 13383b22dc82SSepherosa Ziehau age_mac_config(sc); 13393b22dc82SSepherosa Ziehau goto got_link; 13403b22dc82SSepherosa Ziehau default: 13413b22dc82SSepherosa Ziehau break; 13423b22dc82SSepherosa Ziehau } 13433b22dc82SSepherosa Ziehau } 13443b22dc82SSepherosa Ziehau AGE_UNLOCK(sc); 13453b22dc82SSepherosa Ziehau pause("agelnk", hz); 13463b22dc82SSepherosa Ziehau AGE_LOCK(sc); 13473b22dc82SSepherosa Ziehau } 13483b22dc82SSepherosa Ziehau if (i == MII_ANEGTICKS_GIGE) 13493b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 13503b22dc82SSepherosa Ziehau "establishing link failed, " 13513b22dc82SSepherosa Ziehau "WOL may not work!"); 13523b22dc82SSepherosa Ziehau } 13533b22dc82SSepherosa Ziehau /* 13543b22dc82SSepherosa Ziehau * No link, force MAC to have 100Mbps, full-duplex link. 13553b22dc82SSepherosa Ziehau * This is the last resort and may/may not work. 13563b22dc82SSepherosa Ziehau */ 13573b22dc82SSepherosa Ziehau mii->mii_media_status = IFM_AVALID | IFM_ACTIVE; 13583b22dc82SSepherosa Ziehau mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX; 13593b22dc82SSepherosa Ziehau age_mac_config(sc); 13603b22dc82SSepherosa Ziehau } 13613b22dc82SSepherosa Ziehau 13623b22dc82SSepherosa Ziehau got_link: 13633b22dc82SSepherosa Ziehau pmcs = 0; 13643b22dc82SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) 13653b22dc82SSepherosa Ziehau pmcs |= WOL_CFG_MAGIC | WOL_CFG_MAGIC_ENB; 13663b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_WOL_CFG, pmcs); 13673b22dc82SSepherosa Ziehau reg = CSR_READ_4(sc, AGE_MAC_CFG); 13683b22dc82SSepherosa Ziehau reg &= ~(MAC_CFG_DBG | MAC_CFG_PROMISC); 13693b22dc82SSepherosa Ziehau reg &= ~(MAC_CFG_ALLMULTI | MAC_CFG_BCAST); 13703b22dc82SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0) 13713b22dc82SSepherosa Ziehau reg |= MAC_CFG_ALLMULTI | MAC_CFG_BCAST; 13723b22dc82SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_WOL) != 0) { 13733b22dc82SSepherosa Ziehau reg |= MAC_CFG_RX_ENB; 13743b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MAC_CFG, reg); 13753b22dc82SSepherosa Ziehau } 13763b22dc82SSepherosa Ziehau 13773b22dc82SSepherosa Ziehau /* Request PME. */ 13783b22dc82SSepherosa Ziehau pmstat = pci_read_config(sc->age_dev, pmc + PCIR_POWER_STATUS, 2); 13793b22dc82SSepherosa Ziehau pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); 13803b22dc82SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_WOL) != 0) 13813b22dc82SSepherosa Ziehau pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; 13823b22dc82SSepherosa Ziehau pci_write_config(sc->age_dev, pmc + PCIR_POWER_STATUS, pmstat, 2); 13833b22dc82SSepherosa Ziehau #ifdef notyet 13843b22dc82SSepherosa Ziehau /* See above for powering down PHY issues. */ 13853b22dc82SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_WOL) == 0) { 13863b22dc82SSepherosa Ziehau /* No WOL, PHY power down. */ 13873b22dc82SSepherosa Ziehau age_miibus_writereg(sc->age_dev, sc->age_phyaddr, 13883b22dc82SSepherosa Ziehau MII_BMCR, BMCR_PDOWN); 13893b22dc82SSepherosa Ziehau } 13903b22dc82SSepherosa Ziehau #endif 13913b22dc82SSepherosa Ziehau } 13923b22dc82SSepherosa Ziehau 13933b22dc82SSepherosa Ziehau #endif /* wol_notyet */ 13943b22dc82SSepherosa Ziehau 13953b22dc82SSepherosa Ziehau static int 13963b22dc82SSepherosa Ziehau age_suspend(device_t dev) 13973b22dc82SSepherosa Ziehau { 13983b22dc82SSepherosa Ziehau struct age_softc *sc = device_get_softc(dev); 13993b22dc82SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 14003b22dc82SSepherosa Ziehau 14013b22dc82SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 14023b22dc82SSepherosa Ziehau age_stop(sc); 14033b22dc82SSepherosa Ziehau #ifdef wol_notyet 14043b22dc82SSepherosa Ziehau age_setwol(sc); 14053b22dc82SSepherosa Ziehau #endif 14063b22dc82SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 14073b22dc82SSepherosa Ziehau 14083b22dc82SSepherosa Ziehau return (0); 14093b22dc82SSepherosa Ziehau } 14103b22dc82SSepherosa Ziehau 14113b22dc82SSepherosa Ziehau static int 14123b22dc82SSepherosa Ziehau age_resume(device_t dev) 14133b22dc82SSepherosa Ziehau { 14143b22dc82SSepherosa Ziehau struct age_softc *sc = device_get_softc(dev); 14153b22dc82SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 14163b22dc82SSepherosa Ziehau uint16_t cmd; 14173b22dc82SSepherosa Ziehau 14183b22dc82SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 14193b22dc82SSepherosa Ziehau 14203b22dc82SSepherosa Ziehau /* 14213b22dc82SSepherosa Ziehau * Clear INTx emulation disable for hardwares that 14223b22dc82SSepherosa Ziehau * is set in resume event. From Linux. 14233b22dc82SSepherosa Ziehau */ 14243b22dc82SSepherosa Ziehau cmd = pci_read_config(sc->age_dev, PCIR_COMMAND, 2); 14253b22dc82SSepherosa Ziehau if ((cmd & 0x0400) != 0) { 14263b22dc82SSepherosa Ziehau cmd &= ~0x0400; 14273b22dc82SSepherosa Ziehau pci_write_config(sc->age_dev, PCIR_COMMAND, cmd, 2); 14283b22dc82SSepherosa Ziehau } 14293b22dc82SSepherosa Ziehau if ((ifp->if_flags & IFF_UP) != 0) 14303b22dc82SSepherosa Ziehau age_init(sc); 14313b22dc82SSepherosa Ziehau 14323b22dc82SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 14333b22dc82SSepherosa Ziehau 14343b22dc82SSepherosa Ziehau return (0); 14353b22dc82SSepherosa Ziehau } 14363b22dc82SSepherosa Ziehau 14373b22dc82SSepherosa Ziehau static int 14383b22dc82SSepherosa Ziehau age_encap(struct age_softc *sc, struct mbuf **m_head) 14393b22dc82SSepherosa Ziehau { 14403b22dc82SSepherosa Ziehau struct age_txdesc *txd, *txd_last; 14413b22dc82SSepherosa Ziehau struct tx_desc *desc; 14423b22dc82SSepherosa Ziehau struct mbuf *m; 14433b22dc82SSepherosa Ziehau struct age_dmamap_ctx ctx; 14443b22dc82SSepherosa Ziehau bus_dma_segment_t txsegs[AGE_MAXTXSEGS]; 14453b22dc82SSepherosa Ziehau bus_dmamap_t map; 14463b22dc82SSepherosa Ziehau uint32_t cflags, poff, vtag; 144751c70c94SSascha Wildner int error, i, nsegs, prod; 14483b22dc82SSepherosa Ziehau 14493b22dc82SSepherosa Ziehau M_ASSERTPKTHDR((*m_head)); 14503b22dc82SSepherosa Ziehau 14513b22dc82SSepherosa Ziehau m = *m_head; 14523b22dc82SSepherosa Ziehau cflags = vtag = 0; 14533b22dc82SSepherosa Ziehau poff = 0; 14543b22dc82SSepherosa Ziehau 145551c70c94SSascha Wildner prod = sc->age_cdata.age_tx_prod; 14563b22dc82SSepherosa Ziehau txd = &sc->age_cdata.age_txdesc[prod]; 14573b22dc82SSepherosa Ziehau txd_last = txd; 14583b22dc82SSepherosa Ziehau map = txd->tx_dmamap; 14593b22dc82SSepherosa Ziehau 14603b22dc82SSepherosa Ziehau ctx.nsegs = AGE_MAXTXSEGS; 14613b22dc82SSepherosa Ziehau ctx.segs = txsegs; 14623b22dc82SSepherosa Ziehau error = bus_dmamap_load_mbuf(sc->age_cdata.age_tx_tag, map, 14633b22dc82SSepherosa Ziehau *m_head, age_dmamap_buf_cb, &ctx, 14643b22dc82SSepherosa Ziehau BUS_DMA_NOWAIT); 14653b22dc82SSepherosa Ziehau if (!error && ctx.nsegs == 0) { 14663b22dc82SSepherosa Ziehau bus_dmamap_unload(sc->age_cdata.age_tx_tag, map); 14673b22dc82SSepherosa Ziehau error = EFBIG; 14683b22dc82SSepherosa Ziehau } 14693b22dc82SSepherosa Ziehau if (error == EFBIG) { 14703b22dc82SSepherosa Ziehau m = m_defrag(*m_head, MB_DONTWAIT); 14713b22dc82SSepherosa Ziehau if (m == NULL) { 14723b22dc82SSepherosa Ziehau m_freem(*m_head); 14733b22dc82SSepherosa Ziehau *m_head = NULL; 14743b22dc82SSepherosa Ziehau return (ENOBUFS); 14753b22dc82SSepherosa Ziehau } 14763b22dc82SSepherosa Ziehau *m_head = m; 14773b22dc82SSepherosa Ziehau 14783b22dc82SSepherosa Ziehau ctx.nsegs = AGE_MAXTXSEGS; 14793b22dc82SSepherosa Ziehau ctx.segs = txsegs; 14803b22dc82SSepherosa Ziehau error = bus_dmamap_load_mbuf(sc->age_cdata.age_tx_tag, map, 14813b22dc82SSepherosa Ziehau *m_head, age_dmamap_buf_cb, &ctx, 14823b22dc82SSepherosa Ziehau BUS_DMA_NOWAIT); 14833b22dc82SSepherosa Ziehau if (error || ctx.nsegs == 0) { 14843b22dc82SSepherosa Ziehau if (!error) { 14853b22dc82SSepherosa Ziehau bus_dmamap_unload(sc->age_cdata.age_tx_tag, 14863b22dc82SSepherosa Ziehau map); 14873b22dc82SSepherosa Ziehau error = EFBIG; 14883b22dc82SSepherosa Ziehau } 14893b22dc82SSepherosa Ziehau m_freem(*m_head); 14903b22dc82SSepherosa Ziehau *m_head = NULL; 14913b22dc82SSepherosa Ziehau return (error); 14923b22dc82SSepherosa Ziehau } 14933b22dc82SSepherosa Ziehau } else if (error != 0) { 14943b22dc82SSepherosa Ziehau return (error); 14953b22dc82SSepherosa Ziehau } 14963b22dc82SSepherosa Ziehau nsegs = ctx.nsegs; 14973b22dc82SSepherosa Ziehau 14983b22dc82SSepherosa Ziehau if (nsegs == 0) { 14993b22dc82SSepherosa Ziehau m_freem(*m_head); 15003b22dc82SSepherosa Ziehau *m_head = NULL; 15013b22dc82SSepherosa Ziehau return (EIO); 15023b22dc82SSepherosa Ziehau } 15033b22dc82SSepherosa Ziehau 15043b22dc82SSepherosa Ziehau /* Check descriptor overrun. */ 15053b22dc82SSepherosa Ziehau if (sc->age_cdata.age_tx_cnt + nsegs >= AGE_TX_RING_CNT - 2) { 15063b22dc82SSepherosa Ziehau bus_dmamap_unload(sc->age_cdata.age_tx_tag, map); 15073b22dc82SSepherosa Ziehau return (ENOBUFS); 15083b22dc82SSepherosa Ziehau } 15093b22dc82SSepherosa Ziehau 15103b22dc82SSepherosa Ziehau m = *m_head; 15113b22dc82SSepherosa Ziehau /* Configure Tx IP/TCP/UDP checksum offload. */ 15123b22dc82SSepherosa Ziehau if ((m->m_pkthdr.csum_flags & AGE_CSUM_FEATURES) != 0) { 15133b22dc82SSepherosa Ziehau cflags |= AGE_TD_CSUM; 15143b22dc82SSepherosa Ziehau if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0) 15153b22dc82SSepherosa Ziehau cflags |= AGE_TD_TCPCSUM; 15163b22dc82SSepherosa Ziehau if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) 15173b22dc82SSepherosa Ziehau cflags |= AGE_TD_UDPCSUM; 15183b22dc82SSepherosa Ziehau /* Set checksum start offset. */ 15193b22dc82SSepherosa Ziehau cflags |= (poff << AGE_TD_CSUM_PLOADOFFSET_SHIFT); 15203b22dc82SSepherosa Ziehau /* Set checksum insertion position of TCP/UDP. */ 15213b22dc82SSepherosa Ziehau cflags |= ((poff + m->m_pkthdr.csum_data) << 15223b22dc82SSepherosa Ziehau AGE_TD_CSUM_XSUMOFFSET_SHIFT); 15233b22dc82SSepherosa Ziehau } 15243b22dc82SSepherosa Ziehau 15253b22dc82SSepherosa Ziehau /* Configure VLAN hardware tag insertion. */ 15263b22dc82SSepherosa Ziehau if ((m->m_flags & M_VLANTAG) != 0) { 15273b22dc82SSepherosa Ziehau vtag = AGE_TX_VLAN_TAG(m->m_pkthdr.ether_vlantag); 15283b22dc82SSepherosa Ziehau vtag = ((vtag << AGE_TD_VLAN_SHIFT) & AGE_TD_VLAN_MASK); 15293b22dc82SSepherosa Ziehau cflags |= AGE_TD_INSERT_VLAN_TAG; 15303b22dc82SSepherosa Ziehau } 15313b22dc82SSepherosa Ziehau 15323b22dc82SSepherosa Ziehau desc = NULL; 15333b22dc82SSepherosa Ziehau for (i = 0; i < nsegs; i++) { 15343b22dc82SSepherosa Ziehau desc = &sc->age_rdata.age_tx_ring[prod]; 15353b22dc82SSepherosa Ziehau desc->addr = htole64(txsegs[i].ds_addr); 15363b22dc82SSepherosa Ziehau desc->len = htole32(AGE_TX_BYTES(txsegs[i].ds_len) | vtag); 15373b22dc82SSepherosa Ziehau desc->flags = htole32(cflags); 15383b22dc82SSepherosa Ziehau sc->age_cdata.age_tx_cnt++; 15393b22dc82SSepherosa Ziehau AGE_DESC_INC(prod, AGE_TX_RING_CNT); 15403b22dc82SSepherosa Ziehau } 15413b22dc82SSepherosa Ziehau /* Update producer index. */ 15423b22dc82SSepherosa Ziehau sc->age_cdata.age_tx_prod = prod; 15433b22dc82SSepherosa Ziehau 15443b22dc82SSepherosa Ziehau /* Set EOP on the last descriptor. */ 15453b22dc82SSepherosa Ziehau prod = (prod + AGE_TX_RING_CNT - 1) % AGE_TX_RING_CNT; 15463b22dc82SSepherosa Ziehau desc = &sc->age_rdata.age_tx_ring[prod]; 15473b22dc82SSepherosa Ziehau desc->flags |= htole32(AGE_TD_EOP); 15483b22dc82SSepherosa Ziehau 15493b22dc82SSepherosa Ziehau /* Swap dmamap of the first and the last. */ 15503b22dc82SSepherosa Ziehau txd = &sc->age_cdata.age_txdesc[prod]; 15513b22dc82SSepherosa Ziehau map = txd_last->tx_dmamap; 15523b22dc82SSepherosa Ziehau txd_last->tx_dmamap = txd->tx_dmamap; 15533b22dc82SSepherosa Ziehau txd->tx_dmamap = map; 15543b22dc82SSepherosa Ziehau txd->tx_m = m; 15553b22dc82SSepherosa Ziehau 15563b22dc82SSepherosa Ziehau /* Sync descriptors. */ 15573b22dc82SSepherosa Ziehau bus_dmamap_sync(sc->age_cdata.age_tx_tag, map, BUS_DMASYNC_PREWRITE); 15583b22dc82SSepherosa Ziehau bus_dmamap_sync(sc->age_cdata.age_tx_ring_tag, 15593b22dc82SSepherosa Ziehau sc->age_cdata.age_tx_ring_map, BUS_DMASYNC_PREWRITE); 15603b22dc82SSepherosa Ziehau 15613b22dc82SSepherosa Ziehau return (0); 15623b22dc82SSepherosa Ziehau } 15633b22dc82SSepherosa Ziehau 15643b22dc82SSepherosa Ziehau static void 1565f0a26983SSepherosa Ziehau age_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) 15663b22dc82SSepherosa Ziehau { 15673b22dc82SSepherosa Ziehau struct age_softc *sc = ifp->if_softc; 15683b22dc82SSepherosa Ziehau struct mbuf *m_head; 15693b22dc82SSepherosa Ziehau int enq; 15703b22dc82SSepherosa Ziehau 1571f0a26983SSepherosa Ziehau ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq); 15723b22dc82SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 15733b22dc82SSepherosa Ziehau 15743b22dc82SSepherosa Ziehau if ((sc->age_flags & AGE_FLAG_LINK) == 0) { 15753b22dc82SSepherosa Ziehau ifq_purge(&ifp->if_snd); 15763b22dc82SSepherosa Ziehau return; 15773b22dc82SSepherosa Ziehau } 15783b22dc82SSepherosa Ziehau 15799ed293e0SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0 || ifq_is_oactive(&ifp->if_snd)) 15803b22dc82SSepherosa Ziehau return; 15813b22dc82SSepherosa Ziehau 15823b22dc82SSepherosa Ziehau enq = 0; 15833b22dc82SSepherosa Ziehau while (!ifq_is_empty(&ifp->if_snd)) { 1584ac9843a1SSepherosa Ziehau m_head = ifq_dequeue(&ifp->if_snd); 15853b22dc82SSepherosa Ziehau if (m_head == NULL) 15863b22dc82SSepherosa Ziehau break; 15873b22dc82SSepherosa Ziehau 15883b22dc82SSepherosa Ziehau /* 15893b22dc82SSepherosa Ziehau * Pack the data into the transmit ring. If we 15903b22dc82SSepherosa Ziehau * don't have room, set the OACTIVE flag and wait 15913b22dc82SSepherosa Ziehau * for the NIC to drain the ring. 15923b22dc82SSepherosa Ziehau */ 15933b22dc82SSepherosa Ziehau if (age_encap(sc, &m_head)) { 15943b22dc82SSepherosa Ziehau if (m_head == NULL) 15953b22dc82SSepherosa Ziehau break; 15963b22dc82SSepherosa Ziehau ifq_prepend(&ifp->if_snd, m_head); 15979ed293e0SSepherosa Ziehau ifq_set_oactive(&ifp->if_snd); 15983b22dc82SSepherosa Ziehau break; 15993b22dc82SSepherosa Ziehau } 16003b22dc82SSepherosa Ziehau enq = 1; 16013b22dc82SSepherosa Ziehau 16023b22dc82SSepherosa Ziehau /* 16033b22dc82SSepherosa Ziehau * If there's a BPF listener, bounce a copy of this frame 16043b22dc82SSepherosa Ziehau * to him. 16053b22dc82SSepherosa Ziehau */ 16063b22dc82SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m_head); 16073b22dc82SSepherosa Ziehau } 16083b22dc82SSepherosa Ziehau 16093b22dc82SSepherosa Ziehau if (enq) { 16103b22dc82SSepherosa Ziehau /* Update mbox. */ 16113b22dc82SSepherosa Ziehau AGE_COMMIT_MBOX(sc); 16123b22dc82SSepherosa Ziehau /* Set a timeout in case the chip goes out to lunch. */ 16133b22dc82SSepherosa Ziehau ifp->if_timer = AGE_TX_TIMEOUT; 16143b22dc82SSepherosa Ziehau } 16153b22dc82SSepherosa Ziehau } 16163b22dc82SSepherosa Ziehau 16173b22dc82SSepherosa Ziehau static void 16183b22dc82SSepherosa Ziehau age_watchdog(struct ifnet *ifp) 16193b22dc82SSepherosa Ziehau { 16203b22dc82SSepherosa Ziehau struct age_softc *sc = ifp->if_softc; 16213b22dc82SSepherosa Ziehau 16223b22dc82SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 16233b22dc82SSepherosa Ziehau 16243b22dc82SSepherosa Ziehau if ((sc->age_flags & AGE_FLAG_LINK) == 0) { 16253b22dc82SSepherosa Ziehau if_printf(ifp, "watchdog timeout (missed link)\n"); 1626d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 16273b22dc82SSepherosa Ziehau age_init(sc); 16283b22dc82SSepherosa Ziehau return; 16293b22dc82SSepherosa Ziehau } 16303b22dc82SSepherosa Ziehau 16313b22dc82SSepherosa Ziehau if (sc->age_cdata.age_tx_cnt == 0) { 16323b22dc82SSepherosa Ziehau if_printf(ifp, 16333b22dc82SSepherosa Ziehau "watchdog timeout (missed Tx interrupts) -- recovering\n"); 16343b22dc82SSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd)) 16353b22dc82SSepherosa Ziehau if_devstart(ifp); 16363b22dc82SSepherosa Ziehau return; 16373b22dc82SSepherosa Ziehau } 16383b22dc82SSepherosa Ziehau 16393b22dc82SSepherosa Ziehau if_printf(ifp, "watchdog timeout\n"); 1640d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 16413b22dc82SSepherosa Ziehau age_init(sc); 16423b22dc82SSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd)) 16433b22dc82SSepherosa Ziehau if_devstart(ifp); 16443b22dc82SSepherosa Ziehau } 16453b22dc82SSepherosa Ziehau 16463b22dc82SSepherosa Ziehau static int 16473b22dc82SSepherosa Ziehau age_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) 16483b22dc82SSepherosa Ziehau { 16493b22dc82SSepherosa Ziehau struct age_softc *sc = ifp->if_softc; 16503b22dc82SSepherosa Ziehau struct ifreq *ifr; 16513b22dc82SSepherosa Ziehau struct mii_data *mii; 16523b22dc82SSepherosa Ziehau uint32_t reg; 16533b22dc82SSepherosa Ziehau int error, mask; 16543b22dc82SSepherosa Ziehau 16553b22dc82SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 16563b22dc82SSepherosa Ziehau 16573b22dc82SSepherosa Ziehau ifr = (struct ifreq *)data; 16583b22dc82SSepherosa Ziehau error = 0; 16593b22dc82SSepherosa Ziehau switch (cmd) { 16603b22dc82SSepherosa Ziehau case SIOCSIFMTU: 16613b22dc82SSepherosa Ziehau if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > AGE_JUMBO_MTU) { 16623b22dc82SSepherosa Ziehau error = EINVAL; 16633b22dc82SSepherosa Ziehau } else if (ifp->if_mtu != ifr->ifr_mtu) { 16643b22dc82SSepherosa Ziehau ifp->if_mtu = ifr->ifr_mtu; 16653b22dc82SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) != 0) 16663b22dc82SSepherosa Ziehau age_init(sc); 16673b22dc82SSepherosa Ziehau } 16683b22dc82SSepherosa Ziehau break; 16693b22dc82SSepherosa Ziehau 16703b22dc82SSepherosa Ziehau case SIOCSIFFLAGS: 16713b22dc82SSepherosa Ziehau if ((ifp->if_flags & IFF_UP) != 0) { 16723b22dc82SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) != 0) { 16733b22dc82SSepherosa Ziehau if (((ifp->if_flags ^ sc->age_if_flags) 16743b22dc82SSepherosa Ziehau & (IFF_PROMISC | IFF_ALLMULTI)) != 0) 16753b22dc82SSepherosa Ziehau age_rxfilter(sc); 16763b22dc82SSepherosa Ziehau } else { 16773b22dc82SSepherosa Ziehau if ((sc->age_flags & AGE_FLAG_DETACH) == 0) 16783b22dc82SSepherosa Ziehau age_init(sc); 16793b22dc82SSepherosa Ziehau } 16803b22dc82SSepherosa Ziehau } else { 16813b22dc82SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) != 0) 16823b22dc82SSepherosa Ziehau age_stop(sc); 16833b22dc82SSepherosa Ziehau } 16843b22dc82SSepherosa Ziehau sc->age_if_flags = ifp->if_flags; 16853b22dc82SSepherosa Ziehau break; 16863b22dc82SSepherosa Ziehau 16873b22dc82SSepherosa Ziehau case SIOCADDMULTI: 16883b22dc82SSepherosa Ziehau case SIOCDELMULTI: 16893b22dc82SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) != 0) 16903b22dc82SSepherosa Ziehau age_rxfilter(sc); 16913b22dc82SSepherosa Ziehau break; 16923b22dc82SSepherosa Ziehau 16933b22dc82SSepherosa Ziehau case SIOCSIFMEDIA: 16943b22dc82SSepherosa Ziehau case SIOCGIFMEDIA: 16953b22dc82SSepherosa Ziehau mii = device_get_softc(sc->age_miibus); 16963b22dc82SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 16973b22dc82SSepherosa Ziehau break; 16983b22dc82SSepherosa Ziehau 16993b22dc82SSepherosa Ziehau case SIOCSIFCAP: 17003b22dc82SSepherosa Ziehau mask = ifr->ifr_reqcap ^ ifp->if_capenable; 17013b22dc82SSepherosa Ziehau 17023b22dc82SSepherosa Ziehau if ((mask & IFCAP_TXCSUM) != 0 && 17033b22dc82SSepherosa Ziehau (ifp->if_capabilities & IFCAP_TXCSUM) != 0) { 17043b22dc82SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM; 17053b22dc82SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 17063b22dc82SSepherosa Ziehau ifp->if_hwassist |= AGE_CSUM_FEATURES; 17073b22dc82SSepherosa Ziehau else 17083b22dc82SSepherosa Ziehau ifp->if_hwassist &= ~AGE_CSUM_FEATURES; 17093b22dc82SSepherosa Ziehau } 17103b22dc82SSepherosa Ziehau 17113b22dc82SSepherosa Ziehau if ((mask & IFCAP_RXCSUM) != 0 && 17123b22dc82SSepherosa Ziehau (ifp->if_capabilities & IFCAP_RXCSUM) != 0) { 17133b22dc82SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM; 17143b22dc82SSepherosa Ziehau reg = CSR_READ_4(sc, AGE_MAC_CFG); 17153b22dc82SSepherosa Ziehau reg &= ~MAC_CFG_RXCSUM_ENB; 17163b22dc82SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 17173b22dc82SSepherosa Ziehau reg |= MAC_CFG_RXCSUM_ENB; 17183b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MAC_CFG, reg); 17193b22dc82SSepherosa Ziehau } 17203b22dc82SSepherosa Ziehau 17213b22dc82SSepherosa Ziehau if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && 17223b22dc82SSepherosa Ziehau (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) { 17233b22dc82SSepherosa Ziehau ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 17243b22dc82SSepherosa Ziehau age_rxvlan(sc); 17253b22dc82SSepherosa Ziehau } 17263b22dc82SSepherosa Ziehau break; 17273b22dc82SSepherosa Ziehau 17283b22dc82SSepherosa Ziehau default: 17293b22dc82SSepherosa Ziehau error = ether_ioctl(ifp, cmd, data); 17303b22dc82SSepherosa Ziehau break; 17313b22dc82SSepherosa Ziehau } 17323b22dc82SSepherosa Ziehau return (error); 17333b22dc82SSepherosa Ziehau } 17343b22dc82SSepherosa Ziehau 17353b22dc82SSepherosa Ziehau static void 17363b22dc82SSepherosa Ziehau age_mac_config(struct age_softc *sc) 17373b22dc82SSepherosa Ziehau { 17383b22dc82SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->age_miibus); 17393b22dc82SSepherosa Ziehau uint32_t reg; 17403b22dc82SSepherosa Ziehau 17413b22dc82SSepherosa Ziehau reg = CSR_READ_4(sc, AGE_MAC_CFG); 17423b22dc82SSepherosa Ziehau reg &= ~MAC_CFG_FULL_DUPLEX; 17433b22dc82SSepherosa Ziehau reg &= ~(MAC_CFG_TX_FC | MAC_CFG_RX_FC); 17443b22dc82SSepherosa Ziehau reg &= ~MAC_CFG_SPEED_MASK; 17453b22dc82SSepherosa Ziehau 17463b22dc82SSepherosa Ziehau /* Reprogram MAC with resolved speed/duplex. */ 17473b22dc82SSepherosa Ziehau switch (IFM_SUBTYPE(mii->mii_media_active)) { 17483b22dc82SSepherosa Ziehau case IFM_10_T: 17493b22dc82SSepherosa Ziehau case IFM_100_TX: 17503b22dc82SSepherosa Ziehau reg |= MAC_CFG_SPEED_10_100; 17513b22dc82SSepherosa Ziehau break; 17523b22dc82SSepherosa Ziehau case IFM_1000_T: 17533b22dc82SSepherosa Ziehau reg |= MAC_CFG_SPEED_1000; 17543b22dc82SSepherosa Ziehau break; 17553b22dc82SSepherosa Ziehau } 17563b22dc82SSepherosa Ziehau if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 17573b22dc82SSepherosa Ziehau reg |= MAC_CFG_FULL_DUPLEX; 17583b22dc82SSepherosa Ziehau #ifdef notyet 17593b22dc82SSepherosa Ziehau if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) 17603b22dc82SSepherosa Ziehau reg |= MAC_CFG_TX_FC; 17613b22dc82SSepherosa Ziehau if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) 17623b22dc82SSepherosa Ziehau reg |= MAC_CFG_RX_FC; 17633b22dc82SSepherosa Ziehau #endif 17643b22dc82SSepherosa Ziehau } 17653b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MAC_CFG, reg); 17663b22dc82SSepherosa Ziehau } 17673b22dc82SSepherosa Ziehau 17683b22dc82SSepherosa Ziehau static void 17693b22dc82SSepherosa Ziehau age_stats_update(struct age_softc *sc) 17703b22dc82SSepherosa Ziehau { 17713b22dc82SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 17723b22dc82SSepherosa Ziehau struct age_stats *stat; 17733b22dc82SSepherosa Ziehau struct smb *smb; 17743b22dc82SSepherosa Ziehau 17753b22dc82SSepherosa Ziehau stat = &sc->age_stat; 17763b22dc82SSepherosa Ziehau 17773b22dc82SSepherosa Ziehau bus_dmamap_sync(sc->age_cdata.age_smb_block_tag, 17783b22dc82SSepherosa Ziehau sc->age_cdata.age_smb_block_map, BUS_DMASYNC_POSTREAD); 17793b22dc82SSepherosa Ziehau 17803b22dc82SSepherosa Ziehau smb = sc->age_rdata.age_smb_block; 17813b22dc82SSepherosa Ziehau if (smb->updated == 0) 17823b22dc82SSepherosa Ziehau return; 17833b22dc82SSepherosa Ziehau 17843b22dc82SSepherosa Ziehau /* Rx stats. */ 17853b22dc82SSepherosa Ziehau stat->rx_frames += smb->rx_frames; 17863b22dc82SSepherosa Ziehau stat->rx_bcast_frames += smb->rx_bcast_frames; 17873b22dc82SSepherosa Ziehau stat->rx_mcast_frames += smb->rx_mcast_frames; 17883b22dc82SSepherosa Ziehau stat->rx_pause_frames += smb->rx_pause_frames; 17893b22dc82SSepherosa Ziehau stat->rx_control_frames += smb->rx_control_frames; 17903b22dc82SSepherosa Ziehau stat->rx_crcerrs += smb->rx_crcerrs; 17913b22dc82SSepherosa Ziehau stat->rx_lenerrs += smb->rx_lenerrs; 17923b22dc82SSepherosa Ziehau stat->rx_bytes += smb->rx_bytes; 17933b22dc82SSepherosa Ziehau stat->rx_runts += smb->rx_runts; 17943b22dc82SSepherosa Ziehau stat->rx_fragments += smb->rx_fragments; 17953b22dc82SSepherosa Ziehau stat->rx_pkts_64 += smb->rx_pkts_64; 17963b22dc82SSepherosa Ziehau stat->rx_pkts_65_127 += smb->rx_pkts_65_127; 17973b22dc82SSepherosa Ziehau stat->rx_pkts_128_255 += smb->rx_pkts_128_255; 17983b22dc82SSepherosa Ziehau stat->rx_pkts_256_511 += smb->rx_pkts_256_511; 17993b22dc82SSepherosa Ziehau stat->rx_pkts_512_1023 += smb->rx_pkts_512_1023; 18003b22dc82SSepherosa Ziehau stat->rx_pkts_1024_1518 += smb->rx_pkts_1024_1518; 18013b22dc82SSepherosa Ziehau stat->rx_pkts_1519_max += smb->rx_pkts_1519_max; 18023b22dc82SSepherosa Ziehau stat->rx_pkts_truncated += smb->rx_pkts_truncated; 18033b22dc82SSepherosa Ziehau stat->rx_fifo_oflows += smb->rx_fifo_oflows; 18043b22dc82SSepherosa Ziehau stat->rx_desc_oflows += smb->rx_desc_oflows; 18053b22dc82SSepherosa Ziehau stat->rx_alignerrs += smb->rx_alignerrs; 18063b22dc82SSepherosa Ziehau stat->rx_bcast_bytes += smb->rx_bcast_bytes; 18073b22dc82SSepherosa Ziehau stat->rx_mcast_bytes += smb->rx_mcast_bytes; 18083b22dc82SSepherosa Ziehau stat->rx_pkts_filtered += smb->rx_pkts_filtered; 18093b22dc82SSepherosa Ziehau 18103b22dc82SSepherosa Ziehau /* Tx stats. */ 18113b22dc82SSepherosa Ziehau stat->tx_frames += smb->tx_frames; 18123b22dc82SSepherosa Ziehau stat->tx_bcast_frames += smb->tx_bcast_frames; 18133b22dc82SSepherosa Ziehau stat->tx_mcast_frames += smb->tx_mcast_frames; 18143b22dc82SSepherosa Ziehau stat->tx_pause_frames += smb->tx_pause_frames; 18153b22dc82SSepherosa Ziehau stat->tx_excess_defer += smb->tx_excess_defer; 18163b22dc82SSepherosa Ziehau stat->tx_control_frames += smb->tx_control_frames; 18173b22dc82SSepherosa Ziehau stat->tx_deferred += smb->tx_deferred; 18183b22dc82SSepherosa Ziehau stat->tx_bytes += smb->tx_bytes; 18193b22dc82SSepherosa Ziehau stat->tx_pkts_64 += smb->tx_pkts_64; 18203b22dc82SSepherosa Ziehau stat->tx_pkts_65_127 += smb->tx_pkts_65_127; 18213b22dc82SSepherosa Ziehau stat->tx_pkts_128_255 += smb->tx_pkts_128_255; 18223b22dc82SSepherosa Ziehau stat->tx_pkts_256_511 += smb->tx_pkts_256_511; 18233b22dc82SSepherosa Ziehau stat->tx_pkts_512_1023 += smb->tx_pkts_512_1023; 18243b22dc82SSepherosa Ziehau stat->tx_pkts_1024_1518 += smb->tx_pkts_1024_1518; 18253b22dc82SSepherosa Ziehau stat->tx_pkts_1519_max += smb->tx_pkts_1519_max; 18263b22dc82SSepherosa Ziehau stat->tx_single_colls += smb->tx_single_colls; 18273b22dc82SSepherosa Ziehau stat->tx_multi_colls += smb->tx_multi_colls; 18283b22dc82SSepherosa Ziehau stat->tx_late_colls += smb->tx_late_colls; 18293b22dc82SSepherosa Ziehau stat->tx_excess_colls += smb->tx_excess_colls; 18303b22dc82SSepherosa Ziehau stat->tx_underrun += smb->tx_underrun; 18313b22dc82SSepherosa Ziehau stat->tx_desc_underrun += smb->tx_desc_underrun; 18323b22dc82SSepherosa Ziehau stat->tx_lenerrs += smb->tx_lenerrs; 18333b22dc82SSepherosa Ziehau stat->tx_pkts_truncated += smb->tx_pkts_truncated; 18343b22dc82SSepherosa Ziehau stat->tx_bcast_bytes += smb->tx_bcast_bytes; 18353b22dc82SSepherosa Ziehau stat->tx_mcast_bytes += smb->tx_mcast_bytes; 18363b22dc82SSepherosa Ziehau 18373b22dc82SSepherosa Ziehau /* Update counters in ifnet. */ 1838d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, opackets, smb->tx_frames); 18393b22dc82SSepherosa Ziehau 1840d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, collisions, smb->tx_single_colls + 18413b22dc82SSepherosa Ziehau smb->tx_multi_colls + smb->tx_late_colls + 1842d40991efSSepherosa Ziehau smb->tx_excess_colls * HDPX_CFG_RETRY_DEFAULT); 18433b22dc82SSepherosa Ziehau 1844d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, smb->tx_excess_colls + 18453b22dc82SSepherosa Ziehau smb->tx_late_colls + smb->tx_underrun + 1846d40991efSSepherosa Ziehau smb->tx_pkts_truncated); 18473b22dc82SSepherosa Ziehau 1848d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ipackets, smb->rx_frames); 18493b22dc82SSepherosa Ziehau 1850d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, smb->rx_crcerrs + smb->rx_lenerrs + 18513b22dc82SSepherosa Ziehau smb->rx_runts + smb->rx_pkts_truncated + 18523b22dc82SSepherosa Ziehau smb->rx_fifo_oflows + smb->rx_desc_oflows + 1853d40991efSSepherosa Ziehau smb->rx_alignerrs); 18543b22dc82SSepherosa Ziehau 18553b22dc82SSepherosa Ziehau /* Update done, clear. */ 18563b22dc82SSepherosa Ziehau smb->updated = 0; 18573b22dc82SSepherosa Ziehau 18583b22dc82SSepherosa Ziehau bus_dmamap_sync(sc->age_cdata.age_smb_block_tag, 18593b22dc82SSepherosa Ziehau sc->age_cdata.age_smb_block_map, BUS_DMASYNC_PREWRITE); 18603b22dc82SSepherosa Ziehau } 18613b22dc82SSepherosa Ziehau 18623b22dc82SSepherosa Ziehau static void 18633b22dc82SSepherosa Ziehau age_intr(void *xsc) 18643b22dc82SSepherosa Ziehau { 18653b22dc82SSepherosa Ziehau struct age_softc *sc = xsc; 18663b22dc82SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 18673b22dc82SSepherosa Ziehau struct cmb *cmb; 18683b22dc82SSepherosa Ziehau uint32_t status; 18693b22dc82SSepherosa Ziehau 18703b22dc82SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 18713b22dc82SSepherosa Ziehau 18723b22dc82SSepherosa Ziehau status = CSR_READ_4(sc, AGE_INTR_STATUS); 18733b22dc82SSepherosa Ziehau if (status == 0 || (status & AGE_INTRS) == 0) 18743b22dc82SSepherosa Ziehau return; 18753b22dc82SSepherosa Ziehau 18763b22dc82SSepherosa Ziehau /* Disable and acknowledge interrupts. */ 18773b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_INTR_STATUS, status | INTR_DIS_INT); 18783b22dc82SSepherosa Ziehau 18793b22dc82SSepherosa Ziehau cmb = sc->age_rdata.age_cmb_block; 18803b22dc82SSepherosa Ziehau 18813b22dc82SSepherosa Ziehau bus_dmamap_sync(sc->age_cdata.age_cmb_block_tag, 18823b22dc82SSepherosa Ziehau sc->age_cdata.age_cmb_block_map, BUS_DMASYNC_POSTREAD); 18833b22dc82SSepherosa Ziehau status = le32toh(cmb->intr_status); 18843b22dc82SSepherosa Ziehau if ((status & AGE_INTRS) == 0) 18853b22dc82SSepherosa Ziehau goto done; 18863b22dc82SSepherosa Ziehau again: 18873b22dc82SSepherosa Ziehau sc->age_tpd_cons = (le32toh(cmb->tpd_cons) & TPD_CONS_MASK) >> 18883b22dc82SSepherosa Ziehau TPD_CONS_SHIFT; 18893b22dc82SSepherosa Ziehau sc->age_rr_prod = (le32toh(cmb->rprod_cons) & RRD_PROD_MASK) >> 18903b22dc82SSepherosa Ziehau RRD_PROD_SHIFT; 18913b22dc82SSepherosa Ziehau 18923b22dc82SSepherosa Ziehau /* Let hardware know CMB was served. */ 18933b22dc82SSepherosa Ziehau cmb->intr_status = 0; 18943b22dc82SSepherosa Ziehau bus_dmamap_sync(sc->age_cdata.age_cmb_block_tag, 18953b22dc82SSepherosa Ziehau sc->age_cdata.age_cmb_block_map, BUS_DMASYNC_PREWRITE); 18963b22dc82SSepherosa Ziehau 18973b22dc82SSepherosa Ziehau #if 0 18983b22dc82SSepherosa Ziehau kprintf("INTR: 0x%08x\n", status); 18993b22dc82SSepherosa Ziehau status &= ~INTR_DIS_DMA; 19003b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_INTR_STATUS, status | INTR_DIS_INT); 19013b22dc82SSepherosa Ziehau #endif 19023b22dc82SSepherosa Ziehau 19033b22dc82SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) != 0) { 19043b22dc82SSepherosa Ziehau if ((status & INTR_CMB_RX) != 0) 19053b22dc82SSepherosa Ziehau age_rxintr(sc, sc->age_rr_prod); 19063b22dc82SSepherosa Ziehau 19073b22dc82SSepherosa Ziehau if ((status & INTR_CMB_TX) != 0) 19083b22dc82SSepherosa Ziehau age_txintr(sc, sc->age_tpd_cons); 19093b22dc82SSepherosa Ziehau 19103b22dc82SSepherosa Ziehau if ((status & (INTR_DMA_RD_TO_RST | INTR_DMA_WR_TO_RST)) != 0) { 19113b22dc82SSepherosa Ziehau if ((status & INTR_DMA_RD_TO_RST) != 0) 19123b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 19133b22dc82SSepherosa Ziehau "DMA read error! -- resetting\n"); 19143b22dc82SSepherosa Ziehau if ((status & INTR_DMA_WR_TO_RST) != 0) 19153b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 19163b22dc82SSepherosa Ziehau "DMA write error! -- resetting\n"); 19173b22dc82SSepherosa Ziehau age_init(sc); 19183b22dc82SSepherosa Ziehau /* XXX return? */ 19193b22dc82SSepherosa Ziehau } 19203b22dc82SSepherosa Ziehau 19213b22dc82SSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd)) 19223b22dc82SSepherosa Ziehau if_devstart(ifp); 19233b22dc82SSepherosa Ziehau 19243b22dc82SSepherosa Ziehau if ((status & INTR_SMB) != 0) 19253b22dc82SSepherosa Ziehau age_stats_update(sc); 19263b22dc82SSepherosa Ziehau } 19273b22dc82SSepherosa Ziehau 19283b22dc82SSepherosa Ziehau /* Check whether CMB was updated while serving Tx/Rx/SMB handler. */ 19293b22dc82SSepherosa Ziehau bus_dmamap_sync(sc->age_cdata.age_cmb_block_tag, 19303b22dc82SSepherosa Ziehau sc->age_cdata.age_cmb_block_map, BUS_DMASYNC_POSTREAD); 19313b22dc82SSepherosa Ziehau status = le32toh(cmb->intr_status); 19323b22dc82SSepherosa Ziehau if ((status & AGE_INTRS) != 0) 19333b22dc82SSepherosa Ziehau goto again; 19343b22dc82SSepherosa Ziehau done: 19353b22dc82SSepherosa Ziehau /* Re-enable interrupts. */ 19363b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_INTR_STATUS, 0); 19373b22dc82SSepherosa Ziehau } 19383b22dc82SSepherosa Ziehau 19393b22dc82SSepherosa Ziehau static void 19403b22dc82SSepherosa Ziehau age_txintr(struct age_softc *sc, int tpd_cons) 19413b22dc82SSepherosa Ziehau { 19423b22dc82SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 19433b22dc82SSepherosa Ziehau struct age_txdesc *txd; 19443b22dc82SSepherosa Ziehau int cons, prog; 19453b22dc82SSepherosa Ziehau 19463b22dc82SSepherosa Ziehau bus_dmamap_sync(sc->age_cdata.age_tx_ring_tag, 19473b22dc82SSepherosa Ziehau sc->age_cdata.age_tx_ring_map, BUS_DMASYNC_POSTREAD); 19483b22dc82SSepherosa Ziehau 19493b22dc82SSepherosa Ziehau /* 19503b22dc82SSepherosa Ziehau * Go through our Tx list and free mbufs for those 19513b22dc82SSepherosa Ziehau * frames which have been transmitted. 19523b22dc82SSepherosa Ziehau */ 19533b22dc82SSepherosa Ziehau cons = sc->age_cdata.age_tx_cons; 19543b22dc82SSepherosa Ziehau for (prog = 0; cons != tpd_cons; AGE_DESC_INC(cons, AGE_TX_RING_CNT)) { 19553b22dc82SSepherosa Ziehau if (sc->age_cdata.age_tx_cnt <= 0) 19563b22dc82SSepherosa Ziehau break; 19573b22dc82SSepherosa Ziehau prog++; 19589ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 19593b22dc82SSepherosa Ziehau sc->age_cdata.age_tx_cnt--; 19603b22dc82SSepherosa Ziehau txd = &sc->age_cdata.age_txdesc[cons]; 19613b22dc82SSepherosa Ziehau /* 19623b22dc82SSepherosa Ziehau * Clear Tx descriptors, it's not required but would 19633b22dc82SSepherosa Ziehau * help debugging in case of Tx issues. 19643b22dc82SSepherosa Ziehau */ 19653b22dc82SSepherosa Ziehau txd->tx_desc->addr = 0; 19663b22dc82SSepherosa Ziehau txd->tx_desc->len = 0; 19673b22dc82SSepherosa Ziehau txd->tx_desc->flags = 0; 19683b22dc82SSepherosa Ziehau 19693b22dc82SSepherosa Ziehau if (txd->tx_m == NULL) 19703b22dc82SSepherosa Ziehau continue; 19713b22dc82SSepherosa Ziehau /* Reclaim transmitted mbufs. */ 19723b22dc82SSepherosa Ziehau bus_dmamap_unload(sc->age_cdata.age_tx_tag, txd->tx_dmamap); 19733b22dc82SSepherosa Ziehau m_freem(txd->tx_m); 19743b22dc82SSepherosa Ziehau txd->tx_m = NULL; 19753b22dc82SSepherosa Ziehau } 19763b22dc82SSepherosa Ziehau 19773b22dc82SSepherosa Ziehau if (prog > 0) { 19783b22dc82SSepherosa Ziehau sc->age_cdata.age_tx_cons = cons; 19793b22dc82SSepherosa Ziehau 19803b22dc82SSepherosa Ziehau /* 19813b22dc82SSepherosa Ziehau * Unarm watchdog timer only when there are no pending 19823b22dc82SSepherosa Ziehau * Tx descriptors in queue. 19833b22dc82SSepherosa Ziehau */ 19843b22dc82SSepherosa Ziehau if (sc->age_cdata.age_tx_cnt == 0) 19853b22dc82SSepherosa Ziehau ifp->if_timer = 0; 19863b22dc82SSepherosa Ziehau bus_dmamap_sync(sc->age_cdata.age_tx_ring_tag, 19873b22dc82SSepherosa Ziehau sc->age_cdata.age_tx_ring_map, BUS_DMASYNC_PREWRITE); 19883b22dc82SSepherosa Ziehau } 19893b22dc82SSepherosa Ziehau } 19903b22dc82SSepherosa Ziehau 19913b22dc82SSepherosa Ziehau /* Receive a frame. */ 19923b22dc82SSepherosa Ziehau static void 19933b22dc82SSepherosa Ziehau age_rxeof(struct age_softc *sc, struct rx_rdesc *rxrd) 19943b22dc82SSepherosa Ziehau { 19953b22dc82SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 19963b22dc82SSepherosa Ziehau struct age_rxdesc *rxd; 19973b22dc82SSepherosa Ziehau struct rx_desc *desc; 19983b22dc82SSepherosa Ziehau struct mbuf *mp, *m; 19993b22dc82SSepherosa Ziehau uint32_t status, index, vtag; 20003b22dc82SSepherosa Ziehau int count, nsegs, pktlen; 20013b22dc82SSepherosa Ziehau int rx_cons; 20023b22dc82SSepherosa Ziehau 20033b22dc82SSepherosa Ziehau status = le32toh(rxrd->flags); 20043b22dc82SSepherosa Ziehau index = le32toh(rxrd->index); 20053b22dc82SSepherosa Ziehau rx_cons = AGE_RX_CONS(index); 20063b22dc82SSepherosa Ziehau nsegs = AGE_RX_NSEGS(index); 20073b22dc82SSepherosa Ziehau 20083b22dc82SSepherosa Ziehau sc->age_cdata.age_rxlen = AGE_RX_BYTES(le32toh(rxrd->len)); 20093b22dc82SSepherosa Ziehau if ((status & AGE_RRD_ERROR) != 0 && 20103b22dc82SSepherosa Ziehau (status & (AGE_RRD_CRC | AGE_RRD_CODE | AGE_RRD_DRIBBLE | 20113b22dc82SSepherosa Ziehau AGE_RRD_RUNT | AGE_RRD_OFLOW | AGE_RRD_TRUNC)) != 0) { 20123b22dc82SSepherosa Ziehau /* 20133b22dc82SSepherosa Ziehau * We want to pass the following frames to upper 20143b22dc82SSepherosa Ziehau * layer regardless of error status of Rx return 20153b22dc82SSepherosa Ziehau * ring. 20163b22dc82SSepherosa Ziehau * 20173b22dc82SSepherosa Ziehau * o IP/TCP/UDP checksum is bad. 20183b22dc82SSepherosa Ziehau * o frame length and protocol specific length 20193b22dc82SSepherosa Ziehau * does not match. 20203b22dc82SSepherosa Ziehau */ 20213b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_cons += nsegs; 20223b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_cons %= AGE_RX_RING_CNT; 20233b22dc82SSepherosa Ziehau return; 20243b22dc82SSepherosa Ziehau } 20253b22dc82SSepherosa Ziehau 20263b22dc82SSepherosa Ziehau pktlen = 0; 20273b22dc82SSepherosa Ziehau for (count = 0; count < nsegs; count++, 20283b22dc82SSepherosa Ziehau AGE_DESC_INC(rx_cons, AGE_RX_RING_CNT)) { 20293b22dc82SSepherosa Ziehau rxd = &sc->age_cdata.age_rxdesc[rx_cons]; 20303b22dc82SSepherosa Ziehau mp = rxd->rx_m; 20313b22dc82SSepherosa Ziehau desc = rxd->rx_desc; 20323b22dc82SSepherosa Ziehau /* Add a new receive buffer to the ring. */ 20333b22dc82SSepherosa Ziehau if (age_newbuf(sc, rxd, 0) != 0) { 2034d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, iqdrops, 1); 20353b22dc82SSepherosa Ziehau /* Reuse Rx buffers. */ 20363b22dc82SSepherosa Ziehau if (sc->age_cdata.age_rxhead != NULL) { 20373b22dc82SSepherosa Ziehau m_freem(sc->age_cdata.age_rxhead); 20383b22dc82SSepherosa Ziehau AGE_RXCHAIN_RESET(sc); 20393b22dc82SSepherosa Ziehau } 20403b22dc82SSepherosa Ziehau break; 20413b22dc82SSepherosa Ziehau } 20423b22dc82SSepherosa Ziehau 20433b22dc82SSepherosa Ziehau /* The length of the first mbuf is computed last. */ 20443b22dc82SSepherosa Ziehau if (count != 0) { 20453b22dc82SSepherosa Ziehau mp->m_len = AGE_RX_BYTES(le32toh(desc->len)); 20463b22dc82SSepherosa Ziehau pktlen += mp->m_len; 20473b22dc82SSepherosa Ziehau } 20483b22dc82SSepherosa Ziehau 20493b22dc82SSepherosa Ziehau /* Chain received mbufs. */ 20503b22dc82SSepherosa Ziehau if (sc->age_cdata.age_rxhead == NULL) { 20513b22dc82SSepherosa Ziehau sc->age_cdata.age_rxhead = mp; 20523b22dc82SSepherosa Ziehau sc->age_cdata.age_rxtail = mp; 20533b22dc82SSepherosa Ziehau } else { 20543b22dc82SSepherosa Ziehau mp->m_flags &= ~M_PKTHDR; 20553b22dc82SSepherosa Ziehau sc->age_cdata.age_rxprev_tail = 20563b22dc82SSepherosa Ziehau sc->age_cdata.age_rxtail; 20573b22dc82SSepherosa Ziehau sc->age_cdata.age_rxtail->m_next = mp; 20583b22dc82SSepherosa Ziehau sc->age_cdata.age_rxtail = mp; 20593b22dc82SSepherosa Ziehau } 20603b22dc82SSepherosa Ziehau 20613b22dc82SSepherosa Ziehau if (count == nsegs - 1) { 20623b22dc82SSepherosa Ziehau /* 20633b22dc82SSepherosa Ziehau * It seems that L1 controller has no way 20643b22dc82SSepherosa Ziehau * to tell hardware to strip CRC bytes. 20653b22dc82SSepherosa Ziehau */ 20663b22dc82SSepherosa Ziehau sc->age_cdata.age_rxlen -= ETHER_CRC_LEN; 20673b22dc82SSepherosa Ziehau if (nsegs > 1) { 20683b22dc82SSepherosa Ziehau /* Remove the CRC bytes in chained mbufs. */ 20693b22dc82SSepherosa Ziehau pktlen -= ETHER_CRC_LEN; 20703b22dc82SSepherosa Ziehau if (mp->m_len <= ETHER_CRC_LEN) { 20713b22dc82SSepherosa Ziehau sc->age_cdata.age_rxtail = 20723b22dc82SSepherosa Ziehau sc->age_cdata.age_rxprev_tail; 20733b22dc82SSepherosa Ziehau sc->age_cdata.age_rxtail->m_len -= 20743b22dc82SSepherosa Ziehau (ETHER_CRC_LEN - mp->m_len); 20753b22dc82SSepherosa Ziehau sc->age_cdata.age_rxtail->m_next = NULL; 20763b22dc82SSepherosa Ziehau m_freem(mp); 20773b22dc82SSepherosa Ziehau } else { 20783b22dc82SSepherosa Ziehau mp->m_len -= ETHER_CRC_LEN; 20793b22dc82SSepherosa Ziehau } 20803b22dc82SSepherosa Ziehau } 20813b22dc82SSepherosa Ziehau 20823b22dc82SSepherosa Ziehau m = sc->age_cdata.age_rxhead; 20833b22dc82SSepherosa Ziehau m->m_flags |= M_PKTHDR; 20843b22dc82SSepherosa Ziehau m->m_pkthdr.rcvif = ifp; 20853b22dc82SSepherosa Ziehau m->m_pkthdr.len = sc->age_cdata.age_rxlen; 20863b22dc82SSepherosa Ziehau /* Set the first mbuf length. */ 20873b22dc82SSepherosa Ziehau m->m_len = sc->age_cdata.age_rxlen - pktlen; 20883b22dc82SSepherosa Ziehau 20893b22dc82SSepherosa Ziehau /* 20903b22dc82SSepherosa Ziehau * Set checksum information. 20913b22dc82SSepherosa Ziehau * It seems that L1 controller can compute partial 20923b22dc82SSepherosa Ziehau * checksum. The partial checksum value can be used 20933b22dc82SSepherosa Ziehau * to accelerate checksum computation for fragmented 20943b22dc82SSepherosa Ziehau * TCP/UDP packets. Upper network stack already 20953b22dc82SSepherosa Ziehau * takes advantage of the partial checksum value in 20963b22dc82SSepherosa Ziehau * IP reassembly stage. But I'm not sure the 20973b22dc82SSepherosa Ziehau * correctness of the partial hardware checksum 20983b22dc82SSepherosa Ziehau * assistance due to lack of data sheet. If it is 20993b22dc82SSepherosa Ziehau * proven to work on L1 I'll enable it. 21003b22dc82SSepherosa Ziehau */ 21013b22dc82SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_RXCSUM) != 0 && 21023b22dc82SSepherosa Ziehau (status & AGE_RRD_IPV4) != 0) { 21033b22dc82SSepherosa Ziehau m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 21043b22dc82SSepherosa Ziehau if ((status & AGE_RRD_IPCSUM_NOK) == 0) 21053b22dc82SSepherosa Ziehau m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 21063b22dc82SSepherosa Ziehau if ((status & (AGE_RRD_TCP | AGE_RRD_UDP)) && 21073b22dc82SSepherosa Ziehau (status & AGE_RRD_TCP_UDPCSUM_NOK) == 0) { 21083b22dc82SSepherosa Ziehau m->m_pkthdr.csum_flags |= 21093b22dc82SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 21103b22dc82SSepherosa Ziehau m->m_pkthdr.csum_data = 0xffff; 21113b22dc82SSepherosa Ziehau } 21123b22dc82SSepherosa Ziehau /* 21133b22dc82SSepherosa Ziehau * Don't mark bad checksum for TCP/UDP frames 21143b22dc82SSepherosa Ziehau * as fragmented frames may always have set 21153b22dc82SSepherosa Ziehau * bad checksummed bit of descriptor status. 21163b22dc82SSepherosa Ziehau */ 21173b22dc82SSepherosa Ziehau } 21183b22dc82SSepherosa Ziehau 21193b22dc82SSepherosa Ziehau /* Check for VLAN tagged frames. */ 21203b22dc82SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 && 21213b22dc82SSepherosa Ziehau (status & AGE_RRD_VLAN) != 0) { 21223b22dc82SSepherosa Ziehau vtag = AGE_RX_VLAN(le32toh(rxrd->vtags)); 21233b22dc82SSepherosa Ziehau m->m_pkthdr.ether_vlantag = 21243b22dc82SSepherosa Ziehau AGE_RX_VLAN_TAG(vtag); 21253b22dc82SSepherosa Ziehau m->m_flags |= M_VLANTAG; 21263b22dc82SSepherosa Ziehau } 21273b22dc82SSepherosa Ziehau 21283b22dc82SSepherosa Ziehau /* Pass it on. */ 212973029d08SFranco Fichtner ifp->if_input(ifp, m, NULL, -1); 21303b22dc82SSepherosa Ziehau 21313b22dc82SSepherosa Ziehau /* Reset mbuf chains. */ 21323b22dc82SSepherosa Ziehau AGE_RXCHAIN_RESET(sc); 21333b22dc82SSepherosa Ziehau } 21343b22dc82SSepherosa Ziehau } 21353b22dc82SSepherosa Ziehau 21363b22dc82SSepherosa Ziehau if (count != nsegs) { 21373b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_cons += nsegs; 21383b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_cons %= AGE_RX_RING_CNT; 21393b22dc82SSepherosa Ziehau } else { 21403b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_cons = rx_cons; 21413b22dc82SSepherosa Ziehau } 21423b22dc82SSepherosa Ziehau } 21433b22dc82SSepherosa Ziehau 21443b22dc82SSepherosa Ziehau static void 21453b22dc82SSepherosa Ziehau age_rxintr(struct age_softc *sc, int rr_prod) 21463b22dc82SSepherosa Ziehau { 21473b22dc82SSepherosa Ziehau struct rx_rdesc *rxrd; 21483b22dc82SSepherosa Ziehau int rr_cons, nsegs, pktlen, prog; 21493b22dc82SSepherosa Ziehau 21503b22dc82SSepherosa Ziehau rr_cons = sc->age_cdata.age_rr_cons; 21513b22dc82SSepherosa Ziehau if (rr_cons == rr_prod) 21523b22dc82SSepherosa Ziehau return; 21533b22dc82SSepherosa Ziehau 21543b22dc82SSepherosa Ziehau bus_dmamap_sync(sc->age_cdata.age_rr_ring_tag, 21553b22dc82SSepherosa Ziehau sc->age_cdata.age_rr_ring_map, BUS_DMASYNC_POSTREAD); 21563b22dc82SSepherosa Ziehau 21573b22dc82SSepherosa Ziehau for (prog = 0; rr_cons != rr_prod; prog++) { 21583b22dc82SSepherosa Ziehau rxrd = &sc->age_rdata.age_rr_ring[rr_cons]; 21593b22dc82SSepherosa Ziehau nsegs = AGE_RX_NSEGS(le32toh(rxrd->index)); 21603b22dc82SSepherosa Ziehau if (nsegs == 0) 21613b22dc82SSepherosa Ziehau break; 21623b22dc82SSepherosa Ziehau 21633b22dc82SSepherosa Ziehau /* 21643b22dc82SSepherosa Ziehau * Check number of segments against received bytes. 21653b22dc82SSepherosa Ziehau * Non-matching value would indicate that hardware 21663b22dc82SSepherosa Ziehau * is still trying to update Rx return descriptors. 21673b22dc82SSepherosa Ziehau * I'm not sure whether this check is really needed. 21683b22dc82SSepherosa Ziehau */ 21693b22dc82SSepherosa Ziehau pktlen = AGE_RX_BYTES(le32toh(rxrd->len)); 21703b22dc82SSepherosa Ziehau if (nsegs != ((pktlen + (MCLBYTES - ETHER_ALIGN - 1)) / 21713b22dc82SSepherosa Ziehau (MCLBYTES - ETHER_ALIGN))) 21723b22dc82SSepherosa Ziehau break; 21733b22dc82SSepherosa Ziehau 21743b22dc82SSepherosa Ziehau /* Received a frame. */ 21753b22dc82SSepherosa Ziehau age_rxeof(sc, rxrd); 21763b22dc82SSepherosa Ziehau 21773b22dc82SSepherosa Ziehau /* Clear return ring. */ 21783b22dc82SSepherosa Ziehau rxrd->index = 0; 21793b22dc82SSepherosa Ziehau AGE_DESC_INC(rr_cons, AGE_RR_RING_CNT); 21803b22dc82SSepherosa Ziehau } 21813b22dc82SSepherosa Ziehau 21823b22dc82SSepherosa Ziehau if (prog > 0) { 21833b22dc82SSepherosa Ziehau /* Update the consumer index. */ 21843b22dc82SSepherosa Ziehau sc->age_cdata.age_rr_cons = rr_cons; 21853b22dc82SSepherosa Ziehau 21863b22dc82SSepherosa Ziehau /* Sync descriptors. */ 21873b22dc82SSepherosa Ziehau bus_dmamap_sync(sc->age_cdata.age_rr_ring_tag, 21883b22dc82SSepherosa Ziehau sc->age_cdata.age_rr_ring_map, BUS_DMASYNC_PREWRITE); 21893b22dc82SSepherosa Ziehau 21903b22dc82SSepherosa Ziehau /* Notify hardware availability of new Rx buffers. */ 21913b22dc82SSepherosa Ziehau AGE_COMMIT_MBOX(sc); 21923b22dc82SSepherosa Ziehau } 21933b22dc82SSepherosa Ziehau } 21943b22dc82SSepherosa Ziehau 21953b22dc82SSepherosa Ziehau static void 21963b22dc82SSepherosa Ziehau age_tick(void *xsc) 21973b22dc82SSepherosa Ziehau { 21983b22dc82SSepherosa Ziehau struct age_softc *sc = xsc; 21993b22dc82SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 22003b22dc82SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->age_miibus); 22013b22dc82SSepherosa Ziehau 22023b22dc82SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 22033b22dc82SSepherosa Ziehau 22043b22dc82SSepherosa Ziehau mii_tick(mii); 22053b22dc82SSepherosa Ziehau callout_reset(&sc->age_tick_ch, hz, age_tick, sc); 22063b22dc82SSepherosa Ziehau 22073b22dc82SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 22083b22dc82SSepherosa Ziehau } 22093b22dc82SSepherosa Ziehau 22103b22dc82SSepherosa Ziehau static void 22113b22dc82SSepherosa Ziehau age_reset(struct age_softc *sc) 22123b22dc82SSepherosa Ziehau { 22133b22dc82SSepherosa Ziehau uint32_t reg; 22143b22dc82SSepherosa Ziehau int i; 22153b22dc82SSepherosa Ziehau 22163b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MASTER_CFG, MASTER_RESET); 22173b22dc82SSepherosa Ziehau for (i = AGE_RESET_TIMEOUT; i > 0; i--) { 22183b22dc82SSepherosa Ziehau DELAY(1); 22193b22dc82SSepherosa Ziehau if ((CSR_READ_4(sc, AGE_MASTER_CFG) & MASTER_RESET) == 0) 22203b22dc82SSepherosa Ziehau break; 22213b22dc82SSepherosa Ziehau } 22223b22dc82SSepherosa Ziehau if (i == 0) 22233b22dc82SSepherosa Ziehau device_printf(sc->age_dev, "master reset timeout!\n"); 22243b22dc82SSepherosa Ziehau 22253b22dc82SSepherosa Ziehau for (i = AGE_RESET_TIMEOUT; i > 0; i--) { 22263b22dc82SSepherosa Ziehau if ((reg = CSR_READ_4(sc, AGE_IDLE_STATUS)) == 0) 22273b22dc82SSepherosa Ziehau break; 22283b22dc82SSepherosa Ziehau DELAY(10); 22293b22dc82SSepherosa Ziehau } 22303b22dc82SSepherosa Ziehau if (i == 0) 22313b22dc82SSepherosa Ziehau device_printf(sc->age_dev, "reset timeout(0x%08x)!\n", reg); 22323b22dc82SSepherosa Ziehau 22333b22dc82SSepherosa Ziehau /* Initialize PCIe module. From Linux. */ 22343b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, 0x12FC, 0x6500); 22353b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, 0x1008, CSR_READ_4(sc, 0x1008) | 0x8000); 22363b22dc82SSepherosa Ziehau } 22373b22dc82SSepherosa Ziehau 22383b22dc82SSepherosa Ziehau static void 22393b22dc82SSepherosa Ziehau age_init(void *xsc) 22403b22dc82SSepherosa Ziehau { 22413b22dc82SSepherosa Ziehau struct age_softc *sc = xsc; 22423b22dc82SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 22433b22dc82SSepherosa Ziehau struct mii_data *mii; 22443b22dc82SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN]; 22453b22dc82SSepherosa Ziehau bus_addr_t paddr; 22463b22dc82SSepherosa Ziehau uint32_t reg, fsize; 22473b22dc82SSepherosa Ziehau uint32_t rxf_hi, rxf_lo, rrd_hi, rrd_lo; 22483b22dc82SSepherosa Ziehau int error; 22493b22dc82SSepherosa Ziehau 22503b22dc82SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 22513b22dc82SSepherosa Ziehau 22523b22dc82SSepherosa Ziehau mii = device_get_softc(sc->age_miibus); 22533b22dc82SSepherosa Ziehau 22543b22dc82SSepherosa Ziehau /* 22553b22dc82SSepherosa Ziehau * Cancel any pending I/O. 22563b22dc82SSepherosa Ziehau */ 22573b22dc82SSepherosa Ziehau age_stop(sc); 22583b22dc82SSepherosa Ziehau 22593b22dc82SSepherosa Ziehau /* 22603b22dc82SSepherosa Ziehau * Reset the chip to a known state. 22613b22dc82SSepherosa Ziehau */ 22623b22dc82SSepherosa Ziehau age_reset(sc); 22633b22dc82SSepherosa Ziehau 22643b22dc82SSepherosa Ziehau /* Initialize descriptors. */ 22653b22dc82SSepherosa Ziehau error = age_init_rx_ring(sc); 22663b22dc82SSepherosa Ziehau if (error != 0) { 22673b22dc82SSepherosa Ziehau device_printf(sc->age_dev, "no memory for Rx buffers.\n"); 22683b22dc82SSepherosa Ziehau age_stop(sc); 22693b22dc82SSepherosa Ziehau return; 22703b22dc82SSepherosa Ziehau } 22713b22dc82SSepherosa Ziehau age_init_rr_ring(sc); 22723b22dc82SSepherosa Ziehau age_init_tx_ring(sc); 22733b22dc82SSepherosa Ziehau age_init_cmb_block(sc); 22743b22dc82SSepherosa Ziehau age_init_smb_block(sc); 22753b22dc82SSepherosa Ziehau 22763b22dc82SSepherosa Ziehau /* Reprogram the station address. */ 22773b22dc82SSepherosa Ziehau bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN); 22783b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_PAR0, 22793b22dc82SSepherosa Ziehau eaddr[2] << 24 | eaddr[3] << 16 | eaddr[4] << 8 | eaddr[5]); 22803b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_PAR1, eaddr[0] << 8 | eaddr[1]); 22813b22dc82SSepherosa Ziehau 22823b22dc82SSepherosa Ziehau /* Set descriptor base addresses. */ 22833b22dc82SSepherosa Ziehau paddr = sc->age_rdata.age_tx_ring_paddr; 22843b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_DESC_ADDR_HI, AGE_ADDR_HI(paddr)); 22853b22dc82SSepherosa Ziehau paddr = sc->age_rdata.age_rx_ring_paddr; 22863b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_DESC_RD_ADDR_LO, AGE_ADDR_LO(paddr)); 22873b22dc82SSepherosa Ziehau paddr = sc->age_rdata.age_rr_ring_paddr; 22883b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_DESC_RRD_ADDR_LO, AGE_ADDR_LO(paddr)); 22893b22dc82SSepherosa Ziehau paddr = sc->age_rdata.age_tx_ring_paddr; 22903b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_DESC_TPD_ADDR_LO, AGE_ADDR_LO(paddr)); 22913b22dc82SSepherosa Ziehau paddr = sc->age_rdata.age_cmb_block_paddr; 22923b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_DESC_CMB_ADDR_LO, AGE_ADDR_LO(paddr)); 22933b22dc82SSepherosa Ziehau paddr = sc->age_rdata.age_smb_block_paddr; 22943b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_DESC_SMB_ADDR_LO, AGE_ADDR_LO(paddr)); 22953b22dc82SSepherosa Ziehau 22963b22dc82SSepherosa Ziehau /* Set Rx/Rx return descriptor counter. */ 22973b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_DESC_RRD_RD_CNT, 22983b22dc82SSepherosa Ziehau ((AGE_RR_RING_CNT << DESC_RRD_CNT_SHIFT) & 22993b22dc82SSepherosa Ziehau DESC_RRD_CNT_MASK) | 23003b22dc82SSepherosa Ziehau ((AGE_RX_RING_CNT << DESC_RD_CNT_SHIFT) & DESC_RD_CNT_MASK)); 23013b22dc82SSepherosa Ziehau 23023b22dc82SSepherosa Ziehau /* Set Tx descriptor counter. */ 23033b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_DESC_TPD_CNT, 23043b22dc82SSepherosa Ziehau (AGE_TX_RING_CNT << DESC_TPD_CNT_SHIFT) & DESC_TPD_CNT_MASK); 23053b22dc82SSepherosa Ziehau 23063b22dc82SSepherosa Ziehau /* Tell hardware that we're ready to load descriptors. */ 23073b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_DMA_BLOCK, DMA_BLOCK_LOAD); 23083b22dc82SSepherosa Ziehau 23093b22dc82SSepherosa Ziehau /* 23103b22dc82SSepherosa Ziehau * Initialize mailbox register. 23113b22dc82SSepherosa Ziehau * Updated producer/consumer index information is exchanged 23123b22dc82SSepherosa Ziehau * through this mailbox register. However Tx producer and 23133b22dc82SSepherosa Ziehau * Rx return consumer/Rx producer are all shared such that 23143b22dc82SSepherosa Ziehau * it's hard to separate code path between Tx and Rx without 23153b22dc82SSepherosa Ziehau * locking. If L1 hardware have a separate mail box register 23163b22dc82SSepherosa Ziehau * for Tx and Rx consumer/producer management we could have 23173b22dc82SSepherosa Ziehau * indepent Tx/Rx handler which in turn Rx handler could have 23183b22dc82SSepherosa Ziehau * been run without any locking. 23193b22dc82SSepherosa Ziehau */ 23203b22dc82SSepherosa Ziehau AGE_COMMIT_MBOX(sc); 23213b22dc82SSepherosa Ziehau 23223b22dc82SSepherosa Ziehau /* Configure IPG/IFG parameters. */ 23233b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_IPG_IFG_CFG, 23243b22dc82SSepherosa Ziehau ((IPG_IFG_IPG2_DEFAULT << IPG_IFG_IPG2_SHIFT) & IPG_IFG_IPG2_MASK) | 23253b22dc82SSepherosa Ziehau ((IPG_IFG_IPG1_DEFAULT << IPG_IFG_IPG1_SHIFT) & IPG_IFG_IPG1_MASK) | 23263b22dc82SSepherosa Ziehau ((IPG_IFG_MIFG_DEFAULT << IPG_IFG_MIFG_SHIFT) & IPG_IFG_MIFG_MASK) | 23273b22dc82SSepherosa Ziehau ((IPG_IFG_IPGT_DEFAULT << IPG_IFG_IPGT_SHIFT) & IPG_IFG_IPGT_MASK)); 23283b22dc82SSepherosa Ziehau 23293b22dc82SSepherosa Ziehau /* Set parameters for half-duplex media. */ 23303b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_HDPX_CFG, 23313b22dc82SSepherosa Ziehau ((HDPX_CFG_LCOL_DEFAULT << HDPX_CFG_LCOL_SHIFT) & 23323b22dc82SSepherosa Ziehau HDPX_CFG_LCOL_MASK) | 23333b22dc82SSepherosa Ziehau ((HDPX_CFG_RETRY_DEFAULT << HDPX_CFG_RETRY_SHIFT) & 23343b22dc82SSepherosa Ziehau HDPX_CFG_RETRY_MASK) | HDPX_CFG_EXC_DEF_EN | 23353b22dc82SSepherosa Ziehau ((HDPX_CFG_ABEBT_DEFAULT << HDPX_CFG_ABEBT_SHIFT) & 23363b22dc82SSepherosa Ziehau HDPX_CFG_ABEBT_MASK) | 23373b22dc82SSepherosa Ziehau ((HDPX_CFG_JAMIPG_DEFAULT << HDPX_CFG_JAMIPG_SHIFT) & 23383b22dc82SSepherosa Ziehau HDPX_CFG_JAMIPG_MASK)); 23393b22dc82SSepherosa Ziehau 23403b22dc82SSepherosa Ziehau /* Configure interrupt moderation timer. */ 23413b22dc82SSepherosa Ziehau CSR_WRITE_2(sc, AGE_IM_TIMER, AGE_USECS(sc->age_int_mod)); 23423b22dc82SSepherosa Ziehau reg = CSR_READ_4(sc, AGE_MASTER_CFG); 23433b22dc82SSepherosa Ziehau reg &= ~MASTER_MTIMER_ENB; 23443b22dc82SSepherosa Ziehau if (AGE_USECS(sc->age_int_mod) == 0) 23453b22dc82SSepherosa Ziehau reg &= ~MASTER_ITIMER_ENB; 23463b22dc82SSepherosa Ziehau else 23473b22dc82SSepherosa Ziehau reg |= MASTER_ITIMER_ENB; 23483b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MASTER_CFG, reg); 23493b22dc82SSepherosa Ziehau if (bootverbose) 23503b22dc82SSepherosa Ziehau device_printf(sc->age_dev, "interrupt moderation is %d us.\n", 23513b22dc82SSepherosa Ziehau sc->age_int_mod); 23523b22dc82SSepherosa Ziehau CSR_WRITE_2(sc, AGE_INTR_CLR_TIMER, AGE_USECS(1000)); 23533b22dc82SSepherosa Ziehau 23543b22dc82SSepherosa Ziehau /* Set Maximum frame size but don't let MTU be lass than ETHER_MTU. */ 23553b22dc82SSepherosa Ziehau if (ifp->if_mtu < ETHERMTU) 23563b22dc82SSepherosa Ziehau sc->age_max_frame_size = ETHERMTU; 23573b22dc82SSepherosa Ziehau else 23583b22dc82SSepherosa Ziehau sc->age_max_frame_size = ifp->if_mtu; 23593b22dc82SSepherosa Ziehau sc->age_max_frame_size += ETHER_HDR_LEN + 23603b22dc82SSepherosa Ziehau sizeof(struct ether_vlan_header) + ETHER_CRC_LEN; 23613b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_FRAME_SIZE, sc->age_max_frame_size); 23623b22dc82SSepherosa Ziehau 23633b22dc82SSepherosa Ziehau /* Configure jumbo frame. */ 23643b22dc82SSepherosa Ziehau fsize = roundup(sc->age_max_frame_size, sizeof(uint64_t)); 23653b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_RXQ_JUMBO_CFG, 23663b22dc82SSepherosa Ziehau (((fsize / sizeof(uint64_t)) << 23673b22dc82SSepherosa Ziehau RXQ_JUMBO_CFG_SZ_THRESH_SHIFT) & RXQ_JUMBO_CFG_SZ_THRESH_MASK) | 23683b22dc82SSepherosa Ziehau ((RXQ_JUMBO_CFG_LKAH_DEFAULT << 23693b22dc82SSepherosa Ziehau RXQ_JUMBO_CFG_LKAH_SHIFT) & RXQ_JUMBO_CFG_LKAH_MASK) | 23703b22dc82SSepherosa Ziehau ((AGE_USECS(8) << RXQ_JUMBO_CFG_RRD_TIMER_SHIFT) & 23713b22dc82SSepherosa Ziehau RXQ_JUMBO_CFG_RRD_TIMER_MASK)); 23723b22dc82SSepherosa Ziehau 23733b22dc82SSepherosa Ziehau /* Configure flow-control parameters. From Linux. */ 23743b22dc82SSepherosa Ziehau if ((sc->age_flags & AGE_FLAG_PCIE) != 0) { 23753b22dc82SSepherosa Ziehau /* 23763b22dc82SSepherosa Ziehau * Magic workaround for old-L1. 23773b22dc82SSepherosa Ziehau * Don't know which hw revision requires this magic. 23783b22dc82SSepherosa Ziehau */ 23793b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, 0x12FC, 0x6500); 23803b22dc82SSepherosa Ziehau /* 23813b22dc82SSepherosa Ziehau * Another magic workaround for flow-control mode 23823b22dc82SSepherosa Ziehau * change. From Linux. 23833b22dc82SSepherosa Ziehau */ 23843b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, 0x1008, CSR_READ_4(sc, 0x1008) | 0x8000); 23853b22dc82SSepherosa Ziehau } 23863b22dc82SSepherosa Ziehau /* 23873b22dc82SSepherosa Ziehau * TODO 23883b22dc82SSepherosa Ziehau * Should understand pause parameter relationships between FIFO 23893b22dc82SSepherosa Ziehau * size and number of Rx descriptors and Rx return descriptors. 23903b22dc82SSepherosa Ziehau * 23913b22dc82SSepherosa Ziehau * Magic parameters came from Linux. 23923b22dc82SSepherosa Ziehau */ 23933b22dc82SSepherosa Ziehau switch (sc->age_chip_rev) { 23943b22dc82SSepherosa Ziehau case 0x8001: 23953b22dc82SSepherosa Ziehau case 0x9001: 23963b22dc82SSepherosa Ziehau case 0x9002: 23973b22dc82SSepherosa Ziehau case 0x9003: 23983b22dc82SSepherosa Ziehau rxf_hi = AGE_RX_RING_CNT / 16; 23993b22dc82SSepherosa Ziehau rxf_lo = (AGE_RX_RING_CNT * 7) / 8; 24003b22dc82SSepherosa Ziehau rrd_hi = (AGE_RR_RING_CNT * 7) / 8; 24013b22dc82SSepherosa Ziehau rrd_lo = AGE_RR_RING_CNT / 16; 24023b22dc82SSepherosa Ziehau break; 24033b22dc82SSepherosa Ziehau default: 24043b22dc82SSepherosa Ziehau reg = CSR_READ_4(sc, AGE_SRAM_RX_FIFO_LEN); 24053b22dc82SSepherosa Ziehau rxf_lo = reg / 16; 24063b22dc82SSepherosa Ziehau if (rxf_lo < 192) 24073b22dc82SSepherosa Ziehau rxf_lo = 192; 24083b22dc82SSepherosa Ziehau rxf_hi = (reg * 7) / 8; 24093b22dc82SSepherosa Ziehau if (rxf_hi < rxf_lo) 24103b22dc82SSepherosa Ziehau rxf_hi = rxf_lo + 16; 24113b22dc82SSepherosa Ziehau reg = CSR_READ_4(sc, AGE_SRAM_RRD_LEN); 24123b22dc82SSepherosa Ziehau rrd_lo = reg / 8; 24133b22dc82SSepherosa Ziehau rrd_hi = (reg * 7) / 8; 24143b22dc82SSepherosa Ziehau if (rrd_lo < 2) 24153b22dc82SSepherosa Ziehau rrd_lo = 2; 24163b22dc82SSepherosa Ziehau if (rrd_hi < rrd_lo) 24173b22dc82SSepherosa Ziehau rrd_hi = rrd_lo + 3; 24183b22dc82SSepherosa Ziehau break; 24193b22dc82SSepherosa Ziehau } 24203b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_RXQ_FIFO_PAUSE_THRESH, 24213b22dc82SSepherosa Ziehau ((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) & 24223b22dc82SSepherosa Ziehau RXQ_FIFO_PAUSE_THRESH_LO_MASK) | 24233b22dc82SSepherosa Ziehau ((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) & 24243b22dc82SSepherosa Ziehau RXQ_FIFO_PAUSE_THRESH_HI_MASK)); 24253b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_RXQ_RRD_PAUSE_THRESH, 24263b22dc82SSepherosa Ziehau ((rrd_lo << RXQ_RRD_PAUSE_THRESH_LO_SHIFT) & 24273b22dc82SSepherosa Ziehau RXQ_RRD_PAUSE_THRESH_LO_MASK) | 24283b22dc82SSepherosa Ziehau ((rrd_hi << RXQ_RRD_PAUSE_THRESH_HI_SHIFT) & 24293b22dc82SSepherosa Ziehau RXQ_RRD_PAUSE_THRESH_HI_MASK)); 24303b22dc82SSepherosa Ziehau 24313b22dc82SSepherosa Ziehau /* Configure RxQ. */ 24323b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_RXQ_CFG, 24333b22dc82SSepherosa Ziehau ((RXQ_CFG_RD_BURST_DEFAULT << RXQ_CFG_RD_BURST_SHIFT) & 24343b22dc82SSepherosa Ziehau RXQ_CFG_RD_BURST_MASK) | 24353b22dc82SSepherosa Ziehau ((RXQ_CFG_RRD_BURST_THRESH_DEFAULT << 24363b22dc82SSepherosa Ziehau RXQ_CFG_RRD_BURST_THRESH_SHIFT) & RXQ_CFG_RRD_BURST_THRESH_MASK) | 24373b22dc82SSepherosa Ziehau ((RXQ_CFG_RD_PREF_MIN_IPG_DEFAULT << 24383b22dc82SSepherosa Ziehau RXQ_CFG_RD_PREF_MIN_IPG_SHIFT) & RXQ_CFG_RD_PREF_MIN_IPG_MASK) | 24393b22dc82SSepherosa Ziehau RXQ_CFG_CUT_THROUGH_ENB | RXQ_CFG_ENB); 24403b22dc82SSepherosa Ziehau 24413b22dc82SSepherosa Ziehau /* Configure TxQ. */ 24423b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_TXQ_CFG, 24433b22dc82SSepherosa Ziehau ((TXQ_CFG_TPD_BURST_DEFAULT << TXQ_CFG_TPD_BURST_SHIFT) & 24443b22dc82SSepherosa Ziehau TXQ_CFG_TPD_BURST_MASK) | 24453b22dc82SSepherosa Ziehau ((TXQ_CFG_TX_FIFO_BURST_DEFAULT << TXQ_CFG_TX_FIFO_BURST_SHIFT) & 24463b22dc82SSepherosa Ziehau TXQ_CFG_TX_FIFO_BURST_MASK) | 24473b22dc82SSepherosa Ziehau ((TXQ_CFG_TPD_FETCH_DEFAULT << 24483b22dc82SSepherosa Ziehau TXQ_CFG_TPD_FETCH_THRESH_SHIFT) & TXQ_CFG_TPD_FETCH_THRESH_MASK) | 24493b22dc82SSepherosa Ziehau TXQ_CFG_ENB); 24503b22dc82SSepherosa Ziehau 24513b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_TX_JUMBO_TPD_TH_IPG, 24523b22dc82SSepherosa Ziehau (((fsize / sizeof(uint64_t) << TX_JUMBO_TPD_TH_SHIFT)) & 24533b22dc82SSepherosa Ziehau TX_JUMBO_TPD_TH_MASK) | 24543b22dc82SSepherosa Ziehau ((TX_JUMBO_TPD_IPG_DEFAULT << TX_JUMBO_TPD_IPG_SHIFT) & 24553b22dc82SSepherosa Ziehau TX_JUMBO_TPD_IPG_MASK)); 24563b22dc82SSepherosa Ziehau 24573b22dc82SSepherosa Ziehau /* Configure DMA parameters. */ 24583b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_DMA_CFG, 24593b22dc82SSepherosa Ziehau DMA_CFG_ENH_ORDER | DMA_CFG_RCB_64 | 24603b22dc82SSepherosa Ziehau sc->age_dma_rd_burst | DMA_CFG_RD_ENB | 24613b22dc82SSepherosa Ziehau sc->age_dma_wr_burst | DMA_CFG_WR_ENB); 24623b22dc82SSepherosa Ziehau 24633b22dc82SSepherosa Ziehau /* Configure CMB DMA write threshold. */ 24643b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_CMB_WR_THRESH, 24653b22dc82SSepherosa Ziehau ((CMB_WR_THRESH_RRD_DEFAULT << CMB_WR_THRESH_RRD_SHIFT) & 24663b22dc82SSepherosa Ziehau CMB_WR_THRESH_RRD_MASK) | 24673b22dc82SSepherosa Ziehau ((CMB_WR_THRESH_TPD_DEFAULT << CMB_WR_THRESH_TPD_SHIFT) & 24683b22dc82SSepherosa Ziehau CMB_WR_THRESH_TPD_MASK)); 24693b22dc82SSepherosa Ziehau 24703b22dc82SSepherosa Ziehau /* Set CMB/SMB timer and enable them. */ 24713b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_CMB_WR_TIMER, 24723b22dc82SSepherosa Ziehau ((AGE_USECS(2) << CMB_WR_TIMER_TX_SHIFT) & CMB_WR_TIMER_TX_MASK) | 24733b22dc82SSepherosa Ziehau ((AGE_USECS(2) << CMB_WR_TIMER_RX_SHIFT) & CMB_WR_TIMER_RX_MASK)); 24743b22dc82SSepherosa Ziehau 24753b22dc82SSepherosa Ziehau /* Request SMB updates for every seconds. */ 24763b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_SMB_TIMER, AGE_USECS(1000 * 1000)); 24773b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_CSMB_CTRL, CSMB_CTRL_SMB_ENB | CSMB_CTRL_CMB_ENB); 24783b22dc82SSepherosa Ziehau 24793b22dc82SSepherosa Ziehau /* 24803b22dc82SSepherosa Ziehau * Disable all WOL bits as WOL can interfere normal Rx 24813b22dc82SSepherosa Ziehau * operation. 24823b22dc82SSepherosa Ziehau */ 24833b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_WOL_CFG, 0); 24843b22dc82SSepherosa Ziehau 24853b22dc82SSepherosa Ziehau /* 24863b22dc82SSepherosa Ziehau * Configure Tx/Rx MACs. 24873b22dc82SSepherosa Ziehau * - Auto-padding for short frames. 24883b22dc82SSepherosa Ziehau * - Enable CRC generation. 24893b22dc82SSepherosa Ziehau * Start with full-duplex/1000Mbps media. Actual reconfiguration 24903b22dc82SSepherosa Ziehau * of MAC is followed after link establishment. 24913b22dc82SSepherosa Ziehau */ 24923b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MAC_CFG, 24933b22dc82SSepherosa Ziehau MAC_CFG_TX_CRC_ENB | MAC_CFG_TX_AUTO_PAD | 24943b22dc82SSepherosa Ziehau MAC_CFG_FULL_DUPLEX | MAC_CFG_SPEED_1000 | 24953b22dc82SSepherosa Ziehau ((MAC_CFG_PREAMBLE_DEFAULT << MAC_CFG_PREAMBLE_SHIFT) & 24963b22dc82SSepherosa Ziehau MAC_CFG_PREAMBLE_MASK)); 24973b22dc82SSepherosa Ziehau 24983b22dc82SSepherosa Ziehau /* Set up the receive filter. */ 24993b22dc82SSepherosa Ziehau age_rxfilter(sc); 25003b22dc82SSepherosa Ziehau age_rxvlan(sc); 25013b22dc82SSepherosa Ziehau 25023b22dc82SSepherosa Ziehau reg = CSR_READ_4(sc, AGE_MAC_CFG); 25033b22dc82SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 25043b22dc82SSepherosa Ziehau reg |= MAC_CFG_RXCSUM_ENB; 25053b22dc82SSepherosa Ziehau 25063b22dc82SSepherosa Ziehau /* Ack all pending interrupts and clear it. */ 25073b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_INTR_STATUS, 0); 25083b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_INTR_MASK, AGE_INTRS); 25093b22dc82SSepherosa Ziehau 25103b22dc82SSepherosa Ziehau /* Finally enable Tx/Rx MAC. */ 25113b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MAC_CFG, reg | MAC_CFG_TX_ENB | MAC_CFG_RX_ENB); 25123b22dc82SSepherosa Ziehau 25133b22dc82SSepherosa Ziehau sc->age_flags &= ~AGE_FLAG_LINK; 25143b22dc82SSepherosa Ziehau /* Switch to the current media. */ 25153b22dc82SSepherosa Ziehau mii_mediachg(mii); 25163b22dc82SSepherosa Ziehau 25173b22dc82SSepherosa Ziehau callout_reset(&sc->age_tick_ch, hz, age_tick, sc); 25183b22dc82SSepherosa Ziehau 25193b22dc82SSepherosa Ziehau ifp->if_flags |= IFF_RUNNING; 25209ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 25213b22dc82SSepherosa Ziehau } 25223b22dc82SSepherosa Ziehau 25233b22dc82SSepherosa Ziehau static void 25243b22dc82SSepherosa Ziehau age_stop(struct age_softc *sc) 25253b22dc82SSepherosa Ziehau { 25263b22dc82SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 25273b22dc82SSepherosa Ziehau struct age_txdesc *txd; 25283b22dc82SSepherosa Ziehau struct age_rxdesc *rxd; 25293b22dc82SSepherosa Ziehau uint32_t reg; 25303b22dc82SSepherosa Ziehau int i; 25313b22dc82SSepherosa Ziehau 25323b22dc82SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 25333b22dc82SSepherosa Ziehau 25343b22dc82SSepherosa Ziehau /* 25353b22dc82SSepherosa Ziehau * Mark the interface down and cancel the watchdog timer. 25363b22dc82SSepherosa Ziehau */ 25379ed293e0SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING; 25389ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 25393b22dc82SSepherosa Ziehau ifp->if_timer = 0; 25403b22dc82SSepherosa Ziehau 25413b22dc82SSepherosa Ziehau sc->age_flags &= ~AGE_FLAG_LINK; 25423b22dc82SSepherosa Ziehau callout_stop(&sc->age_tick_ch); 25433b22dc82SSepherosa Ziehau 25443b22dc82SSepherosa Ziehau /* 25453b22dc82SSepherosa Ziehau * Disable interrupts. 25463b22dc82SSepherosa Ziehau */ 25473b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_INTR_MASK, 0); 25483b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_INTR_STATUS, 0xFFFFFFFF); 25493b22dc82SSepherosa Ziehau 25503b22dc82SSepherosa Ziehau /* Stop CMB/SMB updates. */ 25513b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_CSMB_CTRL, 0); 25523b22dc82SSepherosa Ziehau 25533b22dc82SSepherosa Ziehau /* Stop Rx/Tx MAC. */ 25543b22dc82SSepherosa Ziehau age_stop_rxmac(sc); 25553b22dc82SSepherosa Ziehau age_stop_txmac(sc); 25563b22dc82SSepherosa Ziehau 25573b22dc82SSepherosa Ziehau /* Stop DMA. */ 25583b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_DMA_CFG, 25593b22dc82SSepherosa Ziehau CSR_READ_4(sc, AGE_DMA_CFG) & ~(DMA_CFG_RD_ENB | DMA_CFG_WR_ENB)); 25603b22dc82SSepherosa Ziehau 25613b22dc82SSepherosa Ziehau /* Stop TxQ/RxQ. */ 25623b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_TXQ_CFG, 25633b22dc82SSepherosa Ziehau CSR_READ_4(sc, AGE_TXQ_CFG) & ~TXQ_CFG_ENB); 25643b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_RXQ_CFG, 25653b22dc82SSepherosa Ziehau CSR_READ_4(sc, AGE_RXQ_CFG) & ~RXQ_CFG_ENB); 25663b22dc82SSepherosa Ziehau for (i = AGE_RESET_TIMEOUT; i > 0; i--) { 25673b22dc82SSepherosa Ziehau if ((reg = CSR_READ_4(sc, AGE_IDLE_STATUS)) == 0) 25683b22dc82SSepherosa Ziehau break; 25693b22dc82SSepherosa Ziehau DELAY(10); 25703b22dc82SSepherosa Ziehau } 25713b22dc82SSepherosa Ziehau if (i == 0) 25723b22dc82SSepherosa Ziehau device_printf(sc->age_dev, 25733b22dc82SSepherosa Ziehau "stopping Rx/Tx MACs timed out(0x%08x)!\n", reg); 25743b22dc82SSepherosa Ziehau 25753b22dc82SSepherosa Ziehau /* Reclaim Rx buffers that have been processed. */ 25763b22dc82SSepherosa Ziehau if (sc->age_cdata.age_rxhead != NULL) 25773b22dc82SSepherosa Ziehau m_freem(sc->age_cdata.age_rxhead); 25783b22dc82SSepherosa Ziehau AGE_RXCHAIN_RESET(sc); 25793b22dc82SSepherosa Ziehau 25803b22dc82SSepherosa Ziehau /* 25813b22dc82SSepherosa Ziehau * Free RX and TX mbufs still in the queues. 25823b22dc82SSepherosa Ziehau */ 25833b22dc82SSepherosa Ziehau for (i = 0; i < AGE_RX_RING_CNT; i++) { 25843b22dc82SSepherosa Ziehau rxd = &sc->age_cdata.age_rxdesc[i]; 25853b22dc82SSepherosa Ziehau if (rxd->rx_m != NULL) { 25863b22dc82SSepherosa Ziehau bus_dmamap_unload(sc->age_cdata.age_rx_tag, 25873b22dc82SSepherosa Ziehau rxd->rx_dmamap); 25883b22dc82SSepherosa Ziehau m_freem(rxd->rx_m); 25893b22dc82SSepherosa Ziehau rxd->rx_m = NULL; 25903b22dc82SSepherosa Ziehau } 25913b22dc82SSepherosa Ziehau } 25923b22dc82SSepherosa Ziehau for (i = 0; i < AGE_TX_RING_CNT; i++) { 25933b22dc82SSepherosa Ziehau txd = &sc->age_cdata.age_txdesc[i]; 25943b22dc82SSepherosa Ziehau if (txd->tx_m != NULL) { 25953b22dc82SSepherosa Ziehau bus_dmamap_unload(sc->age_cdata.age_tx_tag, 25963b22dc82SSepherosa Ziehau txd->tx_dmamap); 25973b22dc82SSepherosa Ziehau m_freem(txd->tx_m); 25983b22dc82SSepherosa Ziehau txd->tx_m = NULL; 25993b22dc82SSepherosa Ziehau } 26003b22dc82SSepherosa Ziehau } 26013b22dc82SSepherosa Ziehau } 26023b22dc82SSepherosa Ziehau 26033b22dc82SSepherosa Ziehau static void 26043b22dc82SSepherosa Ziehau age_stop_txmac(struct age_softc *sc) 26053b22dc82SSepherosa Ziehau { 26063b22dc82SSepherosa Ziehau uint32_t reg; 26073b22dc82SSepherosa Ziehau int i; 26083b22dc82SSepherosa Ziehau 26093b22dc82SSepherosa Ziehau reg = CSR_READ_4(sc, AGE_MAC_CFG); 26103b22dc82SSepherosa Ziehau if ((reg & MAC_CFG_TX_ENB) != 0) { 26113b22dc82SSepherosa Ziehau reg &= ~MAC_CFG_TX_ENB; 26123b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MAC_CFG, reg); 26133b22dc82SSepherosa Ziehau } 26143b22dc82SSepherosa Ziehau /* Stop Tx DMA engine. */ 26153b22dc82SSepherosa Ziehau reg = CSR_READ_4(sc, AGE_DMA_CFG); 26163b22dc82SSepherosa Ziehau if ((reg & DMA_CFG_RD_ENB) != 0) { 26173b22dc82SSepherosa Ziehau reg &= ~DMA_CFG_RD_ENB; 26183b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_DMA_CFG, reg); 26193b22dc82SSepherosa Ziehau } 26203b22dc82SSepherosa Ziehau for (i = AGE_RESET_TIMEOUT; i > 0; i--) { 26213b22dc82SSepherosa Ziehau if ((CSR_READ_4(sc, AGE_IDLE_STATUS) & 26223b22dc82SSepherosa Ziehau (IDLE_STATUS_TXMAC | IDLE_STATUS_DMARD)) == 0) 26233b22dc82SSepherosa Ziehau break; 26243b22dc82SSepherosa Ziehau DELAY(10); 26253b22dc82SSepherosa Ziehau } 26263b22dc82SSepherosa Ziehau if (i == 0) 26273b22dc82SSepherosa Ziehau device_printf(sc->age_dev, "stopping TxMAC timeout!\n"); 26283b22dc82SSepherosa Ziehau } 26293b22dc82SSepherosa Ziehau 26303b22dc82SSepherosa Ziehau static void 26313b22dc82SSepherosa Ziehau age_stop_rxmac(struct age_softc *sc) 26323b22dc82SSepherosa Ziehau { 26333b22dc82SSepherosa Ziehau uint32_t reg; 26343b22dc82SSepherosa Ziehau int i; 26353b22dc82SSepherosa Ziehau 26363b22dc82SSepherosa Ziehau reg = CSR_READ_4(sc, AGE_MAC_CFG); 26373b22dc82SSepherosa Ziehau if ((reg & MAC_CFG_RX_ENB) != 0) { 26383b22dc82SSepherosa Ziehau reg &= ~MAC_CFG_RX_ENB; 26393b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MAC_CFG, reg); 26403b22dc82SSepherosa Ziehau } 26413b22dc82SSepherosa Ziehau /* Stop Rx DMA engine. */ 26423b22dc82SSepherosa Ziehau reg = CSR_READ_4(sc, AGE_DMA_CFG); 26433b22dc82SSepherosa Ziehau if ((reg & DMA_CFG_WR_ENB) != 0) { 26443b22dc82SSepherosa Ziehau reg &= ~DMA_CFG_WR_ENB; 26453b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_DMA_CFG, reg); 26463b22dc82SSepherosa Ziehau } 26473b22dc82SSepherosa Ziehau for (i = AGE_RESET_TIMEOUT; i > 0; i--) { 26483b22dc82SSepherosa Ziehau if ((CSR_READ_4(sc, AGE_IDLE_STATUS) & 26493b22dc82SSepherosa Ziehau (IDLE_STATUS_RXMAC | IDLE_STATUS_DMAWR)) == 0) 26503b22dc82SSepherosa Ziehau break; 26513b22dc82SSepherosa Ziehau DELAY(10); 26523b22dc82SSepherosa Ziehau } 26533b22dc82SSepherosa Ziehau if (i == 0) 26543b22dc82SSepherosa Ziehau device_printf(sc->age_dev, "stopping RxMAC timeout!\n"); 26553b22dc82SSepherosa Ziehau } 26563b22dc82SSepherosa Ziehau 26573b22dc82SSepherosa Ziehau static void 26583b22dc82SSepherosa Ziehau age_init_tx_ring(struct age_softc *sc) 26593b22dc82SSepherosa Ziehau { 26603b22dc82SSepherosa Ziehau struct age_ring_data *rd; 26613b22dc82SSepherosa Ziehau struct age_txdesc *txd; 26623b22dc82SSepherosa Ziehau int i; 26633b22dc82SSepherosa Ziehau 26643b22dc82SSepherosa Ziehau sc->age_cdata.age_tx_prod = 0; 26653b22dc82SSepherosa Ziehau sc->age_cdata.age_tx_cons = 0; 26663b22dc82SSepherosa Ziehau sc->age_cdata.age_tx_cnt = 0; 26673b22dc82SSepherosa Ziehau 26683b22dc82SSepherosa Ziehau rd = &sc->age_rdata; 26693b22dc82SSepherosa Ziehau bzero(rd->age_tx_ring, AGE_TX_RING_SZ); 26703b22dc82SSepherosa Ziehau for (i = 0; i < AGE_TX_RING_CNT; i++) { 26713b22dc82SSepherosa Ziehau txd = &sc->age_cdata.age_txdesc[i]; 26723b22dc82SSepherosa Ziehau txd->tx_desc = &rd->age_tx_ring[i]; 26733b22dc82SSepherosa Ziehau txd->tx_m = NULL; 26743b22dc82SSepherosa Ziehau } 26753b22dc82SSepherosa Ziehau 26763b22dc82SSepherosa Ziehau bus_dmamap_sync(sc->age_cdata.age_tx_ring_tag, 26773b22dc82SSepherosa Ziehau sc->age_cdata.age_tx_ring_map, BUS_DMASYNC_PREWRITE); 26783b22dc82SSepherosa Ziehau } 26793b22dc82SSepherosa Ziehau 26803b22dc82SSepherosa Ziehau static int 26813b22dc82SSepherosa Ziehau age_init_rx_ring(struct age_softc *sc) 26823b22dc82SSepherosa Ziehau { 26833b22dc82SSepherosa Ziehau struct age_ring_data *rd; 26843b22dc82SSepherosa Ziehau struct age_rxdesc *rxd; 26853b22dc82SSepherosa Ziehau int i; 26863b22dc82SSepherosa Ziehau 26873b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_cons = AGE_RX_RING_CNT - 1; 26883b22dc82SSepherosa Ziehau rd = &sc->age_rdata; 26893b22dc82SSepherosa Ziehau bzero(rd->age_rx_ring, AGE_RX_RING_SZ); 26903b22dc82SSepherosa Ziehau for (i = 0; i < AGE_RX_RING_CNT; i++) { 26913b22dc82SSepherosa Ziehau rxd = &sc->age_cdata.age_rxdesc[i]; 26923b22dc82SSepherosa Ziehau rxd->rx_m = NULL; 26933b22dc82SSepherosa Ziehau rxd->rx_desc = &rd->age_rx_ring[i]; 26943b22dc82SSepherosa Ziehau if (age_newbuf(sc, rxd, 1) != 0) 26953b22dc82SSepherosa Ziehau return (ENOBUFS); 26963b22dc82SSepherosa Ziehau } 26973b22dc82SSepherosa Ziehau 26983b22dc82SSepherosa Ziehau bus_dmamap_sync(sc->age_cdata.age_rx_ring_tag, 26993b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_ring_map, BUS_DMASYNC_PREWRITE); 27003b22dc82SSepherosa Ziehau 27013b22dc82SSepherosa Ziehau return (0); 27023b22dc82SSepherosa Ziehau } 27033b22dc82SSepherosa Ziehau 27043b22dc82SSepherosa Ziehau static void 27053b22dc82SSepherosa Ziehau age_init_rr_ring(struct age_softc *sc) 27063b22dc82SSepherosa Ziehau { 27073b22dc82SSepherosa Ziehau struct age_ring_data *rd; 27083b22dc82SSepherosa Ziehau 27093b22dc82SSepherosa Ziehau sc->age_cdata.age_rr_cons = 0; 27103b22dc82SSepherosa Ziehau AGE_RXCHAIN_RESET(sc); 27113b22dc82SSepherosa Ziehau 27123b22dc82SSepherosa Ziehau rd = &sc->age_rdata; 27133b22dc82SSepherosa Ziehau bzero(rd->age_rr_ring, AGE_RR_RING_SZ); 27143b22dc82SSepherosa Ziehau bus_dmamap_sync(sc->age_cdata.age_rr_ring_tag, 27153b22dc82SSepherosa Ziehau sc->age_cdata.age_rr_ring_map, BUS_DMASYNC_PREWRITE); 27163b22dc82SSepherosa Ziehau } 27173b22dc82SSepherosa Ziehau 27183b22dc82SSepherosa Ziehau static void 27193b22dc82SSepherosa Ziehau age_init_cmb_block(struct age_softc *sc) 27203b22dc82SSepherosa Ziehau { 27213b22dc82SSepherosa Ziehau struct age_ring_data *rd; 27223b22dc82SSepherosa Ziehau 27233b22dc82SSepherosa Ziehau rd = &sc->age_rdata; 27243b22dc82SSepherosa Ziehau bzero(rd->age_cmb_block, AGE_CMB_BLOCK_SZ); 27253b22dc82SSepherosa Ziehau bus_dmamap_sync(sc->age_cdata.age_cmb_block_tag, 27263b22dc82SSepherosa Ziehau sc->age_cdata.age_cmb_block_map, BUS_DMASYNC_PREWRITE); 27273b22dc82SSepherosa Ziehau } 27283b22dc82SSepherosa Ziehau 27293b22dc82SSepherosa Ziehau static void 27303b22dc82SSepherosa Ziehau age_init_smb_block(struct age_softc *sc) 27313b22dc82SSepherosa Ziehau { 27323b22dc82SSepherosa Ziehau struct age_ring_data *rd; 27333b22dc82SSepherosa Ziehau 27343b22dc82SSepherosa Ziehau rd = &sc->age_rdata; 27353b22dc82SSepherosa Ziehau bzero(rd->age_smb_block, AGE_SMB_BLOCK_SZ); 27363b22dc82SSepherosa Ziehau bus_dmamap_sync(sc->age_cdata.age_smb_block_tag, 27373b22dc82SSepherosa Ziehau sc->age_cdata.age_smb_block_map, BUS_DMASYNC_PREWRITE); 27383b22dc82SSepherosa Ziehau } 27393b22dc82SSepherosa Ziehau 27403b22dc82SSepherosa Ziehau static int 27413b22dc82SSepherosa Ziehau age_newbuf(struct age_softc *sc, struct age_rxdesc *rxd, int init) 27423b22dc82SSepherosa Ziehau { 27433b22dc82SSepherosa Ziehau struct rx_desc *desc; 27443b22dc82SSepherosa Ziehau struct mbuf *m; 27453b22dc82SSepherosa Ziehau struct age_dmamap_ctx ctx; 27463b22dc82SSepherosa Ziehau bus_dma_segment_t segs[1]; 27473b22dc82SSepherosa Ziehau bus_dmamap_t map; 27483b22dc82SSepherosa Ziehau int error; 27493b22dc82SSepherosa Ziehau 27503b22dc82SSepherosa Ziehau m = m_getcl(init ? MB_WAIT : MB_DONTWAIT, MT_DATA, M_PKTHDR); 27513b22dc82SSepherosa Ziehau if (m == NULL) 27523b22dc82SSepherosa Ziehau return (ENOBUFS); 27533b22dc82SSepherosa Ziehau 27543b22dc82SSepherosa Ziehau m->m_len = m->m_pkthdr.len = MCLBYTES; 27553b22dc82SSepherosa Ziehau m_adj(m, ETHER_ALIGN); 27563b22dc82SSepherosa Ziehau 27573b22dc82SSepherosa Ziehau ctx.nsegs = 1; 27583b22dc82SSepherosa Ziehau ctx.segs = segs; 27593b22dc82SSepherosa Ziehau error = bus_dmamap_load_mbuf(sc->age_cdata.age_rx_tag, 27603b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_sparemap, 27613b22dc82SSepherosa Ziehau m, age_dmamap_buf_cb, &ctx, 27623b22dc82SSepherosa Ziehau BUS_DMA_NOWAIT); 27633b22dc82SSepherosa Ziehau if (error || ctx.nsegs == 0) { 27643b22dc82SSepherosa Ziehau if (!error) { 27653b22dc82SSepherosa Ziehau bus_dmamap_unload(sc->age_cdata.age_rx_tag, 27663b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_sparemap); 27673b22dc82SSepherosa Ziehau error = EFBIG; 27683b22dc82SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "too many segments?!\n"); 27693b22dc82SSepherosa Ziehau } 27703b22dc82SSepherosa Ziehau m_freem(m); 27713b22dc82SSepherosa Ziehau 27723b22dc82SSepherosa Ziehau if (init) 27733b22dc82SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "can't load RX mbuf\n"); 27743b22dc82SSepherosa Ziehau return (error); 27753b22dc82SSepherosa Ziehau } 27763b22dc82SSepherosa Ziehau KASSERT(ctx.nsegs == 1, 27773b22dc82SSepherosa Ziehau ("%s: %d segments returned!", __func__, ctx.nsegs)); 27783b22dc82SSepherosa Ziehau 27793b22dc82SSepherosa Ziehau if (rxd->rx_m != NULL) { 27803b22dc82SSepherosa Ziehau bus_dmamap_sync(sc->age_cdata.age_rx_tag, rxd->rx_dmamap, 27813b22dc82SSepherosa Ziehau BUS_DMASYNC_POSTREAD); 27823b22dc82SSepherosa Ziehau bus_dmamap_unload(sc->age_cdata.age_rx_tag, rxd->rx_dmamap); 27833b22dc82SSepherosa Ziehau } 27843b22dc82SSepherosa Ziehau map = rxd->rx_dmamap; 27853b22dc82SSepherosa Ziehau rxd->rx_dmamap = sc->age_cdata.age_rx_sparemap; 27863b22dc82SSepherosa Ziehau sc->age_cdata.age_rx_sparemap = map; 27873b22dc82SSepherosa Ziehau rxd->rx_m = m; 27883b22dc82SSepherosa Ziehau 27893b22dc82SSepherosa Ziehau desc = rxd->rx_desc; 27903b22dc82SSepherosa Ziehau desc->addr = htole64(segs[0].ds_addr); 27913b22dc82SSepherosa Ziehau desc->len = htole32((segs[0].ds_len & AGE_RD_LEN_MASK) << 27923b22dc82SSepherosa Ziehau AGE_RD_LEN_SHIFT); 27933b22dc82SSepherosa Ziehau return (0); 27943b22dc82SSepherosa Ziehau } 27953b22dc82SSepherosa Ziehau 27963b22dc82SSepherosa Ziehau static void 27973b22dc82SSepherosa Ziehau age_rxvlan(struct age_softc *sc) 27983b22dc82SSepherosa Ziehau { 27993b22dc82SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 28003b22dc82SSepherosa Ziehau uint32_t reg; 28013b22dc82SSepherosa Ziehau 28023b22dc82SSepherosa Ziehau reg = CSR_READ_4(sc, AGE_MAC_CFG); 28033b22dc82SSepherosa Ziehau reg &= ~MAC_CFG_VLAN_TAG_STRIP; 28043b22dc82SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 28053b22dc82SSepherosa Ziehau reg |= MAC_CFG_VLAN_TAG_STRIP; 28063b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MAC_CFG, reg); 28073b22dc82SSepherosa Ziehau } 28083b22dc82SSepherosa Ziehau 28093b22dc82SSepherosa Ziehau static void 28103b22dc82SSepherosa Ziehau age_rxfilter(struct age_softc *sc) 28113b22dc82SSepherosa Ziehau { 28123b22dc82SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 28133b22dc82SSepherosa Ziehau struct ifmultiaddr *ifma; 28143b22dc82SSepherosa Ziehau uint32_t crc; 28153b22dc82SSepherosa Ziehau uint32_t mchash[2]; 28163b22dc82SSepherosa Ziehau uint32_t rxcfg; 28173b22dc82SSepherosa Ziehau 28183b22dc82SSepherosa Ziehau rxcfg = CSR_READ_4(sc, AGE_MAC_CFG); 28193b22dc82SSepherosa Ziehau rxcfg &= ~(MAC_CFG_ALLMULTI | MAC_CFG_BCAST | MAC_CFG_PROMISC); 28203b22dc82SSepherosa Ziehau if ((ifp->if_flags & IFF_BROADCAST) != 0) 28213b22dc82SSepherosa Ziehau rxcfg |= MAC_CFG_BCAST; 28223b22dc82SSepherosa Ziehau if ((ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { 28233b22dc82SSepherosa Ziehau if ((ifp->if_flags & IFF_PROMISC) != 0) 28243b22dc82SSepherosa Ziehau rxcfg |= MAC_CFG_PROMISC; 28253b22dc82SSepherosa Ziehau if ((ifp->if_flags & IFF_ALLMULTI) != 0) 28263b22dc82SSepherosa Ziehau rxcfg |= MAC_CFG_ALLMULTI; 28273b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MAR0, 0xFFFFFFFF); 28283b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MAR1, 0xFFFFFFFF); 28293b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MAC_CFG, rxcfg); 28303b22dc82SSepherosa Ziehau return; 28313b22dc82SSepherosa Ziehau } 28323b22dc82SSepherosa Ziehau 28333b22dc82SSepherosa Ziehau /* Program new filter. */ 28343b22dc82SSepherosa Ziehau bzero(mchash, sizeof(mchash)); 28353b22dc82SSepherosa Ziehau 2836441d34b2SSascha Wildner TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 28373b22dc82SSepherosa Ziehau if (ifma->ifma_addr->sa_family != AF_LINK) 28383b22dc82SSepherosa Ziehau continue; 28393b22dc82SSepherosa Ziehau crc = ether_crc32_le(LLADDR((struct sockaddr_dl *) 28403b22dc82SSepherosa Ziehau ifma->ifma_addr), ETHER_ADDR_LEN); 28413b22dc82SSepherosa Ziehau mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); 28423b22dc82SSepherosa Ziehau } 28433b22dc82SSepherosa Ziehau 28443b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MAR0, mchash[0]); 28453b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MAR1, mchash[1]); 28463b22dc82SSepherosa Ziehau CSR_WRITE_4(sc, AGE_MAC_CFG, rxcfg); 28473b22dc82SSepherosa Ziehau } 28483b22dc82SSepherosa Ziehau 28493b22dc82SSepherosa Ziehau static int 28503b22dc82SSepherosa Ziehau sysctl_age_stats(SYSCTL_HANDLER_ARGS) 28513b22dc82SSepherosa Ziehau { 28523b22dc82SSepherosa Ziehau struct age_softc *sc; 28533b22dc82SSepherosa Ziehau struct age_stats *stats; 28543b22dc82SSepherosa Ziehau int error, result; 28553b22dc82SSepherosa Ziehau 28563b22dc82SSepherosa Ziehau result = -1; 28573b22dc82SSepherosa Ziehau error = sysctl_handle_int(oidp, &result, 0, req); 28583b22dc82SSepherosa Ziehau 28593b22dc82SSepherosa Ziehau if (error != 0 || req->newptr == NULL) 28603b22dc82SSepherosa Ziehau return (error); 28613b22dc82SSepherosa Ziehau 28623b22dc82SSepherosa Ziehau if (result != 1) 28633b22dc82SSepherosa Ziehau return (error); 28643b22dc82SSepherosa Ziehau 28653b22dc82SSepherosa Ziehau sc = (struct age_softc *)arg1; 28663b22dc82SSepherosa Ziehau stats = &sc->age_stat; 28673b22dc82SSepherosa Ziehau kprintf("%s statistics:\n", device_get_nameunit(sc->age_dev)); 28683b22dc82SSepherosa Ziehau kprintf("Transmit good frames : %ju\n", 28693b22dc82SSepherosa Ziehau (uintmax_t)stats->tx_frames); 28703b22dc82SSepherosa Ziehau kprintf("Transmit good broadcast frames : %ju\n", 28713b22dc82SSepherosa Ziehau (uintmax_t)stats->tx_bcast_frames); 28723b22dc82SSepherosa Ziehau kprintf("Transmit good multicast frames : %ju\n", 28733b22dc82SSepherosa Ziehau (uintmax_t)stats->tx_mcast_frames); 28743b22dc82SSepherosa Ziehau kprintf("Transmit pause control frames : %u\n", 28753b22dc82SSepherosa Ziehau stats->tx_pause_frames); 28763b22dc82SSepherosa Ziehau kprintf("Transmit control frames : %u\n", 28773b22dc82SSepherosa Ziehau stats->tx_control_frames); 28783b22dc82SSepherosa Ziehau kprintf("Transmit frames with excessive deferrals : %u\n", 28793b22dc82SSepherosa Ziehau stats->tx_excess_defer); 28803b22dc82SSepherosa Ziehau kprintf("Transmit deferrals : %u\n", 28813b22dc82SSepherosa Ziehau stats->tx_deferred); 28823b22dc82SSepherosa Ziehau kprintf("Transmit good octets : %ju\n", 28833b22dc82SSepherosa Ziehau (uintmax_t)stats->tx_bytes); 28843b22dc82SSepherosa Ziehau kprintf("Transmit good broadcast octets : %ju\n", 28853b22dc82SSepherosa Ziehau (uintmax_t)stats->tx_bcast_bytes); 28863b22dc82SSepherosa Ziehau kprintf("Transmit good multicast octets : %ju\n", 28873b22dc82SSepherosa Ziehau (uintmax_t)stats->tx_mcast_bytes); 28883b22dc82SSepherosa Ziehau kprintf("Transmit frames 64 bytes : %ju\n", 28893b22dc82SSepherosa Ziehau (uintmax_t)stats->tx_pkts_64); 28903b22dc82SSepherosa Ziehau kprintf("Transmit frames 65 to 127 bytes : %ju\n", 28913b22dc82SSepherosa Ziehau (uintmax_t)stats->tx_pkts_65_127); 28923b22dc82SSepherosa Ziehau kprintf("Transmit frames 128 to 255 bytes : %ju\n", 28933b22dc82SSepherosa Ziehau (uintmax_t)stats->tx_pkts_128_255); 28943b22dc82SSepherosa Ziehau kprintf("Transmit frames 256 to 511 bytes : %ju\n", 28953b22dc82SSepherosa Ziehau (uintmax_t)stats->tx_pkts_256_511); 28963b22dc82SSepherosa Ziehau kprintf("Transmit frames 512 to 1024 bytes : %ju\n", 28973b22dc82SSepherosa Ziehau (uintmax_t)stats->tx_pkts_512_1023); 28983b22dc82SSepherosa Ziehau kprintf("Transmit frames 1024 to 1518 bytes : %ju\n", 28993b22dc82SSepherosa Ziehau (uintmax_t)stats->tx_pkts_1024_1518); 29003b22dc82SSepherosa Ziehau kprintf("Transmit frames 1519 to MTU bytes : %ju\n", 29013b22dc82SSepherosa Ziehau (uintmax_t)stats->tx_pkts_1519_max); 29023b22dc82SSepherosa Ziehau kprintf("Transmit single collisions : %u\n", 29033b22dc82SSepherosa Ziehau stats->tx_single_colls); 29043b22dc82SSepherosa Ziehau kprintf("Transmit multiple collisions : %u\n", 29053b22dc82SSepherosa Ziehau stats->tx_multi_colls); 29063b22dc82SSepherosa Ziehau kprintf("Transmit late collisions : %u\n", 29073b22dc82SSepherosa Ziehau stats->tx_late_colls); 29083b22dc82SSepherosa Ziehau kprintf("Transmit abort due to excessive collisions : %u\n", 29093b22dc82SSepherosa Ziehau stats->tx_excess_colls); 29103b22dc82SSepherosa Ziehau kprintf("Transmit underruns due to FIFO underruns : %u\n", 29113b22dc82SSepherosa Ziehau stats->tx_underrun); 29123b22dc82SSepherosa Ziehau kprintf("Transmit descriptor write-back errors : %u\n", 29133b22dc82SSepherosa Ziehau stats->tx_desc_underrun); 29143b22dc82SSepherosa Ziehau kprintf("Transmit frames with length mismatched frame size : %u\n", 29153b22dc82SSepherosa Ziehau stats->tx_lenerrs); 29163b22dc82SSepherosa Ziehau kprintf("Transmit frames with truncated due to MTU size : %u\n", 29173b22dc82SSepherosa Ziehau stats->tx_lenerrs); 29183b22dc82SSepherosa Ziehau 29193b22dc82SSepherosa Ziehau kprintf("Receive good frames : %ju\n", 29203b22dc82SSepherosa Ziehau (uintmax_t)stats->rx_frames); 29213b22dc82SSepherosa Ziehau kprintf("Receive good broadcast frames : %ju\n", 29223b22dc82SSepherosa Ziehau (uintmax_t)stats->rx_bcast_frames); 29233b22dc82SSepherosa Ziehau kprintf("Receive good multicast frames : %ju\n", 29243b22dc82SSepherosa Ziehau (uintmax_t)stats->rx_mcast_frames); 29253b22dc82SSepherosa Ziehau kprintf("Receive pause control frames : %u\n", 29263b22dc82SSepherosa Ziehau stats->rx_pause_frames); 29273b22dc82SSepherosa Ziehau kprintf("Receive control frames : %u\n", 29283b22dc82SSepherosa Ziehau stats->rx_control_frames); 29293b22dc82SSepherosa Ziehau kprintf("Receive CRC errors : %u\n", 29303b22dc82SSepherosa Ziehau stats->rx_crcerrs); 29313b22dc82SSepherosa Ziehau kprintf("Receive frames with length errors : %u\n", 29323b22dc82SSepherosa Ziehau stats->rx_lenerrs); 29333b22dc82SSepherosa Ziehau kprintf("Receive good octets : %ju\n", 29343b22dc82SSepherosa Ziehau (uintmax_t)stats->rx_bytes); 29353b22dc82SSepherosa Ziehau kprintf("Receive good broadcast octets : %ju\n", 29363b22dc82SSepherosa Ziehau (uintmax_t)stats->rx_bcast_bytes); 29373b22dc82SSepherosa Ziehau kprintf("Receive good multicast octets : %ju\n", 29383b22dc82SSepherosa Ziehau (uintmax_t)stats->rx_mcast_bytes); 29393b22dc82SSepherosa Ziehau kprintf("Receive frames too short : %u\n", 29403b22dc82SSepherosa Ziehau stats->rx_runts); 29413b22dc82SSepherosa Ziehau kprintf("Receive fragmented frames : %ju\n", 29423b22dc82SSepherosa Ziehau (uintmax_t)stats->rx_fragments); 29433b22dc82SSepherosa Ziehau kprintf("Receive frames 64 bytes : %ju\n", 29443b22dc82SSepherosa Ziehau (uintmax_t)stats->rx_pkts_64); 29453b22dc82SSepherosa Ziehau kprintf("Receive frames 65 to 127 bytes : %ju\n", 29463b22dc82SSepherosa Ziehau (uintmax_t)stats->rx_pkts_65_127); 29473b22dc82SSepherosa Ziehau kprintf("Receive frames 128 to 255 bytes : %ju\n", 29483b22dc82SSepherosa Ziehau (uintmax_t)stats->rx_pkts_128_255); 29493b22dc82SSepherosa Ziehau kprintf("Receive frames 256 to 511 bytes : %ju\n", 29503b22dc82SSepherosa Ziehau (uintmax_t)stats->rx_pkts_256_511); 29513b22dc82SSepherosa Ziehau kprintf("Receive frames 512 to 1024 bytes : %ju\n", 29523b22dc82SSepherosa Ziehau (uintmax_t)stats->rx_pkts_512_1023); 29533b22dc82SSepherosa Ziehau kprintf("Receive frames 1024 to 1518 bytes : %ju\n", 29543b22dc82SSepherosa Ziehau (uintmax_t)stats->rx_pkts_1024_1518); 29553b22dc82SSepherosa Ziehau kprintf("Receive frames 1519 to MTU bytes : %ju\n", 29563b22dc82SSepherosa Ziehau (uintmax_t)stats->rx_pkts_1519_max); 29573b22dc82SSepherosa Ziehau kprintf("Receive frames too long : %ju\n", 29583b22dc82SSepherosa Ziehau (uint64_t)stats->rx_pkts_truncated); 29593b22dc82SSepherosa Ziehau kprintf("Receive frames with FIFO overflow : %u\n", 29603b22dc82SSepherosa Ziehau stats->rx_fifo_oflows); 29613b22dc82SSepherosa Ziehau kprintf("Receive frames with return descriptor overflow : %u\n", 29623b22dc82SSepherosa Ziehau stats->rx_desc_oflows); 29633b22dc82SSepherosa Ziehau kprintf("Receive frames with alignment errors : %u\n", 29643b22dc82SSepherosa Ziehau stats->rx_alignerrs); 29653b22dc82SSepherosa Ziehau kprintf("Receive frames dropped due to address filtering : %ju\n", 29663b22dc82SSepherosa Ziehau (uint64_t)stats->rx_pkts_filtered); 29673b22dc82SSepherosa Ziehau 29683b22dc82SSepherosa Ziehau return (error); 29693b22dc82SSepherosa Ziehau } 29703b22dc82SSepherosa Ziehau 29713b22dc82SSepherosa Ziehau static int 29723b22dc82SSepherosa Ziehau sysctl_hw_age_int_mod(SYSCTL_HANDLER_ARGS) 29733b22dc82SSepherosa Ziehau { 29743b22dc82SSepherosa Ziehau 29753b22dc82SSepherosa Ziehau return (sysctl_int_range(oidp, arg1, arg2, req, AGE_IM_TIMER_MIN, 29763b22dc82SSepherosa Ziehau AGE_IM_TIMER_MAX)); 29773b22dc82SSepherosa Ziehau } 29783b22dc82SSepherosa Ziehau 29793b22dc82SSepherosa Ziehau static void 29803b22dc82SSepherosa Ziehau age_dmamap_buf_cb(void *xctx, bus_dma_segment_t *segs, int nsegs, 29813b22dc82SSepherosa Ziehau bus_size_t mapsz __unused, int error) 29823b22dc82SSepherosa Ziehau { 29833b22dc82SSepherosa Ziehau struct age_dmamap_ctx *ctx = xctx; 29843b22dc82SSepherosa Ziehau int i; 29853b22dc82SSepherosa Ziehau 29863b22dc82SSepherosa Ziehau if (error) 29873b22dc82SSepherosa Ziehau return; 29883b22dc82SSepherosa Ziehau 29893b22dc82SSepherosa Ziehau if (nsegs > ctx->nsegs) { 29903b22dc82SSepherosa Ziehau ctx->nsegs = 0; 29913b22dc82SSepherosa Ziehau return; 29923b22dc82SSepherosa Ziehau } 29933b22dc82SSepherosa Ziehau 29943b22dc82SSepherosa Ziehau ctx->nsegs = nsegs; 29953b22dc82SSepherosa Ziehau for (i = 0; i < nsegs; ++i) 29963b22dc82SSepherosa Ziehau ctx->segs[i] = segs[i]; 29973b22dc82SSepherosa Ziehau } 2998