DRM Internals

This chapter documents DRM internals relevant to driver authors and developers working to add support for the latest features to existing drivers.

First, we go over some typical driver initialization requirements, like setting up command buffers, creating an initial output configuration, and initializing core services. Subsequent sections cover core internals in more detail, providing implementation notes and examples.

The DRM layer provides several services to graphics drivers, many of them driven by the application interfaces it provides through libdrm, the library that wraps most of the DRM ioctls. These include vblank event handling, memory management, output management, framebuffer management, command submission & fencing, suspend/resume support, and DMA services.

Driver Initialization

At the core of every DRM driver is a struct drm_driver structure. Drivers typically statically initialize a drm_driver structure, and then pass it to drm_dev_alloc() to allocate a device instance. After the device instance is fully initialized it can be registered (which makes it accessible from userspace) using drm_dev_register().

The struct drm_driver structure contains static information that describes the driver and features it supports, and pointers to methods that the DRM core will call to implement the DRM API. We will first go through the struct drm_driver static information fields, and will then describe individual operations in details as they get used in later sections.

Driver Information

Driver Features

Drivers inform the DRM core about their requirements and supported features by setting appropriate flags in the driver_features field. Since those flags influence the DRM core behaviour since registration time, most of them must be set to registering the struct drm_driver instance.

u32 driver_features;

DRIVER_USE_AGP
Driver uses AGP interface, the DRM core will manage AGP resources.
DRIVER_LEGACY
Denote a legacy driver using shadow attach. Don’t use.
DRIVER_KMS_LEGACY_CONTEXT
Used only by nouveau for backwards compatibility with existing userspace. Don’t use.
DRIVER_PCI_DMA
Driver is capable of PCI DMA, mapping of PCI DMA buffers to userspace will be enabled. Deprecated.
DRIVER_SG
Driver can perform scatter/gather DMA, allocation and mapping of scatter/gather buffers will be enabled. Deprecated.
DRIVER_HAVE_DMA
Driver supports DMA, the userspace DMA API will be supported. Deprecated.
DRIVER_HAVE_IRQ; DRIVER_IRQ_SHARED

DRIVER_HAVE_IRQ indicates whether the driver has an IRQ handler managed by the DRM Core. The core will support simple IRQ handler installation when the flag is set. The installation process is described in ?.

DRIVER_IRQ_SHARED indicates whether the device & handler support shared IRQs (note that this is required of PCI drivers).

DRIVER_GEM
Driver use the GEM memory manager.
DRIVER_MODESET
Driver supports mode setting interfaces (KMS).
DRIVER_PRIME
Driver implements DRM PRIME buffer sharing.
DRIVER_RENDER
Driver supports dedicated render nodes.
DRIVER_ATOMIC
Driver supports atomic properties. In this case the driver must implement appropriate obj->atomic_get_property() vfuncs for any modeset objects with driver specific properties.
DRIVER_SYNCOBJ
Driver support drm sync objects.

Major, Minor and Patchlevel

int major; int minor; int patchlevel; The DRM core identifies driver versions by a major, minor and patch level triplet. The information is printed to the kernel log at initialization time and passed to userspace through the DRM_IOCTL_VERSION ioctl.

The major and minor numbers are also used to verify the requested driver API version passed to DRM_IOCTL_SET_VERSION. When the driver API changes between minor versions, applications can call DRM_IOCTL_SET_VERSION to select a specific version of the API. If the requested major isn’t equal to the driver major, or the requested minor is larger than the driver minor, the DRM_IOCTL_SET_VERSION call will return an error. Otherwise the driver’s set_version() method will be called with the requested version.

Name, Description and Date

char *name; char *desc; char *date; The driver name is printed to the kernel log at initialization time, used for IRQ registration and passed to userspace through DRM_IOCTL_VERSION.

The driver description is a purely informative string passed to userspace through the DRM_IOCTL_VERSION ioctl and otherwise unused by the kernel.

The driver date, formatted as YYYYMMDD, is meant to identify the date of the latest modification to the driver. However, as most drivers fail to update it, its value is mostly useless. The DRM core prints it to the kernel log at initialization time and passes it to userspace through the DRM_IOCTL_VERSION ioctl.

Device Instance and Driver Handling

A device instance for a drm driver is represented by struct drm_device. This is allocated with drm_dev_alloc(), usually from bus-specific ->:c:func:probe() callbacks implemented by the driver. The driver then needs to initialize all the various subsystems for the drm device like memory management, vblank handling, modesetting support and intial output configuration plus obviously initialize all the corresponding hardware bits. An important part of this is also calling drm_dev_set_unique() to set the userspace-visible unique name of this device instance. Finally when everything is up and running and ready for userspace the device instance can be published using drm_dev_register().

There is also deprecated support for initalizing device instances using bus-specific helpers and the drm_driver.load callback. But due to backwards-compatibility needs the device instance have to be published too early, which requires unpretty global locking to make safe and is therefore only support for existing drivers not yet converted to the new scheme.

When cleaning up a device instance everything needs to be done in reverse: First unpublish the device instance with drm_dev_unregister(). Then clean up any other resources allocated at device initialization and drop the driver’s reference to drm_device using drm_dev_put().

Note that the lifetime rules for drm_device instance has still a lot of historical baggage. Hence use the reference counting provided by drm_dev_get() and drm_dev_put() only carefully.

It is recommended that drivers embed struct drm_device into their own device structure, which is supported through drm_dev_init().

struct drm_driver

DRM driver structure

Definition

struct drm_driver {
  int (*load) (struct drm_device *, unsigned long flags);
  int (*open) (struct drm_device *, struct drm_file *);
  void (*postclose) (struct drm_device *, struct drm_file *);
  void (*lastclose) (struct drm_device *);
  void (*unload) (struct drm_device *);
  void (*release) (struct drm_device *);
  u32 (*get_vblank_counter) (struct drm_device *dev, unsigned int pipe);
  int (*enable_vblank) (struct drm_device *dev, unsigned int pipe);
  void (*disable_vblank) (struct drm_device *dev, unsigned int pipe);
  bool (*get_scanout_position) (struct drm_device *dev, unsigned int pipe,bool in_vblank_irq, int *vpos, int *hpos,ktime_t *stime, ktime_t *etime, const struct drm_display_mode *mode);
  bool (*get_vblank_timestamp) (struct drm_device *dev, unsigned int pipe,int *max_error,ktime_t *vblank_time, bool in_vblank_irq);
  irqreturn_t(*irq_handler) (int irq, void *arg);
  void (*irq_preinstall) (struct drm_device *dev);
  int (*irq_postinstall) (struct drm_device *dev);
  void (*irq_uninstall) (struct drm_device *dev);
  int (*master_create)(struct drm_device *dev, struct drm_master *master);
  void (*master_destroy)(struct drm_device *dev, struct drm_master *master);
  int (*master_set)(struct drm_device *dev, struct drm_file *file_priv, bool from_open);
  void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv);
  int (*debugfs_init)(struct drm_minor *minor);
  void (*gem_free_object) (struct drm_gem_object *obj);
  void (*gem_free_object_unlocked) (struct drm_gem_object *obj);
  int (*gem_open_object) (struct drm_gem_object *, struct drm_file *);
  void (*gem_close_object) (struct drm_gem_object *, struct drm_file *);
  void (*gem_print_info)(struct drm_printer *p, unsigned int indent, const struct drm_gem_object *obj);
  struct drm_gem_object *(*gem_create_object)(struct drm_device *dev, size_t size);
  int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv, uint32_t handle, uint32_t flags, int *prime_fd);
  int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv, int prime_fd, uint32_t *handle);
  struct dma_buf * (*gem_prime_export)(struct drm_device *dev, struct drm_gem_object *obj, int flags);
  struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev, struct dma_buf *dma_buf);
  int (*gem_prime_pin)(struct drm_gem_object *obj);
  void (*gem_prime_unpin)(struct drm_gem_object *obj);
  struct reservation_object * (*gem_prime_res_obj)( struct drm_gem_object *obj);
  struct sg_table *(*gem_prime_get_sg_table)(struct drm_gem_object *obj);
  struct drm_gem_object *(*gem_prime_import_sg_table)(struct drm_device *dev,struct dma_buf_attachment *attach, struct sg_table *sgt);
  void *(*gem_prime_vmap)(struct drm_gem_object *obj);
  void (*gem_prime_vunmap)(struct drm_gem_object *obj, void *vaddr);
  int (*gem_prime_mmap)(struct drm_gem_object *obj, struct vm_area_struct *vma);
  int (*dumb_create)(struct drm_file *file_priv,struct drm_device *dev, struct drm_mode_create_dumb *args);
  int (*dumb_map_offset)(struct drm_file *file_priv,struct drm_device *dev, uint32_t handle, uint64_t *offset);
  int (*dumb_destroy)(struct drm_file *file_priv,struct drm_device *dev, uint32_t handle);
  const struct vm_operations_struct *gem_vm_ops;
  int major;
  int minor;
  int patchlevel;
  char *name;
  char *desc;
  char *date;
  u32 driver_features;
  const struct drm_ioctl_desc *ioctls;
  int num_ioctls;
  const struct file_operations *fops;
};

Members

load

Backward-compatible driver callback to complete initialization steps after the driver is registered. For this reason, may suffer from race conditions and its use is deprecated for new drivers. It is therefore only supported for existing drivers not yet converted to the new scheme. See drm_dev_init() and drm_dev_register() for proper and race-free way to set up a struct drm_device.

This is deprecated, do not use!

Returns:

Zero on success, non-zero value on failure.

open

Driver callback when a new struct drm_file is opened. Useful for setting up driver-private data structures like buffer allocators, execution contexts or similar things. Such driver-private resources must be released again in postclose.

Since the display/modeset side of DRM can only be owned by exactly one struct drm_file (see drm_file.is_master and drm_device.master) there should never be a need to set up any modeset related resources in this callback. Doing so would be a driver design bug.

Returns:

0 on success, a negative error code on failure, which will be promoted to userspace as the result of the open() system call.

postclose

One of the driver callbacks when a new struct drm_file is closed. Useful for tearing down driver-private data structures allocated in open like buffer allocators, execution contexts or similar things.

Since the display/modeset side of DRM can only be owned by exactly one struct drm_file (see drm_file.is_master and drm_device.master) there should never be a need to tear down any modeset related resources in this callback. Doing so would be a driver design bug.

lastclose

Called when the last struct drm_file has been closed and there’s currently no userspace client for the struct drm_device.

Modern drivers should only use this to force-restore the fbdev framebuffer using drm_fb_helper_restore_fbdev_mode_unlocked(). Anything else would indicate there’s something seriously wrong. Modern drivers can also use this to execute delayed power switching state changes, e.g. in conjunction with the VGA Switcheroo infrastructure.

This is called after postclose hook has been called.

NOTE:

All legacy drivers use this callback to de-initialize the hardware. This is purely because of the shadow-attach model, where the DRM kernel driver does not really own the hardware. Instead ownershipe is handled with the help of userspace through an inheritedly racy dance to set/unset the VT into raw mode.

Legacy drivers initialize the hardware in the firstopen callback, which isn’t even called for modern drivers.

unload

Reverse the effects of the driver load callback. Ideally, the clean up performed by the driver should happen in the reverse order of the initialization. Similarly to the load hook, this handler is deprecated and its usage should be dropped in favor of an open-coded teardown function at the driver layer. See drm_dev_unregister() and drm_dev_put() for the proper way to remove a struct drm_device.

The unload() hook is called right after unregistering the device.

release
Optional callback for destroying device data after the final reference is released, i.e. the device is being destroyed. Drivers using this callback are responsible for calling drm_dev_fini() to finalize the device and then freeing the struct themselves.
get_vblank_counter

Driver callback for fetching a raw hardware vblank counter for the CRTC specified with the pipe argument. If a device doesn’t have a hardware counter, the driver can simply leave the hook as NULL. The DRM core will account for missed vblank events while interrupts where disabled based on system timestamps.

Wraparound handling and loss of events due to modesetting is dealt with in the DRM core code, as long as drivers call drm_crtc_vblank_off() and drm_crtc_vblank_on() when disabling or enabling a CRTC.

This is deprecated and should not be used by new drivers. Use drm_crtc_funcs.get_vblank_counter instead.

Returns:

Raw vblank counter value.

enable_vblank

Enable vblank interrupts for the CRTC specified with the pipe argument.

This is deprecated and should not be used by new drivers. Use drm_crtc_funcs.enable_vblank instead.

Returns:

Zero on success, appropriate errno if the given crtc‘s vblank interrupt cannot be enabled.

disable_vblank

Disable vblank interrupts for the CRTC specified with the pipe argument.

This is deprecated and should not be used by new drivers. Use drm_crtc_funcs.disable_vblank instead.

get_scanout_position

Called by vblank timestamping code.

Returns the current display scanout position from a crtc, and an optional accurate ktime_get() timestamp of when position was measured. Note that this is a helper callback which is only used if a driver uses drm_calc_vbltimestamp_from_scanoutpos() for the get_vblank_timestamp callback.

Parameters:

dev:
DRM device.
pipe:
Id of the crtc to query.
in_vblank_irq:
True when called from drm_crtc_handle_vblank(). Some drivers need to apply some workarounds for gpu-specific vblank irq quirks if flag is set.
vpos:
Target location for current vertical scanout position.
hpos:
Target location for current horizontal scanout position.
stime:
Target location for timestamp taken immediately before scanout position query. Can be NULL to skip timestamp.
etime:
Target location for timestamp taken immediately after scanout position query. Can be NULL to skip timestamp.
mode:
Current display timings.

Returns vpos as a positive number while in active scanout area. Returns vpos as a negative number inside vblank, counting the number of scanlines to go until end of vblank, e.g., -1 means “one scanline until start of active scanout / end of vblank.”

Returns:

True on success, false if a reliable scanout position counter could not be read out.

FIXME:

Since this is a helper to implement get_vblank_timestamp, we should move it to struct drm_crtc_helper_funcs, like all the other helper-internal hooks.

get_vblank_timestamp

Called by drm_get_last_vbltimestamp(). Should return a precise timestamp when the most recent VBLANK interval ended or will end.

Specifically, the timestamp in vblank_time should correspond as closely as possible to the time when the first video scanline of the video frame after the end of VBLANK will start scanning out, the time immediately after end of the VBLANK interval. If the crtc is currently inside VBLANK, this will be a time in the future. If the crtc is currently scanning out a frame, this will be the past start time of the current scanout. This is meant to adhere to the OpenML OML_sync_control extension specification.

Paramters:

dev:
dev DRM device handle.
pipe:
crtc for which timestamp should be returned.
max_error:
Maximum allowable timestamp error in nanoseconds. Implementation should strive to provide timestamp with an error of at most max_error nanoseconds. Returns true upper bound on error for timestamp.
vblank_time:
Target location for returned vblank timestamp.
in_vblank_irq:
True when called from drm_crtc_handle_vblank(). Some drivers need to apply some workarounds for gpu-specific vblank irq quirks if flag is set.

Returns:

True on success, false on failure, which means the core should fallback to a simple timestamp taken in drm_crtc_handle_vblank().

FIXME:

We should move this hook to struct drm_crtc_funcs like all the other vblank hooks.

irq_handler
Interrupt handler called when using drm_irq_install(). Not used by drivers which implement their own interrupt handling.
irq_preinstall
Optional callback used by drm_irq_install() which is called before the interrupt handler is registered. This should be used to clear out any pending interrupts (from e.g. firmware based drives) and reset the interrupt handling registers.
irq_postinstall
Optional callback used by drm_irq_install() which is called after the interrupt handler is registered. This should be used to enable interrupt generation in the hardware.
irq_uninstall
Optional callback used by drm_irq_uninstall() which is called before the interrupt handler is unregistered. This should be used to disable interrupt generation in the hardware.
master_create
Called whenever a new master is created. Only used by vmwgfx.
master_destroy
Called whenever a master is destroyed. Only used by vmwgfx.
master_set
Called whenever the minor master is set. Only used by vmwgfx.
master_drop
Called whenever the minor master is dropped. Only used by vmwgfx.
debugfs_init
Allows drivers to create driver-specific debugfs files.
gem_free_object

deconstructor for drm_gem_objects

This is deprecated and should not be used by new drivers. Use gem_free_object_unlocked instead.

gem_free_object_unlocked

deconstructor for drm_gem_objects

This is for drivers which are not encumbered with drm_device.struct_mutex legacy locking schemes. Use this hook instead of gem_free_object.

gem_open_object
Driver hook called upon gem handle creation
gem_close_object
Driver hook called upon gem handle release
gem_print_info

If driver subclasses struct drm_gem_object, it can implement this optional hook for printing additional driver specific info.

drm_printf_indent() should be used in the callback passing it the indent argument.

This callback is called from drm_gem_print_info().

gem_create_object

constructor for gem objects

Hook for allocating the GEM object struct, for use by core helpers.

prime_handle_to_fd
export handle -> fd (see drm_gem_prime_handle_to_fd() helper)
prime_fd_to_handle
import fd -> handle (see drm_gem_prime_fd_to_handle() helper)
gem_prime_export
export GEM -> dmabuf
gem_prime_import
import dmabuf -> GEM
dumb_create

This creates a new dumb buffer in the driver’s backing storage manager (GEM, TTM or something else entirely) and returns the resulting buffer handle. This handle can then be wrapped up into a framebuffer modeset object.

Note that userspace is not allowed to use such objects for render acceleration - drivers must create their own private ioctls for such a use case.

Width, height and depth are specified in the drm_mode_create_dumb argument. The callback needs to fill the handle, pitch and size for the created buffer.

Called by the user via ioctl.

Returns:

Zero on success, negative errno on failure.

dumb_map_offset

Allocate an offset in the drm device node’s address space to be able to memory map a dumb buffer. GEM-based drivers must use drm_gem_create_mmap_offset() to implement this.

Called by the user via ioctl.

Returns:

Zero on success, negative errno on failure.

dumb_destroy

This destroys the userspace handle for the given dumb backing storage buffer. Since buffer objects must be reference counted in the kernel a buffer object won’t be immediately freed if a framebuffer modeset object still uses it.

Called by the user via ioctl.

Returns:

Zero on success, negative errno on failure.

gem_vm_ops
Driver private ops for this object
major
driver major number
minor
driver minor number
patchlevel
driver patch level
name
driver name
desc
driver description
date
driver date
driver_features
driver features
ioctls
Array of driver-private IOCTL description entries. See the chapter on IOCTL support in the userland interfaces chapter for the full details.
num_ioctls
Number of entries in ioctls.
fops
File operations for the DRM device node. See the discussion in file operations for in-depth coverage and some examples.

Description

This structure represent the common code for a family of cards. There will one drm_device for each card present in this family. It contains lots of vfunc entries, and a pile of those probably should be moved to more appropriate places like drm_mode_config_funcs or into a new operations structure for GEM drivers.

int drm_dev_is_unplugged(struct drm_device * dev)

is a DRM device unplugged

Parameters

struct drm_device * dev
DRM device

Description

This function can be called to check whether a hotpluggable is unplugged. Unplugging itself is singalled through drm_dev_unplug(). If a device is unplugged, these two functions guarantee that any store before calling drm_dev_unplug() is visible to callers of this function after it completes

void drm_put_dev(struct drm_device * dev)

Unregister and release a DRM device

Parameters

struct drm_device * dev
DRM device

Description

Called at module unload time or when a PCI device is unplugged.

Cleans up all DRM device, calling drm_lastclose().

Note

Use of this function is deprecated. It will eventually go away completely. Please use drm_dev_unregister() and drm_dev_put() explicitly instead to make sure that the device isn’t userspace accessible any more while teardown is in progress, ensuring that userspace can’t access an inconsistent state.

void drm_dev_unplug(struct drm_device * dev)

unplug a DRM device

Parameters

struct drm_device * dev
DRM device

Description

This unplugs a hotpluggable DRM device, which makes it inaccessible to userspace operations. Entry-points can use drm_dev_is_unplugged(). This essentially unregisters the device like drm_dev_unregister(), but can be called while there are still open users of dev.

int drm_dev_init(struct drm_device * dev, struct drm_driver * driver, struct device * parent)

Initialise new DRM device

Parameters

struct drm_device * dev
DRM device
struct drm_driver * driver
DRM driver
struct device * parent
Parent device object

Description

Initialize a new DRM device. No device registration is done. Call drm_dev_register() to advertice the device to user space and register it with other core subsystems. This should be done last in the device initialization sequence to make sure userspace can’t access an inconsistent state.

The initial ref-count of the object is 1. Use drm_dev_get() and drm_dev_put() to take and drop further ref-counts.

Note that for purely virtual devices parent can be NULL.

Drivers that do not want to allocate their own device struct embedding struct drm_device can call drm_dev_alloc() instead. For drivers that do embed struct drm_device it must be placed first in the overall structure, and the overall structure must be allocated using kmalloc(): The drm core’s release function unconditionally calls kfree() on the dev pointer when the final reference is released. To override this behaviour, and so allow embedding of the drm_device inside the driver’s device struct at an arbitrary offset, you must supply a drm_driver.release callback and control the finalization explicitly.

Return

0 on success, or error code on failure.

void drm_dev_fini(struct drm_device * dev)

Finalize a dead DRM device

Parameters

struct drm_device * dev
DRM device

Description

Finalize a dead DRM device. This is the converse to drm_dev_init() and frees up all data allocated by it. All driver private data should be finalized first. Note that this function does not free the dev, that is left to the caller.

The ref-count of dev must be zero, and drm_dev_fini() should only be called from a drm_driver.release callback.

struct drm_device * drm_dev_alloc(struct drm_driver * driver, struct device * parent)

Allocate new DRM device

Parameters

struct drm_driver * driver
DRM driver to allocate device for
struct device * parent
Parent device object

Description

Allocate and initialize a new DRM device. No device registration is done. Call drm_dev_register() to advertice the device to user space and register it with other core subsystems. This should be done last in the device initialization sequence to make sure userspace can’t access an inconsistent state.

The initial ref-count of the object is 1. Use drm_dev_get() and drm_dev_put() to take and drop further ref-counts.

Note that for purely virtual devices parent can be NULL.

Drivers that wish to subclass or embed struct drm_device into their own struct should look at using drm_dev_init() instead.

Return

Pointer to new DRM device, or ERR_PTR on failure.

void drm_dev_get(struct drm_device * dev)

Take reference of a DRM device

Parameters

struct drm_device * dev
device to take reference of or NULL

Description

This increases the ref-count of dev by one. You must already own a reference when calling this. Use drm_dev_put() to drop this reference again.

This function never fails. However, this function does not provide any guarantee whether the device is alive or running. It only provides a reference to the object and the memory associated with it.

void drm_dev_put(struct drm_device * dev)

Drop reference of a DRM device

Parameters

struct drm_device * dev
device to drop reference of or NULL

Description

This decreases the ref-count of dev by one. The device is destroyed if the ref-count drops to zero.

void drm_dev_unref(struct drm_device * dev)

Drop reference of a DRM device

Parameters

struct drm_device * dev
device to drop reference of or NULL

Description

This is a compatibility alias for drm_dev_put() and should not be used by new code.

int drm_dev_register(struct drm_device * dev, unsigned long flags)

Register DRM device

Parameters

struct drm_device * dev
Device to register
unsigned long flags
Flags passed to the driver’s .:c:func:load() function

Description

Register the DRM device dev with the system, advertise device to user-space and start normal device operation. dev must be allocated via drm_dev_alloc() previously.

Never call this twice on any device!

NOTE

To ensure backward compatibility with existing drivers method this function calls the drm_driver.load method after registering the device nodes, creating race conditions. Usage of the drm_driver.load methods is therefore deprecated, drivers must perform all initialization before calling drm_dev_register().

Return

0 on success, negative error code on failure.

void drm_dev_unregister(struct drm_device * dev)

Unregister DRM device

Parameters

struct drm_device * dev
Device to unregister

Description

Unregister the DRM device from the system. This does the reverse of drm_dev_register() but does not deallocate the device. The caller must call drm_dev_put() to drop their final reference.

A special form of unregistering for hotpluggable devices is drm_dev_unplug(), which can be called while there are still open users of dev.

This should be called first in the device teardown code to make sure userspace can’t access the device instance any more.

int drm_dev_set_unique(struct drm_device * dev, const char * name)

Set the unique name of a DRM device

Parameters

struct drm_device * dev
device of which to set the unique name
const char * name
unique name

Description

Sets the unique name of a DRM device using the specified string. Drivers can use this at driver probe time if the unique name of the devices they drive is static.

Return

0 on success or a negative error code on failure.

Driver Load

IRQ Helper Library

The DRM core provides very simple support helpers to enable IRQ handling on a device through the drm_irq_install() and drm_irq_uninstall() functions. This only supports devices with a single interrupt on the main device stored in drm_device.dev and set as the device paramter in drm_dev_alloc().

These IRQ helpers are strictly optional. Drivers which roll their own only need to set drm_device.irq_enabled to signal the DRM core that vblank interrupts are working. Since these helpers don’t automatically clean up the requested interrupt like e.g. devm_request_irq() they’re not really recommended.

int drm_irq_install(struct drm_device * dev, int irq)

install IRQ handler

Parameters

struct drm_device * dev
DRM device
int irq
IRQ number to install the handler for

Description

Initializes the IRQ related data. Installs the handler, calling the driver drm_driver.irq_preinstall and drm_driver.irq_postinstall functions before and after the installation.

This is the simplified helper interface provided for drivers with no special needs. Drivers which need to install interrupt handlers for multiple interrupts must instead set drm_device.irq_enabled to signal the DRM core that vblank interrupts are available.

irq must match the interrupt number that would be passed to request_irq(), if called directly instead of using this helper function.

drm_driver.irq_handler is called to handle the registered interrupt.

Return

Zero on success or a negative error code on failure.

int drm_irq_uninstall(struct drm_device * dev)

uninstall the IRQ handler

Parameters

struct drm_device * dev
DRM device

Description

Calls the driver’s drm_driver.irq_uninstall function and unregisters the IRQ handler. This should only be called by drivers which used drm_irq_install() to set up their interrupt handler. Other drivers must only reset drm_device.irq_enabled to false.

Note that for kernel modesetting drivers it is a bug if this function fails. The sanity checks are only to catch buggy user modesetting drivers which call the same function through an ioctl.

Return

Zero on success or a negative error code on failure.

Memory Manager Initialization

Every DRM driver requires a memory manager which must be initialized at load time. DRM currently contains two memory managers, the Translation Table Manager (TTM) and the Graphics Execution Manager (GEM). This document describes the use of the GEM memory manager only. See ? for details.

Miscellaneous Device Configuration

Another task that may be necessary for PCI devices during configuration is mapping the video BIOS. On many devices, the VBIOS describes device configuration, LCD panel timings (if any), and contains flags indicating device state. Mapping the BIOS can be done using the pci_map_rom() call, a convenience function that takes care of mapping the actual ROM, whether it has been shadowed into memory (typically at address 0xc0000) or exists on the PCI device in the ROM BAR. Note that after the ROM has been mapped and any necessary information has been extracted, it should be unmapped; on many devices, the ROM address decoder is shared with other BARs, so leaving it mapped could cause undesired behaviour like hangs or memory corruption.

Bus-specific Device Registration and PCI Support

A number of functions are provided to help with device registration. The functions deal with PCI and platform devices respectively and are only provided for historical reasons. These are all deprecated and shouldn’t be used in new drivers. Besides that there’s a few helpers for pci drivers.

drm_dma_handle_t * drm_pci_alloc(struct drm_device * dev, size_t size, size_t align)

Allocate a PCI consistent memory block, for DMA.

Parameters

struct drm_device * dev
DRM device
size_t size
size of block to allocate
size_t align
alignment of block

Description

FIXME: This is a needless abstraction of the Linux dma-api and should be removed.

Return

A handle to the allocated memory block on success or NULL on failure.

void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)

Free a PCI consistent memory block

Parameters

struct drm_device * dev
DRM device
drm_dma_handle_t * dmah
handle to memory block

Description

FIXME: This is a needless abstraction of the Linux dma-api and should be removed.

int drm_get_pci_dev(struct pci_dev * pdev, const struct pci_device_id * ent, struct drm_driver * driver)

Register a PCI device with the DRM subsystem

Parameters

struct pci_dev * pdev
PCI device
const struct pci_device_id * ent
entry from the PCI ID table that matches pdev
struct drm_driver * driver
DRM device driver

Description

Attempt to gets inter module “drm” information. If we are first then register the character device and inter module information. Try and register, if we fail to register, backout previous work.

NOTE

This function is deprecated, please use drm_dev_alloc() and drm_dev_register() instead and remove your drm_driver.load callback.

Return

0 on success or a negative error code on failure.

int drm_legacy_pci_init(struct drm_driver * driver, struct pci_driver * pdriver)

shadow-attach a legacy DRM PCI driver

Parameters

struct drm_driver * driver
DRM device driver
struct pci_driver * pdriver
PCI device driver

Description

This is only used by legacy dri1 drivers and deprecated.

Return

0 on success or a negative error code on failure.

void drm_legacy_pci_exit(struct drm_driver * driver, struct pci_driver * pdriver)

unregister shadow-attach legacy DRM driver

Parameters

struct drm_driver * driver
DRM device driver
struct pci_driver * pdriver
PCI device driver

Description

Unregister a DRM driver shadow-attached through drm_legacy_pci_init(). This is deprecated and only used by dri1 drivers.

Open/Close, File Operations and IOCTLs

File Operations

Drivers must define the file operations structure that forms the DRM userspace API entry point, even though most of those operations are implemented in the DRM core. The resulting struct file_operations must be stored in the drm_driver.fops field. The mandatory functions are drm_open(), drm_read(), drm_ioctl() and drm_compat_ioctl() if CONFIG_COMPAT is enabled Note that drm_compat_ioctl will be NULL if CONFIG_COMPAT=n, so there’s no need to sprinkle #ifdef into the code. Drivers which implement private ioctls that require 32/64 bit compatibility support must provide their own file_operations.compat_ioctl handler that processes private ioctls and calls drm_compat_ioctl() for core ioctls.

In addition drm_read() and drm_poll() provide support for DRM events. DRM events are a generic and extensible means to send asynchronous events to userspace through the file descriptor. They are used to send vblank event and page flip completions by the KMS API. But drivers can also use it for their own needs, e.g. to signal completion of rendering.

For the driver-side event interface see drm_event_reserve_init() and drm_send_event() as the main starting points.

The memory mapping implementation will vary depending on how the driver manages memory. Legacy drivers will use the deprecated drm_legacy_mmap() function, modern drivers should use one of the provided memory-manager specific implementations. For GEM-based drivers this is drm_gem_mmap(), and for drivers which use the CMA GEM helpers it’s drm_gem_cma_mmap().

No other file operations are supported by the DRM userspace API. Overall the following is an example file_operations structure:

static const example_drm_fops = {
        .owner = THIS_MODULE,
        .open = drm_open,
        .release = drm_release,
        .unlocked_ioctl = drm_ioctl,
        .compat_ioctl = drm_compat_ioctl, // NULL if CONFIG_COMPAT=n
        .poll = drm_poll,
        .read = drm_read,
        .llseek = no_llseek,
        .mmap = drm_gem_mmap,
};

For plain GEM based drivers there is the DEFINE_DRM_GEM_FOPS() macro, and for CMA based drivers there is the DEFINE_DRM_GEM_CMA_FOPS() macro to make this simpler.

The driver’s file_operations must be stored in drm_driver.fops.

For driver-private IOCTL handling see the more detailed discussion in IOCTL support in the userland interfaces chapter.

struct drm_minor

DRM device minor structure

Definition

struct drm_minor {
};

Members

Description

This structure represents a DRM minor number for device nodes in /dev. Entirely opaque to drivers and should never be inspected directly by drivers. Drivers instead should only interact with struct drm_file and of course struct drm_device, which is also where driver-private data and resources can be attached to.

struct drm_pending_event

Event queued up for userspace to read

Definition

struct drm_pending_event {
  struct completion *completion;
  void (*completion_release)(struct completion *completion);
  struct drm_event *event;
  struct dma_fence *fence;
  struct drm_file *file_priv;
  struct list_head link;
  struct list_head pending_link;
};

Members

completion
Optional pointer to a kernel internal completion signalled when drm_send_event() is called, useful to internally synchronize with nonblocking operations.
completion_release
Optional callback currently only used by the atomic modeset helpers to clean up the reference count for the structure completion is stored in.
event
Pointer to the actual event that should be sent to userspace to be read using drm_read(). Can be optional, since nowadays events are also used to signal kernel internal threads with completion or DMA transactions using fence.
fence
Optional DMA fence to unblock other hardware transactions which depend upon the nonblocking DRM operation this event represents.
file_priv
struct drm_file where event should be delivered to. Only set when event is set.
link
Double-linked list to keep track of this event. Can be used by the driver up to the point when it calls drm_send_event(), after that this list entry is owned by the core for its own book-keeping.
pending_link
Entry on drm_file.pending_event_list, to keep track of all pending events for file_priv, to allow correct unwinding of them when userspace closes the file before the event is delivered.

Description

This represents a DRM event. Drivers can use this as a generic completion mechanism, which supports kernel-internal struct completion, struct dma_fence and also the DRM-specific struct drm_event delivery mechanism.

struct drm_file

DRM file private data

Definition

struct drm_file {
  unsigned authenticated :1;
  unsigned stereo_allowed :1;
  unsigned universal_planes:1;
  unsigned atomic:1;
  unsigned is_master:1;
  struct drm_master *master;
  struct pid *pid;
  drm_magic_t magic;
  struct list_head lhead;
  struct drm_minor *minor;
  struct idr object_idr;
  spinlock_t table_lock;
  struct idr syncobj_idr;
  spinlock_t syncobj_table_lock;
  struct file *filp;
  void *driver_priv;
  struct list_head fbs;
  struct mutex fbs_lock;
  struct list_head blobs;
  wait_queue_head_t event_wait;
  struct list_head pending_event_list;
  struct list_head event_list;
  int event_space;
  struct mutex event_read_lock;
  struct drm_prime_file_private prime;
};

Members

authenticated

Whether the client is allowed to submit rendering, which for legacy nodes means it must be authenticated.

See also the section on primary nodes and authentication.

stereo_allowed
True when the client has asked us to expose stereo 3D mode flags.
universal_planes
True if client understands CRTC primary planes and cursor planes in the plane list. Automatically set when atomic is set.
atomic
True if client understands atomic properties.
is_master

This client is the creator of master. Protected by struct drm_device.master_mutex.

See also the section on primary nodes and authentication.

master

Master this node is currently associated with. Only relevant if drm_is_primary_client() returns true. Note that this only matches drm_device.master if the master is the currently active one.

See also authentication and is_master and the section on primary nodes and authentication.

pid
Process that opened this file.
magic
Authentication magic, see authenticated.
lhead
List of all open files of a DRM device, linked into drm_device.filelist. Protected by drm_device.filelist_mutex.
minor
struct drm_minor for this file.
object_idr
Mapping of mm object handles to object pointers. Used by the GEM subsystem. Protected by table_lock.
table_lock
Protects object_idr.
syncobj_idr
Mapping of sync object handles to object pointers.
syncobj_table_lock
Protects syncobj_idr.
filp
Pointer to the core file structure.
driver_priv
Optional pointer for driver private data. Can be allocated in drm_driver.open and should be freed in drm_driver.postclose.
fbs

List of struct drm_framebuffer associated with this file, using the drm_framebuffer.filp_head entry.

Protected by fbs_lock. Note that the fbs list holds a reference on the framebuffer object to prevent it from untimely disappearing.

fbs_lock
Protects fbs.
blobs

User-created blob properties; this retains a reference on the property.

Protected by drm_mode_config.blob_lock;

event_wait
Waitqueue for new events added to event_list.
pending_event_list

List of pending struct drm_pending_event, used to clean up pending events in case this file gets closed before the event is signalled. Uses the drm_pending_event.pending_link entry.

Protect by drm_device.event_lock.

event_list

List of struct drm_pending_event, ready for delivery to userspace through drm_read(). Uses the drm_pending_event.link entry.

Protect by drm_device.event_lock.

event_space
Available event space to prevent userspace from exhausting kernel memory. Currently limited to the fairly arbitrary value of 4KB.
event_read_lock
Serializes drm_read().
prime
Per-file buffer caches used by the PRIME buffer sharing code.

Description

This structure tracks DRM state per open file descriptor.

bool drm_is_primary_client(const struct drm_file * file_priv)

is this an open file of the primary node

Parameters

const struct drm_file * file_priv
DRM file

Description

Returns true if this is an open file of the primary node, i.e. drm_file.minor of file_priv is a primary minor.

See also the section on primary nodes and authentication.

bool drm_is_render_client(const struct drm_file * file_priv)

is this an open file of the render node

Parameters

const struct drm_file * file_priv
DRM file

Description

Returns true if this is an open file of the render node, i.e. drm_file.minor of file_priv is a render minor.

See also the section on render nodes.

bool drm_is_control_client(const struct drm_file * file_priv)

is this an open file of the control node

Parameters

const struct drm_file * file_priv
DRM file

Description

Control nodes are deprecated and in the process of getting removed from the DRM userspace API. Do not ever use!

int drm_open(struct inode * inode, struct file * filp)

open method for DRM file

Parameters

struct inode * inode
device inode
struct file * filp
file pointer.

Description

This function must be used by drivers as their file_operations.open method. It looks up the correct DRM device and instantiates all the per-file resources for it. It also calls the drm_driver.open driver callback.

Return

0 on success or negative errno value on falure.

int drm_release(struct inode * inode, struct file * filp)

release method for DRM file

Parameters

struct inode * inode
device inode
struct file * filp
file pointer.

Description

This function must be used by drivers as their file_operations.release method. It frees any resources associated with the open file, and calls the drm_driver.postclose driver callback. If this is the last open file for the DRM device also proceeds to call the drm_driver.lastclose driver callback.

Return

Always succeeds and returns 0.

ssize_t drm_read(struct file * filp, char __user * buffer, size_t count, loff_t * offset)

read method for DRM file

Parameters

struct file * filp
file pointer
char __user * buffer
userspace destination pointer for the read
size_t count
count in bytes to read
loff_t * offset
offset to read

Description

This function must be used by drivers as their file_operations.read method iff they use DRM events for asynchronous signalling to userspace. Since events are used by the KMS API for vblank and page flip completion this means all modern display drivers must use it.

offset is ignored, DRM events are read like a pipe. Therefore drivers also must set the file_operation.llseek to no_llseek(). Polling support is provided by drm_poll().

This function will only ever read a full event. Therefore userspace must supply a big enough buffer to fit any event to ensure forward progress. Since the maximum event space is currently 4K it’s recommended to just use that for safety.

Return

Number of bytes read (always aligned to full events, and can be 0) or a negative error code on failure.

__poll_t drm_poll(struct file * filp, struct poll_table_struct * wait)

poll method for DRM file

Parameters

struct file * filp
file pointer
struct poll_table_struct * wait
poll waiter table

Description

This function must be used by drivers as their file_operations.read method iff they use DRM events for asynchronous signalling to userspace. Since events are used by the KMS API for vblank and page flip completion this means all modern display drivers must use it.

See also drm_read().

Return

Mask of POLL flags indicating the current status of the file.

int drm_event_reserve_init_locked(struct drm_device * dev, struct drm_file * file_priv, struct drm_pending_event * p, struct drm_event * e)

init a DRM event and reserve space for it

Parameters

struct drm_device * dev
DRM device
struct drm_file * file_priv
DRM file private data
struct drm_pending_event * p
tracking structure for the pending event
struct drm_event * e
actual event data to deliver to userspace

Description

This function prepares the passed in event for eventual delivery. If the event doesn’t get delivered (because the IOCTL fails later on, before queuing up anything) then the even must be cancelled and freed using drm_event_cancel_free(). Successfully initialized events should be sent out using drm_send_event() or drm_send_event_locked() to signal completion of the asynchronous event to userspace.

If callers embedded p into a larger structure it must be allocated with kmalloc and p must be the first member element.

This is the locked version of drm_event_reserve_init() for callers which already hold drm_device.event_lock.

Return

0 on success or a negative error code on failure.

int drm_event_reserve_init(struct drm_device * dev, struct drm_file * file_priv, struct drm_pending_event * p, struct drm_event * e)

init a DRM event and reserve space for it

Parameters

struct drm_device * dev
DRM device
struct drm_file * file_priv
DRM file private data
struct drm_pending_event * p
tracking structure for the pending event
struct drm_event * e
actual event data to deliver to userspace

Description

This function prepares the passed in event for eventual delivery. If the event doesn’t get delivered (because the IOCTL fails later on, before queuing up anything) then the even must be cancelled and freed using drm_event_cancel_free(). Successfully initialized events should be sent out using drm_send_event() or drm_send_event_locked() to signal completion of the asynchronous event to userspace.

If callers embedded p into a larger structure it must be allocated with kmalloc and p must be the first member element.

Callers which already hold drm_device.event_lock should use drm_event_reserve_init_locked() instead.

Return

0 on success or a negative error code on failure.

void drm_event_cancel_free(struct drm_device * dev, struct drm_pending_event * p)

free a DRM event and release it’s space

Parameters

struct drm_device * dev
DRM device
struct drm_pending_event * p
tracking structure for the pending event

Description

This function frees the event p initialized with drm_event_reserve_init() and releases any allocated space. It is used to cancel an event when the nonblocking operation could not be submitted and needed to be aborted.

void drm_send_event_locked(struct drm_device * dev, struct drm_pending_event * e)

send DRM event to file descriptor

Parameters

struct drm_device * dev
DRM device
struct drm_pending_event * e
DRM event to deliver

Description

This function sends the event e, initialized with drm_event_reserve_init(), to its associated userspace DRM file. Callers must already hold drm_device.event_lock, see drm_send_event() for the unlocked version.

Note that the core will take care of unlinking and disarming events when the corresponding DRM file is closed. Drivers need not worry about whether the DRM file for this event still exists and can call this function upon completion of the asynchronous work unconditionally.

void drm_send_event(struct drm_device * dev, struct drm_pending_event * e)

send DRM event to file descriptor

Parameters

struct drm_device * dev
DRM device
struct drm_pending_event * e
DRM event to deliver

Description

This function sends the event e, initialized with drm_event_reserve_init(), to its associated userspace DRM file. This function acquires drm_device.event_lock, see drm_send_event_locked() for callers which already hold this lock.

Note that the core will take care of unlinking and disarming events when the corresponding DRM file is closed. Drivers need not worry about whether the DRM file for this event still exists and can call this function upon completion of the asynchronous work unconditionally.

Misc Utilities

Printer

A simple wrapper for dev_printk(), seq_printf(), etc. Allows same debug code to be used for both debugfs and printk logging.

For example:

void log_some_info(struct drm_printer *p)
{
        drm_printf(p, "foo=``d``\n", foo);
        drm_printf(p, "bar=``d``\n", bar);
}

#ifdef CONFIG_DEBUG_FS
void debugfs_show(struct seq_file *f)
{
        struct drm_printer p = drm_seq_file_printer(f);
        log_some_info(:c:type:`p`);
}
#endif

void some_other_function(...)
{
        struct drm_printer p = drm_info_printer(drm->dev);
        log_some_info(:c:type:`p`);
}
struct drm_printer

drm output “stream”

Definition

struct drm_printer {
};

Members

Description

Do not use struct members directly. Use drm_printer_seq_file(), drm_printer_info(), etc to initialize. And drm_printf() for output.

void drm_vprintf(struct drm_printer * p, const char * fmt, va_list * va)

print to a drm_printer stream

Parameters

struct drm_printer * p
the drm_printer
const char * fmt
format string
va_list * va
the va_list
drm_printf_indent(printer, indent, fmt, ...)

Print to a drm_printer stream with indentation

Parameters

printer
DRM printer
indent
Tab indentation level (max 5)
fmt
Format string
...
variable arguments
struct drm_printer drm_seq_file_printer(struct seq_file * f)

construct a drm_printer that outputs to seq_file

Parameters

struct seq_file * f
the struct seq_file to output to

Return

The drm_printer object

struct drm_printer drm_info_printer(struct device * dev)

construct a drm_printer that outputs to dev_printk()

Parameters

struct device * dev
the struct device pointer

Return

The drm_printer object

struct drm_printer drm_debug_printer(const char * prefix)

construct a drm_printer that outputs to pr_debug()

Parameters

const char * prefix
debug output prefix

Return

The drm_printer object

DRM_DEV_ERROR(dev, fmt, ...)

Parameters

dev
device pointer
fmt
printf() like format string.
...
variable arguments
DRM_DEV_ERROR_RATELIMITED(dev, fmt, ...)

Parameters

dev
device pointer
fmt
printf() like format string.
...
variable arguments
DRM_DEV_DEBUG(dev, fmt, args...)

Parameters

dev
device pointer
fmt
printf() like format string.
args...
variable arguments
DRM_DEV_DEBUG_RATELIMITED(dev, fmt, args...)

Parameters

dev
device pointer
fmt
printf() like format string.
args...
variable arguments
void drm_printf(struct drm_printer * p, const char * f, ...)

print to a drm_printer stream

Parameters

struct drm_printer * p
the drm_printer
const char * f
format string
...
variable arguments

Legacy Support Code

The section very briefly covers some of the old legacy support code which is only used by old DRM drivers which have done a so-called shadow-attach to the underlying device instead of registering as a real driver. This also includes some of the old generic buffer management and command submission code. Do not use any of this in new and modern drivers.

Legacy Suspend/Resume

The DRM core provides some suspend/resume code, but drivers wanting full suspend/resume support should provide save() and restore() functions. These are called at suspend, hibernate, or resume time, and should perform any state save or restore required by your device across suspend or hibernate states.

int (*suspend) (struct drm_device *, pm_message_t state); int (*resume) (struct drm_device *); Those are legacy suspend and resume methods which only work with the legacy shadow-attach driver registration functions. New driver should use the power management interface provided by their bus type (usually through the struct device_driver dev_pm_ops) and set these methods to NULL.

Legacy DMA Services

This should cover how DMA mapping etc. is supported by the core. These functions are deprecated and should not be used.