FreeBSD/sys/dev/stge/if_stge.c
/*
 * stge_rxeof:
 *
 *	Helper; handle receive interrupts.
 */
Helper; handle receive interrupts.
Helper ; handle receive interrupts .
static int
stge_rxeof(struct stge_softc *sc)
{
	struct ifnet *ifp;
	struct stge_rxdesc *rxd;
	struct mbuf *mp, *m;
	uint64_t status64;
	uint32_t status;
	int cons, prog, rx_npkts;
	STGE_LOCK_ASSERT(sc);
	rx_npkts = 0;
	ifp = sc->sc_ifp;
	bus_dmamap_sync(sc->sc_cdata.stge_rx_ring_tag,
	    sc->sc_cdata.stge_rx_ring_map, BUS_DMASYNC_POSTREAD);
	prog = 0;
	for (cons = sc->sc_cdata.stge_rx_cons; prog < STGE_RX_RING_CNT;
	    prog++, cons = (cons + 1) % STGE_RX_RING_CNT) {
		status64 = le64toh(sc->sc_rdata.stge_rx_ring[cons].rfd_status);
		status = RFD_RxStatus(status64);
		if ((status & RFD_RFDDone) == 0)
			break;
#ifdef DEVICE_POLLING
		if (ifp->if_capenable & IFCAP_POLLING) {
			if (sc->sc_cdata.stge_rxcycles <= 0)
				break;
			sc->sc_cdata.stge_rxcycles--;
		}
#endif
		prog++;
		rxd = &sc->sc_cdata.stge_rxdesc[cons];
		mp = rxd->rx_m;
		if ((status & RFD_FrameEnd) != 0 && (status &
		    (RFD_RxFIFOOverrun | RFD_RxRuntFrame |
		    RFD_RxAlignmentError | RFD_RxFCSError |
		    RFD_RxLengthError)) != 0) {
			stge_discard_rxbuf(sc, cons);
			if (sc->sc_cdata.stge_rxhead != NULL) {
				m_freem(sc->sc_cdata.stge_rxhead);
				STGE_RXCHAIN_RESET(sc);
			}
			continue;
		}
		if (stge_newbuf(sc, cons) != 0) {
			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
			stge_discard_rxbuf(sc, cons);
			if (sc->sc_cdata.stge_rxhead != NULL) {
				m_freem(sc->sc_cdata.stge_rxhead);
				STGE_RXCHAIN_RESET(sc);
			}
			continue;
		}
		if ((status & RFD_FrameEnd) != 0)
			mp->m_len = RFD_RxDMAFrameLen(status) -
			    sc->sc_cdata.stge_rxlen;
		sc->sc_cdata.stge_rxlen += mp->m_len;
		if (sc->sc_cdata.stge_rxhead == NULL) {
			sc->sc_cdata.stge_rxhead = mp;
			sc->sc_cdata.stge_rxtail = mp;
		} else {
			mp->m_flags &= ~M_PKTHDR;
			sc->sc_cdata.stge_rxtail->m_next = mp;
			sc->sc_cdata.stge_rxtail = mp;
		}
		if ((status & RFD_FrameEnd) != 0) {
			m = sc->sc_cdata.stge_rxhead;
			m->m_pkthdr.rcvif = ifp;
			m->m_pkthdr.len = sc->sc_cdata.stge_rxlen;
			if (m->m_pkthdr.len > sc->sc_if_framesize) {
				m_freem(m);
				STGE_RXCHAIN_RESET(sc);
				continue;
			}
			if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) {
				if ((status & RFD_IPDetected) != 0) {
					m->m_pkthdr.csum_flags |=
						CSUM_IP_CHECKED;
					if ((status & RFD_IPError) == 0)
						m->m_pkthdr.csum_flags |=
						    CSUM_IP_VALID;
				}
				if (((status & RFD_TCPDetected) != 0 &&
				    (status & RFD_TCPError) == 0) ||
				    ((status & RFD_UDPDetected) != 0 &&
				    (status & RFD_UDPError) == 0)) {
					m->m_pkthdr.csum_flags |=
					    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
					m->m_pkthdr.csum_data = 0xffff;
				}
			}
#ifndef __NO_STRICT_ALIGNMENT
			if (sc->sc_if_framesize > (MCLBYTES - ETHER_ALIGN)) {
				if ((m = stge_fixup_rx(sc, m)) == NULL) {
					STGE_RXCHAIN_RESET(sc);
					continue;
				}
			}
#endif
			if ((status & RFD_VLANDetected) != 0 &&
			    (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) {
				m->m_pkthdr.ether_vtag = RFD_TCI(status64);
				m->m_flags |= M_VLANTAG;
			}
			STGE_UNLOCK(sc);
			(*ifp->if_input)(ifp, m);
			STGE_LOCK(sc);
			rx_npkts++;
			STGE_RXCHAIN_RESET(sc);
		}
	}
	if (prog > 0) {
		sc->sc_cdata.stge_rx_cons = cons;
		bus_dmamap_sync(sc->sc_cdata.stge_rx_ring_tag,
		    sc->sc_cdata.stge_rx_ring_map,
		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
	}
	return (rx_npkts);
}
static int stge_rxeof ( struct stge_softc * sc ) { struct ifnet * ifp ; struct stge_rxdesc * rxd ; struct mbuf * mp , * m ; uint64_t status64 ; uint32_t status ; int cons , prog , rx_npkts ; STGE_LOCK_ASSERT ( sc ) ; rx_npkts = 0 ; ifp = sc -> sc_ifp ; bus_dmamap_sync ( sc -> sc_cdata . stge_rx_ring_tag , sc -> sc_cdata . stge_rx_ring_map , BUS_DMASYNC_POSTREAD ) ; prog = 0 ; for ( cons = sc -> sc_cdata . stge_rx_cons ; prog < STGE_RX_RING_CNT ; prog ++ , cons = ( cons + 1 ) % STGE_RX_RING_CNT ) { status64 = le64toh ( sc -> sc_rdata . stge_rx_ring [ cons ] . rfd_status ) ; status = RFD_RxStatus ( status64 ) ; if ( ( status & RFD_RFDDone ) == 0 ) break ; #ifdef DEVICE_POLLING if ( ifp -> if_capenable & IFCAP_POLLING ) { if ( sc -> sc_cdata . stge_rxcycles <= 0 ) break ; sc -> sc_cdata . stge_rxcycles -- ; } #endif prog ++ ; rxd = & sc -> sc_cdata . stge_rxdesc [ cons ] ; mp = rxd -> rx_m ; if ( ( status & RFD_FrameEnd ) != 0 && ( status & ( RFD_RxFIFOOverrun | RFD_RxRuntFrame | RFD_RxAlignmentError | RFD_RxFCSError | RFD_RxLengthError ) ) != 0 ) { stge_discard_rxbuf ( sc , cons ) ; if ( sc -> sc_cdata . stge_rxhead != NULL ) { m_freem ( sc -> sc_cdata . stge_rxhead ) ; STGE_RXCHAIN_RESET ( sc ) ; } continue ; } if ( stge_newbuf ( sc , cons ) != 0 ) { if_inc_counter ( ifp , IFCOUNTER_IQDROPS , 1 ) ; stge_discard_rxbuf ( sc , cons ) ; if ( sc -> sc_cdata . stge_rxhead != NULL ) { m_freem ( sc -> sc_cdata . stge_rxhead ) ; STGE_RXCHAIN_RESET ( sc ) ; } continue ; } if ( ( status & RFD_FrameEnd ) != 0 ) mp -> m_len = RFD_RxDMAFrameLen ( status ) - sc -> sc_cdata . stge_rxlen ; sc -> sc_cdata . stge_rxlen += mp -> m_len ; if ( sc -> sc_cdata . stge_rxhead == NULL ) { sc -> sc_cdata . stge_rxhead = mp ; sc -> sc_cdata . stge_rxtail = mp ; } else { mp -> m_flags &= ~ M_PKTHDR ; sc -> sc_cdata . stge_rxtail -> m_next = mp ; sc -> sc_cdata . stge_rxtail = mp ; } if ( ( status & RFD_FrameEnd ) != 0 ) { m = sc -> sc_cdata . stge_rxhead ; m -> m_pkthdr . rcvif = ifp ; m -> m_pkthdr . len = sc -> sc_cdata . stge_rxlen ; if ( m -> m_pkthdr . len > sc -> sc_if_framesize ) { m_freem ( m ) ; STGE_RXCHAIN_RESET ( sc ) ; continue ; } if ( ( ifp -> if_capenable & IFCAP_RXCSUM ) != 0 ) { if ( ( status & RFD_IPDetected ) != 0 ) { m -> m_pkthdr . csum_flags |= CSUM_IP_CHECKED ; if ( ( status & RFD_IPError ) == 0 ) m -> m_pkthdr . csum_flags |= CSUM_IP_VALID ; } if ( ( ( status & RFD_TCPDetected ) != 0 && ( status & RFD_TCPError ) == 0 ) || ( ( status & RFD_UDPDetected ) != 0 && ( status & RFD_UDPError ) == 0 ) ) { m -> m_pkthdr . csum_flags |= ( CSUM_DATA_VALID | CSUM_PSEUDO_HDR ) ; m -> m_pkthdr . csum_data = 0xffff ; } } #ifndef __NO_STRICT_ALIGNMENT if ( sc -> sc_if_framesize > ( MCLBYTES - ETHER_ALIGN ) ) { if ( ( m = stge_fixup_rx ( sc , m ) ) == NULL ) { STGE_RXCHAIN_RESET ( sc ) ; continue ; } } #endif if ( ( status & RFD_VLANDetected ) != 0 && ( ifp -> if_capenable & IFCAP_VLAN_HWTAGGING ) != 0 ) { m -> m_pkthdr . ether_vtag = RFD_TCI ( status64 ) ; m -> m_flags |= M_VLANTAG ; } STGE_UNLOCK ( sc ) ; ( * ifp -> if_input ) ( ifp , m ) ; STGE_LOCK ( sc ) ; rx_npkts ++ ; STGE_RXCHAIN_RESET ( sc ) ; } } if ( prog > 0 ) { sc -> sc_cdata . stge_rx_cons = cons ; bus_dmamap_sync ( sc -> sc_cdata . stge_rx_ring_tag , sc -> sc_cdata . stge_rx_ring_map , BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE ) ; } return ( rx_npkts ) ; }
stge_rxeof:
      Helper; handle receive interrupts.
stge_rxeof : Helper ; handle receive interrupts .
/*
		 * If the packet had an error, drop it.  Note we count
		 * the error later in the periodic stats update.
		 */ /*
		 * Add a new receive buffer to the ring.
		 */ /* Chain mbufs. */ /*
			 * Set the incoming checksum information for
			 * the packet.
			 */ /* Check for VLAN tagged packets. */ /* Pass it on. */ /* Update the consumer index. */