]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'airlied/drm-prime-vmap' into drm-intel-next-queued
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 1 Jun 2012 08:49:16 +0000 (10:49 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 1 Jun 2012 08:52:54 +0000 (10:52 +0200)
We need the latest dma-buf code from Dave Airlie so that we can pimp
the backing storage handling code in drm/i915 with Chris Wilson's
unbound tracking and stolen mem backed gem object code.

Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
16 files changed:
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_sysfs.c
drivers/gpu/drm/i915/i915_trace.h
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_overlay.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_sdvo.c
include/drm/i915_drm.h

index f94792626b94fadae47303f150e7aff278d371ef..262a74d1f852f98ee1e7357eba67e0d35b7c7179 100644 (file)
@@ -1803,6 +1803,7 @@ struct drm_ioctl_desc i915_ioctls[] = {
        DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, intel_sprite_get_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_AUTH|DRM_UNLOCKED),
 };
 
 int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
index c9cfc67c2cf58acdf7871a6e81fda66d3c45dedb..ccabadd2b6c39ac6b613f394ef70e1ffa1a493f5 100644 (file)
@@ -656,6 +656,8 @@ typedef struct drm_i915_private {
                /** PPGTT used for aliasing the PPGTT with the GTT */
                struct i915_hw_ppgtt *aliasing_ppgtt;
 
+               u32 *l3_remap_info;
+
                struct shrinker inactive_shrinker;
 
                /**
@@ -816,6 +818,8 @@ typedef struct drm_i915_private {
 
        struct drm_property *broadcast_rgb_property;
        struct drm_property *force_audio_property;
+
+       struct work_struct parity_error_work;
 } drm_i915_private_t;
 
 /* Iterate over initialised rings */
@@ -1234,6 +1238,8 @@ int i915_gem_get_tiling(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
 int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
+int i915_gem_wait_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
 void i915_gem_load(struct drm_device *dev);
 int i915_gem_init_object(struct drm_gem_object *obj);
 int __must_check i915_gem_flush_ring(struct intel_ring_buffer *ring,
@@ -1312,6 +1318,7 @@ int __must_check i915_gem_object_set_domain(struct drm_i915_gem_object *obj,
 int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj);
 int __must_check i915_gem_init(struct drm_device *dev);
 int __must_check i915_gem_init_hw(struct drm_device *dev);
+void i915_gem_l3_remap(struct drm_device *dev);
 void i915_gem_init_swizzling(struct drm_device *dev);
 void i915_gem_init_ppgtt(struct drm_device *dev);
 void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
@@ -1320,8 +1327,8 @@ int __must_check i915_gem_idle(struct drm_device *dev);
 int __must_check i915_add_request(struct intel_ring_buffer *ring,
                                  struct drm_file *file,
                                  struct drm_i915_gem_request *request);
-int __must_check i915_wait_request(struct intel_ring_buffer *ring,
-                                  uint32_t seqno);
+int __must_check i915_wait_seqno(struct intel_ring_buffer *ring,
+                                uint32_t seqno);
 int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
 int __must_check
 i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj,
index 288d7b8f49ae48858a30c6ad1f9f7ce1d6d6e600..a20ac438b8ef3945b791e82bebc32b6013dc59eb 100644 (file)
@@ -1899,34 +1899,82 @@ i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno)
        return ret;
 }
 
+/**
+ * __wait_seqno - wait until execution of seqno has finished
+ * @ring: the ring expected to report seqno
+ * @seqno: duh!
+ * @interruptible: do an interruptible wait (normally yes)
+ * @timeout: in - how long to wait (NULL forever); out - how much time remaining
+ *
+ * Returns 0 if the seqno was found within the alloted time. Else returns the
+ * errno with remaining time filled in timeout argument.
+ */
 static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
-                       bool interruptible)
+                       bool interruptible, struct timespec *timeout)
 {
        drm_i915_private_t *dev_priv = ring->dev->dev_private;
-       int ret = 0;
+       struct timespec before, now, wait_time={1,0};
+       unsigned long timeout_jiffies;
+       long end;
+       bool wait_forever = true;
 
        if (i915_seqno_passed(ring->get_seqno(ring), seqno))
                return 0;
 
        trace_i915_gem_request_wait_begin(ring, seqno);
+
+       if (timeout != NULL) {
+               wait_time = *timeout;
+               wait_forever = false;
+       }
+
+       timeout_jiffies = timespec_to_jiffies(&wait_time);
+
        if (WARN_ON(!ring->irq_get(ring)))
                return -ENODEV;
 
+       /* Record current time in case interrupted by signal, or wedged * */
+       getrawmonotonic(&before);
+
 #define EXIT_COND \
        (i915_seqno_passed(ring->get_seqno(ring), seqno) || \
        atomic_read(&dev_priv->mm.wedged))
+       do {
+               if (interruptible)
+                       end = wait_event_interruptible_timeout(ring->irq_queue,
+                                                              EXIT_COND,
+                                                              timeout_jiffies);
+               else
+                       end = wait_event_timeout(ring->irq_queue, EXIT_COND,
+                                                timeout_jiffies);
 
-       if (interruptible)
-               ret = wait_event_interruptible(ring->irq_queue,
-                                              EXIT_COND);
-       else
-               wait_event(ring->irq_queue, EXIT_COND);
+               if (atomic_read(&dev_priv->mm.wedged))
+                       end = -EAGAIN;
+       } while (end == 0 && wait_forever);
+
+       getrawmonotonic(&now);
 
        ring->irq_put(ring);
        trace_i915_gem_request_wait_end(ring, seqno);
 #undef EXIT_COND
 
-       return ret;
+       if (timeout) {
+               struct timespec sleep_time = timespec_sub(now, before);
+               *timeout = timespec_sub(*timeout, sleep_time);
+       }
+
+       switch (end) {
+       case -EAGAIN: /* Wedged */
+       case -ERESTARTSYS: /* Signal */
+               return (int)end;
+       case 0: /* Timeout */
+               if (timeout)
+                       set_normalized_timespec(timeout, 0, 0);
+               return -ETIME;
+       default: /* Completed */
+               WARN_ON(end < 0); /* We're not aware of other errors */
+               return 0;
+       }
 }
 
 /**
@@ -1934,8 +1982,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
  * request and object lists appropriately for that event.
  */
 int
-i915_wait_request(struct intel_ring_buffer *ring,
-                 uint32_t seqno)
+i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno)
 {
        drm_i915_private_t *dev_priv = ring->dev->dev_private;
        int ret = 0;
@@ -1950,9 +1997,7 @@ i915_wait_request(struct intel_ring_buffer *ring,
        if (ret)
                return ret;
 
-       ret = __wait_seqno(ring, seqno, dev_priv->mm.interruptible);
-       if (atomic_read(&dev_priv->mm.wedged))
-               ret = -EAGAIN;
+       ret = __wait_seqno(ring, seqno, dev_priv->mm.interruptible, NULL);
 
        return ret;
 }
@@ -1975,7 +2020,7 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj)
         * it.
         */
        if (obj->active) {
-               ret = i915_wait_request(obj->ring, obj->last_rendering_seqno);
+               ret = i915_wait_seqno(obj->ring, obj->last_rendering_seqno);
                if (ret)
                        return ret;
                i915_gem_retire_requests_ring(obj->ring);
@@ -1984,6 +2029,92 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj)
        return 0;
 }
 
+/**
+ * i915_gem_wait_ioctl - implements DRM_IOCTL_I915_GEM_WAIT
+ * @DRM_IOCTL_ARGS: standard ioctl arguments
+ *
+ * Returns 0 if successful, else an error is returned with the remaining time in
+ * the timeout parameter.
+ *  -ETIME: object is still busy after timeout
+ *  -ERESTARTSYS: signal interrupted the wait
+ *  -ENONENT: object doesn't exist
+ * Also possible, but rare:
+ *  -EAGAIN: GPU wedged
+ *  -ENOMEM: damn
+ *  -ENODEV: Internal IRQ fail
+ *  -E?: The add request failed
+ *
+ * The wait ioctl with a timeout of 0 reimplements the busy ioctl. With any
+ * non-zero timeout parameter the wait ioctl will wait for the given number of
+ * nanoseconds on an object becoming unbusy. Since the wait itself does so
+ * without holding struct_mutex the object may become re-busied before this
+ * function completes. A similar but shorter * race condition exists in the busy
+ * ioctl
+ */
+int
+i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
+{
+       struct drm_i915_gem_wait *args = data;
+       struct drm_i915_gem_object *obj;
+       struct intel_ring_buffer *ring = NULL;
+       struct timespec timeout;
+       u32 seqno = 0;
+       int ret = 0;
+
+       timeout = ns_to_timespec(args->timeout_ns);
+
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
+
+       obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->bo_handle));
+       if (&obj->base == NULL) {
+               mutex_unlock(&dev->struct_mutex);
+               return -ENOENT;
+       }
+
+       /* Need to make sure the object is flushed first. This non-obvious
+        * flush is required to enforce that (active && !olr) == no wait
+        * necessary.
+        */
+       ret = i915_gem_object_flush_gpu_write_domain(obj);
+       if (ret)
+               goto out;
+
+       if (obj->active) {
+               seqno = obj->last_rendering_seqno;
+               ring = obj->ring;
+       }
+
+       if (seqno == 0)
+                goto out;
+
+       ret = i915_gem_check_olr(ring, seqno);
+       if (ret)
+               goto out;
+
+       /* Do this after OLR check to make sure we make forward progress polling
+        * on this IOCTL with a 0 timeout (like busy ioctl)
+        */
+       if (!args->timeout_ns) {
+               ret = -ETIME;
+               goto out;
+       }
+
+       drm_gem_object_unreference(&obj->base);
+       mutex_unlock(&dev->struct_mutex);
+
+       ret = __wait_seqno(ring, seqno, true, &timeout);
+       WARN_ON(!timespec_valid(&timeout));
+       args->timeout_ns = timespec_to_ns(&timeout);
+       return ret;
+
+out:
+       drm_gem_object_unreference(&obj->base);
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+}
+
 /**
  * i915_gem_object_sync - sync an object to a ring.
  *
@@ -2160,7 +2291,7 @@ static int i915_ring_idle(struct intel_ring_buffer *ring)
                        return ret;
        }
 
-       return i915_wait_request(ring, i915_gem_next_request_seqno(ring));
+       return i915_wait_seqno(ring, i915_gem_next_request_seqno(ring));
 }
 
 int i915_gpu_idle(struct drm_device *dev)
@@ -2364,7 +2495,7 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj)
        }
 
        if (obj->last_fenced_seqno) {
-               ret = i915_wait_request(obj->ring, obj->last_fenced_seqno);
+               ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno);
                if (ret)
                        return ret;
 
@@ -3030,7 +3161,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
        if (seqno == 0)
                return 0;
 
-       ret = __wait_seqno(ring, seqno, true);
+       ret = __wait_seqno(ring, seqno, true, NULL);
        if (ret == 0)
                queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
 
@@ -3435,6 +3566,38 @@ i915_gem_idle(struct drm_device *dev)
        return 0;
 }
 
+void i915_gem_l3_remap(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       u32 misccpctl;
+       int i;
+
+       if (!IS_IVYBRIDGE(dev))
+               return;
+
+       if (!dev_priv->mm.l3_remap_info)
+               return;
+
+       misccpctl = I915_READ(GEN7_MISCCPCTL);
+       I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
+       POSTING_READ(GEN7_MISCCPCTL);
+
+       for (i = 0; i < GEN7_L3LOG_SIZE; i += 4) {
+               u32 remap = I915_READ(GEN7_L3LOG_BASE + i);
+               if (remap && remap != dev_priv->mm.l3_remap_info[i/4])
+                       DRM_DEBUG("0x%x was already programmed to %x\n",
+                                 GEN7_L3LOG_BASE + i, remap);
+               if (remap && !dev_priv->mm.l3_remap_info[i/4])
+                       DRM_DEBUG_DRIVER("Clearing remapped register\n");
+               I915_WRITE(GEN7_L3LOG_BASE + i, dev_priv->mm.l3_remap_info[i/4]);
+       }
+
+       /* Make sure all the writes land before disabling dop clock gating */
+       POSTING_READ(GEN7_L3LOG_BASE);
+
+       I915_WRITE(GEN7_MISCCPCTL, misccpctl);
+}
+
 void i915_gem_init_swizzling(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -3524,6 +3687,8 @@ i915_gem_init_hw(struct drm_device *dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
        int ret;
 
+       i915_gem_l3_remap(dev);
+
        i915_gem_init_swizzling(dev);
 
        ret = intel_init_render_ring_buffer(dev);
index 1417660a93ec00a0a8a24cc797acc7b7754db063..0e876646d769c6cc5c7a1e03b054dd7770f74123 100644 (file)
@@ -375,6 +375,86 @@ static void gen6_pm_rps_work(struct work_struct *work)
        mutex_unlock(&dev_priv->dev->struct_mutex);
 }
 
+
+/**
+ * ivybridge_parity_work - Workqueue called when a parity error interrupt
+ * occurred.
+ * @work: workqueue struct
+ *
+ * Doesn't actually do anything except notify userspace. As a consequence of
+ * this event, userspace should try to remap the bad rows since statistically
+ * it is likely the same row is more likely to go bad again.
+ */
+static void ivybridge_parity_work(struct work_struct *work)
+{
+       drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
+                                                   parity_error_work);
+       u32 error_status, row, bank, subbank;
+       char *parity_event[5];
+       uint32_t misccpctl;
+       unsigned long flags;
+
+       /* We must turn off DOP level clock gating to access the L3 registers.
+        * In order to prevent a get/put style interface, acquire struct mutex
+        * any time we access those registers.
+        */
+       mutex_lock(&dev_priv->dev->struct_mutex);
+
+       misccpctl = I915_READ(GEN7_MISCCPCTL);
+       I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
+       POSTING_READ(GEN7_MISCCPCTL);
+
+       error_status = I915_READ(GEN7_L3CDERRST1);
+       row = GEN7_PARITY_ERROR_ROW(error_status);
+       bank = GEN7_PARITY_ERROR_BANK(error_status);
+       subbank = GEN7_PARITY_ERROR_SUBBANK(error_status);
+
+       I915_WRITE(GEN7_L3CDERRST1, GEN7_PARITY_ERROR_VALID |
+                                   GEN7_L3CDERRST1_ENABLE);
+       POSTING_READ(GEN7_L3CDERRST1);
+
+       I915_WRITE(GEN7_MISCCPCTL, misccpctl);
+
+       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       dev_priv->gt_irq_mask &= ~GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
+       I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+
+       mutex_unlock(&dev_priv->dev->struct_mutex);
+
+       parity_event[0] = "L3_PARITY_ERROR=1";
+       parity_event[1] = kasprintf(GFP_KERNEL, "ROW=%d", row);
+       parity_event[2] = kasprintf(GFP_KERNEL, "BANK=%d", bank);
+       parity_event[3] = kasprintf(GFP_KERNEL, "SUBBANK=%d", subbank);
+       parity_event[4] = NULL;
+
+       kobject_uevent_env(&dev_priv->dev->primary->kdev.kobj,
+                          KOBJ_CHANGE, parity_event);
+
+       DRM_DEBUG("Parity error: Row = %d, Bank = %d, Sub bank = %d.\n",
+                 row, bank, subbank);
+
+       kfree(parity_event[3]);
+       kfree(parity_event[2]);
+       kfree(parity_event[1]);
+}
+
+static void ivybridge_handle_parity_error(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       unsigned long flags;
+
+       if (!IS_IVYBRIDGE(dev))
+               return;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       dev_priv->gt_irq_mask |= GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
+       I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+
+       queue_work(dev_priv->wq, &dev_priv->parity_error_work);
+}
+
 static void snb_gt_irq_handler(struct drm_device *dev,
                               struct drm_i915_private *dev_priv,
                               u32 gt_iir)
@@ -394,6 +474,9 @@ static void snb_gt_irq_handler(struct drm_device *dev,
                DRM_ERROR("GT error interrupt 0x%08x\n", gt_iir);
                i915_handle_error(dev, false);
        }
+
+       if (gt_iir & GT_GEN7_L3_PARITY_ERROR_INTERRUPT)
+               ivybridge_handle_parity_error(dev);
 }
 
 static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
@@ -1617,7 +1700,6 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
 
        atomic_set(&dev_priv->irq_received, 0);
 
-
        I915_WRITE(HWSTAM, 0xeffe);
 
        /* XXX hotplug from PCH */
@@ -1780,13 +1862,13 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
                   DE_PIPEA_VBLANK_IVB);
        POSTING_READ(DEIER);
 
-       dev_priv->gt_irq_mask = ~0;
+       dev_priv->gt_irq_mask = ~GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
 
        I915_WRITE(GTIIR, I915_READ(GTIIR));
        I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
 
        render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT |
-               GEN6_BLITTER_USER_INTERRUPT;
+               GEN6_BLITTER_USER_INTERRUPT | GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
        I915_WRITE(GTIER, render_irqs);
        POSTING_READ(GTIER);
 
@@ -2135,9 +2217,9 @@ static int i915_irq_postinstall(struct drm_device *dev)
                        hotplug_en |= HDMIC_HOTPLUG_INT_EN;
                if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
                        hotplug_en |= HDMID_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS)
+               if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915)
                        hotplug_en |= SDVOC_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS)
+               if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915)
                        hotplug_en |= SDVOB_HOTPLUG_INT_EN;
                if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
                        hotplug_en |= CRT_HOTPLUG_INT_EN;
@@ -2297,10 +2379,8 @@ static void i965_irq_preinstall(struct drm_device * dev)
 
        atomic_set(&dev_priv->irq_received, 0);
 
-       if (I915_HAS_HOTPLUG(dev)) {
-               I915_WRITE(PORT_HOTPLUG_EN, 0);
-               I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
-       }
+       I915_WRITE(PORT_HOTPLUG_EN, 0);
+       I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
 
        I915_WRITE(HWSTAM, 0xeffe);
        for_each_pipe(pipe)
@@ -2313,11 +2393,13 @@ static void i965_irq_preinstall(struct drm_device * dev)
 static int i965_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       u32 hotplug_en;
        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 |
@@ -2333,13 +2415,6 @@ static int i965_irq_postinstall(struct drm_device *dev)
        dev_priv->pipestat[0] = 0;
        dev_priv->pipestat[1] = 0;
 
-       if (I915_HAS_HOTPLUG(dev)) {
-               /* Enable in IER... */
-               enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
-               /* and unmask in IMR */
-               dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT;
-       }
-
        /*
         * Enable some error detection, note the instruction error mask
         * bit is reserved, so we leave it masked.
@@ -2359,36 +2434,40 @@ static int i965_irq_postinstall(struct drm_device *dev)
        I915_WRITE(IER, enable_mask);
        POSTING_READ(IER);
 
-       if (I915_HAS_HOTPLUG(dev)) {
-               u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
-
-               /* Note HDMI and DP share bits */
-               if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
-                       hotplug_en |= HDMIB_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS)
-                       hotplug_en |= HDMIC_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
-                       hotplug_en |= HDMID_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS)
+       /* Note HDMI and DP share hotplug bits */
+       hotplug_en = 0;
+       if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
+               hotplug_en |= HDMIB_HOTPLUG_INT_EN;
+       if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS)
+               hotplug_en |= HDMIC_HOTPLUG_INT_EN;
+       if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
+               hotplug_en |= HDMID_HOTPLUG_INT_EN;
+       if (IS_G4X(dev)) {
+               if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_G4X)
                        hotplug_en |= SDVOC_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS)
+               if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_G4X)
                        hotplug_en |= SDVOB_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
-                       hotplug_en |= CRT_HOTPLUG_INT_EN;
+       } else {
+               if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I965)
+                       hotplug_en |= SDVOC_HOTPLUG_INT_EN;
+               if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I965)
+                       hotplug_en |= SDVOB_HOTPLUG_INT_EN;
+       }
+       if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
+               hotplug_en |= CRT_HOTPLUG_INT_EN;
 
-                       /* 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_50;
-               }
+               /* 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_50;
+       }
 
-               /* Ignore TV since it's buggy */
+       /* Ignore TV since it's buggy */
 
-               I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
-       }
+       I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
 
        intel_opregion_enable_asle(dev);
 
@@ -2446,8 +2525,7 @@ static irqreturn_t i965_irq_handler(DRM_IRQ_ARGS)
                ret = IRQ_HANDLED;
 
                /* Consume port.  Then clear IIR or we'll miss events */
-               if ((I915_HAS_HOTPLUG(dev)) &&
-                   (iir & I915_DISPLAY_PORT_INTERRUPT)) {
+               if (iir & I915_DISPLAY_PORT_INTERRUPT) {
                        u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
 
                        DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
@@ -2520,10 +2598,8 @@ static void i965_irq_uninstall(struct drm_device * dev)
        if (!dev_priv)
                return;
 
-       if (I915_HAS_HOTPLUG(dev)) {
-               I915_WRITE(PORT_HOTPLUG_EN, 0);
-               I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
-       }
+       I915_WRITE(PORT_HOTPLUG_EN, 0);
+       I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
 
        I915_WRITE(HWSTAM, 0xffffffff);
        for_each_pipe(pipe)
@@ -2544,6 +2620,7 @@ void intel_irq_init(struct drm_device *dev)
        INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
        INIT_WORK(&dev_priv->error_work, i915_error_work_func);
        INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work);
+       INIT_WORK(&dev_priv->parity_error_work, ivybridge_parity_work);
 
        dev->driver->get_vblank_counter = i915_get_vblank_counter;
        dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
index 2d49b9507ed05b2f0693e3c52a22b36dc028b3da..7dcc04f2143e1dc0d80c3520de5a471d67b38c2c 100644 (file)
 #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV       (1 << 2)
 
 #define PORT_HOTPLUG_STAT      0x61114
-#define   HDMIB_HOTPLUG_INT_STATUS             (1 << 29)
-#define   DPB_HOTPLUG_INT_STATUS               (1 << 29)
-#define   HDMIC_HOTPLUG_INT_STATUS             (1 << 28)
-#define   DPC_HOTPLUG_INT_STATUS               (1 << 28)
-#define   HDMID_HOTPLUG_INT_STATUS             (1 << 27)
-#define   DPD_HOTPLUG_INT_STATUS               (1 << 27)
+/* HDMI/DP bits are gen4+ */
+#define   DPB_HOTPLUG_LIVE_STATUS               (1 << 29)
+#define   DPC_HOTPLUG_LIVE_STATUS               (1 << 28)
+#define   DPD_HOTPLUG_LIVE_STATUS               (1 << 27)
+#define   DPD_HOTPLUG_INT_STATUS               (3 << 21)
+#define   DPC_HOTPLUG_INT_STATUS               (3 << 19)
+#define   DPB_HOTPLUG_INT_STATUS               (3 << 17)
+/* HDMI bits are shared with the DP bits */
+#define   HDMIB_HOTPLUG_LIVE_STATUS             (1 << 29)
+#define   HDMIC_HOTPLUG_LIVE_STATUS             (1 << 28)
+#define   HDMID_HOTPLUG_LIVE_STATUS             (1 << 27)
+#define   HDMID_HOTPLUG_INT_STATUS             (3 << 21)
+#define   HDMIC_HOTPLUG_INT_STATUS             (3 << 19)
+#define   HDMIB_HOTPLUG_INT_STATUS             (3 << 17)
+/* CRT/TV common between gen3+ */
 #define   CRT_HOTPLUG_INT_STATUS               (1 << 11)
 #define   TV_HOTPLUG_INT_STATUS                        (1 << 10)
 #define   CRT_HOTPLUG_MONITOR_MASK             (3 << 8)
 #define   CRT_HOTPLUG_MONITOR_COLOR            (3 << 8)
 #define   CRT_HOTPLUG_MONITOR_MONO             (2 << 8)
 #define   CRT_HOTPLUG_MONITOR_NONE             (0 << 8)
-#define   SDVOC_HOTPLUG_INT_STATUS             (1 << 7)
-#define   SDVOB_HOTPLUG_INT_STATUS             (1 << 6)
+/* SDVO is different across gen3/4 */
+#define   SDVOC_HOTPLUG_INT_STATUS_G4X         (1 << 3)
+#define   SDVOB_HOTPLUG_INT_STATUS_G4X         (1 << 2)
+#define   SDVOC_HOTPLUG_INT_STATUS_I965                (3 << 4)
+#define   SDVOB_HOTPLUG_INT_STATUS_I965                (3 << 2)
+#define   SDVOC_HOTPLUG_INT_STATUS_I915                (1 << 7)
+#define   SDVOB_HOTPLUG_INT_STATUS_I915                (1 << 6)
 
 /* SDVO port control */
 #define SDVOB                  0x61140
 #define   VIDEO_DIP_PORT_C             (2 << 29)
 #define   VIDEO_DIP_PORT_D             (3 << 29)
 #define   VIDEO_DIP_PORT_MASK          (3 << 29)
+#define   VIDEO_DIP_ENABLE_GCP         (1 << 25)
 #define   VIDEO_DIP_ENABLE_AVI         (1 << 21)
 #define   VIDEO_DIP_ENABLE_VENDOR      (2 << 21)
+#define   VIDEO_DIP_ENABLE_GAMUT       (4 << 21)
 #define   VIDEO_DIP_ENABLE_SPD         (8 << 21)
 #define   VIDEO_DIP_SELECT_AVI         (0 << 19)
 #define   VIDEO_DIP_SELECT_VENDOR      (1 << 19)
 #define   VIDEO_DIP_FREQ_2VSYNC                (2 << 16)
 #define   VIDEO_DIP_FREQ_MASK          (3 << 16)
 /* HSW and later: */
+#define   VIDEO_DIP_ENABLE_VSC_HSW     (1 << 20)
+#define   VIDEO_DIP_ENABLE_GCP_HSW     (1 << 16)
 #define   VIDEO_DIP_ENABLE_AVI_HSW     (1 << 12)
+#define   VIDEO_DIP_ENABLE_VS_HSW      (1 << 8)
+#define   VIDEO_DIP_ENABLE_GMP_HSW     (1 << 4)
 #define   VIDEO_DIP_ENABLE_SPD_HSW     (1 << 0)
 
 /* Panel power sequencing */
 #define   GEN6_RC6                     3
 #define   GEN6_RC7                     4
 
+#define GEN7_MISCCPCTL                 (0x9424)
+#define   GEN7_DOP_CLOCK_GATE_ENABLE   (1<<0)
+
+/* IVYBRIDGE DPF */
+#define GEN7_L3CDERRST1                        0xB008 /* L3CD Error Status 1 */
+#define   GEN7_L3CDERRST1_ROW_MASK     (0x7ff<<14)
+#define   GEN7_PARITY_ERROR_VALID      (1<<13)
+#define   GEN7_L3CDERRST1_BANK_MASK    (3<<11)
+#define   GEN7_L3CDERRST1_SUBBANK_MASK (7<<8)
+#define GEN7_PARITY_ERROR_ROW(reg) \
+               ((reg & GEN7_L3CDERRST1_ROW_MASK) >> 14)
+#define GEN7_PARITY_ERROR_BANK(reg) \
+               ((reg & GEN7_L3CDERRST1_BANK_MASK) >> 11)
+#define GEN7_PARITY_ERROR_SUBBANK(reg) \
+               ((reg & GEN7_L3CDERRST1_SUBBANK_MASK) >> 8)
+#define   GEN7_L3CDERRST1_ENABLE       (1<<7)
+
+#define GEN7_L3LOG_BASE                        0xB070
+#define GEN7_L3LOG_SIZE                        0x80
+
 #define G4X_AUD_VID_DID                        0x62020
 #define INTEL_AUDIO_DEVCL              0x808629FB
 #define INTEL_AUDIO_DEVBLC             0x80862801
index 79f83445afa07c43d2d5109926bb4865b45b51de..2f5388af8df9cdf775d66d4d4f72f50f29bdecc0 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/stat.h>
 #include <linux/sysfs.h>
+#include "intel_drv.h"
 #include "i915_drv.h"
 
 static u32 calc_residency(struct drm_device *dev, const u32 reg)
@@ -92,20 +93,134 @@ static struct attribute_group rc6_attr_group = {
        .attrs =  rc6_attrs
 };
 
-void i915_setup_sysfs(struct drm_device *dev)
+static int l3_access_valid(struct drm_device *dev, loff_t offset)
+{
+       if (!IS_IVYBRIDGE(dev))
+               return -EPERM;
+
+       if (offset % 4 != 0)
+               return -EINVAL;
+
+       if (offset >= GEN7_L3LOG_SIZE)
+               return -ENXIO;
+
+       return 0;
+}
+
+static ssize_t
+i915_l3_read(struct file *filp, struct kobject *kobj,
+            struct bin_attribute *attr, char *buf,
+            loff_t offset, size_t count)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
+       struct drm_device *drm_dev = dminor->dev;
+       struct drm_i915_private *dev_priv = drm_dev->dev_private;
+       uint32_t misccpctl;
+       int i, ret;
+
+       ret = l3_access_valid(drm_dev, offset);
+       if (ret)
+               return ret;
+
+       ret = i915_mutex_lock_interruptible(drm_dev);
+       if (ret)
+               return ret;
+
+       misccpctl = I915_READ(GEN7_MISCCPCTL);
+       I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
+
+       for (i = offset; count >= 4 && i < GEN7_L3LOG_SIZE; i += 4, count -= 4)
+               *((uint32_t *)(&buf[i])) = I915_READ(GEN7_L3LOG_BASE + i);
+
+       I915_WRITE(GEN7_MISCCPCTL, misccpctl);
+
+       mutex_unlock(&drm_dev->struct_mutex);
+
+       return i - offset;
+}
+
+static ssize_t
+i915_l3_write(struct file *filp, struct kobject *kobj,
+             struct bin_attribute *attr, char *buf,
+             loff_t offset, size_t count)
 {
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
+       struct drm_device *drm_dev = dminor->dev;
+       struct drm_i915_private *dev_priv = drm_dev->dev_private;
+       u32 *temp = NULL; /* Just here to make handling failures easy */
        int ret;
 
-       /* ILK doesn't have any residency information */
-       if (INTEL_INFO(dev)->gen < 6)
-               return;
+       ret = l3_access_valid(drm_dev, offset);
+       if (ret)
+               return ret;
 
-       ret = sysfs_merge_group(&dev->primary->kdev.kobj, &rc6_attr_group);
+       ret = i915_mutex_lock_interruptible(drm_dev);
        if (ret)
-               DRM_ERROR("sysfs setup failed\n");
+               return ret;
+
+       if (!dev_priv->mm.l3_remap_info) {
+               temp = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL);
+               if (!temp) {
+                       mutex_unlock(&drm_dev->struct_mutex);
+                       return -ENOMEM;
+               }
+       }
+
+       ret = i915_gpu_idle(drm_dev);
+       if (ret) {
+               kfree(temp);
+               mutex_unlock(&drm_dev->struct_mutex);
+               return ret;
+       }
+
+       /* TODO: Ideally we really want a GPU reset here to make sure errors
+        * aren't propagated. Since I cannot find a stable way to reset the GPU
+        * at this point it is left as a TODO.
+       */
+       if (temp)
+               dev_priv->mm.l3_remap_info = temp;
+
+       memcpy(dev_priv->mm.l3_remap_info + (offset/4),
+              buf + (offset/4),
+              count);
+
+       i915_gem_l3_remap(drm_dev);
+
+       mutex_unlock(&drm_dev->struct_mutex);
+
+       return count;
+}
+
+static struct bin_attribute dpf_attrs = {
+       .attr = {.name = "l3_parity", .mode = (S_IRUSR | S_IWUSR)},
+       .size = GEN7_L3LOG_SIZE,
+       .read = i915_l3_read,
+       .write = i915_l3_write,
+       .mmap = NULL
+};
+
+void i915_setup_sysfs(struct drm_device *dev)
+{
+       int ret;
+
+       if (INTEL_INFO(dev)->gen >= 6) {
+               ret = sysfs_merge_group(&dev->primary->kdev.kobj,
+                                       &rc6_attr_group);
+               if (ret)
+                       DRM_ERROR("RC6 residency sysfs setup failed\n");
+       }
+
+       if (IS_IVYBRIDGE(dev)) {
+               ret = device_create_bin_file(&dev->primary->kdev, &dpf_attrs);
+               if (ret)
+                       DRM_ERROR("l3 parity sysfs setup failed\n");
+       }
 }
 
 void i915_teardown_sysfs(struct drm_device *dev)
 {
+       device_remove_bin_file(&dev->primary->kdev,  &dpf_attrs);
        sysfs_unmerge_group(&dev->primary->kdev.kobj, &rc6_attr_group);
 }
