Merge branch 'drm-intel-next-fixes' into drm-intel-next
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / i915 / i915_irq.c
index f66392b6e287c3036f420c022241a74108c65527..f17bbf3ac136994464bc5881729d4db27a485c2c 100644 (file)
 #include "i915_trace.h"
 #include "intel_drv.h"
 
+/**
+ * DOC: interrupt handling
+ *
+ * These functions provide the basic support for enabling and disabling the
+ * interrupt handling support. There's a lot more functionality in i915_irq.c
+ * and related files, but that will be described in separate chapters.
+ */
+
 static const u32 hpd_ibx[] = {
        [HPD_CRT] = SDE_CRT_HOTPLUG,
        [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG,
@@ -310,9 +318,8 @@ void i9xx_check_fifo_underruns(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *crtc;
-       unsigned long flags;
 
-       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       spin_lock_irq(&dev_priv->irq_lock);
 
        for_each_intel_crtc(dev, crtc) {
                u32 reg = PIPESTAT(crtc->pipe);
@@ -331,7 +338,7 @@ void i9xx_check_fifo_underruns(struct drm_device *dev)
                DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe));
        }
 
-       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+       spin_unlock_irq(&dev_priv->irq_lock);
 }
 
 static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev,
@@ -503,7 +510,7 @@ static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
                ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
        else if (IS_GEN7(dev))
                ivybridge_set_fifo_underrun_reporting(dev, pipe, enable, old);
-       else if (IS_GEN8(dev))
+       else if (IS_GEN8(dev) || IS_GEN9(dev))
                broadwell_set_fifo_underrun_reporting(dev, pipe, enable);
 
        return old;
@@ -589,6 +596,7 @@ __i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
        u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK;
 
        assert_spin_locked(&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,
@@ -615,6 +623,7 @@ __i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
        u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK;
 
        assert_spin_locked(&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,
@@ -694,19 +703,18 @@ i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
 static void i915_enable_asle_pipestat(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long irqflags;
 
        if (!dev_priv->opregion.asle || !IS_MOBILE(dev))
                return;
 
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       spin_lock_irq(&dev_priv->irq_lock);
 
        i915_enable_pipestat(dev_priv, PIPE_B, PIPE_LEGACY_BLC_EVENT_STATUS);
        if (INTEL_INFO(dev)->gen >= 4)
                i915_enable_pipestat(dev_priv, PIPE_A,
                                     PIPE_LEGACY_BLC_EVENT_STATUS);
 
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       spin_unlock_irq(&dev_priv->irq_lock);
 }
 
 /**
@@ -1094,18 +1102,17 @@ static void i915_digport_work_func(struct work_struct *work)
 {
        struct drm_i915_private *dev_priv =
                container_of(work, struct drm_i915_private, dig_port_work);
-       unsigned long irqflags;
        u32 long_port_mask, short_port_mask;
        struct intel_digital_port *intel_dig_port;
        int i, ret;
        u32 old_bits = 0;
 
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       spin_lock_irq(&dev_priv->irq_lock);
        long_port_mask = dev_priv->long_hpd_port_mask;
        dev_priv->long_hpd_port_mask = 0;
        short_port_mask = dev_priv->short_hpd_port_mask;
        dev_priv->short_hpd_port_mask = 0;
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       spin_unlock_irq(&dev_priv->irq_lock);
 
        for (i = 0; i < I915_MAX_PORTS; i++) {
                bool valid = false;
@@ -1130,9 +1137,9 @@ static void i915_digport_work_func(struct work_struct *work)
        }
 
        if (old_bits) {
-               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+               spin_lock_irq(&dev_priv->irq_lock);
                dev_priv->hpd_event_bits |= old_bits;
-               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+               spin_unlock_irq(&dev_priv->irq_lock);
                schedule_work(&dev_priv->hotplug_work);
        }
 }
@@ -1151,7 +1158,6 @@ static void i915_hotplug_work_func(struct work_struct *work)
        struct intel_connector *intel_connector;
        struct intel_encoder *intel_encoder;
        struct drm_connector *connector;
-       unsigned long irqflags;
        bool hpd_disabled = false;
        bool changed = false;
        u32 hpd_event_bits;
@@ -1159,7 +1165,7 @@ static void i915_hotplug_work_func(struct work_struct *work)
        mutex_lock(&mode_config->mutex);
        DRM_DEBUG_KMS("running encoder hotplug functions\n");
 
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       spin_lock_irq(&dev_priv->irq_lock);
 
        hpd_event_bits = dev_priv->hpd_event_bits;
        dev_priv->hpd_event_bits = 0;
@@ -1193,7 +1199,7 @@ static void i915_hotplug_work_func(struct work_struct *work)
                                 msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY));
        }
 
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       spin_unlock_irq(&dev_priv->irq_lock);
 
        list_for_each_entry(connector, &mode_config->connector_list, head) {
                intel_connector = to_intel_connector(connector);
@@ -1488,7 +1494,6 @@ static void ivybridge_parity_work(struct work_struct *work)
        u32 error_status, row, bank, subbank;
        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.
@@ -1547,9 +1552,9 @@ static void ivybridge_parity_work(struct work_struct *work)
 
 out:
        WARN_ON(dev_priv->l3_parity.which_slice);
-       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       spin_lock_irq(&dev_priv->irq_lock);
        gen5_enable_gt_irq(dev_priv, GT_PARITY_ERROR(dev_priv->dev));
-       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+       spin_unlock_irq(&dev_priv->irq_lock);
 
        mutex_unlock(&dev_priv->dev->struct_mutex);
 }
@@ -2566,7 +2571,7 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
        }
 
        for_each_pipe(dev_priv, pipe) {
-               uint32_t pipe_iir;
+               uint32_t pipe_iir, flip_done = 0, fault_errors = 0;
 
                if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe)))
                        continue;
@@ -2575,11 +2580,17 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
                if (pipe_iir) {
                        ret = IRQ_HANDLED;
                        I915_WRITE(GEN8_DE_PIPE_IIR(pipe), pipe_iir);
+
                        if (pipe_iir & GEN8_PIPE_VBLANK &&
                            intel_pipe_handle_vblank(dev, pipe))
                                intel_check_page_flip(dev, pipe);
 
-                       if (pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE) {
+                       if (IS_GEN9(dev))
+                               flip_done = pipe_iir & GEN9_PIPE_PLANE1_FLIP_DONE;
+                       else
+                               flip_done = pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE;
+
+                       if (flip_done) {
                                intel_prepare_page_flip(dev, pipe);
                                intel_finish_page_flip_plane(dev, pipe);
                        }
@@ -2594,11 +2605,16 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
                                                  pipe_name(pipe));
                        }
 
-                       if (pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS) {
+
+                       if (IS_GEN9(dev))
+                               fault_errors = pipe_iir & GEN9_DE_PIPE_IRQ_FAULT_ERRORS;
+                       else
+                               fault_errors = pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
+
+                       if (fault_errors)
                                DRM_ERROR("Fault errors on pipe %c\n: 0x%08x",
                                          pipe_name(pipe),
                                          pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS);
-                       }
                } else
                        DRM_ERROR("The master control interrupt lied (DE PIPE)!\n");
        }
@@ -3444,8 +3460,8 @@ static void gen8_irq_reset(struct drm_device *dev)
        gen8_gt_irq_reset(dev_priv);
 
        for_each_pipe(dev_priv, pipe)
-               if (intel_display_power_enabled(dev_priv,
-                                               POWER_DOMAIN_PIPE(pipe)))
+               if (intel_display_power_is_enabled(dev_priv,
+                                                  POWER_DOMAIN_PIPE(pipe)))
                        GEN8_IRQ_RESET_NDX(DE_PIPE, pipe);
 
        GEN5_IRQ_RESET(GEN8_DE_PORT_);
@@ -3457,15 +3473,14 @@ static void gen8_irq_reset(struct drm_device *dev)
 
 void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv)
 {
-       unsigned long irqflags;
        uint32_t extra_ier = GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN;
 
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       spin_lock_irq(&dev_priv->irq_lock);
        GEN8_IRQ_INIT_NDX(DE_PIPE, PIPE_B, dev_priv->de_irq_mask[PIPE_B],
                          ~dev_priv->de_irq_mask[PIPE_B] | extra_ier);
        GEN8_IRQ_INIT_NDX(DE_PIPE, PIPE_C, dev_priv->de_irq_mask[PIPE_C],
                          ~dev_priv->de_irq_mask[PIPE_C] | extra_ier);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       spin_unlock_irq(&dev_priv->irq_lock);
 }
 
 static void cherryview_irq_preinstall(struct drm_device *dev)
@@ -3584,7 +3599,6 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
 
 static int ironlake_irq_postinstall(struct drm_device *dev)
 {
-       unsigned long irqflags;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 display_mask, extra_mask;
 
@@ -3623,9 +3637,9 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
                 * spinlocking not required here for correctness since interrupt
                 * setup is guaranteed to run in single-threaded context. But we
                 * need it to make the assert_spin_locked happy. */
-               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+               spin_lock_irq(&dev_priv->irq_lock);
                ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
-               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+               spin_unlock_irq(&dev_priv->irq_lock);
        }
 
        return 0;
@@ -3701,7 +3715,7 @@ void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv)
 
        dev_priv->display_irqs_enabled = true;
 
-       if (dev_priv->dev->irq_enabled)
+       if (intel_irqs_enabled(dev_priv))
                valleyview_display_irqs_install(dev_priv);
 }
 
@@ -3714,14 +3728,13 @@ void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv)
 
        dev_priv->display_irqs_enabled = false;
 
-       if (dev_priv->dev->irq_enabled)
+       if (intel_irqs_enabled(dev_priv))
                valleyview_display_irqs_uninstall(dev_priv);
 }
 
 static int valleyview_irq_postinstall(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long irqflags;
 
        dev_priv->irq_mask = ~0;
 
@@ -3735,10 +3748,10 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
 
        /* Interrupt setup is already guaranteed to be single-threaded, this is
         * just to make the assert_spin_locked check happy. */
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       spin_lock_irq(&dev_priv->irq_lock);
        if (dev_priv->display_irqs_enabled)
                valleyview_display_irqs_install(dev_priv);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       spin_unlock_irq(&dev_priv->irq_lock);
 
        I915_WRITE(VLV_IIR, 0xffffffff);
        I915_WRITE(VLV_IIR, 0xffffffff);
@@ -3783,18 +3796,26 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
 
 static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
 {
-       uint32_t de_pipe_masked = GEN8_PIPE_PRIMARY_FLIP_DONE |
-               GEN8_PIPE_CDCLK_CRC_DONE |
-               GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
-       uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
-               GEN8_PIPE_FIFO_UNDERRUN;
+       uint32_t de_pipe_masked = GEN8_PIPE_CDCLK_CRC_DONE;
+       uint32_t de_pipe_enables;
        int pipe;
+
+       if (IS_GEN9(dev_priv))
+               de_pipe_masked |= GEN9_PIPE_PLANE1_FLIP_DONE |
+                                 GEN9_DE_PIPE_IRQ_FAULT_ERRORS;
+       else
+               de_pipe_masked |= GEN8_PIPE_PRIMARY_FLIP_DONE |
+                                 GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
+
+       de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
+                                          GEN8_PIPE_FIFO_UNDERRUN;
+
        dev_priv->de_irq_mask[PIPE_A] = ~de_pipe_masked;
        dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked;
        dev_priv->de_irq_mask[PIPE_C] = ~de_pipe_masked;
 
        for_each_pipe(dev_priv, pipe)
-               if (intel_display_power_enabled(dev_priv,
+               if (intel_display_power_is_enabled(dev_priv,
                                POWER_DOMAIN_PIPE(pipe)))
                        GEN8_IRQ_INIT_NDX(DE_PIPE, pipe,
                                          dev_priv->de_irq_mask[pipe],
@@ -3829,7 +3850,6 @@ static int cherryview_irq_postinstall(struct drm_device *dev)
                I915_DISPLAY_PIPE_C_EVENT_INTERRUPT;
        u32 pipestat_enable = PLANE_FLIP_DONE_INT_STATUS_VLV |
                PIPE_CRC_DONE_INTERRUPT_STATUS;
-       unsigned long irqflags;
        int pipe;
 
        /*
@@ -3841,11 +3861,11 @@ static int cherryview_irq_postinstall(struct drm_device *dev)
        for_each_pipe(dev_priv, pipe)
                I915_WRITE(PIPESTAT(pipe), 0xffff);
 
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       spin_lock_irq(&dev_priv->irq_lock);
        i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
        for_each_pipe(dev_priv, pipe)
                i915_enable_pipestat(dev_priv, pipe, pipestat_enable);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       spin_unlock_irq(&dev_priv->irq_lock);
 
        I915_WRITE(VLV_IIR, 0xffffffff);
        I915_WRITE(VLV_IMR, dev_priv->irq_mask);
@@ -3872,7 +3892,6 @@ static void gen8_irq_uninstall(struct drm_device *dev)
 static void valleyview_irq_uninstall(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long irqflags;
        int pipe;
 
        if (!dev_priv)
@@ -3887,10 +3906,12 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
 
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       /* 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);
        if (dev_priv->display_irqs_enabled)
                valleyview_display_irqs_uninstall(dev_priv);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       spin_unlock_irq(&dev_priv->irq_lock);
 
        dev_priv->irq_mask = 0;
 
@@ -3976,7 +3997,6 @@ static void i8xx_irq_preinstall(struct drm_device * dev)
 static int i8xx_irq_postinstall(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long irqflags;
 
        I915_WRITE16(EMR,
                     ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
@@ -3999,10 +4019,10 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
 
        /* Interrupt setup is already guaranteed to be single-threaded, this is
         * just to make the assert_spin_locked check happy. */
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       spin_lock_irq(&dev_priv->irq_lock);
        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_irqrestore(&dev_priv->irq_lock, irqflags);
+       spin_unlock_irq(&dev_priv->irq_lock);
 
        return 0;
 }
@@ -4047,7 +4067,6 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
        struct drm_i915_private *dev_priv = dev->dev_private;
        u16 iir, new_iir;
        u32 pipe_stats[2];
-       unsigned long irqflags;
        int pipe;
        u16 flip_mask =
                I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
@@ -4063,7 +4082,7 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                 * It doesn't set the bit in iir again, but it still produces
                 * interrupts (for non-MSI).
                 */
-               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+               spin_lock(&dev_priv->irq_lock);
                if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
                        i915_handle_error(dev, false,
                                          "Command parser error, iir 0x%08x",
@@ -4079,7 +4098,7 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                        if (pipe_stats[pipe] & 0x8000ffff)
                                I915_WRITE(reg, pipe_stats[pipe]);
                }
-               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+               spin_unlock(&dev_priv->irq_lock);
 
                I915_WRITE16(IIR, iir & ~flip_mask);
                new_iir = I915_READ16(IIR); /* Flush posted writes */
@@ -4149,7 +4168,6 @@ static int i915_irq_postinstall(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 enable_mask;
-       unsigned long irqflags;
 
        I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
 
@@ -4187,10 +4205,10 @@ static int i915_irq_postinstall(struct drm_device *dev)
 
        /* Interrupt setup is already guaranteed to be single-threaded, this is
         * just to make the assert_spin_locked check happy. */
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       spin_lock_irq(&dev_priv->irq_lock);
        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_irqrestore(&dev_priv->irq_lock, irqflags);
+       spin_unlock_irq(&dev_priv->irq_lock);
 
        return 0;
 }
@@ -4234,7 +4252,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
        struct drm_device *dev = arg;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 iir, new_iir, pipe_stats[I915_MAX_PIPES];
-       unsigned long irqflags;
        u32 flip_mask =
                I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
@@ -4250,7 +4267,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                 * It doesn't set the bit in iir again, but it still produces
                 * interrupts (for non-MSI).
                 */
-               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+               spin_lock(&dev_priv->irq_lock);
                if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
                        i915_handle_error(dev, false,
                                          "Command parser error, iir 0x%08x",
@@ -4266,7 +4283,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                                irq_received = true;
                        }
                }
-               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+               spin_unlock(&dev_priv->irq_lock);
 
                if (!irq_received)
                        break;
@@ -4372,7 +4389,6 @@ static int i965_irq_postinstall(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 enable_mask;
        u32 error_mask;
-       unsigned long irqflags;
 
        /* Unmask the interrupts that we always want on. */
        dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT |
@@ -4393,11 +4409,11 @@ static int i965_irq_postinstall(struct drm_device *dev)
 
        /* Interrupt setup is already guaranteed to be single-threaded, this is
         * just to make the assert_spin_locked check happy. */
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       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_irqrestore(&dev_priv->irq_lock, irqflags);
+       spin_unlock_irq(&dev_priv->irq_lock);
 
        /*
         * Enable some error detection, note the instruction error mask
@@ -4462,7 +4478,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 iir, new_iir;
        u32 pipe_stats[I915_MAX_PIPES];
-       unsigned long irqflags;
        int ret = IRQ_NONE, pipe;
        u32 flip_mask =
                I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
@@ -4479,7 +4494,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                 * It doesn't set the bit in iir again, but it still produces
                 * interrupts (for non-MSI).
                 */
-               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+               spin_lock(&dev_priv->irq_lock);
                if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
                        i915_handle_error(dev, false,
                                          "Command parser error, iir 0x%08x",
@@ -4497,7 +4512,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                                irq_received = true;
                        }
                }
-               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+               spin_unlock(&dev_priv->irq_lock);
 
                if (!irq_received)
                        break;
@@ -4584,19 +4599,18 @@ static void i965_irq_uninstall(struct drm_device * dev)
        I915_WRITE(IIR, I915_READ(IIR));
 }
 
-static void intel_hpd_irq_reenable(struct work_struct *work)
+static void intel_hpd_irq_reenable_work(struct work_struct *work)
 {
        struct drm_i915_private *dev_priv =
                container_of(work, typeof(*dev_priv),
                             hotplug_reenable_work.work);
        struct drm_device *dev = dev_priv->dev;
        struct drm_mode_config *mode_config = &dev->mode_config;
-       unsigned long irqflags;
        int i;
 
        intel_runtime_pm_get(dev_priv);
 
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       spin_lock_irq(&dev_priv->irq_lock);
        for (i = (HPD_NONE + 1); i < HPD_NUM_PINS; i++) {
                struct drm_connector *connector;
 
@@ -4620,14 +4634,21 @@ static void intel_hpd_irq_reenable(struct work_struct *work)
        }
        if (dev_priv->display.hpd_irq_setup)
                dev_priv->display.hpd_irq_setup(dev);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       spin_unlock_irq(&dev_priv->irq_lock);
 
        intel_runtime_pm_put(dev_priv);
 }
 
-void intel_irq_init(struct drm_device *dev)
+/**
+ * intel_irq_init - initializes irq support
+ * @dev_priv: i915 device instance
+ *
+ * This function initializes all the irq support including work items, timers
+ * and all the vtables. It does not setup the interrupt itself though.
+ */
+void intel_irq_init(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_device *dev = dev_priv->dev;
 
        INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
        INIT_WORK(&dev_priv->dig_port_work, i915_digport_work_func);
@@ -4636,7 +4657,7 @@ void intel_irq_init(struct drm_device *dev)
        INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
 
        /* Let's track the enabled rps events */
-       if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev))
+       if (IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv))
                /* WaGsvRC0ResidencyMethod:vlv */
                dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED;
        else
@@ -4646,17 +4667,14 @@ void intel_irq_init(struct drm_device *dev)
                    i915_hangcheck_elapsed,
                    (unsigned long) dev);
        INIT_DELAYED_WORK(&dev_priv->hotplug_reenable_work,
-                         intel_hpd_irq_reenable);
+                         intel_hpd_irq_reenable_work);
 
        pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
 
-       /* Haven't installed the IRQ handler yet */
-       dev_priv->pm._irqs_disabled = true;
-
-       if (IS_GEN2(dev)) {
+       if (IS_GEN2(dev_priv)) {
                dev->max_vblank_count = 0;
                dev->driver->get_vblank_counter = i8xx_get_vblank_counter;
-       } else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
+       } else if (IS_G4X(dev_priv) || INTEL_INFO(dev_priv)->gen >= 5) {
                dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
                dev->driver->get_vblank_counter = gm45_get_vblank_counter;
        } else {
@@ -4669,7 +4687,7 @@ void intel_irq_init(struct drm_device *dev)
         * Gen2 doesn't have a hardware frame counter and so depends on
         * vblank interrupts to produce sane vblank seuquence numbers.
         */
-       if (!IS_GEN2(dev))
+       if (!IS_GEN2(dev_priv))
                dev->vblank_disable_immediate = true;
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
@@ -4677,7 +4695,7 @@ void intel_irq_init(struct drm_device *dev)
                dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
        }
 
-       if (IS_CHERRYVIEW(dev)) {
+       if (IS_CHERRYVIEW(dev_priv)) {
                dev->driver->irq_handler = cherryview_irq_handler;
                dev->driver->irq_preinstall = cherryview_irq_preinstall;
                dev->driver->irq_postinstall = cherryview_irq_postinstall;
@@ -4685,7 +4703,7 @@ void intel_irq_init(struct drm_device *dev)
                dev->driver->enable_vblank = valleyview_enable_vblank;
                dev->driver->disable_vblank = valleyview_disable_vblank;
                dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
-       } else if (IS_VALLEYVIEW(dev)) {
+       } else if (IS_VALLEYVIEW(dev_priv)) {
                dev->driver->irq_handler = valleyview_irq_handler;
                dev->driver->irq_preinstall = valleyview_irq_preinstall;
                dev->driver->irq_postinstall = valleyview_irq_postinstall;
@@ -4693,7 +4711,7 @@ void intel_irq_init(struct drm_device *dev)
                dev->driver->enable_vblank = valleyview_enable_vblank;
                dev->driver->disable_vblank = valleyview_disable_vblank;
                dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
-       } else if (IS_GEN8(dev)) {
+       } else if (INTEL_INFO(dev_priv)->gen >= 8) {
                dev->driver->irq_handler = gen8_irq_handler;
                dev->driver->irq_preinstall = gen8_irq_reset;
                dev->driver->irq_postinstall = gen8_irq_postinstall;
@@ -4710,12 +4728,12 @@ void intel_irq_init(struct drm_device *dev)
                dev->driver->disable_vblank = ironlake_disable_vblank;
                dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup;
        } else {
-               if (INTEL_INFO(dev)->gen == 2) {
+               if (INTEL_INFO(dev_priv)->gen == 2) {
                        dev->driver->irq_preinstall = i8xx_irq_preinstall;
                        dev->driver->irq_postinstall = i8xx_irq_postinstall;
                        dev->driver->irq_handler = i8xx_irq_handler;
                        dev->driver->irq_uninstall = i8xx_irq_uninstall;
-               } else if (INTEL_INFO(dev)->gen == 3) {
+               } else if (INTEL_INFO(dev_priv)->gen == 3) {
                        dev->driver->irq_preinstall = i915_irq_preinstall;
                        dev->driver->irq_postinstall = i915_irq_postinstall;
                        dev->driver->irq_uninstall = i915_irq_uninstall;
@@ -4733,12 +4751,23 @@ void intel_irq_init(struct drm_device *dev)
        }
 }
 
-void intel_hpd_init(struct drm_device *dev)
+/**
+ * intel_hpd_init - initializes and enables hpd support
+ * @dev_priv: i915 device instance
+ *
+ * This function enables the hotplug support. It requires that interrupts have
+ * already been enabled with intel_irq_init_hw(). From this point on hotplug and
+ * poll request can run concurrently to other code, so locking rules must be
+ * obeyed.
+ *
+ * This is a separate step from interrupt enabling to simplify the locking rules
+ * in the driver load and resume code.
+ */
+void intel_hpd_init(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_device *dev = dev_priv->dev;
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct drm_connector *connector;
-       unsigned long irqflags;
        int i;
 
        for (i = 1; i < HPD_NUM_PINS; i++) {
@@ -4756,27 +4785,72 @@ void intel_hpd_init(struct drm_device *dev)
 
        /* Interrupt setup is already guaranteed to be single-threaded, this is
         * just to make the assert_spin_locked checks happy. */
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       spin_lock_irq(&dev_priv->irq_lock);
        if (dev_priv->display.hpd_irq_setup)
                dev_priv->display.hpd_irq_setup(dev);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       spin_unlock_irq(&dev_priv->irq_lock);
 }
 
-/* Disable interrupts so we can allow runtime PM. */
-void intel_runtime_pm_disable_interrupts(struct drm_device *dev)
+/**
+ * intel_irq_install - enables the hardware interrupt
+ * @dev_priv: i915 device instance
+ *
+ * This function enables the hardware interrupt handling, but leaves the hotplug
+ * handling still disabled. It is called after intel_irq_init().
+ *
+ * In the driver load and resume code we need working interrupts in a few places
+ * but don't want to deal with the hassle of concurrent probe and hotplug
+ * workers. Hence the split into this two-stage approach.
+ */
+int intel_irq_install(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       /*
+        * We enable some interrupt sources in our postinstall hooks, so mark
+        * interrupts as enabled _before_ actually enabling them to avoid
+        * special cases in our ordering checks.
+        */
+       dev_priv->pm.irqs_enabled = true;
 
-       dev->driver->irq_uninstall(dev);
-       dev_priv->pm._irqs_disabled = true;
+       return drm_irq_install(dev_priv->dev, dev_priv->dev->pdev->irq);
 }
 
-/* Restore interrupts so we can recover from runtime PM. */
-void intel_runtime_pm_restore_interrupts(struct drm_device *dev)
+/**
+ * intel_irq_uninstall - finilizes all irq handling
+ * @dev_priv: i915 device instance
+ *
+ * This stops interrupt and hotplug handling and unregisters and frees all
+ * resources acquired in the init functions.
+ */
+void intel_irq_uninstall(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       drm_irq_uninstall(dev_priv->dev);
+       intel_hpd_cancel_work(dev_priv);
+       dev_priv->pm.irqs_enabled = false;
+}
+
+/**
+ * intel_runtime_pm_disable_interrupts - runtime interrupt disabling
+ * @dev_priv: i915 device instance
+ *
+ * This function is used to disable interrupts at runtime, both in the runtime
+ * pm and the system suspend/resume code.
+ */
+void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv)
+{
+       dev_priv->dev->driver->irq_uninstall(dev_priv->dev);
+       dev_priv->pm.irqs_enabled = false;
+}
 
-       dev_priv->pm._irqs_disabled = false;
-       dev->driver->irq_preinstall(dev);
-       dev->driver->irq_postinstall(dev);
+/**
+ * intel_runtime_pm_enable_interrupts - runtime interrupt enabling
+ * @dev_priv: i915 device instance
+ *
+ * This function is used to enable interrupts at runtime, both in the runtime
+ * pm and the system suspend/resume code.
+ */
+void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv)
+{
+       dev_priv->pm.irqs_enabled = true;
+       dev_priv->dev->driver->irq_preinstall(dev_priv->dev);
+       dev_priv->dev->driver->irq_postinstall(dev_priv->dev);
 }