199fe2010SSepherosa Ziehau /*- 299fe2010SSepherosa Ziehau * Copyright (c) 2008, Pyun YongHyeon <yongari@FreeBSD.org> 399fe2010SSepherosa Ziehau * All rights reserved. 499fe2010SSepherosa Ziehau * 599fe2010SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 699fe2010SSepherosa Ziehau * modification, are permitted provided that the following conditions 799fe2010SSepherosa Ziehau * are met: 899fe2010SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 999fe2010SSepherosa Ziehau * notice unmodified, this list of conditions, and the following 1099fe2010SSepherosa Ziehau * disclaimer. 1199fe2010SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 1299fe2010SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 1399fe2010SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 1499fe2010SSepherosa Ziehau * 1599fe2010SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1699fe2010SSepherosa Ziehau * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1799fe2010SSepherosa Ziehau * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1899fe2010SSepherosa Ziehau * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1999fe2010SSepherosa Ziehau * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2099fe2010SSepherosa Ziehau * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2199fe2010SSepherosa Ziehau * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2299fe2010SSepherosa Ziehau * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2399fe2010SSepherosa Ziehau * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2499fe2010SSepherosa Ziehau * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2599fe2010SSepherosa Ziehau * SUCH DAMAGE. 2699fe2010SSepherosa Ziehau * 2799fe2010SSepherosa Ziehau * $FreeBSD: src/sys/dev/ale/if_ale.c,v 1.3 2008/12/03 09:01:12 yongari Exp $ 2899fe2010SSepherosa Ziehau */ 2999fe2010SSepherosa Ziehau 3099fe2010SSepherosa Ziehau /* Driver for Atheros AR8121/AR8113/AR8114 PCIe Ethernet. */ 3199fe2010SSepherosa Ziehau 3299fe2010SSepherosa Ziehau #include <sys/param.h> 3399fe2010SSepherosa Ziehau #include <sys/endian.h> 3499fe2010SSepherosa Ziehau #include <sys/kernel.h> 3599fe2010SSepherosa Ziehau #include <sys/bus.h> 3699fe2010SSepherosa Ziehau #include <sys/interrupt.h> 3799fe2010SSepherosa Ziehau #include <sys/malloc.h> 3899fe2010SSepherosa Ziehau #include <sys/proc.h> 3999fe2010SSepherosa Ziehau #include <sys/rman.h> 4099fe2010SSepherosa Ziehau #include <sys/serialize.h> 4199fe2010SSepherosa Ziehau #include <sys/socket.h> 4299fe2010SSepherosa Ziehau #include <sys/sockio.h> 4399fe2010SSepherosa Ziehau #include <sys/sysctl.h> 4499fe2010SSepherosa Ziehau 4599fe2010SSepherosa Ziehau #include <net/ethernet.h> 4699fe2010SSepherosa Ziehau #include <net/if.h> 4799fe2010SSepherosa Ziehau #include <net/bpf.h> 4899fe2010SSepherosa Ziehau #include <net/if_arp.h> 4999fe2010SSepherosa Ziehau #include <net/if_dl.h> 5099fe2010SSepherosa Ziehau #include <net/if_llc.h> 5199fe2010SSepherosa Ziehau #include <net/if_media.h> 5299fe2010SSepherosa Ziehau #include <net/ifq_var.h> 5399fe2010SSepherosa Ziehau #include <net/vlan/if_vlan_var.h> 5499fe2010SSepherosa Ziehau #include <net/vlan/if_vlan_ether.h> 5599fe2010SSepherosa Ziehau 5699fe2010SSepherosa Ziehau #include <netinet/ip.h> 5799fe2010SSepherosa Ziehau 58e3326a9aSSepherosa Ziehau #include <dev/netif/mii_layer/mii.h> 5999fe2010SSepherosa Ziehau #include <dev/netif/mii_layer/miivar.h> 6099fe2010SSepherosa Ziehau 6199fe2010SSepherosa Ziehau #include <bus/pci/pcireg.h> 6299fe2010SSepherosa Ziehau #include <bus/pci/pcivar.h> 6399fe2010SSepherosa Ziehau #include <bus/pci/pcidevs.h> 6499fe2010SSepherosa Ziehau 6599fe2010SSepherosa Ziehau #include <dev/netif/ale/if_alereg.h> 6699fe2010SSepherosa Ziehau #include <dev/netif/ale/if_alevar.h> 6799fe2010SSepherosa Ziehau 6899fe2010SSepherosa Ziehau /* "device miibus" required. See GENERIC if you get errors here. */ 6999fe2010SSepherosa Ziehau #include "miibus_if.h" 7099fe2010SSepherosa Ziehau 7199fe2010SSepherosa Ziehau /* For more information about Tx checksum offload issues see ale_encap(). */ 7299fe2010SSepherosa Ziehau #define ALE_CSUM_FEATURES (CSUM_TCP | CSUM_UDP) 7399fe2010SSepherosa Ziehau 7499fe2010SSepherosa Ziehau struct ale_dmamap_ctx { 7599fe2010SSepherosa Ziehau int nsegs; 7699fe2010SSepherosa Ziehau bus_dma_segment_t *segs; 7799fe2010SSepherosa Ziehau }; 7899fe2010SSepherosa Ziehau 7999fe2010SSepherosa Ziehau static int ale_probe(device_t); 8099fe2010SSepherosa Ziehau static int ale_attach(device_t); 8199fe2010SSepherosa Ziehau static int ale_detach(device_t); 8299fe2010SSepherosa Ziehau static int ale_shutdown(device_t); 8399fe2010SSepherosa Ziehau static int ale_suspend(device_t); 8499fe2010SSepherosa Ziehau static int ale_resume(device_t); 8599fe2010SSepherosa Ziehau 8699fe2010SSepherosa Ziehau static int ale_miibus_readreg(device_t, int, int); 8799fe2010SSepherosa Ziehau static int ale_miibus_writereg(device_t, int, int, int); 8899fe2010SSepherosa Ziehau static void ale_miibus_statchg(device_t); 8999fe2010SSepherosa Ziehau 9099fe2010SSepherosa Ziehau static void ale_init(void *); 9199fe2010SSepherosa Ziehau static void ale_start(struct ifnet *); 9299fe2010SSepherosa Ziehau static int ale_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *); 9399fe2010SSepherosa Ziehau static void ale_watchdog(struct ifnet *); 9499fe2010SSepherosa Ziehau static int ale_mediachange(struct ifnet *); 9599fe2010SSepherosa Ziehau static void ale_mediastatus(struct ifnet *, struct ifmediareq *); 9699fe2010SSepherosa Ziehau 9799fe2010SSepherosa Ziehau static void ale_intr(void *); 9899fe2010SSepherosa Ziehau static int ale_rxeof(struct ale_softc *sc); 9999fe2010SSepherosa Ziehau static void ale_rx_update_page(struct ale_softc *, struct ale_rx_page **, 10099fe2010SSepherosa Ziehau uint32_t, uint32_t *); 10199fe2010SSepherosa Ziehau static void ale_rxcsum(struct ale_softc *, struct mbuf *, uint32_t); 10299fe2010SSepherosa Ziehau static void ale_txeof(struct ale_softc *); 10399fe2010SSepherosa Ziehau 10499fe2010SSepherosa Ziehau static int ale_dma_alloc(struct ale_softc *); 10599fe2010SSepherosa Ziehau static void ale_dma_free(struct ale_softc *); 10699fe2010SSepherosa Ziehau static int ale_check_boundary(struct ale_softc *); 10799fe2010SSepherosa Ziehau static void ale_dmamap_cb(void *, bus_dma_segment_t *, int, int); 10899fe2010SSepherosa Ziehau static void ale_dmamap_buf_cb(void *, bus_dma_segment_t *, int, 10999fe2010SSepherosa Ziehau bus_size_t, int); 11099fe2010SSepherosa Ziehau static int ale_encap(struct ale_softc *, struct mbuf **); 11199fe2010SSepherosa Ziehau static void ale_init_rx_pages(struct ale_softc *); 11299fe2010SSepherosa Ziehau static void ale_init_tx_ring(struct ale_softc *); 11399fe2010SSepherosa Ziehau 11499fe2010SSepherosa Ziehau static void ale_stop(struct ale_softc *); 11599fe2010SSepherosa Ziehau static void ale_tick(void *); 11699fe2010SSepherosa Ziehau static void ale_get_macaddr(struct ale_softc *); 11799fe2010SSepherosa Ziehau static void ale_mac_config(struct ale_softc *); 11899fe2010SSepherosa Ziehau static void ale_phy_reset(struct ale_softc *); 11999fe2010SSepherosa Ziehau static void ale_reset(struct ale_softc *); 12099fe2010SSepherosa Ziehau static void ale_rxfilter(struct ale_softc *); 12199fe2010SSepherosa Ziehau static void ale_rxvlan(struct ale_softc *); 12299fe2010SSepherosa Ziehau static void ale_stats_clear(struct ale_softc *); 12399fe2010SSepherosa Ziehau static void ale_stats_update(struct ale_softc *); 12499fe2010SSepherosa Ziehau static void ale_stop_mac(struct ale_softc *); 12599fe2010SSepherosa Ziehau #ifdef notyet 12699fe2010SSepherosa Ziehau static void ale_setlinkspeed(struct ale_softc *); 12799fe2010SSepherosa Ziehau static void ale_setwol(struct ale_softc *); 12899fe2010SSepherosa Ziehau #endif 12999fe2010SSepherosa Ziehau 13099fe2010SSepherosa Ziehau static void ale_sysctl_node(struct ale_softc *); 13199fe2010SSepherosa Ziehau static int sysctl_hw_ale_int_mod(SYSCTL_HANDLER_ARGS); 13299fe2010SSepherosa Ziehau 13399fe2010SSepherosa Ziehau /* 13499fe2010SSepherosa Ziehau * Devices supported by this driver. 13599fe2010SSepherosa Ziehau */ 13699fe2010SSepherosa Ziehau static struct ale_dev { 13799fe2010SSepherosa Ziehau uint16_t ale_vendorid; 13899fe2010SSepherosa Ziehau uint16_t ale_deviceid; 13999fe2010SSepherosa Ziehau const char *ale_name; 14099fe2010SSepherosa Ziehau } ale_devs[] = { 14199fe2010SSepherosa Ziehau { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR81XX, 14299fe2010SSepherosa Ziehau "Atheros AR8121/AR8113/AR8114 PCIe Ethernet" }, 14399fe2010SSepherosa Ziehau }; 14499fe2010SSepherosa Ziehau 14599fe2010SSepherosa Ziehau static device_method_t ale_methods[] = { 14699fe2010SSepherosa Ziehau /* Device interface. */ 14799fe2010SSepherosa Ziehau DEVMETHOD(device_probe, ale_probe), 14899fe2010SSepherosa Ziehau DEVMETHOD(device_attach, ale_attach), 14999fe2010SSepherosa Ziehau DEVMETHOD(device_detach, ale_detach), 15099fe2010SSepherosa Ziehau DEVMETHOD(device_shutdown, ale_shutdown), 15199fe2010SSepherosa Ziehau DEVMETHOD(device_suspend, ale_suspend), 15299fe2010SSepherosa Ziehau DEVMETHOD(device_resume, ale_resume), 15399fe2010SSepherosa Ziehau 15499fe2010SSepherosa Ziehau /* Bus interface. */ 15599fe2010SSepherosa Ziehau DEVMETHOD(bus_print_child, bus_generic_print_child), 15699fe2010SSepherosa Ziehau DEVMETHOD(bus_driver_added, bus_generic_driver_added), 15799fe2010SSepherosa Ziehau 15899fe2010SSepherosa Ziehau /* MII interface. */ 15999fe2010SSepherosa Ziehau DEVMETHOD(miibus_readreg, ale_miibus_readreg), 16099fe2010SSepherosa Ziehau DEVMETHOD(miibus_writereg, ale_miibus_writereg), 16199fe2010SSepherosa Ziehau DEVMETHOD(miibus_statchg, ale_miibus_statchg), 16299fe2010SSepherosa Ziehau 16399fe2010SSepherosa Ziehau { NULL, NULL } 16499fe2010SSepherosa Ziehau }; 16599fe2010SSepherosa Ziehau 16699fe2010SSepherosa Ziehau static driver_t ale_driver = { 16799fe2010SSepherosa Ziehau "ale", 16899fe2010SSepherosa Ziehau ale_methods, 16999fe2010SSepherosa Ziehau sizeof(struct ale_softc) 17099fe2010SSepherosa Ziehau }; 17199fe2010SSepherosa Ziehau 17299fe2010SSepherosa Ziehau static devclass_t ale_devclass; 17399fe2010SSepherosa Ziehau 17499fe2010SSepherosa Ziehau DECLARE_DUMMY_MODULE(if_ale); 17566549cf3SMatthew Dillon MODULE_VERSION(if_ale, 1); 17699fe2010SSepherosa Ziehau MODULE_DEPEND(if_ale, miibus, 1, 1, 1); 177aa2b9d05SSascha Wildner DRIVER_MODULE(if_ale, pci, ale_driver, ale_devclass, NULL, NULL); 178aa2b9d05SSascha Wildner DRIVER_MODULE(miibus, ale, miibus_driver, miibus_devclass, NULL, NULL); 17999fe2010SSepherosa Ziehau 18099fe2010SSepherosa Ziehau static int 18199fe2010SSepherosa Ziehau ale_miibus_readreg(device_t dev, int phy, int reg) 18299fe2010SSepherosa Ziehau { 18399fe2010SSepherosa Ziehau struct ale_softc *sc; 18499fe2010SSepherosa Ziehau uint32_t v; 18599fe2010SSepherosa Ziehau int i; 18699fe2010SSepherosa Ziehau 18799fe2010SSepherosa Ziehau sc = device_get_softc(dev); 18899fe2010SSepherosa Ziehau 18999fe2010SSepherosa Ziehau if (phy != sc->ale_phyaddr) 19099fe2010SSepherosa Ziehau return (0); 19199fe2010SSepherosa Ziehau 192e3326a9aSSepherosa Ziehau if (sc->ale_flags & ALE_FLAG_FASTETHER) { 193e3326a9aSSepherosa Ziehau if (reg == MII_100T2CR || reg == MII_100T2SR || 194e3326a9aSSepherosa Ziehau reg == MII_EXTSR) 195e3326a9aSSepherosa Ziehau return (0); 196e3326a9aSSepherosa Ziehau } 197e3326a9aSSepherosa Ziehau 19899fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_MDIO, MDIO_OP_EXECUTE | MDIO_OP_READ | 19999fe2010SSepherosa Ziehau MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg)); 20099fe2010SSepherosa Ziehau for (i = ALE_PHY_TIMEOUT; i > 0; i--) { 20199fe2010SSepherosa Ziehau DELAY(5); 20299fe2010SSepherosa Ziehau v = CSR_READ_4(sc, ALE_MDIO); 20399fe2010SSepherosa Ziehau if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0) 20499fe2010SSepherosa Ziehau break; 20599fe2010SSepherosa Ziehau } 20699fe2010SSepherosa Ziehau 20799fe2010SSepherosa Ziehau if (i == 0) { 20899fe2010SSepherosa Ziehau device_printf(sc->ale_dev, "phy read timeout : %d\n", reg); 20999fe2010SSepherosa Ziehau return (0); 21099fe2010SSepherosa Ziehau } 21199fe2010SSepherosa Ziehau 21299fe2010SSepherosa Ziehau return ((v & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT); 21399fe2010SSepherosa Ziehau } 21499fe2010SSepherosa Ziehau 21599fe2010SSepherosa Ziehau static int 21699fe2010SSepherosa Ziehau ale_miibus_writereg(device_t dev, int phy, int reg, int val) 21799fe2010SSepherosa Ziehau { 21899fe2010SSepherosa Ziehau struct ale_softc *sc; 21999fe2010SSepherosa Ziehau uint32_t v; 22099fe2010SSepherosa Ziehau int i; 22199fe2010SSepherosa Ziehau 22299fe2010SSepherosa Ziehau sc = device_get_softc(dev); 22399fe2010SSepherosa Ziehau 22499fe2010SSepherosa Ziehau if (phy != sc->ale_phyaddr) 22599fe2010SSepherosa Ziehau return (0); 22699fe2010SSepherosa Ziehau 227e3326a9aSSepherosa Ziehau if (sc->ale_flags & ALE_FLAG_FASTETHER) { 228e3326a9aSSepherosa Ziehau if (reg == MII_100T2CR || reg == MII_100T2SR || 229e3326a9aSSepherosa Ziehau reg == MII_EXTSR) 230e3326a9aSSepherosa Ziehau return (0); 231e3326a9aSSepherosa Ziehau } 232e3326a9aSSepherosa Ziehau 23399fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE | 23499fe2010SSepherosa Ziehau (val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT | 23599fe2010SSepherosa Ziehau MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg)); 23699fe2010SSepherosa Ziehau for (i = ALE_PHY_TIMEOUT; i > 0; i--) { 23799fe2010SSepherosa Ziehau DELAY(5); 23899fe2010SSepherosa Ziehau v = CSR_READ_4(sc, ALE_MDIO); 23999fe2010SSepherosa Ziehau if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0) 24099fe2010SSepherosa Ziehau break; 24199fe2010SSepherosa Ziehau } 24299fe2010SSepherosa Ziehau 24399fe2010SSepherosa Ziehau if (i == 0) 24499fe2010SSepherosa Ziehau device_printf(sc->ale_dev, "phy write timeout : %d\n", reg); 24599fe2010SSepherosa Ziehau 24699fe2010SSepherosa Ziehau return (0); 24799fe2010SSepherosa Ziehau } 24899fe2010SSepherosa Ziehau 24999fe2010SSepherosa Ziehau static void 25099fe2010SSepherosa Ziehau ale_miibus_statchg(device_t dev) 25199fe2010SSepherosa Ziehau { 25299fe2010SSepherosa Ziehau struct ale_softc *sc = device_get_softc(dev); 25399fe2010SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 25499fe2010SSepherosa Ziehau struct mii_data *mii; 25599fe2010SSepherosa Ziehau uint32_t reg; 25699fe2010SSepherosa Ziehau 25799fe2010SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 25899fe2010SSepherosa Ziehau 25999fe2010SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0) 26099fe2010SSepherosa Ziehau return; 26199fe2010SSepherosa Ziehau 26299fe2010SSepherosa Ziehau mii = device_get_softc(sc->ale_miibus); 26399fe2010SSepherosa Ziehau 26499fe2010SSepherosa Ziehau sc->ale_flags &= ~ALE_FLAG_LINK; 26599fe2010SSepherosa Ziehau if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 26699fe2010SSepherosa Ziehau (IFM_ACTIVE | IFM_AVALID)) { 26799fe2010SSepherosa Ziehau switch (IFM_SUBTYPE(mii->mii_media_active)) { 26899fe2010SSepherosa Ziehau case IFM_10_T: 26999fe2010SSepherosa Ziehau case IFM_100_TX: 27099fe2010SSepherosa Ziehau sc->ale_flags |= ALE_FLAG_LINK; 27199fe2010SSepherosa Ziehau break; 27299fe2010SSepherosa Ziehau 27399fe2010SSepherosa Ziehau case IFM_1000_T: 27499fe2010SSepherosa Ziehau if ((sc->ale_flags & ALE_FLAG_FASTETHER) == 0) 27599fe2010SSepherosa Ziehau sc->ale_flags |= ALE_FLAG_LINK; 27699fe2010SSepherosa Ziehau break; 27799fe2010SSepherosa Ziehau 27899fe2010SSepherosa Ziehau default: 27999fe2010SSepherosa Ziehau break; 28099fe2010SSepherosa Ziehau } 28199fe2010SSepherosa Ziehau } 28299fe2010SSepherosa Ziehau 28399fe2010SSepherosa Ziehau /* Stop Rx/Tx MACs. */ 28499fe2010SSepherosa Ziehau ale_stop_mac(sc); 28599fe2010SSepherosa Ziehau 28699fe2010SSepherosa Ziehau /* Program MACs with resolved speed/duplex/flow-control. */ 28799fe2010SSepherosa Ziehau if ((sc->ale_flags & ALE_FLAG_LINK) != 0) { 28899fe2010SSepherosa Ziehau ale_mac_config(sc); 28999fe2010SSepherosa Ziehau /* Reenable Tx/Rx MACs. */ 29099fe2010SSepherosa Ziehau reg = CSR_READ_4(sc, ALE_MAC_CFG); 29199fe2010SSepherosa Ziehau reg |= MAC_CFG_TX_ENB | MAC_CFG_RX_ENB; 29299fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_MAC_CFG, reg); 29399fe2010SSepherosa Ziehau } 29499fe2010SSepherosa Ziehau } 29599fe2010SSepherosa Ziehau 29699fe2010SSepherosa Ziehau static void 29799fe2010SSepherosa Ziehau ale_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 29899fe2010SSepherosa Ziehau { 29999fe2010SSepherosa Ziehau struct ale_softc *sc = ifp->if_softc; 30099fe2010SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->ale_miibus); 30199fe2010SSepherosa Ziehau 30299fe2010SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 30399fe2010SSepherosa Ziehau 30499fe2010SSepherosa Ziehau mii_pollstat(mii); 30599fe2010SSepherosa Ziehau ifmr->ifm_status = mii->mii_media_status; 30699fe2010SSepherosa Ziehau ifmr->ifm_active = mii->mii_media_active; 30799fe2010SSepherosa Ziehau } 30899fe2010SSepherosa Ziehau 30999fe2010SSepherosa Ziehau static int 31099fe2010SSepherosa Ziehau ale_mediachange(struct ifnet *ifp) 31199fe2010SSepherosa Ziehau { 31299fe2010SSepherosa Ziehau struct ale_softc *sc = ifp->if_softc; 31399fe2010SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->ale_miibus); 31499fe2010SSepherosa Ziehau int error; 31599fe2010SSepherosa Ziehau 31699fe2010SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 31799fe2010SSepherosa Ziehau 31899fe2010SSepherosa Ziehau if (mii->mii_instance != 0) { 31999fe2010SSepherosa Ziehau struct mii_softc *miisc; 32099fe2010SSepherosa Ziehau 32199fe2010SSepherosa Ziehau LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 32299fe2010SSepherosa Ziehau mii_phy_reset(miisc); 32399fe2010SSepherosa Ziehau } 32499fe2010SSepherosa Ziehau error = mii_mediachg(mii); 32599fe2010SSepherosa Ziehau 32699fe2010SSepherosa Ziehau return (error); 32799fe2010SSepherosa Ziehau } 32899fe2010SSepherosa Ziehau 32999fe2010SSepherosa Ziehau static int 33099fe2010SSepherosa Ziehau ale_probe(device_t dev) 33199fe2010SSepherosa Ziehau { 33299fe2010SSepherosa Ziehau struct ale_dev *sp; 33399fe2010SSepherosa Ziehau int i; 33499fe2010SSepherosa Ziehau uint16_t vendor, devid; 33599fe2010SSepherosa Ziehau 33699fe2010SSepherosa Ziehau vendor = pci_get_vendor(dev); 33799fe2010SSepherosa Ziehau devid = pci_get_device(dev); 33899fe2010SSepherosa Ziehau sp = ale_devs; 339c157ff7aSSascha Wildner for (i = 0; i < NELEM(ale_devs); i++) { 34099fe2010SSepherosa Ziehau if (vendor == sp->ale_vendorid && 34199fe2010SSepherosa Ziehau devid == sp->ale_deviceid) { 34299fe2010SSepherosa Ziehau device_set_desc(dev, sp->ale_name); 34399fe2010SSepherosa Ziehau return (0); 34499fe2010SSepherosa Ziehau } 34599fe2010SSepherosa Ziehau sp++; 34699fe2010SSepherosa Ziehau } 34799fe2010SSepherosa Ziehau 34899fe2010SSepherosa Ziehau return (ENXIO); 34999fe2010SSepherosa Ziehau } 35099fe2010SSepherosa Ziehau 35199fe2010SSepherosa Ziehau static void 35299fe2010SSepherosa Ziehau ale_get_macaddr(struct ale_softc *sc) 35399fe2010SSepherosa Ziehau { 35499fe2010SSepherosa Ziehau uint32_t ea[2], reg; 35599fe2010SSepherosa Ziehau int i, vpdc; 35699fe2010SSepherosa Ziehau 35799fe2010SSepherosa Ziehau reg = CSR_READ_4(sc, ALE_SPI_CTRL); 35899fe2010SSepherosa Ziehau if ((reg & SPI_VPD_ENB) != 0) { 35999fe2010SSepherosa Ziehau reg &= ~SPI_VPD_ENB; 36099fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_SPI_CTRL, reg); 36199fe2010SSepherosa Ziehau } 36299fe2010SSepherosa Ziehau 36399fe2010SSepherosa Ziehau vpdc = pci_get_vpdcap_ptr(sc->ale_dev); 36499fe2010SSepherosa Ziehau if (vpdc) { 36599fe2010SSepherosa Ziehau /* 36699fe2010SSepherosa Ziehau * PCI VPD capability found, let TWSI reload EEPROM. 36799fe2010SSepherosa Ziehau * This will set ethernet address of controller. 36899fe2010SSepherosa Ziehau */ 36999fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_TWSI_CTRL, CSR_READ_4(sc, ALE_TWSI_CTRL) | 37099fe2010SSepherosa Ziehau TWSI_CTRL_SW_LD_START); 37199fe2010SSepherosa Ziehau for (i = 100; i > 0; i--) { 37299fe2010SSepherosa Ziehau DELAY(1000); 37399fe2010SSepherosa Ziehau reg = CSR_READ_4(sc, ALE_TWSI_CTRL); 37499fe2010SSepherosa Ziehau if ((reg & TWSI_CTRL_SW_LD_START) == 0) 37599fe2010SSepherosa Ziehau break; 37699fe2010SSepherosa Ziehau } 37799fe2010SSepherosa Ziehau if (i == 0) 37899fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 37999fe2010SSepherosa Ziehau "reloading EEPROM timeout!\n"); 38099fe2010SSepherosa Ziehau } else { 38199fe2010SSepherosa Ziehau if (bootverbose) 38299fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 38399fe2010SSepherosa Ziehau "PCI VPD capability not found!\n"); 38499fe2010SSepherosa Ziehau } 38599fe2010SSepherosa Ziehau 38699fe2010SSepherosa Ziehau ea[0] = CSR_READ_4(sc, ALE_PAR0); 38799fe2010SSepherosa Ziehau ea[1] = CSR_READ_4(sc, ALE_PAR1); 38899fe2010SSepherosa Ziehau sc->ale_eaddr[0] = (ea[1] >> 8) & 0xFF; 38999fe2010SSepherosa Ziehau sc->ale_eaddr[1] = (ea[1] >> 0) & 0xFF; 39099fe2010SSepherosa Ziehau sc->ale_eaddr[2] = (ea[0] >> 24) & 0xFF; 39199fe2010SSepherosa Ziehau sc->ale_eaddr[3] = (ea[0] >> 16) & 0xFF; 39299fe2010SSepherosa Ziehau sc->ale_eaddr[4] = (ea[0] >> 8) & 0xFF; 39399fe2010SSepherosa Ziehau sc->ale_eaddr[5] = (ea[0] >> 0) & 0xFF; 39499fe2010SSepherosa Ziehau } 39599fe2010SSepherosa Ziehau 39699fe2010SSepherosa Ziehau static void 39799fe2010SSepherosa Ziehau ale_phy_reset(struct ale_softc *sc) 39899fe2010SSepherosa Ziehau { 39999fe2010SSepherosa Ziehau /* Reset magic from Linux. */ 40099fe2010SSepherosa Ziehau CSR_WRITE_2(sc, ALE_GPHY_CTRL, 40199fe2010SSepherosa Ziehau GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE | GPHY_CTRL_SEL_ANA_RESET | 40299fe2010SSepherosa Ziehau GPHY_CTRL_PHY_PLL_ON); 40399fe2010SSepherosa Ziehau DELAY(1000); 40499fe2010SSepherosa Ziehau CSR_WRITE_2(sc, ALE_GPHY_CTRL, 40599fe2010SSepherosa Ziehau GPHY_CTRL_EXT_RESET | GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE | 40699fe2010SSepherosa Ziehau GPHY_CTRL_SEL_ANA_RESET | GPHY_CTRL_PHY_PLL_ON); 40799fe2010SSepherosa Ziehau DELAY(1000); 40899fe2010SSepherosa Ziehau 40999fe2010SSepherosa Ziehau #define ATPHY_DBG_ADDR 0x1D 41099fe2010SSepherosa Ziehau #define ATPHY_DBG_DATA 0x1E 41199fe2010SSepherosa Ziehau 41299fe2010SSepherosa Ziehau /* Enable hibernation mode. */ 41399fe2010SSepherosa Ziehau ale_miibus_writereg(sc->ale_dev, sc->ale_phyaddr, 41499fe2010SSepherosa Ziehau ATPHY_DBG_ADDR, 0x0B); 41599fe2010SSepherosa Ziehau ale_miibus_writereg(sc->ale_dev, sc->ale_phyaddr, 41699fe2010SSepherosa Ziehau ATPHY_DBG_DATA, 0xBC00); 41799fe2010SSepherosa Ziehau /* Set Class A/B for all modes. */ 41899fe2010SSepherosa Ziehau ale_miibus_writereg(sc->ale_dev, sc->ale_phyaddr, 41999fe2010SSepherosa Ziehau ATPHY_DBG_ADDR, 0x00); 42099fe2010SSepherosa Ziehau ale_miibus_writereg(sc->ale_dev, sc->ale_phyaddr, 42199fe2010SSepherosa Ziehau ATPHY_DBG_DATA, 0x02EF); 42299fe2010SSepherosa Ziehau /* Enable 10BT power saving. */ 42399fe2010SSepherosa Ziehau ale_miibus_writereg(sc->ale_dev, sc->ale_phyaddr, 42499fe2010SSepherosa Ziehau ATPHY_DBG_ADDR, 0x12); 42599fe2010SSepherosa Ziehau ale_miibus_writereg(sc->ale_dev, sc->ale_phyaddr, 42699fe2010SSepherosa Ziehau ATPHY_DBG_DATA, 0x4C04); 42799fe2010SSepherosa Ziehau /* Adjust 1000T power. */ 42899fe2010SSepherosa Ziehau ale_miibus_writereg(sc->ale_dev, sc->ale_phyaddr, 42999fe2010SSepherosa Ziehau ATPHY_DBG_ADDR, 0x04); 43099fe2010SSepherosa Ziehau ale_miibus_writereg(sc->ale_dev, sc->ale_phyaddr, 43199fe2010SSepherosa Ziehau ATPHY_DBG_ADDR, 0x8BBB); 43299fe2010SSepherosa Ziehau /* 10BT center tap voltage. */ 43399fe2010SSepherosa Ziehau ale_miibus_writereg(sc->ale_dev, sc->ale_phyaddr, 43499fe2010SSepherosa Ziehau ATPHY_DBG_ADDR, 0x05); 43599fe2010SSepherosa Ziehau ale_miibus_writereg(sc->ale_dev, sc->ale_phyaddr, 43699fe2010SSepherosa Ziehau ATPHY_DBG_ADDR, 0x2C46); 43799fe2010SSepherosa Ziehau 43899fe2010SSepherosa Ziehau #undef ATPHY_DBG_ADDR 43999fe2010SSepherosa Ziehau #undef ATPHY_DBG_DATA 44099fe2010SSepherosa Ziehau DELAY(1000); 44199fe2010SSepherosa Ziehau } 44299fe2010SSepherosa Ziehau 44399fe2010SSepherosa Ziehau static int 44499fe2010SSepherosa Ziehau ale_attach(device_t dev) 44599fe2010SSepherosa Ziehau { 44699fe2010SSepherosa Ziehau struct ale_softc *sc = device_get_softc(dev); 44799fe2010SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 44899fe2010SSepherosa Ziehau int error = 0; 44999fe2010SSepherosa Ziehau uint32_t rxf_len, txf_len; 45099fe2010SSepherosa Ziehau uint8_t pcie_ptr; 45199fe2010SSepherosa Ziehau 45299fe2010SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 45399fe2010SSepherosa Ziehau sc->ale_dev = dev; 45499fe2010SSepherosa Ziehau 45599fe2010SSepherosa Ziehau callout_init(&sc->ale_tick_ch); 45699fe2010SSepherosa Ziehau 45799fe2010SSepherosa Ziehau #ifndef BURN_BRIDGES 45899fe2010SSepherosa Ziehau if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 45999fe2010SSepherosa Ziehau uint32_t irq, mem; 46099fe2010SSepherosa Ziehau 46199fe2010SSepherosa Ziehau irq = pci_read_config(dev, PCIR_INTLINE, 4); 46299fe2010SSepherosa Ziehau mem = pci_read_config(dev, ALE_PCIR_BAR, 4); 46399fe2010SSepherosa Ziehau 46499fe2010SSepherosa Ziehau device_printf(dev, "chip is in D%d power mode " 46599fe2010SSepherosa Ziehau "-- setting to D0\n", pci_get_powerstate(dev)); 46699fe2010SSepherosa Ziehau 46799fe2010SSepherosa Ziehau pci_set_powerstate(dev, PCI_POWERSTATE_D0); 46899fe2010SSepherosa Ziehau 46999fe2010SSepherosa Ziehau pci_write_config(dev, PCIR_INTLINE, irq, 4); 47099fe2010SSepherosa Ziehau pci_write_config(dev, ALE_PCIR_BAR, mem, 4); 47199fe2010SSepherosa Ziehau } 47299fe2010SSepherosa Ziehau #endif /* !BURN_BRIDGE */ 47399fe2010SSepherosa Ziehau 47499fe2010SSepherosa Ziehau /* Enable bus mastering */ 47599fe2010SSepherosa Ziehau pci_enable_busmaster(dev); 47699fe2010SSepherosa Ziehau 47799fe2010SSepherosa Ziehau /* 47899fe2010SSepherosa Ziehau * Allocate memory mapped IO 47999fe2010SSepherosa Ziehau */ 48099fe2010SSepherosa Ziehau sc->ale_mem_rid = ALE_PCIR_BAR; 48199fe2010SSepherosa Ziehau sc->ale_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 48299fe2010SSepherosa Ziehau &sc->ale_mem_rid, RF_ACTIVE); 48399fe2010SSepherosa Ziehau if (sc->ale_mem_res == NULL) { 48499fe2010SSepherosa Ziehau device_printf(dev, "can't allocate IO memory\n"); 48599fe2010SSepherosa Ziehau return ENXIO; 48699fe2010SSepherosa Ziehau } 48799fe2010SSepherosa Ziehau sc->ale_mem_bt = rman_get_bustag(sc->ale_mem_res); 48899fe2010SSepherosa Ziehau sc->ale_mem_bh = rman_get_bushandle(sc->ale_mem_res); 48999fe2010SSepherosa Ziehau 49099fe2010SSepherosa Ziehau /* 49199fe2010SSepherosa Ziehau * Allocate IRQ 49299fe2010SSepherosa Ziehau */ 49399fe2010SSepherosa Ziehau sc->ale_irq_rid = 0; 49499fe2010SSepherosa Ziehau sc->ale_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 49599fe2010SSepherosa Ziehau &sc->ale_irq_rid, 49699fe2010SSepherosa Ziehau RF_SHAREABLE | RF_ACTIVE); 49799fe2010SSepherosa Ziehau if (sc->ale_irq_res == NULL) { 49899fe2010SSepherosa Ziehau device_printf(dev, "can't allocate irq\n"); 49999fe2010SSepherosa Ziehau error = ENXIO; 50099fe2010SSepherosa Ziehau goto fail; 50199fe2010SSepherosa Ziehau } 50299fe2010SSepherosa Ziehau 50399fe2010SSepherosa Ziehau /* Set PHY address. */ 50499fe2010SSepherosa Ziehau sc->ale_phyaddr = ALE_PHY_ADDR; 50599fe2010SSepherosa Ziehau 50699fe2010SSepherosa Ziehau /* Reset PHY. */ 50799fe2010SSepherosa Ziehau ale_phy_reset(sc); 50899fe2010SSepherosa Ziehau 50999fe2010SSepherosa Ziehau /* Reset the ethernet controller. */ 51099fe2010SSepherosa Ziehau ale_reset(sc); 51199fe2010SSepherosa Ziehau 51299fe2010SSepherosa Ziehau /* Get PCI and chip id/revision. */ 51399fe2010SSepherosa Ziehau sc->ale_rev = pci_get_revid(dev); 51499fe2010SSepherosa Ziehau if (sc->ale_rev >= 0xF0) { 51599fe2010SSepherosa Ziehau /* L2E Rev. B. AR8114 */ 51699fe2010SSepherosa Ziehau sc->ale_flags |= ALE_FLAG_FASTETHER; 51799fe2010SSepherosa Ziehau } else { 51899fe2010SSepherosa Ziehau if ((CSR_READ_4(sc, ALE_PHY_STATUS) & PHY_STATUS_100M) != 0) { 51999fe2010SSepherosa Ziehau /* L1E AR8121 */ 52099fe2010SSepherosa Ziehau sc->ale_flags |= ALE_FLAG_JUMBO; 52199fe2010SSepherosa Ziehau } else { 52299fe2010SSepherosa Ziehau /* L2E Rev. A. AR8113 */ 52399fe2010SSepherosa Ziehau sc->ale_flags |= ALE_FLAG_FASTETHER; 52499fe2010SSepherosa Ziehau } 52599fe2010SSepherosa Ziehau } 52699fe2010SSepherosa Ziehau 52799fe2010SSepherosa Ziehau /* 52899fe2010SSepherosa Ziehau * All known controllers seems to require 4 bytes alignment 52999fe2010SSepherosa Ziehau * of Tx buffers to make Tx checksum offload with custom 53099fe2010SSepherosa Ziehau * checksum generation method work. 53199fe2010SSepherosa Ziehau */ 53299fe2010SSepherosa Ziehau sc->ale_flags |= ALE_FLAG_TXCSUM_BUG; 53399fe2010SSepherosa Ziehau 53499fe2010SSepherosa Ziehau /* 53599fe2010SSepherosa Ziehau * All known controllers seems to have issues on Rx checksum 53699fe2010SSepherosa Ziehau * offload for fragmented IP datagrams. 53799fe2010SSepherosa Ziehau */ 53899fe2010SSepherosa Ziehau sc->ale_flags |= ALE_FLAG_RXCSUM_BUG; 53999fe2010SSepherosa Ziehau 54099fe2010SSepherosa Ziehau /* 54199fe2010SSepherosa Ziehau * Don't use Tx CMB. It is known to cause RRS update failure 54299fe2010SSepherosa Ziehau * under certain circumstances. Typical phenomenon of the 54399fe2010SSepherosa Ziehau * issue would be unexpected sequence number encountered in 54499fe2010SSepherosa Ziehau * Rx handler. 54599fe2010SSepherosa Ziehau */ 54699fe2010SSepherosa Ziehau sc->ale_flags |= ALE_FLAG_TXCMB_BUG; 54799fe2010SSepherosa Ziehau sc->ale_chip_rev = CSR_READ_4(sc, ALE_MASTER_CFG) >> 54899fe2010SSepherosa Ziehau MASTER_CHIP_REV_SHIFT; 54999fe2010SSepherosa Ziehau if (bootverbose) { 55099fe2010SSepherosa Ziehau device_printf(dev, "PCI device revision : 0x%04x\n", 55199fe2010SSepherosa Ziehau sc->ale_rev); 55299fe2010SSepherosa Ziehau device_printf(dev, "Chip id/revision : 0x%04x\n", 55399fe2010SSepherosa Ziehau sc->ale_chip_rev); 55499fe2010SSepherosa Ziehau } 55599fe2010SSepherosa Ziehau 55699fe2010SSepherosa Ziehau /* 55799fe2010SSepherosa Ziehau * Uninitialized hardware returns an invalid chip id/revision 55899fe2010SSepherosa Ziehau * as well as 0xFFFFFFFF for Tx/Rx fifo length. 55999fe2010SSepherosa Ziehau */ 56099fe2010SSepherosa Ziehau txf_len = CSR_READ_4(sc, ALE_SRAM_TX_FIFO_LEN); 56199fe2010SSepherosa Ziehau rxf_len = CSR_READ_4(sc, ALE_SRAM_RX_FIFO_LEN); 56299fe2010SSepherosa Ziehau if (sc->ale_chip_rev == 0xFFFF || txf_len == 0xFFFFFFFF || 56399fe2010SSepherosa Ziehau rxf_len == 0xFFFFFFF) { 56499fe2010SSepherosa Ziehau device_printf(dev,"chip revision : 0x%04x, %u Tx FIFO " 56599fe2010SSepherosa Ziehau "%u Rx FIFO -- not initialized?\n", sc->ale_chip_rev, 56699fe2010SSepherosa Ziehau txf_len, rxf_len); 56799fe2010SSepherosa Ziehau error = ENXIO; 56899fe2010SSepherosa Ziehau goto fail; 56999fe2010SSepherosa Ziehau } 57099fe2010SSepherosa Ziehau device_printf(dev, "%u Tx FIFO, %u Rx FIFO\n", txf_len, rxf_len); 57199fe2010SSepherosa Ziehau 57299fe2010SSepherosa Ziehau /* Get DMA parameters from PCIe device control register. */ 57399fe2010SSepherosa Ziehau pcie_ptr = pci_get_pciecap_ptr(dev); 57499fe2010SSepherosa Ziehau if (pcie_ptr) { 57599fe2010SSepherosa Ziehau uint16_t devctl; 57699fe2010SSepherosa Ziehau 57799fe2010SSepherosa Ziehau sc->ale_flags |= ALE_FLAG_PCIE; 57899fe2010SSepherosa Ziehau devctl = pci_read_config(dev, pcie_ptr + PCIER_DEVCTRL, 2); 57999fe2010SSepherosa Ziehau /* Max read request size. */ 58099fe2010SSepherosa Ziehau sc->ale_dma_rd_burst = ((devctl >> 12) & 0x07) << 58199fe2010SSepherosa Ziehau DMA_CFG_RD_BURST_SHIFT; 58299fe2010SSepherosa Ziehau /* Max payload size. */ 58399fe2010SSepherosa Ziehau sc->ale_dma_wr_burst = ((devctl >> 5) & 0x07) << 58499fe2010SSepherosa Ziehau DMA_CFG_WR_BURST_SHIFT; 58599fe2010SSepherosa Ziehau if (bootverbose) { 58699fe2010SSepherosa Ziehau device_printf(dev, "Read request size : %d bytes.\n", 58799fe2010SSepherosa Ziehau 128 << ((devctl >> 12) & 0x07)); 58899fe2010SSepherosa Ziehau device_printf(dev, "TLP payload size : %d bytes.\n", 58999fe2010SSepherosa Ziehau 128 << ((devctl >> 5) & 0x07)); 59099fe2010SSepherosa Ziehau } 59199fe2010SSepherosa Ziehau } else { 59299fe2010SSepherosa Ziehau sc->ale_dma_rd_burst = DMA_CFG_RD_BURST_128; 59399fe2010SSepherosa Ziehau sc->ale_dma_wr_burst = DMA_CFG_WR_BURST_128; 59499fe2010SSepherosa Ziehau } 59599fe2010SSepherosa Ziehau 59699fe2010SSepherosa Ziehau /* Create device sysctl node. */ 59799fe2010SSepherosa Ziehau ale_sysctl_node(sc); 59899fe2010SSepherosa Ziehau 59999fe2010SSepherosa Ziehau if ((error = ale_dma_alloc(sc) != 0)) 60099fe2010SSepherosa Ziehau goto fail; 60199fe2010SSepherosa Ziehau 60299fe2010SSepherosa Ziehau /* Load station address. */ 60399fe2010SSepherosa Ziehau ale_get_macaddr(sc); 60499fe2010SSepherosa Ziehau 60599fe2010SSepherosa Ziehau ifp->if_softc = sc; 60699fe2010SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 60799fe2010SSepherosa Ziehau ifp->if_ioctl = ale_ioctl; 60899fe2010SSepherosa Ziehau ifp->if_start = ale_start; 60999fe2010SSepherosa Ziehau ifp->if_init = ale_init; 61099fe2010SSepherosa Ziehau ifp->if_watchdog = ale_watchdog; 61199fe2010SSepherosa Ziehau ifq_set_maxlen(&ifp->if_snd, ALE_TX_RING_CNT - 1); 61299fe2010SSepherosa Ziehau ifq_set_ready(&ifp->if_snd); 61399fe2010SSepherosa Ziehau 6149d911346SSepherosa Ziehau ifp->if_capabilities = IFCAP_RXCSUM | 61599fe2010SSepherosa Ziehau IFCAP_VLAN_MTU | 61699fe2010SSepherosa Ziehau IFCAP_VLAN_HWTAGGING; 6179d911346SSepherosa Ziehau #ifdef notyet 6189d911346SSepherosa Ziehau ifp->if_capabilities |= IFCAP_TXCSUM; 61999fe2010SSepherosa Ziehau ifp->if_hwassist = ALE_CSUM_FEATURES; 6209d911346SSepherosa Ziehau #endif 62199fe2010SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 62299fe2010SSepherosa Ziehau 62399fe2010SSepherosa Ziehau /* Set up MII bus. */ 62499fe2010SSepherosa Ziehau if ((error = mii_phy_probe(dev, &sc->ale_miibus, ale_mediachange, 62599fe2010SSepherosa Ziehau ale_mediastatus)) != 0) { 62699fe2010SSepherosa Ziehau device_printf(dev, "no PHY found!\n"); 62799fe2010SSepherosa Ziehau goto fail; 62899fe2010SSepherosa Ziehau } 62999fe2010SSepherosa Ziehau 63099fe2010SSepherosa Ziehau ether_ifattach(ifp, sc->ale_eaddr, NULL); 63199fe2010SSepherosa Ziehau 63299fe2010SSepherosa Ziehau /* Tell the upper layer(s) we support long frames. */ 63399fe2010SSepherosa Ziehau ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 63499fe2010SSepherosa Ziehau 63599fe2010SSepherosa Ziehau error = bus_setup_intr(dev, sc->ale_irq_res, INTR_MPSAFE, ale_intr, sc, 63699fe2010SSepherosa Ziehau &sc->ale_irq_handle, ifp->if_serializer); 63799fe2010SSepherosa Ziehau if (error) { 63899fe2010SSepherosa Ziehau device_printf(dev, "could not set up interrupt handler.\n"); 63999fe2010SSepherosa Ziehau ether_ifdetach(ifp); 64099fe2010SSepherosa Ziehau goto fail; 64199fe2010SSepherosa Ziehau } 64299fe2010SSepherosa Ziehau 64328e81a28SSepherosa Ziehau ifp->if_cpuid = rman_get_cpuid(sc->ale_irq_res); 64499fe2010SSepherosa Ziehau KKASSERT(ifp->if_cpuid >= 0 && ifp->if_cpuid < ncpus); 64599fe2010SSepherosa Ziehau return 0; 64699fe2010SSepherosa Ziehau fail: 64799fe2010SSepherosa Ziehau ale_detach(dev); 64899fe2010SSepherosa Ziehau return (error); 64999fe2010SSepherosa Ziehau } 65099fe2010SSepherosa Ziehau 65199fe2010SSepherosa Ziehau static int 65299fe2010SSepherosa Ziehau ale_detach(device_t dev) 65399fe2010SSepherosa Ziehau { 65499fe2010SSepherosa Ziehau struct ale_softc *sc = device_get_softc(dev); 65599fe2010SSepherosa Ziehau 65699fe2010SSepherosa Ziehau if (device_is_attached(dev)) { 65799fe2010SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 65899fe2010SSepherosa Ziehau 65999fe2010SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 66099fe2010SSepherosa Ziehau sc->ale_flags |= ALE_FLAG_DETACH; 66199fe2010SSepherosa Ziehau ale_stop(sc); 66299fe2010SSepherosa Ziehau bus_teardown_intr(dev, sc->ale_irq_res, sc->ale_irq_handle); 66399fe2010SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 66499fe2010SSepherosa Ziehau 66599fe2010SSepherosa Ziehau ether_ifdetach(ifp); 66699fe2010SSepherosa Ziehau } 66799fe2010SSepherosa Ziehau 66899fe2010SSepherosa Ziehau if (sc->ale_sysctl_tree != NULL) 66999fe2010SSepherosa Ziehau sysctl_ctx_free(&sc->ale_sysctl_ctx); 67099fe2010SSepherosa Ziehau 67199fe2010SSepherosa Ziehau if (sc->ale_miibus != NULL) 67299fe2010SSepherosa Ziehau device_delete_child(dev, sc->ale_miibus); 67399fe2010SSepherosa Ziehau bus_generic_detach(dev); 67499fe2010SSepherosa Ziehau 67599fe2010SSepherosa Ziehau if (sc->ale_irq_res != NULL) { 67699fe2010SSepherosa Ziehau bus_release_resource(dev, SYS_RES_IRQ, sc->ale_irq_rid, 67799fe2010SSepherosa Ziehau sc->ale_irq_res); 67899fe2010SSepherosa Ziehau } 67999fe2010SSepherosa Ziehau if (sc->ale_mem_res != NULL) { 68099fe2010SSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, sc->ale_mem_rid, 68199fe2010SSepherosa Ziehau sc->ale_mem_res); 68299fe2010SSepherosa Ziehau } 68399fe2010SSepherosa Ziehau 68499fe2010SSepherosa Ziehau ale_dma_free(sc); 68599fe2010SSepherosa Ziehau 68699fe2010SSepherosa Ziehau return (0); 68799fe2010SSepherosa Ziehau } 68899fe2010SSepherosa Ziehau 68999fe2010SSepherosa Ziehau #define ALE_SYSCTL_STAT_ADD32(c, h, n, p, d) \ 69099fe2010SSepherosa Ziehau SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d) 69199fe2010SSepherosa Ziehau #define ALE_SYSCTL_STAT_ADD64(c, h, n, p, d) \ 69299fe2010SSepherosa Ziehau SYSCTL_ADD_QUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d) 69399fe2010SSepherosa Ziehau 69499fe2010SSepherosa Ziehau static void 69599fe2010SSepherosa Ziehau ale_sysctl_node(struct ale_softc *sc) 69699fe2010SSepherosa Ziehau { 69799fe2010SSepherosa Ziehau struct sysctl_ctx_list *ctx; 69899fe2010SSepherosa Ziehau struct sysctl_oid_list *child, *parent; 69999fe2010SSepherosa Ziehau struct sysctl_oid *tree; 70099fe2010SSepherosa Ziehau struct ale_hw_stats *stats; 70199fe2010SSepherosa Ziehau int error; 70299fe2010SSepherosa Ziehau 70399fe2010SSepherosa Ziehau sysctl_ctx_init(&sc->ale_sysctl_ctx); 70499fe2010SSepherosa Ziehau sc->ale_sysctl_tree = SYSCTL_ADD_NODE(&sc->ale_sysctl_ctx, 70599fe2010SSepherosa Ziehau SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 70699fe2010SSepherosa Ziehau device_get_nameunit(sc->ale_dev), 70799fe2010SSepherosa Ziehau CTLFLAG_RD, 0, ""); 70899fe2010SSepherosa Ziehau if (sc->ale_sysctl_tree == NULL) { 70999fe2010SSepherosa Ziehau device_printf(sc->ale_dev, "can't add sysctl node\n"); 71099fe2010SSepherosa Ziehau return; 71199fe2010SSepherosa Ziehau } 71299fe2010SSepherosa Ziehau 71399fe2010SSepherosa Ziehau stats = &sc->ale_stats; 71499fe2010SSepherosa Ziehau ctx = &sc->ale_sysctl_ctx; 71599fe2010SSepherosa Ziehau child = SYSCTL_CHILDREN(sc->ale_sysctl_tree); 71699fe2010SSepherosa Ziehau 71799fe2010SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "int_rx_mod", 71899fe2010SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW, &sc->ale_int_rx_mod, 0, 71999fe2010SSepherosa Ziehau sysctl_hw_ale_int_mod, "I", "ale Rx interrupt moderation"); 72099fe2010SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "int_tx_mod", 72199fe2010SSepherosa Ziehau CTLTYPE_INT | CTLFLAG_RW, &sc->ale_int_tx_mod, 0, 72299fe2010SSepherosa Ziehau sysctl_hw_ale_int_mod, "I", "ale Tx interrupt moderation"); 72399fe2010SSepherosa Ziehau 72499fe2010SSepherosa Ziehau /* 72599fe2010SSepherosa Ziehau * Pull in device tunables. 72699fe2010SSepherosa Ziehau */ 72799fe2010SSepherosa Ziehau sc->ale_int_rx_mod = ALE_IM_RX_TIMER_DEFAULT; 72899fe2010SSepherosa Ziehau error = resource_int_value(device_get_name(sc->ale_dev), 72999fe2010SSepherosa Ziehau device_get_unit(sc->ale_dev), "int_rx_mod", &sc->ale_int_rx_mod); 73099fe2010SSepherosa Ziehau if (error == 0) { 73199fe2010SSepherosa Ziehau if (sc->ale_int_rx_mod < ALE_IM_TIMER_MIN || 73299fe2010SSepherosa Ziehau sc->ale_int_rx_mod > ALE_IM_TIMER_MAX) { 73399fe2010SSepherosa Ziehau device_printf(sc->ale_dev, "int_rx_mod value out of " 73499fe2010SSepherosa Ziehau "range; using default: %d\n", 73599fe2010SSepherosa Ziehau ALE_IM_RX_TIMER_DEFAULT); 73699fe2010SSepherosa Ziehau sc->ale_int_rx_mod = ALE_IM_RX_TIMER_DEFAULT; 73799fe2010SSepherosa Ziehau } 73899fe2010SSepherosa Ziehau } 73999fe2010SSepherosa Ziehau 74099fe2010SSepherosa Ziehau sc->ale_int_tx_mod = ALE_IM_TX_TIMER_DEFAULT; 74199fe2010SSepherosa Ziehau error = resource_int_value(device_get_name(sc->ale_dev), 74299fe2010SSepherosa Ziehau device_get_unit(sc->ale_dev), "int_tx_mod", &sc->ale_int_tx_mod); 74399fe2010SSepherosa Ziehau if (error == 0) { 74499fe2010SSepherosa Ziehau if (sc->ale_int_tx_mod < ALE_IM_TIMER_MIN || 74599fe2010SSepherosa Ziehau sc->ale_int_tx_mod > ALE_IM_TIMER_MAX) { 74699fe2010SSepherosa Ziehau device_printf(sc->ale_dev, "int_tx_mod value out of " 74799fe2010SSepherosa Ziehau "range; using default: %d\n", 74899fe2010SSepherosa Ziehau ALE_IM_TX_TIMER_DEFAULT); 74999fe2010SSepherosa Ziehau sc->ale_int_tx_mod = ALE_IM_TX_TIMER_DEFAULT; 75099fe2010SSepherosa Ziehau } 75199fe2010SSepherosa Ziehau } 75299fe2010SSepherosa Ziehau 75399fe2010SSepherosa Ziehau /* Misc statistics. */ 75499fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "reset_brk_seq", 75599fe2010SSepherosa Ziehau &stats->reset_brk_seq, 75699fe2010SSepherosa Ziehau "Controller resets due to broken Rx sequnce number"); 75799fe2010SSepherosa Ziehau 75899fe2010SSepherosa Ziehau tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD, 75999fe2010SSepherosa Ziehau NULL, "ATE statistics"); 76099fe2010SSepherosa Ziehau parent = SYSCTL_CHILDREN(tree); 76199fe2010SSepherosa Ziehau 76299fe2010SSepherosa Ziehau /* Rx statistics. */ 76399fe2010SSepherosa Ziehau tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD, 76499fe2010SSepherosa Ziehau NULL, "Rx MAC statistics"); 76599fe2010SSepherosa Ziehau child = SYSCTL_CHILDREN(tree); 76699fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "good_frames", 76799fe2010SSepherosa Ziehau &stats->rx_frames, "Good frames"); 76899fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "good_bcast_frames", 76999fe2010SSepherosa Ziehau &stats->rx_bcast_frames, "Good broadcast frames"); 77099fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "good_mcast_frames", 77199fe2010SSepherosa Ziehau &stats->rx_mcast_frames, "Good multicast frames"); 77299fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "pause_frames", 77399fe2010SSepherosa Ziehau &stats->rx_pause_frames, "Pause control frames"); 77499fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "control_frames", 77599fe2010SSepherosa Ziehau &stats->rx_control_frames, "Control frames"); 77699fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "crc_errs", 77799fe2010SSepherosa Ziehau &stats->rx_crcerrs, "CRC errors"); 77899fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "len_errs", 77999fe2010SSepherosa Ziehau &stats->rx_lenerrs, "Frames with length mismatched"); 78099fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD64(ctx, child, "good_octets", 78199fe2010SSepherosa Ziehau &stats->rx_bytes, "Good octets"); 78299fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD64(ctx, child, "good_bcast_octets", 78399fe2010SSepherosa Ziehau &stats->rx_bcast_bytes, "Good broadcast octets"); 78499fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD64(ctx, child, "good_mcast_octets", 78599fe2010SSepherosa Ziehau &stats->rx_mcast_bytes, "Good multicast octets"); 78699fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "runts", 78799fe2010SSepherosa Ziehau &stats->rx_runts, "Too short frames"); 78899fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "fragments", 78999fe2010SSepherosa Ziehau &stats->rx_fragments, "Fragmented frames"); 79099fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "frames_64", 79199fe2010SSepherosa Ziehau &stats->rx_pkts_64, "64 bytes frames"); 79299fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "frames_65_127", 79399fe2010SSepherosa Ziehau &stats->rx_pkts_65_127, "65 to 127 bytes frames"); 79499fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "frames_128_255", 79599fe2010SSepherosa Ziehau &stats->rx_pkts_128_255, "128 to 255 bytes frames"); 79699fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "frames_256_511", 79799fe2010SSepherosa Ziehau &stats->rx_pkts_256_511, "256 to 511 bytes frames"); 79899fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "frames_512_1023", 79999fe2010SSepherosa Ziehau &stats->rx_pkts_512_1023, "512 to 1023 bytes frames"); 80099fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "frames_1024_1518", 80199fe2010SSepherosa Ziehau &stats->rx_pkts_1024_1518, "1024 to 1518 bytes frames"); 80299fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "frames_1519_max", 80399fe2010SSepherosa Ziehau &stats->rx_pkts_1519_max, "1519 to max frames"); 80499fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "trunc_errs", 80599fe2010SSepherosa Ziehau &stats->rx_pkts_truncated, "Truncated frames due to MTU size"); 80699fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "fifo_oflows", 80799fe2010SSepherosa Ziehau &stats->rx_fifo_oflows, "FIFO overflows"); 80899fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "rrs_errs", 80999fe2010SSepherosa Ziehau &stats->rx_rrs_errs, "Return status write-back errors"); 81099fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "align_errs", 81199fe2010SSepherosa Ziehau &stats->rx_alignerrs, "Alignment errors"); 81299fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "filtered", 81399fe2010SSepherosa Ziehau &stats->rx_pkts_filtered, 81499fe2010SSepherosa Ziehau "Frames dropped due to address filtering"); 81599fe2010SSepherosa Ziehau 81699fe2010SSepherosa Ziehau /* Tx statistics. */ 81799fe2010SSepherosa Ziehau tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD, 81899fe2010SSepherosa Ziehau NULL, "Tx MAC statistics"); 81999fe2010SSepherosa Ziehau child = SYSCTL_CHILDREN(tree); 82099fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "good_frames", 82199fe2010SSepherosa Ziehau &stats->tx_frames, "Good frames"); 82299fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "good_bcast_frames", 82399fe2010SSepherosa Ziehau &stats->tx_bcast_frames, "Good broadcast frames"); 82499fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "good_mcast_frames", 82599fe2010SSepherosa Ziehau &stats->tx_mcast_frames, "Good multicast frames"); 82699fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "pause_frames", 82799fe2010SSepherosa Ziehau &stats->tx_pause_frames, "Pause control frames"); 82899fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "control_frames", 82999fe2010SSepherosa Ziehau &stats->tx_control_frames, "Control frames"); 83099fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "excess_defers", 83199fe2010SSepherosa Ziehau &stats->tx_excess_defer, "Frames with excessive derferrals"); 83299fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "defers", 83399fe2010SSepherosa Ziehau &stats->tx_excess_defer, "Frames with derferrals"); 83499fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD64(ctx, child, "good_octets", 83599fe2010SSepherosa Ziehau &stats->tx_bytes, "Good octets"); 83699fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD64(ctx, child, "good_bcast_octets", 83799fe2010SSepherosa Ziehau &stats->tx_bcast_bytes, "Good broadcast octets"); 83899fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD64(ctx, child, "good_mcast_octets", 83999fe2010SSepherosa Ziehau &stats->tx_mcast_bytes, "Good multicast octets"); 84099fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "frames_64", 84199fe2010SSepherosa Ziehau &stats->tx_pkts_64, "64 bytes frames"); 84299fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "frames_65_127", 84399fe2010SSepherosa Ziehau &stats->tx_pkts_65_127, "65 to 127 bytes frames"); 84499fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "frames_128_255", 84599fe2010SSepherosa Ziehau &stats->tx_pkts_128_255, "128 to 255 bytes frames"); 84699fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "frames_256_511", 84799fe2010SSepherosa Ziehau &stats->tx_pkts_256_511, "256 to 511 bytes frames"); 84899fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "frames_512_1023", 84999fe2010SSepherosa Ziehau &stats->tx_pkts_512_1023, "512 to 1023 bytes frames"); 85099fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "frames_1024_1518", 85199fe2010SSepherosa Ziehau &stats->tx_pkts_1024_1518, "1024 to 1518 bytes frames"); 85299fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "frames_1519_max", 85399fe2010SSepherosa Ziehau &stats->tx_pkts_1519_max, "1519 to max frames"); 85499fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "single_colls", 85599fe2010SSepherosa Ziehau &stats->tx_single_colls, "Single collisions"); 85699fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "multi_colls", 85799fe2010SSepherosa Ziehau &stats->tx_multi_colls, "Multiple collisions"); 85899fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "late_colls", 85999fe2010SSepherosa Ziehau &stats->tx_late_colls, "Late collisions"); 86099fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "excess_colls", 86199fe2010SSepherosa Ziehau &stats->tx_excess_colls, "Excessive collisions"); 86299fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "abort", 86399fe2010SSepherosa Ziehau &stats->tx_abort, "Aborted frames due to Excessive collisions"); 86499fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "underruns", 86599fe2010SSepherosa Ziehau &stats->tx_underrun, "FIFO underruns"); 86699fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "desc_underruns", 86799fe2010SSepherosa Ziehau &stats->tx_desc_underrun, "Descriptor write-back errors"); 86899fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "len_errs", 86999fe2010SSepherosa Ziehau &stats->tx_lenerrs, "Frames with length mismatched"); 87099fe2010SSepherosa Ziehau ALE_SYSCTL_STAT_ADD32(ctx, child, "trunc_errs", 87199fe2010SSepherosa Ziehau &stats->tx_pkts_truncated, "Truncated frames due to MTU size"); 87299fe2010SSepherosa Ziehau } 87399fe2010SSepherosa Ziehau 87499fe2010SSepherosa Ziehau #undef ALE_SYSCTL_STAT_ADD32 87599fe2010SSepherosa Ziehau #undef ALE_SYSCTL_STAT_ADD64 87699fe2010SSepherosa Ziehau 87799fe2010SSepherosa Ziehau struct ale_dmamap_arg { 87899fe2010SSepherosa Ziehau bus_addr_t ale_busaddr; 87999fe2010SSepherosa Ziehau }; 88099fe2010SSepherosa Ziehau 88199fe2010SSepherosa Ziehau static void 88299fe2010SSepherosa Ziehau ale_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 88399fe2010SSepherosa Ziehau { 88499fe2010SSepherosa Ziehau struct ale_dmamap_arg *ctx; 88599fe2010SSepherosa Ziehau 88699fe2010SSepherosa Ziehau if (error != 0) 88799fe2010SSepherosa Ziehau return; 88899fe2010SSepherosa Ziehau 88999fe2010SSepherosa Ziehau KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 89099fe2010SSepherosa Ziehau 89199fe2010SSepherosa Ziehau ctx = (struct ale_dmamap_arg *)arg; 89299fe2010SSepherosa Ziehau ctx->ale_busaddr = segs[0].ds_addr; 89399fe2010SSepherosa Ziehau } 89499fe2010SSepherosa Ziehau 89599fe2010SSepherosa Ziehau /* 89699fe2010SSepherosa Ziehau * Tx descriptors/RXF0/CMB DMA blocks share ALE_DESC_ADDR_HI register 89799fe2010SSepherosa Ziehau * which specifies high address region of DMA blocks. Therefore these 89899fe2010SSepherosa Ziehau * blocks should have the same high address of given 4GB address 89999fe2010SSepherosa Ziehau * space(i.e. crossing 4GB boundary is not allowed). 90099fe2010SSepherosa Ziehau */ 90199fe2010SSepherosa Ziehau static int 90299fe2010SSepherosa Ziehau ale_check_boundary(struct ale_softc *sc) 90399fe2010SSepherosa Ziehau { 90499fe2010SSepherosa Ziehau bus_addr_t rx_cmb_end[ALE_RX_PAGES], tx_cmb_end; 90599fe2010SSepherosa Ziehau bus_addr_t rx_page_end[ALE_RX_PAGES], tx_ring_end; 90699fe2010SSepherosa Ziehau 90799fe2010SSepherosa Ziehau rx_page_end[0] = sc->ale_cdata.ale_rx_page[0].page_paddr + 90899fe2010SSepherosa Ziehau sc->ale_pagesize; 90999fe2010SSepherosa Ziehau rx_page_end[1] = sc->ale_cdata.ale_rx_page[1].page_paddr + 91099fe2010SSepherosa Ziehau sc->ale_pagesize; 91199fe2010SSepherosa Ziehau tx_ring_end = sc->ale_cdata.ale_tx_ring_paddr + ALE_TX_RING_SZ; 91299fe2010SSepherosa Ziehau tx_cmb_end = sc->ale_cdata.ale_tx_cmb_paddr + ALE_TX_CMB_SZ; 91399fe2010SSepherosa Ziehau rx_cmb_end[0] = sc->ale_cdata.ale_rx_page[0].cmb_paddr + ALE_RX_CMB_SZ; 91499fe2010SSepherosa Ziehau rx_cmb_end[1] = sc->ale_cdata.ale_rx_page[1].cmb_paddr + ALE_RX_CMB_SZ; 91599fe2010SSepherosa Ziehau 91699fe2010SSepherosa Ziehau if ((ALE_ADDR_HI(tx_ring_end) != 91799fe2010SSepherosa Ziehau ALE_ADDR_HI(sc->ale_cdata.ale_tx_ring_paddr)) || 91899fe2010SSepherosa Ziehau (ALE_ADDR_HI(rx_page_end[0]) != 91999fe2010SSepherosa Ziehau ALE_ADDR_HI(sc->ale_cdata.ale_rx_page[0].page_paddr)) || 92099fe2010SSepherosa Ziehau (ALE_ADDR_HI(rx_page_end[1]) != 92199fe2010SSepherosa Ziehau ALE_ADDR_HI(sc->ale_cdata.ale_rx_page[1].page_paddr)) || 92299fe2010SSepherosa Ziehau (ALE_ADDR_HI(tx_cmb_end) != 92399fe2010SSepherosa Ziehau ALE_ADDR_HI(sc->ale_cdata.ale_tx_cmb_paddr)) || 92499fe2010SSepherosa Ziehau (ALE_ADDR_HI(rx_cmb_end[0]) != 92599fe2010SSepherosa Ziehau ALE_ADDR_HI(sc->ale_cdata.ale_rx_page[0].cmb_paddr)) || 92699fe2010SSepherosa Ziehau (ALE_ADDR_HI(rx_cmb_end[1]) != 92799fe2010SSepherosa Ziehau ALE_ADDR_HI(sc->ale_cdata.ale_rx_page[1].cmb_paddr))) 92899fe2010SSepherosa Ziehau return (EFBIG); 92999fe2010SSepherosa Ziehau 93099fe2010SSepherosa Ziehau if ((ALE_ADDR_HI(tx_ring_end) != ALE_ADDR_HI(rx_page_end[0])) || 93199fe2010SSepherosa Ziehau (ALE_ADDR_HI(tx_ring_end) != ALE_ADDR_HI(rx_page_end[1])) || 93299fe2010SSepherosa Ziehau (ALE_ADDR_HI(tx_ring_end) != ALE_ADDR_HI(rx_cmb_end[0])) || 93399fe2010SSepherosa Ziehau (ALE_ADDR_HI(tx_ring_end) != ALE_ADDR_HI(rx_cmb_end[1])) || 93499fe2010SSepherosa Ziehau (ALE_ADDR_HI(tx_ring_end) != ALE_ADDR_HI(tx_cmb_end))) 93599fe2010SSepherosa Ziehau return (EFBIG); 93699fe2010SSepherosa Ziehau 93799fe2010SSepherosa Ziehau return (0); 93899fe2010SSepherosa Ziehau } 93999fe2010SSepherosa Ziehau 94099fe2010SSepherosa Ziehau static int 94199fe2010SSepherosa Ziehau ale_dma_alloc(struct ale_softc *sc) 94299fe2010SSepherosa Ziehau { 94399fe2010SSepherosa Ziehau struct ale_txdesc *txd; 94499fe2010SSepherosa Ziehau bus_addr_t lowaddr; 94599fe2010SSepherosa Ziehau struct ale_dmamap_arg ctx; 94699fe2010SSepherosa Ziehau int error, guard_size, i; 94799fe2010SSepherosa Ziehau 94899fe2010SSepherosa Ziehau if ((sc->ale_flags & ALE_FLAG_JUMBO) != 0) 94999fe2010SSepherosa Ziehau guard_size = ALE_JUMBO_FRAMELEN; 95099fe2010SSepherosa Ziehau else 95199fe2010SSepherosa Ziehau guard_size = ALE_MAX_FRAMELEN; 95299fe2010SSepherosa Ziehau sc->ale_pagesize = roundup(guard_size + ALE_RX_PAGE_SZ, 95399fe2010SSepherosa Ziehau ALE_RX_PAGE_ALIGN); 95499fe2010SSepherosa Ziehau lowaddr = BUS_SPACE_MAXADDR; 95599fe2010SSepherosa Ziehau again: 95699fe2010SSepherosa Ziehau /* Create parent DMA tag. */ 95799fe2010SSepherosa Ziehau error = bus_dma_tag_create( 95899fe2010SSepherosa Ziehau NULL, /* parent */ 95999fe2010SSepherosa Ziehau 1, 0, /* alignment, boundary */ 96099fe2010SSepherosa Ziehau lowaddr, /* lowaddr */ 96199fe2010SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 96299fe2010SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 96399fe2010SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 96499fe2010SSepherosa Ziehau 0, /* nsegments */ 96599fe2010SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 96699fe2010SSepherosa Ziehau 0, /* flags */ 96799fe2010SSepherosa Ziehau &sc->ale_cdata.ale_parent_tag); 96899fe2010SSepherosa Ziehau if (error != 0) { 96999fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 97099fe2010SSepherosa Ziehau "could not create parent DMA tag.\n"); 97199fe2010SSepherosa Ziehau goto fail; 97299fe2010SSepherosa Ziehau } 97399fe2010SSepherosa Ziehau 97499fe2010SSepherosa Ziehau /* Create DMA tag for Tx descriptor ring. */ 97599fe2010SSepherosa Ziehau error = bus_dma_tag_create( 97699fe2010SSepherosa Ziehau sc->ale_cdata.ale_parent_tag, /* parent */ 97799fe2010SSepherosa Ziehau ALE_TX_RING_ALIGN, 0, /* alignment, boundary */ 97899fe2010SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 97999fe2010SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 98099fe2010SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 98199fe2010SSepherosa Ziehau ALE_TX_RING_SZ, /* maxsize */ 98299fe2010SSepherosa Ziehau 1, /* nsegments */ 98399fe2010SSepherosa Ziehau ALE_TX_RING_SZ, /* maxsegsize */ 98499fe2010SSepherosa Ziehau 0, /* flags */ 98599fe2010SSepherosa Ziehau &sc->ale_cdata.ale_tx_ring_tag); 98699fe2010SSepherosa Ziehau if (error != 0) { 98799fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 98899fe2010SSepherosa Ziehau "could not create Tx ring DMA tag.\n"); 98999fe2010SSepherosa Ziehau goto fail; 99099fe2010SSepherosa Ziehau } 99199fe2010SSepherosa Ziehau 99299fe2010SSepherosa Ziehau /* Create DMA tag for Rx pages. */ 99399fe2010SSepherosa Ziehau for (i = 0; i < ALE_RX_PAGES; i++) { 99499fe2010SSepherosa Ziehau error = bus_dma_tag_create( 99599fe2010SSepherosa Ziehau sc->ale_cdata.ale_parent_tag, /* parent */ 99699fe2010SSepherosa Ziehau ALE_RX_PAGE_ALIGN, 0, /* alignment, boundary */ 99799fe2010SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 99899fe2010SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 99999fe2010SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 100099fe2010SSepherosa Ziehau sc->ale_pagesize, /* maxsize */ 100199fe2010SSepherosa Ziehau 1, /* nsegments */ 100299fe2010SSepherosa Ziehau sc->ale_pagesize, /* maxsegsize */ 100399fe2010SSepherosa Ziehau 0, /* flags */ 100499fe2010SSepherosa Ziehau &sc->ale_cdata.ale_rx_page[i].page_tag); 100599fe2010SSepherosa Ziehau if (error != 0) { 100699fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 100799fe2010SSepherosa Ziehau "could not create Rx page %d DMA tag.\n", i); 100899fe2010SSepherosa Ziehau goto fail; 100999fe2010SSepherosa Ziehau } 101099fe2010SSepherosa Ziehau } 101199fe2010SSepherosa Ziehau 101299fe2010SSepherosa Ziehau /* Create DMA tag for Tx coalescing message block. */ 101399fe2010SSepherosa Ziehau error = bus_dma_tag_create( 101499fe2010SSepherosa Ziehau sc->ale_cdata.ale_parent_tag, /* parent */ 101599fe2010SSepherosa Ziehau ALE_CMB_ALIGN, 0, /* alignment, boundary */ 101699fe2010SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 101799fe2010SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 101899fe2010SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 101999fe2010SSepherosa Ziehau ALE_TX_CMB_SZ, /* maxsize */ 102099fe2010SSepherosa Ziehau 1, /* nsegments */ 102199fe2010SSepherosa Ziehau ALE_TX_CMB_SZ, /* maxsegsize */ 102299fe2010SSepherosa Ziehau 0, /* flags */ 102399fe2010SSepherosa Ziehau &sc->ale_cdata.ale_tx_cmb_tag); 102499fe2010SSepherosa Ziehau if (error != 0) { 102599fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 102699fe2010SSepherosa Ziehau "could not create Tx CMB DMA tag.\n"); 102799fe2010SSepherosa Ziehau goto fail; 102899fe2010SSepherosa Ziehau } 102999fe2010SSepherosa Ziehau 103099fe2010SSepherosa Ziehau /* Create DMA tag for Rx coalescing message block. */ 103199fe2010SSepherosa Ziehau for (i = 0; i < ALE_RX_PAGES; i++) { 103299fe2010SSepherosa Ziehau error = bus_dma_tag_create( 103399fe2010SSepherosa Ziehau sc->ale_cdata.ale_parent_tag, /* parent */ 103499fe2010SSepherosa Ziehau ALE_CMB_ALIGN, 0, /* alignment, boundary */ 103599fe2010SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 103699fe2010SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 103799fe2010SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 103899fe2010SSepherosa Ziehau ALE_RX_CMB_SZ, /* maxsize */ 103999fe2010SSepherosa Ziehau 1, /* nsegments */ 104099fe2010SSepherosa Ziehau ALE_RX_CMB_SZ, /* maxsegsize */ 104199fe2010SSepherosa Ziehau 0, /* flags */ 104299fe2010SSepherosa Ziehau &sc->ale_cdata.ale_rx_page[i].cmb_tag); 104399fe2010SSepherosa Ziehau if (error != 0) { 104499fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 104599fe2010SSepherosa Ziehau "could not create Rx page %d CMB DMA tag.\n", i); 104699fe2010SSepherosa Ziehau goto fail; 104799fe2010SSepherosa Ziehau } 104899fe2010SSepherosa Ziehau } 104999fe2010SSepherosa Ziehau 105099fe2010SSepherosa Ziehau /* Allocate DMA'able memory and load the DMA map for Tx ring. */ 105199fe2010SSepherosa Ziehau error = bus_dmamem_alloc(sc->ale_cdata.ale_tx_ring_tag, 105299fe2010SSepherosa Ziehau (void **)&sc->ale_cdata.ale_tx_ring, 105399fe2010SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 105499fe2010SSepherosa Ziehau &sc->ale_cdata.ale_tx_ring_map); 105599fe2010SSepherosa Ziehau if (error != 0) { 105699fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 105799fe2010SSepherosa Ziehau "could not allocate DMA'able memory for Tx ring.\n"); 105899fe2010SSepherosa Ziehau goto fail; 105999fe2010SSepherosa Ziehau } 106099fe2010SSepherosa Ziehau ctx.ale_busaddr = 0; 106199fe2010SSepherosa Ziehau error = bus_dmamap_load(sc->ale_cdata.ale_tx_ring_tag, 106299fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_ring_map, sc->ale_cdata.ale_tx_ring, 106399fe2010SSepherosa Ziehau ALE_TX_RING_SZ, ale_dmamap_cb, &ctx, 0); 106499fe2010SSepherosa Ziehau if (error != 0 || ctx.ale_busaddr == 0) { 106599fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 106699fe2010SSepherosa Ziehau "could not load DMA'able memory for Tx ring.\n"); 106799fe2010SSepherosa Ziehau goto fail; 106899fe2010SSepherosa Ziehau } 106999fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_ring_paddr = ctx.ale_busaddr; 107099fe2010SSepherosa Ziehau 107199fe2010SSepherosa Ziehau /* Rx pages. */ 107299fe2010SSepherosa Ziehau for (i = 0; i < ALE_RX_PAGES; i++) { 107399fe2010SSepherosa Ziehau error = bus_dmamem_alloc(sc->ale_cdata.ale_rx_page[i].page_tag, 107499fe2010SSepherosa Ziehau (void **)&sc->ale_cdata.ale_rx_page[i].page_addr, 107599fe2010SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 107699fe2010SSepherosa Ziehau &sc->ale_cdata.ale_rx_page[i].page_map); 107799fe2010SSepherosa Ziehau if (error != 0) { 107899fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 107999fe2010SSepherosa Ziehau "could not allocate DMA'able memory for " 108099fe2010SSepherosa Ziehau "Rx page %d.\n", i); 108199fe2010SSepherosa Ziehau goto fail; 108299fe2010SSepherosa Ziehau } 108399fe2010SSepherosa Ziehau ctx.ale_busaddr = 0; 108499fe2010SSepherosa Ziehau error = bus_dmamap_load(sc->ale_cdata.ale_rx_page[i].page_tag, 108599fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].page_map, 108699fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].page_addr, 108799fe2010SSepherosa Ziehau sc->ale_pagesize, ale_dmamap_cb, &ctx, 0); 108899fe2010SSepherosa Ziehau if (error != 0 || ctx.ale_busaddr == 0) { 108999fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 109099fe2010SSepherosa Ziehau "could not load DMA'able memory for " 109199fe2010SSepherosa Ziehau "Rx page %d.\n", i); 109299fe2010SSepherosa Ziehau goto fail; 109399fe2010SSepherosa Ziehau } 109499fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].page_paddr = ctx.ale_busaddr; 109599fe2010SSepherosa Ziehau } 109699fe2010SSepherosa Ziehau 109799fe2010SSepherosa Ziehau /* Tx CMB. */ 109899fe2010SSepherosa Ziehau error = bus_dmamem_alloc(sc->ale_cdata.ale_tx_cmb_tag, 109999fe2010SSepherosa Ziehau (void **)&sc->ale_cdata.ale_tx_cmb, 110099fe2010SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 110199fe2010SSepherosa Ziehau &sc->ale_cdata.ale_tx_cmb_map); 110299fe2010SSepherosa Ziehau if (error != 0) { 110399fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 110499fe2010SSepherosa Ziehau "could not allocate DMA'able memory for Tx CMB.\n"); 110599fe2010SSepherosa Ziehau goto fail; 110699fe2010SSepherosa Ziehau } 110799fe2010SSepherosa Ziehau ctx.ale_busaddr = 0; 110899fe2010SSepherosa Ziehau error = bus_dmamap_load(sc->ale_cdata.ale_tx_cmb_tag, 110999fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_cmb_map, sc->ale_cdata.ale_tx_cmb, 111099fe2010SSepherosa Ziehau ALE_TX_CMB_SZ, ale_dmamap_cb, &ctx, 0); 111199fe2010SSepherosa Ziehau if (error != 0 || ctx.ale_busaddr == 0) { 111299fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 111399fe2010SSepherosa Ziehau "could not load DMA'able memory for Tx CMB.\n"); 111499fe2010SSepherosa Ziehau goto fail; 111599fe2010SSepherosa Ziehau } 111699fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_cmb_paddr = ctx.ale_busaddr; 111799fe2010SSepherosa Ziehau 111899fe2010SSepherosa Ziehau /* Rx CMB. */ 111999fe2010SSepherosa Ziehau for (i = 0; i < ALE_RX_PAGES; i++) { 112099fe2010SSepherosa Ziehau error = bus_dmamem_alloc(sc->ale_cdata.ale_rx_page[i].cmb_tag, 112199fe2010SSepherosa Ziehau (void **)&sc->ale_cdata.ale_rx_page[i].cmb_addr, 112299fe2010SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 112399fe2010SSepherosa Ziehau &sc->ale_cdata.ale_rx_page[i].cmb_map); 112499fe2010SSepherosa Ziehau if (error != 0) { 112599fe2010SSepherosa Ziehau device_printf(sc->ale_dev, "could not allocate " 112699fe2010SSepherosa Ziehau "DMA'able memory for Rx page %d CMB.\n", i); 112799fe2010SSepherosa Ziehau goto fail; 112899fe2010SSepherosa Ziehau } 112999fe2010SSepherosa Ziehau ctx.ale_busaddr = 0; 113099fe2010SSepherosa Ziehau error = bus_dmamap_load(sc->ale_cdata.ale_rx_page[i].cmb_tag, 113199fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].cmb_map, 113299fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].cmb_addr, 113399fe2010SSepherosa Ziehau ALE_RX_CMB_SZ, ale_dmamap_cb, &ctx, 0); 113499fe2010SSepherosa Ziehau if (error != 0 || ctx.ale_busaddr == 0) { 113599fe2010SSepherosa Ziehau device_printf(sc->ale_dev, "could not load DMA'able " 113699fe2010SSepherosa Ziehau "memory for Rx page %d CMB.\n", i); 113799fe2010SSepherosa Ziehau goto fail; 113899fe2010SSepherosa Ziehau } 113999fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].cmb_paddr = ctx.ale_busaddr; 114099fe2010SSepherosa Ziehau } 114199fe2010SSepherosa Ziehau 114299fe2010SSepherosa Ziehau /* 114399fe2010SSepherosa Ziehau * Tx descriptors/RXF0/CMB DMA blocks share the same 114499fe2010SSepherosa Ziehau * high address region of 64bit DMA address space. 114599fe2010SSepherosa Ziehau */ 114699fe2010SSepherosa Ziehau if (lowaddr != BUS_SPACE_MAXADDR_32BIT && 114799fe2010SSepherosa Ziehau (error = ale_check_boundary(sc)) != 0) { 114899fe2010SSepherosa Ziehau device_printf(sc->ale_dev, "4GB boundary crossed, " 114999fe2010SSepherosa Ziehau "switching to 32bit DMA addressing mode.\n"); 115099fe2010SSepherosa Ziehau ale_dma_free(sc); 115199fe2010SSepherosa Ziehau /* 115299fe2010SSepherosa Ziehau * Limit max allowable DMA address space to 32bit 115399fe2010SSepherosa Ziehau * and try again. 115499fe2010SSepherosa Ziehau */ 115599fe2010SSepherosa Ziehau lowaddr = BUS_SPACE_MAXADDR_32BIT; 115699fe2010SSepherosa Ziehau goto again; 115799fe2010SSepherosa Ziehau } 115899fe2010SSepherosa Ziehau 115999fe2010SSepherosa Ziehau /* 116099fe2010SSepherosa Ziehau * Create Tx buffer parent tag. 116199fe2010SSepherosa Ziehau * AR81xx allows 64bit DMA addressing of Tx buffers so it 116299fe2010SSepherosa Ziehau * needs separate parent DMA tag as parent DMA address space 116399fe2010SSepherosa Ziehau * could be restricted to be within 32bit address space by 116499fe2010SSepherosa Ziehau * 4GB boundary crossing. 116599fe2010SSepherosa Ziehau */ 116699fe2010SSepherosa Ziehau error = bus_dma_tag_create( 116799fe2010SSepherosa Ziehau NULL, /* parent */ 116899fe2010SSepherosa Ziehau 1, 0, /* alignment, boundary */ 116999fe2010SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 117099fe2010SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 117199fe2010SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 117299fe2010SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 117399fe2010SSepherosa Ziehau 0, /* nsegments */ 117499fe2010SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 117599fe2010SSepherosa Ziehau 0, /* flags */ 117699fe2010SSepherosa Ziehau &sc->ale_cdata.ale_buffer_tag); 117799fe2010SSepherosa Ziehau if (error != 0) { 117899fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 117999fe2010SSepherosa Ziehau "could not create parent buffer DMA tag.\n"); 118099fe2010SSepherosa Ziehau goto fail; 118199fe2010SSepherosa Ziehau } 118299fe2010SSepherosa Ziehau 118399fe2010SSepherosa Ziehau /* Create DMA tag for Tx buffers. */ 118499fe2010SSepherosa Ziehau error = bus_dma_tag_create( 118599fe2010SSepherosa Ziehau sc->ale_cdata.ale_buffer_tag, /* parent */ 118699fe2010SSepherosa Ziehau 1, 0, /* alignment, boundary */ 118799fe2010SSepherosa Ziehau BUS_SPACE_MAXADDR, /* lowaddr */ 118899fe2010SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 118999fe2010SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 119099fe2010SSepherosa Ziehau ALE_TSO_MAXSIZE, /* maxsize */ 119199fe2010SSepherosa Ziehau ALE_MAXTXSEGS, /* nsegments */ 119299fe2010SSepherosa Ziehau ALE_TSO_MAXSEGSIZE, /* maxsegsize */ 119399fe2010SSepherosa Ziehau 0, /* flags */ 119499fe2010SSepherosa Ziehau &sc->ale_cdata.ale_tx_tag); 119599fe2010SSepherosa Ziehau if (error != 0) { 119699fe2010SSepherosa Ziehau device_printf(sc->ale_dev, "could not create Tx DMA tag.\n"); 119799fe2010SSepherosa Ziehau goto fail; 119899fe2010SSepherosa Ziehau } 119999fe2010SSepherosa Ziehau 120099fe2010SSepherosa Ziehau /* Create DMA maps for Tx buffers. */ 120199fe2010SSepherosa Ziehau for (i = 0; i < ALE_TX_RING_CNT; i++) { 120299fe2010SSepherosa Ziehau txd = &sc->ale_cdata.ale_txdesc[i]; 120399fe2010SSepherosa Ziehau txd->tx_m = NULL; 120499fe2010SSepherosa Ziehau txd->tx_dmamap = NULL; 120599fe2010SSepherosa Ziehau error = bus_dmamap_create(sc->ale_cdata.ale_tx_tag, 0, 120699fe2010SSepherosa Ziehau &txd->tx_dmamap); 120799fe2010SSepherosa Ziehau if (error != 0) { 120899fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 120999fe2010SSepherosa Ziehau "could not create Tx dmamap.\n"); 121099fe2010SSepherosa Ziehau goto fail; 121199fe2010SSepherosa Ziehau } 121299fe2010SSepherosa Ziehau } 121399fe2010SSepherosa Ziehau fail: 121499fe2010SSepherosa Ziehau return (error); 121599fe2010SSepherosa Ziehau } 121699fe2010SSepherosa Ziehau 121799fe2010SSepherosa Ziehau static void 121899fe2010SSepherosa Ziehau ale_dma_free(struct ale_softc *sc) 121999fe2010SSepherosa Ziehau { 122099fe2010SSepherosa Ziehau struct ale_txdesc *txd; 122199fe2010SSepherosa Ziehau int i; 122299fe2010SSepherosa Ziehau 122399fe2010SSepherosa Ziehau /* Tx buffers. */ 122499fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_tx_tag != NULL) { 122599fe2010SSepherosa Ziehau for (i = 0; i < ALE_TX_RING_CNT; i++) { 122699fe2010SSepherosa Ziehau txd = &sc->ale_cdata.ale_txdesc[i]; 122799fe2010SSepherosa Ziehau if (txd->tx_dmamap != NULL) { 122899fe2010SSepherosa Ziehau bus_dmamap_destroy(sc->ale_cdata.ale_tx_tag, 122999fe2010SSepherosa Ziehau txd->tx_dmamap); 123099fe2010SSepherosa Ziehau txd->tx_dmamap = NULL; 123199fe2010SSepherosa Ziehau } 123299fe2010SSepherosa Ziehau } 123399fe2010SSepherosa Ziehau bus_dma_tag_destroy(sc->ale_cdata.ale_tx_tag); 123499fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_tag = NULL; 123599fe2010SSepherosa Ziehau } 123699fe2010SSepherosa Ziehau /* Tx descriptor ring. */ 123799fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_tx_ring_tag != NULL) { 123899fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_tx_ring_map != NULL) 123999fe2010SSepherosa Ziehau bus_dmamap_unload(sc->ale_cdata.ale_tx_ring_tag, 124099fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_ring_map); 124199fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_tx_ring_map != NULL && 124299fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_ring != NULL) 124399fe2010SSepherosa Ziehau bus_dmamem_free(sc->ale_cdata.ale_tx_ring_tag, 124499fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_ring, 124599fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_ring_map); 124699fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_ring = NULL; 124799fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_ring_map = NULL; 124899fe2010SSepherosa Ziehau bus_dma_tag_destroy(sc->ale_cdata.ale_tx_ring_tag); 124999fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_ring_tag = NULL; 125099fe2010SSepherosa Ziehau } 125199fe2010SSepherosa Ziehau /* Rx page block. */ 125299fe2010SSepherosa Ziehau for (i = 0; i < ALE_RX_PAGES; i++) { 125399fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_rx_page[i].page_tag != NULL) { 125499fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_rx_page[i].page_map != NULL) 125599fe2010SSepherosa Ziehau bus_dmamap_unload( 125699fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].page_tag, 125799fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].page_map); 125899fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_rx_page[i].page_map != NULL && 125999fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].page_addr != NULL) 126099fe2010SSepherosa Ziehau bus_dmamem_free( 126199fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].page_tag, 126299fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].page_addr, 126399fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].page_map); 126499fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].page_addr = NULL; 126599fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].page_map = NULL; 126699fe2010SSepherosa Ziehau bus_dma_tag_destroy( 126799fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].page_tag); 126899fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].page_tag = NULL; 126999fe2010SSepherosa Ziehau } 127099fe2010SSepherosa Ziehau } 127199fe2010SSepherosa Ziehau /* Rx CMB. */ 127299fe2010SSepherosa Ziehau for (i = 0; i < ALE_RX_PAGES; i++) { 127399fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_rx_page[i].cmb_tag != NULL) { 127499fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_rx_page[i].cmb_map != NULL) 127599fe2010SSepherosa Ziehau bus_dmamap_unload( 127699fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].cmb_tag, 127799fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].cmb_map); 127899fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_rx_page[i].cmb_map != NULL && 127999fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].cmb_addr != NULL) 128099fe2010SSepherosa Ziehau bus_dmamem_free( 128199fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].cmb_tag, 128299fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].cmb_addr, 128399fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].cmb_map); 128499fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].cmb_addr = NULL; 128599fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].cmb_map = NULL; 128699fe2010SSepherosa Ziehau bus_dma_tag_destroy( 128799fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].cmb_tag); 128899fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_page[i].cmb_tag = NULL; 128999fe2010SSepherosa Ziehau } 129099fe2010SSepherosa Ziehau } 129199fe2010SSepherosa Ziehau /* Tx CMB. */ 129299fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_tx_cmb_tag != NULL) { 129399fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_tx_cmb_map != NULL) 129499fe2010SSepherosa Ziehau bus_dmamap_unload(sc->ale_cdata.ale_tx_cmb_tag, 129599fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_cmb_map); 129699fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_tx_cmb_map != NULL && 129799fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_cmb != NULL) 129899fe2010SSepherosa Ziehau bus_dmamem_free(sc->ale_cdata.ale_tx_cmb_tag, 129999fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_cmb, 130099fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_cmb_map); 130199fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_cmb = NULL; 130299fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_cmb_map = NULL; 130399fe2010SSepherosa Ziehau bus_dma_tag_destroy(sc->ale_cdata.ale_tx_cmb_tag); 130499fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_cmb_tag = NULL; 130599fe2010SSepherosa Ziehau } 130699fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_buffer_tag != NULL) { 130799fe2010SSepherosa Ziehau bus_dma_tag_destroy(sc->ale_cdata.ale_buffer_tag); 130899fe2010SSepherosa Ziehau sc->ale_cdata.ale_buffer_tag = NULL; 130999fe2010SSepherosa Ziehau } 131099fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_parent_tag != NULL) { 131199fe2010SSepherosa Ziehau bus_dma_tag_destroy(sc->ale_cdata.ale_parent_tag); 131299fe2010SSepherosa Ziehau sc->ale_cdata.ale_parent_tag = NULL; 131399fe2010SSepherosa Ziehau } 131499fe2010SSepherosa Ziehau } 131599fe2010SSepherosa Ziehau 131699fe2010SSepherosa Ziehau static int 131799fe2010SSepherosa Ziehau ale_shutdown(device_t dev) 131899fe2010SSepherosa Ziehau { 131999fe2010SSepherosa Ziehau return (ale_suspend(dev)); 132099fe2010SSepherosa Ziehau } 132199fe2010SSepherosa Ziehau 132299fe2010SSepherosa Ziehau #ifdef notyet 132399fe2010SSepherosa Ziehau 132499fe2010SSepherosa Ziehau /* 132599fe2010SSepherosa Ziehau * Note, this driver resets the link speed to 10/100Mbps by 132699fe2010SSepherosa Ziehau * restarting auto-negotiation in suspend/shutdown phase but we 132799fe2010SSepherosa Ziehau * don't know whether that auto-negotiation would succeed or not 132899fe2010SSepherosa Ziehau * as driver has no control after powering off/suspend operation. 132999fe2010SSepherosa Ziehau * If the renegotiation fail WOL may not work. Running at 1Gbps 133099fe2010SSepherosa Ziehau * will draw more power than 375mA at 3.3V which is specified in 133199fe2010SSepherosa Ziehau * PCI specification and that would result in complete 133299fe2010SSepherosa Ziehau * shutdowning power to ethernet controller. 133399fe2010SSepherosa Ziehau * 133499fe2010SSepherosa Ziehau * TODO 133599fe2010SSepherosa Ziehau * Save current negotiated media speed/duplex/flow-control to 133699fe2010SSepherosa Ziehau * softc and restore the same link again after resuming. PHY 133799fe2010SSepherosa Ziehau * handling such as power down/resetting to 100Mbps may be better 133899fe2010SSepherosa Ziehau * handled in suspend method in phy driver. 133999fe2010SSepherosa Ziehau */ 134099fe2010SSepherosa Ziehau static void 134199fe2010SSepherosa Ziehau ale_setlinkspeed(struct ale_softc *sc) 134299fe2010SSepherosa Ziehau { 134399fe2010SSepherosa Ziehau struct mii_data *mii; 134499fe2010SSepherosa Ziehau int aneg, i; 134599fe2010SSepherosa Ziehau 134699fe2010SSepherosa Ziehau mii = device_get_softc(sc->ale_miibus); 134799fe2010SSepherosa Ziehau mii_pollstat(mii); 134899fe2010SSepherosa Ziehau aneg = 0; 134999fe2010SSepherosa Ziehau if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 135099fe2010SSepherosa Ziehau (IFM_ACTIVE | IFM_AVALID)) { 135199fe2010SSepherosa Ziehau switch IFM_SUBTYPE(mii->mii_media_active) { 135299fe2010SSepherosa Ziehau case IFM_10_T: 135399fe2010SSepherosa Ziehau case IFM_100_TX: 135499fe2010SSepherosa Ziehau return; 135599fe2010SSepherosa Ziehau case IFM_1000_T: 135699fe2010SSepherosa Ziehau aneg++; 135799fe2010SSepherosa Ziehau break; 135899fe2010SSepherosa Ziehau default: 135999fe2010SSepherosa Ziehau break; 136099fe2010SSepherosa Ziehau } 136199fe2010SSepherosa Ziehau } 136299fe2010SSepherosa Ziehau ale_miibus_writereg(sc->ale_dev, sc->ale_phyaddr, MII_100T2CR, 0); 136399fe2010SSepherosa Ziehau ale_miibus_writereg(sc->ale_dev, sc->ale_phyaddr, 136499fe2010SSepherosa Ziehau MII_ANAR, ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA); 136599fe2010SSepherosa Ziehau ale_miibus_writereg(sc->ale_dev, sc->ale_phyaddr, 136699fe2010SSepherosa Ziehau MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); 136799fe2010SSepherosa Ziehau DELAY(1000); 136899fe2010SSepherosa Ziehau if (aneg != 0) { 136999fe2010SSepherosa Ziehau /* 137099fe2010SSepherosa Ziehau * Poll link state until ale(4) get a 10/100Mbps link. 137199fe2010SSepherosa Ziehau */ 137299fe2010SSepherosa Ziehau for (i = 0; i < MII_ANEGTICKS_GIGE; i++) { 137399fe2010SSepherosa Ziehau mii_pollstat(mii); 137499fe2010SSepherosa Ziehau if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) 137599fe2010SSepherosa Ziehau == (IFM_ACTIVE | IFM_AVALID)) { 137699fe2010SSepherosa Ziehau switch (IFM_SUBTYPE( 137799fe2010SSepherosa Ziehau mii->mii_media_active)) { 137899fe2010SSepherosa Ziehau case IFM_10_T: 137999fe2010SSepherosa Ziehau case IFM_100_TX: 138099fe2010SSepherosa Ziehau ale_mac_config(sc); 138199fe2010SSepherosa Ziehau return; 138299fe2010SSepherosa Ziehau default: 138399fe2010SSepherosa Ziehau break; 138499fe2010SSepherosa Ziehau } 138599fe2010SSepherosa Ziehau } 138699fe2010SSepherosa Ziehau ALE_UNLOCK(sc); 138799fe2010SSepherosa Ziehau pause("alelnk", hz); 138899fe2010SSepherosa Ziehau ALE_LOCK(sc); 138999fe2010SSepherosa Ziehau } 139099fe2010SSepherosa Ziehau if (i == MII_ANEGTICKS_GIGE) 139199fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 139299fe2010SSepherosa Ziehau "establishing a link failed, WOL may not work!"); 139399fe2010SSepherosa Ziehau } 139499fe2010SSepherosa Ziehau /* 139599fe2010SSepherosa Ziehau * No link, force MAC to have 100Mbps, full-duplex link. 139699fe2010SSepherosa Ziehau * This is the last resort and may/may not work. 139799fe2010SSepherosa Ziehau */ 139899fe2010SSepherosa Ziehau mii->mii_media_status = IFM_AVALID | IFM_ACTIVE; 139999fe2010SSepherosa Ziehau mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX; 140099fe2010SSepherosa Ziehau ale_mac_config(sc); 140199fe2010SSepherosa Ziehau } 140299fe2010SSepherosa Ziehau 140399fe2010SSepherosa Ziehau static void 140499fe2010SSepherosa Ziehau ale_setwol(struct ale_softc *sc) 140599fe2010SSepherosa Ziehau { 140699fe2010SSepherosa Ziehau struct ifnet *ifp; 140799fe2010SSepherosa Ziehau uint32_t reg, pmcs; 140899fe2010SSepherosa Ziehau uint16_t pmstat; 140999fe2010SSepherosa Ziehau int pmc; 141099fe2010SSepherosa Ziehau 141199fe2010SSepherosa Ziehau ALE_LOCK_ASSERT(sc); 141299fe2010SSepherosa Ziehau 141399fe2010SSepherosa Ziehau if (pci_find_extcap(sc->ale_dev, PCIY_PMG, &pmc) != 0) { 141499fe2010SSepherosa Ziehau /* Disable WOL. */ 141599fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_WOL_CFG, 0); 141699fe2010SSepherosa Ziehau reg = CSR_READ_4(sc, ALE_PCIE_PHYMISC); 141799fe2010SSepherosa Ziehau reg |= PCIE_PHYMISC_FORCE_RCV_DET; 141899fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_PCIE_PHYMISC, reg); 141999fe2010SSepherosa Ziehau /* Force PHY power down. */ 142099fe2010SSepherosa Ziehau CSR_WRITE_2(sc, ALE_GPHY_CTRL, 142199fe2010SSepherosa Ziehau GPHY_CTRL_EXT_RESET | GPHY_CTRL_HIB_EN | 142299fe2010SSepherosa Ziehau GPHY_CTRL_HIB_PULSE | GPHY_CTRL_PHY_PLL_ON | 142399fe2010SSepherosa Ziehau GPHY_CTRL_SEL_ANA_RESET | GPHY_CTRL_PHY_IDDQ | 142499fe2010SSepherosa Ziehau GPHY_CTRL_PCLK_SEL_DIS | GPHY_CTRL_PWDOWN_HW); 142599fe2010SSepherosa Ziehau return; 142699fe2010SSepherosa Ziehau } 142799fe2010SSepherosa Ziehau 142899fe2010SSepherosa Ziehau ifp = sc->ale_ifp; 142999fe2010SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_WOL) != 0) { 143099fe2010SSepherosa Ziehau if ((sc->ale_flags & ALE_FLAG_FASTETHER) == 0) 143199fe2010SSepherosa Ziehau ale_setlinkspeed(sc); 143299fe2010SSepherosa Ziehau } 143399fe2010SSepherosa Ziehau 143499fe2010SSepherosa Ziehau pmcs = 0; 143599fe2010SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) 143699fe2010SSepherosa Ziehau pmcs |= WOL_CFG_MAGIC | WOL_CFG_MAGIC_ENB; 143799fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_WOL_CFG, pmcs); 143899fe2010SSepherosa Ziehau reg = CSR_READ_4(sc, ALE_MAC_CFG); 143999fe2010SSepherosa Ziehau reg &= ~(MAC_CFG_DBG | MAC_CFG_PROMISC | MAC_CFG_ALLMULTI | 144099fe2010SSepherosa Ziehau MAC_CFG_BCAST); 144199fe2010SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0) 144299fe2010SSepherosa Ziehau reg |= MAC_CFG_ALLMULTI | MAC_CFG_BCAST; 144399fe2010SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_WOL) != 0) 144499fe2010SSepherosa Ziehau reg |= MAC_CFG_RX_ENB; 144599fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_MAC_CFG, reg); 144699fe2010SSepherosa Ziehau 144799fe2010SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_WOL) == 0) { 144899fe2010SSepherosa Ziehau /* WOL disabled, PHY power down. */ 144999fe2010SSepherosa Ziehau reg = CSR_READ_4(sc, ALE_PCIE_PHYMISC); 145099fe2010SSepherosa Ziehau reg |= PCIE_PHYMISC_FORCE_RCV_DET; 145199fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_PCIE_PHYMISC, reg); 145299fe2010SSepherosa Ziehau CSR_WRITE_2(sc, ALE_GPHY_CTRL, 145399fe2010SSepherosa Ziehau GPHY_CTRL_EXT_RESET | GPHY_CTRL_HIB_EN | 145499fe2010SSepherosa Ziehau GPHY_CTRL_HIB_PULSE | GPHY_CTRL_SEL_ANA_RESET | 145599fe2010SSepherosa Ziehau GPHY_CTRL_PHY_IDDQ | GPHY_CTRL_PCLK_SEL_DIS | 145699fe2010SSepherosa Ziehau GPHY_CTRL_PWDOWN_HW); 145799fe2010SSepherosa Ziehau } 145899fe2010SSepherosa Ziehau /* Request PME. */ 145999fe2010SSepherosa Ziehau pmstat = pci_read_config(sc->ale_dev, pmc + PCIR_POWER_STATUS, 2); 146099fe2010SSepherosa Ziehau pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); 146199fe2010SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_WOL) != 0) 146299fe2010SSepherosa Ziehau pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; 146399fe2010SSepherosa Ziehau pci_write_config(sc->ale_dev, pmc + PCIR_POWER_STATUS, pmstat, 2); 146499fe2010SSepherosa Ziehau } 146599fe2010SSepherosa Ziehau 146699fe2010SSepherosa Ziehau #endif /* notyet */ 146799fe2010SSepherosa Ziehau 146899fe2010SSepherosa Ziehau static int 146999fe2010SSepherosa Ziehau ale_suspend(device_t dev) 147099fe2010SSepherosa Ziehau { 147199fe2010SSepherosa Ziehau struct ale_softc *sc = device_get_softc(dev); 147299fe2010SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 147399fe2010SSepherosa Ziehau 147499fe2010SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 147599fe2010SSepherosa Ziehau ale_stop(sc); 147699fe2010SSepherosa Ziehau #ifdef notyet 147799fe2010SSepherosa Ziehau ale_setwol(sc); 147899fe2010SSepherosa Ziehau #endif 147999fe2010SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 148099fe2010SSepherosa Ziehau return (0); 148199fe2010SSepherosa Ziehau } 148299fe2010SSepherosa Ziehau 148399fe2010SSepherosa Ziehau static int 148499fe2010SSepherosa Ziehau ale_resume(device_t dev) 148599fe2010SSepherosa Ziehau { 148699fe2010SSepherosa Ziehau struct ale_softc *sc = device_get_softc(dev); 148799fe2010SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 148899fe2010SSepherosa Ziehau uint16_t cmd; 148999fe2010SSepherosa Ziehau 149099fe2010SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 149199fe2010SSepherosa Ziehau 149299fe2010SSepherosa Ziehau /* 149399fe2010SSepherosa Ziehau * Clear INTx emulation disable for hardwares that 149499fe2010SSepherosa Ziehau * is set in resume event. From Linux. 149599fe2010SSepherosa Ziehau */ 149699fe2010SSepherosa Ziehau cmd = pci_read_config(sc->ale_dev, PCIR_COMMAND, 2); 149799fe2010SSepherosa Ziehau if ((cmd & 0x0400) != 0) { 149899fe2010SSepherosa Ziehau cmd &= ~0x0400; 149999fe2010SSepherosa Ziehau pci_write_config(sc->ale_dev, PCIR_COMMAND, cmd, 2); 150099fe2010SSepherosa Ziehau } 150199fe2010SSepherosa Ziehau 150299fe2010SSepherosa Ziehau #ifdef notyet 150399fe2010SSepherosa Ziehau if (pci_find_extcap(sc->ale_dev, PCIY_PMG, &pmc) == 0) { 150499fe2010SSepherosa Ziehau uint16_t pmstat; 150599fe2010SSepherosa Ziehau int pmc; 150699fe2010SSepherosa Ziehau 150799fe2010SSepherosa Ziehau /* Disable PME and clear PME status. */ 150899fe2010SSepherosa Ziehau pmstat = pci_read_config(sc->ale_dev, 150999fe2010SSepherosa Ziehau pmc + PCIR_POWER_STATUS, 2); 151099fe2010SSepherosa Ziehau if ((pmstat & PCIM_PSTAT_PMEENABLE) != 0) { 151199fe2010SSepherosa Ziehau pmstat &= ~PCIM_PSTAT_PMEENABLE; 151299fe2010SSepherosa Ziehau pci_write_config(sc->ale_dev, 151399fe2010SSepherosa Ziehau pmc + PCIR_POWER_STATUS, pmstat, 2); 151499fe2010SSepherosa Ziehau } 151599fe2010SSepherosa Ziehau } 151699fe2010SSepherosa Ziehau #endif 151799fe2010SSepherosa Ziehau 151899fe2010SSepherosa Ziehau /* Reset PHY. */ 151999fe2010SSepherosa Ziehau ale_phy_reset(sc); 152099fe2010SSepherosa Ziehau if ((ifp->if_flags & IFF_UP) != 0) 152199fe2010SSepherosa Ziehau ale_init(sc); 152299fe2010SSepherosa Ziehau 152399fe2010SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 152499fe2010SSepherosa Ziehau return (0); 152599fe2010SSepherosa Ziehau } 152699fe2010SSepherosa Ziehau 152799fe2010SSepherosa Ziehau static int 152899fe2010SSepherosa Ziehau ale_encap(struct ale_softc *sc, struct mbuf **m_head) 152999fe2010SSepherosa Ziehau { 153099fe2010SSepherosa Ziehau struct ale_txdesc *txd, *txd_last; 153199fe2010SSepherosa Ziehau struct tx_desc *desc; 153299fe2010SSepherosa Ziehau struct mbuf *m; 153399fe2010SSepherosa Ziehau bus_dma_segment_t txsegs[ALE_MAXTXSEGS]; 153499fe2010SSepherosa Ziehau struct ale_dmamap_ctx ctx; 153599fe2010SSepherosa Ziehau bus_dmamap_t map; 153699fe2010SSepherosa Ziehau uint32_t cflags, poff, vtag; 1537*51c70c94SSascha Wildner int error, i, nsegs, prod; 153899fe2010SSepherosa Ziehau 153999fe2010SSepherosa Ziehau M_ASSERTPKTHDR((*m_head)); 154099fe2010SSepherosa Ziehau 154199fe2010SSepherosa Ziehau m = *m_head; 154299fe2010SSepherosa Ziehau cflags = vtag = 0; 154399fe2010SSepherosa Ziehau poff = 0; 154499fe2010SSepherosa Ziehau 1545*51c70c94SSascha Wildner prod = sc->ale_cdata.ale_tx_prod; 154699fe2010SSepherosa Ziehau txd = &sc->ale_cdata.ale_txdesc[prod]; 154799fe2010SSepherosa Ziehau txd_last = txd; 154899fe2010SSepherosa Ziehau map = txd->tx_dmamap; 154999fe2010SSepherosa Ziehau 155099fe2010SSepherosa Ziehau ctx.nsegs = ALE_MAXTXSEGS; 155199fe2010SSepherosa Ziehau ctx.segs = txsegs; 155299fe2010SSepherosa Ziehau error = bus_dmamap_load_mbuf(sc->ale_cdata.ale_tx_tag, map, 155399fe2010SSepherosa Ziehau *m_head, ale_dmamap_buf_cb, &ctx, 155499fe2010SSepherosa Ziehau BUS_DMA_NOWAIT); 155599fe2010SSepherosa Ziehau if (error == EFBIG) { 155699fe2010SSepherosa Ziehau m = m_defrag(*m_head, MB_DONTWAIT); 155799fe2010SSepherosa Ziehau if (m == NULL) { 155899fe2010SSepherosa Ziehau m_freem(*m_head); 155999fe2010SSepherosa Ziehau *m_head = NULL; 156099fe2010SSepherosa Ziehau return (ENOMEM); 156199fe2010SSepherosa Ziehau } 156299fe2010SSepherosa Ziehau *m_head = m; 156399fe2010SSepherosa Ziehau 156499fe2010SSepherosa Ziehau ctx.nsegs = ALE_MAXTXSEGS; 156599fe2010SSepherosa Ziehau ctx.segs = txsegs; 156699fe2010SSepherosa Ziehau error = bus_dmamap_load_mbuf(sc->ale_cdata.ale_tx_tag, map, 156799fe2010SSepherosa Ziehau *m_head, ale_dmamap_buf_cb, &ctx, 156899fe2010SSepherosa Ziehau BUS_DMA_NOWAIT); 156999fe2010SSepherosa Ziehau if (error != 0) { 157099fe2010SSepherosa Ziehau m_freem(*m_head); 157199fe2010SSepherosa Ziehau *m_head = NULL; 157299fe2010SSepherosa Ziehau return (error); 157399fe2010SSepherosa Ziehau } 157499fe2010SSepherosa Ziehau } else if (error != 0) { 157599fe2010SSepherosa Ziehau return (error); 157699fe2010SSepherosa Ziehau } 157799fe2010SSepherosa Ziehau nsegs = ctx.nsegs; 157899fe2010SSepherosa Ziehau 157999fe2010SSepherosa Ziehau if (nsegs == 0) { 158099fe2010SSepherosa Ziehau m_freem(*m_head); 158199fe2010SSepherosa Ziehau *m_head = NULL; 158299fe2010SSepherosa Ziehau return (EIO); 158399fe2010SSepherosa Ziehau } 158499fe2010SSepherosa Ziehau 158599fe2010SSepherosa Ziehau /* Check descriptor overrun. */ 158699fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_tx_cnt + nsegs >= ALE_TX_RING_CNT - 2) { 158799fe2010SSepherosa Ziehau bus_dmamap_unload(sc->ale_cdata.ale_tx_tag, map); 158899fe2010SSepherosa Ziehau return (ENOBUFS); 158999fe2010SSepherosa Ziehau } 159099fe2010SSepherosa Ziehau bus_dmamap_sync(sc->ale_cdata.ale_tx_tag, map, BUS_DMASYNC_PREWRITE); 159199fe2010SSepherosa Ziehau 159299fe2010SSepherosa Ziehau m = *m_head; 159399fe2010SSepherosa Ziehau /* Configure Tx checksum offload. */ 159499fe2010SSepherosa Ziehau if ((m->m_pkthdr.csum_flags & ALE_CSUM_FEATURES) != 0) { 159599fe2010SSepherosa Ziehau /* 159699fe2010SSepherosa Ziehau * AR81xx supports Tx custom checksum offload feature 159799fe2010SSepherosa Ziehau * that offloads single 16bit checksum computation. 159899fe2010SSepherosa Ziehau * So you can choose one among IP, TCP and UDP. 159999fe2010SSepherosa Ziehau * Normally driver sets checksum start/insertion 160099fe2010SSepherosa Ziehau * position from the information of TCP/UDP frame as 160199fe2010SSepherosa Ziehau * TCP/UDP checksum takes more time than that of IP. 160299fe2010SSepherosa Ziehau * However it seems that custom checksum offload 160399fe2010SSepherosa Ziehau * requires 4 bytes aligned Tx buffers due to hardware 160499fe2010SSepherosa Ziehau * bug. 160599fe2010SSepherosa Ziehau * AR81xx also supports explicit Tx checksum computation 160699fe2010SSepherosa Ziehau * if it is told that the size of IP header and TCP 160799fe2010SSepherosa Ziehau * header(for UDP, the header size does not matter 160899fe2010SSepherosa Ziehau * because it's fixed length). However with this scheme 160999fe2010SSepherosa Ziehau * TSO does not work so you have to choose one either 161099fe2010SSepherosa Ziehau * TSO or explicit Tx checksum offload. I chosen TSO 161199fe2010SSepherosa Ziehau * plus custom checksum offload with work-around which 161299fe2010SSepherosa Ziehau * will cover most common usage for this consumer 161399fe2010SSepherosa Ziehau * ethernet controller. The work-around takes a lot of 161499fe2010SSepherosa Ziehau * CPU cycles if Tx buffer is not aligned on 4 bytes 161599fe2010SSepherosa Ziehau * boundary, though. 161699fe2010SSepherosa Ziehau */ 161799fe2010SSepherosa Ziehau cflags |= ALE_TD_CXSUM; 161899fe2010SSepherosa Ziehau /* Set checksum start offset. */ 161999fe2010SSepherosa Ziehau cflags |= (poff << ALE_TD_CSUM_PLOADOFFSET_SHIFT); 162099fe2010SSepherosa Ziehau /* Set checksum insertion position of TCP/UDP. */ 162199fe2010SSepherosa Ziehau cflags |= ((poff + m->m_pkthdr.csum_data) << 162299fe2010SSepherosa Ziehau ALE_TD_CSUM_XSUMOFFSET_SHIFT); 162399fe2010SSepherosa Ziehau } 162499fe2010SSepherosa Ziehau 162599fe2010SSepherosa Ziehau /* Configure VLAN hardware tag insertion. */ 162699fe2010SSepherosa Ziehau if ((m->m_flags & M_VLANTAG) != 0) { 162799fe2010SSepherosa Ziehau vtag = ALE_TX_VLAN_TAG(m->m_pkthdr.ether_vlantag); 162899fe2010SSepherosa Ziehau vtag = ((vtag << ALE_TD_VLAN_SHIFT) & ALE_TD_VLAN_MASK); 162999fe2010SSepherosa Ziehau cflags |= ALE_TD_INSERT_VLAN_TAG; 163099fe2010SSepherosa Ziehau } 163199fe2010SSepherosa Ziehau 163299fe2010SSepherosa Ziehau desc = NULL; 163399fe2010SSepherosa Ziehau for (i = 0; i < nsegs; i++) { 163499fe2010SSepherosa Ziehau desc = &sc->ale_cdata.ale_tx_ring[prod]; 163599fe2010SSepherosa Ziehau desc->addr = htole64(txsegs[i].ds_addr); 163699fe2010SSepherosa Ziehau desc->len = htole32(ALE_TX_BYTES(txsegs[i].ds_len) | vtag); 163799fe2010SSepherosa Ziehau desc->flags = htole32(cflags); 163899fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_cnt++; 163999fe2010SSepherosa Ziehau ALE_DESC_INC(prod, ALE_TX_RING_CNT); 164099fe2010SSepherosa Ziehau } 164199fe2010SSepherosa Ziehau /* Update producer index. */ 164299fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_prod = prod; 164399fe2010SSepherosa Ziehau 164499fe2010SSepherosa Ziehau /* Finally set EOP on the last descriptor. */ 164599fe2010SSepherosa Ziehau prod = (prod + ALE_TX_RING_CNT - 1) % ALE_TX_RING_CNT; 164699fe2010SSepherosa Ziehau desc = &sc->ale_cdata.ale_tx_ring[prod]; 164799fe2010SSepherosa Ziehau desc->flags |= htole32(ALE_TD_EOP); 164899fe2010SSepherosa Ziehau 164999fe2010SSepherosa Ziehau /* Swap dmamap of the first and the last. */ 165099fe2010SSepherosa Ziehau txd = &sc->ale_cdata.ale_txdesc[prod]; 165199fe2010SSepherosa Ziehau map = txd_last->tx_dmamap; 165299fe2010SSepherosa Ziehau txd_last->tx_dmamap = txd->tx_dmamap; 165399fe2010SSepherosa Ziehau txd->tx_dmamap = map; 165499fe2010SSepherosa Ziehau txd->tx_m = m; 165599fe2010SSepherosa Ziehau 165699fe2010SSepherosa Ziehau /* Sync descriptors. */ 165799fe2010SSepherosa Ziehau bus_dmamap_sync(sc->ale_cdata.ale_tx_ring_tag, 165899fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_ring_map, BUS_DMASYNC_PREWRITE); 165999fe2010SSepherosa Ziehau 166099fe2010SSepherosa Ziehau return (0); 166199fe2010SSepherosa Ziehau } 166299fe2010SSepherosa Ziehau 166399fe2010SSepherosa Ziehau static void 166499fe2010SSepherosa Ziehau ale_start(struct ifnet *ifp) 166599fe2010SSepherosa Ziehau { 166699fe2010SSepherosa Ziehau struct ale_softc *sc = ifp->if_softc; 166799fe2010SSepherosa Ziehau struct mbuf *m_head; 166899fe2010SSepherosa Ziehau int enq; 166999fe2010SSepherosa Ziehau 167099fe2010SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 167199fe2010SSepherosa Ziehau 167299fe2010SSepherosa Ziehau if ((sc->ale_flags & ALE_FLAG_LINK) == 0) { 167399fe2010SSepherosa Ziehau ifq_purge(&ifp->if_snd); 167499fe2010SSepherosa Ziehau return; 167599fe2010SSepherosa Ziehau } 167699fe2010SSepherosa Ziehau 16779ed293e0SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0 || ifq_is_oactive(&ifp->if_snd)) 167899fe2010SSepherosa Ziehau return; 167999fe2010SSepherosa Ziehau 168099fe2010SSepherosa Ziehau /* Reclaim transmitted frames. */ 168199fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_tx_cnt >= ALE_TX_DESC_HIWAT) 168299fe2010SSepherosa Ziehau ale_txeof(sc); 168399fe2010SSepherosa Ziehau 168499fe2010SSepherosa Ziehau enq = 0; 168599fe2010SSepherosa Ziehau while (!ifq_is_empty(&ifp->if_snd)) { 168699fe2010SSepherosa Ziehau m_head = ifq_dequeue(&ifp->if_snd, NULL); 168799fe2010SSepherosa Ziehau if (m_head == NULL) 168899fe2010SSepherosa Ziehau break; 168999fe2010SSepherosa Ziehau 169099fe2010SSepherosa Ziehau /* 169199fe2010SSepherosa Ziehau * Pack the data into the transmit ring. If we 169299fe2010SSepherosa Ziehau * don't have room, set the OACTIVE flag and wait 169399fe2010SSepherosa Ziehau * for the NIC to drain the ring. 169499fe2010SSepherosa Ziehau */ 169599fe2010SSepherosa Ziehau if (ale_encap(sc, &m_head)) { 169699fe2010SSepherosa Ziehau if (m_head == NULL) 169799fe2010SSepherosa Ziehau break; 169899fe2010SSepherosa Ziehau ifq_prepend(&ifp->if_snd, m_head); 16999ed293e0SSepherosa Ziehau ifq_set_oactive(&ifp->if_snd); 170099fe2010SSepherosa Ziehau break; 170199fe2010SSepherosa Ziehau } 170299fe2010SSepherosa Ziehau enq = 1; 170399fe2010SSepherosa Ziehau 170499fe2010SSepherosa Ziehau /* 170599fe2010SSepherosa Ziehau * If there's a BPF listener, bounce a copy of this frame 170699fe2010SSepherosa Ziehau * to him. 170799fe2010SSepherosa Ziehau */ 170899fe2010SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m_head); 170999fe2010SSepherosa Ziehau } 171099fe2010SSepherosa Ziehau 171199fe2010SSepherosa Ziehau if (enq) { 171299fe2010SSepherosa Ziehau /* Kick. */ 171399fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_MBOX_TPD_PROD_IDX, 171499fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_prod); 171599fe2010SSepherosa Ziehau 171699fe2010SSepherosa Ziehau /* Set a timeout in case the chip goes out to lunch. */ 171799fe2010SSepherosa Ziehau ifp->if_timer = ALE_TX_TIMEOUT; 171899fe2010SSepherosa Ziehau } 171999fe2010SSepherosa Ziehau } 172099fe2010SSepherosa Ziehau 172199fe2010SSepherosa Ziehau static void 172299fe2010SSepherosa Ziehau ale_watchdog(struct ifnet *ifp) 172399fe2010SSepherosa Ziehau { 172499fe2010SSepherosa Ziehau struct ale_softc *sc = ifp->if_softc; 172599fe2010SSepherosa Ziehau 172699fe2010SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 172799fe2010SSepherosa Ziehau 172899fe2010SSepherosa Ziehau if ((sc->ale_flags & ALE_FLAG_LINK) == 0) { 172999fe2010SSepherosa Ziehau if_printf(ifp, "watchdog timeout (lost link)\n"); 173099fe2010SSepherosa Ziehau ifp->if_oerrors++; 173199fe2010SSepherosa Ziehau ale_init(sc); 173299fe2010SSepherosa Ziehau return; 173399fe2010SSepherosa Ziehau } 173499fe2010SSepherosa Ziehau 173599fe2010SSepherosa Ziehau if_printf(ifp, "watchdog timeout -- resetting\n"); 173699fe2010SSepherosa Ziehau ifp->if_oerrors++; 173799fe2010SSepherosa Ziehau ale_init(sc); 173899fe2010SSepherosa Ziehau 173999fe2010SSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd)) 174099fe2010SSepherosa Ziehau if_devstart(ifp); 174199fe2010SSepherosa Ziehau } 174299fe2010SSepherosa Ziehau 174399fe2010SSepherosa Ziehau static int 174499fe2010SSepherosa Ziehau ale_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) 174599fe2010SSepherosa Ziehau { 174699fe2010SSepherosa Ziehau struct ale_softc *sc; 174799fe2010SSepherosa Ziehau struct ifreq *ifr; 174899fe2010SSepherosa Ziehau struct mii_data *mii; 174999fe2010SSepherosa Ziehau int error, mask; 175099fe2010SSepherosa Ziehau 175199fe2010SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 175299fe2010SSepherosa Ziehau 175399fe2010SSepherosa Ziehau sc = ifp->if_softc; 175499fe2010SSepherosa Ziehau ifr = (struct ifreq *)data; 175599fe2010SSepherosa Ziehau error = 0; 175699fe2010SSepherosa Ziehau 175799fe2010SSepherosa Ziehau switch (cmd) { 175899fe2010SSepherosa Ziehau case SIOCSIFMTU: 175999fe2010SSepherosa Ziehau if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ALE_JUMBO_MTU || 176099fe2010SSepherosa Ziehau ((sc->ale_flags & ALE_FLAG_JUMBO) == 0 && 176199fe2010SSepherosa Ziehau ifr->ifr_mtu > ETHERMTU)) 176299fe2010SSepherosa Ziehau error = EINVAL; 176399fe2010SSepherosa Ziehau else if (ifp->if_mtu != ifr->ifr_mtu) { 176499fe2010SSepherosa Ziehau ifp->if_mtu = ifr->ifr_mtu; 176599fe2010SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) != 0) 176699fe2010SSepherosa Ziehau ale_init(sc); 176799fe2010SSepherosa Ziehau } 176899fe2010SSepherosa Ziehau break; 176999fe2010SSepherosa Ziehau 177099fe2010SSepherosa Ziehau case SIOCSIFFLAGS: 177199fe2010SSepherosa Ziehau if ((ifp->if_flags & IFF_UP) != 0) { 177299fe2010SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) != 0) { 177399fe2010SSepherosa Ziehau if (((ifp->if_flags ^ sc->ale_if_flags) 177499fe2010SSepherosa Ziehau & (IFF_PROMISC | IFF_ALLMULTI)) != 0) 177599fe2010SSepherosa Ziehau ale_rxfilter(sc); 177699fe2010SSepherosa Ziehau } else { 177799fe2010SSepherosa Ziehau if ((sc->ale_flags & ALE_FLAG_DETACH) == 0) 177899fe2010SSepherosa Ziehau ale_init(sc); 177999fe2010SSepherosa Ziehau } 178099fe2010SSepherosa Ziehau } else { 178199fe2010SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) != 0) 178299fe2010SSepherosa Ziehau ale_stop(sc); 178399fe2010SSepherosa Ziehau } 178499fe2010SSepherosa Ziehau sc->ale_if_flags = ifp->if_flags; 178599fe2010SSepherosa Ziehau break; 178699fe2010SSepherosa Ziehau 178799fe2010SSepherosa Ziehau case SIOCADDMULTI: 178899fe2010SSepherosa Ziehau case SIOCDELMULTI: 178999fe2010SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) != 0) 179099fe2010SSepherosa Ziehau ale_rxfilter(sc); 179199fe2010SSepherosa Ziehau break; 179299fe2010SSepherosa Ziehau 179399fe2010SSepherosa Ziehau case SIOCSIFMEDIA: 179499fe2010SSepherosa Ziehau case SIOCGIFMEDIA: 179599fe2010SSepherosa Ziehau mii = device_get_softc(sc->ale_miibus); 179699fe2010SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 179799fe2010SSepherosa Ziehau break; 179899fe2010SSepherosa Ziehau 179999fe2010SSepherosa Ziehau case SIOCSIFCAP: 180099fe2010SSepherosa Ziehau mask = ifr->ifr_reqcap ^ ifp->if_capenable; 180199fe2010SSepherosa Ziehau if ((mask & IFCAP_TXCSUM) != 0 && 180299fe2010SSepherosa Ziehau (ifp->if_capabilities & IFCAP_TXCSUM) != 0) { 180399fe2010SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM; 180499fe2010SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 180599fe2010SSepherosa Ziehau ifp->if_hwassist |= ALE_CSUM_FEATURES; 180699fe2010SSepherosa Ziehau else 180799fe2010SSepherosa Ziehau ifp->if_hwassist &= ~ALE_CSUM_FEATURES; 180899fe2010SSepherosa Ziehau } 180999fe2010SSepherosa Ziehau if ((mask & IFCAP_RXCSUM) != 0 && 181099fe2010SSepherosa Ziehau (ifp->if_capabilities & IFCAP_RXCSUM) != 0) 181199fe2010SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM; 181299fe2010SSepherosa Ziehau 181399fe2010SSepherosa Ziehau if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && 181499fe2010SSepherosa Ziehau (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) { 181599fe2010SSepherosa Ziehau ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 181699fe2010SSepherosa Ziehau ale_rxvlan(sc); 181799fe2010SSepherosa Ziehau } 181899fe2010SSepherosa Ziehau break; 181999fe2010SSepherosa Ziehau 182099fe2010SSepherosa Ziehau default: 182199fe2010SSepherosa Ziehau error = ether_ioctl(ifp, cmd, data); 182299fe2010SSepherosa Ziehau break; 182399fe2010SSepherosa Ziehau } 182499fe2010SSepherosa Ziehau return (error); 182599fe2010SSepherosa Ziehau } 182699fe2010SSepherosa Ziehau 182799fe2010SSepherosa Ziehau static void 182899fe2010SSepherosa Ziehau ale_mac_config(struct ale_softc *sc) 182999fe2010SSepherosa Ziehau { 183099fe2010SSepherosa Ziehau struct mii_data *mii; 183199fe2010SSepherosa Ziehau uint32_t reg; 183299fe2010SSepherosa Ziehau 183399fe2010SSepherosa Ziehau mii = device_get_softc(sc->ale_miibus); 183499fe2010SSepherosa Ziehau reg = CSR_READ_4(sc, ALE_MAC_CFG); 183599fe2010SSepherosa Ziehau reg &= ~(MAC_CFG_FULL_DUPLEX | MAC_CFG_TX_FC | MAC_CFG_RX_FC | 183699fe2010SSepherosa Ziehau MAC_CFG_SPEED_MASK); 183799fe2010SSepherosa Ziehau /* Reprogram MAC with resolved speed/duplex. */ 183899fe2010SSepherosa Ziehau switch (IFM_SUBTYPE(mii->mii_media_active)) { 183999fe2010SSepherosa Ziehau case IFM_10_T: 184099fe2010SSepherosa Ziehau case IFM_100_TX: 184199fe2010SSepherosa Ziehau reg |= MAC_CFG_SPEED_10_100; 184299fe2010SSepherosa Ziehau break; 184399fe2010SSepherosa Ziehau case IFM_1000_T: 184499fe2010SSepherosa Ziehau reg |= MAC_CFG_SPEED_1000; 184599fe2010SSepherosa Ziehau break; 184699fe2010SSepherosa Ziehau } 184799fe2010SSepherosa Ziehau if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 184899fe2010SSepherosa Ziehau reg |= MAC_CFG_FULL_DUPLEX; 184999fe2010SSepherosa Ziehau #ifdef notyet 185099fe2010SSepherosa Ziehau if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) 185199fe2010SSepherosa Ziehau reg |= MAC_CFG_TX_FC; 185299fe2010SSepherosa Ziehau if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) 185399fe2010SSepherosa Ziehau reg |= MAC_CFG_RX_FC; 185499fe2010SSepherosa Ziehau #endif 185599fe2010SSepherosa Ziehau } 185699fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_MAC_CFG, reg); 185799fe2010SSepherosa Ziehau } 185899fe2010SSepherosa Ziehau 185999fe2010SSepherosa Ziehau static void 186099fe2010SSepherosa Ziehau ale_stats_clear(struct ale_softc *sc) 186199fe2010SSepherosa Ziehau { 186299fe2010SSepherosa Ziehau struct smb sb; 186399fe2010SSepherosa Ziehau uint32_t *reg; 186499fe2010SSepherosa Ziehau int i; 186599fe2010SSepherosa Ziehau 186699fe2010SSepherosa Ziehau for (reg = &sb.rx_frames, i = 0; reg <= &sb.rx_pkts_filtered; reg++) { 186799fe2010SSepherosa Ziehau CSR_READ_4(sc, ALE_RX_MIB_BASE + i); 186899fe2010SSepherosa Ziehau i += sizeof(uint32_t); 186999fe2010SSepherosa Ziehau } 187099fe2010SSepherosa Ziehau /* Read Tx statistics. */ 187199fe2010SSepherosa Ziehau for (reg = &sb.tx_frames, i = 0; reg <= &sb.tx_mcast_bytes; reg++) { 187299fe2010SSepherosa Ziehau CSR_READ_4(sc, ALE_TX_MIB_BASE + i); 187399fe2010SSepherosa Ziehau i += sizeof(uint32_t); 187499fe2010SSepherosa Ziehau } 187599fe2010SSepherosa Ziehau } 187699fe2010SSepherosa Ziehau 187799fe2010SSepherosa Ziehau static void 187899fe2010SSepherosa Ziehau ale_stats_update(struct ale_softc *sc) 187999fe2010SSepherosa Ziehau { 188099fe2010SSepherosa Ziehau struct ale_hw_stats *stat; 188199fe2010SSepherosa Ziehau struct smb sb, *smb; 188299fe2010SSepherosa Ziehau struct ifnet *ifp; 188399fe2010SSepherosa Ziehau uint32_t *reg; 188499fe2010SSepherosa Ziehau int i; 188599fe2010SSepherosa Ziehau 188699fe2010SSepherosa Ziehau ifp = &sc->arpcom.ac_if; 188799fe2010SSepherosa Ziehau stat = &sc->ale_stats; 188899fe2010SSepherosa Ziehau smb = &sb; 188999fe2010SSepherosa Ziehau 189099fe2010SSepherosa Ziehau /* Read Rx statistics. */ 189199fe2010SSepherosa Ziehau for (reg = &sb.rx_frames, i = 0; reg <= &sb.rx_pkts_filtered; reg++) { 189299fe2010SSepherosa Ziehau *reg = CSR_READ_4(sc, ALE_RX_MIB_BASE + i); 189399fe2010SSepherosa Ziehau i += sizeof(uint32_t); 189499fe2010SSepherosa Ziehau } 189599fe2010SSepherosa Ziehau /* Read Tx statistics. */ 189699fe2010SSepherosa Ziehau for (reg = &sb.tx_frames, i = 0; reg <= &sb.tx_mcast_bytes; reg++) { 189799fe2010SSepherosa Ziehau *reg = CSR_READ_4(sc, ALE_TX_MIB_BASE + i); 189899fe2010SSepherosa Ziehau i += sizeof(uint32_t); 189999fe2010SSepherosa Ziehau } 190099fe2010SSepherosa Ziehau 190199fe2010SSepherosa Ziehau /* Rx stats. */ 190299fe2010SSepherosa Ziehau stat->rx_frames += smb->rx_frames; 190399fe2010SSepherosa Ziehau stat->rx_bcast_frames += smb->rx_bcast_frames; 190499fe2010SSepherosa Ziehau stat->rx_mcast_frames += smb->rx_mcast_frames; 190599fe2010SSepherosa Ziehau stat->rx_pause_frames += smb->rx_pause_frames; 190699fe2010SSepherosa Ziehau stat->rx_control_frames += smb->rx_control_frames; 190799fe2010SSepherosa Ziehau stat->rx_crcerrs += smb->rx_crcerrs; 190899fe2010SSepherosa Ziehau stat->rx_lenerrs += smb->rx_lenerrs; 190999fe2010SSepherosa Ziehau stat->rx_bytes += smb->rx_bytes; 191099fe2010SSepherosa Ziehau stat->rx_runts += smb->rx_runts; 191199fe2010SSepherosa Ziehau stat->rx_fragments += smb->rx_fragments; 191299fe2010SSepherosa Ziehau stat->rx_pkts_64 += smb->rx_pkts_64; 191399fe2010SSepherosa Ziehau stat->rx_pkts_65_127 += smb->rx_pkts_65_127; 191499fe2010SSepherosa Ziehau stat->rx_pkts_128_255 += smb->rx_pkts_128_255; 191599fe2010SSepherosa Ziehau stat->rx_pkts_256_511 += smb->rx_pkts_256_511; 191699fe2010SSepherosa Ziehau stat->rx_pkts_512_1023 += smb->rx_pkts_512_1023; 191799fe2010SSepherosa Ziehau stat->rx_pkts_1024_1518 += smb->rx_pkts_1024_1518; 191899fe2010SSepherosa Ziehau stat->rx_pkts_1519_max += smb->rx_pkts_1519_max; 191999fe2010SSepherosa Ziehau stat->rx_pkts_truncated += smb->rx_pkts_truncated; 192099fe2010SSepherosa Ziehau stat->rx_fifo_oflows += smb->rx_fifo_oflows; 192199fe2010SSepherosa Ziehau stat->rx_rrs_errs += smb->rx_rrs_errs; 192299fe2010SSepherosa Ziehau stat->rx_alignerrs += smb->rx_alignerrs; 192399fe2010SSepherosa Ziehau stat->rx_bcast_bytes += smb->rx_bcast_bytes; 192499fe2010SSepherosa Ziehau stat->rx_mcast_bytes += smb->rx_mcast_bytes; 192599fe2010SSepherosa Ziehau stat->rx_pkts_filtered += smb->rx_pkts_filtered; 192699fe2010SSepherosa Ziehau 192799fe2010SSepherosa Ziehau /* Tx stats. */ 192899fe2010SSepherosa Ziehau stat->tx_frames += smb->tx_frames; 192999fe2010SSepherosa Ziehau stat->tx_bcast_frames += smb->tx_bcast_frames; 193099fe2010SSepherosa Ziehau stat->tx_mcast_frames += smb->tx_mcast_frames; 193199fe2010SSepherosa Ziehau stat->tx_pause_frames += smb->tx_pause_frames; 193299fe2010SSepherosa Ziehau stat->tx_excess_defer += smb->tx_excess_defer; 193399fe2010SSepherosa Ziehau stat->tx_control_frames += smb->tx_control_frames; 193499fe2010SSepherosa Ziehau stat->tx_deferred += smb->tx_deferred; 193599fe2010SSepherosa Ziehau stat->tx_bytes += smb->tx_bytes; 193699fe2010SSepherosa Ziehau stat->tx_pkts_64 += smb->tx_pkts_64; 193799fe2010SSepherosa Ziehau stat->tx_pkts_65_127 += smb->tx_pkts_65_127; 193899fe2010SSepherosa Ziehau stat->tx_pkts_128_255 += smb->tx_pkts_128_255; 193999fe2010SSepherosa Ziehau stat->tx_pkts_256_511 += smb->tx_pkts_256_511; 194099fe2010SSepherosa Ziehau stat->tx_pkts_512_1023 += smb->tx_pkts_512_1023; 194199fe2010SSepherosa Ziehau stat->tx_pkts_1024_1518 += smb->tx_pkts_1024_1518; 194299fe2010SSepherosa Ziehau stat->tx_pkts_1519_max += smb->tx_pkts_1519_max; 194399fe2010SSepherosa Ziehau stat->tx_single_colls += smb->tx_single_colls; 194499fe2010SSepherosa Ziehau stat->tx_multi_colls += smb->tx_multi_colls; 194599fe2010SSepherosa Ziehau stat->tx_late_colls += smb->tx_late_colls; 194699fe2010SSepherosa Ziehau stat->tx_excess_colls += smb->tx_excess_colls; 194799fe2010SSepherosa Ziehau stat->tx_abort += smb->tx_abort; 194899fe2010SSepherosa Ziehau stat->tx_underrun += smb->tx_underrun; 194999fe2010SSepherosa Ziehau stat->tx_desc_underrun += smb->tx_desc_underrun; 195099fe2010SSepherosa Ziehau stat->tx_lenerrs += smb->tx_lenerrs; 195199fe2010SSepherosa Ziehau stat->tx_pkts_truncated += smb->tx_pkts_truncated; 195299fe2010SSepherosa Ziehau stat->tx_bcast_bytes += smb->tx_bcast_bytes; 195399fe2010SSepherosa Ziehau stat->tx_mcast_bytes += smb->tx_mcast_bytes; 195499fe2010SSepherosa Ziehau 195599fe2010SSepherosa Ziehau /* Update counters in ifnet. */ 195699fe2010SSepherosa Ziehau ifp->if_opackets += smb->tx_frames; 195799fe2010SSepherosa Ziehau 195899fe2010SSepherosa Ziehau ifp->if_collisions += smb->tx_single_colls + 195999fe2010SSepherosa Ziehau smb->tx_multi_colls * 2 + smb->tx_late_colls + 196099fe2010SSepherosa Ziehau smb->tx_abort * HDPX_CFG_RETRY_DEFAULT; 196199fe2010SSepherosa Ziehau 196299fe2010SSepherosa Ziehau /* 196399fe2010SSepherosa Ziehau * XXX 196499fe2010SSepherosa Ziehau * tx_pkts_truncated counter looks suspicious. It constantly 196599fe2010SSepherosa Ziehau * increments with no sign of Tx errors. This may indicate 196699fe2010SSepherosa Ziehau * the counter name is not correct one so I've removed the 196799fe2010SSepherosa Ziehau * counter in output errors. 196899fe2010SSepherosa Ziehau */ 196999fe2010SSepherosa Ziehau ifp->if_oerrors += smb->tx_abort + smb->tx_late_colls + 197099fe2010SSepherosa Ziehau smb->tx_underrun; 197199fe2010SSepherosa Ziehau 197299fe2010SSepherosa Ziehau ifp->if_ipackets += smb->rx_frames; 197399fe2010SSepherosa Ziehau 197499fe2010SSepherosa Ziehau ifp->if_ierrors += smb->rx_crcerrs + smb->rx_lenerrs + 197599fe2010SSepherosa Ziehau smb->rx_runts + smb->rx_pkts_truncated + 197699fe2010SSepherosa Ziehau smb->rx_fifo_oflows + smb->rx_rrs_errs + 197799fe2010SSepherosa Ziehau smb->rx_alignerrs; 197899fe2010SSepherosa Ziehau } 197999fe2010SSepherosa Ziehau 198099fe2010SSepherosa Ziehau static void 198199fe2010SSepherosa Ziehau ale_intr(void *xsc) 198299fe2010SSepherosa Ziehau { 198399fe2010SSepherosa Ziehau struct ale_softc *sc = xsc; 198499fe2010SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 198599fe2010SSepherosa Ziehau uint32_t status; 198699fe2010SSepherosa Ziehau 198799fe2010SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 198899fe2010SSepherosa Ziehau 198999fe2010SSepherosa Ziehau status = CSR_READ_4(sc, ALE_INTR_STATUS); 199099fe2010SSepherosa Ziehau if ((status & ALE_INTRS) == 0) 199199fe2010SSepherosa Ziehau return; 199299fe2010SSepherosa Ziehau 199399fe2010SSepherosa Ziehau /* Acknowledge and disable interrupts. */ 199499fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_INTR_STATUS, status | INTR_DIS_INT); 199599fe2010SSepherosa Ziehau 199699fe2010SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) != 0) { 199799fe2010SSepherosa Ziehau int error; 199899fe2010SSepherosa Ziehau 199999fe2010SSepherosa Ziehau error = ale_rxeof(sc); 200099fe2010SSepherosa Ziehau if (error) { 200199fe2010SSepherosa Ziehau sc->ale_stats.reset_brk_seq++; 200299fe2010SSepherosa Ziehau ale_init(sc); 200399fe2010SSepherosa Ziehau return; 200499fe2010SSepherosa Ziehau } 200599fe2010SSepherosa Ziehau 200699fe2010SSepherosa Ziehau if ((status & (INTR_DMA_RD_TO_RST | INTR_DMA_WR_TO_RST)) != 0) { 200799fe2010SSepherosa Ziehau if ((status & INTR_DMA_RD_TO_RST) != 0) 200899fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 200999fe2010SSepherosa Ziehau "DMA read error! -- resetting\n"); 201099fe2010SSepherosa Ziehau if ((status & INTR_DMA_WR_TO_RST) != 0) 201199fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 201299fe2010SSepherosa Ziehau "DMA write error! -- resetting\n"); 201399fe2010SSepherosa Ziehau ale_init(sc); 201499fe2010SSepherosa Ziehau return; 201599fe2010SSepherosa Ziehau } 201699fe2010SSepherosa Ziehau 201799fe2010SSepherosa Ziehau ale_txeof(sc); 201899fe2010SSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd)) 201999fe2010SSepherosa Ziehau if_devstart(ifp); 202099fe2010SSepherosa Ziehau } 202199fe2010SSepherosa Ziehau 202299fe2010SSepherosa Ziehau /* Re-enable interrupts. */ 202399fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_INTR_STATUS, 0x7FFFFFFF); 202499fe2010SSepherosa Ziehau } 202599fe2010SSepherosa Ziehau 202699fe2010SSepherosa Ziehau static void 202799fe2010SSepherosa Ziehau ale_txeof(struct ale_softc *sc) 202899fe2010SSepherosa Ziehau { 202999fe2010SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 203099fe2010SSepherosa Ziehau struct ale_txdesc *txd; 203199fe2010SSepherosa Ziehau uint32_t cons, prod; 203299fe2010SSepherosa Ziehau int prog; 203399fe2010SSepherosa Ziehau 203499fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_tx_cnt == 0) 203599fe2010SSepherosa Ziehau return; 203699fe2010SSepherosa Ziehau 203799fe2010SSepherosa Ziehau bus_dmamap_sync(sc->ale_cdata.ale_tx_ring_tag, 203899fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_ring_map, BUS_DMASYNC_POSTREAD); 203999fe2010SSepherosa Ziehau if ((sc->ale_flags & ALE_FLAG_TXCMB_BUG) == 0) { 204099fe2010SSepherosa Ziehau bus_dmamap_sync(sc->ale_cdata.ale_tx_cmb_tag, 204199fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_cmb_map, BUS_DMASYNC_POSTREAD); 204299fe2010SSepherosa Ziehau prod = *sc->ale_cdata.ale_tx_cmb & TPD_CNT_MASK; 204399fe2010SSepherosa Ziehau } else 204499fe2010SSepherosa Ziehau prod = CSR_READ_2(sc, ALE_TPD_CONS_IDX); 204599fe2010SSepherosa Ziehau cons = sc->ale_cdata.ale_tx_cons; 204699fe2010SSepherosa Ziehau /* 204799fe2010SSepherosa Ziehau * Go through our Tx list and free mbufs for those 204899fe2010SSepherosa Ziehau * frames which have been transmitted. 204999fe2010SSepherosa Ziehau */ 205099fe2010SSepherosa Ziehau for (prog = 0; cons != prod; prog++, 205199fe2010SSepherosa Ziehau ALE_DESC_INC(cons, ALE_TX_RING_CNT)) { 205299fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_tx_cnt <= 0) 205399fe2010SSepherosa Ziehau break; 205499fe2010SSepherosa Ziehau prog++; 20559ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 205699fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_cnt--; 205799fe2010SSepherosa Ziehau txd = &sc->ale_cdata.ale_txdesc[cons]; 205899fe2010SSepherosa Ziehau if (txd->tx_m != NULL) { 205999fe2010SSepherosa Ziehau /* Reclaim transmitted mbufs. */ 206099fe2010SSepherosa Ziehau bus_dmamap_unload(sc->ale_cdata.ale_tx_tag, 206199fe2010SSepherosa Ziehau txd->tx_dmamap); 206299fe2010SSepherosa Ziehau m_freem(txd->tx_m); 206399fe2010SSepherosa Ziehau txd->tx_m = NULL; 206499fe2010SSepherosa Ziehau } 206599fe2010SSepherosa Ziehau } 206699fe2010SSepherosa Ziehau 206799fe2010SSepherosa Ziehau if (prog > 0) { 206899fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_cons = cons; 206999fe2010SSepherosa Ziehau /* 207099fe2010SSepherosa Ziehau * Unarm watchdog timer only when there is no pending 207199fe2010SSepherosa Ziehau * Tx descriptors in queue. 207299fe2010SSepherosa Ziehau */ 207399fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_tx_cnt == 0) 207499fe2010SSepherosa Ziehau ifp->if_timer = 0; 207599fe2010SSepherosa Ziehau } 207699fe2010SSepherosa Ziehau } 207799fe2010SSepherosa Ziehau 207899fe2010SSepherosa Ziehau static void 207999fe2010SSepherosa Ziehau ale_rx_update_page(struct ale_softc *sc, struct ale_rx_page **page, 208099fe2010SSepherosa Ziehau uint32_t length, uint32_t *prod) 208199fe2010SSepherosa Ziehau { 208299fe2010SSepherosa Ziehau struct ale_rx_page *rx_page; 208399fe2010SSepherosa Ziehau 208499fe2010SSepherosa Ziehau rx_page = *page; 208599fe2010SSepherosa Ziehau /* Update consumer position. */ 208699fe2010SSepherosa Ziehau rx_page->cons += roundup(length + sizeof(struct rx_rs), 208799fe2010SSepherosa Ziehau ALE_RX_PAGE_ALIGN); 208899fe2010SSepherosa Ziehau if (rx_page->cons >= ALE_RX_PAGE_SZ) { 208999fe2010SSepherosa Ziehau /* 209099fe2010SSepherosa Ziehau * End of Rx page reached, let hardware reuse 209199fe2010SSepherosa Ziehau * this page. 209299fe2010SSepherosa Ziehau */ 209399fe2010SSepherosa Ziehau rx_page->cons = 0; 209499fe2010SSepherosa Ziehau *rx_page->cmb_addr = 0; 209599fe2010SSepherosa Ziehau bus_dmamap_sync(rx_page->cmb_tag, rx_page->cmb_map, 209699fe2010SSepherosa Ziehau BUS_DMASYNC_PREWRITE); 209799fe2010SSepherosa Ziehau CSR_WRITE_1(sc, ALE_RXF0_PAGE0 + sc->ale_cdata.ale_rx_curp, 209899fe2010SSepherosa Ziehau RXF_VALID); 209999fe2010SSepherosa Ziehau /* Switch to alternate Rx page. */ 210099fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_curp ^= 1; 210199fe2010SSepherosa Ziehau rx_page = *page = 210299fe2010SSepherosa Ziehau &sc->ale_cdata.ale_rx_page[sc->ale_cdata.ale_rx_curp]; 210399fe2010SSepherosa Ziehau /* Page flipped, sync CMB and Rx page. */ 210499fe2010SSepherosa Ziehau bus_dmamap_sync(rx_page->page_tag, rx_page->page_map, 210599fe2010SSepherosa Ziehau BUS_DMASYNC_POSTREAD); 210699fe2010SSepherosa Ziehau bus_dmamap_sync(rx_page->cmb_tag, rx_page->cmb_map, 210799fe2010SSepherosa Ziehau BUS_DMASYNC_POSTREAD); 210899fe2010SSepherosa Ziehau /* Sync completed, cache updated producer index. */ 210999fe2010SSepherosa Ziehau *prod = *rx_page->cmb_addr; 211099fe2010SSepherosa Ziehau } 211199fe2010SSepherosa Ziehau } 211299fe2010SSepherosa Ziehau 211399fe2010SSepherosa Ziehau 211499fe2010SSepherosa Ziehau /* 211599fe2010SSepherosa Ziehau * It seems that AR81xx controller can compute partial checksum. 211699fe2010SSepherosa Ziehau * The partial checksum value can be used to accelerate checksum 211799fe2010SSepherosa Ziehau * computation for fragmented TCP/UDP packets. Upper network stack 211899fe2010SSepherosa Ziehau * already takes advantage of the partial checksum value in IP 211999fe2010SSepherosa Ziehau * reassembly stage. But I'm not sure the correctness of the 212099fe2010SSepherosa Ziehau * partial hardware checksum assistance due to lack of data sheet. 212199fe2010SSepherosa Ziehau * In addition, the Rx feature of controller that requires copying 212299fe2010SSepherosa Ziehau * for every frames effectively nullifies one of most nice offload 212399fe2010SSepherosa Ziehau * capability of controller. 212499fe2010SSepherosa Ziehau */ 212599fe2010SSepherosa Ziehau static void 212699fe2010SSepherosa Ziehau ale_rxcsum(struct ale_softc *sc, struct mbuf *m, uint32_t status) 212799fe2010SSepherosa Ziehau { 212899fe2010SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 212999fe2010SSepherosa Ziehau struct ip *ip; 213099fe2010SSepherosa Ziehau char *p; 213199fe2010SSepherosa Ziehau 213299fe2010SSepherosa Ziehau m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 213399fe2010SSepherosa Ziehau if ((status & ALE_RD_IPCSUM_NOK) == 0) 213499fe2010SSepherosa Ziehau m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 213599fe2010SSepherosa Ziehau 213699fe2010SSepherosa Ziehau if ((sc->ale_flags & ALE_FLAG_RXCSUM_BUG) == 0) { 213799fe2010SSepherosa Ziehau if (((status & ALE_RD_IPV4_FRAG) == 0) && 213899fe2010SSepherosa Ziehau ((status & (ALE_RD_TCP | ALE_RD_UDP)) != 0) && 213999fe2010SSepherosa Ziehau ((status & ALE_RD_TCP_UDPCSUM_NOK) == 0)) { 214099fe2010SSepherosa Ziehau m->m_pkthdr.csum_flags |= 214199fe2010SSepherosa Ziehau CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 214299fe2010SSepherosa Ziehau m->m_pkthdr.csum_data = 0xffff; 214399fe2010SSepherosa Ziehau } 214499fe2010SSepherosa Ziehau } else { 214599fe2010SSepherosa Ziehau if ((status & (ALE_RD_TCP | ALE_RD_UDP)) != 0 && 214699fe2010SSepherosa Ziehau (status & ALE_RD_TCP_UDPCSUM_NOK) == 0) { 214799fe2010SSepherosa Ziehau p = mtod(m, char *); 214899fe2010SSepherosa Ziehau p += ETHER_HDR_LEN; 214999fe2010SSepherosa Ziehau if ((status & ALE_RD_802_3) != 0) 215099fe2010SSepherosa Ziehau p += LLC_SNAPFRAMELEN; 215199fe2010SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0 && 215299fe2010SSepherosa Ziehau (status & ALE_RD_VLAN) != 0) 215399fe2010SSepherosa Ziehau p += EVL_ENCAPLEN; 215499fe2010SSepherosa Ziehau ip = (struct ip *)p; 215599fe2010SSepherosa Ziehau if (ip->ip_off != 0 && (status & ALE_RD_IPV4_DF) == 0) 215699fe2010SSepherosa Ziehau return; 215799fe2010SSepherosa Ziehau m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | 215899fe2010SSepherosa Ziehau CSUM_PSEUDO_HDR; 215999fe2010SSepherosa Ziehau m->m_pkthdr.csum_data = 0xffff; 216099fe2010SSepherosa Ziehau } 216199fe2010SSepherosa Ziehau } 216299fe2010SSepherosa Ziehau /* 216399fe2010SSepherosa Ziehau * Don't mark bad checksum for TCP/UDP frames 216499fe2010SSepherosa Ziehau * as fragmented frames may always have set 216599fe2010SSepherosa Ziehau * bad checksummed bit of frame status. 216699fe2010SSepherosa Ziehau */ 216799fe2010SSepherosa Ziehau } 216899fe2010SSepherosa Ziehau 216999fe2010SSepherosa Ziehau /* Process received frames. */ 217099fe2010SSepherosa Ziehau static int 217199fe2010SSepherosa Ziehau ale_rxeof(struct ale_softc *sc) 217299fe2010SSepherosa Ziehau { 217399fe2010SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 217499fe2010SSepherosa Ziehau struct ale_rx_page *rx_page; 217599fe2010SSepherosa Ziehau struct rx_rs *rs; 217699fe2010SSepherosa Ziehau struct mbuf *m; 217799fe2010SSepherosa Ziehau uint32_t length, prod, seqno, status, vtags; 217899fe2010SSepherosa Ziehau int prog; 217999fe2010SSepherosa Ziehau 218099fe2010SSepherosa Ziehau rx_page = &sc->ale_cdata.ale_rx_page[sc->ale_cdata.ale_rx_curp]; 218199fe2010SSepherosa Ziehau bus_dmamap_sync(rx_page->cmb_tag, rx_page->cmb_map, 218299fe2010SSepherosa Ziehau BUS_DMASYNC_POSTREAD); 218399fe2010SSepherosa Ziehau bus_dmamap_sync(rx_page->page_tag, rx_page->page_map, 218499fe2010SSepherosa Ziehau BUS_DMASYNC_POSTREAD); 218599fe2010SSepherosa Ziehau /* 218699fe2010SSepherosa Ziehau * Don't directly access producer index as hardware may 218799fe2010SSepherosa Ziehau * update it while Rx handler is in progress. It would 218899fe2010SSepherosa Ziehau * be even better if there is a way to let hardware 218999fe2010SSepherosa Ziehau * know how far driver processed its received frames. 219099fe2010SSepherosa Ziehau * Alternatively, hardware could provide a way to disable 219199fe2010SSepherosa Ziehau * CMB updates until driver acknowledges the end of CMB 219299fe2010SSepherosa Ziehau * access. 219399fe2010SSepherosa Ziehau */ 219499fe2010SSepherosa Ziehau prod = *rx_page->cmb_addr; 219599fe2010SSepherosa Ziehau for (prog = 0; ; prog++) { 219699fe2010SSepherosa Ziehau if (rx_page->cons >= prod) 219799fe2010SSepherosa Ziehau break; 219899fe2010SSepherosa Ziehau rs = (struct rx_rs *)(rx_page->page_addr + rx_page->cons); 219999fe2010SSepherosa Ziehau seqno = ALE_RX_SEQNO(le32toh(rs->seqno)); 220099fe2010SSepherosa Ziehau if (sc->ale_cdata.ale_rx_seqno != seqno) { 220199fe2010SSepherosa Ziehau /* 220299fe2010SSepherosa Ziehau * Normally I believe this should not happen unless 220399fe2010SSepherosa Ziehau * severe driver bug or corrupted memory. However 220499fe2010SSepherosa Ziehau * it seems to happen under certain conditions which 220599fe2010SSepherosa Ziehau * is triggered by abrupt Rx events such as initiation 220699fe2010SSepherosa Ziehau * of bulk transfer of remote host. It's not easy to 220799fe2010SSepherosa Ziehau * reproduce this and I doubt it could be related 220899fe2010SSepherosa Ziehau * with FIFO overflow of hardware or activity of Tx 220999fe2010SSepherosa Ziehau * CMB updates. I also remember similar behaviour 221099fe2010SSepherosa Ziehau * seen on RealTek 8139 which uses resembling Rx 221199fe2010SSepherosa Ziehau * scheme. 221299fe2010SSepherosa Ziehau */ 221399fe2010SSepherosa Ziehau if (bootverbose) 221499fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 221599fe2010SSepherosa Ziehau "garbled seq: %u, expected: %u -- " 221699fe2010SSepherosa Ziehau "resetting!\n", seqno, 221799fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_seqno); 221899fe2010SSepherosa Ziehau return (EIO); 221999fe2010SSepherosa Ziehau } 222099fe2010SSepherosa Ziehau /* Frame received. */ 222199fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_seqno++; 222299fe2010SSepherosa Ziehau length = ALE_RX_BYTES(le32toh(rs->length)); 222399fe2010SSepherosa Ziehau status = le32toh(rs->flags); 222499fe2010SSepherosa Ziehau if ((status & ALE_RD_ERROR) != 0) { 222599fe2010SSepherosa Ziehau /* 222699fe2010SSepherosa Ziehau * We want to pass the following frames to upper 222799fe2010SSepherosa Ziehau * layer regardless of error status of Rx return 222899fe2010SSepherosa Ziehau * status. 222999fe2010SSepherosa Ziehau * 223099fe2010SSepherosa Ziehau * o IP/TCP/UDP checksum is bad. 223199fe2010SSepherosa Ziehau * o frame length and protocol specific length 223299fe2010SSepherosa Ziehau * does not match. 223399fe2010SSepherosa Ziehau */ 223499fe2010SSepherosa Ziehau if ((status & (ALE_RD_CRC | ALE_RD_CODE | 223599fe2010SSepherosa Ziehau ALE_RD_DRIBBLE | ALE_RD_RUNT | ALE_RD_OFLOW | 223699fe2010SSepherosa Ziehau ALE_RD_TRUNC)) != 0) { 223799fe2010SSepherosa Ziehau ale_rx_update_page(sc, &rx_page, length, &prod); 223899fe2010SSepherosa Ziehau continue; 223999fe2010SSepherosa Ziehau } 224099fe2010SSepherosa Ziehau } 224199fe2010SSepherosa Ziehau /* 224299fe2010SSepherosa Ziehau * m_devget(9) is major bottle-neck of ale(4)(It comes 224399fe2010SSepherosa Ziehau * from hardware limitation). For jumbo frames we could 224499fe2010SSepherosa Ziehau * get a slightly better performance if driver use 224599fe2010SSepherosa Ziehau * m_getjcl(9) with proper buffer size argument. However 224699fe2010SSepherosa Ziehau * that would make code more complicated and I don't 224799fe2010SSepherosa Ziehau * think users would expect good Rx performance numbers 224899fe2010SSepherosa Ziehau * on these low-end consumer ethernet controller. 224999fe2010SSepherosa Ziehau */ 225099fe2010SSepherosa Ziehau m = m_devget((char *)(rs + 1), length - ETHER_CRC_LEN, 225199fe2010SSepherosa Ziehau ETHER_ALIGN, ifp, NULL); 225299fe2010SSepherosa Ziehau if (m == NULL) { 225399fe2010SSepherosa Ziehau ifp->if_iqdrops++; 225499fe2010SSepherosa Ziehau ale_rx_update_page(sc, &rx_page, length, &prod); 225599fe2010SSepherosa Ziehau continue; 225699fe2010SSepherosa Ziehau } 225799fe2010SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_RXCSUM) != 0 && 225899fe2010SSepherosa Ziehau (status & ALE_RD_IPV4) != 0) 225999fe2010SSepherosa Ziehau ale_rxcsum(sc, m, status); 226099fe2010SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 && 226199fe2010SSepherosa Ziehau (status & ALE_RD_VLAN) != 0) { 226299fe2010SSepherosa Ziehau vtags = ALE_RX_VLAN(le32toh(rs->vtags)); 226399fe2010SSepherosa Ziehau m->m_pkthdr.ether_vlantag = ALE_RX_VLAN_TAG(vtags); 226499fe2010SSepherosa Ziehau m->m_flags |= M_VLANTAG; 226599fe2010SSepherosa Ziehau } 226699fe2010SSepherosa Ziehau 226799fe2010SSepherosa Ziehau /* Pass it to upper layer. */ 226899fe2010SSepherosa Ziehau ifp->if_input(ifp, m); 226999fe2010SSepherosa Ziehau 227099fe2010SSepherosa Ziehau ale_rx_update_page(sc, &rx_page, length, &prod); 227199fe2010SSepherosa Ziehau } 227299fe2010SSepherosa Ziehau return 0; 227399fe2010SSepherosa Ziehau } 227499fe2010SSepherosa Ziehau 227599fe2010SSepherosa Ziehau static void 227699fe2010SSepherosa Ziehau ale_tick(void *xsc) 227799fe2010SSepherosa Ziehau { 227899fe2010SSepherosa Ziehau struct ale_softc *sc = xsc; 227999fe2010SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 228099fe2010SSepherosa Ziehau struct mii_data *mii; 228199fe2010SSepherosa Ziehau 228299fe2010SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 228399fe2010SSepherosa Ziehau 228499fe2010SSepherosa Ziehau mii = device_get_softc(sc->ale_miibus); 228599fe2010SSepherosa Ziehau mii_tick(mii); 228699fe2010SSepherosa Ziehau ale_stats_update(sc); 228799fe2010SSepherosa Ziehau 228899fe2010SSepherosa Ziehau callout_reset(&sc->ale_tick_ch, hz, ale_tick, sc); 228999fe2010SSepherosa Ziehau 229099fe2010SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 229199fe2010SSepherosa Ziehau } 229299fe2010SSepherosa Ziehau 229399fe2010SSepherosa Ziehau static void 229499fe2010SSepherosa Ziehau ale_reset(struct ale_softc *sc) 229599fe2010SSepherosa Ziehau { 229699fe2010SSepherosa Ziehau uint32_t reg; 229799fe2010SSepherosa Ziehau int i; 229899fe2010SSepherosa Ziehau 229999fe2010SSepherosa Ziehau /* Initialize PCIe module. From Linux. */ 230099fe2010SSepherosa Ziehau CSR_WRITE_4(sc, 0x1008, CSR_READ_4(sc, 0x1008) | 0x8000); 230199fe2010SSepherosa Ziehau 230299fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_MASTER_CFG, MASTER_RESET); 230399fe2010SSepherosa Ziehau for (i = ALE_RESET_TIMEOUT; i > 0; i--) { 230499fe2010SSepherosa Ziehau DELAY(10); 230599fe2010SSepherosa Ziehau if ((CSR_READ_4(sc, ALE_MASTER_CFG) & MASTER_RESET) == 0) 230699fe2010SSepherosa Ziehau break; 230799fe2010SSepherosa Ziehau } 230899fe2010SSepherosa Ziehau if (i == 0) 230999fe2010SSepherosa Ziehau device_printf(sc->ale_dev, "master reset timeout!\n"); 231099fe2010SSepherosa Ziehau 231199fe2010SSepherosa Ziehau for (i = ALE_RESET_TIMEOUT; i > 0; i--) { 231299fe2010SSepherosa Ziehau if ((reg = CSR_READ_4(sc, ALE_IDLE_STATUS)) == 0) 231399fe2010SSepherosa Ziehau break; 231499fe2010SSepherosa Ziehau DELAY(10); 231599fe2010SSepherosa Ziehau } 231699fe2010SSepherosa Ziehau 231799fe2010SSepherosa Ziehau if (i == 0) 231899fe2010SSepherosa Ziehau device_printf(sc->ale_dev, "reset timeout(0x%08x)!\n", reg); 231999fe2010SSepherosa Ziehau } 232099fe2010SSepherosa Ziehau 232199fe2010SSepherosa Ziehau static void 232299fe2010SSepherosa Ziehau ale_init(void *xsc) 232399fe2010SSepherosa Ziehau { 232499fe2010SSepherosa Ziehau struct ale_softc *sc = xsc; 232599fe2010SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 232699fe2010SSepherosa Ziehau struct mii_data *mii; 232799fe2010SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN]; 232899fe2010SSepherosa Ziehau bus_addr_t paddr; 232999fe2010SSepherosa Ziehau uint32_t reg, rxf_hi, rxf_lo; 233099fe2010SSepherosa Ziehau 233199fe2010SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 233299fe2010SSepherosa Ziehau 233399fe2010SSepherosa Ziehau mii = device_get_softc(sc->ale_miibus); 233499fe2010SSepherosa Ziehau 233599fe2010SSepherosa Ziehau /* 233699fe2010SSepherosa Ziehau * Cancel any pending I/O. 233799fe2010SSepherosa Ziehau */ 233899fe2010SSepherosa Ziehau ale_stop(sc); 233999fe2010SSepherosa Ziehau 234099fe2010SSepherosa Ziehau /* 234199fe2010SSepherosa Ziehau * Reset the chip to a known state. 234299fe2010SSepherosa Ziehau */ 234399fe2010SSepherosa Ziehau ale_reset(sc); 234499fe2010SSepherosa Ziehau 234599fe2010SSepherosa Ziehau /* Initialize Tx descriptors, DMA memory blocks. */ 234699fe2010SSepherosa Ziehau ale_init_rx_pages(sc); 234799fe2010SSepherosa Ziehau ale_init_tx_ring(sc); 234899fe2010SSepherosa Ziehau 234999fe2010SSepherosa Ziehau /* Reprogram the station address. */ 235099fe2010SSepherosa Ziehau bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN); 235199fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_PAR0, 235299fe2010SSepherosa Ziehau eaddr[2] << 24 | eaddr[3] << 16 | eaddr[4] << 8 | eaddr[5]); 235399fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_PAR1, eaddr[0] << 8 | eaddr[1]); 235499fe2010SSepherosa Ziehau 235599fe2010SSepherosa Ziehau /* 235699fe2010SSepherosa Ziehau * Clear WOL status and disable all WOL feature as WOL 235799fe2010SSepherosa Ziehau * would interfere Rx operation under normal environments. 235899fe2010SSepherosa Ziehau */ 235999fe2010SSepherosa Ziehau CSR_READ_4(sc, ALE_WOL_CFG); 236099fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_WOL_CFG, 0); 236199fe2010SSepherosa Ziehau 236299fe2010SSepherosa Ziehau /* 236399fe2010SSepherosa Ziehau * Set Tx descriptor/RXF0/CMB base addresses. They share 236499fe2010SSepherosa Ziehau * the same high address part of DMAable region. 236599fe2010SSepherosa Ziehau */ 236699fe2010SSepherosa Ziehau paddr = sc->ale_cdata.ale_tx_ring_paddr; 236799fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_TPD_ADDR_HI, ALE_ADDR_HI(paddr)); 236899fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_TPD_ADDR_LO, ALE_ADDR_LO(paddr)); 236999fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_TPD_CNT, 237099fe2010SSepherosa Ziehau (ALE_TX_RING_CNT << TPD_CNT_SHIFT) & TPD_CNT_MASK); 237199fe2010SSepherosa Ziehau 237299fe2010SSepherosa Ziehau /* Set Rx page base address, note we use single queue. */ 237399fe2010SSepherosa Ziehau paddr = sc->ale_cdata.ale_rx_page[0].page_paddr; 237499fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_RXF0_PAGE0_ADDR_LO, ALE_ADDR_LO(paddr)); 237599fe2010SSepherosa Ziehau paddr = sc->ale_cdata.ale_rx_page[1].page_paddr; 237699fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_RXF0_PAGE1_ADDR_LO, ALE_ADDR_LO(paddr)); 237799fe2010SSepherosa Ziehau 237899fe2010SSepherosa Ziehau /* Set Tx/Rx CMB addresses. */ 237999fe2010SSepherosa Ziehau paddr = sc->ale_cdata.ale_tx_cmb_paddr; 238099fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_TX_CMB_ADDR_LO, ALE_ADDR_LO(paddr)); 238199fe2010SSepherosa Ziehau paddr = sc->ale_cdata.ale_rx_page[0].cmb_paddr; 238299fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_RXF0_CMB0_ADDR_LO, ALE_ADDR_LO(paddr)); 238399fe2010SSepherosa Ziehau paddr = sc->ale_cdata.ale_rx_page[1].cmb_paddr; 238499fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_RXF0_CMB1_ADDR_LO, ALE_ADDR_LO(paddr)); 238599fe2010SSepherosa Ziehau 238699fe2010SSepherosa Ziehau /* Mark RXF0 is valid. */ 238799fe2010SSepherosa Ziehau CSR_WRITE_1(sc, ALE_RXF0_PAGE0, RXF_VALID); 238899fe2010SSepherosa Ziehau CSR_WRITE_1(sc, ALE_RXF0_PAGE1, RXF_VALID); 238999fe2010SSepherosa Ziehau /* 239099fe2010SSepherosa Ziehau * No need to initialize RFX1/RXF2/RXF3. We don't use 239199fe2010SSepherosa Ziehau * multi-queue yet. 239299fe2010SSepherosa Ziehau */ 239399fe2010SSepherosa Ziehau 239499fe2010SSepherosa Ziehau /* Set Rx page size, excluding guard frame size. */ 239599fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_RXF_PAGE_SIZE, ALE_RX_PAGE_SZ); 239699fe2010SSepherosa Ziehau 239799fe2010SSepherosa Ziehau /* Tell hardware that we're ready to load DMA blocks. */ 239899fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_DMA_BLOCK, DMA_BLOCK_LOAD); 239999fe2010SSepherosa Ziehau 240099fe2010SSepherosa Ziehau /* Set Rx/Tx interrupt trigger threshold. */ 240199fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_INT_TRIG_THRESH, (1 << INT_TRIG_RX_THRESH_SHIFT) | 240299fe2010SSepherosa Ziehau (4 << INT_TRIG_TX_THRESH_SHIFT)); 240399fe2010SSepherosa Ziehau /* 240499fe2010SSepherosa Ziehau * XXX 240599fe2010SSepherosa Ziehau * Set interrupt trigger timer, its purpose and relation 240699fe2010SSepherosa Ziehau * with interrupt moderation mechanism is not clear yet. 240799fe2010SSepherosa Ziehau */ 240899fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_INT_TRIG_TIMER, 240999fe2010SSepherosa Ziehau ((ALE_USECS(10) << INT_TRIG_RX_TIMER_SHIFT) | 241099fe2010SSepherosa Ziehau (ALE_USECS(1000) << INT_TRIG_TX_TIMER_SHIFT))); 241199fe2010SSepherosa Ziehau 241299fe2010SSepherosa Ziehau /* Configure interrupt moderation timer. */ 241399fe2010SSepherosa Ziehau reg = ALE_USECS(sc->ale_int_rx_mod) << IM_TIMER_RX_SHIFT; 241499fe2010SSepherosa Ziehau reg |= ALE_USECS(sc->ale_int_tx_mod) << IM_TIMER_TX_SHIFT; 241599fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_IM_TIMER, reg); 241699fe2010SSepherosa Ziehau reg = CSR_READ_4(sc, ALE_MASTER_CFG); 241799fe2010SSepherosa Ziehau reg &= ~(MASTER_CHIP_REV_MASK | MASTER_CHIP_ID_MASK); 241899fe2010SSepherosa Ziehau reg &= ~(MASTER_IM_RX_TIMER_ENB | MASTER_IM_TX_TIMER_ENB); 241999fe2010SSepherosa Ziehau if (ALE_USECS(sc->ale_int_rx_mod) != 0) 242099fe2010SSepherosa Ziehau reg |= MASTER_IM_RX_TIMER_ENB; 242199fe2010SSepherosa Ziehau if (ALE_USECS(sc->ale_int_tx_mod) != 0) 242299fe2010SSepherosa Ziehau reg |= MASTER_IM_TX_TIMER_ENB; 242399fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_MASTER_CFG, reg); 242499fe2010SSepherosa Ziehau CSR_WRITE_2(sc, ALE_INTR_CLR_TIMER, ALE_USECS(1000)); 242599fe2010SSepherosa Ziehau 242699fe2010SSepherosa Ziehau /* Set Maximum frame size of controller. */ 242799fe2010SSepherosa Ziehau if (ifp->if_mtu < ETHERMTU) 242899fe2010SSepherosa Ziehau sc->ale_max_frame_size = ETHERMTU; 242999fe2010SSepherosa Ziehau else 243099fe2010SSepherosa Ziehau sc->ale_max_frame_size = ifp->if_mtu; 243199fe2010SSepherosa Ziehau sc->ale_max_frame_size += ETHER_HDR_LEN + EVL_ENCAPLEN + ETHER_CRC_LEN; 243299fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_FRAME_SIZE, sc->ale_max_frame_size); 243399fe2010SSepherosa Ziehau 243499fe2010SSepherosa Ziehau /* Configure IPG/IFG parameters. */ 243599fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_IPG_IFG_CFG, 243699fe2010SSepherosa Ziehau ((IPG_IFG_IPGT_DEFAULT << IPG_IFG_IPGT_SHIFT) & IPG_IFG_IPGT_MASK) | 243799fe2010SSepherosa Ziehau ((IPG_IFG_MIFG_DEFAULT << IPG_IFG_MIFG_SHIFT) & IPG_IFG_MIFG_MASK) | 243899fe2010SSepherosa Ziehau ((IPG_IFG_IPG1_DEFAULT << IPG_IFG_IPG1_SHIFT) & IPG_IFG_IPG1_MASK) | 243999fe2010SSepherosa Ziehau ((IPG_IFG_IPG2_DEFAULT << IPG_IFG_IPG2_SHIFT) & IPG_IFG_IPG2_MASK)); 244099fe2010SSepherosa Ziehau 244199fe2010SSepherosa Ziehau /* Set parameters for half-duplex media. */ 244299fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_HDPX_CFG, 244399fe2010SSepherosa Ziehau ((HDPX_CFG_LCOL_DEFAULT << HDPX_CFG_LCOL_SHIFT) & 244499fe2010SSepherosa Ziehau HDPX_CFG_LCOL_MASK) | 244599fe2010SSepherosa Ziehau ((HDPX_CFG_RETRY_DEFAULT << HDPX_CFG_RETRY_SHIFT) & 244699fe2010SSepherosa Ziehau HDPX_CFG_RETRY_MASK) | HDPX_CFG_EXC_DEF_EN | 244799fe2010SSepherosa Ziehau ((HDPX_CFG_ABEBT_DEFAULT << HDPX_CFG_ABEBT_SHIFT) & 244899fe2010SSepherosa Ziehau HDPX_CFG_ABEBT_MASK) | 244999fe2010SSepherosa Ziehau ((HDPX_CFG_JAMIPG_DEFAULT << HDPX_CFG_JAMIPG_SHIFT) & 245099fe2010SSepherosa Ziehau HDPX_CFG_JAMIPG_MASK)); 245199fe2010SSepherosa Ziehau 245299fe2010SSepherosa Ziehau /* Configure Tx jumbo frame parameters. */ 245399fe2010SSepherosa Ziehau if ((sc->ale_flags & ALE_FLAG_JUMBO) != 0) { 245499fe2010SSepherosa Ziehau if (ifp->if_mtu < ETHERMTU) 245599fe2010SSepherosa Ziehau reg = sc->ale_max_frame_size; 245699fe2010SSepherosa Ziehau else if (ifp->if_mtu < 6 * 1024) 245799fe2010SSepherosa Ziehau reg = (sc->ale_max_frame_size * 2) / 3; 245899fe2010SSepherosa Ziehau else 245999fe2010SSepherosa Ziehau reg = sc->ale_max_frame_size / 2; 246099fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_TX_JUMBO_THRESH, 246199fe2010SSepherosa Ziehau roundup(reg, TX_JUMBO_THRESH_UNIT) >> 246299fe2010SSepherosa Ziehau TX_JUMBO_THRESH_UNIT_SHIFT); 246399fe2010SSepherosa Ziehau } 246499fe2010SSepherosa Ziehau 246599fe2010SSepherosa Ziehau /* Configure TxQ. */ 246699fe2010SSepherosa Ziehau reg = (128 << (sc->ale_dma_rd_burst >> DMA_CFG_RD_BURST_SHIFT)) 246799fe2010SSepherosa Ziehau << TXQ_CFG_TX_FIFO_BURST_SHIFT; 246899fe2010SSepherosa Ziehau reg |= (TXQ_CFG_TPD_BURST_DEFAULT << TXQ_CFG_TPD_BURST_SHIFT) & 246999fe2010SSepherosa Ziehau TXQ_CFG_TPD_BURST_MASK; 247099fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_TXQ_CFG, reg | TXQ_CFG_ENHANCED_MODE | TXQ_CFG_ENB); 247199fe2010SSepherosa Ziehau 247299fe2010SSepherosa Ziehau /* Configure Rx jumbo frame & flow control parameters. */ 247399fe2010SSepherosa Ziehau if ((sc->ale_flags & ALE_FLAG_JUMBO) != 0) { 247499fe2010SSepherosa Ziehau reg = roundup(sc->ale_max_frame_size, RX_JUMBO_THRESH_UNIT); 247599fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_RX_JUMBO_THRESH, 247699fe2010SSepherosa Ziehau (((reg >> RX_JUMBO_THRESH_UNIT_SHIFT) << 247799fe2010SSepherosa Ziehau RX_JUMBO_THRESH_MASK_SHIFT) & RX_JUMBO_THRESH_MASK) | 247899fe2010SSepherosa Ziehau ((RX_JUMBO_LKAH_DEFAULT << RX_JUMBO_LKAH_SHIFT) & 247999fe2010SSepherosa Ziehau RX_JUMBO_LKAH_MASK)); 248099fe2010SSepherosa Ziehau reg = CSR_READ_4(sc, ALE_SRAM_RX_FIFO_LEN); 248199fe2010SSepherosa Ziehau rxf_hi = (reg * 7) / 10; 248299fe2010SSepherosa Ziehau rxf_lo = (reg * 3)/ 10; 248399fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_RX_FIFO_PAUSE_THRESH, 248499fe2010SSepherosa Ziehau ((rxf_lo << RX_FIFO_PAUSE_THRESH_LO_SHIFT) & 248599fe2010SSepherosa Ziehau RX_FIFO_PAUSE_THRESH_LO_MASK) | 248699fe2010SSepherosa Ziehau ((rxf_hi << RX_FIFO_PAUSE_THRESH_HI_SHIFT) & 248799fe2010SSepherosa Ziehau RX_FIFO_PAUSE_THRESH_HI_MASK)); 248899fe2010SSepherosa Ziehau } 248999fe2010SSepherosa Ziehau 249099fe2010SSepherosa Ziehau /* Disable RSS. */ 249199fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_RSS_IDT_TABLE0, 0); 249299fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_RSS_CPU, 0); 249399fe2010SSepherosa Ziehau 249499fe2010SSepherosa Ziehau /* Configure RxQ. */ 249599fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_RXQ_CFG, 249699fe2010SSepherosa Ziehau RXQ_CFG_ALIGN_32 | RXQ_CFG_CUT_THROUGH_ENB | RXQ_CFG_ENB); 249799fe2010SSepherosa Ziehau 249899fe2010SSepherosa Ziehau /* Configure DMA parameters. */ 249999fe2010SSepherosa Ziehau reg = 0; 250099fe2010SSepherosa Ziehau if ((sc->ale_flags & ALE_FLAG_TXCMB_BUG) == 0) 250199fe2010SSepherosa Ziehau reg |= DMA_CFG_TXCMB_ENB; 250299fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_DMA_CFG, 250399fe2010SSepherosa Ziehau DMA_CFG_OUT_ORDER | DMA_CFG_RD_REQ_PRI | DMA_CFG_RCB_64 | 250499fe2010SSepherosa Ziehau sc->ale_dma_rd_burst | reg | 250599fe2010SSepherosa Ziehau sc->ale_dma_wr_burst | DMA_CFG_RXCMB_ENB | 250699fe2010SSepherosa Ziehau ((DMA_CFG_RD_DELAY_CNT_DEFAULT << DMA_CFG_RD_DELAY_CNT_SHIFT) & 250799fe2010SSepherosa Ziehau DMA_CFG_RD_DELAY_CNT_MASK) | 250899fe2010SSepherosa Ziehau ((DMA_CFG_WR_DELAY_CNT_DEFAULT << DMA_CFG_WR_DELAY_CNT_SHIFT) & 250999fe2010SSepherosa Ziehau DMA_CFG_WR_DELAY_CNT_MASK)); 251099fe2010SSepherosa Ziehau 251199fe2010SSepherosa Ziehau /* 251299fe2010SSepherosa Ziehau * Hardware can be configured to issue SMB interrupt based 251399fe2010SSepherosa Ziehau * on programmed interval. Since there is a callout that is 251499fe2010SSepherosa Ziehau * invoked for every hz in driver we use that instead of 251599fe2010SSepherosa Ziehau * relying on periodic SMB interrupt. 251699fe2010SSepherosa Ziehau */ 251799fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_SMB_STAT_TIMER, ALE_USECS(0)); 251899fe2010SSepherosa Ziehau 251999fe2010SSepherosa Ziehau /* Clear MAC statistics. */ 252099fe2010SSepherosa Ziehau ale_stats_clear(sc); 252199fe2010SSepherosa Ziehau 252299fe2010SSepherosa Ziehau /* 252399fe2010SSepherosa Ziehau * Configure Tx/Rx MACs. 252499fe2010SSepherosa Ziehau * - Auto-padding for short frames. 252599fe2010SSepherosa Ziehau * - Enable CRC generation. 252699fe2010SSepherosa Ziehau * Actual reconfiguration of MAC for resolved speed/duplex 252799fe2010SSepherosa Ziehau * is followed after detection of link establishment. 252899fe2010SSepherosa Ziehau * AR81xx always does checksum computation regardless of 252999fe2010SSepherosa Ziehau * MAC_CFG_RXCSUM_ENB bit. In fact, setting the bit will 253099fe2010SSepherosa Ziehau * cause Rx handling issue for fragmented IP datagrams due 253199fe2010SSepherosa Ziehau * to silicon bug. 253299fe2010SSepherosa Ziehau */ 253399fe2010SSepherosa Ziehau reg = MAC_CFG_TX_CRC_ENB | MAC_CFG_TX_AUTO_PAD | MAC_CFG_FULL_DUPLEX | 253499fe2010SSepherosa Ziehau ((MAC_CFG_PREAMBLE_DEFAULT << MAC_CFG_PREAMBLE_SHIFT) & 253599fe2010SSepherosa Ziehau MAC_CFG_PREAMBLE_MASK); 253699fe2010SSepherosa Ziehau if ((sc->ale_flags & ALE_FLAG_FASTETHER) != 0) 253799fe2010SSepherosa Ziehau reg |= MAC_CFG_SPEED_10_100; 253899fe2010SSepherosa Ziehau else 253999fe2010SSepherosa Ziehau reg |= MAC_CFG_SPEED_1000; 254099fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_MAC_CFG, reg); 254199fe2010SSepherosa Ziehau 254299fe2010SSepherosa Ziehau /* Set up the receive filter. */ 254399fe2010SSepherosa Ziehau ale_rxfilter(sc); 254499fe2010SSepherosa Ziehau ale_rxvlan(sc); 254599fe2010SSepherosa Ziehau 254699fe2010SSepherosa Ziehau /* Acknowledge all pending interrupts and clear it. */ 254799fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_INTR_MASK, ALE_INTRS); 254899fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_INTR_STATUS, 0xFFFFFFFF); 254999fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_INTR_STATUS, 0); 255099fe2010SSepherosa Ziehau 255199fe2010SSepherosa Ziehau sc->ale_flags &= ~ALE_FLAG_LINK; 255299fe2010SSepherosa Ziehau 255399fe2010SSepherosa Ziehau /* Switch to the current media. */ 255499fe2010SSepherosa Ziehau mii_mediachg(mii); 255599fe2010SSepherosa Ziehau 255699fe2010SSepherosa Ziehau callout_reset(&sc->ale_tick_ch, hz, ale_tick, sc); 255799fe2010SSepherosa Ziehau 255899fe2010SSepherosa Ziehau ifp->if_flags |= IFF_RUNNING; 25599ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 256099fe2010SSepherosa Ziehau } 256199fe2010SSepherosa Ziehau 256299fe2010SSepherosa Ziehau static void 256399fe2010SSepherosa Ziehau ale_stop(struct ale_softc *sc) 256499fe2010SSepherosa Ziehau { 256599fe2010SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 256699fe2010SSepherosa Ziehau struct ale_txdesc *txd; 256799fe2010SSepherosa Ziehau uint32_t reg; 256899fe2010SSepherosa Ziehau int i; 256999fe2010SSepherosa Ziehau 257099fe2010SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 257199fe2010SSepherosa Ziehau 257299fe2010SSepherosa Ziehau /* 257399fe2010SSepherosa Ziehau * Mark the interface down and cancel the watchdog timer. 257499fe2010SSepherosa Ziehau */ 25759ed293e0SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING; 25769ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 257799fe2010SSepherosa Ziehau ifp->if_timer = 0; 257899fe2010SSepherosa Ziehau 257999fe2010SSepherosa Ziehau callout_stop(&sc->ale_tick_ch); 258099fe2010SSepherosa Ziehau sc->ale_flags &= ~ALE_FLAG_LINK; 258199fe2010SSepherosa Ziehau 258299fe2010SSepherosa Ziehau ale_stats_update(sc); 258399fe2010SSepherosa Ziehau 258499fe2010SSepherosa Ziehau /* Disable interrupts. */ 258599fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_INTR_MASK, 0); 258699fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_INTR_STATUS, 0xFFFFFFFF); 258799fe2010SSepherosa Ziehau 258899fe2010SSepherosa Ziehau /* Disable queue processing and DMA. */ 258999fe2010SSepherosa Ziehau reg = CSR_READ_4(sc, ALE_TXQ_CFG); 259099fe2010SSepherosa Ziehau reg &= ~TXQ_CFG_ENB; 259199fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_TXQ_CFG, reg); 259299fe2010SSepherosa Ziehau reg = CSR_READ_4(sc, ALE_RXQ_CFG); 259399fe2010SSepherosa Ziehau reg &= ~RXQ_CFG_ENB; 259499fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_RXQ_CFG, reg); 259599fe2010SSepherosa Ziehau reg = CSR_READ_4(sc, ALE_DMA_CFG); 259699fe2010SSepherosa Ziehau reg &= ~(DMA_CFG_TXCMB_ENB | DMA_CFG_RXCMB_ENB); 259799fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_DMA_CFG, reg); 259899fe2010SSepherosa Ziehau DELAY(1000); 259999fe2010SSepherosa Ziehau 260099fe2010SSepherosa Ziehau /* Stop Rx/Tx MACs. */ 260199fe2010SSepherosa Ziehau ale_stop_mac(sc); 260299fe2010SSepherosa Ziehau 260399fe2010SSepherosa Ziehau /* Disable interrupts again? XXX */ 260499fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_INTR_STATUS, 0xFFFFFFFF); 260599fe2010SSepherosa Ziehau 260699fe2010SSepherosa Ziehau /* 260799fe2010SSepherosa Ziehau * Free TX mbufs still in the queues. 260899fe2010SSepherosa Ziehau */ 260999fe2010SSepherosa Ziehau for (i = 0; i < ALE_TX_RING_CNT; i++) { 261099fe2010SSepherosa Ziehau txd = &sc->ale_cdata.ale_txdesc[i]; 261199fe2010SSepherosa Ziehau if (txd->tx_m != NULL) { 261299fe2010SSepherosa Ziehau bus_dmamap_unload(sc->ale_cdata.ale_tx_tag, 261399fe2010SSepherosa Ziehau txd->tx_dmamap); 261499fe2010SSepherosa Ziehau m_freem(txd->tx_m); 261599fe2010SSepherosa Ziehau txd->tx_m = NULL; 261699fe2010SSepherosa Ziehau } 261799fe2010SSepherosa Ziehau } 261899fe2010SSepherosa Ziehau } 261999fe2010SSepherosa Ziehau 262099fe2010SSepherosa Ziehau static void 262199fe2010SSepherosa Ziehau ale_stop_mac(struct ale_softc *sc) 262299fe2010SSepherosa Ziehau { 262399fe2010SSepherosa Ziehau uint32_t reg; 262499fe2010SSepherosa Ziehau int i; 262599fe2010SSepherosa Ziehau 262699fe2010SSepherosa Ziehau reg = CSR_READ_4(sc, ALE_MAC_CFG); 262799fe2010SSepherosa Ziehau if ((reg & (MAC_CFG_TX_ENB | MAC_CFG_RX_ENB)) != 0) { 262899fe2010SSepherosa Ziehau reg &= ~MAC_CFG_TX_ENB | MAC_CFG_RX_ENB; 262999fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_MAC_CFG, reg); 263099fe2010SSepherosa Ziehau } 263199fe2010SSepherosa Ziehau 263299fe2010SSepherosa Ziehau for (i = ALE_TIMEOUT; i > 0; i--) { 263399fe2010SSepherosa Ziehau reg = CSR_READ_4(sc, ALE_IDLE_STATUS); 263499fe2010SSepherosa Ziehau if (reg == 0) 263599fe2010SSepherosa Ziehau break; 263699fe2010SSepherosa Ziehau DELAY(10); 263799fe2010SSepherosa Ziehau } 263899fe2010SSepherosa Ziehau if (i == 0) 263999fe2010SSepherosa Ziehau device_printf(sc->ale_dev, 264099fe2010SSepherosa Ziehau "could not disable Tx/Rx MAC(0x%08x)!\n", reg); 264199fe2010SSepherosa Ziehau } 264299fe2010SSepherosa Ziehau 264399fe2010SSepherosa Ziehau static void 264499fe2010SSepherosa Ziehau ale_init_tx_ring(struct ale_softc *sc) 264599fe2010SSepherosa Ziehau { 264699fe2010SSepherosa Ziehau struct ale_txdesc *txd; 264799fe2010SSepherosa Ziehau int i; 264899fe2010SSepherosa Ziehau 264999fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_prod = 0; 265099fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_cons = 0; 265199fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_cnt = 0; 265299fe2010SSepherosa Ziehau 265399fe2010SSepherosa Ziehau bzero(sc->ale_cdata.ale_tx_ring, ALE_TX_RING_SZ); 265499fe2010SSepherosa Ziehau bzero(sc->ale_cdata.ale_tx_cmb, ALE_TX_CMB_SZ); 265599fe2010SSepherosa Ziehau for (i = 0; i < ALE_TX_RING_CNT; i++) { 265699fe2010SSepherosa Ziehau txd = &sc->ale_cdata.ale_txdesc[i]; 265799fe2010SSepherosa Ziehau txd->tx_m = NULL; 265899fe2010SSepherosa Ziehau } 265999fe2010SSepherosa Ziehau *sc->ale_cdata.ale_tx_cmb = 0; 266099fe2010SSepherosa Ziehau bus_dmamap_sync(sc->ale_cdata.ale_tx_cmb_tag, 266199fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_cmb_map, 266299fe2010SSepherosa Ziehau BUS_DMASYNC_PREWRITE); 266399fe2010SSepherosa Ziehau bus_dmamap_sync(sc->ale_cdata.ale_tx_ring_tag, 266499fe2010SSepherosa Ziehau sc->ale_cdata.ale_tx_ring_map, 266599fe2010SSepherosa Ziehau BUS_DMASYNC_PREWRITE); 266699fe2010SSepherosa Ziehau } 266799fe2010SSepherosa Ziehau 266899fe2010SSepherosa Ziehau static void 266999fe2010SSepherosa Ziehau ale_init_rx_pages(struct ale_softc *sc) 267099fe2010SSepherosa Ziehau { 267199fe2010SSepherosa Ziehau struct ale_rx_page *rx_page; 267299fe2010SSepherosa Ziehau int i; 267399fe2010SSepherosa Ziehau 267499fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_seqno = 0; 267599fe2010SSepherosa Ziehau sc->ale_cdata.ale_rx_curp = 0; 267699fe2010SSepherosa Ziehau 267799fe2010SSepherosa Ziehau for (i = 0; i < ALE_RX_PAGES; i++) { 267899fe2010SSepherosa Ziehau rx_page = &sc->ale_cdata.ale_rx_page[i]; 267999fe2010SSepherosa Ziehau bzero(rx_page->page_addr, sc->ale_pagesize); 268099fe2010SSepherosa Ziehau bzero(rx_page->cmb_addr, ALE_RX_CMB_SZ); 268199fe2010SSepherosa Ziehau rx_page->cons = 0; 268299fe2010SSepherosa Ziehau *rx_page->cmb_addr = 0; 268399fe2010SSepherosa Ziehau bus_dmamap_sync(rx_page->page_tag, rx_page->page_map, 268499fe2010SSepherosa Ziehau BUS_DMASYNC_PREWRITE); 268599fe2010SSepherosa Ziehau bus_dmamap_sync(rx_page->cmb_tag, rx_page->cmb_map, 268699fe2010SSepherosa Ziehau BUS_DMASYNC_PREWRITE); 268799fe2010SSepherosa Ziehau } 268899fe2010SSepherosa Ziehau } 268999fe2010SSepherosa Ziehau 269099fe2010SSepherosa Ziehau static void 269199fe2010SSepherosa Ziehau ale_rxvlan(struct ale_softc *sc) 269299fe2010SSepherosa Ziehau { 269399fe2010SSepherosa Ziehau struct ifnet *ifp; 269499fe2010SSepherosa Ziehau uint32_t reg; 269599fe2010SSepherosa Ziehau 269699fe2010SSepherosa Ziehau ifp = &sc->arpcom.ac_if; 269799fe2010SSepherosa Ziehau reg = CSR_READ_4(sc, ALE_MAC_CFG); 269899fe2010SSepherosa Ziehau reg &= ~MAC_CFG_VLAN_TAG_STRIP; 269999fe2010SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 270099fe2010SSepherosa Ziehau reg |= MAC_CFG_VLAN_TAG_STRIP; 270199fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_MAC_CFG, reg); 270299fe2010SSepherosa Ziehau } 270399fe2010SSepherosa Ziehau 270499fe2010SSepherosa Ziehau static void 270599fe2010SSepherosa Ziehau ale_rxfilter(struct ale_softc *sc) 270699fe2010SSepherosa Ziehau { 270799fe2010SSepherosa Ziehau struct ifnet *ifp; 270899fe2010SSepherosa Ziehau struct ifmultiaddr *ifma; 270999fe2010SSepherosa Ziehau uint32_t crc; 271099fe2010SSepherosa Ziehau uint32_t mchash[2]; 271199fe2010SSepherosa Ziehau uint32_t rxcfg; 271299fe2010SSepherosa Ziehau 271399fe2010SSepherosa Ziehau ifp = &sc->arpcom.ac_if; 271499fe2010SSepherosa Ziehau 271599fe2010SSepherosa Ziehau rxcfg = CSR_READ_4(sc, ALE_MAC_CFG); 271699fe2010SSepherosa Ziehau rxcfg &= ~(MAC_CFG_ALLMULTI | MAC_CFG_BCAST | MAC_CFG_PROMISC); 271799fe2010SSepherosa Ziehau if ((ifp->if_flags & IFF_BROADCAST) != 0) 271899fe2010SSepherosa Ziehau rxcfg |= MAC_CFG_BCAST; 271999fe2010SSepherosa Ziehau if ((ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { 272099fe2010SSepherosa Ziehau if ((ifp->if_flags & IFF_PROMISC) != 0) 272199fe2010SSepherosa Ziehau rxcfg |= MAC_CFG_PROMISC; 272299fe2010SSepherosa Ziehau if ((ifp->if_flags & IFF_ALLMULTI) != 0) 272399fe2010SSepherosa Ziehau rxcfg |= MAC_CFG_ALLMULTI; 272499fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_MAR0, 0xFFFFFFFF); 272599fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_MAR1, 0xFFFFFFFF); 272699fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_MAC_CFG, rxcfg); 272799fe2010SSepherosa Ziehau return; 272899fe2010SSepherosa Ziehau } 272999fe2010SSepherosa Ziehau 273099fe2010SSepherosa Ziehau /* Program new filter. */ 273199fe2010SSepherosa Ziehau bzero(mchash, sizeof(mchash)); 273299fe2010SSepherosa Ziehau 2733441d34b2SSascha Wildner TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 273499fe2010SSepherosa Ziehau if (ifma->ifma_addr->sa_family != AF_LINK) 273599fe2010SSepherosa Ziehau continue; 273699fe2010SSepherosa Ziehau crc = ether_crc32_le(LLADDR((struct sockaddr_dl *) 273799fe2010SSepherosa Ziehau ifma->ifma_addr), ETHER_ADDR_LEN); 273899fe2010SSepherosa Ziehau mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); 273999fe2010SSepherosa Ziehau } 274099fe2010SSepherosa Ziehau 274199fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_MAR0, mchash[0]); 274299fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_MAR1, mchash[1]); 274399fe2010SSepherosa Ziehau CSR_WRITE_4(sc, ALE_MAC_CFG, rxcfg); 274499fe2010SSepherosa Ziehau } 274599fe2010SSepherosa Ziehau 274699fe2010SSepherosa Ziehau static int 274799fe2010SSepherosa Ziehau sysctl_hw_ale_int_mod(SYSCTL_HANDLER_ARGS) 274899fe2010SSepherosa Ziehau { 274999fe2010SSepherosa Ziehau return (sysctl_int_range(oidp, arg1, arg2, req, 275099fe2010SSepherosa Ziehau ALE_IM_TIMER_MIN, ALE_IM_TIMER_MAX)); 275199fe2010SSepherosa Ziehau } 275299fe2010SSepherosa Ziehau 275399fe2010SSepherosa Ziehau static void 275499fe2010SSepherosa Ziehau ale_dmamap_buf_cb(void *xctx, bus_dma_segment_t *segs, int nsegs, 275599fe2010SSepherosa Ziehau bus_size_t mapsz __unused, int error) 275699fe2010SSepherosa Ziehau { 275799fe2010SSepherosa Ziehau struct ale_dmamap_ctx *ctx = xctx; 275899fe2010SSepherosa Ziehau int i; 275999fe2010SSepherosa Ziehau 276099fe2010SSepherosa Ziehau if (error) 276199fe2010SSepherosa Ziehau return; 276299fe2010SSepherosa Ziehau 276399fe2010SSepherosa Ziehau if (nsegs > ctx->nsegs) { 276499fe2010SSepherosa Ziehau ctx->nsegs = 0; 276599fe2010SSepherosa Ziehau return; 276699fe2010SSepherosa Ziehau } 276799fe2010SSepherosa Ziehau 276899fe2010SSepherosa Ziehau ctx->nsegs = nsegs; 276999fe2010SSepherosa Ziehau for (i = 0; i < nsegs; ++i) 277099fe2010SSepherosa Ziehau ctx->segs[i] = segs[i]; 277199fe2010SSepherosa Ziehau } 2772