Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /* Copyright (c) 2022 NVIDIA Corporation and Mellanox Technologies. All rights reserved */
0003 
0004 #include <linux/kernel.h>
0005 #include <linux/module.h>
0006 #include <linux/err.h>
0007 #include <linux/types.h>
0008 #include <linux/auxiliary_bus.h>
0009 #include <linux/idr.h>
0010 #include <linux/gfp.h>
0011 #include <linux/slab.h>
0012 #include <net/devlink.h>
0013 #include "core.h"
0014 
0015 #define MLXSW_LINECARD_DEV_ID_NAME "lc"
0016 
0017 struct mlxsw_linecard_dev {
0018     struct mlxsw_linecard *linecard;
0019 };
0020 
0021 struct mlxsw_linecard_bdev {
0022     struct auxiliary_device adev;
0023     struct mlxsw_linecard *linecard;
0024     struct mlxsw_linecard_dev *linecard_dev;
0025 };
0026 
0027 static DEFINE_IDA(mlxsw_linecard_bdev_ida);
0028 
0029 static int mlxsw_linecard_bdev_id_alloc(void)
0030 {
0031     return ida_alloc(&mlxsw_linecard_bdev_ida, GFP_KERNEL);
0032 }
0033 
0034 static void mlxsw_linecard_bdev_id_free(int id)
0035 {
0036     ida_free(&mlxsw_linecard_bdev_ida, id);
0037 }
0038 
0039 static void mlxsw_linecard_bdev_release(struct device *device)
0040 {
0041     struct auxiliary_device *adev =
0042             container_of(device, struct auxiliary_device, dev);
0043     struct mlxsw_linecard_bdev *linecard_bdev =
0044             container_of(adev, struct mlxsw_linecard_bdev, adev);
0045 
0046     mlxsw_linecard_bdev_id_free(adev->id);
0047     kfree(linecard_bdev);
0048 }
0049 
0050 int mlxsw_linecard_bdev_add(struct mlxsw_linecard *linecard)
0051 {
0052     struct mlxsw_linecard_bdev *linecard_bdev;
0053     int err;
0054     int id;
0055 
0056     id = mlxsw_linecard_bdev_id_alloc();
0057     if (id < 0)
0058         return id;
0059 
0060     linecard_bdev = kzalloc(sizeof(*linecard_bdev), GFP_KERNEL);
0061     if (!linecard_bdev) {
0062         mlxsw_linecard_bdev_id_free(id);
0063         return -ENOMEM;
0064     }
0065     linecard_bdev->adev.id = id;
0066     linecard_bdev->adev.name = MLXSW_LINECARD_DEV_ID_NAME;
0067     linecard_bdev->adev.dev.release = mlxsw_linecard_bdev_release;
0068     linecard_bdev->adev.dev.parent = linecard->linecards->bus_info->dev;
0069     linecard_bdev->linecard = linecard;
0070 
0071     err = auxiliary_device_init(&linecard_bdev->adev);
0072     if (err) {
0073         mlxsw_linecard_bdev_id_free(id);
0074         kfree(linecard_bdev);
0075         return err;
0076     }
0077 
0078     err = auxiliary_device_add(&linecard_bdev->adev);
0079     if (err) {
0080         auxiliary_device_uninit(&linecard_bdev->adev);
0081         return err;
0082     }
0083 
0084     linecard->bdev = linecard_bdev;
0085     return 0;
0086 }
0087 
0088 void mlxsw_linecard_bdev_del(struct mlxsw_linecard *linecard)
0089 {
0090     struct mlxsw_linecard_bdev *linecard_bdev = linecard->bdev;
0091 
0092     if (!linecard_bdev)
0093         /* Unprovisioned line cards do not have an auxiliary device. */
0094         return;
0095     auxiliary_device_delete(&linecard_bdev->adev);
0096     auxiliary_device_uninit(&linecard_bdev->adev);
0097     linecard->bdev = NULL;
0098 }
0099 
0100 static int mlxsw_linecard_dev_devlink_info_get(struct devlink *devlink,
0101                            struct devlink_info_req *req,
0102                            struct netlink_ext_ack *extack)
0103 {
0104     struct mlxsw_linecard_dev *linecard_dev = devlink_priv(devlink);
0105     struct mlxsw_linecard *linecard = linecard_dev->linecard;
0106 
0107     return mlxsw_linecard_devlink_info_get(linecard, req, extack);
0108 }
0109 
0110 static int
0111 mlxsw_linecard_dev_devlink_flash_update(struct devlink *devlink,
0112                     struct devlink_flash_update_params *params,
0113                     struct netlink_ext_ack *extack)
0114 {
0115     struct mlxsw_linecard_dev *linecard_dev = devlink_priv(devlink);
0116     struct mlxsw_linecard *linecard = linecard_dev->linecard;
0117 
0118     return mlxsw_linecard_flash_update(devlink, linecard,
0119                        params->fw, extack);
0120 }
0121 
0122 static const struct devlink_ops mlxsw_linecard_dev_devlink_ops = {
0123     .info_get           = mlxsw_linecard_dev_devlink_info_get,
0124     .flash_update           = mlxsw_linecard_dev_devlink_flash_update,
0125 };
0126 
0127 static int mlxsw_linecard_bdev_probe(struct auxiliary_device *adev,
0128                      const struct auxiliary_device_id *id)
0129 {
0130     struct mlxsw_linecard_bdev *linecard_bdev =
0131             container_of(adev, struct mlxsw_linecard_bdev, adev);
0132     struct mlxsw_linecard *linecard = linecard_bdev->linecard;
0133     struct mlxsw_linecard_dev *linecard_dev;
0134     struct devlink *devlink;
0135 
0136     devlink = devlink_alloc(&mlxsw_linecard_dev_devlink_ops,
0137                 sizeof(*linecard_dev), &adev->dev);
0138     if (!devlink)
0139         return -ENOMEM;
0140     linecard_dev = devlink_priv(devlink);
0141     linecard_dev->linecard = linecard_bdev->linecard;
0142     linecard_bdev->linecard_dev = linecard_dev;
0143 
0144     devlink_register(devlink);
0145     devlink_linecard_nested_dl_set(linecard->devlink_linecard, devlink);
0146     return 0;
0147 }
0148 
0149 static void mlxsw_linecard_bdev_remove(struct auxiliary_device *adev)
0150 {
0151     struct mlxsw_linecard_bdev *linecard_bdev =
0152             container_of(adev, struct mlxsw_linecard_bdev, adev);
0153     struct devlink *devlink = priv_to_devlink(linecard_bdev->linecard_dev);
0154     struct mlxsw_linecard *linecard = linecard_bdev->linecard;
0155 
0156     devlink_linecard_nested_dl_set(linecard->devlink_linecard, NULL);
0157     devlink_unregister(devlink);
0158     devlink_free(devlink);
0159 }
0160 
0161 static const struct auxiliary_device_id mlxsw_linecard_bdev_id_table[] = {
0162     { .name = KBUILD_MODNAME "." MLXSW_LINECARD_DEV_ID_NAME },
0163     {},
0164 };
0165 
0166 MODULE_DEVICE_TABLE(auxiliary, mlxsw_linecard_bdev_id_table);
0167 
0168 static struct auxiliary_driver mlxsw_linecard_driver = {
0169     .name = MLXSW_LINECARD_DEV_ID_NAME,
0170     .probe = mlxsw_linecard_bdev_probe,
0171     .remove = mlxsw_linecard_bdev_remove,
0172     .id_table = mlxsw_linecard_bdev_id_table,
0173 };
0174 
0175 int mlxsw_linecard_driver_register(void)
0176 {
0177     return auxiliary_driver_register(&mlxsw_linecard_driver);
0178 }
0179 
0180 void mlxsw_linecard_driver_unregister(void)
0181 {
0182     auxiliary_driver_unregister(&mlxsw_linecard_driver);
0183 }