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