]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
mlxsw: core_linecards: Introduce per line card auxiliary device
authorJiri Pirko <jiri@nvidia.com>
Mon, 25 Jul 2022 08:29:17 +0000 (10:29 +0200)
committerJakub Kicinski <kuba@kernel.org>
Tue, 26 Jul 2022 20:50:51 +0000 (13:50 -0700)
In order to be eventually able to expose line card gearbox version and
possibility to flash FW, model the line card as a separate device on
auxiliary bus.

Add the auxiliary device for provisioned line card in order to be able
to expose provisioned line card info over devlink dev info. When the
line card becomes active, there may be other additional info added to
the output.

Signed-off-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/mellanox/mlxsw/Kconfig
drivers/net/ethernet/mellanox/mlxsw/Makefile
drivers/net/ethernet/mellanox/mlxsw/core.c
drivers/net/ethernet/mellanox/mlxsw/core.h
drivers/net/ethernet/mellanox/mlxsw/core_linecard_dev.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlxsw/core_linecards.c

index 4683312861ac1a9626fee25d3a3393e3042c895f..a510bf2cff2f61f4675ea3d9b7198e33b5cfc6c6 100644 (file)
@@ -7,6 +7,7 @@ config MLXSW_CORE
        tristate "Mellanox Technologies Switch ASICs support"
        select NET_DEVLINK
        select MLXFW
+       select AUXILIARY_BUS
        help
          This driver supports Mellanox Technologies Switch ASICs family.
 
index c2d6d64ffe4b8df1c7ece46e035cc1aca711505b..3ca9fce759eac3360a5e018161fce1836eafb3c6 100644 (file)
@@ -2,7 +2,7 @@
 obj-$(CONFIG_MLXSW_CORE)       += mlxsw_core.o
 mlxsw_core-objs                        := core.o core_acl_flex_keys.o \
                                   core_acl_flex_actions.o core_env.o \
-                                  core_linecards.o
+                                  core_linecards.o core_linecard_dev.o
 mlxsw_core-$(CONFIG_MLXSW_CORE_HWMON) += core_hwmon.o
 mlxsw_core-$(CONFIG_MLXSW_CORE_THERMAL) += core_thermal.o
 obj-$(CONFIG_MLXSW_PCI)                += mlxsw_pci.o
index 1b61bc8f59a2c40f253a4c7404e6c968d10cfc4d..1c8b72faf9e2118006294cf748dd943b2f56d6cf 100644 (file)
@@ -3334,9 +3334,15 @@ static int __init mlxsw_core_module_init(void)
 {
        int err;
 
+       err = mlxsw_linecard_driver_register();
+       if (err)
+               return err;
+
        mlxsw_wq = alloc_workqueue(mlxsw_core_driver_name, 0, 0);
-       if (!mlxsw_wq)
-               return -ENOMEM;
+       if (!mlxsw_wq) {
+               err = -ENOMEM;
+               goto err_alloc_workqueue;
+       }
        mlxsw_owq = alloc_ordered_workqueue("%s_ordered", 0,
                                            mlxsw_core_driver_name);
        if (!mlxsw_owq) {
@@ -3347,6 +3353,8 @@ static int __init mlxsw_core_module_init(void)
 
 err_alloc_ordered_workqueue:
        destroy_workqueue(mlxsw_wq);
+err_alloc_workqueue:
+       mlxsw_linecard_driver_unregister();
        return err;
 }
 
@@ -3354,6 +3362,7 @@ static void __exit mlxsw_core_module_exit(void)
 {
        destroy_workqueue(mlxsw_owq);
        destroy_workqueue(mlxsw_wq);
+       mlxsw_linecard_driver_unregister();
 }
 
 module_init(mlxsw_core_module_init);
index 9d2e8a8d3a7567d30c29d4ef7212f19083c4e0a2..5fe90438cca5e67f37411cb0239d7b03474a8040 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/skbuff.h>
 #include <linux/workqueue.h>
 #include <linux/net_namespace.h>
+#include <linux/auxiliary_bus.h>
 #include <net/devlink.h>
 
 #include "trap.h"
@@ -563,6 +564,8 @@ enum mlxsw_linecard_status_event_type {
        MLXSW_LINECARD_STATUS_EVENT_TYPE_UNPROVISION,
 };
 
+struct mlxsw_linecard_bdev;
+
 struct mlxsw_linecard {
        u8 slot_index;
        struct mlxsw_linecards *linecards;
@@ -577,6 +580,7 @@ struct mlxsw_linecard {
           active:1;
        u16 hw_revision;
        u16 ini_version;
+       struct mlxsw_linecard_bdev *bdev;
 };
 
 struct mlxsw_linecard_types_info;
@@ -616,4 +620,10 @@ void mlxsw_linecards_event_ops_unregister(struct mlxsw_core *mlxsw_core,
                                          struct mlxsw_linecards_event_ops *ops,
                                          void *priv);
 
+int mlxsw_linecard_bdev_add(struct mlxsw_linecard *linecard);
+void mlxsw_linecard_bdev_del(struct mlxsw_linecard *linecard);
+
+int mlxsw_linecard_driver_register(void);
+void mlxsw_linecard_driver_unregister(void);
+
 #endif
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_linecard_dev.c b/drivers/net/ethernet/mellanox/mlxsw/core_linecard_dev.c
new file mode 100644 (file)
index 0000000..b1fa9f6
--- /dev/null
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/* Copyright (c) 2022 NVIDIA Corporation and Mellanox Technologies. All rights reserved */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/auxiliary_bus.h>
+#include <linux/idr.h>
+#include <linux/gfp.h>
+#include <linux/slab.h>
+#include <net/devlink.h>
+#include "core.h"
+
+#define MLXSW_LINECARD_DEV_ID_NAME "lc"
+
+struct mlxsw_linecard_dev {
+       struct mlxsw_linecard *linecard;
+};
+
+struct mlxsw_linecard_bdev {
+       struct auxiliary_device adev;
+       struct mlxsw_linecard *linecard;
+       struct mlxsw_linecard_dev *linecard_dev;
+};
+
+static DEFINE_IDA(mlxsw_linecard_bdev_ida);
+
+static int mlxsw_linecard_bdev_id_alloc(void)
+{
+       return ida_alloc(&mlxsw_linecard_bdev_ida, GFP_KERNEL);
+}
+
+static void mlxsw_linecard_bdev_id_free(int id)
+{
+       ida_free(&mlxsw_linecard_bdev_ida, id);
+}
+
+static void mlxsw_linecard_bdev_release(struct device *device)
+{
+       struct auxiliary_device *adev =
+                       container_of(device, struct auxiliary_device, dev);
+       struct mlxsw_linecard_bdev *linecard_bdev =
+                       container_of(adev, struct mlxsw_linecard_bdev, adev);
+
+       mlxsw_linecard_bdev_id_free(adev->id);
+       kfree(linecard_bdev);
+}
+
+int mlxsw_linecard_bdev_add(struct mlxsw_linecard *linecard)
+{
+       struct mlxsw_linecard_bdev *linecard_bdev;
+       int err;
+       int id;
+
+       id = mlxsw_linecard_bdev_id_alloc();
+       if (id < 0)
+               return id;
+
+       linecard_bdev = kzalloc(sizeof(*linecard_bdev), GFP_KERNEL);
+       if (!linecard_bdev) {
+               mlxsw_linecard_bdev_id_free(id);
+               return -ENOMEM;
+       }
+       linecard_bdev->adev.id = id;
+       linecard_bdev->adev.name = MLXSW_LINECARD_DEV_ID_NAME;
+       linecard_bdev->adev.dev.release = mlxsw_linecard_bdev_release;
+       linecard_bdev->adev.dev.parent = linecard->linecards->bus_info->dev;
+       linecard_bdev->linecard = linecard;
+
+       err = auxiliary_device_init(&linecard_bdev->adev);
+       if (err) {
+               mlxsw_linecard_bdev_id_free(id);
+               kfree(linecard_bdev);
+               return err;
+       }
+
+       err = auxiliary_device_add(&linecard_bdev->adev);
+       if (err) {
+               auxiliary_device_uninit(&linecard_bdev->adev);
+               return err;
+       }
+
+       linecard->bdev = linecard_bdev;
+       return 0;
+}
+
+void mlxsw_linecard_bdev_del(struct mlxsw_linecard *linecard)
+{
+       struct mlxsw_linecard_bdev *linecard_bdev = linecard->bdev;
+
+       if (!linecard_bdev)
+               /* Unprovisioned line cards do not have an auxiliary device. */
+               return;
+       auxiliary_device_delete(&linecard_bdev->adev);
+       auxiliary_device_uninit(&linecard_bdev->adev);
+       linecard->bdev = NULL;
+}
+
+static const struct devlink_ops mlxsw_linecard_dev_devlink_ops = {
+};
+
+static int mlxsw_linecard_bdev_probe(struct auxiliary_device *adev,
+                                    const struct auxiliary_device_id *id)
+{
+       struct mlxsw_linecard_bdev *linecard_bdev =
+                       container_of(adev, struct mlxsw_linecard_bdev, adev);
+       struct mlxsw_linecard *linecard = linecard_bdev->linecard;
+       struct mlxsw_linecard_dev *linecard_dev;
+       struct devlink *devlink;
+
+       devlink = devlink_alloc(&mlxsw_linecard_dev_devlink_ops,
+                               sizeof(*linecard_dev), &adev->dev);
+       if (!devlink)
+               return -ENOMEM;
+       linecard_dev = devlink_priv(devlink);
+       linecard_dev->linecard = linecard_bdev->linecard;
+       linecard_bdev->linecard_dev = linecard_dev;
+
+       devlink_register(devlink);
+       devlink_linecard_nested_dl_set(linecard->devlink_linecard, devlink);
+       return 0;
+}
+
+static void mlxsw_linecard_bdev_remove(struct auxiliary_device *adev)
+{
+       struct mlxsw_linecard_bdev *linecard_bdev =
+                       container_of(adev, struct mlxsw_linecard_bdev, adev);
+       struct devlink *devlink = priv_to_devlink(linecard_bdev->linecard_dev);
+       struct mlxsw_linecard *linecard = linecard_bdev->linecard;
+
+       devlink_linecard_nested_dl_set(linecard->devlink_linecard, NULL);
+       devlink_unregister(devlink);
+       devlink_free(devlink);
+}
+
+static const struct auxiliary_device_id mlxsw_linecard_bdev_id_table[] = {
+       { .name = KBUILD_MODNAME "." MLXSW_LINECARD_DEV_ID_NAME },
+       {},
+};
+
+MODULE_DEVICE_TABLE(auxiliary, mlxsw_linecard_bdev_id_table);
+
+static struct auxiliary_driver mlxsw_linecard_driver = {
+       .name = MLXSW_LINECARD_DEV_ID_NAME,
+       .probe = mlxsw_linecard_bdev_probe,
+       .remove = mlxsw_linecard_bdev_remove,
+       .id_table = mlxsw_linecard_bdev_id_table,
+};
+
+int mlxsw_linecard_driver_register(void)
+{
+       return auxiliary_driver_register(&mlxsw_linecard_driver);
+}
+
+void mlxsw_linecard_driver_unregister(void)
+{
+       auxiliary_driver_unregister(&mlxsw_linecard_driver);
+}
index 5c9869dcf674a3ca1d1ee180d51827aeaffaec54..43696d8badcac49036d3cef7679a5a4001bbb12e 100644 (file)
@@ -232,6 +232,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,
@@ -252,6 +253,14 @@ mlxsw_linecard_provision_set(struct mlxsw_linecard *linecard, u8 card_type,
        linecard->provisioned = true;
        linecard->hw_revision = hw_revision;
        linecard->ini_version = ini_version;
+
+       err = mlxsw_linecard_bdev_add(linecard);
+       if (err) {
+               linecard->provisioned = false;
+               mlxsw_linecard_provision_fail(linecard);
+               return err;
+       }
+
        devlink_linecard_provision_set(linecard->devlink_linecard, type);
        return 0;
 }
@@ -260,6 +269,7 @@ static void mlxsw_linecard_provision_clear(struct mlxsw_linecard *linecard)
 {
        mlxsw_linecard_status_event_done(linecard,
                                         MLXSW_LINECARD_STATUS_EVENT_TYPE_UNPROVISION);
+       mlxsw_linecard_bdev_del(linecard);
        linecard->provisioned = false;
        devlink_linecard_provision_clear(linecard->devlink_linecard);
 }
@@ -885,6 +895,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_bdev_del(linecard);
        devlink_linecard_destroy(linecard->devlink_linecard);
        mutex_destroy(&linecard->lock);
 }