📄 r6040.c
字号:
while(lp->tx_free_desc < TX_DCNT) { if (descptr->status & 0x8000) break; /* Not complte */ skb_ptr = descptr->skb_ptr; pci_unmap_single(lp->pdev, descptr->buf, skb_ptr->len, PCI_DMA_TODEVICE); dev_kfree_skb_irq(skb_ptr); /* Free buffer */ descptr->skb_ptr = 0; descptr = descptr->vndescp; /* To next descriptor */ lp->tx_free_desc++; } lp->tx_remove_ptr = descptr; if (lp->tx_free_desc) netif_wake_queue(dev); } /* RX interrupt request */ if (status & 0x01) { handled = 1; descptr = lp->rx_remove_ptr; while(lp->rx_free_desc) { if (descptr->status & 0x8000) break; /* No Rx packet */ skb_ptr = descptr->skb_ptr; descptr->skb_ptr = 0; skb_ptr->dev = dev; skb_put(skb_ptr, descptr->len - 4); pci_unmap_single(lp->pdev, descptr->buf, MAX_BUF_SIZE, PCI_DMA_FROMDEVICE); skb_ptr->protocol = eth_type_trans(skb_ptr, dev); netif_rx(skb_ptr); /* Send to upper layer */ lp->stats.rx_packets++; lp->stats.rx_bytes += descptr->len; descptr = descptr->vndescp; /* To next descriptor */ lp->rx_free_desc--; } lp->rx_remove_ptr = descptr; } /* Allocate new RX buffer */ if (lp->rx_free_desc < RX_DCNT) rx_buf_alloc(lp,dev); outw(R6040_INT_MASK, ioaddr + 0x40); /* TX/RX interrupt enable */ spin_unlock_irqrestore(&lp->lock, flags); return IRQ_RETVAL(handled);#endif }static struct net_device_stats *r6040_get_stats(struct net_device *dev){ struct r6040_private *lp = dev->priv; RDC_DBUG("r6040_get_stats()", 0); return &lp->stats;}/* * Set or clear the multicast filter for this adaptor. */static voidset_multicast_list(struct net_device *dev){ struct r6040_private *lp = dev->priv; struct dev_mc_list *mcptr; int ioaddr = dev->base_addr; u16 *adrp, i; unsigned long flags; RDC_DBUG("set_multicast_list()", 0); /* MAC Address */ adrp = (u16 *) dev->dev_addr; outw(adrp[0], ioaddr + 0x68); outw(adrp[1], ioaddr + 0x6A); outw(adrp[2], ioaddr + 0x6C); #if RDC_DEBUG printk("MAC ADDR: %04x %04x %04x\n", adrp[0], adrp[1], adrp[2]);#endif /* Promiscous Mode */ spin_lock_irqsave(&lp->lock, flags); i = inw(ioaddr) & ~0x0120; /* Clear AMCP & PROM */ if (dev->flags & IFF_PROMISC) { i |= 0x0020; lp->mcr0 |= 0x0020 ; } if (dev->mc_count > 4) i |= 0x0020; /* Too many multicast address */ outw(i, ioaddr); spin_unlock_irqrestore(&lp->lock, flags); /* Multicast Address */ if (dev->mc_count > 4) /* Wait to do: Hash Table for multicast */ return; /* Multicast Address 1~4 case */ for (i = 0, mcptr = dev->mc_list; (i<dev->mc_count) && (i<4); i++) { adrp = (u16 *)mcptr->dmi_addr; outw(adrp[0], ioaddr + 0x70 + 8*i); outw(adrp[1], ioaddr + 0x72 + 8*i); outw(adrp[2], ioaddr + 0x74 + 8*i); mcptr = mcptr->next;#if RDC_DEBUG printk("M_ADDR: %04x %04x %04x\n", adrp[0], adrp[1], adrp[2]);#endif } for (i = dev->mc_count; i < 4; i++) { outw(0xffff, ioaddr + 0x68 + 8*i); outw(0xffff, ioaddr + 0x6A + 8*i); outw(0xffff, ioaddr + 0x6C + 8*i); }}static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info){ struct r6040_private *rp = dev->priv; strcpy (info->driver, DRV_NAME); strcpy (info->version, DRV_VERSION); strcpy (info->bus_info, pci_name(rp->pdev));}static struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo,};static intr6040_close(struct net_device *dev){ struct r6040_private *lp = dev->priv; RDC_DBUG("r6040_close()", 0); /* deleted timer */ del_timer_sync(&lp->timer); spin_lock_irq(&lp->lock); netif_stop_queue(dev); r6040_down(dev); spin_unlock_irq(&lp->lock); return 0;}/** */static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd){ struct r6040_private *lp = dev->priv; struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; int rc; if (!netif_running(dev)) return -EINVAL; spin_lock_irq(&lp->lock); rc = generic_mii_ioctl(&lp->mii_if, data, cmd, NULL); spin_unlock_irq(&lp->lock); return rc;}/** Stop RDC MAC and Free the allocated resource */static void r6040_down(struct net_device *dev){ struct r6040_private *lp = dev->priv; int i; u16 *adrp; int ioaddr = dev->base_addr; RDC_DBUG("r6040_down()", 0); /* Stop MAC */ outw(0x0000, ioaddr + 0x40); /* Mask Off Interrupt */ outw(0x0001, ioaddr + 0x04); /* Reset RDC MAC */ i = 0; do{}while((i++ < 2048) && (inw(ioaddr + 0x04) & 0x1)); //Restore MAC Address to MIDx adrp = (u16 *) dev->dev_addr; outw(adrp[0], ioaddr + 0x68); outw(adrp[1], ioaddr + 0x6A); outw(adrp[2], ioaddr + 0x6C); free_irq(dev->irq, dev); /* Free RX buffer */ for (i = 0; i < RX_DCNT; i++) { if (lp->rx_insert_ptr->skb_ptr) { pci_unmap_single(lp->pdev, lp->rx_insert_ptr->buf, MAX_BUF_SIZE, PCI_DMA_FROMDEVICE); dev_kfree_skb(lp->rx_insert_ptr->skb_ptr); lp->rx_insert_ptr->skb_ptr = 0; } lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp; } /* Free TX buffer */ for (i = 0; i < TX_DCNT; i++) { if (lp->tx_insert_ptr->skb_ptr) { pci_unmap_single(lp->pdev, lp->tx_insert_ptr->buf, MAX_BUF_SIZE, PCI_DMA_TODEVICE); dev_kfree_skb(lp->tx_insert_ptr->skb_ptr); lp->rx_insert_ptr->skb_ptr = 0; } lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp; } /* Free Descriptor memory */ pci_free_consistent(lp->pdev, ALLOC_DESC_SIZE, lp->desc_pool, lp->desc_dma);}#ifdef CONFIG_R6040_NAPIstatic int r6040_poll(struct net_device *dev, int *budget){ struct r6040_private *lp; struct r6040_descriptor *descptr; struct sk_buff *skb_ptr; int ioaddr, status; unsigned long flags; ioaddr = dev->base_addr; lp = (struct r6040_private *)dev->priv; unsigned long rx_work = dev->quota ; /* Disable RX interrupt */ local_irq_disable(); lp->NAPI_RX_RUNNING = 1 ; outw(inw(ioaddr + 0x40) & (~RX_INT) ,ioaddr + 0x40 ); local_irq_enable(); { descptr = lp->rx_remove_ptr; while(lp->rx_free_desc) { if (descptr->status & 0x8000) break; /* No Rx packet */ skb_ptr = descptr->skb_ptr; descptr->skb_ptr = 0; skb_ptr->dev = dev; skb_put(skb_ptr, descptr->len - 4); pci_unmap_single(lp->pdev, descptr->buf, MAX_BUF_SIZE, PCI_DMA_FROMDEVICE); skb_ptr->protocol = eth_type_trans(skb_ptr, dev); netif_receive_skb(skb_ptr); /* Send to upper layer */ lp->stats.rx_packets++; lp->stats.rx_bytes += descptr->len; descptr = descptr->vndescp; /* To next descriptor */ lp->rx_free_desc--; } lp->rx_remove_ptr = descptr; } /* Allocate new RX buffer */ if (lp->rx_free_desc < RX_DCNT) rx_buf_alloc(lp,dev); local_irq_disable(); lp->NAPI_RX_RUNNING = 0 ; /* Enable RX interrupt */ outw(inw(ioaddr + 0x40)| RX_INT ,ioaddr + 0x40 ); netif_rx_complete(dev); local_irq_enable(); return 0; }#endif/* Init RDC MAC */static void r6040_up(struct net_device *dev){ struct r6040_private *lp = dev->priv; struct r6040_descriptor *descptr; int i; int ioaddr = dev->base_addr; u32 tmp_addr; dma_addr_t desc_dma, start_dma; RDC_DBUG("r6040_up()", 0); /* Initilize */ lp->tx_free_desc = TX_DCNT; lp->rx_free_desc = 0; /* Init descriptor */ memset(lp->desc_pool, 0, ALLOC_DESC_SIZE); /* Let all descriptor = 0 */ lp->tx_insert_ptr = (struct r6040_descriptor *)lp->desc_pool; lp->tx_remove_ptr = lp->tx_insert_ptr; lp->rx_insert_ptr = (struct r6040_descriptor *)lp->tx_insert_ptr+TX_DCNT; lp->rx_remove_ptr = lp->rx_insert_ptr; /* Init TX descriptor */ descptr = lp->tx_insert_ptr; desc_dma = lp->desc_dma; start_dma = desc_dma; for (i = 0; i < TX_DCNT; i++) { descptr->ndesc = cpu_to_le32(desc_dma + sizeof(struct r6040_descriptor)); descptr->vndescp = (descptr + 1); descptr = (descptr + 1); desc_dma += sizeof(struct r6040_descriptor); } (descptr - 1)->ndesc = cpu_to_le32(start_dma); (descptr - 1)->vndescp = lp->tx_insert_ptr; /* Init RX descriptor */ start_dma = desc_dma; descptr = lp->rx_insert_ptr; for (i = 0; i < RX_DCNT; i++) { descptr->ndesc = cpu_to_le32(desc_dma + sizeof(struct r6040_descriptor)); descptr->vndescp = (descptr + 1); descptr = (descptr + 1); desc_dma += sizeof(struct r6040_descriptor); } (descptr - 1)->ndesc = cpu_to_le32(start_dma); (descptr - 1)->vndescp = lp->rx_insert_ptr; /* Allocate buffer for RX descriptor */ rx_buf_alloc(lp,dev);#if RDC_DEBUG descptr = lp->tx_insert_ptr;for (i = 0; i < TX_DCNT; i++) { printk("%08lx:%04x %04x %08lx %08lx %08lx %08lx\n", descptr, descptr->status, descptr->len, descptr->buf, descptr->skb_ptr, descptr->ndesc, descptr->vndescp); descptr = descptr->vndescp;}descptr = lp->rx_insert_ptr;for (i = 0; i < RX_DCNT; i++) { printk("%08lx:%04x %04x %08lx %08lx %08lx %08lx\n", descptr, descptr->status, descptr->len, descptr->buf, descptr->skb_ptr, descptr->ndesc, descptr->vndescp); descptr = descptr->vndescp;}#endif /* TX and RX descriptor start Register */ tmp_addr = cpu_to_le32(lp->tx_insert_ptr); tmp_addr = virt_to_bus((volatile void *)tmp_addr); outw((u16) tmp_addr, ioaddr+0x2c); outw(tmp_addr >> 16, ioaddr+0x30); tmp_addr = cpu_to_le32(lp->rx_insert_ptr); tmp_addr = virt_to_bus((volatile void *)tmp_addr); outw((u16) tmp_addr, ioaddr+0x34); outw(tmp_addr >> 16, ioaddr+0x38); /* Buffer Size Register */ outw(MAX_BUF_SIZE, ioaddr+0x18); /* PHY Mode Check */ phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP); phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE); if (PHY_MODE == 0x3100) lp->phy_mode = phy_mode_chk(dev); else lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;#ifdef CONFIG_R6040_NAPI /* Sending 15 Tx packets ,only generate one interrupt */ outw(0x0F06, ioaddr+ 0x0C); lp->NAPI_RX_RUNNING =0;#endif /* MAC Bus Control Register */ outw(MBCR_DEFAULT, ioaddr+0x8); /* MAC TX/RX Enable */ lp->mcr0 |= lp->phy_mode; outw(lp->mcr0, ioaddr); /* Interrupt Mask Register */ outw(R6040_INT_MASK, ioaddr + 0x40);}/* A periodic timer routine Polling PHY Chip Link Status*/static void r6040_timer(unsigned long data){ struct net_device *dev=(struct net_device *)data; struct r6040_private *lp = dev->priv; u16 ioaddr = dev->base_addr, phy_mode; RDC_DBUG("r6040_timer()", 0); /* Polling PHY Chip Status */ if (PHY_MODE == 0x3100) phy_mode = phy_mode_chk(dev); else phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0; if (phy_mode != lp->phy_mode) { lp->phy_mode = phy_mode; lp->mcr0 = (lp->mcr0 & 0x7fff) | phy_mode; outw(lp->mcr0, ioaddr); printk("<RDC> Link Change %x \n", inw(ioaddr)); } /* Debug */// printk("<RDC> Timer: CR0 %x CR40 %x CR3C %x\n", inw(ioaddr), inw(ioaddr+0x40), inw(ioaddr+0x3c)); /* Timer active again */ lp->timer.expires = TIMER_WUT; add_timer(&lp->timer);}/* Allocate skb buffer for rx descriptor */static void rx_buf_alloc(struct r6040_private *lp,struct net_device *dev){ struct r6040_descriptor *descptr; int ioaddr = dev->base_addr ; RDC_DBUG("rx_buf_alloc()", 0); descptr = lp->rx_insert_ptr; while(lp->rx_free_desc < RX_DCNT){ descptr->skb_ptr = dev_alloc_skb(MAX_BUF_SIZE); if (!descptr->skb_ptr) break; descptr->buf = cpu_to_le32(pci_map_single(lp->pdev, descptr->skb_ptr->tail, MAX_BUF_SIZE, PCI_DMA_FROMDEVICE)); descptr->status = 0x8000; descptr = descptr->vndescp; lp->rx_free_desc++; outw(lp->mcr0 | 0x0002, ioaddr); //Trigger Rx DMA } lp->rx_insert_ptr = descptr;}/* Status of PHY CHIP */static int phy_mode_chk(struct net_device *dev){ struct r6040_private *lp = dev->priv; int ioaddr = dev->base_addr, phy_dat; RDC_DBUG("phy_mode_chk()", 0); /* PHY Link Status Check */ phy_dat = phy_read(ioaddr, lp->phy_addr, 1); if (!(phy_dat & 0x4)) return 0x8000; /* Link Failed, full duplex */ /* PHY Chip Auto-Negotiation Status */ phy_dat = phy_read(ioaddr, lp->phy_addr, 1); if (phy_dat & 0x0020) { /* Auto Negotiation Mode */ phy_dat = phy_read(ioaddr, lp->phy_addr, 5); phy_dat &= phy_read(ioaddr, lp->phy_addr, 4); if (phy_dat & 0x140) phy_dat = 0x8000; else phy_dat = 0; } else { /* Force Mode */ phy_dat = phy_read(ioaddr, lp->phy_addr, 0); if (phy_dat & 0x100) phy_dat = 0x8000; else phy_dat = 0x0000; } return phy_dat;};/* Read a word data from PHY Chip */static int phy_read(int ioaddr, int phy_addr, int reg_idx){ int i = 0; RDC_DBUG("phy_read()", 0); outw(0x2000 + reg_idx + (phy_addr << 8), ioaddr + 0x20); do{}while( (i++ < 2048) && (inw(ioaddr + 0x20) & 0x2000) ); return inw(ioaddr + 0x24);}/* Write a word data from PHY Chip */static void phy_write(int ioaddr, int phy_addr, int reg_idx, int dat){ int i = 0; RDC_DBUG("phy_write()", 0); outw(dat, ioaddr + 0x28); outw(0x4000 + reg_idx + (phy_addr << 8), ioaddr + 0x20); do{}while( (i++ < 2048) && (inw(ioaddr + 0x20) & 0x4000) );}enum { RDC_6040 = 0};static int r6040_GetSet_MACaddress(struct net_device *dev){ struct r6040_private *lp = dev->priv; int ioaddr = dev->base_addr ; u16 *adrp ; /* MAC operation register */ outw(0x01, ioaddr+0x04); /* Reset MAC */ outw(2 , ioaddr+0xAC); /* Reset internal state machine */ outw(0 , ioaddr+0xAC); udelay(5000); //Restore MAC Address */ adrp = (u16 *) dev->dev_addr; outw(adrp[0], ioaddr + 0x68); outw(adrp[1], ioaddr + 0x6A); outw(adrp[2], ioaddr + 0x6C); }static struct pci_device_id r6040_pci_tbl[] = { {0x17F3, 0x6040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RDC_6040}, //{0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RDC_6040}, {0,} /* terminate list */};MODULE_DEVICE_TABLE(pci, r6040_pci_tbl);static struct pci_driver r6040_driver = { .name = "r6040", .id_table = r6040_pci_tbl, .probe = r6040_init_one, .remove = __devexit_p(r6040_remove_one),};static int __init r6040_init (void){ RDC_DBUG("r6040_init()", 0); printk(version); printed_version = 1; return pci_module_init (&r6040_driver);}static void __exit r6040_cleanup (void){ RDC_DBUG("r6040_cleanup()", 0); pci_unregister_driver (&r6040_driver);}module_init(r6040_init);module_exit(r6040_cleanup);/* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c r6040.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -