From: Maarten Lankhorst <[email protected]>

On cursor updates we should never unpin before the cursor is no longer
active. This means that we need to add a delay. The vblank worker
may cancel certain updates, so we/ only use it as a barrier to see
if a vblank has completed, and then wait for that in the cleanup
function.

Signed-off-by: Maarten Lankhorst <[email protected]>
---
 .../gpu/drm/i915/display/intel_atomic_plane.c | 18 ++++++++++++
 .../gpu/drm/i915/display/intel_atomic_plane.h |  2 ++
 drivers/gpu/drm/i915/display/intel_crtc.c     | 29 +++++++++++++++++++
 .../drm/i915/display/intel_display_types.h    |  5 ++++
 4 files changed, 54 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c 
b/drivers/gpu/drm/i915/display/intel_atomic_plane.c
index b1074350616c..1f2bb8e0c65b 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c
@@ -1153,6 +1153,9 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
        intel_display_rps_mark_interactive(dev_priv, state, false);
 
        /* Should only be called after a successful intel_prepare_plane_fb()! */
+       if (old_plane_state->unpin_work.vblank)
+               drm_vblank_work_flush(&old_plane_state->unpin_work);
+
        intel_plane_unpin_fb(old_plane_state);
 }
 
@@ -1165,3 +1168,18 @@ void intel_plane_helper_add(struct intel_plane *plane)
 {
        drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs);
 }
+
+/* Completion is enough */
+static void intel_plane_cursor_vblank_work(struct kthread_work *base)
+{ }
+
+void intel_plane_init_cursor_vblank_work(struct intel_plane_state 
*old_plane_state,
+                                        struct intel_plane_state 
*new_plane_state)
+{
+       if (!old_plane_state->ggtt_vma ||
+           old_plane_state->ggtt_vma == new_plane_state->ggtt_vma)
+               return;
+
+       drm_vblank_work_init(&old_plane_state->unpin_work, 
old_plane_state->uapi.crtc,
+                            intel_plane_cursor_vblank_work);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.h 
b/drivers/gpu/drm/i915/display/intel_atomic_plane.h
index 191dad0efc8e..5a897cf6fa02 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic_plane.h
+++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.h
@@ -66,5 +66,7 @@ int intel_plane_check_src_coordinates(struct 
intel_plane_state *plane_state);
 void intel_plane_set_invisible(struct intel_crtc_state *crtc_state,
                               struct intel_plane_state *plane_state);
 void intel_plane_helper_add(struct intel_plane *plane);
+void intel_plane_init_cursor_vblank_work(struct intel_plane_state 
*old_plane_state,
+                                        struct intel_plane_state 
*new_plane_state);
 
 #endif /* __INTEL_ATOMIC_PLANE_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c 
b/drivers/gpu/drm/i915/display/intel_crtc.c
index 1fd068e6e26c..20de5f62d492 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc.c
+++ b/drivers/gpu/drm/i915/display/intel_crtc.c
@@ -559,7 +559,21 @@ void intel_pipe_update_start(struct intel_atomic_state 
*state,
        if (intel_crtc_needs_vblank_work(new_crtc_state))
                intel_crtc_vblank_work_init(new_crtc_state);
 
+       if (state->base.legacy_cursor_update) {
+               struct intel_plane *plane;
+               struct intel_plane_state *old_plane_state, *new_plane_state;
+               int i;
+
+               for_each_oldnew_intel_plane_in_state(state, plane, 
old_plane_state,
+                                                    new_plane_state, i) {
+                       if (old_plane_state->uapi.crtc == &crtc->base)
+                               
intel_plane_init_cursor_vblank_work(old_plane_state,
+                                                                   
new_plane_state);
+               }
+       }
+
        intel_crtc_vblank_evade_scanlines(state, crtc, &min, &max, 
&vblank_start);
+
        if (min <= 0 || max <= 0)
                goto irq_disable;
 
@@ -721,6 +735,21 @@ void intel_pipe_update_end(struct intel_atomic_state 
*state,
                new_crtc_state->uapi.event = NULL;
        }
 
+       if (state->base.legacy_cursor_update) {
+               struct intel_plane *plane;
+               struct intel_plane_state *old_plane_state;
+               int i;
+
+               for_each_old_intel_plane_in_state(state, plane, 
old_plane_state, i) {
+                       if (old_plane_state->uapi.crtc == &crtc->base &&
+                           old_plane_state->unpin_work.vblank) {
+                               
drm_vblank_work_schedule(&old_plane_state->unpin_work,
+                                                        
drm_crtc_accurate_vblank_count(&crtc->base) + 1,
+                                                        false);
+                       }
+               }
+       }
+
        /*
         * Send VRR Push to terminate Vblank. If we are already in vblank
         * this has to be done _after_ sampling the frame counter, as
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h 
b/drivers/gpu/drm/i915/display/intel_display_types.h
index 8d8b2f8d37a9..d42fb0032ee6 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -761,6 +761,11 @@ struct intel_plane_state {
 
        struct drm_rect psr2_sel_fetch_area;
 
+       /*
+        * Unpin work for cursor fb updates.
+        */
+       struct drm_vblank_work unpin_work;
+
        /* Clear Color Value */
        u64 ccval;
 
-- 
2.40.1

Reply via email to