aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPyun YongHyeon <yongari@FreeBSD.org>2011-02-19 02:47:10 +0000
committerPyun YongHyeon <yongari@FreeBSD.org>2011-02-19 02:47:10 +0000
commit5f14ee2363742961c7e5ddfdf735bbc8720efce4 (patch)
treeb42d4b0cd842d1249d0eed31ab353b80acd4045c
parenta84b4e80ca77cd6e0b335d36307b34579a4364ec (diff)
downloadsrc-5f14ee2363742961c7e5ddfdf735bbc8720efce4.tar.gz
src-5f14ee2363742961c7e5ddfdf735bbc8720efce4.zip
Split common TX/RX descriptor DMA tag to TX and RX DMA tags
respectively and fix all bus_dma(9) issues seen when bounce buffers are used. o Setup frame handling had no bus_dmamap_sync(9) which prevented driver from configuring RX filter. Add missing bus_dmamap_sync(9) in both dc_setfilt_21143()/dc_setfilt_xircom() and dc_txeof(). o Use bus_addr_t for DMA segment instead of using u_int32_t. o Introduce dc_dma_alloc()/dc_dma_free() functions to allocate/free DMA'able memory. o Create two DMA descriptor list for each TX/RX lists. This change will minimize the size of bounce buffers that would be used in each TX/RX path. Previously driver had to copy both TX/RX lists when bounce buffer is active. o 21143 data sheet says descriptor list requires 4 bytes alignment. Remove PAGE_SIZE alignment restriction and use sizeof(struct dc_dec). o Setup frame requires 4 bytes alignment. Remove PAGE_SIZE alignment restriction and use sizeof(struct dc_dec). o Add missing DMA map unload for both setup frame and TX/RX descriptor list. o Overhaul RX handling logic such that make driver always allocate new RX buffer with dc_newbuf(). Previously driver allowed to copy received frame with m_devget(9) after passing the descriptor ownership to controller. This can lead to passing wrong frame to upper stack. o Introduce dc_discard_rxbuf() which will discard received frame and reuse loaded DMA map and RX mbuf. o Correct several wrong bus_dmamap_sync(9) usage in dc_rxeof and dc_txeof. The TX/RX descriptor lists are updated by both driver and HW so READ/WRITE semantics should be used. o If driver failed to allocate new RX buffer, update if_iqdrops counter instead of if_ierrors since driver received the frame without errors. o Make sure to unload loaded setup frame DMA map in dc_txeof and clear the mark of setup frame of the TX descriptor in dc_txeof(). o Add check for possible TX descriptor overruns in dc_encap() and move check for free buffer to caller, dc_start_locked(). o Swap the loaded DMA map and the last DMA map for multi-segmented frames. Since dc_txeof() assumes the last descriptor of the frame has the DMA map, driver should swap the first and the last DMA map in dc_encap(). Previously driver tried to unload not-yet-loaded DMA map such that the loaded DMA map was not unloaded at all for multi-segmented frames. o Rewrite DC_RXDESC/DC_TXDESC macro to simpler one. o Remove definition of ETHER_ALIGN, it's already defined in ethernet.h. With this changes, dc(4) works with bounce buffers and it shall also fix issues which might have shown in PAE environments. Tested by: marius
Notes
Notes: svn path=/head/; revision=218832
-rw-r--r--sys/dev/dc/if_dc.c668
-rw-r--r--sys/dev/dc/if_dcreg.h37
2 files changed, 429 insertions, 276 deletions
diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c
index 13aaf28367de..6bd5ac01db98 100644
--- a/sys/dev/dc/if_dc.c
+++ b/sys/dev/dc/if_dc.c
@@ -233,7 +233,8 @@ static int dc_detach(device_t);
static int dc_suspend(device_t);
static int dc_resume(device_t);
static const struct dc_type *dc_devtype(device_t);
-static int dc_newbuf(struct dc_softc *, int, int);
+static void dc_discard_rxbuf(struct dc_softc *, int);
+static int dc_newbuf(struct dc_softc *, int);
static int dc_encap(struct dc_softc *, struct mbuf **);
static void dc_pnic_rx_bug_war(struct dc_softc *, int);
static int dc_rx_resync(struct dc_softc *);
@@ -253,6 +254,10 @@ static int dc_shutdown(device_t);
static int dc_ifmedia_upd(struct ifnet *);
static void dc_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+static int dc_dma_alloc(struct dc_softc *);
+static void dc_dma_free(struct dc_softc *);
+static void dc_dma_map_addr(void *, bus_dma_segment_t *, int, int);
+
static void dc_delay(struct dc_softc *);
static void dc_eeprom_idle(struct dc_softc *);
static void dc_eeprom_putbyte(struct dc_softc *, int);
@@ -1087,11 +1092,11 @@ dc_setfilt_21143(struct dc_softc *sc)
i = sc->dc_cdata.dc_tx_prod;
DC_INC(sc->dc_cdata.dc_tx_prod, DC_TX_LIST_CNT);
sc->dc_cdata.dc_tx_cnt++;
- sframe = &sc->dc_ldata->dc_tx_list[i];
+ sframe = &sc->dc_ldata.dc_tx_list[i];
sp = sc->dc_cdata.dc_sbuf;
bzero(sp, DC_SFRAME_LEN);
- sframe->dc_data = htole32(sc->dc_saddr);
+ sframe->dc_data = htole32(DC_ADDR_LO(sc->dc_saddr));
sframe->dc_ctl = htole32(DC_SFRAME_LEN | DC_TXCTL_SETUP |
DC_TXCTL_TLINK | DC_FILTER_HASHPERF | DC_TXCTL_FINT);
@@ -1130,6 +1135,7 @@ dc_setfilt_21143(struct dc_softc *sc)
sp[41] = DC_SP_MAC(eaddr[2]);
sframe->dc_status = htole32(DC_TXSTAT_OWN);
+ bus_dmamap_sync(sc->dc_stag, sc->dc_smap, BUS_DMASYNC_PREWRITE);
CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
/*
@@ -1290,11 +1296,11 @@ dc_setfilt_xircom(struct dc_softc *sc)
i = sc->dc_cdata.dc_tx_prod;
DC_INC(sc->dc_cdata.dc_tx_prod, DC_TX_LIST_CNT);
sc->dc_cdata.dc_tx_cnt++;
- sframe = &sc->dc_ldata->dc_tx_list[i];
+ sframe = &sc->dc_ldata.dc_tx_list[i];
sp = sc->dc_cdata.dc_sbuf;
bzero(sp, DC_SFRAME_LEN);
- sframe->dc_data = htole32(sc->dc_saddr);
+ sframe->dc_data = htole32(DC_ADDR_LO(sc->dc_saddr));
sframe->dc_ctl = htole32(DC_SFRAME_LEN | DC_TXCTL_SETUP |
DC_TXCTL_TLINK | DC_FILTER_HASHPERF | DC_TXCTL_FINT);
@@ -1335,6 +1341,7 @@ dc_setfilt_xircom(struct dc_softc *sc)
DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON);
DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ON);
sframe->dc_status = htole32(DC_TXSTAT_OWN);
+ bus_dmamap_sync(sc->dc_stag, sc->dc_smap, BUS_DMASYNC_PREWRITE);
CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
/*
@@ -1806,7 +1813,7 @@ dc_parse_21143_srom(struct dc_softc *sc)
static void
dc_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
- u_int32_t *paddr;
+ bus_addr_t *paddr;
KASSERT(nseg == 1,
("%s: wrong number of segments (%d)", __func__, nseg));
@@ -1814,6 +1821,208 @@ dc_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
*paddr = segs->ds_addr;
}
+static int
+dc_dma_alloc(struct dc_softc *sc)
+{
+ int error, i;
+
+ error = bus_dma_tag_create(bus_get_dma_tag(sc->dc_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->dc_ptag);
+ if (error) {
+ device_printf(sc->dc_dev,
+ "failed to allocate parent DMA tag\n");
+ goto fail;
+ }
+
+ /* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */
+ error = bus_dma_tag_create(sc->dc_ptag, DC_LIST_ALIGN, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, DC_RX_LIST_SZ, 1,
+ DC_RX_LIST_SZ, 0, NULL, NULL, &sc->dc_rx_ltag);
+ if (error) {
+ device_printf(sc->dc_dev, "failed to create RX list DMA tag\n");
+ goto fail;
+ }
+
+ error = bus_dma_tag_create(sc->dc_ptag, DC_LIST_ALIGN, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, DC_TX_LIST_SZ, 1,
+ DC_TX_LIST_SZ, 0, NULL, NULL, &sc->dc_tx_ltag);
+ if (error) {
+ device_printf(sc->dc_dev, "failed to create TX list DMA tag\n");
+ goto fail;
+ }
+
+ /* RX descriptor list. */
+ error = bus_dmamem_alloc(sc->dc_rx_ltag,
+ (void **)&sc->dc_ldata.dc_rx_list, BUS_DMA_NOWAIT |
+ BUS_DMA_ZERO | BUS_DMA_COHERENT, &sc->dc_rx_lmap);
+ if (error) {
+ device_printf(sc->dc_dev,
+ "failed to allocate DMA'able memory for RX list\n");
+ goto fail;
+ }
+ error = bus_dmamap_load(sc->dc_rx_ltag, sc->dc_rx_lmap,
+ sc->dc_ldata.dc_rx_list, DC_RX_LIST_SZ, dc_dma_map_addr,
+ &sc->dc_ldata.dc_rx_list_paddr, BUS_DMA_NOWAIT);
+ if (error) {
+ device_printf(sc->dc_dev,
+ "failed to load DMA'able memory for RX list\n");
+ goto fail;
+ }
+ /* TX descriptor list. */
+ error = bus_dmamem_alloc(sc->dc_tx_ltag,
+ (void **)&sc->dc_ldata.dc_tx_list, BUS_DMA_NOWAIT |
+ BUS_DMA_ZERO | BUS_DMA_COHERENT, &sc->dc_tx_lmap);
+ if (error) {
+ device_printf(sc->dc_dev,
+ "failed to allocate DMA'able memory for TX list\n");
+ goto fail;
+ }
+ error = bus_dmamap_load(sc->dc_tx_ltag, sc->dc_tx_lmap,
+ sc->dc_ldata.dc_tx_list, DC_TX_LIST_SZ, dc_dma_map_addr,
+ &sc->dc_ldata.dc_tx_list_paddr, BUS_DMA_NOWAIT);
+ if (error) {
+ device_printf(sc->dc_dev,
+ "cannot load DMA'able memory for TX list\n");
+ goto fail;
+ }
+
+ /*
+ * Allocate a busdma tag and DMA safe memory for the multicast
+ * setup frame.
+ */
+ error = bus_dma_tag_create(sc->dc_ptag, DC_LIST_ALIGN, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+ DC_SFRAME_LEN + DC_MIN_FRAMELEN, 1, DC_SFRAME_LEN + DC_MIN_FRAMELEN,
+ 0, NULL, NULL, &sc->dc_stag);
+ if (error) {
+ device_printf(sc->dc_dev,
+ "failed to create DMA tag for setup frame\n");
+ goto fail;
+ }
+ error = bus_dmamem_alloc(sc->dc_stag, (void **)&sc->dc_cdata.dc_sbuf,
+ BUS_DMA_NOWAIT, &sc->dc_smap);
+ if (error) {
+ device_printf(sc->dc_dev,
+ "failed to allocate DMA'able memory for setup frame\n");
+ goto fail;
+ }
+ error = bus_dmamap_load(sc->dc_stag, sc->dc_smap, sc->dc_cdata.dc_sbuf,
+ DC_SFRAME_LEN, dc_dma_map_addr, &sc->dc_saddr, BUS_DMA_NOWAIT);
+ if (error) {
+ device_printf(sc->dc_dev,
+ "cannot load DMA'able memory for setup frame\n");
+ goto fail;
+ }
+
+ /* Allocate a busdma tag for RX mbufs. */
+ error = bus_dma_tag_create(sc->dc_ptag, DC_RXBUF_ALIGN, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+ MCLBYTES, 1, MCLBYTES, 0, NULL, NULL, &sc->dc_rx_mtag);
+ if (error) {
+ device_printf(sc->dc_dev, "failed to create RX mbuf tag\n");
+ goto fail;
+ }
+
+ /* Allocate a busdma tag for TX mbufs. */
+ error = bus_dma_tag_create(sc->dc_ptag, 1, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+ MCLBYTES * DC_MAXFRAGS, DC_MAXFRAGS, MCLBYTES,
+ 0, NULL, NULL, &sc->dc_tx_mtag);
+ if (error) {
+ device_printf(sc->dc_dev, "failed to create TX mbuf tag\n");
+ goto fail;
+ }
+
+ /* Create the TX/RX busdma maps. */
+ for (i = 0; i < DC_TX_LIST_CNT; i++) {
+ error = bus_dmamap_create(sc->dc_tx_mtag, 0,
+ &sc->dc_cdata.dc_tx_map[i]);
+ if (error) {
+ device_printf(sc->dc_dev,
+ "failed to create TX mbuf dmamap\n");
+ goto fail;
+ }
+ }
+ for (i = 0; i < DC_RX_LIST_CNT; i++) {
+ error = bus_dmamap_create(sc->dc_rx_mtag, 0,
+ &sc->dc_cdata.dc_rx_map[i]);
+ if (error) {
+ device_printf(sc->dc_dev,
+ "failed to create RX mbuf dmamap\n");
+ goto fail;
+ }
+ }
+ error = bus_dmamap_create(sc->dc_rx_mtag, 0, &sc->dc_sparemap);
+ if (error) {
+ device_printf(sc->dc_dev,
+ "failed to create spare RX mbuf dmamap\n");
+ goto fail;
+ }
+
+fail:
+ return (error);
+}
+
+static void
+dc_dma_free(struct dc_softc *sc)
+{
+ int i;
+
+ /* RX buffers. */
+ if (sc->dc_rx_mtag != NULL) {
+ for (i = 0; i < DC_RX_LIST_CNT; i++) {
+ if (sc->dc_cdata.dc_rx_map[i] != NULL)
+ bus_dmamap_destroy(sc->dc_rx_mtag,
+ sc->dc_cdata.dc_rx_map[i]);
+ }
+ if (sc->dc_sparemap != NULL)
+ bus_dmamap_destroy(sc->dc_rx_mtag, sc->dc_sparemap);
+ bus_dma_tag_destroy(sc->dc_rx_mtag);
+ }
+
+ /* TX buffers. */
+ if (sc->dc_rx_mtag != NULL) {
+ for (i = 0; i < DC_TX_LIST_CNT; i++) {
+ if (sc->dc_cdata.dc_tx_map[i] != NULL)
+ bus_dmamap_destroy(sc->dc_tx_mtag,
+ sc->dc_cdata.dc_tx_map[i]);
+ }
+ bus_dma_tag_destroy(sc->dc_tx_mtag);
+ }
+
+ /* RX descriptor list. */
+ if (sc->dc_rx_ltag) {
+ if (sc->dc_rx_lmap != NULL)
+ bus_dmamap_unload(sc->dc_rx_ltag, sc->dc_rx_lmap);
+ if (sc->dc_rx_lmap != NULL && sc->dc_ldata.dc_rx_list != NULL)
+ bus_dmamem_free(sc->dc_rx_ltag, sc->dc_ldata.dc_rx_list,
+ sc->dc_rx_lmap);
+ bus_dma_tag_destroy(sc->dc_rx_ltag);
+ }
+
+ /* TX descriptor list. */
+ if (sc->dc_tx_ltag) {
+ if (sc->dc_tx_lmap != NULL)
+ bus_dmamap_unload(sc->dc_tx_ltag, sc->dc_tx_lmap);
+ if (sc->dc_tx_lmap != NULL && sc->dc_ldata.dc_tx_list != NULL)
+ bus_dmamem_free(sc->dc_tx_ltag, sc->dc_ldata.dc_tx_list,
+ sc->dc_tx_lmap);
+ bus_dma_tag_destroy(sc->dc_tx_ltag);
+ }
+
+ /* multicast setup frame. */
+ if (sc->dc_stag) {
+ if (sc->dc_smap != NULL)
+ bus_dmamap_unload(sc->dc_stag, sc->dc_smap);
+ if (sc->dc_smap != NULL && sc->dc_cdata.dc_sbuf != NULL)
+ bus_dmamem_free(sc->dc_stag, sc->dc_cdata.dc_sbuf,
+ sc->dc_smap);
+ bus_dma_tag_destroy(sc->dc_stag);
+ }
+}
+
/*
* Attach the interface. Allocate softc structures, do ifmedia
* setup and ethernet/BPF attach.
@@ -1827,7 +2036,7 @@ dc_attach(device_t dev)
struct ifnet *ifp;
struct dc_mediainfo *m;
u_int32_t reg, revision;
- int error, i, mac_offset, phy, rid, tmp;
+ int error, mac_offset, phy, rid, tmp;
u_int8_t *mac;
sc = device_get_softc(dev);
@@ -2139,96 +2348,8 @@ dc_attach(device_t dev)
error = 0;
}
- /* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */
- error = bus_dma_tag_create(bus_get_dma_tag(dev), PAGE_SIZE, 0,
- BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
- sizeof(struct dc_list_data), 1, sizeof(struct dc_list_data),
- 0, NULL, NULL, &sc->dc_ltag);
- if (error) {
- device_printf(dev, "failed to allocate busdma tag\n");
- error = ENXIO;
- goto fail;
- }
- error = bus_dmamem_alloc(sc->dc_ltag, (void **)&sc->dc_ldata,
- BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sc->dc_lmap);
- if (error) {
- device_printf(dev, "failed to allocate DMA safe memory\n");
- error = ENXIO;
- goto fail;
- }
- error = bus_dmamap_load(sc->dc_ltag, sc->dc_lmap, sc->dc_ldata,
- sizeof(struct dc_list_data), dc_dma_map_addr, &sc->dc_laddr,
- BUS_DMA_NOWAIT);
- if (error) {
- device_printf(dev, "cannot get address of the descriptors\n");
- error = ENXIO;
- goto fail;
- }
-
- /*
- * Allocate a busdma tag and DMA safe memory for the multicast
- * setup frame.
- */
- error = bus_dma_tag_create(bus_get_dma_tag(dev), PAGE_SIZE, 0,
- BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
- DC_SFRAME_LEN + DC_MIN_FRAMELEN, 1, DC_SFRAME_LEN + DC_MIN_FRAMELEN,
- 0, NULL, NULL, &sc->dc_stag);
- if (error) {
- device_printf(dev, "failed to allocate busdma tag\n");
- error = ENXIO;
- goto fail;
- }
- error = bus_dmamem_alloc(sc->dc_stag, (void **)&sc->dc_cdata.dc_sbuf,
- BUS_DMA_NOWAIT, &sc->dc_smap);
- if (error) {
- device_printf(dev, "failed to allocate DMA safe memory\n");
- error = ENXIO;
- goto fail;
- }
- error = bus_dmamap_load(sc->dc_stag, sc->dc_smap, sc->dc_cdata.dc_sbuf,
- DC_SFRAME_LEN, dc_dma_map_addr, &sc->dc_saddr, BUS_DMA_NOWAIT);
- if (error) {
- device_printf(dev, "cannot get address of the descriptors\n");
- error = ENXIO;
- goto fail;
- }
-
- /* Allocate a busdma tag for mbufs. */
- error = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
- BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
- MCLBYTES * DC_MAXFRAGS, DC_MAXFRAGS, MCLBYTES,
- 0, NULL, NULL, &sc->dc_mtag);
- if (error) {
- device_printf(dev, "failed to allocate busdma tag\n");
- error = ENXIO;
- goto fail;
- }
-
- /* Create the TX/RX busdma maps. */
- for (i = 0; i < DC_TX_LIST_CNT; i++) {
- error = bus_dmamap_create(sc->dc_mtag, 0,
- &sc->dc_cdata.dc_tx_map[i]);
- if (error) {
- device_printf(dev, "failed to init TX ring\n");
- error = ENXIO;
- goto fail;
- }
- }
- for (i = 0; i < DC_RX_LIST_CNT; i++) {
- error = bus_dmamap_create(sc->dc_mtag, 0,
- &sc->dc_cdata.dc_rx_map[i]);
- if (error) {
- device_printf(dev, "failed to init RX ring\n");
- error = ENXIO;
- goto fail;
- }
- }
- error = bus_dmamap_create(sc->dc_mtag, 0, &sc->dc_sparemap);
- if (error) {
- device_printf(dev, "failed to init RX ring\n");
- error = ENXIO;
+ if ((error = dc_dma_alloc(sc)) != 0)
goto fail;
- }
ifp = sc->dc_ifp = if_alloc(IFT_ETHER);
if (ifp == NULL) {
@@ -2377,7 +2498,6 @@ dc_detach(device_t dev)
struct dc_softc *sc;
struct ifnet *ifp;
struct dc_mediainfo *m;
- int i;
sc = device_get_softc(dev);
KASSERT(mtx_initialized(&sc->dc_mtx), ("dc mutex not initialized"));
@@ -2412,27 +2532,7 @@ dc_detach(device_t dev)
if (ifp)
if_free(ifp);
- if (sc->dc_cdata.dc_sbuf != NULL)
- bus_dmamem_free(sc->dc_stag, sc->dc_cdata.dc_sbuf, sc->dc_smap);
- if (sc->dc_ldata != NULL)
- bus_dmamem_free(sc->dc_ltag, sc->dc_ldata, sc->dc_lmap);
- if (sc->dc_mtag) {
- for (i = 0; i < DC_TX_LIST_CNT; i++)
- if (sc->dc_cdata.dc_tx_map[i] != NULL)
- bus_dmamap_destroy(sc->dc_mtag,
- sc->dc_cdata.dc_tx_map[i]);
- for (i = 0; i < DC_RX_LIST_CNT; i++)
- if (sc->dc_cdata.dc_rx_map[i] != NULL)
- bus_dmamap_destroy(sc->dc_mtag,
- sc->dc_cdata.dc_rx_map[i]);
- bus_dmamap_destroy(sc->dc_mtag, sc->dc_sparemap);
- }
- if (sc->dc_stag)
- bus_dma_tag_destroy(sc->dc_stag);
- if (sc->dc_mtag)
- bus_dma_tag_destroy(sc->dc_mtag);
- if (sc->dc_ltag)
- bus_dma_tag_destroy(sc->dc_ltag);
+ dc_dma_free(sc);
free(sc->dc_pnic_rx_buf, M_DEVBUF);
@@ -2459,7 +2559,7 @@ dc_list_tx_init(struct dc_softc *sc)
int i, nexti;
cd = &sc->dc_cdata;
- ld = sc->dc_ldata;
+ ld = &sc->dc_ldata;
for (i = 0; i < DC_TX_LIST_CNT; i++) {
if (i == DC_TX_LIST_CNT - 1)
nexti = 0;
@@ -2474,7 +2574,7 @@ dc_list_tx_init(struct dc_softc *sc)
cd->dc_tx_prod = cd->dc_tx_cons = cd->dc_tx_cnt = 0;
cd->dc_tx_pkts = 0;
- bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap,
+ bus_dmamap_sync(sc->dc_tx_ltag, sc->dc_tx_lmap,
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
return (0);
}
@@ -2493,10 +2593,10 @@ dc_list_rx_init(struct dc_softc *sc)
int i, nexti;
cd = &sc->dc_cdata;
- ld = sc->dc_ldata;
+ ld = &sc->dc_ldata;
for (i = 0; i < DC_RX_LIST_CNT; i++) {
- if (dc_newbuf(sc, i, 1) != 0)
+ if (dc_newbuf(sc, i) != 0)
return (ENOBUFS);
if (i == DC_RX_LIST_CNT - 1)
nexti = 0;
@@ -2506,7 +2606,7 @@ dc_list_rx_init(struct dc_softc *sc)
}
cd->dc_rx_prod = 0;
- bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap,
+ bus_dmamap_sync(sc->dc_rx_ltag, sc->dc_rx_lmap,
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
return (0);
}
@@ -2515,23 +2615,18 @@ dc_list_rx_init(struct dc_softc *sc)
* Initialize an RX descriptor and attach an MBUF cluster.
*/
static int
-dc_newbuf(struct dc_softc *sc, int i, int alloc)
+dc_newbuf(struct dc_softc *sc, int i)
{
- struct mbuf *m_new;
- bus_dmamap_t tmp;
+ struct mbuf *m;
+ bus_dmamap_t map;
bus_dma_segment_t segs[1];
int error, nseg;
- if (alloc) {
- m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
- if (m_new == NULL)
- return (ENOBUFS);
- } else {
- m_new = sc->dc_cdata.dc_rx_chain[i];
- m_new->m_data = m_new->m_ext.ext_buf;
- }
- m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
- m_adj(m_new, sizeof(u_int64_t));
+ 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, sizeof(u_int64_t));
/*
* If this is a PNIC chip, zero the buffer. This is part
@@ -2539,31 +2634,31 @@ dc_newbuf(struct dc_softc *sc, int i, int alloc)
* 82c169 chips.
*/
if (sc->dc_flags & DC_PNIC_RX_BUG_WAR)
- bzero(mtod(m_new, char *), m_new->m_len);
+ bzero(mtod(m, char *), m->m_len);
- /* No need to remap the mbuf if we're reusing it. */
- if (alloc) {
- error = bus_dmamap_load_mbuf_sg(sc->dc_mtag, sc->dc_sparemap,
- m_new, segs, &nseg, 0);
- if (error) {
- m_freem(m_new);
- return (error);
- }
- KASSERT(nseg == 1,
- ("%s: wrong number of segments (%d)", __func__, nseg));
- sc->dc_ldata->dc_rx_list[i].dc_data = htole32(segs->ds_addr);
- bus_dmamap_unload(sc->dc_mtag, sc->dc_cdata.dc_rx_map[i]);
- tmp = sc->dc_cdata.dc_rx_map[i];
- sc->dc_cdata.dc_rx_map[i] = sc->dc_sparemap;
- sc->dc_sparemap = tmp;
- sc->dc_cdata.dc_rx_chain[i] = m_new;
- }
-
- sc->dc_ldata->dc_rx_list[i].dc_ctl = htole32(DC_RXCTL_RLINK | DC_RXLEN);
- sc->dc_ldata->dc_rx_list[i].dc_status = htole32(DC_RXSTAT_OWN);
- bus_dmamap_sync(sc->dc_mtag, sc->dc_cdata.dc_rx_map[i],
+ error = bus_dmamap_load_mbuf_sg(sc->dc_rx_mtag, sc->dc_sparemap,
+ m, segs, &nseg, 0);
+ if (error) {
+ m_freem(m);
+ return (error);
+ }
+ KASSERT(nseg == 1, ("%s: wrong number of segments (%d)", __func__,
+ nseg));
+ if (sc->dc_cdata.dc_rx_chain[i] != NULL)
+ bus_dmamap_unload(sc->dc_rx_mtag, sc->dc_cdata.dc_rx_map[i]);
+
+ map = sc->dc_cdata.dc_rx_map[i];
+ sc->dc_cdata.dc_rx_map[i] = sc->dc_sparemap;
+ sc->dc_sparemap = map;
+ sc->dc_cdata.dc_rx_chain[i] = m;
+ bus_dmamap_sync(sc->dc_rx_mtag, sc->dc_cdata.dc_rx_map[i],
BUS_DMASYNC_PREREAD);
- bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap,
+
+ sc->dc_ldata.dc_rx_list[i].dc_ctl = htole32(DC_RXCTL_RLINK | DC_RXLEN);
+ sc->dc_ldata.dc_rx_list[i].dc_data =
+ htole32(DC_ADDR_LO(segs[0].ds_addr));
+ sc->dc_ldata.dc_rx_list[i].dc_status = htole32(DC_RXSTAT_OWN);
+ bus_dmamap_sync(sc->dc_rx_ltag, sc->dc_rx_lmap,
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
return (0);
}
@@ -2632,13 +2727,13 @@ dc_pnic_rx_bug_war(struct dc_softc *sc, int idx)
u_int32_t rxstat = 0;
i = sc->dc_pnic_rx_bug_save;
- cur_rx = &sc->dc_ldata->dc_rx_list[idx];
+ cur_rx = &sc->dc_ldata.dc_rx_list[idx];
ptr = sc->dc_pnic_rx_buf;
bzero(ptr, DC_RXLEN * 5);
/* Copy all the bytes from the bogus buffers. */
while (1) {
- c = &sc->dc_ldata->dc_rx_list[i];
+ c = &sc->dc_ldata.dc_rx_list[i];
rxstat = le32toh(c->dc_status);
m = sc->dc_cdata.dc_rx_chain[i];
bcopy(mtod(m, char *), ptr, DC_RXLEN);
@@ -2646,7 +2741,7 @@ dc_pnic_rx_bug_war(struct dc_softc *sc, int idx)
/* If this is the last buffer, break out. */
if (i == idx || rxstat & DC_RXSTAT_LASTFRAG)
break;
- dc_newbuf(sc, i, 0);
+ dc_discard_rxbuf(sc, i);
DC_INC(i, DC_RX_LIST_CNT);
}
@@ -2695,7 +2790,9 @@ dc_rx_resync(struct dc_softc *sc)
pos = sc->dc_cdata.dc_rx_prod;
for (i = 0; i < DC_RX_LIST_CNT; i++) {
- cur_rx = &sc->dc_ldata->dc_rx_list[pos];
+ bus_dmamap_sync(sc->dc_rx_ltag, sc->dc_rx_lmap,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ cur_rx = &sc->dc_ldata.dc_rx_list[pos];
if (!(le32toh(cur_rx->dc_status) & DC_RXSTAT_OWN))
break;
DC_INC(pos, DC_RX_LIST_CNT);
@@ -2711,6 +2808,22 @@ dc_rx_resync(struct dc_softc *sc)
return (EAGAIN);
}
+static void
+dc_discard_rxbuf(struct dc_softc *sc, int i)
+{
+ struct mbuf *m;
+
+ if (sc->dc_flags & DC_PNIC_RX_BUG_WAR) {
+ m = sc->dc_cdata.dc_rx_chain[i];
+ bzero(mtod(m, char *), m->m_len);
+ }
+
+ sc->dc_ldata.dc_rx_list[i].dc_ctl = htole32(DC_RXCTL_RLINK | DC_RXLEN);
+ sc->dc_ldata.dc_rx_list[i].dc_status = htole32(DC_RXSTAT_OWN);
+ bus_dmamap_sync(sc->dc_rx_ltag, sc->dc_rx_lmap, BUS_DMASYNC_PREREAD |
+ BUS_DMASYNC_PREWRITE);
+}
+
/*
* A frame has been uploaded: pass the resulting mbuf chain up to
* the higher level protocols.
@@ -2718,7 +2831,7 @@ dc_rx_resync(struct dc_softc *sc)
static int
dc_rxeof(struct dc_softc *sc)
{
- struct mbuf *m, *m0;
+ struct mbuf *m;
struct ifnet *ifp;
struct dc_desc *cur_rx;
int i, total_len, rx_npkts;
@@ -2727,13 +2840,13 @@ dc_rxeof(struct dc_softc *sc)
DC_LOCK_ASSERT(sc);
ifp = sc->dc_ifp;
- i = sc->dc_cdata.dc_rx_prod;
- total_len = 0;
rx_npkts = 0;
- bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, BUS_DMASYNC_POSTREAD);
- while (!(le32toh(sc->dc_ldata->dc_rx_list[i].dc_status) &
- DC_RXSTAT_OWN)) {
+ bus_dmamap_sync(sc->dc_rx_ltag, sc->dc_rx_lmap, BUS_DMASYNC_POSTREAD |
+ BUS_DMASYNC_POSTWRITE);
+ for (i = sc->dc_cdata.dc_rx_prod;
+ (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
+ DC_INC(i, DC_RX_LIST_CNT)) {
#ifdef DEVICE_POLLING
if (ifp->if_capenable & IFCAP_POLLING) {
if (sc->rxcycles <= 0)
@@ -2741,10 +2854,12 @@ dc_rxeof(struct dc_softc *sc)
sc->rxcycles--;
}
#endif
- cur_rx = &sc->dc_ldata->dc_rx_list[i];
+ cur_rx = &sc->dc_ldata.dc_rx_list[i];
rxstat = le32toh(cur_rx->dc_status);
+ if ((rxstat & DC_RXSTAT_OWN) != 0)
+ break;
m = sc->dc_cdata.dc_rx_chain[i];
- bus_dmamap_sync(sc->dc_mtag, sc->dc_cdata.dc_rx_map[i],
+ bus_dmamap_sync(sc->dc_rx_mtag, sc->dc_cdata.dc_rx_map[i],
BUS_DMASYNC_POSTREAD);
total_len = DC_RXBYTES(rxstat);
@@ -2752,10 +2867,8 @@ dc_rxeof(struct dc_softc *sc)
if ((rxstat & DC_WHOLEFRAME) != DC_WHOLEFRAME) {
if (rxstat & DC_RXSTAT_FIRSTFRAG)
sc->dc_pnic_rx_bug_save = i;
- if ((rxstat & DC_RXSTAT_LASTFRAG) == 0) {
- DC_INC(i, DC_RX_LIST_CNT);
+ if ((rxstat & DC_RXSTAT_LASTFRAG) == 0)
continue;
- }
dc_pnic_rx_bug_war(sc, i);
rxstat = le32toh(cur_rx->dc_status);
total_len = DC_RXBYTES(rxstat);
@@ -2777,11 +2890,10 @@ dc_rxeof(struct dc_softc *sc)
ifp->if_ierrors++;
if (rxstat & DC_RXSTAT_COLLSEEN)
ifp->if_collisions++;
- dc_newbuf(sc, i, 0);
- if (rxstat & DC_RXSTAT_CRCERR) {
- DC_INC(i, DC_RX_LIST_CNT);
+ dc_discard_rxbuf(sc, i);
+ if (rxstat & DC_RXSTAT_CRCERR)
continue;
- } else {
+ else {
dc_init_locked(sc);
return (rx_npkts);
}
@@ -2800,23 +2912,27 @@ dc_rxeof(struct dc_softc *sc)
* if the allocation fails, then use m_devget and leave the
* existing buffer in the receive ring.
*/
- if (dc_newbuf(sc, i, 1) == 0) {
- m->m_pkthdr.rcvif = ifp;
- m->m_pkthdr.len = m->m_len = total_len;
- DC_INC(i, DC_RX_LIST_CNT);
- } else
-#endif
+ if (dc_newbuf(sc, i) != 0) {
+ dc_discard_rxbuf(sc, i);
+ ifp->if_iqdrops++;
+ continue;
+ }
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = total_len;
+#else
{
+ struct mbuf *m0;
+
m0 = m_devget(mtod(m, char *), total_len,
ETHER_ALIGN, ifp, NULL);
- dc_newbuf(sc, i, 0);
- DC_INC(i, DC_RX_LIST_CNT);
+ dc_discard_rxbuf(sc, i);
if (m0 == NULL) {
- ifp->if_ierrors++;
+ ifp->if_iqdrops++;
continue;
}
m = m0;
}
+#endif
ifp->if_ipackets++;
DC_UNLOCK(sc);
@@ -2836,9 +2952,9 @@ dc_rxeof(struct dc_softc *sc)
static void
dc_txeof(struct dc_softc *sc)
{
- struct dc_desc *cur_tx = NULL;
+ struct dc_desc *cur_tx;
struct ifnet *ifp;
- int idx;
+ int idx, setup;
u_int32_t ctl, txstat;
if (sc->dc_cdata.dc_tx_cnt == 0)
@@ -2850,36 +2966,40 @@ dc_txeof(struct dc_softc *sc)
* Go through our tx list and free mbufs for those
* frames that have been transmitted.
*/
- bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, BUS_DMASYNC_POSTREAD);
- idx = sc->dc_cdata.dc_tx_cons;
- while (idx != sc->dc_cdata.dc_tx_prod) {
-
- cur_tx = &sc->dc_ldata->dc_tx_list[idx];
+ bus_dmamap_sync(sc->dc_rx_ltag, sc->dc_tx_lmap, BUS_DMASYNC_POSTREAD |
+ BUS_DMASYNC_POSTWRITE);
+ setup = 0;
+ for (idx = sc->dc_cdata.dc_tx_cons; idx != sc->dc_cdata.dc_tx_prod;
+ DC_INC(idx, DC_TX_LIST_CNT), sc->dc_cdata.dc_tx_cnt--) {
+ cur_tx = &sc->dc_ldata.dc_tx_list[idx];
txstat = le32toh(cur_tx->dc_status);
ctl = le32toh(cur_tx->dc_ctl);
if (txstat & DC_TXSTAT_OWN)
break;
- if (!(ctl & DC_TXCTL_LASTFRAG) || ctl & DC_TXCTL_SETUP) {
- if (ctl & DC_TXCTL_SETUP) {
- /*
- * Yes, the PNIC is so brain damaged
- * that it will sometimes generate a TX
- * underrun error while DMAing the RX
- * filter setup frame. If we detect this,
- * we have to send the setup frame again,
- * or else the filter won't be programmed
- * correctly.
- */
- if (DC_IS_PNIC(sc)) {
- if (txstat & DC_TXSTAT_ERRSUM)
- dc_setfilt(sc);
- }
- sc->dc_cdata.dc_tx_chain[idx] = NULL;
+ if (sc->dc_cdata.dc_tx_chain[idx] == NULL)
+ continue;
+
+ if (ctl & DC_TXCTL_SETUP) {
+ cur_tx->dc_ctl = htole32(ctl & ~DC_TXCTL_SETUP);
+ setup++;
+ bus_dmamap_sync(sc->dc_stag, sc->dc_smap,
+ BUS_DMASYNC_POSTWRITE);
+ /*
+ * Yes, the PNIC is so brain damaged
+ * that it will sometimes generate a TX
+ * underrun error while DMAing the RX
+ * filter setup frame. If we detect this,
+ * we have to send the setup frame again,
+ * or else the filter won't be programmed
+ * correctly.
+ */
+ if (DC_IS_PNIC(sc)) {
+ if (txstat & DC_TXSTAT_ERRSUM)
+ dc_setfilt(sc);
}
- sc->dc_cdata.dc_tx_cnt--;
- DC_INC(idx, DC_TX_LIST_CNT);
+ sc->dc_cdata.dc_tx_chain[idx] = NULL;
continue;
}
@@ -2919,26 +3039,22 @@ dc_txeof(struct dc_softc *sc)
ifp->if_opackets++;
ifp->if_collisions += (txstat & DC_TXSTAT_COLLCNT) >> 3;
- if (sc->dc_cdata.dc_tx_chain[idx] != NULL) {
- bus_dmamap_sync(sc->dc_mtag,
- sc->dc_cdata.dc_tx_map[idx],
- BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->dc_mtag,
- sc->dc_cdata.dc_tx_map[idx]);
- m_freem(sc->dc_cdata.dc_tx_chain[idx]);
- sc->dc_cdata.dc_tx_chain[idx] = NULL;
- }
-
- sc->dc_cdata.dc_tx_cnt--;
- DC_INC(idx, DC_TX_LIST_CNT);
+ bus_dmamap_sync(sc->dc_tx_mtag, sc->dc_cdata.dc_tx_map[idx],
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->dc_tx_mtag, sc->dc_cdata.dc_tx_map[idx]);
+ m_freem(sc->dc_cdata.dc_tx_chain[idx]);
+ sc->dc_cdata.dc_tx_chain[idx] = NULL;
}
sc->dc_cdata.dc_tx_cons = idx;
- if (DC_TX_LIST_CNT - sc->dc_cdata.dc_tx_cnt > DC_TX_LIST_RSVD)
+ if (sc->dc_cdata.dc_tx_cnt <= DC_TX_LIST_CNT - DC_TX_LIST_RSVD) {
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
-
- if (sc->dc_cdata.dc_tx_cnt == 0)
- sc->dc_wdog_timer = 0;
+ if (sc->dc_cdata.dc_tx_cnt == 0)
+ sc->dc_wdog_timer = 0;
+ }
+ if (setup > 0)
+ bus_dmamap_sync(sc->dc_tx_ltag, sc->dc_tx_lmap,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
}
static void
@@ -3226,16 +3342,11 @@ static int
dc_encap(struct dc_softc *sc, struct mbuf **m_head)
{
bus_dma_segment_t segs[DC_MAXFRAGS];
+ bus_dmamap_t map;
struct dc_desc *f;
struct mbuf *m;
int cur, defragged, error, first, frag, i, idx, nseg;
- /*
- * If there's no way we can send any packets, return now.
- */
- if (DC_TX_LIST_CNT - sc->dc_cdata.dc_tx_cnt <= DC_TX_LIST_RSVD)
- return (ENOBUFS);
-
m = NULL;
defragged = 0;
if (sc->dc_flags & DC_TX_COALESCE &&
@@ -3269,7 +3380,7 @@ dc_encap(struct dc_softc *sc, struct mbuf **m_head)
}
idx = sc->dc_cdata.dc_tx_prod;
- error = bus_dmamap_load_mbuf_sg(sc->dc_mtag,
+ error = bus_dmamap_load_mbuf_sg(sc->dc_tx_mtag,
sc->dc_cdata.dc_tx_map[idx], *m_head, segs, &nseg, 0);
if (error == EFBIG) {
if (defragged != 0 || (m = m_collapse(*m_head, M_DONTWAIT,
@@ -3279,7 +3390,7 @@ dc_encap(struct dc_softc *sc, struct mbuf **m_head)
return (defragged != 0 ? error : ENOBUFS);
}
*m_head = m;
- error = bus_dmamap_load_mbuf_sg(sc->dc_mtag,
+ error = bus_dmamap_load_mbuf_sg(sc->dc_tx_mtag,
sc->dc_cdata.dc_tx_map[idx], *m_head, segs, &nseg, 0);
if (error != 0) {
m_freem(*m_head);
@@ -3296,26 +3407,34 @@ dc_encap(struct dc_softc *sc, struct mbuf **m_head)
return (EIO);
}
+ /* Check descriptor overruns. */
+ if (sc->dc_cdata.dc_tx_cnt + nseg > DC_TX_LIST_CNT - DC_TX_LIST_RSVD) {
+ bus_dmamap_unload(sc->dc_tx_mtag, sc->dc_cdata.dc_tx_map[idx]);
+ return (ENOBUFS);
+ }
+ bus_dmamap_sync(sc->dc_tx_mtag, sc->dc_cdata.dc_tx_map[idx],
+ BUS_DMASYNC_PREWRITE);
+
first = cur = frag = sc->dc_cdata.dc_tx_prod;
for (i = 0; i < nseg; i++) {
if ((sc->dc_flags & DC_TX_ADMTEK_WAR) &&
(frag == (DC_TX_LIST_CNT - 1)) &&
(first != sc->dc_cdata.dc_tx_first)) {
- bus_dmamap_unload(sc->dc_mtag,
+ bus_dmamap_unload(sc->dc_tx_mtag,
sc->dc_cdata.dc_tx_map[first]);
m_freem(*m_head);
*m_head = NULL;
return (ENOBUFS);
}
- f = &sc->dc_ldata->dc_tx_list[frag];
+ f = &sc->dc_ldata.dc_tx_list[frag];
f->dc_ctl = htole32(DC_TXCTL_TLINK | segs[i].ds_len);
if (i == 0) {
f->dc_status = 0;
f->dc_ctl |= htole32(DC_TXCTL_FIRSTFRAG);
} else
f->dc_status = htole32(DC_TXSTAT_OWN);
- f->dc_data = htole32(segs[i].ds_addr);
+ f->dc_data = htole32(DC_ADDR_LO(segs[i].ds_addr));
cur = frag;
DC_INC(frag, DC_TX_LIST_CNT);
}
@@ -3323,23 +3442,30 @@ dc_encap(struct dc_softc *sc, struct mbuf **m_head)
sc->dc_cdata.dc_tx_prod = frag;
sc->dc_cdata.dc_tx_cnt += nseg;
sc->dc_cdata.dc_tx_chain[cur] = *m_head;
- sc->dc_ldata->dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_LASTFRAG);
+ sc->dc_ldata.dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_LASTFRAG);
if (sc->dc_flags & DC_TX_INTR_FIRSTFRAG)
- sc->dc_ldata->dc_tx_list[first].dc_ctl |=
+ sc->dc_ldata.dc_tx_list[first].dc_ctl |=
htole32(DC_TXCTL_FINT);
if (sc->dc_flags & DC_TX_INTR_ALWAYS)
- sc->dc_ldata->dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_FINT);
+ sc->dc_ldata.dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_FINT);
if (sc->dc_flags & DC_TX_USE_TX_INTR &&
++sc->dc_cdata.dc_tx_pkts >= 8) {
sc->dc_cdata.dc_tx_pkts = 0;
- sc->dc_ldata->dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_FINT);
+ sc->dc_ldata.dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_FINT);
}
- sc->dc_ldata->dc_tx_list[first].dc_status = htole32(DC_TXSTAT_OWN);
+ sc->dc_ldata.dc_tx_list[first].dc_status = htole32(DC_TXSTAT_OWN);
+
+ bus_dmamap_sync(sc->dc_tx_ltag, sc->dc_tx_lmap,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ /*
+ * Swap the last and the first dmamaps to ensure the map for
+ * this transmission is placed at the last descriptor.
+ */
+ map = sc->dc_cdata.dc_tx_map[cur];
+ sc->dc_cdata.dc_tx_map[cur] = sc->dc_cdata.dc_tx_map[first];
+ sc->dc_cdata.dc_tx_map[first] = map;
- bus_dmamap_sync(sc->dc_mtag, sc->dc_cdata.dc_tx_map[idx],
- BUS_DMASYNC_PREWRITE);
- bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap,
- BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
return (0);
}
@@ -3365,9 +3491,8 @@ static void
dc_start_locked(struct ifnet *ifp)
{
struct dc_softc *sc;
- struct mbuf *m_head = NULL;
- unsigned int queued = 0;
- int idx;
+ struct mbuf *m_head;
+ int queued;
sc = ifp->if_softc;
@@ -3377,9 +3502,16 @@ dc_start_locked(struct ifnet *ifp)
IFF_DRV_RUNNING || sc->dc_link == 0)
return;
- idx = sc->dc_cdata.dc_tx_first = sc->dc_cdata.dc_tx_prod;
+ sc->dc_cdata.dc_tx_first = sc->dc_cdata.dc_tx_prod;
- while (sc->dc_cdata.dc_tx_chain[idx] == NULL) {
+ for (queued = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd); ) {
+ /*
+ * If there's no way we can send any packets, return now.
+ */
+ if (sc->dc_cdata.dc_tx_cnt > DC_TX_LIST_CNT - DC_TX_LIST_RSVD) {
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ break;
+ }
IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
if (m_head == NULL)
break;
@@ -3391,7 +3523,6 @@ dc_start_locked(struct ifnet *ifp)
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
break;
}
- idx = sc->dc_cdata.dc_tx_prod;
queued++;
/*
@@ -3778,7 +3909,7 @@ dc_stop(struct dc_softc *sc)
DC_LOCK_ASSERT(sc);
ifp = sc->dc_ifp;
- ld = sc->dc_ldata;
+ ld = &sc->dc_ldata;
cd = &sc->dc_cdata;
callout_stop(&sc->dc_stat_ch);
@@ -3798,11 +3929,17 @@ dc_stop(struct dc_softc *sc)
*/
for (i = 0; i < DC_RX_LIST_CNT; i++) {
if (cd->dc_rx_chain[i] != NULL) {
+ bus_dmamap_sync(sc->dc_rx_mtag,
+ cd->dc_rx_map[i], BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->dc_rx_mtag,
+ cd->dc_rx_map[i]);
m_freem(cd->dc_rx_chain[i]);
cd->dc_rx_chain[i] = NULL;
}
}
- bzero(&ld->dc_rx_list, sizeof(ld->dc_rx_list));
+ bzero(ld->dc_rx_list, DC_RX_LIST_SZ);
+ bus_dmamap_sync(sc->dc_rx_ltag, sc->dc_rx_lmap,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
/*
* Free the TX list buffers.
@@ -3810,17 +3947,22 @@ dc_stop(struct dc_softc *sc)
for (i = 0; i < DC_TX_LIST_CNT; i++) {
if (cd->dc_tx_chain[i] != NULL) {
ctl = le32toh(ld->dc_tx_list[i].dc_ctl);
- if ((ctl & DC_TXCTL_SETUP) ||
- !(ctl & DC_TXCTL_LASTFRAG)) {
- cd->dc_tx_chain[i] = NULL;
- continue;
+ if (ctl & DC_TXCTL_SETUP) {
+ bus_dmamap_sync(sc->dc_stag, sc->dc_smap,
+ BUS_DMASYNC_POSTWRITE);
+ } else {
+ bus_dmamap_sync(sc->dc_tx_mtag,
+ cd->dc_tx_map[i], BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->dc_tx_mtag,
+ cd->dc_tx_map[i]);
+ m_freem(cd->dc_tx_chain[i]);
}
- bus_dmamap_unload(sc->dc_mtag, cd->dc_tx_map[i]);
- m_freem(cd->dc_tx_chain[i]);
cd->dc_tx_chain[i] = NULL;
}
}
- bzero(&ld->dc_tx_list, sizeof(ld->dc_tx_list));
+ bzero(ld->dc_tx_list, DC_TX_LIST_SZ);
+ bus_dmamap_sync(sc->dc_tx_ltag, sc->dc_tx_lmap,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
}
/*
diff --git a/sys/dev/dc/if_dcreg.h b/sys/dev/dc/if_dcreg.h
index 81c1b313ba85..1d3eaf16d987 100644
--- a/sys/dev/dc/if_dcreg.h
+++ b/sys/dev/dc/if_dcreg.h
@@ -471,11 +471,15 @@ struct dc_desc {
#define DC_INC(x, y) (x) = (x + 1) % y
+#define DC_LIST_ALIGN (sizeof(struct dc_desc))
+#define DC_RXBUF_ALIGN 4
+
/* Macros to easily get the DMA address of a descriptor. */
-#define DC_RXDESC(sc, i) (sc->dc_laddr + \
- (uintptr_t)(sc->dc_ldata->dc_rx_list + i) - (uintptr_t)sc->dc_ldata)
-#define DC_TXDESC(sc, i) (sc->dc_laddr + \
- (uintptr_t)(sc->dc_ldata->dc_tx_list + i) - (uintptr_t)sc->dc_ldata)
+#define DC_ADDR_LO(x) ((uint64_t)(x) & 0xFFFFFFFF)
+#define DC_RXDESC(sc, i) \
+ (DC_ADDR_LO(sc->dc_ldata.dc_rx_list_paddr + (sizeof(struct dc_desc) * i)))
+#define DC_TXDESC(sc, i) \
+ (DC_ADDR_LO(sc->dc_ldata.dc_tx_list_paddr + (sizeof(struct dc_desc) * i)))
#if BYTE_ORDER == BIG_ENDIAN
#define DC_SP_MAC(x) ((x) << 16)
@@ -484,10 +488,15 @@ struct dc_desc {
#endif
struct dc_list_data {
- struct dc_desc dc_rx_list[DC_RX_LIST_CNT];
- struct dc_desc dc_tx_list[DC_TX_LIST_CNT];
+ struct dc_desc *dc_rx_list;
+ bus_addr_t dc_rx_list_paddr;
+ struct dc_desc *dc_tx_list;
+ bus_addr_t dc_tx_list_paddr;
};
+#define DC_RX_LIST_SZ ((sizeof(struct dc_desc) * DC_RX_LIST_CNT))
+#define DC_TX_LIST_SZ ((sizeof(struct dc_desc) * DC_TX_LIST_CNT))
+
struct dc_chain_data {
struct mbuf *dc_rx_chain[DC_RX_LIST_CNT];
struct mbuf *dc_tx_chain[DC_TX_LIST_CNT];
@@ -722,14 +731,17 @@ struct dc_softc {
device_t dc_dev; /* device info */
bus_space_handle_t dc_bhandle; /* bus space handle */
bus_space_tag_t dc_btag; /* bus space tag */
- bus_dma_tag_t dc_ltag; /* tag for descriptor ring */
- bus_dmamap_t dc_lmap; /* map for descriptor ring */
- u_int32_t dc_laddr; /* DMA address of dc_ldata */
- bus_dma_tag_t dc_mtag; /* tag for mbufs */
+ bus_dma_tag_t dc_ptag; /* parent DMA tag */
bus_dmamap_t dc_sparemap;
+ bus_dma_tag_t dc_rx_ltag; /* tag for RX descriptors */
+ bus_dmamap_t dc_rx_lmap;
+ bus_dma_tag_t dc_tx_ltag; /* tag for TX descriptors */
+ bus_dmamap_t dc_tx_lmap;
bus_dma_tag_t dc_stag; /* tag for the setup frame */
bus_dmamap_t dc_smap; /* map for the setup frame */
- u_int32_t dc_saddr; /* DMA address of setup frame */
+ bus_addr_t dc_saddr; /* DMA address of setup frame */
+ bus_dma_tag_t dc_rx_mtag; /* tag for RX mbufs */
+ bus_dma_tag_t dc_tx_mtag; /* tag for TX mbufs */
void *dc_intrhand;
struct resource *dc_irq;
struct resource *dc_res;
@@ -749,7 +761,7 @@ struct dc_softc {
u_int32_t dc_eaddr[2];
u_int8_t *dc_srom;
struct dc_mediainfo *dc_mi;
- struct dc_list_data *dc_ldata;
+ struct dc_list_data dc_ldata;
struct dc_chain_data dc_cdata;
struct callout dc_stat_ch;
struct callout dc_wdog_ch;
@@ -796,7 +808,6 @@ struct dc_softc {
bus_space_barrier(sc->dc_btag, sc->dc_bhandle, reg, 4, flags)
#define DC_TIMEOUT 1000
-#define ETHER_ALIGN 2
/*
* General constants that are fun to know.