Commit de28976d authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller

mlxsw: core_linecards: Introduce ops for linecards status change tracking

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: default avatarJiri Pirko <jiri@nvidia.com>
Signed-off-by: default avatarVadim Pasternak <vadimp@nvidia.com>
Signed-off-by: default avatarIdo Schimmel <idosch@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 85ef87ba
...@@ -590,6 +590,8 @@ struct mlxsw_linecards { ...@@ -590,6 +590,8 @@ struct mlxsw_linecards {
const struct mlxsw_bus_info *bus_info; const struct mlxsw_bus_info *bus_info;
u8 count; u8 count;
struct mlxsw_linecard_types_info *types_info; 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[]; struct mlxsw_linecard linecards[];
}; };
...@@ -603,4 +605,19 @@ int mlxsw_linecards_init(struct mlxsw_core *mlxsw_core, ...@@ -603,4 +605,19 @@ int mlxsw_linecards_init(struct mlxsw_core *mlxsw_core,
const struct mlxsw_bus_info *bus_info); const struct mlxsw_bus_info *bus_info);
void mlxsw_linecards_fini(struct mlxsw_core *mlxsw_core); 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 #endif
...@@ -95,6 +95,137 @@ static void mlxsw_linecard_provision_fail(struct mlxsw_linecard *linecard) ...@@ -95,6 +95,137 @@ static void mlxsw_linecard_provision_fail(struct mlxsw_linecard *linecard)
devlink_linecard_provision_fail(linecard->devlink_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 static int
mlxsw_linecard_provision_set(struct mlxsw_linecard *linecard, u8 card_type, mlxsw_linecard_provision_set(struct mlxsw_linecard *linecard, u8 card_type,
u16 hw_revision, u16 ini_version) u16 hw_revision, u16 ini_version)
...@@ -163,12 +294,14 @@ static int mlxsw_linecard_ready_clear(struct mlxsw_linecard *linecard) ...@@ -163,12 +294,14 @@ static int mlxsw_linecard_ready_clear(struct mlxsw_linecard *linecard)
static void mlxsw_linecard_active_set(struct mlxsw_linecard *linecard) static void mlxsw_linecard_active_set(struct mlxsw_linecard *linecard)
{ {
mlxsw_linecard_active_ops_call(linecard);
linecard->active = true; linecard->active = true;
devlink_linecard_activate(linecard->devlink_linecard); devlink_linecard_activate(linecard->devlink_linecard);
} }
static void mlxsw_linecard_active_clear(struct mlxsw_linecard *linecard) static void mlxsw_linecard_active_clear(struct mlxsw_linecard *linecard)
{ {
mlxsw_linecard_inactive_ops_call(linecard);
linecard->active = false; linecard->active = false;
devlink_linecard_deactivate(linecard->devlink_linecard); devlink_linecard_deactivate(linecard->devlink_linecard);
} }
...@@ -954,6 +1087,8 @@ int mlxsw_linecards_init(struct mlxsw_core *mlxsw_core, ...@@ -954,6 +1087,8 @@ int mlxsw_linecards_init(struct mlxsw_core *mlxsw_core,
linecards->count = slot_count; linecards->count = slot_count;
linecards->mlxsw_core = mlxsw_core; linecards->mlxsw_core = mlxsw_core;
linecards->bus_info = bus_info; 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); err = mlxsw_linecard_types_init(mlxsw_core, linecards);
if (err) if (err)
...@@ -1001,5 +1136,7 @@ void mlxsw_linecards_fini(struct mlxsw_core *mlxsw_core) ...@@ -1001,5 +1136,7 @@ void mlxsw_linecards_fini(struct mlxsw_core *mlxsw_core)
ARRAY_SIZE(mlxsw_linecard_listener), ARRAY_SIZE(mlxsw_linecard_listener),
mlxsw_core); mlxsw_core);
mlxsw_linecard_types_fini(linecards); mlxsw_linecard_types_fini(linecards);
mutex_destroy(&linecards->event_ops_list_lock);
WARN_ON(!list_empty(&linecards->event_ops_list));
vfree(linecards); vfree(linecards);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment