drm/i915/bdw: Implement a basic PM interrupt handler
[deliverable/linux.git] / drivers / gpu / drm / i915 / i915_irq.c
index b10fbde1d5eeb8ac939aee6d2bfa43c8c1bf2e11..4a88fdefc570af5e978cc16a9b5db1f3ebe1db80 100644 (file)
@@ -248,6 +248,46 @@ static bool ivb_can_enable_err_int(struct drm_device *dev)
        return true;
 }
 
+/**
+  * bdw_update_pm_irq - update GT interrupt 2
+  * @dev_priv: driver private
+  * @interrupt_mask: mask of interrupt bits to update
+  * @enabled_irq_mask: mask of interrupt bits to enable
+  *
+  * Copied from the snb function, updated with relevant register offsets
+  */
+static void bdw_update_pm_irq(struct drm_i915_private *dev_priv,
+                             uint32_t interrupt_mask,
+                             uint32_t enabled_irq_mask)
+{
+       uint32_t new_val;
+
+       assert_spin_locked(&dev_priv->irq_lock);
+
+       if (WARN_ON(dev_priv->pm.irqs_disabled))
+               return;
+
+       new_val = dev_priv->pm_irq_mask;
+       new_val &= ~interrupt_mask;
+       new_val |= (~enabled_irq_mask & interrupt_mask);
+
+       if (new_val != dev_priv->pm_irq_mask) {
+               dev_priv->pm_irq_mask = new_val;
+               I915_WRITE(GEN8_GT_IMR(2), dev_priv->pm_irq_mask);
+               POSTING_READ(GEN8_GT_IMR(2));
+       }
+}
+
+void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
+{
+       bdw_update_pm_irq(dev_priv, mask, mask);
+}
+
+void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
+{
+       bdw_update_pm_irq(dev_priv, mask, 0);
+}
+
 static bool cpt_can_enable_serr_int(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1098,8 +1138,12 @@ static void gen6_pm_rps_work(struct work_struct *work)
        spin_lock_irq(&dev_priv->irq_lock);
        pm_iir = dev_priv->rps.pm_iir;
        dev_priv->rps.pm_iir = 0;
-       /* Make sure not to corrupt PMIMR state used by ringbuffer code */
-       snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
+       if (IS_BROADWELL(dev_priv->dev))
+               bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
+       else {
+               /* Make sure not to corrupt PMIMR state used by ringbuffer */
+               snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
+       }
        spin_unlock_irq(&dev_priv->irq_lock);
 
        /* Make sure we didn't queue anything we're not going to process. */
@@ -1296,6 +1340,19 @@ static void snb_gt_irq_handler(struct drm_device *dev,
                ivybridge_parity_error_irq_handler(dev, gt_iir);
 }
 
+static void gen8_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
+{
+       if ((pm_iir & dev_priv->pm_rps_events) == 0)
+               return;
+
+       spin_lock(&dev_priv->irq_lock);
+       dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events;
+       bdw_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
+       spin_unlock(&dev_priv->irq_lock);
+
+       queue_work(dev_priv->wq, &dev_priv->rps.work);
+}
+
 static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
                                       struct drm_i915_private *dev_priv,
                                       u32 master_ctl)
@@ -1334,6 +1391,17 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
                        DRM_ERROR("The master control interrupt lied (GT1)!\n");
        }
 
+       if (master_ctl & GEN8_GT_PM_IRQ) {
+               tmp = I915_READ(GEN8_GT_IIR(2));
+               if (tmp & dev_priv->pm_rps_events) {
+                       ret = IRQ_HANDLED;
+                       gen8_rps_irq_handler(dev_priv, tmp);
+                       I915_WRITE(GEN8_GT_IIR(2),
+                                  tmp & dev_priv->pm_rps_events);
+               } else
+                       DRM_ERROR("The master control interrupt lied (PM)!\n");
+       }
+
        if (master_ctl & GEN8_GT_VECS_IRQ) {
                tmp = I915_READ(GEN8_GT_IIR(3));
                if (tmp) {
@@ -3372,6 +3440,8 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
 
        for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++)
                GEN8_IRQ_INIT_NDX(GT, i, ~gt_interrupts[i], gt_interrupts[i]);
+
+       dev_priv->pm_irq_mask = 0xffffffff;
 }
 
 static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
This page took 0.025185 seconds and 5 git commands to generate.