diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_vm.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_vm.c | 236 |
1 files changed, 149 insertions, 87 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index dfde266529e2..cde48c42b30a 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c | |||
@@ -125,41 +125,37 @@ void radeon_vm_manager_fini(struct radeon_device *rdev) | |||
125 | * Add the page directory to the list of BOs to | 125 | * Add the page directory to the list of BOs to |
126 | * validate for command submission (cayman+). | 126 | * validate for command submission (cayman+). |
127 | */ | 127 | */ |
128 | struct radeon_cs_reloc *radeon_vm_get_bos(struct radeon_device *rdev, | 128 | struct radeon_bo_list *radeon_vm_get_bos(struct radeon_device *rdev, |
129 | struct radeon_vm *vm, | 129 | struct radeon_vm *vm, |
130 | struct list_head *head) | 130 | struct list_head *head) |
131 | { | 131 | { |
132 | struct radeon_cs_reloc *list; | 132 | struct radeon_bo_list *list; |
133 | unsigned i, idx; | 133 | unsigned i, idx; |
134 | 134 | ||
135 | list = drm_malloc_ab(vm->max_pde_used + 2, | 135 | list = drm_malloc_ab(vm->max_pde_used + 2, |
136 | sizeof(struct radeon_cs_reloc)); | 136 | sizeof(struct radeon_bo_list)); |
137 | if (!list) | 137 | if (!list) |
138 | return NULL; | 138 | return NULL; |
139 | 139 | ||
140 | /* add the vm page table to the list */ | 140 | /* add the vm page table to the list */ |
141 | list[0].gobj = NULL; | ||
142 | list[0].robj = vm->page_directory; | 141 | list[0].robj = vm->page_directory; |
143 | list[0].prefered_domains = RADEON_GEM_DOMAIN_VRAM; | 142 | list[0].prefered_domains = RADEON_GEM_DOMAIN_VRAM; |
144 | list[0].allowed_domains = RADEON_GEM_DOMAIN_VRAM; | 143 | list[0].allowed_domains = RADEON_GEM_DOMAIN_VRAM; |
145 | list[0].tv.bo = &vm->page_directory->tbo; | 144 | list[0].tv.bo = &vm->page_directory->tbo; |
146 | list[0].tv.shared = false; | 145 | list[0].tv.shared = true; |
147 | list[0].tiling_flags = 0; | 146 | list[0].tiling_flags = 0; |
148 | list[0].handle = 0; | ||
149 | list_add(&list[0].tv.head, head); | 147 | list_add(&list[0].tv.head, head); |
150 | 148 | ||
151 | for (i = 0, idx = 1; i <= vm->max_pde_used; i++) { | 149 | for (i = 0, idx = 1; i <= vm->max_pde_used; i++) { |
152 | if (!vm->page_tables[i].bo) | 150 | if (!vm->page_tables[i].bo) |
153 | continue; | 151 | continue; |
154 | 152 | ||
155 | list[idx].gobj = NULL; | ||
156 | list[idx].robj = vm->page_tables[i].bo; | 153 | list[idx].robj = vm->page_tables[i].bo; |
157 | list[idx].prefered_domains = RADEON_GEM_DOMAIN_VRAM; | 154 | list[idx].prefered_domains = RADEON_GEM_DOMAIN_VRAM; |
158 | list[idx].allowed_domains = RADEON_GEM_DOMAIN_VRAM; | 155 | list[idx].allowed_domains = RADEON_GEM_DOMAIN_VRAM; |
159 | list[idx].tv.bo = &list[idx].robj->tbo; | 156 | list[idx].tv.bo = &list[idx].robj->tbo; |
160 | list[idx].tv.shared = false; | 157 | list[idx].tv.shared = true; |
161 | list[idx].tiling_flags = 0; | 158 | list[idx].tiling_flags = 0; |
162 | list[idx].handle = 0; | ||
163 | list_add(&list[idx++].tv.head, head); | 159 | list_add(&list[idx++].tv.head, head); |
164 | } | 160 | } |
165 | 161 | ||
@@ -182,15 +178,18 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev, | |||
182 | struct radeon_vm *vm, int ring) | 178 | struct radeon_vm *vm, int ring) |
183 | { | 179 | { |
184 | struct radeon_fence *best[RADEON_NUM_RINGS] = {}; | 180 | struct radeon_fence *best[RADEON_NUM_RINGS] = {}; |
181 | struct radeon_vm_id *vm_id = &vm->ids[ring]; | ||
182 | |||
185 | unsigned choices[2] = {}; | 183 | unsigned choices[2] = {}; |
186 | unsigned i; | 184 | unsigned i; |
187 | 185 | ||
188 | /* check if the id is still valid */ | 186 | /* check if the id is still valid */ |
189 | if (vm->last_id_use && vm->last_id_use == rdev->vm_manager.active[vm->id]) | 187 | if (vm_id->id && vm_id->last_id_use && |
188 | vm_id->last_id_use == rdev->vm_manager.active[vm_id->id]) | ||
190 | return NULL; | 189 | return NULL; |
191 | 190 | ||
192 | /* we definately need to flush */ | 191 | /* we definately need to flush */ |
193 | radeon_fence_unref(&vm->last_flush); | 192 | vm_id->pd_gpu_addr = ~0ll; |
194 | 193 | ||
195 | /* skip over VMID 0, since it is the system VM */ | 194 | /* skip over VMID 0, since it is the system VM */ |
196 | for (i = 1; i < rdev->vm_manager.nvm; ++i) { | 195 | for (i = 1; i < rdev->vm_manager.nvm; ++i) { |
@@ -198,8 +197,8 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev, | |||
198 | 197 | ||
199 | if (fence == NULL) { | 198 | if (fence == NULL) { |
200 | /* found a free one */ | 199 | /* found a free one */ |
201 | vm->id = i; | 200 | vm_id->id = i; |
202 | trace_radeon_vm_grab_id(vm->id, ring); | 201 | trace_radeon_vm_grab_id(i, ring); |
203 | return NULL; | 202 | return NULL; |
204 | } | 203 | } |
205 | 204 | ||
@@ -211,8 +210,8 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev, | |||
211 | 210 | ||
212 | for (i = 0; i < 2; ++i) { | 211 | for (i = 0; i < 2; ++i) { |
213 | if (choices[i]) { | 212 | if (choices[i]) { |
214 | vm->id = choices[i]; | 213 | vm_id->id = choices[i]; |
215 | trace_radeon_vm_grab_id(vm->id, ring); | 214 | trace_radeon_vm_grab_id(choices[i], ring); |
216 | return rdev->vm_manager.active[choices[i]]; | 215 | return rdev->vm_manager.active[choices[i]]; |
217 | } | 216 | } |
218 | } | 217 | } |
@@ -228,6 +227,7 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev, | |||
228 | * @rdev: radeon_device pointer | 227 | * @rdev: radeon_device pointer |
229 | * @vm: vm we want to flush | 228 | * @vm: vm we want to flush |
230 | * @ring: ring to use for flush | 229 | * @ring: ring to use for flush |
230 | * @updates: last vm update that is waited for | ||
231 | * | 231 | * |
232 | * Flush the vm (cayman+). | 232 | * Flush the vm (cayman+). |
233 | * | 233 | * |
@@ -235,15 +235,21 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev, | |||
235 | */ | 235 | */ |
236 | void radeon_vm_flush(struct radeon_device *rdev, | 236 | void radeon_vm_flush(struct radeon_device *rdev, |
237 | struct radeon_vm *vm, | 237 | struct radeon_vm *vm, |
238 | int ring) | 238 | int ring, struct radeon_fence *updates) |
239 | { | 239 | { |
240 | uint64_t pd_addr = radeon_bo_gpu_offset(vm->page_directory); | 240 | uint64_t pd_addr = radeon_bo_gpu_offset(vm->page_directory); |
241 | struct radeon_vm_id *vm_id = &vm->ids[ring]; | ||
242 | |||
243 | if (pd_addr != vm_id->pd_gpu_addr || !vm_id->flushed_updates || | ||
244 | radeon_fence_is_earlier(vm_id->flushed_updates, updates)) { | ||
245 | |||
246 | trace_radeon_vm_flush(pd_addr, ring, vm->ids[ring].id); | ||
247 | radeon_fence_unref(&vm_id->flushed_updates); | ||
248 | vm_id->flushed_updates = radeon_fence_ref(updates); | ||
249 | vm_id->pd_gpu_addr = pd_addr; | ||
250 | radeon_ring_vm_flush(rdev, &rdev->ring[ring], | ||
251 | vm_id->id, vm_id->pd_gpu_addr); | ||
241 | 252 | ||
242 | /* if we can't remember our last VM flush then flush now! */ | ||
243 | if (!vm->last_flush || pd_addr != vm->pd_gpu_addr) { | ||
244 | trace_radeon_vm_flush(pd_addr, ring, vm->id); | ||
245 | vm->pd_gpu_addr = pd_addr; | ||
246 | radeon_ring_vm_flush(rdev, ring, vm); | ||
247 | } | 253 | } |
248 | } | 254 | } |
249 | 255 | ||
@@ -263,18 +269,13 @@ void radeon_vm_fence(struct radeon_device *rdev, | |||
263 | struct radeon_vm *vm, | 269 | struct radeon_vm *vm, |
264 | struct radeon_fence *fence) | 270 | struct radeon_fence *fence) |
265 | { | 271 | { |
266 | radeon_fence_unref(&vm->fence); | 272 | unsigned vm_id = vm->ids[fence->ring].id; |
267 | vm->fence = radeon_fence_ref(fence); | ||
268 | |||
269 | radeon_fence_unref(&rdev->vm_manager.active[vm->id]); | ||
270 | rdev->vm_manager.active[vm->id] = radeon_fence_ref(fence); | ||
271 | 273 | ||
272 | radeon_fence_unref(&vm->last_id_use); | 274 | radeon_fence_unref(&rdev->vm_manager.active[vm_id]); |
273 | vm->last_id_use = radeon_fence_ref(fence); | 275 | rdev->vm_manager.active[vm_id] = radeon_fence_ref(fence); |
274 | 276 | ||
275 | /* we just flushed the VM, remember that */ | 277 | radeon_fence_unref(&vm->ids[fence->ring].last_id_use); |
276 | if (!vm->last_flush) | 278 | vm->ids[fence->ring].last_id_use = radeon_fence_ref(fence); |
277 | vm->last_flush = radeon_fence_ref(fence); | ||
278 | } | 279 | } |
279 | 280 | ||
280 | /** | 281 | /** |
@@ -387,35 +388,25 @@ static void radeon_vm_set_pages(struct radeon_device *rdev, | |||
387 | static int radeon_vm_clear_bo(struct radeon_device *rdev, | 388 | static int radeon_vm_clear_bo(struct radeon_device *rdev, |
388 | struct radeon_bo *bo) | 389 | struct radeon_bo *bo) |
389 | { | 390 | { |
390 | struct ttm_validate_buffer tv; | ||
391 | struct ww_acquire_ctx ticket; | ||
392 | struct list_head head; | ||
393 | struct radeon_ib ib; | 391 | struct radeon_ib ib; |
394 | unsigned entries; | 392 | unsigned entries; |
395 | uint64_t addr; | 393 | uint64_t addr; |
396 | int r; | 394 | int r; |
397 | 395 | ||
398 | memset(&tv, 0, sizeof(tv)); | 396 | r = radeon_bo_reserve(bo, false); |
399 | tv.bo = &bo->tbo; | 397 | if (r) |
400 | tv.shared = false; | ||
401 | |||
402 | INIT_LIST_HEAD(&head); | ||
403 | list_add(&tv.head, &head); | ||
404 | |||
405 | r = ttm_eu_reserve_buffers(&ticket, &head, true); | ||
406 | if (r) | ||
407 | return r; | 398 | return r; |
408 | 399 | ||
409 | r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false); | 400 | r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false); |
410 | if (r) | 401 | if (r) |
411 | goto error; | 402 | goto error_unreserve; |
412 | 403 | ||
413 | addr = radeon_bo_gpu_offset(bo); | 404 | addr = radeon_bo_gpu_offset(bo); |
414 | entries = radeon_bo_size(bo) / 8; | 405 | entries = radeon_bo_size(bo) / 8; |
415 | 406 | ||
416 | r = radeon_ib_get(rdev, R600_RING_TYPE_DMA_INDEX, &ib, NULL, 256); | 407 | r = radeon_ib_get(rdev, R600_RING_TYPE_DMA_INDEX, &ib, NULL, 256); |
417 | if (r) | 408 | if (r) |
418 | goto error; | 409 | goto error_unreserve; |
419 | 410 | ||
420 | ib.length_dw = 0; | 411 | ib.length_dw = 0; |
421 | 412 | ||
@@ -425,15 +416,16 @@ static int radeon_vm_clear_bo(struct radeon_device *rdev, | |||
425 | 416 | ||
426 | r = radeon_ib_schedule(rdev, &ib, NULL, false); | 417 | r = radeon_ib_schedule(rdev, &ib, NULL, false); |
427 | if (r) | 418 | if (r) |
428 | goto error; | 419 | goto error_free; |
429 | 420 | ||
430 | ttm_eu_fence_buffer_objects(&ticket, &head, &ib.fence->base); | 421 | ib.fence->is_vm_update = true; |
431 | radeon_ib_free(rdev, &ib); | 422 | radeon_bo_fence(bo, ib.fence, false); |
432 | 423 | ||
433 | return 0; | 424 | error_free: |
425 | radeon_ib_free(rdev, &ib); | ||
434 | 426 | ||
435 | error: | 427 | error_unreserve: |
436 | ttm_eu_backoff_reservation(&ticket, &head); | 428 | radeon_bo_unreserve(bo); |
437 | return r; | 429 | return r; |
438 | } | 430 | } |
439 | 431 | ||
@@ -449,7 +441,7 @@ error: | |||
449 | * Validate and set the offset requested within the vm address space. | 441 | * Validate and set the offset requested within the vm address space. |
450 | * Returns 0 for success, error for failure. | 442 | * Returns 0 for success, error for failure. |
451 | * | 443 | * |
452 | * Object has to be reserved! | 444 | * Object has to be reserved and gets unreserved by this function! |
453 | */ | 445 | */ |
454 | int radeon_vm_bo_set_addr(struct radeon_device *rdev, | 446 | int radeon_vm_bo_set_addr(struct radeon_device *rdev, |
455 | struct radeon_bo_va *bo_va, | 447 | struct radeon_bo_va *bo_va, |
@@ -495,7 +487,9 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, | |||
495 | tmp->vm = vm; | 487 | tmp->vm = vm; |
496 | tmp->addr = bo_va->addr; | 488 | tmp->addr = bo_va->addr; |
497 | tmp->bo = radeon_bo_ref(bo_va->bo); | 489 | tmp->bo = radeon_bo_ref(bo_va->bo); |
490 | spin_lock(&vm->status_lock); | ||
498 | list_add(&tmp->vm_status, &vm->freed); | 491 | list_add(&tmp->vm_status, &vm->freed); |
492 | spin_unlock(&vm->status_lock); | ||
499 | } | 493 | } |
500 | 494 | ||
501 | interval_tree_remove(&bo_va->it, &vm->va); | 495 | interval_tree_remove(&bo_va->it, &vm->va); |
@@ -575,7 +569,7 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, | |||
575 | } | 569 | } |
576 | 570 | ||
577 | mutex_unlock(&vm->mutex); | 571 | mutex_unlock(&vm->mutex); |
578 | return radeon_bo_reserve(bo_va->bo, false); | 572 | return 0; |
579 | } | 573 | } |
580 | 574 | ||
581 | /** | 575 | /** |
@@ -699,17 +693,15 @@ int radeon_vm_update_page_directory(struct radeon_device *rdev, | |||
699 | if (ib.length_dw != 0) { | 693 | if (ib.length_dw != 0) { |
700 | radeon_asic_vm_pad_ib(rdev, &ib); | 694 | radeon_asic_vm_pad_ib(rdev, &ib); |
701 | 695 | ||
702 | radeon_semaphore_sync_resv(rdev, ib.semaphore, pd->tbo.resv, false); | 696 | radeon_sync_resv(rdev, &ib.sync, pd->tbo.resv, true); |
703 | radeon_semaphore_sync_fence(ib.semaphore, vm->last_id_use); | ||
704 | WARN_ON(ib.length_dw > ndw); | 697 | WARN_ON(ib.length_dw > ndw); |
705 | r = radeon_ib_schedule(rdev, &ib, NULL, false); | 698 | r = radeon_ib_schedule(rdev, &ib, NULL, false); |
706 | if (r) { | 699 | if (r) { |
707 | radeon_ib_free(rdev, &ib); | 700 | radeon_ib_free(rdev, &ib); |
708 | return r; | 701 | return r; |
709 | } | 702 | } |
710 | radeon_fence_unref(&vm->fence); | 703 | ib.fence->is_vm_update = true; |
711 | vm->fence = radeon_fence_ref(ib.fence); | 704 | radeon_bo_fence(pd, ib.fence, false); |
712 | radeon_fence_unref(&vm->last_flush); | ||
713 | } | 705 | } |
714 | radeon_ib_free(rdev, &ib); | 706 | radeon_ib_free(rdev, &ib); |
715 | 707 | ||
@@ -808,11 +800,11 @@ static void radeon_vm_frag_ptes(struct radeon_device *rdev, | |||
808 | * | 800 | * |
809 | * Global and local mutex must be locked! | 801 | * Global and local mutex must be locked! |
810 | */ | 802 | */ |
811 | static void radeon_vm_update_ptes(struct radeon_device *rdev, | 803 | static int radeon_vm_update_ptes(struct radeon_device *rdev, |
812 | struct radeon_vm *vm, | 804 | struct radeon_vm *vm, |
813 | struct radeon_ib *ib, | 805 | struct radeon_ib *ib, |
814 | uint64_t start, uint64_t end, | 806 | uint64_t start, uint64_t end, |
815 | uint64_t dst, uint32_t flags) | 807 | uint64_t dst, uint32_t flags) |
816 | { | 808 | { |
817 | uint64_t mask = RADEON_VM_PTE_COUNT - 1; | 809 | uint64_t mask = RADEON_VM_PTE_COUNT - 1; |
818 | uint64_t last_pte = ~0, last_dst = ~0; | 810 | uint64_t last_pte = ~0, last_dst = ~0; |
@@ -825,8 +817,12 @@ static void radeon_vm_update_ptes(struct radeon_device *rdev, | |||
825 | struct radeon_bo *pt = vm->page_tables[pt_idx].bo; | 817 | struct radeon_bo *pt = vm->page_tables[pt_idx].bo; |
826 | unsigned nptes; | 818 | unsigned nptes; |
827 | uint64_t pte; | 819 | uint64_t pte; |
820 | int r; | ||
828 | 821 | ||
829 | radeon_semaphore_sync_resv(rdev, ib->semaphore, pt->tbo.resv, false); | 822 | radeon_sync_resv(rdev, &ib->sync, pt->tbo.resv, true); |
823 | r = reservation_object_reserve_shared(pt->tbo.resv); | ||
824 | if (r) | ||
825 | return r; | ||
830 | 826 | ||
831 | if ((addr & ~mask) == (end & ~mask)) | 827 | if ((addr & ~mask) == (end & ~mask)) |
832 | nptes = end - addr; | 828 | nptes = end - addr; |
@@ -860,6 +856,33 @@ static void radeon_vm_update_ptes(struct radeon_device *rdev, | |||
860 | last_pte + 8 * count, | 856 | last_pte + 8 * count, |
861 | last_dst, flags); | 857 | last_dst, flags); |
862 | } | 858 | } |
859 | |||
860 | return 0; | ||
861 | } | ||
862 | |||
863 | /** | ||
864 | * radeon_vm_fence_pts - fence page tables after an update | ||
865 | * | ||
866 | * @vm: requested vm | ||
867 | * @start: start of GPU address range | ||
868 | * @end: end of GPU address range | ||
869 | * @fence: fence to use | ||
870 | * | ||
871 | * Fence the page tables in the range @start - @end (cayman+). | ||
872 | * | ||
873 | * Global and local mutex must be locked! | ||
874 | */ | ||
875 | static void radeon_vm_fence_pts(struct radeon_vm *vm, | ||
876 | uint64_t start, uint64_t end, | ||
877 | struct radeon_fence *fence) | ||
878 | { | ||
879 | unsigned i; | ||
880 | |||
881 | start >>= radeon_vm_block_size; | ||
882 | end >>= radeon_vm_block_size; | ||
883 | |||
884 | for (i = start; i <= end; ++i) | ||
885 | radeon_bo_fence(vm->page_tables[i].bo, fence, true); | ||
863 | } | 886 | } |
864 | 887 | ||
865 | /** | 888 | /** |
@@ -892,7 +915,9 @@ int radeon_vm_bo_update(struct radeon_device *rdev, | |||
892 | return -EINVAL; | 915 | return -EINVAL; |
893 | } | 916 | } |
894 | 917 | ||
918 | spin_lock(&vm->status_lock); | ||
895 | list_del_init(&bo_va->vm_status); | 919 | list_del_init(&bo_va->vm_status); |
920 | spin_unlock(&vm->status_lock); | ||
896 | 921 | ||
897 | bo_va->flags &= ~RADEON_VM_PAGE_VALID; | 922 | bo_va->flags &= ~RADEON_VM_PAGE_VALID; |
898 | bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM; | 923 | bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM; |
@@ -961,23 +986,34 @@ int radeon_vm_bo_update(struct radeon_device *rdev, | |||
961 | return r; | 986 | return r; |
962 | ib.length_dw = 0; | 987 | ib.length_dw = 0; |
963 | 988 | ||
964 | radeon_vm_update_ptes(rdev, vm, &ib, bo_va->it.start, | 989 | if (!(bo_va->flags & RADEON_VM_PAGE_VALID)) { |
965 | bo_va->it.last + 1, addr, | 990 | unsigned i; |
966 | radeon_vm_page_flags(bo_va->flags)); | 991 | |
992 | for (i = 0; i < RADEON_NUM_RINGS; ++i) | ||
993 | radeon_sync_fence(&ib.sync, vm->ids[i].last_id_use); | ||
994 | } | ||
995 | |||
996 | r = radeon_vm_update_ptes(rdev, vm, &ib, bo_va->it.start, | ||
997 | bo_va->it.last + 1, addr, | ||
998 | radeon_vm_page_flags(bo_va->flags)); | ||
999 | if (r) { | ||
1000 | radeon_ib_free(rdev, &ib); | ||
1001 | return r; | ||
1002 | } | ||
967 | 1003 | ||
968 | radeon_asic_vm_pad_ib(rdev, &ib); | 1004 | radeon_asic_vm_pad_ib(rdev, &ib); |
969 | WARN_ON(ib.length_dw > ndw); | 1005 | WARN_ON(ib.length_dw > ndw); |
970 | 1006 | ||
971 | radeon_semaphore_sync_fence(ib.semaphore, vm->fence); | ||
972 | r = radeon_ib_schedule(rdev, &ib, NULL, false); | 1007 | r = radeon_ib_schedule(rdev, &ib, NULL, false); |
973 | if (r) { | 1008 | if (r) { |
974 | radeon_ib_free(rdev, &ib); | 1009 | radeon_ib_free(rdev, &ib); |
975 | return r; | 1010 | return r; |
976 | } | 1011 | } |
977 | radeon_fence_unref(&vm->fence); | 1012 | ib.fence->is_vm_update = true; |
978 | vm->fence = radeon_fence_ref(ib.fence); | 1013 | radeon_vm_fence_pts(vm, bo_va->it.start, bo_va->it.last + 1, ib.fence); |
1014 | radeon_fence_unref(&bo_va->last_pt_update); | ||
1015 | bo_va->last_pt_update = radeon_fence_ref(ib.fence); | ||
979 | radeon_ib_free(rdev, &ib); | 1016 | radeon_ib_free(rdev, &ib); |
980 | radeon_fence_unref(&vm->last_flush); | ||
981 | 1017 | ||
982 | return 0; | 1018 | return 0; |
983 | } | 1019 | } |
@@ -996,16 +1032,25 @@ int radeon_vm_bo_update(struct radeon_device *rdev, | |||
996 | int radeon_vm_clear_freed(struct radeon_device *rdev, | 1032 | int radeon_vm_clear_freed(struct radeon_device *rdev, |
997 | struct radeon_vm *vm) | 1033 | struct radeon_vm *vm) |
998 | { | 1034 | { |
999 | struct radeon_bo_va *bo_va, *tmp; | 1035 | struct radeon_bo_va *bo_va; |
1000 | int r; | 1036 | int r; |
1001 | 1037 | ||
1002 | list_for_each_entry_safe(bo_va, tmp, &vm->freed, vm_status) { | 1038 | spin_lock(&vm->status_lock); |
1039 | while (!list_empty(&vm->freed)) { | ||
1040 | bo_va = list_first_entry(&vm->freed, | ||
1041 | struct radeon_bo_va, vm_status); | ||
1042 | spin_unlock(&vm->status_lock); | ||
1043 | |||
1003 | r = radeon_vm_bo_update(rdev, bo_va, NULL); | 1044 | r = radeon_vm_bo_update(rdev, bo_va, NULL); |
1004 | radeon_bo_unref(&bo_va->bo); | 1045 | radeon_bo_unref(&bo_va->bo); |
1046 | radeon_fence_unref(&bo_va->last_pt_update); | ||
1005 | kfree(bo_va); | 1047 | kfree(bo_va); |
1006 | if (r) | 1048 | if (r) |
1007 | return r; | 1049 | return r; |
1050 | |||
1051 | spin_lock(&vm->status_lock); | ||
1008 | } | 1052 | } |
1053 | spin_unlock(&vm->status_lock); | ||
1009 | return 0; | 1054 | return 0; |
1010 | 1055 | ||
1011 | } | 1056 | } |
@@ -1024,14 +1069,23 @@ int radeon_vm_clear_freed(struct radeon_device *rdev, | |||
1024 | int radeon_vm_clear_invalids(struct radeon_device *rdev, | 1069 | int radeon_vm_clear_invalids(struct radeon_device *rdev, |
1025 | struct radeon_vm *vm) | 1070 | struct radeon_vm *vm) |
1026 | { | 1071 | { |
1027 | struct radeon_bo_va *bo_va, *tmp; | 1072 | struct radeon_bo_va *bo_va; |
1028 | int r; | 1073 | int r; |
1029 | 1074 | ||
1030 | list_for_each_entry_safe(bo_va, tmp, &vm->invalidated, vm_status) { | 1075 | spin_lock(&vm->status_lock); |
1076 | while (!list_empty(&vm->invalidated)) { | ||
1077 | bo_va = list_first_entry(&vm->invalidated, | ||
1078 | struct radeon_bo_va, vm_status); | ||
1079 | spin_unlock(&vm->status_lock); | ||
1080 | |||
1031 | r = radeon_vm_bo_update(rdev, bo_va, NULL); | 1081 | r = radeon_vm_bo_update(rdev, bo_va, NULL); |
1032 | if (r) | 1082 | if (r) |
1033 | return r; | 1083 | return r; |
1084 | |||
1085 | spin_lock(&vm->status_lock); | ||
1034 | } | 1086 | } |
1087 | spin_unlock(&vm->status_lock); | ||
1088 | |||
1035 | return 0; | 1089 | return 0; |
1036 | } | 1090 | } |
1037 | 1091 | ||
@@ -1054,14 +1108,17 @@ void radeon_vm_bo_rmv(struct radeon_device *rdev, | |||
1054 | 1108 | ||
1055 | mutex_lock(&vm->mutex); | 1109 | mutex_lock(&vm->mutex); |
1056 | interval_tree_remove(&bo_va->it, &vm->va); | 1110 | interval_tree_remove(&bo_va->it, &vm->va); |
1111 | spin_lock(&vm->status_lock); | ||
1057 | list_del(&bo_va->vm_status); | 1112 | list_del(&bo_va->vm_status); |
1058 | 1113 | ||
1059 | if (bo_va->addr) { | 1114 | if (bo_va->addr) { |
1060 | bo_va->bo = radeon_bo_ref(bo_va->bo); | 1115 | bo_va->bo = radeon_bo_ref(bo_va->bo); |
1061 | list_add(&bo_va->vm_status, &vm->freed); | 1116 | list_add(&bo_va->vm_status, &vm->freed); |
1062 | } else { | 1117 | } else { |
1118 | radeon_fence_unref(&bo_va->last_pt_update); | ||
1063 | kfree(bo_va); | 1119 | kfree(bo_va); |
1064 | } | 1120 | } |
1121 | spin_unlock(&vm->status_lock); | ||
1065 | 1122 | ||
1066 | mutex_unlock(&vm->mutex); | 1123 | mutex_unlock(&vm->mutex); |
1067 | } | 1124 | } |
@@ -1082,10 +1139,10 @@ void radeon_vm_bo_invalidate(struct radeon_device *rdev, | |||
1082 | 1139 | ||
1083 | list_for_each_entry(bo_va, &bo->va, bo_list) { | 1140 | list_for_each_entry(bo_va, &bo->va, bo_list) { |
1084 | if (bo_va->addr) { | 1141 | if (bo_va->addr) { |
1085 | mutex_lock(&bo_va->vm->mutex); | 1142 | spin_lock(&bo_va->vm->status_lock); |
1086 | list_del(&bo_va->vm_status); | 1143 | list_del(&bo_va->vm_status); |
1087 | list_add(&bo_va->vm_status, &bo_va->vm->invalidated); | 1144 | list_add(&bo_va->vm_status, &bo_va->vm->invalidated); |
1088 | mutex_unlock(&bo_va->vm->mutex); | 1145 | spin_unlock(&bo_va->vm->status_lock); |
1089 | } | 1146 | } |
1090 | } | 1147 | } |
1091 | } | 1148 | } |
@@ -1103,15 +1160,17 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) | |||
1103 | const unsigned align = min(RADEON_VM_PTB_ALIGN_SIZE, | 1160 | const unsigned align = min(RADEON_VM_PTB_ALIGN_SIZE, |
1104 | RADEON_VM_PTE_COUNT * 8); | 1161 | RADEON_VM_PTE_COUNT * 8); |
1105 | unsigned pd_size, pd_entries, pts_size; | 1162 | unsigned pd_size, pd_entries, pts_size; |
1106 | int r; | 1163 | int i, r; |
1107 | 1164 | ||
1108 | vm->id = 0; | ||
1109 | vm->ib_bo_va = NULL; | 1165 | vm->ib_bo_va = NULL; |
1110 | vm->fence = NULL; | 1166 | for (i = 0; i < RADEON_NUM_RINGS; ++i) { |
1111 | vm->last_flush = NULL; | 1167 | vm->ids[i].id = 0; |
1112 | vm->last_id_use = NULL; | 1168 | vm->ids[i].flushed_updates = NULL; |
1169 | vm->ids[i].last_id_use = NULL; | ||
1170 | } | ||
1113 | mutex_init(&vm->mutex); | 1171 | mutex_init(&vm->mutex); |
1114 | vm->va = RB_ROOT; | 1172 | vm->va = RB_ROOT; |
1173 | spin_lock_init(&vm->status_lock); | ||
1115 | INIT_LIST_HEAD(&vm->invalidated); | 1174 | INIT_LIST_HEAD(&vm->invalidated); |
1116 | INIT_LIST_HEAD(&vm->freed); | 1175 | INIT_LIST_HEAD(&vm->freed); |
1117 | 1176 | ||
@@ -1165,11 +1224,13 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm) | |||
1165 | if (!r) { | 1224 | if (!r) { |
1166 | list_del_init(&bo_va->bo_list); | 1225 | list_del_init(&bo_va->bo_list); |
1167 | radeon_bo_unreserve(bo_va->bo); | 1226 | radeon_bo_unreserve(bo_va->bo); |
1227 | radeon_fence_unref(&bo_va->last_pt_update); | ||
1168 | kfree(bo_va); | 1228 | kfree(bo_va); |
1169 | } | 1229 | } |
1170 | } | 1230 | } |
1171 | list_for_each_entry_safe(bo_va, tmp, &vm->freed, vm_status) { | 1231 | list_for_each_entry_safe(bo_va, tmp, &vm->freed, vm_status) { |
1172 | radeon_bo_unref(&bo_va->bo); | 1232 | radeon_bo_unref(&bo_va->bo); |
1233 | radeon_fence_unref(&bo_va->last_pt_update); | ||
1173 | kfree(bo_va); | 1234 | kfree(bo_va); |
1174 | } | 1235 | } |
1175 | 1236 | ||
@@ -1179,9 +1240,10 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm) | |||
1179 | 1240 | ||
1180 | radeon_bo_unref(&vm->page_directory); | 1241 | radeon_bo_unref(&vm->page_directory); |
1181 | 1242 | ||
1182 | radeon_fence_unref(&vm->fence); | 1243 | for (i = 0; i < RADEON_NUM_RINGS; ++i) { |
1183 | radeon_fence_unref(&vm->last_flush); | 1244 | radeon_fence_unref(&vm->ids[i].flushed_updates); |
1184 | radeon_fence_unref(&vm->last_id_use); | 1245 | radeon_fence_unref(&vm->ids[i].last_id_use); |
1246 | } | ||
1185 | 1247 | ||
1186 | mutex_destroy(&vm->mutex); | 1248 | mutex_destroy(&vm->mutex); |
1187 | } | 1249 | } |