mlxsw: core_linecards: Separate line card init and fini flow
authorVadim Pasternak <vadimp@nvidia.com>
Sun, 21 Aug 2022 16:20:11 +0000 (18:20 +0200)
committerJakub Kicinski <kuba@kernel.org>
Wed, 24 Aug 2022 00:21:59 +0000 (17:21 -0700)
Currently, each line card is initialized using the following steps:

1. Initializing its various fields (e.g., slot index).
2. Creating the corresponding devlink object.
3. Enabling events (i.e., traps) for changes in line card status.
4. Querying and processing line card status.

Unlike traps, the IRQ that notifies the CPU about line card status
changes cannot be enabled / disabled on a per line card basis.

If a handler is registered before the line cards are initialized, the
handler risks accessing uninitialized memory.

On the other hand, if the handler is registered after initialization,
we risk missing events. For example, in step 4, the driver might see
that a line card is in ready state and will tell the device to enable
it. When enablement is done, the line card will be activated and the
IRQ will be triggered. Since a handler was not registered, the event
will be missed.

Solve this by splitting the initialization sequence into two steps
(1-2 and 3-4). In a subsequent patch, the handler will be registered
between both steps.

Signed-off-by: Vadim Pasternak <vadimp@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Petr Machata <petrm@nvidia.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/mellanox/mlxsw/core_linecards.c

index ca59f0b..8549ccb 100644 (file)
@@ -1238,7 +1238,6 @@ static int mlxsw_linecard_init(struct mlxsw_core *mlxsw_core,
 {
        struct devlink_linecard *devlink_linecard;
        struct mlxsw_linecard *linecard;
-       int err;
 
        linecard = mlxsw_linecard_get(linecards, slot_index);
        linecard->slot_index = slot_index;
@@ -1248,17 +1247,45 @@ static int mlxsw_linecard_init(struct mlxsw_core *mlxsw_core,
        devlink_linecard = devlink_linecard_create(priv_to_devlink(mlxsw_core),
                                                   slot_index, &mlxsw_linecard_ops,
                                                   linecard);
-       if (IS_ERR(devlink_linecard)) {
-               err = PTR_ERR(devlink_linecard);
-               goto err_devlink_linecard_create;
-       }
+       if (IS_ERR(devlink_linecard))
+               return PTR_ERR(devlink_linecard);
+
        linecard->devlink_linecard = devlink_linecard;
        INIT_DELAYED_WORK(&linecard->status_event_to_dw,
                          &mlxsw_linecard_status_event_to_work);
 
+       return 0;
+}
+
+static void mlxsw_linecard_fini(struct mlxsw_core *mlxsw_core,
+                               struct mlxsw_linecards *linecards,
+                               u8 slot_index)
+{
+       struct mlxsw_linecard *linecard;
+
+       linecard = mlxsw_linecard_get(linecards, slot_index);
+       cancel_delayed_work_sync(&linecard->status_event_to_dw);
+       /* Make sure all scheduled events are processed */
+       mlxsw_core_flush_owq();
+       if (linecard->active)
+               mlxsw_linecard_active_clear(linecard);
+       mlxsw_linecard_bdev_del(linecard);
+       devlink_linecard_destroy(linecard->devlink_linecard);
+       mutex_destroy(&linecard->lock);
+}
+
+static int
+mlxsw_linecard_event_delivery_init(struct mlxsw_core *mlxsw_core,
+                                  struct mlxsw_linecards *linecards,
+                                  u8 slot_index)
+{
+       struct mlxsw_linecard *linecard;
+       int err;
+
+       linecard = mlxsw_linecard_get(linecards, slot_index);
        err = mlxsw_linecard_event_delivery_set(mlxsw_core, linecard, true);
        if (err)
-               goto err_event_delivery_set;
+               return err;
 
        err = mlxsw_linecard_status_get_and_process(mlxsw_core, linecards,
                                                    linecard);
@@ -1269,29 +1296,18 @@ static int mlxsw_linecard_init(struct mlxsw_core *mlxsw_core,
 
 err_status_get_and_process:
        mlxsw_linecard_event_delivery_set(mlxsw_core, linecard, false);
-err_event_delivery_set:
-       devlink_linecard_destroy(linecard->devlink_linecard);
-err_devlink_linecard_create:
-       mutex_destroy(&linecard->lock);
        return err;
 }
 
-static void mlxsw_linecard_fini(struct mlxsw_core *mlxsw_core,
-                               struct mlxsw_linecards *linecards,
-                               u8 slot_index)
+static void
+mlxsw_linecard_event_delivery_fini(struct mlxsw_core *mlxsw_core,
+                                  struct mlxsw_linecards *linecards,
+                                  u8 slot_index)
 {
        struct mlxsw_linecard *linecard;
 
        linecard = mlxsw_linecard_get(linecards, slot_index);
        mlxsw_linecard_event_delivery_set(mlxsw_core, linecard, false);
-       cancel_delayed_work_sync(&linecard->status_event_to_dw);
-       /* Make sure all scheduled events are processed */
-       mlxsw_core_flush_owq();
-       if (linecard->active)
-               mlxsw_linecard_active_clear(linecard);
-       mlxsw_linecard_bdev_del(linecard);
-       devlink_linecard_destroy(linecard->devlink_linecard);
-       mutex_destroy(&linecard->lock);
 }
 
 /*       LINECARDS INI BUNDLE FILE
@@ -1513,8 +1529,19 @@ int mlxsw_linecards_init(struct mlxsw_core *mlxsw_core,
                        goto err_linecard_init;
        }
 
+       for (i = 0; i < linecards->count; i++) {
+               err = mlxsw_linecard_event_delivery_init(mlxsw_core, linecards,
+                                                        i + 1);
+               if (err)
+                       goto err_linecard_event_delivery_init;
+       }
+
        return 0;
 
+err_linecard_event_delivery_init:
+       for (i--; i >= 0; i--)
+               mlxsw_linecard_event_delivery_fini(mlxsw_core, linecards, i + 1);
+       i = linecards->count;
 err_linecard_init:
        for (i--; i >= 0; i--)
                mlxsw_linecard_fini(mlxsw_core, linecards, i + 1);
@@ -1536,6 +1563,8 @@ void mlxsw_linecards_fini(struct mlxsw_core *mlxsw_core)
        if (!linecards)
                return;
        for (i = 0; i < linecards->count; i++)
+               mlxsw_linecard_event_delivery_fini(mlxsw_core, linecards, i + 1);
+       for (i = 0; i < linecards->count; i++)
                mlxsw_linecard_fini(mlxsw_core, linecards, i + 1);
        mlxsw_core_traps_unregister(mlxsw_core, mlxsw_linecard_listener,
                                    ARRAY_SIZE(mlxsw_linecard_listener),