File Index
Files and directories
Sign in
FILE

core_linecard_dev.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlxsw/core_linecard_dev.c C
  1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
  2/* Copyright (c) 2022 NVIDIA Corporation and Mellanox Technologies. All rights reserved */
  3
  4#include <linux/kernel.h>
  5#include <linux/module.h>
  6#include <linux/err.h>
  7#include <linux/types.h>
  8#include <linux/auxiliary_bus.h>
  9#include <linux/idr.h>
 10#include <linux/gfp.h>
 11#include <linux/slab.h>
 12#include <net/devlink.h>
 13#include "core.h"
 14
 15#define MLXSW_LINECARD_DEV_ID_NAME "lc"
 16
 17struct mlxsw_linecard_dev {
 18	struct mlxsw_linecard *linecard;
 19};
 20
 21struct mlxsw_linecard_bdev {
 22	struct auxiliary_device adev;
 23	struct mlxsw_linecard *linecard;
 24	struct mlxsw_linecard_dev *linecard_dev;
 25};
 26
 27static DEFINE_IDA(mlxsw_linecard_bdev_ida);
 28
 29static int mlxsw_linecard_bdev_id_alloc(void)
 30{
 31	return ida_alloc(&mlxsw_linecard_bdev_ida, GFP_KERNEL);
 32}
 33
 34static void mlxsw_linecard_bdev_id_free(int id)
 35{
 36	ida_free(&mlxsw_linecard_bdev_ida, id);
 37}
 38
 39static void mlxsw_linecard_bdev_release(struct device *device)
 40{
 41	struct auxiliary_device *adev =
 42			container_of(device, struct auxiliary_device, dev);
 43	struct mlxsw_linecard_bdev *linecard_bdev =
 44			container_of(adev, struct mlxsw_linecard_bdev, adev);
 45
 46	mlxsw_linecard_bdev_id_free(adev->id);
 47	kfree(linecard_bdev);
 48}
 49
 50int mlxsw_linecard_bdev_add(struct mlxsw_linecard *linecard)
 51{
 52	struct mlxsw_linecard_bdev *linecard_bdev;
 53	int err;
 54	int id;
 55
 56	id = mlxsw_linecard_bdev_id_alloc();
 57	if (id < 0)
 58		return id;
 59
 60	linecard_bdev = kzalloc(sizeof(*linecard_bdev), GFP_KERNEL);
 61	if (!linecard_bdev) {
 62		mlxsw_linecard_bdev_id_free(id);
 63		return -ENOMEM;
 64	}
 65	linecard_bdev->adev.id = id;
 66	linecard_bdev->adev.name = MLXSW_LINECARD_DEV_ID_NAME;
 67	linecard_bdev->adev.dev.release = mlxsw_linecard_bdev_release;
 68	linecard_bdev->adev.dev.parent = linecard->linecards->bus_info->dev;
 69	linecard_bdev->linecard = linecard;
 70
 71	err = auxiliary_device_init(&linecard_bdev->adev);
 72	if (err) {
 73		mlxsw_linecard_bdev_id_free(id);
 74		kfree(linecard_bdev);
 75		return err;
 76	}
 77
 78	err = auxiliary_device_add(&linecard_bdev->adev);
 79	if (err) {
 80		auxiliary_device_uninit(&linecard_bdev->adev);
 81		return err;
 82	}
 83
 84	linecard->bdev = linecard_bdev;
 85	return 0;
 86}
 87
 88void mlxsw_linecard_bdev_del(struct mlxsw_linecard *linecard)
 89{
 90	struct mlxsw_linecard_bdev *linecard_bdev = linecard->bdev;
 91
 92	if (!linecard_bdev)
 93		/* Unprovisioned line cards do not have an auxiliary device. */
 94		return;
 95	auxiliary_device_delete(&linecard_bdev->adev);
 96	auxiliary_device_uninit(&linecard_bdev->adev);
 97	linecard->bdev = NULL;
 98}
 99
100static int mlxsw_linecard_dev_devlink_info_get(struct devlink *devlink,
101					       struct devlink_info_req *req,
102					       struct netlink_ext_ack *extack)
103{
104	struct mlxsw_linecard_dev *linecard_dev = devlink_priv(devlink);
105	struct mlxsw_linecard *linecard = linecard_dev->linecard;
106
107	return mlxsw_linecard_devlink_info_get(linecard, req, extack);
108}
109
110static int
111mlxsw_linecard_dev_devlink_flash_update(struct devlink *devlink,
112					struct devlink_flash_update_params *params,
113					struct netlink_ext_ack *extack)
114{
115	struct mlxsw_linecard_dev *linecard_dev = devlink_priv(devlink);
116	struct mlxsw_linecard *linecard = linecard_dev->linecard;
117
118	return mlxsw_linecard_flash_update(devlink, linecard,
119					   params->fw, extack);
120}
121
122static const struct devlink_ops mlxsw_linecard_dev_devlink_ops = {
123	.info_get			= mlxsw_linecard_dev_devlink_info_get,
124	.flash_update			= mlxsw_linecard_dev_devlink_flash_update,
125};
126
127static int mlxsw_linecard_bdev_probe(struct auxiliary_device *adev,
128				     const struct auxiliary_device_id *id)
129{
130	struct mlxsw_linecard_bdev *linecard_bdev =
131			container_of(adev, struct mlxsw_linecard_bdev, adev);
132	struct mlxsw_linecard *linecard = linecard_bdev->linecard;
133	struct mlxsw_linecard_dev *linecard_dev;
134	struct devlink *devlink;
135	int err;
136
137	devlink = devlink_alloc(&mlxsw_linecard_dev_devlink_ops,
138				sizeof(*linecard_dev), &adev->dev);
139	if (!devlink)
140		return -ENOMEM;
141	linecard_dev = devlink_priv(devlink);
142	linecard_dev->linecard = linecard_bdev->linecard;
143	linecard_bdev->linecard_dev = linecard_dev;
144
145	err = devlink_linecard_nested_dl_set(linecard->devlink_linecard, devlink);
146	if (err) {
147		devlink_free(devlink);
148		return err;
149	}
150	devlink_register(devlink);
151	return 0;
152}
153
154static void mlxsw_linecard_bdev_remove(struct auxiliary_device *adev)
155{
156	struct mlxsw_linecard_bdev *linecard_bdev =
157			container_of(adev, struct mlxsw_linecard_bdev, adev);
158	struct devlink *devlink = priv_to_devlink(linecard_bdev->linecard_dev);
159
160	devlink_unregister(devlink);
161	devlink_free(devlink);
162}
163
164static const struct auxiliary_device_id mlxsw_linecard_bdev_id_table[] = {
165	{ .name = KBUILD_MODNAME "." MLXSW_LINECARD_DEV_ID_NAME },
166	{},
167};
168
169MODULE_DEVICE_TABLE(auxiliary, mlxsw_linecard_bdev_id_table);
170
171static struct auxiliary_driver mlxsw_linecard_driver = {
172	.name = MLXSW_LINECARD_DEV_ID_NAME,
173	.probe = mlxsw_linecard_bdev_probe,
174	.remove = mlxsw_linecard_bdev_remove,
175	.id_table = mlxsw_linecard_bdev_id_table,
176};
177
178int mlxsw_linecard_driver_register(void)
179{
180	return auxiliary_driver_register(&mlxsw_linecard_driver);
181}
182
183void mlxsw_linecard_driver_unregister(void)
184{
185	auxiliary_driver_unregister(&mlxsw_linecard_driver);
186}
~/ Read-only file preview.