Commit 365014f5 authored by David S. Miller's avatar David S. Miller

Merge branch 'mlxsw-line-card-status-tracking'

Ido Schimmel says:

====================
mlxsw: Line cards status tracking

When a line card is provisioned, netdevs corresponding to the ports
found on the line card are registered. User space can then perform
various logical configurations (e.g., splitting, setting MTU) on these
netdevs.

However, since the line card is not present / powered on (i.e., it is
not in 'active' state), user space cannot access the various components
found on the line card. For example, user space cannot read the
temperature of gearboxes or transceiver modules found on the line card
via hwmon / thermal. Similarly, it cannot dump the EEPROM contents of
these transceiver modules. The above is only possible when the line card
becomes active.

This patchset solves the problem by tracking the status of each line
card and invoking callbacks from interested parties when a line card
becomes active / inactive.

Patchset overview:

Patch #1 adds the infrastructure in the line cards core that allows
users to registers a set of callbacks that are invoked when a line card
becomes active / inactive. To avoid races, if a line card is already
active during registration, the got_active() callback is invoked.

Patches #2-#3 are preparations.

Patch #4 changes the port module core to register a set of callbacks
with the line cards core. See detailed description with examples in the
commit message.

Patches #5-#6 do the same with regards to thermal / hwmon support, so
that user space will be able to monitor the temperature of various
components on the line card when it becomes active.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 85ef87ba 99a03b31
......@@ -2175,7 +2175,7 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
if (err)
goto err_thermal_init;
err = mlxsw_env_init(mlxsw_core, &mlxsw_core->env);
err = mlxsw_env_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->env);
if (err)
goto err_env_init;
......
......@@ -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
......@@ -60,7 +60,9 @@ int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 slot_index,
void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 slot_index,
u8 module);
int mlxsw_env_init(struct mlxsw_core *core, struct mlxsw_env **p_env);
int mlxsw_env_init(struct mlxsw_core *core,
const struct mlxsw_bus_info *bus_info,
struct mlxsw_env **p_env);
void mlxsw_env_fini(struct mlxsw_env *env);
#endif
......@@ -19,6 +19,7 @@
#define MLXSW_HWMON_ATTR_PER_SENSOR 3
#define MLXSW_HWMON_ATTR_PER_MODULE 7
#define MLXSW_HWMON_ATTR_PER_GEARBOX 4
#define MLXSW_HWMON_DEV_NAME_LEN_MAX 16
#define MLXSW_HWMON_ATTR_COUNT (MLXSW_HWMON_SENSORS_MAX_COUNT * MLXSW_HWMON_ATTR_PER_SENSOR + \
MLXSW_HWMON_MODULES_MAX_COUNT * MLXSW_HWMON_ATTR_PER_MODULE + \
......@@ -41,6 +42,7 @@ static int mlxsw_hwmon_get_attr_index(int index, int count)
}
struct mlxsw_hwmon_dev {
char name[MLXSW_HWMON_DEV_NAME_LEN_MAX];
struct mlxsw_hwmon *hwmon;
struct device *hwmon_dev;
struct attribute_group group;
......@@ -51,6 +53,7 @@ struct mlxsw_hwmon_dev {
u8 sensor_count;
u8 module_sensor_max;
u8 slot_index;
bool active;
};
struct mlxsw_hwmon {
......@@ -780,6 +783,75 @@ static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev)
return 0;
}
static void
mlxsw_hwmon_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index,
void *priv)
{
struct mlxsw_hwmon *hwmon = priv;
struct mlxsw_hwmon_dev *linecard;
struct device *dev;
int err;
dev = hwmon->bus_info->dev;
linecard = &hwmon->line_cards[slot_index];
if (linecard->active)
return;
/* For the main board, module sensor indexes start from 1, sensor index
* 0 is used for the ASIC. Use the same numbering for line cards.
*/
linecard->sensor_count = 1;
linecard->slot_index = slot_index;
linecard->hwmon = hwmon;
err = mlxsw_hwmon_module_init(linecard);
if (err) {
dev_err(dev, "Failed to configure hwmon objects for line card modules in slot %d\n",
slot_index);
return;
}
err = mlxsw_hwmon_gearbox_init(linecard);
if (err) {
dev_err(dev, "Failed to configure hwmon objects for line card gearboxes in slot %d\n",
slot_index);
return;
}
linecard->groups[0] = &linecard->group;
linecard->group.attrs = linecard->attrs;
sprintf(linecard->name, "%s#%02u", "linecard", slot_index);
linecard->hwmon_dev =
hwmon_device_register_with_groups(dev, linecard->name,
linecard, linecard->groups);
if (IS_ERR(linecard->hwmon_dev)) {
dev_err(dev, "Failed to register hwmon objects for line card in slot %d\n",
slot_index);
return;
}
linecard->active = true;
}
static void
mlxsw_hwmon_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index,
void *priv)
{
struct mlxsw_hwmon *hwmon = priv;
struct mlxsw_hwmon_dev *linecard;
linecard = &hwmon->line_cards[slot_index];
if (!linecard->active)
return;
linecard->active = false;
hwmon_device_unregister(linecard->hwmon_dev);
/* Reset attributes counter */
linecard->attrs_count = 0;
}
static struct mlxsw_linecards_event_ops mlxsw_hwmon_event_ops = {
.got_active = mlxsw_hwmon_got_active,
.got_inactive = mlxsw_hwmon_got_inactive,
};
int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
const struct mlxsw_bus_info *mlxsw_bus_info,
struct mlxsw_hwmon **p_hwmon)
......@@ -836,10 +908,19 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
goto err_hwmon_register;
}
err = mlxsw_linecards_event_ops_register(mlxsw_hwmon->core,
&mlxsw_hwmon_event_ops,
mlxsw_hwmon);
if (err)
goto err_linecards_event_ops_register;
mlxsw_hwmon->line_cards[0].hwmon_dev = hwmon_dev;
mlxsw_hwmon->line_cards[0].active = true;
*p_hwmon = mlxsw_hwmon;
return 0;
err_linecards_event_ops_register:
hwmon_device_unregister(mlxsw_hwmon->line_cards[0].hwmon_dev);
err_hwmon_register:
err_temp_gearbox_init:
err_temp_module_init:
......@@ -851,6 +932,9 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon)
{
mlxsw_hwmon->line_cards[0].active = false;
mlxsw_linecards_event_ops_unregister(mlxsw_hwmon->core,
&mlxsw_hwmon_event_ops, mlxsw_hwmon);
hwmon_device_unregister(mlxsw_hwmon->line_cards[0].hwmon_dev);
kfree(mlxsw_hwmon);
}
......@@ -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);
}
......@@ -90,6 +90,7 @@ struct mlxsw_thermal_area {
struct mlxsw_thermal_module *tz_gearbox_arr;
u8 tz_gearbox_num;
u8 slot_index;
bool active;
};
struct mlxsw_thermal {
......@@ -913,6 +914,64 @@ mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal,
kfree(area->tz_gearbox_arr);
}
static void
mlxsw_thermal_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index,
void *priv)
{
struct mlxsw_thermal *thermal = priv;
struct mlxsw_thermal_area *linecard;
int err;
linecard = &thermal->line_cards[slot_index];
if (linecard->active)
return;
linecard->slot_index = slot_index;
err = mlxsw_thermal_modules_init(thermal->bus_info->dev, thermal->core,
thermal, linecard);
if (err) {
dev_err(thermal->bus_info->dev, "Failed to configure thermal objects for line card modules in slot %d\n",
slot_index);
return;
}
err = mlxsw_thermal_gearboxes_init(thermal->bus_info->dev,
thermal->core, thermal, linecard);
if (err) {
dev_err(thermal->bus_info->dev, "Failed to configure thermal objects for line card gearboxes in slot %d\n",
slot_index);
goto err_thermal_linecard_gearboxes_init;
}
linecard->active = true;
return;
err_thermal_linecard_gearboxes_init:
mlxsw_thermal_modules_fini(thermal, linecard);
}
static void
mlxsw_thermal_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index,
void *priv)
{
struct mlxsw_thermal *thermal = priv;
struct mlxsw_thermal_area *linecard;
linecard = &thermal->line_cards[slot_index];
if (!linecard->active)
return;
linecard->active = false;
mlxsw_thermal_gearboxes_fini(thermal, linecard);
mlxsw_thermal_modules_fini(thermal, linecard);
}
static struct mlxsw_linecards_event_ops mlxsw_thermal_event_ops = {
.got_active = mlxsw_thermal_got_active,
.got_inactive = mlxsw_thermal_got_inactive,
};
int mlxsw_thermal_init(struct mlxsw_core *core,
const struct mlxsw_bus_info *bus_info,
struct mlxsw_thermal **p_thermal)
......@@ -1018,14 +1077,25 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
if (err)
goto err_thermal_gearboxes_init;
err = mlxsw_linecards_event_ops_register(core,
&mlxsw_thermal_event_ops,
thermal);
if (err)
goto err_linecards_event_ops_register;
err = thermal_zone_device_enable(thermal->tzdev);
if (err)
goto err_thermal_zone_device_enable;
thermal->line_cards[0].active = true;
*p_thermal = thermal;
return 0;
err_thermal_zone_device_enable:
mlxsw_linecards_event_ops_unregister(thermal->core,
&mlxsw_thermal_event_ops,
thermal);
err_linecards_event_ops_register:
mlxsw_thermal_gearboxes_fini(thermal, &thermal->line_cards[0]);
err_thermal_gearboxes_init:
mlxsw_thermal_modules_fini(thermal, &thermal->line_cards[0]);
......@@ -1049,6 +1119,10 @@ void mlxsw_thermal_fini(struct mlxsw_thermal *thermal)
{
int i;
thermal->line_cards[0].active = false;
mlxsw_linecards_event_ops_unregister(thermal->core,
&mlxsw_thermal_event_ops,
thermal);
mlxsw_thermal_gearboxes_fini(thermal, &thermal->line_cards[0]);
mlxsw_thermal_modules_fini(thermal, &thermal->line_cards[0]);
if (thermal->tzdev) {
......
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