diff options
Diffstat (limited to 'drivers/gpu/drm/drm_plane.c')
-rw-r--r-- | drivers/gpu/drm/drm_plane.c | 91 |
1 files changed, 74 insertions, 17 deletions
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index a22e76837065..bc71aa2b7872 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -277,6 +277,12 @@ EXPORT_SYMBOL(drm_plane_from_index); * * Used when the plane's current framebuffer is destroyed, * and when restoring fbdev mode. + * + * Note that this function is not suitable for atomic drivers, since it doesn't + * wire through the lock acquisition context properly and hence can't handle + * retries or driver private locks. You probably want to use + * drm_atomic_helper_disable_plane() or + * drm_atomic_helper_disable_planes_on_crtc() instead. */ void drm_plane_force_disable(struct drm_plane *plane) { @@ -285,8 +291,10 @@ void drm_plane_force_disable(struct drm_plane *plane) if (!plane->fb) return; + WARN_ON(drm_drv_uses_atomic_modeset(plane->dev)); + plane->old_fb = plane->fb; - ret = plane->funcs->disable_plane(plane); + ret = plane->funcs->disable_plane(plane, NULL); if (ret) { DRM_ERROR("failed to disable plane with busy fb\n"); plane->old_fb = NULL; @@ -457,14 +465,15 @@ static int __setplane_internal(struct drm_plane *plane, uint32_t crtc_w, uint32_t crtc_h, /* src_{x,y,w,h} values are 16.16 fixed point */ uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { int ret = 0; /* No fb means shut it down */ if (!fb) { plane->old_fb = plane->fb; - ret = plane->funcs->disable_plane(plane); + ret = plane->funcs->disable_plane(plane, ctx); if (!ret) { plane->crtc = NULL; plane->fb = NULL; @@ -509,7 +518,7 @@ static int __setplane_internal(struct drm_plane *plane, plane->old_fb = plane->fb; ret = plane->funcs->update_plane(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); + src_x, src_y, src_w, src_h, ctx); if (!ret) { plane->crtc = crtc; plane->fb = fb; @@ -537,13 +546,25 @@ static int setplane_internal(struct drm_plane *plane, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { + struct drm_modeset_acquire_ctx ctx; int ret; - drm_modeset_lock_all(plane->dev); + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock_all_ctx(plane->dev, &ctx); + if (ret) + goto fail; ret = __setplane_internal(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); - drm_modeset_unlock_all(plane->dev); + src_x, src_y, src_w, src_h, &ctx); + +fail: + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); return ret; } @@ -613,11 +634,21 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, int32_t crtc_x, crtc_y; uint32_t crtc_w = 0, crtc_h = 0; uint32_t src_w = 0, src_h = 0; + struct drm_modeset_acquire_ctx ctx; int ret = 0; BUG_ON(!crtc->cursor); WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock(&crtc->mutex, &ctx); + if (ret) + goto fail; + ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx); + if (ret) + goto fail; + /* * Obtain fb we'll be using (either new or existing) and take an extra * reference to it if fb != null. setplane will take care of dropping @@ -662,7 +693,7 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, */ ret = __setplane_internal(crtc->cursor, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, - 0, 0, src_w, src_h); + 0, 0, src_w, src_h, &ctx); /* Update successful; save new cursor position, if necessary */ if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { @@ -670,6 +701,15 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, crtc->cursor_y = req->y; } +fail: + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + return ret; } @@ -696,12 +736,10 @@ static int drm_mode_cursor_common(struct drm_device *dev, * If this crtc has a universal cursor plane, call that plane's update * handler rather than using legacy cursor handlers. */ - drm_modeset_lock_crtc(crtc, crtc->cursor); - if (crtc->cursor) { - ret = drm_mode_cursor_universal(crtc, req, file_priv); - goto out; - } + if (crtc->cursor) + return drm_mode_cursor_universal(crtc, req, file_priv); + drm_modeset_lock_crtc(crtc, crtc->cursor); if (req->flags & DRM_MODE_CURSOR_BO) { if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { ret = -ENXIO; @@ -765,6 +803,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, struct drm_framebuffer *fb = NULL; struct drm_pending_vblank_event *e = NULL; u32 target_vblank = page_flip->sequence; + struct drm_modeset_acquire_ctx ctx; int ret = -EINVAL; if (!drm_core_check_feature(dev, DRIVER_MODESET)) @@ -828,7 +867,15 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, return -EINVAL; } - drm_modeset_lock_crtc(crtc, crtc->primary); + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock(&crtc->mutex, &ctx); + if (ret) + goto out; + ret = drm_modeset_lock(&crtc->primary->mutex, &ctx); + if (ret) + goto out; + if (crtc->primary->fb == NULL) { /* The framebuffer is currently unbound, presumably * due to a hotplug event, that userspace has not @@ -876,6 +923,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base); if (ret) { kfree(e); + e = NULL; goto out; } } @@ -884,9 +932,11 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, if (crtc->funcs->page_flip_target) ret = crtc->funcs->page_flip_target(crtc, fb, e, page_flip->flags, - target_vblank); + target_vblank, + &ctx); else - ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); + ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags, + &ctx); if (ret) { if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) drm_event_cancel_free(dev, &e->base); @@ -906,7 +956,14 @@ out: if (crtc->primary->old_fb) drm_framebuffer_put(crtc->primary->old_fb); crtc->primary->old_fb = NULL; - drm_modeset_unlock_crtc(crtc); + + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); return ret; } |