DRM Driver uAPI

drm/i915 uAPI

uevents generated by i915 on its device node

I915_L3_PARITY_UEVENT - Generated when the driver receives a parity mismatch

event from the GPU L3 cache. Additional information supplied is ROW, BANK, SUBBANK, SLICE of the affected cacheline. Userspace should keep track of these events, and if a specific cache-line seems to have a persistent error, remap it with the L3 remapping tool supplied in intel-gpu-tools. The value supplied with the event is always 1.

I915_ERROR_UEVENT - Generated upon error detection, currently only via

hangcheck. The error detection event is a good indicator of when things began to go badly. The value supplied with the event is a 1 upon error detection, and a 0 upon reset completion, signifying no more error exists. NOTE: Disabling hangcheck or reset via module parameter will cause the related events to not be seen.

I915_RESET_UEVENT - Event is generated just before an attempt to reset the

GPU. The value supplied with the event is always 1. NOTE: Disable reset via module parameter will cause this event to not be seen.

struct i915_user_extension

Base class for defining a chain of extensions

Definition:

struct i915_user_extension {
    __u64 next_extension;
    __u32 name;
    __u32 flags;
    __u32 rsvd[4];
};

Members

next_extension

Pointer to the next struct i915_user_extension, or zero if the end.

name

Name of the extension.

Note that the name here is just some integer.

Also note that the name space for this is not global for the whole driver, but rather its scope/meaning is limited to the specific piece of uAPI which has embedded the struct i915_user_extension.

flags

MBZ

All undefined bits must be zero.

rsvd

MBZ

Reserved for future use; must be zero.

Description

Many interfaces need to grow over time. In most cases we can simply extend the struct and have userspace pass in more data. Another option, as demonstrated by Vulkan's approach to providing extensions for forward and backward compatibility, is to use a list of optional structs to provide those extra details.

The key advantage to using an extension chain is that it allows us to redefine the interface more easily than an ever growing struct of increasing complexity, and for large parts of that interface to be entirely optional. The downside is more pointer chasing; chasing across the __user boundary with pointers encapsulated inside u64.

Example chaining:

struct i915_user_extension ext3 {
        .next_extension = 0, // end
        .name = ...,
};
struct i915_user_extension ext2 {
        .next_extension = (uintptr_t)&ext3,
        .name = ...,
};
struct i915_user_extension ext1 {
        .next_extension = (uintptr_t)&ext2,
        .name = ...,
};

Typically the struct i915_user_extension would be embedded in some uAPI struct, and in this case we would feed it the head of the chain(i.e ext1), which would then apply all of the above extensions.

enum drm_i915_gem_engine_class

uapi engine type enumeration

Constants

I915_ENGINE_CLASS_RENDER

Render engines support instructions used for 3D, Compute (GPGPU), and programmable media workloads. These instructions fetch data and dispatch individual work items to threads that operate in parallel. The threads run small programs (called "kernels" or "shaders") on the GPU's execution units (EUs).

I915_ENGINE_CLASS_COPY

Copy engines (also referred to as "blitters") support instructions that move blocks of data from one location in memory to another, or that fill a specified location of memory with fixed data. Copy engines can perform pre-defined logical or bitwise operations on the source, destination, or pattern data.

I915_ENGINE_CLASS_VIDEO

Video engines (also referred to as "bit stream decode" (BSD) or "vdbox") support instructions that perform fixed-function media decode and encode.

I915_ENGINE_CLASS_VIDEO_ENHANCE

Video enhancement engines (also referred to as "vebox") support instructions related to image enhancement.

I915_ENGINE_CLASS_COMPUTE

Compute engines support a subset of the instructions available on render engines: compute engines support Compute (GPGPU) and programmable media workloads, but do not support the 3D pipeline.

I915_ENGINE_CLASS_INVALID

Placeholder value to represent an invalid engine class assignment.

Description

Different engines serve different roles, and there may be more than one engine serving each role. This enum provides a classification of the role of the engine, which may be used when requesting operations to be performed on a certain subset of engines, or for providing information about that group.

struct i915_engine_class_instance

Engine class/instance identifier

Definition:

struct i915_engine_class_instance {
    __u16 engine_class;
#define I915_ENGINE_CLASS_INVALID_NONE -1;
#define I915_ENGINE_CLASS_INVALID_VIRTUAL -2;
    __u16 engine_instance;
};

Members

engine_class

Engine class from enum drm_i915_gem_engine_class

engine_instance

Engine instance.

Description

There may be more than one engine fulfilling any role within the system. Each engine of a class is given a unique instance number and therefore any engine can be specified by its class:instance tuplet. APIs that allow access to any engine in the system will use struct i915_engine_class_instance for this identification.

perf_events exposed by i915 through /sys/bus/event_sources/drivers/i915

struct drm_i915_getparam

Driver parameter query structure.

Definition:

struct drm_i915_getparam {
    __s32 param;
    int __user *value;
};

Members

param

Driver parameter to query.

value

Address of memory where queried value should be put.

WARNING: Using pointers instead of fixed-size u64 means we need to write compat32 code. Don't repeat this mistake.

type drm_i915_getparam_t

Driver parameter query structure. See struct drm_i915_getparam.

struct drm_i915_gem_mmap_offset

Retrieve an offset so we can mmap this buffer object.

Definition:

struct drm_i915_gem_mmap_offset {
    __u32 handle;
    __u32 pad;
    __u64 offset;
    __u64 flags;
#define I915_MMAP_OFFSET_GTT    0;
#define I915_MMAP_OFFSET_WC     1;
#define I915_MMAP_OFFSET_WB     2;
#define I915_MMAP_OFFSET_UC     3;
#define I915_MMAP_OFFSET_FIXED  4;
    __u64 extensions;
};

Members

handle

Handle for the object being mapped.

pad

Must be zero

offset

The fake offset to use for subsequent mmap call

This is a fixed-size type for 32/64 compatibility.

flags

Flags for extended behaviour.

It is mandatory that one of the MMAP_OFFSET types should be included:

  • I915_MMAP_OFFSET_GTT: Use mmap with the object bound to GTT. (Write-Combined)

  • I915_MMAP_OFFSET_WC: Use Write-Combined caching.

  • I915_MMAP_OFFSET_WB: Use Write-Back caching.

  • I915_MMAP_OFFSET_FIXED: Use object placement to determine caching.

On devices with local memory I915_MMAP_OFFSET_FIXED is the only valid type. On devices without local memory, this caching mode is invalid.

As caching mode when specifying I915_MMAP_OFFSET_FIXED, WC or WB will be used, depending on the object placement on creation. WB will be used when the object can only exist in system memory, WC otherwise.

extensions

Zero-terminated chain of extensions.

No current extensions defined; mbz.

Description

This struct is passed as argument to the DRM_IOCTL_I915_GEM_MMAP_OFFSET ioctl, and is used to retrieve the fake offset to mmap an object specified by handle.

The legacy way of using DRM_IOCTL_I915_GEM_MMAP is removed on gen12+. DRM_IOCTL_I915_GEM_MMAP_GTT is an older supported alias to this struct, but will behave as setting the extensions to 0, and flags to I915_MMAP_OFFSET_GTT.

struct drm_i915_gem_set_domain

Adjust the objects write or read domain, in preparation for accessing the pages via some CPU domain.

Definition:

struct drm_i915_gem_set_domain {
    __u32 handle;
    __u32 read_domains;
    __u32 write_domain;
};

Members

handle

Handle for the object.

read_domains

New read domains.

write_domain

New write domain.

Note that having something in the write domain implies it's in the read domain, and only that read domain.

Description

Specifying a new write or read domain will flush the object out of the previous domain(if required), before then updating the objects domain tracking with the new domain.

Note this might involve waiting for the object first if it is still active on the GPU.

Supported values for read_domains and write_domain:

  • I915_GEM_DOMAIN_WC: Uncached write-combined domain

  • I915_GEM_DOMAIN_CPU: CPU cache domain

  • I915_GEM_DOMAIN_GTT: Mappable aperture domain

All other domains are rejected.

Note that for discrete, starting from DG1, this is no longer supported, and is instead rejected. On such platforms the CPU domain is effectively static, where we also only support a single drm_i915_gem_mmap_offset cache mode, which can't be set explicitly and instead depends on the object placements, as per the below.

Implicit caching rules, starting from DG1:

  • If any of the object placements (see drm_i915_gem_create_ext_memory_regions) contain I915_MEMORY_CLASS_DEVICE then the object will be allocated and mapped as write-combined only.

  • Everything else is always allocated and mapped as write-back, with the guarantee that everything is also coherent with the GPU.

Note that this is likely to change in the future again, where we might need more flexibility on future devices, so making this all explicit as part of a new drm_i915_gem_create_ext extension is probable.

struct drm_i915_gem_exec_fence

An input or output fence for the execbuf ioctl.

Definition:

struct drm_i915_gem_exec_fence {
    __u32 handle;
    __u32 flags;
#define I915_EXEC_FENCE_WAIT            (1<<0);
#define I915_EXEC_FENCE_SIGNAL          (1<<1);
#define __I915_EXEC_FENCE_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_SIGNAL << 1));
};

Members

handle

User's handle for a drm_syncobj to wait on or signal.

flags

Supported flags are:

I915_EXEC_FENCE_WAIT: Wait for the input fence before request submission.

I915_EXEC_FENCE_SIGNAL: Return request completion fence as output

Description

The request will wait for input fence to signal before submission.

The returned output fence will be signaled after the completion of the request.

struct drm_i915_gem_execbuffer_ext_timeline_fences

Timeline fences for execbuf ioctl.

Definition:

struct drm_i915_gem_execbuffer_ext_timeline_fences {
#define DRM_I915_GEM_EXECBUFFER_EXT_TIMELINE_FENCES 0;
    struct i915_user_extension base;
    __u64 fence_count;
    __u64 handles_ptr;
    __u64 values_ptr;
};

Members

base

Extension link. See struct i915_user_extension.

fence_count

Number of elements in the handles_ptr & value_ptr arrays.

handles_ptr

Pointer to an array of struct drm_i915_gem_exec_fence of length fence_count.

values_ptr

Pointer to an array of u64 values of length fence_count. Values must be 0 for a binary drm_syncobj. A Value of 0 for a timeline drm_syncobj is invalid as it turns a drm_syncobj into a binary one.

Description

This structure describes an array of drm_syncobj and associated points for timeline variants of drm_syncobj. It is invalid to append this structure to the execbuf if I915_EXEC_FENCE_ARRAY is set.

struct drm_i915_gem_execbuffer2

Structure for DRM_I915_GEM_EXECBUFFER2 ioctl.

Definition:

struct drm_i915_gem_execbuffer2 {
    __u64 buffers_ptr;
    __u32 buffer_count;
    __u32 batch_start_offset;
    __u32 batch_len;
    __u32 DR1;
    __u32 DR4;
    __u32 num_cliprects;
    __u64 cliprects_ptr;
    __u64 flags;
#define I915_EXEC_RING_MASK              (0x3f);
#define I915_EXEC_DEFAULT                (0<<0);
#define I915_EXEC_RENDER                 (1<<0);
#define I915_EXEC_BSD                    (2<<0);
#define I915_EXEC_BLT                    (3<<0);
#define I915_EXEC_VEBOX                  (4<<0);
#define I915_EXEC_CONSTANTS_MASK        (3<<6);
#define I915_EXEC_CONSTANTS_REL_GENERAL (0<<6) ;
#define I915_EXEC_CONSTANTS_ABSOLUTE    (1<<6);
#define I915_EXEC_CONSTANTS_REL_SURFACE (2<<6) ;
#define I915_EXEC_GEN7_SOL_RESET        (1<<8);
#define I915_EXEC_SECURE                (1<<9);
#define I915_EXEC_IS_PINNED             (1<<10);
#define I915_EXEC_NO_RELOC              (1<<11);
#define I915_EXEC_HANDLE_LUT            (1<<12);
#define I915_EXEC_BSD_SHIFT      (13);
#define I915_EXEC_BSD_MASK       (3 << I915_EXEC_BSD_SHIFT);
#define I915_EXEC_BSD_DEFAULT    (0 << I915_EXEC_BSD_SHIFT);
#define I915_EXEC_BSD_RING1      (1 << I915_EXEC_BSD_SHIFT);
#define I915_EXEC_BSD_RING2      (2 << I915_EXEC_BSD_SHIFT);
#define I915_EXEC_RESOURCE_STREAMER     (1<<15);
#define I915_EXEC_FENCE_IN              (1<<16);
#define I915_EXEC_FENCE_OUT             (1<<17);
#define I915_EXEC_BATCH_FIRST           (1<<18);
#define I915_EXEC_FENCE_ARRAY   (1<<19);
#define I915_EXEC_FENCE_SUBMIT          (1 << 20);
#define I915_EXEC_USE_EXTENSIONS        (1 << 21);
#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_USE_EXTENSIONS << 1));
    __u64 rsvd1;
    __u64 rsvd2;
};

Members

buffers_ptr

Pointer to a list of gem_exec_object2 structs

buffer_count

Number of elements in buffers_ptr array

batch_start_offset

Offset in the batchbuffer to start execution from.

batch_len

Length in bytes of the batch buffer, starting from the batch_start_offset. If 0, length is assumed to be the batch buffer object size.

DR1

deprecated

DR4

deprecated

num_cliprects

See cliprects_ptr

cliprects_ptr

Kernel clipping was a DRI1 misfeature.

It is invalid to use this field if I915_EXEC_FENCE_ARRAY or I915_EXEC_USE_EXTENSIONS flags are not set.

If I915_EXEC_FENCE_ARRAY is set, then this is a pointer to an array of drm_i915_gem_exec_fence and num_cliprects is the length of the array.

If I915_EXEC_USE_EXTENSIONS is set, then this is a pointer to a single i915_user_extension and num_cliprects is 0.

flags

Execbuf flags

rsvd1

Context id

rsvd2

in and out sync_file file descriptors.

When I915_EXEC_FENCE_IN or I915_EXEC_FENCE_SUBMIT flag is set, the lower 32 bits of this field will have the in sync_file fd (input).

When I915_EXEC_FENCE_OUT flag is set, the upper 32 bits of this field will have the out sync_file fd (output).

struct drm_i915_gem_caching

Set or get the caching for given object handle.

Definition:

struct drm_i915_gem_caching {
    __u32 handle;
#define I915_CACHING_NONE               0;
#define I915_CACHING_CACHED             1;
#define I915_CACHING_DISPLAY            2;
    __u32 caching;
};

Members

handle

Handle of the buffer to set/get the caching level.

caching

The GTT caching level to apply or possible return value.

The supported caching values:

I915_CACHING_NONE:

GPU access is not coherent with CPU caches. Default for machines without an LLC. This means manual flushing might be needed, if we want GPU access to be coherent.

I915_CACHING_CACHED:

GPU access is coherent with CPU caches and furthermore the data is cached in last-level caches shared between CPU cores and the GPU GT.

I915_CACHING_DISPLAY:

Special GPU caching mode which is coherent with the scanout engines. Transparently falls back to I915_CACHING_NONE on platforms where no special cache mode (like write-through or gfdt flushing) is available. The kernel automatically sets this mode when using a buffer as a scanout target. Userspace can manually set this mode to avoid a costly stall and clflush in the hotpath of drawing the first frame.

Description

Allow userspace to control the GTT caching bits for a given object when the object is later mapped through the ppGTT(or GGTT on older platforms lacking ppGTT support, or if the object is used for scanout). Note that this might require unbinding the object from the GTT first, if its current caching value doesn't match.

Note that this all changes on discrete platforms, starting from DG1, the set/get caching is no longer supported, and is now rejected. Instead the CPU caching attributes(WB vs WC) will become an immutable creation time property for the object, along with the GTT caching level. For now we don't expose any new uAPI for this, instead on DG1 this is all implicit, although this largely shouldn't matter since DG1 is coherent by default(without any way of controlling it).

Implicit caching rules, starting from DG1:

  • If any of the object placements (see drm_i915_gem_create_ext_memory_regions) contain I915_MEMORY_CLASS_DEVICE then the object will be allocated and mapped as write-combined only.

  • Everything else is always allocated and mapped as write-back, with the guarantee that everything is also coherent with the GPU.

Note that this is likely to change in the future again, where we might need more flexibility on future devices, so making this all explicit as part of a new drm_i915_gem_create_ext extension is probable.

Side note: Part of the reason for this is that changing the at-allocation-time CPU caching attributes for the pages might be required(and is expensive) if we need to then CPU map the pages later with different caching attributes. This inconsistent caching behaviour, while supported on x86, is not universally supported on other architectures. So for simplicity we opt for setting everything at creation time, whilst also making it immutable, on discrete platforms.

struct drm_i915_gem_context_create_ext

Structure for creating contexts.

Definition:

struct drm_i915_gem_context_create_ext {
    __u32 ctx_id;
    __u32 flags;
#define I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS        (1u << 0);
#define I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE       (1u << 1);
#define I915_CONTEXT_CREATE_FLAGS_UNKNOWN       (-(I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE << 1));
    __u64 extensions;
#define I915_CONTEXT_CREATE_EXT_SETPARAM 0;
#define I915_CONTEXT_CREATE_EXT_CLONE 1;
};

Members

ctx_id

Id of the created context (output)

flags

Supported flags are:

I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS:

Extensions may be appended to this structure and driver must check for those. See extensions.

I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE

Created context will have single timeline.

extensions

Zero-terminated chain of extensions.

I915_CONTEXT_CREATE_EXT_SETPARAM: Context parameter to set or query during context creation. See struct drm_i915_gem_context_create_ext_setparam.

I915_CONTEXT_CREATE_EXT_CLONE: This extension has been removed. On the off chance someone somewhere has attempted to use it, never re-use this extension number.

struct drm_i915_gem_context_param

Context parameter to set or query.

Definition:

struct drm_i915_gem_context_param {
    __u32 ctx_id;
    __u32 size;
    __u64 param;
#define I915_CONTEXT_PARAM_BAN_PERIOD   0x1;
#define I915_CONTEXT_PARAM_NO_ZEROMAP   0x2;
#define I915_CONTEXT_PARAM_GTT_SIZE     0x3;
#define I915_CONTEXT_PARAM_NO_ERROR_CAPTURE     0x4;
#define I915_CONTEXT_PARAM_BANNABLE     0x5;
#define I915_CONTEXT_PARAM_PRIORITY     0x6;
#define I915_CONTEXT_MAX_USER_PRIORITY        1023 ;
#define I915_CONTEXT_DEFAULT_PRIORITY         0;
#define I915_CONTEXT_MIN_USER_PRIORITY        -1023 ;
#define I915_CONTEXT_PARAM_SSEU         0x7;
#define I915_CONTEXT_PARAM_RECOVERABLE  0x8;
#define I915_CONTEXT_PARAM_VM           0x9;
#define I915_CONTEXT_PARAM_ENGINES      0xa;
#define I915_CONTEXT_PARAM_PERSISTENCE  0xb;
#define I915_CONTEXT_PARAM_RINGSIZE     0xc;
#define I915_CONTEXT_PARAM_PROTECTED_CONTENT    0xd;
    __u64 value;
};

Members

ctx_id

Context id

size

Size of the parameter value

param

Parameter to set or query

value

Context parameter value to be set or queried

Virtual Engine uAPI

Virtual engine is a concept where userspace is able to configure a set of physical engines, submit a batch buffer, and let the driver execute it on any engine from the set as it sees fit.

This is primarily useful on parts which have multiple instances of a same class engine, like for example GT3+ Skylake parts with their two VCS engines.

For instance userspace can enumerate all engines of a certain class using the previously described Engine Discovery uAPI. After that userspace can create a GEM context with a placeholder slot for the virtual engine (using I915_ENGINE_CLASS_INVALID and I915_ENGINE_CLASS_INVALID_NONE for class and instance respectively) and finally using the I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE extension place a virtual engine in the same reserved slot.

Example of creating a virtual engine and submitting a batch buffer to it:

I915_DEFINE_CONTEXT_ENGINES_LOAD_BALANCE(virtual, 2) = {
        .base.name = I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE,
        .engine_index = 0, // Place this virtual engine into engine map slot 0
        .num_siblings = 2,
        .engines = { { I915_ENGINE_CLASS_VIDEO, 0 },
                     { I915_ENGINE_CLASS_VIDEO, 1 }, },
};
I915_DEFINE_CONTEXT_PARAM_ENGINES(engines, 1) = {
        .engines = { { I915_ENGINE_CLASS_INVALID,
                       I915_ENGINE_CLASS_INVALID_NONE } },
        .extensions = to_user_pointer(&virtual), // Chains after load_balance extension
};
struct drm_i915_gem_context_create_ext_setparam p_engines = {
        .base = {
                .name = I915_CONTEXT_CREATE_EXT_SETPARAM,
        },
        .param = {
                .param = I915_CONTEXT_PARAM_ENGINES,
                .value = to_user_pointer(&engines),
                .size = sizeof(engines),
        },
};
struct drm_i915_gem_context_create_ext create = {
        .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS,
        .extensions = to_user_pointer(&p_engines);
};

ctx_id = gem_context_create_ext(drm_fd, &create);

// Now we have created a GEM context with its engine map containing a
// single virtual engine. Submissions to this slot can go either to
// vcs0 or vcs1, depending on the load balancing algorithm used inside
// the driver. The load balancing is dynamic from one batch buffer to
// another and transparent to userspace.

...
execbuf.rsvd1 = ctx_id;
execbuf.flags = 0; // Submits to index 0 which is the virtual engine
gem_execbuf(drm_fd, &execbuf);
struct i915_context_engines_parallel_submit

Configure engine for parallel submission.

Definition:

struct i915_context_engines_parallel_submit {
    struct i915_user_extension base;
    __u16 engine_index;
    __u16 width;
    __u16 num_siblings;
    __u16 mbz16;
    __u64 flags;
    __u64 mbz64[3];
    struct i915_engine_class_instance engines[];
};

Members

base

base user extension.

engine_index

slot for parallel engine

width

number of contexts per parallel engine or in other words the number of batches in each submission

num_siblings

number of siblings per context or in other words the number of possible placements for each submission

mbz16

reserved for future use; must be zero

flags

all undefined flags must be zero, currently not defined flags

mbz64

reserved for future use; must be zero

engines

2-d array of engine instances to configure parallel engine

length = width (i) * num_siblings (j) index = j + i * num_siblings

Description

Setup a slot in the context engine map to allow multiple BBs to be submitted in a single execbuf IOCTL. Those BBs will then be scheduled to run on the GPU in parallel. Multiple hardware contexts are created internally in the i915 to run these BBs. Once a slot is configured for N BBs only N BBs can be submitted in each execbuf IOCTL and this is implicit behavior e.g. The user doesn't tell the execbuf IOCTL there are N BBs, the execbuf IOCTL knows how many BBs there are based on the slot's configuration. The N BBs are the last N buffer objects or first N if I915_EXEC_BATCH_FIRST is set.

The default placement behavior is to create implicit bonds between each context if each context maps to more than 1 physical engine (e.g. context is a virtual engine). Also we only allow contexts of same engine class and these contexts must be in logically contiguous order. Examples of the placement behavior are described below. Lastly, the default is to not allow BBs to be preempted mid-batch. Rather insert coordinated preemption points on all hardware contexts between each set of BBs. Flags could be added in the future to change both of these default behaviors.

Returns -EINVAL if hardware context placement configuration is invalid or if the placement configuration isn't supported on the platform / submission interface. Returns -ENODEV if extension isn't supported on the platform / submission interface.

Examples syntax:
CS[X] = generic engine of same class, logical instance X
INVALID = I915_ENGINE_CLASS_INVALID, I915_ENGINE_CLASS_INVALID_NONE

Example 1 pseudo code:
set_engines(INVALID)
set_parallel(engine_index=0, width=2, num_siblings=1,
             engines=CS[0],CS[1])

Results in the following valid placement:
CS[0], CS[1]

Example 2 pseudo code:
set_engines(INVALID)
set_parallel(engine_index=0, width=2, num_siblings=2,
             engines=CS[0],CS[2],CS[1],CS[3])

Results in the following valid placements:
CS[0], CS[1]
CS[2], CS[3]

This can be thought of as two virtual engines, each containing two
engines thereby making a 2D array. However, there are bonds tying the
entries together and placing restrictions on how they can be scheduled.
Specifically, the scheduler can choose only vertical columns from the 2D
array. That is, CS[0] is bonded to CS[1] and CS[2] to CS[3]. So if the
scheduler wants to submit to CS[0], it must also choose CS[1] and vice
versa. Same for CS[2] requires also using CS[3].
VE[0] = CS[0], CS[2]
VE[1] = CS[1], CS[3]

Example 3 pseudo code:
set_engines(INVALID)
set_parallel(engine_index=0, width=2, num_siblings=2,
             engines=CS[0],CS[1],CS[1],CS[3])

Results in the following valid and invalid placements:
CS[0], CS[1]
CS[1], CS[3] - Not logically contiguous, return -EINVAL

Context Engine Map uAPI

Context engine map is a new way of addressing engines when submitting batch- buffers, replacing the existing way of using identifiers like I915_EXEC_BLT inside the flags field of struct drm_i915_gem_execbuffer2.

To use it created GEM contexts need to be configured with a list of engines the user is intending to submit to. This is accomplished using the I915_CONTEXT_PARAM_ENGINES parameter and struct i915_context_param_engines.

For such contexts the I915_EXEC_RING_MASK field becomes an index into the configured map.

Example of creating such context and submitting against it:

I915_DEFINE_CONTEXT_PARAM_ENGINES(engines, 2) = {
        .engines = { { I915_ENGINE_CLASS_RENDER, 0 },
                     { I915_ENGINE_CLASS_COPY, 0 } }
};
struct drm_i915_gem_context_create_ext_setparam p_engines = {
        .base = {
                .name = I915_CONTEXT_CREATE_EXT_SETPARAM,
        },
        .param = {
                .param = I915_CONTEXT_PARAM_ENGINES,
                .value = to_user_pointer(&engines),
                .size = sizeof(engines),
        },
};
struct drm_i915_gem_context_create_ext create = {
        .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS,
        .extensions = to_user_pointer(&p_engines);
};

ctx_id = gem_context_create_ext(drm_fd, &create);

// We have now created a GEM context with two engines in the map:
// Index 0 points to rcs0 while index 1 points to bcs0. Other engines
// will not be accessible from this context.

...
execbuf.rsvd1 = ctx_id;
execbuf.flags = 0; // Submits to index 0, which is rcs0 for this context
gem_execbuf(drm_fd, &execbuf);

...
execbuf.rsvd1 = ctx_id;
execbuf.flags = 1; // Submits to index 0, which is bcs0 for this context
gem_execbuf(drm_fd, &execbuf);
struct drm_i915_gem_context_create_ext_setparam

Context parameter to set or query during context creation.

Definition:

struct drm_i915_gem_context_create_ext_setparam {
    struct i915_user_extension base;
    struct drm_i915_gem_context_param param;
};

Members

base

Extension link. See struct i915_user_extension.

param

Context parameter to set or query. See struct drm_i915_gem_context_param.

struct drm_i915_gem_vm_control

Structure to create or destroy VM.

Definition:

struct drm_i915_gem_vm_control {
    __u64 extensions;
    __u32 flags;
    __u32 vm_id;
};

Members

extensions

Zero-terminated chain of extensions.

flags

reserved for future usage, currently MBZ

vm_id

Id of the VM created or to be destroyed

Description

DRM_I915_GEM_VM_CREATE -

Create a new virtual memory address space (ppGTT) for use within a context on the same file. Extensions can be provided to configure exactly how the address space is setup upon creation.

The id of new VM (bound to the fd) for use with I915_CONTEXT_PARAM_VM is returned in the outparam id.

An extension chain maybe provided, starting with extensions, and terminated by the next_extension being 0. Currently, no extensions are defined.

DRM_I915_GEM_VM_DESTROY -

Destroys a previously created VM id, specified in vm_id.

No extensions or flags are allowed currently, and so must be zero.

struct drm_i915_gem_userptr

Create GEM object from user allocated memory.

Definition:

struct drm_i915_gem_userptr {
    __u64 user_ptr;
    __u64 user_size;
    __u32 flags;
#define I915_USERPTR_READ_ONLY 0x1;
#define I915_USERPTR_PROBE 0x2;
#define I915_USERPTR_UNSYNCHRONIZED 0x80000000;
    __u32 handle;
};

Members

user_ptr

The pointer to the allocated memory.

Needs to be aligned to PAGE_SIZE.

user_size

The size in bytes for the allocated memory. This will also become the object size.

Needs to be aligned to PAGE_SIZE, and should be at least PAGE_SIZE, or larger.

flags

Supported flags:

I915_USERPTR_READ_ONLY:

Mark the object as readonly, this also means GPU access can only be readonly. This is only supported on HW which supports readonly access through the GTT. If the HW can't support readonly access, an error is returned.

I915_USERPTR_PROBE:

Probe the provided user_ptr range and validate that the user_ptr is indeed pointing to normal memory and that the range is also valid. For example if some garbage address is given to the kernel, then this should complain.

Returns -EFAULT if the probe failed.

Note that this doesn't populate the backing pages, and also doesn't guarantee that the object will remain valid when the object is eventually used.

The kernel supports this feature if I915_PARAM_HAS_USERPTR_PROBE returns a non-zero value.

I915_USERPTR_UNSYNCHRONIZED:

NOT USED. Setting this flag will result in an error.

handle

Returned handle for the object.

Object handles are nonzero.

Description

Userptr objects have several restrictions on what ioctls can be used with the object handle.

struct drm_i915_perf_oa_config

Definition:

struct drm_i915_perf_oa_config {
    char uuid[36];
    __u32 n_mux_regs;
    __u32 n_boolean_regs;
    __u32 n_flex_regs;
    __u64 mux_regs_ptr;
    __u64 boolean_regs_ptr;
    __u64 flex_regs_ptr;
};

Members

uuid

String formatted like "%08x-%04x-%04x-%04x-%012x"

n_mux_regs

Number of mux regs in mux_regs_ptr.

n_boolean_regs

Number of boolean regs in boolean_regs_ptr.

n_flex_regs

Number of flex regs in flex_regs_ptr.

mux_regs_ptr

Pointer to tuples of u32 values (register address, value) for mux registers. Expected length of buffer is (2 * sizeof(u32) * n_mux_regs).

boolean_regs_ptr

Pointer to tuples of u32 values (register address, value) for mux registers. Expected length of buffer is (2 * sizeof(u32) * n_boolean_regs).

flex_regs_ptr

Pointer to tuples of u32 values (register address, value) for mux registers. Expected length of buffer is (2 * sizeof(u32) * n_flex_regs).

Description

Structure to upload perf dynamic configuration into the kernel.

struct drm_i915_query_item

An individual query for the kernel to process.

Definition:

struct drm_i915_query_item {
    __u64 query_id;
#define DRM_I915_QUERY_TOPOLOGY_INFO            1;
#define DRM_I915_QUERY_ENGINE_INFO              2;
#define DRM_I915_QUERY_PERF_CONFIG              3;
#define DRM_I915_QUERY_MEMORY_REGIONS           4;
#define DRM_I915_QUERY_HWCONFIG_BLOB            5;
#define DRM_I915_QUERY_GEOMETRY_SUBSLICES       6;
    __s32 length;
    __u32 flags;
#define DRM_I915_QUERY_PERF_CONFIG_LIST          1;
#define DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID 2;
#define DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_ID   3;
    __u64 data_ptr;
};

Members

query_id
The id for this query. Currently accepted query IDs are:
length

When set to zero by userspace, this is filled with the size of the data to be written at the data_ptr pointer. The kernel sets this value to a negative value to signal an error on a particular query item.

flags

When query_id == DRM_I915_QUERY_TOPOLOGY_INFO, must be 0.

When query_id == DRM_I915_QUERY_PERF_CONFIG, must be one of the following:

  • DRM_I915_QUERY_PERF_CONFIG_LIST

  • DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID

  • DRM_I915_QUERY_PERF_CONFIG_FOR_UUID

When query_id == DRM_I915_QUERY_GEOMETRY_SUBSLICES must contain a struct i915_engine_class_instance that references a render engine.

data_ptr

Data will be written at the location pointed by data_ptr when the value of length matches the length of the data to be written by the kernel.

Description

The behaviour is determined by the query_id. Note that exactly what data_ptr is also depends on the specific query_id.

struct drm_i915_query

Supply an array of struct drm_i915_query_item for the kernel to fill out.

Definition:

struct drm_i915_query {
    __u32 num_items;
    __u32 flags;
    __u64 items_ptr;
};

Members

num_items

The number of elements in the items_ptr array

flags

Unused for now. Must be cleared to zero.

items_ptr

Pointer to an array of struct drm_i915_query_item. The number of array elements is num_items.

Description

Note that this is generally a two step process for each struct drm_i915_query_item in the array:

  1. Call the DRM_IOCTL_I915_QUERY, giving it our array of struct drm_i915_query_item, with drm_i915_query_item.length set to zero. The kernel will then fill in the size, in bytes, which tells userspace how memory it needs to allocate for the blob(say for an array of properties).

  2. Next we call DRM_IOCTL_I915_QUERY again, this time with the drm_i915_query_item.data_ptr equal to our newly allocated blob. Note that the drm_i915_query_item.length should still be the same as what the kernel previously set. At this point the kernel can fill in the blob.

Note that for some query items it can make sense for userspace to just pass in a buffer/blob equal to or larger than the required size. In this case only a single ioctl call is needed. For some smaller query items this can work quite well.

struct drm_i915_query_topology_info

Definition:

struct drm_i915_query_topology_info {
    __u16 flags;
    __u16 max_slices;
    __u16 max_subslices;
    __u16 max_eus_per_subslice;
    __u16 subslice_offset;
    __u16 subslice_stride;
    __u16 eu_offset;
    __u16 eu_stride;
    __u8 data[];
};

Members

flags

Unused for now. Must be cleared to zero.

max_slices

The number of bits used to express the slice mask.

max_subslices

The number of bits used to express the subslice mask.

max_eus_per_subslice

The number of bits in the EU mask that correspond to a single subslice's EUs.

subslice_offset

Offset in data[] at which the subslice masks are stored.

subslice_stride

Stride at which each of the subslice masks for each slice are stored.

eu_offset

Offset in data[] at which the EU masks are stored.

eu_stride

Stride at which each of the EU masks for each subslice are stored.

data

Contains 3 pieces of information :

  • The slice mask with one bit per slice telling whether a slice is available. The availability of slice X can be queried with the following formula :

    (data[X / 8] >> (X % 8)) & 1
    

    Starting with Xe_HP platforms, Intel hardware no longer has traditional slices so i915 will always report a single slice (hardcoded slicemask = 0x1) which contains all of the platform's subslices. I.e., the mask here does not reflect any of the newer hardware concepts such as "gslices" or "cslices" since userspace is capable of inferring those from the subslice mask.

  • The subslice mask for each slice with one bit per subslice telling whether a subslice is available. Starting with Gen12 we use the term "subslice" to refer to what the hardware documentation describes as a "dual-subslices." The availability of subslice Y in slice X can be queried with the following formula :

    (data[subslice_offset + X * subslice_stride + Y / 8] >> (Y % 8)) & 1
    
  • The EU mask for each subslice in each slice, with one bit per EU telling whether an EU is available. The availability of EU Z in subslice Y in slice X can be queried with the following formula :

    (data[eu_offset +
          (X * max_subslices + Y) * eu_stride +
          Z / 8
     ] >> (Z % 8)) & 1
    

Description

Describes slice/subslice/EU information queried by DRM_I915_QUERY_TOPOLOGY_INFO

Engine Discovery uAPI

Engine discovery uAPI is a way of enumerating physical engines present in a GPU associated with an open i915 DRM file descriptor. This supersedes the old way of using DRM_IOCTL_I915_GETPARAM and engine identifiers like I915_PARAM_HAS_BLT.

The need for this interface came starting with Icelake and newer GPUs, which started to establish a pattern of having multiple engines of a same class, where not all instances were always completely functionally equivalent.

Entry point for this uapi is DRM_IOCTL_I915_QUERY with the DRM_I915_QUERY_ENGINE_INFO as the queried item id.

Example for getting the list of engines:

struct drm_i915_query_engine_info *info;
struct drm_i915_query_item item = {
        .query_id = DRM_I915_QUERY_ENGINE_INFO;
};
struct drm_i915_query query = {
        .num_items = 1,
        .items_ptr = (uintptr_t)&item,
};
int err, i;

// First query the size of the blob we need, this needs to be large
// enough to hold our array of engines. The kernel will fill out the
// item.length for us, which is the number of bytes we need.
//
// Alternatively a large buffer can be allocated straightaway enabling
// querying in one pass, in which case item.length should contain the
// length of the provided buffer.
err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query);
if (err) ...

info = calloc(1, item.length);
// Now that we allocated the required number of bytes, we call the ioctl
// again, this time with the data_ptr pointing to our newly allocated
// blob, which the kernel can then populate with info on all engines.
item.data_ptr = (uintptr_t)&info;

err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query);
if (err) ...

// We can now access each engine in the array
for (i = 0; i < info->num_engines; i++) {
        struct drm_i915_engine_info einfo = info->engines[i];
        u16 class = einfo.engine.class;
        u16 instance = einfo.engine.instance;
        ....
}

free(info);

Each of the enumerated engines, apart from being defined by its class and instance (see struct i915_engine_class_instance), also can have flags and capabilities defined as documented in i915_drm.h.

For instance video engines which support HEVC encoding will have the I915_VIDEO_CLASS_CAPABILITY_HEVC capability bit set.

Engine discovery only fully comes to its own when combined with the new way of addressing engines when submitting batch buffers using contexts with engine maps configured.

struct drm_i915_engine_info

Definition:

struct drm_i915_engine_info {
    struct i915_engine_class_instance engine;
    __u32 rsvd0;
    __u64 flags;
#define I915_ENGINE_INFO_HAS_LOGICAL_INSTANCE           (1 << 0);
    __u64 capabilities;
#define I915_VIDEO_CLASS_CAPABILITY_HEVC                (1 << 0);
#define I915_VIDEO_AND_ENHANCE_CLASS_CAPABILITY_SFC     (1 << 1);
    __u16 logical_instance;
    __u16 rsvd1[3];
    __u64 rsvd2[3];
};

Members

engine

Engine class and instance.

rsvd0

Reserved field.

flags

Engine flags.

capabilities

Capabilities of this engine.

logical_instance

Logical instance of engine

rsvd1

Reserved fields.

rsvd2

Reserved fields.

Description

Describes one engine and its capabilities as known to the driver.

struct drm_i915_query_engine_info

Definition:

struct drm_i915_query_engine_info {
    __u32 num_engines;
    __u32 rsvd[3];
    struct drm_i915_engine_info engines[];
};

Members

num_engines

Number of struct drm_i915_engine_info structs following.

rsvd

MBZ

engines

Marker for drm_i915_engine_info structures.

Description

Engine info query enumerates all engines known to the driver by filling in an array of struct drm_i915_engine_info structures.

struct drm_i915_query_perf_config

Definition:

struct drm_i915_query_perf_config {
    union {
        __u64 n_configs;
        __u64 config;
        char uuid[36];
    };
    __u32 flags;
    __u8 data[];
};

Members

{unnamed_union}

anonymous

n_configs

When drm_i915_query_item.flags == DRM_I915_QUERY_PERF_CONFIG_LIST, i915 sets this fields to the number of configurations available.

config

When drm_i915_query_item.flags == DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_ID, i915 will use the value in this field as configuration identifier to decide what data to write into config_ptr.

uuid

When drm_i915_query_item.flags == DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID, i915 will use the value in this field as configuration identifier to decide what data to write into config_ptr.

String formatted like "08x-````04x-````04x-````04x-````012x"

flags

Unused for now. Must be cleared to zero.

data

When drm_i915_query_item.flags == DRM_I915_QUERY_PERF_CONFIG_LIST, i915 will write an array of __u64 of configuration identifiers.

When drm_i915_query_item.flags == DRM_I915_QUERY_PERF_CONFIG_DATA, i915 will write a struct drm_i915_perf_oa_config. If the following fields of struct drm_i915_perf_oa_config are not set to 0, i915 will write into the associated pointers the values of submitted when the configuration was created :

Description

Data written by the kernel with query DRM_I915_QUERY_PERF_CONFIG and DRM_I915_QUERY_GEOMETRY_SUBSLICES.

enum drm_i915_gem_memory_class

Supported memory classes

Constants

I915_MEMORY_CLASS_SYSTEM

System memory

I915_MEMORY_CLASS_DEVICE

Device local-memory

struct drm_i915_gem_memory_class_instance

Identify particular memory region

Definition:

struct drm_i915_gem_memory_class_instance {
    __u16 memory_class;
    __u16 memory_instance;
};

Members

memory_class

See enum drm_i915_gem_memory_class

memory_instance

Which instance

struct drm_i915_memory_region_info

Describes one region as known to the driver.

Definition:

struct drm_i915_memory_region_info {
    struct drm_i915_gem_memory_class_instance region;
    __u32 rsvd0;
    __u64 probed_size;
    __u64 unallocated_size;
    union {
        __u64 rsvd1[8];
        struct {
            __u64 probed_cpu_visible_size;
            __u64 unallocated_cpu_visible_size;
        };
    };
};

Members

region

The class:instance pair encoding

rsvd0

MBZ

probed_size

Memory probed by the driver

Note that it should not be possible to ever encounter a zero value here, also note that no current region type will ever return -1 here. Although for future region types, this might be a possibility. The same applies to the other size fields.

unallocated_size

Estimate of memory remaining

Requires CAP_PERFMON or CAP_SYS_ADMIN to get reliable accounting. Without this (or if this is an older kernel) the value here will always equal the probed_size. Note this is only currently tracked for I915_MEMORY_CLASS_DEVICE regions (for other types the value here will always equal the probed_size).

{unnamed_union}

anonymous

rsvd1

MBZ

{unnamed_struct}

anonymous

probed_cpu_visible_size

Memory probed by the driver that is CPU accessible.

This will be always be <= probed_size, and the remainder (if there is any) will not be CPU accessible.

On systems without small BAR, the probed_size will always equal the probed_cpu_visible_size, since all of it will be CPU accessible.

Note this is only tracked for I915_MEMORY_CLASS_DEVICE regions (for other types the value here will always equal the probed_size).

Note that if the value returned here is zero, then this must be an old kernel which lacks the relevant small-bar uAPI support (including I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS), but on such systems we should never actually end up with a small BAR configuration, assuming we are able to load the kernel module. Hence it should be safe to treat this the same as when probed_cpu_visible_size == probed_size.

unallocated_cpu_visible_size

Estimate of CPU visible memory remaining.

Note this is only tracked for I915_MEMORY_CLASS_DEVICE regions (for other types the value here will always equal the probed_cpu_visible_size).

Requires CAP_PERFMON or CAP_SYS_ADMIN to get reliable accounting. Without this the value here will always equal the probed_cpu_visible_size. Note this is only currently tracked for I915_MEMORY_CLASS_DEVICE regions (for other types the value here will also always equal the probed_cpu_visible_size).

If this is an older kernel the value here will be zero, see also probed_cpu_visible_size.

Description

Note this is using both struct drm_i915_query_item and struct drm_i915_query. For this new query we are adding the new query id DRM_I915_QUERY_MEMORY_REGIONS at drm_i915_query_item.query_id.

struct drm_i915_query_memory_regions

Definition:

struct drm_i915_query_memory_regions {
    __u32 num_regions;
    __u32 rsvd[3];
    struct drm_i915_memory_region_info regions[];
};

Members

num_regions

Number of supported regions

rsvd

MBZ

regions

Info about each supported region

Description

The region info query enumerates all regions known to the driver by filling in an array of struct drm_i915_memory_region_info structures.

Example for getting the list of supported regions:

struct drm_i915_query_memory_regions *info;
struct drm_i915_query_item item = {
        .query_id = DRM_I915_QUERY_MEMORY_REGIONS;
};
struct drm_i915_query query = {
        .num_items = 1,
        .items_ptr = (uintptr_t)&item,
};
int err, i;

// First query the size of the blob we need, this needs to be large
// enough to hold our array of regions. The kernel will fill out the
// item.length for us, which is the number of bytes we need.
err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query);
if (err) ...

info = calloc(1, item.length);
// Now that we allocated the required number of bytes, we call the ioctl
// again, this time with the data_ptr pointing to our newly allocated
// blob, which the kernel can then populate with the all the region info.
item.data_ptr = (uintptr_t)&info,

err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query);
if (err) ...

// We can now access each region in the array
for (i = 0; i < info->num_regions; i++) {
        struct drm_i915_memory_region_info mr = info->regions[i];
        u16 class = mr.region.class;
        u16 instance = mr.region.instance;

        ....
}

free(info);

GuC HWCONFIG blob uAPI

The GuC produces a blob with information about the current device. i915 reads this blob from GuC and makes it available via this uAPI.

The format and meaning of the blob content are documented in the Programmer's Reference Manual.

struct drm_i915_gem_create_ext

Existing gem_create behaviour, with added extension support using struct i915_user_extension.

Definition:

struct drm_i915_gem_create_ext {
    __u64 size;
    __u32 handle;
#define I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS (1 << 0);
    __u32 flags;
#define I915_GEM_CREATE_EXT_MEMORY_REGIONS 0;
#define I915_GEM_CREATE_EXT_PROTECTED_CONTENT 1;
#define I915_GEM_CREATE_EXT_SET_PAT 2;
    __u64 extensions;
};

Members

size

Requested size for the object.

The (page-aligned) allocated size for the object will be returned.

On platforms like DG2/ATS the kernel will always use 64K or larger pages for I915_MEMORY_CLASS_DEVICE. The kernel also requires a minimum of 64K GTT alignment for such objects.

NOTE: Previously the ABI here required a minimum GTT alignment of 2M on DG2/ATS, due to how the hardware implemented 64K GTT page support, where we had the following complications:

1) The entire PDE (which covers a 2MB virtual address range), must contain only 64K PTEs, i.e mixing 4K and 64K PTEs in the same PDE is forbidden by the hardware.

2) We still need to support 4K PTEs for I915_MEMORY_CLASS_SYSTEM objects.

However on actual production HW this was completely changed to now allow setting a TLB hint at the PTE level (see PS64), which is a lot more flexible than the above. With this the 2M restriction was dropped where we now only require 64K.

handle

Returned handle for the object.

Object handles are nonzero.

flags

Optional flags.

Supported values:

I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS - Signal to the kernel that the object will need to be accessed via the CPU.

Only valid when placing objects in I915_MEMORY_CLASS_DEVICE, and only strictly required on configurations where some subset of the device memory is directly visible/mappable through the CPU (which we also call small BAR), like on some DG2+ systems. Note that this is quite undesirable, but due to various factors like the client CPU, BIOS etc it's something we can expect to see in the wild. See drm_i915_memory_region_info.probed_cpu_visible_size for how to determine if this system applies.

Note that one of the placements MUST be I915_MEMORY_CLASS_SYSTEM, to ensure the kernel can always spill the allocation to system memory, if the object can't be allocated in the mappable part of I915_MEMORY_CLASS_DEVICE.

Also note that since the kernel only supports flat-CCS on objects that can only be placed in I915_MEMORY_CLASS_DEVICE, we therefore don't support I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS together with flat-CCS.

Without this hint, the kernel will assume that non-mappable I915_MEMORY_CLASS_DEVICE is preferred for this object. Note that the kernel can still migrate the object to the mappable part, as a last resort, if userspace ever CPU faults this object, but this might be expensive, and so ideally should be avoided.

On older kernels which lack the relevant small-bar uAPI support (see also drm_i915_memory_region_info.probed_cpu_visible_size), usage of the flag will result in an error, but it should NEVER be possible to end up with a small BAR configuration, assuming we can also successfully load the i915 kernel module. In such cases the entire I915_MEMORY_CLASS_DEVICE region will be CPU accessible, and as such there are zero restrictions on where the object can be placed.

extensions

The chain of extensions to apply to this object.

This will be useful in the future when we need to support several different extensions, and we need to apply more than one when creating the object. See struct i915_user_extension.

If we don't supply any extensions then we get the same old gem_create behaviour.

For I915_GEM_CREATE_EXT_MEMORY_REGIONS usage see struct drm_i915_gem_create_ext_memory_regions.

For I915_GEM_CREATE_EXT_PROTECTED_CONTENT usage see struct drm_i915_gem_create_ext_protected_content.

For I915_GEM_CREATE_EXT_SET_PAT usage see struct drm_i915_gem_create_ext_set_pat.

Description

Note that new buffer flags should be added here, at least for the stuff that is immutable. Previously we would have two ioctls, one to create the object with gem_create, and another to apply various parameters, however this creates some ambiguity for the params which are considered immutable. Also in general we're phasing out the various SET/GET ioctls.

struct drm_i915_gem_create_ext_memory_regions

The I915_GEM_CREATE_EXT_MEMORY_REGIONS extension.

Definition:

struct drm_i915_gem_create_ext_memory_regions {
    struct i915_user_extension base;
    __u32 pad;
    __u32 num_regions;
    __u64 regions;
};

Members

base

Extension link. See struct i915_user_extension.

pad

MBZ

num_regions

Number of elements in the regions array.

regions

The regions/placements array.

An array of struct drm_i915_gem_memory_class_instance.

Description

Set the object with the desired set of placements/regions in priority order. Each entry must be unique and supported by the device.

This is provided as an array of struct drm_i915_gem_memory_class_instance, or an equivalent layout of class:instance pair encodings. See struct drm_i915_query_memory_regions and DRM_I915_QUERY_MEMORY_REGIONS for how to query the supported regions for a device.

As an example, on discrete devices, if we wish to set the placement as device local-memory we can do something like:

struct drm_i915_gem_memory_class_instance region_lmem = {
        .memory_class = I915_MEMORY_CLASS_DEVICE,
        .memory_instance = 0,
};
struct drm_i915_gem_create_ext_memory_regions regions = {
        .base = { .name = I915_GEM_CREATE_EXT_MEMORY_REGIONS },
        .regions = (uintptr_t)&region_lmem,
        .num_regions = 1,
};
struct drm_i915_gem_create_ext create_ext = {
        .size = 16 * PAGE_SIZE,
        .extensions = (uintptr_t)&regions,
};

int err = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create_ext);
if (err) ...

At which point we get the object handle in drm_i915_gem_create_ext.handle, along with the final object size in drm_i915_gem_create_ext.size, which should account for any rounding up, if required.

Note that userspace has no means of knowing the current backing region for objects where num_regions is larger than one. The kernel will only ensure that the priority order of the regions array is honoured, either when initially placing the object, or when moving memory around due to memory pressure

On Flat-CCS capable HW, compression is supported for the objects residing in I915_MEMORY_CLASS_DEVICE. When such objects (compressed) have other memory class in regions and migrated (by i915, due to memory constraints) to the non I915_MEMORY_CLASS_DEVICE region, then i915 needs to decompress the content. But i915 doesn't have the required information to decompress the userspace compressed objects.

So i915 supports Flat-CCS, on the objects which can reside only on I915_MEMORY_CLASS_DEVICE regions.

struct drm_i915_gem_create_ext_protected_content

The I915_OBJECT_PARAM_PROTECTED_CONTENT extension.

Definition:

struct drm_i915_gem_create_ext_protected_content {
    struct i915_user_extension base;
    __u32 flags;
};

Members

base

Extension link. See struct i915_user_extension.

flags

reserved for future usage, currently MBZ

Description

If this extension is provided, buffer contents are expected to be protected by PXP encryption and require decryption for scan out and processing. This is only possible on platforms that have PXP enabled, on all other scenarios using this extension will cause the ioctl to fail and return -ENODEV. The flags parameter is reserved for future expansion and must currently be set to zero.

The buffer contents are considered invalid after a PXP session teardown.

The encryption is guaranteed to be processed correctly only if the object is submitted with a context created using the I915_CONTEXT_PARAM_PROTECTED_CONTENT flag. This will also enable extra checks at submission time on the validity of the objects involved.

Below is an example on how to create a protected object:

struct drm_i915_gem_create_ext_protected_content protected_ext = {
        .base = { .name = I915_GEM_CREATE_EXT_PROTECTED_CONTENT },
        .flags = 0,
};
struct drm_i915_gem_create_ext create_ext = {
        .size = PAGE_SIZE,
        .extensions = (uintptr_t)&protected_ext,
};

int err = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create_ext);
if (err) ...
struct drm_i915_gem_create_ext_set_pat

The I915_GEM_CREATE_EXT_SET_PAT extension.

Definition:

struct drm_i915_gem_create_ext_set_pat {
    struct i915_user_extension base;
    __u32 pat_index;
    __u32 rsvd;
};

Members

base

Extension link. See struct i915_user_extension.

pat_index

PAT index to be set PAT index is a bit field in Page Table Entry to control caching behaviors for GPU accesses. The definition of PAT index is platform dependent and can be found in hardware specifications,

rsvd

reserved for future use

Description

If this extension is provided, the specified caching policy (PAT index) is applied to the buffer object.

