aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Pirko <jiri@nvidia.com>2022-04-25 06:44:25 +0300
committerDavid S. Miller <davem@davemloft.net>2022-04-25 10:42:28 +0100
commit8e2e10f651129d6e270a0b9a8bd3aaf0aa3f06d4 (patch)
treeeec8fd9dd3566247f7ddfba48ae3c832375ca5f0
parentmlxsw: reg: Extend MDDQ by device_info (diff)
downloadlinux-dev-8e2e10f651129d6e270a0b9a8bd3aaf0aa3f06d4.tar.xz
linux-dev-8e2e10f651129d6e270a0b9a8bd3aaf0aa3f06d4.zip
mlxsw: core_linecards: Probe provisioned line cards for devices and attach them
In case the line card is provisioned, go over all possible existing devices (gearboxes) on it and attach them, so devlink core is aware of them. Signed-off-by: Jiri Pirko <jiri@nvidia.com> Signed-off-by: Ido Schimmel <idosch@nvidia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_linecards.c99
2 files changed, 100 insertions, 0 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h
index c2a891287047..d008282d7f2e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.h
@@ -581,6 +581,7 @@ struct mlxsw_linecard {
active:1;
u16 hw_revision;
u16 ini_version;
+ struct list_head device_list;
};
struct mlxsw_linecard_types_info;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c
index 5c9869dcf674..9dd8a56add4a 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c
@@ -87,11 +87,101 @@ static const char *mlxsw_linecard_type_name(struct mlxsw_linecard *linecard)
return linecard->name;
}
+struct mlxsw_linecard_device {
+ struct list_head list;
+ u8 index;
+ struct mlxsw_linecard *linecard;
+ struct devlink_linecard_device *devlink_device;
+};
+
+static int mlxsw_linecard_device_attach(struct mlxsw_core *mlxsw_core,
+ struct mlxsw_linecard *linecard,
+ u8 device_index, bool flash_owner)
+{
+ struct mlxsw_linecard_device *device;
+ int err;
+
+ device = kzalloc(sizeof(*device), GFP_KERNEL);
+ if (!device)
+ return -ENOMEM;
+ device->index = device_index;
+ device->linecard = linecard;
+
+ device->devlink_device = devlink_linecard_device_create(linecard->devlink_linecard,
+ device_index, NULL);
+ if (IS_ERR(device->devlink_device)) {
+ err = PTR_ERR(device->devlink_device);
+ goto err_devlink_linecard_device_attach;
+ }
+
+ list_add_tail(&device->list, &linecard->device_list);
+ return 0;
+
+err_devlink_linecard_device_attach:
+ kfree(device);
+ return err;
+}
+
+static void mlxsw_linecard_device_detach(struct mlxsw_core *mlxsw_core,
+ struct mlxsw_linecard *linecard,
+ struct mlxsw_linecard_device *device)
+{
+ list_del(&device->list);
+ devlink_linecard_device_destroy(linecard->devlink_linecard,
+ device->devlink_device);
+ kfree(device);
+}
+
+static void mlxsw_linecard_devices_detach(struct mlxsw_linecard *linecard)
+{
+ struct mlxsw_core *mlxsw_core = linecard->linecards->mlxsw_core;
+ struct mlxsw_linecard_device *device, *tmp;
+
+ list_for_each_entry_safe(device, tmp, &linecard->device_list, list)
+ mlxsw_linecard_device_detach(mlxsw_core, linecard, device);
+}
+
+static int mlxsw_linecard_devices_attach(struct mlxsw_linecard *linecard)
+{
+ struct mlxsw_core *mlxsw_core = linecard->linecards->mlxsw_core;
+ u8 msg_seq = 0;
+ int err;
+
+ do {
+ char mddq_pl[MLXSW_REG_MDDQ_LEN];
+ bool flash_owner;
+ bool data_valid;
+ u8 device_index;
+
+ 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, &flash_owner,
+ &device_index);
+ if (!data_valid)
+ break;
+ err = mlxsw_linecard_device_attach(mlxsw_core, linecard,
+ device_index, flash_owner);
+ if (err)
+ goto rollback;
+ } while (msg_seq);
+
+ return 0;
+
+rollback:
+ mlxsw_linecard_devices_detach(linecard);
+ return err;
+}
+
static void mlxsw_linecard_provision_fail(struct mlxsw_linecard *linecard)
{
linecard->provisioned = false;
linecard->ready = false;
linecard->active = false;
+ mlxsw_linecard_devices_detach(linecard);
devlink_linecard_provision_fail(linecard->devlink_linecard);
}
@@ -232,6 +322,7 @@ mlxsw_linecard_provision_set(struct mlxsw_linecard *linecard, u8 card_type,
{
struct mlxsw_linecards *linecards = linecard->linecards;
const char *type;
+ int err;
type = mlxsw_linecard_types_lookup(linecards, card_type);
mlxsw_linecard_status_event_done(linecard,
@@ -249,6 +340,11 @@ mlxsw_linecard_provision_set(struct mlxsw_linecard *linecard, u8 card_type,
return PTR_ERR(type);
}
}
+ err = mlxsw_linecard_devices_attach(linecard);
+ if (err) {
+ mlxsw_linecard_provision_fail(linecard);
+ return err;
+ }
linecard->provisioned = true;
linecard->hw_revision = hw_revision;
linecard->ini_version = ini_version;
@@ -261,6 +357,7 @@ static void mlxsw_linecard_provision_clear(struct mlxsw_linecard *linecard)
mlxsw_linecard_status_event_done(linecard,
MLXSW_LINECARD_STATUS_EVENT_TYPE_UNPROVISION);
linecard->provisioned = false;
+ mlxsw_linecard_devices_detach(linecard);
devlink_linecard_provision_clear(linecard->devlink_linecard);
}
@@ -840,6 +937,7 @@ static int mlxsw_linecard_init(struct mlxsw_core *mlxsw_core,
linecard->slot_index = slot_index;
linecard->linecards = linecards;
mutex_init(&linecard->lock);
+ INIT_LIST_HEAD(&linecard->device_list);
devlink_linecard = devlink_linecard_create(priv_to_devlink(mlxsw_core),
slot_index, &mlxsw_linecard_ops,
@@ -885,6 +983,7 @@ static void mlxsw_linecard_fini(struct mlxsw_core *mlxsw_core,
mlxsw_core_flush_owq();
if (linecard->active)
mlxsw_linecard_active_clear(linecard);
+ mlxsw_linecard_devices_detach(linecard);
devlink_linecard_destroy(linecard->devlink_linecard);
mutex_destroy(&linecard->lock);
}