Convert the tx(4) driver to use the busdma API.
Special thanks to brueffer for sending me such a card so that I could do this work.
This commit is contained in:
parent
b9403c495e
commit
a4d0f4d116
@ -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,36 +411,73 @@ 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.
|
||||
*/
|
||||
@ -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 (error)
|
||||
return;
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
/* Bring the chip out of low-power mode. */
|
||||
CSR_WRITE_4(sc, GENCTL, GENCTL_SOFT_RESET);
|
||||
DELAY(500);
|
||||
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;
|
||||
|
||||
/* Workaround for Application Note 7-15. */
|
||||
for (i = 0; i < 16; i++)
|
||||
CSR_WRITE_4(sc, TEST1, TEST1_CLOCK_TEST);
|
||||
if (error)
|
||||
return;
|
||||
|
||||
/* 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(sc->dev, PCIR_SUBVEND_0, 2);
|
||||
sc->cardid = pci_read_config(sc->dev, PCIR_SUBDEV_0, 2);
|
||||
|
||||
if (sc->cardvend != SMC_VENDORID)
|
||||
device_printf(sc->dev, "unknown card vendor %04xh\n",
|
||||
sc->cardvend);
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user