aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2013-03-14 11:52:05 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-03-17 17:52:51 -0400
commita24a11e6b4e96bca817f854e0ffcce75d3eddd13 (patch)
tree2ec3748ba69802d163c1d3071c318c24e8b65886
parent5d83d2947ea8db7362942538772b6f9208f09c0e (diff)
drm/i915: Resurrect ring kicking for semaphores, selectively
Once we thought we got semaphores working, we disabled kicking the ring if hangcheck fired whilst waiting upon a ring as it was doing more harm than good: commit 4e0e90dcb8a7df1229c69e30abebb59b0b3c2a1f Author: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Wed Dec 14 13:56:58 2011 +0100 drm/i915: kicking rings stuck on semaphores considered harmful However, life is never that easy and semaphores are still causing problems whereby the value written by one ring (bcs) is not being propagated to the waiter (rcs). Thus the waiter never wakes up and we declare the GPU hung, which often has unfortunate consequences, even if we successfully reset the GPU. But the GPU is idle as it has completed the work, just didn't notify its clients. So we can detect the incomplete wait during hang check and probe the target ring to see if has indeed emitted the breadcrumb seqno following the work and then and only then kick the waiter. Based on a suggestion by Ben Widawsky. v2: cross-check wait with iphdr. fix signaller calculation. References: https://bugs.freedesktop.org/show_bug.cgi?id=54226 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Mika Kuoppala <mika.kuoppala@intel.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Ben Widawsky <ben@bwidawsk.net> Acked-by: Ben Widawsky <ben@bwidawsk.net> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 39621e50ca5e..63abf2fa1fa4 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1787,6 +1787,37 @@ static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err)
1787 return false; 1787 return false;
1788} 1788}
1789 1789
1790static bool semaphore_passed(struct intel_ring_buffer *ring)
1791{
1792 struct drm_i915_private *dev_priv = ring->dev->dev_private;
1793 u32 acthd = intel_ring_get_active_head(ring) & HEAD_ADDR;
1794 struct intel_ring_buffer *signaller;
1795 u32 cmd, ipehr, acthd_min;
1796
1797 ipehr = I915_READ(RING_IPEHR(ring->mmio_base));
1798 if ((ipehr & ~(0x3 << 16)) !=
1799 (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER))
1800 return false;
1801
1802 /* ACTHD is likely pointing to the dword after the actual command,
1803 * so scan backwards until we find the MBOX.
1804 */
1805 acthd_min = max((int)acthd - 3 * 4, 0);
1806 do {
1807 cmd = ioread32(ring->virtual_start + acthd);
1808 if (cmd == ipehr)
1809 break;
1810
1811 acthd -= 4;
1812 if (acthd < acthd_min)
1813 return false;
1814 } while (1);
1815
1816 signaller = &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3];
1817 return i915_seqno_passed(signaller->get_seqno(signaller, false),
1818 ioread32(ring->virtual_start+acthd+4)+1);
1819}
1820
1790static bool kick_ring(struct intel_ring_buffer *ring) 1821static bool kick_ring(struct intel_ring_buffer *ring)
1791{ 1822{
1792 struct drm_device *dev = ring->dev; 1823 struct drm_device *dev = ring->dev;
@@ -1798,6 +1829,15 @@ static bool kick_ring(struct intel_ring_buffer *ring)
1798 I915_WRITE_CTL(ring, tmp); 1829 I915_WRITE_CTL(ring, tmp);
1799 return true; 1830 return true;
1800 } 1831 }
1832
1833 if (INTEL_INFO(dev)->gen >= 6 &&
1834 tmp & RING_WAIT_SEMAPHORE &&
1835 semaphore_passed(ring)) {
1836 DRM_ERROR("Kicking stuck semaphore on %s\n",
1837 ring->name);
1838 I915_WRITE_CTL(ring, tmp);
1839 return true;
1840 }
1801 return false; 1841 return false;
1802} 1842}
1803 1843