summaryrefslogtreecommitdiffstats
path: root/sys/dev/sis
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2010-09-01 19:33:40 +0000
committeryongari <yongari@FreeBSD.org>2010-09-01 19:33:40 +0000
commit0b65f62811c036da9558dd96e4d6cfe2b0eaf4a3 (patch)
treebe2f826e05ba54db57d123f4b9a7a4fc7c5f80ac /sys/dev/sis
parent7c4a1c6ffa87ae5de930013b66531289fbb45818 (diff)
downloadFreeBSD-src-0b65f62811c036da9558dd96e4d6cfe2b0eaf4a3.zip
FreeBSD-src-0b65f62811c036da9558dd96e4d6cfe2b0eaf4a3.tar.gz
bus_dma(9) cleanup.
o Enforce TX/RX descriptor ring alignment. NS data sheet says the controller needs 4 bytes alignment but use 16 to cover both SiS and NS controllers. I don't have SiS data sheet so I'm not sure what is alignment restriction of SiS controller but 16 would be enough because it's larger than the size of a TX/RX descriptor. Previously sis(4) ignored the alignment restriction. o Enforce RX buffer alignment, 4. Previously sis(4) ignored RX buffer alignment restriction. o Limit number of TX DMA segment to be used to 16. It seems controller has no restriction on number of DMA segments but using more than 16 looks resource waste. o Collapse long mbuf chains with m_collapse(9) instead of calling expensive m_defrag(9). o TX/RX side bus_dmamap_load_mbuf_sg(9) support and remove unnecessary callbacks. o Initial endianness support. o Prefer local alignment fixup code to m_devget(9). o Pre-allocate TX/RX mbuf DMA maps instead of creating/destroying these maps in fast TX/RX path. On non-x86 architectures, this is very expensive operation and there is no need to do that. o Add missing bus_dmamap_sync(9) in TX/RX path. o watchdog is now unarmed only when there are no pending frames on controller. Previously sis(4) blindly unarmed watchdog without checking the number of queued frames. o For efficiency, loaded DMA map is reused for error frames. o DMA map loading failure is now gracefully handled. Previously sis(4) ignored any DMA map loading errors. o Nuke unused macros which are not appropriate for endianness operation. o Stop embedding driver maintained structures into descriptor rings. Because TX/RX descriptor structures are shared between host and controller, frequent bus_dmamap_sync(9) operations are required in fast path. Embedding driver structures will increase the size of DMA map which in turn will slow down performance.
Diffstat (limited to 'sys/dev/sis')
-rw-r--r--sys/dev/sis/if_sis.c856
-rw-r--r--sys/dev/sis/if_sisreg.h61
2 files changed, 497 insertions, 420 deletions
diff --git a/sys/dev/sis/if_sis.c b/sys/dev/sis/if_sis.c
index 96ec5a0..4ad3371 100644
--- a/sys/dev/sis/if_sis.c
+++ b/sys/dev/sis/if_sis.c
@@ -64,12 +64,15 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/sockio.h>
-#include <sys/mbuf.h>
-#include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
#include <sys/module.h>
#include <sys/socket.h>
+#include <sys/sockio.h>
#include <net/if.h>
#include <net/if_arp.h>
@@ -127,13 +130,23 @@ static struct sis_type sis_devs[] = {
};
static int sis_detach(device_t);
+static __inline void sis_discard_rxbuf(struct sis_rxdesc *);
+static int sis_dma_alloc(struct sis_softc *);
+static void sis_dma_free(struct sis_softc *);
+static int sis_dma_ring_alloc(struct sis_softc *, bus_size_t, bus_size_t,
+ bus_dma_tag_t *, uint8_t **, bus_dmamap_t *, bus_addr_t *, const char *);
+static void sis_dmamap_cb(void *, bus_dma_segment_t *, int, int);
+#ifndef __NO_STRICT_ALIGNMENT
+static __inline void sis_fixup_rx(struct mbuf *);
+#endif
static void sis_ifmedia_sts(struct ifnet *, struct ifmediareq *);
static int sis_ifmedia_upd(struct ifnet *);
static void sis_init(void *);
static void sis_initl(struct sis_softc *);
static void sis_intr(void *);
static int sis_ioctl(struct ifnet *, u_long, caddr_t);
-static int sis_newbuf(struct sis_softc *, struct sis_desc *, struct mbuf *);
+static int sis_newbuf(struct sis_softc *, struct sis_rxdesc *);
+static int sis_rxeof(struct sis_softc *);
static void sis_start(struct ifnet *);
static void sis_startl(struct ifnet *);
static void sis_stop(struct sis_softc *);
@@ -164,33 +177,6 @@ static struct resource_spec sis_res_spec[] = {
#define SIO_CLR(x) \
CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) & ~x)
-static void
-sis_dma_map_desc_next(void *arg, bus_dma_segment_t *segs, int nseg, int error)
-{
- struct sis_desc *r;
-
- r = arg;
- r->sis_next = segs->ds_addr;
-}
-
-static void
-sis_dma_map_desc_ptr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
-{
- struct sis_desc *r;
-
- r = arg;
- r->sis_ptr = segs->ds_addr;
-}
-
-static void
-sis_dma_map_ring(void *arg, bus_dma_segment_t *segs, int nseg, int error)
-{
- u_int32_t *p;
-
- p = arg;
- *p = segs->ds_addr;
-}
-
/*
* Routine to reverse the bits in a word. Stolen almost
* verbatim from /usr/games/fortune.
@@ -1055,127 +1041,10 @@ sis_attach(device_t dev)
break;
}
- /*
- * Allocate the parent bus DMA tag appropriate for PCI.
- */
-#define SIS_NSEG_NEW 32
- error = bus_dma_tag_create(NULL, /* parent */
- 1, 0, /* alignment, boundary */
- BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
- BUS_SPACE_MAXADDR, /* highaddr */
- NULL, NULL, /* filter, filterarg */
- MAXBSIZE, SIS_NSEG_NEW, /* maxsize, nsegments */
- BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
- BUS_DMA_ALLOCNOW, /* flags */
- NULL, NULL, /* lockfunc, lockarg */
- &sc->sis_parent_tag);
- if (error)
- goto fail;
-
- /*
- * Now allocate a tag for the DMA descriptor lists and a chunk
- * of DMA-able memory based on the tag. Also obtain the physical
- * addresses of the RX and TX ring, which we'll need later.
- * All of our lists are allocated as a contiguous block
- * of memory.
- */
- error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */
- 1, 0, /* alignment, boundary */
- BUS_SPACE_MAXADDR, /* lowaddr */
- BUS_SPACE_MAXADDR, /* highaddr */
- NULL, NULL, /* filter, filterarg */
- SIS_RX_LIST_SZ, 1, /* maxsize,nsegments */
- BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
- 0, /* flags */
- busdma_lock_mutex, /* lockfunc */
- &Giant, /* lockarg */
- &sc->sis_rx_tag);
- if (error)
- goto fail;
-
- error = bus_dmamem_alloc(sc->sis_rx_tag,
- (void **)&sc->sis_rx_list, BUS_DMA_NOWAIT | BUS_DMA_ZERO,
- &sc->sis_rx_dmamap);
-
- if (error) {
- device_printf(dev, "no memory for rx list buffers!\n");
- bus_dma_tag_destroy(sc->sis_rx_tag);
- sc->sis_rx_tag = NULL;
- goto fail;
- }
-
- error = bus_dmamap_load(sc->sis_rx_tag,
- sc->sis_rx_dmamap, &(sc->sis_rx_list[0]),
- sizeof(struct sis_desc), sis_dma_map_ring,
- &sc->sis_rx_paddr, 0);
-
- if (error) {
- device_printf(dev, "cannot get address of the rx ring!\n");
- bus_dmamem_free(sc->sis_rx_tag,
- sc->sis_rx_list, sc->sis_rx_dmamap);
- bus_dma_tag_destroy(sc->sis_rx_tag);
- sc->sis_rx_tag = NULL;
- goto fail;
- }
-
- error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */
- 1, 0, /* alignment, boundary */
- BUS_SPACE_MAXADDR, /* lowaddr */
- BUS_SPACE_MAXADDR, /* highaddr */
- NULL, NULL, /* filter, filterarg */
- SIS_TX_LIST_SZ, 1, /* maxsize,nsegments */
- BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
- 0, /* flags */
- busdma_lock_mutex, /* lockfunc */
- &Giant, /* lockarg */
- &sc->sis_tx_tag);
- if (error)
- goto fail;
-
- error = bus_dmamem_alloc(sc->sis_tx_tag,
- (void **)&sc->sis_tx_list, BUS_DMA_NOWAIT | BUS_DMA_ZERO,
- &sc->sis_tx_dmamap);
-
- if (error) {
- device_printf(dev, "no memory for tx list buffers!\n");
- bus_dma_tag_destroy(sc->sis_tx_tag);
- sc->sis_tx_tag = NULL;
- goto fail;
- }
-
- error = bus_dmamap_load(sc->sis_tx_tag,
- sc->sis_tx_dmamap, &(sc->sis_tx_list[0]),
- sizeof(struct sis_desc), sis_dma_map_ring,
- &sc->sis_tx_paddr, 0);
-
- if (error) {
- device_printf(dev, "cannot get address of the tx ring!\n");
- bus_dmamem_free(sc->sis_tx_tag,
- sc->sis_tx_list, sc->sis_tx_dmamap);
- bus_dma_tag_destroy(sc->sis_tx_tag);
- sc->sis_tx_tag = NULL;
- goto fail;
- }
-
- error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */
- 1, 0, /* alignment, boundary */
- BUS_SPACE_MAXADDR, /* lowaddr */
- BUS_SPACE_MAXADDR, /* highaddr */
- NULL, NULL, /* filter, filterarg */
- MCLBYTES, 1, /* maxsize,nsegments */
- BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
- 0, /* flags */
- busdma_lock_mutex, /* lockfunc */
- &Giant, /* lockarg */
- &sc->sis_tag);
- if (error)
+ /* Allocate DMA'able memory. */
+ if ((error = sis_dma_alloc(sc)) != 0)
goto fail;
- /*
- * Obtain the physical addresses of the RX and TX
- * rings which we'll need later in the init routine.
- */
-
ifp = sc->sis_ifp = if_alloc(IFT_ETHER);
if (ifp == NULL) {
device_printf(dev, "can not if_alloc()\n");
@@ -1277,30 +1146,206 @@ sis_detach(device_t dev)
if (ifp)
if_free(ifp);
- if (sc->sis_rx_tag) {
- bus_dmamap_unload(sc->sis_rx_tag,
- sc->sis_rx_dmamap);
- bus_dmamem_free(sc->sis_rx_tag,
- sc->sis_rx_list, sc->sis_rx_dmamap);
- bus_dma_tag_destroy(sc->sis_rx_tag);
+ sis_dma_free(sc);
+
+ mtx_destroy(&sc->sis_mtx);
+
+ return (0);
+}
+
+struct sis_dmamap_arg {
+ bus_addr_t sis_busaddr;
+};
+
+static void
+sis_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ struct sis_dmamap_arg *ctx;
+
+ if (error != 0)
+ return;
+
+ KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
+
+ ctx = (struct sis_dmamap_arg *)arg;
+ ctx->sis_busaddr = segs[0].ds_addr;
+}
+
+static int
+sis_dma_ring_alloc(struct sis_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 sis_dmamap_arg ctx;
+ int error;
+
+ error = bus_dma_tag_create(sc->sis_parent_tag, alignment, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, maxsize, 1,
+ maxsize, 0, NULL, NULL, tag);
+ if (error != 0) {
+ device_printf(sc->sis_dev,
+ "could not create %s dma tag\n", msg);
+ return (ENOMEM);
}
- if (sc->sis_tx_tag) {
- bus_dmamap_unload(sc->sis_tx_tag,
- sc->sis_tx_dmamap);
- bus_dmamem_free(sc->sis_tx_tag,
- sc->sis_tx_list, sc->sis_tx_dmamap);
- bus_dma_tag_destroy(sc->sis_tx_tag);
+ /* 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->sis_dev,
+ "could not allocate DMA'able memory for %s\n", msg);
+ return (ENOMEM);
+ }
+ /* Load the address of the ring. */
+ ctx.sis_busaddr = 0;
+ error = bus_dmamap_load(*tag, *map, *ring, maxsize, sis_dmamap_cb,
+ &ctx, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ device_printf(sc->sis_dev,
+ "could not load DMA'able memory for %s\n", msg);
+ return (ENOMEM);
}
- if (sc->sis_parent_tag)
- bus_dma_tag_destroy(sc->sis_parent_tag);
- if (sc->sis_tag)
- bus_dma_tag_destroy(sc->sis_tag);
+ *paddr = ctx.sis_busaddr;
+ return (0);
+}
- mtx_destroy(&sc->sis_mtx);
+static int
+sis_dma_alloc(struct sis_softc *sc)
+{
+ struct sis_rxdesc *rxd;
+ struct sis_txdesc *txd;
+ int error, i;
+
+ /* Allocate the parent bus DMA tag appropriate for PCI. */
+ error = bus_dma_tag_create(bus_get_dma_tag(sc->sis_dev),
+ 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
+ NULL, BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT,
+ 0, NULL, NULL, &sc->sis_parent_tag);
+ if (error != 0) {
+ device_printf(sc->sis_dev,
+ "could not allocate parent dma tag\n");
+ return (ENOMEM);
+ }
+
+ /* Create RX ring. */
+ error = sis_dma_ring_alloc(sc, SIS_DESC_ALIGN, SIS_RX_LIST_SZ,
+ &sc->sis_rx_list_tag, (uint8_t **)&sc->sis_rx_list,
+ &sc->sis_rx_list_map, &sc->sis_rx_paddr, "RX ring");
+ if (error)
+ return (error);
+
+ /* Create TX ring. */
+ error = sis_dma_ring_alloc(sc, SIS_DESC_ALIGN, SIS_TX_LIST_SZ,
+ &sc->sis_tx_list_tag, (uint8_t **)&sc->sis_tx_list,
+ &sc->sis_tx_list_map, &sc->sis_tx_paddr, "TX ring");
+ if (error)
+ return (error);
+
+ /* Create tag for RX mbufs. */
+ error = bus_dma_tag_create(sc->sis_parent_tag, SIS_RX_BUF_ALIGN, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1,
+ MCLBYTES, 0, NULL, NULL, &sc->sis_rx_tag);
+ if (error) {
+ device_printf(sc->sis_dev, "could not allocate RX dma tag\n");
+ return (error);
+ }
+
+ /* Create tag for TX mbufs. */
+ error = bus_dma_tag_create(sc->sis_parent_tag, 1, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+ MCLBYTES * SIS_MAXTXSEGS, SIS_MAXTXSEGS, MCLBYTES, 0, NULL, NULL,
+ &sc->sis_tx_tag);
+ if (error) {
+ device_printf(sc->sis_dev, "could not allocate TX dma tag\n");
+ return (error);
+ }
+
+ /* Create DMA maps for RX buffers. */
+ error = bus_dmamap_create(sc->sis_rx_tag, 0, &sc->sis_rx_sparemap);
+ if (error) {
+ device_printf(sc->sis_dev,
+ "can't create spare DMA map for RX\n");
+ return (error);
+ }
+ for (i = 0; i < SIS_RX_LIST_CNT; i++) {
+ rxd = &sc->sis_rxdesc[i];
+ rxd->rx_m = NULL;
+ error = bus_dmamap_create(sc->sis_rx_tag, 0, &rxd->rx_dmamap);
+ if (error) {
+ device_printf(sc->sis_dev,
+ "can't create DMA map for RX\n");
+ return (error);
+ }
+ }
+
+ /* Create DMA maps for TX buffers. */
+ for (i = 0; i < SIS_TX_LIST_CNT; i++) {
+ txd = &sc->sis_txdesc[i];
+ txd->tx_m = NULL;
+ error = bus_dmamap_create(sc->sis_tx_tag, 0, &txd->tx_dmamap);
+ if (error) {
+ device_printf(sc->sis_dev,
+ "can't create DMA map for TX\n");
+ return (error);
+ }
+ }
return (0);
}
+static void
+sis_dma_free(struct sis_softc *sc)
+{
+ struct sis_rxdesc *rxd;
+ struct sis_txdesc *txd;
+ int i;
+
+ /* Destroy DMA maps for RX buffers. */
+ for (i = 0; i < SIS_RX_LIST_CNT; i++) {
+ rxd = &sc->sis_rxdesc[i];
+ if (rxd->rx_dmamap)
+ bus_dmamap_destroy(sc->sis_rx_tag, rxd->rx_dmamap);
+ }
+ if (sc->sis_rx_sparemap)
+ bus_dmamap_destroy(sc->sis_rx_tag, sc->sis_rx_sparemap);
+
+ /* Destroy DMA maps for TX buffers. */
+ for (i = 0; i < SIS_TX_LIST_CNT; i++) {
+ txd = &sc->sis_txdesc[i];
+ if (txd->tx_dmamap)
+ bus_dmamap_destroy(sc->sis_tx_tag, txd->tx_dmamap);
+ }
+
+ if (sc->sis_rx_tag)
+ bus_dma_tag_destroy(sc->sis_rx_tag);
+ if (sc->sis_tx_tag)
+ bus_dma_tag_destroy(sc->sis_tx_tag);
+
+ /* Destroy RX ring. */
+ if (sc->sis_rx_list_map)
+ bus_dmamap_unload(sc->sis_rx_list_tag, sc->sis_rx_list_map);
+ if (sc->sis_rx_list_map && sc->sis_rx_list)
+ bus_dmamem_free(sc->sis_rx_list_tag, sc->sis_rx_list,
+ sc->sis_rx_list_map);
+
+ if (sc->sis_rx_list_tag)
+ bus_dma_tag_destroy(sc->sis_rx_list_tag);
+
+ /* Destroy TX ring. */
+ if (sc->sis_tx_list_map)
+ bus_dmamap_unload(sc->sis_tx_list_tag, sc->sis_tx_list_map);
+
+ if (sc->sis_tx_list_map && sc->sis_tx_list)
+ bus_dmamem_free(sc->sis_tx_list_tag, sc->sis_tx_list,
+ sc->sis_tx_list_map);
+
+ if (sc->sis_tx_list_tag)
+ bus_dma_tag_destroy(sc->sis_tx_list_tag);
+
+ /* Destroy the parent tag. */
+ if (sc->sis_parent_tag)
+ bus_dma_tag_destroy(sc->sis_parent_tag);
+}
+
/*
* Initialize the TX and RX descriptors and allocate mbufs for them. Note that
* we arrange the descriptors in a closed ring, so that the last descriptor
@@ -1309,48 +1354,41 @@ sis_detach(device_t dev)
static int
sis_ring_init(struct sis_softc *sc)
{
- int i, error;
- struct sis_desc *dp;
-
- dp = &sc->sis_tx_list[0];
- for (i = 0; i < SIS_TX_LIST_CNT; i++, dp++) {
- if (i == (SIS_TX_LIST_CNT - 1))
- dp->sis_nextdesc = &sc->sis_tx_list[0];
+ struct sis_rxdesc *rxd;
+ struct sis_txdesc *txd;
+ bus_addr_t next;
+ int error, i;
+
+ bzero(&sc->sis_tx_list[0], SIS_TX_LIST_SZ);
+ for (i = 0; i < SIS_TX_LIST_CNT; i++) {
+ txd = &sc->sis_txdesc[i];
+ txd->tx_m = NULL;
+ if (i == SIS_TX_LIST_CNT - 1)
+ next = SIS_TX_RING_ADDR(sc, 0);
else
- dp->sis_nextdesc = dp + 1;
- bus_dmamap_load(sc->sis_tx_tag,
- sc->sis_tx_dmamap,
- dp->sis_nextdesc, sizeof(struct sis_desc),
- sis_dma_map_desc_next, dp, 0);
- dp->sis_mbuf = NULL;
- dp->sis_ptr = 0;
- dp->sis_ctl = 0;
+ next = SIS_TX_RING_ADDR(sc, i + 1);
+ sc->sis_tx_list[i].sis_next = htole32(SIS_ADDR_LO(next));
}
-
sc->sis_tx_prod = sc->sis_tx_cons = sc->sis_tx_cnt = 0;
-
- bus_dmamap_sync(sc->sis_tx_tag,
- sc->sis_tx_dmamap, BUS_DMASYNC_PREWRITE);
-
- dp = &sc->sis_rx_list[0];
- for (i = 0; i < SIS_RX_LIST_CNT; i++, dp++) {
- error = sis_newbuf(sc, dp, NULL);
+ bus_dmamap_sync(sc->sis_tx_list_tag, sc->sis_tx_list_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ sc->sis_rx_cons = 0;
+ bzero(&sc->sis_rx_list[0], SIS_RX_LIST_SZ);
+ for (i = 0; i < SIS_RX_LIST_CNT; i++) {
+ rxd = &sc->sis_rxdesc[i];
+ rxd->rx_desc = &sc->sis_rx_list[i];
+ if (i == SIS_RX_LIST_CNT - 1)
+ next = SIS_RX_RING_ADDR(sc, 0);
+ else
+ next = SIS_RX_RING_ADDR(sc, i + 1);
+ rxd->rx_desc->sis_next = htole32(SIS_ADDR_LO(next));
+ error = sis_newbuf(sc, rxd);
if (error)
return (error);
- if (i == (SIS_RX_LIST_CNT - 1))
- dp->sis_nextdesc = &sc->sis_rx_list[0];
- else
- dp->sis_nextdesc = dp + 1;
- bus_dmamap_load(sc->sis_rx_tag,
- sc->sis_rx_dmamap,
- dp->sis_nextdesc, sizeof(struct sis_desc),
- sis_dma_map_desc_next, dp, 0);
- }
-
- bus_dmamap_sync(sc->sis_rx_tag,
- sc->sis_rx_dmamap, BUS_DMASYNC_PREWRITE);
-
- sc->sis_rx_pdsc = &sc->sis_rx_list[0];
+ }
+ bus_dmamap_sync(sc->sis_rx_list_tag, sc->sis_rx_list_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
return (0);
}
@@ -1359,31 +1397,67 @@ sis_ring_init(struct sis_softc *sc)
* Initialize an RX descriptor and attach an MBUF cluster.
*/
static int
-sis_newbuf(struct sis_softc *sc, struct sis_desc *c, struct mbuf *m)
+sis_newbuf(struct sis_softc *sc, struct sis_rxdesc *rxd)
{
+ struct mbuf *m;
+ bus_dma_segment_t segs[1];
+ bus_dmamap_t map;
+ int nsegs;
- if (c == NULL)
- return (EINVAL);
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m == NULL)
+ return (ENOBUFS);
+ m->m_len = m->m_pkthdr.len = SIS_RXLEN;
+#ifndef __NO_STRICT_ALIGNMENT
+ m_adj(m, SIS_RX_BUF_ALIGN);
+#endif
- if (m == NULL) {
- m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
- if (m == NULL)
- return (ENOBUFS);
- } else
- m->m_data = m->m_ext.ext_buf;
+ if (bus_dmamap_load_mbuf_sg(sc->sis_rx_tag, sc->sis_rx_sparemap, m,
+ segs, &nsegs, 0) != 0) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
- c->sis_mbuf = m;
- c->sis_ctl = SIS_RXLEN;
+ if (rxd->rx_m != NULL) {
+ bus_dmamap_sync(sc->sis_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->sis_rx_tag, rxd->rx_dmamap);
+ }
+ map = rxd->rx_dmamap;
+ rxd->rx_dmamap = sc->sis_rx_sparemap;
+ sc->sis_rx_sparemap = map;
+ bus_dmamap_sync(sc->sis_rx_tag, rxd->rx_dmamap, BUS_DMASYNC_PREREAD);
+ rxd->rx_m = m;
+ rxd->rx_desc->sis_cmdsts = htole32(SIS_RXLEN);
+ rxd->rx_desc->sis_ptr = htole32(SIS_ADDR_LO(segs[0].ds_addr));
+ return (0);
+}
- bus_dmamap_create(sc->sis_tag, 0, &c->sis_map);
- bus_dmamap_load(sc->sis_tag, c->sis_map,
- mtod(m, void *), MCLBYTES,
- sis_dma_map_desc_ptr, c, 0);
- bus_dmamap_sync(sc->sis_tag, c->sis_map, BUS_DMASYNC_PREREAD);
+static __inline void
+sis_discard_rxbuf(struct sis_rxdesc *rxd)
+{
- return (0);
+ rxd->rx_desc->sis_cmdsts = htole32(SIS_RXLEN);
}
+#ifndef __NO_STRICT_ALIGNMENT
+static __inline void
+sis_fixup_rx(struct mbuf *m)
+{
+ uint16_t *src, *dst;
+ int i;
+
+ src = mtod(m, uint16_t *);
+ dst = src - (SIS_RX_BUF_ALIGN - ETHER_ALIGN) / sizeof(*src);
+
+ for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++)
+ *dst++ = *src++;
+
+ m->m_data -= SIS_RX_BUF_ALIGN - ETHER_ALIGN;
+}
+#endif
+
/*
* A frame has been uploaded: pass the resulting mbuf chain up to
* the higher level protocols.
@@ -1391,19 +1465,23 @@ sis_newbuf(struct sis_softc *sc, struct sis_desc *c, struct mbuf *m)
static int
sis_rxeof(struct sis_softc *sc)
{
- struct mbuf *m, *m0;
+ struct mbuf *m;
struct ifnet *ifp;
+ struct sis_rxdesc *rxd;
struct sis_desc *cur_rx;
- int total_len = 0, rx_npkts = 0;
- u_int32_t rxstat;
+ int prog, rx_cons, rx_npkts = 0, total_len;
+ uint32_t rxstat;
SIS_LOCK_ASSERT(sc);
- ifp = sc->sis_ifp;
+ bus_dmamap_sync(sc->sis_rx_list_tag, sc->sis_rx_list_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
- for (cur_rx = sc->sis_rx_pdsc; SIS_OWNDESC(cur_rx);
- cur_rx = cur_rx->sis_nextdesc) {
+ rx_cons = sc->sis_rx_cons;
+ ifp = sc->sis_ifp;
+ for (prog = 0; (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
+ SIS_INC(rx_cons, SIS_RX_LIST_CNT), prog++) {
#ifdef DEVICE_POLLING
if (ifp->if_capenable & IFCAP_POLLING) {
if (sc->rxcycles <= 0)
@@ -1411,21 +1489,13 @@ sis_rxeof(struct sis_softc *sc)
sc->rxcycles--;
}
#endif
- rxstat = cur_rx->sis_rxstat;
- bus_dmamap_sync(sc->sis_tag,
- cur_rx->sis_map, BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->sis_tag, cur_rx->sis_map);
- bus_dmamap_destroy(sc->sis_tag, cur_rx->sis_map);
- m = cur_rx->sis_mbuf;
- cur_rx->sis_mbuf = NULL;
- total_len = SIS_RXBYTES(cur_rx);
+ cur_rx = &sc->sis_rx_list[rx_cons];
+ rxstat = le32toh(cur_rx->sis_cmdsts);
+ if ((rxstat & SIS_CMDSTS_OWN) == 0)
+ break;
+ rxd = &sc->sis_rxdesc[rx_cons];
- /*
- * If an error occurs, update stats, clear the
- * status word and leave the mbuf cluster in place:
- * it should simply get re-used next time this descriptor
- * comes up in the ring.
- */
+ total_len = (rxstat & SIS_CMDSTS_BUFLEN) - ETHER_CRC_LEN;
if ((ifp->if_capenable & IFCAP_VLAN_MTU) != 0 &&
total_len <= (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN -
ETHER_CRC_LEN))
@@ -1434,36 +1504,29 @@ sis_rxeof(struct sis_softc *sc)
ifp->if_ierrors++;
if (rxstat & SIS_RXSTAT_COLL)
ifp->if_collisions++;
- sis_newbuf(sc, cur_rx, m);
+ sis_discard_rxbuf(rxd);
+ continue;
+ }
+
+ /* Add a new receive buffer to the ring. */
+ m = rxd->rx_m;
+ if (sis_newbuf(sc, rxd) != 0) {
+ ifp->if_iqdrops++;
+ sis_discard_rxbuf(rxd);
continue;
}
/* No errors; receive the packet. */
-#ifdef __NO_STRICT_ALIGNMENT
+ m->m_pkthdr.len = m->m_len = total_len;
+#ifndef __NO_STRICT_ALIGNMENT
/*
* On architectures without alignment problems we try to
* allocate a new buffer for the receive ring, and pass up
* the one where the packet is already, saving the expensive
- * copy done in m_devget().
- * If we are on an architecture with alignment problems, or
- * if the allocation fails, then use m_devget and leave the
- * existing buffer in the receive ring.
+ * copy operation.
*/
- if (sis_newbuf(sc, cur_rx, NULL) == 0)
- m->m_pkthdr.len = m->m_len = total_len;
- else
+ sis_fixup_rx(m);
#endif
- {
- m0 = m_devget(mtod(m, char *), total_len,
- ETHER_ALIGN, ifp, NULL);
- sis_newbuf(sc, cur_rx, m);
- if (m0 == NULL) {
- ifp->if_ierrors++;
- continue;
- }
- m = m0;
- }
-
ifp->if_ipackets++;
m->m_pkthdr.rcvif = ifp;
@@ -1473,7 +1536,12 @@ sis_rxeof(struct sis_softc *sc)
rx_npkts++;
}
- sc->sis_rx_pdsc = cur_rx;
+ if (prog > 0) {
+ sc->sis_rx_cons = rx_cons;
+ bus_dmamap_sync(sc->sis_rx_list_tag, sc->sis_rx_list_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ }
+
return (rx_npkts);
}
@@ -1486,52 +1554,54 @@ static void
sis_txeof(struct sis_softc *sc)
{
struct ifnet *ifp;
- u_int32_t idx;
+ struct sis_desc *cur_tx;
+ struct sis_txdesc *txd;
+ uint32_t cons, txstat;
SIS_LOCK_ASSERT(sc);
+
+ cons = sc->sis_tx_cons;
+ if (cons == sc->sis_tx_prod)
+ return;
+
ifp = sc->sis_ifp;
+ bus_dmamap_sync(sc->sis_tx_list_tag, sc->sis_tx_list_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
/*
* Go through our tx list and free mbufs for those
* frames that have been transmitted.
*/
- for (idx = sc->sis_tx_cons; sc->sis_tx_cnt > 0;
- sc->sis_tx_cnt--, SIS_INC(idx, SIS_TX_LIST_CNT) ) {
- struct sis_desc *cur_tx = &sc->sis_tx_list[idx];
-
- if (SIS_OWNDESC(cur_tx))
+ for (; cons != sc->sis_tx_prod; SIS_INC(cons, SIS_TX_LIST_CNT)) {
+ cur_tx = &sc->sis_tx_list[cons];
+ txstat = le32toh(cur_tx->sis_cmdsts);
+ if ((txstat & SIS_CMDSTS_OWN) != 0)
break;
-
- if (cur_tx->sis_ctl & SIS_CMDSTS_MORE)
- continue;
-
- if (!(cur_tx->sis_ctl & SIS_CMDSTS_PKT_OK)) {
- ifp->if_oerrors++;
- if (cur_tx->sis_txstat & SIS_TXSTAT_EXCESSCOLLS)
- ifp->if_collisions++;
- if (cur_tx->sis_txstat & SIS_TXSTAT_OUTOFWINCOLL)
- ifp->if_collisions++;
- }
-
- ifp->if_collisions +=
- (cur_tx->sis_txstat & SIS_TXSTAT_COLLCNT) >> 16;
-
- ifp->if_opackets++;
- if (cur_tx->sis_mbuf != NULL) {
- m_freem(cur_tx->sis_mbuf);
- cur_tx->sis_mbuf = NULL;
- bus_dmamap_unload(sc->sis_tag, cur_tx->sis_map);
- bus_dmamap_destroy(sc->sis_tag, cur_tx->sis_map);
+ txd = &sc->sis_txdesc[cons];
+ if (txd->tx_m != NULL) {
+ bus_dmamap_sync(sc->sis_tx_tag, txd->tx_dmamap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sis_tx_tag, txd->tx_dmamap);
+ m_freem(txd->tx_m);
+ txd->tx_m = NULL;
+ if ((txstat & SIS_CMDSTS_PKT_OK) != 0) {
+ ifp->if_opackets++;
+ ifp->if_collisions +=
+ (txstat & SIS_TXSTAT_COLLCNT) >> 16;
+ } else {
+ ifp->if_oerrors++;
+ if (txstat & SIS_TXSTAT_EXCESSCOLLS)
+ ifp->if_collisions++;
+ if (txstat & SIS_TXSTAT_OUTOFWINCOLL)
+ ifp->if_collisions++;
+ }
}
- }
-
- if (idx != sc->sis_tx_cons) {
- /* we freed up some buffers */
- sc->sis_tx_cons = idx;
+ sc->sis_tx_cnt--;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
}
-
- sc->sis_watchdog_timer = (sc->sis_tx_cnt == 0) ? 0 : 5;
+ sc->sis_tx_cons = cons;
+ if (sc->sis_tx_cnt == 0)
+ sc->sis_watchdog_timer = 0;
}
static void
@@ -1680,83 +1750,80 @@ sis_intr(void *arg)
* pointers to the fragment pointers.
*/
static int
-sis_encap(struct sis_softc *sc, struct mbuf **m_head, uint32_t *txidx)
+sis_encap(struct sis_softc *sc, struct mbuf **m_head)
{
- struct sis_desc *f = NULL;
struct mbuf *m;
- int frag, cur, cnt = 0, chainlen = 0;
+ struct sis_txdesc *txd;
+ struct sis_desc *f;
+ bus_dma_segment_t segs[SIS_MAXTXSEGS];
+ bus_dmamap_t map;
+ int error, i, frag, nsegs, prod;
+
+ prod = sc->sis_tx_prod;
+ txd = &sc->sis_txdesc[prod];
+ error = bus_dmamap_load_mbuf_sg(sc->sis_tx_tag, txd->tx_dmamap,
+ *m_head, segs, &nsegs, 0);
+ if (error == EFBIG) {
+ m = m_collapse(*m_head, M_DONTWAIT, SIS_MAXTXSEGS);
+ if (m == NULL) {
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (ENOBUFS);
+ }
+ *m_head = m;
+ error = bus_dmamap_load_mbuf_sg(sc->sis_tx_tag, txd->tx_dmamap,
+ *m_head, segs, &nsegs, 0);
+ if (error != 0) {
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (error);
+ }
+ } else if (error != 0)
+ return (error);
- /*
- * If there's no way we can send any packets, return now.
- */
- if (SIS_TX_LIST_CNT - sc->sis_tx_cnt < 2)
+ /* Check for descriptor overruns. */
+ if (sc->sis_tx_cnt + nsegs > SIS_TX_LIST_CNT - 1) {
+ bus_dmamap_unload(sc->sis_tx_tag, txd->tx_dmamap);
return (ENOBUFS);
+ }
- /*
- * Count the number of frags in this chain to see if
- * we need to m_defrag. Since the descriptor list is shared
- * by all packets, we'll m_defrag long chains so that they
- * do not use up the entire list, even if they would fit.
- */
-
- for (m = *m_head; m != NULL; m = m->m_next)
- chainlen++;
+ bus_dmamap_sync(sc->sis_tx_tag, txd->tx_dmamap, BUS_DMASYNC_PREWRITE);
- if ((chainlen > SIS_TX_LIST_CNT / 4) ||
- ((SIS_TX_LIST_CNT - (chainlen + sc->sis_tx_cnt)) < 2)) {
- m = m_defrag(*m_head, M_DONTWAIT);
- if (m == NULL)
- return (ENOBUFS);
- *m_head = m;
+ frag = prod;
+ for (i = 0; i < nsegs; i++) {
+ f = &sc->sis_tx_list[prod];
+ if (i == 0)
+ f->sis_cmdsts = htole32(segs[i].ds_len |
+ SIS_CMDSTS_MORE);
+ else
+ f->sis_cmdsts = htole32(segs[i].ds_len |
+ SIS_CMDSTS_OWN | SIS_CMDSTS_MORE);
+ f->sis_ptr = htole32(SIS_ADDR_LO(segs[i].ds_addr));
+ SIS_INC(prod, SIS_TX_LIST_CNT);
+ sc->sis_tx_cnt++;
}
- /*
- * Start packing the mbufs in this chain into
- * the fragment pointers. Stop when we run out
- * of fragments or hit the end of the mbuf chain.
- */
- cur = frag = *txidx;
-
- for (m = *m_head; m != NULL; m = m->m_next) {
- if (m->m_len != 0) {
- if ((SIS_TX_LIST_CNT -
- (sc->sis_tx_cnt + cnt)) < 2)
- return (ENOBUFS);
- f = &sc->sis_tx_list[frag];
- f->sis_ctl = SIS_CMDSTS_MORE | m->m_len;
- bus_dmamap_create(sc->sis_tag, 0, &f->sis_map);
- bus_dmamap_load(sc->sis_tag, f->sis_map,
- mtod(m, void *), m->m_len,
- sis_dma_map_desc_ptr, f, 0);
- bus_dmamap_sync(sc->sis_tag,
- f->sis_map, BUS_DMASYNC_PREREAD);
- if (cnt != 0)
- f->sis_ctl |= SIS_CMDSTS_OWN;
- cur = frag;
- SIS_INC(frag, SIS_TX_LIST_CNT);
- cnt++;
- }
- }
+ /* Update producer index. */
+ sc->sis_tx_prod = prod;
- if (m != NULL)
- return (ENOBUFS);
+ /* Remove MORE flag on the last descriptor. */
+ prod = (prod - 1) & (SIS_TX_LIST_CNT - 1);
+ f = &sc->sis_tx_list[prod];
+ f->sis_cmdsts &= ~htole32(SIS_CMDSTS_MORE);
+
+ /* Lastly transfer ownership of packet to the controller. */
+ f = &sc->sis_tx_list[frag];
+ f->sis_cmdsts |= htole32(SIS_CMDSTS_OWN);
- sc->sis_tx_list[cur].sis_mbuf = *m_head;
- sc->sis_tx_list[cur].sis_ctl &= ~SIS_CMDSTS_MORE;
- sc->sis_tx_list[*txidx].sis_ctl |= SIS_CMDSTS_OWN;
- sc->sis_tx_cnt += cnt;
- *txidx = frag;
+ /* Swap the last and the first dmamaps. */
+ map = txd->tx_dmamap;
+ txd->tx_dmamap = sc->sis_txdesc[frag].tx_dmamap;
+ sc->sis_txdesc[frag].tx_dmamap = map;
+ txd->tx_m = *m_head;
return (0);
}
-/*
- * Main transmit routine. To avoid having to do mbuf copies, we put pointers
- * to the mbuf data regions directly in the transmit lists. We also save a
- * copy of the pointers since the transmit list fragment pointers are
- * physical addresses.
- */
-
static void
sis_start(struct ifnet *ifp)
{
@@ -1772,27 +1839,26 @@ static void
sis_startl(struct ifnet *ifp)
{
struct sis_softc *sc;
- struct mbuf *m_head = NULL;
- u_int32_t idx, queued = 0;
+ struct mbuf *m_head;
+ int queued;
sc = ifp->if_softc;
SIS_LOCK_ASSERT(sc);
- if (!sc->sis_link)
+ if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+ IFF_DRV_RUNNING || sc->sis_link == 0)
return;
- idx = sc->sis_tx_prod;
-
- if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
- return;
-
- while (sc->sis_tx_list[idx].sis_mbuf == NULL) {
+ for (queued = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
+ sc->sis_tx_cnt < SIS_TX_LIST_CNT - 4;) {
IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
if (m_head == NULL)
break;
- if (sis_encap(sc, &m_head, &idx)) {
+ if (sis_encap(sc, &m_head) != 0) {
+ if (m_head == NULL)
+ break;
IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
break;
@@ -1805,12 +1871,12 @@ sis_startl(struct ifnet *ifp)
* to him.
*/
BPF_MTAP(ifp, m_head);
-
}
if (queued) {
/* Transmit */
- sc->sis_tx_prod = idx;
+ bus_dmamap_sync(sc->sis_tx_list_tag, sc->sis_tx_list_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_ENABLE);
/*
@@ -1948,8 +2014,8 @@ sis_initl(struct sis_softc *sc)
/*
* Load the address of the RX and TX lists.
*/
- CSR_WRITE_4(sc, SIS_RX_LISTPTR, sc->sis_rx_paddr);
- CSR_WRITE_4(sc, SIS_TX_LISTPTR, sc->sis_tx_paddr);
+ CSR_WRITE_4(sc, SIS_RX_LISTPTR, SIS_ADDR_LO(sc->sis_rx_paddr));
+ CSR_WRITE_4(sc, SIS_TX_LISTPTR, SIS_ADDR_LO(sc->sis_tx_paddr));
/* SIS_CFG_EDB_MASTER_EN indicates the EDB bus is used instead of
* the PCI bus. When this bit is set, the Max DMA Burst Size
@@ -1991,7 +2057,7 @@ sis_initl(struct sis_softc *sc)
}
if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr < NS_SRR_16A &&
- IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) {
+ IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) {
uint32_t reg;
/*
@@ -2186,9 +2252,10 @@ sis_watchdog(struct sis_softc *sc)
static void
sis_stop(struct sis_softc *sc)
{
- int i;
struct ifnet *ifp;
- struct sis_desc *dp;
+ struct sis_rxdesc *rxd;
+ struct sis_txdesc *txd;
+ int i;
if (sc->sis_stopped)
return;
@@ -2212,32 +2279,31 @@ sis_stop(struct sis_softc *sc)
/*
* Free data in the RX lists.
*/
- dp = &sc->sis_rx_list[0];
- for (i = 0; i < SIS_RX_LIST_CNT; i++, dp++) {
- if (dp->sis_mbuf == NULL)
- continue;
- bus_dmamap_unload(sc->sis_tag, dp->sis_map);
- bus_dmamap_destroy(sc->sis_tag, dp->sis_map);
- m_freem(dp->sis_mbuf);
- dp->sis_mbuf = NULL;
+ for (i = 0; i < SIS_RX_LIST_CNT; i++) {
+ rxd = &sc->sis_rxdesc[i];
+ if (rxd->rx_m != NULL) {
+ bus_dmamap_sync(sc->sis_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->sis_rx_tag, rxd->rx_dmamap);
+ m_freem(rxd->rx_m);
+ rxd->rx_m = NULL;
+ }
}
- bzero(sc->sis_rx_list, SIS_RX_LIST_SZ);
/*
* Free the TX list buffers.
*/
- dp = &sc->sis_tx_list[0];
- for (i = 0; i < SIS_TX_LIST_CNT; i++, dp++) {
- if (dp->sis_mbuf == NULL)
- continue;
- bus_dmamap_unload(sc->sis_tag, dp->sis_map);
- bus_dmamap_destroy(sc->sis_tag, dp->sis_map);
- m_freem(dp->sis_mbuf);
- dp->sis_mbuf = NULL;
+ for (i = 0; i < SIS_TX_LIST_CNT; i++) {
+ txd = &sc->sis_txdesc[i];
+ if (txd->tx_m != NULL) {
+ bus_dmamap_sync(sc->sis_tx_tag, txd->tx_dmamap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sis_tx_tag, txd->tx_dmamap);
+ m_freem(txd->tx_m);
+ txd->tx_m = NULL;
+ }
}
- bzero(sc->sis_tx_list, SIS_TX_LIST_SZ);
-
sc->sis_stopped = 1;
}
diff --git a/sys/dev/sis/if_sisreg.h b/sys/dev/sis/if_sisreg.h
index 455c598..2f23304 100644
--- a/sys/dev/sis/if_sisreg.h
+++ b/sys/dev/sis/if_sisreg.h
@@ -304,25 +304,13 @@
#define NS_FILTADDR_FMEM_HI 0x000003FE
/*
- * DMA descriptor structures. The first part of the descriptor
- * is the hardware descriptor format, which is just three longwords.
- * After this, we include some additional structure members for
- * use by the driver. Note that for this structure will be a different
- * size on the alpha, but that's okay as long as it's a multiple of 4
- * bytes in size.
+ * TX/RX DMA descriptor structures.
*/
struct sis_desc {
/* SiS hardware descriptor section */
u_int32_t sis_next;
u_int32_t sis_cmdsts;
-#define sis_rxstat sis_cmdsts
-#define sis_txstat sis_cmdsts
-#define sis_ctl sis_cmdsts
u_int32_t sis_ptr;
- /* Driver software section */
- struct mbuf *sis_mbuf;
- struct sis_desc *sis_nextdesc;
- bus_dmamap_t sis_map;
};
#define SIS_CMDSTS_BUFLEN 0x00000FFF
@@ -332,11 +320,6 @@ struct sis_desc {
#define SIS_CMDSTS_MORE 0x40000000
#define SIS_CMDSTS_OWN 0x80000000
-#define SIS_LASTDESC(x) (!((x)->sis_ctl & SIS_CMDSTS_MORE))
-#define SIS_OWNDESC(x) ((x)->sis_ctl & SIS_CMDSTS_OWN)
-#define SIS_INC(x, y) (x) = ((x) == ((y)-1)) ? 0 : (x)+1
-#define SIS_RXBYTES(x) (((x)->sis_ctl & SIS_CMDSTS_BUFLEN) - ETHER_CRC_LEN)
-
#define SIS_RXSTAT_COLL 0x00010000
#define SIS_RXSTAT_LOOPBK 0x00020000
#define SIS_RXSTAT_ALIGNERR 0x00040000
@@ -367,12 +350,25 @@ struct sis_desc {
#define SIS_TXSTAT_UNDERRUN 0x02000000
#define SIS_TXSTAT_TX_ABORT 0x04000000
+#define SIS_DESC_ALIGN 16
+#define SIS_RX_BUF_ALIGN 4
+#define SIS_MAXTXSEGS 16
#define SIS_RX_LIST_CNT 64
#define SIS_TX_LIST_CNT 128
#define SIS_RX_LIST_SZ SIS_RX_LIST_CNT * sizeof(struct sis_desc)
#define SIS_TX_LIST_SZ SIS_TX_LIST_CNT * sizeof(struct sis_desc)
+#define SIS_ADDR_LO(x) ((uint64_t) (x) & 0xffffffff)
+#define SIS_ADDR_HI(x) ((uint64_t) (x) >> 32)
+
+#define SIS_RX_RING_ADDR(sc, i) \
+ ((sc)->sis_rx_paddr + sizeof(struct sis_desc) * (i))
+#define SIS_TX_RING_ADDR(sc, i) \
+ ((sc)->sis_tx_paddr + sizeof(struct sis_desc) * (i))
+
+#define SIS_INC(x, y) (x) = (x + 1) % (y)
+
/*
* SiS PCI vendor ID.
*/
@@ -434,6 +430,17 @@ struct sis_mii_frame {
#define SIS_TYPE_83815 3
#define SIS_TYPE_83816 4
+struct sis_txdesc {
+ struct mbuf *tx_m;
+ bus_dmamap_t tx_dmamap;
+};
+
+struct sis_rxdesc {
+ struct mbuf *rx_m;
+ bus_dmamap_t rx_dmamap;
+ struct sis_desc *rx_desc;
+};
+
struct sis_softc {
struct ifnet *sis_ifp; /* interface info */
struct resource *sis_res[2];
@@ -446,18 +453,22 @@ struct sis_softc {
u_int sis_srr;
struct sis_desc *sis_rx_list;
struct sis_desc *sis_tx_list;
+ bus_dma_tag_t sis_rx_list_tag;
+ bus_dmamap_t sis_rx_list_map;
+ bus_dma_tag_t sis_tx_list_tag;
+ bus_dmamap_t sis_tx_list_map;
+ bus_dma_tag_t sis_parent_tag;
bus_dma_tag_t sis_rx_tag;
- bus_dmamap_t sis_rx_dmamap;
+ bus_dmamap_t sis_rx_sparemap;
bus_dma_tag_t sis_tx_tag;
- bus_dmamap_t sis_tx_dmamap;
- bus_dma_tag_t sis_parent_tag;
- bus_dma_tag_t sis_tag;
- struct sis_desc *sis_rx_pdsc;
+ struct sis_rxdesc sis_rxdesc[SIS_RX_LIST_CNT];
+ struct sis_txdesc sis_txdesc[SIS_TX_LIST_CNT];
int sis_tx_prod;
int sis_tx_cons;
int sis_tx_cnt;
- u_int32_t sis_rx_paddr;
- u_int32_t sis_tx_paddr;
+ int sis_rx_cons;;
+ bus_addr_t sis_rx_paddr;
+ bus_addr_t sis_tx_paddr;
struct callout sis_stat_ch;
int sis_watchdog_timer;
int sis_stopped;
OpenPOWER on IntegriCloud