Merge commit 'origin/master' into drm-gem
[profile/ivi/libdrm.git] / shared-core / i915_dma.c
index 60b405d..a948834 100644 (file)
@@ -41,10 +41,14 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
        drm_i915_private_t *dev_priv = dev->dev_private;
        drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
        u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+       u32 acthd_reg = IS_I965G(dev) ? I965REG_ACTHD : I915REG_ACTHD;
+       u32 last_acthd = I915_READ(acthd_reg);
+       u32 acthd;
        int i;
 
-       for (i = 0; i < 10000; i++) {
+       for (i = 0; i < 100000; i++) {
                ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+               acthd = I915_READ(acthd_reg);
                ring->space = ring->head - (ring->tail + 8);
                if (ring->space < 0)
                        ring->space += ring->Size;
@@ -54,13 +58,41 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
                if (ring->head != last_head)
                        i = 0;
 
+               if (acthd != last_acthd)
+                       i = 0;
+
                last_head = ring->head;
-               DRM_UDELAY(1);
+               last_acthd = acthd;
+               msleep_interruptible (10);
        }
 
        return -EBUSY;
 }
 
+#if I915_RING_VALIDATE
+/**
+ * Validate the cached ring tail value
+ *
+ * If the X server writes to the ring and DRM doesn't
+ * reload the head and tail pointers, it will end up writing
+ * data to the wrong place in the ring, causing havoc.
+ */
+void i915_ring_validate(struct drm_device *dev, const char *func, int line)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
+       u32     tail = I915_READ(LP_RING+RING_TAIL) & HEAD_ADDR;
+       u32     head = I915_READ(LP_RING+RING_HEAD) & HEAD_ADDR;
+
+       if (tail != ring->tail) {
+               DRM_ERROR("%s:%d head sw %x, hw %x. tail sw %x hw %x\n",
+                         func, line,
+                         ring->head, head, ring->tail, tail);
+               BUG_ON(1);
+       }
+}
+#endif
+
 void i915_kernel_lost_context(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -459,9 +491,9 @@ static int i915_emit_cmds(struct drm_device *dev, int __user *buffer,
        return 0;
 }
 
-static int i915_emit_box(struct drm_device * dev,
-                        struct drm_clip_rect __user * boxes,
-                        int i, int DR1, int DR4)
+int i915_emit_box(struct drm_device * dev,
+                 struct drm_clip_rect __user * boxes,
+                 int i, int DR1, int DR4)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_clip_rect box;
@@ -517,7 +549,7 @@ void i915_emit_breadcrumb(struct drm_device *dev)
 
        BEGIN_LP_RING(4);
        OUT_RING(CMD_STORE_DWORD_IDX);
-       OUT_RING(20);
+       OUT_RING(5 << STORE_DWORD_INDEX_SHIFT);
        OUT_RING(dev_priv->counter);
        OUT_RING(0);
        ADVANCE_LP_RING();
@@ -715,9 +747,19 @@ void i915_dispatch_flip(struct drm_device * dev, int planes, int sync)
 int i915_quiescent(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+       int ret;
 
        i915_kernel_lost_context(dev);
-       return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
+       ret = i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
+       if (ret)
+       {
+               i915_kernel_lost_context (dev);
+               DRM_ERROR ("not quiescent head %08x tail %08x space %08x\n",
+                          dev_priv->ring.head,
+                          dev_priv->ring.tail,
+                          dev_priv->ring.space);
+       }
+       return ret;
 }
 
 static int i915_flush_ioctl(struct drm_device *dev, void *data,
@@ -1026,6 +1068,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        memset(dev_priv, 0, sizeof(drm_i915_private_t));
 
        dev->dev_private = (void *)dev_priv;
+       dev_priv->dev = dev;
 
        /* Add register map (needed for suspend/resume) */
        base = drm_get_resource_start(dev, mmio_bar);
@@ -1034,6 +1077,14 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        ret = drm_addmap(dev, base, size, _DRM_REGISTERS,
                _DRM_KERNEL | _DRM_DRIVER, &dev_priv->mmio_map);
 
+       INIT_LIST_HEAD(&dev_priv->mm.active_list);
+       INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
+       INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
+       INIT_LIST_HEAD(&dev_priv->mm.request_list);
+       INIT_WORK(&dev_priv->user_interrupt_task,
+                 i915_user_interrupt_handler);
+       dev_priv->mm.next_gem_seqno = 1;
+
 #ifdef __linux__
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
        intel_init_chipset_flush_compat(dev);
@@ -1074,6 +1125,7 @@ void i915_driver_lastclose(struct drm_device * dev)
                dev_priv->val_bufs = NULL;
        }
 #endif
+       i915_gem_lastclose(dev);
 
        if (drm_getsarea(dev) && dev_priv->sarea_priv)
                i915_do_cleanup_pageflip(dev);
@@ -1125,6 +1177,11 @@ struct drm_ioctl_desc i915_ioctls[] = {
 #ifdef I915_HAVE_BUFFER
        DRM_IOCTL_DEF(DRM_I915_EXECBUFFER, i915_execbuffer, DRM_AUTH),
 #endif
+       DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH),
 };
 
 int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);