DRM Driver uAPI

drm/i915 uAPI

uevents generated by i915 on it’s 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.

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

I915_CACHING_NONE()

Parameters

Description

GPU access is not coherent with cpu caches. Default for machines without an LLC.

I915_CACHING_CACHED()

Parameters

Description

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. Default on machines with HAS_LLC.

I915_CACHING_DISPLAY()

Parameters

Description

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.

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;
  __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
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
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_engine_info

Definition

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

Members

engine
Engine class and instance.
rsvd0
Reserved field.
flags
Engine flags.
capabilities
Capabilities of this engine.
rsvd1
Reserved fields.

Description

Describes one engine and it’s 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.

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;
  __u64 rsvd1[8];
};

Members

region
The class:instance pair encoding
rsvd0
MBZ
probed_size
Memory probed by the driver (-1 = unknown)
unallocated_size
Estimate of memory remaining (-1 = unknown)
rsvd1
MBZ

Description

Note that we reserve some stuff here for potential future work. As an example we might want expose the capabilities for a given region, which could include things like if the region is CPU mappable/accessible, what are the supported mapping types etc.

Note that to extend struct drm_i915_memory_region_info and struct drm_i915_query_memory_regions in the future the plan is to do the following:

struct drm_i915_memory_region_info {
        struct drm_i915_gem_memory_class_instance region;
        union {
                __u32 rsvd0;
                __u32 new_thing1;
        };
        ...
        union {
                __u64 rsvd1[8];
                struct {
                        __u64 new_thing2;
                        __u64 new_thing3;
                        ...
                };
        };
};

With this things should remain source compatible between versions for userspace, even as we add new fields.

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);
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;
  __u32 flags;
#define I915_GEM_CREATE_EXT_MEMORY_REGIONS 0;
  __u64 extensions;
};

Members

size

Requested size for the object.

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

Note that for some devices we have might have further minimum page-size restrictions(larger than 4K), like for device local-memory. However in general the final size here should always reflect any rounding up, if for example using the I915_GEM_CREATE_EXT_MEMORY_REGIONS extension to place the object in device local-memory.

handle

Returned handle for the object.

Object handles are nonzero.

flags
MBZ
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.

Description

Note that in the future we want to have our buffer flags 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.