> From 217219cc2d3cafe109f2b0a00ac4474e680fe391 Mon Sep 17 00:00:00 2001 > From: Jiri Pirko > Date: Thu, 15 Oct 2026 16:50:36 +0200 > Subject: [PATCH 03/20] ctlv: Add the root family specification and generated > files > > 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. Bisectability: this changelog admits the generated .c is not linked, but it understates the problem. `include/linux/ctlv_gen.h` (outside the `_CTLV_GENERATED_METADATA_ONLY` guard) uses `CTLV_IN_REF`/`CTLV_IN_HAS`/`CTLV_IN_U64`/`CTLV_IN_FOR_EACH` (only added by patch 5), `CTLV_PUT_*`/`CTLV_NEST_START` and `CTLV_EVENT_CREATE` (builder/event patches), and `drivers/ctlv/ctlv_gen.c` refers to `ctlv_op_pre()`, `ctlv_priv_size()`, `ctlv_families_dump_query()` etc. that do not exist before the dispatch patch. Nothing compiles `ctlv_gen.h` (no Makefile/Kconfig yet), so after this patch nothing proves the generated output is even syntactically valid C; it only becomes so ~8 patches later. Also `drivers/ctlv/` is added to MAINTAINERS only in patch 5, so this patch creates `drivers/ctlv/ctlv_gen.c` outside any F: entry. > > Assisted-by: Cursor: GPT-5.6 Sol > Assisted-by: Cursor: Claude Opus 5.5 > Signed-off-by: Jiri Pirko > --- > 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/.yaml, and is added by the change that adds the > +# implementation. Fixtures under tools/ctlv/tests/ are not registered. The registry rule just stated is "added by the change that adds the implementation". This patch registers "ctlv" (and the `abi/families.registry.yaml` baseline) 7 patches before the implementation exists (patch 11, dispatch). Either move the registry/manifest entries into the dispatch patch or relax the comment. Same for `generated-files.yaml`: it lists outputs that cannot be built yet. > + > +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 Speculative generality frozen into the UAPI: blob.fd and blob.offset are "reserved for later fd-backed types", blob-type has the single value "va", and schema.blob-backings is a bitmask over that single value. Nothing in the series reads or writes blob.fd/blob.offset, yet they get attr IDs 3 and 4 forever (and fd has a max with no semantics). If fd-backed blobs come later, they can be appended as new IDs then; reserving IDs speculatively adds dead put-helpers (`ctlv_blob_fd`/offset) and ABI-snapshot entries to maintain. > + # 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. error-info (attr-set) makes every member optional, including error.reason, so a message with no reason at all is schema-valid. If reason is always emitted it should be required, otherwise a client cannot rely on it. Also the comment says "first failure", but the error group/attr-set carries no indication of whether more failures were suppressed; fine, just make sure the docs say first-failure-wins. > + - 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 subscriptions-add/-remove and event-queue-set are state-changing actions declared fd-access: read. This is deliberate for per-open state but it means a read-only open can resize its event queue up to 16 MiB (event.queue-len max 16777216). Please state in the comment/doc that per-open state is considered not to need write access, and confirm the queue allocation is memcg accounted and rlimit-bounded, since a bound of 16 MiB per open fd is cheap to multiply. > + 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 checkpatch: `added, moved or deleted file(s), does MAINTAINERS need updating?` Yes, for this file: the CTLV SUBSYSTEM entry has no `F: drivers/ctlv/` until patch 5, so `drivers/ctlv/ctlv_gen.c` is not covered. Add `F: drivers/ctlv/` to MAINTAINERS in this patch (patch 5 then drops its hunk). > 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) Licensing: per `LICENSES/exceptions/Linux-syscall-note` the exception exists to mark UAPI headers so they can be included in non-GPL userspace code. `drivers/ctlv/ctlv_gen.c` and `include/linux/ctlv_gen.h` are kernel-internal, so I would expect the plain kernel license there; please confirm the intent with the SPDX/licensing maintainers. The generator could pick the SPDX line per output kind. > +/* 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 > +#include > +#include > +#include > +#include > + > +#include > + > +#include > + > +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 > +#include > +#include > + > +#include > + > +/* 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; Redundant: `include/linux/ctlv_family.h` (patch 2, still visible in the context of patch 5) already declares exactly this, and `ctlv_gen.h` includes it. Also note the family-level non-static symbols `ctlv_schema`, `ctlv_op_schemas`, `ctlv_error_info_schema` have very generic names and are not exported or namespaced; with `CONFIG_CTLV`=y they land in the global vmlinux symbol table. Several prototypes above are > 100 columns (generator wrapping). > + > +#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_HAS` is emitted for op.id, which is a required attr in op-schema-request (and validated before the handler runs), so `ctlv_op_schema_get_op_id_present()` can only return true. Dead generated helper; the generator should emit `_present()` only for optional placements. (`CTLV_IN_HAS` is emitted for event.queue-len below likewise, which is required in event-queue-limit.) static inline so no warning, but it is API surface nobody can use meaningfully. > +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 . > + */ > + > +#ifndef _UAPI_LINUX_CTLV_GEN_H > +#define _UAPI_LINUX_CTLV_GEN_H > + > +#include > +#include > + > +/* enum op-type */ > +enum _ctlv_op_type { UAPI naming: tags and enumerators with a leading underscore (`_ctlv_op_type`, `_CTLV_ATTR_FAMILY_ID`, `_CTLV_OP_*`, `_ctlv_group`, ...) are in the C implementation-reserved space (file-scope identifiers starting with underscore, and underscore+capital anywhere). These are installed to userspace; a header leaking them can clash with libc/compiler internals and every consumer sees them as part of the ABI surface. Consider a non-underscore internal prefix, or keep the helper enums out of the installed header. > + 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.55.0 > Summary of the most serious issues in this patch: - Series bisectability: the generated kernel header/source depend on macros and functions from patches 5-11 and are not compiled by anything until dispatch lands; `drivers/ctlv/ctlv_gen.c` is not covered by MAINTAINERS until patch 5. - Registry/manifest entries are added before the implementation, contradicting `families.yaml`'s own rule. - Linux-syscall-note SPDX on non-UAPI kernel files (`ctlv_gen.c`, `linux/ctlv_gen.h`). - Speculative ABI: reserved blob.fd/blob.offset, single-value blob-type, error.reason optional. - Generator output nits: duplicate extern `ctlv_family`, `_present()` for required attrs, underscore-prefixed UAPI identifiers. I regenerated with `tools/ctlv/ctlv-regen.sh` -c at HEAD: the checked-in generated files match their spec (no drift).