From 55edf41b699bcb31dcf45082d99e91b7e217206e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 1 Nov 2016 17:40:44 +0200 Subject: drm: define drm_compat_ioctl NULL on CONFIG_COMPAT=n and reduce #ifdefs If we define drm_compat_ioctl NULL on CONFIG_COMPAT=n, we don't have to check for the config everywhere. Reviewed-by: Patrik Jakobsson Signed-off-by: Jani Nikula Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1478014844-27454-1-git-send-email-jani.nikula@intel.com --- include/drm/drmP.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/drm/drmP.h b/include/drm/drmP.h index e336e3901876..a3effab98407 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -941,8 +941,13 @@ static inline bool drm_is_primary_client(const struct drm_file *file_priv) extern int drm_ioctl_permit(u32 flags, struct drm_file *file_priv); extern long drm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#ifdef CONFIG_COMPAT extern long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#else +/* Let drm_compat_ioctl be assigned to .compat_ioctl unconditionally */ +#define drm_compat_ioctl NULL +#endif extern bool drm_ioctl_flags(unsigned int nr, unsigned int *flags); /* File Operations (drm_fops.c) */ -- cgit 1.4.1 From 5705670d0463423337c82d00877989e7df8b169d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 31 Oct 2016 09:08:06 +0000 Subject: drm: Track drm_mm allocators and show leaks on shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can use the kernel's stack tracer and depot to record the allocation site of every drm_mm user. Then on shutdown, as well as warning that allocated nodes still reside with the drm_mm range manager, we can display who allocated them to aide tracking down the leak. v2: Move Kconfig around so it lies underneath the DRM options submenu. Signed-off-by: Chris Wilson Reviewed-by: Christian König Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161031090806.20073-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/Kconfig | 13 +++++++++ drivers/gpu/drm/drm_mm.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++-- include/drm/drm_mm.h | 6 ++++ 3 files changed, 90 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 483059a22b1b..25e8e3793d29 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -33,6 +33,19 @@ config DRM_DP_AUX_CHARDEV read and write values to arbitrary DPCD registers on the DP aux channel. +config DRM_DEBUG_MM + bool "Insert extra checks and debug info into the DRM range managers" + default n + depends on DRM + select STACKDEPOT + help + Enable allocation tracking of memory manager and leak detection on + shutdown. + + Recommended for driver developers only. + + If in doubt, say "N". + config DRM_KMS_HELPER tristate depends on DRM diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 11d44a1e0ab3..89b891a4847f 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -104,6 +104,66 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_ u64 end, enum drm_mm_search_flags flags); +#ifdef CONFIG_DRM_DEBUG_MM +#define STACKDEPTH 32 +#define BUFSZ 4096 + +static noinline void save_stack(struct drm_mm_node *node) +{ + unsigned long entries[STACKDEPTH]; + struct stack_trace trace = { + .entries = entries, + .max_entries = STACKDEPTH, + .skip = 1 + }; + + save_stack_trace(&trace); + if (trace.nr_entries != 0 && + trace.entries[trace.nr_entries-1] == ULONG_MAX) + trace.nr_entries--; + + /* May be called under spinlock, so avoid sleeping */ + node->stack = depot_save_stack(&trace, GFP_NOWAIT); +} + +static void show_leaks(struct drm_mm *mm) +{ + struct drm_mm_node *node; + unsigned long entries[STACKDEPTH]; + char *buf; + + buf = kmalloc(BUFSZ, GFP_KERNEL); + if (!buf) + return; + + list_for_each_entry(node, &mm->head_node.node_list, node_list) { + struct stack_trace trace = { + .entries = entries, + .max_entries = STACKDEPTH + }; + + if (!node->stack) { + DRM_ERROR("node [%08llx + %08llx]: unknown owner\n", + node->start, node->size); + continue; + } + + depot_fetch_stack(node->stack, &trace); + snprint_stack_trace(buf, BUFSZ, &trace, 0); + DRM_ERROR("node [%08llx + %08llx]: inserted at\n%s", + node->start, node->size, buf); + } + + kfree(buf); +} + +#undef STACKDEPTH +#undef BUFSZ +#else +static void save_stack(struct drm_mm_node *node) { } +static void show_leaks(struct drm_mm *mm) { } +#endif + #define START(node) ((node)->start) #define LAST(node) ((node)->start + (node)->size - 1) @@ -228,6 +288,8 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node, list_add(&node->hole_stack, &mm->hole_stack); node->hole_follows = 1; } + + save_stack(node); } /** @@ -293,6 +355,8 @@ int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node) node->hole_follows = 1; } + save_stack(node); + return 0; } EXPORT_SYMBOL(drm_mm_reserve_node); @@ -397,6 +461,8 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, list_add(&node->hole_stack, &mm->hole_stack); node->hole_follows = 1; } + + save_stack(node); } /** @@ -861,10 +927,12 @@ EXPORT_SYMBOL(drm_mm_init); * Note that it is a bug to call this function on an allocator which is not * clean. */ -void drm_mm_takedown(struct drm_mm * mm) +void drm_mm_takedown(struct drm_mm *mm) { - WARN(!list_empty(&mm->head_node.node_list), - "Memory manager not clean during takedown.\n"); + if (WARN(!list_empty(&mm->head_node.node_list), + "Memory manager not clean during takedown.\n")) + show_leaks(mm); + } EXPORT_SYMBOL(drm_mm_takedown); diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index 205ddcf6d55d..41ddafe92b2f 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h @@ -44,6 +44,9 @@ #ifdef CONFIG_DEBUG_FS #include #endif +#ifdef CONFIG_DRM_DEBUG_MM +#include +#endif enum drm_mm_search_flags { DRM_MM_SEARCH_DEFAULT = 0, @@ -74,6 +77,9 @@ struct drm_mm_node { u64 size; u64 __subtree_last; struct drm_mm *mm; +#ifdef CONFIG_DRM_DEBUG_MM + depot_stack_handle_t stack; +#endif }; struct drm_mm { -- cgit 1.4.1 From 0dc9967d030b6843766e3a97203ab9eaf6b19e41 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 31 Oct 2016 10:36:46 -0700 Subject: drm/atomic-helper: fix reference to drm_atomic_helper_commit_planes The kernel-doc references drm_atomic_commit_planes() which does not exist. The functions name is drm_atomic_helper_commit_planes(). Signed-off-by: Stefan Agner Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161031173646.19453-1-stefan@agner.ch --- include/drm/drm_modeset_helper_vtables.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index 10e449c86dbd..72478cf82147 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -361,8 +361,8 @@ struct drm_crtc_helper_funcs { * * Note that the power state of the display pipe when this function is * called depends upon the exact helpers and calling sequence the driver - * has picked. See drm_atomic_commit_planes() for a discussion of the - * tradeoffs and variants of plane commit helpers. + * has picked. See drm_atomic_helper_commit_planes() for a discussion of + * the tradeoffs and variants of plane commit helpers. * * This callback is used by the atomic modeset helpers and by the * transitional plane helpers, but it is optional. @@ -385,8 +385,8 @@ struct drm_crtc_helper_funcs { * * Note that the power state of the display pipe when this function is * called depends upon the exact helpers and calling sequence the driver - * has picked. See drm_atomic_commit_planes() for a discussion of the - * tradeoffs and variants of plane commit helpers. + * has picked. See drm_atomic_helper_commit_planes() for a discussion of + * the tradeoffs and variants of plane commit helpers. * * This callback is used by the atomic modeset helpers and by the * transitional plane helpers, but it is optional. @@ -940,8 +940,8 @@ struct drm_plane_helper_funcs { * * Note that the power state of the display pipe when this function is * called depends upon the exact helpers and calling sequence the driver - * has picked. See drm_atomic_commit_planes() for a discussion of the - * tradeoffs and variants of plane commit helpers. + * has picked. See drm_atomic_helper_commit_planes() for a discussion of + * the tradeoffs and variants of plane commit helpers. * * This callback is used by the atomic modeset helpers and by the * transitional plane helpers, but it is optional. @@ -963,8 +963,8 @@ struct drm_plane_helper_funcs { * * Note that the power state of the display pipe when this function is * called depends upon the exact helpers and calling sequence the driver - * has picked. See drm_atomic_commit_planes() for a discussion of the - * tradeoffs and variants of plane commit helpers. + * has picked. See drm_atomic_helper_commit_planes() for a discussion of + * the tradeoffs and variants of plane commit helpers. * * This callback is used by the atomic modeset helpers and by the * transitional plane helpers, but it is optional. -- cgit 1.4.1 From 91d5ee0451607d2a33c2b811ef3cc4a3e4578ed8 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 3 Nov 2016 16:10:01 +0200 Subject: drm/uapi: Add a warning that mode flags must match the xrandr definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Existing userspace expected the mode flags to match the xrandr definitions 1:1, and even adding new flags in he previously unused bits is likely to break existing userspace. Add a comment warning people about this potential trap. Cc: Shashank Sharma Cc: "Lin, Jia" Cc: Akashdeep Sharma Cc: Jim Bride Cc: Jose Abreu Cc: Daniel Vetter Cc: Emil Velikov Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1478182201-26086-1-git-send-email-ville.syrjala@linux.intel.com --- include/uapi/drm/drm_mode.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 084b50a02dc5..01000c9f7c2c 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -47,7 +47,15 @@ extern "C" { #define DRM_MODE_TYPE_DRIVER (1<<6) /* Video mode flags */ -/* bit compatible with the xorg definitions. */ +/* bit compatible with the xrandr RR_ definitions (bits 0-13) + * + * ABI warning: Existing userspace really expects + * the mode flags to match the xrandr definitions. Any + * changes that don't match the xrandr definitions will + * likely need a new client cap or some other mechanism + * to avoid breaking existing userspace. This includes + * allocating new flags in the previously unused bits! + */ #define DRM_MODE_FLAG_PHSYNC (1<<0) #define DRM_MODE_FLAG_NHSYNC (1<<1) #define DRM_MODE_FLAG_PVSYNC (1<<2) -- cgit 1.4.1 From 13b55664eec7b85607c4ab9d26a62b4af413a771 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 7 Nov 2016 19:03:30 +0900 Subject: drm/atomic: add drm_atomic_set_fence_for_plane() This new function should be used by drivers when setting a implicit fence for the plane. It abstracts the fact that the user might have chosen explicit fencing instead. Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1478513013-3221-1-git-send-email-gustavo@padovan.org --- drivers/gpu/drm/drm_atomic.c | 30 ++++++++++++++++++++++++++++++ include/drm/drm_atomic.h | 2 ++ include/drm/drm_plane.h | 2 +- 3 files changed, 33 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index c32fb3c1d6f0..5e7395455108 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1146,6 +1146,36 @@ drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, } EXPORT_SYMBOL(drm_atomic_set_fb_for_plane); +/** + * drm_atomic_set_fence_for_plane - set fence for plane + * @plane_state: atomic state object for the plane + * @fence: dma_fence to use for the plane + * + * Helper to setup the plane_state fence in case it is not set yet. + * By using this drivers doesn't need to worry if the user choose + * implicit or explicit fencing. + * + * This function will not set the fence to the state if it was set + * via explicit fencing interfaces on the atomic ioctl. It will + * all drope the reference to the fence as we not storing it + * anywhere. + * + * Otherwise, if plane_state->fence is not set this function we + * just set it with the received implict fence. + */ +void +drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state, + struct dma_fence *fence) +{ + if (plane_state->fence) { + dma_fence_put(fence); + return; + } + + plane_state->fence = fence; +} +EXPORT_SYMBOL(drm_atomic_set_fence_for_plane); + /** * drm_atomic_set_crtc_for_connector - set crtc for connector * @conn_state: atomic state object for the connector diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index fc8af53b18aa..2d1e9c944b54 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -345,6 +345,8 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, struct drm_crtc *crtc); void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, struct drm_framebuffer *fb); +void drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state, + struct dma_fence *fence); int __must_check drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, struct drm_crtc *crtc); diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index c5e8a0df1623..68f6d221a3da 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -59,7 +59,7 @@ struct drm_plane_state { struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_plane() */ struct drm_framebuffer *fb; /* do not write directly, use drm_atomic_set_fb_for_plane() */ - struct dma_fence *fence; + struct dma_fence *fence; /* do not write directly, use drm_atomic_set_fence_for_plane() */ /* Signed dest location allows it to be partially off screen */ int32_t crtc_x, crtc_y; -- cgit 1.4.1 From 3835b46e5535d9ad534776bc93670db097682556 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 7 Nov 2016 19:03:33 +0900 Subject: drm/plane: add inline doc for struct drm_plane Some of the members of struct drm_plane had extra comments so for these add inline kernel comment to consolidate all documentation in one place. Signed-off-by: Gustavo Padovan [danvet: Bikeshed a bit more to have real paragraphs with real sentences.] Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1478513013-3221-4-git-send-email-gustavo@padovan.org --- include/drm/drm_plane.h | 58 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 68f6d221a3da..29a175754aee 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -32,11 +32,6 @@ struct drm_crtc; /** * struct drm_plane_state - mutable plane state * @plane: backpointer to the plane - * @crtc: currently bound CRTC, NULL if disabled - * @fb: currently bound framebuffer - * @fence: optional fence to wait for before scanning out @fb - * @crtc_x: left position of visible portion of plane on crtc - * @crtc_y: upper position of visible portion of plane on crtc * @crtc_w: width of visible portion of plane on crtc * @crtc_h: height of visible portion of plane on crtc * @src_x: left position of visible portion of plane within @@ -51,18 +46,51 @@ struct drm_crtc; * where N is the number of active planes for given crtc * @src: clipped source coordinates of the plane (in 16.16) * @dst: clipped destination coordinates of the plane - * @visible: visibility of the plane * @state: backpointer to global drm_atomic_state */ struct drm_plane_state { struct drm_plane *plane; - struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_plane() */ - struct drm_framebuffer *fb; /* do not write directly, use drm_atomic_set_fb_for_plane() */ - struct dma_fence *fence; /* do not write directly, use drm_atomic_set_fence_for_plane() */ + /** + * @crtc: + * + * Currently bound CRTC, NULL if disabled. Do not this write directly, + * use drm_atomic_set_crtc_for_plane() + */ + struct drm_crtc *crtc; + + /** + * @fb: + * + * Currently bound framebuffer. Do not write this directly, use + * drm_atomic_set_fb_for_plane() + */ + struct drm_framebuffer *fb; + + /** + * @fence: + * + * Optional fence to wait for before scanning out @fb. Do not write this + * directly, use drm_atomic_set_fence_for_plane() + */ + struct dma_fence *fence; + + /** + * @crtc_x: + * + * Left position of visible portion of plane on crtc, signed dest + * location allows it to be partially off screen. + */ + + int32_t crtc_x; + /** + * @crtc_y: + * + * Upper position of visible portion of plane on crtc, signed dest + * location allows it to be partially off screen. + */ + int32_t crtc_y; - /* Signed dest location allows it to be partially off screen */ - int32_t crtc_x, crtc_y; uint32_t crtc_w, crtc_h; /* Source values are 16.16 fixed point */ @@ -79,9 +107,11 @@ struct drm_plane_state { /* Clipped coordinates */ struct drm_rect src, dst; - /* - * Is the plane actually visible? Can be false even - * if fb!=NULL and crtc!=NULL, due to clipping. + /** + * @visible: + * + * Visibility of the plane. This can be false even if fb!=NULL and + * crtc!=NULL, due to clipping. */ bool visible; -- cgit 1.4.1 From 7392b4bb702b05749539ff0936e94976248240c9 Mon Sep 17 00:00:00 2001 From: "monk.liu" Date: Fri, 4 Nov 2016 16:16:09 -0400 Subject: dma-buf: return index of the first signaled fence (v2) Return the index of the first signaled fence. This information is useful in some APIs like Vulkan. v2: rebase on drm-next (fence -> dma_fence) Signed-off-by: monk.liu Signed-off-by: Alex Deucher Cc: Sumit Semwal Signed-off-by: Sumit Semwal [sumits: fix warnings] Link: http://patchwork.freedesktop.org/patch/msgid/1478290570-30982-1-git-send-email-alexander.deucher@amd.com --- drivers/dma-buf/dma-fence.c | 21 ++++++++++++++++----- include/linux/dma-fence.h | 3 ++- 2 files changed, 18 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index 3a7bf009c21c..cda40cbd8c43 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -403,14 +403,18 @@ out: EXPORT_SYMBOL(dma_fence_default_wait); static bool -dma_fence_test_signaled_any(struct dma_fence **fences, uint32_t count) +dma_fence_test_signaled_any(struct dma_fence **fences, uint32_t count, + uint32_t *idx) { int i; for (i = 0; i < count; ++i) { struct dma_fence *fence = fences[i]; - if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) + if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { + if (idx) + *idx = i; return true; + } } return false; } @@ -422,6 +426,8 @@ dma_fence_test_signaled_any(struct dma_fence **fences, uint32_t count) * @count: [in] number of fences to wait on * @intr: [in] if true, do an interruptible wait * @timeout: [in] timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT + * @idx: [out] the first signaled fence index, meaningful only on + * positive return * * Returns -EINVAL on custom fence wait implementation, -ERESTARTSYS if * interrupted, 0 if the wait timed out, or the remaining timeout in jiffies @@ -433,7 +439,7 @@ dma_fence_test_signaled_any(struct dma_fence **fences, uint32_t count) */ signed long dma_fence_wait_any_timeout(struct dma_fence **fences, uint32_t count, - bool intr, signed long timeout) + bool intr, signed long timeout, uint32_t *idx) { struct default_wait_cb *cb; signed long ret = timeout; @@ -444,8 +450,11 @@ dma_fence_wait_any_timeout(struct dma_fence **fences, uint32_t count, if (timeout == 0) { for (i = 0; i < count; ++i) - if (dma_fence_is_signaled(fences[i])) + if (dma_fence_is_signaled(fences[i])) { + if (idx) + *idx = i; return 1; + } return 0; } @@ -468,6 +477,8 @@ dma_fence_wait_any_timeout(struct dma_fence **fences, uint32_t count, if (dma_fence_add_callback(fence, &cb[i].base, dma_fence_default_wait_cb)) { /* This fence is already signaled */ + if (idx) + *idx = i; goto fence_rm_cb; } } @@ -478,7 +489,7 @@ dma_fence_wait_any_timeout(struct dma_fence **fences, uint32_t count, else set_current_state(TASK_UNINTERRUPTIBLE); - if (dma_fence_test_signaled_any(fences, count)) + if (dma_fence_test_signaled_any(fences, count, idx)) break; ret = schedule_timeout(ret); diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h index ba60c043a5d3..fcf4b1971eba 100644 --- a/include/linux/dma-fence.h +++ b/include/linux/dma-fence.h @@ -382,7 +382,8 @@ signed long dma_fence_wait_timeout(struct dma_fence *, bool intr, signed long timeout); signed long dma_fence_wait_any_timeout(struct dma_fence **fences, uint32_t count, - bool intr, signed long timeout); + bool intr, signed long timeout, + uint32_t *idx); /** * dma_fence_wait - sleep until the fence gets signaled -- cgit 1.4.1 From eef18a827a9ec58aa9fc1ccfb7e65ff04ebc25f3 Mon Sep 17 00:00:00 2001 From: Junwei Zhang Date: Fri, 4 Nov 2016 16:16:10 -0400 Subject: drm/amdgpu: add the interface of waiting multiple fences (v4) v2: agd: rebase and squash in all the previous optimizations and changes so everything compiles. v3: squash in Slava's 32bit build fix v4: rebase on drm-next (fence -> dma_fence), squash in Monk's ioctl update patch Signed-off-by: Junwei Zhang Reviewed-by: Monk Liu Reviewed-by: Jammy Zhou Signed-off-by: Alex Deucher Signed-off-by: Sumit Semwal [sumits: fix checkpatch warnings] Link: http://patchwork.freedesktop.org/patch/msgid/1478290570-30982-2-git-send-email-alexander.deucher@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 + drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 174 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c | 3 +- include/uapi/drm/amdgpu_drm.h | 28 +++++ 5 files changed, 207 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 2ec7b3baeec2..c2b8496cdf63 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1212,6 +1212,8 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); int amdgpu_cs_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); +int amdgpu_cs_wait_fences_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp); int amdgpu_gem_metadata_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index a024217896fd..b4bc83aa5999 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1139,6 +1139,180 @@ int amdgpu_cs_wait_ioctl(struct drm_device *dev, void *data, return 0; } +/** + * amdgpu_cs_get_fence - helper to get fence from drm_amdgpu_fence + * + * @adev: amdgpu device + * @filp: file private + * @user: drm_amdgpu_fence copied from user space + */ +static struct dma_fence *amdgpu_cs_get_fence(struct amdgpu_device *adev, + struct drm_file *filp, + struct drm_amdgpu_fence *user) +{ + struct amdgpu_ring *ring; + struct amdgpu_ctx *ctx; + struct dma_fence *fence; + int r; + + r = amdgpu_cs_get_ring(adev, user->ip_type, user->ip_instance, + user->ring, &ring); + if (r) + return ERR_PTR(r); + + ctx = amdgpu_ctx_get(filp->driver_priv, user->ctx_id); + if (ctx == NULL) + return ERR_PTR(-EINVAL); + + fence = amdgpu_ctx_get_fence(ctx, ring, user->seq_no); + amdgpu_ctx_put(ctx); + + return fence; +} + +/** + * amdgpu_cs_wait_all_fence - wait on all fences to signal + * + * @adev: amdgpu device + * @filp: file private + * @wait: wait parameters + * @fences: array of drm_amdgpu_fence + */ +static int amdgpu_cs_wait_all_fences(struct amdgpu_device *adev, + struct drm_file *filp, + union drm_amdgpu_wait_fences *wait, + struct drm_amdgpu_fence *fences) +{ + uint32_t fence_count = wait->in.fence_count; + unsigned int i; + long r = 1; + + for (i = 0; i < fence_count; i++) { + struct dma_fence *fence; + unsigned long timeout = amdgpu_gem_timeout(wait->in.timeout_ns); + + fence = amdgpu_cs_get_fence(adev, filp, &fences[i]); + if (IS_ERR(fence)) + return PTR_ERR(fence); + else if (!fence) + continue; + + r = dma_fence_wait_timeout(fence, true, timeout); + if (r < 0) + return r; + + if (r == 0) + break; + } + + memset(wait, 0, sizeof(*wait)); + wait->out.status = (r > 0); + + return 0; +} + +/** + * amdgpu_cs_wait_any_fence - wait on any fence to signal + * + * @adev: amdgpu device + * @filp: file private + * @wait: wait parameters + * @fences: array of drm_amdgpu_fence + */ +static int amdgpu_cs_wait_any_fence(struct amdgpu_device *adev, + struct drm_file *filp, + union drm_amdgpu_wait_fences *wait, + struct drm_amdgpu_fence *fences) +{ + unsigned long timeout = amdgpu_gem_timeout(wait->in.timeout_ns); + uint32_t fence_count = wait->in.fence_count; + uint32_t first = ~0; + struct dma_fence **array; + unsigned int i; + long r; + + /* Prepare the fence array */ + array = kcalloc(fence_count, sizeof(struct dma_fence *), GFP_KERNEL); + + if (array == NULL) + return -ENOMEM; + + for (i = 0; i < fence_count; i++) { + struct dma_fence *fence; + + fence = amdgpu_cs_get_fence(adev, filp, &fences[i]); + if (IS_ERR(fence)) { + r = PTR_ERR(fence); + goto err_free_fence_array; + } else if (fence) { + array[i] = fence; + } else { /* NULL, the fence has been already signaled */ + r = 1; + goto out; + } + } + + r = dma_fence_wait_any_timeout(array, fence_count, true, timeout, + &first); + if (r < 0) + goto err_free_fence_array; + +out: + memset(wait, 0, sizeof(*wait)); + wait->out.status = (r > 0); + wait->out.first_signaled = first; + /* set return value 0 to indicate success */ + r = 0; + +err_free_fence_array: + for (i = 0; i < fence_count; i++) + dma_fence_put(array[i]); + kfree(array); + + return r; +} + +/** + * amdgpu_cs_wait_fences_ioctl - wait for multiple command submissions to finish + * + * @dev: drm device + * @data: data from userspace + * @filp: file private + */ +int amdgpu_cs_wait_fences_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) +{ + struct amdgpu_device *adev = dev->dev_private; + union drm_amdgpu_wait_fences *wait = data; + uint32_t fence_count = wait->in.fence_count; + struct drm_amdgpu_fence *fences_user; + struct drm_amdgpu_fence *fences; + int r; + + /* Get the fences from userspace */ + fences = kmalloc_array(fence_count, sizeof(struct drm_amdgpu_fence), + GFP_KERNEL); + if (fences == NULL) + return -ENOMEM; + + fences_user = (void __user *)(unsigned long)(wait->in.fences); + if (copy_from_user(fences, fences_user, + sizeof(struct drm_amdgpu_fence) * fence_count)) { + r = -EFAULT; + goto err_free_fences; + } + + if (wait->in.wait_all) + r = amdgpu_cs_wait_all_fences(adev, filp, wait, fences); + else + r = amdgpu_cs_wait_any_fence(adev, filp, wait, fences); + +err_free_fences: + kfree(fences); + + return r; +} + /** * amdgpu_cs_find_bo_va - find bo_va for VM address * diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 78392671046a..06e145b5afd7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -825,6 +825,7 @@ const struct drm_ioctl_desc amdgpu_ioctls_kms[] = { DRM_IOCTL_DEF_DRV(AMDGPU_CS, amdgpu_cs_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(AMDGPU_INFO, amdgpu_info_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(AMDGPU_WAIT_CS, amdgpu_cs_wait_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(AMDGPU_WAIT_FENCES, amdgpu_cs_wait_fences_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(AMDGPU_GEM_METADATA, amdgpu_gem_metadata_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(AMDGPU_GEM_VA, amdgpu_gem_va_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(AMDGPU_GEM_OP, amdgpu_gem_op_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c index fd26c4b8d793..34a795463988 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c @@ -361,7 +361,8 @@ int amdgpu_sa_bo_new(struct amdgpu_sa_manager *sa_manager, if (count) { spin_unlock(&sa_manager->wq.lock); t = dma_fence_wait_any_timeout(fences, count, false, - MAX_SCHEDULE_TIMEOUT); + MAX_SCHEDULE_TIMEOUT, + NULL); for (i = 0; i < count; ++i) dma_fence_put(fences[i]); diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 4684f378f046..2191a9e4f3db 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -50,6 +50,7 @@ extern "C" { #define DRM_AMDGPU_WAIT_CS 0x09 #define DRM_AMDGPU_GEM_OP 0x10 #define DRM_AMDGPU_GEM_USERPTR 0x11 +#define DRM_AMDGPU_WAIT_FENCES 0x12 #define DRM_IOCTL_AMDGPU_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_CREATE, union drm_amdgpu_gem_create) #define DRM_IOCTL_AMDGPU_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_MMAP, union drm_amdgpu_gem_mmap) @@ -63,6 +64,7 @@ extern "C" { #define DRM_IOCTL_AMDGPU_WAIT_CS DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_WAIT_CS, union drm_amdgpu_wait_cs) #define DRM_IOCTL_AMDGPU_GEM_OP DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_OP, struct drm_amdgpu_gem_op) #define DRM_IOCTL_AMDGPU_GEM_USERPTR DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_USERPTR, struct drm_amdgpu_gem_userptr) +#define DRM_IOCTL_AMDGPU_WAIT_FENCES DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_WAIT_FENCES, union drm_amdgpu_wait_fences) #define AMDGPU_GEM_DOMAIN_CPU 0x1 #define AMDGPU_GEM_DOMAIN_GTT 0x2 @@ -307,6 +309,32 @@ union drm_amdgpu_wait_cs { struct drm_amdgpu_wait_cs_out out; }; +struct drm_amdgpu_fence { + __u32 ctx_id; + __u32 ip_type; + __u32 ip_instance; + __u32 ring; + __u64 seq_no; +}; + +struct drm_amdgpu_wait_fences_in { + /** This points to uint64_t * which points to fences */ + __u64 fences; + __u32 fence_count; + __u32 wait_all; + __u64 timeout_ns; +}; + +struct drm_amdgpu_wait_fences_out { + __u32 status; + __u32 first_signaled; +}; + +union drm_amdgpu_wait_fences { + struct drm_amdgpu_wait_fences_in in; + struct drm_amdgpu_wait_fences_out out; +}; + #define AMDGPU_GEM_OP_GET_GEM_CREATE_INFO 0 #define AMDGPU_GEM_OP_SET_PLACEMENT 1 -- cgit 1.4.1 From 65c7dc18b2b6628156c5ed2bc5ef66bca17267fb Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Sat, 5 Nov 2016 11:08:06 -0400 Subject: drm: helper macros to print composite types I'll want to print things in a similar way in a later patch. This will make it easier. Signed-off-by: Rob Clark Reviewed-by: Sean Paul Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1478358492-30738-2-git-send-email-robdclark@gmail.com --- drivers/gpu/drm/drm_modes.c | 8 +------- drivers/gpu/drm/drm_rect.c | 11 ++--------- include/drm/drmP.h | 21 +++++++++++++++++++++ 3 files changed, 24 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index f64ac86deb84..ce6eeda02acf 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -49,13 +49,7 @@ */ void drm_mode_debug_printmodeline(const struct drm_display_mode *mode) { - DRM_DEBUG_KMS("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d " - "0x%x 0x%x\n", - mode->base.id, mode->name, mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, - mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, mode->type, mode->flags); + DRM_DEBUG_KMS("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); } EXPORT_SYMBOL(drm_mode_debug_printmodeline); diff --git a/drivers/gpu/drm/drm_rect.c b/drivers/gpu/drm/drm_rect.c index 73e53a8d1b37..e6057d8cdcd5 100644 --- a/drivers/gpu/drm/drm_rect.c +++ b/drivers/gpu/drm/drm_rect.c @@ -281,17 +281,10 @@ EXPORT_SYMBOL(drm_rect_calc_vscale_relaxed); */ void drm_rect_debug_print(const char *prefix, const struct drm_rect *r, bool fixed_point) { - int w = drm_rect_width(r); - int h = drm_rect_height(r); - if (fixed_point) - DRM_DEBUG_KMS("%s%d.%06ux%d.%06u%+d.%06u%+d.%06u\n", prefix, - w >> 16, ((w & 0xffff) * 15625) >> 10, - h >> 16, ((h & 0xffff) * 15625) >> 10, - r->x1 >> 16, ((r->x1 & 0xffff) * 15625) >> 10, - r->y1 >> 16, ((r->y1 & 0xffff) * 15625) >> 10); + DRM_DEBUG_KMS("%s" DRM_RECT_FP_FMT "\n", prefix, DRM_RECT_FP_ARG(r)); else - DRM_DEBUG_KMS("%s%dx%d%+d%+d\n", prefix, w, h, r->x1, r->y1); + DRM_DEBUG_KMS("%s" DRM_RECT_FMT "\n", prefix, DRM_RECT_ARG(r)); } EXPORT_SYMBOL(drm_rect_debug_print); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index a3effab98407..e92c904fe8cb 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -306,6 +306,27 @@ void drm_printk(const char *level, unsigned int category, #define DRM_DEBUG_PRIME_RATELIMITED(fmt, args...) \ DRM_DEV_DEBUG_PRIME_RATELIMITED(NULL, fmt, ##args) +/* Format strings and argument splitters to simplify printing + * various "complex" objects + */ +#define DRM_MODE_FMT "%d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x" +#define DRM_MODE_ARG(m) \ + (m)->base.id, (m)->name, (m)->vrefresh, (m)->clock, \ + (m)->hdisplay, (m)->hsync_start, (m)->hsync_end, (m)->htotal, \ + (m)->vdisplay, (m)->vsync_start, (m)->vsync_end, (m)->vtotal, \ + (m)->type, (m)->flags + +#define DRM_RECT_FMT "%dx%d%+d%+d" +#define DRM_RECT_ARG(r) drm_rect_width(r), drm_rect_height(r), (r)->x1, (r)->y1 + +/* for rect's in fixed-point format: */ +#define DRM_RECT_FP_FMT "%d.%06ux%d.%06u%+d.%06u%+d.%06u" +#define DRM_RECT_FP_ARG(r) \ + drm_rect_width(r) >> 16, ((drm_rect_width(r) & 0xffff) * 15625) >> 10, \ + drm_rect_height(r) >> 16, ((drm_rect_height(r) & 0xffff) * 15625) >> 10, \ + (r)->x1 >> 16, (((r)->x1 & 0xffff) * 15625) >> 10, \ + (r)->y1 >> 16, (((r)->y1 & 0xffff) * 15625) >> 10 + /*@}*/ /***********************************************************************/ -- cgit 1.4.1 From d8187177b0b195368699ba12b5fa8cd5fdc39b79 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Sat, 5 Nov 2016 11:08:07 -0400 Subject: drm: add helper for printing to log or seq_file Sometimes it is nice not to duplicate equivalent printk() and seq_printf() code. v2: simplify things w/ va_format, and use dev_printk, docs Signed-off-by: Rob Clark Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1478358492-30738-3-git-send-email-robdclark@gmail.com --- Documentation/gpu/drm-internals.rst | 17 ++++++ drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_print.c | 54 +++++++++++++++++ include/drm/drm_print.h | 117 ++++++++++++++++++++++++++++++++++++ 4 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/drm_print.c create mode 100644 include/drm/drm_print.h (limited to 'include') diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst index 37284bcc7764..25ee92c5df65 100644 --- a/Documentation/gpu/drm-internals.rst +++ b/Documentation/gpu/drm-internals.rst @@ -350,6 +350,23 @@ how the ioctl is allowed to be called. .. kernel-doc:: drivers/gpu/drm/drm_ioctl.c :export: + +Misc Utilities +============== + +Printer +------- + +.. kernel-doc:: include/drm/drm_print.h + :doc: print + +.. kernel-doc:: include/drm/drm_print.h + :internal: + +.. kernel-doc:: include/drm/drm_print.h + :export: + + Legacy Support Code =================== diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 74579d2e796e..c1d0602fbe24 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -15,7 +15,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm_modeset_lock.o drm_atomic.o drm_bridge.o \ drm_framebuffer.o drm_connector.o drm_blend.o \ drm_encoder.o drm_mode_object.o drm_property.o \ - drm_plane.o drm_color_mgmt.o + drm_plane.o drm_color_mgmt.o drm_print.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c new file mode 100644 index 000000000000..34eb85618b76 --- /dev/null +++ b/drivers/gpu/drm/drm_print.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2016 Red Hat + * + * 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 + */ + +#include +#include +#include +#include + +void __drm_printfn_seq_file(struct drm_printer *p, struct va_format *vaf) +{ + seq_printf(p->arg, "%pV", vaf); +} +EXPORT_SYMBOL(__drm_printfn_seq_file); + +void __drm_printfn_info(struct drm_printer *p, struct va_format *vaf) +{ + dev_printk(KERN_INFO, p->arg, "[" DRM_NAME "] %pV", vaf); +} +EXPORT_SYMBOL(__drm_printfn_info); + +void drm_printf(struct drm_printer *p, const char *f, ...) +{ + struct va_format vaf; + va_list args; + + va_start(args, f); + vaf.fmt = f; + vaf.va = &args; + p->printfn(p, &vaf); + va_end(args); +} +EXPORT_SYMBOL(drm_printf); diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h new file mode 100644 index 000000000000..475ffe3730e9 --- /dev/null +++ b/include/drm/drm_print.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2016 Red Hat + * + * 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 + */ + +#ifndef DRM_PRINT_H_ +#define DRM_PRINT_H_ + +#include +#include + +/** + * DOC: print + * + * 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(&p); + * } + * #endif + * + * void some_other_function(...) + * { + * struct drm_printer p = drm_info_printer(drm->dev); + * log_some_info(&p); + * } + */ + +/** + * struct drm_printer - drm output "stream" + * @printfn: actual output fxn + * @arg: output fxn specific data + * + * Do not use struct members directly. Use drm_printer_seq_file(), + * drm_printer_info(), etc to initialize. And drm_printf() for output. + */ +struct drm_printer { + void (*printfn)(struct drm_printer *p, struct va_format *vaf); + void *arg; +}; + +void __drm_printfn_seq_file(struct drm_printer *p, struct va_format *vaf); +void __drm_printfn_info(struct drm_printer *p, struct va_format *vaf); + +/** + * drm_printf - print to a &drm_printer stream + * @p: the &drm_printer + * @f: format string + */ +void drm_printf(struct drm_printer *p, const char *f, ...); + + +/** + * drm_seq_file_printer - construct a &drm_printer that outputs to &seq_file + * @f: the struct &seq_file to output to + * + * RETURNS: + * The &drm_printer object + */ +static inline struct drm_printer drm_seq_file_printer(struct seq_file *f) +{ + struct drm_printer p = { + .printfn = __drm_printfn_seq_file, + .arg = f, + }; + return p; +} + +/** + * drm_info_printer - construct a &drm_printer that outputs to dev_printk() + * @dev: the struct &device pointer + * + * RETURNS: + * The &drm_printer object + */ +static inline struct drm_printer drm_info_printer(struct device *dev) +{ + struct drm_printer p = { + .printfn = __drm_printfn_info, + .arg = dev, + }; + return p; +} + +#endif /* DRM_PRINT_H_ */ -- cgit 1.4.1 From 1638d30c1584ff8097776d691f5fa5aafa7aeb8c Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Sat, 5 Nov 2016 11:08:08 -0400 Subject: drm: add helpers to go from plane state to drm_rect Signed-off-by: Rob Clark Reviewed-by: Sean Paul [seanpaul resolved conflict in drm_plane.h] Signed-off-by: Sean Paul --- drivers/gpu/drm/drm_plane_helper.c | 11 ++--------- drivers/gpu/drm/i915/intel_display.c | 10 ++-------- drivers/gpu/drm/i915/intel_sprite.c | 11 ++--------- include/drm/drm_plane.h | 24 ++++++++++++++++++++++++ 4 files changed, 30 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 7899fc1dcdb0..7a7dddf604d7 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -130,15 +130,8 @@ int drm_plane_helper_check_state(struct drm_plane_state *state, unsigned int rotation = state->rotation; int hscale, vscale; - src->x1 = state->src_x; - src->y1 = state->src_y; - src->x2 = state->src_x + state->src_w; - src->y2 = state->src_y + state->src_h; - - dst->x1 = state->crtc_x; - dst->y1 = state->crtc_y; - dst->x2 = state->crtc_x + state->crtc_w; - dst->y2 = state->crtc_y + state->crtc_h; + *src = drm_plane_state_src(state); + *dst = drm_plane_state_dest(state); if (!fb) { state->visible = false; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6f8f6ec5b27a..63423d2f934a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2824,14 +2824,8 @@ valid_fb: plane_state->crtc_w = fb->width; plane_state->crtc_h = fb->height; - intel_state->base.src.x1 = plane_state->src_x; - intel_state->base.src.y1 = plane_state->src_y; - intel_state->base.src.x2 = plane_state->src_x + plane_state->src_w; - intel_state->base.src.y2 = plane_state->src_y + plane_state->src_h; - intel_state->base.dst.x1 = plane_state->crtc_x; - intel_state->base.dst.y1 = plane_state->crtc_y; - intel_state->base.dst.x2 = plane_state->crtc_x + plane_state->crtc_w; - intel_state->base.dst.y2 = plane_state->crtc_y + plane_state->crtc_h; + intel_state->base.src = drm_plane_state_src(plane_state); + intel_state->base.dst = drm_plane_state_dest(plane_state); obj = intel_fb_obj(fb); if (i915_gem_object_is_tiled(obj)) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 43d0350856e7..da9e8b309dd2 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -773,15 +773,8 @@ intel_check_sprite_plane(struct drm_plane *plane, bool can_scale; int ret; - src->x1 = state->base.src_x; - src->y1 = state->base.src_y; - src->x2 = state->base.src_x + state->base.src_w; - src->y2 = state->base.src_y + state->base.src_h; - - dst->x1 = state->base.crtc_x; - dst->y1 = state->base.crtc_y; - dst->x2 = state->base.crtc_x + state->base.crtc_w; - dst->y2 = state->base.crtc_y + state->base.crtc_h; + *src = drm_plane_state_src(&state->base); + *dst = drm_plane_state_dest(&state->base); if (!fb) { state->base.visible = false; diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 29a175754aee..a421cb553620 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -118,6 +118,30 @@ struct drm_plane_state { struct drm_atomic_state *state; }; +static inline struct drm_rect +drm_plane_state_src(const struct drm_plane_state *state) +{ + struct drm_rect src = { + .x1 = state->src_x, + .y1 = state->src_y, + .x2 = state->src_x + state->src_w, + .y2 = state->src_y + state->src_h, + }; + return src; +} + +static inline struct drm_rect +drm_plane_state_dest(const struct drm_plane_state *state) +{ + struct drm_rect dest = { + .x1 = state->crtc_x, + .y1 = state->crtc_y, + .x2 = state->crtc_x + state->crtc_w, + .y2 = state->crtc_y + state->crtc_h, + }; + return dest; +} + /** * struct drm_plane_funcs - driver plane control functions */ -- cgit 1.4.1 From fceffb325b30f6a9f0bdee22e65d0b8bb35883af Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Sat, 5 Nov 2016 11:08:09 -0400 Subject: drm/atomic: add new drm_debug bit to dump atomic state The contents of drm_{plane,crtc,connector}_state is dumped before commit. If a driver extends any of the state structs, it can implement the corresponding funcs->atomic_print_state() to add it's own driver specific state. Signed-off-by: Rob Clark [seanpaul resolved conflict in drm_plane.h] Signed-off-by: Sean Paul --- drivers/gpu/drm/drm_atomic.c | 93 ++++++++++++++++++++++++++++++++++++++++++++ include/drm/drmP.h | 1 + include/drm/drm_connector.h | 13 +++++++ include/drm/drm_crtc.h | 13 +++++++ include/drm/drm_plane.h | 13 +++++++ 5 files changed, 133 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 5e7395455108..bd62c959b475 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "drm_crtc_internal.h" @@ -602,6 +603,28 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc, return 0; } +static void drm_atomic_crtc_print_state(struct drm_printer *p, + const struct drm_crtc_state *state) +{ + struct drm_crtc *crtc = state->crtc; + + drm_printf(p, "crtc[%u]: %s\n", crtc->base.id, crtc->name); + drm_printf(p, "\tenable=%d\n", state->enable); + drm_printf(p, "\tactive=%d\n", state->active); + drm_printf(p, "\tplanes_changed=%d\n", state->planes_changed); + drm_printf(p, "\tmode_changed=%d\n", state->mode_changed); + drm_printf(p, "\tactive_changed=%d\n", state->active_changed); + drm_printf(p, "\tconnectors_changed=%d\n", state->connectors_changed); + drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed); + drm_printf(p, "\tplane_mask=%x\n", state->plane_mask); + drm_printf(p, "\tconnector_mask=%x\n", state->connector_mask); + drm_printf(p, "\tencoder_mask=%x\n", state->encoder_mask); + drm_printf(p, "\tmode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&state->mode)); + + if (crtc->funcs->atomic_print_state) + crtc->funcs->atomic_print_state(p, state); +} + /** * drm_atomic_get_plane_state - get plane state * @state: global atomic state object @@ -878,6 +901,38 @@ static int drm_atomic_plane_check(struct drm_plane *plane, return 0; } +static void drm_atomic_plane_print_state(struct drm_printer *p, + const struct drm_plane_state *state) +{ + struct drm_plane *plane = state->plane; + struct drm_rect src = drm_plane_state_src(state); + struct drm_rect dest = drm_plane_state_dest(state); + + drm_printf(p, "plane[%u]: %s\n", plane->base.id, plane->name); + drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); + drm_printf(p, "\tfb=%u\n", state->fb ? state->fb->base.id : 0); + if (state->fb) { + struct drm_framebuffer *fb = state->fb; + int i, n = drm_format_num_planes(fb->pixel_format); + + drm_printf(p, "\t\tformat=%s\n", + drm_get_format_name(fb->pixel_format)); + drm_printf(p, "\t\tsize=%dx%d\n", fb->width, fb->height); + drm_printf(p, "\t\tlayers:\n"); + for (i = 0; i < n; i++) { + drm_printf(p, "\t\t\tpitch[%d]=%u\n", i, fb->pitches[i]); + drm_printf(p, "\t\t\toffset[%d]=%u\n", i, fb->offsets[i]); + drm_printf(p, "\t\t\tmodifier[%d]=0x%llx\n", i, fb->modifier[i]); + } + } + drm_printf(p, "\tcrtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest)); + drm_printf(p, "\tsrc-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src)); + drm_printf(p, "\trotation=%x\n", state->rotation); + + if (plane->funcs->atomic_print_state) + plane->funcs->atomic_print_state(p, state); +} + /** * drm_atomic_get_connector_state - get connector state * @state: global atomic state object @@ -993,6 +1048,18 @@ int drm_atomic_connector_set_property(struct drm_connector *connector, } EXPORT_SYMBOL(drm_atomic_connector_set_property); +static void drm_atomic_connector_print_state(struct drm_printer *p, + const struct drm_connector_state *state) +{ + struct drm_connector *connector = state->connector; + + drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name); + drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); + + if (connector->funcs->atomic_print_state) + connector->funcs->atomic_print_state(p, state); +} + /** * drm_atomic_connector_get_property - get property value from connector state * @connector: the drm connector to set a property on @@ -1487,6 +1554,29 @@ int drm_atomic_nonblocking_commit(struct drm_atomic_state *state) } EXPORT_SYMBOL(drm_atomic_nonblocking_commit); +static void drm_atomic_print_state(const struct drm_atomic_state *state) +{ + struct drm_printer p = drm_info_printer(state->dev->dev); + struct drm_plane *plane; + struct drm_plane_state *plane_state; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_connector *connector; + struct drm_connector_state *connector_state; + int i; + + DRM_DEBUG_ATOMIC("checking %p\n", state); + + for_each_plane_in_state(state, plane, plane_state, i) + drm_atomic_plane_print_state(&p, plane_state); + + for_each_crtc_in_state(state, crtc, crtc_state, i) + drm_atomic_crtc_print_state(&p, crtc_state); + + for_each_connector_in_state(state, connector, connector_state, i) + drm_atomic_connector_print_state(&p, connector_state); +} + /* * The big monstor ioctl */ @@ -1776,6 +1866,9 @@ retry: } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) { ret = drm_atomic_nonblocking_commit(state); } else { + if (unlikely(drm_debug & DRM_UT_STATE)) + drm_atomic_print_state(state); + ret = drm_atomic_commit(state); } diff --git a/include/drm/drmP.h b/include/drm/drmP.h index e92c904fe8cb..4e58137c1882 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -135,6 +135,7 @@ struct dma_buf_attachment; #define DRM_UT_PRIME 0x08 #define DRM_UT_ATOMIC 0x10 #define DRM_UT_VBL 0x20 +#define DRM_UT_STATE 0x40 extern __printf(6, 7) void drm_dev_printk(const struct device *dev, const char *level, diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index ac9d7d8e0e43..3e9727264b65 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -37,6 +37,7 @@ struct drm_crtc; struct drm_encoder; struct drm_property; struct drm_property_blob; +struct drm_printer; struct edid; enum drm_connector_force { @@ -481,6 +482,18 @@ struct drm_connector_funcs { const struct drm_connector_state *state, struct drm_property *property, uint64_t *val); + + /** + * @atomic_print_state: + * + * If driver subclasses struct &drm_connector_state, it should implement + * this optional hook for printing additional driver specific state. + * + * Do not call this directly, use drm_atomic_connector_print_state() + * instead. + */ + void (*atomic_print_state)(struct drm_printer *p, + const struct drm_connector_state *state); }; /* mode specified on the command line */ diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index fa1aa214c8ea..8cca2a895981 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -53,6 +53,7 @@ struct drm_device; struct drm_mode_set; struct drm_file; struct drm_clip_rect; +struct drm_printer; struct device_node; struct dma_fence; struct edid; @@ -594,6 +595,18 @@ struct drm_crtc_funcs { */ int (*set_crc_source)(struct drm_crtc *crtc, const char *source, size_t *values_cnt); + + /** + * @atomic_print_state: + * + * If driver subclasses struct &drm_crtc_state, it should implement + * this optional hook for printing additional driver specific state. + * + * Do not call this directly, use drm_atomic_crtc_print_state() + * instead. + */ + void (*atomic_print_state)(struct drm_printer *p, + const struct drm_crtc_state *state); }; /** diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index a421cb553620..63d4e5051936 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -28,6 +28,7 @@ #include struct drm_crtc; +struct drm_printer; /** * struct drm_plane_state - mutable plane state @@ -370,6 +371,18 @@ struct drm_plane_funcs { * before data structures are torndown. */ void (*early_unregister)(struct drm_plane *plane); + + /** + * @atomic_print_state: + * + * If driver subclasses struct &drm_plane_state, it should implement + * this optional hook for printing additional driver specific state. + * + * Do not call this directly, use drm_atomic_plane_print_state() + * instead. + */ + void (*atomic_print_state)(struct drm_printer *p, + const struct drm_plane_state *state); }; /** -- cgit 1.4.1 From 6559c901cb4840e46893d587d8af435aac9c4c3f Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Sat, 5 Nov 2016 11:08:10 -0400 Subject: drm/atomic: add debugfs file to dump out atomic state Useful to dump current state from debugfs, if turning on the drm.debug bit is too much overhead. The drm_state_dump() can also be used by drivers, for example to implement a module param that dumps state on error irqs. Signed-off-by: Rob Clark Reviewed-by: Sean Paul Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1478358492-30738-6-git-send-email-robdclark@gmail.com --- drivers/gpu/drm/drm_atomic.c | 63 +++++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_debugfs.c | 9 +++++++ include/drm/drm_atomic.h | 7 +++++ 3 files changed, 79 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index bd62c959b475..b096c1673969 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1577,6 +1577,69 @@ static void drm_atomic_print_state(const struct drm_atomic_state *state) drm_atomic_connector_print_state(&p, connector_state); } +/** + * drm_state_dump - dump entire device atomic state + * @dev: the drm device + * @p: where to print the state to + * + * Just for debugging. Drivers might want an option to dump state + * to dmesg in case of error irq's. (Hint, you probably want to + * ratelimit this!) + * + * The caller must drm_modeset_lock_all(), or if this is called + * from error irq handler, it should not be enabled by default. + * (Ie. if you are debugging errors you might not care that this + * is racey. But calling this without all modeset locks held is + * not inherently safe.) + */ +void drm_state_dump(struct drm_device *dev, struct drm_printer *p) +{ + struct drm_mode_config *config = &dev->mode_config; + struct drm_plane *plane; + struct drm_crtc *crtc; + struct drm_connector *connector; + + if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) + return; + + list_for_each_entry(plane, &config->plane_list, head) + drm_atomic_plane_print_state(p, plane->state); + + list_for_each_entry(crtc, &config->crtc_list, head) + drm_atomic_crtc_print_state(p, crtc->state); + + list_for_each_entry(connector, &config->connector_list, head) + drm_atomic_connector_print_state(p, connector->state); +} +EXPORT_SYMBOL(drm_state_dump); + +#ifdef CONFIG_DEBUG_FS +static int drm_state_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct drm_printer p = drm_seq_file_printer(m); + + drm_modeset_lock_all(dev); + drm_state_dump(dev, &p); + drm_modeset_unlock_all(dev); + + return 0; +} + +/* any use in debugfs files to dump individual planes/crtc/etc? */ +static const struct drm_info_list drm_atomic_debugfs_list[] = { + {"state", drm_state_info, 0}, +}; + +int drm_atomic_debugfs_init(struct drm_minor *minor) +{ + return drm_debugfs_create_files(drm_atomic_debugfs_list, + ARRAY_SIZE(drm_atomic_debugfs_list), + minor->debugfs_root, minor); +} +#endif + /* * The big monstor ioctl */ diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 800055c39cdb..206a4fe7ea26 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "drm_internal.h" #if defined(CONFIG_DEBUG_FS) @@ -163,6 +164,14 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id, return ret; } + if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { + ret = drm_atomic_debugfs_init(minor); + if (ret) { + DRM_ERROR("Failed to create atomic debugfs files\n"); + return ret; + } + } + if (dev->driver->debugfs_init) { ret = dev->driver->debugfs_init(minor); if (ret) { diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 2d1e9c944b54..331bb100b718 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -366,6 +366,13 @@ int __must_check drm_atomic_check_only(struct drm_atomic_state *state); int __must_check drm_atomic_commit(struct drm_atomic_state *state); int __must_check drm_atomic_nonblocking_commit(struct drm_atomic_state *state); +void drm_state_dump(struct drm_device *dev, struct drm_printer *p); + +#ifdef CONFIG_DEBUG_FS +struct drm_minor; +int drm_atomic_debugfs_init(struct drm_minor *minor); +#endif + #define for_each_connector_in_state(__state, connector, connector_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->num_connector && \ -- cgit 1.4.1