📄 ether00.c
字号:
/* * 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/pci.h>#include <linux/netdevice.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 <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");static long base=0x60000000;static int irq=0x1;static int phy_irq=0x2;MODULE_PARM(base,"l");MODULE_PARM(irq,"i");MODULE_PARM(phy_irq,"i");#define PKT_BUF_SZ 1536 /* Size of each rx buffer */#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_PHYS_BASE 0x80000000#define ETHER00_IRQ 0x1/* 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;};static const char vendor_id[2]={0x07,0xed};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 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; blist_ent_ptr->fd.FDCtl=0x8000; skb=dev_alloc_skb(PKT_BUF_SZ); if(skb){ /* 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); skb_reserve(skb,2); /* align IP on 16 Byte (DMA_CTL set to skip 2 bytes) */ blist_ent_ptr->bd.BuffLength=PKT_BUF_SZ-2; blist_ent_ptr->bd.BDCtl=0x80; blist_ent_ptr->bd.BDStat=i++; blist_ent_ptr->fd.FDNext=(FDA_DESC*)__dma_pa(blist_ent_ptr+1); 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 fonds 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; 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 */ /* *Initialise the buffer list */ blist_ent_ptr=priv->rx_blist_vp; while(blist_ent_ptr<(priv->rx_blist_vp+RX_NUM_BUFF)){ /* BuffData of 0 indicates we failed to allocate the buffer in the ISR */ if(!blist_ent_ptr->bd.BuffData){ struct sk_buff *skb; skb=dev_alloc_skb(PKT_BUF_SZ); if(skb){ /* 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); skb_reserve(skb,2); /* align IP on 16 Byte (DMA_CTL set to skip 2 bytes) */ blist_ent_ptr->bd.BuffLength=PKT_BUF_SZ-2; blist_ent_ptr->fd.FDLength=1; blist_ent_ptr->bd.BDCtl=BDCTL_COWNSBD_MSK; blist_ent_ptr->fd.FDCtl=FDCTL_COWNSFD_MSK; } else { break; } } blist_ent_ptr++; } 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; 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*)fda_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 */ skb=dev_alloc_skb(PKT_BUF_SZ); if(skb){ blist_ent_ptr->bd.BuffData=(char*)__pa(skb->data); consistent_sync(skb->data,PKT_BUF_SZ,PCI_DMA_FROMDEVICE); skb_reserve(skb,2); /* align IP on 16 Byte (DMA_CTL set to skip 2 bytes) */ blist_ent_ptr->bd.BuffLength=PKT_BUF_SZ-2; blist_ent_ptr->fd.FDSystem=(unsigned int)skb; /* Pass it to the controller */ blist_ent_ptr->bd.BDCtl=BDCTL_COWNSBD_MSK; blist_ent_ptr->fd.FDCtl=FDCTL_COWNSFD_MSK; } 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; /* If this interrupt was due to a lack of buffers then * we'd better stop the receiver too */ if(interruptValueÐER_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)); } } } fda_ent_ptr++; } /* 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))ÐER_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 - I only allocated 16 descriptors * if you allocate more than 28 you may need to think about this */ printk("Not using this interrupt\n"); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -