/* * 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); }
/* 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)); } }