Commit 9593a657 authored by Chris Wilson's avatar Chris Wilson

drm/i915: Try harder to reset the GPU

Repeat the reset a couple of times if at first we do not succeed.

v2: differentiate which path/engine failed with a debug message
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/20170513083726.502-1-chris@chris-wilson.co.ukReviewed-by: default avatarMika Kuoppala <mika.kuoppala@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170518204811.7408-1-chris@chris-wilson.co.uk
parent 29f31623
...@@ -1427,9 +1427,10 @@ int i915_reg_read_ioctl(struct drm_device *dev, ...@@ -1427,9 +1427,10 @@ int i915_reg_read_ioctl(struct drm_device *dev,
return ret; return ret;
} }
static int i915_reset_complete(struct pci_dev *pdev) static bool i915_reset_complete(struct pci_dev *pdev)
{ {
u8 gdrst; u8 gdrst;
pci_read_config_byte(pdev, I915_GDRST, &gdrst); pci_read_config_byte(pdev, I915_GDRST, &gdrst);
return (gdrst & GRDOM_RESET_STATUS) == 0; return (gdrst & GRDOM_RESET_STATUS) == 0;
} }
...@@ -1440,15 +1441,16 @@ static int i915_do_reset(struct drm_i915_private *dev_priv, unsigned engine_mask ...@@ -1440,15 +1441,16 @@ static int i915_do_reset(struct drm_i915_private *dev_priv, unsigned engine_mask
/* assert reset for at least 20 usec */ /* assert reset for at least 20 usec */
pci_write_config_byte(pdev, I915_GDRST, GRDOM_RESET_ENABLE); pci_write_config_byte(pdev, I915_GDRST, GRDOM_RESET_ENABLE);
udelay(20); usleep_range(50, 200);
pci_write_config_byte(pdev, I915_GDRST, 0); pci_write_config_byte(pdev, I915_GDRST, 0);
return wait_for(i915_reset_complete(pdev), 500); return wait_for(i915_reset_complete(pdev), 500);
} }
static int g4x_reset_complete(struct pci_dev *pdev) static bool g4x_reset_complete(struct pci_dev *pdev)
{ {
u8 gdrst; u8 gdrst;
pci_read_config_byte(pdev, I915_GDRST, &gdrst); pci_read_config_byte(pdev, I915_GDRST, &gdrst);
return (gdrst & GRDOM_RESET_ENABLE) == 0; return (gdrst & GRDOM_RESET_ENABLE) == 0;
} }
...@@ -1456,6 +1458,7 @@ static int g4x_reset_complete(struct pci_dev *pdev) ...@@ -1456,6 +1458,7 @@ static int g4x_reset_complete(struct pci_dev *pdev)
static int g33_do_reset(struct drm_i915_private *dev_priv, unsigned engine_mask) static int g33_do_reset(struct drm_i915_private *dev_priv, unsigned engine_mask)
{ {
struct pci_dev *pdev = dev_priv->drm.pdev; struct pci_dev *pdev = dev_priv->drm.pdev;
pci_write_config_byte(pdev, I915_GDRST, GRDOM_RESET_ENABLE); pci_write_config_byte(pdev, I915_GDRST, GRDOM_RESET_ENABLE);
return wait_for(g4x_reset_complete(pdev), 500); return wait_for(g4x_reset_complete(pdev), 500);
} }
...@@ -1468,8 +1471,10 @@ static int g4x_do_reset(struct drm_i915_private *dev_priv, unsigned engine_mask) ...@@ -1468,8 +1471,10 @@ static int g4x_do_reset(struct drm_i915_private *dev_priv, unsigned engine_mask)
pci_write_config_byte(pdev, I915_GDRST, pci_write_config_byte(pdev, I915_GDRST,
GRDOM_RENDER | GRDOM_RESET_ENABLE); GRDOM_RENDER | GRDOM_RESET_ENABLE);
ret = wait_for(g4x_reset_complete(pdev), 500); ret = wait_for(g4x_reset_complete(pdev), 500);
if (ret) if (ret) {
return ret; DRM_DEBUG_DRIVER("Wait for render reset failed\n");
goto out;
}
/* WaVcpClkGateDisableForMediaReset:ctg,elk */ /* WaVcpClkGateDisableForMediaReset:ctg,elk */
I915_WRITE(VDECCLK_GATE_D, I915_READ(VDECCLK_GATE_D) | VCP_UNIT_CLOCK_GATE_DISABLE); I915_WRITE(VDECCLK_GATE_D, I915_READ(VDECCLK_GATE_D) | VCP_UNIT_CLOCK_GATE_DISABLE);
...@@ -1478,16 +1483,17 @@ static int g4x_do_reset(struct drm_i915_private *dev_priv, unsigned engine_mask) ...@@ -1478,16 +1483,17 @@ static int g4x_do_reset(struct drm_i915_private *dev_priv, unsigned engine_mask)
pci_write_config_byte(pdev, I915_GDRST, pci_write_config_byte(pdev, I915_GDRST,
GRDOM_MEDIA | GRDOM_RESET_ENABLE); GRDOM_MEDIA | GRDOM_RESET_ENABLE);
ret = wait_for(g4x_reset_complete(pdev), 500); ret = wait_for(g4x_reset_complete(pdev), 500);
if (ret) if (ret) {
return ret; DRM_DEBUG_DRIVER("Wait for media reset failed\n");
}
/* WaVcpClkGateDisableForMediaReset:ctg,elk */ /* WaVcpClkGateDisableForMediaReset:ctg,elk */
I915_WRITE(VDECCLK_GATE_D, I915_READ(VDECCLK_GATE_D) & ~VCP_UNIT_CLOCK_GATE_DISABLE); I915_WRITE(VDECCLK_GATE_D, I915_READ(VDECCLK_GATE_D) & ~VCP_UNIT_CLOCK_GATE_DISABLE);
POSTING_READ(VDECCLK_GATE_D); POSTING_READ(VDECCLK_GATE_D);
out:
pci_write_config_byte(pdev, I915_GDRST, 0); pci_write_config_byte(pdev, I915_GDRST, 0);
return ret;
return 0;
} }
static int ironlake_do_reset(struct drm_i915_private *dev_priv, static int ironlake_do_reset(struct drm_i915_private *dev_priv,
...@@ -1495,31 +1501,36 @@ static int ironlake_do_reset(struct drm_i915_private *dev_priv, ...@@ -1495,31 +1501,36 @@ static int ironlake_do_reset(struct drm_i915_private *dev_priv,
{ {
int ret; int ret;
I915_WRITE(ILK_GDSR, I915_WRITE(ILK_GDSR, ILK_GRDOM_RENDER | ILK_GRDOM_RESET_ENABLE);
ILK_GRDOM_RENDER | ILK_GRDOM_RESET_ENABLE);
ret = intel_wait_for_register(dev_priv, ret = intel_wait_for_register(dev_priv,
ILK_GDSR, ILK_GRDOM_RESET_ENABLE, 0, ILK_GDSR, ILK_GRDOM_RESET_ENABLE, 0,
500); 500);
if (ret) if (ret) {
return ret; DRM_DEBUG_DRIVER("Wait for render reset failed\n");
goto out;
}
I915_WRITE(ILK_GDSR, I915_WRITE(ILK_GDSR, ILK_GRDOM_MEDIA | ILK_GRDOM_RESET_ENABLE);
ILK_GRDOM_MEDIA | ILK_GRDOM_RESET_ENABLE);
ret = intel_wait_for_register(dev_priv, ret = intel_wait_for_register(dev_priv,
ILK_GDSR, ILK_GRDOM_RESET_ENABLE, 0, ILK_GDSR, ILK_GRDOM_RESET_ENABLE, 0,
500); 500);
if (ret) if (ret) {
return ret; DRM_DEBUG_DRIVER("Wait for media reset failed\n");
goto out;
}
out:
I915_WRITE(ILK_GDSR, 0); I915_WRITE(ILK_GDSR, 0);
POSTING_READ(ILK_GDSR);
return 0; return ret;
} }
/* Reset the hardware domains (GENX_GRDOM_*) specified by mask */ /* Reset the hardware domains (GENX_GRDOM_*) specified by mask */
static int gen6_hw_domain_reset(struct drm_i915_private *dev_priv, static int gen6_hw_domain_reset(struct drm_i915_private *dev_priv,
u32 hw_domain_mask) u32 hw_domain_mask)
{ {
int err;
/* GEN6_GDRST is not in the gt power well, no need to check /* GEN6_GDRST is not in the gt power well, no need to check
* for fifo space for the write or forcewake the chip for * for fifo space for the write or forcewake the chip for
* the read * the read
...@@ -1527,9 +1538,14 @@ static int gen6_hw_domain_reset(struct drm_i915_private *dev_priv, ...@@ -1527,9 +1538,14 @@ static int gen6_hw_domain_reset(struct drm_i915_private *dev_priv,
__raw_i915_write32(dev_priv, GEN6_GDRST, hw_domain_mask); __raw_i915_write32(dev_priv, GEN6_GDRST, hw_domain_mask);
/* Wait for the device to ack the reset requests */ /* Wait for the device to ack the reset requests */
return intel_wait_for_register_fw(dev_priv, err = intel_wait_for_register_fw(dev_priv,
GEN6_GDRST, hw_domain_mask, 0, GEN6_GDRST, hw_domain_mask, 0,
500); 500);
if (err)
DRM_DEBUG_DRIVER("Wait for 0x%08x engines reset failed\n",
hw_domain_mask);
return err;
} }
/** /**
...@@ -1749,8 +1765,11 @@ static reset_func intel_get_gpu_reset(struct drm_i915_private *dev_priv) ...@@ -1749,8 +1765,11 @@ static reset_func intel_get_gpu_reset(struct drm_i915_private *dev_priv)
int intel_gpu_reset(struct drm_i915_private *dev_priv, unsigned engine_mask) int intel_gpu_reset(struct drm_i915_private *dev_priv, unsigned engine_mask)
{ {
reset_func reset; reset_func reset;
int retry;
int ret; int ret;
might_sleep();
reset = intel_get_gpu_reset(dev_priv); reset = intel_get_gpu_reset(dev_priv);
if (reset == NULL) if (reset == NULL)
return -ENODEV; return -ENODEV;
...@@ -1759,7 +1778,13 @@ int intel_gpu_reset(struct drm_i915_private *dev_priv, unsigned engine_mask) ...@@ -1759,7 +1778,13 @@ int intel_gpu_reset(struct drm_i915_private *dev_priv, unsigned engine_mask)
* request may be dropped and never completes (causing -EIO). * request may be dropped and never completes (causing -EIO).
*/ */
intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
ret = reset(dev_priv, engine_mask); for (retry = 0; retry < 3; retry++) {
ret = reset(dev_priv, engine_mask);
if (ret != -ETIMEDOUT)
break;
cond_resched();
}
intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment