From: Konstantin Sinyuk <ksinyuk@kernel.org>
To: dri-devel@lists.freedesktop.org
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
Francois Dugast <francois.dugast@intel.com>,
David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>,
Maxime Ripard <mripard@kernel.org>,
Thomas Zimmermann <tzimmermann@suse.de>,
Jonathan Corbet <corbet@lwn.net>,
Shuah Khan <skhan@linuxfoundation.org>,
Donald Hunter <donald.hunter@gmail.com>,
Jakub Kicinski <kuba@kernel.org>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Paolo Abeni <pabeni@redhat.com>, Simon Horman <horms@kernel.org>,
Ilia Levi <ilia.levi@intel.com>,
Rodrigo Vivi <rodrigo.vivi@intel.com>,
linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [RFC PATCH 10/12] drm/fabric: make the synthetic provider writable
Date: Mon, 24 Aug 2026 11:09:38 +0300 [thread overview]
Message-ID: <605d72ca904f63a854869c9f88426b767e61554c.1787552412.git.ksinyuk@kernel.org> (raw)
In-Reply-To: <cover.1787552412.git.ksinyuk@kernel.org>
Add provisioning callbacks to fabricsim for endpoint attachment,
administrative-state changes and peer updates.
Reserve each endpoint's last port for userspace-managed peer provisioning;
the remaining ports stay provider-managed, so one topology covers both
peer authorities.
Add per-callback fault injection for error propagation and failure
atomicity. The new debugfs controls remain test-only.
Signed-off-by: Konstantin Sinyuk <ksinyuk@kernel.org>
Assisted-by: GitHub-Copilot:claude-opus-4.8
---
Documentation/gpu/drm-fabric.rst | 4 +
drivers/gpu/drm/fabric/drm_fabric_sim.c | 138 +++++++++++++++++-------
2 files changed, 106 insertions(+), 36 deletions(-)
diff --git a/Documentation/gpu/drm-fabric.rst b/Documentation/gpu/drm-fabric.rst
index 4ee7cb7ef6ac..1fd48027eee3 100644
--- a/Documentation/gpu/drm-fabric.rst
+++ b/Documentation/gpu/drm-fabric.rst
@@ -454,6 +454,10 @@ ports. The switch shape links every endpoint to an opaque switch peer
(``peer-type = switch``) whose id does not resolve to an endpoint, exercising the
directed half-edge model without a first-class switch object.
+It implements the provisioning callbacks, so it is also the reference provider
+for the mutation commands. It reserves each endpoint's last port for userspace
+peer management and wires topology on the ports below it.
+
Its debugfs knobs stimulate synthetic counter activity, operational-state changes
and runtime endpoint add/remove. These files are unstable test controls and are
not part of the uAPI; the stable, reviewed interface is the YAML-described
diff --git a/drivers/gpu/drm/fabric/drm_fabric_sim.c b/drivers/gpu/drm/fabric/drm_fabric_sim.c
index 7d489c6894bf..e441943c02c3 100644
--- a/drivers/gpu/drm/fabric/drm_fabric_sim.c
+++ b/drivers/gpu/drm/fabric/drm_fabric_sim.c
@@ -90,6 +90,7 @@ static struct dentry *fabricsim_debugfs_root;
/* Test-only fault injection (debugfs). Sticky until cleared. */
static bool fabricsim_fail_register;
+static bool fabricsim_fail_mutation;
static u32 fabricsim_fail_errno = ENOMEM;
/*
@@ -142,8 +143,45 @@ static int fabricsim_port_stats_get(struct drm_fabric_port *port,
return 0;
}
+/* The mutation hooks only fail on request; the core owns the model. */
+static int fabricsim_endpoint_set(struct drm_fabric_endpoint *ep,
+ const struct drm_fabric_endpoint_change *change,
+ struct drm_fabric *fabric)
+{
+ if (fabricsim_fail_mutation)
+ return fabricsim_injected_errno();
+ return 0;
+}
+
+static int fabricsim_port_set(struct drm_fabric_port *port,
+ enum drm_fabric_admin_state admin)
+{
+ if (fabricsim_fail_mutation)
+ return fabricsim_injected_errno();
+ return 0;
+}
+
+static int fabricsim_port_peer_new(struct drm_fabric_port *port,
+ const struct drm_fabric_peer *peer)
+{
+ if (fabricsim_fail_mutation)
+ return fabricsim_injected_errno();
+ return 0;
+}
+
+static int fabricsim_port_peer_del(struct drm_fabric_port *port)
+{
+ if (fabricsim_fail_mutation)
+ return fabricsim_injected_errno();
+ return 0;
+}
+
static const struct drm_fabric_ops fabricsim_ops = {
.port_stats_get = fabricsim_port_stats_get,
+ .endpoint_set = fabricsim_endpoint_set,
+ .port_set = fabricsim_port_set,
+ .port_peer_new = fabricsim_port_peer_new,
+ .port_peer_del = fabricsim_port_peer_del,
};
#define FABRICSIM_TICK_MS 100
@@ -343,12 +381,9 @@ static void fabricsim_link_linear(void)
struct drm_fabric_endpoint *ep_b = fabricsim_slots[i + 1]->ep;
struct drm_fabric_port *pa, *pb;
- /*
- * Interior nodes consume two ports; stop rather than walk off
- * an endpoint's port array if it was sized too small.
- */
- if (pa_idx >= fabricsim_slots[i]->num_ports ||
- pb_idx >= fabricsim_slots[i + 1]->num_ports)
+ /* -1 skips the reserved last port. */
+ if (pa_idx >= fabricsim_slots[i]->num_ports - 1 ||
+ pb_idx >= fabricsim_slots[i + 1]->num_ports - 1)
break;
pa = fabricsim_slots[i]->ports[pa_idx].port;
@@ -379,7 +414,8 @@ static void fabricsim_link_mesh(void)
if (i == j)
continue;
- if (port_idx >= fabricsim_slots[i]->num_ports)
+ /* -1 skips the reserved last port. */
+ if (port_idx >= fabricsim_slots[i]->num_ports - 1)
break;
/*
@@ -421,7 +457,8 @@ static void fabricsim_link_switch(void)
struct drm_fabric_port *leaf_port =
fabricsim_slots[i]->ports[0].port;
- if (!leaf_port)
+ /* Port 0 is the uplink; skip an endpoint with only the reserved port. */
+ if (!leaf_port || fabricsim_slots[i]->num_ports < 2)
continue;
/* One directed half-edge from the leaf to an opaque switch. */
@@ -467,11 +504,12 @@ static void fabricsim_ep_debugfs_create(struct fabricsim_ep_priv *ep_priv)
}
/*
- * Create one endpoint at @slot with @nports ports, registered as a member of
- * the synthetic fabric. Returns the new ep_priv or an ERR_PTR. Caller holds
+ * Create an endpoint at @slot with @nports ports. @orphan registers it
+ * without a fabric for a later ENDPOINT_SET attach. Caller holds
* fabricsim_lock.
*/
-static struct fabricsim_ep_priv *fabricsim_make_ep(int slot, int nports)
+static struct fabricsim_ep_priv *fabricsim_make_ep(int slot, int nports,
+ bool orphan)
{
struct drm_fabric_endpoint_desc edesc = {};
struct drm_fabric_port_desc pdescs[16];
@@ -509,6 +547,13 @@ static struct fabricsim_ep_priv *fabricsim_make_ep(int slot, int nports)
pdescs[j].index = j;
pdescs[j].max_lane_count = 4;
pdescs[j].max_lane_signaling_rate_mbps = 200000; /* 200 Gbps/lane */
+ /*
+ * Reserve the last port for userspace peer tests; a single-port
+ * endpoint therefore has no provider-managed port.
+ */
+ pdescs[j].peer_mode = (j == nports - 1) ?
+ DRM_FABRIC_PEER_MODE_USERSPACE :
+ DRM_FABRIC_PEER_MODE_PROVIDER;
}
snprintf(ep_name, sizeof(ep_name), "sim-ep%d", slot);
@@ -540,7 +585,8 @@ static struct fabricsim_ep_priv *fabricsim_make_ep(int slot, int nports)
timer_setup(&pp->activity_timer, fabricsim_activity_tick, 0);
}
- ep_priv->ep = drm_fabric_endpoint_register(fabricsim_fabric, &edesc);
+ ep_priv->ep = drm_fabric_endpoint_register(orphan ? NULL : fabricsim_fabric,
+ &edesc);
if (IS_ERR(ep_priv->ep)) {
ret = PTR_ERR(ep_priv->ep);
goto err_ports;
@@ -597,7 +643,7 @@ static void fabricsim_destroy_ep(struct fabricsim_ep_priv *ep_priv)
kfree(ep_priv);
}
-static int fabricsim_add_endpoint(int nports)
+static int fabricsim_add_endpoint(int nports, bool orphan)
{
struct fabricsim_ep_priv *ep_priv;
int slot, ret;
@@ -616,7 +662,7 @@ static int fabricsim_add_endpoint(int nports)
return -ENOSPC;
}
- ep_priv = fabricsim_make_ep(slot, nports);
+ ep_priv = fabricsim_make_ep(slot, nports, orphan);
if (IS_ERR(ep_priv)) {
ret = PTR_ERR(ep_priv);
mutex_unlock(&fabricsim_lock);
@@ -667,7 +713,7 @@ static int fabricsim_bulk_add(int n)
return -EINVAL;
while (added < n) {
- ret = fabricsim_add_endpoint(1);
+ ret = fabricsim_add_endpoint(1, false);
if (ret < 0)
return added ? added : ret;
added++;
@@ -713,15 +759,28 @@ static int fabricsim_parse_int(const char __user *buf, size_t count, int dflt)
return val;
}
-static ssize_t fabricsim_add_ep_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t fabricsim_add_ep_common(const char __user *buf, size_t count,
+ bool orphan)
{
int nports = fabricsim_parse_int(buf, count, ports_per_ep);
- int ret = fabricsim_add_endpoint(nports);
+ int ret = fabricsim_add_endpoint(nports, orphan);
return ret < 0 ? ret : count;
}
+static ssize_t fabricsim_add_ep_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return fabricsim_add_ep_common(buf, count, false);
+}
+
+static ssize_t fabricsim_add_orphan_write(struct file *file,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return fabricsim_add_ep_common(buf, count, true);
+}
+
static ssize_t fabricsim_del_ep_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
@@ -736,6 +795,11 @@ static const struct file_operations fabricsim_add_ep_fops = {
.write = fabricsim_add_ep_write,
};
+static const struct file_operations fabricsim_add_orphan_fops = {
+ .owner = THIS_MODULE,
+ .write = fabricsim_add_orphan_write,
+};
+
static const struct file_operations fabricsim_del_ep_fops = {
.owner = THIS_MODULE,
.write = fabricsim_del_ep_write,
@@ -810,6 +874,8 @@ static const struct file_operations fabricsim_fail_errno_fops = {
*/
static int __init fabricsim_setup_params(void)
{
+ int wired;
+
/*
* Reject an unrecognised topology rather than falling back to mesh, so
* a typo cannot fake a shape.
@@ -830,22 +896,17 @@ static int __init fabricsim_setup_params(void)
if (ports_per_ep > 16)
ports_per_ep = 16;
- /*
- * A mesh gives every endpoint (N-1) peers, so the busiest endpoint needs
- * at least (N-1) ports. The switch shape only needs one port per leaf
- * (a single half-edge to the opaque switch), so it is not bumped here.
- */
- if (strcmp(topology, "mesh") == 0 && ports_per_ep < num_endpoints - 1)
- ports_per_ep = num_endpoints - 1;
+ /* Peers wired per endpoint: mesh N-1, linear interior 2, switch 1. */
+ if (strcmp(topology, "mesh") == 0)
+ wired = num_endpoints - 1;
+ else if (strcmp(topology, "linear") == 0 && num_endpoints > 2)
+ wired = 2;
+ else
+ wired = 1;
- /*
- * A linear chain gives every interior node two neighbours, so it needs
- * at least two ports; bump a too-small request rather than index past
- * the endpoint's port array.
- */
- if (strcmp(topology, "linear") == 0 && num_endpoints > 2 &&
- ports_per_ep < 2)
- ports_per_ep = 2;
+ /* make_ep() reserves the last port, so @wired alone drops an edge. */
+ if (ports_per_ep < wired + 1)
+ ports_per_ep = wired + 1;
fabricsim_init_eps = num_endpoints;
@@ -877,7 +938,7 @@ static int __init fabricsim_init(void)
mutex_lock(&fabricsim_lock);
for (i = 0; i < fabricsim_init_eps; i++) {
struct fabricsim_ep_priv *ep_priv =
- fabricsim_make_ep(i, ports_per_ep);
+ fabricsim_make_ep(i, ports_per_ep, false);
if (IS_ERR(ep_priv)) {
ret = PTR_ERR(ep_priv);
@@ -910,6 +971,8 @@ static int __init fabricsim_init(void)
if (fabricsim_debugfs_root) {
debugfs_create_file("add_endpoint", 0200, fabricsim_debugfs_root,
NULL, &fabricsim_add_ep_fops);
+ debugfs_create_file("add_orphan", 0200, fabricsim_debugfs_root,
+ NULL, &fabricsim_add_orphan_fops);
debugfs_create_file("del_endpoint", 0200, fabricsim_debugfs_root,
NULL, &fabricsim_del_ep_fops);
@@ -921,9 +984,12 @@ static int __init fabricsim_init(void)
debugfs_create_bool("fail_register", 0644,
fabricsim_debugfs_root,
&fabricsim_fail_register);
- debugfs_create_file("fail_errno", 0644,
+ debugfs_create_bool("fail_mutation", 0644,
fabricsim_debugfs_root,
- NULL, &fabricsim_fail_errno_fops);
+ &fabricsim_fail_mutation);
+ debugfs_create_file("fail_errno", 0644,
+ fabricsim_debugfs_root, NULL,
+ &fabricsim_fail_errno_fops);
}
pr_info("fabricsim: registered %s topology with %d endpoints, %d ports/ep\n",
--
2.43.0
next prev parent reply other threads:[~2026-08-24 8:10 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-24 8:09 [RFC PATCH 0/12] drm/fabric: vendor-neutral topology infrastructure for scale-up accelerator interconnects Konstantin Sinyuk
2026-08-24 8:09 ` [RFC PATCH 01/12] drm/fabric: add core object model and provider API Konstantin Sinyuk
2026-08-24 8:09 ` [RFC PATCH 02/12] drm/fabric: add query uAPI and generated headers Konstantin Sinyuk
2026-08-24 8:09 ` [RFC PATCH 03/12] drm/fabric: implement query netlink operations Konstantin Sinyuk
2026-08-24 8:09 ` [RFC PATCH 04/12] drm/fabric: add read-only synthetic provider Konstantin Sinyuk
2026-08-24 8:09 ` [RFC PATCH 05/12] drm/fabric: add object-model KUnit tests Konstantin Sinyuk
2026-08-24 8:09 ` [RFC PATCH 06/12] drm/fabric: add YNL query and policy selftests Konstantin Sinyuk
2026-08-24 8:09 ` [RFC PATCH 07/12] drm/fabric: add topology-provisioning core Konstantin Sinyuk
2026-08-24 8:09 ` [RFC PATCH 08/12] drm/fabric: add provisioning netlink uAPI Konstantin Sinyuk
2026-08-24 8:09 ` [RFC PATCH 09/12] drm/fabric: implement mutation netlink operations Konstantin Sinyuk
2026-08-24 8:09 ` Konstantin Sinyuk [this message]
2026-08-24 8:09 ` [RFC PATCH 11/12] drm/fabric: add mutation KUnit tests Konstantin Sinyuk
2026-08-24 8:09 ` [RFC PATCH 12/12] drm/fabric: add mutation netlink selftests Konstantin Sinyuk
2026-08-26 9:32 ` [RFC PATCH 0/12] drm/fabric: vendor-neutral topology infrastructure for scale-up accelerator interconnects Leon Romanovsky
2026-08-26 15:38 ` Konstantin Sinyuk
2026-08-27 17:09 ` Leon Romanovsky
2026-08-28 16:13 ` Rodrigo Vivi
2026-09-01 11:01 ` Leon Romanovsky
2026-09-01 15:25 ` Rodrigo Vivi
2026-09-02 7:10 ` Leon Romanovsky
2026-08-31 11:45 ` Konstantin Sinyuk
2026-08-27 12:35 ` Jiri Pirko
2026-08-28 16:28 ` Rodrigo Vivi
2026-08-28 17:03 ` Jason Gunthorpe
2026-08-31 11:45 ` Konstantin Sinyuk
2026-08-31 12:23 ` Jason Gunthorpe
2026-08-31 11:45 ` Konstantin Sinyuk
2026-09-20 6:46 ` Jiri Pirko
2026-09-21 20:19 ` Jakub Kicinski
2026-09-25 18:12 ` Rodrigo Vivi
2026-09-25 19:10 ` Jakub Kicinski
2026-09-22 16:24 ` Austin, Alex (DCCG)
2026-09-23 0:16 ` Jakub Kicinski
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=605d72ca904f63a854869c9f88426b767e61554c.1787552412.git.ksinyuk@kernel.org \
--to=ksinyuk@kernel.org \
--cc=airlied@gmail.com \
--cc=corbet@lwn.net \
--cc=davem@davemloft.net \
--cc=donald.hunter@gmail.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=edumazet@google.com \
--cc=francois.dugast@intel.com \
--cc=horms@kernel.org \
--cc=ilia.levi@intel.com \
--cc=kuba@kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=maarten.lankhorst@linux.intel.com \
--cc=mripard@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=rodrigo.vivi@intel.com \
--cc=simona@ffwll.ch \
--cc=skhan@linuxfoundation.org \
--cc=tzimmermann@suse.de \
/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
all inboxes | Powered by JetHome®