Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /* Copyright (c) 2020 Mellanox Technologies. All rights reserved */
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 /* Maximum delay buffer needed in case of PAUSE frames. Similar to PFC delay, but is
0204  * measured in bytes. Assumes 100m cable and does not take into account MTU.
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     /* IEEE 802.3 Counters */
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     /* RFC 2863 Counters */
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     /* RFC 2819 Counters */
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     /* RFC 3635 Counters */
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     /* Extended Counters */
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     /* Discard Counters */
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     /* Per-Priority Counters */
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     /* Per-TC Counters */
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     /* PTP counters */
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     /* Transceiver counters */
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, &eth_proto_cap, &eth_proto_admin,
0963                        &eth_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, &eth_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, &eth_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, &eth_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                 /* If number of lanes was not set by user space,
1964                  * choose the link mode that supports the width
1965                  * of the port.
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                 /* Else if the number of lanes was set, choose
1971                  * the link mode that its actual width equals to
1972                  * it.
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 };