From 42f1b310332916d130455f300504b72f80c2a66c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 14 Dec 2017 21:30:51 +0100 Subject: drm/print: Unconfuse kerneldoc It thinks we want to document the __printf(2,0) annotion. Not sure we want to teach it about all possible gcc-only flags, hence why I opted for the cheap trick of just moving it ahead of the kerneldoc. This is only a problem for static inline functions, since for non-inline function the kerneldoc is in the .c file, but the special annotations are all in the header. Cc'ing kernel-doc maintainers as fyi. Cc: linux-doc@vger.kernel.org Cc: Jonathan Corbet Acked-by: Alex Deucher Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20171214203054.20141-3-daniel.vetter@ffwll.ch --- include/drm/drm_print.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/drm') diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index 5f9932e2246e1..2a4a42e59a478 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -80,13 +80,13 @@ void __drm_printfn_debug(struct drm_printer *p, struct va_format *vaf); __printf(2, 3) void drm_printf(struct drm_printer *p, const char *f, ...); +__printf(2, 0) /** * drm_vprintf - print to a &drm_printer stream * @p: the &drm_printer * @fmt: format string * @va: the va_list */ -__printf(2, 0) static inline void drm_vprintf(struct drm_printer *p, const char *fmt, va_list *va) { -- cgit v1.2.3 From 924fe8df7fcfa508729b5a1591df41c0bafed429 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 14 Dec 2017 21:30:52 +0100 Subject: drm/syncobj: some kerneldoc polish Complete a few missing bits, fix up the existing xcross-references and add a bunch more. v2: Fix typos (Alex). Cc: Dave Airlie via lists.freedesktop.org Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20171214203054.20141-4-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_syncobj.c | 45 +++++++++++++++++++++++++++++++++++++++---- include/drm/drm_syncobj.h | 34 ++++++++++++++++++-------------- 2 files changed, 61 insertions(+), 18 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 9b733c510cbfc..131695915acd1 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -29,9 +29,9 @@ /** * DOC: Overview * - * DRM synchronisation objects (syncobj) are a persistent objects, - * that contain an optional fence. The fence can be updated with a new - * fence, or be NULL. + * DRM synchronisation objects (syncobj, see struct &drm_syncobj) are + * persistent objects that contain an optional fence. The fence can be updated + * with a new fence, or be NULL. * * syncobj's can be waited upon, where it will wait for the underlying * fence. @@ -61,7 +61,8 @@ * @file_private: drm file private pointer * @handle: sync object handle to lookup. * - * Returns a reference to the syncobj pointed to by handle or NULL. + * Returns a reference to the syncobj pointed to by handle or NULL. The + * reference must be released by calling drm_syncobj_put(). */ struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private, u32 handle) @@ -229,6 +230,19 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) return 0; } +/** + * drm_syncobj_find_fence - lookup and reference the fence in a sync object + * @file_private: drm file private pointer + * @handle: sync object handle to lookup. + * @fence: out parameter for the fence + * + * This is just a convenience function that combines drm_syncobj_find() and + * drm_syncobj_fence_get(). + * + * Returns 0 on success or a negative error value on failure. On success @fence + * contains a reference to the fence, which must be released by calling + * dma_fence_put(). + */ int drm_syncobj_find_fence(struct drm_file *file_private, u32 handle, struct dma_fence **fence) @@ -269,6 +283,12 @@ EXPORT_SYMBOL(drm_syncobj_free); * @out_syncobj: returned syncobj * @flags: DRM_SYNCOBJ_* flags * @fence: if non-NULL, the syncobj will represent this fence + * + * This is the first function to create a sync object. After creating, drivers + * probably want to make it available to userspace, either through + * drm_syncobj_get_handle() or drm_syncobj_get_fd(). + * + * Returns 0 on success or a negative error value on failure. */ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, struct dma_fence *fence) @@ -302,6 +322,14 @@ EXPORT_SYMBOL(drm_syncobj_create); /** * drm_syncobj_get_handle - get a handle from a syncobj + * @file_private: drm file private pointer + * @syncobj: Sync object to export + * @handle: out parameter with the new handle + * + * Exports a sync object created with drm_syncobj_create() as a handle on + * @file_private to userspace. + * + * Returns 0 on success or a negative error value on failure. */ int drm_syncobj_get_handle(struct drm_file *file_private, struct drm_syncobj *syncobj, u32 *handle) @@ -388,6 +416,15 @@ static int drm_syncobj_alloc_file(struct drm_syncobj *syncobj) return 0; } +/** + * drm_syncobj_get_fd - get a file descriptor from a syncobj + * @syncobj: Sync object to export + * @p_fd: out parameter with the new file descriptor + * + * Exports a sync object created with drm_syncobj_create() as a file descriptor. + * + * Returns 0 on success or a negative error value on failure. + */ int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd) { int ret; diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h index 9e8ba90c6784a..3980602472c0f 100644 --- a/include/drm/drm_syncobj.h +++ b/include/drm/drm_syncobj.h @@ -33,36 +33,31 @@ struct drm_syncobj_cb; /** * struct drm_syncobj - sync object. * - * This structure defines a generic sync object which wraps a dma fence. + * This structure defines a generic sync object which wraps a &dma_fence. */ struct drm_syncobj { /** - * @refcount: - * - * Reference count of this object. + * @refcount: Reference count of this object. */ struct kref refcount; /** * @fence: * NULL or a pointer to the fence bound to this object. * - * This field should not be used directly. Use drm_syncobj_fence_get - * and drm_syncobj_replace_fence instead. + * This field should not be used directly. Use drm_syncobj_fence_get() + * and drm_syncobj_replace_fence() instead. */ struct dma_fence __rcu *fence; /** - * @cb_list: - * List of callbacks to call when the fence gets replaced + * @cb_list: List of callbacks to call when the &fence gets replaced. */ struct list_head cb_list; /** - * @lock: - * locks cb_list and write-locks fence. + * @lock: Protects &cb_list and write-locks &fence. */ spinlock_t lock; /** - * @file: - * a file backing for this syncobj. + * @file: A file backing for this syncobj. */ struct file *file; }; @@ -73,7 +68,7 @@ typedef void (*drm_syncobj_func_t)(struct drm_syncobj *syncobj, /** * struct drm_syncobj_cb - callback for drm_syncobj_add_callback * @node: used by drm_syncob_add_callback to append this struct to - * syncobj::cb_list + * &drm_syncobj.cb_list * @func: drm_syncobj_func_t to call * * This struct will be initialized by drm_syncobj_add_callback, additional @@ -92,7 +87,7 @@ void drm_syncobj_free(struct kref *kref); * drm_syncobj_get - acquire a syncobj reference * @obj: sync object * - * This acquires additional reference to @obj. It is illegal to call this + * This acquires an additional reference to @obj. It is illegal to call this * without already holding a reference. No locks required. */ static inline void @@ -111,6 +106,17 @@ drm_syncobj_put(struct drm_syncobj *obj) kref_put(&obj->refcount, drm_syncobj_free); } +/** + * drm_syncobj_fence_get - get a reference to a fence in a sync object + * @syncobj: sync object. + * + * This acquires additional reference to &drm_syncobj.fence contained in @obj, + * if not NULL. It is illegal to call this without already holding a reference. + * No locks required. + * + * Returns: + * Either the fence of @obj or NULL if there's none. + */ static inline struct dma_fence * drm_syncobj_fence_get(struct drm_syncobj *syncobj) { -- cgit v1.2.3 From da6c05969785a0f4108a089ef33c55f46ae21775 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 14 Dec 2017 21:30:53 +0100 Subject: drm/atomic: document how to handle driver private objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DK put some nice docs into the commit introducing driver private state, but in the git history alone it'll be lost. Also, since Ville remove the void* usage it's a good opportunity to give the driver private stuff some tlc on the doc front. Finally try to explain why the "let's just subclass drm_atomic_state" approach wasn't the greatest, and annotate all those functions as deprecated in favour of more standardized driver private states. Also note where we could/should extend driver private states going forward (atm neither locking nor synchronization is handled in core/helpers, which isn't really all that great). v2: Spelling and phrasing improvements (Alex, DK). Cc: Harry Wentland Cc: Dhinakaran Pandiyan Cc: Maarten Lankhorst Cc: Ville Syrjälä Cc: Laurent Pinchart Cc: Rob Clark Cc: Alex Deucher Cc: Ben Skeggs Reviewed-by: Dhinakaran Pandiyan Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20171214203054.20141-5-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms.rst | 6 ++++++ drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++--- include/drm/drm_atomic.h | 28 +++++++++++++++++++++++++++ include/drm/drm_mode_config.h | 9 +++++++++ 4 files changed, 85 insertions(+), 3 deletions(-) (limited to 'include/drm') diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 307284125d7aa..420025bd6a9be 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -271,6 +271,12 @@ Taken all together there's two consequences for the atomic design: Read on in this chapter, and also in :ref:`drm_atomic_helper` for more detailed coverage of specific topics. +Handling Driver Private State +----------------------------- + +.. kernel-doc:: drivers/gpu/drm/drm_atomic.c + :doc: handling driver private state + Atomic Mode Setting Function Reference -------------------------------------- diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 37445d50816a5..b76d49218cf1d 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -50,7 +50,8 @@ EXPORT_SYMBOL(__drm_crtc_commit_free); * @state: atomic state * * Free all the memory allocated by drm_atomic_state_init. - * This is useful for drivers that subclass the atomic state. + * This should only be used by drivers which are still subclassing + * &drm_atomic_state and haven't switched to &drm_private_state yet. */ void drm_atomic_state_default_release(struct drm_atomic_state *state) { @@ -67,7 +68,8 @@ EXPORT_SYMBOL(drm_atomic_state_default_release); * @state: atomic state * * Default implementation for filling in a new atomic state. - * This is useful for drivers that subclass the atomic state. + * This should only be used by drivers which are still subclassing + * &drm_atomic_state and haven't switched to &drm_private_state yet. */ int drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state) @@ -132,7 +134,8 @@ EXPORT_SYMBOL(drm_atomic_state_alloc); * @state: atomic state * * Default implementation for clearing atomic state. - * This is useful for drivers that subclass the atomic state. + * This should only be used by drivers which are still subclassing + * &drm_atomic_state and haven't switched to &drm_private_state yet. */ void drm_atomic_state_default_clear(struct drm_atomic_state *state) { @@ -946,6 +949,42 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, plane->funcs->atomic_print_state(p, state); } +/** + * DOC: handling driver private state + * + * Very often the DRM objects exposed to userspace in the atomic modeset api + * (&drm_connector, &drm_crtc and &drm_plane) do not map neatly to the + * underlying hardware. Especially for any kind of shared resources (e.g. shared + * clocks, scaler units, bandwidth and fifo limits shared among a group of + * planes or CRTCs, and so on) it makes sense to model these as independent + * objects. Drivers then need to do similar state tracking and commit ordering for + * such private (since not exposed to userpace) objects as the atomic core and + * helpers already provide for connectors, planes and CRTCs. + * + * To make this easier on drivers the atomic core provides some support to track + * driver private state objects using struct &drm_private_obj, with the + * associated state struct &drm_private_state. + * + * Similar to userspace-exposed objects, private state structures can be + * acquired by calling drm_atomic_get_private_obj_state(). Since this function + * does not take care of locking, drivers should wrap it for each type of + * private state object they have with the required call to drm_modeset_lock() + * for the corresponding &drm_modeset_lock. + * + * All private state structures contained in a &drm_atomic_state update can be + * iterated using for_each_oldnew_private_obj_in_state(), + * for_each_new_private_obj_in_state() and for_each_old_private_obj_in_state(). + * Drivers are recommended to wrap these for each type of driver private state + * object they have, filtering on &drm_private_obj.funcs using for_each_if(), at + * least if they want to iterate over all objects of a given type. + * + * An earlier way to handle driver private state was by subclassing struct + * &drm_atomic_state. But since that encourages non-standard ways to implement + * the check/commit split atomic requires (by using e.g. "check and rollback or + * commit instead" of "duplicate state, check, then either commit or release + * duplicated state) it is deprecated in favour of using &drm_private_state. + */ + /** * drm_atomic_private_obj_init - initialize private object * @obj: private object diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 5afd6e364fb67..22b60075142ee 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -189,12 +189,40 @@ struct drm_private_state_funcs { 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. + */ struct drm_private_obj { + /** + * @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; }; +/** + * 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; }; diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index a0afeb591dcb1..e5f3b43014e1e 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -268,6 +268,9 @@ struct drm_mode_config_funcs { * state easily. If this hook is implemented, drivers must also * implement @atomic_state_clear and @atomic_state_free. * + * Subclassing of &drm_atomic_state is deprecated in favour of using + * &drm_private_state and &drm_private_obj. + * * RETURNS: * * A new &drm_atomic_state on success or NULL on failure. @@ -289,6 +292,9 @@ struct drm_mode_config_funcs { * * Drivers that implement this must call drm_atomic_state_default_clear() * to clear common state. + * + * Subclassing of &drm_atomic_state is deprecated in favour of using + * &drm_private_state and &drm_private_obj. */ void (*atomic_state_clear)(struct drm_atomic_state *state); @@ -301,6 +307,9 @@ struct drm_mode_config_funcs { * * Drivers that implement this must call * drm_atomic_state_default_release() to release common resources. + * + * Subclassing of &drm_atomic_state is deprecated in favour of using + * &drm_private_state and &drm_private_obj. */ void (*atomic_state_free)(struct drm_atomic_state *state); }; -- cgit v1.2.3 From 5fca5ece6af8dd507c0459262766369e057e6d60 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 14 Dec 2017 21:30:54 +0100 Subject: drm/doc: Move legacy kms helpers to the very end We don't want people to accidentally stumble over there. Also rename the plane helpers to legacy plane helpers. After Ville's patch to make the clipping helper atomic and move it to drm_atomic_helper.c there's nothing left in there that should be useful for modern drivers. v2: Laurent had a few questions around how state is added to drm_atomic_state, tried to clarify that. And spotted another sentence where the docs suggested subclassing. v3: Small polish (Alex). Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20171214203054.20141-6-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms-helpers.rst | 36 +++++++++++++++++------------------ Documentation/gpu/drm-kms.rst | 8 ++++---- include/drm/drm_atomic.h | 4 ++++ 3 files changed, 26 insertions(+), 22 deletions(-) (limited to 'include/drm') diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index 3ea622876b67a..e37557b30f620 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -74,15 +74,6 @@ Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_atomic_helper.c :export: -Legacy CRTC/Modeset Helper Functions Reference -============================================== - -.. kernel-doc:: drivers/gpu/drm/drm_crtc_helper.c - :doc: overview - -.. kernel-doc:: drivers/gpu/drm/drm_crtc_helper.c - :export: - Simple KMS Helper Reference =========================== @@ -282,15 +273,6 @@ Flip-work Helper Reference .. kernel-doc:: drivers/gpu/drm/drm_flip_work.c :export: -Plane Helper Reference -====================== - -.. kernel-doc:: drivers/gpu/drm/drm_plane_helper.c - :doc: overview - -.. kernel-doc:: drivers/gpu/drm/drm_plane_helper.c - :export: - Auxiliary Modeset Helpers ========================= @@ -308,3 +290,21 @@ Framebuffer GEM Helper Reference .. kernel-doc:: drivers/gpu/drm/drm_gem_framebuffer_helper.c :export: + +Legacy Plane Helper Reference +============================= + +.. kernel-doc:: drivers/gpu/drm/drm_plane_helper.c + :doc: overview + +.. kernel-doc:: drivers/gpu/drm/drm_plane_helper.c + :export: + +Legacy CRTC/Modeset Helper Functions Reference +============================================== + +.. kernel-doc:: drivers/gpu/drm/drm_crtc_helper.c + :doc: overview + +.. kernel-doc:: drivers/gpu/drm/drm_crtc_helper.c + :export: diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 420025bd6a9be..2dcf5b42015de 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -263,10 +263,10 @@ Taken all together there's two consequences for the atomic design: - An atomic update is assembled and validated as an entirely free-standing pile of structures within the :c:type:`drm_atomic_state ` - container. Again drivers can subclass that container for their own state - structure tracking needs. Only when a state is committed is it applied to the - driver and modeset objects. This way rolling back an update boils down to - releasing memory and unreferencing objects like framebuffers. + container. Driver private state structures are also tracked in the same + structure; see the next chapter. Only when a state is committed is it applied + to the driver and modeset objects. This way rolling back an update boils down + to releasing memory and unreferencing objects like framebuffers. Read on in this chapter, and also in :ref:`drm_atomic_helper` for more detailed coverage of specific topics. diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 22b60075142ee..1c27526c499ee 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -246,6 +246,10 @@ struct __drm_private_objs_state { * @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; -- cgit v1.2.3 From a65eb01ffcc50b42d1e4ea2e79c274e7f7a240c6 Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Fri, 15 Dec 2017 18:51:13 +0100 Subject: drm/fb-helper: Set/clear dev->fb_helper in dummy init/fini MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set dev->fb_helper even when fbdev emulation is compiled out, so drivers can use it to free the structure. Clear it for consistency. Fixes: 29ad20b22c8f ("drm: Add drm_device->fb_helper pointer") Signed-off-by: Noralf Trønnes Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20171215175119.36181-2-noralf@tronnes.org --- include/drm/drm_fb_helper.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include/drm') diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 1494b12a984aa..1bd624579db75 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -33,6 +33,7 @@ struct drm_fb_helper; #include +#include #include enum mode_set_atomic { @@ -332,11 +333,17 @@ static inline int drm_fb_helper_init(struct drm_device *dev, struct drm_fb_helper *helper, int max_conn) { + /* So drivers can use it to free the struct */ + helper->dev = dev; + dev->fb_helper = helper; + return 0; } static inline void drm_fb_helper_fini(struct drm_fb_helper *helper) { + if (helper && helper->dev) + helper->dev->fb_helper = NULL; } static inline int drm_fb_helper_blank(int blank, struct fb_info *info) -- cgit v1.2.3 From 8741216396b2611142d7a890d06b7040ff585b3f Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Fri, 15 Dec 2017 18:51:14 +0100 Subject: drm/fb-helper: Add drm_fb_helper_fbdev_setup/teardown() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helpers to setup and teardown fbdev emulation. Signed-off-by: Noralf Trønnes Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20171215175119.36181-3-noralf@tronnes.org --- drivers/gpu/drm/drm_fb_helper.c | 106 ++++++++++++++++++++++++++++++++++++++++ include/drm/drm_fb_helper.h | 25 ++++++++++ 2 files changed, 131 insertions(+) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 04a3a5ce370a0..823fc8f50d856 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -2729,6 +2729,112 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) } EXPORT_SYMBOL(drm_fb_helper_hotplug_event); +/** + * drm_fb_helper_fbdev_setup() - Setup fbdev emulation + * @dev: DRM device + * @fb_helper: fbdev helper structure to set up + * @funcs: fbdev helper functions + * @preferred_bpp: Preferred bits per pixel for the device. + * @dev->mode_config.preferred_depth is used if this is zero. + * @max_conn_count: Maximum number of connectors. + * @dev->mode_config.num_connector is used if this is zero. + * + * This function sets up fbdev emulation and registers fbdev for access by + * userspace. If all connectors are disconnected, setup is deferred to the next + * time drm_fb_helper_hotplug_event() is called. + * The caller must to provide a &drm_fb_helper_funcs->fb_probe callback + * function. + * + * See also: drm_fb_helper_initial_config() + * + * Returns: + * Zero on success or negative error code on failure. + */ +int drm_fb_helper_fbdev_setup(struct drm_device *dev, + struct drm_fb_helper *fb_helper, + const struct drm_fb_helper_funcs *funcs, + unsigned int preferred_bpp, + unsigned int max_conn_count) +{ + int ret; + + if (!preferred_bpp) + preferred_bpp = dev->mode_config.preferred_depth; + if (!preferred_bpp) + preferred_bpp = 32; + + if (!max_conn_count) + max_conn_count = dev->mode_config.num_connector; + if (!max_conn_count) { + DRM_DEV_ERROR(dev->dev, "No connectors\n"); + return -EINVAL; + } + + drm_fb_helper_prepare(dev, fb_helper, funcs); + + ret = drm_fb_helper_init(dev, fb_helper, max_conn_count); + if (ret < 0) { + DRM_DEV_ERROR(dev->dev, "Failed to initialize fbdev helper\n"); + return ret; + } + + ret = drm_fb_helper_single_add_all_connectors(fb_helper); + if (ret < 0) { + DRM_DEV_ERROR(dev->dev, "Failed to add connectors\n"); + goto err_drm_fb_helper_fini; + } + + if (!drm_drv_uses_atomic_modeset(dev)) + drm_helper_disable_unused_functions(dev); + + ret = drm_fb_helper_initial_config(fb_helper, preferred_bpp); + if (ret < 0) { + DRM_DEV_ERROR(dev->dev, "Failed to set fbdev configuration\n"); + goto err_drm_fb_helper_fini; + } + + return 0; + +err_drm_fb_helper_fini: + drm_fb_helper_fini(fb_helper); + + return ret; +} +EXPORT_SYMBOL(drm_fb_helper_fbdev_setup); + +/** + * drm_fb_helper_fbdev_teardown - Tear down fbdev emulation + * @dev: DRM device + * + * This function unregisters fbdev if not already done and cleans up the + * associated resources including the &drm_framebuffer. + * The driver is responsible for freeing the &drm_fb_helper structure which is + * stored in &drm_device->fb_helper. Do note that this pointer has been cleared + * when this function returns. + * + * In order to support device removal/unplug while file handles are still open, + * drm_fb_helper_unregister_fbi() should be called on device removal and + * drm_fb_helper_fbdev_teardown() in the &drm_driver->release callback when + * file handles are closed. + */ +void drm_fb_helper_fbdev_teardown(struct drm_device *dev) +{ + struct drm_fb_helper *fb_helper = dev->fb_helper; + + if (!fb_helper) + return; + + /* Unregister if it hasn't been done already */ + if (fb_helper->fbdev && fb_helper->fbdev->dev) + drm_fb_helper_unregister_fbi(fb_helper); + + drm_fb_helper_fini(fb_helper); + + if (fb_helper->fb) + drm_framebuffer_remove(fb_helper->fb); +} +EXPORT_SYMBOL(drm_fb_helper_fbdev_teardown); + /** * drm_fb_helper_lastclose - DRM driver lastclose helper for fbdev emulation * @dev: DRM device diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 1bd624579db75..aa78ac3b8ad05 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -320,6 +320,13 @@ int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector); +int drm_fb_helper_fbdev_setup(struct drm_device *dev, + struct drm_fb_helper *fb_helper, + const struct drm_fb_helper_funcs *funcs, + unsigned int preferred_bpp, + unsigned int max_conn_count); +void drm_fb_helper_fbdev_teardown(struct drm_device *dev); + void drm_fb_helper_lastclose(struct drm_device *dev); void drm_fb_helper_output_poll_changed(struct drm_device *dev); #else @@ -525,6 +532,24 @@ drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, return 0; } +static inline int +drm_fb_helper_fbdev_setup(struct drm_device *dev, + struct drm_fb_helper *fb_helper, + const struct drm_fb_helper_funcs *funcs, + unsigned int preferred_bpp, + unsigned int max_conn_count) +{ + /* So drivers can use it to free the struct */ + dev->fb_helper = fb_helper; + + return 0; +} + +static inline void drm_fb_helper_fbdev_teardown(struct drm_device *dev) +{ + dev->fb_helper = NULL; +} + static inline void drm_fb_helper_lastclose(struct drm_device *dev) { } -- cgit v1.2.3 From 48c9571c34b153abc1c4f2b431fa74490b671943 Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Fri, 15 Dec 2017 18:51:17 +0100 Subject: drm/fb-helper: Add drm_fb_helper_defio_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helper for initializing fbdev deferred I/O. The cleanup could have happened in drm_fb_helper_fini(), but that would have required me to set fb_info->fbdefio to NULL in a couple of drivers before they call _fini() to avoid double defio cleanup. The problem is that one of those is vboxvideo which lives in Greg's staging tree. So I put the cleanup in drm_fb_helper_fbdev_teardown(), not perfect but not that bad either. Signed-off-by: Noralf Trønnes Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20171215175119.36181-6-noralf@tronnes.org --- drivers/gpu/drm/drm_fb_helper.c | 54 ++++++++++++++++++++++++++++++++++++++++- include/drm/drm_fb_helper.h | 6 +++++ 2 files changed, 59 insertions(+), 1 deletion(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index e3eb3c9a98e36..4a61e1aef41b0 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -107,7 +107,8 @@ static DEFINE_MUTEX(kernel_fb_helper_lock); * always run in process context since the fb_*() function could be running in * atomic context. If drm_fb_helper_deferred_io() is used as the deferred_io * callback it will also schedule dirty_work with the damage collected from the - * mmap page writes. + * mmap page writes. Drivers can use drm_fb_helper_defio_init() to setup + * deferred I/O (coupled with drm_fb_helper_fbdev_teardown()). */ #define drm_fb_helper_for_each_connector(fbh, i__) \ @@ -1028,6 +1029,49 @@ void drm_fb_helper_deferred_io(struct fb_info *info, } EXPORT_SYMBOL(drm_fb_helper_deferred_io); +/** + * drm_fb_helper_defio_init - fbdev deferred I/O initialization + * @fb_helper: driver-allocated fbdev helper + * + * This function allocates &fb_deferred_io, sets callback to + * drm_fb_helper_deferred_io(), delay to 50ms and calls fb_deferred_io_init(). + * It should be called from the &drm_fb_helper_funcs->fb_probe callback. + * drm_fb_helper_fbdev_teardown() cleans up deferred I/O. + * + * NOTE: A copy of &fb_ops is made and assigned to &info->fbops. This is done + * because fb_deferred_io_cleanup() clears &fbops->fb_mmap and would thereby + * affect other instances of that &fb_ops. + * + * Returns: + * 0 on success or a negative error code on failure. + */ +int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper) +{ + struct fb_info *info = fb_helper->fbdev; + struct fb_deferred_io *fbdefio; + struct fb_ops *fbops; + + fbdefio = kzalloc(sizeof(*fbdefio), GFP_KERNEL); + fbops = kzalloc(sizeof(*fbops), GFP_KERNEL); + if (!fbdefio || !fbops) { + kfree(fbdefio); + kfree(fbops); + return -ENOMEM; + } + + info->fbdefio = fbdefio; + fbdefio->delay = msecs_to_jiffies(50); + fbdefio->deferred_io = drm_fb_helper_deferred_io; + + *fbops = *info->fbops; + info->fbops = fbops; + + fb_deferred_io_init(info); + + return 0; +} +EXPORT_SYMBOL(drm_fb_helper_defio_init); + /** * drm_fb_helper_sys_read - wrapper around fb_sys_read * @info: fb_info struct pointer @@ -2824,6 +2868,7 @@ EXPORT_SYMBOL(drm_fb_helper_fbdev_setup); void drm_fb_helper_fbdev_teardown(struct drm_device *dev) { struct drm_fb_helper *fb_helper = dev->fb_helper; + struct fb_ops *fbops = NULL; if (!fb_helper) return; @@ -2832,7 +2877,14 @@ void drm_fb_helper_fbdev_teardown(struct drm_device *dev) if (fb_helper->fbdev && fb_helper->fbdev->dev) drm_fb_helper_unregister_fbi(fb_helper); + if (fb_helper->fbdev && fb_helper->fbdev->fbdefio) { + fb_deferred_io_cleanup(fb_helper->fbdev); + kfree(fb_helper->fbdev->fbdefio); + fbops = fb_helper->fbdev->fbops; + } + drm_fb_helper_fini(fb_helper); + kfree(fbops); if (fb_helper->fb) drm_framebuffer_remove(fb_helper->fb); diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index aa78ac3b8ad05..b069433e7fc12 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -276,6 +276,7 @@ void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper); void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagelist); +int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper); ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf, size_t count, loff_t *ppos); @@ -423,6 +424,11 @@ static inline void drm_fb_helper_deferred_io(struct fb_info *info, { } +static inline int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper) +{ + return -ENODEV; +} + static inline ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf, size_t count, loff_t *ppos) -- cgit v1.2.3 From 8d44e9e69aacecd522bb2797eb2febc5c6c46558 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 20 Dec 2017 10:35:44 +0100 Subject: drm/framebuffer: Print task that allocated the fb in debug info. This is is very useful to finding sources of leaked framebufers. The fbcon fb is annotated with [fbcon], to give it a better name than kworker. Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/20171220093545.613-3-maarten.lankhorst@linux.intel.com Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 1 + drivers/gpu/drm/drm_framebuffer.c | 2 ++ include/drm/drm_framebuffer.h | 6 ++++++ 3 files changed, 9 insertions(+) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 4a61e1aef41b0..035784ddd1336 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1896,6 +1896,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, if (ret < 0) return ret; + strcpy(fb_helper->fb->comm, "[fbcon]"); return 0; } diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index d63d4c2ac4c81..5a13ff29f4f04 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -664,6 +664,7 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, INIT_LIST_HEAD(&fb->filp_head); fb->funcs = funcs; + strcpy(fb->comm, current->comm); ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB, false, drm_framebuffer_free); @@ -978,6 +979,7 @@ void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, struct drm_format_name_buf format_name; unsigned int i; + drm_printf_indent(p, indent, "allocated by = %s\n", fb->comm); drm_printf_indent(p, indent, "refcount=%u\n", drm_framebuffer_read_refcount(fb)); drm_printf_indent(p, indent, "format=%s\n", diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index dccb897951bad..c50502c656e57 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h @@ -121,6 +121,12 @@ struct drm_framebuffer { * @base: base modeset object structure, contains the reference count. */ struct drm_mode_object base; + + /** + * @comm: Name of the process allocating the fb, used for fb dumping. + */ + char comm[TASK_COMM_LEN]; + /** * @format: framebuffer format information */ -- cgit v1.2.3