drm/i915: Drop pipe_enable checks in vblank funcs
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / i915 / i915_irq.c
index 49b2eab67c0d8defd748115a935a82d1e74ca8ff..854590fba8fc73d57528d288fc191d60e2741c47 100644 (file)
@@ -296,6 +296,23 @@ void gen6_enable_rps_interrupts(struct drm_device *dev)
        spin_unlock_irq(&dev_priv->irq_lock);
 }
 
+u32 gen6_sanitize_rps_pm_mask(struct drm_i915_private *dev_priv, u32 mask)
+{
+       /*
+        * 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;
+
+       if (INTEL_INFO(dev_priv)->gen >= 8)
+               mask &= ~GEN8_PMINTR_REDIRECT_TO_NON_DISP;
+
+       return mask;
+}
+
 void gen6_disable_rps_interrupts(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -308,8 +325,7 @@ void gen6_disable_rps_interrupts(struct drm_device *dev)
 
        spin_lock_irq(&dev_priv->irq_lock);
 
-       I915_WRITE(GEN6_PMINTRMSK, INTEL_INFO(dev_priv)->gen >= 8 ?
-                  ~GEN8_PMINTR_REDIRECT_TO_NON_DISP : ~0);
+       I915_WRITE(GEN6_PMINTRMSK, gen6_sanitize_rps_pm_mask(dev_priv, ~0));
 
        __gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events);
        I915_WRITE(gen6_pm_ier(dev_priv), I915_READ(gen6_pm_ier(dev_priv)) &
@@ -476,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.
@@ -567,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;
@@ -632,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);
 }
 
@@ -648,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;
 
@@ -675,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;
@@ -833,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,
@@ -863,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);
@@ -887,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);
                        }
                }
@@ -1225,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);
 }
@@ -2403,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 };
@@ -2582,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
@@ -2610,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
@@ -2625,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
@@ -2642,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,
@@ -2664,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);
@@ -2679,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);
@@ -2695,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]);
@@ -2749,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]);
@@ -2956,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.
@@ -2964,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;
@@ -3081,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)
@@ -4324,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);
 
@@ -4335,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);