aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorEmmanuel Vadot <manu@FreeBSD.org>2017-11-18 21:08:18 +0000
committerEmmanuel Vadot <manu@FreeBSD.org>2017-11-18 21:08:18 +0000
commitbd9063297c518e5a9743cfe2d7df516d6c8054d9 (patch)
treee2b3032964afff51f1d1b37707de2f4c8bc0c48c /sys
parent337c6940a9fac95ce4ff94192feb14bd7a587176 (diff)
downloadsrc-bd9063297c518e5a9743cfe2d7df516d6c8054d9.tar.gz
src-bd9063297c518e5a9743cfe2d7df516d6c8054d9.zip
Notes
Diffstat (limited to 'sys')
-rw-r--r--sys/arm/allwinner/if_awg.c161
1 files changed, 89 insertions, 72 deletions
diff --git a/sys/arm/allwinner/if_awg.c b/sys/arm/allwinner/if_awg.c
index 04f0128b2bf5..64085703583a 100644
--- a/sys/arm/allwinner/if_awg.c
+++ b/sys/arm/allwinner/if_awg.c
@@ -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_addr_t paddr)
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, struct mbuf *m)
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;
- }
- }
- m->m_nextpkt = NULL;
- if (mh == NULL)
- mh = m;
- else
- mt->m_nextpkt = m;
- mt = m;
- ++cnt;
- ++npkt;
+ 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;
+ }
- if (cnt == awg_rx_batch) {
- AWG_UNLOCK(sc);
- if_input(ifp, mh);
- AWG_LOCK(sc);
- mh = mt = NULL;
- cnt = 0;
- }
-
+ m = sc->rx.buf_map[index].mbuf;
+
+ 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);