index dac7bba4d9da3ca03d3c3d6a4a4beb0df61bbec2..fe90b3a84a6d9db3b7cac327173749fe0fc0b0a9 100644 (file)
@@ -311,9 +311,33 @@ DEFINE_EVENT(i915_gem_request, i915_gem_request_retire,
            TP_ARGS(ring, seqno)
 );
 
-DEFINE_EVENT(i915_gem_request, i915_gem_request_wait_begin,
+TRACE_EVENT(i915_gem_request_wait_begin,
            TP_PROTO(struct intel_ring_buffer *ring, u32 seqno),
-           TP_ARGS(ring, seqno)
+           TP_ARGS(ring, seqno),
+
+           TP_STRUCT__entry(
+                            __field(u32, dev)
+                            __field(u32, ring)
+                            __field(u32, seqno)
+                            __field(bool, blocking)
+                            ),
+
+           /* NB: the blocking information is racy since mutex_is_locked
+            * doesn't check that the current thread holds the lock. The only
+            * other option would be to pass the boolean information of whether
+            * or not the class was blocking down through the stack which is
+            * less desirable.
+            */
+           TP_fast_assign(
+                          __entry->dev = ring->dev->primary->index;
+                          __entry->ring = ring->id;
+                          __entry->seqno = seqno;
+                          __entry->blocking = mutex_is_locked(&ring->dev->struct_mutex);
+                          ),
+
+           TP_printk("dev=%u, ring=%u, seqno=%u, blocking=%s",
+                     __entry->dev, __entry->ring, __entry->seqno,
+                     __entry->blocking ?  "yes (NB)" : "no")
 );
 
 DEFINE_EVENT(i915_gem_request, i915_gem_request_wait_end,
index 46d1e886c6923f9b9e8373dc65e6417b3c5f98a8..f33fe1a1c33e16295e1f41d50cf5aac4431d36e1 100644 (file)
@@ -726,8 +726,7 @@ void intel_ddi_mode_set(struct drm_encoder *encoder,
 
        I915_WRITE(DDI_FUNC_CTL(pipe), temp);
 
-       intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
-       intel_hdmi_set_spd_infoframe(encoder);
+       intel_hdmi->set_infoframes(encoder, adjusted_mode);
 }
 
 void intel_ddi_dpms(struct drm_encoder *encoder, int mode)
index 9147894209061dd69c12ddc9bde72f904ebae3ac..9f5148acf73c650d9dcd60313ce94eeee096fb73 100644 (file)
@@ -4405,25 +4405,10 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
                                                    &clock,
                                                    &reduced_clock);
        }
-       /* SDVO TV has fixed PLL values depend on its clock range,
-          this mirrors vbios setting. */
-       if (is_sdvo && is_tv) {
-               if (adjusted_mode->clock >= 100000
-                   && adjusted_mode->clock < 140500) {
-                       clock.p1 = 2;
-                       clock.p2 = 10;
-                       clock.n = 3;
-                       clock.m1 = 16;
-                       clock.m2 = 8;
-               } else if (adjusted_mode->clock >= 140500
-                          && adjusted_mode->clock <= 200000) {
-                       clock.p1 = 1;
-                       clock.p2 = 10;
-                       clock.n = 6;
-                       clock.m1 = 12;
-                       clock.m2 = 8;
-               }
-       }
+
+       if (is_sdvo && is_tv)
+               i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock);
+
 
        /* FDI link */
        pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
@@ -4662,16 +4647,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
                if (is_lvds && has_reduced_clock && i915_powersave) {
                        I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp2);
                        intel_crtc->lowfreq_avail = true;
-                       if (HAS_PIPE_CXSR(dev)) {
-                               DRM_DEBUG_KMS("enabling CxSR downclocking\n");
-                               pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
-                       }
                } else {
                        I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp);
-                       if (HAS_PIPE_CXSR(dev)) {
-                               DRM_DEBUG_KMS("disabling CxSR downclocking\n");
-                               pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
-                       }
                }
        }
 
index 296cfc201a81ea9a0017abfb0e97eee7eaf8dc18..c71e7890e6f6127fdd10554ea30618b0105ab3cb 100644 (file)
@@ -2087,25 +2087,23 @@ g4x_dp_detect(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t temp, bit;
+       uint32_t bit;
 
        switch (intel_dp->output_reg) {
        case DP_B:
-               bit = DPB_HOTPLUG_INT_STATUS;
+               bit = DPB_HOTPLUG_LIVE_STATUS;
                break;
        case DP_C:
-               bit = DPC_HOTPLUG_INT_STATUS;
+               bit = DPC_HOTPLUG_LIVE_STATUS;
                break;
        case DP_D:
-               bit = DPD_HOTPLUG_INT_STATUS;
+               bit = DPD_HOTPLUG_LIVE_STATUS;
                break;
        default:
                return connector_status_unknown;
        }
 
-       temp = I915_READ(PORT_HOTPLUG_STAT);
-
-       if ((temp & bit) == 0)
+       if ((I915_READ(PORT_HOTPLUG_STAT) & bit) == 0)
                return connector_status_disconnected;
 
        return intel_dp_detect_dpcd(intel_dp);
@@ -2487,19 +2485,19 @@ intel_dp_init(struct drm_device *dev, int output_reg)
                case DP_B:
                case PCH_DP_B:
                        dev_priv->hotplug_supported_mask |=
-                               HDMIB_HOTPLUG_INT_STATUS;
+                               DPB_HOTPLUG_INT_STATUS;
                        name = "DPDDC-B";
                        break;
                case DP_C:
                case PCH_DP_C:
                        dev_priv->hotplug_supported_mask |=
-                               HDMIC_HOTPLUG_INT_STATUS;
+                               DPC_HOTPLUG_INT_STATUS;
                        name = "DPDDC-C";
                        break;
                case DP_D:
                case PCH_DP_D:
                        dev_priv->hotplug_supported_mask |=
-                               HDMID_HOTPLUG_INT_STATUS;
+                               DPD_HOTPLUG_INT_STATUS;
                        name = "DPDDC-D";
                        break;
        }
index 3e0918834e7e017cf865c48fcfa8677903c031f7..39d7b07c1e8b7ef99f1def90bcddab08281a21a3 100644 (file)
@@ -301,6 +301,8 @@ struct intel_hdmi {
        enum hdmi_force_audio force_audio;
        void (*write_infoframe)(struct drm_encoder *encoder,
                                struct dip_infoframe *frame);
+       void (*set_infoframes)(struct drm_encoder *encoder,
+                              struct drm_display_mode *adjusted_mode);
 };
 
 static inline struct drm_crtc *
@@ -343,9 +345,6 @@ extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector)
 extern void intel_crt_init(struct drm_device *dev);
 extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
 extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
-extern void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
-                           struct drm_display_mode *adjusted_mode);
-extern void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder);
 extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
 extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg,
                            bool is_sdvob);
