Page MenuHomeFreeBSD

D12537.1793782331.diff
No OneTemporary

Authored By
Unknown
Size
7 KB
Referenced Files
None
Subscribers
None

D12537.1793782331.diff

Index: sys/arm/allwinner/if_awg.c
===================================================================
--- sys/arm/allwinner/if_awg.c
+++ sys/arm/allwinner/if_awg.c
@@ -104,6 +104,8 @@
#define TX_INTERVAL_DEFAULT 64
#define RX_BATCH_DEFAULT 64
+#define TX_INTERVAL_NEXT(n) (((n) + 1) & (awg_tx_interval - 1))
+
/* syscon EMAC clock register */
#define EMAC_CLK_EPHY_ADDR (0x1f << 20) /* H3 */
#define EMAC_CLK_EPHY_ADDR_SHIFT 20
@@ -169,6 +171,7 @@
bus_dma_tag_t buf_tag;
struct awg_bufmap buf_map[TX_DESC_COUNT];
u_int cur, next, queued;
+ u_int pkts;
};
struct awg_rxring {
@@ -212,6 +215,8 @@
{ -1, 0 }
};
+static void awg_txeof(struct awg_softc *sc);
+
static int
awg_miibus_readreg(device_t dev, int phy, int reg)
{
@@ -385,55 +390,52 @@
return (error);
}
-static void
-awg_setup_txdesc(struct awg_softc *sc, int index, int flags, bus_addr_t paddr,
- u_int len)
-{
- uint32_t status, size;
-
- if (paddr == 0 || len == 0) {
- status = 0;
- size = 0;
- --sc->tx.queued;
- } else {
- status = TX_DESC_CTL;
- size = flags | len;
- if ((index & (awg_tx_interval - 1)) == 0)
- size |= TX_INT_CTL;
- ++sc->tx.queued;
- }
-
- sc->tx.desc_ring[index].addr = htole32((uint32_t)paddr);
- sc->tx.desc_ring[index].size = htole32(size);
- sc->tx.desc_ring[index].status = htole32(status);
-}
-
static int
-awg_setup_txbuf(struct awg_softc *sc, int index, struct mbuf **mp)
+awg_encap(struct awg_softc *sc, struct mbuf **mp)
{
+ bus_dmamap_t map;
bus_dma_segment_t segs[TX_MAX_SEGS];
- int error, nsegs, cur, i, flags;
+ int error, i, nsegs, cur, first, last;
+ uint32_t flags, status;
u_int csum_flags;
struct mbuf *m;
+ cur = first = sc->tx.cur;
+ 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)
- return (0);
+ if (m == NULL) {
+ m_freem(*mp);
+ *mp = NULL;
+ return (ENOMEM);
+ }
*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) {
+ m_freem(*mp);
+ *mp = NULL;
+ return (ENOMEM);
+ }
+ } else if (error != 0)
+ return (error);
+ if (nsegs == 0) {
+ m_freem(*mp);
+ *mp = NULL;
+ return (EIO);
}
- if (error != 0)
- return (0);
- bus_dmamap_sync(sc->tx.buf_tag, sc->tx.buf_map[index].map,
- BUS_DMASYNC_PREWRITE);
+ if (sc->tx.queued + nsegs > TX_DESC_COUNT) {
+ bus_dmamap_unload(sc->tx.buf_tag, map);
+ return (ENOBUFS);
+ }
flags = TX_FIR_DESC;
+ status = 0;
if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) {
if ((m->m_pkthdr.csum_flags & (CSUM_TCP|CSUM_UDP)) != 0)
csum_flags = TX_CHECKSUM_CTL_FULL;
@@ -442,17 +444,67 @@
flags |= (csum_flags << TX_CHECKSUM_CTL_SHIFT);
}
- for (cur = index, i = 0; i < nsegs; i++) {
- sc->tx.buf_map[cur].mbuf = (i == 0 ? m : NULL);
- if (i == nsegs - 1)
+ bus_dmamap_sync(sc->tx.buf_tag, map, BUS_DMASYNC_PREWRITE);
+
+ for (i = 0; i < nsegs; i++) {
+ if (i == nsegs - 1) {
flags |= TX_LAST_DESC;
- awg_setup_txdesc(sc, cur, flags, segs[i].ds_addr,
- segs[i].ds_len);
+ /*
+ * Request Tx completion interrupt for
+ * every awg_tx_interval frames.
+ */
+ sc->tx.pkts = TX_INTERVAL_NEXT(sc->tx.pkts);
+ if (sc->tx.pkts == 0)
+ flags |= TX_INT_CTL;
+ }
+
+ sc->tx.desc_ring[cur].addr = htole32((uint32_t)segs[i].ds_addr);
+ sc->tx.desc_ring[cur].size = htole32(flags | segs[i].ds_len);
+ sc->tx.desc_ring[cur].status = htole32(status);
+
flags &= ~TX_FIR_DESC;
+
+ /*
+ * Setting of the valid bit in the first descriptor is
+ * deferred until the whole chain is fully setup.
+ */
+ status = TX_DESC_CTL;
+
+ ++sc->tx.queued;
cur = TX_NEXT(cur);
}
- return (nsegs);
+ /*
+ * the whole mbuf chain has been DMA mapped, fix first descriptor.
+ */
+ sc->tx.desc_ring[first].status = htole32(TX_DESC_CTL);
+
+ sc->tx.cur = cur;
+
+ /* 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;
+
+ return (0);
+}
+
+static void
+awg_clean_txbuf(struct awg_softc *sc, int index)
+{
+ struct awg_bufmap *bmap;
+
+ --sc->tx.queued;
+
+ bmap = &sc->tx.buf_map[index];
+ if (bmap->mbuf != NULL) {
+ bus_dmamap_sync(sc->tx.buf_tag, bmap->map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->tx.buf_tag, bmap->map);
+ m_freem(bmap->mbuf);
+ bmap->mbuf = NULL;
+ }
}
static void
@@ -510,7 +562,7 @@
struct mbuf *m;
uint32_t val;
if_t ifp;
- int cnt, nsegs;
+ int cnt, err;
AWG_ASSERT_LOCKED(sc);
@@ -524,22 +576,19 @@
return;
for (cnt = 0; ; cnt++) {
- if (sc->tx.queued >= TX_DESC_COUNT - TX_MAX_SEGS) {
- if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
- break;
- }
-
m = if_dequeue(ifp);
if (m == NULL)
break;
- nsegs = awg_setup_txbuf(sc, sc->tx.cur, &m);
- if (nsegs == 0) {
- if_sendq_prepend(ifp, m);
+ err = awg_encap(sc, &m);
+ if (err != 0) {
+ if (err == ENOBUFS)
+ if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
+ if (m != NULL)
+ if_sendq_prepend(ifp, m);
break;
}
if_bpfmtap(ifp, m);
- sc->tx.cur = TX_SKIP(sc->tx.cur, nsegs);
}
if (cnt != 0) {
@@ -875,13 +924,12 @@
}
static void
-awg_txintr(struct awg_softc *sc)
+awg_txeof(struct awg_softc *sc)
{
- struct awg_bufmap *bmap;
struct emac_desc *desc;
- uint32_t status;
+ uint32_t status, size;
if_t ifp;
- int i;
+ int i, prog;
AWG_ASSERT_LOCKED(sc);
@@ -889,28 +937,29 @@
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
ifp = sc->ifp;
+
+ prog = 0;
for (i = sc->tx.next; sc->tx.queued > 0; i = TX_NEXT(i)) {
desc = &sc->tx.desc_ring[i];
status = le32toh(desc->status);
if ((status & TX_DESC_CTL) != 0)
break;
- bmap = &sc->tx.buf_map[i];
- if (bmap->mbuf != NULL) {
- bus_dmamap_sync(sc->tx.buf_tag, bmap->map,
- BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->tx.buf_tag, bmap->map);
- m_freem(bmap->mbuf);
- bmap->mbuf = NULL;
+
+ prog++;
+ awg_clean_txbuf(sc, i);
+ size = le32toh(desc->size);
+ if (size & TX_LAST_DESC) {
+ if ((status & (TX_HEADER_ERR | TX_PAYLOAD_ERR)) != 0)
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+ else
+ if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
}
- awg_setup_txdesc(sc, i, 0, 0, 0);
- if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
- if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
}
- sc->tx.next = i;
-
- bus_dmamap_sync(sc->tx.desc_tag, sc->tx.desc_map,
- BUS_DMASYNC_PREWRITE);
+ if (prog > 0) {
+ sc->tx.next = i;
+ if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
+ }
}
static void
@@ -928,8 +977,10 @@
if (val & RX_INT)
awg_rxintr(sc);
- if (val & (TX_INT|TX_BUF_UA_INT)) {
- awg_txintr(sc);
+ if (val & TX_INT)
+ awg_txeof(sc);
+
+ if (val & (TX_INT | TX_BUF_UA_INT)) {
if (!if_sendq_empty(sc->ifp))
awg_start_locked(sc);
}
@@ -956,7 +1007,7 @@
}
rx_npkts = awg_rxintr(sc);
- awg_txintr(sc);
+ awg_txeof(sc);
if (!if_sendq_empty(ifp))
awg_start_locked(sc);
@@ -1505,7 +1556,7 @@
return (error);
}
- sc->tx.queued = TX_DESC_COUNT;
+ sc->tx.queued = 0;
for (i = 0; i < TX_DESC_COUNT; i++) {
error = bus_dmamap_create(sc->tx.buf_tag, 0,
&sc->tx.buf_map[i].map);
@@ -1513,7 +1564,6 @@
device_printf(dev, "cannot create TX buffer map\n");
return (error);
}
- awg_setup_txdesc(sc, i, 0, 0, 0);
}
/* Setup RX ring */

File Metadata

Mime Type
text/plain
Expires
Wed, Nov 4, 8:52 AM (11 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41416930
Default Alt Text
D12537.1793782331.diff (7 KB)

Event Timeline