[Midnightbsd-cvs] src [8776] trunk/sys/dev/age: Rework jumbo frame handling.

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sun Sep 25 22:59:39 EDT 2016


Revision: 8776
          http://svnweb.midnightbsd.org/src/?rev=8776
Author:   laffer1
Date:     2016-09-25 22:59:39 -0400 (Sun, 25 Sep 2016)
Log Message:
-----------
Rework jumbo frame handling. QAC confirmed that the controller requires 8 bytes alignment on RX buffer. Given that non-jumbo frame works on any alignment I guess this DMA limitation for RX buffer could be jumbo frame specific one

Modified Paths:
--------------
    trunk/sys/dev/age/if_age.c
    trunk/sys/dev/age/if_agevar.h

Modified: trunk/sys/dev/age/if_age.c
===================================================================
--- trunk/sys/dev/age/if_age.c	2016-09-26 02:58:21 UTC (rev 8775)
+++ trunk/sys/dev/age/if_age.c	2016-09-26 02:59:39 UTC (rev 8776)
@@ -142,6 +142,9 @@
 static void age_init_rr_ring(struct age_softc *);
 static void age_init_cmb_block(struct age_softc *);
 static void age_init_smb_block(struct age_softc *);
+#ifndef __NO_STRICT_ALIGNMENT
+static struct mbuf *age_fixup_rx(struct ifnet *, struct mbuf *);
+#endif
 static int age_newbuf(struct age_softc *, struct age_rxdesc *);
 static void age_rxvlan(struct age_softc *);
 static void age_rxfilter(struct age_softc *);
@@ -1133,7 +1136,7 @@
 	/* Create tag for Rx buffers. */
 	error = bus_dma_tag_create(
 	    sc->age_cdata.age_buffer_tag, /* parent */
-	    1, 0,			/* alignment, boundary */
+	    AGE_RX_BUF_ALIGN, 0,	/* alignment, boundary */
 	    BUS_SPACE_MAXADDR,		/* lowaddr */
 	    BUS_SPACE_MAXADDR,		/* highaddr */
 	    NULL, NULL,			/* filter, filterarg */
@@ -2268,16 +2271,53 @@
 	}
 }
 
