Ejemplo n.º 1
0
/*
 * End of sending
 */
static void
lgue_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
{
	struct ifnet *ifp;
	struct lgue_softc *sc;
	usbd_status err;

	sc = priv;
	if (sc->lgue_dying)
		return;

	ifp = &sc->lgue_arpcom.ac_if;

	if (status != USBD_NORMAL_COMPLETION) {
		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
			return;
		if (status == USBD_STALLED)
			usbd_clear_endpoint_stall(sc->lgue_ep[LGUE_ENDPT_TX]);
		return;
	}
	usbd_get_xfer_status(sc->lgue_tx_xfer, NULL, NULL, NULL,&err);
	if (err)
		IFNET_STAT_INC(ifp, oerrors, 1);
	else
		IFNET_STAT_INC(ifp, opackets, 1);

	if (!STAILQ_EMPTY(&sc->lgue_tx_queue)) {
		if_devstart_sched(ifp);
	}

	ifp->if_timer = 0;
	ifq_clr_oactive(&ifp->if_snd);
}
Ejemplo n.º 2
0
int
uether_rxbuf(struct usb_ether *ue, struct usb_page_cache *pc, 
    unsigned int offset, unsigned int len)
{
	struct ifnet *ifp = uether_getifp(ue);
	struct mbuf *m;

	UE_LOCK_ASSERT(ue);

	if (len < ETHER_HDR_LEN || len > MCLBYTES - ETHER_ALIGN)
		return (1);

	m = uether_newbuf();
	if (m == NULL) {
		IFNET_STAT_INC(ifp, iqdrops, 1);
		return (ENOMEM);
	}

	usbd_copy_out(pc, offset, mtod(m, uint8_t *), len);

	/* finalize mbuf */
	IFNET_STAT_INC(ifp, ipackets, 1);
	m->m_pkthdr.rcvif = ifp;
	m->m_pkthdr.len = m->m_len = len;

	/* enqueue for later when the lock can be released */
	IF_ENQUEUE(&ue->ue_rxq, m);
	return (0);
}
Ejemplo n.º 3
0
/*
 * A frame has been uploaded: pass the resulting mbuf up to
 * the higher level protocols.
 */
static void
lgue_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
{
	struct lgue_softc	*sc;
	struct mbuf		*m;
	struct ifnet	*ifp;
	int			total_len;

	sc = priv;
	if (sc->lgue_dying)
		return;

	ifp = &sc->lgue_arpcom.ac_if;

	total_len = 0;

	if (!(ifp->if_flags & IFF_RUNNING))
		return;

	if (status != USBD_NORMAL_COMPLETION) {
		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
			return;
		if (usbd_ratecheck(&sc->lgue_rx_notice)) {
			if_printf(ifp, "usb error on rx:%s\n",
			    usbd_errstr(status));
		}
		if (status == USBD_STALLED)
			usbd_clear_endpoint_stall(sc->lgue_ep[LGUE_ENDPT_RX]);
		goto done;
	}

	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);

	if (total_len < sizeof(struct ether_header)) {
		IFNET_STAT_INC(ifp, ierrors, 1);
		goto done;
	}

	if (lgue_newbuf(sc, total_len, &m) == ENOBUFS) {
		IFNET_STAT_INC(ifp, ierrors, 1);
		return;
	}

	IFNET_STAT_INC(ifp, ipackets, 1);
	m_copyback(m, 0, total_len, sc->lgue_rx_buf);
	m->m_pkthdr.rcvif = ifp;
	m->m_pkthdr.len = m->m_len = total_len;

	usb_ether_input(m);
	lgue_rxstart(ifp);
	return;
done:
	usbd_setup_xfer(sc->lgue_rx_xfer, sc->lgue_ep[LGUE_ENDPT_RX], sc,
	    sc->lgue_rx_buf, LGUE_BUFSZ,
	    USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, lgue_rxeof);
	usbd_transfer(sc->lgue_rx_xfer);
}
Ejemplo n.º 4
0
static int
ng_iface_output_serialized(struct ifnet *ifp, struct mbuf *m,
			   struct sockaddr *dst, struct rtentry *rt0)
{
	const priv_p priv = (priv_p) ifp->if_softc;
	const iffam_p iffam = get_iffam_from_af(dst->sa_family);
	meta_p meta = NULL;
	int len, error = 0;

	/* Check interface flags */
	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
		m_freem(m);
		return (ENETDOWN);
	}

	/* BPF writes need to be handled specially */
	if (dst->sa_family == AF_UNSPEC) {
		if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL)
			return (ENOBUFS);
		dst->sa_family = (sa_family_t)*mtod(m, int32_t *);
		m->m_data += 4;
		m->m_len -= 4;
		m->m_pkthdr.len -= 4;
	}

	/* Berkeley packet filter */
	ng_iface_bpftap(ifp, m, dst->sa_family);

	/* Check address family to determine hook (if known) */
	if (iffam == NULL) {
		m_freem(m);
		log(LOG_WARNING, "%s: can't handle af%d\n",
		       ifp->if_xname, (int)dst->sa_family);
		return (EAFNOSUPPORT);
	}

	/* Copy length before the mbuf gets invalidated */
	len = m->m_pkthdr.len;

	/* Send packet; if hook is not connected, mbuf will get freed. */
	NG_SEND_DATA(error, *get_hook_from_iffam(priv, iffam), m, meta);

	/* Update stats */
	if (error == 0) {
		IFNET_STAT_INC(ifp, obytes, len);
		IFNET_STAT_INC(ifp, opackets, 1);
	}
	return (error);
}
Ejemplo n.º 5
0
static int
null_transmit(struct ifnet *ifp, struct mbuf *m)
{
	m_freem(m);
	IFNET_STAT_INC(ifp, oerrors, 1);
	return EACCES;		/* XXX EIO/EPERM? */
}
Ejemplo n.º 6
0
/*
 * Watchdog
 */
static void
lgue_watchdog(struct ifnet *ifp)
{
	IFNET_STAT_INC(ifp, oerrors, 1);

	if (!ifq_is_empty(&ifp->if_snd))
		if_devstart_sched(ifp);
}
Ejemplo n.º 7
0
/*
 * After a change in the NPmode for some NP, move packets from the
 * npqueue to the send queue or the fast queue as appropriate.
 * Should be called at spl[soft]net.
 */
static void
ppp_requeue(struct ppp_softc *sc)
{
    struct mbuf *m, **mpp;
    struct ifqueue *ifq;
    struct ifaltq_subque *ifsq;
    enum NPmode mode;
    int error;

    ifsq = ifq_get_subq_default(&sc->sc_if.if_snd);
    for (mpp = &sc->sc_npqueue; (m = *mpp) != NULL; ) {
	switch (PPP_PROTOCOL(mtod(m, u_char *))) {
	case PPP_IP:
	    mode = sc->sc_npmode[NP_IP];
	    break;
	default:
	    mode = NPMODE_PASS;
	}

	switch (mode) {
	case NPMODE_PASS:
	    /*
	     * This packet can now go on one of the queues to be sent.
	     */
	    *mpp = m->m_nextpkt;
	    m->m_nextpkt = NULL;
	    if ((m->m_flags & M_HIGHPRI) && !ifq_is_enabled(&sc->sc_if.if_snd)) {
		ifq = &sc->sc_fastq;
		if (IF_QFULL(ifq)) {
		    IF_DROP(ifq);
		    error = ENOBUFS;
		} else {
		    IF_ENQUEUE(ifq, m);
		    error = 0;
		}
	    } else {
		error = ifsq_enqueue(ifsq, m, NULL);
	    }
	    if (error) {
		    IFNET_STAT_INC(&sc->sc_if, oerrors, 1);
		    sc->sc_stats.ppp_oerrors++;
	    }
	    break;

	case NPMODE_DROP:
	case NPMODE_ERROR:
	    *mpp = m->m_nextpkt;
	    m_freem(m);
	    break;

	case NPMODE_QUEUE:
	    mpp = &m->m_nextpkt;
	    break;
	}
    }
    sc->sc_npqtail = mpp;
}
Ejemplo n.º 8
0
static void
sbsh_intr(void *arg)
{
	struct sbsh_softc  *sc = (struct sbsh_softc *)arg;
	u_int8_t  status = sc->regs->SR;

	if (status == 0)
		return;

	if (status & EXT) {
		cx28975_interrupt(sc);
		sc->regs->SR = EXT;
	}

	if (status & UFL) {
		resume_tx(sc);
		sc->regs->SR = UFL;
		++sc->in_stats.ufl_errs;
		IFNET_STAT_INC(&sc->arpcom.ac_if, oerrors, 1);
	}

	if (status & RXS) {
		sc->regs->SR = RXS;
		indicate_frames(sc);
		alloc_rx_buffers(sc);
	}

	if (status & TXS) {
		sc->regs->SR = TXS;
		free_sent_buffers(sc);
	}

	if (status & CRC) {
		++sc->in_stats.crc_errs;
		IFNET_STAT_INC(&sc->arpcom.ac_if, ierrors, 1);
		sc->regs->SR = CRC;
	}

	if (status & OFL) {
		++sc->in_stats.ofl_errs;
		IFNET_STAT_INC(&sc->arpcom.ac_if, ierrors, 1);
		sc->regs->SR = OFL;
	}
}
Ejemplo n.º 9
0
static int
looutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
	 struct rtentry *rt)
{
	M_ASSERTPKTHDR(m);

	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
		m_freem(m);
		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
		        rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
	}

	IFNET_STAT_INC(ifp, opackets, 1);
	IFNET_STAT_INC(ifp, obytes, m->m_pkthdr.len);
#if 1	/* XXX */
	switch (dst->sa_family) {
	case AF_INET:
	case AF_INET6:
		break;
	default:
		kprintf("looutput: af=%d unexpected\n", dst->sa_family);
		m_freem(m);
		return (EAFNOSUPPORT);
	}
#endif

	if (ifp->if_capenable & IFCAP_RXCSUM) {
		int csum_flags = 0;

		if (m->m_pkthdr.csum_flags & CSUM_IP)
			csum_flags |= (CSUM_IP_CHECKED | CSUM_IP_VALID);
		if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA)
			csum_flags |= (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);

		m->m_pkthdr.csum_flags |= csum_flags;
		if (csum_flags & CSUM_DATA_VALID)
			m->m_pkthdr.csum_data = 0xffff;
	}
	return (if_simloop(ifp, m, dst->sa_family, 0));
}
Ejemplo n.º 10
0
/*
 * Process a received frame in monitor mode.
 */
static int
monitor_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
{
    struct ieee80211vap *vap = ni->ni_vap;
    struct ifnet *ifp = vap->iv_ifp;

    IFNET_STAT_INC(ifp, ipackets, 1);

    if (ieee80211_radiotap_active_vap(vap))
        ieee80211_radiotap_rx(vap, m);
    m_freem(m);
    return -1;
}
Ejemplo n.º 11
0
int
uether_rxmbuf(struct usb_ether *ue, struct mbuf *m, 
    unsigned int len)
{
	struct ifnet *ifp = uether_getifp(ue);

	UE_LOCK_ASSERT(ue);

	/* finalize mbuf */
	IFNET_STAT_INC(ifp, ipackets, 1);
	m->m_pkthdr.rcvif = ifp;
	m->m_pkthdr.len = m->m_len = len;

	/* enqueue for later when the lock can be released */
	IF_ENQUEUE(&ue->ue_rxq, m);
	return (0);
}
Ejemplo n.º 12
0
static void
encap_frame(struct sbsh_softc *sc, struct mbuf *m_head)
{
	struct mbuf	*m;
	u_int32_t	cur_tbd;
	int  done;

look_for_nonzero:
	for (m = m_head; !m->m_len; m = m->m_next)
		;

	cur_tbd = sc->regs->LTDR & 0x7f;
	done = 0;
	do {
		if (m->m_len < 5 || cur_tbd == ((sc->head_tdesc - 1) & 0x7f)) {
			if ((m_head = repack(sc, m_head)) != NULL)
				goto look_for_nonzero;
			else
				return;
		}

		sc->tbd[cur_tbd].address = vtophys(mtod(m, vm_offset_t));
		sc->tbd[cur_tbd].length  = m->m_len;

		do {
			m = m->m_next;
		} while (m && !m->m_len);

		if (!m) {	/* last fragment has been reached */
			sc->tbd[cur_tbd].length |= LAST_FRAG;
			done = 1;
		}

		++cur_tbd;
		cur_tbd &= 0x7f;
	} while (!done);

	sc->xq[sc->tail_xq++] = m_head;
	sc->tail_xq &= (XQLEN - 1);

	sc->regs->LTDR = cur_tbd;
	++sc->in_stats.sent_pkts;
	IFNET_STAT_INC(&sc->arpcom.ac_if, opackets, 1);
}
Ejemplo n.º 13
0
static void
indicate_frames(struct sbsh_softc *sc)
{
	struct ifnet *ifp = &sc->arpcom.ac_if;
	unsigned  cur_rbd = sc->regs->CRDR & 0x7f;

	while (sc->head_rdesc != cur_rbd) {
		struct mbuf  *m = sc->rq[sc->head_rq++];
		sc->head_rq &= (RQLEN - 1);

		m->m_pkthdr.len = m->m_len =
				sc->rbd[sc->head_rdesc].length & 0x7ff;
		m->m_pkthdr.rcvif = ifp;

		ifp->if_input(ifp, m, NULL, -1);
		++sc->in_stats.rcvd_pkts;
		IFNET_STAT_INC(ifp, ipackets, 1);

		sc->head_rdesc = (sc->head_rdesc + 1) & 0x7f;
	}
}
Ejemplo n.º 14
0
/*
 * Queue a packet.  Start transmission if not active.
 * Packet is placed in Information field of PPP frame.
 * Called at splnet as the if->if_output handler.
 * Called at splnet from pppwrite().
 */
static int
pppoutput_serialized(struct ifnet *ifp, struct ifaltq_subque *ifsq,
    struct mbuf *m0, struct sockaddr *dst, struct rtentry *rtp)
{
    struct ppp_softc *sc = &ppp_softc[ifp->if_dunit];
    int protocol, address, control;
    u_char *cp;
    int error;
#ifdef INET
    struct ip *ip;
#endif
    struct ifqueue *ifq;
    enum NPmode mode;
    int len;
    struct mbuf *m;
    struct altq_pktattr pktattr;

