Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F177066642
D12537.1793782331.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
7 KB
Referenced Files
None
Subscribers
None
D12537.1793782331.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D12537: if_awg tx path fixes/modifications
Attached
Detach File
Event Timeline