From: Amit Cohen <amco...@nvidia.com>

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 <amco...@nvidia.com>
Signed-off-by: Ido Schimmel <ido...@nvidia.com>
---
 .../net/ethernet/mellanox/mlxsw/core_env.c    | 126 ++++++++++++++++++
 drivers/net/ethernet/mellanox/mlxsw/reg.h     |   1 +
 .../net/ethernet/mellanox/mlxsw/spectrum.c    |   8 ++
 drivers/net/ethernet/mellanox/mlxsw/trap.h    |   2 +
 4 files changed, 137 insertions(+)

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 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct 
mlxsw_env **p_env)
 
 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 */
-- 
2.26.2

Reply via email to