[RFC PATCH net-next 8/8] mlxsw: Add ability to reset transceiver modules
flat view
STALE1895d
From: Ido Schimmel <hidden>
Date: 2021-08-09 10:23:02
Subsystem:
mellanox ethernet switch drivers, networking drivers, the rest · Maintainers:
Ido Schimmel, Petr Machata, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
From: Ido Schimmel <idosch@nvidia.com> Implement support for ethtool_ops::reset_module. This is done by writing to the "rst" bit of the PMAOS register and waiting for the module to reach a valid operational state. If the module does not transition to a valid state, an error is reported to user space via extack. Signed-off-by: Ido Schimmel <idosch@nvidia.com> --- .../net/ethernet/mellanox/mlxsw/core_env.c | 28 +++++++++++++++++++ .../net/ethernet/mellanox/mlxsw/core_env.h | 3 ++ drivers/net/ethernet/mellanox/mlxsw/minimal.c | 10 +++++++ .../mellanox/mlxsw/spectrum_ethtool.c | 19 +++++++++++++ 4 files changed, 60 insertions(+)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c
index 1ae06730d374..df578ef3319c 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c@@ -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)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.h b/drivers/net/ethernet/mellanox/mlxsw/core_env.h
index 32960de96674..465a095e6a3e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.h@@ -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);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c
index 6fb8204c4d8a..d206442270df 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c@@ -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
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c
index fb6256f16c50..9526ef71e513 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c@@ -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 {
--
2.31.1