[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20210809102152.719961-9-idosch@idosch.org>
Date: Mon, 9 Aug 2021 13:21:52 +0300
From: Ido Schimmel <idosch@...sch.org>
To: netdev@...r.kernel.org
Cc: davem@...emloft.net, kuba@...nel.org, andrew@...n.ch,
mkubecek@...e.cz, pali@...nel.org, vadimp@...dia.com,
mlxsw@...dia.com, Ido Schimmel <idosch@...dia.com>
Subject: [RFC PATCH net-next 8/8] mlxsw: Add ability to reset transceiver modules
From: Ido Schimmel <idosch@...dia.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@...dia.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
Powered by blists - more mailing lists