diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2017-03-08 15:12:44 +0100 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2017-03-14 14:38:33 +0100 |
commit | b93658f83fa7f89cde5cfba7158da2be8cac42b2 (patch) | |
tree | fd39bd7cc02e2d6f40734b252474c0265af3ab81 /include | |
parent | 7d52cb88c9ca20c32288de6ed62b32410c936ccc (diff) |
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
Diffstat (limited to 'include')
-rw-r--r-- | include/drm/drm_drv.h | 81 | ||||
-rw-r--r-- | include/drm/drm_file.h | 265 |
2 files changed, 315 insertions, 31 deletions
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index 4321d012c4ba..8f900fb30275 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -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 *); /** diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h index 4e347399a7bd..5dd27ae5c47c 100644 --- a/include/drm/drm_file.h +++ b/include/drm/drm_file.h @@ -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; + + /** + * @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; - struct drm_file *file_priv; }; -/** 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; + /** + * @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; + + /** @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; - unsigned long lock_count; - /** Mapping of mm object handles to object pointers. */ + /** + * @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: + * + * 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 fb object to prevent it from untimely disappearing. + * 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); |