diff options
Diffstat (limited to 'sys/dev/ic/gem.c')
-rw-r--r-- | sys/dev/ic/gem.c | 106 |
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", |