📄 dm9ks.c
字号:
db->timer.data = (unsigned long)dev;
db->timer.function = &dmfe_timer;
add_timer(&db->timer); //Move to DM9000 initiallization was finished.
netif_start_queue(dev);
return 0;
}
/* Set PHY operationg mode
*/
static void set_PHY_mode(board_info_t *db)
{
#ifndef DM8606
u16 phy_reg0 = 0x1000;/* Auto-negotiation*/
u16 phy_reg4 = 0x01e1;
if ( !(db->op_mode & DM9KS_AUTO) ) // op_mode didn't auto sense */
{
switch(db->op_mode) {
case DM9KS_10MHD: phy_reg4 = 0x21;
phy_reg0 = 0x1000;
break;
case DM9KS_10MFD: phy_reg4 = 0x41;
phy_reg0 = 0x1100;
break;
case DM9KS_100MHD: phy_reg4 = 0x81;
phy_reg0 = 0x3000;
break;
case DM9KS_100MFD: phy_reg4 = 0x101;
phy_reg0 = 0x3100;
break;
default:
break;
} // end of switch
} // end of if
#ifdef FLOW_CONTROL
phy_write(db, 4, phy_reg4|(1<<10));
#else
phy_write(db, 4, phy_reg4);
#endif //end of FLOW_CONTROL
phy_write(db, 0, phy_reg0|0x200);
#else
/* Fiber mode */
phy_write(db, 16, 0x4014);
phy_write(db, 0, 0x2100);
#endif //end of DM8606
if (db->chip_revision == 0x1A)
{
//set 10M TX idle =65mA (TX 100% utility is 160mA)
phy_write(db,20, phy_read(db,20)|(1<<11)|(1<<10));
//:fix harmonic
//For short code:
//PHY_REG 27 (1Bh) <- 0000h
phy_write(db, 27, 0x0000);
//PHY_REG 27 (1Bh) <- AA00h
phy_write(db, 27, 0xaa00);
//PHY_REG 27 (1Bh) <- 0017h
phy_write(db, 27, 0x0017);
//PHY_REG 27 (1Bh) <- AA17h
phy_write(db, 27, 0xaa17);
//PHY_REG 27 (1Bh) <- 002Fh
phy_write(db, 27, 0x002f);
//PHY_REG 27 (1Bh) <- AA2Fh
phy_write(db, 27, 0xaa2f);
//PHY_REG 27 (1Bh) <- 0037h
phy_write(db, 27, 0x0037);
//PHY_REG 27 (1Bh) <- AA37h
phy_write(db, 27, 0xaa37);
//PHY_REG 27 (1Bh) <- 0040h
phy_write(db, 27, 0x0040);
//PHY_REG 27 (1Bh) <- AA40h
phy_write(db, 27, 0xaa40);
//For long code:
//PHY_REG 27 (1Bh) <- 0050h
phy_write(db, 27, 0x0050);
//PHY_REG 27 (1Bh) <- AA50h
phy_write(db, 27, 0xaa50);
//PHY_REG 27 (1Bh) <- 006Bh
phy_write(db, 27, 0x006b);
//PHY_REG 27 (1Bh) <- AA6Bh
phy_write(db, 27, 0xaa6b);
//PHY_REG 27 (1Bh) <- 007Dh
phy_write(db, 27, 0x007d);
//PHY_REG 27 (1Bh) <- AA7Dh
phy_write(db, 27, 0xaa7d);
//PHY_REG 27 (1Bh) <- 008Dh
phy_write(db, 27, 0x008d);
//PHY_REG 27 (1Bh) <- AA8Dh
phy_write(db, 27, 0xaa8d);
//PHY_REG 27 (1Bh) <- 009Ch
phy_write(db, 27, 0x009c);
//PHY_REG 27 (1Bh) <- AA9Ch
phy_write(db, 27, 0xaa9c);
//PHY_REG 27 (1Bh) <- 00A3h
phy_write(db, 27, 0x00a3);
//PHY_REG 27 (1Bh) <- AAA3h
phy_write(db, 27, 0xaaa3);
//PHY_REG 27 (1Bh) <- 00B1h
phy_write(db, 27, 0x00b1);
//PHY_REG 27 (1Bh) <- AAB1h
phy_write(db, 27, 0xaab1);
//PHY_REG 27 (1Bh) <- 00C0h
phy_write(db, 27, 0x00c0);
//PHY_REG 27 (1Bh) <- AAC0h
phy_write(db, 27, 0xaac0);
//PHY_REG 27 (1Bh) <- 00D2h
phy_write(db, 27, 0x00d2);
//PHY_REG 27 (1Bh) <- AAD2h
phy_write(db, 27, 0xaad2);
//PHY_REG 27 (1Bh) <- 00E0h
phy_write(db, 27, 0x00e0);
//PHY_REG 27 (1Bh) <- AAE0h
phy_write(db, 27, 0xaae0);
//PHY_REG 27 (1Bh) <- 0000h
phy_write(db, 27, 0x0000);
}
}
/*
Initilize DM9000x board
*/
static void dmfe_init_dm9000(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
DMFE_DBUG(0, "dmfe_init_dm9000()", 0);
spin_lock_init(&db->lock);
iow(db, DM9KS_GPR, 0); /* GPR (reg_1Fh)bit GPIO0=0 pre-activate PHY */
mdelay(20); /* wait for PHY power-on ready */
/* do a software reset and wait 20us */
iow(db, DM9KS_NCR, 3);
udelay(20); /* wait 20us at least for software reset ok */
iow(db, DM9KS_NCR, 3); /* NCR (reg_00h) bit[0] RST=1 & Loopback=1, reset on */
udelay(20); /* wait 20us at least for software reset ok */
/* I/O mode */
db->io_mode = ior(db, DM9KS_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */
/* Set PHY */
db->op_mode = media_mode;
set_PHY_mode(db);
/* Program operating register */
iow(db, DM9KS_NCR, 0);
iow(db, DM9KS_TCR, 0); /* TX Polling clear */
iow(db, DM9KS_BPTR, 0x3f); /* Less 3kb, 600us */
iow(db, DM9KS_SMCR, 0); /* Special Mode */
iow(db, DM9KS_NSR, 0x2c); /* clear TX status */
iow(db, DM9KS_ISR, 0x0f); /* Clear interrupt status */
iow(db, DM9KS_TCR2, 0x80); /* Set LED mode 1 */
if (db->chip_revision == 0x1A){
/* Data bus current driving/sinking capability */
iow(db, DM9KS_BUSCR, 0x01); /* default: 2mA */
}
#ifdef FLOW_CONTROL
iow(db, DM9KS_BPTR, 0x37);
iow(db, DM9KS_FCTR, 0x38);
iow(db, DM9KS_FCR, 0x29);
#endif
#ifdef DM8606
iow(db,0x34,1);
#endif
if (dev->features & NETIF_F_HW_CSUM){
printk(KERN_INFO "DM9KS:enable TX checksum\n");
iow(db, DM9KS_TCCR, 0x07); /* TX UDP/TCP/IP checksum enable */
}
if (db->rx_csum){
printk(KERN_INFO "DM9KS:enable RX checksum\n");
iow(db, DM9KS_RCSR, 0x02); /* RX checksum enable */
}
#ifdef ETRANS
/*If TX loading is heavy, the driver can try to anbel "early transmit".
The programmer can tune the "Early Transmit Threshold" to get
the optimization. (DM9KS_ETXCSR.[1-0])
Side Effect: It will happen "Transmit under-run". When TX under-run
always happens, the programmer can increase the value of "Early
Transmit Threshold". */
iow(db, DM9KS_ETXCSR, 0x83);
#endif
/* Set address filter table */
dm9000_hash_table(dev);
/* Activate DM9000/DM9010x */
iow(db, DM9KS_IMR, DM9KS_REGFF); /* Enable TX/RX interrupt mask */
iow(db, DM9KS_RXCR, DM9KS_REG05 | 1); /* RX enable */
/* Init Driver variable */
db->tx_pkt_cnt = 0;
netif_carrier_on(dev);
}
/*
Hardware start transmission.
Send a packet to media from the upper layer.
*/
static int dmfe_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
char * data_ptr;
int i, tmplen;
u16 MDWAH, MDWAL;
#ifdef TDBUG /* check TX FIFO pointer */
u16 MDWAH1, MDWAL1;
u16 tx_ptr;
#endif
DMFE_DBUG(0, "dmfe_start_xmit", 0);
if (db->chip_revision != 0x1A)
{
if(db->Speed == 10)
{if (db->tx_pkt_cnt >= 1) return 1;}
else
{if (db->tx_pkt_cnt >= 2) return 1;}
}else
if (db->tx_pkt_cnt >= 2) return 1;
/* packet counting */
db->tx_pkt_cnt++;
db->stats.tx_packets++;
db->stats.tx_bytes+=skb->len;
if (db->chip_revision != 0x1A)
{
if (db->Speed == 10)
{if (db->tx_pkt_cnt >= 1) netif_stop_queue(dev);}
else
{if (db->tx_pkt_cnt >= 2) netif_stop_queue(dev);}
}else
if (db->tx_pkt_cnt >= 2) netif_stop_queue(dev);
/* Disable all interrupt */
iow(db, DM9KS_IMR, DM9KS_DISINTR);
MDWAH = ior(db,DM9KS_MDWAH);
MDWAL = ior(db,DM9KS_MDWAL);
/* Set TX length to reg. 0xfc & 0xfd */
iow(db, DM9KS_TXPLL, (skb->len & 0xff));
iow(db, DM9KS_TXPLH, (skb->len >> 8) & 0xff);
/* Move data to TX SRAM */
data_ptr = (char *)skb->data;
outb(DM9KS_MWCMD, db->io_addr); // Write data into SRAM trigger
switch(db->io_mode)
{
case DM9KS_BYTE_MODE:
for (i = 0; i < skb->len; i++)
outb((data_ptr[i] & 0xff), db->io_data);
break;
case DM9KS_WORD_MODE:
tmplen = (skb->len + 1) / 2;
for (i = 0; i < tmplen; i++)
outw(((u16 *)data_ptr)[i], db->io_data);
break;
case DM9KS_DWORD_MODE:
tmplen = (skb->len + 3) / 4;
for (i = 0; i< tmplen; i++)
outl(((u32 *)data_ptr)[i], db->io_data);
break;
}
#ifndef ETRANS
/* Issue TX polling command */
iow(db, DM9KS_TCR, 0x1); /* Cleared after TX complete*/
#endif
#ifdef TDBUG /* check TX FIFO pointer */
MDWAH1 = ior(db,DM9KS_MDWAH);
MDWAL1 = ior(db,DM9KS_MDWAL);
tx_ptr = (MDWAH<<8)|MDWAL;
switch (db->io_mode)
{
case DM9KS_BYTE_MODE:
tx_ptr += skb->len;
break;
case DM9KS_WORD_MODE:
tx_ptr += ((skb->len + 1) / 2)*2;
break;
case DM9KS_DWORD_MODE:
tx_ptr += ((skb->len+3)/4)*4;
break;
}
if (tx_ptr > 0x0bff)
tx_ptr -= 0x0c00;
if (tx_ptr != ((MDWAH1<<8)|MDWAL1))
printk("[dm9ks:TX FIFO ERROR\n");
#endif
/* Saved the time stamp */
dev->trans_start = jiffies;
db->cont_rx_pkt_cnt =0;
/* Free this SKB */
dev_kfree_skb(skb);
/* Re-enable interrupt */
iow(db, DM9KS_IMR, DM9KS_REGFF);
return 0;
}
/*
Stop the interface.
The interface is stopped when it is brought.
*/
static int dmfe_stop(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
DMFE_DBUG(0, "dmfe_stop", 0);
/* deleted timer */
del_timer(&db->timer);
netif_stop_queue(dev);
/* free interrupt */
free_irq(dev->irq, dev);
/* RESET devie */
phy_write(db, 0x00, 0x8000); /* PHY RESET */
//iow(db, DM9KS_GPR, 0x01); /* Power-Down PHY */
iow(db, DM9KS_IMR, DM9KS_DISINTR); /* Disable all interrupt */
iow(db, DM9KS_RXCR, 0x00); /* Disable RX */
/* Dump Statistic counter */
#if FALSE
printk("\nRX FIFO OVERFLOW %lx\n", db->stats.rx_fifo_errors);
printk("RX CRC %lx\n", db->stats.rx_crc_errors);
printk("RX LEN Err %lx\n", db->stats.rx_length_errors);
printk("RESET %x\n", db->reset_counter);
printk("RESET: TX Timeout %x\n", db->reset_tx_timeout);
printk("g_TX_nsr %x\n", g_TX_nsr);
#endif
return 0;
}
static void dmfe_tx_done(unsigned long unused)
{
struct net_device *dev = dmfe_dev;
board_info_t *db = (board_info_t *)dev->priv;
int nsr;
DMFE_DBUG(0, "dmfe_tx_done()", 0);
nsr = ior(db, DM9KS_NSR);
if (nsr & 0x0c)
{
if(nsr & 0x04) db->tx_pkt_cnt--;
if(nsr & 0x08) db->tx_pkt_cnt--;
if(db->tx_pkt_cnt < 0)
{
printk(KERN_DEBUG "DM9KS:tx_pkt_cnt ERROR!!\n");
while(ior(db,DM9KS_TCR) & 0x1){}
db->tx_pkt_cnt = 0;
}
}else{
while(ior(db,DM9KS_TCR) & 0x1){}
db->tx_pkt_cnt = 0;
}
netif_wake_queue(dev);
return;
}
/*
DM9000x insterrupt handler
receive the packet to upper layer, free the transmitted packet
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
static irqreturn_t dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#else
static irqreturn_t dmfe_interrupt(int irq, void *dev_id) /* for kernel 2.6.20*/
#endif
#endif
{
struct net_device *dev = dev_id;
board_info_t *db;
int int_status,i;
u8 reg_save;
DMFE_DBUG(0, "dmfe_interrupt()", 0);
/* A real interrupt coming */
db = (board_info_t *)dev->priv;
spin_lock(&db->lock);
/* Save previous register address */
reg_save = inb(db->io_addr);
/* Disable all interrupt */
iow(db, DM9KS_IMR, DM9KS_DISINTR);
/* Got DM9000x/DM9010x interrupt status */
int_status = ior(db, DM9KS_ISR); /* Got ISR */
iow(db, DM9KS_ISR, int_status); /* Clear ISR status */
/* Link status change */
if (int_status & DM9KS_LINK_INTR)
{
netif_stop_queue(dev);
for(i=0; i<500; i++) /*wait link OK, waiting time =0.5s */
{
phy_read(db,0x1);
if(phy_read(db,0x1) & 0x4) /*Link OK*/
{
/* wait for detected Speed */
for(i=0; i<200;i++)
udelay(1000);
/* set media speed */
if(phy_read(db,0)&0x2000) db->Speed =100;
else db->Speed =10;
break;
}
udelay(1000);
}
netif_wake_queue(dev);
//printk("[INTR]i=%d speed=%d\n",i, (int)(db->Speed));
}
/* Received the coming packet */
if (int_status & DM9KS_RX_INTR)
dmfe_packet_receive(dev);
/* Trnasmit Interrupt check */
if (int_status & DM9KS_TX_INTR)
dmfe_tx_done(0);
if (db->cont_rx_pkt_cnt>=CONT_RX_PKT_CNT)
{
iow(db, DM9KS_IMR, 0xa2);
}
else
{
/* Re-enable interrupt mask */
iow(db, DM9KS_IMR, DM9KS_REGFF);
}
/* Restore previous register address */
outb(reg_save, db->io_addr);
spin_unlock(&db->lock);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
return IRQ_HANDLED;
#endif
}
/*
Get statistics from driver.
*/
static struct net_device_stats * dmfe_get_stats(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
DMFE_DBUG(0, "dmfe_get_stats", 0);
return &db->stats;
}
/*
* Process the ethtool ioctl command
*/
static int dmfe_ethtool_ioctl(struct net_device *dev, void *useraddr)
{
//struct dmfe_board_info *db = dev->priv;
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
u32 ethcmd;
if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd)))
return -EFAULT;
switch (ethcmd)
{
case ETHTOOL_GDRVINFO:
strcpy(info.driver, DRV_NAME);
strcpy(info.version, DRV_VERSION);
sprintf(info.bus_info, "ISA 0x%lx %d",dev->base_addr, dev->irq);
if (copy_to_user(useraddr, &info, sizeof(info)))
return -EFAULT;
return 0;
}
return -EOPNOTSUPP;
}
/*
Process the upper socket ioctl command
*/
static int dmfe_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
board_info_t *db = (board_info_t *)dev->priv;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7) /* for kernel 2.6.7 */
struct mii_ioctl_data *data=(struct mii_ioctl_data *)&ifr->ifr_data;
#endif
int rc=0;
DMFE_DBUG(0, "dmfe_do_ioctl()", 0);
if (!netif_running(dev))
return -EINVAL;
if (cmd == SIOCETHTOOL)
rc = dmfe_ethtool_ioctl(dev, (void *) ifr->ifr_data);
else {
spin_lock_irq(&db->lock);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7) /* for kernel 2.6.7 */
rc = generic_mii_ioctl(&db->mii, data, cmd, NULL);
#else
rc = generic_mii_ioctl(&db->mii, if_mii(ifr), cmd, NULL);
#endif
spin_unlock_irq(&db->lock);
}
return rc;
}
/* Our watchdog timed out. Called by the networking layer */
static void dmfe_timeout(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
int i;
DMFE_DBUG(0, "dmfe_TX_timeout()", 0);
printk("TX time-out -- dmfe_timeout().\n");
db->reset_tx_timeout++;
db->stats.tx_errors++;
#if FALSE
printk("TX packet count = %d\n", db->tx_pkt_cnt);
printk("TX timeout = %d\n", db->reset_tx_timeout);
printk("22H=0x%02x 23H=0x%02x\n",ior(db,0x22),ior(db,0x23));
printk("faH=0x%02x fbH=0x%02x\n",ior(db,0xfa),ior(db,0xfb));
#endif
i=0;
while((i++<100)&&(ior(db,DM9KS_TCR) & 0x01))
{
udelay(30);
}
if(i<100)
{
db->tx_pkt_cnt = 0;
netif_wake_queue(dev);
}
else
{
dmfe_reset(dev);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -