Esempio n. 1
0
/*
 * 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();
}
Esempio n. 2
0
/*
 * 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);
}
Esempio n. 3
0
File: if_ie.c Progetto: MarginC/kame
/*
 * 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;
}
Esempio n. 4
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));
	}
}