?? r8169.c
字號:
.msi = 0 }, [RTL_CFG_1] = { .hw_start = rtl_hw_start_8168, .region = 2, .align = 8, .intr_event = SYSErr | LinkChg | RxOverflow | TxErr | TxOK | RxOK | RxErr, .napi_event = TxErr | TxOK | RxOK | RxOverflow, .msi = RTL_FEATURE_MSI }, [RTL_CFG_2] = { .hw_start = rtl_hw_start_8101, .region = 2, .align = 8, .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, .msi = RTL_FEATURE_MSI }};/* Cfg9346_Unlock assumed. */static unsigned rtl_try_msi(struct pci_dev *pdev, void __iomem *ioaddr, const struct rtl_cfg_info *cfg){ unsigned msi = 0; u8 cfg2; cfg2 = RTL_R8(Config2) & ~MSIEnable; if (cfg->msi) { if (pci_enable_msi(pdev)) { dev_info(&pdev->dev, "no MSI. Back to INTx.\n"); } else { cfg2 |= MSIEnable; msi = RTL_FEATURE_MSI; } } RTL_W8(Config2, cfg2); return msi;}static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp){ if (tp->features & RTL_FEATURE_MSI) { pci_disable_msi(pdev); tp->features &= ~RTL_FEATURE_MSI; }}static int __devinitrtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){ const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data; const unsigned int region = cfg->region; struct rtl8169_private *tp; struct net_device *dev; void __iomem *ioaddr; unsigned int i; int rc; if (netif_msg_drv(&debug)) { printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n", MODULENAME, RTL8169_VERSION); } dev = alloc_etherdev(sizeof (*tp)); if (!dev) { if (netif_msg_drv(&debug)) dev_err(&pdev->dev, "unable to alloc new ethernet\n"); rc = -ENOMEM; goto out; } SET_NETDEV_DEV(dev, &pdev->dev); tp = netdev_priv(dev); tp->dev = dev; tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT); /* enable device (incl. PCI PM wakeup and hotplug setup) */ rc = pci_enable_device(pdev); if (rc < 0) { if (netif_msg_probe(tp)) dev_err(&pdev->dev, "enable failure\n"); goto err_out_free_dev_1; } rc = pci_set_mwi(pdev); if (rc < 0) goto err_out_disable_2; /* make sure PCI base addr 1 is MMIO */ if (!(pci_resource_flags(pdev, region) & IORESOURCE_MEM)) { if (netif_msg_probe(tp)) { dev_err(&pdev->dev, "region #%d not an MMIO resource, aborting\n", region); } rc = -ENODEV; goto err_out_mwi_3; } /* check for weird/broken PCI region reporting */ if (pci_resource_len(pdev, region) < R8169_REGS_SIZE) { if (netif_msg_probe(tp)) { dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n"); } rc = -ENODEV; goto err_out_mwi_3; } rc = pci_request_regions(pdev, MODULENAME); if (rc < 0) { if (netif_msg_probe(tp)) dev_err(&pdev->dev, "could not request regions.\n"); goto err_out_mwi_3; } tp->cp_cmd = PCIMulRW | RxChkSum; if ((sizeof(dma_addr_t) > 4) && !pci_set_dma_mask(pdev, DMA_64BIT_MASK) && use_dac) { tp->cp_cmd |= PCIDAC; dev->features |= NETIF_F_HIGHDMA; } else { rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (rc < 0) { if (netif_msg_probe(tp)) { dev_err(&pdev->dev, "DMA configuration failed.\n"); } goto err_out_free_res_4; } } pci_set_master(pdev); /* ioremap MMIO region */ ioaddr = ioremap(pci_resource_start(pdev, region), R8169_REGS_SIZE); if (!ioaddr) { if (netif_msg_probe(tp)) dev_err(&pdev->dev, "cannot remap MMIO, aborting\n"); rc = -EIO; goto err_out_free_res_4; } /* Unneeded ? Don't mess with Mrs. Murphy. */ rtl8169_irq_mask_and_ack(ioaddr); /* Soft reset the chip. */ RTL_W8(ChipCmd, CmdReset); /* Check that the chip has finished the reset. */ for (i = 0; i < 100; i++) { if ((RTL_R8(ChipCmd) & CmdReset) == 0) break; msleep_interruptible(1); } /* Identify chip attached to board */ rtl8169_get_mac_version(tp, ioaddr); rtl8169_print_mac_version(tp); for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) { if (tp->mac_version == rtl_chip_info[i].mac_version) break; } if (i < 0) { /* Unknown chip: assume array element #0, original RTL-8169 */ if (netif_msg_probe(tp)) { dev_printk(KERN_DEBUG, &pdev->dev, "unknown chip version, assuming %s\n", rtl_chip_info[0].name); } i++; } tp->chipset = i; RTL_W8(Cfg9346, Cfg9346_Unlock); RTL_W8(Config1, RTL_R8(Config1) | PMEnable); RTL_W8(Config5, RTL_R8(Config5) & PMEStatus); tp->features |= rtl_try_msi(pdev, ioaddr, cfg); RTL_W8(Cfg9346, Cfg9346_Lock); if ((tp->mac_version <= RTL_GIGA_MAC_VER_06) && (RTL_R8(PHYstatus) & TBI_Enable)) { tp->set_speed = rtl8169_set_speed_tbi; tp->get_settings = rtl8169_gset_tbi; tp->phy_reset_enable = rtl8169_tbi_reset_enable; tp->phy_reset_pending = rtl8169_tbi_reset_pending; tp->link_ok = rtl8169_tbi_link_ok; tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */ } else { tp->set_speed = rtl8169_set_speed_xmii; tp->get_settings = rtl8169_gset_xmii; tp->phy_reset_enable = rtl8169_xmii_reset_enable; tp->phy_reset_pending = rtl8169_xmii_reset_pending; tp->link_ok = rtl8169_xmii_link_ok; dev->do_ioctl = rtl8169_ioctl; } /* Get MAC address. FIXME: read EEPROM */ for (i = 0; i < MAC_ADDR_LEN; i++) dev->dev_addr[i] = RTL_R8(MAC0 + i); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); dev->open = rtl8169_open; dev->hard_start_xmit = rtl8169_start_xmit; dev->get_stats = rtl8169_get_stats; SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops); dev->stop = rtl8169_close; dev->tx_timeout = rtl8169_tx_timeout; dev->set_multicast_list = rtl_set_rx_mode; dev->watchdog_timeo = RTL8169_TX_TIMEOUT; dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr; dev->change_mtu = rtl8169_change_mtu; dev->set_mac_address = rtl_set_mac_address;#ifdef CONFIG_R8169_NAPI netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT);#endif#ifdef CONFIG_R8169_VLAN dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; dev->vlan_rx_register = rtl8169_vlan_rx_register;#endif#ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = rtl8169_netpoll;#endif tp->intr_mask = 0xffff; tp->pci_dev = pdev; tp->mmio_addr = ioaddr; tp->align = cfg->align; tp->hw_start = cfg->hw_start; tp->intr_event = cfg->intr_event; tp->napi_event = cfg->napi_event; init_timer(&tp->timer); tp->timer.data = (unsigned long) dev; tp->timer.function = rtl8169_phy_timer; spin_lock_init(&tp->lock); rc = register_netdev(dev); if (rc < 0) goto err_out_msi_5; pci_set_drvdata(pdev, dev); if (netif_msg_probe(tp)) { u32 xid = RTL_R32(TxConfig) & 0x7cf0f8ff; printk(KERN_INFO "%s: %s at 0x%lx, " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " "XID %08x IRQ %d\n", dev->name, rtl_chip_info[tp->chipset].name, dev->base_addr, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], xid, dev->irq); } rtl8169_init_phy(dev, tp);out: return rc;err_out_msi_5: rtl_disable_msi(pdev, tp); iounmap(ioaddr);err_out_free_res_4: pci_release_regions(pdev);err_out_mwi_3: pci_clear_mwi(pdev);err_out_disable_2: pci_disable_device(pdev);err_out_free_dev_1: free_netdev(dev); goto out;}static void __devexit rtl8169_remove_one(struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata(pdev); struct rtl8169_private *tp = netdev_priv(dev); flush_scheduled_work(); unregister_netdev(dev); rtl_disable_msi(pdev, tp); rtl8169_release_board(pdev, dev, tp->mmio_addr); pci_set_drvdata(pdev, NULL);}static void rtl8169_set_rxbufsize(struct rtl8169_private *tp, struct net_device *dev){ unsigned int mtu = dev->mtu; tp->rx_buf_sz = (mtu > RX_BUF_SIZE) ? mtu + ETH_HLEN + 8 : RX_BUF_SIZE;}static int rtl8169_open(struct net_device *dev){ struct rtl8169_private *tp = netdev_priv(dev); struct pci_dev *pdev = tp->pci_dev; int retval = -ENOMEM; rtl8169_set_rxbufsize(tp, dev); /* * Rx and Tx desscriptors needs 256 bytes alignment. * pci_alloc_consistent provides more. */ tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES, &tp->TxPhyAddr); if (!tp->TxDescArray) goto out; tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES, &tp->RxPhyAddr); if (!tp->RxDescArray) goto err_free_tx_0; retval = rtl8169_init_ring(dev); if (retval < 0) goto err_free_rx_1; INIT_DELAYED_WORK(&tp->task, NULL); smp_mb(); retval = request_irq(dev->irq, rtl8169_interrupt, (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED, dev->name, dev); if (retval < 0) goto err_release_ring_2;#ifdef CONFIG_R8169_NAPI napi_enable(&tp->napi);#endif rtl_hw_start(dev); rtl8169_request_timer(dev); rtl8169_check_link_status(dev, tp, tp->mmio_addr);out: return retval;err_release_ring_2: rtl8169_rx_clear(tp);err_free_rx_1: pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, tp->RxPhyAddr);err_free_tx_0: pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, tp->TxPhyAddr); goto out;}static void rtl8169_hw_reset(void __iomem *ioaddr){ /* Disable interrupts */ rtl8169_irq_mask_and_ack(ioaddr); /* Reset the chipset */ RTL_W8(ChipCmd, CmdReset); /* PCI commit */ RTL_R8(ChipCmd);}static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp){ void __iomem *ioaddr = tp->mmio_addr; u32 cfg = rtl8169_rx_config; cfg |= (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); RTL_W32(RxConfig, cfg); /* Set DMA burst size and Interframe Gap Time */ RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) | (InterFrameGap << TxInterFrameGapShift));}static void rtl_hw_start(struct net_device *dev){ struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; unsigned int i; /* Soft reset the chip. */ RTL_W8(ChipCmd, CmdReset); /* Check that the chip has finished the reset. */ for (i = 0; i < 100; i++) { if ((RTL_R8(ChipCmd) & CmdReset) == 0) break; msleep_interruptible(1); } tp->hw_start(dev); netif_start_queue(dev);}static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp, void __iomem *ioaddr){ /* * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh * register to be written before TxDescAddrLow to work. * Switching from MMIO to I/O access fixes the issue as well. */ RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32); RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_32BIT_MASK); RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32); RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_32BIT_MASK);}static u16 rtl_rw_cpluscmd(void __iomem *ioaddr){ u16 cmd; cmd = RTL_R16(CPlusCmd); RTL_W16(CPlusCmd, cmd); return cmd;}static void rtl_set_rx_max_size(void __iomem *ioaddr){ /* Low hurts. Let's disable the filtering. */ RTL_W16(RxMaxSize, 16383);}static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version){ struct { u32 mac_version; u32 clk; u32 val; } cfg2_info [] = { { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff }, { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff } }, *p = cfg2_info; unsigned int i; u32 clk; clk = RTL_R8(Config2) & PCI_Clock_66MHz; for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) { if ((p->mac_version == mac_version) && (p->clk == clk)) { RTL_W32(0x7c, p->val); break; } }}static void rtl_hw_start_8169(struct net_device *dev){ struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; struct pci_dev *pdev = tp->pci_dev; if (tp->mac_version == RTL_GIGA_MAC_VER_05) { RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW); pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08); } RTL_W8(Cfg9346, Cfg9346_Unlock); if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || (tp->mac_version == RTL_GIGA_MAC_VER_02) || (tp->mac_version == RTL_GIGA_MAC_VER_03) || (tp->mac_version == RTL_GIGA_MAC_VER_04)) RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); RTL_W8(EarlyTxThres, EarlyTxThld); rtl_set_rx_max_size(ioaddr); if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || (tp->mac_version == RTL_GIGA_MAC_VER_02) || (tp->mac_version == RTL_GIGA_MAC_VER_03) || (tp->mac_version == RTL_GIGA_MAC_VER_04)) rtl_set_rx_tx_config_registers(tp); tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW; if ((tp->mac_version == RTL_GIGA_MAC_VER_02) || (tp->mac_version == RTL_GIGA_MAC_VER_03)) { dprintk("Set MAC Reg C+CR Offset 0xE0. " "Bit-3 and bit-14 MUST be 1\n"); tp->cp_cmd |= (1 << 14); } RTL_W16(CPlusCmd, tp->cp_cmd); rtl8169_set_magic_reg(ioaddr, tp->mac_version); /* * Undocumented corner. Supposedly: * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -