diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2016-09-09 09:11:52 -0400 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2016-09-09 09:23:04 -0400 |
commit | 780f262a703a683bc56bbb860b25286a6f501d61 (patch) | |
tree | c31bdc885b028ae07757331ceebbcb3ebcc823b3 /drivers/gpu/drm | |
parent | 221fe7994554cc3985fc5d761ed7e44dcae0fa52 (diff) |
drm/i915: Replace wait-on-mutex with wait-on-bit in reset worker
Since we have a cooperative mode now with a direct reset, we can avoid
the contention on struct_mutex and instead try then sleep on the
I915_RESET_IN_PROGRESS bit. If the mutex is held and that bit is
cleared, all is fine. Otherwise, we sleep for a bit and try again. In
the worst case we sleep for an extra second waiting for the mutex to be
released (no one touching the GPU is allowed the struct_mutex whilst the
I915_RESET_IN_PROGRESS bit is set). But when we have a direct reset,
this allows us to clean up the reset worker faster.
v2: Remember to call wake_up_bit() after changing (for the faster wakeup
as promised)
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20160909131201.16673-12-chris@chris-wilson.co.uk
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 31 |
3 files changed, 27 insertions, 20 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ff4173e6e298..f2614b2f59f7 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
@@ -1726,8 +1726,8 @@ int i915_resume_switcheroo(struct drm_device *dev) | |||
1726 | * i915_reset - reset chip after a hang | 1726 | * i915_reset - reset chip after a hang |
1727 | * @dev: drm device to reset | 1727 | * @dev: drm device to reset |
1728 | * | 1728 | * |
1729 | * Reset the chip. Useful if a hang is detected. Returns zero on successful | 1729 | * Reset the chip. Useful if a hang is detected. Marks the device as wedged |
1730 | * reset or otherwise an error code. | 1730 | * on failure. |
1731 | * | 1731 | * |
1732 | * Caller must hold the struct_mutex. | 1732 | * Caller must hold the struct_mutex. |
1733 | * | 1733 | * |
@@ -1739,7 +1739,7 @@ int i915_resume_switcheroo(struct drm_device *dev) | |||
1739 | * - re-init interrupt state | 1739 | * - re-init interrupt state |
1740 | * - re-init display | 1740 | * - re-init display |
1741 | */ | 1741 | */ |
1742 | int i915_reset(struct drm_i915_private *dev_priv) | 1742 | void i915_reset(struct drm_i915_private *dev_priv) |
1743 | { | 1743 | { |
1744 | struct drm_device *dev = &dev_priv->drm; | 1744 | struct drm_device *dev = &dev_priv->drm; |
1745 | struct i915_gpu_error *error = &dev_priv->gpu_error; | 1745 | struct i915_gpu_error *error = &dev_priv->gpu_error; |
@@ -1748,7 +1748,7 @@ int i915_reset(struct drm_i915_private *dev_priv) | |||
1748 | lockdep_assert_held(&dev->struct_mutex); | 1748 | lockdep_assert_held(&dev->struct_mutex); |
1749 | 1749 | ||
1750 | if (!test_and_clear_bit(I915_RESET_IN_PROGRESS, &error->flags)) | 1750 | if (!test_and_clear_bit(I915_RESET_IN_PROGRESS, &error->flags)) |
1751 | return test_bit(I915_WEDGED, &error->flags) ? -EIO : 0; | 1751 | return; |
1752 | 1752 | ||
1753 | /* Clear any previous failed attempts at recovery. Time to try again. */ | 1753 | /* Clear any previous failed attempts at recovery. Time to try again. */ |
1754 | __clear_bit(I915_WEDGED, &error->flags); | 1754 | __clear_bit(I915_WEDGED, &error->flags); |
@@ -1798,11 +1798,13 @@ int i915_reset(struct drm_i915_private *dev_priv) | |||
1798 | intel_sanitize_gt_powersave(dev_priv); | 1798 | intel_sanitize_gt_powersave(dev_priv); |
1799 | intel_autoenable_gt_powersave(dev_priv); | 1799 | intel_autoenable_gt_powersave(dev_priv); |
1800 | 1800 | ||
1801 | return 0; | 1801 | wakeup: |
1802 | wake_up_bit(&error->flags, I915_RESET_IN_PROGRESS); | ||
1803 | return; | ||
1802 | 1804 | ||
1803 | error: | 1805 | error: |
1804 | set_bit(I915_WEDGED, &error->flags); | 1806 | set_bit(I915_WEDGED, &error->flags); |
1805 | return ret; | 1807 | goto wakeup; |
1806 | } | 1808 | } |
1807 | 1809 | ||
1808 | static int i915_pm_suspend(struct device *kdev) | 1810 | static int i915_pm_suspend(struct device *kdev) |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 15f1977e356a..9a9f07f3574c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -2884,7 +2884,7 @@ extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, | |||
2884 | #endif | 2884 | #endif |
2885 | extern int intel_gpu_reset(struct drm_i915_private *dev_priv, u32 engine_mask); | 2885 | extern int intel_gpu_reset(struct drm_i915_private *dev_priv, u32 engine_mask); |
2886 | extern bool intel_has_gpu_reset(struct drm_i915_private *dev_priv); | 2886 | extern bool intel_has_gpu_reset(struct drm_i915_private *dev_priv); |
2887 | extern int i915_reset(struct drm_i915_private *dev_priv); | 2887 | extern void i915_reset(struct drm_i915_private *dev_priv); |
2888 | extern int intel_guc_reset(struct drm_i915_private *dev_priv); | 2888 | extern int intel_guc_reset(struct drm_i915_private *dev_priv); |
2889 | extern void intel_engine_init_hangcheck(struct intel_engine_cs *engine); | 2889 | extern void intel_engine_init_hangcheck(struct intel_engine_cs *engine); |
2890 | extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv); | 2890 | extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv); |
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2c7cb5041511..ef2d40278191 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -2497,7 +2497,6 @@ static void i915_reset_and_wakeup(struct drm_i915_private *dev_priv) | |||
2497 | char *error_event[] = { I915_ERROR_UEVENT "=1", NULL }; | 2497 | char *error_event[] = { I915_ERROR_UEVENT "=1", NULL }; |
2498 | char *reset_event[] = { I915_RESET_UEVENT "=1", NULL }; | 2498 | char *reset_event[] = { I915_RESET_UEVENT "=1", NULL }; |
2499 | char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL }; | 2499 | char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL }; |
2500 | int ret; | ||
2501 | 2500 | ||
2502 | kobject_uevent_env(kobj, KOBJ_CHANGE, error_event); | 2501 | kobject_uevent_env(kobj, KOBJ_CHANGE, error_event); |
2503 | 2502 | ||
@@ -2512,24 +2511,30 @@ static void i915_reset_and_wakeup(struct drm_i915_private *dev_priv) | |||
2512 | * simulated reset via debugs, so get an RPM reference. | 2511 | * simulated reset via debugs, so get an RPM reference. |
2513 | */ | 2512 | */ |
2514 | intel_runtime_pm_get(dev_priv); | 2513 | intel_runtime_pm_get(dev_priv); |
2515 | |||
2516 | intel_prepare_reset(dev_priv); | 2514 | intel_prepare_reset(dev_priv); |
2517 | 2515 | ||
2518 | /* | 2516 | do { |
2519 | * All state reset _must_ be completed before we update the | 2517 | /* |
2520 | * reset counter, for otherwise waiters might miss the reset | 2518 | * All state reset _must_ be completed before we update the |
2521 | * pending state and not properly drop locks, resulting in | 2519 | * reset counter, for otherwise waiters might miss the reset |
2522 | * deadlocks with the reset work. | 2520 | * pending state and not properly drop locks, resulting in |
2523 | */ | 2521 | * deadlocks with the reset work. |
2524 | mutex_lock(&dev_priv->drm.struct_mutex); | 2522 | */ |
2525 | ret = i915_reset(dev_priv); | 2523 | if (mutex_trylock(&dev_priv->drm.struct_mutex)) { |
2526 | mutex_unlock(&dev_priv->drm.struct_mutex); | 2524 | i915_reset(dev_priv); |
2525 | mutex_unlock(&dev_priv->drm.struct_mutex); | ||
2526 | } | ||
2527 | 2527 | ||
2528 | intel_finish_reset(dev_priv); | 2528 | /* We need to wait for anyone holding the lock to wakeup */ |
2529 | } while (wait_on_bit_timeout(&dev_priv->gpu_error.flags, | ||
2530 | I915_RESET_IN_PROGRESS, | ||
2531 | TASK_UNINTERRUPTIBLE, | ||
2532 | HZ)); | ||
2529 | 2533 | ||
2534 | intel_finish_reset(dev_priv); | ||
2530 | intel_runtime_pm_put(dev_priv); | 2535 | intel_runtime_pm_put(dev_priv); |
2531 | 2536 | ||
2532 | if (ret == 0) | 2537 | if (!test_bit(I915_WEDGED, &dev_priv->gpu_error.flags)) |
2533 | kobject_uevent_env(kobj, | 2538 | kobject_uevent_env(kobj, |
2534 | KOBJ_CHANGE, reset_done_event); | 2539 | KOBJ_CHANGE, reset_done_event); |
2535 | 2540 | ||