xref: /linux/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c (revision 4eca0ef49af9b2b0c52ef2b58e045ab34629796b)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */
3 
4 #include <linux/pci.h>
5 #include <linux/phy.h>
6 #include <linux/ethtool.h>
7 
8 #include "wx_type.h"
9 #include "wx_ethtool.h"
10 #include "wx_hw.h"
11 
12 struct wx_stats {
13 	char stat_string[ETH_GSTRING_LEN];
14 	size_t sizeof_stat;
15 	off_t stat_offset;
16 };
17 
18 #define WX_STAT(str, m) { \
19 		.stat_string = str, \
20 		.sizeof_stat = sizeof(((struct wx *)0)->m), \
21 		.stat_offset = offsetof(struct wx, m) }
22 
23 static const struct wx_stats wx_gstrings_stats[] = {
24 	WX_STAT("rx_dma_pkts", stats.gprc),
25 	WX_STAT("tx_dma_pkts", stats.gptc),
26 	WX_STAT("rx_dma_bytes", stats.gorc),
27 	WX_STAT("tx_dma_bytes", stats.gotc),
28 	WX_STAT("rx_total_pkts", stats.tpr),
29 	WX_STAT("tx_total_pkts", stats.tpt),
30 	WX_STAT("rx_long_length_count", stats.roc),
31 	WX_STAT("rx_short_length_count", stats.ruc),
32 	WX_STAT("os2bmc_rx_by_bmc", stats.o2bgptc),
33 	WX_STAT("os2bmc_tx_by_bmc", stats.b2ospc),
34 	WX_STAT("os2bmc_tx_by_host", stats.o2bspc),
35 	WX_STAT("os2bmc_rx_by_host", stats.b2ogprc),
36 	WX_STAT("rx_no_dma_resources", stats.rdmdrop),
37 	WX_STAT("tx_busy", tx_busy),
38 	WX_STAT("non_eop_descs", non_eop_descs),
39 	WX_STAT("tx_restart_queue", restart_queue),
40 	WX_STAT("rx_csum_offload_good_count", hw_csum_rx_good),
41 	WX_STAT("rx_csum_offload_errors", hw_csum_rx_error),
42 	WX_STAT("alloc_rx_buff_failed", alloc_rx_buff_failed),
43 };
44 
45 /* drivers allocates num_tx_queues and num_rx_queues symmetrically so
46  * we set the num_rx_queues to evaluate to num_tx_queues. This is
47  * used because we do not have a good way to get the max number of
48  * rx queues with CONFIG_RPS disabled.
49  */
50 #define WX_NUM_RX_QUEUES netdev->num_tx_queues
51 #define WX_NUM_TX_QUEUES netdev->num_tx_queues
52 
53 #define WX_QUEUE_STATS_LEN ( \
54 		(WX_NUM_TX_QUEUES + WX_NUM_RX_QUEUES) * \
55 		(sizeof(struct wx_queue_stats) / sizeof(u64)))
56 #define WX_GLOBAL_STATS_LEN  ARRAY_SIZE(wx_gstrings_stats)
57 #define WX_STATS_LEN (WX_GLOBAL_STATS_LEN + WX_QUEUE_STATS_LEN)
58 
59 int wx_get_sset_count(struct net_device *netdev, int sset)
60 {
61 	switch (sset) {
62 	case ETH_SS_STATS:
63 		return WX_STATS_LEN;
64 	default:
65 		return -EOPNOTSUPP;
66 	}
67 }
68 EXPORT_SYMBOL(wx_get_sset_count);
69 
70 void wx_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
71 {
72 	u8 *p = data;
73 	int i;
74 
75 	switch (stringset) {
76 	case ETH_SS_STATS:
77 		for (i = 0; i < WX_GLOBAL_STATS_LEN; i++)
78 			ethtool_sprintf(&p, wx_gstrings_stats[i].stat_string);
79 		for (i = 0; i < netdev->num_tx_queues; i++) {
80 			ethtool_sprintf(&p, "tx_queue_%u_packets", i);
81 			ethtool_sprintf(&p, "tx_queue_%u_bytes", i);
82 		}
83 		for (i = 0; i < WX_NUM_RX_QUEUES; i++) {
84 			ethtool_sprintf(&p, "rx_queue_%u_packets", i);
85 			ethtool_sprintf(&p, "rx_queue_%u_bytes", i);
86 		}
87 		break;
88 	}
89 }
90 EXPORT_SYMBOL(wx_get_strings);
91 
92 void wx_get_ethtool_stats(struct net_device *netdev,
93 			  struct ethtool_stats *stats, u64 *data)
94 {
95 	struct wx *wx = netdev_priv(netdev);
96 	struct wx_ring *ring;
97 	unsigned int start;
98 	int i, j;
99 	char *p;
100 
101 	wx_update_stats(wx);
102 
103 	for (i = 0; i < WX_GLOBAL_STATS_LEN; i++) {
104 		p = (char *)wx + wx_gstrings_stats[i].stat_offset;
105 		data[i] = (wx_gstrings_stats[i].sizeof_stat ==
106 			   sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
107 	}
108 
109 	for (j = 0; j < netdev->num_tx_queues; j++) {
110 		ring = wx->tx_ring[j];
111 		if (!ring) {
112 			data[i++] = 0;
113 			data[i++] = 0;
114 			continue;
115 		}
116 
117 		do {
118 			start = u64_stats_fetch_begin(&ring->syncp);
119 			data[i] = ring->stats.packets;
120 			data[i + 1] = ring->stats.bytes;
121 		} while (u64_stats_fetch_retry(&ring->syncp, start));
122 		i += 2;
123 	}
124 	for (j = 0; j < WX_NUM_RX_QUEUES; j++) {
125 		ring = wx->rx_ring[j];
126 		if (!ring) {
127 			data[i++] = 0;
128 			data[i++] = 0;
129 			continue;
130 		}
131 
132 		do {
133 			start = u64_stats_fetch_begin(&ring->syncp);
134 			data[i] = ring->stats.packets;
135 			data[i + 1] = ring->stats.bytes;
136 		} while (u64_stats_fetch_retry(&ring->syncp, start));
137 		i += 2;
138 	}
139 }
140 EXPORT_SYMBOL(wx_get_ethtool_stats);
141 
142 void wx_get_mac_stats(struct net_device *netdev,
143 		      struct ethtool_eth_mac_stats *mac_stats)
144 {
145 	struct wx *wx = netdev_priv(netdev);
146 	struct wx_hw_stats *hwstats;
147 
148 	wx_update_stats(wx);
149 
150 	hwstats = &wx->stats;
151 	mac_stats->MulticastFramesXmittedOK = hwstats->mptc;
152 	mac_stats->BroadcastFramesXmittedOK = hwstats->bptc;
153 	mac_stats->MulticastFramesReceivedOK = hwstats->mprc;
154 	mac_stats->BroadcastFramesReceivedOK = hwstats->bprc;
155 }
156 EXPORT_SYMBOL(wx_get_mac_stats);
157 
158 void wx_get_pause_stats(struct net_device *netdev,
159 			struct ethtool_pause_stats *stats)
160 {
161 	struct wx *wx = netdev_priv(netdev);
162 	struct wx_hw_stats *hwstats;
163 
164 	wx_update_stats(wx);
165 
166 	hwstats = &wx->stats;
167 	stats->tx_pause_frames = hwstats->lxontxc + hwstats->lxofftxc;
168 	stats->rx_pause_frames = hwstats->lxonoffrxc;
169 }
170 EXPORT_SYMBOL(wx_get_pause_stats);
171 
172 void wx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
173 {
174 	struct wx *wx = netdev_priv(netdev);
175 
176 	strscpy(info->driver, wx->driver_name, sizeof(info->driver));
177 	strscpy(info->fw_version, wx->eeprom_id, sizeof(info->fw_version));
178 	strscpy(info->bus_info, pci_name(wx->pdev), sizeof(info->bus_info));
179 	if (wx->num_tx_queues <= WX_NUM_TX_QUEUES) {
180 		info->n_stats = WX_STATS_LEN -
181 				   (WX_NUM_TX_QUEUES - wx->num_tx_queues) *
182 				   (sizeof(struct wx_queue_stats) / sizeof(u64)) * 2;
183 	} else {
184 		info->n_stats = WX_STATS_LEN;
185 	}
186 }
187 EXPORT_SYMBOL(wx_get_drvinfo);
188