From: Jiri Pirko <jiri@resnulli.us>
To: netdev@vger.kernel.org
Cc: davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com, horms@kernel.org, donald.hunter@gmail.com,
corbet@lwn.net, skhan@linuxfoundation.org, saeedm@nvidia.com,
leon@kernel.org, tariqt@nvidia.com, mbloch@nvidia.com,
przemyslaw.kitszel@intel.com, mschmidt@redhat.com,
andrew+netdev@lunn.ch, rostedt@goodmis.org, mhiramat@kernel.org,
mathieu.desnoyers@efficios.com, chuck.lever@oracle.com,
matttbe@kernel.org, cjubran@nvidia.com, daniel.zahka@gmail.com,
linux-doc@vger.kernel.org, linux-rdma@vger.kernel.org,
linux-trace-kernel@vger.kernel.org
Subject: [PATCH net-next v4 11/13] devlink: introduce shared devlink instance for PFs on same chip
Date: Thu, 12 Mar 2026 11:04:05 +0100 [thread overview]
Message-ID: <20260312100407.551173-12-jiri@resnulli.us> (raw)
In-Reply-To: <20260312100407.551173-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@nvidia.com>
Multiple PFs may reside on the same physical chip, running a single
firmware. Some of the resources and configurations may be shared among
these PFs. Currently, there is no good object to pin the configuration
knobs on.
Introduce a shared devlink instance, instantiated upon probe of
the first PF and removed during remove of the last PF. The shared
devlink instance is not backed by any device device, as there is
no PCI device related to it.
The implementation uses reference counting to manage the lifecycle:
each PF that probes calls devlink_shd_get() to get or create
the shared instance, and calls devlink_shd_put() when it removes.
The shared instance is automatically destroyed when the last PF removes.
Example:
pci/0000:08:00.0: index 0
nested_devlink:
auxiliary/mlx5_core.eth.0
devlink_index/1: index 1
nested_devlink:
pci/0000:08:00.0
pci/0000:08:00.1
auxiliary/mlx5_core.eth.0: index 2
pci/0000:08:00.1: index 3
nested_devlink:
auxiliary/mlx5_core.eth.1
auxiliary/mlx5_core.eth.1: index 4
Signed-off-by: Jiri Pirko <jiri@nvidia.com>
---
v2->v3:
- added __counter_by() for priv
- added *driver arg to devlink_shd_get()
- added ops, priv_size and driver pointer consistency check
v1->v2:
- s/err_kstrdup_id/err_devlink_free/
- fixed kernel-doc comment of devlink_shd_get()
- removed NULL arg check in devlink_shd_get/put()
---
include/net/devlink.h | 7 ++
net/devlink/Makefile | 2 +-
net/devlink/sh_dev.c | 161 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 169 insertions(+), 1 deletion(-)
create mode 100644 net/devlink/sh_dev.c
diff --git a/include/net/devlink.h b/include/net/devlink.h
index 45dec7067a8e..3038af6ec017 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -1647,6 +1647,13 @@ void devlink_register(struct devlink *devlink);
void devlink_unregister(struct devlink *devlink);
void devlink_free(struct devlink *devlink);
+struct devlink *devlink_shd_get(const char *id,
+ const struct devlink_ops *ops,
+ size_t priv_size,
+ const struct device_driver *driver);
+void devlink_shd_put(struct devlink *devlink);
+void *devlink_shd_get_priv(struct devlink *devlink);
+
/**
* struct devlink_port_ops - Port operations
* @port_split: Callback used to split the port into multiple ones.
diff --git a/net/devlink/Makefile b/net/devlink/Makefile
index 000da622116a..8f2adb5e5836 100644
--- a/net/devlink/Makefile
+++ b/net/devlink/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
obj-y := core.o netlink.o netlink_gen.o dev.o port.o sb.o dpipe.o \
- resource.o param.o region.o health.o trap.o rate.o linecard.o
+ resource.o param.o region.o health.o trap.o rate.o linecard.o sh_dev.o
diff --git a/net/devlink/sh_dev.c b/net/devlink/sh_dev.c
new file mode 100644
index 000000000000..85acce97e788
--- /dev/null
+++ b/net/devlink/sh_dev.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#include <net/devlink.h>
+
+#include "devl_internal.h"
+
+static LIST_HEAD(shd_list);
+static DEFINE_MUTEX(shd_mutex); /* Protects shd_list and shd->list */
+
+/* This structure represents a shared devlink instance,
+ * there is one created per identifier (e.g., serial number).
+ */
+struct devlink_shd {
+ struct list_head list; /* Node in shd list */
+ const char *id; /* Identifier string (e.g., serial number) */
+ refcount_t refcount; /* Reference count */
+ size_t priv_size; /* Size of driver private data */
+ char priv[] __aligned(NETDEV_ALIGN) __counted_by(priv_size);
+};
+
+static struct devlink_shd *devlink_shd_lookup(const char *id)
+{
+ struct devlink_shd *shd;
+
+ list_for_each_entry(shd, &shd_list, list) {
+ if (!strcmp(shd->id, id))
+ return shd;
+ }
+
+ return NULL;
+}
+
+static struct devlink_shd *devlink_shd_create(const char *id,
+ const struct devlink_ops *ops,
+ size_t priv_size,
+ const struct device_driver *driver)
+{
+ struct devlink_shd *shd;
+ struct devlink *devlink;
+
+ devlink = __devlink_alloc(ops, sizeof(struct devlink_shd) + priv_size,
+ &init_net, NULL, driver);
+ if (!devlink)
+ return NULL;
+ shd = devlink_priv(devlink);
+
+ shd->id = kstrdup(id, GFP_KERNEL);
+ if (!shd->id)
+ goto err_devlink_free;
+ shd->priv_size = priv_size;
+ refcount_set(&shd->refcount, 1);
+
+ devl_lock(devlink);
+ devl_register(devlink);
+ devl_unlock(devlink);
+
+ list_add_tail(&shd->list, &shd_list);
+
+ return shd;
+
+err_devlink_free:
+ devlink_free(devlink);
+ return NULL;
+}
+
+static void devlink_shd_destroy(struct devlink_shd *shd)
+{
+ struct devlink *devlink = priv_to_devlink(shd);
+
+ list_del(&shd->list);
+ devl_lock(devlink);
+ devl_unregister(devlink);
+ devl_unlock(devlink);
+ kfree(shd->id);
+ devlink_free(devlink);
+}
+
+/**
+ * devlink_shd_get - Get or create a shared devlink instance
+ * @id: Identifier string (e.g., serial number) for the shared instance
+ * @ops: Devlink operations structure
+ * @priv_size: Size of private data structure
+ * @driver: Driver associated with the shared devlink instance
+ *
+ * Get an existing shared devlink instance identified by @id, or create
+ * a new one if it doesn't exist. Return the devlink instance with a
+ * reference held. The caller must call devlink_shd_put() when done.
+ *
+ * All callers sharing the same @id must pass identical @ops, @priv_size
+ * and @driver. A mismatch triggers a warning and returns NULL.
+ *
+ * Return: Pointer to the shared devlink instance on success,
+ * NULL on failure
+ */
+struct devlink *devlink_shd_get(const char *id,
+ const struct devlink_ops *ops,
+ size_t priv_size,
+ const struct device_driver *driver)
+{
+ struct devlink *devlink;
+ struct devlink_shd *shd;
+
+ mutex_lock(&shd_mutex);
+
+ shd = devlink_shd_lookup(id);
+ if (!shd) {
+ shd = devlink_shd_create(id, ops, priv_size, driver);
+ goto unlock;
+ }
+
+ devlink = priv_to_devlink(shd);
+ if (WARN_ON_ONCE(devlink->ops != ops ||
+ shd->priv_size != priv_size ||
+ devlink->dev_driver != driver)) {
+ shd = NULL;
+ goto unlock;
+ }
+ refcount_inc(&shd->refcount);
+
+unlock:
+ mutex_unlock(&shd_mutex);
+ return shd ? priv_to_devlink(shd) : NULL;
+}
+EXPORT_SYMBOL_GPL(devlink_shd_get);
+
+/**
+ * devlink_shd_put - Release a reference on a shared devlink instance
+ * @devlink: Shared devlink instance
+ *
+ * Release a reference on a shared devlink instance obtained via
+ * devlink_shd_get().
+ */
+void devlink_shd_put(struct devlink *devlink)
+{
+ struct devlink_shd *shd;
+
+ mutex_lock(&shd_mutex);
+ shd = devlink_priv(devlink);
+ if (refcount_dec_and_test(&shd->refcount))
+ devlink_shd_destroy(shd);
+ mutex_unlock(&shd_mutex);
+}
+EXPORT_SYMBOL_GPL(devlink_shd_put);
+
+/**
+ * devlink_shd_get_priv - Get private data from shared devlink instance
+ * @devlink: Devlink instance
+ *
+ * Returns a pointer to the driver's private data structure within
+ * the shared devlink instance.
+ *
+ * Return: Pointer to private data
+ */
+void *devlink_shd_get_priv(struct devlink *devlink)
+{
+ struct devlink_shd *shd = devlink_priv(devlink);
+
+ return shd->priv;
+}
+EXPORT_SYMBOL_GPL(devlink_shd_get_priv);
--
2.51.1
next prev parent reply other threads:[~2026-03-12 10:04 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-12 10:03 [PATCH net-next v4 00/13] devlink: introduce shared devlink instance for PFs on same chip Jiri Pirko
2026-03-12 10:03 ` [PATCH net-next v4 01/13] devlink: expose devlink instance index over netlink Jiri Pirko
2026-03-12 10:03 ` [PATCH net-next v4 02/13] devlink: add helpers to get bus_name/dev_name Jiri Pirko
2026-03-12 10:03 ` [PATCH net-next v4 03/13] devlink: avoid extra iterations when found devlink is not registered Jiri Pirko
2026-03-12 10:03 ` [PATCH net-next v4 04/13] devlink: allow to use devlink index as a command handle Jiri Pirko
2026-03-12 10:03 ` [PATCH net-next v4 05/13] devlink: support index-based lookup via bus_name/dev_name handle Jiri Pirko
2026-03-12 10:04 ` [PATCH net-next v4 06/13] devlink: support index-based notification filtering Jiri Pirko
2026-03-12 10:04 ` [PATCH net-next v4 07/13] devlink: introduce __devlink_alloc() with dev driver pointer Jiri Pirko
2026-03-12 10:04 ` [PATCH net-next v4 08/13] devlink: add devlink_dev_driver_name() helper and use it in trace events Jiri Pirko
2026-03-12 10:04 ` [PATCH net-next v4 09/13] devlink: add devl_warn() helper and use it in port warnings Jiri Pirko
2026-03-12 10:04 ` [PATCH net-next v4 10/13] devlink: allow devlink instance allocation without a backing device Jiri Pirko
2026-03-12 10:04 ` Jiri Pirko [this message]
2026-03-12 10:04 ` [PATCH net-next v4 12/13] documentation: networking: add shared devlink documentation Jiri Pirko
2026-03-12 10:04 ` [PATCH net-next v4 13/13] net/mlx5: Add a shared devlink instance for PFs on same chip Jiri Pirko
2026-03-20 23:16 ` Adam Young
2026-03-20 23:37 ` Adam Young
2026-03-23 15:05 ` Jiri Pirko
2026-03-24 13:02 ` Jiri Pirko
2026-03-24 17:49 ` Adam Young
2026-03-24 19:57 ` Adam Young
2026-03-24 15:10 ` [PATCH net-next v4 13/15] " Ben Copeland
2026-03-24 15:21 ` Jiri Pirko
2026-03-24 15:37 ` Ben Copeland
2026-03-14 20:20 ` [PATCH net-next v4 00/13] devlink: introduce " patchwork-bot+netdevbpf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260312100407.551173-12-jiri@resnulli.us \
--to=jiri@resnulli.us \
--cc=andrew+netdev@lunn.ch \
--cc=chuck.lever@oracle.com \
--cc=cjubran@nvidia.com \
--cc=corbet@lwn.net \
--cc=daniel.zahka@gmail.com \
--cc=davem@davemloft.net \
--cc=donald.hunter@gmail.com \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=leon@kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-rdma@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=matttbe@kernel.org \
--cc=mbloch@nvidia.com \
--cc=mhiramat@kernel.org \
--cc=mschmidt@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=przemyslaw.kitszel@intel.com \
--cc=rostedt@goodmis.org \
--cc=saeedm@nvidia.com \
--cc=skhan@linuxfoundation.org \
--cc=tariqt@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox