📄 dm9xs.c
字号:
static int __init dmfe_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
unsigned long pci_iobase;
u8 pci_irqline;
struct dmfe_board_info *db; /* board information structure */
int i;
struct net_device *dev;
u32 dev_rev, pci_pmr;
DMFE_DBUG(0, "dmfe_init_one()", 0);
pci_iobase = pci_resource_start(pdev, 0);
pci_irqline = pdev->irq;
/* iobase check */
if (pci_iobase == 0) {
printk(KERN_ERR "<DM9XS>: I/O base is zero\n");
goto err_out;
}
#if 0 /* pci_{enable_device,set_master} sets minimum latency for us now */
/* Set Latency Timer 80h */
/* FIXME: setting values > 32 breaks some SiS 559x stuff.
Need a PCI quirk.. */
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);
#endif
/* Read Chip revision */
pci_read_config_dword(pdev, PCI_REVISION_ID, &dev_rev);
/* Init network device */
dev = init_etherdev(NULL, sizeof(*db));
if (dev == NULL)
goto err_out;
SET_MODULE_OWNER(dev);
/* IO range check */
if (pci_resource_len (pdev, 0) < (CHK_IO_SIZE(pdev, dev_rev)) ) {
printk(KERN_ERR "<DM9XS>: Allocated I/O size too small\n");
goto err_out_netdev;
}
if (!request_region(pci_iobase,
pci_resource_len (pdev, 0),
dev->name)) {
printk(KERN_ERR "<DM9XS>: I/O conflict : IO=%lx Range=%x\n",
pci_iobase, CHK_IO_SIZE(pdev, dev_rev));
goto err_out_netdev;
}
/* Enable Master/IO access, Disable memory access */
if (pci_enable_device(pdev))
goto err_out_netdev;
pci_set_master(pdev);
/* Init system & device */
db = dev->priv;
/* Allocated Tx/Rx descriptor memory */
db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr);
db->buf_pool_ptr = pci_alloc_consistent(pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4, &db->buf_pool_dma_ptr);
db->first_tx_desc = (struct tx_desc *)db->desc_pool_ptr;
db->first_tx_desc_dma = db->desc_pool_dma_ptr;
db->buf_pool_start = db->buf_pool_ptr;
db->buf_pool_dma_start = db->buf_pool_dma_ptr;
pdev->driver_data = dev;
db->chip_id = ent->driver_data;
db->ioaddr = pci_iobase;
db->chip_revision = dev_rev;
db->net_dev = pdev;
dev->base_addr = pci_iobase;
dev->irq = pci_irqline;
pci_set_drvdata(pdev, dev);
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;
spin_lock_init(&db->lock);
pci_read_config_dword(pdev, 0x50, &pci_pmr);
pci_pmr &= 0x70000;
if ( (pci_pmr == 0x10000) && (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];
return 0;
err_out_netdev:
unregister_netdev(dev);
kfree(dev);
err_out:
return -ENODEV;
}
static void __exit dmfe_remove_one (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct dmfe_board_info *db = dev->priv;
DMFE_DBUG(0, "dmfe_remove_one()", 0);
if (dev) {
pci_free_consistent(db->net_dev, sizeof(struct tx_desc) *
DESC_ALL_CNT + 0x20, db->desc_pool_ptr,
db->desc_pool_dma_ptr);
pci_free_consistent(db->net_dev, TX_BUF_ALLOC * TX_DESC_CNT + 4,
db->buf_pool_ptr, db->buf_pool_dma_ptr);
unregister_netdev(dev);
release_region(dev->base_addr,
CHK_IO_SIZE(pdev, db->chip_revision));
kfree(dev); /* free board information */
pci_set_drvdata(pdev, NULL);
}
DMFE_DBUG(0, "dmfe_remove_one() exit", 0);
}
/*
* Open the interface.
* The interface is opened whenever "ifconfig" actives it.
*/
static int dmfe_open(struct DEVICE *dev)
{
int ret;
struct dmfe_board_info *db = dev->priv;
DMFE_DBUG(0, "dmfe_open", 0);
ret = request_irq(dev->irq, &dmfe_interrupt, SA_SHIRQ, dev->name, dev);
if (ret)
return ret;
/* 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;
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 */
netif_wake_queue(dev);
/* 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 Process */
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 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 */
netif_stop_queue(dev);
/* Too large packet check */
if (skb->len > MAX_PACKET_SIZE) {
printk(KERN_ERR "<DM9XS>: big packet = %d\n", (u16)skb->len);
dev_kfree_skb(skb);
return 0;
}
/* No Tx resource check, it never happen nromally */
if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) {
printk(KERN_ERR "<DM9XS>: No Tx resource %d\n", db->tx_queue_cnt);
return 1;
}
/* Disable NIC interrupt */
outl(0, dev->base_addr + DCR7);
spin_lock_irq(&db->lock);
/* transmit this packet */
txptr = db->tx_insert_ptr;
memcpy( (char *) txptr->tx_buf_ptr, (char *) skb->data, skb->len);
txptr->tdes1 = cpu_to_le32(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 = cpu_to_le32(0x80000000); /* Set owner bit */
db->tx_packet_cnt++; /* Ready to send */
outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling */
dev->trans_start = jiffies; /* saved time stamp */
} else {
db->tx_queue_cnt++; /* queue TX packet */
outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling */
}
/* Tx resource check */
if ( db->tx_queue_cnt < TX_FREE_DESC_CNT )
netif_wake_queue(dev);
/* free this SKB */
dev_kfree_skb(skb);
/* Restore CR7 to enable interrupt */
spin_unlock_irq(&db->lock);
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 */
netif_stop_queue(dev);
/* deleted timer */
del_timer_sync(&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 */
free_irq(dev->irq, dev);
/* free allocated rx buffer */
dmfe_free_rxbuffer(db);
#if 0
/* show statistic counter */
printk("<DM9XS>: FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",
db->tx_fifo_underrun, db->tx_excessive_collision,
db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier,
db->tx_jabber_timeout, db->reset_count, db->reset_cr8,
db->reset_fatal, db->reset_TXtimeout);
#endif
return 0;
}
/*
* DM9102 insterrupt handler
* receive the packet to upper layer, free the transmitted packet
*/
static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct DEVICE *dev = dev_id;
struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;
u32 ioaddr = dev->base_addr;
DMFE_DBUG(0, "dmfe_interrupt()", 0);
if (!dev) {
DMFE_DBUG(1, "dmfe_interrupt() without DEVICE arg", 0);
return;
}
/* Got DM910X status */
db->cr5_data = inl(ioaddr + DCR5);
outl(db->cr5_data, ioaddr + DCR5);
if ( !(db->cr5_data & 0xc1) )
return;
/* Disable all interrupt in CR7 to solve the interrupt edge problem */
outl(0, ioaddr + DCR7);
/* Check system status */
if (db->cr5_data & 0x2000) {
/* system bus error happen */
DMFE_DBUG(1, "System bus error happen. CR5=", db->cr5_data);
db->reset_fatal++;
db->wait_reset = 1; /* Need to RESET */
outl(0, ioaddr + DCR7); /* disable all interrupt */
return;
}
/* Received the coming packet */
if ( (db->cr5_data & 0x40) && db->rx_avail_cnt )
dmfe_rx_packet(dev, db);
/* reallocated rx descriptor buffer */
if (db->rx_avail_cnt<RX_DESC_CNT)
allocated_rx_buffer(db);
/* Free the transmitted descriptor */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -