VM: add "vm_mmap()" helper function
[linux-flexiantxendom0-3.2.10.git] / drivers / gpu / drm / i915 / i915_gem.c
index 2031cc7..0d1e4b7 100644 (file)
@@ -1087,11 +1087,9 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
        if (obj == NULL)
                return -ENOENT;
 
-       down_write(&current->mm->mmap_sem);
-       addr = do_mmap(obj->filp, 0, args->size,
+       addr = vm_mmap(obj->filp, 0, args->size,
                       PROT_READ | PROT_WRITE, MAP_SHARED,
                       args->offset);
-       up_write(&current->mm->mmap_sem);
        drm_gem_object_unreference_unlocked(obj);
        if (IS_ERR((void *)addr))
                return addr;
@@ -1472,16 +1470,19 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
        list_move_tail(&obj->ring_list, &ring->active_list);
 
        obj->last_rendering_seqno = seqno;
-       if (obj->fenced_gpu_access) {
-               struct drm_i915_fence_reg *reg;
-
-               BUG_ON(obj->fence_reg == I915_FENCE_REG_NONE);
 
+       if (obj->fenced_gpu_access) {
                obj->last_fenced_seqno = seqno;
                obj->last_fenced_ring = ring;
 
-               reg = &dev_priv->fence_regs[obj->fence_reg];
-               list_move_tail(&reg->lru_list, &dev_priv->mm.fence_list);
+               /* Bump MRU to take account of the delayed flush */
+               if (obj->fence_reg != I915_FENCE_REG_NONE) {
+                       struct drm_i915_fence_reg *reg;
+
+                       reg = &dev_priv->fence_regs[obj->fence_reg];
+                       list_move_tail(&reg->lru_list,
+                                      &dev_priv->mm.fence_list);
+               }
        }
 }
 
@@ -1490,6 +1491,7 @@ i915_gem_object_move_off_active(struct drm_i915_gem_object *obj)
 {
        list_del_init(&obj->ring_list);
        obj->last_rendering_seqno = 0;
+       obj->last_fenced_seqno = 0;
 }
 
 static void
@@ -1518,6 +1520,7 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
        BUG_ON(!list_empty(&obj->gpu_write_list));
        BUG_ON(!obj->active);
        obj->ring = NULL;
+       obj->last_fenced_ring = NULL;
 
        i915_gem_object_move_off_active(obj);
        obj->fenced_gpu_access = false;
@@ -1605,12 +1608,20 @@ i915_add_request(struct intel_ring_buffer *ring,
 {
        drm_i915_private_t *dev_priv = ring->dev->dev_private;
        uint32_t seqno;
+       u32 request_ring_position;
        int was_empty;
        int ret;
 
        BUG_ON(request == NULL);
        seqno = i915_gem_next_request_seqno(ring);
 
+       /* Record the position of the start of the request so that
+        * should we detect the updated seqno part-way through the
+        * GPU processing the request, we never over-estimate the
+        * position of the head.
+        */
+       request_ring_position = intel_ring_get_tail(ring);
+
        ret = ring->add_request(ring, &seqno);
        if (ret)
            return ret;
@@ -1619,6 +1630,7 @@ i915_add_request(struct intel_ring_buffer *ring,
 
        request->seqno = seqno;
        request->ring = ring;
+       request->tail = request_ring_position;
        request->emitted_jiffies = jiffies;
        was_empty = list_empty(&ring->request_list);
        list_add_tail(&request->list, &ring->request_list);
@@ -1755,7 +1767,7 @@ void i915_gem_reset(struct drm_device *dev)
 /**
  * This function clears the request list as sequence numbers are passed.
  */
-static void
+void
 i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
 {
        uint32_t seqno;
@@ -1783,6 +1795,12 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
                        break;
 
                trace_i915_gem_request_retire(ring, request->seqno);
+               /* We know the GPU must have read the request to have
+                * sent us the seqno + interrupt, so use the position
+                * of tail of the request to update the last known position
+                * of the GPU head.
+                */
+               ring->last_retired_head = request->tail;
 
                list_del(&request->list);
                i915_gem_request_remove_from_client(request);
@@ -1970,11 +1988,6 @@ i915_wait_request(struct intel_ring_buffer *ring,
        if (atomic_read(&dev_priv->mm.wedged))
                ret = -EAGAIN;
 
-       if (ret && ret != -ERESTARTSYS)
-               DRM_ERROR("%s returns %d (awaiting %d at %d, next %d)\n",
-                         __func__, ret, seqno, ring->get_seqno(ring),
-                         dev_priv->next_seqno);
-
        /* Directly dispatch request retiring.  While we have the work queue
         * to handle this, the waiter on a request often wants an associated
         * buffer to have made it to the inactive list, and we would need
@@ -3054,10 +3067,13 @@ i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj)
                        return ret;
        }
 
+       ret = i915_gem_object_wait_rendering(obj);
+       if (ret)
+               return ret;
+
        /* Ensure that we invalidate the GPU's caches and TLBs. */
        obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS;
-
-       return i915_gem_object_wait_rendering(obj);
+       return 0;
 }
 
 /**
@@ -3741,12 +3757,32 @@ void i915_gem_init_ppgtt(struct drm_device *dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
        uint32_t pd_offset;
        struct intel_ring_buffer *ring;
+       struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+       uint32_t __iomem *pd_addr;
+       uint32_t pd_entry;
        int i;
 
        if (!dev_priv->mm.aliasing_ppgtt)
                return;
 
-       pd_offset = dev_priv->mm.aliasing_ppgtt->pd_offset;
+
+       pd_addr = dev_priv->mm.gtt->gtt + ppgtt->pd_offset/sizeof(uint32_t);
+       for (i = 0; i < ppgtt->num_pd_entries; i++) {
+               dma_addr_t pt_addr;
+
+               if (dev_priv->mm.gtt->needs_dmar)
+                       pt_addr = ppgtt->pt_dma_addr[i];
+               else
+                       pt_addr = page_to_phys(ppgtt->pt_pages[i]);
+
+               pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr);
+               pd_entry |= GEN6_PDE_VALID;
+
+               writel(pd_entry, pd_addr + i);
+       }
+       readl(pd_addr);
+
+       pd_offset = ppgtt->pd_offset;
        pd_offset /= 64; /* in cachelines, */
        pd_offset <<= 16;