/* * Controller interrupt. */ int elintr(void *arg) { struct el_softc *sc = arg; bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; u_int8_t rxstat; int len; DPRINTF(("elintr: ")); /* Check board status. */ if ((bus_space_read_1(iot, ioh, EL_AS) & EL_AS_RXBUSY) != 0) { (void)bus_space_read_1(iot, ioh, EL_RXC); bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX); return 0; } for (;;) { rxstat = bus_space_read_1(iot, ioh, EL_RXS); if (rxstat & EL_RXS_STALE) break; /* If there's an overflow, reinit the board. */ if ((rxstat & EL_RXS_NOFLOW) == 0) { DPRINTF(("overflow.\n")); el_hardreset(sc); /* Put board back into receive mode. */ if (sc->sc_ethercom.ec_if.if_flags & IFF_PROMISC) bus_space_write_1(iot, ioh, EL_RXC, EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB | EL_RXC_DOFLOW | EL_RXC_PROMISC); else bus_space_write_1(iot, ioh, EL_RXC, EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB | EL_RXC_DOFLOW | EL_RXC_ABROAD); (void)bus_space_read_1(iot, ioh, EL_AS); bus_space_write_1(iot, ioh, EL_RBC, 0); break; } /* Incoming packet. */ len = bus_space_read_1(iot, ioh, EL_RBL); len |= bus_space_read_1(iot, ioh, EL_RBH) << 8; DPRINTF(("receive len=%d rxstat=%x ", len, rxstat)); bus_space_write_1(iot, ioh, EL_AC, EL_AC_HOST); /* Pass data up to upper levels. */ elread(sc, len); /* Is there another packet? */ if ((bus_space_read_1(iot, ioh, EL_AS) & EL_AS_RXBUSY) != 0) break; rnd_add_uint32(&sc->rnd_source, rxstat); DPRINTF(("<rescan> ")); } (void)bus_space_read_1(iot, ioh, EL_RXC); bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX); return 1; }
/* controller interrupt */ static void elintr(void *arg) { int unit = (int)arg; struct el_softc *sc; int base; int stat, rxstat, len, done; lwkt_serialize_enter(&el_serializer); /* Get things pointing properly */ sc = &el_softc[unit]; base = sc->el_base; dprintf(("elintr: ")); /* Check board status */ stat = inb(base+EL_AS); if(stat & EL_AS_RXBUSY) { inb(base+EL_RXC); outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX)); lwkt_serialize_exit(&el_serializer); return; } done = 0; while(!done) { rxstat = inb(base+EL_RXS); if(rxstat & EL_RXS_STALE) { inb(base+EL_RXC); outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX)); lwkt_serialize_exit(&el_serializer); return; } /* If there's an overflow, reinit the board. */ if(!(rxstat & EL_RXS_NOFLOW)) { dprintf(("overflow.\n")); el_hardreset(sc); /* Put board back into receive mode */ if(sc->arpcom.ac_if.if_flags & IFF_PROMISC) outb(base+EL_RXC,(EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW)); else outb(base+EL_RXC,(EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW)); inb(base+EL_AS); outb(base+EL_RBC,0); inb(base+EL_RXC); outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX)); lwkt_serialize_exit(&el_serializer); return; } /* Incoming packet */ len = inb(base+EL_RBL); len |= inb(base+EL_RBH) << 8; dprintf(("receive len=%d rxstat=%x ",len,rxstat)); outb(base+EL_AC,EL_AC_HOST); /* If packet too short or too long, restore rx mode and return */ if((len <= sizeof(struct ether_header)) || (len > ETHER_MAX_LEN)) { if(sc->arpcom.ac_if.if_flags & IFF_PROMISC) outb(base+EL_RXC,(EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW)); else outb(base+EL_RXC,(EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW)); inb(base+EL_AS); outb(base+EL_RBC,0); inb(base+EL_RXC); outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX)); lwkt_serialize_exit(&el_serializer); return; } sc->arpcom.ac_if.if_ipackets++; /* Copy the data into our buffer */ outb(base+EL_GPBL,0); outb(base+EL_GPBH,0); insb(base+EL_BUF,sc->el_pktbuf,len); outb(base+EL_RBC,0); outb(base+EL_AC,EL_AC_RX); dprintf(("%6D-->",sc->el_pktbuf+6,":")); dprintf(("%6D\n",sc->el_pktbuf,":")); /* Pass data up to upper levels */ elread(sc,(caddr_t)(sc->el_pktbuf),len); /* Is there another packet? */ stat = inb(base+EL_AS); /* If so, do it all again (i.e. don't set done to 1) */ if(!(stat & EL_AS_RXBUSY)) dprintf(("<rescan> ")); else done = 1; } inb(base+EL_RXC); outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX)); lwkt_serialize_exit(&el_serializer); }