diff options
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_evict.c | 104 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_execbuffer.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_trace.h | 28 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_vma.c | 2 |
5 files changed, 111 insertions, 27 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a0c6791..605247b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3341,7 +3341,8 @@ int __must_check i915_gem_evict_something(struct i915_address_space *vm, unsigned cache_level, u64 start, u64 end, unsigned flags); -int __must_check i915_gem_evict_for_vma(struct i915_vma *target); +int __must_check i915_gem_evict_for_vma(struct i915_vma *vma, + unsigned int flags); int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle); /* belongs in i915_gem_gtt.h */ diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 739ede7..fa40100 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -212,45 +212,99 @@ found: return ret; } -int -i915_gem_evict_for_vma(struct i915_vma *target) +/** + * i915_gem_evict_for_vma - Evict vmas to make room for binding a new one + * @target: address space and range to evict for + * @flags: additional flags to control the eviction algorithm + * + * This function will try to evict vmas that overlap the target node. + * + * To clarify: This is for freeing up virtual address space, not for freeing + * memory in e.g. the shrinker. + */ +int i915_gem_evict_for_vma(struct i915_vma *target, unsigned int flags) { - struct drm_mm_node *node, *next; + LIST_HEAD(eviction_list); + struct drm_mm_node *node; + u64 start = target->node.start; + u64 end = start + target->node.size; + struct i915_vma *vma, *next; + bool check_color; + int ret = 0; lockdep_assert_held(&target->vm->i915->drm.struct_mutex); + trace_i915_gem_evict_vma(target, flags); + + check_color = target->vm->mm.color_adjust; + if (check_color) { + /* Expand search to cover neighbouring guard pages (or lack!) */ + if (start > target->vm->start) + start -= 4096; + if (end < target->vm->start + target->vm->total) + end += 4096; + } - 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) + drm_mm_for_each_node_in_range(node, &target->vm->mm, start, end) { + /* If we find any non-objects (!vma), we cannot evict them */ + if (node->color == I915_COLOR_UNEVICTABLE) { + ret = -ENOSPC; break; + } vma = container_of(node, typeof(*vma), node); - if (i915_vma_is_pinned(vma)) { - if (!vma->exec_entry || i915_vma_pin_count(vma) > 1) - /* Object is pinned for some other use */ - return -EBUSY; + /* If we are using coloring to insert guard pages between + * different cache domains within the address space, we have + * to check whether the objects on either side of our range + * abutt and conflict. If they are in conflict, then we evict + * those as well to make room for our guard pages. + */ + if (check_color) { + if (vma->node.start + vma->node.size == target->node.start) { + if (vma->node.color == target->node.color) + continue; + } + if (vma->node.start == target->node.start + target->node.size) { + if (vma->node.color == target->node.color) + continue; + } + } - /* We need to evict a buffer in the same batch */ - if (vma->exec_entry->flags & EXEC_OBJECT_PINNED) - /* Overlapping fixed objects in the same batch */ - return -EINVAL; + if (flags & PIN_NONBLOCK && + (i915_vma_is_pinned(vma) || i915_vma_is_active(vma))) { + ret = -ENOSPC; + break; + } - return -ENOSPC; + /* Overlap of objects in the same batch? */ + if (i915_vma_is_pinned(vma)) { + ret = -ENOSPC; + if (vma->exec_entry && + vma->exec_entry->flags & EXEC_OBJECT_PINNED) + ret = -EINVAL; + break; } - ret = i915_vma_unbind(vma); - if (ret) - return ret; + /* Never show fear in the face of dragons! + * + * We cannot directly remove this node from within this + * iterator and as with i915_gem_evict_something() we employ + * the vma pin_count in order to prevent the action of + * unbinding one vma from freeing (by dropping its active + * reference) another in our eviction list. + */ + __i915_vma_pin(vma); + list_add(&vma->exec_list, &eviction_list); } - return 0; + list_for_each_entry_safe(vma, next, &eviction_list, exec_list) { + list_del_init(&vma->exec_list); + __i915_vma_unpin(vma); + if (ret == 0) + ret = i915_vma_unbind(vma); + } + + return ret; } /** diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 5f164ad..d665a33 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -274,6 +274,7 @@ static void eb_destroy(struct eb_vmas *eb) exec_list); list_del_init(&vma->exec_list); i915_gem_execbuffer_unreserve_vma(vma); + vma->exec_entry = NULL; i915_vma_put(vma); } kfree(eb); diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 2400677..18ae37c 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -450,6 +450,34 @@ TRACE_EVENT(i915_gem_evict_vm, TP_printk("dev=%d, vm=%p", __entry->dev, __entry->vm) ); +TRACE_EVENT(i915_gem_evict_vma, + TP_PROTO(struct i915_vma *vma, unsigned int flags), + TP_ARGS(vma, flags), + + TP_STRUCT__entry( + __field(u32, dev) + __field(struct i915_address_space *, vm) + __field(u64, start) + __field(u64, size) + __field(unsigned long, color) + __field(unsigned int, flags) + ), + + TP_fast_assign( + __entry->dev = vma->vm->i915->drm.primary->index; + __entry->vm = vma->vm; + __entry->start = vma->node.start; + __entry->size = vma->node.size; + __entry->color = vma->node.color; + __entry->flags = flags; + ), + + TP_printk("dev=%d, vm=%p, start=%llx size=%llx, color=%lx, flags=%x", + __entry->dev, __entry->vm, + __entry->start, __entry->size, + __entry->color, __entry->flags) +); + TRACE_EVENT(i915_gem_ring_sync_to, TP_PROTO(struct drm_i915_gem_request *to, struct drm_i915_gem_request *from), diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index 4c91a68..bc077e5 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -401,7 +401,7 @@ i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags) vma->node.color = obj->cache_level; ret = drm_mm_reserve_node(&vma->vm->mm, &vma->node); if (ret) { - ret = i915_gem_evict_for_vma(vma); + ret = i915_gem_evict_for_vma(vma, flags); if (ret == 0) ret = drm_mm_reserve_node(&vma->vm->mm, &vma->node); if (ret) |