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

📄 fcc_enet.c

📁 《嵌入式系统设计与实例开发实验教材二源码》Linux内核移植与编译实验
💻 C
📖 第 1 页 / 共 3 页
字号:
 * 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++;	/* 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) {		cep->stats.rx_frame_errors++;	}	else {		/* Process the incoming frame.		*/		cep->stats.rx_packets++;		pkt_len = bdp->cbd_datlen;		cep->stats.rx_bytes += pkt_len;		/* This does 16 byte alignment, much more than 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);			cep->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);		}	}	/* 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;}/* The MII is simulated from the 8xx FEC implementation.  The FCC * is not responsible for the MII control/status interface. */static voidfcc_enet_mii(struct net_device *dev){	struct	fcc_enet_private *fep;	mii_list_t	*mip;	uint		mii_reg;	fep = (struct fcc_enet_private *)dev->priv;#if 0	ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec);	mii_reg = ep->fec_mii_data;#endif		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 0	if ((mip = mii_head) != NULL)		ep->fec_mii_data = mip->mii_regval;#endif}static intmii_queue(int regval, void (*func)(uint, struct net_device *)){	unsigned long	flags;	mii_list_t	*mip;	int		retval;	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;#if 0			(&(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec))->fec_mii_data = regval;#endif		}	}	else {		retval = 1;	}	restore_flags(flags);	return(retval);}static	volatile uint	full_duplex;static voidmii_status(uint mii_reg, struct net_device *dev){	volatile uint	prev_duplex;	if (((mii_reg >> 18) & 0x1f) == 1) {		/* status register.		*/		printk("fec: ");		if (mii_reg & 0x0004)			printk("link up");		else			printk("link down");		if (mii_reg & 0x0010)			printk(",remote fault");		if (mii_reg & 0x0020)			printk(",auto complete");		printk("\n");	}	if (((mii_reg >> 18) & 0x1f) == 0x14) {		/* Extended chip status register.		*/		prev_duplex = full_duplex;		printk("fec: ");		if (mii_reg & 0x0800)			printk("100 Mbps");		else			printk("10 Mbps");		if (mii_reg & 0x1000) {			printk(", Full-Duplex\n");			full_duplex = 1;		}		else {			printk(", Half-Duplex\n");			full_duplex = 0;		}#if 0		if (prev_duplex != full_duplex)			restart_fec(dev);#endif	}	if (((mii_reg >> 18) & 0x1f) == 31) {		/* QS6612 PHY Control/Status.		 * OK, now we have it all, so figure out what is going on.		 */		prev_duplex = full_duplex;		printk("fec: ");		mii_reg = (mii_reg >> 2) & 7;		if (mii_reg & 1)			printk("10 Mbps");		else			printk("100 Mbps");		if (mii_reg > 4) {			printk(", Full-Duplex\n");			full_duplex = 1;		}		else {			printk(", Half-Duplex\n");			full_duplex = 0;		}#if 0		if (prev_duplex != full_duplex)			restart_fec(dev);#endif	}}static	uint	phyno;static voidmii_discover_phy3(uint mii_reg, struct net_device *dev){	phytype <<= 16;	phytype |= (mii_reg & 0xffff);	printk("fec: Phy @ 0x%x, type 0x%08x\n", phyno, phytype);	mii_startup_cmds();}static voidmii_discover_phy(uint mii_reg, struct net_device *dev){	if (phyno < 32) {		if ((phytype = (mii_reg & 0xffff)) != 0xffff) {			phyaddr = phyno;			mii_queue(mk_mii_read(3), mii_discover_phy3);		}		else {			phyno++;			mii_queue(mk_mii_phyaddr(phyno), mii_discover_phy);		}	}	else {		printk("FEC: No PHY device found.\n");	}}static voidmii_discover_phy_poll(fcc_info_t *fip){	uint	rv;	int	i;	for (i=0; i<32; i++) {		rv = mii_send_receive(fip, mk_mii_phyaddr(i));		if ((phytype = (rv & 0xffff)) != 0xffff) {			phyaddr = i;			rv = mii_send_receive(fip, mk_mii_read(3));			phytype <<= 16;			phytype |= (rv & 0xffff);			printk("fec: Phy @ 0x%x, type 0x%08x\n", phyaddr, phytype);		}	}}static	voidmii_startup_cmds(void){#if 1	/* Level One PHY.	*/	/* Read status registers to clear any pending interrupt.	*/	mii_queue(mk_mii_read(1), mii_status);	mii_queue(mk_mii_read(18), mii_status);	/* Read extended chip status register.	*/	mii_queue(mk_mii_read(0x14), mii_status);	/* Set default operation of 100-TX....for some reason	 * some of these bits are set on power up, which is wrong.	 */	mii_queue(mk_mii_write(0x13, 0), NULL);	/* Enable Link status change interrupts.	*/	mii_queue(mk_mii_write(0x11, 0x0002), NULL);	/* Don't advertize Full duplex.	mii_queue(mk_mii_write(0x04, 0x0021), NULL);	*/#endif}/* This supports the mii_link interrupt below. * We should get called three times.  Once for register 1, once for * register 18, and once for register 20. */static	uint mii_saved_reg1;static voidmii_relink(uint mii_reg, struct net_device *dev){	volatile uint	prev_duplex;	unsigned long	flags;	if (((mii_reg >> 18) & 0x1f) == 1) {		/* Just save the status register and get out.		*/		mii_saved_reg1 = mii_reg;		return;	}	if (((mii_reg >> 18) & 0x1f) == 18) {		/* Not much here, but has to be read to clear the		 * interrupt condition.		 */		if ((mii_reg & 0x8000) == 0)			printk("fec: re-link and no IRQ?\n");		if ((mii_reg & 0x4000) == 0)			printk("fec: no PHY power?\n");	}	if (((mii_reg >> 18) & 0x1f) == 20) {		/* Extended chip status register.		 * OK, now we have it all, so figure out what is going on.		 */		prev_duplex = full_duplex;		printk("fec: ");		if (mii_saved_reg1 & 0x0004)			printk("link up");		else			printk("link down");		if (mii_saved_reg1 & 0x0010)			printk(", remote fault");		if (mii_saved_reg1 & 0x0020)			printk(", auto complete");		if (mii_reg & 0x0800)			printk(", 100 Mbps");		else			printk(", 10 Mbps");		if (mii_reg & 0x1000) {			printk(", Full-Duplex\n");			full_duplex = 1;		}		else {			printk(", Half-Duplex\n");			full_duplex = 0;		}		if (prev_duplex != full_duplex) {			save_flags(flags);			cli();#if 0			restart_fec(dev);#endif			restore_flags(flags);		}	}	if (((mii_reg >> 18) & 0x1f) == 31) {		/* QS6612 PHY Control/Status.		 * OK, now we have it all, so figure out what is going on.		 */		prev_duplex = full_duplex;		printk("fec: ");		if (mii_saved_reg1 & 0x0004)			printk("link up");		else			printk("link down");		if (mii_saved_reg1 & 0x0010)			printk(", remote fault");		if (mii_saved_reg1 & 0x0020)			printk(", auto complete");		mii_reg = (mii_reg >> 2) & 7;		if (mii_reg & 1)			printk(", 10 Mbps");		else			printk(", 100 Mbps");		if (mii_reg > 4) {			printk(", Full-Duplex\n");			full_duplex = 1;		}		else {			printk(", Half-Duplex\n");			full_duplex = 0;		}#if 0		if (prev_duplex != full_duplex) {			save_flags(flags);			cli();			restart_fec(dev);			restore_flags(flags);		}#endif	}}/* Set or clear the multicast filter for this adaptor. * Skeleton taken from sunlance driver. * The CPM Ethernet implementation allows Multicast as well as individual * MAC address filtering.  Some of the drivers check to make sure it is * a group multicast address, and discard those that are not.  I guess I * will do the same for now, but just remove the test if you want * individual filtering as well (do the upper net layers want or support * this kind of feature?). */static voidset_multicast_list(struct net_device *dev){	struct	fcc_enet_private *cep;	struct	dev_mc_list *dmi;	u_char	*mcptr, *tdptr;	volatile fcc_enet_t *ep;	int	i, j;	cep = (struct fcc_enet_private *)dev->priv;return;	/* Get pointer to FCC area in parameter RAM.	*/	ep = (fcc_enet_t *)dev->base_addr;	if (dev->flags&IFF_PROMISC) {	  		/* Log any net taps. */		printk("%s: Promiscuous mode enabled.\n", dev->name);		cep->fccp->fcc_fpsmr |= FCC_PSMR_PRO;	} else {		cep->fccp->fcc_fpsmr &= ~FCC_PSMR_PRO;		if (dev->flags & IFF_ALLMULTI) {			/* Catch all multicast addresses, so set the			 * filter to all 1's.			 */			ep->fen_gaddrh = 0xffffffff;			ep->fen_gaddrl = 0xffffffff;		}		else {			/* Clear filter and add the addresses in the list.			*/			ep->fen_gaddrh = 0;			ep->fen_gaddrl = 0;			dmi = dev->mc_list;			for (i=0; i<dev->mc_count; i++) {								/* Only support group multicast for now.				*/				if (!(dmi->dmi_addr[0] & 1))					continue;				/* The address in dmi_addr is LSB first,				 * and taddr is MSB first.  We have to				 * copy bytes MSB first from dmi_addr.				 */				mcptr = (u_char *)dmi->dmi_addr + 5;				tdptr = (u_char *)&ep->fen_taddrh;				for (j=0; j<6; j++)					*tdptr++ = *mcptr--;				/* Ask CPM to run CRC and set bit in				 * filter mask.				 */				cpmp->cp_cpcr = mk_cr_cmd(cep->fip->fc_cpmpage,						cep->fip->fc_cpmblock, 0x0c,						CPM_CR_SET_GADDR) | CPM_CR_FLG;				udelay(10);				while (cpmp->cp_cpcr & CPM_CR_FLG);			}		}	}}/* Initialize the CPM Ethernet on FCC. */int __init fec_enet_init(void){	struct net_device *dev;	struct fcc_enet_private *cep;	fcc_info_t	*fip;	int	i, np;

⌨️ 快捷键说明

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