* [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank
@ 2014-09-02 13:57 Chris Wilson
2014-09-02 13:57 ` [PATCH 02/10] drm/i915: Decouple the stuck pageflip on modeset Chris Wilson
` (10 more replies)
0 siblings, 11 replies; 18+ messages in thread
From: Chris Wilson @ 2014-09-02 13:57 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 | 34 +++++++---
drivers/gpu/drm/i915/i915_irq.c | 84 +++++++------------------
drivers/gpu/drm/i915/intel_display.c | 119 ++++++++++++++++++++++++++++-------
drivers/gpu/drm/i915/intel_drv.h | 3 +
4 files changed, 147 insertions(+), 93 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 97c257d06729..f7816b4329d6 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -518,6 +518,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;
@@ -537,6 +538,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);
@@ -544,23 +547,34 @@ 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->flip_queued_request) {
+ struct i915_gem_request *rq = work->flip_queued_request;
+ seq_printf(m, "Flip queued on %s at seqno %u, next seqno %u [current breadcrumb %u], completed? %d\n",
+ rq->engine->name,
+ rq->seqno, rq->i915->next_seqno,
+ rq->engine->get_seqno(rq->engine),
+ __i915_request_complete__wa(rq));
+ } 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 1cd3a8ecb2f8..60ca89986499 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2090,8 +2090,9 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
spin_unlock(&dev_priv->irq_lock);
for_each_pipe(dev_priv, 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);
@@ -2390,8 +2391,9 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
DRM_ERROR("Poison interrupt\n");
for_each_pipe(dev_priv, 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))
@@ -2440,8 +2442,9 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
intel_opregion_asle_intr(dev);
for_each_pipe(dev_priv, 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)) {
@@ -2596,8 +2599,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);
@@ -2900,52 +2904,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
*/
@@ -4091,7 +4049,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);
@@ -4102,11 +4060,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)
@@ -4274,7 +4235,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);
@@ -4285,11 +4246,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 8496a6b6f182..18c431e4f099 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3405,6 +3405,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;
@@ -9234,7 +9257,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;
@@ -9254,23 +9276,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)
@@ -9688,6 +9696,64 @@ static int intel_default_queue_flip(struct i915_gem_request *rq,
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->flip_queued_request &&
+ !i915_request_complete(work->flip_queued_request))
+ 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,
@@ -9748,12 +9814,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);
@@ -9773,8 +9847,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);
@@ -9839,6 +9911,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
}
work->flip_queued_request = rq;
+ work->flip_queued_vblank = drm_vblank_count(dev, intel_crtc->pipe);
work->enable_stall_check = true;
i915_gem_track_fb(work->old_fb_obj, obj,
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 18403c266682..1722673c534e 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -663,6 +663,8 @@ struct intel_unpin_work {
u32 flip_count;
u32 gtt_offset;
struct i915_gem_request *flip_queued_request;
+ int flip_queued_vblank;
+ int flip_ready_vblank;
bool enable_stall_check;
};
@@ -847,6 +849,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);
/* shared dpll functions */
struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
--
2.1.0
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 02/10] drm/i915: Decouple the stuck pageflip on modeset
2014-09-02 13:57 [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank Chris Wilson
@ 2014-09-02 13:57 ` Chris Wilson
2014-09-04 17:15 ` Ville Syrjälä
2014-09-02 13:57 ` [PATCH 03/10] drm/i915: Boost GPU frequency if we detect outstanding pageflips Chris Wilson
` (9 subsequent siblings)
10 siblings, 1 reply; 18+ messages in thread
From: Chris Wilson @ 2014-09-02 13:57 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 18c431e4f099..bbc3d509bcd7 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3434,9 +3434,19 @@ void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
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);
+ }
if (crtc->primary->fb) {
mutex_lock(&dev->struct_mutex);
--
2.1.0
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 03/10] drm/i915: Boost GPU frequency if we detect outstanding pageflips
2014-09-02 13:57 [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank Chris Wilson
2014-09-02 13:57 ` [PATCH 02/10] drm/i915: Decouple the stuck pageflip on modeset Chris Wilson
@ 2014-09-02 13:57 ` Chris Wilson
2014-09-02 13:57 ` [PATCH 04/10] drm/i915: Deminish contribution of wait-boosting from clients Chris Wilson
` (8 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Chris Wilson @ 2014-09-02 13:57 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/intel_display.c | 5 +++++
drivers/gpu/drm/i915/intel_drv.h | 3 +++
drivers/gpu/drm/i915/intel_pm.c | 34 ++++++++++++++++++++++++++++++++++
3 files changed, 42 insertions(+)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index bbc3d509bcd7..455cb0b0dcac 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -9761,6 +9761,10 @@ 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);
}
+ if (intel_crtc->unpin_work != NULL &&
+ intel_crtc->unpin_work->rcs_active &&
+ drm_vblank_count(dev, pipe) - intel_crtc->unpin_work->flip_queued_vblank > 1)
+ intel_queue_rps_boost_for_request(dev, intel_crtc->unpin_work->flip_queued_request);
spin_unlock_irqrestore(&dev->event_lock, flags);
}
@@ -9856,6 +9860,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
crtc->primary->fb = fb;
work->pending_flip_obj = obj;
+ work->rcs_active = RCS_ENGINE(dev_priv)->last_request != NULL;
atomic_inc(&intel_crtc->unpin_work_count);
intel_crtc->reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 1722673c534e..bbd59dd7be1b 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -666,6 +666,7 @@ struct intel_unpin_work {
int flip_queued_vblank;
int flip_ready_vblank;
bool enable_stall_check;
+ bool rcs_active;
};
struct intel_set_config {
@@ -1076,6 +1077,8 @@ 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_for_request(struct drm_device *dev,
+ struct i915_gem_request *rq);
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 2f4e38f36523..a560eb109160 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -7568,6 +7568,40 @@ int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val)
return ret;
}
+struct request_boost {
+ struct work_struct work;
+ struct i915_gem_request *rq;
+};
+
+static void __intel_rps_boost_work(struct work_struct *work)
+{
+ struct request_boost *boost = container_of(work, struct request_boost, work);
+
+ if (!i915_request_complete(boost->rq))
+ gen6_rps_boost(boost->rq->i915);
+
+ i915_request_put__unlocked(boost->rq);
+ kfree(boost);
+}
+
+void intel_queue_rps_boost_for_request(struct drm_device *dev,
+ struct i915_gem_request *rq)
+{
+ struct request_boost *boost;
+
+ if (rq == NULL || INTEL_INFO(dev)->gen < 6)
+ return;
+
+ boost = kmalloc(sizeof(*boost), GFP_ATOMIC);
+ if (boost == NULL)
+ return;
+
+ INIT_WORK(&boost->work, __intel_rps_boost_work);
+ boost->rq = i915_request_get(rq);
+
+ queue_work(to_i915(dev)->wq, &boost->work);
+}
+
void intel_pm_setup(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
--
2.1.0
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 04/10] drm/i915: Deminish contribution of wait-boosting from clients
2014-09-02 13:57 [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank Chris Wilson
2014-09-02 13:57 ` [PATCH 02/10] drm/i915: Decouple the stuck pageflip on modeset Chris Wilson
2014-09-02 13:57 ` [PATCH 03/10] drm/i915: Boost GPU frequency if we detect outstanding pageflips Chris Wilson
@ 2014-09-02 13:57 ` Chris Wilson
2014-09-02 13:57 ` [PATCH 05/10] drm/i915: Relax RPS contraints to allows setting minfreq on idle Chris Wilson
` (7 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Chris Wilson @ 2014-09-02 13:57 UTC (permalink / raw)
To: intel-gfx
Only allow each client to perform one RPS boost in each period of GPU
activity.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
drivers/gpu/drm/i915/i915_drv.h | 8 +++++---
drivers/gpu/drm/i915/i915_gem.c | 18 ++++++------------
drivers/gpu/drm/i915/i915_gem_request.c | 17 ++---------------
drivers/gpu/drm/i915/intel_drv.h | 3 ++-
drivers/gpu/drm/i915/intel_pm.c | 29 ++++++++++++++++++++++-------
5 files changed, 37 insertions(+), 38 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index da33964ce711..cefe67fb3949 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -991,6 +991,7 @@ struct intel_gen6_power_mgmt {
bool enabled;
struct delayed_work delayed_resume_work;
+ struct list_head clients;
bool is_bdw_sw_turbo; /* Switch of BDW software turbo */
struct intel_rps_bdw_turbo sw_turbo; /* Calculate RP interrupt timing */
@@ -1880,12 +1881,13 @@ struct drm_i915_file_private {
struct {
spinlock_t lock;
struct list_head request_list;
- struct delayed_work idle_work;
} mm;
struct idr context_idr;
- atomic_t rps_wait_boost;
- struct intel_engine_cs *bsd_engine;
+ struct list_head rps_boost;
+ struct intel_engine_cs *bsd_engine;
+
+ unsigned rps_boosts;
};
/*
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 4d46170f4b74..abbe2c6196cd 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4650,8 +4650,6 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file)
{
struct drm_i915_file_private *file_priv = file->driver_priv;
- cancel_delayed_work_sync(&file_priv->mm.idle_work);
-
/* Clean up our request list when the client is going away, so that
* later retire_requests won't dereference our soon-to-be-gone
* file_priv.
@@ -4667,15 +4665,12 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file)
rq->file_priv = NULL;
}
spin_unlock(&file_priv->mm.lock);
-}
-
-static void
-i915_gem_file_idle_work_handler(struct work_struct *work)
-{
- struct drm_i915_file_private *file_priv =
- container_of(work, typeof(*file_priv), mm.idle_work.work);
- atomic_set(&file_priv->rps_wait_boost, false);
+ if (!list_empty(&file_priv->rps_boost)) {
+ mutex_lock(&to_i915(dev)->rps.hw_lock);
+ list_del(&file_priv->rps_boost);
+ mutex_unlock(&to_i915(dev)->rps.hw_lock);
+ }
}
int i915_gem_open(struct drm_device *dev, struct drm_file *file)
@@ -4692,11 +4687,10 @@ int i915_gem_open(struct drm_device *dev, struct drm_file *file)
file->driver_priv = file_priv;
file_priv->dev_priv = dev->dev_private;
file_priv->file = file;
+ INIT_LIST_HEAD(&file_priv->rps_boost);
spin_lock_init(&file_priv->mm.lock);
INIT_LIST_HEAD(&file_priv->mm.request_list);
- INIT_DELAYED_WORK(&file_priv->mm.idle_work,
- i915_gem_file_idle_work_handler);
ret = i915_gem_context_open(dev, file);
if (ret)
diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c
index 49f93faa0db0..ca777f6c35d7 100644
--- a/drivers/gpu/drm/i915/i915_gem_request.c
+++ b/drivers/gpu/drm/i915/i915_gem_request.c
@@ -408,14 +408,6 @@ static bool missed_irq(struct i915_gem_request *rq)
return test_bit(rq->engine->id, &rq->i915->gpu_error.missed_irq_rings);
}
-static bool can_wait_boost(struct drm_i915_file_private *file_priv)
-{
- if (file_priv == NULL)
- return true;
-
- return !atomic_xchg(&file_priv->rps_wait_boost, true);
-}
-
bool __i915_request_complete__wa(struct i915_gem_request *rq)
{
struct drm_i915_private *dev_priv = rq->i915;
@@ -475,13 +467,8 @@ int __i915_request_wait(struct i915_gem_request *rq,
timeout_expire = timeout_ns ? jiffies + nsecs_to_jiffies((u64)*timeout_ns) : 0;
- if (INTEL_INFO(rq->i915)->gen >= 6 && rq->engine->id == RCS && can_wait_boost(file_priv)) {
- gen6_rps_boost(rq->i915);
- if (file_priv)
- mod_delayed_work(rq->i915->wq,
- &file_priv->mm.idle_work,
- msecs_to_jiffies(100));
- }
+ if (rq->engine->id == RCS && INTEL_INFO(rq->i915)->gen >= 6)
+ gen6_rps_boost(rq->i915, file_priv);
if (!irq_test_in_progress && WARN_ON(!rq->engine->irq_get(rq->engine)))
return -ENODEV;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index bbd59dd7be1b..36bf92b026a7 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1076,7 +1076,8 @@ void intel_reset_gt_powersave(struct drm_device *dev);
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 gen6_rps_boost(struct drm_i915_private *dev_priv,
+ struct drm_i915_file_private *file_priv);
void intel_queue_rps_boost_for_request(struct drm_device *dev,
struct i915_gem_request *rq);
void intel_aux_display_runtime_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 a560eb109160..c8ea3ff6e062 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3459,23 +3459,37 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
dev_priv->rps.last_adj = 0;
}
+
+ while (!list_empty(&dev_priv->rps.clients))
+ list_del_init(dev_priv->rps.clients.next);
mutex_unlock(&dev_priv->rps.hw_lock);
}
-void gen6_rps_boost(struct drm_i915_private *dev_priv)
+void gen6_rps_boost(struct drm_i915_private *dev_priv,
+ struct drm_i915_file_private *file_priv)
{
struct drm_device *dev = dev_priv->dev;
+ u32 val;
mutex_lock(&dev_priv->rps.hw_lock);
- if (dev_priv->rps.enabled) {
+ val = dev_priv->rps.max_freq_softlimit;
+ if (dev_priv->rps.enabled &&
+ dev_priv->rps.cur_freq != val &&
+ (file_priv == NULL || list_empty(&file_priv->rps_boost))) {
if (IS_VALLEYVIEW(dev))
- valleyview_set_rps(dev_priv->dev, dev_priv->rps.max_freq_softlimit);
- else if (!dev_priv->rps.is_bdw_sw_turbo
- || atomic_read(&dev_priv->rps.sw_turbo.flip_received)){
- gen6_set_rps(dev_priv->dev, dev_priv->rps.max_freq_softlimit);
+ valleyview_set_rps(dev_priv->dev, val);
+ else if (!dev_priv->rps.is_bdw_sw_turbo ||
+ atomic_read(&dev_priv->rps.sw_turbo.flip_received)) {
+ gen6_set_rps(dev_priv->dev, val);
}
dev_priv->rps.last_adj = 0;
+
+ if (file_priv != NULL) {
+ file_priv->rps_boosts++;
+ list_move(&file_priv->rps_boost,
+ &dev_priv->rps.clients);
+ }
}
mutex_unlock(&dev_priv->rps.hw_lock);
}
@@ -7578,7 +7592,7 @@ static void __intel_rps_boost_work(struct work_struct *work)
struct request_boost *boost = container_of(work, struct request_boost, work);
if (!i915_request_complete(boost->rq))
- gen6_rps_boost(boost->rq->i915);
+ gen6_rps_boost(boost->rq->i915, NULL);
i915_request_put__unlocked(boost->rq);
kfree(boost);
@@ -7610,6 +7624,7 @@ void intel_pm_setup(struct drm_device *dev)
INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work,
intel_gen6_powersave_work);
+ INIT_LIST_HEAD(&dev_priv->rps.clients);
dev_priv->pm.suspended = false;
dev_priv->pm._irqs_disabled = false;
--
2.1.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 05/10] drm/i915: Relax RPS contraints to allows setting minfreq on idle
2014-09-02 13:57 [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank Chris Wilson
` (2 preceding siblings ...)
2014-09-02 13:57 ` [PATCH 04/10] drm/i915: Deminish contribution of wait-boosting from clients Chris Wilson
@ 2014-09-02 13:57 ` Chris Wilson
2014-09-02 13:57 ` [PATCH 06/10] drm/i915: Rearrange RPS frequency calculation Chris Wilson
` (6 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Chris Wilson @ 2014-09-02 13:57 UTC (permalink / raw)
To: intel-gfx
When we idle, we set the GPU frequency to minimum. This should be a
safety blanket as the pcu on the GPU should be power gating itself
anyway. However, in order for us to do set the absolute minimum
frequency, we need to relax a few of our assertions that we do not
exceed the user limits.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
drivers/gpu/drm/i915/intel_pm.c | 39 ++++++++++++++++++++-------------------
1 file changed, 20 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index c8ea3ff6e062..50af00c5655d 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3265,9 +3265,9 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
break;
}
/* Max/min bins are special */
- if (val == dev_priv->rps.min_freq_softlimit)
+ if (val <= dev_priv->rps.min_freq_softlimit)
new_power = LOW_POWER;
- if (val == dev_priv->rps.max_freq_softlimit)
+ if (val >= dev_priv->rps.max_freq_softlimit)
new_power = HIGH_POWER;
if (new_power == dev_priv->rps.power)
return;
@@ -3365,8 +3365,8 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
struct drm_i915_private *dev_priv = dev->dev_private;
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
- WARN_ON(val > dev_priv->rps.max_freq_softlimit);
- WARN_ON(val < dev_priv->rps.min_freq_softlimit);
+ WARN_ON(val > dev_priv->rps.max_freq);
+ WARN_ON(val < dev_priv->rps.min_freq);
/* min/max delay may still have been modified so be sure to
* write the limits value.
@@ -3408,10 +3408,11 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
+ u32 val = dev_priv->rps.min_freq;
/* Latest VLV doesn't need to force the gfx clock */
if (dev->pdev->revision >= 0xd) {
- valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
+ valleyview_set_rps(dev_priv->dev, val);
return;
}
@@ -3419,7 +3420,7 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
* When we are idle. Drop to min voltage state.
*/
- if (dev_priv->rps.cur_freq <= dev_priv->rps.min_freq_softlimit)
+ if (dev_priv->rps.cur_freq <= val)
return;
/* Mask turbo interrupt so that they will not come in between */
@@ -3427,10 +3428,9 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
vlv_force_gfx_clock(dev_priv, true);
- dev_priv->rps.cur_freq = dev_priv->rps.min_freq_softlimit;
+ dev_priv->rps.cur_freq = val;
- vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ,
- dev_priv->rps.min_freq_softlimit);
+ vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
if (wait_for(((vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS))
& GENFREQSTATUS) == 0, 5))
@@ -3438,8 +3438,7 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
vlv_force_gfx_clock(dev_priv, false);
- I915_WRITE(GEN6_PMINTRMSK,
- gen6_rps_pm_mask(dev_priv, dev_priv->rps.cur_freq));
+ I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
}
void gen6_rps_idle(struct drm_i915_private *dev_priv)
@@ -3448,13 +3447,15 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
mutex_lock(&dev_priv->rps.hw_lock);
if (dev_priv->rps.enabled) {
+ u32 val = dev_priv->rps.min_freq;
+
if (IS_CHERRYVIEW(dev))
- valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
+ valleyview_set_rps(dev_priv->dev, val);
else if (IS_VALLEYVIEW(dev))
vlv_set_rps_idle(dev_priv);
- else if (!dev_priv->rps.is_bdw_sw_turbo
- || atomic_read(&dev_priv->rps.sw_turbo.flip_received)){
- gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
+ else if (!dev_priv->rps.is_bdw_sw_turbo ||
+ atomic_read(&dev_priv->rps.sw_turbo.flip_received)) {
+ gen6_set_rps(dev_priv->dev, val);
}
dev_priv->rps.last_adj = 0;
@@ -3499,8 +3500,8 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
struct drm_i915_private *dev_priv = dev->dev_private;
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
- WARN_ON(val > dev_priv->rps.max_freq_softlimit);
- WARN_ON(val < dev_priv->rps.min_freq_softlimit);
+ WARN_ON(val > dev_priv->rps.max_freq);
+ WARN_ON(val < dev_priv->rps.min_freq);
DRM_DEBUG_DRIVER("GPU freq request from %d MHz (%u) to %d MHz (%u)\n",
vlv_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
@@ -4013,7 +4014,7 @@ static void gen6_enable_rps(struct drm_device *dev)
}
dev_priv->rps.power = HIGH_POWER; /* force a reset */
- gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
+ gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq);
gen6_enable_rps_interrupts(dev);
@@ -4069,7 +4070,7 @@ static void __gen6_update_ring_freq(struct drm_device *dev)
* to use for memory access. We do this by specifying the IA frequency
* the PCU should use as a reference to determine the ring frequency.
*/
- for (gpu_freq = dev_priv->rps.max_freq_softlimit; gpu_freq >= dev_priv->rps.min_freq_softlimit;
+ for (gpu_freq = dev_priv->rps.max_freq; gpu_freq >= dev_priv->rps.min_freq;
gpu_freq--) {
int diff = dev_priv->rps.max_freq_softlimit - gpu_freq;
unsigned int ia_freq = 0, ring_freq = 0;
--
2.1.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 06/10] drm/i915: Rearrange RPS frequency calculation
2014-09-02 13:57 [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank Chris Wilson
` (3 preceding siblings ...)
2014-09-02 13:57 ` [PATCH 05/10] drm/i915: Relax RPS contraints to allows setting minfreq on idle Chris Wilson
@ 2014-09-02 13:57 ` Chris Wilson
2014-09-02 13:57 ` [PATCH 07/10] drm/i915: Improved w/a for rps on Baytrail Chris Wilson
` (5 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Chris Wilson @ 2014-09-02 13:57 UTC (permalink / raw)
To: intel-gfx
The goal is to refactor the Cherryview special casing to only be in a
single location. To do so we need to compute the desired adjustment and
then tweak it for Cherryview. This has the minor side-effect of making
sure we set adj to 0 if we directly update the target frequency.
Ensuring that the RPS constants are correct for Cherryview is outside
the scope of this function
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
drivers/gpu/drm/i915/i915_irq.c | 27 ++++++++++++++-------------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 60ca89986499..586625b78cbb 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1420,21 +1420,20 @@ static void gen6_pm_rps_work(struct work_struct *work)
mutex_lock(&dev_priv->rps.hw_lock);
adj = dev_priv->rps.last_adj;
+ new_delay = dev_priv->rps.cur_freq;
if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
if (adj > 0)
adj *= 2;
- else {
- /* CHV needs even encode values */
- adj = IS_CHERRYVIEW(dev_priv->dev) ? 2 : 1;
- }
- new_delay = dev_priv->rps.cur_freq + adj;
-
+ else
+ adj = 1;
/*
* For better performance, jump directly
* to RPe if we're below it.
*/
- if (new_delay < dev_priv->rps.efficient_freq)
+ if (new_delay < dev_priv->rps.efficient_freq - adj) {
new_delay = dev_priv->rps.efficient_freq;
+ adj = 0;
+ }
} else if (pm_iir & GEN6_PM_RP_DOWN_TIMEOUT) {
if (dev_priv->rps.cur_freq > dev_priv->rps.efficient_freq)
new_delay = dev_priv->rps.efficient_freq;
@@ -1446,15 +1445,17 @@ static void gen6_pm_rps_work(struct work_struct *work)
} else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) {
if (adj < 0)
adj *= 2;
- else {
- /* CHV needs even encode values */
- adj = IS_CHERRYVIEW(dev_priv->dev) ? -2 : -1;
- }
- new_delay = dev_priv->rps.cur_freq + adj;
+ else
+ adj = -1;
} else { /* unknown event */
- new_delay = dev_priv->rps.cur_freq;
+ adj = 0;
}
+ /* CHV needs even encode values */
+ if (IS_CHERRYVIEW(dev_priv->dev))
+ adj <<= 1;
+ new_delay += adj;
+
/* sysfs frequency interfaces may have snuck in while servicing the
* interrupt
*/
--
2.1.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 07/10] drm/i915: Improved w/a for rps on Baytrail
2014-09-02 13:57 [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank Chris Wilson
` (4 preceding siblings ...)
2014-09-02 13:57 ` [PATCH 06/10] drm/i915: Rearrange RPS frequency calculation Chris Wilson
@ 2014-09-02 13:57 ` Chris Wilson
2014-09-02 13:57 ` [PATCH 08/10] drm/i915: Use down ei for manual Baytrail RPS calculations Chris Wilson
` (4 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Chris Wilson @ 2014-09-02 13:57 UTC (permalink / raw)
To: intel-gfx; +Cc: Daniel Vetter, Rodrigo Vivi
Rewrite commit 31685c258e0b0ad6aa486c5ec001382cf8a64212
Author: Deepak S <deepak.s@linux.intel.com>
Date: Thu Jul 3 17:33:01 2014 -0400
drm/i915/vlv: WA for Turbo and RC6 to work together.
Other than code clarity, the major improvement is to disable the extra
interrupts generated when idle. However, the reclocking remains rather
slow under the new manual regime, in particular it fails to downclock as
quickly as desired.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Deepak S <deepak.s@linux.intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
---
drivers/gpu/drm/i915/i915_irq.c | 154 ++++++++++++-----------------------
drivers/gpu/drm/i915/i915_reg.h | 4 +-
drivers/gpu/drm/i915/intel_display.c | 2 +
drivers/gpu/drm/i915/intel_drv.h | 2 +
drivers/gpu/drm/i915/intel_pm.c | 13 +++
5 files changed, 69 insertions(+), 106 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 586625b78cbb..abf9239b58bb 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1268,129 +1268,72 @@ static void notify_ring(struct drm_device *dev,
i915_queue_hangcheck(dev);
}
-static u32 vlv_c0_residency(struct drm_i915_private *dev_priv,
- struct intel_rps_ei *rps_ei)
+static void vlv_c0_read(struct drm_i915_private *dev_priv,
+ struct intel_rps_ei *ei)
{
- u32 cz_ts, cz_freq_khz;
- u32 render_count, media_count;
- u32 elapsed_render, elapsed_media, elapsed_time;
- u32 residency = 0;
-
- cz_ts = vlv_punit_read(dev_priv, PUNIT_REG_CZ_TIMESTAMP);
- cz_freq_khz = DIV_ROUND_CLOSEST(dev_priv->mem_freq * 1000, 4);
-
- render_count = I915_READ(VLV_RENDER_C0_COUNT_REG);
- media_count = I915_READ(VLV_MEDIA_C0_COUNT_REG);
-
- if (rps_ei->cz_clock == 0) {
- rps_ei->cz_clock = cz_ts;
- rps_ei->render_c0 = render_count;
- rps_ei->media_c0 = media_count;
-
- return dev_priv->rps.cur_freq;
- }
-
- elapsed_time = cz_ts - rps_ei->cz_clock;
- rps_ei->cz_clock = cz_ts;
-
- elapsed_render = render_count - rps_ei->render_c0;
- rps_ei->render_c0 = render_count;
-
- elapsed_media = media_count - rps_ei->media_c0;
- rps_ei->media_c0 = media_count;
-
- /* Convert all the counters into common unit of milli sec */
- elapsed_time /= VLV_CZ_CLOCK_TO_MILLI_SEC;
- elapsed_render /= cz_freq_khz;
- elapsed_media /= cz_freq_khz;
-
- /*
- * Calculate overall C0 residency percentage
- * only if elapsed time is non zero
- */
- if (elapsed_time) {
- residency =
- ((max(elapsed_render, elapsed_media) * 100)
- / elapsed_time);
- }
-
- return residency;
+ ei->cz_clock = vlv_punit_read(dev_priv, PUNIT_REG_CZ_TIMESTAMP);
+ ei->render_c0 = I915_READ(VLV_RENDER_C0_COUNT);
+ ei->media_c0 = I915_READ(VLV_MEDIA_C0_COUNT);
}
-/**
- * vlv_calc_delay_from_C0_counters - Increase/Decrease freq based on GPU
- * busy-ness calculated from C0 counters of render & media power wells
- * @dev_priv: DRM device private
- *
- */
-static int vlv_calc_delay_from_C0_counters(struct drm_i915_private *dev_priv)
+static bool vlv_c0_above(struct drm_i915_private *dev_priv,
+ const struct intel_rps_ei *old,
+ const struct intel_rps_ei *now,
+ int threshold)
{
- u32 residency_C0_up = 0, residency_C0_down = 0;
- int new_delay, adj;
+ u64 time = now->cz_clock - old->cz_clock;
+ u64 c0 = max(now->render_c0 - old->render_c0,
+ now->media_c0 - old->media_c0);
- dev_priv->rps.ei_interrupt_count++;
+ c0 *= 100 * VLV_CZ_CLOCK_TO_MILLI_SEC * 4 / 1000;
+ time *= threshold * dev_priv->mem_freq;
+ return c0 >= time;
+}
- WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
+void gen6_rps_reset_ei(struct drm_i915_private *dev_priv)
+{
+ vlv_c0_read(dev_priv, &dev_priv->rps.down_ei);
+ dev_priv->rps.up_ei = dev_priv->rps.down_ei;
+ dev_priv->rps.ei_interrupt_count = 0;
+}
+static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir)
+{
+ struct intel_rps_ei now;
+ u32 events = 0;
- if (dev_priv->rps.up_ei.cz_clock == 0) {
- vlv_c0_residency(dev_priv, &dev_priv->rps.up_ei);
- vlv_c0_residency(dev_priv, &dev_priv->rps.down_ei);
- return dev_priv->rps.cur_freq;
- }
+ if ((pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) == 0)
+ return 0;
+ vlv_c0_read(dev_priv, &now);
/*
* To down throttle, C0 residency should be less than down threshold
* for continous EI intervals. So calculate down EI counters
* once in VLV_INT_COUNT_FOR_DOWN_EI
*/
- if (dev_priv->rps.ei_interrupt_count == VLV_INT_COUNT_FOR_DOWN_EI) {
-
+ if (++dev_priv->rps.ei_interrupt_count >= VLV_INT_COUNT_FOR_DOWN_EI) {
+ pm_iir |= GEN6_PM_RP_DOWN_EI_EXPIRED;
dev_priv->rps.ei_interrupt_count = 0;
-
- residency_C0_down = vlv_c0_residency(dev_priv,
- &dev_priv->rps.down_ei);
- } else {
- residency_C0_up = vlv_c0_residency(dev_priv,
- &dev_priv->rps.up_ei);
}
- new_delay = dev_priv->rps.cur_freq;
-
- adj = dev_priv->rps.last_adj;
- /* C0 residency is greater than UP threshold. Increase Frequency */
- if (residency_C0_up >= VLV_RP_UP_EI_THRESHOLD) {
- if (adj > 0)
- adj *= 2;
- else
- adj = 1;
-
- if (dev_priv->rps.cur_freq < dev_priv->rps.max_freq_softlimit)
- new_delay = dev_priv->rps.cur_freq + adj;
-
- /*
- * For better performance, jump directly
- * to RPe if we're below it.
- */
- if (new_delay < dev_priv->rps.efficient_freq)
- new_delay = dev_priv->rps.efficient_freq;
+ if (pm_iir & GEN6_PM_RP_DOWN_EI_EXPIRED) {
+ if (!vlv_c0_above(dev_priv,
+ &dev_priv->rps.down_ei, &now,
+ VLV_RP_DOWN_EI_THRESHOLD))
+ events |= GEN6_PM_RP_DOWN_THRESHOLD;
+ dev_priv->rps.down_ei = now;
+ }
- } else if (!dev_priv->rps.ei_interrupt_count &&
- (residency_C0_down < VLV_RP_DOWN_EI_THRESHOLD)) {
- if (adj < 0)
- adj *= 2;
- else
- adj = -1;
- /*
- * This means, C0 residency is less than down threshold over
- * a period of VLV_INT_COUNT_FOR_DOWN_EI. So, reduce the freq
- */
- if (dev_priv->rps.cur_freq > dev_priv->rps.min_freq_softlimit)
- new_delay = dev_priv->rps.cur_freq + adj;
+ if (pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) {
+ if (vlv_c0_above(dev_priv,
+ &dev_priv->rps.up_ei, &now,
+ VLV_RP_UP_EI_THRESHOLD))
+ events |= GEN6_PM_RP_UP_THRESHOLD;
+ dev_priv->rps.up_ei = now;
}
- return new_delay;
+ return events;
}
static void gen6_pm_rps_work(struct work_struct *work)
@@ -1419,6 +1362,8 @@ static void gen6_pm_rps_work(struct work_struct *work)
mutex_lock(&dev_priv->rps.hw_lock);
+ pm_iir |= vlv_wa_c0_ei(dev_priv, pm_iir);
+
adj = dev_priv->rps.last_adj;
new_delay = dev_priv->rps.cur_freq;
if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
@@ -1440,8 +1385,6 @@ static void gen6_pm_rps_work(struct work_struct *work)
else
new_delay = dev_priv->rps.min_freq_softlimit;
adj = 0;
- } else if (pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) {
- new_delay = vlv_calc_delay_from_C0_counters(dev_priv);
} else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) {
if (adj < 0)
adj *= 2;
@@ -1462,6 +1405,9 @@ static void gen6_pm_rps_work(struct work_struct *work)
new_delay = clamp_t(int, new_delay,
dev_priv->rps.min_freq_softlimit,
dev_priv->rps.max_freq_softlimit);
+ /* CHV needs even encode values */
+ if (IS_CHERRYVIEW(dev_priv->dev))
+ new_delay = new_delay & ~1;
dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_freq;
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 59f0852d89d6..d0f9816ec780 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -5686,8 +5686,8 @@ enum punit_power_well {
#define GEN6_GT_GFX_RC6p 0x13810C
#define GEN6_GT_GFX_RC6pp 0x138110
-#define VLV_RENDER_C0_COUNT_REG 0x138118
-#define VLV_MEDIA_C0_COUNT_REG 0x13811C
+#define VLV_RENDER_C0_COUNT 0x138118
+#define VLV_MEDIA_C0_COUNT 0x13811C
#define GEN6_PCODE_MAILBOX 0x138124
#define GEN6_PCODE_READY (1<<31)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 455cb0b0dcac..1b2d640e10ac 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -9011,6 +9011,8 @@ void intel_mark_busy(struct drm_device *dev)
intel_runtime_pm_get(dev_priv);
i915_update_gfx_val(dev_priv);
+ if (INTEL_INFO(dev)->gen >= 6)
+ gen6_rps_busy(dev_priv);
dev_priv->mm.busy = true;
}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 36bf92b026a7..c5d387852394 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1075,6 +1075,8 @@ void intel_suspend_gt_powersave(struct drm_device *dev);
void intel_reset_gt_powersave(struct drm_device *dev);
void ironlake_teardown_rc6(struct drm_device *dev);
void gen6_update_ring_freq(struct drm_device *dev);
+void gen6_rps_busy(struct drm_i915_private *dev_priv);
+void gen6_rps_reset_ei(struct drm_i915_private *dev_priv);
void gen6_rps_idle(struct drm_i915_private *dev_priv);
void gen6_rps_boost(struct drm_i915_private *dev_priv,
struct drm_i915_file_private *file_priv);
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 50af00c5655d..a3348da6e8a4 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3441,6 +3441,18 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
}
+void gen6_rps_busy(struct drm_i915_private *dev_priv)
+{
+ mutex_lock(&dev_priv->rps.hw_lock);
+ if (dev_priv->rps.enabled) {
+ if (dev_priv->pm_rps_events & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED))
+ gen6_rps_reset_ei(dev_priv);
+ I915_WRITE(GEN6_PMINTRMSK,
+ gen6_rps_pm_mask(dev_priv, dev_priv->rps.cur_freq));
+ }
+ mutex_unlock(&dev_priv->rps.hw_lock);
+}
+
void gen6_rps_idle(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
@@ -3459,6 +3471,7 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
}
dev_priv->rps.last_adj = 0;
+ I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
}
while (!list_empty(&dev_priv->rps.clients))
--
2.1.0
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 08/10] drm/i915: Use down ei for manual Baytrail RPS calculations
2014-09-02 13:57 [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank Chris Wilson
` (5 preceding siblings ...)
2014-09-02 13:57 ` [PATCH 07/10] drm/i915: Improved w/a for rps on Baytrail Chris Wilson
@ 2014-09-02 13:57 ` Chris Wilson
2014-09-02 13:57 ` [PATCH 09/10] drm/i915: Agressive downclocking on Baytrail Chris Wilson
` (3 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Chris Wilson @ 2014-09-02 13:57 UTC (permalink / raw)
To: intel-gfx
Use both up/down manual ei calcuations for symmetry and greater
flexibility for reclocking, instead of faking the down interrupt based
on a fixed integer number of up interrupts.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
drivers/gpu/drm/i915/i915_drv.h | 2 --
drivers/gpu/drm/i915/i915_irq.c | 17 +++--------------
drivers/gpu/drm/i915/i915_reg.h | 1 -
drivers/gpu/drm/i915/intel_pm.c | 5 ++---
4 files changed, 5 insertions(+), 20 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index cefe67fb3949..54d4c8bb7465 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -984,8 +984,6 @@ struct intel_gen6_power_mgmt {
u8 rp0_freq; /* Non-overclocked max frequency. */
u32 cz_freq;
- u32 ei_interrupt_count;
-
int last_adj;
enum { LOW_POWER, BETWEEN, HIGH_POWER } power;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index abf9239b58bb..ea127f5dd57d 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1294,7 +1294,6 @@ void gen6_rps_reset_ei(struct drm_i915_private *dev_priv)
{
vlv_c0_read(dev_priv, &dev_priv->rps.down_ei);
dev_priv->rps.up_ei = dev_priv->rps.down_ei;
- dev_priv->rps.ei_interrupt_count = 0;
}
static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir)
@@ -1302,21 +1301,11 @@ static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir)
struct intel_rps_ei now;
u32 events = 0;
- if ((pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) == 0)
+ if ((pm_iir & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED)) == 0)
return 0;
vlv_c0_read(dev_priv, &now);
- /*
- * To down throttle, C0 residency should be less than down threshold
- * for continous EI intervals. So calculate down EI counters
- * once in VLV_INT_COUNT_FOR_DOWN_EI
- */
- if (++dev_priv->rps.ei_interrupt_count >= VLV_INT_COUNT_FOR_DOWN_EI) {
- pm_iir |= GEN6_PM_RP_DOWN_EI_EXPIRED;
- dev_priv->rps.ei_interrupt_count = 0;
- }
-
if (pm_iir & GEN6_PM_RP_DOWN_EI_EXPIRED) {
if (!vlv_c0_above(dev_priv,
&dev_priv->rps.down_ei, &now,
@@ -4607,8 +4596,8 @@ void intel_irq_init(struct drm_device *dev)
/* Let's track the enabled rps events */
if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev))
- /* WaGsvRC0ResidencyMethod:vlv */
- dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED;
+ /* WaGsvRC0ResidenncyMethod:VLV */
+ dev_priv->pm_rps_events = GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED;
else
dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index d0f9816ec780..89c532e71af5 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -583,7 +583,6 @@ enum punit_power_well {
#define VLV_CZ_CLOCK_TO_MILLI_SEC 100000
#define VLV_RP_UP_EI_THRESHOLD 90
#define VLV_RP_DOWN_EI_THRESHOLD 70
-#define VLV_INT_COUNT_FOR_DOWN_EI 5
/* vlv2 north clock has */
#define CCK_FUSE_REG 0x8
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index a3348da6e8a4..53b488d75882 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3338,11 +3338,10 @@ static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val)
u32 mask = 0;
if (val > dev_priv->rps.min_freq_softlimit)
- mask |= GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT;
+ mask |= GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT;
if (val < dev_priv->rps.max_freq_softlimit)
- mask |= GEN6_PM_RP_UP_THRESHOLD;
+ mask |= GEN6_PM_RP_UP_EI_EXPIRED | GEN6_PM_RP_UP_THRESHOLD;
- mask |= dev_priv->pm_rps_events & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED);
mask &= dev_priv->pm_rps_events;
/* IVB and SNB hard hangs on looping batchbuffer
--
2.1.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 09/10] drm/i915: Agressive downclocking on Baytrail
2014-09-02 13:57 [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank Chris Wilson
` (6 preceding siblings ...)
2014-09-02 13:57 ` [PATCH 08/10] drm/i915: Use down ei for manual Baytrail RPS calculations Chris Wilson
@ 2014-09-02 13:57 ` Chris Wilson
2014-09-02 13:57 ` [PATCH 10/10] drm/i915: Move pm_rps_events to i915->rps Chris Wilson
` (2 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Chris Wilson @ 2014-09-02 13:57 UTC (permalink / raw)
To: intel-gfx; +Cc: Daniel Vetter, Rodrigo Vivi
Reuse the same reclocking strategy for Baytail as on its bigger brethren,
Sandybridge and Ivybridge. In particular, this makes the device quicker
to reclock (both up and down) though the tendency now is to downclock
more aggressively to compensate for the RPS boosts.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Deepak S <deepak.s@linux.intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
---
drivers/gpu/drm/i915/i915_drv.h | 3 +++
drivers/gpu/drm/i915/i915_irq.c | 4 ++--
drivers/gpu/drm/i915/i915_reg.h | 2 --
drivers/gpu/drm/i915/intel_pm.c | 11 ++++++++++-
4 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 54d4c8bb7465..e8e532dcf136 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -984,6 +984,9 @@ struct intel_gen6_power_mgmt {
u8 rp0_freq; /* Non-overclocked max frequency. */
u32 cz_freq;
+ u8 up_threshold; /* Current %busy required to uplock */
+ u8 down_threshold; /* Current %busy required to downclock */
+
int last_adj;
enum { LOW_POWER, BETWEEN, HIGH_POWER } power;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index ea127f5dd57d..9c72d26f1066 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1309,7 +1309,7 @@ static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir)
if (pm_iir & GEN6_PM_RP_DOWN_EI_EXPIRED) {
if (!vlv_c0_above(dev_priv,
&dev_priv->rps.down_ei, &now,
- VLV_RP_DOWN_EI_THRESHOLD))
+ dev_priv->rps.down_threshold))
events |= GEN6_PM_RP_DOWN_THRESHOLD;
dev_priv->rps.down_ei = now;
}
@@ -1317,7 +1317,7 @@ static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir)
if (pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) {
if (vlv_c0_above(dev_priv,
&dev_priv->rps.up_ei, &now,
- VLV_RP_UP_EI_THRESHOLD))
+ dev_priv->rps.up_threshold))
events |= GEN6_PM_RP_UP_THRESHOLD;
dev_priv->rps.up_ei = now;
}
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 89c532e71af5..7b3ef6459ed3 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -581,8 +581,6 @@ enum punit_power_well {
#define FB_FMAX_VMIN_FREQ_LO_MASK 0xf8000000
#define VLV_CZ_CLOCK_TO_MILLI_SEC 100000
-#define VLV_RP_UP_EI_THRESHOLD 90
-#define VLV_RP_DOWN_EI_THRESHOLD 70
/* vlv2 north clock has */
#define CCK_FUSE_REG 0x8
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 53b488d75882..70f6d9c392c4 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3276,10 +3276,12 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
switch (new_power) {
case LOW_POWER:
/* Upclock if more than 95% busy over 16ms */
+ dev_priv->rps.up_threshold = 95;
I915_WRITE(GEN6_RP_UP_EI, 12500);
I915_WRITE(GEN6_RP_UP_THRESHOLD, 11800);
/* Downclock if less than 85% busy over 32ms */
+ dev_priv->rps.down_threshold = 85;
I915_WRITE(GEN6_RP_DOWN_EI, 25000);
I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 21250);
@@ -3294,10 +3296,12 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
case BETWEEN:
/* Upclock if more than 90% busy over 13ms */
+ dev_priv->rps.up_threshold = 90;
I915_WRITE(GEN6_RP_UP_EI, 10250);
I915_WRITE(GEN6_RP_UP_THRESHOLD, 9225);
/* Downclock if less than 75% busy over 32ms */
+ dev_priv->rps.down_threshold = 75;
I915_WRITE(GEN6_RP_DOWN_EI, 25000);
I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 18750);
@@ -3312,10 +3316,12 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
case HIGH_POWER:
/* Upclock if more than 85% busy over 10ms */
+ dev_priv->rps.up_threshold = 85;
I915_WRITE(GEN6_RP_UP_EI, 8000);
I915_WRITE(GEN6_RP_UP_THRESHOLD, 6800);
/* Downclock if less than 60% busy over 32ms */
+ dev_priv->rps.down_threshold = 60;
I915_WRITE(GEN6_RP_DOWN_EI, 25000);
I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 15000);
@@ -3435,6 +3441,7 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
& GENFREQSTATUS) == 0, 5))
DRM_ERROR("timed out waiting for Punit\n");
+ gen6_set_rps_thresholds(dev_priv, val);
vlv_force_gfx_clock(dev_priv, false);
I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
@@ -3524,8 +3531,10 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
"Odd GPU freq value\n"))
val &= ~1;
- if (val != dev_priv->rps.cur_freq)
+ if (val != dev_priv->rps.cur_freq) {
vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
+ gen6_set_rps_thresholds(dev_priv, val);
+ }
I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
--
2.1.0
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 10/10] drm/i915: Move pm_rps_events to i915->rps
2014-09-02 13:57 [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank Chris Wilson
` (7 preceding siblings ...)
2014-09-02 13:57 ` [PATCH 09/10] drm/i915: Agressive downclocking on Baytrail Chris Wilson
@ 2014-09-02 13:57 ` Chris Wilson
2014-09-02 14:31 ` [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank Ville Syrjälä
2014-09-02 14:52 ` Daniel Vetter
10 siblings, 0 replies; 18+ messages in thread
From: Chris Wilson @ 2014-09-02 13:57 UTC (permalink / raw)
To: intel-gfx
Since this mask is only used in conjunction with RPS, move it alongside
its brethen in the i915->rps struct.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
drivers/gpu/drm/i915/i915_drv.h | 2 +-
drivers/gpu/drm/i915/i915_irq.c | 35 +++++++++++++++++------------------
drivers/gpu/drm/i915/intel_pm.c | 22 +++++++++++-----------
3 files changed, 29 insertions(+), 30 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index e8e532dcf136..3461b9838013 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -963,6 +963,7 @@ struct intel_gen6_power_mgmt {
/* work and pm_iir are protected by dev_priv->irq_lock */
struct work_struct work;
u32 pm_iir;
+ u32 pm_events;
/* Frequencies are stored in potentially platform dependent multiples.
* In other words, *_freq needs to be multiplied by X to be interesting.
@@ -1486,7 +1487,6 @@ struct drm_i915_private {
};
u32 gt_irq_mask;
u32 pm_irq_mask;
- u32 pm_rps_events;
u32 pipestat_irq_mask[I915_MAX_PIPES];
struct delayed_work hotplug_work;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 9c72d26f1066..973dd03a21e5 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1336,17 +1336,16 @@ static void gen6_pm_rps_work(struct work_struct *work)
pm_iir = dev_priv->rps.pm_iir;
dev_priv->rps.pm_iir = 0;
if (INTEL_INFO(dev_priv->dev)->gen >= 8)
- gen8_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
- else {
+ gen8_enable_pm_irq(dev_priv, dev_priv->rps.pm_events);
+ else
/* Make sure not to corrupt PMIMR state used by ringbuffer */
- gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
- }
+ gen6_enable_pm_irq(dev_priv, dev_priv->rps.pm_events);
spin_unlock_irq(&dev_priv->irq_lock);
/* Make sure we didn't queue anything we're not going to process. */
- WARN_ON(pm_iir & ~dev_priv->pm_rps_events);
+ WARN_ON(pm_iir & ~dev_priv->rps.pm_events);
- if ((pm_iir & dev_priv->pm_rps_events) == 0)
+ if ((pm_iir & dev_priv->rps.pm_events) == 0)
return;
mutex_lock(&dev_priv->rps.hw_lock);
@@ -1549,12 +1548,12 @@ static void snb_gt_irq_handler(struct drm_device *dev,
static void gen8_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
{
- if ((pm_iir & dev_priv->pm_rps_events) == 0)
+ if ((pm_iir & dev_priv->rps.pm_events) == 0)
return;
spin_lock(&dev_priv->irq_lock);
- dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events;
- gen8_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
+ dev_priv->rps.pm_iir |= pm_iir & dev_priv->rps.pm_events;
+ gen8_disable_pm_irq(dev_priv, pm_iir & dev_priv->rps.pm_events);
spin_unlock(&dev_priv->irq_lock);
queue_work(dev_priv->wq, &dev_priv->rps.work);
@@ -1617,9 +1616,9 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
if (master_ctl & GEN8_GT_PM_IRQ) {
tmp = I915_READ(GEN8_GT_IIR(2));
- if (tmp & dev_priv->pm_rps_events) {
+ if (tmp & dev_priv->rps.pm_events) {
I915_WRITE(GEN8_GT_IIR(2),
- tmp & dev_priv->pm_rps_events);
+ tmp & dev_priv->rps.pm_events);
ret = IRQ_HANDLED;
gen8_rps_irq_handler(dev_priv, tmp);
} else
@@ -1944,10 +1943,10 @@ void gen8_flip_interrupt(struct drm_device *dev)
* the work queue. */
static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
{
- if (pm_iir & dev_priv->pm_rps_events) {
+ if (pm_iir & dev_priv->rps.pm_events) {
spin_lock(&dev_priv->irq_lock);
- dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events;
- gen6_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
+ dev_priv->rps.pm_iir |= pm_iir & dev_priv->rps.pm_events;
+ gen6_disable_pm_irq(dev_priv, pm_iir & dev_priv->rps.pm_events);
spin_unlock(&dev_priv->irq_lock);
queue_work(dev_priv->wq, &dev_priv->rps.work);
@@ -3537,7 +3536,7 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
GEN5_IRQ_INIT(GT, dev_priv->gt_irq_mask, gt_irqs);
if (INTEL_INFO(dev)->gen >= 6) {
- pm_irqs |= dev_priv->pm_rps_events;
+ pm_irqs |= dev_priv->rps.pm_events;
if (HAS_VEBOX(dev))
pm_irqs |= PM_VEBOX_USER_INTERRUPT;
@@ -3742,7 +3741,7 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
dev_priv->pm_irq_mask = 0xffffffff;
GEN8_IRQ_INIT_NDX(GT, 0, ~gt_interrupts[0], gt_interrupts[0]);
GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]);
- GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_irq_mask, dev_priv->pm_rps_events);
+ GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_irq_mask, dev_priv->rps.pm_events);
GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]);
}
@@ -4597,9 +4596,9 @@ void intel_irq_init(struct drm_device *dev)
/* Let's track the enabled rps events */
if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev))
/* WaGsvRC0ResidenncyMethod:VLV */
- dev_priv->pm_rps_events = GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED;
+ dev_priv->rps.pm_events = GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED;
else
- dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
+ dev_priv->rps.pm_events = GEN6_PM_RPS_EVENTS;
setup_timer(&dev_priv->gpu_error.hangcheck_timer,
i915_hangcheck_elapsed,
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 70f6d9c392c4..9903073ec5a3 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3348,7 +3348,7 @@ static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val)
if (val < dev_priv->rps.max_freq_softlimit)
mask |= GEN6_PM_RP_UP_EI_EXPIRED | GEN6_PM_RP_UP_THRESHOLD;
- mask &= dev_priv->pm_rps_events;
+ mask &= dev_priv->rps.pm_events;
/* IVB and SNB hard hangs on looping batchbuffer
* if GEN6_PM_UP_EI_EXPIRED is masked.
@@ -3451,7 +3451,7 @@ void gen6_rps_busy(struct drm_i915_private *dev_priv)
{
mutex_lock(&dev_priv->rps.hw_lock);
if (dev_priv->rps.enabled) {
- if (dev_priv->pm_rps_events & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED))
+ if (dev_priv->rps.pm_events & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED))
gen6_rps_reset_ei(dev_priv);
I915_WRITE(GEN6_PMINTRMSK,
gen6_rps_pm_mask(dev_priv, dev_priv->rps.cur_freq));
@@ -3551,8 +3551,8 @@ static void gen8_disable_rps_interrupts(struct drm_device *dev)
dev_priv-> rps.is_bdw_sw_turbo = false;
} else {
I915_WRITE(GEN6_PMINTRMSK, ~GEN8_PMINTR_REDIRECT_TO_NON_DISP);
- I915_WRITE(GEN8_GT_IER(2), I915_READ(GEN8_GT_IER(2)) &
- ~dev_priv->pm_rps_events);
+ I915_WRITE(GEN8_GT_IER(2),
+ I915_READ(GEN8_GT_IER(2)) & ~dev_priv->rps.pm_events);
/* Complete PM interrupt masking here doesn't race with the rps work
* item again unmasking PM interrupts because that is using a different
* register (GEN8_GT_IMR(2)) to mask PM interrupts. The only risk is in
@@ -3563,7 +3563,7 @@ static void gen8_disable_rps_interrupts(struct drm_device *dev)
dev_priv->rps.pm_iir = 0;
spin_unlock_irq(&dev_priv->irq_lock);
- I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);
+ I915_WRITE(GEN8_GT_IIR(2), dev_priv->rps.pm_events);
}
}
@@ -3573,7 +3573,7 @@ static void gen6_disable_rps_interrupts(struct drm_device *dev)
I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) &
- ~dev_priv->pm_rps_events);
+ ~dev_priv->rps.pm_events);
/* Complete PM interrupt masking here doesn't race with the rps work
* item again unmasking PM interrupts because that is using a different
* register (PMIMR) to mask PM interrupts. The only risk is in leaving
@@ -3583,7 +3583,7 @@ static void gen6_disable_rps_interrupts(struct drm_device *dev)
dev_priv->rps.pm_iir = 0;
spin_unlock_irq(&dev_priv->irq_lock);
- I915_WRITE(GEN6_PMIIR, dev_priv->pm_rps_events);
+ I915_WRITE(GEN6_PMIIR, dev_priv->rps.pm_events);
}
static void gen6_disable_rps(struct drm_device *dev)
@@ -3687,8 +3687,8 @@ static void gen8_enable_rps_interrupts(struct drm_device *dev)
spin_lock_irq(&dev_priv->irq_lock);
WARN_ON(dev_priv->rps.pm_iir);
- gen8_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
- I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);
+ gen8_enable_pm_irq(dev_priv, dev_priv->rps.pm_events);
+ I915_WRITE(GEN8_GT_IIR(2), dev_priv->rps.pm_events);
spin_unlock_irq(&dev_priv->irq_lock);
}
@@ -3698,8 +3698,8 @@ static void gen6_enable_rps_interrupts(struct drm_device *dev)
spin_lock_irq(&dev_priv->irq_lock);
WARN_ON(dev_priv->rps.pm_iir);
- gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
- I915_WRITE(GEN6_PMIIR, dev_priv->pm_rps_events);
+ gen6_enable_pm_irq(dev_priv, dev_priv->rps.pm_events);
+ I915_WRITE(GEN6_PMIIR, dev_priv->rps.pm_events);
spin_unlock_irq(&dev_priv->irq_lock);
}
--
2.1.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank
2014-09-02 13:57 [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank Chris Wilson
` (8 preceding siblings ...)
2014-09-02 13:57 ` [PATCH 10/10] drm/i915: Move pm_rps_events to i915->rps Chris Wilson
@ 2014-09-02 14:31 ` Ville Syrjälä
2014-09-02 14:36 ` Chris Wilson
2014-09-02 14:52 ` Daniel Vetter
10 siblings, 1 reply; 18+ messages in thread
From: Ville Syrjälä @ 2014-09-02 14:31 UTC (permalink / raw)
To: Chris Wilson; +Cc: Daniel Vetter, intel-gfx
On Tue, Sep 02, 2014 at 02:57:36PM +0100, Chris Wilson wrote:
> 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.
I have this plan that we stop using the flip done interrupts,
since they're anyway fairly broken on bdw. But I haven't really
thought how that would interact with this stall checking.
But I guess we can merge this stuff first and figure out the rest
when someone gets around to posting a patch for killing flip done.
>
> 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 | 34 +++++++---
> drivers/gpu/drm/i915/i915_irq.c | 84 +++++++------------------
> drivers/gpu/drm/i915/intel_display.c | 119 ++++++++++++++++++++++++++++-------
> drivers/gpu/drm/i915/intel_drv.h | 3 +
> 4 files changed, 147 insertions(+), 93 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 97c257d06729..f7816b4329d6 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -518,6 +518,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;
> @@ -537,6 +538,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);
> @@ -544,23 +547,34 @@ 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->flip_queued_request) {
> + struct i915_gem_request *rq = work->flip_queued_request;
> + seq_printf(m, "Flip queued on %s at seqno %u, next seqno %u [current breadcrumb %u], completed? %d\n",
> + rq->engine->name,
> + rq->seqno, rq->i915->next_seqno,
> + rq->engine->get_seqno(rq->engine),
> + __i915_request_complete__wa(rq));
> + } 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 1cd3a8ecb2f8..60ca89986499 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -2090,8 +2090,9 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
> spin_unlock(&dev_priv->irq_lock);
>
> for_each_pipe(dev_priv, 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);
> @@ -2390,8 +2391,9 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
> DRM_ERROR("Poison interrupt\n");
>
> for_each_pipe(dev_priv, 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))
> @@ -2440,8 +2442,9 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
> intel_opregion_asle_intr(dev);
>
> for_each_pipe(dev_priv, 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)) {
> @@ -2596,8 +2599,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);
> @@ -2900,52 +2904,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
> */
> @@ -4091,7 +4049,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);
>
> @@ -4102,11 +4060,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)
> @@ -4274,7 +4235,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);
>
> @@ -4285,11 +4246,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 8496a6b6f182..18c431e4f099 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3405,6 +3405,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;
> @@ -9234,7 +9257,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;
> @@ -9254,23 +9276,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)
> @@ -9688,6 +9696,64 @@ static int intel_default_queue_flip(struct i915_gem_request *rq,
> 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->flip_queued_request &&
> + !i915_request_complete(work->flip_queued_request))
> + 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,
> @@ -9748,12 +9814,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);
> @@ -9773,8 +9847,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);
>
> @@ -9839,6 +9911,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
> }
>
> work->flip_queued_request = rq;
> + work->flip_queued_vblank = drm_vblank_count(dev, intel_crtc->pipe);
> work->enable_stall_check = true;
>
> i915_gem_track_fb(work->old_fb_obj, obj,
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 18403c266682..1722673c534e 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -663,6 +663,8 @@ struct intel_unpin_work {
> u32 flip_count;
> u32 gtt_offset;
> struct i915_gem_request *flip_queued_request;
> + int flip_queued_vblank;
> + int flip_ready_vblank;
> bool enable_stall_check;
> };
>
> @@ -847,6 +849,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);
>
> /* shared dpll functions */
> struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
> --
> 2.1.0
--
Ville Syrjälä
Intel OTC
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank
2014-09-02 14:31 ` [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank Ville Syrjälä
@ 2014-09-02 14:36 ` Chris Wilson
0 siblings, 0 replies; 18+ messages in thread
From: Chris Wilson @ 2014-09-02 14:36 UTC (permalink / raw)
To: Ville Syrjälä; +Cc: Daniel Vetter, intel-gfx
On Tue, Sep 02, 2014 at 05:31:22PM +0300, Ville Syrjälä wrote:
> On Tue, Sep 02, 2014 at 02:57:36PM +0100, Chris Wilson wrote:
> > 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.
>
> I have this plan that we stop using the flip done interrupts,
> since they're anyway fairly broken on bdw. But I haven't really
> thought how that would interact with this stall checking.
Now that you remind me, I had a plan to rewrite this on top of that
future.
> But I guess we can merge this stuff first and figure out the rest
> when someone gets around to posting a patch for killing flip done.
Yeah, I think this is important in the short term as we have a bug
causing system freezes that this at least (+ next patch) allows us to
recover from.
-Chris
--
Chris Wilson, Intel Open Source Technology Centre
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank
2014-09-02 13:57 [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank Chris Wilson
` (9 preceding siblings ...)
2014-09-02 14:31 ` [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank Ville Syrjälä
@ 2014-09-02 14:52 ` Daniel Vetter
2014-09-02 15:07 ` Chris Wilson
10 siblings, 1 reply; 18+ messages in thread
From: Daniel Vetter @ 2014-09-02 14:52 UTC (permalink / raw)
To: Chris Wilson; +Cc: Daniel Vetter, intel-gfx
On Tue, Sep 02, 2014 at 02:57:36PM +0100, Chris Wilson wrote:
> 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>
This seems to be on top of the s/seqno/request/ patch which moves around
flip->enable_stall_check, which this patch here also does. I'm rather
confused about the resulting conflict. Especially since it took me a while
to understand what happened to enable_stall_check in your request patch,
so I don't think I'm qualified to resolve the conflict.
Can you please rebase this one here quickly?
Thanks, Daniel
> ---
> drivers/gpu/drm/i915/i915_debugfs.c | 34 +++++++---
> drivers/gpu/drm/i915/i915_irq.c | 84 +++++++------------------
> drivers/gpu/drm/i915/intel_display.c | 119 ++++++++++++++++++++++++++++-------
> drivers/gpu/drm/i915/intel_drv.h | 3 +
> 4 files changed, 147 insertions(+), 93 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 97c257d06729..f7816b4329d6 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -518,6 +518,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;
> @@ -537,6 +538,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);
> @@ -544,23 +547,34 @@ 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->flip_queued_request) {
> + struct i915_gem_request *rq = work->flip_queued_request;
> + seq_printf(m, "Flip queued on %s at seqno %u, next seqno %u [current breadcrumb %u], completed? %d\n",
> + rq->engine->name,
> + rq->seqno, rq->i915->next_seqno,
> + rq->engine->get_seqno(rq->engine),
> + __i915_request_complete__wa(rq));
> + } 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 1cd3a8ecb2f8..60ca89986499 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -2090,8 +2090,9 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
> spin_unlock(&dev_priv->irq_lock);
>
> for_each_pipe(dev_priv, 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);
> @@ -2390,8 +2391,9 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
> DRM_ERROR("Poison interrupt\n");
>
> for_each_pipe(dev_priv, 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))
> @@ -2440,8 +2442,9 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
> intel_opregion_asle_intr(dev);
>
> for_each_pipe(dev_priv, 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)) {
> @@ -2596,8 +2599,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);
> @@ -2900,52 +2904,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
> */
> @@ -4091,7 +4049,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);
>
> @@ -4102,11 +4060,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)
> @@ -4274,7 +4235,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);
>
> @@ -4285,11 +4246,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 8496a6b6f182..18c431e4f099 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3405,6 +3405,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;
> @@ -9234,7 +9257,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;
> @@ -9254,23 +9276,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)
> @@ -9688,6 +9696,64 @@ static int intel_default_queue_flip(struct i915_gem_request *rq,
> 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->flip_queued_request &&
> + !i915_request_complete(work->flip_queued_request))
> + 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,
> @@ -9748,12 +9814,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);
> @@ -9773,8 +9847,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);
>
> @@ -9839,6 +9911,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
> }
>
> work->flip_queued_request = rq;
> + work->flip_queued_vblank = drm_vblank_count(dev, intel_crtc->pipe);
> work->enable_stall_check = true;
>
> i915_gem_track_fb(work->old_fb_obj, obj,
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 18403c266682..1722673c534e 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -663,6 +663,8 @@ struct intel_unpin_work {
> u32 flip_count;
> u32 gtt_offset;
> struct i915_gem_request *flip_queued_request;
> + int flip_queued_vblank;
> + int flip_ready_vblank;
> bool enable_stall_check;
> };
>
> @@ -847,6 +849,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);
>
> /* shared dpll functions */
> struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
> --
> 2.1.0
>
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank
2014-09-02 14:52 ` Daniel Vetter
@ 2014-09-02 15:07 ` Chris Wilson
0 siblings, 0 replies; 18+ messages in thread
From: Chris Wilson @ 2014-09-02 15:07 UTC (permalink / raw)
To: Daniel Vetter; +Cc: Daniel Vetter, intel-gfx
On Tue, Sep 02, 2014 at 04:52:54PM +0200, Daniel Vetter wrote:
> On Tue, Sep 02, 2014 at 02:57:36PM +0100, Chris Wilson wrote:
> > 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>
>
> This seems to be on top of the s/seqno/request/ patch which moves around
> flip->enable_stall_check, which this patch here also does. I'm rather
> confused about the resulting conflict. Especially since it took me a while
> to understand what happened to enable_stall_check in your request patch,
> so I don't think I'm qualified to resolve the conflict.
>
> Can you please rebase this one here quickly?
I have an aversion to seqno/ring combinations. That is so archaic! :)
Just these two? I think keeping the requests interface for the boosting
is neater than readding more seqno compares.
-Chris
--
Chris Wilson, Intel Open Source Technology Centre
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 02/10] drm/i915: Decouple the stuck pageflip on modeset
2014-09-02 13:57 ` [PATCH 02/10] drm/i915: Decouple the stuck pageflip on modeset Chris Wilson
@ 2014-09-04 17:15 ` Ville Syrjälä
2014-09-05 7:27 ` Daniel Vetter
0 siblings, 1 reply; 18+ messages in thread
From: Ville Syrjälä @ 2014-09-04 17:15 UTC (permalink / raw)
To: Chris Wilson; +Cc: Daniel Vetter, intel-gfx
On Tue, Sep 02, 2014 at 02:57:37PM +0100, Chris Wilson wrote:
> 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>
Yeah, seems better than having the flip stuck forever.
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
> 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 18c431e4f099..bbc3d509bcd7 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3434,9 +3434,19 @@ void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
> struct drm_i915_private *dev_priv = dev->dev_private;
>
> 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);
> + }
>
> if (crtc->primary->fb) {
> mutex_lock(&dev->struct_mutex);
> --
> 2.1.0
--
Ville Syrjälä
Intel OTC
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 02/10] drm/i915: Decouple the stuck pageflip on modeset
2014-09-04 17:15 ` Ville Syrjälä
@ 2014-09-05 7:27 ` Daniel Vetter
2014-09-05 7:31 ` Chris Wilson
0 siblings, 1 reply; 18+ messages in thread
From: Daniel Vetter @ 2014-09-05 7:27 UTC (permalink / raw)
To: Ville Syrjälä; +Cc: Daniel Vetter, intel-gfx
On Thu, Sep 04, 2014 at 08:15:32PM +0300, Ville Syrjälä wrote:
> On Tue, Sep 02, 2014 at 02:57:37PM +0100, Chris Wilson wrote:
> > 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
This applied cleanly despite that I don't have that refactor. Should I be
concerned?
> > 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>
>
> Yeah, seems better than having the flip stuck forever.
>
> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Queued for -next, thanks for the patch.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 02/10] drm/i915: Decouple the stuck pageflip on modeset
2014-09-05 7:27 ` Daniel Vetter
@ 2014-09-05 7:31 ` Chris Wilson
2014-09-05 8:51 ` Daniel Vetter
0 siblings, 1 reply; 18+ messages in thread
From: Chris Wilson @ 2014-09-05 7:31 UTC (permalink / raw)
To: Daniel Vetter; +Cc: Daniel Vetter, intel-gfx
On Fri, Sep 05, 2014 at 09:27:16AM +0200, Daniel Vetter wrote:
> On Thu, Sep 04, 2014 at 08:15:32PM +0300, Ville Syrjälä wrote:
> > On Tue, Sep 02, 2014 at 02:57:37PM +0100, Chris Wilson wrote:
> > > 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
>
> This applied cleanly despite that I don't have that refactor. Should I be
> concerned?
No, the refactoring here was about the pageflip checking itself in patch
1. I just kept moving these two in lockstep.
-Chris
--
Chris Wilson, Intel Open Source Technology Centre
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 02/10] drm/i915: Decouple the stuck pageflip on modeset
2014-09-05 7:31 ` Chris Wilson
@ 2014-09-05 8:51 ` Daniel Vetter
0 siblings, 0 replies; 18+ messages in thread
From: Daniel Vetter @ 2014-09-05 8:51 UTC (permalink / raw)
To: Chris Wilson, Daniel Vetter, Ville Syrjälä, intel-gfx,
Daniel Vetter
On Fri, Sep 05, 2014 at 08:31:20AM +0100, Chris Wilson wrote:
> On Fri, Sep 05, 2014 at 09:27:16AM +0200, Daniel Vetter wrote:
> > On Thu, Sep 04, 2014 at 08:15:32PM +0300, Ville Syrjälä wrote:
> > > On Tue, Sep 02, 2014 at 02:57:37PM +0100, Chris Wilson wrote:
> > > > 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
> >
> > This applied cleanly despite that I don't have that refactor. Should I be
> > concerned?
>
> No, the refactoring here was about the pageflip checking itself in patch
> 1. I just kept moving these two in lockstep.
Yeah, serious lack of coffee when I tried to apply this ;-)
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2014-09-05 8:51 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-09-02 13:57 [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank Chris Wilson
2014-09-02 13:57 ` [PATCH 02/10] drm/i915: Decouple the stuck pageflip on modeset Chris Wilson
2014-09-04 17:15 ` Ville Syrjälä
2014-09-05 7:27 ` Daniel Vetter
2014-09-05 7:31 ` Chris Wilson
2014-09-05 8:51 ` Daniel Vetter
2014-09-02 13:57 ` [PATCH 03/10] drm/i915: Boost GPU frequency if we detect outstanding pageflips Chris Wilson
2014-09-02 13:57 ` [PATCH 04/10] drm/i915: Deminish contribution of wait-boosting from clients Chris Wilson
2014-09-02 13:57 ` [PATCH 05/10] drm/i915: Relax RPS contraints to allows setting minfreq on idle Chris Wilson
2014-09-02 13:57 ` [PATCH 06/10] drm/i915: Rearrange RPS frequency calculation Chris Wilson
2014-09-02 13:57 ` [PATCH 07/10] drm/i915: Improved w/a for rps on Baytrail Chris Wilson
2014-09-02 13:57 ` [PATCH 08/10] drm/i915: Use down ei for manual Baytrail RPS calculations Chris Wilson
2014-09-02 13:57 ` [PATCH 09/10] drm/i915: Agressive downclocking on Baytrail Chris Wilson
2014-09-02 13:57 ` [PATCH 10/10] drm/i915: Move pm_rps_events to i915->rps Chris Wilson
2014-09-02 14:31 ` [PATCH 01/10] drm/i915: Check for a stalled page flip after each vblank Ville Syrjälä
2014-09-02 14:36 ` Chris Wilson
2014-09-02 14:52 ` Daniel Vetter
2014-09-02 15:07 ` Chris Wilson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox