drm/doc: Document drm_file.[hc]

Well, mostly drm_file.h, and clean up all related things:

- I didnt' figure out the difference between preclose and postclose.
  The existing explanation in drm-internals.rst didn't convince me,
  since it's also really outdated - we clean up pending DRM events in
  the core nowadays. I put a FIXME in for the future.

- Another FIXME is to have a macro for default fops.

- Lots of links all around, main areas are to tie the overview in
  drm_file.c more into the callbacks in struct drm_device, and the
  other is to link render/primary node code to the right sections in
  drm-uapi.rst.

- Also moved the open/close stuff to drm_drv.h from drm-internals.rst,
  seems like the better place for that information. Since that section
  was rather outdated this amounted to full-on rewrite.

A big missing piece here is some overview graph, but I think better to
wait with that one until drm_device and drm_driver are also fully
documented.

v2: Nits from Sean.

Reviewed-by: Sean Paul <seanpaul@chromium.org>
Reviewed-by: Liviu Dudau <Liviu.Dudau@arm.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170308141257.12119-12-daniel.vetter@ffwll.ch
This commit is contained in:
Daniel Vetter 2017-03-08 15:12:44 +01:00
parent 7d52cb88c9
commit b93658f83f
5 changed files with 359 additions and 119 deletions

View file

@ -243,61 +243,15 @@ drivers.
Open/Close, File Operations and IOCTLs
======================================
Open and Close
--------------
Open and close handlers. None of those methods are mandatory::
int (*firstopen) (struct drm_device *);
void (*lastclose) (struct drm_device *);
int (*open) (struct drm_device *, struct drm_file *);
void (*preclose) (struct drm_device *, struct drm_file *);
void (*postclose) (struct drm_device *, struct drm_file *);
The firstopen method is called by the DRM core for legacy UMS (User Mode
Setting) drivers only when an application opens a device that has no
other opened file handle. UMS drivers can implement it to acquire device
resources. KMS drivers can't use the method and must acquire resources
in the load method instead.
Similarly the lastclose method is called when the last application
holding a file handle opened on the device closes it, for both UMS and
KMS drivers. Additionally, the method is also called at module unload
time or, for hot-pluggable devices, when the device is unplugged. The
firstopen and lastclose calls can thus be unbalanced.
The open method is called every time the device is opened by an
application. Drivers can allocate per-file private data in this method
and store them in the struct :c:type:`struct drm_file
<drm_file>` driver_priv field. Note that the open method is
called before firstopen.
The close operation is split into preclose and postclose methods.
Drivers must stop and cleanup all per-file operations in the preclose
method. For instance pending vertical blanking and page flip events must
be cancelled. No per-file operation is allowed on the file handle after
returning from the preclose method.
Finally the postclose method is called as the last step of the close
operation, right before calling the lastclose method if no other open
file handle exists for the device. Drivers that have allocated per-file
private data in the open method should free it here.
The lastclose method should restore CRTC and plane properties to default
value, so that a subsequent open of the device will not inherit state
from the previous user. It can also be used to execute delayed power
switching state changes, e.g. in conjunction with the :ref:`vga_switcheroo`
infrastructure. Beyond that KMS drivers should not do any
further cleanup. Only legacy UMS drivers might need to clean up device
state so that the vga console or an independent fbdev driver could take
over.
File Operations
---------------
.. kernel-doc:: drivers/gpu/drm/drm_file.c
:doc: file operations
.. kernel-doc:: include/drm/drm_file.h
:internal:
.. kernel-doc:: drivers/gpu/drm/drm_file.c
:export:

View file

@ -21,6 +21,8 @@ libdrm Device Lookup
:doc: getunique and setversion story
.. _drm_primary_node:
Primary Nodes, DRM Master and Authentication
============================================
@ -103,6 +105,8 @@ is already rather painful for the DRM subsystem, with multiple different uAPIs
for the same thing co-existing. If we add a few more complete mistakes into the
mix every year it would be entirely unmanageable.
.. _drm_render_node:
Render nodes
============

View file

@ -50,12 +50,14 @@ DEFINE_MUTEX(drm_global_mutex);
*
* 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 mandatory functions are drm_open(),
* 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). Drivers which
* implement private ioctls that require 32/64 bit compatibility support must
* provide their own .compat_ioctl() handler that processes private ioctls and
* calls drm_compat_ioctl() for core ioctls.
* 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
@ -63,10 +65,14 @@ DEFINE_MUTEX(drm_global_mutex);
* 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().
* 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::
@ -82,6 +88,9 @@ DEFINE_MUTEX(drm_global_mutex);
* .llseek = no_llseek,
* .mmap = drm_gem_mmap,
* };
*
* FIXME: We should have a macro for this (and the CMA version) so that drivers
* don't have to repeat it all the time.
*/
static int drm_open_helper(struct file *filp, struct drm_minor *minor);
@ -111,9 +120,9 @@ static int drm_setup(struct drm_device * dev)
* @inode: device inode
* @filp: file pointer.
*
* This function must be used by drivers as their .open() #file_operations
* method. It looks up the correct DRM device and instantiates all the per-file
* resources for it.
* 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.
*
* RETURNS:
*
@ -298,11 +307,6 @@ static void drm_events_release(struct drm_file *file_priv)
spin_unlock_irqrestore(&dev->event_lock, flags);
}
/*
* drm_legacy_dev_reinit
*
* Reinitializes a legacy/ums drm device in it's lastclose function.
*/
static void drm_legacy_dev_reinit(struct drm_device *dev)
{
if (dev->irq_enabled)
@ -327,15 +331,6 @@ static void drm_legacy_dev_reinit(struct drm_device *dev)
DRM_DEBUG("lastclose completed\n");
}
/*
* Take down the DRM device.
*
* \param dev DRM device structure.
*
* Frees every resource in \p dev.
*
* \sa drm_device
*/
void drm_lastclose(struct drm_device * dev)
{
DRM_DEBUG("\n");
@ -353,9 +348,11 @@ void drm_lastclose(struct drm_device * dev)
* @inode: device inode
* @filp: file pointer.
*
* This function must be used by drivers as their .release() #file_operations
* method. It frees any resources associated with the open file, and if this is
* the last open file for the DRM device also proceeds to call drm_lastclose().
* 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.preclose and &drm_driver.lastclose driver callbacks. If this is
* the last open file for the DRM device also proceeds to call the
* &drm_driver.lastclose driver callback.
*
* RETURNS:
*
@ -443,13 +440,13 @@ EXPORT_SYMBOL(drm_release);
* @count: count in bytes to read
* @offset: offset to read
*
* This function must be used by drivers as their .read() #file_operations
* 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 ignore, DRM events are read like a pipe. Therefore drivers also
* must set the .llseek() #file_operation to no_llseek(). Polling support is
* @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
@ -537,10 +534,10 @@ EXPORT_SYMBOL(drm_read);
* @filp: file pointer
* @wait: poll waiter table
*
* This function must be used by drivers as their .read() #file_operations
* 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.
* 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().
*
@ -650,7 +647,8 @@ EXPORT_SYMBOL(drm_event_reserve_init);
* @p: tracking structure for the pending event
*
* This function frees the event @p initialized with drm_event_reserve_init()
* and releases any allocated space.
* 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_event_cancel_free(struct drm_device *dev,
struct drm_pending_event *p)

View file

@ -64,7 +64,6 @@ struct drm_mode_create_dumb;
* structure for GEM drivers.
*/
struct drm_driver {
/**
* @load:
*
@ -76,14 +75,94 @@ struct drm_driver {
* 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.
*/
int (*load) (struct drm_device *, unsigned long flags);
/**
* @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.
*/
int (*open) (struct drm_device *, struct drm_file *);
/**
* @preclose:
*
* 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.
*
* FIXME: It is not really clear why there's both @preclose and
* @postclose. Without a really good reason, use @postclose only.
*/
void (*preclose) (struct drm_device *, struct drm_file *file_priv);
/**
* @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.
*
* FIXME: It is not really clear why there's both @preclose and
* @postclose. Without a really good reason, use @postclose only.
*/
void (*postclose) (struct drm_device *, struct drm_file *);
/**
* @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 :ref:`vga_switcheroo`
* infrastructure.
*
* This is called after @preclose and @postclose have 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.
*/
void (*lastclose) (struct drm_device *);
/**

View file

@ -45,6 +45,7 @@ struct drm_device;
* FIXME: Not sure we want to have drm_minor here in the end, but to avoid
* header include loops we need it here for now.
*/
enum drm_minor_type {
DRM_MINOR_PRIMARY,
DRM_MINOR_CONTROL,
@ -52,12 +53,19 @@ enum drm_minor_type {
};
/**
* DRM minor structure. This structure represents a drm minor number.
* struct drm_minor - DRM device minor structure
*
* 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_minor {
int index; /**< Minor device number */
int type; /**< Control or render */
struct device *kdev; /**< Linux device */
/* private: */
int index; /* Minor device number */
int type; /* Control or render */
struct device *kdev; /* Linux device */
struct drm_device *dev;
struct dentry *debugfs_root;
@ -66,89 +74,286 @@ struct drm_minor {
struct mutex debugfs_lock; /* Protects debugfs_list. */
};
/* Event queued up for userspace to read */
/**
* struct drm_pending_event - Event queued up for userspace to read
*
* 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_pending_event {
/**
* @completion:
*
* Optional pointer to a kernel internal completion signalled when
* drm_send_event() is called, useful to internally synchronize with
* nonblocking operations.
*/
struct completion *completion;
/**
* @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.
*/
void (*completion_release)(struct completion *completion);
/**
* @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.
*/
struct drm_event *event;
/**
* @fence:
*
* Optional DMA fence to unblock other hardware transactions which
* depend upon the nonblocking DRM operation this event represents.
*/
struct dma_fence *fence;
struct list_head link;
struct list_head pending_link;
/**
* @file_priv:
*
* &struct drm_file where @event should be delivered to. Only set when
* @event is set.
*/
struct drm_file *file_priv;
/**
* @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.
*/
struct list_head link;
/**
* @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.
*/
struct list_head pending_link;
};
/** File private data */
/**
* struct drm_file - DRM file private data
*
* This structure tracks DRM state per open file descriptor.
*/
struct drm_file {
/**
* @authenticated:
*
* Whether the client is allowed to submit rendering, which for legacy
* nodes means it must be authenticated.
*
* See also the :ref:`section on primary nodes and authentication
* <drm_primary_node>`.
*/
unsigned authenticated :1;
/* true when the client has asked us to expose stereo 3D mode flags */
/**
* @stereo_allowed:
*
* True when the client has asked us to expose stereo 3D mode flags.
*/
unsigned stereo_allowed :1;
/*
* true if client understands CRTC primary planes and cursor planes
* in the plane list
/**
* @universal_planes:
*
* True if client understands CRTC primary planes and cursor planes
* in the plane list. Automatically set when @atomic is set.
*/
unsigned universal_planes:1;
/* true if client understands atomic properties */
/** @atomic: True if client understands atomic properties. */
unsigned atomic:1;
/*
* This client is the creator of @master.
* Protected by struct drm_device::master_mutex.
/**
* @is_master:
*
* This client is the creator of @master. Protected by struct
* &drm_device.master_mutex.
*
* See also the :ref:`section on primary nodes and authentication
* <drm_primary_node>`.
*/
unsigned is_master:1;
struct pid *pid;
drm_magic_t magic;
struct list_head lhead;
struct drm_minor *minor;
unsigned long lock_count;
/**
* @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 :ref:`section on
* primary nodes and authentication <drm_primary_node>`.
*/
struct drm_master *master;
/** Mapping of mm object handles to object pointers. */
/** @pid: Process that opened this file. */
struct pid *pid;
/** @magic: Authentication magic, see @authenticated. */
drm_magic_t magic;
/**
* @lhead:
*
* List of all open files of a DRM device, linked into
* &drm_device.filelist. Protected by &drm_device.filelist_mutex.
*/
struct list_head lhead;
/** @minor: &struct drm_minor for this file. */
struct drm_minor *minor;
/**
* @object_idr:
*
* Mapping of mm object handles to object pointers. Used by the GEM
* subsystem. Protected by @table_lock.
*/
struct idr object_idr;
/** Lock for synchronization of access to object_idr. */
/** @table_lock: Protects @object_idr. */
spinlock_t table_lock;
/** @filp: Pointer to the core file structure. */
struct file *filp;
/**
* @driver_priv:
*
* Optional pointer for driver private data. Can be allocated in
* &drm_driver.open and should be freed in &drm_driver.postclose.
*/
void *driver_priv;
struct drm_master *master; /* master this node is currently associated with
N.B. not always dev->master */
/**
* fbs - List of framebuffers associated with this file.
* @fbs:
*
* Protected by fbs_lock. Note that the fbs list holds a reference on
* the fb object to prevent it from untimely disappearing.
* 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.
*/
struct list_head fbs;
/** @fbs_lock: Protects @fbs. */
struct mutex fbs_lock;
/** User-created blob properties; this retains a reference on the
* property. */
/**
* @blobs:
*
* User-created blob properties; this retains a reference on the
* property.
*
* Protected by @drm_mode_config.blob_lock;
*/
struct list_head blobs;
/** @event_wait: Waitqueue for new events added to @event_list. */
wait_queue_head_t event_wait;
/**
* @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.
*/
struct list_head pending_event_list;
/**
* @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.
*/
struct list_head event_list;
/**
* @event_space:
*
* Available event space to prevent userspace from
* exhausting kernel memory. Currently limited to the fairly arbitrary
* value of 4KB.
*/
int event_space;
/** @event_read_lock: Serializes drm_read(). */
struct mutex event_read_lock;
/**
* @prime:
*
* Per-file buffer caches used by the PRIME buffer sharing code.
*/
struct drm_prime_file_private prime;
/* private: */
unsigned long lock_count; /* DRI1 legacy lock count */
};
/**
* drm_is_primary_client - is this an open file of the primary node
* @file_priv: DRM file
*
* 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 :ref:`section on primary nodes and authentication
* <drm_primary_node>`.
*/
static inline bool drm_is_primary_client(const struct drm_file *file_priv)
{
return file_priv->minor->type == DRM_MINOR_PRIMARY;
}
/**
* drm_is_render_client - is this an open file of the render node
* @file_priv: DRM file
*
* 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 :ref:`section on render nodes <drm_render_node>`.
*/
static inline bool drm_is_render_client(const struct drm_file *file_priv)
{
return file_priv->minor->type == DRM_MINOR_RENDER;
}
/**
* drm_is_control_client - is this an open file of the control node
* @file_priv: DRM file
*
* Control nodes are deprecated and in the process of getting removed from the
* DRM userspace API. Do not ever use!
*/
static inline bool drm_is_control_client(const struct drm_file *file_priv)
{
return file_priv->minor->type == DRM_MINOR_CONTROL;
}
static inline bool drm_is_primary_client(const struct drm_file *file_priv)
{
return file_priv->minor->type == DRM_MINOR_PRIMARY;
}
int drm_open(struct inode *inode, struct file *filp);
ssize_t drm_read(struct file *filp, char __user *buffer,
size_t count, loff_t *offset);