1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Marvell Octeon EP (EndPoint) Ethernet Driver |
3 | * |
4 | * Copyright (C) 2020 Marvell. |
5 | * |
6 | */ |
7 | |
8 | #include <linux/pci.h> |
9 | #include <linux/netdevice.h> |
10 | #include <linux/ethtool.h> |
11 | |
12 | #include "octep_config.h" |
13 | #include "octep_main.h" |
14 | #include "octep_ctrl_net.h" |
15 | |
16 | static const char octep_gstrings_global_stats[][ETH_GSTRING_LEN] = { |
17 | "rx_packets" , |
18 | "tx_packets" , |
19 | "rx_bytes" , |
20 | "tx_bytes" , |
21 | "rx_alloc_errors" , |
22 | "tx_busy_errors" , |
23 | "rx_dropped" , |
24 | "tx_dropped" , |
25 | "tx_hw_pkts" , |
26 | "tx_hw_octs" , |
27 | "tx_hw_bcast" , |
28 | "tx_hw_mcast" , |
29 | "tx_hw_underflow" , |
30 | "tx_hw_control" , |
31 | "tx_less_than_64" , |
32 | "tx_equal_64" , |
33 | "tx_equal_65_to_127" , |
34 | "tx_equal_128_to_255" , |
35 | "tx_equal_256_to_511" , |
36 | "tx_equal_512_to_1023" , |
37 | "tx_equal_1024_to_1518" , |
38 | "tx_greater_than_1518" , |
39 | "rx_hw_pkts" , |
40 | "rx_hw_bytes" , |
41 | "rx_hw_bcast" , |
42 | "rx_hw_mcast" , |
43 | "rx_pause_pkts" , |
44 | "rx_pause_bytes" , |
45 | "rx_dropped_pkts_fifo_full" , |
46 | "rx_dropped_bytes_fifo_full" , |
47 | "rx_err_pkts" , |
48 | }; |
49 | |
50 | #define OCTEP_GLOBAL_STATS_CNT (sizeof(octep_gstrings_global_stats) / ETH_GSTRING_LEN) |
51 | |
52 | static const char octep_gstrings_tx_q_stats[][ETH_GSTRING_LEN] = { |
53 | "tx_packets_posted[Q-%u]" , |
54 | "tx_packets_completed[Q-%u]" , |
55 | "tx_bytes[Q-%u]" , |
56 | "tx_busy[Q-%u]" , |
57 | }; |
58 | |
59 | #define OCTEP_TX_Q_STATS_CNT (sizeof(octep_gstrings_tx_q_stats) / ETH_GSTRING_LEN) |
60 | |
61 | static const char octep_gstrings_rx_q_stats[][ETH_GSTRING_LEN] = { |
62 | "rx_packets[Q-%u]" , |
63 | "rx_bytes[Q-%u]" , |
64 | "rx_alloc_errors[Q-%u]" , |
65 | }; |
66 | |
67 | #define OCTEP_RX_Q_STATS_CNT (sizeof(octep_gstrings_rx_q_stats) / ETH_GSTRING_LEN) |
68 | |
69 | static void octep_get_drvinfo(struct net_device *netdev, |
70 | struct ethtool_drvinfo *info) |
71 | { |
72 | struct octep_device *oct = netdev_priv(dev: netdev); |
73 | |
74 | strscpy(info->driver, OCTEP_DRV_NAME, sizeof(info->driver)); |
75 | strscpy(info->bus_info, pci_name(oct->pdev), sizeof(info->bus_info)); |
76 | } |
77 | |
78 | static void octep_get_strings(struct net_device *netdev, |
79 | u32 stringset, u8 *data) |
80 | { |
81 | struct octep_device *oct = netdev_priv(dev: netdev); |
82 | u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); |
83 | char *strings = (char *)data; |
84 | int i, j; |
85 | |
86 | switch (stringset) { |
87 | case ETH_SS_STATS: |
88 | for (i = 0; i < OCTEP_GLOBAL_STATS_CNT; i++) { |
89 | snprintf(buf: strings, ETH_GSTRING_LEN, |
90 | fmt: octep_gstrings_global_stats[i]); |
91 | strings += ETH_GSTRING_LEN; |
92 | } |
93 | |
94 | for (i = 0; i < num_queues; i++) { |
95 | for (j = 0; j < OCTEP_TX_Q_STATS_CNT; j++) { |
96 | snprintf(buf: strings, ETH_GSTRING_LEN, |
97 | fmt: octep_gstrings_tx_q_stats[j], i); |
98 | strings += ETH_GSTRING_LEN; |
99 | } |
100 | } |
101 | |
102 | for (i = 0; i < num_queues; i++) { |
103 | for (j = 0; j < OCTEP_RX_Q_STATS_CNT; j++) { |
104 | snprintf(buf: strings, ETH_GSTRING_LEN, |
105 | fmt: octep_gstrings_rx_q_stats[j], i); |
106 | strings += ETH_GSTRING_LEN; |
107 | } |
108 | } |
109 | break; |
110 | default: |
111 | break; |
112 | } |
113 | } |
114 | |
115 | static int octep_get_sset_count(struct net_device *netdev, int sset) |
116 | { |
117 | struct octep_device *oct = netdev_priv(dev: netdev); |
118 | u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); |
119 | |
120 | switch (sset) { |
121 | case ETH_SS_STATS: |
122 | return OCTEP_GLOBAL_STATS_CNT + (num_queues * |
123 | (OCTEP_TX_Q_STATS_CNT + OCTEP_RX_Q_STATS_CNT)); |
124 | break; |
125 | default: |
126 | return -EOPNOTSUPP; |
127 | } |
128 | } |
129 | |
130 | static void |
131 | octep_get_ethtool_stats(struct net_device *netdev, |
132 | struct ethtool_stats *stats, u64 *data) |
133 | { |
134 | struct octep_device *oct = netdev_priv(dev: netdev); |
135 | struct octep_iface_tx_stats *iface_tx_stats; |
136 | struct octep_iface_rx_stats *iface_rx_stats; |
137 | u64 rx_packets, rx_bytes; |
138 | u64 tx_packets, tx_bytes; |
139 | u64 rx_alloc_errors, tx_busy_errors; |
140 | int q, i; |
141 | |
142 | rx_packets = 0; |
143 | rx_bytes = 0; |
144 | tx_packets = 0; |
145 | tx_bytes = 0; |
146 | rx_alloc_errors = 0; |
147 | tx_busy_errors = 0; |
148 | tx_packets = 0; |
149 | tx_bytes = 0; |
150 | rx_packets = 0; |
151 | rx_bytes = 0; |
152 | |
153 | iface_tx_stats = &oct->iface_tx_stats; |
154 | iface_rx_stats = &oct->iface_rx_stats; |
155 | octep_ctrl_net_get_if_stats(oct, |
156 | OCTEP_CTRL_NET_INVALID_VFID, |
157 | rx_stats: iface_rx_stats, |
158 | tx_stats: iface_tx_stats); |
159 | |
160 | for (q = 0; q < oct->num_oqs; q++) { |
161 | struct octep_iq *iq = oct->iq[q]; |
162 | struct octep_oq *oq = oct->oq[q]; |
163 | |
164 | tx_packets += iq->stats.instr_completed; |
165 | tx_bytes += iq->stats.bytes_sent; |
166 | tx_busy_errors += iq->stats.tx_busy; |
167 | |
168 | rx_packets += oq->stats.packets; |
169 | rx_bytes += oq->stats.bytes; |
170 | rx_alloc_errors += oq->stats.alloc_failures; |
171 | } |
172 | i = 0; |
173 | data[i++] = rx_packets; |
174 | data[i++] = tx_packets; |
175 | data[i++] = rx_bytes; |
176 | data[i++] = tx_bytes; |
177 | data[i++] = rx_alloc_errors; |
178 | data[i++] = tx_busy_errors; |
179 | data[i++] = iface_rx_stats->dropped_pkts_fifo_full + |
180 | iface_rx_stats->err_pkts; |
181 | data[i++] = iface_tx_stats->xscol + |
182 | iface_tx_stats->xsdef; |
183 | data[i++] = iface_tx_stats->pkts; |
184 | data[i++] = iface_tx_stats->octs; |
185 | data[i++] = iface_tx_stats->bcst; |
186 | data[i++] = iface_tx_stats->mcst; |
187 | data[i++] = iface_tx_stats->undflw; |
188 | data[i++] = iface_tx_stats->ctl; |
189 | data[i++] = iface_tx_stats->hist_lt64; |
190 | data[i++] = iface_tx_stats->hist_eq64; |
191 | data[i++] = iface_tx_stats->hist_65to127; |
192 | data[i++] = iface_tx_stats->hist_128to255; |
193 | data[i++] = iface_tx_stats->hist_256to511; |
194 | data[i++] = iface_tx_stats->hist_512to1023; |
195 | data[i++] = iface_tx_stats->hist_1024to1518; |
196 | data[i++] = iface_tx_stats->hist_gt1518; |
197 | data[i++] = iface_rx_stats->pkts; |
198 | data[i++] = iface_rx_stats->octets; |
199 | data[i++] = iface_rx_stats->mcast_pkts; |
200 | data[i++] = iface_rx_stats->bcast_pkts; |
201 | data[i++] = iface_rx_stats->pause_pkts; |
202 | data[i++] = iface_rx_stats->pause_octets; |
203 | data[i++] = iface_rx_stats->dropped_pkts_fifo_full; |
204 | data[i++] = iface_rx_stats->dropped_octets_fifo_full; |
205 | data[i++] = iface_rx_stats->err_pkts; |
206 | |
207 | /* Per Tx Queue stats */ |
208 | for (q = 0; q < oct->num_iqs; q++) { |
209 | struct octep_iq *iq = oct->iq[q]; |
210 | |
211 | data[i++] = iq->stats.instr_posted; |
212 | data[i++] = iq->stats.instr_completed; |
213 | data[i++] = iq->stats.bytes_sent; |
214 | data[i++] = iq->stats.tx_busy; |
215 | } |
216 | |
217 | /* Per Rx Queue stats */ |
218 | for (q = 0; q < oct->num_oqs; q++) { |
219 | struct octep_oq *oq = oct->oq[q]; |
220 | |
221 | data[i++] = oq->stats.packets; |
222 | data[i++] = oq->stats.bytes; |
223 | data[i++] = oq->stats.alloc_failures; |
224 | } |
225 | } |
226 | |
227 | #define OCTEP_SET_ETHTOOL_LINK_MODES_BITMAP(octep_speeds, ksettings, name) \ |
228 | { \ |
229 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_10GBASE_T)) \ |
230 | ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseT_Full); \ |
231 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_10GBASE_R)) \ |
232 | ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseR_FEC); \ |
233 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_10GBASE_CR)) \ |
234 | ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseCR_Full); \ |
235 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_10GBASE_KR)) \ |
236 | ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseKR_Full); \ |
237 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_10GBASE_LR)) \ |
238 | ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseLR_Full); \ |
239 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_10GBASE_SR)) \ |
240 | ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseSR_Full); \ |
241 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_25GBASE_CR)) \ |
242 | ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseCR_Full); \ |
243 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_25GBASE_KR)) \ |
244 | ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseKR_Full); \ |
245 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_25GBASE_SR)) \ |
246 | ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseSR_Full); \ |
247 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_40GBASE_CR4)) \ |
248 | ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseCR4_Full); \ |
249 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_40GBASE_KR4)) \ |
250 | ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseKR4_Full); \ |
251 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_40GBASE_LR4)) \ |
252 | ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseLR4_Full); \ |
253 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_40GBASE_SR4)) \ |
254 | ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseSR4_Full); \ |
255 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_50GBASE_CR2)) \ |
256 | ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseCR2_Full); \ |
257 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_50GBASE_KR2)) \ |
258 | ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseKR2_Full); \ |
259 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_50GBASE_SR2)) \ |
260 | ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseSR2_Full); \ |
261 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_50GBASE_CR)) \ |
262 | ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseCR_Full); \ |
263 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_50GBASE_KR)) \ |
264 | ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseKR_Full); \ |
265 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_50GBASE_LR)) \ |
266 | ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseLR_ER_FR_Full); \ |
267 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_50GBASE_SR)) \ |
268 | ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseSR_Full); \ |
269 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_100GBASE_CR4)) \ |
270 | ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseCR4_Full); \ |
271 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_100GBASE_KR4)) \ |
272 | ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseKR4_Full); \ |
273 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_100GBASE_LR4)) \ |
274 | ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseLR4_ER4_Full); \ |
275 | if ((octep_speeds) & BIT(OCTEP_LINK_MODE_100GBASE_SR4)) \ |
276 | ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseSR4_Full); \ |
277 | } |
278 | |
279 | static int octep_get_link_ksettings(struct net_device *netdev, |
280 | struct ethtool_link_ksettings *cmd) |
281 | { |
282 | struct octep_device *oct = netdev_priv(dev: netdev); |
283 | struct octep_iface_link_info *link_info; |
284 | u32 advertised_modes, supported_modes; |
285 | |
286 | ethtool_link_ksettings_zero_link_mode(cmd, supported); |
287 | ethtool_link_ksettings_zero_link_mode(cmd, advertising); |
288 | |
289 | link_info = &oct->link_info; |
290 | octep_ctrl_net_get_link_info(oct, OCTEP_CTRL_NET_INVALID_VFID, link_info); |
291 | |
292 | advertised_modes = oct->link_info.advertised_modes; |
293 | supported_modes = oct->link_info.supported_modes; |
294 | |
295 | OCTEP_SET_ETHTOOL_LINK_MODES_BITMAP(supported_modes, cmd, supported); |
296 | OCTEP_SET_ETHTOOL_LINK_MODES_BITMAP(advertised_modes, cmd, advertising); |
297 | |
298 | if (link_info->autoneg) { |
299 | if (link_info->autoneg & OCTEP_LINK_MODE_AUTONEG_SUPPORTED) |
300 | ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); |
301 | if (link_info->autoneg & OCTEP_LINK_MODE_AUTONEG_ADVERTISED) { |
302 | ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); |
303 | cmd->base.autoneg = AUTONEG_ENABLE; |
304 | } else { |
305 | cmd->base.autoneg = AUTONEG_DISABLE; |
306 | } |
307 | } else { |
308 | cmd->base.autoneg = AUTONEG_DISABLE; |
309 | } |
310 | |
311 | if (link_info->pause) { |
312 | if (link_info->pause & OCTEP_LINK_MODE_PAUSE_SUPPORTED) |
313 | ethtool_link_ksettings_add_link_mode(cmd, supported, Pause); |
314 | if (link_info->pause & OCTEP_LINK_MODE_PAUSE_ADVERTISED) |
315 | ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); |
316 | } |
317 | |
318 | cmd->base.port = PORT_FIBRE; |
319 | ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); |
320 | ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); |
321 | |
322 | if (netif_carrier_ok(dev: netdev)) { |
323 | cmd->base.speed = link_info->speed; |
324 | cmd->base.duplex = DUPLEX_FULL; |
325 | } else { |
326 | cmd->base.speed = SPEED_UNKNOWN; |
327 | cmd->base.duplex = DUPLEX_UNKNOWN; |
328 | } |
329 | return 0; |
330 | } |
331 | |
332 | static int octep_set_link_ksettings(struct net_device *netdev, |
333 | const struct ethtool_link_ksettings *cmd) |
334 | { |
335 | struct octep_device *oct = netdev_priv(dev: netdev); |
336 | struct octep_iface_link_info link_info_new; |
337 | struct octep_iface_link_info *link_info; |
338 | u64 advertised = 0; |
339 | u8 autoneg = 0; |
340 | int err; |
341 | |
342 | link_info = &oct->link_info; |
343 | memcpy(&link_info_new, link_info, sizeof(struct octep_iface_link_info)); |
344 | |
345 | /* Only Full duplex is supported; |
346 | * Assume full duplex when duplex is unknown. |
347 | */ |
348 | if (cmd->base.duplex != DUPLEX_FULL && |
349 | cmd->base.duplex != DUPLEX_UNKNOWN) |
350 | return -EOPNOTSUPP; |
351 | |
352 | if (cmd->base.autoneg == AUTONEG_ENABLE) { |
353 | if (!(link_info->autoneg & OCTEP_LINK_MODE_AUTONEG_SUPPORTED)) |
354 | return -EOPNOTSUPP; |
355 | autoneg = 1; |
356 | } |
357 | |
358 | if (!bitmap_subset(src1: cmd->link_modes.advertising, |
359 | src2: cmd->link_modes.supported, |
360 | nbits: __ETHTOOL_LINK_MODE_MASK_NBITS)) |
361 | return -EINVAL; |
362 | |
363 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
364 | 10000baseT_Full)) |
365 | advertised |= BIT(OCTEP_LINK_MODE_10GBASE_T); |
366 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
367 | 10000baseR_FEC)) |
368 | advertised |= BIT(OCTEP_LINK_MODE_10GBASE_R); |
369 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
370 | 10000baseCR_Full)) |
371 | advertised |= BIT(OCTEP_LINK_MODE_10GBASE_CR); |
372 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
373 | 10000baseKR_Full)) |
374 | advertised |= BIT(OCTEP_LINK_MODE_10GBASE_KR); |
375 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
376 | 10000baseLR_Full)) |
377 | advertised |= BIT(OCTEP_LINK_MODE_10GBASE_LR); |
378 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
379 | 10000baseSR_Full)) |
380 | advertised |= BIT(OCTEP_LINK_MODE_10GBASE_SR); |
381 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
382 | 25000baseCR_Full)) |
383 | advertised |= BIT(OCTEP_LINK_MODE_25GBASE_CR); |
384 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
385 | 25000baseKR_Full)) |
386 | advertised |= BIT(OCTEP_LINK_MODE_25GBASE_KR); |
387 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
388 | 25000baseSR_Full)) |
389 | advertised |= BIT(OCTEP_LINK_MODE_25GBASE_SR); |
390 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
391 | 40000baseCR4_Full)) |
392 | advertised |= BIT(OCTEP_LINK_MODE_40GBASE_CR4); |
393 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
394 | 40000baseKR4_Full)) |
395 | advertised |= BIT(OCTEP_LINK_MODE_40GBASE_KR4); |
396 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
397 | 40000baseLR4_Full)) |
398 | advertised |= BIT(OCTEP_LINK_MODE_40GBASE_LR4); |
399 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
400 | 40000baseSR4_Full)) |
401 | advertised |= BIT(OCTEP_LINK_MODE_40GBASE_SR4); |
402 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
403 | 50000baseCR2_Full)) |
404 | advertised |= BIT(OCTEP_LINK_MODE_50GBASE_CR2); |
405 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
406 | 50000baseKR2_Full)) |
407 | advertised |= BIT(OCTEP_LINK_MODE_50GBASE_KR2); |
408 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
409 | 50000baseSR2_Full)) |
410 | advertised |= BIT(OCTEP_LINK_MODE_50GBASE_SR2); |
411 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
412 | 50000baseCR_Full)) |
413 | advertised |= BIT(OCTEP_LINK_MODE_50GBASE_CR); |
414 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
415 | 50000baseKR_Full)) |
416 | advertised |= BIT(OCTEP_LINK_MODE_50GBASE_KR); |
417 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
418 | 50000baseLR_ER_FR_Full)) |
419 | advertised |= BIT(OCTEP_LINK_MODE_50GBASE_LR); |
420 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
421 | 50000baseSR_Full)) |
422 | advertised |= BIT(OCTEP_LINK_MODE_50GBASE_SR); |
423 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
424 | 100000baseCR4_Full)) |
425 | advertised |= BIT(OCTEP_LINK_MODE_100GBASE_CR4); |
426 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
427 | 100000baseKR4_Full)) |
428 | advertised |= BIT(OCTEP_LINK_MODE_100GBASE_KR4); |
429 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
430 | 100000baseLR4_ER4_Full)) |
431 | advertised |= BIT(OCTEP_LINK_MODE_100GBASE_LR4); |
432 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
433 | 100000baseSR4_Full)) |
434 | advertised |= BIT(OCTEP_LINK_MODE_100GBASE_SR4); |
435 | |
436 | if (advertised == link_info->advertised_modes && |
437 | cmd->base.speed == link_info->speed && |
438 | cmd->base.autoneg == link_info->autoneg) |
439 | return 0; |
440 | |
441 | link_info_new.advertised_modes = advertised; |
442 | link_info_new.speed = cmd->base.speed; |
443 | link_info_new.autoneg = autoneg; |
444 | |
445 | err = octep_ctrl_net_set_link_info(oct, OCTEP_CTRL_NET_INVALID_VFID, |
446 | link_info: &link_info_new, wait_for_response: true); |
447 | if (err) |
448 | return err; |
449 | |
450 | memcpy(link_info, &link_info_new, sizeof(struct octep_iface_link_info)); |
451 | return 0; |
452 | } |
453 | |
454 | static const struct ethtool_ops octep_ethtool_ops = { |
455 | .get_drvinfo = octep_get_drvinfo, |
456 | .get_link = ethtool_op_get_link, |
457 | .get_strings = octep_get_strings, |
458 | .get_sset_count = octep_get_sset_count, |
459 | .get_ethtool_stats = octep_get_ethtool_stats, |
460 | .get_link_ksettings = octep_get_link_ksettings, |
461 | .set_link_ksettings = octep_set_link_ksettings, |
462 | }; |
463 | |
464 | void octep_set_ethtool_ops(struct net_device *netdev) |
465 | { |
466 | netdev->ethtool_ops = &octep_ethtool_ops; |
467 | } |
468 | |