svn commit: r325984 - head/sys/arm/allwinner

Emmanuel Vadot manu at FreeBSD.org
Sat Nov 18 21:08:19 UTC 2017


Author: manu
Date: Sat Nov 18 21:08:18 2017
New Revision: 325984
URL: https://svnweb.freebsd.org/changeset/base/325984

Log:
  if_awg: avoid hole in the rx ring buffer when mbuf allocation fails
  
  Use a spare dma map when attempting to map a new mbuf on the rx path.
  If the mbuf allocation fails or the dma map loading for the new mbuf fails just reuse the old mbuf
  and increase the drop counter.
  
  Submitted by:	Guy Yur <guyyur at gmail.com>
  Differential Revision:	https://reviews.freebsd.org/D12538

Modified:
  head/sys/arm/allwinner/if_awg.c

Modified: head/sys/arm/allwinner/if_awg.c
==============================================================================
--- head/sys/arm/allwinner/if_awg.c	Sat Nov 18 21:04:39 2017	(r325983)
+++ head/sys/arm/allwinner/if_awg.c	Sat Nov 18 21:08:18 2017	(r325984)
@@ -179,6 +179,7 @@ struct awg_rxring {
 	bus_addr_t		desc_ring_paddr;
 	bus_dma_tag_t		buf_tag;
 	struct awg_bufmap	buf_map[RX_DESC_COUNT];
+	bus_dmamap_t		buf_spare_map;
 	u_int			cur;
 };
 
@@ -519,24 +520,45 @@ awg_setup_rxdesc(struct awg_softc *sc, int index, bus_
 
 	sc->rx.desc_ring[index].addr = htole32((uint32_t)paddr);
 	sc->rx.desc_ring[index].size = htole32(size);
-	sc->rx.desc_ring[index].next =
-	    htole32(sc->rx.desc_ring_paddr + DESC_OFF(RX_NEXT(index)));
 	sc->rx.desc_ring[index].status = htole32(status);
 }
 
+static void
+awg_reuse_rxdesc(struct awg_softc *sc, int index)
+{
+
+	sc->rx.desc_ring[index].status = htole32(RX_DESC_CTL);
+}
+
 static int
