📄 w90p710_mac.c
字号:
memcpy(p710_mac_address0,dev->dev_addr,ETH_ALEN);
TRACE_ERROR("\nSet MaC Address %u:%u:%u:%u:%u:%u\n",
dev->dev_addr[0],\
dev->dev_addr[1],\
dev->dev_addr[2],\
dev->dev_addr[3],\
dev->dev_addr[4],\
dev->dev_addr[5]);
//p710_WriteReg(CAMEN,p710_ReadReg(CAMEN,priv->which) & ~1,priv->which);
return 0;
}
/************************************************************************
* FUNCTION
* init_rxtx_rings
*
* DESCRIPTION
* Initialize the Tx ring and Rx ring.
*
* INPUTS
* dev :Which Ring is initialized including Tx and Rx Ring.
*
* OUTPUTS
* None
*************************************************************************/
static void init_rxtx_rings(struct net_device *dev)
{
int i;
struct p710_priv * p710_priv=dev->priv;
p710_priv->start_tx_ptr =(unsigned long)&p710_priv->tx_desc[0]|NON_CACHE_FLAG;
p710_priv->start_tx_buf =(unsigned long)&p710_priv->tx_buf[0] | NON_CACHE_FLAG;
p710_priv->start_rx_ptr =(unsigned long)&p710_priv->rx_desc[0]|NON_CACHE_FLAG;
p710_priv->start_rx_buf =(unsigned long)&p710_priv->rx_buf[0] | NON_CACHE_FLAG;
//Tx Ring
MAC_ASSERT(p710_priv->start_tx_ptr );
MAC_ASSERT(p710_priv->start_tx_buf );
TRACE(" tx which %d start_tx_ptr %x\n",p710_priv->which,p710_priv->start_tx_ptr);
for ( i = 0 ; i < TX_DESC_SIZE ; i++ )
{
//p710_priv->tx_desc[i]=0;
p710_priv->tx_desc[i].SL=0;
p710_priv->tx_desc[i].mode=0;
p710_priv->tx_desc[i].buffer=(unsigned long)&p710_priv->tx_buf[i]|NON_CACHE_FLAG;
p710_priv->tx_desc[i].next=(unsigned long)&p710_priv->tx_desc[i+1]|NON_CACHE_FLAG;
TRACE(" *tx cur %d desc %x buffer %x", i, &p710_priv->tx_desc[i],p710_priv->tx_desc[i].buffer);
TRACE(" next %x\n",p710_priv->tx_desc[i].next);
}
p710_priv->tx_desc[i-1].next=(unsigned long)&p710_priv->tx_desc[0]|NON_CACHE_FLAG;
TRACE(" * cur %d desc %x buffer %x", i-1, &p710_priv->tx_desc[i-1],p710_priv->tx_desc[i-1].buffer);
TRACE(" next %x\n",p710_priv->tx_desc[i-1].next);
//Rx Ring
MAC_ASSERT(p710_priv->start_rx_ptr );
MAC_ASSERT(p710_priv->start_rx_buf );
TRACE(" tx which %d start_rx_ptr %x\n",p710_priv->which,p710_priv->start_rx_ptr);
for( i =0 ; i < RX_DESC_SIZE ; i++)
{
p710_priv->rx_desc[i].SL=RXfOwnership_DMA;
p710_priv->rx_desc[i].buffer=(unsigned long)&p710_priv->rx_buf[i]|NON_CACHE_FLAG;
p710_priv->rx_desc[i].next=(unsigned long)&p710_priv->rx_desc[i+1]|NON_CACHE_FLAG;
TRACE(" # rx which %d,desc %d desc-addr %x", p710_priv->which,i, &p710_priv->rx_desc[i]);
TRACE(" next %x\n",p710_priv->rx_desc[i].next);
}
p710_priv->rx_desc[i-1].next=(unsigned long)&p710_priv->rx_desc[0]|NON_CACHE_FLAG;
}
#ifdef AUTO_SENSE
#define MAX_AN_CHECK 5
static int an_check;
static void w710_autodetect(unsigned long arg)
{
struct net_device * dev =(struct net_device *)arg;
struct p710_priv * priv=(struct p710_priv *)dev->priv;
int which=priv->which;
//unsigned int rxfsm=w740_ReadReg(RXFSM,priv->which);
//unsigned long status=w740_ReadReg(MISTA,priv->which);
unsigned int RdValue;
RdValue = MiiStationRead(which, PHY_STATUS_REG, PHYAD) ;
if((RdValue&0x20)==0)
{
if(!priv->plugout)
{
printk("MAC Line-off...\n");
*(unsigned int volatile *)(0xfff83020) = 0x50000;
resetPhyOk = 0;
priv->plugout=1;
}
}
else
{
if(priv->plugout)
{
printk("MAC Line-on...\n");
ResetMAC(dev);
if(MiiStationWrite(0, PHY_CNTL_REG, PHYAD, ENABLE_AN | RESTART_AN) != 1) {
priv->timer1.expires = jiffies + (RX_TIMEOUT) * HZ; // Check every seconds for five times
an_check = 1;
add_timer(&priv->timer1);
timer_num = 1;
return;
}
}
}
priv->timer0.expires = jiffies +RX_TIMEOUT*HZ;
add_timer(&priv->timer0);
}
static void check_an_result(unsigned long arg)
{
struct net_device * dev =(struct net_device *)arg;
struct p710_priv * priv=(struct p710_priv *)dev->priv;
unsigned int RdValue;
RdValue = MiiStationRead(0, PHY_STATUS_REG, PHYAD) ;
if(RdValue !=(unsigned long)1) {
// Needs to read second time to let Davicom 9161 PHYs set the link status
RdValue = MiiStationRead(0, PHY_STATUS_REG, PHYAD) ;
if ((RdValue & AN_COMPLETE) != 0 && (RdValue & 4)) // Auto-nego. complete and link valid
{
RdValue = MiiStationRead(0, PHY_ANLPA_REG, PHYAD) ;
if ((RdValue & 0x100)!=0) /* 100MB */
{
TRACE_ERROR("100MB - FULL\n");
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,0)|MCMDR_OPMOD|MCMDR_FDUP,0);
}
else if ((RdValue & 0x80)!=0)
{
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,0)&~MCMDR_FDUP,0);
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,0)|MCMDR_OPMOD,0);
TRACE_ERROR("100MB - HALF\n");
}
else if ((RdValue & 0x40)!=0)/* Full Duplex */
{
TRACE_ERROR("10MB - FULL\n");
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,0)&~MCMDR_OPMOD,0);
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,0)|MCMDR_FDUP,0);
}
else
{
TRACE_ERROR("10MB - HALF\n");
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,0)&~MCMDR_OPMOD,0);
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,0)&~MCMDR_FDUP,0);
}
resetPhyOk = 1;
*(unsigned int volatile *)(0xfff83020) = 0x55555;
priv->plugout=0;
} else if(an_check < MAX_AN_CHECK) {
priv->timer1.expires = jiffies + (RX_TIMEOUT * 2) * HZ;
an_check++;
add_timer(&priv->timer1);
return;
}
}
// ok. check state finished. keep monitoring for plug/unplug
priv->timer0.expires = jiffies +RX_TIMEOUT*HZ;
add_timer(&priv->timer0);
timer_num = 0;
}
#endif
/************************************************************************
* FUNCTION
* p710_open
*
* DESCRIPTION
* Set Register ,Register ISR ,The MAC began to Receive Package.
*
* INPUTS
* dev :Pointer to MAC That is Opened.
*
* OUTPUTS
* Sucess if Return 0
*************************************************************************/
static int p710_open(struct net_device *dev)
{
struct p710_priv * priv;
int which ;
priv=(struct p710_priv *)dev->priv;
which= priv->which;
init_rxtx_rings(dev);
ResetMAC(dev);
priv->rx_ptr=priv->start_rx_ptr ;
priv->tx_ptr=priv->start_tx_ptr ;
p710_WriteReg(FIFOTHD,0x10000,which); //0x10100
p710_WriteReg(FIFOTHD,0x100300,which); //0x10100
p710_WriteReg(RXDLSA,priv->start_rx_ptr,which);
p710_WriteReg(TXDLSA,priv->start_tx_ptr,which);
p710_WriteReg(DMARFC,2000,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);
//p710_WriteReg(CAMCMR,CAMCMR_ECMP|CAMCMR_ABP|CAMCMR_AMP|CAMCMR_AUP,which);
p710_WriteReg(MCMDR,1<<19,which);
*(unsigned int volatile *)(0xfff83020) = 0x50000;
*(unsigned int volatile *)(0xfff83024) = 0; // make sure other pins are in input mode.
ResetP(which);
if(ResetPhyChip(which)==1)
{
TRACE_ERROR("ResetPhyChip Failed\n");
priv->plugout=1;
/*return -1;*/ // yachen
}
else
priv->plugout=0;
//number interrupt number
TRACE("**** which %d \n", which);
/* Configure the MAC control registers. */
p710_WriteReg(MIEN,gMIEN,which);
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,which)|gMCMDR,which);
p710_WriteReg(MCMDR,p710_ReadReg(MCMDR,which)|MCMDR_RXON,which);
priv->mcmdr=p710_ReadReg(MCMDR,which);
priv->bInit=1;
priv->rx_packets=0;
priv->rx_bytes=0;
priv->start_time=jiffies;
#ifdef AUTO_SENSE
init_timer(&priv->timer0);
priv->timer0.expires =jiffies+RX_TIMEOUT*HZ;
priv->timer0.data = (unsigned long) dev;
priv->timer0.function = w710_autodetect;
add_timer(&priv->timer0);
timer_num = 0;
init_timer(&priv->timer1);
priv->timer1.data = (unsigned long) dev;
priv->timer1.function = check_an_result;
#endif
if(which==0){
/* Tx interrupt vector setup. */
AIC_SCR_EMCTX0 = 0x41;
/* Rx interrupt vector setup. */
AIC_SCR_EMCRX0 = 0x41;
/* Enable MAC Tx and Rx interrupt. */
// Enable_Int(INT_EMCTXINT0);
// Enable_Int(EMCRXINT0);
/* set MAC0 as LAN port */
//MCMDR_0 |= MCMDR_LAN ;
}
if(request_irq(INT_EMCTXINT0+which,&tx_interrupt,SA_INTERRUPT,"",dev))
{
TRACE_ERROR(KERN_ERR "W90P710 : register irq tx failed\n");
return -EAGAIN;
}
//compute interrupt number
if(request_irq(INT_EMCRXINT0+which,&rx_interrupt,SA_INTERRUPT,"",dev))
{
TRACE_ERROR(KERN_ERR "W90P710 : register irq rx failed\n");
return -EAGAIN;
}
netif_start_queue(dev);
p710_WriteReg(RSDR ,0,which);
if(resetPhyOk == 1)
*(unsigned int volatile *)(0xfff83020) = 0x55555;
TRACE("%s is OPENED\n",dev->name);
return 0;
}
static int p710_close(struct net_device *dev)
{
struct p710_priv *priv=(struct p710_priv *)dev->priv;
int which=priv->which;
priv->bInit=0;
#ifdef AUTO_SENSE
// there's only one active tiemr at a time. recorded in timer_num.
if(timer_num == 0)
del_timer(&priv->timer0);
else
del_timer(&priv->timer1);
#endif
netif_stop_queue(dev);
p710_WriteReg(MCMDR,0,which);
free_irq(INT_EMCTXINT0+which,dev);
free_irq(INT_EMCRXINT0+which,dev);
TRACE_ERROR(KERN_ERR "W90P710 : p710_close\n");
return 0;
}
/* Get the current statistics. This may be called with the card open or
closed. */
static struct net_device_stats * p710_get_stats(struct net_device *dev)
{
struct p710_priv *priv = (struct p710_priv *)dev->priv;
return &priv->stats;
}
static void p710_timeout(struct net_device *dev)
{
struct p710_priv * priv=(struct p710_priv *)dev->priv;
int which=priv->which;
#ifdef DEBUG
int i=0;
unsigned long cur_ptr;
TXBD *txbd;
cur_ptr=p710_ReadReg(CTXDSA,which);
printk("&(priv->tx_desc[%d]):%x,&(priv->tx_desc[%d]:%x\n"
,priv->cur_tx_entry,&(priv->tx_desc[priv->cur_tx_entry])
,priv->cur_tx_entry+1,&(priv->tx_desc[priv->cur_tx_entry+1]));
printk(",cur_ptr:%x,mode:%x,SL:%x\n",
cur_ptr,((TXBD *)cur_ptr)->mode,((TXBD *)cur_ptr)->SL);
printk("priv->tx_ptr:%x,SL:%x,mode:%x\n",
priv->tx_ptr,((TXBD *)(priv->tx_ptr))->SL,((TXBD *)(priv->tx_ptr))->mode);
printk("0xfff82114:%x,MIEN:%x,MISTA:%x\n",CSR_READ(0xfff82114),
p710_ReadReg(MIEN,which),p710_ReadReg(MISTA,which));
//printk("MAC %d timeout,pid:%d,mode:%d\n",priv->which,current->pid,mode);
for ( i = 0 ; i < TX_DESC_SIZE ; i++ )
{
printk("*tx cur %d desc %x buffer %x",i,&priv->tx_desc[i],priv->tx_desc[i].buffer);
printk(" next %x\n",priv->tx_desc[i].next);
}
#endif
{
printk("RXFSM:%x\n",p710_ReadReg(RXFSM,which));
printk("TXFSM:%x\n",p710_ReadReg(TXFSM,which));
printk("FSM0:%x\n",p710_ReadReg(FSM0,which));
printk("FSM1:%x\n",p710_ReadReg(FSM1,which));
//if((p710_ReadReg(TXFSM,which)&0x0FFF0000)==0x8200000)
ResetMAC(dev);
}
dev->trans_start = jiffies;
}
static int p710_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
#ifdef DEBUG
char *data;
int i=0;
int len=skb->len;
for(i=0;i<len;i+=10)
printk("%2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n",*(data+i),*(data+i+1),
*(data+i+2),*(data+i+3),*(data+i+4),*(data+i+5),*(data+i+6),
*(data+i+7),*(data+i+8),*(data+i+9));
printk("\n");
#endif
//printk("p710_start_xmit:dev:%x\n",dev);
if(!(send_frame(dev,skb->data,skb->len)) )
{
dev_kfree_skb(skb);
TRACE("p710_start_xmit ok\n");
return 0;
}
printk("send failed\n");
return -1;
}
/* The typical workload of the driver:
Handle the network interface interrupts. */
static void tx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct net_device *dev = (struct net_device *)dev_id;
struct p710_priv *priv = (struct p710_priv *)dev->priv;
unsigned long status;
unsigned long cur_ptr;
int which=priv->which;
TXBD *txbd;
static unsigned reset_rx_loop=0;
unsigned long flags;
save_flags(flags); cli();
status=p710_ReadReg(MISTA,which); //get interrupt status;
//p710_WriteReg(MISTA,status&0xFFFF0000,which); //clear interrupt
p710_WriteReg(MISTA,status,which); //clear interrupt
restore_flags(flags);
cur_ptr=p710_ReadReg(CTXDSA,which);
#if 0
if(which==1)
printk("tx_ptr:%x,cur_ptr:%x,tx_entry:%d,s:%x\n",priv->tx_ptr,cur_ptr,priv->cur_tx_entry,status);
#endif
while((&(priv->tx_desc[priv->cur_tx_entry]) != cur_ptr))
{
txbd =(TXBD *)&(priv->tx_desc[priv->cur_tx_entry]);
priv->cur_tx_entry = (priv->cur_tx_entry+1)%(TX_DESC_SIZE);
TRACE("*txbd->SL %x\n",txbd->SL);
TRACE("priv->tx_ptr %x cru_ptr =%x\n",priv->tx_ptr,cur_ptr);
if(txbd->SL &TXDS_TXCP)
{
priv->stats.tx_packets++;
priv->stats.tx_bytes += txbd->SL&0xFFFF;
}
else
{
priv->stats.tx_errors++;
}
txbd->SL=0;
txbd->mode=0;
if (netif_queue_stopped(dev))
{
netif_wake_queue(dev);
}
}
if(status&MISTA_EXDEF)
{
printk("MISTA_EXDEF\n");
}
if((status & MISTA_RDU)&& ++reset_rx_loop==5)
{
TRACE_ERROR("W90P710 MAC In Tx %d RX I Have Not Any Descript Needed\n",priv->which);
//ResetMAC(dev);
//reset_rx_loop=0;
}
if(status&MISTA_TxBErr)
printk("MISTA_TxBErr\n");
if(status&MISTA_TDU)
{
//printk("MISTA_TDU\n");
if (netif_queue_stopped(dev))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -