mlxsw: core_linecards: Introduce ops for linecards status change tracking
authorJiri Pirko <jiri@nvidia.com>
Tue, 19 Apr 2022 14:54:26 +0000 (17:54 +0300)
committerDavid S. Miller <davem@davemloft.net>
Wed, 20 Apr 2022 14:03:21 +0000 (15:03 +0100)
Introduce an infrastructure allowing users to register a set
of operations which are to be called whenever a line card gets
active/inactive.

Signed-off-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Vadim Pasternak <vadimp@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/core.h
drivers/net/ethernet/mellanox/mlxsw/core_linecards.c

index 850fff51b79f3bd1e0760907e2539ccc3c766f9d..c2a891287047b94c62273dffb5193aa630d88bb2 100644 (file)
@@ -590,6 +590,8 @@ struct mlxsw_linecards {
        const struct mlxsw_bus_info *bus_info;
        u8 count;
        struct mlxsw_linecard_types_info *types_info;
+       struct list_head event_ops_list;
+       struct mutex event_ops_list_lock; /* Locks accesses to event ops list */
        struct mlxsw_linecard linecards[];
 };
 
@@ -603,4 +605,19 @@ int mlxsw_linecards_init(struct mlxsw_core *mlxsw_core,
                         const struct mlxsw_bus_info *bus_info);
 void mlxsw_linecards_fini(struct mlxsw_core *mlxsw_core);
 
+typedef void mlxsw_linecards_event_op_t(struct mlxsw_core *mlxsw_core,
+                                       u8 slot_index, void *priv);
+
+struct mlxsw_linecards_event_ops {
+       mlxsw_linecards_event_op_t *got_active;
+       mlxsw_linecards_event_op_t *got_inactive;
+};
+
+int mlxsw_linecards_event_ops_register(struct mlxsw_core *mlxsw_core,
+                                      struct mlxsw_linecards_event_ops *ops,
+                                      void *priv);
+void mlxsw_linecards_event_ops_unregister(struct mlxsw_core *mlxsw_core,
+                                         struct mlxsw_linecards_event_ops *ops,
+                                         void *priv);
+
 #endif
index 1d50bfe67156496c8cfbc040c6a220724f4f18a8..90e487cc2e2a52c6bab61e946b779a4e077fe972 100644 (file)
@@ -95,6 +95,137 @@ static void mlxsw_linecard_provision_fail(struct mlxsw_linecard *linecard)
        devlink_linecard_provision_fail(linecard->devlink_linecard);
 }
 
+struct mlxsw_linecards_event_ops_item {
+       struct list_head list;
+       const struct mlxsw_linecards_event_ops *event_ops;
+       void *priv;
+};
+
+static void
+mlxsw_linecard_event_op_call(struct mlxsw_linecard *linecard,
+                            mlxsw_linecards_event_op_t *op, void *priv)
+{
+       struct mlxsw_core *mlxsw_core = linecard->linecards->mlxsw_core;
+
+       if (!op)
+               return;
+       op(mlxsw_core, linecard->slot_index, priv);
+}
+
+static void
+mlxsw_linecard_active_ops_call(struct mlxsw_linecard *linecard)
+{
+       struct mlxsw_linecards *linecards = linecard->linecards;
+       struct mlxsw_linecards_event_ops_item *item;
+
+       mutex_lock(&linecards->event_ops_list_lock);
+       list_for_each_entry(item, &linecards->event_ops_list, list)
+               mlxsw_linecard_event_op_call(linecard,
+                                            item->event_ops->got_active,
+                                            item->priv);
+       mutex_unlock(&linecards->event_ops_list_lock);
+}
+
+static void
+mlxsw_linecard_inactive_ops_call(struct mlxsw_linecard *linecard)
+{
+       struct mlxsw_linecards *linecards = linecard->linecards;
+       struct mlxsw_linecards_event_ops_item *item;
+
+       mutex_lock(&linecards->event_ops_list_lock);
+       list_for_each_entry(item, &linecards->event_ops_list, list)
+               mlxsw_linecard_event_op_call(linecard,
+                                            item->event_ops->got_inactive,
+                                            item->priv);
+       mutex_unlock(&linecards->event_ops_list_lock);
+}
+
+static void
+mlxsw_linecards_event_ops_register_call(struct mlxsw_linecards *linecards,
+                                       const struct mlxsw_linecards_event_ops_item *item)
+{
+       struct mlxsw_linecard *linecard;
+       int i;
+
+       for (i = 0; i < linecards->count; i++) {
+               linecard = mlxsw_linecard_get(linecards, i + 1);
+               mutex_lock(&linecard->lock);
+               if (linecard->active)
+                       mlxsw_linecard_event_op_call(linecard,
+                                                    item->event_ops->got_active,
+                                                    item->priv);
+               mutex_unlock(&linecard->lock);
+       }
+}
+
+static void
+mlxsw_linecards_event_ops_unregister_call(struct mlxsw_linecards *linecards,
+                                         const struct mlxsw_linecards_event_ops_item *item)
+{
+       struct mlxsw_linecard *linecard;
+       int i;
+
+       for (i = 0; i < linecards->count; i++) {
+               linecard = mlxsw_linecard_get(linecards, i + 1);
+               mutex_lock(&linecard->lock);
+               if (linecard->active)
+                       mlxsw_linecard_event_op_call(linecard,
+                                                    item->event_ops->got_inactive,
+                                                    item->priv);
+               mutex_unlock(&linecard->lock);
+       }
+}
+
+int mlxsw_linecards_event_ops_register(struct mlxsw_core *mlxsw_core,
+                                      struct mlxsw_linecards_event_ops *ops,
+                                      void *priv)
+{
+       struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_core);
+       struct mlxsw_linecards_event_ops_item *item;
+
+       if (!linecards)
+               return 0;
+       item = kzalloc(sizeof(*item), GFP_KERNEL);
+       if (!item)
+               return -ENOMEM;
+       item->event_ops = ops;
+       item->priv = priv;
+
+       mutex_lock(&linecards->event_ops_list_lock);
+       list_add_tail(&item->list, &linecards->event_ops_list);
+       mutex_unlock(&linecards->event_ops_list_lock);
+       mlxsw_linecards_event_ops_register_call(linecards, item);
+       return 0;
+}
+EXPORT_SYMBOL(mlxsw_linecards_event_ops_register);
+
+void mlxsw_linecards_event_ops_unregister(struct mlxsw_core *mlxsw_core,
+                                         struct mlxsw_linecards_event_ops *ops,
+                                         void *priv)
+{
+       struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_core);
+       struct mlxsw_linecards_event_ops_item *item, *tmp;
+       bool found = false;
+
+       if (!linecards)
+               return;
+       mutex_lock(&linecards->event_ops_list_lock);
+       list_for_each_entry_safe(item, tmp, &linecards->event_ops_list, list) {
+               if (item->event_ops == ops && item->priv == priv) {
+                       list_del(&item->list);
+                       found = true;
+                       break;
+               }
+       }
+       mutex_unlock(&linecards->event_ops_list_lock);
+
+       if (!found)
+               return;
+       mlxsw_linecards_event_ops_unregister_call(linecards, item);
+       kfree(item);
+}
+EXPORT_SYMBOL(mlxsw_linecards_event_ops_unregister);
+
 static int
 mlxsw_linecard_provision_set(struct mlxsw_linecard *linecard, u8 card_type,
                             u16 hw_revision, u16 ini_version)
@@ -163,12 +294,14 @@ static int mlxsw_linecard_ready_clear(struct mlxsw_linecard *linecard)
 
 static void mlxsw_linecard_active_set(struct mlxsw_linecard *linecard)
 {
+       mlxsw_linecard_active_ops_call(linecard);
        linecard->active = true;
        devlink_linecard_activate(linecard->devlink_linecard);
 }
 
 static void mlxsw_linecard_active_clear(struct mlxsw_linecard *linecard)
 {
+       mlxsw_linecard_inactive_ops_call(linecard);
        linecard->active = false;
        devlink_linecard_deactivate(linecard->devlink_linecard);
 }
@@ -954,6 +1087,8 @@ int mlxsw_linecards_init(struct mlxsw_core *mlxsw_core,
        linecards->count = slot_count;
        linecards->mlxsw_core = mlxsw_core;
        linecards->bus_info = bus_info;
+       INIT_LIST_HEAD(&linecards->event_ops_list);
+       mutex_init(&linecards->event_ops_list_lock);
 
        err = mlxsw_linecard_types_init(mlxsw_core, linecards);
        if (err)
@@ -1001,5 +1136,7 @@ void mlxsw_linecards_fini(struct mlxsw_core *mlxsw_core)
                                    ARRAY_SIZE(mlxsw_linecard_listener),
                                    mlxsw_core);
        mlxsw_linecard_types_fini(linecards);
+       mutex_destroy(&linecards->event_ops_list_lock);
+       WARN_ON(!list_empty(&linecards->event_ops_list));
        vfree(linecards);
 }