aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian König <christian.koenig@amd.com>2016-10-27 14:04:38 -0400
committerAlex Deucher <alexander.deucher@amd.com>2017-03-29 23:55:28 -0400
commitf566ceb165f8f3bf0e7492a3a8d5eefed9e499a6 (patch)
tree3e73754ea4169809bb1434f20015986bdfafd5d7
parent4e2cb640c2efbf86058cffd2785307690ebefe20 (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.c175
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 */
257static 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
319static bool amdgpu_vm_is_gpu_reset(struct amdgpu_device *adev, 360static 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:
2058error_free_sched_entity: 2088error_free_sched_entity:
2059 amd_sched_entity_fini(&ring->sched, &vm->entity); 2089 amd_sched_entity_fini(&ring->sched, &vm->entity);
2060 2090
2061err:
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 */
2101static 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