diff --git a/Documentation/networking/devlink/mlxsw.rst b/Documentation/networking/devlink/mlxsw.rst index da1fbb265a11..0af345680510 100644 --- a/Documentation/networking/devlink/mlxsw.rst +++ b/Documentation/networking/devlink/mlxsw.rst @@ -76,6 +76,21 @@ The ``mlxsw`` driver reports the following versions for line cards - running - Version of line card INI loaded +Line card device info versions +============================== + +The ``mlxsw`` driver reports the following versions for line card devices + +.. list-table:: devlink line card device info versions implemented + :widths: 5 5 90 + + * - Name + - Type + - Description + * - ``fw.version`` + - running + - Three digit firmware version + Driver-specific Traps ===================== diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c index 42fe93ac629d..2abd31a62776 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c @@ -87,13 +87,31 @@ static const char *mlxsw_linecard_type_name(struct mlxsw_linecard *linecard) return linecard->name; } +struct mlxsw_linecard_device_info { + u16 fw_major; + u16 fw_minor; + u16 fw_sub_minor; +}; + struct mlxsw_linecard_device { struct list_head list; u8 index; struct mlxsw_linecard *linecard; struct devlink_linecard_device *devlink_device; + struct mlxsw_linecard_device_info info; }; +static struct mlxsw_linecard_device * +mlxsw_linecard_device_lookup(struct mlxsw_linecard *linecard, u8 index) +{ + struct mlxsw_linecard_device *device; + + list_for_each_entry(device, &linecard->device_list, list) + if (device->index == index) + return device; + return NULL; +} + static int mlxsw_linecard_device_attach(struct mlxsw_core *mlxsw_core, struct mlxsw_linecard *linecard, u8 device_index, bool flash_owner) @@ -108,7 +126,7 @@ static int mlxsw_linecard_device_attach(struct mlxsw_core *mlxsw_core, device->linecard = linecard; device->devlink_device = devlink_linecard_device_create(linecard->devlink_linecard, - device_index, NULL); + device_index, device); if (IS_ERR(device->devlink_device)) { err = PTR_ERR(device->devlink_device); goto err_devlink_linecard_device_attach; @@ -177,6 +195,77 @@ rollback: return err; } +static void mlxsw_linecard_device_update(struct mlxsw_linecard *linecard, + u8 device_index, + struct mlxsw_linecard_device_info *info) +{ + struct mlxsw_linecard_device *device; + + device = mlxsw_linecard_device_lookup(linecard, device_index); + if (!device) + return; + device->info = *info; +} + +static int mlxsw_linecard_devices_update(struct mlxsw_linecard *linecard) +{ + struct mlxsw_core *mlxsw_core = linecard->linecards->mlxsw_core; + u8 msg_seq = 0; + + do { + struct mlxsw_linecard_device_info info; + char mddq_pl[MLXSW_REG_MDDQ_LEN]; + bool data_valid; + u8 device_index; + int err; + + mlxsw_reg_mddq_device_info_pack(mddq_pl, linecard->slot_index, + msg_seq); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mddq), mddq_pl); + if (err) + return err; + mlxsw_reg_mddq_device_info_unpack(mddq_pl, &msg_seq, + &data_valid, NULL, + &device_index, + &info.fw_major, + &info.fw_minor, + &info.fw_sub_minor); + if (!data_valid) + break; + mlxsw_linecard_device_update(linecard, device_index, &info); + } while (msg_seq); + + return 0; +} + +static int +mlxsw_linecard_device_info_get(struct devlink_linecard_device *devlink_linecard_device, + void *priv, struct devlink_info_req *req, + struct netlink_ext_ack *extack) +{ + struct mlxsw_linecard_device *device = priv; + struct mlxsw_linecard_device_info *info; + struct mlxsw_linecard *linecard; + char buf[32]; + + linecard = device->linecard; + mutex_lock(&linecard->lock); + if (!linecard->active) { + mutex_unlock(&linecard->lock); + return 0; + } + + info = &device->info; + + sprintf(buf, "%u.%u.%u", info->fw_major, info->fw_minor, + info->fw_sub_minor); + mutex_unlock(&linecard->lock); + + return devlink_info_version_running_put(req, + DEVLINK_INFO_VERSION_GENERIC_FW, + buf); +} + static void mlxsw_linecard_provision_fail(struct mlxsw_linecard *linecard) { linecard->provisioned = false; @@ -390,11 +479,18 @@ static int mlxsw_linecard_ready_clear(struct mlxsw_linecard *linecard) return 0; } -static void mlxsw_linecard_active_set(struct mlxsw_linecard *linecard) +static int mlxsw_linecard_active_set(struct mlxsw_linecard *linecard) { + int err; + + err = mlxsw_linecard_devices_update(linecard); + if (err) + return err; + mlxsw_linecard_active_ops_call(linecard); linecard->active = true; devlink_linecard_activate(linecard->devlink_linecard); + return 0; } static void mlxsw_linecard_active_clear(struct mlxsw_linecard *linecard) @@ -443,8 +539,11 @@ static int mlxsw_linecard_status_process(struct mlxsw_linecards *linecards, goto out; } - if (active && linecard->active != active) - mlxsw_linecard_active_set(linecard); + if (active && linecard->active != active) { + err = mlxsw_linecard_active_set(linecard); + if (err) + goto out; + } if (!active && linecard->active != active) mlxsw_linecard_active_clear(linecard); @@ -872,6 +971,7 @@ static const struct devlink_linecard_ops mlxsw_linecard_ops = { .types_count = mlxsw_linecard_types_count, .types_get = mlxsw_linecard_types_get, .info_get = mlxsw_linecard_info_get, + .device_info_get = mlxsw_linecard_device_info_get, }; struct mlxsw_linecard_status_event {