Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F176249635
D59191.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
66 KB
Referenced Files
None
Subscribers
None
D59191.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D59191: dwc(4): support Synopsys IP version 4 and 5
Attached
Detach File
Event Timeline
Log In to Comment