* [PATCH 1/4] drm/i915: Suppress redundant syncs with mmio page flips
@ 2014-06-18 11:23 Chris Wilson
2014-06-18 11:23 ` [PATCH 2/4] drm/i915: Check for a stalled page flip after each vblank Chris Wilson
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Chris Wilson @ 2014-06-18 11:23 UTC (permalink / raw)
To: intel-gfx
Since mmio-flips do not occur on the suggested ring, we are introducing
an extra sync operation where none is required. Pass the current
obj->ring, which is what mmio flip will use, to pin_to_display_plane so
that we emit the appropriate synchronisation (none).
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
drivers/gpu/drm/i915/intel_display.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 5e8e711..55cb343 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -9492,21 +9492,32 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
ring = &dev_priv->ring[RCS];
}
- ret = intel_pin_and_fence_fb_obj(dev, obj, ring);
- if (ret)
- goto cleanup_pending;
+ if (use_mmio_flip(ring, obj)) {
+ ret = intel_pin_and_fence_fb_obj(dev, obj, obj->ring);
+ if (ret)
+ goto cleanup_pending;
- work->gtt_offset =
- i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;
+ work->gtt_offset =
+ i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;
- if (use_mmio_flip(ring, obj))
ret = intel_queue_mmio_flip(dev, crtc, fb, obj, ring,
page_flip_flags);
- else
+ if (ret)
+ goto cleanup_unpin;
+
+ } else {
+ ret = intel_pin_and_fence_fb_obj(dev, obj, ring);
+ if (ret)
+ goto cleanup_pending;
+
+ work->gtt_offset =
+ i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;
+
ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, ring,
page_flip_flags);
- if (ret)
- goto cleanup_unpin;
+ if (ret)
+ goto cleanup_unpin;
+ }
intel_disable_fbc(dev);
intel_mark_fb_busy(obj, NULL);
--
1.9.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 2/4] drm/i915: Check for a stalled page flip after each vblank 2014-06-18 11:23 [PATCH 1/4] drm/i915: Suppress redundant syncs with mmio page flips Chris Wilson @ 2014-06-18 11:23 ` Chris Wilson 2014-06-18 11:23 ` [PATCH 3/4] drm/i915: Decouple the stuck pageflip on modeset Chris Wilson ` (2 subsequent siblings) 3 siblings, 0 replies; 7+ messages in thread From: Chris Wilson @ 2014-06-18 11:23 UTC (permalink / raw) To: intel-gfx; +Cc: Daniel Vetter Long ago, back in the racy haydays of 915gm interrupt handling, page flips would occasionally go astray and leave the hardware stuck, and the display not updating. This annoyed people who relied on their systems being able to display continuously updating information 24/7, and so some code to detect when the driver missed the page flip completion signal was added. Until recently, it was presumed that the interrupt handling was now flawless, but once again Simon Farnsworth has found a system whose display will stall. Reinstate the pageflip stall detection, which works by checking to see if the hardware has been updated to the new framebuffer address following each vblank. If the hardware is scanning out from the new framebuffer, but we still think the flip is pending, then we kick our driver into submision. This is a continuation of the effort started with commit 4e5359cd053bfb7d8dabe4a63624a5726848ffbc Author: Simon Farnsworth <simon.farnsworth@onelan.co.uk> Date: Wed Sep 1 17:47:52 2010 +0100 drm/i915: Avoid pageflipping freeze when we miss the flip prepare interrupt This now includes a belt-and-braces approach to make sure the driver (or the hardware) doesn't miss an interrupt and cause us to stop updating the display should the unthinkable happen and the pageflip fail - i.e. that the user is able to continue submitting flips. v2: Cleanup, refactor, and rename v3: Only start counting vblanks after the flip command has been seen by the hardware. v4: Record the seqno after we touch the ring, or else there may be no seqno allocated yet. v5: Rebase on mmio-flip. Reported-by: Simon Farnsworth <simon@farnz.org.uk> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=75502 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> [v4] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> --- drivers/gpu/drm/i915/i915_debugfs.c | 32 ++++++--- drivers/gpu/drm/i915/i915_irq.c | 84 +++++++---------------- drivers/gpu/drm/i915/intel_display.c | 127 ++++++++++++++++++++++++++++------- drivers/gpu/drm/i915/intel_drv.h | 5 ++ 4 files changed, 155 insertions(+), 93 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 76c2572..b4c6f20 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -511,6 +511,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data) { struct drm_info_node *node = m->private; struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; unsigned long flags; struct intel_crtc *crtc; int ret; @@ -530,6 +531,8 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data) seq_printf(m, "No flip due on pipe %c (plane %c)\n", pipe, plane); } else { + u32 addr; + if (atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) { seq_printf(m, "Flip queued on pipe %c (plane %c)\n", pipe, plane); @@ -537,23 +540,32 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data) seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n", pipe, plane); } + if (work->ring) + seq_printf(m, "Flip queued on %s at seqno %u, now %u\n", + work->ring->name, + work->flip_queued_seqno, + work->ring->get_seqno(work->ring, true)); + else + seq_printf(m, "Flip not associated with any ring\n"); + seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n", + work->flip_queued_vblank, + work->flip_ready_vblank, + drm_vblank_count(dev, crtc->pipe)); if (work->enable_stall_check) seq_puts(m, "Stall check enabled, "); else seq_puts(m, "Stall check waiting for page flip ioctl, "); seq_printf(m, "%d prepares\n", atomic_read(&work->pending)); - if (work->old_fb_obj) { - struct drm_i915_gem_object *obj = work->old_fb_obj; - if (obj) - seq_printf(m, "Old framebuffer gtt_offset 0x%08lx\n", - i915_gem_obj_ggtt_offset(obj)); - } + if (INTEL_INFO(dev)->gen >= 4) + addr = I915_HI_DISPBASE(I915_READ(DSPSURF(crtc->plane))); + else + addr = I915_READ(DSPADDR(crtc->plane)); + seq_printf(m, "Current scanout address 0x%08x\n", addr); + if (work->pending_flip_obj) { - struct drm_i915_gem_object *obj = work->pending_flip_obj; - if (obj) - seq_printf(m, "New framebuffer gtt_offset 0x%08lx\n", - i915_gem_obj_ggtt_offset(obj)); + seq_printf(m, "New framebuffer address 0x%08lx\n", (long)work->gtt_offset); + seq_printf(m, "MMIO update completed? %d\n", addr == work->gtt_offset); } } spin_unlock_irqrestore(&dev->event_lock, flags); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 1c1ec22..809fd50 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1791,8 +1791,9 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir) spin_unlock(&dev_priv->irq_lock); for_each_pipe(pipe) { - if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS) - intel_pipe_handle_vblank(dev, pipe); + if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS && + intel_pipe_handle_vblank(dev, pipe)) + intel_check_page_flip(dev, pipe); if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) { intel_prepare_page_flip(dev, pipe); @@ -2083,8 +2084,9 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir) DRM_ERROR("Poison interrupt\n"); for_each_pipe(pipe) { - if (de_iir & DE_PIPE_VBLANK(pipe)) - intel_pipe_handle_vblank(dev, pipe); + if (de_iir & DE_PIPE_VBLANK(pipe) && + intel_pipe_handle_vblank(dev, pipe)) + intel_check_page_flip(dev, pipe); if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe)) if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) @@ -2133,8 +2135,9 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir) intel_opregion_asle_intr(dev); for_each_pipe(pipe) { - if (de_iir & (DE_PIPE_VBLANK_IVB(pipe))) - intel_pipe_handle_vblank(dev, pipe); + if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)) && + intel_pipe_handle_vblank(dev, pipe)) + intel_check_page_flip(dev, pipe); /* plane/pipes map 1:1 on ilk+ */ if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) { @@ -2289,8 +2292,9 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg) if (pipe_iir) { ret = IRQ_HANDLED; I915_WRITE(GEN8_DE_PIPE_IIR(pipe), pipe_iir); - if (pipe_iir & GEN8_PIPE_VBLANK) - intel_pipe_handle_vblank(dev, pipe); + if (pipe_iir & GEN8_PIPE_VBLANK && + intel_pipe_handle_vblank(dev, pipe)) + intel_check_page_flip(dev, pipe); if (pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE) { intel_prepare_page_flip(dev, pipe); @@ -2595,52 +2599,6 @@ void i915_handle_error(struct drm_device *dev, bool wedged, schedule_work(&dev_priv->gpu_error.work); } -static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, int pipe) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct drm_i915_gem_object *obj; - struct intel_unpin_work *work; - unsigned long flags; - bool stall_detected; - - /* Ignore early vblank irqs */ - if (intel_crtc == NULL) - return; - - spin_lock_irqsave(&dev->event_lock, flags); - work = intel_crtc->unpin_work; - - if (work == NULL || - atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE || - !work->enable_stall_check) { - /* Either the pending flip IRQ arrived, or we're too early. Don't check */ - spin_unlock_irqrestore(&dev->event_lock, flags); - return; - } - - /* Potential stall - if we see that the flip has happened, assume a missed interrupt */ - obj = work->pending_flip_obj; - if (INTEL_INFO(dev)->gen >= 4) { - int dspsurf = DSPSURF(intel_crtc->plane); - stall_detected = I915_HI_DISPBASE(I915_READ(dspsurf)) == - i915_gem_obj_ggtt_offset(obj); - } else { - int dspaddr = DSPADDR(intel_crtc->plane); - stall_detected = I915_READ(dspaddr) == (i915_gem_obj_ggtt_offset(obj) + - crtc->y * crtc->primary->fb->pitches[0] + - crtc->x * crtc->primary->fb->bits_per_pixel/8); - } - - spin_unlock_irqrestore(&dev->event_lock, flags); - - if (stall_detected) { - DRM_DEBUG_DRIVER("Pageflip stall detected\n"); - intel_prepare_page_flip(dev, intel_crtc->plane); - } -} - /* Called from drm generic code, passed 'crtc' which * we use as a pipe index */ @@ -3755,7 +3713,7 @@ static bool i8xx_handle_vblank(struct drm_device *dev, return false; if ((iir & flip_pending) == 0) - return false; + goto check_page_flip; intel_prepare_page_flip(dev, plane); @@ -3766,11 +3724,14 @@ static bool i8xx_handle_vblank(struct drm_device *dev, * an interrupt per se, we watch for the change at vblank. */ if (I915_READ16(ISR) & flip_pending) - return false; + goto check_page_flip; intel_finish_page_flip(dev, pipe); - return true; + +check_page_flip: + intel_check_page_flip(dev, pipe); + return false; } static irqreturn_t i8xx_irq_handler(int irq, void *arg) @@ -3940,7 +3901,7 @@ static bool i915_handle_vblank(struct drm_device *dev, return false; if ((iir & flip_pending) == 0) - return false; + goto check_page_flip; intel_prepare_page_flip(dev, plane); @@ -3951,11 +3912,14 @@ static bool i915_handle_vblank(struct drm_device *dev, * an interrupt per se, we watch for the change at vblank. */ if (I915_READ(ISR) & flip_pending) - return false; + goto check_page_flip; intel_finish_page_flip(dev, pipe); - return true; + +check_page_flip: + intel_check_page_flip(dev, pipe); + return false; } static irqreturn_t i915_irq_handler(int irq, void *arg) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 55cb343..9a077b6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3335,6 +3335,29 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev) return false; } +static void page_flip_completed(struct intel_crtc *intel_crtc) +{ + struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); + struct intel_unpin_work *work = intel_crtc->unpin_work; + + /* ensure that the unpin work is consistent wrt ->pending. */ + smp_rmb(); + intel_crtc->unpin_work = NULL; + + if (work->event) + drm_send_vblank_event(intel_crtc->base.dev, + intel_crtc->pipe, + work->event); + + drm_crtc_vblank_put(&intel_crtc->base); + + wake_up_all(&dev_priv->pending_flip_queue); + queue_work(dev_priv->wq, &work->work); + + trace_i915_flip_complete(intel_crtc->plane, + work->pending_flip_obj); +} + void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -8888,7 +8911,6 @@ static void intel_unpin_work_fn(struct work_struct *__work) static void do_intel_finish_page_flip(struct drm_device *dev, struct drm_crtc *crtc) { - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_unpin_work *work; unsigned long flags; @@ -8908,23 +8930,9 @@ static void do_intel_finish_page_flip(struct drm_device *dev, return; } - /* and that the unpin work is consistent wrt ->pending. */ - smp_rmb(); - - intel_crtc->unpin_work = NULL; - - if (work->event) - drm_send_vblank_event(dev, intel_crtc->pipe, work->event); - - drm_crtc_vblank_put(crtc); + page_flip_completed(intel_crtc); spin_unlock_irqrestore(&dev->event_lock, flags); - - wake_up_all(&dev_priv->pending_flip_queue); - - queue_work(dev_priv->wq, &work->work); - - trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj); } void intel_finish_page_flip(struct drm_device *dev, int pipe) @@ -9399,6 +9407,65 @@ static int intel_default_queue_flip(struct drm_device *dev, return -ENODEV; } +static bool __intel_pageflip_stall_check(struct drm_device *dev, + struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_unpin_work *work = intel_crtc->unpin_work; + u32 addr; + + if (atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE) + return true; + + if (!work->enable_stall_check) + return false; + + if (work->flip_ready_vblank == 0) { + if (work->ring && + !i915_seqno_passed(work->ring->get_seqno(work->ring, true), + work->flip_queued_seqno)) + return false; + + work->flip_ready_vblank = drm_vblank_count(dev, intel_crtc->pipe); + } + + if (drm_vblank_count(dev, intel_crtc->pipe) - work->flip_ready_vblank < 3) + return false; + + /* Potential stall - if we see that the flip has happened, + * assume a missed interrupt. */ + if (INTEL_INFO(dev)->gen >= 4) + addr = I915_HI_DISPBASE(I915_READ(DSPSURF(intel_crtc->plane))); + else + addr = I915_READ(DSPADDR(intel_crtc->plane)); + + /* There is a potential issue here with a false positive after a flip + * to the same address. We could address this by checking for a + * non-incrementing frame counter. + */ + return addr == work->gtt_offset; +} + +void intel_check_page_flip(struct drm_device *dev, int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + unsigned long flags; + + if (crtc == NULL) + return; + + spin_lock_irqsave(&dev->event_lock, flags); + if (intel_crtc->unpin_work && __intel_pageflip_stall_check(dev, crtc)) { + WARN_ONCE(1, "Kicking stuck page flip: queued at %d, now %d\n", + intel_crtc->unpin_work->flip_queued_vblank, drm_vblank_count(dev, pipe)); + page_flip_completed(intel_crtc); + } + spin_unlock_irqrestore(&dev->event_lock, flags); +} + static int intel_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, @@ -9449,12 +9516,20 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, /* We borrow the event spin lock for protecting unpin_work */ spin_lock_irqsave(&dev->event_lock, flags); if (intel_crtc->unpin_work) { - spin_unlock_irqrestore(&dev->event_lock, flags); - kfree(work); - drm_crtc_vblank_put(crtc); + /* Before declaring the flip queue wedged, check if + * the hardware completed the operation behind our backs. + */ + if (__intel_pageflip_stall_check(dev, crtc)) { + DRM_DEBUG_DRIVER("flip queue: previous flip completed, continuing\n"); + page_flip_completed(intel_crtc); + } else { + DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); + spin_unlock_irqrestore(&dev->event_lock, flags); - DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); - return -EBUSY; + drm_crtc_vblank_put(crtc); + kfree(work); + return -EBUSY; + } } intel_crtc->unpin_work = work; spin_unlock_irqrestore(&dev->event_lock, flags); @@ -9474,8 +9549,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, work->pending_flip_obj = obj; - work->enable_stall_check = true; - atomic_inc(&intel_crtc->unpin_work_count); intel_crtc->reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); @@ -9505,6 +9578,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, if (ret) goto cleanup_unpin; + work->flip_queued_seqno = obj->last_write_seqno; + work->ring = obj->ring; } else { ret = intel_pin_and_fence_fb_obj(dev, obj, ring); if (ret) @@ -9517,8 +9592,14 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, page_flip_flags); if (ret) goto cleanup_unpin; + + work->flip_queued_seqno = intel_ring_get_seqno(ring); + work->ring = ring; } + work->flip_queued_vblank = drm_vblank_count(dev, intel_crtc->pipe); + work->enable_stall_check = true; + intel_disable_fbc(dev); intel_mark_fb_busy(obj, NULL); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ab5962b..fd5d1ef 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -617,12 +617,16 @@ struct intel_unpin_work { struct drm_i915_gem_object *old_fb_obj; struct drm_i915_gem_object *pending_flip_obj; struct drm_pending_vblank_event *event; + struct intel_engine_cs *ring; atomic_t pending; #define INTEL_FLIP_INACTIVE 0 #define INTEL_FLIP_PENDING 1 #define INTEL_FLIP_COMPLETE 2 u32 flip_count; u32 gtt_offset; + u32 flip_queued_seqno; + int flip_queued_vblank; + int flip_ready_vblank; bool enable_stall_check; }; @@ -768,6 +772,7 @@ __intel_framebuffer_create(struct drm_device *dev, void intel_prepare_page_flip(struct drm_device *dev, int plane); void intel_finish_page_flip(struct drm_device *dev, int pipe); void intel_finish_page_flip_plane(struct drm_device *dev, int plane); +void intel_check_page_flip(struct drm_device *dev, int pipe); struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc); void assert_shared_dpll(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll, -- 1.9.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/4] drm/i915: Decouple the stuck pageflip on modeset 2014-06-18 11:23 [PATCH 1/4] drm/i915: Suppress redundant syncs with mmio page flips Chris Wilson 2014-06-18 11:23 ` [PATCH 2/4] drm/i915: Check for a stalled page flip after each vblank Chris Wilson @ 2014-06-18 11:23 ` Chris Wilson 2014-06-18 11:23 ` [PATCH 4/4] drm/i915: Boost GPU frequency if we detect outstanding pageflips Chris Wilson 2014-09-19 17:58 ` [PATCH 1/4] drm/i915: Suppress redundant syncs with mmio page flips Ville Syrjälä 3 siblings, 0 replies; 7+ messages in thread From: Chris Wilson @ 2014-06-18 11:23 UTC (permalink / raw) To: intel-gfx; +Cc: Daniel Vetter If we successfully confuse the hardware, and cause it to drop a queued pageflip, we wait for 60s and issue a warning before continuing on with the modeset. However, this leaves the pending pageflip still stuck indefinitely. Pretend to userspace that it does complete, and let us start afresh following the modeset. v2: Rebase after refactor Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> --- drivers/gpu/drm/i915/intel_display.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9a077b6..0301e8c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3368,9 +3368,19 @@ void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue)); - WARN_ON(wait_event_timeout(dev_priv->pending_flip_queue, - !intel_crtc_has_pending_flip(crtc), - 60*HZ) == 0); + if (WARN_ON(wait_event_timeout(dev_priv->pending_flip_queue, + !intel_crtc_has_pending_flip(crtc), + 60*HZ) == 0)) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + if (intel_crtc->unpin_work) { + WARN_ONCE(1, "Removing stuck page flip\n"); + page_flip_completed(intel_crtc); + } + spin_unlock_irqrestore(&dev->event_lock, flags); + } mutex_lock(&dev->struct_mutex); intel_finish_fb(crtc->primary->fb); -- 1.9.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 4/4] drm/i915: Boost GPU frequency if we detect outstanding pageflips 2014-06-18 11:23 [PATCH 1/4] drm/i915: Suppress redundant syncs with mmio page flips Chris Wilson 2014-06-18 11:23 ` [PATCH 2/4] drm/i915: Check for a stalled page flip after each vblank Chris Wilson 2014-06-18 11:23 ` [PATCH 3/4] drm/i915: Decouple the stuck pageflip on modeset Chris Wilson @ 2014-06-18 11:23 ` Chris Wilson 2014-09-19 17:58 ` [PATCH 1/4] drm/i915: Suppress redundant syncs with mmio page flips Ville Syrjälä 3 siblings, 0 replies; 7+ messages in thread From: Chris Wilson @ 2014-06-18 11:23 UTC (permalink / raw) To: intel-gfx; +Cc: Daniel Vetter If we hit a vblank and see that have a pageflip queue but not yet processed, ensure that the GPU is running at maximum in order to clear the backlog. Pageflips are only queued for the following vblank, if we miss it, there will be a visible stutter. Boosting the GPU frequency doesn't prevent us from missing the target vblank, but it should help the subsequent frames hitting theirs. v2: Reorder vblank vs flip-complete so that we only check for a missed flip after processing the completion events, and avoid spurious boosts. v3: Rename missed_vblank v4: Rebase v5: Cancel the outstanding work in runtime suspend Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> --- drivers/gpu/drm/i915/i915_drv.c | 1 + drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_display.c | 6 ++++++ drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 15 +++++++++++++++ 5 files changed, 24 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 7ae4e2a..e792aa4 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1399,6 +1399,7 @@ static int intel_runtime_suspend(struct device *device) * sure the GPU is idle and the RPS freq is set to the minimum. See * intel_mark_idle(). */ + cancel_work_sync(&dev_priv->rps.boost_work); cancel_work_sync(&dev_priv->rps.work); intel_runtime_pm_disable_interrupts(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0640071..d8a59c2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -910,6 +910,7 @@ struct intel_gen6_power_mgmt { bool enabled; struct delayed_work delayed_resume_work; + struct work_struct boost_work; /* * Protects RPS/RC6 register access and PCU communication. diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0301e8c..b9c62b7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9463,6 +9463,7 @@ void intel_check_page_flip(struct drm_device *dev, int pipe) struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); unsigned long flags; + bool missed_vblank; if (crtc == NULL) return; @@ -9473,7 +9474,12 @@ void intel_check_page_flip(struct drm_device *dev, int pipe) intel_crtc->unpin_work->flip_queued_vblank, drm_vblank_count(dev, pipe)); page_flip_completed(intel_crtc); } + missed_vblank = (intel_crtc->unpin_work != NULL && + drm_vblank_count(dev, pipe) - intel_crtc->unpin_work->flip_queued_vblank > 1); spin_unlock_irqrestore(&dev->event_lock, flags); + + if (missed_vblank) + intel_queue_rps_boost(dev); } static int intel_crtc_page_flip(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index fd5d1ef..e38645c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -978,6 +978,7 @@ void ironlake_teardown_rc6(struct drm_device *dev); void gen6_update_ring_freq(struct drm_device *dev); void gen6_rps_idle(struct drm_i915_private *dev_priv); void gen6_rps_boost(struct drm_i915_private *dev_priv); +void intel_queue_rps_boost(struct drm_device *dev); void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv); void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv); void intel_runtime_pm_get(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2043c4b..ebc11bd 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6792,6 +6792,19 @@ int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val) return DIV_ROUND_CLOSEST(4 * mul * val, dev_priv->mem_freq) + 0xbd - 6; } +static void __intel_rps_boost_work(struct work_struct *work) +{ + gen6_rps_boost(container_of(work, struct drm_i915_private, rps.boost_work)); +} + +void intel_queue_rps_boost(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + + if (INTEL_INFO(dev)->gen >= 6) + queue_work(dev_priv->wq, &dev_priv->rps.boost_work); +} + void intel_pm_setup(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -6800,6 +6813,8 @@ void intel_pm_setup(struct drm_device *dev) INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work, intel_gen6_powersave_work); + INIT_WORK(&dev_priv->rps.boost_work, + __intel_rps_boost_work); dev_priv->pm.suspended = false; dev_priv->pm.irqs_disabled = false; -- 1.9.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 1/4] drm/i915: Suppress redundant syncs with mmio page flips 2014-06-18 11:23 [PATCH 1/4] drm/i915: Suppress redundant syncs with mmio page flips Chris Wilson ` (2 preceding siblings ...) 2014-06-18 11:23 ` [PATCH 4/4] drm/i915: Boost GPU frequency if we detect outstanding pageflips Chris Wilson @ 2014-09-19 17:58 ` Ville Syrjälä 2014-09-19 20:30 ` Chris Wilson 2014-09-23 8:13 ` Daniel Vetter 3 siblings, 2 replies; 7+ messages in thread From: Ville Syrjälä @ 2014-09-19 17:58 UTC (permalink / raw) To: Chris Wilson; +Cc: intel-gfx On Wed, Jun 18, 2014 at 12:23:14PM +0100, Chris Wilson wrote: > Since mmio-flips do not occur on the suggested ring, we are introducing > an extra sync operation where none is required. Pass the current > obj->ring, which is what mmio flip will use, to pin_to_display_plane so > that we emit the appropriate synchronisation (none). > > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> I had a vague recollection that I had seen something like this and now I found it... The patch could use a rebase I think, and perhaps it could use a boolean to avoid duplicating the buffer pinning in two place? I was thinking something like: ring = whatever; bool mmio_flip = use_mmio_flip(ring); if (mmio_flip) ring = obj->ring; pin_and_fence(ring); ... if (mmio_flip) ... else ... But either way this gets Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> > --- > drivers/gpu/drm/i915/intel_display.c | 29 ++++++++++++++++++++--------- > 1 file changed, 20 insertions(+), 9 deletions(-) > > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c > index 5e8e711..55cb343 100644 > --- a/drivers/gpu/drm/i915/intel_display.c > +++ b/drivers/gpu/drm/i915/intel_display.c > @@ -9492,21 +9492,32 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, > ring = &dev_priv->ring[RCS]; > } > > - ret = intel_pin_and_fence_fb_obj(dev, obj, ring); > - if (ret) > - goto cleanup_pending; > + if (use_mmio_flip(ring, obj)) { > + ret = intel_pin_and_fence_fb_obj(dev, obj, obj->ring); > + if (ret) > + goto cleanup_pending; > > - work->gtt_offset = > - i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset; > + work->gtt_offset = > + i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset; > > - if (use_mmio_flip(ring, obj)) > ret = intel_queue_mmio_flip(dev, crtc, fb, obj, ring, > page_flip_flags); > - else > + if (ret) > + goto cleanup_unpin; > + > + } else { > + ret = intel_pin_and_fence_fb_obj(dev, obj, ring); > + if (ret) > + goto cleanup_pending; > + > + work->gtt_offset = > + i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset; > + > ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, ring, > page_flip_flags); > - if (ret) > - goto cleanup_unpin; > + if (ret) > + goto cleanup_unpin; > + } > > intel_disable_fbc(dev); > intel_mark_fb_busy(obj, NULL); > -- > 1.9.1 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/intel-gfx -- Ville Syrjälä Intel OTC ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/4] drm/i915: Suppress redundant syncs with mmio page flips 2014-09-19 17:58 ` [PATCH 1/4] drm/i915: Suppress redundant syncs with mmio page flips Ville Syrjälä @ 2014-09-19 20:30 ` Chris Wilson 2014-09-23 8:13 ` Daniel Vetter 1 sibling, 0 replies; 7+ messages in thread From: Chris Wilson @ 2014-09-19 20:30 UTC (permalink / raw) To: Ville Syrjälä; +Cc: intel-gfx On Fri, Sep 19, 2014 at 08:58:58PM +0300, Ville Syrjälä wrote: > On Wed, Jun 18, 2014 at 12:23:14PM +0100, Chris Wilson wrote: > > Since mmio-flips do not occur on the suggested ring, we are introducing > > an extra sync operation where none is required. Pass the current > > obj->ring, which is what mmio flip will use, to pin_to_display_plane so > > that we emit the appropriate synchronisation (none). > > > > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> > > I had a vague recollection that I had seen something like this and now I > found it... > > The patch could use a rebase I think, and perhaps it could use a boolean > to avoid duplicating the buffer pinning in two place? I was thinking > something like: > > ring = whatever; > bool mmio_flip = use_mmio_flip(ring); > if (mmio_flip) > ring = obj->ring; > pin_and_fence(ring); > ... > if (mmio_flip) > ... > else > ... This is the final version: if (use_mmio_flip(engine, obj, page_flip_flags)) { rq = i915_request_get(obj->last_write.request); ret = intel_pin_and_fence_fb_obj(dev, obj, rq); if (ret) goto cleanup_rq; work->gtt_offset = i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset; ret = intel_queue_mmio_flip(intel_crtc, rq); if (ret) goto cleanup_unpin; } else { struct intel_context *ctx = engine->default_context; if (obj->last_write.request) ctx = obj->last_write.request->ctx; rq = intel_engine_alloc_request(engine, ctx); if (IS_ERR(rq)) { ret = PTR_ERR(rq); goto cleanup_pending; } ret = intel_pin_and_fence_fb_obj(dev, obj, rq); if (ret) goto cleanup_rq; work->gtt_offset = i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset; ret = dev_priv->display.queue_flip(rq, intel_crtc, fb, obj, page_flip_flags); if (ret) goto cleanup_unpin; intel_mark_page_flip_active(intel_crtc); ret = i915_request_commit(rq); if (ret) goto cleanup_unpin; } which your suggestion would make do_mmio = use_mmio_flip(engine, obj, page_flip_flags); if (do_mmio) { rq = i915_request_get(obj->last_write.request); } else { struct intel_context *ctx = engine->default_context; if (obj->last_write.request) ctx = obj->last_write.request->ctx; rq = intel_engine_alloc_request(engine, ctx); if (IS_ERR(rq)) { ret = PTR_ERR(rq); goto cleanup_pending; } ] ret = intel_pin_and_fence_fb_obj(dev, obj, rq); if (ret) goto cleanup_rq; work->gtt_offset = i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset; if (do_mmio) { ret = intel_queue_mmio_flip(intel_crtc, rq); } else { ret = dev_priv->display.queue_flip(rq, intel_crtc, fb, obj, page_flip_flags); if (ret == 0) { intel_mark_page_flip_active(intel_crtc); ret = i915_request_commit(rq); } } if (ret) goto cleanup_unpin; Here, I definitely want to keep the allocated request tied to the i915_request_commit(), so I favour the duplication in this case. Unless I push the queue_flip tail down again, i.e. if (do_mmio) ret = intel_queue_mmio_flip(intel_crtc, rq); else ret = intel_queue_page_flip(rq, intel_crtc, fb, obj, page_flip_flags); if (ret) goto cleanup_unpin; or push do_mmio into page_flip_flags and have a single function here? page_flip_flags |= use_mmio_flip(engine, obj, page_flip_flags); rq = intel_page_flip_alloc_request(engine, obj, page_flip_flags); if (IS_ERR(rq)) { ret = PTR_ERR(rq); goto cleanup_pending; } ret = intel_pin_and_fence_fb_obj(dev, obj, rq); if (ret) goto cleanup_rq; work->gtt_offset = i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset; ret = intel_page_flip_queue(rq, intel_crtc, fb, obj, page_flip_flags); if (ret) goto cleanup_unpin; Maybe, just now worrying about hiding too much magic behind the scenes. -Chris -- Chris Wilson, Intel Open Source Technology Centre ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/4] drm/i915: Suppress redundant syncs with mmio page flips 2014-09-19 17:58 ` [PATCH 1/4] drm/i915: Suppress redundant syncs with mmio page flips Ville Syrjälä 2014-09-19 20:30 ` Chris Wilson @ 2014-09-23 8:13 ` Daniel Vetter 1 sibling, 0 replies; 7+ messages in thread From: Daniel Vetter @ 2014-09-23 8:13 UTC (permalink / raw) To: Ville Syrjälä; +Cc: intel-gfx On Fri, Sep 19, 2014 at 08:58:58PM +0300, Ville Syrjälä wrote: > On Wed, Jun 18, 2014 at 12:23:14PM +0100, Chris Wilson wrote: > > Since mmio-flips do not occur on the suggested ring, we are introducing > > an extra sync operation where none is required. Pass the current > > obj->ring, which is what mmio flip will use, to pin_to_display_plane so > > that we emit the appropriate synchronisation (none). > > > > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> > > I had a vague recollection that I had seen something like this and now I > found it... > > The patch could use a rebase I think, and perhaps it could use a boolean > to avoid duplicating the buffer pinning in two place? I was thinking > something like: Yeah, patch doesn't apply with the s/seqno/request/ patch, which I don't have here. And the conflict looks messy enough that I don't want to fix it up myself. Can you please rebase? Thanks, Daniel > > ring = whatever; > bool mmio_flip = use_mmio_flip(ring); > if (mmio_flip) > ring = obj->ring; > pin_and_fence(ring); > ... > if (mmio_flip) > ... > else > ... > > But either way this gets > Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> > > > --- > > drivers/gpu/drm/i915/intel_display.c | 29 ++++++++++++++++++++--------- > > 1 file changed, 20 insertions(+), 9 deletions(-) > > > > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c > > index 5e8e711..55cb343 100644 > > --- a/drivers/gpu/drm/i915/intel_display.c > > +++ b/drivers/gpu/drm/i915/intel_display.c > > @@ -9492,21 +9492,32 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, > > ring = &dev_priv->ring[RCS]; > > } > > > > - ret = intel_pin_and_fence_fb_obj(dev, obj, ring); > > - if (ret) > > - goto cleanup_pending; > > + if (use_mmio_flip(ring, obj)) { > > + ret = intel_pin_and_fence_fb_obj(dev, obj, obj->ring); > > + if (ret) > > + goto cleanup_pending; > > > > - work->gtt_offset = > > - i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset; > > + work->gtt_offset = > > + i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset; > > > > - if (use_mmio_flip(ring, obj)) > > ret = intel_queue_mmio_flip(dev, crtc, fb, obj, ring, > > page_flip_flags); > > - else > > + if (ret) > > + goto cleanup_unpin; > > + > > + } else { > > + ret = intel_pin_and_fence_fb_obj(dev, obj, ring); > > + if (ret) > > + goto cleanup_pending; > > + > > + work->gtt_offset = > > + i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset; > > + > > ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, ring, > > page_flip_flags); > > - if (ret) > > - goto cleanup_unpin; > > + if (ret) > > + goto cleanup_unpin; > > + } > > > > intel_disable_fbc(dev); > > intel_mark_fb_busy(obj, NULL); > > -- > > 1.9.1 > > > > _______________________________________________ > > Intel-gfx mailing list > > Intel-gfx@lists.freedesktop.org > > http://lists.freedesktop.org/mailman/listinfo/intel-gfx > > -- > Ville Syrjälä > Intel OTC > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/intel-gfx -- Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2014-09-23 8:13 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2014-06-18 11:23 [PATCH 1/4] drm/i915: Suppress redundant syncs with mmio page flips Chris Wilson 2014-06-18 11:23 ` [PATCH 2/4] drm/i915: Check for a stalled page flip after each vblank Chris Wilson 2014-06-18 11:23 ` [PATCH 3/4] drm/i915: Decouple the stuck pageflip on modeset Chris Wilson 2014-06-18 11:23 ` [PATCH 4/4] drm/i915: Boost GPU frequency if we detect outstanding pageflips Chris Wilson 2014-09-19 17:58 ` [PATCH 1/4] drm/i915: Suppress redundant syncs with mmio page flips Ville Syrjälä 2014-09-19 20:30 ` Chris Wilson 2014-09-23 8:13 ` Daniel Vetter
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox