summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c53
-rw-r--r--drivers/gpu/drm/i915/intel_display.c26
-rw-r--r--include/drm/drm_plane.h5
3 files changed, 34 insertions, 50 deletions
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 820adcda45b8..b97c054f9786 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1388,35 +1388,31 @@ int drm_atomic_helper_async_check(struct drm_device *dev,
{
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
- struct drm_crtc_commit *commit;
- struct drm_plane *__plane, *plane = NULL;
- struct drm_plane_state *__plane_state, *plane_state = NULL;
+ struct drm_plane *plane;
+ struct drm_plane_state *old_plane_state, *new_plane_state;
const struct drm_plane_helper_funcs *funcs;
- int i, j, n_planes = 0;
+ int i, n_planes = 0;
for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
if (drm_atomic_crtc_needs_modeset(crtc_state))
return -EINVAL;
}
- for_each_new_plane_in_state(state, __plane, __plane_state, i) {
+ for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i)
n_planes++;
- plane = __plane;
- plane_state = __plane_state;
- }
/* FIXME: we support only single plane updates for now */
- if (!plane || n_planes != 1)
+ if (n_planes != 1)
return -EINVAL;
- if (!plane_state->crtc)
+ if (!new_plane_state->crtc)
return -EINVAL;
funcs = plane->helper_private;
if (!funcs->atomic_async_update)
return -EINVAL;
- if (plane_state->fence)
+ if (new_plane_state->fence)
return -EINVAL;
/*
@@ -1424,31 +1420,11 @@ int drm_atomic_helper_async_check(struct drm_device *dev,
* the plane. This prevents our async update's changes from getting
* overridden by a previous synchronous update's state.
*/
- for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
- if (plane->crtc != crtc)
- continue;
-
- spin_lock(&crtc->commit_lock);
- commit = list_first_entry_or_null(&crtc->commit_list,
- struct drm_crtc_commit,
- commit_entry);
- if (!commit) {
- spin_unlock(&crtc->commit_lock);
- continue;
- }
- spin_unlock(&crtc->commit_lock);
-
- if (!crtc->state->state)
- continue;
+ if (old_plane_state->commit &&
+ !try_wait_for_completion(&old_plane_state->commit->hw_done))
+ return -EBUSY;
- for_each_plane_in_state(crtc->state->state, __plane,
- __plane_state, j) {
- if (__plane == plane)
- return -EINVAL;
- }
- }
-
- return funcs->atomic_async_check(plane, plane_state);
+ return funcs->atomic_async_check(plane, new_plane_state);
}
EXPORT_SYMBOL(drm_atomic_helper_async_check);
@@ -1814,9 +1790,10 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
}
for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
- /* commit tracked through new_crtc_state->commit, no need to do it explicitly */
- if (new_plane_state->crtc)
- continue;
+ /*
+ * Unlike connectors, always track planes explicitly for
+ * async pageflip support.
+ */
/* Userspace is not allowed to get ahead of the previous
* commit with nonblocking ones. */
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 2e7376f9019f..3f505682963f 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13548,6 +13548,14 @@ intel_legacy_cursor_update(struct drm_plane *plane,
goto slow;
old_plane_state = plane->state;
+ /*
+ * Don't do an async update if there is an outstanding commit modifying
+ * the plane. This prevents our async update's changes from getting
+ * overridden by a previous synchronous update's state.
+ */
+ if (old_plane_state->commit &&
+ !try_wait_for_completion(&old_plane_state->commit->hw_done))
+ goto slow;
/*
* If any parameters change that may affect watermarks,
@@ -13609,19 +13617,12 @@ intel_legacy_cursor_update(struct drm_plane *plane,
}
old_fb = old_plane_state->fb;
- old_vma = to_intel_plane_state(old_plane_state)->vma;
i915_gem_track_fb(intel_fb_obj(old_fb), intel_fb_obj(fb),
intel_plane->frontbuffer_bit);
/* Swap plane state */
- new_plane_state->fence = old_plane_state->fence;
- new_plane_state->commit = old_plane_state->commit;
- *to_intel_plane_state(old_plane_state) = *to_intel_plane_state(new_plane_state);
- new_plane_state->fence = NULL;
- new_plane_state->commit = NULL;
- new_plane_state->fb = old_fb;
- to_intel_plane_state(new_plane_state)->vma = old_vma;
+ plane->state = new_plane_state;
if (plane->state->visible) {
trace_intel_update_plane(plane, to_intel_crtc(crtc));
@@ -13633,12 +13634,17 @@ intel_legacy_cursor_update(struct drm_plane *plane,
intel_plane->disable_plane(intel_plane, to_intel_crtc(crtc));
}
- intel_cleanup_plane_fb(plane, new_plane_state);
+ old_vma = fetch_and_zero(&to_intel_plane_state(old_plane_state)->vma);
+ if (old_vma)
+ intel_unpin_fb_vma(old_vma);
out_unlock:
mutex_unlock(&dev_priv->drm.struct_mutex);
out_free:
- intel_plane_destroy_state(plane, new_plane_state);
+ if (ret)
+ intel_plane_destroy_state(plane, new_plane_state);
+ else
+ intel_plane_destroy_state(plane, old_plane_state);
return ret;
slow:
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
index 7d96116fd4c4..feb9941d0cdb 100644
--- a/include/drm/drm_plane.h
+++ b/include/drm/drm_plane.h
@@ -124,9 +124,10 @@ struct drm_plane_state {
bool visible;
/**
- * @commit: Tracks the pending commit to prevent use-after-free conditions.
+ * @commit: Tracks the pending commit to prevent use-after-free conditions,
+ * and for async plane updates.
*
- * Is only set when @crtc is NULL.
+ * May be NULL.
*/
struct drm_crtc_commit *commit;