Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/ic Compute CRC for all segments of a multi-buffer pa...
details: https://anonhg.NetBSD.org/src/rev/877773d67765
branches: trunk
changeset: 960105:877773d67765
user: mlelstv <mlelstv%NetBSD.org@localhost>
date: Mon Mar 08 13:14:44 2021 +0000
description:
Compute CRC for all segments of a multi-buffer packet.
Add interrupt mitigation for transmit and receive.
Use separate transmit lock.
Fix some error paths.
diffstat:
sys/dev/ic/bcmgenet.c | 215 +++++++++++++++++++++++++++++++++-------------
sys/dev/ic/bcmgenetreg.h | 10 +-
sys/dev/ic/bcmgenetvar.h | 3 +-
3 files changed, 166 insertions(+), 62 deletions(-)
diffs (truncated from 493 to 300 lines):
diff -r 472d0c4e745a -r 877773d67765 sys/dev/ic/bcmgenet.c
--- a/sys/dev/ic/bcmgenet.c Mon Mar 08 07:10:45 2021 +0000
+++ b/sys/dev/ic/bcmgenet.c Mon Mar 08 13:14:44 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: bcmgenet.c,v 1.7 2020/06/27 13:34:20 jmcneill Exp $ */
+/* $NetBSD: bcmgenet.c,v 1.8 2021/03/08 13:14:44 mlelstv Exp $ */
/*-
* Copyright (c) 2020 Jared McNeill <jmcneill%invisible.ca@localhost>
@@ -34,7 +34,7 @@
#include "opt_ddb.h"
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bcmgenet.c,v 1.7 2020/06/27 13:34:20 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bcmgenet.c,v 1.8 2021/03/08 13:14:44 mlelstv Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -72,20 +72,24 @@
#define CALLOUT_FLAGS 0
#endif
-#define TX_SKIP(n, o) (((n) + (o)) & (GENET_DMA_DESC_COUNT - 1))
-#define TX_NEXT(n) TX_SKIP(n, 1)
-#define RX_NEXT(n) (((n) + 1) & (GENET_DMA_DESC_COUNT - 1))
-
#define TX_MAX_SEGS 128
-#define TX_DESC_COUNT GENET_DMA_DESC_COUNT
-#define RX_DESC_COUNT GENET_DMA_DESC_COUNT
+#define TX_DESC_COUNT 256 /* GENET_DMA_DESC_COUNT */
+#define RX_DESC_COUNT 256 /* GENET_DMA_DESC_COUNT */
#define MII_BUSY_RETRY 1000
#define GENET_MAX_MDF_FILTER 17
+#define TX_SKIP(n, o) (((n) + (o)) % TX_DESC_COUNT)
+#define TX_NEXT(n) TX_SKIP(n, 1)
+#define RX_NEXT(n) (((n) + 1) % RX_DESC_COUNT)
+
#define GENET_LOCK(sc) mutex_enter(&(sc)->sc_lock)
#define GENET_UNLOCK(sc) mutex_exit(&(sc)->sc_lock)
#define GENET_ASSERT_LOCKED(sc) KASSERT(mutex_owned(&(sc)->sc_lock))
+#define GENET_TXLOCK(sc) mutex_enter(&(sc)->sc_txlock)
+#define GENET_TXUNLOCK(sc) mutex_exit(&(sc)->sc_txlock)
+#define GENET_ASSERT_TXLOCKED(sc) KASSERT(mutex_owned(&(sc)->sc_txlock))
+
#define RD4(sc, reg) \
bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
#define WR4(sc, reg, val) \
@@ -190,7 +194,6 @@
uint32_t status;
status = flags | __SHIFTIN(len, GENET_TX_DESC_STATUS_BUFLEN);
- ++sc->sc_tx.queued;
WR4(sc, GENET_TX_DESC_ADDRESS_LO(index), (uint32_t)paddr);
WR4(sc, GENET_TX_DESC_ADDRESS_HI(index), (uint32_t)(paddr >> 32));
@@ -203,49 +206,58 @@
bus_dma_segment_t *segs;
int error, nsegs, cur, i;
uint32_t flags;
+ bool nospace;
+
+ /* at least one descriptor free ? */
+ if (sc->sc_tx.queued >= TX_DESC_COUNT - 1)
+ return -1;
error = bus_dmamap_load_mbuf(sc->sc_tx.buf_tag,
sc->sc_tx.buf_map[index].map, m, BUS_DMA_WRITE | BUS_DMA_NOWAIT);
if (error == EFBIG) {
device_printf(sc->sc_dev,
"TX packet needs too many DMA segments, dropping...\n");
- m_freem(m);
+ return -2;
+ }
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "TX packet cannot be mapped, retried...\n");
return 0;
}
- if (error != 0)
- return 0;
segs = sc->sc_tx.buf_map[index].map->dm_segs;
nsegs = sc->sc_tx.buf_map[index].map->dm_nsegs;
- if (sc->sc_tx.queued >= GENET_DMA_DESC_COUNT - nsegs) {
+ nospace = sc->sc_tx.queued >= TX_DESC_COUNT - nsegs;
+ if (nospace) {
bus_dmamap_unload(sc->sc_tx.buf_tag,
sc->sc_tx.buf_map[index].map);
+ /* XXX coalesce and retry ? */
return -1;
}
+ bus_dmamap_sync(sc->sc_tx.buf_tag, sc->sc_tx.buf_map[index].map,
+ 0, sc->sc_tx.buf_map[index].map->dm_mapsize, BUS_DMASYNC_PREWRITE);
+
+ /* stored in same index as loaded map */
+ sc->sc_tx.buf_map[index].mbuf = m;
+
flags = GENET_TX_DESC_STATUS_SOP |
GENET_TX_DESC_STATUS_CRC |
GENET_TX_DESC_STATUS_QTAG;
for (cur = index, i = 0; i < nsegs; i++) {
- sc->sc_tx.buf_map[cur].mbuf = (i == 0 ? m : NULL);
if (i == nsegs - 1)
flags |= GENET_TX_DESC_STATUS_EOP;
genet_setup_txdesc(sc, cur, flags, segs[i].ds_addr,
segs[i].ds_len);
- if (i == 0) {
+ if (i == 0)
flags &= ~GENET_TX_DESC_STATUS_SOP;
- flags &= ~GENET_TX_DESC_STATUS_CRC;
- }
cur = TX_NEXT(cur);
}
- bus_dmamap_sync(sc->sc_tx.buf_tag, sc->sc_tx.buf_map[index].map,
- 0, sc->sc_tx.buf_map[index].map->dm_mapsize, BUS_DMASYNC_PREWRITE);
-
return nsegs;
}
@@ -426,6 +438,43 @@
}
static void
+genet_set_rxthresh(struct genet_softc *sc, int qid, int usecs, int count)
+{
+ int ticks;
+ uint32_t val;
+
+ /* convert to 125MHz/1024 ticks */
+ ticks = howmany(usecs * 125, 1024);
+
+ if (count < 1)
+ count = 1;
+ if (count > GENET_INTR_THRESHOLD_MASK)
+ count = GENET_INTR_THRESHOLD_MASK;
+ if (ticks < 0)
+ ticks = 0;
+ if (ticks > GENET_DMA_RING_TIMEOUT_MASK)
+ ticks = GENET_DMA_RING_TIMEOUT_MASK;
+
+ WR4(sc, GENET_RX_DMA_MBUF_DONE_THRES(qid), count);
+
+ val = RD4(sc, GENET_RX_DMA_RING_TIMEOUT(qid));
+ val &= ~GENET_DMA_RING_TIMEOUT_MASK;
+ val |= ticks;
+ WR4(sc, GENET_RX_DMA_RING_TIMEOUT(qid), val);
+}
+
+static void
+genet_set_txthresh(struct genet_softc *sc, int qid, int count)
+{
+ if (count < 1)
+ count = 1;
+ if (count > GENET_INTR_THRESHOLD_MASK)
+ count = GENET_INTR_THRESHOLD_MASK;
+
+ WR4(sc, GENET_TX_DMA_MBUF_DONE_THRES(qid), count);
+}
+
+static void
genet_init_rings(struct genet_softc *sc, int qid)
{
uint32_t val;
@@ -449,11 +498,13 @@
WR4(sc, GENET_TX_DMA_END_ADDR_LO(qid),
TX_DESC_COUNT * GENET_DMA_DESC_SIZE / 4 - 1);
WR4(sc, GENET_TX_DMA_END_ADDR_HI(qid), 0);
- WR4(sc, GENET_TX_DMA_MBUF_DONE_THRES(qid), 1);
WR4(sc, GENET_TX_DMA_FLOW_PERIOD(qid), 0);
WR4(sc, GENET_TX_DMA_WRITE_PTR_LO(qid), 0);
WR4(sc, GENET_TX_DMA_WRITE_PTR_HI(qid), 0);
+ /* interrupt after 10 packets or when ring empty */
+ genet_set_txthresh(sc, qid, 10);
+
WR4(sc, GENET_TX_DMA_RING_CFG, __BIT(qid)); /* enable */
/* Enable transmit DMA */
@@ -486,6 +537,12 @@
WR4(sc, GENET_RX_DMA_READ_PTR_LO(qid), 0);
WR4(sc, GENET_RX_DMA_READ_PTR_HI(qid), 0);
+ /*
+ * interrupt on first packet,
+ * mitigation timeout timeout 57 us (~84 minimal packets at 1Gbit/s)
+ */
+ genet_set_rxthresh(sc, qid, 57, 10);
+
WR4(sc, GENET_RX_DMA_RING_CFG, __BIT(qid)); /* enable */
/* Enable receive DMA */
@@ -504,6 +561,7 @@
const uint8_t *enaddr = CLLADDR(ifp->if_sadl);
GENET_ASSERT_LOCKED(sc);
+ GENET_ASSERT_TXLOCKED(sc);
if ((ifp->if_flags & IFF_RUNNING) != 0)
return 0;
@@ -555,7 +613,9 @@
int error;
GENET_LOCK(sc);
+ GENET_TXLOCK(sc);
error = genet_init_locked(sc);
+ GENET_TXUNLOCK(sc);
GENET_UNLOCK(sc);
return error;
@@ -627,10 +687,33 @@
DPRINTF("RX pidx=%08x total=%d\n", pidx, total);
- index = sc->sc_rx.cidx & (RX_DESC_COUNT - 1);
+ index = sc->sc_rx.cidx % RX_DESC_COUNT;
for (n = 0; n < total; n++) {
status = RD4(sc, GENET_RX_DESC_STATUS(index));
+
+ if (status & GENET_RX_DESC_STATUS_ALL_ERRS) {
+ if (status & GENET_RX_DESC_STATUS_OVRUN_ERR)
+ device_printf(sc->sc_dev, "overrun\n");
+ if (status & GENET_RX_DESC_STATUS_CRC_ERR)
+ device_printf(sc->sc_dev, "CRC error\n");
+ if (status & GENET_RX_DESC_STATUS_RX_ERR)
+ device_printf(sc->sc_dev, "receive error\n");
+ if (status & GENET_RX_DESC_STATUS_FRAME_ERR)
+ device_printf(sc->sc_dev, "frame error\n");
+ if (status & GENET_RX_DESC_STATUS_LEN_ERR)
+ device_printf(sc->sc_dev, "length error\n");
+ if_statinc(ifp, if_ierrors);
+ goto next;
+ }
+
+ if (status & GENET_RX_DESC_STATUS_OWN)
+ device_printf(sc->sc_dev, "OWN %d of %d\n",n,total);
+
len = __SHIFTOUT(status, GENET_RX_DESC_STATUS_BUFLEN);
+ if (len < ETHER_ALIGN) {
+ if_statinc(ifp, if_ierrors);
+ goto next;
+ }
m = sc->sc_rx.buf_map[index].mbuf;
@@ -638,29 +721,34 @@
if_statinc(ifp, if_ierrors);
goto next;
}
- error = genet_setup_rxbuf(sc, index, m0);
- if (error != 0) {
- if_statinc(ifp, if_ierrors);
- goto next;
- }
+ /* unload map before it gets loaded in setup_rxbuf */
bus_dmamap_sync(sc->sc_rx.buf_tag, sc->sc_rx.buf_map[index].map,
0, sc->sc_rx.buf_map[index].map->dm_mapsize,
BUS_DMASYNC_POSTREAD);
bus_dmamap_unload(sc->sc_rx.buf_tag, sc->sc_rx.buf_map[index].map);
+ sc->sc_rx.buf_map[index].mbuf = NULL;
+
+ error = genet_setup_rxbuf(sc, index, m0);
+ if (error != 0) {
+ m_freem(m0);
+ if_statinc(ifp, if_ierrors);
+
+ /* XXX mbuf is unloaded but load failed */
+ m_freem(m);
+ device_printf(sc->sc_dev,
+ "cannot load RX mbuf. panic?\n");
+ goto next;
+ }
DPRINTF("RX [#%d] index=%02x status=%08x len=%d adj_len=%d\n",
n, index, status, len, len - ETHER_ALIGN);
- if (len > ETHER_ALIGN) {
- m_adj(m, ETHER_ALIGN);
+ m_set_rcvif(m, ifp);
+ m->m_len = m->m_pkthdr.len = len;
+ m_adj(m, ETHER_ALIGN);
- m_set_rcvif(m, ifp);
- m->m_len = m->m_pkthdr.len = len - ETHER_ALIGN;
- m->m_nextpkt = NULL;
-
- if_percpuq_enqueue(ifp->if_percpuq, m);
- }
+ if_percpuq_enqueue(ifp->if_percpuq, m);
next:
index = RX_NEXT(index);
Home |
Main Index |
Thread Index |
Old Index