1107 lines · 40.0 KB · C
RawDownload
/* * Copyright (C) 2014 Red Hat * Copyright (C) 2014 Intel Corp. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Rob Clark <robdclark@gmail.com> * Daniel Vetter <daniel.vetter@ffwll.ch> */ #ifndef DRM_ATOMIC_H_#define DRM_ATOMIC_H_ #include <drm/drm_crtc.h>#include <drm/drm_util.h> /** * struct drm_crtc_commit - track modeset commits on a CRTC * * This structure is used to track pending modeset changes and atomic commit on * a per-CRTC basis. Since updating the list should never block, this structure * is reference counted to allow waiters to safely wait on an event to complete, * without holding any locks. * * It has 3 different events in total to allow a fine-grained synchronization * between outstanding updates:: * *	atomic commit thread			hardware * * 	write new state into hardware	---->	... * 	signal hw_done * 						switch to new state on next * 	...					v/hblank * *	wait for buffers to show up		... * *	...					send completion irq *						irq handler signals flip_done *	cleanup old buffers * * 	signal cleanup_done * * 	wait for flip_done		<---- * 	clean up atomic state * * The important bit to know is that &cleanup_done is the terminal event, but the * ordering between &flip_done and &hw_done is entirely up to the specific driver * and modeset state change. * * For an implementation of how to use this look at * drm_atomic_helper_setup_commit() from the atomic helper library. * * See also drm_crtc_commit_wait(). */struct drm_crtc_commit {	/**	 * @crtc:	 *	 * DRM CRTC for this commit.	 */	struct drm_crtc *crtc; 	/**	 * @ref:	 *	 * Reference count for this structure. Needed to allow blocking on	 * completions without the risk of the completion disappearing	 * meanwhile.	 */	struct kref ref; 	/**	 * @flip_done:	 *	 * Will be signaled when the hardware has flipped to the new set of	 * buffers. Signals at the same time as when the drm event for this	 * commit is sent to userspace, or when an out-fence is singalled. Note	 * that for most hardware, in most cases this happens after @hw_done is	 * signalled.	 *	 * Completion of this stage is signalled implicitly by calling	 * drm_crtc_send_vblank_event() on &drm_crtc_state.event.	 */	struct completion flip_done; 	/**	 * @hw_done:	 *	 * Will be signalled when all hw register changes for this commit have	 * been written out. Especially when disabling a pipe this can be much	 * later than @flip_done, since that can signal already when the	 * screen goes black, whereas to fully shut down a pipe more register	 * I/O is required.	 *	 * Note that this does not need to include separately reference-counted	 * resources like backing storage buffer pinning, or runtime pm	 * management.	 *	 * Drivers should call drm_atomic_helper_commit_hw_done() to signal	 * completion of this stage.	 */	struct completion hw_done; 	/**	 * @cleanup_done:	 *	 * Will be signalled after old buffers have been cleaned up by calling	 * drm_atomic_helper_cleanup_planes(). Since this can only happen after	 * a vblank wait completed it might be a bit later. This completion is	 * useful to throttle updates and avoid hardware updates getting ahead	 * of the buffer cleanup too much.	 *	 * Drivers should call drm_atomic_helper_commit_cleanup_done() to signal	 * completion of this stage.	 */	struct completion cleanup_done; 	/**	 * @commit_entry:	 *	 * Entry on the per-CRTC &drm_crtc.commit_list. Protected by	 * $drm_crtc.commit_lock.	 */	struct list_head commit_entry; 	/**	 * @event:	 *	 * &drm_pending_vblank_event pointer to clean up private events.	 */	struct drm_pending_vblank_event *event; 	/**	 * @abort_completion:	 *	 * A flag that's set after drm_atomic_helper_setup_commit() takes a	 * second reference for the completion of $drm_crtc_state.event. It's	 * used by the free code to remove the second reference if commit fails.	 */	bool abort_completion;}; struct __drm_planes_state {	struct drm_plane *ptr;	struct drm_plane_state *state, *old_state, *new_state;}; struct __drm_crtcs_state {	struct drm_crtc *ptr;	struct drm_crtc_state *state, *old_state, *new_state; 	/**	 * @commit:	 *	 * A reference to the CRTC commit object that is kept for use by	 * drm_atomic_helper_wait_for_flip_done() after	 * drm_atomic_helper_commit_hw_done() is called. This ensures that a	 * concurrent commit won't free a commit object that is still in use.	 */	struct drm_crtc_commit *commit; 	s32 __user *out_fence_ptr;	u64 last_vblank_count;}; struct __drm_connnectors_state {	struct drm_connector *ptr;	struct drm_connector_state *state, *old_state, *new_state;	/**	 * @out_fence_ptr:	 *	 * User-provided pointer which the kernel uses to return a sync_file	 * file descriptor. Used by writeback connectors to signal completion of	 * the writeback.	 */	s32 __user *out_fence_ptr;}; struct drm_private_obj;struct drm_private_state; /** * struct drm_private_state_funcs - atomic state functions for private objects * * These hooks are used by atomic helpers to create, swap and destroy states of * private objects. The structure itself is used as a vtable to identify the * associated private object type. Each private object type that needs to be * added to the atomic states is expected to have an implementation of these * hooks and pass a pointer to its drm_private_state_funcs struct to * drm_atomic_get_private_obj_state(). */struct drm_private_state_funcs {	/**	 * @atomic_duplicate_state:	 *	 * Duplicate the current state of the private object and return it. It	 * is an error to call this before obj->state has been initialized.	 *	 * RETURNS:	 *	 * Duplicated atomic state or NULL when obj->state is not	 * initialized or allocation failed.	 */	struct drm_private_state *(*atomic_duplicate_state)(struct drm_private_obj *obj); 	/**	 * @atomic_destroy_state:	 *	 * Frees the private object state created with @atomic_duplicate_state.	 */	void (*atomic_destroy_state)(struct drm_private_obj *obj,				     struct drm_private_state *state);}; /** * struct drm_private_obj - base struct for driver private atomic object * * A driver private object is initialized by calling * drm_atomic_private_obj_init() and cleaned up by calling * drm_atomic_private_obj_fini(). * * Currently only tracks the state update functions and the opaque driver * private state itself, but in the future might also track which * &drm_modeset_lock is required to duplicate and update this object's state. * * All private objects must be initialized before the DRM device they are * attached to is registered to the DRM subsystem (call to drm_dev_register()) * and should stay around until this DRM device is unregistered (call to * drm_dev_unregister()). In other words, private objects lifetime is tied * to the DRM device lifetime. This implies that: * * 1/ all calls to drm_atomic_private_obj_init() must be done before calling *    drm_dev_register() * 2/ all calls to drm_atomic_private_obj_fini() must be done after calling *    drm_dev_unregister() * * If that private object is used to store a state shared by multiple * CRTCs, proper care must be taken to ensure that non-blocking commits are * properly ordered to avoid a use-after-free issue. * * Indeed, assuming a sequence of two non-blocking &drm_atomic_commit on two * different &drm_crtc using different &drm_plane and &drm_connector, so with no * resources shared, there's no guarantee on which commit is going to happen * first. However, the second &drm_atomic_commit will consider the first * &drm_private_obj its old state, and will be in charge of freeing it whenever * the second &drm_atomic_commit is done. * * If the first &drm_atomic_commit happens after it, it will consider its * &drm_private_obj the new state and will be likely to access it, resulting in * an access to a freed memory region. Drivers should store (and get a reference * to) the &drm_crtc_commit structure in our private state in * &drm_mode_config_helper_funcs.atomic_commit_setup, and then wait for that * commit to complete as the first step of * &drm_mode_config_helper_funcs.atomic_commit_tail, similar to * drm_atomic_helper_wait_for_dependencies(). */struct drm_private_obj {	/**	 * @head: List entry used to attach a private object to a &drm_device	 * (queued to &drm_mode_config.privobj_list).	 */	struct list_head head; 	/**	 * @lock: Modeset lock to protect the state object.	 */	struct drm_modeset_lock lock; 	/**	 * @state: Current atomic state for this driver private object.	 */	struct drm_private_state *state; 	/**	 * @funcs:	 *	 * Functions to manipulate the state of this driver private object, see	 * &drm_private_state_funcs.	 */	const struct drm_private_state_funcs *funcs;}; /** * drm_for_each_privobj() - private object iterator * * @privobj: pointer to the current private object. Updated after each *	     iteration * @dev: the DRM device we want get private objects from * * Allows one to iterate over all private objects attached to @dev */#define drm_for_each_privobj(privobj, dev) \	list_for_each_entry(privobj, &(dev)->mode_config.privobj_list, head) /** * struct drm_private_state - base struct for driver private object state * @state: backpointer to global drm_atomic_state * * Currently only contains a backpointer to the overall atomic update, but in * the future also might hold synchronization information similar to e.g. * &drm_crtc.commit. */struct drm_private_state {	struct drm_atomic_state *state;}; struct __drm_private_objs_state {	struct drm_private_obj *ptr;	struct drm_private_state *state, *old_state, *new_state;}; /** * struct drm_atomic_state - the global state object for atomic updates * @ref: count of all references to this state (will not be freed until zero) * @dev: parent DRM device * @async_update: hint for asynchronous plane update * @planes: pointer to array of structures with per-plane data * @crtcs: pointer to array of CRTC pointers * @num_connector: size of the @connectors and @connector_states arrays * @connectors: pointer to array of structures with per-connector data * @num_private_objs: size of the @private_objs array * @private_objs: pointer to array of private object pointers * @acquire_ctx: acquire context for this atomic modeset state update * * States are added to an atomic update by calling drm_atomic_get_crtc_state(), * drm_atomic_get_plane_state(), drm_atomic_get_connector_state(), or for * private state structures, drm_atomic_get_private_obj_state(). */struct drm_atomic_state {	struct kref ref; 	struct drm_device *dev; 	/**	 * @allow_modeset:	 *	 * Allow full modeset. This is used by the ATOMIC IOCTL handler to	 * implement the DRM_MODE_ATOMIC_ALLOW_MODESET flag. Drivers should	 * never consult this flag, instead looking at the output of	 * drm_atomic_crtc_needs_modeset().	 */	bool allow_modeset : 1;	/**	 * @legacy_cursor_update:	 *	 * Hint to enforce legacy cursor IOCTL semantics.	 *	 * WARNING: This is thoroughly broken and pretty much impossible to	 * implement correctly. Drivers must ignore this and should instead	 * implement &drm_plane_helper_funcs.atomic_async_check and	 * &drm_plane_helper_funcs.atomic_async_commit hooks. New users of this	 * flag are not allowed.	 */	bool legacy_cursor_update : 1;	bool async_update : 1;	/**	 * @duplicated:	 *	 * Indicates whether or not this atomic state was duplicated using	 * drm_atomic_helper_duplicate_state(). Drivers and atomic helpers	 * should use this to fixup normal  inconsistencies in duplicated	 * states.	 */	bool duplicated : 1;	struct __drm_planes_state *planes;	struct __drm_crtcs_state *crtcs;	int num_connector;	struct __drm_connnectors_state *connectors;	int num_private_objs;	struct __drm_private_objs_state *private_objs; 	struct drm_modeset_acquire_ctx *acquire_ctx; 	/**	 * @fake_commit:	 *	 * Used for signaling unbound planes/connectors.	 * When a connector or plane is not bound to any CRTC, it's still important	 * to preserve linearity to prevent the atomic states from being freed to early.	 *	 * This commit (if set) is not bound to any CRTC, but will be completed when	 * drm_atomic_helper_commit_hw_done() is called.	 */	struct drm_crtc_commit *fake_commit; 	/**	 * @commit_work:	 *	 * Work item which can be used by the driver or helpers to execute the	 * commit without blocking.	 */	struct work_struct commit_work;}; void __drm_crtc_commit_free(struct kref *kref); /** * drm_crtc_commit_get - acquire a reference to the CRTC commit * @commit: CRTC commit * * Increases the reference of @commit. * * Returns: * The pointer to @commit, with reference increased. */static inline struct drm_crtc_commit *drm_crtc_commit_get(struct drm_crtc_commit *commit){	kref_get(&commit->ref);	return commit;} /** * drm_crtc_commit_put - release a reference to the CRTC commmit * @commit: CRTC commit * * This releases a reference to @commit which is freed after removing the * final reference. No locking required and callable from any context. */static inline void drm_crtc_commit_put(struct drm_crtc_commit *commit){	kref_put(&commit->ref, __drm_crtc_commit_free);} int drm_crtc_commit_wait(struct drm_crtc_commit *commit); struct drm_atomic_state * __must_checkdrm_atomic_state_alloc(struct drm_device *dev);void drm_atomic_state_clear(struct drm_atomic_state *state); /** * drm_atomic_state_get - acquire a reference to the atomic state * @state: The atomic state * * Returns a new reference to the @state */static inline struct drm_atomic_state *drm_atomic_state_get(struct drm_atomic_state *state){	kref_get(&state->ref);	return state;} void __drm_atomic_state_free(struct kref *ref); /** * drm_atomic_state_put - release a reference to the atomic state * @state: The atomic state * * This releases a reference to @state which is freed after removing the * final reference. No locking required and callable from any context. */static inline void drm_atomic_state_put(struct drm_atomic_state *state){	kref_put(&state->ref, __drm_atomic_state_free);} int  __must_checkdrm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state);void drm_atomic_state_default_clear(struct drm_atomic_state *state);void drm_atomic_state_default_release(struct drm_atomic_state *state); struct drm_crtc_state * __must_checkdrm_atomic_get_crtc_state(struct drm_atomic_state *state,			  struct drm_crtc *crtc);struct drm_plane_state * __must_checkdrm_atomic_get_plane_state(struct drm_atomic_state *state,			   struct drm_plane *plane);struct drm_connector_state * __must_checkdrm_atomic_get_connector_state(struct drm_atomic_state *state,			       struct drm_connector *connector); void drm_atomic_private_obj_init(struct drm_device *dev,				 struct drm_private_obj *obj,				 struct drm_private_state *state,				 const struct drm_private_state_funcs *funcs);void drm_atomic_private_obj_fini(struct drm_private_obj *obj); struct drm_private_state * __must_checkdrm_atomic_get_private_obj_state(struct drm_atomic_state *state,				 struct drm_private_obj *obj);struct drm_private_state *drm_atomic_get_old_private_obj_state(struct drm_atomic_state *state,				     struct drm_private_obj *obj);

Lines 1–500 of 1107.