aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorEmmanuel Vadot <manu@FreeBSD.org>2017-11-18 20:46:31 +0000
committerEmmanuel Vadot <manu@FreeBSD.org>2017-11-18 20:46:31 +0000
commitfce9d29f8d7d0174aa93a825c1a9fed1f3b0f862 (patch)
tree20ff91e961db83256630d8009971ed5e8da7d121 /sys
parentc6110e75146b65100ed334ba59e9cd434c86daed (diff)
downloadsrc-fce9d29f8d7d0174aa93a825c1a9fed1f3b0f862.tar.gz
src-fce9d29f8d7d0174aa93a825c1a9fed1f3b0f862.zip
if_awg: store mbuf and dma mapping in the last segment of a tx frame instead of the first
According to the datasheet, TX_DESC_CTL is cleared when whole frame is transmitted or all data in the current descriptor's buffer are transmitted. When the mbuf and mapping are stored in the first segment and in a scenario where a tx completion interrupt arrives for a frame and only the start of the next frame was transmitted, at the time of interrupt processing the mbuf and mapping will be freed when processing the first segment of the next frame but the other untrasmitted segments still need to use them. Submitted by: Guy Yur <guyyur@gmail.com> Differential Revision: https://reviews.freebsd.org/D13031
Notes
Notes: svn path=/head/; revision=325979
Diffstat (limited to 'sys')
-rw-r--r--sys/arm/allwinner/if_awg.c21
1 files changed, 13 insertions, 8 deletions
diff --git a/sys/arm/allwinner/if_awg.c b/sys/arm/allwinner/if_awg.c
index 038349b5abe1..e19213657fc9 100644
--- a/sys/arm/allwinner/if_awg.c
+++ b/sys/arm/allwinner/if_awg.c
@@ -390,17 +390,19 @@ awg_media_change(if_t ifp)
static int
awg_setup_txbuf(struct awg_softc *sc, int index, struct mbuf **mp)
{
+ bus_dmamap_t map;
bus_dma_segment_t segs[TX_MAX_SEGS];
- int error, nsegs, cur, first, i;
+ int error, nsegs, cur, first, last, i;
u_int csum_flags;
uint32_t flags, status;
struct mbuf *m;
cur = first = index;
+ map = sc->tx.buf_map[first].map;
m = *mp;
- error = bus_dmamap_load_mbuf_sg(sc->tx.buf_tag,
- sc->tx.buf_map[index].map, m, segs, &nsegs, BUS_DMA_NOWAIT);
+ error = bus_dmamap_load_mbuf_sg(sc->tx.buf_tag, map, m, segs,
+ &nsegs, BUS_DMA_NOWAIT);
if (error == EFBIG) {
m = m_collapse(m, M_NOWAIT, TX_MAX_SEGS);
if (m == NULL) {
@@ -408,16 +410,15 @@ awg_setup_txbuf(struct awg_softc *sc, int index, struct mbuf **mp)
return (0);
}
*mp = m;
- error = bus_dmamap_load_mbuf_sg(sc->tx.buf_tag,
- sc->tx.buf_map[index].map, m, segs, &nsegs, BUS_DMA_NOWAIT);
+ error = bus_dmamap_load_mbuf_sg(sc->tx.buf_tag, map, m,
+ segs, &nsegs, BUS_DMA_NOWAIT);
}
if (error != 0) {
device_printf(sc->dev, "awg_setup_txbuf: bus_dmamap_load_mbuf_sg failed\n");
return (0);
}
- bus_dmamap_sync(sc->tx.buf_tag, sc->tx.buf_map[index].map,
- BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(sc->tx.buf_tag, map, BUS_DMASYNC_PREWRITE);
flags = TX_FIR_DESC;
status = 0;
@@ -458,7 +459,11 @@ awg_setup_txbuf(struct awg_softc *sc, int index, struct mbuf **mp)
cur = TX_NEXT(cur);
}
- sc->tx.buf_map[first].mbuf = m;
+ /* Store mapping and mbuf in the last segment */
+ last = TX_SKIP(cur, TX_DESC_COUNT - 1);
+ sc->tx.buf_map[first].map = sc->tx.buf_map[last].map;
+ sc->tx.buf_map[last].map = map;
+ sc->tx.buf_map[last].mbuf = m;
/*
* The whole mbuf chain has been DMA mapped,