aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-04-10 12:00:41 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-04-15 13:37:37 -0400
commitd1e61e7fc4456c4cb9a33ed182edf40e34ddedea (patch)
tree24210178e48521c970b66c4c673b9cbff9a2bb2a /drivers/gpu/drm
parent56fa6d6ff76c7700f8dd131bee9ffa6c3c06dcd4 (diff)
drm/i915: Trigger hangcheck if we detect more a repeating missed IRQ
On the first instance we just wish to kick the waiters and see if that terminates the wait conditions. If it does not, then we do not want to keep retrying without ever making any forward progress and becoming stuck in a hangcheck loop. Reported-and-tested-by: Lukas Hejtmanek <xhejtman@fi.muni.cz> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=48209 Reviewed-by: Ben Widawsky <ben@bwidawsk.net> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c63
1 files changed, 38 insertions, 25 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index febddc2952fb..39663f51e102 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1875,6 +1875,36 @@ static bool kick_ring(struct intel_ring_buffer *ring)
1875 return false; 1875 return false;
1876} 1876}
1877 1877
1878static bool i915_hangcheck_hung(struct drm_device *dev)
1879{
1880 drm_i915_private_t *dev_priv = dev->dev_private;
1881
1882 if (dev_priv->hangcheck_count++ > 1) {
1883 DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
1884 i915_handle_error(dev, true);
1885
1886 if (!IS_GEN2(dev)) {
1887 /* Is the chip hanging on a WAIT_FOR_EVENT?
1888 * If so we can simply poke the RB_WAIT bit
1889 * and break the hang. This should work on
1890 * all but the second generation chipsets.
1891 */
1892 if (kick_ring(&dev_priv->ring[RCS]))
1893 return false;
1894
1895 if (HAS_BSD(dev) && kick_ring(&dev_priv->ring[VCS]))
1896 return false;
1897
1898 if (HAS_BLT(dev) && kick_ring(&dev_priv->ring[BCS]))
1899 return false;
1900 }
1901
1902 return true;
1903 }
1904
1905 return false;
1906}
1907
1878/** 1908/**
1879 * This is called when the chip hasn't reported back with completed 1909 * This is called when the chip hasn't reported back with completed
1880 * batchbuffers in a long time. The first time this is called we simply record 1910 * batchbuffers in a long time. The first time this is called we simply record
@@ -1895,9 +1925,14 @@ void i915_hangcheck_elapsed(unsigned long data)
1895 if (i915_hangcheck_ring_idle(&dev_priv->ring[RCS], &err) && 1925 if (i915_hangcheck_ring_idle(&dev_priv->ring[RCS], &err) &&
1896 i915_hangcheck_ring_idle(&dev_priv->ring[VCS], &err) && 1926 i915_hangcheck_ring_idle(&dev_priv->ring[VCS], &err) &&
1897 i915_hangcheck_ring_idle(&dev_priv->ring[BCS], &err)) { 1927 i915_hangcheck_ring_idle(&dev_priv->ring[BCS], &err)) {
1898 dev_priv->hangcheck_count = 0; 1928 if (err) {
1899 if (err) 1929 if (i915_hangcheck_hung(dev))
1930 return;
1931
1900 goto repeat; 1932 goto repeat;
1933 }
1934
1935 dev_priv->hangcheck_count = 0;
1901 return; 1936 return;
1902 } 1937 }
1903 1938
@@ -1919,30 +1954,8 @@ void i915_hangcheck_elapsed(unsigned long data)
1919 dev_priv->last_acthd_blt == acthd_blt && 1954 dev_priv->last_acthd_blt == acthd_blt &&
1920 dev_priv->last_instdone == instdone && 1955 dev_priv->last_instdone == instdone &&
1921 dev_priv->last_instdone1 == instdone1) { 1956 dev_priv->last_instdone1 == instdone1) {
1922 if (dev_priv->hangcheck_count++ > 1) { 1957 if (i915_hangcheck_hung(dev))
1923 DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
1924 i915_handle_error(dev, true);
1925
1926 if (!IS_GEN2(dev)) {
1927 /* Is the chip hanging on a WAIT_FOR_EVENT?
1928 * If so we can simply poke the RB_WAIT bit
1929 * and break the hang. This should work on
1930 * all but the second generation chipsets.
1931 */
1932 if (kick_ring(&dev_priv->ring[RCS]))
1933 goto repeat;
1934
1935 if (HAS_BSD(dev) &&
1936 kick_ring(&dev_priv->ring[VCS]))
1937 goto repeat;
1938
1939 if (HAS_BLT(dev) &&
1940 kick_ring(&dev_priv->ring[BCS]))
1941 goto repeat;
1942 }
1943
1944 return; 1958 return;
1945 }
1946 } else { 1959 } else {
1947 dev_priv->hangcheck_count = 0; 1960 dev_priv->hangcheck_count = 0;
1948 1961