diff options
author | Dave Airlie <airlied@redhat.com> | 2013-11-06 21:22:10 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2013-11-06 21:22:10 -0500 |
commit | 212c444baa4efe0077fb2a07a65ccb3011b94e8f (patch) | |
tree | b8892c347a6901dd711f0ba01dc5bc41ce7ad80b | |
parent | 1e95ab5846504b2c0e9a01405bbb3278e2e20480 (diff) | |
parent | 59c8e66378fb78adbcd05f0d09783dde6fef282b (diff) |
Merge branch 'ttm-next-3.13' of git://people.freedesktop.org/~thomash/linux into drm-next
- A couple of fixes that never made it into fixes-3.12
- Make NO_EVICT bo's available for shrinkers when on delayed-delete list
- Allow retrying page-faults that need to wait for GPU.
* 'ttm-next-3.13' of git://people.freedesktop.org/~thomash/linux:
drm/ttm: Fix memory type compatibility check
drm/ttm: Fix ttm_bo_move_memcpy
drm/ttm: Handle in-memory region copies
drm/ttm: Make NO_EVICT bos available to shrinkers pending destruction
drm/ttm: Allow vm fault retries
-rw-r--r-- | drivers/gpu/drm/ttm/ttm_bo.c | 46 | ||||
-rw-r--r-- | drivers/gpu/drm/ttm/ttm_bo_util.c | 30 | ||||
-rw-r--r-- | drivers/gpu/drm/ttm/ttm_bo_vm.c | 62 |
3 files changed, 102 insertions, 36 deletions
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index f1a857ec1021..8d5a646ebe6a 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c | |||
@@ -429,8 +429,20 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) | |||
429 | sync_obj = driver->sync_obj_ref(bo->sync_obj); | 429 | sync_obj = driver->sync_obj_ref(bo->sync_obj); |
430 | spin_unlock(&bdev->fence_lock); | 430 | spin_unlock(&bdev->fence_lock); |
431 | 431 | ||
432 | if (!ret) | 432 | if (!ret) { |
433 | |||
434 | /* | ||
435 | * Make NO_EVICT bos immediately available to | ||
436 | * shrinkers, now that they are queued for | ||
437 | * destruction. | ||
438 | */ | ||
439 | if (bo->mem.placement & TTM_PL_FLAG_NO_EVICT) { | ||
440 | bo->mem.placement &= ~TTM_PL_FLAG_NO_EVICT; | ||
441 | ttm_bo_add_to_lru(bo); | ||
442 | } | ||
443 | |||
433 | ww_mutex_unlock(&bo->resv->lock); | 444 | ww_mutex_unlock(&bo->resv->lock); |
445 | } | ||
434 | 446 | ||
435 | kref_get(&bo->list_kref); | 447 | kref_get(&bo->list_kref); |
436 | list_add_tail(&bo->ddestroy, &bdev->ddestroy); | 448 | list_add_tail(&bo->ddestroy, &bdev->ddestroy); |
@@ -986,24 +998,32 @@ out_unlock: | |||
986 | return ret; | 998 | return ret; |
987 | } | 999 | } |
988 | 1000 | ||
989 | static int ttm_bo_mem_compat(struct ttm_placement *placement, | 1001 | static bool ttm_bo_mem_compat(struct ttm_placement *placement, |
990 | struct ttm_mem_reg *mem) | 1002 | struct ttm_mem_reg *mem, |
1003 | uint32_t *new_flags) | ||
991 | { | 1004 | { |
992 | int i; | 1005 | int i; |
993 | 1006 | ||
994 | if (mem->mm_node && placement->lpfn != 0 && | 1007 | if (mem->mm_node && placement->lpfn != 0 && |
995 | (mem->start < placement->fpfn || | 1008 | (mem->start < placement->fpfn || |
996 | mem->start + mem->num_pages > placement->lpfn)) | 1009 | mem->start + mem->num_pages > placement->lpfn)) |
997 | return -1; | 1010 | return false; |
998 | 1011 | ||
999 | for (i = 0; i < placement->num_placement; i++) { | 1012 | for (i = 0; i < placement->num_placement; i++) { |
1000 | if ((placement->placement[i] & mem->placement & | 1013 | *new_flags = placement->placement[i]; |
1001 | TTM_PL_MASK_CACHING) && | 1014 | if ((*new_flags & mem->placement & TTM_PL_MASK_CACHING) && |
1002 | (placement->placement[i] & mem->placement & | 1015 | (*new_flags & mem->placement & TTM_PL_MASK_MEM)) |
1003 | TTM_PL_MASK_MEM)) | 1016 | return true; |
1004 | return i; | ||
1005 | } | 1017 | } |
1006 | return -1; | 1018 | |
1019 | for (i = 0; i < placement->num_busy_placement; i++) { | ||
1020 | *new_flags = placement->busy_placement[i]; | ||
1021 | if ((*new_flags & mem->placement & TTM_PL_MASK_CACHING) && | ||
1022 | (*new_flags & mem->placement & TTM_PL_MASK_MEM)) | ||
1023 | return true; | ||
1024 | } | ||
1025 | |||
1026 | return false; | ||
1007 | } | 1027 | } |
1008 | 1028 | ||
1009 | int ttm_bo_validate(struct ttm_buffer_object *bo, | 1029 | int ttm_bo_validate(struct ttm_buffer_object *bo, |
@@ -1012,6 +1032,7 @@ int ttm_bo_validate(struct ttm_buffer_object *bo, | |||
1012 | bool no_wait_gpu) | 1032 | bool no_wait_gpu) |
1013 | { | 1033 | { |
1014 | int ret; | 1034 | int ret; |
1035 | uint32_t new_flags; | ||
1015 | 1036 | ||
1016 | lockdep_assert_held(&bo->resv->lock.base); | 1037 | lockdep_assert_held(&bo->resv->lock.base); |
1017 | /* Check that range is valid */ | 1038 | /* Check that range is valid */ |
@@ -1022,8 +1043,7 @@ int ttm_bo_validate(struct ttm_buffer_object *bo, | |||
1022 | /* | 1043 | /* |
1023 | * Check whether we need to move buffer. | 1044 | * Check whether we need to move buffer. |
1024 | */ | 1045 | */ |
1025 | ret = ttm_bo_mem_compat(placement, &bo->mem); | 1046 | if (!ttm_bo_mem_compat(placement, &bo->mem, &new_flags)) { |
1026 | if (ret < 0) { | ||
1027 | ret = ttm_bo_move_buffer(bo, placement, interruptible, | 1047 | ret = ttm_bo_move_buffer(bo, placement, interruptible, |
1028 | no_wait_gpu); | 1048 | no_wait_gpu); |
1029 | if (ret) | 1049 | if (ret) |
@@ -1033,7 +1053,7 @@ int ttm_bo_validate(struct ttm_buffer_object *bo, | |||
1033 | * Use the access and other non-mapping-related flag bits from | 1053 | * Use the access and other non-mapping-related flag bits from |
1034 | * the compatible memory placement flags to the active flags | 1054 | * the compatible memory placement flags to the active flags |
1035 | */ | 1055 | */ |
1036 | ttm_flag_masked(&bo->mem.placement, placement->placement[ret], | 1056 | ttm_flag_masked(&bo->mem.placement, new_flags, |
1037 | ~TTM_PL_MASK_MEMTYPE); | 1057 | ~TTM_PL_MASK_MEMTYPE); |
1038 | } | 1058 | } |
1039 | /* | 1059 | /* |
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 7cc904d3a4d1..4834c463c38b 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c | |||
@@ -343,19 +343,25 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, | |||
343 | if (ret) | 343 | if (ret) |
344 | goto out; | 344 | goto out; |
345 | 345 | ||
346 | /* | ||
347 | * Single TTM move. NOP. | ||
348 | */ | ||
346 | if (old_iomap == NULL && new_iomap == NULL) | 349 | if (old_iomap == NULL && new_iomap == NULL) |
347 | goto out2; | 350 | goto out2; |
351 | |||
352 | /* | ||
353 | * Move nonexistent data. NOP. | ||
354 | */ | ||
348 | if (old_iomap == NULL && ttm == NULL) | 355 | if (old_iomap == NULL && ttm == NULL) |
349 | goto out2; | 356 | goto out2; |
350 | 357 | ||
351 | if (ttm->state == tt_unpopulated) { | 358 | /* |
359 | * TTM might be null for moves within the same region. | ||
360 | */ | ||
361 | if (ttm && ttm->state == tt_unpopulated) { | ||
352 | ret = ttm->bdev->driver->ttm_tt_populate(ttm); | 362 | ret = ttm->bdev->driver->ttm_tt_populate(ttm); |
353 | if (ret) { | 363 | if (ret) |
354 | /* if we fail here don't nuke the mm node | ||
355 | * as the bo still owns it */ | ||
356 | old_copy.mm_node = NULL; | ||
357 | goto out1; | 364 | goto out1; |
358 | } | ||
359 | } | 365 | } |
360 | 366 | ||
361 | add = 0; | 367 | add = 0; |
@@ -381,11 +387,8 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, | |||
381 | prot); | 387 | prot); |
382 | } else | 388 | } else |
383 | ret = ttm_copy_io_page(new_iomap, old_iomap, page); | 389 | ret = ttm_copy_io_page(new_iomap, old_iomap, page); |
384 | if (ret) { | 390 | if (ret) |
385 | /* failing here, means keep old copy as-is */ | ||
386 | old_copy.mm_node = NULL; | ||
387 | goto out1; | 391 | goto out1; |
388 | } | ||
389 | } | 392 | } |
390 | mb(); | 393 | mb(); |
391 | out2: | 394 | out2: |
@@ -403,7 +406,12 @@ out1: | |||
403 | ttm_mem_reg_iounmap(bdev, old_mem, new_iomap); | 406 | ttm_mem_reg_iounmap(bdev, old_mem, new_iomap); |
404 | out: | 407 | out: |
405 | ttm_mem_reg_iounmap(bdev, &old_copy, old_iomap); | 408 | ttm_mem_reg_iounmap(bdev, &old_copy, old_iomap); |
406 | ttm_bo_mem_put(bo, &old_copy); | 409 | |
410 | /* | ||
411 | * On error, keep the mm node! | ||
412 | */ | ||
413 | if (!ret) | ||
414 | ttm_bo_mem_put(bo, &old_copy); | ||
407 | return ret; | 415 | return ret; |
408 | } | 416 | } |
409 | EXPORT_SYMBOL(ttm_bo_move_memcpy); | 417 | EXPORT_SYMBOL(ttm_bo_move_memcpy); |
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 1006c15445e9..c03514b93f9c 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c | |||
@@ -41,6 +41,51 @@ | |||
41 | 41 | ||
42 | #define TTM_BO_VM_NUM_PREFAULT 16 | 42 | #define TTM_BO_VM_NUM_PREFAULT 16 |
43 | 43 | ||
44 | static int ttm_bo_vm_fault_idle(struct ttm_buffer_object *bo, | ||
45 | struct vm_area_struct *vma, | ||
46 | struct vm_fault *vmf) | ||
47 | { | ||
48 | struct ttm_bo_device *bdev = bo->bdev; | ||
49 | int ret = 0; | ||
50 | |||
51 | spin_lock(&bdev->fence_lock); | ||
52 | if (likely(!test_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags))) | ||
53 | goto out_unlock; | ||
54 | |||
55 | /* | ||
56 | * Quick non-stalling check for idle. | ||
57 | */ | ||
58 | ret = ttm_bo_wait(bo, false, false, true); | ||
59 | if (likely(ret == 0)) | ||
60 | goto out_unlock; | ||
61 | |||
62 | /* | ||
63 | * If possible, avoid waiting for GPU with mmap_sem | ||
64 | * held. | ||
65 | */ | ||
66 | if (vmf->flags & FAULT_FLAG_ALLOW_RETRY) { | ||
67 | ret = VM_FAULT_RETRY; | ||
68 | if (vmf->flags & FAULT_FLAG_RETRY_NOWAIT) | ||
69 | goto out_unlock; | ||
70 | |||
71 | up_read(&vma->vm_mm->mmap_sem); | ||
72 | (void) ttm_bo_wait(bo, false, true, false); | ||
73 | goto out_unlock; | ||
74 | } | ||
75 | |||
76 | /* | ||
77 | * Ordinary wait. | ||
78 | */ | ||
79 | ret = ttm_bo_wait(bo, false, true, false); | ||
80 | if (unlikely(ret != 0)) | ||
81 | ret = (ret != -ERESTARTSYS) ? VM_FAULT_SIGBUS : | ||
82 | VM_FAULT_NOPAGE; | ||
83 | |||
84 | out_unlock: | ||
85 | spin_unlock(&bdev->fence_lock); | ||
86 | return ret; | ||
87 | } | ||
88 | |||
44 | static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | 89 | static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) |
45 | { | 90 | { |
46 | struct ttm_buffer_object *bo = (struct ttm_buffer_object *) | 91 | struct ttm_buffer_object *bo = (struct ttm_buffer_object *) |
@@ -91,18 +136,11 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
91 | * Wait for buffer data in transit, due to a pipelined | 136 | * Wait for buffer data in transit, due to a pipelined |
92 | * move. | 137 | * move. |
93 | */ | 138 | */ |
94 | 139 | ret = ttm_bo_vm_fault_idle(bo, vma, vmf); | |
95 | spin_lock(&bdev->fence_lock); | 140 | if (unlikely(ret != 0)) { |
96 | if (test_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags)) { | 141 | retval = ret; |
97 | ret = ttm_bo_wait(bo, false, true, false); | 142 | goto out_unlock; |
98 | spin_unlock(&bdev->fence_lock); | 143 | } |
99 | if (unlikely(ret != 0)) { | ||
100 | retval = (ret != -ERESTARTSYS) ? | ||
101 | VM_FAULT_SIGBUS : VM_FAULT_NOPAGE; | ||
102 | goto out_unlock; | ||
103 | } | ||
104 | } else | ||
105 | spin_unlock(&bdev->fence_lock); | ||
106 | 144 | ||
107 | ret = ttm_mem_io_lock(man, true); | 145 | ret = ttm_mem_io_lock(man, true); |
108 | if (unlikely(ret != 0)) { | 146 | if (unlikely(ret != 0)) { |