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 <jmcne...@invisible.ca> @@ -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 <jmcne...@invisible.ca> + * 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 <jmcne...@invisible.ca> + * 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 <jmcne...@invisible.ca> + * 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 <jmcne...@invisible.ca> + * 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 */