diff options
author | Amit Cohen <amcohen@nvidia.com> | 2020-09-27 10:50:14 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2020-09-27 23:27:01 +0300 |
commit | 05cf5828bc8e18fcff095222395e188766683409 (patch) | |
tree | bc5a66a4ba313e9fd876e3ccde8ae7a8efafd72e | |
parent | 3bdbab3fee87e7d2b29a61ea55808ae9d993f1d2 (diff) | |
download | linux-05cf5828bc8e18fcff095222395e188766683409.tar.xz |
mlxsw: Update module's settings when module is plugged in
Module temperature warning events are enabled for modules that have a
temperature sensor and configured according to the temperature
thresholds queried from the module.
When a module is unplugged we are guaranteed not to get temperature
warning events. However, when a module is plugged in we need to
potentially update its current settings (i.e., event enablement and
thresholds).
Register to port module plug/unplug events and update module's settings
upon plug in events.
Signed-off-by: Amit Cohen <amcohen@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/core_env.c | 126 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/reg.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/trap.h | 2 |
4 files changed, 137 insertions, 0 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c index 63dd1fb58381..dd26865bd587 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c @@ -467,6 +467,117 @@ static void mlxsw_env_temp_warn_event_unregister(struct mlxsw_env *mlxsw_env) &mlxsw_env_temp_warn_listener, mlxsw_env); } +struct mlxsw_env_module_plug_unplug_event { + struct mlxsw_env *mlxsw_env; + u8 module; + struct work_struct work; +}; + +static void mlxsw_env_pmpe_event_work(struct work_struct *work) +{ + struct mlxsw_env_module_plug_unplug_event *event; + struct mlxsw_env *mlxsw_env; + bool has_temp_sensor; + u16 sensor_index; + int err; + + event = container_of(work, struct mlxsw_env_module_plug_unplug_event, + work); + mlxsw_env = event->mlxsw_env; + + spin_lock_bh(&mlxsw_env->module_info_lock); + mlxsw_env->module_info[event->module].is_overheat = false; + spin_unlock_bh(&mlxsw_env->module_info_lock); + + err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core, event->module, + &has_temp_sensor); + /* Do not disable events on modules without sensors or faulty sensors + * because FW returns errors. + */ + if (err) + goto out; + + if (!has_temp_sensor) + goto out; + + sensor_index = event->module + MLXSW_REG_MTMP_MODULE_INDEX_MIN; + mlxsw_env_temp_event_set(mlxsw_env->core, sensor_index, true); + +out: + kfree(event); +} + +static void +mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl, + void *priv) +{ + struct mlxsw_env_module_plug_unplug_event *event; + enum mlxsw_reg_pmpe_module_status module_status; + u8 module = mlxsw_reg_pmpe_module_get(pmpe_pl); + struct mlxsw_env *mlxsw_env = priv; + + if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) + return; + + module_status = mlxsw_reg_pmpe_module_status_get(pmpe_pl); + if (module_status != MLXSW_REG_PMPE_MODULE_STATUS_PLUGGED_ENABLED) + return; + + event = kmalloc(sizeof(*event), GFP_ATOMIC); + if (!event) + return; + + event->mlxsw_env = mlxsw_env; + event->module = module; + INIT_WORK(&event->work, mlxsw_env_pmpe_event_work); + mlxsw_core_schedule_work(&event->work); +} + +static const struct mlxsw_listener mlxsw_env_module_plug_listener = + MLXSW_EVENTL(mlxsw_env_pmpe_listener_func, PMPE, PMPE); + +static int +mlxsw_env_module_plug_event_register(struct mlxsw_core *mlxsw_core) +{ + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + + if (!mlxsw_core_temp_warn_enabled(mlxsw_core)) + return 0; + + return mlxsw_core_trap_register(mlxsw_core, + &mlxsw_env_module_plug_listener, + mlxsw_env); +} + +static void +mlxsw_env_module_plug_event_unregister(struct mlxsw_env *mlxsw_env) +{ + if (!mlxsw_core_temp_warn_enabled(mlxsw_env->core)) + return; + + mlxsw_core_trap_unregister(mlxsw_env->core, + &mlxsw_env_module_plug_listener, + mlxsw_env); +} + +static int +mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core, + u8 module_count) +{ + int i, err; + + for (i = 0; i < module_count; i++) { + char pmaos_pl[MLXSW_REG_PMAOS_LEN]; + + mlxsw_reg_pmaos_pack(pmaos_pl, i, + MLXSW_REG_PMAOS_E_GENERATE_EVENT); + err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl); + if (err) + return err; + } + return 0; +} + int mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module, u64 *p_counter) @@ -517,6 +628,15 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) if (err) goto err_temp_warn_event_register; + err = mlxsw_env_module_plug_event_register(mlxsw_core); + if (err) + goto err_module_plug_event_register; + + err = mlxsw_env_module_oper_state_event_enable(mlxsw_core, + env->module_count); + if (err) + goto err_oper_state_event_enable; + err = mlxsw_env_module_temp_event_enable(mlxsw_core, env->module_count); if (err) goto err_temp_event_enable; @@ -524,6 +644,9 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) return 0; err_temp_event_enable: +err_oper_state_event_enable: + mlxsw_env_module_plug_event_unregister(env); +err_module_plug_event_register: mlxsw_env_temp_warn_event_unregister(env); err_temp_warn_event_register: kfree(env); @@ -532,6 +655,9 @@ err_temp_warn_event_register: void mlxsw_env_fini(struct mlxsw_env *env) { + mlxsw_env_module_plug_event_unregister(env); + /* Make sure there is no more event work scheduled. */ + mlxsw_core_flush_owq(); mlxsw_env_temp_warn_event_unregister(env); kfree(env); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index e8415589d4fb..39eff6a57ba2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -5683,6 +5683,7 @@ enum mlxsw_reg_htgt_trap_group { MLXSW_REG_HTGT_TRAP_GROUP_EMAD, MLXSW_REG_HTGT_TRAP_GROUP_MFDE, MLXSW_REG_HTGT_TRAP_GROUP_MTWE, + MLXSW_REG_HTGT_TRAP_GROUP_PMPE, MLXSW_REG_HTGT_TRAP_GROUP_SP_STP, MLXSW_REG_HTGT_TRAP_GROUP_SP_LACP, MLXSW_REG_HTGT_TRAP_GROUP_SP_LLDP, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 25b1ab1cfa68..ab7d12aad880 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -2473,6 +2473,14 @@ static int mlxsw_sp_basic_trap_groups_set(struct mlxsw_core *mlxsw_core) MLXSW_REG_HTGT_INVALID_POLICER, MLXSW_REG_HTGT_DEFAULT_PRIORITY, MLXSW_REG_HTGT_DEFAULT_TC); + err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); + if (err) + return err; + + mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_PMPE, + MLXSW_REG_HTGT_INVALID_POLICER, + MLXSW_REG_HTGT_DEFAULT_PRIORITY, + MLXSW_REG_HTGT_DEFAULT_TC); return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h index 8d73e54f6c29..57f9e24602d0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/trap.h +++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h @@ -124,6 +124,8 @@ enum mlxsw_event_trap_id { MLXSW_TRAP_ID_MFDE = 0x3, /* Port Up/Down event generated by hardware */ MLXSW_TRAP_ID_PUDE = 0x8, + /* Port Module Plug/Unplug Event generated by hardware */ + MLXSW_TRAP_ID_PMPE = 0x9, /* Temperature Warning event generated by hardware */ MLXSW_TRAP_ID_MTWE = 0xC, /* PTP Ingress FIFO has a new entry */ |