fcc_enet.c

来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 1,911 行 · 第 1/4 页

C
1,911
字号
	/* Check for a transmit error.  The manual is a little unclear	 * about this, so the debug code until I get it figured out.  It	 * appears that if TXE is set, then TXB is not set.  However,	 * if carrier sense is lost during frame transmission, the TXE	 * bit is set, "and continues the buffer transmission normally."	 * I don't know if "normally" implies TXB is set when the buffer	 * descriptor is closed.....trial and error :-).	 */	/* Transmit OK, or non-fatal error.  Update the buffer descriptors.	*/	if (int_events & (FCC_ENET_TXE | FCC_ENET_TXB)) {	    spin_lock(&cep->lock);	    bdp = cep->dirty_tx;	    while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) {		if ((bdp==cep->cur_tx) && (cep->tx_full == 0))		    break;		if (bdp->cbd_sc & BD_ENET_TX_HB)	/* No heartbeat */			cep->stats.tx_heartbeat_errors++;		if (bdp->cbd_sc & BD_ENET_TX_LC)	/* Late collision */			cep->stats.tx_window_errors++;		if (bdp->cbd_sc & BD_ENET_TX_RL)	/* Retrans limit */			cep->stats.tx_aborted_errors++;		if (bdp->cbd_sc & BD_ENET_TX_UN)	/* Underrun */			cep->stats.tx_fifo_errors++;		if (bdp->cbd_sc & BD_ENET_TX_CSL)	/* Carrier lost */			cep->stats.tx_carrier_errors++;		/* No heartbeat or Lost carrier are not really bad errors.		 * The others require a restart transmit command.		 */		if (bdp->cbd_sc &		    (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) {			must_restart = 1;			cep->stats.tx_errors++;		}		cep->stats.tx_packets++;		/* Deferred means some collisions occurred during transmit,		 * but we eventually sent the packet OK.		 */		if (bdp->cbd_sc & BD_ENET_TX_DEF)			cep->stats.collisions++;		/* Free the sk buffer associated with this last transmit. */		dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]);		cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK;		/* Update pointer to next buffer descriptor to be transmitted. */		if (bdp->cbd_sc & BD_ENET_TX_WRAP)			bdp = cep->tx_bd_base;		else			bdp++;		/* I don't know if we can be held off from processing these		 * interrupts for more than one frame time.  I really hope		 * not.  In such a case, we would now want to check the		 * currently available BD (cur_tx) and determine if any		 * buffers between the dirty_tx and cur_tx have also been		 * sent.  We would want to process anything in between that		 * does not have BD_ENET_TX_READY set.		 */		/* Since we have freed up a buffer, the ring is no longer		 * full.		 */		if (cep->tx_full) {			cep->tx_full = 0;			if (netif_queue_stopped(dev)) {				netif_wake_queue(dev);			}		}		cep->dirty_tx = (cbd_t *)bdp;	    }	    if (must_restart) {		volatile cpm8260_t *cp;		/* Some transmit errors cause the transmitter to shut		 * down.  We now issue a restart transmit.  Since the		 * errors close the BD and update the pointers, the restart		 * _should_ pick up without having to reset any of our		 * pointers either.  Also, To workaround 8260 device erratum 		 * CPM37, we must disable and then re-enable the transmitter		 * following a Late Collision, Underrun, or Retry Limit error.		 */		cep->fccp->fcc_gfmr &= ~FCC_GFMR_ENT;		udelay(10); /* wait a few microseconds just on principle */		cep->fccp->fcc_gfmr |=  FCC_GFMR_ENT;		cp = cpmp;		cp->cp_cpcr =		    mk_cr_cmd(cep->fip->fc_cpmpage, cep->fip->fc_cpmblock,		    		0x0c, CPM_CR_RESTART_TX) | CPM_CR_FLG;		while (cp->cp_cpcr & CPM_CR_FLG);	    }	    spin_unlock(&cep->lock);	}	/* Check for receive busy, i.e. packets coming but no place to	 * put them.	 */	if (int_events & FCC_ENET_BSY) {		cep->stats.rx_dropped++;	}	return;}/* During a receive, the cur_rx points to the current incoming buffer. * When we update through the ring, if the next incoming buffer has * not been given to the system, we just set the empty indicator, * effectively tossing the packet. */static intfcc_enet_rx(struct net_device *dev){	struct	fcc_enet_private *cep;	volatile cbd_t	*bdp;	struct	sk_buff *skb;	ushort	pkt_len;	cep = (struct fcc_enet_private *)dev->priv;	/* First, grab all of the stats for the incoming packet.	 * These get messed up if we get called due to a busy condition.	 */	bdp = cep->cur_rx;for (;;) {	if (bdp->cbd_sc & BD_ENET_RX_EMPTY)		break;		#ifndef final_version	/* Since we have allocated space to hold a complete frame, both	 * the first and last indicators should be set.	 */	if ((bdp->cbd_sc & (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) !=		(BD_ENET_RX_FIRST | BD_ENET_RX_LAST))			printk("CPM ENET: rcv is not first+last\n");#endif	/* Frame too long or too short. */	if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH))		cep->stats.rx_length_errors++;	if (bdp->cbd_sc & BD_ENET_RX_NO)	/* Frame alignment */		cep->stats.rx_frame_errors++;	if (bdp->cbd_sc & BD_ENET_RX_CR)	/* CRC Error */		cep->stats.rx_crc_errors++;	if (bdp->cbd_sc & BD_ENET_RX_OV)	/* FIFO overrun */		cep->stats.rx_crc_errors++;	if (bdp->cbd_sc & BD_ENET_RX_CL)	/* Late Collision */		cep->stats.rx_frame_errors++;	if (!(bdp->cbd_sc &	      (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | BD_ENET_RX_CR	       | BD_ENET_RX_OV | BD_ENET_RX_CL)))	{		/* Process the incoming frame. */		cep->stats.rx_packets++;		/* Remove the FCS from the packet length. */		pkt_len = bdp->cbd_datlen - 4;		cep->stats.rx_bytes += pkt_len;		/* This does 16 byte alignment, much more than we need. */		skb = dev_alloc_skb(pkt_len);		if (skb == NULL) {			printk("%s: Memory squeeze, dropping packet.\n", dev->name);			cep->stats.rx_dropped++;		}		else {			skb->dev = dev;			skb_put(skb,pkt_len);	/* Make room */			eth_copy_and_sum(skb,				(unsigned char *)__va(bdp->cbd_bufaddr),				pkt_len, 0);			skb->protocol=eth_type_trans(skb,dev);			netif_rx(skb);		}	}	/* Clear the status flags for this buffer. */	bdp->cbd_sc &= ~BD_ENET_RX_STATS;	/* Mark the buffer empty. */	bdp->cbd_sc |= BD_ENET_RX_EMPTY;	/* Update BD pointer to next entry. */	if (bdp->cbd_sc & BD_ENET_RX_WRAP)		bdp = cep->rx_bd_base;	else		bdp++;   }	cep->cur_rx = (cbd_t *)bdp;	return 0;}static intfcc_enet_close(struct net_device *dev){	/* Don't know what to do yet. */	netif_stop_queue(dev);	return 0;}static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev){	struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv;	return &cep->stats;}#ifdef	CONFIG_USE_MDIO/* NOTE: Most of the following comes from the FEC driver for 860. The * overall structure of MII code has been retained (as it's proved stable * and well-tested), but actual transfer requests are processed "at once" * instead of being queued (there's no interrupt-driven MII transfer * mechanism, one has to toggle the data/clock bits manually). */static intmii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_device *)){	struct fcc_enet_private *fep;	int		retval, tmp;	/* Add PHY address to register command. */	fep = dev->priv;	regval |= fep->phy_addr << 23;	retval = 0;	tmp = mii_send_receive(fep->fip, regval);	if (func)		func(tmp, dev);	return retval;}static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c){	int k;	if(!c)		return;	for(k = 0; (c+k)->mii_data != mk_mii_end; k++)		mii_queue(dev, (c+k)->mii_data, (c+k)->funct);}static void mii_parse_sr(uint mii_reg, struct net_device *dev){	volatile struct fcc_enet_private *fep = dev->priv;	uint s = fep->phy_status;	s &= ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC);	if (mii_reg & 0x0004)		s |= PHY_STAT_LINK;	if (mii_reg & 0x0010)		s |= PHY_STAT_FAULT;	if (mii_reg & 0x0020)		s |= PHY_STAT_ANC;	fep->phy_status = s;	fep->link = (s & PHY_STAT_LINK) ? 1 : 0;}static void mii_parse_cr(uint mii_reg, struct net_device *dev){	volatile struct fcc_enet_private *fep = dev->priv;	uint s = fep->phy_status;	s &= ~(PHY_CONF_ANE | PHY_CONF_LOOP);	if (mii_reg & 0x1000)		s |= PHY_CONF_ANE;	if (mii_reg & 0x4000)		s |= PHY_CONF_LOOP;	fep->phy_status = s;}static void mii_parse_anar(uint mii_reg, struct net_device *dev){	volatile struct fcc_enet_private *fep = dev->priv;	uint s = fep->phy_status;	s &= ~(PHY_CONF_SPMASK);	if (mii_reg & 0x0020)		s |= PHY_CONF_10HDX;	if (mii_reg & 0x0040)		s |= PHY_CONF_10FDX;	if (mii_reg & 0x0080)		s |= PHY_CONF_100HDX;	if (mii_reg & 0x00100)		s |= PHY_CONF_100FDX;	fep->phy_status = s;}/* ------------------------------------------------------------------------- *//* The Level one LXT970 is used by many boards				     */#ifdef CONFIG_FCC_LXT970#define MII_LXT970_MIRROR    16  /* Mirror register           */#define MII_LXT970_IER       17  /* Interrupt Enable Register */#define MII_LXT970_ISR       18  /* Interrupt Status Register */#define MII_LXT970_CONFIG    19  /* Configuration Register    */#define MII_LXT970_CSR       20  /* Chip Status Register      */static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev){	volatile struct fcc_enet_private *fep = dev->priv;	uint s = fep->phy_status;	s &= ~(PHY_STAT_SPMASK);	if (mii_reg & 0x0800) {		if (mii_reg & 0x1000)			s |= PHY_STAT_100FDX;		else			s |= PHY_STAT_100HDX;	} else {		if (mii_reg & 0x1000)			s |= PHY_STAT_10FDX;		else			s |= PHY_STAT_10HDX;	}	fep->phy_status = s;}static phy_info_t phy_info_lxt970 = {	0x07810000,	"LXT970",	(const phy_cmd_t []) {  /* config */#if 0//		{ mk_mii_write(MII_REG_ANAR, 0x0021), NULL },		/* Set default operation of 100-TX....for some reason		 * some of these bits are set on power up, which is wrong.		 */		{ mk_mii_write(MII_LXT970_CONFIG, 0), NULL },#endif		{ mk_mii_read(MII_REG_CR), mii_parse_cr },		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },		{ mk_mii_end, }	},	(const phy_cmd_t []) {  /* startup - enable interrupts */		{ mk_mii_write(MII_LXT970_IER, 0x0002), NULL },		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */		{ mk_mii_end, }	},	(const phy_cmd_t []) { /* ack_int */		/* read SR and ISR to acknowledge */		{ mk_mii_read(MII_REG_SR), mii_parse_sr },		{ mk_mii_read(MII_LXT970_ISR), NULL },		/* find out the current status */		{ mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr },		{ mk_mii_end, }	},	(const phy_cmd_t []) {  /* shutdown - disable interrupts */		{ mk_mii_write(MII_LXT970_IER, 0x0000), NULL },		{ mk_mii_end, }	},};#endif /* CONFIG_FEC_LXT970 *//* ------------------------------------------------------------------------- *//* The Level one LXT971 is used on some of my custom boards                  */#ifdef CONFIG_FCC_LXT971/* register definitions for the 971 */#define MII_LXT971_PCR       16  /* Port Control Register     */#define MII_LXT971_SR2       17  /* Status Register 2         */#define MII_LXT971_IER       18  /* Interrupt Enable Register */#define MII_LXT971_ISR       19  /* Interrupt Status Register */#define MII_LXT971_LCR       20  /* LED Control Register      */#define MII_LXT971_TCR       30  /* Transmit Control Register *//* * I had some nice ideas of running the MDIO faster... * The 971 should support 8MHz and I tried it, but things acted really * weird, so 2.5 MHz ought to be enough for anyone... */static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev){	volatile struct fcc_enet_private *fep = dev->priv;	uint s = fep->phy_status;	s &= ~(PHY_STAT_SPMASK);	if (mii_reg & 0x4000) {		if (mii_reg & 0x0200)			s |= PHY_STAT_100FDX;		else			s |= PHY_STAT_100HDX;	} else {		if (mii_reg & 0x0200)			s |= PHY_STAT_10FDX;		else			s |= PHY_STAT_10HDX;	}	if (mii_reg & 0x0008)		s |= PHY_STAT_FAULT;	fep->phy_status = s;}static phy_info_t phy_info_lxt971 = {	0x0001378e,	"LXT971",	(const phy_cmd_t []) {  /* config *///		{ mk_mii_write(MII_REG_ANAR, 0x021), NULL }, /* 10  Mbps, HD */		{ mk_mii_read(MII_REG_CR), mii_parse_cr },		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },		{ mk_mii_end, }	},	(const phy_cmd_t []) {  /* startup - enable interrupts */		{ mk_mii_write(MII_LXT971_IER, 0x00f2), NULL },		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */		/* Somehow does the 971 tell me that the link is down		 * the first read after power-up.		 * read here to get a valid value in ack_int */		{ mk_mii_read(MII_REG_SR), mii_parse_sr },		{ mk_mii_end, }	},	(const phy_cmd_t []) { /* ack_int */		/* find out the current status */		{ mk_mii_read(MII_REG_SR), mii_parse_sr },		{ mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 },		/* we only need to read ISR to acknowledge */		{ mk_mii_read(MII_LXT971_ISR), NULL },		{ mk_mii_end, }	},	(const phy_cmd_t []) {  /* shutdown - disable interrupts */		{ mk_mii_write(MII_LXT971_IER, 0x0000), NULL },		{ mk_mii_end, }	},};#endif /* CONFIG_FEC_LXT970 *//* ------------------------------------------------------------------------- *//* The Quality Semiconductor QS6612 is used on the RPX CLLF                  */#ifdef CONFIG_FCC_QS6612/* register definitions */#define MII_QS6612_MCR       17  /* Mode Control Register      */#define MII_QS6612_FTR       27  /* Factory Test Register      */

⌨️ 快捷键说明

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