diff options
author | Sasha Neftin <sasha.neftin@intel.com> | 2019-02-18 03:37:31 -0500 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2019-03-19 18:12:28 -0400 |
commit | 36b9fea60961d7426b6d4b0faaf609e5d820482d (patch) | |
tree | 169b454659327210a910669d3db3c5e4ee7bf225 /drivers/net/ethernet/intel/igc/igc_ethtool.c | |
parent | 6245c8483ae0110d2eb7e7cd2922dba1a5fce720 (diff) |
igc: Add support for statistics
Add support for statistics and show basic counters.
Signed-off-by: Sasha Neftin <sasha.neftin@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/igc/igc_ethtool.c')
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc_ethtool.c | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index 25d14fc82bf8..aaa1f97d5920 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c | |||
@@ -7,6 +7,115 @@ | |||
7 | 7 | ||
8 | #include "igc.h" | 8 | #include "igc.h" |
9 | 9 | ||
10 | /* forward declaration */ | ||
11 | struct igc_stats { | ||
12 | char stat_string[ETH_GSTRING_LEN]; | ||
13 | int sizeof_stat; | ||
14 | int stat_offset; | ||
15 | }; | ||
16 | |||
17 | #define IGC_STAT(_name, _stat) { \ | ||
18 | .stat_string = _name, \ | ||
19 | .sizeof_stat = FIELD_SIZEOF(struct igc_adapter, _stat), \ | ||
20 | .stat_offset = offsetof(struct igc_adapter, _stat) \ | ||
21 | } | ||
22 | |||
23 | static const struct igc_stats igc_gstrings_stats[] = { | ||
24 | IGC_STAT("rx_packets", stats.gprc), | ||
25 | IGC_STAT("tx_packets", stats.gptc), | ||
26 | IGC_STAT("rx_bytes", stats.gorc), | ||
27 | IGC_STAT("tx_bytes", stats.gotc), | ||
28 | IGC_STAT("rx_broadcast", stats.bprc), | ||
29 | IGC_STAT("tx_broadcast", stats.bptc), | ||
30 | IGC_STAT("rx_multicast", stats.mprc), | ||
31 | IGC_STAT("tx_multicast", stats.mptc), | ||
32 | IGC_STAT("multicast", stats.mprc), | ||
33 | IGC_STAT("collisions", stats.colc), | ||
34 | IGC_STAT("rx_crc_errors", stats.crcerrs), | ||
35 | IGC_STAT("rx_no_buffer_count", stats.rnbc), | ||
36 | IGC_STAT("rx_missed_errors", stats.mpc), | ||
37 | IGC_STAT("tx_aborted_errors", stats.ecol), | ||
38 | IGC_STAT("tx_carrier_errors", stats.tncrs), | ||
39 | IGC_STAT("tx_window_errors", stats.latecol), | ||
40 | IGC_STAT("tx_abort_late_coll", stats.latecol), | ||
41 | IGC_STAT("tx_deferred_ok", stats.dc), | ||
42 | IGC_STAT("tx_single_coll_ok", stats.scc), | ||
43 | IGC_STAT("tx_multi_coll_ok", stats.mcc), | ||
44 | IGC_STAT("tx_timeout_count", tx_timeout_count), | ||
45 | IGC_STAT("rx_long_length_errors", stats.roc), | ||
46 | IGC_STAT("rx_short_length_errors", stats.ruc), | ||
47 | IGC_STAT("rx_align_errors", stats.algnerrc), | ||
48 | IGC_STAT("tx_tcp_seg_good", stats.tsctc), | ||
49 | IGC_STAT("tx_tcp_seg_failed", stats.tsctfc), | ||
50 | IGC_STAT("rx_flow_control_xon", stats.xonrxc), | ||
51 | IGC_STAT("rx_flow_control_xoff", stats.xoffrxc), | ||
52 | IGC_STAT("tx_flow_control_xon", stats.xontxc), | ||
53 | IGC_STAT("tx_flow_control_xoff", stats.xofftxc), | ||
54 | IGC_STAT("rx_long_byte_count", stats.gorc), | ||
55 | IGC_STAT("tx_dma_out_of_sync", stats.doosync), | ||
56 | IGC_STAT("tx_smbus", stats.mgptc), | ||
57 | IGC_STAT("rx_smbus", stats.mgprc), | ||
58 | IGC_STAT("dropped_smbus", stats.mgpdc), | ||
59 | IGC_STAT("os2bmc_rx_by_bmc", stats.o2bgptc), | ||
60 | IGC_STAT("os2bmc_tx_by_bmc", stats.b2ospc), | ||
61 | IGC_STAT("os2bmc_tx_by_host", stats.o2bspc), | ||
62 | IGC_STAT("os2bmc_rx_by_host", stats.b2ogprc), | ||
63 | IGC_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts), | ||
64 | IGC_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped), | ||
65 | IGC_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared), | ||
66 | }; | ||
67 | |||
68 | #define IGC_NETDEV_STAT(_net_stat) { \ | ||
69 | .stat_string = __stringify(_net_stat), \ | ||
70 | .sizeof_stat = FIELD_SIZEOF(struct rtnl_link_stats64, _net_stat), \ | ||
71 | .stat_offset = offsetof(struct rtnl_link_stats64, _net_stat) \ | ||
72 | } | ||
73 | |||
74 | static const struct igc_stats igc_gstrings_net_stats[] = { | ||
75 | IGC_NETDEV_STAT(rx_errors), | ||
76 | IGC_NETDEV_STAT(tx_errors), | ||
77 | IGC_NETDEV_STAT(tx_dropped), | ||
78 | IGC_NETDEV_STAT(rx_length_errors), | ||
79 | IGC_NETDEV_STAT(rx_over_errors), | ||
80 | IGC_NETDEV_STAT(rx_frame_errors), | ||
81 | IGC_NETDEV_STAT(rx_fifo_errors), | ||
82 | IGC_NETDEV_STAT(tx_fifo_errors), | ||
83 | IGC_NETDEV_STAT(tx_heartbeat_errors) | ||
84 | }; | ||
85 | |||
86 | enum igc_diagnostics_results { | ||
87 | TEST_REG = 0, | ||
88 | TEST_EEP, | ||
89 | TEST_IRQ, | ||
90 | TEST_LOOP, | ||
91 | TEST_LINK | ||
92 | }; | ||
93 | |||
94 | static const char igc_gstrings_test[][ETH_GSTRING_LEN] = { | ||
95 | [TEST_REG] = "Register test (offline)", | ||
96 | [TEST_EEP] = "Eeprom test (offline)", | ||
97 | [TEST_IRQ] = "Interrupt test (offline)", | ||
98 | [TEST_LOOP] = "Loopback test (offline)", | ||
99 | [TEST_LINK] = "Link test (on/offline)" | ||
100 | }; | ||
101 | |||
102 | #define IGC_TEST_LEN (sizeof(igc_gstrings_test) / ETH_GSTRING_LEN) | ||
103 | |||
104 | #define IGC_GLOBAL_STATS_LEN \ | ||
105 | (sizeof(igc_gstrings_stats) / sizeof(struct igc_stats)) | ||
106 | #define IGC_NETDEV_STATS_LEN \ | ||
107 | (sizeof(igc_gstrings_net_stats) / sizeof(struct igc_stats)) | ||
108 | #define IGC_RX_QUEUE_STATS_LEN \ | ||
109 | (sizeof(struct igc_rx_queue_stats) / sizeof(u64)) | ||
110 | #define IGC_TX_QUEUE_STATS_LEN 3 /* packets, bytes, restart_queue */ | ||
111 | #define IGC_QUEUE_STATS_LEN \ | ||
112 | ((((struct igc_adapter *)netdev_priv(netdev))->num_rx_queues * \ | ||
113 | IGC_RX_QUEUE_STATS_LEN) + \ | ||
114 | (((struct igc_adapter *)netdev_priv(netdev))->num_tx_queues * \ | ||
115 | IGC_TX_QUEUE_STATS_LEN)) | ||
116 | #define IGC_STATS_LEN \ | ||
117 | (IGC_GLOBAL_STATS_LEN + IGC_NETDEV_STATS_LEN + IGC_QUEUE_STATS_LEN) | ||
118 | |||
10 | static const char igc_priv_flags_strings[][ETH_GSTRING_LEN] = { | 119 | static const char igc_priv_flags_strings[][ETH_GSTRING_LEN] = { |
11 | #define IGC_PRIV_FLAGS_LEGACY_RX BIT(0) | 120 | #define IGC_PRIV_FLAGS_LEGACY_RX BIT(0) |
12 | "legacy-rx", | 121 | "legacy-rx", |
@@ -546,6 +655,127 @@ static int igc_set_pauseparam(struct net_device *netdev, | |||
546 | return retval; | 655 | return retval; |
547 | } | 656 | } |
548 | 657 | ||
658 | static void igc_get_strings(struct net_device *netdev, u32 stringset, u8 *data) | ||
659 | { | ||
660 | struct igc_adapter *adapter = netdev_priv(netdev); | ||
661 | u8 *p = data; | ||
662 | int i; | ||
663 | |||
664 | switch (stringset) { | ||
665 | case ETH_SS_TEST: | ||
666 | memcpy(data, *igc_gstrings_test, | ||
667 | IGC_TEST_LEN * ETH_GSTRING_LEN); | ||
668 | break; | ||
669 | case ETH_SS_STATS: | ||
670 | for (i = 0; i < IGC_GLOBAL_STATS_LEN; i++) { | ||
671 | memcpy(p, igc_gstrings_stats[i].stat_string, | ||
672 | ETH_GSTRING_LEN); | ||
673 | p += ETH_GSTRING_LEN; | ||
674 | } | ||
675 | for (i = 0; i < IGC_NETDEV_STATS_LEN; i++) { | ||
676 | memcpy(p, igc_gstrings_net_stats[i].stat_string, | ||
677 | ETH_GSTRING_LEN); | ||
678 | p += ETH_GSTRING_LEN; | ||
679 | } | ||
680 | for (i = 0; i < adapter->num_tx_queues; i++) { | ||
681 | sprintf(p, "tx_queue_%u_packets", i); | ||
682 | p += ETH_GSTRING_LEN; | ||
683 | sprintf(p, "tx_queue_%u_bytes", i); | ||
684 | p += ETH_GSTRING_LEN; | ||
685 | sprintf(p, "tx_queue_%u_restart", i); | ||
686 | p += ETH_GSTRING_LEN; | ||
687 | } | ||
688 | for (i = 0; i < adapter->num_rx_queues; i++) { | ||
689 | sprintf(p, "rx_queue_%u_packets", i); | ||
690 | p += ETH_GSTRING_LEN; | ||
691 | sprintf(p, "rx_queue_%u_bytes", i); | ||
692 | p += ETH_GSTRING_LEN; | ||
693 | sprintf(p, "rx_queue_%u_drops", i); | ||
694 | p += ETH_GSTRING_LEN; | ||
695 | sprintf(p, "rx_queue_%u_csum_err", i); | ||
696 | p += ETH_GSTRING_LEN; | ||
697 | sprintf(p, "rx_queue_%u_alloc_failed", i); | ||
698 | p += ETH_GSTRING_LEN; | ||
699 | } | ||
700 | /* BUG_ON(p - data != IGC_STATS_LEN * ETH_GSTRING_LEN); */ | ||
701 | break; | ||
702 | case ETH_SS_PRIV_FLAGS: | ||
703 | memcpy(data, igc_priv_flags_strings, | ||
704 | IGC_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN); | ||
705 | break; | ||
706 | } | ||
707 | } | ||
708 | |||
709 | static int igc_get_sset_count(struct net_device *netdev, int sset) | ||
710 | { | ||
711 | switch (sset) { | ||
712 | case ETH_SS_STATS: | ||
713 | return IGC_STATS_LEN; | ||
714 | case ETH_SS_TEST: | ||
715 | return IGC_TEST_LEN; | ||
716 | case ETH_SS_PRIV_FLAGS: | ||
717 | return IGC_PRIV_FLAGS_STR_LEN; | ||
718 | default: | ||
719 | return -ENOTSUPP; | ||
720 | } | ||
721 | } | ||
722 | |||
723 | static void igc_get_ethtool_stats(struct net_device *netdev, | ||
724 | struct ethtool_stats *stats, u64 *data) | ||
725 | { | ||
726 | struct igc_adapter *adapter = netdev_priv(netdev); | ||
727 | struct rtnl_link_stats64 *net_stats = &adapter->stats64; | ||
728 | unsigned int start; | ||
729 | struct igc_ring *ring; | ||
730 | int i, j; | ||
731 | char *p; | ||
732 | |||
733 | spin_lock(&adapter->stats64_lock); | ||
734 | igc_update_stats(adapter); | ||
735 | |||
736 | for (i = 0; i < IGC_GLOBAL_STATS_LEN; i++) { | ||
737 | p = (char *)adapter + igc_gstrings_stats[i].stat_offset; | ||
738 | data[i] = (igc_gstrings_stats[i].sizeof_stat == | ||
739 | sizeof(u64)) ? *(u64 *)p : *(u32 *)p; | ||
740 | } | ||
741 | for (j = 0; j < IGC_NETDEV_STATS_LEN; j++, i++) { | ||
742 | p = (char *)net_stats + igc_gstrings_net_stats[j].stat_offset; | ||
743 | data[i] = (igc_gstrings_net_stats[j].sizeof_stat == | ||
744 | sizeof(u64)) ? *(u64 *)p : *(u32 *)p; | ||
745 | } | ||
746 | for (j = 0; j < adapter->num_tx_queues; j++) { | ||
747 | u64 restart2; | ||
748 | |||
749 | ring = adapter->tx_ring[j]; | ||
750 | do { | ||
751 | start = u64_stats_fetch_begin_irq(&ring->tx_syncp); | ||
752 | data[i] = ring->tx_stats.packets; | ||
753 | data[i + 1] = ring->tx_stats.bytes; | ||
754 | data[i + 2] = ring->tx_stats.restart_queue; | ||
755 | } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start)); | ||
756 | do { | ||
757 | start = u64_stats_fetch_begin_irq(&ring->tx_syncp2); | ||
758 | restart2 = ring->tx_stats.restart_queue2; | ||
759 | } while (u64_stats_fetch_retry_irq(&ring->tx_syncp2, start)); | ||
760 | data[i + 2] += restart2; | ||
761 | |||
762 | i += IGC_TX_QUEUE_STATS_LEN; | ||
763 | } | ||
764 | for (j = 0; j < adapter->num_rx_queues; j++) { | ||
765 | ring = adapter->rx_ring[j]; | ||
766 | do { | ||
767 | start = u64_stats_fetch_begin_irq(&ring->rx_syncp); | ||
768 | data[i] = ring->rx_stats.packets; | ||
769 | data[i + 1] = ring->rx_stats.bytes; | ||
770 | data[i + 2] = ring->rx_stats.drops; | ||
771 | data[i + 3] = ring->rx_stats.csum_err; | ||
772 | data[i + 4] = ring->rx_stats.alloc_failed; | ||
773 | } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start)); | ||
774 | i += IGC_RX_QUEUE_STATS_LEN; | ||
775 | } | ||
776 | spin_unlock(&adapter->stats64_lock); | ||
777 | } | ||
778 | |||
549 | static int igc_get_coalesce(struct net_device *netdev, | 779 | static int igc_get_coalesce(struct net_device *netdev, |
550 | struct ethtool_coalesce *ec) | 780 | struct ethtool_coalesce *ec) |
551 | { | 781 | { |
@@ -1611,6 +1841,9 @@ static const struct ethtool_ops igc_ethtool_ops = { | |||
1611 | .set_ringparam = igc_set_ringparam, | 1841 | .set_ringparam = igc_set_ringparam, |
1612 | .get_pauseparam = igc_get_pauseparam, | 1842 | .get_pauseparam = igc_get_pauseparam, |
1613 | .set_pauseparam = igc_set_pauseparam, | 1843 | .set_pauseparam = igc_set_pauseparam, |
1844 | .get_strings = igc_get_strings, | ||
1845 | .get_sset_count = igc_get_sset_count, | ||
1846 | .get_ethtool_stats = igc_get_ethtool_stats, | ||
1614 | .get_coalesce = igc_get_coalesce, | 1847 | .get_coalesce = igc_get_coalesce, |
1615 | .set_coalesce = igc_set_coalesce, | 1848 | .set_coalesce = igc_set_coalesce, |
1616 | .get_rxnfc = igc_get_rxnfc, | 1849 | .get_rxnfc = igc_get_rxnfc, |