/* * Handle control requests from the operator. * [ifnet interface function] */ int epic_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct epic_softc *sc = ifp->if_softc; struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; s = splnet(); switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; switch (ifa->ifa_addr->sa_family) { case AF_INET: epic_init(ifp); arp_ifinit(&sc->sc_arpcom, ifa); break; default: epic_init(ifp); break; } break; case SIOCSIFFLAGS: /* * If interface is marked up and not running, then start it. * If it is marked down and running, stop it. * XXX If it's up then re-initialize it. This is so flags * such as IFF_PROMISC are handled. */ if (ifp->if_flags & IFF_UP) epic_init(ifp); else if (ifp->if_flags & IFF_RUNNING) epic_stop(ifp, 1); break; case SIOCSIFMEDIA: case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd); break; default: error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data); } if (error == ENETRESET) { if (ifp->if_flags & IFF_RUNNING) { mii_pollstat(&sc->sc_mii); epic_set_mchash(sc); } error = 0; } splx(s); return (error); }
int main( void ) { epic_init(); epic_main(); return 0; }
/* * Watchdog timer handler. * [ifnet interface function] */ void epic_watchdog(struct ifnet *ifp) { struct epic_softc *sc = ifp->if_softc; printf("%s: device timeout\n", sc->sc_dev.dv_xname); ifp->if_oerrors++; (void) epic_init(ifp); }
/* * Interrupt handler. */ int epic_intr(void *arg) { struct epic_softc *sc = arg; struct ifnet *ifp = &sc->sc_arpcom.ac_if; struct epic_rxdesc *rxd; struct epic_txdesc *txd; struct epic_descsoft *ds; struct mbuf_list ml = MBUF_LIST_INITIALIZER(); struct mbuf *m; u_int32_t intstat, rxstatus, txstatus; int i, claimed = 0; u_int len; /* * Get the interrupt status from the EPIC. */ intstat = bus_space_read_4(sc->sc_st, sc->sc_sh, EPIC_INTSTAT); if ((intstat & INTSTAT_INT_ACTV) == 0) return (claimed); claimed = 1; /* * Acknowledge the interrupt. */ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_INTSTAT, intstat & INTMASK); /* * Check for receive interrupts. */ if (intstat & (INTSTAT_RCC | INTSTAT_RXE | INTSTAT_RQE)) { for (i = sc->sc_rxptr;; i = EPIC_NEXTRX(i)) { rxd = EPIC_CDRX(sc, i); ds = EPIC_DSRX(sc, i); EPIC_CDRXSYNC(sc, i, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); rxstatus = rxd->er_rxstatus; if (rxstatus & ER_RXSTAT_OWNER) { /* * We have processed all of the * receive buffers. */ break; } /* * Make sure the packet arrived intact. If an error * occurred, update stats and reset the descriptor. * The buffer will be reused the next time the * descriptor comes up in the ring. */ if ((rxstatus & ER_RXSTAT_PKTINTACT) == 0) { if (rxstatus & ER_RXSTAT_CRCERROR) printf("%s: CRC error\n", sc->sc_dev.dv_xname); if (rxstatus & ER_RXSTAT_ALIGNERROR) printf("%s: alignment error\n", sc->sc_dev.dv_xname); ifp->if_ierrors++; EPIC_INIT_RXDESC(sc, i); 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. */ len = RXSTAT_RXLENGTH(rxstatus) - ETHER_CRC_LEN; if (len < sizeof(struct ether_header)) { /* * Runt packet; drop it now. */ 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; } /* * 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.len = m->m_len = len; ml_enqueue(&ml, m); } /* Update the receive pointer. */ sc->sc_rxptr = i; /* * 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); } } if_input(ifp, &ml); /* * Check for transmission complete interrupts. */ if (intstat & (INTSTAT_TXC | INTSTAT_TXU)) { ifp->if_flags &= ~IFF_OACTIVE; for (i = sc->sc_txdirty; sc->sc_txpending != 0; i = EPIC_NEXTTX(i), sc->sc_txpending--) { txd = EPIC_CDTX(sc, i); ds = EPIC_DSTX(sc, i); EPIC_CDTXSYNC(sc, i, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); txstatus = txd->et_txstatus; if (txstatus & ET_TXSTAT_OWNER) break; EPIC_CDFLSYNC(sc, i, BUS_DMASYNC_POSTWRITE); bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); m_freem(ds->ds_mbuf); ds->ds_mbuf = NULL; /* * Check for errors and collisions. */ if ((txstatus & ET_TXSTAT_PACKETTX) == 0) ifp->if_oerrors++; else ifp->if_opackets++; ifp->if_collisions += TXSTAT_COLLISIONS(txstatus); if (txstatus & ET_TXSTAT_CARSENSELOST) printf("%s: lost carrier\n", sc->sc_dev.dv_xname); } /* Update the dirty transmit buffer pointer. */ sc->sc_txdirty = i; /* * Cancel the watchdog timer if there are no pending * transmissions. */ if (sc->sc_txpending == 0) ifp->if_timer = 0; /* * Kick the transmitter after a DMA underrun. */ if (intstat & INTSTAT_TXU) { printf("%s: transmit underrun\n", sc->sc_dev.dv_xname); bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_COMMAND, COMMAND_TXUGO); if (sc->sc_txpending) bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_COMMAND, COMMAND_TXQUEUED); } /* * Try to get more packets going. */ epic_start(ifp); } /* * Check for fatal interrupts. */ if (intstat & INTSTAT_FATAL_INT) { if (intstat & INTSTAT_PTA) printf("%s: PCI target abort error\n", sc->sc_dev.dv_xname); else if (intstat & INTSTAT_PMA) printf("%s: PCI master abort error\n", sc->sc_dev.dv_xname); else if (intstat & INTSTAT_APE) printf("%s: PCI address parity error\n", sc->sc_dev.dv_xname); else if (intstat & INTSTAT_DPE) printf("%s: PCI data parity error\n", sc->sc_dev.dv_xname); else printf("%s: unknown fatal error\n", sc->sc_dev.dv_xname); (void) epic_init(ifp); } return (claimed); }