Pull in numerous fixes from myself and cognet. With these fixes the

KB9202 eval board is finally stable with a nfs root.
This commit is contained in:
imp 2006-04-06 04:30:23 +00:00
parent 9a23a843f0
commit b8ec0fd91c

View File

@ -86,13 +86,14 @@ struct ate_softc
struct callout tick_ch; /* Tick callout */ struct callout tick_ch; /* Tick callout */
bus_dma_tag_t mtag; /* bus dma tag for mbufs */ bus_dma_tag_t mtag; /* bus dma tag for mbufs */
bus_dmamap_t tx_map[ATE_MAX_TX_BUFFERS]; bus_dmamap_t tx_map[ATE_MAX_TX_BUFFERS];
struct mbuf *sent_mbuf[ATE_MAX_TX_BUFFERS]; /* Sent mbufs */
bus_dma_tag_t rxtag; bus_dma_tag_t rxtag;
bus_dmamap_t rx_map[ATE_MAX_RX_BUFFERS]; bus_dmamap_t rx_map[ATE_MAX_RX_BUFFERS];
void *rx_buf[ATE_MAX_RX_BUFFERS]; /* RX buffer space */
int rx_buf_ptr;
bus_dma_tag_t rx_desc_tag; bus_dma_tag_t rx_desc_tag;
bus_dmamap_t rx_desc_map; bus_dmamap_t rx_desc_map;
int txcur; /* current tx map pointer */ int txcur; /* current tx map pointer */
struct mbuf *sent_mbuf[ATE_MAX_TX_BUFFERS]; /* Sent mbufs */
struct mbuf *rx_mbuf[ATE_MAX_RX_BUFFERS]; /* RX mbufs */
bus_addr_t rx_desc_phys; bus_addr_t rx_desc_phys;
eth_rx_desc_t *rx_descs; eth_rx_desc_t *rx_descs;
struct ifmib_iso_8802_3 mibdata; /* stuff for network mgmt */ struct ifmib_iso_8802_3 mibdata; /* stuff for network mgmt */
@ -241,6 +242,30 @@ ate_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
sc->rx_desc_phys = segs[0].ds_addr; sc->rx_desc_phys = segs[0].ds_addr;
} }
static void
ate_load_rx_buf(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
{
struct ate_softc *sc;
int i;
if (error != 0)
return;
sc = (struct ate_softc *)arg;
i = sc->rx_buf_ptr;
/*
* For the last buffer, set the wrap bit so the controller
* restarts from the first descriptor.
*/
if (i == ATE_MAX_RX_BUFFERS - 1)
sc->rx_descs[i].addr = segs[0].ds_addr | ETH_WRAP_BIT;
else
sc->rx_descs[i].addr = segs[0].ds_addr;
sc->rx_descs[i].status = 0;
/* Flush the memory in the mbuf */
bus_dmamap_sync(sc->rxtag, sc->rx_map[i], BUS_DMASYNC_PREREAD);
}
/* /*
* Compute the multicast filter for this device using the standard * Compute the multicast filter for this device using the standard
* algorithm. I wonder why this isn't in ether somewhere as a lot * algorithm. I wonder why this isn't in ether somewhere as a lot
@ -275,10 +300,8 @@ ate_setmcast(struct ate_softc *sc)
* advantage of that. Locks here are to avoid LOR with the * advantage of that. Locks here are to avoid LOR with the
* IF_ADDR_LOCK, but might not be strictly necessary. * IF_ADDR_LOCK, but might not be strictly necessary.
*/ */
ATE_LOCK(sc);
WR4(sc, ETH_HSL, mcaf[0]); WR4(sc, ETH_HSL, mcaf[0]);
WR4(sc, ETH_HSH, mcaf[1]); WR4(sc, ETH_HSH, mcaf[1]);
ATE_UNLOCK(sc);
} }
static int static int
@ -348,27 +371,15 @@ ate_activate(device_t dev)
goto errout; goto errout;
/* XXX TODO(5) Put this in ateinit_locked? */ /* XXX TODO(5) Put this in ateinit_locked? */
for (i = 0; i < ATE_MAX_RX_BUFFERS; i++) { for (i = 0; i < ATE_MAX_RX_BUFFERS; i++) {
bus_dma_segment_t seg; sc->rx_buf_ptr = i;
int nsegs; if (bus_dmamem_alloc(sc->rxtag, (void **)&sc->rx_buf[i],
BUS_DMA_NOWAIT, &sc->rx_map[i]) != 0)
sc->rx_mbuf[i] = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR); goto errout;
sc->rx_mbuf[i]->m_len = sc->rx_mbuf[i]->m_pkthdr.len = if (bus_dmamap_load(sc->rxtag, sc->rx_map[i], sc->rx_buf[i],
MCLBYTES; MCLBYTES, ate_load_rx_buf, sc, 0) != 0)
if (bus_dmamap_load_mbuf_sg(sc->rxtag, sc->rx_map[i],
sc->rx_mbuf[i], &seg, &nsegs, 0) != 0)
goto errout; goto errout;
/*
* For the last buffer, set the wrap bit so the controller
* restarts from the first descriptor.
*/
if (i == ATE_MAX_RX_BUFFERS - 1)
sc->rx_descs[i].addr = seg.ds_addr | ETH_WRAP_BIT;
else
sc->rx_descs[i].addr = seg.ds_addr;
sc->rx_descs[i].status = 0;
/* Flush the memory in the mbuf */
bus_dmamap_sync(sc->rxtag, sc->rx_map[i], BUS_DMASYNC_PREREAD);
} }
sc->rx_buf_ptr = 0;
/* Flush the memory for the EMAC rx descriptor */ /* Flush the memory for the EMAC rx descriptor */
bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, BUS_DMASYNC_PREWRITE); bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, BUS_DMASYNC_PREWRITE);
/* Write the descriptor queue address. */ /* Write the descriptor queue address. */
@ -577,11 +588,9 @@ ate_intr(void *xsc)
struct ate_softc *sc = xsc; struct ate_softc *sc = xsc;
int status; int status;
int i; int i;
struct mbuf *mb, *tmp_mbuf; void *bp;
bus_dma_segment_t seg; struct mbuf *mb;
int rx_stat; uint32_t rx_stat;
int nsegs;
status = RD4(sc, ETH_ISR); status = RD4(sc, ETH_ISR);
if (status == 0) if (status == 0)
@ -589,92 +598,37 @@ ate_intr(void *xsc)
if (status & ETH_ISR_RCOM) { if (status & ETH_ISR_RCOM) {
bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map,
BUS_DMASYNC_POSTREAD); BUS_DMASYNC_POSTREAD);
for (i = 0; i < ATE_MAX_RX_BUFFERS; i++) { while (sc->rx_descs[sc->rx_buf_ptr].addr & ETH_CPU_OWNER) {
if ((sc->rx_descs[i].addr & ETH_CPU_OWNER) == 0) i = sc->rx_buf_ptr;
continue; sc->rx_buf_ptr = (i + 1) % ATE_MAX_RX_BUFFERS;
bp = sc->rx_buf[i];
mb = sc->rx_mbuf[i];
rx_stat = sc->rx_descs[i].status; rx_stat = sc->rx_descs[i].status;
if ((rx_stat & ETH_LEN_MASK) == 0) { if ((rx_stat & ETH_LEN_MASK) == 0) {
printf("ignoring bogus 0 len packet\n"); printf("ignoring bogus 0 len packet\n");
bus_dmamap_load_mbuf_sg(sc->rxtag, sc->rx_descs[i].addr &= ~ETH_CPU_OWNER;
sc->rx_map[i], sc->rx_mbuf[i],
&seg, &nsegs, 0);
sc->rx_descs[i].status = 0;
sc->rx_descs[i].addr = seg.ds_addr;
if (i == ATE_MAX_RX_BUFFERS - 1)
sc->rx_descs[i].addr |=
ETH_WRAP_BIT;
/* Flush memory for mbuf */
bus_dmamap_sync(sc->rxtag, sc->rx_map[i],
BUS_DMASYNC_PREREAD);
/* Flush rx dtor table rx_descs */
bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map,
BUS_DMASYNC_PREWRITE); BUS_DMASYNC_PREWRITE);
continue; continue;
} }
/* Flush memory for mbuf so we don't get stale bytes */ /* Flush memory for mbuf so we don't get stale bytes */
bus_dmamap_sync(sc->rxtag, sc->rx_map[i], bus_dmamap_sync(sc->rxtag, sc->rx_map[i],
BUS_DMASYNC_POSTREAD); BUS_DMASYNC_POSTREAD);
WR4(sc, ETH_RSR, RD4(sc, ETH_RSR)); WR4(sc, ETH_RSR, RD4(sc, ETH_RSR)); // XXX WHY? XXX imp
/*
* Allocate a new buffer to replace this one.
* if we cannot, then we drop this packet
* and keep the old buffer we had. Once allocated
* the new buffer is loaded for dma.
*/
sc->rx_mbuf[i] = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
if (!sc->rx_mbuf[i]) {
printf("Failed to get another mbuf -- discarding packet\n");
sc->rx_mbuf[i] = mb;
sc->rx_descs[i].addr &= ~ETH_CPU_OWNER;
bus_dmamap_sync(sc->rxtag, sc->rx_map[i],
BUS_DMASYNC_PREREAD);
bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map,
BUS_DMASYNC_PREWRITE);
continue;
}
sc->rx_mbuf[i]->m_len =
sc->rx_mbuf[i]->m_pkthdr.len = MCLBYTES;
bus_dmamap_unload(sc->rxtag, sc->rx_map[i]);
if (bus_dmamap_load_mbuf_sg(sc->rxtag, sc->rx_map[i],
sc->rx_mbuf[i], &seg, &nsegs, 0) != 0) {
printf("Failed to load mbuf -- discarding packet -- reload old?\n");
sc->rx_mbuf[i] = mb;
sc->rx_descs[i].addr &= ~ETH_CPU_OWNER;
bus_dmamap_sync(sc->rxtag, sc->rx_map[i],
BUS_DMASYNC_PREREAD);
bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map,
BUS_DMASYNC_PREWRITE);
continue;
}
/* /*
* The length returned by the device includes the * The length returned by the device includes the
* ethernet CRC calculation for the packet, but * ethernet CRC calculation for the packet, but
* ifnet drivers are supposed to discard it. * ifnet drivers are supposed to discard it.
*/ */
mb->m_len = (rx_stat & ETH_LEN_MASK) - ETHER_CRC_LEN; mb = m_devget(sc->rx_buf[i],
mb->m_pkthdr.len = mb->m_len; (rx_stat & ETH_LEN_MASK) - ETHER_CRC_LEN,
mb->m_pkthdr.rcvif = sc->ifp;
tmp_mbuf = m_devget(mtod(mb, caddr_t), mb->m_len,
ETHER_ALIGN, sc->ifp, NULL); ETHER_ALIGN, sc->ifp, NULL);
m_free(mb); sc->rx_descs[i].addr &= ~ETH_CPU_OWNER;
/*
* For the last buffer, set the wrap bit so
* the controller restarts from the first
* descriptor.
*/
sc->rx_descs[i].status = 0;
sc->rx_descs[i].addr = seg.ds_addr;
if (i == ATE_MAX_RX_BUFFERS - 1)
sc->rx_descs[i].addr |= ETH_WRAP_BIT;
bus_dmamap_sync(sc->rxtag, sc->rx_map[i],
BUS_DMASYNC_PREREAD);
bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map,
BUS_DMASYNC_PREWRITE); BUS_DMASYNC_PREWRITE);
if (tmp_mbuf != NULL) bus_dmamap_sync(sc->rxtag, sc->rx_map[i],
(*sc->ifp->if_input)(sc->ifp, tmp_mbuf); BUS_DMASYNC_PREREAD);
if (mb != NULL)
(*sc->ifp->if_input)(sc->ifp, mb);
} }
} }
if (status & ETH_ISR_TCOM) { if (status & ETH_ISR_TCOM) {
@ -760,7 +714,6 @@ ateinit_locked(void *xsc)
* the byte order is big endian, not little endian, so we have some * the byte order is big endian, not little endian, so we have some
* swapping to do. Again, if we need it (which I don't think we do). * swapping to do. Again, if we need it (which I don't think we do).
*/ */
ate_setmcast(sc); ate_setmcast(sc);
/* /*
@ -926,6 +879,8 @@ static int
ateioctl(struct ifnet *ifp, u_long cmd, caddr_t data) ateioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{ {
struct ate_softc *sc = ifp->if_softc; struct ate_softc *sc = ifp->if_softc;
struct mii_data *mii;
struct ifreq *ifr = (struct ifreq *)data;
int error = 0; int error = 0;
switch (cmd) { switch (cmd) {
@ -945,10 +900,17 @@ ateioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
case SIOCADDMULTI: case SIOCADDMULTI:
case SIOCDELMULTI: case SIOCDELMULTI:
/* update multicast filter list. */ /* update multicast filter list. */
ATE_LOCK(sc);
ate_setmcast(sc); ate_setmcast(sc);
ATE_UNLOCK(sc);
error = 0; error = 0;
break; break;
case SIOCSIFMEDIA:
case SIOCGIFMEDIA:
mii = device_get_softc(sc->miibus);
error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
break;
default: default:
error = ether_ioctl(ifp, cmd, data); error = ether_ioctl(ifp, cmd, data);
break; break;