Page MenuHomeFreeBSD

D59191.diff
No OneTemporary

D59191.diff

diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1633,6 +1633,8 @@
dev/dwc/if_dwc_if.m optional dwc fdt
dev/dwc/dwc1000_core.c optional dwc fdt
dev/dwc/dwc1000_dma.c optional dwc fdt
+dev/dwc/dwc4_core.c optional dwc fdt
+dev/dwc/dwc4_dma.c optional dwc fdt
dev/efidev/efidev.c optional efirt efidev
dev/efidev/efirt.c optional efirt
dev/efidev/efirtc.c optional efirt efirtc
diff --git a/sys/dev/dwc/dwc1000_dma.h b/sys/dev/dwc/dwc1000_dma.h
--- a/sys/dev/dwc/dwc1000_dma.h
+++ b/sys/dev/dwc/dwc1000_dma.h
@@ -30,18 +30,6 @@
#ifndef __DWC1000_DMA_H__
#define __DWC1000_DMA_H__
-/*
- * A hardware buffer descriptor. Rx and Tx buffers have the same descriptor
- * layout, but the bits in the fields have different meanings.
- */
-struct dwc_hwdesc
-{
- uint32_t desc0;
- uint32_t desc1;
- uint32_t addr1; /* ptr to first buffer data */
- uint32_t addr2; /* ptr to next descriptor / second buffer data*/
-};
-
int dma1000_init(struct dwc_softc *sc);
void dma1000_free(struct dwc_softc *sc);
void dma1000_start(struct dwc_softc *sc);
diff --git a/sys/dev/dwc/dwc1000_dma.c b/sys/dev/dwc/dwc1000_dma.c
--- a/sys/dev/dwc/dwc1000_dma.c
+++ b/sys/dev/dwc/dwc1000_dma.c
@@ -151,6 +151,21 @@
#define ERDESC1_RBS1_MASK 0x7ffff
#define ERDESC1_RBS1_SHIFT 0 /* Receive Buffer 1 Size */
+/*
+ * A hardware buffer descriptor. Rx and Tx buffers have the same descriptor
+ * layout, but the bits in the fields have different meanings.
+ */
+struct dwc_hwdesc
+{
+ uint32_t desc0;
+ uint32_t desc1;
+ uint32_t addr1; /* ptr to first buffer data */
+ uint32_t addr2; /* ptr to next descriptor / second buffer data*/
+};
+
+#define RX_DESC_SIZE (sizeof(struct dwc_hwdesc) * RX_DESC_COUNT)
+#define TX_DESC_SIZE (sizeof(struct dwc_hwdesc) * TX_DESC_COUNT)
+
/*
* The hardware imposes alignment restrictions on various objects involved in
* DMA transfers. These values are expressed in bytes (not bits).
diff --git a/sys/dev/dwc/dwc4_core.c b/sys/dev/dwc/dwc4_core.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/dwc/dwc4_core.c
@@ -0,0 +1,432 @@
+/*-
+ * Copyright (c) 2026 Ruslan Bukin <br@bsdpad.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <machine/bus.h>
+
+#include <dev/clk/clk.h>
+#include <dev/hwreset/hwreset.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/mii/mii_fdt.h>
+
+#include <dev/dwc/if_dwcvar.h>
+#include <dev/dwc/dwc4_reg.h>
+#include <dev/dwc/dwc4_dma.h>
+
+#include "if_dwc_if.h"
+
+struct dwc_hash_maddr_ctx {
+ struct dwc_softc *sc;
+ uint32_t hash[8];
+};
+
+#define STATS_HARVEST_INTERVAL 2
+
+/* Pause time field in the transmitted control frame */
+static int dwc_pause_time = 0xffff;
+TUNABLE_INT("hw.dwc.pause_time", &dwc_pause_time);
+
+/*
+ * MIIBUS functions
+ */
+
+int
+dwc4_miibus_read_reg(device_t dev, int phy, int reg)
+{
+ struct dwc_softc *sc;
+ uint32_t mii;
+ size_t cnt;
+ int rv = 0;
+
+ sc = device_get_softc(dev);
+
+ mii = ((phy << MACMDIOAR_PA_S) & MACMDIOAR_PA_M)
+ | ((reg << MACMDIOAR_RDA_S) & MACMDIOAR_RDA_M)
+ | (sc->mii_clk << MACMDIOAR_CR_S)
+ | MACMDIOAR_READ
+ | MACMDIOAR_GB; /* Busy flag */
+
+ WRITE4(sc, ETH_MACMDIOAR, mii);
+
+ for (cnt = 0; cnt < 1000; cnt++) {
+ if (!(READ4(sc, ETH_MACMDIOAR) & MACMDIOAR_GB)) {
+ rv = READ4(sc, ETH_MACMDIODR);
+ break;
+ }
+ DELAY(10);
+ }
+
+ return rv;
+}
+
+int
+dwc4_miibus_write_reg(device_t dev, int phy, int reg, int val)
+{
+ struct dwc_softc *sc;
+ uint32_t mii;
+ size_t cnt;
+
+ sc = device_get_softc(dev);
+
+ mii = ((phy << MACMDIOAR_PA_S) & MACMDIOAR_PA_M)
+ | ((reg << MACMDIOAR_RDA_S) & MACMDIOAR_RDA_M)
+ | (sc->mii_clk << MACMDIOAR_CR_S)
+ | MACMDIOAR_WRITE
+ | MACMDIOAR_GB; /* Busy flag */
+
+ WRITE4(sc, ETH_MACMDIODR, val);
+ WRITE4(sc, ETH_MACMDIOAR, mii);
+
+ for (cnt = 0; cnt < 1000; cnt++) {
+ if (!(READ4(sc, ETH_MACMDIOAR) & MACMDIOAR_GB)) {
+ break;
+ }
+ DELAY(10);
+ }
+
+ return (0);
+}
+
+void
+dwc4_miibus_statchg(device_t dev)
+{
+ struct dwc_softc *sc;
+ struct mii_data *mii;
+ uint32_t reg;
+
+ /*
+ * Called by the MII bus driver when the PHY establishes
+ * link to set the MAC interface registers.
+ */
+
+ sc = device_get_softc(dev);
+
+ DWC_ASSERT_LOCKED(sc);
+
+ mii = sc->mii_softc;
+
+ if (mii->mii_media_status & IFM_ACTIVE)
+ sc->link_is_up = true;
+ else
+ sc->link_is_up = false;
+
+ reg = READ4(sc, ETH_MACCR);
+ switch (IFM_SUBTYPE(mii->mii_media_active)) {
+ case IFM_1000_T:
+ case IFM_1000_SX:
+ reg &= ~(MACCR_FES | MACCR_PS);
+ break;
+ case IFM_100_TX:
+ reg |= (MACCR_FES | MACCR_PS);
+ break;
+ case IFM_10_T:
+ reg &= ~(MACCR_FES);
+ reg |= (MACCR_PS);
+ break;
+ case IFM_NONE:
+ sc->link_is_up = false;
+ return;
+ default:
+ sc->link_is_up = false;
+ device_printf(dev, "Unsupported media %u\n",
+ IFM_SUBTYPE(mii->mii_media_active));
+ return;
+ }
+ if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
+ reg |= (MACCR_DM);
+ else
+ reg &= ~(MACCR_DM);
+ WRITE4(sc, ETH_MACCR, reg);
+
+ IF_DWC_SET_SPEED(dev, IFM_SUBTYPE(mii->mii_media_active));
+
+}
+
+void
+dwc4_core_setup(struct dwc_softc *sc)
+{
+ uint32_t reg;
+
+ DWC_ASSERT_LOCKED(sc);
+
+ reg = READ4(sc, ETH_MACVR);
+ device_printf(sc->dev, "MAC Version: %x\n", reg);
+
+ /* Enable core */
+ reg = READ4(sc, ETH_MACCR);
+ reg |= (MACCR_JD | MACCR_ACS | MACCR_BE);
+ WRITE4(sc, ETH_MACCR, reg);
+}
+
+void
+dwc4_enable_mac(struct dwc_softc *sc, bool enable)
+{
+ uint32_t reg;
+
+ DWC_ASSERT_LOCKED(sc);
+
+ reg = READ4(sc, ETH_MACCR);
+ if (enable)
+ reg |= MACCR_TE | MACCR_RE;
+ else
+ reg &= ~(MACCR_TE | MACCR_RE);
+ WRITE4(sc, ETH_MACCR, reg);
+}
+
+void
+dwc4_enable_csum_offload(struct dwc_softc *sc)
+{
+ uint32_t reg;
+
+ DWC_ASSERT_LOCKED(sc);
+ reg = READ4(sc, ETH_MACCR);
+ if ((if_getcapenable(sc->ifp) & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) !=
+ 0)
+ reg |= MACCR_IPC;
+ else
+ reg &= ~MACCR_IPC;
+ WRITE4(sc, ETH_MACCR, reg);
+}
+
+static const uint8_t nibbletab[] = {
+ /* 0x0 0000 -> 0000 */ 0x0,
+ /* 0x1 0001 -> 1000 */ 0x8,
+ /* 0x2 0010 -> 0100 */ 0x4,
+ /* 0x3 0011 -> 1100 */ 0xc,
+ /* 0x4 0100 -> 0010 */ 0x2,
+ /* 0x5 0101 -> 1010 */ 0xa,
+ /* 0x6 0110 -> 0110 */ 0x6,
+ /* 0x7 0111 -> 1110 */ 0xe,
+ /* 0x8 1000 -> 0001 */ 0x1,
+ /* 0x9 1001 -> 1001 */ 0x9,
+ /* 0xa 1010 -> 0101 */ 0x5,
+ /* 0xb 1011 -> 1101 */ 0xd,
+ /* 0xc 1100 -> 0011 */ 0x3,
+ /* 0xd 1101 -> 1011 */ 0xb,
+ /* 0xe 1110 -> 0111 */ 0x7,
+ /* 0xf 1111 -> 1111 */ 0xf, };
+
+static uint8_t
+bitreverse(uint8_t x)
+{
+
+ return (nibbletab[x & 0xf] << 4) | nibbletab[x >> 4];
+}
+
+static u_int
+dwc_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
+{
+ struct dwc_hash_maddr_ctx *ctx = arg;
+ uint32_t crc, hashbit, hashreg;
+ uint8_t val;
+
+ crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN);
+ /* Take lower 8 bits and reverse it */
+ val = bitreverse(~crc & 0xff);
+ /*
+ * TODO: There is probably a HW_FEATURES bit which isn't
+ * related to the extended descriptors that describe this
+ */
+ if (!ctx->sc->dma_ext_desc)
+ val >>= 2; /* Only need lower 6 bits */
+ hashreg = (val >> 5);
+ hashbit = (val & 31);
+ ctx->hash[hashreg] |= (1 << hashbit);
+
+ return (1);
+}
+
+void
+dwc4_setup_rxfilter(struct dwc_softc *sc)
+{
+ struct dwc_hash_maddr_ctx ctx;
+ if_t ifp;
+ uint8_t *eaddr;
+ uint32_t ffval, hi, lo;
+ int nhash, i;
+
+ DWC_ASSERT_LOCKED(sc);
+
+ ifp = sc->ifp;
+ /*
+ * TODO: There is probably a HW_FEATURES bit which isn't
+ * related to the extended descriptors that describe this
+ */
+ nhash = sc->dma_ext_desc == false ? 2 : 8;
+
+ /*
+ * Set the multicast (group) filter hash.
+ */
+ if ((if_getflags(ifp) & IFF_ALLMULTI) != 0) {
+ ffval = (MACPFR_PM);
+ for (i = 0; i < nhash; i++)
+ ctx.hash[i] = ~0;
+ } else {
+ ffval = (MACPFR_HMC);
+ for (i = 0; i < nhash; i++)
+ ctx.hash[i] = 0;
+ ctx.sc = sc;
+ if_foreach_llmaddr(ifp, dwc_hash_maddr, &ctx);
+ }
+
+ /*
+ * Set the individual address filter hash.
+ */
+ if ((if_getflags(ifp) & IFF_PROMISC) != 0)
+ ffval |= MACPFR_PR;
+
+ /*
+ * Set the primary address.
+ */
+ eaddr = if_getlladdr(ifp);
+ lo = eaddr[0] | (eaddr[1] << 8) | (eaddr[2] << 16) |
+ (eaddr[3] << 24);
+ hi = eaddr[4] | (eaddr[5] << 8);
+ WRITE4(sc, ETH_MACA0LR, lo);
+ WRITE4(sc, ETH_MACA0HR, hi);
+
+ WRITE4(sc, ETH_MACPFR, ffval);
+ if (!sc->dma_ext_desc) {
+ WRITE4(sc, ETH_MACHT0R, ctx.hash[0]);
+ WRITE4(sc, ETH_MACHT1R, ctx.hash[1]);
+ } else
+ panic("implement me: ext_desc");
+}
+
+void
+dwc4_get_hwaddr(struct dwc_softc *sc, uint8_t *hwaddr)
+{
+ uint32_t hi, lo, rnd;
+
+ /*
+ * Try to recover a MAC address from the running hardware. If there's
+ * something non-zero there, assume the bootloader did the right thing
+ * and just use it.
+ *
+ * Otherwise, set the address to a convenient locally assigned address,
+ * 'bsd' + random 24 low-order bits. 'b' is 0x62, which has the locally
+ * assigned bit set, and the broadcast/multicast bit clear.
+ */
+ lo = READ4(sc, ETH_MACA0LR);
+ hi = READ4(sc, ETH_MACA0HR) & 0xffff;
+ if ((lo != 0xffffffff) || (hi != 0xffff)) {
+ hwaddr[0] = (lo >> 0) & 0xff;
+ hwaddr[1] = (lo >> 8) & 0xff;
+ hwaddr[2] = (lo >> 16) & 0xff;
+ hwaddr[3] = (lo >> 24) & 0xff;
+ hwaddr[4] = (hi >> 0) & 0xff;
+ hwaddr[5] = (hi >> 8) & 0xff;
+ } else {
+ rnd = arc4random() & 0x00ffffff;
+ hwaddr[0] = 'b';
+ hwaddr[1] = 's';
+ hwaddr[2] = 'd';
+ hwaddr[3] = rnd >> 16;
+ hwaddr[4] = rnd >> 8;
+ hwaddr[5] = rnd >> 0;
+ }
+}
+
+/*
+ * Stats
+ */
+
+static void
+dwc4_clear_stats(struct dwc_softc *sc)
+{
+ uint32_t reg;
+
+ reg = READ4(sc, ETH_MMC_CONTROL);
+ reg |= MMC_CONTROL_CNTRST;
+ WRITE4(sc, ETH_MMC_CONTROL, reg);
+}
+
+void
+dwc4_harvest_stats(struct dwc_softc *sc)
+{
+ if_t ifp __unused;
+ int val;
+
+ /* We don't need to harvest too often. */
+ if (++sc->stats_harvest_count < STATS_HARVEST_INTERVAL)
+ return;
+
+ sc->stats_harvest_count = 0;
+ ifp = sc->ifp;
+
+ val = READ4(sc, ETH_RX_RECEIVE_ERROR);
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, val);
+
+ val = READ4(sc, ETH_TX_PACKET_COUNT_GOOD_BAD);
+ val -= READ4(sc, ETH_TX_PACKET_COUNT_GOOD);
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, val);
+
+ val = READ4(sc, ETH_TX_SINGLE_COLLISION_GOOD_PACKETS);
+ val += READ4(sc, ETH_TX_MULTIPLE_COLLISION_GOOD_PACKETS);
+ val += READ4(sc, ETH_TX_LATE_COLLISION_PACKETS);
+ val += READ4(sc, ETH_TX_EXCESSIVE_COLLISION_PACKETS);
+ if_inc_counter(ifp, IFCOUNTER_COLLISIONS, val);
+
+ dwc4_clear_stats(sc);
+}
+
+void
+dwc4_intr(struct dwc_softc *sc)
+{
+ uint32_t reg;
+
+ DWC_ASSERT_LOCKED(sc);
+
+ reg = READ4(sc, ETH_MACISR);
+ if (reg)
+ READ4(sc, ETH_MACPHYCSR);
+}
+
+void
+dwc4_intr_disable(struct dwc_softc *sc)
+{
+
+ WRITE4(sc, ETH_MACIER, 0);
+}
diff --git a/sys/dev/dwc/dwc4_dma.h b/sys/dev/dwc/dwc4_dma.h
new file mode 100644
--- /dev/null
+++ b/sys/dev/dwc/dwc4_dma.h
@@ -0,0 +1,111 @@
+/*-
+ * Copyright (c) 2026 Ruslan Bukin <br@bsdpad.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _DEV_DWC_DWC4_DMA_H_
+#define _DEV_DWC_DWC4_DMA_H_
+
+#define ETH_DMAMR 0x1000
+#define DMAMR_SWR (1 << 0) /* Software Reset */
+#define ETH_DMASBMR 0x1004
+#define DMASBMR_RD_OSR_LMT_S 16 /* AXI Maximum Read Outstanding Req Limit */
+#define DMASBMR_AAL (1 << 12) /* Address-Aligned Beats */
+#define DMASBMR_EAME (1 << 11) /* Enhanced Address Mode Enable */
+#define DMASBMR_BLEN16 (1 << 3) /* Fixed Burst Length */
+#define DMASBMR_BLEN8 (1 << 2) /* Fixed Burst Length */
+#define DMASBMR_BLEN4 (1 << 1) /* Fixed Burst Length */
+#define DMASBMR_FB (1 << 0) /* Fixed Burst Length */
+#define ETH_DMAISR 0x1008
+#define ETH_DMADS1R 0x100C
+#define ETH_DMADS2R 0x1010
+#define ETH_DMAA4TXACR 0x1020
+#define ETH_DMAA4RXACR 0x1024
+#define ETH_DMAA4DACR 0x1028
+#define ETH_DMALPIEI 0x1040
+#define ETH_DMATBSCTRLR(x) (0x1050 + 0x04 * (x))
+
+/* DMA Channel */
+#define ETH_DMACCR(x) (0x1100 + 0x80 * (x))
+#define DMACCR_PBLX8 (1 << 16) /* 8xPBL mode */
+#define DMACCR_DSL_S 18
+#define ETH_DMACTXCR(x) (0x1104 + 0x80 * (x))
+#define DMACTXCR_EDSE (1 << 28) /* Enhanced Descriptor Enable */
+#define DMACTXCR_TXPBL_S 16 /* Transmit Programmable Burst Length */
+#define DMACTXCR_TXPBL_M (0x3f << DMACTXCR_TXPBL_S)
+#define DMACTXCR_OSF (1 << 4) /* Operate on Second Packet */
+#define DMACTXCR_ST (1 << 0) /* Start or Stop Transmission Command */
+#define ETH_DMACRXCR(x) (0x1108 + 0x80 * (x))
+#define DMACRXCR_RXPBL_S 16 /* Receive Programmable Burst Length */
+#define DMACRXCR_RXPBL_M (0x3f << DMACRXCR_RXPBL_S)
+#define DMACRXCR_RBSZ_S 1 /* Receive Buffer size */
+#define DMACRXCR_RBSZ_M (0x3fff << DMACRXCR_RBSZ_S)
+#define DMACRXCR_SR (1 << 0) /* Start or Stop Receive */
+#define ETH_DMACTXDLAR_HI(x) (0x1110 + 0x80 * (x))
+#define ETH_DMACTXDLAR(x) (0x1114 + 0x80 * (x))
+#define ETH_DMACRXDLAR_HI(x) (0x1118 + 0x80 * (x))
+#define ETH_DMACRXDLAR(x) (0x111C + 0x80 * (x))
+#define ETH_DMACTXDTPR(x) (0x1120 + 0x80 * (x))
+#define ETH_DMACRXDTPR(x) (0x1128 + 0x80 * (x))
+#define ETH_DMACTXRLR(x) (0x112C + 0x80 * (x))
+#define ETH_DMACRXRLR(x) (0x1130 + 0x80 * (x))
+#define ETH_DMACIER(x) (0x1134 + 0x80 * (x))
+#define DMACIER_TIE (1 << 0) /* Transmit Interrupt Enable */
+#define DMACIER_TXSE (1 << 1) /* Transmit Stopped Enable */
+#define DMACIER_TBUE (1 << 2) /* Transmit Buffer Unavailable Enable */
+#define DMACIER_RIE (1 << 6) /* Receive Interrupt Enable */
+#define DMACIER_RBUE (1 << 7) /* Receive Buffer Unavailable Enable */
+#define DMACIER_RSE (1 << 8) /* Receive Stopped Enable */
+#define DMACIER_RWTE (1 << 9) /* Receive Watchdog Timeout Enable */
+#define DMACIER_ETIE (1 << 10) /* Early Transmit Interrupt Enable */
+#define DMACIER_ERIE (1 << 11) /* Early Receive Interrupt Enable */
+#define DMACIER_FBEE (1 << 12) /* Fatal Bus Error Enable */
+#define DMACIER_CDEE (1 << 13) /* Context Descriptor Error Enable */
+#define DMACIER_AIE (1 << 14) /* Abnormal Interrupt Summary Enable */
+#define DMACIER_NIE (1 << 15) /* Normal Interrupt Summary Enable */
+#define ETH_DMACRXIWTR(x) (0x1138 + 0x80 * (x))
+#define ETH_DMACSFCSR(x) (0x113C + 0x80 * (x))
+#define ETH_DMACCATXDR(x) (0x1144 + 0x80 * (x))
+#define ETH_DMACCARXDR(x) (0x114C + 0x80 * (x))
+#define ETH_DMACCATXBR(x) (0x1154 + 0x80 * (x))
+#define ETH_DMACCARXBR(x) (0x115C + 0x80 * (x))
+#define ETH_DMACSR(x) (0x1160 + 0x80 * (x))
+#define DMACSR_NIS (1 << 15) /* Normal Interrupt Summary */
+#define DMACSR_AIS (1 << 14) /* AIS: Abnormal Interrupt Summary */
+#define DMACSR_FBE (1 << 12) /* Fatal Bus Error */
+#define DMACSR_RI (1 << 6) /* Receive Interrupt */
+#define DMACSR_TI (1 << 0) /* Transmit Interrupt */
+#define ETH_DMACMFCR(x) (0x1164 + 0x80 * (x))
+
+int dma4_init(struct dwc_softc *sc);
+void dma4_free(struct dwc_softc *sc);
+void dma4_start(struct dwc_softc *sc);
+void dma4_stop(struct dwc_softc *sc);
+int dma4_reset(struct dwc_softc *sc);
+int dma4_setup_txbuf(struct dwc_softc *sc, int idx, struct mbuf **mp);
+void dma4_txfinish_locked(struct dwc_softc *sc);
+void dma4_rxfinish_locked(struct dwc_softc *sc);
+void dma4_txstart(struct dwc_softc *sc);
+int dma4_intr(struct dwc_softc *sc);
+
+#endif /* !_DEV_DWC_DWC4_DMA_H_ */
diff --git a/sys/dev/dwc/dwc1000_dma.c b/sys/dev/dwc/dwc4_dma.c
copy from sys/dev/dwc/dwc1000_dma.c
copy to sys/dev/dwc/dwc4_dma.c
--- a/sys/dev/dwc/dwc1000_dma.c
+++ b/sys/dev/dwc/dwc4_dma.c
@@ -1,9 +1,5 @@
/*-
- * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
- *
- * This software was developed by SRI International and the University of
- * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
- * ("CTSRD"), as part of the DARPA CRASH research programme.
+ * Copyright (c) 2026 Ruslan Bukin <br@bsdpad.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -56,100 +52,81 @@
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/dwc/if_dwcvar.h>
-#include <dev/dwc/dwc1000_reg.h>
-#include <dev/dwc/dwc1000_dma.h>
+#include <dev/dwc/dwc4_reg.h>
+#include <dev/dwc/dwc4_dma.h>
+#include <dev/dwc/dwc4_mtl.h>
#define WATCHDOG_TIMEOUT_SECS 5
#define DMA_RESET_TIMEOUT 100
-/* TX descriptors - TDESC0 is almost unified */
-#define TDESC0_OWN (1U << 31)
-#define TDESC0_IHE (1U << 16) /* IP Header Error */
-#define TDESC0_ES (1U << 15) /* Error Summary */
-#define TDESC0_JT (1U << 14) /* Jabber Timeout */
-#define TDESC0_FF (1U << 13) /* Frame Flushed */
-#define TDESC0_PCE (1U << 12) /* Payload Checksum Error */
-#define TDESC0_LOC (1U << 11) /* Loss of Carrier */
-#define TDESC0_NC (1U << 10) /* No Carrier */
-#define TDESC0_LC (1U << 9) /* Late Collision */
-#define TDESC0_EC (1U << 8) /* Excessive Collision */
-#define TDESC0_VF (1U << 7) /* VLAN Frame */
-#define TDESC0_CC_MASK 0xf
-#define TDESC0_CC_SHIFT 3 /* Collision Count */
-#define TDESC0_ED (1U << 2) /* Excessive Deferral */
-#define TDESC0_UF (1U << 1) /* Underflow Error */
-#define TDESC0_DB (1U << 0) /* Deferred Bit */
-/* TX descriptors - TDESC0 extended format only */
-#define ETDESC0_IC (1U << 30) /* Interrupt on Completion */
-#define ETDESC0_LS (1U << 29) /* Last Segment */
-#define ETDESC0_FS (1U << 28) /* First Segment */
-#define ETDESC0_DC (1U << 27) /* Disable CRC */
-#define ETDESC0_DP (1U << 26) /* Disable Padding */
-#define ETDESC0_CIC_NONE (0U << 22) /* Checksum Insertion Control */
-#define ETDESC0_CIC_HDR (1U << 22)
-#define ETDESC0_CIC_SEG (2U << 22)
-#define ETDESC0_CIC_FULL (3U << 22)
-#define ETDESC0_TER (1U << 21) /* Transmit End of Ring */
-#define ETDESC0_TCH (1U << 20) /* Second Address Chained */
-
-/* TX descriptors - TDESC1 normal format */
-#define NTDESC1_IC (1U << 31) /* Interrupt on Completion */
-#define NTDESC1_LS (1U << 30) /* Last Segment */
-#define NTDESC1_FS (1U << 29) /* First Segment */
-#define NTDESC1_CIC_NONE (0U << 27) /* Checksum Insertion Control */
-#define NTDESC1_CIC_HDR (1U << 27)
-#define NTDESC1_CIC_SEG (2U << 27)
-#define NTDESC1_CIC_FULL (3U << 27)
-#define NTDESC1_DC (1U << 26) /* Disable CRC */
-#define NTDESC1_TER (1U << 25) /* Transmit End of Ring */
-#define NTDESC1_TCH (1U << 24) /* Second Address Chained */
-/* TX descriptors - TDESC1 extended format */
-#define ETDESC1_DP (1U << 23) /* Disable Padding */
-#define ETDESC1_TBS2_MASK 0x7ff
-#define ETDESC1_TBS2_SHIFT 11 /* Receive Buffer 2 Size */
-#define ETDESC1_TBS1_MASK 0x7ff
-#define ETDESC1_TBS1_SHIFT 0 /* Receive Buffer 1 Size */
-
-/* RX descriptor - RDESC0 is unified */
-#define RDESC0_OWN (1U << 31)
-#define RDESC0_AFM (1U << 30) /* Dest. Address Filter Fail */
-#define RDESC0_FL_MASK 0x3fff
-#define RDESC0_FL_SHIFT 16 /* Frame Length */
-#define RDESC0_ES (1U << 15) /* Error Summary */
-#define RDESC0_DE (1U << 14) /* Descriptor Error */
-#define RDESC0_SAF (1U << 13) /* Source Address Filter Fail */
-#define RDESC0_LE (1U << 12) /* Length Error */
-#define RDESC0_OE (1U << 11) /* Overflow Error */
-#define RDESC0_VLAN (1U << 10) /* VLAN Tag */
-#define RDESC0_FS (1U << 9) /* First Descriptor */
-#define RDESC0_LS (1U << 8) /* Last Descriptor */
-#define RDESC0_ICE (1U << 7) /* IPC Checksum Error */
-#define RDESC0_LC (1U << 6) /* Late Collision */
-#define RDESC0_FT (1U << 5) /* Frame Type */
-#define RDESC0_RWT (1U << 4) /* Receive Watchdog Timeout */
-#define RDESC0_RE (1U << 3) /* Receive Error */
-#define RDESC0_DBE (1U << 2) /* Dribble Bit Error */
-#define RDESC0_CE (1U << 1) /* CRC Error */
-#define RDESC0_PCE (1U << 0) /* Payload Checksum Error */
-#define RDESC0_RXMA (1U << 0) /* Rx MAC Address */
-
-/* RX descriptors - RDESC1 normal format */
-#define NRDESC1_DIC (1U << 31) /* Disable Intr on Completion */
-#define NRDESC1_RER (1U << 25) /* Receive End of Ring */
-#define NRDESC1_RCH (1U << 24) /* Second Address Chained */
-#define NRDESC1_RBS2_MASK 0x7ff
-#define NRDESC1_RBS2_SHIFT 11 /* Receive Buffer 2 Size */
-#define NRDESC1_RBS1_MASK 0x7ff
-#define NRDESC1_RBS1_SHIFT 0 /* Receive Buffer 1 Size */
-
-/* RX descriptors - RDESC1 enhanced format */
-#define ERDESC1_DIC (1U << 31) /* Disable Intr on Completion */
-#define ERDESC1_RBS2_MASK 0x7ffff
-#define ERDESC1_RBS2_SHIFT 16 /* Receive Buffer 2 Size */
-#define ERDESC1_RER (1U << 15) /* Receive End of Ring */
-#define ERDESC1_RCH (1U << 14) /* Second Address Chained */
-#define ERDESC1_RBS1_MASK 0x7ffff
-#define ERDESC1_RBS1_SHIFT 0 /* Receive Buffer 1 Size */
+/* RDES1 Write-back format */
+#define RDES1_IPCE (1 << 7) /* IP Payload Error;
+ * 16-bit IP payload checksum mismatch.
+ */
+#define RDES1_IPCB (1 << 6) /* Checksum offload engine is bypassed. */
+#define RDES1_IPHE (1 << 3) /*
+ * IP Header Error;
+ * 16-bit IP header checksum mismatch.
+ */
+/* RX Read format */
+#define RDES3_OWN (1 << 31) /* DMA owns the descriptor */
+#define RDES3_IOC (1 << 30) /* Interrupt Enabled on Completion */
+#define RDES3_BUF2V (1 << 25) /* Buffer 2 Address Valid */
+#define RDES3_BUF1V (1 << 24) /* Buffer 1 Address Valid */
+
+/* RX Write-back format */
+#define RDES3_FD (1 << 29) /* First Descriptor */
+#define RDES3_LD (1 << 28) /* Last Descriptor */
+#define RDES3_RE (1 << 20) /* Receive Error */
+#define RDES3_PL_S 0 /* Packet Length */
+#define RDES3_PL_M (0x7fff << RDES3_PL_S)
+#define RDES3_CE (1 << 24) /* CRC Error */
+#define RDES3_LT_S 16 /* Length/Type Field */
+#define RDES3_LT_M (0x3 << RDES3_LT_S)
+
+/* TX Read format */
+#define TDES2_IOC (1 << 31) /* Interrupt on completion */
+#define TDES2_TTSE (1 << 30) /* Transmit Timestamp Enable */
+#define TDES2_B2L_S 16 /* Buffer 2 Length */
+#define TDES2_B2L_M (0x3fff << TDES2_B2L_S)
+#define TDES2_VTIR_S 14 /* VLAN Tag Insertion or Replacement */
+#define TDES2_VTIR_M (0x3 << TDES2_VTIR_S)
+
+#define TDES3_OWN (1 << 31) /* the DMA owns the descriptor */
+#define TDES3_CTXT (1 << 30) /* Context Type */
+#define TDES3_FD (1 << 29) /* First Descriptor */
+#define TDES3_LD (1 << 28) /* Last Descriptor */
+#define TDES3_CPC_S 26
+#define TDES3_CPC_M (0x3 << TDES3_CPC_S)
+#define TDES3_CPC_CRC_PAD (0x0 << TDES3_CPC_S)
+#define TDES3_CPC_CRC (0x1 << TDES3_CPC_S)
+#define TDES3_CPC_CRC_DISABLE (0x2 << TDES3_CPC_S)
+#define TDES3_CPC_CRC_REPLACE (0x3 << TDES3_CPC_S)
+#define TDES3_SAIC_S 23
+#define TDES3_SAIC_M (0x7 << TDES3_SAIC_S)
+#define TDES3_TSE 18 /* TCP Segmentation Enable */
+#define TDES3_CIC_S 16
+#define TDES3_CIC_M (0x3 << TDES3_CIC_S)
+#define TDES3_CIC_HDR (0x1 << TDES3_CIC_S) /* Only IP header csum inserted */
+#define TDES3_CIC_FULL (0x2 << TDES3_CIC_S) /* IP header & payload */
+#define TDES3_CIC_FULLP (0x3 << TDES3_CIC_S) /* IP header, payload, pseudo-hdr*/
+#define TDES3_TPL_S 0 /* TCP Payload Length */
+#define TDES3_TPL_M (0x3ffff << TDES3_TPL_S)
+
+/*
+ * A hardware buffer descriptor. Rx and Tx buffers have the same descriptor
+ * layout, but the bits in the fields have different meanings.
+ */
+struct dwc_hwdesc
+{
+ uint32_t tdes0; /* Header or Buffer 1 Address[31:0] */
+ uint32_t tdes1; /* Buffer 2 Address [31:0] or Buffer 1 Address[63:32] */
+ uint32_t tdes2;
+ uint32_t tdes3;
+};
+
+#define RX_DESC_SIZE (sizeof(struct dwc_hwdesc) * RX_DESC_COUNT)
+#define TX_DESC_SIZE (sizeof(struct dwc_hwdesc) * TX_DESC_COUNT)
/*
* The hardware imposes alignment restrictions on various objects involved in
@@ -185,73 +162,75 @@
{
sc->tx_desccount--;
- sc->txdesc_ring[idx].addr1 = (uint32_t)(0);
- sc->txdesc_ring[idx].desc0 = 0;
- sc->txdesc_ring[idx].desc1 = 0;
+ sc->txdesc_ring[idx].tdes0 = 0;
+ sc->txdesc_ring[idx].tdes1 = 0;
+ sc->txdesc_ring[idx].tdes2 = 0;
+ sc->txdesc_ring[idx].tdes3 = 0;
}
inline static void
txdesc_setup(struct dwc_softc *sc, int idx, bus_addr_t paddr,
uint32_t len, uint32_t flags, bool first, bool last)
{
- uint32_t desc0, desc1;
+ uint32_t tdes0, tdes1, tdes2, tdes3;
if (!sc->dma_ext_desc) {
- desc0 = 0;
- desc1 = NTDESC1_TCH | len | flags;
+ tdes0 = paddr;
+ tdes1 = paddr >> 32;
+ tdes2 = len | TDES2_TTSE;
+ tdes3 = flags;
+
if (first)
- desc1 |= NTDESC1_FS;
- if (last)
- desc1 |= NTDESC1_LS | NTDESC1_IC;
+ tdes3 |= TDES3_FD;
+ if (last) {
+ tdes2 |= TDES2_IOC;
+ tdes3 |= TDES3_LD;
+ }
} else {
- desc0 = ETDESC0_TCH | flags;
- if (first)
- desc0 |= ETDESC0_FS;
- if (last)
- desc0 |= ETDESC0_LS | ETDESC0_IC;
- desc1 = len;
+ tdes0 = 0;
+ tdes1 = 0;
+ tdes2 = 0;
+ tdes3 = 0;
}
++sc->tx_desccount;
- sc->txdesc_ring[idx].addr1 = (uint32_t)(paddr);
- sc->txdesc_ring[idx].desc0 = desc0;
- sc->txdesc_ring[idx].desc1 = desc1;
+ sc->txdesc_ring[idx].tdes0 = tdes0;
+ sc->txdesc_ring[idx].tdes1 = tdes1;
+ sc->txdesc_ring[idx].tdes2 = tdes2;
+ sc->txdesc_ring[idx].tdes3 = tdes3;
+
wmb();
- sc->txdesc_ring[idx].desc0 |= TDESC0_OWN;
+ sc->txdesc_ring[idx].tdes3 |= TDES3_OWN;
wmb();
}
inline static uint32_t
rxdesc_setup(struct dwc_softc *sc, int idx, bus_addr_t paddr)
{
- uint32_t nidx;
-
- sc->rxdesc_ring[idx].addr1 = (uint32_t)paddr;
- nidx = next_rxidx(sc, idx);
- sc->rxdesc_ring[idx].addr2 = sc->rxdesc_ring_paddr +
- (nidx * sizeof(struct dwc_hwdesc));
- if (!sc->dma_ext_desc)
- sc->rxdesc_ring[idx].desc1 = NRDESC1_RCH |
- MIN(MCLBYTES, NRDESC1_RBS1_MASK);
- else
- sc->rxdesc_ring[idx].desc1 = ERDESC1_RCH |
- MIN(MCLBYTES, ERDESC1_RBS1_MASK);
+
+ sc->rxdesc_ring[idx].tdes0 = (uint32_t)paddr;
+ sc->rxdesc_ring[idx].tdes1 = (uint32_t)(paddr >> 32);
+ sc->rxdesc_ring[idx].tdes2 = 0;
+ sc->rxdesc_ring[idx].tdes3 = RDES3_IOC | RDES3_BUF1V;
wmb();
- sc->rxdesc_ring[idx].desc0 = RDESC0_OWN;
+ sc->rxdesc_ring[idx].tdes3 |= RDES3_OWN;
wmb();
- return (nidx);
+
+ return (0);
}
int
-dma1000_setup_txbuf(struct dwc_softc *sc, int idx, struct mbuf **mp)
+dma4_setup_txbuf(struct dwc_softc *sc, int idx, struct mbuf **mp)
{
struct bus_dma_segment segs[TX_MAP_MAX_SEGS];
int error, nsegs;
struct mbuf * m;
uint32_t flags;
+ uint32_t csum_flags;
int i;
int last;
+ flags = 0;
error = bus_dmamap_load_mbuf_sg(sc->txbuf_tag, sc->txbuf_map[idx].map,
*mp, segs, &nsegs, 0);
if (error == EFBIG) {
@@ -263,8 +242,8 @@
if ((m = m_defrag(*mp, M_NOWAIT)) == NULL)
return (ENOMEM);
*mp = m;
- error = bus_dmamap_load_mbuf_sg(sc->txbuf_tag, sc->txbuf_map[idx].map,
- *mp, segs, &nsegs, 0);
+ error = bus_dmamap_load_mbuf_sg(sc->txbuf_tag,
+ sc->txbuf_map[idx].map, *mp, segs, &nsegs, 0);
}
if (error != 0)
return (ENOMEM);
@@ -276,12 +255,18 @@
m = *mp;
- if ((m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA | CSUM_DELAY_DATA_IPV6)) != 0)
- flags = sc->dma_ext_desc ? ETDESC0_CIC_SEG : NTDESC1_CIC_SEG;
- else if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0)
- flags = sc->dma_ext_desc ? ETDESC0_CIC_HDR : NTDESC1_CIC_HDR;
- else
- flags = sc->dma_ext_desc ? ETDESC0_CIC_NONE : NTDESC1_CIC_NONE;
+ csum_flags = CSUM_TCP | CSUM_UDP | CSUM_IP6_TCP | CSUM_IP6_UDP;
+ if ((m->m_pkthdr.csum_flags & csum_flags) != 0) {
+ if (!sc->dma_ext_desc)
+ flags = TDES3_CIC_FULLP;
+ else
+ panic("implement me");
+ } else if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) {
+ if (!sc->dma_ext_desc)
+ flags = TDES3_CIC_HDR;
+ else
+ panic("implement me");
+ }
bus_dmamap_sync(sc->txbuf_tag, sc->txbuf_map[idx].map,
BUS_DMASYNC_PREWRITE);
@@ -300,11 +285,16 @@
sc->txbuf_map[idx].last_desc_idx = last;
+ wmb();
+
+ WRITE4(sc, ETH_DMACTXDTPR(0), sc->txdesc_ring_paddr +
+ sc->tx_desc_head * sizeof(struct dwc_hwdesc));
+
return (0);
}
static int
-dma1000_setup_rxbuf(struct dwc_softc *sc, int idx, struct mbuf *m)
+dma4_setup_rxbuf(struct dwc_softc *sc, int idx, struct mbuf *m)
{
struct bus_dma_segment seg;
int error, nsegs;
@@ -346,36 +336,32 @@
if_t ifp;
struct mbuf *m, *m0;
int len;
- uint32_t rdesc0;
+ uint32_t rdes1;
+ uint32_t rdes3;
m = map->mbuf;
ifp = sc->ifp;
- rdesc0 = desc ->desc0;
+ rdes1 = desc->tdes1;
+ rdes3 = desc->tdes3;
- if ((rdesc0 & (RDESC0_FS | RDESC0_LS)) !=
- (RDESC0_FS | RDESC0_LS)) {
+ if ((rdes3 & (RDES3_FD | RDES3_LD)) != (RDES3_FD | RDES3_LD)) {
/*
* Something very wrong happens. The whole packet should be
* received in one descriptor. Report problem.
*/
device_printf(sc->dev,
"%s: RX descriptor without FIRST and LAST bit set: 0x%08X",
- __func__, rdesc0);
+ __func__, rdes3);
return (NULL);
}
- len = (rdesc0 >> RDESC0_FL_SHIFT) & RDESC0_FL_MASK;
- if (len < 64) {
- /*
- * Lenght is invalid, recycle old mbuf
- * Probably impossible case
- */
- return (NULL);
- }
+ len = (rdes3 & RDES3_PL_M) >> RDES3_PL_S;
/* Allocate new buffer */
m0 = dwc_alloc_mbufcl(sc);
if (m0 == NULL) {
+ device_printf(sc->dev, "no mbufs\n");
+
/* no new mbuf available, recycle old */
if_inc_counter(sc->ifp, IFCOUNTER_IQDROPS, 1);
return (NULL);
@@ -391,13 +377,13 @@
if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
if ((if_getcapenable(ifp) & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) != 0 &&
- (rdesc0 & RDESC0_FT) != 0) {
+ (rdes1 & RDES1_IPCB) == 0) {
m->m_pkthdr.csum_flags = CSUM_IP_CHECKED;
- if ((rdesc0 & RDESC0_ICE) == 0)
+ if ((rdes1 & RDES1_IPCE) == 0)
m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
- if ((rdesc0 & RDESC0_PCE) == 0) {
+ if ((rdes1 & RDES1_IPHE) == 0) {
m->m_pkthdr.csum_flags |=
- CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
+ CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
m->m_pkthdr.csum_data = 0xffff;
}
}
@@ -412,7 +398,7 @@
}
void
-dma1000_txfinish_locked(struct dwc_softc *sc)
+dma4_txfinish_locked(struct dwc_softc *sc)
{
struct dwc_bufmap *bmap;
struct dwc_hwdesc *desc;
@@ -431,7 +417,7 @@
last_idx = next_txidx(sc, bmap->last_desc_idx);
while (idx != last_idx) {
desc = &sc->txdesc_ring[idx];
- if ((desc->desc0 & TDESC0_OWN) != 0) {
+ if ((desc->tdes3 & TDES3_OWN) != 0) {
map_finished = false;
break;
}
@@ -462,7 +448,7 @@
}
void
-dma1000_txstart(struct dwc_softc *sc)
+dma4_txstart(struct dwc_softc *sc)
{
int enqueued;
struct mbuf *m;
@@ -483,7 +469,7 @@
m = if_dequeue(sc->ifp);
if (m == NULL)
break;
- if (dma1000_setup_txbuf(sc, sc->tx_map_head, &m) != 0) {
+ if (dma4_setup_txbuf(sc, sc->tx_map_head, &m) != 0) {
if_sendq_prepend(sc->ifp, m);
if_setdrvflagbits(sc->ifp, IFF_DRV_OACTIVE, 0);
break;
@@ -494,39 +480,39 @@
++enqueued;
}
- if (enqueued != 0) {
- WRITE4(sc, TRANSMIT_POLL_DEMAND, 0x1);
+ if (enqueued != 0)
sc->tx_watchdog_count = WATCHDOG_TIMEOUT_SECS;
- }
}
void
-dma1000_rxfinish_locked(struct dwc_softc *sc)
+dma4_rxfinish_locked(struct dwc_softc *sc)
{
struct mbuf *m;
int error, idx;
struct dwc_hwdesc *desc;
DWC_ASSERT_LOCKED(sc);
+
for (;;) {
idx = sc->rx_idx;
desc = sc->rxdesc_ring + idx;
- if ((desc->desc0 & RDESC0_OWN) != 0)
+ if (desc->tdes3 & RDES3_OWN)
break;
-
m = dwc_rxfinish_one(sc, desc, sc->rxbuf_map + idx);
if (m == NULL) {
- wmb();
- desc->desc0 = RDESC0_OWN;
+ desc->tdes3 = RDES3_BUF1V | RDES3_IOC | RDES3_OWN;
wmb();
} else {
/* We cannot create hole in RX ring */
- error = dma1000_setup_rxbuf(sc, idx, m);
+ error = dma4_setup_rxbuf(sc, idx, m);
if (error != 0)
- panic("dma1000_setup_rxbuf failed: error %d\n",
+ panic("dma4_setup_rxbuf failed: error %d\n",
error);
-
}
+
+ WRITE4(sc, ETH_DMACRXDTPR(0), sc->rxdesc_ring_paddr +
+ idx * sizeof(struct dwc_hwdesc));
+
sc->rx_idx = next_rxidx(sc, sc->rx_idx);
}
}
@@ -535,71 +521,95 @@
* Start the DMA controller
*/
void
-dma1000_start(struct dwc_softc *sc)
+dma4_start(struct dwc_softc *sc)
{
uint32_t reg;
DWC_ASSERT_LOCKED(sc);
- /* Initializa DMA and enable transmitters */
- reg = READ4(sc, OPERATION_MODE);
- reg |= (MODE_TSF | MODE_OSF | MODE_FUF);
- reg &= ~(MODE_RSF);
- reg |= (MODE_RTC_LEV32 << MODE_RTC_SHIFT);
- WRITE4(sc, OPERATION_MODE, reg);
-
- WRITE4(sc, INTERRUPT_ENABLE, INT_EN_DEFAULT);
-
- /* Start DMA */
- reg = READ4(sc, OPERATION_MODE);
- reg |= (MODE_ST | MODE_SR);
- WRITE4(sc, OPERATION_MODE, reg);
+ /* Initialize DMA and enable transmitters */
+
+ /* Configure TX channel 0 */
+ reg = READ4(sc, ETH_DMACTXCR(0));
+ reg |= DMACTXCR_OSF;
+ WRITE4(sc, ETH_DMACTXCR(0), reg);
+
+ reg = MTLTXQOMR_TSF; /* Transmit Store and Forward */
+ reg |= MTLTXQOMR_EN;
+ reg |= MTLTXQOMR_TQS_8K;
+ WRITE4(sc, ETH_MTLTXQOMR(0), reg);
+
+ /* Configure RX channel 0 */
+ reg = MTLRXQOMR_RSF;
+ reg |= MTLRXQOMR_EHFC;
+ reg |= MTLRXQOMR_RQS_4K;
+ WRITE4(sc, ETH_MTLRXQOMR(0), reg);
+
+ reg = READ4(sc, ETH_MACRXQC0R(0));
+ reg |= MACRXQC0R_RXQ0EN_GEN;
+ WRITE4(sc, ETH_MACRXQC0R(0), reg);
+
+ /* Enable Interrupts. */
+ reg = DMACIER_TIE | DMACIER_TXSE | DMACIER_TBUE | DMACIER_RIE |
+ DMACIER_RBUE | DMACIER_RSE | DMACIER_RWTE | DMACIER_ETIE |
+ DMACIER_ERIE | DMACIER_FBEE | DMACIER_CDEE | DMACIER_AIE |
+ DMACIER_NIE;
+ WRITE4(sc, ETH_DMACIER(0), reg);
+
+ /* Start DMA RX. */
+ reg = READ4(sc, ETH_DMACRXCR(0));
+ reg |= DMACRXCR_SR;
+ WRITE4(sc, ETH_DMACRXCR(0), reg);
+
+ /* Start DMA TX. */
+ reg = READ4(sc, ETH_DMACTXCR(0));
+ reg |= DMACTXCR_ST;
+ WRITE4(sc, ETH_DMACTXCR(0), reg);
}
/*
* Stop the DMA controller
*/
void
-dma1000_stop(struct dwc_softc *sc)
+dma4_stop(struct dwc_softc *sc)
{
uint32_t reg;
DWC_ASSERT_LOCKED(sc);
/* Stop DMA TX */
- reg = READ4(sc, OPERATION_MODE);
- reg &= ~(MODE_ST);
- WRITE4(sc, OPERATION_MODE, reg);
+ reg = READ4(sc, ETH_DMACTXCR(0));
+ reg &= ~DMACTXCR_ST;
+ WRITE4(sc, ETH_DMACTXCR(0), reg);
/* Flush TX */
- reg = READ4(sc, OPERATION_MODE);
- reg |= (MODE_FTF);
- WRITE4(sc, OPERATION_MODE, reg);
+ reg = READ4(sc, ETH_MTLTXQOMR(0));
+ reg |= MTLTXQOMR_FTQ;
+ WRITE4(sc, ETH_MTLTXQOMR(0), reg);
/* Stop DMA RX */
- reg = READ4(sc, OPERATION_MODE);
- reg &= ~(MODE_SR);
- WRITE4(sc, OPERATION_MODE, reg);
+ reg = READ4(sc, ETH_DMACRXCR(0));
+ reg &= ~DMACRXCR_SR;
+ WRITE4(sc, ETH_DMACRXCR(0), reg);
}
int
-dma1000_reset(struct dwc_softc *sc)
+dma4_reset(struct dwc_softc *sc)
{
uint32_t reg;
int i;
- reg = READ4(sc, BUS_MODE);
- reg |= (BUS_MODE_SWR);
- WRITE4(sc, BUS_MODE, reg);
+ reg = READ4(sc, ETH_DMAMR);
+ reg |= DMAMR_SWR;
+ WRITE4(sc, ETH_DMAMR, reg);
for (i = 0; i < DMA_RESET_TIMEOUT; i++) {
- if ((READ4(sc, BUS_MODE) & BUS_MODE_SWR) == 0)
+ if ((READ4(sc, ETH_DMAMR) & DMAMR_SWR) == 0)
break;
DELAY(10);
}
- if (i >= DMA_RESET_TIMEOUT) {
+ if (i >= DMA_RESET_TIMEOUT)
return (ENXIO);
- }
return (0);
}
@@ -608,38 +618,61 @@
* Create the bus_dma resources
*/
int
-dma1000_init(struct dwc_softc *sc)
+dma4_init(struct dwc_softc *sc)
{
struct mbuf *m;
uint32_t reg;
int error;
- int nidx;
int idx;
- reg = BUS_MODE_USP;
- if (!sc->nopblx8)
- reg |= BUS_MODE_EIGHTXPBL;
- reg |= (sc->txpbl << BUS_MODE_PBL_SHIFT);
- reg |= (sc->rxpbl << BUS_MODE_RPBL_SHIFT);
+ WRITE4(sc, ETH_MACQ0TXFCR, 0xffff << 16 | 1);
+ WRITE4(sc, ETH_MACRXFCR, 1);
+
+ reg = READ4(sc, ETH_DMACCR(0));
+ if (sc->nopblx8)
+ reg &= ~DMACCR_PBLX8;
+ else
+ reg |= DMACCR_PBLX8;
+ WRITE4(sc, ETH_DMACCR(0), reg);
+
+ WRITE4(sc, ETH_DMACTXCR(0), 0);
+
+ reg = (MCLBYTES << DMACRXCR_RBSZ_S);
+ WRITE4(sc, ETH_DMACRXCR(0), reg);
+
+ reg = DMASBMR_BLEN4;
+ reg |= DMASBMR_BLEN8;
+ reg |= DMASBMR_BLEN16;
+ reg |= DMASBMR_EAME;
+ WRITE4(sc, ETH_DMASBMR, reg);
+
+ reg = READ4(sc, ETH_DMASBMR);
if (sc->fixed_burst)
- reg |= BUS_MODE_FIXEDBURST;
- if (sc->mixed_burst)
- reg |= BUS_MODE_MIXEDBURST;
+ reg |= DMASBMR_FB;
+ else
+ reg &= ~DMASBMR_FB;
if (sc->aal)
- reg |= BUS_MODE_AAL;
-
- WRITE4(sc, BUS_MODE, reg);
+ reg |= DMASBMR_AAL;
+ else
+ reg &= ~DMASBMR_AAL;
+ WRITE4(sc, ETH_DMASBMR, reg);
- reg = READ4(sc, HW_FEATURE);
- if (reg & HW_FEATURE_EXT_DESCRIPTOR)
- sc->dma_ext_desc = true;
+ /* No support in the driver. */
+ sc->dma_ext_desc = false;
/*
* DMA must be stop while changing descriptor list addresses.
*/
- reg = READ4(sc, OPERATION_MODE);
- reg &= ~(MODE_ST | MODE_SR);
- WRITE4(sc, OPERATION_MODE, reg);
+
+ /* Stop DMA TX */
+ reg = READ4(sc, ETH_DMACTXCR(0));
+ reg &= ~DMACTXCR_ST;
+ WRITE4(sc, ETH_DMACTXCR(0), reg);
+
+ /* Stop DMA RX */
+ reg = READ4(sc, ETH_DMACRXCR(0));
+ reg &= ~DMACRXCR_SR;
+ WRITE4(sc, ETH_DMACRXCR(0), reg);
/*
* Set up TX descriptor ring, descriptors, and dma maps.
@@ -647,7 +680,7 @@
error = bus_dma_tag_create(
bus_get_dma_tag(sc->dev), /* Parent tag. */
DWC_DESC_RING_ALIGN, 0, /* alignment, boundary */
- BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
TX_DESC_SIZE, 1, /* maxsize, nsegments */
@@ -661,7 +694,7 @@
goto out;
}
- error = bus_dmamem_alloc(sc->txdesc_tag, (void**)&sc->txdesc_ring,
+ error = bus_dmamem_alloc(sc->txdesc_tag, (void **)&sc->txdesc_ring,
BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO,
&sc->txdesc_map);
if (error != 0) {
@@ -679,19 +712,13 @@
goto out;
}
- for (idx = 0; idx < TX_DESC_COUNT; idx++) {
- nidx = next_txidx(sc, idx);
- sc->txdesc_ring[idx].addr2 = sc->txdesc_ring_paddr +
- (nidx * sizeof(struct dwc_hwdesc));
- }
-
error = bus_dma_tag_create(
bus_get_dma_tag(sc->dev), /* Parent tag. */
1, 0, /* alignment, boundary */
- BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
- MCLBYTES*TX_MAP_MAX_SEGS, /* maxsize */
+ MCLBYTES * TX_MAP_MAX_SEGS, /* maxsize */
TX_MAP_MAX_SEGS, /* nsegments */
MCLBYTES, /* maxsegsize */
0, /* flags */
@@ -704,7 +731,7 @@
}
for (idx = 0; idx < TX_MAP_COUNT; idx++) {
- error = bus_dmamap_create(sc->txbuf_tag, BUS_DMA_COHERENT,
+ error = bus_dmamap_create(sc->txbuf_tag, 0,
&sc->txbuf_map[idx].map);
if (error != 0) {
device_printf(sc->dev,
@@ -716,7 +743,9 @@
for (idx = 0; idx < TX_DESC_COUNT; idx++)
txdesc_clear(sc, idx);
- WRITE4(sc, TX_DESCR_LIST_ADDR, sc->txdesc_ring_paddr);
+ WRITE4(sc, ETH_DMACTXDLAR_HI(0), sc->txdesc_ring_paddr >> 32);
+ WRITE4(sc, ETH_DMACTXDLAR(0), sc->txdesc_ring_paddr);
+ WRITE4(sc, ETH_DMACTXRLR(0), TX_DESC_COUNT - 1);
/*
* Set up RX descriptor ring, descriptors, dma maps, and mbufs.
@@ -724,7 +753,7 @@
error = bus_dma_tag_create(
bus_get_dma_tag(sc->dev), /* Parent tag. */
DWC_DESC_RING_ALIGN, 0, /* alignment, boundary */
- BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
RX_DESC_SIZE, 1, /* maxsize, nsegments */
@@ -759,7 +788,7 @@
error = bus_dma_tag_create(
bus_get_dma_tag(sc->dev), /* Parent tag. */
1, 0, /* alignment, boundary */
- BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
MCLBYTES, 1, /* maxsize, nsegments */
@@ -773,8 +802,8 @@
goto out;
}
- for (idx = 0; idx < RX_DESC_COUNT; idx++) {
- error = bus_dmamap_create(sc->rxbuf_tag, BUS_DMA_COHERENT,
+ for (idx = 0; idx < RX_MAP_COUNT; idx++) {
+ error = bus_dmamap_create(sc->rxbuf_tag, 0,
&sc->rxbuf_map[idx].map);
if (error != 0) {
device_printf(sc->dev,
@@ -786,13 +815,19 @@
error = ENOMEM;
goto out;
}
- if ((error = dma1000_setup_rxbuf(sc, idx, m)) != 0) {
+ if ((error = dma4_setup_rxbuf(sc, idx, m)) != 0) {
device_printf(sc->dev,
"could not create new RX buffer.\n");
goto out;
}
}
- WRITE4(sc, RX_DESCR_LIST_ADDR, sc->rxdesc_ring_paddr);
+
+ WRITE4(sc, ETH_DMACRXDLAR_HI(0), sc->rxdesc_ring_paddr >> 32);
+ WRITE4(sc, ETH_DMACRXDLAR(0), sc->rxdesc_ring_paddr);
+
+ WRITE4(sc, ETH_DMACRXDTPR(0), sc->rxdesc_ring_paddr +
+ (RX_DESC_COUNT - 1) * sizeof(struct dwc_hwdesc));
+ WRITE4(sc, ETH_DMACRXRLR(0), RX_DESC_COUNT - 1);
out:
if (error != 0)
@@ -805,7 +840,7 @@
* Free the bus_dma resources
*/
void
-dma1000_free(struct dwc_softc *sc)
+dma4_free(struct dwc_softc *sc)
{
bus_dmamap_t map;
int idx;
@@ -851,32 +886,35 @@
*/
int
-dma1000_intr(struct dwc_softc *sc)
+dma4_intr(struct dwc_softc *sc)
{
uint32_t reg;
int rv;
+ rv = 0;
+
DWC_ASSERT_LOCKED(sc);
- rv = 0;
- reg = READ4(sc, DMA_STATUS);
- if (reg & DMA_STATUS_NIS) {
- if (reg & DMA_STATUS_RI)
- dma1000_rxfinish_locked(sc);
-
- if (reg & DMA_STATUS_TI) {
- dma1000_txfinish_locked(sc);
- dma1000_txstart(sc);
+ reg = READ4(sc, ETH_DMACSR(0));
+
+ if (reg & DMACSR_NIS) {
+ if (reg & DMACSR_RI)
+ dma4_rxfinish_locked(sc);
+
+ if (reg & DMACSR_TI) {
+ dma4_txfinish_locked(sc);
+ dma4_txstart(sc);
}
}
- if (reg & DMA_STATUS_AIS) {
- if (reg & DMA_STATUS_FBI) {
- /* Fatal bus error */
+ if (reg & DMACSR_AIS) {
+ if (reg & DMACSR_FBE) {
+ /* Fatal Bus Error. */
rv = EIO;
}
}
- WRITE4(sc, DMA_STATUS, reg & DMA_STATUS_INTR_MASK);
+ WRITE4(sc, ETH_DMACSR(0), reg);
+
return (rv);
}
diff --git a/sys/dev/dwc/dwc4_mtl.h b/sys/dev/dwc/dwc4_mtl.h
new file mode 100644
--- /dev/null
+++ b/sys/dev/dwc/dwc4_mtl.h
@@ -0,0 +1,124 @@
+/*-
+ * Copyright (c) 2026 Ruslan Bukin <br@bsdpad.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _DEV_DWC_DWC4_MTL_H_
+#define _DEV_DWC_DWC4_MTL_H_
+
+#define ETH_MTLOMR 0x0C00
+#define ETH_MTLISR 0x0C20
+#define ETH_MTLRXQDMAMR 0x0C30
+#define ETH_MTLTBSCR 0x0C40
+#define ETH_MTLESTCR 0x0C50
+#define ETH_MTLESTECR 0x0C54
+#define ETH_MTLESTSR 0x0C58
+#define ETH_MTLESTSCHER 0x0C60
+#define ETH_MTLESTFSER 0x0C64
+#define ETH_MTLESTFSCR 0x0C68
+#define ETH_MTLESTIER 0x0C70
+#define ETH_MTLESTGCLCR 0x0C80
+#define ETH_MTLESTGCLDR 0x0C84
+#define ETH_MTLFPECSR 0x0C90
+#define ETH_MTLFPEAR 0x0C94
+
+#define ETH_MTLTXQOMR(x) (0x0D00 + 0x40 * (x))
+#define MTLTXQOMR_TQS_S 16 /* Transmit queue size */
+#define MTLTXQOMR_TQS_M (0x1f << MTLTXQOMR_TQS_S)
+#define MTLTXQOMR_TQS_8K (0x1f << MTLTXQOMR_TQS_S)
+#define MTLTXQOMR_TXQEN_S 2 /* Transmit Queue Enable */
+#define MTLTXQOMR_TXQEN_M (0x3 << MTLTXQOMR_TXQEN_S)
+#define MTLTXQOMR_EN_AV_MODE (0x1 << MTLTXQOMR_TXQEN_S)
+#define MTLTXQOMR_EN (0x2 << MTLTXQOMR_TXQEN_S)
+#define MTLTXQOMR_TSF (1 << 1) /* Transmit Store and Forward */
+#define MTLTXQOMR_FTQ (1 << 0) /* Flush Transmit Queue */
+#define ETH_MTLTXQUR(x) (0x0D04 + 0x40 * (x))
+#define ETH_MTLTXQDR(x) (0x0D08 + 0x40 * (x))
+#define ETH_MTLTXQESR(x) (0x0D14 + 0x40 * (x))
+#define ETH_MTLTXQQWR(x) (0x0D18 + 0x40 * (x))
+#define ETH_MTLQICSR(x) (0x0D2C + 0x40 * (x))
+#define ETH_MTLRXQOMR(x) (0x0D30 + 0x40 * (x))
+#define MTLRXQOMR_RQS_S 20 /* Receive Queue Size */
+#define MTLRXQOMR_RQS_M (0xf << MTLRXQOMR_RQS_S)
+#define MTLRXQOMR_RQS_4K (0xf << MTLRXQOMR_RQS_S)
+#define MTLRXQOMR_EHFC (1 << 7) /* Enable Hardware Flow Control */
+#define MTLRXQOMR_RSF (1 << 5) /* Receive Queue Store and Forward */
+#define MTLRXQOMR_RTC_S 0 /* Receive Queue Threshold Control */
+#define MTLRXQOMR_RTC_M (0x3 << MTLRXQOMR_RTC_S)
+#define MTLRXQOMR_RTC_64 (0x0 << MTLRXQOMR_RTC_S)
+#define MTLRXQOMR_RTC_32 (0x1 << MTLRXQOMR_RTC_S)
+#define MTLRXQOMR_RTC_96 (0x2 << MTLRXQOMR_RTC_S)
+#define MTLRXQOMR_RTC_128 (0x3 << MTLRXQOMR_RTC_S)
+#define ETH_MTLRXQMPOCR(x) (0x0D34 + 0x40 * (x))
+#define ETH_MTLRXQDR(x) (0x0D38 + 0x40 * (x))
+#define ETH_MTLRXQCR(x) (0x0D3C + 0x40 * (x))
+
+#define ETH_MTLTXQ0OMR 0x0D00
+#define ETH_MTLTXQ0UR 0x0D04
+#define ETH_MTLTXQ0DR 0x0D08
+#define ETH_MTLTXQ0ESR 0x0D14
+#define ETH_MTLTXQ0QWR 0x0D18
+#define ETH_MTLQ0ICSR 0x0D2C
+#define ETH_MTLRXQ0OMR 0x0D30
+#define ETH_MTLRXQ0MPOCR 0x0D34
+#define ETH_MTLRXQ0DR 0x0D38
+#define ETH_MTLRXQ0CR 0x0D3C
+
+#define ETH_MTLTXQ1OMR 0x0D40
+#define ETH_MTLTXQ1UR 0x0D44
+#define ETH_MTLTXQ1DR 0x0D48
+#define ETH_MTLTXQ1ECR 0x0D50
+#define ETH_MTLTXQ1ESR 0x0D54
+#define ETH_MTLTXQ1QWR 0x0D58
+#define ETH_MTLTXQ1SSCR 0x0D5C
+#define ETH_MTLTXQ1HCR 0x0D60
+#define ETH_MTLTXQ1LCR 0x0D64
+#define ETH_MTLQ1ICSR 0x0D6C
+#define ETH_MTLRXQ1OMR 0x0D70
+#define ETH_MTLRXQ1MPOCR 0x0D74
+#define ETH_MTLRXQ1DR 0x0D78
+#define ETH_MTLRXQ1CR 0x0D7C
+
+#define ETH_MTLTXQ2OMR 0x0D80
+#define ETH_MTLTXQ2UR 0x0D84
+#define ETH_MTLTXQ2DR 0x0D88
+#define ETH_MTLTXQ2ECR 0x0D90
+#define ETH_MTLTXQ2ESR 0x0D94
+#define ETH_MTLTXQ2QWR 0x0D98
+#define ETH_MTLTXQ2SSCR 0x0D9C
+#define ETH_MTLTXQ2HCR 0x0DA0
+#define ETH_MTLTXQ2LCR 0x0DA4
+#define ETH_MTLQ2ICSR 0x0DAC
+
+#define ETH_MTLTXQ3OMR 0x0DC0
+#define ETH_MTLTXQ3UR 0x0DC4
+#define ETH_MTLTXQ3DR 0x0DC8
+#define ETH_MTLTXQ3ECR 0x0DD0
+#define ETH_MTLTXQ3ESR 0x0DD4
+#define ETH_MTLTXQ3QWR 0x0DD8
+#define ETH_MTLTXQ3SSCR 0x0DDC
+#define ETH_MTLTXQ3HCR 0x0DE0
+#define ETH_MTLTXQ3LCR 0x0DE4
+#define ETH_MTLQ3ICSR 0x0DEC
+
+#endif /* _DEV_DWC_DWC4_MTL_H_ */
diff --git a/sys/dev/dwc/dwc4_reg.h b/sys/dev/dwc/dwc4_reg.h
new file mode 100644
--- /dev/null
+++ b/sys/dev/dwc/dwc4_reg.h
@@ -0,0 +1,242 @@
+/*-
+ * Copyright (c) 2026 Ruslan Bukin <br@bsdpad.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _DEV_DWC_DWC4_REG_H_
+#define _DEV_DWC_DWC4_REG_H_
+
+#define ETH_MACCR 0x0000
+#define MACCR_IPC (1 << 27) /* Checksum Offload */
+#define MACCR_ACS (1 << 20) /* Automatic Pad or CRC Stripping */
+#define MACCR_BE (1 << 18) /* Packet Burst Enable */
+#define MACCR_JD (1 << 17) /* Jabber Disable */
+#define MACCR_PS (1 << 15) /* Port Select */
+#define MACCR_FES (1 << 14) /* MAC Speed */
+#define MACCR_DM (1 << 13) /* Duplex Mode */
+#define MACCR_TE (1 << 1) /* Transmitter Enable */
+#define MACCR_RE (1 << 0) /* Receiver Enable */
+#define ETH_MACECR 0x0004
+#define ETH_MACPFR 0x0008
+#define MACPFR_RA (1 << 31) /* Receive All */
+#define MACPFR_PM (1 << 4) /* Pass All Multicast */
+#define MACPFR_HMC (1 << 2) /* Hash Multicast */
+#define MACPFR_PR (1 << 0) /* Promiscuous Mode */
+#define ETH_MACWJBTR 0x000C
+#define ETH_MACHT0R 0x0010
+#define ETH_MACHT1R 0x0014
+#define ETH_MACVTCR 0x0050
+#define ETH_MACVTDR 0x0054
+#define ETH_MACVHTR 0x0058
+#define ETH_MACVIR 0x0060
+#define ETH_MACiVIR 0x0064
+#define ETH_MACQ0TXFCR 0x0070
+#define ETH_MACRXFCR 0x0090
+#define ETH_MACRXQCR 0x0094
+
+#define ETH_MACRXQC0R(x) (0x00A0 + 0x4 * (x))
+#define MACRXQC0R_RXQ0EN_S 0 /* Receive Queue 0 Enable */
+#define MACRXQC0R_RXQ0EN_AV (0x1 << MACRXQC0R_RXQ0EN_S)
+#define MACRXQC0R_RXQ0EN_GEN (0x2 << MACRXQC0R_RXQ0EN_S)
+#define MACRXQC0R_RXQ0EN_M (0x3 << MACRXQC0R_RXQ0EN_S)
+#define ETH_MACRXQC1R 0x00A4
+#define ETH_MACRXQC2R 0x00A8
+
+#define ETH_MACISR 0x00B0
+#define ETH_MACIER 0x00B4
+#define ETH_MACRXTXSR 0x00B8
+#define ETH_MACPCSR 0x00C0
+#define ETH_MACRWKPFR 0x00C4
+#define ETH_MACLCSR 0x00D0
+#define ETH_MACLTCR 0x00D4
+#define ETH_MACLETR 0x00D8
+#define ETH_MAC1USTCR 0x00DC
+#define ETH_MACPHYCSR 0x00F8
+#define ETH_MACVR 0x0110
+#define ETH_MACDR 0x0114
+#define ETH_MACHWF0R 0x011C
+#define ETH_MACHWF1R 0x0120
+#define ETH_MACHWF2R 0x0124
+#define ETH_MACHWF3R 0x0128
+#define ETH_MACMDIOAR 0x0200
+#define MACMDIOAR_CR_S 8 /* CSR Clock Range */
+#define MACMDIOAR_CR_M (0xf << MACMDIOAR_CR_S)
+#define MACMDIOAR_GOC_S 2 /* GMII Operation Command */
+#define MACMDIOAR_GOC_M (0x3 << MACMDIOAR_GOC_S)
+#define MACMDIOAR_WRITE (0x1 << MACMDIOAR_GOC_S)
+#define MACMDIOAR_POST_RD_INC (0x2 << MACMDIOAR_GOC_S)
+#define MACMDIOAR_READ (0x3 << MACMDIOAR_GOC_S)
+#define MACMDIOAR_GB (1 << 0) /* GMII Busy */
+#define MACMDIOAR_PA_S 21 /* Physical Layer Address */
+#define MACMDIOAR_PA_M (0x1f << MACMDIOAR_PA_S)
+#define MACMDIOAR_RDA_S 16 /* Register/Device Address */
+#define MACMDIOAR_RDA_M (0x1f << MACMDIOAR_RDA_S)
+#define ETH_MACMDIODR 0x0204
+#define ETH_MACARPAR 0x0210
+#define ETH_MACCSRSWCR 0x0230
+#define ETH_MACFPECSR 0x0234
+#define ETH_MACPRSTIMR 0x0240
+#define ETH_MACPRSTIMUR 0x0244
+#define ETH_MACA0HR 0x0300
+#define ETH_MACA0LR 0x0304
+#define ETH_MACA1HR 0x0308
+#define ETH_MACA1LR 0x030C
+#define ETH_MACA2HR 0x0310
+#define ETH_MACA2LR 0x0314
+#define ETH_MACA3HR 0x0318
+#define ETH_MACA3LR 0x031C
+#define ETH_MMC_CONTROL 0x0700
+#define MMC_CONTROL_CNTRST (1 << 0) /* Counters Reset */
+#define ETH_MMC_RX_INTERRUPT 0x0704
+#define ETH_MMC_TX_INTERRUPT 0x0708
+#define ETH_MMC_RX_INTERRUPT_MASK 0x070C
+#define ETH_MMC_TX_INTERRUPT_MASK 0x0710
+#define ETH_TX_OCTET_COUNT_GOOD_BAD 0x0714
+#define ETH_TX_PACKET_COUNT_GOOD_BAD 0x0718
+#define ETH_TX_BROADCAST_PACKETS_GOOD 0x071C
+#define ETH_TX_MULTICAST_PACKETS_GOOD 0x0720
+#define ETH_TX_64OCTETS_PACKETS_GOOD_BAD 0x0724
+#define ETH_TX_64TO127OCTETS_PACKETS_GOOD_BAD 0x0728
+#define ETH_TX_128TO255OCTETS_PACKETS_GOOD_BAD 0x072C
+#define ETH_TX_256TO511OCTETS_PACKETS_GOOD_BAD 0x0730
+#define ETH_TX_512TO1023OCTETS_PACKETS_GOOD_BAD 0x0734
+#define ETH_TX_1024TOMAXOCTETS_PACKETS_GOOD_BAD 0x0738
+#define ETH_TX_UNICAST_PACKETS_GOOD_BAD 0x073C
+#define ETH_TX_MULTICAST_PACKETS_GOOD_BAD 0x0740
+#define ETH_TX_BROADCAST_PACKETS_GOOD_BAD 0x0744
+#define ETH_TX_UNDERFLOW_ERROR_PACKETS 0x0748
+#define ETH_TX_SINGLE_COLLISION_GOOD_PACKETS 0x074C
+#define ETH_TX_MULTIPLE_COLLISION_GOOD_PACKETS 0x0750
+#define ETH_TX_DEFERRED_PACKETS 0x0754
+#define ETH_TX_LATE_COLLISION_PACKETS 0x0758
+#define ETH_TX_EXCESSIVE_COLLISION_PACKETS 0x075C
+#define ETH_TX_CARRIER_ERROR_PACKETS 0x0760
+#define ETH_TX_OCTET_COUNT_GOOD 0x0764
+#define ETH_TX_PACKET_COUNT_GOOD 0x0768
+#define ETH_TX_EXCESSIVE_DEFERRAL_ERROR 0x076C
+#define ETH_TX_PAUSE_PACKETS 0x0770
+#define ETH_TX_VLAN_PACKETS_GOOD 0x0774
+#define ETH_TX_OSIZE_PACKETS_GOOD 0x0778
+#define ETH_RX_PACKETS_COUNT_GOOD_BAD 0x0780
+#define ETH_RX_OCTET_COUNT_GOOD_BAD 0x0784
+#define ETH_RX_OCTET_COUNT_GOOD 0x0788
+#define ETH_RX_BROADCAST_PACKETS_GOOD 0x078C
+#define ETH_RX_MULTICAST_PACKETS_GOOD 0x0790
+#define ETH_RX_CRC_ERROR_PACKETS 0x0794
+#define ETH_RX_ALIGNMENT_ERROR_PACKETS 0x0798
+#define ETH_RX_RUNT_ERROR_PACKETS 0x079C
+#define ETH_RX_JABBER_ERROR_PACKETS 0x07A0
+#define ETH_RX_UNDERSIZE_PACKETS_GOOD 0x07A4
+#define ETH_RX_OVERSIZE_PACKETS_GOOD 0x07A8
+#define ETH_RX_64OCTETS_PACKETS_GOOD_BAD 0x07AC
+#define ETH_RX_65TO127OCTETS_PACKETS_GOOD_BAD 0x07B0
+#define ETH_RX_128TO255OCTETS_PACKETS_GOOD_BAD 0x07B4
+#define ETH_RX_256TO511OCTETS_PACKETS_GOOD_BAD 0x07B8
+#define ETH_RX_512TO1023OCTETS_PACKETS_GOOD_BAD 0x07BC
+#define ETH_RX_1024TOMAXOCTETS_PACKETS_GOOD_BAD 0x07C0
+#define ETH_RX_UNICAST_PACKETS_GOOD 0x07C4
+#define ETH_RX_LENGTH_ERROR_PACKETS 0x07C8
+#define ETH_RX_OUT_OF_RANGE_PACKETS 0x07CC
+#define ETH_RX_PAUSE_PACKETS 0x07D0
+#define ETH_RX_FIFO_OVERFLOW_PACKETS 0x07D4
+#define ETH_RX_VLAN_PACKETS_GOOD_BAD 0x07D8
+#define ETH_RX_WATCHDOG_ERROR_PACKETS 0x07DC
+#define ETH_RX_RECEIVE_ERROR 0x07E0
+#define ETH_RX_CONTROL_PACKETS_GOOD 0x07E4
+#define ETH_TX_LPI_USEC_CNTR 0x07EC
+#define ETH_TX_LPI_TRAN_CNTR 0x07F0
+#define ETH_RX_LPI_USEC_CNTR 0x07F4
+#define ETH_RX_LPI_TRAN_CNTR 0x07F8
+#define ETH_MMC_FPE_TX_ISR 0x08A0
+#define ETH_MMC_FPE_TX_IMR 0x08A4
+#define ETH_MMC_FPE_TX_FCR 0x08A8
+#define ETH_MMC_TX_HRCR 0x08AC
+#define ETH_MMC_FPE_RX_ISR 0x08C0
+#define ETH_MMC_FPE_RX_IMR 0x08C4
+#define ETH_RX_PACKET_ASM_ERR 0x08C8
+#define ETH_RX_PACKET_SMD_ERR 0x08CC
+#define ETH_RX_PACKET_ASM_OKR 0x08D0
+#define ETH_RX_FPE_FRAG_CR 0x08D4
+#define ETH_MACL3L4C0R 0x0900
+#define ETH_MACL4A0R 0x0904
+#define ETH_MACL3A00R 0x0910
+#define ETH_MACL3A10R 0x0914
+#define ETH_MACL3A20R 0x0918
+#define ETH_MACL3A30R 0x091C
+#define ETH_MACL3L4C1R 0x0930
+#define ETH_MACL4A1R 0x0934
+#define ETH_MACL3A01R 0x0940
+#define ETH_MACL3A11R 0x0944
+#define ETH_MACL3A21R 0x0948
+#define ETH_MACL3A31R 0x094C
+#define ETH_MAC_IACR 0x0A70
+#define ETH_MAC_TMRQR 0x0A74
+#define ETH_MACTSCR 0x0B00
+#define ETH_MACSSIR 0x0B04
+#define ETH_MACSTSR 0x0B08
+#define ETH_MACSTNR 0x0B0C
+#define ETH_MACSTSUR 0x0B10
+#define ETH_MACSTNUR 0x0B14
+#define ETH_MACTSAR 0x0B18
+#define ETH_MACTSSR 0x0B20
+#define ETH_MACRXDTI 0x0B24
+#define ETH_MACTXDTI 0x0B28
+#define ETH_MACTXTSSNR 0x0B30
+#define ETH_MACTXTSSSR 0x0B34
+#define ETH_MACACR 0x0B40
+#define ETH_MACATSNR 0x0B48
+#define ETH_MACATSSR 0x0B4C
+#define ETH_MACTSIACR 0x0B50
+#define ETH_MACTSEACR 0x0B54
+#define ETH_MACTSICNR 0x0B58
+#define ETH_MACTSECNR 0x0B5C
+#define ETH_MACTSILR 0x0B68
+#define ETH_MACTSELR 0x0B6C
+#define ETH_MACPPSCR 0x0B70
+#define ETH_MACPPSTTS0R 0x0B80
+#define ETH_MACPPSTTN0R 0x0B84
+#define ETH_MACPPSI0R 0x0B88
+#define ETH_MACPPSW0R 0x0B8C
+#define ETH_MACPPSTTS1R 0x0B90
+#define ETH_MACPPSTTN1R 0x0B94
+#define ETH_MACPPSI1R 0x0B98
+#define ETH_MACPPSW1R 0x0B9C
+#define ETH_MACPOCR 0x0BC0
+#define ETH_MACSPI0R 0x0BC4
+#define ETH_MACSPI1R 0x0BC8
+#define ETH_MACSPI2R 0x0BCC
+#define ETH_MACLMIR 0x0BD0
+
+int dwc4_miibus_read_reg(device_t dev, int phy, int reg);
+int dwc4_miibus_write_reg(device_t dev, int phy, int reg, int val);
+void dwc4_miibus_statchg(device_t dev);
+void dwc4_core_setup(struct dwc_softc *sc);
+void dwc4_enable_mac(struct dwc_softc *sc, bool enable);
+void dwc4_enable_csum_offload(struct dwc_softc *sc);
+void dwc4_setup_rxfilter(struct dwc_softc *sc);
+void dwc4_get_hwaddr(struct dwc_softc *sc, uint8_t *hwaddr);
+void dwc4_harvest_stats(struct dwc_softc *sc);
+void dwc4_intr(struct dwc_softc *softc);
+void dwc4_intr_disable(struct dwc_softc *sc);
+
+#endif /* !_DEV_DWC_DWC4_REG_H_ */
diff --git a/sys/dev/dwc/if_dwc.c b/sys/dev/dwc/if_dwc.c
--- a/sys/dev/dwc/if_dwc.c
+++ b/sys/dev/dwc/if_dwc.c
@@ -70,7 +70,10 @@
#include <dev/dwc/if_dwcvar.h>
#include <dev/dwc/dwc1000_core.h>
+#include <dev/dwc/dwc1000_reg.h>
#include <dev/dwc/dwc1000_dma.h>
+#include <dev/dwc/dwc4_dma.h>
+#include <dev/dwc/dwc4_reg.h>
#include "if_dwc_if.h"
#include "gpio_if.h"
@@ -145,7 +148,7 @@
if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) !=
IFF_DRV_RUNNING)
return;
- dma1000_txstart(sc);
+ sc->ops->dma_txstart(sc);
}
static void
@@ -169,16 +172,16 @@
return;
/*
- * Call mii_mediachg() which will call back into dwc1000_miibus_statchg()
+ * Call mii_mediachg() which will call back into dwc*_miibus_statchg()
* to set up the remaining config registers based on current media.
*/
mii_mediachg(sc->mii_softc);
- dwc1000_setup_rxfilter(sc);
- dwc1000_core_setup(sc);
- dwc1000_enable_mac(sc, true);
- dwc1000_enable_csum_offload(sc);
- dma1000_start(sc);
+ sc->ops->core_setup_rxfilter(sc);
+ sc->ops->core_setup(sc);
+ sc->ops->core_enable_mac(sc, true);
+ sc->ops->core_enable_csum_offload(sc);
+ sc->ops->dma_start(sc);
if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);
@@ -209,8 +212,8 @@
callout_stop(&sc->dwc_callout);
- dma1000_stop(sc);
- dwc1000_enable_mac(sc, false);
+ sc->ops->dma_stop(sc);
+ sc->ops->core_enable_mac(sc, false);
}
static int
@@ -232,7 +235,7 @@
if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
flags = if_getflags(ifp) ^ sc->if_flags;
if ((flags & (IFF_PROMISC|IFF_ALLMULTI)) != 0)
- dwc1000_setup_rxfilter(sc);
+ sc->ops->core_setup_rxfilter(sc);
} else {
if (!sc->is_detaching)
dwc_init_locked(sc);
@@ -248,7 +251,7 @@
case SIOCDELMULTI:
if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
DWC_LOCK(sc);
- dwc1000_setup_rxfilter(sc);
+ sc->ops->core_setup_rxfilter(sc);
DWC_UNLOCK(sc);
}
break;
@@ -276,7 +279,7 @@
if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
DWC_LOCK(sc);
- dwc1000_enable_csum_offload(sc);
+ sc->ops->core_enable_csum_offload(sc);
DWC_UNLOCK(sc);
}
break;
@@ -302,8 +305,8 @@
sc = arg;
DWC_LOCK(sc);
- dwc1000_intr(sc);
- rv = dma1000_intr(sc);
+ sc->ops->core_intr(sc);
+ rv = sc->ops->dma_intr(sc);
if (rv == EIO) {
device_printf(sc->dev,
"Ethernet DMA error, restarting controller.\n");
@@ -336,12 +339,12 @@
*/
if (sc->tx_watchdog_count > 0) {
if (--sc->tx_watchdog_count == 0) {
- dma1000_txfinish_locked(sc);
+ sc->ops->dma_txfinish_locked(sc);
}
}
/* Gather stats from hardware counters. */
- dwc1000_harvest_stats(sc);
+ sc->ops->core_harvest_stats(sc);
/* Check the media status. */
link_was_up = sc->link_is_up;
@@ -473,6 +476,52 @@
return (0);
}
+static struct dwc_ops dwc_ops_3 = {
+ .dma_init = dma1000_init,
+ .dma_free = dma1000_free,
+ .dma_start = dma1000_start,
+ .dma_stop = dma1000_stop,
+ .dma_reset = dma1000_reset,
+ .dma_txfinish_locked = dma1000_txfinish_locked,
+ .dma_txstart = dma1000_txstart,
+ .dma_intr = dma1000_intr,
+
+ .core_miibus_read_reg = dwc1000_miibus_read_reg,
+ .core_miibus_write_reg = dwc1000_miibus_write_reg,
+ .core_miibus_statchg = dwc1000_miibus_statchg,
+ .core_setup = dwc1000_core_setup,
+ .core_enable_mac = dwc1000_enable_mac,
+ .core_enable_csum_offload = dwc1000_enable_csum_offload,
+ .core_setup_rxfilter = dwc1000_setup_rxfilter,
+ .core_get_hwaddr = dwc1000_get_hwaddr,
+ .core_harvest_stats = dwc1000_harvest_stats,
+ .core_intr = dwc1000_intr,
+ .core_intr_disable = dwc1000_intr_disable,
+};
+
+static struct dwc_ops dwc_ops_4 = {
+ .dma_init = dma4_init,
+ .dma_free = dma4_free,
+ .dma_start = dma4_start,
+ .dma_stop = dma4_stop,
+ .dma_reset = dma4_reset,
+ .dma_txfinish_locked = dma4_txfinish_locked,
+ .dma_txstart = dma4_txstart,
+ .dma_intr = dma4_intr,
+
+ .core_miibus_read_reg = dwc4_miibus_read_reg,
+ .core_miibus_write_reg = dwc4_miibus_write_reg,
+ .core_miibus_statchg = dwc4_miibus_statchg,
+ .core_setup = dwc4_core_setup,
+ .core_enable_mac = dwc4_enable_mac,
+ .core_enable_csum_offload = dwc4_enable_csum_offload,
+ .core_setup_rxfilter = dwc4_setup_rxfilter,
+ .core_get_hwaddr = dwc4_get_hwaddr,
+ .core_harvest_stats = dwc4_harvest_stats,
+ .core_intr = dwc4_intr,
+ .core_intr_disable = dwc4_intr_disable,
+};
+
/*
* Probe/Attach functions
*/
@@ -562,8 +611,16 @@
return (ENXIO);
}
+ if (sc->flags & DWC_HAS_GMAC5 || sc->flags & DWC_HAS_GMAC4) {
+ device_printf(dev, "gmac version %x\n", READ4(sc, ETH_MACVR));
+ sc->ops = &dwc_ops_4;
+ } else {
+ device_printf(dev, "gmac version %x\n", READ4(sc, VERSION));
+ sc->ops = &dwc_ops_3;
+ }
+
/* Read MAC before reset */
- dwc1000_get_hwaddr(sc, macaddr);
+ sc->ops->core_get_hwaddr(sc, macaddr);
/* Reset the PHY if needed */
if (dwc_reset_phy(sc) != 0) {
@@ -573,13 +630,13 @@
}
/* Reset */
- if ((error = dma1000_reset(sc)) != 0) {
+ if ((error = sc->ops->dma_reset(sc)) != 0) {
device_printf(sc->dev, "Can't reset DMA controller.\n");
bus_release_resources(sc->dev, dwc_spec, sc->res);
return (error);
}
- if (dma1000_init(sc)) {
+ if (sc->ops->dma_init(sc)) {
bus_release_resources(dev, dwc_spec, sc->res);
return (ENXIO);
}
@@ -644,7 +701,7 @@
* Disable and tear down interrupts before anything else, so we don't
* race with the handler.
*/
- dwc1000_intr_disable(sc);
+ sc->ops->core_intr_disable(sc);
if (sc->intr_cookie != NULL) {
bus_teardown_intr(dev, sc->res[1], sc->intr_cookie);
}
@@ -661,7 +718,7 @@
bus_generic_detach(dev);
/* Free DMA descriptors */
- dma1000_free(sc);
+ sc->ops->dma_free(sc);
if (sc->ifp != NULL) {
if_free(sc->ifp);
@@ -674,15 +731,42 @@
return (0);
}
+static int
+dwc_miibus_read_reg(device_t dev, int phy, int reg)
+{
+ struct dwc_softc *sc;
+
+ sc = device_get_softc(dev);
+ return (sc->ops->core_miibus_read_reg(dev, phy, reg));
+}
+
+static int
+dwc_miibus_write_reg(device_t dev, int phy, int reg, int val)
+{
+ struct dwc_softc *sc;
+
+ sc = device_get_softc(dev);
+ return (sc->ops->core_miibus_write_reg(dev, phy, reg, val));
+}
+
+static void
+dwc_miibus_statchg(device_t dev)
+{
+ struct dwc_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->ops->core_miibus_statchg(dev);
+}
+
static device_method_t dwc_methods[] = {
DEVMETHOD(device_probe, dwc_probe),
DEVMETHOD(device_attach, dwc_attach),
DEVMETHOD(device_detach, dwc_detach),
/* MII Interface */
- DEVMETHOD(miibus_readreg, dwc1000_miibus_read_reg),
- DEVMETHOD(miibus_writereg, dwc1000_miibus_write_reg),
- DEVMETHOD(miibus_statchg, dwc1000_miibus_statchg),
+ DEVMETHOD(miibus_readreg, dwc_miibus_read_reg),
+ DEVMETHOD(miibus_writereg, dwc_miibus_write_reg),
+ DEVMETHOD(miibus_statchg, dwc_miibus_statchg),
DEVMETHOD_END
};
diff --git a/sys/dev/dwc/if_dwcvar.h b/sys/dev/dwc/if_dwcvar.h
--- a/sys/dev/dwc/if_dwcvar.h
+++ b/sys/dev/dwc/if_dwcvar.h
@@ -42,14 +42,24 @@
* Driver data and defines.
*/
#define RX_DESC_COUNT 1024
-#define RX_DESC_SIZE (sizeof(struct dwc_hwdesc) * RX_DESC_COUNT)
+#define RX_MAP_COUNT RX_DESC_COUNT
#define TX_DESC_COUNT 1024
#define TX_MAP_COUNT TX_DESC_COUNT
-#define TX_DESC_SIZE (sizeof(struct dwc_hwdesc) * TX_DESC_COUNT)
#define TX_MAP_MAX_SEGS 32
#define DMA_DEFAULT_PBL 8
+/* Synopsys Core versions IDs */
+#define DWMAC_CORE_3_40 0x34
+#define DWMAC_CORE_3_50 0x35
+#define DWMAC_CORE_3_70 0x37
+#define DWMAC_CORE_4_00 0x40
+#define DWMAC_CORE_4_10 0x41
+#define DWMAC_CORE_5_00 0x50
+#define DWMAC_CORE_5_10 0x51
+#define DWMAC_CORE_5_20 0x52
+#define DWMAC_CORE_5_40 0x54
+
struct dwc_bufmap {
bus_dmamap_t map;
struct mbuf *mbuf;
@@ -57,6 +67,31 @@
int last_desc_idx;
};
+struct dwc_softc;
+
+struct dwc_ops {
+ int (*dma_init)(struct dwc_softc *sc);
+ void (*dma_free)(struct dwc_softc *sc);
+ void (*dma_start)(struct dwc_softc *sc);
+ void (*dma_stop)(struct dwc_softc *sc);
+ int (*dma_reset)(struct dwc_softc *sc);
+ void (*dma_txfinish_locked)(struct dwc_softc *sc);
+ void (*dma_txstart)(struct dwc_softc *sc);
+ int (*dma_intr)(struct dwc_softc *sc);
+
+ int (*core_miibus_read_reg)(device_t dev, int phy, int reg);
+ int (*core_miibus_write_reg)(device_t dev, int phy, int reg, int val);
+ void (*core_miibus_statchg)(device_t dev);
+ void (*core_setup)(struct dwc_softc *sc);
+ void (*core_enable_mac)(struct dwc_softc *sc, bool enable);
+ void (*core_enable_csum_offload)(struct dwc_softc *sc);
+ void (*core_setup_rxfilter)(struct dwc_softc *sc);
+ void (*core_get_hwaddr)(struct dwc_softc *sc, uint8_t *hwaddr);
+ void (*core_harvest_stats)(struct dwc_softc *sc);
+ void (*core_intr)(struct dwc_softc *softc);
+ void (*core_intr_disable)(struct dwc_softc *sc);
+};
+
struct dwc_softc {
struct resource *res[2];
device_t dev;
@@ -113,6 +148,12 @@
uint32_t tx_map_tail;
int tx_desccount;
int tx_mapcount;
+ struct dwc_ops *ops;
+
+ int flags;
+#define DWC_HAS_GMAC5 (1 << 2)
+#define DWC_HAS_GMAC4 (1 << 1)
+#define DWC_HAS_GMAC3 (1 << 0)
};
#define READ4(_sc, _reg) \

File Metadata

Mime Type
text/plain
Expires
Sun, Oct 18, 8:18 AM (16 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40977682
Default Alt Text
D59191.diff (66 KB)

Event Timeline