Below is an example on how to create an object with specific caching policy:

struct drm_i915_gem_create_ext_set_pat set_pat_ext = {
        .base = { .name = I915_GEM_CREATE_EXT_SET_PAT },
        .pat_index = 0,
};
struct drm_i915_gem_create_ext create_ext = {
        .size = PAGE_SIZE,
        .extensions = (uintptr_t)&set_pat_ext,
};

int err = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create_ext);
if (err) ...

drm/nouveau uAPI

VM_BIND / EXEC uAPI

Nouveau's VM_BIND / EXEC UAPI consists of three ioctls: DRM_NOUVEAU_VM_INIT, DRM_NOUVEAU_VM_BIND and DRM_NOUVEAU_EXEC.

In order to use the UAPI firstly a user client must initialize the VA space using the DRM_NOUVEAU_VM_INIT ioctl specifying which region of the VA space should be managed by the kernel and which by the UMD.

The DRM_NOUVEAU_VM_BIND ioctl provides clients an interface to manage the userspace-managable portion of the VA space. It provides operations to map and unmap memory. Mappings may be flagged as sparse. Sparse mappings are not backed by a GEM object and the kernel will ignore GEM handles provided alongside a sparse mapping.

Userspace may request memory backed mappings either within or outside of the bounds (but not crossing those bounds) of a previously mapped sparse mapping. Subsequently requested memory backed mappings within a sparse mapping will take precedence over the corresponding range of the sparse mapping. If such memory backed mappings are unmapped the kernel will make sure that the corresponding sparse mapping will take their place again. Requests to unmap a sparse mapping that still contains memory backed mappings will result in those memory backed mappings being unmapped first.

Unmap requests are not bound to the range of existing mappings and can even overlap the bounds of sparse mappings. For such a request the kernel will make sure to unmap all memory backed mappings within the given range, splitting up memory backed mappings which are only partially contained within the given range. Unmap requests with the sparse flag set must match the range of a previously mapped sparse mapping exactly though.

While the kernel generally permits arbitrary sequences and ranges of memory backed mappings being mapped and unmapped, either within a single or multiple VM_BIND ioctl calls, there are some restrictions for sparse mappings.

The kernel does not permit to:
  • unmap non-existent sparse mappings

  • unmap a sparse mapping and map a new sparse mapping overlapping the range of the previously unmapped sparse mapping within the same VM_BIND ioctl

  • unmap a sparse mapping and map new memory backed mappings overlapping the range of the previously unmapped sparse mapping within the same VM_BIND ioctl

When using the VM_BIND ioctl to request the kernel to map memory to a given virtual address in the GPU's VA space there is no guarantee that the actual mappings are created in the GPU's MMU. If the given memory is swapped out at the time the bind operation is executed the kernel will stash the mapping details into it's internal alloctor and create the actual MMU mappings once the memory is swapped back in. While this is transparent for userspace, it is guaranteed that all the backing memory is swapped back in and all the memory mappings, as requested by userspace previously, are actually mapped once the DRM_NOUVEAU_EXEC ioctl is called to submit an exec job.

A VM_BIND job can be executed either synchronously or asynchronously. If exectued asynchronously, userspace may provide a list of syncobjs this job will wait for and/or a list of syncobj the kernel will signal once the VM_BIND job finished execution. If executed synchronously the ioctl will block until the bind job is finished. For synchronous jobs the kernel will not permit any syncobjs submitted to the kernel.

To execute a push buffer the UAPI provides the DRM_NOUVEAU_EXEC ioctl. EXEC jobs are always executed asynchronously, and, equal to VM_BIND jobs, provide the option to synchronize them with syncobjs.

Besides that, EXEC jobs can be scheduled for a specified channel to execute on.

Since VM_BIND jobs update the GPU's VA space on job submit, EXEC jobs do have an up to date view of the VA space. However, the actual mappings might still be pending. Hence, EXEC jobs require to have the particular fences - of the corresponding VM_BIND jobs they depent on - attached to them.

struct drm_nouveau_sync

sync object

Definition:

struct drm_nouveau_sync {
    __u32 flags;
#define DRM_NOUVEAU_SYNC_SYNCOBJ 0x0;
#define DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ 0x1;
#define DRM_NOUVEAU_SYNC_TYPE_MASK 0xf;
    __u32 handle;
    __u64 timeline_value;
};

Members

flags

the flags for a sync object

The first 8 bits are used to determine the type of the sync object.

handle

the handle of the sync object

timeline_value

The timeline point of the sync object in case the syncobj is of type DRM_NOUVEAU_SYNC_TIMELINE_SYNCOBJ.

Description

This structure serves as synchronization mechanism for (potentially) asynchronous operations such as EXEC or VM_BIND.

struct drm_nouveau_vm_init

GPU VA space init structure

Definition:

struct drm_nouveau_vm_init {
    __u64 kernel_managed_addr;
    __u64 kernel_managed_size;
};

Members

kernel_managed_addr

start address of the kernel managed VA space region

kernel_managed_size

size of the kernel managed VA space region in bytes

Description

Used to initialize the GPU's VA space for a user client, telling the kernel which portion of the VA space is managed by the UMD and kernel respectively.

For the UMD to use the VM_BIND uAPI, this must be called before any BOs or channels are created; if called afterwards DRM_IOCTL_NOUVEAU_VM_INIT fails with -ENOSYS.

struct drm_nouveau_vm_bind_op

VM_BIND operation

Definition:

struct drm_nouveau_vm_bind_op {
    __u32 op;
#define DRM_NOUVEAU_VM_BIND_OP_MAP 0x0;
#define DRM_NOUVEAU_VM_BIND_OP_UNMAP 0x1;
    __u32 flags;
#define DRM_NOUVEAU_VM_BIND_SPARSE (1 << 8);
    __u32 handle;
    __u32 pad;
    __u64 addr;
    __u64 bo_offset;
    __u64 range;
};

Members

op

the operation type

Supported values:

DRM_NOUVEAU_VM_BIND_OP_MAP - Map a GEM object to the GPU's VA space. Optionally, the DRM_NOUVEAU_VM_BIND_SPARSE flag can be passed to instruct the kernel to create sparse mappings for the given range.

DRM_NOUVEAU_VM_BIND_OP_UNMAP - Unmap an existing mapping in the GPU's VA space. If the region the mapping is located in is a sparse region, new sparse mappings are created where the unmapped (memory backed) mapping was mapped previously. To remove a sparse region the DRM_NOUVEAU_VM_BIND_SPARSE must be set.

flags

the flags for a drm_nouveau_vm_bind_op

Supported values:

DRM_NOUVEAU_VM_BIND_SPARSE - Indicates that an allocated VA space region should be sparse.

handle

the handle of the DRM GEM object to map

pad

32 bit padding, should be 0

addr

the address the VA space region or (memory backed) mapping should be mapped to

bo_offset

the offset within the BO backing the mapping

range

the size of the requested mapping in bytes

Description

This structure represents a single VM_BIND operation. UMDs should pass an array of this structure via struct drm_nouveau_vm_bind's op_ptr field.

struct drm_nouveau_vm_bind

structure for DRM_IOCTL_NOUVEAU_VM_BIND

Definition:

struct drm_nouveau_vm_bind {
    __u32 op_count;
    __u32 flags;
#define DRM_NOUVEAU_VM_BIND_RUN_ASYNC 0x1;
    __u32 wait_count;
    __u32 sig_count;
    __u64 wait_ptr;
    __u64 sig_ptr;
    __u64 op_ptr;
};

Members

op_count

the number of drm_nouveau_vm_bind_op

flags

the flags for a drm_nouveau_vm_bind ioctl

Supported values:

DRM_NOUVEAU_VM_BIND_RUN_ASYNC - Indicates that the given VM_BIND operation should be executed asynchronously by the kernel.

If this flag is not supplied the kernel executes the associated operations synchronously and doesn't accept any drm_nouveau_sync objects.

wait_count

the number of wait drm_nouveau_syncs

sig_count

the number of drm_nouveau_syncs to signal when finished

wait_ptr

pointer to drm_nouveau_syncs to wait for

sig_ptr

pointer to drm_nouveau_syncs to signal when finished

op_ptr

pointer to the drm_nouveau_vm_bind_ops to execute

struct drm_nouveau_exec_push

EXEC push operation

Definition:

struct drm_nouveau_exec_push {
    __u64 va;
    __u32 va_len;
    __u32 flags;
#define DRM_NOUVEAU_EXEC_PUSH_NO_PREFETCH 0x1;
};

Members

va

the virtual address of the push buffer mapping

va_len

the length of the push buffer mapping

flags

the flags for this push buffer mapping

Description

This structure represents a single EXEC push operation. UMDs should pass an array of this structure via struct drm_nouveau_exec's push_ptr field.

struct drm_nouveau_exec

structure for DRM_IOCTL_NOUVEAU_EXEC

Definition:

struct drm_nouveau_exec {
    __u32 channel;
    __u32 push_count;
    __u32 wait_count;
    __u32 sig_count;
    __u64 wait_ptr;
    __u64 sig_ptr;
    __u64 push_ptr;
};

Members

channel

the channel to execute the push buffer in

push_count

the number of drm_nouveau_exec_push ops

wait_count

the number of wait drm_nouveau_syncs

sig_count

the number of drm_nouveau_syncs to signal when finished

wait_ptr

pointer to drm_nouveau_syncs to wait for

sig_ptr

pointer to drm_nouveau_syncs to signal when finished

push_ptr

pointer to drm_nouveau_exec_push ops

drm/xe uAPI

Xe Device Block Diagram

The diagram below represents a high-level simplification of a discrete GPU supported by the Xe driver. It shows some device components which are necessary to understand this API, as well as how their relations to each other. This diagram does not represent real hardware:

┌──────────────────────────────────────────────────────────────────┐
│ ┌──────────────────────────────────────────────────┐ ┌─────────┐ │
│ │        ┌───────────────────────┐   ┌─────┐       │ │ ┌─────┐ │ │
│ │        │         VRAM0         ├───┤ ... │       │ │ │VRAM1│ │ │
│ │        └───────────┬───────────┘   └─GT1─┘       │ │ └──┬──┘ │ │
│ │ ┌──────────────────┴───────────────────────────┐ │ │ ┌──┴──┐ │ │
│ │ │ ┌─────────────────────┐  ┌─────────────────┐ │ │ │ │     │ │ │
│ │ │ │ ┌──┐ ┌──┐ ┌──┐ ┌──┐ │  │ ┌─────┐ ┌─────┐ │ │ │ │ │     │ │ │
│ │ │ │ │EU│ │EU│ │EU│ │EU│ │  │ │RCS0 │ │BCS0 │ │ │ │ │ │     │ │ │
│ │ │ │ └──┘ └──┘ └──┘ └──┘ │  │ └─────┘ └─────┘ │ │ │ │ │     │ │ │
│ │ │ │ ┌──┐ ┌──┐ ┌──┐ ┌──┐ │  │ ┌─────┐ ┌─────┐ │ │ │ │ │     │ │ │
│ │ │ │ │EU│ │EU│ │EU│ │EU│ │  │ │VCS0 │ │VCS1 │ │ │ │ │ │     │ │ │
│ │ │ │ └──┘ └──┘ └──┘ └──┘ │  │ └─────┘ └─────┘ │ │ │ │ │     │ │ │
│ │ │ │ ┌──┐ ┌──┐ ┌──┐ ┌──┐ │  │ ┌─────┐ ┌─────┐ │ │ │ │ │     │ │ │
│ │ │ │ │EU│ │EU│ │EU│ │EU│ │  │ │VECS0│ │VECS1│ │ │ │ │ │ ... │ │ │
│ │ │ │ └──┘ └──┘ └──┘ └──┘ │  │ └─────┘ └─────┘ │ │ │ │ │     │ │ │
│ │ │ │ ┌──┐ ┌──┐ ┌──┐ ┌──┐ │  │ ┌─────┐ ┌─────┐ │ │ │ │ │     │ │ │
│ │ │ │ │EU│ │EU│ │EU│ │EU│ │  │ │CCS0 │ │CCS1 │ │ │ │ │ │     │ │ │
│ │ │ │ └──┘ └──┘ └──┘ └──┘ │  │ └─────┘ └─────┘ │ │ │ │ │     │ │ │
│ │ │ └─────────DSS─────────┘  │ ┌─────┐ ┌─────┐ │ │ │ │ │     │ │ │
│ │ │                          │ │CCS2 │ │CCS3 │ │ │ │ │ │     │ │ │
│ │ │ ┌─────┐ ┌─────┐ ┌─────┐  │ └─────┘ └─────┘ │ │ │ │ │     │ │ │
│ │ │ │ ... │ │ ... │ │ ... │  │                 │ │ │ │ │     │ │ │
│ │ │ └─DSS─┘ └─DSS─┘ └─DSS─┘  └─────Engines─────┘ │ │ │ │     │ │ │
│ │ └───────────────────────────GT0────────────────┘ │ │ └─GT2─┘ │ │
│ └────────────────────────────Tile0─────────────────┘ └─ Tile1──┘ │
└─────────────────────────────Device0───────┬──────────────────────┘
                                            │
                     ───────────────────────┴────────── PCI bus

Xe uAPI Overview

This section aims to describe the Xe's IOCTL entries, its structs, and other Xe related uAPI such as uevents and PMU (Platform Monitoring Unit) related entries and usage.

