xref: /linux/drivers/net/ethernet/alibaba/eea/eea_ethtool.c (revision 5f4f7bc0ed1180a1bff423c39e05256172805b5d)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Driver for Alibaba Elastic Ethernet Adapter.
4  *
5  * Copyright (C) 2025 Alibaba Inc.
6  */
7 
8 #include <linux/ethtool.h>
9 #include <linux/ethtool_netlink.h>
10 #include <linux/rtnetlink.h>
11 
12 #include "eea_adminq.h"
13 #include "eea_net.h"
14 #include "eea_pci.h"
15 
16 struct eea_stat_desc {
17 	char desc[ETH_GSTRING_LEN];
18 	size_t offset;
19 };
20 
21 #define EEA_TX_STAT(m)	{#m, offsetof(struct eea_tx_stats, m)}
22 #define EEA_RX_STAT(m)	{#m, offsetof(struct eea_rx_stats, m)}
23 
24 static const struct eea_stat_desc eea_rx_stats_desc[] = {
25 	EEA_RX_STAT(descs),
26 	EEA_RX_STAT(kicks),
27 };
28 
29 static const struct eea_stat_desc eea_tx_stats_desc[] = {
30 	EEA_TX_STAT(descs),
31 	EEA_TX_STAT(kicks),
32 };
33 
34 #define EEA_TX_STATS_LEN	ARRAY_SIZE(eea_tx_stats_desc)
35 #define EEA_RX_STATS_LEN	ARRAY_SIZE(eea_rx_stats_desc)
36 
37 static void eea_get_drvinfo(struct net_device *netdev,
38 			    struct ethtool_drvinfo *info)
39 {
40 	struct eea_net *enet = netdev_priv(netdev);
41 	struct eea_device *edev = enet->edev;
42 
43 	strscpy(info->driver,   KBUILD_MODNAME,     sizeof(info->driver));
44 	strscpy(info->bus_info, eea_pci_name(edev), sizeof(info->bus_info));
45 }
46 
47 static void eea_get_ringparam(struct net_device *netdev,
48 			      struct ethtool_ringparam *ring,
49 			      struct kernel_ethtool_ringparam *kernel_ring,
50 			      struct netlink_ext_ack *extack)
51 {
52 	struct eea_net *enet = netdev_priv(netdev);
53 
54 	ring->rx_max_pending = enet->cfg_hw.rx_ring_depth;
55 	ring->tx_max_pending = enet->cfg_hw.tx_ring_depth;
56 	ring->rx_pending = enet->cfg.rx_ring_depth;
57 	ring->tx_pending = enet->cfg.tx_ring_depth;
58 
59 	kernel_ring->tcp_data_split = enet->cfg.split_hdr ?
60 				      ETHTOOL_TCP_DATA_SPLIT_ENABLED :
61 				      ETHTOOL_TCP_DATA_SPLIT_DISABLED;
62 }
63 
64 static int eea_set_ringparam(struct net_device *netdev,
65 			     struct ethtool_ringparam *ring,
66 			     struct kernel_ethtool_ringparam *kernel_ring,
67 			     struct netlink_ext_ack *extack)
68 {
69 	struct eea_net *enet = netdev_priv(netdev);
70 	struct eea_net_init_ctx ctx;
71 	bool need_update = false;
72 	struct eea_net_cfg *cfg;
73 	bool sh;
74 
75 	if (ring->rx_pending < EEA_NET_IO_RING_DEPTH_MIN ||
76 	    ring->tx_pending < EEA_NET_IO_RING_DEPTH_MIN)
77 		return -EINVAL;
78 
79 	if (!is_power_of_2(ring->rx_pending) ||
80 	    !is_power_of_2(ring->tx_pending))
81 		return -EINVAL;
82 
83 	eea_init_ctx(enet, &ctx);
84 
85 	cfg = &ctx.cfg;
86 
87 	if (ring->rx_pending != cfg->rx_ring_depth)
88 		need_update = true;
89 
90 	if (ring->tx_pending != cfg->tx_ring_depth)
91 		need_update = true;
92 
93 	sh = false;
94 
95 	switch (kernel_ring->tcp_data_split) {
96 	case ETHTOOL_TCP_DATA_SPLIT_ENABLED:
97 		sh = true;
98 		break;
99 
100 	case ETHTOOL_TCP_DATA_SPLIT_DISABLED:
101 		sh = false;
102 		break;
103 
104 	case ETHTOOL_TCP_DATA_SPLIT_UNKNOWN:
105 		sh = !!cfg->split_hdr;
106 		break;
107 	}
108 
109 	if (sh != !!(cfg->split_hdr))
110 		need_update = true;
111 
112 	if (!need_update)
113 		return 0;
114 
115 	cfg->rx_ring_depth = ring->rx_pending;
116 	cfg->tx_ring_depth = ring->tx_pending;
117 
118 	/* By default, enet->cfg_hw.split_hdr is 128. */
119 	cfg->split_hdr = sh ? enet->cfg_hw.split_hdr : 0;
120 
121 	return eea_reset_hw_resources(enet, &ctx);
122 }
123 
124 static int eea_set_channels(struct net_device *netdev,
125 			    struct ethtool_channels *channels)
126 {
127 	struct eea_net *enet = netdev_priv(netdev);
128 	u16 queue_pairs = channels->combined_count;
129 	struct eea_net_init_ctx ctx;
130 	struct eea_net_cfg *cfg;
131 
132 	eea_init_ctx(enet, &ctx);
133 
134 	cfg = &ctx.cfg;
135 
136 	cfg->rx_ring_num = queue_pairs;
137 	cfg->tx_ring_num = queue_pairs;
138 
139 	return eea_reset_hw_resources(enet, &ctx);
140 }
141 
142 static void eea_get_channels(struct net_device *netdev,
143 			     struct ethtool_channels *channels)
144 {
145 	struct eea_net *enet = netdev_priv(netdev);
146 
147 	channels->combined_count = enet->cfg.rx_ring_num;
148 	channels->max_combined   = enet->cfg_hw.rx_ring_num;
149 }
150 
151 static void eea_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
152 {
153 	struct eea_net *enet = netdev_priv(netdev);
154 	u8 *p = data;
155 	u32 i, j;
156 
157 	if (stringset != ETH_SS_STATS)
158 		return;
159 
160 	for (i = 0; i < enet->cfg.rx_ring_num; i++) {
161 		for (j = 0; j < EEA_RX_STATS_LEN; j++)
162 			ethtool_sprintf(&p, "rx%u_%s", i,
163 					eea_rx_stats_desc[j].desc);
164 	}
165 
166 	for (i = 0; i < enet->cfg.tx_ring_num; i++) {
167 		for (j = 0; j < EEA_TX_STATS_LEN; j++)
168 			ethtool_sprintf(&p, "tx%u_%s", i,
169 					eea_tx_stats_desc[j].desc);
170 	}
171 }
172 
173 static int eea_get_sset_count(struct net_device *netdev, int sset)
174 {
175 	struct eea_net *enet = netdev_priv(netdev);
176 
177 	if (sset != ETH_SS_STATS)
178 		return -EOPNOTSUPP;
179 
180 	return enet->cfg.rx_ring_num * EEA_RX_STATS_LEN +
181 		enet->cfg.tx_ring_num * EEA_TX_STATS_LEN;
182 }
183 
184 static void eea_stats_fill_for_q(struct u64_stats_sync *syncp, u32 num,
185 				 const struct eea_stat_desc *desc,
186 				 u64 *data, u32 idx)
187 {
188 	void *stats_base = syncp;
189 	u32 start, i;
190 
191 	do {
192 		start = u64_stats_fetch_begin(syncp);
193 		for (i = 0; i < num; i++)
194 			data[idx + i] =
195 				u64_stats_read(stats_base + desc[i].offset);
196 
197 	} while (u64_stats_fetch_retry(syncp, start));
198 
199 	BUILD_BUG_ON(offsetof(struct eea_tx_stats, syncp));
200 	BUILD_BUG_ON(offsetof(struct eea_rx_stats, syncp));
201 }
202 
203 static void eea_get_ethtool_stats(struct net_device *netdev,
204 				  struct ethtool_stats *stats, u64 *data)
205 {
206 	struct eea_net *enet = netdev_priv(netdev);
207 	u32 i, idx = 0;
208 
209 	ASSERT_RTNL();
210 
211 	if (enet->rx) {
212 		for (i = 0; i < enet->cfg.rx_ring_num; i++) {
213 			struct eea_net_rx *rx = enet->rx[i];
214 
215 			eea_stats_fill_for_q(&rx->stats.syncp, EEA_RX_STATS_LEN,
216 					     eea_rx_stats_desc, data, idx);
217 
218 			idx += EEA_RX_STATS_LEN;
219 		}
220 	}
221 
222 	if (enet->tx) {
223 		for (i = 0; i < enet->cfg.tx_ring_num; i++) {
224 			struct eea_net_tx *tx = &enet->tx[i];
225 
226 			eea_stats_fill_for_q(&tx->stats.syncp, EEA_TX_STATS_LEN,
227 					     eea_tx_stats_desc, data, idx);
228 
229 			idx += EEA_TX_STATS_LEN;
230 		}
231 	}
232 }
233 
234 void eea_update_rx_stats(struct eea_rx_stats *rx_stats,
235 			 struct eea_rx_ctx_stats *stats)
236 {
237 	u64_stats_update_begin(&rx_stats->syncp);
238 	u64_stats_add(&rx_stats->descs,             stats->descs);
239 	u64_stats_add(&rx_stats->packets,           stats->packets);
240 	u64_stats_add(&rx_stats->bytes,             stats->bytes);
241 	u64_stats_add(&rx_stats->drops,             stats->drops);
242 	u64_stats_add(&rx_stats->split_hdr_bytes,   stats->split_hdr_bytes);
243 	u64_stats_add(&rx_stats->split_hdr_packets, stats->split_hdr_packets);
244 	u64_stats_add(&rx_stats->length_errors,     stats->length_errors);
245 	u64_stats_add(&rx_stats->kicks,             stats->kicks);
246 	u64_stats_update_end(&rx_stats->syncp);
247 }
248 
249 static int eea_get_link_ksettings(struct net_device *netdev,
250 				  struct ethtool_link_ksettings *cmd)
251 {
252 	struct eea_net *enet = netdev_priv(netdev);
253 
254 	cmd->base.speed  = enet->speed;
255 	cmd->base.duplex = enet->duplex;
256 	cmd->base.port   = PORT_OTHER;
257 
258 	return 0;
259 }
260 
261 const struct ethtool_ops eea_ethtool_ops = {
262 	.supported_ring_params = ETHTOOL_RING_USE_TCP_DATA_SPLIT,
263 	.get_drvinfo        = eea_get_drvinfo,
264 	.get_link           = ethtool_op_get_link,
265 	.get_ringparam      = eea_get_ringparam,
266 	.set_ringparam      = eea_set_ringparam,
267 	.set_channels       = eea_set_channels,
268 	.get_channels       = eea_get_channels,
269 	.get_strings        = eea_get_strings,
270 	.get_sset_count     = eea_get_sset_count,
271 	.get_ethtool_stats  = eea_get_ethtool_stats,
272 	.get_link_ksettings = eea_get_link_ksettings,
273 };
274