    if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0
	|| ((ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC)) {
	error = ENETDOWN;	/* sort of */
	goto bad;
    }

    ifq_classify(&ifp->if_snd, m0, dst->sa_family, &pktattr);

    /*
     * Compute PPP header.
     */
    m0->m_flags &= ~M_HIGHPRI;
    switch (dst->sa_family) {
#ifdef INET
    case AF_INET:
	address = PPP_ALLSTATIONS;
	control = PPP_UI;
	protocol = PPP_IP;
	mode = sc->sc_npmode[NP_IP];

	/*
	 * If this packet has the "low delay" bit set in the IP header,
	 * put it on the fastq instead.
	 */
	ip = mtod(m0, struct ip *);
	if (ip->ip_tos & IPTOS_LOWDELAY)
	    m0->m_flags |= M_HIGHPRI;
	break;
#endif
#ifdef IPX
    case AF_IPX:
	/*
	 * This is pretty bogus.. We dont have an ipxcp module in pppd
	 * yet to configure the link parameters.  Sigh. I guess a
	 * manual ifconfig would do....  -Peter
	 */
	address = PPP_ALLSTATIONS;
	control = PPP_UI;
	protocol = PPP_IPX;
	mode = NPMODE_PASS;
	break;
#endif
    case AF_UNSPEC:
	address = PPP_ADDRESS(dst->sa_data);
	control = PPP_CONTROL(dst->sa_data);
	protocol = PPP_PROTOCOL(dst->sa_data);
	mode = NPMODE_PASS;
	break;
    default:
	kprintf("%s: af%d not supported\n", ifp->if_xname, dst->sa_family);
	error = EAFNOSUPPORT;
	goto bad;
    }

    /*
     * Drop this packet, or return an error, if necessary.
     */
    if (mode == NPMODE_ERROR) {
	error = ENETDOWN;
	goto bad;
    }
    if (mode == NPMODE_DROP) {
	error = 0;
	goto bad;
    }

    /*
     * Add PPP header.  If no space in first mbuf, allocate another.
     * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.)
     */
    if (M_LEADINGSPACE(m0) < PPP_HDRLEN) {
	m0 = m_prepend(m0, PPP_HDRLEN, MB_DONTWAIT);
	if (m0 == NULL) {
	    error = ENOBUFS;
	    goto bad;
	}
	m0->m_len = 0;
    } else
	m0->m_data -= PPP_HDRLEN;

    cp = mtod(m0, u_char *);
    *cp++ = address;
    *cp++ = control;
    *cp++ = protocol >> 8;
    *cp++ = protocol & 0xff;
    m0->m_len += PPP_HDRLEN;

    len = 0;
    for (m = m0; m != NULL; m = m->m_next)
	len += m->m_len;

    if (sc->sc_flags & SC_LOG_OUTPKT) {
	kprintf("%s output: ", ifp->if_xname);
	pppdumpm(m0);
    }

    if ((protocol & 0x8000) == 0) {
#ifdef PPP_FILTER
	/*
	 * Apply the pass and active filters to the packet,
	 * but only if it is a data packet.
	 */
	*mtod(m0, u_char *) = 1;	/* indicates outbound */
	if (sc->sc_pass_filt.bf_insns != NULL
	    && bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m0,
			  len, 0) == 0) {
	    error = 0;		/* drop this packet */
	    goto bad;
	}

	/*
	 * Update the time we sent the most recent packet.
	 */
	if (sc->sc_active_filt.bf_insns == NULL
	    || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m0, len, 0))
	    sc->sc_last_sent = time_uptime;

	*mtod(m0, u_char *) = address;
#else
	/*
	 * Update the time we sent the most recent data packet.
	 */
	sc->sc_last_sent = time_uptime;
#endif /* PPP_FILTER */
    }

    BPF_MTAP(ifp, m0);

    /*
     * Put the packet on the appropriate queue.
     */
    crit_enter();
    if (mode == NPMODE_QUEUE) {
	/* XXX we should limit the number of packets on this queue */
	*sc->sc_npqtail = m0;
	m0->m_nextpkt = NULL;
	sc->sc_npqtail = &m0->m_nextpkt;
    } else {
	/* fastq and if_snd are emptied at spl[soft]net now */
	if ((m0->m_flags & M_HIGHPRI) && !ifq_is_enabled(&sc->sc_if.if_snd)) {
	    ifq = &sc->sc_fastq;
	    if (IF_QFULL(ifq) && dst->sa_family != AF_UNSPEC) {
	        IF_DROP(ifq);
	        m_freem(m0);
	        error = ENOBUFS;
	    } else {
	        IF_ENQUEUE(ifq, m0);
	        error = 0;
	    }
	} else {
	    ASSERT_ALTQ_SQ_SERIALIZED_HW(ifsq);
	    error = ifsq_enqueue(ifsq, m0, &pktattr);
	}
	if (error) {
	    crit_exit();
	    IFNET_STAT_INC(&sc->sc_if, oerrors, 1);
	    sc->sc_stats.ppp_oerrors++;
	    return (error);
	}
	(*sc->sc_start)(sc);
    }
    getmicrotime(&ifp->if_lastchange);
    IFNET_STAT_INC(ifp, opackets, 1);
    IFNET_STAT_INC(ifp, obytes, len);

    crit_exit();
    return (0);

bad:
    m_freem(m0);
    return (error);
}
Ejemplo n.º 15
0
static void
ipheth_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct ipheth_softc *sc = usbd_xfer_softc(xfer);
	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
	struct usb_page_cache *pc;
	struct mbuf *m;
	uint8_t x;
	int actlen;
	int aframes;

	usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);

	DPRINTFN(1, "\n");

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:
		DPRINTFN(11, "transfer complete: %u bytes in %u frames\n",
		    actlen, aframes);

		IFNET_STAT_INC(ifp, opackets, 1);

		/* free all previous TX buffers */
		ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX);

		/* FALLTHROUGH */
	case USB_ST_SETUP:
tr_setup:
		for (x = 0; x != IPHETH_TX_FRAMES_MAX; x++) {

			m = ifq_dequeue(&ifp->if_snd);

			if (m == NULL)
				break;

			usbd_xfer_set_frame_offset(xfer,
			    x * IPHETH_BUF_SIZE, x);

			pc = usbd_xfer_get_frame(xfer, x);

			sc->sc_tx_buf[x] = m;

			if (m->m_pkthdr.len > IPHETH_BUF_SIZE)
				m->m_pkthdr.len = IPHETH_BUF_SIZE;

			usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);

			usbd_xfer_set_frame_len(xfer, x, IPHETH_BUF_SIZE);

			if (IPHETH_BUF_SIZE != m->m_pkthdr.len) {
				usbd_frame_zero(pc, m->m_pkthdr.len,
					IPHETH_BUF_SIZE - m->m_pkthdr.len);
			}

			/*
			 * If there's a BPF listener, bounce a copy of
			 * this frame to him:
			 */
			BPF_MTAP(ifp, m);
		}
		if (x != 0) {
			usbd_xfer_set_frames(xfer, x);

			usbd_transfer_submit(xfer);
		}
		break;

	default:			/* Error */
		DPRINTFN(11, "transfer error, %s\n",
		    usbd_errstr(error));

		/* free all previous TX buffers */
		ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX);

		/* count output errors */
		IFNET_STAT_INC(ifp, oerrors, 1);

		if (error != USB_ERR_CANCELLED) {
			/* try to clear stall first */
			usbd_xfer_set_stall(xfer);
			goto tr_setup;
		}
		break;
	}
}
Ejemplo n.º 16
0
static void
ep_if_start(struct ifnet *ifp, struct ifaltq_subque *ifsq)
{
    struct ep_softc *sc = ifp->if_softc;
    u_int len;
    struct mbuf *m;
    struct mbuf *top;
    int pad;

    ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq);

    if (sc->gone) {
	ifq_purge(&ifp->if_snd);
	return;
    }

    while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
    if (ifq_is_oactive(&ifp->if_snd)) {
	return;
    }

    crit_enter();

