diff options
| -rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 46 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_gem_evict.c | 9 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_gem_execbuffer.c | 76 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_gem_gtt.c | 4 |
5 files changed, 103 insertions, 38 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ec5f6fb42ab3..388c028e223c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
| @@ -2189,10 +2189,12 @@ void i915_gem_vma_destroy(struct i915_vma *vma); | |||
| 2189 | #define PIN_MAPPABLE 0x1 | 2189 | #define PIN_MAPPABLE 0x1 |
| 2190 | #define PIN_NONBLOCK 0x2 | 2190 | #define PIN_NONBLOCK 0x2 |
| 2191 | #define PIN_GLOBAL 0x4 | 2191 | #define PIN_GLOBAL 0x4 |
| 2192 | #define PIN_OFFSET_BIAS 0x8 | ||
| 2193 | #define PIN_OFFSET_MASK (~4095) | ||
| 2192 | int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj, | 2194 | int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj, |
| 2193 | struct i915_address_space *vm, | 2195 | struct i915_address_space *vm, |
| 2194 | uint32_t alignment, | 2196 | uint32_t alignment, |
| 2195 | unsigned flags); | 2197 | uint64_t flags); |
| 2196 | int __must_check i915_vma_unbind(struct i915_vma *vma); | 2198 | int __must_check i915_vma_unbind(struct i915_vma *vma); |
| 2197 | int i915_gem_object_put_pages(struct drm_i915_gem_object *obj); | 2199 | int i915_gem_object_put_pages(struct drm_i915_gem_object *obj); |
| 2198 | void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv); | 2200 | void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv); |
| @@ -2445,6 +2447,8 @@ int __must_check i915_gem_evict_something(struct drm_device *dev, | |||
| 2445 | int min_size, | 2447 | int min_size, |
| 2446 | unsigned alignment, | 2448 | unsigned alignment, |
| 2447 | unsigned cache_level, | 2449 | unsigned cache_level, |
| 2450 | unsigned long start, | ||
| 2451 | unsigned long end, | ||
| 2448 | unsigned flags); | 2452 | unsigned flags); |
| 2449 | int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle); | 2453 | int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle); |
| 2450 | int i915_gem_evict_everything(struct drm_device *dev); | 2454 | 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 b391f30f9985..3326770c9ed2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
| @@ -3326,12 +3326,14 @@ static struct i915_vma * | |||
| 3326 | i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, | 3326 | i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, |
| 3327 | struct i915_address_space *vm, | 3327 | struct i915_address_space *vm, |
| 3328 | unsigned alignment, | 3328 | unsigned alignment, |
| 3329 | unsigned flags) | 3329 | uint64_t flags) |
| 3330 | { | 3330 | { |
| 3331 | struct drm_device *dev = obj->base.dev; | 3331 | struct drm_device *dev = obj->base.dev; |
| 3332 | struct drm_i915_private *dev_priv = dev->dev_private; | 3332 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 3333 | u32 size, fence_size, fence_alignment, unfenced_alignment; | 3333 | u32 size, fence_size, fence_alignment, unfenced_alignment; |
| 3334 | size_t gtt_max = | 3334 | unsigned long start = |
| 3335 | flags & PIN_OFFSET_BIAS ? flags & PIN_OFFSET_MASK : 0; | ||
| 3336 | unsigned long end = | ||
| 3335 | flags & PIN_MAPPABLE ? dev_priv->gtt.mappable_end : vm->total; | 3337 | flags & PIN_MAPPABLE ? dev_priv->gtt.mappable_end : vm->total; |
| 3336 | struct i915_vma *vma; | 3338 | struct i915_vma *vma; |
| 3337 | int ret; | 3339 | int ret; |
| @@ -3360,11 +3362,11 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, | |||
| 3360 | /* If the object is bigger than the entire aperture, reject it early | 3362 | /* If the object is bigger than the entire aperture, reject it early |
| 3361 | * before evicting everything in a vain attempt to find space. | 3363 | * before evicting everything in a vain attempt to find space. |
| 3362 | */ | 3364 | */ |
| 3363 | if (obj->base.size > gtt_max) { | 3365 | if (obj->base.size > end) { |
| 3364 | DRM_DEBUG("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%zu\n", | 3366 | DRM_DEBUG("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%lu\n", |
| 3365 | obj->base.size, | 3367 | obj->base.size, |
| 3366 | flags & PIN_MAPPABLE ? "mappable" : "total", | 3368 | flags & PIN_MAPPABLE ? "mappable" : "total", |
| 3367 | gtt_max); | 3369 | end); |
| 3368 | return ERR_PTR(-E2BIG); | 3370 | return ERR_PTR(-E2BIG); |
| 3369 | } | 3371 | } |
| 3370 | 3372 | ||
| @@ -3381,12 +3383,15 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, | |||
| 3381 | search_free: | 3383 | search_free: |
| 3382 | ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node, | 3384 | ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node, |
| 3383 | size, alignment, | 3385 | size, alignment, |
| 3384 | obj->cache_level, 0, gtt_max, | 3386 | obj->cache_level, |
| 3387 | start, end, | ||
| 3385 | DRM_MM_SEARCH_DEFAULT, | 3388 | DRM_MM_SEARCH_DEFAULT, |
| 3386 | DRM_MM_CREATE_DEFAULT); | 3389 | DRM_MM_CREATE_DEFAULT); |
| 3387 | if (ret) { | 3390 | if (ret) { |
| 3388 | ret = i915_gem_evict_something(dev, vm, size, alignment, | 3391 | ret = i915_gem_evict_something(dev, vm, size, alignment, |
| 3389 | obj->cache_level, flags); | 3392 | obj->cache_level, |
| 3393 | start, end, | ||
| 3394 | flags); | ||
| 3390 | if (ret == 0) | 3395 | if (ret == 0) |
| 3391 | goto search_free; | 3396 | goto search_free; |
| 3392 | 3397 | ||
| @@ -3946,11 +3951,30 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) | |||
| 3946 | return ret; | 3951 | return ret; |
| 3947 | } | 3952 | } |
| 3948 | 3953 | ||
| 3954 | static bool | ||
| 3955 | i915_vma_misplaced(struct i915_vma *vma, uint32_t alignment, uint64_t flags) | ||
| 3956 | { | ||
| 3957 | struct drm_i915_gem_object *obj = vma->obj; | ||
| 3958 | |||
| 3959 | if (alignment && | ||
| 3960 | vma->node.start & (alignment - 1)) | ||
| 3961 | return true; | ||
| 3962 | |||
| 3963 | if (flags & PIN_MAPPABLE && !obj->map_and_fenceable) | ||
| 3964 | return true; | ||
| 3965 | |||
| 3966 | if (flags & PIN_OFFSET_BIAS && | ||
| 3967 | vma->node.start < (flags & PIN_OFFSET_MASK)) | ||
| 3968 | return true; | ||
| 3969 | |||
| 3970 | return false; | ||
| 3971 | } | ||
| 3972 | |||
| 3949 | int | 3973 | int |
| 3950 | i915_gem_object_pin(struct drm_i915_gem_object *obj, | 3974 | i915_gem_object_pin(struct drm_i915_gem_object *obj, |
| 3951 | struct i915_address_space *vm, | 3975 | struct i915_address_space *vm, |
| 3952 | uint32_t alignment, | 3976 | uint32_t alignment, |
| 3953 | unsigned flags) | 3977 | uint64_t flags) |
| 3954 | { | 3978 | { |
| 3955 | struct i915_vma *vma; | 3979 | struct i915_vma *vma; |
| 3956 | int ret; | 3980 | int ret; |
| @@ -3963,15 +3987,13 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, | |||
| 3963 | if (WARN_ON(vma->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT)) | 3987 | if (WARN_ON(vma->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT)) |
| 3964 | return -EBUSY; | 3988 | return -EBUSY; |
| 3965 | 3989 | ||
| 3966 | if ((alignment && | 3990 | if (i915_vma_misplaced(vma, alignment, flags)) { |
| 3967 | vma->node.start & (alignment - 1)) || | ||
| 3968 | (flags & PIN_MAPPABLE && !obj->map_and_fenceable)) { | ||
| 3969 | WARN(vma->pin_count, | 3991 | WARN(vma->pin_count, |
| 3970 | "bo is already pinned with incorrect alignment:" | 3992 | "bo is already pinned with incorrect alignment:" |
| 3971 | " offset=%lx, req.alignment=%x, req.map_and_fenceable=%d," | 3993 | " offset=%lx, req.alignment=%x, req.map_and_fenceable=%d," |
| 3972 | " obj->map_and_fenceable=%d\n", | 3994 | " obj->map_and_fenceable=%d\n", |
| 3973 | i915_gem_obj_offset(obj, vm), alignment, | 3995 | i915_gem_obj_offset(obj, vm), alignment, |
| 3974 | flags & PIN_MAPPABLE, | 3996 | !!(flags & PIN_MAPPABLE), |
| 3975 | obj->map_and_fenceable); | 3997 | obj->map_and_fenceable); |
| 3976 | ret = i915_vma_unbind(vma); | 3998 | ret = i915_vma_unbind(vma); |
| 3977 | if (ret) | 3999 | if (ret) |
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 75fca63dc8c1..bbf4b12d842e 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c | |||
| @@ -68,9 +68,9 @@ mark_free(struct i915_vma *vma, struct list_head *unwind) | |||
| 68 | int | 68 | int |
| 69 | i915_gem_evict_something(struct drm_device *dev, struct i915_address_space *vm, | 69 | i915_gem_evict_something(struct drm_device *dev, struct i915_address_space *vm, |
| 70 | int min_size, unsigned alignment, unsigned cache_level, | 70 | int min_size, unsigned alignment, unsigned cache_level, |
| 71 | unsigned long start, unsigned long end, | ||
| 71 | unsigned flags) | 72 | unsigned flags) |
| 72 | { | 73 | { |
| 73 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 74 | struct list_head eviction_list, unwind_list; | 74 | struct list_head eviction_list, unwind_list; |
| 75 | struct i915_vma *vma; | 75 | struct i915_vma *vma; |
| 76 | int ret = 0; | 76 | int ret = 0; |
| @@ -102,11 +102,10 @@ i915_gem_evict_something(struct drm_device *dev, struct i915_address_space *vm, | |||
| 102 | */ | 102 | */ |
| 103 | 103 | ||
| 104 | INIT_LIST_HEAD(&unwind_list); | 104 | INIT_LIST_HEAD(&unwind_list); |
| 105 | if (flags & PIN_MAPPABLE) { | 105 | if (start != 0 || end != vm->total) { |
| 106 | BUG_ON(!i915_is_ggtt(vm)); | ||
| 107 | drm_mm_init_scan_with_range(&vm->mm, min_size, | 106 | drm_mm_init_scan_with_range(&vm->mm, min_size, |
| 108 | alignment, cache_level, 0, | 107 | alignment, cache_level, |
| 109 | dev_priv->gtt.mappable_end); | 108 | start, end); |
| 110 | } else | 109 | } else |
| 111 | drm_mm_init_scan(&vm->mm, min_size, alignment, cache_level); | 110 | drm_mm_init_scan(&vm->mm, min_size, alignment, cache_level); |
| 112 | 111 | ||
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 7aaf6390cfaf..20fef6c50267 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c | |||
| @@ -35,6 +35,9 @@ | |||
| 35 | 35 | ||
| 36 | #define __EXEC_OBJECT_HAS_PIN (1<<31) | 36 | #define __EXEC_OBJECT_HAS_PIN (1<<31) |
| 37 | #define __EXEC_OBJECT_HAS_FENCE (1<<30) | 37 | #define __EXEC_OBJECT_HAS_FENCE (1<<30) |
| 38 | #define __EXEC_OBJECT_NEEDS_BIAS (1<<28) | ||
| 39 | |||
| 40 | #define BATCH_OFFSET_BIAS (256*1024) | ||
| 38 | 41 | ||
| 39 | struct eb_vmas { | 42 | struct eb_vmas { |
| 40 | struct list_head vmas; | 43 | struct list_head vmas; |
| @@ -545,7 +548,7 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma, | |||
| 545 | struct drm_i915_gem_exec_object2 *entry = vma->exec_entry; | 548 | struct drm_i915_gem_exec_object2 *entry = vma->exec_entry; |
| 546 | bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4; | 549 | bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4; |
| 547 | bool need_fence; | 550 | bool need_fence; |
| 548 | unsigned flags; | 551 | uint64_t flags; |
| 549 | int ret; | 552 | int ret; |
| 550 | 553 | ||
| 551 | flags = 0; | 554 | flags = 0; |
| @@ -559,6 +562,8 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma, | |||
| 559 | 562 | ||
| 560 | if (entry->flags & EXEC_OBJECT_NEEDS_GTT) | 563 | if (entry->flags & EXEC_OBJECT_NEEDS_GTT) |
| 561 | flags |= PIN_GLOBAL; | 564 | flags |= PIN_GLOBAL; |
| 565 | if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS) | ||
| 566 | flags |= BATCH_OFFSET_BIAS | PIN_OFFSET_BIAS; | ||
| 562 | 567 | ||
| 563 | ret = i915_gem_object_pin(obj, vma->vm, entry->alignment, flags); | 568 | ret = i915_gem_object_pin(obj, vma->vm, entry->alignment, flags); |
| 564 | if (ret) | 569 | if (ret) |
| @@ -592,6 +597,36 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma, | |||
| 592 | return 0; | 597 | return 0; |
| 593 | } | 598 | } |
| 594 | 599 | ||
| 600 | static bool | ||
| 601 | eb_vma_misplaced(struct i915_vma *vma, bool has_fenced_gpu_access) | ||
| 602 | { | ||
| 603 | struct drm_i915_gem_exec_object2 *entry = vma->exec_entry; | ||
| 604 | struct drm_i915_gem_object *obj = vma->obj; | ||
| 605 | bool need_fence, need_mappable; | ||
| 606 | |||
| 607 | need_fence = | ||
| 608 | has_fenced_gpu_access && | ||
| 609 | entry->flags & EXEC_OBJECT_NEEDS_FENCE && | ||
| 610 | obj->tiling_mode != I915_TILING_NONE; | ||
| 611 | need_mappable = need_fence || need_reloc_mappable(vma); | ||
| 612 | |||
| 613 | WARN_ON((need_mappable || need_fence) && | ||
| 614 | !i915_is_ggtt(vma->vm)); | ||
| 615 | |||
| 616 | if (entry->alignment && | ||
| 617 | vma->node.start & (entry->alignment - 1)) | ||
| 618 | return true; | ||
| 619 | |||
| 620 | if (need_mappable && !obj->map_and_fenceable) | ||
| 621 | return true; | ||
| 622 | |||
| 623 | if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS && | ||
| 624 | vma->node.start < BATCH_OFFSET_BIAS) | ||
| 625 | return true; | ||
| 626 | |||
| 627 | return false; | ||
| 628 | } | ||
| 629 | |||
| 595 | static int | 630 | static int |
| 596 | i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, | 631 | i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, |
| 597 | struct list_head *vmas, | 632 | struct list_head *vmas, |
| @@ -653,26 +688,10 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, | |||
| 653 | 688 | ||
| 654 | /* Unbind any ill-fitting objects or pin. */ | 689 | /* Unbind any ill-fitting objects or pin. */ |
| 655 | list_for_each_entry(vma, vmas, exec_list) { | 690 | list_for_each_entry(vma, vmas, exec_list) { |
| 656 | struct drm_i915_gem_exec_object2 *entry = vma->exec_entry; | ||
| 657 | bool need_fence, need_mappable; | ||
| 658 | |||
| 659 | obj = vma->obj; | ||
| 660 | |||
| 661 | if (!drm_mm_node_allocated(&vma->node)) | 691 | if (!drm_mm_node_allocated(&vma->node)) |
| 662 | continue; | 692 | continue; |
| 663 | 693 | ||
| 664 | need_fence = | 694 | if (eb_vma_misplaced(vma, has_fenced_gpu_access)) |
| 665 | has_fenced_gpu_access && | ||
| 666 | entry->flags & EXEC_OBJECT_NEEDS_FENCE && | ||
| 667 | obj->tiling_mode != I915_TILING_NONE; | ||
| 668 | need_mappable = need_fence || need_reloc_mappable(vma); | ||
| 669 | |||
| 670 | WARN_ON((need_mappable || need_fence) && | ||
| 671 | !i915_is_ggtt(vma->vm)); | ||
| 672 | |||
| 673 | if ((entry->alignment && | ||
| 674 | vma->node.start & (entry->alignment - 1)) || | ||
| 675 | (need_mappable && !obj->map_and_fenceable)) | ||
| 676 | ret = i915_vma_unbind(vma); | 695 | ret = i915_vma_unbind(vma); |
| 677 | else | 696 | else |
| 678 | ret = i915_gem_execbuffer_reserve_vma(vma, ring, need_relocs); | 697 | ret = i915_gem_execbuffer_reserve_vma(vma, ring, need_relocs); |
| @@ -999,6 +1018,25 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev, | |||
| 999 | return 0; | 1018 | return 0; |
| 1000 | } | 1019 | } |
| 1001 | 1020 | ||
| 1021 | static struct drm_i915_gem_object * | ||
| 1022 | eb_get_batch(struct eb_vmas *eb) | ||
| 1023 | { | ||
| 1024 | struct i915_vma *vma = list_entry(eb->vmas.prev, typeof(*vma), exec_list); | ||
| 1025 | |||
| 1026 | /* | ||
| 1027 | * SNA is doing fancy tricks with compressing batch buffers, which leads | ||
| 1028 | * to negative relocation deltas. Usually that works out ok since the | ||
| 1029 | * relocate address is still positive, except when the batch is placed | ||
| 1030 | * very low in the GTT. Ensure this doesn't happen. | ||
| 1031 | * | ||
| 1032 | * Note that actual hangs have only been observed on gen7, but for | ||
| 1033 | * paranoia do it everywhere. | ||
| 1034 | */ | ||
| 1035 | vma->exec_entry->flags |= __EXEC_OBJECT_NEEDS_BIAS; | ||
| 1036 | |||
| 1037 | return vma->obj; | ||
| 1038 | } | ||
| 1039 | |||
| 1002 | static int | 1040 | static int |
| 1003 | i915_gem_do_execbuffer(struct drm_device *dev, void *data, | 1041 | i915_gem_do_execbuffer(struct drm_device *dev, void *data, |
| 1004 | struct drm_file *file, | 1042 | struct drm_file *file, |
| @@ -1153,7 +1191,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, | |||
| 1153 | goto err; | 1191 | goto err; |
| 1154 | 1192 | ||
| 1155 | /* take note of the batch buffer before we might reorder the lists */ | 1193 | /* take note of the batch buffer before we might reorder the lists */ |
| 1156 | batch_obj = list_entry(eb->vmas.prev, struct i915_vma, exec_list)->obj; | 1194 | batch_obj = eb_get_batch(eb); |
| 1157 | 1195 | ||
| 1158 | /* Move the objects en-masse into the GTT, evicting if necessary. */ | 1196 | /* Move the objects en-masse into the GTT, evicting if necessary. */ |
| 1159 | need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; | 1197 | need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; |
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 154b0f8bb88d..5deb22864c52 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c | |||
| @@ -1089,7 +1089,9 @@ alloc: | |||
| 1089 | if (ret == -ENOSPC && !retried) { | 1089 | if (ret == -ENOSPC && !retried) { |
| 1090 | ret = i915_gem_evict_something(dev, &dev_priv->gtt.base, | 1090 | ret = i915_gem_evict_something(dev, &dev_priv->gtt.base, |
| 1091 | GEN6_PD_SIZE, GEN6_PD_ALIGN, | 1091 | GEN6_PD_SIZE, GEN6_PD_ALIGN, |
| 1092 | I915_CACHE_NONE, 0); | 1092 | I915_CACHE_NONE, |
| 1093 | 0, dev_priv->gtt.base.total, | ||
| 1094 | 0); | ||
| 1093 | if (ret) | 1095 | if (ret) |
| 1094 | return ret; | 1096 | return ret; |
| 1095 | 1097 | ||
