?? r8169.c
字號:
ASSERT_RTNL(); counters = pci_alloc_consistent(tp->pci_dev, sizeof(*counters), &paddr); if (!counters) return; RTL_W32(CounterAddrHigh, (u64)paddr >> 32); cmd = (u64)paddr & DMA_32BIT_MASK; RTL_W32(CounterAddrLow, cmd); RTL_W32(CounterAddrLow, cmd | CounterDump); while (RTL_R32(CounterAddrLow) & CounterDump) { if (msleep_interruptible(1)) break; } RTL_W32(CounterAddrLow, 0); RTL_W32(CounterAddrHigh, 0); data[0] = le64_to_cpu(counters->tx_packets); data[1] = le64_to_cpu(counters->rx_packets); data[2] = le64_to_cpu(counters->tx_errors); data[3] = le32_to_cpu(counters->rx_errors); data[4] = le16_to_cpu(counters->rx_missed); data[5] = le16_to_cpu(counters->align_errors); data[6] = le32_to_cpu(counters->tx_one_collision); data[7] = le32_to_cpu(counters->tx_multi_collision); data[8] = le64_to_cpu(counters->rx_unicast); data[9] = le64_to_cpu(counters->rx_broadcast); data[10] = le32_to_cpu(counters->rx_multicast); data[11] = le16_to_cpu(counters->tx_aborted); data[12] = le16_to_cpu(counters->tx_underun); pci_free_consistent(tp->pci_dev, sizeof(*counters), counters, paddr);}static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data){ switch(stringset) { case ETH_SS_STATS: memcpy(data, *rtl8169_gstrings, sizeof(rtl8169_gstrings)); break; }}static const struct ethtool_ops rtl8169_ethtool_ops = { .get_drvinfo = rtl8169_get_drvinfo, .get_regs_len = rtl8169_get_regs_len, .get_link = ethtool_op_get_link, .get_settings = rtl8169_get_settings, .set_settings = rtl8169_set_settings, .get_msglevel = rtl8169_get_msglevel, .set_msglevel = rtl8169_set_msglevel, .get_rx_csum = rtl8169_get_rx_csum, .set_rx_csum = rtl8169_set_rx_csum, .set_tx_csum = ethtool_op_set_tx_csum, .set_sg = ethtool_op_set_sg, .set_tso = ethtool_op_set_tso, .get_regs = rtl8169_get_regs, .get_wol = rtl8169_get_wol, .set_wol = rtl8169_set_wol, .get_strings = rtl8169_get_strings, .get_sset_count = rtl8169_get_sset_count, .get_ethtool_stats = rtl8169_get_ethtool_stats,};static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, int bitnum, int bitval){ int val; val = mdio_read(ioaddr, reg); val = (bitval == 1) ? val | (bitval << bitnum) : val & ~(0x0001 << bitnum); mdio_write(ioaddr, reg, val & 0xffff);}static void rtl8169_get_mac_version(struct rtl8169_private *tp, void __iomem *ioaddr){ /* * The driver currently handles the 8168Bf and the 8168Be identically * but they can be identified more specifically through the test below * if needed: * * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be * * Same thing for the 8101Eb and the 8101Ec: * * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec */ const struct { u32 mask; u32 val; int mac_version; } mac_info[] = { /* 8168B family. */ { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_18 }, { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 }, { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 }, { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_20 }, /* 8168B family. */ { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 }, { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 }, { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 }, { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 }, /* 8101 family. */ { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 }, { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 }, { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 }, /* FIXME: where did these entries come from ? -- FR */ { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 }, { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 }, /* 8110 family. */ { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 }, { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 }, { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 }, { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 }, { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 }, { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 }, { 0x00000000, 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */ }, *p = mac_info; u32 reg; reg = RTL_R32(TxConfig); while ((reg & p->mask) != p->val) p++; tp->mac_version = p->mac_version; if (p->mask == 0x00000000) { struct pci_dev *pdev = tp->pci_dev; dev_info(&pdev->dev, "unknown MAC (%08x)\n", reg); }}static void rtl8169_print_mac_version(struct rtl8169_private *tp){ dprintk("mac_version = 0x%02x\n", tp->mac_version);}struct phy_reg { u16 reg; u16 val;};static void rtl_phy_write(void __iomem *ioaddr, struct phy_reg *regs, int len){ while (len-- > 0) { mdio_write(ioaddr, regs->reg, regs->val); regs++; }}static void rtl8169s_hw_phy_config(void __iomem *ioaddr){ struct { u16 regs[5]; /* Beware of bit-sign propagation */ } phy_magic[5] = { { { 0x0000, //w 4 15 12 0 0x00a1, //w 3 15 0 00a1 0x0008, //w 2 15 0 0008 0x1020, //w 1 15 0 1020 0x1000 } },{ //w 0 15 0 1000 { 0x7000, //w 4 15 12 7 0xff41, //w 3 15 0 ff41 0xde60, //w 2 15 0 de60 0x0140, //w 1 15 0 0140 0x0077 } },{ //w 0 15 0 0077 { 0xa000, //w 4 15 12 a 0xdf01, //w 3 15 0 df01 0xdf20, //w 2 15 0 df20 0xff95, //w 1 15 0 ff95 0xfa00 } },{ //w 0 15 0 fa00 { 0xb000, //w 4 15 12 b 0xff41, //w 3 15 0 ff41 0xde20, //w 2 15 0 de20 0x0140, //w 1 15 0 0140 0x00bb } },{ //w 0 15 0 00bb { 0xf000, //w 4 15 12 f 0xdf01, //w 3 15 0 df01 0xdf20, //w 2 15 0 df20 0xff95, //w 1 15 0 ff95 0xbf00 } //w 0 15 0 bf00 } }, *p = phy_magic; unsigned int i; mdio_write(ioaddr, 0x1f, 0x0001); //w 31 2 0 1 mdio_write(ioaddr, 0x15, 0x1000); //w 21 15 0 1000 mdio_write(ioaddr, 0x18, 0x65c7); //w 24 15 0 65c7 rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) { int val, pos = 4; val = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff); mdio_write(ioaddr, pos, val); while (--pos >= 0) mdio_write(ioaddr, pos, p->regs[4 - pos] & 0xffff); rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1 rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 } mdio_write(ioaddr, 0x1f, 0x0000); //w 31 2 0 0}static void rtl8169sb_hw_phy_config(void __iomem *ioaddr){ struct phy_reg phy_reg_init[] = { { 0x1f, 0x0002 }, { 0x01, 0x90d0 }, { 0x1f, 0x0000 } }; rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));}static void rtl8168cp_hw_phy_config(void __iomem *ioaddr){ struct phy_reg phy_reg_init[] = { { 0x1f, 0x0000 }, { 0x1d, 0x0f00 }, { 0x1f, 0x0002 }, { 0x0c, 0x1ec8 }, { 0x1f, 0x0000 } }; rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));}static void rtl8168c_hw_phy_config(void __iomem *ioaddr){ struct phy_reg phy_reg_init[] = { { 0x1f, 0x0001 }, { 0x12, 0x2300 }, { 0x1f, 0x0002 }, { 0x00, 0x88d4 }, { 0x01, 0x82b1 }, { 0x03, 0x7002 }, { 0x08, 0x9e30 }, { 0x09, 0x01f0 }, { 0x0a, 0x5500 }, { 0x0c, 0x00c8 }, { 0x1f, 0x0003 }, { 0x12, 0xc096 }, { 0x16, 0x000a }, { 0x1f, 0x0000 } }; rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));}static void rtl8168cx_hw_phy_config(void __iomem *ioaddr){ struct phy_reg phy_reg_init[] = { { 0x1f, 0x0000 }, { 0x12, 0x2300 }, { 0x1f, 0x0003 }, { 0x16, 0x0f0a }, { 0x1f, 0x0000 }, { 0x1f, 0x0002 }, { 0x0c, 0x7eb8 }, { 0x1f, 0x0000 } }; rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));}static void rtl_hw_phy_config(struct net_device *dev){ struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; rtl8169_print_mac_version(tp); switch (tp->mac_version) { case RTL_GIGA_MAC_VER_01: break; case RTL_GIGA_MAC_VER_02: case RTL_GIGA_MAC_VER_03: rtl8169s_hw_phy_config(ioaddr); break; case RTL_GIGA_MAC_VER_04: rtl8169sb_hw_phy_config(ioaddr); break; case RTL_GIGA_MAC_VER_18: rtl8168cp_hw_phy_config(ioaddr); break; case RTL_GIGA_MAC_VER_19: rtl8168c_hw_phy_config(ioaddr); break; case RTL_GIGA_MAC_VER_20: rtl8168cx_hw_phy_config(ioaddr); break; default: break; }}static void rtl8169_phy_timer(unsigned long __opaque){ struct net_device *dev = (struct net_device *)__opaque; struct rtl8169_private *tp = netdev_priv(dev); struct timer_list *timer = &tp->timer; void __iomem *ioaddr = tp->mmio_addr; unsigned long timeout = RTL8169_PHY_TIMEOUT; assert(tp->mac_version > RTL_GIGA_MAC_VER_01); if (!(tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL)) return; spin_lock_irq(&tp->lock); if (tp->phy_reset_pending(ioaddr)) { /* * A busy loop could burn quite a few cycles on nowadays CPU. * Let's delay the execution of the timer for a few ticks. */ timeout = HZ/10; goto out_mod_timer; } if (tp->link_ok(ioaddr)) goto out_unlock; if (netif_msg_link(tp)) printk(KERN_WARNING "%s: PHY reset until link up\n", dev->name); tp->phy_reset_enable(ioaddr);out_mod_timer: mod_timer(timer, jiffies + timeout);out_unlock: spin_unlock_irq(&tp->lock);}static inline void rtl8169_delete_timer(struct net_device *dev){ struct rtl8169_private *tp = netdev_priv(dev); struct timer_list *timer = &tp->timer; if (tp->mac_version <= RTL_GIGA_MAC_VER_01) return; del_timer_sync(timer);}static inline void rtl8169_request_timer(struct net_device *dev){ struct rtl8169_private *tp = netdev_priv(dev); struct timer_list *timer = &tp->timer; if (tp->mac_version <= RTL_GIGA_MAC_VER_01) return; mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT);}#ifdef CONFIG_NET_POLL_CONTROLLER/* * Polling 'interrupt' - used by things like netconsole to send skbs * without having to re-enable interrupts. It's not called while * the interrupt routine is executing. */static void rtl8169_netpoll(struct net_device *dev){ struct rtl8169_private *tp = netdev_priv(dev); struct pci_dev *pdev = tp->pci_dev; disable_irq(pdev->irq); rtl8169_interrupt(pdev->irq, dev); enable_irq(pdev->irq);}#endifstatic void rtl8169_release_board(struct pci_dev *pdev, struct net_device *dev, void __iomem *ioaddr){ iounmap(ioaddr); pci_release_regions(pdev); pci_disable_device(pdev); free_netdev(dev);}static void rtl8169_phy_reset(struct net_device *dev, struct rtl8169_private *tp){ void __iomem *ioaddr = tp->mmio_addr; unsigned int i; tp->phy_reset_enable(ioaddr); for (i = 0; i < 100; i++) { if (!tp->phy_reset_pending(ioaddr)) return; msleep(1); } if (netif_msg_link(tp)) printk(KERN_ERR "%s: PHY reset failed.\n", dev->name);}static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp){ void __iomem *ioaddr = tp->mmio_addr; rtl_hw_phy_config(dev); dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); RTL_W8(0x82, 0x01); pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40); if (tp->mac_version <= RTL_GIGA_MAC_VER_06) pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08); if (tp->mac_version == RTL_GIGA_MAC_VER_02) { 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_phy_reset(dev, tp); /* * rtl8169_set_speed_xmii takes good care of the Fast Ethernet * only 8101. Don't panic. */ rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL); if ((RTL_R8(PHYstatus) & TBI_Enable) && netif_msg_link(tp)) printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name);}static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr){ void __iomem *ioaddr = tp->mmio_addr; u32 high; u32 low; low = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24); high = addr[4] | (addr[5] << 8); spin_lock_irq(&tp->lock); RTL_W8(Cfg9346, Cfg9346_Unlock); RTL_W32(MAC0, low); RTL_W32(MAC4, high); RTL_W8(Cfg9346, Cfg9346_Lock); spin_unlock_irq(&tp->lock);}static int rtl_set_mac_address(struct net_device *dev, void *p){ struct rtl8169_private *tp = netdev_priv(dev); struct sockaddr *addr = p; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); rtl_rar_set(tp, dev->dev_addr); return 0;}static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ struct rtl8169_private *tp = netdev_priv(dev); struct mii_ioctl_data *data = if_mii(ifr); if (!netif_running(dev)) return -ENODEV; switch (cmd) { case SIOCGMIIPHY: data->phy_id = 32; /* Internal PHY */ return 0; case SIOCGMIIREG: data->val_out = mdio_read(tp->mmio_addr, data->reg_num & 0x1f); return 0; case SIOCSMIIREG: if (!capable(CAP_NET_ADMIN)) return -EPERM; mdio_write(tp->mmio_addr, data->reg_num & 0x1f, data->val_in); return 0; } return -EOPNOTSUPP;}static const struct rtl_cfg_info { void (*hw_start)(struct net_device *); unsigned int region; unsigned int align; u16 intr_event; u16 napi_event; unsigned msi;} rtl_cfg_infos [] = { [RTL_CFG_0] = { .hw_start = rtl_hw_start_8169, .region = 1, .align = 0, .intr_event = SYSErr | LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -