git: 62519d5a4f71 - main - dwc: Split core functions

From: Emmanuel Vadot <manu_at_FreeBSD.org>
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 ***