📄 w90p710_mac.c
字号:
/*
* linux/deriver/net/w90p710_mac.c
* Ethernet driver for winbond W90P710 ( PC34 Lsshi )
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/in.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>
#include <asm/semaphore.h>
#include <asm/irq.h>
#include "w90p710_mac.h"
#include <asm/arch/flash.h>
#define HAVE_PHY
#define RX_TIMEOUT 1
//#define IC_PLUS
//#define TEST_REST
#undef DEBUG
//#define DEBUG
#define TRACE_ERROR printk
#ifdef DEBUG
#define TRACE(str, args...) printk("W90P710 eth: " str, ## args)
#define MAC_ASSERT(x) \
do { \
if (!(x)) \
printk("ASSERT: %s:%i(%s)\n", \
__FILE__, __LINE__, __FUNCTION__); \
} while(0);
#else
#define MAC_ASSERT(x)
#define TRACE(str, args...)
#endif
/* Global variables used for MAC driver */
static unsigned long gMCMDR = MCMDR_SPCRC | MCMDR_EnMDC | MCMDR_ACP ;//|MCMDR_LBK;
static unsigned long gMIEN = EnTXINTR | EnRXINTR | EnRXGD | EnTXCP |
EnTxBErr | EnRxBErr | EnTXABT;//| EnTXEMP;//EnDEN
#define RX_DESC_SIZE (3*10)
#define TX_DESC_SIZE (10)
#define CHECK_SIZE
#define PACKET_BUFFER_SIZE 1600
#define PACKET_SIZE 1560
#define TX_TIMEOUT (50)
#define AUTO_SENSE
struct p710_priv
{
struct net_device_stats stats;
unsigned long which;
unsigned long rx_mode;
volatile unsigned long cur_tx_entry;
volatile unsigned long cur_rx_entry;
volatile unsigned long is_rx_all;
//Test
unsigned long bInit;
unsigned long rx_packets;
unsigned long rx_bytes;
unsigned long start_time;
#ifdef AUTO_SENSE
struct timer_list timer0; // detect plug/unplug
struct timer_list timer1; // check auto negotiation result
char plugout;
#endif
volatile unsigned long tx_ptr;
unsigned long tx_finish_ptr;
volatile unsigned long rx_ptr;
unsigned long start_tx_ptr;
unsigned long start_tx_buf;
//char aa[100*100];
unsigned long mcmdr;
volatile unsigned long start_rx_ptr;
volatile unsigned long start_rx_buf;
char mac_address[ETH_ALEN];
volatile RXBD rx_desc[RX_DESC_SIZE] __attribute__ ((aligned (16)));
volatile TXBD tx_desc[TX_DESC_SIZE] __attribute__ ((aligned (16)));
volatile char rx_buf[RX_DESC_SIZE][PACKET_BUFFER_SIZE] __attribute__ ((aligned (16)));
volatile char tx_buf[TX_DESC_SIZE][PACKET_BUFFER_SIZE] __attribute__ ((aligned (16)));
};
char p710_mac_address0[ETH_ALEN]={0x00,0x02,0xac,0x55,0x88,0xa1};
static void init_rxtx_rings(struct net_device *dev);
void notify_hit(struct net_device *dev ,RXBD *rxbd);
int send_frame(struct net_device * ,unsigned char *,int);
void ResetMACRx(struct net_device * dev);
void output_register_context(int );
static int p710_init(struct net_device *dev);
static void netdev_rx(struct net_device *dev);
static void rx_interrupt(int irq, void *dev_id, struct pt_regs * regs);
static void tx_interrupt(int irq, void *dev_id, struct pt_regs * regs);
int prossess_nata(struct net_device *dev,RXBD * rxbd );
void ResetTxRing(struct p710_priv * p710_priv);
int ResetMAC0(struct net_device * dev);
int ResetMAC1(struct net_device * dev);
void ResetMAC(struct net_device * dev);
void ResetRxRing(struct p710_priv * p710_priv);
int MiiStationWrite(int num,unsigned long PhyInAddr,unsigned long PhyAddr,unsigned long PhyWrData);
unsigned long MiiStationRead(int num, unsigned long PhyInAddr, unsigned long PhyAddr);
static int resetPhyOk = 0;
static int timer_num = 0;
volatile struct net_device p710_netdevice[1]=
{
{init:p710_init}
//{init:p710_init}
};
void Dump_Register()
{
printk("RXFSM:%d\n",DWORD_READ(RXFSM));
printk("TXFSM:%d\n",DWORD_READ(TXFSM));
printk("FSM0:%d\n",DWORD_READ(FSM0));
printk("FSM1:%d\n",DWORD_READ(FSM1));
}
void p710_WriteCam(int which,int x, unsigned char *pval)
{
unsigned int msw,lsw;
msw = (pval[0] << 24) |
(pval[1] << 16) |
(pval[2] << 8) |
pval[3];
lsw = (pval[4] << 24) |
(pval[5] << 16);
p710_WriteCam0(which,0,lsw,msw);
}
void ResetP(int num)
{
MiiStationWrite(num,PHY_CNTL_REG,0x0100,RESET_PHY);
MiiStationWrite(num, 20, PHYAD, MiiStationRead(num, 20, PHYAD) | 2); // Set to RMII 1.0 mode
}
int ResetPhyChip(int num)
{
#ifdef HAVE_PHY
unsigned long RdValue;
int which=num;
volatile int loop=1000*100;
//MiiStationWrite(which, PHY_ANA_REG, PHYAD, DR10_TX_HALF|IEEE_802_3_CSMA_CD);
TRACE_ERROR("\nWait for auto-negotiation complete...");
if(MiiStationWrite(which, PHY_CNTL_REG, PHYAD, ENABLE_AN | RESTART_AN)==1)
{
return 1;
}
while (1) /* wait for auto-negotiation complete */
{
RdValue = MiiStationRead(which, PHY_STATUS_REG, PHYAD) ;
if(RdValue==(unsigned long)1)
{
printk("ResetPhyChip failed 1\n");
return 1;
}
if ((RdValue & AN_COMPLETE) != 0 && (RdValue & 4)) // Auto-nego. complete and link valid
{
break;
}
loop--;
if(loop==0)
{
return 1;
}
}
TRACE_ERROR("OK\n");
resetPhyOk = 1;
/* read the result of auto-negotiation */
RdValue = MiiStationRead(which, PHY_ANLPA_REG, PHYAD) ;
if ((RdValue & 0x100)!=0) /* 100MB */
{
TRACE_ERROR("100MB - FULL\n");
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,which)|MCMDR_OPMOD|MCMDR_FDUP,which);
}
else if ((RdValue & 0x80)!=0)
{
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,which)&~MCMDR_FDUP,which);
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,which)|MCMDR_OPMOD,which);
TRACE_ERROR("100MB - HALF\n");
}
else if ((RdValue & 0x40)!=0)/* Full Duplex */
{
TRACE_ERROR("10MB - FULL\n");
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,which)&~MCMDR_OPMOD,which);
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,which)|MCMDR_FDUP,which);
}
else
{
TRACE_ERROR("10MB - HALF\n");
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,which)&~MCMDR_OPMOD,which);
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,which)&~MCMDR_FDUP,which);
}
return 0;
#endif
#ifdef IC_PLUS
{
unsigned long RdValue,i;
// if (!skip_reset)
static int reset_phy=0;
MiiStationWrite(num, PHY_ANA_REG, PHYAD, DR100_TX_FULL|DR100_TX_HALF|\
DR10_TX_FULL|DR10_TX_HALF|IEEE_802_3_CSMA_CD);
MiiStationWrite(num, PHY_CNTL_REG, PHYAD, ENABLE_AN | RESET_PHY|RESTART_AN);
//cbhuang num
MiiStationWrite(num, 0x16, PHYAD, 0x8420);
RdValue = MiiStationRead(num, 0x12, PHYAD);
MiiStationWrite(num, 0x12, PHYAD, RdValue | 0x80); // enable MII registers
if(num == 1) {
for(i=0;i<3;i++)
{
RdValue = MiiStationRead(num, PHY_STATUS_REG, PHYAD) ;
if ((RdValue & AN_COMPLETE) != 0)
{
printk("come cbhuang %s %s %d \n",__FILE__,__FUNCTION__,__LINE__);
break;
}
}
if(i==3)
{
printk("come cbhuang %s %s %d \n",__FILE__,__FUNCTION__,__LINE__);
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,1)| MCMDR_OPMOD,1);
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,1)| MCMDR_FDUP,1);
return 0;
}
}
{
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,num)|MCMDR_OPMOD,num);
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,num)|MCMDR_FDUP,num);
}
return 0;
}
#endif
}
void ResetMAC(struct net_device * dev)
{
struct p710_priv * priv=(struct p710_priv *)dev->priv;
int which=priv->which ;
unsigned long val=p710_ReadReg(MCMDR,which);
unsigned long flags;
save_flags(flags); cli();
p710_WriteReg(FIFOTHD,0x10000,which); //0x10100
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,which)&~(MCMDR_TXON|MCMDR_RXON),which);
p710_WriteReg(FIFOTHD,0x100300,which); //0x10100
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,which)|SWR,which); //lsshi add 2005-4-22 13:05 Software reset
//printk("Reset MAC:%x\n",(unsigned int)&flags);
//printk("Reset MAC MCMDR:%x\n",p710_ReadReg(MCMDR,which));
if(!netif_queue_stopped(dev))
{
netif_stop_queue(dev);
//printk("Reset MAC stop queue\n");
}
init_rxtx_rings(dev);
dev->trans_start=jiffies;
priv->cur_tx_entry=0;
priv->cur_rx_entry=0;
priv->rx_ptr=priv->start_rx_ptr ;
priv->tx_ptr=priv->start_tx_ptr ;
//11-21
priv->tx_finish_ptr=priv->tx_ptr;
p710_WriteReg(RXDLSA,priv->start_rx_ptr,which);
p710_WriteReg(TXDLSA,priv->start_tx_ptr,which);
p710_WriteReg(DMARFC,PACKET_SIZE,which);
p710_WriteCam(priv->which,0,dev->dev_addr);
p710_WriteReg(CAMEN,p710_ReadReg(CAMEN,priv->which) | 1,priv->which);
p710_WriteReg(CAMCMR,CAMCMR_ECMP|CAMCMR_ABP|CAMCMR_AMP,which);
/* Configure the MAC control registers. */
p710_WriteReg(MIEN,gMIEN,which);
//p710_WriteReg(MCMDR,priv->mcmdr,priv->which);
if(which==0)
{
Enable_Int(INT_EMCTXINT0);
Enable_Int(INT_EMCRXINT0);
}
{
p710_WriteReg(MCMDR,MCMDR_TXON|MCMDR_RXON|val,which);
p710_WriteReg(TSDR ,0,which);
p710_WriteReg(RSDR ,0,which);
}
p710_WriteReg(MISTA,p710_ReadReg(MISTA,which),which); //clear interrupt
//printk("reset\n");
restore_flags(flags);
//up(&priv->locksend);
dev->trans_start = jiffies;
if(netif_queue_stopped(dev))
{
netif_wake_queue(dev);
}
}
/************************************************************************
* FUNCTION
* MiiStationWrite
*
* DESCRIPTION
* Write to the Mii Station Control register.
*
* INPUTS
* int num which MAC of W90P710
* unsigned long PhyInAddr PHY register address
* unsigned long PhyAddr Address to write to.
* unsigned long PhyWrData Data to write.
*
* OUTPUTS
* None.
*************************************************************************/
int MiiStationWrite(int num,unsigned long PhyInAddr,unsigned long PhyAddr,unsigned long PhyWrData)
{
volatile int i = 1000;
int which=num;
volatile int loop=1000*100;
#ifdef IC_PLUS1
num = 0;
#endif
which=num;
p710_WriteReg(MIID,PhyWrData,which);
p710_WriteReg(MIIDA,PhyInAddr|PhyAddr|PHYBUSY|PHYWR|MDCCR1,which);
while(i--);
while((p710_ReadReg(MIIDA,which) &PHYBUSY))
{
loop--;
if(loop==0)
return 1;
}
//printk("MiiStationWrite 1\n");
return 0;
}
/************************************************************************
* FUNCTION
* MiiStationRead
*
* DESCRIPTION
* Read from the Mii Station control register.
*
* INPUTS
* int num which MAC of W90P710
* unsigned long PhyInAddr PHY register address.
* unsigned long PhyAddr Address to read from.
*
* OUTPUTS
* unsigned long Data read.
*************************************************************************/
unsigned long MiiStationRead(int num, unsigned long PhyInAddr, unsigned long PhyAddr)
{
unsigned long PhyRdData ;
int which=num;
volatile int loop=1000*100;
#ifdef IC_PLUS1
num = 0;
#endif
which=num;
#define MDCCR1 0x00a00000 // MDC clock rating
p710_WriteReg(MIIDA, PhyInAddr | PhyAddr | PHYBUSY | MDCCR1,which);
while( (p710_ReadReg(MIIDA,which)& PHYBUSY) )
{
loop--;
if(loop==0)
return (unsigned long)1;
}
PhyRdData = p710_ReadReg(MIID,which) ;
return PhyRdData ;
}
/************************************************************************
* FUNCTION
* p710_set_mac_address
*
* DESCRIPTION
* Set MAC Address For Device By Writing CAM Entry 0,
*
* INPUTS
* dev :The MAC which address require to modified
* addr:New Address
*
* OUTPUTS
* Always sucess
*************************************************************************/
static int p710_set_mac_address(struct net_device *dev, void *addr)
{
struct p710_priv * priv=(struct p710_priv *)dev->priv;
if(netif_running(dev))
return -EBUSY;
memcpy(&priv->mac_address[0],addr+2,ETH_ALEN);
memcpy(dev->dev_addr,priv->mac_address,ETH_ALEN);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -