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"); +}