]> git.ipfire.org Git - people/arne_f/kernel.git/blobdiff - drivers/net/ethernet/broadcom/bcmsysport.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[people/arne_f/kernel.git] / drivers / net / ethernet / broadcom / bcmsysport.c
index dc3052751bc13ed2248c218de01849d865dbe952..b3a21418f5114d52e7d2eb5fe10597e19d9290db 100644 (file)
@@ -201,10 +201,10 @@ static int bcm_sysport_set_features(struct net_device *dev,
  */
 static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = {
        /* general stats */
-       STAT_NETDEV(rx_packets),
-       STAT_NETDEV(tx_packets),
-       STAT_NETDEV(rx_bytes),
-       STAT_NETDEV(tx_bytes),
+       STAT_NETDEV64(rx_packets),
+       STAT_NETDEV64(tx_packets),
+       STAT_NETDEV64(rx_bytes),
+       STAT_NETDEV64(tx_bytes),
        STAT_NETDEV(rx_errors),
        STAT_NETDEV(tx_errors),
        STAT_NETDEV(rx_dropped),
@@ -316,6 +316,7 @@ static inline bool bcm_sysport_lite_stat_valid(enum bcm_sysport_stat_type type)
 {
        switch (type) {
        case BCM_SYSPORT_STAT_NETDEV:
+       case BCM_SYSPORT_STAT_NETDEV64:
        case BCM_SYSPORT_STAT_RXCHK:
        case BCM_SYSPORT_STAT_RBUF:
        case BCM_SYSPORT_STAT_SOFT:
@@ -398,6 +399,7 @@ static void bcm_sysport_update_mib_counters(struct bcm_sysport_priv *priv)
                s = &bcm_sysport_gstrings_stats[i];
                switch (s->type) {
                case BCM_SYSPORT_STAT_NETDEV:
+               case BCM_SYSPORT_STAT_NETDEV64:
                case BCM_SYSPORT_STAT_SOFT:
                        continue;
                case BCM_SYSPORT_STAT_MIB_RX:
@@ -434,7 +436,10 @@ static void bcm_sysport_get_stats(struct net_device *dev,
                                  struct ethtool_stats *stats, u64 *data)
 {
        struct bcm_sysport_priv *priv = netdev_priv(dev);
+       struct bcm_sysport_stats64 *stats64 = &priv->stats64;
+       struct u64_stats_sync *syncp = &priv->syncp;
        struct bcm_sysport_tx_ring *ring;
+       unsigned int start;
        int i, j;
 
        if (netif_running(dev))
@@ -447,14 +452,22 @@ static void bcm_sysport_get_stats(struct net_device *dev,
                s = &bcm_sysport_gstrings_stats[i];
                if (s->type == BCM_SYSPORT_STAT_NETDEV)
                        p = (char *)&dev->stats;
+               else if (s->type == BCM_SYSPORT_STAT_NETDEV64)
+                       p = (char *)stats64;
                else
                        p = (char *)priv;
 
                if (priv->is_lite && !bcm_sysport_lite_stat_valid(s->type))
                        continue;
-
                p += s->stat_offset;
-               data[j] = *(unsigned long *)p;
+
+               if (s->stat_sizeof == sizeof(u64))
+                       do {
+                               start = u64_stats_fetch_begin_irq(syncp);
+                               data[i] = *(u64 *)p;
+                       } while (u64_stats_fetch_retry_irq(syncp, start));
+               else
+                       data[i] = *(u32 *)p;
                j++;
        }
 
@@ -666,6 +679,7 @@ static int bcm_sysport_alloc_rx_bufs(struct bcm_sysport_priv *priv)
 static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
                                        unsigned int budget)
 {
+       struct bcm_sysport_stats64 *stats64 = &priv->stats64;
        struct net_device *ndev = priv->netdev;
        unsigned int processed = 0, to_process;
        struct bcm_sysport_cb *cb;
@@ -769,6 +783,10 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
                skb->protocol = eth_type_trans(skb, ndev);
                ndev->stats.rx_packets++;
                ndev->stats.rx_bytes += len;
+               u64_stats_update_begin(&priv->syncp);
+               stats64->rx_packets++;
+               stats64->rx_bytes += len;
+               u64_stats_update_end(&priv->syncp);
 
                napi_gro_receive(&priv->napi, skb);
 next:
@@ -791,17 +809,15 @@ static void bcm_sysport_tx_reclaim_one(struct bcm_sysport_tx_ring *ring,
        struct device *kdev = &priv->pdev->dev;
 
        if (cb->skb) {
-               ring->bytes += cb->skb->len;
                *bytes_compl += cb->skb->len;
                dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr),
                                 dma_unmap_len(cb, dma_len),
                                 DMA_TO_DEVICE);
-               ring->packets++;
                (*pkts_compl)++;
                bcm_sysport_free_cb(cb);
        /* SKB fragment */
        } else if (dma_unmap_addr(cb, dma_addr)) {
-               ring->bytes += dma_unmap_len(cb, dma_len);
+               *bytes_compl += dma_unmap_len(cb, dma_len);
                dma_unmap_page(kdev, dma_unmap_addr(cb, dma_addr),
                               dma_unmap_len(cb, dma_len), DMA_TO_DEVICE);
                dma_unmap_addr_set(cb, dma_addr, 0);
@@ -812,9 +828,9 @@ static void bcm_sysport_tx_reclaim_one(struct bcm_sysport_tx_ring *ring,
 static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
                                             struct bcm_sysport_tx_ring *ring)
 {
-       struct net_device *ndev = priv->netdev;
        unsigned int c_index, last_c_index, last_tx_cn, num_tx_cbs;
        unsigned int pkts_compl = 0, bytes_compl = 0;
+       struct net_device *ndev = priv->netdev;
        struct bcm_sysport_cb *cb;
        u32 hw_ind;
 
@@ -853,6 +869,11 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
                last_c_index &= (num_tx_cbs - 1);
        }
 
+       u64_stats_update_begin(&priv->syncp);
+       ring->packets += pkts_compl;
+       ring->bytes += bytes_compl;
+       u64_stats_update_end(&priv->syncp);
+
        ring->c_index = c_index;
 
        netif_dbg(priv, tx_done, ndev,
@@ -1675,22 +1696,41 @@ static int bcm_sysport_change_mac(struct net_device *dev, void *p)
        return 0;
 }
 
-static struct net_device_stats *bcm_sysport_get_nstats(struct net_device *dev)
+static void bcm_sysport_get_stats64(struct net_device *dev,
+                                   struct rtnl_link_stats64 *stats)
 {
        struct bcm_sysport_priv *priv = netdev_priv(dev);
-       unsigned long tx_bytes = 0, tx_packets = 0;
+       struct bcm_sysport_stats64 *stats64 = &priv->stats64;
        struct bcm_sysport_tx_ring *ring;
+       u64 tx_packets = 0, tx_bytes = 0;
+       unsigned int start;
        unsigned int q;
 
+       netdev_stats_to_stats64(stats, &dev->stats);
+
        for (q = 0; q < dev->num_tx_queues; q++) {
                ring = &priv->tx_rings[q];
-               tx_bytes += ring->bytes;
-               tx_packets += ring->packets;
+               do {
+                       start = u64_stats_fetch_begin_irq(&priv->syncp);
+                       tx_bytes = ring->bytes;
+                       tx_packets = ring->packets;
+               } while (u64_stats_fetch_retry_irq(&priv->syncp, start));
+
+               stats->tx_bytes += tx_bytes;
+               stats->tx_packets += tx_packets;
        }
 
-       dev->stats.tx_bytes = tx_bytes;
-       dev->stats.tx_packets = tx_packets;
-       return &dev->stats;
+       /* lockless update tx_bytes and tx_packets */
+       u64_stats_update_begin(&priv->syncp);
+       stats64->tx_bytes = stats->tx_bytes;
+       stats64->tx_packets = stats->tx_packets;
+       u64_stats_update_end(&priv->syncp);
+
+       do {
+               start = u64_stats_fetch_begin_irq(&priv->syncp);
+               stats->rx_packets = stats64->rx_packets;
+               stats->rx_bytes = stats64->rx_bytes;
+       } while (u64_stats_fetch_retry_irq(&priv->syncp, start));
 }
 
 static void bcm_sysport_netif_start(struct net_device *dev)
@@ -1954,7 +1994,7 @@ static const struct net_device_ops bcm_sysport_netdev_ops = {
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = bcm_sysport_poll_controller,
 #endif
-       .ndo_get_stats          = bcm_sysport_get_nstats,
+       .ndo_get_stats64        = bcm_sysport_get_stats64,
 };
 
 #define REV_FMT        "v%2x.%02x"
@@ -2102,6 +2142,8 @@ static int bcm_sysport_probe(struct platform_device *pdev)
        /* libphy will adjust the link state accordingly */
        netif_carrier_off(dev);
 
+       u64_stats_init(&priv->syncp);
+
        ret = register_netdev(dev);
        if (ret) {
                dev_err(&pdev->dev, "failed to register net_device\n");