162519d5aSEmmanuel Vadot /*- 262519d5aSEmmanuel Vadot * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> 362519d5aSEmmanuel Vadot * 462519d5aSEmmanuel Vadot * This software was developed by SRI International and the University of 562519d5aSEmmanuel Vadot * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 662519d5aSEmmanuel Vadot * ("CTSRD"), as part of the DARPA CRASH research programme. 762519d5aSEmmanuel Vadot * 862519d5aSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 962519d5aSEmmanuel Vadot * modification, are permitted provided that the following conditions 1062519d5aSEmmanuel Vadot * are met: 1162519d5aSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 1262519d5aSEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 1362519d5aSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 1462519d5aSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 1562519d5aSEmmanuel Vadot * documentation and/or other materials provided with the distribution. 1662519d5aSEmmanuel Vadot * 1762519d5aSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1862519d5aSEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1962519d5aSEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2062519d5aSEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2162519d5aSEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2262519d5aSEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2362519d5aSEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2462519d5aSEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2562519d5aSEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2662519d5aSEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2762519d5aSEmmanuel Vadot * SUCH DAMAGE. 2862519d5aSEmmanuel Vadot */ 2962519d5aSEmmanuel Vadot 3062519d5aSEmmanuel Vadot /* 3162519d5aSEmmanuel Vadot * Ethernet media access controller (EMAC) 3262519d5aSEmmanuel Vadot * Chapter 17, Altera Cyclone V Device Handbook (CV-5V2 2014.07.22) 3362519d5aSEmmanuel Vadot * 3462519d5aSEmmanuel Vadot * EMAC is an instance of the Synopsys DesignWare 3504-0 3562519d5aSEmmanuel Vadot * Universal 10/100/1000 Ethernet MAC (DWC_gmac). 3662519d5aSEmmanuel Vadot */ 3762519d5aSEmmanuel Vadot 3862519d5aSEmmanuel Vadot #include <sys/param.h> 3962519d5aSEmmanuel Vadot #include <sys/systm.h> 4062519d5aSEmmanuel Vadot #include <sys/bus.h> 4162519d5aSEmmanuel Vadot #include <sys/kernel.h> 4262519d5aSEmmanuel Vadot #include <sys/lock.h> 4362519d5aSEmmanuel Vadot #include <sys/malloc.h> 4462519d5aSEmmanuel Vadot #include <sys/mbuf.h> 4562519d5aSEmmanuel Vadot #include <sys/module.h> 4662519d5aSEmmanuel Vadot #include <sys/mutex.h> 4762519d5aSEmmanuel Vadot #include <sys/rman.h> 4862519d5aSEmmanuel Vadot #include <sys/socket.h> 4962519d5aSEmmanuel Vadot 5062519d5aSEmmanuel Vadot #include <net/if.h> 5162519d5aSEmmanuel Vadot #include <net/ethernet.h> 5262519d5aSEmmanuel Vadot #include <net/if_dl.h> 5362519d5aSEmmanuel Vadot #include <net/if_media.h> 5462519d5aSEmmanuel Vadot 5562519d5aSEmmanuel Vadot #include <machine/bus.h> 5662519d5aSEmmanuel Vadot 57be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h> 5862519d5aSEmmanuel Vadot #include <dev/extres/hwreset/hwreset.h> 5962519d5aSEmmanuel Vadot 6062519d5aSEmmanuel Vadot #include <dev/mii/mii.h> 6162519d5aSEmmanuel Vadot #include <dev/mii/miivar.h> 6262519d5aSEmmanuel Vadot #include <dev/ofw/ofw_bus.h> 6362519d5aSEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h> 6462519d5aSEmmanuel Vadot #include <dev/mii/mii_fdt.h> 6562519d5aSEmmanuel Vadot 6662519d5aSEmmanuel Vadot #include <dev/dwc/if_dwcvar.h> 6762519d5aSEmmanuel Vadot #include <dev/dwc/dwc1000_reg.h> 6862519d5aSEmmanuel Vadot #include <dev/dwc/dwc1000_core.h> 6962519d5aSEmmanuel Vadot #include <dev/dwc/dwc1000_dma.h> 7062519d5aSEmmanuel Vadot 7162519d5aSEmmanuel Vadot #include "if_dwc_if.h" 7262519d5aSEmmanuel Vadot 73627726b5SEmmanuel Vadot struct dwc_hash_maddr_ctx { 74627726b5SEmmanuel Vadot struct dwc_softc *sc; 75627726b5SEmmanuel Vadot uint32_t hash[8]; 76627726b5SEmmanuel Vadot }; 77627726b5SEmmanuel Vadot 7862519d5aSEmmanuel Vadot #define STATS_HARVEST_INTERVAL 2 7962519d5aSEmmanuel Vadot 8062519d5aSEmmanuel Vadot /* Pause time field in the transmitted control frame */ 8162519d5aSEmmanuel Vadot static int dwc_pause_time = 0xffff; 8262519d5aSEmmanuel Vadot TUNABLE_INT("hw.dwc.pause_time", &dwc_pause_time); 8362519d5aSEmmanuel Vadot 8462519d5aSEmmanuel Vadot /* 8562519d5aSEmmanuel Vadot * MIIBUS functions 8662519d5aSEmmanuel Vadot */ 8762519d5aSEmmanuel Vadot 8862519d5aSEmmanuel Vadot int 8962519d5aSEmmanuel Vadot dwc1000_miibus_read_reg(device_t dev, int phy, int reg) 9062519d5aSEmmanuel Vadot { 9162519d5aSEmmanuel Vadot struct dwc_softc *sc; 9262519d5aSEmmanuel Vadot uint16_t mii; 9362519d5aSEmmanuel Vadot size_t cnt; 9462519d5aSEmmanuel Vadot int rv = 0; 9562519d5aSEmmanuel Vadot 9662519d5aSEmmanuel Vadot sc = device_get_softc(dev); 9762519d5aSEmmanuel Vadot 9862519d5aSEmmanuel Vadot mii = ((phy & GMII_ADDRESS_PA_MASK) << GMII_ADDRESS_PA_SHIFT) 9962519d5aSEmmanuel Vadot | ((reg & GMII_ADDRESS_GR_MASK) << GMII_ADDRESS_GR_SHIFT) 10062519d5aSEmmanuel Vadot | (sc->mii_clk << GMII_ADDRESS_CR_SHIFT) 10162519d5aSEmmanuel Vadot | GMII_ADDRESS_GB; /* Busy flag */ 10262519d5aSEmmanuel Vadot 10362519d5aSEmmanuel Vadot WRITE4(sc, GMII_ADDRESS, mii); 10462519d5aSEmmanuel Vadot 10562519d5aSEmmanuel Vadot for (cnt = 0; cnt < 1000; cnt++) { 10662519d5aSEmmanuel Vadot if (!(READ4(sc, GMII_ADDRESS) & GMII_ADDRESS_GB)) { 10762519d5aSEmmanuel Vadot rv = READ4(sc, GMII_DATA); 10862519d5aSEmmanuel Vadot break; 10962519d5aSEmmanuel Vadot } 11062519d5aSEmmanuel Vadot DELAY(10); 11162519d5aSEmmanuel Vadot } 11262519d5aSEmmanuel Vadot 11362519d5aSEmmanuel Vadot return rv; 11462519d5aSEmmanuel Vadot } 11562519d5aSEmmanuel Vadot 11662519d5aSEmmanuel Vadot int 11762519d5aSEmmanuel Vadot dwc1000_miibus_write_reg(device_t dev, int phy, int reg, int val) 11862519d5aSEmmanuel Vadot { 11962519d5aSEmmanuel Vadot struct dwc_softc *sc; 12062519d5aSEmmanuel Vadot uint16_t mii; 12162519d5aSEmmanuel Vadot size_t cnt; 12262519d5aSEmmanuel Vadot 12362519d5aSEmmanuel Vadot sc = device_get_softc(dev); 12462519d5aSEmmanuel Vadot 12562519d5aSEmmanuel Vadot mii = ((phy & GMII_ADDRESS_PA_MASK) << GMII_ADDRESS_PA_SHIFT) 12662519d5aSEmmanuel Vadot | ((reg & GMII_ADDRESS_GR_MASK) << GMII_ADDRESS_GR_SHIFT) 12762519d5aSEmmanuel Vadot | (sc->mii_clk << GMII_ADDRESS_CR_SHIFT) 12862519d5aSEmmanuel Vadot | GMII_ADDRESS_GB | GMII_ADDRESS_GW; 12962519d5aSEmmanuel Vadot 13062519d5aSEmmanuel Vadot WRITE4(sc, GMII_DATA, val); 13162519d5aSEmmanuel Vadot WRITE4(sc, GMII_ADDRESS, mii); 13262519d5aSEmmanuel Vadot 13362519d5aSEmmanuel Vadot for (cnt = 0; cnt < 1000; cnt++) { 13462519d5aSEmmanuel Vadot if (!(READ4(sc, GMII_ADDRESS) & GMII_ADDRESS_GB)) { 13562519d5aSEmmanuel Vadot break; 13662519d5aSEmmanuel Vadot } 13762519d5aSEmmanuel Vadot DELAY(10); 13862519d5aSEmmanuel Vadot } 13962519d5aSEmmanuel Vadot 14062519d5aSEmmanuel Vadot return (0); 14162519d5aSEmmanuel Vadot } 14262519d5aSEmmanuel Vadot 14362519d5aSEmmanuel Vadot void 14462519d5aSEmmanuel Vadot dwc1000_miibus_statchg(device_t dev) 14562519d5aSEmmanuel Vadot { 14662519d5aSEmmanuel Vadot struct dwc_softc *sc; 14762519d5aSEmmanuel Vadot struct mii_data *mii; 14862519d5aSEmmanuel Vadot uint32_t reg; 14962519d5aSEmmanuel Vadot 15062519d5aSEmmanuel Vadot /* 15162519d5aSEmmanuel Vadot * Called by the MII bus driver when the PHY establishes 15262519d5aSEmmanuel Vadot * link to set the MAC interface registers. 15362519d5aSEmmanuel Vadot */ 15462519d5aSEmmanuel Vadot 15562519d5aSEmmanuel Vadot sc = device_get_softc(dev); 15662519d5aSEmmanuel Vadot 15762519d5aSEmmanuel Vadot DWC_ASSERT_LOCKED(sc); 15862519d5aSEmmanuel Vadot 15962519d5aSEmmanuel Vadot mii = sc->mii_softc; 16062519d5aSEmmanuel Vadot 16162519d5aSEmmanuel Vadot if (mii->mii_media_status & IFM_ACTIVE) 16262519d5aSEmmanuel Vadot sc->link_is_up = true; 16362519d5aSEmmanuel Vadot else 16462519d5aSEmmanuel Vadot sc->link_is_up = false; 16562519d5aSEmmanuel Vadot 16662519d5aSEmmanuel Vadot reg = READ4(sc, MAC_CONFIGURATION); 16762519d5aSEmmanuel Vadot switch (IFM_SUBTYPE(mii->mii_media_active)) { 16862519d5aSEmmanuel Vadot case IFM_1000_T: 16962519d5aSEmmanuel Vadot case IFM_1000_SX: 17062519d5aSEmmanuel Vadot reg &= ~(CONF_FES | CONF_PS); 17162519d5aSEmmanuel Vadot break; 17262519d5aSEmmanuel Vadot case IFM_100_TX: 17362519d5aSEmmanuel Vadot reg |= (CONF_FES | CONF_PS); 17462519d5aSEmmanuel Vadot break; 17562519d5aSEmmanuel Vadot case IFM_10_T: 17662519d5aSEmmanuel Vadot reg &= ~(CONF_FES); 17762519d5aSEmmanuel Vadot reg |= (CONF_PS); 17862519d5aSEmmanuel Vadot break; 17962519d5aSEmmanuel Vadot case IFM_NONE: 18062519d5aSEmmanuel Vadot sc->link_is_up = false; 18162519d5aSEmmanuel Vadot return; 18262519d5aSEmmanuel Vadot default: 18362519d5aSEmmanuel Vadot sc->link_is_up = false; 18462519d5aSEmmanuel Vadot device_printf(dev, "Unsupported media %u\n", 18562519d5aSEmmanuel Vadot IFM_SUBTYPE(mii->mii_media_active)); 18662519d5aSEmmanuel Vadot return; 18762519d5aSEmmanuel Vadot } 18862519d5aSEmmanuel Vadot if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) 18962519d5aSEmmanuel Vadot reg |= (CONF_DM); 19062519d5aSEmmanuel Vadot else 19162519d5aSEmmanuel Vadot reg &= ~(CONF_DM); 19262519d5aSEmmanuel Vadot WRITE4(sc, MAC_CONFIGURATION, reg); 19362519d5aSEmmanuel Vadot 19462519d5aSEmmanuel Vadot reg = FLOW_CONTROL_UP; 19562519d5aSEmmanuel Vadot if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) 19662519d5aSEmmanuel Vadot reg |= FLOW_CONTROL_TX; 19762519d5aSEmmanuel Vadot if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) 19862519d5aSEmmanuel Vadot reg |= FLOW_CONTROL_RX; 19962519d5aSEmmanuel Vadot if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) 20062519d5aSEmmanuel Vadot reg |= dwc_pause_time << FLOW_CONTROL_PT_SHIFT; 20162519d5aSEmmanuel Vadot WRITE4(sc, FLOW_CONTROL, reg); 20262519d5aSEmmanuel Vadot 20362519d5aSEmmanuel Vadot IF_DWC_SET_SPEED(dev, IFM_SUBTYPE(mii->mii_media_active)); 20462519d5aSEmmanuel Vadot 20562519d5aSEmmanuel Vadot } 20662519d5aSEmmanuel Vadot 20762519d5aSEmmanuel Vadot void 20862519d5aSEmmanuel Vadot dwc1000_core_setup(struct dwc_softc *sc) 20962519d5aSEmmanuel Vadot { 21062519d5aSEmmanuel Vadot uint32_t reg; 21162519d5aSEmmanuel Vadot 21262519d5aSEmmanuel Vadot DWC_ASSERT_LOCKED(sc); 21362519d5aSEmmanuel Vadot 21462519d5aSEmmanuel Vadot /* Enable core */ 21562519d5aSEmmanuel Vadot reg = READ4(sc, MAC_CONFIGURATION); 21662519d5aSEmmanuel Vadot reg |= (CONF_JD | CONF_ACS | CONF_BE); 21762519d5aSEmmanuel Vadot WRITE4(sc, MAC_CONFIGURATION, reg); 21862519d5aSEmmanuel Vadot } 21962519d5aSEmmanuel Vadot 22062519d5aSEmmanuel Vadot void 22162519d5aSEmmanuel Vadot dwc1000_enable_mac(struct dwc_softc *sc, bool enable) 22262519d5aSEmmanuel Vadot { 22362519d5aSEmmanuel Vadot uint32_t reg; 22462519d5aSEmmanuel Vadot 22562519d5aSEmmanuel Vadot DWC_ASSERT_LOCKED(sc); 22662519d5aSEmmanuel Vadot reg = READ4(sc, MAC_CONFIGURATION); 22762519d5aSEmmanuel Vadot if (enable) 22862519d5aSEmmanuel Vadot reg |= CONF_TE | CONF_RE; 22962519d5aSEmmanuel Vadot else 23062519d5aSEmmanuel Vadot reg &= ~(CONF_TE | CONF_RE); 23162519d5aSEmmanuel Vadot WRITE4(sc, MAC_CONFIGURATION, reg); 23262519d5aSEmmanuel Vadot } 23362519d5aSEmmanuel Vadot 23462519d5aSEmmanuel Vadot void 23562519d5aSEmmanuel Vadot dwc1000_enable_csum_offload(struct dwc_softc *sc) 23662519d5aSEmmanuel Vadot { 23762519d5aSEmmanuel Vadot uint32_t reg; 23862519d5aSEmmanuel Vadot 23962519d5aSEmmanuel Vadot DWC_ASSERT_LOCKED(sc); 24062519d5aSEmmanuel Vadot reg = READ4(sc, MAC_CONFIGURATION); 24162519d5aSEmmanuel Vadot if ((if_getcapenable(sc->ifp) & IFCAP_RXCSUM) != 0) 24262519d5aSEmmanuel Vadot reg |= CONF_IPC; 24362519d5aSEmmanuel Vadot else 24462519d5aSEmmanuel Vadot reg &= ~CONF_IPC; 24562519d5aSEmmanuel Vadot WRITE4(sc, MAC_CONFIGURATION, reg); 24662519d5aSEmmanuel Vadot } 24762519d5aSEmmanuel Vadot 24862519d5aSEmmanuel Vadot static const uint8_t nibbletab[] = { 24962519d5aSEmmanuel Vadot /* 0x0 0000 -> 0000 */ 0x0, 25062519d5aSEmmanuel Vadot /* 0x1 0001 -> 1000 */ 0x8, 25162519d5aSEmmanuel Vadot /* 0x2 0010 -> 0100 */ 0x4, 25262519d5aSEmmanuel Vadot /* 0x3 0011 -> 1100 */ 0xc, 25362519d5aSEmmanuel Vadot /* 0x4 0100 -> 0010 */ 0x2, 25462519d5aSEmmanuel Vadot /* 0x5 0101 -> 1010 */ 0xa, 25562519d5aSEmmanuel Vadot /* 0x6 0110 -> 0110 */ 0x6, 25662519d5aSEmmanuel Vadot /* 0x7 0111 -> 1110 */ 0xe, 25762519d5aSEmmanuel Vadot /* 0x8 1000 -> 0001 */ 0x1, 25862519d5aSEmmanuel Vadot /* 0x9 1001 -> 1001 */ 0x9, 25962519d5aSEmmanuel Vadot /* 0xa 1010 -> 0101 */ 0x5, 26062519d5aSEmmanuel Vadot /* 0xb 1011 -> 1101 */ 0xd, 26162519d5aSEmmanuel Vadot /* 0xc 1100 -> 0011 */ 0x3, 26262519d5aSEmmanuel Vadot /* 0xd 1101 -> 1011 */ 0xb, 26362519d5aSEmmanuel Vadot /* 0xe 1110 -> 0111 */ 0x7, 26462519d5aSEmmanuel Vadot /* 0xf 1111 -> 1111 */ 0xf, }; 26562519d5aSEmmanuel Vadot 26662519d5aSEmmanuel Vadot static uint8_t 26762519d5aSEmmanuel Vadot bitreverse(uint8_t x) 26862519d5aSEmmanuel Vadot { 26962519d5aSEmmanuel Vadot 27062519d5aSEmmanuel Vadot return (nibbletab[x & 0xf] << 4) | nibbletab[x >> 4]; 27162519d5aSEmmanuel Vadot } 27262519d5aSEmmanuel Vadot 27362519d5aSEmmanuel Vadot static u_int 27462519d5aSEmmanuel Vadot dwc_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 27562519d5aSEmmanuel Vadot { 27662519d5aSEmmanuel Vadot struct dwc_hash_maddr_ctx *ctx = arg; 27762519d5aSEmmanuel Vadot uint32_t crc, hashbit, hashreg; 27862519d5aSEmmanuel Vadot uint8_t val; 27962519d5aSEmmanuel Vadot 28062519d5aSEmmanuel Vadot crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN); 28162519d5aSEmmanuel Vadot /* Take lower 8 bits and reverse it */ 28262519d5aSEmmanuel Vadot val = bitreverse(~crc & 0xff); 2834b7975ecSEmmanuel Vadot /* 2844b7975ecSEmmanuel Vadot * TODO: There is probably a HW_FEATURES bit which isn't 2854b7975ecSEmmanuel Vadot * related to the extended descriptors that describe this 2864b7975ecSEmmanuel Vadot */ 2874b7975ecSEmmanuel Vadot if (!ctx->sc->dma_ext_desc) 28862519d5aSEmmanuel Vadot val >>= 2; /* Only need lower 6 bits */ 28962519d5aSEmmanuel Vadot hashreg = (val >> 5); 29062519d5aSEmmanuel Vadot hashbit = (val & 31); 29162519d5aSEmmanuel Vadot ctx->hash[hashreg] |= (1 << hashbit); 29262519d5aSEmmanuel Vadot 29362519d5aSEmmanuel Vadot return (1); 29462519d5aSEmmanuel Vadot } 29562519d5aSEmmanuel Vadot 29662519d5aSEmmanuel Vadot void 29762519d5aSEmmanuel Vadot dwc1000_setup_rxfilter(struct dwc_softc *sc) 29862519d5aSEmmanuel Vadot { 29962519d5aSEmmanuel Vadot struct dwc_hash_maddr_ctx ctx; 30062519d5aSEmmanuel Vadot if_t ifp; 30162519d5aSEmmanuel Vadot uint8_t *eaddr; 30262519d5aSEmmanuel Vadot uint32_t ffval, hi, lo; 30362519d5aSEmmanuel Vadot int nhash, i; 30462519d5aSEmmanuel Vadot 30562519d5aSEmmanuel Vadot DWC_ASSERT_LOCKED(sc); 30662519d5aSEmmanuel Vadot 30762519d5aSEmmanuel Vadot ifp = sc->ifp; 3084b7975ecSEmmanuel Vadot /* 3094b7975ecSEmmanuel Vadot * TODO: There is probably a HW_FEATURES bit which isn't 3104b7975ecSEmmanuel Vadot * related to the extended descriptors that describe this 3114b7975ecSEmmanuel Vadot */ 3124b7975ecSEmmanuel Vadot nhash = sc->dma_ext_desc == false ? 2 : 8; 31362519d5aSEmmanuel Vadot 31462519d5aSEmmanuel Vadot /* 31562519d5aSEmmanuel Vadot * Set the multicast (group) filter hash. 31662519d5aSEmmanuel Vadot */ 31762519d5aSEmmanuel Vadot if ((if_getflags(ifp) & IFF_ALLMULTI) != 0) { 31862519d5aSEmmanuel Vadot ffval = (FRAME_FILTER_PM); 31962519d5aSEmmanuel Vadot for (i = 0; i < nhash; i++) 32062519d5aSEmmanuel Vadot ctx.hash[i] = ~0; 32162519d5aSEmmanuel Vadot } else { 32262519d5aSEmmanuel Vadot ffval = (FRAME_FILTER_HMC); 32362519d5aSEmmanuel Vadot for (i = 0; i < nhash; i++) 32462519d5aSEmmanuel Vadot ctx.hash[i] = 0; 32562519d5aSEmmanuel Vadot ctx.sc = sc; 32662519d5aSEmmanuel Vadot if_foreach_llmaddr(ifp, dwc_hash_maddr, &ctx); 32762519d5aSEmmanuel Vadot } 32862519d5aSEmmanuel Vadot 32962519d5aSEmmanuel Vadot /* 33062519d5aSEmmanuel Vadot * Set the individual address filter hash. 33162519d5aSEmmanuel Vadot */ 33262519d5aSEmmanuel Vadot if ((if_getflags(ifp) & IFF_PROMISC) != 0) 33362519d5aSEmmanuel Vadot ffval |= (FRAME_FILTER_PR); 33462519d5aSEmmanuel Vadot 33562519d5aSEmmanuel Vadot /* 33662519d5aSEmmanuel Vadot * Set the primary address. 33762519d5aSEmmanuel Vadot */ 33862519d5aSEmmanuel Vadot eaddr = if_getlladdr(ifp); 33962519d5aSEmmanuel Vadot lo = eaddr[0] | (eaddr[1] << 8) | (eaddr[2] << 16) | 34062519d5aSEmmanuel Vadot (eaddr[3] << 24); 34162519d5aSEmmanuel Vadot hi = eaddr[4] | (eaddr[5] << 8); 34262519d5aSEmmanuel Vadot WRITE4(sc, MAC_ADDRESS_LOW(0), lo); 34362519d5aSEmmanuel Vadot WRITE4(sc, MAC_ADDRESS_HIGH(0), hi); 34462519d5aSEmmanuel Vadot WRITE4(sc, MAC_FRAME_FILTER, ffval); 3454b7975ecSEmmanuel Vadot if (!sc->dma_ext_desc) { 34662519d5aSEmmanuel Vadot WRITE4(sc, GMAC_MAC_HTLOW, ctx.hash[0]); 34762519d5aSEmmanuel Vadot WRITE4(sc, GMAC_MAC_HTHIGH, ctx.hash[1]); 34862519d5aSEmmanuel Vadot } else { 34962519d5aSEmmanuel Vadot for (i = 0; i < nhash; i++) 35062519d5aSEmmanuel Vadot WRITE4(sc, HASH_TABLE_REG(i), ctx.hash[i]); 35162519d5aSEmmanuel Vadot } 35262519d5aSEmmanuel Vadot } 35362519d5aSEmmanuel Vadot 35462519d5aSEmmanuel Vadot void 35562519d5aSEmmanuel Vadot dwc1000_get_hwaddr(struct dwc_softc *sc, uint8_t *hwaddr) 35662519d5aSEmmanuel Vadot { 35762519d5aSEmmanuel Vadot uint32_t hi, lo, rnd; 35862519d5aSEmmanuel Vadot 35962519d5aSEmmanuel Vadot /* 36062519d5aSEmmanuel Vadot * Try to recover a MAC address from the running hardware. If there's 36162519d5aSEmmanuel Vadot * something non-zero there, assume the bootloader did the right thing 36262519d5aSEmmanuel Vadot * and just use it. 36362519d5aSEmmanuel Vadot * 36462519d5aSEmmanuel Vadot * Otherwise, set the address to a convenient locally assigned address, 36562519d5aSEmmanuel Vadot * 'bsd' + random 24 low-order bits. 'b' is 0x62, which has the locally 36662519d5aSEmmanuel Vadot * assigned bit set, and the broadcast/multicast bit clear. 36762519d5aSEmmanuel Vadot */ 36862519d5aSEmmanuel Vadot lo = READ4(sc, MAC_ADDRESS_LOW(0)); 36962519d5aSEmmanuel Vadot hi = READ4(sc, MAC_ADDRESS_HIGH(0)) & 0xffff; 37062519d5aSEmmanuel Vadot if ((lo != 0xffffffff) || (hi != 0xffff)) { 37162519d5aSEmmanuel Vadot hwaddr[0] = (lo >> 0) & 0xff; 37262519d5aSEmmanuel Vadot hwaddr[1] = (lo >> 8) & 0xff; 37362519d5aSEmmanuel Vadot hwaddr[2] = (lo >> 16) & 0xff; 37462519d5aSEmmanuel Vadot hwaddr[3] = (lo >> 24) & 0xff; 37562519d5aSEmmanuel Vadot hwaddr[4] = (hi >> 0) & 0xff; 37662519d5aSEmmanuel Vadot hwaddr[5] = (hi >> 8) & 0xff; 37762519d5aSEmmanuel Vadot } else { 37862519d5aSEmmanuel Vadot rnd = arc4random() & 0x00ffffff; 37962519d5aSEmmanuel Vadot hwaddr[0] = 'b'; 38062519d5aSEmmanuel Vadot hwaddr[1] = 's'; 38162519d5aSEmmanuel Vadot hwaddr[2] = 'd'; 38262519d5aSEmmanuel Vadot hwaddr[3] = rnd >> 16; 38362519d5aSEmmanuel Vadot hwaddr[4] = rnd >> 8; 38462519d5aSEmmanuel Vadot hwaddr[5] = rnd >> 0; 38562519d5aSEmmanuel Vadot } 38662519d5aSEmmanuel Vadot } 38762519d5aSEmmanuel Vadot 38862519d5aSEmmanuel Vadot /* 38962519d5aSEmmanuel Vadot * Stats 39062519d5aSEmmanuel Vadot */ 39162519d5aSEmmanuel Vadot 39262519d5aSEmmanuel Vadot static void 39362519d5aSEmmanuel Vadot dwc1000_clear_stats(struct dwc_softc *sc) 39462519d5aSEmmanuel Vadot { 39562519d5aSEmmanuel Vadot uint32_t reg; 39662519d5aSEmmanuel Vadot 39762519d5aSEmmanuel Vadot reg = READ4(sc, MMC_CONTROL); 39862519d5aSEmmanuel Vadot reg |= (MMC_CONTROL_CNTRST); 39962519d5aSEmmanuel Vadot WRITE4(sc, MMC_CONTROL, reg); 40062519d5aSEmmanuel Vadot } 40162519d5aSEmmanuel Vadot 40262519d5aSEmmanuel Vadot void 40362519d5aSEmmanuel Vadot dwc1000_harvest_stats(struct dwc_softc *sc) 40462519d5aSEmmanuel Vadot { 40562519d5aSEmmanuel Vadot if_t ifp; 40662519d5aSEmmanuel Vadot 40762519d5aSEmmanuel Vadot /* We don't need to harvest too often. */ 40862519d5aSEmmanuel Vadot if (++sc->stats_harvest_count < STATS_HARVEST_INTERVAL) 40962519d5aSEmmanuel Vadot return; 41062519d5aSEmmanuel Vadot 41162519d5aSEmmanuel Vadot sc->stats_harvest_count = 0; 41262519d5aSEmmanuel Vadot ifp = sc->ifp; 41362519d5aSEmmanuel Vadot 41462519d5aSEmmanuel Vadot if_inc_counter(ifp, IFCOUNTER_IERRORS, 41562519d5aSEmmanuel Vadot READ4(sc, RXOVERSIZE_G) + READ4(sc, RXUNDERSIZE_G) + 41662519d5aSEmmanuel Vadot READ4(sc, RXCRCERROR) + READ4(sc, RXALIGNMENTERROR) + 41762519d5aSEmmanuel Vadot READ4(sc, RXRUNTERROR) + READ4(sc, RXJABBERERROR) + 41862519d5aSEmmanuel Vadot READ4(sc, RXLENGTHERROR)); 41962519d5aSEmmanuel Vadot 42062519d5aSEmmanuel Vadot if_inc_counter(ifp, IFCOUNTER_OERRORS, 42162519d5aSEmmanuel Vadot READ4(sc, TXOVERSIZE_G) + READ4(sc, TXEXCESSDEF) + 42262519d5aSEmmanuel Vadot READ4(sc, TXCARRIERERR) + READ4(sc, TXUNDERFLOWERROR)); 42362519d5aSEmmanuel Vadot 42462519d5aSEmmanuel Vadot if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 42562519d5aSEmmanuel Vadot READ4(sc, TXEXESSCOL) + READ4(sc, TXLATECOL)); 42662519d5aSEmmanuel Vadot 42762519d5aSEmmanuel Vadot dwc1000_clear_stats(sc); 42862519d5aSEmmanuel Vadot } 42929776aa4SEmmanuel Vadot 43029776aa4SEmmanuel Vadot void 43129776aa4SEmmanuel Vadot dwc1000_intr(struct dwc_softc *sc) 43229776aa4SEmmanuel Vadot { 43329776aa4SEmmanuel Vadot uint32_t reg; 43429776aa4SEmmanuel Vadot 43529776aa4SEmmanuel Vadot DWC_ASSERT_LOCKED(sc); 43629776aa4SEmmanuel Vadot 43729776aa4SEmmanuel Vadot reg = READ4(sc, INTERRUPT_STATUS); 43829776aa4SEmmanuel Vadot if (reg) 43929776aa4SEmmanuel Vadot READ4(sc, SGMII_RGMII_SMII_CTRL_STATUS); 44029776aa4SEmmanuel Vadot } 44129776aa4SEmmanuel Vadot 44229776aa4SEmmanuel Vadot void 44329776aa4SEmmanuel Vadot dwc1000_intr_disable(struct dwc_softc *sc) 44429776aa4SEmmanuel Vadot { 44529776aa4SEmmanuel Vadot 44629776aa4SEmmanuel Vadot WRITE4(sc, INTERRUPT_ENABLE, 0); 44729776aa4SEmmanuel Vadot } 448