svn commit: r357676 - head/sys/dev/neta

Marcin Wojtas mw at FreeBSD.org
Sat Feb 8 13:33:48 UTC 2020


Author: mw
Date: Sat Feb  8 13:33:47 2020
New Revision: 357676
URL: https://svnweb.freebsd.org/changeset/base/357676

Log:
  Implement jumbo frame support in mvneta driver
  
  This patch introduces processing of the frames
  up to 9kB by the mvneta driver. Some versions of
  this NIC limit TX checksum offloading, depending
  on the frame size, so add appropriate handling
  of this feature.
  
  Submitted by: Kornel Duleba
  Obtained from: Semihalf
  Sponsored by: Stormshield
  Differential Revision: https://reviews.freebsd.org/D23225

Modified:
  head/sys/dev/neta/if_mvneta.c
  head/sys/dev/neta/if_mvneta_fdt.c
  head/sys/dev/neta/if_mvnetavar.h

Modified: head/sys/dev/neta/if_mvneta.c
==============================================================================
--- head/sys/dev/neta/if_mvneta.c	Sat Feb  8 13:25:39 2020	(r357675)
+++ head/sys/dev/neta/if_mvneta.c	Sat Feb  8 13:33:47 2020	(r357676)
@@ -483,9 +483,9 @@ mvneta_dma_create(struct mvneta_softc *sc)
 	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
 	    BUS_SPACE_MAXADDR,			/* highaddr */
 	    NULL, NULL,				/* filtfunc, filtfuncarg */
-	    MVNETA_PACKET_SIZE,			/* maxsize */
+	    MVNETA_MAX_FRAME,			/* maxsize */
 	    MVNETA_TX_SEGLIMIT,			/* nsegments */
-	    MVNETA_PACKET_SIZE,			/* maxsegsz */
+	    MVNETA_MAX_FRAME,			/* maxsegsz */
 	    BUS_DMA_ALLOCNOW,			/* flags */
 	    NULL, NULL,				/* lockfunc, lockfuncarg */
 	    &sc->txmbuf_dtag);
@@ -533,8 +533,8 @@ mvneta_dma_create(struct mvneta_softc *sc)
 	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
 	    BUS_SPACE_MAXADDR,			/* highaddr */
 	    NULL, NULL,				/* filtfunc, filtfuncarg */
-	    MVNETA_PACKET_SIZE, 1,		/* maxsize, nsegments */
-	    MVNETA_PACKET_SIZE,			/* maxsegsz */
+	    MVNETA_MAX_FRAME, 1,		/* maxsize, nsegments */
+	    MVNETA_MAX_FRAME,			/* maxsegsz */
 	    0,					/* flags */
 	    NULL, NULL,				/* lockfunc, lockfuncarg */
 	    &sc->rxbuf_dtag);			/* dmat */
@@ -674,6 +674,8 @@ mvneta_attach(device_t self)
 
 	ifp->if_hwassist = CSUM_IP | CSUM_TCP | CSUM_UDP;
 
+	sc->rx_frame_size = MCLBYTES; /* ether_ifattach() always sets normal mtu */
+
 	/*
 	 * Device DMA Buffer allocation.
 	 * Handles resource deallocation in case of failure.
@@ -1158,7 +1160,7 @@ mvneta_initreg(struct ifnet *ifp)
 	/* Port MAC Control set 0 */
 	reg  = MVNETA_PMACC0_MUSTSET;	/* must write 0x1 */
 	reg &= ~MVNETA_PMACC0_PORTEN;	/* port is still disabled */
-	reg |= MVNETA_PMACC0_FRAMESIZELIMIT(MVNETA_MAX_FRAME);
+	reg |= MVNETA_PMACC0_FRAMESIZELIMIT(ifp->if_mtu + MVNETA_ETHER_SIZE);
 	MVNETA_WRITE(sc, MVNETA_PMACC0, reg);
 
 	/* Port MAC Control set 2 */
@@ -1525,7 +1527,7 @@ mvneta_rx_queue_init(struct ifnet *ifp, int q)
 	MVNETA_WRITE(sc, MVNETA_PRXDQA(q), rx->desc_pa);
 
 	/* Rx buffer size and descriptor ring size */
-	reg  = MVNETA_PRXDQS_BUFFERSIZE(MVNETA_PACKET_SIZE >> 3);
+	reg  = MVNETA_PRXDQS_BUFFERSIZE(sc->rx_frame_size >> 3);
 	reg |= MVNETA_PRXDQS_DESCRIPTORSQUEUESIZE(MVNETA_RX_RING_CNT);
 	MVNETA_WRITE(sc, MVNETA_PRXDQS(q), reg);
 #ifdef MVNETA_KTR
@@ -2103,7 +2105,7 @@ mvneta_ioctl(struct ifnet *ifp, u_long cmd, caddr_t da
 		mvneta_sc_unlock(sc);
 		break;
 	case SIOCSIFCAP:
-		if (ifp->if_mtu > MVNETA_MAX_CSUM_MTU &&
+		if (ifp->if_mtu > sc->tx_csum_limit &&
 		    ifr->ifr_reqcap & IFCAP_TXCSUM)
 			ifr->ifr_reqcap &= ~IFCAP_TXCSUM;
 		mask = ifp->if_capenable ^ ifr->ifr_reqcap;
@@ -2157,7 +2159,12 @@ mvneta_ioctl(struct ifnet *ifp, u_long cmd, caddr_t da
 		} else {
 			ifp->if_mtu = ifr->ifr_mtu;
 			mvneta_sc_lock(sc);
-			if (ifp->if_mtu > MVNETA_MAX_CSUM_MTU) {
+			if (ifp->if_mtu + MVNETA_ETHER_SIZE <= MCLBYTES) {
+				sc->rx_frame_size = MCLBYTES;
+			} else {
+				sc->rx_frame_size = MJUM9BYTES;
+			}
+			if (ifp->if_mtu > sc->tx_csum_limit) {
 				ifp->if_capenable &= ~IFCAP_TXCSUM;
 				ifp->if_hwassist = 0;
 			} else {
@@ -2167,8 +2174,25 @@ mvneta_ioctl(struct ifnet *ifp, u_long cmd, caddr_t da
 			}
 
 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
-				/* Trigger reinitialize sequence */
+				/* Stop hardware */
 				mvneta_stop_locked(sc);
+				/*
+				 * Reinitialize RX queues.
+				 * We need to update RX descriptor size.
+				 */
+				for (q = 0; q < MVNETA_RX_QNUM_MAX; q++) {
+					mvneta_rx_lockq(sc, q);
+					if (mvneta_rx_queue_init(ifp, q) != 0) {
+						device_printf(sc->dev,
+						    "initialization failed:"
+						    " cannot initialize queue\n");
+						mvneta_rx_unlockq(sc, q);
+						error = ENOBUFS;
+						break;
+					}
+					mvneta_rx_unlockq(sc, q);
+				}
+				/* Trigger reinitialization */
 				mvneta_init_locked(sc);
 			}
 			mvneta_sc_unlock(sc);
@@ -2214,6 +2238,8 @@ mvneta_init_locked(void *arg)
 	/* Enable port */
 	reg  = MVNETA_READ(sc, MVNETA_PMACC0);
 	reg |= MVNETA_PMACC0_PORTEN;
+	reg &= ~MVNETA_PMACC0_FRAMESIZELIMIT_MASK;
+	reg |= MVNETA_PMACC0_FRAMESIZELIMIT(ifp->if_mtu + MVNETA_ETHER_SIZE);
 	MVNETA_WRITE(sc, MVNETA_PMACC0, reg);
 
 	/* Allow access to each TXQ/RXQ from both CPU's */
@@ -2801,6 +2827,10 @@ mvneta_tx_set_csumflag(struct ifnet *ifp,
 	iphl = ipoff = 0;
 	csum_flags = ifp->if_hwassist & m->m_pkthdr.csum_flags;
 	eh = mtod(m, struct ether_header *);
+
+	if (csum_flags == 0)
+		return;
+
 	switch (ntohs(eh->ether_type)) {
 	case ETHERTYPE_IP:
 		ipoff = ETHER_HDR_LEN;
@@ -3158,7 +3188,7 @@ mvneta_rx_queue_refill(struct mvneta_softc *sc, int q)
 
 	for (npkt = 0; npkt < refill; npkt++) {
 		rxbuf = &rx->rxbuf[rx->cpu];
-		m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
+		m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, sc->rx_frame_size);
 		if (__predict_false(m == NULL)) {
 			error = ENOBUFS;
 			break;

Modified: head/sys/dev/neta/if_mvneta_fdt.c
==============================================================================
--- head/sys/dev/neta/if_mvneta_fdt.c	Sat Feb  8 13:25:39 2020	(r357675)
+++ head/sys/dev/neta/if_mvneta_fdt.c	Sat Feb  8 13:33:47 2020	(r357676)
@@ -106,12 +106,33 @@ mvneta_fdt_probe(device_t dev)
 static int
 mvneta_fdt_attach(device_t dev)
 {
+	struct mvneta_softc *sc;
+	uint32_t tx_csum_limit;
 	int err;
 
+	sc = device_get_softc(dev);
+
 	/* Try to fetch PHY information from FDT */
 	err = mvneta_fdt_phy_acquire(dev);
 	if (err != 0)
 		return (err);
+
+	if (ofw_bus_is_compatible(dev, "marvell,armada-370-neta")) {
+		tx_csum_limit = MVNETA_A370_MAX_CSUM_MTU;
+	} else {
+		tx_csum_limit = MVNETA_A3700_MAX_CSUM_MTU;
+	}
+
+	if (ofw_bus_has_prop(dev, "tx-csum-limit")) {
+		err = OF_getprop(ofw_bus_get_node(dev), "tx-csum-limit",
+			    &tx_csum_limit, sizeof(tx_csum_limit));
+		if (err <= 0) {
+			device_printf(dev,
+				"Failed to acquire tx-csum-limit property\n");
+			return (ENXIO);
+		}
+	}
+	sc->tx_csum_limit = tx_csum_limit;
 
 	return (mvneta_attach(dev));
 }

Modified: head/sys/dev/neta/if_mvnetavar.h
==============================================================================
--- head/sys/dev/neta/if_mvnetavar.h	Sat Feb  8 13:25:39 2020	(r357675)
+++ head/sys/dev/neta/if_mvnetavar.h	Sat Feb  8 13:33:47 2020	(r357676)
@@ -32,15 +32,12 @@
 #define	_IF_MVNETAVAR_H_
 #include <net/if.h>
 
-#define	MVNETA_HWHEADER_SIZE	2	/* Marvell Header */
-#define	MVNETA_ETHER_SIZE	22	/* Maximum ether size */
-#define	MVNETA_MAX_CSUM_MTU	1600	/* Port1,2 hw limit */
+#define	MVNETA_HWHEADER_SIZE		2	/* Marvell Header */
+#define	MVNETA_ETHER_SIZE		22	/* Maximum ether size */
+#define	MVNETA_A370_MAX_CSUM_MTU	1600	/* Max frame len for TX csum */
+#define	MVNETA_A3700_MAX_CSUM_MTU	9600
 
-/*
- * Limit support for frame up to hw csum limit
- * until jumbo frame support is added.
- */
-#define	MVNETA_MAX_FRAME		(MVNETA_MAX_CSUM_MTU + MVNETA_ETHER_SIZE)
+#define	MVNETA_MAX_FRAME		(MJUM9BYTES)
 
 /*
  * Default limit of queue length
@@ -54,7 +51,6 @@
 #define	MVNETA_BUFRING_SIZE	1024
 
 #define	MVNETA_PACKET_OFFSET	64
-#define	MVNETA_PACKET_SIZE	MCLBYTES
 
 #define	MVNETA_RXTH_COUNT	128
 #define	MVNETA_RX_REFILL_COUNT	8
@@ -268,6 +264,8 @@ struct mvneta_softc {
 	struct ifnet	*ifp;
 	uint32_t        mvneta_if_flags;
 	uint32_t        mvneta_media;
+	uint32_t	tx_csum_limit;
+	uint32_t	rx_frame_size;
 
 	int			phy_attached;
 	enum mvneta_phy_mode	phy_mode;


More information about the svn-src-head mailing list