Module Name:    src
Committed By:   martin
Date:           Fri Nov  3 08:56:37 UTC 2023

Modified Files:
        src/share/man/man4 [netbsd-10]: eqos.4
        src/sys/arch/amd64/conf [netbsd-10]: GENERIC
        src/sys/arch/i386/conf [netbsd-10]: GENERIC
        src/sys/dev/ic [netbsd-10]: dwc_eqos.c dwc_eqos_reg.h dwc_eqos_var.h
        src/sys/dev/pci [netbsd-10]: files.pci
Added Files:
        src/sys/dev/pci [netbsd-10]: if_eqos_pci.c

Log Message:
Pull up following revision(s) (requested by msaitoh in ticket #446):

        sys/dev/pci/if_eqos_pci.c: revision 1.3
        sys/arch/i386/conf/GENERIC: revision 1.1251
        sys/arch/i386/conf/GENERIC: revision 1.1252
        sys/arch/amd64/conf/GENERIC: revision 1.607
        sys/arch/amd64/conf/GENERIC: revision 1.608
        sys/dev/ic/dwc_eqos.c: revision 1.20
        sys/dev/ic/dwc_eqos.c: revision 1.21
        share/man/man4/eqos.4: revision 1.2
        sys/dev/ic/dwc_eqos.c: revision 1.22
        sys/dev/ic/dwc_eqos_reg.h: revision 1.7
        sys/dev/ic/dwc_eqos.c: revision 1.23
        sys/dev/ic/dwc_eqos_reg.h: revision 1.8
        sys/dev/ic/dwc_eqos.c: revision 1.24
        sys/dev/ic/dwc_eqos.c: revision 1.25
        sys/dev/ic/dwc_eqos.c: revision 1.26
        sys/dev/ic/dwc_eqos.c: revision 1.27
        sys/dev/ic/dwc_eqos_var.h: revision 1.5
        sys/dev/ic/dwc_eqos.c: revision 1.28
        sys/dev/ic/dwc_eqos_var.h: revision 1.6
        sys/dev/ic/dwc_eqos.c: revision 1.29
        sys/dev/ic/dwc_eqos.c: revision 1.18
        sys/dev/ic/dwc_eqos.c: revision 1.19
        sys/dev/pci/files.pci: revision 1.448
        sys/dev/pci/if_eqos_pci.c: revision 1.1
        sys/dev/pci/if_eqos_pci.c: revision 1.2

eqos(4): Fix definition of GMAC_MAC_HW_FEATURE1_RXFIFOSIZE.

eqos(4): Fix a bug that the MAC address is swapped.
 Don't swap the MAC address in eqos_get_eaddr(). Other OSes except FreeBSD
(which was based on NetBSD's) don't swap it. With this change, my own
OnLogic Helix 330's MAC address becomes correct. The OUI is 84:8b:cd:4d.
It's owned by Logic Supply and they were acquired by OnLogic.

On Quartz64 with UEFI, the MAC address is wrongly set and the multicast
bit might be set. To do workaround, clear the bit if it's set.

eqos(4): Add missing clock range.

eqos(4): Accept if snpsver == 0x52. Tested with Intel Elkhart Lake.

 TODO:
        Multiqueue support.
        Add watchdog timer.
        Add detach function.

eqos(4): Add initial support for Intel Elkhart Lake internal Ethernet devices.
 - Only tested on PSE SGMII 1G Ethernet MAC with MaxLinear GPY115.
 - I don't know why dmat64 doesn't work. eqos_attach() have a special
   code if EQOS_HW_FEATURE_ADDR64_32BIT(sc) is true, but it seems it doesn't
   work.
 - TODO:
        Multiqueue support.
        Detach support.

eqos(4): Fix compile error for arch that sizeof(bus_size_t) == 4 (i386).
Trailing whitespace

eqos(4): Disable eqos(4) by default because it's not stable on x86.

eqos(4): KNF. No functional change.

eqos(4): Add and modify some DPRINTF()s.

eqos(4): Add sysctls for debugging.

eqos(4): Use EQOS_TXLOCK() more to be stable.
 Fix a bug that sc_tx.{cur,next,queued} become inconsitent.
Use txlock when accessing TX data.

eqos(4): Set TX/RX DMA burst length to improve performance.

eqos(4): Set flow control correctly.

eqos_pci: Limit to 32bit DMA only for PSE devices.

eqos(4): Fix typo in comment.


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.1.2.1 src/share/man/man4/eqos.4
cvs rdiff -u -r1.599.4.4 -r1.599.4.5 src/sys/arch/amd64/conf/GENERIC
cvs rdiff -u -r1.1243.2.2 -r1.1243.2.3 src/sys/arch/i386/conf/GENERIC
cvs rdiff -u -r1.16 -r1.16.4.1 src/sys/dev/ic/dwc_eqos.c
cvs rdiff -u -r1.6 -r1.6.4.1 src/sys/dev/ic/dwc_eqos_reg.h
cvs rdiff -u -r1.4 -r1.4.4.1 src/sys/dev/ic/dwc_eqos_var.h
cvs rdiff -u -r1.445.2.2 -r1.445.2.3 src/sys/dev/pci/files.pci
cvs rdiff -u -r0 -r1.3.2.2 src/sys/dev/pci/if_eqos_pci.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/share/man/man4/eqos.4
diff -u src/share/man/man4/eqos.4:1.1 src/share/man/man4/eqos.4:1.1.2.1
--- src/share/man/man4/eqos.4:1.1	Thu Jan  6 21:55:23 2022
+++ src/share/man/man4/eqos.4	Fri Nov  3 08:56:37 2023
@@ -1,4 +1,4 @@
-.\" $NetBSD: eqos.4,v 1.1 2022/01/06 21:55:23 nia Exp $
+.\" $NetBSD: eqos.4,v 1.1.2.1 2023/11/03 08:56:37 martin Exp $
 .\"
 .\" Copyright (c) 2022 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -27,7 +27,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd January 6, 2022
+.Dd October 20, 2023
 .Dt EQOS 4
 .Os
 .Sh NAME
@@ -35,6 +35,7 @@
 .Nd DesignWare Ethernet Quality-of-Service controller
 .Sh SYNOPSIS
 .Cd "eqos* at acpi?"
+.Cd "eqos* at pci?"
 .Sh DESCRIPTION
 The
 .Nm

Index: src/sys/arch/amd64/conf/GENERIC
diff -u src/sys/arch/amd64/conf/GENERIC:1.599.4.4 src/sys/arch/amd64/conf/GENERIC:1.599.4.5
--- src/sys/arch/amd64/conf/GENERIC:1.599.4.4	Mon Oct  9 23:33:45 2023
+++ src/sys/arch/amd64/conf/GENERIC	Fri Nov  3 08:56:36 2023
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.599.4.4 2023/10/09 23:33:45 snj Exp $
+# $NetBSD: GENERIC,v 1.599.4.5 2023/11/03 08:56:36 martin Exp $
 #
 # GENERIC machine description file
 #
@@ -22,7 +22,7 @@ include 	"arch/amd64/conf/std.amd64"
 
 options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident		"GENERIC-$Revision: 1.599.4.4 $"
+#ident		"GENERIC-$Revision: 1.599.4.5 $"
 
 maxusers	64		# estimated number of users
 
@@ -823,6 +823,7 @@ dge*	at pci? dev ? function ?	# Intel 82
 ena*	at pci? dev ? function ?	# Amazon.com Elastic Network Adapter
 ep*	at pci? dev ? function ?	# 3Com 3c59x
 epic*	at pci? dev ? function ?	# SMC EPIC/100 Ethernet
+#eqos*	at pci? dev ? function ?	# DesignWare Ethernet QoS
 et*	at pci? dev ? function ?	# Agere/LSI ET1310/ET1301 Gigabit
 ex*	at pci? dev ? function ?	# 3Com 90x[BC]
 fxp*	at pci? dev ? function ?	# Intel EtherExpress PRO 10+/100B

Index: src/sys/arch/i386/conf/GENERIC
diff -u src/sys/arch/i386/conf/GENERIC:1.1243.2.2 src/sys/arch/i386/conf/GENERIC:1.1243.2.3
--- src/sys/arch/i386/conf/GENERIC:1.1243.2.2	Mon Oct  9 23:33:46 2023
+++ src/sys/arch/i386/conf/GENERIC	Fri Nov  3 08:56:36 2023
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.1243.2.2 2023/10/09 23:33:46 snj Exp $
+# $NetBSD: GENERIC,v 1.1243.2.3 2023/11/03 08:56:36 martin Exp $
 #
 # GENERIC machine description file
 #
@@ -22,7 +22,7 @@ include 	"arch/i386/conf/std.i386"
 
 options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident		"GENERIC-$Revision: 1.1243.2.2 $"
+#ident		"GENERIC-$Revision: 1.1243.2.3 $"
 
 maxusers	64		# estimated number of users
 
@@ -978,6 +978,7 @@ bwfm*	at pci? dev ? function ?	# Broadco
 dge*	at pci? dev ? function ?	# Intel 82597 10GbE LR
 ep*	at pci? dev ? function ?	# 3Com 3c59x
 epic*	at pci? dev ? function ?	# SMC EPIC/100 Ethernet
+#eqos*	at pci? dev ? function ?	# DesignWare Ethernet QoS
 et*	at pci? dev ? function ?	# Agere/LSI ET1310/ET1301 Gigabit
 ex*	at pci? dev ? function ?	# 3Com 3c90x[BC]
 fxp*	at pci? dev ? function ?	# Intel EtherExpress PRO 10+/100B

Index: src/sys/dev/ic/dwc_eqos.c
diff -u src/sys/dev/ic/dwc_eqos.c:1.16 src/sys/dev/ic/dwc_eqos.c:1.16.4.1
--- src/sys/dev/ic/dwc_eqos.c:1.16	Sun Sep 18 18:20:31 2022
+++ src/sys/dev/ic/dwc_eqos.c	Fri Nov  3 08:56:36 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc_eqos.c,v 1.16 2022/09/18 18:20:31 thorpej Exp $ */
+/* $NetBSD: dwc_eqos.c,v 1.16.4.1 2023/11/03 08:56:36 martin Exp $ */
 
 /*-
  * Copyright (c) 2022 Jared McNeill <jmcne...@invisible.ca>
@@ -28,12 +28,17 @@
 
 /*
  * DesignWare Ethernet Quality-of-Service controller
+ *
+ * TODO:
+ *	Multiqueue support.
+ *	Add watchdog timer.
+ *	Add detach function.
  */
 
 #include "opt_net_mpsafe.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc_eqos.c,v 1.16 2022/09/18 18:20:31 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc_eqos.c,v 1.16.4.1 2023/11/03 08:56:36 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -45,6 +50,7 @@ __KERNEL_RCSID(0, "$NetBSD: dwc_eqos.c,v
 #include <sys/callout.h>
 #include <sys/cprng.h>
 #include <sys/evcnt.h>
+#include <sys/sysctl.h>
 
 #include <sys/rndsource.h>
 
@@ -65,18 +71,18 @@ __KERNEL_RCSID(0, "$NetBSD: dwc_eqos.c,v
 CTASSERT(MCLBYTES >= EQOS_RXDMA_SIZE);
 
 #ifdef EQOS_DEBUG
-unsigned int eqos_debug;
-#define	DPRINTF(FLAG, FORMAT, ...)	\
-	if (eqos_debug & FLAG) 		\
+#define	EDEB_NOTE		(1U << 0)
+#define	EDEB_INTR		(1U << 1)
+#define	EDEB_RXRING		(1U << 2)
+#define	EDEB_TXRING		(1U << 3)
+unsigned int eqos_debug;	/* Default value */
+#define	DPRINTF(FLAG, FORMAT, ...)			 \
+	if (sc->sc_debug & FLAG)			 \
 		device_printf(sc->sc_dev, "%s: " FORMAT, \
 		    __func__, ##__VA_ARGS__)
 #else
 #define	DPRINTF(FLAG, FORMAT, ...)	((void)0)
 #endif
-#define	EDEB_NOTE		1U<<0
-#define	EDEB_INTR		1U<<1
-#define	EDEB_RXRING		1U<<2
-#define	EDEB_TXRING		1U<<3
 
 #ifdef NET_MPSAFE
 #define	EQOS_MPSAFE		1
@@ -85,7 +91,7 @@ unsigned int eqos_debug;
 #define	CALLOUT_FLAGS		0
 #endif
 
-#define	DESC_BOUNDARY		(1ULL << 32)
+#define	DESC_BOUNDARY		((sizeof(bus_size_t) > 4) ? (1ULL << 32) : 0)
 #define	DESC_ALIGN		sizeof(struct eqos_dma_desc)
 #define	TX_DESC_COUNT		EQOS_DMA_DESC_COUNT
 #define	TX_DESC_SIZE		(TX_DESC_COUNT * DESC_ALIGN)
@@ -118,6 +124,15 @@ unsigned int eqos_debug;
 #define	WR4(sc, reg, val)		\
 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
 
+static void	eqos_init_sysctls(struct eqos_softc *);
+static int	eqos_sysctl_tx_cur_handler(SYSCTLFN_PROTO);
+static int	eqos_sysctl_tx_end_handler(SYSCTLFN_PROTO);
+static int	eqos_sysctl_rx_cur_handler(SYSCTLFN_PROTO);
+static int	eqos_sysctl_rx_end_handler(SYSCTLFN_PROTO);
+#ifdef EQOS_DEBUG
+static int	eqos_sysctl_debug_handler(SYSCTLFN_PROTO);
+#endif
+
 static int
 eqos_mii_readreg(device_t dev, int phy, int reg, uint16_t *val)
 {
@@ -128,8 +143,7 @@ eqos_mii_readreg(device_t dev, int phy, 
 	addr = sc->sc_clock_range |
 	    (phy << GMAC_MAC_MDIO_ADDRESS_PA_SHIFT) |
 	    (reg << GMAC_MAC_MDIO_ADDRESS_RDA_SHIFT) |
-	    GMAC_MAC_MDIO_ADDRESS_GOC_READ |
-	    GMAC_MAC_MDIO_ADDRESS_GB;
+	    GMAC_MAC_MDIO_ADDRESS_GOC_READ | GMAC_MAC_MDIO_ADDRESS_GB;
 	WR4(sc, GMAC_MAC_MDIO_ADDRESS, addr);
 
 	delay(10000);
@@ -163,8 +177,7 @@ eqos_mii_writereg(device_t dev, int phy,
 	addr = sc->sc_clock_range |
 	    (phy << GMAC_MAC_MDIO_ADDRESS_PA_SHIFT) |
 	    (reg << GMAC_MAC_MDIO_ADDRESS_RDA_SHIFT) |
-	    GMAC_MAC_MDIO_ADDRESS_GOC_WRITE |
-	    GMAC_MAC_MDIO_ADDRESS_GB;
+	    GMAC_MAC_MDIO_ADDRESS_GOC_WRITE | GMAC_MAC_MDIO_ADDRESS_GB;
 	WR4(sc, GMAC_MAC_MDIO_ADDRESS, addr);
 
 	delay(10000);
@@ -190,7 +203,7 @@ eqos_update_link(struct eqos_softc *sc)
 {
 	struct mii_data * const mii = &sc->sc_mii;
 	uint64_t baudrate;
-	uint32_t conf;
+	uint32_t conf, flow;
 
 	baudrate = ifmedia_baudrate(mii->mii_media_active);
 
@@ -214,13 +227,28 @@ eqos_update_link(struct eqos_softc *sc)
 		break;
 	}
 
+	/* Set duplex. */
 	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) {
 		conf |= GMAC_MAC_CONFIGURATION_DM;
 	} else {
 		conf &= ~GMAC_MAC_CONFIGURATION_DM;
 	}
-
 	WR4(sc, GMAC_MAC_CONFIGURATION, conf);
+
+	/* Set TX flow control. */
+	if (mii->mii_media_active & IFM_ETH_TXPAUSE) {
+		flow = GMAC_MAC_Q0_TX_FLOW_CTRL_TFE;
+		flow |= 0xFFFFU << GMAC_MAC_Q0_TX_FLOW_CTRL_PT_SHIFT;
+	} else
+		flow = 0;
+	WR4(sc, GMAC_MAC_Q0_TX_FLOW_CTRL, flow);
+
+	/* Set RX flow control. */
+	if (mii->mii_media_active & IFM_ETH_RXPAUSE)
+		flow = GMAC_MAC_RX_FLOW_CTRL_RFE;
+	else
+		flow = 0;
+	WR4(sc, GMAC_MAC_RX_FLOW_CTRL, flow);
 }
 
 static void
@@ -254,6 +282,10 @@ eqos_setup_txdesc(struct eqos_softc *sc,
 {
 	uint32_t tdes2, tdes3;
 
+	DPRINTF(EDEB_TXRING, "preparing desc %u\n", index);
+
+	EQOS_ASSERT_TXLOCKED(sc);
+
 	if (paddr == 0 || len == 0) {
 		DPRINTF(EDEB_TXRING,
 		    "tx for desc %u done!\n", index);
@@ -267,13 +299,14 @@ eqos_setup_txdesc(struct eqos_softc *sc,
 		++sc->sc_tx.queued;
 	}
 
-	KASSERT(!EQOS_HW_FEATURE_ADDR64_32BIT(sc) || (paddr >> 32) == 0);
+	KASSERT(!EQOS_HW_FEATURE_ADDR64_32BIT(sc) ||
+	    ((uint64_t)paddr >> 32) == 0);
 
 	sc->sc_tx.desc_ring[index].tdes0 = htole32((uint32_t)paddr);
-	sc->sc_tx.desc_ring[index].tdes1 = htole32((uint32_t)(paddr >> 32));
+	sc->sc_tx.desc_ring[index].tdes1
+	    = htole32((uint32_t)((uint64_t)paddr >> 32));
 	sc->sc_tx.desc_ring[index].tdes2 = htole32(tdes2 | len);
 	sc->sc_tx.desc_ring[index].tdes3 = htole32(tdes3 | total_len);
-	DPRINTF(EDEB_TXRING, "preparing desc %u\n", index);
 }
 
 static int
@@ -284,6 +317,8 @@ eqos_setup_txbuf(struct eqos_softc *sc, 
 	uint32_t flags;
 	bool nospace;
 
+	DPRINTF(EDEB_TXRING, "preparing desc %u\n", index);
+
 	/* at least one descriptor free ? */
 	if (sc->sc_tx.queued >= TX_DESC_COUNT - 1)
 		return -1;
@@ -353,8 +388,11 @@ static void
 eqos_setup_rxdesc(struct eqos_softc *sc, int index, bus_addr_t paddr)
 {
 
+	DPRINTF(EDEB_RXRING, "preparing desc %u\n", index);
+
 	sc->sc_rx.desc_ring[index].tdes0 = htole32((uint32_t)paddr);
-	sc->sc_rx.desc_ring[index].tdes1 = htole32((uint32_t)(paddr >> 32));
+	sc->sc_rx.desc_ring[index].tdes1 =
+	    htole32((uint32_t)((uint64_t)paddr >> 32));
 	sc->sc_rx.desc_ring[index].tdes2 = htole32(0);
 	bus_dmamap_sync(sc->sc_dmat, sc->sc_rx.desc_map,
 	    DESC_OFF(index), offsetof(struct eqos_dma_desc, tdes3),
@@ -368,6 +406,8 @@ eqos_setup_rxbuf(struct eqos_softc *sc, 
 {
 	int error;
 
+	DPRINTF(EDEB_RXRING, "preparing desc %u\n", index);
+
 #if MCLBYTES >= (EQOS_RXDMA_SIZE + ETHER_ALIGN)
 	m_adj(m, ETHER_ALIGN);
 #endif
@@ -401,6 +441,7 @@ eqos_alloc_mbufcl(struct eqos_softc *sc)
 static void
 eqos_enable_intr(struct eqos_softc *sc)
 {
+
 	WR4(sc, GMAC_DMA_CHAN0_INTR_ENABLE,
 	    GMAC_DMA_CHAN0_INTR_ENABLE_NIE |
 	    GMAC_DMA_CHAN0_INTR_ENABLE_AIE |
@@ -412,6 +453,7 @@ eqos_enable_intr(struct eqos_softc *sc)
 static void
 eqos_disable_intr(struct eqos_softc *sc)
 {
+
 	WR4(sc, GMAC_DMA_CHAN0_INTR_ENABLE, 0);
 }
 
@@ -437,6 +479,7 @@ eqos_tick(void *softc)
 static uint32_t
 eqos_bitrev32(uint32_t x)
 {
+
 	x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
 	x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
 	x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
@@ -536,7 +579,7 @@ eqos_init_rings(struct eqos_softc *sc, i
 	sc->sc_rx_receiving_m_last = NULL;
 
 	WR4(sc, GMAC_DMA_CHAN0_TX_BASE_ADDR_HI,
-	    (uint32_t)(sc->sc_tx.desc_ring_paddr >> 32));
+	    (uint32_t)((uint64_t)sc->sc_tx.desc_ring_paddr >> 32));
 	WR4(sc, GMAC_DMA_CHAN0_TX_BASE_ADDR,
 	    (uint32_t)sc->sc_tx.desc_ring_paddr);
 	WR4(sc, GMAC_DMA_CHAN0_TX_RING_LEN, TX_DESC_COUNT - 1);
@@ -545,7 +588,7 @@ eqos_init_rings(struct eqos_softc *sc, i
 
 	sc->sc_rx.cur = sc->sc_rx.next = sc->sc_rx.queued = 0;
 	WR4(sc, GMAC_DMA_CHAN0_RX_BASE_ADDR_HI,
-	    (uint32_t)(sc->sc_rx.desc_ring_paddr >> 32));
+	    (uint32_t)((uint64_t)sc->sc_rx.desc_ring_paddr >> 32));
 	WR4(sc, GMAC_DMA_CHAN0_RX_BASE_ADDR,
 	    (uint32_t)sc->sc_rx.desc_ring_paddr);
 	WR4(sc, GMAC_DMA_CHAN0_RX_RING_LEN, RX_DESC_COUNT - 1);
@@ -584,12 +627,16 @@ eqos_init_locked(struct eqos_softc *sc)
 	val |= GMAC_DMA_CHAN0_CONTROL_PBLX8;
 	WR4(sc, GMAC_DMA_CHAN0_CONTROL, val);
 	val = RD4(sc, GMAC_DMA_CHAN0_TX_CONTROL);
+	val &= ~GMAC_DMA_CHAN0_TX_CONTROL_TXPBL_MASK;
+	val |= (sc->sc_dma_txpbl << GMAC_DMA_CHAN0_TX_CONTROL_TXPBL_SHIFT);
 	val |= GMAC_DMA_CHAN0_TX_CONTROL_OSP;
 	val |= GMAC_DMA_CHAN0_TX_CONTROL_START;
 	WR4(sc, GMAC_DMA_CHAN0_TX_CONTROL, val);
 	val = RD4(sc, GMAC_DMA_CHAN0_RX_CONTROL);
-	val &= ~GMAC_DMA_CHAN0_RX_CONTROL_RBSZ_MASK;
+	val &= ~(GMAC_DMA_CHAN0_RX_CONTROL_RBSZ_MASK |
+	    GMAC_DMA_CHAN0_RX_CONTROL_RXPBL_MASK);
 	val |= (MCLBYTES << GMAC_DMA_CHAN0_RX_CONTROL_RBSZ_SHIFT);
+	val |= (sc->sc_dma_rxpbl << GMAC_DMA_CHAN0_RX_CONTROL_RXPBL_SHIFT);
 	val |= GMAC_DMA_CHAN0_RX_CONTROL_START;
 	WR4(sc, GMAC_DMA_CHAN0_RX_CONTROL, val);
 
@@ -626,14 +673,12 @@ eqos_init_locked(struct eqos_softc *sc)
 	val |= __SHIFTIN(rqs, GMAC_MTL_RXQ0_OPERATION_MODE_RQS);
 	WR4(sc, GMAC_MTL_RXQ0_OPERATION_MODE, val);
 
-	/* Enable flow control */
-	val = RD4(sc, GMAC_MAC_Q0_TX_FLOW_CTRL);
-	val |= 0xFFFFU << GMAC_MAC_Q0_TX_FLOW_CTRL_PT_SHIFT;
-	val |= GMAC_MAC_Q0_TX_FLOW_CTRL_TFE;
-	WR4(sc, GMAC_MAC_Q0_TX_FLOW_CTRL, val);
-	val = RD4(sc, GMAC_MAC_RX_FLOW_CTRL);
-	val |= GMAC_MAC_RX_FLOW_CTRL_RFE;
-	WR4(sc, GMAC_MAC_RX_FLOW_CTRL, val);
+	/*
+	 * Disable flow control.
+	 * It'll be configured later from the negotiated result.
+	 */
+	WR4(sc, GMAC_MAC_Q0_TX_FLOW_CTRL, 0);
+	WR4(sc, GMAC_MAC_RX_FLOW_CTRL, 0);
 
 	/* set RX queue mode. must be in DCB mode. */
 	val = __SHIFTIN(GMAC_RXQ_CTRL0_EN_DCB, GMAC_RXQ_CTRL0_EN_MASK);
@@ -791,7 +836,8 @@ eqos_rxintr(struct eqos_softc *sc, int q
 			    "b\x13" "DE\0"	/* 19 */
 			    "b\x0f" "ES\0"	/* 15 */
 			    "\0", tdes3);
-			DPRINTF(EDEB_NOTE, "rxdesc[%d].tdes3=%s\n", index, buf);
+			DPRINTF(EDEB_NOTE,
+			    "rxdesc[%d].tdes3=%s\n", index, buf);
 #endif
 			if_statinc(ifp, if_ierrors);
 			if (m0 != NULL) {
@@ -876,6 +922,8 @@ eqos_rxintr(struct eqos_softc *sc, int q
 	sc->sc_rx_receiving_m = m0;
 	sc->sc_rx_receiving_m_last = mprev;
 
+	DPRINTF(EDEB_RXRING, "sc_rx.cur %u -> %u\n",
+	    sc->sc_rx.cur, index);
 	sc->sc_rx.cur = index;
 
 	if (pkts != 0) {
@@ -895,6 +943,7 @@ eqos_txintr(struct eqos_softc *sc, int q
 	DPRINTF(EDEB_INTR, "qid: %u\n", qid);
 
 	EQOS_ASSERT_LOCKED(sc);
+	EQOS_ASSERT_TXLOCKED(sc);
 
 	for (i = sc->sc_tx.next; sc->sc_tx.queued > 0; i = TX_NEXT(i)) {
 		KASSERT(sc->sc_tx.queued > 0);
@@ -1053,7 +1102,7 @@ eqos_intr_mtl(struct eqos_softc *sc, uin
 		}
 		if (new_status) {
 			new_status |= (ictrl &
-			    (GMAC_MTL_Q0_INTERRUPT_CTRL_STATUS_RXOIE|
+			    (GMAC_MTL_Q0_INTERRUPT_CTRL_STATUS_RXOIE |
 			     GMAC_MTL_Q0_INTERRUPT_CTRL_STATUS_TXUIE));
 			WR4(sc, GMAC_MTL_Q0_INTERRUPT_CTRL_STATUS, new_status);
 		}
@@ -1099,7 +1148,9 @@ eqos_intr(void *arg)
 	}
 
 	if ((dma_status & GMAC_DMA_CHAN0_STATUS_TI) != 0) {
+		EQOS_TXLOCK(sc);
 		eqos_txintr(sc, 0);
+		EQOS_TXUNLOCK(sc);
 		if_schedule_deferred_start(ifp);
 		sc->sc_ev_txintr.ev_count++;
 	}
@@ -1202,8 +1253,13 @@ eqos_get_eaddr(struct eqos_softc *sc, ui
 		return;
 	}
 
-	maclo = htobe32(RD4(sc, GMAC_MAC_ADDRESS0_LOW));
-	machi = htobe16(RD4(sc, GMAC_MAC_ADDRESS0_HIGH) & 0xFFFF);
+	maclo = RD4(sc, GMAC_MAC_ADDRESS0_LOW);
+	machi = RD4(sc, GMAC_MAC_ADDRESS0_HIGH) & 0xFFFF;
+	if ((maclo & 0x00000001) != 0) {
+		aprint_error_dev(sc->sc_dev,
+		    "Wrong MAC address. Clear the multicast bit.\n");
+		maclo &= ~0x00000001;
+	}
 
 	if (maclo == 0xFFFFFFFF && machi == 0xFFFF) {
 		/* Create one */
@@ -1220,6 +1276,24 @@ eqos_get_eaddr(struct eqos_softc *sc, ui
 }
 
 static void
+eqos_get_dma_pbl(struct eqos_softc *sc)
+{
+	prop_dictionary_t prop = device_properties(sc->sc_dev);
+	uint32_t pbl;
+
+	/* Set default values. */
+	sc->sc_dma_txpbl = sc->sc_dma_rxpbl = EQOS_DMA_PBL_DEFAULT;
+
+	/* Get values from props. */
+	if (prop_dictionary_get_uint32(prop, "snps,pbl", &pbl) && pbl)
+		sc->sc_dma_txpbl = sc->sc_dma_rxpbl = pbl;
+	if (prop_dictionary_get_uint32(prop, "snps,txpbl", &pbl) && pbl)
+		sc->sc_dma_txpbl = pbl;
+	if (prop_dictionary_get_uint32(prop, "snps,rxpbl", &pbl) && pbl)
+		sc->sc_dma_rxpbl = pbl;
+}
+
+static void
 eqos_axi_configure(struct eqos_softc *sc)
 {
 	prop_dictionary_t prop = device_properties(sc->sc_dev);
@@ -1261,6 +1335,10 @@ eqos_setup_dma(struct eqos_softc *sc, in
 	struct mbuf *m;
 	int error, nsegs, i;
 
+	/* Set back pointer */
+	sc->sc_tx.sc = sc;
+	sc->sc_rx.sc = sc;
+
 	/* Setup TX ring */
 	error = bus_dmamap_create(sc->sc_dmat, TX_DESC_SIZE, 1, TX_DESC_SIZE,
 	    DESC_BOUNDARY, BUS_DMA_WAITOK, &sc->sc_tx.desc_map);
@@ -1298,7 +1376,9 @@ eqos_setup_dma(struct eqos_softc *sc, in
 			    "cannot create TX buffer map\n");
 			return error;
 		}
+		EQOS_TXLOCK(sc);
 		eqos_setup_txdesc(sc, i, 0, 0, 0, 0);
+		EQOS_TXUNLOCK(sc);
 	}
 
 	/* Setup RX ring */
@@ -1364,16 +1444,20 @@ eqos_attach(struct eqos_softc *sc)
 	struct ifnet * const ifp = &sc->sc_ec.ec_if;
 	uint8_t eaddr[ETHER_ADDR_LEN];
 	u_int userver, snpsver;
-	int mii_flags = 0;
 	int error;
 	int n;
 
+#ifdef EQOS_DEBUG
+	/* Load the default debug flags. */
+	sc->sc_debug = eqos_debug;
+#endif
+
 	const uint32_t ver = RD4(sc, GMAC_MAC_VERSION);
 	userver = (ver & GMAC_MAC_VERSION_USERVER_MASK) >>
 	    GMAC_MAC_VERSION_USERVER_SHIFT;
 	snpsver = ver & GMAC_MAC_VERSION_SNPSVER_MASK;
 
-	if (snpsver != 0x51) {
+	if ((snpsver < 0x51) || (snpsver > 0x52)) {
 		aprint_error(": EQOS version 0x%02xx not supported\n",
 		    snpsver);
 		return ENXIO;
@@ -1393,6 +1477,8 @@ eqos_attach(struct eqos_softc *sc)
 	} else if (sc->sc_csr_clock < 250000000) {
 		sc->sc_clock_range = GMAC_MAC_MDIO_ADDRESS_CR_150_250;
 	} else if (sc->sc_csr_clock < 300000000) {
+		sc->sc_clock_range = GMAC_MAC_MDIO_ADDRESS_CR_250_300;
+	} else if (sc->sc_csr_clock < 500000000) {
 		sc->sc_clock_range = GMAC_MAC_MDIO_ADDRESS_CR_300_500;
 	} else if (sc->sc_csr_clock < 800000000) {
 		sc->sc_clock_range = GMAC_MAC_MDIO_ADDRESS_CR_500_800;
@@ -1432,7 +1518,8 @@ eqos_attach(struct eqos_softc *sc)
 	callout_setfunc(&sc->sc_stat_ch, eqos_tick, sc);
 
 	eqos_get_eaddr(sc, eaddr);
-	aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n", ether_sprintf(eaddr));
+	aprint_normal_dev(sc->sc_dev,
+	    "Ethernet address %s\n", ether_sprintf(eaddr));
 
 	/* Soft reset EMAC core */
 	error = eqos_reset(sc);
@@ -1440,12 +1527,16 @@ eqos_attach(struct eqos_softc *sc)
 		return error;
 	}
 
+	/* Get DMA burst length */
+	eqos_get_dma_pbl(sc);
+
 	/* Configure AXI Bus mode parameters */
 	eqos_axi_configure(sc);
 
 	/* Setup DMA descriptors */
 	if (eqos_setup_dma(sc, 0) != 0) {
-		aprint_error_dev(sc->sc_dev, "failed to setup DMA descriptors\n");
+		aprint_error_dev(sc->sc_dev,
+		    "failed to setup DMA descriptors\n");
 		return EINVAL;
 	}
 
@@ -1477,7 +1568,7 @@ eqos_attach(struct eqos_softc *sc)
 	mii->mii_writereg = eqos_mii_writereg;
 	mii->mii_statchg = eqos_mii_statchg;
 	mii_attach(sc->sc_dev, mii, 0xffffffff, sc->sc_phy_id, MII_OFFSET_ANY,
-	    mii_flags);
+	    MIIF_DOPAUSE);
 
 	if (LIST_EMPTY(&mii->mii_phys)) {
 		aprint_error_dev(sc->sc_dev, "no PHY found!\n");
@@ -1532,8 +1623,229 @@ eqos_attach(struct eqos_softc *sc)
 	/* Attach ethernet interface */
 	ether_ifattach(ifp, eaddr);
 
+	eqos_init_sysctls(sc);
+
 	rnd_attach_source(&sc->sc_rndsource, ifp->if_xname, RND_TYPE_NET,
 	    RND_FLAG_DEFAULT);
 
 	return 0;
 }
+
+static void
+eqos_init_sysctls(struct eqos_softc *sc)
+{
+	struct sysctllog **log;
+	const struct sysctlnode *rnode, *qnode, *cnode;
+	const char *dvname;
+	int i, rv;
+
+	log = &sc->sc_sysctllog;
+	dvname = device_xname(sc->sc_dev);
+
+	rv = sysctl_createv(log, 0, NULL, &rnode,
+	    0, CTLTYPE_NODE, dvname,
+	    SYSCTL_DESCR("eqos information and settings"),
+	    NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL);
+	if (rv != 0)
+		goto err;
+
+	for (i = 0; i < 1; i++) {
+		struct eqos_ring *txr = &sc->sc_tx;
+		struct eqos_ring *rxr = &sc->sc_rx;
+		const unsigned char *name = "q0";
+
+		if (sysctl_createv(log, 0, &rnode, &qnode,
+		    0, CTLTYPE_NODE,
+		    name, SYSCTL_DESCR("Queue Name"),
+		    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL) != 0)
+			break;
+
+		if (sysctl_createv(log, 0, &qnode, &cnode,
+		    CTLFLAG_READONLY, CTLTYPE_INT,
+		    "txs_cur", SYSCTL_DESCR("TX cur"),
+		    NULL, 0, &txr->cur,
+		    0, CTL_CREATE, CTL_EOL) != 0)
+			break;
+		if (sysctl_createv(log, 0, &qnode, &cnode,
+		    CTLFLAG_READONLY, CTLTYPE_INT,
+		    "txs_next", SYSCTL_DESCR("TX next"),
+		    NULL, 0, &txr->next,
+		    0, CTL_CREATE, CTL_EOL) != 0)
+			break;
+		if (sysctl_createv(log, 0, &qnode, &cnode,
+		    CTLFLAG_READONLY, CTLTYPE_INT,
+		    "txs_queued", SYSCTL_DESCR("TX queued"),
+		    NULL, 0, &txr->queued,
+		    0, CTL_CREATE, CTL_EOL) != 0)
+			break;
+		if (sysctl_createv(log, 0, &qnode, &cnode,
+		    CTLFLAG_READONLY, CTLTYPE_INT,
+		    "txr_cur", SYSCTL_DESCR("TX descriptor cur"),
+		    eqos_sysctl_tx_cur_handler, 0, (void *)txr,
+		    0, CTL_CREATE, CTL_EOL) != 0)
+			break;
+		if (sysctl_createv(log, 0, &qnode, &cnode,
+		    CTLFLAG_READONLY, CTLTYPE_INT,
+		    "txr_end", SYSCTL_DESCR("TX descriptor end"),
+		    eqos_sysctl_tx_end_handler, 0, (void *)txr,
+		    0, CTL_CREATE, CTL_EOL) != 0)
+			break;
+		if (sysctl_createv(log, 0, &qnode, &cnode,
+		    CTLFLAG_READONLY, CTLTYPE_INT,
+		    "rxs_cur", SYSCTL_DESCR("RX cur"),
+		    NULL, 0, &rxr->cur,
+		    0, CTL_CREATE, CTL_EOL) != 0)
+			break;
+		if (sysctl_createv(log, 0, &qnode, &cnode,
+		    CTLFLAG_READONLY, CTLTYPE_INT,
+		    "rxs_next", SYSCTL_DESCR("RX next"),
+		    NULL, 0, &rxr->next,
+		    0, CTL_CREATE, CTL_EOL) != 0)
+			break;
+		if (sysctl_createv(log, 0, &qnode, &cnode,
+		    CTLFLAG_READONLY, CTLTYPE_INT,
+		    "rxs_queued", SYSCTL_DESCR("RX queued"),
+		    NULL, 0, &rxr->queued,
+		    0, CTL_CREATE, CTL_EOL) != 0)
+			break;
+		if (sysctl_createv(log, 0, &qnode, &cnode,
+		    CTLFLAG_READONLY, CTLTYPE_INT,
+		    "rxr_cur", SYSCTL_DESCR("RX descriptor cur"),
+		    eqos_sysctl_rx_cur_handler, 0, (void *)rxr,
+		    0, CTL_CREATE, CTL_EOL) != 0)
+			break;
+		if (sysctl_createv(log, 0, &qnode, &cnode,
+		    CTLFLAG_READONLY, CTLTYPE_INT,
+		    "rxr_end", SYSCTL_DESCR("RX descriptor end"),
+		    eqos_sysctl_rx_end_handler, 0, (void *)rxr,
+		    0, CTL_CREATE, CTL_EOL) != 0)
+			break;
+	}
+
+#ifdef EQOS_DEBUG
+	rv = sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE,
+	    CTLTYPE_INT, "debug_flags",
+	    SYSCTL_DESCR(
+		    "Debug flags:\n"	\
+		    "\t0x01 NOTE\n"	\
+		    "\t0x02 INTR\n"	\
+		    "\t0x04 RX RING\n"	\
+		    "\t0x08 TX RING\n"),
+	    eqos_sysctl_debug_handler, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL);
+#endif
+
+	return;
+
+err:
+	sc->sc_sysctllog = NULL;
+	device_printf(sc->sc_dev, "%s: sysctl_createv failed, rv = %d\n",
+	    __func__, rv);
+}
+
+static int
+eqos_sysctl_tx_cur_handler(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node = *rnode;
+	struct eqos_ring *txq = (struct eqos_ring *)node.sysctl_data;
+	struct eqos_softc *sc = txq->sc;
+	uint32_t reg, index;
+
+	reg = RD4(sc, GMAC_DMA_CHAN0_CUR_TX_DESC);
+#if 0
+	printf("head  = %08x\n", (uint32_t)sc->sc_tx.desc_ring_paddr);
+	printf("cdesc = %08x\n", reg);
+	printf("index = %zu\n",
+	    (reg - (uint32_t)sc->sc_tx.desc_ring_paddr) /
+	    sizeof(struct eqos_dma_desc));
+#endif
+	if (reg == 0)
+		index = 0;
+	else {
+		index = (reg - (uint32_t)sc->sc_tx.desc_ring_paddr) /
+		    sizeof(struct eqos_dma_desc);
+	}
+	node.sysctl_data = &index;
+	return sysctl_lookup(SYSCTLFN_CALL(&node));
+}
+
+static int
+eqos_sysctl_tx_end_handler(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node = *rnode;
+	struct eqos_ring *txq = (struct eqos_ring *)node.sysctl_data;
+	struct eqos_softc *sc = txq->sc;
+	uint32_t reg, index;
+
+	reg = RD4(sc, GMAC_DMA_CHAN0_TX_END_ADDR);
+	if (reg == 0)
+		index = 0;
+	else {
+		index = (reg - (uint32_t)sc->sc_tx.desc_ring_paddr) /
+		    sizeof(struct eqos_dma_desc);
+	}
+	node.sysctl_data = &index;
+	return sysctl_lookup(SYSCTLFN_CALL(&node));
+}
+
+static int
+eqos_sysctl_rx_cur_handler(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node = *rnode;
+	struct eqos_ring *rxq = (struct eqos_ring *)node.sysctl_data;
+	struct eqos_softc *sc = rxq->sc;
+	uint32_t reg, index;
+
+	reg = RD4(sc, GMAC_DMA_CHAN0_CUR_RX_DESC);
+	if (reg == 0)
+		index = 0;
+	else {
+		index = (reg - (uint32_t)sc->sc_rx.desc_ring_paddr) /
+		    sizeof(struct eqos_dma_desc);
+	}
+	node.sysctl_data = &index;
+	return sysctl_lookup(SYSCTLFN_CALL(&node));
+}
+
+static int
+eqos_sysctl_rx_end_handler(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node = *rnode;
+	struct eqos_ring *rxq = (struct eqos_ring *)node.sysctl_data;
+	struct eqos_softc *sc = rxq->sc;
+	uint32_t reg, index;
+
+	reg = RD4(sc, GMAC_DMA_CHAN0_RX_END_ADDR);
+	if (reg == 0)
+		index = 0;
+	else {
+		index = (reg - (uint32_t)sc->sc_rx.desc_ring_paddr) /
+		    sizeof(struct eqos_dma_desc);
+	}
+	node.sysctl_data = &index;
+	return sysctl_lookup(SYSCTLFN_CALL(&node));
+}
+
+#ifdef EQOS_DEBUG
+static int
+eqos_sysctl_debug_handler(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node = *rnode;
+	struct eqos_softc *sc = (struct eqos_softc *)node.sysctl_data;
+	uint32_t dflags;
+	int error;
+
+	dflags = sc->sc_debug;
+	node.sysctl_data = &dflags;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+
+	if (error || newp == NULL)
+		return error;
+
+	sc->sc_debug = dflags;
+#if 0
+	/* Addd debug code here if you want. */
+#endif
+
+	return 0;
+}
+#endif

Index: src/sys/dev/ic/dwc_eqos_reg.h
diff -u src/sys/dev/ic/dwc_eqos_reg.h:1.6 src/sys/dev/ic/dwc_eqos_reg.h:1.6.4.1
--- src/sys/dev/ic/dwc_eqos_reg.h:1.6	Wed Aug 24 19:21:41 2022
+++ src/sys/dev/ic/dwc_eqos_reg.h	Fri Nov  3 08:56:36 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc_eqos_reg.h,v 1.6 2022/08/24 19:21:41 ryo Exp $ */
+/* $NetBSD: dwc_eqos_reg.h,v 1.6.4.1 2023/11/03 08:56:36 martin Exp $ */
 
 /*-
  * Copyright (c) 2022 Jared McNeill <jmcne...@invisible.ca>
@@ -94,7 +94,7 @@
 #define	GMAC_MAC_DEBUG				0x0114
 #define	GMAC_MAC_HW_FEATURE(n)			(0x011C + 0x4 * (n))
 #define	 GMAC_MAC_HW_FEATURE1_TXFIFOSIZE	__BITS(10,6)
-#define	 GMAC_MAC_HW_FEATURE1_RXFIFOSIZE	__BITS(5,0)
+#define	 GMAC_MAC_HW_FEATURE1_RXFIFOSIZE	__BITS(4,0)
 #define	 GMAC_MAC_HW_FEATURE1_ADDR64_SHIFT	14
 #define	 GMAC_MAC_HW_FEATURE1_ADDR64_MASK	(0x3U << GMAC_MAC_HW_FEATURE1_ADDR64_SHIFT)
 #define	 GMAC_MAC_HW_FEATURE1_ADDR64_32BIT	(0x0U << GMAC_MAC_HW_FEATURE1_ADDR64_SHIFT)
@@ -250,9 +250,13 @@
 #define	 GMAC_DMA_CHAN0_CONTROL_DSL_MASK	(0x7U << GMAC_DMA_CHAN0_CONTROL_DSL_SHIFT)
 #define	 GMAC_DMA_CHAN0_CONTROL_PBLX8		(1U << 16)
 #define	GMAC_DMA_CHAN0_TX_CONTROL		0x1104
+#define	 GMAC_DMA_CHAN0_TX_CONTROL_TXPBL_SHIFT	16
+#define	 GMAC_DMA_CHAN0_TX_CONTROL_TXPBL_MASK	(0x3FU << GMAC_DMA_CHAN0_TX_CONTROL_TXPBL_SHIFT)
 #define	 GMAC_DMA_CHAN0_TX_CONTROL_OSP		(1U << 4)
 #define	 GMAC_DMA_CHAN0_TX_CONTROL_START	(1U << 0)
 #define	GMAC_DMA_CHAN0_RX_CONTROL		0x1108
+#define	 GMAC_DMA_CHAN0_RX_CONTROL_RXPBL_SHIFT	16
+#define	 GMAC_DMA_CHAN0_RX_CONTROL_RXPBL_MASK	(0x3FU << GMAC_DMA_CHAN0_RX_CONTROL_RXPBL_SHIFT)
 #define	 GMAC_DMA_CHAN0_RX_CONTROL_RBSZ_SHIFT	1
 #define	 GMAC_DMA_CHAN0_RX_CONTROL_RBSZ_MASK	(0x3FFFU << GMAC_DMA_CHAN0_RX_CONTROL_RBSZ_SHIFT)
 #define	 GMAC_DMA_CHAN0_RX_CONTROL_START	(1U << 0)

Index: src/sys/dev/ic/dwc_eqos_var.h
diff -u src/sys/dev/ic/dwc_eqos_var.h:1.4 src/sys/dev/ic/dwc_eqos_var.h:1.4.4.1
--- src/sys/dev/ic/dwc_eqos_var.h:1.4	Wed Aug 24 19:22:37 2022
+++ src/sys/dev/ic/dwc_eqos_var.h	Fri Nov  3 08:56:36 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc_eqos_var.h,v 1.4 2022/08/24 19:22:37 ryo Exp $ */
+/* $NetBSD: dwc_eqos_var.h,v 1.4.4.1 2023/11/03 08:56:36 martin Exp $ */
 
 /*-
  * Copyright (c) 2022 Jared McNeill <jmcne...@invisible.ca>
@@ -36,6 +36,7 @@
 #include <dev/ic/dwc_eqos_reg.h>
 
 #define	EQOS_DMA_DESC_COUNT	256
+#define	EQOS_DMA_PBL_DEFAULT	8
 
 struct eqos_bufmap {
 	bus_dmamap_t		map;
@@ -43,6 +44,7 @@ struct eqos_bufmap {
 };
 
 struct eqos_ring {
+	struct eqos_softc	*sc;
 	bus_dmamap_t		desc_map;
 	bus_dma_segment_t	desc_dmaseg;
 	struct eqos_dma_desc	*desc_ring;
@@ -59,8 +61,9 @@ struct eqos_softc {
 	int			sc_phy_id;
 	uint32_t		sc_csr_clock;
 	uint32_t		sc_clock_range;
-
 	uint32_t		sc_hw_feature[4];
+	uint32_t		sc_dma_txpbl;
+	uint32_t		sc_dma_rxpbl;
 
 	struct ethercom		sc_ec;
 	struct mii_data		sc_mii;
@@ -77,6 +80,8 @@ struct eqos_softc {
 	struct mbuf		*sc_rx_receiving_m_last;
 
 	krndsource_t		sc_rndsource;
+	struct sysctllog	*sc_sysctllog;
+	uint32_t		sc_debug;
 
 	/* Indents indicate groups within evcnt. */
 	struct evcnt		sc_ev_intr;

Index: src/sys/dev/pci/files.pci
diff -u src/sys/dev/pci/files.pci:1.445.2.2 src/sys/dev/pci/files.pci:1.445.2.3
--- src/sys/dev/pci/files.pci:1.445.2.2	Sun Oct  8 13:19:34 2023
+++ src/sys/dev/pci/files.pci	Fri Nov  3 08:56:36 2023
@@ -1,4 +1,4 @@
-#	$NetBSD: files.pci,v 1.445.2.2 2023/10/08 13:19:34 martin Exp $
+#	$NetBSD: files.pci,v 1.445.2.3 2023/11/03 08:56:36 martin Exp $
 #
 # Config file and device description for machine-independent PCI code.
 # Included by ports that need it.  Requires that the SCSI files be
@@ -1172,6 +1172,10 @@ file	dev/pci/if_ena.c			ena
 file	external/bsd/ena-com/ena_com.c		ena
 file	external/bsd/ena-com/ena_eth_com.c	ena
 
+# PCI based DesignWare Ethernet QoS
+attach	eqos at pci with eqos_pci
+file	dev/pci/if_eqos_pci.c eqos_pci
+
 # Intel QuickAssist
 device qat: opencrypto, firmload
 attach qat at pci

Added files:

Index: src/sys/dev/pci/if_eqos_pci.c
diff -u /dev/null src/sys/dev/pci/if_eqos_pci.c:1.3.2.2
--- /dev/null	Fri Nov  3 08:56:37 2023
+++ src/sys/dev/pci/if_eqos_pci.c	Fri Nov  3 08:56:36 2023
@@ -0,0 +1,198 @@
+/* $NetBSD: if_eqos_pci.c,v 1.3.2.2 2023/11/03 08:56:36 martin Exp $ */
+
+/*-
+ * Copyright (c) 2023 Masanobu SAITOH <msai...@netbsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * TODO:
+ *	Use multi vector MSI to support multiqueue.
+ *
+ */
+
+#include "opt_net_mpsafe.h"
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: if_eqos_pci.c,v 1.3.2.2 2023/11/03 08:56:36 martin Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/rndsource.h>
+
+#include <net/if_ether.h>
+#include <net/if_media.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/mii/miivar.h>
+#include <dev/ic/dwc_eqos_var.h>
+
+#define EQOS_PCI_MAX_INTR	1
+
+static int eqos_pci_match(device_t, cfdata_t, void *);
+static void eqos_pci_attach(device_t, device_t, void *);
+
+struct eqos_pci_softc {
+	struct eqos_softc	sc_eqos;
+	pci_chipset_tag_t	sc_pc;
+	pcitag_t		sc_tag;
+	void			*sc_ihs[EQOS_PCI_MAX_INTR];
+	pci_intr_handle_t	*sc_intrs;
+	uint16_t		sc_pcidevid;
+};
+
+static const struct device_compatible_entry compat_data[] = {
+	{ .id = PCI_ID_CODE(PCI_VENDOR_INTEL,
+		    PCI_PRODUCT_INTEL_EHL_ETH) },
+	{ .id = PCI_ID_CODE(PCI_VENDOR_INTEL,
+		    PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_RGMII) },
+	{ .id = PCI_ID_CODE(PCI_VENDOR_INTEL,
+		    PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_RGMII) },
+	{ .id = PCI_ID_CODE(PCI_VENDOR_INTEL,
+		    PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_SGMII_1G) },
+	{ .id = PCI_ID_CODE(PCI_VENDOR_INTEL,
+		    PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_SGMII_1G) },
+	{ .id = PCI_ID_CODE(PCI_VENDOR_INTEL,
+		    PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_SGMII_2_5G) },
+	{ .id = PCI_ID_CODE(PCI_VENDOR_INTEL,
+		    PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_SGMII_2_5G) },
+
+	PCI_COMPAT_EOL
+};
+
+CFATTACH_DECL3_NEW(eqos_pci, sizeof(struct eqos_pci_softc),
+    eqos_pci_match, eqos_pci_attach, NULL, NULL, NULL, NULL,
+    0);
+
+static int
+eqos_pci_match(device_t parent, cfdata_t match, void *aux)
+{
+	struct pci_attach_args *pa =aux;
+
+	return pci_compatible_match(pa, compat_data);
+}
+
+static void
+eqos_pci_attach(device_t parent, device_t self, void *aux)
+{
+	struct eqos_pci_softc * const psc = device_private(self);
+	struct eqos_softc * const sc = &psc->sc_eqos;
+	struct pci_attach_args *pa =aux;
+	const pci_chipset_tag_t pc = pa->pa_pc;
+	const pcitag_t tag = pa->pa_tag;
+	prop_dictionary_t prop;
+	bus_space_tag_t memt;
+	bus_space_handle_t memh;
+	int counts[PCI_INTR_TYPE_SIZE];
+	char intrbuf[PCI_INTRSTR_LEN];
+	bus_size_t memsize;
+	pcireg_t memtype;
+	const char *intrstr;
+	uint32_t dma_pbl = 0;
+
+	psc->sc_pc = pc;
+	psc->sc_tag = tag;
+	psc->sc_pcidevid = PCI_PRODUCT(pa->pa_id);
+
+	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, PCI_BAR0);
+	if (pci_mapreg_map(pa, PCI_BAR0, memtype, 0, &memt, &memh, NULL,
+		&memsize) != 0) {
+		aprint_error(": can't map mem space\n");
+		return;
+	}
+	sc->sc_dev = self;
+	sc->sc_bst = memt;
+	sc->sc_bsh = memh;
+	prop = device_properties(sc->sc_dev);
+
+	if (pci_dma64_available(pa))
+		sc->sc_dmat = pa->pa_dmat64;
+	else
+		sc->sc_dmat = pa->pa_dmat;
+
+	sc->sc_phy_id = MII_PHY_ANY;
+	switch (psc->sc_pcidevid) {
+	case PCI_PRODUCT_INTEL_EHL_ETH:
+		sc->sc_csr_clock = 204800000;
+		dma_pbl = 32;
+		break;
+	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_RGMII:
+	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_RGMII:
+	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_SGMII_1G:
+	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_SGMII_1G:
+	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_SGMII_2_5G:
+	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_SGMII_2_5G:
+		sc->sc_dmat = pa->pa_dmat; /* 32bit DMA only */
+		sc->sc_csr_clock = 200000000;
+		dma_pbl = 32;
+		break;
+#if 0
+	case PCI_PRODUCT_INTEL_QUARTK_ETH:
+		dma_pbl = 16;
+#endif
+	default:
+		sc->sc_csr_clock = 200000000; /* XXX */
+	}
+
+	if (sc->sc_dmat == pa->pa_dmat64)
+		aprint_verbose(", 64-bit DMA");
+	else
+		aprint_verbose(", 32-bit DMA");
+
+	/* Defaults */
+	if (dma_pbl != 0) {
+		prop = device_properties(sc->sc_dev);
+		prop_dictionary_set_uint32(prop, "snps,pbl", dma_pbl);
+	}
+
+	if (eqos_attach(sc) != 0) {
+		aprint_error_dev(sc->sc_dev, "failed in eqos_attach()\n");
+		return;
+	}
+
+	/* Allocation settings */
+	counts[PCI_INTR_TYPE_MSI] = 1;
+	counts[PCI_INTR_TYPE_INTX] = 1;
+	if (pci_intr_alloc(pa, &psc->sc_intrs, counts, PCI_INTR_TYPE_MSI) != 0)
+	{
+		aprint_error_dev(sc->sc_dev, "failed to allocate interrupt\n");
+		return;
+	}
+	intrstr = pci_intr_string(pc, psc->sc_intrs[0], intrbuf,
+	    sizeof(intrbuf));
+	pci_intr_setattr(pc, &psc->sc_intrs[0], PCI_INTR_MPSAFE, true);
+	psc->sc_ihs[0] = pci_intr_establish_xname(pc, psc->sc_intrs[0],
+	    IPL_NET, eqos_intr, sc, device_xname(self));
+
+	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
+
+	if (pmf_device_register(self, NULL, NULL))
+		pmf_class_network_register(self, &sc->sc_ec.ec_if);
+	else
+		aprint_error_dev(self, "couldn't establish power handler\n");
+}

Reply via email to