ixgbevf: provide 64 bit statistics
authorEric Dumazet <eric.dumazet@gmail.com>
Wed, 22 Jun 2011 05:01:35 +0000 (05:01 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Sat, 27 Aug 2011 06:50:09 +0000 (23:50 -0700)
Compute statistics per ring using 64 bits, and provide
network device stats in 64 bits.

It should make this driver multiqueue operations faster (no more cache
line ping pongs on netdev->stats structure)

Use u64_stats_sync infrastructure so that its safe on 32bit arches as
well.

Based on a prior patch from Stephen Hemminger

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
CC: Stephen Hemminger <shemminger@vyatta.com>
Acked-by: Greg Rose <gregory.v.rose@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c

index 8857df4dd3b9a4e0dc5dc141690cd0ae08a5023c..e6c9d1a927a9d0e06b003341b78f9b44620ed8c5 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/io.h>
 #include <linux/netdevice.h>
 #include <linux/if_vlan.h>
+#include <linux/u64_stats_sync.h>
 
 #include "vf.h"
 
@@ -71,12 +72,13 @@ struct ixgbevf_ring {
                struct ixgbevf_rx_buffer *rx_buffer_info;
        };
 
+       u64                     total_bytes;
+       u64                     total_packets;
+       struct u64_stats_sync   syncp;
+
        u16 head;
        u16 tail;
 
-       unsigned int total_bytes;
-       unsigned int total_packets;
-
        u16 reg_idx; /* holds the special value that gets the hardware register
                      * offset associated with this ring, which is different
                      * for DCB and RSS modes */
index 936532fa42ad0b10dca5afcc7326022199e5f9a4..bc12dd8d474a9b08e88875419be3c8d48d494187 100644 (file)
@@ -270,11 +270,10 @@ cont_loop:
                IXGBE_WRITE_REG(hw, IXGBE_VTEICS, tx_ring->v_idx);
        }
 
+       u64_stats_update_begin(&tx_ring->syncp);
        tx_ring->total_bytes += total_bytes;
        tx_ring->total_packets += total_packets;
-
-       netdev->stats.tx_bytes += total_bytes;
-       netdev->stats.tx_packets += total_packets;
+       u64_stats_update_end(&tx_ring->syncp);
 
        return count < tx_ring->work_limit;
 }
@@ -597,10 +596,10 @@ next_desc:
        if (cleaned_count)
                ixgbevf_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
 
+       u64_stats_update_begin(&rx_ring->syncp);
        rx_ring->total_packets += total_rx_packets;
        rx_ring->total_bytes += total_rx_bytes;
-       adapter->netdev->stats.rx_bytes += total_rx_bytes;
-       adapter->netdev->stats.rx_packets += total_rx_packets;
+       u64_stats_update_end(&rx_ring->syncp);
 
        return cleaned;
 }
@@ -2260,10 +2259,6 @@ void ixgbevf_update_stats(struct ixgbevf_adapter *adapter)
                                adapter->stats.vfgotc);
        UPDATE_VF_COUNTER_32bit(IXGBE_VFMPRC, adapter->stats.last_vfmprc,
                                adapter->stats.vfmprc);
-
-       /* Fill out the OS statistics structure */
-       adapter->netdev->stats.multicast = adapter->stats.vfmprc -
-               adapter->stats.base_vfmprc;
 }
 
 /**
@@ -3220,11 +3215,50 @@ static void ixgbevf_shutdown(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
+static struct rtnl_link_stats64 *ixgbevf_get_stats(struct net_device *netdev,
+                                               struct rtnl_link_stats64 *stats)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       unsigned int start;
+       u64 bytes, packets;
+       const struct ixgbevf_ring *ring;
+       int i;
+
+       ixgbevf_update_stats(adapter);
+
+       stats->multicast = adapter->stats.vfmprc - adapter->stats.base_vfmprc;
+
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               ring = &adapter->rx_ring[i];
+               do {
+                       start = u64_stats_fetch_begin_bh(&ring->syncp);
+                       bytes = ring->total_bytes;
+                       packets = ring->total_packets;
+               } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+               stats->rx_bytes += bytes;
+               stats->rx_packets += packets;
+       }
+
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               ring = &adapter->tx_ring[i];
+               do {
+                       start = u64_stats_fetch_begin_bh(&ring->syncp);
+                       bytes = ring->total_bytes;
+                       packets = ring->total_packets;
+               } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+               stats->tx_bytes += bytes;
+               stats->tx_packets += packets;
+       }
+
+       return stats;
+}
+
 static const struct net_device_ops ixgbe_netdev_ops = {
        .ndo_open               = ixgbevf_open,
        .ndo_stop               = ixgbevf_close,
        .ndo_start_xmit         = ixgbevf_xmit_frame,
        .ndo_set_rx_mode        = ixgbevf_set_rx_mode,
+       .ndo_get_stats64        = ixgbevf_get_stats,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = ixgbevf_set_mac,
        .ndo_change_mtu         = ixgbevf_change_mtu,