git: 62519d5a4f71 - main - dwc: Split core functions
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 05 Oct 2023 15:35:03 UTC
The branch main has been updated by manu: URL: https://cgit.FreeBSD.org/src/commit/?id=62519d5a4f719a420803a3a0823268da6e950fcb commit 62519d5a4f719a420803a3a0823268da6e950fcb Author: Emmanuel Vadot <manu@FreeBSD.org> AuthorDate: 2023-09-28 19:38:36 +0000 Commit: Emmanuel Vadot <manu@FreeBSD.org> CommitDate: 2023-10-05 15:34:39 +0000 dwc: Split core functions Synopsis/Designware controller have multiple version. The version currently supported by dwc(4) is the version 3 and it's usually called 1000 for gigabit. In the goal to support all of those in the same base driver start splitting the core function to a new file. No functional changes intended. --- sys/conf/files.arm | 1 + sys/conf/files.arm64 | 1 + sys/dev/dwc/dwc1000_core.c | 416 +++++++++++++++++++++++++++++++++++++++++++++ sys/dev/dwc/dwc1000_core.h | 43 +++++ sys/dev/dwc/if_dwc.c | 378 ++-------------------------------------- 5 files changed, 476 insertions(+), 363 deletions(-) diff --git a/sys/conf/files.arm b/sys/conf/files.arm index d47f2b7a78e8..772bbb8b0e3b 100644 --- a/sys/conf/files.arm +++ b/sys/conf/files.arm @@ -88,6 +88,7 @@ crypto/des/des_enc.c optional netsmb dev/cpufreq/cpufreq_dt.c optional cpufreq fdt dev/dwc/if_dwc.c optional dwc dev/dwc/if_dwc_if.m optional dwc +dev/dwc/dwc1000_core.c optional dwc dev/dwc/dwc1000_dma.c optional dwc dev/fb/fb.c optional sc dev/fdt/fdt_arm_platform.c optional platform fdt diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 index b9e690d2ca50..38b9e40463eb 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -227,6 +227,7 @@ dev/dpaa2/memac_mdio_if.m optional soc_nxp_ls dpaa2 acpi | soc_nxp_ls dpaa2 fd # Synopsys DesignWare Ethernet Controller dev/dwc/if_dwc.c optional fdt dwc_rk soc_rockchip_rk3328 | fdt dwc_rk soc_rockchip_rk3399 | fdt dwc_socfpga soc_intel_stratix10 dev/dwc/if_dwc_if.m optional fdt dwc_rk soc_rockchip_rk3328 | fdt dwc_rk soc_rockchip_rk3399 | fdt dwc_socfpga soc_intel_stratix10 +dev/dwc/dwc1000_core.c optional fdt dwc_rk soc_rockchip_rk3328 | fdt dwc_rk soc_rockchip_rk3399 | fdt dwc_socfpga soc_intel_stratix10 dev/dwc/dwc1000_dma.c optional fdt dwc_rk soc_rockchip_rk3328 | fdt dwc_rk soc_rockchip_rk3399 | fdt dwc_socfpga soc_intel_stratix10 dev/dwc/if_dwc_rk.c optional fdt dwc_rk soc_rockchip_rk3328 | fdt dwc_rk soc_rockchip_rk3399 dev/dwc/if_dwc_socfpga.c optional fdt dwc_socfpga diff --git a/sys/dev/dwc/dwc1000_core.c b/sys/dev/dwc/dwc1000_core.c new file mode 100644 index 000000000000..ef6db707a3a1 --- /dev/null +++ b/sys/dev/dwc/dwc1000_core.c @@ -0,0 +1,416 @@ +/*- + * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) + * ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Ethernet media access controller (EMAC) + * Chapter 17, Altera Cyclone V Device Handbook (CV-5V2 2014.07.22) + * + * EMAC is an instance of the Synopsys DesignWare 3504-0 + * Universal 10/100/1000 Ethernet MAC (DWC_gmac). + */ + +#include <sys/cdefs.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/rman.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> + +#include <machine/bus.h> + +#include <dev/extres/clk/clk.h> +#include <dev/extres/hwreset/hwreset.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> +#include <dev/mii/mii_fdt.h> + +#include <dev/dwc/if_dwcvar.h> +#include <dev/dwc/dwc1000_reg.h> +#include <dev/dwc/dwc1000_core.h> +#include <dev/dwc/dwc1000_dma.h> + +#include "if_dwc_if.h" + +#define STATS_HARVEST_INTERVAL 2 + +/* Pause time field in the transmitted control frame */ +static int dwc_pause_time = 0xffff; +TUNABLE_INT("hw.dwc.pause_time", &dwc_pause_time); + +/* + * MIIBUS functions + */ + +int +dwc1000_miibus_read_reg(device_t dev, int phy, int reg) +{ + struct dwc_softc *sc; + uint16_t mii; + size_t cnt; + int rv = 0; + + sc = device_get_softc(dev); + + mii = ((phy & GMII_ADDRESS_PA_MASK) << GMII_ADDRESS_PA_SHIFT) + | ((reg & GMII_ADDRESS_GR_MASK) << GMII_ADDRESS_GR_SHIFT) + | (sc->mii_clk << GMII_ADDRESS_CR_SHIFT) + | GMII_ADDRESS_GB; /* Busy flag */ + + WRITE4(sc, GMII_ADDRESS, mii); + + for (cnt = 0; cnt < 1000; cnt++) { + if (!(READ4(sc, GMII_ADDRESS) & GMII_ADDRESS_GB)) { + rv = READ4(sc, GMII_DATA); + break; + } + DELAY(10); + } + + return rv; +} + +int +dwc1000_miibus_write_reg(device_t dev, int phy, int reg, int val) +{ + struct dwc_softc *sc; + uint16_t mii; + size_t cnt; + + sc = device_get_softc(dev); + + mii = ((phy & GMII_ADDRESS_PA_MASK) << GMII_ADDRESS_PA_SHIFT) + | ((reg & GMII_ADDRESS_GR_MASK) << GMII_ADDRESS_GR_SHIFT) + | (sc->mii_clk << GMII_ADDRESS_CR_SHIFT) + | GMII_ADDRESS_GB | GMII_ADDRESS_GW; + + WRITE4(sc, GMII_DATA, val); + WRITE4(sc, GMII_ADDRESS, mii); + + for (cnt = 0; cnt < 1000; cnt++) { + if (!(READ4(sc, GMII_ADDRESS) & GMII_ADDRESS_GB)) { + break; + } + DELAY(10); + } + + return (0); +} + +void +dwc1000_miibus_statchg(device_t dev) +{ + struct dwc_softc *sc; + struct mii_data *mii; + uint32_t reg; + + /* + * Called by the MII bus driver when the PHY establishes + * link to set the MAC interface registers. + */ + + sc = device_get_softc(dev); + + DWC_ASSERT_LOCKED(sc); + + mii = sc->mii_softc; + + if (mii->mii_media_status & IFM_ACTIVE) + sc->link_is_up = true; + else + sc->link_is_up = false; + + reg = READ4(sc, MAC_CONFIGURATION); + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_1000_T: + case IFM_1000_SX: + reg &= ~(CONF_FES | CONF_PS); + break; + case IFM_100_TX: + reg |= (CONF_FES | CONF_PS); + break; + case IFM_10_T: + reg &= ~(CONF_FES); + reg |= (CONF_PS); + break; + case IFM_NONE: + sc->link_is_up = false; + return; + default: + sc->link_is_up = false; + device_printf(dev, "Unsupported media %u\n", + IFM_SUBTYPE(mii->mii_media_active)); + return; + } + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) + reg |= (CONF_DM); + else + reg &= ~(CONF_DM); + WRITE4(sc, MAC_CONFIGURATION, reg); + + reg = FLOW_CONTROL_UP; + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) + reg |= FLOW_CONTROL_TX; + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) + reg |= FLOW_CONTROL_RX; + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) + reg |= dwc_pause_time << FLOW_CONTROL_PT_SHIFT; + WRITE4(sc, FLOW_CONTROL, reg); + + IF_DWC_SET_SPEED(dev, IFM_SUBTYPE(mii->mii_media_active)); + +} + +void +dwc1000_core_setup(struct dwc_softc *sc) +{ + uint32_t reg; + + DWC_ASSERT_LOCKED(sc); + + /* Enable core */ + reg = READ4(sc, MAC_CONFIGURATION); + reg |= (CONF_JD | CONF_ACS | CONF_BE); + WRITE4(sc, MAC_CONFIGURATION, reg); +} + +void +dwc1000_enable_mac(struct dwc_softc *sc, bool enable) +{ + uint32_t reg; + + DWC_ASSERT_LOCKED(sc); + reg = READ4(sc, MAC_CONFIGURATION); + if (enable) + reg |= CONF_TE | CONF_RE; + else + reg &= ~(CONF_TE | CONF_RE); + WRITE4(sc, MAC_CONFIGURATION, reg); +} + +void +dwc1000_enable_csum_offload(struct dwc_softc *sc) +{ + uint32_t reg; + + DWC_ASSERT_LOCKED(sc); + reg = READ4(sc, MAC_CONFIGURATION); + if ((if_getcapenable(sc->ifp) & IFCAP_RXCSUM) != 0) + reg |= CONF_IPC; + else + reg &= ~CONF_IPC; + WRITE4(sc, MAC_CONFIGURATION, reg); +} + +static const uint8_t nibbletab[] = { + /* 0x0 0000 -> 0000 */ 0x0, + /* 0x1 0001 -> 1000 */ 0x8, + /* 0x2 0010 -> 0100 */ 0x4, + /* 0x3 0011 -> 1100 */ 0xc, + /* 0x4 0100 -> 0010 */ 0x2, + /* 0x5 0101 -> 1010 */ 0xa, + /* 0x6 0110 -> 0110 */ 0x6, + /* 0x7 0111 -> 1110 */ 0xe, + /* 0x8 1000 -> 0001 */ 0x1, + /* 0x9 1001 -> 1001 */ 0x9, + /* 0xa 1010 -> 0101 */ 0x5, + /* 0xb 1011 -> 1101 */ 0xd, + /* 0xc 1100 -> 0011 */ 0x3, + /* 0xd 1101 -> 1011 */ 0xb, + /* 0xe 1110 -> 0111 */ 0x7, + /* 0xf 1111 -> 1111 */ 0xf, }; + +static uint8_t +bitreverse(uint8_t x) +{ + + return (nibbletab[x & 0xf] << 4) | nibbletab[x >> 4]; +} + +static u_int +dwc_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct dwc_hash_maddr_ctx *ctx = arg; + uint32_t crc, hashbit, hashreg; + uint8_t val; + + crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN); + /* Take lower 8 bits and reverse it */ + val = bitreverse(~crc & 0xff); + if (ctx->sc->mactype != DWC_GMAC_EXT_DESC) + val >>= 2; /* Only need lower 6 bits */ + hashreg = (val >> 5); + hashbit = (val & 31); + ctx->hash[hashreg] |= (1 << hashbit); + + return (1); +} + +void +dwc1000_setup_rxfilter(struct dwc_softc *sc) +{ + struct dwc_hash_maddr_ctx ctx; + if_t ifp; + uint8_t *eaddr; + uint32_t ffval, hi, lo; + int nhash, i; + + DWC_ASSERT_LOCKED(sc); + + ifp = sc->ifp; + nhash = sc->mactype != DWC_GMAC_EXT_DESC ? 2 : 8; + + /* + * Set the multicast (group) filter hash. + */ + if ((if_getflags(ifp) & IFF_ALLMULTI) != 0) { + ffval = (FRAME_FILTER_PM); + for (i = 0; i < nhash; i++) + ctx.hash[i] = ~0; + } else { + ffval = (FRAME_FILTER_HMC); + for (i = 0; i < nhash; i++) + ctx.hash[i] = 0; + ctx.sc = sc; + if_foreach_llmaddr(ifp, dwc_hash_maddr, &ctx); + } + + /* + * Set the individual address filter hash. + */ + if ((if_getflags(ifp) & IFF_PROMISC) != 0) + ffval |= (FRAME_FILTER_PR); + + /* + * Set the primary address. + */ + eaddr = if_getlladdr(ifp); + lo = eaddr[0] | (eaddr[1] << 8) | (eaddr[2] << 16) | + (eaddr[3] << 24); + hi = eaddr[4] | (eaddr[5] << 8); + WRITE4(sc, MAC_ADDRESS_LOW(0), lo); + WRITE4(sc, MAC_ADDRESS_HIGH(0), hi); + WRITE4(sc, MAC_FRAME_FILTER, ffval); + if (sc->mactype != DWC_GMAC_EXT_DESC) { + WRITE4(sc, GMAC_MAC_HTLOW, ctx.hash[0]); + WRITE4(sc, GMAC_MAC_HTHIGH, ctx.hash[1]); + } else { + for (i = 0; i < nhash; i++) + WRITE4(sc, HASH_TABLE_REG(i), ctx.hash[i]); + } +} + +void +dwc1000_get_hwaddr(struct dwc_softc *sc, uint8_t *hwaddr) +{ + uint32_t hi, lo, rnd; + + /* + * Try to recover a MAC address from the running hardware. If there's + * something non-zero there, assume the bootloader did the right thing + * and just use it. + * + * Otherwise, set the address to a convenient locally assigned address, + * 'bsd' + random 24 low-order bits. 'b' is 0x62, which has the locally + * assigned bit set, and the broadcast/multicast bit clear. + */ + lo = READ4(sc, MAC_ADDRESS_LOW(0)); + hi = READ4(sc, MAC_ADDRESS_HIGH(0)) & 0xffff; + if ((lo != 0xffffffff) || (hi != 0xffff)) { + hwaddr[0] = (lo >> 0) & 0xff; + hwaddr[1] = (lo >> 8) & 0xff; + hwaddr[2] = (lo >> 16) & 0xff; + hwaddr[3] = (lo >> 24) & 0xff; + hwaddr[4] = (hi >> 0) & 0xff; + hwaddr[5] = (hi >> 8) & 0xff; + } else { + rnd = arc4random() & 0x00ffffff; + hwaddr[0] = 'b'; + hwaddr[1] = 's'; + hwaddr[2] = 'd'; + hwaddr[3] = rnd >> 16; + hwaddr[4] = rnd >> 8; + hwaddr[5] = rnd >> 0; + } +} + +/* + * Stats + */ + +static void +dwc1000_clear_stats(struct dwc_softc *sc) +{ + uint32_t reg; + + reg = READ4(sc, MMC_CONTROL); + reg |= (MMC_CONTROL_CNTRST); + WRITE4(sc, MMC_CONTROL, reg); +} + +void +dwc1000_harvest_stats(struct dwc_softc *sc) +{ + if_t ifp; + + /* We don't need to harvest too often. */ + if (++sc->stats_harvest_count < STATS_HARVEST_INTERVAL) + return; + + sc->stats_harvest_count = 0; + ifp = sc->ifp; + + if_inc_counter(ifp, IFCOUNTER_IERRORS, + READ4(sc, RXOVERSIZE_G) + READ4(sc, RXUNDERSIZE_G) + + READ4(sc, RXCRCERROR) + READ4(sc, RXALIGNMENTERROR) + + READ4(sc, RXRUNTERROR) + READ4(sc, RXJABBERERROR) + + READ4(sc, RXLENGTHERROR)); + + if_inc_counter(ifp, IFCOUNTER_OERRORS, + READ4(sc, TXOVERSIZE_G) + READ4(sc, TXEXCESSDEF) + + READ4(sc, TXCARRIERERR) + READ4(sc, TXUNDERFLOWERROR)); + + if_inc_counter(ifp, IFCOUNTER_COLLISIONS, + READ4(sc, TXEXESSCOL) + READ4(sc, TXLATECOL)); + + dwc1000_clear_stats(sc); +} diff --git a/sys/dev/dwc/dwc1000_core.h b/sys/dev/dwc/dwc1000_core.h new file mode 100644 index 000000000000..2069215bfffe --- /dev/null +++ b/sys/dev/dwc/dwc1000_core.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) + * ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __DWC1000_CORE_H__ +#define __DWC1000_CORE_H__ + +int dwc1000_miibus_read_reg(device_t dev, int phy, int reg); +int dwc1000_miibus_write_reg(device_t dev, int phy, int reg, int val); +void dwc1000_miibus_statchg(device_t dev); +void dwc1000_core_setup(struct dwc_softc *sc); +void dwc1000_enable_mac(struct dwc_softc *sc, bool enable); +void dwc1000_enable_csum_offload(struct dwc_softc *sc); +void dwc1000_setup_rxfilter(struct dwc_softc *sc); +void dwc1000_get_hwaddr(struct dwc_softc *sc, uint8_t *hwaddr); +void dwc1000_harvest_stats(struct dwc_softc *sc); + +#endif /* __DWC1000_CORE_H__ */ diff --git a/sys/dev/dwc/if_dwc.c b/sys/dev/dwc/if_dwc.c index c491106eacd0..29f78dd94a9a 100644 --- a/sys/dev/dwc/if_dwc.c +++ b/sys/dev/dwc/if_dwc.c @@ -71,6 +71,7 @@ #include <dev/dwc/if_dwcvar.h> #include <dev/dwc/dwc1000_reg.h> +#include <dev/dwc/dwc1000_core.h> #include <dev/dwc/dwc1000_dma.h> #include "if_dwc_if.h" @@ -79,7 +80,6 @@ #define MAC_RESET_TIMEOUT 100 #define WATCHDOG_TIMEOUT_SECS 5 -#define STATS_HARVEST_INTERVAL 2 static struct resource_spec dwc_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, @@ -88,139 +88,9 @@ static struct resource_spec dwc_spec[] = { }; static void dwc_stop_locked(struct dwc_softc *sc); -static void dwc_setup_rxfilter(struct dwc_softc *sc); -static void dwc_setup_core(struct dwc_softc *sc); -static void dwc_enable_mac(struct dwc_softc *sc, bool enable); static void dwc_tick(void *arg); -/* Pause time field in the transmitted control frame */ -static int dwc_pause_time = 0xffff; -TUNABLE_INT("hw.dwc.pause_time", &dwc_pause_time); - -/* - * MIIBUS functions - */ - -static int -dwc_miibus_read_reg(device_t dev, int phy, int reg) -{ - struct dwc_softc *sc; - uint16_t mii; - size_t cnt; - int rv = 0; - - sc = device_get_softc(dev); - - mii = ((phy & GMII_ADDRESS_PA_MASK) << GMII_ADDRESS_PA_SHIFT) - | ((reg & GMII_ADDRESS_GR_MASK) << GMII_ADDRESS_GR_SHIFT) - | (sc->mii_clk << GMII_ADDRESS_CR_SHIFT) - | GMII_ADDRESS_GB; /* Busy flag */ - - WRITE4(sc, GMII_ADDRESS, mii); - - for (cnt = 0; cnt < 1000; cnt++) { - if (!(READ4(sc, GMII_ADDRESS) & GMII_ADDRESS_GB)) { - rv = READ4(sc, GMII_DATA); - break; - } - DELAY(10); - } - - return rv; -} - -static int -dwc_miibus_write_reg(device_t dev, int phy, int reg, int val) -{ - struct dwc_softc *sc; - uint16_t mii; - size_t cnt; - - sc = device_get_softc(dev); - - mii = ((phy & GMII_ADDRESS_PA_MASK) << GMII_ADDRESS_PA_SHIFT) - | ((reg & GMII_ADDRESS_GR_MASK) << GMII_ADDRESS_GR_SHIFT) - | (sc->mii_clk << GMII_ADDRESS_CR_SHIFT) - | GMII_ADDRESS_GB | GMII_ADDRESS_GW; - - WRITE4(sc, GMII_DATA, val); - WRITE4(sc, GMII_ADDRESS, mii); - - for (cnt = 0; cnt < 1000; cnt++) { - if (!(READ4(sc, GMII_ADDRESS) & GMII_ADDRESS_GB)) { - break; - } - DELAY(10); - } - - return (0); -} - -static void -dwc_miibus_statchg(device_t dev) -{ - struct dwc_softc *sc; - struct mii_data *mii; - uint32_t reg; - - /* - * Called by the MII bus driver when the PHY establishes - * link to set the MAC interface registers. - */ - - sc = device_get_softc(dev); - - DWC_ASSERT_LOCKED(sc); - - mii = sc->mii_softc; - - if (mii->mii_media_status & IFM_ACTIVE) - sc->link_is_up = true; - else - sc->link_is_up = false; - - reg = READ4(sc, MAC_CONFIGURATION); - switch (IFM_SUBTYPE(mii->mii_media_active)) { - case IFM_1000_T: - case IFM_1000_SX: - reg &= ~(CONF_FES | CONF_PS); - break; - case IFM_100_TX: - reg |= (CONF_FES | CONF_PS); - break; - case IFM_10_T: - reg &= ~(CONF_FES); - reg |= (CONF_PS); - break; - case IFM_NONE: - sc->link_is_up = false; - return; - default: - sc->link_is_up = false; - device_printf(dev, "Unsupported media %u\n", - IFM_SUBTYPE(mii->mii_media_active)); - return; - } - if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) - reg |= (CONF_DM); - else - reg &= ~(CONF_DM); - WRITE4(sc, MAC_CONFIGURATION, reg); - - reg = FLOW_CONTROL_UP; - if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) - reg |= FLOW_CONTROL_TX; - if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) - reg |= FLOW_CONTROL_RX; - if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) - reg |= dwc_pause_time << FLOW_CONTROL_PT_SHIFT; - WRITE4(sc, FLOW_CONTROL, reg); - - IF_DWC_SET_SPEED(dev, IFM_SUBTYPE(mii->mii_media_active)); - -} - /* * Media functions */ @@ -261,183 +131,6 @@ dwc_media_change(if_t ifp) return (error); } -/* - * Core functions - */ - -static const uint8_t nibbletab[] = { - /* 0x0 0000 -> 0000 */ 0x0, - /* 0x1 0001 -> 1000 */ 0x8, - /* 0x2 0010 -> 0100 */ 0x4, - /* 0x3 0011 -> 1100 */ 0xc, - /* 0x4 0100 -> 0010 */ 0x2, - /* 0x5 0101 -> 1010 */ 0xa, - /* 0x6 0110 -> 0110 */ 0x6, - /* 0x7 0111 -> 1110 */ 0xe, - /* 0x8 1000 -> 0001 */ 0x1, - /* 0x9 1001 -> 1001 */ 0x9, - /* 0xa 1010 -> 0101 */ 0x5, - /* 0xb 1011 -> 1101 */ 0xd, - /* 0xc 1100 -> 0011 */ 0x3, - /* 0xd 1101 -> 1011 */ 0xb, - /* 0xe 1110 -> 0111 */ 0x7, - /* 0xf 1111 -> 1111 */ 0xf, }; - -static uint8_t -bitreverse(uint8_t x) -{ - - return (nibbletab[x & 0xf] << 4) | nibbletab[x >> 4]; -} - -static u_int -dwc_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) -{ - struct dwc_hash_maddr_ctx *ctx = arg; - uint32_t crc, hashbit, hashreg; - uint8_t val; - - crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN); - /* Take lower 8 bits and reverse it */ - val = bitreverse(~crc & 0xff); - if (ctx->sc->mactype != DWC_GMAC_EXT_DESC) - val >>= 2; /* Only need lower 6 bits */ - hashreg = (val >> 5); - hashbit = (val & 31); - ctx->hash[hashreg] |= (1 << hashbit); - - return (1); -} - -static void -dwc_setup_rxfilter(struct dwc_softc *sc) -{ - struct dwc_hash_maddr_ctx ctx; - if_t ifp; - uint8_t *eaddr; - uint32_t ffval, hi, lo; - int nhash, i; - - DWC_ASSERT_LOCKED(sc); - - ifp = sc->ifp; - nhash = sc->mactype != DWC_GMAC_EXT_DESC ? 2 : 8; - - /* - * Set the multicast (group) filter hash. - */ - if ((if_getflags(ifp) & IFF_ALLMULTI) != 0) { - ffval = (FRAME_FILTER_PM); - for (i = 0; i < nhash; i++) - ctx.hash[i] = ~0; - } else { - ffval = (FRAME_FILTER_HMC); - for (i = 0; i < nhash; i++) - ctx.hash[i] = 0; - ctx.sc = sc; - if_foreach_llmaddr(ifp, dwc_hash_maddr, &ctx); - } - - /* - * Set the individual address filter hash. - */ - if ((if_getflags(ifp) & IFF_PROMISC) != 0) - ffval |= (FRAME_FILTER_PR); - - /* - * Set the primary address. - */ - eaddr = if_getlladdr(ifp); - lo = eaddr[0] | (eaddr[1] << 8) | (eaddr[2] << 16) | - (eaddr[3] << 24); - hi = eaddr[4] | (eaddr[5] << 8); - WRITE4(sc, MAC_ADDRESS_LOW(0), lo); - WRITE4(sc, MAC_ADDRESS_HIGH(0), hi); - WRITE4(sc, MAC_FRAME_FILTER, ffval); - if (sc->mactype != DWC_GMAC_EXT_DESC) { - WRITE4(sc, GMAC_MAC_HTLOW, ctx.hash[0]); - WRITE4(sc, GMAC_MAC_HTHIGH, ctx.hash[1]); - } else { - for (i = 0; i < nhash; i++) - WRITE4(sc, HASH_TABLE_REG(i), ctx.hash[i]); - } -} - -static void -dwc_setup_core(struct dwc_softc *sc) -{ - uint32_t reg; - - DWC_ASSERT_LOCKED(sc); - - /* Enable core */ - reg = READ4(sc, MAC_CONFIGURATION); - reg |= (CONF_JD | CONF_ACS | CONF_BE); - WRITE4(sc, MAC_CONFIGURATION, reg); -} - -static void -dwc_enable_mac(struct dwc_softc *sc, bool enable) -{ - uint32_t reg; - - DWC_ASSERT_LOCKED(sc); - reg = READ4(sc, MAC_CONFIGURATION); - if (enable) - reg |= CONF_TE | CONF_RE; - else - reg &= ~(CONF_TE | CONF_RE); - WRITE4(sc, MAC_CONFIGURATION, reg); -} - -static void -dwc_enable_csum_offload(struct dwc_softc *sc) -{ - uint32_t reg; - - DWC_ASSERT_LOCKED(sc); - reg = READ4(sc, MAC_CONFIGURATION); - if ((if_getcapenable(sc->ifp) & IFCAP_RXCSUM) != 0) - reg |= CONF_IPC; - else - reg &= ~CONF_IPC; - WRITE4(sc, MAC_CONFIGURATION, reg); -} - -static void -dwc_get_hwaddr(struct dwc_softc *sc, uint8_t *hwaddr) -{ - uint32_t hi, lo, rnd; - - /* - * Try to recover a MAC address from the running hardware. If there's - * something non-zero there, assume the bootloader did the right thing - * and just use it. - * - * Otherwise, set the address to a convenient locally assigned address, - * 'bsd' + random 24 low-order bits. 'b' is 0x62, which has the locally - * assigned bit set, and the broadcast/multicast bit clear. - */ - lo = READ4(sc, MAC_ADDRESS_LOW(0)); - hi = READ4(sc, MAC_ADDRESS_HIGH(0)) & 0xffff; - if ((lo != 0xffffffff) || (hi != 0xffff)) { - hwaddr[0] = (lo >> 0) & 0xff; - hwaddr[1] = (lo >> 8) & 0xff; - hwaddr[2] = (lo >> 16) & 0xff; - hwaddr[3] = (lo >> 24) & 0xff; - hwaddr[4] = (hi >> 0) & 0xff; - hwaddr[5] = (hi >> 8) & 0xff; - } else { - rnd = arc4random() & 0x00ffffff; - hwaddr[0] = 'b'; - hwaddr[1] = 's'; - hwaddr[2] = 'd'; - hwaddr[3] = rnd >> 16; - hwaddr[4] = rnd >> 8; - hwaddr[5] = rnd >> 0; - } -} - /* * if_ functions */ @@ -514,15 +207,15 @@ dwc_init_locked(struct dwc_softc *sc) return; /* - * Call mii_mediachg() which will call back into dwc_miibus_statchg() + * Call mii_mediachg() which will call back into dwc1000_miibus_statchg() * to set up the remaining config registers based on current media. */ mii_mediachg(sc->mii_softc); - dwc_setup_rxfilter(sc); - dwc_setup_core(sc); - dwc_enable_mac(sc, true); - dwc_enable_csum_offload(sc); + dwc1000_setup_rxfilter(sc); + dwc1000_core_setup(sc); + dwc1000_enable_mac(sc, true); + dwc1000_enable_csum_offload(sc); dma1000_start(sc); if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); @@ -555,7 +248,7 @@ dwc_stop_locked(struct dwc_softc *sc) callout_stop(&sc->dwc_callout); dma1000_stop(sc); - dwc_enable_mac(sc, false); + dwc1000_enable_mac(sc, false); } static int @@ -577,7 +270,7 @@ dwc_ioctl(if_t ifp, u_long cmd, caddr_t data) if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { flags = if_getflags(ifp) ^ sc->if_flags; if ((flags & (IFF_PROMISC|IFF_ALLMULTI)) != 0) - dwc_setup_rxfilter(sc); + dwc1000_setup_rxfilter(sc); } else { if (!sc->is_detaching) dwc_init_locked(sc); @@ -593,7 +286,7 @@ dwc_ioctl(if_t ifp, u_long cmd, caddr_t data) case SIOCDELMULTI: if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { DWC_LOCK(sc); - dwc_setup_rxfilter(sc); + dwc1000_setup_rxfilter(sc); DWC_UNLOCK(sc); } break; @@ -619,7 +312,7 @@ dwc_ioctl(if_t ifp, u_long cmd, caddr_t data) if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { DWC_LOCK(sc); - dwc_enable_csum_offload(sc); + dwc1000_enable_csum_offload(sc); DWC_UNLOCK(sc); } break; @@ -676,47 +369,6 @@ dwc_intr(void *arg) DWC_UNLOCK(sc); } -/* - * Stats - */ - -static void dwc_clear_stats(struct dwc_softc *sc) -{ - uint32_t reg; - - reg = READ4(sc, MMC_CONTROL); - reg |= (MMC_CONTROL_CNTRST); - WRITE4(sc, MMC_CONTROL, reg); -} - -static void -dwc_harvest_stats(struct dwc_softc *sc) -{ - if_t ifp; - - /* We don't need to harvest too often. */ - if (++sc->stats_harvest_count < STATS_HARVEST_INTERVAL) - return; - - sc->stats_harvest_count = 0; - ifp = sc->ifp; - - if_inc_counter(ifp, IFCOUNTER_IERRORS, - READ4(sc, RXOVERSIZE_G) + READ4(sc, RXUNDERSIZE_G) + - READ4(sc, RXCRCERROR) + READ4(sc, RXALIGNMENTERROR) + - READ4(sc, RXRUNTERROR) + READ4(sc, RXJABBERERROR) + - READ4(sc, RXLENGTHERROR)); - - if_inc_counter(ifp, IFCOUNTER_OERRORS, - READ4(sc, TXOVERSIZE_G) + READ4(sc, TXEXCESSDEF) + - READ4(sc, TXCARRIERERR) + READ4(sc, TXUNDERFLOWERROR)); - - if_inc_counter(ifp, IFCOUNTER_COLLISIONS, - READ4(sc, TXEXESSCOL) + READ4(sc, TXLATECOL)); - - dwc_clear_stats(sc); -} - static void dwc_tick(void *arg) { @@ -745,7 +397,7 @@ dwc_tick(void *arg) } /* Gather stats from hardware counters. */ - dwc_harvest_stats(sc); + dwc1000_harvest_stats(sc); /* Check the media status. */ link_was_up = sc->link_is_up; @@ -973,7 +625,7 @@ dwc_attach(device_t dev) } /* Read MAC before reset */ - dwc_get_hwaddr(sc, macaddr); + dwc1000_get_hwaddr(sc, macaddr); /* Reset the PHY if needed */ *** 14 LINES SKIPPED ***