@@ -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);
@@ -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;
@@ -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;
@@ -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);
@@ -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;
@@ -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;
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 <ben@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(-)