0001
0002
0003
0004 #include "reg.h"
0005 #include "core.h"
0006 #include "spectrum.h"
0007 #include "core_env.h"
0008
0009 static const char mlxsw_sp_driver_version[] = "1.0";
0010
0011 static void mlxsw_sp_port_get_drvinfo(struct net_device *dev,
0012 struct ethtool_drvinfo *drvinfo)
0013 {
0014 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
0015 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
0016
0017 strlcpy(drvinfo->driver, mlxsw_sp->bus_info->device_kind,
0018 sizeof(drvinfo->driver));
0019 strlcpy(drvinfo->version, mlxsw_sp_driver_version,
0020 sizeof(drvinfo->version));
0021 snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
0022 "%d.%d.%d",
0023 mlxsw_sp->bus_info->fw_rev.major,
0024 mlxsw_sp->bus_info->fw_rev.minor,
0025 mlxsw_sp->bus_info->fw_rev.subminor);
0026 strlcpy(drvinfo->bus_info, mlxsw_sp->bus_info->device_name,
0027 sizeof(drvinfo->bus_info));
0028 }
0029
0030 struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping {
0031 u32 status_opcode;
0032 enum ethtool_link_ext_state link_ext_state;
0033 u8 link_ext_substate;
0034 };
0035
0036 static const struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping
0037 mlxsw_sp_link_ext_state_opcode_map[] = {
0038 {2, ETHTOOL_LINK_EXT_STATE_AUTONEG,
0039 ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED},
0040 {3, ETHTOOL_LINK_EXT_STATE_AUTONEG,
0041 ETHTOOL_LINK_EXT_SUBSTATE_AN_ACK_NOT_RECEIVED},
0042 {4, ETHTOOL_LINK_EXT_STATE_AUTONEG,
0043 ETHTOOL_LINK_EXT_SUBSTATE_AN_NEXT_PAGE_EXCHANGE_FAILED},
0044 {36, ETHTOOL_LINK_EXT_STATE_AUTONEG,
0045 ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED_FORCE_MODE},
0046 {38, ETHTOOL_LINK_EXT_STATE_AUTONEG,
0047 ETHTOOL_LINK_EXT_SUBSTATE_AN_FEC_MISMATCH_DURING_OVERRIDE},
0048 {39, ETHTOOL_LINK_EXT_STATE_AUTONEG,
0049 ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_HCD},
0050
0051 {5, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
0052 ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_FRAME_LOCK_NOT_ACQUIRED},
0053 {6, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
0054 ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_INHIBIT_TIMEOUT},
0055 {7, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
0056 ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_PARTNER_DID_NOT_SET_RECEIVER_READY},
0057 {8, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE, 0},
0058 {14, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
0059 ETHTOOL_LINK_EXT_SUBSTATE_LT_REMOTE_FAULT},
0060
0061 {9, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
0062 ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_BLOCK_LOCK},
0063 {10, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
0064 ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_AM_LOCK},
0065 {11, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
0066 ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_GET_ALIGN_STATUS},
0067 {12, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
0068 ETHTOOL_LINK_EXT_SUBSTATE_LLM_FC_FEC_IS_NOT_LOCKED},
0069 {13, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
0070 ETHTOOL_LINK_EXT_SUBSTATE_LLM_RS_FEC_IS_NOT_LOCKED},
0071
0072 {15, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY, 0},
0073 {17, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY,
0074 ETHTOOL_LINK_EXT_SUBSTATE_BSI_LARGE_NUMBER_OF_PHYSICAL_ERRORS},
0075 {42, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY,
0076 ETHTOOL_LINK_EXT_SUBSTATE_BSI_UNSUPPORTED_RATE},
0077
0078 {1024, ETHTOOL_LINK_EXT_STATE_NO_CABLE, 0},
0079
0080 {16, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
0081 ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
0082 {20, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
0083 ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
0084 {29, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
0085 ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
0086 {1025, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
0087 ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
0088 {1029, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
0089 ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
0090 {1031, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE, 0},
0091
0092 {1027, ETHTOOL_LINK_EXT_STATE_EEPROM_ISSUE, 0},
0093
0094 {23, ETHTOOL_LINK_EXT_STATE_CALIBRATION_FAILURE, 0},
0095
0096 {1032, ETHTOOL_LINK_EXT_STATE_POWER_BUDGET_EXCEEDED, 0},
0097
0098 {1030, ETHTOOL_LINK_EXT_STATE_OVERHEAT, 0},
0099
0100 {1042, ETHTOOL_LINK_EXT_STATE_MODULE,
0101 ETHTOOL_LINK_EXT_SUBSTATE_MODULE_CMIS_NOT_READY},
0102 };
0103
0104 static void
0105 mlxsw_sp_port_set_link_ext_state(struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping
0106 link_ext_state_mapping,
0107 struct ethtool_link_ext_state_info *link_ext_state_info)
0108 {
0109 switch (link_ext_state_mapping.link_ext_state) {
0110 case ETHTOOL_LINK_EXT_STATE_AUTONEG:
0111 link_ext_state_info->autoneg =
0112 link_ext_state_mapping.link_ext_substate;
0113 break;
0114 case ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE:
0115 link_ext_state_info->link_training =
0116 link_ext_state_mapping.link_ext_substate;
0117 break;
0118 case ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH:
0119 link_ext_state_info->link_logical_mismatch =
0120 link_ext_state_mapping.link_ext_substate;
0121 break;
0122 case ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY:
0123 link_ext_state_info->bad_signal_integrity =
0124 link_ext_state_mapping.link_ext_substate;
0125 break;
0126 case ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE:
0127 link_ext_state_info->cable_issue =
0128 link_ext_state_mapping.link_ext_substate;
0129 break;
0130 case ETHTOOL_LINK_EXT_STATE_MODULE:
0131 link_ext_state_info->module =
0132 link_ext_state_mapping.link_ext_substate;
0133 break;
0134 default:
0135 break;
0136 }
0137
0138 link_ext_state_info->link_ext_state = link_ext_state_mapping.link_ext_state;
0139 }
0140
0141 static int
0142 mlxsw_sp_port_get_link_ext_state(struct net_device *dev,
0143 struct ethtool_link_ext_state_info *link_ext_state_info)
0144 {
0145 struct mlxsw_sp_ethtool_link_ext_state_opcode_mapping link_ext_state_mapping;
0146 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
0147 char pddr_pl[MLXSW_REG_PDDR_LEN];
0148 int opcode, err, i;
0149 u32 status_opcode;
0150
0151 if (netif_carrier_ok(dev))
0152 return -ENODATA;
0153
0154 mlxsw_reg_pddr_pack(pddr_pl, mlxsw_sp_port->local_port,
0155 MLXSW_REG_PDDR_PAGE_SELECT_TROUBLESHOOTING_INFO);
0156
0157 opcode = MLXSW_REG_PDDR_TRBLSH_GROUP_OPCODE_MONITOR;
0158 mlxsw_reg_pddr_trblsh_group_opcode_set(pddr_pl, opcode);
0159
0160 err = mlxsw_reg_query(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pddr),
0161 pddr_pl);
0162 if (err)
0163 return err;
0164
0165 status_opcode = mlxsw_reg_pddr_trblsh_status_opcode_get(pddr_pl);
0166 if (!status_opcode)
0167 return -ENODATA;
0168
0169 for (i = 0; i < ARRAY_SIZE(mlxsw_sp_link_ext_state_opcode_map); i++) {
0170 link_ext_state_mapping = mlxsw_sp_link_ext_state_opcode_map[i];
0171 if (link_ext_state_mapping.status_opcode == status_opcode) {
0172 mlxsw_sp_port_set_link_ext_state(link_ext_state_mapping,
0173 link_ext_state_info);
0174 return 0;
0175 }
0176 }
0177
0178 return -ENODATA;
0179 }
0180
0181 static void mlxsw_sp_port_get_pauseparam(struct net_device *dev,
0182 struct ethtool_pauseparam *pause)
0183 {
0184 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
0185
0186 pause->rx_pause = mlxsw_sp_port->link.rx_pause;
0187 pause->tx_pause = mlxsw_sp_port->link.tx_pause;
0188 }
0189
0190 static int mlxsw_sp_port_pause_set(struct mlxsw_sp_port *mlxsw_sp_port,
0191 struct ethtool_pauseparam *pause)
0192 {
0193 char pfcc_pl[MLXSW_REG_PFCC_LEN];
0194
0195 mlxsw_reg_pfcc_pack(pfcc_pl, mlxsw_sp_port->local_port);
0196 mlxsw_reg_pfcc_pprx_set(pfcc_pl, pause->rx_pause);
0197 mlxsw_reg_pfcc_pptx_set(pfcc_pl, pause->tx_pause);
0198
0199 return mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pfcc),
0200 pfcc_pl);
0201 }
0202
0203
0204
0205
0206 #define MLXSW_SP_PAUSE_DELAY_BYTES 19476
0207
0208 static int mlxsw_sp_port_set_pauseparam(struct net_device *dev,
0209 struct ethtool_pauseparam *pause)
0210 {
0211 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
0212 bool pause_en = pause->tx_pause || pause->rx_pause;
0213 struct mlxsw_sp_hdroom orig_hdroom;
0214 struct mlxsw_sp_hdroom hdroom;
0215 int prio;
0216 int err;
0217
0218 if (mlxsw_sp_port->dcb.pfc && mlxsw_sp_port->dcb.pfc->pfc_en) {
0219 netdev_err(dev, "PFC already enabled on port\n");
0220 return -EINVAL;
0221 }
0222
0223 if (pause->autoneg) {
0224 netdev_err(dev, "PAUSE frames autonegotiation isn't supported\n");
0225 return -EINVAL;
0226 }
0227
0228 orig_hdroom = *mlxsw_sp_port->hdroom;
0229
0230 hdroom = orig_hdroom;
0231 if (pause_en)
0232 hdroom.delay_bytes = MLXSW_SP_PAUSE_DELAY_BYTES;
0233 else
0234 hdroom.delay_bytes = 0;
0235
0236 for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
0237 hdroom.prios.prio[prio].lossy = !pause_en;
0238
0239 mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
0240 mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
0241
0242 err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
0243 if (err) {
0244 netdev_err(dev, "Failed to configure port's headroom\n");
0245 return err;
0246 }
0247
0248 err = mlxsw_sp_port_pause_set(mlxsw_sp_port, pause);
0249 if (err) {
0250 netdev_err(dev, "Failed to set PAUSE parameters\n");
0251 goto err_port_pause_configure;
0252 }
0253
0254 mlxsw_sp_port->link.rx_pause = pause->rx_pause;
0255 mlxsw_sp_port->link.tx_pause = pause->tx_pause;
0256
0257 return 0;
0258
0259 err_port_pause_configure:
0260 mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom);
0261 return err;
0262 }
0263
0264 struct mlxsw_sp_port_hw_stats {
0265 char str[ETH_GSTRING_LEN];
0266 u64 (*getter)(const char *payload);
0267 bool cells_bytes;
0268 };
0269
0270 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_stats[] = {
0271 {
0272 .str = "a_frames_transmitted_ok",
0273 .getter = mlxsw_reg_ppcnt_a_frames_transmitted_ok_get,
0274 },
0275 {
0276 .str = "a_frames_received_ok",
0277 .getter = mlxsw_reg_ppcnt_a_frames_received_ok_get,
0278 },
0279 {
0280 .str = "a_frame_check_sequence_errors",
0281 .getter = mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get,
0282 },
0283 {
0284 .str = "a_alignment_errors",
0285 .getter = mlxsw_reg_ppcnt_a_alignment_errors_get,
0286 },
0287 {
0288 .str = "a_octets_transmitted_ok",
0289 .getter = mlxsw_reg_ppcnt_a_octets_transmitted_ok_get,
0290 },
0291 {
0292 .str = "a_octets_received_ok",
0293 .getter = mlxsw_reg_ppcnt_a_octets_received_ok_get,
0294 },
0295 {
0296 .str = "a_multicast_frames_xmitted_ok",
0297 .getter = mlxsw_reg_ppcnt_a_multicast_frames_xmitted_ok_get,
0298 },
0299 {
0300 .str = "a_broadcast_frames_xmitted_ok",
0301 .getter = mlxsw_reg_ppcnt_a_broadcast_frames_xmitted_ok_get,
0302 },
0303 {
0304 .str = "a_multicast_frames_received_ok",
0305 .getter = mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get,
0306 },
0307 {
0308 .str = "a_broadcast_frames_received_ok",
0309 .getter = mlxsw_reg_ppcnt_a_broadcast_frames_received_ok_get,
0310 },
0311 {
0312 .str = "a_in_range_length_errors",
0313 .getter = mlxsw_reg_ppcnt_a_in_range_length_errors_get,
0314 },
0315 {
0316 .str = "a_out_of_range_length_field",
0317 .getter = mlxsw_reg_ppcnt_a_out_of_range_length_field_get,
0318 },
0319 {
0320 .str = "a_frame_too_long_errors",
0321 .getter = mlxsw_reg_ppcnt_a_frame_too_long_errors_get,
0322 },
0323 {
0324 .str = "a_symbol_error_during_carrier",
0325 .getter = mlxsw_reg_ppcnt_a_symbol_error_during_carrier_get,
0326 },
0327 {
0328 .str = "a_mac_control_frames_transmitted",
0329 .getter = mlxsw_reg_ppcnt_a_mac_control_frames_transmitted_get,
0330 },
0331 {
0332 .str = "a_mac_control_frames_received",
0333 .getter = mlxsw_reg_ppcnt_a_mac_control_frames_received_get,
0334 },
0335 {
0336 .str = "a_unsupported_opcodes_received",
0337 .getter = mlxsw_reg_ppcnt_a_unsupported_opcodes_received_get,
0338 },
0339 {
0340 .str = "a_pause_mac_ctrl_frames_received",
0341 .getter = mlxsw_reg_ppcnt_a_pause_mac_ctrl_frames_received_get,
0342 },
0343 {
0344 .str = "a_pause_mac_ctrl_frames_xmitted",
0345 .getter = mlxsw_reg_ppcnt_a_pause_mac_ctrl_frames_transmitted_get,
0346 },
0347 };
0348
0349 #define MLXSW_SP_PORT_HW_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_stats)
0350
0351 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_rfc_2863_stats[] = {
0352 {
0353 .str = "if_in_discards",
0354 .getter = mlxsw_reg_ppcnt_if_in_discards_get,
0355 },
0356 {
0357 .str = "if_out_discards",
0358 .getter = mlxsw_reg_ppcnt_if_out_discards_get,
0359 },
0360 {
0361 .str = "if_out_errors",
0362 .getter = mlxsw_reg_ppcnt_if_out_errors_get,
0363 },
0364 };
0365
0366 #define MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN \
0367 ARRAY_SIZE(mlxsw_sp_port_hw_rfc_2863_stats)
0368
0369 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_rfc_2819_stats[] = {
0370 {
0371 .str = "ether_stats_undersize_pkts",
0372 .getter = mlxsw_reg_ppcnt_ether_stats_undersize_pkts_get,
0373 },
0374 {
0375 .str = "ether_stats_oversize_pkts",
0376 .getter = mlxsw_reg_ppcnt_ether_stats_oversize_pkts_get,
0377 },
0378 {
0379 .str = "ether_stats_fragments",
0380 .getter = mlxsw_reg_ppcnt_ether_stats_fragments_get,
0381 },
0382 {
0383 .str = "ether_pkts64octets",
0384 .getter = mlxsw_reg_ppcnt_ether_stats_pkts64octets_get,
0385 },
0386 {
0387 .str = "ether_pkts65to127octets",
0388 .getter = mlxsw_reg_ppcnt_ether_stats_pkts65to127octets_get,
0389 },
0390 {
0391 .str = "ether_pkts128to255octets",
0392 .getter = mlxsw_reg_ppcnt_ether_stats_pkts128to255octets_get,
0393 },
0394 {
0395 .str = "ether_pkts256to511octets",
0396 .getter = mlxsw_reg_ppcnt_ether_stats_pkts256to511octets_get,
0397 },
0398 {
0399 .str = "ether_pkts512to1023octets",
0400 .getter = mlxsw_reg_ppcnt_ether_stats_pkts512to1023octets_get,
0401 },
0402 {
0403 .str = "ether_pkts1024to1518octets",
0404 .getter = mlxsw_reg_ppcnt_ether_stats_pkts1024to1518octets_get,
0405 },
0406 {
0407 .str = "ether_pkts1519to2047octets",
0408 .getter = mlxsw_reg_ppcnt_ether_stats_pkts1519to2047octets_get,
0409 },
0410 {
0411 .str = "ether_pkts2048to4095octets",
0412 .getter = mlxsw_reg_ppcnt_ether_stats_pkts2048to4095octets_get,
0413 },
0414 {
0415 .str = "ether_pkts4096to8191octets",
0416 .getter = mlxsw_reg_ppcnt_ether_stats_pkts4096to8191octets_get,
0417 },
0418 {
0419 .str = "ether_pkts8192to10239octets",
0420 .getter = mlxsw_reg_ppcnt_ether_stats_pkts8192to10239octets_get,
0421 },
0422 };
0423
0424 #define MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN \
0425 ARRAY_SIZE(mlxsw_sp_port_hw_rfc_2819_stats)
0426
0427 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_rfc_3635_stats[] = {
0428 {
0429 .str = "dot3stats_fcs_errors",
0430 .getter = mlxsw_reg_ppcnt_dot3stats_fcs_errors_get,
0431 },
0432 {
0433 .str = "dot3stats_symbol_errors",
0434 .getter = mlxsw_reg_ppcnt_dot3stats_symbol_errors_get,
0435 },
0436 {
0437 .str = "dot3control_in_unknown_opcodes",
0438 .getter = mlxsw_reg_ppcnt_dot3control_in_unknown_opcodes_get,
0439 },
0440 {
0441 .str = "dot3in_pause_frames",
0442 .getter = mlxsw_reg_ppcnt_dot3in_pause_frames_get,
0443 },
0444 };
0445
0446 #define MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN \
0447 ARRAY_SIZE(mlxsw_sp_port_hw_rfc_3635_stats)
0448
0449 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_ext_stats[] = {
0450 {
0451 .str = "ecn_marked",
0452 .getter = mlxsw_reg_ppcnt_ecn_marked_get,
0453 },
0454 };
0455
0456 #define MLXSW_SP_PORT_HW_EXT_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_ext_stats)
0457
0458 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_discard_stats[] = {
0459 {
0460 .str = "discard_ingress_general",
0461 .getter = mlxsw_reg_ppcnt_ingress_general_get,
0462 },
0463 {
0464 .str = "discard_ingress_policy_engine",
0465 .getter = mlxsw_reg_ppcnt_ingress_policy_engine_get,
0466 },
0467 {
0468 .str = "discard_ingress_vlan_membership",
0469 .getter = mlxsw_reg_ppcnt_ingress_vlan_membership_get,
0470 },
0471 {
0472 .str = "discard_ingress_tag_frame_type",
0473 .getter = mlxsw_reg_ppcnt_ingress_tag_frame_type_get,
0474 },
0475 {
0476 .str = "discard_egress_vlan_membership",
0477 .getter = mlxsw_reg_ppcnt_egress_vlan_membership_get,
0478 },
0479 {
0480 .str = "discard_loopback_filter",
0481 .getter = mlxsw_reg_ppcnt_loopback_filter_get,
0482 },
0483 {
0484 .str = "discard_egress_general",
0485 .getter = mlxsw_reg_ppcnt_egress_general_get,
0486 },
0487 {
0488 .str = "discard_egress_hoq",
0489 .getter = mlxsw_reg_ppcnt_egress_hoq_get,
0490 },
0491 {
0492 .str = "discard_egress_policy_engine",
0493 .getter = mlxsw_reg_ppcnt_egress_policy_engine_get,
0494 },
0495 {
0496 .str = "discard_ingress_tx_link_down",
0497 .getter = mlxsw_reg_ppcnt_ingress_tx_link_down_get,
0498 },
0499 {
0500 .str = "discard_egress_stp_filter",
0501 .getter = mlxsw_reg_ppcnt_egress_stp_filter_get,
0502 },
0503 {
0504 .str = "discard_egress_sll",
0505 .getter = mlxsw_reg_ppcnt_egress_sll_get,
0506 },
0507 };
0508
0509 #define MLXSW_SP_PORT_HW_DISCARD_STATS_LEN \
0510 ARRAY_SIZE(mlxsw_sp_port_hw_discard_stats)
0511
0512 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_prio_stats[] = {
0513 {
0514 .str = "rx_octets_prio",
0515 .getter = mlxsw_reg_ppcnt_rx_octets_get,
0516 },
0517 {
0518 .str = "rx_frames_prio",
0519 .getter = mlxsw_reg_ppcnt_rx_frames_get,
0520 },
0521 {
0522 .str = "tx_octets_prio",
0523 .getter = mlxsw_reg_ppcnt_tx_octets_get,
0524 },
0525 {
0526 .str = "tx_frames_prio",
0527 .getter = mlxsw_reg_ppcnt_tx_frames_get,
0528 },
0529 {
0530 .str = "rx_pause_prio",
0531 .getter = mlxsw_reg_ppcnt_rx_pause_get,
0532 },
0533 {
0534 .str = "rx_pause_duration_prio",
0535 .getter = mlxsw_reg_ppcnt_rx_pause_duration_get,
0536 },
0537 {
0538 .str = "tx_pause_prio",
0539 .getter = mlxsw_reg_ppcnt_tx_pause_get,
0540 },
0541 {
0542 .str = "tx_pause_duration_prio",
0543 .getter = mlxsw_reg_ppcnt_tx_pause_duration_get,
0544 },
0545 };
0546
0547 #define MLXSW_SP_PORT_HW_PRIO_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_prio_stats)
0548
0549 static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_tc_stats[] = {
0550 {
0551 .str = "tc_transmit_queue_tc",
0552 .getter = mlxsw_reg_ppcnt_tc_transmit_queue_get,
0553 .cells_bytes = true,
0554 },
0555 {
0556 .str = "tc_no_buffer_discard_uc_tc",
0557 .getter = mlxsw_reg_ppcnt_tc_no_buffer_discard_uc_get,
0558 },
0559 };
0560
0561 #define MLXSW_SP_PORT_HW_TC_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_tc_stats)
0562
0563 struct mlxsw_sp_port_stats {
0564 char str[ETH_GSTRING_LEN];
0565 u64 (*getter)(struct mlxsw_sp_port *mlxsw_sp_port);
0566 };
0567
0568 static u64
0569 mlxsw_sp_port_get_transceiver_overheat_stats(struct mlxsw_sp_port *mlxsw_sp_port)
0570 {
0571 struct mlxsw_core *mlxsw_core = mlxsw_sp_port->mlxsw_sp->core;
0572 u8 slot_index = mlxsw_sp_port->mapping.slot_index;
0573 u8 module = mlxsw_sp_port->mapping.module;
0574 u64 stats;
0575 int err;
0576
0577 err = mlxsw_env_module_overheat_counter_get(mlxsw_core, slot_index,
0578 module, &stats);
0579 if (err)
0580 return mlxsw_sp_port->module_overheat_initial_val;
0581
0582 return stats - mlxsw_sp_port->module_overheat_initial_val;
0583 }
0584
0585 static struct mlxsw_sp_port_stats mlxsw_sp_port_transceiver_stats[] = {
0586 {
0587 .str = "transceiver_overheat",
0588 .getter = mlxsw_sp_port_get_transceiver_overheat_stats,
0589 },
0590 };
0591
0592 #define MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_transceiver_stats)
0593
0594 #define MLXSW_SP_PORT_ETHTOOL_STATS_LEN (MLXSW_SP_PORT_HW_STATS_LEN + \
0595 MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN + \
0596 MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN + \
0597 MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN + \
0598 MLXSW_SP_PORT_HW_EXT_STATS_LEN + \
0599 MLXSW_SP_PORT_HW_DISCARD_STATS_LEN + \
0600 (MLXSW_SP_PORT_HW_PRIO_STATS_LEN * \
0601 IEEE_8021QAZ_MAX_TCS) + \
0602 (MLXSW_SP_PORT_HW_TC_STATS_LEN * \
0603 TC_MAX_QUEUE) + \
0604 MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN)
0605
0606 static void mlxsw_sp_port_get_prio_strings(u8 **p, int prio)
0607 {
0608 int i;
0609
0610 for (i = 0; i < MLXSW_SP_PORT_HW_PRIO_STATS_LEN; i++) {
0611 snprintf(*p, ETH_GSTRING_LEN, "%.29s_%.1d",
0612 mlxsw_sp_port_hw_prio_stats[i].str, prio);
0613 *p += ETH_GSTRING_LEN;
0614 }
0615 }
0616
0617 static void mlxsw_sp_port_get_tc_strings(u8 **p, int tc)
0618 {
0619 int i;
0620
0621 for (i = 0; i < MLXSW_SP_PORT_HW_TC_STATS_LEN; i++) {
0622 snprintf(*p, ETH_GSTRING_LEN, "%.29s_%.1d",
0623 mlxsw_sp_port_hw_tc_stats[i].str, tc);
0624 *p += ETH_GSTRING_LEN;
0625 }
0626 }
0627
0628 static void mlxsw_sp_port_get_strings(struct net_device *dev,
0629 u32 stringset, u8 *data)
0630 {
0631 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
0632 u8 *p = data;
0633 int i;
0634
0635 switch (stringset) {
0636 case ETH_SS_STATS:
0637 for (i = 0; i < MLXSW_SP_PORT_HW_STATS_LEN; i++) {
0638 memcpy(p, mlxsw_sp_port_hw_stats[i].str,
0639 ETH_GSTRING_LEN);
0640 p += ETH_GSTRING_LEN;
0641 }
0642
0643 for (i = 0; i < MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN; i++) {
0644 memcpy(p, mlxsw_sp_port_hw_rfc_2863_stats[i].str,
0645 ETH_GSTRING_LEN);
0646 p += ETH_GSTRING_LEN;
0647 }
0648
0649 for (i = 0; i < MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN; i++) {
0650 memcpy(p, mlxsw_sp_port_hw_rfc_2819_stats[i].str,
0651 ETH_GSTRING_LEN);
0652 p += ETH_GSTRING_LEN;
0653 }
0654
0655 for (i = 0; i < MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN; i++) {
0656 memcpy(p, mlxsw_sp_port_hw_rfc_3635_stats[i].str,
0657 ETH_GSTRING_LEN);
0658 p += ETH_GSTRING_LEN;
0659 }
0660
0661 for (i = 0; i < MLXSW_SP_PORT_HW_EXT_STATS_LEN; i++) {
0662 memcpy(p, mlxsw_sp_port_hw_ext_stats[i].str,
0663 ETH_GSTRING_LEN);
0664 p += ETH_GSTRING_LEN;
0665 }
0666
0667 for (i = 0; i < MLXSW_SP_PORT_HW_DISCARD_STATS_LEN; i++) {
0668 memcpy(p, mlxsw_sp_port_hw_discard_stats[i].str,
0669 ETH_GSTRING_LEN);
0670 p += ETH_GSTRING_LEN;
0671 }
0672
0673 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
0674 mlxsw_sp_port_get_prio_strings(&p, i);
0675
0676 for (i = 0; i < TC_MAX_QUEUE; i++)
0677 mlxsw_sp_port_get_tc_strings(&p, i);
0678
0679 mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats_strings(&p);
0680
0681 for (i = 0; i < MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN; i++) {
0682 memcpy(p, mlxsw_sp_port_transceiver_stats[i].str,
0683 ETH_GSTRING_LEN);
0684 p += ETH_GSTRING_LEN;
0685 }
0686 break;
0687 }
0688 }
0689
0690 static int mlxsw_sp_port_set_phys_id(struct net_device *dev,
0691 enum ethtool_phys_id_state state)
0692 {
0693 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
0694 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
0695 char mlcr_pl[MLXSW_REG_MLCR_LEN];
0696 bool active;
0697
0698 switch (state) {
0699 case ETHTOOL_ID_ACTIVE:
0700 active = true;
0701 break;
0702 case ETHTOOL_ID_INACTIVE:
0703 active = false;
0704 break;
0705 default:
0706 return -EOPNOTSUPP;
0707 }
0708
0709 mlxsw_reg_mlcr_pack(mlcr_pl, mlxsw_sp_port->local_port, active);
0710 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mlcr), mlcr_pl);
0711 }
0712
0713 static int
0714 mlxsw_sp_get_hw_stats_by_group(struct mlxsw_sp_port_hw_stats **p_hw_stats,
0715 int *p_len, enum mlxsw_reg_ppcnt_grp grp)
0716 {
0717 switch (grp) {
0718 case MLXSW_REG_PPCNT_IEEE_8023_CNT:
0719 *p_hw_stats = mlxsw_sp_port_hw_stats;
0720 *p_len = MLXSW_SP_PORT_HW_STATS_LEN;
0721 break;
0722 case MLXSW_REG_PPCNT_RFC_2863_CNT:
0723 *p_hw_stats = mlxsw_sp_port_hw_rfc_2863_stats;
0724 *p_len = MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN;
0725 break;
0726 case MLXSW_REG_PPCNT_RFC_2819_CNT:
0727 *p_hw_stats = mlxsw_sp_port_hw_rfc_2819_stats;
0728 *p_len = MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN;
0729 break;
0730 case MLXSW_REG_PPCNT_RFC_3635_CNT:
0731 *p_hw_stats = mlxsw_sp_port_hw_rfc_3635_stats;
0732 *p_len = MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN;
0733 break;
0734 case MLXSW_REG_PPCNT_EXT_CNT:
0735 *p_hw_stats = mlxsw_sp_port_hw_ext_stats;
0736 *p_len = MLXSW_SP_PORT_HW_EXT_STATS_LEN;
0737 break;
0738 case MLXSW_REG_PPCNT_DISCARD_CNT:
0739 *p_hw_stats = mlxsw_sp_port_hw_discard_stats;
0740 *p_len = MLXSW_SP_PORT_HW_DISCARD_STATS_LEN;
0741 break;
0742 case MLXSW_REG_PPCNT_PRIO_CNT:
0743 *p_hw_stats = mlxsw_sp_port_hw_prio_stats;
0744 *p_len = MLXSW_SP_PORT_HW_PRIO_STATS_LEN;
0745 break;
0746 case MLXSW_REG_PPCNT_TC_CNT:
0747 *p_hw_stats = mlxsw_sp_port_hw_tc_stats;
0748 *p_len = MLXSW_SP_PORT_HW_TC_STATS_LEN;
0749 break;
0750 default:
0751 WARN_ON(1);
0752 return -EOPNOTSUPP;
0753 }
0754 return 0;
0755 }
0756
0757 static void __mlxsw_sp_port_get_stats(struct net_device *dev,
0758 enum mlxsw_reg_ppcnt_grp grp, int prio,
0759 u64 *data, int data_index)
0760 {
0761 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
0762 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
0763 struct mlxsw_sp_port_hw_stats *hw_stats;
0764 char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
0765 int i, len;
0766 int err;
0767
0768 err = mlxsw_sp_get_hw_stats_by_group(&hw_stats, &len, grp);
0769 if (err)
0770 return;
0771 mlxsw_sp_port_get_stats_raw(dev, grp, prio, ppcnt_pl);
0772 for (i = 0; i < len; i++) {
0773 data[data_index + i] = hw_stats[i].getter(ppcnt_pl);
0774 if (!hw_stats[i].cells_bytes)
0775 continue;
0776 data[data_index + i] = mlxsw_sp_cells_bytes(mlxsw_sp,
0777 data[data_index + i]);
0778 }
0779 }
0780
0781 static void __mlxsw_sp_port_get_env_stats(struct net_device *dev, u64 *data, int data_index,
0782 struct mlxsw_sp_port_stats *port_stats,
0783 int len)
0784 {
0785 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
0786 int i;
0787
0788 for (i = 0; i < len; i++)
0789 data[data_index + i] = port_stats[i].getter(mlxsw_sp_port);
0790 }
0791
0792 static void mlxsw_sp_port_get_stats(struct net_device *dev,
0793 struct ethtool_stats *stats, u64 *data)
0794 {
0795 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
0796 int i, data_index = 0;
0797
0798
0799 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT, 0,
0800 data, data_index);
0801 data_index = MLXSW_SP_PORT_HW_STATS_LEN;
0802
0803
0804 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_RFC_2863_CNT, 0,
0805 data, data_index);
0806 data_index += MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN;
0807
0808
0809 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_RFC_2819_CNT, 0,
0810 data, data_index);
0811 data_index += MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN;
0812
0813
0814 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_RFC_3635_CNT, 0,
0815 data, data_index);
0816 data_index += MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN;
0817
0818
0819 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_EXT_CNT, 0,
0820 data, data_index);
0821 data_index += MLXSW_SP_PORT_HW_EXT_STATS_LEN;
0822
0823
0824 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_DISCARD_CNT, 0,
0825 data, data_index);
0826 data_index += MLXSW_SP_PORT_HW_DISCARD_STATS_LEN;
0827
0828
0829 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
0830 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_PRIO_CNT, i,
0831 data, data_index);
0832 data_index += MLXSW_SP_PORT_HW_PRIO_STATS_LEN;
0833 }
0834
0835
0836 for (i = 0; i < TC_MAX_QUEUE; i++) {
0837 __mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_TC_CNT, i,
0838 data, data_index);
0839 data_index += MLXSW_SP_PORT_HW_TC_STATS_LEN;
0840 }
0841
0842
0843 mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats(mlxsw_sp_port,
0844 data, data_index);
0845 data_index += mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats_count();
0846
0847
0848 __mlxsw_sp_port_get_env_stats(dev, data, data_index, mlxsw_sp_port_transceiver_stats,
0849 MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN);
0850 data_index += MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN;
0851 }
0852
0853 static int mlxsw_sp_port_get_sset_count(struct net_device *dev, int sset)
0854 {
0855 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
0856
0857 switch (sset) {
0858 case ETH_SS_STATS:
0859 return MLXSW_SP_PORT_ETHTOOL_STATS_LEN +
0860 mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats_count();
0861 default:
0862 return -EOPNOTSUPP;
0863 }
0864 }
0865
0866 static void
0867 mlxsw_sp_port_get_link_supported(struct mlxsw_sp *mlxsw_sp, u32 eth_proto_cap,
0868 struct ethtool_link_ksettings *cmd)
0869 {
0870 const struct mlxsw_sp_port_type_speed_ops *ops;
0871
0872 ops = mlxsw_sp->port_type_speed_ops;
0873
0874 ethtool_link_ksettings_add_link_mode(cmd, supported, Asym_Pause);
0875 ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
0876 ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
0877
0878 ops->from_ptys_supported_port(mlxsw_sp, eth_proto_cap, cmd);
0879 ops->from_ptys_link(mlxsw_sp, eth_proto_cap,
0880 cmd->link_modes.supported);
0881 }
0882
0883 static void
0884 mlxsw_sp_port_get_link_advertise(struct mlxsw_sp *mlxsw_sp,
0885 u32 eth_proto_admin, bool autoneg,
0886 struct ethtool_link_ksettings *cmd)
0887 {
0888 const struct mlxsw_sp_port_type_speed_ops *ops;
0889
0890 ops = mlxsw_sp->port_type_speed_ops;
0891
0892 if (!autoneg)
0893 return;
0894
0895 ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
0896 ops->from_ptys_link(mlxsw_sp, eth_proto_admin,
0897 cmd->link_modes.advertising);
0898 }
0899
0900 static u8
0901 mlxsw_sp_port_connector_port(enum mlxsw_reg_ptys_connector_type connector_type)
0902 {
0903 switch (connector_type) {
0904 case MLXSW_REG_PTYS_CONNECTOR_TYPE_UNKNOWN_OR_NO_CONNECTOR:
0905 return PORT_OTHER;
0906 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_NONE:
0907 return PORT_NONE;
0908 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_TP:
0909 return PORT_TP;
0910 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_AUI:
0911 return PORT_AUI;
0912 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_BNC:
0913 return PORT_BNC;
0914 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_MII:
0915 return PORT_MII;
0916 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_FIBRE:
0917 return PORT_FIBRE;
0918 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_DA:
0919 return PORT_DA;
0920 case MLXSW_REG_PTYS_CONNECTOR_TYPE_PORT_OTHER:
0921 return PORT_OTHER;
0922 default:
0923 WARN_ON_ONCE(1);
0924 return PORT_OTHER;
0925 }
0926 }
0927
0928 static int mlxsw_sp_port_ptys_query(struct mlxsw_sp_port *mlxsw_sp_port,
0929 u32 *p_eth_proto_cap, u32 *p_eth_proto_admin,
0930 u32 *p_eth_proto_oper, u8 *p_connector_type)
0931 {
0932 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
0933 const struct mlxsw_sp_port_type_speed_ops *ops;
0934 char ptys_pl[MLXSW_REG_PTYS_LEN];
0935 int err;
0936
0937 ops = mlxsw_sp->port_type_speed_ops;
0938
0939 ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port, 0, false);
0940 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
0941 if (err)
0942 return err;
0943
0944 ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, p_eth_proto_cap, p_eth_proto_admin,
0945 p_eth_proto_oper);
0946 if (p_connector_type)
0947 *p_connector_type = mlxsw_reg_ptys_connector_type_get(ptys_pl);
0948 return 0;
0949 }
0950
0951 static int mlxsw_sp_port_get_link_ksettings(struct net_device *dev,
0952 struct ethtool_link_ksettings *cmd)
0953 {
0954 u32 eth_proto_cap, eth_proto_admin, eth_proto_oper;
0955 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
0956 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
0957 const struct mlxsw_sp_port_type_speed_ops *ops;
0958 u8 connector_type;
0959 bool autoneg;
0960 int err;
0961
0962 err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, ð_proto_cap, ð_proto_admin,
0963 ð_proto_oper, &connector_type);
0964 if (err)
0965 return err;
0966
0967 ops = mlxsw_sp->port_type_speed_ops;
0968 autoneg = mlxsw_sp_port->link.autoneg;
0969
0970 mlxsw_sp_port_get_link_supported(mlxsw_sp, eth_proto_cap, cmd);
0971
0972 mlxsw_sp_port_get_link_advertise(mlxsw_sp, eth_proto_admin, autoneg, cmd);
0973
0974 cmd->base.autoneg = autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
0975 cmd->base.port = mlxsw_sp_port_connector_port(connector_type);
0976 ops->from_ptys_link_mode(mlxsw_sp, netif_carrier_ok(dev),
0977 eth_proto_oper, cmd);
0978
0979 return 0;
0980 }
0981
0982 static int
0983 mlxsw_sp_port_set_link_ksettings(struct net_device *dev,
0984 const struct ethtool_link_ksettings *cmd)
0985 {
0986 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
0987 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
0988 const struct mlxsw_sp_port_type_speed_ops *ops;
0989 char ptys_pl[MLXSW_REG_PTYS_LEN];
0990 u32 eth_proto_cap, eth_proto_new;
0991 bool autoneg;
0992 int err;
0993
0994 ops = mlxsw_sp->port_type_speed_ops;
0995
0996 ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,
0997 0, false);
0998 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
0999 if (err)
1000 return err;
1001 ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, ð_proto_cap, NULL, NULL);
1002
1003 autoneg = cmd->base.autoneg == AUTONEG_ENABLE;
1004 eth_proto_new = autoneg ?
1005 ops->to_ptys_advert_link(mlxsw_sp, cmd) :
1006 ops->to_ptys_speed_lanes(mlxsw_sp, mlxsw_sp_port->mapping.width,
1007 cmd);
1008
1009 eth_proto_new = eth_proto_new & eth_proto_cap;
1010 if (!eth_proto_new) {
1011 netdev_err(dev, "No supported speed or lanes requested\n");
1012 return -EINVAL;
1013 }
1014
1015 ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,
1016 eth_proto_new, autoneg);
1017 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
1018 if (err)
1019 return err;
1020
1021 mlxsw_sp_port->link.autoneg = autoneg;
1022
1023 if (!netif_running(dev))
1024 return 0;
1025
1026 mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false);
1027 mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true);
1028
1029 return 0;
1030 }
1031
1032 static int mlxsw_sp_get_module_info(struct net_device *netdev,
1033 struct ethtool_modinfo *modinfo)
1034 {
1035 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev);
1036 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1037
1038 return mlxsw_env_get_module_info(netdev, mlxsw_sp->core,
1039 mlxsw_sp_port->mapping.slot_index,
1040 mlxsw_sp_port->mapping.module,
1041 modinfo);
1042 }
1043
1044 static int mlxsw_sp_get_module_eeprom(struct net_device *netdev,
1045 struct ethtool_eeprom *ee, u8 *data)
1046 {
1047 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev);
1048 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1049 u8 slot_index = mlxsw_sp_port->mapping.slot_index;
1050 u8 module = mlxsw_sp_port->mapping.module;
1051
1052 return mlxsw_env_get_module_eeprom(netdev, mlxsw_sp->core, slot_index,
1053 module, ee, data);
1054 }
1055
1056 static int
1057 mlxsw_sp_get_module_eeprom_by_page(struct net_device *dev,
1058 const struct ethtool_module_eeprom *page,
1059 struct netlink_ext_ack *extack)
1060 {
1061 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1062 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1063 u8 slot_index = mlxsw_sp_port->mapping.slot_index;
1064 u8 module = mlxsw_sp_port->mapping.module;
1065
1066 return mlxsw_env_get_module_eeprom_by_page(mlxsw_sp->core, slot_index,
1067 module, page, extack);
1068 }
1069
1070 static int
1071 mlxsw_sp_get_ts_info(struct net_device *netdev, struct ethtool_ts_info *info)
1072 {
1073 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev);
1074 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1075
1076 return mlxsw_sp->ptp_ops->get_ts_info(mlxsw_sp, info);
1077 }
1078
1079 static void
1080 mlxsw_sp_get_eth_phy_stats(struct net_device *dev,
1081 struct ethtool_eth_phy_stats *phy_stats)
1082 {
1083 char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
1084
1085 if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,
1086 0, ppcnt_pl))
1087 return;
1088
1089 phy_stats->SymbolErrorDuringCarrier =
1090 mlxsw_reg_ppcnt_a_symbol_error_during_carrier_get(ppcnt_pl);
1091 }
1092
1093 static void
1094 mlxsw_sp_get_eth_mac_stats(struct net_device *dev,
1095 struct ethtool_eth_mac_stats *mac_stats)
1096 {
1097 char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
1098
1099 if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,
1100 0, ppcnt_pl))
1101 return;
1102
1103 mac_stats->FramesTransmittedOK =
1104 mlxsw_reg_ppcnt_a_frames_transmitted_ok_get(ppcnt_pl);
1105 mac_stats->FramesReceivedOK =
1106 mlxsw_reg_ppcnt_a_frames_received_ok_get(ppcnt_pl);
1107 mac_stats->FrameCheckSequenceErrors =
1108 mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get(ppcnt_pl);
1109 mac_stats->AlignmentErrors =
1110 mlxsw_reg_ppcnt_a_alignment_errors_get(ppcnt_pl);
1111 mac_stats->OctetsTransmittedOK =
1112 mlxsw_reg_ppcnt_a_octets_transmitted_ok_get(ppcnt_pl);
1113 mac_stats->OctetsReceivedOK =
1114 mlxsw_reg_ppcnt_a_octets_received_ok_get(ppcnt_pl);
1115 mac_stats->MulticastFramesXmittedOK =
1116 mlxsw_reg_ppcnt_a_multicast_frames_xmitted_ok_get(ppcnt_pl);
1117 mac_stats->BroadcastFramesXmittedOK =
1118 mlxsw_reg_ppcnt_a_broadcast_frames_xmitted_ok_get(ppcnt_pl);
1119 mac_stats->MulticastFramesReceivedOK =
1120 mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get(ppcnt_pl);
1121 mac_stats->BroadcastFramesReceivedOK =
1122 mlxsw_reg_ppcnt_a_broadcast_frames_received_ok_get(ppcnt_pl);
1123 mac_stats->InRangeLengthErrors =
1124 mlxsw_reg_ppcnt_a_in_range_length_errors_get(ppcnt_pl);
1125 mac_stats->OutOfRangeLengthField =
1126 mlxsw_reg_ppcnt_a_out_of_range_length_field_get(ppcnt_pl);
1127 mac_stats->FrameTooLongErrors =
1128 mlxsw_reg_ppcnt_a_frame_too_long_errors_get(ppcnt_pl);
1129 }
1130
1131 static void
1132 mlxsw_sp_get_eth_ctrl_stats(struct net_device *dev,
1133 struct ethtool_eth_ctrl_stats *ctrl_stats)
1134 {
1135 char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
1136
1137 if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,
1138 0, ppcnt_pl))
1139 return;
1140
1141 ctrl_stats->MACControlFramesTransmitted =
1142 mlxsw_reg_ppcnt_a_mac_control_frames_transmitted_get(ppcnt_pl);
1143 ctrl_stats->MACControlFramesReceived =
1144 mlxsw_reg_ppcnt_a_mac_control_frames_received_get(ppcnt_pl);
1145 ctrl_stats->UnsupportedOpcodesReceived =
1146 mlxsw_reg_ppcnt_a_unsupported_opcodes_received_get(ppcnt_pl);
1147 }
1148
1149 static const struct ethtool_rmon_hist_range mlxsw_rmon_ranges[] = {
1150 { 0, 64 },
1151 { 65, 127 },
1152 { 128, 255 },
1153 { 256, 511 },
1154 { 512, 1023 },
1155 { 1024, 1518 },
1156 { 1519, 2047 },
1157 { 2048, 4095 },
1158 { 4096, 8191 },
1159 { 8192, 10239 },
1160 {}
1161 };
1162
1163 static void
1164 mlxsw_sp_get_rmon_stats(struct net_device *dev,
1165 struct ethtool_rmon_stats *rmon,
1166 const struct ethtool_rmon_hist_range **ranges)
1167 {
1168 char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
1169
1170 if (mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_RFC_2819_CNT,
1171 0, ppcnt_pl))
1172 return;
1173
1174 rmon->undersize_pkts =
1175 mlxsw_reg_ppcnt_ether_stats_undersize_pkts_get(ppcnt_pl);
1176 rmon->oversize_pkts =
1177 mlxsw_reg_ppcnt_ether_stats_oversize_pkts_get(ppcnt_pl);
1178 rmon->fragments =
1179 mlxsw_reg_ppcnt_ether_stats_fragments_get(ppcnt_pl);
1180
1181 rmon->hist[0] = mlxsw_reg_ppcnt_ether_stats_pkts64octets_get(ppcnt_pl);
1182 rmon->hist[1] =
1183 mlxsw_reg_ppcnt_ether_stats_pkts65to127octets_get(ppcnt_pl);
1184 rmon->hist[2] =
1185 mlxsw_reg_ppcnt_ether_stats_pkts128to255octets_get(ppcnt_pl);
1186 rmon->hist[3] =
1187 mlxsw_reg_ppcnt_ether_stats_pkts256to511octets_get(ppcnt_pl);
1188 rmon->hist[4] =
1189 mlxsw_reg_ppcnt_ether_stats_pkts512to1023octets_get(ppcnt_pl);
1190 rmon->hist[5] =
1191 mlxsw_reg_ppcnt_ether_stats_pkts1024to1518octets_get(ppcnt_pl);
1192 rmon->hist[6] =
1193 mlxsw_reg_ppcnt_ether_stats_pkts1519to2047octets_get(ppcnt_pl);
1194 rmon->hist[7] =
1195 mlxsw_reg_ppcnt_ether_stats_pkts2048to4095octets_get(ppcnt_pl);
1196 rmon->hist[8] =
1197 mlxsw_reg_ppcnt_ether_stats_pkts4096to8191octets_get(ppcnt_pl);
1198 rmon->hist[9] =
1199 mlxsw_reg_ppcnt_ether_stats_pkts8192to10239octets_get(ppcnt_pl);
1200
1201 *ranges = mlxsw_rmon_ranges;
1202 }
1203
1204 static int mlxsw_sp_reset(struct net_device *dev, u32 *flags)
1205 {
1206 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1207 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1208 u8 slot_index = mlxsw_sp_port->mapping.slot_index;
1209 u8 module = mlxsw_sp_port->mapping.module;
1210
1211 return mlxsw_env_reset_module(dev, mlxsw_sp->core, slot_index,
1212 module, flags);
1213 }
1214
1215 static int
1216 mlxsw_sp_get_module_power_mode(struct net_device *dev,
1217 struct ethtool_module_power_mode_params *params,
1218 struct netlink_ext_ack *extack)
1219 {
1220 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1221 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1222 u8 slot_index = mlxsw_sp_port->mapping.slot_index;
1223 u8 module = mlxsw_sp_port->mapping.module;
1224
1225 return mlxsw_env_get_module_power_mode(mlxsw_sp->core, slot_index,
1226 module, params, extack);
1227 }
1228
1229 static int
1230 mlxsw_sp_set_module_power_mode(struct net_device *dev,
1231 const struct ethtool_module_power_mode_params *params,
1232 struct netlink_ext_ack *extack)
1233 {
1234 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1235 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1236 u8 slot_index = mlxsw_sp_port->mapping.slot_index;
1237 u8 module = mlxsw_sp_port->mapping.module;
1238
1239 return mlxsw_env_set_module_power_mode(mlxsw_sp->core, slot_index,
1240 module, params->policy, extack);
1241 }
1242
1243 const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
1244 .cap_link_lanes_supported = true,
1245 .get_drvinfo = mlxsw_sp_port_get_drvinfo,
1246 .get_link = ethtool_op_get_link,
1247 .get_link_ext_state = mlxsw_sp_port_get_link_ext_state,
1248 .get_pauseparam = mlxsw_sp_port_get_pauseparam,
1249 .set_pauseparam = mlxsw_sp_port_set_pauseparam,
1250 .get_strings = mlxsw_sp_port_get_strings,
1251 .set_phys_id = mlxsw_sp_port_set_phys_id,
1252 .get_ethtool_stats = mlxsw_sp_port_get_stats,
1253 .get_sset_count = mlxsw_sp_port_get_sset_count,
1254 .get_link_ksettings = mlxsw_sp_port_get_link_ksettings,
1255 .set_link_ksettings = mlxsw_sp_port_set_link_ksettings,
1256 .get_module_info = mlxsw_sp_get_module_info,
1257 .get_module_eeprom = mlxsw_sp_get_module_eeprom,
1258 .get_module_eeprom_by_page = mlxsw_sp_get_module_eeprom_by_page,
1259 .get_ts_info = mlxsw_sp_get_ts_info,
1260 .get_eth_phy_stats = mlxsw_sp_get_eth_phy_stats,
1261 .get_eth_mac_stats = mlxsw_sp_get_eth_mac_stats,
1262 .get_eth_ctrl_stats = mlxsw_sp_get_eth_ctrl_stats,
1263 .get_rmon_stats = mlxsw_sp_get_rmon_stats,
1264 .reset = mlxsw_sp_reset,
1265 .get_module_power_mode = mlxsw_sp_get_module_power_mode,
1266 .set_module_power_mode = mlxsw_sp_set_module_power_mode,
1267 };
1268
1269 struct mlxsw_sp1_port_link_mode {
1270 enum ethtool_link_mode_bit_indices mask_ethtool;
1271 u32 mask;
1272 u32 speed;
1273 };
1274
1275 static const struct mlxsw_sp1_port_link_mode mlxsw_sp1_port_link_mode[] = {
1276 {
1277 .mask = MLXSW_REG_PTYS_ETH_SPEED_100BASE_T,
1278 .mask_ethtool = ETHTOOL_LINK_MODE_100baseT_Full_BIT,
1279 .speed = SPEED_100,
1280 },
1281 {
1282 .mask = MLXSW_REG_PTYS_ETH_SPEED_SGMII |
1283 MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX,
1284 .mask_ethtool = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
1285 .speed = SPEED_1000,
1286 },
1287 {
1288 .mask = MLXSW_REG_PTYS_ETH_SPEED_1000BASE_T,
1289 .mask_ethtool = ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
1290 .speed = SPEED_1000,
1291 },
1292 {
1293 .mask = MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CX4 |
1294 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4,
1295 .mask_ethtool = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
1296 .speed = SPEED_10000,
1297 },
1298 {
1299 .mask = MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR |
1300 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR |
1301 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR |
1302 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_ER_LR,
1303 .mask_ethtool = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
1304 .speed = SPEED_10000,
1305 },
1306 {
1307 .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4,
1308 .mask_ethtool = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
1309 .speed = SPEED_40000,
1310 },
1311 {
1312 .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4,
1313 .mask_ethtool = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
1314 .speed = SPEED_40000,
1315 },
1316 {
1317 .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4,
1318 .mask_ethtool = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
1319 .speed = SPEED_40000,
1320 },
1321 {
1322 .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_LR4_ER4,
1323 .mask_ethtool = ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
1324 .speed = SPEED_40000,
1325 },
1326 {
1327 .mask = MLXSW_REG_PTYS_ETH_SPEED_25GBASE_CR,
1328 .mask_ethtool = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
1329 .speed = SPEED_25000,
1330 },
1331 {
1332 .mask = MLXSW_REG_PTYS_ETH_SPEED_25GBASE_KR,
1333 .mask_ethtool = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
1334 .speed = SPEED_25000,
1335 },
1336 {
1337 .mask = MLXSW_REG_PTYS_ETH_SPEED_25GBASE_SR,
1338 .mask_ethtool = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
1339 .speed = SPEED_25000,
1340 },
1341 {
1342 .mask = MLXSW_REG_PTYS_ETH_SPEED_50GBASE_CR2,
1343 .mask_ethtool = ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
1344 .speed = SPEED_50000,
1345 },
1346 {
1347 .mask = MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR2,
1348 .mask_ethtool = ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
1349 .speed = SPEED_50000,
1350 },
1351 {
1352 .mask = MLXSW_REG_PTYS_ETH_SPEED_50GBASE_SR2,
1353 .mask_ethtool = ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
1354 .speed = SPEED_50000,
1355 },
1356 {
1357 .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4,
1358 .mask_ethtool = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
1359 .speed = SPEED_100000,
1360 },
1361 {
1362 .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4,
1363 .mask_ethtool = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
1364 .speed = SPEED_100000,
1365 },
1366 {
1367 .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4,
1368 .mask_ethtool = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
1369 .speed = SPEED_100000,
1370 },
1371 {
1372 .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_LR4_ER4,
1373 .mask_ethtool = ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
1374 .speed = SPEED_100000,
1375 },
1376 };
1377
1378 #define MLXSW_SP1_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp1_port_link_mode)
1379
1380 static void
1381 mlxsw_sp1_from_ptys_supported_port(struct mlxsw_sp *mlxsw_sp,
1382 u32 ptys_eth_proto,
1383 struct ethtool_link_ksettings *cmd)
1384 {
1385 if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR |
1386 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR |
1387 MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4 |
1388 MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4 |
1389 MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 |
1390 MLXSW_REG_PTYS_ETH_SPEED_SGMII))
1391 ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
1392
1393 if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR |
1394 MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4 |
1395 MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4 |
1396 MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 |
1397 MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX))
1398 ethtool_link_ksettings_add_link_mode(cmd, supported, Backplane);
1399 }
1400
1401 static void
1402 mlxsw_sp1_from_ptys_link(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto,
1403 unsigned long *mode)
1404 {
1405 int i;
1406
1407 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
1408 if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask)
1409 __set_bit(mlxsw_sp1_port_link_mode[i].mask_ethtool,
1410 mode);
1411 }
1412 }
1413
1414 static u32
1415 mlxsw_sp1_from_ptys_speed(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto)
1416 {
1417 int i;
1418
1419 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
1420 if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask)
1421 return mlxsw_sp1_port_link_mode[i].speed;
1422 }
1423
1424 return SPEED_UNKNOWN;
1425 }
1426
1427 static void
1428 mlxsw_sp1_from_ptys_link_mode(struct mlxsw_sp *mlxsw_sp, bool carrier_ok,
1429 u32 ptys_eth_proto,
1430 struct ethtool_link_ksettings *cmd)
1431 {
1432 struct mlxsw_sp1_port_link_mode link;
1433 int i;
1434
1435 cmd->base.speed = SPEED_UNKNOWN;
1436 cmd->base.duplex = DUPLEX_UNKNOWN;
1437 cmd->lanes = 0;
1438
1439 if (!carrier_ok)
1440 return;
1441
1442 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
1443 if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask) {
1444 link = mlxsw_sp1_port_link_mode[i];
1445 ethtool_params_from_link_mode(cmd,
1446 link.mask_ethtool);
1447 }
1448 }
1449 }
1450
1451 static int mlxsw_sp1_ptys_max_speed(struct mlxsw_sp_port *mlxsw_sp_port, u32 *p_max_speed)
1452 {
1453 u32 eth_proto_cap;
1454 u32 max_speed = 0;
1455 int err;
1456 int i;
1457
1458 err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, ð_proto_cap, NULL, NULL, NULL);
1459 if (err)
1460 return err;
1461
1462 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
1463 if ((eth_proto_cap & mlxsw_sp1_port_link_mode[i].mask) &&
1464 mlxsw_sp1_port_link_mode[i].speed > max_speed)
1465 max_speed = mlxsw_sp1_port_link_mode[i].speed;
1466 }
1467
1468 *p_max_speed = max_speed;
1469 return 0;
1470 }
1471
1472 static u32
1473 mlxsw_sp1_to_ptys_advert_link(struct mlxsw_sp *mlxsw_sp,
1474 const struct ethtool_link_ksettings *cmd)
1475 {
1476 u32 ptys_proto = 0;
1477 int i;
1478
1479 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
1480 if (test_bit(mlxsw_sp1_port_link_mode[i].mask_ethtool,
1481 cmd->link_modes.advertising))
1482 ptys_proto |= mlxsw_sp1_port_link_mode[i].mask;
1483 }
1484 return ptys_proto;
1485 }
1486
1487 static u32 mlxsw_sp1_to_ptys_speed_lanes(struct mlxsw_sp *mlxsw_sp, u8 width,
1488 const struct ethtool_link_ksettings *cmd)
1489 {
1490 u32 ptys_proto = 0;
1491 int i;
1492
1493 if (cmd->lanes > width)
1494 return ptys_proto;
1495
1496 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
1497 if (cmd->base.speed == mlxsw_sp1_port_link_mode[i].speed)
1498 ptys_proto |= mlxsw_sp1_port_link_mode[i].mask;
1499 }
1500 return ptys_proto;
1501 }
1502
1503 static void
1504 mlxsw_sp1_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload,
1505 u16 local_port, u32 proto_admin, bool autoneg)
1506 {
1507 mlxsw_reg_ptys_eth_pack(payload, local_port, proto_admin, autoneg);
1508 }
1509
1510 static void
1511 mlxsw_sp1_reg_ptys_eth_unpack(struct mlxsw_sp *mlxsw_sp, char *payload,
1512 u32 *p_eth_proto_cap, u32 *p_eth_proto_admin,
1513 u32 *p_eth_proto_oper)
1514 {
1515 mlxsw_reg_ptys_eth_unpack(payload, p_eth_proto_cap, p_eth_proto_admin,
1516 p_eth_proto_oper);
1517 }
1518
1519 static u32 mlxsw_sp1_ptys_proto_cap_masked_get(u32 eth_proto_cap)
1520 {
1521 u32 ptys_proto_cap_masked = 0;
1522 int i;
1523
1524 for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
1525 if (mlxsw_sp1_port_link_mode[i].mask & eth_proto_cap)
1526 ptys_proto_cap_masked |=
1527 mlxsw_sp1_port_link_mode[i].mask;
1528 }
1529
1530 return ptys_proto_cap_masked;
1531 }
1532
1533 const struct mlxsw_sp_port_type_speed_ops mlxsw_sp1_port_type_speed_ops = {
1534 .from_ptys_supported_port = mlxsw_sp1_from_ptys_supported_port,
1535 .from_ptys_link = mlxsw_sp1_from_ptys_link,
1536 .from_ptys_speed = mlxsw_sp1_from_ptys_speed,
1537 .from_ptys_link_mode = mlxsw_sp1_from_ptys_link_mode,
1538 .ptys_max_speed = mlxsw_sp1_ptys_max_speed,
1539 .to_ptys_advert_link = mlxsw_sp1_to_ptys_advert_link,
1540 .to_ptys_speed_lanes = mlxsw_sp1_to_ptys_speed_lanes,
1541 .reg_ptys_eth_pack = mlxsw_sp1_reg_ptys_eth_pack,
1542 .reg_ptys_eth_unpack = mlxsw_sp1_reg_ptys_eth_unpack,
1543 .ptys_proto_cap_masked_get = mlxsw_sp1_ptys_proto_cap_masked_get,
1544 };
1545
1546 static const enum ethtool_link_mode_bit_indices
1547 mlxsw_sp2_mask_ethtool_sgmii_100m[] = {
1548 ETHTOOL_LINK_MODE_100baseT_Full_BIT,
1549 };
1550
1551 #define MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN \
1552 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_sgmii_100m)
1553
1554 static const enum ethtool_link_mode_bit_indices
1555 mlxsw_sp2_mask_ethtool_1000base_x_sgmii[] = {
1556 ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
1557 ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
1558 };
1559
1560 #define MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN \
1561 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_1000base_x_sgmii)
1562
1563 static const enum ethtool_link_mode_bit_indices
1564 mlxsw_sp2_mask_ethtool_5gbase_r[] = {
1565 ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
1566 };
1567
1568 #define MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN \
1569 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_5gbase_r)
1570
1571 static const enum ethtool_link_mode_bit_indices
1572 mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g[] = {
1573 ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
1574 ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
1575 ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
1576 ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
1577 ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
1578 ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
1579 ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
1580 };
1581
1582 #define MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN \
1583 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g)
1584
1585 static const enum ethtool_link_mode_bit_indices
1586 mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g[] = {
1587 ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
1588 ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
1589 ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
1590 ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
1591 };
1592
1593 #define MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN \
1594 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g)
1595
1596 static const enum ethtool_link_mode_bit_indices
1597 mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr[] = {
1598 ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
1599 ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
1600 ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
1601 };
1602
1603 #define MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_LEN \
1604 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr)
1605
1606 static const enum ethtool_link_mode_bit_indices
1607 mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2[] = {
1608 ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
1609 ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
1610 ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
1611 };
1612
1613 #define MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN \
1614 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2)
1615
1616 static const enum ethtool_link_mode_bit_indices
1617 mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr[] = {
1618 ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
1619 ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
1620 ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
1621 ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
1622 ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
1623 };
1624
1625 #define MLXSW_SP2_MASK_ETHTOOL_50GAUI_1_LAUI_1_50GBASE_CR_KR_LEN \
1626 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr)
1627
1628 static const enum ethtool_link_mode_bit_indices
1629 mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4[] = {
1630 ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
1631 ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
1632 ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
1633 ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
1634 };
1635
1636 #define MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN \
1637 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4)
1638
1639 static const enum ethtool_link_mode_bit_indices
1640 mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2[] = {
1641 ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
1642 ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
1643 ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
1644 ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
1645 ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
1646 };
1647
1648 #define MLXSW_SP2_MASK_ETHTOOL_100GAUI_2_100GBASE_CR2_KR2_LEN \
1649 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2)
1650
1651 static const enum ethtool_link_mode_bit_indices
1652 mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4[] = {
1653 ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT,
1654 ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT,
1655 ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT,
1656 ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT,
1657 ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT,
1658 };
1659
1660 #define MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN \
1661 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4)
1662
1663 static const enum ethtool_link_mode_bit_indices
1664 mlxsw_sp2_mask_ethtool_400gaui_8[] = {
1665 ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT,
1666 ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT,
1667 ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT,
1668 ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT,
1669 ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT,
1670 };
1671
1672 #define MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN \
1673 ARRAY_SIZE(mlxsw_sp2_mask_ethtool_400gaui_8)
1674
1675 #define MLXSW_SP_PORT_MASK_WIDTH_1X BIT(0)
1676 #define MLXSW_SP_PORT_MASK_WIDTH_2X BIT(1)
1677 #define MLXSW_SP_PORT_MASK_WIDTH_4X BIT(2)
1678 #define MLXSW_SP_PORT_MASK_WIDTH_8X BIT(3)
1679
1680 static u8 mlxsw_sp_port_mask_width_get(u8 width)
1681 {
1682 switch (width) {
1683 case 1:
1684 return MLXSW_SP_PORT_MASK_WIDTH_1X;
1685 case 2:
1686 return MLXSW_SP_PORT_MASK_WIDTH_2X;
1687 case 4:
1688 return MLXSW_SP_PORT_MASK_WIDTH_4X;
1689 case 8:
1690 return MLXSW_SP_PORT_MASK_WIDTH_8X;
1691 default:
1692 WARN_ON_ONCE(1);
1693 return 0;
1694 }
1695 }
1696
1697 struct mlxsw_sp2_port_link_mode {
1698 const enum ethtool_link_mode_bit_indices *mask_ethtool;
1699 int m_ethtool_len;
1700 u32 mask;
1701 u32 speed;
1702 u32 width;
1703 u8 mask_sup_width;
1704 };
1705
1706 static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = {
1707 {
1708 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_SGMII_100M,
1709 .mask_ethtool = mlxsw_sp2_mask_ethtool_sgmii_100m,
1710 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN,
1711 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X |
1712 MLXSW_SP_PORT_MASK_WIDTH_2X |
1713 MLXSW_SP_PORT_MASK_WIDTH_4X |
1714 MLXSW_SP_PORT_MASK_WIDTH_8X,
1715 .speed = SPEED_100,
1716 .width = 1,
1717 },
1718 {
1719 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_1000BASE_X_SGMII,
1720 .mask_ethtool = mlxsw_sp2_mask_ethtool_1000base_x_sgmii,
1721 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN,
1722 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X |
1723 MLXSW_SP_PORT_MASK_WIDTH_2X |
1724 MLXSW_SP_PORT_MASK_WIDTH_4X |
1725 MLXSW_SP_PORT_MASK_WIDTH_8X,
1726 .speed = SPEED_1000,
1727 .width = 1,
1728 },
1729 {
1730 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_5GBASE_R,
1731 .mask_ethtool = mlxsw_sp2_mask_ethtool_5gbase_r,
1732 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN,
1733 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X |
1734 MLXSW_SP_PORT_MASK_WIDTH_2X |
1735 MLXSW_SP_PORT_MASK_WIDTH_4X |
1736 MLXSW_SP_PORT_MASK_WIDTH_8X,
1737 .speed = SPEED_5000,
1738 .width = 1,
1739 },
1740 {
1741 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_XFI_XAUI_1_10G,
1742 .mask_ethtool = mlxsw_sp2_mask_ethtool_xfi_xaui_1_10g,
1743 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN,
1744 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X |
1745 MLXSW_SP_PORT_MASK_WIDTH_2X |
1746 MLXSW_SP_PORT_MASK_WIDTH_4X |
1747 MLXSW_SP_PORT_MASK_WIDTH_8X,
1748 .speed = SPEED_10000,
1749 .width = 1,
1750 },
1751 {
1752 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_XLAUI_4_XLPPI_4_40G,
1753 .mask_ethtool = mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g,
1754 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN,
1755 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_4X |
1756 MLXSW_SP_PORT_MASK_WIDTH_8X,
1757 .speed = SPEED_40000,
1758 .width = 4,
1759 },
1760 {
1761 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_25GAUI_1_25GBASE_CR_KR,
1762 .mask_ethtool = mlxsw_sp2_mask_ethtool_25gaui_1_25gbase_cr_kr,
1763 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_LEN,
1764 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X |
1765 MLXSW_SP_PORT_MASK_WIDTH_2X |
1766 MLXSW_SP_PORT_MASK_WIDTH_4X |
1767 MLXSW_SP_PORT_MASK_WIDTH_8X,
1768 .speed = SPEED_25000,
1769 .width = 1,
1770 },
1771 {
1772 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_2_LAUI_2_50GBASE_CR2_KR2,
1773 .mask_ethtool = mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2,
1774 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN,
1775 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_2X |
1776 MLXSW_SP_PORT_MASK_WIDTH_4X |
1777 MLXSW_SP_PORT_MASK_WIDTH_8X,
1778 .speed = SPEED_50000,
1779 .width = 2,
1780 },
1781 {
1782 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_1_LAUI_1_50GBASE_CR_KR,
1783 .mask_ethtool = mlxsw_sp2_mask_ethtool_50gaui_1_laui_1_50gbase_cr_kr,
1784 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_50GAUI_1_LAUI_1_50GBASE_CR_KR_LEN,
1785 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_1X,
1786 .speed = SPEED_50000,
1787 .width = 1,
1788 },
1789 {
1790 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_CAUI_4_100GBASE_CR4_KR4,
1791 .mask_ethtool = mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4,
1792 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN,
1793 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_4X |
1794 MLXSW_SP_PORT_MASK_WIDTH_8X,
1795 .speed = SPEED_100000,
1796 .width = 4,
1797 },
1798 {
1799 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_100GAUI_2_100GBASE_CR2_KR2,
1800 .mask_ethtool = mlxsw_sp2_mask_ethtool_100gaui_2_100gbase_cr2_kr2,
1801 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_100GAUI_2_100GBASE_CR2_KR2_LEN,
1802 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_2X,
1803 .speed = SPEED_100000,
1804 .width = 2,
1805 },
1806 {
1807 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_200GAUI_4_200GBASE_CR4_KR4,
1808 .mask_ethtool = mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4,
1809 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN,
1810 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_4X |
1811 MLXSW_SP_PORT_MASK_WIDTH_8X,
1812 .speed = SPEED_200000,
1813 .width = 4,
1814 },
1815 {
1816 .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_400GAUI_8,
1817 .mask_ethtool = mlxsw_sp2_mask_ethtool_400gaui_8,
1818 .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN,
1819 .mask_sup_width = MLXSW_SP_PORT_MASK_WIDTH_8X,
1820 .speed = SPEED_400000,
1821 .width = 8,
1822 },
1823 };
1824
1825 #define MLXSW_SP2_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp2_port_link_mode)
1826
1827 static void
1828 mlxsw_sp2_from_ptys_supported_port(struct mlxsw_sp *mlxsw_sp,
1829 u32 ptys_eth_proto,
1830 struct ethtool_link_ksettings *cmd)
1831 {
1832 ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
1833 ethtool_link_ksettings_add_link_mode(cmd, supported, Backplane);
1834 }
1835
1836 static void
1837 mlxsw_sp2_set_bit_ethtool(const struct mlxsw_sp2_port_link_mode *link_mode,
1838 unsigned long *mode)
1839 {
1840 int i;
1841
1842 for (i = 0; i < link_mode->m_ethtool_len; i++)
1843 __set_bit(link_mode->mask_ethtool[i], mode);
1844 }
1845
1846 static void
1847 mlxsw_sp2_from_ptys_link(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto,
1848 unsigned long *mode)
1849 {
1850 int i;
1851
1852 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
1853 if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask)
1854 mlxsw_sp2_set_bit_ethtool(&mlxsw_sp2_port_link_mode[i],
1855 mode);
1856 }
1857 }
1858
1859 static u32
1860 mlxsw_sp2_from_ptys_speed(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto)
1861 {
1862 int i;
1863
1864 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
1865 if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask)
1866 return mlxsw_sp2_port_link_mode[i].speed;
1867 }
1868
1869 return SPEED_UNKNOWN;
1870 }
1871
1872 static void
1873 mlxsw_sp2_from_ptys_link_mode(struct mlxsw_sp *mlxsw_sp, bool carrier_ok,
1874 u32 ptys_eth_proto,
1875 struct ethtool_link_ksettings *cmd)
1876 {
1877 struct mlxsw_sp2_port_link_mode link;
1878 int i;
1879
1880 cmd->base.speed = SPEED_UNKNOWN;
1881 cmd->base.duplex = DUPLEX_UNKNOWN;
1882 cmd->lanes = 0;
1883
1884 if (!carrier_ok)
1885 return;
1886
1887 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
1888 if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask) {
1889 link = mlxsw_sp2_port_link_mode[i];
1890 ethtool_params_from_link_mode(cmd,
1891 link.mask_ethtool[1]);
1892 }
1893 }
1894 }
1895
1896 static int mlxsw_sp2_ptys_max_speed(struct mlxsw_sp_port *mlxsw_sp_port, u32 *p_max_speed)
1897 {
1898 u32 eth_proto_cap;
1899 u32 max_speed = 0;
1900 int err;
1901 int i;
1902
1903 err = mlxsw_sp_port_ptys_query(mlxsw_sp_port, ð_proto_cap, NULL, NULL, NULL);
1904 if (err)
1905 return err;
1906
1907 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
1908 if ((eth_proto_cap & mlxsw_sp2_port_link_mode[i].mask) &&
1909 mlxsw_sp2_port_link_mode[i].speed > max_speed)
1910 max_speed = mlxsw_sp2_port_link_mode[i].speed;
1911 }
1912
1913 *p_max_speed = max_speed;
1914 return 0;
1915 }
1916
1917 static bool
1918 mlxsw_sp2_test_bit_ethtool(const struct mlxsw_sp2_port_link_mode *link_mode,
1919 const unsigned long *mode)
1920 {
1921 int cnt = 0;
1922 int i;
1923
1924 for (i = 0; i < link_mode->m_ethtool_len; i++) {
1925 if (test_bit(link_mode->mask_ethtool[i], mode))
1926 cnt++;
1927 }
1928
1929 return cnt == link_mode->m_ethtool_len;
1930 }
1931
1932 static u32
1933 mlxsw_sp2_to_ptys_advert_link(struct mlxsw_sp *mlxsw_sp,
1934 const struct ethtool_link_ksettings *cmd)
1935 {
1936 u32 ptys_proto = 0;
1937 int i;
1938
1939 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
1940 if (mlxsw_sp2_test_bit_ethtool(&mlxsw_sp2_port_link_mode[i],
1941 cmd->link_modes.advertising))
1942 ptys_proto |= mlxsw_sp2_port_link_mode[i].mask;
1943 }
1944 return ptys_proto;
1945 }
1946
1947 static u32 mlxsw_sp2_to_ptys_speed_lanes(struct mlxsw_sp *mlxsw_sp, u8 width,
1948 const struct ethtool_link_ksettings *cmd)
1949 {
1950 u8 mask_width = mlxsw_sp_port_mask_width_get(width);
1951 struct mlxsw_sp2_port_link_mode link_mode;
1952 u32 ptys_proto = 0;
1953 int i;
1954
1955 if (cmd->lanes > width)
1956 return ptys_proto;
1957
1958 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
1959 if (cmd->base.speed == mlxsw_sp2_port_link_mode[i].speed) {
1960 link_mode = mlxsw_sp2_port_link_mode[i];
1961
1962 if (!cmd->lanes) {
1963
1964
1965
1966
1967 if (mask_width & link_mode.mask_sup_width)
1968 ptys_proto |= link_mode.mask;
1969 } else if (cmd->lanes == link_mode.width) {
1970
1971
1972
1973
1974 ptys_proto |= link_mode.mask;
1975 }
1976 }
1977 }
1978 return ptys_proto;
1979 }
1980
1981 static void
1982 mlxsw_sp2_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload,
1983 u16 local_port, u32 proto_admin,
1984 bool autoneg)
1985 {
1986 mlxsw_reg_ptys_ext_eth_pack(payload, local_port, proto_admin, autoneg);
1987 }
1988
1989 static void
1990 mlxsw_sp2_reg_ptys_eth_unpack(struct mlxsw_sp *mlxsw_sp, char *payload,
1991 u32 *p_eth_proto_cap, u32 *p_eth_proto_admin,
1992 u32 *p_eth_proto_oper)
1993 {
1994 mlxsw_reg_ptys_ext_eth_unpack(payload, p_eth_proto_cap,
1995 p_eth_proto_admin, p_eth_proto_oper);
1996 }
1997
1998 static u32 mlxsw_sp2_ptys_proto_cap_masked_get(u32 eth_proto_cap)
1999 {
2000 u32 ptys_proto_cap_masked = 0;
2001 int i;
2002
2003 for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
2004 if (mlxsw_sp2_port_link_mode[i].mask & eth_proto_cap)
2005 ptys_proto_cap_masked |=
2006 mlxsw_sp2_port_link_mode[i].mask;
2007 }
2008
2009 return ptys_proto_cap_masked;
2010 }
2011
2012 const struct mlxsw_sp_port_type_speed_ops mlxsw_sp2_port_type_speed_ops = {
2013 .from_ptys_supported_port = mlxsw_sp2_from_ptys_supported_port,
2014 .from_ptys_link = mlxsw_sp2_from_ptys_link,
2015 .from_ptys_speed = mlxsw_sp2_from_ptys_speed,
2016 .from_ptys_link_mode = mlxsw_sp2_from_ptys_link_mode,
2017 .ptys_max_speed = mlxsw_sp2_ptys_max_speed,
2018 .to_ptys_advert_link = mlxsw_sp2_to_ptys_advert_link,
2019 .to_ptys_speed_lanes = mlxsw_sp2_to_ptys_speed_lanes,
2020 .reg_ptys_eth_pack = mlxsw_sp2_reg_ptys_eth_pack,
2021 .reg_ptys_eth_unpack = mlxsw_sp2_reg_ptys_eth_unpack,
2022 .ptys_proto_cap_masked_get = mlxsw_sp2_ptys_proto_cap_masked_get,
2023 };