GIT 50a645a4f245d9e63669860b6dc19200d40055cd git://electric-eye.fr.zoreil.com/home/romieu/linux-2.6.git#r8169 commit Author: Francois Romieu Date: Sun Aug 26 16:57:23 2007 +0200 r8169: micro bloatectomy Signed-off-by: Francois Romieu Cc: Edward Hsu commit 47ed30850319f54747ac32774eebfc9b30206aed Author: Francois Romieu Date: Sun Aug 26 16:51:52 2007 +0200 r8169: balance rtl_phy_power_up Realtek's current r8xxx driver contain some code to power the phy down but it is not used. Apply it to the whole 816x family and see if it hurts. Signed-off-by: Francois Romieu Cc: Edward Hsu commit 03875470b27760e837a6548c6d6378fb3fca46ab Author: Francois Romieu Date: Sun Aug 26 16:18:51 2007 +0200 r8169: tweak hardware reset rtl8169_hw_reset is synced with Realtek's driver (r8168 version 8.002.00). The wait loop is applied to the whole 816x family even if it does not appear in Realtek's r8169 (version 6.002.00) and r8101 (version 1.002.00) drivers. It is documented in the registers datasheet of the 8169 anyway. Signed-off-by: Francois Romieu Cc: Edward Hsu commit cea587131e5cf7e9d845cd30b25c669af1033ea7 Author: Francois Romieu Date: Thu Aug 23 12:19:37 2007 +0200 r8169: hardware start changes III/III (8168) The changes have been extracted from Realtek's r8168 driver (version 8.002.00). I have kept some differences: 1. RxMaxSize register is set early, with a larger value 2. MEMMap and IOMAP bits in Config1 are read-only. There is no point in writing them. 3. Turned data16 = RTL_R16(EPHYAR) & ~(1 << 11); data16 = RTL_R16(EPHYAR) | (1 << 12); into: data16 = RTL_R16(EPHYAR) & ~(1 << 11); data16 |= (1 << 12); 4. Turned data16 = RTL_R16(EPHYAR) | (1 << 1); data16 = RTL_R16(EPHYAR) | (1 << 6); into: data16 = RTL_R16(EPHYAR) | (1 << 1); data16 |= (1 << 6); Signed-off-by: Francois Romieu Cc: Edward Hsu commit 4279368b9bb043fcdfc6c602bd3e00ac49853d40 Author: Francois Romieu Date: Thu Aug 23 12:04:17 2007 +0200 r8169: hardware start changes II/III (8168) The changes have been extracted from Realtek's r8168 driver (version 8.002.00). I have kept some differences: 1. RxMaxSize register is set early, with a larger value. 2. MEMMap and IOMAP bits in Config1 are read-only. What is the point in writing them ? Signed-off-by: Francois Romieu Cc: Edward Hsu commit bd127ae4c114f4e127a4ca66029b814fb26f4d63 Author: Francois Romieu Date: Wed Aug 22 16:55:21 2007 +0200 r8169: hardware start changes I/III (8168) A change of behavior could be noticed for a specific flavor of 8168C (see RTL_GIGA_MAC_VER_20). Otherwise, the rework of the code should be unnoticeable. Signed-off-by: Francois Romieu Cc: Edward Hsu commit 8aff551df780279b6738f4660252a16fa0556af3 Author: Francois Romieu Date: Wed Aug 22 16:35:24 2007 +0200 r8169: sync rtl_hw_start_8168 with Realtek's one rtl_hw_start_8168 exhibits several modifications in the version 8.002.00 of Realtek's driver: the ordering of writes to registers is different and new device-specific paths have been added. This patch addresses the part related to the changes of ordering. Some differences between the kernel's and Realtek's drivers are left unchanged: I have kept the MultiIntr and RxMissed registers while Realtek's driver ignores them. Signed-off-by: Francois Romieu Cc: Edward Hsu commit abefbeab97844fba47caa2fc1337ef9f9f6c5633 Author: Francois Romieu Date: Wed Aug 22 16:33:37 2007 +0200 r8169: avoid accessing the RxConfig register outside of rtl_set_rx_mode It is not clear whether writing into the RxConfig register some value that does not include any of the Accept{Broadcast/Multicast/...} bits during the start of the hardware is always safe. Let's use the value attached to the current network device instead. A change of behavior could appear ("fix"/break rtl_set_rx_mode ?). Testing will tell. Signed-off-by: Francois Romieu Cc: Edward Hsu commit b6d8db815a0e2f4fff76bee058ec64925e5a6ca9 Author: Francois Romieu Date: Wed Aug 22 14:47:36 2007 +0200 r8169: factor out a 8168 specific performance tweak This sequence of code is used repeatedly in the hw start code of the new 8168 chips. Factoring it out lowers the noise. Signed-off-by: Francois Romieu Cc: Edward Hsu commit 46a7e445f6e0bac824fbd31ced15a17b3fee4582 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 05bb1e6c9201a8a8f9ef975ee4189c9ab59b5a51 Author: Francois Romieu Date: Fri Aug 17 18:26:35 2007 +0200 r8169: phy init cleanup Signed-off-by: Francois Romieu Cc: Edward Hsu commit 85a854a8bbbc18051a416bbab9a386a572d0cbee Author: Francois Romieu Date: Fri Aug 17 18:21:58 2007 +0200 r8169: phy init for the 8168 The values have been extracted from Realtek's r8168 driver version 8.002.00. Signed-off-by: Francois Romieu Cc: Edward Hsu commit f7a13e5fcde376a9289eda7fb7323b2fa1fb66be 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 Cc: Edward Hsu commit 38e0d070e7af74c2e12df78938de576c5ae8a1ee Author: Francois Romieu Date: Fri Aug 17 15:05:21 2007 +0200 r8169: remove dead wood Signed-off-by: Francois Romieu Cc: Edward Hsu commit dbcecd1cec23572a943a961ad8d263b349514961 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 avoid 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 Cc: Edward Hsu commit 67c4898ca76646c389c6519fa0ebbaf955dbb163 Author: Francois Romieu Date: Wed Jul 4 23:24:55 2007 +0100 r8169: MSI support It is currently limited to the tested 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 426749c69c957826d379ccce8d68925a4c88becb Author: Francois Romieu Date: Sun Aug 26 20:08:19 2007 +0200 r8169: workaround against ignored TxPoll writes (8168) The 8168 ignores the requests to fetch the Tx descriptors when the relevant TxPoll bit is already set. It easily kills the performances of the 8168. David Gundersen has noticed that it is enough to wait for the completion of the DMA transfer (NPQ bit is cleared) before writing the TxPoll register again. The extra IO traffic added by the proposed workaround could be minimalized but it is not a high-priority task. Signed-off-by: Francois Romieu Cc: David Gundersen Cc: Edward Hsu commit 381092bcf0dbef0f450e7fd82605a8a9fdc7fdd3 Author: Edward Hsu Date: Fri Aug 17 10:14:36 2007 +0200 r8169: correct phy parameters for the 8110SC The phys 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 drivers/net/Kconfig | 1 drivers/net/r8169.c | 716 +++++++++++++++++++++++++++++++++--------- include/linux/eeprom_93cx6.h | 4 3 files changed, 563 insertions(+), 158 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index c551925..c88c888 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2121,6 +2121,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 --git a/drivers/net/r8169.c b/drivers/net/r8169.c index b85ab4a..21612f2 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -23,6 +23,7 @@ #include #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 @@ -208,8 +210,6 @@ enum rtl_registers { Config5 = 0x56, MultiIntr = 0x5c, PHYAR = 0x60, - TBICSR = 0x64, - TBI_ANAR = 0x68, TBI_LPAR = 0x6a, PHYstatus = 0x6c, RxMaxSize = 0xda, @@ -224,6 +224,18 @@ enum rtl_registers { FuncForceEvent = 0xfc, }; +enum rtl_registers_8169 { + TBICSR = 0x64, + TBI_ANAR = 0x68 +}; + +enum rtl_registers_8168 { + CSIDR = 0x64, + CSIAR = 0x68, + EPHYAR = 0x80, + DbgReg = 0xd1 +}; + enum rtl_register_content { /* InterruptStatusBits */ SYSErr = 0x8000, @@ -246,6 +258,7 @@ enum rtl_register_content { RxCRC = (1 << 19), /* ChipCmdBits */ + StopReq = 0x80, CmdReset = 0x10, CmdRxEnb = 0x08, CmdTxEnb = 0x04, @@ -256,9 +269,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 +288,23 @@ 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 */ + Leds_1 = (1 << 7), + Leds_0 = (1 << 6), + MSIEnable = (1 << 5), /* Enable Message Signaled Interrupt */ + SpeedDown = (1 << 4), + MemMap = (1 << 3), + IoMap = (1 << 2), + VPD = (1 << 1), PMEnable = (1 << 0), /* Power Management Enable */ /* Config2 register p. 25 */ @@ -286,6 +314,7 @@ enum rtl_register_content { /* Config3 register p.25 */ MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */ LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */ + BeaconEnable = (1 << 0), /* 8168B */ /* Config5 register p.27 */ BWF = (1 << 6), /* Accept Broadcast wakeup frame */ @@ -303,16 +332,29 @@ enum rtl_register_content { TBINwComplete = 0x01000000, /* CPlusCmd p.31 */ + EnableBist = (1 << 15), // 8168 + Macdbgo_oe = (1 << 14), // 8168 + Normal_Mode = (1 << 13), // 8168 + Force_Half_Dup = (1 << 12), // 8168 + Force_RxFlow_En = (1 << 11), // 8168 + Force_TxFlow_En = (1 << 10), // 8168 + Cxpl_Dbg_Sel = (1 << 9), // 8168B + ASF = (1 << 8), // 8168C PktCntrDisable = (1 << 7), // 8168 RxVlan = (1 << 6), RxChkSum = (1 << 5), PCIDAC = (1 << 4), PCIMulRW = (1 << 3), + Macdbgo_Sel = 0x001c, INTT_0 = 0x0000, // 8168 INTT_1 = 0x0001, // 8168 INTT_2 = 0x0002, // 8168 INTT_3 = 0x0003, // 8168 + /* DbgReg */ + Fix_Nak_1 = (1 << 4), + Fix_Nak_2 = (1 << 3), + /* rtl8169_PHYstatus */ TBI_Enable = 0x80, TxFlowCtrl = 0x40, @@ -389,7 +431,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; @@ -418,8 +459,10 @@ #endif 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 "); @@ -647,6 +690,59 @@ 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; + unsigned long flags; + u32 len = ee->len; + u16 reg; + + spin_lock_irqsave(&tp->lock, flags); + + 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_irqrestore(&tp->lock, flags); + + return 0; +} + static int rtl8169_set_speed_tbi(struct net_device *dev, u8 autoneg, u16 speed, u8 duplex) { @@ -673,6 +769,20 @@ static int rtl8169_set_speed_tbi(struct return ret; } +static void rtl_phy_power_up(void __iomem *ioaddr) +{ + /* Vendor specific (0x1f) and reserved (0x0e) MII registers. */ + mdio_write(ioaddr, 0x1f, 0x0000); + mdio_write(ioaddr, 0x0e, 0x0000); +} + +static void rtl_phy_power_down(void __iomem *ioaddr) +{ + mdio_write(ioaddr, 0x1f, 0x0000); + mdio_write(ioaddr, 0x0e, 0x0200); + mdio_write(ioaddr, MII_BMCR, mdio_read(ioaddr, MII_BMCR) | BMCR_PDOWN); +} + static int rtl8169_set_speed_xmii(struct net_device *dev, u8 autoneg, u16 speed, u8 duplex) { @@ -706,7 +816,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; } } @@ -714,7 +825,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", @@ -725,11 +837,7 @@ static int rtl8169_set_speed_xmii(struct auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; - if (tp->mac_version == RTL_GIGA_MAC_VER_12) { - /* Vendor specific (0x1f) and reserved (0x0e) MII registers. */ - mdio_write(ioaddr, 0x1f, 0x0000); - mdio_write(ioaddr, 0x0e, 0x0000); - } + rtl_phy_power_up(ioaddr); tp->phy_auto_nego_reg = auto_nego; tp->phy_1000_ctrl_reg = giga_ctrl; @@ -1054,6 +1162,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, @@ -1101,26 +1211,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) @@ -1128,54 +1263,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] = { { @@ -1208,30 +1310,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++) { @@ -1244,7 +1325,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) @@ -1256,7 +1409,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; @@ -1291,8 +1443,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); @@ -1303,8 +1454,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); @@ -1327,15 +1477,6 @@ static void rtl8169_netpoll(struct net_d } #endif -static 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) { @@ -1356,7 +1497,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); @@ -1385,6 +1526,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; @@ -1451,6 +1649,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, @@ -1458,7 +1657,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, @@ -1466,7 +1666,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, @@ -1474,10 +1675,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) { @@ -1591,10 +1821,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) @@ -1614,6 +1842,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 +1903,8 @@ #endif 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 +1913,7 @@ #endif rc = register_netdev(dev); if (rc < 0) - goto err_out_unmap_5; + goto err_out_msi_5; pci_set_drvdata(pdev, dev); @@ -1705,7 +1936,8 @@ #endif 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); @@ -1722,11 +1954,17 @@ static void __devexit rtl8169_remove_one { struct net_device *dev = pci_get_drvdata(pdev); struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; flush_scheduled_work(); unregister_netdev(dev); - rtl8169_release_board(pdev, dev, tp->mmio_addr); + rtl_phy_power_down(ioaddr); + rtl_disable_msi(pdev, tp); + iounmap(ioaddr); + pci_release_regions(pdev); + pci_disable_device(pdev); + free_netdev(dev); pci_set_drvdata(pdev, NULL); } @@ -1769,8 +2007,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; @@ -1793,25 +2031,36 @@ err_free_tx_0: goto out; } -static void rtl8169_hw_reset(void __iomem *ioaddr) +static void rtl8169_hw_reset(struct rtl8169_private *tp) { + void __iomem *ioaddr = tp->mmio_addr; + unsigned int i; + /* Disable interrupts */ rtl8169_irq_mask_and_ack(ioaddr); - /* Reset the chipset */ + if ((tp->mac_version == RTL_GIGA_MAC_VER_18) || + (tp->mac_version == RTL_GIGA_MAC_VER_19)) { + RTL_W8(ChipCmd, StopReq | CmdRxEnb | CmdTxEnb); + RTL_R8(ChipCmd); + } + RTL_W8(ChipCmd, CmdReset); - /* PCI commit */ - RTL_R8(ChipCmd); + /* The reset can take some time. */ + for (i = 0; i < 1000; i++) { + if (!(RTL_R8(ChipCmd) & CmdReset)) + break; + udelay(100); + } } -static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp) +static void rtl_set_rx_tx_config_registers(struct net_device *dev) { + struct rtl8169_private *tp = netdev_priv(dev); 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); + rtl_set_rx_mode(dev); /* Set DMA burst size and Interframe Gap Time */ RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) | @@ -1915,7 +2164,7 @@ static void rtl_hw_start_8169(struct net rtl_set_rx_max_size(ioaddr); - rtl_set_rx_tx_config_registers(tp); + rtl_set_rx_tx_config_registers(dev); tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW; @@ -1956,12 +2205,137 @@ static void rtl_hw_start_8169(struct net RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); } +static void rtl_tx_performance_tweak_8168(struct pci_dev *pdev) +{ + u8 ctl; + + pci_read_config_byte(pdev, 0x69, &ctl); + ctl = (ctl & ~0x70) | 0x50; + pci_write_config_byte(pdev, 0x69, ctl); +} + +static void __rtl_hw_start_8168c(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + unsigned int i; + u16 data16; + + RTL_W32(CSIDR, 0x27000000); + RTL_W32(CSIAR, 0x8000870c); + + RTL_W8(DbgReg, (0x0e << 4) | Fix_Nak_1 | Fix_Nak_2); + + RTL_W32(EPHYAR, 0x00060000); + for (i = 0; i < 10; i++) { + if (RTL_R32(EPHYAR) & 0x80000000) + break; + udelay(100); + } + data16 = RTL_R16(EPHYAR) & ~(1 << 7); + RTL_W32(EPHYAR, 0x80060000 | data16); + + rtl_tx_performance_tweak_8168(tp->pci_dev); + + RTL_W8(Config1, Leds_1 | Leds_0 | SpeedDown | VPD | PMEnable); + + RTL_W8(Config3, RTL_R8(Config3) & ~BeaconEnable); + + /* Disable clock request. */ + pci_write_config_byte(tp->pci_dev, 0x81, 0x00); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & + ~(EnableBist | Macdbgo_oe | Force_Half_Dup | Force_RxFlow_En | + Force_TxFlow_En | Cxpl_Dbg_Sel | ASF | PktCntrDisable | + Macdbgo_Sel)); +} + +static void __rtl_hw_start_8168cp(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + unsigned int i; + u16 data16; + + RTL_W32(CSIDR, 0x27000000); + RTL_W32(CSIAR, 0x8000870c); + + RTL_W8(DbgReg, 0x23); + + rtl_tx_performance_tweak_8168(tp->pci_dev); + + RTL_W8(Config1, Leds_1 | Leds_0 | SpeedDown | VPD | PMEnable); + + /* Set EPHY register offset 0x01 bit 0 to 1. */ + RTL_W32(EPHYAR, 0x00010000); + for (i = 0; i < 10; i++) { + if (RTL_R32(EPHYAR) & 0x80000000) + break; + udelay(100); + } + data16 = RTL_R16(EPHYAR) | (1 << 0); + RTL_W32(EPHYAR, 0x80010000 | data16); + + /* Set EPHY register offset 0x02 bit 11 to 0 and bit 12 to 1. */ + RTL_W32(EPHYAR, 0x00020000); + for (i = 0; i < 10; i++) { + if (RTL_R32(EPHYAR) & 0x80000000) + break; + udelay(100); + } + data16 = RTL_R16(EPHYAR) & ~(1 << 11); + data16 |= (1 << 12); + RTL_W32(EPHYAR, 0x80020000 | data16); + + /* Set EPHY register offset 0x03 bit 1 to 1 and bit 6 to 1. */ + RTL_W32(EPHYAR, 0x00030000); + for (i = 0; i < 10; i++) { + if (RTL_R32(EPHYAR) & 0x80000000) + break; + udelay(100); + } + data16 = RTL_R16(EPHYAR) | (1 << 1); + data16 = RTL_R16(EPHYAR) | (1 << 6); + RTL_W32(EPHYAR, 0x80030000 | data16); + + /* Set EPHY register offset 0x06 bit 7 to 0. */ + RTL_W32(EPHYAR, 0x00060000); + for (i = 0; i < 10; i++) { + if (RTL_R32(EPHYAR) & 0x80000000) + break; + udelay(100); + } + data16 = RTL_R16(EPHYAR) & ~(1 << 7); + RTL_W32(EPHYAR, 0x80060000 | data16); + + /* Set EPHY register offset 0x07 bit 13 to 1. */ + RTL_W32(EPHYAR, 0x00070000); + for (i = 0; i < 10; i++) { + if (RTL_R32(EPHYAR) & 0x80000000) + break; + udelay(100); + } + data16 = RTL_R16(EPHYAR) | (1 << 13); + RTL_W32(EPHYAR, 0x80070000 | data16); + + RTL_W8(Config3, RTL_R8(Config3) & ~BeaconEnable); + + /* Disable clock request. */ + pci_write_config_byte(tp->pci_dev, 0x81, 0x00); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & + ~(EnableBist | Macdbgo_oe | Force_Half_Dup | Force_RxFlow_En | + Force_TxFlow_En | Cxpl_Dbg_Sel | ASF | PktCntrDisable | + Macdbgo_Sel)); +} + +static void __rtl_hw_start_8168b(struct rtl8169_private *tp) +{ + rtl_tx_performance_tweak_8168(tp->pci_dev); +} + static void rtl_hw_start_8168(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; - struct pci_dev *pdev = tp->pci_dev; - u8 ctl; RTL_W8(Cfg9346, Cfg9346_Unlock); @@ -1969,17 +2343,10 @@ static void rtl_hw_start_8168(struct net rtl_set_rx_max_size(ioaddr); - rtl_set_rx_tx_config_registers(tp); - tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1; RTL_W16(CPlusCmd, tp->cp_cmd); - /* Tx performance tweak. */ - pci_read_config_byte(pdev, 0x69, &ctl); - ctl = (ctl & ~0x70) | 0x50; - pci_write_config_byte(pdev, 0x69, ctl); - RTL_W16(IntrMitigate, 0x5151); /* Work around for RxFIFO overflow. */ @@ -1990,18 +2357,41 @@ static void rtl_hw_start_8168(struct net rtl_set_rx_tx_desc_registers(tp, ioaddr); + rtl_set_rx_tx_config_registers(dev); + + /* FIXME: the hw should already be in a reset, irq acked, state. */ + RTL_W16(IntrStatus, 0xffff); + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_19: + __rtl_hw_start_8168c(tp); + break; + case RTL_GIGA_MAC_VER_18: + __rtl_hw_start_8168cp(tp); + break; + case RTL_GIGA_MAC_VER_11: + case RTL_GIGA_MAC_VER_12: + case RTL_GIGA_MAC_VER_17: + __rtl_hw_start_8168b(tp); + break; + default: + /* + * Realtek's driver does nothing for RTL_GIGA_MAC_VER_20. + * Call me surprized. -- FR + */ + break; + } + RTL_W8(Cfg9346, Cfg9346_Lock); RTL_R8(IntrMask); RTL_W32(RxMissed, 0); - rtl_set_rx_mode(dev); + RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); - RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); - RTL_W16(IntrMask, tp->intr_event); } @@ -2011,7 +2401,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); } @@ -2031,7 +2422,7 @@ static void rtl_hw_start_8101(struct net rtl_set_rx_tx_desc_registers(tp, ioaddr); RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); - rtl_set_rx_tx_config_registers(tp); + rtl_set_rx_tx_config_registers(dev); RTL_W8(Cfg9346, Cfg9346_Lock); @@ -2332,7 +2723,7 @@ static void rtl8169_tx_timeout(struct ne { struct rtl8169_private *tp = netdev_priv(dev); - rtl8169_hw_reset(tp->mmio_addr); + rtl8169_hw_reset(tp); /* Let's wait a bit while any (async) irq lands on */ rtl8169_schedule_work(dev, rtl8169_reset_task); @@ -2521,7 +2912,7 @@ static void rtl8169_pcierr_interrupt(str dev->features &= ~NETIF_F_HIGHDMA; } - rtl8169_hw_reset(ioaddr); + rtl8169_hw_reset(tp); rtl8169_schedule_work(dev, rtl8169_reinit_task); } @@ -2567,6 +2958,15 @@ static void rtl8169_tx_interrupt(struct (TX_BUFFS_AVAIL(tp) >= MAX_SKB_FRAGS)) { netif_wake_queue(dev); } + /* + * 8168 hack: TxPoll requests are lost when the Tx packets are + * too close. Let's kick an extra TxPoll request when a burst + * of start_xmit activity is detected (if it is not detected, + * it is slow enough). -- FR + */ + smp_rmb(); + if (tp->cur_tx != dirty_tx) + RTL_W8(TxPoll, NPQ); } } @@ -2955,7 +3355,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 --git a/include/linux/eeprom_93cx6.h b/include/linux/eeprom_93cx6.h index d774b77..ced7730 100644 --- a/include/linux/eeprom_93cx6.h +++ b/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;