diff options
Diffstat (limited to 'drivers/net/r8169.c')
-rw-r--r-- | drivers/net/r8169.c | 207 |
1 files changed, 170 insertions, 37 deletions
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 2c73ca606b35..b3473401c83a 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c | |||
@@ -81,9 +81,9 @@ static const int multicast_filter_limit = 32; | |||
81 | #define RTL8169_TX_TIMEOUT (6*HZ) | 81 | #define RTL8169_TX_TIMEOUT (6*HZ) |
82 | #define RTL8169_PHY_TIMEOUT (10*HZ) | 82 | #define RTL8169_PHY_TIMEOUT (10*HZ) |
83 | 83 | ||
84 | #define RTL_EEPROM_SIG cpu_to_le32(0x8129) | 84 | #define RTL_EEPROM_SIG 0x8129 |
85 | #define RTL_EEPROM_SIG_MASK cpu_to_le32(0xffff) | ||
86 | #define RTL_EEPROM_SIG_ADDR 0x0000 | 85 | #define RTL_EEPROM_SIG_ADDR 0x0000 |
86 | #define RTL_EEPROM_MAC_ADDR 0x0007 | ||
87 | 87 | ||
88 | /* write/read MMIO register */ | 88 | /* write/read MMIO register */ |
89 | #define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) | 89 | #define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) |
@@ -293,6 +293,11 @@ enum rtl_register_content { | |||
293 | /* Cfg9346Bits */ | 293 | /* Cfg9346Bits */ |
294 | Cfg9346_Lock = 0x00, | 294 | Cfg9346_Lock = 0x00, |
295 | Cfg9346_Unlock = 0xc0, | 295 | Cfg9346_Unlock = 0xc0, |
296 | Cfg9346_Program = 0x80, /* Programming mode */ | ||
297 | Cfg9346_EECS = 0x08, /* Chip select */ | ||
298 | Cfg9346_EESK = 0x04, /* Serial data clock */ | ||
299 | Cfg9346_EEDI = 0x02, /* Data input */ | ||
300 | Cfg9346_EEDO = 0x01, /* Data output */ | ||
296 | 301 | ||
297 | /* rx_mode_bits */ | 302 | /* rx_mode_bits */ |
298 | AcceptErr = 0x20, | 303 | AcceptErr = 0x20, |
@@ -305,6 +310,7 @@ enum rtl_register_content { | |||
305 | /* RxConfigBits */ | 310 | /* RxConfigBits */ |
306 | RxCfgFIFOShift = 13, | 311 | RxCfgFIFOShift = 13, |
307 | RxCfgDMAShift = 8, | 312 | RxCfgDMAShift = 8, |
313 | RxCfg9356SEL = 6, /* EEPROM type: 0 = 9346, 1 = 9356 */ | ||
308 | 314 | ||
309 | /* TxConfigBits */ | 315 | /* TxConfigBits */ |
310 | TxInterFrameGapShift = 24, | 316 | TxInterFrameGapShift = 24, |
@@ -437,6 +443,22 @@ enum features { | |||
437 | RTL_FEATURE_GMII = (1 << 2), | 443 | RTL_FEATURE_GMII = (1 << 2), |
438 | }; | 444 | }; |
439 | 445 | ||
446 | struct rtl8169_counters { | ||
447 | __le64 tx_packets; | ||
448 | __le64 rx_packets; | ||
449 | __le64 tx_errors; | ||
450 | __le32 rx_errors; | ||
451 | __le16 rx_missed; | ||
452 | __le16 align_errors; | ||
453 | __le32 tx_one_collision; | ||
454 | __le32 tx_multi_collision; | ||
455 | __le64 rx_unicast; | ||
456 | __le64 rx_broadcast; | ||
457 | __le32 rx_multicast; | ||
458 | __le16 tx_aborted; | ||
459 | __le16 tx_underun; | ||
460 | }; | ||
461 | |||
440 | struct rtl8169_private { | 462 | struct rtl8169_private { |
441 | void __iomem *mmio_addr; /* memory map physical address */ | 463 | void __iomem *mmio_addr; /* memory map physical address */ |
442 | struct pci_dev *pci_dev; /* Index of PCI device */ | 464 | struct pci_dev *pci_dev; /* Index of PCI device */ |
@@ -480,6 +502,7 @@ struct rtl8169_private { | |||
480 | unsigned features; | 502 | unsigned features; |
481 | 503 | ||
482 | struct mii_if_info mii; | 504 | struct mii_if_info mii; |
505 | struct rtl8169_counters counters; | ||
483 | }; | 506 | }; |
484 | 507 | ||
485 | MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>"); | 508 | MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>"); |
@@ -1100,22 +1123,6 @@ static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = { | |||
1100 | "tx_underrun", | 1123 | "tx_underrun", |
1101 | }; | 1124 | }; |
1102 | 1125 | ||
1103 | struct rtl8169_counters { | ||
1104 | __le64 tx_packets; | ||
1105 | __le64 rx_packets; | ||
1106 | __le64 tx_errors; | ||
1107 | __le32 rx_errors; | ||
1108 | __le16 rx_missed; | ||
1109 | __le16 align_errors; | ||
1110 | __le32 tx_one_collision; | ||
1111 | __le32 tx_multi_collision; | ||
1112 | __le64 rx_unicast; | ||
1113 | __le64 rx_broadcast; | ||
1114 | __le32 rx_multicast; | ||
1115 | __le16 tx_aborted; | ||
1116 | __le16 tx_underun; | ||
1117 | }; | ||
1118 | |||
1119 | static int rtl8169_get_sset_count(struct net_device *dev, int sset) | 1126 | static int rtl8169_get_sset_count(struct net_device *dev, int sset) |
1120 | { | 1127 | { |
1121 | switch (sset) { | 1128 | switch (sset) { |
@@ -1126,16 +1133,21 @@ static int rtl8169_get_sset_count(struct net_device *dev, int sset) | |||
1126 | } | 1133 | } |
1127 | } | 1134 | } |
1128 | 1135 | ||
1129 | static void rtl8169_get_ethtool_stats(struct net_device *dev, | 1136 | static void rtl8169_update_counters(struct net_device *dev) |
1130 | struct ethtool_stats *stats, u64 *data) | ||
1131 | { | 1137 | { |
1132 | struct rtl8169_private *tp = netdev_priv(dev); | 1138 | struct rtl8169_private *tp = netdev_priv(dev); |
1133 | void __iomem *ioaddr = tp->mmio_addr; | 1139 | void __iomem *ioaddr = tp->mmio_addr; |
1134 | struct rtl8169_counters *counters; | 1140 | struct rtl8169_counters *counters; |
1135 | dma_addr_t paddr; | 1141 | dma_addr_t paddr; |
1136 | u32 cmd; | 1142 | u32 cmd; |
1143 | int wait = 1000; | ||
1137 | 1144 | ||
1138 | ASSERT_RTNL(); | 1145 | /* |
1146 | * Some chips are unable to dump tally counters when the receiver | ||
1147 | * is disabled. | ||
1148 | */ | ||
1149 | if ((RTL_R8(ChipCmd) & CmdRxEnb) == 0) | ||
1150 | return; | ||
1139 | 1151 | ||
1140 | counters = pci_alloc_consistent(tp->pci_dev, sizeof(*counters), &paddr); | 1152 | counters = pci_alloc_consistent(tp->pci_dev, sizeof(*counters), &paddr); |
1141 | if (!counters) | 1153 | if (!counters) |
@@ -1146,31 +1158,45 @@ static void rtl8169_get_ethtool_stats(struct net_device *dev, | |||
1146 | RTL_W32(CounterAddrLow, cmd); | 1158 | RTL_W32(CounterAddrLow, cmd); |
1147 | RTL_W32(CounterAddrLow, cmd | CounterDump); | 1159 | RTL_W32(CounterAddrLow, cmd | CounterDump); |
1148 | 1160 | ||
1149 | while (RTL_R32(CounterAddrLow) & CounterDump) { | 1161 | while (wait--) { |
1150 | if (msleep_interruptible(1)) | 1162 | if ((RTL_R32(CounterAddrLow) & CounterDump) == 0) { |
1163 | /* copy updated counters */ | ||
1164 | memcpy(&tp->counters, counters, sizeof(*counters)); | ||
1151 | break; | 1165 | break; |
1166 | } | ||
1167 | udelay(10); | ||
1152 | } | 1168 | } |
1153 | 1169 | ||
1154 | RTL_W32(CounterAddrLow, 0); | 1170 | RTL_W32(CounterAddrLow, 0); |
1155 | RTL_W32(CounterAddrHigh, 0); | 1171 | RTL_W32(CounterAddrHigh, 0); |
1156 | 1172 | ||
1157 | data[0] = le64_to_cpu(counters->tx_packets); | ||
1158 | data[1] = le64_to_cpu(counters->rx_packets); | ||
1159 | data[2] = le64_to_cpu(counters->tx_errors); | ||
1160 | data[3] = le32_to_cpu(counters->rx_errors); | ||
1161 | data[4] = le16_to_cpu(counters->rx_missed); | ||
1162 | data[5] = le16_to_cpu(counters->align_errors); | ||
1163 | data[6] = le32_to_cpu(counters->tx_one_collision); | ||
1164 | data[7] = le32_to_cpu(counters->tx_multi_collision); | ||
1165 | data[8] = le64_to_cpu(counters->rx_unicast); | ||
1166 | data[9] = le64_to_cpu(counters->rx_broadcast); | ||
1167 | data[10] = le32_to_cpu(counters->rx_multicast); | ||
1168 | data[11] = le16_to_cpu(counters->tx_aborted); | ||
1169 | data[12] = le16_to_cpu(counters->tx_underun); | ||
1170 | |||
1171 | pci_free_consistent(tp->pci_dev, sizeof(*counters), counters, paddr); | 1173 | pci_free_consistent(tp->pci_dev, sizeof(*counters), counters, paddr); |
1172 | } | 1174 | } |
1173 | 1175 | ||
1176 | static void rtl8169_get_ethtool_stats(struct net_device *dev, | ||
1177 | struct ethtool_stats *stats, u64 *data) | ||
1178 | { | ||
1179 | struct rtl8169_private *tp = netdev_priv(dev); | ||
1180 | |||
1181 | ASSERT_RTNL(); | ||
1182 | |||
1183 | rtl8169_update_counters(dev); | ||
1184 | |||
1185 | data[0] = le64_to_cpu(tp->counters.tx_packets); | ||
1186 | data[1] = le64_to_cpu(tp->counters.rx_packets); | ||
1187 | data[2] = le64_to_cpu(tp->counters.tx_errors); | ||
1188 | data[3] = le32_to_cpu(tp->counters.rx_errors); | ||
1189 | data[4] = le16_to_cpu(tp->counters.rx_missed); | ||
1190 | data[5] = le16_to_cpu(tp->counters.align_errors); | ||
1191 | data[6] = le32_to_cpu(tp->counters.tx_one_collision); | ||
1192 | data[7] = le32_to_cpu(tp->counters.tx_multi_collision); | ||
1193 | data[8] = le64_to_cpu(tp->counters.rx_unicast); | ||
1194 | data[9] = le64_to_cpu(tp->counters.rx_broadcast); | ||
1195 | data[10] = le32_to_cpu(tp->counters.rx_multicast); | ||
1196 | data[11] = le16_to_cpu(tp->counters.tx_aborted); | ||
1197 | data[12] = le16_to_cpu(tp->counters.tx_underun); | ||
1198 | } | ||
1199 | |||
1174 | static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data) | 1200 | static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data) |
1175 | { | 1201 | { |
1176 | switch(stringset) { | 1202 | switch(stringset) { |
@@ -1943,6 +1969,108 @@ static const struct net_device_ops rtl8169_netdev_ops = { | |||
1943 | 1969 | ||
1944 | }; | 1970 | }; |
1945 | 1971 | ||
1972 | /* Delay between EEPROM clock transitions. Force out buffered PCI writes. */ | ||
1973 | #define RTL_EEPROM_DELAY() RTL_R8(Cfg9346) | ||
1974 | #define RTL_EEPROM_READ_CMD 6 | ||
1975 | |||
1976 | /* read 16bit word stored in EEPROM. EEPROM is addressed by words. */ | ||
1977 | static u16 rtl_eeprom_read(void __iomem *ioaddr, int addr) | ||
1978 | { | ||
1979 | u16 result = 0; | ||
1980 | int cmd, cmd_len, i; | ||
1981 | |||
1982 | /* check for EEPROM address size (in bits) */ | ||
1983 | if (RTL_R32(RxConfig) & (1 << RxCfg9356SEL)) { | ||
1984 | /* EEPROM is 93C56 */ | ||
1985 | cmd_len = 3 + 8; /* 3 bits for command id and 8 for address */ | ||
1986 | cmd = (RTL_EEPROM_READ_CMD << 8) | (addr & 0xff); | ||
1987 | } else { | ||
1988 | /* EEPROM is 93C46 */ | ||
1989 | cmd_len = 3 + 6; /* 3 bits for command id and 6 for address */ | ||
1990 | cmd = (RTL_EEPROM_READ_CMD << 6) | (addr & 0x3f); | ||
1991 | } | ||
1992 | |||
1993 | /* enter programming mode */ | ||
1994 | RTL_W8(Cfg9346, Cfg9346_Program | Cfg9346_EECS); | ||
1995 | RTL_EEPROM_DELAY(); | ||
1996 | |||
1997 | /* write command and requested address */ | ||
1998 | while (cmd_len--) { | ||
1999 | u8 x = Cfg9346_Program | Cfg9346_EECS; | ||
2000 | |||
2001 | x |= (cmd & (1 << cmd_len)) ? Cfg9346_EEDI : 0; | ||
2002 | |||
2003 | /* write a bit */ | ||
2004 | RTL_W8(Cfg9346, x); | ||
2005 | RTL_EEPROM_DELAY(); | ||
2006 | |||
2007 | /* raise clock */ | ||
2008 | RTL_W8(Cfg9346, x | Cfg9346_EESK); | ||
2009 | RTL_EEPROM_DELAY(); | ||
2010 | } | ||
2011 | |||
2012 | /* lower clock */ | ||
2013 | RTL_W8(Cfg9346, Cfg9346_Program | Cfg9346_EECS); | ||
2014 | RTL_EEPROM_DELAY(); | ||
2015 | |||
2016 | /* read back 16bit value */ | ||
2017 | for (i = 16; i > 0; i--) { | ||
2018 | /* raise clock */ | ||
2019 | RTL_W8(Cfg9346, Cfg9346_Program | Cfg9346_EECS | Cfg9346_EESK); | ||
2020 | RTL_EEPROM_DELAY(); | ||
2021 | |||
2022 | result <<= 1; | ||
2023 | result |= (RTL_R8(Cfg9346) & Cfg9346_EEDO) ? 1 : 0; | ||
2024 | |||
2025 | /* lower clock */ | ||
2026 | RTL_W8(Cfg9346, Cfg9346_Program | Cfg9346_EECS); | ||
2027 | RTL_EEPROM_DELAY(); | ||
2028 | } | ||
2029 | |||
2030 | RTL_W8(Cfg9346, Cfg9346_Program); | ||
2031 | /* leave programming mode */ | ||
2032 | RTL_W8(Cfg9346, Cfg9346_Lock); | ||
2033 | |||
2034 | return result; | ||
2035 | } | ||
2036 | |||
2037 | static void rtl_init_mac_address(struct rtl8169_private *tp, | ||
2038 | void __iomem *ioaddr) | ||
2039 | { | ||
2040 | struct pci_dev *pdev = tp->pci_dev; | ||
2041 | u16 x; | ||
2042 | u8 mac[8]; | ||
2043 | |||
2044 | /* read EEPROM signature */ | ||
2045 | x = rtl_eeprom_read(ioaddr, RTL_EEPROM_SIG_ADDR); | ||
2046 | |||
2047 | if (x != RTL_EEPROM_SIG) { | ||
2048 | dev_info(&pdev->dev, "Missing EEPROM signature: %04x\n", x); | ||
2049 | return; | ||
2050 | } | ||
2051 | |||
2052 | /* read MAC address */ | ||
2053 | x = rtl_eeprom_read(ioaddr, RTL_EEPROM_MAC_ADDR); | ||
2054 | mac[0] = x & 0xff; | ||
2055 | mac[1] = x >> 8; | ||
2056 | x = rtl_eeprom_read(ioaddr, RTL_EEPROM_MAC_ADDR + 1); | ||
2057 | mac[2] = x & 0xff; | ||
2058 | mac[3] = x >> 8; | ||
2059 | x = rtl_eeprom_read(ioaddr, RTL_EEPROM_MAC_ADDR + 2); | ||
2060 | mac[4] = x & 0xff; | ||
2061 | mac[5] = x >> 8; | ||
2062 | |||
2063 | if (netif_msg_probe(tp)) { | ||
2064 | DECLARE_MAC_BUF(buf); | ||
2065 | |||
2066 | dev_info(&pdev->dev, "MAC address found in EEPROM: %s\n", | ||
2067 | print_mac(buf, mac)); | ||
2068 | } | ||
2069 | |||
2070 | if (is_valid_ether_addr(mac)) | ||
2071 | rtl_rar_set(tp, mac); | ||
2072 | } | ||
2073 | |||
1946 | static int __devinit | 2074 | static int __devinit |
1947 | rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | 2075 | rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) |
1948 | { | 2076 | { |
@@ -2121,6 +2249,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
2121 | 2249 | ||
2122 | tp->mmio_addr = ioaddr; | 2250 | tp->mmio_addr = ioaddr; |
2123 | 2251 | ||
2252 | rtl_init_mac_address(tp, ioaddr); | ||
2253 | |||
2124 | /* Get MAC address */ | 2254 | /* Get MAC address */ |
2125 | for (i = 0; i < MAC_ADDR_LEN; i++) | 2255 | for (i = 0; i < MAC_ADDR_LEN; i++) |
2126 | dev->dev_addr[i] = RTL_R8(MAC0 + i); | 2256 | dev->dev_addr[i] = RTL_R8(MAC0 + i); |
@@ -3682,6 +3812,9 @@ static int rtl8169_close(struct net_device *dev) | |||
3682 | struct rtl8169_private *tp = netdev_priv(dev); | 3812 | struct rtl8169_private *tp = netdev_priv(dev); |
3683 | struct pci_dev *pdev = tp->pci_dev; | 3813 | struct pci_dev *pdev = tp->pci_dev; |
3684 | 3814 | ||
3815 | /* update counters before going down */ | ||
3816 | rtl8169_update_counters(dev); | ||
3817 | |||
3685 | rtl8169_down(dev); | 3818 | rtl8169_down(dev); |
3686 | 3819 | ||
3687 | free_irq(dev->irq, dev); | 3820 | free_irq(dev->irq, dev); |