Merge branch 'rmobile-latest' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal...
[firefly-linux-kernel-4.4.55.git] / drivers / net / igb / igb_ethtool.c
index 26bf6a13d1c1a6e40beb4f1b8ec9c207fb501e1a..a70e16bcfa7e3fb58ac34205c3540cb306957cd7 100644 (file)
@@ -90,8 +90,8 @@ static const struct igb_stats igb_gstrings_stats[] = {
 
 #define IGB_NETDEV_STAT(_net_stat) { \
        .stat_string = __stringify(_net_stat), \
-       .sizeof_stat = FIELD_SIZEOF(struct net_device_stats, _net_stat), \
-       .stat_offset = offsetof(struct net_device_stats, _net_stat) \
+       .sizeof_stat = FIELD_SIZEOF(struct rtnl_link_stats64, _net_stat), \
+       .stat_offset = offsetof(struct rtnl_link_stats64, _net_stat) \
 }
 static const struct igb_stats igb_gstrings_net_stats[] = {
        IGB_NETDEV_STAT(rx_errors),
@@ -111,8 +111,9 @@ static const struct igb_stats igb_gstrings_net_stats[] = {
        (sizeof(igb_gstrings_net_stats) / sizeof(struct igb_stats))
 #define IGB_RX_QUEUE_STATS_LEN \
        (sizeof(struct igb_rx_queue_stats) / sizeof(u64))
-#define IGB_TX_QUEUE_STATS_LEN \
-       (sizeof(struct igb_tx_queue_stats) / sizeof(u64))
+
+#define IGB_TX_QUEUE_STATS_LEN 3 /* packets, bytes, restart_queue */
+
 #define IGB_QUEUE_STATS_LEN \
        ((((struct igb_adapter *)netdev_priv(netdev))->num_rx_queues * \
          IGB_RX_QUEUE_STATS_LEN) + \
@@ -2070,12 +2071,14 @@ static void igb_get_ethtool_stats(struct net_device *netdev,
                                  struct ethtool_stats *stats, u64 *data)
 {
        struct igb_adapter *adapter = netdev_priv(netdev);
-       struct net_device_stats *net_stats = &netdev->stats;
-       u64 *queue_stat;
-       int i, j, k;
+       struct rtnl_link_stats64 *net_stats = &adapter->stats64;
+       unsigned int start;
+       struct igb_ring *ring;
+       int i, j;
        char *p;
 
-       igb_update_stats(adapter);
+       spin_lock(&adapter->stats64_lock);
+       igb_update_stats(adapter, net_stats);
 
        for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) {
                p = (char *)adapter + igb_gstrings_stats[i].stat_offset;
@@ -2088,15 +2091,36 @@ static void igb_get_ethtool_stats(struct net_device *netdev,
                        sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
        }
        for (j = 0; j < adapter->num_tx_queues; j++) {
-               queue_stat = (u64 *)&adapter->tx_ring[j]->tx_stats;
-               for (k = 0; k < IGB_TX_QUEUE_STATS_LEN; k++, i++)
-                       data[i] = queue_stat[k];
+               u64     restart2;
+
+               ring = adapter->tx_ring[j];
+               do {
+                       start = u64_stats_fetch_begin_bh(&ring->tx_syncp);
+                       data[i]   = ring->tx_stats.packets;
+                       data[i+1] = ring->tx_stats.bytes;
+                       data[i+2] = ring->tx_stats.restart_queue;
+               } while (u64_stats_fetch_retry_bh(&ring->tx_syncp, start));
+               do {
+                       start = u64_stats_fetch_begin_bh(&ring->tx_syncp2);
+                       restart2  = ring->tx_stats.restart_queue2;
+               } while (u64_stats_fetch_retry_bh(&ring->tx_syncp2, start));
+               data[i+2] += restart2;
+
+               i += IGB_TX_QUEUE_STATS_LEN;
        }
        for (j = 0; j < adapter->num_rx_queues; j++) {
-               queue_stat = (u64 *)&adapter->rx_ring[j]->rx_stats;
-               for (k = 0; k < IGB_RX_QUEUE_STATS_LEN; k++, i++)
-                       data[i] = queue_stat[k];
+               ring = adapter->rx_ring[j];
+               do {
+                       start = u64_stats_fetch_begin_bh(&ring->rx_syncp);
+                       data[i]   = ring->rx_stats.packets;
+                       data[i+1] = ring->rx_stats.bytes;
+                       data[i+2] = ring->rx_stats.drops;
+                       data[i+3] = ring->rx_stats.csum_err;
+                       data[i+4] = ring->rx_stats.alloc_failed;
+               } while (u64_stats_fetch_retry_bh(&ring->rx_syncp, start));
+               i += IGB_RX_QUEUE_STATS_LEN;
        }
+       spin_unlock(&adapter->stats64_lock);
 }
 
 static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data)