drm/i915: Stop accessing crtc->state from the flip done irq
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Thu, 28 Sep 2023 15:24:49 +0000 (18:24 +0300)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Sat, 9 Dec 2023 02:13:57 +0000 (04:13 +0200)
Assuming crtc->state is pointing at the correct thing for the
async flip commit is nonsense. If we had already queued up multiple
commits this would point at the very lates crtc state even if the
older commits hadn't even happened yet.

Instead properly stage/arm the event like we do for async flips.
Since we don't need to arm multiple of these at the same time we
don't need a list like the normal vblank even processing uses.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230928152450.30109-1-ville.syrjala@linux.intel.com
Reviewed-by: Arun R Murthy <arun.r.murthy@intel.com>
drivers/gpu/drm/i915/display/intel_crtc.c
drivers/gpu/drm/i915/display/intel_display_irq.c
drivers/gpu/drm/i915/display/intel_display_types.h

index 1fd068e6e26ca6f265a9702085acae67dfc94a05..8a84a31c7b48a24ceb8c9e61116410854c38dc39 100644 (file)
@@ -553,8 +553,15 @@ void intel_pipe_update_start(struct intel_atomic_state *state,
 
        intel_psr_lock(new_crtc_state);
 
-       if (new_crtc_state->do_async_flip)
+       if (new_crtc_state->do_async_flip) {
+               spin_lock_irq(&crtc->base.dev->event_lock);
+               /* arm the event for the flip done irq handler */
+               crtc->flip_done_event = new_crtc_state->uapi.event;
+               spin_unlock_irq(&crtc->base.dev->event_lock);
+
+               new_crtc_state->uapi.event = NULL;
                return;
+       }
 
        if (intel_crtc_needs_vblank_work(new_crtc_state))
                intel_crtc_vblank_work_init(new_crtc_state);
index f8ed53f30b2e44ec732876c7e1a758277aff51ee..6f2b45cfcf72104da26c097569973107635c540e 100644 (file)
@@ -340,16 +340,15 @@ static void flip_done_handler(struct drm_i915_private *i915,
                              enum pipe pipe)
 {
        struct intel_crtc *crtc = intel_crtc_for_pipe(i915, pipe);
-       struct drm_crtc_state *crtc_state = crtc->base.state;
-       struct drm_pending_vblank_event *e = crtc_state->event;
        struct drm_device *dev = &i915->drm;
        unsigned long irqflags;
 
        spin_lock_irqsave(&dev->event_lock, irqflags);
 
-       crtc_state->event = NULL;
-
-       drm_crtc_send_vblank_event(&crtc->base, e);
+       if (crtc->flip_done_event) {
+               drm_crtc_send_vblank_event(&crtc->base, crtc->flip_done_event);
+               crtc->flip_done_event = NULL;
+       }
 
        spin_unlock_irqrestore(&dev->event_lock, irqflags);
 }
index 2616bb6267a10e6c61970a827aa74b479d0f1269..341d80c2b9de9f2ab3021935009e3e129d6b8684 100644 (file)
@@ -1475,6 +1475,9 @@ struct intel_crtc {
 
        struct intel_crtc_state *config;
 
+       /* armed event for async flip */
+       struct drm_pending_vblank_event *flip_done_event;
+
        /* Access to these should be protected by dev_priv->irq_lock. */
        bool cpu_fifo_underrun_disabled;
        bool pch_fifo_underrun_disabled;