Skip to contentSkip to conversation

drm/fabric: vendor-neutral topology infrastructure for scale-up accelerator interconnects

RFC PATCH In review Konstantin Sinyuk 8 participants 40 messages Aug 24 – Sep 25

Subsystems (7)
lore
Share & tools
lore
#0 lore raw

cover drm/fabric: vendor-neutral topology infrastructure for scale-up accelerator interconnects

Modern GPUs and AI accelerators are increasingly connected through scale-up fabrics such as AMD xGMI today and emerging UALink systems [4]. Linux lacks common, vendor-neutral infrastructure for reporting which accelerators are directly connected, through which ports, and in what state.

Vendors expose fragments through driver-specific interfaces such as amdgpu's xGMI sysfs [3] and AMD's UALink pod-configuration sysfs [6], while prior per-driver proposals such as XeLink never became shared infrastructure, so topology semantics remain per-driver.

Building on the LPC 2025 "Toward Mainline Linux Support for UALink" BoF [1], this RFC proposes DRM Fabric: vendor-neutral, protocol-agnostic DRM topology infrastructure for scale-up interconnects, using the model

    fabric -> endpoint -> port -> peer

A fabric groups the endpoints of one provider-defined interconnect instance. An endpoint is one accelerator attachment holding its physical ports. A port reports lane capability, operational state and optional counters. A peer is a typed value naming the directly adjacent accelerator or switch port, not a reference to a live kernel object; it may identify an accelerator managed by another OS or an opaque switch in another trust domain.

The core records direct adjacency only, not end-to-end reachability or switch forwarding, which remain with the fabric controller. Vendor drivers retain hardware discovery, firmware interaction, memory semantics and the hardware-carried data path. DRM Fabric represents topology and control state of DRM-managed accelerators; it does not create a network device or own route computation, switch forwarding, transport, or congestion control.

Generic Netlink fits this multi-object, event-driven model better than sysfs, which maps poorly onto dump enumeration and asynchronous notifications, and provides the YAML-described uAPI discipline introduced to DRM by DRM RAS [2]. Devlink was considered, but models devices and subordinate objects rather than a fabric spanning DRM devices.

Patches 1-6 form a complete, separately tested read-only milestone that can be merged independently while provisioning remains under review. Providers publish objects, adjacency, operational state and optional port statistics through a small in-kernel API; userspace queries the live graph but cannot modify it.

Patches 7-12 add privileged provisioning for software-defined fabrics. Userspace can create and delete empty fabrics, attach orphan endpoints registered without a fabric, request administrative state and manage peer adjacency, while the provider performs the hardware programming. Administrative state records control-plane intent, operational state remains provider-reported, and each port is managed either by its provider or by userspace. The mutation operations are fabric-new, fabric-del, endpoint-set, port-set, port-peer-new and port-peer-del.

Provider callbacks may sleep or report state back into the core, so drm_fabric_lock is not held across them. Provisioning instead uses an outer mutation lock across validation, callback and commit. The complete locking, lifetime and failure contracts are documented in Documentation/gpu/drm-fabric.rst.

Every operation is confined to the initial network namespace, and mutation additionally requires CAP_NET_ADMIN.

drm_fabric_sim is a software-only provider modeled on netdevsim [5]. It registers linear, mesh and switch-facing topologies without accelerator hardware and gains provisioning callbacks and fault injection. Its debugfs interface is not ABI; the reviewed interface is the Generic Netlink family.

The series defines no accelerator memory sharing, MMU programming, data transport, route computation, switch policy, key management, live migration, required userspace daemon or protocol-specific commands.

No production provider is included. Shipping only the synthetic provider is deliberate, allowing the object model and uAPI to be reviewed before being tied to hardware. We used the public amdgpu xGMI implementation to shape the provider API, but that mapping has not been validated by AMD.

Example queries using the in-tree YNL tool are:

    $ ./tools/net/ynl/pyynl/cli.py \
          --spec Documentation/netlink/specs/drm_fabric.yaml \
          --dump fabric-get
    $ ./tools/net/ynl/pyynl/cli.py \
          --spec Documentation/netlink/specs/drm_fabric.yaml \
          --dump endpoint-get --json '{"fabric-id": <id>}'
    $ ./tools/net/ynl/pyynl/cli.py \
          --spec Documentation/netlink/specs/drm_fabric.yaml \
          --do port-get --json '{"endpoint-id": <id>, "port-index": 0}'

Testing includes 12/12 per-commit W=1 builds, 43 passing KUnit tests and 172 passing kselftest results across 14 programs. KASAN, UBSAN, lockdep, atomic-sleep and kmemleak validation completed without reports.

The series is also available from the public review tree:

https://git.kernel.org/pub/scm/linux/kernel/git/ksinyuk/linux.git/tag/?h=drm-fabric-v1

We are specifically requesting feedback on:

1. Is fabric -> endpoint -> port -> peer the right minimum common DRM representation for accelerator interconnects?

2. Are the Generic Netlink semantics, including dump consistency, notifications and optional port statistics, aligned with YNL expectations?

3. Do the object model and provider API cover xGMI topology-management requirements, or would any xGMI requirement force protocol-specific uAPI or provider semantics? AMD's assessment would be especially valuable.

[1] LPC 2025 BoF, "Toward Mainline Linux Support for UALink":

    https://lpc.events/event/19/contributions/2308/

[2] Riana Tauro, "[PATCH v10 0/5] Introduce DRM_RAS using generic netlink

    for RAS", 2026-03-04:
    https://lore.kernel.org/dri-devel/[email protected]

[3] amdgpu xGMI topology:
drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c

[4] UALink specification:
https://ualinkconsortium.org/specification/

[5] netdevsim:
Documentation/networking/devlink/netdevsim.rst

[6] Alex Deucher, "[PATCH 00/95] Add UALink instrastructure series 1",

    2026-08-21:
    https://lore.kernel.org/amd-gfx/[email protected]/

Ilia Levi (4):
drm/fabric: add core object model and provider API drm/fabric: add query uAPI and generated headers drm/fabric: add topology-provisioning core drm/fabric: add provisioning netlink uAPI

Konstantin Sinyuk (8):
drm/fabric: implement query netlink operations drm/fabric: add read-only synthetic provider drm/fabric: add object-model KUnit tests drm/fabric: add YNL query and policy selftests drm/fabric: implement mutation netlink operations drm/fabric: make the synthetic provider writable drm/fabric: add mutation KUnit tests drm/fabric: add mutation netlink selftests

 Documentation/gpu/drm-fabric.rst              |  479 +++
 Documentation/gpu/index.rst                   |    1 +
 Documentation/netlink/specs/drm_fabric.yaml   |  580 ++++
 MAINTAINERS                                   |   14 +
 drivers/gpu/drm/Kconfig                       |    1 +
 drivers/gpu/drm/Makefile                      |    1 +
 drivers/gpu/drm/fabric/.kunitconfig           |    5 +
 drivers/gpu/drm/fabric/.kunitconfig.debug     |   16 +
 drivers/gpu/drm/fabric/Kconfig                |   41 +
 drivers/gpu/drm/fabric/Makefile               |    9 +
 drivers/gpu/drm/fabric/drm_fabric.c           | 1045 +++++++
 drivers/gpu/drm/fabric/drm_fabric_internal.h  |   66 +
 drivers/gpu/drm/fabric/drm_fabric_netlink.c   | 1310 ++++++++
 drivers/gpu/drm/fabric/drm_fabric_nl.c        |  231 ++
 drivers/gpu/drm/fabric/drm_fabric_nl.h        |   66 +
 drivers/gpu/drm/fabric/drm_fabric_sim.c       | 1044 +++++++
 drivers/gpu/drm/fabric/drm_fabric_test.c      | 2635 +++++++++++++++++
 include/drm/drm_fabric.h                      |  333 +++
 include/uapi/drm/drm_fabric.h                 |  162 +
 tools/testing/selftests/Makefile              |    1 +
 .../selftests/drivers/gpu/drm_fabric/Makefile |   44 +
 .../drivers/gpu/drm_fabric/README.rst         |  146 +
 .../drivers/gpu/drm_fabric/cap_netadmin.py    |  314 ++
 .../gpu/drm_fabric/check-spec-regen.sh        |  114 +
 .../selftests/drivers/gpu/drm_fabric/config   |   13 +
 .../drivers/gpu/drm_fabric/dump_intr_abi.py   |  361 +++
 .../drivers/gpu/drm_fabric/dump_scale_abi.py  |  178 ++
 .../drivers/gpu/drm_fabric/fabric_abi.py      |  553 ++++
 .../drivers/gpu/drm_fabric/fault_abi.py       |  302 ++
 .../gpu/drm_fabric/harness_reset_abi.py       |  113 +
 .../drivers/gpu/drm_fabric/hotplug_abi.py     |  331 +++
 .../drivers/gpu/drm_fabric/lib_drm_fabric.py  |  498 ++++
 .../drivers/gpu/drm_fabric/netns_abi.py       |  294 ++
 .../drivers/gpu/drm_fabric/nl_policy_probe.py |  651 ++++
 .../drivers/gpu/drm_fabric/port_cursor_abi.py |  401 +++
 .../gpu/drm_fabric/port_stats_cap_abi.py      |  374 +++
 .../drm_fabric/provisioning_scenarios_abi.py  |  324 ++
 .../selftests/drivers/gpu/drm_fabric/settings |    1 +
 .../drivers/gpu/drm_fabric/switch_abi.py      |  137 +
 39 files changed, 13189 insertions(+)
 create mode 100644 Documentation/gpu/drm-fabric.rst
 create mode 100644 Documentation/netlink/specs/drm_fabric.yaml
 create mode 100644 drivers/gpu/drm/fabric/.kunitconfig
 create mode 100644 drivers/gpu/drm/fabric/.kunitconfig.debug
 create mode 100644 drivers/gpu/drm/fabric/Kconfig
 create mode 100644 drivers/gpu/drm/fabric/Makefile
 create mode 100644 drivers/gpu/drm/fabric/drm_fabric.c
 create mode 100644 drivers/gpu/drm/fabric/drm_fabric_internal.h
 create mode 100644 drivers/gpu/drm/fabric/drm_fabric_netlink.c
 create mode 100644 drivers/gpu/drm/fabric/drm_fabric_nl.c
 create mode 100644 drivers/gpu/drm/fabric/drm_fabric_nl.h
 create mode 100644 drivers/gpu/drm/fabric/drm_fabric_sim.c
 create mode 100644 drivers/gpu/drm/fabric/drm_fabric_test.c
 create mode 100644 include/drm/drm_fabric.h
 create mode 100644 include/uapi/drm/drm_fabric.h
 create mode 100644 tools/testing/selftests/drivers/gpu/drm_fabric/Makefile
 create mode 100644 tools/testing/selftests/drivers/gpu/drm_fabric/README.rst
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/cap_netadmin.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/check-spec-regen.sh
 create mode 100644 tools/testing/selftests/drivers/gpu/drm_fabric/config
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/dump_intr_abi.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/dump_scale_abi.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/fabric_abi.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/fault_abi.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/harness_reset_abi.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/hotplug_abi.py
 create mode 100644 tools/testing/selftests/drivers/gpu/drm_fabric/lib_drm_fabric.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/netns_abi.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/nl_policy_probe.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/port_cursor_abi.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/port_stats_cap_abi.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/provisioning_scenarios_abi.py
 create mode 100644 tools/testing/selftests/drivers/gpu/drm_fabric/settings
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/switch_abi.py

base-commit: e3e05bddbe9fea67639d2a3551e7cf2d473b804c

Signature · 1 line
2.43.0
#1 lore raw

RFC PATCH 1/12 drm/fabric: add core object model and provider API

From: Ilia Levi <[email protected]>

Accelerator drivers currently expose interconnect topology through driver-specific interfaces, leaving topology semantics fragmented across drivers. Add a common DRM object model for fabrics, endpoints, ports and directly adjacent peers, together with the provider API drivers use to populate it:

    fabric -> endpoint -> port -> peer

A fabric groups the endpoints of one provider-defined interconnect instance. An endpoint owns a fixed set of ports. A port may carry a type-qualified peer value describing the accelerator or switch directly adjacent at the far end of its link; the peer need not resolve to another live kernel object. The core assigns live-object IDs, manages object lifetime and enforces the model's invariants. The complete object, peer, locking and lifecycle contracts are documented in Documentation/gpu/drm-fabric.rst, added here.

CONFIG_DRM_FABRIC builds the core as drm-fabric.ko and depends on NET for the Generic Netlink uAPI added next. No provider uses the API yet, so loading the module registers no fabric objects.

Add a MAINTAINERS entry for the subsystem.

Split the core and generated uAPI header across this patch and the next to keep the object model and wire contract separately reviewable while both commits remain buildable. Temporarily define the uAPI value enums locally; the generated header replaces them in the next patch.

Assisted-by GitHub-Copilot:claude-opus-4.8
---
 Documentation/gpu/drm-fabric.rst             | 142 ++++
 Documentation/gpu/index.rst                  |   1 +
 MAINTAINERS                                  |  14 +
 drivers/gpu/drm/Kconfig                      |   1 +
 drivers/gpu/drm/Makefile                     |   1 +
 drivers/gpu/drm/fabric/Kconfig               |  14 +
 drivers/gpu/drm/fabric/Makefile              |   4 +
 drivers/gpu/drm/fabric/drm_fabric.c          | 681 +++++++++++++++++++
 drivers/gpu/drm/fabric/drm_fabric_internal.h |  34 +
 include/drm/drm_fabric.h                     | 259 +++++++
 10 files changed, 1151 insertions(+)
 create mode 100644 Documentation/gpu/drm-fabric.rst
 create mode 100644 drivers/gpu/drm/fabric/Kconfig
 create mode 100644 drivers/gpu/drm/fabric/Makefile
 create mode 100644 drivers/gpu/drm/fabric/drm_fabric.c
 create mode 100644 drivers/gpu/drm/fabric/drm_fabric_internal.h
 create mode 100644 include/drm/drm_fabric.h
Documentation/gpu/drm-fabric.rst new file +142 -0
new file mode 100644
index 000000000000..99b189dc614e
@@ -0,0 +1,142 @@
+.. SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+===============================
+DRM Fabric over Generic Netlink
+===============================
+
+Modern GPUs and dedicated AI accelerators are increasingly connected through
+scale-up interconnect fabrics such as AMD xGMI and
+`UALink <https://ualinkconsortium.org/specification/>`__.
+
+DRM Fabric is a registry and dispatcher. It does not discover routes, compute
+reachability, program switch forwarding, manage device memory, or provide a
+data path; those remain with the vendor driver and the fabric controller.
+
+Key Goals:
+
+* Provide a standardized topology model for GPU and accelerator interconnects
+  (xGMI, UALink and similar), enabling data-center discovery and monitoring.
+* Support read-only enumeration, monitoring and state queries for
+  provider-owned topology.
+* Offer a flexible, future-proof interface that can be extended with new fabric
+  types and attributes without breaking the uAPI.
+* Allow multiple endpoints and ports per provider, so drivers can model
+  accelerator attachments, links and their peers.
+
+.. contents::
+
+Object model
+============
+
+DRM Fabric models interconnect topology with four object types::
+
+    fabric
+      `-- endpoint
+            `-- port
+                  `-- peer (optional value descriptor)
+
+A *fabric* is a membership group of *endpoints*; each endpoint represents one
+accelerator attachment and owns a fixed set of *ports*; and a *port* may carry a
+*peer* describing the device directly adjacent at the far end of its link, which
+is either another accelerator or a fabric switch.
+
+Identity is layered. The core assigns kernel-local ``fabric-id`` and
+``endpoint-id`` values that address live registry objects for the duration of
+their registration. Providers supply an endpoint ``fabric-ep-id`` -- an
+accelerator's identity within its fabric's identity domain. A peer instead
+carries a type-qualified ``peer-id``: for ``peer-type = accel`` it is the
+far-end accelerator's ``fabric-ep-id``, and for ``peer-type = switch`` it is an
+opaque provider-defined switch identity that names no local object. Accelerator
+and switch identities occupy separate namespaces selected by ``peer-type``, so
+the same numeric value may name different objects under each type.
+
+Fabric membership does not imply end-to-end reachability, and the topology is
+not necessarily a tree. The registered shape reflects the direct adjacency the
+provider reports: for example, it may be a full mesh with no root, a linear
+chain, or a switch-based topology in which ports terminate at opaque switch
+peers rather than locally registered endpoints.
+
+A *peer* is a value descriptor, not a reference to a live kernel object: its
+``peer-id`` may name a remote accelerator managed by another OS or an opaque
+switch in another trust domain, and need not resolve in the local registry. The
+core stores one directed half-edge and does not require the reverse half-edge to
+exist, so removing an endpoint does not retract peer descriptors held by other
+endpoints. ``peer-type = switch`` only describes the kind of far end; it does
+not create a first-class switch object.
+
+.. kernel-doc:: drivers/gpu/drm/fabric/drm_fabric.c
+   :doc: DRM Fabric core
+
+Peer semantics
+--------------
+
+A peer is an identity rather than a reference to a live object, and the
+difference decides what the core reports. A ``peer-id`` that resolves in the
+local registry today may stop resolving later because the endpoint it named
+unregistered, and no event is emitted on the port still carrying it: a peer
+is recorded on one local half-edge, and peer disappearance does not retract
+that half-edge. A peer is therefore topology as last set, not proof of live
+connectivity; liveness belongs to the fabric controller.
+
+The core never retracts a half-edge on its own. Failing to resolve a peer
+locally is not the same as the link going away -- the far end may be a switch,
+an accelerator on another node, or a local endpoint that merely unregistered
+-- so only the provider knows when a port's physical adjacency actually
+changed, and only the provider retracts or replaces the descriptor.
+
+Endpoint teardown removes the endpoint's owned half-edges without generating
+a separate event for each port: the delete already describes the transition,
+so removing an endpoint advances the topology generation once rather than
+once per child port.
+
+Driver API
+----------
+
+.. kernel-doc:: include/drm/drm_fabric.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/fabric/drm_fabric.c
+   :export:
+
+Design scope and boundaries
+===========================
+
+Vendor drivers retain hardware discovery, firmware interaction and the
+load/store data path; DRM Fabric represents only the topology and
+provider-reported state of DRM-managed accelerators, which is why it
+belongs in DRM. The interface does not define MMU programming, switch
+policy, key management, live migration, or any required user space daemon.
+
+DRM Fabric does not define in-network collective operations or how an
+endpoint or switch executes them. Such capabilities belong to the
+interconnect implementation and its provider. Adding capability later is not
+foreclosed: for an endpoint it is a new attribute, while
+``peer-type = switch`` is a value descriptor rather than a registered object,
+so there is nowhere to attach one today. ``peer-id`` is already an opaque
+switch identity that need not resolve locally, so making one resolvable later
+strengthens the contract rather than breaking it.
+
+Object lifetime and locking
+===========================
+
+All registry and object state is protected by ``drm_fabric_lock``. A fabric and
+its endpoints are created and torn down through the provider API; endpoint
+unregister removes the endpoint from the registry and frees its fixed set of
+ports. Fabric membership is tracked, so a provider must remove all member
+endpoints before unregistering a provider-owned fabric: drm_fabric_unregister()
+returns ``-EBUSY`` and leaves the fabric registered if any remain, so the
+provider must retry after removing them rather than treat the fabric as gone.
+
+Objects are reference counted and a port is pinned through its owning endpoint.
+Endpoint unregister drops the registration reference and waits for outstanding
+pins before freeing the ports; fabric membership holds a fabric reference.
+
+Providers own object lifetime, so a provider must serialise endpoint
+registration against unregistration of the containing fabric. The unregister
+entry points compare the supplied pointer against the registry before
+dereferencing it, so a stale or repeated teardown is rejected: fabric
+unregistration returns ``-ENODEV``, and endpoint unregistration, having no
+error return, warns and performs no teardown. Endpoint registration rejects a
+departed parent the same way. These checks prove current address membership
+only: they cannot tell an earlier incarnation from another object registered
+later at the same address.
Documentation/gpu/index.rst +1 -0
index 65bf3b26e4f4..7d99c47ddbe7 100644
@@ -16,6 +16,7 @@ GPU Driver Developer's Guide
    driver-uapi
    drm-client
    drm-compute
+   drm-fabric
    drivers
    backlight
    vga-switcheroo
MAINTAINERS +14 -0
index 3c508bda61d5..2ab63bd763b3 100644
@@ -8966,6 +8966,20 @@ F:	Documentation/devicetree/bindings/display/xlnx/
 F:	Documentation/gpu/zynqmp.rst
 F:	drivers/gpu/drm/xlnx/
 
+DRM FABRIC
+M:	Konstantin Sinyuk <[email protected]>
+M:	Maarten Lankhorst <[email protected]>
+R:	Francois Dugast <[email protected]>
+L:	[email protected]
+S:	Maintained
+T:	git https://gitlab.freedesktop.org/drm/misc/kernel.git
+F:	Documentation/gpu/drm-fabric.rst
+F:	Documentation/netlink/specs/drm_fabric.yaml
+F:	drivers/gpu/drm/fabric/
+F:	include/drm/drm_fabric.h
+F:	include/uapi/drm/drm_fabric.h
+F:	tools/testing/selftests/drivers/gpu/drm_fabric/
+
 DRM GPU SCHEDULER
 M:	Matthew Brost <[email protected]>
 M:	Danilo Krummrich <[email protected]>
drivers/gpu/drm/Kconfig +1 -0
index 323422861e8f..fc66146a603b 100644
@@ -309,6 +309,7 @@ source "drivers/gpu/drm/atmel-hlcdc/Kconfig"
 source "drivers/gpu/drm/bridge/Kconfig"
 source "drivers/gpu/drm/etnaviv/Kconfig"
 source "drivers/gpu/drm/exynos/Kconfig"
+source "drivers/gpu/drm/fabric/Kconfig"
 source "drivers/gpu/drm/fsl-dcu/Kconfig"
 source "drivers/gpu/drm/gma500/Kconfig"
 source "drivers/gpu/drm/gud/Kconfig"
drivers/gpu/drm/Makefile +1 -0
index e635fcffd379..bdf67dd3aab9 100644
@@ -213,6 +213,7 @@ obj-y			+= panel/
 obj-y			+= bridge/
 obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
 obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
+obj-$(CONFIG_DRM_FABRIC) += fabric/
 obj-y			+= hisilicon/
 obj-y			+= mxsfb/
 obj-y			+= sysfb/
drivers/gpu/drm/fabric/Kconfig new file +14 -0
new file mode 100644
index 000000000000..21fbfae9863d
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config DRM_FABRIC
+	tristate "DRM fabric support"
+	depends on DRM && NET
+	help
+	  Enable DRM fabric support. This infrastructure provides the
+	  core object model and provider API for registered accelerator
+	  interconnect topologies.
+
+	  To compile this as a module, choose M here: the module will be
+	  called drm-fabric.
+
+	  If in doubt, say N.
drivers/gpu/drm/fabric/Makefile new file +4 -0
new file mode 100644
index 000000000000..3a76f31f1e83
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_DRM_FABRIC) += drm-fabric.o
+drm-fabric-y := drm_fabric.o
drivers/gpu/drm/fabric/drm_fabric.c new file +681 -0

681 lines not on this page · raw message

drivers/gpu/drm/fabric/drm_fabric_internal.h new file +34 -0
new file mode 100644
index 000000000000..d454225a0b81
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#ifndef __DRM_FABRIC_INTERNAL_H__
+#define __DRM_FABRIC_INTERNAL_H__
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/xarray.h>
+
+#include <drm/drm_fabric.h>
+
+extern struct mutex drm_fabric_lock;
+extern struct xarray drm_fabric_xa;    /* Fabric registry */
+extern struct xarray drm_fabric_ep_xa; /* Endpoint registry */
+
+extern u32 drm_fabric_base_seq;        /* Dump consistency sequence */
+
+struct drm_fabric *drm_fabric_find_by_id(u32 id);
+struct drm_fabric_endpoint *drm_fabric_endpoint_find_by_id(u32 id);
+struct drm_fabric_endpoint *
+drm_fabric_endpoint_find_by_dev_name(const char *devname, const char *busname);
+struct drm_fabric_port *drm_fabric_port_find(u32 ep_id, u32 port_idx);
+
+struct drm_fabric_port *drm_fabric_port_find_get(u32 ep_id, u32 port_idx);
+void drm_fabric_port_put(struct drm_fabric_port *port);
+struct drm_fabric_endpoint *drm_fabric_endpoint_get(struct drm_fabric_endpoint *ep);
+void drm_fabric_endpoint_put(struct drm_fabric_endpoint *ep);
+struct drm_fabric *drm_fabric_get(struct drm_fabric *fabric);
+void drm_fabric_put(struct drm_fabric *fabric);
+
+#endif /* __DRM_FABRIC_INTERNAL_H__ */
include/drm/drm_fabric.h new file +259 -0

259 lines not on this page · raw message

Signature · 1 line
2.43.0
#2 lore raw

Re: [RFC PATCH 01/12] drm/fabric: add core object model and provider API

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] drm_fabric_endpoint_find_by_dev_name() skips ambiguity checking when busname is provided. --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] drm_fabric_endpoint_find_by_dev_name() skips ambiguity checking when busname is provided. --

--- Patch [1]: [RFC PATCH 01/12] drm/fabric: add core object model and provider API --- commit a52787ad8ee51af45c9fca91640883affafd66ca
Author: Ilia Levi <[email protected]>

drm/fabric: add core object model and provider API

This commit introduces a common DRM object model for interconnect fabrics, endpoints, ports, and peers. It provides a registry and a provider API to manage object identities, relationships, and lifetimes under a central lock.

Quoted 5 lines
drivers/gpu/drm/fabric/drm_fabric.c new file +0 -0
new file mode 100644
index 0000000000000..8769d7bdcde1f

[ ... ]

Quoted 10 lines
drivers/gpu/drm/fabric/drm_fabric.c new file +10 -0
+/*
+ * Returns NULL if no endpoint matches, or ERR_PTR(-EINVAL) if @devname is
+ * ambiguous across buses and @busname does not disambiguate it.
+ */
+struct drm_fabric_endpoint *
+drm_fabric_endpoint_find_by_dev_name(const char *devname, const char *busname)
+{
+	struct drm_fabric_endpoint *match = NULL;
+	struct drm_fabric_endpoint *ep;
+	unsigned long idx;

drivers/gpu/drm/fabric/drm_fabric.c line 91

Quoted 10 lines
drivers/gpu/drm/fabric/drm_fabric.c new file +10 -0
+
+	lockdep_assert_held(&drm_fabric_lock);
+	xa_for_each(&drm_fabric_ep_xa, idx, ep) {
+		if (strcmp(dev_name(ep->parent), devname))
+			continue;
+
+		if (busname) {
+			if (strcmp(dev_bus_name(ep->parent), busname))
+				continue;
+			return ep;

[Severity: Medium]
Does this early return bypass the ambiguity check if a single parent device registers multiple endpoints?

When a busname is provided, this path returns the very first matching endpoint it finds. If a device matching both the devname and busname has registered multiple endpoints, this silently resolves to the first one instead of rejecting the ambiguous lookup with ERR_PTR(-EINVAL).

The code block just below this handles the ambiguity correctly when busname is not provided. Should the busname path also continue checking the rest of the xarray to ensure only one match exists?

Quoted 10 lines
drivers/gpu/drm/fabric/drm_fabric.c new file +10 -0
+		}
+
+		if (match)
+			return ERR_PTR(-EINVAL);
+
+		match = ep;
+	}
+
+	return match;
+}

[ ... ]

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
#3 lore raw

RFC PATCH 2/12 drm/fabric: add query uAPI and generated headers

In reply to Konstantin Sinyuk

From: Ilia Levi <[email protected]>

Add a YNL specification for the drm-fabric Generic Netlink family and generate its userspace and kernel headers, giving the object model from the previous patch a userspace-visible wire format.

The read-only ABI provides FABRIC_GET, ENDPOINT_GET, PORT_GET and PORT_STATS_GET as single lookups and multipart dumps. Notifications report fabric and endpoint lifecycle, peer adjacency and port state through the monitor multicast group.

The wire format separates core-assigned object IDs from provider-defined endpoint and peer identities and carries a topology-generation token. Document the family, the YAML-as-contract rule and the append-only stability guarantees in Documentation/gpu/drm-fabric.rst, together with the full identity and consistency semantics.

Generate the headers from the tree root with:

  tools/net/ynl/pyynl/ynl_gen_c.py --mode uapi --header \
      --spec Documentation/netlink/specs/drm_fabric.yaml \
      -o include/uapi/drm/drm_fabric.h
  tools/net/ynl/pyynl/ynl_gen_c.py --mode kernel --header \
      --spec Documentation/netlink/specs/drm_fabric.yaml \
      -o drivers/gpu/drm/fabric/drm_fabric_nl.h

The generated operation and policy source references the doit and dumpit handlers, so it lands with their implementation in the next patch. The generated uAPI header replaces the enums defined locally in the previous patch.

Assisted-by GitHub-Copilot:claude-opus-4.8
---
 Documentation/gpu/drm-fabric.rst            |  35 ++
 Documentation/netlink/specs/drm_fabric.yaml | 427 ++++++++++++++++++++
 drivers/gpu/drm/fabric/drm_fabric_nl.h      |  36 ++
 include/drm/drm_fabric.h                    |  21 +-
 include/uapi/drm/drm_fabric.h               | 134 ++++++
 5 files changed, 635 insertions(+), 18 deletions(-)
 create mode 100644 Documentation/netlink/specs/drm_fabric.yaml
 create mode 100644 drivers/gpu/drm/fabric/drm_fabric_nl.h
 create mode 100644 include/uapi/drm/drm_fabric.h
Documentation/gpu/drm-fabric.rst +35 -0
index 99b189dc614e..d2c9e694b67f 100644
@@ -140,3 +140,38 @@ error return, warns and performs no teardown. Endpoint registration rejects a
 departed parent the same way. These checks prove current address membership
 only: they cannot tell an earlier incarnation from another object registered
 later at the same address.
+
+Generic Netlink family
+======================
+
+DRM Fabric is exposed through the ``drm-fabric`` Generic Netlink family.
+Dump enumeration and asynchronous notifications fit this multi-object model
+better than one-value-per-file sysfs. The family follows the YAML/ynl
+discipline used by DRM RAS; devlink's device hierarchy does not represent a
+fabric spanning multiple DRM devices.
+
+YAML specification
+------------------
+
+The interface is described in a YAML specification
+``Documentation/netlink/specs/drm_fabric.yaml``, which is the source of truth for
+the wire format. It auto-generates the uAPI header
+(``include/uapi/drm/drm_fabric.h``) and the kernel glue via
+``tools/net/ynl/pyynl/ynl_gen_c.py``. Generated files must never be edited by
+hand; regenerate them with ``tools/net/ynl/ynl-regen.sh`` after any spec change.
+
+uAPI stability
+--------------
+
+The YAML specification is the contract. New attributes, commands and enum values
+are added append-only; existing attribute numbers, command numbers and meanings
+are never reused. Requests are strictly validated, so an unknown attribute in a
+request is rejected; user space should ignore attributes it does not recognize
+in replies and notifications. The family is versioned through
+``DRM_FABRIC_FAMILY_VERSION``.
+
+Kernel-local ``fabric-id`` and ``endpoint-id`` values identify live registry
+objects and are not persistent hardware identities: they remain valid for the
+lifetime of the registered object, but may disappear or be reused after the
+object is unregistered. ``instance-id`` and ``fabric-ep-id`` carry
+provider-defined identity, whose scope is described by the containing object.
Documentation/netlink/specs/drm_fabric.yaml new file +427 -0

427 lines not on this page · raw message

drivers/gpu/drm/fabric/drm_fabric_nl.h new file +36 -0
new file mode 100644
index 000000000000..8cedc004260f
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
+/* Do not edit directly, auto-generated from: */
+/*	Documentation/netlink/specs/drm_fabric.yaml */
+/* YNL-GEN kernel header */
+/* To regenerate run: tools/net/ynl/ynl-regen.sh */
+
+#ifndef _LINUX_DRM_FABRIC_GEN_H
+#define _LINUX_DRM_FABRIC_GEN_H
+
+#include <net/netlink.h>
+#include <net/genetlink.h>
+
+#include <uapi/drm/drm_fabric.h>
+
+int drm_fabric_nl_fabric_get_doit(struct sk_buff *skb, struct genl_info *info);
+int drm_fabric_nl_fabric_get_dumpit(struct sk_buff *skb,
+				    struct netlink_callback *cb);
+int drm_fabric_nl_endpoint_get_doit(struct sk_buff *skb,
+				    struct genl_info *info);
+int drm_fabric_nl_endpoint_get_dumpit(struct sk_buff *skb,
+				      struct netlink_callback *cb);
+int drm_fabric_nl_port_get_doit(struct sk_buff *skb, struct genl_info *info);
+int drm_fabric_nl_port_get_dumpit(struct sk_buff *skb,
+				  struct netlink_callback *cb);
+int drm_fabric_nl_port_stats_get_doit(struct sk_buff *skb,
+				      struct genl_info *info);
+int drm_fabric_nl_port_stats_get_dumpit(struct sk_buff *skb,
+					struct netlink_callback *cb);
+
+enum {
+	DRM_FABRIC_NLGRP_MONITOR,
+};
+
+extern struct genl_family drm_fabric_nl_family;
+
+#endif /* _LINUX_DRM_FABRIC_GEN_H */
include/drm/drm_fabric.h +3 -18
index 68d8acec2d38..136100b3da67 100644
@@ -4,8 +4,8 @@
  */
 
 /*
- * DRM Fabric driver API: common object model for GPU interconnect topology
- * (fabric, endpoint, port and peer relationships).
+ * Common object model for GPU interconnect topology: fabric, endpoint, port
+ * and peer relationships.
  */
 
 #ifndef __DRM_FABRIC_H__
@@ -16,22 +16,7 @@
 #include <linux/types.h>
 #include <linux/xarray.h>
 
-enum drm_fabric_type {
-	/* Zero is invalid; concrete fabric types start at 1. */
-	DRM_FABRIC_TYPE_SYNTHETIC = 1,
-};
-
-enum drm_fabric_port_state {
-	DRM_FABRIC_PORT_STATE_UNKNOWN,
-	DRM_FABRIC_PORT_STATE_INACTIVE,
-	DRM_FABRIC_PORT_STATE_ACTIVE,
-	DRM_FABRIC_PORT_STATE_DEGRADED,
-};
-
-enum drm_fabric_peer_type {
-	DRM_FABRIC_PEER_TYPE_ACCEL = 1,
-	DRM_FABRIC_PEER_TYPE_SWITCH,
-};
+#include <uapi/drm/drm_fabric.h>
 
 struct device;
 
include/uapi/drm/drm_fabric.h new file +134 -0

134 lines not on this page · raw message

Signature · 1 line
2.43.0
#4 lore raw

Re: [RFC PATCH 02/12] drm/fabric: add query uAPI and generated headers

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [Medium] The Netlink YAML specification uses fixed-width integer types (`u32`, `u64`) and `pad`…

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] The Netlink YAML specification uses fixed-width integer types (u32, u64) and pad attributes instead of the preferred variable-width types (uint, sint).
- [Medium] The port-peer-create-ntf and port-peer-delete-ntf notifications use custom event subsets instead of reusing the GET operation shape via notify. --

--- Patch [2]: [RFC PATCH 02/12] drm/fabric: add query uAPI and generated headers --- commit 180af4ca3a8c57e81df2225599a4c339598edf21
Author: Ilia Levi <[email protected]>

drm/fabric: add query uAPI and generated headers

This commit introduces the drm-fabric Generic Netlink family using a YNL specification, along with generated userspace and kernel headers. It defines the core object model attributes, operations, and multicast notifications. The read-only ABI supports lookup, dump, and change notifications for fabrics, endpoints, and ports.

Quoted 5 lines
Documentation/netlink/specs/drm_fabric.yaml new file +0 -0
new file mode 100644
index 0000000000000..778443d92a0d4

[ ... ]

Documentation/netlink/specs/drm_fabric.yaml line 123

Quoted 12 lines
Documentation/netlink/specs/drm_fabric.yaml new file +12 -0
+  -
+    name: fabric
+    name-prefix: drm-fabric-a-fabric-attrs-
+    enum-name: drm-fabric-a-fabric-attrs
+    doc: Attributes describing a fabric object.
+    attributes:
+      -
+        name: pad
+        type: pad
+      -
+        name: fabric-id
+        type: u32

[Severity: Medium]
Since this is a new Netlink family, should we prefer the variable-width uint or sint types instead of fixed-width u32 and u64 integers?

The pad attribute is also generally restricted to legacy fixed structs. Changing this before the uAPI is finalized might be a good idea to maintain consistency with modern Netlink design guidelines.

[ ... ]

Quoted 11 lines
Documentation/netlink/specs/drm_fabric.yaml new file +11 -0
+    -
+      name: port-peer-create-ntf
+      doc: A port's neighbor has been set.
+      attribute-set: drm-fabric
+      event:
+        attributes:
+          - endpoint-id
+          - port-index
+          - peer
+          - topology-generation
+

Documentation/netlink/specs/drm_fabric.yaml line 391

Quoted 10 lines
Documentation/netlink/specs/drm_fabric.yaml new file +10 -0
+    -
+      name: port-peer-delete-ntf
+      doc: A port's neighbor has been unset.
+      attribute-set: drm-fabric
+      event:
+        attributes:
+          - endpoint-id
+          - port-index
+          - peer
+          - topology-generation

[Severity: Medium]
Could we use notify: port-get for these notifications instead of custom event subsets?

Events are considered less idiomatic than notify operations, which share contents with the GET op. Since peer information is queryable via port-get, reusing the port-get shape here would avoid forcing userspace to implement separate parsing logic for these notifications.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
#5 lore raw

RFC PATCH 3/12 drm/fabric: implement query netlink operations

In reply to Konstantin Sinyuk

Register the drm-fabric Generic Netlink family and connect the four read-only query commands to the core object model, adding the generated operation and policy source that dispatches to them. Their reply shapes are:

  fabric-get       -> fabric, topology-generation
  endpoint-get     -> endpoint, topology-generation
  port-get         -> port, topology-generation
  port-stats-get   -> port-stats

Support single-object lookup and multipart dumps for fabrics, endpoints and ports, with optional fabric and endpoint filters. Preserve the nested endpoint/port dump cursor across batches, including endpoint removal and terminal port indices.

Port statistics are optional: a targeted unsupported request returns -EOPNOTSUPP, while a dump skips unsupported ports and continues; other provider errors terminate the dump. Use topology-generation for dump consistency and report concurrent changes with NLM_F_DUMP_INTR.

Emit fabric, endpoint, port-state and peer notifications through the monitor multicast group. Advance topology-generation before emitting each notification, so the event carries the same post-change value as a later query.

Queries and notifications are confined to init_net. The query commands, notifications and dump-consistency behavior are documented in Documentation/gpu/drm-fabric.rst.

Assisted-by GitHub-Copilot:claude-opus-4.8
---
 Documentation/gpu/drm-fabric.rst             |  148 ++-
 drivers/gpu/drm/fabric/Kconfig               |    6 +-
 drivers/gpu/drm/fabric/Makefile              |    2 +-
 drivers/gpu/drm/fabric/drm_fabric.c          |   29 +-
 drivers/gpu/drm/fabric/drm_fabric_internal.h |   19 +
 drivers/gpu/drm/fabric/drm_fabric_netlink.c  | 1035 ++++++++++++++++++
 drivers/gpu/drm/fabric/drm_fabric_nl.c       |  125 +++
 7 files changed, 1345 insertions(+), 19 deletions(-)
 create mode 100644 drivers/gpu/drm/fabric/drm_fabric_netlink.c
 create mode 100644 drivers/gpu/drm/fabric/drm_fabric_nl.c
Documentation/gpu/drm-fabric.rst +142 -6
index d2c9e694b67f..a8b33d6cd618 100644
@@ -18,8 +18,8 @@ Key Goals:
   (xGMI, UALink and similar), enabling data-center discovery and monitoring.
 * Support read-only enumeration, monitoring and state queries for
   provider-owned topology.
-* Offer a flexible, future-proof interface that can be extended with new fabric
-  types and attributes without breaking the uAPI.
+* Allow new attributes and fabric types to be added without reusing existing
+  wire identifiers, so the uAPI extends without breaking existing consumers.
 * Allow multiple endpoints and ports per provider, so drivers can model
   accelerator attachments, links and their peers.
 
@@ -84,10 +84,14 @@ an accelerator on another node, or a local endpoint that merely unregistered
 -- so only the provider knows when a port's physical adjacency actually
 changed, and only the provider retracts or replaces the descriptor.
 
-Endpoint teardown removes the endpoint's owned half-edges without generating
-a separate event for each port: the delete already describes the transition,
-so removing an endpoint advances the topology generation once rather than
-once per child port.
+``port-peer-delete-ntf`` reports an explicitly retracted half-edge; it is
+not emitted when a peer merely becomes locally unresolvable, so its absence
+is not evidence the far end is still reachable.
+
+Endpoint teardown removes the endpoint's owned half-edges without
+generating a separate event for each port: the delete already describes
+the transition, so removing an endpoint advances the topology generation
+once rather than once per child port.
 
 Driver API
 ----------
@@ -175,3 +179,135 @@ objects and are not persistent hardware identities: they remain valid for the
 lifetime of the registered object, but may disappear or be reused after the
 object is unregistered. ``instance-id`` and ``fabric-ep-id`` carry
 provider-defined identity, whose scope is described by the containing object.
+
+Query operations
+================
+
+User space enumerates topology with four read-only commands, each supporting a
+single lookup (``do``) and a bulk dump (``dump``):
+
+* ``fabric-get`` -- enumerate fabrics (``do`` by ``fabric-id``, ``dump`` for all).
+* ``endpoint-get`` -- enumerate endpoints, optionally filtered by ``fabric-id``,
+  or resolve one by ``endpoint-id`` or backing ``dev-name``/``bus-name``.
+* ``port-get`` -- enumerate ports, filtered by ``endpoint-id``. Ports may report
+  the provider's maximum capability as ``max-lane-count`` and
+  ``max-lane-signaling-rate-mbps`` (zero means unknown); these are maxima, not
+  the currently negotiated width or rate.
+* ``port-stats-get`` -- per-port statistics, filtered by ``endpoint-id``. A
+  targeted request for a port whose provider does not implement
+  ``port_stats_get`` returns ``-EOPNOTSUPP``. During a dump, ports without
+  statistics support are omitted and enumeration continues with later ports;
+  any other provider error ends the dump.
+
+Notifications
+-------------
+
+Subscribe to the ``monitor`` multicast group to receive asynchronous change
+notifications. Full-object notifications reuse the shape of their matching
+``get`` reply and are declared with ``notify:``; peer-link notifications carry
+a partial payload and are declared with ``event:``.
+
+.. list-table::
+   :header-rows: 1
+
+   * - Notification
+     - Trigger
+     - Payload
+   * - ``fabric-create-ntf``
+     - a fabric is registered by a provider
+     - reuses ``fabric-get``
+   * - ``fabric-delete-ntf``
+     - a provider-owned fabric is unregistered
+     - reuses ``fabric-get``
+   * - ``endpoint-create-ntf``
+     - an endpoint is registered
+     - reuses ``endpoint-get``
+   * - ``endpoint-delete-ntf``
+     - an endpoint is unregistered
+     - reuses ``endpoint-get``
+   * - ``port-change-ntf``
+     - a port's operational state changes
+     - reuses ``port-get``
+   * - ``port-peer-create-ntf``
+     - a port's peer descriptor is set by its provider
+     - partial (``event:``)
+   * - ``port-peer-delete-ntf``
+     - a port's peer descriptor is explicitly unset by its provider; never
+       emitted for an implicit half-edge loss (see `Peer semantics`_)
+     - partial (``event:``)
+
+Notifications are best-effort. A listener that detects loss, restarts, or
+receives an interrupted dump must rebuild state with the query commands.
+
+Topology generation and dump consistency
+----------------------------------------
+
+The core keeps a nonzero generation counter and advances it whenever topology or
+exposed state changes. It is surfaced as the ``topology-generation`` attribute on
+``fabric-get``, ``endpoint-get`` and ``port-get`` replies and on the topology
+notifications. A provider-reported change advances the generation before its
+notification is serialized, so an event carries the post-change value that a
+later ``get``/``dump`` will also report.
+
+``topology-generation`` is a change token, not a timestamp, liveness counter or
+event count: a changed value means topology changed, but the delta between two
+values has no defined meaning and the counter may wrap (it skips zero). Statistics
+reads do not advance it.
+
+The same value backs dump consistency. Every multipart dump samples it and calls
+``genl_dump_check_consistent()``; if it changes between dump batches, Generic
+Netlink marks the dump with ``NLM_F_DUMP_INTR``, meaning the snapshot may be torn.
+User space must then discard the partial result and retry the complete dump. The
+generation does not apply to statistics reads.
+
+Only a dump that serialized at least one entry can carry ``NLM_F_DUMP_INTR``,
+because Generic Netlink arms the consistency check on the first entry it emits.
+A dump that yields no entries at all cannot report interruption, so user space
+should treat an empty result as advisory and re-read ``topology-generation``
+before concluding that the topology is empty.
+
+Namespaces
+----------
+
+DRM Fabric objects describe host-global hardware and are not scoped per network
+namespace. Query and dump operations (``*-get``) are therefore accepted only from
+the initial network namespace; a request from any other network namespace fails
+with ``-EPERM``. The Generic Netlink family is registered ``netnsok`` (so it
+resolves in any network namespace and can return that policy error rather than
+being invisible), but the operations themselves remain confined to ``init_net``.
+Monitor notifications are likewise emitted only into ``init_net``, so a listener
+that joins the multicast group from another network namespace never receives
+them.
+
+Examples
+========
+
+Query the topology with the in-tree YNL tool, pointing it at the spec:
+
+.. code-block:: bash
+
+    # List all fabrics
+    ./tools/net/ynl/pyynl/cli.py \
+        --spec Documentation/netlink/specs/drm_fabric.yaml \
+        --dump fabric-get
+
+Replies follow the shapes described above; a provider must be registered for
+the topology to be non-empty.
+
+List the endpoints of a fabric:
+
+.. code-block:: bash
+
+    ./tools/net/ynl/pyynl/cli.py \
+        --spec Documentation/netlink/specs/drm_fabric.yaml \
+        --dump endpoint-get --json '{"fabric-id": 1}'
+
+Query a single port:
+
+.. code-block:: bash
+
+    ./tools/net/ynl/pyynl/cli.py \
+        --spec Documentation/netlink/specs/drm_fabric.yaml \
+        --do port-get --json '{"endpoint-id": 1, "port-index": 0}'
+
+The family name on the wire is ``drm-fabric``.
drivers/gpu/drm/fabric/Kconfig +3 -3
index 21fbfae9863d..7e9c569fd258 100644
@@ -4,9 +4,9 @@ config DRM_FABRIC
 	tristate "DRM fabric support"
 	depends on DRM && NET
 	help
-	  Enable DRM fabric support. This infrastructure provides the
-	  core object model and provider API for registered accelerator
-	  interconnect topologies.
+	  Enable DRM fabric support. This infrastructure exposes
+	  registered accelerator interconnect topologies to userspace
+	  through the drm-fabric generic netlink family.
 
 	  To compile this as a module, choose M here: the module will be
 	  called drm-fabric.
drivers/gpu/drm/fabric/Makefile +1 -1
index 3a76f31f1e83..cf9d9d6be3d3 100644
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
 obj-$(CONFIG_DRM_FABRIC) += drm-fabric.o
-drm-fabric-y := drm_fabric.o
+drm-fabric-y := drm_fabric.o drm_fabric_netlink.o drm_fabric_nl.o
drivers/gpu/drm/fabric/drm_fabric.c +20 -9
index 8769d7bdcde1..ce331656af70 100644
@@ -186,7 +186,7 @@ struct drm_fabric *drm_fabric_register(const struct drm_fabric_desc *desc)
 			       xa_limit_32b, GFP_KERNEL);
 		if (ret)
 			return ERR_PTR(ret);
-		drm_fabric_base_seq_inc();
+		drm_fabric_emit_fabric_create(fabric, drm_fabric_base_seq_inc());
 	}
 
 	return_ptr(fabric);
@@ -270,7 +270,9 @@ int drm_fabric_unregister(struct drm_fabric *fabric)
 		 */
 		if (WARN_ON_ONCE(drm_fabric_has_members(fabric)))
 			return -EBUSY;
-		drm_fabric_base_seq_inc();
+		/* Emit before the erase, while @fabric is still live. */
+		drm_fabric_emit_fabric_delete(fabric,
+					      drm_fabric_base_seq_inc());
 		xa_erase(&drm_fabric_xa, fabric->id);
 	}
 
@@ -410,7 +412,7 @@ drm_fabric_endpoint_register(struct drm_fabric *fabric,
 			break;
 		drm_fabric_get(fabric);
 
-		drm_fabric_base_seq_inc();
+		drm_fabric_emit_endpoint_create(ep, drm_fabric_base_seq_inc());
 	}
 
 	if (ret) {
@@ -499,7 +501,8 @@ void drm_fabric_endpoint_unregister(struct drm_fabric_endpoint *ep)
 	scoped_guard(mutex, &drm_fabric_lock) {
 		if (WARN_ON_ONCE(!drm_fabric_ep_is_registered(ep)))
 			return;
-		drm_fabric_base_seq_inc();
+		/* Emit before the erase, while @ep is still live. */
+		drm_fabric_emit_endpoint_delete(ep, drm_fabric_base_seq_inc());
 		xa_erase(&drm_fabric_ep_xa, ep->id);
 	}
 
@@ -587,7 +590,8 @@ int drm_fabric_port_set_peer(struct drm_fabric_port *port,
 			return -EEXIST;
 		port->peer = *peer;
 		port->has_peer = true;
-		drm_fabric_base_seq_inc();
+		drm_fabric_emit_port_peer_create(port, peer,
+						 drm_fabric_base_seq_inc());
 	}
 
 	return 0;
@@ -612,7 +616,9 @@ int drm_fabric_port_unset_peer(struct drm_fabric_port *port)
 	scoped_guard(mutex, &drm_fabric_lock) {
 		if (!port->has_peer)
 			return -ENOENT;
-		drm_fabric_base_seq_inc();
+		/* Emit before clearing to show the peer being removed. */
+		drm_fabric_emit_port_peer_delete(port, &port->peer,
+						 drm_fabric_base_seq_inc());
 		port->has_peer = false;
 		memset(&port->peer, 0, sizeof(port->peer));
 	}
@@ -654,19 +660,24 @@ void drm_fabric_port_set_oper(struct drm_fabric_port *port,
 		enum drm_fabric_port_state old = port->oper_state;
 
 		port->oper_state = state;
-		if (old != state)
-			drm_fabric_base_seq_inc();
+		if (old != state) {
+			u32 gen = drm_fabric_base_seq_inc();
+
+			drm_fabric_emit_port_change(port, gen);
+		}
 	}
 }
 EXPORT_SYMBOL(drm_fabric_port_set_oper);
 
 static int __init drm_fabric_init(void)
 {
-	return 0;
+	return drm_fabric_netlink_register();
 }
 
 static void __exit drm_fabric_exit(void)
 {
+	drm_fabric_netlink_unregister();
+
 	WARN_ON(!xa_empty(&drm_fabric_xa));
 	WARN_ON(!xa_empty(&drm_fabric_ep_xa));
 	xa_destroy(&drm_fabric_xa);
drivers/gpu/drm/fabric/drm_fabric_internal.h +19 -0
index d454225a0b81..7fc5bc3f33f9 100644
@@ -18,6 +18,9 @@ extern struct xarray drm_fabric_ep_xa; /* Endpoint registry */
 
 extern u32 drm_fabric_base_seq;        /* Dump consistency sequence */
 
+int drm_fabric_netlink_register(void);
+void drm_fabric_netlink_unregister(void);
+
 struct drm_fabric *drm_fabric_find_by_id(u32 id);
 struct drm_fabric_endpoint *drm_fabric_endpoint_find_by_id(u32 id);
 struct drm_fabric_endpoint *
@@ -31,4 +34,20 @@ void drm_fabric_endpoint_put(struct drm_fabric_endpoint *ep);
 struct drm_fabric *drm_fabric_get(struct drm_fabric *fabric);
 void drm_fabric_put(struct drm_fabric *fabric);
 
+/* Emits use the post-change generation. */
+void drm_fabric_emit_endpoint_create(struct drm_fabric_endpoint *ep, u32 generation);
+void drm_fabric_emit_endpoint_delete(struct drm_fabric_endpoint *ep, u32 generation);
+
+void drm_fabric_emit_port_peer_create(struct drm_fabric_port *port,
+				      const struct drm_fabric_peer *peer,
+				      u32 generation);
+void drm_fabric_emit_port_peer_delete(struct drm_fabric_port *port,
+				      const struct drm_fabric_peer *peer,
+				      u32 generation);
+
+void drm_fabric_emit_port_change(struct drm_fabric_port *port, u32 generation);
+
+void drm_fabric_emit_fabric_create(struct drm_fabric *fabric, u32 generation);
+void drm_fabric_emit_fabric_delete(struct drm_fabric *fabric, u32 generation);
+
 #endif /* __DRM_FABRIC_INTERNAL_H__ */
drivers/gpu/drm/fabric/drm_fabric_netlink.c new file +1035 -0

1,035 lines not on this page · raw message

drivers/gpu/drm/fabric/drm_fabric_nl.c new file +125 -0

125 lines not on this page · raw message

Signature · 1 line
2.43.0
#6 lore raw

Re: [RFC PATCH 03/12] drm/fabric: implement query netlink operations

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] Ambiguity check bypass in endpoint resolution when busname is provided. --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Ambiguity check bypass in endpoint resolution when busname is provided. --

--- Patch [3]: [RFC PATCH 03/12] drm/fabric: implement query netlink operations --- commit ec7b295b3219dced2d6c1d65d7829fa5aa0283c3
Author: Konstantin Sinyuk <[email protected]>
Subject: drm/fabric: implement query netlink operations

This commit registers the drm-fabric Generic Netlink family and connects read-only query commands to the core object model. It supports single-object lookup and multipart dumps for fabrics, endpoints, and ports.

Quoted 4 lines
drivers/gpu/drm/fabric/drm_fabric_netlink.c new file +0 -0
new file mode 100644

[ ... ]

Quoted 15 lines
drivers/gpu/drm/fabric/drm_fabric_netlink.c new file +15 -0
+/* Identified by core-assigned id, or by bus + dev name. */
+static struct drm_fabric_endpoint *
+drm_fabric_resolve_endpoint(struct genl_info *info)
+{
+	struct nlattr **attrs = info->attrs;
+	const char *devname = NULL;
+	const char *busname = NULL;
+	struct drm_fabric_endpoint *ep;
+
+	lockdep_assert_held(&drm_fabric_lock);
+
+	if (attrs[DRM_FABRIC_A_DEV_NAME])
+		devname = nla_data(attrs[DRM_FABRIC_A_DEV_NAME]);
+	if (attrs[DRM_FABRIC_A_BUS_NAME])
+		busname = nla_data(attrs[DRM_FABRIC_A_BUS_NAME]);

[ ... ]

drivers/gpu/drm/fabric/drm_fabric_netlink.c line 319

Quoted 4 lines
drivers/gpu/drm/fabric/drm_fabric_netlink.c new file +4 -0
+	if (!devname)
+		return ERR_PTR(-EINVAL);
+
+	ep = drm_fabric_endpoint_find_by_dev_name(devname, busname);

[Severity: High]
Does this lookup bypass the ambiguity check when both devname and busname are provided?

Looking at drm_fabric_endpoint_find_by_dev_name() in drm_fabric.c:

drm_fabric_endpoint_find_by_dev_name() {
    ...
    xa_for_each(&drm_fabric_ep_xa, idx, ep) {
        if (strcmp(dev_name(ep->parent), devname))
            continue;

        if (busname) {
            if (strcmp(dev_bus_name(ep->parent), busname))
                continue;
            return ep;
        }
    ...
}

When busname is matched, the loop immediately returns the first matched endpoint instead of assigning it to the match variable and continuing the loop. If multiple endpoints are registered by the same physical device (sharing the exact same devname and busname), could this cause userspace queries to silently succeed and operate on the wrong endpoint instead of returning an ambiguity error?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
#7 lore raw

RFC PATCH 4/12 drm/fabric: add read-only synthetic provider

In reply to Konstantin Sinyuk

Add drm_fabric_sim (fabricsim), a software-only provider modeled on netdevsim. It registers deterministic linear, mesh and switch-facing topologies through the same provider API a hardware driver uses, so the object model and query uAPI can be exercised without accelerator hardware. The switch shape uses opaque peers that do not resolve to registered endpoints.

CONFIG_DRM_FABRIC_SIM builds the provider as drm-fabric-sim.ko. Module parameters select the topology shape and initial endpoint and port counts.

With topology=linear num_endpoints=2, an endpoint is queried using the in-tree YNL tool:

  $ ./tools/net/ynl/pyynl/cli.py \
        --spec Documentation/netlink/specs/drm_fabric.yaml \
        --do endpoint-get --json '{"endpoint-id": 1}'
  {'endpoint': {'bus-name': 'platform',
                'dev-name': 'fabricsim.1',
                'endpoint-id': 1,
                'fabric-ep-id': 257,
                'fabric-id': 1,
                'name': 'sim-ep1'},
   'topology-generation': 18}

The reply separates the core-assigned endpoint-id from the provider-defined fabric-ep-id and carries the topology-generation token.

Report maximum link capabilities at registration, operational state through drm_fabric_port_set_oper() and optional port statistics through the port_stats_get callback.

Test-only debugfs controls stimulate provider behavior for the selftests. They are not uAPI; observable results are reported through the drm-fabric Generic Netlink family.

Assisted-by GitHub-Copilot:claude-opus-4.8
---
 Documentation/gpu/drm-fabric.rst        |  46 +-
 drivers/gpu/drm/fabric/Kconfig          |  10 +
 drivers/gpu/drm/fabric/Makefile         |   3 +
 drivers/gpu/drm/fabric/drm_fabric_sim.c | 978 ++++++++++++++++++++++++
 4 files changed, 1034 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/fabric/drm_fabric_sim.c
Documentation/gpu/drm-fabric.rst +43 -3
index a8b33d6cd618..8bd3633d41be 100644
@@ -291,10 +291,16 @@ Query the topology with the in-tree YNL tool, pointing it at the spec:
         --spec Documentation/netlink/specs/drm_fabric.yaml \
         --dump fabric-get
 
-Replies follow the shapes described above; a provider must be registered for
-the topology to be non-empty.
+Against drm_fabric_sim loaded with ``topology=linear num_endpoints=2``
+(both non-default, for a minimal example), this returns:
 
-List the endpoints of a fabric:
+.. code-block:: text
+
+    [{'fabric': {'fabric-id': 1, 'instance-id': 2156317438,
+                 'name': 'fabricsim', 'type': 'synthetic'},
+      'topology-generation': 18}]
+
+List the endpoints of that fabric:
 
 .. code-block:: bash
 
@@ -302,6 +308,15 @@ List the endpoints of a fabric:
         --spec Documentation/netlink/specs/drm_fabric.yaml \
         --dump endpoint-get --json '{"fabric-id": 1}'
 
+.. code-block:: text
+
+    [{'endpoint': {'bus-name': 'platform', 'dev-name': 'fabricsim.0',
+                   'endpoint-id': 0, 'fabric-ep-id': 256, 'fabric-id': 1,
+                   'name': 'sim-ep0'}, 'topology-generation': 18},
+     {'endpoint': {'bus-name': 'platform', 'dev-name': 'fabricsim.1',
+                   'endpoint-id': 1, 'fabric-ep-id': 257, 'fabric-id': 1,
+                   'name': 'sim-ep1'}, 'topology-generation': 18}]
+
 Query a single port:
 
 .. code-block:: bash
@@ -310,4 +325,29 @@ Query a single port:
         --spec Documentation/netlink/specs/drm_fabric.yaml \
         --do port-get --json '{"endpoint-id": 1, "port-index": 0}'
 
+.. code-block:: text
+
+    {'port': {'endpoint-id': 1, 'max-lane-count': 4,
+              'max-lane-signaling-rate-mbps': 200000, 'oper-state': 'active',
+              'peer': {'peer-id': 256, 'port-index': 0, 'type': 'accel'},
+              'port-index': 0},
+     'topology-generation': 18}
+
 The family name on the wire is ``drm-fabric``.
+
+Synthetic provider
+==================
+
+``CONFIG_DRM_FABRIC_SIM`` builds ``drm-fabric-sim.ko``, a software-only provider
+modeled on netdevsim (Documentation/networking/devlink/netdevsim.rst) that drives
+the object model and uAPI without real hardware. Module parameters select a
+linear, mesh or switch-shaped topology and bound the number of endpoints and
+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.
+
+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
+Generic Netlink family. Tests mutate simulator state through debugfs and observe
+the result over Generic Netlink.
drivers/gpu/drm/fabric/Kconfig +10 -0
index 7e9c569fd258..87115356baca 100644
@@ -12,3 +12,13 @@ config DRM_FABRIC
 	  called drm-fabric.
 
 	  If in doubt, say N.
+
+config DRM_FABRIC_SIM
+	tristate "DRM fabric synthetic provider (test-only)"
+	depends on DRM_FABRIC
+	help
+	  Synthetic provider for testing drm_fabric topology and ABI.
+	  Provides debugfs-only hooks for synthetic activity generation,
+	  error injection, and port-state transitions.  These hooks are
+	  NOT part of the drm_fabric uAPI and are used only by selftests.
+	  Does not model UALink protocol traffic or memory semantics.
drivers/gpu/drm/fabric/Makefile +3 -0
index cf9d9d6be3d3..bc0a6c742164 100644
@@ -2,3 +2,6 @@
 
 obj-$(CONFIG_DRM_FABRIC) += drm-fabric.o
 drm-fabric-y := drm_fabric.o drm_fabric_netlink.o drm_fabric_nl.o
+
+obj-$(CONFIG_DRM_FABRIC_SIM) += drm-fabric-sim.o
+drm-fabric-sim-y := drm_fabric_sim.o
drivers/gpu/drm/fabric/drm_fabric_sim.c new file +978 -0

978 lines not on this page · raw message

Signature · 1 line
2.43.0
#8 lore raw

RFC PATCH 5/12 drm/fabric: add object-model KUnit tests

In reply to Konstantin Sinyuk

The object model has invariants a refactor can break: identity scope, borrowed port lifetime, topology-generation updates and the context in which provider callbacks run.

Build the tests into drm_fabric.o under CONFIG_DRM_FABRIC_KUNIT_TEST so no test-only symbols need to be exported.

Coverage includes registration and identity uniqueness, object lifetime, half-edge peer state, topology-generation changes and provider ops wiring. Linear and mesh topologies are parameterized. Unregister rejects a non-member pointer, including one carrying a registered object's identifier.

Provide .kunitconfig for UML and .kunitconfig.debug for x86-64 with KASAN, KMEMLEAK, UBSAN, PROVE_LOCKING and DEBUG_ATOMIC_SLEEP.

  $ ./tools/testing/kunit/kunit.py run \
        --kunitconfig=drivers/gpu/drm/fabric/.kunitconfig
  [...]
  Testing complete. Ran 31 tests: passed: 31
Assisted-by GitHub-Copilot:claude-opus-4.8
---
 Documentation/gpu/drm-fabric.rst          |    6 +
 drivers/gpu/drm/fabric/.kunitconfig       |    5 +
 drivers/gpu/drm/fabric/.kunitconfig.debug |   16 +
 drivers/gpu/drm/fabric/Kconfig            |   16 +
 drivers/gpu/drm/fabric/Makefile           |    2 +
 drivers/gpu/drm/fabric/drm_fabric.c       |    4 +
 drivers/gpu/drm/fabric/drm_fabric_test.c  | 1312 +++++++++++++++++++++
 7 files changed, 1361 insertions(+)
 create mode 100644 drivers/gpu/drm/fabric/.kunitconfig
 create mode 100644 drivers/gpu/drm/fabric/.kunitconfig.debug
 create mode 100644 drivers/gpu/drm/fabric/drm_fabric_test.c
Documentation/gpu/drm-fabric.rst +6 -0
index 8bd3633d41be..cd98a97e1662 100644
@@ -351,3 +351,9 @@ 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
 Generic Netlink family. Tests mutate simulator state through debugfs and observe
 the result over Generic Netlink.
+
+Testing
+=======
+
+The object model is covered by KUnit when ``CONFIG_DRM_FABRIC_KUNIT_TEST`` is
+enabled. The test source is folded into the core translation unit.
drivers/gpu/drm/fabric/.kunitconfig new file +5 -0
new file mode 100644
index 000000000000..d6087f45f2ac
@@ -0,0 +1,5 @@
+CONFIG_KUNIT=y
+CONFIG_NET=y
+CONFIG_DRM=y
+CONFIG_DRM_FABRIC=y
+CONFIG_DRM_FABRIC_KUNIT_TEST=y
drivers/gpu/drm/fabric/.kunitconfig.debug new file +16 -0
new file mode 100644
index 000000000000..8add027fc766
@@ -0,0 +1,16 @@
+CONFIG_KUNIT=y
+CONFIG_NET=y
+CONFIG_DRM=y
+CONFIG_DRM_FABRIC=y
+CONFIG_DRM_FABRIC_KUNIT_TEST=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_KASAN=y
+CONFIG_KASAN_GENERIC=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_UBSAN=y
+CONFIG_UBSAN_BOUNDS=y
+CONFIG_UBSAN_SHIFT=y
+CONFIG_UBSAN_ENUM=y
+CONFIG_UBSAN_BOOL=y
drivers/gpu/drm/fabric/Kconfig +16 -0
index 87115356baca..2a70cac85b1d 100644
@@ -22,3 +22,19 @@ config DRM_FABRIC_SIM
 	  error injection, and port-state transitions.  These hooks are
 	  NOT part of the drm_fabric uAPI and are used only by selftests.
 	  Does not model UALink protocol traffic or memory semantics.
+
+config DRM_FABRIC_KUNIT_TEST
+	bool "DRM fabric object-model KUnit tests" if !KUNIT_ALL_TESTS
+	depends on DRM_FABRIC && KUNIT
+	depends on KUNIT=y || DRM_FABRIC=m
+	default KUNIT_ALL_TESTS
+	help
+	  Enable KUnit coverage for the drm_fabric object model.
+
+	  The tests are built into drm_fabric itself, so they need no exported
+	  symbols or test-only accessors in the production source.
+
+	  For more information on KUnit and unit tests in general, please refer
+	  to the KUnit documentation in Documentation/dev-tools/kunit/.
+
+	  If unsure, say N.
drivers/gpu/drm/fabric/Makefile +2 -0
index bc0a6c742164..05f1c96bb8de 100644
@@ -5,3 +5,5 @@ drm-fabric-y := drm_fabric.o drm_fabric_netlink.o drm_fabric_nl.o
 
 obj-$(CONFIG_DRM_FABRIC_SIM) += drm-fabric-sim.o
 drm-fabric-sim-y := drm_fabric_sim.o
+
+# The tests are included in drm_fabric.o, not built as a separate object.
drivers/gpu/drm/fabric/drm_fabric.c +4 -0
index ce331656af70..bbc3224c3314 100644
@@ -690,3 +690,7 @@ module_exit(drm_fabric_exit);
 MODULE_AUTHOR("Intel Corporation");
 MODULE_DESCRIPTION("DRM fabric infrastructure");
 MODULE_LICENSE("Dual MIT/GPL");
+
+#if IS_ENABLED(CONFIG_DRM_FABRIC_KUNIT_TEST)
+#include "drm_fabric_test.c"
+#endif
drivers/gpu/drm/fabric/drm_fabric_test.c new file +1312 -0

1,312 lines not on this page · raw message

Signature · 1 line
2.43.0
#9 lore raw

RFC PATCH 6/12 drm/fabric: add YNL query and policy selftests

In reply to Konstantin Sinyuk

The read-only Generic Netlink ABI has userspace-visible behavior KUnit cannot reach: policy validation, multipart dumps, notifications and family introspection. These paths require a live netlink socket.

Add eleven kselftest programs using the in-tree YNL client against fabricsim. They cover queries and filters, notifications, malformed policy input, interrupted dumps, nested port-cursor resumption after endpoint removal, mixed per-port statistics support, topology churn, opaque switch peers and provider error propagation.

Shared helpers manage module lifetime and restore fabricsim state between programs. Add the selftest configuration, README and a regeneration guard for the generated uAPI header, kernel header and operation/policy source.

  $ make -C tools/testing/selftests TARGETS=drivers/gpu/drm_fabric \
        run_tests
  [...]
  ok 1 selftests: drivers/gpu/drm_fabric: check-spec-regen.sh
  [...]
  ok 11 selftests: drivers/gpu/drm_fabric: harness_reset_abi.py

The run reports 89 results across eleven programs, all passing in a booted virtme-ng guest.

Assisted-by GitHub-Copilot:claude-opus-4.8
---
 Documentation/gpu/drm-fabric.rst              |   7 +
 tools/testing/selftests/Makefile              |   1 +
 .../selftests/drivers/gpu/drm_fabric/Makefile |  41 ++
 .../drivers/gpu/drm_fabric/README.rst         | 136 +++++
 .../gpu/drm_fabric/check-spec-regen.sh        | 114 ++++
 .../selftests/drivers/gpu/drm_fabric/config   |   8 +
 .../drivers/gpu/drm_fabric/dump_intr_abi.py   | 361 +++++++++++++
 .../drivers/gpu/drm_fabric/dump_scale_abi.py  | 178 +++++++
 .../drivers/gpu/drm_fabric/fabric_abi.py      | 401 +++++++++++++++
 .../drivers/gpu/drm_fabric/fault_abi.py       | 105 ++++
 .../gpu/drm_fabric/harness_reset_abi.py       | 113 ++++
 .../drivers/gpu/drm_fabric/hotplug_abi.py     | 204 ++++++++
 .../drivers/gpu/drm_fabric/lib_drm_fabric.py  | 481 +++++++++++++++++
 .../drivers/gpu/drm_fabric/nl_policy_probe.py | 485 ++++++++++++++++++
 .../drivers/gpu/drm_fabric/port_cursor_abi.py | 401 +++++++++++++++
 .../gpu/drm_fabric/port_stats_cap_abi.py      | 374 ++++++++++++++
 .../selftests/drivers/gpu/drm_fabric/settings |   1 +
 .../drivers/gpu/drm_fabric/switch_abi.py      | 108 ++++
 18 files changed, 3519 insertions(+)
 create mode 100644 tools/testing/selftests/drivers/gpu/drm_fabric/Makefile
 create mode 100644 tools/testing/selftests/drivers/gpu/drm_fabric/README.rst
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/check-spec-regen.sh
 create mode 100644 tools/testing/selftests/drivers/gpu/drm_fabric/config
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/dump_intr_abi.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/dump_scale_abi.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/fabric_abi.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/fault_abi.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/harness_reset_abi.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/hotplug_abi.py
 create mode 100644 tools/testing/selftests/drivers/gpu/drm_fabric/lib_drm_fabric.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/nl_policy_probe.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/port_cursor_abi.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/port_stats_cap_abi.py
 create mode 100644 tools/testing/selftests/drivers/gpu/drm_fabric/settings
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/switch_abi.py
Documentation/gpu/drm-fabric.rst +7 -0
index cd98a97e1662..bc7b87c766cc 100644
@@ -357,3 +357,10 @@ Testing
 
 The object model is covered by KUnit when ``CONFIG_DRM_FABRIC_KUNIT_TEST`` is
 enabled. The test source is folded into the core translation unit.
+
+Generic Netlink ABI tests live under
+``tools/testing/selftests/drivers/gpu/drm_fabric``. They cover the YNL query
+paths, malformed policy input, generated-header synchronization, dump-cursor
+correctness across endpoint removal, ``NLM_F_DUMP_INTR`` handling, the opaque
+switch half-edge, and provider fault handling. See that directory's ``README.rst``
+for build and execution commands.
tools/testing/selftests/Makefile +1 -0
index b622052ec3e9..c90eb5d33ec6 100644
@@ -18,6 +18,7 @@ TARGETS += devices/error_logs
 TARGETS += devices/probe
 TARGETS += dmabuf-heaps
 TARGETS += drivers/dma-buf
+TARGETS += drivers/gpu/drm_fabric
 TARGETS += drivers/ntsync
 TARGETS += drivers/s390x/uvdevice
 TARGETS += drivers/net
tools/testing/selftests/drivers/gpu/drm_fabric/Makefile new file +41 -0

41 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/README.rst new file +136 -0

137 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/check-spec-regen.sh new file +114 -0

114 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/config new file +8 -0
new file mode 100644
index 000000000000..6eaab8a7d771
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+# Kernel config fragment required to run the drm_fabric kselftests.
+# Merge with: scripts/kconfig/merge_config.sh or make kselftest-merge.
+CONFIG_NET=y
+CONFIG_DRM=y
+CONFIG_DEBUG_FS=y
+CONFIG_DRM_FABRIC=m
+CONFIG_DRM_FABRIC_SIM=m
tools/testing/selftests/drivers/gpu/drm_fabric/dump_intr_abi.py new file +361 -0

361 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/dump_scale_abi.py new file +178 -0

178 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/fabric_abi.py new file +401 -0

401 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/fault_abi.py new file +105 -0

105 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/harness_reset_abi.py new file +113 -0

113 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/hotplug_abi.py new file +204 -0

204 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/lib_drm_fabric.py new file +481 -0

481 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/nl_policy_probe.py new file +485 -0

485 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/port_cursor_abi.py new file +401 -0

355 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/port_stats_cap_abi.py new file +374 -0

374 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/settings new file +1 -0
new file mode 100644
index 000000000000..694d70710ff0

Lines of this file are not shown. View the raw message.

tools/testing/selftests/drivers/gpu/drm_fabric/switch_abi.py new file +108 -0

108 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Signature · 1 line
2.43.0

Part of the diff is not shown here. View the raw message.

#10 lore raw

Re: [RFC PATCH 06/12] drm/fabric: add YNL query and policy selftests

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] harness_reset_abi.py races with its child process when resolving the Generic Netlink family…

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] harness_reset_abi.py races with its child process when resolving the Generic Netlink family, leading to test failure on a fresh system. --

--- Patch [6]: [RFC PATCH 06/12] drm/fabric: add YNL query and policy selftests --- commit 095db697e4004f927fd42e79eb88a4bd06030771
Author: Konstantin Sinyuk <[email protected]>
Subject: drm/fabric: add YNL query and policy selftests

This commit adds eleven kselftest programs for the drm-fabric Generic Netlink ABI. These tests use the in-tree YNL client against fabricsim to cover paths like policy validation, multipart dumps, and family introspection.

Quoted 5 lines
tools/testing/selftests/drivers/gpu/drm_fabric/harness_reset_abi.py new file +0 -0
new file mode 100755
index 0000000000000..211613185a39b

[ ... ]

tools/testing/selftests/drivers/gpu/drm_fabric/harness_reset_abi.py line 56

Quoted 6 lines
tools/testing/selftests/drivers/gpu/drm_fabric/harness_reset_abi.py new file +6 -0
+def test_sigkill_topology_recovery(ksft, cfg):
+    """A SIGKILL-leaked switch shape must not survive the next entry reset."""
+    # 1. Bring up the switch shape in a helper and confirm it is observable.
+    child = subprocess.Popen([sys.executable, "-c", _CHILD])
+    try:
+        fab = L.DrmFabric()

[Severity: Medium]
Is there a race condition here on a fresh system where the drm_fabric module is not yet loaded?

The child process executes a script that calls insmod('drm-fabric.ko'). However, immediately after spawning the child, the parent process calls L.DrmFabric().

Since L.DrmFabric() synchronously resolves the generic netlink family, wouldn't this fail with an NlError exception if the child process hasn't finished loading the module yet?

Quoted 7 lines
tools/testing/selftests/drivers/gpu/drm_fabric/harness_reset_abi.py new file +7 -0
+        loaded = L.wait_until(
+            lambda: L.module_loaded("drm_fabric_sim") and _has_switch_peer(fab),
+            timeout=10.0)
+        if not loaded:
+            child.send_signal(signal.SIGKILL)
+            ksft.skip("harness-reset-sigkill-recovery",
+                      "helper could not establish switch shape")
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=6
#11 lore raw

RFC PATCH 7/12 drm/fabric: add topology-provisioning core

In reply to Konstantin Sinyuk

From: Ilia Levi <[email protected]>

Everything so far reports topology that a provider composed. Composing it from userspace needs the core to create an empty fabric, move an endpoint into or out of one, change administrative state and record a peer. None of that may leave the object model half-updated.

Add the core mechanisms without exposing provisioning netlink operations. Deleting a provider-owned or non-empty fabric is refused.

Provider callbacks may sleep and therefore run without drm_fabric_lock. drm_fabric_mutation_lock serialises validation, the provider callback and the core update, with targets pinned across the unlocked callback. Registration and teardown join the same transaction domain, so a successful callback cannot be invalidated before commit.

Administrative intent stays separate from operational state, and each port selects one peer writer at registration. A request that already matches committed state succeeds without invoking the provider.

Registering an orphan endpoint is now valid, so the KUnit case asserting that a NULL fabric is rejected is repurposed to assert that it yields an orphan reporting fabric-id 0.

Assisted-by GitHub-Copilot:claude-opus-4.8
---
 Documentation/gpu/drm-fabric.rst             |  93 ++--
 drivers/gpu/drm/fabric/drm_fabric.c          | 554 +++++++++++++++----
 drivers/gpu/drm/fabric/drm_fabric_internal.h |  13 +
 drivers/gpu/drm/fabric/drm_fabric_test.c     |  17 +-
 include/drm/drm_fabric.h                     | 108 +++-
 5 files changed, 637 insertions(+), 148 deletions(-)
Documentation/gpu/drm-fabric.rst +61 -32
index bc7b87c766cc..61e2c18bf0b5 100644
@@ -18,6 +18,8 @@ Key Goals:
   (xGMI, UALink and similar), enabling data-center discovery and monitoring.
 * Support read-only enumeration, monitoring and state queries for
   provider-owned topology.
+* Support topology provisioning as an optional provider capability, covering
+  fabric and endpoint lifecycle, port administration and peer management.
 * Allow new attributes and fabric types to be added without reusing existing
   wire identifiers, so the uAPI extends without breaking existing consumers.
 * Allow multiple endpoints and ports per provider, so drivers can model
@@ -56,13 +58,14 @@ provider reports: for example, it may be a full mesh with no root, a linear
 chain, or a switch-based topology in which ports terminate at opaque switch
 peers rather than locally registered endpoints.
 
-A *peer* is a value descriptor, not a reference to a live kernel object: its
-``peer-id`` may name a remote accelerator managed by another OS or an opaque
-switch in another trust domain, and need not resolve in the local registry. The
-core stores one directed half-edge and does not require the reverse half-edge to
-exist, so removing an endpoint does not retract peer descriptors held by other
-endpoints. ``peer-type = switch`` only describes the kind of far end; it does
-not create a first-class switch object.
+An endpoint may be registered without a fabric. Such an endpoint is an *orphan*
+and reports ``fabric-id`` 0. A *peer* is a value descriptor, not a reference to
+a live kernel object: its ``peer-id`` may name a remote accelerator managed by
+another OS or an opaque switch in another trust domain, and need not resolve in
+the local registry. The core stores one directed half-edge and does not require
+the reverse half-edge to exist, so removing an endpoint does not retract peer
+descriptors held by other endpoints. ``peer-type = switch`` only describes the
+kind of far end; it does not create a first-class switch object.
 
 .. kernel-doc:: drivers/gpu/drm/fabric/drm_fabric.c
    :doc: DRM Fabric core
@@ -79,10 +82,10 @@ that half-edge. A peer is therefore topology as last set, not proof of live
 connectivity; liveness belongs to the fabric controller.
 
 The core never retracts a half-edge on its own. Failing to resolve a peer
-locally is not the same as the link going away -- the far end may be a switch,
-an accelerator on another node, or a local endpoint that merely unregistered
--- so only the provider knows when a port's physical adjacency actually
-changed, and only the provider retracts or replaces the descriptor.
+locally is not the same as the link going away -- the far end may be a
+switch, an accelerator on another node, or a local endpoint that merely
+unregistered -- so only the provider knows when a port's physical adjacency
+actually changed, and only the provider retracts or replaces the descriptor.
 
 ``port-peer-delete-ntf`` reports an explicitly retracted half-edge; it is
 not emitted when a peer merely becomes locally unresolvable, so its absence
@@ -105,11 +108,15 @@ Driver API
 Design scope and boundaries
 ===========================
 
-Vendor drivers retain hardware discovery, firmware interaction and the
-load/store data path; DRM Fabric represents only the topology and
-provider-reported state of DRM-managed accelerators, which is why it
-belongs in DRM. The interface does not define MMU programming, switch
-policy, key management, live migration, or any required user space daemon.
+The core records direct adjacency only, not end-to-end reachability or switch
+forwarding, which remain with the fabric controller. Vendor drivers retain
+hardware discovery, firmware interaction, memory semantics and the
+hardware-carried data path; DRM Fabric represents only the topology and
+control state of DRM-managed accelerators, which is why it belongs in DRM.
+It does not create a network device or own route computation, switch
+forwarding, transport or congestion control. The interface also does not
+define MMU programming, switch policy, key management, live migration, or
+any required user space daemon.
 
 DRM Fabric does not define in-network collective operations or how an
 endpoint or switch executes them. Such capabilities belong to the
@@ -123,27 +130,49 @@ strengthens the contract rather than breaking it.
 Object lifetime and locking
 ===========================
 
-All registry and object state is protected by ``drm_fabric_lock``. A fabric and
-its endpoints are created and torn down through the provider API; endpoint
-unregister removes the endpoint from the registry and frees its fixed set of
-ports. Fabric membership is tracked, so a provider must remove all member
-endpoints before unregistering a provider-owned fabric: drm_fabric_unregister()
-returns ``-EBUSY`` and leaves the fabric registered if any remain, so the
-provider must retry after removing them rather than treat the fabric as gone.
+Registry membership and object state are protected by ``drm_fabric_lock``;
+topology mutation is additionally serialised by ``drm_fabric_mutation_lock``,
+described below. A fabric and its endpoints are created and torn down through
+the provider API; endpoint unregister removes the endpoint from the registry
+and frees its fixed set of ports. Fabric membership is tracked, so a provider
+must remove all member endpoints before unregistering a provider-owned fabric:
+drm_fabric_unregister() returns ``-EBUSY`` and leaves the fabric registered if
+any remain, so the provider must retry after removing them rather than treat
+the fabric as gone.
 
 Objects are reference counted and a port is pinned through its owning endpoint.
 Endpoint unregister drops the registration reference and waits for outstanding
 pins before freeing the ports; fabric membership holds a fabric reference.
 
-Providers own object lifetime, so a provider must serialise endpoint
-registration against unregistration of the containing fabric. The unregister
-entry points compare the supplied pointer against the registry before
-dereferencing it, so a stale or repeated teardown is rejected: fabric
-unregistration returns ``-ENODEV``, and endpoint unregistration, having no
-error return, warns and performs no teardown. Endpoint registration rejects a
-departed parent the same way. These checks prove current address membership
-only: they cannot tell an earlier incarnation from another object registered
-later at the same address.
+Providers own object lifetime. The unregister entry points compare the supplied
+pointer against the registry before dereferencing it, so a stale or repeated
+teardown is rejected: fabric unregistration returns ``-ENODEV``, and endpoint
+unregistration, having no error return, warns and performs no teardown.
+Endpoint registration rejects a departed parent the same way. These checks
+prove current address membership only: they cannot tell an earlier incarnation
+from another object registered later at the same address. Only the provider
+knows its own object lifecycle.
+
+Netlink mutation commands additionally hold ``drm_fabric_mutation_lock`` across
+target resolution, the provider callback and the core commit. The lock order
+is::
+
+    drm_fabric_mutation_lock -> drm_fabric_lock
+
+Provider lifecycle operations that can invalidate a prepared mutation take the
+same mutation lock: endpoint registration as well as endpoint and fabric
+unregister. A provider-driven teardown therefore cannot race an in-flight
+mutation on the same object, and a registration cannot claim a fabric-scoped
+``fabric-ep-id`` after an attach has validated the identifier but before its
+provider callback completes. A provider must not invoke any of these lifecycle
+operations from one of its own mutation callbacks: the callback already holds
+the mutation lock, so the nested acquisition would self-deadlock. A successful
+callback therefore cannot be invalidated before commit, and the post-callback
+checks are invariant assertions only.
+
+A fabric records whether it was created by a provider or by userspace. Only an
+empty userspace-created fabric may be deleted through the provisioning core;
+provider-owned and non-empty fabrics are rejected.
 
 Generic Netlink family
 ======================
drivers/gpu/drm/fabric/drm_fabric.c +451 -103

690 lines not on this page · raw message

drivers/gpu/drm/fabric/drm_fabric_internal.h +13 -0
index 7fc5bc3f33f9..dc95b9967b64 100644
@@ -13,6 +13,7 @@
 #include <drm/drm_fabric.h>
 
 extern struct mutex drm_fabric_lock;
+extern struct mutex drm_fabric_mutation_lock;
 extern struct xarray drm_fabric_xa;    /* Fabric registry */
 extern struct xarray drm_fabric_ep_xa; /* Endpoint registry */
 
@@ -34,9 +35,21 @@ void drm_fabric_endpoint_put(struct drm_fabric_endpoint *ep);
 struct drm_fabric *drm_fabric_get(struct drm_fabric *fabric);
 void drm_fabric_put(struct drm_fabric *fabric);
 
+int drm_fabric_user_fabric_new(enum drm_fabric_type type, u64 instance_id,
+			       const char *name, u32 *fabric_id_out);
+int drm_fabric_user_fabric_del(u32 fabric_id);
+int drm_fabric_endpoint_set(struct drm_fabric_endpoint *ep,
+			    const struct drm_fabric_endpoint_change *change);
+int drm_fabric_port_set_admin(struct drm_fabric_port *port,
+			      enum drm_fabric_admin_state admin);
+int drm_fabric_port_peer_new(struct drm_fabric_port *port,
+			     const struct drm_fabric_peer *peer);
+int drm_fabric_port_peer_del(struct drm_fabric_port *port);
+
 /* Emits use the post-change generation. */
 void drm_fabric_emit_endpoint_create(struct drm_fabric_endpoint *ep, u32 generation);
 void drm_fabric_emit_endpoint_delete(struct drm_fabric_endpoint *ep, u32 generation);
+void drm_fabric_emit_endpoint_change(struct drm_fabric_endpoint *ep, u32 generation);
 
 void drm_fabric_emit_port_peer_create(struct drm_fabric_port *port,
 				      const struct drm_fabric_peer *peer,
drivers/gpu/drm/fabric/drm_fabric_test.c +11 -6
index 3457675645f6..863b7cf69068 100644
@@ -112,13 +112,17 @@ static void drm_fabric_test_unregister_reports_removal(struct kunit *test)
 	KUNIT_EXPECT_EQ(test, drm_fabric_unregister(fab), 0);
 }
 
-static void drm_fabric_test_endpoint_requires_fabric(struct kunit *test)
+/*
+ * A NULL fabric registers an orphan endpoint, which reports fabric-id 0
+ * and can be unregistered.
+ */
+static void drm_fabric_test_endpoint_orphan_register(struct kunit *test)
 {
 	struct device *fabrictest_dev = fabrictest_alloc_dev(test);
 	struct drm_fabric_port_desc pdesc = { .index = 0, .max_lane_count = 4 };
 	struct drm_fabric_endpoint_desc edesc = {
 		.fabric_ep_id = 1,
-		.name = "no-fabric",
+		.name = "orphan",
 		.parent = fabrictest_dev,
 		.ports = &pdesc,
 		.num_ports = 1,
@@ -126,9 +130,10 @@ static void drm_fabric_test_endpoint_requires_fabric(struct kunit *test)
 	struct drm_fabric_endpoint *ep;
 
 	ep = drm_fabric_endpoint_register(NULL, &edesc);
-	KUNIT_EXPECT_TRUE(test, IS_ERR(ep));
-	if (IS_ERR(ep))
-		KUNIT_EXPECT_EQ(test, PTR_ERR(ep), -EINVAL);
+	KUNIT_ASSERT_FALSE(test, IS_ERR(ep));
+	KUNIT_EXPECT_EQ(test, drm_fabric_endpoint_fabric_id(ep), 0);
+
+	drm_fabric_endpoint_unregister(ep);
 }
 
 /* Registration must not walk a NULL port array. */
@@ -1280,7 +1285,7 @@ static struct kunit_case drm_fabric_test_cases[] = {
 	KUNIT_CASE(drm_fabric_test_unregister_reports_removal),
 	KUNIT_CASE(drm_fabric_test_instance_id_unique),
 	KUNIT_CASE(drm_fabric_test_endpoint_register),
-	KUNIT_CASE(drm_fabric_test_endpoint_requires_fabric),
+	KUNIT_CASE(drm_fabric_test_endpoint_orphan_register),
 	KUNIT_CASE(drm_fabric_test_endpoint_requires_port_array),
 	KUNIT_CASE(drm_fabric_test_endpoint_register_stale_fabric),
 	KUNIT_CASE(drm_fabric_test_unregister_rejects_non_member),
include/drm/drm_fabric.h +101 -7

183 lines not on this page · raw message

Signature · 1 line
2.43.0
#12 lore raw

RFC PATCH 8/12 drm/fabric: add provisioning netlink uAPI

In reply to Konstantin Sinyuk

From: Ilia Levi <[email protected]>

Extend the YNL specification with six privileged provisioning commands.

FABRIC_NEW and FABRIC_DEL create and delete empty userspace-owned fabrics; FABRIC_NEW carries a fabric-new-params nest with the type, name and instance ID. ENDPOINT_SET changes fabric membership and endpoint administrative state, PORT_SET changes port administrative state, and PORT_PEER_NEW and PORT_PEER_DEL manage peer adjacency. All six require GENL_ADMIN_PERM.

A peer request carries its type-qualified identity and far-end port index. The descriptor is stored without resolving it to a local object, as documented in Documentation/gpu/drm-fabric.rst.

Add an endpoint-change notification and extend the existing port-change and peer notifications to cover userspace-requested transitions.

Generate the headers from the tree root with:

  tools/net/ynl/pyynl/ynl_gen_c.py --mode uapi --header \
      --spec Documentation/netlink/specs/drm_fabric.yaml \
      -o include/uapi/drm/drm_fabric.h
  tools/net/ynl/pyynl/ynl_gen_c.py --mode kernel --header \
      --spec Documentation/netlink/specs/drm_fabric.yaml \
      -o drivers/gpu/drm/fabric/drm_fabric_nl.h

The generated source names the six doit handlers, so it lands with their implementation in the next patch. Drop the temporary administrative-state definitions now that the generated headers provide them.

Assisted-by GitHub-Copilot:claude-opus-4.8
---
 Documentation/gpu/drm-fabric.rst            | 117 ++++++++++++---
 Documentation/netlink/specs/drm_fabric.yaml | 155 +++++++++++++++++++-
 drivers/gpu/drm/fabric/drm_fabric_nl.h      |  30 ++++
 include/drm/drm_fabric.h                    |   9 +-
 include/uapi/drm/drm_fabric.h               |  28 ++++
 5 files changed, 312 insertions(+), 27 deletions(-)
Documentation/gpu/drm-fabric.rst +98 -19
index 61e2c18bf0b5..4ee7cb7ef6ac 100644
@@ -87,9 +87,11 @@ switch, an accelerator on another node, or a local endpoint that merely
 unregistered -- so only the provider knows when a port's physical adjacency
 actually changed, and only the provider retracts or replaces the descriptor.
 
-``port-peer-delete-ntf`` reports an explicitly retracted half-edge; it is
-not emitted when a peer merely becomes locally unresolvable, so its absence
-is not evidence the far end is still reachable.
+``port-peer-delete-ntf`` reports an explicitly retracted half-edge -- through
+the provider's own report or, on a userspace-managed port, a userspace
+``port-peer-del`` request -- and is never emitted when a peer merely becomes
+locally unresolvable, so its absence is not evidence the far end is still
+reachable.
 
 Endpoint teardown removes the endpoint's owned half-edges without
 generating a separate event for each port: the delete already describes
@@ -170,9 +172,9 @@ the mutation lock, so the nested acquisition would self-deadlock. A successful
 callback therefore cannot be invalidated before commit, and the post-callback
 checks are invariant assertions only.
 
-A fabric records whether it was created by a provider or by userspace. Only an
-empty userspace-created fabric may be deleted through the provisioning core;
-provider-owned and non-empty fabrics are rejected.
+A fabric records whether it was created by a provider
+(drm_fabric_register()) or by userspace (``fabric-new``); see
+`Provisioning`_ for the deletion rules.
 
 Generic Netlink family
 ======================
@@ -216,8 +218,9 @@ User space enumerates topology with four read-only commands, each supporting a
 single lookup (``do``) and a bulk dump (``dump``):
 
 * ``fabric-get`` -- enumerate fabrics (``do`` by ``fabric-id``, ``dump`` for all).
-* ``endpoint-get`` -- enumerate endpoints, optionally filtered by ``fabric-id``,
-  or resolve one by ``endpoint-id`` or backing ``dev-name``/``bus-name``.
+* ``endpoint-get`` -- enumerate endpoints, optionally filtered by ``fabric-id``
+  (0 selects orphans), or resolve one by ``endpoint-id`` or by its backing
+  ``dev-name`` with an optional ``bus-name``.
 * ``port-get`` -- enumerate ports, filtered by ``endpoint-id``. Ports may report
   the provider's maximum capability as ``max-lane-count`` and
   ``max-lane-signaling-rate-mbps`` (zero means unknown); these are maxima, not
@@ -243,10 +246,10 @@ a partial payload and are declared with ``event:``.
      - Trigger
      - Payload
    * - ``fabric-create-ntf``
-     - a fabric is registered by a provider
+     - a fabric is registered (provider or ``fabric-new``)
      - reuses ``fabric-get``
    * - ``fabric-delete-ntf``
-     - a provider-owned fabric is unregistered
+     - a fabric is unregistered or removed via ``fabric-del``
      - reuses ``fabric-get``
    * - ``endpoint-create-ntf``
      - an endpoint is registered
@@ -254,15 +257,19 @@ a partial payload and are declared with ``event:``.
    * - ``endpoint-delete-ntf``
      - an endpoint is unregistered
      - reuses ``endpoint-get``
+   * - ``endpoint-change-ntf``
+     - an endpoint's fabric attachment or administrative state changes
+     - reuses ``endpoint-get``
    * - ``port-change-ntf``
-     - a port's operational state changes
+     - a port's operational or administrative state changes
      - reuses ``port-get``
    * - ``port-peer-create-ntf``
-     - a port's peer descriptor is set by its provider
+     - a port's peer descriptor is set (provider or ``port-peer-new``)
      - partial (``event:``)
    * - ``port-peer-delete-ntf``
-     - a port's peer descriptor is explicitly unset by its provider; never
-       emitted for an implicit half-edge loss (see `Peer semantics`_)
+     - a port's peer descriptor is explicitly unset (provider or
+       ``port-peer-del``); never emitted for an implicit half-edge loss
+       (see `Peer semantics`_)
      - partial (``event:``)
 
 Notifications are best-effort. A listener that detects loss, restarts, or
@@ -274,9 +281,9 @@ Topology generation and dump consistency
 The core keeps a nonzero generation counter and advances it whenever topology or
 exposed state changes. It is surfaced as the ``topology-generation`` attribute on
 ``fabric-get``, ``endpoint-get`` and ``port-get`` replies and on the topology
-notifications. A provider-reported change advances the generation before its
-notification is serialized, so an event carries the post-change value that a
-later ``get``/``dump`` will also report.
+notifications. A committed change -- provider-reported or userspace mutation
+-- advances the generation before its notification is serialized, so an event
+carries the post-change value that a later ``get``/``dump`` will also report.
 
 ``topology-generation`` is a change token, not a timestamp, liveness counter or
 event count: a changed value means topology changed, but the delta between two
@@ -308,8 +315,8 @@ Monitor notifications are likewise emitted only into ``init_net``, so a listener
 that joins the multicast group from another network namespace never receives
 them.
 
-Examples
-========
+Query examples
+--------------
 
 Query the topology with the in-tree YNL tool, pointing it at the spec:
 
@@ -364,6 +371,78 @@ Query a single port:
 
 The family name on the wire is ``drm-fabric``.
 
+Provisioning
+============
+
+The provisioning interface requires ``CAP_NET_ADMIN``. ``fabric-new`` and
+``fabric-del`` are core-owned; the rest are serviced by the provider and
+return ``-EOPNOTSUPP`` where it does not implement the matching callback:
+
+* ``fabric-new`` -- create an empty, userspace-owned fabric. The request
+  carries a ``fabric-new-params`` nest with the fabric type, an optional name
+  and a provider-defined instance ID.
+* ``fabric-del`` -- delete an empty, userspace-owned fabric. Refuses a
+  provider-owned fabric (``-EPERM``) and a non-empty one (``-EBUSY``).
+* ``endpoint-set`` -- attach an orphan endpoint, selected by ``endpoint-id`` or
+  by its backing ``dev-name`` with an optional ``bus-name``, to a fabric;
+  detach it with ``fabric-id`` 0; and/or set its administrative state.
+* ``port-set`` -- set a port's administrative state.
+* ``port-peer-new`` / ``port-peer-del`` -- set or unset a port's neighbor
+  half-edge. Valid only on a userspace-managed port; a provider-managed port
+  returns ``-EOPNOTSUPP`` (see `Peer management mode`_).
+
+Mutation commands carry ``GENL_ADMIN_PERM`` and are additionally confined to
+``init_net``. ``GENL_ADMIN_PERM`` only checks ``CAP_NET_ADMIN`` in the caller's
+user namespace, which a process in a nested user and network namespace may
+hold; restricting mutators to ``init_net`` prevents container-local privilege
+from reconfiguring host-global topology.
+
+A userspace-created fabric additionally pins this module for as long as it
+remains registered: ``fabric-new`` takes the pin, ``fabric-del`` releases it.
+
+Peer management mode
+--------------------
+
+A port uses one peer-management mode, fixed by the provider at registration.
+
+In provider-managed mode, the provider reports peer creation and removal
+(drm_fabric_port_set_peer() / drm_fabric_port_unset_peer()) and userspace peer
+provisioning is unsupported (``port-peer-new`` / ``port-peer-del`` return
+``-EOPNOTSUPP``).
+
+In userspace-managed mode, peer creation and removal are requested through the
+provisioning API and the provider does not independently replace or retract the
+peer (drm_fabric_port_set_peer() / drm_fabric_port_unset_peer() return
+``-EOPNOTSUPP``).
+
+One authority per descriptor prevents concurrent updates from both sources.
+Setting an occupied port returns ``-EEXIST``; unsetting an empty port returns
+``-ENOENT``.
+
+Provisioning examples
+---------------------
+
+Provision with the in-tree YNL tool (root, initial namespace):
+
+.. code-block:: bash
+
+    # Create an empty fabric
+    ./tools/net/ynl/pyynl/cli.py \
+        --spec Documentation/netlink/specs/drm_fabric.yaml \
+        --do fabric-new \
+        --json '{"fabric-new-params": {"type": "synthetic", "instance-id": 42}}'
+
+The command returns a core-assigned ``fabric-id``. Use that value in the
+following requests.
+
+.. code-block:: bash
+
+    # Attach an orphan endpoint to the returned fabric
+    ./tools/net/ynl/pyynl/cli.py \
+        --spec Documentation/netlink/specs/drm_fabric.yaml \
+        --do endpoint-set \
+        --json '{"endpoint-id": 5, "fabric-id": <returned-fabric-id>}'
+
 Synthetic provider
 ==================
 
Documentation/netlink/specs/drm_fabric.yaml +154 -1

203 lines not on this page · raw message

drivers/gpu/drm/fabric/drm_fabric_nl.h +30 -0
index 8cedc004260f..03b3d22f180c 100644
@@ -12,6 +12,27 @@
 
 #include <uapi/drm/drm_fabric.h>
 
+/* Common nested types */
+extern const struct nla_policy drm_fabric_fabric_new_params_nl_policy[DRM_FABRIC_A_FABRIC_NEW_PARAMS_INSTANCE_ID + 1];
+extern const struct nla_policy drm_fabric_peer_nl_policy[DRM_FABRIC_A_PEER_ATTRS_PORT_INDEX + 1];
+
+int drm_fabric_nl_pre_doit(const struct genl_split_ops *ops,
+			   struct sk_buff *skb, struct genl_info *info);
+int drm_fabric_nl_endpoint_pre_doit(const struct genl_split_ops *ops,
+				    struct sk_buff *skb,
+				    struct genl_info *info);
+int drm_fabric_nl_port_pre_doit(const struct genl_split_ops *ops,
+				struct sk_buff *skb, struct genl_info *info);
+void
+drm_fabric_nl_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
+			struct genl_info *info);
+void
+drm_fabric_nl_endpoint_post_doit(const struct genl_split_ops *ops,
+				 struct sk_buff *skb, struct genl_info *info);
+void
+drm_fabric_nl_port_post_doit(const struct genl_split_ops *ops,
+			     struct sk_buff *skb, struct genl_info *info);
+
 int drm_fabric_nl_fabric_get_doit(struct sk_buff *skb, struct genl_info *info);
 int drm_fabric_nl_fabric_get_dumpit(struct sk_buff *skb,
 				    struct netlink_callback *cb);
@@ -26,6 +47,15 @@ int drm_fabric_nl_port_stats_get_doit(struct sk_buff *skb,
 				      struct genl_info *info);
 int drm_fabric_nl_port_stats_get_dumpit(struct sk_buff *skb,
 					struct netlink_callback *cb);
+int drm_fabric_nl_fabric_new_doit(struct sk_buff *skb, struct genl_info *info);
+int drm_fabric_nl_fabric_del_doit(struct sk_buff *skb, struct genl_info *info);
+int drm_fabric_nl_endpoint_set_doit(struct sk_buff *skb,
+				    struct genl_info *info);
+int drm_fabric_nl_port_set_doit(struct sk_buff *skb, struct genl_info *info);
+int drm_fabric_nl_port_peer_new_doit(struct sk_buff *skb,
+				     struct genl_info *info);
+int drm_fabric_nl_port_peer_del_doit(struct sk_buff *skb,
+				     struct genl_info *info);
 
 enum {
 	DRM_FABRIC_NLGRP_MONITOR,
include/drm/drm_fabric.h +2 -7
index 69e9099a1e57..0479b6435a0e 100644
@@ -4,8 +4,8 @@
  */
 
 /*
- * DRM Fabric driver API: common object model for GPU interconnect topology
- * (fabric, endpoint, port and peer relationships).
+ * Common object model for GPU interconnect topology: fabric, endpoint, port
+ * and peer relationships.
  */
 
 #ifndef __DRM_FABRIC_H__
@@ -18,11 +18,6 @@
 
 #include <uapi/drm/drm_fabric.h>
 
-enum drm_fabric_admin_state {
-	DRM_FABRIC_ADMIN_STATE_DOWN = 1,
-	DRM_FABRIC_ADMIN_STATE_UP,
-};
-
 struct device;
 
 /**
include/uapi/drm/drm_fabric.h +28 -0
index b6c7bd6e35f0..e004200423e8 100644
@@ -36,6 +36,14 @@ enum drm_fabric_peer_type {
 	DRM_FABRIC_PEER_TYPE_SWITCH,
 };
 
+/*
+ * Administrative (requested) state of an endpoint or port.
+ */
+enum drm_fabric_admin_state {
+	DRM_FABRIC_ADMIN_STATE_DOWN = 1,
+	DRM_FABRIC_ADMIN_STATE_UP,
+};
+
 enum drm_fabric_a {
 	DRM_FABRIC_A_FABRIC = 1,
 	DRM_FABRIC_A_ENDPOINT,
@@ -48,6 +56,8 @@ enum drm_fabric_a {
 	DRM_FABRIC_A_BUS_NAME,
 	DRM_FABRIC_A_PEER,
 	DRM_FABRIC_A_TOPOLOGY_GENERATION,
+	DRM_FABRIC_A_ADMIN_STATE,
+	DRM_FABRIC_A_FABRIC_NEW_PARAMS,
 
 	__DRM_FABRIC_A_MAX,
 	DRM_FABRIC_A_MAX = (__DRM_FABRIC_A_MAX - 1)
@@ -64,6 +74,15 @@ enum drm_fabric_a_fabric_attrs {
 	DRM_FABRIC_A_FABRIC_ATTRS_MAX = (__DRM_FABRIC_A_FABRIC_ATTRS_MAX - 1)
 };
 
+enum drm_fabric_a_fabric_new_params {
+	DRM_FABRIC_A_FABRIC_NEW_PARAMS_TYPE = 1,
+	DRM_FABRIC_A_FABRIC_NEW_PARAMS_NAME,
+	DRM_FABRIC_A_FABRIC_NEW_PARAMS_INSTANCE_ID,
+
+	__DRM_FABRIC_A_FABRIC_NEW_PARAMS_MAX,
+	DRM_FABRIC_A_FABRIC_NEW_PARAMS_MAX = (__DRM_FABRIC_A_FABRIC_NEW_PARAMS_MAX - 1)
+};
+
 enum drm_fabric_a_endpoint_attrs {
 	DRM_FABRIC_A_ENDPOINT_ATTRS_PAD = 1,
 	DRM_FABRIC_A_ENDPOINT_ATTRS_ENDPOINT_ID,
@@ -72,6 +91,7 @@ enum drm_fabric_a_endpoint_attrs {
 	DRM_FABRIC_A_ENDPOINT_ATTRS_NAME,
 	DRM_FABRIC_A_ENDPOINT_ATTRS_DEV_NAME,
 	DRM_FABRIC_A_ENDPOINT_ATTRS_BUS_NAME,
+	DRM_FABRIC_A_ENDPOINT_ATTRS_ADMIN_STATE,
 
 	__DRM_FABRIC_A_ENDPOINT_ATTRS_MAX,
 	DRM_FABRIC_A_ENDPOINT_ATTRS_MAX = (__DRM_FABRIC_A_ENDPOINT_ATTRS_MAX - 1)
@@ -84,6 +104,7 @@ enum drm_fabric_a_port_attrs {
 	DRM_FABRIC_A_PORT_ATTRS_MAX_LANE_COUNT,
 	DRM_FABRIC_A_PORT_ATTRS_MAX_LANE_SIGNALING_RATE_MBPS,
 	DRM_FABRIC_A_PORT_ATTRS_PEER,
+	DRM_FABRIC_A_PORT_ATTRS_ADMIN_STATE,
 
 	__DRM_FABRIC_A_PORT_ATTRS_MAX,
 	DRM_FABRIC_A_PORT_ATTRS_MAX = (__DRM_FABRIC_A_PORT_ATTRS_MAX - 1)
@@ -124,6 +145,13 @@ enum drm_fabric_cmd {
 	DRM_FABRIC_CMD_ENDPOINT_DELETE_NTF,
 	DRM_FABRIC_CMD_FABRIC_CREATE_NTF,
 	DRM_FABRIC_CMD_FABRIC_DELETE_NTF,
+	DRM_FABRIC_CMD_ENDPOINT_CHANGE_NTF,
+	DRM_FABRIC_CMD_FABRIC_NEW,
+	DRM_FABRIC_CMD_FABRIC_DEL,
+	DRM_FABRIC_CMD_ENDPOINT_SET,
+	DRM_FABRIC_CMD_PORT_SET,
+	DRM_FABRIC_CMD_PORT_PEER_NEW,
+	DRM_FABRIC_CMD_PORT_PEER_DEL,
 
 	__DRM_FABRIC_CMD_MAX,
 	DRM_FABRIC_CMD_MAX = (__DRM_FABRIC_CMD_MAX - 1)
Signature · 1 line
2.43.0
#13 lore raw

Re: [RFC PATCH 08/12] drm/fabric: add provisioning netlink uAPI

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [Medium] New provisioning commands (`fabric-new`, `endpoint-set`, `port-set`, `port-peer-new`…

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] New provisioning commands (fabric-new, endpoint-set, port-set, port-peer-new, port-peer-del) do not reply with a full message; most only ACK on success.
- [Medium] The fabric-new-params nested attribute introduces an unnecessary extra wrapping nest for request parameters.
--

--- Patch [8]: [RFC PATCH 08/12] drm/fabric: add provisioning netlink uAPI --- commit 99dd7c47ab1a93cd9f0234f8280e8cd261d71d5a
Author: Ilia Levi <[email protected]>
Subject: drm/fabric: add provisioning netlink uAPI

This commit extends the DRM fabric YNL specification with six privileged provisioning commands for managing fabrics, endpoints, and ports.

Quoted 8 lines
Documentation/netlink/specs/drm_fabric.yaml +1 -0
@@ -108,6 +125,17 @@ attribute-sets:
           or DUMP reply carries its snapshot's generation; a notification
           carries the generation of its change. Statistics reads do not
           advance it.
+      # Provisioning request parameters

Documentation/netlink/specs/drm_fabric.yaml attribute-sets: · line 138

Quoted 10 lines
Documentation/netlink/specs/drm_fabric.yaml +10 -0
+      -
+        name: admin-state
+        type: u32
+        enum: admin-state
+        doc: Requested administrative state.
+      -
+        name: fabric-new-params
+        type: nest
+        nested-attributes: fabric-new-params
+        doc: Creation parameters for ``fabric-new`` (full nest).

[Severity: Medium]
Does this introduce an extra wrapping nest for the request parameters?

The generic netlink design rules for new families specify avoiding extra wrapping nests. Wrapping the request parameters inside the fabric-new-params nested attribute rather than placing them directly in the main drm-fabric request attributes creates unnecessary API complexity.

[ ... ]

Quoted 15 lines
Documentation/netlink/specs/drm_fabric.yaml +11 -0
@@ -421,6 +483,97 @@ operations:
         reply shape (full fabric nest).
       notify: fabric-get
 
+    -
+      name: endpoint-change-ntf
+      doc: |
+        Endpoint state change notification.
+        Reuses the endpoint-get reply shape (full endpoint nest).
+      notify: endpoint-get
+
+    -
+      name: fabric-new
+      doc: Create a new empty fabric
+      attribute-set: drm-fabric

Documentation/netlink/specs/drm_fabric.yaml operations: · line 506

Quoted 10 lines
Documentation/netlink/specs/drm_fabric.yaml +10 -0
+      flags: [admin-perm]
+      do:
+        pre: drm-fabric-nl-pre-doit
+        post: drm-fabric-nl-post-doit
+        request:
+          attributes:
+            - fabric-new-params
+        reply:
+          attributes:
+            - fabric-id

[Severity: Medium]
Should this operation reply with a full message representing the object rather than just the fabric-id?

The generic netlink design rules require that all operations, especially NEW/ADD, reply with a full message carrying identifying information about the new object. Replying only with the ID forces userspace to issue a separate GET command to retrieve the full state.

[ ... ]

Quoted 5 lines
Documentation/netlink/specs/drm_fabric.yaml +5 -0
+    -
+      name: endpoint-set
+      doc: Attach/detach an endpoint to a fabric and/or set its admin state
+      attribute-set: drm-fabric
+      flags: [admin-perm]

Documentation/netlink/specs/drm_fabric.yaml operations: · line 534

Quoted 10 lines
Documentation/netlink/specs/drm_fabric.yaml +10 -0
+      do:
+        pre: drm-fabric-nl-endpoint-pre-doit
+        post: drm-fabric-nl-endpoint-post-doit
+        request:
+          attributes:
+            - endpoint-id
+            - dev-name
+            - bus-name
+            - fabric-id
+            - admin-state

[Severity: Medium]
Does this command intentionally omit a reply block?

Without a reply block, this state-mutating operation will only ACK on success. Since once a command only ACKs, that behavior becomes unchangeable uAPI, should this operation be updated to return a full message reflecting the updated state?

[ ... ]

Documentation/netlink/specs/drm_fabric.yaml operations: · line 562

Quoted 13 lines
Documentation/netlink/specs/drm_fabric.yaml +13 -0
+    -
+      name: port-peer-new
+      doc: Set a port's neighbor
+      attribute-set: drm-fabric
+      flags: [admin-perm]
+      do:
+        pre: drm-fabric-nl-port-pre-doit
+        post: drm-fabric-nl-port-post-doit
+        request:
+          attributes:
+            - endpoint-id
+            - port-index
+            - peer

[Severity: Medium]
Like the endpoint-set command above, should this ADD operation define a reply payload rather than defaulting to an ACK-only response?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=8
#14 lore raw

RFC PATCH 9/12 drm/fabric: implement mutation netlink operations

In reply to Konstantin Sinyuk

Connect the six provisioning operations to the core mutation helpers and add the generated operation and policy source that dispatches to them.

Resolve and pin mutation targets in pre_doit, run each transaction under drm_fabric_mutation_lock, call the provider without drm_fabric_lock held, and release references in post_doit. All six require GENL_ADMIN_PERM and are confined to init_net.

A failed provider callback returns its error with core state unchanged. Successful mutations emit notifications after commit, carrying the resulting topology generation.

Assisted-by GitHub-Copilot:claude-opus-4.8
---
 drivers/gpu/drm/fabric/drm_fabric.c         |   5 +-
 drivers/gpu/drm/fabric/drm_fabric_netlink.c | 275 ++++++++++++++++++++
 drivers/gpu/drm/fabric/drm_fabric_nl.c      | 106 ++++++++
 3 files changed, 384 insertions(+), 2 deletions(-)
drivers/gpu/drm/fabric/drm_fabric.c +3 -2
index 1aae5ff68798..50c34b4fd722 100644
@@ -793,7 +793,8 @@ int drm_fabric_user_fabric_del(u32 fabric_id)
 		/* Symmetric with FABRIC_NEW: only an empty fabric may be removed. */
 		if (drm_fabric_has_members(fabric))
 			return -EBUSY;
-		drm_fabric_base_seq_inc();
+		/* Notify while the userspace-owned fabric is still addressable by id. */
+		drm_fabric_emit_fabric_delete(fabric, drm_fabric_base_seq_inc());
 		xa_erase(&drm_fabric_xa, fabric->id);
 	}
 
@@ -906,7 +907,7 @@ int drm_fabric_endpoint_set(struct drm_fabric_endpoint *ep,
 		if (change.valid & DRM_FABRIC_EP_CHANGE_ADMIN)
 			ep->admin_state = change.admin;
 
-		drm_fabric_base_seq_inc();
+		drm_fabric_emit_endpoint_change(ep, drm_fabric_base_seq_inc());
 	}
 
 	return 0;
drivers/gpu/drm/fabric/drm_fabric_netlink.c +275 -0

299 lines not on this page · raw message

drivers/gpu/drm/fabric/drm_fabric_nl.c +106 -0

124 lines not on this page · raw message

Signature · 1 line
2.43.0
#15 lore raw

Re: [RFC PATCH 09/12] drm/fabric: implement mutation netlink operations

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider: - [Medium] Mutation operations (NEW/ADD/SET) only return an ACK instead of replying with a full message.…

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Medium] Mutation operations (NEW/ADD/SET) only return an ACK instead of replying with a full message.
- [Medium] Notifications emitted in response to mutation requests do not honor the NLM_F_ECHO flag.
- [Medium] Extraneous wrapping nest used for FABRIC_NEW parameters.
- [Low] Missing extended ACK coverage when required nested attributes in peer descriptors are absent. --

--- Patch [9]: [RFC PATCH 09/12] drm/fabric: implement mutation netlink operations --- commit 7000874bd5559d10291fdcd411ac9f167a4334c9
Author: Konstantin Sinyuk <[email protected]>

drm/fabric: implement mutation netlink operations

Connect the six provisioning operations to the core mutation helpers and add the generated operation and policy source that dispatches to them.

Resolve and pin mutation targets in pre_doit, run each transaction under drm_fabric_mutation_lock, call the provider without drm_fabric_lock held, and release references in post_doit. All six require GENL_ADMIN_PERM and are confined to init_net.

A failed provider callback returns its error with core state unchanged. Successful mutations emit notifications after commit, carrying the resulting topology generation.

Quoted 4 lines
drivers/gpu/drm/fabric/drm_fabric_netlink.c +0 -0
index fef2d4c8f5bb9..1a0f293723e95 100644

[ ... ]

Quoted 6 lines
drivers/gpu/drm/fabric/drm_fabric_netlink.c +6 -0
+/* A nested policy cannot mark members required; check type and instance-id here. */
+static int drm_fabric_parse_new_params(struct genl_info *info,
+					enum drm_fabric_type *type,
+					const char **name, u64 *instance_id)
+{
+	struct nlattr *pa[DRM_FABRIC_A_FABRIC_NEW_PARAMS_MAX + 1];

drivers/gpu/drm/fabric/drm_fabric_netlink.c int drm_fabric_nl_port_stats_get_dumpit(struct sk_buff *skb, · line 958

Quoted 10 lines
drivers/gpu/drm/fabric/drm_fabric_netlink.c +10 -0
+	struct nlattr *nest;
+	int ret;
+
+	if (GENL_REQ_ATTR_CHECK(info, DRM_FABRIC_A_FABRIC_NEW_PARAMS))
+		return -EINVAL;
+
+	nest = info->attrs[DRM_FABRIC_A_FABRIC_NEW_PARAMS];
+	ret = nla_parse_nested(pa, DRM_FABRIC_A_FABRIC_NEW_PARAMS_MAX, nest,
+			       drm_fabric_fabric_new_params_nl_policy,
+			       info->extack);

[Severity: Medium]
Does this create an extra wrapping nest for the new parameters?

Netlink uAPI guidelines for new families prefer flat attributes over wrapping nests. Is it possible to avoid using DRM_FABRIC_A_FABRIC_NEW_PARAMS and instead place these parameters directly in the main attribute set?

[ ... ]

Quoted 3 lines
drivers/gpu/drm/fabric/drm_fabric_netlink.c +3 -0
+int drm_fabric_nl_endpoint_set_doit(struct sk_buff *skb,
+				    struct genl_info *info)
+{

[ ... ]

drivers/gpu/drm/fabric/drm_fabric_netlink.c int drm_fabric_nl_port_stats_get_dumpit(struct sk_buff *skb, · line 1061

Quoted 5 lines
drivers/gpu/drm/fabric/drm_fabric_netlink.c +5 -0
+	if (!change.valid)
+		return -EINVAL;
+
+	return drm_fabric_endpoint_set(ep, &change);
+}

[Severity: Medium]
Should this function reply with a full message rather than just an ACK?

New netlink families should reply to mutation operations (like SET and NEW) with a full message carrying the object state, rather than just relying on a generic ACK. This applies here as well as to drm_fabric_nl_port_set_doit() and drm_fabric_nl_port_peer_new_doit().

[ ... ]

Quoted 15 lines
drivers/gpu/drm/fabric/drm_fabric_netlink.c +15 -0
+int drm_fabric_nl_port_peer_new_doit(struct sk_buff *skb,
+				     struct genl_info *info)
+{
+	struct drm_fabric_port *port = info->user_ptr[0];
+	struct nlattr *pa[DRM_FABRIC_A_PEER_ATTRS_MAX + 1];
+	struct drm_fabric_peer peer = {};
+	int ret;
+
+	if (GENL_REQ_ATTR_CHECK(info, DRM_FABRIC_A_PEER))
+		return -EINVAL;
+
+	ret = nla_parse_nested(pa, DRM_FABRIC_A_PEER_ATTRS_MAX,
+			       info->attrs[DRM_FABRIC_A_PEER],
+			       drm_fabric_peer_nl_policy, info->extack);
+	if (ret)

drivers/gpu/drm/fabric/drm_fabric_netlink.c int drm_fabric_nl_port_stats_get_dumpit(struct sk_buff *skb, · line 1101

Quoted 10 lines
drivers/gpu/drm/fabric/drm_fabric_netlink.c +10 -0
+		return ret;
+
+	/*
+	 * A nested policy cannot require members; require the complete peer
+	 * descriptor here.
+	 */
+	if (!pa[DRM_FABRIC_A_PEER_ATTRS_PEER_ID] ||
+	    !pa[DRM_FABRIC_A_PEER_ATTRS_TYPE] ||
+	    !pa[DRM_FABRIC_A_PEER_ATTRS_PORT_INDEX])
+		return -EINVAL;

[Severity: Low]
Could this manual check use NL_REQ_ATTR_CHECK() to provide extended ACK information?

Currently, this returns a bare -EINVAL without populating the extack to inform userspace which specific nested attribute was missing from the peer descriptor.

Quoted 7 lines
drivers/gpu/drm/fabric/drm_fabric_netlink.c +7 -0
+
+	peer.peer_id = nla_get_u64(pa[DRM_FABRIC_A_PEER_ATTRS_PEER_ID]);
+	peer.peer_type = nla_get_u32(pa[DRM_FABRIC_A_PEER_ATTRS_TYPE]);
+	peer.port_index = nla_get_u32(pa[DRM_FABRIC_A_PEER_ATTRS_PORT_INDEX]);
+
+	return drm_fabric_port_peer_new(port, &peer);
+}

[ ... ]

drivers/gpu/drm/fabric/drm_fabric_netlink.c void drm_fabric_emit_endpoint_delete(struct drm_fabric_endpoint *ep, u32 generat · line 1258

Quoted 5 lines
drivers/gpu/drm/fabric/drm_fabric_netlink.c +5 -0
+void drm_fabric_emit_endpoint_change(struct drm_fabric_endpoint *ep, u32 generation)
+{
+	drm_fabric_endpoint_event_send(DRM_FABRIC_CMD_ENDPOINT_CHANGE_NTF, ep,
+				       generation);
+}

[Severity: Medium]
Will these notifications honor the NLM_F_ECHO flag?

The event send functions (such as drm_fabric_endpoint_event_send() called here, and drm_fabric_emit_port_change()) use genlmsg_multicast() directly without the originating request context.

When emitting a notification in response to a request, passing the request info to genl_notify() ensures that userspace applications setting NLM_F_ECHO will correctly receive their own mutations back.

Quoted 4 lines
drivers/gpu/drm/fabric/drm_fabric_nl.c +0 -0
index 0325484051466..20b277f27ae9b 100644

[ ... ]

drivers/gpu/drm/fabric/drm_fabric_nl.c static const struct nla_policy drm_fabric_port_stats_get_dump_nl_policy[DRM_FABR · line 69

Quoted 4 lines
drivers/gpu/drm/fabric/drm_fabric_nl.c +4 -0
+/* DRM_FABRIC_CMD_FABRIC_NEW - do */
+static const struct nla_policy drm_fabric_fabric_new_nl_policy[DRM_FABRIC_A_FABRIC_NEW_PARAMS + 1] = {
+	[DRM_FABRIC_A_FABRIC_NEW_PARAMS] = NLA_POLICY_NESTED(drm_fabric_fabric_new_params_nl_policy),
+};

[Severity: Medium]
Does this policy enforce an extraneous wrapping nest?

As mentioned earlier, Netlink uAPI guidelines discourage wrapping nests for new families. Can these parameters be flattened into the main attribute set?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=9
#16 lore raw

RFC PATCH 10/12 drm/fabric: make the synthetic provider writable

In reply to Konstantin Sinyuk

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.

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(-)
Documentation/gpu/drm-fabric.rst +4 -0
index 4ee7cb7ef6ac..1fd48027eee3 100644
@@ -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
drivers/gpu/drm/fabric/drm_fabric_sim.c +102 -36

258 lines not on this page · raw message

Signature · 1 line
2.43.0
#17 lore raw

RFC PATCH 11/12 drm/fabric: add mutation KUnit tests

In reply to Konstantin Sinyuk

Add KUnit coverage for the provisioning core: userspace-fabric lifetime and its module reference, orphan attach and detach, administrative state, peer-management authority, and failure paths that must not commit.

Threaded cases verify that mutation serializes against endpoint unregister and competing fabric-ep-id registration, and that concurrent mutators never overlap provider callbacks.

Assisted-by GitHub-Copilot:claude-opus-4.8
---
 drivers/gpu/drm/fabric/Kconfig           |    3 +-
 drivers/gpu/drm/fabric/drm_fabric_test.c | 1612 ++++++++++++++++++++--
 2 files changed, 1467 insertions(+), 148 deletions(-)
drivers/gpu/drm/fabric/Kconfig +2 -1
index 2a70cac85b1d..7f427ac42a27 100644
@@ -29,7 +29,8 @@ config DRM_FABRIC_KUNIT_TEST
 	depends on KUNIT=y || DRM_FABRIC=m
 	default KUNIT_ALL_TESTS
 	help
-	  Enable KUnit coverage for the drm_fabric object model.
+	  KUnit tests for the drm_fabric object model and topology-mutation
+	  paths.
 
 	  The tests are built into drm_fabric itself, so they need no exported
 	  symbols or test-only accessors in the production source.
drivers/gpu/drm/fabric/drm_fabric_test.c +1465 -147

1,735 lines not on this page · raw message

Signature · 1 line
2.43.0
#18 lore raw

Re: [RFC PATCH 11/12] drm/fabric: add mutation KUnit tests

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] Uninitialized pointer in test timeout path causes kernel panic during cleanup --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Uninitialized pointer in test timeout path causes kernel panic during cleanup --

--- Patch [11]: [RFC PATCH 11/12] drm/fabric: add mutation KUnit tests --- commit 4053deb9cc41982c0c7a86f0e14eb969bfd85f18
Author: Konstantin Sinyuk <[email protected]>

drm/fabric: add mutation KUnit tests

This commit adds KUnit coverage for the drm_fabric object model and topology-mutation paths. It tests various endpoint and port mutation scenarios, including concurrent mutations, orphan attach/detach, and error paths.

Quoted 4 lines
drivers/gpu/drm/fabric/drm_fabric_test.c +0 -0
index 863b7cf690689..d2c88d1837375 100644

[ ... ]

Quoted 2 lines
drivers/gpu/drm/fabric/drm_fabric_test.c +2 -0
+static void drm_fabric_test_attach_register_collision(struct kunit *test)
+{

[ ... ]

Quoted 5 lines
drivers/gpu/drm/fabric/drm_fabric_test.c +5 -0
+	/* B then proceeds and must fail: X is now owned by A. */
+	KUNIT_EXPECT_GT(test,
+			wait_for_completion_timeout(&l4->reg_done, msecs_to_jiffies(5000)),
+			0);
+	if (!IS_ERR(l4->reg_ep)) {

drivers/gpu/drm/fabric/drm_fabric_test.c static void drm_fabric_test_subtree_delete_single_bump(struct kunit *test) · line 1616

Quoted 10 lines
drivers/gpu/drm/fabric/drm_fabric_test.c +10 -0
+		KUNIT_ASSERT_EQ(test, 0,
+				kunit_add_action_or_reset(test,
+							  fabrictest_unregister_endpoint,
+							  l4->reg_ep));
+		KUNIT_FAIL(test, "racing registration unexpectedly succeeded");
+		return;
+	}
+
+	KUNIT_EXPECT_EQ(test, PTR_ERR(l4->reg_ep), -EEXIST);
+}

[Severity: Medium]
If the registration thread stalls and wait_for_completion_timeout() times out (returning 0), l4->reg_ep will remain NULL since l4 was allocated with kunit_kzalloc().

Because IS_ERR(NULL) evaluates to false, wouldn't this execution path enter the if block and pass NULL to fabrictest_unregister_endpoint() during cleanup?

This would lead to a NULL pointer dereference and a kernel panic when drm_fabric_endpoint_unregister() attempts to access the pointer.

Should this check use IS_ERR_OR_NULL(l4->reg_ep) instead, or should l4->reg_ep be initialized to an error pointer before the thread is spawned?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=11
#19 lore raw

RFC PATCH 12/12 drm/fabric: add mutation netlink selftests

In reply to Konstantin Sinyuk

Add three programs covering CAP_NET_ADMIN enforcement, non-init_net rejection and end-to-end provisioning: orphan attach, administrative-state changes, peer installation, link failure and recovery.

Extend the query, hotplug, fault and policy tests for the mutation operations. The policy probe now builds nested requests with NLA_F_NESTED, so an out-of-range nested member reaches the range check and is refused with -ERANGE instead of as a malformed nest.

The run reports 172 results across fourteen programs, all passing in a booted virtme-ng guest.

Assisted-by GitHub-Copilot:claude-opus-4.8
---
 Documentation/gpu/drm-fabric.rst              |   3 +-
 .../selftests/drivers/gpu/drm_fabric/Makefile |   3 +
 .../drivers/gpu/drm_fabric/README.rst         |  20 +-
 .../drivers/gpu/drm_fabric/cap_netadmin.py    | 314 +++++++++++++++++
 .../selftests/drivers/gpu/drm_fabric/config   |   5 +
 .../drivers/gpu/drm_fabric/fabric_abi.py      | 156 ++++++++-
 .../drivers/gpu/drm_fabric/fault_abi.py       | 211 +++++++++++-
 .../drivers/gpu/drm_fabric/hotplug_abi.py     | 145 +++++++-
 .../drivers/gpu/drm_fabric/lib_drm_fabric.py  |  17 +
 .../drivers/gpu/drm_fabric/netns_abi.py       | 294 ++++++++++++++++
 .../drivers/gpu/drm_fabric/nl_policy_probe.py | 280 ++++++++++++---
 .../drm_fabric/provisioning_scenarios_abi.py  | 324 ++++++++++++++++++
 .../drivers/gpu/drm_fabric/switch_abi.py      |  31 +-
 13 files changed, 1721 insertions(+), 82 deletions(-)
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/cap_netadmin.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/netns_abi.py
 create mode 100755 tools/testing/selftests/drivers/gpu/drm_fabric/provisioning_scenarios_abi.py
Documentation/gpu/drm-fabric.rst +2 -1
index 1fd48027eee3..e400c44d32b8 100644
@@ -474,5 +474,6 @@ Generic Netlink ABI tests live under
 ``tools/testing/selftests/drivers/gpu/drm_fabric``. They cover the YNL query
 paths, malformed policy input, generated-header synchronization, dump-cursor
 correctness across endpoint removal, ``NLM_F_DUMP_INTR`` handling, the opaque
-switch half-edge, and provider fault handling. See that directory's ``README.rst``
+switch half-edge, ``CAP_NET_ADMIN`` gating and provisioning rejects, and
+provider fault-injection failure atomicity. See that directory's ``README.rst``
 for build and execution commands.
tools/testing/selftests/drivers/gpu/drm_fabric/Makefile +3 -0
index 54d756979d97..6cdf14c44a5a 100644
@@ -18,7 +18,10 @@ TEST_PROGS := \
 	hotplug_abi.py \
 	dump_scale_abi.py \
 	switch_abi.py \
+	cap_netadmin.py \
+	netns_abi.py \
 	fault_abi.py \
+	provisioning_scenarios_abi.py \
 	harness_reset_abi.py
 
 TEST_FILES := lib_drm_fabric.py
tools/testing/selftests/drivers/gpu/drm_fabric/README.rst +15 -5
index 6c24581db1f2..33d9618b31d5 100644
@@ -4,7 +4,7 @@
 drm_fabric selftests
 ====================
 
-These selftests exercise the ``drm-fabric`` query uAPI against
+These selftests exercise the ``drm-fabric`` query and mutation uAPI against
 ``drm_fabric_sim`` using the in-tree YNL library. KUnit covers the core object
 model.
 
@@ -45,7 +45,7 @@ Suites
   ends the dump.
 
 ``hotplug_abi.py``
-  Endpoint hotplug: CREATE/DELETE notifications.
+  Endpoint hotplug: CREATE/DELETE NTFs and mutation round-trips.
 
 ``dump_scale_abi.py``
   Dump resume under many endpoints (``bulk_add``).
@@ -54,10 +54,19 @@ Suites
   Opaque switch peers whose identifiers do not resolve to an endpoint
   (``topology=switch``).
 
+``cap_netadmin.py``
+  ``CAP_NET_ADMIN`` enforcement for mutation commands.
+
+``netns_abi.py``
+  Rejects commands outside ``init_net``, including with ``CAP_NET_ADMIN``.
+
 ``fault_abi.py``
-  Provider fault injection: errno propagation and no leaked endpoint
+  Provider failures: errno propagation, rollback and no notification
   (``fail_*``).
 
+``provisioning_scenarios_abi.py``
+  Endpoint, port and peer provisioning scenarios.
+
 ``harness_reset_abi.py``
   Recovery after a SIGKILL-terminated predecessor.
 
@@ -71,6 +80,7 @@ A SKIP means a required precondition was unavailable.
 
 Environment
   ``check-spec-regen.sh`` needs PyYAML and writable temporary storage.
+  ``netns_abi.py`` needs ``CONFIG_NET_NS``.
 
 Per case
   A case skips when a required control, parameter or family capability is
@@ -81,7 +91,7 @@ Whole suite
 
 Timing
   The two ``dump_intr_abi.py`` boundary cases may skip if the concurrent
-  topology change misses the required dump boundary.
+  mutation misses the required dump boundary.
 
 KUnit
 -----
@@ -133,4 +143,4 @@ Build out-of-tree, boot with ``vng`` and run the same target in the guest:
        make -C tools/testing/selftests TARGETS=drivers/gpu/drm_fabric run_tests
 
 Dependencies (Debian/Ubuntu): ``python3``, ``python3-yaml``,
-``qemu-system-x86``, ``virtme-ng`` (``pip install --user virtme-ng``).
\ No newline at end of file
+``qemu-system-x86``, ``virtme-ng`` (``pip install --user virtme-ng``).
tools/testing/selftests/drivers/gpu/drm_fabric/cap_netadmin.py new file +314 -0

314 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/config +5 -0
index 6eaab8a7d771..f7b38c11a5a9 100644
@@ -2,6 +2,11 @@
 # Kernel config fragment required to run the drm_fabric kselftests.
 # Merge with: scripts/kconfig/merge_config.sh or make kselftest-merge.
 CONFIG_NET=y
+# netns_abi.py drives the init_net restriction from a non-initial namespace.
+# USER_NS lets it model container root; without it the suite still runs, using
+# a network namespace alone.
+CONFIG_NET_NS=y
+CONFIG_USER_NS=y
 CONFIG_DRM=y
 CONFIG_DEBUG_FS=y
 CONFIG_DRM_FABRIC=m
tools/testing/selftests/drivers/gpu/drm_fabric/fabric_abi.py +154 -2

194 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/fault_abi.py +204 -7

250 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/hotplug_abi.py +136 -9

185 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/lib_drm_fabric.py +17 -0
index 30fb0edb02b9..9e5dfd6a6ba9 100644
@@ -267,6 +267,16 @@ def family_has_op(fab, name):
     return name in getattr(fab, "ops", {})
 
 
+def select_cases(fab, cases, mutation_cases, probe="fabric-new"):
+    """Return @cases, dropping @mutation_cases when @probe (a representative
+    mutation op) is absent from the family.
+    """
+    if family_has_op(fab, probe):
+        return tuple(cases)
+    drop = set(mutation_cases)
+    return tuple(c for c in cases if c not in drop)
+
+
 # System helpers (kselftest runs as root)
 
 def is_root():
@@ -462,6 +472,13 @@ def fabricsim(ksft, topology=None, need_debugfs=False, need_control=None,
         if not insmod("drm-fabric.ko") or not insmod("drm-fabric-sim.ko"):
             ksft.skip_all("could not load drm_fabric + drm_fabric_sim modules")
         wait_until(lambda: module_loaded("drm_fabric_sim"))
+    else:
+        # Running against providers somebody else loaded (--no-load, or a
+        # previous suite that restored the sim but kept the core). There is no
+        # module to unwind, but the suite can still add endpoints and peers,
+        # and without a teardown that state would leak into the next suite and
+        # survive the timeout killer's SIGTERM. Restore the default shape.
+        on_teardown(sim_restore_default)
 
     if not module_loaded("drm_fabric_sim"):
         ksft.skip_all("drm_fabric_sim not loaded")
tools/testing/selftests/drivers/gpu/drm_fabric/netns_abi.py new file +294 -0

294 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/nl_policy_probe.py +223 -57

395 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/provisioning_scenarios_abi.py new file +324 -0

324 lines not on this page · raw message

tools/testing/selftests/drivers/gpu/drm_fabric/switch_abi.py +30 -1
index 775be4ac2160..152d16cdc464 100755
@@ -4,7 +4,9 @@
 """
 fabricsim's "switch" shape links each leaf's first port to an opaque
 switch that is not a registered endpoint: asserts half-edge serialization
-and peer-id non-resolution, not leaf-switch-leaf reachability.
+and peer-id non-resolution, not leaf-switch-leaf reachability. A final case
+reloads at a one-port-per-endpoint request, where the port reserved for
+userspace peers would otherwise consume the only half-edge.
 
 --no-load is ignored (needs a fresh insmod). Run as root.
 """
@@ -78,11 +80,38 @@ def test_switch_id_does_not_resolve(ksft, cfg):
                % sorted(leaked))
 
 
+def test_minimum_request_preserves_switch_wiring(ksft, cfg):
+    """A one-port-per-endpoint request must still leave the switch wired:
+    setup raises the count so the reserved userspace port does not consume
+    the only half-edge.
+
+    Runs last: it reloads the sim, invalidating the snapshot above.
+    """
+    fab = cfg.fab
+    L.rmmod("drm_fabric_sim")
+    if not L.insmod("drm-fabric-sim.ko", "topology=switch", "ports_per_ep=1"):
+        ksft.skip("switch-minimum-request-wired",
+                  "could not load sim with ports_per_ep=1")
+        return
+    if not L.wait_until(lambda: L.module_loaded("drm_fabric_sim")):
+        ksft.skip("switch-minimum-request-wired", "sim did not reappear")
+        return
+
+    eps = [e["endpoint"] for e in fab.dump("endpoint-get", {})]
+    sim_eps = [e for e in eps if e["name"].startswith("sim-ep")]
+    peers = switch_peers(fab, sim_eps)
+    ksft.check(bool(sim_eps) and len(peers) == len(sim_eps),
+               "switch-minimum-request-wired",
+               "ports_per_ep=1: switch-peers=%d leaves=%d"
+               % (len(peers), len(sim_eps)))
+
+
 CASES = (
     test_every_leaf_has_switch_peer,
     test_half_edge_fully_serialized,
     test_single_opaque_switch_id,
     test_switch_id_does_not_resolve,
+    test_minimum_request_preserves_switch_wiring,
 )
 
 
Signature · 1 line
2.43.0
#20 lore raw
In reply to Konstantin Sinyuk
Quoted 4 lines · Konstantin Sinyuk

Modern GPUs and AI accelerators are increasingly connected through scale-up fabrics such as AMD xGMI today and emerging UALink systems [4]. Linux lacks common, vendor-neutral infrastructure for reporting which accelerators are directly connected, through which ports, and in what state.

<...>

Quoted 3 lines

No production provider is included. Shipping only the synthetic provider is deliberate, allowing the object model and uAPI to be reviewed before being tied to hardware.

Tell your AI that this is not how things work in the real world. The chances of multiple hardware implementations fitting a software model designed without considering the actual hardware are effectively zero. This is why successful subsystems have emerged from consolidating support for multiple existing hardware implementations.

Thanks

#21 lore raw
Quoted 5 lines · Leon Romanovsky

Tell your AI that this is not how things work in the real world. The chances of multiple hardware implementations fitting a software model designed without considering the actual hardware are effectively zero. This is why successful subsystems have emerged from consolidating support for multiple existing hardware implementations.

Fair point. The simulator validates the implementation, not whether the abstraction fits real hardware.

The model was shaped by the public amdgpu xGMI implementation, and the cover letter asks AMD whether it covers their requirements. It still needs validation against production implementations, and the read-only milestone will not be proposed for merge without a production provider. I will fix the wording in the next revision.

Thanks,
Konstantin.

#22 lore raw
Quoted 7 lines · Konstantin Sinyuk
Quoted 5 lines · Leon Romanovsky

Tell your AI that this is not how things work in the real world. The chances of multiple hardware implementations fitting a software model designed without considering the actual hardware are effectively zero. This is why successful subsystems have emerged from consolidating support for multiple existing hardware implementations.

Quoted 8 lines

Fair point. The simulator validates the implementation, not whether the abstraction fits real hardware.

The model was shaped by the public amdgpu xGMI implementation, and the cover letter asks AMD whether it covers their requirements. It still needs validation against production implementations, and the read-only milestone will not be proposed for merge without a production provider. I will fix the wording in the next revision.

The wording alone is not sufficient. Your proposal should be backed by real devices representing different architectures from different vendors.

The current proposal is based on a single implementation, which is unlikely to be ported to this new framework in the foreseeable future. The amdgpu xGMI implementation already exposes the required UAPI through sysfs and would need very strong incentives to abandon its "legacy" users in favor of this new netlink interface.

The last new subsystem I am aware of was introduced with implementations from three different vendors to demonstrate its robustness. You should probably aim for a similar level of coverage here.

Thanks

Quoted 3 lines

Thanks,
Konstantin.

#23 lore raw
Quoted 7 lines · Leon Romanovsky
Quoted 6 lines · Konstantin Sinyuk
Quoted 5 lines · Leon Romanovsky

Tell your AI that this is not how things work in the real world. The chances of multiple hardware implementations fitting a software model designed without considering the actual hardware are effectively zero. This is why successful subsystems have emerged from consolidating support for multiple existing hardware implementations.

Right, but we also have to tell AI that the real world is much more complicated than this. When various vendors already had multiple different implementations in place, they will refuse to consolidate... like you stated yourself below:
"which is unlikely to be ported to this new framework"

Perhaps what we missed to tell AI is to add a clear statement that this is an RFC for future. To discuss the design in advance so when the real hardware starts to appear perhaps we have a chance of moving things to a consolidated vendor-agnostic API that fulfills the need of the vendor-agnostic UALink design.

Quoted 10 lines
Quoted 9 lines

Fair point. The simulator validates the implementation, not whether the abstraction fits real hardware.

The model was shaped by the public amdgpu xGMI implementation, and the cover letter asks AMD whether it covers their requirements. It still needs validation against production implementations, and the read-only milestone will not be proposed for merge without a production provider. I will fix the wording in the next revision.

Quoted 3 lines

The wording alone is not sufficient. Your proposal should be backed by real devices representing different architectures from different vendors.

Future Intel (and other vendors) hardware will include UALink. Please notice this is an RFC to discuss the viability and design for when these devices start to appear.

Quoted 10 lines

The current proposal is based on a single implementation, which is unlikely to be ported to this new framework in the foreseeable future. The amdgpu xGMI implementation already exposes the required UAPI through sysfs and would need very strong incentives to abandon its "legacy" users in favor of this new netlink interface.

The last new subsystem I am aware of was introduced with implementations from three different vendors to demonstrate its robustness. You should probably aim for a similar level of coverage here.

If we wait 3 different devices to show-up before we can start discussing a common API, then it might be way too late.

But of course, we can definitely move this netlink as is to inside drivers/gpu/drm/xe and call it xe_fabric and if someone else is interested in join effort we move that outside.

Thanks,
Rodrigo.

Quoted 6 lines

Thanks

Quoted 3 lines

Thanks,
Konstantin.

#24 lore raw
Quoted 3 lines · Rodrigo Vivi
Quoted 2 lines · Leon Romanovsky
Quoted 1 line · Konstantin Sinyuk

On Wed, Aug 26, 2026 at 12:32:22PM +0300, Leon Romanovsky wrote:

<...>

Quoted 5 lines
Quoted 3 lines

The wording alone is not sufficient. Your proposal should be backed by real devices representing different architectures from different vendors.

Future Intel (and other vendors) hardware will include UALink.

I guess that, like most of us, you are not authorized to discuss or comment on Intel's non-public roadmap. Can you point to any public commitment from Intel to implement UALink in its devices?

I couldn't find one.

<...>

Quoted 10 lines
Quoted 9 lines

The current proposal is based on a single implementation, which is unlikely to be ported to this new framework in the foreseeable future. The amdgpu xGMI implementation already exposes the required UAPI through sysfs and would need very strong incentives to abandon its "legacy" users in favor of this new netlink interface.

The last new subsystem I am aware of was introduced with implementations from three different vendors to demonstrate its robustness. You should probably aim for a similar level of coverage here.

Quoted 6 lines

If we wait 3 different devices to show-up before we can start discussing a common API, then it might be way too late.

But of course, we can definitely move this netlink as is to inside drivers/gpu/drm/xe and call it xe_fabric and if someone else is interested in join effort we move that outside.

We are not talking about "waiting for", but about "being backed by". The general kernel rule is that the second implementation is responsible for consolidating the code. XE appears to be that second implementation.

Thanks

Quoted 10 lines

Thanks,
Rodrigo.

Quoted 6 lines

Thanks

Quoted 3 lines

Thanks,
Konstantin.

#25 lore raw
Quoted 11 lines · Leon Romanovsky
Quoted 3 lines · Rodrigo Vivi
Quoted 2 lines · Leon Romanovsky
Quoted 1 line · Konstantin Sinyuk

On Wed, Aug 26, 2026 at 12:32:22PM +0300, Leon Romanovsky wrote:

<...>

Quoted 4 lines
Quoted 3 lines

The wording alone is not sufficient. Your proposal should be backed by real devices representing different architectures from different vendors.

Quoted 5 lines
Quoted 1 line

Future Intel (and other vendors) hardware will include UALink.

I guess that, like most of us, you are not authorized to discuss or comment on Intel's non-public roadmap. Can you point to any public commitment from Intel to implement UALink in its devices?

That's the only public support commitment you will find for now:

https://ualinkconsortium.org/blog/intel-supports-ualink-for-scale-up-networking-829/

as an active member of the consortium
https://ualinkconsortium.org/members/

Quoted 18 lines

I couldn't find one.

<...>

Quoted 13 lines
Quoted 9 lines

The current proposal is based on a single implementation, which is unlikely to be ported to this new framework in the foreseeable future. The amdgpu xGMI implementation already exposes the required UAPI through sysfs and would need very strong incentives to abandon its "legacy" users in favor of this new netlink interface.

The last new subsystem I am aware of was introduced with implementations from three different vendors to demonstrate its robustness. You should probably aim for a similar level of coverage here.

If we wait 3 different devices to show-up before we can start discussing a common API, then it might be way too late.

Quoted 7 lines
Quoted 3 lines

But of course, we can definitely move this netlink as is to inside drivers/gpu/drm/xe and call it xe_fabric and if someone else is interested in join effort we move that outside.

We are not talking about "waiting for", but about "being backed by". The general kernel rule is that the second implementation is responsible for consolidating the code. XE appears to be that second implementation.

Again, this is an RFC, not a merge request. The goal is to do it right from beginning rather than facing years of churn after things are already implemented so differently by downstream solutions.

Quoted 14 lines

Thanks

Quoted 10 lines

Thanks,
Rodrigo.

Quoted 6 lines

Thanks

Quoted 3 lines

Thanks,
Konstantin.

#26 lore raw
Quoted 18 lines · Rodrigo Vivi
Quoted 11 lines · Leon Romanovsky
Quoted 3 lines · Rodrigo Vivi
Quoted 2 lines · Leon Romanovsky
Quoted 1 line · Konstantin Sinyuk

On Wed, Aug 26, 2026 at 12:32:22PM +0300, Leon Romanovsky wrote:

<...>

Quoted 4 lines
Quoted 3 lines

The wording alone is not sufficient. Your proposal should be backed by real devices representing different architectures from different vendors.

Quoted 5 lines
Quoted 1 line

Future Intel (and other vendors) hardware will include UALink.

I guess that, like most of us, you are not authorized to discuss or comment on Intel's non-public roadmap. Can you point to any public commitment from Intel to implement UALink in its devices?

Quoted 6 lines

That's the only public support commitment you will find for now:

https://ualinkconsortium.org/blog/intel-supports-ualink-for-scale-up-networking-829/

as an active member of the consortium
https://ualinkconsortium.org/members/

I saw that PR article, but I couldn't find anything on the Internet stating that "future Intel (or other vendors') hardware will include UALink."

So, for now, this RFC can be considered an academic project.

Thanks

#27 lore raw
In reply to Leon Romanovsky
Quoted 3 lines · Leon Romanovsky

The wording alone is not sufficient. Your proposal should be backed by real devices representing different architectures from different vendors.

Agreed that discussion and simulation are not substitutes for hardware implementations. This RFC is meant to shape the model early, while it can still change, and to ask whether the objects hold for other scale-up protocols, including NVLink and SUE/ESUN, not only xGMI and UALink. It is not a merge proposal.

Quoted 3 lines

The amdgpu xGMI implementation already exposes the required UAPI through sysfs and would need very strong incentives to abandon its "legacy" users in favor of this new netlink interface.

Nothing has to be abandoned. An amdgpu provider could publish topology through the common in-kernel API while the existing xGMI sysfs stays as it is.

I agree that xGMI alone gives AMD little incentive to add another interface. The stronger motivation is UALink: it is a new cross-vendor ecosystem, and accelerator and switch components may be owned by different vendors and subsystems. Common userspace should not have to assemble one fabric from incompatible vendor interfaces.

The cost of waiting until every vendor has a shipped interface is that the common model then has to preserve all of them. That is the position xGMI is already in today.

Quoted 3 lines

The last new subsystem I am aware of was introduced with implementations from three different vendors to demonstrate its robustness. You should probably aim for a similar level of coverage here.

That is a reasonable robustness target, and I cannot claim it today. The next revision remains a design RFC. The object model and subsystem boundary still need review against different hardware architectures.

The LPC BoF is the next step:

https://lpc.events/event/20/contributions/2412/

Thanks,
Konstantin

#28 lore raw
In reply to Konstantin Sinyuk

Mon, Aug 24, 2026 at 10:09:28AM +0200, [email protected] wrote:

[..]

Quoted 11 lines

Example queries using the in-tree YNL tool are:

   $ ./tools/net/ynl/pyynl/cli.py \
         --spec Documentation/netlink/specs/drm_fabric.yaml \
         --dump fabric-get
   $ ./tools/net/ynl/pyynl/cli.py \
         --spec Documentation/netlink/specs/drm_fabric.yaml \
         --dump endpoint-get --json '{"fabric-id": <id>}'
   $ ./tools/net/ynl/pyynl/cli.py \
         --spec Documentation/netlink/specs/drm_fabric.yaml \
         --do port-get --json '{"endpoint-id": <id>, "port-index": 0}'

Using generic netlink instead of sysfs for this makes a lot of sense, but it may be a bit odd to use it outside the networking area. I've been struggling with the same in another non-networking use-case as well. I have been building a framework that keeps the benefits of generic netlink, extends it and is fd-based.
I call it CTLV, here's a link to an early pre-RFC draft:

https://github.com/jpirko/linux_mlxsw/commits/wip_ctlv_pre_rfc_draft1/

What are the benefits over generic netlink:

- No networking in the dependency chain. No netlink sockets, no CAP_NET_ADMIN, and no network namespace semantics to reason about for a device that has none.

- One character device per registered instance, not one global family. Access control is the file: udev rules, ACLs, an fd passed into a container. The open mode decides what is allowed - actions need write, queries need read - so there is no permission model to reinvent per family.

- Events per open file description, not a multicast group. Each descriptor has its own subscriptions and queue, and an overflow is reported in-band: the next read returns an event-overflow record naming the first and last sequence lost and how many.

- Large payloads are referenced, not copied. A blob attribute carries a user VA, a memfd and offset, or a dma-buf fd. Nothing big travels through the message.

- One YAML specification, everything generated from it: kernel metadata, UAPI headers, userspace bindings and the reference documentation. Introspectio. is answered out of the same metadata the validator enforces, so a device cannot advertise an operation it will refuse. A checked-in ABI snapshot makes any wire change a reviewable diff.

- Family inheritance. A family inherits another's operations and fills declared extension points. The effective schema is resolved per device and the chain is exposed to user. A shared core with per-driver extensions is declared once, and both attributes and operations can be extended.

- Introspection is per-device and live. The framework answers three queries on every device: the family chain, one entry per published operation, and any operation's full attribute tree with its bounds and limits.

The answer is what this device accepts right now, including what a vendor extension added to an inherited operation and whether an op is currently disabled, and op-changed events carry the generation ops-dump reports, so a dump can be ordered against a change. GETFAMILY and GETPOLICY describe a family statically - there is no device in that model to ask.

- Fragmented queries are built in, with a consistency check. A continuation carries the generation it started from, and if the answer changed underneath it is refused with ESTALE, reporting the expected and the current generation instead of reassembling a torn reply.

- Attributes are 8-byte aligned. CTLV_ALIGNTO is 8, so a 64-bit payload is naturally aligned and there is no per-family padding to remember - netlink's 4-byte alignment is why nla_put_64bit() needs an explicit NOP pad attribute.

- Cheaper round trip. A one-attribute query measured 2.6x cheaper than a genetlink one in the same guest - a debug kernel.

- Async operations using io_uring are planned as a follow-up extension.

The framework owns validation, schema resolution, blob acquisition, reply serialization and the event queues. All getters and putters are generated helpers. A family implements semantics only, and the aim is to make that hard to get wrong.

Would this make sense to use for you?

[..]

#29 lore raw
Quoted 16 lines · Jiri Pirko

Mon, Aug 24, 2026 at 10:09:28AM +0200, [email protected] wrote:

[..]

Quoted 11 lines

Example queries using the in-tree YNL tool are:

   $ ./tools/net/ynl/pyynl/cli.py \
         --spec Documentation/netlink/specs/drm_fabric.yaml \
         --dump fabric-get
   $ ./tools/net/ynl/pyynl/cli.py \
         --spec Documentation/netlink/specs/drm_fabric.yaml \
         --dump endpoint-get --json '{"fabric-id": <id>}'
   $ ./tools/net/ynl/pyynl/cli.py \
         --spec Documentation/netlink/specs/drm_fabric.yaml \
         --do port-get --json '{"endpoint-id": <id>, "port-index": 0}'
Quoted 4 lines

Using generic netlink instead of sysfs for this makes a lot of sense, but it may be a bit odd to use it outside the networking area. I've been struggling with the same in another non-networking use-case as well.

Please notice that this bubble was already broken. Netlink design always had the dream to replace ioctl everywhere. And there are already other usage in place that are not network related.

In our case we use the netlink API for GPU RAS error reporting: drm-ras.

Also there are other usages in netlink spec that apparently has nothing to do with networking, like energy...

And in this particular case here, the drm-fabric is a 'network' of GPU memory... At some point we even wondered if net/ was the right place for this common API....

Quoted 75 lines

I have been building a framework that keeps the benefits of generic netlink, extends it and is fd-based.
I call it CTLV, here's a link to an early pre-RFC draft:

https://github.com/jpirko/linux_mlxsw/commits/wip_ctlv_pre_rfc_draft1/

What are the benefits over generic netlink:

- No networking in the dependency chain. No netlink sockets, no CAP_NET_ADMIN, and no network namespace semantics to reason about for a device that has none.

- One character device per registered instance, not one global family. Access control is the file: udev rules, ACLs, an fd passed into a container. The open mode decides what is allowed - actions need write, queries need read - so there is no permission model to reinvent per family.

- Events per open file description, not a multicast group. Each descriptor has its own subscriptions and queue, and an overflow is reported in-band: the next read returns an event-overflow record naming the first and last sequence lost and how many.

- Large payloads are referenced, not copied. A blob attribute carries a user VA, a memfd and offset, or a dma-buf fd. Nothing big travels through the message.

- One YAML specification, everything generated from it: kernel metadata, UAPI headers, userspace bindings and the reference documentation. Introspectio. is answered out of the same metadata the validator enforces, so a device cannot advertise an operation it will refuse. A checked-in ABI snapshot makes any wire change a reviewable diff.

- Family inheritance. A family inherits another's operations and fills declared extension points. The effective schema is resolved per device and the chain is exposed to user. A shared core with per-driver extensions is declared once, and both attributes and operations can be extended.

- Introspection is per-device and live. The framework answers three queries on every device: the family chain, one entry per published operation, and any operation's full attribute tree with its bounds and limits.

The answer is what this device accepts right now, including what a vendor extension added to an inherited operation and whether an op is currently disabled, and op-changed events carry the generation ops-dump reports, so a dump can be ordered against a change. GETFAMILY and GETPOLICY describe a family statically - there is no device in that model to ask.

- Fragmented queries are built in, with a consistency check. A continuation carries the generation it started from, and if the answer changed underneath it is refused with ESTALE, reporting the expected and the current generation instead of reassembling a torn reply.

- Attributes are 8-byte aligned. CTLV_ALIGNTO is 8, so a 64-bit payload is naturally aligned and there is no per-family padding to remember - netlink's 4-byte alignment is why nla_put_64bit() needs an explicit NOP pad attribute.

- Cheaper round trip. A one-attribute query measured 2.6x cheaper than a genetlink one in the same guest - a debug kernel.

- Async operations using io_uring are planned as a follow-up extension.

The framework owns validation, schema resolution, blob acquisition, reply serialization and the event queues. All getters and putters are generated helpers. A family implements semantics only, and the aim is to make that hard to get wrong.

Would this make sense to use for you?

[..]

#30 lore raw
Quoted 17 lines · Rodrigo Vivi
Quoted 16 lines · Jiri Pirko

Mon, Aug 24, 2026 at 10:09:28AM +0200, [email protected] wrote:

[..]

Quoted 11 lines

Example queries using the in-tree YNL tool are:

   $ ./tools/net/ynl/pyynl/cli.py \
         --spec Documentation/netlink/specs/drm_fabric.yaml \
         --dump fabric-get
   $ ./tools/net/ynl/pyynl/cli.py \
         --spec Documentation/netlink/specs/drm_fabric.yaml \
         --dump endpoint-get --json '{"fabric-id": <id>}'
   $ ./tools/net/ynl/pyynl/cli.py \
         --spec Documentation/netlink/specs/drm_fabric.yaml \
         --do port-get --json '{"endpoint-id": <id>, "port-index": 0}'
Quoted 8 lines
Quoted 4 lines

Using generic netlink instead of sysfs for this makes a lot of sense, but it may be a bit odd to use it outside the networking area. I've been struggling with the same in another non-networking use-case as well.

Please notice that this bubble was already broken. Netlink design always had the dream to replace ioctl everywhere. And there are already other usage in place that are not network related.

Yeah, and people have been living with the friction, and some places don't have quite the same complexity, but that doesn't mean it cannot be improved. :)

For something complex like this, if you can't concretetly tie the HW to a net namespace, and follow the net namespace rules for visibility, then it is going to be a painful choice. I speak from alot of rdma experiance where net namespaces have been consistently challenging.

Quoted 8 lines

In our case we use the netlink API for GPU RAS error reporting: drm-ras.

Also there are other usages in netlink spec that apparently has nothing to do with networking, like energy...

And in this particular case here, the drm-fabric is a 'network' of GPU memory... At some point we even wondered if net/ was the right place for this common API....

net/ is mainly focused on IP networking, it is where you should be putting the ethernet layer at the bottom of the ua link over ethernet, SUE, or whatever. It is hard to imagine having an actual physical ethernet network and claiming no implementation will ever need to process ethernet packets or deal with ethernet phy.

There are so many variations of these "scale up" fabrics now, it would probably be appropriate to have one subsystem that aims to work with all of them. It is almost rdma but different enough it probably wouldn't fit well.

Certainly redoing all that ethernet related stuff in drm or, worse, in amdgpu, is a pretty ugly idea.

Jason

#31 lore raw
Quoted 4 lines · Jason Gunthorpe

For something complex like this, if you can't concretetly tie the HW to a net namespace, and follow the net namespace rules for visibility, then it is going to be a painful choice. I speak from alot of rdma experiance where net namespaces have been consistently challenging.

Agreed. The series does not provide meaningful namespace semantics; it is host-global and confined to init_net. I would rather make that scope explicit than invent per-netns fabric semantics that the hardware does not have.

Generic Netlink was a practical starting point, and drm_ras established the pattern in DRM, but that is a simpler problem and does not settle the choice here. A device-fd model like Jiri's may fit visibility and access control better, since a global family has no descriptor to check against. I would not switch transports based on an early pre-RFC, but I no longer consider the transport choice settled.

Quoted 3 lines

net/ is mainly focused on IP networking, it is where you should be putting the ethernet layer at the bottom of the ua link over ethernet, SUE, or whatever.

Agreed. Ethernet PHY, MAC, packet processing and switch routing belong in the networking stack, not in DRM or an accelerator driver.

Scale-up can reuse those layers where they fit. What differs is the accelerator-facing semantics, even when the underlying transport reuses Ethernet. From the accelerator side, a scale-up endpoint behaves more like another core in a tightly coupled system than an ordinary NIC.

This series does not duplicate the networking layers. It models endpoints, ports, direct adjacency, membership and local state: no netdev, packet processing, Ethernet PHY management, route computation or switch forwarding.

Quoted 4 lines

There are so many variations of these "scale up" fabrics now, it would probably be appropriate to have one subsystem that aims to work with all of them. It is almost rdma but different enough it probably wouldn't fit well.

Worth testing. I would rather approach that through the minimum common object model than start by defining a complete subsystem.

DRM is the current location because the initial providers are DRM and accel drivers, not because DRM should own the transport or must be the final home. The objects do not depend on GEM, scheduling, display or DRM memory semantics.

Switches are the difficult case. A UALink switch is not a DRM device, and complete Pod topology may involve information owned by the Pod Controller and switch-management plane, not only accelerator drivers. If that information has to be represented as first-class objects, DRM may not be the right final home.

There is no established common Linux answer for this class of fabric yet. I would rather start with the minimum topology objects, test them against direct-link and switched implementations, and review the model with multiple vendors before deciding its final scope and home.

The LPC BoF is where I want the accelerator, networking and RDMA sides in the same room:

https://lpc.events/event/20/contributions/2412/

Thanks,
Konstantin

#32 lore raw
Quoted 10 lines · Konstantin Sinyuk
Quoted 4 lines · Jason Gunthorpe

For something complex like this, if you can't concretetly tie the HW to a net namespace, and follow the net namespace rules for visibility, then it is going to be a painful choice. I speak from alot of rdma experiance where net namespaces have been consistently challenging.

Agreed. The series does not provide meaningful namespace semantics; it is host-global and confined to init_net. I would rather make that scope explicit than invent per-netns fabric semantics that the hardware does not have.

For namespaces and permissions you need to decide on a granual of control. For something like this is probably one of:
- Whole machine/subsystem/fabric
- Per ASIC / end point
- Per ethernet port

I would kind of broadly guess you'd have one cdev for each fabric and one cdev per asic or port...

Then you could shove a fabric into a container sensibly..

Quoted 2 lines

against. I would not switch transports based on an early pre-RFC, but I no longer consider the transport choice settled.

It is a good moment to collaborate with Jiri so it can work out for this use case too.

Quoted 5 lines

Switches are the difficult case. A UALink switch is not a DRM device, and complete Pod topology may involve information owned by the Pod Controller and switch-management plane, not only accelerator drivers. If that information has to be represented as first-class objects, DRM may not be the right final home.

Well this series looks like it is all about telling the kernel the routing and address map to presumably program into the HW. I guess there is a bunch more to actually do the network trafic to get the routing in the first place and some userspace to bridge beween the on-link protocol and the the kernel objects?

Then there is probably another big swath to get metrics and monitoring out of the end ports..

Jason

#33 lore raw
In reply to Jiri Pirko
Quoted 4 lines · Jiri Pirko

Using generic netlink instead of sysfs for this makes a lot of sense, but it may be a bit odd to use it outside the networking area. I've been struggling with the same in another non-networking use-case as well.

Agreed, and the series shows the friction. The namespace handling is nominal, and CAP_NET_ADMIN as the mutation gate is another borrowed part of the model. I went into that in more detail in the reply to Jason.

Quoted 3 lines

- One character device per registered instance, not one global family. Access control is the file: udev rules, ACLs, an fd passed into a container.

The fd-based access and event model addresses real problems with one global family and one multicast group.

The main question is what the CTLV instance would represent. A fabric can span multiple devices and has its own lifetime. An endpoint can also be detached from a fabric with fabric-id 0 and continue to exist. A character device per accelerator would not provide the same global view as the current family.

Can a CTLV instance represent a multi-device fabric or the global fabric registry rather than one physical device?

Quoted 1 line

Would this make sense to use for you?

In principle, yes. I cannot base this series on an out-of-tree pre-RFC, but the fabric, endpoint, port and peer model is separate from the current serialization.

Changing transports would be more than regeneration, so I will read the draft before saying more.

Thanks,
Konstantin

#34 lore raw
Quoted 15 lines · Mon, Aug 31, 2026 at 01:45:15PM +0200, [email protected] wrote:
Quoted 4 lines · Jiri Pirko

Using generic netlink instead of sysfs for this makes a lot of sense, but it may be a bit odd to use it outside the networking area. I've been struggling with the same in another non-networking use-case as well.

Agreed, and the series shows the friction. The namespace handling is nominal, and CAP_NET_ADMIN as the mutation gate is another borrowed part of the model. I went into that in more detail in the reply to Jason.

Quoted 3 lines

- One character device per registered instance, not one global family. Access control is the file: udev rules, ACLs, an fd passed into a container.

Quoted 8 lines

The fd-based access and event model addresses real problems with one global family and one multicast group.

The main question is what the CTLV instance would represent. A fabric can span multiple devices and has its own lifetime. An endpoint can also be detached from a fabric with fabric-id 0 and continue to exist. A character device per accelerator would not provide the same global view as the current family.

CTVL is supposed to be just "transport". So however you use it is up to you.

Quoted 3 lines

Can a CTLV instance represent a multi-device fabric or the global fabric registry rather than one physical device?

Yes, whoever creates the ctlv instance is in charge of the lifecycle.

Quoted 12 lines
Quoted 2 lines

Would this make sense to use for you?

In principle, yes. I cannot base this series on an out-of-tree pre-RFC, but the fabric, endpoint, port and peer model is separate from the current serialization.

Changing transports would be more than regeneration, so I will read the draft before saying more.

Thanks,
Konstantin

maintainer
#35 lore raw
In reply to Konstantin Sinyuk
Quoted 5 lines · On Mon, 24 Aug 2026 11:09:28 +0300 Konstantin Sinyuk wrote:

2. Are the Generic Netlink semantics, including dump consistency, notifications and optional port statistics, aligned with YNL expectations?

39 files changed, 13189 insertions(+)

Networking is absolutely flooded with AI generated patches. Including long term contributors excreting huge unreviewed code dumps :/ We have absolutely no time to help other subsystems. Please do not use Netlink going forward, sorry.

#36 lore raw
Quoted 11 lines · Jakub Kicinski
Quoted 5 lines · On Mon, 24 Aug 2026 11:09:28 +0300 Konstantin Sinyuk wrote:

2. Are the Generic Netlink semantics, including dump consistency, notifications and optional port statistics, aligned with YNL expectations?

39 files changed, 13189 insertions(+)

Networking is absolutely flooded with AI generated patches. Including long term contributors excreting huge unreviewed code dumps :/ We have absolutely no time to help other subsystems. Please do not use Netlink going forward, sorry.

Hi Jakub,

I do understand the feeling here :(

But I do hope that you reconsider your position here. We had such a great experience with the drm-ras using the netlink and I was really hoping that we could just reproduce the same experience here.

Netlink is such an incredible API.

Would it help if I take the maintainership of this drm-fabric netlink along with the drm-ras one, ensuring the same consistent and clean usage?

Thanks,
Rodrigo.

maintainer
#37 lore raw
Quoted 10 lines · On Fri, 25 Sep 2026 14:12:25 -0400 Rodrigo Vivi wrote:

I do understand the feeling here :(

But I do hope that you reconsider your position here. We had such a great experience with the drm-ras using the netlink and I was really hoping that we could just reproduce the same experience here.

Netlink is such an incredible API.

Would it help if I take the maintainership of this drm-fabric netlink along with the drm-ras one, ensuring the same consistent and clean usage?

Hard call, I have nothing to complain about with the drm-ras work. Purely worried about the time :( Well, that, and DRMs general love of Rust which seems to be about 10x less development efficient for us..

Let's start by feeding this + the spec into your LLM
https://github.com/masoncl/review-prompts/blob/main/kernel/subsystem/netlink.md

#38 lore raw
In reply to Konstantin Sinyuk
Quoted 4 lines

Modern GPUs and AI accelerators are increasingly connected through scale-up fabrics such as AMD xGMI today and emerging UALink systems [4]. Linux lacks common, vendor-neutral infrastructure for reporting which accelerators are directly connected, through which ports, and in what state.

Sorry for jumping in late to this discussion. We have hardware that uses UALoE (https://www.amd.com/en/products/rackscale-solutions/helios.html).
The suggestion from Jason is sensible: a new subsystem for fabrics and reuse ethernet stuff from networking subsystem where possible. We would like to continue discussing this -  Alejandro and I will be attending Plumbers virtually.

Thanks,

Alex

maintainer
#39 lore raw
Quoted 6 lines · Alex (DCCG)

Sorry for jumping in late to this discussion. We have hardware that uses UALoE (https://www.amd.com/en/products/rackscale-solutions/helios.html).
The suggestion from Jason is sensible: a new subsystem for fabrics and reuse ethernet stuff from networking subsystem where possible. We would like to continue discussing this -  Alejandro and I will be attending Plumbers virtually.

Please don't "reuse" any networking subsystem code without an ack from a networking maintainers.