-----Original Message-----
From: Daniel, Thomas
Sent: Tuesday, June 30, 2015 3:13 PM
To: intel-gfx@xxxxxxxxxxxxxxxxxxxxx
Cc: Chris Wilson; Goel, Akash; Belgaumkar, Vinay; Michal Winiarsky; Zou,
Nanhai; Daniel, Thomas
Subject: [PATCH v4] drm/i915: Add soft-pinning API for execbuffer
From: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx>
Userspace can pass in an offset that it presumes the object is located
at. The kernel will then do its utmost to fit the object into that
location. The assumption is that userspace is handling its own object
locations (for example along with full-ppgtt) and that the kernel will
rarely have to make space for the user's requests.
Signed-off-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx>
v2: Fixed incorrect eviction found by Michal Winiarski - fix suggested by Chris
Wilson. Fixed incorrect error paths causing crash found by Michal Winiarski.
(Not published externally)
v3: Rebased because of trivial conflict in object_bind_to_vm. Fixed eviction
to allow eviction of soft-pinned objects when another soft-pinned object used
by a subsequent execbuffer overlaps reported by Michal Winiarski.
(Not published externally)
v4: Moved soft-pinned objects to the front of ordered_vmas so that they are
pinned first after an address conflict happens to avoid repeated conflicts in
rare cases (Suggested by Chris Wilson). Expanded comment on
drm_i915_gem_exec_object2.offset to cover this new API.
Cc: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx>
Cc: Akash Goel <akash.goel@xxxxxxxxx>
Cc: Vinay Belgaumkar <vinay.belgaumkar@xxxxxxxxx>
Cc: Michal Winiarsky <michal.winiarsky@xxxxxxxxx>
Cc: Zou Nanhai <nanhai.zou@xxxxxxxxx>
Signed-off-by: Thomas Daniel <thomas.daniel@xxxxxxxxx>
---
drivers/gpu/drm/i915/i915_drv.h | 4 +++
drivers/gpu/drm/i915/i915_gem.c | 51 ++++++++++++++++++++--------
drivers/gpu/drm/i915/i915_gem_evict.c | 38 +++++++++++++++++++++
drivers/gpu/drm/i915/i915_gem_execbuffer.c | 16 +++++++--
include/uapi/drm/i915_drm.h | 9 +++--
5 files changed, 99 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index d90a782..e96c101 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2747,7 +2747,9 @@ void i915_gem_vma_destroy(struct i915_vma *vma);
#define PIN_USER (1<<4)
#define PIN_UPDATE (1<<5)
#define PIN_FULL_RANGE (1<<6)
+#define PIN_OFFSET_FIXED (1<<7)
#define PIN_OFFSET_MASK (~4095)
+
int __must_check
i915_gem_object_pin(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
@@ -3085,6 +3087,8 @@ int __must_check i915_gem_evict_something(struct
drm_device *dev,
unsigned long start,
unsigned long end,
unsigned flags);
+int __must_check
+i915_gem_evict_for_vma(struct i915_vma *target);
int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle);
int i915_gem_evict_everything(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_gem.c
b/drivers/gpu/drm/i915/i915_gem.c
index f170da6..a7e5ff2 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3806,22 +3806,41 @@ i915_gem_object_bind_to_vm(struct
drm_i915_gem_object *obj,
if (IS_ERR(vma))
goto err_unpin;
+ if (flags & PIN_OFFSET_FIXED) {
+ uint64_t offset = flags & PIN_OFFSET_MASK;
+ if (offset & (alignment - 1)) {
+ ret = -EINVAL;
+ goto err_free_vma;
+ }
+ vma->node.start = offset;
+ vma->node.size = size;
+ vma->node.color = obj->cache_level;
+ ret = drm_mm_reserve_node(&vm->mm, &vma->node);
+ if (ret) {
+ ret = i915_gem_evict_for_vma(vma);
+ if (ret == 0)
+ ret = drm_mm_reserve_node(&vm->mm,
&vma->node);
+ }
+ if (ret)
+ goto err_free_vma;
+ } else {
search_free:
- ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node,
- size, alignment,
- obj->cache_level,
- start, end,
- search_flag,
- alloc_flag);
- if (ret) {
- ret = i915_gem_evict_something(dev, vm, size, alignment,
- obj->cache_level,
- start, end,
- flags);
- if (ret == 0)
- goto search_free;
+ ret = drm_mm_insert_node_in_range_generic(&vm->mm,
&vma->node,
+ size, alignment,
+ obj->cache_level,
+ start, end,
+ search_flag,
+ alloc_flag);
+ if (ret) {
+ ret = i915_gem_evict_something(dev, vm, size,
alignment,
+ obj->cache_level,
+ start, end,
+ flags);
+ if (ret == 0)
+ goto search_free;
- goto err_free_vma;
+ goto err_free_vma;
+ }
}
if (WARN_ON(!i915_gem_valid_gtt_space(vma, obj->cache_level))) {
ret = -EINVAL;
@@ -4357,6 +4376,10 @@ i915_vma_misplaced(struct i915_vma *vma,
uint32_t alignment, uint64_t flags)
vma->node.start < (flags & PIN_OFFSET_MASK))
return true;
+ if (flags & PIN_OFFSET_FIXED &&
+ vma->node.start != (flags & PIN_OFFSET_MASK))
+ return true;
+
return false;
}
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c
b/drivers/gpu/drm/i915/i915_gem_evict.c
index d09e35e..6098e2f 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -199,6 +199,44 @@ found:
return ret;
}
+int
+i915_gem_evict_for_vma(struct i915_vma *target)
+{
+ struct drm_mm_node *node, *next;
+
+ list_for_each_entry_safe(node, next,
+ &target->vm->mm.head_node.node_list,
+ node_list) {
+ struct i915_vma *vma;
+ int ret;
+
+ if (node->start + node->size <= target->node.start)
+ continue;
+ if (node->start >= target->node.start + target->node.size)
+ break;
+
+ vma = container_of(node, typeof(*vma), node);
+
+ if (vma->pin_count) {
+ /* We may need to evict a buffer in the same batch */
+ if (!vma->exec_entry)
+ return -EBUSY;
+
+ if (vma->exec_entry->flags & EXEC_OBJECT_PINNED)
+ /* Overlapping fixed objects in the same batch
*/
+ return -EINVAL;
+
+ return -ENOSPC;