diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-10-15 13:27:10 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-10-18 10:54:29 -0400 |
commit | 12dcd86b75d571772512676ab301279952efc0b0 (patch) | |
tree | 8214cabf20bfcba9fb58c642f5d1d2b544f4966e /drivers/net/igb/igb_ethtool.c | |
parent | dce87b960cf4794141f067d8c8180ccc6716513f (diff) |
igb: fix stats handling
There are currently some problems with igb.
- On 32bit arches, maintaining 64bit counters without proper
synchronization between writers and readers.
- Stats updated every two seconds, as reported by Jesper.
(Jesper provided a patch for this)
- Potential problem between worker thread and ethtool -S
This patch uses u64_stats_sync, and convert everything to be 64bit safe,
SMP safe, even on 32bit arches. It integrates Jesper idea of providing
accurate stats at the time user reads them.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Tested-by: Emil Tantilov <emil.s.tantilov@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/igb/igb_ethtool.c')
-rw-r--r-- | drivers/net/igb/igb_ethtool.c | 52 |
1 files changed, 38 insertions, 14 deletions
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 26bf6a13d1c1..a70e16bcfa7e 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c | |||
@@ -90,8 +90,8 @@ static const struct igb_stats igb_gstrings_stats[] = { | |||
90 | 90 | ||
91 | #define IGB_NETDEV_STAT(_net_stat) { \ | 91 | #define IGB_NETDEV_STAT(_net_stat) { \ |
92 | .stat_string = __stringify(_net_stat), \ | 92 | .stat_string = __stringify(_net_stat), \ |
93 | .sizeof_stat = FIELD_SIZEOF(struct net_device_stats, _net_stat), \ | 93 | .sizeof_stat = FIELD_SIZEOF(struct rtnl_link_stats64, _net_stat), \ |
94 | .stat_offset = offsetof(struct net_device_stats, _net_stat) \ | 94 | .stat_offset = offsetof(struct rtnl_link_stats64, _net_stat) \ |
95 | } | 95 | } |
96 | static const struct igb_stats igb_gstrings_net_stats[] = { | 96 | static const struct igb_stats igb_gstrings_net_stats[] = { |
97 | IGB_NETDEV_STAT(rx_errors), | 97 | IGB_NETDEV_STAT(rx_errors), |
@@ -111,8 +111,9 @@ static const struct igb_stats igb_gstrings_net_stats[] = { | |||
111 | (sizeof(igb_gstrings_net_stats) / sizeof(struct igb_stats)) | 111 | (sizeof(igb_gstrings_net_stats) / sizeof(struct igb_stats)) |
112 | #define IGB_RX_QUEUE_STATS_LEN \ | 112 | #define IGB_RX_QUEUE_STATS_LEN \ |
113 | (sizeof(struct igb_rx_queue_stats) / sizeof(u64)) | 113 | (sizeof(struct igb_rx_queue_stats) / sizeof(u64)) |
114 | #define IGB_TX_QUEUE_STATS_LEN \ | 114 | |
115 | (sizeof(struct igb_tx_queue_stats) / sizeof(u64)) | 115 | #define IGB_TX_QUEUE_STATS_LEN 3 /* packets, bytes, restart_queue */ |
116 | |||
116 | #define IGB_QUEUE_STATS_LEN \ | 117 | #define IGB_QUEUE_STATS_LEN \ |
117 | ((((struct igb_adapter *)netdev_priv(netdev))->num_rx_queues * \ | 118 | ((((struct igb_adapter *)netdev_priv(netdev))->num_rx_queues * \ |
118 | IGB_RX_QUEUE_STATS_LEN) + \ | 119 | IGB_RX_QUEUE_STATS_LEN) + \ |
@@ -2070,12 +2071,14 @@ static void igb_get_ethtool_stats(struct net_device *netdev, | |||
2070 | struct ethtool_stats *stats, u64 *data) | 2071 | struct ethtool_stats *stats, u64 *data) |
2071 | { | 2072 | { |
2072 | struct igb_adapter *adapter = netdev_priv(netdev); | 2073 | struct igb_adapter *adapter = netdev_priv(netdev); |
2073 | struct net_device_stats *net_stats = &netdev->stats; | 2074 | struct rtnl_link_stats64 *net_stats = &adapter->stats64; |
2074 | u64 *queue_stat; | 2075 | unsigned int start; |
2075 | int i, j, k; | 2076 | struct igb_ring *ring; |
2077 | int i, j; | ||
2076 | char *p; | 2078 | char *p; |
2077 | 2079 | ||
2078 | igb_update_stats(adapter); | 2080 | spin_lock(&adapter->stats64_lock); |
2081 | igb_update_stats(adapter, net_stats); | ||
2079 | 2082 | ||
2080 | for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) { | 2083 | for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) { |
2081 | p = (char *)adapter + igb_gstrings_stats[i].stat_offset; | 2084 | p = (char *)adapter + igb_gstrings_stats[i].stat_offset; |
@@ -2088,15 +2091,36 @@ static void igb_get_ethtool_stats(struct net_device *netdev, | |||
2088 | sizeof(u64)) ? *(u64 *)p : *(u32 *)p; | 2091 | sizeof(u64)) ? *(u64 *)p : *(u32 *)p; |
2089 | } | 2092 | } |
2090 | for (j = 0; j < adapter->num_tx_queues; j++) { | 2093 | for (j = 0; j < adapter->num_tx_queues; j++) { |
2091 | queue_stat = (u64 *)&adapter->tx_ring[j]->tx_stats; | 2094 | u64 restart2; |
2092 | for (k = 0; k < IGB_TX_QUEUE_STATS_LEN; k++, i++) | 2095 | |
2093 | data[i] = queue_stat[k]; | 2096 | ring = adapter->tx_ring[j]; |
2097 | do { | ||
2098 | start = u64_stats_fetch_begin_bh(&ring->tx_syncp); | ||
2099 | data[i] = ring->tx_stats.packets; | ||
2100 | data[i+1] = ring->tx_stats.bytes; | ||
2101 | data[i+2] = ring->tx_stats.restart_queue; | ||
2102 | } while (u64_stats_fetch_retry_bh(&ring->tx_syncp, start)); | ||
2103 | do { | ||
2104 | start = u64_stats_fetch_begin_bh(&ring->tx_syncp2); | ||
2105 | restart2 = ring->tx_stats.restart_queue2; | ||
2106 | } while (u64_stats_fetch_retry_bh(&ring->tx_syncp2, start)); | ||
2107 | data[i+2] += restart2; | ||
2108 | |||
2109 | i += IGB_TX_QUEUE_STATS_LEN; | ||
2094 | } | 2110 | } |
2095 | for (j = 0; j < adapter->num_rx_queues; j++) { | 2111 | for (j = 0; j < adapter->num_rx_queues; j++) { |
2096 | queue_stat = (u64 *)&adapter->rx_ring[j]->rx_stats; | 2112 | ring = adapter->rx_ring[j]; |
2097 | for (k = 0; k < IGB_RX_QUEUE_STATS_LEN; k++, i++) | 2113 | do { |
2098 | data[i] = queue_stat[k]; | 2114 | start = u64_stats_fetch_begin_bh(&ring->rx_syncp); |
2115 | data[i] = ring->rx_stats.packets; | ||
2116 | data[i+1] = ring->rx_stats.bytes; | ||
2117 | data[i+2] = ring->rx_stats.drops; | ||
2118 | data[i+3] = ring->rx_stats.csum_err; | ||
2119 | data[i+4] = ring->rx_stats.alloc_failed; | ||
2120 | } while (u64_stats_fetch_retry_bh(&ring->rx_syncp, start)); | ||
2121 | i += IGB_RX_QUEUE_STATS_LEN; | ||
2099 | } | 2122 | } |
2123 | spin_unlock(&adapter->stats64_lock); | ||
2100 | } | 2124 | } |
2101 | 2125 | ||
2102 | static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data) | 2126 | static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data) |