+#ifndef __NO_STRICT_ALIGNMENT
+static struct mbuf *
+age_fixup_rx(struct ifnet *ifp, struct mbuf *m)
+{
+	struct mbuf *n;
+        int i;
+        uint16_t *src, *dst;
+
+	src = mtod(m, uint16_t *);
+	dst = src - 3;
+
+	if (m->m_next == NULL) {
+		for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++)
+			*dst++ = *src++;
+		m->m_data -= 6;
+		return (m);
+	}
+	/*
+	 * Append a new mbuf to received mbuf chain and copy ethernet
+	 * header from the mbuf chain. This can save lots of CPU
+	 * cycles for jumbo frame.
+	 */
+	MGETHDR(n, M_NOWAIT, MT_DATA);
+	if (n == NULL) {
+		ifp->if_iqdrops++;
+		m_freem(m);
+		return (NULL);
+	}
+	bcopy(m->m_data, n->m_data, ETHER_HDR_LEN);
+	m->m_data += ETHER_HDR_LEN;
+	m->m_len -= ETHER_HDR_LEN;
+	n->m_len = ETHER_HDR_LEN;
+	M_MOVE_PKTHDR(n, m);
+	n->m_next = m;
+	return (n);
+}
+#endif
+
 /* Receive a frame. */
 static void
 age_rxeof(struct age_softc *sc, struct rx_rdesc *rxrd)
 {
 	struct age_rxdesc *rxd;
-	struct rx_desc *desc;
 	struct ifnet *ifp;
 	struct mbuf *mp, *m;
 	uint32_t status, index, vtag;
-	int count, nsegs, pktlen;
+	int count, nsegs;
 	int rx_cons;
 
 	AGE_LOCK_ASSERT(sc);
@@ -2289,9 +2329,7 @@
 	nsegs = AGE_RX_NSEGS(index);
 
 	sc->age_cdata.age_rxlen = AGE_RX_BYTES(le32toh(rxrd->len));
-	if ((status & AGE_RRD_ERROR) != 0 &&
-	    (status & (AGE_RRD_CRC | AGE_RRD_CODE | AGE_RRD_DRIBBLE |
-	    AGE_RRD_RUNT | AGE_RRD_OFLOW | AGE_RRD_TRUNC)) != 0) {
+	if ((status & (AGE_RRD_ERROR | AGE_RRD_LENGTH_NOK)) != 0) {
 		/*
 		 * We want to pass the following frames to upper
 		 * layer regardless of error status of Rx return
@@ -2301,33 +2339,31 @@
 		 *  o frame length and protocol specific length
 		 *     does not match.
 		 */
-		sc->age_cdata.age_rx_cons += nsegs;
-		sc->age_cdata.age_rx_cons %= AGE_RX_RING_CNT;
-		return;
+		status |= AGE_RRD_IPCSUM_NOK | AGE_RRD_TCP_UDPCSUM_NOK;
+		if ((status & (AGE_RRD_CRC | AGE_RRD_CODE | AGE_RRD_DRIBBLE |
+		    AGE_RRD_RUNT | AGE_RRD_OFLOW | AGE_RRD_TRUNC)) != 0)
+			return;
 	}
 
-	pktlen = 0;
 	for (count = 0; count < nsegs; count++,
 	    AGE_DESC_INC(rx_cons, AGE_RX_RING_CNT)) {
 		rxd = &sc->age_cdata.age_rxdesc[rx_cons];
 		mp = rxd->rx_m;
-		desc = rxd->rx_desc;
 		/* Add a new receive buffer to the ring. */
 		if (age_newbuf(sc, rxd) != 0) {
 			ifp->if_iqdrops++;
 			/* Reuse Rx buffers. */
-			if (sc->age_cdata.age_rxhead != NULL) {
+			if (sc->age_cdata.age_rxhead != NULL)
 				m_freem(sc->age_cdata.age_rxhead);
-				AGE_RXCHAIN_RESET(sc);
-			}
 			break;
 		}
 
-		/* The length of the first mbuf is computed last. */
-		if (count != 0) {
-			mp->m_len = AGE_RX_BYTES(le32toh(desc->len));
-			pktlen += mp->m_len;
-		}
+		/*
+		 * Assume we've received a full sized frame.
+		 * Actual size is fixed when we encounter the end of
+		 * multi-segmented frame.
+		 */
+		mp->m_len = AGE_RX_BUF_SIZE;
 
 		/* Chain received mbufs. */
 		if (sc->age_cdata.age_rxhead == NULL) {
@@ -2342,14 +2378,20 @@
 		}
 
 		if (count == nsegs - 1) {
+			/* Last desc. for this frame. */
+			m = sc->age_cdata.age_rxhead;
+			m->m_flags |= M_PKTHDR;
 			/*
 			 * It seems that L1 controller has no way
 			 * to tell hardware to strip CRC bytes.
 			 */
-			sc->age_cdata.age_rxlen -= ETHER_CRC_LEN;
+			m->m_pkthdr.len = sc->age_cdata.age_rxlen -
+			    ETHER_CRC_LEN;
 			if (nsegs > 1) {
+				/* Set last mbuf size. */
+				mp->m_len = sc->age_cdata.age_rxlen -
+				    ((nsegs - 1) * AGE_RX_BUF_SIZE);
 				/* Remove the CRC bytes in chained mbufs. */
-				pktlen -= ETHER_CRC_LEN;
 				if (mp->m_len <= ETHER_CRC_LEN) {
 					sc->age_cdata.age_rxtail =
 					    sc->age_cdata.age_rxprev_tail;
@@ -2360,15 +2402,9 @@
 				} else {
 					mp->m_len -= ETHER_CRC_LEN;
 				}
-			}
-
-			m = sc->age_cdata.age_rxhead;
-			m->m_flags |= M_PKTHDR;
+			} else
+				m->m_len = m->m_pkthdr.len;
 			m->m_pkthdr.rcvif = ifp;
-			m->m_pkthdr.len = sc->age_cdata.age_rxlen;
-			/* Set the first mbuf length. */
-			m->m_len = sc->age_cdata.age_rxlen - pktlen;
-
 			/*
 			 * Set checksum information.
 			 * It seems that L1 controller can compute partial
@@ -2383,9 +2419,9 @@
 			 */
 			if ((ifp->if_capenable & IFCAP_RXCSUM) != 0 &&
 			    (status & AGE_RRD_IPV4) != 0) {
-				m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
 				if ((status & AGE_RRD_IPCSUM_NOK) == 0)
-					m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
+					m->m_pkthdr.csum_flags |=
+					    CSUM_IP_CHECKED | CSUM_IP_VALID;
 				if ((status & (AGE_RRD_TCP | AGE_RRD_UDP)) &&
 				    (status & AGE_RRD_TCP_UDPCSUM_NOK) == 0) {
 					m->m_pkthdr.csum_flags |=
@@ -2406,22 +2442,21 @@
 				m->m_pkthdr.ether_vtag = AGE_RX_VLAN_TAG(vtag);
 				m->m_flags |= M_VLANTAG;
 			}
-
+#ifndef __NO_STRICT_ALIGNMENT
+			m = age_fixup_rx(ifp, m);
+			if (m != NULL)
+#endif
+			{
 			/* Pass it on. */
 			AGE_UNLOCK(sc);
 			(*ifp->if_input)(ifp, m);
 			AGE_LOCK(sc);
-
-			/* Reset mbuf chains. */
-			AGE_RXCHAIN_RESET(sc);
+			}
 		}
 	}
 
-	if (count != nsegs) {
-		sc->age_cdata.age_rx_cons += nsegs;
-		sc->age_cdata.age_rx_cons %= AGE_RX_RING_CNT;
-	} else
-		sc->age_cdata.age_rx_cons = rx_cons;
+	/* Reset mbuf chains. */
+	AGE_RXCHAIN_RESET(sc);
 }
 
 static int
@@ -2456,16 +2491,16 @@
 		 * I'm not sure whether this check is really needed.
 		 */
 		pktlen = AGE_RX_BYTES(le32toh(rxrd->len));
-		if (nsegs != ((pktlen + (MCLBYTES - ETHER_ALIGN - 1)) /
-		    (MCLBYTES - ETHER_ALIGN)))
+		if (nsegs != (pktlen + (AGE_RX_BUF_SIZE - 1)) / AGE_RX_BUF_SIZE)
 			break;
 
-		prog++;
 		/* Received a frame. */
 		age_rxeof(sc, rxrd);
 		/* Clear return ring. */
 		rxrd->index = 0;
 		AGE_DESC_INC(rr_cons, AGE_RR_RING_CNT);
+		sc->age_cdata.age_rx_cons += nsegs;
+		sc->age_cdata.age_rx_cons %= AGE_RX_RING_CNT;
 	}
 
 	if (prog > 0) {
@@ -3065,7 +3100,9 @@
 	if (m == NULL)
 		return (ENOBUFS);
 	m->m_len = m->m_pkthdr.len = MCLBYTES;
-	m_adj(m, ETHER_ALIGN);
+#ifndef __NO_STRICT_ALIGNMENT
+	m_adj(m, AGE_RX_BUF_ALIGN);
+#endif
 
 	if (bus_dmamap_load_mbuf_sg(sc->age_cdata.age_rx_tag,
 	    sc->age_cdata.age_rx_sparemap, m, segs, &nsegs, 0) != 0) {

Modified: trunk/sys/dev/age/if_agevar.h
===================================================================
--- trunk/sys/dev/age/if_agevar.h	2016-09-26 02:58:21 UTC (rev 8775)
+++ trunk/sys/dev/age/if_agevar.h	2016-09-26 02:59:39 UTC (rev 8776)
@@ -43,6 +43,12 @@
 #define	AGE_TSO_MAXSEGSIZE	4096
 #define	AGE_TSO_MAXSIZE		(65535 + sizeof(struct ether_vlan_header))
 #define	AGE_MAXTXSEGS		32
+#define	AGE_RX_BUF_ALIGN	8
+#ifndef __NO_STRICT_ALIGNMENT
+#define	AGE_RX_BUF_SIZE		(MCLBYTES - AGE_RX_BUF_ALIGN)	
+#else
+#define	AGE_RX_BUF_SIZE		(MCLBYTES)	
+#endif
 
 #define	AGE_ADDR_LO(x)		((uint64_t) (x) & 0xFFFFFFFF)
 #define	AGE_ADDR_HI(x)		((uint64_t) (x) >> 32)



More information about the Midnightbsd-cvs mailing list