This patch is a proof of concept hack which repurposes the MSB of the
size field in created. Userptr already has the gup code, and all we need
to do is reuse it.

Signed-off-by: Ben Widawsky <b...@bwidawsk.net>
---
 drivers/gpu/drm/i915/i915_drv.h            | 12 ++++-
 drivers/gpu/drm/i915/i915_gem.c            | 86 +++++++++++++++++++++++++++---
 drivers/gpu/drm/i915/i915_gem_execbuffer.c |  5 +-
 drivers/gpu/drm/i915/i915_gem_gtt.h        |  1 +
 drivers/gpu/drm/i915/i915_gem_userptr.c    |  7 +--
 include/uapi/drm/i915_drm.h                |  3 +-
 6 files changed, 100 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 00d9ab3..cfad8c1 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2298,8 +2298,14 @@ void *i915_gem_object_alloc(struct drm_device *dev);
 void i915_gem_object_free(struct drm_i915_gem_object *obj);
 void i915_gem_object_init(struct drm_i915_gem_object *obj,
                         const struct drm_i915_gem_object_ops *ops);
-struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
-                                                 size_t size);
+struct drm_i915_gem_object *_i915_gem_alloc_object(struct drm_device *dev,
+                                                 size_t size,
+                                                 bool user_obj);
+#define i915_gem_alloc_object(dev, size) _i915_gem_alloc_object(dev, size, 
false)
+int i915_gem_userptr_init__mmu_notifier(struct drm_i915_gem_object *obj, 
unsigned flags);
+int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj);
+void i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj);
+#define i915_is_soft_pinned(vma) ((vma)->obj->ops->get_pages == 
i915_gem_userptr_get_pages)
 void i915_init_vm(struct drm_i915_private *dev_priv,
                  struct i915_address_space *vm);
 void i915_gem_free_object(struct drm_gem_object *obj);
@@ -2311,11 +2317,13 @@ void i915_gem_vma_destroy(struct i915_vma *vma);
 #define PIN_ALIASING   (1<<3)
 #define PIN_GLOBAL_ALIASED (PIN_ALIASING | PIN_GLOBAL)
 #define PIN_OFFSET_BIAS (1<<4)
+#define PIN_SOFT       (1<<5)
 #define PIN_OFFSET_MASK (PAGE_MASK)
 int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj,
                                     struct i915_address_space *vm,
                                     uint32_t alignment,
                                     uint64_t flags);
+int i915_vma_softpin(struct i915_vma *vma, uint64_t start, uint64_t size);
 int __must_check i915_vma_unbind(struct i915_vma *vma);
 int i915_gem_object_put_pages(struct drm_i915_gem_object *obj);
 void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 6413f3a..75d2454 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -347,21 +347,33 @@ static int
 i915_gem_create(struct drm_file *file,
                struct drm_device *dev,
                uint64_t size,
+               uint64_t loc,
                uint32_t *handle_p)
 {
        struct drm_i915_gem_object *obj;
        int ret;
        u32 handle;
+       bool user_obj = false;
+
+       if (size & BIT_ULL(63)) {
+               if (!HAS_48B_PPGTT(dev) || !USES_FULL_PPGTT(dev))
+                       return -EINVAL;
+               size &= ~BIT_ULL(63);
+               user_obj = true;
+       }
 
        size = roundup(size, PAGE_SIZE);
        if (size == 0)
                return -EINVAL;
 
        /* Allocate the new object */
-       obj = i915_gem_alloc_object(dev, size);
+       obj = _i915_gem_alloc_object(dev, size, user_obj);
        if (obj == NULL)
                return -ENOMEM;
 
+       if (user_obj)
+                obj->userptr.ptr = loc;
+
        ret = drm_gem_handle_create(file, &obj->base, &handle);
        /* drop reference from allocate - handle holds it now */
        drm_gem_object_unreference_unlocked(&obj->base);
@@ -380,7 +392,7 @@ i915_gem_dumb_create(struct drm_file *file,
        /* have to work out size/pitch and return them */
        args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 64);
        args->size = args->pitch * args->height;
-       return i915_gem_create(file, dev,
+       return i915_gem_create(file, dev, 0,
                               args->size, &args->handle);
 }
 
@@ -392,9 +404,10 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
                      struct drm_file *file)
 {
        struct drm_i915_gem_create *args = data;
+       uint64_t location = ((uint64_t)args->handle) << 32 | args->pad;
 
        return i915_gem_create(file, dev,
-                              args->size, &args->handle);
+                              args->size, location, &args->handle);
 }
 
 static inline int
@@ -3038,7 +3051,10 @@ int i915_vma_unbind(struct i915_vma *vma)
        if (i915_is_ggtt(vma->vm))
                obj->map_and_fenceable = true;
 