index 2ead3bf7c21d9a2839901d2d28fcd858d5411a88..b507d38faa10d9cc035932b1f4bf537ca263fbca 100644 (file)
@@ -121,36 +121,31 @@ static void g4x_write_infoframe(struct drm_encoder *encoder,
        uint32_t *data = (uint32_t *)frame;
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
        u32 val = I915_READ(VIDEO_DIP_CTL);
        unsigned i, len = DIP_HEADER_SIZE + frame->len;
 
-       val &= ~VIDEO_DIP_PORT_MASK;
-       if (intel_hdmi->sdvox_reg == SDVOB)
-               val |= VIDEO_DIP_PORT_B;
-       else if (intel_hdmi->sdvox_reg == SDVOC)
-               val |= VIDEO_DIP_PORT_C;
-       else
-               return;
+       WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
 
        val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
        val |= g4x_infoframe_index(frame);
 
        val &= ~g4x_infoframe_enable(frame);
-       val |= VIDEO_DIP_ENABLE;
 
        I915_WRITE(VIDEO_DIP_CTL, val);
 
+       mmiowb();
        for (i = 0; i < len; i += 4) {
                I915_WRITE(VIDEO_DIP_DATA, *data);
                data++;
        }
+       mmiowb();
 
        val |= g4x_infoframe_enable(frame);
        val &= ~VIDEO_DIP_FREQ_MASK;
        val |= VIDEO_DIP_FREQ_VSYNC;
 
        I915_WRITE(VIDEO_DIP_CTL, val);
+       POSTING_READ(VIDEO_DIP_CTL);
 }
 
 static void ibx_write_infoframe(struct drm_encoder *encoder,
@@ -160,46 +155,32 @@ static void ibx_write_infoframe(struct drm_encoder *encoder,
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
        int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
        unsigned i, len = DIP_HEADER_SIZE + frame->len;
        u32 val = I915_READ(reg);
 
-       val &= ~VIDEO_DIP_PORT_MASK;
-       switch (intel_hdmi->sdvox_reg) {
-       case HDMIB:
-               val |= VIDEO_DIP_PORT_B;
-               break;
-       case HDMIC:
-               val |= VIDEO_DIP_PORT_C;
-               break;
-       case HDMID:
-               val |= VIDEO_DIP_PORT_D;
-               break;
-       default:
-               return;
-       }
-
-       intel_wait_for_vblank(dev, intel_crtc->pipe);
+       WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
 
        val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
        val |= g4x_infoframe_index(frame);
 
        val &= ~g4x_infoframe_enable(frame);
-       val |= VIDEO_DIP_ENABLE;
 
        I915_WRITE(reg, val);
 
+       mmiowb();
        for (i = 0; i < len; i += 4) {
                I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
                data++;
        }
+       mmiowb();
 
        val |= g4x_infoframe_enable(frame);
        val &= ~VIDEO_DIP_FREQ_MASK;
        val |= VIDEO_DIP_FREQ_VSYNC;
 
        I915_WRITE(reg, val);
+       POSTING_READ(reg);
 }
 
 static void cpt_write_infoframe(struct drm_encoder *encoder,
@@ -213,32 +194,31 @@ static void cpt_write_infoframe(struct drm_encoder *encoder,
        unsigned i, len = DIP_HEADER_SIZE + frame->len;
        u32 val = I915_READ(reg);
 
-       intel_wait_for_vblank(dev, intel_crtc->pipe);
+       WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
 
        val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
        val |= g4x_infoframe_index(frame);
 
        /* The DIP control register spec says that we need to update the AVI
         * infoframe without clearing its enable bit */
-       if (frame->type == DIP_TYPE_AVI)
-               val |= VIDEO_DIP_ENABLE_AVI;
-       else
+       if (frame->type != DIP_TYPE_AVI)
                val &= ~g4x_infoframe_enable(frame);
 
-       val |= VIDEO_DIP_ENABLE;
-
        I915_WRITE(reg, val);
 
+       mmiowb();
        for (i = 0; i < len; i += 4) {
                I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
                data++;
        }
+       mmiowb();
 
        val |= g4x_infoframe_enable(frame);
        val &= ~VIDEO_DIP_FREQ_MASK;
        val |= VIDEO_DIP_FREQ_VSYNC;
 
        I915_WRITE(reg, val);
+       POSTING_READ(reg);
 }
 
 static void vlv_write_infoframe(struct drm_encoder *encoder,
@@ -252,26 +232,28 @@ static void vlv_write_infoframe(struct drm_encoder *encoder,
        unsigned i, len = DIP_HEADER_SIZE + frame->len;
        u32 val = I915_READ(reg);
 
-       intel_wait_for_vblank(dev, intel_crtc->pipe);
+       WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
 
        val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
        val |= g4x_infoframe_index(frame);
 
        val &= ~g4x_infoframe_enable(frame);
-       val |= VIDEO_DIP_ENABLE;
 
        I915_WRITE(reg, val);
 
+       mmiowb();
        for (i = 0; i < len; i += 4) {
                I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
                data++;
        }
+       mmiowb();
 
        val |= g4x_infoframe_enable(frame);
        val &= ~VIDEO_DIP_FREQ_MASK;
        val |= VIDEO_DIP_FREQ_VSYNC;
 
        I915_WRITE(reg, val);
+       POSTING_READ(reg);
 }
 
 static void hsw_write_infoframe(struct drm_encoder *encoder,
@@ -289,18 +271,19 @@ static void hsw_write_infoframe(struct drm_encoder *encoder,
        if (data_reg == 0)
                return;
 
-       intel_wait_for_vblank(dev, intel_crtc->pipe);
-
        val &= ~hsw_infoframe_enable(frame);
        I915_WRITE(ctl_reg, val);
 
+       mmiowb();
        for (i = 0; i < len; i += 4) {
                I915_WRITE(data_reg + i, *data);
                data++;
        }
+       mmiowb();
 
        val |= hsw_infoframe_enable(frame);
        I915_WRITE(ctl_reg, val);
+       POSTING_READ(ctl_reg);
 }
 
 static void intel_set_infoframe(struct drm_encoder *encoder,
@@ -308,14 +291,11 @@ static void intel_set_infoframe(struct drm_encoder *encoder,
 {
        struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 
-       if (!intel_hdmi->has_hdmi_sink)
-               return;
-
        intel_dip_infoframe_csum(frame);
        intel_hdmi->write_infoframe(encoder, frame);
 }
 
-void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
+static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
                                         struct drm_display_mode *adjusted_mode)
 {
        struct dip_infoframe avi_if = {
@@ -330,7 +310,7 @@ void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
        intel_set_infoframe(encoder, &avi_if);
 }
 
-void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
+static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
 {
        struct dip_infoframe spd_if;
 
@@ -345,6 +325,213 @@ void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
        intel_set_infoframe(encoder, &spd_if);
 }
 
+static void g4x_set_infoframes(struct drm_encoder *encoder,
+                              struct drm_display_mode *adjusted_mode)
+{
+       struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+       u32 reg = VIDEO_DIP_CTL;
+       u32 val = I915_READ(reg);
+       u32 port;
+
+       /* If the registers were not initialized yet, they might be zeroes,
+        * which means we're selecting the AVI DIP and we're setting its
+        * frequency to once. This seems to really confuse the HW and make
+        * things stop working (the register spec says the AVI always needs to
+        * be sent every VSync). So here we avoid writing to the register more
+        * than we need and also explicitly select the AVI DIP and explicitly
+        * set its frequency to every VSync. Avoiding to write it twice seems to
+        * be enough to solve the problem, but being defensive shouldn't hurt us
+        * either. */
+       val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
+
+       if (!intel_hdmi->has_hdmi_sink) {
+               if (!(val & VIDEO_DIP_ENABLE))
+                       return;
+               val &= ~VIDEO_DIP_ENABLE;
+               I915_WRITE(reg, val);
+               POSTING_READ(reg);
+               return;
+       }
+
+       switch (intel_hdmi->sdvox_reg) {
+       case SDVOB:
+               port = VIDEO_DIP_PORT_B;
+               break;
+       case SDVOC:
+               port = VIDEO_DIP_PORT_C;
+               break;
+       default:
+               return;
+       }
+
+       if (port != (val & VIDEO_DIP_PORT_MASK)) {
+               if (val & VIDEO_DIP_ENABLE) {
+                       val &= ~VIDEO_DIP_ENABLE;
+                       I915_WRITE(reg, val);
+                       POSTING_READ(reg);
+               }
+               val &= ~VIDEO_DIP_PORT_MASK;
+               val |= port;
+       }
+
+       val |= VIDEO_DIP_ENABLE;
+       val &= ~VIDEO_DIP_ENABLE_VENDOR;
+
+       I915_WRITE(reg, val);
+       POSTING_READ(reg);
+
+       intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
+       intel_hdmi_set_spd_infoframe(encoder);
+}
+
+static void ibx_set_infoframes(struct drm_encoder *encoder,
+                              struct drm_display_mode *adjusted_mode)
+{
+       struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+       u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+       u32 val = I915_READ(reg);
+       u32 port;
+
+       /* See the big comment in g4x_set_infoframes() */
+       val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
+
+       if (!intel_hdmi->has_hdmi_sink) {
+               if (!(val & VIDEO_DIP_ENABLE))
+                       return;
+               val &= ~VIDEO_DIP_ENABLE;
+               I915_WRITE(reg, val);
+               POSTING_READ(reg);
+               return;
+       }
+
+       switch (intel_hdmi->sdvox_reg) {
+       case HDMIB:
+               port = VIDEO_DIP_PORT_B;
+               break;
+       case HDMIC:
+               port = VIDEO_DIP_PORT_C;
+               break;
+       case HDMID:
+               port = VIDEO_DIP_PORT_D;
+               break;
+       default:
+               return;
+       }
+
+       if (port != (val & VIDEO_DIP_PORT_MASK)) {
+               if (val & VIDEO_DIP_ENABLE) {
+                       val &= ~VIDEO_DIP_ENABLE;
+                       I915_WRITE(reg, val);
+                       POSTING_READ(reg);
+               }
+               val &= ~VIDEO_DIP_PORT_MASK;
+               val |= port;
+       }
+
+       val |= VIDEO_DIP_ENABLE;
+       val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
+                VIDEO_DIP_ENABLE_GCP);
+
+       I915_WRITE(reg, val);
+       POSTING_READ(reg);
+
+       intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
+       intel_hdmi_set_spd_infoframe(encoder);
+}
+
+static void cpt_set_infoframes(struct drm_encoder *encoder,
+                              struct drm_display_mode *adjusted_mode)
+{
+       struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+       u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+       u32 val = I915_READ(reg);
+
+       /* See the big comment in g4x_set_infoframes() */
+       val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
+
+       if (!intel_hdmi->has_hdmi_sink) {
+               if (!(val & VIDEO_DIP_ENABLE))
+                       return;
+               val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI);
+               I915_WRITE(reg, val);
+               POSTING_READ(reg);
+               return;
+       }
+
+       /* Set both together, unset both together: see the spec. */
+       val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI;
+       val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
+                VIDEO_DIP_ENABLE_GCP);
+
+       I915_WRITE(reg, val);
+       POSTING_READ(reg);
+
+       intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
+       intel_hdmi_set_spd_infoframe(encoder);
+}
+
+static void vlv_set_infoframes(struct drm_encoder *encoder,
+                              struct drm_display_mode *adjusted_mode)
+{
+       struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+       u32 reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
+       u32 val = I915_READ(reg);
+
+       /* See the big comment in g4x_set_infoframes() */
+       val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
+
+       if (!intel_hdmi->has_hdmi_sink) {
+               if (!(val & VIDEO_DIP_ENABLE))
+                       return;
+               val &= ~VIDEO_DIP_ENABLE;
+               I915_WRITE(reg, val);
+               POSTING_READ(reg);
+               return;
+       }
+
+       val |= VIDEO_DIP_ENABLE;
+       val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
+                VIDEO_DIP_ENABLE_GCP);
+
+       I915_WRITE(reg, val);
+       POSTING_READ(reg);
+
+       intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
+       intel_hdmi_set_spd_infoframe(encoder);
+}
+
+static void hsw_set_infoframes(struct drm_encoder *encoder,
+                              struct drm_display_mode *adjusted_mode)
+{
+       struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+       u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe);
+       u32 val = I915_READ(reg);
+
+       if (!intel_hdmi->has_hdmi_sink) {
+               I915_WRITE(reg, 0);
+               POSTING_READ(reg);
+               return;
+       }
+
+       val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_GCP_HSW |
+                VIDEO_DIP_ENABLE_VS_HSW | VIDEO_DIP_ENABLE_GMP_HSW);
+
+       I915_WRITE(reg, val);
+       POSTING_READ(reg);
+
+       intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
+       intel_hdmi_set_spd_infoframe(encoder);
+}
+
 static void intel_hdmi_mode_set(struct drm_encoder *encoder,
                                struct drm_display_mode *mode,
                                struct drm_display_mode *adjusted_mode)
@@ -355,7 +542,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
        struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
        u32 sdvox;
 
-       sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE;
+       sdvox = SDVO_ENCODING_HDMI;
        if (!HAS_PCH_SPLIT(dev))
                sdvox |= intel_hdmi->color_range;
        if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
@@ -388,8 +575,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
        I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
        POSTING_READ(intel_hdmi->sdvox_reg);
 
-       intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
-       intel_hdmi_set_spd_infoframe(encoder);
+       intel_hdmi->set_infoframes(encoder, adjusted_mode);
 }
 
 static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
@@ -452,6 +638,27 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
        return true;
 }
 
+static bool g4x_hdmi_connected(struct intel_hdmi *intel_hdmi)
+{
+       struct drm_device *dev = intel_hdmi->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t bit;
+
+       switch (intel_hdmi->sdvox_reg) {
+       case SDVOB:
+               bit = HDMIB_HOTPLUG_LIVE_STATUS;
+               break;
+       case SDVOC:
+               bit = HDMIC_HOTPLUG_LIVE_STATUS;
+               break;
+       default:
+               bit = 0;
+               break;
+       }
+
+       return I915_READ(PORT_HOTPLUG_STAT) & bit;
+}
+
 static enum drm_connector_status
 intel_hdmi_detect(struct drm_connector *connector, bool force)
 {
@@ -460,6 +667,9 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
        struct edid *edid;
        enum drm_connector_status status = connector_status_disconnected;
 
+       if (IS_G4X(connector->dev) && !g4x_hdmi_connected(intel_hdmi))
+               return status;
+
        intel_hdmi->has_hdmi_sink = false;
        intel_hdmi->has_audio = false;
        edid = drm_get_edid(connector,
@@ -633,7 +843,6 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
        struct intel_encoder *intel_encoder;
        struct intel_connector *intel_connector;
        struct intel_hdmi *intel_hdmi;
-       int i;
 
        intel_hdmi = kzalloc(sizeof(struct intel_hdmi), GFP_KERNEL);
        if (!intel_hdmi)
@@ -710,26 +919,19 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
 
        if (!HAS_PCH_SPLIT(dev)) {
                intel_hdmi->write_infoframe = g4x_write_infoframe;
-               I915_WRITE(VIDEO_DIP_CTL, 0);
+               intel_hdmi->set_infoframes = g4x_set_infoframes;
        } else if (IS_VALLEYVIEW(dev)) {
                intel_hdmi->write_infoframe = vlv_write_infoframe;
-               for_each_pipe(i)
-                       I915_WRITE(VLV_TVIDEO_DIP_CTL(i), 0);
+               intel_hdmi->set_infoframes = vlv_set_infoframes;
        } else if (IS_HASWELL(dev)) {
-               /* FIXME: Haswell has a new set of DIP frame registers, but we are
-                * just doing the minimal required for HDMI to work at this stage.
-                */
                intel_hdmi->write_infoframe = hsw_write_infoframe;
-               for_each_pipe(i)
-                       I915_WRITE(HSW_TVIDEO_DIP_CTL(i), 0);
+               intel_hdmi->set_infoframes = hsw_set_infoframes;
        } else if (HAS_PCH_IBX(dev)) {
                intel_hdmi->write_infoframe = ibx_write_infoframe;
-               for_each_pipe(i)
-                       I915_WRITE(TVIDEO_DIP_CTL(i), 0);
+               intel_hdmi->set_infoframes = ibx_set_infoframes;
        } else {
                intel_hdmi->write_infoframe = cpt_write_infoframe;
-               for_each_pipe(i)
-                       I915_WRITE(TVIDEO_DIP_CTL(i), 0);
+               intel_hdmi->set_infoframes = cpt_set_infoframes;
        }
 
        if (IS_HASWELL(dev))
index 458743da37743e702a8ccea57f7c37ae01cbfc07..830d0dd610e1276bc45f5636f77c324d08bf2a16 100644 (file)
@@ -226,7 +226,7 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
        }
        overlay->last_flip_req = request->seqno;
        overlay->flip_tail = tail;
-       ret = i915_wait_request(ring, overlay->last_flip_req);
+       ret = i915_wait_seqno(ring, overlay->last_flip_req);
        if (ret)
                return ret;
        i915_gem_retire_requests(dev);
@@ -452,7 +452,7 @@ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
        if (overlay->last_flip_req == 0)
                return 0;
 
-       ret = i915_wait_request(ring, overlay->last_flip_req);
+       ret = i915_wait_seqno(ring, overlay->last_flip_req);
        if (ret)
                return ret;
        i915_gem_retire_requests(dev);
index b59b6d5b75833e37e204da899c4dda2f65a9bf2d..89a5e7f89d7ab0d4924925dca1826d1b646691ba 100644 (file)
@@ -427,6 +427,9 @@ static int init_render_ring(struct intel_ring_buffer *ring)
        if (INTEL_INFO(dev)->gen >= 6)
                I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
 
+       if (IS_IVYBRIDGE(dev))
+               I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR);
+
        return ret;
 }
 
@@ -814,7 +817,11 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring)
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
        if (ring->irq_refcount++ == 0) {
-               I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
+               if (IS_IVYBRIDGE(dev) && ring->id == RCS)
+                       I915_WRITE_IMR(ring, ~(ring->irq_enable_mask |
+                                               GEN6_RENDER_L3_PARITY_ERROR));
+               else
+                       I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
                dev_priv->gt_irq_mask &= ~ring->irq_enable_mask;
                I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
                POSTING_READ(GTIMR);
@@ -833,7 +840,10 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring)
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
        if (--ring->irq_refcount == 0) {
-               I915_WRITE_IMR(ring, ~0);
+               if (IS_IVYBRIDGE(dev) && ring->id == RCS)
+                       I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR);
+               else
+                       I915_WRITE_IMR(ring, ~0);
                dev_priv->gt_irq_mask |= ring->irq_enable_mask;
                I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
                POSTING_READ(GTIMR);
@@ -1085,7 +1095,7 @@ static int intel_ring_wait_seqno(struct intel_ring_buffer *ring, u32 seqno)
        was_interruptible = dev_priv->mm.interruptible;
        dev_priv->mm.interruptible = false;
 
-       ret = i915_wait_request(ring, seqno);
+       ret = i915_wait_seqno(ring, seqno);
 
        dev_priv->mm.interruptible = was_interruptible;
        if (!ret)
index b6a9d45fc3c69d4b5be7e8c6f93490636b6049c2..2f5106a488c511be29f63d482ce0828ae05187bb 100644 (file)
@@ -140,9 +140,6 @@ struct intel_sdvo {
 
        /* DDC bus used by this SDVO encoder */
        uint8_t ddc_bus;
-
-       /* Input timings for adjusted_mode */
-       struct intel_sdvo_dtd input_dtd;
 };
 
 struct intel_sdvo_connector {
@@ -953,11 +950,15 @@ intel_sdvo_set_output_timings_from_mode(struct intel_sdvo *intel_sdvo,
        return true;
 }
 
+/* Asks the sdvo controller for the preferred input mode given the output mode.
+ * Unfortunately we have to set up the full output mode to do that. */
 static bool
-intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo,
-                                       struct drm_display_mode *mode,
-                                       struct drm_display_mode *adjusted_mode)
+intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo,
+                                   struct drm_display_mode *mode,
+                                   struct drm_display_mode *adjusted_mode)
 {
+       struct intel_sdvo_dtd input_dtd;
+
        /* Reset the input timing to the screen. Assume always input 0. */
        if (!intel_sdvo_set_target_input(intel_sdvo))
                return false;
@@ -969,10 +970,10 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo,
                return false;
 
        if (!intel_sdvo_get_preferred_input_timing(intel_sdvo,
-                                                  &intel_sdvo->input_dtd))
+                                                  &input_dtd))
                return false;
 
-       intel_sdvo_get_mode_from_dtd(adjusted_mode, &intel_sdvo->input_dtd);
+       intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
 
        return true;
 }
@@ -993,17 +994,17 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
                if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode))
                        return false;
 
-               (void) intel_sdvo_set_input_timings_for_mode(intel_sdvo,
-                                                            mode,
-                                                            adjusted_mode);
+               (void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
+                                                          mode,
+                                                          adjusted_mode);
        } else if (intel_sdvo->is_lvds) {
                if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
                                                             intel_sdvo->sdvo_lvds_fixed_mode))
                        return false;
 
-               (void) intel_sdvo_set_input_timings_for_mode(intel_sdvo,
-                                                            mode,
-                                                            adjusted_mode);
+               (void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
+                                                          mode,
+                                                          adjusted_mode);
        }
 
        /* Make the CRTC code factor in the SDVO pixel multiplier.  The
@@ -1057,7 +1058,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
                                             intel_sdvo->sdvo_lvds_fixed_mode);
        else
                intel_sdvo_get_dtd_from_mode(&output_dtd, mode);
-       (void) intel_sdvo_set_output_timing(intel_sdvo, &output_dtd);
+       if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd))
+               DRM_INFO("Setting output timings on %s failed\n",
+                        SDVO_NAME(intel_sdvo));
 
        /* Set the input timing to the screen. Assume always input 0. */
        if (!intel_sdvo_set_target_input(intel_sdvo))
@@ -1079,7 +1082,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
         * adjusted_mode.
         */
        intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
-       (void) intel_sdvo_set_input_timing(intel_sdvo, &input_dtd);
+       if (!intel_sdvo_set_input_timing(intel_sdvo, &input_dtd))
+               DRM_INFO("Setting input timings on %s failed\n",
+                        SDVO_NAME(intel_sdvo));
 
        switch (pixel_multiplier) {
        default:
@@ -1376,7 +1381,7 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
 
        /* add 30ms delay when the output type might be TV */
        if (intel_sdvo->caps.output_flags & SDVO_TV_MASK)
-               mdelay(30);
+               msleep(30);
 
        if (!intel_sdvo_read_response(intel_sdvo, &response, 2))
                return connector_status_unknown;
@@ -2521,6 +2526,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_encoder *intel_encoder;
        struct intel_sdvo *intel_sdvo;
+       u32 hotplug_mask;
        int i;
 
        intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL);
@@ -2552,10 +2558,18 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
                }
        }
 
-       if (intel_sdvo->is_sdvob)
-               dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS;
-       else
-               dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS;
+       hotplug_mask = 0;
+       if (IS_G4X(dev)) {
+               hotplug_mask = intel_sdvo->is_sdvob ?
+                       SDVOB_HOTPLUG_INT_STATUS_G4X : SDVOC_HOTPLUG_INT_STATUS_G4X;
+       } else if (IS_GEN4(dev)) {
+               hotplug_mask = intel_sdvo->is_sdvob ?
+                       SDVOB_HOTPLUG_INT_STATUS_I965 : SDVOC_HOTPLUG_INT_STATUS_I965;
+       } else {
+               hotplug_mask = intel_sdvo->is_sdvob ?
+                       SDVOB_HOTPLUG_INT_STATUS_I915 : SDVOC_HOTPLUG_INT_STATUS_I915;
+       }
+       dev_priv->hotplug_supported_mask |= hotplug_mask;
 
        drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs);
 
index f3f82242bf1dc9312551c9b2526ce892bcb5ed5b..bab174334da574fd5f481cb1612e782061802b6e 100644 (file)
@@ -200,6 +200,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_GEM_EXECBUFFER2       0x29
 #define DRM_I915_GET_SPRITE_COLORKEY   0x2a
 #define DRM_I915_SET_SPRITE_COLORKEY   0x2b
+#define DRM_I915_GEM_WAIT      0x2c
 
 #define DRM_IOCTL_I915_INIT            DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
 #define DRM_IOCTL_I915_FLUSH           DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -243,6 +244,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_OVERLAY_ATTRS   DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs)
 #define DRM_IOCTL_I915_SET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
 #define DRM_IOCTL_I915_GET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
+#define DRM_IOCTL_I915_GEM_WAIT                DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_WAIT, struct drm_i915_gem_wait)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -886,4 +888,12 @@ struct drm_intel_sprite_colorkey {
        __u32 flags;
 };
 
+struct drm_i915_gem_wait {
+       /** Handle of BO we shall wait on */
+       __u32 bo_handle;
+       __u32 flags;
+       /** Number of nanoseconds to wait, Returns time remaining. */
+       __u64 timeout_ns;
+};
+
 #endif                         /* _I915_DRM_H_ */