/* structs defined in e1000_hw.h */
        struct e1000_hw hw;
 
+       spinlock_t stats64_lock;
        struct e1000_hw_stats stats;
        struct e1000_phy_info phy_info;
        struct e1000_phy_stats phy_stats;
 extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter);
 extern void e1000e_free_rx_resources(struct e1000_adapter *adapter);
 extern void e1000e_free_tx_resources(struct e1000_adapter *adapter);
-extern void e1000e_update_stats(struct e1000_adapter *adapter);
+extern struct rtnl_link_stats64 *e1000e_get_stats64(struct net_device *netdev,
+                                                    struct rtnl_link_stats64
+                                                    *stats);
 extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter);
 extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter);
 extern void e1000e_get_hw_control(struct e1000_adapter *adapter);
 
 };
 
 #define E1000_STAT(str, m) { \
-                       .stat_string = str, \
-                       .type = E1000_STATS, \
-                       .sizeof_stat = sizeof(((struct e1000_adapter *)0)->m), \
-                       .stat_offset = offsetof(struct e1000_adapter, m) }
+               .stat_string = str, \
+               .type = E1000_STATS, \
+               .sizeof_stat = sizeof(((struct e1000_adapter *)0)->m), \
+               .stat_offset = offsetof(struct e1000_adapter, m) }
 #define E1000_NETDEV_STAT(str, m) { \
-                       .stat_string = str, \
-                       .type = NETDEV_STATS, \
-                       .sizeof_stat = sizeof(((struct net_device *)0)->m), \
-                       .stat_offset = offsetof(struct net_device, m) }
+               .stat_string = str, \
+               .type = NETDEV_STATS, \
+               .sizeof_stat = sizeof(((struct rtnl_link_stats64 *)0)->m), \
+               .stat_offset = offsetof(struct rtnl_link_stats64, m) }
 
 static const struct e1000_stats e1000_gstrings_stats[] = {
        E1000_STAT("rx_packets", stats.gprc),
        E1000_STAT("tx_broadcast", stats.bptc),
        E1000_STAT("rx_multicast", stats.mprc),
        E1000_STAT("tx_multicast", stats.mptc),
-       E1000_NETDEV_STAT("rx_errors", stats.rx_errors),
-       E1000_NETDEV_STAT("tx_errors", stats.tx_errors),
-       E1000_NETDEV_STAT("tx_dropped", stats.tx_dropped),
+       E1000_NETDEV_STAT("rx_errors", rx_errors),
+       E1000_NETDEV_STAT("tx_errors", tx_errors),
+       E1000_NETDEV_STAT("tx_dropped", tx_dropped),
        E1000_STAT("multicast", stats.mprc),
        E1000_STAT("collisions", stats.colc),
-       E1000_NETDEV_STAT("rx_length_errors", stats.rx_length_errors),
-       E1000_NETDEV_STAT("rx_over_errors", stats.rx_over_errors),
+       E1000_NETDEV_STAT("rx_length_errors", rx_length_errors),
+       E1000_NETDEV_STAT("rx_over_errors", rx_over_errors),
        E1000_STAT("rx_crc_errors", stats.crcerrs),
-       E1000_NETDEV_STAT("rx_frame_errors", stats.rx_frame_errors),
+       E1000_NETDEV_STAT("rx_frame_errors", rx_frame_errors),
        E1000_STAT("rx_no_buffer_count", stats.rnbc),
        E1000_STAT("rx_missed_errors", stats.mpc),
        E1000_STAT("tx_aborted_errors", stats.ecol),
        E1000_STAT("tx_carrier_errors", stats.tncrs),
-       E1000_NETDEV_STAT("tx_fifo_errors", stats.tx_fifo_errors),
-       E1000_NETDEV_STAT("tx_heartbeat_errors", stats.tx_heartbeat_errors),
+       E1000_NETDEV_STAT("tx_fifo_errors", tx_fifo_errors),
+       E1000_NETDEV_STAT("tx_heartbeat_errors", tx_heartbeat_errors),
        E1000_STAT("tx_window_errors", stats.latecol),
        E1000_STAT("tx_abort_late_coll", stats.latecol),
        E1000_STAT("tx_deferred_ok", stats.dc),
                                    u64 *data)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
+       struct rtnl_link_stats64 net_stats;
        int i;
        char *p = NULL;
 
-       e1000e_update_stats(adapter);
+       e1000e_get_stats64(netdev, &net_stats);
        for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
                switch (e1000_gstrings_stats[i].type) {
                case NETDEV_STATS:
-                       p = (char *) netdev +
+                       p = (char *) &net_stats +
                                        e1000_gstrings_stats[i].stat_offset;
                        break;
                case E1000_STATS:
 
 
        adapter->total_rx_bytes += total_rx_bytes;
        adapter->total_rx_packets += total_rx_packets;
-       netdev->stats.rx_bytes += total_rx_bytes;
-       netdev->stats.rx_packets += total_rx_packets;
        return cleaned;
 }
 
        }
        adapter->total_tx_bytes += total_tx_bytes;
        adapter->total_tx_packets += total_tx_packets;
-       netdev->stats.tx_bytes += total_tx_bytes;
-       netdev->stats.tx_packets += total_tx_packets;
        return count < tx_ring->count;
 }
 
 
        adapter->total_rx_bytes += total_rx_bytes;
        adapter->total_rx_packets += total_rx_packets;
-       netdev->stats.rx_bytes += total_rx_bytes;
-       netdev->stats.rx_packets += total_rx_packets;
        return cleaned;
 }
 
 
        adapter->total_rx_bytes += total_rx_bytes;
        adapter->total_rx_packets += total_rx_packets;
-       netdev->stats.rx_bytes += total_rx_bytes;
-       netdev->stats.rx_packets += total_rx_packets;
        return cleaned;
 }
 
        return 0;
 }
 
+static void e1000e_update_stats(struct e1000_adapter *adapter);
+
 void e1000e_down(struct e1000_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
        del_timer_sync(&adapter->phy_info_timer);
 
        netif_carrier_off(netdev);
+
+       spin_lock(&adapter->stats64_lock);
+       e1000e_update_stats(adapter);
+       spin_unlock(&adapter->stats64_lock);
+
        adapter->link_speed = 0;
        adapter->link_duplex = 0;
 
        adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
        adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
 
+       spin_lock_init(&adapter->stats64_lock);
+
        e1000e_set_interrupt_capability(adapter);
 
        if (e1000_alloc_queues(adapter))
  * e1000e_update_stats - Update the board statistics counters
  * @adapter: board private structure
  **/
-void e1000e_update_stats(struct e1000_adapter *adapter)
+static void e1000e_update_stats(struct e1000_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
        struct e1000_hw *hw = &adapter->hw;
        }
 
 link_up:
+       spin_lock(&adapter->stats64_lock);
        e1000e_update_stats(adapter);
+       spin_unlock(&adapter->stats64_lock);
 
        mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old;
        adapter->tpt_old = adapter->stats.tpt;
 }
 
 /**
- * e1000_get_stats - Get System Network Statistics
+ * e1000_get_stats64 - Get System Network Statistics
  * @netdev: network interface device structure
+ * @stats: rtnl_link_stats64 pointer
  *
  * Returns the address of the device statistics structure.
- * The statistics are actually updated from the timer callback.
  **/
-static struct net_device_stats *e1000_get_stats(struct net_device *netdev)
+struct rtnl_link_stats64 *e1000e_get_stats64(struct net_device *netdev,
+                                             struct rtnl_link_stats64 *stats)
 {
-       /* only return the current stats */
-       return &netdev->stats;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+
+       memset(stats, 0, sizeof(struct rtnl_link_stats64));
+       spin_lock(&adapter->stats64_lock);
+       e1000e_update_stats(adapter);
+       /* Fill out the OS statistics structure */
+       stats->rx_bytes = adapter->stats.gorc;
+       stats->rx_packets = adapter->stats.gprc;
+       stats->tx_bytes = adapter->stats.gotc;
+       stats->tx_packets = adapter->stats.gptc;
+       stats->multicast = adapter->stats.mprc;
+       stats->collisions = adapter->stats.colc;
+
+       /* Rx Errors */
+
+       /*
+        * RLEC on some newer hardware can be incorrect so build
+        * our own version based on RUC and ROC
+        */
+       stats->rx_errors = adapter->stats.rxerrc +
+               adapter->stats.crcerrs + adapter->stats.algnerrc +
+               adapter->stats.ruc + adapter->stats.roc +
+               adapter->stats.cexterr;
+       stats->rx_length_errors = adapter->stats.ruc +
+                                             adapter->stats.roc;
+       stats->rx_crc_errors = adapter->stats.crcerrs;
+       stats->rx_frame_errors = adapter->stats.algnerrc;
+       stats->rx_missed_errors = adapter->stats.mpc;
+
+       /* Tx Errors */
+       stats->tx_errors = adapter->stats.ecol +
+                                      adapter->stats.latecol;
+       stats->tx_aborted_errors = adapter->stats.ecol;
+       stats->tx_window_errors = adapter->stats.latecol;
+       stats->tx_carrier_errors = adapter->stats.tncrs;
+
+       /* Tx Dropped needs to be maintained elsewhere */
+
+       spin_unlock(&adapter->stats64_lock);
+       return stats;
 }
 
 /**
        .ndo_open               = e1000_open,
        .ndo_stop               = e1000_close,
        .ndo_start_xmit         = e1000_xmit_frame,
-       .ndo_get_stats          = e1000_get_stats,
+       .ndo_get_stats64        = e1000e_get_stats64,
        .ndo_set_multicast_list = e1000_set_multi,
        .ndo_set_mac_address    = e1000_set_mac,
        .ndo_change_mtu         = e1000_change_mtu,