startagain:
    /* Sneak a peek at the next packet */
    m = ifq_dequeue(&ifp->if_snd, NULL);
    if (m == NULL) {
	crit_exit();
	return;
    }

    for (len = 0, top = m; m; m = m->m_next)
	len += m->m_len;
    m = top;

    pad = padmap[len & 3];

    /*
     * The 3c509 automatically pads short packets to minimum ethernet length,
     * but we drop packets that are too large. Perhaps we should truncate
     * them instead?
     */
    if (len + pad > ETHER_MAX_LEN) {
	/* packet is obviously too large: toss it */
	IFNET_STAT_INC(ifp, oerrors, 1);
	m_freem(m);
	goto readcheck;
    }
    if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) {
	/* no room in FIFO */
	outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4));
	/* make sure */
	if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) {
	    ifq_set_oactive(&ifp->if_snd);
	    ifq_prepend(&ifp->if_snd, top);
	    crit_exit();
	    return;
	}
    } else {
	outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | EP_THRESH_DISABLE);
    }

    outw(BASE + EP_W1_TX_PIO_WR_1, len); 
    outw(BASE + EP_W1_TX_PIO_WR_1, 0x0);	/* Second dword meaningless */

    if (EP_FTST(sc, F_ACCESS_32_BITS)) {
        for (top = m; m != NULL; m = m->m_next) {
	    outsl(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t),
		  m->m_len / 4);
	    if (m->m_len & 3)
		outsb(BASE + EP_W1_TX_PIO_WR_1,
		      mtod(m, caddr_t) + (m->m_len & (~3)),
		      m->m_len & 3);
	}
    } else {
        for (top = m; m != NULL; m = m->m_next) {
	    outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len / 2);
	    if (m->m_len & 1)
		outb(BASE + EP_W1_TX_PIO_WR_1,
		     *(mtod(m, caddr_t) + m->m_len - 1));
	}
    }

    while (pad--)
	outb(BASE + EP_W1_TX_PIO_WR_1, 0);	/* Padding */

    BPF_MTAP(ifp, top);

    ifp->if_timer = 2;
    IFNET_STAT_INC(ifp, opackets, 1);
    m_freem(top);

    /*
     * Is another packet coming in? We don't want to overflow the tiny RX
     * fifo.
     */
readcheck:
    if (inw(BASE + EP_W1_RX_STATUS) & RX_BYTES_MASK) {
	/*
	 * we check if we have packets left, in that case we prepare to come
	 * back later
	 */
	if (!ifq_is_empty(&ifp->if_snd))
	    outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8);

        crit_exit();
	return;
    }
    goto startagain;
}
Ejemplo n.º 17
0
static void
epread(struct ep_softc *sc)
{
    struct mbuf *top, *mcur, *m;
    struct ifnet *ifp;
    int lenthisone;

    short rx_fifo2, status;
    short rx_fifo;

    ifp = &sc->arpcom.ac_if;
    status = inw(BASE + EP_W1_RX_STATUS);

read_again:

    if (status & ERR_RX) {
	IFNET_STAT_INC(ifp, ierrors, 1);
	if (status & ERR_RX_OVERRUN) {
	    /*
	     * we can think the rx latency is actually greather than we
	     * expect
	     */
#ifdef EP_LOCAL_STATS
	    if (EP_FTST(sc, F_RX_FIRST))
		sc->rx_overrunf++;
	    else
		sc->rx_overrunl++;
#endif
	}
	goto out;
    }
    rx_fifo = rx_fifo2 = status & RX_BYTES_MASK;

    if (EP_FTST(sc, F_RX_FIRST)) {
	m = m_getl(rx_fifo, MB_DONTWAIT, MT_DATA, M_PKTHDR, NULL);
	if (!m)
	    goto out;
	sc->top = sc->mcur = top = m;
#define EROUND  ((sizeof(struct ether_header) + 3) & ~3)
#define EOFF    (EROUND - sizeof(struct ether_header))
	top->m_data += EOFF;

	/* Read what should be the header. */
	insw(BASE + EP_W1_RX_PIO_RD_1,
	     mtod(top, caddr_t), sizeof(struct ether_header) / 2);
	top->m_len = sizeof(struct ether_header);
	rx_fifo -= sizeof(struct ether_header);
	sc->cur_len = rx_fifo2;
    } else {
	/* come here if we didn't have a complete packet last time */
	top = sc->top;
	m = sc->mcur;
	sc->cur_len += rx_fifo2;
    }

    /* Reads what is left in the RX FIFO */
    while (rx_fifo > 0) {
	lenthisone = min(rx_fifo, M_TRAILINGSPACE(m));
	if (lenthisone == 0) {	/* no room in this one */
	    mcur = m;
	    m = m_getl(rx_fifo, MB_DONTWAIT, MT_DATA, 0, NULL);
	    if (!m)
		goto out;
	    m->m_len = 0;
	    mcur->m_next = m;
	    lenthisone = min(rx_fifo, M_TRAILINGSPACE(m));
	}
	if (EP_FTST(sc, F_ACCESS_32_BITS)) { /* default for EISA configured cards*/
	    insl(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
		 lenthisone / 4);
	    m->m_len += (lenthisone & ~3);
	    if (lenthisone & 3)
		insb(BASE + EP_W1_RX_PIO_RD_1,
		     mtod(m, caddr_t) + m->m_len,
		     lenthisone & 3);
	    m->m_len += (lenthisone & 3);
	} else {
	    insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
		 lenthisone / 2);
	    m->m_len += lenthisone;
	    if (lenthisone & 1)
		*(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1);
	}
	rx_fifo -= lenthisone;
    }

    if (status & ERR_RX_INCOMPLETE) {	/* we haven't received the complete
					 * packet */
	sc->mcur = m;
#ifdef EP_LOCAL_STATS
	sc->rx_no_first++;	/* to know how often we come here */
#endif
	EP_FRST(sc, F_RX_FIRST);
	if (!((status = inw(BASE + EP_W1_RX_STATUS)) & ERR_RX_INCOMPLETE)) {
	    /* we see if by now, the packet has completly arrived */
	    goto read_again;
	}
	outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_NEXT_EARLY_THRESH);
	return;
    }
    outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
    IFNET_STAT_INC(ifp, ipackets, 1);
    EP_FSET(sc, F_RX_FIRST);
    top->m_pkthdr.rcvif = &sc->arpcom.ac_if;
    top->m_pkthdr.len = sc->cur_len;

    ifp->if_input(ifp, top);
    sc->top = 0;
    while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
    outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);
    return;

out:
    outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
    if (sc->top) {
	m_freem(sc->top);
	sc->top = 0;
#ifdef EP_LOCAL_STATS
	sc->rx_no_mbuf++;
#endif
    }
    EP_FSET(sc, F_RX_FIRST);
    while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
    outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);
}
Ejemplo n.º 18
0
void
ep_intr(void *arg)
{
    struct ep_softc *sc = arg;
    struct ifnet *ifp = &sc->arpcom.ac_if;
    int status;

     /*
      * quick fix: Try to detect an interrupt when the card goes away.
      */
    if (sc->gone || inw(BASE + EP_STATUS) == 0xffff) {
	    return;
    }

    outw(BASE + EP_COMMAND, SET_INTR_MASK); /* disable all Ints */

rescan:

    while ((status = inw(BASE + EP_STATUS)) & S_5_INTS) {

	/* first acknowledge all interrupt sources */
	outw(BASE + EP_COMMAND, ACK_INTR | (status & S_MASK));

	if (status & (S_RX_COMPLETE | S_RX_EARLY))
	    epread(sc);
	if (status & S_TX_AVAIL) {
	    /* we need ACK */
	    ifp->if_timer = 0;
	    ifq_clr_oactive(&ifp->if_snd);
	    GO_WINDOW(1);
	    inw(BASE + EP_W1_FREE_TX);
	    if_devstart(ifp);
	}
	if (status & S_CARD_FAILURE) {
	    ifp->if_timer = 0;
#ifdef EP_LOCAL_STATS
	    kprintf("\n");
	    if_printf(ifp, "\n\tStatus: %x\n", status);
	    GO_WINDOW(4);
	    kprintf("\tFIFO Diagnostic: %x\n", inw(BASE + EP_W4_FIFO_DIAG));
	    kprintf("\tStat: %x\n", sc->stat);
	    kprintf("\tIpackets=%d, Opackets=%d\n",
		ifp->if_ipackets, ifp->if_opackets);
	    kprintf("\tNOF=%d, NOMB=%d, RXOF=%d, RXOL=%d, TXU=%d\n",
		   sc->rx_no_first, sc->rx_no_mbuf, sc->rx_overrunf,
		   sc->rx_overrunl, sc->tx_underrun);
#else

#ifdef DIAGNOSTIC
	    if_printf(ifp, "Status: %x (input buffer overflow)\n", status);
#else
	    IFNET_STAT_INC(ifp, ierrors, 1);
#endif

#endif
	    ep_if_init(sc);
	    return;
	}
	if (status & S_TX_COMPLETE) {
	    ifp->if_timer = 0;
	    /* we  need ACK. we do it at the end */
	    /*
	     * We need to read TX_STATUS until we get a 0 status in order to
	     * turn off the interrupt flag.
	     */
	    while ((status = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE) {
		if (status & TXS_SUCCES_INTR_REQ);
		else if (status & (TXS_UNDERRUN | TXS_JABBER | TXS_MAX_COLLISION)) {
		    outw(BASE + EP_COMMAND, TX_RESET);
		    if (status & TXS_UNDERRUN) {
#ifdef EP_LOCAL_STATS
			sc->tx_underrun++;
#endif
		    } else {
			if (status & TXS_JABBER);
			else	/* TXS_MAX_COLLISION - we shouldn't get here */
			    IFNET_STAT_INC(ifp, collisions, 1);
		    }
		    IFNET_STAT_INC(ifp, oerrors, 1);
		    outw(BASE + EP_COMMAND, TX_ENABLE);
		    /*
		     * To have a tx_avail_int but giving the chance to the
		     * Reception
		     */
		    if (!ifq_is_empty(&ifp->if_snd))
			outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8);
		}
		outb(BASE + EP_W1_TX_STATUS, 0x0);	/* pops up the next
							 * status */
	    }			/* while */
	    ifq_clr_oactive(&ifp->if_snd);
	    GO_WINDOW(1);
	    inw(BASE + EP_W1_FREE_TX);
	    if_devstart(ifp);
	}			/* end TX_COMPLETE */
    }

    outw(BASE + EP_COMMAND, C_INTR_LATCH);	/* ACK int Latch */

    if ((status = inw(BASE + EP_STATUS)) & S_5_INTS)
	goto rescan;

    /* re-enable Ints */
    outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS);
}
Ejemplo n.º 19
0
static void
am7990_rint(struct lance_softc *sc)
{
	struct ifnet *ifp = sc->ifp;
	struct mbuf *m;
	struct lermd rmd;
	int bix, rp;
#if defined(LANCE_REVC_BUG)
	struct ether_header *eh;
	/* Make sure this is short-aligned, for ether_cmp(). */
	static uint16_t bcast_enaddr[3] = { ~0, ~0, ~0 };
#endif

	bix = sc->sc_last_rd;

	/* Process all buffers with valid data. */
	for (;;) {
		rp = LE_RMDADDR(sc, bix);
		(*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd));

		if (rmd.rmd1_bits & LE_R1_OWN)
			break;

		m = NULL;
		if ((rmd.rmd1_bits & (LE_R1_ERR | LE_R1_STP | LE_R1_ENP)) !=
		    (LE_R1_STP | LE_R1_ENP)) {
			if (rmd.rmd1_bits & LE_R1_ERR) {
#ifdef LEDEBUG
				if (rmd.rmd1_bits & LE_R1_ENP) {
					if ((rmd.rmd1_bits & LE_R1_OFLO) == 0) {
						if (rmd.rmd1_bits & LE_R1_FRAM)
							if_printf(ifp,
							    "framing error\n");
						if (rmd.rmd1_bits & LE_R1_CRC)
							if_printf(ifp,
							    "crc mismatch\n");
					}
				} else
					if (rmd.rmd1_bits & LE_R1_OFLO)
						if_printf(ifp, "overflow\n");
#endif
				if (rmd.rmd1_bits & LE_R1_BUFF)
					if_printf(ifp,
					    "receive buffer error\n");
			} else if ((rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP)) !=
			    (LE_R1_STP | LE_R1_ENP))
				if_printf(ifp, "dropping chained buffer\n");
		} else {
#ifdef LEDEBUG
			if (sc->sc_flags & LE_DEBUG)
				am7990_recv_print(sc, bix);
#endif
			/* Pull the packet off the interface. */
			m = lance_get(sc, LE_RBUFADDR(sc, bix),
			    (int)rmd.rmd3 - ETHER_CRC_LEN);
		}

		rmd.rmd1_bits = LE_R1_OWN;
		rmd.rmd2 = -LEBLEN | LE_XMD2_ONES;
		rmd.rmd3 = 0;
		(*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));

		if (++bix == sc->sc_nrbuf)
			bix = 0;

		if (m != NULL) {
			IFNET_STAT_INC(ifp, ipackets, 1);

#ifdef LANCE_REVC_BUG
			/*
			 * The old LANCE (Rev. C) chips have a bug which
			 * causes garbage to be inserted in front of the
			 * received packet. The workaround is to ignore
			 * packets with an invalid destination address
			 * (garbage will usually not match).
			 * Of course, this precludes multicast support...
			 */
			eh = mtod(m, struct ether_header *);
			if (memcmp(eh->ether_dhost, sc->sc_enaddr,
				   ETHER_ADDR_LEN) &&
			    memcmp(eh->ether_dhost, etherbroadcastaddr,
				   ETHER_ADDR_LEN)) {
				m_freem(m);
				continue;
			}
#endif

			/* Pass the packet up. */
			(*ifp->if_input)(ifp, m);
		} else
Ejemplo n.º 20
0
static void
am79900_rint(struct lance_softc *sc)
{
	struct ifnet *ifp = sc->ifp;
	struct mbuf *m;
	struct lermd rmd;
	uint32_t rmd1;
	int bix, rp;
#if defined(__i386__)
	struct ether_header *eh;
#endif

	bix = sc->sc_last_rd;

	/* Process all buffers with valid data. */
	for (;;) {
		rp = LE_RMDADDR(sc, bix);
		(*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd));

		rmd1 = LE_LE32TOH(rmd.rmd1);
		if (rmd1 & LE_R1_OWN)
			break;

		m = NULL;
		if ((rmd1 & (LE_R1_ERR | LE_R1_STP | LE_R1_ENP)) !=
		    (LE_R1_STP | LE_R1_ENP)){
			if (rmd1 & LE_R1_ERR) {
#ifdef LEDEBUG
				if (rmd1 & LE_R1_ENP) {
					if ((rmd1 & LE_R1_OFLO) == 0) {
						if (rmd1 & LE_R1_FRAM)
							if_printf(ifp,
							    "framing error\n");
						if (rmd1 & LE_R1_CRC)
							if_printf(ifp,
							    "crc mismatch\n");
					}
				} else
					if (rmd1 & LE_R1_OFLO)
						if_printf(ifp, "overflow\n");
#endif
				if (rmd1 & LE_R1_BUFF)
					if_printf(ifp,
					    "receive buffer error\n");
			} else if ((rmd1 & (LE_R1_STP | LE_R1_ENP)) !=
			    (LE_R1_STP | LE_R1_ENP))
				if_printf(ifp, "dropping chained buffer\n");
		} else {
#ifdef LEDEBUG
			if (sc->sc_flags & LE_DEBUG)
				am79900_recv_print(sc, bix);
#endif
			/* Pull the packet off the interface. */
			m = lance_get(sc, LE_RBUFADDR(sc, bix),
			    (LE_LE32TOH(rmd.rmd2) & 0xfff) - ETHER_CRC_LEN);
		}

		rmd.rmd1 = LE_HTOLE32(LE_R1_OWN | LE_R1_ONES |
		    (-LEBLEN & 0xfff));
		rmd.rmd2 = 0;
		rmd.rmd3 = 0;
		(*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));

		if (++bix == sc->sc_nrbuf)
			bix = 0;

		if (m != NULL) {
			IFNET_STAT_INC(ifp, ipackets, 1);

#ifdef __i386__
			/*
			 * The VMware LANCE does not present IFF_SIMPLEX
			 * behavior on multicast packets. Thus drop the
			 * packet if it is from ourselves.
			 */
			eh = mtod(m, struct ether_header *);
			if (memcmp(eh->ether_shost, sc->sc_enaddr,
				   ETHER_ADDR_LEN) == 0) {
				m_freem(m);
				continue;
			}
#endif

			/* Pass the packet up. */
			(*ifp->if_input)(ifp, m);
		} else
Ejemplo n.º 21
0
void
sn_intr(void *arg)
{
	int             status, interrupts;
	struct sn_softc *sc = (struct sn_softc *) arg;
	struct ifnet   *ifp = &sc->arpcom.ac_if;

	/*
	 * Chip state registers
	 */
	u_char          mask;
	u_char          packet_no;
	u_short         tx_status;
	u_short         card_stats;

	/*
	 * Clear the watchdog.
	 */
	ifp->if_timer = 0;

	SMC_SELECT_BANK(2);

	/*
	 * Obtain the current interrupt mask and clear the hardware mask
	 * while servicing interrupts.
	 */
	mask = inb(BASE + INTR_MASK_REG_B);
	outb(BASE + INTR_MASK_REG_B, 0x00);

	/*
	 * Get the set of interrupts which occurred and eliminate any which
	 * are masked.
	 */
	interrupts = inb(BASE + INTR_STAT_REG_B);
	status = interrupts & mask;

	/*
	 * Now, process each of the interrupt types.
	 */

	/*
	 * Receive Overrun.
	 */
	if (status & IM_RX_OVRN_INT) {

		/*
		 * Acknowlege Interrupt
		 */
		SMC_SELECT_BANK(2);
		outb(BASE + INTR_ACK_REG_B, IM_RX_OVRN_INT);

		IFNET_STAT_INC(&sc->arpcom.ac_if, ierrors, 1);
	}
	/*
	 * Got a packet.
	 */
	if (status & IM_RCV_INT) {
#if 1
		int             packet_number;

		SMC_SELECT_BANK(2);
		packet_number = inw(BASE + FIFO_PORTS_REG_W);

		if (packet_number & FIFO_REMPTY) {

			/*
			 * we got called , but nothing was on the FIFO
			 */
			kprintf("sn: Receive interrupt with nothing on FIFO\n");

			goto out;
		}
#endif
		snread(ifp);
	}
	/*
	 * An on-card memory allocation came through.
	 */
	if (status & IM_ALLOC_INT) {

		/*
		 * Disable this interrupt.
		 */
		mask &= ~IM_ALLOC_INT;
		ifq_clr_oactive(&sc->arpcom.ac_if.if_snd);
		snresume(&sc->arpcom.ac_if);
	}
	/*
	 * TX Completion.  Handle a transmit error message. This will only be
	 * called when there is an error, because of the AUTO_RELEASE mode.
	 */
	if (status & IM_TX_INT) {

		/*
		 * Acknowlege Interrupt
		 */
		SMC_SELECT_BANK(2);
		outb(BASE + INTR_ACK_REG_B, IM_TX_INT);

		packet_no = inw(BASE + FIFO_PORTS_REG_W);
		packet_no &= FIFO_TX_MASK;

		/*
		 * select this as the packet to read from
		 */
		outb(BASE + PACKET_NUM_REG_B, packet_no);

		/*
		 * Position the pointer to the first word from this packet
		 */
		outw(BASE + POINTER_REG_W, PTR_AUTOINC | PTR_READ | 0x0000);

		/*
		 * Fetch the TX status word.  The value found here will be a
		 * copy of the EPH_STATUS_REG_W at the time the transmit
		 * failed.
		 */
		tx_status = inw(BASE + DATA_REG_W);

		if (tx_status & EPHSR_TX_SUC) {
			device_printf(sc->dev, 
			    "Successful packet caused interrupt\n");
		} else {
			IFNET_STAT_INC(&sc->arpcom.ac_if, oerrors, 1);
		}

		if (tx_status & EPHSR_LATCOL)
			IFNET_STAT_INC(&sc->arpcom.ac_if, collisions, 1);

		/*
		 * Some of these errors will have disabled transmit.
		 * Re-enable transmit now.
		 */
		SMC_SELECT_BANK(0);

#ifdef SW_PAD
		outw(BASE + TXMIT_CONTROL_REG_W, TCR_ENABLE);
#else
		outw(BASE + TXMIT_CONTROL_REG_W, TCR_ENABLE | TCR_PAD_ENABLE);
#endif	/* SW_PAD */

		/*
		 * kill the failed packet. Wait for the MMU to be un-busy.
		 */
		SMC_SELECT_BANK(2);
		while (inw(BASE + MMU_CMD_REG_W) & MMUCR_BUSY)	/* NOTHING */
			;
		outw(BASE + MMU_CMD_REG_W, MMUCR_FREEPKT);

		/*
		 * Attempt to queue more transmits.
		 */
		ifq_clr_oactive(&sc->arpcom.ac_if.if_snd);
		if_devstart(&sc->arpcom.ac_if);
	}
	/*
	 * Transmit underrun.  We use this opportunity to update transmit
	 * statistics from the card.
	 */
	if (status & IM_TX_EMPTY_INT) {

		/*
		 * Acknowlege Interrupt
		 */
		SMC_SELECT_BANK(2);
		outb(BASE + INTR_ACK_REG_B, IM_TX_EMPTY_INT);

		/*
		 * Disable this interrupt.
		 */
		mask &= ~IM_TX_EMPTY_INT;

		SMC_SELECT_BANK(0);
		card_stats = inw(BASE + COUNTER_REG_W);

		/*
		 * Single collisions
		 */
		IFNET_STAT_INC(&sc->arpcom.ac_if, collisions,
		    card_stats & ECR_COLN_MASK);

		/*
		 * Multiple collisions
		 */
		IFNET_STAT_INC(&sc->arpcom.ac_if, collisions,
		    (card_stats & ECR_MCOLN_MASK) >> 4);

		SMC_SELECT_BANK(2);

		/*
		 * Attempt to enqueue some more stuff.
		 */
		ifq_clr_oactive(&sc->arpcom.ac_if.if_snd);
		if_devstart(&sc->arpcom.ac_if);
	}
Ejemplo n.º 22
0
/* Resume a packet transmit operation after a memory allocation
 * has completed.
 *
 * This is basically a hacked up copy of snstart() which handles
 * a completed memory allocation the same way snstart() does.
 * It then passes control to snstart to handle any other queued
 * packets.
 */
static void
snresume(struct ifnet *ifp)
{
	struct sn_softc *sc = ifp->if_softc;
	u_int  len;
	struct mbuf *m;
	struct mbuf    *top;
	int             pad;
	int             mask;
	u_short         length;
	u_short         numPages;
	u_short         pages_wanted;
	u_char          packet_no;

	if (sc->pages_wanted < 0)
		return;

	pages_wanted = sc->pages_wanted;
	sc->pages_wanted = -1;

	/*
	 * Sneak a peek at the next packet
	 */
	m = ifq_dequeue(&ifp->if_snd);
	if (m == NULL) {
		kprintf("%s: snresume() with nothing to send\n",
			ifp->if_xname);
		return;
	}

	/*
	 * Compute the frame length and set pad to give an overall even
	 * number of bytes.  Below we assume that the packet length is even.
	 */
	for (len = 0, top = m; m; m = m->m_next)
		len += m->m_len;

	pad = (len & 1);

	/*
	 * We drop packets that are too large. Perhaps we should truncate
	 * them instead?
	 */
	if (len + pad > ETHER_MAX_LEN - ETHER_CRC_LEN) {
		kprintf("%s: large packet discarded (B)\n", ifp->if_xname);
		IFNET_STAT_INC(ifp, oerrors, 1);
		m_freem(top);
		return;
	}
#ifdef SW_PAD

	/*
	 * If HW padding is not turned on, then pad to ETHER_MIN_LEN.
	 */
	if (len < ETHER_MIN_LEN - ETHER_CRC_LEN)
		pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len;

#endif	/* SW_PAD */

	length = pad + len;


	/*
	 * The MMU wants the number of pages to be the number of 256 byte
	 * 'pages', minus 1 (A packet can't ever have 0 pages. We also
	 * include space for the status word, byte count and control bytes in
	 * the allocation request.
	 */
	numPages = (length + 6) >> 8;


	SMC_SELECT_BANK(2);

	/*
	 * The memory allocation completed.  Check the results. If it failed,
	 * we simply set a watchdog timer and hope for the best.
	 */
	packet_no = inb(BASE + ALLOC_RESULT_REG_B);
	if (packet_no & ARR_FAILED) {
		kprintf("%s: Memory allocation failed.  Weird.\n", ifp->if_xname);
		ifp->if_timer = 1;
		ifq_prepend(&ifp->if_snd, top);
		goto try_start;
	}
	/*
	 * We have a packet number, so tell the card to use it.
	 */
	outb(BASE + PACKET_NUM_REG_B, packet_no);

	/*
	 * Now, numPages should match the pages_wanted recorded when the
	 * memory allocation was initiated.
	 */
	if (pages_wanted != numPages) {
		kprintf("%s: memory allocation wrong size.  Weird.\n", ifp->if_xname);
		/*
		 * If the allocation was the wrong size we simply release the
		 * memory once it is granted. Wait for the MMU to be un-busy.
		 */
		while (inw(BASE + MMU_CMD_REG_W) & MMUCR_BUSY)	/* NOTHING */
			;
		outw(BASE + MMU_CMD_REG_W, MMUCR_FREEPKT);

		ifq_prepend(&ifp->if_snd, top);
		return;
	}
	/*
	 * Point to the beginning of the packet
	 */
	outw(BASE + POINTER_REG_W, PTR_AUTOINC | 0x0000);

	/*
	 * Send the packet length (+6 for status, length and control byte)
	 * and the status word (set to zeros)
	 */
	outw(BASE + DATA_REG_W, 0);
	outb(BASE + DATA_REG_B, (length + 6) & 0xFF);
	outb(BASE + DATA_REG_B, (length + 6) >> 8);

	/*
	 * Push out the data to the card.
	 */
	for (m = top; m != NULL; m = m->m_next) {

		/*
		 * Push out words.
		 */
		outsw(BASE + DATA_REG_W, mtod(m, caddr_t), m->m_len / 2);

		/*
		 * Push out remaining byte.
		 */
		if (m->m_len & 1)
			outb(BASE + DATA_REG_B, *(mtod(m, caddr_t) + m->m_len - 1));
	}

	/*
	 * Push out padding.
	 */
	while (pad > 1) {
		outw(BASE + DATA_REG_W, 0);
		pad -= 2;
	}
	if (pad)
		outb(BASE + DATA_REG_B, 0);

	/*
	 * Push out control byte and unused packet byte The control byte is 0
	 * meaning the packet is even lengthed and no special CRC handling is
	 * desired.
	 */
	outw(BASE + DATA_REG_W, 0);

	/*
	 * Enable the interrupts and let the chipset deal with it Also set a
	 * watchdog in case we miss the interrupt.
	 */
	mask = inb(BASE + INTR_MASK_REG_B) | (IM_TX_INT | IM_TX_EMPTY_INT);
	outb(BASE + INTR_MASK_REG_B, mask);
	sc->intr_mask = mask;
	outw(BASE + MMU_CMD_REG_W, MMUCR_ENQUEUE);

	BPF_MTAP(ifp, top);

	IFNET_STAT_INC(ifp, opackets, 1);
	m_freem(top);

try_start:

	/*
	 * Now pass control to snstart() to queue any additional packets
	 */
	ifq_clr_oactive(&ifp->if_snd);
	if_devstart(ifp);

	/*
	 * We've sent something, so we're active.  Set a watchdog in case the
	 * TX_EMPTY interrupt is lost.
	 */
	ifq_set_oactive(&ifp->if_snd);
	ifp->if_timer = 1;
}
Ejemplo n.º 23
0
void
snstart(struct ifnet *ifp, struct ifaltq_subque *ifsq)
{
	struct sn_softc *sc = ifp->if_softc;
	u_int  len;
	struct mbuf *m;
	struct mbuf    *top;
	int             pad;
	int             mask;
	u_short         length;
	u_short         numPages;
	u_char          packet_no;
	int             time_out;

	ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq);

	if ((ifp->if_flags & IFF_RUNNING) == 0 || ifq_is_oactive(&ifp->if_snd))
		return;

	if (sc->pages_wanted != -1) {
		/* XXX should never happen */
		kprintf("%s: snstart() while memory allocation pending\n",
		       ifp->if_xname);
		ifq_set_oactive(&ifp->if_snd);
		return;
	}
startagain:

	/*
	 * Sneak a peek at the next packet
	 */
	m = ifq_dequeue(&ifp->if_snd);
	if (m == NULL)
		return;

	/*
	 * Compute the frame length and set pad to give an overall even
	 * number of bytes.  Below we assume that the packet length is even.
	 */
	for (len = 0, top = m; m; m = m->m_next)
		len += m->m_len;

	pad = (len & 1);

	/*
	 * We drop packets that are too large. Perhaps we should truncate
	 * them instead?
	 */
	if (len + pad > ETHER_MAX_LEN - ETHER_CRC_LEN) {
		kprintf("%s: large packet discarded (A)\n", ifp->if_xname);
		IFNET_STAT_INC(&sc->arpcom.ac_if, oerrors, 1);
		m_freem(top);
		goto readcheck;
	}
#ifdef SW_PAD

	/*
	 * If HW padding is not turned on, then pad to ETHER_MIN_LEN.
	 */
	if (len < ETHER_MIN_LEN - ETHER_CRC_LEN)
		pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len;

#endif	/* SW_PAD */

	length = pad + len;

	/*
	 * The MMU wants the number of pages to be the number of 256 byte
	 * 'pages', minus 1 (A packet can't ever have 0 pages. We also
	 * include space for the status word, byte count and control bytes in
	 * the allocation request.
	 */
	numPages = (length + 6) >> 8;


	/*
	 * Now, try to allocate the memory
	 */
	SMC_SELECT_BANK(2);
	outw(BASE + MMU_CMD_REG_W, MMUCR_ALLOC | numPages);

	/*
	 * Wait a short amount of time to see if the allocation request
	 * completes.  Otherwise, I enable the interrupt and wait for
	 * completion asyncronously.
	 */

	time_out = MEMORY_WAIT_TIME;
	do {
		if (inb(BASE + INTR_STAT_REG_B) & IM_ALLOC_INT)
			break;
	} while (--time_out);

	if (!time_out) {

		/*
		 * No memory now.  Oh well, wait until the chip finds memory
		 * later.   Remember how many pages we were asking for and
		 * enable the allocation completion interrupt. Also set a
		 * watchdog in case  we miss the interrupt. We mark the
		 * interface active since there is no point in attempting an
		 * snstart() until after the memory is available.
		 */
		mask = inb(BASE + INTR_MASK_REG_B) | IM_ALLOC_INT;
		outb(BASE + INTR_MASK_REG_B, mask);
		sc->intr_mask = mask;

		ifp->if_timer = 1;
		ifq_set_oactive(&ifp->if_snd);
		sc->pages_wanted = numPages;
		ifq_prepend(&ifp->if_snd, top);

		return;
	}
	/*
	 * The memory allocation completed.  Check the results.
	 */
	packet_no = inb(BASE + ALLOC_RESULT_REG_B);
	if (packet_no & ARR_FAILED) {
		kprintf("%s: Memory allocation failed\n", ifp->if_xname);
		ifq_prepend(&ifp->if_snd, top);
		goto startagain;
	}
	/*
	 * We have a packet number, so tell the card to use it.
	 */
	outb(BASE + PACKET_NUM_REG_B, packet_no);

	/*
	 * Point to the beginning of the packet
	 */
	outw(BASE + POINTER_REG_W, PTR_AUTOINC | 0x0000);

	/*
	 * Send the packet length (+6 for status, length and control byte)
	 * and the status word (set to zeros)
	 */
	outw(BASE + DATA_REG_W, 0);
	outb(BASE + DATA_REG_B, (length + 6) & 0xFF);
	outb(BASE + DATA_REG_B, (length + 6) >> 8);

	/*
	 * Push out the data to the card.
	 */
	for (m = top; m != NULL; m = m->m_next) {

		/*
		 * Push out words.
		 */
		outsw(BASE + DATA_REG_W, mtod(m, caddr_t), m->m_len / 2);

		/*
		 * Push out remaining byte.
		 */
		if (m->m_len & 1)
			outb(BASE + DATA_REG_B, *(mtod(m, caddr_t) + m->m_len - 1));
	}

	/*
	 * Push out padding.
	 */
	while (pad > 1) {
		outw(BASE + DATA_REG_W, 0);
		pad -= 2;
	}
	if (pad)
		outb(BASE + DATA_REG_B, 0);

	/*
	 * Push out control byte and unused packet byte The control byte is 0
	 * meaning the packet is even lengthed and no special CRC handling is
	 * desired.
	 */
	outw(BASE + DATA_REG_W, 0);

	/*
	 * Enable the interrupts and let the chipset deal with it Also set a
	 * watchdog in case we miss the interrupt.
	 */
	mask = inb(BASE + INTR_MASK_REG_B) | (IM_TX_INT | IM_TX_EMPTY_INT);
	outb(BASE + INTR_MASK_REG_B, mask);
	sc->intr_mask = mask;

	outw(BASE + MMU_CMD_REG_W, MMUCR_ENQUEUE);

	ifq_set_oactive(&ifp->if_snd);
	ifp->if_timer = 1;

	BPF_MTAP(ifp, top);

	IFNET_STAT_INC(ifp, opackets, 1);
	m_freem(top);

readcheck:

	/*
	 * Is another packet coming in?  We don't want to overflow the tiny
	 * RX FIFO.  If nothing has arrived then attempt to queue another
	 * transmit packet.
	 */
	if (inw(BASE + FIFO_PORTS_REG_W) & FIFO_REMPTY)
		goto startagain;
}