linux/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
/* Validate invalid userptr BOs
 *
 * Validates BOs on the userptr_inval_list, and moves them back to the
 * userptr_valid_list. Also updates GPUVM page tables with new page
 * addresses and waits for the page table updates to complete.
 */
Validate invalid userptr BOs
Validates BOs on the userptr_inval_list, and moves them back to the
userptr_valid_list. Also updates GPUVM page tables with new page
addresses and waits for the page table updates to complete.
Validate invalid userptr BOs Validates BOs on the userptr_inval_list and moves them back to the userptr_valid_list . Also updates GPUVM page tables with new page addresses and waits for the page table updates to complete .
static int validate_invalid_user_pages(struct amdkfd_process_info *process_info)
{
	struct amdgpu_bo_list_entry *pd_bo_list_entries;
	struct list_head resv_list, duplicates;
	struct ww_acquire_ctx ticket;
	struct amdgpu_sync sync;
	struct amdgpu_vm *peer_vm;
	struct kgd_mem *mem, *tmp_mem;
	struct amdgpu_bo *bo;
	struct ttm_operation_ctx ctx = { false, false };
	int i, ret;
	pd_bo_list_entries = kcalloc(process_info->n_vms,
				     sizeof(struct amdgpu_bo_list_entry),
				     GFP_KERNEL);
	if (!pd_bo_list_entries) {
		pr_err("%s: Failed to allocate PD BO list entries\n", __func__);
		return -ENOMEM;
	}
	INIT_LIST_HEAD(&resv_list);
	INIT_LIST_HEAD(&duplicates);
	i = 0;
	list_for_each_entry(peer_vm, &process_info->vm_list_head,
			    vm_list_node)
		amdgpu_vm_get_pd_bo(peer_vm, &resv_list,
				    &pd_bo_list_entries[i++]);
	list_for_each_entry(mem, &process_info->userptr_inval_list,
			    validate_list.head) {
		list_add_tail(&mem->resv_list.head, &resv_list);
		mem->resv_list.bo = mem->validate_list.bo;
		mem->resv_list.shared = mem->validate_list.shared;
	}
	ret = ttm_eu_reserve_buffers(&ticket, &resv_list, false, &duplicates);
	WARN(!list_empty(&duplicates), "Duplicates should be empty");
	if (ret)
		goto out;
	amdgpu_sync_create(&sync);
	list_for_each_entry(peer_vm, &process_info->vm_list_head,
			    vm_list_node)
		amdgpu_amdkfd_remove_eviction_fence(peer_vm->root.base.bo,
						process_info->eviction_fence,
						NULL, NULL);
	ret = process_validate_vms(process_info);
	if (ret)
		goto unreserve_out;
	list_for_each_entry_safe(mem, tmp_mem,
				 &process_info->userptr_inval_list,
				 validate_list.head) {
		struct kfd_bo_va_list *bo_va_entry;
		bo = mem->bo;
		if (mem->user_pages[0]) {
			amdgpu_ttm_tt_set_user_pages(bo->tbo.ttm,
						     mem->user_pages);
			amdgpu_bo_placement_from_domain(bo, mem->domain);
			ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
			if (ret) {
				pr_err("%s: failed to validate BO\n", __func__);
				goto unreserve_out;
			}
		}
		kvfree(mem->user_pages);
		mem->user_pages = NULL;
		list_move_tail(&mem->validate_list.head,
			       &process_info->userptr_valid_list);
		list_for_each_entry(bo_va_entry, &mem->bo_va_list, bo_list) {
			if (!bo_va_entry->is_mapped)
				continue;
			ret = update_gpuvm_pte((struct amdgpu_device *)
					       bo_va_entry->kgd_dev,
					       bo_va_entry, &sync);
			if (ret) {
				pr_err("%s: update PTE failed\n", __func__);
				atomic_inc(&mem->invalid);
				goto unreserve_out;
			}
		}
	}
	ret = process_update_pds(process_info, &sync);
unreserve_out:
	list_for_each_entry(peer_vm, &process_info->vm_list_head,
			    vm_list_node)
		amdgpu_bo_fence(peer_vm->root.base.bo,
				&process_info->eviction_fence->base, true);
	ttm_eu_backoff_reservation(&ticket, &resv_list);
	amdgpu_sync_wait(&sync, false);
	amdgpu_sync_free(&sync);
out:
	kfree(pd_bo_list_entries);
	return ret;
}
static int validate_invalid_user_pages ( struct amdkfd_process_info * process_info ) { struct amdgpu_bo_list_entry * pd_bo_list_entries ; struct list_head resv_list , duplicates ; struct ww_acquire_ctx ticket ; struct amdgpu_sync sync ; struct amdgpu_vm * peer_vm ; struct kgd_mem * mem , * tmp_mem ; struct amdgpu_bo * bo ; struct ttm_operation_ctx ctx = { false , false } ; int i , ret ; pd_bo_list_entries = kcalloc ( process_info -> n_vms , sizeof ( struct amdgpu_bo_list_entry ) , GFP_KERNEL ) ; if ( ! pd_bo_list_entries ) { pr_err ( " \n " , __func__ ) ; return - ENOMEM ; } INIT_LIST_HEAD ( & resv_list ) ; INIT_LIST_HEAD ( & duplicates ) ; i = 0 ; list_for_each_entry ( peer_vm , & process_info -> vm_list_head , vm_list_node ) amdgpu_vm_get_pd_bo ( peer_vm , & resv_list , & pd_bo_list_entries [ i ++ ] ) ; list_for_each_entry ( mem , & process_info -> userptr_inval_list , validate_list . head ) { list_add_tail ( & mem -> resv_list . head , & resv_list ) ; mem -> resv_list . bo = mem -> validate_list . bo ; mem -> resv_list . shared = mem -> validate_list . shared ; } ret = ttm_eu_reserve_buffers ( & ticket , & resv_list , false , & duplicates ) ; WARN ( ! list_empty ( & duplicates ) , " " ) ; if ( ret ) goto out ; amdgpu_sync_create ( & sync ) ; list_for_each_entry ( peer_vm , & process_info -> vm_list_head , vm_list_node ) amdgpu_amdkfd_remove_eviction_fence ( peer_vm -> root . base . bo , process_info -> eviction_fence , NULL , NULL ) ; ret = process_validate_vms ( process_info ) ; if ( ret ) goto unreserve_out ; list_for_each_entry_safe ( mem , tmp_mem , & process_info -> userptr_inval_list , validate_list . head ) { struct kfd_bo_va_list * bo_va_entry ; bo = mem -> bo ; if ( mem -> user_pages [ 0 ] ) { amdgpu_ttm_tt_set_user_pages ( bo -> tbo . ttm , mem -> user_pages ) ; amdgpu_bo_placement_from_domain ( bo , mem -> domain ) ; ret = ttm_bo_validate ( & bo -> tbo , & bo -> placement , & ctx ) ; if ( ret ) { pr_err ( " \n " , __func__ ) ; goto unreserve_out ; } } kvfree ( mem -> user_pages ) ; mem -> user_pages = NULL ; list_move_tail ( & mem -> validate_list . head , & process_info -> userptr_valid_list ) ; list_for_each_entry ( bo_va_entry , & mem -> bo_va_list , bo_list ) { if ( ! bo_va_entry -> is_mapped ) continue ; ret = update_gpuvm_pte ( ( struct amdgpu_device * ) bo_va_entry -> kgd_dev , bo_va_entry , & sync ) ; if ( ret ) { pr_err ( " \n " , __func__ ) ; atomic_inc ( & mem -> invalid ) ; goto unreserve_out ; } } } ret = process_update_pds ( process_info , & sync ) ; unreserve_out : list_for_each_entry ( peer_vm , & process_info -> vm_list_head , vm_list_node ) amdgpu_bo_fence ( peer_vm -> root . base . bo , & process_info -> eviction_fence -> base , true ) ; ttm_eu_backoff_reservation ( & ticket , & resv_list ) ; amdgpu_sync_wait ( & sync , false ) ; amdgpu_sync_free ( & sync ) ; out : kfree ( pd_bo_list_entries ) ; return ret ; }
Validate invalid userptr BOs
 Validates BOs on the userptr_inval_list, and moves them back to the
 userptr_valid_list.
Validate invalid userptr BOs Validates BOs on the userptr_inval_list and moves them back to the userptr_valid_list .
/* Get all the page directory BOs that need to be reserved */ /* Add the userptr_inval_list entries to resv_list */ /* Reserve all BOs and page tables for validation */ /* Avoid triggering eviction fences when unmapping invalid
	 * userptr BOs (waits for all fences, doesn't use
	 * FENCE_OWNER_VM)
	 */ /* Validate BOs and update GPUVM page tables */ /* Copy pages array and validate the BO if we got user pages */ /* Validate succeeded, now the BO owns the pages, free
		 * our copy of the pointer array. Put this BO back on
		 * the userptr_valid_list. If we need to revalidate
		 * it, we need to start from scratch.
		 */ /* Update mapping. If the BO was not validated
		 * (because we couldn't get user pages), this will
		 * clear the page table entries, which will result in
		 * VM faults if the GPU tries to access the invalid
		 * memory.
		 */ /* make sure this gets validated again */ /* Update page directories */