diff options
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 30 |
1 files changed, 21 insertions, 9 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index d4f8fa5b3c18..64ef12079528 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -445,6 +445,12 @@ static void drm_framebuffer_free_bug(struct kref *kref) BUG(); } +static void __drm_framebuffer_unreference(struct drm_framebuffer *fb) +{ + DRM_DEBUG("FB ID: %d\n", fb->base.id); + kref_put(&fb->refcount, drm_framebuffer_free_bug); +} + /* dev->mode_config.fb_lock must be held! */ static void __drm_framebuffer_unregister(struct drm_device *dev, struct drm_framebuffer *fb) @@ -455,7 +461,7 @@ static void __drm_framebuffer_unregister(struct drm_device *dev, fb->base.id = 0; - kref_put(&fb->refcount, drm_framebuffer_free_bug); + __drm_framebuffer_unreference(fb); } /** @@ -544,6 +550,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) if (ret) DRM_ERROR("failed to disable plane with busy fb\n"); /* disconnect the plane from the fb and crtc: */ + __drm_framebuffer_unreference(plane->fb); plane->fb = NULL; plane->crtc = NULL; } @@ -1850,7 +1857,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data, struct drm_mode_object *obj; struct drm_plane *plane; struct drm_crtc *crtc; - struct drm_framebuffer *fb; + struct drm_framebuffer *fb = NULL, *old_fb = NULL; int ret = 0; unsigned int fb_width, fb_height; int i; @@ -1858,8 +1865,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - drm_modeset_lock_all(dev); - /* * First, find the plane, crtc, and fb objects. If not available, * we don't bother to call the driver. @@ -1869,16 +1874,18 @@ int drm_mode_setplane(struct drm_device *dev, void *data, if (!obj) { DRM_DEBUG_KMS("Unknown plane ID %d\n", plane_req->plane_id); - ret = -ENOENT; - goto out; + return -ENOENT; } plane = obj_to_plane(obj); /* No fb means shut it down */ if (!plane_req->fb_id) { + drm_modeset_lock_all(dev); + old_fb = plane->fb; plane->funcs->disable_plane(plane); plane->crtc = NULL; plane->fb = NULL; + drm_modeset_unlock_all(dev); goto out; } @@ -1899,8 +1906,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data, ret = -ENOENT; goto out; } - /* fb is protect by the mode_config lock, so drop the ref immediately */ - drm_framebuffer_unreference(fb); /* Check whether this plane supports the fb pixel format. */ for (i = 0; i < plane->format_count; i++) @@ -1946,18 +1951,25 @@ int drm_mode_setplane(struct drm_device *dev, void *data, goto out; } + drm_modeset_lock_all(dev); ret = plane->funcs->update_plane(plane, crtc, fb, plane_req->crtc_x, plane_req->crtc_y, plane_req->crtc_w, plane_req->crtc_h, plane_req->src_x, plane_req->src_y, plane_req->src_w, plane_req->src_h); if (!ret) { + old_fb = plane->fb; + fb = NULL; plane->crtc = crtc; plane->fb = fb; } + drm_modeset_unlock_all(dev); out: - drm_modeset_unlock_all(dev); + if (fb) + drm_framebuffer_unreference(fb); + if (old_fb) + drm_framebuffer_unreference(old_fb); return ret; } |