/* * icintr() */ static void icintr (device_t dev, int event, char *ptr) { struct ic_softc *sc = (struct ic_softc *)device_get_softc(dev); int unit = device_get_unit(dev); int len; struct mbuf *top; crit_enter(); switch (event) { case INTR_GENERAL: case INTR_START: sc->ic_cp = sc->ic_ifbuf; sc->ic_xfercnt = 0; break; case INTR_STOP: /* if any error occured during transfert, * drop the packet */ if (sc->ic_iferrs) goto err; if ((len = sc->ic_xfercnt) == 0) break; /* ignore */ if (len <= ICHDRLEN) goto err; len -= ICHDRLEN; sc->ic_if.if_ipackets ++; sc->ic_if.if_ibytes += len; BPF_TAP(&sc->ic_if, sc->ic_ifbuf, len + ICHDRLEN); top = m_devget(sc->ic_ifbuf + ICHDRLEN, len, 0, &sc->ic_if, 0); if (top) netisr_queue(NETISR_IP, top); break; err: kprintf("ic%d: errors (%d)!\n", unit, sc->ic_iferrs); sc->ic_iferrs = 0; /* reset error count */ sc->ic_if.if_ierrors ++; break; case INTR_RECEIVE: if (sc->ic_xfercnt >= sc->ic_if.if_mtu+ICHDRLEN) { sc->ic_iferrs ++; } else { *sc->ic_cp++ = *ptr; sc->ic_xfercnt ++; } break; case INTR_NOACK: /* xfer terminated by master */ break; case INTR_TRANSMIT: *ptr = 0xff; /* XXX */ break; case INTR_ERROR: sc->ic_iferrs ++; break; default: panic("%s: unknown event (%d)!", __func__, event); } crit_exit(); }
/* * icintr() */ static int icintr(device_t dev, int event, char *ptr) { struct ic_softc *sc = (struct ic_softc *)device_get_softc(dev); struct mbuf *top; int len; mtx_lock(&sc->ic_lock); switch (event) { case INTR_GENERAL: case INTR_START: sc->ic_cp = sc->ic_ifbuf; sc->ic_xfercnt = 0; sc->ic_flags |= IC_IFBUF_BUSY; break; case INTR_STOP: /* if any error occured during transfert, * drop the packet */ sc->ic_flags &= ~IC_IFBUF_BUSY; if ((sc->ic_flags & (IC_BUFFERS_BUSY | IC_BUFFER_WAITER)) == IC_BUFFER_WAITER) wakeup(&sc); if (sc->ic_iferrs) goto err; if ((len = sc->ic_xfercnt) == 0) break; /* ignore */ if (len <= ICHDRLEN) goto err; len -= ICHDRLEN; sc->ic_ifp->if_ipackets++; sc->ic_ifp->if_ibytes += len; BPF_TAP(sc->ic_ifp, sc->ic_ifbuf, len + ICHDRLEN); top = m_devget(sc->ic_ifbuf + ICHDRLEN, len, 0, sc->ic_ifp, 0); if (top) { mtx_unlock(&sc->ic_lock); M_SETFIB(top, sc->ic_ifp->if_fib); netisr_dispatch(NETISR_IP, top); mtx_lock(&sc->ic_lock); } break; err: if_printf(sc->ic_ifp, "errors (%d)!\n", sc->ic_iferrs); sc->ic_iferrs = 0; /* reset error count */ sc->ic_ifp->if_ierrors++; break; case INTR_RECEIVE: if (sc->ic_xfercnt >= sc->ic_ifp->if_mtu + ICHDRLEN) { sc->ic_iferrs++; } else { *sc->ic_cp++ = *ptr; sc->ic_xfercnt++; } break; case INTR_NOACK: /* xfer terminated by master */ break; case INTR_TRANSMIT: *ptr = 0xff; /* XXX */ break; case INTR_ERROR: sc->ic_iferrs++; break; default: panic("%s: unknown event (%d)!", __func__, event); } mtx_unlock(&sc->ic_lock); return (0); }
/* * Start transmission on an interface. */ static void iestart(struct ifnet *ifp) { struct ie_softc *sc = ifp->if_softc; struct mbuf *m0, *m; volatile unsigned char *buffer; u_short len; /* * This is not really volatile, in this routine, but it makes gcc * happy. */ volatile u_short *bptr = &sc->scb->ie_command_list; if (!(ifp->if_flags & IFF_RUNNING)) return; if (ifp->if_flags & IFF_OACTIVE) return; do { IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); if (!m) break; buffer = sc->xmit_cbuffs[sc->xmit_count]; len = 0; for (m0 = m; m && len < IE_BUF_LEN; m = m->m_next) { bcopy(mtod(m, caddr_t), buffer, m->m_len); buffer += m->m_len; len += m->m_len; } m_freem(m0); len = max(len, ETHER_MIN_LEN); /* * See if bpf is listening on this interface, let it see the * packet before we commit it to the wire. */ BPF_TAP(&sc->arpcom.ac_if, (void *)sc->xmit_cbuffs[sc->xmit_count], len); sc->xmit_buffs[sc->xmit_count]->ie_xmit_flags = IE_XMIT_LAST|len; sc->xmit_buffs[sc->xmit_count]->ie_xmit_next = 0xffff; sc->xmit_buffs[sc->xmit_count]->ie_xmit_buf = MK_24(sc->iomem, sc->xmit_cbuffs[sc->xmit_count]); sc->xmit_cmds[sc->xmit_count]->com.ie_cmd_cmd = IE_CMD_XMIT; sc->xmit_cmds[sc->xmit_count]->ie_xmit_status = 0; sc->xmit_cmds[sc->xmit_count]->ie_xmit_desc = MK_16(sc->iomem, sc->xmit_buffs[sc->xmit_count]); *bptr = MK_16(sc->iomem, sc->xmit_cmds[sc->xmit_count]); bptr = &sc->xmit_cmds[sc->xmit_count]->com.ie_cmd_link; sc->xmit_count++; } while (sc->xmit_count < sc->ntxbufs); /* * If we queued up anything for transmission, send it. */ if (sc->xmit_count) { sc->xmit_cmds[sc->xmit_count - 1]->com.ie_cmd_cmd |= IE_CMD_LAST | IE_CMD_INTR; /* * By passing the command pointer as a null, we tell * command_and_wait() to pretend that this isn't an action * command. I wish I understood what was happening here. */ command_and_wait(sc, IE_CU_START, 0, 0); ifp->if_flags |= IFF_OACTIVE; } return; }
/* 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)); } }