diff options
-rw-r--r-- | drivers/net/ethernet/broadcom/bcmsysport.c | 78 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bcmsysport.h | 21 |
2 files changed, 82 insertions, 17 deletions
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 5333601f855f..bf9ca3c79d1a 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c | |||
@@ -201,10 +201,10 @@ static int bcm_sysport_set_features(struct net_device *dev, | |||
201 | */ | 201 | */ |
202 | static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = { | 202 | static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = { |
203 | /* general stats */ | 203 | /* general stats */ |
204 | STAT_NETDEV(rx_packets), | 204 | STAT_NETDEV64(rx_packets), |
205 | STAT_NETDEV(tx_packets), | 205 | STAT_NETDEV64(tx_packets), |
206 | STAT_NETDEV(rx_bytes), | 206 | STAT_NETDEV64(rx_bytes), |
207 | STAT_NETDEV(tx_bytes), | 207 | STAT_NETDEV64(tx_bytes), |
208 | STAT_NETDEV(rx_errors), | 208 | STAT_NETDEV(rx_errors), |
209 | STAT_NETDEV(tx_errors), | 209 | STAT_NETDEV(tx_errors), |
210 | STAT_NETDEV(rx_dropped), | 210 | STAT_NETDEV(rx_dropped), |
@@ -316,6 +316,7 @@ static inline bool bcm_sysport_lite_stat_valid(enum bcm_sysport_stat_type type) | |||
316 | { | 316 | { |
317 | switch (type) { | 317 | switch (type) { |
318 | case BCM_SYSPORT_STAT_NETDEV: | 318 | case BCM_SYSPORT_STAT_NETDEV: |
319 | case BCM_SYSPORT_STAT_NETDEV64: | ||
319 | case BCM_SYSPORT_STAT_RXCHK: | 320 | case BCM_SYSPORT_STAT_RXCHK: |
320 | case BCM_SYSPORT_STAT_RBUF: | 321 | case BCM_SYSPORT_STAT_RBUF: |
321 | case BCM_SYSPORT_STAT_SOFT: | 322 | case BCM_SYSPORT_STAT_SOFT: |
@@ -398,6 +399,7 @@ static void bcm_sysport_update_mib_counters(struct bcm_sysport_priv *priv) | |||
398 | s = &bcm_sysport_gstrings_stats[i]; | 399 | s = &bcm_sysport_gstrings_stats[i]; |
399 | switch (s->type) { | 400 | switch (s->type) { |
400 | case BCM_SYSPORT_STAT_NETDEV: | 401 | case BCM_SYSPORT_STAT_NETDEV: |
402 | case BCM_SYSPORT_STAT_NETDEV64: | ||
401 | case BCM_SYSPORT_STAT_SOFT: | 403 | case BCM_SYSPORT_STAT_SOFT: |
402 | continue; | 404 | continue; |
403 | case BCM_SYSPORT_STAT_MIB_RX: | 405 | case BCM_SYSPORT_STAT_MIB_RX: |
@@ -434,7 +436,10 @@ static void bcm_sysport_get_stats(struct net_device *dev, | |||
434 | struct ethtool_stats *stats, u64 *data) | 436 | struct ethtool_stats *stats, u64 *data) |
435 | { | 437 | { |
436 | struct bcm_sysport_priv *priv = netdev_priv(dev); | 438 | struct bcm_sysport_priv *priv = netdev_priv(dev); |
439 | struct bcm_sysport_stats64 *stats64 = &priv->stats64; | ||
440 | struct u64_stats_sync *syncp = &priv->syncp; | ||
437 | struct bcm_sysport_tx_ring *ring; | 441 | struct bcm_sysport_tx_ring *ring; |
442 | unsigned int start; | ||
438 | int i, j; | 443 | int i, j; |
439 | 444 | ||
440 | if (netif_running(dev)) | 445 | if (netif_running(dev)) |
@@ -447,10 +452,20 @@ static void bcm_sysport_get_stats(struct net_device *dev, | |||
447 | s = &bcm_sysport_gstrings_stats[i]; | 452 | s = &bcm_sysport_gstrings_stats[i]; |
448 | if (s->type == BCM_SYSPORT_STAT_NETDEV) | 453 | if (s->type == BCM_SYSPORT_STAT_NETDEV) |
449 | p = (char *)&dev->stats; | 454 | p = (char *)&dev->stats; |
455 | else if (s->type == BCM_SYSPORT_STAT_NETDEV64) | ||
456 | p = (char *)stats64; | ||
450 | else | 457 | else |
451 | p = (char *)priv; | 458 | p = (char *)priv; |
459 | |||
452 | p += s->stat_offset; | 460 | p += s->stat_offset; |
453 | data[j] = *(unsigned long *)p; | 461 | |
462 | if (s->stat_sizeof == sizeof(u64)) | ||
463 | do { | ||
464 | start = u64_stats_fetch_begin_irq(syncp); | ||
465 | data[i] = *(u64 *)p; | ||
466 | } while (u64_stats_fetch_retry_irq(syncp, start)); | ||
467 | else | ||
468 | data[i] = *(u32 *)p; | ||
454 | j++; | 469 | j++; |
455 | } | 470 | } |
456 | 471 | ||
@@ -662,6 +677,7 @@ static int bcm_sysport_alloc_rx_bufs(struct bcm_sysport_priv *priv) | |||
662 | static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv, | 677 | static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv, |
663 | unsigned int budget) | 678 | unsigned int budget) |
664 | { | 679 | { |
680 | struct bcm_sysport_stats64 *stats64 = &priv->stats64; | ||
665 | struct net_device *ndev = priv->netdev; | 681 | struct net_device *ndev = priv->netdev; |
666 | unsigned int processed = 0, to_process; | 682 | unsigned int processed = 0, to_process; |
667 | struct bcm_sysport_cb *cb; | 683 | struct bcm_sysport_cb *cb; |
@@ -765,6 +781,10 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv, | |||
765 | skb->protocol = eth_type_trans(skb, ndev); | 781 | skb->protocol = eth_type_trans(skb, ndev); |
766 | ndev->stats.rx_packets++; | 782 | ndev->stats.rx_packets++; |
767 | ndev->stats.rx_bytes += len; | 783 | ndev->stats.rx_bytes += len; |
784 | u64_stats_update_begin(&priv->syncp); | ||
785 | stats64->rx_packets++; | ||
786 | stats64->rx_bytes += len; | ||
787 | u64_stats_update_end(&priv->syncp); | ||
768 | 788 | ||
769 | napi_gro_receive(&priv->napi, skb); | 789 | napi_gro_receive(&priv->napi, skb); |
770 | next: | 790 | next: |
@@ -787,17 +807,15 @@ static void bcm_sysport_tx_reclaim_one(struct bcm_sysport_tx_ring *ring, | |||
787 | struct device *kdev = &priv->pdev->dev; | 807 | struct device *kdev = &priv->pdev->dev; |
788 | 808 | ||
789 | if (cb->skb) { | 809 | if (cb->skb) { |
790 | ring->bytes += cb->skb->len; | ||
791 | *bytes_compl += cb->skb->len; | 810 | *bytes_compl += cb->skb->len; |
792 | dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr), | 811 | dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr), |
793 | dma_unmap_len(cb, dma_len), | 812 | dma_unmap_len(cb, dma_len), |
794 | DMA_TO_DEVICE); | 813 | DMA_TO_DEVICE); |
795 | ring->packets++; | ||
796 | (*pkts_compl)++; | 814 | (*pkts_compl)++; |
797 | bcm_sysport_free_cb(cb); | 815 | bcm_sysport_free_cb(cb); |
798 | /* SKB fragment */ | 816 | /* SKB fragment */ |
799 | } else if (dma_unmap_addr(cb, dma_addr)) { | 817 | } else if (dma_unmap_addr(cb, dma_addr)) { |
800 | ring->bytes += dma_unmap_len(cb, dma_len); | 818 | *bytes_compl += dma_unmap_len(cb, dma_len); |
801 | dma_unmap_page(kdev, dma_unmap_addr(cb, dma_addr), | 819 | dma_unmap_page(kdev, dma_unmap_addr(cb, dma_addr), |
802 | dma_unmap_len(cb, dma_len), DMA_TO_DEVICE); | 820 | dma_unmap_len(cb, dma_len), DMA_TO_DEVICE); |
803 | dma_unmap_addr_set(cb, dma_addr, 0); | 821 | dma_unmap_addr_set(cb, dma_addr, 0); |
@@ -808,9 +826,9 @@ static void bcm_sysport_tx_reclaim_one(struct bcm_sysport_tx_ring *ring, | |||
808 | static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, | 826 | static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, |
809 | struct bcm_sysport_tx_ring *ring) | 827 | struct bcm_sysport_tx_ring *ring) |
810 | { | 828 | { |
811 | struct net_device *ndev = priv->netdev; | ||
812 | unsigned int c_index, last_c_index, last_tx_cn, num_tx_cbs; | 829 | unsigned int c_index, last_c_index, last_tx_cn, num_tx_cbs; |
813 | unsigned int pkts_compl = 0, bytes_compl = 0; | 830 | unsigned int pkts_compl = 0, bytes_compl = 0; |
831 | struct net_device *ndev = priv->netdev; | ||
814 | struct bcm_sysport_cb *cb; | 832 | struct bcm_sysport_cb *cb; |
815 | u32 hw_ind; | 833 | u32 hw_ind; |
816 | 834 | ||
@@ -849,6 +867,11 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, | |||
849 | last_c_index &= (num_tx_cbs - 1); | 867 | last_c_index &= (num_tx_cbs - 1); |
850 | } | 868 | } |
851 | 869 | ||
870 | u64_stats_update_begin(&priv->syncp); | ||
871 | ring->packets += pkts_compl; | ||
872 | ring->bytes += bytes_compl; | ||
873 | u64_stats_update_end(&priv->syncp); | ||
874 | |||
852 | ring->c_index = c_index; | 875 | ring->c_index = c_index; |
853 | 876 | ||
854 | netif_dbg(priv, tx_done, ndev, | 877 | netif_dbg(priv, tx_done, ndev, |
@@ -1671,22 +1694,41 @@ static int bcm_sysport_change_mac(struct net_device *dev, void *p) | |||
1671 | return 0; | 1694 | return 0; |
1672 | } | 1695 | } |
1673 | 1696 | ||
1674 | static struct net_device_stats *bcm_sysport_get_nstats(struct net_device *dev) | 1697 | static void bcm_sysport_get_stats64(struct net_device *dev, |
1698 | struct rtnl_link_stats64 *stats) | ||
1675 | { | 1699 | { |
1676 | struct bcm_sysport_priv *priv = netdev_priv(dev); | 1700 | struct bcm_sysport_priv *priv = netdev_priv(dev); |
1677 | unsigned long tx_bytes = 0, tx_packets = 0; | 1701 | struct bcm_sysport_stats64 *stats64 = &priv->stats64; |
1678 | struct bcm_sysport_tx_ring *ring; | 1702 | struct bcm_sysport_tx_ring *ring; |
1703 | u64 tx_packets = 0, tx_bytes = 0; | ||
1704 | unsigned int start; | ||
1679 | unsigned int q; | 1705 | unsigned int q; |
1680 | 1706 | ||
1707 | netdev_stats_to_stats64(stats, &dev->stats); | ||
1708 | |||
1681 | for (q = 0; q < dev->num_tx_queues; q++) { | 1709 | for (q = 0; q < dev->num_tx_queues; q++) { |
1682 | ring = &priv->tx_rings[q]; | 1710 | ring = &priv->tx_rings[q]; |
1683 | tx_bytes += ring->bytes; | 1711 | do { |
1684 | tx_packets += ring->packets; | 1712 | start = u64_stats_fetch_begin_irq(&priv->syncp); |
1713 | tx_bytes = ring->bytes; | ||
1714 | tx_packets = ring->packets; | ||
1715 | } while (u64_stats_fetch_retry_irq(&priv->syncp, start)); | ||
1716 | |||
1717 | stats->tx_bytes += tx_bytes; | ||
1718 | stats->tx_packets += tx_packets; | ||
1685 | } | 1719 | } |
1686 | 1720 | ||
1687 | dev->stats.tx_bytes = tx_bytes; | 1721 | /* lockless update tx_bytes and tx_packets */ |
1688 | dev->stats.tx_packets = tx_packets; | 1722 | u64_stats_update_begin(&priv->syncp); |
1689 | return &dev->stats; | 1723 | stats64->tx_bytes = stats->tx_bytes; |
1724 | stats64->tx_packets = stats->tx_packets; | ||
1725 | u64_stats_update_end(&priv->syncp); | ||
1726 | |||
1727 | do { | ||
1728 | start = u64_stats_fetch_begin_irq(&priv->syncp); | ||
1729 | stats->rx_packets = stats64->rx_packets; | ||
1730 | stats->rx_bytes = stats64->rx_bytes; | ||
1731 | } while (u64_stats_fetch_retry_irq(&priv->syncp, start)); | ||
1690 | } | 1732 | } |
1691 | 1733 | ||
1692 | static void bcm_sysport_netif_start(struct net_device *dev) | 1734 | static void bcm_sysport_netif_start(struct net_device *dev) |
@@ -1950,7 +1992,7 @@ static const struct net_device_ops bcm_sysport_netdev_ops = { | |||
1950 | #ifdef CONFIG_NET_POLL_CONTROLLER | 1992 | #ifdef CONFIG_NET_POLL_CONTROLLER |
1951 | .ndo_poll_controller = bcm_sysport_poll_controller, | 1993 | .ndo_poll_controller = bcm_sysport_poll_controller, |
1952 | #endif | 1994 | #endif |
1953 | .ndo_get_stats = bcm_sysport_get_nstats, | 1995 | .ndo_get_stats64 = bcm_sysport_get_stats64, |
1954 | }; | 1996 | }; |
1955 | 1997 | ||
1956 | #define REV_FMT "v%2x.%02x" | 1998 | #define REV_FMT "v%2x.%02x" |
@@ -2098,6 +2140,8 @@ static int bcm_sysport_probe(struct platform_device *pdev) | |||
2098 | /* libphy will adjust the link state accordingly */ | 2140 | /* libphy will adjust the link state accordingly */ |
2099 | netif_carrier_off(dev); | 2141 | netif_carrier_off(dev); |
2100 | 2142 | ||
2143 | u64_stats_init(&priv->syncp); | ||
2144 | |||
2101 | ret = register_netdev(dev); | 2145 | ret = register_netdev(dev); |
2102 | if (ret) { | 2146 | if (ret) { |
2103 | dev_err(&pdev->dev, "failed to register net_device\n"); | 2147 | dev_err(&pdev->dev, "failed to register net_device\n"); |
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h index 77a51c167a69..80b4ffff63b7 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.h +++ b/drivers/net/ethernet/broadcom/bcmsysport.h | |||
@@ -603,6 +603,7 @@ struct bcm_sysport_mib { | |||
603 | /* HW maintains a large list of counters */ | 603 | /* HW maintains a large list of counters */ |
604 | enum bcm_sysport_stat_type { | 604 | enum bcm_sysport_stat_type { |
605 | BCM_SYSPORT_STAT_NETDEV = -1, | 605 | BCM_SYSPORT_STAT_NETDEV = -1, |
606 | BCM_SYSPORT_STAT_NETDEV64, | ||
606 | BCM_SYSPORT_STAT_MIB_RX, | 607 | BCM_SYSPORT_STAT_MIB_RX, |
607 | BCM_SYSPORT_STAT_MIB_TX, | 608 | BCM_SYSPORT_STAT_MIB_TX, |
608 | BCM_SYSPORT_STAT_RUNT, | 609 | BCM_SYSPORT_STAT_RUNT, |
@@ -619,6 +620,13 @@ enum bcm_sysport_stat_type { | |||
619 | .type = BCM_SYSPORT_STAT_NETDEV, \ | 620 | .type = BCM_SYSPORT_STAT_NETDEV, \ |
620 | } | 621 | } |
621 | 622 | ||
623 | #define STAT_NETDEV64(m) { \ | ||
624 | .stat_string = __stringify(m), \ | ||
625 | .stat_sizeof = sizeof(((struct bcm_sysport_stats64 *)0)->m), \ | ||
626 | .stat_offset = offsetof(struct bcm_sysport_stats64, m), \ | ||
627 | .type = BCM_SYSPORT_STAT_NETDEV64, \ | ||
628 | } | ||
629 | |||
622 | #define STAT_MIB(str, m, _type) { \ | 630 | #define STAT_MIB(str, m, _type) { \ |
623 | .stat_string = str, \ | 631 | .stat_string = str, \ |
624 | .stat_sizeof = sizeof(((struct bcm_sysport_priv *)0)->m), \ | 632 | .stat_sizeof = sizeof(((struct bcm_sysport_priv *)0)->m), \ |
@@ -659,6 +667,14 @@ struct bcm_sysport_stats { | |||
659 | u16 reg_offset; | 667 | u16 reg_offset; |
660 | }; | 668 | }; |
661 | 669 | ||
670 | struct bcm_sysport_stats64 { | ||
671 | /* 64bit stats on 32bit/64bit Machine */ | ||
672 | u64 rx_packets; | ||
673 | u64 rx_bytes; | ||
674 | u64 tx_packets; | ||
675 | u64 tx_bytes; | ||
676 | }; | ||
677 | |||
662 | /* Software house keeping helper structure */ | 678 | /* Software house keeping helper structure */ |
663 | struct bcm_sysport_cb { | 679 | struct bcm_sysport_cb { |
664 | struct sk_buff *skb; /* SKB for RX packets */ | 680 | struct sk_buff *skb; /* SKB for RX packets */ |
@@ -743,5 +759,10 @@ struct bcm_sysport_priv { | |||
743 | 759 | ||
744 | /* Ethtool */ | 760 | /* Ethtool */ |
745 | u32 msg_enable; | 761 | u32 msg_enable; |
762 | |||
763 | struct bcm_sysport_stats64 stats64; | ||
764 | |||
765 | /* For atomic update generic 64bit value on 32bit Machine */ | ||
766 | struct u64_stats_sync syncp; | ||
746 | }; | 767 | }; |
747 | #endif /* __BCM_SYSPORT_H */ | 768 | #endif /* __BCM_SYSPORT_H */ |