List of supported IOCTLs:
  • DRM_IOCTL_XE_DEVICE_QUERY

  • DRM_IOCTL_XE_GEM_CREATE

  • DRM_IOCTL_XE_GEM_MMAP_OFFSET

  • DRM_IOCTL_XE_VM_CREATE

  • DRM_IOCTL_XE_VM_DESTROY

  • DRM_IOCTL_XE_VM_BIND

  • DRM_IOCTL_XE_EXEC_QUEUE_CREATE

  • DRM_IOCTL_XE_EXEC_QUEUE_DESTROY

  • DRM_IOCTL_XE_EXEC_QUEUE_GET_PROPERTY

  • DRM_IOCTL_XE_EXEC

  • DRM_IOCTL_XE_WAIT_USER_FENCE

Xe IOCTL Extensions

Before detailing the IOCTLs and its structs, it is important to highlight that every IOCTL in Xe is extensible.

Many interfaces need to grow over time. In most cases we can simply extend the struct and have userspace pass in more data. Another option, as demonstrated by Vulkan's approach to providing extensions for forward and backward compatibility, is to use a list of optional structs to provide those extra details.

The key advantage to using an extension chain is that it allows us to redefine the interface more easily than an ever growing struct of increasing complexity, and for large parts of that interface to be entirely optional. The downside is more pointer chasing; chasing across the __user boundary with pointers encapsulated inside u64.

Example chaining:

struct drm_xe_user_extension ext3 {
        .next_extension = 0, // end
        .name = ...,
};
struct drm_xe_user_extension ext2 {
        .next_extension = (uintptr_t)&ext3,
        .name = ...,
};
struct drm_xe_user_extension ext1 {
        .next_extension = (uintptr_t)&ext2,
        .name = ...,
};

Typically the struct drm_xe_user_extension would be embedded in some uAPI struct, and in this case we would feed it the head of the chain(i.e ext1), which would then apply all of the above extensions.

struct drm_xe_user_extension

Base class for defining a chain of extensions

Definition:

struct drm_xe_user_extension {
    __u64 next_extension;
    __u32 name;
    __u32 pad;
};

Members

next_extension

Pointer to the next struct drm_xe_user_extension, or zero if the end.

name

Name of the extension.

Note that the name here is just some integer.

Also note that the name space for this is not global for the whole driver, but rather its scope/meaning is limited to the specific piece of uAPI which has embedded the struct drm_xe_user_extension.

pad

MBZ

All undefined bits must be zero.

struct drm_xe_ext_set_property

Generic set property extension

Definition:

struct drm_xe_ext_set_property {
    struct drm_xe_user_extension base;
    __u32 property;
    __u32 pad;
    __u64 value;
    __u64 reserved[2];
};

Members

base

base user extension

property

property to set

pad

MBZ

value

property value

reserved

Reserved

Description

A generic struct that allows any of the Xe's IOCTL to be extended with a set_property operation.

struct drm_xe_engine_class_instance

instance of an engine class

Definition:

struct drm_xe_engine_class_instance {
#define DRM_XE_ENGINE_CLASS_RENDER              0;
#define DRM_XE_ENGINE_CLASS_COPY                1;
#define DRM_XE_ENGINE_CLASS_VIDEO_DECODE        2;
#define DRM_XE_ENGINE_CLASS_VIDEO_ENHANCE       3;
#define DRM_XE_ENGINE_CLASS_COMPUTE             4;
#define DRM_XE_ENGINE_CLASS_VM_BIND             5;
    __u16 engine_class;
    __u16 engine_instance;
    __u16 gt_id;
    __u16 pad;
};

Members

engine_class

engine class id

engine_instance

engine instance id

gt_id

Unique ID of this GT within the PCI Device

pad

MBZ

Description

It is returned as part of the drm_xe_engine, but it also is used as the input of engine selection for both drm_xe_exec_queue_create and drm_xe_query_engine_cycles

The engine_class can be:
  • DRM_XE_ENGINE_CLASS_RENDER

  • DRM_XE_ENGINE_CLASS_COPY

  • DRM_XE_ENGINE_CLASS_VIDEO_DECODE

  • DRM_XE_ENGINE_CLASS_VIDEO_ENHANCE

  • DRM_XE_ENGINE_CLASS_COMPUTE

  • DRM_XE_ENGINE_CLASS_VM_BIND - Kernel only classes (not actual hardware engine class). Used for creating ordered queues of VM bind operations.

struct drm_xe_engine

describe hardware engine

Definition:

struct drm_xe_engine {
    struct drm_xe_engine_class_instance instance;
    __u64 reserved[3];
};

Members

instance

The drm_xe_engine_class_instance

reserved

Reserved

struct drm_xe_query_engines

describe engines

Definition:

struct drm_xe_query_engines {
    __u32 num_engines;
    __u32 pad;
    struct drm_xe_engine engines[];
};

Members

num_engines

number of engines returned in engines

pad

MBZ

engines

The returned engines for this device

Description

If a query is made with a struct drm_xe_device_query where .query is equal to DRM_XE_DEVICE_QUERY_ENGINES, then the reply uses an array of struct drm_xe_query_engines in .data.

enum drm_xe_memory_class

Supported memory classes.

Constants

DRM_XE_MEM_REGION_CLASS_SYSMEM

Represents system memory.

DRM_XE_MEM_REGION_CLASS_VRAM

On discrete platforms, this represents the memory that is local to the device, which we call VRAM. Not valid on integrated platforms.

struct drm_xe_mem_region

Describes some region as known to the driver.

Definition:

struct drm_xe_mem_region {
    __u16 mem_class;
    __u16 instance;
    __u32 min_page_size;
    __u64 total_size;
    __u64 used;
    __u64 cpu_visible_size;
    __u64 cpu_visible_used;
    __u64 reserved[6];
};

Members

mem_class

The memory class describing this region.

See enum drm_xe_memory_class for supported values.

instance

The unique ID for this region, which serves as the index in the placement bitmask used as argument for DRM_IOCTL_XE_GEM_CREATE

min_page_size

Min page-size in bytes for this region.

When the kernel allocates memory for this region, the underlying pages will be at least min_page_size in size. Buffer objects with an allowable placement in this region must be created with a size aligned to this value. GPU virtual address mappings of (parts of) buffer objects that may be placed in this region must also have their GPU virtual address and range aligned to this value. Affected IOCTLS will return -EINVAL if alignment restrictions are not met.

total_size

The usable size in bytes for this region.

used

Estimate of the memory used in bytes for this region.

Requires CAP_PERFMON or CAP_SYS_ADMIN to get reliable accounting. Without this the value here will always equal zero.

cpu_visible_size

How much of this region can be CPU accessed, in bytes.

This will always be <= total_size, and the remainder (if any) will not be CPU accessible. If the CPU accessible part is smaller than total_size then this is referred to as a small BAR system.

On systems without small BAR (full BAR), the probed_size will always equal the total_size, since all of it will be CPU accessible.

Note this is only tracked for DRM_XE_MEM_REGION_CLASS_VRAM regions (for other types the value here will always equal zero).

cpu_visible_used

Estimate of CPU visible memory used, in bytes.

Requires CAP_PERFMON or CAP_SYS_ADMIN to get reliable accounting. Without this the value here will always equal zero. Note this is only currently tracked for DRM_XE_MEM_REGION_CLASS_VRAM regions (for other types the value here will always be zero).

reserved

Reserved

struct drm_xe_query_mem_regions

describe memory regions

Definition:

struct drm_xe_query_mem_regions {
    __u32 num_mem_regions;
    __u32 pad;
    struct drm_xe_mem_region mem_regions[];
};

Members

num_mem_regions

number of memory regions returned in mem_regions

pad

MBZ

mem_regions

The returned memory regions for this device

Description

If a query is made with a struct drm_xe_device_query where .query is equal to DRM_XE_DEVICE_QUERY_MEM_REGIONS, then the reply uses struct drm_xe_query_mem_regions in .data.

struct drm_xe_query_config

describe the device configuration

Definition:

struct drm_xe_query_config {
    __u32 num_params;
    __u32 pad;
#define DRM_XE_QUERY_CONFIG_REV_AND_DEVICE_ID   0;
#define DRM_XE_QUERY_CONFIG_FLAGS                       1;
#define DRM_XE_QUERY_CONFIG_FLAG_HAS_VRAM       (1 << 0);
#define DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT               2;
#define DRM_XE_QUERY_CONFIG_VA_BITS                     3;
#define DRM_XE_QUERY_CONFIG_MAX_EXEC_QUEUE_PRIORITY     4;
    __u64 info[];
};

Members

num_params

number of parameters returned in info

pad

MBZ

info

array of elements containing the config info

Description

If a query is made with a struct drm_xe_device_query where .query is equal to DRM_XE_DEVICE_QUERY_CONFIG, then the reply uses struct drm_xe_query_config in .data.

The index in info can be:
  • DRM_XE_QUERY_CONFIG_REV_AND_DEVICE_ID - Device ID (lower 16 bits) and the device revision (next 8 bits)

  • DRM_XE_QUERY_CONFIG_FLAGS - Flags describing the device configuration, see list below

    • DRM_XE_QUERY_CONFIG_FLAG_HAS_VRAM - Flag is set if the device has usable VRAM

  • DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT - Minimal memory alignment required by this device, typically SZ_4K or SZ_64K

  • DRM_XE_QUERY_CONFIG_VA_BITS - Maximum bits of a virtual address

  • DRM_XE_QUERY_CONFIG_MAX_EXEC_QUEUE_PRIORITY - Value of the highest available exec queue priority

struct drm_xe_gt

describe an individual GT.

Definition:

struct drm_xe_gt {
#define DRM_XE_QUERY_GT_TYPE_MAIN               0;
#define DRM_XE_QUERY_GT_TYPE_MEDIA              1;
    __u16 type;
    __u16 tile_id;
    __u16 gt_id;
    __u16 pad[3];
    __u32 reference_clock;
    __u64 near_mem_regions;
    __u64 far_mem_regions;
    __u64 reserved[8];
};

Members

type

GT type: Main or Media

tile_id

Tile ID where this GT lives (Information only)

gt_id

Unique ID of this GT within the PCI Device

pad

MBZ

reference_clock

A clock frequency for timestamp

near_mem_regions

Bit mask of instances from drm_xe_query_mem_regions that are nearest to the current engines of this GT. Each index in this mask refers directly to the struct drm_xe_query_mem_regions' instance, no assumptions should be made about order. The type of each region is described by struct drm_xe_query_mem_regions' mem_class.

far_mem_regions

Bit mask of instances from drm_xe_query_mem_regions that are far from the engines of this GT. In general, they have extra indirections when compared to the near_mem_regions. For a discrete device this could mean system memory and memory living in a different tile. Each index in this mask refers directly to the struct drm_xe_query_mem_regions' instance, no assumptions should be made about order. The type of each region is described by struct drm_xe_query_mem_regions' mem_class.

reserved

Reserved

Description

To be used with drm_xe_query_gt_list, which will return a list with all the existing GT individual descriptions. Graphics Technology (GT) is a subset of a GPU/tile that is responsible for implementing graphics and/or media operations.

The index in type can be:
  • DRM_XE_QUERY_GT_TYPE_MAIN

  • DRM_XE_QUERY_GT_TYPE_MEDIA

struct drm_xe_query_gt_list

A list with GT description items.

Definition:

struct drm_xe_query_gt_list {
    __u32 num_gt;
    __u32 pad;
    struct drm_xe_gt gt_list[];
};

Members

num_gt

number of GT items returned in gt_list

pad

MBZ

gt_list

The GT list returned for this device

Description

If a query is made with a struct drm_xe_device_query where .query is equal to DRM_XE_DEVICE_QUERY_GT_LIST, then the reply uses struct drm_xe_query_gt_list in .data.

struct drm_xe_query_topology_mask

describe the topology mask of a GT

Definition:

struct drm_xe_query_topology_mask {
    __u16 gt_id;
#define DRM_XE_TOPO_DSS_GEOMETRY        (1 << 0);
#define DRM_XE_TOPO_DSS_COMPUTE         (1 << 1);
#define DRM_XE_TOPO_EU_PER_DSS          (1 << 2);
    __u16 type;
    __u32 num_bytes;
    __u8 mask[];
};

Members

gt_id

GT ID the mask is associated with

type

type of mask

num_bytes

number of bytes in requested mask

mask

little-endian mask of num_bytes

Description

This is the hardware topology which reflects the internal physical structure of the GPU.

If a query is made with a struct drm_xe_device_query where .query is equal to DRM_XE_DEVICE_QUERY_GT_TOPOLOGY, then the reply uses struct drm_xe_query_topology_mask in .data.

The type can be:
  • DRM_XE_TOPO_DSS_GEOMETRY - To query the mask of Dual Sub Slices (DSS) available for geometry operations. For example a query response containing the following in mask: DSS_GEOMETRY    ff ff ff ff 00 00 00 00 means 32 DSS are available for geometry.

  • DRM_XE_TOPO_DSS_COMPUTE - To query the mask of Dual Sub Slices (DSS) available for compute operations. For example a query response containing the following in mask: DSS_COMPUTE    ff ff ff ff 00 00 00 00 means 32 DSS are available for compute.

  • DRM_XE_TOPO_EU_PER_DSS - To query the mask of Execution Units (EU) available per Dual Sub Slices (DSS). For example a query response containing the following in mask: EU_PER_DSS    ff ff 00 00 00 00 00 00 means each DSS has 16 EU.

struct drm_xe_query_engine_cycles

correlate CPU and GPU timestamps

Definition:

struct drm_xe_query_engine_cycles {
    struct drm_xe_engine_class_instance eci;
    __s32 clockid;
    __u32 width;
    __u64 engine_cycles;
    __u64 cpu_timestamp;
    __u64 cpu_delta;
};

Members

eci

This is input by the user and is the engine for which command streamer cycles is queried.

clockid

This is input by the user and is the reference clock id for CPU timestamp. For definition, see clock_gettime(2) and perf_event_open(2). Supported clock ids are CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_REALTIME, CLOCK_BOOTTIME, CLOCK_TAI.

width

Width of the engine cycle counter in bits.

engine_cycles

Engine cycles as read from its register at 0x358 offset.

cpu_timestamp

CPU timestamp in ns. The timestamp is captured before reading the engine_cycles register using the reference clockid set by the user.

cpu_delta

Time delta in ns captured around reading the lower dword of the engine_cycles register.

Description

If a query is made with a struct drm_xe_device_query where .query is equal to DRM_XE_DEVICE_QUERY_ENGINE_CYCLES, then the reply uses struct drm_xe_query_engine_cycles in .data. struct drm_xe_query_engine_cycles is allocated by the user and .data points to this allocated structure.

The query returns the engine cycles, which along with GT's reference_clock, can be used to calculate the engine timestamp. In addition the query returns a set of cpu timestamps that indicate when the command streamer cycle count was captured.

struct drm_xe_device_query

Input of DRM_IOCTL_XE_DEVICE_QUERY - main structure to query device information

Definition:

struct drm_xe_device_query {
    __u64 extensions;
#define DRM_XE_DEVICE_QUERY_ENGINES             0;
#define DRM_XE_DEVICE_QUERY_MEM_REGIONS         1;
#define DRM_XE_DEVICE_QUERY_CONFIG              2;
#define DRM_XE_DEVICE_QUERY_GT_LIST             3;
#define DRM_XE_DEVICE_QUERY_HWCONFIG            4;
#define DRM_XE_DEVICE_QUERY_GT_TOPOLOGY         5;
#define DRM_XE_DEVICE_QUERY_ENGINE_CYCLES       6;
    __u32 query;
    __u32 size;
    __u64 data;
    __u64 reserved[2];
};

Members

extensions

Pointer to the first extension struct, if any

query

The type of data to query

size

Size of the queried data

data

Queried data is placed here

reserved

Reserved

Description

The user selects the type of data to query among DRM_XE_DEVICE_QUERY_* and sets the value in the query member. This determines the type of the structure provided by the driver in data, among struct drm_xe_query_*.

The query can be:
  • DRM_XE_DEVICE_QUERY_ENGINES

  • DRM_XE_DEVICE_QUERY_MEM_REGIONS

  • DRM_XE_DEVICE_QUERY_CONFIG

  • DRM_XE_DEVICE_QUERY_GT_LIST

  • DRM_XE_DEVICE_QUERY_HWCONFIG - Query type to retrieve the hardware configuration of the device such as information on slices, memory, caches, and so on. It is provided as a table of key / value attributes.

  • DRM_XE_DEVICE_QUERY_GT_TOPOLOGY

  • DRM_XE_DEVICE_QUERY_ENGINE_CYCLES

If size is set to 0, the driver fills it with the required size for the requested type of data to query. If size is equal to the required size, the queried information is copied into data. If size is set to a value different from 0 and different from the required size, the IOCTL call returns -EINVAL.

For example the following code snippet allows retrieving and printing information about the device engines with DRM_XE_DEVICE_QUERY_ENGINES:

struct drm_xe_query_engines *engines;
struct drm_xe_device_query query = {
    .extensions = 0,
    .query = DRM_XE_DEVICE_QUERY_ENGINES,
    .size = 0,
    .data = 0,
};
ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query);
engines = malloc(query.size);
query.data = (uintptr_t)engines;
ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query);
for (int i = 0; i < engines->num_engines; i++) {
    printf("Engine %d: %s\n", i,
        engines->engines[i].instance.engine_class ==
            DRM_XE_ENGINE_CLASS_RENDER ? "RENDER":
        engines->engines[i].instance.engine_class ==
            DRM_XE_ENGINE_CLASS_COPY ? "COPY":
        engines->engines[i].instance.engine_class ==
            DRM_XE_ENGINE_CLASS_VIDEO_DECODE ? "VIDEO_DECODE":
        engines->engines[i].instance.engine_class ==
            DRM_XE_ENGINE_CLASS_VIDEO_ENHANCE ? "VIDEO_ENHANCE":
        engines->engines[i].instance.engine_class ==
            DRM_XE_ENGINE_CLASS_COMPUTE ? "COMPUTE":
        "UNKNOWN");
}
free(engines);
struct drm_xe_gem_create

Input of DRM_IOCTL_XE_GEM_CREATE - A structure for gem creation

Definition:

struct drm_xe_gem_create {
    __u64 extensions;
    __u64 size;
    __u32 placement;
#define DRM_XE_GEM_CREATE_FLAG_DEFER_BACKING            (1 << 0);
#define DRM_XE_GEM_CREATE_FLAG_SCANOUT                  (1 << 1);
#define DRM_XE_GEM_CREATE_FLAG_NEEDS_VISIBLE_VRAM       (1 << 2);
    __u32 flags;
    __u32 vm_id;
    __u32 handle;
#define DRM_XE_GEM_CPU_CACHING_WB                      1;
#define DRM_XE_GEM_CPU_CACHING_WC                      2;
    __u16 cpu_caching;
    __u16 pad[3];
    __u64 reserved[2];
};

Members

extensions

Pointer to the first extension struct, if any

size

Size of the object to be created, must match region (system or vram) minimum alignment (min_page_size).

placement

A mask of memory instances of where BO can be placed. Each index in this mask refers directly to the struct drm_xe_query_mem_regions' instance, no assumptions should be made about order. The type of each region is described by struct drm_xe_query_mem_regions' mem_class.

flags

Flags, currently a mask of memory instances of where BO can be placed

vm_id

Attached VM, if any

If a VM is specified, this BO must:

  1. Only ever be bound to that VM.

  2. Cannot be exported as a PRIME fd.

handle

Returned handle for the object.

Object handles are nonzero.

cpu_caching

The CPU caching mode to select for this object. If mmaping the object the mode selected here will also be used.

pad

MBZ

reserved

Reserved

Description

The flags can be:
  • DRM_XE_GEM_CREATE_FLAG_DEFER_BACKING

  • DRM_XE_GEM_CREATE_FLAG_SCANOUT

  • DRM_XE_GEM_CREATE_FLAG_NEEDS_VISIBLE_VRAM - When using VRAM as a possible placement, ensure that the corresponding VRAM allocation will always use the CPU accessible part of VRAM. This is important for small-bar systems (on full-bar systems this gets turned into a noop). Note1: System memory can be used as an extra placement if the kernel should spill the allocation to system memory, if space can't be made available in the CPU accessible part of VRAM (giving the same behaviour as the i915 interface, see I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS). Note2: For clear-color CCS surfaces the kernel needs to read the clear-color value stored in the buffer, and on discrete platforms we need to use VRAM for display surfaces, therefore the kernel requires setting this flag for such objects, otherwise an error is thrown on small-bar systems.

cpu_caching supports the following values:
  • DRM_XE_GEM_CPU_CACHING_WB - Allocate the pages with write-back caching. On iGPU this can't be used for scanout surfaces. Currently not allowed for objects placed in VRAM.

  • DRM_XE_GEM_CPU_CACHING_WC - Allocate the pages as write-combined. This is uncached. Scanout surfaces should likely use this. All objects that can be placed in VRAM must use this.

struct drm_xe_gem_mmap_offset

Input of DRM_IOCTL_XE_GEM_MMAP_OFFSET

Definition:

struct drm_xe_gem_mmap_offset {
    __u64 extensions;
    __u32 handle;
    __u32 flags;
    __u64 offset;
    __u64 reserved[2];
};

Members

extensions

Pointer to the first extension struct, if any

handle

Handle for the object being mapped.

flags

Must be zero

offset

The fake offset to use for subsequent mmap call

reserved

Reserved

struct drm_xe_vm_create

Input of DRM_IOCTL_XE_VM_CREATE

Definition:

struct drm_xe_vm_create {
    __u64 extensions;
#define DRM_XE_VM_CREATE_FLAG_SCRATCH_PAGE      (1 << 0);
#define DRM_XE_VM_CREATE_FLAG_LR_MODE           (1 << 1);
#define DRM_XE_VM_CREATE_FLAG_FAULT_MODE        (1 << 2);
    __u32 flags;
    __u32 vm_id;
    __u64 reserved[2];
};

Members

extensions

Pointer to the first extension struct, if any

flags

Flags

vm_id

Returned VM ID

reserved

Reserved

Description

The flags can be:
  • DRM_XE_VM_CREATE_FLAG_SCRATCH_PAGE

  • DRM_XE_VM_CREATE_FLAG_LR_MODE - An LR, or Long Running VM accepts exec submissions to its exec_queues that don't have an upper time limit on the job execution time. But exec submissions to these don't allow any of the flags DRM_XE_SYNC_FLAG_SYNCOBJ, DRM_XE_SYNC_FLAG_TIMELINE_SYNCOBJ, DRM_XE_SYNC_FLAG_DMA_BUF, used as out-syncobjs, that is, together with DRM_XE_SYNC_FLAG_SIGNAL. LR VMs can be created in recoverable page-fault mode using DRM_XE_VM_CREATE_FLAG_FAULT_MODE, if the device supports it. If that flag is omitted, the UMD can not rely on the slightly different per-VM overcommit semantics that are enabled by DRM_XE_VM_CREATE_FLAG_FAULT_MODE (see below), but KMD may still enable recoverable pagefaults if supported by the device.

  • DRM_XE_VM_CREATE_FLAG_FAULT_MODE - Requires also DRM_XE_VM_CREATE_FLAG_LR_MODE. It allows memory to be allocated on demand when accessed, and also allows per-VM overcommit of memory. The xe driver internally uses recoverable pagefaults to implement this.

struct drm_xe_vm_destroy

Input of DRM_IOCTL_XE_VM_DESTROY

Definition:

struct drm_xe_vm_destroy {
    __u32 vm_id;
    __u32 pad;
    __u64 reserved[2];
};

Members

vm_id

VM ID

pad

MBZ

reserved

Reserved

struct drm_xe_vm_bind_op

run bind operations

Definition:

struct drm_xe_vm_bind_op {
    __u64 extensions;
    __u32 obj;
    __u16 pat_index;
    __u16 pad;
    union {
        __u64 obj_offset;
        __u64 userptr;
    };
    __u64 range;
    __u64 addr;
#define DRM_XE_VM_BIND_OP_MAP           0x0;
#define DRM_XE_VM_BIND_OP_UNMAP         0x1;
#define DRM_XE_VM_BIND_OP_MAP_USERPTR   0x2;
#define DRM_XE_VM_BIND_OP_UNMAP_ALL     0x3;
#define DRM_XE_VM_BIND_OP_PREFETCH      0x4;
    __u32 op;
#define DRM_XE_VM_BIND_FLAG_READONLY    (1 << 0);
#define DRM_XE_VM_BIND_FLAG_IMMEDIATE   (1 << 1);
#define DRM_XE_VM_BIND_FLAG_NULL        (1 << 2);
    __u32 flags;
    __u32 prefetch_mem_region_instance;
    __u32 pad2;
    __u64 reserved[3];
};

Members

extensions

Pointer to the first extension struct, if any

obj

GEM object to operate on, MBZ for MAP_USERPTR, MBZ for UNMAP

pat_index

The platform defined pat_index to use for this mapping. The index basically maps to some predefined memory attributes, including things like caching, coherency, compression etc. The exact meaning of the pat_index is platform specific and defined in the Bspec and PRMs. When the KMD sets up the binding the index here is encoded into the ppGTT PTE.

For coherency the pat_index needs to be at least 1way coherent when drm_xe_gem_create.cpu_caching is DRM_XE_GEM_CPU_CACHING_WB. The KMD will extract the coherency mode from the pat_index and reject if there is a mismatch (see note below for pre-MTL platforms).

Note: On pre-MTL platforms there is only a caching mode and no explicit coherency mode, but on such hardware there is always a shared-LLC (or is dgpu) so all GT memory accesses are coherent with CPU caches even with the caching mode set as uncached. It's only the display engine that is incoherent (on dgpu it must be in VRAM which is always mapped as WC on the CPU). However to keep the uapi somewhat consistent with newer platforms the KMD groups the different cache levels into the following coherency buckets on all pre-MTL platforms:

ppGTT UC -> COH_NONE ppGTT WC -> COH_NONE ppGTT WT -> COH_NONE ppGTT WB -> COH_AT_LEAST_1WAY

In practice UC/WC/WT should only ever used for scanout surfaces on such platforms (or perhaps in general for dma-buf if shared with another device) since it is only the display engine that is actually incoherent. Everything else should typically use WB given that we have a shared-LLC. On MTL+ this completely changes and the HW defines the coherency mode as part of the pat_index, where incoherent GT access is possible.

Note: For userptr and externally imported dma-buf the kernel expects either 1WAY or 2WAY for the pat_index.

For DRM_XE_VM_BIND_FLAG_NULL bindings there are no KMD restrictions on the pat_index. For such mappings there is no actual memory being mapped (the address in the PTE is invalid), so the various PAT memory attributes likely do not apply. Simply leaving as zero is one option (still a valid pat_index).

pad

MBZ

{unnamed_union}

anonymous

obj_offset

Offset into the object, MBZ for CLEAR_RANGE, ignored for unbind

userptr

user pointer to bind on

range

Number of bytes from the object to bind to addr, MBZ for UNMAP_ALL

addr

Address to operate on, MBZ for UNMAP_ALL

op

Bind operation to perform

flags

Bind flags

prefetch_mem_region_instance

Memory region to prefetch VMA to. It is a region instance, not a mask. To be used only with DRM_XE_VM_BIND_OP_PREFETCH operation.

pad2

MBZ

reserved

Reserved

Description

The op can be:
  • DRM_XE_VM_BIND_OP_MAP

  • DRM_XE_VM_BIND_OP_UNMAP

  • DRM_XE_VM_BIND_OP_MAP_USERPTR

  • DRM_XE_VM_BIND_OP_UNMAP_ALL

  • DRM_XE_VM_BIND_OP_PREFETCH

and the flags can be:
  • DRM_XE_VM_BIND_FLAG_READONLY

  • DRM_XE_VM_BIND_FLAG_IMMEDIATE - Valid on a faulting VM only, do the MAP operation immediately rather than deferring the MAP to the page fault handler.

  • DRM_XE_VM_BIND_FLAG_NULL - When the NULL flag is set, the page tables are setup with a special bit which indicates writes are dropped and all reads return zero. In the future, the NULL flags will only be valid for DRM_XE_VM_BIND_OP_MAP operations, the BO handle MBZ, and the BO offset MBZ. This flag is intended to implement VK sparse bindings.

struct drm_xe_vm_bind

Input of DRM_IOCTL_XE_VM_BIND

Definition:

struct drm_xe_vm_bind {
    __u64 extensions;
    __u32 vm_id;
    __u32 exec_queue_id;
    __u32 pad;
    __u32 num_binds;
    union {
        struct drm_xe_vm_bind_op bind;
        __u64 vector_of_binds;
    };
    __u32 pad2;
    __u32 num_syncs;
    __u64 syncs;
    __u64 reserved[2];
};

Members

extensions

Pointer to the first extension struct, if any

vm_id

The ID of the VM to bind to

exec_queue_id

exec_queue_id, must be of class DRM_XE_ENGINE_CLASS_VM_BIND and exec queue must have same vm_id. If zero, the default VM bind engine is used.

pad

MBZ

num_binds

number of binds in this IOCTL

{unnamed_union}

anonymous

bind

used if num_binds == 1

vector_of_binds

userptr to array of struct drm_xe_vm_bind_op if num_binds > 1

pad2

MBZ

num_syncs

amount of syncs to wait on

syncs

pointer to struct drm_xe_sync array

reserved

Reserved

Description

Below is an example of a minimal use of drm_xe_vm_bind to asynchronously bind the buffer data at address BIND_ADDRESS to illustrate userptr. It can be synchronized by using the example provided for drm_xe_sync.

data = aligned_alloc(ALIGNMENT, BO_SIZE);
struct drm_xe_vm_bind bind = {
    .vm_id = vm,
    .num_binds = 1,
    .bind.obj = 0,
    .bind.obj_offset = to_user_pointer(data),
    .bind.range = BO_SIZE,
    .bind.addr = BIND_ADDRESS,
    .bind.op = DRM_XE_VM_BIND_OP_MAP_USERPTR,
    .bind.flags = 0,
    .num_syncs = 1,
    .syncs = &sync,
    .exec_queue_id = 0,
};
ioctl(fd, DRM_IOCTL_XE_VM_BIND, &bind);
struct drm_xe_exec_queue_create

Input of DRM_IOCTL_XE_EXEC_QUEUE_CREATE

Definition:

struct drm_xe_exec_queue_create {
#define DRM_XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY                0;
#define DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY               0;
#define DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE              1;
#define DRM_XE_EXEC_QUEUE_SET_PROPERTY_PREEMPTION_TIMEOUT     2;
#define DRM_XE_EXEC_QUEUE_SET_PROPERTY_PERSISTENCE            3;
#define DRM_XE_EXEC_QUEUE_SET_PROPERTY_JOB_TIMEOUT            4;
#define DRM_XE_EXEC_QUEUE_SET_PROPERTY_ACC_TRIGGER            5;
#define DRM_XE_EXEC_QUEUE_SET_PROPERTY_ACC_NOTIFY             6;
#define DRM_XE_EXEC_QUEUE_SET_PROPERTY_ACC_GRANULARITY        7;
#define DRM_XE_ACC_GRANULARITY_128K                         0;
#define DRM_XE_ACC_GRANULARITY_2M                           1;
#define DRM_XE_ACC_GRANULARITY_16M                          2;
#define DRM_XE_ACC_GRANULARITY_64M                          3;
    __u64 extensions;
    __u16 width;
    __u16 num_placements;
    __u32 vm_id;
    __u32 flags;
    __u32 exec_queue_id;
    __u64 instances;
    __u64 reserved[2];
};

Members

extensions

Pointer to the first extension struct, if any

width

submission width (number BB per exec) for this exec queue

num_placements

number of valid placements for this exec queue

vm_id

VM to use for this exec queue

flags

MBZ

exec_queue_id

Returned exec queue ID

instances

user pointer to a 2-d array of struct drm_xe_engine_class_instance

length = width (i) * num_placements (j) index = j + i * width

reserved

Reserved

Description

The example below shows how to use drm_xe_exec_queue_create to create a simple exec_queue (no parallel submission) of class DRM_XE_ENGINE_CLASS_RENDER.

struct drm_xe_engine_class_instance instance = {
    .engine_class = DRM_XE_ENGINE_CLASS_RENDER,
};
struct drm_xe_exec_queue_create exec_queue_create = {
     .extensions = 0,
     .vm_id = vm,
     .num_bb_per_exec = 1,
     .num_eng_per_bb = 1,
     .instances = to_user_pointer(&instance),
};
ioctl(fd, DRM_IOCTL_XE_EXEC_QUEUE_CREATE, &exec_queue_create);
struct drm_xe_exec_queue_destroy

Input of DRM_IOCTL_XE_EXEC_QUEUE_DESTROY

Definition:

struct drm_xe_exec_queue_destroy {
    __u32 exec_queue_id;
    __u32 pad;
    __u64 reserved[2];
};

Members

exec_queue_id

Exec queue ID

pad

MBZ

reserved

Reserved

struct drm_xe_exec_queue_get_property

Input of DRM_IOCTL_XE_EXEC_QUEUE_GET_PROPERTY

Definition:

struct drm_xe_exec_queue_get_property {
    __u64 extensions;
    __u32 exec_queue_id;
#define DRM_XE_EXEC_QUEUE_GET_PROPERTY_BAN      0;
    __u32 property;
    __u64 value;
    __u64 reserved[2];
};

Members

extensions

Pointer to the first extension struct, if any

exec_queue_id

Exec queue ID

property

property to get

value

property value

reserved

Reserved

Description

The property can be:
  • DRM_XE_EXEC_QUEUE_GET_PROPERTY_BAN

struct drm_xe_sync

sync object

Definition:

struct drm_xe_sync {
    __u64 extensions;
#define DRM_XE_SYNC_TYPE_SYNCOBJ                0x0;
#define DRM_XE_SYNC_TYPE_TIMELINE_SYNCOBJ       0x1;
#define DRM_XE_SYNC_TYPE_USER_FENCE             0x2;
    __u32 type;
#define DRM_XE_SYNC_FLAG_SIGNAL (1 << 0);
    __u32 flags;
    union {
        __u32 handle;
        __u64 addr;
    };
    __u64 timeline_value;
    __u64 reserved[2];
};

Members

extensions

Pointer to the first extension struct, if any

type

Type of the this sync object

flags

Sync Flags

{unnamed_union}

anonymous

handle

Handle for the object

addr

Address of user fence. When sync is passed in via exec IOCTL this is a GPU address in the VM. When sync passed in via VM bind IOCTL this is a user pointer. In either case, it is the users responsibility that this address is present and mapped when the user fence is signalled. Must be qword aligned.

timeline_value

Input for the timeline sync object. Needs to be different than 0 when used with DRM_XE_SYNC_FLAG_TIMELINE_SYNCOBJ.

reserved

Reserved

Description

The type can be:
  • DRM_XE_SYNC_TYPE_SYNCOBJ

  • DRM_XE_SYNC_TYPE_TIMELINE_SYNCOBJ

  • DRM_XE_SYNC_TYPE_USER_FENCE

and the flags can be:
  • DRM_XE_SYNC_FLAG_SIGNAL

A minimal use of drm_xe_sync looks like this:

struct drm_xe_sync sync = {
    .flags = DRM_XE_SYNC_FLAG_SIGNAL,
    .type = DRM_XE_SYNC_TYPE_SYNCOBJ,
};
struct drm_syncobj_create syncobj_create = { 0 };
ioctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &syncobj_create);
sync.handle = syncobj_create.handle;
    ...
    use of &sync in drm_xe_exec or drm_xe_vm_bind
    ...
struct drm_syncobj_wait wait = {
    .handles = &sync.handle,
    .timeout_nsec = INT64_MAX,
    .count_handles = 1,
    .flags = 0,
    .first_signaled = 0,
    .pad = 0,
};
ioctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &wait);
struct drm_xe_exec

Input of DRM_IOCTL_XE_EXEC

Definition:

struct drm_xe_exec {
    __u64 extensions;
    __u32 exec_queue_id;
    __u32 num_syncs;
    __u64 syncs;
    __u64 address;
    __u16 num_batch_buffer;
    __u16 pad[3];
    __u64 reserved[2];
};

Members

extensions

Pointer to the first extension struct, if any

exec_queue_id

Exec queue ID for the batch buffer

num_syncs

Amount of struct drm_xe_sync in array.

syncs

Pointer to struct drm_xe_sync array.

address

address of batch buffer if num_batch_buffer == 1 or an array of batch buffer addresses

num_batch_buffer

number of batch buffer in this exec, must match the width of the engine

pad

MBZ

reserved

Reserved

Description

This is an example to use drm_xe_exec for execution of the object at BIND_ADDRESS (see example in drm_xe_vm_bind) by an exec_queue (see example in drm_xe_exec_queue_create). It can be synchronized by using the example provided for drm_xe_sync.

struct drm_xe_exec exec = {
    .exec_queue_id = exec_queue,
    .syncs = &sync,
    .num_syncs = 1,
    .address = BIND_ADDRESS,
    .num_batch_buffer = 1,
};
ioctl(fd, DRM_IOCTL_XE_EXEC, &exec);
struct drm_xe_wait_user_fence

Input of DRM_IOCTL_XE_WAIT_USER_FENCE

Definition:

struct drm_xe_wait_user_fence {
    __u64 extensions;
    __u64 addr;
#define DRM_XE_UFENCE_WAIT_OP_EQ        0x0;
#define DRM_XE_UFENCE_WAIT_OP_NEQ       0x1;
#define DRM_XE_UFENCE_WAIT_OP_GT        0x2;
#define DRM_XE_UFENCE_WAIT_OP_GTE       0x3;
#define DRM_XE_UFENCE_WAIT_OP_LT        0x4;
#define DRM_XE_UFENCE_WAIT_OP_LTE       0x5;
    __u16 op;
#define DRM_XE_UFENCE_WAIT_FLAG_ABSTIME (1 << 0);
    __u16 flags;
    __u32 pad;
    __u64 value;
    __u64 mask;
    __s64 timeout;
    __u32 exec_queue_id;
    __u32 pad2;
    __u64 reserved[2];
};

Members

extensions

Pointer to the first extension struct, if any

addr

user pointer address to wait on, must qword aligned

op

wait operation (type of comparison)

flags

wait flags

pad

MBZ

value

compare value

mask

comparison mask

timeout

how long to wait before bailing, value in nanoseconds. Without DRM_XE_UFENCE_WAIT_FLAG_ABSTIME flag set (relative timeout) it contains timeout expressed in nanoseconds to wait (fence will expire at now() + timeout). When DRM_XE_UFENCE_WAIT_FLAG_ABSTIME flat is set (absolute timeout) wait will end at timeout (uses system MONOTONIC_CLOCK). Passing negative timeout leads to neverending wait.

On relative timeout this value is updated with timeout left (for restarting the call in case of signal delivery). On absolute timeout this value stays intact (restarted call still expire at the same point of time).

exec_queue_id

exec_queue_id returned from xe_exec_queue_create_ioctl

pad2

MBZ

reserved

Reserved

Description

Wait on user fence, XE will wake-up on every HW engine interrupt in the instances list and check if user fence is complete:

(*addr & MASK) OP (VALUE & MASK)

Returns to user on user fence completion or timeout.

The op can be:
  • DRM_XE_UFENCE_WAIT_OP_EQ

  • DRM_XE_UFENCE_WAIT_OP_NEQ

  • DRM_XE_UFENCE_WAIT_OP_GT

  • DRM_XE_UFENCE_WAIT_OP_GTE

  • DRM_XE_UFENCE_WAIT_OP_LT

  • DRM_XE_UFENCE_WAIT_OP_LTE

and the flags can be:
  • DRM_XE_UFENCE_WAIT_FLAG_ABSTIME

  • DRM_XE_UFENCE_WAIT_FLAG_SOFT_OP

The mask values can be for example:
  • 0xffu for u8

  • 0xffffu for u16

  • 0xffffffffu for u32

  • 0xffffffffffffffffu for u64