📄 dmfe.c
字号:
u8 pci_irqline;
static int index=0; /* For multiple call */
struct dmfe_board_info *db; /* Point a board information structure */
int i;
#if LINUX_VERSION_CODE >= 0x20155
struct pci_dev * net_dev=NULL;
#else
unsigned char bus, fun;
#endif
DMFE_DBUG(0, "dmfe_probe()",0);
#if LINUX_VERSION_CODE >= 0x20155
if (! pci_present())
return -ENODEV;
#else
if (! pcibios_present())
return -ENODEV;
#endif
index=0;
#if LINUX_VERSION_CODE >= 0x20155
while ((net_dev=pci_find_class(PCI_CLASS_NETWORK_ETHERNET<<8, net_dev)))
#else
while (pcibios_find_class(PCI_CLASS_NETWORK_ETHERNET<<8, index, &bus, &fun)==PCIBIOS_SUCCESSFUL)
#endif
{
u32 pci_id, dev_rev, pci_pmr;
u8 pci_cmd;
index++;
#if LINUX_VERSION_CODE >= 0x20155
if (pci_read_config_dword(net_dev, PCI_VENDOR_ID, &pci_id)!=DMFE_SUCC)
#else
if (pcibios_read_config_dword(bus,fun,PCI_VENDOR_ID,&pci_id)!=DMFE_SUCC)
#endif
continue;
if ((pci_id != PCI_DM9102_ID)&&(pci_id != PCI_DM9132_ID)&&(pci_id!=PCI_DM9009_ID) )
continue;
#if LINUX_VERSION_CODE >= 0x20155
/* read PCI IO base address and IRQ to check */
pci_read_config_dword(net_dev, PCI_BASE_ADDRESS_0, &pci_iobase);
pci_read_config_byte(net_dev, PCI_INTERRUPT_LINE, &pci_irqline);
pci_read_config_byte(net_dev, PCI_COMMAND, &pci_cmd);
pci_read_config_dword(net_dev, 8, &dev_rev); /* Read Chip revision */
pci_read_config_dword(net_dev, 0x50, &pci_pmr); /* Read PMR */
#else
/* read PCI IO base address and IRQ to check */
pcibios_read_config_dword(bus,fun,PCI_BASE_ADDRESS_0, &pci_iobase);
pcibios_read_config_byte(bus, fun, PCI_INTERRUPT_LINE, &pci_irqline);
pcibios_read_config_byte(bus, fun, PCI_COMMAND, &pci_cmd);
pcibios_read_config_dword(bus,fun,8,&dev_rev); /* Read Chip revision */
pcibios_read_config_dword(bus,fun,0x50,&pci_pmr); /* Read PMR */
#endif
/* Enable Master/IO access, Disable memory access */
pci_cmd|=PCI_COMMAND_IO+PCI_COMMAND_MASTER;
pci_cmd&=~PCI_COMMAND_MEMORY;
/* Write back PCI command & Let latency timer = 0x80 */
#if LINUX_VERSION_CODE >= 0x20155
pci_write_config_byte(net_dev, PCI_COMMAND, pci_cmd);
pci_write_config_byte(net_dev, PCI_LATENCY_TIMER, 0x80);
#else
pcibios_write_config_byte(bus, fun, PCI_COMMAND, pci_cmd);
pcibios_write_config_byte(bus, fun, PCI_LATENCY_TIMER, 0x80);
#endif
/* IO range check */
pci_iobase&=~0x7f; /* mask off bit0~6 */
if (check_region(pci_iobase, CHK_IO_SIZE(pci_id, dev_rev)))
{
printk(KERN_ERR "dmfe: I/O conflict : IO=%x Range=%x\n", pci_iobase, CHK_IO_SIZE(pci_id, dev_rev));
continue;
}
/* Interrupt check */
if ( (pci_irqline==0xff) || (pci_irqline==0) )
{
printk(KERN_ERR "dmfe: Interrupt wrong : IRQ=%d\n", pci_irqline);
continue;
}
/* Found DM9102 card and PCI resource allocated OK */
dm9102_count++; /* Found a DM9102 card */
/* Init network device */
dev=init_etherdev(dev, 0);
/* Allocated board information structure */
db=(void *)(kmalloc(sizeof(*db), GFP_KERNEL|GFP_DMA));
memset(db, 0, sizeof(*db));
dev->priv = db; /* link device and board info */
db->next_dev=dmfe_root_dev;
dmfe_root_dev=dev;
db->chip_id=pci_id; /* keep Chip vandor/Device ID */
db->ioaddr=pci_iobase;
db->chip_revision=dev_rev;
#if LINUX_VERSION_CODE >= 0x20155
db->net_dev=net_dev;
#else
db->bus=bus; /* keep bus/function */
db->fun=fun;
#endif
dev->base_addr=pci_iobase;
dev->irq=pci_irqline;
dev->open=&dmfe_open;
dev->hard_start_xmit=&dmfe_start_xmit;
dev->stop=&dmfe_stop;
dev->get_stats=&dmfe_get_stats;
dev->set_multicast_list=&dmfe_set_filter_mode;
dev->do_ioctl=&dmfe_do_ioctl;
request_region(pci_iobase, CHK_IO_SIZE(pci_id, dev_rev), dev->name);
printk("dmfe: INDEX=%d ID=%x NAME=%s IO=%x IRQ=%d\n", index, pci_id, dev->name, pci_iobase, pci_irqline);
/* Check Chip type decision */
pci_pmr &= 0x070000; /* Leave PMR revision */
if ( (pci_pmr==0x010000) && (dev_rev==0x02000031) )
db->chip_type=1; /* DM9102A E3 */
else
db->chip_type=0;
/* read 64 word srom data */
for (i=0; i<64; i++)
((u16 *)db->srom)[i]=read_srom_word(pci_iobase, i);
/* Set Node address */
for (i=0; i<6; i++)
dev->dev_addr[i]=db->srom[20+i];
dev=0; /* NULL device */
}
if (!dm9102_count)
printk(KERN_ERR "dmfe: Can't find DM910X board or resource error\n");
return dm9102_count ? 0:-ENODEV;
}
/*
Open the interface.
The interface is opened whenever "ifconfig" actives it.
*/
static int dmfe_open(struct DEVICE *dev)
{
struct dmfe_board_info * db=dev->priv;
DMFE_DBUG(0, "dmfe_open", 0);
#ifdef SA_SHIRQ
if (request_irq(dev->irq, &dmfe_interrupt, SA_SHIRQ, dev->name, dev))
return -EAGAIN;
#else
if (irq2dev_map[dev->irq] != NULL || (irq2dev_map[dev->irq]=dev)==NULL
|| request_irq(dev->irq, &dmfe_interrupt, 0, "DM910X"))
return -EAGAIN;
#endif
/* Allocated Tx/Rx descriptor memory */
db->desc_pool_ptr=kmalloc(sizeof(struct tx_desc)*DESC_ALL_CNT+0x20,GFP_KERNEL|GFP_DMA);
if (db->desc_pool_ptr==NULL)
return -ENOMEM;
if ((u32)db->desc_pool_ptr & 0x1f)
db->first_tx_desc=(struct tx_desc *)(((u32)db->desc_pool_ptr&~0x1f)+0x20);
else
db->first_tx_desc=(struct tx_desc *)db->desc_pool_ptr;
/* Allocated Tx buffer memory */
db->buf_pool_ptr=kmalloc(TX_BUF_ALLOC*TX_DESC_CNT+4,GFP_KERNEL|GFP_DMA);
if (db->buf_pool_ptr==NULL)
{
kfree(db->desc_pool_ptr);
return -ENOMEM;
}
if ((u32)db->buf_pool_ptr & 0x3)
db->buf_pool_start=(char *)(((u32)db->buf_pool_ptr & ~0x3) + 0x4);
else
db->buf_pool_start=db->buf_pool_ptr;
/* system variable init */
db->cr6_data=CR6_DEFAULT | dmfe_cr6_user_set;
db->tx_packet_cnt=0;
db->tx_queue_cnt=0;
db->rx_avail_cnt=0;
db->link_failed=1;
db->wait_reset=0;
db->first_in_callback=0;
db->NIC_capability=0xf; /* All capability*/
db->PHY_reg4=0x1e0;
/* CR6 operation mode decision */
if ( !chkmode || (db->chip_id == PCI_DM9132_ID) || (db->chip_revision >= 0x02000030) )
{
db->cr6_data |= DMFE_TXTH_256;
db->cr0_data = CR0_DEFAULT; /* TX/RX desc burst mode */
db->dm910x_chk_mode=4; /* Enter the normal mode */
}
else
{
db->cr6_data |= CR6_SFT; /* Store & Forward mode */
db->cr0_data=0;
db->dm910x_chk_mode=1; /* Enter the check mode */
}
/* Initilize DM910X board */
dmfe_init_dm910x(dev);
/* Active System Interface */
#if LINUX_VERSION_CODE < 0x20400
dev->tbusy=0; /* Can transmit packet */
dev->start=1; /* interface ready */
#else
netif_wake_queue(dev);
#endif
MOD_INC_USE_COUNT;
/* set and active a timer process */
init_timer(&db->timer);
db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
db->timer.data = (unsigned long)dev;
db->timer.function = &dmfe_timer;
add_timer(&db->timer);
return 0;
}
/* Initilize DM910X board
Reset DM910X board
Initilize TX/Rx descriptor chain structure
Send the set-up frame
Enable Tx/Rx machine
*/
static void dmfe_init_dm910x(struct DEVICE *dev)
{
struct dmfe_board_info *db=dev->priv;
u32 ioaddr=db->ioaddr;
DMFE_DBUG(0, "dmfe_init_dm910x()", 0);
/* Reset DM910x MAC controller */
outl(DM910X_RESET, ioaddr+DCR0); /* RESET MAC */
udelay(100);
outl(db->cr0_data, ioaddr+DCR0);
DELAY_5US;
/* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */
db->phy_addr= 1;
/* Parser SROM and media mode */
dmfe_parse_srom(db);
db->media_mode=dmfe_media_mode;
/* RESET Phyxcer Chip by GPR port bit 7 */
outl(0x180, ioaddr+DCR12); /* Let bit 7 output port */
if (db->chip_id==PCI_DM9009_ID)
{
outl(0x80, ioaddr+DCR12); /* Issue RESET signal */
mdelay(300); /* Delay 300 ms */
}
outl(0x0, ioaddr+DCR12); /* Clear RESET signal */
/* Process Phyxcer Media Mode */
if ( !(db->media_mode & 0x10) ) /* Force 1M mode */
dmfe_set_phyxcer(db);
/* Media Mode Check */
/* Don't need now. We did Restart Auto-Negotiation in dmfe_set_phyxcer()
and it should not complete now. We check media mode and program in
dmfe_timer() later */
if ( !(db->media_mode & DMFE_AUTO) )
db->op_mode=db->media_mode; /* Force Mode */
/* Initiliaze Transmit/Receive decriptor and CR3/4 */
dmfe_descriptor_init(db, ioaddr);
/* Init CR6 to program DM910x operation */
update_cr6(db->cr6_data, ioaddr);
/* Send setup frame */
if (db->chip_id == PCI_DM9132_ID)
dm9132_id_table(dev, dev->mc_count); /* DM9132 */
else
send_filter_frame(dev, dev->mc_count); /* DM9102/DM9102A */
/* Init CR5/CR7, interrupt active bit */
db->cr7_data=CR7_DEFAULT;
outl(db->cr7_data, ioaddr+DCR7);
/* Init CR15, Tx jabber and Rx watchdog timer */
outl(db->cr15_data, ioaddr+DCR15);
/* Enable DM910X Tx/Rx function */
db->cr6_data|=CR6_RXSC | CR6_TXSC | 0x40000;
update_cr6(db->cr6_data, ioaddr);
}
/*
Hardware start transmission.
Send a packet to media from the upper layer.
*/
static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev)
{
struct dmfe_board_info *db=dev->priv;
struct tx_desc *txptr;
DMFE_DBUG(0, "dmfe_start_xmit", 0);
/* Resource flag check */
#if LINUX_VERSION_CODE < 0x20400
if ( test_and_set_bit(0, (void *)&dev->tbusy) )
return 1;
#else
netif_stop_queue(dev);
#endif
/* Too large packet check */
if (skb->len>MAX_PACKET_SIZE)
{
printk(KERN_ERR "dmfe: A big packet, size=%d\n", (u16)skb->len);
#if LINUX_VERSION_CODE > 0x20155
dev_kfree_skb(skb);
#else
dev_kfree_skb(skb, FREE_WRITE);
#endif
return 0;
}
/* No Tx resource check, it never happen nromally */
if (db->tx_queue_cnt >= TX_FREE_DESC_CNT)
return -EBUSY;
/* Disable all interrupt */
outl(0, dev->base_addr+DCR7);
/* transmit this packet */
txptr=db->tx_insert_ptr;
memcpy((char *)txptr->tx_buf_ptr, (char *)skb->data, skb->len);
txptr->tdes1=0xe1000000 | skb->len;
/* Point to next transmit free descriptor */
db->tx_insert_ptr=(struct tx_desc *)txptr->next_tx_desc;
/* Transmit Packet Process */
if ( (!db->tx_queue_cnt) && (db->tx_packet_cnt < TX_MAX_SEND_CNT) )
{
txptr->tdes0=0x80000000; /* set owner bit to DM910X */
db->tx_packet_cnt++; /* Ready to send count */
outl(0x1, dev->base_addr+DCR1); /* Issue Tx polling comand */
dev->trans_start=jiffies; /* saved the time stamp */
}
else
{
db->tx_queue_cnt++; /* queue the tx packet */
outl(0x1, dev->base_addr+DCR1); /* Issue Tx polling comand */
}
/* Tx resource check */
if ( db->tx_queue_cnt < TX_FREE_DESC_CNT )
#if LINUX_VERSION_CODE < 0x20400
dev->tbusy=0;
#else
netif_wake_queue(dev);
#endif
/* free this SKB */
#if LINUX_VERSION_CODE > 0x20155
dev_kfree_skb(skb);
#else
dev_kfree_skb(skb, FREE_WRITE);
#endif
/* Restore CR7 to enable interrupt */
outl(db->cr7_data, dev->base_addr+DCR7);
return 0;
}
/*
Stop the interface.
The interface is stopped when it is brought.
*/
static int dmfe_stop(struct DEVICE *dev)
{
struct dmfe_board_info *db=dev->priv;
u32 ioaddr=dev->base_addr;
DMFE_DBUG(0, "dmfe_stop", 0);
/* disable system */
#if LINUX_VERSION_CODE < 0x20400
dev->start=0; /* interface disable */
dev->tbusy=1; /* can't transmit */
#else
netif_stop_queue(dev);
#endif
/* deleted timer */
del_timer(&db->timer);
/* Reset & stop DM910X board */
outl(DM910X_RESET, ioaddr+DCR0);
DELAY_5US;
phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);
/* free interrupt */
#ifdef SA_SHIRQ
free_irq(dev->irq, dev);
#else
free_irq(dev->irq);
irq2dev_map[dev->irq] = 0;
#endif
/* free allocated rx buffer */
dmfe_free_rxbuffer(db);
/* free all descriptor memory and buffer memory */
kfree(db->desc_pool_ptr);
kfree(db->buf_pool_ptr);
MOD_DEC_USE_COUNT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -