Greetings, I tried to write mclgeti support for epic(4). Unfortunately, I can't blast it enough. I'd much appreciate if someone can a more in depth torture.
Feedback and advice would be very helpful. Thanks, Logan Index: src/sys/dev/ic/smc83c170.c =================================================================== RCS file: /cvs/src/sys/dev/ic/smc83c170.c,v retrieving revision 1.14 diff -u -p -r1.14 smc83c170.c --- src/sys/dev/ic/smc83c170.c 10 Aug 2009 20:29:54 -0000 1.14 +++ src/sys/dev/ic/smc83c170.c 12 Dec 2010 18:00:07 -0000 @@ -83,6 +83,7 @@ void epic_stop(struct ifnet *, int); void epic_reset(struct epic_softc *); void epic_rxdrain(struct epic_softc *); +void epic_fill_rx_ring(struct epic_softc *); int epic_add_rxbuf(struct epic_softc *, int); void epic_read_eeprom(struct epic_softc *, int, int, u_int16_t *); void epic_set_mchash(struct epic_softc *); @@ -286,7 +287,7 @@ epic_attach(struct epic_softc *sc, const ifp->if_watchdog = epic_watchdog; IFQ_SET_MAXLEN(&ifp->if_snd, EPIC_NTXDESC - 1); IFQ_SET_READY(&ifp->if_snd); - + m_clsetwms(ifp, MCLBYTES, 2, EPIC_NRXDESC - 1); ifp->if_capabilities = IFCAP_VLAN_MTU; /* @@ -621,7 +622,7 @@ epic_intr(void *arg) * Check for receive interrupts. */ if (intstat & (INTSTAT_RCC | INTSTAT_RXE | INTSTAT_RQE)) { - for (i = sc->sc_rxptr;; i = EPIC_NEXTRX(i)) { + for (i = sc->sc_rx_cons; sc->sc_rx_cnt > 0; i = EPIC_NEXTRX(i)) { rxd = EPIC_CDRX(sc, i); ds = EPIC_DSRX(sc, i); @@ -637,6 +638,13 @@ epic_intr(void *arg) break; } + bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, + ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); + + m = ds->ds_mbuf; + ds->ds_mbuf = NULL; + sc->sc_rx_cnt--; /* * Make sure the packet arrived intact. If an error * occurred, update stats and reset the descriptor. @@ -651,13 +659,10 @@ epic_intr(void *arg) printf("%s: alignment error\n", sc->sc_dev.dv_xname); ifp->if_ierrors++; - EPIC_INIT_RXDESC(sc, i); + m_freem(m); continue; } - bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, - ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD); - /* * The EPIC includes the CRC with every packet; * trim it. @@ -669,51 +674,16 @@ epic_intr(void *arg) * Runt packet; drop it now. */ ifp->if_ierrors++; - EPIC_INIT_RXDESC(sc, i); + m_freem(m); bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); continue; } - /* - * If the packet is small enough to fit in a - * single header mbuf, allocate one and copy - * the data into it. This greatly reduces - * memory consumption when we receive lots - * of small packets. - * - * Otherwise, we add a new buffer to the receive - * chain. If this fails, we drop the packet and - * recycle the old buffer. - */ - if (epic_copy_small != 0 && len <= MHLEN) { - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - goto dropit; - memcpy(mtod(m, caddr_t), - mtod(ds->ds_mbuf, caddr_t), len); - EPIC_INIT_RXDESC(sc, i); - bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, - ds->ds_dmamap->dm_mapsize, - BUS_DMASYNC_PREREAD); - } else { - m = ds->ds_mbuf; - if (epic_add_rxbuf(sc, i) != 0) { - dropit: - ifp->if_ierrors++; - EPIC_INIT_RXDESC(sc, i); - bus_dmamap_sync(sc->sc_dmat, - ds->ds_dmamap, 0, - ds->ds_dmamap->dm_mapsize, - BUS_DMASYNC_PREREAD); - continue; - } - } - m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = len; - + m->m_data += 2; #if NBPFILTER > 0 /* * Pass this up to any BPF listeners, but only @@ -729,20 +699,16 @@ epic_intr(void *arg) } /* Update the receive pointer. */ - sc->sc_rxptr = i; - + sc->sc_rx_cons = i; + epic_fill_rx_ring(sc); /* * Check for receive queue underflow. */ if (intstat & INTSTAT_RQE) { - printf("%s: receiver queue empty\n", - sc->sc_dev.dv_xname); /* * Ring is already built; just restart the * receiver. */ - bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_PRCDAR, - EPIC_CDRXADDR(sc, sc->sc_rxptr)); bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_COMMAND, COMMAND_RXQUEUED | COMMAND_START_RX); } @@ -908,9 +874,8 @@ epic_init(struct ifnet *ifp) bus_space_tag_t st = sc->sc_st; bus_space_handle_t sh = sc->sc_sh; struct epic_txdesc *txd; - struct epic_descsoft *ds; u_int32_t genctl, reg0; - int i, error = 0; + int i; /* * Cancel any pending I/O. @@ -998,24 +963,12 @@ epic_init(struct ifnet *ifp) * Initialize the receive descriptor ring. */ for (i = 0; i < EPIC_NRXDESC; i++) { - ds = EPIC_DSRX(sc, i); - if (ds->ds_mbuf == NULL) { - if ((error = epic_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. - */ - epic_rxdrain(sc); - goto out; - } - } else - EPIC_INIT_RXDESC(sc, i); + sc->sc_control_data->ecd_rxdescs[i].er_bufaddr = 0; + sc->sc_control_data->ecd_rxdescs[i].er_control = 0; + sc->sc_control_data->ecd_rxdescs[i].er_rxstatus = 0; + sc->sc_control_data->ecd_rxdescs[i].er_nextdesc = 0; } - sc->sc_rxptr = 0; - + epic_fill_rx_ring(sc); /* * Initialize the interrupt mask and enable interrupts. */ @@ -1028,7 +981,7 @@ epic_init(struct ifnet *ifp) bus_space_write_4(st, sh, EPIC_PTCDAR, EPIC_CDTXADDR(sc, EPIC_NEXTTX(sc->sc_txlast))); bus_space_write_4(st, sh, EPIC_PRCDAR, - EPIC_CDRXADDR(sc, sc->sc_rxptr)); + EPIC_CDRXADDR(sc, sc->sc_rx_prod)); /* * Set the EPIC in motion. @@ -1052,10 +1005,7 @@ epic_init(struct ifnet *ifp) */ epic_start(ifp); - out: - if (error) - printf("%s: interface not running\n", sc->sc_dev.dv_xname); - return (error); + return (0); } /* @@ -1075,6 +1025,7 @@ epic_rxdrain(struct epic_softc *sc) ds->ds_mbuf = NULL; } } + sc->sc_rx_prod = sc->sc_rx_cons = sc->sc_rx_cnt = 0; } /* @@ -1213,6 +1164,15 @@ epic_read_eeprom(struct epic_softc *sc, #undef EEPROM_WAIT_READY } +void +epic_fill_rx_ring(struct epic_softc *sc) +{ + while(sc->sc_rx_cnt < EPIC_NRXDESC) { + if(epic_add_rxbuf(sc, sc->sc_rx_prod)) + break; + } +} + /* * Add a receive buffer to the indicated descriptor. */ @@ -1223,23 +1183,14 @@ epic_add_rxbuf(struct epic_softc *sc, in struct mbuf *m; int error; - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) + m = MCLGETI(NULL, M_DONTWAIT, &sc->sc_arpcom.ac_if, MCLBYTES); + if (!m) return (ENOBUFS); - - MCLGET(m, M_DONTWAIT); - if ((m->m_flags & M_EXT) == 0) { - m_freem(m); - return (ENOBUFS); - } - - if (ds->ds_mbuf != NULL) - bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); + m->m_len = m->m_pkthdr.len = MCLBYTES; ds->ds_mbuf = m; - error = bus_dmamap_load(sc->sc_dmat, ds->ds_dmamap, - m->m_ext.ext_buf, m->m_ext.ext_size, NULL, + error = bus_dmamap_load_mbuf(sc->sc_dmat, ds->ds_dmamap, m, BUS_DMA_READ|BUS_DMA_NOWAIT); if (error) { printf("%s: can't load rx DMA map %d, error = %d\n", @@ -1251,6 +1202,8 @@ epic_add_rxbuf(struct epic_softc *sc, in ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); EPIC_INIT_RXDESC(sc, idx); + sc->sc_rx_prod = EPIC_NEXTRX(sc->sc_rx_prod); + sc->sc_rx_cnt++; return (0); } Index: src/sys/dev/ic/smc83c170var.h =================================================================== RCS file: /cvs/src/sys/dev/ic/smc83c170var.h,v retrieving revision 1.3 diff -u -p -r1.3 smc83c170var.h --- src/sys/dev/ic/smc83c170var.h 10 Aug 2009 20:29:54 -0000 1.3 +++ src/sys/dev/ic/smc83c170var.h 12 Dec 2010 18:00:07 -0000 @@ -128,7 +128,9 @@ struct epic_softc { int sc_txdirty; /* first dirty TX descriptor */ int sc_txlast; /* last used TX descriptor */ - int sc_rxptr; /* next ready RX descriptor */ + int sc_rx_cnt; + int sc_rx_prod; + int sc_rx_cons; u_int sc_serinst; /* ifmedia instance for serial mode */ }; @@ -167,7 +169,6 @@ do { \ * so that the payload after the Ethernet header is aligned \ * to a 4 byte boundary. \ */ \ - __m->m_data = __m->m_ext.ext_buf + 2; \ __rxd->er_bufaddr = __ds->ds_dmamap->dm_segs[0].ds_addr + 2; \ __rxd->er_control = RXCTL_BUFLENGTH(__m->m_ext.ext_size - 2); \ __rxd->er_rxstatus = ER_RXSTAT_OWNER; \