Skip to content

Commit 49fd3b6

Browse files
idoschdavem330
authored andcommitted
mlxsw: Add support for transceiver modules reset
Implement support for ethtool_ops::reset in order to reset transceiver modules. The module backing the netdev is reset when the 'ETH_RESET_PHY' flag is set. After a successful reset, the flag is cleared by the driver and other flags are ignored. This is in accordance with the interface documentation: "The reset() operation must clear the flags for the components which were actually reset. On successful return, the flags indicate the components which were not reset, either because they do not exist in the hardware or because they cannot be reset independently. The driver must never reset any components that were not requested." Reset is useful in order to allow a module to transition out of a fault state. From section 6.3.2.12 in CMIS 5.0: "Except for a power cycle, the only exit path from the ModuleFault state is to perform a module reset by taking an action that causes the ResetS transition signal to become TRUE (see Table 6-11)". An error is returned when the netdev is administratively up: # ip link set dev swp11 up # ethtool --reset swp11 phy ETHTOOL_RESET 0x40 Cannot issue ETHTOOL_RESET: Invalid argument # ip link set dev swp11 down # ethtool --reset swp11 phy ETHTOOL_RESET 0x40 Components reset: 0x40 An error is returned when the module is shared by multiple ports (split ports) and the "phy-shared" flag is not set: # devlink port split swp11 count 4 # ethtool --reset swp11s0 phy ETHTOOL_RESET 0x40 Cannot issue ETHTOOL_RESET: Invalid argument # ethtool --reset swp11s0 phy-shared ETHTOOL_RESET 0x400000 Components reset: 0x400000 # devlink port unsplit swp11s0 # ethtool --reset swp11 phy ETHTOOL_RESET 0x40 Components reset: 0x40 An error is also returned when one of the ports using the module is administratively up: # devlink port split swp11 count 4 # ip link set dev swp11s1 up # ethtool --reset swp11s0 phy-shared ETHTOOL_RESET 0x400000 Cannot issue ETHTOOL_RESET: Invalid argument # ip link set dev swp11s1 down # ethtool --reset swp11s0 phy-shared ETHTOOL_RESET 0x400000 Components reset: 0x400000 Reset is performed by writing to the "rst" bit of the PMAOS register, which instructs the firmware to assert the reset signal connected to the module for a fixed amount of time. Signed-off-by: Ido Schimmel <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 8f4ebdb commit 49fd3b6

File tree

4 files changed

+77
-0
lines changed

4 files changed

+77
-0
lines changed

drivers/net/ethernet/mellanox/mlxsw/core_env.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,59 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module,
392392
}
393393
EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page);
394394

395+
static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 module)
396+
{
397+
char pmaos_pl[MLXSW_REG_PMAOS_LEN];
398+
399+
mlxsw_reg_pmaos_pack(pmaos_pl, module);
400+
mlxsw_reg_pmaos_rst_set(pmaos_pl, true);
401+
402+
return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
403+
}
404+
405+
int mlxsw_env_reset_module(struct net_device *netdev,
406+
struct mlxsw_core *mlxsw_core, u8 module, u32 *flags)
407+
{
408+
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
409+
u32 req = *flags;
410+
int err;
411+
412+
if (!(req & ETH_RESET_PHY) &&
413+
!(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT)))
414+
return 0;
415+
416+
if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
417+
return -EINVAL;
418+
419+
mutex_lock(&mlxsw_env->module_info_lock);
420+
421+
if (mlxsw_env->module_info[module].num_ports_up) {
422+
netdev_err(netdev, "Cannot reset module when ports using it are administratively up\n");
423+
err = -EINVAL;
424+
goto out;
425+
}
426+
427+
if (mlxsw_env->module_info[module].num_ports_mapped > 1 &&
428+
!(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) {
429+
netdev_err(netdev, "Cannot reset module without \"phy-shared\" flag when shared by multiple ports\n");
430+
err = -EINVAL;
431+
goto out;
432+
}
433+
434+
err = mlxsw_env_module_reset(mlxsw_core, module);
435+
if (err) {
436+
netdev_err(netdev, "Failed to reset module\n");
437+
goto out;
438+
}
439+
440+
*flags &= ~(ETH_RESET_PHY | (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT));
441+
442+
out:
443+
mutex_unlock(&mlxsw_env->module_info_lock);
444+
return err;
445+
}
446+
EXPORT_SYMBOL(mlxsw_env_reset_module);
447+
395448
static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core,
396449
u8 module,
397450
bool *p_has_temp_sensor)

drivers/net/ethernet/mellanox/mlxsw/core_env.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module,
2424
const struct ethtool_module_eeprom *page,
2525
struct netlink_ext_ack *extack);
2626

27+
int mlxsw_env_reset_module(struct net_device *netdev,
28+
struct mlxsw_core *mlxsw_core, u8 module,
29+
u32 *flags);
30+
2731
int
2832
mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module,
2933
u64 *p_counter);

drivers/net/ethernet/mellanox/mlxsw/minimal.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,21 @@ mlxsw_m_get_module_eeprom_by_page(struct net_device *netdev,
136136
page, extack);
137137
}
138138

139+
static int mlxsw_m_reset(struct net_device *netdev, u32 *flags)
140+
{
141+
struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
142+
struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
143+
144+
return mlxsw_env_reset_module(netdev, core, mlxsw_m_port->module,
145+
flags);
146+
}
147+
139148
static const struct ethtool_ops mlxsw_m_port_ethtool_ops = {
140149
.get_drvinfo = mlxsw_m_module_get_drvinfo,
141150
.get_module_info = mlxsw_m_get_module_info,
142151
.get_module_eeprom = mlxsw_m_get_module_eeprom,
143152
.get_module_eeprom_by_page = mlxsw_m_get_module_eeprom_by_page,
153+
.reset = mlxsw_m_reset,
144154
};
145155

146156
static int

drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,6 +1197,15 @@ mlxsw_sp_get_rmon_stats(struct net_device *dev,
11971197
*ranges = mlxsw_rmon_ranges;
11981198
}
11991199

1200+
static int mlxsw_sp_reset(struct net_device *dev, u32 *flags)
1201+
{
1202+
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1203+
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1204+
u8 module = mlxsw_sp_port->mapping.module;
1205+
1206+
return mlxsw_env_reset_module(dev, mlxsw_sp->core, module, flags);
1207+
}
1208+
12001209
const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
12011210
.cap_link_lanes_supported = true,
12021211
.get_drvinfo = mlxsw_sp_port_get_drvinfo,
@@ -1218,6 +1227,7 @@ const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
12181227
.get_eth_mac_stats = mlxsw_sp_get_eth_mac_stats,
12191228
.get_eth_ctrl_stats = mlxsw_sp_get_eth_ctrl_stats,
12201229
.get_rmon_stats = mlxsw_sp_get_rmon_stats,
1230+
.reset = mlxsw_sp_reset,
12211231
};
12221232

12231233
struct mlxsw_sp1_port_link_mode {

0 commit comments

Comments
 (0)