summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/tx/if_tx.c437
-rw-r--r--sys/dev/tx/if_txvar.h17
2 files changed, 328 insertions, 126 deletions
diff --git a/sys/dev/tx/if_tx.c b/sys/dev/tx/if_tx.c
index 871494b..f4bf170 100644
--- a/sys/dev/tx/if_tx.c
+++ b/sys/dev/tx/if_tx.c
@@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/sockio.h>
#include <sys/mbuf.h>
-#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/queue.h>
@@ -59,8 +58,6 @@ __FBSDID("$FreeBSD$");
#include <net/if_vlan_var.h>
-#include <vm/vm.h> /* for vtophys */
-#include <vm/pmap.h> /* for vtophys */
#include <machine/bus_memio.h>
#include <machine/bus_pio.h>
#include <machine/bus.h>
@@ -90,7 +87,6 @@ MODULE_DEPEND(tx, miibus, 1, 1, 1);
static int epic_ifioctl(struct ifnet *, u_long, caddr_t);
static void epic_intr(void *);
static void epic_tx_underrun(epic_softc_t *);
-static int epic_common_attach(epic_softc_t *);
static void epic_ifstart(struct ifnet *);
static void epic_ifwatchdog(struct ifnet *);
static void epic_stats_update(epic_softc_t *);
@@ -129,6 +125,7 @@ static int epic_probe(device_t);
static int epic_attach(device_t);
static void epic_shutdown(device_t);
static int epic_detach(device_t);
+static void epic_release(epic_softc_t *);
static struct epic_type *epic_devtype(device_t);
static device_method_t epic_methods[] = {
@@ -205,6 +202,19 @@ epic_devtype(dev)
#define EPIC_RID PCIR_BASEMEM
#endif
+static void
+epic_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ u_int32_t *addr;
+
+ if (error)
+ return;
+
+ KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
+ addr = arg;
+ *addr = segs->ds_addr;
+}
+
/*
* Attach routine: map registers, allocate softc, rings and descriptors.
* Reset to known state.
@@ -263,26 +273,123 @@ epic_attach(dev)
RF_SHAREABLE | RF_ACTIVE);
if (sc->irq == NULL) {
device_printf(dev, "couldn't map interrupt\n");
- bus_release_resource(dev, EPIC_RES, EPIC_RID, sc->res);
error = ENXIO;
goto fail;
}
- /* Do OS independent part, including chip wakeup and reset. */
- error = epic_common_attach(sc);
+ /* Allocate DMA tags. */
+ error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT,
+ BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES * EPIC_MAX_FRAGS,
+ EPIC_MAX_FRAGS, MCLBYTES, 0, &sc->mtag);
if (error) {
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
- bus_release_resource(dev, EPIC_RES, EPIC_RID, sc->res);
- error = ENXIO;
+ device_printf(dev, "couldn't allocate dma tag\n");
+ goto fail;
+ }
+
+ error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT,
+ BUS_SPACE_MAXADDR, NULL, NULL,
+ sizeof(struct epic_rx_desc) * RX_RING_SIZE,
+ 1, sizeof(struct epic_rx_desc) * RX_RING_SIZE, 0, &sc->rtag);
+ if (error) {
+ device_printf(dev, "couldn't allocate dma tag\n");
+ goto fail;
+ }
+
+ error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT,
+ BUS_SPACE_MAXADDR, NULL, NULL,
+ sizeof(struct epic_tx_desc) * TX_RING_SIZE,
+ 1, sizeof(struct epic_tx_desc) * TX_RING_SIZE, 0, &sc->ttag);
+ if (error) {
+ device_printf(dev, "couldn't allocate dma tag\n");
goto fail;
}
+ error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT,
+ BUS_SPACE_MAXADDR, NULL, NULL,
+ sizeof(struct epic_frag_list) * TX_RING_SIZE,
+ 1, sizeof(struct epic_frag_list) * TX_RING_SIZE, 0, &sc->ftag);
+ if (error) {
+ device_printf(dev, "couldn't allocate dma tag\n");
+ goto fail;
+ }
+
+ /* Allocate DMA safe memory and get the DMA addresses. */
+ error = bus_dmamem_alloc(sc->ftag, (void **)&sc->tx_flist,
+ BUS_DMA_NOWAIT, &sc->fmap);
+ if (error) {
+ device_printf(dev, "couldn't allocate dma memory\n");
+ goto fail;
+ }
+ bzero(sc->tx_flist, sizeof(struct epic_frag_list) * TX_RING_SIZE);
+ error = bus_dmamap_load(sc->ftag, sc->fmap, sc->tx_flist,
+ sizeof(struct epic_frag_list) * TX_RING_SIZE, epic_dma_map_addr,
+ &sc->frag_addr, 0);
+ if (error) {
+ device_printf(dev, "couldn't map dma memory\n");
+ goto fail;
+ }
+ error = bus_dmamem_alloc(sc->ttag, (void **)&sc->tx_desc,
+ BUS_DMA_NOWAIT, &sc->tmap);
+ if (error) {
+ device_printf(dev, "couldn't allocate dma memory\n");
+ goto fail;
+ }
+ bzero(sc->tx_desc, sizeof(struct epic_tx_desc) * TX_RING_SIZE);
+ error = bus_dmamap_load(sc->ttag, sc->tmap, sc->tx_desc,
+ sizeof(struct epic_tx_desc) * TX_RING_SIZE, epic_dma_map_addr,
+ &sc->tx_addr, 0);
+ if (error) {
+ device_printf(dev, "couldn't map dma memory\n");
+ goto fail;
+ }
+ error = bus_dmamem_alloc(sc->rtag, (void **)&sc->rx_desc,
+ BUS_DMA_NOWAIT, &sc->rmap);
+ if (error) {
+ device_printf(dev, "couldn't allocate dma memory\n");
+ goto fail;
+ }
+ bzero(sc->rx_desc, sizeof(struct epic_rx_desc) * RX_RING_SIZE);
+ error = bus_dmamap_load(sc->rtag, sc->rmap, sc->rx_desc,
+ sizeof(struct epic_rx_desc) * RX_RING_SIZE, epic_dma_map_addr,
+ &sc->rx_addr, 0);
+ if (error) {
+ device_printf(dev, "couldn't map dma memory\n");
+ goto fail;
+ }
+
+ /* Bring the chip out of low-power mode. */
+ CSR_WRITE_4(sc, GENCTL, GENCTL_SOFT_RESET);
+ DELAY(500);
+
+ /* Workaround for Application Note 7-15. */
+ for (i = 0; i < 16; i++)
+ CSR_WRITE_4(sc, TEST1, TEST1_CLOCK_TEST);
+
+ /* Read MAC address from EEPROM. */
+ for (i = 0; i < ETHER_ADDR_LEN / sizeof(u_int16_t); i++)
+ ((u_int16_t *)sc->sc_macaddr)[i] = epic_read_eeprom(sc,i);
+
+ /* Set Non-Volatile Control Register from EEPROM. */
+ CSR_WRITE_4(sc, NVCTL, epic_read_eeprom(sc, EEPROM_NVCTL) & 0x1F);
+
+ /* Set defaults. */
+ sc->tx_threshold = TRANSMIT_THRESHOLD;
+ sc->txcon = TXCON_DEFAULT;
+ sc->miicfg = MIICFG_SMI_ENABLE;
+ sc->phyid = EPIC_UNKN_PHY;
+ sc->serinst = -1;
+
+ /* Fetch card id. */
+ sc->cardvend = pci_read_config(dev, PCIR_SUBVEND_0, 2);
+ sc->cardid = pci_read_config(dev, PCIR_SUBDEV_0, 2);
+
+ if (sc->cardvend != SMC_VENDORID)
+ device_printf(dev, "unknown card vendor %04xh\n", sc->cardvend);
+
/* Do ifmedia setup. */
if (mii_phy_probe(dev, &sc->miibus,
epic_ifmedia_upd, epic_ifmedia_sts)) {
device_printf(dev, "ERROR! MII without any PHY!?\n");
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
- bus_release_resource(dev, EPIC_RES, EPIC_RID, sc->res);
error = ENXIO;
goto fail;
}
@@ -304,37 +411,74 @@ epic_attach(dev)
}
printf("\n");
- /* Attach to OS's managers. */
- ether_ifattach(ifp, sc->sc_macaddr);
- ifp->if_hdrlen = sizeof(struct ether_vlan_header);
- ifp->if_capabilities |= IFCAP_VLAN_MTU;
- callout_handle_init(&sc->stat_ch);
-
/* Initialize rings. */
if (epic_init_rings(sc)) {
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
- bus_release_resource(dev, EPIC_RES, EPIC_RID, sc->res);
device_printf(dev, "failed to init rings\n");
error = ENXIO;
goto fail;
}
+ ifp->if_hdrlen = sizeof(struct ether_vlan_header);
+ ifp->if_capabilities |= IFCAP_VLAN_MTU;
+ callout_handle_init(&sc->stat_ch);
+
/* Activate our interrupt handler. */
error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET,
epic_intr, sc, &sc->sc_ih);
if (error) {
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
- bus_release_resource(dev, EPIC_RES, EPIC_RID, sc->res);
device_printf(dev, "couldn't set up irq\n");
goto fail;
}
+ /* Attach to OS's managers. */
+ ether_ifattach(ifp, sc->sc_macaddr);
+
+ splx(s);
+ return (0);
fail:
+ epic_release(sc);
splx(s);
return (error);
}
/*
+ * Free any resources allocated by the driver.
+ */
+static void
+epic_release(epic_softc_t *sc)
+{
+
+ if (sc->irq)
+ bus_release_resource(sc->dev, SYS_RES_IRQ, 0, sc->irq);
+ if (sc->res)
+ bus_release_resource(sc->dev, EPIC_RES, EPIC_RID, sc->res);
+ epic_free_rings(sc);
+ if (sc->tx_flist) {
+ bus_dmamap_unload(sc->ftag, sc->fmap);
+ bus_dmamem_free(sc->ftag, sc->tx_flist, sc->fmap);
+ bus_dmamap_destroy(sc->ftag, sc->fmap);
+ }
+ if (sc->tx_desc) {
+ bus_dmamap_unload(sc->ttag, sc->tmap);
+ bus_dmamem_free(sc->ttag, sc->tx_desc, sc->tmap);
+ bus_dmamap_destroy(sc->ttag, sc->tmap);
+ }
+ if (sc->rx_desc) {
+ bus_dmamap_unload(sc->rtag, sc->rmap);
+ bus_dmamem_free(sc->rtag, sc->rx_desc, sc->rmap);
+ bus_dmamap_destroy(sc->rtag, sc->rmap);
+ }
+ if (sc->mtag)
+ bus_dma_tag_destroy(sc->mtag);
+ if (sc->ftag)
+ bus_dma_tag_destroy(sc->ftag);
+ if (sc->ttag)
+ bus_dma_tag_destroy(sc->ttag);
+ if (sc->rtag)
+ bus_dma_tag_destroy(sc->rtag);
+}
+
+/*
* Detach driver and free resources.
*/
static int
@@ -358,14 +502,7 @@ epic_detach(dev)
device_delete_child(dev, sc->miibus);
bus_teardown_intr(dev, sc->irq, sc->sc_ih);
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
- bus_release_resource(dev, EPIC_RES, EPIC_RID, sc->res);
-
- epic_free_rings(sc);
- free(sc->tx_flist, M_DEVBUF);
- free(sc->tx_desc, M_DEVBUF);
- free(sc->rx_desc, M_DEVBUF);
-
+ epic_release(sc);
splx(s);
return (0);
}
@@ -467,65 +604,39 @@ epic_ifioctl(ifp, command, data)
return (error);
}
-/*
- * OS-independed part of attach process. allocate memory for descriptors
- * and frag lists, wake up chip, read MAC address and PHY identyfier.
- */
-static int
-epic_common_attach(sc)
- epic_softc_t *sc;
+static void
+epic_dma_map_txbuf(void *arg, bus_dma_segment_t *segs, int nseg,
+ bus_size_t mapsize, int error)
{
+ struct epic_frag_list *flist;
int i;
- sc->tx_flist = malloc(sizeof(struct epic_frag_list) * TX_RING_SIZE,
- M_DEVBUF, M_NOWAIT | M_ZERO);
- sc->tx_desc = malloc(sizeof(struct epic_tx_desc) * TX_RING_SIZE,
- M_DEVBUF, M_NOWAIT | M_ZERO);
- sc->rx_desc = malloc(sizeof(struct epic_rx_desc) * RX_RING_SIZE,
- M_DEVBUF, M_NOWAIT | M_ZERO);
-
- if (sc->tx_flist == NULL || sc->tx_desc == NULL || sc->rx_desc == NULL){
- device_printf(sc->dev, "failed to malloc memory\n");
- if (sc->tx_flist)
- free(sc->tx_flist, M_DEVBUF);
- if (sc->tx_desc)
- free(sc->tx_desc, M_DEVBUF);
- if (sc->rx_desc)
- free(sc->rx_desc, M_DEVBUF);
- return (ENOMEM);
- }
-
- /* Bring the chip out of low-power mode. */
- CSR_WRITE_4(sc, GENCTL, GENCTL_SOFT_RESET);
- DELAY(500);
-
- /* Workaround for Application Note 7-15. */
- for (i = 0; i < 16; i++)
- CSR_WRITE_4(sc, TEST1, TEST1_CLOCK_TEST);
-
- /* Read MAC address from EEPROM. */
- for (i = 0; i < ETHER_ADDR_LEN / sizeof(u_int16_t); i++)
- ((u_int16_t *)sc->sc_macaddr)[i] = epic_read_eeprom(sc,i);
-
- /* Set Non-Volatile Control Register from EEPROM. */
- CSR_WRITE_4(sc, NVCTL, epic_read_eeprom(sc, EEPROM_NVCTL) & 0x1F);
+ if (error)
+ return;
- /* Set defaults. */
- sc->tx_threshold = TRANSMIT_THRESHOLD;
- sc->txcon = TXCON_DEFAULT;
- sc->miicfg = MIICFG_SMI_ENABLE;
- sc->phyid = EPIC_UNKN_PHY;
- sc->serinst = -1;
+ KASSERT(nseg <= EPIC_MAX_FRAGS, ("too many DMA segments"));
+ flist = arg;
+ /* Fill fragments list. */
+ for (i = 0; i < nseg; i++) {
+ KASSERT(segs[i].ds_len <= MCLBYTES, ("segment size too large"));
+ flist->frag[i].fraglen = segs[i].ds_len;
+ flist->frag[i].fragaddr = segs[i].ds_addr;
+ }
+ flist->numfrags = nseg;
+}
- /* Fetch card id. */
- sc->cardvend = pci_read_config(sc->dev, PCIR_SUBVEND_0, 2);
- sc->cardid = pci_read_config(sc->dev, PCIR_SUBDEV_0, 2);
+static void
+epic_dma_map_rxbuf(void *arg, bus_dma_segment_t *segs, int nseg,
+ bus_size_t mapsize, int error)
+{
+ struct epic_rx_desc *desc;
- if (sc->cardvend != SMC_VENDORID)
- device_printf(sc->dev, "unknown card vendor %04xh\n",
- sc->cardvend);
+ if (error)
+ return;
- return (0);
+ KASSERT(nseg == 1, ("too many DMA segments"));
+ desc = arg;
+ desc->bufaddr = segs->ds_addr;
}
/*
@@ -542,7 +653,7 @@ epic_ifstart(ifp)
struct epic_tx_desc *desc;
struct epic_frag_list *flist;
struct mbuf *m0, *m;
- int i;
+ int error;
while (sc->pending_txs < TX_RING_SIZE) {
buf = sc->tx_buffer + sc->cur_tx;
@@ -556,44 +667,49 @@ epic_ifstart(ifp)
if (m0 == NULL)
return;
- /* Fill fragments list. */
- for (m = m0, i = 0; (m != NULL) && (i < EPIC_MAX_FRAGS);
- m = m->m_next, i++) {
- flist->frag[i].fraglen = m->m_len;
- flist->frag[i].fragaddr = vtophys(mtod(m, caddr_t));
+ error = bus_dmamap_load_mbuf(sc->mtag, buf->map, m0,
+ epic_dma_map_txbuf, flist, 0);
+
+ if (error && error != EFBIG) {
+ m_freem(m0);
+ ifp->if_oerrors++;
+ continue;
}
- flist->numfrags = i;
/*
* If packet was more than EPIC_MAX_FRAGS parts,
* recopy packet to a newly allocated mbuf cluster.
*/
- if (m != NULL) {
- m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (error) {
+ m = m_defrag(m0, M_DONTWAIT);
if (m == NULL) {
m_freem(m0);
ifp->if_oerrors++;
continue;
}
-
- m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, caddr_t));
- flist->frag[0].fraglen =
- m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len;
- m->m_pkthdr.rcvif = ifp;
-
- flist->numfrags = 1;
- flist->frag[0].fragaddr = vtophys(mtod(m, caddr_t));
m_freem(m0);
m0 = m;
+
+ error = bus_dmamap_load_mbuf(sc->mtag, buf->map, m,
+ epic_dma_map_txbuf, flist, 0);
+ if (error) {
+ m_freem(m);
+ ifp->if_oerrors++;
+ continue;
+ }
}
+ bus_dmamap_sync(sc->mtag, buf->map, BUS_DMASYNC_PREWRITE);
buf->mbuf = m0;
sc->pending_txs++;
sc->cur_tx = (sc->cur_tx + 1) & TX_RING_MASK;
desc->control = 0x01;
desc->txlength =
- max(m0->m_pkthdr.len,ETHER_MIN_LEN-ETHER_CRC_LEN);
+ max(m0->m_pkthdr.len, ETHER_MIN_LEN - ETHER_CRC_LEN);
desc->status = 0x8000;
+ bus_dmamap_sync(sc->ttag, sc->tmap,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(sc->ftag, sc->fmap, BUS_DMASYNC_PREWRITE);
CSR_WRITE_4(sc, COMMAND, COMMAND_TXQUEUED);
/* Set watchdog timer. */
@@ -617,7 +733,10 @@ epic_rx_done(sc)
struct epic_rx_buffer *buf;
struct epic_rx_desc *desc;
struct mbuf *m;
+ bus_dmamap_t map;
+ int error;
+ bus_dmamap_sync(sc->rtag, sc->rmap, BUS_DMASYNC_POSTREAD);
while ((sc->rx_desc[sc->cur_rx].status & 0x8000) == 0) {
buf = sc->rx_buffer + sc->cur_rx;
desc = sc->rx_desc + sc->cur_rx;
@@ -637,6 +756,7 @@ epic_rx_done(sc)
}
/* Save packet length and mbuf contained packet. */
+ bus_dmamap_sync(sc->mtag, buf->map, BUS_DMASYNC_POSTREAD);
len = desc->rxlength - ETHER_CRC_LEN;
m = buf->mbuf;
@@ -652,8 +772,21 @@ epic_rx_done(sc)
m_adj(buf->mbuf, ETHER_ALIGN);
/* Point to new mbuf, and give descriptor to chip. */
- desc->bufaddr = vtophys(mtod(buf->mbuf, caddr_t));
+ error = bus_dmamap_load_mbuf(sc->mtag, sc->sparemap, buf->mbuf,
+ epic_dma_map_rxbuf, desc, 0);
+ if (error) {
+ buf->mbuf = m;
+ desc->status = 0x8000;
+ ifp->if_ierrors++;
+ continue;
+ }
+
desc->status = 0x8000;
+ bus_dmamap_unload(sc->mtag, buf->map);
+ map = buf->map;
+ buf->map = sc->sparemap;
+ sc->sparemap = map;
+ bus_dmamap_sync(sc->mtag, buf->map, BUS_DMASYNC_PREREAD);
/* First mbuf in packet holds the ethernet and packet headers */
m->m_pkthdr.rcvif = ifp;
@@ -665,6 +798,8 @@ epic_rx_done(sc)
/* Successfuly received frame */
ifp->if_ipackets++;
}
+ bus_dmamap_sync(sc->rtag, sc->rmap,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
}
/*
@@ -681,6 +816,7 @@ epic_tx_done(sc)
struct epic_tx_desc *desc;
u_int16_t status;
+ bus_dmamap_sync(sc->ttag, sc->tmap, BUS_DMASYNC_POSTREAD);
while (sc->pending_txs > 0) {
buf = sc->tx_buffer + sc->dirty_tx;
desc = sc->tx_desc + sc->dirty_tx;
@@ -696,6 +832,8 @@ epic_tx_done(sc)
/* Packet is transmitted. Switch to next and free mbuf. */
sc->pending_txs--;
sc->dirty_tx = (sc->dirty_tx + 1) & TX_RING_MASK;
+ bus_dmamap_sync(sc->mtag, buf->map, BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->mtag, buf->map);
m_freem(buf->mbuf);
buf->mbuf = NULL;
@@ -714,6 +852,8 @@ epic_tx_done(sc)
if (sc->pending_txs < TX_RING_SIZE)
sc->sc_if.if_flags &= ~IFF_OACTIVE;
+ bus_dmamap_sync(sc->ttag, sc->tmap,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
}
/*
@@ -840,7 +980,7 @@ epic_ifwatchdog(ifp)
/* If not successful. */
if (sc->pending_txs > 0) {
- ifp->if_oerrors+=sc->pending_txs;
+ ifp->if_oerrors += sc->pending_txs;
/* Reinitialize board. */
device_printf(sc->dev, "reinitialization\n");
@@ -1113,7 +1253,7 @@ epic_miibus_mediainit(dev)
}
/*
- * Reset chip, allocate rings, and update media.
+ * Reset chip and update media.
*/
static void
epic_init(xsc)
@@ -1149,8 +1289,8 @@ epic_init(xsc)
CSR_WRITE_4(sc, TEST1, TEST1_CLOCK_TEST);
/* Give rings to EPIC */
- CSR_WRITE_4(sc, PRCDAR, vtophys(sc->rx_desc));
- CSR_WRITE_4(sc, PTCDAR, vtophys(sc->tx_desc));
+ CSR_WRITE_4(sc, PRCDAR, sc->rx_addr);
+ CSR_WRITE_4(sc, PTCDAR, sc->tx_addr);
/* Put node address to EPIC. */
CSR_WRITE_4(sc, LAN0, ((u_int16_t *)sc->sc_macaddr)[0]);
@@ -1324,9 +1464,8 @@ epic_start_activity(sc)
{
/* Start rx process. */
- CSR_WRITE_4(sc, COMMAND,
- COMMAND_RXQUEUED | COMMAND_START_RX |
- (sc->pending_txs ? COMMAND_TXQUEUED : 0));
+ CSR_WRITE_4(sc, COMMAND, COMMAND_RXQUEUED | COMMAND_START_RX |
+ (sc->pending_txs ? COMMAND_TXQUEUED : 0));
}
/*
@@ -1387,7 +1526,7 @@ epic_queue_last_packet(sc)
struct epic_frag_list *flist;
struct epic_tx_buffer *buf;
struct mbuf *m0;
- int i;
+ int error, i;
device_printf(sc->dev, "queue last packet\n");
@@ -1403,24 +1542,30 @@ epic_queue_last_packet(sc)
return (ENOBUFS);
/* Prepare mbuf. */
- m0->m_len = min(MHLEN, ETHER_MIN_LEN-ETHER_CRC_LEN);
- flist->frag[0].fraglen = m0->m_len;
+ m0->m_len = min(MHLEN, ETHER_MIN_LEN - ETHER_CRC_LEN);
m0->m_pkthdr.len = m0->m_len;
m0->m_pkthdr.rcvif = &sc->sc_if;
bzero(mtod(m0, caddr_t), m0->m_len);
/* Fill fragments list. */
- flist->frag[0].fraglen = m0->m_len;
- flist->frag[0].fragaddr = vtophys(mtod(m0, caddr_t));
- flist->numfrags = 1;
+ error = bus_dmamap_load_mbuf(sc->mtag, buf->map, m0,
+ epic_dma_map_txbuf, flist, 0);
+ if (error) {
+ m_freem(m0);
+ return (error);
+ }
+ bus_dmamap_sync(sc->mtag, buf->map, BUS_DMASYNC_PREWRITE);
/* Fill in descriptor. */
buf->mbuf = m0;
sc->pending_txs++;
sc->cur_tx = (sc->cur_tx + 1) & TX_RING_MASK;
desc->control = 0x01;
- desc->txlength = max(m0->m_pkthdr.len,ETHER_MIN_LEN-ETHER_CRC_LEN);
+ desc->txlength = max(m0->m_pkthdr.len, ETHER_MIN_LEN - ETHER_CRC_LEN);
desc->status = 0x8000;
+ bus_dmamap_sync(sc->ttag, sc->tmap,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(sc->ftag, sc->fmap, BUS_DMASYNC_PREWRITE);
/* Launch transmission. */
CSR_WRITE_4(sc, COMMAND, COMMAND_STOP_TDMA | COMMAND_TXQUEUED);
@@ -1492,11 +1637,17 @@ epic_free_rings(sc)
desc->buflength = 0;
desc->bufaddr = 0;
- if (buf->mbuf)
+ if (buf->mbuf) {
+ bus_dmamap_unload(sc->mtag, buf->map);
+ bus_dmamap_destroy(sc->mtag, buf->map);
m_freem(buf->mbuf);
+ }
buf->mbuf = NULL;
}
+ if (sc->sparemap != NULL)
+ bus_dmamap_destroy(sc->mtag, sc->sparemap);
+
for (i = 0; i < TX_RING_SIZE; i++) {
struct epic_tx_buffer *buf = sc->tx_buffer + i;
struct epic_tx_desc *desc = sc->tx_desc + i;
@@ -1505,8 +1656,11 @@ epic_free_rings(sc)
desc->buflength = 0;
desc->bufaddr = 0;
- if (buf->mbuf)
+ if (buf->mbuf) {
+ bus_dmamap_unload(sc->mtag, buf->map);
+ bus_dmamap_destroy(sc->mtag, buf->map);
m_freem(buf->mbuf);
+ }
buf->mbuf = NULL;
}
}
@@ -1520,16 +1674,18 @@ static int
epic_init_rings(sc)
epic_softc_t *sc;
{
- int i;
+ int error, i;
sc->cur_rx = sc->cur_tx = sc->dirty_tx = sc->pending_txs = 0;
+ /* Initialize the RX descriptor ring. */
for (i = 0; i < RX_RING_SIZE; i++) {
struct epic_rx_buffer *buf = sc->rx_buffer + i;
struct epic_rx_desc *desc = sc->rx_desc + i;
desc->status = 0; /* Owned by driver */
- desc->next = vtophys(sc->rx_desc + ((i+1) & RX_RING_MASK));
+ desc->next = sc->rx_addr +
+ ((i + 1) & RX_RING_MASK) * sizeof(struct epic_rx_desc);
if ((desc->next & 3) ||
((desc->next & PAGE_MASK) + sizeof *desc) > PAGE_SIZE) {
@@ -1538,24 +1694,47 @@ epic_init_rings(sc)
}
buf->mbuf = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
- if(buf->mbuf == NULL) {
+ if (buf->mbuf == NULL) {
epic_free_rings(sc);
return (ENOBUFS);
}
buf->mbuf->m_len = buf->mbuf->m_pkthdr.len = MCLBYTES;
m_adj(buf->mbuf, ETHER_ALIGN);
- desc->bufaddr = vtophys( mtod(buf->mbuf,caddr_t) );
- desc->buflength = buf->mbuf->m_len;/* Max RX buffer length */
+ error = bus_dmamap_create(sc->mtag, 0, &buf->map);
+ if (error) {
+ epic_free_rings(sc);
+ return (error);
+ }
+ error = bus_dmamap_load_mbuf(sc->mtag, buf->map, buf->mbuf,
+ epic_dma_map_rxbuf, desc, 0);
+ if (error) {
+ epic_free_rings(sc);
+ return (error);
+ }
+ bus_dmamap_sync(sc->mtag, buf->map, BUS_DMASYNC_PREREAD);
+
+ desc->buflength = buf->mbuf->m_len; /* Max RX buffer length */
desc->status = 0x8000; /* Set owner bit to NIC */
}
+ bus_dmamap_sync(sc->rtag, sc->rmap,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ /* Create the spare DMA map. */
+ error = bus_dmamap_create(sc->mtag, 0, &sc->sparemap);
+ if (error) {
+ epic_free_rings(sc);
+ return (error);
+ }
+ /* Initialize the TX descriptor ring. */
for (i = 0; i < TX_RING_SIZE; i++) {
struct epic_tx_buffer *buf = sc->tx_buffer + i;
struct epic_tx_desc *desc = sc->tx_desc + i;
desc->status = 0;
- desc->next = vtophys(sc->tx_desc + ((i+1) & TX_RING_MASK));
+ desc->next = sc->tx_addr +
+ ((i + 1) & TX_RING_MASK) * sizeof(struct epic_tx_desc);
if ((desc->next & 3) ||
((desc->next & PAGE_MASK) + sizeof *desc) > PAGE_SIZE) {
@@ -1564,7 +1743,8 @@ epic_init_rings(sc)
}
buf->mbuf = NULL;
- desc->bufaddr = vtophys(sc->tx_flist + i);
+ desc->bufaddr = sc->frag_addr +
+ i * sizeof(struct epic_frag_list);
if ((desc->bufaddr & 3) ||
((desc->bufaddr & PAGE_MASK) +
@@ -1572,7 +1752,16 @@ epic_init_rings(sc)
epic_free_rings(sc);
return (EFAULT);
}
+
+ error = bus_dmamap_create(sc->mtag, 0, &buf->map);
+ if (error) {
+ epic_free_rings(sc);
+ return (error);
+ }
}
+ bus_dmamap_sync(sc->ttag, sc->tmap,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(sc->ftag, sc->fmap, BUS_DMASYNC_PREWRITE);
return (0);
}
diff --git a/sys/dev/tx/if_txvar.h b/sys/dev/tx/if_txvar.h
index 101b9e8..1277244 100644
--- a/sys/dev/tx/if_txvar.h
+++ b/sys/dev/tx/if_txvar.h
@@ -52,11 +52,13 @@
/* This is driver's structure to define EPIC descriptors */
struct epic_rx_buffer {
- struct mbuf * mbuf; /* mbuf receiving packet */
+ struct mbuf *mbuf; /* mbuf receiving packet */
+ bus_dmamap_t map; /* DMA map */
};
struct epic_tx_buffer {
- struct mbuf * mbuf; /* mbuf contained packet */
+ struct mbuf *mbuf; /* mbuf contained packet */
+ bus_dmamap_t map; /* DMA map */
};
/* PHY, known by tx driver */
@@ -80,6 +82,14 @@ typedef struct {
void *sc_ih;
bus_space_tag_t sc_st;
bus_space_handle_t sc_sh;
+ bus_dma_tag_t mtag;
+ bus_dma_tag_t rtag;
+ bus_dmamap_t rmap;
+ bus_dma_tag_t ttag;
+ bus_dmamap_t tmap;
+ bus_dma_tag_t ftag;
+ bus_dmamap_t fmap;
+ bus_dmamap_t sparemap;
struct epic_rx_buffer rx_buffer[RX_RING_SIZE];
struct epic_tx_buffer tx_buffer[TX_RING_SIZE];
@@ -89,6 +99,9 @@ typedef struct {
struct epic_rx_desc *rx_desc;
struct epic_tx_desc *tx_desc;
struct epic_frag_list *tx_flist;
+ u_int32_t rx_addr;
+ u_int32_t tx_addr;
+ u_int32_t frag_addr;
u_int32_t flags;
u_int32_t tx_threshold;
u_int32_t txcon;
OpenPOWER on IntegriCloud