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

📄 ether00.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  drivers/net/ether00.c * *  Copyright (C) 2001 Altera Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *//* includes */#include <linux/config.h>#include <linux/pci.h>#include <linux/sched.h>#include <linux/netdevice.h>#include <linux/skbuff.h>#include <linux/etherdevice.h>#include <linux/module.h>#include <linux/tqueue.h>#include <linux/mtd/mtd.h>#include <linux/pld/pld_hotswap.h>#include <asm/arch/excalibur.h>#include <asm/arch/hardware.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/sizes.h>#include <asm/arch/ether00.h>#include <asm/arch/tdkphy.h>MODULE_AUTHOR("Clive Davies");MODULE_DESCRIPTION("Altera Ether00 IP core driver");MODULE_LICENSE("GPL");#define PKT_BUF_SZ 1540 /* Size of each rx buffer */#define ETH_NR 4 /* Number of MACs this driver supports */#define DEBUG(x)#define __dma_va(x) (unsigned int)((unsigned int)priv->dma_data+(((unsigned int)(x))&(EXC_SPSRAM_BLOCK0_SIZE-1)))#define __dma_pa(x) (unsigned int)(EXC_SPSRAM_BLOCK0_BASE+(((unsigned int)(x))-(unsigned int)priv->dma_data))#define ETHER00_BASE	0#define	ETHER00_TYPE#define ETHER00_NAME "ether00"#define MAC_REG_SIZE 0x400 /* size of MAC register area *//* typedefs *//* The definition of the driver control structure */#define RX_NUM_BUFF     10#define RX_NUM_FDESC    10#define TX_NUM_FDESC    10struct tx_fda_ent{	FDA_DESC  fd;	BUF_DESC  bd;	BUF_DESC  pad;};struct rx_fda_ent{	FDA_DESC  fd;	BUF_DESC  bd;	BUF_DESC  pad;};struct rx_blist_ent{	FDA_DESC  fd;	BUF_DESC  bd;	BUF_DESC  pad;};struct net_priv{	struct net_device_stats stats;	struct sk_buff* skb;	void* dma_data;	struct rx_blist_ent*  rx_blist_vp;	struct rx_fda_ent* rx_fda_ptr;	struct tx_fda_ent* tx_fdalist_vp;	struct tq_struct  tq_memupdate;	unsigned char   memupdate_scheduled;	unsigned char   rx_disabled;	unsigned char   queue_stopped;	spinlock_t rx_lock;};static const char vendor_id[2]={0x07,0xed};#ifdef ETHER00_DEBUG/* Dump (most) registers for debugging puposes */static void dump_regs(struct net_device *dev){	struct net_priv* priv=dev->priv;	unsigned int* i;	printk("\n RX free descriptor area:\n");	for(i=(unsigned int*)priv->rx_fda_ptr;	    i<((unsigned int*)(priv->rx_fda_ptr+RX_NUM_FDESC));){		printk("%#8x %#8x %#8x %#8x\n",*i,*(i+1),*(i+2),*(i+3));		i+=4;	}	printk("\n RX buffer list:\n");	for(i=(unsigned int*)priv->rx_blist_vp;	    i<((unsigned int*)(priv->rx_blist_vp+RX_NUM_BUFF));){		printk("%#8x %#8x %#8x %#8x\n",*i,*(i+1),*(i+2),*(i+3));		i+=4;	}	printk("\n TX frame descriptor list:\n");	for(i=(unsigned int*)priv->tx_fdalist_vp;	    i<((unsigned int*)(priv->tx_fdalist_vp+TX_NUM_FDESC));){		printk("%#8x %#8x %#8x %#8x\n",*i,*(i+1),*(i+2),*(i+3));		i+=4;	}	printk("\ndma ctl=%#x\n",readw(ETHER_DMA_CTL(dev->base_addr)));	printk("txfrmptr=%#x\n",readw(ETHER_TXFRMPTR(dev->base_addr)));	printk("txthrsh=%#x\n",readw(ETHER_TXTHRSH(dev->base_addr)));	printk("txpollctr=%#x\n",readw(ETHER_TXPOLLCTR(dev->base_addr)));	printk("blfrmptr=%#x\n",readw(ETHER_BLFRMPTR(dev->base_addr)));	printk("rxfragsize=%#x\n",readw(ETHER_RXFRAGSIZE(dev->base_addr)));	printk("tx_int_en=%#x\n",readw(ETHER_INT_EN(dev->base_addr)));	printk("fda_bas=%#x\n",readw(ETHER_FDA_BAS(dev->base_addr)));	printk("fda_lim=%#x\n",readw(ETHER_FDA_LIM(dev->base_addr)));	printk("int_src=%#x\n",readw(ETHER_INT_SRC(dev->base_addr)));	printk("pausecnt=%#x\n",readw(ETHER_PAUSECNT(dev->base_addr)));	printk("rempaucnt=%#x\n",readw(ETHER_REMPAUCNT(dev->base_addr)));	printk("txconfrmstat=%#x\n",readw(ETHER_TXCONFRMSTAT(dev->base_addr)));	printk("mac_ctl=%#x\n",readw(ETHER_MAC_CTL(dev->base_addr)));	printk("arc_ctl=%#x\n",readw(ETHER_ARC_CTL(dev->base_addr)));	printk("tx_ctl=%#x\n",readw(ETHER_TX_CTL(dev->base_addr)));}#endif /* ETHER00_DEBUG */static int ether00_write_phy(struct net_device *dev, short address, short value){	volatile int count = 1024;	writew(value,ETHER_MD_DATA(dev->base_addr));	writew( ETHER_MD_CA_BUSY_MSK |		ETHER_MD_CA_WR_MSK |		(address & ETHER_MD_CA_ADDR_MSK),		ETHER_MD_CA(dev->base_addr));	/* Wait for the command to complete */	while((readw(ETHER_MD_CA(dev->base_addr)) & ETHER_MD_CA_BUSY_MSK)&&count){		count--;	}	if (!count){		printk("Write to phy failed, addr=%#x, data=%#x\n",address, value);		return -EIO;	}	return 0;}static int ether00_read_phy(struct net_device *dev, short address){	volatile int count = 1024;	writew( ETHER_MD_CA_BUSY_MSK |		(address & ETHER_MD_CA_ADDR_MSK),		ETHER_MD_CA(dev->base_addr));	/* Wait for the command to complete */	while((readw(ETHER_MD_CA(dev->base_addr)) & ETHER_MD_CA_BUSY_MSK)&&count){		count--;	}	if (!count){		printk(KERN_WARNING "Read from phy timed out\n");		return -EIO;	}	return readw(ETHER_MD_DATA(dev->base_addr));}static void ether00_phy_int(int irq_num, void* dev_id, struct pt_regs* regs){	struct net_device* dev=dev_id;	int irq_status;	irq_status=ether00_read_phy(dev, PHY_IRQ_CONTROL);	if(irq_status & PHY_IRQ_CONTROL_ANEG_COMP_INT_MSK){		/*		 * Autonegotiation complete on epxa10db. The mac doesn't		 * twig if we're in full duplex so we need to check the		 * phy status register and configure the mac accordingly		 */		if(ether00_read_phy(dev, PHY_STATUS)&(PHY_STATUS_10T_F_MSK|PHY_STATUS_100_X_F_MSK)){			int tmp;			tmp=readl(ETHER_MAC_CTL(dev->base_addr));			writel(tmp|ETHER_MAC_CTL_FULLDUP_MSK,ETHER_MAC_CTL(dev->base_addr));		}	}	if(irq_status&PHY_IRQ_CONTROL_LS_CHG_INT_MSK){		if(ether00_read_phy(dev, PHY_STATUS)& PHY_STATUS_LINK_MSK){			/* Link is up */			netif_carrier_on(dev);			//printk("Carrier on\n");		}else{			netif_carrier_off(dev);			//printk("Carrier off\n");		}	}}static void setup_blist_entry(struct sk_buff* skb,struct rx_blist_ent* blist_ent_ptr){	/* Make the buffer consistent with the cache as the mac is going to write	 * directly into it*/	blist_ent_ptr->fd.FDSystem=(unsigned int)skb;	blist_ent_ptr->bd.BuffData=(char*)__pa(skb->data);	consistent_sync(skb->data,PKT_BUF_SZ,PCI_DMA_FROMDEVICE);        /* align IP on 16 Byte (DMA_CTL set to skip 2 bytes) */	skb_reserve(skb,2);	blist_ent_ptr->bd.BuffLength=PKT_BUF_SZ-2;	blist_ent_ptr->fd.FDLength=1;	blist_ent_ptr->fd.FDCtl=FDCTL_COWNSFD_MSK;	blist_ent_ptr->bd.BDCtl=BDCTL_COWNSBD_MSK;}static int ether00_mem_init(struct net_device* dev){	struct net_priv* priv=dev->priv;	struct tx_fda_ent *tx_fd_ptr,*tx_end_ptr;	struct rx_blist_ent* blist_ent_ptr;	int i;	/*	 * Grab a block of on chip SRAM to contain the control stuctures for	 * the ethernet MAC. This uncached becuase it needs to be accesses by both	 * bus masters (cpu + mac). However, it shouldn't matter too much in terms	 * of speed as its on chip memory	 */	priv->dma_data=ioremap_nocache(EXC_SPSRAM_BLOCK0_BASE,EXC_SPSRAM_BLOCK0_SIZE );	if (!priv->dma_data)		return -ENOMEM;	priv->rx_fda_ptr=(struct rx_fda_ent*)priv->dma_data;	/*	 * Now share it out amongst the Frame descriptors and the buffer list	 */	priv->rx_blist_vp=(struct rx_blist_ent*)((unsigned int)priv->dma_data+RX_NUM_FDESC*sizeof(struct rx_fda_ent));	/*	 *Initalise the FDA list	 */	/* set ownership to the controller */	memset(priv->rx_fda_ptr,0x80,RX_NUM_FDESC*sizeof(struct rx_fda_ent));	/*	 *Initialise the buffer list	 */	blist_ent_ptr=priv->rx_blist_vp;	i=0;	while(blist_ent_ptr<(priv->rx_blist_vp+RX_NUM_BUFF)){		struct sk_buff *skb;		blist_ent_ptr->fd.FDLength=1;		skb=dev_alloc_skb(PKT_BUF_SZ);		if(skb){			setup_blist_entry(skb,blist_ent_ptr);			blist_ent_ptr->fd.FDNext=(FDA_DESC*)__dma_pa(blist_ent_ptr+1);			blist_ent_ptr->bd.BDStat=i++;			blist_ent_ptr++;		}		else		{			printk("Failed to initalise buffer list\n");		}	}	blist_ent_ptr--;	blist_ent_ptr->fd.FDNext=(FDA_DESC*)__dma_pa(priv->rx_blist_vp);	priv->tx_fdalist_vp=(struct tx_fda_ent*)(priv->rx_blist_vp+RX_NUM_BUFF);	/* Initialise the buffers to be a circular list. The mac will then go poll	 * the list until it finds a frame ready to transmit */	tx_end_ptr=priv->tx_fdalist_vp+TX_NUM_FDESC;	for(tx_fd_ptr=priv->tx_fdalist_vp;tx_fd_ptr<tx_end_ptr;tx_fd_ptr++){		tx_fd_ptr->fd.FDNext=(FDA_DESC*)__dma_pa((tx_fd_ptr+1));		tx_fd_ptr->fd.FDCtl=1;		tx_fd_ptr->fd.FDStat=0;		tx_fd_ptr->fd.FDLength=1;	}	/* Change the last FDNext pointer to make a circular list */	tx_fd_ptr--;	tx_fd_ptr->fd.FDNext=(FDA_DESC*)__dma_pa(priv->tx_fdalist_vp);	/* Point the device at the chain of Rx and Tx Buffers */	writel((unsigned int)__dma_pa(priv->rx_fda_ptr),ETHER_FDA_BAS(dev->base_addr));	writel((RX_NUM_FDESC-1)*sizeof(struct rx_fda_ent),ETHER_FDA_LIM(dev->base_addr));	writel((unsigned int)__dma_pa(priv->rx_blist_vp),ETHER_BLFRMPTR(dev->base_addr));	writel((unsigned int)__dma_pa(priv->tx_fdalist_vp),ETHER_TXFRMPTR(dev->base_addr));	return 0;}void ether00_mem_update(void* dev_id){	struct net_device* dev=dev_id;	struct net_priv* priv=dev->priv;	struct sk_buff* skb;	struct tx_fda_ent *fda_ptr=priv->tx_fdalist_vp;	struct rx_blist_ent* blist_ent_ptr;	unsigned long flags;	priv->tq_memupdate.sync=0;	//priv->tq_memupdate.list=	priv->memupdate_scheduled=0;	/* Transmit interrupt */	while(fda_ptr<(priv->tx_fdalist_vp+TX_NUM_FDESC)){		if(!(FDCTL_COWNSFD_MSK&fda_ptr->fd.FDCtl) && (ETHER_TX_STAT_COMP_MSK&fda_ptr->fd.FDStat)){			priv->stats.tx_packets++;			priv->stats.tx_bytes+=fda_ptr->bd.BuffLength;			skb=(struct sk_buff*)fda_ptr->fd.FDSystem;			//printk("%d:txcln:fda=%#x skb=%#x\n",jiffies,fda_ptr,skb);			dev_kfree_skb(skb);			fda_ptr->fd.FDSystem=0;			fda_ptr->fd.FDStat=0;			fda_ptr->fd.FDCtl=0;		}		fda_ptr++;	}	/* Fill in any missing buffers from the received queue */	spin_lock_irqsave(&priv->rx_lock,flags);	blist_ent_ptr=priv->rx_blist_vp;	while(blist_ent_ptr<(priv->rx_blist_vp+RX_NUM_BUFF)){		/* fd.FDSystem of 0 indicates we failed to allocate the buffer in the ISR */		if(!blist_ent_ptr->fd.FDSystem){			struct sk_buff *skb;			skb=dev_alloc_skb(PKT_BUF_SZ);			blist_ent_ptr->fd.FDSystem=(unsigned int)skb;			if(skb){				setup_blist_entry(skb,blist_ent_ptr);			}			else			{				break;			}		}		blist_ent_ptr++;	}	spin_unlock_irqrestore(&priv->rx_lock,flags);	if(priv->queue_stopped){		//printk("%d:cln:start q\n",jiffies);		netif_start_queue(dev);	}	if(priv->rx_disabled){		//printk("%d:enable_irq\n",jiffies);		priv->rx_disabled=0;		writel(ETHER_RX_CTL_RXEN_MSK,ETHER_RX_CTL(dev->base_addr));	}}static void ether00_int( int irq_num, void* dev_id, struct pt_regs* regs){	struct net_device* dev=dev_id;	struct net_priv* priv=dev->priv;	unsigned int   interruptValue;	interruptValue=readl(ETHER_INT_SRC(dev->base_addr));	//printk("INT_SRC=%x\n",interruptValue);	if(!(readl(ETHER_INT_SRC(dev->base_addr)) & ETHER_INT_SRC_IRQ_MSK))	{		return;		/* Interrupt wasn't caused by us!! */	}	if(readl(ETHER_INT_SRC(dev->base_addr))&	   (ETHER_INT_SRC_INTMACRX_MSK |	    ETHER_INT_SRC_FDAEX_MSK |	    ETHER_INT_SRC_BLEX_MSK)) {		struct rx_blist_ent* blist_ent_ptr;		struct rx_fda_ent* fda_ent_ptr;		struct sk_buff* skb;		fda_ent_ptr=priv->rx_fda_ptr;		spin_lock(&priv->rx_lock);		while(fda_ent_ptr<(priv->rx_fda_ptr+RX_NUM_FDESC)){			int result;			if(!(fda_ent_ptr->fd.FDCtl&FDCTL_COWNSFD_MSK))			{				/* This frame is ready for processing */				/*find the corresponding buffer in the bufferlist */				blist_ent_ptr=priv->rx_blist_vp+fda_ent_ptr->bd.BDStat;				skb=(struct sk_buff*)blist_ent_ptr->fd.FDSystem;				/* Pass this skb up the stack */				skb->dev=dev;				skb_put(skb,fda_ent_ptr->fd.FDLength);				skb->protocol=eth_type_trans(skb,dev);				skb->ip_summed=CHECKSUM_UNNECESSARY;				result=netif_rx(skb);				/* Update statistics */				priv->stats.rx_packets++;				priv->stats.rx_bytes+=fda_ent_ptr->fd.FDLength;				/* Free the FDA entry */				fda_ent_ptr->bd.BDStat=0xff;				fda_ent_ptr->fd.FDCtl=FDCTL_COWNSFD_MSK;				/* Allocate a new skb and point the bd entry to it */				blist_ent_ptr->fd.FDSystem=0;				skb=dev_alloc_skb(PKT_BUF_SZ);				//printk("allocskb=%#x\n",skb);				if(skb){					setup_blist_entry(skb,blist_ent_ptr);				}				else if(!priv->memupdate_scheduled){					int tmp;					/* There are no buffers at the moment, so schedule */					/* the background task to sort this out */					schedule_task(&priv->tq_memupdate);					priv->memupdate_scheduled=1;					printk(KERN_DEBUG "%s:No buffers",dev->name);					/* If this interrupt was due to a lack of buffers then					 * we'd better stop the receiver too */					if(interruptValue&ETHER_INT_SRC_BLEX_MSK){						priv->rx_disabled=1;						tmp=readl(ETHER_INT_SRC(dev->base_addr));						writel(tmp&~ETHER_RX_CTL_RXEN_MSK,ETHER_RX_CTL(dev->base_addr));						printk(KERN_DEBUG "%s:Halting rx",dev->name);					}				}			}			fda_ent_ptr++;		}		spin_unlock(&priv->rx_lock);		/* Clear the  interrupts */		writel(ETHER_INT_SRC_INTMACRX_MSK | ETHER_INT_SRC_FDAEX_MSK		       | ETHER_INT_SRC_BLEX_MSK,ETHER_INT_SRC(dev->base_addr));	}	if(readl(ETHER_INT_SRC(dev->base_addr))&ETHER_INT_SRC_INTMACTX_MSK){		if(!priv->memupdate_scheduled){			schedule_task(&priv->tq_memupdate);			priv->memupdate_scheduled=1;		}		/* Clear the interrupt */		writel(ETHER_INT_SRC_INTMACTX_MSK,ETHER_INT_SRC(dev->base_addr));	}	if (readl(ETHER_INT_SRC(dev->base_addr)) & (ETHER_INT_SRC_SWINT_MSK|						    ETHER_INT_SRC_INTEARNOT_MSK|						    ETHER_INT_SRC_INTLINK_MSK|						    ETHER_INT_SRC_INTEXBD_MSK|						    ETHER_INT_SRC_INTTXCTLCMP_MSK))	{		/*		 *	Not using any of these so they shouldn't happen		 *		 *	In the cased of INTEXBD - if you allocate more		 *      than 28 decsriptors you may need to think about this		 */		printk("Not using this interrupt\n");	}	if (readl(ETHER_INT_SRC(dev->base_addr)) &	    (ETHER_INT_SRC_INTSBUS_MSK |	     ETHER_INT_SRC_INTNRABT_MSK	     |ETHER_INT_SRC_DMPARERR_MSK))	{		/*		 * Hardware errors, we can either ignore them and hope they go away		 *or reset the device, I'll try the first for now to see if they happen		 */		printk("Hardware error\n");	}}static void ether00_setup_ethernet_address(struct net_device* dev){	int tmp;

⌨️ 快捷键说明

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