📄 r8169.c
字号:
tp->cp_cmd |= PCIDAC; else { rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (rc < 0) { printk(KERN_ERR PFX "DMA configuration failed.\n"); goto err_out_free_res; } } // enable PCI bus-mastering pci_set_master(pdev); // ioremap MMIO region ioaddr = ioremap(mmio_start, mmio_len); if (ioaddr == NULL) { printk(KERN_ERR PFX "cannot remap MMIO, aborting\n"); rc = -EIO; goto err_out_free_res; } // Soft reset the chip. RTL_W8(ChipCmd, CmdReset); // Check that the chip has finished the reset. for (i = 1000; i > 0; i--) { if ((RTL_R8(ChipCmd) & CmdReset) == 0) break; udelay(10); } // Identify chip attached to board rtl8169_get_mac_version(tp, ioaddr); rtl8169_get_phy_version(tp, ioaddr); rtl8169_print_mac_version(tp); rtl8169_print_phy_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 */ printk(KERN_DEBUG PFX "PCI device %s: unknown chip version, assuming %s\n", pci_name(pdev), rtl_chip_info[0].name); i++; } tp->chipset = i; *ioaddr_out = ioaddr; *dev_out = dev; return 0;err_out_free_res: pci_release_regions(pdev);err_out_disable: pci_disable_device(pdev);err_out: free_netdev(dev); return rc;}static int __devinitrtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){ struct net_device *dev = NULL; struct rtl8169_private *tp = NULL; void *ioaddr = NULL; static int board_idx = -1; static int printed_version = 0; u8 autoneg, duplex; u16 speed; int i, rc; assert(pdev != NULL); assert(ent != NULL); board_idx++; if (!printed_version) { printk(KERN_INFO RTL8169_DRIVER_NAME " loaded\n"); printed_version = 1; } rc = rtl8169_init_board(pdev, &dev, &ioaddr); if (rc) return rc; tp = dev->priv; assert(ioaddr != NULL); assert(dev != NULL); assert(tp != NULL); if (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 = PHY_Cap_1000_Full; /* 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; } // Get MAC address. FIXME: read EEPROM for (i = 0; i < MAC_ADDR_LEN; i++) dev->dev_addr[i] = RTL_R8(MAC0 + i); dev->open = rtl8169_open; dev->hard_start_xmit = rtl8169_start_xmit; dev->get_stats = rtl8169_get_stats; dev->ethtool_ops = &rtl8169_ethtool_ops; dev->stop = rtl8169_close; dev->tx_timeout = rtl8169_tx_timeout; dev->set_multicast_list = rtl8169_set_rx_mode; dev->watchdog_timeo = RTL8169_TX_TIMEOUT; dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr;#ifdef CONFIG_R8169_NAPI dev->poll = rtl8169_poll; dev->weight = R8169_NAPI_WEIGHT; printk(KERN_INFO PFX "NAPI enabled\n");#endif tp->intr_mask = 0xffff; tp->pci_dev = pdev; tp->mmio_addr = ioaddr; spin_lock_init(&tp->lock); rc = register_netdev(dev); if (rc) { iounmap(ioaddr); pci_release_regions(pdev); pci_disable_device(pdev); free_netdev(dev); return rc; } printk(KERN_DEBUG "%s: Identified chip type is '%s'.\n", dev->name, rtl_chip_info[tp->chipset].name); pci_set_drvdata(pdev, dev); printk(KERN_INFO "%s: %s at 0x%lx, " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " "IRQ %d\n", dev->name, rtl_chip_info[ent->driver_data].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], dev->irq); rtl8169_hw_phy_config(dev); dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); RTL_W8(0x82, 0x01); if (tp->mac_version < RTL_GIGA_MAC_VER_E) { dprintk("Set PCI Latency=0x40\n"); pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40); } if (tp->mac_version == RTL_GIGA_MAC_VER_D) { dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); RTL_W8(0x82, 0x01); dprintk("Set PHY Reg 0x0bh = 0x00h\n"); mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0 } rtl8169_link_option(board_idx, &autoneg, &speed, &duplex); rtl8169_set_speed(dev, autoneg, speed, duplex); if (RTL_R8(PHYstatus) & TBI_Enable) printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name); return 0;}static void __devexitrtl8169_remove_one(struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata(pdev); struct rtl8169_private *tp = netdev_priv(dev); assert(dev != NULL); assert(tp != NULL); unregister_netdev(dev); iounmap(tp->mmio_addr); pci_release_regions(pdev); pci_disable_device(pdev); free_netdev(dev); pci_set_drvdata(pdev, NULL);}#ifdef CONFIG_PMstatic int rtl8169_suspend(struct pci_dev *pdev, u32 state){ struct net_device *dev = pci_get_drvdata(pdev); struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; unsigned long flags; if (!netif_running(dev)) return 0; netif_device_detach(dev); netif_stop_queue(dev); spin_lock_irqsave(&tp->lock, flags); /* Disable interrupts, stop Rx and Tx */ RTL_W16(IntrMask, 0); RTL_W8(ChipCmd, 0); /* Update the error counts. */ tp->stats.rx_missed_errors += RTL_R32(RxMissed); RTL_W32(RxMissed, 0); spin_unlock_irqrestore(&tp->lock, flags); return 0;}static int rtl8169_resume(struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata(pdev); if (!netif_running(dev)) return 0; netif_device_attach(dev); rtl8169_hw_start(dev); return 0;} #endif /* CONFIG_PM */static intrtl8169_open(struct net_device *dev){ struct rtl8169_private *tp = netdev_priv(dev); struct pci_dev *pdev = tp->pci_dev; int retval; retval = request_irq(dev->irq, rtl8169_interrupt, SA_SHIRQ, dev->name, dev); if (retval < 0) goto out; retval = -ENOMEM; /* * 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 err_free_irq; tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES, &tp->RxPhyAddr); if (!tp->RxDescArray) goto err_free_tx; retval = rtl8169_init_ring(dev); if (retval < 0) goto err_free_rx; rtl8169_hw_start(dev); rtl8169_request_timer(dev); rtl8169_check_link_status(dev, tp, tp->mmio_addr);out: return retval;err_free_rx: pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, tp->RxPhyAddr);err_free_tx: pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, tp->TxPhyAddr);err_free_irq: free_irq(dev->irq, dev); goto out;}static voidrtl8169_hw_start(struct net_device *dev){ struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; u32 i; /* Soft reset the chip. */ RTL_W8(ChipCmd, CmdReset); /* Check that the chip has finished the reset. */ for (i = 1000; i > 0; i--) { if ((RTL_R8(ChipCmd) & CmdReset) == 0) break; udelay(10); } RTL_W8(Cfg9346, Cfg9346_Unlock); RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); RTL_W8(EarlyTxThres, EarlyTxThld); // For gigabit rtl8169 RTL_W16(RxMaxSize, RxPacketMaxSize); // Set Rx Config register i = rtl8169_rx_config | (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); RTL_W32(RxConfig, i); /* Set DMA burst size and Interframe Gap Time */ RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) | (InterFrameGap << TxInterFrameGapShift)); tp->cp_cmd |= RTL_R16(CPlusCmd); RTL_W16(CPlusCmd, tp->cp_cmd); if (tp->mac_version == RTL_GIGA_MAC_VER_D) { dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0. " "Bit-3 and bit-14 MUST be 1\n"); tp->cp_cmd |= (1 << 14) | PCIMulRW; RTL_W16(CPlusCmd, tp->cp_cmd); } tp->cur_rx = 0; RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr & DMA_32BIT_MASK)); RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr >> 32)); RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr & DMA_32BIT_MASK)); RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr >> 32)); RTL_W8(Cfg9346, Cfg9346_Lock); udelay(10); RTL_W32(RxMissed, 0); rtl8169_set_rx_mode(dev); /* no early-rx interrupts */ RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); /* Enable all known interrupts by setting the interrupt mask. */ RTL_W16(IntrMask, rtl8169_intr_mask); netif_start_queue(dev);}static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc){ desc->addr = 0x0badbadbadbadbadull; desc->status &= ~cpu_to_le32(OWNbit | RsvdMask);}static void rtl8169_free_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff, struct RxDesc *desc){ pci_unmap_single(pdev, le64_to_cpu(desc->addr), RX_BUF_SIZE, PCI_DMA_FROMDEVICE); dev_kfree_skb(*sk_buff); *sk_buff = NULL; rtl8169_make_unusable_by_asic(desc);}static inline void rtl8169_return_to_asic(struct RxDesc *desc){ desc->status |= cpu_to_le32(OWNbit + RX_BUF_SIZE);}static inline void rtl8169_give_to_asic(struct RxDesc *desc, dma_addr_t mapping){ desc->addr = cpu_to_le64(mapping); desc->status |= cpu_to_le32(OWNbit + RX_BUF_SIZE);}static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct net_device *dev, struct sk_buff **sk_buff, struct RxDesc *desc){ struct sk_buff *skb; dma_addr_t mapping; int ret = 0; skb = dev_alloc_skb(RX_BUF_SIZE); if (!skb) goto err_out; skb->dev = dev; skb_reserve(skb, 2); *sk_buff = skb; mapping = pci_map_single(pdev, skb->tail, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); rtl8169_give_to_asic(desc, mapping);out: return ret;err_out: ret = -ENOMEM; rtl8169_make_unusable_by_asic(desc); goto out;}static void rtl8169_rx_clear(struct rtl8169_private *tp){ int i; for (i = 0; i < NUM_RX_DESC; i++) { if (tp->Rx_skbuff[i]) { rtl8169_free_rx_skb(tp->pci_dev, tp->Rx_skbuff + i, tp->RxDescArray + i); } }}static u32 rtl8169_rx_fill(struct rtl8169_private *tp, struct net_device *dev, u32 start, u32 end){ u32 cur; for (cur = start; end - cur > 0; cur++) { int ret, i = cur % NUM_RX_DESC; if (tp->Rx_skbuff[i]) continue; ret = rtl8169_alloc_rx_skb(tp->pci_dev, dev, tp->Rx_skbuff + i, tp->RxDescArray + i); if (ret < 0) break; } return cur - start;}static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc){ desc->status |= cpu_to_le32(EORbit);}static int rtl8169_init_ring(struct net_device *dev){ struct rtl8169_private *tp = netdev_priv(dev); tp->cur_rx = tp->dirty_rx = 0; tp->cur_tx = tp->dirty_tx = 0; memset(tp->TxDescArray, 0x0, NUM_TX_DESC * sizeof (struct TxDesc)); memset(tp->RxDescArray, 0x0, NUM_RX_DESC * sizeof (struct RxDesc)); memset(tp->Tx_skbuff, 0x0, NUM_TX_DESC * sizeof(struct sk_buff *)); memset(tp->Rx_skbuff, 0x0, NUM_RX_DESC * sizeof(struct sk_buff *)); if (rtl8169_rx_fill(tp, dev, 0, NUM_RX_DESC) != NUM_RX_DESC) goto err_out; rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1); return 0;err_out: rtl8169_rx_clear(tp); return -ENOMEM;}static void rtl8169_unmap_tx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff, struct TxDesc *desc){ u32 len = sk_buff[0]->len; pci_unmap_single(pdev, le64_to_cpu(desc->addr), len < ETH_ZLEN ? ETH_ZLEN : len, PCI_DMA_TODEVICE); desc->addr = 0x00; *sk_buff = NULL;}static voidrtl8169_tx_clear(struct rtl8169_private *tp)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -