drm/ttm: optionally move duplicates to a separate list
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / radeon / radeon_gem.c
index c194497aa586e16c5c17776d5baa5959f3eac7c5..fe48f229043e33720c26bcdd40949d7a8fd41b00 100644 (file)
@@ -394,9 +394,10 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
        return r;
 }
 
-int radeon_mode_dumb_mmap(struct drm_file *filp,
-                         struct drm_device *dev,
-                         uint32_t handle, uint64_t *offset_p)
+static int radeon_mode_mmap(struct drm_file *filp,
+                           struct drm_device *dev,
+                           uint32_t handle, bool dumb,
+                           uint64_t *offset_p)
 {
        struct drm_gem_object *gobj;
        struct radeon_bo *robj;
@@ -405,6 +406,14 @@ int radeon_mode_dumb_mmap(struct drm_file *filp,
        if (gobj == NULL) {
                return -ENOENT;
        }
+
+       /*
+        * We don't allow dumb mmaps on objects created using another
+        * interface.
+        */
+       WARN_ONCE(dumb && !(gobj->dumb || gobj->import_attach),
+               "Illegal dumb map of GPU buffer.\n");
+
        robj = gem_to_radeon_bo(gobj);
        if (radeon_ttm_tt_has_userptr(robj->tbo.ttm)) {
                drm_gem_object_unreference_unlocked(gobj);
@@ -415,12 +424,20 @@ int radeon_mode_dumb_mmap(struct drm_file *filp,
        return 0;
 }
 
+int radeon_mode_dumb_mmap(struct drm_file *filp,
+                         struct drm_device *dev,
+                         uint32_t handle, uint64_t *offset_p)
+{
+       return radeon_mode_mmap(filp, dev, handle, true, offset_p);
+}
+
 int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data,
                          struct drm_file *filp)
 {
        struct drm_radeon_gem_mmap *args = data;
 
-       return radeon_mode_dumb_mmap(filp, dev, args->handle, &args->addr_ptr);
+       return radeon_mode_mmap(filp, dev, args->handle, false,
+                               &args->addr_ptr);
 }
 
 int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
@@ -518,6 +535,68 @@ out:
        return r;
 }
 
+/**
+ * radeon_gem_va_update_vm -update the bo_va in its VM
+ *
+ * @rdev: radeon_device pointer
+ * @bo_va: bo_va to update
+ *
+ * Update the bo_va directly after setting it's address. Errors are not
+ * vital here, so they are not reported back to userspace.
+ */
+static void radeon_gem_va_update_vm(struct radeon_device *rdev,
+                                   struct radeon_bo_va *bo_va)
+{
+       struct ttm_validate_buffer tv, *entry;
+       struct radeon_bo_list *vm_bos;
+       struct ww_acquire_ctx ticket;
+       struct list_head list;
+       unsigned domain;
+       int r;
+
+       INIT_LIST_HEAD(&list);
+
+       tv.bo = &bo_va->bo->tbo;
+       tv.shared = true;
+       list_add(&tv.head, &list);
+
+       vm_bos = radeon_vm_get_bos(rdev, bo_va->vm, &list);
+       if (!vm_bos)
+               return;
+
+       r = ttm_eu_reserve_buffers(&ticket, &list, true, NULL);
+       if (r)
+               goto error_free;
+
+       list_for_each_entry(entry, &list, head) {
+               domain = radeon_mem_type_to_domain(entry->bo->mem.mem_type);
+               /* if anything is swapped out don't swap it in here,
+                  just abort and wait for the next CS */
+               if (domain == RADEON_GEM_DOMAIN_CPU)
+                       goto error_unreserve;
+       }
+
+       mutex_lock(&bo_va->vm->mutex);
+       r = radeon_vm_clear_freed(rdev, bo_va->vm);
+       if (r)
+               goto error_unlock;
+
+       if (bo_va->it.start)
+               r = radeon_vm_bo_update(rdev, bo_va, &bo_va->bo->tbo.mem);
+
+error_unlock:
+       mutex_unlock(&bo_va->vm->mutex);
+
+error_unreserve:
+       ttm_eu_backoff_reservation(&ticket, &list);
+
+error_free:
+       drm_free_large(vm_bos);
+
+       if (r)
+               DRM_ERROR("Couldn't update BO_VA (%d)\n", r);
+}
+
 int radeon_gem_va_ioctl(struct drm_device *dev, void *data,
                          struct drm_file *filp)
 {
@@ -601,6 +680,7 @@ int radeon_gem_va_ioctl(struct drm_device *dev, void *data,
                if (bo_va->it.start) {
                        args->operation = RADEON_VA_RESULT_VA_EXIST;
                        args->offset = bo_va->it.start * RADEON_GPU_PAGE_SIZE;
+                       radeon_bo_unreserve(rbo);
                        goto out;
                }
                r = radeon_vm_bo_set_addr(rdev, bo_va, args->offset, args->flags);
@@ -611,12 +691,13 @@ int radeon_gem_va_ioctl(struct drm_device *dev, void *data,
        default:
                break;
        }
+       if (!r)
+               radeon_gem_va_update_vm(rdev, bo_va);
        args->operation = RADEON_VA_RESULT_OK;
        if (r) {
                args->operation = RADEON_VA_RESULT_ERROR;
        }
 out:
-       radeon_bo_unreserve(rbo);
        drm_gem_object_unreference_unlocked(gobj);
        return r;
 }
@@ -682,6 +763,7 @@ int radeon_mode_dumb_create(struct drm_file *file_priv,
                return -ENOMEM;
 
        r = drm_gem_handle_create(file_priv, gobj, &handle);
+       gobj->dumb = true;
        /* drop reference from allocate - handle holds it now */
        drm_gem_object_unreference_unlocked(gobj);
        if (r) {