예제 #1
0
파일: if_el.c 프로젝트: ycui1984/netbsd-src
/*
 * 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;
}
예제 #2
0
/* 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);
}