GIT cd7ef0a71e3a7d9cf8af0126a0849513aaec26e9 git://electric-eye.fr.zoreil.com/home/romieu/linux-2.6.git#r8169 commit cd7ef0a71e3a7d9cf8af0126a0849513aaec26e9 Author: Francois Romieu Date: Sun May 27 22:20:51 2007 +0200 r8169: eeprom read support No need for literacy. Ugo's API is clear. I have added a size member to the eeprom struct for convenience and filled it according to the National Semiconductor NM93C06/C46/C56/C66 documentation. Signed-off-by: Francois Romieu Cc: Michael Wu Cc: John W. Linville Cc: Edward Hsu commit c9859f8cfee0d92ac53277fc24efbcb609ae2c5d Author: Francois Romieu Date: Fri Aug 17 18:26:35 2007 +0200 r8169: phy init cleanup Signed-off-by: Francois Romieu commit aef02f5fe18e24118c2f0012d43d37edd7e130d4 Author: Francois Romieu Date: Fri Aug 17 18:21:58 2007 +0200 r8169: PHY init for the 8168 Extracted from Realtek's r8168 driver version 8.002.00. Signed-off-by: Francois Romieu commit b3c75d0ca356cfb86cf5dd90284560b9091af75d Author: Francois Romieu Date: Fri Aug 17 17:50:46 2007 +0200 r8169: make room for more PHY init changes The code is reworked to easily add PHY-dependant init changes. No change of behavior should be noticed. Signed-off-by: Francois Romieu commit 8f267e02d76efc369a38cf48fbc3fa991add5401 Author: Francois Romieu Date: Fri Aug 17 15:05:21 2007 +0200 r8169: remove dead wood Signed-off-by: Francois Romieu commit 5ffe984a5f44dd201238285cd90e63ede3142dd0 Author: Francois Romieu Date: Fri Aug 17 14:55:46 2007 +0200 r8169: add MAC identifiers The identifiers have been extracted from Realtek's drivers: - version 8.002.00 of the r8168 driver - version 6.002.00 of the r8169 driver - version 1.002.00 of the r8101 driver 1. RTL_GIGA_MAC_VER_17 (8168Bf) is isolated from RTL_GIGA_MAC_VER_12 (8168Be) Both are still handled the same in rtl8169_set_speed_xmii and in rtl_set_rx_mode to limit the changes of behavior in this patch. 2. RTL_GIGA_MAC_VER_16 (8101Ec) is isolated from RTL_GIGA_MAC_VER_13 (8101Eb) Same thing as above with relation to rtl8169_set_speed_xmii, rtl_set_rx_mode and rtl_hw_start_8101. 3. The remaining new identifiers should not hurt. Signed-off-by: Francois Romieu commit 622ab4c7ef653a231a326d03a80dfe17899107e1 Author: Francois Romieu Date: Wed Jul 4 23:24:55 2007 +0100 r8169: MSI support It is currently limited to 0x8136 and 0x8168. 8169sb/8110sb ought to handle it as well where they support MSI. Signed-off-by: Francois Romieu Cc: Edward Hsu Tester-Cc: Rolf Eike Beer commit 341e696803001c86910f8ef74a5fb4d29f7a7a6f Author: Edward Hsu Date: Fri Aug 17 10:14:36 2007 +0200 r8169: correct phy parameters for the 8110SC The phy of the 8110SC (RTL_GIGA_MAC_VER_{05/06}) act abnormally in gigabit mode if they are applied the parameters in rtl8169_hw_phy_config which actually aim the 8110S/SB. It is ok to return early from rtl8169_hw_phy_config as it does not apply to the 8101 and 8168 families. Signed-off-by: Edward Hsu Signed-off-by: Francois Romieu Signed-off-by: Andrew Morton --- drivers/net/Kconfig | 1 drivers/net/r8169.c | 438 ++++++++++++++++++++++++--------- include/linux/eeprom_93cx6.h | 4 3 files changed, 325 insertions(+), 118 deletions(-) diff -puN drivers/net/Kconfig~git-r8169 drivers/net/Kconfig --- a/drivers/net/Kconfig~git-r8169 +++ a/drivers/net/Kconfig @@ -2130,6 +2130,7 @@ config R8169 tristate "Realtek 8169 gigabit ethernet support" depends on PCI select CRC32 + select EEPROM_93CX6 ---help--- Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter. diff -puN drivers/net/r8169.c~git-r8169 drivers/net/r8169.c --- a/drivers/net/r8169.c~git-r8169 +++ a/drivers/net/r8169.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -111,19 +112,15 @@ enum mac_version { RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb - RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be 8168Bf - RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb 8101Ec - RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 - RTL_GIGA_MAC_VER_15 = 0x0f // 8101 -}; - -enum phy_version { - RTL_GIGA_PHY_VER_C = 0x03, /* PHY Reg 0x03 bit0-3 == 0x0000 */ - RTL_GIGA_PHY_VER_D = 0x04, /* PHY Reg 0x03 bit0-3 == 0x0000 */ - RTL_GIGA_PHY_VER_E = 0x05, /* PHY Reg 0x03 bit0-3 == 0x0000 */ - RTL_GIGA_PHY_VER_F = 0x06, /* PHY Reg 0x03 bit0-3 == 0x0001 */ - RTL_GIGA_PHY_VER_G = 0x07, /* PHY Reg 0x03 bit0-3 == 0x0002 */ - RTL_GIGA_PHY_VER_H = 0x08, /* PHY Reg 0x03 bit0-3 == 0x0003 */ + RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be + RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb + RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ? + RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ? + RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec + RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf + RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP + RTL_GIGA_MAC_VER_19 = 0x13, // 8168C + RTL_GIGA_MAC_VER_20 = 0x14 // 8168C }; #define _R(NAME,MAC,MASK) \ @@ -144,7 +141,12 @@ static const struct { _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E _R("RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139 _R("RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880), // PCI-E 8139 - _R("RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880) // PCI-E 8139 + _R("RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880), // PCI-E 8139 + _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_17, 0xff7e1880), // PCI-E + _R("RTL8101e", RTL_GIGA_MAC_VER_16, 0xff7e1880), // PCI-E + _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, 0xff7e1880), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_19, 0xff7e1880), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_20, 0xff7e1880) // PCI-E }; #undef _R @@ -256,9 +258,16 @@ enum rtl_register_content { NPQ = 0x40, /* Poll cmd on the low prio queue */ FSWInt = 0x01, /* Forced software interrupt */ - /* Cfg9346Bits */ - Cfg9346_Lock = 0x00, + /* Cfg9346 operating mode register p.23 */ Cfg9346_Unlock = 0xc0, + Cfg9346_Prog = 0x80, + Cfg9346_Auto = 0x80, + Cfg9346_Lock = 0x00, + /* Sub-mode bits in Programming or Auto-load mode. */ + Cfg9346_CS = 0x08, /* Chip Select */ + Cfg9346_SK = 0x04, /* Serial Data Clock */ + Cfg9346_DI = 0x02, /* Data In (going into the eeprom) */ + Cfg9346_DO = 0x01, /* Data Out (coming from the eeprom) */ /* rx_mode_bits */ AcceptErr = 0x20, @@ -268,15 +277,17 @@ enum rtl_register_content { AcceptMyPhys = 0x02, AcceptAllPhys = 0x01, - /* RxConfigBits */ + /* RxConfigBits p.21 */ RxCfgFIFOShift = 13, RxCfgDMAShift = 8, + Cfg9356Select = 6, /* TxConfigBits */ TxInterFrameGapShift = 24, TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ /* Config1 register p.24 */ + MSIEnable = (1 << 5), /* Enable Message Signaled Interrupt */ PMEnable = (1 << 0), /* Power Management Enable */ /* Config2 register p. 25 */ @@ -390,7 +401,6 @@ struct rtl8169_private { u32 msg_enable; int chipset; int mac_version; - int phy_version; u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ u32 dirty_rx; @@ -419,8 +429,10 @@ struct rtl8169_private { void (*hw_start)(struct net_device *); unsigned int (*phy_reset_pending)(void __iomem *); unsigned int (*link_ok)(void __iomem *); + struct eeprom_93cx6 eeprom; struct delayed_work task; unsigned wol_enabled : 1; + unsigned msi : 1; }; MODULE_AUTHOR("Realtek and the Linux r8169 crew "); @@ -648,6 +660,58 @@ static int rtl8169_get_regs_len(struct n return R8169_REGS_SIZE; } +static int rtl_get_eeprom_len(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + return tp->eeprom.size; +} + +static void eeprom_cmd_start(void __iomem *ioaddr) +{ + RTL_W8(Cfg9346, Cfg9346_Prog); +} + +static void eeprom_cmd_end(void __iomem *ioaddr) +{ + RTL_W8(Cfg9346, Cfg9346_Lock); +} + +static int rtl_get_eeprom(struct net_device *dev, struct ethtool_eeprom *ee, + u8 *data) +{ + struct rtl8169_private *tp = netdev_priv(dev); + struct eeprom_93cx6 *eeprom = &tp->eeprom; + void __iomem *ioaddr = tp->mmio_addr; + u32 offset = ee->offset; + u32 len = ee->len; + u16 reg; + + spin_lock_irq(&tp->lock); + + eeprom_cmd_start(ioaddr); + + if (offset & 0x1) { + eeprom_93cx6_read(eeprom, offset >> 1, ®); + *data++ = cpu_to_le16(reg) >> 8; + offset++; + len--; + } + + eeprom_93cx6_multiread(eeprom, offset >> 1, (__le16 *)data, len >> 1); + + if (len & 0x1) { + eeprom_93cx6_read(eeprom, (offset >> 1) + (len >> 1) + 1, ®); + data[len] = cpu_to_le16(reg); + } + + eeprom_cmd_end(ioaddr); + + spin_unlock_irq(&tp->lock); + + return 0; +} + static int rtl8169_set_speed_tbi(struct net_device *dev, u8 autoneg, u16 speed, u8 duplex) { @@ -707,7 +771,8 @@ static int rtl8169_set_speed_xmii(struct /* This tweak comes straight from Realtek's driver. */ if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) && - (tp->mac_version == RTL_GIGA_MAC_VER_13)) { + ((tp->mac_version == RTL_GIGA_MAC_VER_13) || + (tp->mac_version == RTL_GIGA_MAC_VER_16))) { auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA; } } @@ -715,7 +780,8 @@ static int rtl8169_set_speed_xmii(struct /* The 8100e/8101e do Fast Ethernet only. */ if ((tp->mac_version == RTL_GIGA_MAC_VER_13) || (tp->mac_version == RTL_GIGA_MAC_VER_14) || - (tp->mac_version == RTL_GIGA_MAC_VER_15)) { + (tp->mac_version == RTL_GIGA_MAC_VER_15) || + (tp->mac_version == RTL_GIGA_MAC_VER_16)) { if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) && netif_msg_link(tp)) { printk(KERN_INFO "%s: PHY does not support 1000Mbps.\n", @@ -726,7 +792,8 @@ static int rtl8169_set_speed_xmii(struct auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; - if (tp->mac_version == RTL_GIGA_MAC_VER_12) { + if ((tp->mac_version == RTL_GIGA_MAC_VER_12) || + (tp->mac_version == RTL_GIGA_MAC_VER_17)) { /* Vendor specific (0x1f) and reserved (0x0e) MII registers. */ mdio_write(ioaddr, 0x1f, 0x0000); mdio_write(ioaddr, 0x0e, 0x0000); @@ -1055,6 +1122,8 @@ static const struct ethtool_ops rtl8169_ .get_drvinfo = rtl8169_get_drvinfo, .get_regs_len = rtl8169_get_regs_len, .get_link = ethtool_op_get_link, + .get_eeprom_len = rtl_get_eeprom_len, + .get_eeprom = rtl_get_eeprom, .get_settings = rtl8169_get_settings, .set_settings = rtl8169_set_settings, .get_msglevel = rtl8169_get_msglevel, @@ -1102,26 +1171,51 @@ static void rtl8169_get_mac_version(stru */ const struct { u32 mask; + u32 val; int mac_version; } mac_info[] = { - { 0x38800000, RTL_GIGA_MAC_VER_15 }, - { 0x38000000, RTL_GIGA_MAC_VER_12 }, - { 0x34000000, RTL_GIGA_MAC_VER_13 }, - { 0x30800000, RTL_GIGA_MAC_VER_14 }, - { 0x30000000, RTL_GIGA_MAC_VER_11 }, - { 0x98000000, RTL_GIGA_MAC_VER_06 }, - { 0x18000000, RTL_GIGA_MAC_VER_05 }, - { 0x10000000, RTL_GIGA_MAC_VER_04 }, - { 0x04000000, RTL_GIGA_MAC_VER_03 }, - { 0x00800000, RTL_GIGA_MAC_VER_02 }, - { 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */ + /* 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) & 0xfc800000; - while ((reg & p->mask) != p->mask) + 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) @@ -1129,54 +1223,21 @@ static void rtl8169_print_mac_version(st dprintk("mac_version = 0x%02x\n", tp->mac_version); } -static void rtl8169_get_phy_version(struct rtl8169_private *tp, - void __iomem *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; +struct phy_reg { u16 reg; + u16 val; +}; - reg = mdio_read(ioaddr, MII_PHYSID2) & 0xffff; - while ((reg & p->mask) != p->set) - p++; - tp->phy_version = p->phy_version; -} - -static void rtl8169_print_phy_version(struct rtl8169_private *tp) +static void rtl_phy_write(void __iomem *ioaddr, struct phy_reg *regs, int len) { - 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; - } + while (len-- > 0) { + mdio_write(ioaddr, regs->reg, regs->val); + regs++; } - dprintk("phy_version == Unknown\n"); } -static void rtl8169_hw_phy_config(struct net_device *dev) +static void rtl8169s_hw_phy_config(void __iomem *ioaddr) { - struct rtl8169_private *tp = netdev_priv(dev); - void __iomem *ioaddr = tp->mmio_addr; struct { u16 regs[5]; /* Beware of bit-sign propagation */ } phy_magic[5] = { { @@ -1209,30 +1270,9 @@ static void rtl8169_hw_phy_config(struct }, *p = phy_magic; unsigned int i; - rtl8169_print_mac_version(tp); - rtl8169_print_phy_version(tp); - - if (tp->mac_version <= RTL_GIGA_MAC_VER_01) - return; - if (tp->phy_version >= RTL_GIGA_PHY_VER_H) - return; - - dprintk("MAC version != 0 && PHY version == 0 or 1\n"); - dprintk("Do final_reg2.cfg\n"); - - /* Shazam ! */ - - if (tp->mac_version == RTL_GIGA_MAC_VER_04) { - mdio_write(ioaddr, 31, 0x0002); - mdio_write(ioaddr, 1, 0x90d0); - mdio_write(ioaddr, 31, 0x0000); - return; - } - - /* 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 + 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++) { @@ -1245,7 +1285,79 @@ static void rtl8169_hw_phy_config(struct 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 + 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, 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 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; + default: + break; + } } static void rtl8169_phy_timer(unsigned long __opaque) @@ -1257,7 +1369,6 @@ static void rtl8169_phy_timer(unsigned l unsigned long timeout = RTL8169_PHY_TIMEOUT; assert(tp->mac_version > RTL_GIGA_MAC_VER_01); - assert(tp->phy_version < RTL_GIGA_PHY_VER_H); if (!(tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL)) return; @@ -1292,8 +1403,7 @@ static inline void rtl8169_delete_timer( struct rtl8169_private *tp = netdev_priv(dev); struct timer_list *timer = &tp->timer; - if ((tp->mac_version <= RTL_GIGA_MAC_VER_01) || - (tp->phy_version >= RTL_GIGA_PHY_VER_H)) + if (tp->mac_version <= RTL_GIGA_MAC_VER_01) return; del_timer_sync(timer); @@ -1304,8 +1414,7 @@ static inline void rtl8169_request_timer struct rtl8169_private *tp = netdev_priv(dev); struct timer_list *timer = &tp->timer; - if ((tp->mac_version <= RTL_GIGA_MAC_VER_01) || - (tp->phy_version >= RTL_GIGA_PHY_VER_H)) + if (tp->mac_version <= RTL_GIGA_MAC_VER_01) return; mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT); @@ -1357,7 +1466,7 @@ static void rtl8169_init_phy(struct net_ { void __iomem *ioaddr = tp->mmio_addr; - rtl8169_hw_phy_config(dev); + rtl_hw_phy_config(dev); dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); RTL_W8(0x82, 0x01); @@ -1386,6 +1495,63 @@ static void rtl8169_init_phy(struct net_ printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name); } +static void rtl_93cx6_register_read(struct eeprom_93cx6 *eeprom) +{ + struct net_device *dev = eeprom->data; + struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + u8 reg; + + reg = RTL_R8(Cfg9346); + + eeprom->reg_data_in = reg & Cfg9346_DI; + eeprom->reg_data_out = reg & Cfg9346_DO; + eeprom->reg_data_clock = reg & Cfg9346_SK; + eeprom->reg_chip_select = reg & Cfg9346_CS; +} + +static void rtl_93cx6_register_write(struct eeprom_93cx6 *eeprom) +{ + struct net_device *dev = eeprom->data; + struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + u8 reg = Cfg9346_Prog; + + if (eeprom->reg_data_in) + reg |= Cfg9346_DI; + if (eeprom->reg_data_out) + reg |= Cfg9346_DO; + if (eeprom->reg_data_clock) + reg |= Cfg9346_SK; + if (eeprom->reg_chip_select) + reg |= Cfg9346_CS; + + RTL_W8(Cfg9346, reg); + /* PCI commit */ + RTL_R8(ChipCmd); + /* This is not a posting bug band-aid: the eeprom wants ~250 ns. */ + ndelay(250); +} + +static void rtl_init_eeprom(struct net_device *dev, struct rtl8169_private *tp) +{ + struct eeprom_93cx6 *eeprom = &tp->eeprom; + void __iomem *ioaddr = tp->mmio_addr; + + eeprom->data = dev; + + eeprom->register_read = rtl_93cx6_register_read; + eeprom->register_write = rtl_93cx6_register_write; + + if (RTL_R32(RxConfig) & Cfg9356Select) { + eeprom->width = PCI_EEPROM_WIDTH_93C56; + eeprom->size = 256; + } else { + eeprom->width = PCI_EEPROM_WIDTH_93C46; + eeprom->size = 128; + } +} + static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr) { void __iomem *ioaddr = tp->mmio_addr; @@ -1452,6 +1618,7 @@ static const struct rtl_cfg_info { unsigned int align; u16 intr_event; u16 napi_event; + unsigned msi : 1; } rtl_cfg_infos [] = { [RTL_CFG_0] = { .hw_start = rtl_hw_start_8169, @@ -1459,7 +1626,8 @@ static const struct rtl_cfg_info { .align = 0, .intr_event = SYSErr | LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, - .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow + .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, + .msi = 0 }, [RTL_CFG_1] = { .hw_start = rtl_hw_start_8168, @@ -1467,7 +1635,8 @@ static const struct rtl_cfg_info { .align = 8, .intr_event = SYSErr | LinkChg | RxOverflow | TxErr | TxOK | RxOK | RxErr, - .napi_event = TxErr | TxOK | RxOK | RxOverflow + .napi_event = TxErr | TxOK | RxOK | RxOverflow, + .msi = 1 }, [RTL_CFG_2] = { .hw_start = rtl_hw_start_8101, @@ -1475,10 +1644,39 @@ static const struct rtl_cfg_info { .align = 8, .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, - .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow + .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, + .msi = 1 } }; +/* Cfg9346_Unlock assumed. */ +static bool rtl_try_msi(struct pci_dev *pdev, void __iomem *ioaddr, + const struct rtl_cfg_info *cfg) +{ + bool msi = false; + 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 = true; + } + } + RTL_W8(Config2, cfg2); + return msi; +} + +static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp) +{ + if (tp->msi) { + pci_disable_msi(pdev); + tp->msi = 0; + } +} + static int __devinit rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1592,10 +1790,8 @@ rtl8169_init_one(struct pci_dev *pdev, c /* 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) @@ -1615,6 +1811,7 @@ rtl8169_init_one(struct pci_dev *pdev, c RTL_W8(Cfg9346, Cfg9346_Unlock); RTL_W8(Config1, RTL_R8(Config1) | PMEnable); RTL_W8(Config5, RTL_R8(Config5) & PMEStatus); + tp->msi = rtl_try_msi(pdev, ioaddr, cfg); RTL_W8(Cfg9346, Cfg9346_Lock); if (RTL_R8(PHYstatus) & TBI_Enable) { @@ -1674,6 +1871,8 @@ rtl8169_init_one(struct pci_dev *pdev, c tp->intr_event = cfg->intr_event; tp->napi_event = cfg->napi_event; + rtl_init_eeprom(dev, tp); + init_timer(&tp->timer); tp->timer.data = (unsigned long) dev; tp->timer.function = rtl8169_phy_timer; @@ -1682,7 +1881,7 @@ rtl8169_init_one(struct pci_dev *pdev, c rc = register_netdev(dev); if (rc < 0) - goto err_out_unmap_5; + goto err_out_msi_5; pci_set_drvdata(pdev, dev); @@ -1705,7 +1904,8 @@ rtl8169_init_one(struct pci_dev *pdev, c out: return rc; -err_out_unmap_5: +err_out_msi_5: + rtl_disable_msi(pdev, tp); iounmap(ioaddr); err_out_free_res_4: pci_release_regions(pdev); @@ -1726,6 +1926,7 @@ static void __devexit rtl8169_remove_one flush_scheduled_work(); unregister_netdev(dev); + rtl_disable_msi(pdev, tp); rtl8169_release_board(pdev, dev, tp->mmio_addr); pci_set_drvdata(pdev, NULL); } @@ -1769,8 +1970,8 @@ static int rtl8169_open(struct net_devic smp_mb(); - retval = request_irq(dev->irq, rtl8169_interrupt, IRQF_SHARED, - dev->name, dev); + retval = request_irq(dev->irq, rtl8169_interrupt, + tp->msi ? 0 : IRQF_SHARED, dev->name, dev); if (retval < 0) goto err_release_ring_2; @@ -2015,7 +2216,8 @@ static void rtl_hw_start_8101(struct net void __iomem *ioaddr = tp->mmio_addr; struct pci_dev *pdev = tp->pci_dev; - if (tp->mac_version == RTL_GIGA_MAC_VER_13) { + if ((tp->mac_version == RTL_GIGA_MAC_VER_13) || + (tp->mac_version == RTL_GIGA_MAC_VER_16)) { pci_write_config_word(pdev, 0x68, 0x00); pci_write_config_word(pdev, 0x69, 0x08); } @@ -2961,7 +3163,9 @@ static void rtl_set_rx_mode(struct net_d (tp->mac_version == RTL_GIGA_MAC_VER_12) || (tp->mac_version == RTL_GIGA_MAC_VER_13) || (tp->mac_version == RTL_GIGA_MAC_VER_14) || - (tp->mac_version == RTL_GIGA_MAC_VER_15)) { + (tp->mac_version == RTL_GIGA_MAC_VER_15) || + (tp->mac_version == RTL_GIGA_MAC_VER_16) || + (tp->mac_version == RTL_GIGA_MAC_VER_17)) { mc_filter[0] = 0xffffffff; mc_filter[1] = 0xffffffff; } diff -puN include/linux/eeprom_93cx6.h~git-r8169 include/linux/eeprom_93cx6.h --- a/include/linux/eeprom_93cx6.h~git-r8169 +++ a/include/linux/eeprom_93cx6.h @@ -21,13 +21,14 @@ /* Module: eeprom_93cx6 Abstract: EEPROM reader datastructures for 93cx6 chipsets. - Supported chipsets: 93c46 & 93c66. + Supported chipsets: 93c46/93c56/93c66. */ /* * EEPROM operation defines. */ #define PCI_EEPROM_WIDTH_93C46 6 +#define PCI_EEPROM_WIDTH_93C56 8 #define PCI_EEPROM_WIDTH_93C66 8 #define PCI_EEPROM_WIDTH_OPCODE 3 #define PCI_EEPROM_WRITE_OPCODE 0x05 @@ -59,6 +60,7 @@ struct eeprom_93cx6 { void (*register_write)(struct eeprom_93cx6 *eeprom); int width; + int size; char reg_data_in; char reg_data_out; _