drm: pin new and unpin old buffer when setting a mode.
This removes the requirement for user space to pin a buffer before
setting a mode that is backed by the pixels from that buffer.
Signed-off-by: Kristian Høgsberg <krh@redhat.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@linux.ie>
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 58e3359..d8a982b 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -432,7 +432,8 @@
*/
bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
struct drm_display_mode *mode,
- int x, int y)
+ int x, int y,
+ struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
struct drm_display_mode *adjusted_mode, saved_mode;
@@ -462,7 +463,8 @@
if (drm_mode_equal(&saved_mode, &crtc->mode)) {
if (saved_x != crtc->x || saved_y != crtc->y) {
- crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y);
+ crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y,
+ old_fb);
goto done;
}
}
@@ -501,7 +503,7 @@
/* Set up the DPLL and any encoders state that needs to adjust or depend
* on the DPLL.
*/
- crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y);
+ crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb);
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
@@ -564,6 +566,7 @@
struct drm_device *dev;
struct drm_crtc **save_crtcs, *new_crtc;
struct drm_encoder **save_encoders, *new_encoder;
+ struct drm_framebuffer *old_fb;
bool save_enabled;
bool changed = false;
bool flip_or_move = false;
@@ -684,13 +687,15 @@
changed = true;
if (changed) {
+ old_fb = set->crtc->fb;
set->crtc->fb = set->fb;
set->crtc->enabled = (set->mode != NULL);
if (set->mode != NULL) {
DRM_DEBUG("attempting to set mode from userspace\n");
drm_mode_debug_printmodeline(set->mode);
if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
- set->x, set->y)) {
+ set->x, set->y,
+ old_fb)) {
ret = -EINVAL;
goto fail_set_mode;
}
@@ -701,9 +706,10 @@
}
drm_helper_disable_unused_functions(dev);
} else if (flip_or_move) {
+ old_fb = set->crtc->fb;
if (set->crtc->fb != set->fb)
set->crtc->fb = set->fb;
- crtc_funcs->mode_set_base(set->crtc, set->x, set->y);
+ crtc_funcs->mode_set_base(set->crtc, set->x, set->y, old_fb);
}
kfree(save_encoders);
@@ -809,8 +815,8 @@
if (!crtc->enabled)
continue;
- ret = drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
- crtc->y);
+ ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
+ crtc->x, crtc->y, crtc->fb);
if (ret == false)
DRM_ERROR("failed to set mode on crtc %p\n", crtc);