@@ -1003,13 +1003,112 @@ int drm_mode_cursor2_ioctl(struct drm_device *dev,
return drm_mode_cursor_common(dev, req, file_priv);
}
+static int page_flip_check_fbs(const struct drm_framebuffer *fb,
+ const struct drm_framebuffer *old_fb)
+{
+ /* The framebuffer is currently unbound, presumably
+ * due to a hotplug event, that userspace has not
+ * yet discovered.
+ */
+ if (!old_fb)
+ return -EBUSY;
+
+ if (old_fb->format != fb->format) {
+ DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int page_flip_internal(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *e,
+ u32 flags,
+ u32 target_vblank,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_plane *plane = crtc->primary;
+ int ret;
+
+ WARN_ON(drm_drv_uses_atomic_modeset(crtc->dev));
+
+ ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y,
+ &crtc->mode, fb);
+ if (ret)
+ return ret;
+
+ ret = page_flip_check_fbs(fb, plane->fb);
+ if (ret)
+ return ret;
+
+ plane->old_fb = plane->fb;
+
+ if (crtc->funcs->page_flip_target)
+ ret = crtc->funcs->page_flip_target(crtc, fb, e, flags,
+ target_vblank, ctx);
+ else
+ ret = crtc->funcs->page_flip(crtc, fb, e, flags, ctx);
+
+ if (ret) {
+ /* Keep the old fb, don't unref it. */
+ plane->old_fb = NULL;
+ } else {
+ plane->fb = fb;
+ drm_framebuffer_get(plane->fb);
+ }
+
+ if (plane->old_fb)
+ drm_framebuffer_put(plane->old_fb);
+ plane->old_fb = NULL;
+
+ return ret;
+}
+
+static int page_flip_atomic(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *e,
+ u32 flags,
+ u32 target_vblank,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_plane *plane = crtc->primary;
+ struct drm_plane_state *plane_state = plane->state;
+ int ret;
+
+ WARN_ON(!drm_drv_uses_atomic_modeset(crtc->dev));
+
+ /*
+ * FIXME: Can we assume all drivers end up calling
+ * drm_atomic_plane_check() in their page flip paths?
+ * If so we could remove this.
+ */
+ ret = drm_framebuffer_check_src_coords(plane_state->src_x,
+ plane_state->src_y,
+ plane_state->src_w,
+ plane_state->src_h,
+ fb);
+ if (ret)
+ return ret;
+
+ ret = page_flip_check_fbs(fb, plane_state->fb);
+ if (ret)
+ return ret;
+
+ if (crtc->funcs->page_flip_target)
+ return crtc->funcs->page_flip_target(crtc, fb, e, flags,
+ target_vblank, ctx);
+ else
+ return crtc->funcs->page_flip(crtc, fb, e, flags, ctx);
+}
+
int drm_mode_page_flip_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
{
struct drm_mode_crtc_page_flip_target *page_flip = data;
struct drm_crtc *crtc;
struct drm_plane *plane;
- struct drm_framebuffer *fb, *old_fb;
+ struct drm_framebuffer *fb;
struct drm_pending_vblank_event *e = NULL;
u32 target_vblank = page_flip->sequence;
struct drm_modeset_acquire_ctx ctx;
@@ -1114,65 +1213,14 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
if (ret)
goto out;
- if (plane->state)
- old_fb = plane->state->fb;
- else
- old_fb = plane->fb;
-
- if (old_fb == NULL) {
- /* The framebuffer is currently unbound, presumably
- * due to a hotplug event, that userspace has not
- * yet discovered.
- */
- ret = -EBUSY;
- goto out;
- }
-
- if (plane->state) {
- const struct drm_plane_state *state = plane->state;
-
- ret = drm_framebuffer_check_src_coords(state->src_x,
- state->src_y,
- state->src_w,
- state->src_h,
- fb);
- } else {
- ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y,
- &crtc->mode, fb);
- }
- if (ret)
- goto out;
-
- if (old_fb->format != fb->format) {
- DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
- ret = -EINVAL;
- goto out;
- }
-
- plane->old_fb = plane->fb;
- if (crtc->funcs->page_flip_target)
- ret = crtc->funcs->page_flip_target(crtc, fb, e,
- page_flip->flags,
- target_vblank,
- &ctx);
+ if (drm_drv_uses_atomic_modeset(dev))
+ ret = page_flip_atomic(crtc, fb, e, page_flip->flags,
+ target_vblank, &ctx);
else
- ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags,
- &ctx);
- if (ret) {
- /* Keep the old fb, don't unref it. */
- plane->old_fb = NULL;
- } else {
- if (!plane->state) {
- plane->fb = fb;
- drm_framebuffer_get(fb);
- }
- }
+ ret = page_flip_internal(crtc, fb, e, page_flip->flags,
+ target_vblank, &ctx);
out:
- if (plane->old_fb)
- drm_framebuffer_put(plane->old_fb);
- plane->old_fb = NULL;
-
if (ret == -EDEADLK) {
ret = drm_modeset_backoff(&ctx);
if (!ret)