diff options
Diffstat (limited to 'recipes/linux/linux-2.6.32/ep93xx/ep93xx-eth.patch')
-rw-r--r-- | recipes/linux/linux-2.6.32/ep93xx/ep93xx-eth.patch | 2718 |
1 files changed, 2718 insertions, 0 deletions
diff --git a/recipes/linux/linux-2.6.32/ep93xx/ep93xx-eth.patch b/recipes/linux/linux-2.6.32/ep93xx/ep93xx-eth.patch new file mode 100644 index 0000000000..776cafcbf5 --- /dev/null +++ b/recipes/linux/linux-2.6.32/ep93xx/ep93xx-eth.patch @@ -0,0 +1,2718 @@ +Index: linux-2.6.24.7/drivers/net/arm/ep93xx_eth.c +=================================================================== +--- linux-2.6.24.7.orig/drivers/net/arm/ep93xx_eth.c 2009-09-16 17:26:48.000000000 +0100 ++++ linux-2.6.24.7/drivers/net/arm/ep93xx_eth.c 2009-09-16 17:38:23.000000000 +0100 +@@ -1,916 +1,1586 @@ +-/* +- * EP93xx ethernet network device driver +- * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> +- * Dedicated to Marija Kulikova. +- * +- * 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. +- */ +- +-#include <linux/dma-mapping.h> ++/*---------------------------------------------------------------------------- ++ * ep93xx_eth.c ++ * Ethernet Device Driver for Cirrus Logic EP93xx. ++ * ++ * Copyright (C) 2003 by Cirrus Logic www.cirrus.com ++ * This software may be used and distributed according to the terms ++ * of the GNU Public License. ++ * ++ * This driver was written based on skeleton.c by Donald Becker and ++ * smc9194.c by Erik Stahlman. ++ * ++ * Theory of Operation ++ * Driver Configuration ++ * - Getting MAC address from system ++ * To setup identical MAC address for each target board, driver need ++ * to get a MAC address from system. Normally, system has a Serial ++ * EEPROM or other media to store individual MAC address when ++ * manufacturing. ++ * The macro GET_MAC_ADDR is prepared to get the MAC address from ++ * system and one should supply a routine for this purpose. ++ * Driver Initialization ++ * DMA Operation ++ * Cache Coherence ++ * ++ * History: ++ * 07/19/01 0.1 Sungwook Kim initial release ++ * 10/16/01 0.2 Sungwook Kim add workaround for ignorance of Tx request while sending frame ++ * add some error stuations handling ++ * ++ * 03/25/03 Melody Lee Modified for EP93xx ++ *--------------------------------------------------------------------------*/ + #include <linux/module.h> ++#include <linux/version.h> + #include <linux/kernel.h> +-#include <linux/netdevice.h> +-#include <linux/mii.h> +-#include <linux/etherdevice.h> +-#include <linux/ethtool.h> +-#include <linux/init.h> +-#include <linux/moduleparam.h> +-#include <linux/platform_device.h> ++#include <linux/sched.h> ++#include <linux/types.h> ++#include <linux/fcntl.h> ++#include <linux/interrupt.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/in.h> + #include <linux/delay.h> +-#include <asm/arch/ep93xx-regs.h> +-#include <asm/arch/platform.h> ++#include <linux/slab.h> ++#include <linux/string.h> ++#include <linux/platform_device.h> ++#include <linux/dma-mapping.h> ++#include <asm/system.h> ++#include <asm/bitops.h> + #include <asm/io.h> ++#include <asm/dma.h> ++#include <asm/irq.h> ++#include <linux/errno.h> ++#include <linux/init.h> + +-#define DRV_MODULE_NAME "ep93xx-eth" +-#define DRV_MODULE_VERSION "0.1" ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> + +-#define RX_QUEUE_ENTRIES 64 +-#define TX_QUEUE_ENTRIES 8 ++#include <asm/arch/hardware.h> + +-#define MAX_PKT_SIZE 2044 +-#define PKT_BUF_SIZE 2048 ++#include "ep93xx_eth.h" + +-#define REG_RXCTL 0x0000 +-#define REG_RXCTL_DEFAULT 0x00073800 +-#define REG_TXCTL 0x0004 +-#define REG_TXCTL_ENABLE 0x00000001 +-#define REG_MIICMD 0x0010 +-#define REG_MIICMD_READ 0x00008000 +-#define REG_MIICMD_WRITE 0x00004000 +-#define REG_MIIDATA 0x0014 +-#define REG_MIISTS 0x0018 +-#define REG_MIISTS_BUSY 0x00000001 +-#define REG_SELFCTL 0x0020 +-#define REG_SELFCTL_RESET 0x00000001 +-#define REG_INTEN 0x0024 +-#define REG_INTEN_TX 0x00000008 +-#define REG_INTEN_RX 0x00000007 +-#define REG_INTSTSP 0x0028 +-#define REG_INTSTS_TX 0x00000008 +-#define REG_INTSTS_RX 0x00000004 +-#define REG_INTSTSC 0x002c +-#define REG_AFP 0x004c +-#define REG_INDAD0 0x0050 +-#define REG_INDAD1 0x0051 +-#define REG_INDAD2 0x0052 +-#define REG_INDAD3 0x0053 +-#define REG_INDAD4 0x0054 +-#define REG_INDAD5 0x0055 +-#define REG_GIINTMSK 0x0064 +-#define REG_GIINTMSK_ENABLE 0x00008000 +-#define REG_BMCTL 0x0080 +-#define REG_BMCTL_ENABLE_TX 0x00000100 +-#define REG_BMCTL_ENABLE_RX 0x00000001 +-#define REG_BMSTS 0x0084 +-#define REG_BMSTS_RX_ACTIVE 0x00000008 +-#define REG_RXDQBADD 0x0090 +-#define REG_RXDQBLEN 0x0094 +-#define REG_RXDCURADD 0x0098 +-#define REG_RXDENQ 0x009c +-#define REG_RXSTSQBADD 0x00a0 +-#define REG_RXSTSQBLEN 0x00a4 +-#define REG_RXSTSQCURADD 0x00a8 +-#define REG_RXSTSENQ 0x00ac +-#define REG_TXDQBADD 0x00b0 +-#define REG_TXDQBLEN 0x00b4 +-#define REG_TXDQCURADD 0x00b8 +-#define REG_TXDENQ 0x00bc +-#define REG_TXSTSQBADD 0x00c0 +-#define REG_TXSTSQBLEN 0x00c4 +-#define REG_TXSTSQCURADD 0x00c8 +-#define REG_MAXFRMLEN 0x00e8 ++/*---------------------------------------------------------------------------- ++ * The name of the card. ++ * It is used for messages and in the requests for io regions, irqs and ... ++ * This device is not in a card but I used same name in skeleton.c file. ++ *--------------------------------------------------------------------------*/ ++#define cardname "ep93xx-eth" ++ ++ ++/**** default MAC address *************/ ++static const U8 default_mac[6] = {0x00, 0xba, 0xd0, 0x0b, 0xad, 0x00}; ++ ++/*---------------------------------------------------------------------------- ++ * Some definitions belong to the operation of this driver. ++ * You should understand how it affect to driver before any modification. ++ *--------------------------------------------------------------------------*/ ++ ++/**** Interrupt Sources in Use *******************************************/ ++/*#define Default_IntSrc (IntEn_RxMIE|IntEn_RxSQIE|IntEn_TxLEIE|IntEn_TIE|IntEn_TxSQIE|IntEn_RxEOFIE|IntEn_RxEOBIE|IntEn_RxHDRIE) ++*/ ++#define Default_IntSrc (IntEn_TxSQIE|IntEn_RxEOFIE|IntEn_RxEOBIE|IntEn_RxHDRIE) ++ ++/**** Length of Device Queue in number of entries ++ (must be less than or equal to 255) ********************************/ ++#define LEN_QueRxDesc 64 /*length of Rx Descriptor Queue (4 or bigger) Must be power of 2.*/ ++#define LEN_QueRxSts LEN_QueRxDesc /*length of Rx Status Queue*/ ++#define LEN_QueTxDesc 8 /*length of Tx Descriptor Queue (4 or bigger) Must be power of 2.*/ ++#define LEN_QueTxSts LEN_QueTxDesc /*length of Tx Status Queue*/ ++ ++/**** Tx Queue fill-up level control *************************************/ ++#define LVL_TxStop LEN_QueTxDesc - 2 /*level to ask the stack to stop Tx*/ ++#define LVL_TxResume 2 /*level to ask the stack to resume Tx*/ ++ ++/**** Rx Buffer length in bytes ******************************************/ ++#define LEN_RxBuf (1518+2+16) /*length of Rx buffer, must be 4-byte aligned*/ ++#define LEN_TxBuf LEN_RxBuf ++ ++/*---------------------------------------------------------------------------- ++ * MACRO for ease ++ *--------------------------------------------------------------------------*/ ++#define Align32(a) (((unsigned int)(a)+3)&~0x03) /*32bit address alignment*/ ++#define IdxNext(idxCur,len) (((idxCur)+1)%(len)) /*calc next array index number*/ ++ ++/**** malloc/free routine for DMA buffer **********************************/ ++ /*use non-cached DMA buffer*/ ++#define MALLOC_DMA(size, pPhyAddr) dma_alloc_writecombine(NULL, (size), (dma_addr_t*)(pPhyAddr), GFP_KERNEL | GFP_DMA) ++//#define FREE_DMA(size, vaddr, paddr) dma_free_writecombine(NULL, (size), (vaddr), (paddr)) + +-struct ep93xx_rdesc +-{ +- u32 buf_addr; +- u32 rdesc1; +-}; ++/*---------------------------------------------------------------------------- ++ * DEBUGGING LEVELS ++ * ++ * 0 for normal operation ++ * 1 for slightly more details ++ * >2 for various levels of increasingly useless information ++ * 2 for interrupt tracking, status flags ++ * 3 for packet dumps, etc. ++ *--------------------------------------------------------------------------*/ ++//#define _DBG_3 ++//#define _DBG_2 ++//#define _DBG_1 ++//#define _DBG ++ ++#ifdef _DBG_3 ++#define PRINTK3( fmt, arg... ) printk( fmt, ##arg ) ++#else ++#define PRINTK3( fmt, arg... ) ++#endif ++ ++#ifdef _DBG_2 ++#define PRINTK2( fmt, arg... ) printk( fmt, ##arg ) ++#else ++#define PRINTK2( fmt, arg... ) ++#endif ++ ++#ifdef _DBG_1 ++#define PRINTK1( fmt, arg... ) printk( fmt, ##arg ) ++#else ++#define PRINTK1( fmt, arg... ) ++#endif ++ ++#ifdef _DBG ++#define PRINTK(x) printk x ++#else ++#define PRINTK(x) ++#endif ++ ++ ++ ++#define _PRTK_ENTRY PRINTK2 /*to trace function entries*/ ++#define _PRTK_SWERR PRINTK /*logical S/W error*/ ++#define _PRTK_SYSFAIL PRINTK /*system service failure*/ ++#define _PRTK_HWFAIL PRINTK /*H/W operation failure message*/ ++#define _PRTK_WARN PRINTK1 /*warning information*/ ++#define _PRTK_INFO PRINTK2 /*general information*/ ++#define _PRTK_ENTRY_ISR PRINTK3 /*to trace function entries belong to ISR*/ ++#define _PRTK_WARN_ISR PRINTK1 /*warning informations from ISR*/ ++#define _PRTK_INFO_ISR PRINTK3 /*general informations from ISR*/ ++#define _PRTK_ PRINTK /*for temporary print out*/ ++ ++#if 0 ++# define _PRTK_DUMP PRINTK1 /*to dump large amount of debug info*/ ++#endif ++ ++/*---------------------------------------------------------------------------- ++ * Custom Data Structures ++ *--------------------------------------------------------------------------*/ ++ ++/**** the information about the buffer passed to device. ++ there are matching bufferDescriptor informations ++ for each Tx/Rx Descriptor Queue entry to trace ++ the buffer within those queues. ************************************/ ++typedef struct bufferDescriptor { ++ void *vaddr; /*virtual address representing the buffer passed to device*/ ++ int(*pFreeRtn)(void *pBuf); /*free routine*/ ++} bufferDescriptor; ++ ++/**** device privite informations ++ pointed by struct net_device::priv *********************************/ ++typedef struct ep93xxEth_info { ++ /**** static device informations **********************************/ ++ struct { ++ int id; /*device instance ID (0 for 1st and so on) ++ must be first element of this structure*/ ++ receiveDescriptor *pQueRxDesc; /*pointer to Rx Descriptor Queue*/ ++ receiveStatus *pQueRxSts; /*pointer to Rx Status Queue*/ ++ transmitDescriptor *pQueTxDesc; /*pointer to Tx Descriptor Queue*/ ++ transmitStatus *pQueTxSts; /*pointer to Tx Status Queue*/ ++ unsigned char *pRxBuf; /*base of Rx Buffer pool*/ ++ unsigned char *pTxBuf; /*base of Tx Buffer pool*/ ++ unsigned long phyQueueBase; /*physical address of device queues*/ ++ unsigned long phyQueRxDesc, /*physical address of Rx Descriptor Queue*/ ++ phyQueRxSts, /*physical address of Rx Status Queue*/ ++ phyQueTxDesc, /*physical address of Tx Descriptor Queue*/ ++ phyQueTxSts, /*physical address of Tx Status Queue*/ ++ phyRxBuf, /*physical address of Rx Buffer pool*/ ++ phyTxBuf; /*physical address of Tx Buffer pool*/ ++ bufferDescriptor *pRxBufDesc, /*info of Rx Buffers*/ ++ *pTxBufDesc; /*info of Tx Buffers*/ ++ int miiIdPhy; /*MII Bus ID of Ethernet PHY*/ ++ } s; ++ /**** dynamic information, subject to clear when device open ******/ ++ struct { ++ struct net_device_stats stats; /*statistic data*/ ++ int idxQueRxDesc, /*next processing index of device queues*/ ++ idxQueRxSts, ++ idxQueTxDescHead, ++ idxQueTxDescTail, ++ idxQueTxSts; ++ int txStopped; /*flag for Tx condition*/ ++ } d; ++} ep93xxEth_info; ++ ++/*---------------------------------------------------------------------------- ++ * Global Variables ++ *--------------------------------------------------------------------------*/ ++static int numOfInstance = 0; /*total number of device instance, 0 means the 1st instance.*/ ++ ++//static struct sk_buff gTxSkb; ++//static char gTxBuff[LEN_TxBuf]; + +-#define RDESC1_NSOF 0x80000000 +-#define RDESC1_BUFFER_INDEX 0x7fff0000 +-#define RDESC1_BUFFER_LENGTH 0x0000ffff ++//static char gTxDataBuff[LEN_QueTxDesc][LEN_TxBuf]; + +-struct ep93xx_rstat +-{ +- u32 rstat0; +- u32 rstat1; +-}; ++// To know if PHY auto-negotiation has done? ++static int gPhyAutoNegoDone=0; + +-#define RSTAT0_RFP 0x80000000 +-#define RSTAT0_RWE 0x40000000 +-#define RSTAT0_EOF 0x20000000 +-#define RSTAT0_EOB 0x10000000 +-#define RSTAT0_AM 0x00c00000 +-#define RSTAT0_RX_ERR 0x00200000 +-#define RSTAT0_OE 0x00100000 +-#define RSTAT0_FE 0x00080000 +-#define RSTAT0_RUNT 0x00040000 +-#define RSTAT0_EDATA 0x00020000 +-#define RSTAT0_CRCE 0x00010000 +-#define RSTAT0_CRCI 0x00008000 +-#define RSTAT0_HTI 0x00003f00 +-#define RSTAT1_RFP 0x80000000 +-#define RSTAT1_BUFFER_INDEX 0x7fff0000 +-#define RSTAT1_FRAME_LENGTH 0x0000ffff ++/*============================================================================ ++ * ++ * Internal Routines ++ * ++ *==========================================================================*/ + +-struct ep93xx_tdesc ++/***************************************************************************** ++* free_skb() ++*****************************************************************************/ ++static int ++free_skb(void *pSkb) + { +- u32 buf_addr; +- u32 tdesc1; +-}; ++ dev_kfree_skb_irq((struct sk_buff*)pSkb); ++ return 0; ++} + +-#define TDESC1_EOF 0x80000000 +-#define TDESC1_BUFFER_INDEX 0x7fff0000 +-#define TDESC1_BUFFER_ABORT 0x00008000 +-#define TDESC1_BUFFER_LENGTH 0x00000fff ++/***************************************************************************** ++* waitOnReg32() ++*****************************************************************************/ ++static int ++waitOnReg32(struct net_device *pD, int reg, unsigned long mask, ++ unsigned long expect, int tout) ++{ ++ int i; ++ int dt; ++ ++ for (i = 0; i < 10000; ) { ++ dt = RegRd32(reg); ++ dt = (dt ^ expect) & mask; ++ if (dt == 0) ++ break; ++ if (tout) ++ i++; ++ } + +-struct ep93xx_tstat +-{ +- u32 tstat0; +-}; ++ return dt; ++} + +-#define TSTAT0_TXFP 0x80000000 +-#define TSTAT0_TXWE 0x40000000 +-#define TSTAT0_FA 0x20000000 +-#define TSTAT0_LCRS 0x10000000 +-#define TSTAT0_OW 0x04000000 +-#define TSTAT0_TXU 0x02000000 +-#define TSTAT0_ECOLL 0x01000000 +-#define TSTAT0_NCOLL 0x001f0000 +-#define TSTAT0_BUFFER_INDEX 0x00007fff +- +-struct ep93xx_descs +-{ +- struct ep93xx_rdesc rdesc[RX_QUEUE_ENTRIES]; +- struct ep93xx_tdesc tdesc[TX_QUEUE_ENTRIES]; +- struct ep93xx_rstat rstat[RX_QUEUE_ENTRIES]; +- struct ep93xx_tstat tstat[TX_QUEUE_ENTRIES]; +-}; ++#define phy_wr(reg,dt) _phy_write(pD, ((ep93xxEth_info*)pD->priv)->s.miiIdPhy, (reg), (dt)) ++#define phy_rd(reg) _phy_read(pD, ((ep93xxEth_info*)pD->priv)->s.miiIdPhy, (reg)) ++#define phy_waitRdy() waitOnReg32(pD, REG_MIISts,MIISts_Busy, ~MIISts_Busy, 1) + +-struct ep93xx_priv ++/***************************************************************************** ++* _phy_write() ++*****************************************************************************/ ++static void ++_phy_write(struct net_device *pD, int idPhy, int reg, U16 dt) + { +- struct resource *res; +- void *base_addr; +- int irq; ++ phy_waitRdy(); ++ RegWr32(REG_MIIData, dt); ++ RegWr32(REG_MIICmd, MIICmd_OP_WR | ((idPhy & 0x1f) << 5) | ++ ((reg & 0x1f) << 0)); ++} + +- struct ep93xx_descs *descs; +- dma_addr_t descs_dma_addr; ++/***************************************************************************** ++* _phy_read() ++*****************************************************************************/ ++static U16 ++_phy_read(struct net_device *pD,int idPhy,int reg) ++{ ++ U16 dt; + +- void *rx_buf[RX_QUEUE_ENTRIES]; +- void *tx_buf[TX_QUEUE_ENTRIES]; ++ phy_waitRdy(); ++ RegWr32(REG_MIICmd, MIICmd_OP_RD | ((idPhy & 0x1f) << 5) | ++ ((reg & 0x1f) << 0)); ++ phy_waitRdy(); ++ dt = (unsigned short)RegRd32(REG_MIIData); + +- spinlock_t rx_lock; +- unsigned int rx_pointer; +- unsigned int tx_clean_pointer; +- unsigned int tx_pointer; +- spinlock_t tx_pending_lock; +- unsigned int tx_pending; ++ return dt; ++} + +- struct net_device *dev; +- struct napi_struct napi; ++#ifndef _PRTK_DUMP ++#define _dbg_phy_dumpReg(pD) ++#else ++/***************************************************************************** ++* _dbg_phy_dumpReg() ++*****************************************************************************/ ++static void ++_dbg_phy_dumpReg(struct net_device *pD) ++{ ++ _PRTK_DUMP(("Dumping registers of Ethernet PHY\n")); ++ _PRTK_DUMP((" pD:0x%p, Eth Base Address:0x%x\n", pD, ++ (unsigned int)pD->base_addr)); + +- struct net_device_stats stats; ++ _PRTK_DUMP((" 0-3:0x%04x 0x%04x 0x%04x 0x%04x\n", ++ phy_rd(0), phy_rd(1), phy_rd(2), phy_rd(3))); ++ _PRTK_DUMP((" 4-6:0x%04x 0x%04x 0x%04x\n", ++ phy_rd(4), phy_rd(5), phy_rd(6))); ++ _PRTK_DUMP((" 16-19:0x%04x 0x%04x 0x%04x 0x%04x\n", ++ phy_rd(16), phy_rd(17), phy_rd(18), phy_rd(19))); ++ _PRTK_DUMP((" 20:0x%04x\n", phy_rd(20))); ++} ++#endif + +- struct mii_if_info mii; +- u8 mdc_divisor; +-}; ++/***************************************************************************** ++* phy_autoNegotiation() ++*****************************************************************************/ ++static int ++phy_autoNegotiation(struct net_device *pD) ++{ ++ U16 val; ++ U16 oldVal; ++ U16 count = 0; + +-#define rdb(ep, off) __raw_readb((ep)->base_addr + (off)) +-#define rdw(ep, off) __raw_readw((ep)->base_addr + (off)) +-#define rdl(ep, off) __raw_readl((ep)->base_addr + (off)) +-#define wrb(ep, off, val) __raw_writeb((val), (ep)->base_addr + (off)) +-#define wrw(ep, off, val) __raw_writew((val), (ep)->base_addr + (off)) +-#define wrl(ep, off, val) __raw_writel((val), (ep)->base_addr + (off)) ++ phy_wr(4, 0x01e1); /*Set 802.3, 100M/10M Full/Half ability*/ ++ phy_wr(0, (1 << 12) | (1 << 9)); /* enable auto negotiation*/ ++ while (1) { ++ val = phy_rd(1); /* read BM status Reg*/ ++ if (val & 0x0020) /* if Auto_Neg_complete?*/ ++ break; ++ else { ++ if (count >= 3) ++ return -1; ++ mdelay(1000);//delay 1 second. ++ count++; ++ } ++ } + +-static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg); ++ //CS8952 PHY needs the delay. Otherwise it won't send the 1st frame. ++ mdelay(1000);//delay 1 second. + +-static struct net_device_stats *ep93xx_get_stats(struct net_device *dev) +-{ +- struct ep93xx_priv *ep = netdev_priv(dev); +- return &(ep->stats); ++ val = phy_rd(5); /* read ANLPAR Reg*/ ++ if (val & 0x0140) { /* if 100M_FDX or 10M_FDX?*/ ++ oldVal = RegRd16(REG_TestCTL); ++ /*Enable MAC's Full Duplex mode.*/ ++ RegWr16(REG_TestCTL, oldVal | TestCTL_MFDX); ++ } ++ ++ gPhyAutoNegoDone = 1; ++ ++ return 0; + } + +-static int ep93xx_rx(struct net_device *dev, int processed, int budget) ++/***************************************************************************** ++* phy_init() ++*****************************************************************************/ ++static int ++phy_init(struct net_device *pD) ++{ ++ U32 oldVal; ++ int status = -1; ++ U16 val; ++ ++ oldVal = RegRd32(REG_SelfCTL); ++ ++ /* ++ * Set MDC clock to be divided by 8 and disable PreambleSuppress bit ++ */ ++ RegWr32(REG_SelfCTL, 0x4e00); ++ ++ /* ++ * read BM status Reg; Link Status Bit remains cleared until the Reg is ++ * read. ++ */ ++ val = phy_rd(1); ++ ++ /* ++ * read BMStaReg again to get the current link status ++ */ ++ val = phy_rd(1); ++ if (val & 0x0004) ++ status = phy_autoNegotiation(pD); ++ ++ RegWr32(REG_SelfCTL, oldVal); ++ ++ return status; ++} ++ ++/***************************************************************************** ++* phy_reset() ++*****************************************************************************/ ++#if 0 ++static int ++phy_reset(struct net_device *pD) + { +- struct ep93xx_priv *ep = netdev_priv(dev); ++ int i; + +- while (processed < budget) { +- int entry; +- struct ep93xx_rstat *rstat; +- u32 rstat0; +- u32 rstat1; +- int length; +- struct sk_buff *skb; + +- entry = ep->rx_pointer; +- rstat = ep->descs->rstat + entry; ++ phy_wr(0, 1 << 15); + +- rstat0 = rstat->rstat0; +- rstat1 = rstat->rstat1; +- if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP)) ++ for (i = 0; i < 1000; i++) ++ if ((phy_rd(0) & (1 << 15)) == 0) + break; + +- rstat->rstat0 = 0; +- rstat->rstat1 = 0; ++ if ((phy_rd(0) & (1 << 15)) != 0) { ++ _PRTK_HWFAIL(("phy_reset(): PHY reset does not self-clear\n")); ++ return -1; ++ } + +- if (!(rstat0 & RSTAT0_EOF)) +- printk(KERN_CRIT "ep93xx_rx: not end-of-frame " +- " %.8x %.8x\n", rstat0, rstat1); +- if (!(rstat0 & RSTAT0_EOB)) +- printk(KERN_CRIT "ep93xx_rx: not end-of-buffer " +- " %.8x %.8x\n", rstat0, rstat1); +- if ((rstat1 & RSTAT1_BUFFER_INDEX) >> 16 != entry) +- printk(KERN_CRIT "ep93xx_rx: entry mismatch " +- " %.8x %.8x\n", rstat0, rstat1); +- +- if (!(rstat0 & RSTAT0_RWE)) { +- ep->stats.rx_errors++; +- if (rstat0 & RSTAT0_OE) +- ep->stats.rx_fifo_errors++; +- if (rstat0 & RSTAT0_FE) +- ep->stats.rx_frame_errors++; +- if (rstat0 & (RSTAT0_RUNT | RSTAT0_EDATA)) +- ep->stats.rx_length_errors++; +- if (rstat0 & RSTAT0_CRCE) +- ep->stats.rx_crc_errors++; +- goto err; +- } +- +- length = rstat1 & RSTAT1_FRAME_LENGTH; +- if (length > MAX_PKT_SIZE) { +- printk(KERN_NOTICE "ep93xx_rx: invalid length " +- " %.8x %.8x\n", rstat0, rstat1); +- goto err; +- } +- +- /* Strip FCS. */ +- if (rstat0 & RSTAT0_CRCI) +- length -= 4; +- +- skb = dev_alloc_skb(length + 2); +- if (likely(skb != NULL)) { +- skb_reserve(skb, 2); +- dma_sync_single(NULL, ep->descs->rdesc[entry].buf_addr, +- length, DMA_FROM_DEVICE); +- skb_copy_to_linear_data(skb, ep->rx_buf[entry], length); +- skb_put(skb, length); +- skb->protocol = eth_type_trans(skb, dev); ++ phy_wr(19, 0x00); ++ phy_wr(4, (1 << 8) | (1 << 7) | (1 << 6) | (1 << 5) | (0x01 << 0)); ++ phy_wr(0, (1 << 12) | (1 << 9)); + +- dev->last_rx = jiffies; ++ return 0; ++} ++#endif + +- netif_receive_skb(skb); ++#ifndef _PRTK_DUMP ++# define _dbg_ep93xxEth_dumpQueues(pD) ++#else ++/***************************************************************************** ++* _dbg_ep93xxEth_dumpQueues() ++*****************************************************************************/ ++static void ++_dbg_ep93xxEth_dumpQueues(struct net_device *pD) ++{ ++ struct ep93xxEth_info *pP = pD->priv; ++ int i; + +- ep->stats.rx_packets++; +- ep->stats.rx_bytes += length; +- } else { +- ep->stats.rx_dropped++; +- } ++ _PRTK_DUMP(("Dumping Descriptor/Status Queues\n")); ++ _PRTK_DUMP((" pD:0x%p, Base Address:0x%x\n", pD, ++ (unsigned int)pD->base_addr)); ++ ++ _PRTK_DUMP((" o Rx Status Queue: at 0x%p, %d entries\n", ++ pP->s.pQueRxSts, LEN_QueRxSts)); ++ for (i = 0; i < LEN_QueRxSts; i++) ++ _PRTK_DUMP((" - %2d: 0x%08x 0x%08x \n", i, ++ (unsigned int)pP->s.pQueRxSts[i].w.e0, ++ (unsigned int)pP->s.pQueRxSts[i].w.e1)); ++ ++ _PRTK_DUMP((" o Rx Descriptor Queue: at 0x%p, %d entries\n", ++ pP->s.pQueRxDesc, LEN_QueRxDesc)); ++ for (i = 0; i < LEN_QueRxDesc; i++) ++ _PRTK_DUMP((" - %2d: 0x%08x 0x%08x \n", i, ++ (unsigned int)pP->s.pQueRxDesc[i].w.e0, ++ (unsigned int)pP->s.pQueRxDesc[i].w.e1)); ++ ++ _PRTK_DUMP((" o Tx Status Queue: at 0x%p, %d entries\n", ++ pP->s.pQueTxSts, LEN_QueTxSts)); ++ for (i = 0; i < LEN_QueTxSts; i++) ++ _PRTK_DUMP((" - %2d: 0x%08x \n", i, ++ (unsigned int)pP->s.pQueTxSts[i].w.e0)); ++ ++ _PRTK_DUMP((" o Tx Descriptor Queue: at 0x%p, %d entries\n", ++ pP->s.pQueTxDesc, LEN_QueTxDesc)); ++ for (i = 0; i < LEN_QueTxDesc; i++) ++ _PRTK_DUMP((" - %2d: 0x%08x 0x%08x \n", i, ++ (unsigned int)pP->s.pQueTxDesc[i].w.e0, ++ (unsigned int)pP->s.pQueTxDesc[i].w.e1)); ++} ++#endif ++ ++/***************************************************************************** ++* devQue_start() ++* ++ make descriptor queues active ++ allocate queue entries if needed ++ and set device registers up to make it operational ++ assume device has been initialized ++* ++*****************************************************************************/ ++static int ++devQue_start(struct net_device *pD) ++{ ++ int err; ++ struct ep93xxEth_info *pP = pD->priv; ++ int i; ++ void *pBuf; ++ U32 phyA; + +-err: +- ep->rx_pointer = (entry + 1) & (RX_QUEUE_ENTRIES - 1); +- processed++; +- } ++ RegWr32(REG_BMCtl, BMCtl_RxDis | BMCtl_TxDis | RegRd32(REG_BMCtl)); ++ err = waitOnReg32(pD, REG_BMSts, BMSts_TxAct, ~BMSts_TxAct, 1); ++ err |= waitOnReg32(pD, REG_BMSts, BMSts_RxAct, ~BMSts_RxAct, 1); ++ if (err) ++ _PRTK_HWFAIL(("devQue_start(): BM does not stop\n")); ++ ++ memset(pP->s.pQueTxSts, 0, sizeof(pP->s.pQueTxSts[0]) * LEN_QueTxSts); ++ pP->d.idxQueTxSts = 0; ++ RegWr32(REG_TxSBA, pP->s.phyQueTxSts); ++ RegWr32(REG_TxSCA, pP->s.phyQueTxSts); ++ RegWr16(REG_TxSBL, sizeof(pP->s.pQueTxSts[0]) * LEN_QueTxSts); ++ RegWr16(REG_TxSCL, sizeof(pP->s.pQueTxSts[0]) * LEN_QueTxSts); ++ ++ memset(pP->s.pQueTxDesc, 0, ++ sizeof(pP->s.pQueTxDesc[0]) * LEN_QueTxDesc); ++ pP->d.idxQueTxDescHead = pP->d.idxQueTxDescTail = 0; ++ RegWr32(REG_TxDBA, pP->s.phyQueTxDesc); ++ RegWr32(REG_TxDCA, pP->s.phyQueTxDesc); ++ RegWr16(REG_TxDBL, sizeof(pP->s.pQueTxDesc[0]) * LEN_QueTxDesc); ++ RegWr16(REG_TxDCL, sizeof(pP->s.pQueTxDesc[0]) * LEN_QueTxDesc); ++ ++ memset(pP->s.pQueRxSts, 0, sizeof(pP->s.pQueRxSts[0]) * LEN_QueRxSts); ++ pP->d.idxQueRxSts = 0; ++ RegWr32(REG_RxSBA, pP->s.phyQueRxSts); ++ RegWr32(REG_RxSCA, pP->s.phyQueRxSts); ++ RegWr16(REG_RxSBL, sizeof(pP->s.pQueRxSts[0]) * LEN_QueRxSts); ++ RegWr16(REG_RxSCL, sizeof(pP->s.pQueRxSts[0]) * LEN_QueRxSts); ++ ++ memset(pP->s.pQueRxDesc, 0, ++ sizeof(pP->s.pQueRxDesc[0]) * LEN_QueRxDesc); ++ phyA = pP->s.phyRxBuf; ++ for (i = 0; i < LEN_QueRxDesc; i++) { ++ pP->s.pQueRxDesc[i].f.bi = i; ++ pP->s.pQueRxDesc[i].f.ba = phyA; ++ pP->s.pQueRxDesc[i].f.bl = LEN_RxBuf; ++ phyA += (LEN_RxBuf + 3) & ~0x03; ++ } ++ pP->d.idxQueRxDesc = 0; ++ RegWr32(REG_RxDBA, pP->s.phyQueRxDesc); ++ RegWr32(REG_RxDCA, pP->s.phyQueRxDesc); ++ RegWr16(REG_RxDBL, sizeof(pP->s.pQueRxDesc[0]) * LEN_QueRxDesc); ++ RegWr16(REG_RxDCL, sizeof(pP->s.pQueRxDesc[0]) * LEN_QueRxDesc); ++ ++ pBuf = pP->s.pRxBuf; ++ for (i = 0; i < LEN_QueRxDesc; i++) { ++ pP->s.pRxBufDesc[i].vaddr = pBuf; ++ pP->s.pRxBufDesc[i].pFreeRtn = 0; ++ pBuf += (LEN_RxBuf + 3) & ~0x03; ++ } ++ ++ memset(pP->s.pTxBufDesc, 0x0, ++ sizeof(*pP->s.pTxBufDesc) * LEN_QueTxDesc); ++ pBuf = pP->s.pTxBuf;// = &gTxDataBuff[0][0]; ++ for (i = 0; i < LEN_QueTxDesc; i++) { ++ pP->s.pTxBufDesc[i].vaddr = pBuf + (i*LEN_TxBuf);//&gTxDataBuff[i][0]; ++ pP->s.pTxBufDesc[i].pFreeRtn = 0; ++ } ++ ++ RegWr32(REG_BMCtl, BMCtl_TxEn | BMCtl_RxEn | RegRd32(REG_BMCtl)); ++ err = waitOnReg32(pD, REG_BMSts, BMSts_TxAct | BMSts_TxAct, ++ BMSts_TxAct | BMSts_TxAct, 1); ++ if(err) ++ _PRTK_HWFAIL(("devQue_start(): BM does not start\n")); + +- if (processed) { +- wrw(ep, REG_RXDENQ, processed); +- wrw(ep, REG_RXSTSENQ, processed); +- } ++ RegWr32(REG_RxSEQ, LEN_QueRxSts); ++ RegWr32(REG_RxDEQ, LEN_QueRxDesc); + +- return processed; ++ return 0; + } + +-static int ep93xx_have_more_rx(struct ep93xx_priv *ep) +-{ +- struct ep93xx_rstat *rstat = ep->descs->rstat + ep->rx_pointer; +- return !!((rstat->rstat0 & RSTAT0_RFP) && (rstat->rstat1 & RSTAT1_RFP)); +-} ++/***************************************************************************** ++* devQue_init() ++ init device descriptor queues at system level ++ device access is not recommended at this point ++* ++*****************************************************************************/ ++static int ++devQue_init(struct net_device *pD) ++{ ++ struct ep93xxEth_info *pP = pD->priv; ++ void *pBuf; ++ int size; ++ ++ if (sizeof(receiveDescriptor) != 8) { ++ _PRTK_SWERR(("devQue_init(): size of receiveDescriptor is not 8 bytes!!!\n")); ++ return -1; ++ } else if (sizeof(receiveStatus) != 8) { ++ _PRTK_SWERR(("devQue_init(): size of receiveStatus is not 8 bytes!!!\n")); ++ return -1; ++ } else if (sizeof(transmitDescriptor) != 8) { ++ _PRTK_SWERR(("devQue_init(): size of transmitDescriptor is not 8 bytes!!!\n")); ++ return -1; ++ } else if (sizeof(transmitStatus) != 4) { ++ _PRTK_SWERR(("devQue_init(): size of transmitStatus is not 4 bytes!!!\n")); ++ return -1; ++ } ++ ++ size = sizeof(receiveDescriptor) * (LEN_QueRxDesc + 1) + ++ sizeof(receiveStatus) * (LEN_QueRxSts + 1) + ++ sizeof(transmitDescriptor) * (LEN_QueTxDesc + 1) + ++ sizeof(transmitStatus) * (LEN_QueTxSts + 1) + ++ sizeof(unsigned long) * 4; ++ ++ pBuf = MALLOC_DMA(size, &pP->s.phyQueueBase); ++ if(!pBuf) ++ return -1; ++ ++ pP->s.pQueRxDesc = (void *)Align32(pBuf); ++ pBuf = (char *)pBuf + sizeof(receiveDescriptor) * (LEN_QueRxDesc + 1); ++ pP->s.pQueRxSts = (void *)Align32(pBuf); ++ pBuf = (char *)pBuf + sizeof(receiveStatus) * (LEN_QueRxSts + 1); ++ pP->s.pQueTxDesc = (void *)Align32(pBuf); ++ pBuf = (char *)pBuf + sizeof(transmitDescriptor) * (LEN_QueTxDesc + 1); ++ pP->s.pQueTxSts = (void *)Align32(pBuf); ++ pBuf = (char *)pBuf + sizeof(transmitStatus) * (LEN_QueTxSts + 1); ++ ++ pP->s.phyQueRxDesc = Align32(pP->s.phyQueueBase); ++ pP->s.phyQueRxSts = pP->s.phyQueRxDesc + ((U32)pP->s.pQueRxSts - ++ (U32)pP->s.pQueRxDesc); ++ pP->s.phyQueTxDesc = pP->s.phyQueRxDesc + ((U32)pP->s.pQueTxDesc - ++ (U32)pP->s.pQueRxDesc); ++ pP->s.phyQueTxSts = pP->s.phyQueRxDesc + ((U32)pP->s.pQueTxSts - ++ (U32)pP->s.pQueRxDesc); ++ ++ memset(pP->s.pQueRxDesc, 0, sizeof(receiveDescriptor) * LEN_QueRxDesc); ++ memset(pP->s.pQueRxSts, 0, sizeof(receiveStatus) * LEN_QueRxSts); ++ memset(pP->s.pQueTxDesc, 0, ++ sizeof(transmitDescriptor) * LEN_QueTxDesc); ++ memset(pP->s.pQueTxSts, 0, sizeof(transmitStatus) * LEN_QueTxSts); ++ ++ pP->s.pRxBuf = MALLOC_DMA(((LEN_RxBuf + 3) & ~0x03) * LEN_QueRxDesc, ++ &pP->s.phyRxBuf); ++ if (!pP->s.pRxBuf) { ++ pP->s.pRxBuf = 0; ++ _PRTK_SYSFAIL(("devQue_init(): fail to allocate memory for RxBuf\n")); ++ return -1; ++ } ++ ++ pP->s.pTxBuf = MALLOC_DMA(((LEN_TxBuf + 3) & ~0x03) * LEN_QueTxDesc, ++ &pP->s.phyTxBuf); ++ if (!pP->s.pTxBuf) { ++ pP->s.pTxBuf = 0; ++ _PRTK_SYSFAIL(("devQue_init(): fail to allocate memory for TxBuf\n")); ++ return -1; ++ } ++ ++ size = sizeof(bufferDescriptor) * (LEN_QueRxDesc + LEN_QueTxDesc); ++ pBuf = kmalloc(size, GFP_KERNEL); ++ if(!pBuf) { ++ _PRTK_SYSFAIL(("devQue_initAll(): fail to allocate memory for buf desc\n")); ++ return -1; ++ } ++ memset(pBuf, 0x0, size); ++ pP->s.pRxBufDesc = pBuf; ++ pP->s.pTxBufDesc = pBuf + sizeof(bufferDescriptor) * LEN_QueRxDesc; + +-static int ep93xx_poll(struct napi_struct *napi, int budget) +-{ +- struct ep93xx_priv *ep = container_of(napi, struct ep93xx_priv, napi); +- struct net_device *dev = ep->dev; +- int rx = 0; ++ return 0; ++} + +-poll_some_more: +- rx = ep93xx_rx(dev, rx, budget); +- if (rx < budget) { +- int more = 0; ++#ifndef _PRTK_DUMP ++# define _dbg_ep93xxeth_dumpReg(pD) ++#else ++/***************************************************************************** ++* _dbg_ep93xxeth_dumpReg() ++*****************************************************************************/ ++static void ++_dbg_ep93xxeth_dumpReg(struct net_device *pD) ++{ ++ struct ep93xxEth_info *pP = pD->priv; ++ ++ _PRTK_DUMP(("Dumping registers of Ethernet Module Embedded within EP93xx\n")); ++ _PRTK_DUMP((" pD:0x%p, Base Address:0x%x\n", pD, ++ (unsigned int)pD->base_addr)); ++ ++ _PRTK_DUMP((" RxCTL:0x%08x TxCTL:0x%08x TestCTL:0x%08x\n", ++ (unsigned int)RegRd32(REG_RxCTL), ++ (unsigned int)RegRd32(REG_TxCTL), ++ (unsigned int)RegRd32(REG_TestCTL))); ++ _PRTK_DUMP((" SelfCTL:0x%08x IntEn:0x%08x IntStsP:0x%08x\n", ++ (unsigned int)RegRd32(REG_SelfCTL), ++ (unsigned int)RegRd32(REG_IntEn), ++ (unsigned int)RegRd32(REG_IntStsP))); ++ _PRTK_DUMP((" GT:0x%08x FCT:0x%08x FCF:0x%08x\n", ++ (unsigned int)RegRd32(REG_GT), ++ (unsigned int)RegRd32(REG_FCT), ++ (unsigned int)RegRd32(REG_FCF))); ++ _PRTK_DUMP((" AFP:0x%08x\n", (unsigned int)RegRd32(REG_AFP))); ++ _PRTK_DUMP((" TxCollCnt:0x%08x RxMissCnt:0x%08x RxRntCnt:0x%08x\n", ++ (unsigned int)RegRd32(REG_TxCollCnt), ++ (unsigned int)RegRd32(REG_RxMissCnt), ++ (unsigned int)RegRd32(REG_RxRntCnt))); ++ _PRTK_DUMP((" BMCtl:0x%08x BMSts:0x%08x\n", ++ (unsigned int)RegRd32(REG_BMCtl), ++ (unsigned int)RegRd32(REG_BMSts))); ++ _PRTK_DUMP((" RBCA:0x%08x TBCA:0x%08x\n", ++ (unsigned int)RegRd32(REG_RBCA), ++ (unsigned int)RegRd32(REG_TBCA))); ++ _PRTK_DUMP((" RxDBA:0x%08x RxDBL/CL:0x%08x RxDCA:0x%08x\n", ++ (unsigned int)RegRd32(REG_RxDBA), ++ (unsigned int)RegRd32(REG_RxDBL), ++ (unsigned int)RegRd32(REG_RxDCA))); ++ _PRTK_DUMP((" RxSBA:0x%08x RxSBL/CL:0x%08x RxSCA:0x%08x\n", ++ (unsigned int)RegRd32(REG_RxSBA), ++ (unsigned int)RegRd32(REG_RxSBL), ++ (unsigned int)RegRd32(REG_RxSCA))); ++ _PRTK_DUMP((" RxDEQ:0x%08x RxSEQ:0x%08x\n", ++ (unsigned int)RegRd32(REG_RxDEQ), ++ (unsigned int)RegRd32(REG_RxSEQ))); ++ _PRTK_DUMP((" TxDBA:0x%08x TxDBL/CL:0x%08x TxDCA:0x%08x\n", ++ (unsigned int)RegRd32(REG_TxDBA), ++ (unsigned int)RegRd32(REG_TxDBL), ++ (unsigned int)RegRd32(REG_TxDCA))); ++ _PRTK_DUMP((" TxSBA:0x%08x TxSBL/CL:0x%08x TxSCA:0x%08x\n", ++ (unsigned int)RegRd32(REG_TxSBA), ++ (unsigned int)RegRd32(REG_TxSBL), ++ (unsigned int)RegRd32(REG_TxSCA))); ++ _PRTK_DUMP((" TxDEQ:0x%08x\n",(unsigned int)RegRd32(REG_TxDEQ))); ++ _PRTK_DUMP((" RxBTH:0x%08x TxBTH:0x%08x RxSTH:0x%08x\n", ++ (unsigned int)RegRd32(REG_RxBTH), ++ (unsigned int)RegRd32(REG_TxBTH), ++ (unsigned int)RegRd32(REG_RxSTH))); ++ _PRTK_DUMP((" TxSTH:0x%08x RxDTH:0x%08x TxDTH:0x%08x\n", ++ (unsigned int)RegRd32(REG_TxSTH), ++ (unsigned int)RegRd32(REG_RxDTH), ++ (unsigned int)RegRd32(REG_TxDTH))); ++ _PRTK_DUMP((" MaxFL:0x%08x RxHL:0x%08x\n", ++ (unsigned int)RegRd32(REG_MaxFL), ++ (unsigned int)RegRd32(REG_RxHL))); ++ _PRTK_DUMP((" MACCFG0-3:0x%08x 0x%08x 0x%08x 0x%08x\n", ++ (unsigned int)RegRd32(REG_MACCFG0), ++ (unsigned int)RegRd32(REG_MACCFG1), ++ (unsigned int)RegRd32(REG_MACCFG2), ++ (unsigned int)RegRd32(REG_MACCFG3))); ++ ++ /* ++ _PRTK_DUMP((" ---INT Controller Reg---\n")); ++ _PRTK_DUMP((" RawIrqSts :0x%08x 0x%08x\n", _RegRd(U32,0x80800004), ++ _RegRd(U32,0x80800018))); ++ _PRTK_DUMP((" IrqMask :0x%08x 0x%08x\n", _RegRd(U32,0x80800008), ++ _RegRd(U32,0x8080001c))); ++ _PRTK_DUMP((" MaskIrqSts:0x%08x 0x%08x\n", _RegRd(U32,0x80800000), ++ _RegRd(U32,0x80800014))); ++ */ ++ ++ ++ _PRTK_DUMP(("Dumping private data:\n")); ++ _PRTK_DUMP((" d.txStopped:%d d.idxQueTxSts:%d d.idxQueTxDescHead:%d d.idxQueTxDescTail:%d\n", ++ pP->d.txStopped, pP->d.idxQueTxSts, pP->d.idxQueTxDescHead, ++ pP->d.idxQueTxDescTail)); ++ _PRTK_DUMP((" d.idxQueRxDesc:%d d.idxQueRxSts:%d\n", ++ pP->d.idxQueRxDesc, pP->d.idxQueRxSts)); ++} ++#endif ++ ++#define CRC_PRIME 0xFFFFFFFF ++#define CRC_POLYNOMIAL 0x04C11DB6 ++/***************************************************************************** ++* calculate_hash_index() ++*****************************************************************************/ ++static unsigned char ++calculate_hash_index(char *pMulticastAddr) ++{ ++ unsigned long CRC; ++ unsigned char HashIndex; ++ unsigned char AddrByte; ++ unsigned char *pC; ++ unsigned long HighBit; ++ int Byte; ++ int Bit; ++ ++ CRC = CRC_PRIME; ++ pC = pMulticastAddr; ++ ++ for (Byte = 0; Byte < 6; Byte++) { ++ AddrByte = *pC; ++ pC++; ++ ++ for (Bit = 8; Bit > 0; Bit--) ++ { ++ HighBit = CRC >> 31; ++ CRC <<= 1; ++ ++ if (HighBit ^ (AddrByte & 1)) ++ { ++ CRC ^= CRC_POLYNOMIAL; ++ CRC |= 1; ++ } + +- spin_lock_irq(&ep->rx_lock); +- __netif_rx_complete(dev, napi); +- wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX); +- if (ep93xx_have_more_rx(ep)) { +- wrl(ep, REG_INTEN, REG_INTEN_TX); +- wrl(ep, REG_INTSTSP, REG_INTSTS_RX); +- more = 1; ++ AddrByte >>= 1; + } +- spin_unlock_irq(&ep->rx_lock); ++ } + +- if (more && netif_rx_reschedule(dev, napi)) +- goto poll_some_more; ++ for (Bit = 0, HashIndex = 0; Bit < 6; Bit++) ++ { ++ HashIndex <<= 1; ++ HashIndex |= (unsigned char)(CRC & 1); ++ CRC >>= 1; + } + +- return rx; ++ return HashIndex; + } + +-static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev) ++/***************************************************************************** ++* eth_setMulticastTbl() ++*****************************************************************************/ ++static void ++eth_setMulticastTbl(struct net_device *pD, U8 *pBuf) + { +- struct ep93xx_priv *ep = netdev_priv(dev); +- int entry; +- +- if (unlikely(skb->len > MAX_PKT_SIZE)) { +- ep->stats.tx_dropped++; +- dev_kfree_skb(skb); +- return NETDEV_TX_OK; +- } +- +- entry = ep->tx_pointer; +- ep->tx_pointer = (ep->tx_pointer + 1) & (TX_QUEUE_ENTRIES - 1); +- +- ep->descs->tdesc[entry].tdesc1 = +- TDESC1_EOF | (entry << 16) | (skb->len & 0xfff); +- skb_copy_and_csum_dev(skb, ep->tx_buf[entry]); +- dma_sync_single(NULL, ep->descs->tdesc[entry].buf_addr, +- skb->len, DMA_TO_DEVICE); +- dev_kfree_skb(skb); ++ int i; ++ unsigned char position; ++ struct dev_mc_list *cur_addr; + +- dev->trans_start = jiffies; ++ memset(pBuf, 0x00, 8); + +- spin_lock_irq(&ep->tx_pending_lock); +- ep->tx_pending++; +- if (ep->tx_pending == TX_QUEUE_ENTRIES) +- netif_stop_queue(dev); +- spin_unlock_irq(&ep->tx_pending_lock); ++ cur_addr = pD->mc_list; ++ for (i = 0; i < pD->mc_count; i++, cur_addr = cur_addr->next) { ++ if (!cur_addr) ++ break; ++ if (!(*cur_addr->dmi_addr & 1)) ++ continue; ++ position = calculate_hash_index(cur_addr->dmi_addr); ++ pBuf[position >> 3] |= 1 << (position & 0x07); ++ } ++} + +- wrl(ep, REG_TXDENQ, 1); ++/***************************************************************************** ++* eth_indAddrWr() ++*****************************************************************************/ ++static int ++eth_indAddrWr(struct net_device *pD, int afp, char *pBuf) ++{ ++ U32 rxctl; ++ int i, len; ++ ++ afp &= 0x07; ++ if (afp == 4 || afp == 5) { ++ _PRTK_SWERR(("eth_indAddrWr(): invalid afp value\n")); ++ return -1; ++ } ++ len = (afp == AFP_AFP_HASH) ? 8 : 6; ++ ++ rxctl = RegRd32(REG_RxCTL); ++ RegWr32(REG_RxCTL, ~RxCTL_SRxON & rxctl); ++ RegWr32(REG_AFP, afp); ++ for (i = 0; i < len; i++) ++ RegWr8(REG_IndAD + i, pBuf[i]); ++ RegWr32(REG_RxCTL, rxctl); + +- return NETDEV_TX_OK; ++ return 0; + } + +-static void ep93xx_tx_complete(struct net_device *dev) +-{ +- struct ep93xx_priv *ep = netdev_priv(dev); +- int wake; ++/***************************************************************************** ++* eth_indAddrRd() ++*****************************************************************************/ ++#if 0 ++static int ++eth_indAddrRd(struct net_device *pD, int afp, char *pBuf) ++{ ++ int i, len; ++ ++ afp &= 0x07; ++ if (afp == 4 || afp == 5) { ++ _PRTK_SWERR(("eth_indAddrRd(): invalid afp value\n")); ++ return -1; ++ } ++ ++ RegWr32(REG_AFP, afp); ++ len = (afp == AFP_AFP_HASH) ? 8 : 6; ++ for (i = 0; i < len; i++) ++ pBuf[i] = RegRd8(REG_IndAD + i); + +- wake = 0; ++ return 0; ++} ++#endif + +- spin_lock(&ep->tx_pending_lock); +- while (1) { +- int entry; +- struct ep93xx_tstat *tstat; +- u32 tstat0; ++/***************************************************************************** ++* eth_rxCtl() ++*****************************************************************************/ ++static int ++eth_rxCtl(struct net_device *pD, int sw) ++{ ++ /* ++ * Workaround for MAC lost 60-byte-long frames: must enable ++ * Runt_CRC_Accept bit ++ */ ++ RegWr32(REG_RxCTL, ++ sw ? RegRd32(REG_RxCTL) | RxCTL_SRxON | RxCTL_RCRCA : ++ RegRd32(REG_RxCTL) & ~RxCTL_SRxON); + +- entry = ep->tx_clean_pointer; +- tstat = ep->descs->tstat + entry; ++ return 0; ++} + +- tstat0 = tstat->tstat0; +- if (!(tstat0 & TSTAT0_TXFP)) +- break; ++/***************************************************************************** ++* eth_chkTxLvl() ++*****************************************************************************/ ++static void ++eth_chkTxLvl(struct net_device *pD) ++{ ++ struct ep93xxEth_info *pP = pD->priv; ++ int idxQTxDescHd; ++ int filled; ++ ++ idxQTxDescHd = pP->d.idxQueTxDescHead; ++ ++ filled = idxQTxDescHd - pP->d.idxQueTxDescTail; ++ if (filled < 0) ++ filled += LEN_QueTxDesc; ++ ++ if (pP->d.txStopped && filled <= (LVL_TxResume + 1)) { ++ pP->d.txStopped = 0; ++ pD->trans_start = jiffies; ++ netif_wake_queue(pD); ++ } ++} + +- tstat->tstat0 = 0; ++/***************************************************************************** ++* eth_cleanUpTx() ++*****************************************************************************/ ++static int ++eth_cleanUpTx(struct net_device *pD) ++{ ++ struct ep93xxEth_info *pP = pD->priv; ++ transmitStatus *pQTxSts; ++ int idxSts, bi; ++ ++ while (pP->s.pQueTxSts[pP->d.idxQueTxSts].f.txfp) { ++ idxSts = pP->d.idxQueTxSts; ++ ++ pP->d.idxQueTxSts = IdxNext(pP->d.idxQueTxSts,LEN_QueTxSts); ++ pQTxSts = &pP->s.pQueTxSts[idxSts]; ++ if (!pQTxSts->f.txfp) { ++ _PRTK_HWFAIL(("eth_cleanUpTx(): QueTxSts[%d]:x%08x is empty\n", ++ idxSts, (int)pQTxSts->w.e0)); ++ return -1; ++ } + +- if (tstat0 & TSTAT0_FA) +- printk(KERN_CRIT "ep93xx_tx_complete: frame aborted " +- " %.8x\n", tstat0); +- if ((tstat0 & TSTAT0_BUFFER_INDEX) != entry) +- printk(KERN_CRIT "ep93xx_tx_complete: entry mismatch " +- " %.8x\n", tstat0); ++ pQTxSts->f.txfp = 0; + +- if (tstat0 & TSTAT0_TXWE) { +- int length = ep->descs->tdesc[entry].tdesc1 & 0xfff; ++ bi = pQTxSts->f.bi; ++#if 0 ++ if (pP->d.idxQueTxDescTail != bi) { ++ _PRTK_HWFAIL(("eth_cleanUpTx(): unmatching QTxSts[%d].BI:%d idxQTxDTail:%d\n", ++ idxSts,bi, pP->d.idxQueTxDescTail)); ++ } ++#endif ++ ++ if (pP->s.pTxBufDesc[bi].pFreeRtn) { ++ (*pP->s.pTxBufDesc[bi].pFreeRtn)(pP->s.pTxBufDesc[bi].vaddr); ++ pP->s.pTxBufDesc[bi].pFreeRtn = 0; ++ } + +- ep->stats.tx_packets++; +- ep->stats.tx_bytes += length; ++ if (pQTxSts->f.txwe) { ++ pP->d.stats.tx_packets++; + } else { +- ep->stats.tx_errors++; ++ pP->d.stats.tx_errors++; ++ if (pQTxSts->f.lcrs) ++ pP->d.stats.tx_carrier_errors++; ++ if(pQTxSts->f.txu) ++ pP->d.stats.tx_fifo_errors++; ++ if(pQTxSts->f.ecoll) ++ pP->d.stats.collisions++; + } + +- if (tstat0 & TSTAT0_OW) +- ep->stats.tx_window_errors++; +- if (tstat0 & TSTAT0_TXU) +- ep->stats.tx_fifo_errors++; +- ep->stats.collisions += (tstat0 >> 16) & 0x1f; +- +- ep->tx_clean_pointer = (entry + 1) & (TX_QUEUE_ENTRIES - 1); +- if (ep->tx_pending == TX_QUEUE_ENTRIES) +- wake = 1; +- ep->tx_pending--; ++ pP->d.idxQueTxDescTail = IdxNext(pP->d.idxQueTxDescTail, ++ LEN_QueTxDesc); + } +- spin_unlock(&ep->tx_pending_lock); + +- if (wake) +- netif_wake_queue(dev); ++ return 0; + } + +-static irqreturn_t ep93xx_irq(int irq, void *dev_id) ++/***************************************************************************** ++* eth_restartTx() ++*****************************************************************************/ ++static int ++eth_restartTx(struct net_device *pD) + { +- struct net_device *dev = dev_id; +- struct ep93xx_priv *ep = netdev_priv(dev); +- u32 status; ++ struct ep93xxEth_info *pP = pD->priv; ++ int i; + +- status = rdl(ep, REG_INTSTSC); +- if (status == 0) +- return IRQ_NONE; ++ RegWr32(REG_GIntMsk, RegRd32(REG_GIntMsk) & ~GIntMsk_IntEn); + +- if (status & REG_INTSTS_RX) { +- spin_lock(&ep->rx_lock); +- if (likely(netif_rx_schedule_prep(dev, &ep->napi))) { +- wrl(ep, REG_INTEN, REG_INTEN_TX); +- __netif_rx_schedule(dev, &ep->napi); +- } +- spin_unlock(&ep->rx_lock); ++ RegWr32(REG_TxCTL, RegRd32(REG_TxCTL) & ~TxCTL_STxON); ++ RegWr32(REG_BMCtl, RegRd32(REG_BMCtl) | BMCtl_TxDis); ++ ++ RegWr32(REG_BMCtl, BMCtl_TxChR | RegRd32(REG_BMCtl)); ++ ++ for (i = 0; i < LEN_QueTxDesc; i++) { ++ if (pP->s.pTxBufDesc[i].pFreeRtn) { ++ pP->s.pTxBufDesc[i].pFreeRtn(pP->s.pTxBufDesc[i].vaddr); ++ pP->s.pTxBufDesc[i].pFreeRtn = 0; ++ } ++ pP->d.stats.tx_dropped++; + } + +- if (status & REG_INTSTS_TX) +- ep93xx_tx_complete(dev); ++ memset(pP->s.pQueTxSts, 0, sizeof(pP->s.pQueTxSts[0]) * LEN_QueTxSts); + +- return IRQ_HANDLED; +-} ++ pP->d.txStopped = 0; ++ pP->d.idxQueTxSts = pP->d.idxQueTxDescHead = pP->d.idxQueTxDescTail = ++ 0; + +-static void ep93xx_free_buffers(struct ep93xx_priv *ep) +-{ +- int i; ++ waitOnReg32(pD, REG_BMSts, BMCtl_TxChR, ~BMCtl_TxChR, 1); ++ RegWr32(REG_TxSBA, pP->s.phyQueTxSts); ++ RegWr32(REG_TxSCA, pP->s.phyQueTxSts); ++ RegWr16(REG_TxSBL, sizeof(pP->s.pQueTxSts[0]) * LEN_QueTxSts); ++ RegWr16(REG_TxSCL, sizeof(pP->s.pQueTxSts[0]) * LEN_QueTxSts); ++ RegWr32(REG_TxDBA, pP->s.phyQueTxDesc); ++ RegWr32(REG_TxDCA, pP->s.phyQueTxDesc); ++ RegWr16(REG_TxDBL, sizeof(pP->s.pQueTxDesc[0]) * LEN_QueTxDesc); ++ RegWr16(REG_TxDCL, sizeof(pP->s.pQueTxDesc[0]) * LEN_QueTxDesc); + +- for (i = 0; i < RX_QUEUE_ENTRIES; i += 2) { +- dma_addr_t d; ++ RegWr32(REG_TxCTL, RegRd32(REG_TxCTL) | TxCTL_STxON); ++ RegWr32(REG_BMCtl, RegRd32(REG_BMCtl) | BMCtl_TxEn); + +- d = ep->descs->rdesc[i].buf_addr; +- if (d) +- dma_unmap_single(NULL, d, PAGE_SIZE, DMA_FROM_DEVICE); ++ RegWr32(REG_GIntMsk, RegRd32(REG_GIntMsk) | GIntMsk_IntEn); + +- if (ep->rx_buf[i] != NULL) +- free_page((unsigned long)ep->rx_buf[i]); +- } ++ return 0; ++} + +- for (i = 0; i < TX_QUEUE_ENTRIES; i += 2) { +- dma_addr_t d; ++/***************************************************************************** ++* eth_reset() ++*****************************************************************************/ ++static int ++eth_reset(struct net_device *pD) ++{ ++ int err; + +- d = ep->descs->tdesc[i].buf_addr; +- if (d) +- dma_unmap_single(NULL, d, PAGE_SIZE, DMA_TO_DEVICE); ++ RegWr8(REG_SelfCTL, SelfCTL_RESET); ++ err = waitOnReg32(pD, REG_SelfCTL, SelfCTL_RESET, ~SelfCTL_RESET, 1); ++ if (err) ++ _PRTK_WARN(("eth_reset(): Soft Reset does not self-clear\n")); + +- if (ep->tx_buf[i] != NULL) +- free_page((unsigned long)ep->tx_buf[i]); +- } ++ //phy_reset(pD); + +- dma_free_coherent(NULL, sizeof(struct ep93xx_descs), ep->descs, +- ep->descs_dma_addr); ++ return 0; + } + +-/* +- * The hardware enforces a sub-2K maximum packet size, so we put +- * two buffers on every hardware page. +- */ +-static int ep93xx_alloc_buffers(struct ep93xx_priv *ep) ++/***************************************************************************** ++ . Function: eth_shutDown() ++ . Purpose: closes down the Ethernet module ++ . Make sure to: ++ . 1. disable all interrupt mask ++ . 2. disable Rx ++ . 3. disable Tx ++ . ++ . TODO: ++ . (1) maybe utilize power down mode. ++ . Why not yet? Because while the chip will go into power down mode, ++ . the manual says that it will wake up in response to any I/O requests ++ . in the register space. Empirical results do not show this working. ++* ++*****************************************************************************/ ++static int ++eth_shutDown(struct net_device *pD) + { +- int i; +- +- ep->descs = dma_alloc_coherent(NULL, sizeof(struct ep93xx_descs), +- &ep->descs_dma_addr, GFP_KERNEL | GFP_DMA); +- if (ep->descs == NULL) +- return 1; ++ eth_reset(pD); + +- for (i = 0; i < RX_QUEUE_ENTRIES; i += 2) { +- void *page; +- dma_addr_t d; ++ return 0; ++} + +- page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); +- if (page == NULL) +- goto err; ++/***************************************************************************** ++* eth_enable() + +- d = dma_map_single(NULL, page, PAGE_SIZE, DMA_FROM_DEVICE); +- if (dma_mapping_error(d)) { +- free_page((unsigned long)page); +- goto err; +- } ++ Purpose: ++ Turn on device interrupt for interrupt driven operation. ++ Also turn on Rx but no Tx. ++* ++*****************************************************************************/ ++static int ++eth_enable(struct net_device *pD) ++{ ++ RegWr32(REG_IntEn, Default_IntSrc); ++ RegWr32(REG_GIntMsk, GIntMsk_IntEn); ++ eth_rxCtl(pD, 1); + +- ep->rx_buf[i] = page; +- ep->descs->rdesc[i].buf_addr = d; +- ep->descs->rdesc[i].rdesc1 = (i << 16) | PKT_BUF_SIZE; ++ return 0; ++} + +- ep->rx_buf[i + 1] = page + PKT_BUF_SIZE; +- ep->descs->rdesc[i + 1].buf_addr = d + PKT_BUF_SIZE; +- ep->descs->rdesc[i + 1].rdesc1 = ((i + 1) << 16) | PKT_BUF_SIZE; +- } ++/***************************************************************************** ++* eth_init() + +- for (i = 0; i < TX_QUEUE_ENTRIES; i += 2) { +- void *page; +- dma_addr_t d; ++ Purpose: ++ Reset and initialize the device. ++ Device should be initialized enough to function in polling mode. ++ Tx and Rx must be disabled and no INT generation. ++* ++*****************************************************************************/ ++static int ++eth_init(struct net_device *pD) ++{ ++ int status; ++ ++ eth_reset(pD); ++ ++ gPhyAutoNegoDone = 0; ++ status = phy_init(pD); ++ if (status != 0) ++ printk(KERN_WARNING "%s: No network cable detected!\n", pD->name); ++ ++ RegWr32(REG_SelfCTL, 0x0f00); ++ RegWr32(REG_GIntMsk, 0x00); ++ RegWr32(REG_RxCTL, RxCTL_BA | RxCTL_IA0); ++ RegWr32(REG_TxCTL, 0x00); ++ RegWr32(REG_GT, 0x00); ++ RegWr32(REG_BMCtl, 0x00); ++ RegWr32(REG_RxBTH, (0x80 << 16) | (0x40 << 0)); ++ RegWr32(REG_TxBTH, (0x80 << 16) | (0x40 << 0)); ++ RegWr32(REG_RxSTH, (4 << 16) | (2 << 0)); ++ RegWr32(REG_TxSTH, (4 << 16) | (2 << 0)); ++ RegWr32(REG_RxDTH, (4 << 16) | (2 << 0)); ++ RegWr32(REG_TxDTH, (4 << 16) | (2 << 0)); ++ RegWr32(REG_MaxFL, ((1518 + 1) << 16) | (944 << 0)); ++ ++ RegRd32(REG_TxCollCnt); ++ RegRd32(REG_RxMissCnt); ++ RegRd32(REG_RxRntCnt); + +- page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); +- if (page == NULL) +- goto err; ++ RegRd32(REG_IntStsC); + +- d = dma_map_single(NULL, page, PAGE_SIZE, DMA_TO_DEVICE); +- if (dma_mapping_error(d)) { +- free_page((unsigned long)page); +- goto err; +- } ++ RegWr32(REG_TxCTL, TxCTL_STxON | RegRd32(REG_TxCTL)); + +- ep->tx_buf[i] = page; +- ep->descs->tdesc[i].buf_addr = d; ++ eth_indAddrWr(pD, AFP_AFP_IA0, &pD->dev_addr[0]); + +- ep->tx_buf[i + 1] = page + PKT_BUF_SIZE; +- ep->descs->tdesc[i + 1].buf_addr = d + PKT_BUF_SIZE; +- } ++ devQue_start(pD); + + return 0; +- +-err: +- ep93xx_free_buffers(ep); +- return 1; + } + +-static int ep93xx_start_hw(struct net_device *dev) +-{ +- struct ep93xx_priv *ep = netdev_priv(dev); +- unsigned long addr; +- int i; +- +- wrl(ep, REG_SELFCTL, REG_SELFCTL_RESET); +- for (i = 0; i < 10; i++) { +- if ((rdl(ep, REG_SELFCTL) & REG_SELFCTL_RESET) == 0) +- break; +- msleep(1); +- } +- +- if (i == 10) { +- printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to reset\n"); +- return 1; +- } +- +- wrl(ep, REG_SELFCTL, ((ep->mdc_divisor - 1) << 9)); +- +- /* Does the PHY support preamble suppress? */ +- if ((ep93xx_mdio_read(dev, ep->mii.phy_id, MII_BMSR) & 0x0040) != 0) +- wrl(ep, REG_SELFCTL, ((ep->mdc_divisor - 1) << 9) | (1 << 8)); +- +- /* Receive descriptor ring. */ +- addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, rdesc); +- wrl(ep, REG_RXDQBADD, addr); +- wrl(ep, REG_RXDCURADD, addr); +- wrw(ep, REG_RXDQBLEN, RX_QUEUE_ENTRIES * sizeof(struct ep93xx_rdesc)); +- +- /* Receive status ring. */ +- addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, rstat); +- wrl(ep, REG_RXSTSQBADD, addr); +- wrl(ep, REG_RXSTSQCURADD, addr); +- wrw(ep, REG_RXSTSQBLEN, RX_QUEUE_ENTRIES * sizeof(struct ep93xx_rstat)); +- +- /* Transmit descriptor ring. */ +- addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, tdesc); +- wrl(ep, REG_TXDQBADD, addr); +- wrl(ep, REG_TXDQCURADD, addr); +- wrw(ep, REG_TXDQBLEN, TX_QUEUE_ENTRIES * sizeof(struct ep93xx_tdesc)); +- +- /* Transmit status ring. */ +- addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, tstat); +- wrl(ep, REG_TXSTSQBADD, addr); +- wrl(ep, REG_TXSTSQCURADD, addr); +- wrw(ep, REG_TXSTSQBLEN, TX_QUEUE_ENTRIES * sizeof(struct ep93xx_tstat)); +- +- wrl(ep, REG_BMCTL, REG_BMCTL_ENABLE_TX | REG_BMCTL_ENABLE_RX); +- wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX); +- wrl(ep, REG_GIINTMSK, 0); ++/***************************************************************************** ++* eth_isrRx() ++* ++* Interrupt Service Routines ++* ++*****************************************************************************/ ++static int ++eth_isrRx(struct net_device *pD) ++{ ++ ep93xxEth_info *pP = pD->priv; ++ receiveStatus *pQRxSts; ++ int idxQRxStsHead; ++ int idxSts; ++ int cntStsProcessed, cntDescProcessed; ++ char *pDest; ++ struct sk_buff *pSkb; ++ int len; ++ UINT dt; ++ ++ dt = RegRd32(REG_RxSCA); ++ idxQRxStsHead = (dt - pP->s.phyQueRxSts) / sizeof(pP->s.pQueRxSts[0]); ++ if (!(idxQRxStsHead >= 0 && idxQRxStsHead < LEN_QueRxSts)) { ++ _PRTK_HWFAIL(("eth_isrRx(): invalid REG_RxSCA:0x%x idx:%d (phyQueRxSts:0x%x Len:%x)\n", ++ dt,idxQRxStsHead, (int)pP->s.phyQueRxSts, ++ LEN_QueRxSts)); ++ return -1; ++ } ++ ++ cntStsProcessed = cntDescProcessed = 0; ++ while (idxQRxStsHead != pP->d.idxQueRxSts) { ++ idxSts = pP->d.idxQueRxSts; ++ pP->d.idxQueRxSts = IdxNext(pP->d.idxQueRxSts, LEN_QueRxSts); ++ pQRxSts = &pP->s.pQueRxSts[idxSts]; ++ if (!pQRxSts->f.rfp) { ++ _PRTK_HWFAIL(("eth_isrRx(): QueRxSts[%d] is empty; Hd:%d\n", ++ idxSts,idxQRxStsHead)); ++ return -1; ++ } ++ pQRxSts->f.rfp = 0; + +- for (i = 0; i < 10; i++) { +- if ((rdl(ep, REG_BMSTS) & REG_BMSTS_RX_ACTIVE) != 0) +- break; +- msleep(1); +- } ++ if(pQRxSts->f.eob) { ++ if(pQRxSts->f.bi == pP->d.idxQueRxDesc) { ++ pP->d.idxQueRxDesc = ++ IdxNext(pP->d.idxQueRxDesc, ++ LEN_QueRxDesc); ++ cntDescProcessed++; ++ if (pQRxSts->f.eof && pQRxSts->f.rwe) { ++ len = pQRxSts->f.fl; ++ pSkb = dev_alloc_skb(len + 5); ++ if (pSkb != NULL) { ++ skb_reserve(pSkb, 2); ++ pSkb->dev = pD; ++ pDest = skb_put(pSkb, len); ++ ++ memcpy(pDest, ++ pP->s.pRxBufDesc[pQRxSts->f.bi].vaddr, ++ len); ++ pSkb->protocol = ++ eth_type_trans(pSkb, ++ pD); ++ netif_rx(pSkb); ++ pP->d.stats.rx_packets++; ++ if(pQRxSts->f.am == 3) ++ pP->d.stats.multicast++; ++ } else ++ _PRTK_SYSFAIL(("eth_isrRx(): Low Memory, Rx dropped\n")); ++ pP->d.stats.rx_dropped++; ++ } else { ++ pP->d.stats.rx_errors++; ++ if (pQRxSts->f.oe) ++ pP->d.stats.rx_fifo_errors++; ++ if (pQRxSts->f.fe) ++ pP->d.stats.rx_frame_errors++; ++ if (pQRxSts->f.runt || ++ pQRxSts->f.edata) ++ pP->d.stats.rx_length_errors++; ++ if (pQRxSts->f.crce) ++ pP->d.stats.rx_crc_errors++; ++ } ++ } else ++ _PRTK_HWFAIL(("eth_isrRx(): unmatching QueRxSts[%d].BI:0x%x; idxQueRxDesc:0x%x\n", ++ idxSts, pQRxSts->f.bi, ++ pP->d.idxQueRxDesc)); ++ } + +- if (i == 10) { +- printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to start\n"); +- return 1; ++ cntStsProcessed++; + } + +- wrl(ep, REG_RXDENQ, RX_QUEUE_ENTRIES); +- wrl(ep, REG_RXSTSENQ, RX_QUEUE_ENTRIES); +- +- wrb(ep, REG_INDAD0, dev->dev_addr[0]); +- wrb(ep, REG_INDAD1, dev->dev_addr[1]); +- wrb(ep, REG_INDAD2, dev->dev_addr[2]); +- wrb(ep, REG_INDAD3, dev->dev_addr[3]); +- wrb(ep, REG_INDAD4, dev->dev_addr[4]); +- wrb(ep, REG_INDAD5, dev->dev_addr[5]); +- wrl(ep, REG_AFP, 0); +- +- wrl(ep, REG_MAXFRMLEN, (MAX_PKT_SIZE << 16) | MAX_PKT_SIZE); +- +- wrl(ep, REG_RXCTL, REG_RXCTL_DEFAULT); +- wrl(ep, REG_TXCTL, REG_TXCTL_ENABLE); ++ RegWr32(REG_RxSEQ, cntStsProcessed); ++ RegWr32(REG_RxDEQ, cntDescProcessed); + + return 0; + } + +-static void ep93xx_stop_hw(struct net_device *dev) ++/***************************************************************************** ++* eth_isrTx() ++*****************************************************************************/ ++static int ++eth_isrTx(struct net_device *pD) + { +- struct ep93xx_priv *ep = netdev_priv(dev); +- int i; ++ eth_cleanUpTx(pD); ++ eth_chkTxLvl(pD); ++ return 0; ++} + +- wrl(ep, REG_SELFCTL, REG_SELFCTL_RESET); +- for (i = 0; i < 10; i++) { +- if ((rdl(ep, REG_SELFCTL) & REG_SELFCTL_RESET) == 0) +- break; +- msleep(1); +- } ++/***************************************************************************** ++* ep93xxEth_isr() ++*****************************************************************************/ ++static irqreturn_t ++ep93xxEth_isr(int irq,void *pDev) ++{ ++ struct net_device *pD = pDev; ++ int lpCnt; ++ U32 intS; ++ ++ lpCnt = 0; ++ do { ++ intS = RegRd32(REG_IntStsC); + +- if (i == 10) +- printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to reset\n"); ++ if (!intS) ++ break; ++ if (intS & IntSts_RxSQ) ++ eth_isrRx(pD); ++ if (intS & IntSts_TxSQ) ++ eth_isrTx(pD); ++ } while (lpCnt++ < 64); ++ ++ if (lpCnt) ++ return IRQ_HANDLED; ++ else ++ return IRQ_NONE; + } + +-static int ep93xx_open(struct net_device *dev) +-{ +- struct ep93xx_priv *ep = netdev_priv(dev); +- int err; ++/*========================================================= ++ * Exposed Driver Routines to the Outside World ++ *=======================================================*/ ++ ++/***************************************************************************** ++* ep93xxEth_getStats() ++*****************************************************************************/ ++static struct net_device_stats * ++ep93xxEth_getStats(struct net_device *pD) ++{ ++ return &((struct ep93xxEth_info *)pD->priv)->d.stats; ++} ++ ++/***************************************************************************** ++* ep93xxEth_setMulticastList() ++*****************************************************************************/ ++static void ++ep93xxEth_setMulticastList(struct net_device *pD) ++{ ++ U8 tblMulti[8 + 1]; ++ ++ if (pD->flags & IFF_PROMISC) ++ RegWr32(REG_RxCTL, RxCTL_PA | RegRd32(REG_RxCTL)); ++ else if(pD->flags & IFF_ALLMULTI) { ++ RegWr32(REG_RxCTL, RxCTL_MA | ++ (~RxCTL_PA & RegRd32(REG_RxCTL))); ++ eth_indAddrWr(pD, AFP_AFP_HASH, ++ "\xff\xff\xff\xff\xff\xff\xff\xff"); ++ } else if(pD->mc_count) { ++ RegWr32(REG_RxCTL, RxCTL_MA | ++ (~RxCTL_PA & RegRd32(REG_RxCTL))); ++ eth_setMulticastTbl(pD, &tblMulti[0]); ++ eth_indAddrWr(pD, AFP_AFP_HASH, &tblMulti[0]); ++ } else ++ RegWr32(REG_RxCTL, ++ ~(RxCTL_PA | RxCTL_MA) & RegRd32(REG_RxCTL)); ++} ++ ++/***************************************************************************** ++* ep93xxEth_txTimeout() ++*****************************************************************************/ ++static void ++ep93xxEth_txTimeout(struct net_device *pD) ++{ ++ int status; ++ ++ _PRTK_WARN(("ep93xxEth_txTimeout(): transmit timed out\n")); ++ ++ if (gPhyAutoNegoDone == 0) { ++ status = phy_init(pD); ++ if (status != 0) ++ { ++ printk(KERN_WARNING "%s: No network cable detected!\n", ++ pD->name); ++ return; ++ } ++ } + +- if (ep93xx_alloc_buffers(ep)) +- return -ENOMEM; ++ eth_restartTx(pD); + +- if (is_zero_ether_addr(dev->dev_addr)) { +- random_ether_addr(dev->dev_addr); +- printk(KERN_INFO "%s: generated random MAC address " +- "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x.\n", dev->name, +- dev->dev_addr[0], dev->dev_addr[1], +- dev->dev_addr[2], dev->dev_addr[3], +- dev->dev_addr[4], dev->dev_addr[5]); +- } +- +- napi_enable(&ep->napi); +- +- if (ep93xx_start_hw(dev)) { +- napi_disable(&ep->napi); +- ep93xx_free_buffers(ep); +- return -EIO; +- } +- +- spin_lock_init(&ep->rx_lock); +- ep->rx_pointer = 0; +- ep->tx_clean_pointer = 0; +- ep->tx_pointer = 0; +- spin_lock_init(&ep->tx_pending_lock); +- ep->tx_pending = 0; ++ pD->trans_start = jiffies; ++ netif_wake_queue(pD); ++} + +- err = request_irq(ep->irq, ep93xx_irq, IRQF_SHARED, dev->name, dev); +- if (err) { +- napi_disable(&ep->napi); +- ep93xx_stop_hw(dev); +- ep93xx_free_buffers(ep); +- return err; ++/***************************************************************************** ++* ep93xxEth_hardStartXmit() ++*****************************************************************************/ ++static int ++ep93xxEth_hardStartXmit(struct sk_buff *pSkb, struct net_device *pD) ++{ ++ struct ep93xxEth_info *pP = pD->priv; ++ transmitDescriptor *pQTxDesc; ++ int idxQTxDescHd; ++ int filled; ++ int status; ++ ++ if (gPhyAutoNegoDone == 0) { ++ status = phy_init(pD); ++ if (status != 0) ++ { ++ return 1; ++ } + } + +- wrl(ep, REG_GIINTMSK, REG_GIINTMSK_ENABLE); ++ idxQTxDescHd = pP->d.idxQueTxDescHead; ++ pQTxDesc = &pP->s.pQueTxDesc[idxQTxDescHd]; ++ ++ filled = idxQTxDescHd - pP->d.idxQueTxDescTail; ++ if (filled < 0) ++ filled += LEN_QueTxDesc; ++ filled += 1; ++ ++ if(filled >= LVL_TxStop) { ++ netif_stop_queue(pD); ++ pP->d.txStopped = 1; ++ if(filled > LVL_TxStop) { ++ _PRTK_SYSFAIL(("ep93xxEth_hardStartXmit(): a Tx Request while stop\n")); ++ return 1; ++ } ++ } + +- netif_start_queue(dev); ++ if (pSkb->len < 60) { ++ pQTxDesc->f.bl = 60; ++ memset(pP->s.pTxBufDesc[idxQTxDescHd].vaddr, 0, 60); ++ } else ++ pQTxDesc->f.bl = pSkb->len; ++ pQTxDesc->f.ba = pP->s.phyTxBuf+(idxQTxDescHd * LEN_TxBuf);//virt_to_bus(pP->s.pTxBufDesc[idxQTxDescHd].vaddr); ++ pQTxDesc->f.bi = idxQTxDescHd; ++ pQTxDesc->f.af = 0; ++ pQTxDesc->f.eof = 1; ++ ++ memcpy(pP->s.pTxBufDesc[idxQTxDescHd].vaddr, pSkb->data, pSkb->len); ++ pP->s.pTxBufDesc[idxQTxDescHd].pFreeRtn = 0; ++ ++ free_skb(pSkb); ++ ++ pP->d.idxQueTxDescHead = IdxNext(pP->d.idxQueTxDescHead, ++ LEN_QueTxDesc); ++ RegWr32(REG_TxDEQ, 1); + + return 0; + } + +-static int ep93xx_close(struct net_device *dev) ++/***************************************************************************** ++ . ep93xxEth_close() ++ . ++ . this makes the board clean up everything that it can ++ . and not talk to the outside world. Caused by ++ . an 'ifconfig ethX down' ++ * ++*****************************************************************************/ ++static int ++ep93xxEth_close(struct net_device *pD) + { +- struct ep93xx_priv *ep = netdev_priv(dev); ++ netif_stop_queue(pD); ++ eth_shutDown(pD); + +- napi_disable(&ep->napi); +- netif_stop_queue(dev); +- +- wrl(ep, REG_GIINTMSK, 0); +- free_irq(ep->irq, dev); +- ep93xx_stop_hw(dev); +- ep93xx_free_buffers(ep); ++ /*MOD_DEC_USE_COUNT;*/ + + return 0; + } + +-static int ep93xx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ++/******************************************************* ++ * ep93xxEth_open() ++ * ++ * Open and Initialize the board ++ * ++ * Set up everything, reset the card, etc .. ++ * ++ ******************************************************/ ++static int ++ep93xxEth_open(struct net_device *pD) + { +- struct ep93xx_priv *ep = netdev_priv(dev); +- struct mii_ioctl_data *data = if_mii(ifr); ++ int status; ++ struct ep93xxEth_info *pP = pD->priv; + +- return generic_mii_ioctl(&ep->mii, data, cmd, NULL); +-} ++ memset(&pP->d, 0, sizeof(pP->d)); + +-static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg) +-{ +- struct ep93xx_priv *ep = netdev_priv(dev); +- int data; +- int i; ++ /*MOD_INC_USE_COUNT;*/ + +- wrl(ep, REG_MIICMD, REG_MIICMD_READ | (phy_id << 5) | reg); ++ status = eth_init(pD); ++ if (status != 0 ) ++ return -EAGAIN; + +- for (i = 0; i < 10; i++) { +- if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0) +- break; +- msleep(1); +- } ++ eth_enable(pD); + +- if (i == 10) { +- printk(KERN_INFO DRV_MODULE_NAME ": mdio read timed out\n"); +- data = 0xffff; +- } else { +- data = rdl(ep, REG_MIIDATA); +- } ++#if 0 ++ _dbg_phy_dumpReg(pD); ++ _dbg_ep93xxeth_dumpReg(pD); ++ _dbg_ep93xxEth_dumpQueues(pD); ++#endif + +- return data; ++ netif_start_queue(pD); ++ ++ return 0; + } + +-static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int data) +-{ +- struct ep93xx_priv *ep = netdev_priv(dev); ++/***************************************************************************** ++ . ++ . ep93xxEth_probe( struct net_device * dev ) ++ . This is the first routine called to probe device existance ++ . and initialize the driver if the device found. ++ . ++ . Input parameters: ++ . dev->base_addr == 0, try to find all possible locations ++ . dev->base_addr == 1, return failure code ++ . dev->base_addr == 2, always allocate space, and return success ++ . dev->base_addr == <anything else> this is the address to check ++ . ++ . Output: ++ . 0 --> there is a device ++ . anything else, error ++ ++*****************************************************************************/ ++int ep93xxEth_probe(struct net_device *pD) { ++ struct ep93xxEth_info *pP; ++ int err; + int i; + +- wrl(ep, REG_MIIDATA, data); +- wrl(ep, REG_MIICMD, REG_MIICMD_WRITE | (phy_id << 5) | reg); +- +- for (i = 0; i < 10; i++) { +- if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0) +- break; +- msleep(1); ++ if (pD->priv == 0) { ++ pD->priv = kmalloc(sizeof(struct ep93xxEth_info), GFP_KERNEL); ++ if(pD->priv == 0) ++ return -ENOMEM; + } ++ memset(pD->priv, 0x00, sizeof(struct ep93xxEth_info)); + +- if (i == 10) +- printk(KERN_INFO DRV_MODULE_NAME ": mdio write timed out\n"); +-} ++ pP = pD->priv; ++ pP->s.id = numOfInstance; ++ pP->s.miiIdPhy = 1; + +-static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +-{ +- strcpy(info->driver, DRV_MODULE_NAME); +- strcpy(info->version, DRV_MODULE_VERSION); +-} ++ for (i = 0; i < 6; i++) ++ pD->dev_addr[i] = default_mac[i]; + +-static int ep93xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +-{ +- struct ep93xx_priv *ep = netdev_priv(dev); +- return mii_ethtool_gset(&ep->mii, cmd); +-} ++ err = (int)request_irq(pD->irq, &ep93xxEth_isr, 0, cardname, pD); ++ if(err) { ++ kfree(pD->priv); ++ return -EAGAIN; ++ } + +-static int ep93xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +-{ +- struct ep93xx_priv *ep = netdev_priv(dev); +- return mii_ethtool_sset(&ep->mii, cmd); +-} ++ pD->open = &ep93xxEth_open; ++ pD->stop = &ep93xxEth_close; ++ pD->hard_start_xmit = &ep93xxEth_hardStartXmit; ++ pD->tx_timeout = &ep93xxEth_txTimeout; ++ pD->watchdog_timeo = HZ * 5; ++ pD->get_stats = &ep93xxEth_getStats; ++ pD->set_multicast_list = &ep93xxEth_setMulticastList; + +-static int ep93xx_nway_reset(struct net_device *dev) +-{ +- struct ep93xx_priv *ep = netdev_priv(dev); +- return mii_nway_restart(&ep->mii); +-} ++ ether_setup(pD); + +-static u32 ep93xx_get_link(struct net_device *dev) +-{ +- struct ep93xx_priv *ep = netdev_priv(dev); +- return mii_link_ok(&ep->mii); +-} ++ devQue_init(pD); ++ eth_reset(pD); + +-static struct ethtool_ops ep93xx_ethtool_ops = { +- .get_drvinfo = ep93xx_get_drvinfo, +- .get_settings = ep93xx_get_settings, +- .set_settings = ep93xx_set_settings, +- .nway_reset = ep93xx_nway_reset, +- .get_link = ep93xx_get_link, +-}; ++ numOfInstance++; + +-struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data) +-{ +- struct net_device *dev; ++ err = register_netdev(pD); ++ if (err) { ++ free_irq(pD->irq, pD); ++ kfree(pP); ++ return err; ++ } + +- dev = alloc_etherdev(sizeof(struct ep93xx_priv)); +- if (dev == NULL) +- return NULL; ++ return 0; ++} + +- memcpy(dev->dev_addr, data->dev_addr, ETH_ALEN); ++static int ep93xxEth_drv_probe(struct platform_device *pdev) ++{ ++ struct net_device *ndev; ++ struct resource *res; ++ int ret; + +- dev->get_stats = ep93xx_get_stats; +- dev->ethtool_ops = &ep93xx_ethtool_ops; +- dev->hard_start_xmit = ep93xx_xmit; +- dev->open = ep93xx_open; +- dev->stop = ep93xx_close; +- dev->do_ioctl = ep93xx_ioctl; ++ PRINTK("ep93xxEth_drv_probe init\n"); + +- dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res){ ++ printk("platform_get_resource fail\n"); ++ return -ENODEV; ++ } + +- return dev; +-} ++ if (!request_mem_region(res->start, 0x10000, cardname)){ ++ printk("request_mem_region fail\n"); ++ return -EBUSY; ++ } + ++ ndev = alloc_etherdev(sizeof(struct ep93xxEth_info)); ++ if (!ndev) { ++ release_mem_region(res->start, 0x10000); ++ printk("alloc_etherdev fail\n"); ++ return -ENOMEM; ++ } + +-static int ep93xx_eth_remove(struct platform_device *pdev) +-{ +- struct net_device *dev; +- struct ep93xx_priv *ep; + +- dev = platform_get_drvdata(pdev); +- if (dev == NULL) +- return 0; +- platform_set_drvdata(pdev, NULL); ++ SET_NETDEV_DEV(ndev, &pdev->dev); + +- ep = netdev_priv(dev); ++ ndev->base_addr = (unsigned long)ioremap(res->start, 0x10000); ++ if (!ndev->base_addr) { ++ printk("ioremap failed\n"); ++ release_mem_region(res->start, 0x10000); ++ return -ENOMEM; ++ } ++ ndev->irq = platform_get_irq(pdev, 0); + +- /* @@@ Force down. */ +- unregister_netdev(dev); +- ep93xx_free_buffers(ep); + +- if (ep->base_addr != NULL) +- iounmap(ep->base_addr); ++ dev_set_drvdata(&pdev->dev, ndev); + +- if (ep->res != NULL) { +- release_resource(ep->res); +- kfree(ep->res); ++ ret = ep93xxEth_probe(ndev); ++ if (ret != 0) { ++ free_netdev(ndev); ++ release_mem_region(res->start, 0x10000); ++ printk("ep93xxEth_probe fail\n"); ++ return ret; + } + +- free_netdev(dev); +- + return 0; + } + +-static int ep93xx_eth_probe(struct platform_device *pdev) ++static int ep93xxEth_drv_remove(struct platform_device *pdev) + { +- struct ep93xx_eth_data *data; +- struct net_device *dev; +- struct ep93xx_priv *ep; +- int err; ++ struct net_device *ndev = dev_get_drvdata(&pdev->dev); ++ struct resource *res; + +- if (pdev == NULL) +- return -ENODEV; +- data = pdev->dev.platform_data; ++ dev_set_drvdata(&pdev->dev, NULL); + +- dev = ep93xx_dev_alloc(data); +- if (dev == NULL) { +- err = -ENOMEM; +- goto err_out; +- } +- ep = netdev_priv(dev); +- ep->dev = dev; +- netif_napi_add(dev, &ep->napi, ep93xx_poll, 64); +- +- platform_set_drvdata(pdev, dev); +- +- ep->res = request_mem_region(pdev->resource[0].start, +- pdev->resource[0].end - pdev->resource[0].start + 1, +- pdev->dev.bus_id); +- if (ep->res == NULL) { +- dev_err(&pdev->dev, "Could not reserve memory region\n"); +- err = -ENOMEM; +- goto err_out; +- } +- +- ep->base_addr = ioremap(pdev->resource[0].start, +- pdev->resource[0].end - pdev->resource[0].start); +- if (ep->base_addr == NULL) { +- dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n"); +- err = -EIO; +- goto err_out; +- } +- ep->irq = pdev->resource[1].start; +- +- ep->mii.phy_id = data->phy_id; +- ep->mii.phy_id_mask = 0x1f; +- ep->mii.reg_num_mask = 0x1f; +- ep->mii.dev = dev; +- ep->mii.mdio_read = ep93xx_mdio_read; +- ep->mii.mdio_write = ep93xx_mdio_write; +- ep->mdc_divisor = 40; /* Max HCLK 100 MHz, min MDIO clk 2.5 MHz. */ ++ unregister_netdev(ndev); + +- err = register_netdev(dev); +- if (err) { +- dev_err(&pdev->dev, "Failed to register netdev\n"); +- goto err_out; +- } ++ free_irq(ndev->irq, ndev); + +- printk(KERN_INFO "%s: ep93xx on-chip ethernet, IRQ %d, " +- "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x.\n", dev->name, +- ep->irq, data->dev_addr[0], data->dev_addr[1], +- data->dev_addr[2], data->dev_addr[3], +- data->dev_addr[4], data->dev_addr[5]); ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ release_mem_region(res->start, 0x10000); + +- return 0; ++ free_netdev(ndev); + +-err_out: +- ep93xx_eth_remove(pdev); +- return err; ++ return 0; + } + +- + static struct platform_driver ep93xx_eth_driver = { +- .probe = ep93xx_eth_probe, +- .remove = ep93xx_eth_remove, ++ .probe = ep93xxEth_drv_probe, ++ .remove = ep93xxEth_drv_remove, + .driver = { +- .name = "ep93xx-eth", ++ .name = cardname, ++ .owner = THIS_MODULE, + }, + }; + +-static int __init ep93xx_eth_init_module(void) ++static int __init ep93xxEth_init(void) + { +- printk(KERN_INFO DRV_MODULE_NAME " version " DRV_MODULE_VERSION " loading\n"); ++ PRINTK("ep93xxEth_init\n"); + return platform_driver_register(&ep93xx_eth_driver); + } + +-static void __exit ep93xx_eth_cleanup_module(void) ++static void __exit ep93xxEth_cleanup(void) + { + platform_driver_unregister(&ep93xx_eth_driver); + } + +-module_init(ep93xx_eth_init_module); +-module_exit(ep93xx_eth_cleanup_module); ++module_init(ep93xxEth_init); ++module_exit(ep93xxEth_cleanup); ++ ++MODULE_AUTHOR("Cirrus Logic"); ++MODULE_DESCRIPTION("EP93xx ethernet driver"); + MODULE_LICENSE("GPL"); +Index: linux-2.6.24.7/drivers/net/arm/ep93xx_eth.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.24.7/drivers/net/arm/ep93xx_eth.h 2009-09-16 17:37:41.000000000 +0100 +@@ -0,0 +1,402 @@ ++/*------------------------------------------------------------------------ ++ * ep93xx_eth.h ++ * : header file of Ethernet Device Driver for Cirrus Logic EP93xx. ++ * ++ * Copyright (C) 2003 by Cirrus Logic www.cirrus.com ++ * This software may be used and distributed according to the terms ++ * of the GNU Public License. ++ * ++ * This file contains device related information like register info ++ * and register access method macros for the Ethernet device ++ * embedded within Cirrus Logic's EP93xx SOC chip. ++ * ++ * Information contained in this file was obtained from ++ * the EP9312 Manual Revision 0.12 and 0.14 from Cirrus Logic. ++ * ++ * History ++ * 05/18/01 Sungwook Kim Initial release ++ * 03/25/2003 Melody Modified for EP92xx ++ *--------------------------------------------------------------------------*/ ++ ++ ++#ifndef _EP9213_ETH_H_ ++#define _EP9213_ETH_H_ ++ ++ ++/*--------------------------------------------------------------- ++ * Definition of H/W Defects and Their Workarounds ++ *-------------------------------------------------------------*/ ++ ++ ++ ++/*--------------------------------------------------------------- ++ * Data types used in this driver ++ *-------------------------------------------------------------*/ ++typedef unsigned char U8; ++typedef unsigned short U16; ++typedef unsigned long U32; ++typedef unsigned int UINT; ++ ++ ++ ++/*--------------------------------------------------------------- ++ * Definition of the registers. ++ * For details, refer to the datasheet . ++ * ++ * Basically, most registers are 32 bits width register. ++ * But some are 16 bits and some are 6 or 8 bytes long. ++ *-------------------------------------------------------------*/ ++ ++#define REG_RxCTL 0x0000 /*offset to Receiver Control Reg*/ ++#define RxCTL_PauseA (1<<20) ++#define RxCTL_RxFCE1 (1<<19) ++#define RxCTL_RxFCE0 (1<<18) ++#define RxCTL_BCRC (1<<17) ++#define RxCTL_SRxON (1<<16) ++#define RxCTL_RCRCA (1<<13) ++#define RxCTL_RA (1<<12) ++#define RxCTL_PA (1<<11) ++#define RxCTL_BA (1<<10) ++#define RxCTL_MA (1<<9) ++#define RxCTL_IAHA (1<<8) ++#define RxCTL_IA3 (1<<3) ++#define RxCTL_IA2 (1<<2) ++#define RxCTL_IA1 (1<<1) ++#define RxCTL_IA0 (1<<0) ++ ++#define REG_TxCTL 0x0004 /*offset to Transmit Control Reg*/ ++#define TxCTL_DefDis (1<<7) ++#define TxCTL_MBE (1<<6) ++#define TxCTL_ICRC (1<<5) ++#define TxCTL_TxPD (1<<5) ++#define TxCTL_OColl (1<<3) ++#define TxCTL_SP (1<<2) ++#define TxCTL_PB (1<<1) ++#define TxCTL_STxON (1<<0) ++ ++#define REG_TestCTL 0x0008 /*Test Control Reg, R/W*/ ++#define TestCTL_MACF (1<<7) ++#define TestCTL_MFDX (1<<6) ++#define TestCTL_DB (1<<5) ++#define TestCTL_MIIF (1<<4) ++ ++#define REG_MIICmd 0x0010 /*offset to MII Command Reg, R/W*/ ++#define MIICmd_OP (0x03<<14) ++#define MIICmd_OP_RD (2<<14) ++#define MIICmd_OP_WR (1<<14) ++#define MIICmd_PHYAD (0x1f<<5) ++#define MIICmd_REGAD (0x1f<<0) ++ ++#define REG_MIIData 0x0014 /*offset to MII Data Reg, R/W*/ ++#define MIIData_MIIData (0xffff<<0) ++ ++#define REG_MIISts 0x0018 /*offset to MII Status Reg, R*/ ++#define MIISts_Busy (1<<0) ++ ++#define REG_SelfCTL 0x0020 /*offset to Self Control Reg*/ ++#define SelfCTL_RWP (1<<7) /*Remote Wake Pin*/ ++#define SelfCTL_GPO0 (1<<5) ++#define SelfCTL_PUWE (1<<4) ++#define SelfCTL_PDWE (1<<3) ++#define SelfCTL_MIIL (1<<2) ++#define SelfCTL_RESET (1<<0) ++ ++#define REG_IntEn 0x0024 /*Interrupt Enable Reg, R/W*/ ++#define IntEn_RWIE (1<<30) ++#define IntEn_RxMIE (1<<29) ++#define IntEn_RxBIE (1<<28) ++#define IntEn_RxSQIE (1<<27) ++#define IntEn_TxLEIE (1<<26) ++#define IntEn_ECIE (1<<25) ++#define IntEn_TxUHIE (1<<24) ++#define IntEn_MOIE (1<<18) ++#define IntEn_TxCOIE (1<<17) ++#define IntEn_RxROIE (1<<16) ++#define IntEn_MIIIE (1<<12) ++#define IntEn_PHYSIE (1<<11) ++#define IntEn_TIE (1<<10) ++#define IntEn_SWIE (1<<8) ++#define IntEn_TxSQIE (1<<3) ++#define IntEn_RxEOFIE (1<<2) ++#define IntEn_RxEOBIE (1<<1) ++#define IntEn_RxHDRIE (1<<0) ++ ++#define REG_IntStsP 0x0028 /*offset to Interrupt Status Preserve Reg, R/W*/ ++#define REG_IntStsC 0x002c /*offset to Interrupt Status Clear Reg, R*/ ++#define IntSts_RWI (1<<30) ++#define IntSts_RxMI (1<<29) ++#define IntSts_RxBI (1<<28) ++#define IntSts_RxSQI (1<<27) ++#define IntSts_TxLEI (1<<26) ++#define IntSts_ECI (1<<25) ++#define IntSts_TxUHI (1<<24) ++#define IntSts_MOI (1<<18) ++#define IntSts_TxCOI (1<<17) ++#define IntSts_RxROI (1<<16) ++#define IntSts_MIII (1<<12) ++#define IntSts_PHYSI (1<<11) ++#define IntSts_TI (1<<10) ++#define IntSts_AHBE (1<<9) ++#define IntSts_SWI (1<<8) ++#define IntSts_OTHER (1<<4) ++#define IntSts_TxSQ (1<<3) ++#define IntSts_RxSQ (1<<2) ++ ++#define REG_GT 0x0040 /*offset to General Timer Reg*/ ++#define GT_GTC (0xffff<<16) ++#define GT_GTP (0xffff<<0) ++ ++#define REG_FCT 0x0044 /*offset to Flow Control Timer Reg*/ ++#define FCT_FCT (0x00ffffff<<0) ++ ++#define REG_FCF 0x0048 /*offset to Flow Control Format Reg*/ ++#define FCF_MACCT (0xffff<<16) ++#define FCF_TPT (0xffff<<0) ++ ++#define REG_AFP 0x004c /*offset to Address Filter Pointer Reg*/ ++#define AFP_AFP (0x07<<0) /*Address Filter Pointer (bank control for REG_IndAD)*/ ++#define AFP_AFP_IA0 0 /*Primary Individual Address (MAC Addr)*/ ++#define AFP_AFP_IA1 1 /*Individual Address 1*/ ++#define AFP_AFP_IA2 2 /*Individual Address 2*/ ++#define AFP_AFP_IA3 3 /*Individual Address 3*/ ++#define AFP_AFP_DTxP 6 /*Destination Address of Tx Pause Frame*/ ++#define AFP_AFP_HASH 7 /*Hash Table*/ ++ ++#define REG_IndAD 0x0050 /*offset to Individual Address Reg, n bytes, R/W*/ ++ ++#define REG_GIntSts 0x0060 /*offset to Global Interrupt Status Reg (writing 1 will clear)*/ ++#define REG_GIntROS 0x0068 /*offset to Global Interrupt Status Read Only Reg*/ ++#define GIntSts_INT (1<<15) /*Global Interrupt Request Status*/ ++ ++#define REG_GIntMsk 0x0064 /*offset to Global Interrupt Mask Reg*/ ++#define GIntMsk_IntEn (1<<15) /*Global Interrupt Enable*/ ++ ++#define REG_GIntFrc 0x006c /*offset to Global Interrupt Force Reg*/ ++#define GIntFrc_INT (1<<15) /*Force to set GIntSts*/ ++ ++#define REG_TxCollCnt 0x0070 /*Transmit Collision Count Reg, R*/ ++#define REG_RxMissCnt 0x0074 /*Receive Miss Count Reg, R*/ ++#define REG_RxRntCnt 0x0078 /*Receive Runt Count Reg, R*/ ++ ++#define REG_BMCtl 0x0080 /*offset to Bus Master Control Reg, R/W*/ ++#define BMCtl_MT (1<<13) ++#define BMCtl_TT (1<<12) ++#define BMCtl_UnH (1<<11) ++#define BMCtl_TxChR (1<<10) ++#define BMCtl_TxDis (1<<9) ++#define BMCtl_TxEn (1<<8) ++#define BMCtl_EH2 (1<<6) ++#define BMCtl_EH1 (1<<5) ++#define BMCtl_EEOB (1<<4) ++#define BMCtl_RxChR (1<<2) ++#define BMCtl_RxDis (1<<1) ++#define BMCtl_RxEn (1<<0) ++ ++#define REG_BMSts 0x0084 /*offset to Bus Master Status Reg, R*/ ++#define BMSts_TxAct (1<<7) ++#define BMSts_TP (1<<4) ++#define BMSts_RxAct (1<<3) ++#define BMSts_QID (0x07<<0) ++#define BMSts_QID_RxDt (0<<0) ++#define BMSts_QID_TxDt (1<<0) ++#define BMSts_QID_RxSts (2<<0) ++#define BMSts_QID_TxSts (3<<0) ++#define BMSts_QID_RxDesc (4<<0) ++#define BMSts_QID_TxDesc (5<<0) ++ ++#define REG_RBCA 0x0088 /*offset to Receive Buffer Current Address Reg, R*/ ++#define REG_TBCA 0x008c /*offset to Transmit Buffer Current Address Reg, R*/ ++ ++#define REG_RxDBA 0x0090 /*offset to Receive Descriptor Queue Base Address Reg, R/W*/ ++#define REG_RxDBL 0x0094 /*offset to Receive Descriptor Queue Base Length Reg, R/W, 16bits*/ ++#define REG_RxDCL 0x0096 /*offset to Receive Descriptor Queue Current Length Reg, R/W, 16bits*/ ++#define REG_RxDCA 0x0098 /*offset to Receive Descriptor Queue Current Address Reg, R/W*/ ++ ++#define REG_RxDEQ 0x009c /*offset to Receive Descriptor Enqueue Reg, R/W*/ ++#define RxDEQ_RDV (0xffff<<16) /*R 16bit; Receive Descriptor Value*/ ++#define RxDEQ_RDI (0xff<<0) /*W 8bit; Receive Descriptor Increment*/ ++ ++#define REG_RxSBA 0x00a0 /*offset to Receive Status Queue Base Address Reg, R/W*/ ++#define REG_RxSBL 0x00a4 /*offset to Receive Status Queue Base Length Reg, R/W, 16bits*/ ++#define REG_RxSCL 0x00a6 /*offset to Receive Status Queue Current Length Reg, R/W, 16bits*/ ++#define REG_RxSCA 0x00a8 /*offset to Receive Status Queue Current Address Reg, R/W*/ ++ ++#define REG_RxSEQ 0x00ac /*offset to Receive Status Queue Current Address Reg, R/W*/ ++#define RxSEQ_RSV (0xffff<<16) ++#define RxSEQ_RSI (0xff<<0) ++ ++#define REG_TxDBA 0x00b0 /*offset to Transmit Descriptor Queue Base Address Reg, R/W*/ ++#define REG_TxDBL 0x00b4 /*offset to Transmit Descriptor Queue Base Length Reg, R/W, 16bits*/ ++#define REG_TxDCL 0x00b6 /*offset to Transmit Descriptor Queue Current Length Reg, R/W, 16bits*/ ++#define REG_TxDCA 0x00b8 /*offset to Transmit Descriptor Queue Current Address Reg, R/W*/ ++ ++#define REG_TxDEQ 0x00bc /*offset to Transmit Descriptor Queue Current Address Reg, R/W*/ ++#define TxDEQ_TDV (0xffff<<16) ++#define TxDEQ_TDI (0xff<<0) ++ ++#define REG_TxSBA 0x00c0 /*offset to Transmit Status Queue Base Address Reg, R/W*/ ++#define REG_TxSBL 0x00c4 /*offset to Transmit Status Queue Base Length Reg, R/W, 16bits*/ ++#define REG_TxSCL 0x00c6 /*offset to Transmit Status Queue Current Length Reg, R/W, 16bits*/ ++#define REG_TxSCA 0x00c8 /*offset to Transmit Status Queue Current Address Reg, R/W*/ ++ ++#define REG_RxBTH 0x00d0 /*offset to Receive Buffer Threshold Reg, R/W*/ ++#define RxBTH_RDHT (0x03ff<<16) ++#define RxBTH_RDST (0x03ff<<0) ++ ++#define REG_TxBTH 0x00d4 /*offset to Transmit Buffer Threshold Reg, R/W*/ ++#define TxBTH_TDHT (0x03ff<<16) ++#define TxBTH_TDST (0x03ff<<0) ++ ++#define REG_RxSTH 0x00d8 /*offset to Receive Status Threshold Reg, R/W*/ ++#define RxSTH_RSHT (0x003f<<16) ++#define RxSTH_RSST (0x003f<<0) ++ ++#define REG_TxSTH 0x00dc /*offset to Transmit Status Threshold Reg, R/W*/ ++#define TxSTH_TSHT (0x003f<<16) ++#define TxSTH_TSST (0x003f<<0) ++ ++#define REG_RxDTH 0x00e0 /*offset to Receive Descriptor Threshold Reg, R/W*/ ++#define RxDTH_RDHT (0x003f<<16) ++#define RxDTH_RDST (0x003f<<0) ++ ++#define REG_TxDTH 0x00e4 /*offset to Transmit Descriptor Threshold Reg, R/W*/ ++#define TxDTH_TDHT (0x003f<<16) ++#define TxDTH_TDST (0x003f<<0) ++ ++#define REG_MaxFL 0x00e8 /*offset to Max Frame Length Reg, R/W*/ ++#define MaxFL_MFL (0x07ff<<16) ++#define MaxFL_TST (0x07ff<<0) ++ ++#define REG_RxHL 0x00ec /*offset to Receive Header Length Reg, R/W*/ ++#define RxHL_RHL2 (0x07ff<<16) ++#define RxHL_RHL1 (0x03ff<<0) ++ ++#define REG_MACCFG0 0x0100 /*offset to Test Reg #0, R/W*/ ++#define MACCFG0_DbgSel (1<<7) ++#define MACCFG0_LCKEN (1<<6) ++#define MACCFG0_LRATE (1<<5) ++#define MACCFG0_RXERR (1<<4) ++#define MACCFG0_BIT33 (1<<2) ++#define MACCFG0_PMEEN (1<<1) ++#define MACCFG0_PMEST (1<<0) ++ ++#define REG_MACCFG1 0x0104 /*offset to Test Reg #1, R/W*/ ++#define REG_MACCFG2 0x0108 /*offset to Test Reg #2, R*/ ++#define REG_MACCFG3 0x010c /*offset to Test Reg #3, R*/ ++ ++ ++ ++/*--------------------------------------------------------------- ++ * Definition of Descriptor/Status Queue Entry ++ *-------------------------------------------------------------*/ ++ ++typedef union receiveDescriptor { /*data structure of Receive Descriptor Queue Entry*/ ++ struct { /*whole value*/ ++ U32 e0, /*1st dword entry*/ ++ e1; /*2nd dword entry*/ ++ } w; ++ struct { /*bit field definitions*/ ++ U32 ba:32, /*Buffer Address (keep in mind this is physical address)*/ ++ bl:16, /*b15-0; Buffer Length*/ ++ bi:15, /*b30-16; Buffer Index*/ ++ nsof:1; /*b31; Not Start Of Frame*/ ++ } f; ++} receiveDescriptor; ++ ++ ++typedef union receiveStatus { /*data structure of Receive Status Queue Entry*/ ++ struct { /*whole word*/ ++ U32 e0, /*1st dword entry*/ ++ e1; /*2nd dword entry*/ ++ } w; ++ struct { /*bit field*/ ++ U32 rsrv1:8, /*b7-0: reserved*/ ++ hti:6, /*b13-8: Hash Table Index*/ ++ rsrv2:1, /*b14: reserved*/ ++ crci:1, /*b15: CRC Included*/ ++ crce:1, /*b16: CRC Error*/ ++ edata:1, /*b17: Extra Data*/ ++ runt:1, /*b18: Runt Frame*/ ++ fe:1, /*b19: Framing Error*/ ++ oe:1, /*b20: Overrun Error*/ ++ rxerr:1, /*b21: Rx Error*/ ++ am:2, /*b23-22: Address Match*/ ++ rsrv3:4, /*b27-24: reserved*/ ++ eob:1, /*b28: End Of Buffer*/ ++ eof:1, /*b29: End Of Frame*/ ++ rwe:1, /*b30: Received Without Error*/ ++ rfp:1, /*b31: Receive Frame Processed*/ ++ fl:16, /*b15-0: frame length*/ ++ bi:15, /*b30-16: Buffer Index*/ ++ rfp2:1; /*b31: Receive Frame Processed at 2nd word*/ ++ } f; ++} receiveStatus; ++ ++ ++typedef union transmitDescriptor { /*data structure of Transmit Descriptor Queue Entry*/ ++ struct { /*whole value*/ ++ U32 e0, /*1st dword entry*/ ++ e1; /*2nd dword entry*/ ++ } w; ++ struct { /*bit field*/ ++ U32 ba:32, /*b31-0: Buffer Address (keep in mind this is physical address)*/ ++ bl:12, /*b11-0: Buffer Length*/ ++ rsrv1:3, /*b14-12: reserved*/ ++ af:1, /*b15: Abort Frame*/ ++ bi:15, /*b30-16: Buffer Index*/ ++ eof:1; /*b31: End Of Frame*/ ++ ++ } f; ++} transmitDescriptor; ++ ++ ++typedef union transmitStatus { /*data structure of Transmit Status Queue Entry*/ ++ struct { /*whole word*/ ++ U32 e0; /*1st dword entry*/ ++ } w; ++ struct { /*bit field*/ ++ U32 bi:15, /*b14-0: Buffer Index*/ ++ rsrv3:1, /*b15: reserved*/ ++ ncoll:5, /*b20-16: Number of Collisions*/ ++ rsrv2:3, /*b23-21: reserved*/ ++ ecoll:1, /*b24: Excess Collisions*/ ++ txu:1, /*b25: Tx Underrun*/ ++ ow:1, /*b26: Out of Window*/ ++ rsrv1:1, /*b27: reserved*/ ++ lcrs:1, /*b28: Loss of CRS*/ ++ fa:1, /*b29: Frame Abort*/ ++ txwe:1, /*b30: Transmitted Without Error*/ ++ txfp:1; /*b31: Transmit Frame Processed*/ ++ } f; ++} transmitStatus; ++ ++ ++ ++/*--------------------------------------------------------------- ++ * Size of device registers occupied in memory/IO address map ++ *-------------------------------------------------------------*/ ++#define DEV_REG_SPACE 0x00010000 ++ ++/* ++#define U8 unsigned char ++#define U16 unsigned short ++#define U32 unsigned long ++*/ ++ ++/*--------------------------------------------------------------- ++ * A definition of register access macros ++ *-------------------------------------------------------------*/ ++#define _RegRd(type,ofs) (*(volatile type*)(ofs)) ++#define _RegWr(type,ofs,dt) *(volatile type*)(ofs)=((type)(dt)) ++ ++#define RegRd8(ofs) _RegRd(U8,(char*)pD->base_addr+(ofs)) ++#define RegRd16(ofs) _RegRd(U16,(char*)pD->base_addr+(ofs)) ++#define RegRd32(ofs) _RegRd(U32,(char*)pD->base_addr+(ofs)) ++#define RegWr8(ofs,dt) _RegWr(U8,(char*)pD->base_addr+(ofs),(dt)) ++#define RegWr16(ofs,dt) _RegWr(U16,(char*)pD->base_addr+(ofs),(dt)) ++#define RegWr32(ofs,dt) _RegWr(U32,(char*)pD->base_addr+(ofs),(dt)) ++ ++ ++ ++#endif /* _EP9213_ETH_H_ */ ++ |