summaryrefslogtreecommitdiff
path: root/sys/dev/ic/gem.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ic/gem.c')
-rw-r--r--sys/dev/ic/gem.c106
1 files changed, 44 insertions, 62 deletions
diff --git a/sys/dev/ic/gem.c b/sys/dev/ic/gem.c
index 08620c290ce..c81f1f3319f 100644
--- a/sys/dev/ic/gem.c
+++ b/sys/dev/ic/gem.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: gem.c,v 1.85 2008/12/10 20:37:48 brad Exp $ */
+/* $OpenBSD: gem.c,v 1.86 2008/12/14 21:31:50 kettenis Exp $ */
/* $NetBSD: gem.c,v 1.1 2001/09/16 00:11:43 eeh Exp $ */
/*
@@ -98,6 +98,7 @@ int gem_reset_tx(struct gem_softc *);
int gem_disable_rx(struct gem_softc *);
int gem_disable_tx(struct gem_softc *);
void gem_rxdrain(struct gem_softc *);
+void gem_fill_rx_ring(struct gem_softc *);
int gem_add_rxbuf(struct gem_softc *, int idx);
void gem_setladrf(struct gem_softc *);
@@ -227,6 +228,9 @@ gem_config(struct gem_softc *sc)
IFQ_SET_MAXLEN(&ifp->if_snd, GEM_NTXDESC - 1);
IFQ_SET_READY(&ifp->if_snd);
+ /* Hardware reads RX descriptors in multiples of four. */
+ m_clsetlwm(ifp, MCLBYTES, 4);
+
ifp->if_capabilities = IFCAP_VLAN_MTU;
/* Initialize ifmedia structures and MII info */
@@ -475,6 +479,7 @@ gem_rxdrain(struct gem_softc *sc)
rxs->rxs_mbuf = NULL;
}
}
+ sc->sc_rx_prod = sc->sc_rx_cons = sc->sc_rx_cnt = 0;
}
/*
@@ -630,8 +635,7 @@ gem_disable_tx(struct gem_softc *sc)
int
gem_meminit(struct gem_softc *sc)
{
- struct gem_rxsoft *rxs;
- int i, error;
+ int i;
/*
* Initialize the transmit descriptor ring.
@@ -648,23 +652,10 @@ gem_meminit(struct gem_softc *sc)
* descriptor rings.
*/
for (i = 0; i < GEM_NRXDESC; i++) {
- rxs = &sc->sc_rxsoft[i];
- if (rxs->rxs_mbuf == NULL) {
- if ((error = gem_add_rxbuf(sc, i)) != 0) {
- printf("%s: unable to allocate or map rx "
- "buffer %d, error = %d\n",
- sc->sc_dev.dv_xname, i, error);
- /*
- * XXX Should attempt to run with fewer receive
- * XXX buffers instead of just failing.
- */
- gem_rxdrain(sc);
- return (1);
- }
- } else
- GEM_INIT_RXDESC(sc, i);
+ sc->sc_rxdescs[i].gd_flags = 0;
+ sc->sc_rxdescs[i].gd_addr = 0;
}
- sc->sc_rxptr = 0;
+ gem_fill_rx_ring(sc);
return (0);
}
@@ -810,9 +801,8 @@ gem_init(struct ifnet *ifp)
if (sc->sc_hwinit)
(*sc->sc_hwinit)(sc);
-
/* step 15. Give the receiver a swift kick */
- bus_space_write_4(t, h, GEM_RX_KICK, GEM_NRXDESC-4);
+ bus_space_write_4(t, h, GEM_RX_KICK, sc->sc_rx_prod);
/* Start the one second timer. */
timeout_add_sec(&sc->sc_tick_ch, 1);
@@ -931,7 +921,7 @@ gem_rint(struct gem_softc *sc)
u_int64_t rxstat;
int i, len;
- for (i = sc->sc_rxptr;; i = GEM_NEXTRX(i)) {
+ for (i = sc->sc_rx_cons; sc->sc_rx_cnt > 0; i = GEM_NEXTRX(i)) {
rxs = &sc->sc_rxsoft[i];
GEM_CDRXSYNC(sc, i,
@@ -940,23 +930,29 @@ gem_rint(struct gem_softc *sc)
rxstat = GEM_DMA_READ(sc, sc->sc_rxdescs[i].gd_flags);
if (rxstat & GEM_RD_OWN) {
- /*
- * We have processed all of the receive buffers.
- */
+ /* We have processed all of the receive buffers. */
break;
}
+ bus_dmamap_sync(sc->sc_dmatag, rxs->rxs_dmamap, 0,
+ rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->sc_dmatag, rxs->rxs_dmamap);
+
+ m = rxs->rxs_mbuf;
+ rxs->rxs_mbuf = NULL;
+
+ sc->sc_rx_cnt--;
+
if (rxstat & GEM_RD_BAD_CRC) {
+ ifp->if_ierrors++;
#ifdef GEM_DEBUG
printf("%s: receive error: CRC error\n",
sc->sc_dev.dv_xname);
#endif
- GEM_INIT_RXDESC(sc, i);
+ m_freem(m);
continue;
}
- bus_dmamap_sync(sc->sc_dmatag, rxs->rxs_dmamap, 0,
- rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
#ifdef GEM_DEBUG
if (ifp->if_flags & IFF_DEBUG) {
printf(" rxsoft %p descriptor %d: ", rxs, i);
@@ -970,19 +966,6 @@ gem_rint(struct gem_softc *sc)
/* No errors; receive the packet. */
len = GEM_RD_BUFLEN(rxstat);
- /*
- * Allocate a new mbuf cluster. If that fails, we are
- * out of memory, and must drop the packet and recycle
- * the buffer that's already attached to this descriptor.
- */
- m = rxs->rxs_mbuf;
- if (gem_add_rxbuf(sc, i) != 0) {
- ifp->if_ierrors++;
- GEM_INIT_RXDESC(sc, i);
- bus_dmamap_sync(sc->sc_dmatag, rxs->rxs_dmamap, 0,
- rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
- continue;
- }
m->m_data += 2; /* We're already off by two */
ifp->if_ipackets++;
@@ -990,10 +973,6 @@ gem_rint(struct gem_softc *sc)
m->m_pkthdr.len = m->m_len = len;
#if NBPFILTER > 0
- /*
- * Pass this up to any BPF listeners, but only
- * pass it up the stack if its for us.
- */
if (ifp->if_bpf)
bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
#endif /* NBPFILTER > 0 */
@@ -1003,15 +982,24 @@ gem_rint(struct gem_softc *sc)
}
/* Update the receive pointer. */
- sc->sc_rxptr = i;
- bus_space_write_4(t, h, GEM_RX_KICK, i);
+ sc->sc_rx_cons = i;
+ gem_fill_rx_ring(sc);
+ bus_space_write_4(t, h, GEM_RX_KICK, sc->sc_rx_prod);
- DPRINTF(sc, ("gem_rint: done sc->rxptr %d, complete %d\n",
- sc->sc_rxptr, bus_space_read_4(t, h, GEM_RX_COMPLETION)));
+ DPRINTF(sc, ("gem_rint: done sc->sc_rx_cons %d, complete %d\n",
+ sc->sc_rx_cons, bus_space_read_4(t, h, GEM_RX_COMPLETION)));
return (1);
}
+void
+gem_fill_rx_ring(struct gem_softc *sc)
+{
+ while (sc->sc_rx_cnt < (GEM_NRXDESC - 4)) {
+ if (gem_add_rxbuf(sc, sc->sc_rx_prod))
+ break;
+ }
+}
/*
* Add a receive buffer to the indicated descriptor.
@@ -1027,24 +1015,21 @@ gem_add_rxbuf(struct gem_softc *sc, int idx)
if (m == NULL)
return (ENOBUFS);
- MCLGET(m, M_DONTWAIT);
+ MCLGETI(m, M_DONTWAIT, &sc->sc_arpcom.ac_if, MCLBYTES);
if ((m->m_flags & M_EXT) == 0) {
m_freem(m);
return (ENOBUFS);
}
+ m->m_len = m->m_pkthdr.len = MCLBYTES;
#ifdef GEM_DEBUG
/* bzero the packet to check dma */
memset(m->m_ext.ext_buf, 0, m->m_ext.ext_size);
#endif
- if (rxs->rxs_mbuf != NULL)
- bus_dmamap_unload(sc->sc_dmatag, rxs->rxs_dmamap);
-
rxs->rxs_mbuf = m;
- error = bus_dmamap_load(sc->sc_dmatag, rxs->rxs_dmamap,
- m->m_ext.ext_buf, m->m_ext.ext_size, NULL,
+ error = bus_dmamap_load_mbuf(sc->sc_dmatag, rxs->rxs_dmamap, m,
BUS_DMA_READ|BUS_DMA_NOWAIT);
if (error) {
printf("%s: can't load rx DMA map %d, error = %d\n",
@@ -1057,6 +1042,9 @@ gem_add_rxbuf(struct gem_softc *sc, int idx)
GEM_INIT_RXDESC(sc, idx);
+ sc->sc_rx_prod = GEM_NEXTRX(sc->sc_rx_prod);
+ sc->sc_rx_cnt++;
+
return (0);
}
@@ -1135,14 +1123,8 @@ gem_intr(void *v)
printf("%s: MAC rx fault, status %x\n",
sc->sc_dev.dv_xname, rxstat);
#endif
- /*
- * On some chip revisions GEM_MAC_RX_OVERFLOW happen often
- * due to a silicon bug so handle them silently.
- */
- if (rxstat & GEM_MAC_RX_OVERFLOW) {
+ if (rxstat & GEM_MAC_RX_OVERFLOW)
ifp->if_ierrors++;
- gem_init(ifp);
- }
#ifdef GEM_DEBUG
else if (rxstat & ~(GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT))
printf("%s: MAC rx fault, status %x\n",