📄 pmcmspeth.c
字号:
/****************************************************************** * Copyright 2005 PMC-Sierra, Inc * * PMC-SIERRA DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. *//*********************************************************************** * mspeth.c : PMC-Sierra MSP EVM ethernet driver for linux * * Originally based on mspeth.c driver which contains substantially the * same hardware. * Based on skelton.c by Donald Becker. * ported by Andrew Hughes, Andrew_Hughes@pmc-sierra.com * * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * 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., * 675 Mass Ave, Cambridge, MA 02139, USA. */#include <asm/brecis/prom.h>#include <asm/brecis/brecisint.h>#include <asm/bootinfo.h>#include <asm/uaccess.h>/* Include file with the procfs structs and function protos */#include <linux/proc_fs.h>/* driver includes */#include "pmcmspeth.h"#include "bridge.h"unsigned char seth0mac[6],seth1mac[6];int nFlag[5];int tempdata[4];MAC smac;unsigned int sxjvalue;#define TIME_IP 50//added by Shi ->struct PORT{ unsigned flag; unsigned count;};struct IP{ unsigned int ip; unsigned long t; int flag;};struct COMP{ int nCount; struct IP Ip[10];};struct COMP scomp[65536]; //struct PORT nPubPort[65536];//struct PORT nPubIcmpPort[65536];//MAC smac1[5];VLAN svlan[6];VLAN tmpsvlan[5];//added by Shi <-/*static struct timer_list macTimer;static int macTimer_on;*/struct sdata{ struct sk_buff *skb[64]; int flag[64]; int nFlag[64];}data;int nwCur,nrCur;struct tasklet_struct wan_tasklet;unsigned long stime;//added by Shi ->unsigned short getmol(char *strKey){ int nStrLen=0; union suffix unTemp; int nCount=0; unsigned short nMark=0; nStrLen=3; unTemp.cMarker[0]=(strKey[nCount]&0xff); unTemp.cMarker[1]=(strKey[nCount+1]&0xff); nMark=unTemp.nMarker; for(nCount=1;nCount<nStrLen;nCount++) { unTemp.cMarker[0]=(strKey[nCount]&0xff); unTemp.cMarker[1]=(strKey[nCount+1]&0xff); nMark^=unTemp.nMarker; } return nMark;}unsigned short makeword(unsigned char hi,unsigned char lo){ unsigned short n; n=hi; n=n<<8; n|=lo; return n;}unsigned int makelong(unsigned short hi,unsigned short lo){ unsigned int n; n=hi; n=n<<16; n|=lo; return n;}//added by Shi <-/************************************************************************** * The name of the card. Is used for messages and in the requests for * io regions, irqs and dma channels. versions etc. Also, various other * identifying character constants. */static const char version[] = "pmcmspeth.c:v0.00 25/05/2005, PMC-Sierra\n";static const char cardname[] = "pmcmspeth";static const char drv_version[] = "$Revision: 1.1.4.2 $";static const char drv_reldate[] = "$Date: 2007/03/01 09:34:13 $";static const char drv_file[] = __FILE__;/************************************************************************** * Internal mspeth data structures. Two things to recall * (1) use the KSEG1 address to access hardware * (2) make sure of the indice ordering */static const u32 MacBases[MSPETH_MAX_UNITS + 1] = { MAC0_BASE, MAC1_BASE, MAC2_BASE, 0 };static const u32 MacRSTBases[MSPETH_MAX_UNITS + 1] = { MAC0_RST, MAC1_RST, MAC2_RST, 0 };static const u8 MacIRQs[MSPETH_MAX_UNITS + 1] = { BRECISINT_MAC0, BRECISINT_MAC1, BRECISINT_MAC2, 0 };static char *macname[] = { "ethaddr0", "ethaddr1", "ethaddr2", "unknown" };/* array of PHYs. Notice that the index here isn't for hardware (although we might have as many * PHYs as we have MACs) */static struct mspeth_phy phy_ctrl[MSPETH_MAX_UNITS + 3] = { {0, MD_UNASSIGNED_PHY, false},{0, MD_UNASSIGNED_PHY, false},{0, MD_UNASSIGNED_PHY, false},{0, MD_UNASSIGNED_PHY, false},{0, MD_UNASSIGNED_PHY, false},{0, MD_UNASSIGNED_PHY, false}};/* debugging flags *//* hammtrev, 2005-11-25: * For some odd reason, setting MSPETH_DEBUG to a non-zero value was setting * this variable to some garbage value when assigned statically here. Moving * assignment of this variable into mspeth_probe(). */static unsigned int mspeth_debug;/* A list of all installed mspeth devices. */static struct net_device *root_mspeth_dev = NULL;/************************************************************************** * Function prototypes *//* all the functions that get called by upper layers */static int mspeth_open(struct net_device *dev);static int mspeth_send_packet(struct sk_buff *skb, struct net_device *dev);static void mspeth_tx_timeout(struct net_device *dev);static void mspeth_interrupt(int irq, void *dev_id, struct pt_regs *regs);static void mspeth_hard_restart_bh(unsigned long devaddr);static void mspeth_rx(unsigned long devaddr);static void mspeth_txdone(unsigned long devaddr);static int mspeth_close(struct net_device *dev);static struct net_device_stats *mspeth_get_stats(struct net_device *dev);static void mspeth_set_multicast_list(struct net_device *dev);static int mspeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);/* private utility functions */static void mspeth_soft_restart(struct net_device *dev);static void mspeth_hard_restart(struct net_device *dev);static void mspeth_mac_reset(struct net_device *dev);static void mspeth_mac_init(struct net_device *dev);static void mspeth_phy_init(struct net_device *dev);static void mspeth_phy_reset(struct net_device *dev);static int mspeth_proc_info(char *buffer, char **start, off_t offset, int length);static bool mspeth_queue_init(struct net_device *dev);static void mspeth_set_arc_entry(struct mspeth_regs *tr, int index, unsigned char *addr);static void mspeth_check_tx_stat(struct net_device *dev, int status);static void mspeth_phyprobe(void);static void mspeth_init_phyaddr(struct net_device *dev);static void mspeth_init_cmdline(struct net_device *devp);static void mspeth_clear_queues(struct net_device *dev);static void mspeth_fatal_error_interrupt(struct net_device *dev, int status);/*############################################################################### ## Define the utility functions used by the the various other actual ## routines here. These should all be inline or macros ## ###############################################################################*/#define flush_memqueue() ({__asm__ volatile ("lw $0, %0" : : "m" (*MEM_CNFG1_REG));})#define flush_dmaqueue() ({__asm__ volatile ("lw $0, %0" : : "m" ((u32)&tr->Int_Src));})#define read_mspreg(addr) (*(volatile u32 *)((addr)))#define write_mspreg(val,addr) (*(volatile u32 *)((addr)) = (u32)(val))#define setbit_mspreg(val,addr) write_mspreg(read_mspreg(addr) | (val),addr)#define clrbit_mspreg(val,addr) write_mspreg(read_mspreg(addr) & ~(val),addr)#define vtonocache(p) KSEG1ADDR(virt_to_phys(p))#define rd_nocache(addr) (*(volatile u32 *)(KSEG1ADDR((u32)(addr))))#define wr_nocache(val,addr) (*(volatile u32 *)(KSEG1ADDR((u32)(addr))) = (u32)(val))#ifdef CONFIG_CPU_HAS_NONCOHERENT_CACHE/************************************************************************ * writeback_buffer - force the cache to write contents of cached buffer * to memory and invalidate the buffer. Must start on 16 byte boundary, * must "own" to next higher 15 byte boundary from end of buffer */inline static void writeback_buffer(void *bufaddr, unsigned int length){ unsigned long end = (unsigned long) bufaddr + length; bufaddr = (void *) ((unsigned int) bufaddr & ~(L1_CACHE_BYTES - 1)); while (((unsigned long) bufaddr + 0x200) < end) { cache16_unroll32(bufaddr, Hit_Writeback_Inv_D); bufaddr += 0x200; } while ((unsigned long) bufaddr < end) { flush_dcache_line((u32) bufaddr); bufaddr += L1_CACHE_BYTES; }}/************************************************************************ * writeback_qdesc - writeback a Q_Desc structure. Must start on a * 16 byte boundary */inline static void writeback_qdesc(struct Q_Desc *qdesc){ flush_dcache_line((u32) qdesc); flush_dcache_line(((u32) qdesc) + 16);}/************************************************************************ * writeback_bdesc - writeback a BDesc structure. */inline static void writeback_bdesc(struct BDesc *bdesc){ flush_dcache_line((u32) bdesc);}#else#define writeback_buffer(a,l) do {} while (0)#define writeback_qdesc(a) do {} while (0)#define writeback_bdesc(a) do {} while (0)#endif /* CONFIG_CPU_HAS_NONCOHERENT_CACHE *//************************************************************************ * pref - prefetch to data cache * Prefetch data to help improve performance */#define pref(base, offset) __asm__ __volatile__( \ "pref 0, %1(%0)" \ : \ : "r" (base), \ "I" (offset));/************************************************************************ * invalidate_buffer - Invalidate buffer cache * - must start on 16 byte boundary * - must "own" to next higher 16 byte boundary from end of buffer */inline static void invalidate_buffer(void *bufaddr, unsigned int length){ unsigned long end = (unsigned long) bufaddr + length; bufaddr = (void *) ((unsigned int) bufaddr & ~(L1_CACHE_BYTES - 1)); while (((unsigned long) bufaddr + 0x200) < end) { cache16_unroll32(bufaddr, Hit_Invalidate_D); bufaddr += 0x200; } while ((unsigned long) bufaddr < end) { invalidate_dcache_line((u32) bufaddr); bufaddr += L1_CACHE_BYTES; }}/************************************************************************ * invalidate_qdesc - Invalidate a Q_Desc structure. Must start on a * 16 byte boundary */inline static void invalidate_qdesc(struct Q_Desc *qdesc){ if (mspeth_debug > 2) printk(KERN_INFO "Invalidating Q_Desc at address 0x%08x\n", qdesc); invalidate_dcache_line((u32) qdesc); invalidate_dcache_line(((u32) qdesc) + 16);}/************************************************************************ * Read/Write a MDIO register. */inline static u32 read_mspphyreg(int phyindex, int phy_reg){ struct mspeth_regs *tr =// (struct mspeth_regs *) MacBases[phy_ctrl[phyindex].hwindex]; (struct mspeth_regs *) MacBases[phy_ctrl[0].hwindex]; int flags; u32 data; /* protect access with spin lock */// spin_lock_irqsave(&phy_ctrl[phyindex], flags); spin_lock_irqsave(&phy_ctrl[0], flags);// write_mspreg(MD_CA_BUSY_BIT | (phy_ctrl[phyindex].phyaddr << 5) | write_mspreg(MD_CA_BUSY_BIT | (phyindex << 5) | phy_reg, &tr->MD_CA); while (read_mspreg(&tr->MD_CA) & MD_CA_BUSY_BIT) {; } data = read_mspreg(&tr->MD_DATA); /* unlock */// spin_unlock_irqrestore(&phy_ctrl[phyindex], flags); spin_unlock_irqrestore(&phy_ctrl[0], flags); return data;}inline static void write_mspphyreg(u32 d, int phyindex, int phy_reg){ struct mspeth_regs *tr =// (struct mspeth_regs *) MacBases[phy_ctrl[phyindex].hwindex]; (struct mspeth_regs *) MacBases[phy_ctrl[0].hwindex]; int flags; /* protect access with spin lock */// spin_lock_irqsave(&phy_ctrl[phyindex], flags); spin_lock_irqsave(&phy_ctrl[0], flags); write_mspreg(d, &tr->MD_DATA); write_mspreg(MD_CA_BUSY_BIT | MD_CA_Wr |// (phy_ctrl[phyindex].phyaddr << 5) | phy_reg, (phyindex << 5) | phy_reg, &tr->MD_CA); while (read_mspreg(&tr->MD_CA) & MD_CA_BUSY_BIT) {; } /* unlock */// spin_unlock_irqrestore(&phy_ctrl[phyindex], flags); spin_unlock_irqrestore(&phy_ctrl[0], flags);}/************************************************************************** * allocate and align a max length socket buffer for this device */inline static struct sk_buff *mspeth_alloc_skb(struct net_device *dev){ struct sk_buff *skb; /* we need a bit more that an ethernet frame for the aligment stuff so * preallocate two more*/ skb = dev_alloc_skb(MSP_END_BUFSIZE + 2); if (skb == NULL) { printk(KERN_WARNING "MSETH (alloc_skb) %s: cannot allocate skb!\n", dev->name); return NULL; } /* align and fill out fields specific to our device. Notice that * our device is smart about FCS etc ...... */ skb_reserve(skb, 2); skb->dev = dev; skb->ip_summed = CHECKSUM_HW; return skb;}/************************************************************************** * error reporting functions -- used for debugging mostly */static void dump_qdesc(struct Q_Desc *fd){ printk(" Q_Desc(%p): %08x %08x %08x %08x\n", fd, fd->fd.FDNext, fd->fd.FDSystem, fd->fd.FDStat, fd->fd.FDCtl); printk(" BD: %08x %08x\n", fd->bd.BuffData, fd->bd.BDCtl);}static void dump_blist(struct BL_Desc *fd){ int i; printk(" BL_Desc(%p): %08x %08x %08x %08x\n", fd, fd->fd.FDNext, fd->fd.FDSystem, fd->fd.FDStat, fd->fd.FDCtl); for (i = 0; i < RX_BUF_NUM << 1; i++) printk(" BD #%d: %08x %08x\n", i, fd->bd[i].BuffData, fd->bd[i].BDCtl);}static void print_buf(char *add, int length){ int i; int len = length; printk("print_buf(%08x)(%x)\n", (unsigned int) add, length); if (len > 100) len = 100; for (i = 0; i < len; i++) { printk(" %2.2X", (unsigned char) add[i]); if (!(i % 16)) printk("\n"); } printk("\n");}static void print_eth(char *add){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -