1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved */
3 
4 #include <linux/ethtool.h>
5 #include <linux/kernel.h>
6 #include <linux/netdevice.h>
7 
8 #include "prestera_ethtool.h"
9 #include "prestera.h"
10 #include "prestera_hw.h"
11 
12 #define PRESTERA_STATS_CNT \
13 	(sizeof(struct prestera_port_stats) / sizeof(u64))
14 #define PRESTERA_STATS_IDX(name) \
15 	(offsetof(struct prestera_port_stats, name) / sizeof(u64))
16 #define PRESTERA_STATS_FIELD(name)	\
17 	[PRESTERA_STATS_IDX(name)] = __stringify(name)
18 
19 static const char driver_kind[] = "prestera";
20 
21 static const struct prestera_link_mode {
22 	enum ethtool_link_mode_bit_indices eth_mode;
23 	u32 speed;
24 	u64 pr_mask;
25 	u8 duplex;
26 	u8 port_type;
27 } port_link_modes[PRESTERA_LINK_MODE_MAX] = {
28 	[PRESTERA_LINK_MODE_10baseT_Half] = {
29 		.eth_mode =  ETHTOOL_LINK_MODE_10baseT_Half_BIT,
30 		.speed = 10,
31 		.pr_mask = 1 << PRESTERA_LINK_MODE_10baseT_Half,
32 		.duplex = PRESTERA_PORT_DUPLEX_HALF,
33 		.port_type = PRESTERA_PORT_TYPE_TP,
34 	},
35 	[PRESTERA_LINK_MODE_10baseT_Full] = {
36 		.eth_mode =  ETHTOOL_LINK_MODE_10baseT_Full_BIT,
37 		.speed = 10,
38 		.pr_mask = 1 << PRESTERA_LINK_MODE_10baseT_Full,
39 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
40 		.port_type = PRESTERA_PORT_TYPE_TP,
41 	},
42 	[PRESTERA_LINK_MODE_100baseT_Half] = {
43 		.eth_mode =  ETHTOOL_LINK_MODE_100baseT_Half_BIT,
44 		.speed = 100,
45 		.pr_mask = 1 << PRESTERA_LINK_MODE_100baseT_Half,
46 		.duplex = PRESTERA_PORT_DUPLEX_HALF,
47 		.port_type = PRESTERA_PORT_TYPE_TP,
48 	},
49 	[PRESTERA_LINK_MODE_100baseT_Full] = {
50 		.eth_mode =  ETHTOOL_LINK_MODE_100baseT_Full_BIT,
51 		.speed = 100,
52 		.pr_mask = 1 << PRESTERA_LINK_MODE_100baseT_Full,
53 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
54 		.port_type = PRESTERA_PORT_TYPE_TP,
55 	},
56 	[PRESTERA_LINK_MODE_1000baseT_Half] = {
57 		.eth_mode =  ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
58 		.speed = 1000,
59 		.pr_mask = 1 << PRESTERA_LINK_MODE_1000baseT_Half,
60 		.duplex = PRESTERA_PORT_DUPLEX_HALF,
61 		.port_type = PRESTERA_PORT_TYPE_TP,
62 	},
63 	[PRESTERA_LINK_MODE_1000baseT_Full] = {
64 		.eth_mode =  ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
65 		.speed = 1000,
66 		.pr_mask = 1 << PRESTERA_LINK_MODE_1000baseT_Full,
67 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
68 		.port_type = PRESTERA_PORT_TYPE_TP,
69 	},
70 	[PRESTERA_LINK_MODE_1000baseX_Full] = {
71 		.eth_mode = ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
72 		.speed = 1000,
73 		.pr_mask = 1 << PRESTERA_LINK_MODE_1000baseX_Full,
74 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
75 		.port_type = PRESTERA_PORT_TYPE_FIBRE,
76 	},
77 	[PRESTERA_LINK_MODE_1000baseKX_Full] = {
78 		.eth_mode = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
79 		.speed = 1000,
80 		.pr_mask = 1 << PRESTERA_LINK_MODE_1000baseKX_Full,
81 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
82 		.port_type = PRESTERA_PORT_TYPE_TP,
83 	},
84 	[PRESTERA_LINK_MODE_2500baseX_Full] = {
85 		.eth_mode =  ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
86 		.speed = 2500,
87 		.pr_mask = 1 << PRESTERA_LINK_MODE_2500baseX_Full,
88 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
89 	},
90 	[PRESTERA_LINK_MODE_10GbaseKR_Full] = {
91 		.eth_mode = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
92 		.speed = 10000,
93 		.pr_mask = 1 << PRESTERA_LINK_MODE_10GbaseKR_Full,
94 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
95 		.port_type = PRESTERA_PORT_TYPE_TP,
96 	},
97 	[PRESTERA_LINK_MODE_10GbaseSR_Full] = {
98 		.eth_mode = ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
99 		.speed = 10000,
100 		.pr_mask = 1 << PRESTERA_LINK_MODE_10GbaseSR_Full,
101 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
102 		.port_type = PRESTERA_PORT_TYPE_FIBRE,
103 	},
104 	[PRESTERA_LINK_MODE_10GbaseLR_Full] = {
105 		.eth_mode = ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
106 		.speed = 10000,
107 		.pr_mask = 1 << PRESTERA_LINK_MODE_10GbaseLR_Full,
108 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
109 		.port_type = PRESTERA_PORT_TYPE_FIBRE,
110 	},
111 	[PRESTERA_LINK_MODE_20GbaseKR2_Full] = {
112 		.eth_mode = ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
113 		.speed = 20000,
114 		.pr_mask = 1 << PRESTERA_LINK_MODE_20GbaseKR2_Full,
115 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
116 		.port_type = PRESTERA_PORT_TYPE_TP,
117 	},
118 	[PRESTERA_LINK_MODE_25GbaseCR_Full] = {
119 		.eth_mode = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
120 		.speed = 25000,
121 		.pr_mask = 1 << PRESTERA_LINK_MODE_25GbaseCR_Full,
122 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
123 		.port_type = PRESTERA_PORT_TYPE_DA,
124 	},
125 	[PRESTERA_LINK_MODE_25GbaseKR_Full] = {
126 		.eth_mode = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
127 		.speed = 25000,
128 		.pr_mask = 1 << PRESTERA_LINK_MODE_25GbaseKR_Full,
129 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
130 		.port_type = PRESTERA_PORT_TYPE_TP,
131 	},
132 	[PRESTERA_LINK_MODE_25GbaseSR_Full] = {
133 		.eth_mode = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
134 		.speed = 25000,
135 		.pr_mask = 1 << PRESTERA_LINK_MODE_25GbaseSR_Full,
136 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
137 		.port_type = PRESTERA_PORT_TYPE_FIBRE,
138 	},
139 	[PRESTERA_LINK_MODE_40GbaseKR4_Full] = {
140 		.eth_mode = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
141 		.speed = 40000,
142 		.pr_mask = 1 << PRESTERA_LINK_MODE_40GbaseKR4_Full,
143 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
144 		.port_type = PRESTERA_PORT_TYPE_TP,
145 	},
146 	[PRESTERA_LINK_MODE_40GbaseCR4_Full] = {
147 		.eth_mode = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
148 		.speed = 40000,
149 		.pr_mask = 1 << PRESTERA_LINK_MODE_40GbaseCR4_Full,
150 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
151 		.port_type = PRESTERA_PORT_TYPE_DA,
152 	},
153 	[PRESTERA_LINK_MODE_40GbaseSR4_Full] = {
154 		.eth_mode = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
155 		.speed = 40000,
156 		.pr_mask = 1 << PRESTERA_LINK_MODE_40GbaseSR4_Full,
157 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
158 		.port_type = PRESTERA_PORT_TYPE_FIBRE,
159 	},
160 	[PRESTERA_LINK_MODE_50GbaseCR2_Full] = {
161 		.eth_mode = ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
162 		.speed = 50000,
163 		.pr_mask = 1 << PRESTERA_LINK_MODE_50GbaseCR2_Full,
164 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
165 		.port_type = PRESTERA_PORT_TYPE_DA,
166 	},
167 	[PRESTERA_LINK_MODE_50GbaseKR2_Full] = {
168 		.eth_mode = ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
169 		.speed = 50000,
170 		.pr_mask = 1 << PRESTERA_LINK_MODE_50GbaseKR2_Full,
171 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
172 		.port_type = PRESTERA_PORT_TYPE_TP,
173 	},
174 	[PRESTERA_LINK_MODE_50GbaseSR2_Full] = {
175 		.eth_mode = ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
176 		.speed = 50000,
177 		.pr_mask = 1 << PRESTERA_LINK_MODE_50GbaseSR2_Full,
178 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
179 		.port_type = PRESTERA_PORT_TYPE_FIBRE,
180 	},
181 	[PRESTERA_LINK_MODE_100GbaseKR4_Full] = {
182 		.eth_mode = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
183 		.speed = 100000,
184 		.pr_mask = 1 << PRESTERA_LINK_MODE_100GbaseKR4_Full,
185 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
186 		.port_type = PRESTERA_PORT_TYPE_TP,
187 	},
188 	[PRESTERA_LINK_MODE_100GbaseSR4_Full] = {
189 		.eth_mode = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
190 		.speed = 100000,
191 		.pr_mask = 1 << PRESTERA_LINK_MODE_100GbaseSR4_Full,
192 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
193 		.port_type = PRESTERA_PORT_TYPE_FIBRE,
194 	},
195 	[PRESTERA_LINK_MODE_100GbaseCR4_Full] = {
196 		.eth_mode = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
197 		.speed = 100000,
198 		.pr_mask = 1 << PRESTERA_LINK_MODE_100GbaseCR4_Full,
199 		.duplex = PRESTERA_PORT_DUPLEX_FULL,
200 		.port_type = PRESTERA_PORT_TYPE_DA,
201 	}
202 };
203 
204 static const struct prestera_fec {
205 	u32 eth_fec;
206 	enum ethtool_link_mode_bit_indices eth_mode;
207 	u8 pr_fec;
208 } port_fec_caps[PRESTERA_PORT_FEC_MAX] = {
209 	[PRESTERA_PORT_FEC_OFF] = {
210 		.eth_fec = ETHTOOL_FEC_OFF,
211 		.eth_mode = ETHTOOL_LINK_MODE_FEC_NONE_BIT,
212 		.pr_fec = 1 << PRESTERA_PORT_FEC_OFF,
213 	},
214 	[PRESTERA_PORT_FEC_BASER] = {
215 		.eth_fec = ETHTOOL_FEC_BASER,
216 		.eth_mode = ETHTOOL_LINK_MODE_FEC_BASER_BIT,
217 		.pr_fec = 1 << PRESTERA_PORT_FEC_BASER,
218 	},
219 	[PRESTERA_PORT_FEC_RS] = {
220 		.eth_fec = ETHTOOL_FEC_RS,
221 		.eth_mode = ETHTOOL_LINK_MODE_FEC_RS_BIT,
222 		.pr_fec = 1 << PRESTERA_PORT_FEC_RS,
223 	}
224 };
225 
226 static const struct prestera_port_type {
227 	enum ethtool_link_mode_bit_indices eth_mode;
228 	u8 eth_type;
229 } port_types[PRESTERA_PORT_TYPE_MAX] = {
230 	[PRESTERA_PORT_TYPE_NONE] = {
231 		.eth_mode = __ETHTOOL_LINK_MODE_MASK_NBITS,
232 		.eth_type = PORT_NONE,
233 	},
234 	[PRESTERA_PORT_TYPE_TP] = {
235 		.eth_mode = ETHTOOL_LINK_MODE_TP_BIT,
236 		.eth_type = PORT_TP,
237 	},
238 	[PRESTERA_PORT_TYPE_AUI] = {
239 		.eth_mode = ETHTOOL_LINK_MODE_AUI_BIT,
240 		.eth_type = PORT_AUI,
241 	},
242 	[PRESTERA_PORT_TYPE_MII] = {
243 		.eth_mode = ETHTOOL_LINK_MODE_MII_BIT,
244 		.eth_type = PORT_MII,
245 	},
246 	[PRESTERA_PORT_TYPE_FIBRE] = {
247 		.eth_mode = ETHTOOL_LINK_MODE_FIBRE_BIT,
248 		.eth_type = PORT_FIBRE,
249 	},
250 	[PRESTERA_PORT_TYPE_BNC] = {
251 		.eth_mode = ETHTOOL_LINK_MODE_BNC_BIT,
252 		.eth_type = PORT_BNC,
253 	},
254 	[PRESTERA_PORT_TYPE_DA] = {
255 		.eth_mode = ETHTOOL_LINK_MODE_TP_BIT,
256 		.eth_type = PORT_TP,
257 	},
258 	[PRESTERA_PORT_TYPE_OTHER] = {
259 		.eth_mode = __ETHTOOL_LINK_MODE_MASK_NBITS,
260 		.eth_type = PORT_OTHER,
261 	}
262 };
263 
264 static const char prestera_cnt_name[PRESTERA_STATS_CNT][ETH_GSTRING_LEN] = {
265 	PRESTERA_STATS_FIELD(good_octets_received),
266 	PRESTERA_STATS_FIELD(bad_octets_received),
267 	PRESTERA_STATS_FIELD(mac_trans_error),
268 	PRESTERA_STATS_FIELD(broadcast_frames_received),
269 	PRESTERA_STATS_FIELD(multicast_frames_received),
270 	PRESTERA_STATS_FIELD(frames_64_octets),
271 	PRESTERA_STATS_FIELD(frames_65_to_127_octets),
272 	PRESTERA_STATS_FIELD(frames_128_to_255_octets),
273 	PRESTERA_STATS_FIELD(frames_256_to_511_octets),
274 	PRESTERA_STATS_FIELD(frames_512_to_1023_octets),
275 	PRESTERA_STATS_FIELD(frames_1024_to_max_octets),
276 	PRESTERA_STATS_FIELD(excessive_collision),
277 	PRESTERA_STATS_FIELD(multicast_frames_sent),
278 	PRESTERA_STATS_FIELD(broadcast_frames_sent),
279 	PRESTERA_STATS_FIELD(fc_sent),
280 	PRESTERA_STATS_FIELD(fc_received),
281 	PRESTERA_STATS_FIELD(buffer_overrun),
282 	PRESTERA_STATS_FIELD(undersize),
283 	PRESTERA_STATS_FIELD(fragments),
284 	PRESTERA_STATS_FIELD(oversize),
285 	PRESTERA_STATS_FIELD(jabber),
286 	PRESTERA_STATS_FIELD(rx_error_frame_received),
287 	PRESTERA_STATS_FIELD(bad_crc),
288 	PRESTERA_STATS_FIELD(collisions),
289 	PRESTERA_STATS_FIELD(late_collision),
290 	PRESTERA_STATS_FIELD(unicast_frames_received),
291 	PRESTERA_STATS_FIELD(unicast_frames_sent),
292 	PRESTERA_STATS_FIELD(sent_multiple),
293 	PRESTERA_STATS_FIELD(sent_deferred),
294 	PRESTERA_STATS_FIELD(good_octets_sent),
295 };
296 
297 static void prestera_ethtool_get_drvinfo(struct net_device *dev,
298 					 struct ethtool_drvinfo *drvinfo)
299 {
300 	struct prestera_port *port = netdev_priv(dev);
301 	struct prestera_switch *sw = port->sw;
302 
303 	strlcpy(drvinfo->driver, driver_kind, sizeof(drvinfo->driver));
304 	strlcpy(drvinfo->bus_info, dev_name(prestera_dev(sw)),
305 		sizeof(drvinfo->bus_info));
306 	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
307 		 "%d.%d.%d",
308 		 sw->dev->fw_rev.maj,
309 		 sw->dev->fw_rev.min,
310 		 sw->dev->fw_rev.sub);
311 }
312 
313 static u8 prestera_port_type_get(struct prestera_port *port)
314 {
315 	if (port->caps.type < PRESTERA_PORT_TYPE_MAX)
316 		return port_types[port->caps.type].eth_type;
317 
318 	return PORT_OTHER;
319 }
320 
321 static int prestera_port_type_set(const struct ethtool_link_ksettings *ecmd,
322 				  struct prestera_port *port)
323 {
324 	u32 new_mode = PRESTERA_LINK_MODE_MAX;
325 	u32 type, mode;
326 
327 	for (type = 0; type < PRESTERA_PORT_TYPE_MAX; type++) {
328 		if (port_types[type].eth_type == ecmd->base.port &&
329 		    test_bit(port_types[type].eth_mode,
330 			     ecmd->link_modes.supported)) {
331 			break;
332 		}
333 	}
334 
335 	if (type == port->caps.type)
336 		return 0;
337 	if (type != port->caps.type && ecmd->base.autoneg == AUTONEG_ENABLE)
338 		return -EINVAL;
339 	if (type == PRESTERA_PORT_TYPE_MAX)
340 		return -EOPNOTSUPP;
341 
342 	for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
343 		if ((port_link_modes[mode].pr_mask &
344 		    port->caps.supp_link_modes) &&
345 		    type == port_link_modes[mode].port_type) {
346 			new_mode = mode;
347 		}
348 	}
349 
350 	if (new_mode >= PRESTERA_LINK_MODE_MAX)
351 		return -EINVAL;
352 
353 	port->caps.type = type;
354 	port->autoneg = false;
355 
356 	return 0;
357 }
358 
359 static void prestera_modes_to_eth(unsigned long *eth_modes, u64 link_modes,
360 				  u8 fec, u8 type)
361 {
362 	u32 mode;
363 
364 	for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
365 		if ((port_link_modes[mode].pr_mask & link_modes) == 0)
366 			continue;
367 
368 		if (type != PRESTERA_PORT_TYPE_NONE &&
369 		    port_link_modes[mode].port_type != type)
370 			continue;
371 
372 		__set_bit(port_link_modes[mode].eth_mode, eth_modes);
373 	}
374 
375 	for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) {
376 		if ((port_fec_caps[mode].pr_fec & fec) == 0)
377 			continue;
378 
379 		__set_bit(port_fec_caps[mode].eth_mode, eth_modes);
380 	}
381 }
382 
383 static void prestera_modes_from_eth(const unsigned long *eth_modes,
384 				    u64 *link_modes, u8 *fec, u8 type)
385 {
386 	u64 adver_modes = 0;
387 	u32 fec_modes = 0;
388 	u32 mode;
389 
390 	for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
391 		if (!test_bit(port_link_modes[mode].eth_mode, eth_modes))
392 			continue;
393 
394 		if (port_link_modes[mode].port_type != type)
395 			continue;
396 
397 		adver_modes |= port_link_modes[mode].pr_mask;
398 	}
399 
400 	for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) {
401 		if (!test_bit(port_fec_caps[mode].eth_mode, eth_modes))
402 			continue;
403 
404 		fec_modes |= port_fec_caps[mode].pr_fec;
405 	}
406 
407 	*link_modes = adver_modes;
408 	*fec = fec_modes;
409 }
410 
411 static void prestera_port_supp_types_get(struct ethtool_link_ksettings *ecmd,
412 					 struct prestera_port *port)
413 {
414 	u32 mode;
415 	u8 ptype;
416 
417 	for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
418 		if ((port_link_modes[mode].pr_mask &
419 		    port->caps.supp_link_modes) == 0)
420 			continue;
421 
422 		ptype = port_link_modes[mode].port_type;
423 		__set_bit(port_types[ptype].eth_mode,
424 			  ecmd->link_modes.supported);
425 	}
426 }
427 
428 static void prestera_port_remote_cap_get(struct ethtool_link_ksettings *ecmd,
429 					 struct prestera_port *port)
430 {
431 	struct prestera_port_phy_state *state = &port->state_phy;
432 	bool asym_pause;
433 	bool pause;
434 	u64 bitmap;
435 	int err;
436 
437 	err = prestera_hw_port_phy_mode_get(port, NULL, &state->lmode_bmap,
438 					    &state->remote_fc.pause,
439 					    &state->remote_fc.asym_pause);
440 	if (err)
441 		netdev_warn(port->dev, "Remote link caps get failed %d",
442 			    port->caps.transceiver);
443 
444 	bitmap = state->lmode_bmap;
445 
446 	prestera_modes_to_eth(ecmd->link_modes.lp_advertising,
447 			      bitmap, 0, PRESTERA_PORT_TYPE_NONE);
448 
449 	if (!bitmap_empty(ecmd->link_modes.lp_advertising,
450 			  __ETHTOOL_LINK_MODE_MASK_NBITS)) {
451 		ethtool_link_ksettings_add_link_mode(ecmd,
452 						     lp_advertising,
453 						     Autoneg);
454 	}
455 
456 	pause = state->remote_fc.pause;
457 	asym_pause = state->remote_fc.asym_pause;
458 
459 	if (pause)
460 		ethtool_link_ksettings_add_link_mode(ecmd,
461 						     lp_advertising,
462 						     Pause);
463 	if (asym_pause)
464 		ethtool_link_ksettings_add_link_mode(ecmd,
465 						     lp_advertising,
466 						     Asym_Pause);
467 }
468 
469 static void prestera_port_link_mode_get(struct ethtool_link_ksettings *ecmd,
470 					struct prestera_port *port)
471 {
472 	struct prestera_port_mac_state *state = &port->state_mac;
473 	u32 speed;
474 	u8 duplex;
475 	int err;
476 
477 	if (!port->state_mac.oper)
478 		return;
479 
480 	if (state->speed == SPEED_UNKNOWN || state->duplex == DUPLEX_UNKNOWN) {
481 		err = prestera_hw_port_mac_mode_get(port, NULL, &speed,
482 						    &duplex, NULL);
483 		if (err) {
484 			state->speed = SPEED_UNKNOWN;
485 			state->duplex = DUPLEX_UNKNOWN;
486 		} else {
487 			state->speed = speed;
488 			state->duplex = duplex == PRESTERA_PORT_DUPLEX_FULL ?
489 					  DUPLEX_FULL : DUPLEX_HALF;
490 		}
491 	}
492 
493 	ecmd->base.speed = port->state_mac.speed;
494 	ecmd->base.duplex = port->state_mac.duplex;
495 }
496 
497 static void prestera_port_mdix_get(struct ethtool_link_ksettings *ecmd,
498 				   struct prestera_port *port)
499 {
500 	struct prestera_port_phy_state *state = &port->state_phy;
501 
502 	if (prestera_hw_port_phy_mode_get(port,
503 					  &state->mdix, NULL, NULL, NULL)) {
504 		netdev_warn(port->dev, "MDIX params get failed");
505 		state->mdix = ETH_TP_MDI_INVALID;
506 	}
507 
508 	ecmd->base.eth_tp_mdix = port->state_phy.mdix;
509 	ecmd->base.eth_tp_mdix_ctrl = port->cfg_phy.mdix;
510 }
511 
512 static int
513 prestera_ethtool_get_link_ksettings(struct net_device *dev,
514 				    struct ethtool_link_ksettings *ecmd)
515 {
516 	struct prestera_port *port = netdev_priv(dev);
517 
518 	ethtool_link_ksettings_zero_link_mode(ecmd, supported);
519 	ethtool_link_ksettings_zero_link_mode(ecmd, advertising);
520 	ethtool_link_ksettings_zero_link_mode(ecmd, lp_advertising);
521 	ecmd->base.speed = SPEED_UNKNOWN;
522 	ecmd->base.duplex = DUPLEX_UNKNOWN;
523 
524 	ecmd->base.autoneg = port->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
525 
526 	if (port->caps.type == PRESTERA_PORT_TYPE_TP) {
527 		ethtool_link_ksettings_add_link_mode(ecmd, supported, Autoneg);
528 
529 		if (netif_running(dev) &&
530 		    (port->autoneg ||
531 		     port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER))
532 			ethtool_link_ksettings_add_link_mode(ecmd, advertising,
533 							     Autoneg);
534 	}
535 
536 	prestera_modes_to_eth(ecmd->link_modes.supported,
537 			      port->caps.supp_link_modes,
538 			      port->caps.supp_fec,
539 			      port->caps.type);
540 
541 	prestera_port_supp_types_get(ecmd, port);
542 
543 	if (netif_carrier_ok(dev))
544 		prestera_port_link_mode_get(ecmd, port);
545 
546 	ecmd->base.port = prestera_port_type_get(port);
547 
548 	if (port->autoneg) {
549 		if (netif_running(dev))
550 			prestera_modes_to_eth(ecmd->link_modes.advertising,
551 					      port->adver_link_modes,
552 					      port->adver_fec,
553 					      port->caps.type);
554 
555 		if (netif_carrier_ok(dev) &&
556 		    port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER)
557 			prestera_port_remote_cap_get(ecmd, port);
558 	}
559 
560 	if (port->caps.type == PRESTERA_PORT_TYPE_TP &&
561 	    port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER)
562 		prestera_port_mdix_get(ecmd, port);
563 
564 	return 0;
565 }
566 
567 static int prestera_port_mdix_set(const struct ethtool_link_ksettings *ecmd,
568 				  struct prestera_port *port)
569 {
570 	if (ecmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_INVALID &&
571 	    port->caps.transceiver ==  PRESTERA_PORT_TCVR_COPPER &&
572 	    port->caps.type == PRESTERA_PORT_TYPE_TP) {
573 		port->cfg_phy.mdix = ecmd->base.eth_tp_mdix_ctrl;
574 		return prestera_hw_port_phy_mode_set(port, port->cfg_phy.admin,
575 						     port->autoneg,
576 						     port->cfg_phy.mode,
577 						     port->adver_link_modes,
578 						     port->cfg_phy.mdix);
579 	}
580 	return 0;
581 
582 }
583 
584 static int prestera_port_link_mode_set(struct prestera_port *port,
585 				       u32 speed, u8 duplex, u8 type)
586 {
587 	u32 new_mode = PRESTERA_LINK_MODE_MAX;
588 	u32 mode;
589 	int err;
590 
591 	for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
592 		if (speed != SPEED_UNKNOWN &&
593 		    speed != port_link_modes[mode].speed)
594 			continue;
595 
596 		if (duplex != DUPLEX_UNKNOWN &&
597 		    duplex != port_link_modes[mode].duplex)
598 			continue;
599 
600 		if (!(port_link_modes[mode].pr_mask &
601 		    port->caps.supp_link_modes))
602 			continue;
603 
604 		if (type != port_link_modes[mode].port_type)
605 			continue;
606 
607 		new_mode = mode;
608 		break;
609 	}
610 
611 	if (new_mode == PRESTERA_LINK_MODE_MAX)
612 		return -EOPNOTSUPP;
613 
614 	err = prestera_hw_port_phy_mode_set(port, port->cfg_phy.admin,
615 					    false, new_mode, 0,
616 					    port->cfg_phy.mdix);
617 	if (err)
618 		return err;
619 
620 	port->adver_fec = BIT(PRESTERA_PORT_FEC_OFF);
621 	port->adver_link_modes = 0;
622 	port->cfg_phy.mode = new_mode;
623 	port->autoneg = false;
624 
625 	return 0;
626 }
627 
628 static int
629 prestera_port_speed_duplex_set(const struct ethtool_link_ksettings *ecmd,
630 			       struct prestera_port *port)
631 {
632 	u8 duplex = DUPLEX_UNKNOWN;
633 
634 	if (ecmd->base.duplex != DUPLEX_UNKNOWN)
635 		duplex = ecmd->base.duplex == DUPLEX_FULL ?
636 			 PRESTERA_PORT_DUPLEX_FULL : PRESTERA_PORT_DUPLEX_HALF;
637 
638 	return prestera_port_link_mode_set(port, ecmd->base.speed, duplex,
639 					   port->caps.type);
640 }
641 
642 static int
643 prestera_ethtool_set_link_ksettings(struct net_device *dev,
644 				    const struct ethtool_link_ksettings *ecmd)
645 {
646 	struct prestera_port *port = netdev_priv(dev);
647 	u64 adver_modes;
648 	u8 adver_fec;
649 	int err;
650 
651 	err = prestera_port_type_set(ecmd, port);
652 	if (err)
653 		return err;
654 
655 	if (port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER) {
656 		err = prestera_port_mdix_set(ecmd, port);
657 		if (err)
658 			return err;
659 	}
660 
661 	prestera_modes_from_eth(ecmd->link_modes.advertising, &adver_modes,
662 				&adver_fec, port->caps.type);
663 
664 	if (ecmd->base.autoneg == AUTONEG_ENABLE)
665 		err = prestera_port_autoneg_set(port, adver_modes);
666 	else
667 		err = prestera_port_speed_duplex_set(ecmd, port);
668 
669 	return err;
670 }
671 
672 static int prestera_ethtool_get_fecparam(struct net_device *dev,
673 					 struct ethtool_fecparam *fecparam)
674 {
675 	struct prestera_port *port = netdev_priv(dev);
676 	u8 active;
677 	u32 mode;
678 	int err;
679 
680 	err = prestera_hw_port_mac_mode_get(port, NULL, NULL, NULL, &active);
681 	if (err)
682 		return err;
683 
684 	fecparam->fec = 0;
685 
686 	for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) {
687 		if ((port_fec_caps[mode].pr_fec & port->caps.supp_fec) == 0)
688 			continue;
689 
690 		fecparam->fec |= port_fec_caps[mode].eth_fec;
691 	}
692 
693 	if (active < PRESTERA_PORT_FEC_MAX)
694 		fecparam->active_fec = port_fec_caps[active].eth_fec;
695 	else
696 		fecparam->active_fec = ETHTOOL_FEC_AUTO;
697 
698 	return 0;
699 }
700 
701 static int prestera_ethtool_set_fecparam(struct net_device *dev,
702 					 struct ethtool_fecparam *fecparam)
703 {
704 	struct prestera_port *port = netdev_priv(dev);
705 	struct prestera_port_mac_config cfg_mac;
706 	u32 mode;
707 	u8 fec;
708 
709 	if (port->autoneg) {
710 		netdev_err(dev, "FEC set is not allowed while autoneg is on\n");
711 		return -EINVAL;
712 	}
713 
714 	if (port->caps.transceiver == PRESTERA_PORT_TCVR_SFP) {
715 		netdev_err(dev, "FEC set is not allowed on non-SFP ports\n");
716 		return -EINVAL;
717 	}
718 
719 	fec = PRESTERA_PORT_FEC_MAX;
720 	for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) {
721 		if ((port_fec_caps[mode].eth_fec & fecparam->fec) &&
722 		    (port_fec_caps[mode].pr_fec & port->caps.supp_fec)) {
723 			fec = mode;
724 			break;
725 		}
726 	}
727 
728 	prestera_port_cfg_mac_read(port, &cfg_mac);
729 
730 	if (fec == cfg_mac.fec)
731 		return 0;
732 
733 	if (fec == PRESTERA_PORT_FEC_MAX) {
734 		netdev_err(dev, "Unsupported FEC requested");
735 		return -EINVAL;
736 	}
737 
738 	cfg_mac.fec = fec;
739 
740 	return prestera_port_cfg_mac_write(port, &cfg_mac);
741 }
742 
743 static int prestera_ethtool_get_sset_count(struct net_device *dev, int sset)
744 {
745 	switch (sset) {
746 	case ETH_SS_STATS:
747 		return PRESTERA_STATS_CNT;
748 	default:
749 		return -EOPNOTSUPP;
750 	}
751 }
752 
753 static void prestera_ethtool_get_strings(struct net_device *dev,
754 					 u32 stringset, u8 *data)
755 {
756 	if (stringset != ETH_SS_STATS)
757 		return;
758 
759 	memcpy(data, prestera_cnt_name, sizeof(prestera_cnt_name));
760 }
761 
762 static void prestera_ethtool_get_stats(struct net_device *dev,
763 				       struct ethtool_stats *stats, u64 *data)
764 {
765 	struct prestera_port *port = netdev_priv(dev);
766 	struct prestera_port_stats *port_stats;
767 
768 	port_stats = &port->cached_hw_stats.stats;
769 
770 	memcpy(data, port_stats, sizeof(*port_stats));
771 }
772 
773 static int prestera_ethtool_nway_reset(struct net_device *dev)
774 {
775 	struct prestera_port *port = netdev_priv(dev);
776 
777 	if (netif_running(dev) &&
778 	    port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER &&
779 	    port->caps.type == PRESTERA_PORT_TYPE_TP)
780 		return prestera_hw_port_autoneg_restart(port);
781 
782 	return -EINVAL;
783 }
784 
785 void prestera_ethtool_port_state_changed(struct prestera_port *port,
786 					 struct prestera_port_event *evt)
787 {
788 	struct prestera_port_mac_state *smac = &port->state_mac;
789 
790 	smac->oper = evt->data.mac.oper;
791 
792 	if (smac->oper) {
793 		smac->mode = evt->data.mac.mode;
794 		smac->speed = evt->data.mac.speed;
795 		smac->duplex = evt->data.mac.duplex;
796 		smac->fc = evt->data.mac.fc;
797 		smac->fec = evt->data.mac.fec;
798 	} else {
799 		smac->mode = PRESTERA_MAC_MODE_MAX;
800 		smac->speed = SPEED_UNKNOWN;
801 		smac->duplex = DUPLEX_UNKNOWN;
802 		smac->fc = 0;
803 		smac->fec = 0;
804 	}
805 }
806 
807 const struct ethtool_ops prestera_ethtool_ops = {
808 	.get_drvinfo = prestera_ethtool_get_drvinfo,
809 	.get_link_ksettings = prestera_ethtool_get_link_ksettings,
810 	.set_link_ksettings = prestera_ethtool_set_link_ksettings,
811 	.get_fecparam = prestera_ethtool_get_fecparam,
812 	.set_fecparam = prestera_ethtool_set_fecparam,
813 	.get_sset_count = prestera_ethtool_get_sset_count,
814 	.get_strings = prestera_ethtool_get_strings,
815 	.get_ethtool_stats = prestera_ethtool_get_stats,
816 	.get_link = ethtool_op_get_link,
817 	.nway_reset = prestera_ethtool_nway_reset
818 };
819