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

📄 if_fe.c

📁 很好的一个嵌入式linux平台下的bootloader
💻 C
📖 第 1 页 / 共 5 页
字号:
		 * Add in total number of collisions on last		 * transmission.  We also clear "collision occurred" flag		 * here.		 *		 * 86960 has a design flaw on collision count on multiple		 * packet transmission.  When we send two or more packets		 * with one start command (that's what we do when the		 * transmission queue is clauded), 86960 informs us number		 * of collisions occured on the last packet on the		 * transmission only.  Number of collisions on previous		 * packets are lost.  I have told that the fact is clearly		 * stated in the Fujitsu document.		 *		 * I considered not to mind it seriously.  Collision		 * count is not so important, anyway.  Any comments?  FIXME.		 */		if ( INB( sc->addr, FE_DLCR0 ) & FE_D0_COLLID ) {			/* Clear collision flag.  */			OUTB( sc->addr, FE_DLCR0, FE_D0_COLLID );			/* Extract collision count from 86960.  */			col = INB( sc->addr, FE_DLCR4 );			col = ( col & FE_D4_COL ) >> FE_D4_COL_SHIFT;			if ( col == 0 ) {				/*				 * Status register indicates collisions,				 * while the collision count is zero.				 * This can happen after multiple packet				 * transmission, indicating that one or more				 * previous packet(s) had been collided.				 *				 * Since the accurate number of collisions				 * has been lost, we just guess it as 1;				 * Am I too optimistic?  FIXME.				 */				col = 1;			}			sc->sc_if.if_collisions += col;#if FE_DEBUG >= 3			log( LOG_INFO, "fe%d: %d collision(s) (%d)\n",				sc->sc_unit, col, sc->txb_sched );#endif		}		/*		 * Update total number of successfully		 * transmitted packets.		 */		sc->sc_if.if_opackets += sc->txb_sched;		sc->txb_sched = 0;		/*		 * The transmitter is no more active.		 * Reset output active flag and watchdog timer.		 */		sc->sc_if.if_flags &= ~IFF_OACTIVE;		sc->sc_if.if_timer = 0;		/*		 * If more data is ready to transmit in the buffer, start		 * transmitting them.  Otherwise keep transmitter idle,		 * even if more data is queued.  This gives receive		 * process a slight priority.		 */		if ( sc->txb_count > 0 ) fe_xmit( sc );	}}/* * Ethernet interface receiver interrupt. */static voidfe_rint ( struct fe_softc * sc, u_char rstat ){	u_short len;	u_short status;	int i;	/*	 * Update statistics if this interrupt is caused by an error.	 */	if ( (rstat & ( FE_D1_OVRFLO | FE_D1_BUSERR ) )	     || ( !(sc->proto_dlcr5 & FE_D5_BADPKT)		  && (rstat & ( FE_D1_CRCERR | FE_D1_ALGERR ) ) ) ) {#if FE_DEBUG >= 2		log( LOG_WARNING,			"fe%d: receive error: %s%s%s%s(%02x)\n",			sc->sc_unit,			rstat & FE_D1_OVRFLO ? "OVR " : "",			rstat & FE_D1_BUSERR ? "BUS " : "",			rstat & FE_D1_CRCERR ? "CRC " : "",			rstat & FE_D1_ALGERR ? "ALG " : "",			rstat );#endif		sc->sc_if.if_ierrors++;	}	/*	 * MB86960 has a flag indicating "receive queue empty."	 * We just loop cheking the flag to pull out all received	 * packets.	 *	 * We limit the number of iterrations to avoid inifnit-loop.	 * It can be caused by a very slow CPU (some broken	 * peripheral may insert incredible number of wait cycles)	 * or, worse, by a broken MB86960 chip.	 */	for ( i = 0; i < FE_MAX_RECV_COUNT; i++ ) {		/* Stop the iterration if 86960 indicates no packets.  */		if ( INB( sc->addr, FE_DLCR5 ) & FE_D5_BUFEMP ) break;		/*		 * Extract A receive status byte.		 * As our 86960 is in 16 bit bus access mode, we have to		 * use inw() to get the status byte.  The significant		 * value is returned in lower 8 bits.		 */		status = INW( sc->addr, FE_BMPR8 );		/*		 * Extract the packet length.		 * It is a sum of a header (14 bytes) and a payload.		 * CRC has been stripped off by the 86960.		 */		len = INW( sc->addr, FE_BMPR8 );#if FE_DEBUG >= 1		log( LOG_INFO, "fe%d: receive status = %04x len = %04x\n",			sc->sc_unit, status, len );#endif		status &= 0xff;		/*		 * If there was an error, update statistics and drop		 * the packet, unless the interface is in promiscuous		 * mode.		 */		if ( ( status & 0xF0 ) != 0x20 ) {#if FE_DEBUG >= 2		        if ( status & (FE_D1_CRCERR | FE_D1_ALGERR | FE_D1_SRTPKT)) {			    log( LOG_WARNING,				 "fe%d: receive packet error: %s%s%s(%02x), %u bytes\n",				 sc->sc_unit,				 status & FE_D1_CRCERR ? "CRC " : "",				 status & FE_D1_ALGERR ? "ALG " : "",				 status & FE_D1_SRTPKT ? "LEN " : "",				 status, len );			}#endif			if ( !( sc->sc_if.if_flags & IFF_PROMISC ) ) {				sc->sc_if.if_ierrors++;				fe_droppacket(sc, len);				continue;			}		}		/*		 * MB86965 checks the packet length and drop big packet		 * before passing it to us.  There are no chance we can		 * get [crufty] packets.  Hence, if the length exceeds		 * the specified limit, it means some serious failure,		 * such as out-of-sync on receive buffer management.		 *		 * Is this statement true?  FIXME.		 */		if ( len > ETHER_MAX_LEN || len < ETHER_HDR_SIZE ) {#if FE_DEBUG >= 2			log( LOG_WARNING,				"fe%d: received a %s packet? (%u bytes)\n",				sc->sc_unit,				len < ETHER_HDR_SIZE ? "partial" : "big",				len );#endif			sc->sc_if.if_ierrors++;			fe_droppacket( sc, len );			continue;		}		/*		 * Check for a short (RUNT) packet.  We *do* check		 * but do nothing other than print a message.		 * Short packets are illegal, but does nothing bad		 * if it carries data for upper layer.		 */#if FE_DEBUG >= 2		if ( len < ETHER_MIN_LEN ) {			log( LOG_WARNING,			     "fe%d: received a short packet? (%u bytes)\n",			     sc->sc_unit, len );		}#endif		/*		 * Go get a packet.		 */		if ( fe_get_packet( sc, len ) < 0 ) {			/* Skip a packet, updating statistics.  */#if FE_DEBUG >= 2			log( LOG_WARNING, "fe%d: not enough mbuf;"			    " a packet (%u bytes) dropped\n",			    sc->sc_unit, len );#endif			sc->sc_if.if_ierrors++;			/*			 * We stop receiving packets, even if there are			 * more in the buffer.  We hope we can get more			 * mbuf next time.			 */			return;		}		/* Successfully received a packet.  Update stat.  */		sc->sc_if.if_ipackets++;	}}/* * Ethernet interface interrupt processor */voidfeintr ( int unit ){	struct fe_softc *sc = &fe_softc[unit];	u_char tstat, rstat;	u_char dlcr0, dlcr1, dlcr5;	/*	 * Loop until there are no more new interrupt conditions.	 */	for (;;) {		/*		 * Get interrupt conditions, masking unneeded flags.		 */		dlcr0 = INB( sc->addr, FE_DLCR0 );		dlcr1 = INB( sc->addr, FE_DLCR1 );		tstat = dlcr0 & FE_TMASK;		rstat = dlcr1 & FE_RMASK;#if FE_DEBUG >= 1 && 0		dlcr5 = INB( sc->addr, FE_DLCR5 );		if (rstat == 0 && (dlcr5 & FE_D5_BUFEMP) == 0) {		    log (LOG_DEBUG, "Kicking receiver\n");		    rstat = FE_D1_PKTRDY;		}#endif		if ( tstat == 0 && rstat == 0 ) break;#if FE_DEBUG >= 4		fe_dump( LOG_INFO, sc, "intr()" );#endif		/*		 * Reset the conditions we are acknowledging.		 */		OUTB( sc->addr, FE_DLCR0, dlcr0 );		OUTB( sc->addr, FE_DLCR1, dlcr1 );		/*		 * Handle transmitter interrupts. Handle these first because		 * the receiver will reset the board under some conditions.		 */		if ( tstat ) {			fe_tint( sc, dlcr0 );		}		/*		 * Handle receiver interrupts		 */		if ( rstat ) {			fe_rint( sc, dlcr1 );		}#ifdef MULTICAST		/*		 * Update the multicast address filter if it is		 * needed and possible.  We do it now, because		 * we can make sure the transmission buffer is empty,		 * and there is a good chance that the receive queue		 * is empty.  It will minimize the possibility of		 * packet lossage.		 */		if ( sc->filter_change		  && sc->txb_count == 0 && sc->txb_sched == 0 ) {			fe_loadmar(sc);			sc->sc_if.if_flags &= ~IFF_OACTIVE;		}#endif		/*		 * If it looks like the transmitter can take more data,		 * attempt to start output on the interface. This is done		 * after handling the receiver interrupt to give the		 * receive operation priority.		 *		 * BTW, I'm not sure in what case the OACTIVE is on at		 * this point.  Is the following test redundant?		 *		 * No.  This routine polls for both transmitter and		 * receiver interrupts.  86960 can raise a receiver		 * interrupt when the transmission buffer is full.		 */		if ( ( sc->sc_if.if_flags & IFF_OACTIVE ) == 0 ) {			fe_start( &sc->sc_if );		}	}}/* * Process an ioctl request. This code needs some work - it looks * pretty ugly. */intfe_ioctl ( struct ifnet *ifp, int command, caddr_t data ){	struct fe_softc *sc = IFNET2SOFTC( ifp );	int s, error = 0;#if FE_DEBUG >= 3	if (command != SIOCPOLL)	    log( LOG_INFO, "fe%d: ioctl(%x)\n", sc->sc_unit, command );#endif	s = splimp();	switch (command) {	case SIOCPOLL:	    if (ifp->if_flags & IFF_RUNNING)		feintr (ifp->if_unit);	    break;	  case SIOCSIFADDR:	    {		struct ifaddr * ifa = ( struct ifaddr * )data;		sc->sc_if.if_flags |= IFF_UP;		switch (ifa->ifa_addr->sa_family) {#ifdef INET		  case AF_INET:			fe_init( sc->sc_unit );	/* before arpwhohas */			arp_ifinit( &sc->arpcom, ifa );			break;#endif#ifdef NS			/*			 * XXX - This code is probably wrong			 */		  case AF_NS:			{				register struct ns_addr *ina				    = &(IA_SNS(ifa)->sns_addr);				if (ns_nullhost(*ina))					ina->x_host =					    *(union ns_host *) (sc->sc_enaddr);				else {					bcopy((caddr_t) ina->x_host.c_host,					      (caddr_t) sc->sc_enaddr,					      sizeof(sc->sc_enaddr));				}				/*				 * Set new address				 */				fe_init(sc->sc_unit);				break;			}#endif		  default:			fe_init( sc->sc_unit );			break;		}		break;	    }#ifdef SIOCGIFADDR	  case SIOCGIFADDR:	    {		struct ifreq * ifr = ( struct ifreq * )data;		struct sockaddr * sa = ( struct sockaddr * )&ifr->ifr_data;		bcopy((caddr_t)sc->sc_enaddr,		      (caddr_t)sa->sa_data, ETHER_ADDR_LEN);		break;	    }#endif#ifdef SIOCGIFPHYSADDR	  case SIOCGIFPHYSADDR:	    {		struct ifreq * ifr = ( struct ifreq * )data;		bcopy((caddr_t)sc->sc_enaddr,		      (caddr_t)&ifr->ifr_data, ETHER_ADDR_LEN);		break;	    }#endif#ifdef SIOCSIFPHYSADDR	  case SIOCSIFPHYSADDR:	    {		/*		 * Set the physical (Ehternet) address of the interface.		 * When and by whom is this command used?  FIXME.		 */		struct ifreq * ifr = ( struct ifreq * )data;		bcopy((caddr_t)&ifr->ifr_data,		      (caddr_t)sc->sc_enaddr, ETHER_ADDR_LEN);#ifdef PROM		if_newaddr(ifp, IFT_ETHER, 			   (caddr_t)((struct arpcom *)ifp)->ac_enaddr);#else		fe_setlinkaddr( sc );#endif		break;	    }#endif#ifdef SIOCSIFFLAGS	  case SIOCSIFFLAGS:	    {		/*		 * Switch interface state between "running" and		 * "stopped", reflecting the UP flag.		 */		if ( sc->sc_if.if_flags & IFF_UP ) {			if ( ( sc->sc_if.if_flags & IFF_RUNNING ) == 0 ) {				fe_init( sc->sc_unit );			}		} else {			if ( ( sc->sc_if.if_flags & IFF_RUNNING ) != 0 ) {				fe_stop( sc->sc_unit );			}		}		/*		 * Promiscuous and/or multicast flags may have changed,		 * so reprogram the multicast filter and/or receive mode.		 */		fe_setmode( sc );#if FE_DEBUG >= 1		/* "ifconfig fe0 debug" to print register dump.  */		if ( sc->sc_if.if_flags & IFF_DEBUG ) {			fe_dump( LOG_DEBUG, sc, "SIOCSIFFLAGS(DEBUG)" );		}#endif		break;	    }#endif#ifdef SIOCADDMULTI	  case SIOCADDMULTI:	  case SIOCDELMULTI:	    {		/*		 * Update out multicast list.		 */		struct ifreq * ifr = ( struct ifreq * )data;		error = ( command == SIOCADDMULTI )		      ? ether_addmulti( ifr, &sc->arpcom )		      : ether_delmulti( ifr, &sc->arpcom );		if ( error == ENETRESET ) {			/*			 * Multicast list has changed; set the hardware filter			 * accordingly.			 */			fe_setmode( sc );			error = 0;		}		break;	    }#endif#ifdef SIOCSIFMTU	  case SIOC

⌨️ 快捷键说明

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