|
@@ -888,9 +888,10 @@ static void ivybridge_parity_work(struct work_struct *work)
|
|
|
drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
|
|
|
l3_parity.error_work);
|
|
|
u32 error_status, row, bank, subbank;
|
|
|
- char *parity_event[5];
|
|
|
+ char *parity_event[6];
|
|
|
uint32_t misccpctl;
|
|
|
unsigned long flags;
|
|
|
+ uint8_t slice = 0;
|
|
|
|
|
|
/* We must turn off DOP level clock gating to access the L3 registers.
|
|
|
* In order to prevent a get/put style interface, acquire struct mutex
|
|
@@ -898,45 +899,64 @@ static void ivybridge_parity_work(struct work_struct *work)
|
|
|
*/
|
|
|
mutex_lock(&dev_priv->dev->struct_mutex);
|
|
|
|
|
|
+ /* If we've screwed up tracking, just let the interrupt fire again */
|
|
|
+ if (WARN_ON(!dev_priv->l3_parity.which_slice))
|
|
|
+ goto out;
|
|
|
+
|
|
|
misccpctl = I915_READ(GEN7_MISCCPCTL);
|
|
|
I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
|
|
|
POSTING_READ(GEN7_MISCCPCTL);
|
|
|
|
|
|
- error_status = I915_READ(GEN7_L3CDERRST1);
|
|
|
- row = GEN7_PARITY_ERROR_ROW(error_status);
|
|
|
- bank = GEN7_PARITY_ERROR_BANK(error_status);
|
|
|
- subbank = GEN7_PARITY_ERROR_SUBBANK(error_status);
|
|
|
+ while ((slice = ffs(dev_priv->l3_parity.which_slice)) != 0) {
|
|
|
+ u32 reg;
|
|
|
|
|
|
- I915_WRITE(GEN7_L3CDERRST1, GEN7_PARITY_ERROR_VALID |
|
|
|
- GEN7_L3CDERRST1_ENABLE);
|
|
|
- POSTING_READ(GEN7_L3CDERRST1);
|
|
|
+ slice--;
|
|
|
+ if (WARN_ON_ONCE(slice >= NUM_L3_SLICES(dev_priv->dev)))
|
|
|
+ break;
|
|
|
|
|
|
- I915_WRITE(GEN7_MISCCPCTL, misccpctl);
|
|
|
+ dev_priv->l3_parity.which_slice &= ~(1<<slice);
|
|
|
|
|
|
- spin_lock_irqsave(&dev_priv->irq_lock, flags);
|
|
|
- ilk_enable_gt_irq(dev_priv, GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
|
|
|
- spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
|
|
|
+ reg = GEN7_L3CDERRST1 + (slice * 0x200);
|
|
|
|
|
|
- mutex_unlock(&dev_priv->dev->struct_mutex);
|
|
|
+ error_status = I915_READ(reg);
|
|
|
+ row = GEN7_PARITY_ERROR_ROW(error_status);
|
|
|
+ bank = GEN7_PARITY_ERROR_BANK(error_status);
|
|
|
+ subbank = GEN7_PARITY_ERROR_SUBBANK(error_status);
|
|
|
+
|
|
|
+ I915_WRITE(reg, GEN7_PARITY_ERROR_VALID | GEN7_L3CDERRST1_ENABLE);
|
|
|
+ POSTING_READ(reg);
|
|
|
+
|
|
|
+ parity_event[0] = I915_L3_PARITY_UEVENT "=1";
|
|
|
+ parity_event[1] = kasprintf(GFP_KERNEL, "ROW=%d", row);
|
|
|
+ parity_event[2] = kasprintf(GFP_KERNEL, "BANK=%d", bank);
|
|
|
+ parity_event[3] = kasprintf(GFP_KERNEL, "SUBBANK=%d", subbank);
|
|
|
+ parity_event[4] = kasprintf(GFP_KERNEL, "SLICE=%d", slice);
|
|
|
+ parity_event[5] = NULL;
|
|
|
+
|
|
|
+ kobject_uevent_env(&dev_priv->dev->primary->kdev.kobj,
|
|
|
+ KOBJ_CHANGE, parity_event);
|
|
|
|
|
|
- parity_event[0] = I915_L3_PARITY_UEVENT "=1";
|
|
|
- parity_event[1] = kasprintf(GFP_KERNEL, "ROW=%d", row);
|
|
|
- parity_event[2] = kasprintf(GFP_KERNEL, "BANK=%d", bank);
|
|
|
- parity_event[3] = kasprintf(GFP_KERNEL, "SUBBANK=%d", subbank);
|
|
|
- parity_event[4] = NULL;
|
|
|
+ DRM_DEBUG("Parity error: Slice = %d, Row = %d, Bank = %d, Sub bank = %d.\n",
|
|
|
+ slice, row, bank, subbank);
|
|
|
|
|
|
- kobject_uevent_env(&dev_priv->dev->primary->kdev.kobj,
|
|
|
- KOBJ_CHANGE, parity_event);
|
|
|
+ kfree(parity_event[4]);
|
|
|
+ kfree(parity_event[3]);
|
|
|
+ kfree(parity_event[2]);
|
|
|
+ kfree(parity_event[1]);
|
|
|
+ }
|
|
|
|
|
|
- DRM_DEBUG("Parity error: Row = %d, Bank = %d, Sub bank = %d.\n",
|
|
|
- row, bank, subbank);
|
|
|
+ I915_WRITE(GEN7_MISCCPCTL, misccpctl);
|
|
|
|
|
|
- kfree(parity_event[3]);
|
|
|
- kfree(parity_event[2]);
|
|
|
- kfree(parity_event[1]);
|
|
|
+out:
|
|
|
+ WARN_ON(dev_priv->l3_parity.which_slice);
|
|
|
+ spin_lock_irqsave(&dev_priv->irq_lock, flags);
|
|
|
+ ilk_enable_gt_irq(dev_priv, GT_PARITY_ERROR(dev_priv->dev));
|
|
|
+ spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
|
|
|
+
|
|
|
+ mutex_unlock(&dev_priv->dev->struct_mutex);
|
|
|
}
|
|
|
|
|
|
-static void ivybridge_parity_error_irq_handler(struct drm_device *dev)
|
|
|
+static void ivybridge_parity_error_irq_handler(struct drm_device *dev, u32 iir)
|
|
|
{
|
|
|
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
|
|
|
|
@@ -944,9 +964,16 @@ static void ivybridge_parity_error_irq_handler(struct drm_device *dev)
|
|
|
return;
|
|
|
|
|
|
spin_lock(&dev_priv->irq_lock);
|
|
|
- ilk_disable_gt_irq(dev_priv, GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
|
|
|
+ ilk_disable_gt_irq(dev_priv, GT_PARITY_ERROR(dev));
|
|
|
spin_unlock(&dev_priv->irq_lock);
|
|
|
|
|
|
+ iir &= GT_PARITY_ERROR(dev);
|
|
|
+ if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1)
|
|
|
+ dev_priv->l3_parity.which_slice |= 1 << 1;
|
|
|
+
|
|
|
+ if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT)
|
|
|
+ dev_priv->l3_parity.which_slice |= 1 << 0;
|
|
|
+
|
|
|
queue_work(dev_priv->wq, &dev_priv->l3_parity.error_work);
|
|
|
}
|
|
|
|
|
@@ -981,8 +1008,8 @@ static void snb_gt_irq_handler(struct drm_device *dev,
|
|
|
i915_handle_error(dev, false);
|
|
|
}
|
|
|
|
|
|
- if (gt_iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT)
|
|
|
- ivybridge_parity_error_irq_handler(dev);
|
|
|
+ if (gt_iir & GT_PARITY_ERROR(dev))
|
|
|
+ ivybridge_parity_error_irq_handler(dev, gt_iir);
|
|
|
}
|
|
|
|
|
|
#define HPD_STORM_DETECT_PERIOD 1000
|
|
@@ -2221,8 +2248,8 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
|
|
|
dev_priv->gt_irq_mask = ~0;
|
|
|
if (HAS_L3_GPU_CACHE(dev)) {
|
|
|
/* L3 parity interrupt is always unmasked. */
|
|
|
- dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
|
|
|
- gt_irqs |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
|
|
|
+ dev_priv->gt_irq_mask = ~GT_PARITY_ERROR(dev);
|
|
|
+ gt_irqs |= GT_PARITY_ERROR(dev);
|
|
|
}
|
|
|
|
|
|
gt_irqs |= GT_RENDER_USER_INTERRUPT;
|