diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/r8169.c | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index d795b31649f3..b30e13867e1e 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c | |||
@@ -201,6 +201,8 @@ static struct { | |||
201 | enum RTL8169_registers { | 201 | enum RTL8169_registers { |
202 | MAC0 = 0, /* Ethernet hardware address. */ | 202 | MAC0 = 0, /* Ethernet hardware address. */ |
203 | MAR0 = 8, /* Multicast filter. */ | 203 | MAR0 = 8, /* Multicast filter. */ |
204 | CounterAddrLow = 0x10, | ||
205 | CounterAddrHigh = 0x14, | ||
204 | TxDescStartAddrLow = 0x20, | 206 | TxDescStartAddrLow = 0x20, |
205 | TxDescStartAddrHigh = 0x24, | 207 | TxDescStartAddrHigh = 0x24, |
206 | TxHDescStartAddrLow = 0x28, | 208 | TxHDescStartAddrLow = 0x28, |
@@ -342,6 +344,9 @@ enum RTL8169_register_content { | |||
342 | 344 | ||
343 | /* _TBICSRBit */ | 345 | /* _TBICSRBit */ |
344 | TBILinkOK = 0x02000000, | 346 | TBILinkOK = 0x02000000, |
347 | |||
348 | /* DumpCounterCommand */ | ||
349 | CounterDump = 0x8, | ||
345 | }; | 350 | }; |
346 | 351 | ||
347 | enum _DescStatusBit { | 352 | enum _DescStatusBit { |
@@ -910,6 +915,98 @@ static void rtl8169_set_msglevel(struct net_device *dev, u32 value) | |||
910 | tp->msg_enable = value; | 915 | tp->msg_enable = value; |
911 | } | 916 | } |
912 | 917 | ||
918 | static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = { | ||
919 | "tx_packets", | ||
920 | "rx_packets", | ||
921 | "tx_errors", | ||
922 | "rx_errors", | ||
923 | "rx_missed", | ||
924 | "align_errors", | ||
925 | "tx_single_collisions", | ||
926 | "tx_multi_collisions", | ||
927 | "unicast", | ||
928 | "broadcast", | ||
929 | "multicast", | ||
930 | "tx_aborted", | ||
931 | "tx_underrun", | ||
932 | }; | ||
933 | |||
934 | struct rtl8169_counters { | ||
935 | u64 tx_packets; | ||
936 | u64 rx_packets; | ||
937 | u64 tx_errors; | ||
938 | u32 rx_errors; | ||
939 | u16 rx_missed; | ||
940 | u16 align_errors; | ||
941 | u32 tx_one_collision; | ||
942 | u32 tx_multi_collision; | ||
943 | u64 rx_unicast; | ||
944 | u64 rx_broadcast; | ||
945 | u32 rx_multicast; | ||
946 | u16 tx_aborted; | ||
947 | u16 tx_underun; | ||
948 | }; | ||
949 | |||
950 | static int rtl8169_get_stats_count(struct net_device *dev) | ||
951 | { | ||
952 | return ARRAY_SIZE(rtl8169_gstrings); | ||
953 | } | ||
954 | |||
955 | static void rtl8169_get_ethtool_stats(struct net_device *dev, | ||
956 | struct ethtool_stats *stats, u64 *data) | ||
957 | { | ||
958 | struct rtl8169_private *tp = netdev_priv(dev); | ||
959 | void __iomem *ioaddr = tp->mmio_addr; | ||
960 | struct rtl8169_counters *counters; | ||
961 | dma_addr_t paddr; | ||
962 | u32 cmd; | ||
963 | |||
964 | ASSERT_RTNL(); | ||
965 | |||
966 | counters = pci_alloc_consistent(tp->pci_dev, sizeof(*counters), &paddr); | ||
967 | if (!counters) | ||
968 | return; | ||
969 | |||
970 | RTL_W32(CounterAddrHigh, (u64)paddr >> 32); | ||
971 | cmd = (u64)paddr & DMA_32BIT_MASK; | ||
972 | RTL_W32(CounterAddrLow, cmd); | ||
973 | RTL_W32(CounterAddrLow, cmd | CounterDump); | ||
974 | |||
975 | while (RTL_R32(CounterAddrLow) & CounterDump) { | ||
976 | if (msleep_interruptible(1)) | ||
977 | break; | ||
978 | } | ||
979 | |||
980 | RTL_W32(CounterAddrLow, 0); | ||
981 | RTL_W32(CounterAddrHigh, 0); | ||
982 | |||
983 | data[0] = le64_to_cpu(counters->tx_packets); | ||
984 | data[1] = le64_to_cpu(counters->rx_packets); | ||
985 | data[2] = le64_to_cpu(counters->tx_errors); | ||
986 | data[3] = le32_to_cpu(counters->rx_errors); | ||
987 | data[4] = le16_to_cpu(counters->rx_missed); | ||
988 | data[5] = le16_to_cpu(counters->align_errors); | ||
989 | data[6] = le32_to_cpu(counters->tx_one_collision); | ||
990 | data[7] = le32_to_cpu(counters->tx_multi_collision); | ||
991 | data[8] = le64_to_cpu(counters->rx_unicast); | ||
992 | data[9] = le64_to_cpu(counters->rx_broadcast); | ||
993 | data[10] = le32_to_cpu(counters->rx_multicast); | ||
994 | data[11] = le16_to_cpu(counters->tx_aborted); | ||
995 | data[12] = le16_to_cpu(counters->tx_underun); | ||
996 | |||
997 | pci_free_consistent(tp->pci_dev, sizeof(*counters), counters, paddr); | ||
998 | } | ||
999 | |||
1000 | static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data) | ||
1001 | { | ||
1002 | switch(stringset) { | ||
1003 | case ETH_SS_STATS: | ||
1004 | memcpy(data, *rtl8169_gstrings, sizeof(rtl8169_gstrings)); | ||
1005 | break; | ||
1006 | } | ||
1007 | } | ||
1008 | |||
1009 | |||
913 | static struct ethtool_ops rtl8169_ethtool_ops = { | 1010 | static struct ethtool_ops rtl8169_ethtool_ops = { |
914 | .get_drvinfo = rtl8169_get_drvinfo, | 1011 | .get_drvinfo = rtl8169_get_drvinfo, |
915 | .get_regs_len = rtl8169_get_regs_len, | 1012 | .get_regs_len = rtl8169_get_regs_len, |
@@ -927,6 +1024,9 @@ static struct ethtool_ops rtl8169_ethtool_ops = { | |||
927 | .get_tso = ethtool_op_get_tso, | 1024 | .get_tso = ethtool_op_get_tso, |
928 | .set_tso = ethtool_op_set_tso, | 1025 | .set_tso = ethtool_op_set_tso, |
929 | .get_regs = rtl8169_get_regs, | 1026 | .get_regs = rtl8169_get_regs, |
1027 | .get_strings = rtl8169_get_strings, | ||
1028 | .get_stats_count = rtl8169_get_stats_count, | ||
1029 | .get_ethtool_stats = rtl8169_get_ethtool_stats, | ||
930 | }; | 1030 | }; |
931 | 1031 | ||
932 | static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, int bitnum, | 1032 | static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, int bitnum, |