@@ -868,6 +868,64 @@ static void intel_init_dpio(struct drm_i915_private *dev_priv)
}
}
+void i915_watchdog_init(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int freq;
+ int i;
+
+ /*
+ * Based on pre-defined time out value (60ms or 30ms) calculate
+ * timer count thresholds needed based on core frequency.
+ *
+ * For RCS.
+ * The timestamp resolution changed in Gen7 and beyond to 80ns
+ * for all pipes. Before that it was 640ns.
+ */
+
+#define KM_RCS_ENGINE_TIMEOUT_VALUE_IN_MS 60
+#define KM_BSD_ENGINE_TIMEOUT_VALUE_IN_MS 60
+#define KM_TIMER_MILLISECOND 1000
+
+ /*
+ * Timestamp timer resolution = 0.080 uSec,
+ * or 12500000 counts per second
+ */
+#define KM_TIMESTAMP_CNTS_PER_SEC_80NS 12500000
+
+ /*
+ * Timestamp timer resolution = 0.640 uSec,
+ * or 1562500 counts per second
+ */
+#define KM_TIMESTAMP_CNTS_PER_SEC_640NS 1562500
+
+ if (INTEL_INFO(dev)->gen >= 7)
+ freq = KM_TIMESTAMP_CNTS_PER_SEC_80NS;
+ else
+ freq = KM_TIMESTAMP_CNTS_PER_SEC_640NS;
+
+ dev_priv->ring[RCS].watchdog_threshold =
+ ((KM_RCS_ENGINE_TIMEOUT_VALUE_IN_MS) *
+ (freq / KM_TIMER_MILLISECOND));
+
+ dev_priv->ring[VCS].watchdog_threshold =
+ ((KM_BSD_ENGINE_TIMEOUT_VALUE_IN_MS) *
+ (freq / KM_TIMER_MILLISECOND));
+
+ dev_priv->ring[VCS2].watchdog_threshold =
+ ((KM_BSD_ENGINE_TIMEOUT_VALUE_IN_MS) *
+ (freq / KM_TIMER_MILLISECOND));
+
+ for (i = 0; i < I915_NUM_RINGS; i++)
+ dev_priv->ring[i].hangcheck.watchdog_count = 0;
+
+ DRM_INFO("Watchdog Timeout [ms], " \
+ "RCS: 0x%08X, VCS: 0x%08X, VCS2: 0x%08X\n", \
+ KM_RCS_ENGINE_TIMEOUT_VALUE_IN_MS,
+ KM_BSD_ENGINE_TIMEOUT_VALUE_IN_MS,
+ KM_BSD_ENGINE_TIMEOUT_VALUE_IN_MS);
+}
+
/**
* i915_driver_load - setup chip and create an initial config
* @dev: DRM device
@@ -1051,6 +1109,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
i915_gem_load(dev);
i915_hangcheck_init(dev);
+ i915_watchdog_init(dev);
/* On the 945G/GM, the chipset reports the MSI capability on the
* integrated graphics even though the support isn't actually there
@@ -2751,6 +2751,7 @@ void intel_hpd_init(struct drm_i915_private *dev_priv);
void intel_hpd_init_work(struct drm_i915_private *dev_priv);
void intel_hpd_cancel_work(struct drm_i915_private *dev_priv);
bool intel_hpd_pin_to_port(enum hpd_pin pin, enum port *port);
+void i915_watchdog_init(struct drm_device *dev);
static inline void i915_hangcheck_reinit(struct intel_engine_cs *engine)
{
struct intel_ring_hangcheck *hc = &engine->hangcheck;
@@ -1325,6 +1325,27 @@ gen8_cs_irq_handler(struct intel_engine_cs *ring, u32 iir, int test_shift)
notify_ring(ring);
if (iir & (GT_CONTEXT_SWITCH_INTERRUPT << test_shift))
intel_lrc_irq_handler(ring);
+ if (iir & (GT_GEN8_RCS_WATCHDOG_INTERRUPT << GEN8_RCS_IRQ_SHIFT)) {
+ struct drm_i915_private *dev_priv = ring->dev->dev_private;
+
+ /* Stop the counter to prevent further interrupts */
+ I915_WRITE(RING_CNTR(ring->mmio_base), GEN6_RCS_WATCHDOG_DISABLE);
+
+ ring->hangcheck.watchdog_count++;
+ i915_handle_error(ring->dev, intel_ring_flag(ring), true, true,
+ "%s watchdog timed out", ring->name);
+ }
+ if (iir & ((GT_GEN8_VCS_WATCHDOG_INTERRUPT << GEN8_VCS1_IRQ_SHIFT) |
+ (GT_GEN8_VCS_WATCHDOG_INTERRUPT << GEN8_VCS2_IRQ_SHIFT))) {
+ struct drm_i915_private *dev_priv = ring->dev->dev_private;
+
+ /* Stop the counter to prevent further interrupts */
+ I915_WRITE(RING_CNTR(ring->mmio_base), GEN8_VCS_WATCHDOG_DISABLE);
+
+ ring->hangcheck.watchdog_count++;
+ i915_handle_error(ring->dev, intel_ring_flag(ring), true, true,
+ "%s watchdog timed out", ring->name);
+ }
}
static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
@@ -3906,11 +3927,14 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
{
/* These are interrupts we'll toggle with the ring mask register */
uint32_t gt_interrupts[] = {
+ GT_GEN8_RCS_WATCHDOG_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
GT_RENDER_L3_PARITY_ERROR_INTERRUPT |
GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT |
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
+ GT_GEN8_VCS_WATCHDOG_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
+ GT_GEN8_VCS_WATCHDOG_INTERRUPT << GEN8_VCS2_IRQ_SHIFT |
GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT |
@@ -1583,6 +1583,8 @@ enum skl_disp_power_wells {
#define RING_RESET_CTL(base) _MMIO((base)+0xd0)
#define RESET_CTL_REQUEST_RESET (1 << 0)
#define RESET_CTL_READY_TO_RESET (1 << 1)
+#define RING_CNTR(base) _MMIO((base)+0x178)
+#define RING_THRESH(base) _MMIO((base)+0x17C)
#define HSW_GTT_CACHE_EN _MMIO(0x4024)
#define GTT_CACHE_EN_ALL 0xF0007FFF
@@ -2008,6 +2010,11 @@ enum skl_disp_power_wells {
#define GT_BSD_USER_INTERRUPT (1 << 12)
#define GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1 (1 << 11) /* hsw+; rsvd on snb, ivb, vlv */
#define GT_CONTEXT_SWITCH_INTERRUPT (1 << 8)
+#define GT_GEN6_RENDER_WATCHDOG_INTERRUPT (1 << 6)
+#define GT_GEN8_RCS_WATCHDOG_INTERRUPT (1 << 6)
+#define GEN6_RCS_WATCHDOG_DISABLE (1)
+#define GT_GEN8_VCS_WATCHDOG_INTERRUPT (1 << 6)
+#define GEN8_VCS_WATCHDOG_DISABLE 0xFFFFFFFF
#define GT_RENDER_L3_PARITY_ERROR_INTERRUPT (1 << 5) /* !snb */
#define GT_RENDER_PIPECTL_NOTIFY_INTERRUPT (1 << 4)
#define GT_RENDER_CS_MASTER_ERROR_INTERRUPT (1 << 3)
@@ -2400,6 +2400,9 @@ static int logical_render_ring_init(struct drm_device *dev)
if (HAS_L3_DPF(dev))
ring->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
+ ring->irq_keep_mask |=
+ (GT_GEN8_RCS_WATCHDOG_INTERRUPT << GEN8_RCS_IRQ_SHIFT);
+
if (INTEL_INFO(dev)->gen >= 9)
ring->init_hw = gen9_init_render_ring;
else
@@ -2460,6 +2463,8 @@ static int logical_bsd_ring_init(struct drm_device *dev)
GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
ring->irq_keep_mask =
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
+ ring->irq_keep_mask |=
+ (GT_GEN8_VCS_WATCHDOG_INTERRUPT << GEN8_VCS1_IRQ_SHIFT);
ring->init_hw = gen8_init_common_ring;
if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
@@ -2494,6 +2499,8 @@ static int logical_bsd2_ring_init(struct drm_device *dev)
GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
ring->irq_keep_mask =
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
+ ring->irq_keep_mask |=
+ (GT_GEN8_VCS_WATCHDOG_INTERRUPT << GEN8_VCS2_IRQ_SHIFT);
ring->init_hw = gen8_init_common_ring;
ring->get_seqno = gen8_get_seqno;
@@ -138,6 +138,9 @@ struct intel_ring_hangcheck {
/* Number of TDR hang detections */
u32 tdr_count;
+
+ /* Number of watchdog hang detections for this ring */
+ u32 watchdog_count;
};
struct intel_ringbuffer {
@@ -366,6 +369,12 @@ struct intel_engine_cs {
/* Saved head value to be restored after reset */
u32 saved_head;
+ /*
+ * Watchdog timer threshold values
+ * only RCS, VCS, VCS2 rings have watchdog timeout support
+ */
+ uint32_t watchdog_threshold;
+
struct {
struct drm_i915_gem_object *obj;
u32 gtt_offset;