>From 698fdaf8a85fb7039dacdff3068be2018a486816 Mon Sep 17 00:00:00 2001 Message-Id: <698fdaf8a85fb7039dacdff3068be2018a486816.1387201899.git.ian.lister@xxxxxxxxx> In-Reply-To: <cover.1387201899.git.ian.lister@xxxxxxxxx> References: <cover.1387201899.git.ian.lister@xxxxxxxxx> From: ian-lister <ian.lister@xxxxxxxxx> Date: Mon, 9 Dec 2013 09:47:20 +0000 Subject: [RFC 04/13] drm/i915: Force wake restore for TDR Abstracted force wake restore code from gen6_do_reset into its own function "gen6_gt_force_wake_restore" as it will also be needed for per-engine reset. It has been expanded to cope with the Valleyview specific forcewake restore. Signed-off-by: ian-lister <ian.lister@xxxxxxxxx> --- drivers/gpu/drm/i915/i915_drv.h | 4 + drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + drivers/gpu/drm/i915/intel_uncore.c | 197 ++++++++++++++++++++++++++++++-- 4 files changed, 192 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f261ab5..b9c4876 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -459,6 +459,8 @@ struct intel_uncore { unsigned fw_rendercount; unsigned fw_mediacount; + unsigned ecobus; + struct delayed_work force_wake_work; }; @@ -1927,6 +1929,8 @@ extern int i915_emit_box(struct drm_device *dev, struct drm_clip_rect *box, int DR1, int DR4); extern int intel_gpu_reset(struct drm_device *dev); +extern int intel_gpu_engine_reset(struct drm_device *dev, + enum intel_ring_id engine); extern int i915_reset(struct drm_device *dev); extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv); extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index bda7562..e896bca 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -107,6 +107,7 @@ #define GEN6_GRDOM_RENDER (1 << 1) #define GEN6_GRDOM_MEDIA (1 << 2) #define GEN6_GRDOM_BLT (1 << 3) +#define GEN6_GRDOM_VEBOX (1 << 4) #define RING_PP_DIR_BASE(ring) ((ring)->mmio_base+0x228) #define RING_PP_DIR_BASE_READ(ring) ((ring)->mmio_base+0x518) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index c15b97b..6417de1 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -65,6 +65,7 @@ struct intel_ring_hangcheck { u32 hd; int score; enum intel_ring_hangcheck_action action; + u32 resets; /* Total resets applied to this ring/engine*/ }; struct intel_ring_buffer { diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 848bdaf..764e2af 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -283,6 +283,44 @@ void vlv_force_wake_put(struct drm_i915_private *dev_priv, spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } +void vlv_force_wake_restore(struct drm_i915_private *dev_priv, + int fw_engine) +{ + /* Restore the current force wake state with the hardware + * WARNING: Caller *MUST* hold uncore.lock whilst calling this function + */ + + if (FORCEWAKE_RENDER & fw_engine) { + if (dev_priv->uncore.fw_rendercount + && (__raw_i915_read32(dev_priv, FORCEWAKE_ACK_VLV) + & FORCEWAKE_KERNEL) == 0) + dev_priv->uncore.funcs.force_wake_get(dev_priv, + FORCEWAKE_RENDER); + else if (!dev_priv->uncore.fw_rendercount + && (__raw_i915_read32(dev_priv, FORCEWAKE_ACK_VLV) + & FORCEWAKE_KERNEL) == 1) + dev_priv->uncore.funcs.force_wake_put(dev_priv, + FORCEWAKE_RENDER); + } + + if (FORCEWAKE_MEDIA & fw_engine) { + if (dev_priv->uncore.fw_mediacount + && (__raw_i915_read32(dev_priv, FORCEWAKE_ACK_MEDIA_VLV) + & FORCEWAKE_KERNEL) == 0) + dev_priv->uncore.funcs.force_wake_get(dev_priv, + FORCEWAKE_MEDIA); + else if (!dev_priv->uncore.fw_mediacount + && (__raw_i915_read32(dev_priv, FORCEWAKE_ACK_MEDIA_VLV) + & FORCEWAKE_KERNEL) == 1) + dev_priv->uncore.funcs.force_wake_put(dev_priv, + FORCEWAKE_MEDIA); + } + + dev_priv->uncore.fifo_count = + __raw_i915_read32(dev_priv, GTFIFOCTL) + & GT_FIFO_FREE_ENTRIES_MASK; +} + static void gen6_force_wake_work(struct work_struct *work) { struct drm_i915_private *dev_priv = @@ -397,6 +435,50 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } +void gen6_gt_force_wake_restore(struct drm_i915_private *dev_priv) +{ + /* Restore the current expected force wake state with the + * hardware. This may be required following a reset. + * + * WARNING: Caller *MUST* hold uncore.lock + * + * uncore.lock isn't taken in this function to allow the caller the + * flexibility to do other work immediately before/after + * whilst holding the lock. + */ + struct drm_device *dev = dev_priv->dev; + u32 forcewake_ack; + + if (IS_VALLEYVIEW(dev)) + return vlv_force_wake_restore(dev_priv, FORCEWAKE_ALL); + + if (IS_HASWELL(dev) || IS_GEN8(dev)) + forcewake_ack = FORCEWAKE_ACK_HSW; + else if (IS_IVYBRIDGE(dev) + && (dev_priv->uncore.ecobus & FORCEWAKE_MT_ENABLE)) + forcewake_ack = FORCEWAKE_MT_ACK; + else + forcewake_ack = 0; + + if (dev_priv->uncore.forcewake_count + && (!forcewake_ack + || ((__raw_i915_read32(dev_priv, forcewake_ack) + & FORCEWAKE_KERNEL) == 0))) { + /* It was enabled, so re-enable it */ + dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL); + } else if ((dev_priv->uncore.forcewake_count == 0) + && (!forcewake_ack + || ((__raw_i915_read32(dev_priv, forcewake_ack) + & FORCEWAKE_KERNEL) == 1))) { + /* It was disabled, so disable it */ + dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL); + } + + dev_priv->uncore.fifo_count = + __raw_i915_read32(dev_priv, GTFIFOCTL) + & GT_FIFO_FREE_ENTRIES_MASK; +} + /* We give fast paths for the really cool registers */ #define NEEDS_FORCE_WAKE(dev_priv, reg) \ ((reg) < 0x40000 && (reg) != FORCEWAKE) @@ -661,8 +743,6 @@ void intel_uncore_init(struct drm_device *dev) dev_priv->uncore.funcs.force_wake_get = __gen6_gt_force_wake_mt_get; dev_priv->uncore.funcs.force_wake_put = __gen6_gt_force_wake_mt_put; } else if (IS_IVYBRIDGE(dev)) { - u32 ecobus; - /* IVB configs may use multi-threaded forcewake */ /* A small trick here - if the bios hasn't configured @@ -674,11 +754,11 @@ void intel_uncore_init(struct drm_device *dev) */ mutex_lock(&dev->struct_mutex); __gen6_gt_force_wake_mt_get(dev_priv, FORCEWAKE_ALL); - ecobus = __raw_i915_read32(dev_priv, ECOBUS); + dev_priv->uncore.ecobus = __raw_i915_read32(dev_priv, ECOBUS); __gen6_gt_force_wake_mt_put(dev_priv, FORCEWAKE_ALL); mutex_unlock(&dev->struct_mutex); - if (ecobus & FORCEWAKE_MT_ENABLE) { + if (dev_priv->uncore.ecobus & FORCEWAKE_MT_ENABLE) { dev_priv->uncore.funcs.force_wake_get = __gen6_gt_force_wake_mt_get; dev_priv->uncore.funcs.force_wake_put = @@ -897,16 +977,88 @@ static int gen6_do_reset(struct drm_device *dev) intel_uncore_forcewake_reset(dev); - /* If reset with a user forcewake, try to restore, otherwise turn it off */ - if (dev_priv->uncore.forcewake_count) - dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL); - else - dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL); + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); + return ret; +} + +static int gen6_do_engine_reset(struct drm_device *dev, + enum intel_ring_id engine) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = &dev_priv->ring[engine]; + int ret = -ENODEV; + unsigned long irqflags; + char *reset_event[2]; + reset_event[1] = NULL; - /* Restore fifo count */ - dev_priv->uncore.fifo_count = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK; + DRM_DEBUG_TDR("Engine reset %d\n", engine); + + /* Hold uncore.lock across reset to prevent any register access + * with forcewake not set correctly + */ + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + + ring->hangcheck.resets++; + + /* Reset the engine. + * GEN6_GDRST is not in the gt power well so no need to check + * for fifo space for the write or forcewake the chip for + * the read. + */ + switch (engine) { + case RCS: + __raw_i915_write32(dev_priv, GEN6_GDRST, GEN6_GRDOM_RENDER); + /* Spin waiting for the device to ack the reset request */ + ret = wait_for_atomic((__raw_i915_read32(dev_priv, + GEN6_GDRST) + & GEN6_GRDOM_RENDER) == 0, 500); + DRM_DEBUG_TDR("RCS Reset\n"); + break; + + case BCS: + __raw_i915_write32(dev_priv, GEN6_GDRST, GEN6_GRDOM_BLT); + + /* Spin waiting for the device to ack the reset request */ + ret = wait_for_atomic((__raw_i915_read32(dev_priv, + GEN6_GDRST) + & GEN6_GRDOM_BLT) == 0, 500); + DRM_DEBUG_TDR("BCS Reset\n"); + break; + + case VCS: + __raw_i915_write32(dev_priv, GEN6_GDRST, GEN6_GRDOM_MEDIA); + + /* Spin waiting for the device to ack the reset request */ + ret = wait_for_atomic((__raw_i915_read32(dev_priv, + GEN6_GDRST) + & GEN6_GRDOM_MEDIA) == 0, 500); + DRM_DEBUG_TDR("VCS Reset\n"); + break; + + case VECS: + I915_WRITE_NOTRACE(GEN6_GDRST, GEN6_GRDOM_VEBOX); + + /* Spin waiting for the device to ack the reset request */ + ret = wait_for_atomic((I915_READ_NOTRACE(GEN6_GDRST) + & GEN6_GRDOM_VEBOX) == 0, 500); + DRM_DEBUG_TDR("VECS Reset\n"); + break; + + default: + DRM_ERROR("Unexpected engine\n"); + break; + } + + gen6_gt_force_wake_restore(dev_priv); spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); + + /* Do uevent outside of spinlock as uevent can sleep */ + reset_event[0] = kasprintf(GFP_KERNEL, "RESET RING=%d", engine); + kobject_uevent_env(&dev->primary->kdev->kobj, + KOBJ_CHANGE, reset_event); + kfree(reset_event[0]); + return ret; } @@ -922,6 +1074,29 @@ int intel_gpu_reset(struct drm_device *dev) } } +int intel_gpu_engine_reset(struct drm_device *dev, enum intel_ring_id engine) +{ + /* Reset an individual engine */ + int ret = -ENODEV; + + if (!dev) + return -EINVAL; + + switch (INTEL_INFO(dev)->gen) { + case 7: + case 6: + ret = gen6_do_engine_reset(dev, engine); + break; + default: + DRM_ERROR("Engine reset not supported\n"); + ret = -ENODEV; + break; + } + + return ret; +} + + void intel_uncore_clear_errors(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; -- 1.8.5.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx