aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_plane.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_plane.c')
-rw-r--r--drivers/gpu/drm/drm_plane.c107
1 files changed, 82 insertions, 25 deletions
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index c464fc4a874d..5dc8c4350602 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -88,7 +88,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
struct drm_mode_config *config = &dev->mode_config;
int ret;
- ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
+ ret = drm_mode_object_add(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
if (ret)
return ret;
@@ -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,15 +291,17 @@ 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;
return;
}
/* disconnect the plane from the fb and crtc: */
- drm_framebuffer_unreference(plane->old_fb);
+ drm_framebuffer_put(plane->old_fb);
plane->old_fb = NULL;
plane->fb = NULL;
plane->crtc = 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;
@@ -520,9 +529,9 @@ static int __setplane_internal(struct drm_plane *plane,
out:
if (fb)
- drm_framebuffer_unreference(fb);
+ drm_framebuffer_put(fb);
if (plane->old_fb)
- drm_framebuffer_unreference(plane->old_fb);
+ drm_framebuffer_put(plane->old_fb);
plane->old_fb = NULL;
return ret;
@@ -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;
}
@@ -599,7 +620,8 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
static int drm_mode_cursor_universal(struct drm_crtc *crtc,
struct drm_mode_cursor2 *req,
- struct drm_file *file_priv)
+ struct drm_file *file_priv,
+ struct drm_modeset_acquire_ctx *ctx)
{
struct drm_device *dev = crtc->dev;
struct drm_framebuffer *fb = NULL;
@@ -638,7 +660,7 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc,
} else {
fb = crtc->cursor->fb;
if (fb)
- drm_framebuffer_reference(fb);
+ drm_framebuffer_get(fb);
}
if (req->flags & DRM_MODE_CURSOR_MOVE) {
@@ -662,7 +684,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) {
@@ -678,6 +700,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
struct drm_file *file_priv)
{
struct drm_crtc *crtc;
+ struct drm_modeset_acquire_ctx ctx;
int ret = 0;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
@@ -692,13 +715,21 @@ static int drm_mode_cursor_common(struct drm_device *dev,
return -ENOENT;
}
+ drm_modeset_acquire_init(&ctx, 0);
+retry:
+ ret = drm_modeset_lock(&crtc->mutex, &ctx);
+ if (ret)
+ goto out;
/*
* 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);
+ ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx);
+ if (ret)
+ goto out;
+
+ ret = drm_mode_cursor_universal(crtc, req, file_priv, &ctx);
goto out;
}
@@ -725,7 +756,13 @@ static int drm_mode_cursor_common(struct drm_device *dev,
}
}
out:
- 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;
@@ -765,6 +802,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 +866,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 +922,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 +931,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);
@@ -899,14 +948,22 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
}
out:
- if (ret && crtc->funcs->page_flip_target)
- drm_crtc_vblank_put(crtc);
if (fb)
- drm_framebuffer_unreference(fb);
+ drm_framebuffer_put(fb);
if (crtc->primary->old_fb)
- drm_framebuffer_unreference(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);
+
+ if (ret && crtc->funcs->page_flip_target)
+ drm_crtc_vblank_put(crtc);
return ret;
}