diff options
author | Christian König <christian.koenig@amd.com> | 2016-10-27 14:04:38 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2017-03-29 23:55:28 -0400 |
commit | f566ceb165f8f3bf0e7492a3a8d5eefed9e499a6 (patch) | |
tree | 3e73754ea4169809bb1434f20015986bdfafd5d7 | |
parent | 4e2cb640c2efbf86058cffd2785307690ebefe20 (diff) |
drm/amdgpu: add alloc/free for multi level PDs V2
Allocate and free page directories on demand.
V2:
a. clear entries allocation
b. fix entries index calculation
c. need alloc sub level even parent bo was allocated
Signed-off-by: Christian König <christian.koenig@amd.com> (v1)
Reviewed-by: Alex Deucher <alexander.deucher@amd.com> (v1)
Signed-off-by: Chunming Zhou <David1.Zhou@amd.com> (v2)
Acked-by: Alex Deucher <alexander.deucher@amd.com> (v2)
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 175 |
1 files changed, 106 insertions, 69 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index c9f5f10ed4c0..10e8232d6cac 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | |||
@@ -244,6 +244,84 @@ void amdgpu_vm_move_pt_bos_in_lru(struct amdgpu_device *adev, | |||
244 | spin_unlock(&glob->lru_lock); | 244 | spin_unlock(&glob->lru_lock); |
245 | } | 245 | } |
246 | 246 | ||
247 | /** | ||
248 | * amdgpu_vm_alloc_levels - allocate the PD/PT levels | ||
249 | * | ||
250 | * @adev: amdgpu_device pointer | ||
251 | * @vm: requested vm | ||
252 | * @saddr: start of the address range | ||
253 | * @eaddr: end of the address range | ||
254 | * | ||
255 | * Make sure the page directories and page tables are allocated | ||
256 | */ | ||
257 | static int amdgpu_vm_alloc_levels(struct amdgpu_device *adev, | ||
258 | struct amdgpu_vm *vm, | ||
259 | struct amdgpu_vm_pt *parent, | ||
260 | uint64_t saddr, uint64_t eaddr, | ||
261 | unsigned level) | ||
262 | { | ||
263 | unsigned shift = (adev->vm_manager.num_level - level) * | ||
264 | amdgpu_vm_block_size; | ||
265 | unsigned pt_idx, from, to; | ||
266 | int r; | ||
267 | |||
268 | if (!parent->entries) { | ||
269 | unsigned num_entries = amdgpu_vm_num_entries(adev, level); | ||
270 | |||
271 | parent->entries = drm_calloc_large(num_entries, | ||
272 | sizeof(struct amdgpu_vm_pt)); | ||
273 | if (!parent->entries) | ||
274 | return -ENOMEM; | ||
275 | memset(parent->entries, 0 , sizeof(struct amdgpu_vm_pt)); | ||
276 | } | ||
277 | |||
278 | from = (saddr >> shift) % amdgpu_vm_num_entries(adev, level); | ||
279 | to = (eaddr >> shift) % amdgpu_vm_num_entries(adev, level); | ||
280 | |||
281 | if (to > parent->last_entry_used) | ||
282 | parent->last_entry_used = to; | ||
283 | |||
284 | ++level; | ||
285 | |||
286 | /* walk over the address space and allocate the page tables */ | ||
287 | for (pt_idx = from; pt_idx <= to; ++pt_idx) { | ||
288 | struct reservation_object *resv = vm->root.bo->tbo.resv; | ||
289 | struct amdgpu_vm_pt *entry = &parent->entries[pt_idx]; | ||
290 | struct amdgpu_bo *pt; | ||
291 | |||
292 | if (!entry->bo) { | ||
293 | r = amdgpu_bo_create(adev, | ||
294 | amdgpu_vm_bo_size(adev, level), | ||
295 | AMDGPU_GPU_PAGE_SIZE, true, | ||
296 | AMDGPU_GEM_DOMAIN_VRAM, | ||
297 | AMDGPU_GEM_CREATE_NO_CPU_ACCESS | | ||
298 | AMDGPU_GEM_CREATE_SHADOW | | ||
299 | AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS | | ||
300 | AMDGPU_GEM_CREATE_VRAM_CLEARED, | ||
301 | NULL, resv, &pt); | ||
302 | if (r) | ||
303 | return r; | ||
304 | |||
305 | /* Keep a reference to the root directory to avoid | ||
306 | * freeing them up in the wrong order. | ||
307 | */ | ||
308 | pt->parent = amdgpu_bo_ref(vm->root.bo); | ||
309 | |||
310 | entry->bo = pt; | ||
311 | entry->addr = 0; | ||
312 | } | ||
313 | |||
314 | if (level < adev->vm_manager.num_level) { | ||
315 | r = amdgpu_vm_alloc_levels(adev, vm, entry, saddr, | ||
316 | eaddr, level); | ||
317 | if (r) | ||
318 | return r; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
247 | /** | 325 | /** |
248 | * amdgpu_vm_alloc_pts - Allocate page tables. | 326 | * amdgpu_vm_alloc_pts - Allocate page tables. |
249 | * | 327 | * |
@@ -258,9 +336,8 @@ int amdgpu_vm_alloc_pts(struct amdgpu_device *adev, | |||
258 | struct amdgpu_vm *vm, | 336 | struct amdgpu_vm *vm, |
259 | uint64_t saddr, uint64_t size) | 337 | uint64_t saddr, uint64_t size) |
260 | { | 338 | { |
261 | unsigned last_pfn, pt_idx; | 339 | unsigned last_pfn; |
262 | uint64_t eaddr; | 340 | uint64_t eaddr; |
263 | int r; | ||
264 | 341 | ||
265 | /* validate the parameters */ | 342 | /* validate the parameters */ |
266 | if (saddr & AMDGPU_GPU_PAGE_MASK || size & AMDGPU_GPU_PAGE_MASK) | 343 | if (saddr & AMDGPU_GPU_PAGE_MASK || size & AMDGPU_GPU_PAGE_MASK) |
@@ -277,43 +354,7 @@ int amdgpu_vm_alloc_pts(struct amdgpu_device *adev, | |||
277 | saddr /= AMDGPU_GPU_PAGE_SIZE; | 354 | saddr /= AMDGPU_GPU_PAGE_SIZE; |
278 | eaddr /= AMDGPU_GPU_PAGE_SIZE; | 355 | eaddr /= AMDGPU_GPU_PAGE_SIZE; |
279 | 356 | ||
280 | saddr >>= amdgpu_vm_block_size; | 357 | return amdgpu_vm_alloc_levels(adev, vm, &vm->root, saddr, eaddr, 0); |
281 | eaddr >>= amdgpu_vm_block_size; | ||
282 | |||
283 | BUG_ON(eaddr >= amdgpu_vm_num_entries(adev, 0)); | ||
284 | |||
285 | if (eaddr > vm->root.last_entry_used) | ||
286 | vm->root.last_entry_used = eaddr; | ||
287 | |||
288 | /* walk over the address space and allocate the page tables */ | ||
289 | for (pt_idx = saddr; pt_idx <= eaddr; ++pt_idx) { | ||
290 | struct reservation_object *resv = vm->root.bo->tbo.resv; | ||
291 | struct amdgpu_bo *pt; | ||
292 | |||
293 | if (vm->root.entries[pt_idx].bo) | ||
294 | continue; | ||
295 | |||
296 | r = amdgpu_bo_create(adev, AMDGPU_VM_PTE_COUNT * 8, | ||
297 | AMDGPU_GPU_PAGE_SIZE, true, | ||
298 | AMDGPU_GEM_DOMAIN_VRAM, | ||
299 | AMDGPU_GEM_CREATE_NO_CPU_ACCESS | | ||
300 | AMDGPU_GEM_CREATE_SHADOW | | ||
301 | AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS | | ||
302 | AMDGPU_GEM_CREATE_VRAM_CLEARED, | ||
303 | NULL, resv, &pt); | ||
304 | if (r) | ||
305 | return r; | ||
306 | |||
307 | /* Keep a reference to the page table to avoid freeing | ||
308 | * them up in the wrong order. | ||
309 | */ | ||
310 | pt->parent = amdgpu_bo_ref(vm->root.bo); | ||
311 | |||
312 | vm->root.entries[pt_idx].bo = pt; | ||
313 | vm->root.entries[pt_idx].addr = 0; | ||
314 | } | ||
315 | |||
316 | return 0; | ||
317 | } | 358 | } |
318 | 359 | ||
319 | static bool amdgpu_vm_is_gpu_reset(struct amdgpu_device *adev, | 360 | static bool amdgpu_vm_is_gpu_reset(struct amdgpu_device *adev, |
@@ -1993,7 +2034,6 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) | |||
1993 | { | 2034 | { |
1994 | const unsigned align = min(AMDGPU_VM_PTB_ALIGN_SIZE, | 2035 | const unsigned align = min(AMDGPU_VM_PTB_ALIGN_SIZE, |
1995 | AMDGPU_VM_PTE_COUNT * 8); | 2036 | AMDGPU_VM_PTE_COUNT * 8); |
1996 | unsigned pd_size, pd_entries; | ||
1997 | unsigned ring_instance; | 2037 | unsigned ring_instance; |
1998 | struct amdgpu_ring *ring; | 2038 | struct amdgpu_ring *ring; |
1999 | struct amd_sched_rq *rq; | 2039 | struct amd_sched_rq *rq; |
@@ -2008,16 +2048,6 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) | |||
2008 | INIT_LIST_HEAD(&vm->cleared); | 2048 | INIT_LIST_HEAD(&vm->cleared); |
2009 | INIT_LIST_HEAD(&vm->freed); | 2049 | INIT_LIST_HEAD(&vm->freed); |
2010 | 2050 | ||
2011 | pd_size = amdgpu_vm_bo_size(adev, 0); | ||
2012 | pd_entries = amdgpu_vm_num_entries(adev, 0); | ||
2013 | |||
2014 | /* allocate page table array */ | ||
2015 | vm->root.entries = drm_calloc_large(pd_entries, sizeof(struct amdgpu_vm_pt)); | ||
2016 | if (vm->root.entries == NULL) { | ||
2017 | DRM_ERROR("Cannot allocate memory for page table array\n"); | ||
2018 | return -ENOMEM; | ||
2019 | } | ||
2020 | |||
2021 | /* create scheduler entity for page table updates */ | 2051 | /* create scheduler entity for page table updates */ |
2022 | 2052 | ||
2023 | ring_instance = atomic_inc_return(&adev->vm_manager.vm_pte_next_ring); | 2053 | ring_instance = atomic_inc_return(&adev->vm_manager.vm_pte_next_ring); |
@@ -2027,11 +2057,11 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) | |||
2027 | r = amd_sched_entity_init(&ring->sched, &vm->entity, | 2057 | r = amd_sched_entity_init(&ring->sched, &vm->entity, |
2028 | rq, amdgpu_sched_jobs); | 2058 | rq, amdgpu_sched_jobs); |
2029 | if (r) | 2059 | if (r) |
2030 | goto err; | 2060 | return r; |
2031 | 2061 | ||
2032 | vm->last_dir_update = NULL; | 2062 | vm->last_dir_update = NULL; |
2033 | 2063 | ||
2034 | r = amdgpu_bo_create(adev, pd_size, align, true, | 2064 | r = amdgpu_bo_create(adev, amdgpu_vm_bo_size(adev, 0), align, true, |
2035 | AMDGPU_GEM_DOMAIN_VRAM, | 2065 | AMDGPU_GEM_DOMAIN_VRAM, |
2036 | AMDGPU_GEM_CREATE_NO_CPU_ACCESS | | 2066 | AMDGPU_GEM_CREATE_NO_CPU_ACCESS | |
2037 | AMDGPU_GEM_CREATE_SHADOW | | 2067 | AMDGPU_GEM_CREATE_SHADOW | |
@@ -2058,13 +2088,33 @@ error_free_root: | |||
2058 | error_free_sched_entity: | 2088 | error_free_sched_entity: |
2059 | amd_sched_entity_fini(&ring->sched, &vm->entity); | 2089 | amd_sched_entity_fini(&ring->sched, &vm->entity); |
2060 | 2090 | ||
2061 | err: | ||
2062 | drm_free_large(vm->root.entries); | ||
2063 | |||
2064 | return r; | 2091 | return r; |
2065 | } | 2092 | } |
2066 | 2093 | ||
2067 | /** | 2094 | /** |
2095 | * amdgpu_vm_free_levels - free PD/PT levels | ||
2096 | * | ||
2097 | * @level: PD/PT starting level to free | ||
2098 | * | ||
2099 | * Free the page directory or page table level and all sub levels. | ||
2100 | */ | ||
2101 | static void amdgpu_vm_free_levels(struct amdgpu_vm_pt *level) | ||
2102 | { | ||
2103 | unsigned i; | ||
2104 | |||
2105 | if (level->bo) { | ||
2106 | amdgpu_bo_unref(&level->bo->shadow); | ||
2107 | amdgpu_bo_unref(&level->bo); | ||
2108 | } | ||
2109 | |||
2110 | if (level->entries) | ||
2111 | for (i = 0; i <= level->last_entry_used; i++) | ||
2112 | amdgpu_vm_free_levels(&level->entries[i]); | ||
2113 | |||
2114 | drm_free_large(level->entries); | ||
2115 | } | ||
2116 | |||
2117 | /** | ||
2068 | * amdgpu_vm_fini - tear down a vm instance | 2118 | * amdgpu_vm_fini - tear down a vm instance |
2069 | * | 2119 | * |
2070 | * @adev: amdgpu_device pointer | 2120 | * @adev: amdgpu_device pointer |
@@ -2077,7 +2127,6 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) | |||
2077 | { | 2127 | { |
2078 | struct amdgpu_bo_va_mapping *mapping, *tmp; | 2128 | struct amdgpu_bo_va_mapping *mapping, *tmp; |
2079 | bool prt_fini_needed = !!adev->gart.gart_funcs->set_prt; | 2129 | bool prt_fini_needed = !!adev->gart.gart_funcs->set_prt; |
2080 | int i; | ||
2081 | 2130 | ||
2082 | amd_sched_entity_fini(vm->entity.sched, &vm->entity); | 2131 | amd_sched_entity_fini(vm->entity.sched, &vm->entity); |
2083 | 2132 | ||
@@ -2099,19 +2148,7 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) | |||
2099 | amdgpu_vm_free_mapping(adev, vm, mapping, NULL); | 2148 | amdgpu_vm_free_mapping(adev, vm, mapping, NULL); |
2100 | } | 2149 | } |
2101 | 2150 | ||
2102 | for (i = 0; i < amdgpu_vm_num_entries(adev, 0); i++) { | 2151 | amdgpu_vm_free_levels(&vm->root); |
2103 | struct amdgpu_bo *pt = vm->root.entries[i].bo; | ||
2104 | |||
2105 | if (!pt) | ||
2106 | continue; | ||
2107 | |||
2108 | amdgpu_bo_unref(&pt->shadow); | ||
2109 | amdgpu_bo_unref(&pt); | ||
2110 | } | ||
2111 | drm_free_large(vm->root.entries); | ||
2112 | |||
2113 | amdgpu_bo_unref(&vm->root.bo->shadow); | ||
2114 | amdgpu_bo_unref(&vm->root.bo); | ||
2115 | dma_fence_put(vm->last_dir_update); | 2152 | dma_fence_put(vm->last_dir_update); |
2116 | } | 2153 | } |
2117 | 2154 | ||