diff options
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 64 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_evict.c | 39 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_execbuffer.c | 16 | ||||
-rw-r--r-- | include/uapi/drm/i915_drm.h | 12 |
6 files changed, 111 insertions, 25 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a81c76603544..52b82893ba42 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
@@ -169,6 +169,9 @@ static int i915_getparam(struct drm_device *dev, void *data, | |||
169 | case I915_PARAM_HAS_RESOURCE_STREAMER: | 169 | case I915_PARAM_HAS_RESOURCE_STREAMER: |
170 | value = HAS_RESOURCE_STREAMER(dev); | 170 | value = HAS_RESOURCE_STREAMER(dev); |
171 | break; | 171 | break; |
172 | case I915_PARAM_HAS_EXEC_SOFTPIN: | ||
173 | value = 1; | ||
174 | break; | ||
172 | default: | 175 | default: |
173 | DRM_DEBUG("Unknown parameter %d\n", param->param); | 176 | DRM_DEBUG("Unknown parameter %d\n", param->param); |
174 | return -EINVAL; | 177 | return -EINVAL; |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6dee97c0d5d0..547c14269292 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -2868,6 +2868,7 @@ void i915_gem_vma_destroy(struct i915_vma *vma); | |||
2868 | #define PIN_UPDATE (1<<5) | 2868 | #define PIN_UPDATE (1<<5) |
2869 | #define PIN_ZONE_4G (1<<6) | 2869 | #define PIN_ZONE_4G (1<<6) |
2870 | #define PIN_HIGH (1<<7) | 2870 | #define PIN_HIGH (1<<7) |
2871 | #define PIN_OFFSET_FIXED (1<<8) | ||
2871 | #define PIN_OFFSET_MASK (~4095) | 2872 | #define PIN_OFFSET_MASK (~4095) |
2872 | int __must_check | 2873 | int __must_check |
2873 | i915_gem_object_pin(struct drm_i915_gem_object *obj, | 2874 | i915_gem_object_pin(struct drm_i915_gem_object *obj, |
@@ -3213,6 +3214,7 @@ int __must_check i915_gem_evict_something(struct drm_device *dev, | |||
3213 | unsigned long start, | 3214 | unsigned long start, |
3214 | unsigned long end, | 3215 | unsigned long end, |
3215 | unsigned flags); | 3216 | unsigned flags); |
3217 | int __must_check i915_gem_evict_for_vma(struct i915_vma *target); | ||
3216 | int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle); | 3218 | int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle); |
3217 | 3219 | ||
3218 | /* belongs in i915_gem_gtt.h */ | 3220 | /* belongs in i915_gem_gtt.h */ |
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a531cb83295c..d7b8d16ff6e6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -3468,30 +3468,50 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, | |||
3468 | if (IS_ERR(vma)) | 3468 | if (IS_ERR(vma)) |
3469 | goto err_unpin; | 3469 | goto err_unpin; |
3470 | 3470 | ||
3471 | if (flags & PIN_HIGH) { | 3471 | if (flags & PIN_OFFSET_FIXED) { |
3472 | search_flag = DRM_MM_SEARCH_BELOW; | 3472 | uint64_t offset = flags & PIN_OFFSET_MASK; |
3473 | alloc_flag = DRM_MM_CREATE_TOP; | 3473 | |
3474 | if (offset & (alignment - 1) || offset + size > end) { | ||
3475 | ret = -EINVAL; | ||
3476 | goto err_free_vma; | ||
3477 | } | ||
3478 | vma->node.start = offset; | ||
3479 | vma->node.size = size; | ||
3480 | vma->node.color = obj->cache_level; | ||
3481 | ret = drm_mm_reserve_node(&vm->mm, &vma->node); | ||
3482 | if (ret) { | ||
3483 | ret = i915_gem_evict_for_vma(vma); | ||
3484 | if (ret == 0) | ||
3485 | ret = drm_mm_reserve_node(&vm->mm, &vma->node); | ||
3486 | } | ||
3487 | if (ret) | ||
3488 | goto err_free_vma; | ||
3474 | } else { | 3489 | } else { |
3475 | search_flag = DRM_MM_SEARCH_DEFAULT; | 3490 | if (flags & PIN_HIGH) { |
3476 | alloc_flag = DRM_MM_CREATE_DEFAULT; | 3491 | search_flag = DRM_MM_SEARCH_BELOW; |
3477 | } | 3492 | alloc_flag = DRM_MM_CREATE_TOP; |
3493 | } else { | ||
3494 | search_flag = DRM_MM_SEARCH_DEFAULT; | ||
3495 | alloc_flag = DRM_MM_CREATE_DEFAULT; | ||
3496 | } | ||
3478 | 3497 | ||
3479 | search_free: | 3498 | search_free: |
3480 | ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node, | 3499 | ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node, |
3481 | size, alignment, | 3500 | size, alignment, |
3482 | obj->cache_level, | 3501 | obj->cache_level, |
3483 | start, end, | 3502 | start, end, |
3484 | search_flag, | 3503 | search_flag, |
3485 | alloc_flag); | 3504 | alloc_flag); |
3486 | if (ret) { | 3505 | if (ret) { |
3487 | ret = i915_gem_evict_something(dev, vm, size, alignment, | 3506 | ret = i915_gem_evict_something(dev, vm, size, alignment, |
3488 | obj->cache_level, | 3507 | obj->cache_level, |
3489 | start, end, | 3508 | start, end, |
3490 | flags); | 3509 | flags); |
3491 | if (ret == 0) | 3510 | if (ret == 0) |
3492 | goto search_free; | 3511 | goto search_free; |
3493 | 3512 | ||
3494 | goto err_free_vma; | 3513 | goto err_free_vma; |
3514 | } | ||
3495 | } | 3515 | } |
3496 | if (WARN_ON(!i915_gem_valid_gtt_space(vma, obj->cache_level))) { | 3516 | if (WARN_ON(!i915_gem_valid_gtt_space(vma, obj->cache_level))) { |
3497 | ret = -EINVAL; | 3517 | ret = -EINVAL; |
@@ -4082,6 +4102,10 @@ i915_vma_misplaced(struct i915_vma *vma, uint32_t alignment, uint64_t flags) | |||
4082 | vma->node.start < (flags & PIN_OFFSET_MASK)) | 4102 | vma->node.start < (flags & PIN_OFFSET_MASK)) |
4083 | return true; | 4103 | return true; |
4084 | 4104 | ||
4105 | if (flags & PIN_OFFSET_FIXED && | ||
4106 | vma->node.start != (flags & PIN_OFFSET_MASK)) | ||
4107 | return true; | ||
4108 | |||
4085 | return false; | 4109 | return false; |
4086 | } | 4110 | } |
4087 | 4111 | ||
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index d71a133ceff5..07c6e4d320c9 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c | |||
@@ -199,6 +199,45 @@ found: | |||
199 | return ret; | 199 | return ret; |
200 | } | 200 | } |
201 | 201 | ||
202 | int | ||
203 | i915_gem_evict_for_vma(struct i915_vma *target) | ||
204 | { | ||
205 | struct drm_mm_node *node, *next; | ||
206 | |||
207 | list_for_each_entry_safe(node, next, | ||
208 | &target->vm->mm.head_node.node_list, | ||
209 | node_list) { | ||
210 | struct i915_vma *vma; | ||
211 | int ret; | ||
212 | |||
213 | if (node->start + node->size <= target->node.start) | ||
214 | continue; | ||
215 | if (node->start >= target->node.start + target->node.size) | ||
216 | break; | ||
217 | |||
218 | vma = container_of(node, typeof(*vma), node); | ||
219 | |||
220 | if (vma->pin_count) { | ||
221 | if (!vma->exec_entry || (vma->pin_count > 1)) | ||
222 | /* Object is pinned for some other use */ | ||
223 | return -EBUSY; | ||
224 | |||
225 | /* We need to evict a buffer in the same batch */ | ||
226 | if (vma->exec_entry->flags & EXEC_OBJECT_PINNED) | ||
227 | /* Overlapping fixed objects in the same batch */ | ||
228 | return -EINVAL; | ||
229 | |||
230 | return -ENOSPC; | ||
231 | } | ||
232 | |||
233 | ret = i915_vma_unbind(vma); | ||
234 | if (ret) | ||
235 | return ret; | ||
236 | } | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
202 | /** | 241 | /** |
203 | * i915_gem_evict_vm - Evict all idle vmas from a vm | 242 | * i915_gem_evict_vm - Evict all idle vmas from a vm |
204 | * @vm: Address space to cleanse | 243 | * @vm: Address space to cleanse |
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index a4c243cec4aa..48ec4846e6f2 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c | |||
@@ -599,6 +599,8 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma, | |||
599 | flags |= PIN_GLOBAL | PIN_MAPPABLE; | 599 | flags |= PIN_GLOBAL | PIN_MAPPABLE; |
600 | if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS) | 600 | if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS) |
601 | flags |= BATCH_OFFSET_BIAS | PIN_OFFSET_BIAS; | 601 | flags |= BATCH_OFFSET_BIAS | PIN_OFFSET_BIAS; |
602 | if (entry->flags & EXEC_OBJECT_PINNED) | ||
603 | flags |= entry->offset | PIN_OFFSET_FIXED; | ||
602 | if ((flags & PIN_MAPPABLE) == 0) | 604 | if ((flags & PIN_MAPPABLE) == 0) |
603 | flags |= PIN_HIGH; | 605 | flags |= PIN_HIGH; |
604 | } | 606 | } |
@@ -670,6 +672,10 @@ eb_vma_misplaced(struct i915_vma *vma) | |||
670 | vma->node.start & (entry->alignment - 1)) | 672 | vma->node.start & (entry->alignment - 1)) |
671 | return true; | 673 | return true; |
672 | 674 | ||
675 | if (entry->flags & EXEC_OBJECT_PINNED && | ||
676 | vma->node.start != entry->offset) | ||
677 | return true; | ||
678 | |||
673 | if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS && | 679 | if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS && |
674 | vma->node.start < BATCH_OFFSET_BIAS) | 680 | vma->node.start < BATCH_OFFSET_BIAS) |
675 | return true; | 681 | return true; |
@@ -695,6 +701,7 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring, | |||
695 | struct i915_vma *vma; | 701 | struct i915_vma *vma; |
696 | struct i915_address_space *vm; | 702 | struct i915_address_space *vm; |
697 | struct list_head ordered_vmas; | 703 | struct list_head ordered_vmas; |
704 | struct list_head pinned_vmas; | ||
698 | bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4; | 705 | bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4; |
699 | int retry; | 706 | int retry; |
700 | 707 | ||
@@ -703,6 +710,7 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring, | |||
703 | vm = list_first_entry(vmas, struct i915_vma, exec_list)->vm; | 710 | vm = list_first_entry(vmas, struct i915_vma, exec_list)->vm; |
704 | 711 | ||
705 | INIT_LIST_HEAD(&ordered_vmas); | 712 | INIT_LIST_HEAD(&ordered_vmas); |
713 | INIT_LIST_HEAD(&pinned_vmas); | ||
706 | while (!list_empty(vmas)) { | 714 | while (!list_empty(vmas)) { |
707 | struct drm_i915_gem_exec_object2 *entry; | 715 | struct drm_i915_gem_exec_object2 *entry; |
708 | bool need_fence, need_mappable; | 716 | bool need_fence, need_mappable; |
@@ -721,7 +729,9 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring, | |||
721 | obj->tiling_mode != I915_TILING_NONE; | 729 | obj->tiling_mode != I915_TILING_NONE; |
722 | need_mappable = need_fence || need_reloc_mappable(vma); | 730 | need_mappable = need_fence || need_reloc_mappable(vma); |
723 | 731 | ||
724 | if (need_mappable) { | 732 | if (entry->flags & EXEC_OBJECT_PINNED) |
733 | list_move_tail(&vma->exec_list, &pinned_vmas); | ||
734 | else if (need_mappable) { | ||
725 | entry->flags |= __EXEC_OBJECT_NEEDS_MAP; | 735 | entry->flags |= __EXEC_OBJECT_NEEDS_MAP; |
726 | list_move(&vma->exec_list, &ordered_vmas); | 736 | list_move(&vma->exec_list, &ordered_vmas); |
727 | } else | 737 | } else |
@@ -731,6 +741,7 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring, | |||
731 | obj->base.pending_write_domain = 0; | 741 | obj->base.pending_write_domain = 0; |
732 | } | 742 | } |
733 | list_splice(&ordered_vmas, vmas); | 743 | list_splice(&ordered_vmas, vmas); |
744 | list_splice(&pinned_vmas, vmas); | ||
734 | 745 | ||
735 | /* Attempt to pin all of the buffers into the GTT. | 746 | /* Attempt to pin all of the buffers into the GTT. |
736 | * This is done in 3 phases: | 747 | * This is done in 3 phases: |
@@ -1317,7 +1328,8 @@ eb_get_batch(struct eb_vmas *eb) | |||
1317 | * Note that actual hangs have only been observed on gen7, but for | 1328 | * Note that actual hangs have only been observed on gen7, but for |
1318 | * paranoia do it everywhere. | 1329 | * paranoia do it everywhere. |
1319 | */ | 1330 | */ |
1320 | vma->exec_entry->flags |= __EXEC_OBJECT_NEEDS_BIAS; | 1331 | if ((vma->exec_entry->flags & EXEC_OBJECT_PINNED) == 0) |
1332 | vma->exec_entry->flags |= __EXEC_OBJECT_NEEDS_BIAS; | ||
1321 | 1333 | ||
1322 | return vma->obj; | 1334 | return vma->obj; |
1323 | } | 1335 | } |
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 67ef73a5d6eb..d727b49f07ac 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h | |||
@@ -356,6 +356,7 @@ typedef struct drm_i915_irq_wait { | |||
356 | #define I915_PARAM_EU_TOTAL 34 | 356 | #define I915_PARAM_EU_TOTAL 34 |
357 | #define I915_PARAM_HAS_GPU_RESET 35 | 357 | #define I915_PARAM_HAS_GPU_RESET 35 |
358 | #define I915_PARAM_HAS_RESOURCE_STREAMER 36 | 358 | #define I915_PARAM_HAS_RESOURCE_STREAMER 36 |
359 | #define I915_PARAM_HAS_EXEC_SOFTPIN 37 | ||
359 | 360 | ||
360 | typedef struct drm_i915_getparam { | 361 | typedef struct drm_i915_getparam { |
361 | __s32 param; | 362 | __s32 param; |
@@ -682,8 +683,12 @@ struct drm_i915_gem_exec_object2 { | |||
682 | __u64 alignment; | 683 | __u64 alignment; |
683 | 684 | ||
684 | /** | 685 | /** |
685 | * Returned value of the updated offset of the object, for future | 686 | * When the EXEC_OBJECT_PINNED flag is specified this is populated by |
686 | * presumed_offset writes. | 687 | * the user with the GTT offset at which this object will be pinned. |
688 | * When the I915_EXEC_NO_RELOC flag is specified this must contain the | ||
689 | * presumed_offset of the object. | ||
690 | * During execbuffer2 the kernel populates it with the value of the | ||
691 | * current GTT offset of the object, for future presumed_offset writes. | ||
687 | */ | 692 | */ |
688 | __u64 offset; | 693 | __u64 offset; |
689 | 694 | ||
@@ -691,7 +696,8 @@ struct drm_i915_gem_exec_object2 { | |||
691 | #define EXEC_OBJECT_NEEDS_GTT (1<<1) | 696 | #define EXEC_OBJECT_NEEDS_GTT (1<<1) |
692 | #define EXEC_OBJECT_WRITE (1<<2) | 697 | #define EXEC_OBJECT_WRITE (1<<2) |
693 | #define EXEC_OBJECT_SUPPORTS_48B_ADDRESS (1<<3) | 698 | #define EXEC_OBJECT_SUPPORTS_48B_ADDRESS (1<<3) |
694 | #define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_SUPPORTS_48B_ADDRESS<<1) | 699 | #define EXEC_OBJECT_PINNED (1<<4) |
700 | #define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_PINNED<<1) | ||
695 | __u64 flags; | 701 | __u64 flags; |
696 | 702 | ||
697 | __u64 rsvd1; | 703 | __u64 rsvd1; |