Exemple #1
0
/*
 * Start output on interface.  Get datagrams from the queue and output them,
 * giving the receiver a chance between datagrams.  Call only from splnet or
 * interrupt level!
 */
void
elstart(struct ifnet *ifp)
{
	struct el_softc *sc = ifp->if_softc;
	bus_space_tag_t iot = sc->sc_iot;
	bus_space_handle_t ioh = sc->sc_ioh;
	struct mbuf *m, *m0;
	int s, i, off, retries;

	DPRINTF(("elstart()...\n"));
	s = splnet();

	/* Don't do anything if output is active. */
	if ((ifp->if_flags & IFF_OACTIVE) != 0) {
		splx(s);
		return;
	}

	ifp->if_flags |= IFF_OACTIVE;

	/*
	 * The main loop.  They warned me against endless loops, but would I
	 * listen?  NOOO....
	 */
	for (;;) {
		/* Dequeue the next datagram. */
		IFQ_DEQUEUE(&ifp->if_snd, m0);

		/* If there's nothing to send, return. */
		if (m0 == 0)
			break;

		/* Give the packet to the bpf, if any. */
		bpf_mtap(ifp, m0);

		/* Disable the receiver. */
		bus_space_write_1(iot, ioh, EL_AC, EL_AC_HOST);
		bus_space_write_1(iot, ioh, EL_RBC, 0);

		/* Transfer datagram to board. */
		DPRINTF(("el: xfr pkt length=%d...\n", m0->m_pkthdr.len));
		off = EL_BUFSIZ - max(m0->m_pkthdr.len,
		    ETHER_MIN_LEN - ETHER_CRC_LEN);
#ifdef DIAGNOSTIC
		if ((off & 0xffff) != off)
			printf("%s: bogus off 0x%x\n",
			    device_xname(sc->sc_dev), off);
#endif
		bus_space_write_1(iot, ioh, EL_GPBL, off & 0xff);
		bus_space_write_1(iot, ioh, EL_GPBH, (off >> 8) & 0xff);

		/* Copy the datagram to the buffer. */
		for (m = m0; m != 0; m = m->m_next)
			bus_space_write_multi_1(iot, ioh, EL_BUF,
			    mtod(m, u_int8_t *), m->m_len);
		for (i = 0;
		    i < ETHER_MIN_LEN - ETHER_CRC_LEN - m0->m_pkthdr.len; i++)
			bus_space_write_1(iot, ioh, EL_BUF, 0);

		m_freem(m0);

		/* Now transmit the datagram. */
		retries = 0;
		for (;;) {
			bus_space_write_1(iot, ioh, EL_GPBL, off & 0xff);
			bus_space_write_1(iot, ioh, EL_GPBH, (off >> 8) & 0xff);
			if (el_xmit(sc)) {
				ifp->if_oerrors++;
				break;
			}
			/* Check out status. */
			i = bus_space_read_1(iot, ioh, EL_TXS);
			DPRINTF(("tx status=0x%x\n", i));
			if ((i & EL_TXS_READY) == 0) {
				DPRINTF(("el: err txs=%x\n", i));
				if (i & (EL_TXS_COLL | EL_TXS_COLL16)) {
					ifp->if_collisions++;
					if ((i & EL_TXC_DCOLL16) == 0 &&
					    retries < 15) {
						retries++;
						bus_space_write_1(iot, ioh,
						    EL_AC, EL_AC_HOST);
					}
				} else {
					ifp->if_oerrors++;
					break;
				}
			} else {
				ifp->if_opackets++;
				break;
			}
		}

		/*
		 * Now give the card a chance to receive.
		 * Gotta love 3c501s...
		 */
		(void)bus_space_read_1(iot, ioh, EL_AS);
		bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
		splx(s);
		/* Interrupt here. */
		s = splnet();
	}

	(void)bus_space_read_1(iot, ioh, EL_AS);
	bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
	ifp->if_flags &= ~IFF_OACTIVE;
	splx(s);
}
Exemple #2
0
/* Start output on interface.  Get datagrams from the queue and output
 * them, giving the receiver a chance between datagrams.  Call only
 * from splimp or interrupt level!
 */
static void
el_start(struct ifnet *ifp)
{
	struct el_softc *sc;
	u_short base;
	struct mbuf *m, *m0;
	int i, len, retries, done;

	/* Get things pointing in the right directions */
	sc = ifp->if_softc;
	base = sc->el_base;

	dprintf(("el_start()...\n"));

	/* Don't do anything if output is active */
	if (ifp->if_flags & IFF_OACTIVE)
		return;
	ifp->if_flags |= IFF_OACTIVE;

	/* The main loop.  They warned me against endless loops, but
	 * would I listen?  NOOO....
	 */
	while(1) {
		/* Dequeue the next datagram */
		m0 = ifq_dequeue(&ifp->if_snd, NULL);

		/* If there's nothing to send, return. */
		if(m0 == NULL) {
			sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
			return;
		}

		/* Disable the receiver */
		outb(base+EL_AC,EL_AC_HOST);
		outb(base+EL_RBC,0);

		/* Copy the datagram to the buffer. */
		len = 0;
		for(m = m0; m != NULL; m = m->m_next) {
			if(m->m_len == 0)
				continue;
			bcopy(mtod(m,caddr_t),sc->el_pktbuf+len,m->m_len);
			len += m->m_len;
		}
		m_freem(m0);

		len = max(len,ETHER_MIN_LEN);

		BPF_TAP(&sc->arpcom.ac_if, sc->el_pktbuf, len);

		/* Transfer datagram to board */
		dprintf(("el: xfr pkt length=%d...\n",len));
		i = EL_BUFSIZ - len;
		outb(base+EL_GPBL,(i & 0xff));
		outb(base+EL_GPBH,((i>>8)&0xff));
		outsb(base+EL_BUF,sc->el_pktbuf,len);

		/* Now transmit the datagram */
		retries=0;
		done=0;
		while(!done) {
			if(el_xmit(sc,len)) { /* Something went wrong */
				done = -1;
				break;
			}
			/* Check out status */
			i = inb(base+EL_TXS);
			dprintf(("tx status=0x%x\n",i));
			if(!(i & EL_TXS_READY)) {
				dprintf(("el: err txs=%x\n",i));
				sc->arpcom.ac_if.if_oerrors++;
				if(i & (EL_TXS_COLL|EL_TXS_COLL16)) {
					if((!(i & EL_TXC_DCOLL16)) && retries < 15) {
						retries++;
						outb(base+EL_AC,EL_AC_HOST);
					}
				}
				else
					done = 1;
			}
			else {
				sc->arpcom.ac_if.if_opackets++;
				done = 1;
			}
		}
		if(done == -1)  /* Packet not transmitted */
			continue;

		/* Now give the card a chance to receive.
		 * Gotta love 3c501s...
		 */
		inb(base+EL_AS);
		outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
	}
}