-       drm_mm_remove_node(&vma->node);
+       if (i915_is_soft_pinned(vma))
+               vma->node.allocated = 0;
+       else
+               drm_mm_remove_node(&vma->node);
        i915_gem_vma_destroy(vma);
 
        /* Since the unbound list is global, only move to that list if
@@ -3544,6 +3560,8 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object 
*obj,
        if (IS_ERR(vma))
                goto err_unpin;
 
+       BUG_ON(i915_is_soft_pinned(vma));
+
 search_free:
        ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node,
                                                  size, alignment,
@@ -4227,6 +4245,43 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
        return 0;
 }
 
+int i915_vma_softpin(struct i915_vma *vma, uint64_t start, uint64_t size)
+{
+       struct drm_i915_private *dev_priv = to_i915(vma->vm->dev);
+       struct drm_i915_gem_object *obj = vma->obj;
+       int ret;
+
+       BUG_ON(!i915_is_soft_pinned(vma));
+       ret = i915_gem_object_get_pages(obj);
+       if (ret)
+               return ret;
+
+       i915_gem_object_pin_pages(obj);
+
+       ret = i915_gem_gtt_prepare_object(obj);
+       if (ret)
+               goto err_release_pages;
+
+       vma->node.allocated = 1;
+
+       list_move_tail(&obj->global_list, &dev_priv->mm.bound_list);
+       list_add_tail(&vma->mm_list, &vma->vm->inactive_list);
+
+       vma->node.start = start;
+       vma->node.size = size;
+       trace_i915_vma_bind(vma, PIN_SOFT);
+       i915_gem_vma_bind(vma, obj->cache_level, SOFT_PINNED);
+       vma->pin_count++;
+
+       return 0;
+
+err_release_pages:
+       i915_gem_vma_destroy(vma);
+       i915_gem_object_unpin_pages(obj);
+
+       return ret;
+}
+
 void
 i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj)
 {
@@ -4473,8 +4528,16 @@ static const struct drm_i915_gem_object_ops 
i915_gem_object_ops = {
        .put_pages = i915_gem_object_put_pages_gtt,
 };
 
-struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
-                                                 size_t size)
+/* Soft pinned objects are those which have user pages, and an offset defined 
by
+ * userspace
+ */
+static const struct drm_i915_gem_object_ops i915_gem_soft_pin_object_ops = {
+       .get_pages = i915_gem_userptr_get_pages,
+       .put_pages = i915_gem_userptr_put_pages,
+};
+
+struct drm_i915_gem_object *_i915_gem_alloc_object(struct drm_device *dev,
+                                                  size_t size, bool user_obj)
 {
        struct drm_i915_gem_object *obj;
        struct address_space *mapping;
@@ -4499,7 +4562,16 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct 
drm_device *dev,
        mapping = file_inode(obj->base.filp)->i_mapping;
        mapping_set_gfp_mask(mapping, mask);
 
-       i915_gem_object_init(obj, &i915_gem_object_ops);
+       if (user_obj) {
+               i915_gem_object_init(obj, &i915_gem_soft_pin_object_ops);
+               obj->userptr.mm = get_task_mm(current);
+               if (i915_gem_userptr_init__mmu_notifier(obj, 0)) {
+                       i915_gem_object_free(obj);
+                       drm_gem_object_unreference_unlocked(&obj->base);
+                       return NULL;
+               }
+       } else
+               i915_gem_object_init(obj, &i915_gem_object_ops);
 
        obj->base.write_domain = I915_GEM_DOMAIN_CPU;
        obj->base.read_domains = I915_GEM_DOMAIN_CPU;
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c 
b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index fdd68d6..c1761f0 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -571,7 +571,10 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
        if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS)
                flags |= BATCH_OFFSET_BIAS | PIN_OFFSET_BIAS;
 
-       ret = i915_gem_object_pin(obj, vma->vm, entry->alignment, flags);
+       if (i915_is_soft_pinned(vma))
+               ret = i915_vma_softpin(vma, entry->offset, vma->obj->base.size);
+       else
+               ret = i915_gem_object_pin(obj, vma->vm, entry->alignment, 
flags);
        if (ret)
                return ret;
 
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h 
b/drivers/gpu/drm/i915/i915_gem_gtt.h
index 92acd95..e4ab4ba 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.h
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
@@ -185,6 +185,7 @@ struct i915_vma {
 /* Only use this if you know you want a strictly aliased binding */
 #define ALIASING_BIND (1<<1)
 #define PTE_READ_ONLY (1<<2)
+#define SOFT_PINNED   (1<<3) /* Just debug for now */
        int (*bind_vma)(struct i915_vma *vma,
                        enum i915_cache_level cache_level,
                        u32 flags);
diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c 
b/drivers/gpu/drm/i915/i915_gem_userptr.c
index fe69fc8..ff7aea6 100644
--- a/drivers/gpu/drm/i915/i915_gem_userptr.c
+++ b/drivers/gpu/drm/i915/i915_gem_userptr.c
@@ -341,7 +341,7 @@ i915_gem_userptr_release__mmu_notifier(struct 
drm_i915_gem_object *obj)
        obj->userptr.mn = NULL;
 }
 
-static int
+int
 i915_gem_userptr_init__mmu_notifier(struct drm_i915_gem_object *obj,
                                    unsigned flags)
 {
@@ -519,7 +519,7 @@ __i915_gem_userptr_get_pages_worker(struct work_struct 
*_work)
        kfree(work);
 }
 
-static int
+int
 i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
 {
        const int num_pages = obj->base.size >> PAGE_SHIFT;
@@ -598,6 +598,7 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
                                        get_task_struct(work->task);
 
                                        INIT_WORK(&work->work, 
__i915_gem_userptr_get_pages_worker);
+                                       WARN_ON(!obj->userptr.ptr);
                                        schedule_work(&work->work);
                                } else
                                        ret = -ENOMEM;
@@ -621,7 +622,7 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
        return ret;
 }
 
-static void
+void
 i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj)
 {
        struct scatterlist *sg;
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index ff57f07..413a4fb 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -662,7 +662,8 @@ struct drm_i915_gem_exec_object2 {
 #define EXEC_OBJECT_NEEDS_FENCE (1<<0)
 #define EXEC_OBJECT_NEEDS_GTT  (1<<1)
 #define EXEC_OBJECT_WRITE      (1<<2)
-#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_WRITE<<1)
+#define EXEC_OBJECT_SOFT_PINNED (1<<3)
+#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_SOFT_PINNED<<1)
        __u64 flags;
 
        __u64 rsvd1;
-- 
2.0.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to