Index: share/man/man4/Makefile =================================================================== --- share/man/man4/Makefile +++ share/man/man4/Makefile @@ -107,6 +107,7 @@ cdceem.4 \ cfi.4 \ cfumass.4 \ + ${_cgem.4} \ ch.4 \ chromebook_platform.4 \ ciss.4 \ @@ -879,6 +880,12 @@ _virtio_random.4= virtio_random.4 _virtio_scsi.4= virtio_scsi.4 _vtnet.4= vtnet.4 +.endif + +.if ${MACHINE_ARCH} == "armv7" || ${MACHINE_ARCH} == "aarch64" || \ + ${MACHINE_ARCH} == "riscv64" +_cgem.4= cgem.4 +MLINKS+=cgem.4 if_cgem.4 .endif .if empty(MAN_ARCH) Index: share/man/man4/cgem.4 =================================================================== --- share/man/man4/cgem.4 +++ share/man/man4/cgem.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD: head/share/man/man4/man4.arm/cgem.4 301591 2016-06-08 09:36:07Z trasz $ .\" -.Dd August 26, 2014 +.Dd March 27, 2020 .Dt CGEM 4 .Os .Sh NAME @@ -44,7 +44,8 @@ .Nm driver provides support for the Cadence GEM (Gigabit Ethernet MAC). The Cadence GEM is used in some SoC (System on a Chip) devices such as -the Xilinx Zynq-7000 and the Atmel SAMA5D3. +the Xilinx Zynq-7000, the Xilinx Zynq UltraScale+, and the SiFive +HiFive Unleashed. .Pp The .Nm @@ -284,7 +285,7 @@ variables that count packets discarded by the hardware (see below). .Pp -The GEM used in the Zynq-7000 has a bug such that the receiver can +The GEM used in the Zynq-7000 has a bug such that the receiver can potentially freeze up under a high load. The issue is described in sec. 16.7 "Known Issues" of the Zynq-7000 SoC Technical Reference Manual (Xilinx @@ -292,7 +293,9 @@ The .Nm driver implements the work-around suggested in the manual. -If the bug does not exist in other versions of this device, the -work-around can be disabled by setting the dev.cgem.%d.rxhangwar +It is believed that the bug does not exist in the Zynq UltraScale+ and +SiFive SoCs so the work-around is disabled in those instances and enabled +in all others. The work-around can be disabled by setting the +dev.cgem.%d.rxhangwar .Xr sysctl 8 variable to 0. Index: share/man/man4/man4.arm/Makefile =================================================================== --- share/man/man4/man4.arm/Makefile +++ share/man/man4/man4.arm/Makefile @@ -8,7 +8,6 @@ aw_spi.4 \ aw_syscon.4 \ bcm283x_pwm.4 \ - cgem.4 \ devcfg.4 \ imx6_ahci.4 \ imx6_snvs.4 \ @@ -16,8 +15,7 @@ mge.4 \ ti_adc.4 -MLINKS= cgem.4 if_cgem.4 -MLINKS+= imx_wdog.4 imxwdt.4 +MLINKS= imx_wdog.4 imxwdt.4 MLINKS+= mge.4 if_mge.4 MANSUBDIR=/arm Index: share/man/man4/man4.arm/cgem.4 =================================================================== --- share/man/man4/man4.arm/cgem.4 +++ share/man/man4/man4.arm/cgem.4 @@ -1,298 +0,0 @@ -.\" -.\" Copyright (c) 2014 Thomas Skibo -.\" 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. The name of the author may not be used to endorse or promote products -.\" derived from this software without specific prior written permission. -.\" -.\" 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. -.\" -.\" $FreeBSD$ -.\" -.Dd August 26, 2014 -.Dt CGEM 4 -.Os -.Sh NAME -.Nm cgem -.Nd "Cadence GEM Gigabit Ethernet driver" -.Sh SYNOPSIS -To compile this driver into the kernel, -place the following lines in your -kernel configuration file: -.Bd -ragged -offset indent -.Cd "device ether" -.Cd "device miibus" -.Cd "device cgem" -.Ed -.Sh DESCRIPTION -The -.Nm -driver provides support for the Cadence GEM (Gigabit Ethernet MAC). -The Cadence GEM is used in some SoC (System on a Chip) devices such as -the Xilinx Zynq-7000 and the Atmel SAMA5D3. -.Pp -The -.Nm -driver supports the following media types: -.Bl -tag -width ".Cm 10baseT/UTP" -.It Cm autoselect -Enable autoselection of the media type and options. -The user can manually override -the autoselected mode using -.Xr ifconfig 8 -or by adding media options to -.Xr rc.conf 5 . -.It Cm 10baseT/UTP -Set 10Mbps operation. -The -.Xr ifconfig 8 -.Cm mediaopt -option can also be used to select either -.Cm full-duplex -or -.Cm half-duplex -modes. -.It Cm 100baseTX -Set 100Mbps (Fast Ethernet) operation. -The -.Xr ifconfig 8 -.Cm mediaopt -option can also be used to select either -.Cm full-duplex -or -.Cm half-duplex -modes. -.It Cm 1000baseT -Set 1000Mbps (Gigabit Ethernet) operation over twisted pair. -The GEM supports 1000Mbps in -.Cm full-duplex -mode only. -.El -.Pp -The -.Nm -driver supports the following media options: -.Bl -tag -width ".Cm full-duplex" -.It Cm full-duplex -Force full-duplex operation. -.It Cm half-duplex -Force half-duplex operation. -.El -.Pp -The driver provides support for TCP/UDP/IP checksum offloading (although -disabled by default). -The device and driver also support 1536-byte frames for VLANs (vlanmtu). -.Sh SYSCTL VARIABLES -The following variables are available as both -.Xr sysctl 8 -variables and -.Xr loader 8 -tunables: -.Bl -tag -width "xxxxxxxx" -.It Va dev.cgem.%d.rxbufs -The number of receive buffers allocated to the hardware. -The default value is 256. -The maximum value is 511. -If this number is increased while the interface is UP, it will not -take effect until the next packet is received. -If this number is decreased while the interface is UP, buffers will -not be immediately removed from the receive buffer ring but the -number of buffers will decrease as packets are received until it -reaches the new value. -.It Va dev.cgem.%d.rxhangwar -This tunable enables a work-around to recover from receive hangs. -The default value is 1. -Set to 0 to disable the work-around. -.El -.Pp -The following read-only variables are available as -.Xr sysctl 8 -variables: -.Bl -tag -width "xxxxxxxx" -.It Va dev.cgem.%d._rxoverruns -This variable counts the number of receive packet buffer overrun interrupts. -.It Va dev.cgem.%d._rxnobufs -This variable counts the number of interrupts due to the GEM buffer ring -going empty. -.It Va dev.cgem.%d._rxdmamapfails -This variable is the number of times bus_dmamap_load_mbuf_sg(9) failed in -the receive path. -.It Va dev.cgem.%d._txfull -The number of times the GEM's transmit ring was full. -.It Va dev.cgem.%d._txdmamapfails -This variable is the number of times bus_dmamap_load_mbuf_sg(9) failed in -the transmit path. -.It Va dev.cgem.%d._txdefrags -This variable is the number of times the driver needed to call m_defrag(9) -because a packet queued for transmit had too many DMA segments. -.It Va dev.cgem.%d._txdefragfails -This variable is the number of times -.Xr m_defrag 9 -failed. -.It Va dev.cgem.%d.stats.* -The following variables are useful MAC counters supplied by the hardware: -.It Va dev.cgem.%d.stats.tx_bytes -A 64-bit counter of the number of bytes transmitted in frames without error. -.It Va dev.cgem.%d.stats.tx_frames -Counter of frames transmitted without error excluding pause frames. -.It Va dev.cgem.%d.stats.tx_frames_bcast -Counter of broadcast frames transmitted without error excluding -pause frames. -.It Va dev.cgem.%d.stats.tx_frames_multi -Counter of multicast frames transmitted without error excluding -pause frames. -.It Va dev.cgem.%d.stats.tx_frames_pause -Counter of pause frames transmitted without error. -.It Va dev.cgem.%d.stats.tx_frames_64b -Counter of 64 byte frames transmitted without error. -.It Va dev.cgem.%d.stats.tx_frames_65to127b -Counter of 65 to 127 byte frames transmitted without error. -.It Va dev.cgem.%d.stats.tx_frames_128to255b -Counter of 128 to 255 byte frames transmitted without error. -.It Va dev.cgem.%d.stats.tx_frames_256to511b -Counter of 256 to 511 byte frames transmitted without error. -.It Va dev.cgem.%d.stats.tx_frames_512to1023b -Counter of 512 to 1023 byte frames transmitted without error. -.It Va dev.cgem.%d.stats.tx_frames_1024to1536b -Counter of 1024 to 1536 byte frames transmitted without error. -.It Va dev.cgem.%d.stats.tx_under_runs -Counter of frames not transmitted due to a transmit underrun. -.It Va dev.cgem.%d.stats.tx_single_collisn -Counter of frames experiencing a single collision before being successfully -transmitted. -.It Va dev.cgem.%d.stats.tx_multi_collisn -Counter of frames experiencing between 2 and 15 collisions before -being successfully transmitted. -.It Va dev.cgem.%d.stats.tx_excsv_collisn -Counter of frames that failed to transmit because they experienced 16 -collisions. -.It Va dev.cgem.%d.stats.tx_late_collisn -Counter of frames that experienced a late collision. -.It Va dev.cgem.%d.stats.tx_deferred_frames -Counter of frames experiencing deferral due to carrier sense being -active on their first attempt at transmission. -.It Va dev.cgem.%d.stats.tx_carrier_sense_errs -Counter of frames transmitted where carrier sense was not seen during -transmission or where carrier sense was deasserted after being asserted -in a transmit frame without collision. -.It Va dev.cgem.%d.stats.rx_bytes -A 64-bit counter of bytes received without error excluding pause -frames. -.It Va dev.cgem.%d.stats.rx_frames -Counter of frames received without error excluding pause frames. -.It Va dev.cgem.%d.stats.rx_frames_bcast -Counter of broadcast frames receive without error excluding pause frames. -.It Va dev.cgem.%d.stats.rx_frames_multi -Counter of multicast frames receive without error excluding pause frames. -.It Va dev.cgem.%d.stats.rx_frames_pause -Counter of pause frames recevied without error. -.It Va dev.cgem.%d.stats.rx_frames_64b -Counter of 64-byte frames received without error. -.It Va dev.cgem.%d.stats.rx_frames_65to127b -Counter of 65 to 127 byte frames received without error. -.It Va dev.cgem.%d.stats.rx_frames_128to255b -Counter of 128 to 255 byte frames received without error. -.It Va dev.cgem.%d.stats.rx_frames_256to511b -Counter of 256 to 511 byte frames received without error. -.It Va dev.cgem.%d.stats.rx_frames_512to1023b -Counter of 512 to 1023 byte frames received without error. -.It Va dev.cgem.%d.stats.rx_frames_1024to1536b -Counter of 1024 to 1536 byte frames received without error. -.It Va dev.cgem.%d.stats.rx_frames_undersize -Counter of frames received less than 64 bytes in length that -do not also have either a CRC error or an alignment error. -.It Va dev.cgem.%d.stats.rx_frames_oversize -Counter of frames received exceeding 1536 bytes and do not also have either -a CRC error or an alignment error. -.It Va dev.cgem.%d.stats.rx_frames_jabber -Counter of frames received exceeding 1536 bytes and also have either a CRC -error, an alignment error, or a receive symbol error. -.It Va dev.cgem.%d.stats.rx_frames_fcs_errs -Counter of frames received with a bad CRC and are between 64 -and 1536 bytes. -.It Va dev.cgem.%d.stats.rx_frames_length_errs -Counter of frames received that are shorter than that extracted -from the length field. -.It Va dev.cgem.%d.stats.rx_symbol_errs -Counter of receive symbol errors. -.It Va dev.cgem.%d.stats.rx_align_errs -Counter of received frames that are not an integral number of bytes. -.It Va dev.cgem.%d.stats.rx_resource_errs -Counter of frames successfully receive by the MAC but could not be -copied to memory because no receive buffer was available. -.It Va dev.cgem.%d.stats.rx_overrun_errs -Counter of frames that are address recognized but were not copied -to memory due to a receive overrun. -.It Va dev.cgem.%d.stats.rx_frames_ip_hdr_csum_errs -Counter of frames discarded due to an incorrect IP header checksum when -checksum offloading is enabled. -.It Va dev.cgem.%d.stats.rx_frames_tcp_csum_errs -Counter of frames discarded due to an incorrect TCP checksum when -checksum offloading is enabled. -.It Va dev.cgem.%d.stats.rx_frames_udp_csum_errs -Counter of frames discarded due to an incorrect UDP checksum when -checksum offloading is enabled. -.El -.Sh SEE ALSO -.Xr miibus 4 , -.Xr ifconfig 8 -.Rs -.%T "Zynq-7000 SoC Technical Reference Manual (Xilinx doc UG585)" -.%U http://www.xilinx.com/support/documentation/user_guides/\:ug585-Zynq-7000-TRM.pdf -.Re -.Sh HISTORY -The -.Nm -device driver first appeared in -.Fx 10.0 . -.Sh AUTHORS -The -.Nm -driver and this manual page was written by -.An Thomas Skibo Aq Mt thomasskibo@yahoo.com . -.Sh BUGS -The GEM can perform TCP/UDP/IP checksum offloading. -However, when transmit checksum offloading is enabled, the GEM generates and -replaces checksums for all packets it transmits. -In a system that is forwarding packets, the device could potentially correct -the checksum of packet that was corrupted in transit. -For this reason, checksum offloading is disabled by default but can be -enabled using ifconfig(8). -.Pp -When receive checksum offloading is enabled, the device will discard packets -with bad TCP/UDP/IP checksums. -The bad packets will not be counted in any -.Xr netstat 1 -statistics. -There are -.Xr sysctl 8 -variables that count -packets discarded by the hardware (see below). -.Pp -The GEM used in the Zynq-7000 has a bug such that the receiver can -potentially freeze up under a high load. -The issue is described in sec. 16.7 -"Known Issues" of the Zynq-7000 SoC Technical Reference Manual (Xilinx -UG585 v1.7). -The -.Nm -driver implements the work-around suggested in the manual. -If the bug does not exist in other versions of this device, the -work-around can be disabled by setting the dev.cgem.%d.rxhangwar -.Xr sysctl 8 -variable to 0. Index: sys/arm/conf/GENERIC =================================================================== --- sys/arm/conf/GENERIC +++ sys/arm/conf/GENERIC @@ -226,8 +226,8 @@ device miibus device awg # 10/100/1000 integrated EMAC controller +device cgem # Cadence GEM Gigabit Ethernet device device cpsw # TI Common Platform Ethernet Switch (CPSW) -device cgem # Zynq-7000 gig ethernet device device dwc # 10/100/1000 integrated GMAC controller device emac # 10/100 integrated EMAC controller device ffec # Freescale Fast Ethernet Controller Index: sys/arm/conf/ZEDBOARD =================================================================== --- sys/arm/conf/ZEDBOARD +++ sys/arm/conf/ZEDBOARD @@ -49,7 +49,7 @@ device loop device ether -device cgem # Zynq-7000 gig ethernet device +device cgem # Cadence GEM Gigabit Ethernet device device mii device e1000phy device rgephy # Zybo uses Realtek RTL8211E Index: sys/arm64/conf/GENERIC =================================================================== --- sys/arm64/conf/GENERIC +++ sys/arm64/conf/GENERIC @@ -163,6 +163,7 @@ device miibus # MII bus support device awg # Allwinner EMAC Gigabit Ethernet device axgbe # AMD Opteron A1100 integrated NIC +device cgem # Cadence GEM Gigabit Ethernet device device msk # Marvell/SysKonnect Yukon II Gigabit Ethernet device neta # Marvell Armada 370/38x/XP/3700 NIC device smc # SMSC LAN91C111 Index: sys/conf/files.arm64 =================================================================== --- sys/conf/files.arm64 +++ sys/conf/files.arm64 @@ -235,6 +235,7 @@ dev/axgbe/xgbe-dev.c optional axgbe dev/axgbe/xgbe-drv.c optional axgbe dev/axgbe/xgbe-mdio.c optional axgbe +dev/cadence/if_cgem.c optional cgem dev/cpufreq/cpufreq_dt.c optional cpufreq fdt dev/iicbus/sy8106a.c optional sy8106a fdt dev/iicbus/twsi/mv_twsi.c optional twsi fdt Index: sys/dev/cadence/if_cgem.c =================================================================== --- sys/dev/cadence/if_cgem.c +++ sys/dev/cadence/if_cgem.c @@ -86,10 +86,6 @@ #define CGEM_NUM_RX_DESCS 512 /* size of receive descriptor ring */ #define CGEM_NUM_TX_DESCS 512 /* size of transmit descriptor ring */ -#define MAX_DESC_RING_SIZE (MAX(CGEM_NUM_RX_DESCS*sizeof(struct cgem_rx_desc),\ - CGEM_NUM_TX_DESCS*sizeof(struct cgem_tx_desc))) - - /* Default for sysctl rxbufs. Must be < CGEM_NUM_RX_DESCS of course. */ #define DEFAULT_NUM_RX_BUFS 256 /* number of receive bufs to queue. */ @@ -98,11 +94,18 @@ #define CGEM_CKSUM_ASSIST (CSUM_IP | CSUM_TCP | CSUM_UDP | \ CSUM_TCP_IPV6 | CSUM_UDP_IPV6) +#define HWTYPE_GENERIC_GEM 1 +#define HWTYPE_ZYNQ 2 +#define HWTYPE_ZYNQMP 3 +#define HWTYPE_SIFIVE_FU540 4 + static struct ofw_compat_data compat_data[] = { - { "cadence,gem", 1 }, - { "cdns,macb", 1 }, - { "sifive,fu540-c000-gem", 1 }, - { NULL, 0 }, + { "cdns,zynq-gem", HWTYPE_ZYNQ }, + { "cdns,zynqmp-gem", HWTYPE_ZYNQMP }, + { "sifive,fu540-c000-gem", HWTYPE_SIFIVE_FU540 }, + { "cdns,gem", HWTYPE_GENERIC_GEM }, + { "cadence,gem", HWTYPE_GENERIC_GEM }, + { NULL, 0 } }; struct cgem_softc { @@ -117,14 +120,17 @@ void *intrhand; struct callout tick_ch; uint32_t net_ctl_shadow; + uint32_t net_cfg_shadow; int ref_clk_num; - u_char eaddr[6]; + int descwds; /* descriptor size in 32-bit words */ + int is64bit; + int neednullqs; bus_dma_tag_t desc_dma_tag; bus_dma_tag_t mbuf_dma_tag; /* receive descriptor ring */ - struct cgem_rx_desc *rxring; + uint32_t *rxring; bus_addr_t rxring_physaddr; struct mbuf *rxring_m[CGEM_NUM_RX_DESCS]; bus_dmamap_t rxring_m_dmamap[CGEM_NUM_RX_DESCS]; @@ -140,19 +146,22 @@ uint32_t rx_frames_prev; /* transmit descriptor ring */ - struct cgem_tx_desc *txring; + uint32_t *txring; bus_addr_t txring_physaddr; struct mbuf *txring_m[CGEM_NUM_TX_DESCS]; bus_dmamap_t txring_m_dmamap[CGEM_NUM_TX_DESCS]; int txring_hd_ptr; /* where to put next xmits */ int txring_tl_ptr; /* next xmit mbuf to free */ int txring_queued; /* num xmits segs queued */ - bus_dmamap_t txring_dma_map; u_int txfull; /* tx ring full events */ u_int txdefrags; /* tx calls to m_defrag() */ u_int txdefragfails; /* tx m_defrag() failures */ u_int txdmamapfails; /* tx dmamap failures */ + /* null descriptor rings */ + uint32_t *null_qs; + bus_addr_t null_qs_physaddr; + /* hardware provided statistics */ struct cgem_hw_stats { uint64_t tx_bytes; @@ -275,9 +284,9 @@ /* * cgem_mac_hash(): map 48-bit address to a 6-bit hash. The 6-bit hash - * corresponds to a bit in a 64-bit hash register. Setting that bit in the hash - * register enables reception of all frames with a destination address that - * hashes to that 6-bit value. + * corresponds to a bit in a 64-bit hash register. Setting that bit in the + * hash register enables reception of all frames with a destination address + * that hashes to that 6-bit value. * * The hash function is described in sec. 16.2.3 in the Zynq-7000 Tech * Reference Manual. Bits 0-5 in the hash are the exclusive-or of @@ -322,18 +331,15 @@ { if_t ifp = sc->ifp; uint32_t hashes[2] = { 0, 0 }; - uint32_t net_cfg; - net_cfg = RD4(sc, CGEM_NET_CFG); - - net_cfg &= ~(CGEM_NET_CFG_MULTI_HASH_EN | + sc->net_cfg_shadow &= ~(CGEM_NET_CFG_MULTI_HASH_EN | CGEM_NET_CFG_NO_BCAST | CGEM_NET_CFG_COPY_ALL); if ((if_getflags(ifp) & IFF_PROMISC) != 0) - net_cfg |= CGEM_NET_CFG_COPY_ALL; + sc->net_cfg_shadow |= CGEM_NET_CFG_COPY_ALL; else { if ((if_getflags(ifp) & IFF_BROADCAST) == 0) - net_cfg |= CGEM_NET_CFG_NO_BCAST; + sc->net_cfg_shadow |= CGEM_NET_CFG_NO_BCAST; if ((if_getflags(ifp) & IFF_ALLMULTI) != 0) { hashes[0] = 0xffffffff; hashes[1] = 0xffffffff; @@ -341,12 +347,12 @@ if_foreach_llmaddr(ifp, cgem_hash_maddr, hashes); if (hashes[0] != 0 || hashes[1] != 0) - net_cfg |= CGEM_NET_CFG_MULTI_HASH_EN; + sc->net_cfg_shadow |= CGEM_NET_CFG_MULTI_HASH_EN; } WR4(sc, CGEM_HASH_TOP, hashes[0]); WR4(sc, CGEM_HASH_BOT, hashes[1]); - WR4(sc, CGEM_NET_CFG, net_cfg); + WR4(sc, CGEM_NET_CFG, sc->net_cfg_shadow); } /* For bus_dmamap_load() callback. */ @@ -359,83 +365,132 @@ *(bus_addr_t *)arg = segs[0].ds_addr; } +/* Set up null queues for priority queues we actually can't disable. */ +static void +cgem_null_qs(struct cgem_softc *sc) +{ + uint32_t *rx_desc; + uint32_t *tx_desc; + uint32_t queue_mask; + int n; + + /* Read design config register 6 to determine number of queues. */ + queue_mask = (RD4(sc, CGEM_DESIGN_CFG6) & + CGEM_DESIGN_CFG6_DMA_PRIO_Q_MASK) >> 1; + if (queue_mask == 0) + return; + + /* Create empty RX queue and empty TX buf queues. */ + memset(sc->null_qs, 0, sc->descwds * sizeof(uint32_t)); + rx_desc = sc->null_qs; + rx_desc[0] = CGEM_RXDESC_OWN | CGEM_RXDESC_WRAP; + tx_desc = rx_desc + sc->descwds; + tx_desc[1] = CGEM_TXDESC_USED | CGEM_TXDESC_WRAP; + + /* Point all valid ring base pointers to the null queues. */ + for (n = 1; (queue_mask & 1) != 0; n++, queue_mask >>= 1) { + WR4(sc, CGEM_RX_QN_BAR(n), sc->null_qs_physaddr); + WR4(sc, CGEM_TX_QN_BAR(n), sc->null_qs_physaddr + + sc->descwds * sizeof(uint32_t)); + } +} + /* Create DMA'able descriptor rings. */ static int cgem_setup_descs(struct cgem_softc *sc) { int i, err; + int desc_rings_size = (CGEM_NUM_RX_DESCS + CGEM_NUM_TX_DESCS) * + sc->descwds * sizeof(uint32_t); + if (sc->neednullqs) + desc_rings_size += 2 * sc->descwds * sizeof(uint32_t); + sc->txring = NULL; sc->rxring = NULL; /* Allocate non-cached DMA space for RX and TX descriptors. */ - err = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, - MAX_DESC_RING_SIZE, 1, MAX_DESC_RING_SIZE, 0, - busdma_lock_mutex, &sc->sc_mtx, &sc->desc_dma_tag); + err = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1, +#if INTPTR_MAX == INT64_MAX + 1ULL << 32, /* Do not cross a 4G boundary. */ +#else + 0, +#endif + sc->is64bit ? BUS_SPACE_MAXADDR : BUS_SPACE_MAXADDR_32BIT, + BUS_SPACE_MAXADDR, NULL, NULL, desc_rings_size, 1, + desc_rings_size, 0, busdma_lock_mutex, &sc->sc_mtx, + &sc->desc_dma_tag); if (err) return (err); /* Set up a bus_dma_tag for mbufs. */ err = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, - MCLBYTES, TX_MAX_DMA_SEGS, MCLBYTES, 0, - busdma_lock_mutex, &sc->sc_mtx, &sc->mbuf_dma_tag); + sc->is64bit ? BUS_SPACE_MAXADDR : BUS_SPACE_MAXADDR_32BIT, + BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, TX_MAX_DMA_SEGS, + MCLBYTES, 0, busdma_lock_mutex, &sc->sc_mtx, &sc->mbuf_dma_tag); if (err) return (err); - /* Allocate DMA memory in non-cacheable space. */ + /* + * Allocate DMA memory in non-cacheable space. We allocate transmit, + * receive and null descriptor queues all at once because the + * hardware only provides one register for the upper 32 bits of + * rx and tx descriptor queues hardware addresses. + */ err = bus_dmamem_alloc(sc->desc_dma_tag, (void **)&sc->rxring, - BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &sc->rxring_dma_map); +#ifdef __arm__ + BUS_DMA_NOWAIT | BUS_DMA_COHERENT | BUS_DMA_ZERO, +#else + BUS_DMA_NOWAIT | BUS_DMA_NOCACHE | BUS_DMA_ZERO, +#endif + &sc->rxring_dma_map); if (err) return (err); /* Load descriptor DMA memory. */ err = bus_dmamap_load(sc->desc_dma_tag, sc->rxring_dma_map, - (void *)sc->rxring, CGEM_NUM_RX_DESCS*sizeof(struct cgem_rx_desc), + (void *)sc->rxring, desc_rings_size, cgem_getaddr, &sc->rxring_physaddr, BUS_DMA_NOWAIT); if (err) return (err); /* Initialize RX descriptors. */ for (i = 0; i < CGEM_NUM_RX_DESCS; i++) { - sc->rxring[i].addr = CGEM_RXDESC_OWN; - sc->rxring[i].ctl = 0; + sc->rxring[i * sc->descwds] = CGEM_RXDESC_OWN; sc->rxring_m[i] = NULL; sc->rxring_m_dmamap[i] = NULL; } - sc->rxring[CGEM_NUM_RX_DESCS - 1].addr |= CGEM_RXDESC_WRAP; + sc->rxring[sc->descwds * (CGEM_NUM_RX_DESCS - 1)] |= CGEM_RXDESC_WRAP; sc->rxring_hd_ptr = 0; sc->rxring_tl_ptr = 0; sc->rxring_queued = 0; - /* Allocate DMA memory for TX descriptors in non-cacheable space. */ - err = bus_dmamem_alloc(sc->desc_dma_tag, (void **)&sc->txring, - BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &sc->txring_dma_map); - if (err) - return (err); + sc->txring = sc->rxring + CGEM_NUM_RX_DESCS * sc->descwds; + sc->txring_physaddr = sc->rxring_physaddr + CGEM_NUM_RX_DESCS * + sc->descwds * sizeof(uint32_t); - /* Load TX descriptor DMA memory. */ - err = bus_dmamap_load(sc->desc_dma_tag, sc->txring_dma_map, - (void *)sc->txring, CGEM_NUM_TX_DESCS*sizeof(struct cgem_tx_desc), - cgem_getaddr, &sc->txring_physaddr, BUS_DMA_NOWAIT); - if (err) - return (err); - /* Initialize TX descriptor ring. */ for (i = 0; i < CGEM_NUM_TX_DESCS; i++) { - sc->txring[i].addr = 0; - sc->txring[i].ctl = CGEM_TXDESC_USED; + sc->txring[i * sc->descwds + 1] = CGEM_TXDESC_USED; sc->txring_m[i] = NULL; sc->txring_m_dmamap[i] = NULL; } - sc->txring[CGEM_NUM_TX_DESCS - 1].ctl |= CGEM_TXDESC_WRAP; + sc->txring[sc->descwds * (CGEM_NUM_TX_DESCS - 1) + 1] |= + CGEM_TXDESC_WRAP; sc->txring_hd_ptr = 0; sc->txring_tl_ptr = 0; sc->txring_queued = 0; + if (sc->neednullqs) { + sc->null_qs = sc->txring + CGEM_NUM_TX_DESCS * sc->descwds; + sc->null_qs_physaddr = sc->txring_physaddr + + CGEM_NUM_TX_DESCS * sc->descwds * sizeof(uint32_t); + + cgem_null_qs(sc); + } + return (0); } @@ -484,13 +539,19 @@ BUS_DMASYNC_PREREAD); /* Write rx descriptor and increment head pointer. */ - sc->rxring[sc->rxring_hd_ptr].ctl = 0; + sc->rxring[sc->rxring_hd_ptr * sc->descwds + 1] = 0; +#if INTPTR_MAX == INT64_MAX + if (sc->is64bit) + sc->rxring[sc->rxring_hd_ptr * sc->descwds + 2] = + segs[0].ds_addr >> 32; +#endif if (sc->rxring_hd_ptr == CGEM_NUM_RX_DESCS - 1) { - sc->rxring[sc->rxring_hd_ptr].addr = segs[0].ds_addr | - CGEM_RXDESC_WRAP; + sc->rxring[sc->rxring_hd_ptr * sc->descwds] = + segs[0].ds_addr | CGEM_RXDESC_WRAP; sc->rxring_hd_ptr = 0; } else - sc->rxring[sc->rxring_hd_ptr++].addr = segs[0].ds_addr; + sc->rxring[sc->rxring_hd_ptr++ * sc->descwds] = + segs[0].ds_addr; sc->rxring_queued++; } @@ -509,10 +570,10 @@ /* Pick up all packets in which the OWN bit is set. */ m_hd = NULL; m_tl = &m_hd; - while (sc->rxring_queued > 0 && - (sc->rxring[sc->rxring_tl_ptr].addr & CGEM_RXDESC_OWN) != 0) { + while (sc->rxring_queued > 0 && (sc->rxring[sc->rxring_tl_ptr * + sc->descwds] & CGEM_RXDESC_OWN) != 0) { - ctl = sc->rxring[sc->rxring_tl_ptr].ctl; + ctl = sc->rxring[sc->rxring_tl_ptr * sc->descwds + 1]; /* Grab filled mbuf. */ m = sc->rxring_m[sc->rxring_tl_ptr]; @@ -609,7 +670,7 @@ /* free up finished transmits. */ while (sc->txring_queued > 0 && - ((ctl = sc->txring[sc->txring_tl_ptr].ctl) & + ((ctl = sc->txring[sc->txring_tl_ptr * sc->descwds + 1]) & CGEM_TXDESC_USED) != 0) { /* Sync cache. */ @@ -632,9 +693,16 @@ /* Check the status. */ if ((ctl & CGEM_TXDESC_AHB_ERR) != 0) { /* Serious bus error. log to console. */ +#if INTPTR_MAX == INT64_MAX device_printf(sc->dev, + "cgem_clean_tx: AHB error, addr=0x%x%08x\n", + sc->txring[sc->txring_tl_ptr * sc->descwds + 2], + sc->txring[sc->txring_tl_ptr * sc->descwds]); +#else + device_printf(sc->dev, "cgem_clean_tx: AHB error, addr=0x%x\n", - sc->txring[sc->txring_tl_ptr].addr); + sc->txring[sc->txring_tl_ptr * sc->descwds]); +#endif } else if ((ctl & (CGEM_TXDESC_RETRY_ERR | CGEM_TXDESC_LATE_COLL)) != 0) { if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1); @@ -643,8 +711,8 @@ /* * If the packet spanned more than one tx descriptor, skip - * descriptors until we find the end so that only start-of-frame - * descriptors are processed. + * descriptors until we find the end so that only + * start-of-frame descriptors are processed. */ while ((ctl & CGEM_TXDESC_LAST_BUF) == 0) { if ((ctl & CGEM_TXDESC_WRAP) != 0) @@ -653,9 +721,9 @@ sc->txring_tl_ptr++; sc->txring_queued--; - ctl = sc->txring[sc->txring_tl_ptr].ctl; + ctl = sc->txring[sc->txring_tl_ptr * sc->descwds + 1]; - sc->txring[sc->txring_tl_ptr].ctl = + sc->txring[sc->txring_tl_ptr * sc->descwds + 1] = ctl | CGEM_TXDESC_USED; } @@ -761,9 +829,13 @@ */ for (i = nsegs - 1; i >= 0; i--) { /* Descriptor address. */ - sc->txring[sc->txring_hd_ptr + i].addr = + sc->txring[(sc->txring_hd_ptr + i) * sc->descwds] = segs[i].ds_addr; - +#if INTPTR_MAX == INT64_MAX + if (sc->is64bit) + sc->txring[(sc->txring_hd_ptr + i) * + sc->descwds + 2] = segs[i].ds_addr >> 32; +#endif /* Descriptor control word. */ ctl = segs[i].ds_len; if (i == nsegs - 1) { @@ -771,7 +843,8 @@ if (wrap) ctl |= CGEM_TXDESC_WRAP; } - sc->txring[sc->txring_hd_ptr + i].ctl = ctl; + sc->txring[(sc->txring_hd_ptr + i) * sc->descwds + 1] = + ctl; if (i != 0) sc->txring_m[sc->txring_hd_ptr + i] = NULL; @@ -965,8 +1038,21 @@ CGEM_ASSERT_LOCKED(sc); + /* Determine data bus width from design configuration register. */ + switch (RD4(sc, CGEM_DESIGN_CFG1) & + CGEM_DESIGN_CFG1_DMA_BUS_WIDTH_MASK) { + case CGEM_DESIGN_CFG1_DMA_BUS_WIDTH_64: + sc->net_cfg_shadow = CGEM_NET_CFG_DBUS_WIDTH_64; + break; + case CGEM_DESIGN_CFG1_DMA_BUS_WIDTH_128: + sc->net_cfg_shadow = CGEM_NET_CFG_DBUS_WIDTH_128; + break; + default: + sc->net_cfg_shadow = CGEM_NET_CFG_DBUS_WIDTH_32; + } + WR4(sc, CGEM_NET_CTRL, 0); - WR4(sc, CGEM_NET_CFG, 0); + WR4(sc, CGEM_NET_CFG, sc->net_cfg_shadow); WR4(sc, CGEM_NET_CTRL, CGEM_NET_CTRL_CLR_STAT_REGS); WR4(sc, CGEM_TX_STAT, CGEM_TX_STAT_ALL); WR4(sc, CGEM_RX_STAT, CGEM_RX_STAT_ALL); @@ -977,8 +1063,8 @@ WR4(sc, CGEM_RX_QBAR, 0); /* Get management port running even if interface is down. */ - WR4(sc, CGEM_NET_CFG, CGEM_NET_CFG_DBUS_WIDTH_32 | - CGEM_NET_CFG_MDC_CLK_DIV_64); + sc->net_cfg_shadow |= CGEM_NET_CFG_MDC_CLK_DIV_48; + WR4(sc, CGEM_NET_CFG, sc->net_cfg_shadow); sc->net_ctl_shadow = CGEM_NET_CTRL_MGMT_PORT_EN; WR4(sc, CGEM_NET_CTRL, sc->net_ctl_shadow); @@ -989,33 +1075,31 @@ cgem_config(struct cgem_softc *sc) { if_t ifp = sc->ifp; - uint32_t net_cfg; uint32_t dma_cfg; u_char *eaddr = if_getlladdr(ifp); CGEM_ASSERT_LOCKED(sc); /* Program Net Config Register. */ - net_cfg = CGEM_NET_CFG_DBUS_WIDTH_32 | - CGEM_NET_CFG_MDC_CLK_DIV_64 | - CGEM_NET_CFG_FCS_REMOVE | + sc->net_cfg_shadow &= (CGEM_NET_CFG_MDC_CLK_DIV_MASK | + CGEM_NET_CFG_DBUS_WIDTH_MASK); + sc->net_cfg_shadow |= (CGEM_NET_CFG_FCS_REMOVE | CGEM_NET_CFG_RX_BUF_OFFSET(ETHER_ALIGN) | - CGEM_NET_CFG_GIGE_EN | - CGEM_NET_CFG_1536RXEN | - CGEM_NET_CFG_FULL_DUPLEX | - CGEM_NET_CFG_SPEED100; + CGEM_NET_CFG_GIGE_EN | CGEM_NET_CFG_1536RXEN | + CGEM_NET_CFG_FULL_DUPLEX | CGEM_NET_CFG_SPEED100); /* Enable receive checksum offloading? */ if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0) - net_cfg |= CGEM_NET_CFG_RX_CHKSUM_OFFLD_EN; + sc->net_cfg_shadow |= CGEM_NET_CFG_RX_CHKSUM_OFFLD_EN; - WR4(sc, CGEM_NET_CFG, net_cfg); + WR4(sc, CGEM_NET_CFG, sc->net_cfg_shadow); /* Program DMA Config Register. */ dma_cfg = CGEM_DMA_CFG_RX_BUF_SIZE(MCLBYTES) | CGEM_DMA_CFG_RX_PKTBUF_MEMSZ_SEL_8K | CGEM_DMA_CFG_TX_PKTBUF_MEMSZ_SEL | CGEM_DMA_CFG_AHB_FIXED_BURST_LEN_16 | + (sc->is64bit ? CGEM_DMA_CFG_ADDR_BUS_64 : 0) | CGEM_DMA_CFG_DISC_WHEN_NO_AHB; /* Enable transmit checksum offloading? */ @@ -1025,8 +1109,16 @@ WR4(sc, CGEM_DMA_CFG, dma_cfg); /* Write the rx and tx descriptor ring addresses to the QBAR regs. */ - WR4(sc, CGEM_RX_QBAR, (uint32_t) sc->rxring_physaddr); - WR4(sc, CGEM_TX_QBAR, (uint32_t) sc->txring_physaddr); + WR4(sc, CGEM_RX_QBAR, (uint32_t)sc->rxring_physaddr); + WR4(sc, CGEM_TX_QBAR, (uint32_t)sc->txring_physaddr); +#if INTPTR_MAX == INT64_MAX + if (sc->is64bit) { + WR4(sc, CGEM_RX_QBAR_HI, + (uint32_t)(sc->rxring_physaddr >> 32)); + WR4(sc, CGEM_TX_QBAR_HI, + (uint32_t)(sc->txring_physaddr >> 32)); + } +#endif /* Enable rx and tx. */ sc->net_ctl_shadow |= (CGEM_NET_CTRL_TX_EN | CGEM_NET_CTRL_RX_EN); @@ -1059,8 +1151,10 @@ if_setdrvflagbits(sc->ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); - mii = device_get_softc(sc->miibus); - mii_mediachg(mii); + if (sc->miibus != NULL) { + mii = device_get_softc(sc->miibus); + mii_mediachg(mii); + } callout_reset(&sc->tick_ch, hz, cgem_tick, sc); } @@ -1089,9 +1183,10 @@ cgem_reset(sc); /* Clear out transmit queue. */ + memset(sc->txring, 0, CGEM_NUM_TX_DESCS * sc->descwds * + sizeof(uint32_t)); for (i = 0; i < CGEM_NUM_TX_DESCS; i++) { - sc->txring[i].ctl = CGEM_TXDESC_USED; - sc->txring[i].addr = 0; + sc->txring[i * sc->descwds + 1] = CGEM_TXDESC_USED; if (sc->txring_m[i]) { /* Unload and destroy dmamap. */ bus_dmamap_unload(sc->mbuf_dma_tag, @@ -1103,16 +1198,18 @@ sc->txring_m[i] = NULL; } } - sc->txring[CGEM_NUM_TX_DESCS - 1].ctl |= CGEM_TXDESC_WRAP; + sc->txring[(CGEM_NUM_TX_DESCS - 1) * sc->descwds + 1] |= + CGEM_TXDESC_WRAP; sc->txring_hd_ptr = 0; sc->txring_tl_ptr = 0; sc->txring_queued = 0; /* Clear out receive queue. */ + memset(sc->rxring, 0, CGEM_NUM_RX_DESCS * sc->descwds * + sizeof(uint32_t)); for (i = 0; i < CGEM_NUM_RX_DESCS; i++) { - sc->rxring[i].addr = CGEM_RXDESC_OWN; - sc->rxring[i].ctl = 0; + sc->rxring[i * sc->descwds] = CGEM_RXDESC_OWN; if (sc->rxring_m[i]) { /* Unload and destroy dmamap. */ bus_dmamap_unload(sc->mbuf_dma_tag, @@ -1125,7 +1222,7 @@ sc->rxring_m[i] = NULL; } } - sc->rxring[CGEM_NUM_RX_DESCS - 1].addr |= CGEM_RXDESC_WRAP; + sc->rxring[(CGEM_NUM_RX_DESCS - 1) * sc->descwds] |= CGEM_RXDESC_WRAP; sc->rxring_hd_ptr = 0; sc->rxring_tl_ptr = 0; @@ -1176,6 +1273,8 @@ case SIOCSIFMEDIA: case SIOCGIFMEDIA: + if (sc->miibus == NULL) + return (ENXIO); mii = device_get_softc(sc->miibus); error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); break; @@ -1210,16 +1309,16 @@ /* Turn on RX checksumming. */ if_setcapenablebit(ifp, IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6, 0); - WR4(sc, CGEM_NET_CFG, - RD4(sc, CGEM_NET_CFG) | - CGEM_NET_CFG_RX_CHKSUM_OFFLD_EN); + sc->net_cfg_shadow |= + CGEM_NET_CFG_RX_CHKSUM_OFFLD_EN; + WR4(sc, CGEM_NET_CFG, sc->net_cfg_shadow); } else { /* Turn off RX checksumming. */ if_setcapenablebit(ifp, 0, IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6); - WR4(sc, CGEM_NET_CFG, - RD4(sc, CGEM_NET_CFG) & - ~CGEM_NET_CFG_RX_CHKSUM_OFFLD_EN); + sc->net_cfg_shadow &= + ~CGEM_NET_CFG_RX_CHKSUM_OFFLD_EN; + WR4(sc, CGEM_NET_CFG, sc->net_cfg_shadow); } } if ((if_getcapenable(ifp) & (IFCAP_RXCSUM | IFCAP_TXCSUM)) == @@ -1240,15 +1339,6 @@ /* MII bus support routines. */ -static void -cgem_child_detached(device_t dev, device_t child) -{ - struct cgem_softc *sc = device_get_softc(dev); - - if (child == sc->miibus) - sc->miibus = NULL; -} - static int cgem_ifmedia_upd(if_t ifp) { @@ -1385,24 +1475,22 @@ static void cgem_mediachange(struct cgem_softc *sc, struct mii_data *mii) { - uint32_t net_cfg; int ref_clk_freq; CGEM_ASSERT_LOCKED(sc); /* Update hardware to reflect media. */ - net_cfg = RD4(sc, CGEM_NET_CFG); - net_cfg &= ~(CGEM_NET_CFG_SPEED100 | CGEM_NET_CFG_GIGE_EN | + sc->net_cfg_shadow &= ~(CGEM_NET_CFG_SPEED100 | CGEM_NET_CFG_GIGE_EN | CGEM_NET_CFG_FULL_DUPLEX); switch (IFM_SUBTYPE(mii->mii_media_active)) { case IFM_1000_T: - net_cfg |= (CGEM_NET_CFG_SPEED100 | + sc->net_cfg_shadow |= (CGEM_NET_CFG_SPEED100 | CGEM_NET_CFG_GIGE_EN); ref_clk_freq = 125000000; break; case IFM_100_TX: - net_cfg |= CGEM_NET_CFG_SPEED100; + sc->net_cfg_shadow |= CGEM_NET_CFG_SPEED100; ref_clk_freq = 25000000; break; default: @@ -1410,9 +1498,9 @@ } if ((mii->mii_media_active & IFM_FDX) != 0) - net_cfg |= CGEM_NET_CFG_FULL_DUPLEX; + sc->net_cfg_shadow |= CGEM_NET_CFG_FULL_DUPLEX; - WR4(sc, CGEM_NET_CFG, net_cfg); + WR4(sc, CGEM_NET_CFG, sc->net_cfg_shadow); /* Set the reference clock if necessary. */ if (cgem_set_ref_clk(sc->ref_clk_num, ref_clk_freq)) @@ -1654,6 +1742,22 @@ sc->dev = dev; CGEM_LOCK_INIT(sc); + /* Key off of compatible string and set hardware-specific options. */ + switch(ofw_bus_search_compatible(dev, compat_data)->ocd_data) { + case HWTYPE_ZYNQMP: + sc->is64bit = 1; + sc->neednullqs = 1; + break; + case HWTYPE_SIFIVE_FU540: + sc->is64bit = 1; + break; + default: + /* Implement receive hang bug work-around. */ + sc->rxhangwar = 1; + break; + } + sc->descwds = sc->is64bit ? 4 : 2; + /* Get reference clock number and base divider from fdt. */ node = ofw_bus_get_node(dev); sc->ref_clk_num = 0; @@ -1671,7 +1775,8 @@ /* Get IRQ resource. */ rid = 0; - sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); + sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_ACTIVE); if (sc->irq_res == NULL) { device_printf(dev, "could not allocate interrupt resource.\n"); cgem_detach(dev); @@ -1703,7 +1808,6 @@ sc->if_old_flags = if_getflags(ifp); sc->rxbufs = DEFAULT_NUM_RX_BUFS; - sc->rxhangwar = 1; /* Reset hardware. */ CGEM_LOCK(sc); @@ -1714,11 +1818,8 @@ err = mii_attach(dev, &sc->miibus, ifp, cgem_ifmedia_upd, cgem_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); - if (err) { - device_printf(dev, "attaching PHYs failed\n"); - cgem_detach(dev); - return (err); - } + if (err) + device_printf(dev, "warning: attaching PHYs failed\n"); /* Set up TX and RX descriptor area. */ err = cgem_setup_descs(sc); @@ -1793,26 +1894,21 @@ bus_dmamap_unload(sc->desc_dma_tag, sc->rxring_dma_map); sc->rxring_physaddr = 0; + sc->txring_physaddr = 0; + sc->null_qs_physaddr = 0; } bus_dmamem_free(sc->desc_dma_tag, sc->rxring, sc->rxring_dma_map); sc->rxring = NULL; + sc->txring = NULL; + sc->null_qs = NULL; + for (i = 0; i < CGEM_NUM_RX_DESCS; i++) if (sc->rxring_m_dmamap[i] != NULL) { bus_dmamap_destroy(sc->mbuf_dma_tag, sc->rxring_m_dmamap[i]); sc->rxring_m_dmamap[i] = NULL; } - } - if (sc->txring != NULL) { - if (sc->txring_physaddr != 0) { - bus_dmamap_unload(sc->desc_dma_tag, - sc->txring_dma_map); - sc->txring_physaddr = 0; - } - bus_dmamem_free(sc->desc_dma_tag, sc->txring, - sc->txring_dma_map); - sc->txring = NULL; for (i = 0; i < CGEM_NUM_TX_DESCS; i++) if (sc->txring_m_dmamap[i] != NULL) { bus_dmamap_destroy(sc->mbuf_dma_tag, @@ -1842,9 +1938,6 @@ DEVMETHOD(device_attach, cgem_attach), DEVMETHOD(device_detach, cgem_detach), - /* Bus interface */ - DEVMETHOD(bus_child_detached, cgem_child_detached), - /* MII interface */ DEVMETHOD(miibus_readreg, cgem_miibus_readreg), DEVMETHOD(miibus_writereg, cgem_miibus_writereg), @@ -1864,3 +1957,4 @@ DRIVER_MODULE(miibus, cgem, miibus_driver, miibus_devclass, NULL, NULL); MODULE_DEPEND(cgem, miibus, 1, 1, 1); MODULE_DEPEND(cgem, ether, 1, 1, 1); +SIMPLEBUS_PNP_INFO(compat_data); Index: sys/dev/cadence/if_cgem_hw.h =================================================================== --- sys/dev/cadence/if_cgem_hw.h +++ sys/dev/cadence/if_cgem_hw.h @@ -35,6 +35,10 @@ * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual. * (v1.4) November 16, 2012. Xilinx doc UG585. GEM is covered in Ch. 16 * and register definitions are in appendix B.18. + * + * Additional Reference: Zynq UltraScale+ Device Register Reference + * (UG1087 v1.7 Feb 8,2019): + * https://www.xilinx.com/html_docs/registers/ug1087/ug1087-zynq-ultrascale-registers.html */ #ifndef _IF_CGEM_HW_H_ @@ -113,6 +117,7 @@ #define CGEM_USER_IO 0x00C /* User I/O */ #define CGEM_DMA_CFG 0x010 /* DMA Config */ +#define CGEM_DMA_CFG_ADDR_BUS_64 (1 << 30) #define CGEM_DMA_CFG_DISC_WHEN_NO_AHB (1 << 24) #define CGEM_DMA_CFG_RX_BUF_SIZE_SHIFT 16 #define CGEM_DMA_CFG_RX_BUF_SIZE_MASK (0xff << 16) @@ -290,6 +295,29 @@ #define CGEM_PTP_PEER_RX_S 0x1F8 /* PTP Peer Event rcv'd s */ #define CGEM_PTP_PEER_RX_NS 0x1FC /* PTP Peer Event rcv'd ns */ +#define CGEM_DESIGN_CFG1 0x280 /* Design Configuration 1 */ +#define CGEM_DESIGN_CFG1_AXI_CACHE_WIDTH_MASK (0xfU << 28) +#define CGEM_DESIGN_CFG1_DMA_BUS_WIDTH_MASK (7 << 25) +#define CGEM_DESIGN_CFG1_DMA_BUS_WIDTH_32 (1 << 25) +#define CGEM_DESIGN_CFG1_DMA_BUS_WIDTH_64 (2 << 25) +#define CGEM_DESIGN_CFG1_DMA_BUS_WIDTH_128 (4 << 25) +#define CGEM_DESIGN_CFG1_IRQ_READ_CLR (1 << 23) +#define CGEM_DESIGN_CFG1_NO_SNAPSHOT (1 << 22) +#define CGEM_DESIGN_CFG1_NO_STATS (1 << 21) +#define CGEM_DESIGN_CFG1_NO_SCAN_PINS (1 << 20) +#define CGEM_DESIGN_CFG1_USER_IN_WIDTH_MASK (0x1f << 15) +#define CGEM_DESIGN_CFG1_USER_OUT_WIDTH_MASK (0x1f << 10) +#define CGEM_DESIGN_CFG1_USER_IO (1 << 9) +#define CGEM_DESIGN_CFG1_APB_REV2 (1 << 8) +#define CGEM_DESIGN_CFG1_APB_REV1 (1 << 7) +#define CGEM_DESIGN_CFG1_EXT_FIFO_INTERFACE (1 << 6) +#define CGEM_DESIGN_CFG1_NO_INT_LOOPBACK (1 << 5) +#define CGEM_DESIGN_CFG1_INT_LOOPBACK (1 << 4) +#define CGEM_DESIGN_CFG1_TDC_50 (1 << 3) +#define CGEM_DESIGN_CFG1_RDC_50 (1 << 2) +#define CGEM_DESIGN_CFG1_SERDES (1 << 1) +#define CGEM_DESIGN_CFG1_NO_PCS (1 << 0) + #define CGEM_DESIGN_CFG2 0x284 /* Design Configuration 2 */ #define CGEM_DESIGN_CFG2_TX_PBUF_ADDR_SHIFT 26 #define CGEM_DESIGN_CFG2_TX_PBUF_ADDR_MASK (0xf << 26) @@ -330,10 +358,25 @@ #define CGEM_DESIGN_CFG5_TX_FIFO_CNT_WIDTH_MASK (0xf << 4) #define CGEM_DESIGN_CFG5_RX_FIFO_CNT_WIDTH_MASK 0xf -/* Transmit Descriptors */ -struct cgem_tx_desc { - uint32_t addr; - uint32_t ctl; +#define CGEM_DESIGN_CFG6 0x294 /* Design Configuration 6 */ +#define CGEM_DESIGN_CFG6_ADDR_64B (1 << 23) /* 64-bit addr cap */ +#define CGEM_DESIGN_CFG6_DMA_PRIO_Q_MASK 0xfffe +#define CGEM_DESIGN_CFG6_DMA_PRIO_Q(n) (1 << (n)) + +#define CGEM_TX_QN_BAR(n) (0x440 + ((n) - 1) * 4) +#define CGEM_RX_QN_BAR(n) (0x480 + ((n) - 1) * 4) + +#define CGEM_TX_QBAR_HI 0x4C8 +#define CGEM_RX_QBAR_HI 0x4D4 + +/* Transmit Descriptors: two or four 32-bit words: + * word0: address + * word1: length and control + * word2: address upper 32-bits (64-bit mode) + * word3: unused (64-bit mode) + */ + +/* Tx descriptor length and control word bits: */ #define CGEM_TXDESC_USED (1U << 31) /* done txmitting */ #define CGEM_TXDESC_WRAP (1 << 30) /* end descr ring */ #define CGEM_TXDESC_RETRY_ERR (1 << 29) @@ -350,13 +393,18 @@ #define CGEM_TXDESC_NO_CRC_APPENDED (1 << 16) #define CGEM_TXDESC_LAST_BUF (1 << 15) /* last in frame */ #define CGEM_TXDESC_LENGTH_MASK 0x3fff -}; -struct cgem_rx_desc { - uint32_t addr; +/* Receive Descriptors: two or four 32-bit words: + * word0: address | WRAP and OWN flags + * word1: length and control + * word2: address upper 32 bits (64-bit mode) + * word3: unused + */ + +/* address word flags: */ #define CGEM_RXDESC_WRAP (1 << 1) /* goes in addr! */ #define CGEM_RXDESC_OWN (1 << 0) /* buf filled */ - uint32_t ctl; +/* length and control word flags: */ #define CGEM_RXDESC_BCAST (1U << 31)/* all 1's bcast */ #define CGEM_RXDESC_MULTI_MATCH (1 << 30) /* mutlicast match */ #define CGEM_RXDESC_UNICAST_MATCH (1 << 29) @@ -379,6 +427,5 @@ #define CGEM_RXDESC_SOF (1 << 14) /* start of frame */ #define CGEM_RXDESC_BAD_FCS (1 << 13) #define CGEM_RXDESC_LENGTH_MASK 0x1fff -}; #endif /* _IF_CGEM_HW_H_ */ Index: sys/dts/arm/zynq-7000.dtsi =================================================================== --- sys/dts/arm/zynq-7000.dtsi +++ sys/dts/arm/zynq-7000.dtsi @@ -177,7 +177,7 @@ // Gigabit Ethernet controllers eth0: eth@b000 { device_type = "network"; - compatible = "cadence,gem"; + compatible = "cdns,zynq-gem", "cadence,gem"; status = "disabled"; reg = <0xb000 0x1000>; interrupts = <0 22 4>; @@ -187,7 +187,7 @@ eth1: eth@c000 { device_type = "network"; - compatible = "cadence,gem"; + compatible = "cdns,zynq-gem", "cadence,gem"; status = "disabled"; reg = <0xc000 0x1000>; interrupts = <0 45 4>;