Module Name: src
Committed By: jmcneill
Date: Sat Feb 22 00:28:36 UTC 2020
Modified Files:
src/sys/arch/arm/broadcom: bcm283x_platform.c
src/sys/arch/evbarm/conf: GENERIC64
src/sys/conf: files
src/sys/dev/fdt: files.fdt
Added Files:
src/sys/dev/fdt: genet_fdt.c
src/sys/dev/ic: bcmgenet.c bcmgenetreg.h bcmgenetvar.h
Log Message:
Add support for Broadcom GENET v5 ethernet controller as found on the
Raspberry Pi 4 (BCM2711).
To generate a diff of this commit:
cvs rdiff -u -r1.36 -r1.37 src/sys/arch/arm/broadcom/bcm283x_platform.c
cvs rdiff -u -r1.137 -r1.138 src/sys/arch/evbarm/conf/GENERIC64
cvs rdiff -u -r1.1255 -r1.1256 src/sys/conf/files
cvs rdiff -u -r1.50 -r1.51 src/sys/dev/fdt/files.fdt
cvs rdiff -u -r0 -r1.1 src/sys/dev/fdt/genet_fdt.c
cvs rdiff -u -r0 -r1.1 src/sys/dev/ic/bcmgenet.c src/sys/dev/ic/bcmgenetreg.h \
src/sys/dev/ic/bcmgenetvar.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/arm/broadcom/bcm283x_platform.c
diff -u src/sys/arch/arm/broadcom/bcm283x_platform.c:1.36 src/sys/arch/arm/broadcom/bcm283x_platform.c:1.37
--- src/sys/arch/arm/broadcom/bcm283x_platform.c:1.36 Sat Feb 22 00:17:54 2020
+++ src/sys/arch/arm/broadcom/bcm283x_platform.c Sat Feb 22 00:28:35 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: bcm283x_platform.c,v 1.36 2020/02/22 00:17:54 jmcneill Exp $ */
+/* $NetBSD: bcm283x_platform.c,v 1.37 2020/02/22 00:28:35 jmcneill Exp $ */
/*-
* Copyright (c) 2017 Jared D. McNeill <[email protected]>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bcm283x_platform.c,v 1.36 2020/02/22 00:17:54 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bcm283x_platform.c,v 1.37 2020/02/22 00:28:35 jmcneill Exp $");
#include "opt_arm_debug.h"
#include "opt_bcm283x.h"
@@ -1415,7 +1415,9 @@ bcm283x_platform_device_register(device_
booted_device = dev;
}
#endif
- if ((device_is_a(dev, "usmsc") || device_is_a(dev, "mue")) &&
+ if ((device_is_a(dev, "usmsc") ||
+ device_is_a(dev, "mue") ||
+ device_is_a(dev, "genet")) &&
vcprop_tag_success_p(&vb.vbt_macaddr.tag)) {
const uint8_t enaddr[ETHER_ADDR_LEN] = {
(vb.vbt_macaddr.addr >> 0) & 0xff,
Index: src/sys/arch/evbarm/conf/GENERIC64
diff -u src/sys/arch/evbarm/conf/GENERIC64:1.137 src/sys/arch/evbarm/conf/GENERIC64:1.138
--- src/sys/arch/evbarm/conf/GENERIC64:1.137 Thu Feb 20 01:36:37 2020
+++ src/sys/arch/evbarm/conf/GENERIC64 Sat Feb 22 00:28:35 2020
@@ -1,5 +1,5 @@
#
-# $NetBSD: GENERIC64,v 1.137 2020/02/20 01:36:37 jmcneill Exp $
+# $NetBSD: GENERIC64,v 1.138 2020/02/22 00:28:35 jmcneill Exp $
#
# GENERIC ARM (aarch64) kernel
#
@@ -327,6 +327,7 @@ emac* at fdt? # Allwinner Gigabit Et
enet* at fdt? # IMX FEC
aq* at pci? dev ? function ? # Aquantia AQC 10 gigabit
ena* at pci? dev ? function ? # Amazon.com Elastic Network Adapter
+genet* at fdt? # Broadcom GENET v5
mcx* at pci? dev ? function ? # Mellanox 5th generation Ethernet
mskc* at pci? dev ? function ? # Marvell Yukon 2 Gigabit Ethernet
msk* at mskc?
Index: src/sys/conf/files
diff -u src/sys/conf/files:1.1255 src/sys/conf/files:1.1256
--- src/sys/conf/files:1.1255 Sat Feb 8 07:07:07 2020
+++ src/sys/conf/files Sat Feb 22 00:28:35 2020
@@ -1,4 +1,4 @@
-# $NetBSD: files,v 1.1255 2020/02/08 07:07:07 maxv Exp $
+# $NetBSD: files,v 1.1256 2020/02/22 00:28:35 jmcneill Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
version 20171118
@@ -1470,6 +1470,10 @@ file dev/ic/dw_hdmi_phy.c dwhdmi
device anxdp: edid, videomode, drmkms, drmkms_i2c
file dev/ic/anx_dp.c anxdp
+# Broadcom GENET v5 ethernet
+device genet: arp, ether, ifnet, mii
+file dev/ic/bcmgenet.c genet
+
#
# File systems
#
Index: src/sys/dev/fdt/files.fdt
diff -u src/sys/dev/fdt/files.fdt:1.50 src/sys/dev/fdt/files.fdt:1.51
--- src/sys/dev/fdt/files.fdt:1.50 Thu Jan 2 00:57:10 2020
+++ src/sys/dev/fdt/files.fdt Sat Feb 22 00:28:35 2020
@@ -1,4 +1,4 @@
-# $NetBSD: files.fdt,v 1.50 2020/01/02 00:57:10 jmcneill Exp $
+# $NetBSD: files.fdt,v 1.51 2020/02/22 00:28:35 jmcneill Exp $
include "external/bsd/libfdt/conf/files.libfdt"
@@ -171,3 +171,6 @@ device simpleamp
attach simpleamp at fdt
file dev/fdt/simple_amplifier.c simpleamp
+# Broadcom GENET v5
+attach genet at fdt with genet_fdt
+file dev/fdt/genet_fdt.c genet_fdt
Added files:
Index: src/sys/dev/fdt/genet_fdt.c
diff -u /dev/null src/sys/dev/fdt/genet_fdt.c:1.1
--- /dev/null Sat Feb 22 00:28:36 2020
+++ src/sys/dev/fdt/genet_fdt.c Sat Feb 22 00:28:35 2020
@@ -0,0 +1,134 @@
+/* $NetBSD: genet_fdt.c,v 1.1 2020/02/22 00:28:35 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2020 Jared McNeill <[email protected]>
+ * All rights reserved.
+ *
+ * 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 ``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 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.
+ */
+
+#include "opt_net_mpsafe.h"
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: genet_fdt.c,v 1.1 2020/02/22 00:28:35 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_ether.h>
+#include <net/if_media.h>
+
+#include <dev/mii/miivar.h>
+
+#include <dev/ic/bcmgenetvar.h>
+
+#include <dev/fdt/fdtvar.h>
+
+#ifdef NET_MPSAFE
+#define FDT_INTR_FLAGS FDT_INTR_MPSAFE
+#else
+#define FDT_INTR_FLAGS 0
+#endif
+
+static int genet_fdt_match(device_t, cfdata_t, void *);
+static void genet_fdt_attach(device_t, device_t, void *);
+
+CFATTACH_DECL_NEW(genet_fdt, sizeof(struct genet_softc),
+ genet_fdt_match, genet_fdt_attach, NULL, NULL);
+
+static int
+genet_fdt_match(device_t parent, cfdata_t cf, void *aux)
+{
+ const char * const compatible[] = {
+ "brcm,bcm2711-genet-v5",
+ NULL
+ };
+ struct fdt_attach_args * const faa = aux;
+
+ return of_match_compatible(faa->faa_phandle, compatible);
+}
+
+static void
+genet_fdt_attach(device_t parent, device_t self, void *aux)
+{
+ struct genet_softc * const sc = device_private(self);
+ struct fdt_attach_args * const faa = aux;
+ const int phandle = faa->faa_phandle;
+ char intrstr[128];
+ bus_addr_t addr;
+ bus_size_t size;
+ void *ih;
+
+ if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
+ aprint_error(": couldn't get registers\n");
+ return;
+ }
+
+ sc->sc_dev = self;
+ sc->sc_bst = faa->faa_bst;
+ if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
+ aprint_error(": couldn't map registers\n");
+ return;
+ }
+ sc->sc_dmat = faa->faa_dmat;
+ sc->sc_phy_id = MII_PHY_ANY;
+
+ const char *phy_mode = fdtbus_get_string(phandle, "phy-mode");
+ if (phy_mode == NULL) {
+ aprint_error(": missing 'phy-mode' property\n");
+ return;
+ }
+
+ if (strcmp(phy_mode, "rgmii-rxid") == 0)
+ sc->sc_phy_mode = GENET_PHY_MODE_RGMII_RXID;
+ else if (strcmp(phy_mode, "rgmii-txid") == 0)
+ sc->sc_phy_mode = GENET_PHY_MODE_RGMII_TXID;
+ else if (strcmp(phy_mode, "rgmii") == 0)
+ sc->sc_phy_mode = GENET_PHY_MODE_RGMII;
+ else {
+ aprint_error(": unsupported phy-mode '%s'\n", phy_mode);
+ return;
+ }
+
+ if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
+ aprint_error(": failed to decode interrupt\n");
+ return;
+ }
+
+ if (genet_attach(sc) != 0)
+ return;
+
+ ih = fdtbus_intr_establish(phandle, 0, IPL_NET, FDT_INTR_FLAGS,
+ genet_intr, sc);
+ if (ih == NULL) {
+ aprint_error_dev(self, "couldn't establish interrupt on %s\n",
+ intrstr);
+ return;
+ }
+ aprint_normal_dev(self, "interrupting on %s\n", intrstr);
+}
Index: src/sys/dev/ic/bcmgenet.c
diff -u /dev/null src/sys/dev/ic/bcmgenet.c:1.1
--- /dev/null Sat Feb 22 00:28:36 2020
+++ src/sys/dev/ic/bcmgenet.c Sat Feb 22 00:28:35 2020
@@ -0,0 +1,955 @@
+/* $NetBSD: bcmgenet.c,v 1.1 2020/02/22 00:28:35 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2020 Jared McNeill <[email protected]>
+ * All rights reserved.
+ *
+ * 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 ``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 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.
+ */
+
+/*
+ * Broadcom GENETv5
+ */
+
+#include "opt_net_mpsafe.h"
+#include "opt_ddb.h"
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: bcmgenet.c,v 1.1 2020/02/22 00:28:35 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mutex.h>
+#include <sys/callout.h>
+#include <sys/cprng.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_ether.h>
+#include <net/if_media.h>
+#include <net/bpf.h>
+
+#include <dev/mii/miivar.h>
+
+#include <dev/ic/bcmgenetreg.h>
+#include <dev/ic/bcmgenetvar.h>
+
+CTASSERT(MCLBYTES == 2048);
+
+#ifdef GENET_DEBUG
+#define DPRINTF(...) printf(##__VA_ARGS__)
+#else
+#define DPRINTF(...) ((void)0)
+#endif
+
+#ifdef NET_MPSAFE
+#define GENET_MPSAFE 1
+#define CALLOUT_FLAGS CALLOUT_MPSAFE
+#else
+#define CALLOUT_FLAGS 0
+#endif
+
+#define TX_SKIP(n, o) (((n) + (o)) & (GENET_DMA_DESC_COUNT - 1))
+#define TX_NEXT(n) TX_SKIP(n, 1)
+#define RX_NEXT(n) (((n) + 1) & (GENET_DMA_DESC_COUNT - 1))
+
+#define TX_MAX_SEGS 128
+#define TX_DESC_COUNT GENET_DMA_DESC_COUNT
+#define RX_DESC_COUNT GENET_DMA_DESC_COUNT
+#define MII_BUSY_RETRY 1000
+
+#define GENET_LOCK(sc) mutex_enter(&(sc)->sc_lock)
+#define GENET_UNLOCK(sc) mutex_exit(&(sc)->sc_lock)
+#define GENET_ASSERT_LOCKED(sc) KASSERT(mutex_owned(&(sc)->sc_lock))
+
+#define RD4(sc, reg) \
+ bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define WR4(sc, reg, val) \
+ bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+static int
+genet_mii_readreg(device_t dev, int phy, int reg, uint16_t *val)
+{
+ struct genet_softc *sc = device_private(dev);
+ int retry;
+
+ WR4(sc, GENET_MDIO_CMD,
+ GENET_MDIO_READ | GENET_MDIO_START_BUSY |
+ __SHIFTIN(phy, GENET_MDIO_PMD) |
+ __SHIFTIN(reg, GENET_MDIO_REG));
+ for (retry = MII_BUSY_RETRY; retry > 0; retry--) {
+ if ((RD4(sc, GENET_MDIO_CMD) & GENET_MDIO_START_BUSY) == 0) {
+ *val = RD4(sc, GENET_MDIO_CMD) & 0xffff;
+ break;
+ }
+ delay(10);
+ }
+
+
+ if (retry == 0) {
+ device_printf(dev, "phy read timeout, phy=%d reg=%d\n",
+ phy, reg);
+ return ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int
+genet_mii_writereg(device_t dev, int phy, int reg, uint16_t val)
+{
+ struct genet_softc *sc = device_private(dev);
+ int retry;
+
+ WR4(sc, GENET_MDIO_CMD,
+ val | GENET_MDIO_WRITE | GENET_MDIO_START_BUSY |
+ __SHIFTIN(phy, GENET_MDIO_PMD) |
+ __SHIFTIN(reg, GENET_MDIO_REG));
+ for (retry = MII_BUSY_RETRY; retry > 0; retry--) {
+ if ((RD4(sc, GENET_MDIO_CMD) & GENET_MDIO_START_BUSY) == 0)
+ break;
+ delay(10);
+ }
+
+ if (retry == 0) {
+ device_printf(dev, "phy write timeout, phy=%d reg=%d\n",
+ phy, reg);
+ return ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static void
+genet_update_link(struct genet_softc *sc)
+{
+ struct mii_data *mii = &sc->sc_mii;
+ uint32_t val;
+ u_int speed;
+
+ if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T ||
+ IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX)
+ speed = GENET_UMAC_CMD_SPEED_1000;
+ else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX)
+ speed = GENET_UMAC_CMD_SPEED_100;
+ else
+ speed = GENET_UMAC_CMD_SPEED_10;
+
+ val = RD4(sc, GENET_EXT_RGMII_OOB_CTRL);
+ val &= ~GENET_EXT_RGMII_OOB_OOB_DISABLE;
+ val |= GENET_EXT_RGMII_OOB_RGMII_LINK;
+ val |= GENET_EXT_RGMII_OOB_RGMII_MODE_EN;
+ if (sc->sc_phy_mode == GENET_PHY_MODE_RGMII)
+ val |= GENET_EXT_RGMII_OOB_ID_MODE_DISABLE;
+ WR4(sc, GENET_EXT_RGMII_OOB_CTRL, val);
+
+ val = RD4(sc, GENET_UMAC_CMD);
+ val &= ~GENET_UMAC_CMD_SPEED;
+ val |= __SHIFTIN(speed, GENET_UMAC_CMD_SPEED);
+ WR4(sc, GENET_UMAC_CMD, val);
+}
+
+static void
+genet_mii_statchg(struct ifnet *ifp)
+{
+ struct genet_softc * const sc = ifp->if_softc;
+
+ genet_update_link(sc);
+}
+
+static void
+genet_setup_txdesc(struct genet_softc *sc, int index, int flags,
+ bus_addr_t paddr, u_int len)
+{
+ uint32_t status;
+
+ status = flags | __SHIFTIN(len, GENET_TX_DESC_STATUS_BUFLEN);
+ ++sc->sc_tx.queued;
+
+ WR4(sc, GENET_TX_DESC_ADDRESS_LO(index), (uint32_t)paddr);
+ WR4(sc, GENET_TX_DESC_ADDRESS_HI(index), (uint32_t)(paddr >> 32));
+ WR4(sc, GENET_TX_DESC_STATUS(index), status);
+}
+
+static int
+genet_setup_txbuf(struct genet_softc *sc, int index, struct mbuf *m)
+{
+ bus_dma_segment_t *segs;
+ int error, nsegs, cur, i;
+ uint32_t flags;
+
+ error = bus_dmamap_load_mbuf(sc->sc_tx.buf_tag,
+ sc->sc_tx.buf_map[index].map, m, BUS_DMA_WRITE | BUS_DMA_NOWAIT);
+ if (error == EFBIG) {
+ device_printf(sc->sc_dev,
+ "TX packet needs too many DMA segments, dropping...\n");
+ m_freem(m);
+ return 0;
+ }
+ if (error != 0)
+ return 0;
+
+ segs = sc->sc_tx.buf_map[index].map->dm_segs;
+ nsegs = sc->sc_tx.buf_map[index].map->dm_nsegs;
+
+ if (sc->sc_tx.queued >= GENET_DMA_DESC_COUNT - nsegs) {
+ bus_dmamap_unload(sc->sc_tx.buf_tag,
+ sc->sc_tx.buf_map[index].map);
+ return -1;
+ }
+
+ flags = GENET_TX_DESC_STATUS_SOP |
+ GENET_TX_DESC_STATUS_CRC |
+ GENET_TX_DESC_STATUS_QTAG;
+
+ for (cur = index, i = 0; i < nsegs; i++) {
+ sc->sc_tx.buf_map[cur].mbuf = (i == 0 ? m : NULL);
+ if (i == nsegs - 1)
+ flags |= GENET_TX_DESC_STATUS_EOP;
+
+ genet_setup_txdesc(sc, cur, flags, segs[i].ds_addr,
+ segs[i].ds_len);
+
+ if (i == 0) {
+ flags &= ~GENET_TX_DESC_STATUS_SOP;
+ flags &= ~GENET_TX_DESC_STATUS_CRC;
+ }
+ cur = TX_NEXT(cur);
+ }
+
+ bus_dmamap_sync(sc->sc_tx.buf_tag, sc->sc_tx.buf_map[index].map,
+ 0, sc->sc_tx.buf_map[index].map->dm_mapsize, BUS_DMASYNC_PREWRITE);
+
+ return nsegs;
+}
+
+static void
+genet_setup_rxdesc(struct genet_softc *sc, int index,
+ bus_addr_t paddr, bus_size_t len)
+{
+ WR4(sc, GENET_RX_DESC_ADDRESS_LO(index), (uint32_t)paddr);
+ WR4(sc, GENET_RX_DESC_ADDRESS_HI(index), (uint32_t)(paddr >> 32));
+}
+
+static int
+genet_setup_rxbuf(struct genet_softc *sc, int index, struct mbuf *m)
+{
+ int error;
+
+ error = bus_dmamap_load_mbuf(sc->sc_rx.buf_tag,
+ sc->sc_rx.buf_map[index].map, m, BUS_DMA_READ | BUS_DMA_NOWAIT);
+ if (error != 0)
+ return error;
+
+ bus_dmamap_sync(sc->sc_rx.buf_tag, sc->sc_rx.buf_map[index].map,
+ 0, sc->sc_rx.buf_map[index].map->dm_mapsize,
+ BUS_DMASYNC_PREREAD);
+
+ sc->sc_rx.buf_map[index].mbuf = m;
+ genet_setup_rxdesc(sc, index,
+ sc->sc_rx.buf_map[index].map->dm_segs[0].ds_addr,
+ sc->sc_rx.buf_map[index].map->dm_segs[0].ds_len);
+
+ return 0;
+}
+
+static struct mbuf *
+genet_alloc_mbufcl(struct genet_softc *sc)
+{
+ struct mbuf *m;
+
+ m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
+ if (m != NULL)
+ m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;
+
+ return m;
+}
+
+static void
+genet_enable_intr(struct genet_softc *sc)
+{
+ WR4(sc, GENET_INTRL2_CPU_CLEAR_MASK,
+ GENET_IRQ_TXDMA_DONE | GENET_IRQ_RXDMA_DONE);
+}
+
+static void
+genet_disable_intr(struct genet_softc *sc)
+{
+ /* Disable interrupts */
+ WR4(sc, GENET_INTRL2_CPU_SET_MASK, 0xffffffff);
+ WR4(sc, GENET_INTRL2_CPU_CLEAR, 0xffffffff);
+}
+
+static void
+genet_tick(void *softc)
+{
+ struct genet_softc *sc = softc;
+ struct mii_data *mii = &sc->sc_mii;
+#ifndef GENET_MPSAFE
+ int s = splnet();
+#endif
+
+ GENET_LOCK(sc);
+ mii_tick(mii);
+ callout_schedule(&sc->sc_stat_ch, hz);
+ GENET_UNLOCK(sc);
+
+#ifndef GENET_MPSAFE
+ splx(s);
+#endif
+}
+
+static void
+genet_setup_rxfilter(struct genet_softc *sc)
+{
+ uint32_t val;
+
+ GENET_ASSERT_LOCKED(sc);
+
+ /* Enable promiscuous mode */
+ val = RD4(sc, GENET_UMAC_CMD);
+ val |= GENET_UMAC_CMD_PROMISC;
+ WR4(sc, GENET_UMAC_CMD, val);
+
+ /* Disable filters */
+ WR4(sc, GENET_UMAC_MDF_CTRL, 0);
+}
+
+static int
+genet_reset(struct genet_softc *sc)
+{
+ uint32_t val;
+
+ val = RD4(sc, GENET_SYS_RBUF_FLUSH_CTRL);
+ val |= GENET_SYS_RBUF_FLUSH_RESET;
+ WR4(sc, GENET_SYS_RBUF_FLUSH_CTRL, val);
+ delay(10);
+
+ val &= ~GENET_SYS_RBUF_FLUSH_RESET;
+ WR4(sc, GENET_SYS_RBUF_FLUSH_CTRL, val);
+ delay(10);
+
+ WR4(sc, GENET_SYS_RBUF_FLUSH_CTRL, 0);
+ delay(10);
+
+ WR4(sc, GENET_UMAC_CMD, 0);
+ WR4(sc, GENET_UMAC_CMD,
+ GENET_UMAC_CMD_LCL_LOOP_EN | GENET_UMAC_CMD_SW_RESET);
+ delay(10);
+ WR4(sc, GENET_UMAC_CMD, 0);
+
+ WR4(sc, GENET_UMAC_MIB_CTRL, GENET_UMAC_MIB_RESET_RUNT |
+ GENET_UMAC_MIB_RESET_RX | GENET_UMAC_MIB_RESET_TX);
+ WR4(sc, GENET_UMAC_MIB_CTRL, 0);
+
+ WR4(sc, GENET_UMAC_MAX_FRAME_LEN, 1536);
+
+ val = RD4(sc, GENET_RBUF_CTRL);
+ val |= GENET_RBUF_ALIGN_2B;
+ WR4(sc, GENET_RBUF_CTRL, val);
+
+ WR4(sc, GENET_RBUF_TBUF_SIZE_CTRL, 1);
+
+ return 0;
+}
+
+static void
+genet_init_rings(struct genet_softc *sc, int qid)
+{
+ uint32_t val;
+
+ /* TX ring */
+
+ sc->sc_tx.queued = 0;
+ sc->sc_tx.cidx = sc->sc_tx.pidx = 0;
+
+ WR4(sc, GENET_TX_SCB_BURST_SIZE, 0x08);
+
+ WR4(sc, GENET_TX_DMA_READ_PTR_LO(qid), 0);
+ WR4(sc, GENET_TX_DMA_READ_PTR_HI(qid), 0);
+ WR4(sc, GENET_TX_DMA_CONS_INDEX(qid), 0);
+ WR4(sc, GENET_TX_DMA_PROD_INDEX(qid), 0);
+ WR4(sc, GENET_TX_DMA_RING_BUF_SIZE(qid),
+ __SHIFTIN(TX_DESC_COUNT, GENET_TX_DMA_RING_BUF_SIZE_DESC_COUNT) |
+ __SHIFTIN(MCLBYTES, GENET_TX_DMA_RING_BUF_SIZE_BUF_LENGTH));
+ WR4(sc, GENET_TX_DMA_START_ADDR_LO(qid), 0);
+ WR4(sc, GENET_TX_DMA_START_ADDR_HI(qid), 0);
+ WR4(sc, GENET_TX_DMA_END_ADDR_LO(qid),
+ TX_DESC_COUNT * GENET_DMA_DESC_SIZE / 4 - 1);
+ WR4(sc, GENET_TX_DMA_END_ADDR_HI(qid), 0);
+ WR4(sc, GENET_TX_DMA_MBUF_DONE_THRES(qid), 1);
+ WR4(sc, GENET_TX_DMA_FLOW_PERIOD(qid), 0);
+ WR4(sc, GENET_TX_DMA_WRITE_PTR_LO(qid), 0);
+ WR4(sc, GENET_TX_DMA_WRITE_PTR_HI(qid), 0);
+
+ WR4(sc, GENET_TX_DMA_RING_CFG, __BIT(qid)); /* enable */
+
+ /* Enable transmit DMA */
+ val = RD4(sc, GENET_TX_DMA_CTRL);
+ val |= GENET_TX_DMA_CTRL_EN;
+ val |= GENET_TX_DMA_CTRL_RBUF_EN(GENET_DMA_DEFAULT_QUEUE);
+ WR4(sc, GENET_TX_DMA_CTRL, val);
+
+ /* RX ring */
+
+ sc->sc_rx.cidx = sc->sc_rx.pidx = 0;
+
+ WR4(sc, GENET_RX_SCB_BURST_SIZE, 0x08);
+
+ WR4(sc, GENET_RX_DMA_WRITE_PTR_LO(qid), 0);
+ WR4(sc, GENET_RX_DMA_WRITE_PTR_HI(qid), 0);
+ WR4(sc, GENET_RX_DMA_PROD_INDEX(qid), 0);
+ WR4(sc, GENET_RX_DMA_CONS_INDEX(qid), 0);
+ WR4(sc, GENET_RX_DMA_RING_BUF_SIZE(qid),
+ __SHIFTIN(RX_DESC_COUNT, GENET_RX_DMA_RING_BUF_SIZE_DESC_COUNT) |
+ __SHIFTIN(MCLBYTES, GENET_RX_DMA_RING_BUF_SIZE_BUF_LENGTH));
+ WR4(sc, GENET_RX_DMA_START_ADDR_LO(qid), 0);
+ WR4(sc, GENET_RX_DMA_START_ADDR_HI(qid), 0);
+ WR4(sc, GENET_RX_DMA_END_ADDR_LO(qid),
+ RX_DESC_COUNT * GENET_DMA_DESC_SIZE / 4 - 1);
+ WR4(sc, GENET_RX_DMA_END_ADDR_HI(qid), 0);
+ WR4(sc, GENET_RX_DMA_XON_XOFF_THRES(qid),
+ __SHIFTIN(5, GENET_RX_DMA_XON_XOFF_THRES_LO) |
+ __SHIFTIN(RX_DESC_COUNT >> 4, GENET_RX_DMA_XON_XOFF_THRES_HI));
+ WR4(sc, GENET_RX_DMA_READ_PTR_LO(qid), 0);
+ WR4(sc, GENET_RX_DMA_READ_PTR_HI(qid), 0);
+
+ WR4(sc, GENET_RX_DMA_RING_CFG, __BIT(qid)); /* enable */
+
+ /* Enable receive DMA */
+ val = RD4(sc, GENET_RX_DMA_CTRL);
+ val |= GENET_RX_DMA_CTRL_EN;
+ val |= GENET_RX_DMA_CTRL_RBUF_EN(GENET_DMA_DEFAULT_QUEUE);
+ WR4(sc, GENET_RX_DMA_CTRL, val);
+}
+
+static int
+genet_init_locked(struct genet_softc *sc)
+{
+ struct ifnet *ifp = &sc->sc_ec.ec_if;
+ struct mii_data *mii = &sc->sc_mii;
+ uint32_t val;
+ const uint8_t *enaddr = CLLADDR(ifp->if_sadl);
+
+ GENET_ASSERT_LOCKED(sc);
+
+ if ((ifp->if_flags & IFF_RUNNING) != 0)
+ return 0;
+
+ if (sc->sc_phy_mode == GENET_PHY_MODE_RGMII ||
+ sc->sc_phy_mode == GENET_PHY_MODE_RGMII_RXID)
+ WR4(sc, GENET_SYS_PORT_CTRL,
+ GENET_SYS_PORT_MODE_EXT_GPHY);
+
+ /* Write hardware address */
+ val = enaddr[0] | (enaddr[1] << 8) | (enaddr[2] << 16) |
+ (enaddr[3] << 24);
+ WR4(sc, GENET_UMAC_MAC0, val);
+ val = enaddr[4] | (enaddr[5] << 8);
+ WR4(sc, GENET_UMAC_MAC1, val);
+
+ /* Setup RX filter */
+ genet_setup_rxfilter(sc);
+
+ /* Setup TX/RX rings */
+ genet_init_rings(sc, GENET_DMA_DEFAULT_QUEUE);
+
+ /* Enable transmitter and receiver */
+ val = RD4(sc, GENET_UMAC_CMD);
+ val |= GENET_UMAC_CMD_TXEN;
+ val |= GENET_UMAC_CMD_RXEN;
+ WR4(sc, GENET_UMAC_CMD, val);
+
+ /* Enable interrupts */
+ genet_enable_intr(sc);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ mii_mediachg(mii);
+ callout_schedule(&sc->sc_stat_ch, hz);
+
+ return 0;
+}
+
+static int
+genet_init(struct ifnet *ifp)
+{
+ struct genet_softc *sc = ifp->if_softc;
+ int error;
+
+ GENET_LOCK(sc);
+ error = genet_init_locked(sc);
+ GENET_UNLOCK(sc);
+
+ return error;
+}
+
+static void
+genet_stop_locked(struct genet_softc *sc, int disable)
+{
+ struct ifnet *ifp = &sc->sc_ec.ec_if;
+ uint32_t val;
+
+ GENET_ASSERT_LOCKED(sc);
+
+ callout_stop(&sc->sc_stat_ch);
+
+ mii_down(&sc->sc_mii);
+
+ /* Disable receiver */
+ val = RD4(sc, GENET_UMAC_CMD);
+ val &= ~GENET_UMAC_CMD_RXEN;
+ WR4(sc, GENET_UMAC_CMD, val);
+
+ /* Stop receive DMA */
+ val = RD4(sc, GENET_RX_DMA_CTRL);
+ val &= ~GENET_RX_DMA_CTRL_EN;
+ WR4(sc, GENET_RX_DMA_CTRL, val);
+
+ /* Stop transmit DMA */
+ val = RD4(sc, GENET_TX_DMA_CTRL);
+ val &= ~GENET_TX_DMA_CTRL_EN;
+ WR4(sc, GENET_TX_DMA_CTRL, val);
+
+ /* Flush data in the TX FIFO */
+ WR4(sc, GENET_UMAC_TX_FLUSH, 1);
+ delay(10);
+ WR4(sc, GENET_UMAC_TX_FLUSH, 0);
+
+ /* Disable transmitter */
+ val = RD4(sc, GENET_UMAC_CMD);
+ val &= ~GENET_UMAC_CMD_TXEN;
+ WR4(sc, GENET_UMAC_CMD, val);
+
+ /* Disable interrupts */
+ genet_disable_intr(sc);
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+}
+
+static void
+genet_stop(struct ifnet *ifp, int disable)
+{
+ struct genet_softc * const sc = ifp->if_softc;
+
+ GENET_LOCK(sc);
+ genet_stop_locked(sc, disable);
+ GENET_UNLOCK(sc);
+}
+
+static void
+genet_rxintr(struct genet_softc *sc, int qid)
+{
+ struct ifnet *ifp = &sc->sc_ec.ec_if;
+ int error, index, len, n;
+ struct mbuf *m, *m0;
+ uint32_t status, pidx, total;
+
+ pidx = RD4(sc, GENET_RX_DMA_PROD_INDEX(qid)) & 0xffff;
+ total = (pidx - sc->sc_rx.cidx) & 0xffff;
+
+ DPRINTF("RX pidx=%08x total=%d\n", pidx, total);
+
+ index = sc->sc_rx.cidx & (RX_DESC_COUNT - 1);
+ for (n = 0; n < total; n++) {
+ status = RD4(sc, GENET_RX_DESC_STATUS(index));
+ len = __SHIFTOUT(status, GENET_RX_DESC_STATUS_BUFLEN);
+
+ /* XXX check for errors */
+
+ bus_dmamap_sync(sc->sc_rx.buf_tag, sc->sc_rx.buf_map[index].map,
+ 0, sc->sc_rx.buf_map[index].map->dm_mapsize,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->sc_rx.buf_tag, sc->sc_rx.buf_map[index].map);
+
+ DPRINTF("RX [#%d] index=%02x status=%08x len=%d adj_len=%d\n",
+ n, index, status, len, len - ETHER_ALIGN);
+
+ if (len > ETHER_ALIGN) {
+ m = sc->sc_rx.buf_map[index].mbuf;
+
+ m_adj(m, ETHER_ALIGN);
+
+ m_set_rcvif(m, ifp);
+ m->m_len = m->m_pkthdr.len = len - ETHER_ALIGN;
+ m->m_nextpkt = NULL;
+
+ if_percpuq_enqueue(ifp->if_percpuq, m);
+ }
+
+ if ((m0 = genet_alloc_mbufcl(sc)) != NULL) {
+ error = genet_setup_rxbuf(sc, index, m0);
+ if (error != 0) {
+ /* XXX hole in RX ring */
+ }
+ } else {
+ if_statinc(ifp, if_ierrors);
+ }
+
+ index = RX_NEXT(index);
+
+ sc->sc_rx.cidx = (sc->sc_rx.cidx + 1) & 0xffff;
+ WR4(sc, GENET_RX_DMA_CONS_INDEX(qid), sc->sc_rx.cidx);
+ }
+}
+
+static void
+genet_txintr(struct genet_softc *sc, int qid)
+{
+ struct ifnet *ifp = &sc->sc_ec.ec_if;
+ struct genet_bufmap *bmap;
+ uint32_t cidx, total;
+ int i;
+
+ GENET_ASSERT_LOCKED(sc);
+
+ cidx = RD4(sc, GENET_TX_DMA_CONS_INDEX(qid)) & 0xffff;
+ total = (cidx - sc->sc_tx.cidx) & 0xffff;
+
+ for (i = sc->sc_tx.next; sc->sc_tx.queued > 0 && total > 0; i = TX_NEXT(i), total--) {
+ /* XXX check for errors */
+
+ bmap = &sc->sc_tx.buf_map[i];
+ if (bmap->mbuf != NULL) {
+ bus_dmamap_sync(sc->sc_tx.buf_tag, bmap->map,
+ 0, bmap->map->dm_mapsize,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_tx.buf_tag, bmap->map);
+ m_freem(bmap->mbuf);
+ bmap->mbuf = NULL;
+ }
+
+ --sc->sc_tx.queued;
+ ifp->if_flags &= ~IFF_OACTIVE;
+ if_statinc(ifp, if_opackets);
+ }
+
+ sc->sc_tx.next = i;
+ sc->sc_tx.cidx = cidx;
+}
+
+static void
+genet_start_locked(struct genet_softc *sc)
+{
+ struct ifnet *ifp = &sc->sc_ec.ec_if;
+ struct mbuf *m;
+ int nsegs, index, cnt;
+
+ GENET_ASSERT_LOCKED(sc);
+
+ if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
+ return;
+
+ const int qid = GENET_DMA_DEFAULT_QUEUE;
+
+ index = sc->sc_tx.pidx & (TX_DESC_COUNT - 1);
+ cnt = 0;
+
+ for (;;) {
+ IFQ_POLL(&ifp->if_snd, m);
+ if (m == NULL)
+ break;
+
+ nsegs = genet_setup_txbuf(sc, index, m);
+ if (nsegs <= 0) {
+ if (nsegs == -1)
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+ IFQ_DEQUEUE(&ifp->if_snd, m);
+ bpf_mtap(ifp, m, BPF_D_OUT);
+
+ index = TX_SKIP(index, nsegs);
+
+ sc->sc_tx.pidx = (sc->sc_tx.pidx + nsegs) & 0xffff;
+ cnt++;
+ }
+
+ if (cnt != 0)
+ WR4(sc, GENET_TX_DMA_PROD_INDEX(qid), sc->sc_tx.pidx);
+}
+
+static void
+genet_start(struct ifnet *ifp)
+{
+ struct genet_softc *sc = ifp->if_softc;
+
+ GENET_LOCK(sc);
+ genet_start_locked(sc);
+ GENET_UNLOCK(sc);
+}
+
+int
+genet_intr(void *arg)
+{
+ struct genet_softc *sc = arg;
+ struct ifnet *ifp = &sc->sc_ec.ec_if;
+ uint32_t val;
+
+ GENET_LOCK(sc);
+
+ val = RD4(sc, GENET_INTRL2_CPU_STAT);
+ val &= ~RD4(sc, GENET_INTRL2_CPU_STAT_MASK);
+ WR4(sc, GENET_INTRL2_CPU_CLEAR, val);
+
+ if (val & GENET_IRQ_RXDMA_DONE)
+ genet_rxintr(sc, GENET_DMA_DEFAULT_QUEUE);
+
+ if (val & GENET_IRQ_TXDMA_DONE) {
+ genet_txintr(sc, GENET_DMA_DEFAULT_QUEUE);
+ if_schedule_deferred_start(ifp);
+ }
+
+ GENET_UNLOCK(sc);
+
+ return 1;
+}
+
+static int
+genet_ioctl(struct ifnet *ifp, u_long cmd, void *data)
+{
+ struct genet_softc *sc = ifp->if_softc;
+ int error, s;
+
+#ifndef GENET_MPSAFE
+ s = splnet();
+#endif
+
+ switch (cmd) {
+ default:
+#ifdef GENET_MPSAFE
+ s = splnet();
+#endif
+ error = ether_ioctl(ifp, cmd, data);
+#ifdef GENET_MPSAFE
+ splx(s);
+#endif
+ if (error != ENETRESET)
+ break;
+
+ error = 0;
+
+ if (cmd == SIOCSIFCAP)
+ error = (*ifp->if_init)(ifp);
+ else if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
+ ;
+ else if ((ifp->if_flags & IFF_RUNNING) != 0) {
+ GENET_LOCK(sc);
+ genet_setup_rxfilter(sc);
+ GENET_UNLOCK(sc);
+ }
+ break;
+ }
+
+#ifndef GENET_MPSAFE
+ splx(s);
+#endif
+
+ return error;
+}
+
+static void
+genet_get_eaddr(struct genet_softc *sc, uint8_t *eaddr)
+{
+ prop_dictionary_t prop = device_properties(sc->sc_dev);
+ uint32_t maclo, machi;
+ prop_data_t eaprop;
+
+ eaprop = prop_dictionary_get(prop, "mac-address");
+ if (eaprop == NULL) {
+ /* Create one */
+ maclo = 0x00f2 | (cprng_strong32() & 0xffff0000);
+ machi = cprng_strong32() & 0xffff;
+
+ eaddr[0] = maclo & 0xff;
+ eaddr[1] = (maclo >> 8) & 0xff;
+ eaddr[2] = (maclo >> 16) & 0xff;
+ eaddr[3] = (maclo >> 24) & 0xff;
+ eaddr[4] = machi & 0xff;
+ eaddr[5] = (machi >> 8) & 0xff;
+ } else {
+ KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA);
+ KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN);
+ memcpy(eaddr, prop_data_data_nocopy(eaprop),
+ ETHER_ADDR_LEN);
+ }
+
+}
+
+static int
+genet_setup_dma(struct genet_softc *sc, int qid)
+{
+ struct mbuf *m;
+ int error, i;
+
+ /* Setup TX ring */
+ sc->sc_tx.buf_tag = sc->sc_dmat;
+ for (i = 0; i < TX_DESC_COUNT; i++) {
+ error = bus_dmamap_create(sc->sc_tx.buf_tag, MCLBYTES,
+ TX_MAX_SEGS, MCLBYTES, 0, BUS_DMA_WAITOK,
+ &sc->sc_tx.buf_map[i].map);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "cannot create TX buffer map\n");
+ return error;
+ }
+ }
+
+ /* Setup RX ring */
+ sc->sc_rx.buf_tag = sc->sc_dmat;
+ for (i = 0; i < RX_DESC_COUNT; i++) {
+ error = bus_dmamap_create(sc->sc_rx.buf_tag, MCLBYTES,
+ 1, MCLBYTES, 0, BUS_DMA_WAITOK,
+ &sc->sc_rx.buf_map[i].map);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "cannot create RX buffer map\n");
+ return error;
+ }
+ if ((m = genet_alloc_mbufcl(sc)) == NULL) {
+ device_printf(sc->sc_dev, "cannot allocate RX mbuf\n");
+ return ENOMEM;
+ }
+ error = genet_setup_rxbuf(sc, i, m);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "cannot create RX buffer\n");
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+int
+genet_attach(struct genet_softc *sc)
+{
+ struct mii_data *mii = &sc->sc_mii;
+ struct ifnet *ifp = &sc->sc_ec.ec_if;
+ uint8_t eaddr[ETHER_ADDR_LEN];
+ u_int maj, min;
+
+ const uint32_t rev = RD4(sc, GENET_SYS_REV_CTRL);
+ min = __SHIFTOUT(rev, SYS_REV_MINOR);
+ maj = __SHIFTOUT(rev, SYS_REV_MAJOR);
+ if (maj == 0)
+ maj++;
+ else if (maj == 5 || maj == 6)
+ maj--;
+
+ if (maj != 5) {
+ aprint_error(": GENETv%d.%d not supported\n", maj, min);
+ return ENXIO;
+ }
+
+ aprint_naive("\n");
+ aprint_normal(": GENETv%d.%d\n", maj, min);
+
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NET);
+ callout_init(&sc->sc_stat_ch, CALLOUT_FLAGS);
+ callout_setfunc(&sc->sc_stat_ch, genet_tick, sc);
+
+ genet_get_eaddr(sc, eaddr);
+ aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n", ether_sprintf(eaddr));
+
+ /* Soft reset EMAC core */
+ genet_reset(sc);
+
+ /* Setup DMA descriptors */
+ if (genet_setup_dma(sc, GENET_DMA_DEFAULT_QUEUE) != 0) {
+ aprint_error_dev(sc->sc_dev, "failed to setup DMA descriptors\n");
+ return EINVAL;
+ }
+
+ /* Setup ethernet interface */
+ ifp->if_softc = sc;
+ snprintf(ifp->if_xname, IFNAMSIZ, device_xname(sc->sc_dev));
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+#ifdef GENET_MPSAFE
+ ifp->if_extflags = IFEF_MPSAFE;
+#endif
+ ifp->if_start = genet_start;
+ ifp->if_ioctl = genet_ioctl;
+ ifp->if_init = genet_init;
+ ifp->if_stop = genet_stop;
+ ifp->if_capabilities = 0;
+ ifp->if_capenable = ifp->if_capabilities;
+ IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+ IFQ_SET_READY(&ifp->if_snd);
+
+ /* 802.1Q VLAN-sized frames are supported */
+ sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_MTU;
+
+ /* Attach MII driver */
+ sc->sc_ec.ec_mii = mii;
+ ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus);
+ mii->mii_ifp = ifp;
+ mii->mii_readreg = genet_mii_readreg;
+ mii->mii_writereg = genet_mii_writereg;
+ mii->mii_statchg = genet_mii_statchg;
+ mii_attach(sc->sc_dev, mii, 0xffffffff, sc->sc_phy_id, MII_OFFSET_ANY,
+ 0);
+
+ if (LIST_EMPTY(&mii->mii_phys)) {
+ aprint_error_dev(sc->sc_dev, "no PHY found!\n");
+ return ENOENT;
+ }
+ ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
+
+ /* Attach interface */
+ if_attach(ifp);
+ if_deferred_start_init(ifp, NULL);
+
+ /* Attach ethernet interface */
+ ether_ifattach(ifp, eaddr);
+
+ return 0;
+}
+
+#ifdef DDB
+void genet_debug(void);
+
+void
+genet_debug(void)
+{
+ device_t dev = device_find_by_xname("genet0");
+ if (dev == NULL)
+ return;
+
+ struct genet_softc * const sc = device_private(dev);
+ const int qid = GENET_DMA_DEFAULT_QUEUE;
+
+ printf("TX CIDX = %08x (soft)\n", sc->sc_tx.cidx);
+ printf("TX CIDX = %08x\n", RD4(sc, GENET_TX_DMA_CONS_INDEX(qid)));
+ printf("TX PIDX = %08x (soft)\n", sc->sc_tx.pidx);
+ printf("TX PIDX = %08x\n", RD4(sc, GENET_TX_DMA_PROD_INDEX(qid)));
+
+ printf("RX CIDX = %08x (soft)\n", sc->sc_rx.cidx);
+ printf("RX CIDX = %08x\n", RD4(sc, GENET_RX_DMA_CONS_INDEX(qid)));
+ printf("RX PIDX = %08x (soft)\n", sc->sc_rx.pidx);
+ printf("RX PIDX = %08x\n", RD4(sc, GENET_RX_DMA_PROD_INDEX(qid)));
+}
+#endif
Index: src/sys/dev/ic/bcmgenetreg.h
diff -u /dev/null src/sys/dev/ic/bcmgenetreg.h:1.1
--- /dev/null Sat Feb 22 00:28:36 2020
+++ src/sys/dev/ic/bcmgenetreg.h Sat Feb 22 00:28:35 2020
@@ -0,0 +1,165 @@
+/* $NetBSD: bcmgenetreg.h,v 1.1 2020/02/22 00:28:35 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2020 Jared McNeill <[email protected]>
+ * All rights reserved.
+ *
+ * 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 ``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 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.
+ */
+
+/*
+ * Broadcom GENETv5
+ */
+
+#ifndef _BCMGENETREG_H
+#define _BCMGENETREG_H
+
+#define GENET_SYS_REV_CTRL 0x000
+#define SYS_REV_MAJOR __BITS(27,24)
+#define SYS_REV_MINOR __BITS(19,16)
+#define GENET_SYS_PORT_CTRL 0x004
+#define GENET_SYS_PORT_MODE_EXT_GPHY 3
+#define GENET_SYS_RBUF_FLUSH_CTRL 0x008
+#define GENET_SYS_RBUF_FLUSH_RESET __BIT(1)
+#define GENET_SYS_TBUF_FLUSH_CTRL 0x00c
+#define GENET_EXT_RGMII_OOB_CTRL 0x08c
+#define GENET_EXT_RGMII_OOB_ID_MODE_DISABLE __BIT(16)
+#define GENET_EXT_RGMII_OOB_RGMII_MODE_EN __BIT(6)
+#define GENET_EXT_RGMII_OOB_OOB_DISABLE __BIT(5)
+#define GENET_EXT_RGMII_OOB_RGMII_LINK __BIT(4)
+#define GENET_INTRL2_CPU_STAT 0x200
+#define GENET_INTRL2_CPU_CLEAR 0x208
+#define GENET_INTRL2_CPU_STAT_MASK 0x20c
+#define GENET_INTRL2_CPU_SET_MASK 0x210
+#define GENET_INTRL2_CPU_CLEAR_MASK 0x214
+#define GENET_IRQ_MDIO_ERROR __BIT(24)
+#define GENET_IRQ_MDIO_DONE __BIT(23)
+#define GENET_IRQ_TXDMA_DONE __BIT(16)
+#define GENET_IRQ_RXDMA_DONE __BIT(13)
+#define GENET_RBUF_CTRL 0x300
+#define GENET_RBUF_BAD_DIS __BIT(2)
+#define GENET_RBUF_ALIGN_2B __BIT(1)
+#define GENET_RBUF_64B_EN __BIT(0)
+#define GENET_RBUF_TBUF_SIZE_CTRL 0x3b4
+#define GENET_UMAC_CMD 0x808
+#define GENET_UMAC_CMD_LCL_LOOP_EN __BIT(15)
+#define GENET_UMAC_CMD_SW_RESET __BIT(13)
+#define GENET_UMAC_CMD_PROMISC __BIT(4)
+#define GENET_UMAC_CMD_SPEED __BITS(3,2)
+#define GENET_UMAC_CMD_SPEED_10 0
+#define GENET_UMAC_CMD_SPEED_100 1
+#define GENET_UMAC_CMD_SPEED_1000 2
+#define GENET_UMAC_CMD_RXEN __BIT(1)
+#define GENET_UMAC_CMD_TXEN __BIT(0)
+#define GENET_UMAC_MAC0 0x80c
+#define GENET_UMAC_MAC1 0x810
+#define GENET_UMAC_MAX_FRAME_LEN 0x814
+#define GENET_UMAC_TX_FLUSH 0xb34
+#define GENET_UMAC_MIB_CTRL 0xd80
+#define GENET_UMAC_MIB_RESET_TX __BIT(2)
+#define GENET_UMAC_MIB_RESET_RUNT __BIT(1)
+#define GENET_UMAC_MIB_RESET_RX __BIT(0)
+#define GENET_MDIO_CMD 0xe14
+#define GENET_MDIO_START_BUSY __BIT(29)
+#define GENET_MDIO_READ __BIT(27)
+#define GENET_MDIO_WRITE __BIT(26)
+#define GENET_MDIO_PMD __BITS(25,21)
+#define GENET_MDIO_REG __BITS(20,16)
+#define GENET_UMAC_MDF_CTRL 0xe50
+
+#define GENET_DMA_DESC_COUNT 256
+#define GENET_DMA_DESC_SIZE 12
+#define GENET_DMA_DEFAULT_QUEUE 16
+
+#define GENET_DMA_RING_SIZE 0x40
+#define GENET_DMA_RINGS_SIZE (GENET_DMA_RING_SIZE * (GENET_DMA_DEFAULT_QUEUE + 1))
+
+#define GENET_RX_BASE 0x2000
+#define GENET_TX_BASE 0x4000
+
+#define GENET_RX_DMA_RINGBASE(qid) (GENET_RX_BASE + 0xc00 + GENET_DMA_RING_SIZE * (qid))
+#define GENET_RX_DMA_WRITE_PTR_LO(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x00)
+#define GENET_RX_DMA_WRITE_PTR_HI(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x04)
+#define GENET_RX_DMA_PROD_INDEX(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x08)
+#define GENET_RX_DMA_CONS_INDEX(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x0c)
+#define GENET_RX_DMA_RING_BUF_SIZE(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x10)
+#define GENET_RX_DMA_RING_BUF_SIZE_DESC_COUNT __BITS(31,16)
+#define GENET_RX_DMA_RING_BUF_SIZE_BUF_LENGTH __BITS(15,0)
+#define GENET_RX_DMA_START_ADDR_LO(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x14)
+#define GENET_RX_DMA_START_ADDR_HI(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x18)
+#define GENET_RX_DMA_END_ADDR_LO(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x1c)
+#define GENET_RX_DMA_END_ADDR_HI(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x20)
+#define GENET_RX_DMA_XON_XOFF_THRES(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x28)
+#define GENET_RX_DMA_XON_XOFF_THRES_LO __BITS(31,16)
+#define GENET_RX_DMA_XON_XOFF_THRES_HI __BITS(15,0)
+#define GENET_RX_DMA_READ_PTR_LO(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x2c)
+#define GENET_RX_DMA_READ_PTR_HI(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x30)
+
+#define GENET_TX_DMA_RINGBASE(qid) (GENET_TX_BASE + 0xc00 + GENET_DMA_RING_SIZE * (qid))
+#define GENET_TX_DMA_READ_PTR_LO(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x00)
+#define GENET_TX_DMA_READ_PTR_HI(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x04)
+#define GENET_TX_DMA_CONS_INDEX(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x08)
+#define GENET_TX_DMA_PROD_INDEX(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x0c)
+#define GENET_TX_DMA_RING_BUF_SIZE(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x10)
+#define GENET_TX_DMA_RING_BUF_SIZE_DESC_COUNT __BITS(31,16)
+#define GENET_TX_DMA_RING_BUF_SIZE_BUF_LENGTH __BITS(15,0)
+#define GENET_TX_DMA_START_ADDR_LO(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x14)
+#define GENET_TX_DMA_START_ADDR_HI(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x18)
+#define GENET_TX_DMA_END_ADDR_LO(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x1c)
+#define GENET_TX_DMA_END_ADDR_HI(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x20)
+#define GENET_TX_DMA_MBUF_DONE_THRES(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x24)
+#define GENET_TX_DMA_FLOW_PERIOD(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x28)
+#define GENET_TX_DMA_WRITE_PTR_LO(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x2c)
+#define GENET_TX_DMA_WRITE_PTR_HI(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x30)
+
+#define GENET_RX_DESC_STATUS(idx) (GENET_RX_BASE + GENET_DMA_DESC_SIZE * (idx) + 0x00)
+#define GENET_RX_DESC_STATUS_BUFLEN __BITS(27,16)
+#define GENET_RX_DESC_STATUS_OWN __BIT(15)
+#define GENET_RX_DESC_STATUS_EOP __BIT(14)
+#define GENET_RX_DESC_STATUS_SOP __BIT(13)
+#define GENET_RX_DESC_STATUS_RX_ERROR __BIT(2)
+#define GENET_RX_DESC_ADDRESS_LO(idx) (GENET_RX_BASE + GENET_DMA_DESC_SIZE * (idx) + 0x04)
+#define GENET_RX_DESC_ADDRESS_HI(idx) (GENET_RX_BASE + GENET_DMA_DESC_SIZE * (idx) + 0x08)
+
+#define GENET_TX_DESC_STATUS(idx) (GENET_TX_BASE + GENET_DMA_DESC_SIZE * (idx) + 0x00)
+#define GENET_TX_DESC_STATUS_BUFLEN __BITS(27,16)
+#define GENET_TX_DESC_STATUS_OWN __BIT(15)
+#define GENET_TX_DESC_STATUS_EOP __BIT(14)
+#define GENET_TX_DESC_STATUS_SOP __BIT(13)
+#define GENET_TX_DESC_STATUS_QTAG __BITS(12,7)
+#define GENET_TX_DESC_STATUS_CRC __BIT(6)
+#define GENET_TX_DESC_ADDRESS_LO(idx) (GENET_TX_BASE + GENET_DMA_DESC_SIZE * (idx) + 0x04)
+#define GENET_TX_DESC_ADDRESS_HI(idx) (GENET_TX_BASE + GENET_DMA_DESC_SIZE * (idx) + 0x08)
+
+#define GENET_RX_DMA_RING_CFG (GENET_RX_BASE + 0x1040 + 0x00)
+#define GENET_RX_DMA_CTRL (GENET_RX_BASE + 0x1040 + 0x04)
+#define GENET_RX_DMA_CTRL_RBUF_EN(qid) __BIT((qid) + 1)
+#define GENET_RX_DMA_CTRL_EN __BIT(0)
+#define GENET_RX_SCB_BURST_SIZE (GENET_RX_BASE + 0x1040 + 0x0c)
+
+#define GENET_TX_DMA_RING_CFG (GENET_TX_BASE + 0x1040 + 0x00)
+#define GENET_TX_DMA_CTRL (GENET_TX_BASE + 0x1040 + 0x04)
+#define GENET_TX_DMA_CTRL_RBUF_EN(qid) __BIT((qid) + 1)
+#define GENET_TX_DMA_CTRL_EN __BIT(0)
+#define GENET_TX_SCB_BURST_SIZE (GENET_TX_BASE + 0x1040 + 0x0c)
+
+#endif /* !_BCMGENETREG_H */
Index: src/sys/dev/ic/bcmgenetvar.h
diff -u /dev/null src/sys/dev/ic/bcmgenetvar.h:1.1
--- /dev/null Sat Feb 22 00:28:36 2020
+++ src/sys/dev/ic/bcmgenetvar.h Sat Feb 22 00:28:35 2020
@@ -0,0 +1,76 @@
+/* $NetBSD: bcmgenetvar.h,v 1.1 2020/02/22 00:28:35 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2020 Jared McNeill <[email protected]>
+ * All rights reserved.
+ *
+ * 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 ``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 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.
+ */
+
+/*
+ * Broadcom GENETv5
+ */
+
+#ifndef _BCMGENETVAR_H
+#define _BCMGENETVAR_H
+
+#include <dev/ic/bcmgenetreg.h>
+
+enum genet_phy_mode {
+ GENET_PHY_MODE_RGMII,
+ GENET_PHY_MODE_RGMII_TXID,
+ GENET_PHY_MODE_RGMII_RXID,
+};
+
+struct genet_bufmap {
+ bus_dmamap_t map;
+ struct mbuf *mbuf;
+};
+
+struct genet_ring {
+ bus_dma_tag_t buf_tag;
+ struct genet_bufmap buf_map[GENET_DMA_DESC_COUNT];
+ u_int next, queued;
+ uint32_t cidx, pidx;
+};
+
+struct genet_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_bst;
+ bus_space_handle_t sc_bsh;
+ bus_dma_tag_t sc_dmat;
+ int sc_phy_id;
+ enum genet_phy_mode sc_phy_mode;
+
+ struct ethercom sc_ec;
+ struct mii_data sc_mii;
+ callout_t sc_stat_ch;
+ kmutex_t sc_lock;
+
+ struct genet_ring sc_tx;
+ struct genet_ring sc_rx;
+};
+
+int genet_attach(struct genet_softc *);
+int genet_intr(void *);
+
+#endif /* !_BCMGENETVAR_H */