Merge branch 'topic/ppgtt' into drm-intel-next-queued
[linux-2.6-microblaze.git] / drivers / gpu / drm / i915 / i915_gem_execbuffer.c
index 0843e0e..bd5f4e7 100644 (file)
@@ -94,7 +94,7 @@ eb_lookup_vmas(struct eb_vmas *eb,
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
        struct drm_i915_gem_object *obj;
        struct list_head objects;
-       int i, ret = 0;
+       int i, ret;
 
        INIT_LIST_HEAD(&objects);
        spin_lock(&file->table_lock);
@@ -107,7 +107,7 @@ eb_lookup_vmas(struct eb_vmas *eb,
                        DRM_DEBUG("Invalid object handle %d at index %d\n",
                                   exec[i].handle, i);
                        ret = -ENOENT;
-                       goto out;
+                       goto err;
                }
 
                if (!list_empty(&obj->obj_exec_link)) {
@@ -115,7 +115,7 @@ eb_lookup_vmas(struct eb_vmas *eb,
                        DRM_DEBUG("Object %p [handle %d, index %d] appears more than once in object list\n",
                                   obj, exec[i].handle, i);
                        ret = -EINVAL;
-                       goto out;
+                       goto err;
                }
 
                drm_gem_object_reference(&obj->base);
@@ -124,7 +124,7 @@ eb_lookup_vmas(struct eb_vmas *eb,
        spin_unlock(&file->table_lock);
 
        i = 0;
-       list_for_each_entry(obj, &objects, obj_exec_link) {
+       while (!list_empty(&objects)) {
                struct i915_vma *vma;
                struct i915_address_space *bind_vm = vm;
 
@@ -141,6 +141,10 @@ eb_lookup_vmas(struct eb_vmas *eb,
                    (i == (args->buffer_count - 1))))
                        bind_vm = &dev_priv->gtt.base;
 
+               obj = list_first_entry(&objects,
+                                      struct drm_i915_gem_object,
+                                      obj_exec_link);
+
                /*
                 * NOTE: We can leak any vmas created here when something fails
                 * later on. But that's no issue since vma_unbind can deal with
@@ -153,10 +157,12 @@ eb_lookup_vmas(struct eb_vmas *eb,
                if (IS_ERR(vma)) {
                        DRM_DEBUG("Failed to lookup VMA\n");
                        ret = PTR_ERR(vma);
-                       goto out;
+                       goto err;
                }
 
+               /* Transfer ownership from the objects list to the vmas list. */
                list_add_tail(&vma->exec_list, &eb->vmas);
+               list_del_init(&obj->obj_exec_link);
 
                vma->exec_entry = &exec[i];
                if (eb->and < 0) {
@@ -170,16 +176,22 @@ eb_lookup_vmas(struct eb_vmas *eb,
                ++i;
        }
 
+       return 0;
+
 
-out:
+err:
        while (!list_empty(&objects)) {
                obj = list_first_entry(&objects,
                                       struct drm_i915_gem_object,
                                       obj_exec_link);
                list_del_init(&obj->obj_exec_link);
-               if (ret)
-                       drm_gem_object_unreference(&obj->base);
+               drm_gem_object_unreference(&obj->base);
        }
+       /*
+        * Objects already transfered to the vmas list will be unreferenced by
+        * eb_destroy.
+        */
+
        return ret;
 }
 
@@ -255,7 +267,7 @@ relocate_entry_cpu(struct drm_i915_gem_object *obj,
        struct drm_device *dev = obj->base.dev;
        uint32_t page_offset = offset_in_page(reloc->offset);
        char *vaddr;
-       int ret = -EINVAL;
+       int ret;
 
        ret = i915_gem_object_set_to_cpu_domain(obj, true);
        if (ret)
@@ -290,7 +302,7 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj,
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t __iomem *reloc_entry;
        void __iomem *reloc_page;
-       int ret = -EINVAL;
+       int ret;
 
        ret = i915_gem_object_set_to_gtt_domain(obj, true);
        if (ret)
@@ -337,7 +349,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
        struct drm_i915_gem_object *target_i915_obj;
        struct i915_vma *target_vma;
        uint32_t target_offset;
-       int ret = -EINVAL;
+       int ret;
 
        /* we've already hold a reference to all valid objects */
        target_vma = eb_get_vma(eb, reloc->target_handle);
@@ -369,7 +381,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
                          (int) reloc->offset,
                          reloc->read_domains,
                          reloc->write_domain);
-               return ret;
+               return -EINVAL;
        }
        if (unlikely((reloc->write_domain | reloc->read_domains)
                     & ~I915_GEM_GPU_DOMAINS)) {
@@ -380,7 +392,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
                          (int) reloc->offset,
                          reloc->read_domains,
                          reloc->write_domain);
-               return ret;
+               return -EINVAL;
        }
 
        target_obj->pending_read_domains |= reloc->read_domains;
@@ -400,14 +412,14 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
                          obj, reloc->target_handle,
                          (int) reloc->offset,
                          (int) obj->base.size);
-               return ret;
+               return -EINVAL;
        }
        if (unlikely(reloc->offset & 3)) {
                DRM_DEBUG("Relocation not 4-byte aligned: "
                          "obj %p target %d offset %d.\n",
                          obj, reloc->target_handle,
                          (int) reloc->offset);
-               return ret;
+               return -EINVAL;
        }
 
        /* We can't wait for rendering with pagefaults disabled */
@@ -1101,6 +1113,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                }
        }
 
+       intel_runtime_pm_get(dev_priv);
+
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
                goto pre_mutex_err;
@@ -1249,6 +1263,10 @@ err:
 
 pre_mutex_err:
        kfree(cliprects);
+
+       /* intel_gpu_busy should also get a ref, so it will free when the device
+        * is really idle. */
+       intel_runtime_pm_put(dev_priv);
        return ret;
 }