summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/et/if_et.c1111
-rw-r--r--sys/dev/et/if_etvar.h83
2 files changed, 579 insertions, 615 deletions
diff --git a/sys/dev/et/if_et.c b/sys/dev/et/if_et.c
index 66df867..4ea1193 100644
--- a/sys/dev/et/if_et.c
+++ b/sys/dev/et/if_et.c
@@ -99,7 +99,7 @@ static void et_init(void *);
static int et_ioctl(struct ifnet *, u_long, caddr_t);
static void et_start_locked(struct ifnet *);
static void et_start(struct ifnet *);
-static void et_watchdog(struct et_softc *);
+static int et_watchdog(struct et_softc *);
static int et_ifmedia_upd_locked(struct ifnet *);
static int et_ifmedia_upd(struct ifnet *);
static void et_ifmedia_sts(struct ifnet *, struct ifmediareq *);
@@ -114,24 +114,22 @@ static void et_disable_intrs(struct et_softc *);
static void et_rxeof(struct et_softc *);
static void et_txeof(struct et_softc *);
-static int et_dma_alloc(device_t);
-static void et_dma_free(device_t);
-static int et_dma_mem_create(device_t, bus_size_t, bus_dma_tag_t *,
- void **, bus_addr_t *, bus_dmamap_t *);
-static void et_dma_mem_destroy(bus_dma_tag_t, void *, bus_dmamap_t);
-static int et_dma_mbuf_create(device_t);
-static void et_dma_mbuf_destroy(device_t, int, const int[]);
-static void et_dma_ring_addr(void *, bus_dma_segment_t *, int, int);
-static void et_dma_buf_addr(void *, bus_dma_segment_t *, int,
- bus_size_t, int);
-static int et_init_tx_ring(struct et_softc *);
+static int et_dma_alloc(struct et_softc *);
+static void et_dma_free(struct et_softc *);
+static void et_dma_map_addr(void *, bus_dma_segment_t *, int, int);
+static int et_dma_ring_alloc(struct et_softc *, bus_size_t, bus_size_t,
+ bus_dma_tag_t *, uint8_t **, bus_dmamap_t *, bus_addr_t *,
+ const char *);
+static void et_dma_ring_free(struct et_softc *, bus_dma_tag_t *, uint8_t **,
+ bus_dmamap_t *);
+static void et_init_tx_ring(struct et_softc *);
static int et_init_rx_ring(struct et_softc *);
static void et_free_tx_ring(struct et_softc *);
static void et_free_rx_ring(struct et_softc *);
static int et_encap(struct et_softc *, struct mbuf **);
-static int et_newbuf(struct et_rxbuf_data *, int, int, int);
-static int et_newbuf_cluster(struct et_rxbuf_data *, int, int);
-static int et_newbuf_hdr(struct et_rxbuf_data *, int, int);
+static int et_newbuf_cluster(struct et_rxbuf_data *, int);
+static int et_newbuf_hdr(struct et_rxbuf_data *, int);
+static void et_rxbuf_discard(struct et_rxbuf_data *, int);
static void et_stop(struct et_softc *);
static int et_chip_init(struct et_softc *);
@@ -152,7 +150,6 @@ static void et_get_eaddr(device_t, uint8_t[]);
static void et_setmulti(struct et_softc *);
static void et_tick(void *);
static void et_setmedia(struct et_softc *);
-static void et_setup_rxdesc(struct et_rxbuf_data *, int, bus_addr_t);
static const struct et_dev {
uint16_t vid;
@@ -202,18 +199,6 @@ TUNABLE_INT("hw.et.rx_intr_npkts", &et_rx_intr_npkts);
TUNABLE_INT("hw.et.rx_intr_delay", &et_rx_intr_delay);
TUNABLE_INT("hw.et.tx_intr_nsegs", &et_tx_intr_nsegs);
-struct et_bsize {
- int bufsize;
- et_newbuf_t newbuf;
-};
-
-static const struct et_bsize et_bufsize_std[ET_RX_NRING] = {
- { .bufsize = ET_RXDMA_CTRL_RING0_128,
- .newbuf = et_newbuf_hdr },
- { .bufsize = ET_RXDMA_CTRL_RING1_2048,
- .newbuf = et_newbuf_cluster },
-};
-
static int
et_probe(device_t dev)
{
@@ -326,7 +311,7 @@ et_attach(device_t dev)
et_disable_intrs(sc);
- error = et_dma_alloc(dev);
+ error = et_dma_alloc(sc);
if (error)
goto fail;
@@ -403,7 +388,7 @@ et_detach(device_t dev)
if (sc->ifp != NULL)
if_free(sc->ifp);
- et_dma_free(dev);
+ et_dma_free(sc);
mtx_destroy(&sc->sc_mtx);
@@ -699,235 +684,250 @@ et_enable_intrs(struct et_softc *sc, uint32_t intrs)
CSR_WRITE_4(sc, ET_INTR_MASK, ~intrs);
}
+struct et_dmamap_arg {
+ bus_addr_t et_busaddr;
+};
+
+static void
+et_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ struct et_dmamap_arg *ctx;
+
+ if (error)
+ return;
+
+ KASSERT(nseg == 1, ("%s: %d segments returned!", __func__, nseg));
+
+ ctx = arg;
+ ctx->et_busaddr = segs->ds_addr;
+}
+
static int
-et_dma_alloc(device_t dev)
+et_dma_ring_alloc(struct et_softc *sc, bus_size_t alignment, bus_size_t maxsize,
+ bus_dma_tag_t *tag, uint8_t **ring, bus_dmamap_t *map, bus_addr_t *paddr,
+ const char *msg)
{
- struct et_softc *sc = device_get_softc(dev);
- struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring;
- struct et_txstatus_data *txsd = &sc->sc_tx_status;
- struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring;
- struct et_rxstatus_data *rxsd = &sc->sc_rx_status;
- int i, error;
+ struct et_dmamap_arg ctx;
+ int error;
- /*
- * Create top level DMA tag
- */
- error = bus_dma_tag_create(NULL, 1, 0,
- BUS_SPACE_MAXADDR_32BIT,
- BUS_SPACE_MAXADDR,
- NULL, NULL,
- MAXBSIZE,
- BUS_SPACE_UNRESTRICTED,
- BUS_SPACE_MAXSIZE_32BIT,
- 0, NULL, NULL, &sc->sc_dtag);
- if (error) {
- device_printf(dev, "can't create DMA tag\n");
+ error = bus_dma_tag_create(sc->sc_dtag, alignment, 0, BUS_SPACE_MAXADDR,
+ BUS_SPACE_MAXADDR, NULL, NULL, maxsize, 1, maxsize, 0, NULL, NULL,
+ tag);
+ if (error != 0) {
+ device_printf(sc->dev, "could not create %s dma tag\n", msg);
return (error);
}
-
- /*
- * Create TX ring DMA stuffs
- */
- error = et_dma_mem_create(dev, ET_TX_RING_SIZE, &tx_ring->tr_dtag,
- (void **)&tx_ring->tr_desc,
- &tx_ring->tr_paddr, &tx_ring->tr_dmap);
- if (error) {
- device_printf(dev, "can't create TX ring DMA stuffs\n");
+ /* Allocate DMA'able memory for ring. */
+ error = bus_dmamem_alloc(*tag, (void **)ring,
+ BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, map);
+ if (error != 0) {
+ device_printf(sc->dev,
+ "could not allocate DMA'able memory for %s\n", msg);
return (error);
}
-
- /*
- * Create TX status DMA stuffs
- */
- error = et_dma_mem_create(dev, sizeof(uint32_t), &txsd->txsd_dtag,
- (void **)&txsd->txsd_status,
- &txsd->txsd_paddr, &txsd->txsd_dmap);
- if (error) {
- device_printf(dev, "can't create TX status DMA stuffs\n");
+ /* Load the address of the ring. */
+ ctx.et_busaddr = 0;
+ error = bus_dmamap_load(*tag, *map, *ring, maxsize, et_dma_map_addr,
+ &ctx, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ device_printf(sc->dev,
+ "could not load DMA'able memory for %s\n", msg);
return (error);
}
+ *paddr = ctx.et_busaddr;
+ return (0);
+}
- /*
- * Create DMA stuffs for RX rings
- */
- for (i = 0; i < ET_RX_NRING; ++i) {
- static const uint32_t rx_ring_posreg[ET_RX_NRING] =
- { ET_RX_RING0_POS, ET_RX_RING1_POS };
-
- struct et_rxdesc_ring *rx_ring = &sc->sc_rx_ring[i];
+static void
+et_dma_ring_free(struct et_softc *sc, bus_dma_tag_t *tag, uint8_t **ring,
+ bus_dmamap_t *map)
+{
- error = et_dma_mem_create(dev, ET_RX_RING_SIZE,
- &rx_ring->rr_dtag,
- (void **)&rx_ring->rr_desc,
- &rx_ring->rr_paddr,
- &rx_ring->rr_dmap);
- if (error) {
- device_printf(dev, "can't create DMA stuffs for "
- "the %d RX ring\n", i);
- return (error);
- }
- rx_ring->rr_posreg = rx_ring_posreg[i];
+ if (*map != NULL)
+ bus_dmamap_unload(*tag, *map);
+ if (*map != NULL && *ring != NULL) {
+ bus_dmamem_free(*tag, *ring, *map);
+ *ring = NULL;
+ *map = NULL;
}
-
- /*
- * Create RX stat ring DMA stuffs
- */
- error = et_dma_mem_create(dev, ET_RXSTAT_RING_SIZE,
- &rxst_ring->rsr_dtag,
- (void **)&rxst_ring->rsr_stat,
- &rxst_ring->rsr_paddr, &rxst_ring->rsr_dmap);
- if (error) {
- device_printf(dev, "can't create RX stat ring DMA stuffs\n");
- return (error);
+ if (*tag) {
+ bus_dma_tag_destroy(*tag);
+ *tag = NULL;
}
+}
- /*
- * Create RX status DMA stuffs
- */
- error = et_dma_mem_create(dev, sizeof(struct et_rxstatus),
- &rxsd->rxsd_dtag,
- (void **)&rxsd->rxsd_status,
- &rxsd->rxsd_paddr, &rxsd->rxsd_dmap);
- if (error) {
- device_printf(dev, "can't create RX status DMA stuffs\n");
+static int
+et_dma_alloc(struct et_softc *sc)
+{
+ struct et_txdesc_ring *tx_ring;
+ struct et_rxdesc_ring *rx_ring;
+ struct et_rxstat_ring *rxst_ring;
+ struct et_rxstatus_data *rxsd;
+ struct et_rxbuf_data *rbd;
+ struct et_txbuf_data *tbd;
+ struct et_txstatus_data *txsd;
+ int i, error;
+
+ error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+ BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL,
+ &sc->sc_dtag);
+ if (error != 0) {
+ device_printf(sc->dev, "could not allocate parent dma tag\n");
return (error);
}
- /*
- * Create mbuf DMA stuffs
- */
- error = et_dma_mbuf_create(dev);
+ /* TX ring. */
+ tx_ring = &sc->sc_tx_ring;
+ error = et_dma_ring_alloc(sc, ET_RING_ALIGN, ET_TX_RING_SIZE,
+ &tx_ring->tr_dtag, (uint8_t **)&tx_ring->tr_desc, &tx_ring->tr_dmap,
+ &tx_ring->tr_paddr, "TX ring");
if (error)
return (error);
- return (0);
-}
+ /* TX status block. */
+ txsd = &sc->sc_tx_status;
+ error = et_dma_ring_alloc(sc, ET_STATUS_ALIGN, sizeof(uint32_t),
+ &txsd->txsd_dtag, (uint8_t **)&txsd->txsd_status, &txsd->txsd_dmap,
+ &txsd->txsd_paddr, "TX status block");
+ if (error)
+ return (error);
-static void
-et_dma_free(device_t dev)
-{
- struct et_softc *sc = device_get_softc(dev);
- struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring;
- struct et_txstatus_data *txsd = &sc->sc_tx_status;
- struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring;
- struct et_rxstatus_data *rxsd = &sc->sc_rx_status;
- int i, rx_done[ET_RX_NRING];
+ /* RX ring 0, used as to recive small sized frames. */
+ rx_ring = &sc->sc_rx_ring[0];
+ error = et_dma_ring_alloc(sc, ET_RING_ALIGN, ET_RX_RING_SIZE,
+ &rx_ring->rr_dtag, (uint8_t **)&rx_ring->rr_desc, &rx_ring->rr_dmap,
+ &rx_ring->rr_paddr, "RX ring 0");
+ rx_ring->rr_posreg = ET_RX_RING0_POS;
+ if (error)
+ return (error);
- /*
- * Destroy TX ring DMA stuffs
- */
- et_dma_mem_destroy(tx_ring->tr_dtag, tx_ring->tr_desc,
- tx_ring->tr_dmap);
+ /* RX ring 1, used as to store normal sized frames. */
+ rx_ring = &sc->sc_rx_ring[1];
+ error = et_dma_ring_alloc(sc, ET_RING_ALIGN, ET_RX_RING_SIZE,
+ &rx_ring->rr_dtag, (uint8_t **)&rx_ring->rr_desc, &rx_ring->rr_dmap,
+ &rx_ring->rr_paddr, "RX ring 1");
+ rx_ring->rr_posreg = ET_RX_RING1_POS;
+ if (error)
+ return (error);
- /*
- * Destroy TX status DMA stuffs
- */
- et_dma_mem_destroy(txsd->txsd_dtag, txsd->txsd_status,
- txsd->txsd_dmap);
+ /* RX stat ring. */
+ rxst_ring = &sc->sc_rxstat_ring;
+ error = et_dma_ring_alloc(sc, ET_RING_ALIGN, ET_RXSTAT_RING_SIZE,
+ &rxst_ring->rsr_dtag, (uint8_t **)&rxst_ring->rsr_stat,
+ &rxst_ring->rsr_dmap, &rxst_ring->rsr_paddr, "RX stat ring");
+ if (error)
+ return (error);
- /*
- * Destroy DMA stuffs for RX rings
- */
- for (i = 0; i < ET_RX_NRING; ++i) {
- struct et_rxdesc_ring *rx_ring = &sc->sc_rx_ring[i];
+ /* RX status block. */
+ rxsd = &sc->sc_rx_status;
+ error = et_dma_ring_alloc(sc, ET_STATUS_ALIGN,
+ sizeof(struct et_rxstatus), &rxsd->rxsd_dtag,
+ (uint8_t **)&rxsd->rxsd_status, &rxsd->rxsd_dmap,
+ &rxsd->rxsd_paddr, "RX status block");
+ if (error)
+ return (error);
- et_dma_mem_destroy(rx_ring->rr_dtag, rx_ring->rr_desc,
- rx_ring->rr_dmap);
+ /* Create parent DMA tag for mbufs. */
+ error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+ BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL,
+ &sc->sc_mbuf_dtag);
+ if (error != 0) {
+ device_printf(sc->dev,
+ "could not allocate parent dma tag for mbuf\n");
+ return (error);
}
- /*
- * Destroy RX stat ring DMA stuffs
- */
- et_dma_mem_destroy(rxst_ring->rsr_dtag, rxst_ring->rsr_stat,
- rxst_ring->rsr_dmap);
-
- /*
- * Destroy RX status DMA stuffs
- */
- et_dma_mem_destroy(rxsd->rxsd_dtag, rxsd->rxsd_status,
- rxsd->rxsd_dmap);
-
- /*
- * Destroy mbuf DMA stuffs
- */
- for (i = 0; i < ET_RX_NRING; ++i)
- rx_done[i] = ET_RX_NDESC;
- et_dma_mbuf_destroy(dev, ET_TX_NDESC, rx_done);
-
- /*
- * Destroy top level DMA tag
- */
- if (sc->sc_dtag != NULL)
- bus_dma_tag_destroy(sc->sc_dtag);
-}
+ /* Create DMA tag for mini RX mbufs to use RX ring 0. */
+ error = bus_dma_tag_create(sc->sc_mbuf_dtag, 1, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MHLEN, 1,
+ MHLEN, 0, NULL, NULL, &sc->sc_rx_mini_tag);
+ if (error) {
+ device_printf(sc->dev, "could not create mini RX dma tag\n");
+ return (error);
+ }
-static int
-et_dma_mbuf_create(device_t dev)
-{
- struct et_softc *sc = device_get_softc(dev);
- struct et_txbuf_data *tbd = &sc->sc_tx_data;
- int i, error, rx_done[ET_RX_NRING];
+ /* Create DMA tag for standard RX mbufs to use RX ring 1. */
+ error = bus_dma_tag_create(sc->sc_mbuf_dtag, 1, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1,
+ MCLBYTES, 0, NULL, NULL, &sc->sc_rx_tag);
+ if (error) {
+ device_printf(sc->dev, "could not create RX dma tag\n");
+ return (error);
+ }
- /*
- * Create mbuf DMA tag
- */
- error = bus_dma_tag_create(sc->sc_dtag, 1, 0,
- BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
- NULL, NULL,
- ET_JUMBO_FRAMELEN, ET_NSEG_MAX,
- BUS_SPACE_MAXSIZE_32BIT,
- BUS_DMA_ALLOCNOW, NULL, NULL, &sc->sc_mbuf_dtag);
+ /* Create DMA tag for TX mbufs. */
+ error = bus_dma_tag_create(sc->sc_mbuf_dtag, 1, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+ MCLBYTES * ET_NSEG_MAX, ET_NSEG_MAX, MCLBYTES, 0, NULL, NULL,
+ &sc->sc_tx_tag);
if (error) {
- device_printf(dev, "can't create mbuf DMA tag\n");
+ device_printf(sc->dev, "could not create TX dma tag\n");
return (error);
}
- /*
- * Create spare DMA map for RX mbufs
- */
- error = bus_dmamap_create(sc->sc_mbuf_dtag, 0, &sc->sc_mbuf_tmp_dmap);
+ /* Initialize RX ring 0. */
+ rbd = &sc->sc_rx_data[0];
+ rbd->rbd_bufsize = ET_RXDMA_CTRL_RING0_128;
+ rbd->rbd_newbuf = et_newbuf_hdr;
+ rbd->rbd_discard = et_rxbuf_discard;
+ rbd->rbd_softc = sc;
+ rbd->rbd_ring = &sc->sc_rx_ring[0];
+ /* Create DMA maps for mini RX buffers, ring 0. */
+ for (i = 0; i < ET_RX_NDESC; i++) {
+ error = bus_dmamap_create(sc->sc_rx_mini_tag, 0,
+ &rbd->rbd_buf[i].rb_dmap);
+ if (error) {
+ device_printf(sc->dev,
+ "could not create DMA map for mini RX mbufs\n");
+ return (error);
+ }
+ }
+
+ /* Create a spare DMA map for mini RX buffers, ring 0. */
+ error = bus_dmamap_create(sc->sc_rx_mini_tag, 0,
+ &sc->sc_rx_mini_sparemap);
if (error) {
- device_printf(dev, "can't create spare mbuf DMA map\n");
- bus_dma_tag_destroy(sc->sc_mbuf_dtag);
- sc->sc_mbuf_dtag = NULL;
+ device_printf(sc->dev,
+ "could not create spare DMA map for mini RX mbuf\n");
return (error);
}
- /*
- * Create DMA maps for RX mbufs
- */
- bzero(rx_done, sizeof(rx_done));
- for (i = 0; i < ET_RX_NRING; ++i) {
- struct et_rxbuf_data *rbd = &sc->sc_rx_data[i];
- int j;
-
- for (j = 0; j < ET_RX_NDESC; ++j) {
- error = bus_dmamap_create(sc->sc_mbuf_dtag, 0,
- &rbd->rbd_buf[j].rb_dmap);
- if (error) {
- device_printf(dev, "can't create %d RX mbuf "
- "for %d RX ring\n", j, i);
- rx_done[i] = j;
- et_dma_mbuf_destroy(dev, 0, rx_done);
- return (error);
- }
+ /* Initialize RX ring 1. */
+ rbd = &sc->sc_rx_data[1];
+ rbd->rbd_bufsize = ET_RXDMA_CTRL_RING1_2048;
+ rbd->rbd_newbuf = et_newbuf_cluster;
+ rbd->rbd_discard = et_rxbuf_discard;
+ rbd->rbd_softc = sc;
+ rbd->rbd_ring = &sc->sc_rx_ring[1];
+ /* Create DMA maps for standard RX buffers, ring 1. */
+ for (i = 0; i < ET_RX_NDESC; i++) {
+ error = bus_dmamap_create(sc->sc_rx_tag, 0,
+ &rbd->rbd_buf[i].rb_dmap);
+ if (error) {
+ device_printf(sc->dev,
+ "could not create DMA map for mini RX mbufs\n");
+ return (error);
}
- rx_done[i] = ET_RX_NDESC;
+ }
- rbd->rbd_softc = sc;
- rbd->rbd_ring = &sc->sc_rx_ring[i];
+ /* Create a spare DMA map for standard RX buffers, ring 1. */
+ error = bus_dmamap_create(sc->sc_rx_tag, 0, &sc->sc_rx_sparemap);
+ if (error) {
+ device_printf(sc->dev,
+ "could not create spare DMA map for RX mbuf\n");
+ return (error);
}
- /*
- * Create DMA maps for TX mbufs
- */
- for (i = 0; i < ET_TX_NDESC; ++i) {
- error = bus_dmamap_create(sc->sc_mbuf_dtag, 0,
- &tbd->tbd_buf[i].tb_dmap);
+ /* Create DMA maps for TX buffers. */
+ tbd = &sc->sc_tx_data;
+ for (i = 0; i < ET_TX_NDESC; i++) {
+ error = bus_dmamap_create(sc->sc_tx_tag, 0,
+ &tbd->tbd_buf[i].tb_dmap);
if (error) {
- device_printf(dev, "can't create %d TX mbuf "
- "DMA map\n", i);
- et_dma_mbuf_destroy(dev, i, rx_done);
+ device_printf(sc->dev,
+ "could not create DMA map for TX mbufs\n");
return (error);
}
}
@@ -936,106 +936,97 @@ et_dma_mbuf_create(device_t dev)
}
static void
-et_dma_mbuf_destroy(device_t dev, int tx_done, const int rx_done[])
+et_dma_free(struct et_softc *sc)
{
- struct et_softc *sc = device_get_softc(dev);
- struct et_txbuf_data *tbd = &sc->sc_tx_data;
+ struct et_txdesc_ring *tx_ring;
+ struct et_rxdesc_ring *rx_ring;
+ struct et_txstatus_data *txsd;
+ struct et_rxstat_ring *rxst_ring;
+ struct et_rxstatus_data *rxsd;
+ struct et_rxbuf_data *rbd;
+ struct et_txbuf_data *tbd;
int i;
- if (sc->sc_mbuf_dtag == NULL)
- return;
-
- /*
- * Destroy DMA maps for RX mbufs
- */
- for (i = 0; i < ET_RX_NRING; ++i) {
- struct et_rxbuf_data *rbd = &sc->sc_rx_data[i];
- int j;
-
- for (j = 0; j < rx_done[i]; ++j) {
- struct et_rxbuf *rb = &rbd->rbd_buf[j];
-
- KASSERT(rb->rb_mbuf == NULL,
- ("RX mbuf in %d RX ring is not freed yet\n", i));
- bus_dmamap_destroy(sc->sc_mbuf_dtag, rb->rb_dmap);
+ /* Destroy DMA maps for mini RX buffers, ring 0. */
+ rbd = &sc->sc_rx_data[0];
+ for (i = 0; i < ET_RX_NDESC; i++) {
+ if (rbd->rbd_buf[i].rb_dmap) {
+ bus_dmamap_destroy(sc->sc_rx_mini_tag,
+ rbd->rbd_buf[i].rb_dmap);
+ rbd->rbd_buf[i].rb_dmap = NULL;
}
}
-
- /*
- * Destroy DMA maps for TX mbufs
- */
- for (i = 0; i < tx_done; ++i) {
- struct et_txbuf *tb = &tbd->tbd_buf[i];
-
- KASSERT(tb->tb_mbuf == NULL, ("TX mbuf is not freed yet\n"));
- bus_dmamap_destroy(sc->sc_mbuf_dtag, tb->tb_dmap);
+ if (sc->sc_rx_mini_sparemap) {
+ bus_dmamap_destroy(sc->sc_rx_mini_tag, sc->sc_rx_mini_sparemap);
+ sc->sc_rx_mini_sparemap = NULL;
}
-
- /*
- * Destroy spare mbuf DMA map
- */
- bus_dmamap_destroy(sc->sc_mbuf_dtag, sc->sc_mbuf_tmp_dmap);
-
- /*
- * Destroy mbuf DMA tag
- */
- bus_dma_tag_destroy(sc->sc_mbuf_dtag);
- sc->sc_mbuf_dtag = NULL;
-}
-
-static int
-et_dma_mem_create(device_t dev, bus_size_t size, bus_dma_tag_t *dtag,
- void **addr, bus_addr_t *paddr, bus_dmamap_t *dmap)
-{
- struct et_softc *sc = device_get_softc(dev);
- int error;
-
- error = bus_dma_tag_create(sc->sc_dtag, ET_ALIGN, 0,
- BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
- NULL, NULL,
- size, 1, BUS_SPACE_MAXSIZE_32BIT,
- 0, NULL, NULL, dtag);
- if (error) {
- device_printf(dev, "can't create DMA tag\n");
- return (error);
+ if (sc->sc_rx_mini_tag) {
+ bus_dma_tag_destroy(sc->sc_rx_mini_tag);
+ sc->sc_rx_mini_tag = NULL;
}
- error = bus_dmamem_alloc(*dtag, addr, BUS_DMA_WAITOK | BUS_DMA_ZERO,
- dmap);
- if (error) {
- device_printf(dev, "can't allocate DMA mem\n");
- bus_dma_tag_destroy(*dtag);
- *dtag = NULL;
- return (error);
+ /* Destroy DMA maps for standard RX buffers, ring 1. */
+ rbd = &sc->sc_rx_data[1];
+ for (i = 0; i < ET_RX_NDESC; i++) {
+ if (rbd->rbd_buf[i].rb_dmap) {
+ bus_dmamap_destroy(sc->sc_rx_tag,
+ rbd->rbd_buf[i].rb_dmap);
+ rbd->rbd_buf[i].rb_dmap = NULL;
+ }
}
-
- error = bus_dmamap_load(*dtag, *dmap, *addr, size,
- et_dma_ring_addr, paddr, BUS_DMA_WAITOK);
- if (error) {
- device_printf(dev, "can't load DMA mem\n");
- bus_dmamem_free(*dtag, *addr, *dmap);
- bus_dma_tag_destroy(*dtag);
- *dtag = NULL;
- return (error);
+ if (sc->sc_rx_sparemap) {
+ bus_dmamap_destroy(sc->sc_rx_tag, sc->sc_rx_sparemap);
+ sc->sc_rx_sparemap = NULL;
+ }
+ if (sc->sc_rx_tag) {
+ bus_dma_tag_destroy(sc->sc_rx_tag);
+ sc->sc_rx_tag = NULL;
}
- return (0);
-}
-static void
-et_dma_mem_destroy(bus_dma_tag_t dtag, void *addr, bus_dmamap_t dmap)
-{
- if (dtag != NULL) {
- bus_dmamap_unload(dtag, dmap);
- bus_dmamem_free(dtag, addr, dmap);
- bus_dma_tag_destroy(dtag);
+ /* Destroy DMA maps for TX buffers. */
+ tbd = &sc->sc_tx_data;
+ for (i = 0; i < ET_TX_NDESC; i++) {
+ if (tbd->tbd_buf[i].tb_dmap) {
+ bus_dmamap_destroy(sc->sc_tx_tag,
+ tbd->tbd_buf[i].tb_dmap);
+ tbd->tbd_buf[i].tb_dmap = NULL;
+ }
+ }
+ if (sc->sc_tx_tag) {
+ bus_dma_tag_destroy(sc->sc_tx_tag);
+ sc->sc_tx_tag = NULL;
}
-}
-static void
-et_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error)
-{
- KASSERT(nseg == 1, ("too many segments\n"));
- *((bus_addr_t *)arg) = seg->ds_addr;
+ /* Destroy mini RX ring, ring 0. */
+ rx_ring = &sc->sc_rx_ring[0];
+ et_dma_ring_free(sc, &rx_ring->rr_dtag, (void *)&rx_ring->rr_desc,
+ &rx_ring->rr_dmap);
+ /* Destroy standard RX ring, ring 1. */
+ rx_ring = &sc->sc_rx_ring[1];
+ et_dma_ring_free(sc, &rx_ring->rr_dtag, (void *)&rx_ring->rr_desc,
+ &rx_ring->rr_dmap);
+ /* Destroy RX stat ring. */
+ rxst_ring = &sc->sc_rxstat_ring;
+ et_dma_ring_free(sc, &rxst_ring->rsr_dtag, (void *)&rxst_ring->rsr_stat,
+ &rxst_ring->rsr_dmap);
+ /* Destroy RX status block. */
+ rxsd = &sc->sc_rx_status;
+ et_dma_ring_free(sc, &rxst_ring->rsr_dtag, (void *)&rxst_ring->rsr_stat,
+ &rxst_ring->rsr_dmap);
+ /* Destroy TX ring. */
+ tx_ring = &sc->sc_tx_ring;
+ et_dma_ring_free(sc, &tx_ring->tr_dtag, (void *)&tx_ring->tr_desc,
+ &tx_ring->tr_dmap);
+ /* Destroy TX status block. */
+ txsd = &sc->sc_tx_status;
+ et_dma_ring_free(sc, &txsd->txsd_dtag, (void *)&txsd->txsd_status,
+ &txsd->txsd_dmap);
+
+ /* Destroy the parent tag. */
+ if (sc->sc_dtag) {
+ bus_dma_tag_destroy(sc->sc_dtag);
+ sc->sc_dtag = NULL;
+ }
}
static void
@@ -1113,30 +1104,21 @@ back:
static void
et_init_locked(struct et_softc *sc)
{
- struct ifnet *ifp = sc->ifp;
- const struct et_bsize *arr;
- int error, i;
+ struct ifnet *ifp;
+ int error;
ET_LOCK_ASSERT(sc);
+ ifp = sc->ifp;
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
return;
et_stop(sc);
- arr = et_bufsize_std;
- for (i = 0; i < ET_RX_NRING; ++i) {
- sc->sc_rx_data[i].rbd_bufsize = arr[i].bufsize;
- sc->sc_rx_data[i].rbd_newbuf = arr[i].newbuf;
- }
-
- error = et_init_tx_ring(sc);
- if (error)
- goto back;
-
+ et_init_tx_ring(sc);
error = et_init_rx_ring(sc);
if (error)
- goto back;
+ return;
error = et_chip_init(sc);
if (error)
@@ -1309,20 +1291,26 @@ et_start(struct ifnet *ifp)
ET_UNLOCK(sc);
}
-static void
+static int
et_watchdog(struct et_softc *sc)
{
+ uint32_t status;
+
ET_LOCK_ASSERT(sc);
if (sc->watchdog_timer == 0 || --sc->watchdog_timer)
- return;
+ return (0);
- if_printf(sc->ifp, "watchdog timed out\n");
+ bus_dmamap_sync(sc->sc_tx_status.txsd_dtag, sc->sc_tx_status.txsd_dmap,
+ BUS_DMASYNC_POSTREAD);
+ status = le32toh(*(sc->sc_tx_status.txsd_status));
+ if_printf(sc->ifp, "watchdog timed out (0x%08x) -- resetting\n",
+ status);
sc->ifp->if_oerrors++;
sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
et_init_locked(sc);
- et_start_locked(sc->ifp);
+ return (EJUSTRETURN);
}
static int
@@ -1350,49 +1338,59 @@ et_stop_txdma(struct et_softc *sc)
static void
et_free_tx_ring(struct et_softc *sc)
{
- struct et_txbuf_data *tbd = &sc->sc_tx_data;
- struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring;
+ struct et_txdesc_ring *tx_ring;
+ struct et_txbuf_data *tbd;
+ struct et_txbuf *tb;
int i;
+ tbd = &sc->sc_tx_data;
+ tx_ring = &sc->sc_tx_ring;
for (i = 0; i < ET_TX_NDESC; ++i) {
- struct et_txbuf *tb = &tbd->tbd_buf[i];
-
+ tb = &tbd->tbd_buf[i];
if (tb->tb_mbuf != NULL) {
+ bus_dmamap_sync(sc->sc_tx_tag, tb->tb_dmap,
+ BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(sc->sc_mbuf_dtag, tb->tb_dmap);
m_freem(tb->tb_mbuf);
tb->tb_mbuf = NULL;
}
}
-
- bzero(tx_ring->tr_desc, ET_TX_RING_SIZE);
- bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap,
- BUS_DMASYNC_PREWRITE);
}
static void
et_free_rx_ring(struct et_softc *sc)
{
- int n;
-
- for (n = 0; n < ET_RX_NRING; ++n) {
- struct et_rxbuf_data *rbd = &sc->sc_rx_data[n];
- struct et_rxdesc_ring *rx_ring = &sc->sc_rx_ring[n];
- int i;
-
- for (i = 0; i < ET_RX_NDESC; ++i) {
- struct et_rxbuf *rb = &rbd->rbd_buf[i];
+ struct et_rxbuf_data *rbd;
+ struct et_rxdesc_ring *rx_ring;
+ struct et_rxbuf *rb;
+ int i;
- if (rb->rb_mbuf != NULL) {
- bus_dmamap_unload(sc->sc_mbuf_dtag,
- rb->rb_dmap);
- m_freem(rb->rb_mbuf);
- rb->rb_mbuf = NULL;
- }
+ /* Ring 0 */
+ rx_ring = &sc->sc_rx_ring[0];
+ rbd = &sc->sc_rx_data[0];
+ for (i = 0; i < ET_RX_NDESC; ++i) {
+ rb = &rbd->rbd_buf[i];
+ if (rb->rb_mbuf != NULL) {
+ bus_dmamap_sync(sc->sc_rx_mini_tag, rx_ring->rr_dmap,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->sc_rx_mini_tag, rb->rb_dmap);
+ m_freem(rb->rb_mbuf);
+ rb->rb_mbuf = NULL;
}
+ }
- bzero(rx_ring->rr_desc, ET_RX_RING_SIZE);
- bus_dmamap_sync(rx_ring->rr_dtag, rx_ring->rr_dmap,
- BUS_DMASYNC_PREWRITE);
+ /* Ring 1 */
+ rx_ring = &sc->sc_rx_ring[1];
+ rbd = &sc->sc_rx_data[1];
+ for (i = 0; i < ET_RX_NDESC; ++i) {
+ rb = &rbd->rbd_buf[i];
+ if (rb->rb_mbuf != NULL) {
+ bus_dmamap_sync(sc->sc_rx_tag, rx_ring->rr_dmap,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->sc_rx_tag, rb->rb_dmap);
+ m_freem(rb->rb_mbuf);
+ rb->rb_mbuf = NULL;
+ }
}
}
@@ -1519,40 +1517,41 @@ et_chip_init(struct et_softc *sc)
return (0);
}
-static int
+static void
et_init_tx_ring(struct et_softc *sc)
{
- struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring;
- struct et_txstatus_data *txsd = &sc->sc_tx_status;
- struct et_txbuf_data *tbd = &sc->sc_tx_data;
+ struct et_txdesc_ring *tx_ring;
+ struct et_txbuf_data *tbd;
+ struct et_txstatus_data *txsd;
+ tx_ring = &sc->sc_tx_ring;
bzero(tx_ring->tr_desc, ET_TX_RING_SIZE);
bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap,
- BUS_DMASYNC_PREWRITE);
+ BUS_DMASYNC_PREWRITE);
+ tbd = &sc->sc_tx_data;
tbd->tbd_start_index = 0;
tbd->tbd_start_wrap = 0;
tbd->tbd_used = 0;
+ txsd = &sc->sc_tx_status;
bzero(txsd->txsd_status, sizeof(uint32_t));
bus_dmamap_sync(txsd->txsd_dtag, txsd->txsd_dmap,
- BUS_DMASYNC_PREWRITE);
- return (0);
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
}
static int
et_init_rx_ring(struct et_softc *sc)
{
- struct et_rxstatus_data *rxsd = &sc->sc_rx_status;
- struct et_rxstat_ring *rxst_ring = &sc->sc_rxstat_ring;
- int n;
+ struct et_rxstatus_data *rxsd;
+ struct et_rxstat_ring *rxst_ring;
+ struct et_rxbuf_data *rbd;
+ int i, error, n;
for (n = 0; n < ET_RX_NRING; ++n) {
- struct et_rxbuf_data *rbd = &sc->sc_rx_data[n];
- int i, error;
-
+ rbd = &sc->sc_rx_data[n];
for (i = 0; i < ET_RX_NDESC; ++i) {
- error = rbd->rbd_newbuf(rbd, i, 1);
+ error = rbd->rbd_newbuf(rbd, i);
if (error) {
if_printf(sc->ifp, "%d ring %d buf, "
"newbuf failed: %d\n", n, i, error);
@@ -1561,37 +1560,19 @@ et_init_rx_ring(struct et_softc *sc)
}
}
+ rxsd = &sc->sc_rx_status;
bzero(rxsd->rxsd_status, sizeof(struct et_rxstatus));
bus_dmamap_sync(rxsd->rxsd_dtag, rxsd->rxsd_dmap,
- BUS_DMASYNC_PREWRITE);
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ rxst_ring = &sc->sc_rxstat_ring;
bzero(rxst_ring->rsr_stat, ET_RXSTAT_RING_SIZE);
bus_dmamap_sync(rxst_ring->rsr_dtag, rxst_ring->rsr_dmap,
- BUS_DMASYNC_PREWRITE);
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
return (0);
}
-static void
-et_dma_buf_addr(void *xctx, bus_dma_segment_t *segs, int nsegs,
- bus_size_t mapsz __unused, int error)
-{
- struct et_dmamap_ctx *ctx = xctx;
- int i;
-
- if (error)
- return;
-
- if (nsegs > ctx->nsegs) {
- ctx->nsegs = 0;
- return;
- }
-
- ctx->nsegs = nsegs;
- for (i = 0; i < nsegs; ++i)
- ctx->segs[i] = segs[i];
-}
-
static int
et_init_rxdma(struct et_softc *sc)
{
@@ -1929,13 +1910,20 @@ et_enable_txrx(struct et_softc *sc, int media_upd)
static void
et_rxeof(struct et_softc *sc)
{
- struct ifnet *ifp;
struct et_rxstatus_data *rxsd;
struct et_rxstat_ring *rxst_ring;
- uint32_t rxs_stat_ring, rxst_info2;
- int rxst_wrap, rxst_index;
+ struct et_rxbuf_data *rbd;
+ struct et_rxdesc_ring *rx_ring;
+ struct et_rxstat *st;
+ struct ifnet *ifp;
+ struct mbuf *m;
+ uint32_t rxstat_pos, rxring_pos;
+ uint32_t rxst_info1, rxst_info2, rxs_stat_ring;
+ int buflen, buf_idx, npost[2], ring_idx;
+ int rxst_index, rxst_wrap;
ET_LOCK_ASSERT(sc);
+
ifp = sc->ifp;
rxsd = &sc->sc_rx_status;
rxst_ring = &sc->sc_rxstat_ring;
@@ -1944,26 +1932,24 @@ et_rxeof(struct et_softc *sc)
return;
bus_dmamap_sync(rxsd->rxsd_dtag, rxsd->rxsd_dmap,
- BUS_DMASYNC_POSTREAD);
+ BUS_DMASYNC_POSTREAD);
bus_dmamap_sync(rxst_ring->rsr_dtag, rxst_ring->rsr_dmap,
- BUS_DMASYNC_POSTREAD);
+ BUS_DMASYNC_POSTREAD);
+ npost[0] = npost[1] = 0;
rxs_stat_ring = le32toh(rxsd->rxsd_status->rxs_stat_ring);
rxst_wrap = (rxs_stat_ring & ET_RXS_STATRING_WRAP) ? 1 : 0;
rxst_index = (rxs_stat_ring & ET_RXS_STATRING_INDEX_MASK) >>
ET_RXS_STATRING_INDEX_SHIFT;
while (rxst_index != rxst_ring->rsr_index ||
- rxst_wrap != rxst_ring->rsr_wrap) {
- struct et_rxbuf_data *rbd;
- struct et_rxdesc_ring *rx_ring;
- struct et_rxstat *st;
- struct mbuf *m;
- int buflen, buf_idx, ring_idx;
- uint32_t rxstat_pos, rxring_pos;
+ rxst_wrap != rxst_ring->rsr_wrap) {
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+ break;
MPASS(rxst_ring->rsr_index < ET_RX_NSTAT);
st = &rxst_ring->rsr_stat[rxst_ring->rsr_index];
+ rxst_info1 = le32toh(st->rxst_info1);
rxst_info2 = le32toh(st->rxst_info2);
buflen = (rxst_info2 & ET_RXST_INFO2_LEN_MASK) >>
ET_RXST_INFO2_LEN_SHIFT;
@@ -1994,32 +1980,34 @@ et_rxeof(struct et_softc *sc)
rbd = &sc->sc_rx_data[ring_idx];
m = rbd->rbd_buf[buf_idx].rb_mbuf;
-
- if (rbd->rbd_newbuf(rbd, buf_idx, 0) == 0) {
- if (buflen < ETHER_CRC_LEN) {
+ if ((rxst_info1 & ET_RXST_INFO1_OK) == 0){
+ /* Discard errored frame. */
+ ifp->if_ierrors++;
+ rbd->rbd_discard(rbd, buf_idx);
+ } else if (rbd->rbd_newbuf(rbd, buf_idx) != 0) {
+ /* No available mbufs, discard it. */
+ ifp->if_iqdrops++;
+ rbd->rbd_discard(rbd, buf_idx);
+ } else {
+ buflen -= ETHER_CRC_LEN;
+ if (buflen < ETHER_HDR_LEN) {
m_freem(m);
- m = NULL;
ifp->if_ierrors++;
} else {
- m->m_pkthdr.len = m->m_len =
- buflen - ETHER_CRC_LEN;
+ m->m_pkthdr.len = m->m_len = buflen;
m->m_pkthdr.rcvif = ifp;
ifp->if_ipackets++;
ET_UNLOCK(sc);
ifp->if_input(ifp, m);
ET_LOCK(sc);
}
- } else {
- ifp->if_ierrors++;
}
- m = NULL; /* Catch invalid reference */
rx_ring = &sc->sc_rx_ring[ring_idx];
-
if (buf_idx != rx_ring->rr_index) {
- if_printf(ifp, "WARNING!! ring %d, "
- "buf_idx %d, rr_idx %d\n",
- ring_idx, buf_idx, rx_ring->rr_index);
+ if_printf(ifp,
+ "WARNING!! ring %d, buf_idx %d, rr_idx %d\n",
+ ring_idx, buf_idx, rx_ring->rr_index);
}
MPASS(rx_ring->rr_index < ET_RX_NDESC);
@@ -2032,81 +2020,66 @@ et_rxeof(struct et_softc *sc)
rxring_pos |= ET_RX_RING_POS_WRAP;
CSR_WRITE_4(sc, rx_ring->rr_posreg, rxring_pos);
}
+
+ bus_dmamap_sync(rxsd->rxsd_dtag, rxsd->rxsd_dmap,
+ BUS_DMASYNC_PREREAD);
+ bus_dmamap_sync(rxst_ring->rsr_dtag, rxst_ring->rsr_dmap,
+ BUS_DMASYNC_PREREAD);
}
static int
et_encap(struct et_softc *sc, struct mbuf **m0)
{
- struct mbuf *m = *m0;
- bus_dma_segment_t segs[ET_NSEG_MAX];
- struct et_dmamap_ctx ctx;
- struct et_txdesc_ring *tx_ring = &sc->sc_tx_ring;
- struct et_txbuf_data *tbd = &sc->sc_tx_data;
+ struct et_txdesc_ring *tx_ring;
+ struct et_txbuf_data *tbd;
struct et_txdesc *td;
+ struct mbuf *m;
+ bus_dma_segment_t segs[ET_NSEG_MAX];
bus_dmamap_t map;
- int error, maxsegs, first_idx, last_idx, i;
- uint32_t csum_flags, tx_ready_pos, last_td_ctrl2;
-
- maxsegs = ET_TX_NDESC - tbd->tbd_used;
- if (maxsegs > ET_NSEG_MAX)
- maxsegs = ET_NSEG_MAX;
- KASSERT(maxsegs >= ET_NSEG_SPARE,
- ("not enough spare TX desc (%d)\n", maxsegs));
+ uint32_t csum_flags, last_td_ctrl2, tx_ready_pos;
+ int error, i, idx, first_idx, last_idx, nsegs;
+ tx_ring = &sc->sc_tx_ring;
MPASS(tx_ring->tr_ready_index < ET_TX_NDESC);
+ tbd = &sc->sc_tx_data;
first_idx = tx_ring->tr_ready_index;
map = tbd->tbd_buf[first_idx].tb_dmap;
- ctx.nsegs = maxsegs;
- ctx.segs = segs;
- error = bus_dmamap_load_mbuf(sc->sc_mbuf_dtag, map, m,
- et_dma_buf_addr, &ctx, BUS_DMA_NOWAIT);
- if (!error && ctx.nsegs == 0) {
- bus_dmamap_unload(sc->sc_mbuf_dtag, map);
- error = EFBIG;
- }
- if (error && error != EFBIG) {
- if_printf(sc->ifp, "can't load TX mbuf, error %d\n",
- error);
- goto back;
- }
- if (error) { /* error == EFBIG */
- struct mbuf *m_new;
-
- m_new = m_defrag(m, M_DONTWAIT);
- if (m_new == NULL) {
- if_printf(sc->ifp, "can't defrag TX mbuf\n");
- error = ENOBUFS;
- goto back;
- } else {
- *m0 = m = m_new;
+ error = bus_dmamap_load_mbuf_sg(sc->sc_tx_tag, map, *m0, segs, &nsegs,
+ 0);
+ if (error == EFBIG) {
+ m = m_collapse(*m0, M_DONTWAIT, ET_NSEG_MAX);
+ if (m == NULL) {
+ m_freem(*m0);
+ *m0 = NULL;
+ return (ENOMEM);
}
-
- ctx.nsegs = maxsegs;
- ctx.segs = segs;
- error = bus_dmamap_load_mbuf(sc->sc_mbuf_dtag, map, m,
- et_dma_buf_addr, &ctx,
- BUS_DMA_NOWAIT);
- if (error || ctx.nsegs == 0) {
- if (ctx.nsegs == 0) {
- bus_dmamap_unload(sc->sc_mbuf_dtag, map);
- error = EFBIG;
- }
- if_printf(sc->ifp,
- "can't load defraged TX mbuf\n");
- goto back;
+ *m0 = m;
+ error = bus_dmamap_load_mbuf_sg(sc->sc_tx_tag, map, *m0, segs,
+ &nsegs, 0);
+ if (error != 0) {
+ m_freem(*m0);
+ *m0 = NULL;
+ return (error);
}
- }
+ } else if (error != 0)
+ return (error);
- bus_dmamap_sync(sc->sc_mbuf_dtag, map, BUS_DMASYNC_PREWRITE);
+ /* Check for descriptor overruns. */
+ if (tbd->tbd_used + nsegs > ET_TX_NDESC - 1) {
+ bus_dmamap_unload(sc->sc_tx_tag, map);
+ return (ENOBUFS);
+ }
+ bus_dmamap_sync(sc->sc_tx_tag, map, BUS_DMASYNC_PREWRITE);
last_td_ctrl2 = ET_TDCTRL2_LAST_FRAG;
- sc->sc_tx += ctx.nsegs;
+ sc->sc_tx += nsegs;
if (sc->sc_tx / sc->sc_tx_intr_nsegs != sc->sc_tx_intr) {
sc->sc_tx_intr = sc->sc_tx / sc->sc_tx_intr_nsegs;
last_td_ctrl2 |= ET_TDCTRL2_INTR;
}
+ m = *m0;
csum_flags = 0;
if ((m->m_pkthdr.csum_flags & ET_CSUM_FEATURES) != 0) {
if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0)
@@ -2117,15 +2090,14 @@ et_encap(struct et_softc *sc, struct mbuf **m0)
csum_flags |= ET_TDCTRL2_CSUM_TCP;
}
last_idx = -1;
- for (i = 0; i < ctx.nsegs; ++i) {
- int idx;
-
+ for (i = 0; i < nsegs; ++i) {
idx = (first_idx + i) % ET_TX_NDESC;
td = &tx_ring->tr_desc[idx];
td->td_addr_hi = htole32(ET_ADDR_HI(segs[i].ds_addr));
td->td_addr_lo = htole32(ET_ADDR_LO(segs[i].ds_addr));
td->td_ctrl1 = htole32(segs[i].ds_len & ET_TDCTRL1_LEN_MASK);
- if (i == ctx.nsegs - 1) { /* Last frag */
+ if (i == nsegs - 1) {
+ /* Last frag */
td->td_ctrl2 = htole32(last_td_ctrl2 | csum_flags);
last_idx = idx;
} else
@@ -2138,43 +2110,38 @@ et_encap(struct et_softc *sc, struct mbuf **m0)
}
}
td = &tx_ring->tr_desc[first_idx];
- td->td_ctrl2 |= htole32(ET_TDCTRL2_FIRST_FRAG); /* First frag */
+ /* First frag */
+ td->td_ctrl2 |= htole32(ET_TDCTRL2_FIRST_FRAG);
MPASS(last_idx >= 0);
tbd->tbd_buf[first_idx].tb_dmap = tbd->tbd_buf[last_idx].tb_dmap;
tbd->tbd_buf[last_idx].tb_dmap = map;
tbd->tbd_buf[last_idx].tb_mbuf = m;
- tbd->tbd_used += ctx.nsegs;
+ tbd->tbd_used += nsegs;
MPASS(tbd->tbd_used <= ET_TX_NDESC);
bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap,
- BUS_DMASYNC_PREWRITE);
-
+ BUS_DMASYNC_PREWRITE);
tx_ready_pos = tx_ring->tr_ready_index & ET_TX_READY_POS_INDEX_MASK;
if (tx_ring->tr_ready_wrap)
tx_ready_pos |= ET_TX_READY_POS_WRAP;
CSR_WRITE_4(sc, ET_TX_READY_POS, tx_ready_pos);
-
- error = 0;
-back:
- if (error) {
- m_freem(m);
- *m0 = NULL;
- }
- return (error);
+ return (0);
}
static void
et_txeof(struct et_softc *sc)
{
- struct ifnet *ifp;
struct et_txdesc_ring *tx_ring;
struct et_txbuf_data *tbd;
+ struct et_txbuf *tb;
+ struct ifnet *ifp;
uint32_t tx_done;
int end, wrap;
ET_LOCK_ASSERT(sc);
+
ifp = sc->ifp;
tx_ring = &sc->sc_tx_ring;
tbd = &sc->sc_tx_data;
@@ -2185,23 +2152,20 @@ et_txeof(struct et_softc *sc)
if (tbd->tbd_used == 0)
return;
+ bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap,
+ BUS_DMASYNC_POSTWRITE);
+
tx_done = CSR_READ_4(sc, ET_TX_DONE_POS);
end = tx_done & ET_TX_DONE_POS_INDEX_MASK;
wrap = (tx_done & ET_TX_DONE_POS_WRAP) ? 1 : 0;
while (tbd->tbd_start_index != end || tbd->tbd_start_wrap != wrap) {
- struct et_txbuf *tb;
-
MPASS(tbd->tbd_start_index < ET_TX_NDESC);
tb = &tbd->tbd_buf[tbd->tbd_start_index];
-
- bzero(&tx_ring->tr_desc[tbd->tbd_start_index],
- sizeof(struct et_txdesc));
- bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap,
- BUS_DMASYNC_PREWRITE);
-
if (tb->tb_mbuf != NULL) {
- bus_dmamap_unload(sc->sc_mbuf_dtag, tb->tb_dmap);
+ bus_dmamap_sync(sc->sc_tx_tag, tb->tb_dmap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_tx_tag, tb->tb_dmap);
m_freem(tb->tb_mbuf);
tb->tb_mbuf = NULL;
ifp->if_opackets++;
@@ -2218,12 +2182,9 @@ et_txeof(struct et_softc *sc)
if (tbd->tbd_used == 0)
sc->watchdog_timer = 0;
- if (tbd->tbd_used + ET_NSEG_SPARE <= ET_TX_NDESC)
+ if (tbd->tbd_used + ET_NSEG_SPARE < ET_TX_NDESC)
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
-
- et_start_locked(ifp);
}
-
static void
et_tick(void *xsc)
{
@@ -2243,95 +2204,116 @@ et_tick(void *xsc)
if (et_enable_txrx(sc, 0) == 0)
et_start_locked(ifp);
}
- et_watchdog(sc);
+ if (et_watchdog(sc) == EJUSTRETURN)
+ return;
callout_reset(&sc->sc_tick, hz, et_tick, sc);
}
static int
-et_newbuf_cluster(struct et_rxbuf_data *rbd, int buf_idx, int init)
+et_newbuf_cluster(struct et_rxbuf_data *rbd, int buf_idx)
{
- return (et_newbuf(rbd, buf_idx, init, MCLBYTES));
+ struct et_softc *sc;
+ struct et_rxdesc *desc;
+ struct et_rxbuf *rb;
+ struct mbuf *m;
+ bus_dma_segment_t segs[1];
+ bus_dmamap_t dmap;
+ int nsegs;
+
+ MPASS(buf_idx < ET_RX_NDESC);
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m == NULL)
+ return (ENOBUFS);
+ m->m_len = m->m_pkthdr.len = MCLBYTES;
+ m_adj(m, ETHER_ALIGN);
+
+ sc = rbd->rbd_softc;
+ rb = &rbd->rbd_buf[buf_idx];
+
+ if (bus_dmamap_load_mbuf_sg(sc->sc_rx_tag, sc->sc_rx_sparemap, m,
+ segs, &nsegs, 0) != 0) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
+
+ if (rb->rb_mbuf != NULL) {
+ bus_dmamap_sync(sc->sc_rx_tag, rb->rb_dmap,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->sc_rx_tag, rb->rb_dmap);
+ }
+ dmap = rb->rb_dmap;
+ rb->rb_dmap = sc->sc_rx_sparemap;
+ sc->sc_rx_sparemap = dmap;
+ bus_dmamap_sync(sc->sc_rx_tag, rb->rb_dmap, BUS_DMASYNC_PREREAD);
+
+ rb->rb_mbuf = m;
+ desc = &rbd->rbd_ring->rr_desc[buf_idx];
+ desc->rd_addr_hi = htole32(ET_ADDR_HI(segs[0].ds_addr));
+ desc->rd_addr_lo = htole32(ET_ADDR_LO(segs[0].ds_addr));
+ desc->rd_ctrl = htole32(buf_idx & ET_RDCTRL_BUFIDX_MASK);
+ bus_dmamap_sync(rbd->rbd_ring->rr_dtag, rbd->rbd_ring->rr_dmap,
+ BUS_DMASYNC_PREWRITE);
+ return (0);
}
-static int
-et_newbuf_hdr(struct et_rxbuf_data *rbd, int buf_idx, int init)
+static void
+et_rxbuf_discard(struct et_rxbuf_data *rbd, int buf_idx)
{
- return (et_newbuf(rbd, buf_idx, init, MHLEN));
+ struct et_rxdesc *desc;
+
+ desc = &rbd->rbd_ring->rr_desc[buf_idx];
+ desc->rd_ctrl = htole32(buf_idx & ET_RDCTRL_BUFIDX_MASK);
+ bus_dmamap_sync(rbd->rbd_ring->rr_dtag, rbd->rbd_ring->rr_dmap,
+ BUS_DMASYNC_PREWRITE);
}
static int
-et_newbuf(struct et_rxbuf_data *rbd, int buf_idx, int init, int len0)
+et_newbuf_hdr(struct et_rxbuf_data *rbd, int buf_idx)
{
- struct et_softc *sc = rbd->rbd_softc;
+ struct et_softc *sc;
+ struct et_rxdesc *desc;
struct et_rxbuf *rb;
struct mbuf *m;
- struct et_dmamap_ctx ctx;
- bus_dma_segment_t seg;
+ bus_dma_segment_t segs[1];
bus_dmamap_t dmap;
- int error, len;
+ int nsegs;
MPASS(buf_idx < ET_RX_NDESC);
- rb = &rbd->rbd_buf[buf_idx];
-
- m = m_getl(len0, /* init ? M_WAIT :*/ M_DONTWAIT, MT_DATA, M_PKTHDR, &len);
- if (m == NULL) {
- error = ENOBUFS;
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return (ENOBUFS);
+ m->m_len = m->m_pkthdr.len = MHLEN;
+ m_adj(m, ETHER_ALIGN);
- if (init) {
- if_printf(sc->ifp,
- "m_getl failed, size %d\n", len0);
- return (error);
- } else {
- goto back;
- }
- }
- m->m_len = m->m_pkthdr.len = len;
+ sc = rbd->rbd_softc;
+ rb = &rbd->rbd_buf[buf_idx];
- /*
- * Try load RX mbuf into temporary DMA tag
- */
- ctx.nsegs = 1;
- ctx.segs = &seg;
- error = bus_dmamap_load_mbuf(sc->sc_mbuf_dtag, sc->sc_mbuf_tmp_dmap, m,
- et_dma_buf_addr, &ctx,
- init ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT);
- if (error || ctx.nsegs == 0) {
- if (!error) {
- bus_dmamap_unload(sc->sc_mbuf_dtag,
- sc->sc_mbuf_tmp_dmap);
- error = EFBIG;
- if_printf(sc->ifp, "too many segments?!\n");
- }
+ if (bus_dmamap_load_mbuf_sg(sc->sc_rx_mini_tag, sc->sc_rx_mini_sparemap,
+ m, segs, &nsegs, 0) != 0) {
m_freem(m);
- m = NULL;
-
- if (init) {
- if_printf(sc->ifp, "can't load RX mbuf\n");
- return (error);
- } else {
- goto back;
- }
+ return (ENOBUFS);
}
+ KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
- if (!init) {
- bus_dmamap_sync(sc->sc_mbuf_dtag, rb->rb_dmap,
- BUS_DMASYNC_POSTREAD);
- bus_dmamap_unload(sc->sc_mbuf_dtag, rb->rb_dmap);
+ if (rb->rb_mbuf != NULL) {
+ bus_dmamap_sync(sc->sc_rx_mini_tag, rb->rb_dmap,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->sc_rx_mini_tag, rb->rb_dmap);
}
- rb->rb_mbuf = m;
- rb->rb_paddr = seg.ds_addr;
-
- /*
- * Swap RX buf's DMA map with the loaded temporary one
- */
dmap = rb->rb_dmap;
- rb->rb_dmap = sc->sc_mbuf_tmp_dmap;
- sc->sc_mbuf_tmp_dmap = dmap;
+ rb->rb_dmap = sc->sc_rx_mini_sparemap;
+ sc->sc_rx_mini_sparemap = dmap;
+ bus_dmamap_sync(sc->sc_rx_mini_tag, rb->rb_dmap, BUS_DMASYNC_PREREAD);
- error = 0;
-back:
- et_setup_rxdesc(rbd, buf_idx, rb->rb_paddr);
- return (error);
+ rb->rb_mbuf = m;
+ desc = &rbd->rbd_ring->rr_desc[buf_idx];
+ desc->rd_addr_hi = htole32(ET_ADDR_HI(segs[0].ds_addr));
+ desc->rd_addr_lo = htole32(ET_ADDR_LO(segs[0].ds_addr));
+ desc->rd_ctrl = htole32(buf_idx & ET_RDCTRL_BUFIDX_MASK);
+ bus_dmamap_sync(rbd->rbd_ring->rr_dtag, rbd->rbd_ring->rr_dmap,
+ BUS_DMASYNC_PREWRITE);
+ return (0);
}
/*
@@ -2441,23 +2423,6 @@ et_setmedia(struct et_softc *sc)
CSR_WRITE_4(sc, ET_MAC_CFG2, cfg2);
}
-static void
-et_setup_rxdesc(struct et_rxbuf_data *rbd, int buf_idx, bus_addr_t paddr)
-{
- struct et_rxdesc_ring *rx_ring = rbd->rbd_ring;
- struct et_rxdesc *desc;
-
- MPASS(buf_idx < ET_RX_NDESC);
- desc = &rx_ring->rr_desc[buf_idx];
-
- desc->rd_addr_hi = htole32(ET_ADDR_HI(paddr));
- desc->rd_addr_lo = htole32(ET_ADDR_LO(paddr));
- desc->rd_ctrl = htole32(buf_idx & ET_RDCTRL_BUFIDX_MASK);
-
- bus_dmamap_sync(rx_ring->rr_dtag, rx_ring->rr_dmap,
- BUS_DMASYNC_PREWRITE);
-}
-
static int
et_suspend(device_t dev)
{
diff --git a/sys/dev/et/if_etvar.h b/sys/dev/et/if_etvar.h
index cc2ebcf..6ad0e8e 100644
--- a/sys/dev/et/if_etvar.h
+++ b/sys/dev/et/if_etvar.h
@@ -38,35 +38,8 @@
#ifndef _IF_ETVAR_H
#define _IF_ETVAR_H
-/* DragonFly compatibility */
-#define EVL_ENCAPLEN ETHER_VLAN_ENCAP_LEN
-
-/*
- * Allocate the right type of mbuf for the desired total length.
- */
-static __inline struct mbuf *
-m_getl(int len, int how, int type, int flags, int *psize)
-{
- struct mbuf *m;
- int size;
-
- if (len >= MINCLSIZE) {
- m = m_getcl(how, type, flags);
- size = MCLBYTES;
- } else if (flags & M_PKTHDR) {
- m = m_gethdr(how, type);
- size = MHLEN;
- } else {
- m = m_get(how, type);
- size = MLEN;
- }
- if (psize != NULL)
- *psize = size;
- return (m);
-}
-
-
-#define ET_ALIGN 0x1000
+#define ET_RING_ALIGN 4096
+#define ET_STATUS_ALIGN 8
#define ET_NSEG_MAX 32 /* XXX no limit actually */
#define ET_NSEG_SPARE 8
@@ -84,8 +57,8 @@ m_getl(int len, int how, int type, int flags, int *psize)
#define ET_JUMBO_MTU (ET_JUMBO_FRAMELEN - ETHER_HDR_LEN - \
EVL_ENCAPLEN - ETHER_CRC_LEN)
-#define ET_FRAMELEN(mtu) (ETHER_HDR_LEN + EVL_ENCAPLEN + (mtu) + \
- ETHER_CRC_LEN)
+#define ET_FRAMELEN(mtu) (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + \
+ (mtu) + ETHER_CRC_LEN)
#define ET_JSLOTS (ET_RX_NDESC + 128)
#define ET_JLEN (ET_JUMBO_FRAMELEN + ETHER_ALIGN)
@@ -137,8 +110,36 @@ struct et_rxstat {
uint32_t rxst_info2; /* ET_RXST_INFO2_ */
};
-#define ET_RXST_INFO2_LEN_MASK 0x0000FFFF
-#define ET_RXST_INFO2_LEN_SHIFT 0
+#define ET_RXST_INFO1_HASH_PASS 0x00000001
+#define ET_RXST_INFO1_IPCSUM 0x00000002
+#define ET_RXST_INFO1_IPCSUM_OK 0x00000004
+#define ET_RXST_INFO1_TCPCSUM 0x00000008
+#define ET_RXST_INFO1_TCPCSUM_OK 0x00000010
+#define ET_RXST_INFO1_WOL 0x00000020
+#define ET_RXST_INFO1_RXMAC_ERR 0x00000040
+#define ET_RXST_INFO1_DROP 0x00000080
+#define ET_RXST_INFO1_FRAME_TRUNC 0x00000100
+#define ET_RXST_INFO1_JUMBO 0x00000200
+#define ET_RXST_INFO1_VLAN 0x00000400
+#define ET_RXST_INFO1_PREV_FRMAE_DROP 0x00010000
+#define ET_RXST_INFO1_SHORT 0x00020000
+#define ET_RXST_INFO1_BAD_CARRIER 0x00040000
+#define ET_RXST_INFO1_CODE_ERR 0x00080000
+#define ET_RXST_INFO1_CRC_ERR 0x00100000
+#define ET_RXST_INFO1_LEN_MISMATCH 0x00200000
+#define ET_RXST_INFO1_TOO_LONG 0x00400000
+#define ET_RXST_INFO1_OK 0x00800000
+#define ET_RXST_INFO1_MULTICAST 0x01000000
+#define ET_RXST_INFO1_BROADCAST 0x02000000
+#define ET_RXST_INFO1_DRIBBLE 0x04000000
+#define ET_RXST_INFO1_CTL_FRAME 0x08000000
+#define ET_RXST_INFO1_PAUSE_FRAME 0x10000000
+#define ET_RXST_INFO1_UNKWN_CTL_FRAME 0x20000000
+#define ET_RXST_INFO1_VLAN_TAG 0x40000000
+#define ET_RXST_INFO1_LONG_EVENT 0x80000000
+
+#define ET_RXST_INFO2_LEN_MASK 0x0000FFFF
+#define ET_RXST_INFO2_LEN_SHIFT 0
#define ET_RXST_INFO2_BUFIDX_MASK 0x03FF0000
#define ET_RXST_INFO2_BUFIDX_SHIFT 16
#define ET_RXST_INFO2_RINGIDX_MASK 0x0C000000
@@ -153,11 +154,6 @@ struct et_rxstatus {
#define ET_RXS_STATRING_INDEX_SHIFT 16
#define ET_RXS_STATRING_WRAP 0x10000000
-struct et_dmamap_ctx {
- int nsegs;
- bus_dma_segment_t *segs;
-};
-
struct et_txbuf {
struct mbuf *tb_mbuf;
bus_dmamap_t tb_dmap;
@@ -166,7 +162,6 @@ struct et_txbuf {
struct et_rxbuf {
struct mbuf *rb_mbuf;
bus_dmamap_t rb_dmap;
- bus_addr_t rb_paddr;
};
struct et_txstatus_data {
@@ -224,7 +219,6 @@ struct et_txbuf_data {
struct et_softc;
struct et_rxbuf_data;
-typedef int (*et_newbuf_t)(struct et_rxbuf_data *, int, int);
struct et_rxbuf_data {
struct et_rxbuf rbd_buf[ET_RX_NDESC];
@@ -233,7 +227,8 @@ struct et_rxbuf_data {
struct et_rxdesc_ring *rbd_ring;
int rbd_bufsize;
- et_newbuf_t rbd_newbuf;
+ int (*rbd_newbuf)(struct et_rxbuf_data *, int);
+ void (*rbd_discard)(struct et_rxbuf_data *, int);
};
struct et_softc {
@@ -268,7 +263,11 @@ struct et_softc {
struct et_txstatus_data sc_tx_status;
bus_dma_tag_t sc_mbuf_dtag;
- bus_dmamap_t sc_mbuf_tmp_dmap;
+ bus_dma_tag_t sc_rx_mini_tag;
+ bus_dmamap_t sc_rx_mini_sparemap;
+ bus_dma_tag_t sc_rx_tag;
+ bus_dmamap_t sc_rx_sparemap;
+ bus_dma_tag_t sc_tx_tag;
struct et_rxbuf_data sc_rx_data[ET_RX_NRING];
struct et_txbuf_data sc_tx_data;
OpenPOWER on IntegriCloud