📄 acenic.c
字号:
if (dev == NULL) { printk(KERN_ERR "acenic: Unable to allocate " "net_device structure!\n"); return -ENOMEM; } SET_NETDEV_DEV(dev, &pdev->dev); ap = dev->priv; ap->pdev = pdev; ap->name = pci_name(pdev); dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;#if ACENIC_DO_VLAN dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; dev->vlan_rx_register = ace_vlan_rx_register;#endif dev->tx_timeout = &ace_watchdog; dev->watchdog_timeo = 5*HZ; dev->open = &ace_open; dev->stop = &ace_close; dev->hard_start_xmit = &ace_start_xmit; dev->get_stats = &ace_get_stats; dev->set_multicast_list = &ace_set_multicast_list; SET_ETHTOOL_OPS(dev, &ace_ethtool_ops); dev->set_mac_address = &ace_set_mac_addr; dev->change_mtu = &ace_change_mtu; /* we only display this string ONCE */ if (!boards_found) printk(version); if (pci_enable_device(pdev)) goto fail_free_netdev; /* * Enable master mode before we start playing with the * pci_command word since pci_set_master() will modify * it. */ pci_set_master(pdev); pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command); /* OpenFirmware on Mac's does not set this - DOH.. */ if (!(ap->pci_command & PCI_COMMAND_MEMORY)) { printk(KERN_INFO "%s: Enabling PCI Memory Mapped " "access - was not enabled by BIOS/Firmware\n", ap->name); ap->pci_command = ap->pci_command | PCI_COMMAND_MEMORY; pci_write_config_word(ap->pdev, PCI_COMMAND, ap->pci_command); wmb(); } pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &ap->pci_latency); if (ap->pci_latency <= 0x40) { ap->pci_latency = 0x40; pci_write_config_byte(pdev, PCI_LATENCY_TIMER, ap->pci_latency); } /* * Remap the regs into kernel space - this is abuse of * dev->base_addr since it was means for I/O port * addresses but who gives a damn. */ dev->base_addr = pci_resource_start(pdev, 0); ap->regs = ioremap(dev->base_addr, 0x4000); if (!ap->regs) { printk(KERN_ERR "%s: Unable to map I/O register, " "AceNIC %i will be disabled.\n", ap->name, boards_found); goto fail_free_netdev; } switch(pdev->vendor) { case PCI_VENDOR_ID_ALTEON: if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T) { printk(KERN_INFO "%s: Farallon PN9100-T ", ap->name); } else { printk(KERN_INFO "%s: Alteon AceNIC ", ap->name); } break; case PCI_VENDOR_ID_3COM: printk(KERN_INFO "%s: 3Com 3C985 ", ap->name); break; case PCI_VENDOR_ID_NETGEAR: printk(KERN_INFO "%s: NetGear GA620 ", ap->name); break; case PCI_VENDOR_ID_DEC: if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX) { printk(KERN_INFO "%s: Farallon PN9000-SX ", ap->name); break; } case PCI_VENDOR_ID_SGI: printk(KERN_INFO "%s: SGI AceNIC ", ap->name); break; default: printk(KERN_INFO "%s: Unknown AceNIC ", ap->name); break; } printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr); printk("irq %d\n", pdev->irq);#ifdef CONFIG_ACENIC_OMIT_TIGON_I if ((readl(&ap->regs->HostCtrl) >> 28) == 4) { printk(KERN_ERR "%s: Driver compiled without Tigon I" " support - NIC disabled\n", dev->name); goto fail_uninit; }#endif if (ace_allocate_descriptors(dev)) goto fail_free_netdev;#ifdef MODULE if (boards_found >= ACE_MAX_MOD_PARMS) ap->board_idx = BOARD_IDX_OVERFLOW; else ap->board_idx = boards_found;#else ap->board_idx = BOARD_IDX_STATIC;#endif if (ace_init(dev)) goto fail_free_netdev; if (register_netdev(dev)) { printk(KERN_ERR "acenic: device registration failed\n"); goto fail_uninit; } ap->name = dev->name; if (ap->pci_using_dac) dev->features |= NETIF_F_HIGHDMA; pci_set_drvdata(pdev, dev); boards_found++; return 0; fail_uninit: ace_init_cleanup(dev); fail_free_netdev: free_netdev(dev); return -ENODEV;}static void __devexit acenic_remove_one(struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata(pdev); struct ace_private *ap = netdev_priv(dev); struct ace_regs __iomem *regs = ap->regs; short i; unregister_netdev(dev); writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); if (ap->version >= 2) writel(readl(®s->CpuBCtrl) | CPU_HALT, ®s->CpuBCtrl); /* * This clears any pending interrupts */ writel(1, ®s->Mb0Lo); readl(®s->CpuCtrl); /* flush */ /* * Make sure no other CPUs are processing interrupts * on the card before the buffers are being released. * Otherwise one might experience some `interesting' * effects. * * Then release the RX buffers - jumbo buffers were * already released in ace_close(). */ ace_sync_irq(dev->irq); for (i = 0; i < RX_STD_RING_ENTRIES; i++) { struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb; if (skb) { struct ring_info *ringp; dma_addr_t mapping; ringp = &ap->skb->rx_std_skbuff[i]; mapping = pci_unmap_addr(ringp, mapping); pci_unmap_page(ap->pdev, mapping, ACE_STD_BUFSIZE, PCI_DMA_FROMDEVICE); ap->rx_std_ring[i].size = 0; ap->skb->rx_std_skbuff[i].skb = NULL; dev_kfree_skb(skb); } } if (ap->version >= 2) { for (i = 0; i < RX_MINI_RING_ENTRIES; i++) { struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb; if (skb) { struct ring_info *ringp; dma_addr_t mapping; ringp = &ap->skb->rx_mini_skbuff[i]; mapping = pci_unmap_addr(ringp,mapping); pci_unmap_page(ap->pdev, mapping, ACE_MINI_BUFSIZE, PCI_DMA_FROMDEVICE); ap->rx_mini_ring[i].size = 0; ap->skb->rx_mini_skbuff[i].skb = NULL; dev_kfree_skb(skb); } } } for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) { struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb; if (skb) { struct ring_info *ringp; dma_addr_t mapping; ringp = &ap->skb->rx_jumbo_skbuff[i]; mapping = pci_unmap_addr(ringp, mapping); pci_unmap_page(ap->pdev, mapping, ACE_JUMBO_BUFSIZE, PCI_DMA_FROMDEVICE); ap->rx_jumbo_ring[i].size = 0; ap->skb->rx_jumbo_skbuff[i].skb = NULL; dev_kfree_skb(skb); } } ace_init_cleanup(dev); free_netdev(dev);}static struct pci_driver acenic_pci_driver = { .name = "acenic", .id_table = acenic_pci_tbl, .probe = acenic_probe_one, .remove = __devexit_p(acenic_remove_one),};static int __init acenic_init(void){ return pci_register_driver(&acenic_pci_driver);}static void __exit acenic_exit(void){ pci_unregister_driver(&acenic_pci_driver);}module_init(acenic_init);module_exit(acenic_exit);static void ace_free_descriptors(struct net_device *dev){ struct ace_private *ap = netdev_priv(dev); int size; if (ap->rx_std_ring != NULL) { size = (sizeof(struct rx_desc) * (RX_STD_RING_ENTRIES + RX_JUMBO_RING_ENTRIES + RX_MINI_RING_ENTRIES + RX_RETURN_RING_ENTRIES)); pci_free_consistent(ap->pdev, size, ap->rx_std_ring, ap->rx_ring_base_dma); ap->rx_std_ring = NULL; ap->rx_jumbo_ring = NULL; ap->rx_mini_ring = NULL; ap->rx_return_ring = NULL; } if (ap->evt_ring != NULL) { size = (sizeof(struct event) * EVT_RING_ENTRIES); pci_free_consistent(ap->pdev, size, ap->evt_ring, ap->evt_ring_dma); ap->evt_ring = NULL; } if (ap->tx_ring != NULL && !ACE_IS_TIGON_I(ap)) { size = (sizeof(struct tx_desc) * MAX_TX_RING_ENTRIES); pci_free_consistent(ap->pdev, size, ap->tx_ring, ap->tx_ring_dma); } ap->tx_ring = NULL; if (ap->evt_prd != NULL) { pci_free_consistent(ap->pdev, sizeof(u32), (void *)ap->evt_prd, ap->evt_prd_dma); ap->evt_prd = NULL; } if (ap->rx_ret_prd != NULL) { pci_free_consistent(ap->pdev, sizeof(u32), (void *)ap->rx_ret_prd, ap->rx_ret_prd_dma); ap->rx_ret_prd = NULL; } if (ap->tx_csm != NULL) { pci_free_consistent(ap->pdev, sizeof(u32), (void *)ap->tx_csm, ap->tx_csm_dma); ap->tx_csm = NULL; }}static int ace_allocate_descriptors(struct net_device *dev){ struct ace_private *ap = netdev_priv(dev); int size; size = (sizeof(struct rx_desc) * (RX_STD_RING_ENTRIES + RX_JUMBO_RING_ENTRIES + RX_MINI_RING_ENTRIES + RX_RETURN_RING_ENTRIES)); ap->rx_std_ring = pci_alloc_consistent(ap->pdev, size, &ap->rx_ring_base_dma); if (ap->rx_std_ring == NULL) goto fail; ap->rx_jumbo_ring = ap->rx_std_ring + RX_STD_RING_ENTRIES; ap->rx_mini_ring = ap->rx_jumbo_ring + RX_JUMBO_RING_ENTRIES; ap->rx_return_ring = ap->rx_mini_ring + RX_MINI_RING_ENTRIES; size = (sizeof(struct event) * EVT_RING_ENTRIES); ap->evt_ring = pci_alloc_consistent(ap->pdev, size, &ap->evt_ring_dma); if (ap->evt_ring == NULL) goto fail; /* * Only allocate a host TX ring for the Tigon II, the Tigon I * has to use PCI registers for this ;-( */ if (!ACE_IS_TIGON_I(ap)) { size = (sizeof(struct tx_desc) * MAX_TX_RING_ENTRIES); ap->tx_ring = pci_alloc_consistent(ap->pdev, size, &ap->tx_ring_dma); if (ap->tx_ring == NULL) goto fail; } ap->evt_prd = pci_alloc_consistent(ap->pdev, sizeof(u32), &ap->evt_prd_dma); if (ap->evt_prd == NULL) goto fail; ap->rx_ret_prd = pci_alloc_consistent(ap->pdev, sizeof(u32), &ap->rx_ret_prd_dma); if (ap->rx_ret_prd == NULL) goto fail; ap->tx_csm = pci_alloc_consistent(ap->pdev, sizeof(u32), &ap->tx_csm_dma); if (ap->tx_csm == NULL) goto fail; return 0;fail: /* Clean up. */ ace_init_cleanup(dev); return 1;}/* * Generic cleanup handling data allocated during init. Used when the * module is unloaded or if an error occurs during initialization */static void ace_init_cleanup(struct net_device *dev){ struct ace_private *ap; ap = netdev_priv(dev); ace_free_descriptors(dev); if (ap->info) pci_free_consistent(ap->pdev, sizeof(struct ace_info), ap->info, ap->info_dma); kfree(ap->skb); kfree(ap->trace_buf); if (dev->irq) free_irq(dev->irq, dev); iounmap(ap->regs);}/* * Commands are considered to be slow. */static inline void ace_issue_cmd(struct ace_regs __iomem *regs, struct cmd *cmd){ u32 idx; idx = readl(®s->CmdPrd); writel(*(u32 *)(cmd), ®s->CmdRng[idx]); idx = (idx + 1) % CMD_RING_ENTRIES; writel(idx, ®s->CmdPrd);}static int __devinit ace_init(struct net_device *dev){ struct ace_private *ap; struct ace_regs __iomem *regs; struct ace_info *info = NULL; struct pci_dev *pdev; unsigned long myjif; u64 tmp_ptr; u32 tig_ver, mac1, mac2, tmp, pci_state; int board_idx, ecode = 0; short i; unsigned char cache_size; DECLARE_MAC_BUF(mac); ap = netdev_priv(dev); regs = ap->regs; board_idx = ap->board_idx; /* * aman@sgi.com - its useful to do a NIC reset here to * address the `Firmware not running' problem subsequent * to any crashes involving the NIC */ writel(HW_RESET | (HW_RESET << 24), ®s->HostCtrl); readl(®s->HostCtrl); /* PCI write posting */ udelay(5); /* * Don't access any other registers before this point! */#ifdef __BIG_ENDIAN /* * This will most likely need BYTE_SWAP once we switch * to using __raw_writel() */ writel((WORD_SWAP | CLR_INT | ((WORD_SWAP | CLR_INT) << 24)), ®s->HostCtrl);#else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -