⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_fe.c

📁 很好的一个嵌入式linux平台下的bootloader
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Put the interface into known initial state.  */	if ( sc->sc_if.if_flags & IFF_UP ) {		fe_reset( unit );	} else {		fe_stop( unit );	}}/* * Drop (skip) a packet from receive buffer in 86960 memory. */static INLINE voidfe_droppacket ( struct fe_softc * sc, int len ){    int n;    /* read at least 8 bytes (or total remaining) from packet;       leave at least 9 if we're going to tell chip to skip. */    n = (len > 15) ? 8 : len;    while (n > 0) {#if FE_SYS_BUS_WIDTH == 16	INW( sc->addr, FE_BMPR8);	n -= 2; len -= 2;#else	INB( sc->addr, FE_BMPR8);	n -= 1; len -= 1;#endif    }    /* if any is remaining then tell chip to skip it */    if (len > 0) {	OUTB( sc->addr, FE_BMPR14, FE_B14_SKIP );	while (INB ( sc->addr, FE_BMPR14 ) & FE_B14_SKIP)	    continue;    }}/* * Initialize device. */voidfe_init ( int unit ){	struct fe_softc *sc = &fe_softc[unit];	int i, s;#if FE_DEBUG >= 3	fe_dump( LOG_INFO, sc, "init()" );#endif	/* We need an address. */	if (sc->sc_if.if_addrlist == 0) {#if FE_DEBUG >= 1		log( LOG_ERR, "fe%d: init() without any address\n",			sc->sc_unit );#endif		return;	}#if FE_DEBUG >= 1	/*	 * Make sure we have a valid station address.	 * The following test is applicable for any Ethernet interfaces.	 * It can be done in somewhere common to all of them.  FIXME.	 */	if ( ( sc->sc_enaddr[ 0 ] & 0x01 ) != 0	  || ( sc->sc_enaddr[ 0 ] == 0x00	    && sc->sc_enaddr[ 1 ] == 0x00	    && sc->sc_enaddr[ 2 ] == 0x00 ) ) {		log( LOG_ERR, "fe%d: invalid station address (%s)\n",			sc->sc_unit, ether_sprintf( sc->sc_enaddr ) );		return;	}#endif	/* Start initializing 86960.  */	s = splimp();	/* Call a hook.  */	if ( sc->init ) sc->init( sc );#if FE_DEBUG >= 3	fe_dump( LOG_INFO, sc, "after init hook" );#endif	/*	 * Make sure to disable the chip, also.	 * This may also help re-programming the chip after	 * hot insertion of PCMCIAs.	 */	OUTB( sc->addr, FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_DISABLE );	/* Power up the chip and select register bank for DLCRs.  */	DELAY(200);	OUTB( sc->addr, FE_DLCR7,		sc->proto_dlcr7 | FE_D7_RBS_DLCR | FE_D7_POWER_UP );	DELAY(200);	/* Feed the station address.  */	outblk( sc->addr, FE_DLCR8, sc->sc_enaddr, ETHER_ADDR_LEN );	/* Clear multicast address filter to receive nothing.  */	OUTB( sc->addr, FE_DLCR7,		sc->proto_dlcr7 | FE_D7_RBS_MAR | FE_D7_POWER_UP );	outblk( sc->addr, FE_MAR8, fe_filter_nothing.data, FE_FILTER_LEN );	/* Select the BMPR bank for runtime register access.  */	OUTB( sc->addr, FE_DLCR7,		sc->proto_dlcr7 | FE_D7_RBS_BMPR | FE_D7_POWER_UP );	/* Initialize registers.  */	OUTB( sc->addr, FE_DLCR0, 0xFF );	/* Clear all bits.  */	OUTB( sc->addr, FE_DLCR1, 0xFF );	/* ditto.  */	OUTB( sc->addr, FE_DLCR2, 0x00 );	OUTB( sc->addr, FE_DLCR3, 0x00 );	OUTB( sc->addr, FE_DLCR4, sc->proto_dlcr4 );	OUTB( sc->addr, FE_DLCR5, sc->proto_dlcr5 );	OUTB( sc->addr, FE_BMPR10, 0x00 );	OUTB( sc->addr, FE_BMPR11, FE_B11_CTRL_SKIP );	OUTB( sc->addr, FE_BMPR12, 0x00 );#ifndef FE_B13_INIT#define FE_B13_INIT	(FE_B13_TPTYPE_UTP | FE_B13_PORT_AUTO)#endif	OUTB( sc->addr, FE_BMPR13, FE_B13_INIT );	OUTB( sc->addr, FE_BMPR14, 0x00 );	OUTB( sc->addr, FE_BMPR14, 0x00 );	OUTB( sc->addr, FE_BMPR15, 0x00 );#if FE_DEBUG >= 3	fe_dump( LOG_INFO, sc, "just before enabling DLC" );#endif	/* Enable interrupts.  */	OUTB( sc->addr, FE_DLCR2, FE_TMASK );	OUTB( sc->addr, FE_DLCR3, FE_RMASK );	/* Enable transmitter and receiver.  */	DELAY(200);	OUTB( sc->addr, FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_ENABLE );	DELAY(200);#if FE_DEBUG >= 3	fe_dump( LOG_INFO, sc, "just after enabling DLC" );#endif	/*	 * Make sure to empty the receive buffer.	 *	 * This may be redundant, but *if* the receive buffer were full	 * at this point, the driver would hang.  I have experienced	 * some strange hangups just after UP.  I hope the following	 * code solve the problem.	 *	 * I have changed the order of hardware initialization.	 * I think the receive buffer cannot have any packets at this	 * point in this version.  The following code *must* be	 * redundant now.  FIXME.	 */	for ( i = 0; i < FE_MAX_RECV_COUNT; i++ ) {	    	u_short status, len;		if ( INB( sc->addr, FE_DLCR5 ) & FE_D5_BUFEMP ) break;		status = INW( sc->addr, FE_BMPR8 );		len = INW( sc->addr, FE_BMPR8 );		fe_droppacket (sc, len);	}#if FE_DEBUG >= 1	if ( i >= FE_MAX_RECV_COUNT ) {		log( LOG_ERR, "fe%d: cannot empty receive buffer\n",			sc->sc_unit );	}#endif#if FE_DEBUG >= 3	if ( i < FE_MAX_RECV_COUNT ) {		log( LOG_INFO, "fe%d: receive buffer emptied (%d)\n",			sc->sc_unit, i );	}#endif#if FE_DEBUG >= 3	fe_dump( LOG_INFO, sc, "after ERB loop" );#endif	/* Do we need this here?  */	OUTB( sc->addr, FE_DLCR0, 0xFF );	/* Clear all bits.  */	OUTB( sc->addr, FE_DLCR1, 0xFF );	/* ditto.  */#if FE_DEBUG >= 3	fe_dump( LOG_INFO, sc, "after FIXME" );#endif	/* Set 'running' flag, because we are now running.   */	sc->sc_if.if_flags |= IFF_RUNNING;#ifndef PROM	/* Update device config status.  */	sc->sc_dcstate = DC_BUSY;#endif	/*	 * At this point, the interface is runnung properly,	 * except that it receives *no* packets.  we then call	 * fe_setmode() to tell the chip what packets to be	 * received, based on the if_flags and multicast group	 * list.  It completes the initialization process.	 */	fe_setmode( sc );#if FE_DEBUG >= 3	fe_dump( LOG_INFO, sc, "after setmode" );#endif	/* ...and attempt to start output queued packets.  */	fe_start( &sc->sc_if );#if FE_DEBUG >= 3	fe_dump( LOG_INFO, sc, "init() done" );#endif	(void) splx(s);}/* * This routine actually starts the transmission on the interface */static INLINE voidfe_xmit ( struct fe_softc * sc ){	/*	 * Set a timer just in case we never hear from the board again.	 * We use longer timeout for multiple packet transmission.	 * I'm not sure this timer value is appropriate.  FIXME.	 */	sc->sc_if.if_timer = 1 + sc->txb_count;#if FE_DEBUG >= 1	log (LOG_DEBUG, "Switching transmit buffers\n");#endif	/* Update txb variables.  */	sc->txb_sched = sc->txb_count;	sc->txb_count = 0;	sc->txb_free = sc->txb_size;#if FE_DELAYED_PADDING	/* Omit the postponed padding process.  */	sc->txb_padding = 0;#endif	/* Start transmitter, passing packets in TX buffer.  */	OUTB( sc->addr, FE_BMPR10, sc->txb_sched | FE_B10_START );}/* * Start output on interface. * We make two assumptions here: *  1) that the current priority is set to splimp _before_ this code *     is called *and* is returned to the appropriate priority after *     return *  2) that the IFF_OACTIVE flag is checked before this code is called *     (i.e. that the output part of the interface is idle) */voidfe_start ( struct ifnet *ifp ){	struct fe_softc *sc = IFNET2SOFTC( ifp );	struct mbuf *m;#if FE_DEBUG >= 1	/* Just a sanity check.  */	if ( ( sc->txb_count == 0 ) != ( sc->txb_free == sc->txb_size ) ) {		/*		 * Txb_count and txb_free co-works to manage the		 * transmission buffer.  Txb_count keeps track of the		 * used potion of the buffer, while txb_free does unused		 * potion.  So, as long as the driver runs properly,		 * txb_count is zero if and only if txb_free is same		 * as txb_size (which represents whole buffer.)		 */		log( LOG_ERR, "fe%d: inconsistent txb variables (%d, %d)\n",			sc->sc_unit, sc->txb_count, sc->txb_free );		/*		 * So, what should I do, then?		 *		 * We now know txb_count and txb_free contradicts.  We		 * cannot, however, tell which is wrong.  More		 * over, we cannot peek 86960 transmission buffer or		 * reset the transmission buffer.  (In fact, we can		 * reset the entire interface.  I don't want to do it.)		 *		 * If txb_count is incorrect, leaving it as is will cause		 * sending of gabages after next interrupt.  We have to		 * avoid it.  Hence, we reset the txb_count here.  If		 * txb_free was incorrect, resetting txb_count just loose		 * some packets.  We can live with it.		 */		sc->txb_count = 0;	}#endif#if FE_DEBUG >= 1	/*	 * First, see if there are buffered packets and an idle	 * transmitter - should never happen at this point.	 */	if ( ( sc->txb_count > 0 ) && ( sc->txb_sched == 0 ) ) {		log( LOG_ERR,			"fe%d: transmitter idle with %d buffered packets\n",			sc->sc_unit, sc->txb_count );		fe_xmit( sc );	}#endif#ifdef MULTICAST	/*	 * Stop accepting more transmission packets temporarily, when	 * a filter change request is delayed.  Updating the MARs on	 * 86960 flushes the transmisstion buffer, so it is delayed	 * until all buffered transmission packets have been sent	 * out.	 */	if ( sc->filter_change ) {		/*		 * Filter change requst is delayed only when the DLC is		 * working.  DLC soon raise an interrupt after finishing		 * the work.		 */		goto indicate_active;	}#endif	for (;;) {		/*		 * Get the next mbuf chain for a packet to send.		 */		IF_DEQUEUE( &sc->sc_if.if_snd, m );		if ( m == NULL ) {			/* No more packets to send.  */			goto indicate_inactive;		}		/* We need to use m->m_pkthdr.len, so require the header */		if ((m->m_flags & M_PKTHDR) == 0)		    panic("fe_start: mbuf not pkthdr");		/*		 * See if there is room to put another packet in the buffer.		 */		if ( sc->txb_free < max (m->m_pkthdr.len, ETHER_MIN_LEN)		     + FE_DATA_LEN_LEN ) {			/* No room.  */		        IF_PREPEND( &sc->sc_if.if_snd, m );			goto indicate_active;		}#if FE_SINGLE_TRANSMISSION		if ( sc->txb_count > 0 ) {			/* Just one packet per a transmission buffer.  */		        IF_PREPEND( &sc->sc_if.if_snd, m );			goto indicate_active;		}#else		if ( sc->txb_count >= FE_QUEUEING_MAX ) {			/* Limit of packets per transmit buffer.  */		        IF_PREPEND( &sc->sc_if.if_snd, m );			goto indicate_active;		}#endif		/*		 * Copy the mbuf chain into the transmission buffer.		 * txb_* variables are updated as necessary.		 */		fe_write_mbufs( sc, m );		/* Start transmitter if it's idle.  */		if ( sc->txb_sched == 0 ) fe_xmit( sc );#if 0 /* Turned of, since our interface is now duplex.  */		/*		 * Tap off here if there is a bpf listener.		 */#if NBPFILTER > 0		if ( sc->bpf ) bpf_mtap( sc->bpf, m );#endif#endif		m_freem( m );	}  indicate_inactive:	/*	 * We are using the !OACTIVE flag to indicate to	 * the outside world that we can accept an	 * additional packet rather than that the	 * transmitter is _actually_ active.  Indeed, the	 * transmitter may be active, but if we haven't	 * filled all the buffers with data then we still	 * want to accept more.	 */	sc->sc_if.if_flags &= ~IFF_OACTIVE;	return;  indicate_active:	/*	 * The transmitter is active, and there are no room for	 * more outgoing packets in the transmission buffer.	 */	sc->sc_if.if_flags |= IFF_OACTIVE;	return;}/* * Transmission interrupt handler * The control flow of this function looks silly.  FIXME. */static voidfe_tint ( struct fe_softc * sc, u_char tstat ){	int left;	int col;	/*	 * Handle "excessive collision" interrupt.	 */	if ( tstat & FE_D0_COLL16 ) {		/*		 * Find how many packets (including this collided one)		 * are left unsent in transmission buffer.		 */		left = INB( sc->addr, FE_BMPR10 );#if FE_DEBUG >= 2		log( LOG_ERR, "fe%d: excessive collision (%d/%d)\n",			sc->sc_unit, left, sc->txb_sched );#endif#if FE_DEBUG >= 3		fe_dump( LOG_INFO, sc, NULL );#endif		/*		 * Update statistics.		 */		sc->sc_if.if_collisions += 16;		sc->sc_if.if_oerrors++;		sc->sc_if.if_opackets += sc->txb_sched - left;		/*		 * Collision statistics has been updated.		 * Clear the collision flag on 86960 now to avoid confusion.		 */		OUTB( sc->addr, FE_DLCR0, FE_D0_COLLID );		/*		 * Restart transmitter, skipping the		 * collided packet.		 *		 * We *must* skip the packet to keep network running		 * properly.  Excessive collision error is an		 * indication of the network overload.  If we		 * tried sending the same packet after excessive		 * collision, the network would be filled with		 * out-of-time packets.  Packets belonging		 * to reliable transport (such as TCP) are resent		 * by some upper layer.		 */		OUTB( sc->addr, FE_BMPR11,			FE_B11_CTRL_SKIP | FE_B11_MODE1 );		sc->txb_sched = left - 1;	}	if ( tstat & ( FE_D0_BUSERR | FE_D0_JABBER | FE_D0_CRLOST ) ) {#if FE_DEBUG >= 2		log( LOG_WARNING,			"fe%d: transmit error: %s%s%s(%02x)\n",			sc->sc_unit,			tstat & FE_D0_BUSERR ? "BUS " : "",			tstat & FE_D0_JABBER ? "JAB " : "",			tstat & FE_D0_CRLOST ? "CRL " : "",			tstat );#endif		sc->sc_if.if_oerrors++;	}	/*	 * Handle "transmission complete" interrupt.	 */	if ( tstat & FE_D0_TXDONE ) {		/*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -