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:
Call the DRM_IOCTL_I915_QUERY, giving it our array of
struct drm_i915_query_item
, withdrm_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).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 thedrm_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
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)®ion_lmem,
.num_regions = 1,
};
struct drm_i915_gem_create_ext create_ext = {
.size = 16 * PAGE_SIZE,
.extensions = (uintptr_t)®ions,
};
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.