Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: systemport: Support 64bit statistics

When using Broadcom Systemport device in 32bit Platform, ifconfig can
only report up to 4G tx,rx status, which will be wrapped to 0 when the
number of incoming or outgoing packets exceeds 4G, only taking
around 2 hours in busy network environment (such as streaming).
Therefore, it makes hard for network diagnostic tool to get reliable
statistical result, so the patch is used to add 64bit support for
Broadcom Systemport device in 32bit Platform.

This patch provides 64bit statistics capability on both ethtool and ifconfig.

Signed-off-by: Jianming.qiao <kiki-good@hotmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

kiki good and committed by
David S. Miller
10377ba7 2470f3a2

+82 -17
+61 -17
drivers/net/ethernet/broadcom/bcmsysport.c
··· 201 201 */ 202 202 static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = { 203 203 /* general stats */ 204 - STAT_NETDEV(rx_packets), 205 - STAT_NETDEV(tx_packets), 206 - STAT_NETDEV(rx_bytes), 207 - STAT_NETDEV(tx_bytes), 204 + STAT_NETDEV64(rx_packets), 205 + STAT_NETDEV64(tx_packets), 206 + STAT_NETDEV64(rx_bytes), 207 + STAT_NETDEV64(tx_bytes), 208 208 STAT_NETDEV(rx_errors), 209 209 STAT_NETDEV(tx_errors), 210 210 STAT_NETDEV(rx_dropped), ··· 316 316 { 317 317 switch (type) { 318 318 case BCM_SYSPORT_STAT_NETDEV: 319 + case BCM_SYSPORT_STAT_NETDEV64: 319 320 case BCM_SYSPORT_STAT_RXCHK: 320 321 case BCM_SYSPORT_STAT_RBUF: 321 322 case BCM_SYSPORT_STAT_SOFT: ··· 399 398 s = &bcm_sysport_gstrings_stats[i]; 400 399 switch (s->type) { 401 400 case BCM_SYSPORT_STAT_NETDEV: 401 + case BCM_SYSPORT_STAT_NETDEV64: 402 402 case BCM_SYSPORT_STAT_SOFT: 403 403 continue; 404 404 case BCM_SYSPORT_STAT_MIB_RX: ··· 436 434 struct ethtool_stats *stats, u64 *data) 437 435 { 438 436 struct bcm_sysport_priv *priv = netdev_priv(dev); 437 + struct bcm_sysport_stats64 *stats64 = &priv->stats64; 438 + struct u64_stats_sync *syncp = &priv->syncp; 439 439 struct bcm_sysport_tx_ring *ring; 440 + unsigned int start; 440 441 int i, j; 441 442 442 443 if (netif_running(dev)) ··· 452 447 s = &bcm_sysport_gstrings_stats[i]; 453 448 if (s->type == BCM_SYSPORT_STAT_NETDEV) 454 449 p = (char *)&dev->stats; 450 + else if (s->type == BCM_SYSPORT_STAT_NETDEV64) 451 + p = (char *)stats64; 455 452 else 456 453 p = (char *)priv; 454 + 457 455 p += s->stat_offset; 458 - data[j] = *(unsigned long *)p; 456 + 457 + if (s->stat_sizeof == sizeof(u64)) 458 + do { 459 + start = u64_stats_fetch_begin_irq(syncp); 460 + data[i] = *(u64 *)p; 461 + } while (u64_stats_fetch_retry_irq(syncp, start)); 462 + else 463 + data[i] = *(u32 *)p; 459 464 j++; 460 465 } 461 466 ··· 677 662 static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv, 678 663 unsigned int budget) 679 664 { 665 + struct bcm_sysport_stats64 *stats64 = &priv->stats64; 680 666 struct net_device *ndev = priv->netdev; 681 667 unsigned int processed = 0, to_process; 682 668 struct bcm_sysport_cb *cb; ··· 781 765 skb->protocol = eth_type_trans(skb, ndev); 782 766 ndev->stats.rx_packets++; 783 767 ndev->stats.rx_bytes += len; 768 + u64_stats_update_begin(&priv->syncp); 769 + stats64->rx_packets++; 770 + stats64->rx_bytes += len; 771 + u64_stats_update_end(&priv->syncp); 784 772 785 773 napi_gro_receive(&priv->napi, skb); 786 774 next: ··· 807 787 struct device *kdev = &priv->pdev->dev; 808 788 809 789 if (cb->skb) { 810 - ring->bytes += cb->skb->len; 811 790 *bytes_compl += cb->skb->len; 812 791 dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr), 813 792 dma_unmap_len(cb, dma_len), 814 793 DMA_TO_DEVICE); 815 - ring->packets++; 816 794 (*pkts_compl)++; 817 795 bcm_sysport_free_cb(cb); 818 796 /* SKB fragment */ 819 797 } else if (dma_unmap_addr(cb, dma_addr)) { 820 - ring->bytes += dma_unmap_len(cb, dma_len); 798 + *bytes_compl += dma_unmap_len(cb, dma_len); 821 799 dma_unmap_page(kdev, dma_unmap_addr(cb, dma_addr), 822 800 dma_unmap_len(cb, dma_len), DMA_TO_DEVICE); 823 801 dma_unmap_addr_set(cb, dma_addr, 0); ··· 826 808 static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, 827 809 struct bcm_sysport_tx_ring *ring) 828 810 { 829 - struct net_device *ndev = priv->netdev; 830 811 unsigned int c_index, last_c_index, last_tx_cn, num_tx_cbs; 831 812 unsigned int pkts_compl = 0, bytes_compl = 0; 813 + struct net_device *ndev = priv->netdev; 832 814 struct bcm_sysport_cb *cb; 833 815 u32 hw_ind; 834 816 ··· 866 848 last_c_index++; 867 849 last_c_index &= (num_tx_cbs - 1); 868 850 } 851 + 852 + u64_stats_update_begin(&priv->syncp); 853 + ring->packets += pkts_compl; 854 + ring->bytes += bytes_compl; 855 + u64_stats_update_end(&priv->syncp); 869 856 870 857 ring->c_index = c_index; 871 858 ··· 1694 1671 return 0; 1695 1672 } 1696 1673 1697 - static struct net_device_stats *bcm_sysport_get_nstats(struct net_device *dev) 1674 + static void bcm_sysport_get_stats64(struct net_device *dev, 1675 + struct rtnl_link_stats64 *stats) 1698 1676 { 1699 1677 struct bcm_sysport_priv *priv = netdev_priv(dev); 1700 - unsigned long tx_bytes = 0, tx_packets = 0; 1678 + struct bcm_sysport_stats64 *stats64 = &priv->stats64; 1701 1679 struct bcm_sysport_tx_ring *ring; 1680 + u64 tx_packets = 0, tx_bytes = 0; 1681 + unsigned int start; 1702 1682 unsigned int q; 1683 + 1684 + netdev_stats_to_stats64(stats, &dev->stats); 1703 1685 1704 1686 for (q = 0; q < dev->num_tx_queues; q++) { 1705 1687 ring = &priv->tx_rings[q]; 1706 - tx_bytes += ring->bytes; 1707 - tx_packets += ring->packets; 1688 + do { 1689 + start = u64_stats_fetch_begin_irq(&priv->syncp); 1690 + tx_bytes = ring->bytes; 1691 + tx_packets = ring->packets; 1692 + } while (u64_stats_fetch_retry_irq(&priv->syncp, start)); 1693 + 1694 + stats->tx_bytes += tx_bytes; 1695 + stats->tx_packets += tx_packets; 1708 1696 } 1709 1697 1710 - dev->stats.tx_bytes = tx_bytes; 1711 - dev->stats.tx_packets = tx_packets; 1712 - return &dev->stats; 1698 + /* lockless update tx_bytes and tx_packets */ 1699 + u64_stats_update_begin(&priv->syncp); 1700 + stats64->tx_bytes = stats->tx_bytes; 1701 + stats64->tx_packets = stats->tx_packets; 1702 + u64_stats_update_end(&priv->syncp); 1703 + 1704 + do { 1705 + start = u64_stats_fetch_begin_irq(&priv->syncp); 1706 + stats->rx_packets = stats64->rx_packets; 1707 + stats->rx_bytes = stats64->rx_bytes; 1708 + } while (u64_stats_fetch_retry_irq(&priv->syncp, start)); 1713 1709 } 1714 1710 1715 1711 static void bcm_sysport_netif_start(struct net_device *dev) ··· 1992 1950 #ifdef CONFIG_NET_POLL_CONTROLLER 1993 1951 .ndo_poll_controller = bcm_sysport_poll_controller, 1994 1952 #endif 1995 - .ndo_get_stats = bcm_sysport_get_nstats, 1953 + .ndo_get_stats64 = bcm_sysport_get_stats64, 1996 1954 }; 1997 1955 1998 1956 #define REV_FMT "v%2x.%02x" ··· 2139 2097 2140 2098 /* libphy will adjust the link state accordingly */ 2141 2099 netif_carrier_off(dev); 2100 + 2101 + u64_stats_init(&priv->syncp); 2142 2102 2143 2103 ret = register_netdev(dev); 2144 2104 if (ret) {
+21
drivers/net/ethernet/broadcom/bcmsysport.h
··· 603 603 /* HW maintains a large list of counters */ 604 604 enum bcm_sysport_stat_type { 605 605 BCM_SYSPORT_STAT_NETDEV = -1, 606 + BCM_SYSPORT_STAT_NETDEV64, 606 607 BCM_SYSPORT_STAT_MIB_RX, 607 608 BCM_SYSPORT_STAT_MIB_TX, 608 609 BCM_SYSPORT_STAT_RUNT, ··· 618 617 .stat_sizeof = sizeof(((struct net_device_stats *)0)->m), \ 619 618 .stat_offset = offsetof(struct net_device_stats, m), \ 620 619 .type = BCM_SYSPORT_STAT_NETDEV, \ 620 + } 621 + 622 + #define STAT_NETDEV64(m) { \ 623 + .stat_string = __stringify(m), \ 624 + .stat_sizeof = sizeof(((struct bcm_sysport_stats64 *)0)->m), \ 625 + .stat_offset = offsetof(struct bcm_sysport_stats64, m), \ 626 + .type = BCM_SYSPORT_STAT_NETDEV64, \ 621 627 } 622 628 623 629 #define STAT_MIB(str, m, _type) { \ ··· 665 657 enum bcm_sysport_stat_type type; 666 658 /* reg offset from UMAC base for misc counters */ 667 659 u16 reg_offset; 660 + }; 661 + 662 + struct bcm_sysport_stats64 { 663 + /* 64bit stats on 32bit/64bit Machine */ 664 + u64 rx_packets; 665 + u64 rx_bytes; 666 + u64 tx_packets; 667 + u64 tx_bytes; 668 668 }; 669 669 670 670 /* Software house keeping helper structure */ ··· 759 743 760 744 /* Ethtool */ 761 745 u32 msg_enable; 746 + 747 + struct bcm_sysport_stats64 stats64; 748 + 749 + /* For atomic update generic 64bit value on 32bit Machine */ 750 + struct u64_stats_sync syncp; 762 751 }; 763 752 #endif /* __BCM_SYSPORT_H */