drm/i915: Drop pipe_enable checks in vblank funcs
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / i915 / i915_irq.c
index ba86dc3305476c247404f9f35b257286bd547e88..854590fba8fc73d57528d288fc191d60e2741c47 100644 (file)
@@ -45,7 +45,7 @@
  * and related files, but that will be described in separate chapters.
  */
 
-static const u32 hpd_ibx[] = {
+static const u32 hpd_ibx[HPD_NUM_PINS] = {
        [HPD_CRT] = SDE_CRT_HOTPLUG,
        [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG,
        [HPD_PORT_B] = SDE_PORTB_HOTPLUG,
@@ -53,7 +53,7 @@ static const u32 hpd_ibx[] = {
        [HPD_PORT_D] = SDE_PORTD_HOTPLUG
 };
 
-static const u32 hpd_cpt[] = {
+static const u32 hpd_cpt[HPD_NUM_PINS] = {
        [HPD_CRT] = SDE_CRT_HOTPLUG_CPT,
        [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG_CPT,
        [HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT,
@@ -61,7 +61,7 @@ static const u32 hpd_cpt[] = {
        [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT
 };
 
-static const u32 hpd_mask_i915[] = {
+static const u32 hpd_mask_i915[HPD_NUM_PINS] = {
        [HPD_CRT] = CRT_HOTPLUG_INT_EN,
        [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN,
        [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN,
@@ -70,7 +70,7 @@ static const u32 hpd_mask_i915[] = {
        [HPD_PORT_D] = PORTD_HOTPLUG_INT_EN
 };
 
-static const u32 hpd_status_g4x[] = {
+static const u32 hpd_status_g4x[HPD_NUM_PINS] = {
        [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
        [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X,
        [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X,
@@ -79,7 +79,7 @@ static const u32 hpd_status_g4x[] = {
        [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
 };
 
-static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
+static const u32 hpd_status_i915[HPD_NUM_PINS] = { /* i915 and valleyview are the same */
        [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
        [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915,
        [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915,
@@ -183,6 +183,8 @@ static void ilk_update_gt_irq(struct drm_i915_private *dev_priv,
 {
        assert_spin_locked(&dev_priv->irq_lock);
 
+       WARN_ON(enabled_irq_mask & ~interrupt_mask);
+
        if (WARN_ON(!intel_irqs_enabled(dev_priv)))
                return;
 
@@ -229,6 +231,8 @@ static void snb_update_pm_irq(struct drm_i915_private *dev_priv,
 {
        uint32_t new_val;
 
+       WARN_ON(enabled_irq_mask & ~interrupt_mask);
+
        assert_spin_locked(&dev_priv->irq_lock);
 
        new_val = dev_priv->pm_irq_mask;
@@ -295,8 +299,10 @@ void gen6_enable_rps_interrupts(struct drm_device *dev)
 u32 gen6_sanitize_rps_pm_mask(struct drm_i915_private *dev_priv, u32 mask)
 {
        /*
-        * IVB and SNB hard hangs on looping batchbuffer
+        * SNB,IVB can while VLV,CHV may hard hang on looping batchbuffer
         * if GEN6_PM_UP_EI_EXPIRED is masked.
+        *
+        * TODO: verify if this can be reproduced on VLV,CHV.
         */
        if (INTEL_INFO(dev_priv)->gen <= 7 && !IS_HASWELL(dev_priv))
                mask &= ~GEN6_PM_RP_UP_EI_EXPIRED;
@@ -346,6 +352,8 @@ void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
        sdeimr &= ~interrupt_mask;
        sdeimr |= (~enabled_irq_mask & interrupt_mask);
 
+       WARN_ON(enabled_irq_mask & ~interrupt_mask);
+
        assert_spin_locked(&dev_priv->irq_lock);
 
        if (WARN_ON(!intel_irqs_enabled(dev_priv)))
@@ -484,31 +492,6 @@ static void i915_enable_asle_pipestat(struct drm_device *dev)
        spin_unlock_irq(&dev_priv->irq_lock);
 }
 
-/**
- * i915_pipe_enabled - check if a pipe is enabled
- * @dev: DRM device
- * @pipe: pipe to check
- *
- * Reading certain registers when the pipe is disabled can hang the chip.
- * Use this routine to make sure the PLL is running and the pipe is active
- * before reading such registers if unsure.
- */
-static int
-i915_pipe_enabled(struct drm_device *dev, int pipe)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               /* Locking is horribly broken here, but whatever. */
-               struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
-               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-               return intel_crtc->active;
-       } else {
-               return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE;
-       }
-}
-
 /*
  * This timing diagram depicts the video signal in and
  * around the vertical blanking period.
@@ -575,17 +558,11 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
        unsigned long low_frame;
        u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
 
-       if (!i915_pipe_enabled(dev, pipe)) {
-               DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
-                               "pipe %c\n", pipe_name(pipe));
-               return 0;
-       }
-
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                struct intel_crtc *intel_crtc =
                        to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
                const struct drm_display_mode *mode =
-                       &intel_crtc->config.adjusted_mode;
+                       &intel_crtc->config->base.adjusted_mode;
 
                htotal = mode->crtc_htotal;
                hsync_start = mode->crtc_hsync_start;
@@ -640,12 +617,6 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int reg = PIPE_FRMCOUNT_GM45(pipe);
 
-       if (!i915_pipe_enabled(dev, pipe)) {
-               DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
-                                "pipe %c\n", pipe_name(pipe));
-               return 0;
-       }
-
        return I915_READ(reg);
 }
 
@@ -656,7 +627,7 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       const struct drm_display_mode *mode = &crtc->config.adjusted_mode;
+       const struct drm_display_mode *mode = &crtc->config->base.adjusted_mode;
        enum pipe pipe = crtc->pipe;
        int position, vtotal;
 
@@ -683,7 +654,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       const struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode;
+       const struct drm_display_mode *mode = &intel_crtc->config->base.adjusted_mode;
        int position;
        int vbl_start, vbl_end, hsync_start, htotal, vtotal;
        bool in_vbl = true;
@@ -841,7 +812,7 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
        return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
                                                     vblank_time, flags,
                                                     crtc,
-                                                    &to_intel_crtc(crtc)->config.adjusted_mode);
+                                                    &to_intel_crtc(crtc)->config->base.adjusted_mode);
 }
 
 static bool intel_hpd_irq_event(struct drm_device *dev,
@@ -871,7 +842,7 @@ static void i915_digport_work_func(struct work_struct *work)
                container_of(work, struct drm_i915_private, dig_port_work);
        u32 long_port_mask, short_port_mask;
        struct intel_digital_port *intel_dig_port;
-       int i, ret;
+       int i;
        u32 old_bits = 0;
 
        spin_lock_irq(&dev_priv->irq_lock);
@@ -895,9 +866,11 @@ static void i915_digport_work_func(struct work_struct *work)
                        valid = true;
 
                if (valid) {
+                       enum irqreturn ret;
+
                        ret = intel_dig_port->hpd_pulse(intel_dig_port, long_hpd);
-                       if (ret == true) {
-                               /* if we get true fallback to old school hpd */
+                       if (ret == IRQ_NONE) {
+                               /* fall back to old school hpd */
                                old_bits |= (1 << intel_dig_port->base.hpd_pin);
                        }
                }
@@ -1031,7 +1004,7 @@ static void notify_ring(struct drm_device *dev,
        if (!intel_ring_initialized(ring))
                return;
 
-       trace_i915_gem_request_complete(ring);
+       trace_i915_gem_request_notify(ring);
 
        wake_up_all(&ring->irq_queue);
 }
@@ -1233,10 +1206,7 @@ static void gen6_pm_rps_work(struct work_struct *work)
 
        dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_freq;
 
-       if (IS_VALLEYVIEW(dev_priv->dev))
-               valleyview_set_rps(dev_priv->dev, new_delay);
-       else
-               gen6_set_rps(dev_priv->dev, new_delay);
+       intel_set_rps(dev_priv->dev, new_delay);
 
        mutex_unlock(&dev_priv->rps.hw_lock);
 }
@@ -1397,14 +1367,14 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
                        if (rcs & GT_RENDER_USER_INTERRUPT)
                                notify_ring(dev, ring);
                        if (rcs & GT_CONTEXT_SWITCH_INTERRUPT)
-                               intel_execlists_handle_ctx_events(ring);
+                               intel_lrc_irq_handler(ring);
 
                        bcs = tmp >> GEN8_BCS_IRQ_SHIFT;
                        ring = &dev_priv->ring[BCS];
                        if (bcs & GT_RENDER_USER_INTERRUPT)
                                notify_ring(dev, ring);
                        if (bcs & GT_CONTEXT_SWITCH_INTERRUPT)
-                               intel_execlists_handle_ctx_events(ring);
+                               intel_lrc_irq_handler(ring);
                } else
                        DRM_ERROR("The master control interrupt lied (GT0)!\n");
        }
@@ -1420,14 +1390,14 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
                        if (vcs & GT_RENDER_USER_INTERRUPT)
                                notify_ring(dev, ring);
                        if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
-                               intel_execlists_handle_ctx_events(ring);
+                               intel_lrc_irq_handler(ring);
 
                        vcs = tmp >> GEN8_VCS2_IRQ_SHIFT;
                        ring = &dev_priv->ring[VCS2];
                        if (vcs & GT_RENDER_USER_INTERRUPT)
                                notify_ring(dev, ring);
                        if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
-                               intel_execlists_handle_ctx_events(ring);
+                               intel_lrc_irq_handler(ring);
                } else
                        DRM_ERROR("The master control interrupt lied (GT1)!\n");
        }
@@ -1454,7 +1424,7 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
                        if (vcs & GT_RENDER_USER_INTERRUPT)
                                notify_ring(dev, ring);
                        if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
-                               intel_execlists_handle_ctx_events(ring);
+                               intel_lrc_irq_handler(ring);
                } else
                        DRM_ERROR("The master control interrupt lied (GT3)!\n");
        }
@@ -1514,7 +1484,7 @@ static inline enum port get_port_from_pin(enum hpd_pin pin)
 static inline void intel_hpd_irq_handler(struct drm_device *dev,
                                         u32 hotplug_trigger,
                                         u32 dig_hotplug_reg,
-                                        const u32 *hpd)
+                                        const u32 hpd[HPD_NUM_PINS])
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int i;
@@ -2411,19 +2381,15 @@ static void i915_error_wake_up(struct drm_i915_private *dev_priv,
 }
 
 /**
- * i915_error_work_func - do process context error handling work
- * @work: work struct
+ * i915_reset_and_wakeup - do process context error handling work
  *
  * Fire an error uevent so userspace can see that a hang or error
  * was detected.
  */
-static void i915_error_work_func(struct work_struct *work)
+static void i915_reset_and_wakeup(struct drm_device *dev)
 {
-       struct i915_gpu_error *error = container_of(work, struct i915_gpu_error,
-                                                   work);
-       struct drm_i915_private *dev_priv =
-               container_of(error, struct drm_i915_private, gpu_error);
-       struct drm_device *dev = dev_priv->dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct i915_gpu_error *error = &dev_priv->gpu_error;
        char *error_event[] = { I915_ERROR_UEVENT "=1", NULL };
        char *reset_event[] = { I915_RESET_UEVENT "=1", NULL };
        char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL };
@@ -2590,10 +2556,10 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
 }
 
 /**
- * i915_handle_error - handle an error interrupt
+ * i915_handle_error - handle a gpu error
  * @dev: drm device
  *
- * Do some basic checking of regsiter state at error interrupt time and
+ * Do some basic checking of regsiter state at error time and
  * dump it to the syslog.  Also call i915_capture_error_state() to make
  * sure we get a record and make it available in debugfs.  Fire a uevent
  * so userspace knows something bad happened (should trigger collection
@@ -2618,9 +2584,9 @@ void i915_handle_error(struct drm_device *dev, bool wedged,
                                &dev_priv->gpu_error.reset_counter);
 
                /*
-                * Wakeup waiting processes so that the reset work function
-                * i915_error_work_func doesn't deadlock trying to grab various
-                * locks. By bumping the reset counter first, the woken
+                * Wakeup waiting processes so that the reset function
+                * i915_reset_and_wakeup doesn't deadlock trying to grab
+                * various locks. By bumping the reset counter first, the woken
                 * processes will see a reset in progress and back off,
                 * releasing their locks and then wait for the reset completion.
                 * We must do this for _all_ gpu waiters that might hold locks
@@ -2633,13 +2599,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged,
                i915_error_wake_up(dev_priv, false);
        }
 
-       /*
-        * Our reset work can grab modeset locks (since it needs to reset the
-        * state of outstanding pagelips). Hence it must not be run on our own
-        * dev-priv->wq work queue for otherwise the flush_work in the pageflip
-        * code will deadlock.
-        */
-       schedule_work(&dev_priv->gpu_error.work);
+       i915_reset_and_wakeup(dev);
 }
 
 /* Called from drm generic code, passed 'crtc' which
@@ -2650,9 +2610,6 @@ static int i915_enable_vblank(struct drm_device *dev, int pipe)
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
 
-       if (!i915_pipe_enabled(dev, pipe))
-               return -EINVAL;
-
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        if (INTEL_INFO(dev)->gen >= 4)
                i915_enable_pipestat(dev_priv, pipe,
@@ -2672,9 +2629,6 @@ static int ironlake_enable_vblank(struct drm_device *dev, int pipe)
        uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) :
                                                     DE_PIPE_VBLANK(pipe);
 
-       if (!i915_pipe_enabled(dev, pipe))
-               return -EINVAL;
-
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        ironlake_enable_display_irq(dev_priv, bit);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
@@ -2687,9 +2641,6 @@ static int valleyview_enable_vblank(struct drm_device *dev, int pipe)
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
 
-       if (!i915_pipe_enabled(dev, pipe))
-               return -EINVAL;
-
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        i915_enable_pipestat(dev_priv, pipe,
                             PIPE_START_VBLANK_INTERRUPT_STATUS);
@@ -2703,9 +2654,6 @@ static int gen8_enable_vblank(struct drm_device *dev, int pipe)
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
 
-       if (!i915_pipe_enabled(dev, pipe))
-               return -EINVAL;
-
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_VBLANK;
        I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
@@ -2757,9 +2705,6 @@ static void gen8_disable_vblank(struct drm_device *dev, int pipe)
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
 
-       if (!i915_pipe_enabled(dev, pipe))
-               return;
-
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_VBLANK;
        I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
@@ -2767,18 +2712,18 @@ static void gen8_disable_vblank(struct drm_device *dev, int pipe)
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
-static u32
-ring_last_seqno(struct intel_engine_cs *ring)
+static struct drm_i915_gem_request *
+ring_last_request(struct intel_engine_cs *ring)
 {
        return list_entry(ring->request_list.prev,
-                         struct drm_i915_gem_request, list)->seqno;
+                         struct drm_i915_gem_request, list);
 }
 
 static bool
-ring_idle(struct intel_engine_cs *ring, u32 seqno)
+ring_idle(struct intel_engine_cs *ring)
 {
        return (list_empty(&ring->request_list) ||
-               i915_seqno_passed(seqno, ring_last_seqno(ring)));
+               i915_gem_request_completed(ring_last_request(ring), false));
 }
 
 static bool
@@ -2964,7 +2909,7 @@ ring_stuck(struct intel_engine_cs *ring, u64 acthd)
        return HANGCHECK_HUNG;
 }
 
-/**
+/*
  * This is called when the chip hasn't reported back with completed
  * batchbuffers in a long time. We keep track per ring seqno progress and
  * if there are no progress, hangcheck score for that ring is increased.
@@ -2972,10 +2917,12 @@ ring_stuck(struct intel_engine_cs *ring, u64 acthd)
  * we kick the ring. If we see no progress on three subsequent calls
  * we assume chip is wedged and try to fix it by resetting the chip.
  */
-static void i915_hangcheck_elapsed(unsigned long data)
+static void i915_hangcheck_elapsed(struct work_struct *work)
 {
-       struct drm_device *dev = (struct drm_device *)data;
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv =
+               container_of(work, typeof(*dev_priv),
+                            gpu_error.hangcheck_work.work);
+       struct drm_device *dev = dev_priv->dev;
        struct intel_engine_cs *ring;
        int i;
        int busy_count = 0, rings_hung = 0;
@@ -2998,7 +2945,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
                acthd = intel_ring_get_active_head(ring);
 
                if (ring->hangcheck.seqno == seqno) {
-                       if (ring_idle(ring, seqno)) {
+                       if (ring_idle(ring)) {
                                ring->hangcheck.action = HANGCHECK_IDLE;
 
                                if (waitqueue_active(&ring->irq_queue)) {
@@ -3089,17 +3036,18 @@ static void i915_hangcheck_elapsed(unsigned long data)
 
 void i915_queue_hangcheck(struct drm_device *dev)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct timer_list *timer = &dev_priv->gpu_error.hangcheck_timer;
+       struct i915_gpu_error *e = &to_i915(dev)->gpu_error;
 
        if (!i915.enable_hangcheck)
                return;
 
-       /* Don't continually defer the hangcheck, but make sure it is active */
-       if (timer_pending(timer))
-               return;
-       mod_timer(timer,
-                 round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
+       /* Don't continually defer the hangcheck so that it is always run at
+        * least once after work has been scheduled on any ring. Otherwise,
+        * we will ignore a hung ring if a second ring is kept busy.
+        */
+
+       queue_delayed_work(e->hangcheck_wq, &e->hangcheck_work,
+                          round_jiffies_up_relative(DRM_I915_HANGCHECK_JIFFIES));
 }
 
 static void ibx_irq_reset(struct drm_device *dev)
@@ -4137,26 +4085,24 @@ static void i915_hpd_irq_setup(struct drm_device *dev)
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (I915_HAS_HOTPLUG(dev)) {
-               hotplug_en = I915_READ(PORT_HOTPLUG_EN);
-               hotplug_en &= ~HOTPLUG_INT_EN_MASK;
-               /* Note HDMI and DP share hotplug bits */
-               /* enable bits are the same for all generations */
-               for_each_intel_encoder(dev, intel_encoder)
-                       if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
-                               hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin];
-               /* Programming the CRT detection parameters tends
-                  to generate a spurious hotplug event about three
-                  seconds later.  So just do it once.
-               */
-               if (IS_G4X(dev))
-                       hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
-               hotplug_en &= ~CRT_HOTPLUG_VOLTAGE_COMPARE_MASK;
-               hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
-
-               /* Ignore TV since it's buggy */
-               I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
-       }
+       hotplug_en = I915_READ(PORT_HOTPLUG_EN);
+       hotplug_en &= ~HOTPLUG_INT_EN_MASK;
+       /* Note HDMI and DP share hotplug bits */
+       /* enable bits are the same for all generations */
+       for_each_intel_encoder(dev, intel_encoder)
+               if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
+                       hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin];
+       /* Programming the CRT detection parameters tends
+          to generate a spurious hotplug event about three
+          seconds later.  So just do it once.
+       */
+       if (IS_G4X(dev))
+               hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
+       hotplug_en &= ~CRT_HOTPLUG_VOLTAGE_COMPARE_MASK;
+       hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
+
+       /* Ignore TV since it's buggy */
+       I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
 }
 
 static irqreturn_t i965_irq_handler(int irq, void *arg)
@@ -4334,7 +4280,6 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
 
        INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
        INIT_WORK(&dev_priv->dig_port_work, i915_digport_work_func);
-       INIT_WORK(&dev_priv->gpu_error.work, i915_error_work_func);
        INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work);
        INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
 
@@ -4345,9 +4290,8 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
        else
                dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
 
-       setup_timer(&dev_priv->gpu_error.hangcheck_timer,
-                   i915_hangcheck_elapsed,
-                   (unsigned long) dev);
+       INIT_DELAYED_WORK(&dev_priv->gpu_error.hangcheck_work,
+                         i915_hangcheck_elapsed);
        INIT_DELAYED_WORK(&dev_priv->hotplug_reenable_work,
                          intel_hpd_irq_reenable_work);
 
@@ -4420,14 +4364,14 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
                        dev->driver->irq_postinstall = i915_irq_postinstall;
                        dev->driver->irq_uninstall = i915_irq_uninstall;
                        dev->driver->irq_handler = i915_irq_handler;
-                       dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
                } else {
                        dev->driver->irq_preinstall = i965_irq_preinstall;
                        dev->driver->irq_postinstall = i965_irq_postinstall;
                        dev->driver->irq_uninstall = i965_irq_uninstall;
                        dev->driver->irq_handler = i965_irq_handler;
-                       dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
                }
+               if (I915_HAS_HOTPLUG(dev_priv))
+                       dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
                dev->driver->enable_vblank = i915_enable_vblank;
                dev->driver->disable_vblank = i915_disable_vblank;
        }