svn commit: r362415 - head/sys/dev/dwc

Michal Meloun mmel at FreeBSD.org
Fri Jun 19 19:26:56 UTC 2020


Author: mmel
Date: Fri Jun 19 19:26:55 2020
New Revision: 362415
URL: https://svnweb.freebsd.org/changeset/base/362415

Log:
  Improve if_dwc:
   - refactorize packet receive path. Make sure that we don't leak mbufs
     and/or that we don't create holes in RX descriptor ring
   - slightly simplify handling with TX descriptors
  
  MFC after:	4 weeks

Modified:
  head/sys/dev/dwc/if_dwc.c
  head/sys/dev/dwc/if_dwcvar.h

Modified: head/sys/dev/dwc/if_dwc.c
==============================================================================
--- head/sys/dev/dwc/if_dwc.c	Fri Jun 19 19:25:47 2020	(r362414)
+++ head/sys/dev/dwc/if_dwc.c	Fri Jun 19 19:26:55 2020	(r362415)
@@ -235,45 +235,39 @@ dwc_get1paddr(void *arg, bus_dma_segment_t *segs, int 
 	*(bus_addr_t *)arg = segs[0].ds_addr;
 }
 
-inline static uint32_t
+inline static void
 dwc_setup_txdesc(struct dwc_softc *sc, int idx, bus_addr_t paddr,
     uint32_t len)
 {
-	uint32_t flags;
-	uint32_t nidx;
+	uint32_t desc0, desc1;
 
-	nidx = next_txidx(sc, idx);
-
 	/* Addr/len 0 means we're clearing the descriptor after xmit done. */
 	if (paddr == 0 || len == 0) {
-		flags = 0;
+		desc0 = 0;
+		desc1 = 0;
 		--sc->txcount;
 	} else {
-		if (sc->mactype != DWC_GMAC_EXT_DESC)
-			flags = NTDESC1_TCH | NTDESC1_FS
-			    | NTDESC1_LS | NTDESC1_IC;
-		else
-			flags = ETDESC0_TCH | ETDESC0_FS | ETDESC0_LS |
-				    ETDESC0_IC;
+		if (sc->mactype != DWC_GMAC_EXT_DESC) {
+			desc0 = 0;
+			desc1 = NTDESC1_TCH | NTDESC1_FS | NTDESC1_LS |
+			    NTDESC1_IC | len;
+		} else {
+			desc0 = ETDESC0_TCH | ETDESC0_FS | ETDESC0_LS |
+			    ETDESC0_IC;
+			desc1 = len;
+		}
 		++sc->txcount;
 	}
 
 	sc->txdesc_ring[idx].addr1 = (uint32_t)(paddr);
-	if (sc->mactype != DWC_GMAC_EXT_DESC) {
-		sc->txdesc_ring[idx].desc0 = 0;
-		sc->txdesc_ring[idx].desc1 = flags | len;
-	} else {
-		sc->txdesc_ring[idx].desc0 = flags;
-		sc->txdesc_ring[idx].desc1 = len;
-	}
+	sc->txdesc_ring[idx].desc0 = desc0;
+	sc->txdesc_ring[idx].desc1 = desc1;
 
 	if (paddr && len) {
 		wmb();
 		sc->txdesc_ring[idx].desc0 |= TDESC0_OWN;
 		wmb();
 	}
-
-	return (nidx);
 }
 
 static int
@@ -528,6 +522,7 @@ dwc_init(void *if_softc)
 	DWC_UNLOCK(sc);
 }
 
+
 inline static uint32_t
 dwc_setup_rxdesc(struct dwc_softc *sc, int idx, bus_addr_t paddr)
 {
@@ -538,14 +533,15 @@ dwc_setup_rxdesc(struct dwc_softc *sc, int idx, bus_ad
 	sc->rxdesc_ring[idx].addr2 = sc->rxdesc_ring_paddr +
 	    (nidx * sizeof(struct dwc_hwdesc));
 	if (sc->mactype != DWC_GMAC_EXT_DESC)
-		sc->rxdesc_ring[idx].desc1 = NRDESC1_RCH | RX_MAX_PACKET;
+		sc->rxdesc_ring[idx].desc1 = NRDESC1_RCH |
+		    MIN(MCLBYTES, NRDESC1_RBS1_MASK);
 	else
-		sc->rxdesc_ring[idx].desc1 = ERDESC1_RCH | MCLBYTES;
+		sc->rxdesc_ring[idx].desc1 = ERDESC1_RCH |
+		    MIN(MCLBYTES, ERDESC1_RBS1_MASK);
 
 	wmb();
 	sc->rxdesc_ring[idx].desc0 = RDESC0_OWN;
 	wmb();
-
 	return (nidx);
 }
 
@@ -585,6 +581,74 @@ dwc_alloc_mbufcl(struct dwc_softc *sc)
 	return (m);
 }
 
+static struct mbuf *
+dwc_rxfinish_one(struct dwc_softc *sc, struct dwc_hwdesc *desc,
+    struct dwc_bufmap *map)
+{
+	struct ifnet *ifp;
+	struct mbuf *m, *m0;
+	int len;
+	uint32_t rdesc0;
+
+	m = map->mbuf;
+	ifp = sc->ifp;
+	rdesc0 = desc ->desc0;
+	/* Validate descriptor. */
+	if (rdesc0 & RDESC0_ES) {
+		/*
+		 * Errored packet. Statistic counters are updated
+		 * globally, so do nothing
+		 */
+		return (NULL);
+	}
+
+	if ((rdesc0 & (RDESC0_FS | RDESC0_LS)) !=
+		    (RDESC0_FS | RDESC0_LS)) {
+		/*
+		 * Something very wrong happens. The whole packet should be
+		 * recevied in one descriptr. Report problem.
+		 */
+		device_printf(sc->dev,
+		    "%s: RX descriptor without FIRST and LAST bit set: 0x%08X",
+		    __func__, rdesc0);
+		return (NULL);
+	}
+
+	len = (rdesc0 >> RDESC0_FL_SHIFT) & RDESC0_FL_MASK;
+	if (len < 64) {
+		/*
+		 * Lenght is invalid, recycle old mbuf
+		 * Probably impossible case
+		 */
+		return (NULL);
+	}
+
+	/* Allocate new buffer */
+	m0 = dwc_alloc_mbufcl(sc);
+	if (m0 == NULL) {
+		/* no new mbuf available, recycle old */
+		if_inc_counter(sc->ifp, IFCOUNTER_IQDROPS, 1);
+		return (NULL);
+	}
+	/* Do dmasync for newly received packet */
+	bus_dmamap_sync(sc->rxbuf_tag, map->map, BUS_DMASYNC_POSTREAD);
+	bus_dmamap_unload(sc->rxbuf_tag, map->map);
+
+	/* Received packet is valid, process it */
+	m->m_pkthdr.rcvif = ifp;
+	m->m_pkthdr.len = len;
+	m->m_len = len;
+	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
+
+	/* Remove trailing FCS */
+	m_adj(m, -ETHER_CRC_LEN);
+
+	DWC_UNLOCK(sc);
+	(*ifp->if_input)(ifp, m);
+	DWC_LOCK(sc);
+	return (m0);
+}
+
 static void
 dwc_media_status(struct ifnet * ifp, struct ifmediareq *ifmr)
 {
@@ -820,52 +884,30 @@ static void
 dwc_rxfinish_locked(struct dwc_softc *sc)
 {
 	struct ifnet *ifp;
-	struct mbuf *m0;
 	struct mbuf *m;
-	int error, idx, len;
-	uint32_t rdes0;
+	int error, idx;
+	struct dwc_hwdesc *desc;
 
+	DWC_ASSERT_LOCKED(sc);
 	ifp = sc->ifp;
-
 	for (;;) {
 		idx = sc->rx_idx;
-
-		rdes0 = sc->rxdesc_ring[idx].desc0;
-		if ((rdes0 & RDESC0_OWN) != 0)
+		desc = sc->rxdesc_ring + idx;
+		if ((desc->desc0 & RDESC0_OWN) != 0)
 			break;
 
-		bus_dmamap_sync(sc->rxbuf_tag, sc->rxbuf_map[idx].map,
-		    BUS_DMASYNC_POSTREAD);
-		bus_dmamap_unload(sc->rxbuf_tag, sc->rxbuf_map[idx].map);
-
-		len = (rdes0 >> RDESC0_FL_SHIFT) & RDESC0_FL_MASK;
-		if (len != 0) {
-			m = sc->rxbuf_map[idx].mbuf;
-			m->m_pkthdr.rcvif = ifp;
-			m->m_pkthdr.len = len;
-			m->m_len = len;
-			if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
-
-			/* Remove trailing FCS */
-			m_adj(m, -ETHER_CRC_LEN);
-
-			DWC_UNLOCK(sc);
-			(*ifp->if_input)(ifp, m);
-			DWC_LOCK(sc);
+		m = dwc_rxfinish_one(sc, desc, sc->rxbuf_map + idx);
+		if (m == NULL) {
+			wmb();
+			desc->desc0 = RDESC0_OWN;
+			wmb();
 		} else {
-			/* XXX Zero-length packet ? */
+			/* We cannot create hole in RX ring */
+			error = dwc_setup_rxbuf(sc, idx, m);
+			if (error != 0)
+				panic("dwc_setup_rxbuf failed:  error %d\n",
+				    error);
 		}
-
-		if ((m0 = dwc_alloc_mbufcl(sc)) != NULL) {
-			if ((error = dwc_setup_rxbuf(sc, idx, m0)) != 0) {
-				/*
-				 * XXX Now what?
-				 * We've got a hole in the rx ring.
-				 */
-			}
-		} else
-			if_inc_counter(sc->ifp, IFCOUNTER_IQDROPS, 1);
-
 		sc->rx_idx = next_rxidx(sc, sc->rx_idx);
 	}
 }

Modified: head/sys/dev/dwc/if_dwcvar.h
==============================================================================
--- head/sys/dev/dwc/if_dwcvar.h	Fri Jun 19 19:25:47 2020	(r362414)
+++ head/sys/dev/dwc/if_dwcvar.h	Fri Jun 19 19:26:55 2020	(r362415)
@@ -44,7 +44,6 @@
 /*
  * Driver data and defines.
  */
-#define	RX_MAX_PACKET	0x7ff
 #define	RX_DESC_COUNT	1024
 #define	RX_DESC_SIZE	(sizeof(struct dwc_hwdesc) * RX_DESC_COUNT)
 #define	TX_DESC_COUNT	1024


More information about the svn-src-all mailing list