|
@@ -126,7 +126,7 @@ static const u32 hpd_bxt[HPD_NUM_PINS] = {
|
|
|
POSTING_READ(GEN8_##type##_IIR(which)); \
|
|
|
} while (0)
|
|
|
|
|
|
-#define GEN5_IRQ_RESET(type) do { \
|
|
|
+#define GEN3_IRQ_RESET(type) do { \
|
|
|
I915_WRITE(type##IMR, 0xffffffff); \
|
|
|
POSTING_READ(type##IMR); \
|
|
|
I915_WRITE(type##IER, 0); \
|
|
@@ -136,10 +136,20 @@ static const u32 hpd_bxt[HPD_NUM_PINS] = {
|
|
|
POSTING_READ(type##IIR); \
|
|
|
} while (0)
|
|
|
|
|
|
+#define GEN2_IRQ_RESET(type) do { \
|
|
|
+ I915_WRITE16(type##IMR, 0xffff); \
|
|
|
+ POSTING_READ16(type##IMR); \
|
|
|
+ I915_WRITE16(type##IER, 0); \
|
|
|
+ I915_WRITE16(type##IIR, 0xffff); \
|
|
|
+ POSTING_READ16(type##IIR); \
|
|
|
+ I915_WRITE16(type##IIR, 0xffff); \
|
|
|
+ POSTING_READ16(type##IIR); \
|
|
|
+} while (0)
|
|
|
+
|
|
|
/*
|
|
|
* We should clear IMR at preinstall/uninstall, and just check at postinstall.
|
|
|
*/
|
|
|
-static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv,
|
|
|
+static void gen3_assert_iir_is_zero(struct drm_i915_private *dev_priv,
|
|
|
i915_reg_t reg)
|
|
|
{
|
|
|
u32 val = I915_READ(reg);
|
|
@@ -155,20 +165,43 @@ static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv,
|
|
|
POSTING_READ(reg);
|
|
|
}
|
|
|
|
|
|
+static void gen2_assert_iir_is_zero(struct drm_i915_private *dev_priv,
|
|
|
+ i915_reg_t reg)
|
|
|
+{
|
|
|
+ u16 val = I915_READ16(reg);
|
|
|
+
|
|
|
+ if (val == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ WARN(1, "Interrupt register 0x%x is not zero: 0x%08x\n",
|
|
|
+ i915_mmio_reg_offset(reg), val);
|
|
|
+ I915_WRITE16(reg, 0xffff);
|
|
|
+ POSTING_READ16(reg);
|
|
|
+ I915_WRITE16(reg, 0xffff);
|
|
|
+ POSTING_READ16(reg);
|
|
|
+}
|
|
|
+
|
|
|
#define GEN8_IRQ_INIT_NDX(type, which, imr_val, ier_val) do { \
|
|
|
- gen5_assert_iir_is_zero(dev_priv, GEN8_##type##_IIR(which)); \
|
|
|
+ gen3_assert_iir_is_zero(dev_priv, GEN8_##type##_IIR(which)); \
|
|
|
I915_WRITE(GEN8_##type##_IER(which), (ier_val)); \
|
|
|
I915_WRITE(GEN8_##type##_IMR(which), (imr_val)); \
|
|
|
POSTING_READ(GEN8_##type##_IMR(which)); \
|
|
|
} while (0)
|
|
|
|
|
|
-#define GEN5_IRQ_INIT(type, imr_val, ier_val) do { \
|
|
|
- gen5_assert_iir_is_zero(dev_priv, type##IIR); \
|
|
|
+#define GEN3_IRQ_INIT(type, imr_val, ier_val) do { \
|
|
|
+ gen3_assert_iir_is_zero(dev_priv, type##IIR); \
|
|
|
I915_WRITE(type##IER, (ier_val)); \
|
|
|
I915_WRITE(type##IMR, (imr_val)); \
|
|
|
POSTING_READ(type##IMR); \
|
|
|
} while (0)
|
|
|
|
|
|
+#define GEN2_IRQ_INIT(type, imr_val, ier_val) do { \
|
|
|
+ gen2_assert_iir_is_zero(dev_priv, type##IIR); \
|
|
|
+ I915_WRITE16(type##IER, (ier_val)); \
|
|
|
+ I915_WRITE16(type##IMR, (imr_val)); \
|
|
|
+ POSTING_READ16(type##IMR); \
|
|
|
+} while (0)
|
|
|
+
|
|
|
static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir);
|
|
|
static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir);
|
|
|
|
|
@@ -534,62 +567,16 @@ void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
|
|
|
POSTING_READ(SDEIMR);
|
|
|
}
|
|
|
|
|
|
-static void
|
|
|
-__i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
|
|
|
- u32 enable_mask, u32 status_mask)
|
|
|
+u32 i915_pipestat_enable_mask(struct drm_i915_private *dev_priv,
|
|
|
+ enum pipe pipe)
|
|
|
{
|
|
|
- i915_reg_t reg = PIPESTAT(pipe);
|
|
|
- u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK;
|
|
|
-
|
|
|
- lockdep_assert_held(&dev_priv->irq_lock);
|
|
|
- WARN_ON(!intel_irqs_enabled(dev_priv));
|
|
|
-
|
|
|
- if (WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
|
|
|
- status_mask & ~PIPESTAT_INT_STATUS_MASK,
|
|
|
- "pipe %c: enable_mask=0x%x, status_mask=0x%x\n",
|
|
|
- pipe_name(pipe), enable_mask, status_mask))
|
|
|
- return;
|
|
|
-
|
|
|
- if ((pipestat & enable_mask) == enable_mask)
|
|
|
- return;
|
|
|
-
|
|
|
- dev_priv->pipestat_irq_mask[pipe] |= status_mask;
|
|
|
-
|
|
|
- /* Enable the interrupt, clear any pending status */
|
|
|
- pipestat |= enable_mask | status_mask;
|
|
|
- I915_WRITE(reg, pipestat);
|
|
|
- POSTING_READ(reg);
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-__i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
|
|
|
- u32 enable_mask, u32 status_mask)
|
|
|
-{
|
|
|
- i915_reg_t reg = PIPESTAT(pipe);
|
|
|
- u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK;
|
|
|
+ u32 status_mask = dev_priv->pipestat_irq_mask[pipe];
|
|
|
+ u32 enable_mask = status_mask << 16;
|
|
|
|
|
|
lockdep_assert_held(&dev_priv->irq_lock);
|
|
|
- WARN_ON(!intel_irqs_enabled(dev_priv));
|
|
|
-
|
|
|
- if (WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
|
|
|
- status_mask & ~PIPESTAT_INT_STATUS_MASK,
|
|
|
- "pipe %c: enable_mask=0x%x, status_mask=0x%x\n",
|
|
|
- pipe_name(pipe), enable_mask, status_mask))
|
|
|
- return;
|
|
|
-
|
|
|
- if ((pipestat & enable_mask) == 0)
|
|
|
- return;
|
|
|
-
|
|
|
- dev_priv->pipestat_irq_mask[pipe] &= ~status_mask;
|
|
|
|
|
|
- pipestat &= ~enable_mask;
|
|
|
- I915_WRITE(reg, pipestat);
|
|
|
- POSTING_READ(reg);
|
|
|
-}
|
|
|
-
|
|
|
-static u32 vlv_get_pipestat_enable_mask(struct drm_device *dev, u32 status_mask)
|
|
|
-{
|
|
|
- u32 enable_mask = status_mask << 16;
|
|
|
+ if (INTEL_GEN(dev_priv) < 5)
|
|
|
+ goto out;
|
|
|
|
|
|
/*
|
|
|
* On pipe A we don't support the PSR interrupt yet,
|
|
@@ -612,35 +599,59 @@ static u32 vlv_get_pipestat_enable_mask(struct drm_device *dev, u32 status_mask)
|
|
|
if (status_mask & SPRITE1_FLIP_DONE_INT_STATUS_VLV)
|
|
|
enable_mask |= SPRITE1_FLIP_DONE_INT_EN_VLV;
|
|
|
|
|
|
+out:
|
|
|
+ WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
|
|
|
+ status_mask & ~PIPESTAT_INT_STATUS_MASK,
|
|
|
+ "pipe %c: enable_mask=0x%x, status_mask=0x%x\n",
|
|
|
+ pipe_name(pipe), enable_mask, status_mask);
|
|
|
+
|
|
|
return enable_mask;
|
|
|
}
|
|
|
|
|
|
-void
|
|
|
-i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
|
|
|
- u32 status_mask)
|
|
|
+void i915_enable_pipestat(struct drm_i915_private *dev_priv,
|
|
|
+ enum pipe pipe, u32 status_mask)
|
|
|
{
|
|
|
+ i915_reg_t reg = PIPESTAT(pipe);
|
|
|
u32 enable_mask;
|
|
|
|
|
|
- if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
|
|
|
- enable_mask = vlv_get_pipestat_enable_mask(&dev_priv->drm,
|
|
|
- status_mask);
|
|
|
- else
|
|
|
- enable_mask = status_mask << 16;
|
|
|
- __i915_enable_pipestat(dev_priv, pipe, enable_mask, status_mask);
|
|
|
+ WARN_ONCE(status_mask & ~PIPESTAT_INT_STATUS_MASK,
|
|
|
+ "pipe %c: status_mask=0x%x\n",
|
|
|
+ pipe_name(pipe), status_mask);
|
|
|
+
|
|
|
+ lockdep_assert_held(&dev_priv->irq_lock);
|
|
|
+ WARN_ON(!intel_irqs_enabled(dev_priv));
|
|
|
+
|
|
|
+ if ((dev_priv->pipestat_irq_mask[pipe] & status_mask) == status_mask)
|
|
|
+ return;
|
|
|
+
|
|
|
+ dev_priv->pipestat_irq_mask[pipe] |= status_mask;
|
|
|
+ enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
|
|
|
+
|
|
|
+ I915_WRITE(reg, enable_mask | status_mask);
|
|
|
+ POSTING_READ(reg);
|
|
|
}
|
|
|
|
|
|
-void
|
|
|
-i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
|
|
|
- u32 status_mask)
|
|
|
+void i915_disable_pipestat(struct drm_i915_private *dev_priv,
|
|
|
+ enum pipe pipe, u32 status_mask)
|
|
|
{
|
|
|
+ i915_reg_t reg = PIPESTAT(pipe);
|
|
|
u32 enable_mask;
|
|
|
|
|
|
- if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
|
|
|
- enable_mask = vlv_get_pipestat_enable_mask(&dev_priv->drm,
|
|
|
- status_mask);
|
|
|
- else
|
|
|
- enable_mask = status_mask << 16;
|
|
|
- __i915_disable_pipestat(dev_priv, pipe, enable_mask, status_mask);
|
|
|
+ WARN_ONCE(status_mask & ~PIPESTAT_INT_STATUS_MASK,
|
|
|
+ "pipe %c: status_mask=0x%x\n",
|
|
|
+ pipe_name(pipe), status_mask);
|
|
|
+
|
|
|
+ lockdep_assert_held(&dev_priv->irq_lock);
|
|
|
+ WARN_ON(!intel_irqs_enabled(dev_priv));
|
|
|
+
|
|
|
+ if ((dev_priv->pipestat_irq_mask[pipe] & status_mask) == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ dev_priv->pipestat_irq_mask[pipe] &= ~status_mask;
|
|
|
+ enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
|
|
|
+
|
|
|
+ I915_WRITE(reg, enable_mask | status_mask);
|
|
|
+ POSTING_READ(reg);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -772,6 +783,57 @@ static u32 g4x_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
|
|
|
return I915_READ(PIPE_FRMCOUNT_G4X(pipe));
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * On certain encoders on certain platforms, pipe
|
|
|
+ * scanline register will not work to get the scanline,
|
|
|
+ * since the timings are driven from the PORT or issues
|
|
|
+ * with scanline register updates.
|
|
|
+ * This function will use Framestamp and current
|
|
|
+ * timestamp registers to calculate the scanline.
|
|
|
+ */
|
|
|
+static u32 __intel_get_crtc_scanline_from_timestamp(struct intel_crtc *crtc)
|
|
|
+{
|
|
|
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
|
|
+ struct drm_vblank_crtc *vblank =
|
|
|
+ &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
|
|
|
+ const struct drm_display_mode *mode = &vblank->hwmode;
|
|
|
+ u32 vblank_start = mode->crtc_vblank_start;
|
|
|
+ u32 vtotal = mode->crtc_vtotal;
|
|
|
+ u32 htotal = mode->crtc_htotal;
|
|
|
+ u32 clock = mode->crtc_clock;
|
|
|
+ u32 scanline, scan_prev_time, scan_curr_time, scan_post_time;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * To avoid the race condition where we might cross into the
|
|
|
+ * next vblank just between the PIPE_FRMTMSTMP and TIMESTAMP_CTR
|
|
|
+ * reads. We make sure we read PIPE_FRMTMSTMP and TIMESTAMP_CTR
|
|
|
+ * during the same frame.
|
|
|
+ */
|
|
|
+ do {
|
|
|
+ /*
|
|
|
+ * This field provides read back of the display
|
|
|
+ * pipe frame time stamp. The time stamp value
|
|
|
+ * is sampled at every start of vertical blank.
|
|
|
+ */
|
|
|
+ scan_prev_time = I915_READ_FW(PIPE_FRMTMSTMP(crtc->pipe));
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The TIMESTAMP_CTR register has the current
|
|
|
+ * time stamp value.
|
|
|
+ */
|
|
|
+ scan_curr_time = I915_READ_FW(IVB_TIMESTAMP_CTR);
|
|
|
+
|
|
|
+ scan_post_time = I915_READ_FW(PIPE_FRMTMSTMP(crtc->pipe));
|
|
|
+ } while (scan_post_time != scan_prev_time);
|
|
|
+
|
|
|
+ scanline = div_u64(mul_u32_u32(scan_curr_time - scan_prev_time,
|
|
|
+ clock), 1000 * htotal);
|
|
|
+ scanline = min(scanline, vtotal - 1);
|
|
|
+ scanline = (scanline + vblank_start) % vtotal;
|
|
|
+
|
|
|
+ return scanline;
|
|
|
+}
|
|
|
+
|
|
|
/* I915_READ_FW, only for fast reads of display block, no need for forcewake etc. */
|
|
|
static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
|
|
|
{
|
|
@@ -788,6 +850,9 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
|
|
|
vblank = &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
|
|
|
mode = &vblank->hwmode;
|
|
|
|
|
|
+ if (mode->private_flags & I915_MODE_FLAG_GET_SCANLINE_FROM_TIMESTAMP)
|
|
|
+ return __intel_get_crtc_scanline_from_timestamp(crtc);
|
|
|
+
|
|
|
vtotal = mode->crtc_vtotal;
|
|
|
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
|
|
vtotal /= 2;
|
|
@@ -1005,6 +1070,8 @@ static void notify_ring(struct intel_engine_cs *engine)
|
|
|
spin_lock(&engine->breadcrumbs.irq_lock);
|
|
|
wait = engine->breadcrumbs.irq_wait;
|
|
|
if (wait) {
|
|
|
+ bool wakeup = engine->irq_seqno_barrier;
|
|
|
+
|
|
|
/* We use a callback from the dma-fence to submit
|
|
|
* requests after waiting on our own requests. To
|
|
|
* ensure minimum delay in queuing the next request to
|
|
@@ -1017,12 +1084,18 @@ static void notify_ring(struct intel_engine_cs *engine)
|
|
|
* and many waiters.
|
|
|
*/
|
|
|
if (i915_seqno_passed(intel_engine_get_seqno(engine),
|
|
|
- wait->seqno) &&
|
|
|
- !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
|
|
|
- &wait->request->fence.flags))
|
|
|
- rq = i915_gem_request_get(wait->request);
|
|
|
+ wait->seqno)) {
|
|
|
+ struct drm_i915_gem_request *waiter = wait->request;
|
|
|
+
|
|
|
+ wakeup = true;
|
|
|
+ if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
|
|
|
+ &waiter->fence.flags) &&
|
|
|
+ intel_wait_check_request(wait, waiter))
|
|
|
+ rq = i915_gem_request_get(waiter);
|
|
|
+ }
|
|
|
|
|
|
- wake_up_process(wait->tsk);
|
|
|
+ if (wakeup)
|
|
|
+ wake_up_process(wait->tsk);
|
|
|
} else {
|
|
|
__intel_engine_disarm_breadcrumbs(engine);
|
|
|
}
|
|
@@ -1305,10 +1378,11 @@ static void snb_gt_irq_handler(struct drm_i915_private *dev_priv,
|
|
|
static void
|
|
|
gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir, int test_shift)
|
|
|
{
|
|
|
+ struct intel_engine_execlists * const execlists = &engine->execlists;
|
|
|
bool tasklet = false;
|
|
|
|
|
|
if (iir & (GT_CONTEXT_SWITCH_INTERRUPT << test_shift)) {
|
|
|
- if (port_count(&engine->execlist_port[0])) {
|
|
|
+ if (port_count(&execlists->port[0])) {
|
|
|
__set_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted);
|
|
|
tasklet = true;
|
|
|
}
|
|
@@ -1316,11 +1390,11 @@ gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir, int test_shift)
|
|
|
|
|
|
if (iir & (GT_RENDER_USER_INTERRUPT << test_shift)) {
|
|
|
notify_ring(engine);
|
|
|
- tasklet |= i915.enable_guc_submission;
|
|
|
+ tasklet |= i915_modparams.enable_guc_submission;
|
|
|
}
|
|
|
|
|
|
if (tasklet)
|
|
|
- tasklet_hi_schedule(&engine->irq_tasklet);
|
|
|
+ tasklet_hi_schedule(&execlists->irq_tasklet);
|
|
|
}
|
|
|
|
|
|
static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv,
|
|
@@ -1573,11 +1647,11 @@ static void display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
|
|
|
* bonkers. So let's just wait for the next vblank and read
|
|
|
* out the buggy result.
|
|
|
*
|
|
|
- * On CHV sometimes the second CRC is bonkers as well, so
|
|
|
+ * On GEN8+ sometimes the second CRC is bonkers as well, so
|
|
|
* don't trust that one either.
|
|
|
*/
|
|
|
if (pipe_crc->skipped == 0 ||
|
|
|
- (IS_CHERRYVIEW(dev_priv) && pipe_crc->skipped == 1)) {
|
|
|
+ (INTEL_GEN(dev_priv) >= 8 && pipe_crc->skipped == 1)) {
|
|
|
pipe_crc->skipped++;
|
|
|
spin_unlock(&pipe_crc->lock);
|
|
|
return;
|
|
@@ -1706,8 +1780,21 @@ static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv,
|
|
|
- u32 iir, u32 pipe_stats[I915_MAX_PIPES])
|
|
|
+static void i9xx_pipestat_irq_reset(struct drm_i915_private *dev_priv)
|
|
|
+{
|
|
|
+ enum pipe pipe;
|
|
|
+
|
|
|
+ for_each_pipe(dev_priv, pipe) {
|
|
|
+ I915_WRITE(PIPESTAT(pipe),
|
|
|
+ PIPESTAT_INT_STATUS_MASK |
|
|
|
+ PIPE_FIFO_UNDERRUN_STATUS);
|
|
|
+
|
|
|
+ dev_priv->pipestat_irq_mask[pipe] = 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void i9xx_pipestat_irq_ack(struct drm_i915_private *dev_priv,
|
|
|
+ u32 iir, u32 pipe_stats[I915_MAX_PIPES])
|
|
|
{
|
|
|
int pipe;
|
|
|
|
|
@@ -1720,7 +1807,7 @@ static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv,
|
|
|
|
|
|
for_each_pipe(dev_priv, pipe) {
|
|
|
i915_reg_t reg;
|
|
|
- u32 mask, iir_bit = 0;
|
|
|
+ u32 status_mask, enable_mask, iir_bit = 0;
|
|
|
|
|
|
/*
|
|
|
* PIPESTAT bits get signalled even when the interrupt is
|
|
@@ -1731,7 +1818,7 @@ static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv,
|
|
|
*/
|
|
|
|
|
|
/* fifo underruns are filterered in the underrun handler. */
|
|
|
- mask = PIPE_FIFO_UNDERRUN_STATUS;
|
|
|
+ status_mask = PIPE_FIFO_UNDERRUN_STATUS;
|
|
|
|
|
|
switch (pipe) {
|
|
|
case PIPE_A:
|
|
@@ -1745,25 +1832,92 @@ static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv,
|
|
|
break;
|
|
|
}
|
|
|
if (iir & iir_bit)
|
|
|
- mask |= dev_priv->pipestat_irq_mask[pipe];
|
|
|
+ status_mask |= dev_priv->pipestat_irq_mask[pipe];
|
|
|
|
|
|
- if (!mask)
|
|
|
+ if (!status_mask)
|
|
|
continue;
|
|
|
|
|
|
reg = PIPESTAT(pipe);
|
|
|
- mask |= PIPESTAT_INT_ENABLE_MASK;
|
|
|
- pipe_stats[pipe] = I915_READ(reg) & mask;
|
|
|
+ pipe_stats[pipe] = I915_READ(reg) & status_mask;
|
|
|
+ enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
|
|
|
|
|
|
/*
|
|
|
* Clear the PIPE*STAT regs before the IIR
|
|
|
*/
|
|
|
- if (pipe_stats[pipe] & (PIPE_FIFO_UNDERRUN_STATUS |
|
|
|
- PIPESTAT_INT_STATUS_MASK))
|
|
|
- I915_WRITE(reg, pipe_stats[pipe]);
|
|
|
+ if (pipe_stats[pipe])
|
|
|
+ I915_WRITE(reg, enable_mask | pipe_stats[pipe]);
|
|
|
}
|
|
|
spin_unlock(&dev_priv->irq_lock);
|
|
|
}
|
|
|
|
|
|
+static void i8xx_pipestat_irq_handler(struct drm_i915_private *dev_priv,
|
|
|
+ u16 iir, u32 pipe_stats[I915_MAX_PIPES])
|
|
|
+{
|
|
|
+ enum pipe pipe;
|
|
|
+
|
|
|
+ for_each_pipe(dev_priv, pipe) {
|
|
|
+ if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
|
|
|
+ drm_handle_vblank(&dev_priv->drm, pipe);
|
|
|
+
|
|
|
+ if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
|
|
|
+ i9xx_pipe_crc_irq_handler(dev_priv, pipe);
|
|
|
+
|
|
|
+ if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
|
|
|
+ intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void i915_pipestat_irq_handler(struct drm_i915_private *dev_priv,
|
|
|
+ u32 iir, u32 pipe_stats[I915_MAX_PIPES])
|
|
|
+{
|
|
|
+ bool blc_event = false;
|
|
|
+ enum pipe pipe;
|
|
|
+
|
|
|
+ for_each_pipe(dev_priv, pipe) {
|
|
|
+ if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
|
|
|
+ drm_handle_vblank(&dev_priv->drm, pipe);
|
|
|
+
|
|
|
+ if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
|
|
|
+ blc_event = true;
|
|
|
+
|
|
|
+ if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
|
|
|
+ i9xx_pipe_crc_irq_handler(dev_priv, pipe);
|
|
|
+
|
|
|
+ if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
|
|
|
+ intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (blc_event || (iir & I915_ASLE_INTERRUPT))
|
|
|
+ intel_opregion_asle_intr(dev_priv);
|
|
|
+}
|
|
|
+
|
|
|
+static void i965_pipestat_irq_handler(struct drm_i915_private *dev_priv,
|
|
|
+ u32 iir, u32 pipe_stats[I915_MAX_PIPES])
|
|
|
+{
|
|
|
+ bool blc_event = false;
|
|
|
+ enum pipe pipe;
|
|
|
+
|
|
|
+ for_each_pipe(dev_priv, pipe) {
|
|
|
+ if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
|
|
|
+ drm_handle_vblank(&dev_priv->drm, pipe);
|
|
|
+
|
|
|
+ if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
|
|
|
+ blc_event = true;
|
|
|
+
|
|
|
+ if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
|
|
|
+ i9xx_pipe_crc_irq_handler(dev_priv, pipe);
|
|
|
+
|
|
|
+ if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
|
|
|
+ intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (blc_event || (iir & I915_ASLE_INTERRUPT))
|
|
|
+ intel_opregion_asle_intr(dev_priv);
|
|
|
+
|
|
|
+ if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
|
|
|
+ gmbus_irq_handler(dev_priv);
|
|
|
+}
|
|
|
+
|
|
|
static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv,
|
|
|
u32 pipe_stats[I915_MAX_PIPES])
|
|
|
{
|
|
@@ -1879,7 +2033,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
|
|
|
|
|
|
/* Call regardless, as some status bits might not be
|
|
|
* signalled in iir */
|
|
|
- valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats);
|
|
|
+ i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
|
|
|
|
|
|
if (iir & (I915_LPE_PIPE_A_INTERRUPT |
|
|
|
I915_LPE_PIPE_B_INTERRUPT))
|
|
@@ -1963,7 +2117,7 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
|
|
|
|
|
|
/* Call regardless, as some status bits might not be
|
|
|
* signalled in iir */
|
|
|
- valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats);
|
|
|
+ i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
|
|
|
|
|
|
if (iir & (I915_LPE_PIPE_A_INTERRUPT |
|
|
|
I915_LPE_PIPE_B_INTERRUPT |
|
|
@@ -2860,7 +3014,7 @@ static void ibx_irq_reset(struct drm_i915_private *dev_priv)
|
|
|
if (HAS_PCH_NOP(dev_priv))
|
|
|
return;
|
|
|
|
|
|
- GEN5_IRQ_RESET(SDE);
|
|
|
+ GEN3_IRQ_RESET(SDE);
|
|
|
|
|
|
if (HAS_PCH_CPT(dev_priv) || HAS_PCH_LPT(dev_priv))
|
|
|
I915_WRITE(SERR_INT, 0xffffffff);
|
|
@@ -2888,15 +3042,13 @@ static void ibx_irq_pre_postinstall(struct drm_device *dev)
|
|
|
|
|
|
static void gen5_gt_irq_reset(struct drm_i915_private *dev_priv)
|
|
|
{
|
|
|
- GEN5_IRQ_RESET(GT);
|
|
|
+ GEN3_IRQ_RESET(GT);
|
|
|
if (INTEL_GEN(dev_priv) >= 6)
|
|
|
- GEN5_IRQ_RESET(GEN6_PM);
|
|
|
+ GEN3_IRQ_RESET(GEN6_PM);
|
|
|
}
|
|
|
|
|
|
static void vlv_display_irq_reset(struct drm_i915_private *dev_priv)
|
|
|
{
|
|
|
- enum pipe pipe;
|
|
|
-
|
|
|
if (IS_CHERRYVIEW(dev_priv))
|
|
|
I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK_CHV);
|
|
|
else
|
|
@@ -2905,14 +3057,9 @@ static void vlv_display_irq_reset(struct drm_i915_private *dev_priv)
|
|
|
i915_hotplug_interrupt_update_locked(dev_priv, 0xffffffff, 0);
|
|
|
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
|
|
|
|
|
|
- for_each_pipe(dev_priv, pipe) {
|
|
|
- I915_WRITE(PIPESTAT(pipe),
|
|
|
- PIPE_FIFO_UNDERRUN_STATUS |
|
|
|
- PIPESTAT_INT_STATUS_MASK);
|
|
|
- dev_priv->pipestat_irq_mask[pipe] = 0;
|
|
|
- }
|
|
|
+ i9xx_pipestat_irq_reset(dev_priv);
|
|
|
|
|
|
- GEN5_IRQ_RESET(VLV_);
|
|
|
+ GEN3_IRQ_RESET(VLV_);
|
|
|
dev_priv->irq_mask = ~0;
|
|
|
}
|
|
|
|
|
@@ -2922,8 +3069,7 @@ static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv)
|
|
|
u32 enable_mask;
|
|
|
enum pipe pipe;
|
|
|
|
|
|
- pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV |
|
|
|
- PIPE_CRC_DONE_INTERRUPT_STATUS;
|
|
|
+ pipestat_mask = PIPE_CRC_DONE_INTERRUPT_STATUS;
|
|
|
|
|
|
i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
|
|
|
for_each_pipe(dev_priv, pipe)
|
|
@@ -2943,7 +3089,7 @@ static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv)
|
|
|
|
|
|
dev_priv->irq_mask = ~enable_mask;
|
|
|
|
|
|
- GEN5_IRQ_INIT(VLV_, dev_priv->irq_mask, enable_mask);
|
|
|
+ GEN3_IRQ_INIT(VLV_, dev_priv->irq_mask, enable_mask);
|
|
|
}
|
|
|
|
|
|
/* drm_dma.h hooks
|
|
@@ -2952,9 +3098,10 @@ static void ironlake_irq_reset(struct drm_device *dev)
|
|
|
{
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
|
|
|
- I915_WRITE(HWSTAM, 0xffffffff);
|
|
|
+ if (IS_GEN5(dev_priv))
|
|
|
+ I915_WRITE(HWSTAM, 0xffffffff);
|
|
|
|
|
|
- GEN5_IRQ_RESET(DE);
|
|
|
+ GEN3_IRQ_RESET(DE);
|
|
|
if (IS_GEN7(dev_priv))
|
|
|
I915_WRITE(GEN7_ERR_INT, 0xffffffff);
|
|
|
|
|
@@ -2963,7 +3110,7 @@ static void ironlake_irq_reset(struct drm_device *dev)
|
|
|
ibx_irq_reset(dev_priv);
|
|
|
}
|
|
|
|
|
|
-static void valleyview_irq_preinstall(struct drm_device *dev)
|
|
|
+static void valleyview_irq_reset(struct drm_device *dev)
|
|
|
{
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
|
|
@@ -3001,9 +3148,9 @@ static void gen8_irq_reset(struct drm_device *dev)
|
|
|
POWER_DOMAIN_PIPE(pipe)))
|
|
|
GEN8_IRQ_RESET_NDX(DE_PIPE, pipe);
|
|
|
|
|
|
- GEN5_IRQ_RESET(GEN8_DE_PORT_);
|
|
|
- GEN5_IRQ_RESET(GEN8_DE_MISC_);
|
|
|
- GEN5_IRQ_RESET(GEN8_PCU_);
|
|
|
+ GEN3_IRQ_RESET(GEN8_DE_PORT_);
|
|
|
+ GEN3_IRQ_RESET(GEN8_DE_MISC_);
|
|
|
+ GEN3_IRQ_RESET(GEN8_PCU_);
|
|
|
|
|
|
if (HAS_PCH_SPLIT(dev_priv))
|
|
|
ibx_irq_reset(dev_priv);
|
|
@@ -3037,7 +3184,7 @@ void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv,
|
|
|
synchronize_irq(dev_priv->drm.irq);
|
|
|
}
|
|
|
|
|
|
-static void cherryview_irq_preinstall(struct drm_device *dev)
|
|
|
+static void cherryview_irq_reset(struct drm_device *dev)
|
|
|
{
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
|
|
@@ -3046,7 +3193,7 @@ static void cherryview_irq_preinstall(struct drm_device *dev)
|
|
|
|
|
|
gen8_gt_irq_reset(dev_priv);
|
|
|
|
|
|
- GEN5_IRQ_RESET(GEN8_PCU_);
|
|
|
+ GEN3_IRQ_RESET(GEN8_PCU_);
|
|
|
|
|
|
spin_lock_irq(&dev_priv->irq_lock);
|
|
|
if (dev_priv->display_irqs_enabled)
|
|
@@ -3111,7 +3258,15 @@ static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv)
|
|
|
|
|
|
static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv)
|
|
|
{
|
|
|
- u32 hotplug;
|
|
|
+ u32 val, hotplug;
|
|
|
+
|
|
|
+ /* Display WA #1179 WaHardHangonHotPlug: cnp */
|
|
|
+ if (HAS_PCH_CNP(dev_priv)) {
|
|
|
+ val = I915_READ(SOUTH_CHICKEN1);
|
|
|
+ val &= ~CHASSIS_CLK_REQ_DURATION_MASK;
|
|
|
+ val |= CHASSIS_CLK_REQ_DURATION(0xf);
|
|
|
+ I915_WRITE(SOUTH_CHICKEN1, val);
|
|
|
+ }
|
|
|
|
|
|
/* Enable digital hotplug on the PCH */
|
|
|
hotplug = I915_READ(PCH_PORT_HOTPLUG);
|
|
@@ -3238,10 +3393,12 @@ static void ibx_irq_postinstall(struct drm_device *dev)
|
|
|
|
|
|
if (HAS_PCH_IBX(dev_priv))
|
|
|
mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON;
|
|
|
- else
|
|
|
+ else if (HAS_PCH_CPT(dev_priv) || HAS_PCH_LPT(dev_priv))
|
|
|
mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
|
|
|
+ else
|
|
|
+ mask = SDE_GMBUS_CPT;
|
|
|
|
|
|
- gen5_assert_iir_is_zero(dev_priv, SDEIIR);
|
|
|
+ gen3_assert_iir_is_zero(dev_priv, SDEIIR);
|
|
|
I915_WRITE(SDEIMR, ~mask);
|
|
|
|
|
|
if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv) ||
|
|
@@ -3272,7 +3429,7 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
|
|
|
gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT;
|
|
|
}
|
|
|
|
|
|
- GEN5_IRQ_INIT(GT, dev_priv->gt_irq_mask, gt_irqs);
|
|
|
+ GEN3_IRQ_INIT(GT, dev_priv->gt_irq_mask, gt_irqs);
|
|
|
|
|
|
if (INTEL_GEN(dev_priv) >= 6) {
|
|
|
/*
|
|
@@ -3285,7 +3442,7 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
|
|
|
}
|
|
|
|
|
|
dev_priv->pm_imr = 0xffffffff;
|
|
|
- GEN5_IRQ_INIT(GEN6_PM, dev_priv->pm_imr, pm_irqs);
|
|
|
+ GEN3_IRQ_INIT(GEN6_PM, dev_priv->pm_imr, pm_irqs);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -3296,18 +3453,14 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
|
|
|
|
|
|
if (INTEL_GEN(dev_priv) >= 7) {
|
|
|
display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
|
|
|
- DE_PCH_EVENT_IVB | DE_PLANEC_FLIP_DONE_IVB |
|
|
|
- DE_PLANEB_FLIP_DONE_IVB |
|
|
|
- DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB);
|
|
|
+ DE_PCH_EVENT_IVB | DE_AUX_CHANNEL_A_IVB);
|
|
|
extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB |
|
|
|
DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB |
|
|
|
DE_DP_A_HOTPLUG_IVB);
|
|
|
} else {
|
|
|
display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
|
|
|
- DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
|
|
|
- DE_AUX_CHANNEL_A |
|
|
|
- DE_PIPEB_CRC_DONE | DE_PIPEA_CRC_DONE |
|
|
|
- DE_POISON);
|
|
|
+ DE_AUX_CHANNEL_A | DE_PIPEB_CRC_DONE |
|
|
|
+ DE_PIPEA_CRC_DONE | DE_POISON);
|
|
|
extra_mask = (DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT |
|
|
|
DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN |
|
|
|
DE_DP_A_HOTPLUG);
|
|
@@ -3315,11 +3468,9 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
|
|
|
|
|
|
dev_priv->irq_mask = ~display_mask;
|
|
|
|
|
|
- I915_WRITE(HWSTAM, 0xeffe);
|
|
|
-
|
|
|
ibx_irq_pre_postinstall(dev);
|
|
|
|
|
|
- GEN5_IRQ_INIT(DE, dev_priv->irq_mask, display_mask | extra_mask);
|
|
|
+ GEN3_IRQ_INIT(DE, dev_priv->irq_mask, display_mask | extra_mask);
|
|
|
|
|
|
gen5_gt_irq_postinstall(dev);
|
|
|
|
|
@@ -3429,15 +3580,13 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
|
|
|
enum pipe pipe;
|
|
|
|
|
|
if (INTEL_GEN(dev_priv) >= 9) {
|
|
|
- de_pipe_masked |= GEN9_PIPE_PLANE1_FLIP_DONE |
|
|
|
- GEN9_DE_PIPE_IRQ_FAULT_ERRORS;
|
|
|
+ de_pipe_masked |= GEN9_DE_PIPE_IRQ_FAULT_ERRORS;
|
|
|
de_port_masked |= GEN9_AUX_CHANNEL_B | GEN9_AUX_CHANNEL_C |
|
|
|
GEN9_AUX_CHANNEL_D;
|
|
|
if (IS_GEN9_LP(dev_priv))
|
|
|
de_port_masked |= BXT_DE_PORT_GMBUS;
|
|
|
} else {
|
|
|
- de_pipe_masked |= GEN8_PIPE_PRIMARY_FLIP_DONE |
|
|
|
- GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
|
|
|
+ de_pipe_masked |= GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
|
|
|
}
|
|
|
|
|
|
de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
|
|
@@ -3460,8 +3609,8 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
|
|
|
dev_priv->de_irq_mask[pipe],
|
|
|
de_pipe_enables);
|
|
|
|
|
|
- GEN5_IRQ_INIT(GEN8_DE_PORT_, ~de_port_masked, de_port_enables);
|
|
|
- GEN5_IRQ_INIT(GEN8_DE_MISC_, ~de_misc_masked, de_misc_masked);
|
|
|
+ GEN3_IRQ_INIT(GEN8_DE_PORT_, ~de_port_masked, de_port_enables);
|
|
|
+ GEN3_IRQ_INIT(GEN8_DE_MISC_, ~de_misc_masked, de_misc_masked);
|
|
|
|
|
|
if (IS_GEN9_LP(dev_priv))
|
|
|
bxt_hpd_detection_setup(dev_priv);
|
|
@@ -3505,98 +3654,36 @@ static int cherryview_irq_postinstall(struct drm_device *dev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void gen8_irq_uninstall(struct drm_device *dev)
|
|
|
-{
|
|
|
- struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
-
|
|
|
- if (!dev_priv)
|
|
|
- return;
|
|
|
-
|
|
|
- gen8_irq_reset(dev);
|
|
|
-}
|
|
|
-
|
|
|
-static void valleyview_irq_uninstall(struct drm_device *dev)
|
|
|
-{
|
|
|
- struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
-
|
|
|
- if (!dev_priv)
|
|
|
- return;
|
|
|
-
|
|
|
- I915_WRITE(VLV_MASTER_IER, 0);
|
|
|
- POSTING_READ(VLV_MASTER_IER);
|
|
|
-
|
|
|
- gen5_gt_irq_reset(dev_priv);
|
|
|
-
|
|
|
- I915_WRITE(HWSTAM, 0xffffffff);
|
|
|
-
|
|
|
- spin_lock_irq(&dev_priv->irq_lock);
|
|
|
- if (dev_priv->display_irqs_enabled)
|
|
|
- vlv_display_irq_reset(dev_priv);
|
|
|
- spin_unlock_irq(&dev_priv->irq_lock);
|
|
|
-}
|
|
|
-
|
|
|
-static void cherryview_irq_uninstall(struct drm_device *dev)
|
|
|
+static void i8xx_irq_reset(struct drm_device *dev)
|
|
|
{
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
|
|
|
- if (!dev_priv)
|
|
|
- return;
|
|
|
-
|
|
|
- I915_WRITE(GEN8_MASTER_IRQ, 0);
|
|
|
- POSTING_READ(GEN8_MASTER_IRQ);
|
|
|
-
|
|
|
- gen8_gt_irq_reset(dev_priv);
|
|
|
-
|
|
|
- GEN5_IRQ_RESET(GEN8_PCU_);
|
|
|
-
|
|
|
- spin_lock_irq(&dev_priv->irq_lock);
|
|
|
- if (dev_priv->display_irqs_enabled)
|
|
|
- vlv_display_irq_reset(dev_priv);
|
|
|
- spin_unlock_irq(&dev_priv->irq_lock);
|
|
|
-}
|
|
|
-
|
|
|
-static void ironlake_irq_uninstall(struct drm_device *dev)
|
|
|
-{
|
|
|
- struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
+ i9xx_pipestat_irq_reset(dev_priv);
|
|
|
|
|
|
- if (!dev_priv)
|
|
|
- return;
|
|
|
-
|
|
|
- ironlake_irq_reset(dev);
|
|
|
-}
|
|
|
-
|
|
|
-static void i8xx_irq_preinstall(struct drm_device * dev)
|
|
|
-{
|
|
|
- struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
- int pipe;
|
|
|
+ I915_WRITE16(HWSTAM, 0xffff);
|
|
|
|
|
|
- for_each_pipe(dev_priv, pipe)
|
|
|
- I915_WRITE(PIPESTAT(pipe), 0);
|
|
|
- I915_WRITE16(IMR, 0xffff);
|
|
|
- I915_WRITE16(IER, 0x0);
|
|
|
- POSTING_READ16(IER);
|
|
|
+ GEN2_IRQ_RESET();
|
|
|
}
|
|
|
|
|
|
static int i8xx_irq_postinstall(struct drm_device *dev)
|
|
|
{
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
+ u16 enable_mask;
|
|
|
|
|
|
- I915_WRITE16(EMR,
|
|
|
- ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
|
|
|
+ I915_WRITE16(EMR, ~(I915_ERROR_PAGE_TABLE |
|
|
|
+ I915_ERROR_MEMORY_REFRESH));
|
|
|
|
|
|
/* Unmask the interrupts that we always want on. */
|
|
|
dev_priv->irq_mask =
|
|
|
~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
|
|
|
- I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
|
|
|
- I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
|
|
|
- I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT);
|
|
|
- I915_WRITE16(IMR, dev_priv->irq_mask);
|
|
|
+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT);
|
|
|
+
|
|
|
+ enable_mask =
|
|
|
+ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
|
|
|
+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
|
|
|
+ I915_USER_INTERRUPT;
|
|
|
|
|
|
- I915_WRITE16(IER,
|
|
|
- I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
|
|
|
- I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
|
|
|
- I915_USER_INTERRUPT);
|
|
|
- POSTING_READ16(IER);
|
|
|
+ GEN2_IRQ_INIT(, dev_priv->irq_mask, enable_mask);
|
|
|
|
|
|
/* Interrupt setup is already guaranteed to be single-threaded, this is
|
|
|
* just to make the assert_spin_locked check happy. */
|
|
@@ -3608,17 +3695,11 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Returns true when a page flip has completed.
|
|
|
- */
|
|
|
static irqreturn_t i8xx_irq_handler(int irq, void *arg)
|
|
|
{
|
|
|
struct drm_device *dev = arg;
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
- u16 iir, new_iir;
|
|
|
- u32 pipe_stats[2];
|
|
|
- int pipe;
|
|
|
- irqreturn_t ret;
|
|
|
+ irqreturn_t ret = IRQ_NONE;
|
|
|
|
|
|
if (!intel_irqs_enabled(dev_priv))
|
|
|
return IRQ_NONE;
|
|
@@ -3626,96 +3707,50 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
|
|
|
/* IRQs are synced during runtime_suspend, we don't require a wakeref */
|
|
|
disable_rpm_wakeref_asserts(dev_priv);
|
|
|
|
|
|
- ret = IRQ_NONE;
|
|
|
- iir = I915_READ16(IIR);
|
|
|
- if (iir == 0)
|
|
|
- goto out;
|
|
|
+ do {
|
|
|
+ u32 pipe_stats[I915_MAX_PIPES] = {};
|
|
|
+ u16 iir;
|
|
|
|
|
|
- while (iir) {
|
|
|
- /* Can't rely on pipestat interrupt bit in iir as it might
|
|
|
- * have been cleared after the pipestat interrupt was received.
|
|
|
- * It doesn't set the bit in iir again, but it still produces
|
|
|
- * interrupts (for non-MSI).
|
|
|
- */
|
|
|
- spin_lock(&dev_priv->irq_lock);
|
|
|
- if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
|
|
|
- DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
|
|
|
+ iir = I915_READ16(IIR);
|
|
|
+ if (iir == 0)
|
|
|
+ break;
|
|
|
|
|
|
- for_each_pipe(dev_priv, pipe) {
|
|
|
- i915_reg_t reg = PIPESTAT(pipe);
|
|
|
- pipe_stats[pipe] = I915_READ(reg);
|
|
|
+ ret = IRQ_HANDLED;
|
|
|
|
|
|
- /*
|
|
|
- * Clear the PIPE*STAT regs before the IIR
|
|
|
- */
|
|
|
- if (pipe_stats[pipe] & 0x8000ffff)
|
|
|
- I915_WRITE(reg, pipe_stats[pipe]);
|
|
|
- }
|
|
|
- spin_unlock(&dev_priv->irq_lock);
|
|
|
+ /* Call regardless, as some status bits might not be
|
|
|
+ * signalled in iir */
|
|
|
+ i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
|
|
|
|
|
|
I915_WRITE16(IIR, iir);
|
|
|
- new_iir = I915_READ16(IIR); /* Flush posted writes */
|
|
|
|
|
|
if (iir & I915_USER_INTERRUPT)
|
|
|
notify_ring(dev_priv->engine[RCS]);
|
|
|
|
|
|
- for_each_pipe(dev_priv, pipe) {
|
|
|
- int plane = pipe;
|
|
|
- if (HAS_FBC(dev_priv))
|
|
|
- plane = !plane;
|
|
|
-
|
|
|
- if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
|
|
|
- drm_handle_vblank(&dev_priv->drm, pipe);
|
|
|
-
|
|
|
- if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
|
|
|
- i9xx_pipe_crc_irq_handler(dev_priv, pipe);
|
|
|
-
|
|
|
- if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
|
|
|
- intel_cpu_fifo_underrun_irq_handler(dev_priv,
|
|
|
- pipe);
|
|
|
- }
|
|
|
+ if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
|
|
|
+ DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
|
|
|
|
|
|
- iir = new_iir;
|
|
|
- }
|
|
|
- ret = IRQ_HANDLED;
|
|
|
+ i8xx_pipestat_irq_handler(dev_priv, iir, pipe_stats);
|
|
|
+ } while (0);
|
|
|
|
|
|
-out:
|
|
|
enable_rpm_wakeref_asserts(dev_priv);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static void i8xx_irq_uninstall(struct drm_device * dev)
|
|
|
-{
|
|
|
- struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
- int pipe;
|
|
|
-
|
|
|
- for_each_pipe(dev_priv, pipe) {
|
|
|
- /* Clear enable bits; then clear status bits */
|
|
|
- I915_WRITE(PIPESTAT(pipe), 0);
|
|
|
- I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe)));
|
|
|
- }
|
|
|
- I915_WRITE16(IMR, 0xffff);
|
|
|
- I915_WRITE16(IER, 0x0);
|
|
|
- I915_WRITE16(IIR, I915_READ16(IIR));
|
|
|
-}
|
|
|
-
|
|
|
-static void i915_irq_preinstall(struct drm_device * dev)
|
|
|
+static void i915_irq_reset(struct drm_device *dev)
|
|
|
{
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
- int pipe;
|
|
|
|
|
|
if (I915_HAS_HOTPLUG(dev_priv)) {
|
|
|
i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
|
|
|
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
|
|
|
}
|
|
|
|
|
|
- I915_WRITE16(HWSTAM, 0xeffe);
|
|
|
- for_each_pipe(dev_priv, pipe)
|
|
|
- I915_WRITE(PIPESTAT(pipe), 0);
|
|
|
- I915_WRITE(IMR, 0xffffffff);
|
|
|
- I915_WRITE(IER, 0x0);
|
|
|
- POSTING_READ(IER);
|
|
|
+ i9xx_pipestat_irq_reset(dev_priv);
|
|
|
+
|
|
|
+ I915_WRITE(HWSTAM, 0xffffffff);
|
|
|
+
|
|
|
+ GEN3_IRQ_RESET();
|
|
|
}
|
|
|
|
|
|
static int i915_irq_postinstall(struct drm_device *dev)
|
|
@@ -3723,15 +3758,14 @@ static int i915_irq_postinstall(struct drm_device *dev)
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
u32 enable_mask;
|
|
|
|
|
|
- I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
|
|
|
+ I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE |
|
|
|
+ I915_ERROR_MEMORY_REFRESH));
|
|
|
|
|
|
/* Unmask the interrupts that we always want on. */
|
|
|
dev_priv->irq_mask =
|
|
|
~(I915_ASLE_INTERRUPT |
|
|
|
I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
|
|
|
- I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
|
|
|
- I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
|
|
|
- I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT);
|
|
|
+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT);
|
|
|
|
|
|
enable_mask =
|
|
|
I915_ASLE_INTERRUPT |
|
|
@@ -3740,20 +3774,13 @@ static int i915_irq_postinstall(struct drm_device *dev)
|
|
|
I915_USER_INTERRUPT;
|
|
|
|
|
|
if (I915_HAS_HOTPLUG(dev_priv)) {
|
|
|
- i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
|
|
|
- POSTING_READ(PORT_HOTPLUG_EN);
|
|
|
-
|
|
|
/* Enable in IER... */
|
|
|
enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
|
|
|
/* and unmask in IMR */
|
|
|
dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT;
|
|
|
}
|
|
|
|
|
|
- I915_WRITE(IMR, dev_priv->irq_mask);
|
|
|
- I915_WRITE(IER, enable_mask);
|
|
|
- POSTING_READ(IER);
|
|
|
-
|
|
|
- i915_enable_asle_pipestat(dev_priv);
|
|
|
+ GEN3_IRQ_INIT(, dev_priv->irq_mask, enable_mask);
|
|
|
|
|
|
/* Interrupt setup is already guaranteed to be single-threaded, this is
|
|
|
* just to make the assert_spin_locked check happy. */
|
|
@@ -3762,6 +3789,8 @@ static int i915_irq_postinstall(struct drm_device *dev)
|
|
|
i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
|
|
|
spin_unlock_irq(&dev_priv->irq_lock);
|
|
|
|
|
|
+ i915_enable_asle_pipestat(dev_priv);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -3769,8 +3798,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
|
|
|
{
|
|
|
struct drm_device *dev = arg;
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
- u32 iir, new_iir, pipe_stats[I915_MAX_PIPES];
|
|
|
- int pipe, ret = IRQ_NONE;
|
|
|
+ irqreturn_t ret = IRQ_NONE;
|
|
|
|
|
|
if (!intel_irqs_enabled(dev_priv))
|
|
|
return IRQ_NONE;
|
|
@@ -3778,131 +3806,56 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
|
|
|
/* IRQs are synced during runtime_suspend, we don't require a wakeref */
|
|
|
disable_rpm_wakeref_asserts(dev_priv);
|
|
|
|
|
|
- iir = I915_READ(IIR);
|
|
|
do {
|
|
|
- bool irq_received = (iir) != 0;
|
|
|
- bool blc_event = false;
|
|
|
-
|
|
|
- /* Can't rely on pipestat interrupt bit in iir as it might
|
|
|
- * have been cleared after the pipestat interrupt was received.
|
|
|
- * It doesn't set the bit in iir again, but it still produces
|
|
|
- * interrupts (for non-MSI).
|
|
|
- */
|
|
|
- spin_lock(&dev_priv->irq_lock);
|
|
|
- if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
|
|
|
- DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
|
|
|
-
|
|
|
- for_each_pipe(dev_priv, pipe) {
|
|
|
- i915_reg_t reg = PIPESTAT(pipe);
|
|
|
- pipe_stats[pipe] = I915_READ(reg);
|
|
|
-
|
|
|
- /* Clear the PIPE*STAT regs before the IIR */
|
|
|
- if (pipe_stats[pipe] & 0x8000ffff) {
|
|
|
- I915_WRITE(reg, pipe_stats[pipe]);
|
|
|
- irq_received = true;
|
|
|
- }
|
|
|
- }
|
|
|
- spin_unlock(&dev_priv->irq_lock);
|
|
|
+ u32 pipe_stats[I915_MAX_PIPES] = {};
|
|
|
+ u32 hotplug_status = 0;
|
|
|
+ u32 iir;
|
|
|
|
|
|
- if (!irq_received)
|
|
|
+ iir = I915_READ(IIR);
|
|
|
+ if (iir == 0)
|
|
|
break;
|
|
|
|
|
|
- /* Consume port. Then clear IIR or we'll miss events */
|
|
|
+ ret = IRQ_HANDLED;
|
|
|
+
|
|
|
if (I915_HAS_HOTPLUG(dev_priv) &&
|
|
|
- iir & I915_DISPLAY_PORT_INTERRUPT) {
|
|
|
- u32 hotplug_status = i9xx_hpd_irq_ack(dev_priv);
|
|
|
- if (hotplug_status)
|
|
|
- i9xx_hpd_irq_handler(dev_priv, hotplug_status);
|
|
|
- }
|
|
|
+ iir & I915_DISPLAY_PORT_INTERRUPT)
|
|
|
+ hotplug_status = i9xx_hpd_irq_ack(dev_priv);
|
|
|
+
|
|
|
+ /* Call regardless, as some status bits might not be
|
|
|
+ * signalled in iir */
|
|
|
+ i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
|
|
|
|
|
|
I915_WRITE(IIR, iir);
|
|
|
- new_iir = I915_READ(IIR); /* Flush posted writes */
|
|
|
|
|
|
if (iir & I915_USER_INTERRUPT)
|
|
|
notify_ring(dev_priv->engine[RCS]);
|
|
|
|
|
|
- for_each_pipe(dev_priv, pipe) {
|
|
|
- int plane = pipe;
|
|
|
- if (HAS_FBC(dev_priv))
|
|
|
- plane = !plane;
|
|
|
-
|
|
|
- if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
|
|
|
- drm_handle_vblank(&dev_priv->drm, pipe);
|
|
|
-
|
|
|
- if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
|
|
|
- blc_event = true;
|
|
|
-
|
|
|
- if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
|
|
|
- i9xx_pipe_crc_irq_handler(dev_priv, pipe);
|
|
|
-
|
|
|
- if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
|
|
|
- intel_cpu_fifo_underrun_irq_handler(dev_priv,
|
|
|
- pipe);
|
|
|
- }
|
|
|
+ if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
|
|
|
+ DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
|
|
|
|
|
|
- if (blc_event || (iir & I915_ASLE_INTERRUPT))
|
|
|
- intel_opregion_asle_intr(dev_priv);
|
|
|
+ if (hotplug_status)
|
|
|
+ i9xx_hpd_irq_handler(dev_priv, hotplug_status);
|
|
|
|
|
|
- /* With MSI, interrupts are only generated when iir
|
|
|
- * transitions from zero to nonzero. If another bit got
|
|
|
- * set while we were handling the existing iir bits, then
|
|
|
- * we would never get another interrupt.
|
|
|
- *
|
|
|
- * This is fine on non-MSI as well, as if we hit this path
|
|
|
- * we avoid exiting the interrupt handler only to generate
|
|
|
- * another one.
|
|
|
- *
|
|
|
- * Note that for MSI this could cause a stray interrupt report
|
|
|
- * if an interrupt landed in the time between writing IIR and
|
|
|
- * the posting read. This should be rare enough to never
|
|
|
- * trigger the 99% of 100,000 interrupts test for disabling
|
|
|
- * stray interrupts.
|
|
|
- */
|
|
|
- ret = IRQ_HANDLED;
|
|
|
- iir = new_iir;
|
|
|
- } while (iir);
|
|
|
+ i915_pipestat_irq_handler(dev_priv, iir, pipe_stats);
|
|
|
+ } while (0);
|
|
|
|
|
|
enable_rpm_wakeref_asserts(dev_priv);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static void i915_irq_uninstall(struct drm_device * dev)
|
|
|
-{
|
|
|
- struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
- int pipe;
|
|
|
-
|
|
|
- if (I915_HAS_HOTPLUG(dev_priv)) {
|
|
|
- i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
|
|
|
- I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
|
|
|
- }
|
|
|
-
|
|
|
- I915_WRITE16(HWSTAM, 0xffff);
|
|
|
- for_each_pipe(dev_priv, pipe) {
|
|
|
- /* Clear enable bits; then clear status bits */
|
|
|
- I915_WRITE(PIPESTAT(pipe), 0);
|
|
|
- I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe)));
|
|
|
- }
|
|
|
- I915_WRITE(IMR, 0xffffffff);
|
|
|
- I915_WRITE(IER, 0x0);
|
|
|
-
|
|
|
- I915_WRITE(IIR, I915_READ(IIR));
|
|
|
-}
|
|
|
-
|
|
|
-static void i965_irq_preinstall(struct drm_device * dev)
|
|
|
+static void i965_irq_reset(struct drm_device *dev)
|
|
|
{
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
- int pipe;
|
|
|
|
|
|
i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
|
|
|
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
|
|
|
|
|
|
- I915_WRITE(HWSTAM, 0xeffe);
|
|
|
- for_each_pipe(dev_priv, pipe)
|
|
|
- I915_WRITE(PIPESTAT(pipe), 0);
|
|
|
- I915_WRITE(IMR, 0xffffffff);
|
|
|
- I915_WRITE(IER, 0x0);
|
|
|
- POSTING_READ(IER);
|
|
|
+ i9xx_pipestat_irq_reset(dev_priv);
|
|
|
+
|
|
|
+ I915_WRITE(HWSTAM, 0xffffffff);
|
|
|
+
|
|
|
+ GEN3_IRQ_RESET();
|
|
|
}
|
|
|
|
|
|
static int i965_irq_postinstall(struct drm_device *dev)
|
|
@@ -3911,31 +3864,6 @@ static int i965_irq_postinstall(struct drm_device *dev)
|
|
|
u32 enable_mask;
|
|
|
u32 error_mask;
|
|
|
|
|
|
- /* Unmask the interrupts that we always want on. */
|
|
|
- dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT |
|
|
|
- I915_DISPLAY_PORT_INTERRUPT |
|
|
|
- I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
|
|
|
- I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
|
|
|
- I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
|
|
|
- I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT |
|
|
|
- I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
|
|
|
-
|
|
|
- enable_mask = ~dev_priv->irq_mask;
|
|
|
- enable_mask &= ~(I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
|
|
|
- I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT);
|
|
|
- enable_mask |= I915_USER_INTERRUPT;
|
|
|
-
|
|
|
- if (IS_G4X(dev_priv))
|
|
|
- enable_mask |= I915_BSD_USER_INTERRUPT;
|
|
|
-
|
|
|
- /* Interrupt setup is already guaranteed to be single-threaded, this is
|
|
|
- * just to make the assert_spin_locked check happy. */
|
|
|
- spin_lock_irq(&dev_priv->irq_lock);
|
|
|
- i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
|
|
|
- i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS);
|
|
|
- i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
|
|
|
- spin_unlock_irq(&dev_priv->irq_lock);
|
|
|
-
|
|
|
/*
|
|
|
* Enable some error detection, note the instruction error mask
|
|
|
* bit is reserved, so we leave it masked.
|
|
@@ -3951,12 +3879,34 @@ static int i965_irq_postinstall(struct drm_device *dev)
|
|
|
}
|
|
|
I915_WRITE(EMR, error_mask);
|
|
|
|
|
|
- I915_WRITE(IMR, dev_priv->irq_mask);
|
|
|
- I915_WRITE(IER, enable_mask);
|
|
|
- POSTING_READ(IER);
|
|
|
+ /* Unmask the interrupts that we always want on. */
|
|
|
+ dev_priv->irq_mask =
|
|
|
+ ~(I915_ASLE_INTERRUPT |
|
|
|
+ I915_DISPLAY_PORT_INTERRUPT |
|
|
|
+ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
|
|
|
+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
|
|
|
+ I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
|
|
|
|
|
|
- i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
|
|
|
- POSTING_READ(PORT_HOTPLUG_EN);
|
|
|
+ enable_mask =
|
|
|
+ I915_ASLE_INTERRUPT |
|
|
|
+ I915_DISPLAY_PORT_INTERRUPT |
|
|
|
+ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
|
|
|
+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
|
|
|
+ I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT |
|
|
|
+ I915_USER_INTERRUPT;
|
|
|
+
|
|
|
+ if (IS_G4X(dev_priv))
|
|
|
+ enable_mask |= I915_BSD_USER_INTERRUPT;
|
|
|
+
|
|
|
+ GEN3_IRQ_INIT(, dev_priv->irq_mask, enable_mask);
|
|
|
+
|
|
|
+ /* Interrupt setup is already guaranteed to be single-threaded, this is
|
|
|
+ * just to make the assert_spin_locked check happy. */
|
|
|
+ spin_lock_irq(&dev_priv->irq_lock);
|
|
|
+ i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
|
|
|
+ i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS);
|
|
|
+ i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
|
|
|
+ spin_unlock_irq(&dev_priv->irq_lock);
|
|
|
|
|
|
i915_enable_asle_pipestat(dev_priv);
|
|
|
|
|
@@ -3992,9 +3942,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
|
|
|
{
|
|
|
struct drm_device *dev = arg;
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
- u32 iir, new_iir;
|
|
|
- u32 pipe_stats[I915_MAX_PIPES];
|
|
|
- int ret = IRQ_NONE, pipe;
|
|
|
+ irqreturn_t ret = IRQ_NONE;
|
|
|
|
|
|
if (!intel_irqs_enabled(dev_priv))
|
|
|
return IRQ_NONE;
|
|
@@ -4002,121 +3950,46 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
|
|
|
/* IRQs are synced during runtime_suspend, we don't require a wakeref */
|
|
|
disable_rpm_wakeref_asserts(dev_priv);
|
|
|
|
|
|
- iir = I915_READ(IIR);
|
|
|
-
|
|
|
- for (;;) {
|
|
|
- bool irq_received = (iir) != 0;
|
|
|
- bool blc_event = false;
|
|
|
-
|
|
|
- /* Can't rely on pipestat interrupt bit in iir as it might
|
|
|
- * have been cleared after the pipestat interrupt was received.
|
|
|
- * It doesn't set the bit in iir again, but it still produces
|
|
|
- * interrupts (for non-MSI).
|
|
|
- */
|
|
|
- spin_lock(&dev_priv->irq_lock);
|
|
|
- if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
|
|
|
- DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
|
|
|
-
|
|
|
- for_each_pipe(dev_priv, pipe) {
|
|
|
- i915_reg_t reg = PIPESTAT(pipe);
|
|
|
- pipe_stats[pipe] = I915_READ(reg);
|
|
|
-
|
|
|
- /*
|
|
|
- * Clear the PIPE*STAT regs before the IIR
|
|
|
- */
|
|
|
- if (pipe_stats[pipe] & 0x8000ffff) {
|
|
|
- I915_WRITE(reg, pipe_stats[pipe]);
|
|
|
- irq_received = true;
|
|
|
- }
|
|
|
- }
|
|
|
- spin_unlock(&dev_priv->irq_lock);
|
|
|
+ do {
|
|
|
+ u32 pipe_stats[I915_MAX_PIPES] = {};
|
|
|
+ u32 hotplug_status = 0;
|
|
|
+ u32 iir;
|
|
|
|
|
|
- if (!irq_received)
|
|
|
+ iir = I915_READ(IIR);
|
|
|
+ if (iir == 0)
|
|
|
break;
|
|
|
|
|
|
ret = IRQ_HANDLED;
|
|
|
|
|
|
- /* Consume port. Then clear IIR or we'll miss events */
|
|
|
- if (iir & I915_DISPLAY_PORT_INTERRUPT) {
|
|
|
- u32 hotplug_status = i9xx_hpd_irq_ack(dev_priv);
|
|
|
- if (hotplug_status)
|
|
|
- i9xx_hpd_irq_handler(dev_priv, hotplug_status);
|
|
|
- }
|
|
|
+ if (iir & I915_DISPLAY_PORT_INTERRUPT)
|
|
|
+ hotplug_status = i9xx_hpd_irq_ack(dev_priv);
|
|
|
+
|
|
|
+ /* Call regardless, as some status bits might not be
|
|
|
+ * signalled in iir */
|
|
|
+ i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
|
|
|
|
|
|
I915_WRITE(IIR, iir);
|
|
|
- new_iir = I915_READ(IIR); /* Flush posted writes */
|
|
|
|
|
|
if (iir & I915_USER_INTERRUPT)
|
|
|
notify_ring(dev_priv->engine[RCS]);
|
|
|
+
|
|
|
if (iir & I915_BSD_USER_INTERRUPT)
|
|
|
notify_ring(dev_priv->engine[VCS]);
|
|
|
|
|
|
- for_each_pipe(dev_priv, pipe) {
|
|
|
- if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
|
|
|
- drm_handle_vblank(&dev_priv->drm, pipe);
|
|
|
-
|
|
|
- if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
|
|
|
- blc_event = true;
|
|
|
-
|
|
|
- if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
|
|
|
- i9xx_pipe_crc_irq_handler(dev_priv, pipe);
|
|
|
-
|
|
|
- if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
|
|
|
- intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
|
|
|
- }
|
|
|
-
|
|
|
- if (blc_event || (iir & I915_ASLE_INTERRUPT))
|
|
|
- intel_opregion_asle_intr(dev_priv);
|
|
|
+ if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
|
|
|
+ DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
|
|
|
|
|
|
- if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
|
|
|
- gmbus_irq_handler(dev_priv);
|
|
|
+ if (hotplug_status)
|
|
|
+ i9xx_hpd_irq_handler(dev_priv, hotplug_status);
|
|
|
|
|
|
- /* With MSI, interrupts are only generated when iir
|
|
|
- * transitions from zero to nonzero. If another bit got
|
|
|
- * set while we were handling the existing iir bits, then
|
|
|
- * we would never get another interrupt.
|
|
|
- *
|
|
|
- * This is fine on non-MSI as well, as if we hit this path
|
|
|
- * we avoid exiting the interrupt handler only to generate
|
|
|
- * another one.
|
|
|
- *
|
|
|
- * Note that for MSI this could cause a stray interrupt report
|
|
|
- * if an interrupt landed in the time between writing IIR and
|
|
|
- * the posting read. This should be rare enough to never
|
|
|
- * trigger the 99% of 100,000 interrupts test for disabling
|
|
|
- * stray interrupts.
|
|
|
- */
|
|
|
- iir = new_iir;
|
|
|
- }
|
|
|
+ i965_pipestat_irq_handler(dev_priv, iir, pipe_stats);
|
|
|
+ } while (0);
|
|
|
|
|
|
enable_rpm_wakeref_asserts(dev_priv);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static void i965_irq_uninstall(struct drm_device * dev)
|
|
|
-{
|
|
|
- struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
- int pipe;
|
|
|
-
|
|
|
- if (!dev_priv)
|
|
|
- return;
|
|
|
-
|
|
|
- i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
|
|
|
- I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
|
|
|
-
|
|
|
- I915_WRITE(HWSTAM, 0xffffffff);
|
|
|
- for_each_pipe(dev_priv, pipe)
|
|
|
- I915_WRITE(PIPESTAT(pipe), 0);
|
|
|
- I915_WRITE(IMR, 0xffffffff);
|
|
|
- I915_WRITE(IER, 0x0);
|
|
|
-
|
|
|
- for_each_pipe(dev_priv, pipe)
|
|
|
- I915_WRITE(PIPESTAT(pipe),
|
|
|
- I915_READ(PIPESTAT(pipe)) & 0x8000ffff);
|
|
|
- I915_WRITE(IIR, I915_READ(IIR));
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* intel_irq_init - initializes irq support
|
|
|
* @dev_priv: i915 device instance
|
|
@@ -4197,17 +4070,17 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
|
|
|
|
|
|
if (IS_CHERRYVIEW(dev_priv)) {
|
|
|
dev->driver->irq_handler = cherryview_irq_handler;
|
|
|
- dev->driver->irq_preinstall = cherryview_irq_preinstall;
|
|
|
+ dev->driver->irq_preinstall = cherryview_irq_reset;
|
|
|
dev->driver->irq_postinstall = cherryview_irq_postinstall;
|
|
|
- dev->driver->irq_uninstall = cherryview_irq_uninstall;
|
|
|
+ dev->driver->irq_uninstall = cherryview_irq_reset;
|
|
|
dev->driver->enable_vblank = i965_enable_vblank;
|
|
|
dev->driver->disable_vblank = i965_disable_vblank;
|
|
|
dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
|
|
|
} else if (IS_VALLEYVIEW(dev_priv)) {
|
|
|
dev->driver->irq_handler = valleyview_irq_handler;
|
|
|
- dev->driver->irq_preinstall = valleyview_irq_preinstall;
|
|
|
+ dev->driver->irq_preinstall = valleyview_irq_reset;
|
|
|
dev->driver->irq_postinstall = valleyview_irq_postinstall;
|
|
|
- dev->driver->irq_uninstall = valleyview_irq_uninstall;
|
|
|
+ dev->driver->irq_uninstall = valleyview_irq_reset;
|
|
|
dev->driver->enable_vblank = i965_enable_vblank;
|
|
|
dev->driver->disable_vblank = i965_disable_vblank;
|
|
|
dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
|
|
@@ -4215,7 +4088,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
|
|
|
dev->driver->irq_handler = gen8_irq_handler;
|
|
|
dev->driver->irq_preinstall = gen8_irq_reset;
|
|
|
dev->driver->irq_postinstall = gen8_irq_postinstall;
|
|
|
- dev->driver->irq_uninstall = gen8_irq_uninstall;
|
|
|
+ dev->driver->irq_uninstall = gen8_irq_reset;
|
|
|
dev->driver->enable_vblank = gen8_enable_vblank;
|
|
|
dev->driver->disable_vblank = gen8_disable_vblank;
|
|
|
if (IS_GEN9_LP(dev_priv))
|
|
@@ -4229,29 +4102,29 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
|
|
|
dev->driver->irq_handler = ironlake_irq_handler;
|
|
|
dev->driver->irq_preinstall = ironlake_irq_reset;
|
|
|
dev->driver->irq_postinstall = ironlake_irq_postinstall;
|
|
|
- dev->driver->irq_uninstall = ironlake_irq_uninstall;
|
|
|
+ dev->driver->irq_uninstall = ironlake_irq_reset;
|
|
|
dev->driver->enable_vblank = ironlake_enable_vblank;
|
|
|
dev->driver->disable_vblank = ironlake_disable_vblank;
|
|
|
dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup;
|
|
|
} else {
|
|
|
if (IS_GEN2(dev_priv)) {
|
|
|
- dev->driver->irq_preinstall = i8xx_irq_preinstall;
|
|
|
+ dev->driver->irq_preinstall = i8xx_irq_reset;
|
|
|
dev->driver->irq_postinstall = i8xx_irq_postinstall;
|
|
|
dev->driver->irq_handler = i8xx_irq_handler;
|
|
|
- dev->driver->irq_uninstall = i8xx_irq_uninstall;
|
|
|
+ dev->driver->irq_uninstall = i8xx_irq_reset;
|
|
|
dev->driver->enable_vblank = i8xx_enable_vblank;
|
|
|
dev->driver->disable_vblank = i8xx_disable_vblank;
|
|
|
} else if (IS_GEN3(dev_priv)) {
|
|
|
- dev->driver->irq_preinstall = i915_irq_preinstall;
|
|
|
+ dev->driver->irq_preinstall = i915_irq_reset;
|
|
|
dev->driver->irq_postinstall = i915_irq_postinstall;
|
|
|
- dev->driver->irq_uninstall = i915_irq_uninstall;
|
|
|
+ dev->driver->irq_uninstall = i915_irq_reset;
|
|
|
dev->driver->irq_handler = i915_irq_handler;
|
|
|
dev->driver->enable_vblank = i8xx_enable_vblank;
|
|
|
dev->driver->disable_vblank = i8xx_disable_vblank;
|
|
|
} else {
|
|
|
- dev->driver->irq_preinstall = i965_irq_preinstall;
|
|
|
+ dev->driver->irq_preinstall = i965_irq_reset;
|
|
|
dev->driver->irq_postinstall = i965_irq_postinstall;
|
|
|
- dev->driver->irq_uninstall = i965_irq_uninstall;
|
|
|
+ dev->driver->irq_uninstall = i965_irq_reset;
|
|
|
dev->driver->irq_handler = i965_irq_handler;
|
|
|
dev->driver->enable_vblank = i965_enable_vblank;
|
|
|
dev->driver->disable_vblank = i965_disable_vblank;
|