mlxsw: core_env: Defer handling of module temperature warning events
authorIdo Schimmel <idosch@nvidia.com>
Wed, 15 Sep 2021 10:13:07 +0000 (13:13 +0300)
committerDavid S. Miller <davem@davemloft.net>
Wed, 15 Sep 2021 15:17:15 +0000 (16:17 +0100)
Module temperature events are currently handled in softIRQ context,
requiring the 'module_info_lock' to be a spin lock. In future patchsets
we will need to be able to hold the lock while sleeping.

Therefore, defer handling of these events using a work queue so that the
next patch will be able to convert the lock to a mutex.

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/core_env.c

index 27e721f..27eba0a 100644 (file)
@@ -482,20 +482,30 @@ static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core,
        return 0;
 }
 
-static void mlxsw_env_mtwe_event_func(const struct mlxsw_reg_info *reg,
-                                     char *mtwe_pl, void *priv)
+struct mlxsw_env_module_temp_warn_event {
+       struct mlxsw_env *mlxsw_env;
+       char mtwe_pl[MLXSW_REG_MTWE_LEN];
+       struct work_struct work;
+};
+
+static void mlxsw_env_mtwe_event_work(struct work_struct *work)
 {
-       struct mlxsw_env *mlxsw_env = priv;
+       struct mlxsw_env_module_temp_warn_event *event;
+       struct mlxsw_env *mlxsw_env;
        int i, sensor_warning;
        bool is_overheat;
 
+       event = container_of(work, struct mlxsw_env_module_temp_warn_event,
+                            work);
+       mlxsw_env = event->mlxsw_env;
+
        for (i = 0; i < mlxsw_env->module_count; i++) {
                /* 64-127 of sensor_index are mapped to the port modules
                 * sequentially (module 0 is mapped to sensor_index 64,
                 * module 1 to sensor_index 65 and so on)
                 */
                sensor_warning =
-                       mlxsw_reg_mtwe_sensor_warning_get(mtwe_pl,
+                       mlxsw_reg_mtwe_sensor_warning_get(event->mtwe_pl,
                                                          i + MLXSW_REG_MTMP_MODULE_INDEX_MIN);
                spin_lock(&mlxsw_env->module_info_lock);
                is_overheat =
@@ -524,10 +534,29 @@ static void mlxsw_env_mtwe_event_func(const struct mlxsw_reg_info *reg,
                        spin_unlock(&mlxsw_env->module_info_lock);
                }
        }
+
+       kfree(event);
+}
+
+static void
+mlxsw_env_mtwe_listener_func(const struct mlxsw_reg_info *reg, char *mtwe_pl,
+                            void *priv)
+{
+       struct mlxsw_env_module_temp_warn_event *event;
+       struct mlxsw_env *mlxsw_env = priv;
+
+       event = kmalloc(sizeof(*event), GFP_ATOMIC);
+       if (!event)
+               return;
+
+       event->mlxsw_env = mlxsw_env;
+       memcpy(event->mtwe_pl, mtwe_pl, MLXSW_REG_MTWE_LEN);
+       INIT_WORK(&event->work, mlxsw_env_mtwe_event_work);
+       mlxsw_core_schedule_work(&event->work);
 }
 
 static const struct mlxsw_listener mlxsw_env_temp_warn_listener =
-       MLXSW_EVENTL(mlxsw_env_mtwe_event_func, MTWE, MTWE);
+       MLXSW_EVENTL(mlxsw_env_mtwe_listener_func, MTWE, MTWE);
 
 static int mlxsw_env_temp_warn_event_register(struct mlxsw_core *mlxsw_core)
 {