aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/igb/igb_ethtool.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-10-15 13:27:10 -0400
committerDavid S. Miller <davem@davemloft.net>2010-10-18 10:54:29 -0400
commit12dcd86b75d571772512676ab301279952efc0b0 (patch)
tree8214cabf20bfcba9fb58c642f5d1d2b544f4966e /drivers/net/igb/igb_ethtool.c
parentdce87b960cf4794141f067d8c8180ccc6716513f (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.c52
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}
96static const struct igb_stats igb_gstrings_net_stats[] = { 96static 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
2102static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data) 2126static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data)