0001
0002
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
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 }