@@ -587,6 +587,34 @@ int mlxsw_env_set_module_low_power(struct mlxsw_core *mlxsw_core, u8 module,
}
EXPORT_SYMBOL(mlxsw_env_set_module_low_power);
+static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 module)
+{
+ char pmaos_pl[MLXSW_REG_PMAOS_LEN];
+
+ mlxsw_reg_pmaos_pack(pmaos_pl, module);
+ mlxsw_reg_pmaos_rst_set(pmaos_pl, true);
+
+ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
+}
+
+int mlxsw_env_reset_module(struct mlxsw_core *mlxsw_core, u8 module,
+ struct netlink_ext_ack *extack)
+{
+ int err;
+
+ err = mlxsw_env_module_reset(mlxsw_core, module);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to reset module");
+ return err;
+ }
+
+ /* Wait for the module to reach a valid operational state following its
+ * reset.
+ */
+ return mlxsw_env_module_oper_wait(mlxsw_core, module, extack);
+}
+EXPORT_SYMBOL(mlxsw_env_reset_module);
+
static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core,
u8 module,
bool *p_has_temp_sensor)
@@ -32,6 +32,9 @@ int mlxsw_env_set_module_low_power(struct mlxsw_core *mlxsw_core, u8 module,
bool low_power,
struct netlink_ext_ack *extack);
+int mlxsw_env_reset_module(struct mlxsw_core *mlxsw_core, u8 module,
+ struct netlink_ext_ack *extack);
+
int
mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module,
u64 *p_counter);
@@ -146,6 +146,15 @@ static int mlxsw_m_set_module_low_power(struct net_device *netdev,
low_power, extack);
}
+static int mlxsw_m_reset_module(struct net_device *netdev,
+ struct netlink_ext_ack *extack)
+{
+ struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
+ struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
+
+ return mlxsw_env_reset_module(core, mlxsw_m_port->module, extack);
+}
+
static const struct ethtool_ops mlxsw_m_port_ethtool_ops = {
.get_drvinfo = mlxsw_m_module_get_drvinfo,
.get_module_info = mlxsw_m_get_module_info,
@@ -153,6 +162,7 @@ static const struct ethtool_ops mlxsw_m_port_ethtool_ops = {
.get_module_eeprom_by_page = mlxsw_m_get_module_eeprom_by_page,
.get_module_low_power = mlxsw_m_get_module_low_power,
.set_module_low_power = mlxsw_m_set_module_low_power,
+ .reset_module = mlxsw_m_reset_module,
};
static int
@@ -1244,6 +1244,24 @@ static int mlxsw_sp_set_module_low_power(struct net_device *dev, bool low_power,
extack);
}
+static int mlxsw_sp_reset_module(struct net_device *dev,
+ struct netlink_ext_ack *extack)
+{
+ struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ u8 module = mlxsw_sp_port->mapping.module;
+
+ /* We are going to take the module down, so no port using it can be
+ * administratively up.
+ */
+ if (mlxsw_sp_module_ports_up_check(mlxsw_sp, module)) {
+ NL_SET_ERR_MSG_MOD(extack, "Cannot reset module when ports using it are administratively up");
+ return -EINVAL;
+ }
+
+ return mlxsw_env_reset_module(mlxsw_sp->core, module, extack);
+}
+
const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
.cap_link_lanes_supported = true,
.get_drvinfo = mlxsw_sp_port_get_drvinfo,
@@ -1267,6 +1285,7 @@ const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
.get_rmon_stats = mlxsw_sp_get_rmon_stats,
.get_module_low_power = mlxsw_sp_get_module_low_power,
.set_module_low_power = mlxsw_sp_set_module_low_power,
+ .reset_module = mlxsw_sp_reset_module,
};
struct mlxsw_sp1_port_link_mode {