-awg_setup_rxbuf(struct awg_softc *sc, int index, struct mbuf *m)
+awg_newbuf_rx(struct awg_softc *sc, int index)
 {
+	struct mbuf *m;
 	bus_dma_segment_t seg;
-	int error, nsegs;
+	bus_dmamap_t map;
+	int nsegs;
 
+	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
+	if (m == NULL)
+		return (ENOBUFS);
+
+	m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;
 	m_adj(m, ETHER_ALIGN);
 
-	error = bus_dmamap_load_mbuf_sg(sc->rx.buf_tag,
-	    sc->rx.buf_map[index].map, m, &seg, &nsegs, 0);
-	if (error != 0)
-		return (error);
+	if (bus_dmamap_load_mbuf_sg(sc->rx.buf_tag, sc->rx.buf_spare_map,
+	    m, &seg, &nsegs, BUS_DMA_NOWAIT) != 0) {
+		m_freem(m);
+		return (ENOBUFS);
+	}
 
+	if (sc->rx.buf_map[index].mbuf != NULL) {
+		bus_dmamap_sync(sc->rx.buf_tag, sc->rx.buf_map[index].map,
+		    BUS_DMASYNC_POSTREAD);
+		bus_dmamap_unload(sc->rx.buf_tag, sc->rx.buf_map[index].map);
+	}
+	map = sc->rx.buf_map[index].map;
+	sc->rx.buf_map[index].map = sc->rx.buf_spare_map;
+	sc->rx.buf_spare_map = map;
 	bus_dmamap_sync(sc->rx.buf_tag, sc->rx.buf_map[index].map,
 	    BUS_DMASYNC_PREREAD);
 
@@ -546,18 +568,6 @@ awg_setup_rxbuf(struct awg_softc *sc, int index, struc
 	return (0);
 }
 
-static struct mbuf *
-awg_alloc_mbufcl(struct awg_softc *sc)
-{
-	struct mbuf *m;
-
-	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
-	if (m != NULL)
-		m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;
-
-	return (m);
-}
-
 static void
 awg_start_locked(struct awg_softc *sc)
 {
@@ -840,7 +850,7 @@ static int
 awg_rxintr(struct awg_softc *sc)
 {
 	if_t ifp;
-	struct mbuf *m, *m0, *mh, *mt;
+	struct mbuf *m, *mh, *mt;
 	int error, index, len, cnt, npkt;
 	uint32_t status;
 
@@ -857,61 +867,62 @@ awg_rxintr(struct awg_softc *sc)
 		if ((status & RX_DESC_CTL) != 0)
 			break;
 
-		bus_dmamap_sync(sc->rx.buf_tag, sc->rx.buf_map[index].map,
-		    BUS_DMASYNC_POSTREAD);
-		bus_dmamap_unload(sc->rx.buf_tag, sc->rx.buf_map[index].map);
-
 		len = (status & RX_FRM_LEN) >> RX_FRM_LEN_SHIFT;
-		if (len != 0) {
-			m = sc->rx.buf_map[index].mbuf;
-			m->m_pkthdr.rcvif = ifp;
-			m->m_pkthdr.len = len;
-			m->m_len = len;
-			if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
 
-			if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0 &&
-			    (status & RX_FRM_TYPE) != 0) {
-				m->m_pkthdr.csum_flags = CSUM_IP_CHECKED;
-				if ((status & RX_HEADER_ERR) == 0)
-					m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
-				if ((status & RX_PAYLOAD_ERR) == 0) {
-					m->m_pkthdr.csum_flags |=
-					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
-					m->m_pkthdr.csum_data = 0xffff;
-				}
-			}
+		if (len == 0) {
+			if ((status & (RX_NO_ENOUGH_BUF_ERR | RX_OVERFLOW_ERR)) != 0)
+				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
+			awg_reuse_rxdesc(sc, index);
+			continue;
+		}
 
-			m->m_nextpkt = NULL;
-			if (mh == NULL)
-				mh = m;
-			else
-				mt->m_nextpkt = m;
-			mt = m;
-			++cnt;
-			++npkt;
+		m = sc->rx.buf_map[index].mbuf;
 
-			if (cnt == awg_rx_batch) {
-				AWG_UNLOCK(sc);
-				if_input(ifp, mh);
-				AWG_LOCK(sc);
-				mh = mt = NULL;
-				cnt = 0;
-			}
-			
+		error = awg_newbuf_rx(sc, index);
+		if (error != 0) {
+			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
+			awg_reuse_rxdesc(sc, index);
+			continue;
 		}
 
-		if ((m0 = awg_alloc_mbufcl(sc)) != NULL) {
-			error = awg_setup_rxbuf(sc, index, m0);
-			if (error != 0) {
-				/* XXX hole in RX ring */
+		m->m_pkthdr.rcvif = ifp;
+		m->m_pkthdr.len = len;
+		m->m_len = len;
+		if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
+
+		if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0 &&
+		    (status & RX_FRM_TYPE) != 0) {
+			m->m_pkthdr.csum_flags = CSUM_IP_CHECKED;
+			if ((status & RX_HEADER_ERR) == 0)
+				m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
+			if ((status & RX_PAYLOAD_ERR) == 0) {
+				m->m_pkthdr.csum_flags |=
+				    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
+				m->m_pkthdr.csum_data = 0xffff;
 			}
-		} else
-			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
+		}
+
+		m->m_nextpkt = NULL;
+		if (mh == NULL)
+			mh = m;
+		else
+			mt->m_nextpkt = m;
+		mt = m;
+		++cnt;
+		++npkt;
+
+		if (cnt == awg_rx_batch) {
+			AWG_UNLOCK(sc);
+			if_input(ifp, mh);
+			AWG_LOCK(sc);
+			mh = mt = NULL;
+			cnt = 0;
+		}
 	}
 
 	if (index != sc->rx.cur) {
 		bus_dmamap_sync(sc->rx.desc_tag, sc->rx.desc_map,
-		    BUS_DMASYNC_PREWRITE);
+		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 	}
 
 	if (mh != NULL) {
@@ -1500,7 +1511,6 @@ static int
 awg_setup_dma(device_t dev)
 {
 	struct awg_softc *sc;
-	struct mbuf *m;
 	int error, i;
 
 	sc = device_get_softc(dev);
@@ -1615,18 +1625,25 @@ awg_setup_dma(device_t dev)
 		return (error);
 	}
 
+	error = bus_dmamap_create(sc->rx.buf_tag, 0, &sc->rx.buf_spare_map);
+	if (error != 0) {
+		device_printf(dev,
+		    "cannot create RX buffer spare map\n");
+		return (error);
+	}
+
 	for (i = 0; i < RX_DESC_COUNT; i++) {
+		sc->rx.desc_ring[i].next =
+		    htole32(sc->rx.desc_ring_paddr + DESC_OFF(RX_NEXT(i)));
+
 		error = bus_dmamap_create(sc->rx.buf_tag, 0,
 		    &sc->rx.buf_map[i].map);
 		if (error != 0) {
 			device_printf(dev, "cannot create RX buffer map\n");
 			return (error);
 		}
-		if ((m = awg_alloc_mbufcl(sc)) == NULL) {
-			device_printf(dev, "cannot allocate RX mbuf\n");
-			return (ENOMEM);
-		}
-		error = awg_setup_rxbuf(sc, i, m);
+		sc->rx.buf_map[i].mbuf = NULL;
+		error = awg_newbuf_rx(sc, i);
 		if (error != 0) {
 			device_printf(dev, "cannot create RX buffer\n");
 			return (error);


More information about the svn-src-all mailing list