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

📄 fec.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* First, grab all of the stats for the incoming packet.	 * These get messed up if we get called due to a busy condition.	 */	bdp = fep->cur_rx;while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {#ifndef final_version	/* Since we have allocated space to hold a complete frame,	 * the last indicator should be set.	 */	if ((bdp->cbd_sc & BD_ENET_RX_LAST) == 0)		printk("FEC ENET: rcv is not +last\n");#endif	/* Check for 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)) {		fep->stats.rx_errors++;       		if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {		/* Frame too long or too short. */			fep->stats.rx_length_errors++;		}		if (bdp->cbd_sc & BD_ENET_RX_NO)	/* Frame alignment */			fep->stats.rx_frame_errors++;		if (bdp->cbd_sc & BD_ENET_RX_CR)	/* CRC Error */			fep->stats.rx_crc_errors++;		if (bdp->cbd_sc & BD_ENET_RX_OV)	/* FIFO overrun */			fep->stats.rx_crc_errors++;	}	/* Report late collisions as a frame error.	 * On this error, the BD is closed, but we don't know what we	 * have in the buffer.  So, just drop this frame on the floor.	 */	if (bdp->cbd_sc & BD_ENET_RX_CL) {		fep->stats.rx_errors++;		fep->stats.rx_frame_errors++;		goto rx_processing_done;	}	/* Process the incoming frame.	 */	fep->stats.rx_packets++;	pkt_len = bdp->cbd_datlen;	fep->stats.rx_bytes += pkt_len;	data = (__u8*)__va(bdp->cbd_bufaddr);#ifdef CONFIG_FEC_PACKETHOOK	/* Packet hook ... */	if (fep->ph_rxhandler) {		if (((struct ethhdr *)data)->h_proto == fep->ph_proto) {			switch (fep->ph_rxhandler(data, pkt_len, regval,						  fep->ph_priv)) {			case 1:				goto rx_processing_done;				break;			case 0:				break;			default:				fep->stats.rx_errors++;				goto rx_processing_done;			}		}	}	/* If it wasn't filtered - copy it to an sk buffer. */#endif	/* This does 16 byte alignment, exactly what we need.	 * The packet length includes FCS, but we don't want to	 * include that when passing upstream as it messes up	 * bridging applications.	 */	skb = dev_alloc_skb(pkt_len-4);	if (skb == NULL) {		printk("%s: Memory squeeze, dropping packet.\n", dev->name);		fep->stats.rx_dropped++;	} else {		skb->dev = dev;		skb_put(skb,pkt_len-4);	/* Make room */		eth_copy_and_sum(skb,				 (unsigned char *)__va(bdp->cbd_bufaddr),				 pkt_len-4, 0);		skb->protocol=eth_type_trans(skb,dev);		netif_rx(skb);	}  rx_processing_done:	/* 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 = fep->rx_bd_base;	else		bdp++;	#if 1	/* Doing this here will keep the FEC running while we process	 * incoming frames.  On a heavily loaded network, we should be	 * able to keep up at the expense of system resources.	 */	fecp->fec_r_des_active = 0x01000000;#endif#ifdef CONFIG_FEC_PACKETHOOK	/* Re-read register. Not exactly guaranteed to be correct,	   but... */	if (fep->ph_regaddr) regval = *fep->ph_regaddr;#endif   } /* while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) */	fep->cur_rx = (cbd_t *)bdp;#if 0	/* Doing this here will allow us to process all frames in the	 * ring before the FEC is allowed to put more there.  On a heavily	 * loaded network, some frames may be lost.  Unfortunately, this	 * increases the interrupt overhead since we can potentially work	 * our way back to the interrupt return only to come right back	 * here.	 */	fecp->fec_r_des_active = 0x01000000;#endif}static voidfec_enet_mii(struct net_device *dev){	struct	fec_enet_private *fep;	volatile fec_t	*ep;	mii_list_t	*mip;	uint		mii_reg;	fep = (struct fec_enet_private *)dev->priv;	ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec);	mii_reg = ep->fec_mii_data;		if ((mip = mii_head) == NULL) {		printk("MII and no head!\n");		return;	}	if (mip->mii_func != NULL)		(*(mip->mii_func))(mii_reg, dev);	mii_head = mip->mii_next;	mip->mii_next = mii_free;	mii_free = mip;	if ((mip = mii_head) != NULL)		ep->fec_mii_data = mip->mii_regval;}static intmii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_device *)){	struct fec_enet_private *fep;	unsigned long	flags;	mii_list_t	*mip;	int		retval;	/* Add PHY address to register command.	*/	fep = dev->priv;	regval |= fep->phy_addr << 23;	retval = 0;	save_flags(flags);	cli();	if ((mip = mii_free) != NULL) {		mii_free = mip->mii_next;		mip->mii_regval = regval;		mip->mii_func = func;		mip->mii_next = NULL;		if (mii_head) {			mii_tail->mii_next = mip;			mii_tail = mip;		}		else {			mii_head = mii_tail = mip;			(&(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec))->fec_mii_data = regval;		}	}	else {		retval = 1;	}	restore_flags(flags);	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){	struct fec_enet_private *fep = dev->priv;	volatile 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;}static void mii_parse_cr(uint mii_reg, struct net_device *dev){	struct fec_enet_private *fep = dev->priv;	volatile 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;}static void mii_parse_anar(uint mii_reg, struct net_device *dev){	struct fec_enet_private *fep = dev->priv;	volatile 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;}#if 0static void mii_disp_reg(uint mii_reg, struct net_device *dev){	printk("reg %u = 0x%04x\n", (mii_reg >> 18) & 0x1f, mii_reg & 0xffff);}#endif/* ------------------------------------------------------------------------- *//* The Level one LXT970 is used by many boards				     */#ifdef CONFIG_FEC_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){	struct fec_enet_private *fep = dev->priv;	volatile 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;	}}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_FEC_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 * wierd, so 2.5 MHz ought to be enough for anyone... */static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev){	struct fec_enet_private *fep = dev->priv;	volatile 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;}static phy_info_t phy_info_lxt971 = {	0x0001378e, 	"LXT971",		(const phy_cmd_t []) {  /* config */  		/* limit to 10MBit because my protorype board 		 * doesn't work with 100. */		{ mk_mii_write(MII_REG_ANAR, 0x061), NULL }, /* 10 MBit */		{ 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_FEC_QS6612/* register definitions */#define MII_QS6612_MCR       17  /* Mode Control Register      */#define MII_QS6612_FTR       27  /* Factory Test Register      */#define MII_QS6612_MCO       28  /* Misc. Control Register     */#define MII_QS6612_ISR       29  /* Interrupt Source Register  */#define MII_QS6612_IMR       30  /* Interrupt Mask Register    */#define MII_QS6612_PCR       31  /* 100BaseTx PHY Control Reg. */static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev){	struct fec_enet_private *fep = dev->priv;	volatile uint *s = &(fep->phy_status);	*s &= ~(PHY_STAT_SPMASK);	switch((mii_reg >> 2) & 7) {	case 1: *s |= PHY_STAT_10HDX; break;	case 2: *s |= PHY_STAT_100HDX; break;	case 5: *s |= PHY_STAT_10FDX; break;	case 6: *s |= PHY_STAT_100FDX; break;	}}static phy_info_t phy_info_qs6612 = {	0x00181440, 	"QS6612",		(const phy_cmd_t []) {  /* config */  //	{ mk_mii_write(MII_REG_ANAR, 0x061), NULL }, /* 10 MBit */		/* The PHY powers up isolated on the RPX, 		 * so send a command to allow operation.		 */		{ mk_mii_write(MII_QS6612_PCR, 0x0dc0), NULL },		/* parse cr and anar to get some info */		{ 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_QS6612_IMR, 0x003a), NULL },		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */		{ mk_mii_end, }	},	(const phy_cmd_t []) { /* ack_int */				/* we need to read ISR, SR and ANER to acknowledge */				{ mk_mii_read(MII_QS6612_ISR), NULL },		{ mk_mii_read(MII_REG_SR), mii_parse_sr },		{ mk_mii_read(MII_REG_ANER), NULL },		/* read pcr to get info */		{ mk_mii_read(MII_QS6612_PCR), mii_parse_qs6612_pcr },		{ mk_mii_end, }	},	(const phy_cmd_t []) {  /* shutdown - disable interrupts */		{ mk_mii_write(MII_QS6612_IMR, 0x0000), NULL },		{ mk_mii_end, }	},};#endif /* CONFIG_FEC_QS6612 */static phy_info_t *phy_info[] = {#ifdef CONFIG_FEC_LXT970	&phy_info_lxt970,#endif /* CONFIG_FEC_LXT970 */#ifdef CONFIG_FEC_LXT971	&phy_info_lxt971,#endif /* CONFIG_FEC_LXT971 */#ifdef CONFIG_FEC_QS6612	&phy_info_qs6612,#endif /* CONFIG_FEC_LXT971 */	NULL};static void mii_display_status(struct net_device *dev){	struct fec_enet_private *fep = dev->priv;	volatile uint *s = &(fep->phy_status);	if (!fep->link && !fep->old_link) {		/* Link is still down - don't print anything */		return;	}	printk("%s: status: ", dev->name);	if (!fep->link) {		printk("link down");	} else {		printk("link up");		switch(*s & PHY_STAT_SPMASK) {		case PHY_STAT_100FDX: printk(", 100MBit Full Duplex"); break;		case PHY_STAT_100HDX: printk(", 100MBit Half Duplex"); break;		case PHY_STAT_10FDX: printk(", 10MBit Full Duplex"); break;		case PHY_STAT_10HDX: printk(", 10MBit Half Duplex"); break;		default:			printk(", Unknown speed/duplex");		}		if (*s & PHY_STAT_ANC)			printk(", auto-negotiation complete");	}	if (*s & PHY_STAT_FAULT)		printk(", remote fault");	printk(".\n");}static void mii_display_config(struct net_device *dev){	struct fec_enet_private *fep = dev->priv;	volatile uint *s = &(fep->phy_status);	printk("%s: config: auto-negotiation ", dev->name);	if (*s & PHY_CONF_ANE)		printk("on");	else		printk("off");	if (*s & PHY_CONF_100FDX)		printk(", 100FDX");	if (*s & PHY_CONF_100HDX)		printk(", 100HDX");	if (*s & PHY_CONF_10FDX)		printk(", 10FDX");	if (*s & PHY_CONF_10HDX)		printk(", 10HDX");	if (!(*s & PHY_CONF_SPMASK))		printk(", No speed/duplex selected?");	if (*s & PHY_CONF_LOOP)		printk(", loopback enabled");		printk(".\n");	fep->sequence_done = 1;}static void mii_relink(struct net_device *dev){	struct fec_enet_private *fep = dev->priv;	int duplex;	fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0;	mii_display_status(dev);	fep->old_link = fep->link;	if (fep->link) {		duplex = 0;		if (fep->phy_status 		    & (PHY_STAT_100FDX | PHY_STAT_10FDX))			duplex = 1;		fec_restart(dev, duplex);

⌨️ 快捷键说明

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