📄 r8169.c
字号:
if (p->media == option) break; } *autoneg = p->autoneg; *speed = p->speed; *duplex = p->duplex;}static void rtl8169_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ struct rtl8169_private *tp = netdev_priv(dev); strcpy(info->driver, RTL8169_DRIVER_NAME); strcpy(info->version, RTL8169_VERSION ); strcpy(info->bus_info, pci_name(tp->pci_dev));}static int rtl8169_set_speed_tbi(struct net_device *dev, u8 autoneg, u16 speed, u8 duplex){ struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; int ret = 0; u32 reg; reg = RTL_R32(TBICSR); if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) && (duplex == DUPLEX_FULL)) { RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart)); } else if (autoneg == AUTONEG_ENABLE) RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart); else { printk(KERN_WARNING PFX "%s: incorrect speed setting refused in TBI mode\n", dev->name); ret = -EOPNOTSUPP; } return ret;}static int rtl8169_set_speed_xmii(struct net_device *dev, u8 autoneg, u16 speed, u8 duplex){ struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; int auto_nego, giga_ctrl; auto_nego = mdio_read(ioaddr, PHY_AUTO_NEGO_REG); auto_nego &= ~(PHY_Cap_10_Half | PHY_Cap_10_Full | PHY_Cap_100_Half | PHY_Cap_100_Full); giga_ctrl = mdio_read(ioaddr, PHY_1000_CTRL_REG); giga_ctrl &= ~(PHY_Cap_1000_Full | PHY_Cap_Null); if (autoneg == AUTONEG_ENABLE) { auto_nego |= (PHY_Cap_10_Half | PHY_Cap_10_Full | PHY_Cap_100_Half | PHY_Cap_100_Full); giga_ctrl |= PHY_Cap_1000_Full; } else { if (speed == SPEED_10) auto_nego |= PHY_Cap_10_Half | PHY_Cap_10_Full; else if (speed == SPEED_100) auto_nego |= PHY_Cap_100_Half | PHY_Cap_100_Full; else if (speed == SPEED_1000) giga_ctrl |= PHY_Cap_1000_Full; if (duplex == DUPLEX_HALF) auto_nego &= ~(PHY_Cap_10_Full | PHY_Cap_100_Full); } tp->phy_auto_nego_reg = auto_nego; tp->phy_1000_ctrl_reg = giga_ctrl; mdio_write(ioaddr, PHY_AUTO_NEGO_REG, auto_nego); mdio_write(ioaddr, PHY_1000_CTRL_REG, giga_ctrl); mdio_write(ioaddr, PHY_CTRL_REG, PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego); return 0;}static int rtl8169_set_speed(struct net_device *dev, u8 autoneg, u16 speed, u8 duplex){ struct rtl8169_private *tp = netdev_priv(dev); int ret; ret = tp->set_speed(dev, autoneg, speed, duplex); if (netif_running(dev) && (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full)) mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT); return ret;}static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct rtl8169_private *tp = netdev_priv(dev); unsigned long flags; int ret; spin_lock_irqsave(&tp->lock, flags); ret = rtl8169_set_speed(dev, cmd->autoneg, cmd->speed, cmd->duplex); spin_unlock_irqrestore(&tp->lock, flags); return ret;}static void rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd){ struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; u32 status; cmd->supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE; cmd->port = PORT_FIBRE; cmd->transceiver = XCVR_INTERNAL; status = RTL_R32(TBICSR); cmd->advertising = (status & TBINwEnable) ? ADVERTISED_Autoneg : 0; cmd->autoneg = !!(status & TBINwEnable); cmd->speed = SPEED_1000; cmd->duplex = DUPLEX_FULL; /* Always set */}static void rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd){ struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; u8 status; cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_TP; cmd->autoneg = 1; cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg; if (tp->phy_auto_nego_reg & PHY_Cap_10_Half) cmd->advertising |= ADVERTISED_10baseT_Half; if (tp->phy_auto_nego_reg & PHY_Cap_10_Full) cmd->advertising |= ADVERTISED_10baseT_Full; if (tp->phy_auto_nego_reg & PHY_Cap_100_Half) cmd->advertising |= ADVERTISED_100baseT_Half; if (tp->phy_auto_nego_reg & PHY_Cap_100_Full) cmd->advertising |= ADVERTISED_100baseT_Full; if (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full) cmd->advertising |= ADVERTISED_1000baseT_Full; status = RTL_R8(PHYstatus); if (status & _1000bpsF) cmd->speed = SPEED_1000; else if (status & _100bps) cmd->speed = SPEED_100; else if (status & _10bps) cmd->speed = SPEED_10; cmd->duplex = ((status & _1000bpsF) || (status & FullDup)) ? DUPLEX_FULL : DUPLEX_HALF;}static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct rtl8169_private *tp = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&tp->lock, flags); tp->get_settings(dev, cmd); spin_unlock_irqrestore(&tp->lock, flags); return 0;}static struct ethtool_ops rtl8169_ethtool_ops = { .get_drvinfo = rtl8169_get_drvinfo, .get_link = ethtool_op_get_link, .get_settings = rtl8169_get_settings, .set_settings = rtl8169_set_settings,};static void rtl8169_write_gmii_reg_bit(void *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 *ioaddr){ const struct { u32 mask; int mac_version; } mac_info[] = { { 0x1 << 26, RTL_GIGA_MAC_VER_E }, { 0x1 << 23, RTL_GIGA_MAC_VER_D }, { 0x00000000, RTL_GIGA_MAC_VER_B } /* Catch-all */ }, *p = mac_info; u32 reg; reg = RTL_R32(TxConfig) & 0x7c800000; while ((reg & p->mask) != p->mask) p++; tp->mac_version = p->mac_version;}static void rtl8169_print_mac_version(struct rtl8169_private *tp){ struct { int version; char *msg; } mac_print[] = { { RTL_GIGA_MAC_VER_E, "RTL_GIGA_MAC_VER_E" }, { RTL_GIGA_MAC_VER_D, "RTL_GIGA_MAC_VER_D" }, { RTL_GIGA_MAC_VER_B, "RTL_GIGA_MAC_VER_B" }, { 0, NULL } }, *p; for (p = mac_print; p->msg; p++) { if (tp->mac_version == p->version) { dprintk("mac_version == %s (%04d)\n", p->msg, p->version); return; } } dprintk("mac_version == Unknown\n");}static void rtl8169_get_phy_version(struct rtl8169_private *tp, void *ioaddr){ const struct { u16 mask; u16 set; int phy_version; } phy_info[] = { { 0x000f, 0x0002, RTL_GIGA_PHY_VER_G }, { 0x000f, 0x0001, RTL_GIGA_PHY_VER_F }, { 0x000f, 0x0000, RTL_GIGA_PHY_VER_E }, { 0x0000, 0x0000, RTL_GIGA_PHY_VER_D } /* Catch-all */ }, *p = phy_info; u16 reg; reg = mdio_read(ioaddr, 3) & 0xffff; while ((reg & p->mask) != p->set) p++; tp->phy_version = p->phy_version;}static void rtl8169_print_phy_version(struct rtl8169_private *tp){ struct { int version; char *msg; u32 reg; } phy_print[] = { { RTL_GIGA_PHY_VER_G, "RTL_GIGA_PHY_VER_G", 0x0002 }, { RTL_GIGA_PHY_VER_F, "RTL_GIGA_PHY_VER_F", 0x0001 }, { RTL_GIGA_PHY_VER_E, "RTL_GIGA_PHY_VER_E", 0x0000 }, { RTL_GIGA_PHY_VER_D, "RTL_GIGA_PHY_VER_D", 0x0000 }, { 0, NULL, 0x0000 } }, *p; for (p = phy_print; p->msg; p++) { if (tp->phy_version == p->version) { dprintk("phy_version == %s (%04x)\n", p->msg, p->reg); return; } } dprintk("phy_version == Unknown\n");}static void rtl8169_hw_phy_config(struct net_device *dev){ struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; 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; int i; rtl8169_print_mac_version(tp); rtl8169_print_phy_version(tp); if (tp->mac_version <= RTL_GIGA_MAC_VER_B) return; if (tp->phy_version >= RTL_GIGA_PHY_VER_F) return; dprintk("MAC version != 0 && PHY version == 0 or 1\n"); dprintk("Do final_reg2.cfg\n"); /* Shazam ! */ // phy config for RTL8169s mac_version C chip mdio_write(ioaddr, 31, 0x0001); //w 31 2 0 1 mdio_write(ioaddr, 21, 0x1000); //w 21 15 0 1000 mdio_write(ioaddr, 24, 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, 31, 0x0000); //w 31 2 0 0}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 *ioaddr = tp->mmio_addr; unsigned long timeout = RTL8169_PHY_TIMEOUT; assert(tp->mac_version > RTL_GIGA_MAC_VER_B); assert(tp->phy_version < RTL_GIGA_PHY_VER_G); if (!(tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full)) 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; printk(KERN_WARNING PFX "%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_B) || (tp->phy_version >= RTL_GIGA_PHY_VER_G)) 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_B) || (tp->phy_version >= RTL_GIGA_PHY_VER_G)) return; init_timer(timer); timer->expires = jiffies + RTL8169_PHY_TIMEOUT; timer->data = (unsigned long)(dev); timer->function = rtl8169_phy_timer; add_timer(timer);}static int __devinitrtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out, void **ioaddr_out){ void *ioaddr = NULL; struct net_device *dev; struct rtl8169_private *tp; unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; int rc, i, acpi_idle_state = 0, pm_cap; assert(pdev != NULL); assert(ioaddr_out != NULL); *ioaddr_out = NULL; *dev_out = NULL; // dev zeroed in alloc_etherdev dev = alloc_etherdev(sizeof (*tp)); if (dev == NULL) { printk(KERN_ERR PFX "unable to alloc new ethernet\n"); return -ENOMEM; } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); tp = dev->priv; // enable device (incl. PCI PM wakeup and hotplug setup) rc = pci_enable_device(pdev); if (rc) { printk(KERN_ERR PFX "%s: enable failure\n", pdev->slot_name); goto err_out; } /* save power state before pci_enable_device overwrites it */ pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); if (pm_cap) { u16 pwr_command; pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command); acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; } else { printk(KERN_ERR PFX "Cannot find PowerManagement capability, aborting.\n"); goto err_out_free_res; } mmio_start = pci_resource_start(pdev, 1); mmio_end = pci_resource_end(pdev, 1); mmio_flags = pci_resource_flags(pdev, 1); mmio_len = pci_resource_len(pdev, 1); // make sure PCI base addr 1 is MMIO if (!(mmio_flags & IORESOURCE_MEM)) { printk(KERN_ERR PFX "region #1 not an MMIO resource, aborting\n"); rc = -ENODEV; goto err_out_disable; } // check for weird/broken PCI region reporting if (mmio_len < RTL_MIN_IO_SIZE) { printk(KERN_ERR PFX "Invalid PCI region size(s), aborting\n"); rc = -ENODEV; goto err_out_disable; } rc = pci_request_regions(pdev, MODULENAME); if (rc) { printk(KERN_ERR PFX "%s: could not request regions.\n", pdev->slot_name); goto err_out_disable; } tp->cp_cmd = PCIMulRW | RxChkSum; if ((sizeof(dma_addr_t) > 4) && !pci_set_dma_mask(pdev, DMA_64BIT_MASK) && use_dac)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -