Linux userland API discussions
 help / color / mirror / Atom feed
From: Jiri Pirko <jiri@resnulli.us>
To: linux-coco@lists.linux.dev
Cc: linux-kernel@vger.kernel.org, linux-api@vger.kernel.org,
	x86@kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org,
	jgg@ziepe.ca, david.quigley@intel.com, lukas@wunner.de,
	ksinyuk@kernel.org, rodrigo.vivi@intel.com,
	cedric.xing@intel.com, sameo@meta.com, drdeeglaze@gmail.com,
	James.Bottomley@HansenPartnership.com, aik@amd.com,
	jpiotrowski@nvidia.com, qinkun@google.com, pgonda@google.com,
	jic23@kernel.org, alistair.francis@wdc.com, ankita@nvidia.com,
	suzuki.poulose@arm.com, kas@kernel.org,
	rick.p.edgecombe@intel.com, elena.reshetova@intel.com,
	dave.hansen@linux.intel.com,
	sathyanarayanan.kuppuswamy@linux.intel.com, peter.fang@intel.com
Subject: [PATCH RFC 03/20] ctlv: Add the root family specification and generated files
Date: Thu, 15 Oct 2026 16:50:36 +0200	[thread overview]
Message-ID: <20261015145053.3664509-4-jiri@resnulli.us> (raw)
In-Reply-To: <20261015145053.3664509-1-jiri@resnulli.us>

From: Jiri Pirko <jiri@nvidia.com>

Define the root family used by every CTLV device. Add its ABI snapshot,
registry and manifest entries, and generated outputs.

The generated kernel descriptor is preparatory and is linked after its
handlers arrive with device and operation dispatch.

Assisted-by: Cursor: GPT-5.6 Sol
Assisted-by: Cursor: Claude Opus 5.5
Signed-off-by: Jiri Pirko <jiri@nvidia.com>
---
 Documentation/ctlv/abi/ctlv.yaml              | 186 +++++++++
 Documentation/ctlv/abi/families.registry.yaml |   7 +
 Documentation/ctlv/families.yaml              |  13 +
 Documentation/ctlv/generated-files.yaml       |  17 +
 Documentation/ctlv/specs/ctlv.yaml            | 379 ++++++++++++++++++
 drivers/ctlv/ctlv_gen.c                       | 229 +++++++++++
 include/linux/ctlv_gen.h                      | 137 +++++++
 include/uapi/linux/ctlv_families_gen.h        |  15 +
 include/uapi/linux/ctlv_gen.h                 | 271 +++++++++++++
 9 files changed, 1254 insertions(+)
 create mode 100644 Documentation/ctlv/abi/ctlv.yaml
 create mode 100644 Documentation/ctlv/abi/families.registry.yaml
 create mode 100644 Documentation/ctlv/families.yaml
 create mode 100644 Documentation/ctlv/generated-files.yaml
 create mode 100644 Documentation/ctlv/specs/ctlv.yaml
 create mode 100644 drivers/ctlv/ctlv_gen.c
 create mode 100644 include/linux/ctlv_gen.h
 create mode 100644 include/uapi/linux/ctlv_families_gen.h
 create mode 100644 include/uapi/linux/ctlv_gen.h

diff --git a/Documentation/ctlv/abi/ctlv.yaml b/Documentation/ctlv/abi/ctlv.yaml
new file mode 100644
index 000000000000..fa11bce98f46
--- /dev/null
+++ b/Documentation/ctlv/abi/ctlv.yaml
@@ -0,0 +1,186 @@
+# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
+%YAML 1.2
+---
+# Checked-in ABI snapshot of the ctlv family, written by
+# "make -C tools/ctlv abi-update".
+#
+# The checker compares this family's declarations and inherited stub fills
+# against this file. Updating it is how a UAPI change gets reviewed; an update
+# that removes or renumbers anything, narrows a bound, or makes a placement
+# required is an ABI break, whatever this file says afterwards.
+family: {name: ctlv, id: 0}
+enums:
+  op-type: {action: 1, query: 2, event: 3}
+  op-availability: {fixed: 1, dynamic: 2}
+  blob-type: {va: 1}
+  blob-direction: {input: 1, output: 2, inout: 3}
+  validation-reason: {malformed-message: 1, unknown-attr: 2, unknown-flag: 3,
+                      nesting-too-deep: 4, missing-attr: 5,
+                      too-many-occurrences: 6, value-out-of-range: 7,
+                      bad-length: 8, bad-string: 9, bad-blob-descriptor: 10,
+                      stale-generation: 11, noncontiguous-attr: 12}
+  op-fd-access: {read: 1, read-write: 2}
+attr-groups:
+  family:
+    id: 1
+    attrs:
+      id: {id: 1, type: uint}
+      name: {id: 2, type: string, max-length: 63}
+      entry: {id: 3, type: nested, max-occurrences: unlimited}
+  blob:
+    id: 2
+    attrs:
+      type: {id: 1, enum: blob-type}
+      address: {id: 2, type: uint}
+      fd: {id: 3, type: uint, max: 2147483647}
+      offset: {id: 4, type: uint}
+      length: {id: 5, type: uint, min: 1}
+  error:
+    id: 3
+    attrs:
+      reason: {id: 1, enum: validation-reason}
+      message: {id: 2, type: string, max-length: 255}
+      bad-attr-offset: {id: 3, type: uint}
+      nest-offset: {id: 4, type: uint}
+      missing-attr-id: {id: 5, type: uint}
+      expected-generation: {id: 6, type: uint}
+      current-generation: {id: 7, type: uint}
+  op:
+    id: 4
+    attrs:
+      id: {id: 1, type: uint, min: 1}
+      type: {id: 2, enum: op-type}
+      availability: {id: 3, enum: op-availability}
+      disabled: {id: 4, type: bool}
+      request-max-len: {id: 5, type: uint}
+      action-reply-max-len: {id: 6, type: uint}
+      query-reply-min-len: {id: 7, type: uint}
+      query-reply-suggested-len: {id: 8, type: uint}
+      event-record-max-len: {id: 9, type: uint}
+      state-generation: {id: 10, type: uint}
+      entry: {id: 11, type: nested, max-occurrences: unlimited}
+      fd-access: {id: 12, enum: op-fd-access}
+  schema:
+    id: 5
+    attrs:
+      attr-id: {id: 1, type: uint}
+      kind: {id: 2, type: uint}
+      max-occurrences: {id: 3, type: uint}
+      min: {id: 4, type: uint}
+      max: {id: 5, type: uint}
+      min-length: {id: 6, type: uint}
+      max-length: {id: 7, type: uint}
+      flags-mask: {id: 8, type: uint}
+      unit: {id: 9, type: uint}
+      scale: {id: 10, type: sint}
+      blob-direction: {id: 11, enum: blob-direction}
+      blob-backings: {id: 12, type: uint}
+      blob-max-length: {id: 13, type: uint}
+      blob-alignment: {id: 14, type: uint}
+      reenters: {id: 15, type: uint, min: 1}
+      attrs: {id: 16, type: nested, max-occurrences: unlimited}
+      optional-attrs: {id: 17, type: nested, max-occurrences: unlimited}
+      request: {id: 18, type: nested}
+      reply: {id: 19, type: nested}
+  event:
+    id: 6
+    attrs:
+      op-id: {id: 1, type: uint, min: 1, max-occurrences: 256}
+      queue-len: {id: 2, type: uint, min: 1, max: 16777216, unit: bytes}
+      queue-used: {id: 3, type: uint, unit: bytes}
+      first-sequence: {id: 4, type: uint}
+      last-sequence: {id: 5, type: uint}
+      dropped-count: {id: 6, type: uint}
+attr-sets:
+  family-entry: {id: 1}
+  op-entry: {id: 2}
+  op-schema-request: {id: 3}
+  schema-node: {id: 4}
+  op-schema-info: {id: 5}
+  op-change-info: {id: 6}
+  error-info: {id: 7}
+  event-subscription: {id: 8}
+  event-queue-limit: {id: 9}
+  event-queue-state: {id: 10}
+  event-overflow-info: {id: 11}
+ops:
+  families-dump:
+    abi: {id: 1, type: query, fd-access: read}
+    reply:
+      attrs:
+        - family.entry: {attrs: [family.id, family.name]}
+  ops-dump:
+    abi: {id: 2, type: query, fd-access: read}
+    reply:
+      attrs:
+        - op.entry:
+            attrs: [op.id, op.type]
+            optional-attrs: [op.availability, op.disabled, op.request-max-len,
+                             op.action-reply-max-len, op.query-reply-min-len,
+                             op.query-reply-suggested-len,
+                             op.event-record-max-len, op.fd-access]
+  op-schema-get:
+    abi: {id: 3, type: query, fd-access: read}
+    request: {attrs: [op.id]}
+    reply:
+      optional-attrs:
+        - schema.request:
+            attrs: [schema.attr-id, schema.kind, schema.max-occurrences]
+            optional-attrs:
+              - schema.min
+              - schema.max
+              - schema.min-length
+              - schema.max-length
+              - schema.flags-mask
+              - schema.unit
+              - schema.scale
+              - schema.blob-direction
+              - schema.blob-backings
+              - schema.blob-max-length
+              - schema.blob-alignment
+              - schema.reenters
+              - schema.attrs:
+                  reenters: schema-node
+              - schema.optional-attrs:
+                  reenters: schema-node
+        - schema.reply:
+            attrs: [schema.attr-id, schema.kind, schema.max-occurrences]
+            optional-attrs:
+              - schema.min
+              - schema.max
+              - schema.min-length
+              - schema.max-length
+              - schema.flags-mask
+              - schema.unit
+              - schema.scale
+              - schema.blob-direction
+              - schema.blob-backings
+              - schema.blob-max-length
+              - schema.blob-alignment
+              - schema.reenters
+              - schema.attrs:
+                  reenters: schema-node
+              - schema.optional-attrs:
+                  reenters: schema-node
+  subscriptions-add:
+    abi: {id: 4, type: action, fd-access: read}
+    request: {attrs: [event.op-id]}
+  subscriptions-remove:
+    abi: {id: 5, type: action, fd-access: read}
+    request: {attrs: [event.op-id]}
+  event-queue-get:
+    abi: {id: 6, type: query, fd-access: read}
+    reply: {attrs: [event.queue-len, event.queue-used]}
+  event-queue-set:
+    abi: {id: 7, type: action, fd-access: read}
+    request: {attrs: [event.queue-len]}
+  op-changed:
+    abi: {id: 8, type: event}
+    reply: {attrs: [op.id, op.disabled, op.state-generation]}
+  event-overflow:
+    abi: {id: 9, type: event}
+    reply:
+      attrs: [event.first-sequence, event.last-sequence, event.dropped-count]
+  device-removed:
+    abi: {id: 10, type: event}
+    reply: {}
diff --git a/Documentation/ctlv/abi/families.registry.yaml b/Documentation/ctlv/abi/families.registry.yaml
new file mode 100644
index 000000000000..2c9b9e7eee15
--- /dev/null
+++ b/Documentation/ctlv/abi/families.registry.yaml
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
+%YAML 1.2
+---
+# Checked-in ABI baseline of the ordered CTLV family registry.
+# Updated deliberately by "make -C tools/ctlv abi-update".
+families:
+  - ctlv
diff --git a/Documentation/ctlv/families.yaml b/Documentation/ctlv/families.yaml
new file mode 100644
index 000000000000..bf1dabdba5c9
--- /dev/null
+++ b/Documentation/ctlv/families.yaml
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
+%YAML 1.2
+---
+# Append-only registry of CTLV family names, indexed by family ID: the entry at
+# index N has family ID N, up to 65535. The root family owns ID 0 and heads the
+# list, and every other entry comes after the entry of the family it inherits.
+# An entry may be marked deprecated, but never reordered, removed, renamed or
+# reused, its position being its wire identity. Every entry must have a
+# specification in specs/<name>.yaml, and is added by the change that adds the
+# implementation. Fixtures under tools/ctlv/tests/ are not registered.
+
+families:
+  - ctlv
diff --git a/Documentation/ctlv/generated-files.yaml b/Documentation/ctlv/generated-files.yaml
new file mode 100644
index 000000000000..6773e0be0883
--- /dev/null
+++ b/Documentation/ctlv/generated-files.yaml
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
+%YAML 1.2
+---
+# Generated files for registered families.
+version: 1
+registry:
+  source: Documentation/ctlv/families.yaml
+  outputs:
+    uapi-header: include/uapi/linux/ctlv_families_gen.h
+
+families:
+  - name: ctlv
+    source: Documentation/ctlv/specs/ctlv.yaml
+    outputs:
+      uapi-header: include/uapi/linux/ctlv_gen.h
+      kernel-header: include/linux/ctlv_gen.h
+      kernel-source: drivers/ctlv/ctlv_gen.c
diff --git a/Documentation/ctlv/specs/ctlv.yaml b/Documentation/ctlv/specs/ctlv.yaml
new file mode 100644
index 000000000000..d58f02747e0f
--- /dev/null
+++ b/Documentation/ctlv/specs/ctlv.yaml
@@ -0,0 +1,379 @@
+# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
+%YAML 1.2
+---
+# The root CTLV family, family ID 0 and the first entry in families.yaml. It
+# inherits nothing, and every other family name begins with "ctlv-". Every CTLV
+# device answers these ops in addition to its own family's, and the attrs
+# declared here appear inside family messages: the blob group is the descriptor
+# nest of every family blob attr, the error group the error information written
+# on failure. Nothing here may be reordered or removed.
+
+family:
+  name: ctlv
+
+enums:
+  - name: op-type
+    values:
+      - action
+      - query
+      - event
+
+  # A permission, not a state: what a device currently allows is op.disabled.
+  - name: op-availability
+    values:
+      - fixed
+      - dynamic
+
+  - name: blob-type
+    values:
+      - va
+
+  - name: blob-direction
+    values:
+      - input
+      - output
+      - inout
+
+  - name: validation-reason
+    values:
+      - malformed-message
+      - unknown-attr
+      - unknown-flag
+      - nesting-too-deep
+      - missing-attr
+      - too-many-occurrences
+      - value-out-of-range
+      - bad-length
+      - bad-string
+      - bad-blob-descriptor
+      - stale-generation
+      - noncontiguous-attr
+
+  - name: op-fd-access
+    values:
+      - read
+      - read-write
+
+attr-groups:
+  # One record per family of the chain a device answers, as reported by
+  # families-dump.
+  - name: family
+    attrs:
+      - name: id
+        type: uint
+      # The registry name, also what a uevent carries. Bounded here, this being
+      # the only place a family name is on the wire.
+      - name: name
+        type: string
+        max-length: 63
+      - name: entry
+        attrs: family-entry
+        max-occurrences: unlimited
+
+  # The nest carried by every family blob attr. va uses address; fd and offset
+  # are reserved for later fd-backed types.
+  - name: blob
+    attrs:
+      - name: type
+        enum: blob-type
+      - name: address
+        type: uint
+      - name: fd
+        type: uint
+        max: 2147483647
+      - name: offset
+        type: uint
+      - name: length
+        type: uint
+        min: 1
+
+  # Error information: only what describes the first failure is present.
+  - name: error
+    attrs:
+      - name: reason
+        enum: validation-reason
+      - name: message
+        type: string
+        max-length: 255
+      - name: bad-attr-offset
+        type: uint
+      - name: nest-offset
+        type: uint
+      - name: missing-attr-id
+        type: uint
+      - name: expected-generation
+        type: uint
+      - name: current-generation
+        type: uint
+
+  # One entry per effective op, as reported by ops-dump. Length members that do
+  # not apply to an entry's op type are absent, as are fd access, availability
+  # and disabled for an event.
+  - name: op
+    attrs:
+      - name: id
+        type: uint
+        min: 1
+      - name: type
+        enum: op-type
+      - name: availability
+        enum: op-availability
+      - name: disabled
+        type: bool
+      - name: request-max-len
+        type: uint
+      - name: action-reply-max-len
+        type: uint
+      - name: query-reply-min-len
+        type: uint
+      - name: query-reply-suggested-len
+        type: uint
+      - name: event-record-max-len
+        type: uint
+      # Advances once per op state change on one device.
+      - name: state-generation
+        type: uint
+      - name: entry
+        attrs: op-entry
+        max-occurrences: unlimited
+      - name: fd-access
+        enum: op-fd-access
+
+  # One node of an op's request or reply tree, as reported by op-schema-get. A
+  # node describes a node, so attrs and optional-attrs hold these same members
+  # one level further in. Nothing here is a name: a caller matches the family
+  # chain from families-dump to find the generated UAPI.
+  - name: schema
+    attrs:
+      # Zero in a message root node, as on the wire.
+      - name: attr-id
+        type: uint
+      # enum ctlv_schema_kind.
+      - name: kind
+        type: uint
+      # Zero where the placement may repeat as often as the message has room.
+      - name: max-occurrences
+        type: uint
+      # Inclusive bounds of an integer or enum payload, raw 64-bit values read
+      # according to kind. An enum's values are numbered without gaps.
+      - name: min
+        type: uint
+      - name: max
+        type: uint
+      # Payload length bounds of a string or binary attr, a string's
+      # terminator excluded.
+      - name: min-length
+        type: uint
+      - name: max-length
+        type: uint
+      - name: flags-mask
+        type: uint
+      # enum ctlv_unit, absent when the payload is dimensionless, and a scale
+      # only ever accompanies a unit.
+      - name: unit
+        type: uint
+      - name: scale
+        type: sint
+      - name: blob-direction
+        enum: blob-direction
+      # Mask of BIT(enum ctlv_blob_type): the backings this placement takes.
+      - name: blob-backings
+        type: uint
+      # Maximum external payload length, unrelated to the inline message limit.
+      - name: blob-max-length
+        type: uint
+      - name: blob-alignment
+        type: uint
+      # Levels to climb to the node whose members are this one's as well, one
+      # meaning the node this one is a member of. A node that carries it lists
+      # no members itself.
+      - name: reenters
+        type: uint
+        min: 1
+      # The nodes one level in; required and optional are different attrs.
+      - name: attrs
+        attrs: schema-node
+        recursive: true
+        max-occurrences: unlimited
+      - name: optional-attrs
+        attrs: schema-node
+        recursive: true
+        max-occurrences: unlimited
+      # The root of each of an op's two trees, a node like any other.
+      - name: request
+        attrs: schema-node
+      - name: reply
+        attrs: schema-node
+
+  - name: event
+    attrs:
+      - name: op-id
+        type: uint
+        min: 1
+        max-occurrences: 256
+      - name: queue-len
+        type: uint
+        unit: bytes
+        min: 1
+        max: 16777216
+      - name: queue-used
+        type: uint
+        unit: bytes
+      - name: first-sequence
+        type: uint
+      - name: last-sequence
+        type: uint
+      - name: dropped-count
+        type: uint
+
+attr-sets:
+  - name: family-entry
+    attrs:
+      - family.id
+      - family.name
+
+  - name: op-entry
+    attrs:
+      - op.id
+      - op.type
+    optional-attrs:
+      - op.availability
+      - op.disabled
+      - op.request-max-len
+      - op.action-reply-max-len
+      - op.query-reply-min-len
+      - op.query-reply-suggested-len
+      - op.event-record-max-len
+      - op.fd-access
+
+  - name: op-schema-request
+    attrs: op.id
+
+  # Only the members the node's form has are present.
+  - name: schema-node
+    attrs:
+      - schema.attr-id
+      - schema.kind
+      - schema.max-occurrences
+    optional-attrs:
+      - schema.min
+      - schema.max
+      - schema.min-length
+      - schema.max-length
+      - schema.flags-mask
+      - schema.unit
+      - schema.scale
+      - schema.blob-direction
+      - schema.blob-backings
+      - schema.blob-max-length
+      - schema.blob-alignment
+      - schema.reenters
+      - schema.attrs
+      - schema.optional-attrs
+
+  # The two trees of one op, each absent when the op has no such message. An
+  # event's one tree is reported as the reply.
+  - name: op-schema-info
+    optional-attrs:
+      - schema.request
+      - schema.reply
+
+  # What changed about one op, in the same attrs a dump entry uses.
+  - name: op-change-info
+    attrs:
+      - op.id
+      - op.disabled
+      - op.state-generation
+
+  # The root of an error information message.
+  - name: error-info
+    optional-attrs:
+      - error.reason
+      - error.message
+      - error.bad-attr-offset
+      - error.nest-offset
+      - error.missing-attr-id
+      - error.expected-generation
+      - error.current-generation
+
+  - name: event-subscription
+    attrs: event.op-id
+
+  - name: event-queue-limit
+    attrs: event.queue-len
+
+  - name: event-queue-state
+    attrs:
+      - event.queue-len
+      - event.queue-used
+
+  - name: event-overflow-info
+    attrs:
+      - event.first-sequence
+      - event.last-sequence
+      - event.dropped-count
+
+ops:
+  # The families this device answers, this one first and the device family
+  # last. The only names any reply of this family carries.
+  - name: families-dump
+    type: query
+    fd-access: read
+    reply:
+      attrs: family.entry
+
+  - name: ops-dump
+    type: query
+    fd-access: read
+    reply:
+      attrs: op.entry
+
+  # The request and reply ABI of one op, whether or not it can be called right
+  # now. A removed op answers as one that was never declared.
+  - name: op-schema-get
+    type: query
+    fd-access: read
+    request:
+      attrs: op-schema-request
+    reply:
+      attrs: op-schema-info
+
+  - name: subscriptions-add
+    type: action
+    fd-access: read
+    request:
+      attrs: event-subscription
+
+  - name: subscriptions-remove
+    type: action
+    fd-access: read
+    request:
+      attrs: event-subscription
+
+  - name: event-queue-get
+    type: query
+    fd-access: read
+    reply:
+      attrs: event-queue-state
+
+  - name: event-queue-set
+    type: action
+    fd-access: read
+    request:
+      attrs: event-queue-limit
+
+  # A dynamically available op was enabled or disabled. The name is not about
+  # availability: a later mutable op property reports its state here too.
+  - name: op-changed
+    type: event
+    reply:
+      attrs: op-change-info
+
+  - name: event-overflow
+    type: event
+    reply:
+      attrs: event-overflow-info
+
+  # Payload-free: the record itself is the whole indication.
+  - name: device-removed
+    type: event
diff --git a/drivers/ctlv/ctlv_gen.c b/drivers/ctlv/ctlv_gen.c
new file mode 100644
index 000000000000..daf54495658f
--- /dev/null
+++ b/drivers/ctlv/ctlv_gen.c
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
+/* Do not edit, regenerate with tools/ctlv/ctlv-regen.sh, from: */
+/*	Documentation/ctlv/specs/ctlv.yaml */
+/* CTLV-GEN kernel source */
+
+#define _CTLV_GENERATED_METADATA_ONLY
+#include <linux/array_size.h>
+#include <linux/build_bug.h>
+#include <linux/ctlv_family.h>
+#include <linux/export.h>
+#include <linux/limits.h>
+
+#include <uapi/linux/ctlv_gen.h>
+
+#include <linux/ctlv_gen.h>
+
+static const struct ctlv_node_schema families_dump_request_node_schemas[] = {
+	CTLV_NODE_SCHEMA_ROOT(0, 0, 0),
+};
+
+static const struct ctlv_node_schema families_dump_reply_node_schemas[] = {
+	CTLV_NODE_SCHEMA_ROOT(1, 1, 1),
+	CTLV_NODE_SCHEMA_NEST(CTLV_ATTR_FAMILY_ENTRY, CTLV_NODE_SCHEMA_UNLIMITED, 2, 2, 2),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_FAMILY_ID, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_STRING(CTLV_ATTR_FAMILY_NAME, 1, 0, 63),
+};
+
+static const struct ctlv_node_schema ops_dump_request_node_schemas[] = {
+	CTLV_NODE_SCHEMA_ROOT(0, 0, 0),
+};
+
+static const struct ctlv_node_schema ops_dump_reply_node_schemas[] = {
+	CTLV_NODE_SCHEMA_ROOT(1, 1, 1),
+	CTLV_NODE_SCHEMA_NEST(CTLV_ATTR_OP_ENTRY, CTLV_NODE_SCHEMA_UNLIMITED, 2, 10, 2),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_OP_ID, 1, 1, U64_MAX),
+	CTLV_NODE_SCHEMA_ENUM(CTLV_ATTR_OP_TYPE, 1, 3),
+	CTLV_NODE_SCHEMA_ENUM(CTLV_ATTR_OP_AVAILABILITY, 1, 2),
+	CTLV_NODE_SCHEMA_BOOL(CTLV_ATTR_OP_DISABLED, 1),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_OP_REQUEST_MAX_LEN, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_OP_ACTION_REPLY_MAX_LEN, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_OP_QUERY_REPLY_MIN_LEN, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_OP_QUERY_REPLY_SUGGESTED_LEN, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_OP_EVENT_RECORD_MAX_LEN, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_ENUM(CTLV_ATTR_OP_FD_ACCESS, 1, 2),
+};
+
+static const struct ctlv_node_schema op_schema_get_request_node_schemas[] = {
+	CTLV_NODE_SCHEMA_ROOT(1, 1, 1),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_OP_ID, 1, 1, U64_MAX),
+};
+
+static const struct ctlv_node_schema op_schema_get_reply_node_schemas[] = {
+	CTLV_NODE_SCHEMA_ROOT(1, 2, 0),
+	CTLV_NODE_SCHEMA_NEST(CTLV_ATTR_SCHEMA_REQUEST, 1, 3, 17, 3),
+	CTLV_NODE_SCHEMA_NEST(CTLV_ATTR_SCHEMA_REPLY, 1, 20, 17, 3),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_ATTR_ID, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_KIND, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_MAX_OCCURRENCES, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_MIN, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_MAX, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_MIN_LENGTH, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_MAX_LENGTH, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_FLAGS_MASK, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_UNIT, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_SINT(CTLV_ATTR_SCHEMA_SCALE, 1, S64_MIN, S64_MAX),
+	CTLV_NODE_SCHEMA_ENUM(CTLV_ATTR_SCHEMA_BLOB_DIRECTION, 1, 3),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_BLOB_BACKINGS, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_BLOB_MAX_LENGTH, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_BLOB_ALIGNMENT, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_REENTERS, 1, 1, U64_MAX),
+	CTLV_NODE_SCHEMA_NEST_REENTERS(CTLV_ATTR_SCHEMA_ATTRS, CTLV_NODE_SCHEMA_UNLIMITED, 3, 17,
+				       3),
+	CTLV_NODE_SCHEMA_NEST_REENTERS(CTLV_ATTR_SCHEMA_OPTIONAL_ATTRS, CTLV_NODE_SCHEMA_UNLIMITED,
+				       3, 17, 3),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_ATTR_ID, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_KIND, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_MAX_OCCURRENCES, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_MIN, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_MAX, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_MIN_LENGTH, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_MAX_LENGTH, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_FLAGS_MASK, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_UNIT, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_SINT(CTLV_ATTR_SCHEMA_SCALE, 1, S64_MIN, S64_MAX),
+	CTLV_NODE_SCHEMA_ENUM(CTLV_ATTR_SCHEMA_BLOB_DIRECTION, 1, 3),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_BLOB_BACKINGS, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_BLOB_MAX_LENGTH, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_BLOB_ALIGNMENT, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_SCHEMA_REENTERS, 1, 1, U64_MAX),
+	CTLV_NODE_SCHEMA_NEST_REENTERS(CTLV_ATTR_SCHEMA_ATTRS, CTLV_NODE_SCHEMA_UNLIMITED, 20, 17,
+				       3),
+	CTLV_NODE_SCHEMA_NEST_REENTERS(CTLV_ATTR_SCHEMA_OPTIONAL_ATTRS, CTLV_NODE_SCHEMA_UNLIMITED,
+				       20, 17, 3),
+};
+
+static const struct ctlv_node_schema subscriptions_add_request_node_schemas[] = {
+	CTLV_NODE_SCHEMA_ROOT(1, 1, 1),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_EVENT_OP_ID, 256, 1, U64_MAX),
+};
+
+static const struct ctlv_node_schema subscriptions_remove_request_node_schemas[] = {
+	CTLV_NODE_SCHEMA_ROOT(1, 1, 1),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_EVENT_OP_ID, 256, 1, U64_MAX),
+};
+
+static const struct ctlv_node_schema event_queue_get_request_node_schemas[] = {
+	CTLV_NODE_SCHEMA_ROOT(0, 0, 0),
+};
+
+static const struct ctlv_node_schema event_queue_get_reply_node_schemas[] = {
+	CTLV_NODE_SCHEMA_ROOT(1, 2, 2),
+	CTLV_NODE_SCHEMA_UINT_UNIT(CTLV_ATTR_EVENT_QUEUE_LEN, 1, 1, 16777216, CTLV_UNIT_BYTES, 0),
+	CTLV_NODE_SCHEMA_UINT_UNIT(CTLV_ATTR_EVENT_QUEUE_USED, 1, 0, U64_MAX, CTLV_UNIT_BYTES, 0),
+};
+
+static const struct ctlv_node_schema event_queue_set_request_node_schemas[] = {
+	CTLV_NODE_SCHEMA_ROOT(1, 1, 1),
+	CTLV_NODE_SCHEMA_UINT_UNIT(CTLV_ATTR_EVENT_QUEUE_LEN, 1, 1, 16777216, CTLV_UNIT_BYTES, 0),
+};
+
+static const struct ctlv_node_schema op_changed_reply_node_schemas[] = {
+	CTLV_NODE_SCHEMA_ROOT(1, 3, 3),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_OP_ID, 1, 1, U64_MAX),
+	CTLV_NODE_SCHEMA_BOOL(CTLV_ATTR_OP_DISABLED, 1),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_OP_STATE_GENERATION, 1, 0, U64_MAX),
+};
+
+static const struct ctlv_node_schema event_overflow_reply_node_schemas[] = {
+	CTLV_NODE_SCHEMA_ROOT(1, 3, 3),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_EVENT_FIRST_SEQUENCE, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_EVENT_LAST_SEQUENCE, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_EVENT_DROPPED_COUNT, 1, 0, U64_MAX),
+};
+
+static const struct ctlv_node_schema device_removed_reply_node_schemas[] = {
+	CTLV_NODE_SCHEMA_ROOT(0, 0, 0),
+};
+
+static const struct ctlv_node_schema error_info_node_schemas[] = {
+	CTLV_NODE_SCHEMA_ROOT(1, 7, 0),
+	CTLV_NODE_SCHEMA_ENUM(CTLV_ATTR_ERROR_REASON, 1, 12),
+	CTLV_NODE_SCHEMA_STRING(CTLV_ATTR_ERROR_MESSAGE, 1, 0, 255),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_ERROR_BAD_ATTR_OFFSET, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_ERROR_NEST_OFFSET, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_ERROR_MISSING_ATTR_ID, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_ERROR_EXPECTED_GENERATION, 1, 0, U64_MAX),
+	CTLV_NODE_SCHEMA_UINT(CTLV_ATTR_ERROR_CURRENT_GENERATION, 1, 0, U64_MAX),
+};
+
+const struct ctlv_schema_tree ctlv_error_info_schema = {
+	.node_schemas = error_info_node_schemas,
+	.node_schemas_count =
+		ARRAY_SIZE(error_info_node_schemas),
+};
+
+static_assert(CTLV_ERROR_INFO_MAX_LEN <= CTLV_MAX_ERROR_LEN);
+
+/* The ops this family declares, in declaration order. */
+const struct ctlv_op_schema ctlv_op_schemas[] = {
+	CTLV_OP_SCHEMA_QUERY(CTLV_OP_FAMILIES_DUMP, CTLV_OP_FD_ACCESS_READ,
+			     CTLV_OP_AVAILABILITY_FIXED, 16, 112, 65536,
+			     CTLV_SCHEMA_TREE(families_dump_request),
+			     CTLV_SCHEMA_TREE(families_dump_reply)),
+	CTLV_OP_SCHEMA_QUERY(CTLV_OP_OPS_DUMP, CTLV_OP_FD_ACCESS_READ, CTLV_OP_AVAILABILITY_FIXED,
+			     16, 56, 65536, CTLV_SCHEMA_TREE(ops_dump_request),
+			     CTLV_SCHEMA_TREE(ops_dump_reply)),
+	CTLV_OP_SCHEMA_QUERY(CTLV_OP_OP_SCHEMA_GET, CTLV_OP_FD_ACCESS_READ,
+			     CTLV_OP_AVAILABILITY_FIXED, 40, 552, 65536,
+			     CTLV_SCHEMA_TREE(op_schema_get_request),
+			     CTLV_SCHEMA_TREE(op_schema_get_reply)),
+	CTLV_OP_SCHEMA_ACTION(CTLV_OP_SUBSCRIPTIONS_ADD, CTLV_OP_FD_ACCESS_READ,
+			      CTLV_OP_AVAILABILITY_FIXED, 6160, 0,
+			      CTLV_SCHEMA_TREE(subscriptions_add_request), CTLV_SCHEMA_TREE_NONE()),
+	CTLV_OP_SCHEMA_ACTION(CTLV_OP_SUBSCRIPTIONS_REMOVE, CTLV_OP_FD_ACCESS_READ,
+			      CTLV_OP_AVAILABILITY_FIXED, 6160, 0,
+			      CTLV_SCHEMA_TREE(subscriptions_remove_request),
+			      CTLV_SCHEMA_TREE_NONE()),
+	CTLV_OP_SCHEMA_QUERY(CTLV_OP_EVENT_QUEUE_GET, CTLV_OP_FD_ACCESS_READ,
+			     CTLV_OP_AVAILABILITY_FIXED, 16, 40, 65536,
+			     CTLV_SCHEMA_TREE(event_queue_get_request),
+			     CTLV_SCHEMA_TREE(event_queue_get_reply)),
+	CTLV_OP_SCHEMA_ACTION(CTLV_OP_EVENT_QUEUE_SET, CTLV_OP_FD_ACCESS_READ,
+			      CTLV_OP_AVAILABILITY_FIXED, 40, 0,
+			      CTLV_SCHEMA_TREE(event_queue_set_request), CTLV_SCHEMA_TREE_NONE()),
+	CTLV_OP_SCHEMA_EVENT(CTLV_OP_OP_CHANGED, 112, CTLV_SCHEMA_TREE(op_changed_reply)),
+	CTLV_OP_SCHEMA_EVENT(CTLV_OP_EVENT_OVERFLOW, 112, CTLV_SCHEMA_TREE(event_overflow_reply)),
+	CTLV_OP_SCHEMA_EVENT(CTLV_OP_DEVICE_REMOVED, 40, CTLV_SCHEMA_TREE(device_removed_reply)),
+};
+
+/* The family ID is its position in the central registry. */
+const struct ctlv_family_schema ctlv_schema = {
+	.name = "ctlv",
+	.family_id = 0,
+	.ops = ctlv_op_schemas,
+	.ops_count = ARRAY_SIZE(ctlv_op_schemas),
+};
+
+/* Maximum uevent cost for this family chain. */
+static_assert(60 <= CTLV_UEVENT_MAX_LEN);
+static_assert(3 <= CTLV_UEVENT_MAX_VARS);
+
+/* Guards for generated maxima. */
+static_assert(65536 <= CTLV_MAX_INLINE_MESSAGE_LEN);
+static_assert(112 <= CTLV_MAX_EVENT_QUEUE_LEN);
+static_assert(2 <= CTLV_MAX_DECLARED_NEST_DEPTH);
+
+/* Local action and query bindings in declaration order. */
+static const struct ctlv_op ctlv_ops[] = {
+	CTLV_OP_QUERY(ctlv_families_dump),
+	CTLV_OP_QUERY(ctlv_ops_dump),
+	CTLV_OP_QUERY(ctlv_op_schema_get),
+	CTLV_OP_ACTION(ctlv_subscriptions_add),
+	CTLV_OP_ACTION(ctlv_subscriptions_remove),
+	CTLV_OP_QUERY(ctlv_event_queue_get),
+	CTLV_OP_ACTION(ctlv_event_queue_set),
+};
+
+/* Root-family descriptor used by the CTLV core. */
+const struct ctlv_family ctlv_family = {
+	.schema = &ctlv_schema,
+	.ops = ctlv_ops,
+	.ops_count = ARRAY_SIZE(ctlv_ops),
+	.pre = ctlv_op_pre,
+	.post = ctlv_op_post,
+	.priv_size = ctlv_priv_size,
+	.init = ctlv_init,
+	.fini = ctlv_fini,
+};
+EXPORT_SYMBOL_NS_GPL(ctlv_family, "CTLV");
diff --git a/include/linux/ctlv_gen.h b/include/linux/ctlv_gen.h
new file mode 100644
index 000000000000..e389803449a0
--- /dev/null
+++ b/include/linux/ctlv_gen.h
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
+/* Do not edit, regenerate with tools/ctlv/ctlv-regen.sh, from: */
+/*	Documentation/ctlv/specs/ctlv.yaml */
+/* CTLV-GEN kernel header */
+
+/* Kernel metadata and family API of the ctlv CTLV family. */
+
+#ifndef _LINUX_CTLV_GEN_H
+#define _LINUX_CTLV_GEN_H
+
+#include <linux/ctlv_family.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+
+#include <uapi/linux/ctlv_gen.h>
+
+/* Ops this family declares, in declaration order. */
+extern const struct ctlv_op_schema ctlv_op_schemas[];
+
+extern const struct ctlv_family_schema ctlv_schema;
+
+/* The error-info message, built by the core. */
+#define CTLV_ERROR_INFO_MAX_LEN 432
+
+extern const struct ctlv_schema_tree ctlv_error_info_schema;
+
+/* Implemented by the CTLV core, one per action and query it declares. */
+int ctlv_families_dump_query(void *priv, struct ctlv_op_ctx *ctx, const struct ctlv_cursor *request,
+			     struct ctlv_cursor *reply);
+int ctlv_ops_dump_query(void *priv, struct ctlv_op_ctx *ctx, const struct ctlv_cursor *request,
+			struct ctlv_cursor *reply);
+int ctlv_op_schema_get_query(void *priv, struct ctlv_op_ctx *ctx, const struct ctlv_cursor *request,
+			     struct ctlv_cursor *reply);
+int ctlv_subscriptions_add_action(void *priv, struct ctlv_op_ctx *ctx,
+				  const struct ctlv_cursor *request, struct ctlv_cursor *reply);
+int ctlv_subscriptions_remove_action(void *priv, struct ctlv_op_ctx *ctx,
+				     const struct ctlv_cursor *request, struct ctlv_cursor *reply);
+int ctlv_event_queue_get_query(void *priv, struct ctlv_op_ctx *ctx,
+			       const struct ctlv_cursor *request, struct ctlv_cursor *reply);
+int ctlv_event_queue_set_action(void *priv, struct ctlv_op_ctx *ctx,
+				const struct ctlv_cursor *request, struct ctlv_cursor *reply);
+
+/* Root-family hooks around every core action or query. */
+int ctlv_op_pre(void *priv, struct ctlv_op_ctx *ctx);
+void ctlv_op_post(void *priv, struct ctlv_op_ctx *ctx);
+
+/* Core-allocated family priv lifecycle. */
+size_t ctlv_priv_size(void);
+int ctlv_init(struct ctlv_device *ctlvdev, const void *init_info, void *priv);
+void ctlv_fini(struct ctlv_device *ctlvdev, void *priv);
+
+extern const struct ctlv_family ctlv_family;
+
+#ifndef _CTLV_GENERATED_METADATA_ONLY
+
+/* Reading a validated message. A blob has a resolver instead of a getter. */
+CTLV_IN_REF(ctlv_op_schema_get_op_id, &ctlv_op_schemas[2].request, CTLV_ATTR_OP_ID, 0, 0,
+	    CTLV_SCHEMA_UINT)
+CTLV_IN_HAS(ctlv_op_schema_get_op_id)
+CTLV_IN_U64(ctlv_op_schema_get_op_id)
+CTLV_IN_REF(ctlv_subscriptions_add_event_op_id, &ctlv_op_schemas[3].request, CTLV_ATTR_EVENT_OP_ID,
+	    0, 0, CTLV_SCHEMA_UINT)
+#define ctlv_subscriptions_add_event_op_id_for_each(_attr, _nest) \
+	CTLV_IN_FOR_EACH(ctlv_subscriptions_add_event_op_id, _attr, _nest)
+CTLV_IN_EACH_U64(ctlv_subscriptions_add_event_op_id)
+CTLV_IN_REF(ctlv_subscriptions_remove_event_op_id, &ctlv_op_schemas[4].request,
+	    CTLV_ATTR_EVENT_OP_ID, 0, 0, CTLV_SCHEMA_UINT)
+#define ctlv_subscriptions_remove_event_op_id_for_each(_attr, _nest) \
+	CTLV_IN_FOR_EACH(ctlv_subscriptions_remove_event_op_id, _attr, _nest)
+CTLV_IN_EACH_U64(ctlv_subscriptions_remove_event_op_id)
+CTLV_IN_REF(ctlv_event_queue_set_event_queue_len, &ctlv_op_schemas[6].request,
+	    CTLV_ATTR_EVENT_QUEUE_LEN, 0, 0, CTLV_SCHEMA_UINT)
+CTLV_IN_HAS(ctlv_event_queue_set_event_queue_len)
+CTLV_IN_U64(ctlv_event_queue_set_event_queue_len)
+
+/* Writing a reply. An append is atomic; a nest ends with ctlv_nest_end(). */
+CTLV_PUT_U64(ctlv_family_id, CTLV_ATTR_FAMILY_ID, CTLV_SCHEMA_UINT)
+CTLV_PUT_STRING(ctlv_family_name, CTLV_ATTR_FAMILY_NAME, CTLV_SCHEMA_STRING)
+CTLV_NEST_START(ctlv_family_entry, CTLV_ATTR_FAMILY_ENTRY, CTLV_SCHEMA_NEST)
+CTLV_PUT_U64(ctlv_blob_type, CTLV_ATTR_BLOB_TYPE, CTLV_SCHEMA_ENUM)
+CTLV_PUT_U64(ctlv_blob_address, CTLV_ATTR_BLOB_ADDRESS, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_blob_fd, CTLV_ATTR_BLOB_FD, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_blob_offset, CTLV_ATTR_BLOB_OFFSET, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_blob_length, CTLV_ATTR_BLOB_LENGTH, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_error_reason, CTLV_ATTR_ERROR_REASON, CTLV_SCHEMA_ENUM)
+CTLV_PUT_STRING(ctlv_error_message, CTLV_ATTR_ERROR_MESSAGE, CTLV_SCHEMA_STRING)
+CTLV_PUT_U64(ctlv_error_bad_attr_offset, CTLV_ATTR_ERROR_BAD_ATTR_OFFSET, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_error_nest_offset, CTLV_ATTR_ERROR_NEST_OFFSET, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_error_missing_attr_id, CTLV_ATTR_ERROR_MISSING_ATTR_ID, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_error_expected_generation, CTLV_ATTR_ERROR_EXPECTED_GENERATION, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_error_current_generation, CTLV_ATTR_ERROR_CURRENT_GENERATION, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_op_id, CTLV_ATTR_OP_ID, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_op_type, CTLV_ATTR_OP_TYPE, CTLV_SCHEMA_ENUM)
+CTLV_PUT_U64(ctlv_op_availability, CTLV_ATTR_OP_AVAILABILITY, CTLV_SCHEMA_ENUM)
+CTLV_PUT_BOOL(ctlv_op_disabled, CTLV_ATTR_OP_DISABLED, CTLV_SCHEMA_BOOL)
+CTLV_PUT_U64(ctlv_op_request_max_len, CTLV_ATTR_OP_REQUEST_MAX_LEN, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_op_action_reply_max_len, CTLV_ATTR_OP_ACTION_REPLY_MAX_LEN, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_op_query_reply_min_len, CTLV_ATTR_OP_QUERY_REPLY_MIN_LEN, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_op_query_reply_suggested_len, CTLV_ATTR_OP_QUERY_REPLY_SUGGESTED_LEN,
+	     CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_op_event_record_max_len, CTLV_ATTR_OP_EVENT_RECORD_MAX_LEN, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_op_state_generation, CTLV_ATTR_OP_STATE_GENERATION, CTLV_SCHEMA_UINT)
+CTLV_NEST_START(ctlv_op_entry, CTLV_ATTR_OP_ENTRY, CTLV_SCHEMA_NEST)
+CTLV_PUT_U64(ctlv_op_fd_access, CTLV_ATTR_OP_FD_ACCESS, CTLV_SCHEMA_ENUM)
+CTLV_PUT_U64(ctlv_schema_attr_id, CTLV_ATTR_SCHEMA_ATTR_ID, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_schema_kind, CTLV_ATTR_SCHEMA_KIND, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_schema_max_occurrences, CTLV_ATTR_SCHEMA_MAX_OCCURRENCES, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_schema_min, CTLV_ATTR_SCHEMA_MIN, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_schema_max, CTLV_ATTR_SCHEMA_MAX, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_schema_min_length, CTLV_ATTR_SCHEMA_MIN_LENGTH, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_schema_max_length, CTLV_ATTR_SCHEMA_MAX_LENGTH, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_schema_flags_mask, CTLV_ATTR_SCHEMA_FLAGS_MASK, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_schema_unit, CTLV_ATTR_SCHEMA_UNIT, CTLV_SCHEMA_UINT)
+CTLV_PUT_S64(ctlv_schema_scale, CTLV_ATTR_SCHEMA_SCALE, CTLV_SCHEMA_SINT)
+CTLV_PUT_U64(ctlv_schema_blob_direction, CTLV_ATTR_SCHEMA_BLOB_DIRECTION, CTLV_SCHEMA_ENUM)
+CTLV_PUT_U64(ctlv_schema_blob_backings, CTLV_ATTR_SCHEMA_BLOB_BACKINGS, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_schema_blob_max_length, CTLV_ATTR_SCHEMA_BLOB_MAX_LENGTH, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_schema_blob_alignment, CTLV_ATTR_SCHEMA_BLOB_ALIGNMENT, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_schema_reenters, CTLV_ATTR_SCHEMA_REENTERS, CTLV_SCHEMA_UINT)
+CTLV_NEST_START(ctlv_schema_attrs, CTLV_ATTR_SCHEMA_ATTRS, CTLV_SCHEMA_NEST)
+CTLV_NEST_START(ctlv_schema_optional_attrs, CTLV_ATTR_SCHEMA_OPTIONAL_ATTRS, CTLV_SCHEMA_NEST)
+CTLV_NEST_START(ctlv_schema_request, CTLV_ATTR_SCHEMA_REQUEST, CTLV_SCHEMA_NEST)
+CTLV_NEST_START(ctlv_schema_reply, CTLV_ATTR_SCHEMA_REPLY, CTLV_SCHEMA_NEST)
+CTLV_PUT_U64(ctlv_event_op_id, CTLV_ATTR_EVENT_OP_ID, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_event_queue_len, CTLV_ATTR_EVENT_QUEUE_LEN, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_event_queue_used, CTLV_ATTR_EVENT_QUEUE_USED, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_event_first_sequence, CTLV_ATTR_EVENT_FIRST_SEQUENCE, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_event_last_sequence, CTLV_ATTR_EVENT_LAST_SEQUENCE, CTLV_SCHEMA_UINT)
+CTLV_PUT_U64(ctlv_event_dropped_count, CTLV_ATTR_EVENT_DROPPED_COUNT, CTLV_SCHEMA_UINT)
+
+/* Building one event, passed to ctlv_event_emit() or ctlv_event_abort() once. */
+CTLV_EVENT_CREATE(ctlv_op_changed, CTLV_OP_OP_CHANGED)
+CTLV_EVENT_CREATE(ctlv_event_overflow, CTLV_OP_EVENT_OVERFLOW)
+CTLV_EVENT_CREATE(ctlv_device_removed, CTLV_OP_DEVICE_REMOVED)
+#endif /* _CTLV_GENERATED_METADATA_ONLY */
+
+#endif /* _LINUX_CTLV_GEN_H */
diff --git a/include/uapi/linux/ctlv_families_gen.h b/include/uapi/linux/ctlv_families_gen.h
new file mode 100644
index 000000000000..a649483ab3f5
--- /dev/null
+++ b/include/uapi/linux/ctlv_families_gen.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
+/* Do not edit, regenerate with tools/ctlv/ctlv-regen.sh, from: */
+/*	Documentation/ctlv/families.yaml */
+/* CTLV-GEN uapi header */
+
+/* CTLV family numbers. */
+
+#ifndef _UAPI_LINUX_CTLV_FAMILIES_GEN_H
+#define _UAPI_LINUX_CTLV_FAMILIES_GEN_H
+
+enum _ctlv_family {
+	CTLV_FAMILY_ROOT,
+};
+
+#endif /* _UAPI_LINUX_CTLV_FAMILIES_GEN_H */
diff --git a/include/uapi/linux/ctlv_gen.h b/include/uapi/linux/ctlv_gen.h
new file mode 100644
index 000000000000..64eba093a6d4
--- /dev/null
+++ b/include/uapi/linux/ctlv_gen.h
@@ -0,0 +1,271 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
+/* Do not edit, regenerate with tools/ctlv/ctlv-regen.sh, from: */
+/*	Documentation/ctlv/specs/ctlv.yaml */
+/* CTLV-GEN uapi header */
+
+/*
+ * Constants of the ctlv CTLV family. Attr and op IDs are complete; the wire format carrying them is
+ * in <linux/ctlv.h>.
+ */
+
+#ifndef _UAPI_LINUX_CTLV_GEN_H
+#define _UAPI_LINUX_CTLV_GEN_H
+
+#include <linux/ctlv.h>
+#include <linux/ctlv_families_gen.h>
+
+/* enum op-type */
+enum _ctlv_op_type {
+	CTLV_OP_TYPE_ACTION = 1,
+	CTLV_OP_TYPE_QUERY,
+	CTLV_OP_TYPE_EVENT,
+};
+
+/* enum op-availability */
+enum _ctlv_op_availability {
+	CTLV_OP_AVAILABILITY_FIXED = 1,
+	CTLV_OP_AVAILABILITY_DYNAMIC,
+};
+
+/* enum blob-type */
+enum _ctlv_blob_type {
+	CTLV_BLOB_TYPE_VA = 1,
+};
+
+/* enum blob-direction */
+enum _ctlv_blob_direction {
+	CTLV_BLOB_DIRECTION_INPUT = 1,
+	CTLV_BLOB_DIRECTION_OUTPUT,
+	CTLV_BLOB_DIRECTION_INOUT,
+};
+
+/* enum validation-reason */
+enum _ctlv_validation_reason {
+	CTLV_VALIDATION_REASON_MALFORMED_MESSAGE = 1,
+	CTLV_VALIDATION_REASON_UNKNOWN_ATTR,
+	CTLV_VALIDATION_REASON_UNKNOWN_FLAG,
+	CTLV_VALIDATION_REASON_NESTING_TOO_DEEP,
+	CTLV_VALIDATION_REASON_MISSING_ATTR,
+	CTLV_VALIDATION_REASON_TOO_MANY_OCCURRENCES,
+	CTLV_VALIDATION_REASON_VALUE_OUT_OF_RANGE,
+	CTLV_VALIDATION_REASON_BAD_LENGTH,
+	CTLV_VALIDATION_REASON_BAD_STRING,
+	CTLV_VALIDATION_REASON_BAD_BLOB_DESCRIPTOR,
+	CTLV_VALIDATION_REASON_STALE_GENERATION,
+	CTLV_VALIDATION_REASON_NONCONTIGUOUS_ATTR,
+};
+
+/* enum op-fd-access */
+enum _ctlv_op_fd_access {
+	CTLV_OP_FD_ACCESS_READ = 1,
+	CTLV_OP_FD_ACCESS_READ_WRITE,
+};
+
+/* attr groups */
+enum _ctlv_group {
+	CTLV_GROUP_FAMILY = 1,
+	CTLV_GROUP_BLOB,
+	CTLV_GROUP_ERROR,
+	CTLV_GROUP_OP,
+	CTLV_GROUP_SCHEMA,
+	CTLV_GROUP_EVENT,
+};
+
+#define _CTLV_ATTR(_group, _attr) CTLV_ATTR(CTLV_FAMILY_ROOT, (_group), (_attr))
+
+/* attrs of group family */
+#define _CTLV_ATTR_FAMILY(_attr) _CTLV_ATTR(CTLV_GROUP_FAMILY, _CTLV_ATTR_FAMILY_##_attr)
+
+enum _ctlv_attr_family {
+	_CTLV_ATTR_FAMILY_ID = 1,
+	_CTLV_ATTR_FAMILY_NAME,
+	_CTLV_ATTR_FAMILY_ENTRY,
+};
+
+#define CTLV_ATTR_FAMILY_ID _CTLV_ATTR_FAMILY(ID)
+#define CTLV_ATTR_FAMILY_NAME _CTLV_ATTR_FAMILY(NAME)
+#define CTLV_ATTR_FAMILY_ENTRY _CTLV_ATTR_FAMILY(ENTRY)
+
+/* attrs of group blob */
+#define _CTLV_ATTR_BLOB(_attr) _CTLV_ATTR(CTLV_GROUP_BLOB, _CTLV_ATTR_BLOB_##_attr)
+
+enum _ctlv_attr_blob {
+	_CTLV_ATTR_BLOB_TYPE = 1,
+	_CTLV_ATTR_BLOB_ADDRESS,
+	_CTLV_ATTR_BLOB_FD,
+	_CTLV_ATTR_BLOB_OFFSET,
+	_CTLV_ATTR_BLOB_LENGTH,
+};
+
+#define CTLV_ATTR_BLOB_TYPE _CTLV_ATTR_BLOB(TYPE)
+#define CTLV_ATTR_BLOB_ADDRESS _CTLV_ATTR_BLOB(ADDRESS)
+#define CTLV_ATTR_BLOB_FD _CTLV_ATTR_BLOB(FD)
+#define CTLV_ATTR_BLOB_OFFSET _CTLV_ATTR_BLOB(OFFSET)
+#define CTLV_ATTR_BLOB_LENGTH _CTLV_ATTR_BLOB(LENGTH)
+
+/* attrs of group error */
+#define _CTLV_ATTR_ERROR(_attr) _CTLV_ATTR(CTLV_GROUP_ERROR, _CTLV_ATTR_ERROR_##_attr)
+
+enum _ctlv_attr_error {
+	_CTLV_ATTR_ERROR_REASON = 1,
+	_CTLV_ATTR_ERROR_MESSAGE,
+	_CTLV_ATTR_ERROR_BAD_ATTR_OFFSET,
+	_CTLV_ATTR_ERROR_NEST_OFFSET,
+	_CTLV_ATTR_ERROR_MISSING_ATTR_ID,
+	_CTLV_ATTR_ERROR_EXPECTED_GENERATION,
+	_CTLV_ATTR_ERROR_CURRENT_GENERATION,
+};
+
+#define CTLV_ATTR_ERROR_REASON _CTLV_ATTR_ERROR(REASON)
+#define CTLV_ATTR_ERROR_MESSAGE _CTLV_ATTR_ERROR(MESSAGE)
+#define CTLV_ATTR_ERROR_BAD_ATTR_OFFSET _CTLV_ATTR_ERROR(BAD_ATTR_OFFSET)
+#define CTLV_ATTR_ERROR_NEST_OFFSET _CTLV_ATTR_ERROR(NEST_OFFSET)
+#define CTLV_ATTR_ERROR_MISSING_ATTR_ID _CTLV_ATTR_ERROR(MISSING_ATTR_ID)
+#define CTLV_ATTR_ERROR_EXPECTED_GENERATION _CTLV_ATTR_ERROR(EXPECTED_GENERATION)
+#define CTLV_ATTR_ERROR_CURRENT_GENERATION _CTLV_ATTR_ERROR(CURRENT_GENERATION)
+
+/* attrs of group op */
+#define _CTLV_ATTR_OP(_attr) _CTLV_ATTR(CTLV_GROUP_OP, _CTLV_ATTR_OP_##_attr)
+
+enum _ctlv_attr_op {
+	_CTLV_ATTR_OP_ID = 1,
+	_CTLV_ATTR_OP_TYPE,
+	_CTLV_ATTR_OP_AVAILABILITY,
+	_CTLV_ATTR_OP_DISABLED,
+	_CTLV_ATTR_OP_REQUEST_MAX_LEN,
+	_CTLV_ATTR_OP_ACTION_REPLY_MAX_LEN,
+	_CTLV_ATTR_OP_QUERY_REPLY_MIN_LEN,
+	_CTLV_ATTR_OP_QUERY_REPLY_SUGGESTED_LEN,
+	_CTLV_ATTR_OP_EVENT_RECORD_MAX_LEN,
+	_CTLV_ATTR_OP_STATE_GENERATION,
+	_CTLV_ATTR_OP_ENTRY,
+	_CTLV_ATTR_OP_FD_ACCESS,
+};
+
+#define CTLV_ATTR_OP_ID _CTLV_ATTR_OP(ID)
+#define CTLV_ATTR_OP_TYPE _CTLV_ATTR_OP(TYPE)
+#define CTLV_ATTR_OP_AVAILABILITY _CTLV_ATTR_OP(AVAILABILITY)
+#define CTLV_ATTR_OP_DISABLED _CTLV_ATTR_OP(DISABLED)
+#define CTLV_ATTR_OP_REQUEST_MAX_LEN _CTLV_ATTR_OP(REQUEST_MAX_LEN)
+#define CTLV_ATTR_OP_ACTION_REPLY_MAX_LEN _CTLV_ATTR_OP(ACTION_REPLY_MAX_LEN)
+#define CTLV_ATTR_OP_QUERY_REPLY_MIN_LEN _CTLV_ATTR_OP(QUERY_REPLY_MIN_LEN)
+#define CTLV_ATTR_OP_QUERY_REPLY_SUGGESTED_LEN _CTLV_ATTR_OP(QUERY_REPLY_SUGGESTED_LEN)
+#define CTLV_ATTR_OP_EVENT_RECORD_MAX_LEN _CTLV_ATTR_OP(EVENT_RECORD_MAX_LEN)
+#define CTLV_ATTR_OP_STATE_GENERATION _CTLV_ATTR_OP(STATE_GENERATION)
+#define CTLV_ATTR_OP_ENTRY _CTLV_ATTR_OP(ENTRY)
+#define CTLV_ATTR_OP_FD_ACCESS _CTLV_ATTR_OP(FD_ACCESS)
+
+/* attrs of group schema */
+#define _CTLV_ATTR_SCHEMA(_attr) _CTLV_ATTR(CTLV_GROUP_SCHEMA, _CTLV_ATTR_SCHEMA_##_attr)
+
+enum _ctlv_attr_schema {
+	_CTLV_ATTR_SCHEMA_ATTR_ID = 1,
+	_CTLV_ATTR_SCHEMA_KIND,
+	_CTLV_ATTR_SCHEMA_MAX_OCCURRENCES,
+	_CTLV_ATTR_SCHEMA_MIN,
+	_CTLV_ATTR_SCHEMA_MAX,
+	_CTLV_ATTR_SCHEMA_MIN_LENGTH,
+	_CTLV_ATTR_SCHEMA_MAX_LENGTH,
+	_CTLV_ATTR_SCHEMA_FLAGS_MASK,
+	_CTLV_ATTR_SCHEMA_UNIT,
+	_CTLV_ATTR_SCHEMA_SCALE,
+	_CTLV_ATTR_SCHEMA_BLOB_DIRECTION,
+	_CTLV_ATTR_SCHEMA_BLOB_BACKINGS,
+	_CTLV_ATTR_SCHEMA_BLOB_MAX_LENGTH,
+	_CTLV_ATTR_SCHEMA_BLOB_ALIGNMENT,
+	_CTLV_ATTR_SCHEMA_REENTERS,
+	_CTLV_ATTR_SCHEMA_ATTRS,
+	_CTLV_ATTR_SCHEMA_OPTIONAL_ATTRS,
+	_CTLV_ATTR_SCHEMA_REQUEST,
+	_CTLV_ATTR_SCHEMA_REPLY,
+};
+
+#define CTLV_ATTR_SCHEMA_ATTR_ID _CTLV_ATTR_SCHEMA(ATTR_ID)
+#define CTLV_ATTR_SCHEMA_KIND _CTLV_ATTR_SCHEMA(KIND)
+#define CTLV_ATTR_SCHEMA_MAX_OCCURRENCES _CTLV_ATTR_SCHEMA(MAX_OCCURRENCES)
+#define CTLV_ATTR_SCHEMA_MIN _CTLV_ATTR_SCHEMA(MIN)
+#define CTLV_ATTR_SCHEMA_MAX _CTLV_ATTR_SCHEMA(MAX)
+#define CTLV_ATTR_SCHEMA_MIN_LENGTH _CTLV_ATTR_SCHEMA(MIN_LENGTH)
+#define CTLV_ATTR_SCHEMA_MAX_LENGTH _CTLV_ATTR_SCHEMA(MAX_LENGTH)
+#define CTLV_ATTR_SCHEMA_FLAGS_MASK _CTLV_ATTR_SCHEMA(FLAGS_MASK)
+#define CTLV_ATTR_SCHEMA_UNIT _CTLV_ATTR_SCHEMA(UNIT)
+#define CTLV_ATTR_SCHEMA_SCALE _CTLV_ATTR_SCHEMA(SCALE)
+#define CTLV_ATTR_SCHEMA_BLOB_DIRECTION _CTLV_ATTR_SCHEMA(BLOB_DIRECTION)
+#define CTLV_ATTR_SCHEMA_BLOB_BACKINGS _CTLV_ATTR_SCHEMA(BLOB_BACKINGS)
+#define CTLV_ATTR_SCHEMA_BLOB_MAX_LENGTH _CTLV_ATTR_SCHEMA(BLOB_MAX_LENGTH)
+#define CTLV_ATTR_SCHEMA_BLOB_ALIGNMENT _CTLV_ATTR_SCHEMA(BLOB_ALIGNMENT)
+#define CTLV_ATTR_SCHEMA_REENTERS _CTLV_ATTR_SCHEMA(REENTERS)
+#define CTLV_ATTR_SCHEMA_ATTRS _CTLV_ATTR_SCHEMA(ATTRS)
+#define CTLV_ATTR_SCHEMA_OPTIONAL_ATTRS _CTLV_ATTR_SCHEMA(OPTIONAL_ATTRS)
+#define CTLV_ATTR_SCHEMA_REQUEST _CTLV_ATTR_SCHEMA(REQUEST)
+#define CTLV_ATTR_SCHEMA_REPLY _CTLV_ATTR_SCHEMA(REPLY)
+
+/* attrs of group event */
+#define _CTLV_ATTR_EVENT(_attr) _CTLV_ATTR(CTLV_GROUP_EVENT, _CTLV_ATTR_EVENT_##_attr)
+
+enum _ctlv_attr_event {
+	_CTLV_ATTR_EVENT_OP_ID = 1,
+	_CTLV_ATTR_EVENT_QUEUE_LEN,
+	_CTLV_ATTR_EVENT_QUEUE_USED,
+	_CTLV_ATTR_EVENT_FIRST_SEQUENCE,
+	_CTLV_ATTR_EVENT_LAST_SEQUENCE,
+	_CTLV_ATTR_EVENT_DROPPED_COUNT,
+};
+
+#define CTLV_ATTR_EVENT_OP_ID _CTLV_ATTR_EVENT(OP_ID)
+#define CTLV_ATTR_EVENT_QUEUE_LEN _CTLV_ATTR_EVENT(QUEUE_LEN)
+#define CTLV_ATTR_EVENT_QUEUE_USED _CTLV_ATTR_EVENT(QUEUE_USED)
+#define CTLV_ATTR_EVENT_FIRST_SEQUENCE _CTLV_ATTR_EVENT(FIRST_SEQUENCE)
+#define CTLV_ATTR_EVENT_LAST_SEQUENCE _CTLV_ATTR_EVENT(LAST_SEQUENCE)
+#define CTLV_ATTR_EVENT_DROPPED_COUNT _CTLV_ATTR_EVENT(DROPPED_COUNT)
+
+/* metadata of group event */
+enum _ctlv_attr_event_metadata {
+	CTLV_ATTR_EVENT_QUEUE_LEN_UNIT = CTLV_UNIT_BYTES,
+	CTLV_ATTR_EVENT_QUEUE_LEN_SCALE = 0,
+	CTLV_ATTR_EVENT_QUEUE_USED_UNIT = CTLV_UNIT_BYTES,
+	CTLV_ATTR_EVENT_QUEUE_USED_SCALE = 0,
+};
+
+/* attr sets */
+enum _ctlv_set {
+	CTLV_SET_FAMILY_ENTRY = 1,
+	CTLV_SET_OP_ENTRY,
+	CTLV_SET_OP_SCHEMA_REQUEST,
+	CTLV_SET_SCHEMA_NODE,
+	CTLV_SET_OP_SCHEMA_INFO,
+	CTLV_SET_OP_CHANGE_INFO,
+	CTLV_SET_ERROR_INFO,
+	CTLV_SET_EVENT_SUBSCRIPTION,
+	CTLV_SET_EVENT_QUEUE_LIMIT,
+	CTLV_SET_EVENT_QUEUE_STATE,
+	CTLV_SET_EVENT_OVERFLOW_INFO,
+};
+
+/* ops */
+enum _ctlv_op {
+	_CTLV_OP_FAMILIES_DUMP = 1,
+	_CTLV_OP_OPS_DUMP,
+	_CTLV_OP_OP_SCHEMA_GET,
+	_CTLV_OP_SUBSCRIPTIONS_ADD,
+	_CTLV_OP_SUBSCRIPTIONS_REMOVE,
+	_CTLV_OP_EVENT_QUEUE_GET,
+	_CTLV_OP_EVENT_QUEUE_SET,
+	_CTLV_OP_OP_CHANGED,
+	_CTLV_OP_EVENT_OVERFLOW,
+	_CTLV_OP_DEVICE_REMOVED,
+};
+
+#define _CTLV_OP(_op) CTLV_OP(CTLV_FAMILY_ROOT, _CTLV_OP_##_op)
+#define CTLV_OP_FAMILIES_DUMP _CTLV_OP(FAMILIES_DUMP)
+#define CTLV_OP_OPS_DUMP _CTLV_OP(OPS_DUMP)
+#define CTLV_OP_OP_SCHEMA_GET _CTLV_OP(OP_SCHEMA_GET)
+#define CTLV_OP_SUBSCRIPTIONS_ADD _CTLV_OP(SUBSCRIPTIONS_ADD)
+#define CTLV_OP_SUBSCRIPTIONS_REMOVE _CTLV_OP(SUBSCRIPTIONS_REMOVE)
+#define CTLV_OP_EVENT_QUEUE_GET _CTLV_OP(EVENT_QUEUE_GET)
+#define CTLV_OP_EVENT_QUEUE_SET _CTLV_OP(EVENT_QUEUE_SET)
+#define CTLV_OP_OP_CHANGED _CTLV_OP(OP_CHANGED)
+#define CTLV_OP_EVENT_OVERFLOW _CTLV_OP(EVENT_OVERFLOW)
+#define CTLV_OP_DEVICE_REMOVED _CTLV_OP(DEVICE_REMOVED)
+
+#endif /* _UAPI_LINUX_CTLV_GEN_H */
-- 
2.56.0


  parent reply	other threads:[~2026-10-15 14:51 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-15 14:50 [PATCH RFC 00/20] attestation: Add a common subsystem and TDX support Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 01/20] ctlv: Add the schema language and generator Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 02/20] ctlv: Add the UAPI wire format and family API Jiri Pirko
2026-10-15 14:50 ` Jiri Pirko [this message]
2026-10-15 14:50 ` [PATCH RFC 04/20] Documentation: ctlv: Add userspace ABI Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 05/20] ctlv: Prepare message input handling Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 06/20] ctlv: Prepare blob descriptor validation Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 07/20] ctlv: Prepare schema validation Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 08/20] ctlv: Prepare message output handling Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 09/20] ctlv: Prepare VA blob handling Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 10/20] ctlv: Prepare event queue support Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 11/20] ctlv: Prepare runtime introspection Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 12/20] ctlv: Add device and operation dispatch Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 13/20] Documentation: ctlv: Describe how to write a family Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 14/20] attestation: Add the base family specification and generated files Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 15/20] attestation: Prepare provider and instance core Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 16/20] attestation: Prepare measurement register journal Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 17/20] attestation: Add CTLV operation handling Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 18/20] tdx-guest: Expose the native attestation service API Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 19/20] attestation: Add the TDX family specification and generated files Jiri Pirko
2026-10-15 14:50 ` [PATCH RFC 20/20] attestation: Add the TDX family implementation Jiri Pirko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261015145053.3664509-4-jiri@resnulli.us \
    --to=jiri@resnulli.us \
    --cc=James.Bottomley@HansenPartnership.com \
    --cc=aik@amd.com \
    --cc=alistair.francis@wdc.com \
    --cc=ankita@nvidia.com \
    --cc=cedric.xing@intel.com \
    --cc=dave.hansen@linux.intel.com \
    --cc=david.quigley@intel.com \
    --cc=drdeeglaze@gmail.com \
    --cc=elena.reshetova@intel.com \
    --cc=jgg@ziepe.ca \
    --cc=jic23@kernel.org \
    --cc=jpiotrowski@nvidia.com \
    --cc=kas@kernel.org \
    --cc=ksinyuk@kernel.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-api@vger.kernel.org \
    --cc=linux-coco@lists.linux.dev \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lukas@wunner.de \
    --cc=peter.fang@intel.com \
    --cc=pgonda@google.com \
    --cc=qinkun@google.com \
    --cc=rick.p.edgecombe@intel.com \
    --cc=rodrigo.vivi@intel.com \
    --cc=sameo@meta.com \
    --cc=sathyanarayanan.kuppuswamy@linux.intel.com \
    --cc=suzuki.poulose@arm.com \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox