The diff below adds support for the Ethernet interface on the Raspberry Pi4. The new driver is called bse(4) for Broadcom SoC Ethernet ;). It is a port of the NetBSD driver (where the driver is called genet(4), but over here we prefer short names for our network drivers). There have been many changes to adapt the driver to our codebase, in particular the ring accounting framework. Only the ACPI attachment is provided for now. An FDT attachment will follow later. Seems I can sustain ~700 Mbit/s with this diff.
This is the complete diff including the acpi_getprop() and brgphy(4) diffs I posted earlier. It is my intention to commit those separately. ok? Index: arch/arm64/conf/GENERIC =================================================================== RCS file: /cvs/src/sys/arch/arm64/conf/GENERIC,v retrieving revision 1.149 diff -u -p -r1.149 GENERIC --- arch/arm64/conf/GENERIC 3 Apr 2020 16:29:17 -0000 1.149 +++ arch/arm64/conf/GENERIC 12 Apr 2020 15:38:42 -0000 @@ -138,12 +138,13 @@ ssdfb* at spi? wsdisplay* at ssdfb? imxtmu* at fdt? -# Raspberry Pi 3 +# Raspberry Pi 3/4 bcmaux* at fdt? bcmintc* at fdt? bcmdog* at fdt? bcmrng* at fdt? bcmtemp* at fdt? +bse* at acpi? dwctwo* at fdt? usb* at dwctwo? @@ -383,6 +384,7 @@ bwfm* at uhub? # Broadcom FullMAC amphy* at mii? # AMD 79C873 PHYs atphy* at mii? # Attansic F1 PHYs +brgphy* at mii? # Broadcom Gigabit PHYs eephy* at mii? # Marvell 88E1000 series PHY rgephy* at mii? # Realtek 8169S/8110S PHY rlphy* at mii? # Realtek 8139 internal PHYs Index: conf/files =================================================================== RCS file: /cvs/src/sys/conf/files,v retrieving revision 1.685 diff -u -p -r1.685 files --- conf/files 2 Mar 2020 10:37:22 -0000 1.685 +++ conf/files 12 Apr 2020 15:38:43 -0000 @@ -306,6 +306,10 @@ file dev/ic/gem.c gem device ti: ether, ifnet, ifmedia, mii, firmload file dev/ic/ti.c ti +# Broadcom BCM7XXX Ethernet controller +device bse: ether, ifnet, ifmedia, mii +file dev/ic/bcmgenet.c bse + # 8250/16[45]50-based "com" ports device com: tty file dev/ic/com.c com & (com | com_cardbus | com_gsc | Index: dev/acpi/acpi.c =================================================================== RCS file: /cvs/src/sys/dev/acpi/acpi.c,v retrieving revision 1.381 diff -u -p -r1.381 acpi.c --- dev/acpi/acpi.c 12 Apr 2020 09:21:19 -0000 1.381 +++ dev/acpi/acpi.c 12 Apr 2020 15:38:43 -0000 @@ -2961,6 +2961,57 @@ acpi_foundsony(struct aml_node *node, vo /* Support for _DSD Device Properties. */ +int +acpi_getprop(struct aml_node *node, const char *prop, void *buf, int buflen) +{ + struct aml_value dsd; + int i; + + /* daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */ + static uint8_t prop_guid[] = { + 0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d, + 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01, + }; + + if (aml_evalname(acpi_softc, node, "_DSD", 0, NULL, &dsd)) + return -1; + + if (dsd.type != AML_OBJTYPE_PACKAGE || dsd.length != 2 || + dsd.v_package[0]->type != AML_OBJTYPE_BUFFER || + dsd.v_package[1]->type != AML_OBJTYPE_PACKAGE) + return -1; + + /* Check UUID. */ + if (dsd.v_package[0]->length != sizeof(prop_guid) || + memcmp(dsd.v_package[0]->v_buffer, prop_guid, + sizeof(prop_guid)) != 0) + return -1; + + /* Check properties. */ + for (i = 0; i < dsd.v_package[1]->length; i++) { + struct aml_value *res = dsd.v_package[1]->v_package[i]; + int len; + + if (res->type != AML_OBJTYPE_PACKAGE || res->length != 2 || + res->v_package[0]->type != AML_OBJTYPE_STRING) + continue; + + len = res->v_package[1]->length; + switch (res->v_package[1]->type) { + case AML_OBJTYPE_BUFFER: + memcpy(buf, res->v_package[1]->v_buffer, + min(len, buflen)); + return len; + case AML_OBJTYPE_STRING: + memcpy(buf, res->v_package[1]->v_string, + min(len, buflen)); + return len; + } + } + + return -1; +} + uint32_t acpi_getpropint(struct aml_node *node, const char *prop, uint32_t defval) { @@ -2999,7 +3050,7 @@ acpi_getpropint(struct aml_node *node, c if (strcmp(res->v_package[0]->v_string, prop) == 0) return res->v_package[1]->v_integer; } - + return defval; } Index: dev/acpi/acpivar.h =================================================================== RCS file: /cvs/src/sys/dev/acpi/acpivar.h,v retrieving revision 1.106 diff -u -p -r1.106 acpivar.h --- dev/acpi/acpivar.h 12 Apr 2020 09:21:19 -0000 1.106 +++ dev/acpi/acpivar.h 12 Apr 2020 15:38:43 -0000 @@ -372,6 +372,7 @@ int acpi_matchhids(struct acpi_attach_ar int acpi_parsehid(struct aml_node *, void *, char *, char *, size_t); int64_t acpi_getsta(struct acpi_softc *sc, struct aml_node *); +int acpi_getprop(struct aml_node *, const char *, void *, int); uint32_t acpi_getpropint(struct aml_node *, const char *, uint32_t); int acpi_record_event(struct acpi_softc *, u_int); Index: dev/acpi/files.acpi =================================================================== RCS file: /cvs/src/sys/dev/acpi/files.acpi,v retrieving revision 1.53 diff -u -p -r1.53 files.acpi --- dev/acpi/files.acpi 23 Dec 2019 08:05:42 -0000 1.53 +++ dev/acpi/files.acpi 12 Apr 2020 15:38:43 -0000 @@ -212,3 +212,7 @@ file dev/acpi/ccp_acpi.c ccp_acpi device amdgpio attach amdgpio at acpi file dev/acpi/amdgpio.c amdgpio + +# Broadcom BC7XXX Ethernet controller +attach bse at acpi with bse_acpi +file dev/acpi/if_bse_acpi.c bse_acpi Index: dev/acpi/if_bse_acpi.c =================================================================== RCS file: dev/acpi/if_bse_acpi.c diff -N dev/acpi/if_bse_acpi.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/acpi/if_bse_acpi.c 12 Apr 2020 15:38:43 -0000 @@ -0,0 +1,172 @@ +/* $OpenBSD$ */ +/* + * Copyright (c) 2020 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/bus.h> +#include <machine/intr.h> + +#include <net/if.h> +#include <net/if_media.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> +#include <dev/acpi/acpidev.h> +#include <dev/acpi/amltypes.h> +#include <dev/acpi/dsdt.h> + + +#include <dev/mii/miivar.h> + +#include <dev/ic/bcmgenetvar.h> + +struct bse_acpi_softc { + struct genet_softc sc; + struct acpi_softc *sc_acpi; + struct aml_node *sc_node; + + bus_addr_t sc_addr; + bus_size_t sc_size; + + int sc_irq; + int sc_irq_flags; +}; + +int bse_acpi_match(struct device *, void *, void *); +void bse_acpi_attach(struct device *, struct device *, void *); + +struct cfattach bse_acpi_ca = { + sizeof(struct bse_acpi_softc), bse_acpi_match, bse_acpi_attach +}; + +const char *bse_hids[] = { + "BCM6E4E", + NULL +}; + +int bse_acpi_parse_resources(int, union acpi_resource *, void *); + +int +bse_acpi_match(struct device *parent, void *match, void *aux) +{ + struct acpi_attach_args *aaa = aux; + struct cfdata *cf = match; + + return acpi_matchhids(aaa, bse_hids, cf->cf_driver->cd_name); +} + +void +bse_acpi_attach(struct device *parent, struct device *self, void *aux) +{ + struct bse_acpi_softc *sc = (struct bse_acpi_softc *)self; + struct acpi_attach_args *aaa = aux; + struct aml_value res; + char phy_mode[16] = { 0 }; + int error; + + sc->sc_acpi = (struct acpi_softc *)parent; + sc->sc_node = aaa->aaa_node; + printf(" %s", sc->sc_node->name); + + if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) { + printf(": can't find registers\n"); + return; + } + + aml_parse_resource(&res, bse_acpi_parse_resources, sc); + printf(" addr 0x%lx/0x%lx", sc->sc_addr, sc->sc_size); + if (sc->sc_addr == 0 || sc->sc_size == 0) { + printf("\n"); + return; + } + + printf(" irq %d", sc->sc_irq); + + sc->sc.sc_bst = aaa->aaa_memt; + sc->sc.sc_dmat = aaa->aaa_dmat; + + if (bus_space_map(sc->sc.sc_bst, sc->sc_addr, sc->sc_size, 0, + &sc->sc.sc_bsh)) { + printf(": can't map registers\n"); + return; + } + + sc->sc.sc_ih = acpi_intr_establish(sc->sc_irq, sc->sc_irq_flags, + IPL_NET, genet_intr, sc, sc->sc.sc_dev.dv_xname); + if (sc->sc.sc_ih == NULL) { + printf(": can't establish interrupt\n"); + goto unmap; + } + + /* + * UEFI firmware initializes the hardware MAC address + * registers. Read them here before we reset the hardware. + */ + genet_lladdr_read(&sc->sc, sc->sc.sc_lladdr); + + acpi_getprop(sc->sc_node, "phy-mode", phy_mode, sizeof(phy_mode)); + if (strcmp(phy_mode, "rgmii-id") == 0) + sc->sc.sc_phy_mode = GENET_PHY_MODE_RGMII_ID; + else if (strcmp(phy_mode, "rgmii-rxid") == 0) + sc->sc.sc_phy_mode = GENET_PHY_MODE_RGMII_RXID; + else if (strcmp(phy_mode, "rgmii-txid") == 0) + sc->sc.sc_phy_mode = GENET_PHY_MODE_RGMII_TXID; + else + sc->sc.sc_phy_mode = GENET_PHY_MODE_RGMII; + + sc->sc.sc_phy_id = MII_PHY_ANY; + error = genet_attach(&sc->sc); + if (error) + goto disestablish; + + return; + +disestablish: +#ifdef notyet + acpi_intr_disestablish(sc->sc.sc_ih); +#endif +unmap: + bus_space_unmap(sc->sc.sc_bst, sc->sc.sc_bsh, sc->sc_size); + return; +} + +int +bse_acpi_parse_resources(int crsidx, union acpi_resource *crs, void *arg) +{ + struct bse_acpi_softc *sc = arg; + int type = AML_CRSTYPE(crs); + + switch (type) { + case LR_MEM32FIXED: + /* XHCI registers are specified by the first resource. */ + if (sc->sc_size == 0) { + sc->sc_addr = crs->lr_m32fixed._bas; + sc->sc_size = crs->lr_m32fixed._len; + } + break; + case LR_EXTIRQ: + sc->sc_irq = crs->lr_extirq.irq[0]; + sc->sc_irq_flags = crs->lr_extirq.flags; + break; + } + + return 0; +} Index: dev/ic/bcmgenet.c =================================================================== RCS file: dev/ic/bcmgenet.c diff -N dev/ic/bcmgenet.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/ic/bcmgenet.c 12 Apr 2020 15:38:43 -0000 @@ -0,0 +1,1020 @@ +/* $OpenBSD$ */ +/* $NetBSD: bcmgenet.c,v 1.3 2020/02/27 17:30:07 jmcneill Exp $ */ + +/*- + * Copyright (c) 2020 Jared McNeill <jmcne...@invisible.ca> + * Copyright (c) 2020 Mark Kettenis <kette...@openbsd.org> + * 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 <sys/param.h> +#include <sys/device.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/timeout.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/bpf.h> + +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <machine/bus.h> +#include <machine/intr.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 + +#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_MAX_MDF_FILTER 17 + +#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)) + +struct cfdriver bse_cd = { + 0, "bse", DV_IFNET +}; + +int +genet_media_change(struct ifnet *ifp) +{ + struct genet_softc *sc = ifp->if_softc; + + if (LIST_FIRST(&sc->sc_mii.mii_phys)) + mii_mediachg(&sc->sc_mii); + + return (0); +} + +void +genet_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + struct genet_softc *sc = ifp->if_softc; + + if (LIST_FIRST(&sc->sc_mii.mii_phys)) { + mii_pollstat(&sc->sc_mii); + ifmr->ifm_active = sc->sc_mii.mii_media_active; + ifmr->ifm_status = sc->sc_mii.mii_media_status; + } +} + +int +genet_mii_readreg(struct device *dev, int phy, int reg) +{ + struct genet_softc *sc = (struct genet_softc *)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) + return RD4(sc, GENET_MDIO_CMD) & 0xffff; + delay(10); + } + + printf("%s: phy read timeout, phy=%d reg=%d\n", + sc->sc_dev.dv_xname, phy, reg); + return 0; +} + +void +genet_mii_writereg(struct device *dev, int phy, int reg, int val) +{ + struct genet_softc *sc = (struct genet_softc *)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) + return; + delay(10); + } + + printf("%s: phy write timeout, phy=%d reg=%d\n", + sc->sc_dev.dv_xname, phy, reg); +} + +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; + else + 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); +} + +void +genet_mii_statchg(struct device *self) +{ + struct genet_softc *sc = (struct genet_softc *)self; + + genet_update_link(sc); +} + +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); +} + +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; + + /* + * XXX Hardware doesn't seem to like small fragments. For now + * just look ate the first fragment and defrag if it is + * smaller than the minimum Ethernet packet size. + */ + if (m->m_len < ETHER_MIN_LEN - ETHER_CRC_LEN) { + if (m_defrag(m, M_DONTWAIT)) + return 0; + } + + 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) { + if (m_defrag(m, M_DONTWAIT)) + return 0; + 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 != 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; +} + +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)); +} + +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; +} + +struct mbuf * +genet_alloc_mbufcl(struct genet_softc *sc) +{ + struct mbuf *m; + + m = MCLGETI(NULL, M_DONTWAIT, NULL, MCLBYTES); + if (m != NULL) + m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; + + return m; +} + +void +genet_fill_rx_ring(struct genet_softc *sc, int qid) +{ + struct mbuf *m; + uint32_t cidx, index, total; + u_int slots; + int error; + + cidx = sc->sc_rx.cidx; + total = (sc->sc_rx.pidx - cidx) & 0xffff; + KASSERT(total <= RX_DESC_COUNT); + + index = sc->sc_rx.cidx & (RX_DESC_COUNT - 1); + for (slots = if_rxr_get(&sc->sc_rx_ring, total); + slots > 0; slots--) { + if ((m = genet_alloc_mbufcl(sc)) == NULL) { + printf("%s: cannot allocate RX mbuf\n", + sc->sc_dev.dv_xname); + break; + } + error = genet_setup_rxbuf(sc, index, m); + if (error != 0) { + printf("%s: cannot create RX buffer\n", + sc->sc_dev.dv_xname); + m_freem(m); + break; + } + + cidx = (cidx + 1) & 0xffff; + index = RX_NEXT(index); + } + if_rxr_put(&sc->sc_rx_ring, slots); + + if (sc->sc_rx.cidx != cidx) { + sc->sc_rx.cidx = cidx; + WR4(sc, GENET_RX_DMA_CONS_INDEX(qid), sc->sc_rx.cidx); + } + + if (if_rxr_inuse(&sc->sc_rx_ring) == 0) + timeout_add(&sc->sc_rxto, 1); +} + +void +genet_rxtick(void *arg) +{ + genet_fill_rx_ring(arg, GENET_DMA_DEFAULT_QUEUE); +} + +void +genet_enable_intr(struct genet_softc *sc) +{ + WR4(sc, GENET_INTRL2_CPU_CLEAR_MASK, + GENET_IRQ_TXDMA_DONE | GENET_IRQ_RXDMA_DONE); +} + +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); +} + +void +genet_tick(void *softc) +{ + struct genet_softc *sc = softc; + struct mii_data *mii = &sc->sc_mii; + int s = splnet(); + + mii_tick(mii); + timeout_add_sec(&sc->sc_stat_ch, 1); + + splx(s); +} + +void +genet_setup_rxfilter_mdf(struct genet_softc *sc, u_int n, const uint8_t *ea) +{ + uint32_t addr0 = (ea[0] << 8) | ea[1]; + uint32_t addr1 = (ea[2] << 24) | (ea[3] << 16) | (ea[4] << 8) | ea[5]; + + WR4(sc, GENET_UMAC_MDF_ADDR0(n), addr0); + WR4(sc, GENET_UMAC_MDF_ADDR1(n), addr1); +} + +void +genet_setup_rxfilter(struct genet_softc *sc) +{ + struct arpcom *ac = &sc->sc_ac; + struct ifnet *ifp = &ac->ac_if; + struct ether_multistep step; + struct ether_multi *enm; + uint32_t cmd, mdf_ctrl; + u_int n; + + cmd = RD4(sc, GENET_UMAC_CMD); + + /* + * Count the required number of hardware filters. We need one + * for each multicast address, plus one for our own address and + * the broadcast address. + */ + ETHER_FIRST_MULTI(step, ac, enm); + for (n = 2; enm != NULL; n++) + ETHER_NEXT_MULTI(step, enm); + + if (n > GENET_MAX_MDF_FILTER || ac->ac_multirangecnt > 0) + ifp->if_flags |= IFF_ALLMULTI; + else + ifp->if_flags &= ~IFF_ALLMULTI; + + if ((ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)) != 0) { + cmd |= GENET_UMAC_CMD_PROMISC; + mdf_ctrl = 0; + } else { + cmd &= ~GENET_UMAC_CMD_PROMISC; + genet_setup_rxfilter_mdf(sc, 0, etherbroadcastaddr); + genet_setup_rxfilter_mdf(sc, 1, LLADDR(ifp->if_sadl)); + ETHER_FIRST_MULTI(step, ac, enm); + for (n = 2; enm != NULL; n++) { + genet_setup_rxfilter_mdf(sc, n, enm->enm_addrlo); + ETHER_NEXT_MULTI(step, enm); + } + mdf_ctrl = __BITS(GENET_MAX_MDF_FILTER - 1, + GENET_MAX_MDF_FILTER - n); + } + + WR4(sc, GENET_UMAC_CMD, cmd); + WR4(sc, GENET_UMAC_MDF_CTRL, mdf_ctrl); +} + +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; +} + +void +genet_init_rings(struct genet_softc *sc, int qid) +{ + uint32_t val; + + /* TX ring */ + + sc->sc_tx.next = 0; + 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), sc->sc_tx.cidx); + WR4(sc, GENET_TX_DMA_PROD_INDEX(qid), sc->sc_tx.pidx); + 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.next = 0; + sc->sc_rx.cidx = 0; + sc->sc_rx.pidx = RX_DESC_COUNT; + + 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), sc->sc_rx.pidx); + WR4(sc, GENET_RX_DMA_CONS_INDEX(qid), sc->sc_rx.cidx); + 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 */ + + if_rxr_init(&sc->sc_rx_ring, 2, RX_DESC_COUNT); + genet_fill_rx_ring(sc, qid); + + /* 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); +} + +int +genet_init(struct genet_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct mii_data *mii = &sc->sc_mii; + uint32_t val; + uint8_t *enaddr = LLADDR(ifp->if_sadl); + + if (ifp->if_flags & IFF_RUNNING) + return 0; + + if (sc->sc_phy_mode == GENET_PHY_MODE_RGMII || + sc->sc_phy_mode == GENET_PHY_MODE_RGMII_ID || + sc->sc_phy_mode == GENET_PHY_MODE_RGMII_RXID || + sc->sc_phy_mode == GENET_PHY_MODE_RGMII_TXID) + WR4(sc, GENET_SYS_PORT_CTRL, + GENET_SYS_PORT_MODE_EXT_GPHY); + + /* Write hardware address */ + val = enaddr[3] | (enaddr[2] << 8) | (enaddr[1] << 16) | + (enaddr[0] << 24); + WR4(sc, GENET_UMAC_MAC0, val); + val = enaddr[5] | (enaddr[4] << 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; + ifq_clr_oactive(&ifp->if_snd); + + mii_mediachg(mii); + timeout_add_sec(&sc->sc_stat_ch, 1); + + return 0; +} + +void +genet_stop(struct genet_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct genet_bufmap *bmap; + uint32_t val; + int i; + + timeout_del(&sc->sc_rxto); + timeout_del(&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; + val &= ~GENET_RX_DMA_CTRL_RBUF_EN(GENET_DMA_DEFAULT_QUEUE); + WR4(sc, GENET_RX_DMA_CTRL, val); + + /* Stop 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); + + /* 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; + ifq_clr_oactive(&ifp->if_snd); + ifp->if_timer = 0; + + intr_barrier(sc->sc_ih); + + /* Clean RX ring. */ + for (i = 0; i < RX_DESC_COUNT; i++) { + bmap = &sc->sc_rx.buf_map[i]; + if (bmap->mbuf) { + bus_dmamap_sync(sc->sc_dmat, bmap->map, 0, + bmap->map->dm_mapsize, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->sc_dmat, bmap->map); + m_freem(bmap->mbuf); + bmap->mbuf = NULL; + } + } + + /* Clean TX ring. */ + for (i = 0; i < TX_DESC_COUNT; i++) { + bmap = &sc->sc_tx.buf_map[i]; + if (bmap->mbuf) { + bus_dmamap_sync(sc->sc_dmat, bmap->map, 0, + bmap->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, bmap->map); + m_freem(bmap->mbuf); + bmap->mbuf = NULL; + } + } +} + +void +genet_rxintr(struct genet_softc *sc, int qid) +{ + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct mbuf_list ml = MBUF_LIST_INITIALIZER(); + struct mbuf *m; + int index, len, n; + uint32_t status, pidx, total; + + pidx = RD4(sc, GENET_RX_DMA_PROD_INDEX(qid)) & 0xffff; + total = (pidx - sc->sc_rx.pidx) & 0xffff; + + DPRINTF("RX pidx=%08x total=%d\n", pidx, total); + + index = sc->sc_rx.next; + 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); + + m = sc->sc_rx.buf_map[index].mbuf; + sc->sc_rx.buf_map[index].mbuf = NULL; + + if (len > ETHER_ALIGN) { + m_adj(m, ETHER_ALIGN); + + m->m_len = m->m_pkthdr.len = len - ETHER_ALIGN; + m->m_nextpkt = NULL; + + ml_enqueue(&ml, m); + } else { + ifp->if_ierrors++; + m_freem(m); + } + + if_rxr_put(&sc->sc_rx_ring, 1); + + index = RX_NEXT(index); + } + + if (sc->sc_rx.pidx != pidx) { + sc->sc_rx.next = index; + sc->sc_rx.pidx = pidx; + + genet_fill_rx_ring(sc, qid); + if_input(ifp, &ml); + } +} + +void +genet_txintr(struct genet_softc *sc, int qid) +{ + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct genet_bufmap *bmap; + uint32_t cidx, total; + int i; + + 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; + } + + if (sc->sc_tx.queued == 0) + ifp->if_timer = 0; + + if (sc->sc_tx.cidx != cidx) { + sc->sc_tx.next = i; + sc->sc_tx.cidx = cidx; + + if (ifq_is_oactive(&ifp->if_snd)) + ifq_restart(&ifp->if_snd); + } +} + +void +genet_start(struct ifnet *ifp) +{ + struct genet_softc *sc = ifp->if_softc; + struct mbuf *m; + const int qid = GENET_DMA_DEFAULT_QUEUE; + int nsegs, index, cnt; + + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + if (ifq_is_oactive(&ifp->if_snd)) + return; + + index = sc->sc_tx.pidx & (TX_DESC_COUNT - 1); + cnt = 0; + + for (;;) { + m = ifq_deq_begin(&ifp->if_snd); + if (m == NULL) + break; + + nsegs = genet_setup_txbuf(sc, index, m); + if (nsegs == -1) { + ifq_deq_rollback(&ifp->if_snd, m); + ifq_set_oactive(&ifp->if_snd); + break; + } + if (nsegs == 0) { + ifq_deq_commit(&ifp->if_snd, m); + m_freem(m); + ifp->if_oerrors++; + continue; + } + ifq_deq_commit(&ifp->if_snd, m); + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_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); + ifp->if_timer = 5; + } +} + +int +genet_intr(void *arg) +{ + struct genet_softc *sc = arg; + struct ifnet *ifp = &sc->sc_ac.ac_if; + uint32_t val; + + 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 (ifq_is_oactive(&ifp->if_snd)) + ifq_restart(&ifp->if_snd); + } + + return 1; +} + +int +genet_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr) +{ + struct genet_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)addr; + int error = 0, s; + + s = splnet(); + + switch (cmd) { + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + /* FALLTHROUGH */ + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + if (ifp->if_flags & IFF_RUNNING) + error = ENETRESET; + else + genet_init(sc); + } else { + if (ifp->if_flags & IFF_RUNNING) + genet_stop(sc); + } + break; + + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd); + break; + + case SIOCGIFRXR: + error = if_rxr_ioctl((struct if_rxrinfo *)ifr->ifr_data, + NULL, MCLBYTES, &sc->sc_rx_ring); + break; + + default: + error = ether_ioctl(ifp, &sc->sc_ac, cmd, addr); + break; + } + + if (error == ENETRESET) { + if (ifp->if_flags & IFF_RUNNING) + genet_setup_rxfilter(sc); + error = 0; + } + + splx(s); + return error; +} + +int +genet_setup_dma(struct genet_softc *sc, int qid) +{ + 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) { + printf("%s: cannot create TX buffer map\n", + sc->sc_dev.dv_xname); + 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) { + printf("%s: cannot create RX buffer map\n", + sc->sc_dev.dv_xname); + return error; + } + } + + return 0; +} + +int +genet_attach(struct genet_softc *sc) +{ + struct mii_data *mii = &sc->sc_mii; + struct ifnet *ifp = &sc->sc_ac.ac_if; + int mii_flags = 0; + + switch (sc->sc_phy_mode) { + case GENET_PHY_MODE_RGMII_ID: + mii_flags |= MIIF_RXID | MIIF_TXID; + break; + case GENET_PHY_MODE_RGMII_RXID: + mii_flags |= MIIF_RXID; + break; + case GENET_PHY_MODE_RGMII_TXID: + mii_flags |= MIIF_TXID; + break; + case GENET_PHY_MODE_RGMII: + default: + break; + } + + printf(": address %s\n", ether_sprintf(sc->sc_lladdr)); + + /* Soft reset EMAC core */ + genet_reset(sc); + + /* Setup DMA descriptors */ + if (genet_setup_dma(sc, GENET_DMA_DEFAULT_QUEUE) != 0) { + printf("%s: failed to setup DMA descriptors\n", + sc->sc_dev.dv_xname); + return EINVAL; + } + + timeout_set(&sc->sc_stat_ch, genet_tick, sc); + timeout_set(&sc->sc_rxto, genet_rxtick, sc); + + /* Setup ethernet interface */ + ifp->if_softc = sc; + snprintf(ifp->if_xname, IFNAMSIZ, "%s", sc->sc_dev.dv_xname); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_start = genet_start; + ifp->if_ioctl = genet_ioctl; + IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); + + /* 802.1Q VLAN-sized frames are supported */ + ifp->if_capabilities = IFCAP_VLAN_MTU; + + /* Attach MII driver */ + ifmedia_init(&mii->mii_media, 0, genet_media_change, genet_media_status); + 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, mii_flags); + + if (LIST_EMPTY(&mii->mii_phys)) { + printf("%s: no PHY found!\n", sc->sc_dev.dv_xname); + ifmedia_add(&mii->mii_media, IFM_ETHER|IFM_MANUAL, 0, NULL); + ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_MANUAL); + } + ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); + + /* Attach interface */ + if_attach(ifp); + + /* Attach ethernet interface */ + ether_ifattach(ifp); + + return 0; +} + +void +genet_lladdr_read(struct genet_softc *sc, uint8_t *lladdr) +{ + uint32_t maclo, machi; + + maclo = RD4(sc, GENET_UMAC_MAC0); + machi = RD4(sc, GENET_UMAC_MAC1); + + lladdr[0] = (maclo >> 24) & 0xff; + lladdr[1] = (maclo >> 16) & 0xff; + lladdr[2] = (maclo >> 8) & 0xff; + lladdr[3] = (maclo >> 0) & 0xff; + lladdr[4] = (machi >> 8) & 0xff; + lladdr[5] = (machi >> 0) & 0xff; +} Index: dev/ic/bcmgenetreg.h =================================================================== RCS file: dev/ic/bcmgenetreg.h diff -N dev/ic/bcmgenetreg.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/ic/bcmgenetreg.h 12 Apr 2020 15:38:43 -0000 @@ -0,0 +1,175 @@ +/* $OpenBSD$ */ +/* $NetBSD: bcmgenetreg.h,v 1.2 2020/02/22 13:41:41 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 __BIT(__n) (1U << (__n)) +#define __BITS(__n, __m) ((__BIT((__n) - (__m) + 1) - 1) << (__m)) + +#define __LOWEST_SET_BIT(__mask) ((((__mask) - 1) & (__mask)) ^ (__mask)) +#define __SHIFTOUT(__x, __mask) (((__x) & (__mask)) / __LOWEST_SET_BIT(__mask)) +#define __SHIFTIN(__x, __mask) ((__x) * __LOWEST_SET_BIT(__mask)) + +#define GENET_SYS_REV_CTRL 0x000 +#define GENET_SYS_REV_MAJOR __BITS(27,24) +#define GENET_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_UMAC_MDF_ADDR0(n) (0xe54 + (n) * 0x8) +#define GENET_UMAC_MDF_ADDR1(n) (0xe58 + (n) * 0x8) + +#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: dev/ic/bcmgenetvar.h =================================================================== RCS file: dev/ic/bcmgenetvar.h diff -N dev/ic/bcmgenetvar.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/ic/bcmgenetvar.h 12 Apr 2020 15:38:43 -0000 @@ -0,0 +1,83 @@ +/* $OpenBSD$ */ +/* $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_ID, + 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 { + struct device 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; + + void *sc_ih; + + struct arpcom sc_ac; +#define sc_lladdr sc_ac.ac_enaddr + struct mii_data sc_mii; + struct timeout sc_stat_ch; + + struct genet_ring sc_tx; + struct genet_ring sc_rx; + struct if_rxring sc_rx_ring; + struct timeout sc_rxto; +}; + +int genet_attach(struct genet_softc *); +int genet_intr(void *); +void genet_lladdr_read(struct genet_softc *, uint8_t *); + +#endif /* !_BCMGENETVAR_H */ Index: dev/mii/brgphy.c =================================================================== RCS file: /cvs/src/sys/dev/mii/brgphy.c,v retrieving revision 1.105 diff -u -p -r1.105 brgphy.c --- dev/mii/brgphy.c 19 Jul 2015 06:28:12 -0000 1.105 +++ dev/mii/brgphy.c 12 Apr 2020 15:38:44 -0000 @@ -92,6 +92,7 @@ void brgphy_crc_bug(struct mii_softc *); void brgphy_disable_early_dac(struct mii_softc *sc); void brgphy_jumbo_settings(struct mii_softc *); void brgphy_eth_wirespeed(struct mii_softc *); +void brgphy_bcm54xx_clock_delay(struct mii_softc *); const struct mii_phy_funcs brgphy_copper_funcs = { brgphy_service, brgphy_copper_status, brgphy_reset, @@ -180,6 +181,8 @@ static const struct mii_phydesc brgphys[ MII_STR_xxBROADCOM3_BCM57765 }, { MII_OUI_xxBROADCOM3, MII_MODEL_xxBROADCOM3_BCM57780, MII_STR_xxBROADCOM3_BCM57780 }, + { MII_OUI_xxBROADCOM4, MII_MODEL_xxBROADCOM4_BCM54210E, + MII_STR_xxBROADCOM4_BCM54210E }, { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5906, MII_STR_BROADCOM2_BCM5906 }, @@ -789,6 +792,12 @@ brgphy_reset(struct mii_softc *sc) break; } break; + case MII_OUI_xxBROADCOM4: + switch (sc->mii_model) { + case MII_MODEL_xxBROADCOM4_BCM54210E: + brgphy_bcm54xx_clock_delay(sc); + break; + } } /* Handle any bge (NetXtreme/NetLink) workarounds. */ @@ -1187,11 +1196,38 @@ brgphy_jumbo_settings(struct mii_softc * void brgphy_eth_wirespeed(struct mii_softc *sc) { - u_int32_t val; + uint16_t val; /* Enable Ethernet@Wirespeed */ - PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007); - val = PHY_READ(sc, BRGPHY_MII_AUXCTL); - PHY_WRITE(sc, BRGPHY_MII_AUXCTL, - (val | (1 << 15) | (1 << 4))); + PHY_WRITE(sc, BRGPHY_MII_AUXCTL, BRGPHY_AUXCTL_SHADOW_MISC | + BRGPHY_AUXCTL_SHADOW_MISC << BRGPHY_AUXCTL_MISC_READ_SHIFT); + val = PHY_READ(sc, BRGPHY_MII_AUXCTL) & BRGPHY_AUXCTL_MISC_DATA_MASK; + val |= BRGPHY_AUXCTL_MISC_WIRESPEED_EN; + PHY_WRITE(sc, BRGPHY_MII_AUXCTL, BRGPHY_AUXCTL_MISC_WRITE_EN | + BRGPHY_AUXCTL_SHADOW_MISC | val); +} + +void +brgphy_bcm54xx_clock_delay(struct mii_softc *sc) +{ + uint16_t val; + + PHY_WRITE(sc, BRGPHY_MII_AUXCTL, BRGPHY_AUXCTL_SHADOW_MISC | + BRGPHY_AUXCTL_SHADOW_MISC << BRGPHY_AUXCTL_MISC_READ_SHIFT); + val = PHY_READ(sc, BRGPHY_MII_AUXCTL) & BRGPHY_AUXCTL_MISC_DATA_MASK; + if (sc->mii_flags & MIIF_RXID) + val |= BRGPHY_AUXCTL_MISC_RGMII_SKEW_EN; + else + val &= ~BRGPHY_AUXCTL_MISC_RGMII_SKEW_EN; + PHY_WRITE(sc, BRGPHY_MII_AUXCTL, BRGPHY_AUXCTL_MISC_WRITE_EN | + BRGPHY_AUXCTL_SHADOW_MISC | val); + + PHY_WRITE(sc, BRGPHY_MII_SHADOW_1C, BRGPHY_SHADOW_1C_CLK_CTRL); + val = PHY_READ(sc, BRGPHY_MII_SHADOW_1C) & BRGPHY_SHADOW_1C_DATA_MASK; + if (sc->mii_flags & MIIF_TXID) + val |= BRGPHY_SHADOW_1C_GTXCLK_EN; + else + val &= ~BRGPHY_SHADOW_1C_GTXCLK_EN; + PHY_WRITE(sc, BRGPHY_MII_SHADOW_1C, BRGPHY_SHADOW_1C_WRITE_EN | + BRGPHY_SHADOW_1C_CLK_CTRL | val); } Index: dev/mii/brgphyreg.h =================================================================== RCS file: /cvs/src/sys/dev/mii/brgphyreg.h,v retrieving revision 1.17 diff -u -p -r1.17 brgphyreg.h --- dev/mii/brgphyreg.h 19 Jul 2015 06:28:12 -0000 1.17 +++ dev/mii/brgphyreg.h 12 Apr 2020 15:38:44 -0000 @@ -195,6 +195,17 @@ /* Begin: PHY register values for the 5706 PHY */ /*******************************************************/ +/* + * Aux control shadow register, bits 0-2 select function (0x00 to + * 0x07). + */ +#define BRGPHY_AUXCTL_SHADOW_MISC 0x07 +#define BRGPHY_AUXCTL_MISC_DATA_MASK 0x7ff8 +#define BRGPHY_AUXCTL_MISC_READ_SHIFT 12 +#define BRGPHY_AUXCTL_MISC_WRITE_EN 0x8000 +#define BRGPHY_AUXCTL_MISC_RGMII_SKEW_EN 0x0200 +#define BRGPHY_AUXCTL_MISC_WIRESPEED_EN 0x0010 + /* * Shadow register 0x1C, bit 15 is write enable, * bits 14-10 select function (0x00 to 0x1F). @@ -202,6 +213,11 @@ #define BRGPHY_MII_SHADOW_1C 0x1C #define BRGPHY_SHADOW_1C_WRITE_EN 0x8000 #define BRGPHY_SHADOW_1C_SELECT_MASK 0x7C00 +#define BRGPHY_SHADOW_1C_DATA_MASK 0x03FF + +/* Shadow 0x1C Clock Alignment Control Register (select value 0x03) */ +#define BRGPHY_SHADOW_1C_CLK_CTRL (0x03 << 10) +#define BRGPHY_SHADOW_1C_GTXCLK_EN 0x0200 /* Shadow 0x1C Mode Control Register (select value 0x1F) */ #define BRGPHY_SHADOW_1C_MODE_CTRL (0x1F << 10) Index: dev/mii/miidevs =================================================================== RCS file: /cvs/src/sys/dev/mii/miidevs,v retrieving revision 1.128 diff -u -p -r1.128 miidevs --- dev/mii/miidevs 24 Sep 2019 14:35:22 -0000 1.128 +++ dev/mii/miidevs 12 Apr 2020 15:38:44 -0000 @@ -96,6 +96,7 @@ oui xxLEVEL1 0x1e0400 Level 1 /* Don't know what's going on here. */ oui xxBROADCOM2 0x0050ef Broadcom oui xxBROADCOM3 0x00d897 Broadcom +oui xxBROADCOM4 0x180361 Broadcom oui xxDAVICOM 0x006040 Davicom /* This is the OUI of the gigE PHY in the Realtek 8169S/8110S chips */ @@ -177,6 +178,7 @@ model BROADCOM BCM5222 0x0032 BCM5222 D model BROADCOM BCM5220 0x0033 BCM5220 10/100 PHY model BROADCOM BCM4401 0x0036 BCM4401 10/100baseTX PHY model BROADCOM2 BCM5906 0x0004 BCM5906 10/100baseTX PHY +model xxBROADCOM4 BCM54210E 0x000a BCM54210E 10/100/1000baseT PHY /* Cicada PHYs (now owned by Vitesse) */ model xxCICADA CS8201B 0x0021 CS8201 10/100/1000TX PHY Index: dev/mii/miidevs.h =================================================================== RCS file: /cvs/src/sys/dev/mii/miidevs.h,v retrieving revision 1.131 diff -u -p -r1.131 miidevs.h --- dev/mii/miidevs.h 24 Sep 2019 14:36:00 -0000 1.131 +++ dev/mii/miidevs.h 12 Apr 2020 15:38:44 -0000 @@ -1,4 +1,4 @@ -/* $OpenBSD: miidevs.h,v 1.131 2019/09/24 14:36:00 visa Exp $ */ +/* $OpenBSD$ */ /* * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT. @@ -103,6 +103,7 @@ /* Don't know what's going on here. */ #define MII_OUI_xxBROADCOM2 0x0050ef /* Broadcom */ #define MII_OUI_xxBROADCOM3 0x00d897 /* Broadcom */ +#define MII_OUI_xxBROADCOM4 0x180361 /* Broadcom */ #define MII_OUI_xxDAVICOM 0x006040 /* Davicom */ /* This is the OUI of the gigE PHY in the Realtek 8169S/8110S chips */ @@ -242,6 +243,8 @@ #define MII_STR_BROADCOM_BCM4401 "BCM4401 10/100baseTX PHY" #define MII_MODEL_BROADCOM2_BCM5906 0x0004 #define MII_STR_BROADCOM2_BCM5906 "BCM5906 10/100baseTX PHY" +#define MII_MODEL_xxBROADCOM4_BCM54210E 0x000a +#define MII_STR_xxBROADCOM4_BCM54210E "BCM54210E 10/100/1000baseT PHY" /* Cicada PHYs (now owned by Vitesse) */ #define MII_MODEL_xxCICADA_CS8201B 0x0021 Index: dev/mii/miivar.h =================================================================== RCS file: /cvs/src/sys/dev/mii/miivar.h,v retrieving revision 1.34 diff -u -p -r1.34 miivar.h --- dev/mii/miivar.h 12 Sep 2015 09:49:20 -0000 1.34 +++ dev/mii/miivar.h 12 Apr 2020 15:38:44 -0000 @@ -152,6 +152,8 @@ typedef struct mii_softc mii_softc_t; #define MIIF_DOPAUSE 0x0100 /* advertise PAUSE capability */ #define MIIF_IS_HPNA 0x0200 /* is a HomePNA device */ #define MIIF_FORCEANEG 0x0400 /* force autonegotiation */ +#define MIIF_RXID 0x0800 /* add Rx delay */ +#define MIIF_TXID 0x1000 /* add Tx delay */ #define MIIF_INHERIT_MASK (MIIF_NOISOLATE|MIIF_NOLOOP|MIIF_AUTOTSLEEP)