Message ID | 20250326-agx-uapi-v5-1-04fccfc9e631@rosenzweig.io (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | [v5] drm: Add UAPI for the Asahi driver | expand |
On Wed, Mar 26, 2025 at 02:16:38PM -0400, Alyssa Rosenzweig wrote: > This adds the UAPI for the Asahi driver targeting the GPU in the Apple > M1 and M2 series systems on chip. The UAPI design is based on other > modern Vulkan-capable drivers, including Xe and Panthor. Memory > management is based on explicit VM management. Synchronization is > exclusively explicit sync. > > This UAPI is validated against our open source Mesa stack, which is > fully conformant to the OpenGL 4.6, OpenGL ES 3.2, OpenCL 3.0, and > Vulkan 1.4 standards. The Vulkan driver supports sparse, exercising the > VM_BIND mechanism. > > This patch adds the standalone UAPI header. It is implemented by an open > source DRM driver written in Rust. We fully intend to upstream this > driver when possible. However, as a production graphics driver, it > depends on a significant number of Rust abstractions that will take a > long time to upstream. In the mean time, our userspace is upstream in > Mesa but is not allowed to probe with upstream Mesa as the UAPI is not > yet reviewed and merged in the upstream kernel. Although we ship a > patched Mesa in Fedora Asahi Remix, any containers shipping upstream > Mesa builds are broken for our users, including upstream Flatpak and > Waydroid runtimes. Additionally, it forces us to maintain forks of Mesa > and virglrenderer, which complicates bisects. > > The intention in sending out this patch is for this UAPI to be > thoroughly reviewed. Once we as the DRM community are satisfied with the > UAPI, this header lands signifying that the UAPI is stable and must only > be evolved in backwards-compatible ways; it will be the UAPI implemented > in the DRM driver that eventually lands upstream. That promise lets us > enable upstream Mesa, solving all these issues while the upstream Rust > abstractions are developed. > > https://github.com/alyssarosenzweig/linux/commits/agx-uapi-v5 contains > the DRM driver implementing this proposed UAPI. > > https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33984 contains > the Mesa patches to implement this proposed UAPI. > > That Linux and Mesa branch together give a complete graphics/compute > stack on top of this UAPI. > > Co-developed-by: Asahi Lina <lina@asahilina.net> > Signed-off-by: Asahi Lina <lina@asahilina.net> > Acked-by: Simona Vetter <simona.vetter@ffwll.ch> > Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> > --- > Changes in v5: > - Rename GEM_BIND to VM_BIND and make it take an array of bind ops. This > significantly decreases the # of kernel<-->user roundtrips with Vulkan > sparse binding. The uAPI here is lifted directly from Xe. > - Merge in_syncs and out_syncs arrays, but leave > in_sync_count/out_sync_count alone, requiring waits to precede > signals. This simplifies both kernel & userspace, compared to either > fully merged or fully separate arrays, so it seems like a Good idea. > - Drop queue caps, make all caps render + compute. Even GLES2 uses > compute to accelerate blits, and even compute workloads use render for > a few fallback blits. This lets us drop a bunch of crud in both kernel > & userspace and should slightly improve submit overhead. > - Reorder ioctl IDs to group a little more logically (bikeshed...). > - Improve some comments. > - Link to v4: https://lore.kernel.org/r/20250323-agx-uapi-v4-1-12ed2db96737@rosenzweig.io ... > diff --git a/include/uapi/drm/asahi_drm.h b/include/uapi/drm/asahi_drm.h > new file mode 100644 > index 0000000000000000000000000000000000000000..a9465cb89ebde6f6768fbd5ba0fa4d753e2a7e32 > --- /dev/null > +++ b/include/uapi/drm/asahi_drm.h > @@ -0,0 +1,1211 @@ ... > +/** > + * struct drm_asahi_params_global - Global parameters. > + * > + * This struct may be queried by drm_asahi_get_params. > + */ > +struct drm_asahi_params_global { > + /** @features: Feature bits from drm_asahi_feature */ > + __u64 features; > + > + /** @gpu_generation: GPU generation, e.g. 13 for G13G */ > + __u32 gpu_generation; > + > + /** @gpu_variant: GPU variant as a character, e.g. 'G' for G13G */ > + __u32 gpu_variant; nit: the example can avoid the duplication of 'G' with "e.g. 'C' for G13C" ... > +/** > + * struct drm_asahi_get_params - Arguments passed to DRM_IOCTL_ASAHI_GET_PARAMS > + */ > +struct drm_asahi_get_params { > + /** @param_group: Parameter group to fetch (MBZ) */ > + __u32 param_group; > + > + /** @pad: MBZ */ > + __u32 pad; > + > + /** @pointer: User pointer to write parameter struct */ > + __u64 pointer; > + > + /** @size: Size of user buffer, max size supported on return */ > + __u64 size; The comment is misleading in the case of newer / extended kernel which supports a larger size than supplied. You could change it to "size written on return" or clarify that the value on return will not exceed the input value. > +}; > + > +/** > + * struct drm_asahi_vm_create - Arguments passed to DRM_IOCTL_ASAHI_VM_CREATE > + */ > +struct drm_asahi_vm_create { > + /** > + * @kernel_start: Start of the kernel-reserved address range. See > + * drm_asahi_params_global::vm_kernel_min_size. > + * > + * Both @kernel_start and @kernel_end must be within the range of > + * valid VAs given by drm_asahi_params_global::vm_user_start and > + * drm_asahi_params_global::vm_user_end. The size of the kernel range This reads a little strange. Would it make sense to rename drm_asahi_params_global's vm_user_start and vm_user_end to vm_start/vm_end? > + * (@kernel_end - @kernel_start) must be at least > + * drm_asahi_params_global::vm_kernel_min_size. > + * > + * Userspace must not bind any memory on this VM into this reserved > + * range, it is for kernel use only. > + */ > + __u64 kernel_start; > + > + /** > + * @kernel_end: End of the kernel-reserved address range. See > + * @kernel_start. > + */ > + __u64 kernel_end; ... > +/** > + * struct drm_asahi_vm_bind - Arguments passed to > + * DRM_IOCTL_ASAHI_VM_BIND > + */ > +struct drm_asahi_vm_bind { > + /** @vm_id: The ID of the VM to bind to */ > + __u32 vm_id; > + > + /** @num_binds: number of binds in this IOCTL. Must be non-zero. */ > + __u32 num_binds; > + > + /** > + * @stride: If num_binds > 1, stride in bytes between consecutive binds. > + * This allows extensibility of drm_asahi_gem_bind_op. > + * > + * If num_binds == 1, MBZ. Extensibility in that case is handled at the > + * ioctl level instead. > + */ > + __u32 stride; > + > + /** @pad: MBZ */ > + __u32 pad; > + > + /** > + * @bind: Union holding the bind request. > + * > + * This union is named to make the Rust bindings nicer to work with. > + */ This comment could use a short justification why this union does not defeat extensibility after the initial statement that "structures should not contain unions" > + union { > + /** @bind.b: If num_binds == 1, the bind */ > + struct drm_asahi_gem_bind_op b; > + > + /** > + * @bind.userptr: If num_binds > 1, user pointer to an array of > + * @num_binds structures of type @drm_asahi_gem_bind_op and size > + * @stride bytes. > + */ > + __u64 userptr; > + } bind; > +}; ... > +/** > + * struct drm_asahi_submit - Arguments passed to DRM_IOCTL_ASAHI_SUBMIT > + */ > +struct drm_asahi_submit { > + /** > + * @syncs: An optional array of drm_asahi_sync. First @in_sync_count > + * in-syncs then @out_sync_count out-syncs. > + */ > + __u64 syncs; Would it make sense to explictly state that this is a pointer? Reviewed-by: Janne Grunau <j@jannau.net> ciao Janne
On Wed, Mar 26, 2025 at 2:16 PM Alyssa Rosenzweig <alyssa@rosenzweig.io> wrote: > > This adds the UAPI for the Asahi driver targeting the GPU in the Apple > M1 and M2 series systems on chip. The UAPI design is based on other > modern Vulkan-capable drivers, including Xe and Panthor. Memory > management is based on explicit VM management. Synchronization is > exclusively explicit sync. > > This UAPI is validated against our open source Mesa stack, which is > fully conformant to the OpenGL 4.6, OpenGL ES 3.2, OpenCL 3.0, and > Vulkan 1.4 standards. The Vulkan driver supports sparse, exercising the > VM_BIND mechanism. > > This patch adds the standalone UAPI header. It is implemented by an open > source DRM driver written in Rust. We fully intend to upstream this > driver when possible. However, as a production graphics driver, it > depends on a significant number of Rust abstractions that will take a > long time to upstream. In the mean time, our userspace is upstream in > Mesa but is not allowed to probe with upstream Mesa as the UAPI is not > yet reviewed and merged in the upstream kernel. Although we ship a > patched Mesa in Fedora Asahi Remix, any containers shipping upstream > Mesa builds are broken for our users, including upstream Flatpak and > Waydroid runtimes. Additionally, it forces us to maintain forks of Mesa > and virglrenderer, which complicates bisects. > > The intention in sending out this patch is for this UAPI to be > thoroughly reviewed. Once we as the DRM community are satisfied with the > UAPI, this header lands signifying that the UAPI is stable and must only > be evolved in backwards-compatible ways; it will be the UAPI implemented > in the DRM driver that eventually lands upstream. That promise lets us > enable upstream Mesa, solving all these issues while the upstream Rust > abstractions are developed. > > https://github.com/alyssarosenzweig/linux/commits/agx-uapi-v5 contains > the DRM driver implementing this proposed UAPI. > > https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33984 contains > the Mesa patches to implement this proposed UAPI. > > That Linux and Mesa branch together give a complete graphics/compute > stack on top of this UAPI. Do we want these links to be present in the commit message? I doubt they'll stick around permanently... > > Co-developed-by: Asahi Lina <lina@asahilina.net> > Signed-off-by: Asahi Lina <lina@asahilina.net> > Acked-by: Simona Vetter <simona.vetter@ffwll.ch> > Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> > --- > Changes in v5: > - Rename GEM_BIND to VM_BIND and make it take an array of bind ops. This > significantly decreases the # of kernel<-->user roundtrips with Vulkan > sparse binding. The uAPI here is lifted directly from Xe. > - Merge in_syncs and out_syncs arrays, but leave > in_sync_count/out_sync_count alone, requiring waits to precede > signals. This simplifies both kernel & userspace, compared to either > fully merged or fully separate arrays, so it seems like a Good idea. > - Drop queue caps, make all caps render + compute. Even GLES2 uses > compute to accelerate blits, and even compute workloads use render for > a few fallback blits. This lets us drop a bunch of crud in both kernel > & userspace and should slightly improve submit overhead. > - Reorder ioctl IDs to group a little more logically (bikeshed...). > - Improve some comments. > - Link to v4: https://lore.kernel.org/r/20250323-agx-uapi-v4-1-12ed2db96737@rosenzweig.io > > Changes in v4: > - get_time now returns time in nanoseconds, timer_frequency_hz dropped. > This hides an extra time domain from userspace for no real downside. > - Added lots more comments answering questions Faith raised in v3 > review. > - Drop firmware_version per discussion. > - Drop UNBIND_ALL, it is unused. > - Switch priority to an enum per discussion. > - Drop drm_asahi_subqueue and instead make barriers separate fields to > make obvious the extensability situation resolving discusison on v3. > > Changes in v3: > - Merge load/store/partial fields for depth/stencil as discussed with > Faith. This shrinks the submit a lot with little loss of > functionality. There's maaaybe a use case for splitting out depth load > base (only) later. But it's easier to add uAPI than remove it! > - Make usc_exec_base per-queue instead of per-command. No use case for > doing it finer grained, and this shrinks the submits and simplifies > userspace handling. > - Improve descriptions. > - Reorder/shrink fields to remove padding. > - Use full names for vdm/cdm_ctrl_stream_base > - Link to v2: https://lore.kernel.org/r/20250313-agx-uapi-v2-1-59cc53a59ea3@rosenzweig.io > > Changes in v2: > - Flatten submits. Previously, the submit ioctl pointed to an array of > command structures, which each pointed to separate payload structures, > which pointed to attachment structures. This is a lot of indirection, > which complicates greatly virtgpu. In the new approach, the submit > ioctl points to a single contiguous blob of plain-old-data, no CPU > pointers, copied from userspace in one go and suitable as virtgpu wire > protocol. > - Remove vm_page_size, userspace has to hardcode it anyway. > - Turn random #defines into enums for better kernel doc, etc. > - Improve comments, particularly around barriers[]. > - Rename various flags/fields to better match canonical names when known > (a lot of the names are pulled from the drivers/gpu/drm/imagination, > naturally). > - Drop unnecessary encoder_id, cmd_id handles. > - Fix padding in submit ioctl (thanks Ryan). > - Link to v1: https://lore.kernel.org/r/20250310-agx-uapi-v1-1-86c80905004e@rosenzweig.io > --- > Documentation/gpu/driver-uapi.rst | 5 + > MAINTAINERS | 1 + > include/uapi/drm/asahi_drm.h | 1211 +++++++++++++++++++++++++++++++++++++ > 3 files changed, 1217 insertions(+) > > diff --git a/Documentation/gpu/driver-uapi.rst b/Documentation/gpu/driver-uapi.rst > index 971cdb4816fc98d80a64d93637481d10c2e79718..1f15a8ca126516c23bd7374cc4aead0dfbbccf67 100644 > --- a/Documentation/gpu/driver-uapi.rst > +++ b/Documentation/gpu/driver-uapi.rst > @@ -27,3 +27,8 @@ drm/xe uAPI > =========== > > .. kernel-doc:: include/uapi/drm/xe_drm.h > + > +drm/asahi uAPI > +================ > + > +.. kernel-doc:: include/uapi/drm/asahi_drm.h > diff --git a/MAINTAINERS b/MAINTAINERS > index d1050702f681fbd0e4e2d0457b2ba569a64070d9..7f692a935808d4ec82ee741324f8043302dae491 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -2256,6 +2256,7 @@ F: drivers/watchdog/apple_wdt.c > F: include/dt-bindings/interrupt-controller/apple-aic.h > F: include/dt-bindings/pinctrl/apple.h > F: include/linux/soc/apple/* > +F: include/uapi/drm/asahi_drm.h > > ARM/ARTPEC MACHINE SUPPORT > M: Jesper Nilsson <jesper.nilsson@axis.com> > diff --git a/include/uapi/drm/asahi_drm.h b/include/uapi/drm/asahi_drm.h > new file mode 100644 > index 0000000000000000000000000000000000000000..a9465cb89ebde6f6768fbd5ba0fa4d753e2a7e32 > --- /dev/null > +++ b/include/uapi/drm/asahi_drm.h > @@ -0,0 +1,1211 @@ > +/* SPDX-License-Identifier: MIT */ > +/* > + * Copyright (C) The Asahi Linux Contributors > + * Copyright (C) 2018-2023 Collabora Ltd. > + * Copyright (C) 2014-2018 Broadcom > + */ > +#ifndef _ASAHI_DRM_H_ > +#define _ASAHI_DRM_H_ > + > +#include "drm.h" > + > +#if defined(__cplusplus) > +extern "C" { > +#endif > + > +/** > + * DOC: Introduction to the Asahi UAPI > + * > + * This documentation describes the Asahi IOCTLs. > + * > + * Just a few generic rules about the data passed to the Asahi IOCTLs (cribbed > + * from Panthor): > + * > + * - Structures must be aligned on 64-bit/8-byte. If the object is not > + * naturally aligned, a padding field must be added. > + * - Fields must be explicitly aligned to their natural type alignment with > + * pad[0..N] fields. > + * - All padding fields will be checked by the driver to make sure they are > + * zeroed. > + * - Flags can be added, but not removed/replaced. > + * - New fields can be added to the main structures (the structures > + * directly passed to the ioctl). Those fields can be added at the end of > + * the structure, or replace existing padding fields. Any new field being > + * added must preserve the behavior that existed before those fields were > + * added when a value of zero is passed. > + * - New fields can be added to indirect objects (objects pointed by the > + * main structure), iff those objects are passed a size to reflect the > + * size known by the userspace driver (see > + * drm_asahi_command::cmd_buffer_size). > + * - If the kernel driver is too old to know some fields, those will be > + * ignored if zero, and otherwise rejected (and so will be zero on output). > + * - If userspace is too old to know some fields, those will be zeroed > + * (input) before the structure is parsed by the kernel driver. > + * - Each new flag/field addition must come with a driver version update so > + * the userspace driver doesn't have to trial and error to know which > + * flags are supported. > + * - Structures should not contain unions, as this would defeat the > + * extensibility of such structures. > + * - IOCTLs can't be removed or replaced. New IOCTL IDs should be placed > + * at the end of the drm_asahi_ioctl_id enum. > + */ > + > +/** > + * enum drm_asahi_ioctl_id - IOCTL IDs > + * > + * Place new ioctls at the end, don't re-order, don't replace or remove entries. > + * > + * These IDs are not meant to be used directly. Use the DRM_IOCTL_ASAHI_xxx > + * definitions instead. > + */ > +enum drm_asahi_ioctl_id { > + /** @DRM_ASAHI_GET_PARAMS: Query device properties. */ > + DRM_ASAHI_GET_PARAMS = 0, > + > + /** @DRM_ASAHI_GET_TIME: Query device time. */ > + DRM_ASAHI_GET_TIME, > + > + /** @DRM_ASAHI_VM_CREATE: Create a GPU VM address space. */ > + DRM_ASAHI_VM_CREATE, > + > + /** @DRM_ASAHI_VM_DESTROY: Destroy a VM. */ > + DRM_ASAHI_VM_DESTROY, > + > + /** @DRM_ASAHI_VM_BIND: Bind/unbind memory to a VM. */ > + DRM_ASAHI_VM_BIND, > + > + /** @DRM_ASAHI_GEM_CREATE: Create a buffer object. */ > + DRM_ASAHI_GEM_CREATE, > + > + /** > + * @DRM_ASAHI_GEM_MMAP_OFFSET: Get offset to pass to mmap() to map a > + * given GEM handle. > + */ > + DRM_ASAHI_GEM_MMAP_OFFSET, > + > + /** @DRM_ASAHI_GEM_BIND_OBJECT: Bind memory as a special object */ > + DRM_ASAHI_GEM_BIND_OBJECT, > + > + /** @DRM_ASAHI_QUEUE_CREATE: Create a scheduling queue. */ > + DRM_ASAHI_QUEUE_CREATE, > + > + /** @DRM_ASAHI_QUEUE_DESTROY: Destroy a scheduling queue. */ > + DRM_ASAHI_QUEUE_DESTROY, > + > + /** @DRM_ASAHI_SUBMIT: Submit commands to a queue. */ > + DRM_ASAHI_SUBMIT, > +}; > + > +#define DRM_ASAHI_MAX_CLUSTERS 64 > + > +/** > + * struct drm_asahi_params_global - Global parameters. > + * > + * This struct may be queried by drm_asahi_get_params. > + */ > +struct drm_asahi_params_global { > + /** @features: Feature bits from drm_asahi_feature */ > + __u64 features; > + > + /** @gpu_generation: GPU generation, e.g. 13 for G13G */ > + __u32 gpu_generation; > + > + /** @gpu_variant: GPU variant as a character, e.g. 'G' for G13G */ > + __u32 gpu_variant; > + > + /** > + * @gpu_revision: GPU revision in BCD, e.g. 0x00 for 'A0' or > + * 0x21 for 'C1' > + */ > + __u32 gpu_revision; > + > + /** @chip_id: Chip ID in BCD, e.g. 0x8103 for T8103 */ > + __u32 chip_id; > + > + /** @num_dies: Number of dies in the SoC */ > + __u32 num_dies; > + > + /** @num_clusters_total: Number of GPU clusters (across all dies) */ > + __u32 num_clusters_total; > + > + /** > + * @num_cores_per_cluster: Number of logical cores per cluster > + * (including inactive/nonexistent) > + */ > + __u32 num_cores_per_cluster; > + > + /** @num_frags_per_cluster: Number of frags per cluster */ > + __u32 num_frags_per_cluster; > + > + /** @num_gps_per_cluster: Number of GPs per cluster */ > + __u32 num_gps_per_cluster; > + > + /** @max_power_mw: Maximum GPU power consumption */ > + __u32 max_power_mw; > + > + /** @core_masks: Bitmask of present/enabled cores per cluster */ > + __u64 core_masks[DRM_ASAHI_MAX_CLUSTERS]; > + > + /** @min_frequency_khz: Minimum GPU core clock frequency */ > + __u32 min_frequency_khz; > + > + /** @max_frequency_khz: Maximum GPU core clock frequency */ > + __u32 max_frequency_khz; > + > + /** > + * @vm_user_start: VM user range start VMA. Together with > + * @vm_user_end, this defines the window of valid GPU VAs. Userspace is > + * expected to subdivide VAs out of this window. > + */ > + __u64 vm_user_start; > + > + /** @vm_user_end: VM user range end VMA */ > + __u64 vm_user_end; > + > + /** > + * @vm_kernel_min_size: Minimum kernel VMA window size within user > + * range. > + * > + * When creating a VM, userspace is required to carve out a section of > + * virtual addresses (within the range given by @vm_user_start and > + * @vm_user_end). The kernel will allocate various internal structures > + * within the specified VA range. > + * > + * Allowing userspace to choose the VA range for the kernel, rather than > + * the kernel reserving VAs and requiring userspace to cope, can assist > + * in implementing SVM. > + */ > + __u64 vm_kernel_min_size; > + > + /** > + * @max_commands_per_submission: Maximum number of supported commands > + * per submission. This mirrors firmware limits. Userspace must split up > + * larger command buffers, which may require inserting additional > + * barriers explicitly. > + */ > + __u32 max_commands_per_submission; > + > + /** > + * @max_attachments: Maximum number of drm_asahi_attachment's per > + * command > + */ > + __u32 max_attachments; > + > + /** > + * @command_timestamp_frequency_hz: Timebase frequency for timestamps > + * written during command exeuction, specified via drm_asahi_timestamp > + * structures. As this rate is controlled by the firmware, it is a > + * queryable parameter. > + * > + * Userspace must divide by this frequency to convert timestamps to > + * seconds, rather than hardcoding a particular firmware's rate. > + */ > + __u64 command_timestamp_frequency_hz; > +}; > + > +/** > + * enum drm_asahi_feature - Feature bits > + * > + * This covers only features that userspace cannot infer from the architecture > + * version. Most features don't need to be here. > + */ > +enum drm_asahi_feature { > + /** > + * @DRM_ASAHI_FEATURE_SOFT_FAULTS: GPU has "soft fault" enabled. Shader > + * loads of unmapped memory will return zero. Shader stores to unmapped > + * memory will be silently discarded. Note that only shader load/store > + * is affected. Other hardware units are not affected, notably including > + * texture sampling. > + * > + * Soft fault is set when initializing the GPU and cannot be runtime > + * toggled. Therefore, it is exposed as a feature bit and not a > + * userspace-settable flag on the VM. When soft fault is enabled, > + * userspace can speculate memory accesses more aggressively. > + */ > + DRM_ASAHI_FEATURE_SOFT_FAULTS = (1UL) << 0, > +}; > + > +/** > + * struct drm_asahi_get_params - Arguments passed to DRM_IOCTL_ASAHI_GET_PARAMS > + */ > +struct drm_asahi_get_params { > + /** @param_group: Parameter group to fetch (MBZ) */ > + __u32 param_group; > + > + /** @pad: MBZ */ > + __u32 pad; > + > + /** @pointer: User pointer to write parameter struct */ > + __u64 pointer; > + > + /** @size: Size of user buffer, max size supported on return */ > + __u64 size; > +}; > + > +/** > + * struct drm_asahi_vm_create - Arguments passed to DRM_IOCTL_ASAHI_VM_CREATE > + */ > +struct drm_asahi_vm_create { > + /** > + * @kernel_start: Start of the kernel-reserved address range. See > + * drm_asahi_params_global::vm_kernel_min_size. > + * > + * Both @kernel_start and @kernel_end must be within the range of > + * valid VAs given by drm_asahi_params_global::vm_user_start and > + * drm_asahi_params_global::vm_user_end. The size of the kernel range > + * (@kernel_end - @kernel_start) must be at least > + * drm_asahi_params_global::vm_kernel_min_size. > + * > + * Userspace must not bind any memory on this VM into this reserved > + * range, it is for kernel use only. > + */ > + __u64 kernel_start; > + > + /** > + * @kernel_end: End of the kernel-reserved address range. See > + * @kernel_start. > + */ > + __u64 kernel_end; > + > + /** @vm_id: Returned VM ID */ > + __u32 vm_id; > + > + /** @pad: MBZ */ > + __u32 pad; > +}; > + > +/** > + * struct drm_asahi_vm_destroy - Arguments passed to DRM_IOCTL_ASAHI_VM_DESTROY > + */ > +struct drm_asahi_vm_destroy { > + /** @vm_id: VM ID to be destroyed */ > + __u32 vm_id; > + > + /** @pad: MBZ */ > + __u32 pad; > +}; > + > +/** > + * enum drm_asahi_gem_flags - Flags for GEM creation > + */ > +enum drm_asahi_gem_flags { > + /** > + * @DRM_ASAHI_GEM_WRITEBACK: BO should be CPU-mapped as writeback. > + * > + * Map as writeback instead of write-combine. This optimizes for CPU > + * reads. > + */ > + DRM_ASAHI_GEM_WRITEBACK = (1L << 0), > + > + /** > + * @DRM_ASAHI_GEM_VM_PRIVATE: BO is private to this GPU VM (no exports). > + */ > + DRM_ASAHI_GEM_VM_PRIVATE = (1L << 1), > +}; > + > +/** > + * struct drm_asahi_gem_create - Arguments passed to DRM_IOCTL_ASAHI_GEM_CREATE > + */ > +struct drm_asahi_gem_create { > + /** @size: Size of the BO */ > + __u64 size; > + > + /** @flags: Combination of drm_asahi_gem_flags flags. */ > + __u32 flags; > + > + /** > + * @vm_id: VM ID to assign to the BO, if DRM_ASAHI_GEM_VM_PRIVATE is set > + */ > + __u32 vm_id; > + > + /** @handle: Returned GEM handle for the BO */ > + __u32 handle; > + > + /** @pad: MBZ */ > + __u32 pad; > +}; > + > +/** > + * struct drm_asahi_gem_mmap_offset - Arguments passed to > + * DRM_IOCTL_ASAHI_GEM_MMAP_OFFSET > + */ > +struct drm_asahi_gem_mmap_offset { > + /** @handle: Handle for the object being mapped. */ > + __u32 handle; > + > + /** @flags: Must be zero */ > + __u32 flags; > + > + /** @offset: The fake offset to use for subsequent mmap call */ > + __u64 offset; > +}; > + > +/** > + * enum drm_asahi_bind_flags - Flags for GEM binding > + */ > +enum drm_asahi_bind_flags { > + /** > + * @DRM_ASAHI_BIND_UNBIND: Instead of binding a GEM object to the range, > + * simply unbind the GPU VMA range. > + */ > + DRM_ASAHI_BIND_UNBIND = (1L << 0), > + > + /** @DRM_ASAHI_BIND_READ: Map BO with GPU read permission */ > + DRM_ASAHI_BIND_READ = (1L << 1), > + > + /** @DRM_ASAHI_BIND_WRITE: Map BO with GPU write permission */ > + DRM_ASAHI_BIND_WRITE = (1L << 2), > + > + /** > + * @DRM_ASAHI_BIND_SINGLE_PAGE: Map a single page of the BO repeatedly > + * across the VA range. > + * > + * This is useful to fill a VA range with scratch pages or zero pages. > + * It is intended as a mechanism to accelerate sparse. > + */ > + DRM_ASAHI_BIND_SINGLE_PAGE = (1L << 3), > +}; > + > +/** > + * struct drm_asahi_gem_bind_op - Description of a single GEM bind operation. > + */ > +struct drm_asahi_gem_bind_op { > + /** @flags: Combination of drm_asahi_bind_flags flags. */ > + __u32 flags; > + > + /** @handle: GEM object to bind (except for UNBIND) */ > + __u32 handle; > + > + /** > + * @offset: Offset into the object (except for UNBIND). > + * > + * For a regular bind, this is the beginning of the region of the GEM > + * object to bind. > + * > + * For a single-page bind, this is the offset to the single page that > + * will be repeatedly bound. > + * > + * Must be page-size aligned. > + */ > + __u64 offset; > + > + /** > + * @range: Number of bytes to bind/unbind to @addr. > + * > + * Must be page-size aligned. > + */ > + __u64 range; > + > + /** > + * @addr: Address to bind to. > + * > + * Must be page-size aligned. > + */ > + __u64 addr; > +}; > + > +/** > + * struct drm_asahi_vm_bind - Arguments passed to > + * DRM_IOCTL_ASAHI_VM_BIND > + */ > +struct drm_asahi_vm_bind { > + /** @vm_id: The ID of the VM to bind to */ > + __u32 vm_id; > + > + /** @num_binds: number of binds in this IOCTL. Must be non-zero. */ > + __u32 num_binds; > + > + /** > + * @stride: If num_binds > 1, stride in bytes between consecutive binds. > + * This allows extensibility of drm_asahi_gem_bind_op. > + * > + * If num_binds == 1, MBZ. Extensibility in that case is handled at the > + * ioctl level instead. > + */ > + __u32 stride; > + > + /** @pad: MBZ */ > + __u32 pad; > + > + /** > + * @bind: Union holding the bind request. > + * > + * This union is named to make the Rust bindings nicer to work with. > + */ > + union { > + /** @bind.b: If num_binds == 1, the bind */ > + struct drm_asahi_gem_bind_op b; > + > + /** > + * @bind.userptr: If num_binds > 1, user pointer to an array of > + * @num_binds structures of type @drm_asahi_gem_bind_op and size > + * @stride bytes. > + */ > + __u64 userptr; > + } bind; > +}; > + > +/** > + * enum drm_asahi_bind_object_op - Special object bind operation > + */ > +enum drm_asahi_bind_object_op { > + /** @DRM_ASAHI_BIND_OBJECT_OP_BIND: Bind a BO as a special GPU object */ > + DRM_ASAHI_BIND_OBJECT_OP_BIND = 0, > + > + /** @DRM_ASAHI_BIND_OBJECT_OP_UNBIND: Unbind a special GPU object */ > + DRM_ASAHI_BIND_OBJECT_OP_UNBIND = 1, > +}; > + > +/** > + * enum drm_asahi_bind_object_flags - Special object bind flags > + */ > +enum drm_asahi_bind_object_flags { > + /** > + * @DRM_ASAHI_BIND_OBJECT_USAGE_TIMESTAMPS: Map a BO as a timestamp > + * buffer. > + */ > + DRM_ASAHI_BIND_OBJECT_USAGE_TIMESTAMPS = (1L << 0), > +}; > + > +/** > + * struct drm_asahi_gem_bind_object - Arguments passed to > + * DRM_IOCTL_ASAHI_GEM_BIND_OBJECT > + */ > +struct drm_asahi_gem_bind_object { > + /** @op: Bind operation (enum drm_asahi_bind_object_op) */ > + __u32 op; > + > + /** @flags: Combination of drm_asahi_bind_object_flags flags. */ > + __u32 flags; > + > + /** @handle: GEM object to bind/unbind (BIND) */ > + __u32 handle; > + > + /** @vm_id: The ID of the VM to operate on (MBZ currently) */ > + __u32 vm_id; > + > + /** @offset: Offset into the object (BIND only) */ > + __u64 offset; > + > + /** @range: Number of bytes to bind/unbind (BIND only) */ > + __u64 range; > + > + /** @object_handle: Object handle (out for BIND, in for UNBIND) */ > + __u32 object_handle; > + > + /** @pad: MBZ */ > + __u32 pad; > +}; > + > +/** > + * enum drm_asahi_cmd_type - Command type > + */ > +enum drm_asahi_cmd_type { > + /** > + * @DRM_ASAHI_CMD_RENDER: Render command, executing on the render > + * subqueue. Combined vertex and fragment operation. > + * > + * Followed by a @drm_asahi_cmd_render payload. > + */ > + DRM_ASAHI_CMD_RENDER = 0, > + > + /** > + * @DRM_ASAHI_CMD_COMPUTE: Compute command on the compute subqueue. > + * > + * Followed by a @drm_asahi_cmd_compute payload. > + */ > + DRM_ASAHI_CMD_COMPUTE = 1, > + > + /** > + * @DRM_ASAHI_SET_VERTEX_ATTACHMENTS: Software command to set > + * attachments for subsequent vertex shaders in the same submit. > + * > + * Followed by (possibly multiple) @drm_asahi_attachment payloads. > + */ > + DRM_ASAHI_SET_VERTEX_ATTACHMENTS = 2, > + > + /** > + * @DRM_ASAHI_SET_FRAGMENT_ATTACHMENTS: Software command to set > + * attachments for subsequent fragment shaders in the same submit. > + * > + * Followed by (possibly multiple) @drm_asahi_attachment payloads. > + */ > + DRM_ASAHI_SET_FRAGMENT_ATTACHMENTS = 3, > + > + /** > + * @DRM_ASAHI_SET_COMPUTE_ATTACHMENTS: Software command to set > + * attachments for subsequent compute shaders in the same submit. > + * > + * Followed by (possibly multiple) @drm_asahi_attachment payloads. > + */ > + DRM_ASAHI_SET_COMPUTE_ATTACHMENTS = 4, > +}; > + > +/** > + * enum drm_asahi_priority - Scheduling queue priority. > + * > + * These priorities are forwarded to the firmware to influence firmware > + * scheduling. The exact policy is ultimately decided by firmware, but > + * these enums allow userspace to communicate the intentions. > + */ > +enum drm_asahi_priority { > + /** @DRM_ASAHI_PRIORITY_LOW: Low priority queue. */ > + DRM_ASAHI_PRIORITY_LOW = 0, > + > + /** @DRM_ASAHI_PRIORITY_MEDIUM: Medium priority queue. */ > + DRM_ASAHI_PRIORITY_MEDIUM = 1, > + > + /** > + * @DRM_ASAHI_PRIORITY_HIGH: High priority queue. > + * > + * Reserved for future extension. > + */ > + DRM_ASAHI_PRIORITY_HIGH = 2, > + > + /** > + * @DRM_ASAHI_PRIORITY_REALTIME: Real-time priority queue. > + * > + * Reserved for future extension. > + */ > + DRM_ASAHI_PRIORITY_REALTIME = 3, > +}; > + > +/** > + * struct drm_asahi_queue_create - Arguments passed to > + * DRM_IOCTL_ASAHI_QUEUE_CREATE > + */ > +struct drm_asahi_queue_create { > + /** @flags: MBZ */ > + __u32 flags; > + > + /** @vm_id: The ID of the VM this queue is bound to */ > + __u32 vm_id; > + > + /** @priority: One of drm_asahi_priority */ > + __u32 priority; > + > + /** @queue_id: The returned queue ID */ > + __u32 queue_id; > + > + /** > + * @usc_exec_base: GPU base address for all USC binaries (shaders) on > + * this queue. USC addresses are 32-bit relative to this 64-bit base. > + * > + * This sets the following registers on all queue commands: > + * > + * USC_EXEC_BASE_TA (vertex) > + * USC_EXEC_BASE_ISP (fragment) > + * USC_EXEC_BASE_CP (compute) > + * > + * While the hardware lets us configure these independently per command, > + * we do not have a use case for this. Instead, we expect userspace to > + * fix a 4GiB VA carveout for USC memory and pass its base address here. > + */ > + __u64 usc_exec_base; > +}; > + > +/** > + * struct drm_asahi_queue_destroy - Arguments passed to > + * DRM_IOCTL_ASAHI_QUEUE_DESTROY > + */ > +struct drm_asahi_queue_destroy { > + /** @queue_id: The queue ID to be destroyed */ > + __u32 queue_id; > + > + /** @pad: MBZ */ > + __u32 pad; > +}; > + > +/** > + * enum drm_asahi_sync_type - Sync item type > + */ > +enum drm_asahi_sync_type { > + /** @DRM_ASAHI_SYNC_SYNCOBJ: Binary sync object */ > + DRM_ASAHI_SYNC_SYNCOBJ = 0, > + > + /** @DRM_ASAHI_SYNC_TIMELINE_SYNCOBJ: Timeline sync object */ > + DRM_ASAHI_SYNC_TIMELINE_SYNCOBJ = 1, > +}; > + > +/** > + * struct drm_asahi_sync - Sync item > + */ > +struct drm_asahi_sync { > + /** @sync_type: One of drm_asahi_sync_type */ > + __u32 sync_type; > + > + /** @handle: The sync object handle */ > + __u32 handle; > + > + /** @timeline_value: Timeline value for timeline sync objects */ > + __u64 timeline_value; > +}; > + > +/** > + * define DRM_ASAHI_BARRIER_NONE - Command index for no barrier > + * > + * This special value may be passed in to drm_asahi_command::barriers[] to > + * indicate that the respective subqueue should not wait on any previous work. > + */ > +#define DRM_ASAHI_BARRIER_NONE (0xFFFFu) > + > +/** > + * struct drm_asahi_cmd_header - Top level command structure > + * > + * This struct is core to the command buffer definition and therefore is not > + * extensible. > + */ > +struct drm_asahi_cmd_header { > + /** @cmd_type: One of drm_asahi_cmd_type */ > + __u16 cmd_type; > + > + /** > + * @size: Size of this command, not including this header. > + * > + * For hardware commands, this enables extensibility of commands without > + * requiring extra command types. Passing a command that is shorter > + * than expected is explicitly allowed for backwards-compatibility. > + * Truncated fields will be zeroed. > + * > + * For the synthetic attachment setting commands, this implicitly > + * encodes the number of attachments. These commands take multiple > + * fixed-size @drm_asahi_attachment structures as their payload, so size > + * equals number of attachments * sizeof(struct drm_asahi_attachment). > + */ > + __u16 size; > + > + /** > + * @vdm_barrier: VDM (render) command index to wait on. > + * > + * Barriers are indices relative to the beginning of a given submit. A > + * barrier of 0 waits on commands submitted to the respective subqueue > + * in previous submit ioctls. A barrier of N waits on N previous > + * commands on the subqueue within the current submit ioctl. As a > + * special case, passing @DRM_ASAHI_BARRIER_NONE avoids waiting on any > + * commands in the subqueue. > + * > + * Examples: > + * > + * 0: This waits on all previous work. > + * > + * NONE: This does not wait for anything on this subqueue. > + * > + * 1: This waits on the first render command in the submit. > + * This only makes sense if there are multiple render commands in the > + * same submit. > + * > + * Barriers only make sense for hardware commands. Synthetic software > + * commands to set attachments must pass NONE here. > + */ > + __u16 vdm_barrier; > + > + /** > + * @cdm_barrier: CDM (compute) command index to wait on. > + * > + * See @vdm_barrier, and substitute VDM/render for CDM/compute. > + */ > + __u16 cdm_barrier; > +}; > + > +/** > + * struct drm_asahi_submit - Arguments passed to DRM_IOCTL_ASAHI_SUBMIT > + */ > +struct drm_asahi_submit { > + /** > + * @syncs: An optional array of drm_asahi_sync. First @in_sync_count > + * in-syncs then @out_sync_count out-syncs. > + */ > + __u64 syncs; > + > + /** > + * @cmdbuf: Pointer to the command buffer to submit. > + * > + * This is a flat command buffer. By design, it contains no CPU > + * pointers, which makes it suitable for a virtgpu wire protocol without > + * requiring any serializing/deserializing step. > + * > + * It consists of a series of commands. Each command begins with a > + * fixed-size @drm_asahi_cmd_header and is followed by a variable-length > + * payload according to the type and size in the header. > + * > + * The combined count of "real" hardware commands must be nonzero and at > + * most drm_asahi_params_global::max_commands_per_submission. > + */ > + __u64 cmdbuf; > + > + /** @flags: Flags for command submission (MBZ) */ > + __u32 flags; > + > + /** @queue_id: The queue ID to be submitted to */ > + __u32 queue_id; > + > + /** > + * @in_sync_count: Number of sync objects to wait on before starting > + * this job. > + */ > + __u32 in_sync_count; > + > + /** > + * @out_sync_count: Number of sync objects to signal upon completion of > + * this job. > + */ > + __u32 out_sync_count; > + > + /** @cmdbuf_size: Command buffer size in bytes */ > + __u32 cmdbuf_size; > + > + /** @pad: MBZ */ > + __u32 pad; > +}; > + > +/** > + * struct drm_asahi_attachment - Describe an "attachment". > + * > + * Attachments are any memory written by shaders, notably including render > + * target attachments written by the end-of-tile program. This is purely a hint > + * about the accessed memory regions. It is optional to specify, which is > + * fortunate as it cannot be specified precisely with bindless access anyway. > + * But where possible, it's probably a good idea for userspace to include these > + * hints, forwarded to the firmware. > + * > + * This struct is implicitly sized and therefore is not extensible. > + */ > +struct drm_asahi_attachment { > + /** @pointer: Base address of the attachment */ > + __u64 pointer; > + > + /** @size: Size of the attachment in bytes */ > + __u64 size; > + > + /** @pad: MBZ */ > + __u32 pad; > + > + /** @flags: MBZ */ > + __u32 flags; > +}; > + > +enum drm_asahi_render_flags { > + /** > + * @DRM_ASAHI_RENDER_VERTEX_SCRATCH: A vertex stage shader uses scratch > + * memory. > + */ > + DRM_ASAHI_RENDER_VERTEX_SCRATCH = (1U << 0), > + > + /** > + * @DRM_ASAHI_RENDER_PROCESS_EMPTY_TILES: Process even empty tiles. > + * This must be set when clearing render targets. > + */ > + DRM_ASAHI_RENDER_PROCESS_EMPTY_TILES = (1U << 1), > + > + /** > + * @DRM_ASAHI_RENDER_NO_VERTEX_CLUSTERING: Run vertex stage on a single > + * cluster (on multi-cluster GPUs) > + * > + * This harms performance but can workaround certain sync/coherency > + * bugs, and therefore is useful for debugging. > + */ > + DRM_ASAHI_RENDER_NO_VERTEX_CLUSTERING = (1U << 2), > + > + /** > + * @DRM_ASAHI_RENDER_DBIAS_IS_INT: Use integer depth bias formula. > + * > + * Graphics specifications contain two alternate formulas for depth > + * bias, a float formula used with floating-point depth buffers and an > + * integer formula using with unorm depth buffers. This flag specifies > + * that the integer formula should be used. If omitted, the float > + * formula is used instead. > + * > + * This corresponds to bit 18 of the relevant hardware control register, > + * so we match that here for efficiency. > + */ > + DRM_ASAHI_RENDER_DBIAS_IS_INT = (1U << 18), > +}; > + > +/** > + * struct drm_asahi_zls_buffer - Describe a depth or stencil buffer. > + * > + * These fields correspond to hardware registers in the ZLS (Z Load/Store) unit. > + * There are three hardware registers for each field respectively for loads, > + * stores, and partial renders. In practice, it makes sense to set all to the > + * same values, except in exceptional cases not yet implemented in userspace, so > + * we do not duplicate here for simplicity/efficiency. > + * > + * This struct is embedded in other structs and therefore is not extensible. > + */ > +struct drm_asahi_zls_buffer { > + /** @base: Base address of the buffer */ > + __u64 base; > + > + /** > + * @comp_base: If the load buffer is compressed, address of the > + * compression metadata section. > + */ > + __u64 comp_base; > + > + /** > + * @stride: If layered rendering is enabled, the number of bytes > + * between each layer of the buffer. > + */ > + __u32 stride; > + > + /** > + * @comp_stride: If layered rendering is enabled, the number of bytes > + * between each layer of the compression metadata. > + */ > + __u32 comp_stride; > +}; > + > +/** > + * struct drm_asahi_timestamp - Describe a timestamp write. > + * > + * The firmware can optionally write the GPU timestamp at render pass > + * granularities, but it needs to be mapped specially via > + * DRM_IOCTL_ASAHI_GEM_BIND_OBJECT. This structure therefore describes where to > + * write as a handle-offset pair, rather than a GPU address like normal. > + * > + * This struct is embedded in other structs and therefore is not extensible. > + */ > +struct drm_asahi_timestamp { > + /** > + * @handle: Handle of the timestamp buffer, or 0 to skip this > + * timestamp. If nonzero, this must equal the value returned in > + * drm_asahi_gem_bind_object::object_handle. > + */ > + __u32 handle; > + > + /** @offset: Offset to write into the timestamp buffer */ > + __u32 offset; > +}; > + > +/** > + * struct drm_asahi_timestamps - Describe timestamp writes. > + * > + * Each operation that can be timestamped, can be timestamped at the start and > + * end. Therefore, drm_asahi_timestamp structs always come in pairs, bundled > + * together into drm_asahi_timestamps. > + * > + * This struct is embedded in other structs and therefore is not extensible. > + */ > +struct drm_asahi_timestamps { > + /** @start: Timestamp recorded at the start of the operation */ > + struct drm_asahi_timestamp start; > + > + /** @end: Timestamp recorded at the end of the operation */ > + struct drm_asahi_timestamp end; > +}; > + > +/** > + * struct drm_asahi_helper_program - Describe helper program configuration. > + * > + * The helper program is a compute-like kernel required for various hardware > + * functionality. Its most important role is dynamically allocating > + * scratch/stack memory for individual subgroups, by partitioning a static > + * allocation shared for the whole device. It is supplied by userspace via > + * drm_asahi_helper_program and internally dispatched by the hardware as needed. > + * > + * This struct is embedded in other structs and therefore is not extensible. > + */ > +struct drm_asahi_helper_program { > + /** > + * @binary: USC address to the helper program binary. This is a tagged > + * pointer with configuration in the bottom bits. > + */ > + __u32 binary; > + > + /** @cfg: Configuration bits for the helper program. */ > + __u32 cfg; > + > + /** > + * @data: Data passed to the helper program. This value is not > + * interpreted by the kernel, firmware, or hardware in any way. It is > + * simply a sideband for userspace, set with the submit ioctl and read > + * via special registers inside the helper program. > + * > + * In practice, userspace will pass a 64-bit GPU VA here pointing to the > + * actual arguments, which presumably don't fit in 64-bits. > + */ > + __u64 data; > +}; > + > +/** > + * struct drm_asahi_bg_eot - Describe a background or end-of-tile program. > + * > + * The background and end-of-tile programs are dispatched by the hardware at the > + * beginning and end of rendering. As the hardware "tilebuffer" is simply local > + * memory, these programs are necessary to implement API-level render targets. > + * The fragment-like background program is responsible for loading either the > + * clear colour or the existing render target contents, while the compute-like > + * end-of-tile program stores the tilebuffer contents to memory. > + * > + * This struct is embedded in other structs and therefore is not extensible. > + */ > +struct drm_asahi_bg_eot { > + /** > + * @usc: USC address of the hardware USC words binding resources > + * (including images and uniforms) and the program itself. Note this is > + * an additional layer of indirection compared to the helper program, > + * avoiding the need for a sideband for data. This is a tagged pointer > + * with additional configuration in the bottom bits. > + */ > + __u32 usc; > + > + /** > + * @rsrc_spec: Resource specifier for the program. This is a packed > + * hardware data structure describing the required number of registers, > + * uniforms, bound textures, and bound samplers. > + */ > + __u32 rsrc_spec; > +}; > + > +/** > + * struct drm_asahi_cmd_render - Command to submit 3D > + * > + * This command submits a single render pass. The hardware control stream may > + * include many draws and subpasses, but within the command, the framebuffer > + * dimensions and attachments are fixed. > + * > + * The hardware requires the firmware to set a large number of Control Registers > + * setting up state at render pass granularity before each command rendering 3D. > + * The firmware bundles this state into data structures. Unfortunately, we > + * cannot expose either any of that directly to userspace, because the > + * kernel-firmware ABI is not stable. Although we can guarantee the firmware > + * updates in tandem with the kernel, we cannot break old userspace when > + * upgrading the firmware and kernel. Therefore, we need to abstract well the > + * data structures to avoid tying our hands with future firmwares. > + * > + * The bulk of drm_asahi_cmd_render therefore consists of values of hardware > + * control registers, marshalled via the firmware interface. > + * > + * The framebuffer/tilebuffer dimensions are also specified here. In addition to > + * being passed to the firmware/hardware, the kernel requires these dimensions > + * to calculate various essential tiling-related data structures. It is > + * unfortunate that our submits are heavier than on vendors with saner > + * hardware-software interfaces. The upshot is all of this information is > + * readily available to userspace with all current APIs. > + * > + * It looks odd - but it's not overly burdensome and it ensures we can remain > + * compatible with old userspace. > + */ > +struct drm_asahi_cmd_render { > + /** @flags: Combination of drm_asahi_render_flags flags. */ > + __u32 flags; > + > + /** > + * @isp_zls_pixels: ISP_ZLS_PIXELS register value. This contains the > + * depth/stencil width/height, which may differ from the framebuffer > + * width/height. > + */ > + __u32 isp_zls_pixels; > + > + /** > + * @vdm_ctrl_stream_base: VDM_CTRL_STREAM_BASE register value. GPU > + * address to the beginning of the VDM control stream. > + */ > + __u64 vdm_ctrl_stream_base; > + > + /** @vertex_helper: Helper program used for the vertex shader */ > + struct drm_asahi_helper_program vertex_helper; > + > + /** @fragment_helper: Helper program used for the fragment shader */ > + struct drm_asahi_helper_program fragment_helper; > + > + /** > + * @isp_scissor_base: ISP_SCISSOR_BASE register value. GPU address of an > + * array of scissor descriptors indexed in the render pass. > + */ > + __u64 isp_scissor_base; > + > + /** > + * @isp_dbias_base: ISP_DBIAS_BASE register value. GPU address of an > + * array of depth bias values indexed in the render pass. > + */ > + __u64 isp_dbias_base; > + > + /** > + * @isp_oclqry_base: ISP_OCLQRY_BASE register value. GPU address of an > + * array of occlusion query results written by the render pass. > + */ > + __u64 isp_oclqry_base; > + > + /** @depth: Depth buffer */ > + struct drm_asahi_zls_buffer depth; > + > + /** @stencil: Stencil buffer */ > + struct drm_asahi_zls_buffer stencil; > + > + /** @zls_ctrl: ZLS_CTRL register value */ > + __u64 zls_ctrl; > + > + /** @ppp_multisamplectl: PPP_MULTISAMPLECTL register value */ > + __u64 ppp_multisamplectl; > + > + /** > + * @sampler_heap: Base address of the sampler heap. This heap is used > + * for both vertex shaders and fragment shaders. The registers are > + * per-stage, but there is no known use case for separate heaps. > + */ > + __u64 sampler_heap; > + > + /** @ppp_ctrl: PPP_CTRL register value */ > + __u32 ppp_ctrl; > + > + /** @width_px: Framebuffer width in pixels */ > + __u16 width_px; > + > + /** @height_px: Framebuffer height in pixels */ > + __u16 height_px; > + > + /** @layers: Number of layers in the framebuffer */ > + __u16 layers; > + > + /** @sampler_count: Number of samplers in the sampler heap. */ > + __u16 sampler_count; > + > + /** @utile_width_px: Width of a logical tilebuffer tile in pixels */ > + __u8 utile_width_px; > + > + /** @utile_height_px: Height of a logical tilebuffer tile in pixels */ > + __u8 utile_height_px; > + > + /** @samples: # of samples in the framebuffer. Must be 1, 2, or 4. */ > + __u8 samples; > + > + /** @sample_size_B: # of bytes in the tilebuffer required per sample. */ > + __u8 sample_size_B; > + > + /** > + * @isp_merge_upper_x: 32-bit float used in the hardware triangle > + * merging. Calculate as: tan(60 deg) * width. > + * > + * Making these values UAPI avoids requiring floating-point calculations > + * in the kernel in the hot path. > + */ > + __u32 isp_merge_upper_x; > + > + /** > + * @isp_merge_upper_y: 32-bit float. Calculate as: tan(60 deg) * height. > + * See @isp_merge_upper_x. > + */ > + __u32 isp_merge_upper_y; > + > + /** @bg: Background program run for each tile at the start */ > + struct drm_asahi_bg_eot bg; > + > + /** @eot: End-of-tile program ran for each tile at the end */ > + struct drm_asahi_bg_eot eot; > + > + /** > + * @partial_bg: Background program ran at the start of each tile when > + * resuming the render pass during a partial render. > + */ > + struct drm_asahi_bg_eot partial_bg; > + > + /** > + * @partial_eot: End-of-tile program ran at the end of each tile when > + * pausing the render pass during a partial render. > + */ > + struct drm_asahi_bg_eot partial_eot; > + > + /** > + * @isp_bgobjdepth: ISP_BGOBJDEPTH register value. This is the depth > + * buffer clear value, encoded in the depth buffer's format: either a > + * 32-bit float or a 16-bit unorm (with upper bits zeroed). > + */ > + __u32 isp_bgobjdepth; > + > + /** > + * @isp_bgobjvals: ISP_BGOBJVALS register value. The bottom 8-bits > + * contain the stencil buffer clear value. > + */ > + __u32 isp_bgobjvals; > + > + /** @ts_vtx: Timestamps for the vertex portion of the render */ > + struct drm_asahi_timestamps ts_vtx; > + > + /** @ts_frag: Timestamps for the fragment portion of the render */ > + struct drm_asahi_timestamps ts_frag; > +}; > + > +/** > + * struct drm_asahi_cmd_compute - Command to submit compute > + * > + * This command submits a control stream consisting of compute dispatches. There > + * is essentially no limit on how many compute dispatches may be included in a > + * single compute command, although timestamps are at command granularity. > + */ > +struct drm_asahi_cmd_compute { > + /** @flags: MBZ */ > + __u32 flags; > + > + /** @sampler_count: Number of samplers in the sampler heap. */ > + __u32 sampler_count; > + > + /** > + * @cdm_ctrl_stream_base: CDM_CTRL_STREAM_BASE register value. GPU > + * address to the beginning of the CDM control stream. > + */ > + __u64 cdm_ctrl_stream_base; > + > + /** > + * @cdm_ctrl_stream_end: GPU base address to the end of the hardware > + * control stream. Note this only considers the first contiguous segment > + * of the control stream, as the stream might jump elsewhere. > + */ > + __u64 cdm_ctrl_stream_end; > + > + /** @sampler_heap: Base address of the sampler heap. */ > + __u64 sampler_heap; > + > + /** @helper: Helper program used for this compute command */ > + struct drm_asahi_helper_program helper; > + > + /** @ts: Timestamps for the compute command */ > + struct drm_asahi_timestamps ts; > +}; > + > +/** > + * struct drm_asahi_get_time - Arguments passed to DRM_IOCTL_ASAHI_GET_TIME > + */ > +struct drm_asahi_get_time { > + /** @flags: MBZ. */ > + __u64 flags; > + > + /** @gpu_timestamp: On return, the GPU timestamp in nanoseconds. */ > + __u64 gpu_timestamp; > +}; > + > +/** > + * DRM_IOCTL_ASAHI() - Build an Asahi IOCTL number > + * @__access: Access type. Must be R, W or RW. > + * @__id: One of the DRM_ASAHI_xxx id. > + * @__type: Suffix of the type being passed to the IOCTL. > + * > + * Don't use this macro directly, use the DRM_IOCTL_ASAHI_xxx > + * values instead. > + * > + * Return: An IOCTL number to be passed to ioctl() from userspace. > + */ > +#define DRM_IOCTL_ASAHI(__access, __id, __type) \ > + DRM_IO ## __access(DRM_COMMAND_BASE + DRM_ASAHI_ ## __id, \ > + struct drm_asahi_ ## __type) > + > +/* Note: this is an enum so that it can be resolved by Rust bindgen. */ > +enum { > + DRM_IOCTL_ASAHI_GET_PARAMS = DRM_IOCTL_ASAHI(WR, GET_PARAMS, get_params), > + DRM_IOCTL_ASAHI_GET_TIME = DRM_IOCTL_ASAHI(WR, GET_TIME, get_time), > + DRM_IOCTL_ASAHI_VM_CREATE = DRM_IOCTL_ASAHI(WR, VM_CREATE, vm_create), > + DRM_IOCTL_ASAHI_VM_DESTROY = DRM_IOCTL_ASAHI(W, VM_DESTROY, vm_destroy), > + DRM_IOCTL_ASAHI_VM_BIND = DRM_IOCTL_ASAHI(W, VM_BIND, vm_bind), > + DRM_IOCTL_ASAHI_GEM_CREATE = DRM_IOCTL_ASAHI(WR, GEM_CREATE, gem_create), > + DRM_IOCTL_ASAHI_GEM_MMAP_OFFSET = DRM_IOCTL_ASAHI(WR, GEM_MMAP_OFFSET, gem_mmap_offset), > + DRM_IOCTL_ASAHI_GEM_BIND_OBJECT = DRM_IOCTL_ASAHI(WR, GEM_BIND_OBJECT, gem_bind_object), > + DRM_IOCTL_ASAHI_QUEUE_CREATE = DRM_IOCTL_ASAHI(WR, QUEUE_CREATE, queue_create), > + DRM_IOCTL_ASAHI_QUEUE_DESTROY = DRM_IOCTL_ASAHI(W, QUEUE_DESTROY, queue_destroy), > + DRM_IOCTL_ASAHI_SUBMIT = DRM_IOCTL_ASAHI(W, SUBMIT, submit), > +}; > + > +#if defined(__cplusplus) > +} > +#endif > + > +#endif /* _ASAHI_DRM_H_ */ > > --- > base-commit: 0ed1356af8f629ae807963b7db4e501e3b580bc2 > change-id: 20250307-agx-uapi-930579437f19 > > Best regards, > -- > Alyssa Rosenzweig <alyssa@rosenzweig.io> > > This looks good to me, and the referenced integration code also looks good. Reviewed-by: Neal Gompa <neal@gompa.dev> -- 真実はいつも一つ!/ Always, there's only one truth!
> > +/** > > + * struct drm_asahi_params_global - Global parameters. > > + * > > + * This struct may be queried by drm_asahi_get_params. > > + */ > > +struct drm_asahi_params_global { > > + /** @features: Feature bits from drm_asahi_feature */ > > + __u64 features; > > + > > + /** @gpu_generation: GPU generation, e.g. 13 for G13G */ > > + __u32 gpu_generation; > > + > > + /** @gpu_variant: GPU variant as a character, e.g. 'G' for G13G */ > > + __u32 gpu_variant; > > nit: the example can avoid the duplication of 'G' with "e.g. 'C' for > G13C" done in v6, thanks. > > +/** > > + * struct drm_asahi_get_params - Arguments passed to DRM_IOCTL_ASAHI_GET_PARAMS > > + */ > > +struct drm_asahi_get_params { > > + /** @param_group: Parameter group to fetch (MBZ) */ > > + __u32 param_group; > > + > > + /** @pad: MBZ */ > > + __u32 pad; > > + > > + /** @pointer: User pointer to write parameter struct */ > > + __u64 pointer; > > + > > + /** @size: Size of user buffer, max size supported on return */ > > + __u64 size; > > The comment is misleading in the case of newer / extended kernel which > supports a larger size than supplied. You could change it to "size > written on return" or clarify that the value on return will not exceed > the input value. fixed. > > +struct drm_asahi_vm_create { > > + /** > > + * @kernel_start: Start of the kernel-reserved address range. See > > + * drm_asahi_params_global::vm_kernel_min_size. > > + * > > + * Both @kernel_start and @kernel_end must be within the range of > > + * valid VAs given by drm_asahi_params_global::vm_user_start and > > + * drm_asahi_params_global::vm_user_end. The size of the kernel range > > This reads a little strange. Would it make sense to rename drm_asahi_params_global's > vm_user_start and vm_user_end to vm_start/vm_end? Good point, renamed. > > + /** > > + * @bind: Union holding the bind request. > > + * > > + * This union is named to make the Rust bindings nicer to work with. > > + */ > > This comment could use a short justification why this union does not > defeat extensibility after the initial statement that "structures should > not contain unions" Added. > > + /** > > + * @syncs: An optional array of drm_asahi_sync. First @in_sync_count > > + * in-syncs then @out_sync_count out-syncs. > > + */ > > + __u64 syncs; > > Would it make sense to explictly state that this is a pointer? Done. > Reviewed-by: Janne Grunau <j@jannau.net> Thanks!
> > https://github.com/alyssarosenzweig/linux/commits/agx-uapi-v5 contains > > the DRM driver implementing this proposed UAPI. > > > > https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33984 contains > > the Mesa patches to implement this proposed UAPI. > > > > That Linux and Mesa branch together give a complete graphics/compute > > stack on top of this UAPI. > > Do we want these links to be present in the commit message? I doubt > they'll stick around permanently... Permanently, no. But by the time they go dark, the relevant code will hopefully be upstream in both kernel & Mesa. So I'm not worried. Not really weirder than any other links in commit messages we have. > This looks good to me, and the referenced integration code also looks good. > > Reviewed-by: Neal Gompa <neal@gompa.dev> Thanks!
diff --git a/Documentation/gpu/driver-uapi.rst b/Documentation/gpu/driver-uapi.rst index 971cdb4816fc98d80a64d93637481d10c2e79718..1f15a8ca126516c23bd7374cc4aead0dfbbccf67 100644 --- a/Documentation/gpu/driver-uapi.rst +++ b/Documentation/gpu/driver-uapi.rst @@ -27,3 +27,8 @@ drm/xe uAPI =========== .. kernel-doc:: include/uapi/drm/xe_drm.h + +drm/asahi uAPI +================ + +.. kernel-doc:: include/uapi/drm/asahi_drm.h diff --git a/MAINTAINERS b/MAINTAINERS index d1050702f681fbd0e4e2d0457b2ba569a64070d9..7f692a935808d4ec82ee741324f8043302dae491 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2256,6 +2256,7 @@ F: drivers/watchdog/apple_wdt.c F: include/dt-bindings/interrupt-controller/apple-aic.h F: include/dt-bindings/pinctrl/apple.h F: include/linux/soc/apple/* +F: include/uapi/drm/asahi_drm.h ARM/ARTPEC MACHINE SUPPORT M: Jesper Nilsson <jesper.nilsson@axis.com> diff --git a/include/uapi/drm/asahi_drm.h b/include/uapi/drm/asahi_drm.h new file mode 100644 index 0000000000000000000000000000000000000000..a9465cb89ebde6f6768fbd5ba0fa4d753e2a7e32 --- /dev/null +++ b/include/uapi/drm/asahi_drm.h @@ -0,0 +1,1211 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) The Asahi Linux Contributors + * Copyright (C) 2018-2023 Collabora Ltd. + * Copyright (C) 2014-2018 Broadcom + */ +#ifndef _ASAHI_DRM_H_ +#define _ASAHI_DRM_H_ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * DOC: Introduction to the Asahi UAPI + * + * This documentation describes the Asahi IOCTLs. + * + * Just a few generic rules about the data passed to the Asahi IOCTLs (cribbed + * from Panthor): + * + * - Structures must be aligned on 64-bit/8-byte. If the object is not + * naturally aligned, a padding field must be added. + * - Fields must be explicitly aligned to their natural type alignment with + * pad[0..N] fields. + * - All padding fields will be checked by the driver to make sure they are + * zeroed. + * - Flags can be added, but not removed/replaced. + * - New fields can be added to the main structures (the structures + * directly passed to the ioctl). Those fields can be added at the end of + * the structure, or replace existing padding fields. Any new field being + * added must preserve the behavior that existed before those fields were + * added when a value of zero is passed. + * - New fields can be added to indirect objects (objects pointed by the + * main structure), iff those objects are passed a size to reflect the + * size known by the userspace driver (see + * drm_asahi_command::cmd_buffer_size). + * - If the kernel driver is too old to know some fields, those will be + * ignored if zero, and otherwise rejected (and so will be zero on output). + * - If userspace is too old to know some fields, those will be zeroed + * (input) before the structure is parsed by the kernel driver. + * - Each new flag/field addition must come with a driver version update so + * the userspace driver doesn't have to trial and error to know which + * flags are supported. + * - Structures should not contain unions, as this would defeat the + * extensibility of such structures. + * - IOCTLs can't be removed or replaced. New IOCTL IDs should be placed + * at the end of the drm_asahi_ioctl_id enum. + */ + +/** + * enum drm_asahi_ioctl_id - IOCTL IDs + * + * Place new ioctls at the end, don't re-order, don't replace or remove entries. + * + * These IDs are not meant to be used directly. Use the DRM_IOCTL_ASAHI_xxx + * definitions instead. + */ +enum drm_asahi_ioctl_id { + /** @DRM_ASAHI_GET_PARAMS: Query device properties. */ + DRM_ASAHI_GET_PARAMS = 0, + + /** @DRM_ASAHI_GET_TIME: Query device time. */ + DRM_ASAHI_GET_TIME, + + /** @DRM_ASAHI_VM_CREATE: Create a GPU VM address space. */ + DRM_ASAHI_VM_CREATE, + + /** @DRM_ASAHI_VM_DESTROY: Destroy a VM. */ + DRM_ASAHI_VM_DESTROY, + + /** @DRM_ASAHI_VM_BIND: Bind/unbind memory to a VM. */ + DRM_ASAHI_VM_BIND, + + /** @DRM_ASAHI_GEM_CREATE: Create a buffer object. */ + DRM_ASAHI_GEM_CREATE, + + /** + * @DRM_ASAHI_GEM_MMAP_OFFSET: Get offset to pass to mmap() to map a + * given GEM handle. + */ + DRM_ASAHI_GEM_MMAP_OFFSET, + + /** @DRM_ASAHI_GEM_BIND_OBJECT: Bind memory as a special object */ + DRM_ASAHI_GEM_BIND_OBJECT, + + /** @DRM_ASAHI_QUEUE_CREATE: Create a scheduling queue. */ + DRM_ASAHI_QUEUE_CREATE, + + /** @DRM_ASAHI_QUEUE_DESTROY: Destroy a scheduling queue. */ + DRM_ASAHI_QUEUE_DESTROY, + + /** @DRM_ASAHI_SUBMIT: Submit commands to a queue. */ + DRM_ASAHI_SUBMIT, +}; + +#define DRM_ASAHI_MAX_CLUSTERS 64 + +/** + * struct drm_asahi_params_global - Global parameters. + * + * This struct may be queried by drm_asahi_get_params. + */ +struct drm_asahi_params_global { + /** @features: Feature bits from drm_asahi_feature */ + __u64 features; + + /** @gpu_generation: GPU generation, e.g. 13 for G13G */ + __u32 gpu_generation; + + /** @gpu_variant: GPU variant as a character, e.g. 'G' for G13G */ + __u32 gpu_variant; + + /** + * @gpu_revision: GPU revision in BCD, e.g. 0x00 for 'A0' or + * 0x21 for 'C1' + */ + __u32 gpu_revision; + + /** @chip_id: Chip ID in BCD, e.g. 0x8103 for T8103 */ + __u32 chip_id; + + /** @num_dies: Number of dies in the SoC */ + __u32 num_dies; + + /** @num_clusters_total: Number of GPU clusters (across all dies) */ + __u32 num_clusters_total; + + /** + * @num_cores_per_cluster: Number of logical cores per cluster + * (including inactive/nonexistent) + */ + __u32 num_cores_per_cluster; + + /** @num_frags_per_cluster: Number of frags per cluster */ + __u32 num_frags_per_cluster; + + /** @num_gps_per_cluster: Number of GPs per cluster */ + __u32 num_gps_per_cluster; + + /** @max_power_mw: Maximum GPU power consumption */ + __u32 max_power_mw; + + /** @core_masks: Bitmask of present/enabled cores per cluster */ + __u64 core_masks[DRM_ASAHI_MAX_CLUSTERS]; + + /** @min_frequency_khz: Minimum GPU core clock frequency */ + __u32 min_frequency_khz; + + /** @max_frequency_khz: Maximum GPU core clock frequency */ + __u32 max_frequency_khz; + + /** + * @vm_user_start: VM user range start VMA. Together with + * @vm_user_end, this defines the window of valid GPU VAs. Userspace is + * expected to subdivide VAs out of this window. + */ + __u64 vm_user_start; + + /** @vm_user_end: VM user range end VMA */ + __u64 vm_user_end; + + /** + * @vm_kernel_min_size: Minimum kernel VMA window size within user + * range. + * + * When creating a VM, userspace is required to carve out a section of + * virtual addresses (within the range given by @vm_user_start and + * @vm_user_end). The kernel will allocate various internal structures + * within the specified VA range. + * + * Allowing userspace to choose the VA range for the kernel, rather than + * the kernel reserving VAs and requiring userspace to cope, can assist + * in implementing SVM. + */ + __u64 vm_kernel_min_size; + + /** + * @max_commands_per_submission: Maximum number of supported commands + * per submission. This mirrors firmware limits. Userspace must split up + * larger command buffers, which may require inserting additional + * barriers explicitly. + */ + __u32 max_commands_per_submission; + + /** + * @max_attachments: Maximum number of drm_asahi_attachment's per + * command + */ + __u32 max_attachments; + + /** + * @command_timestamp_frequency_hz: Timebase frequency for timestamps + * written during command exeuction, specified via drm_asahi_timestamp + * structures. As this rate is controlled by the firmware, it is a + * queryable parameter. + * + * Userspace must divide by this frequency to convert timestamps to + * seconds, rather than hardcoding a particular firmware's rate. + */ + __u64 command_timestamp_frequency_hz; +}; + +/** + * enum drm_asahi_feature - Feature bits + * + * This covers only features that userspace cannot infer from the architecture + * version. Most features don't need to be here. + */ +enum drm_asahi_feature { + /** + * @DRM_ASAHI_FEATURE_SOFT_FAULTS: GPU has "soft fault" enabled. Shader + * loads of unmapped memory will return zero. Shader stores to unmapped + * memory will be silently discarded. Note that only shader load/store + * is affected. Other hardware units are not affected, notably including + * texture sampling. + * + * Soft fault is set when initializing the GPU and cannot be runtime + * toggled. Therefore, it is exposed as a feature bit and not a + * userspace-settable flag on the VM. When soft fault is enabled, + * userspace can speculate memory accesses more aggressively. + */ + DRM_ASAHI_FEATURE_SOFT_FAULTS = (1UL) << 0, +}; + +/** + * struct drm_asahi_get_params - Arguments passed to DRM_IOCTL_ASAHI_GET_PARAMS + */ +struct drm_asahi_get_params { + /** @param_group: Parameter group to fetch (MBZ) */ + __u32 param_group; + + /** @pad: MBZ */ + __u32 pad; + + /** @pointer: User pointer to write parameter struct */ + __u64 pointer; + + /** @size: Size of user buffer, max size supported on return */ + __u64 size; +}; + +/** + * struct drm_asahi_vm_create - Arguments passed to DRM_IOCTL_ASAHI_VM_CREATE + */ +struct drm_asahi_vm_create { + /** + * @kernel_start: Start of the kernel-reserved address range. See + * drm_asahi_params_global::vm_kernel_min_size. + * + * Both @kernel_start and @kernel_end must be within the range of + * valid VAs given by drm_asahi_params_global::vm_user_start and + * drm_asahi_params_global::vm_user_end. The size of the kernel range + * (@kernel_end - @kernel_start) must be at least + * drm_asahi_params_global::vm_kernel_min_size. + * + * Userspace must not bind any memory on this VM into this reserved + * range, it is for kernel use only. + */ + __u64 kernel_start; + + /** + * @kernel_end: End of the kernel-reserved address range. See + * @kernel_start. + */ + __u64 kernel_end; + + /** @vm_id: Returned VM ID */ + __u32 vm_id; + + /** @pad: MBZ */ + __u32 pad; +}; + +/** + * struct drm_asahi_vm_destroy - Arguments passed to DRM_IOCTL_ASAHI_VM_DESTROY + */ +struct drm_asahi_vm_destroy { + /** @vm_id: VM ID to be destroyed */ + __u32 vm_id; + + /** @pad: MBZ */ + __u32 pad; +}; + +/** + * enum drm_asahi_gem_flags - Flags for GEM creation + */ +enum drm_asahi_gem_flags { + /** + * @DRM_ASAHI_GEM_WRITEBACK: BO should be CPU-mapped as writeback. + * + * Map as writeback instead of write-combine. This optimizes for CPU + * reads. + */ + DRM_ASAHI_GEM_WRITEBACK = (1L << 0), + + /** + * @DRM_ASAHI_GEM_VM_PRIVATE: BO is private to this GPU VM (no exports). + */ + DRM_ASAHI_GEM_VM_PRIVATE = (1L << 1), +}; + +/** + * struct drm_asahi_gem_create - Arguments passed to DRM_IOCTL_ASAHI_GEM_CREATE + */ +struct drm_asahi_gem_create { + /** @size: Size of the BO */ + __u64 size; + + /** @flags: Combination of drm_asahi_gem_flags flags. */ + __u32 flags; + + /** + * @vm_id: VM ID to assign to the BO, if DRM_ASAHI_GEM_VM_PRIVATE is set + */ + __u32 vm_id; + + /** @handle: Returned GEM handle for the BO */ + __u32 handle; + + /** @pad: MBZ */ + __u32 pad; +}; + +/** + * struct drm_asahi_gem_mmap_offset - Arguments passed to + * DRM_IOCTL_ASAHI_GEM_MMAP_OFFSET + */ +struct drm_asahi_gem_mmap_offset { + /** @handle: Handle for the object being mapped. */ + __u32 handle; + + /** @flags: Must be zero */ + __u32 flags; + + /** @offset: The fake offset to use for subsequent mmap call */ + __u64 offset; +}; + +/** + * enum drm_asahi_bind_flags - Flags for GEM binding + */ +enum drm_asahi_bind_flags { + /** + * @DRM_ASAHI_BIND_UNBIND: Instead of binding a GEM object to the range, + * simply unbind the GPU VMA range. + */ + DRM_ASAHI_BIND_UNBIND = (1L << 0), + + /** @DRM_ASAHI_BIND_READ: Map BO with GPU read permission */ + DRM_ASAHI_BIND_READ = (1L << 1), + + /** @DRM_ASAHI_BIND_WRITE: Map BO with GPU write permission */ + DRM_ASAHI_BIND_WRITE = (1L << 2), + + /** + * @DRM_ASAHI_BIND_SINGLE_PAGE: Map a single page of the BO repeatedly + * across the VA range. + * + * This is useful to fill a VA range with scratch pages or zero pages. + * It is intended as a mechanism to accelerate sparse. + */ + DRM_ASAHI_BIND_SINGLE_PAGE = (1L << 3), +}; + +/** + * struct drm_asahi_gem_bind_op - Description of a single GEM bind operation. + */ +struct drm_asahi_gem_bind_op { + /** @flags: Combination of drm_asahi_bind_flags flags. */ + __u32 flags; + + /** @handle: GEM object to bind (except for UNBIND) */ + __u32 handle; + + /** + * @offset: Offset into the object (except for UNBIND). + * + * For a regular bind, this is the beginning of the region of the GEM + * object to bind. + * + * For a single-page bind, this is the offset to the single page that + * will be repeatedly bound. + * + * Must be page-size aligned. + */ + __u64 offset; + + /** + * @range: Number of bytes to bind/unbind to @addr. + * + * Must be page-size aligned. + */ + __u64 range; + + /** + * @addr: Address to bind to. + * + * Must be page-size aligned. + */ + __u64 addr; +}; + +/** + * struct drm_asahi_vm_bind - Arguments passed to + * DRM_IOCTL_ASAHI_VM_BIND + */ +struct drm_asahi_vm_bind { + /** @vm_id: The ID of the VM to bind to */ + __u32 vm_id; + + /** @num_binds: number of binds in this IOCTL. Must be non-zero. */ + __u32 num_binds; + + /** + * @stride: If num_binds > 1, stride in bytes between consecutive binds. + * This allows extensibility of drm_asahi_gem_bind_op. + * + * If num_binds == 1, MBZ. Extensibility in that case is handled at the + * ioctl level instead. + */ + __u32 stride; + + /** @pad: MBZ */ + __u32 pad; + + /** + * @bind: Union holding the bind request. + * + * This union is named to make the Rust bindings nicer to work with. + */ + union { + /** @bind.b: If num_binds == 1, the bind */ + struct drm_asahi_gem_bind_op b; + + /** + * @bind.userptr: If num_binds > 1, user pointer to an array of + * @num_binds structures of type @drm_asahi_gem_bind_op and size + * @stride bytes. + */ + __u64 userptr; + } bind; +}; + +/** + * enum drm_asahi_bind_object_op - Special object bind operation + */ +enum drm_asahi_bind_object_op { + /** @DRM_ASAHI_BIND_OBJECT_OP_BIND: Bind a BO as a special GPU object */ + DRM_ASAHI_BIND_OBJECT_OP_BIND = 0, + + /** @DRM_ASAHI_BIND_OBJECT_OP_UNBIND: Unbind a special GPU object */ + DRM_ASAHI_BIND_OBJECT_OP_UNBIND = 1, +}; + +/** + * enum drm_asahi_bind_object_flags - Special object bind flags + */ +enum drm_asahi_bind_object_flags { + /** + * @DRM_ASAHI_BIND_OBJECT_USAGE_TIMESTAMPS: Map a BO as a timestamp + * buffer. + */ + DRM_ASAHI_BIND_OBJECT_USAGE_TIMESTAMPS = (1L << 0), +}; + +/** + * struct drm_asahi_gem_bind_object - Arguments passed to + * DRM_IOCTL_ASAHI_GEM_BIND_OBJECT + */ +struct drm_asahi_gem_bind_object { + /** @op: Bind operation (enum drm_asahi_bind_object_op) */ + __u32 op; + + /** @flags: Combination of drm_asahi_bind_object_flags flags. */ + __u32 flags; + + /** @handle: GEM object to bind/unbind (BIND) */ + __u32 handle; + + /** @vm_id: The ID of the VM to operate on (MBZ currently) */ + __u32 vm_id; + + /** @offset: Offset into the object (BIND only) */ + __u64 offset; + + /** @range: Number of bytes to bind/unbind (BIND only) */ + __u64 range; + + /** @object_handle: Object handle (out for BIND, in for UNBIND) */ + __u32 object_handle; + + /** @pad: MBZ */ + __u32 pad; +}; + +/** + * enum drm_asahi_cmd_type - Command type + */ +enum drm_asahi_cmd_type { + /** + * @DRM_ASAHI_CMD_RENDER: Render command, executing on the render + * subqueue. Combined vertex and fragment operation. + * + * Followed by a @drm_asahi_cmd_render payload. + */ + DRM_ASAHI_CMD_RENDER = 0, + + /** + * @DRM_ASAHI_CMD_COMPUTE: Compute command on the compute subqueue. + * + * Followed by a @drm_asahi_cmd_compute payload. + */ + DRM_ASAHI_CMD_COMPUTE = 1, + + /** + * @DRM_ASAHI_SET_VERTEX_ATTACHMENTS: Software command to set + * attachments for subsequent vertex shaders in the same submit. + * + * Followed by (possibly multiple) @drm_asahi_attachment payloads. + */ + DRM_ASAHI_SET_VERTEX_ATTACHMENTS = 2, + + /** + * @DRM_ASAHI_SET_FRAGMENT_ATTACHMENTS: Software command to set + * attachments for subsequent fragment shaders in the same submit. + * + * Followed by (possibly multiple) @drm_asahi_attachment payloads. + */ + DRM_ASAHI_SET_FRAGMENT_ATTACHMENTS = 3, + + /** + * @DRM_ASAHI_SET_COMPUTE_ATTACHMENTS: Software command to set + * attachments for subsequent compute shaders in the same submit. + * + * Followed by (possibly multiple) @drm_asahi_attachment payloads. + */ + DRM_ASAHI_SET_COMPUTE_ATTACHMENTS = 4, +}; + +/** + * enum drm_asahi_priority - Scheduling queue priority. + * + * These priorities are forwarded to the firmware to influence firmware + * scheduling. The exact policy is ultimately decided by firmware, but + * these enums allow userspace to communicate the intentions. + */ +enum drm_asahi_priority { + /** @DRM_ASAHI_PRIORITY_LOW: Low priority queue. */ + DRM_ASAHI_PRIORITY_LOW = 0, + + /** @DRM_ASAHI_PRIORITY_MEDIUM: Medium priority queue. */ + DRM_ASAHI_PRIORITY_MEDIUM = 1, + + /** + * @DRM_ASAHI_PRIORITY_HIGH: High priority queue. + * + * Reserved for future extension. + */ + DRM_ASAHI_PRIORITY_HIGH = 2, + + /** + * @DRM_ASAHI_PRIORITY_REALTIME: Real-time priority queue. + * + * Reserved for future extension. + */ + DRM_ASAHI_PRIORITY_REALTIME = 3, +}; + +/** + * struct drm_asahi_queue_create - Arguments passed to + * DRM_IOCTL_ASAHI_QUEUE_CREATE + */ +struct drm_asahi_queue_create { + /** @flags: MBZ */ + __u32 flags; + + /** @vm_id: The ID of the VM this queue is bound to */ + __u32 vm_id; + + /** @priority: One of drm_asahi_priority */ + __u32 priority; + + /** @queue_id: The returned queue ID */ + __u32 queue_id; + + /** + * @usc_exec_base: GPU base address for all USC binaries (shaders) on + * this queue. USC addresses are 32-bit relative to this 64-bit base. + * + * This sets the following registers on all queue commands: + * + * USC_EXEC_BASE_TA (vertex) + * USC_EXEC_BASE_ISP (fragment) + * USC_EXEC_BASE_CP (compute) + * + * While the hardware lets us configure these independently per command, + * we do not have a use case for this. Instead, we expect userspace to + * fix a 4GiB VA carveout for USC memory and pass its base address here. + */ + __u64 usc_exec_base; +}; + +/** + * struct drm_asahi_queue_destroy - Arguments passed to + * DRM_IOCTL_ASAHI_QUEUE_DESTROY + */ +struct drm_asahi_queue_destroy { + /** @queue_id: The queue ID to be destroyed */ + __u32 queue_id; + + /** @pad: MBZ */ + __u32 pad; +}; + +/** + * enum drm_asahi_sync_type - Sync item type + */ +enum drm_asahi_sync_type { + /** @DRM_ASAHI_SYNC_SYNCOBJ: Binary sync object */ + DRM_ASAHI_SYNC_SYNCOBJ = 0, + + /** @DRM_ASAHI_SYNC_TIMELINE_SYNCOBJ: Timeline sync object */ + DRM_ASAHI_SYNC_TIMELINE_SYNCOBJ = 1, +}; + +/** + * struct drm_asahi_sync - Sync item + */ +struct drm_asahi_sync { + /** @sync_type: One of drm_asahi_sync_type */ + __u32 sync_type; + + /** @handle: The sync object handle */ + __u32 handle; + + /** @timeline_value: Timeline value for timeline sync objects */ + __u64 timeline_value; +}; + +/** + * define DRM_ASAHI_BARRIER_NONE - Command index for no barrier + * + * This special value may be passed in to drm_asahi_command::barriers[] to + * indicate that the respective subqueue should not wait on any previous work. + */ +#define DRM_ASAHI_BARRIER_NONE (0xFFFFu) + +/** + * struct drm_asahi_cmd_header - Top level command structure + * + * This struct is core to the command buffer definition and therefore is not + * extensible. + */ +struct drm_asahi_cmd_header { + /** @cmd_type: One of drm_asahi_cmd_type */ + __u16 cmd_type; + + /** + * @size: Size of this command, not including this header. + * + * For hardware commands, this enables extensibility of commands without + * requiring extra command types. Passing a command that is shorter + * than expected is explicitly allowed for backwards-compatibility. + * Truncated fields will be zeroed. + * + * For the synthetic attachment setting commands, this implicitly + * encodes the number of attachments. These commands take multiple + * fixed-size @drm_asahi_attachment structures as their payload, so size + * equals number of attachments * sizeof(struct drm_asahi_attachment). + */ + __u16 size; + + /** + * @vdm_barrier: VDM (render) command index to wait on. + * + * Barriers are indices relative to the beginning of a given submit. A + * barrier of 0 waits on commands submitted to the respective subqueue + * in previous submit ioctls. A barrier of N waits on N previous + * commands on the subqueue within the current submit ioctl. As a + * special case, passing @DRM_ASAHI_BARRIER_NONE avoids waiting on any + * commands in the subqueue. + * + * Examples: + * + * 0: This waits on all previous work. + * + * NONE: This does not wait for anything on this subqueue. + * + * 1: This waits on the first render command in the submit. + * This only makes sense if there are multiple render commands in the + * same submit. + * + * Barriers only make sense for hardware commands. Synthetic software + * commands to set attachments must pass NONE here. + */ + __u16 vdm_barrier; + + /** + * @cdm_barrier: CDM (compute) command index to wait on. + * + * See @vdm_barrier, and substitute VDM/render for CDM/compute. + */ + __u16 cdm_barrier; +}; + +/** + * struct drm_asahi_submit - Arguments passed to DRM_IOCTL_ASAHI_SUBMIT + */ +struct drm_asahi_submit { + /** + * @syncs: An optional array of drm_asahi_sync. First @in_sync_count + * in-syncs then @out_sync_count out-syncs. + */ + __u64 syncs; + + /** + * @cmdbuf: Pointer to the command buffer to submit. + * + * This is a flat command buffer. By design, it contains no CPU + * pointers, which makes it suitable for a virtgpu wire protocol without + * requiring any serializing/deserializing step. + * + * It consists of a series of commands. Each command begins with a + * fixed-size @drm_asahi_cmd_header and is followed by a variable-length + * payload according to the type and size in the header. + * + * The combined count of "real" hardware commands must be nonzero and at + * most drm_asahi_params_global::max_commands_per_submission. + */ + __u64 cmdbuf; + + /** @flags: Flags for command submission (MBZ) */ + __u32 flags; + + /** @queue_id: The queue ID to be submitted to */ + __u32 queue_id; + + /** + * @in_sync_count: Number of sync objects to wait on before starting + * this job. + */ + __u32 in_sync_count; + + /** + * @out_sync_count: Number of sync objects to signal upon completion of + * this job. + */ + __u32 out_sync_count; + + /** @cmdbuf_size: Command buffer size in bytes */ + __u32 cmdbuf_size; + + /** @pad: MBZ */ + __u32 pad; +}; + +/** + * struct drm_asahi_attachment - Describe an "attachment". + * + * Attachments are any memory written by shaders, notably including render + * target attachments written by the end-of-tile program. This is purely a hint + * about the accessed memory regions. It is optional to specify, which is + * fortunate as it cannot be specified precisely with bindless access anyway. + * But where possible, it's probably a good idea for userspace to include these + * hints, forwarded to the firmware. + * + * This struct is implicitly sized and therefore is not extensible. + */ +struct drm_asahi_attachment { + /** @pointer: Base address of the attachment */ + __u64 pointer; + + /** @size: Size of the attachment in bytes */ + __u64 size; + + /** @pad: MBZ */ + __u32 pad; + + /** @flags: MBZ */ + __u32 flags; +}; + +enum drm_asahi_render_flags { + /** + * @DRM_ASAHI_RENDER_VERTEX_SCRATCH: A vertex stage shader uses scratch + * memory. + */ + DRM_ASAHI_RENDER_VERTEX_SCRATCH = (1U << 0), + + /** + * @DRM_ASAHI_RENDER_PROCESS_EMPTY_TILES: Process even empty tiles. + * This must be set when clearing render targets. + */ + DRM_ASAHI_RENDER_PROCESS_EMPTY_TILES = (1U << 1), + + /** + * @DRM_ASAHI_RENDER_NO_VERTEX_CLUSTERING: Run vertex stage on a single + * cluster (on multi-cluster GPUs) + * + * This harms performance but can workaround certain sync/coherency + * bugs, and therefore is useful for debugging. + */ + DRM_ASAHI_RENDER_NO_VERTEX_CLUSTERING = (1U << 2), + + /** + * @DRM_ASAHI_RENDER_DBIAS_IS_INT: Use integer depth bias formula. + * + * Graphics specifications contain two alternate formulas for depth + * bias, a float formula used with floating-point depth buffers and an + * integer formula using with unorm depth buffers. This flag specifies + * that the integer formula should be used. If omitted, the float + * formula is used instead. + * + * This corresponds to bit 18 of the relevant hardware control register, + * so we match that here for efficiency. + */ + DRM_ASAHI_RENDER_DBIAS_IS_INT = (1U << 18), +}; + +/** + * struct drm_asahi_zls_buffer - Describe a depth or stencil buffer. + * + * These fields correspond to hardware registers in the ZLS (Z Load/Store) unit. + * There are three hardware registers for each field respectively for loads, + * stores, and partial renders. In practice, it makes sense to set all to the + * same values, except in exceptional cases not yet implemented in userspace, so + * we do not duplicate here for simplicity/efficiency. + * + * This struct is embedded in other structs and therefore is not extensible. + */ +struct drm_asahi_zls_buffer { + /** @base: Base address of the buffer */ + __u64 base; + + /** + * @comp_base: If the load buffer is compressed, address of the + * compression metadata section. + */ + __u64 comp_base; + + /** + * @stride: If layered rendering is enabled, the number of bytes + * between each layer of the buffer. + */ + __u32 stride; + + /** + * @comp_stride: If layered rendering is enabled, the number of bytes + * between each layer of the compression metadata. + */ + __u32 comp_stride; +}; + +/** + * struct drm_asahi_timestamp - Describe a timestamp write. + * + * The firmware can optionally write the GPU timestamp at render pass + * granularities, but it needs to be mapped specially via + * DRM_IOCTL_ASAHI_GEM_BIND_OBJECT. This structure therefore describes where to + * write as a handle-offset pair, rather than a GPU address like normal. + * + * This struct is embedded in other structs and therefore is not extensible. + */ +struct drm_asahi_timestamp { + /** + * @handle: Handle of the timestamp buffer, or 0 to skip this + * timestamp. If nonzero, this must equal the value returned in + * drm_asahi_gem_bind_object::object_handle. + */ + __u32 handle; + + /** @offset: Offset to write into the timestamp buffer */ + __u32 offset; +}; + +/** + * struct drm_asahi_timestamps - Describe timestamp writes. + * + * Each operation that can be timestamped, can be timestamped at the start and + * end. Therefore, drm_asahi_timestamp structs always come in pairs, bundled + * together into drm_asahi_timestamps. + * + * This struct is embedded in other structs and therefore is not extensible. + */ +struct drm_asahi_timestamps { + /** @start: Timestamp recorded at the start of the operation */ + struct drm_asahi_timestamp start; + + /** @end: Timestamp recorded at the end of the operation */ + struct drm_asahi_timestamp end; +}; + +/** + * struct drm_asahi_helper_program - Describe helper program configuration. + * + * The helper program is a compute-like kernel required for various hardware + * functionality. Its most important role is dynamically allocating + * scratch/stack memory for individual subgroups, by partitioning a static + * allocation shared for the whole device. It is supplied by userspace via + * drm_asahi_helper_program and internally dispatched by the hardware as needed. + * + * This struct is embedded in other structs and therefore is not extensible. + */ +struct drm_asahi_helper_program { + /** + * @binary: USC address to the helper program binary. This is a tagged + * pointer with configuration in the bottom bits. + */ + __u32 binary; + + /** @cfg: Configuration bits for the helper program. */ + __u32 cfg; + + /** + * @data: Data passed to the helper program. This value is not + * interpreted by the kernel, firmware, or hardware in any way. It is + * simply a sideband for userspace, set with the submit ioctl and read + * via special registers inside the helper program. + * + * In practice, userspace will pass a 64-bit GPU VA here pointing to the + * actual arguments, which presumably don't fit in 64-bits. + */ + __u64 data; +}; + +/** + * struct drm_asahi_bg_eot - Describe a background or end-of-tile program. + * + * The background and end-of-tile programs are dispatched by the hardware at the + * beginning and end of rendering. As the hardware "tilebuffer" is simply local + * memory, these programs are necessary to implement API-level render targets. + * The fragment-like background program is responsible for loading either the + * clear colour or the existing render target contents, while the compute-like + * end-of-tile program stores the tilebuffer contents to memory. + * + * This struct is embedded in other structs and therefore is not extensible. + */ +struct drm_asahi_bg_eot { + /** + * @usc: USC address of the hardware USC words binding resources + * (including images and uniforms) and the program itself. Note this is + * an additional layer of indirection compared to the helper program, + * avoiding the need for a sideband for data. This is a tagged pointer + * with additional configuration in the bottom bits. + */ + __u32 usc; + + /** + * @rsrc_spec: Resource specifier for the program. This is a packed + * hardware data structure describing the required number of registers, + * uniforms, bound textures, and bound samplers. + */ + __u32 rsrc_spec; +}; + +/** + * struct drm_asahi_cmd_render - Command to submit 3D + * + * This command submits a single render pass. The hardware control stream may + * include many draws and subpasses, but within the command, the framebuffer + * dimensions and attachments are fixed. + * + * The hardware requires the firmware to set a large number of Control Registers + * setting up state at render pass granularity before each command rendering 3D. + * The firmware bundles this state into data structures. Unfortunately, we + * cannot expose either any of that directly to userspace, because the + * kernel-firmware ABI is not stable. Although we can guarantee the firmware + * updates in tandem with the kernel, we cannot break old userspace when + * upgrading the firmware and kernel. Therefore, we need to abstract well the + * data structures to avoid tying our hands with future firmwares. + * + * The bulk of drm_asahi_cmd_render therefore consists of values of hardware + * control registers, marshalled via the firmware interface. + * + * The framebuffer/tilebuffer dimensions are also specified here. In addition to + * being passed to the firmware/hardware, the kernel requires these dimensions + * to calculate various essential tiling-related data structures. It is + * unfortunate that our submits are heavier than on vendors with saner + * hardware-software interfaces. The upshot is all of this information is + * readily available to userspace with all current APIs. + * + * It looks odd - but it's not overly burdensome and it ensures we can remain + * compatible with old userspace. + */ +struct drm_asahi_cmd_render { + /** @flags: Combination of drm_asahi_render_flags flags. */ + __u32 flags; + + /** + * @isp_zls_pixels: ISP_ZLS_PIXELS register value. This contains the + * depth/stencil width/height, which may differ from the framebuffer + * width/height. + */ + __u32 isp_zls_pixels; + + /** + * @vdm_ctrl_stream_base: VDM_CTRL_STREAM_BASE register value. GPU + * address to the beginning of the VDM control stream. + */ + __u64 vdm_ctrl_stream_base; + + /** @vertex_helper: Helper program used for the vertex shader */ + struct drm_asahi_helper_program vertex_helper; + + /** @fragment_helper: Helper program used for the fragment shader */ + struct drm_asahi_helper_program fragment_helper; + + /** + * @isp_scissor_base: ISP_SCISSOR_BASE register value. GPU address of an + * array of scissor descriptors indexed in the render pass. + */ + __u64 isp_scissor_base; + + /** + * @isp_dbias_base: ISP_DBIAS_BASE register value. GPU address of an + * array of depth bias values indexed in the render pass. + */ + __u64 isp_dbias_base; + + /** + * @isp_oclqry_base: ISP_OCLQRY_BASE register value. GPU address of an + * array of occlusion query results written by the render pass. + */ + __u64 isp_oclqry_base; + + /** @depth: Depth buffer */ + struct drm_asahi_zls_buffer depth; + + /** @stencil: Stencil buffer */ + struct drm_asahi_zls_buffer stencil; + + /** @zls_ctrl: ZLS_CTRL register value */ + __u64 zls_ctrl; + + /** @ppp_multisamplectl: PPP_MULTISAMPLECTL register value */ + __u64 ppp_multisamplectl; + + /** + * @sampler_heap: Base address of the sampler heap. This heap is used + * for both vertex shaders and fragment shaders. The registers are + * per-stage, but there is no known use case for separate heaps. + */ + __u64 sampler_heap; + + /** @ppp_ctrl: PPP_CTRL register value */ + __u32 ppp_ctrl; + + /** @width_px: Framebuffer width in pixels */ + __u16 width_px; + + /** @height_px: Framebuffer height in pixels */ + __u16 height_px; + + /** @layers: Number of layers in the framebuffer */ + __u16 layers; + + /** @sampler_count: Number of samplers in the sampler heap. */ + __u16 sampler_count; + + /** @utile_width_px: Width of a logical tilebuffer tile in pixels */ + __u8 utile_width_px; + + /** @utile_height_px: Height of a logical tilebuffer tile in pixels */ + __u8 utile_height_px; + + /** @samples: # of samples in the framebuffer. Must be 1, 2, or 4. */ + __u8 samples; + + /** @sample_size_B: # of bytes in the tilebuffer required per sample. */ + __u8 sample_size_B; + + /** + * @isp_merge_upper_x: 32-bit float used in the hardware triangle + * merging. Calculate as: tan(60 deg) * width. + * + * Making these values UAPI avoids requiring floating-point calculations + * in the kernel in the hot path. + */ + __u32 isp_merge_upper_x; + + /** + * @isp_merge_upper_y: 32-bit float. Calculate as: tan(60 deg) * height. + * See @isp_merge_upper_x. + */ + __u32 isp_merge_upper_y; + + /** @bg: Background program run for each tile at the start */ + struct drm_asahi_bg_eot bg; + + /** @eot: End-of-tile program ran for each tile at the end */ + struct drm_asahi_bg_eot eot; + + /** + * @partial_bg: Background program ran at the start of each tile when + * resuming the render pass during a partial render. + */ + struct drm_asahi_bg_eot partial_bg; + + /** + * @partial_eot: End-of-tile program ran at the end of each tile when + * pausing the render pass during a partial render. + */ + struct drm_asahi_bg_eot partial_eot; + + /** + * @isp_bgobjdepth: ISP_BGOBJDEPTH register value. This is the depth + * buffer clear value, encoded in the depth buffer's format: either a + * 32-bit float or a 16-bit unorm (with upper bits zeroed). + */ + __u32 isp_bgobjdepth; + + /** + * @isp_bgobjvals: ISP_BGOBJVALS register value. The bottom 8-bits + * contain the stencil buffer clear value. + */ + __u32 isp_bgobjvals; + + /** @ts_vtx: Timestamps for the vertex portion of the render */ + struct drm_asahi_timestamps ts_vtx; + + /** @ts_frag: Timestamps for the fragment portion of the render */ + struct drm_asahi_timestamps ts_frag; +}; + +/** + * struct drm_asahi_cmd_compute - Command to submit compute + * + * This command submits a control stream consisting of compute dispatches. There + * is essentially no limit on how many compute dispatches may be included in a + * single compute command, although timestamps are at command granularity. + */ +struct drm_asahi_cmd_compute { + /** @flags: MBZ */ + __u32 flags; + + /** @sampler_count: Number of samplers in the sampler heap. */ + __u32 sampler_count; + + /** + * @cdm_ctrl_stream_base: CDM_CTRL_STREAM_BASE register value. GPU + * address to the beginning of the CDM control stream. + */ + __u64 cdm_ctrl_stream_base; + + /** + * @cdm_ctrl_stream_end: GPU base address to the end of the hardware + * control stream. Note this only considers the first contiguous segment + * of the control stream, as the stream might jump elsewhere. + */ + __u64 cdm_ctrl_stream_end; + + /** @sampler_heap: Base address of the sampler heap. */ + __u64 sampler_heap; + + /** @helper: Helper program used for this compute command */ + struct drm_asahi_helper_program helper; + + /** @ts: Timestamps for the compute command */ + struct drm_asahi_timestamps ts; +}; + +/** + * struct drm_asahi_get_time - Arguments passed to DRM_IOCTL_ASAHI_GET_TIME + */ +struct drm_asahi_get_time { + /** @flags: MBZ. */ + __u64 flags; + + /** @gpu_timestamp: On return, the GPU timestamp in nanoseconds. */ + __u64 gpu_timestamp; +}; + +/** + * DRM_IOCTL_ASAHI() - Build an Asahi IOCTL number + * @__access: Access type. Must be R, W or RW. + * @__id: One of the DRM_ASAHI_xxx id. + * @__type: Suffix of the type being passed to the IOCTL. + * + * Don't use this macro directly, use the DRM_IOCTL_ASAHI_xxx + * values instead. + * + * Return: An IOCTL number to be passed to ioctl() from userspace. + */ +#define DRM_IOCTL_ASAHI(__access, __id, __type) \ + DRM_IO ## __access(DRM_COMMAND_BASE + DRM_ASAHI_ ## __id, \ + struct drm_asahi_ ## __type) + +/* Note: this is an enum so that it can be resolved by Rust bindgen. */ +enum { + DRM_IOCTL_ASAHI_GET_PARAMS = DRM_IOCTL_ASAHI(WR, GET_PARAMS, get_params), + DRM_IOCTL_ASAHI_GET_TIME = DRM_IOCTL_ASAHI(WR, GET_TIME, get_time), + DRM_IOCTL_ASAHI_VM_CREATE = DRM_IOCTL_ASAHI(WR, VM_CREATE, vm_create), + DRM_IOCTL_ASAHI_VM_DESTROY = DRM_IOCTL_ASAHI(W, VM_DESTROY, vm_destroy), + DRM_IOCTL_ASAHI_VM_BIND = DRM_IOCTL_ASAHI(W, VM_BIND, vm_bind), + DRM_IOCTL_ASAHI_GEM_CREATE = DRM_IOCTL_ASAHI(WR, GEM_CREATE, gem_create), + DRM_IOCTL_ASAHI_GEM_MMAP_OFFSET = DRM_IOCTL_ASAHI(WR, GEM_MMAP_OFFSET, gem_mmap_offset), + DRM_IOCTL_ASAHI_GEM_BIND_OBJECT = DRM_IOCTL_ASAHI(WR, GEM_BIND_OBJECT, gem_bind_object), + DRM_IOCTL_ASAHI_QUEUE_CREATE = DRM_IOCTL_ASAHI(WR, QUEUE_CREATE, queue_create), + DRM_IOCTL_ASAHI_QUEUE_DESTROY = DRM_IOCTL_ASAHI(W, QUEUE_DESTROY, queue_destroy), + DRM_IOCTL_ASAHI_SUBMIT = DRM_IOCTL_ASAHI(W, SUBMIT, submit), +}; + +#if defined(__cplusplus) +} +#endif + +#endif /* _ASAHI_DRM_H_ */