1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2020 Mellanox Technologies. All rights reserved */
3
4 #include "reg.h"
5 #include "core.h"
6 #include "spectrum.h"
7 #include "core_env.h"
8
9 static const char mlxsw_sp_driver_version[] = "1.0";
10
mlxsw_sp_port_get_drvinfo(struct net_device * dev,struct ethtool_drvinfo * drvinfo)11 static void mlxsw_sp_port_get_drvinfo(struct net_device *dev,
12 struct ethtool_drvinfo *drvinfo)
13 {
14 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
15 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
16
17 strlcpy(drvinfo->driver, mlxsw_sp->bus_info->device_kind,
18 sizeof(drvinfo->driver));
19 strlcpy(drvinfo->version, mlxsw_sp_driver_version,
20 sizeof(drvinfo->version));
21 snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
22 "%d.%d.%d",
23 mlxsw_sp->bus_info->fw_rev.major,
24 mlxsw_sp->bus_info->fw_rev.minor,
25 mlxsw_sp->bus_info->fw_rev.subminor);
26 strlcpy(drvinfo->bus_info, mlxsw_sp->bus_info->device_name,
27 sizeof(drvinfo->bus_info));
28 }
29
30 struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping {
31 u32 status_opcode;
32 enum ethtool_link_ext_state link_ext_state;
33 u8 link_ext_substate;
34 };
35
36 static const struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping
37 mlxsw_sp_link_ext_state_opcode_map[] = {
38 {2, ETHTOOL_LINK_EXT_STATE_AUTONEG,
39 ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED},
40 {3, ETHTOOL_LINK_EXT_STATE_AUTONEG,
41 ETHTOOL_LINK_EXT_SUBSTATE_AN_ACK_NOT_RECEIVED},
42 {4, ETHTOOL_LINK_EXT_STATE_AUTONEG,
43 ETHTOOL_LINK_EXT_SUBSTATE_AN_NEXT_PAGE_EXCHANGE_FAILED},
44 {36, ETHTOOL_LINK_EXT_STATE_AUTONEG,
45 ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED_FORCE_MODE},
46 {38, ETHTOOL_LINK_EXT_STATE_AUTONEG,
47 ETHTOOL_LINK_EXT_SUBSTATE_AN_FEC_MISMATCH_DURING_OVERRIDE},
48 {39, ETHTOOL_LINK_EXT_STATE_AUTONEG,
49 ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_HCD},
50
51 {5, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
52 ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_FRAME_LOCK_NOT_ACQUIRED},
53 {6, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
54 ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_INHIBIT_TIMEOUT},
55 {7, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
56 ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_PARTNER_DID_NOT_SET_RECEIVER_READY},
57 {8, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE, 0},
58 {14, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
59 ETHTOOL_LINK_EXT_SUBSTATE_LT_REMOTE_FAULT},
60
61 {9, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
62 ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_BLOCK_LOCK},
63 {10, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
64 ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_AM_LOCK},
65 {11, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
66 ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_GET_ALIGN_STATUS},
67 {12, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
68 ETHTOOL_LINK_EXT_SUBSTATE_LLM_FC_FEC_IS_NOT_LOCKED},
69 {13, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
70 ETHTOOL_LINK_EXT_SUBSTATE_LLM_RS_FEC_IS_NOT_LOCKED},
71
72 {15, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY, 0},
73 {17, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY,
74 ETHTOOL_LINK_EXT_SUBSTATE_BSI_LARGE_NUMBER_OF_PHYSICAL_ERRORS},
75 {42, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY,
76 ETHTOOL_LINK_EXT_SUBSTATE_BSI_UNSUPPORTED_RATE},
77
78 {1024, ETHTOOL_LINK_EXT_STATE_NO_CABLE, 0},
79
80 {16, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
81 ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
82 {20, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
83 ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
84 {29, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
85 ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
86 {1025, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
87 ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
88 {1029, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
89 ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
90 {1031, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE, 0},
91
92 {1027, ETHTOOL_LINK_EXT_STATE_EEPROM_ISSUE, 0},
93
94 {23, ETHTOOL_LINK_EXT_STATE_CALIBRATION_FAILURE, 0},
95
96 {1032, ETHTOOL_LINK_EXT_STATE_POWER_BUDGET_EXCEEDED, 0},
97
98 {1030, ETHTOOL_LINK_EXT_STATE_OVERHEAT, 0},
99 };
100
101 static void
mlxsw_sp_port_set_link_ext_state(struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping link_ext_state_mapping,struct ethtool_link_ext_state_info * link_ext_state_info)102 mlxsw_sp_port_set_link_ext_state(struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping
103 link_ext_state_mapping,
104 struct ethtool_link_ext_state_info *link_ext_state_info)
105 {
106 switch (link_ext_state_mapping.link_ext_state) {
107 case ETHTOOL_LINK_EXT_STATE_AUTONEG:
108 link_ext_state_info->autoneg =
109 link_ext_state_mapping.link_ext_substate;
110 break;
111 case ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE:
112 link_ext_state_info->link_training =
113 link_ext_state_mapping.link_ext_substate;
114 break;
115 case ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH:
116 link_ext_state_info->link_logical_mismatch =
117 link_ext_state_mapping.link_ext_substate;
118 break;
119 case ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY:
120 link_ext_state_info->bad_signal_integrity =
121 link_ext_state_mapping.link_ext_substate;
122 break;
123 case ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE:
124 link_ext_state_info->cable_issue =
125 link_ext_state_mapping.link_ext_substate;
126 break;
127 default:
128 break;
129 }
130
131 link_ext_state_info->link_ext_state = link_ext_state_mapping.link_ext_state;
132 }
133
134 static int
mlxsw_sp_port_get_link_ext_state(struct net_device * dev,struct ethtool_link_ext_state_info * link_ext_state_info)135 mlxsw_sp_port_get_link_ext_state(struct net_device *dev,
136 struct ethtool_link_ext_state_info *link_ext_state_info)
137 {
138 struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping link_ext_state_mapping;
139 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
140 char pddr_pl[MLXSW_REG_PDDR_LEN];
141 int opcode, err, i;
142 u32 status_opcode;
143
144 if (netif_carrier_ok(dev))
145 return -ENODATA;
146
147 mlxsw_reg_pddr_pack(pddr_pl, mlxsw_sp_port->local_port,
148 MLXSW_REG_PDDR_PAGE_SELECT_TROUBLESHOOTING_INFO);
149
150 opcode = MLXSW_REG_PDDR_TRBLSH_GROUP_OPCODE_MONITOR;
151 mlxsw_reg_pddr_trblsh_group_opcode_set(pddr_pl, opcode);
152
153 err = mlxsw_reg_query(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pddr),
154 pddr_pl);
155 if (err)
156 return err;
157
158 status_opcode = mlxsw_reg_pddr_trblsh_status_opcode_get(pddr_pl);
159 if (!status_opcode)
160 return -ENODATA;
161
162 for (i = 0; i < ARRAY_SIZE(mlxsw_sp_link_ext_state_opcode_map); i++) {
163 link_ext_state_mapping = mlxsw_sp_link_ext_state_opcode_map[i];
164 if (link_ext_state_mapping.status_opcode == status_opcode) {
165 mlxsw_sp_port_set_link_ext_state(link_ext_state_mapping,
166 link_ext_state_info);
167 return 0;
168 }
169 }
170
171 return -ENODATA;
172 }
173
mlxsw_sp_port_get_pauseparam(struct net_device * dev,struct ethtool_pauseparam * pause)174 static void mlxsw_sp_port_get_pauseparam(struct net_device *dev,
175 struct ethtool_pauseparam *pause)
176 {
177 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
178
179 pause->rx_pause = mlxsw_sp_port->link.rx_pause;
180 pause->tx_pause = mlxsw_sp_port->link.tx_pause;
181 }
182
mlxsw_sp_port_pause_set(struct mlxsw_sp_port * mlxsw_sp_port,struct ethtool_pauseparam * pause)183 static int mlxsw_sp_port_pause_set(struct mlxsw_sp_port *mlxsw_sp_port,
184 struct ethtool_pauseparam *pause)
185 {
186 char pfcc_pl[MLXSW_REG_PFCC_LEN];
187
188 mlxsw_reg_pfcc_pack(pfcc_pl, mlxsw_sp_port->local_port);
189 mlxsw_reg_pfcc_pprx_set(pfcc_pl, pause->rx_pause);
190 mlxsw_reg_pfcc_pptx_set(pfcc_pl, pause->tx_pause);
191
192 return mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pfcc),
193 pfcc_pl);
194 }
195
196 /* Maximum delay buffer needed in case of PAUSE frames. Similar to PFC delay, but is
197 * measured in bytes. Assumes 100m cable and does not take into account MTU.
198 */
199 #define MLXSW_SP_PAUSE_DELAY_BYTES 19476
200
mlxsw_sp_port_set_pauseparam(struct net_device * dev,struct ethtool_pauseparam * pause)201 static int mlxsw_sp_port_set_pauseparam(struct net_device *dev,
202 struct ethtool_pauseparam *pause)
203 {
204 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
205 bool pause_en = pause->tx_pause || pause->rx_pause;
206 struct mlxsw_sp_hdroom orig_hdroom;
207 struct mlxsw_sp_hdroom hdroom;
208 int prio;
209 int err;
210
211 if (mlxsw_sp_port->dcb.pfc && mlxsw_sp_port->dcb.pfc->pfc_en) {
212 netdev_err(dev, "PFC already enabled on port\n");
213 return -EINVAL;
214 }
215
216 if (pause->autoneg) {
217 netdev_err(dev, "PAUSE frames autonegotiation isn't supported\n");
218 return -EINVAL;
219 }
220
221 orig_hdroom = *mlxsw_sp_port->hdroom;
222
223 hdroom = orig_hdroom;
224 if (pause_en)
225 hdroom.delay_bytes = MLXSW_SP_PAUSE_DELAY_BYTES;
226 else
227 hdroom.delay_bytes = 0;
228
229 for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
230 hdroom.prios.prio[prio].lossy = !pause_en;
231
232 mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
233 mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
234
235 err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
236 if (err) {
237 netdev_err(dev, "Failed to configure port's headroom\n");
238 return err;
239 }
240
241 err = mlxsw_sp_port_pause_set(mlxsw_sp_port, pause);
242 if (err) {
243 netdev_err(dev, "Failed to set PAUSE parameters\n");
244 goto err_port_pause_configure;
245 }
246
247 mlxsw_sp_port->link.rx_pause = pause->rx_pause;
248 mlxsw_sp_port->link.tx_pause = pause->tx_pause;
249
250 return 0;
251
252 err_port_pause_configure:
253 mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom);
254 return err;
255 }
256
257 struct mlxsw_sp_port_hw_stats {
258 char str[ETH_GSTRING_LEN];
259 u64 (*getter)(const char *payload);
260 bool cells_bytes;
261 };
262
263 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_stats[] = {
264 {
265 .str = "a_frames_transmitted_ok",
266 .getter = mlxsw_reg_ppcnt_a_frames_transmitted_ok_get,
267 },
268 {
269 .str = "a_frames_received_ok",
270 .getter = mlxsw_reg_ppcnt_a_frames_received_ok_get,
271 },
272 {
273 .str = "a_frame_check_sequence_errors",
274 .getter = mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get,
275 },
276 {
277 .str = "a_alignment_errors",
278 .getter = mlxsw_reg_ppcnt_a_alignment_errors_get,
279 },
280 {
281 .str = "a_octets_transmitted_ok",
282 .getter = mlxsw_reg_ppcnt_a_octets_transmitted_ok_get,
283 },
284 {
285 .str = "a_octets_received_ok",
286 .getter = mlxsw_reg_ppcnt_a_octets_received_ok_get,
287 },
288 {
289 .str = "a_multicast_frames_xmitted_ok",
290 .getter = mlxsw_reg_ppcnt_a_multicast_frames_xmitted_ok_get,
291 },
292 {
293 .str = "a_broadcast_frames_xmitted_ok",
294 .getter = mlxsw_reg_ppcnt_a_broadcast_frames_xmitted_ok_get,
295 },
296 {
297 .str = "a_multicast_frames_received_ok",
298 .getter = mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get,
299 },
300 {
301 .str = "a_broadcast_frames_received_ok",
302 .getter = mlxsw_reg_ppcnt_a_broadcast_frames_received_ok_get,
303 },
304 {
305 .str = "a_in_range_length_errors",
306 .getter = mlxsw_reg_ppcnt_a_in_range_length_errors_get,
307 },
308 {
309 .str = "a_out_of_range_length_field",
310 .getter = mlxsw_reg_ppcnt_a_out_of_range_length_field_get,
311 },
312 {
313 .str = "a_frame_too_long_errors",
314 .getter = mlxsw_reg_ppcnt_a_frame_too_long_errors_get,
315 },
316 {
317 .str = "a_symbol_error_during_carrier",
318 .getter = mlxsw_reg_ppcnt_a_symbol_error_during_carrier_get,
319 },
320 {
321 .str = "a_mac_control_frames_transmitted",
322 .getter = mlxsw_reg_ppcnt_a_mac_control_frames_transmitted_get,
323 },
324 {
325 .str = "a_mac_control_frames_received",
326 .getter = mlxsw_reg_ppcnt_a_mac_control_frames_received_get,
327 },
328 {
329 .str = "a_unsupported_opcodes_received",
330 .getter = mlxsw_reg_ppcnt_a_unsupported_opcodes_received_get,
331 },
332 {
333 .str = "a_pause_mac_ctrl_frames_received",
334 .getter = mlxsw_reg_ppcnt_a_pause_mac_ctrl_frames_received_get,
335 },
336 {
337 .str = "a_pause_mac_ctrl_frames_xmitted",
338 .getter = mlxsw_reg_ppcnt_a_pause_mac_ctrl_frames_transmitted_get,
339 },
340 };
341
342 #define MLXSW_SP_PORT_HW_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_stats)
343
344 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_rfc_2863_stats[] = {
345 {
346 .str = "if_in_discards",
347 .getter = mlxsw_reg_ppcnt_if_in_discards_get,
348 },
349 {
350 .str = "if_out_discards",
351 .getter = mlxsw_reg_ppcnt_if_out_discards_get,
352 },
353 {
354 .str = "if_out_errors",
355 .getter = mlxsw_reg_ppcnt_if_out_errors_get,
356 },
357 };
358
359 #define MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN \
360 ARRAY_SIZE(mlxsw_sp_port_hw_rfc_2863_stats)
361
362 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_rfc_2819_stats[] = {
363 {
364 .str = "ether_stats_undersize_pkts",
365 .getter = mlxsw_reg_ppcnt_ether_stats_undersize_pkts_get,
366 },
367 {
368 .str = "ether_stats_oversize_pkts",
369 .getter = mlxsw_reg_ppcnt_ether_stats_oversize_pkts_get,
370 },
371 {
372 .str = "ether_stats_fragments",
373 .getter = mlxsw_reg_ppcnt_ether_stats_fragments_get,
374 },
375 {
376 .str = "ether_pkts64octets",
377 .getter = mlxsw_reg_ppcnt_ether_stats_pkts64octets_get,
378 },
379 {
380 .str = "ether_pkts65to127octets",
381 .getter = mlxsw_reg_ppcnt_ether_stats_pkts65to127octets_get,
382 },
383 {
384 .str = "ether_pkts128to255octets",
385 .getter = mlxsw_reg_ppcnt_ether_stats_pkts128to255octets_get,
386 },
387 {
388 .str = "ether_pkts256to511octets",
389 .getter = mlxsw_reg_ppcnt_ether_stats_pkts256to511octets_get,
390 },
391 {
392 .str = "ether_pkts512to1023octets",
393 .getter = mlxsw_reg_ppcnt_ether_stats_pkts512to1023octets_get,
394 },
395 {
396 .str = "ether_pkts1024to1518octets",
397 .getter = mlxsw_reg_ppcnt_ether_stats_pkts1024to1518octets_get,
398 },
399 {
400 .str = "ether_pkts1519to2047octets",
401 .getter = mlxsw_reg_ppcnt_ether_stats_pkts1519to2047octets_get,
402 },
403 {
404 .str = "ether_pkts2048to4095octets",
405 .getter = mlxsw_reg_ppcnt_ether_stats_pkts2048to4095octets_get,
406 },
407 {
408 .str = "ether_pkts4096to8191octets",
409 .getter = mlxsw_reg_ppcnt_ether_stats_pkts4096to8191octets_get,
410 },
411 {
412 .str = "ether_pkts8192to10239octets",
413 .getter = mlxsw_reg_ppcnt_ether_stats_pkts8192to10239octets_get,
414 },
415 };
416
417 #define MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN \
418 ARRAY_SIZE(mlxsw_sp_port_hw_rfc_2819_stats)
419
420 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_rfc_3635_stats[] = {
421 {
422 .str = "dot3stats_fcs_errors",
423 .getter = mlxsw_reg_ppcnt_dot3stats_fcs_errors_get,
424 },
425 {
426 .str = "dot3stats_symbol_errors",
427 .getter = mlxsw_reg_ppcnt_dot3stats_symbol_errors_get,
428 },
429 {
430 .str = "dot3control_in_unknown_opcodes",
431 .getter = mlxsw_reg_ppcnt_dot3control_in_unknown_opcodes_get,
432 },
433 {
434 .str = "dot3in_pause_frames",
435 .getter = mlxsw_reg_ppcnt_dot3in_pause_frames_get,
436 },
437 };
438
439 #define MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN \
440 ARRAY_SIZE(mlxsw_sp_port_hw_rfc_3635_stats)
441
442 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_ext_stats[] = {
443 {
444 .str = "ecn_marked",
445 .getter = mlxsw_reg_ppcnt_ecn_marked_get,
446 },
447 };
448
449 #define MLXSW_SP_PORT_HW_EXT_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_ext_stats)
450
451 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_discard_stats[] = {
452 {
453 .str = "discard_ingress_general",
454 .getter = mlxsw_reg_ppcnt_ingress_general_get,
455 },
456 {
457 .str = "discard_ingress_policy_engine",
458 .getter = mlxsw_reg_ppcnt_ingress_policy_engine_get,
459 },
460 {
461 .str = "discard_ingress_vlan_membership",
462 .getter = mlxsw_reg_ppcnt_ingress_vlan_membership_get,
463 },
464 {
465 .str = "discard_ingress_tag_frame_type",
466 .getter = mlxsw_reg_ppcnt_ingress_tag_frame_type_get,
467 },
468 {
469 .str = "discard_egress_vlan_membership",
470 .getter = mlxsw_reg_ppcnt_egress_vlan_membership_get,
471 },
472 {
473 .str = "discard_loopback_filter",
474 .getter = mlxsw_reg_ppcnt_loopback_filter_get,
475 },
476 {
477 .str = "discard_egress_general",
478 .getter = mlxsw_reg_ppcnt_egress_general_get,
479 },
480 {
481 .str = "discard_egress_hoq",
482 .getter = mlxsw_reg_ppcnt_egress_hoq_get,
483 },
484 {
485 .str = "discard_egress_policy_engine",
486 .getter = mlxsw_reg_ppcnt_egress_policy_engine_get,
487 },
488 {
489 .str = "discard_ingress_tx_link_down",
490 .getter = mlxsw_reg_ppcnt_ingress_tx_link_down_get,
491 },
492 {
493 .str = "discard_egress_stp_filter",
494 .getter = mlxsw_reg_ppcnt_egress_stp_filter_get,
495 },
496 {
497 .str = "discard_egress_sll",
498 .getter = mlxsw_reg_ppcnt_egress_sll_get,
499 },
500 };
501
502 #define MLXSW_SP_PORT_HW_DISCARD_STATS_LEN \
503 ARRAY_SIZE(mlxsw_sp_port_hw_discard_stats)
504
505 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_prio_stats[] = {
506 {
507 .str = "rx_octets_prio",
508 .getter = mlxsw_reg_ppcnt_rx_octets_get,
509 },
510 {
511 .str = "rx_frames_prio",
512 .getter = mlxsw_reg_ppcnt_rx_frames_get,
513 },
514 {
515 .str = "tx_octets_prio",
516 .getter = mlxsw_reg_ppcnt_tx_octets_get,
517 },
518 {
519 .str = "tx_frames_prio",
520 .getter = mlxsw_reg_ppcnt_tx_frames_get,
521 },
522 {
523 .str = "rx_pause_prio",
524 .getter = mlxsw_reg_ppcnt_rx_pause_get,
525 },
526 {
527 .str = "rx_pause_duration_prio",
528 .getter = mlxsw_reg_ppcnt_rx_pause_duration_get,
529 },
530 {
531 .str = "tx_pause_prio",
532 .getter = mlxsw_reg_ppcnt_tx_pause_get,
533 },
534 {
535 .str = "tx_pause_duration_prio",
536 .getter = mlxsw_reg_ppcnt_tx_pause_duration_get,
537 },
538 };
539
540 #define MLXSW_SP_PORT_HW_PRIO_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_prio_stats)
541
542 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_tc_stats[] = {
543 {
544 .str = "tc_transmit_queue_tc",
545 .getter = mlxsw_reg_ppcnt_tc_transmit_queue_get,
546 .cells_bytes = true,
547 },
548 {
549 .str = "tc_no_buffer_discard_uc_tc",
550 .getter = mlxsw_reg_ppcnt_tc_no_buffer_discard_uc_get,
551 },
552 };
553
554 #define MLXSW_SP_PORT_HW_TC_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_tc_stats)
555
556 struct mlxsw_sp_port_stats {
557 char str[ETH_GSTRING_LEN];
558 u64 (*getter)(struct mlxsw_sp_port *mlxsw_sp_port);
559 };
560
561 static u64
mlxsw_sp_port_get_transceiver_overheat_stats(struct mlxsw_sp_port * mlxsw_sp_port)562 mlxsw_sp_port_get_transceiver_overheat_stats(struct mlxsw_sp_port *mlxsw_sp_port)
563 {
564 struct mlxsw_sp_port_mapping port_mapping = mlxsw_sp_port->mapping;
565 struct mlxsw_core *mlxsw_core = mlxsw_sp_port->mlxsw_sp->core;
566 u64 stats;
567 int err;
568
569 err = mlxsw_env_module_overheat_counter_get(mlxsw_core,
570 port_mapping.module,
571 &stats);
572 if (err)
573 return mlxsw_sp_port->module_overheat_initial_val;
574
575 return stats - mlxsw_sp_port->module_overheat_initial_val;
576 }
577
578 static struct mlxsw_sp_port_stats mlxsw_sp_port_transceiver_stats[] = {
579 {
580 .str = "transceiver_overheat",
581 .getter = mlxsw_sp_port_get_transceiver_overheat_stats,
582 },
583 };
584
585 #define MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_transceiver_stats)
586
587 #define MLXSW_SP_PORT_ETHTOOL_STATS_LEN (MLXSW_SP_PORT_HW_STATS_LEN + \
588 MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN + \
589 MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN + \
590 MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN + \
591 MLXSW_SP_PORT_HW_EXT_STATS_LEN + \
592 MLXSW_SP_PORT_HW_DISCARD_STATS_LEN + \
593 (MLXSW_SP_PORT_HW_PRIO_STATS_LEN * \
594 IEEE_8021QAZ_MAX_TCS) + \
595 (MLXSW_SP_PORT_HW_TC_STATS_LEN * \
596 TC_MAX_QUEUE) + \
597 MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN)
598
mlxsw_sp_port_get_prio_strings(u8 ** p,int prio)599 static void mlxsw_sp_port_get_prio_strings(u8 **p, int prio)
600 {
601 int i;
602
603 for (i = 0; i < MLXSW_SP_PORT_HW_PRIO_STATS_LEN; i++) {
604 snprintf(*p, ETH_GSTRING_LEN, "%.29s_%.1d",
605 mlxsw_sp_port_hw_prio_stats[i].str, prio);
606 *p += ETH_GSTRING_LEN;
607 }
608 }
609
mlxsw_sp_port_get_tc_strings(u8 ** p,int tc)610 static void mlxsw_sp_port_get_tc_strings(u8 **p, int tc)
611 {
612 int i;
613
614 for (i = 0; i < MLXSW_SP_PORT_HW_TC_STATS_LEN; i++) {
615 snprintf(*p, ETH_GSTRING_LEN, "%.29s_%.1d",
616 mlxsw_sp_port_hw_tc_stats[i].str, tc);
617 *p += ETH_GSTRING_LEN;
618 }
619 }
620
mlxsw_sp_port_get_strings(struct net_device * dev,u32 stringset,u8 * data)621 static void mlxsw_sp_port_get_strings(struct net_device *dev,
622 u32 stringset, u8 *data)
623 {
624 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
625 u8 *p = data;
626 int i;
627
628 switch (stringset) {
629 case ETH_SS_STATS:
630 for (i = 0; i < MLXSW_SP_PORT_HW_STATS_LEN; i++) {
631 memcpy(p, mlxsw_sp_port_hw_stats[i].str,
632 ETH_GSTRING_LEN);
633 p += ETH_GSTRING_LEN;
634 }
635
636 for (i = 0; i < MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN; i++) {
637 memcpy(p, mlxsw_sp_port_hw_rfc_2863_stats[i].str,
638 ETH_GSTRING_LEN);
639 p += ETH_GSTRING_LEN;
640 }
641
642 for (i = 0; i < MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN; i++) {
643 memcpy(p, mlxsw_sp_port_hw_rfc_2819_stats[i].str,
644 ETH_GSTRING_LEN);
645 p += ETH_GSTRING_LEN;
646 }
647
648 for (i = 0; i < MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN; i++) {
649 memcpy(p, mlxsw_sp_port_hw_rfc_3635_stats[i].str,
650 ETH_GSTRING_LEN);
651 p += ETH_GSTRING_LEN;
652 }
653
654 for (i = 0; i < MLXSW_SP_PORT_HW_EXT_STATS_LEN; i++) {
655 memcpy(p, mlxsw_sp_port_hw_ext_stats[i].str,
656 ETH_GSTRING_LEN);
657 p += ETH_GSTRING_LEN;
658 }
659
660 for (i = 0; i < MLXSW_SP_PORT_HW_DISCARD_STATS_LEN; i++) {
661 memcpy(p, mlxsw_sp_port_hw_discard_stats[i].str,
662 ETH_GSTRING_LEN);
663 p += ETH_GSTRING_LEN;
664 }
665
666 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
667 mlxsw_sp_port_get_prio_strings(&p, i);
668
669 for (i = 0; i < TC_MAX_QUEUE; i++)
670 mlxsw_sp_port_get_tc_strings(&p, i);
671
672 mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats_strings(&p);
673
674 for (i = 0; i < MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN; i++) {
675 memcpy(p, mlxsw_sp_port_transceiver_stats[i].str,
676 ETH_GSTRING_LEN);
677 p += ETH_GSTRING_LEN;
678 }
679 break;
680 }
681 }
682
mlxsw_sp_port_set_phys_id(struct net_device * dev,enum ethtool_phys_id_state state)683 static int mlxsw_sp_port_set_phys_id(struct net_device *dev,
684 enum ethtool_phys_id_state state)
685 {
686 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
687 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
688 char mlcr_pl[MLXSW_REG_MLCR_LEN];
689 bool active;
690
691 switch (state) {
692 case ETHTOOL_ID_ACTIVE:
693 active = true;
694 break;
695 case ETHTOOL_ID_INACTIVE:
696 active = false;
697 break;
698 default:
699 return -EOPNOTSUPP;
700 }
701
702 mlxsw_reg_mlcr_pack(mlcr_pl, mlxsw_sp_port->local_port, active);
703 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mlcr), mlcr_pl);
704 }
705
706 static int
mlxsw_sp_get_hw_stats_by_group(struct mlxsw_sp_port_hw_stats ** p_hw_stats,int * p_len,enum mlxsw_reg_ppcnt_grp grp)707 mlxsw_sp_get_hw_stats_by_group(struct mlxsw_sp_port_hw_stats **p_hw_stats,
708 int *p_len, enum mlxsw_reg_ppcnt_grp grp)
709 {
710 switch (grp) {
711 case MLXSW_REG_PPCNT_IEEE_8023_CNT:
712 *p_hw_stats = mlxsw_sp_port_hw_stats;
713 *p_len = MLXSW_SP_PORT_HW_STATS_LEN;
714 break;
715 case MLXSW_REG_PPCNT_RFC_2863_CNT:
716 *p_hw_stats = mlxsw_sp_port_hw_rfc_2863_stats;
717 *p_len = MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN;
718 break;
719 case MLXSW_REG_PPCNT_RFC_2819_CNT:
720 *p_hw_stats = mlxsw_sp_port_hw_rfc_2819_stats;
721 *p_len = MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN;
722 break;
723 case MLXSW_REG_PPCNT_RFC_3635_CNT:
724 *p_hw_stats = mlxsw_sp_port_hw_rfc_3635_stats;
725 *p_len = MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN;
726 break;
727 case MLXSW_REG_PPCNT_EXT_CNT:
728 *p_hw_stats = mlxsw_sp_port_hw_ext_stats;
729 *p_len = MLXSW_SP_PORT_HW_EXT_STATS_LEN;
730 break;
731 case MLXSW_REG_PPCNT_DISCARD_CNT:
732 *p_hw_stats = mlxsw_sp_port_hw_discard_stats;
733 *p_len = MLXSW_SP_PORT_HW_DISCARD_STATS_LEN;
734 break;
735 case MLXSW_REG_PPCNT_PRIO_CNT:
736 *p_hw_stats = mlxsw_sp_port_hw_prio_stats;
737 *p_len = MLXSW_SP_PORT_HW_PRIO_STATS_LEN;
738 break;
739 case MLXSW_REG_PPCNT_TC_CNT:
740 *p_hw_stats = mlxsw_sp_port_hw_tc_stats;
741 *p_len = MLXSW_SP_PORT_HW_TC_STATS_LEN;
742 break;
743 default:
744 WARN_ON(1);
745 return -EOPNOTSUPP;
746 }
747 return 0;
748 }
749
__mlxsw_sp_port_get_stats(struct net_device * dev,enum mlxsw_reg_ppcnt_grp grp,int prio,u64 * data,int data_index)750 static void __mlxsw_sp_port_get_stats(struct net_device *dev,
751 enum mlxsw_reg_ppcnt_grp grp, int prio,
752 u64 *data, int data_index)
753 {
754 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
755 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
756 struct mlxsw_sp_port_hw_stats *hw_stats;
757 char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
758 int i, len;
759 int err;
760
761 err = mlxsw_sp_get_hw_stats_by_group(&hw_stats, &len, grp);
762 if (err)
763 return;
764 mlxsw_sp_port_get_stats_raw(dev, grp, prio, ppcnt_pl);
765 for (i = 0; i < len; i++) {
766 data[data_index + i] = hw_stats[i].getter(ppcnt_pl);
767 if (!hw_stats[i].cells_bytes)
768 continue;
769 data[data_index + i] = mlxsw_sp_cells_bytes(mlxsw_sp,
770 data[data_index + i]);
771 }
772 }
773
__mlxsw_sp_port_get_env_stats(struct net_device * dev,u64 * data,int data_index,struct mlxsw_sp_port_stats * port_stats,int len)774 static void __mlxsw_sp_port_get_env_stats(struct net_device *dev, u64 *data, int data_index,
775 struct mlxsw_sp_port_stats *port_stats,
776 int len)
777 {
778 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
779 int i;
780
781 for (i = 0; i < len; i++)
782 data[data_index + i] = port_stats[i].getter(mlxsw_sp_port);
783 }
784
mlxsw_sp_port_get_stats(struct net_device * dev,struct ethtool_stats * stats,u64 * data)785 static void mlxsw_sp_port_get_stats(struct net_device *dev,
786 struct ethtool_stats *stats, u64 *data)
787 {
788 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
789 int i, data_index = 0;
790
791 /* IEEE 802.3 Counters */
792 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT, 0,
793 data, data_index);
794 data_index = MLXSW_SP_PORT_HW_STATS_LEN;
795
796 /* RFC 2863 Counters */
797 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_RFC_2863_CNT, 0,
798 data, data_index);
799 data_index += MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN;
800
801 /* RFC 2819 Counters */
802 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_RFC_2819_CNT, 0,
803 data, data_index);
804 data_index += MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN;
805
806 /* RFC 3635 Counters */
807 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_RFC_3635_CNT, 0,
808 data, data_index);
809 data_index += MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN;
810
811 /* Extended Counters */
812 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_EXT_CNT, 0,
813 data, data_index);
814 data_index += MLXSW_SP_PORT_HW_EXT_STATS_LEN;
815
816 /* Discard Counters */
817 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_DISCARD_CNT, 0,
818 data, data_index);
819 data_index += MLXSW_SP_PORT_HW_DISCARD_STATS_LEN;
820
821 /* Per-Priority Counters */
822 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
823 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_PRIO_CNT, i,
824 data, data_index);
825 data_index += MLXSW_SP_PORT_HW_PRIO_STATS_LEN;
826 }
827
828 /* Per-TC Counters */
829 for (i = 0; i < TC_MAX_QUEUE; i++) {
830 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_TC_CNT, i,
831 data, data_index);
832 data_index += MLXSW_SP_PORT_HW_TC_STATS_LEN;
833 }
834
835 /* PTP counters */
836 mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats(mlxsw_sp_port,
837 data, data_index);
838 data_index += mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats_count();
839
840 /* Transceiver counters */
841 __mlxsw_sp_port_get_env_stats(dev, data, data_index, mlxsw_sp_port_transceiver_stats,
842 MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN);
843 data_index += MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN;
844 }
845
mlxsw_sp_port_get_sset_count(struct net_device * dev,int sset)846 static int mlxsw_sp_port_get_sset_count(struct net_device *dev, int sset)
847 {
848 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
849
850 switch (sset) {
851 case ETH_SS_STATS:
852 return MLXSW_SP_PORT_ETHTOOL_STATS_LEN +
853 mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats_count();
854 default:
855 return -EOPNOTSUPP;
856 }
857 }
858
859 static void
mlxsw_sp_port_get_link_supported(struct mlxsw_sp * mlxsw_sp,u32 eth_proto_cap,struct ethtool_link_ksettings * cmd)860 mlxsw_sp_port_get_link_supported(struct mlxsw_sp *mlxsw_sp, u32 eth_proto_cap,
861 struct ethtool_link_ksettings *cmd)
862 {
863 const struct mlxsw_sp_port_type_speed_ops *ops;
864
865 ops = mlxsw_sp->port_type_speed_ops;
866
867 ethtool_link_ksettings_add_link_mode(cmd, supported, Asym_Pause);
868 ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
869 ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
870
871 ops->from_ptys_supported_port(mlxsw_sp, eth_proto_cap, cmd);
872 ops->from_ptys_link(mlxsw_sp, eth_proto_cap,
873 cmd->link_modes.supported);
874 }
875
876 static void
mlxsw_sp_port_get_link_advertise(struct mlxsw_sp * mlxsw_sp,u32 eth_proto_admin,bool autoneg,struct ethtool_link_ksettings * cmd)877 mlxsw_sp_port_get_link_advertise(struct mlxsw_sp *mlxsw_sp,
878 u32 eth_proto_admin, bool autoneg,
879 struct ethtool_link_ksettings *cmd)
880 {
881 const struct mlxsw_sp_port_type_speed_ops *ops;
882
883 ops = mlxsw_sp->port_type_speed_ops;
884
885 if (!autoneg)
886 return;
887
888 ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
889 ops->from_ptys_link(mlxsw_sp, eth_proto_admin,
890 cmd->link_modes.advertising);
891 }
892
893 static u8
mlxsw_sp_port_connector_port(enum mlxsw_reg_ptys_connector_type connector_type)894 mlxsw_sp_port_connector_port(enum mlxsw_reg_ptys_connector_type connector_type)
895 {
896 switch (connector_type) {
897 case MLXSW_REG_PTYS_CONNECTOR_TYPE_UNKNOWN_OR_NO_CONNECTOR:
898 return PORT_OTHER;
899 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_NONE:
900 return PORT_NONE;
901 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_TP:
902 return PORT_TP;
903 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_AUI:
904 return PORT_AUI;
905 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_BNC:
906 return PORT_BNC;
907 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_MII:
908 return PORT_MII;
909 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_FIBRE:
910 return PORT_FIBRE;
911 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_DA:
912 return PORT_DA;
913 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_OTHER:
914 return PORT_OTHER;
915 default:
916 WARN_ON_ONCE(1);
917 return PORT_OTHER;
918 }
919 }
920
mlxsw_sp_port_ptys_query(struct mlxsw_sp_port * mlxsw_sp_port,u32 * p_eth_proto_cap,u32 * p_eth_proto_admin,u32 * p_eth_proto_oper,u8 * p_connector_type)921 static int mlxsw_sp_port_ptys_query(struct mlxsw_sp_port *mlxsw_sp_port,
922 u32 *p_eth_proto_cap, u32 *p_eth_proto_admin,
923 u32 *p_eth_proto_oper, u8 *p_connector_type)
924 {
925 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
926 const struct mlxsw_sp_port_type_speed_ops *ops;
927 char ptys_pl[MLXSW_REG_PTYS_LEN];
928 int err;
929
930 ops = mlxsw_sp->port_type_speed_ops;
931
932 ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port, 0, false);
933 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
934 if (err)
935 return err;
936
937 ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, p_eth_proto_cap, p_eth_proto_admin,
938 p_eth_proto_oper);
939 if (p_connector_type)
940 *p_connector_type = mlxsw_reg_ptys_connector_type_get(ptys_pl);
941 return 0;
942 }
943
mlxsw_sp_port_get_link_ksettings(struct net_device * dev,struct ethtool_link_ksettings * cmd)944 static int mlxsw_sp_port_get_link_ksettings(struct net_device *dev,
945 struct ethtool_link_ksettings *cmd)
946 {
947 u32 eth_proto_cap, eth_proto_admin, eth_proto_oper;
948 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
949 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
950 const struct mlxsw_sp_port_type_speed_ops *ops;
951 u8 connector_type;
952 bool autoneg;
953 int err;
954
955 err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, ð_proto_cap, ð_proto_admin,
956 ð_proto_oper, &connector_type);
957 if (err)
958 return err;
959
960 ops = mlxsw_sp->port_type_speed_ops;
961 autoneg = mlxsw_sp_port->link.autoneg;
962
963 mlxsw_sp_port_get_link_supported(mlxsw_sp, eth_proto_cap, cmd);
964
965 mlxsw_sp_port_get_link_advertise(mlxsw_sp, eth_proto_admin, autoneg, cmd);
966
967 cmd->base.autoneg = autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
968 cmd->base.port = mlxsw_sp_port_connector_port(connector_type);
969 ops->from_ptys_link_mode(mlxsw_sp, netif_carrier_ok(dev),
970 eth_proto_oper, cmd);
971
972 return 0;
973 }
974
975 static int
mlxsw_sp_port_set_link_ksettings(struct net_device * dev,const struct ethtool_link_ksettings * cmd)976 mlxsw_sp_port_set_link_ksettings(struct net_device *dev,
977 const struct ethtool_link_ksettings *cmd)
978 {
979 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
980 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
981 const struct mlxsw_sp_port_type_speed_ops *ops;
982 char ptys_pl[MLXSW_REG_PTYS_LEN];
983 u32 eth_proto_cap, eth_proto_new;
984 bool autoneg;
985 int err;
986
987 ops = mlxsw_sp->port_type_speed_ops;
988
989 ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,
990 0, false);
991 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
992 if (err)
993 return err;
994 ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, ð_proto_cap, NULL, NULL);
995
996 autoneg = cmd->base.autoneg == AUTONEG_ENABLE;
997 eth_proto_new = autoneg ?
998 ops->to_ptys_advert_link(mlxsw_sp, cmd) :
999 ops->to_ptys_speed_lanes(mlxsw_sp, mlxsw_sp_port->mapping.width,
1000 cmd);
1001
1002 eth_proto_new = eth_proto_new & eth_proto_cap;
1003 if (!eth_proto_new) {
1004 netdev_err(dev, "No supported speed or lanes requested\n");
1005 return -EINVAL;
1006 }
1007
1008 ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,
1009 eth_proto_new, autoneg);
1010 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
1011 if (err)
1012 return err;
1013
1014 mlxsw_sp_port->link.autoneg = autoneg;
1015
1016 if (!netif_running(dev))
1017 return 0;
1018
1019 mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false);
1020 mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true);
1021
1022 return 0;
1023 }
1024
mlxsw_sp_get_module_info(struct net_device * netdev,struct ethtool_modinfo * modinfo)1025 static int mlxsw_sp_get_module_info(struct net_device *netdev,
1026 struct ethtool_modinfo *modinfo)
1027 {
1028 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev);
1029 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1030 int err;
1031
1032 err = mlxsw_env_get_module_info(mlxsw_sp->core,
1033 mlxsw_sp_port->mapping.module,
1034 modinfo);
1035
1036 return err;
1037 }
1038
mlxsw_sp_get_module_eeprom(struct net_device * netdev,struct ethtool_eeprom * ee,u8 * data)1039 static int mlxsw_sp_get_module_eeprom(struct net_device *netdev,
1040 struct ethtool_eeprom *ee, u8 *data)
1041 {
1042 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev);
1043 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1044 int err;
1045
1046 err = mlxsw_env_get_module_eeprom(netdev, mlxsw_sp->core,
1047 mlxsw_sp_port->mapping.module, ee,
1048 data);
1049
1050 return err;
1051 }
1052
1053 static int
mlxsw_sp_get_module_eeprom_by_page(struct net_device * dev,const struct ethtool_module_eeprom * page,struct netlink_ext_ack * extack)1054 mlxsw_sp_get_module_eeprom_by_page(struct net_device *dev,
1055 const struct ethtool_module_eeprom *page,
1056 struct netlink_ext_ack *extack)
1057 {
1058 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1059 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1060 u8 module = mlxsw_sp_port->mapping.module;
1061
1062 return mlxsw_env_get_module_eeprom_by_page(mlxsw_sp->core, module, page,
1063 extack);
1064 }
1065
1066 static int
mlxsw_sp_get_ts_info(struct net_device * netdev,struct ethtool_ts_info * info)1067 mlxsw_sp_get_ts_info(struct net_device *netdev, struct ethtool_ts_info *info)
1068 {
1069 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev);
1070 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1071
1072 return mlxsw_sp->ptp_ops->get_ts_info(mlxsw_sp, info);
1073 }
1074
1075 static void
mlxsw_sp_get_eth_phy_stats(struct net_device * dev,struct ethtool_eth_phy_stats * phy_stats)1076 mlxsw_sp_get_eth_phy_stats(struct net_device *dev,
1077 struct ethtool_eth_phy_stats *phy_stats)
1078 {
1079 char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
1080
1081 if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,
1082 0, ppcnt_pl))
1083 return;
1084
1085 phy_stats->SymbolErrorDuringCarrier =
1086 mlxsw_reg_ppcnt_a_symbol_error_during_carrier_get(ppcnt_pl);
1087 }
1088
1089 static void
mlxsw_sp_get_eth_mac_stats(struct net_device * dev,struct ethtool_eth_mac_stats * mac_stats)1090 mlxsw_sp_get_eth_mac_stats(struct net_device *dev,
1091 struct ethtool_eth_mac_stats *mac_stats)
1092 {
1093 char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
1094
1095 if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,
1096 0, ppcnt_pl))
1097 return;
1098
1099 mac_stats->FramesTransmittedOK =
1100 mlxsw_reg_ppcnt_a_frames_transmitted_ok_get(ppcnt_pl);
1101 mac_stats->FramesReceivedOK =
1102 mlxsw_reg_ppcnt_a_frames_received_ok_get(ppcnt_pl);
1103 mac_stats->FrameCheckSequenceErrors =
1104 mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get(ppcnt_pl);
1105 mac_stats->AlignmentErrors =
1106 mlxsw_reg_ppcnt_a_alignment_errors_get(ppcnt_pl);
1107 mac_stats->OctetsTransmittedOK =
1108 mlxsw_reg_ppcnt_a_octets_transmitted_ok_get(ppcnt_pl);
1109 mac_stats->OctetsReceivedOK =
1110 mlxsw_reg_ppcnt_a_octets_received_ok_get(ppcnt_pl);
1111 mac_stats->MulticastFramesXmittedOK =
1112 mlxsw_reg_ppcnt_a_multicast_frames_xmitted_ok_get(ppcnt_pl);
1113 mac_stats->BroadcastFramesXmittedOK =
1114 mlxsw_reg_ppcnt_a_broadcast_frames_xmitted_ok_get(ppcnt_pl);
1115 mac_stats->MulticastFramesReceivedOK =
1116 mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get(ppcnt_pl);
1117 mac_stats->BroadcastFramesReceivedOK =
1118 mlxsw_reg_ppcnt_a_broadcast_frames_received_ok_get(ppcnt_pl);
1119 mac_stats->InRangeLengthErrors =
1120 mlxsw_reg_ppcnt_a_in_range_length_errors_get(ppcnt_pl);
1121 mac_stats->OutOfRangeLengthField =
1122 mlxsw_reg_ppcnt_a_out_of_range_length_field_get(ppcnt_pl);
1123 mac_stats->FrameTooLongErrors =
1124 mlxsw_reg_ppcnt_a_frame_too_long_errors_get(ppcnt_pl);
1125 }
1126
1127 static void
mlxsw_sp_get_eth_ctrl_stats(struct net_device * dev,struct ethtool_eth_ctrl_stats * ctrl_stats)1128 mlxsw_sp_get_eth_ctrl_stats(struct net_device *dev,
1129 struct ethtool_eth_ctrl_stats *ctrl_stats)
1130 {
1131 char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
1132
1133 if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,
1134 0, ppcnt_pl))
1135 return;
1136
1137 ctrl_stats->MACControlFramesTransmitted =
1138 mlxsw_reg_ppcnt_a_mac_control_frames_transmitted_get(ppcnt_pl);
1139 ctrl_stats->MACControlFramesReceived =
1140 mlxsw_reg_ppcnt_a_mac_control_frames_received_get(ppcnt_pl);
1141 ctrl_stats->UnsupportedOpcodesReceived =
1142 mlxsw_reg_ppcnt_a_unsupported_opcodes_received_get(ppcnt_pl);
1143 }
1144
1145 static const struct ethtool_rmon_hist_range mlxsw_rmon_ranges[] = {
1146 { 0, 64 },
1147 { 65, 127 },
1148 { 128, 255 },
1149 { 256, 511 },
1150 { 512, 1023 },
1151 { 1024, 1518 },
1152 { 1519, 2047 },
1153 { 2048, 4095 },
1154 { 4096, 8191 },
1155 { 8192, 10239 },
1156 {}
1157 };
1158
1159 static void
mlxsw_sp_get_rmon_stats(struct net_device * dev,struct ethtool_rmon_stats * rmon,const struct ethtool_rmon_hist_range ** ranges)1160 mlxsw_sp_get_rmon_stats(struct net_device *dev,
1161 struct ethtool_rmon_stats *rmon,
1162 const struct ethtool_rmon_hist_range **ranges)
1163 {
1164 char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
1165
1166 if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_RFC_2819_CNT,
1167 0, ppcnt_pl))
1168 return;
1169
1170 rmon->undersize_pkts =
1171 mlxsw_reg_ppcnt_ether_stats_undersize_pkts_get(ppcnt_pl);
1172 rmon->oversize_pkts =
1173 mlxsw_reg_ppcnt_ether_stats_oversize_pkts_get(ppcnt_pl);
1174 rmon->fragments =
1175 mlxsw_reg_ppcnt_ether_stats_fragments_get(ppcnt_pl);
1176
1177 rmon->hist[0] = mlxsw_reg_ppcnt_ether_stats_pkts64octets_get(ppcnt_pl);
1178 rmon->hist[1] =
1179 mlxsw_reg_ppcnt_ether_stats_pkts65to127octets_get(ppcnt_pl);
1180 rmon->hist[2] =
1181 mlxsw_reg_ppcnt_ether_stats_pkts128to255octets_get(ppcnt_pl);
1182 rmon->hist[3] =
1183 mlxsw_reg_ppcnt_ether_stats_pkts256to511octets_get(ppcnt_pl);
1184 rmon->hist[4] =
1185 mlxsw_reg_ppcnt_ether_stats_pkts512to1023octets_get(ppcnt_pl);
1186 rmon->hist[5] =
1187 mlxsw_reg_ppcnt_ether_stats_pkts1024to1518octets_get(ppcnt_pl);
1188 rmon->hist[6] =
1189 mlxsw_reg_ppcnt_ether_stats_pkts1519to2047octets_get(ppcnt_pl);
1190 rmon->hist[7] =
1191 mlxsw_reg_ppcnt_ether_stats_pkts2048to4095octets_get(ppcnt_pl);
1192 rmon->hist[8] =
1193 mlxsw_reg_ppcnt_ether_stats_pkts4096to8191octets_get(ppcnt_pl);
1194 rmon->hist[9] =
1195 mlxsw_reg_ppcnt_ether_stats_pkts8192to10239octets_get(ppcnt_pl);
1196
1197 *ranges = mlxsw_rmon_ranges;
1198 }
1199
1200 const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
1201 .cap_link_lanes_supported = true,
1202 .get_drvinfo = mlxsw_sp_port_get_drvinfo,
1203 .get_link = ethtool_op_get_link,
1204 .get_link_ext_state = mlxsw_sp_port_get_link_ext_state,
1205 .get_pauseparam = mlxsw_sp_port_get_pauseparam,
1206 .set_pauseparam = mlxsw_sp_port_set_pauseparam,
1207 .get_strings = mlxsw_sp_port_get_strings,
1208 .set_phys_id = mlxsw_sp_port_set_phys_id,
1209 .get_ethtool_stats = mlxsw_sp_port_get_stats,
1210 .get_sset_count = mlxsw_sp_port_get_sset_count,
1211 .get_link_ksettings = mlxsw_sp_port_get_link_ksettings,
1212 .set_link_ksettings = mlxsw_sp_port_set_link_ksettings,
1213 .get_module_info = mlxsw_sp_get_module_info,
1214 .get_module_eeprom = mlxsw_sp_get_module_eeprom,
1215 .get_module_eeprom_by_page = mlxsw_sp_get_module_eeprom_by_page,
1216 .get_ts_info = mlxsw_sp_get_ts_info,
1217 .get_eth_phy_stats = mlxsw_sp_get_eth_phy_stats,
1218 .get_eth_mac_stats = mlxsw_sp_get_eth_mac_stats,
1219 .get_eth_ctrl_stats = mlxsw_sp_get_eth_ctrl_stats,
1220 .get_rmon_stats = mlxsw_sp_get_rmon_stats,
1221 };
1222
1223 struct mlxsw_sp1_port_link_mode {
1224 enum ethtool_link_mode_bit_indices mask_ethtool;
1225 u32 mask;
1226 u32 speed;
1227 };
1228
1229 static const struct mlxsw_sp1_port_link_mode mlxsw_sp1_port_link_mode[] = {
1230 {
1231 .mask = MLXSW_REG_PTYS_ETH_SPEED_SGMII |
1232 MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX,
1233 .mask_ethtool = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
1234 .speed = SPEED_1000,
1235 },
1236 {
1237 .mask = MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CX4 |
1238 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4,
1239 .mask_ethtool = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
1240 .speed = SPEED_10000,
1241 },
1242 {
1243 .mask = MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR |
1244 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR |
1245 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR |
1246 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_ER_LR,
1247 .mask_ethtool = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
1248 .speed = SPEED_10000,
1249 },
1250 {
1251 .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4,
1252 .mask_ethtool = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
1253 .speed = SPEED_40000,
1254 },
1255 {
1256 .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4,
1257 .mask_ethtool = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
1258 .speed = SPEED_40000,
1259 },
1260 {
1261 .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4,
1262 .mask_ethtool = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
1263 .speed = SPEED_40000,
1264 },
1265 {
1266 .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_LR4_ER4,
1267 .mask_ethtool = ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
1268 .speed = SPEED_40000,
1269 },
1270 {
1271 .mask = MLXSW_REG_PTYS_ETH_SPEED_25GBASE_CR,
1272 .mask_ethtool = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
1273 .speed = SPEED_25000,
1274 },
1275 {
1276 .mask = MLXSW_REG_PTYS_ETH_SPEED_25GBASE_KR,
1277 .mask_ethtool = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
1278 .speed = SPEED_25000,
1279 },
1280 {
1281 .mask = MLXSW_REG_PTYS_ETH_SPEED_25GBASE_SR,
1282 .mask_ethtool = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
1283 .speed = SPEED_25000,
1284 },
1285 {
1286 .mask = MLXSW_REG_PTYS_ETH_SPEED_50GBASE_CR2,
1287 .mask_ethtool = ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
1288 .speed = SPEED_50000,
1289 },
1290 {
1291 .mask = MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR2,
1292 .mask_ethtool = ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
1293 .speed = SPEED_50000,
1294 },
1295 {
1296 .mask = MLXSW_REG_PTYS_ETH_SPEED_50GBASE_SR2,
1297 .mask_ethtool = ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
1298 .speed = SPEED_50000,
1299 },
1300 {
1301 .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4,
1302 .mask_ethtool = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
1303 .speed = SPEED_100000,
1304 },
1305 {
1306 .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4,
1307 .mask_ethtool = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
1308 .speed = SPEED_100000,
1309 },
1310 {
1311 .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4,
1312 .mask_ethtool = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
1313 .speed = SPEED_100000,
1314 },
1315 {
1316 .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_LR4_ER4,
1317 .mask_ethtool = ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
1318 .speed = SPEED_100000,
1319 },
1320 };
1321
1322 #define MLXSW_SP1_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp1_port_link_mode)
1323
1324 static void
mlxsw_sp1_from_ptys_supported_port(struct mlxsw_sp * mlxsw_sp,u32 ptys_eth_proto,struct ethtool_link_ksettings * cmd)1325 mlxsw_sp1_from_ptys_supported_port(struct mlxsw_sp *mlxsw_sp,
1326 u32 ptys_eth_proto,
1327 struct ethtool_link_ksettings *cmd)
1328 {
1329 if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR |
1330 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR |
1331 MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4 |
1332 MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4 |
1333 MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 |
1334 MLXSW_REG_PTYS_ETH_SPEED_SGMII))
1335 ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
1336
1337 if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR |
1338 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4 |
1339 MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4 |
1340 MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 |
1341 MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX))
1342 ethtool_link_ksettings_add_link_mode(cmd, supported, Backplane);
1343 }
1344
1345 static void
mlxsw_sp1_from_ptys_link(struct mlxsw_sp * mlxsw_sp,u32 ptys_eth_proto,unsigned long * mode)1346 mlxsw_sp1_from_ptys_link(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto,
1347 unsigned long *mode)
1348 {
1349 int i;
1350
1351 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
1352 if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask)
1353 __set_bit(mlxsw_sp1_port_link_mode[i].mask_ethtool,
1354 mode);
1355 }
1356 }
1357
1358 static u32
mlxsw_sp1_from_ptys_speed(struct mlxsw_sp * mlxsw_sp,u32 ptys_eth_proto)1359 mlxsw_sp1_from_ptys_speed(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto)
1360 {
1361 int i;
1362
1363 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
1364 if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask)
1365 return mlxsw_sp1_port_link_mode[i].speed;
1366 }
1367
1368 return SPEED_UNKNOWN;
1369 }
1370
1371 static void
mlxsw_sp1_from_ptys_link_mode(struct mlxsw_sp * mlxsw_sp,bool carrier_ok,u32 ptys_eth_proto,struct ethtool_link_ksettings * cmd)1372 mlxsw_sp1_from_ptys_link_mode(struct mlxsw_sp *mlxsw_sp, bool carrier_ok,
1373 u32 ptys_eth_proto,
1374 struct ethtool_link_ksettings *cmd)
1375 {
1376 struct mlxsw_sp1_port_link_mode link;
1377 int i;
1378
1379 cmd->base.speed = SPEED_UNKNOWN;
1380 cmd->base.duplex = DUPLEX_UNKNOWN;
1381 cmd->lanes = 0;
1382
1383 if (!carrier_ok)
1384 return;
1385
1386 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
1387 if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask) {
1388 link = mlxsw_sp1_port_link_mode[i];
1389 ethtool_params_from_link_mode(cmd,
1390 link.mask_ethtool);
1391 }
1392 }
1393 }
1394
mlxsw_sp1_ptys_max_speed(struct mlxsw_sp_port * mlxsw_sp_port,u32 * p_max_speed)1395 static int mlxsw_sp1_ptys_max_speed(struct mlxsw_sp_port *mlxsw_sp_port, u32 *p_max_speed)
1396 {
1397 u32 eth_proto_cap;
1398 u32 max_speed = 0;
1399 int err;
1400 int i;
1401
1402 err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, ð_proto_cap, NULL, NULL, NULL);
1403 if (err)
1404 return err;
1405
1406 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
1407 if ((eth_proto_cap & mlxsw_sp1_port_link_mode[i].mask) &&
1408 mlxsw_sp1_port_link_mode[i].speed > max_speed)
1409 max_speed = mlxsw_sp1_port_link_mode[i].speed;
1410 }
1411
1412 *p_max_speed = max_speed;
1413 return 0;
1414 }
1415
1416 static u32
mlxsw_sp1_to_ptys_advert_link(struct mlxsw_sp * mlxsw_sp,const struct ethtool_link_ksettings * cmd)1417 mlxsw_sp1_to_ptys_advert_link(struct mlxsw_sp *mlxsw_sp,
1418 const struct ethtool_link_ksettings *cmd)
1419 {
1420 u32 ptys_proto = 0;
1421 int i;
1422
1423 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
1424 if (test_bit(mlxsw_sp1_port_link_mode[i].mask_ethtool,
1425 cmd->link_modes.advertising))
1426 ptys_proto |= mlxsw_sp1_port_link_mode[i].mask;
1427 }
1428 return ptys_proto;
1429 }
1430
mlxsw_sp1_to_ptys_speed_lanes(struct mlxsw_sp * mlxsw_sp,u8 width,const struct ethtool_link_ksettings * cmd)1431 static u32 mlxsw_sp1_to_ptys_speed_lanes(struct mlxsw_sp *mlxsw_sp, u8 width,
1432 const struct ethtool_link_ksettings *cmd)
1433 {
1434 u32 ptys_proto = 0;
1435 int i;
1436
1437 if (cmd->lanes > width)
1438 return ptys_proto;
1439
1440 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
1441 if (cmd->base.speed == mlxsw_sp1_port_link_mode[i].speed)
1442 ptys_proto |= mlxsw_sp1_port_link_mode[i].mask;
1443 }
1444 return ptys_proto;
1445 }
1446
1447 static void
mlxsw_sp1_reg_ptys_eth_pack(struct mlxsw_sp * mlxsw_sp,char * payload,u8 local_port,u32 proto_admin,bool autoneg)1448 mlxsw_sp1_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload,
1449 u8 local_port, u32 proto_admin, bool autoneg)
1450 {
1451 mlxsw_reg_ptys_eth_pack(payload, local_port, proto_admin, autoneg);
1452 }
1453
1454 static void
mlxsw_sp1_reg_ptys_eth_unpack(struct mlxsw_sp * mlxsw_sp,char * payload,u32 * p_eth_proto_cap,u32 * p_eth_proto_admin,u32 * p_eth_proto_oper)1455 mlxsw_sp1_reg_ptys_eth_unpack(struct mlxsw_sp *mlxsw_sp, char *payload,
1456 u32 *p_eth_proto_cap, u32 *p_eth_proto_admin,
1457 u32 *p_eth_proto_oper)
1458 {
1459 mlxsw_reg_ptys_eth_unpack(payload, p_eth_proto_cap, p_eth_proto_admin,
1460 p_eth_proto_oper);
1461 }
1462
mlxsw_sp1_ptys_proto_cap_masked_get(u32 eth_proto_cap)1463 static u32 mlxsw_sp1_ptys_proto_cap_masked_get(u32 eth_proto_cap)
1464 {
1465 u32 ptys_proto_cap_masked = 0;
1466 int i;
1467
1468 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
1469 if (mlxsw_sp1_port_link_mode[i].mask & eth_proto_cap)
1470 ptys_proto_cap_masked |=
1471 mlxsw_sp1_port_link_mode[i].mask;
1472 }
1473
1474 return ptys_proto_cap_masked;
1475 }
1476
1477 const struct mlxsw_sp_port_type_speed_ops mlxsw_sp1_port_type_speed_ops = {
1478 .from_ptys_supported_port = mlxsw_sp1_from_ptys_supported_port,
1479 .from_ptys_link = mlxsw_sp1_from_ptys_link,
1480 .from_ptys_speed = mlxsw_sp1_from_ptys_speed,
1481 .from_ptys_link_mode = mlxsw_sp1_from_ptys_link_mode,
1482 .ptys_max_speed = mlxsw_sp1_ptys_max_speed,
1483 .to_ptys_advert_link = mlxsw_sp1_to_ptys_advert_link,
1484 .to_ptys_speed_lanes = mlxsw_sp1_to_ptys_speed_lanes,
1485 .reg_ptys_eth_pack = mlxsw_sp1_reg_ptys_eth_pack,
1486 .reg_ptys_eth_unpack = mlxsw_sp1_reg_ptys_eth_unpack,
1487 .ptys_proto_cap_masked_get = mlxsw_sp1_ptys_proto_cap_masked_get,
1488 };
1489
1490 static const enum ethtool_link_mode_bit_indices
1491 mlxsw_sp2_mask_ethtool_sgmii_100m[] = {
1492 ETHTOOL_LINK_MODE_100baseT_Full_BIT,
1493 };
1494
1495 #define MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN \
1496 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_sgmii_100m)
1497
1498 static const enum ethtool_link_mode_bit_indices
1499 mlxsw_sp2_mask_ethtool_1000base_x_sgmii[] = {
1500 ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
1501 ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
1502 };
1503
1504 #define MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN \
1505 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_1000base_x_sgmii)
1506
1507 static const enum ethtool_link_mode_bit_indices
1508 mlxsw_sp2_mask_ethtool_5gbase_r[] = {
1509 ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
1510 };
1511
1512 #define MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN \
1513 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_5gbase_r)
1514
1515 static const enum ethtool_link_mode_bit_indices
1516 mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g[] = {
1517 ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
1518 ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
1519 ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
1520 ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
1521 ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
1522 ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
1523 ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
1524 };
1525
1526 #define MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN \
1527 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g)
1528
1529 static const enum ethtool_link_mode_bit_indices
1530 mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g[] = {
1531 ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
1532 ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
1533 ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
1534 ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
1535 };
1536
1537 #define MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN \
1538 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g)
1539
1540 static const enum ethtool_link_mode_bit_indices
1541 mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr[] = {
1542 ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
1543 ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
1544 ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
1545 };
1546
1547 #define MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_LEN \
1548 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr)
1549
1550 static const enum ethtool_link_mode_bit_indices
1551 mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2[] = {
1552 ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
1553 ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
1554 ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
1555 };
1556
1557 #define MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN \
1558 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2)
1559
1560 static const enum ethtool_link_mode_bit_indices
1561 mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr[] = {
1562 ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
1563 ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
1564 ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
1565 ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
1566 ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
1567 };
1568
1569 #define MLXSW_SP2_MASK_ETHTOOL_50GAUI_1_LAUI_1_50GBASE_CR_KR_LEN \
1570 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr)
1571
1572 static const enum ethtool_link_mode_bit_indices
1573 mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4[] = {
1574 ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
1575 ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
1576 ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
1577 ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
1578 };
1579
1580 #define MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN \
1581 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4)
1582
1583 static const enum ethtool_link_mode_bit_indices
1584 mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2[] = {
1585 ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
1586 ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
1587 ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
1588 ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
1589 ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
1590 };
1591
1592 #define MLXSW_SP2_MASK_ETHTOOL_100GAUI_2_100GBASE_CR2_KR2_LEN \
1593 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2)
1594
1595 static const enum ethtool_link_mode_bit_indices
1596 mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4[] = {
1597 ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT,
1598 ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT,
1599 ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT,
1600 ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT,
1601 ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT,
1602 };
1603
1604 #define MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN \
1605 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4)
1606
1607 static const enum ethtool_link_mode_bit_indices
1608 mlxsw_sp2_mask_ethtool_400gaui_8[] = {
1609 ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT,
1610 ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT,
1611 ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT,
1612 ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT,
1613 ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT,
1614 };
1615
1616 #define MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN \
1617 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_400gaui_8)
1618
1619 #define MLXSW_SP_PORT_MASK_WIDTH_1X BIT(0)
1620 #define MLXSW_SP_PORT_MASK_WIDTH_2X BIT(1)
1621 #define MLXSW_SP_PORT_MASK_WIDTH_4X BIT(2)
1622 #define MLXSW_SP_PORT_MASK_WIDTH_8X BIT(3)
1623
mlxsw_sp_port_mask_width_get(u8 width)1624 static u8 mlxsw_sp_port_mask_width_get(u8 width)
1625 {
1626 switch (width) {
1627 case 1:
1628 return MLXSW_SP_PORT_MASK_WIDTH_1X;
1629 case 2:
1630 return MLXSW_SP_PORT_MASK_WIDTH_2X;
1631 case 4:
1632 return MLXSW_SP_PORT_MASK_WIDTH_4X;
1633 case 8:
1634 return MLXSW_SP_PORT_MASK_WIDTH_8X;
1635 default:
1636 WARN_ON_ONCE(1);
1637 return 0;
1638 }
1639 }
1640
1641 struct mlxsw_sp2_port_link_mode {
1642 const enum ethtool_link_mode_bit_indices *mask_ethtool;
1643 int m_ethtool_len;
1644 u32 mask;
1645 u32 speed;
1646 u32 width;
1647 u8 mask_sup_width;
1648 };
1649
1650 static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = {
1651 {
1652 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_SGMII_100M,
1653 .mask_ethtool = mlxsw_sp2_mask_ethtool_sgmii_100m,
1654 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN,
1655 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X |
1656 MLXSW_SP_PORT_MASK_WIDTH_2X |
1657 MLXSW_SP_PORT_MASK_WIDTH_4X |
1658 MLXSW_SP_PORT_MASK_WIDTH_8X,
1659 .speed = SPEED_100,
1660 .width = 1,
1661 },
1662 {
1663 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_1000BASE_X_SGMII,
1664 .mask_ethtool = mlxsw_sp2_mask_ethtool_1000base_x_sgmii,
1665 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN,
1666 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X |
1667 MLXSW_SP_PORT_MASK_WIDTH_2X |
1668 MLXSW_SP_PORT_MASK_WIDTH_4X |
1669 MLXSW_SP_PORT_MASK_WIDTH_8X,
1670 .speed = SPEED_1000,
1671 .width = 1,
1672 },
1673 {
1674 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_5GBASE_R,
1675 .mask_ethtool = mlxsw_sp2_mask_ethtool_5gbase_r,
1676 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN,
1677 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X |
1678 MLXSW_SP_PORT_MASK_WIDTH_2X |
1679 MLXSW_SP_PORT_MASK_WIDTH_4X |
1680 MLXSW_SP_PORT_MASK_WIDTH_8X,
1681 .speed = SPEED_5000,
1682 .width = 1,
1683 },
1684 {
1685 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_XFI_XAUI_1_10G,
1686 .mask_ethtool = mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g,
1687 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN,
1688 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X |
1689 MLXSW_SP_PORT_MASK_WIDTH_2X |
1690 MLXSW_SP_PORT_MASK_WIDTH_4X |
1691 MLXSW_SP_PORT_MASK_WIDTH_8X,
1692 .speed = SPEED_10000,
1693 .width = 1,
1694 },
1695 {
1696 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_XLAUI_4_XLPPI_4_40G,
1697 .mask_ethtool = mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g,
1698 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN,
1699 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_4X |
1700 MLXSW_SP_PORT_MASK_WIDTH_8X,
1701 .speed = SPEED_40000,
1702 .width = 4,
1703 },
1704 {
1705 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_25GAUI_1_25GBASE_CR_KR,
1706 .mask_ethtool = mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr,
1707 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_LEN,
1708 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X |
1709 MLXSW_SP_PORT_MASK_WIDTH_2X |
1710 MLXSW_SP_PORT_MASK_WIDTH_4X |
1711 MLXSW_SP_PORT_MASK_WIDTH_8X,
1712 .speed = SPEED_25000,
1713 .width = 1,
1714 },
1715 {
1716 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_2_LAUI_2_50GBASE_CR2_KR2,
1717 .mask_ethtool = mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2,
1718 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN,
1719 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_2X |
1720 MLXSW_SP_PORT_MASK_WIDTH_4X |
1721 MLXSW_SP_PORT_MASK_WIDTH_8X,
1722 .speed = SPEED_50000,
1723 .width = 2,
1724 },
1725 {
1726 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_1_LAUI_1_50GBASE_CR_KR,
1727 .mask_ethtool = mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr,
1728 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_50GAUI_1_LAUI_1_50GBASE_CR_KR_LEN,
1729 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X,
1730 .speed = SPEED_50000,
1731 .width = 1,
1732 },
1733 {
1734 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_CAUI_4_100GBASE_CR4_KR4,
1735 .mask_ethtool = mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4,
1736 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN,
1737 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_4X |
1738 MLXSW_SP_PORT_MASK_WIDTH_8X,
1739 .speed = SPEED_100000,
1740 .width = 4,
1741 },
1742 {
1743 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_100GAUI_2_100GBASE_CR2_KR2,
1744 .mask_ethtool = mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2,
1745 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_100GAUI_2_100GBASE_CR2_KR2_LEN,
1746 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_2X,
1747 .speed = SPEED_100000,
1748 .width = 2,
1749 },
1750 {
1751 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_200GAUI_4_200GBASE_CR4_KR4,
1752 .mask_ethtool = mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4,
1753 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN,
1754 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_4X |
1755 MLXSW_SP_PORT_MASK_WIDTH_8X,
1756 .speed = SPEED_200000,
1757 .width = 4,
1758 },
1759 {
1760 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_400GAUI_8,
1761 .mask_ethtool = mlxsw_sp2_mask_ethtool_400gaui_8,
1762 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN,
1763 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_8X,
1764 .speed = SPEED_400000,
1765 .width = 8,
1766 },
1767 };
1768
1769 #define MLXSW_SP2_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp2_port_link_mode)
1770
1771 static void
mlxsw_sp2_from_ptys_supported_port(struct mlxsw_sp * mlxsw_sp,u32 ptys_eth_proto,struct ethtool_link_ksettings * cmd)1772 mlxsw_sp2_from_ptys_supported_port(struct mlxsw_sp *mlxsw_sp,
1773 u32 ptys_eth_proto,
1774 struct ethtool_link_ksettings *cmd)
1775 {
1776 ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
1777 ethtool_link_ksettings_add_link_mode(cmd, supported, Backplane);
1778 }
1779
1780 static void
mlxsw_sp2_set_bit_ethtool(const struct mlxsw_sp2_port_link_mode * link_mode,unsigned long * mode)1781 mlxsw_sp2_set_bit_ethtool(const struct mlxsw_sp2_port_link_mode *link_mode,
1782 unsigned long *mode)
1783 {
1784 int i;
1785
1786 for (i = 0; i < link_mode->m_ethtool_len; i++)
1787 __set_bit(link_mode->mask_ethtool[i], mode);
1788 }
1789
1790 static void
mlxsw_sp2_from_ptys_link(struct mlxsw_sp * mlxsw_sp,u32 ptys_eth_proto,unsigned long * mode)1791 mlxsw_sp2_from_ptys_link(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto,
1792 unsigned long *mode)
1793 {
1794 int i;
1795
1796 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
1797 if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask)
1798 mlxsw_sp2_set_bit_ethtool(&mlxsw_sp2_port_link_mode[i],
1799 mode);
1800 }
1801 }
1802
1803 static u32
mlxsw_sp2_from_ptys_speed(struct mlxsw_sp * mlxsw_sp,u32 ptys_eth_proto)1804 mlxsw_sp2_from_ptys_speed(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto)
1805 {
1806 int i;
1807
1808 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
1809 if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask)
1810 return mlxsw_sp2_port_link_mode[i].speed;
1811 }
1812
1813 return SPEED_UNKNOWN;
1814 }
1815
1816 static void
mlxsw_sp2_from_ptys_link_mode(struct mlxsw_sp * mlxsw_sp,bool carrier_ok,u32 ptys_eth_proto,struct ethtool_link_ksettings * cmd)1817 mlxsw_sp2_from_ptys_link_mode(struct mlxsw_sp *mlxsw_sp, bool carrier_ok,
1818 u32 ptys_eth_proto,
1819 struct ethtool_link_ksettings *cmd)
1820 {
1821 struct mlxsw_sp2_port_link_mode link;
1822 int i;
1823
1824 cmd->base.speed = SPEED_UNKNOWN;
1825 cmd->base.duplex = DUPLEX_UNKNOWN;
1826 cmd->lanes = 0;
1827
1828 if (!carrier_ok)
1829 return;
1830
1831 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
1832 if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask) {
1833 link = mlxsw_sp2_port_link_mode[i];
1834 ethtool_params_from_link_mode(cmd,
1835 link.mask_ethtool[1]);
1836 }
1837 }
1838 }
1839
mlxsw_sp2_ptys_max_speed(struct mlxsw_sp_port * mlxsw_sp_port,u32 * p_max_speed)1840 static int mlxsw_sp2_ptys_max_speed(struct mlxsw_sp_port *mlxsw_sp_port, u32 *p_max_speed)
1841 {
1842 u32 eth_proto_cap;
1843 u32 max_speed = 0;
1844 int err;
1845 int i;
1846
1847 err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, ð_proto_cap, NULL, NULL, NULL);
1848 if (err)
1849 return err;
1850
1851 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
1852 if ((eth_proto_cap & mlxsw_sp2_port_link_mode[i].mask) &&
1853 mlxsw_sp2_port_link_mode[i].speed > max_speed)
1854 max_speed = mlxsw_sp2_port_link_mode[i].speed;
1855 }
1856
1857 *p_max_speed = max_speed;
1858 return 0;
1859 }
1860
1861 static bool
mlxsw_sp2_test_bit_ethtool(const struct mlxsw_sp2_port_link_mode * link_mode,const unsigned long * mode)1862 mlxsw_sp2_test_bit_ethtool(const struct mlxsw_sp2_port_link_mode *link_mode,
1863 const unsigned long *mode)
1864 {
1865 int cnt = 0;
1866 int i;
1867
1868 for (i = 0; i < link_mode->m_ethtool_len; i++) {
1869 if (test_bit(link_mode->mask_ethtool[i], mode))
1870 cnt++;
1871 }
1872
1873 return cnt == link_mode->m_ethtool_len;
1874 }
1875
1876 static u32
mlxsw_sp2_to_ptys_advert_link(struct mlxsw_sp * mlxsw_sp,const struct ethtool_link_ksettings * cmd)1877 mlxsw_sp2_to_ptys_advert_link(struct mlxsw_sp *mlxsw_sp,
1878 const struct ethtool_link_ksettings *cmd)
1879 {
1880 u32 ptys_proto = 0;
1881 int i;
1882
1883 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
1884 if (mlxsw_sp2_test_bit_ethtool(&mlxsw_sp2_port_link_mode[i],
1885 cmd->link_modes.advertising))
1886 ptys_proto |= mlxsw_sp2_port_link_mode[i].mask;
1887 }
1888 return ptys_proto;
1889 }
1890
mlxsw_sp2_to_ptys_speed_lanes(struct mlxsw_sp * mlxsw_sp,u8 width,const struct ethtool_link_ksettings * cmd)1891 static u32 mlxsw_sp2_to_ptys_speed_lanes(struct mlxsw_sp *mlxsw_sp, u8 width,
1892 const struct ethtool_link_ksettings *cmd)
1893 {
1894 u8 mask_width = mlxsw_sp_port_mask_width_get(width);
1895 struct mlxsw_sp2_port_link_mode link_mode;
1896 u32 ptys_proto = 0;
1897 int i;
1898
1899 if (cmd->lanes > width)
1900 return ptys_proto;
1901
1902 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
1903 if (cmd->base.speed == mlxsw_sp2_port_link_mode[i].speed) {
1904 link_mode = mlxsw_sp2_port_link_mode[i];
1905
1906 if (!cmd->lanes) {
1907 /* If number of lanes was not set by user space,
1908 * choose the link mode that supports the width
1909 * of the port.
1910 */
1911 if (mask_width & link_mode.mask_sup_width)
1912 ptys_proto |= link_mode.mask;
1913 } else if (cmd->lanes == link_mode.width) {
1914 /* Else if the number of lanes was set, choose
1915 * the link mode that its actual width equals to
1916 * it.
1917 */
1918 ptys_proto |= link_mode.mask;
1919 }
1920 }
1921 }
1922 return ptys_proto;
1923 }
1924
1925 static void
mlxsw_sp2_reg_ptys_eth_pack(struct mlxsw_sp * mlxsw_sp,char * payload,u8 local_port,u32 proto_admin,bool autoneg)1926 mlxsw_sp2_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload,
1927 u8 local_port, u32 proto_admin,
1928 bool autoneg)
1929 {
1930 mlxsw_reg_ptys_ext_eth_pack(payload, local_port, proto_admin, autoneg);
1931 }
1932
1933 static void
mlxsw_sp2_reg_ptys_eth_unpack(struct mlxsw_sp * mlxsw_sp,char * payload,u32 * p_eth_proto_cap,u32 * p_eth_proto_admin,u32 * p_eth_proto_oper)1934 mlxsw_sp2_reg_ptys_eth_unpack(struct mlxsw_sp *mlxsw_sp, char *payload,
1935 u32 *p_eth_proto_cap, u32 *p_eth_proto_admin,
1936 u32 *p_eth_proto_oper)
1937 {
1938 mlxsw_reg_ptys_ext_eth_unpack(payload, p_eth_proto_cap,
1939 p_eth_proto_admin, p_eth_proto_oper);
1940 }
1941
mlxsw_sp2_ptys_proto_cap_masked_get(u32 eth_proto_cap)1942 static u32 mlxsw_sp2_ptys_proto_cap_masked_get(u32 eth_proto_cap)
1943 {
1944 u32 ptys_proto_cap_masked = 0;
1945 int i;
1946
1947 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
1948 if (mlxsw_sp2_port_link_mode[i].mask & eth_proto_cap)
1949 ptys_proto_cap_masked |=
1950 mlxsw_sp2_port_link_mode[i].mask;
1951 }
1952
1953 return ptys_proto_cap_masked;
1954 }
1955
1956 const struct mlxsw_sp_port_type_speed_ops mlxsw_sp2_port_type_speed_ops = {
1957 .from_ptys_supported_port = mlxsw_sp2_from_ptys_supported_port,
1958 .from_ptys_link = mlxsw_sp2_from_ptys_link,
1959 .from_ptys_speed = mlxsw_sp2_from_ptys_speed,
1960 .from_ptys_link_mode = mlxsw_sp2_from_ptys_link_mode,
1961 .ptys_max_speed = mlxsw_sp2_ptys_max_speed,
1962 .to_ptys_advert_link = mlxsw_sp2_to_ptys_advert_link,
1963 .to_ptys_speed_lanes = mlxsw_sp2_to_ptys_speed_lanes,
1964 .reg_ptys_eth_pack = mlxsw_sp2_reg_ptys_eth_pack,
1965 .reg_ptys_eth_unpack = mlxsw_sp2_reg_ptys_eth_unpack,
1966 .ptys_proto_cap_masked_get = mlxsw_sp2_ptys_proto_cap_masked_get,
1967 };
1968