diff options
78 files changed, 969 insertions, 171 deletions
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/MAINTAINERS b/MAINTAINERS index 955134d22cff..561d4174cdfe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3919,8 +3919,10 @@ R: Gustavo Padovan <gustavo@padovan.org> S: Maintained L: linux-media@vger.kernel.org L: dri-devel@lists.freedesktop.org -F: drivers/dma-buf/sync_file.c +F: drivers/dma-buf/sync_* +F: drivers/dma-buf/sw_sync.c F: include/linux/sync_file.h +F: include/uapi/linux/sync_file.h F: Documentation/sync_file.txt T: git git://git.linaro.org/people/sumitsemwal/linux-dma-buf.git diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index 3a7bf009c21c..0212af7997d9 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -161,9 +161,6 @@ dma_fence_wait_timeout(struct dma_fence *fence, bool intr, signed long timeout) if (WARN_ON(timeout < 0)) return -EINVAL; - if (timeout == 0) - return dma_fence_is_signaled(fence); - trace_dma_fence_wait_start(fence); ret = fence->ops->wait(fence, intr, timeout); trace_dma_fence_wait_end(fence); @@ -339,18 +336,20 @@ dma_fence_default_wait_cb(struct dma_fence *fence, struct dma_fence_cb *cb) * @timeout: [in] timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT * * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or the - * remaining timeout in jiffies on success. + * remaining timeout in jiffies on success. If timeout is zero the value one is + * returned if the fence is already signaled for consistency with other + * functions taking a jiffies timeout. */ signed long dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout) { struct default_wait_cb cb; unsigned long flags; - signed long ret = timeout; + signed long ret = timeout ? timeout : 1; bool was_set; if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) - return timeout; + return ret; spin_lock_irqsave(fence->lock, flags); @@ -403,14 +402,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 +425,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 +438,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 +449,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 +476,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 +488,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/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c index 7ed56f3edfb7..393817e849ed 100644 --- a/drivers/dma-buf/reservation.c +++ b/drivers/dma-buf/reservation.c @@ -370,10 +370,7 @@ long reservation_object_wait_timeout_rcu(struct reservation_object *obj, { struct dma_fence *fence; unsigned seq, shared_count, i = 0; - long ret = timeout; - - if (!timeout) - return reservation_object_test_signaled_rcu(obj, wait_all); + long ret = timeout ? timeout : 1; retry: fence = NULL; diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index 82e0ca4dd0c1..69c5ff36e2f9 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -84,7 +84,7 @@ static inline struct sync_pt *dma_fence_to_sync_pt(struct dma_fence *fence) * Creates a new sync_timeline. Returns the sync_timeline object or NULL in * case of error. */ -struct sync_timeline *sync_timeline_create(const char *name) +static struct sync_timeline *sync_timeline_create(const char *name) { struct sync_timeline *obj; @@ -316,8 +316,8 @@ static long sw_sync_ioctl_create_fence(struct sync_timeline *obj, } sync_file = sync_file_create(&pt->base); + dma_fence_put(&pt->base); if (!sync_file) { - dma_fence_put(&pt->base); err = -ENOMEM; goto err; } diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 483059a22b1b..2ac0a564af60 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -33,6 +33,20 @@ 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=y + depends on STACKTRACE_SUPPORT + 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/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/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 a370101d923f..78da52f90099 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1141,6 +1141,180 @@ int amdgpu_cs_wait_ioctl(struct drm_device *dev, void *data, } /** + * 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 * * @parser: command submission parser context diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 55c413a55a40..ad908612aff9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -823,6 +823,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/drivers/gpu/drm/arc/arcpgu_drv.c b/drivers/gpu/drm/arc/arcpgu_drv.c index 28e6471257d0..0b6eaa49a1db 100644 --- a/drivers/gpu/drm/arc/arcpgu_drv.c +++ b/drivers/gpu/drm/arc/arcpgu_drv.c @@ -65,9 +65,7 @@ static const struct file_operations arcpgu_drm_ops = { .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .poll = drm_poll, .read = drm_read, .llseek = no_llseek, diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index 6477d1a65266..59747ecaad54 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -268,9 +268,7 @@ static const struct file_operations fops = { .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .poll = drm_poll, .read = drm_read, .llseek = noop_llseek, diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 9f4739452a25..d53b625b14fe 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -197,9 +197,7 @@ static const struct file_operations fops = { .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .poll = drm_poll, .read = drm_read, .llseek = noop_llseek, diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index f54afd2113a9..fd7c9eec92e4 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -188,9 +188,7 @@ static const struct file_operations ast_fops = { .unlocked_ioctl = drm_ioctl, .mmap = ast_mmap, .poll = drm_poll, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .read = drm_read, }; diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 9f6222895212..cbd0070265c9 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -749,9 +749,7 @@ static const struct file_operations fops = { .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .poll = drm_poll, .read = drm_read, .llseek = no_llseek, diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c index 534227df23f3..15a293e65b31 100644 --- a/drivers/gpu/drm/bochs/bochs_drv.c +++ b/drivers/gpu/drm/bochs/bochs_drv.c @@ -70,9 +70,7 @@ static const struct file_operations bochs_fops = { .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .poll = drm_poll, .read = drm_read, .llseek = no_llseek, diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c index 6c76d125995b..d893ea21a359 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.c +++ b/drivers/gpu/drm/cirrus/cirrus_drv.c @@ -126,9 +126,7 @@ static const struct file_operations cirrus_driver_fops = { .unlocked_ioctl = drm_ioctl, .mmap = cirrus_mmap, .poll = drm_poll, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif }; static struct drm_driver driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM, diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 1d6ab371cd52..f5ea7db4a48a 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -30,6 +30,7 @@ #include <drm/drm_atomic.h> #include <drm/drm_mode.h> #include <drm/drm_plane_helper.h> +#include <drm/drm_print.h> #include "drm_crtc_internal.h" @@ -605,6 +606,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 @@ -881,6 +904,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 @@ -996,6 +1051,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 @@ -1150,6 +1217,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 * @crtc: crtc to use for the connector @@ -1460,6 +1557,92 @@ 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); +} + +/** + * 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 */ @@ -1749,6 +1932,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/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 13441e21117c..ce274edb9e52 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -229,9 +229,9 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, crtc->primary = primary; crtc->cursor = cursor; - if (primary) + if (primary && !primary->possible_crtcs) primary->possible_crtcs = 1 << drm_crtc_index(crtc); - if (cursor) + if (cursor && !cursor->possible_crtcs) cursor->possible_crtcs = 1 << drm_crtc_index(crtc); ret = drm_crtc_crc_init(crtc); 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 <linux/export.h> #include <drm/drmP.h> #include <drm/drm_edid.h> +#include <drm/drm_atomic.h> #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/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 9506933b41cd..7eec18925b70 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -957,13 +957,13 @@ static const struct drm_display_mode edid_cea_modes[] = { 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 58 - 720(1440)x480i@240 */ + /* 58 - 720(1440)x480i@240Hz */ { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 54000, 720, 739, 801, 858, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), .vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 59 - 720(1440)x480i@240 */ + /* 59 - 720(1440)x480i@240Hz */ { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 54000, 720, 739, 801, 858, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index cf993dbf602e..5d96de40b63f 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -51,10 +51,11 @@ DEFINE_MUTEX(drm_global_mutex); * Drivers must define the file operations structure that forms the DRM * userspace API entry point, even though most of those operations are * implemented in the DRM core. The mandatory functions are drm_open(), - * drm_read(), drm_ioctl() and drm_compat_ioctl if CONFIG_COMPAT is enabled. - * Drivers which implement private ioctls that require 32/64 bit compatibility - * support must provided their onw .compat_ioctl() handler that processes - * private ioctls and calls drm_compat_ioctl() for core ioctls. + * drm_read(), drm_ioctl() and drm_compat_ioctl() if CONFIG_COMPAT is enabled + * (note that drm_compat_ioctl will be NULL if CONFIG_COMPAT=n). Drivers which + * implement private ioctls that require 32/64 bit compatibility support must + * provide their own .compat_ioctl() handler that processes private ioctls and + * calls drm_compat_ioctl() for core ioctls. * * In addition drm_read() and drm_poll() provide support for DRM events. DRM * events are a generic and extensible means to send asynchronous events to @@ -75,9 +76,7 @@ DEFINE_MUTEX(drm_global_mutex); * .open = drm_open, * .release = drm_release, * .unlocked_ioctl = drm_ioctl, - * #ifdef CONFIG_COMPAT - * .compat_ioctl = drm_compat_ioctl, - * #endif + * .compat_ioctl = drm_compat_ioctl, // NULL if CONFIG_COMPAT=n * .poll = drm_poll, * .read = drm_read, * .llseek = no_llseek, diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 49fd7db758e0..af786f27f72e 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -673,6 +673,11 @@ EXPORT_SYMBOL(drm_framebuffer_lookup); * those used for fbdev. Note that the caller must hold a reference of it's own, * i.e. the object may not be destroyed through this call (since it'll lead to a * locking inversion). + * + * NOTE: This function is deprecated. For driver-private framebuffers it is not + * recommended to embed a framebuffer struct info fbdev struct, instead, a + * framebuffer pointer is preferred and drm_framebuffer_unreference() should be + * called when the framebuffer is to be cleaned up. */ void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) { diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 11d44a1e0ab3..632473beb40c 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -104,6 +104,68 @@ 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 +#include <linux/stackdepot.h> + +#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 +290,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 +357,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 +463,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 +929,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/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_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/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 <robdclark@gmail.com> + */ + +#include <stdarg.h> +#include <linux/seq_file.h> +#include <drm/drmP.h> +#include <drm/drm_print.h> + +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/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/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index 0dee6acbd880..a6799b0aa3d9 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -479,9 +479,7 @@ static const struct file_operations fops = { .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .poll = drm_poll, .read = drm_read, .llseek = no_llseek, diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 463d6fd56756..739180ac3da5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -366,9 +366,7 @@ static const struct file_operations exynos_drm_driver_fops = { .poll = drm_poll, .read = drm_read, .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .release = drm_release, }; diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c index e04efbed1a54..0b0d1cb11641 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c @@ -180,9 +180,7 @@ static const struct file_operations fsl_dcu_drm_fops = { .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .poll = drm_poll, .read = drm_read, .llseek = no_llseek, diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c index 76aea2e7fb9d..3f4f424196b2 100644 --- a/drivers/gpu/drm/gma500/gtt.c +++ b/drivers/gpu/drm/gma500/gtt.c @@ -131,7 +131,7 @@ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r, * page table entries with the dummy page. This is protected via the gtt * mutex which the caller must hold. */ -void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r) +static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r) { struct drm_psb_private *dev_priv = dev->dev_private; u32 __iomem *gtt_slot; diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 50eb944fb78a..ff37ea585664 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -473,6 +473,7 @@ static const struct file_operations psb_gem_fops = { .open = drm_open, .release = drm_release, .unlocked_ioctl = psb_unlocked_ioctl, + .compat_ioctl = drm_compat_ioctl, .mmap = drm_gem_mmap, .poll = drm_poll, .read = drm_read, diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index b74372760d7f..05d7aaf47eea 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -753,10 +753,6 @@ extern int psb_gem_dumb_create(struct drm_file *file, struct drm_device *dev, extern int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev, uint32_t handle, uint64_t *offset); extern int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); -extern int psb_gem_create_ioctl(struct drm_device *dev, void *data, - struct drm_file *file); -extern int psb_gem_mmap_ioctl(struct drm_device *dev, void *data, - struct drm_file *file); /* psb_device.c */ extern const struct psb_ops psb_chip_ops; diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c index e88fde18c946..ebd5f4fe4c23 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c @@ -152,9 +152,7 @@ static const struct file_operations kirin_drm_fops = { .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .poll = drm_poll, .read = drm_read, .llseek = no_llseek, diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c index d91856779beb..ab4e6cbe1f8b 100644 --- a/drivers/gpu/drm/i810/i810_dma.c +++ b/drivers/gpu/drm/i810/i810_dma.c @@ -113,9 +113,7 @@ static const struct file_operations i810_buffer_fops = { .release = drm_release, .unlocked_ioctl = drm_ioctl, .mmap = i810_mmap_buffers, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .llseek = noop_llseek, }; diff --git a/drivers/gpu/drm/i810/i810_drv.c b/drivers/gpu/drm/i810/i810_drv.c index 0be55dc1ef4b..02504a7cfaf2 100644 --- a/drivers/gpu/drm/i810/i810_drv.c +++ b/drivers/gpu/drm/i810/i810_drv.c @@ -49,9 +49,7 @@ static const struct file_operations i810_driver_fops = { .unlocked_ioctl = drm_ioctl, .mmap = drm_legacy_mmap, .poll = drm_poll, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .llseek = noop_llseek, }; diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug index cee87bfd10c4..51ba630a134b 100644 --- a/drivers/gpu/drm/i915/Kconfig.debug +++ b/drivers/gpu/drm/i915/Kconfig.debug @@ -21,6 +21,7 @@ config DRM_I915_DEBUG select PREEMPT_COUNT select X86_MSR # used by igt/pm_rpm select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks) + select DRM_DEBUG_MM if DRM=y default n help Choose this option to turn on extra driver debugging that may affect diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index b72c24ff39c3..0213a3090ab3 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -2497,9 +2497,7 @@ static const struct file_operations i915_driver_fops = { .mmap = drm_gem_mmap, .poll = drm_poll, .read = drm_read, -#ifdef CONFIG_COMPAT .compat_ioctl = i915_compat_ioctl, -#endif .llseek = noop_llseek, }; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 80775b882b4a..6f4a6bcf6ed4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3001,6 +3001,8 @@ __i915_printk(struct drm_i915_private *dev_priv, const char *level, #ifdef CONFIG_COMPAT extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#else +#define i915_compat_ioctl NULL #endif extern const struct dev_pm_ops i915_pm_ops; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 92ab01f33208..f4e321853fa4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2821,14 +2821,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 df0fbb4b15a3..0e9aac2e3eae 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/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 9672b579f950..a16e8b7df120 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -158,6 +158,7 @@ static int imx_drm_atomic_commit(struct drm_device *dev, struct drm_plane_state *plane_state; struct drm_plane *plane; struct dma_buf *dma_buf; + struct dma_fence *fence; int i; /* @@ -170,8 +171,9 @@ static int imx_drm_atomic_commit(struct drm_device *dev, 0)->base.dma_buf; if (!dma_buf) continue; - plane_state->fence = - reservation_object_get_excl_rcu(dma_buf->resv); + fence = reservation_object_get_excl_rcu(dma_buf->resv); + + drm_atomic_set_fence_for_plane(plane_state, fence); } } diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 296f541fbe2f..d90152e85ed0 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -249,9 +249,7 @@ static const struct file_operations mtk_drm_fops = { .mmap = mtk_drm_gem_mmap, .poll = drm_poll, .read = drm_read, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif }; static struct drm_driver mtk_drm_driver = { diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 1443b3a34775..b0b874264f9d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -82,9 +82,7 @@ static const struct file_operations mgag200_driver_fops = { .unlocked_ioctl = drm_ioctl, .mmap = mgag200_mmap, .poll = drm_poll, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .read = drm_read, }; diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c index a521207db8a1..b764d7f10312 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c @@ -15,6 +15,7 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <drm/drm_print.h> #include "msm_drv.h" #include "mdp4_kms.h" @@ -29,7 +30,16 @@ void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask, static void mdp4_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus) { + struct mdp4_kms *mdp4_kms = container_of(irq, struct mdp4_kms, error_handler); + static DEFINE_RATELIMIT_STATE(rs, 5*HZ, 1); + extern bool dumpstate; + DRM_ERROR_RATELIMITED("errors: %08x\n", irqstatus); + + if (dumpstate && __ratelimit(&rs)) { + struct drm_printer p = drm_info_printer(mdp4_kms->dev->dev); + drm_state_dump(mdp4_kms->dev, &p); + } } void mdp4_irq_preinstall(struct msm_kms *kms) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c index d53e5510fd7c..5c5940db898e 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c @@ -17,6 +17,8 @@ #include <linux/irq.h> +#include <drm/drm_print.h> + #include "msm_drv.h" #include "mdp5_kms.h" @@ -30,7 +32,16 @@ void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask, static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus) { + struct mdp5_kms *mdp5_kms = container_of(irq, struct mdp5_kms, error_handler); + static DEFINE_RATELIMIT_STATE(rs, 5*HZ, 1); + extern bool dumpstate; + DRM_ERROR_RATELIMITED("errors: %08x\n", irqstatus); + + if (dumpstate && __ratelimit(&rs)) { + struct drm_printer p = drm_info_printer(mdp5_kms->dev->dev); + drm_state_dump(mdp5_kms->dev, &p); + } } void mdp5_irq_preinstall(struct msm_kms *kms) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index 03738927be10..c6fbcfad2d59 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -114,6 +114,18 @@ static inline u32 mdp5_read(struct mdp5_kms *mdp5_kms, u32 reg) return msm_readl(mdp5_kms->mmio + reg); } +static inline const char *stage2name(enum mdp_mixer_stage_id stage) +{ + static const char *names[] = { +#define NAME(n) [n] = #n + NAME(STAGE_UNUSED), NAME(STAGE_BASE), + NAME(STAGE0), NAME(STAGE1), NAME(STAGE2), + NAME(STAGE3), NAME(STAGE4), NAME(STAGE6), +#undef NAME + }; + return names[stage]; +} + static inline const char *pipe2name(enum mdp5_pipe pipe) { static const char *names[] = { diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index cf50d3ec8d1b..8bf55e3450c5 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -16,6 +16,7 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <drm/drm_print.h> #include "mdp5_kms.h" struct mdp5_plane { @@ -181,6 +182,20 @@ done: #undef SET_PROPERTY } +static void +mdp5_plane_atomic_print_state(struct drm_printer *p, + const struct drm_plane_state *state) +{ + struct mdp5_plane_state *pstate = to_mdp5_plane_state(state); + + drm_printf(p, "\tpremultiplied=%u\n", pstate->premultiplied); + drm_printf(p, "\tzpos=%u\n", pstate->zpos); + drm_printf(p, "\talpha=%u\n", pstate->alpha); + drm_printf(p, "\tstage=%s\n", stage2name(pstate->stage)); + drm_printf(p, "\tmode_changed=%u\n", pstate->mode_changed); + drm_printf(p, "\tpending=%u\n", pstate->pending); +} + static void mdp5_plane_reset(struct drm_plane *plane) { struct mdp5_plane_state *mdp5_state; @@ -244,6 +259,7 @@ static const struct drm_plane_funcs mdp5_plane_funcs = { .reset = mdp5_plane_reset, .atomic_duplicate_state = mdp5_plane_duplicate_state, .atomic_destroy_state = mdp5_plane_destroy_state, + .atomic_print_state = mdp5_plane_atomic_print_state, }; static int mdp5_plane_prepare_fb(struct drm_plane *plane, @@ -913,7 +929,7 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev, type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs, mdp5_plane->formats, mdp5_plane->nformats, - type, NULL); + type, "%s", mdp5_plane->name); if (ret) goto fail; diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index db193f835298..4e21e1d72378 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -217,8 +217,9 @@ int msm_atomic_commit(struct drm_device *dev, if ((plane->state->fb != plane_state->fb) && plane_state->fb) { struct drm_gem_object *obj = msm_framebuffer_bo(plane_state->fb, 0); struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct dma_fence *fence = reservation_object_get_excl_rcu(msm_obj->resv); - plane_state->fence = reservation_object_get_excl_rcu(msm_obj->resv); + drm_atomic_set_fence_for_plane(plane_state, fence); } } diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 84d38eaea585..8d21fb27a401 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -79,6 +79,10 @@ static char *vram = "16m"; MODULE_PARM_DESC(vram, "Configure VRAM size (for devices without IOMMU/GPUMMU)"); module_param(vram, charp, 0); +bool dumpstate = false; +MODULE_PARM_DESC(dumpstate, "Dump KMS state on errors"); +module_param(dumpstate, bool, 0600); + /* * Util/helpers: */ @@ -768,9 +772,7 @@ static const struct file_operations fops = { .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .poll = drm_poll, .read = drm_read, .llseek = no_llseek, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 73c971e39b1c..68fd167d7313 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -201,9 +201,7 @@ static const struct file_operations rcar_du_fops = { .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .poll = drm_poll, .read = drm_read, .llseek = no_llseek, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 6fe161192bb4..2390c8577617 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -275,9 +275,7 @@ static const struct file_operations rockchip_drm_driver_fops = { .poll = drm_poll, .read = drm_read, .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .release = drm_release, }; diff --git a/drivers/gpu/drm/savage/savage_drv.c b/drivers/gpu/drm/savage/savage_drv.c index 3b807135a5cd..78c6d8e9b42c 100644 --- a/drivers/gpu/drm/savage/savage_drv.c +++ b/drivers/gpu/drm/savage/savage_drv.c @@ -42,9 +42,7 @@ static const struct file_operations savage_driver_fops = { .unlocked_ioctl = drm_ioctl, .mmap = drm_legacy_mmap, .poll = drm_poll, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .llseek = noop_llseek, }; diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index f0492603ea88..38dd55f4af81 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c @@ -245,9 +245,7 @@ static const struct file_operations shmob_drm_fops = { .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .poll = drm_poll, .read = drm_read, .llseek = no_llseek, diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c index ae9839886c4d..a836451920f0 100644 --- a/drivers/gpu/drm/sis/sis_drv.c +++ b/drivers/gpu/drm/sis/sis_drv.c @@ -72,9 +72,7 @@ static const struct file_operations sis_driver_fops = { .unlocked_ioctl = drm_ioctl, .mmap = drm_legacy_mmap, .poll = drm_poll, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .llseek = noop_llseek, }; diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index d614701bdcc7..ff71e25ab5bf 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -297,9 +297,7 @@ static const struct file_operations sti_driver_fops = { .poll = drm_poll, .read = drm_read, .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .release = drm_release, }; diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index b3c4ad605e81..aae723cd6d79 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -53,9 +53,7 @@ static const struct file_operations sun4i_drv_fops = { .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .poll = drm_poll, .read = drm_read, .llseek = no_llseek, diff --git a/drivers/gpu/drm/tdfx/tdfx_drv.c b/drivers/gpu/drm/tdfx/tdfx_drv.c index f418892b0c71..c54138c3a376 100644 --- a/drivers/gpu/drm/tdfx/tdfx_drv.c +++ b/drivers/gpu/drm/tdfx/tdfx_drv.c @@ -49,9 +49,7 @@ static const struct file_operations tdfx_driver_fops = { .unlocked_ioctl = drm_ioctl, .mmap = drm_legacy_mmap, .poll = drm_poll, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .llseek = noop_llseek, }; diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index a9630c2d6cb3..b8be3ee4d3b8 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -802,9 +802,7 @@ static const struct file_operations tegra_drm_fops = { .mmap = tegra_drm_mmap, .poll = drm_poll, .read = drm_read, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .llseek = noop_llseek, }; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 147fb28287ae..0f58a74f25d1 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -573,9 +573,7 @@ static const struct file_operations fops = { .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .poll = drm_poll, .read = drm_read, .llseek = no_llseek, diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index f6ff579e8918..d5063618efa7 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1611,7 +1611,14 @@ EXPORT_SYMBOL(ttm_bo_unmap_virtual); int ttm_bo_wait(struct ttm_buffer_object *bo, bool interruptible, bool no_wait) { - long timeout = no_wait ? 0 : 15 * HZ; + long timeout = 15 * HZ; + + if (no_wait) { + if (reservation_object_test_signaled_rcu(bo->resv, true)) + return 0; + else + return -EBUSY; + } timeout = reservation_object_wait_timeout_rcu(bo->resv, true, interruptible, timeout); diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c index cc45d98f9bb5..cd8b01727734 100644 --- a/drivers/gpu/drm/udl/udl_drv.c +++ b/drivers/gpu/drm/udl/udl_drv.c @@ -44,9 +44,7 @@ static const struct file_operations udl_driver_fops = { .read = drm_read, .unlocked_ioctl = drm_ioctl, .release = drm_release, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .llseek = noop_llseek, }; diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 8703f56b7947..eaf26d9b5f11 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -103,9 +103,7 @@ static const struct file_operations vc4_drm_fops = { .mmap = vc4_mmap, .poll = drm_poll, .read = drm_read, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .llseek = noop_llseek, }; diff --git a/drivers/gpu/drm/via/via_drv.c b/drivers/gpu/drm/via/via_drv.c index e5582bab7e3c..9e0e5392b6ec 100644 --- a/drivers/gpu/drm/via/via_drv.c +++ b/drivers/gpu/drm/via/via_drv.c @@ -64,9 +64,7 @@ static const struct file_operations via_driver_fops = { .unlocked_ioctl = drm_ioctl, .mmap = drm_legacy_mmap, .poll = drm_poll, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .llseek = noop_llseek, }; diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index 5820b7020ae5..04d98db75c64 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -108,9 +108,7 @@ static const struct file_operations virtio_gpu_driver_fops = { .read = drm_read, .unlocked_ioctl = drm_ioctl, .release = drm_release, -#ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, -#endif .llseek = noop_llseek, }; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index e336e3901876..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, @@ -306,6 +307,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 + /*@}*/ /***********************************************************************/ @@ -941,8 +963,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) */ diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index fc8af53b18aa..331bb100b718 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); @@ -364,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 && \ 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_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 <linux/seq_file.h> #endif +#ifdef CONFIG_DRM_DEBUG_MM +#include <linux/stackdepot.h> +#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 { 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. diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 0bed92c5dbd8..5b38eb94783b 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -28,15 +28,11 @@ #include <drm/drm_mode_object.h> struct drm_crtc; +struct drm_printer; /** * 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 @@ -57,18 +53,51 @@ struct drm_crtc; * it can be trusted. * @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() */ + /** + * @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; - /* Signed dest location allows it to be partially off screen */ - int32_t crtc_x, crtc_y; + /** + * @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; + uint32_t crtc_w, crtc_h; /* Source values are 16.16 fixed point */ @@ -85,15 +114,41 @@ 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; 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 */ @@ -322,6 +377,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); }; /** 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 <robdclark@gmail.com> + */ + +#ifndef DRM_PRINT_H_ +#define DRM_PRINT_H_ + +#include <linux/seq_file.h> +#include <linux/device.h> + +/** + * 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_ */ 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 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 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) |