aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.c78
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.h21
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 */
202static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = { 202static 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)
662static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv, 677static 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);
770next: 790next:
@@ -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,
808static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, 826static 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
1674static struct net_device_stats *bcm_sysport_get_nstats(struct net_device *dev) 1697static 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
1692static void bcm_sysport_netif_start(struct net_device *dev) 1734static 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 */
604enum bcm_sysport_stat_type { 604enum 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
670struct 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 */
663struct bcm_sysport_cb { 679struct 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 */