xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_vm.c (revision e8e95709d3872383f40d80246ed90b5f1420abd9)
1*e8e95709Sriastradh /*	$NetBSD: amdgpu_vm.c,v 1.12 2021/12/19 12:38:24 riastradh Exp $	*/
2efa246c0Sriastradh 
3efa246c0Sriastradh /*
4efa246c0Sriastradh  * Copyright 2008 Advanced Micro Devices, Inc.
5efa246c0Sriastradh  * Copyright 2008 Red Hat Inc.
6efa246c0Sriastradh  * Copyright 2009 Jerome Glisse.
7efa246c0Sriastradh  *
8efa246c0Sriastradh  * Permission is hereby granted, free of charge, to any person obtaining a
9efa246c0Sriastradh  * copy of this software and associated documentation files (the "Software"),
10efa246c0Sriastradh  * to deal in the Software without restriction, including without limitation
11efa246c0Sriastradh  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12efa246c0Sriastradh  * and/or sell copies of the Software, and to permit persons to whom the
13efa246c0Sriastradh  * Software is furnished to do so, subject to the following conditions:
14efa246c0Sriastradh  *
15efa246c0Sriastradh  * The above copyright notice and this permission notice shall be included in
16efa246c0Sriastradh  * all copies or substantial portions of the Software.
17efa246c0Sriastradh  *
18efa246c0Sriastradh  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19efa246c0Sriastradh  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20efa246c0Sriastradh  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21efa246c0Sriastradh  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
22efa246c0Sriastradh  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23efa246c0Sriastradh  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24efa246c0Sriastradh  * OTHER DEALINGS IN THE SOFTWARE.
25efa246c0Sriastradh  *
26efa246c0Sriastradh  * Authors: Dave Airlie
27efa246c0Sriastradh  *          Alex Deucher
28efa246c0Sriastradh  *          Jerome Glisse
29efa246c0Sriastradh  */
30efa246c0Sriastradh #include <sys/cdefs.h>
31*e8e95709Sriastradh __KERNEL_RCSID(0, "$NetBSD: amdgpu_vm.c,v 1.12 2021/12/19 12:38:24 riastradh Exp $");
32efa246c0Sriastradh 
3341ec0267Sriastradh #include <linux/dma-fence-array.h>
3441ec0267Sriastradh #include <linux/interval_tree_generic.h>
3541ec0267Sriastradh #include <linux/idr.h>
3641ec0267Sriastradh 
37efa246c0Sriastradh #include <drm/amdgpu_drm.h>
38efa246c0Sriastradh #include "amdgpu.h"
39efa246c0Sriastradh #include "amdgpu_trace.h"
4041ec0267Sriastradh #include "amdgpu_amdkfd.h"
4141ec0267Sriastradh #include "amdgpu_gmc.h"
4241ec0267Sriastradh #include "amdgpu_xgmi.h"
43efa246c0Sriastradh 
441b46a69aSriastradh #include <linux/nbsd-namespace.h>
4541ec0267Sriastradh /**
4641ec0267Sriastradh  * DOC: GPUVM
4741ec0267Sriastradh  *
48efa246c0Sriastradh  * GPUVM is similar to the legacy gart on older asics, however
49efa246c0Sriastradh  * rather than there being a single global gart table
50efa246c0Sriastradh  * for the entire GPU, there are multiple VM page tables active
51efa246c0Sriastradh  * at any given time.  The VM page tables can contain a mix
52efa246c0Sriastradh  * vram pages and system memory pages and system memory pages
53efa246c0Sriastradh  * can be mapped as snooped (cached system pages) or unsnooped
54efa246c0Sriastradh  * (uncached system pages).
55efa246c0Sriastradh  * Each VM has an ID associated with it and there is a page table
56efa246c0Sriastradh  * associated with each VMID.  When execting a command buffer,
57efa246c0Sriastradh  * the kernel tells the the ring what VMID to use for that command
58efa246c0Sriastradh  * buffer.  VMIDs are allocated dynamically as commands are submitted.
59efa246c0Sriastradh  * The userspace drivers maintain their own address space and the kernel
60efa246c0Sriastradh  * sets up their pages tables accordingly when they submit their
61efa246c0Sriastradh  * command buffers and a VMID is assigned.
62efa246c0Sriastradh  * Cayman/Trinity support up to 8 active VMs at any given time;
63efa246c0Sriastradh  * SI supports 16.
64efa246c0Sriastradh  */
65efa246c0Sriastradh 
6641ec0267Sriastradh #define START(node) ((node)->start)
6741ec0267Sriastradh #define LAST(node) ((node)->last)
6841ec0267Sriastradh 
6941ec0267Sriastradh INTERVAL_TREE_DEFINE(struct amdgpu_bo_va_mapping, rb, uint64_t, __subtree_last,
7041ec0267Sriastradh 		     START, LAST, static, amdgpu_vm_it)
7141ec0267Sriastradh 
7241ec0267Sriastradh #undef START
7341ec0267Sriastradh #undef LAST
7441ec0267Sriastradh 
75efa246c0Sriastradh /**
7641ec0267Sriastradh  * struct amdgpu_prt_cb - Helper to disable partial resident texture feature from a fence callback
77efa246c0Sriastradh  */
7841ec0267Sriastradh struct amdgpu_prt_cb {
7941ec0267Sriastradh 
8041ec0267Sriastradh 	/**
8141ec0267Sriastradh 	 * @adev: amdgpu device
8241ec0267Sriastradh 	 */
8341ec0267Sriastradh 	struct amdgpu_device *adev;
8441ec0267Sriastradh 
8541ec0267Sriastradh 	/**
8641ec0267Sriastradh 	 * @cb: callback
8741ec0267Sriastradh 	 */
8841ec0267Sriastradh 	struct dma_fence_cb cb;
8941ec0267Sriastradh };
9041ec0267Sriastradh 
9141ec0267Sriastradh /**
9241ec0267Sriastradh  * vm eviction_lock can be taken in MMU notifiers. Make sure no reclaim-FS
9341ec0267Sriastradh  * happens while holding this lock anywhere to prevent deadlocks when
9441ec0267Sriastradh  * an MMU notifier runs in reclaim-FS context.
9541ec0267Sriastradh  */
amdgpu_vm_eviction_lock(struct amdgpu_vm * vm)9641ec0267Sriastradh static inline void amdgpu_vm_eviction_lock(struct amdgpu_vm *vm)
97efa246c0Sriastradh {
9841ec0267Sriastradh 	mutex_lock(&vm->eviction_lock);
9941ec0267Sriastradh 	vm->saved_flags = memalloc_nofs_save();
10041ec0267Sriastradh }
10141ec0267Sriastradh 
amdgpu_vm_eviction_trylock(struct amdgpu_vm * vm)10241ec0267Sriastradh static inline int amdgpu_vm_eviction_trylock(struct amdgpu_vm *vm)
10341ec0267Sriastradh {
10441ec0267Sriastradh 	if (mutex_trylock(&vm->eviction_lock)) {
10541ec0267Sriastradh 		vm->saved_flags = memalloc_nofs_save();
10641ec0267Sriastradh 		return 1;
10741ec0267Sriastradh 	}
10841ec0267Sriastradh 	return 0;
10941ec0267Sriastradh }
11041ec0267Sriastradh 
amdgpu_vm_eviction_unlock(struct amdgpu_vm * vm)11141ec0267Sriastradh static inline void amdgpu_vm_eviction_unlock(struct amdgpu_vm *vm)
11241ec0267Sriastradh {
11341ec0267Sriastradh 	memalloc_nofs_restore(vm->saved_flags);
11441ec0267Sriastradh 	mutex_unlock(&vm->eviction_lock);
115efa246c0Sriastradh }
116efa246c0Sriastradh 
117efa246c0Sriastradh /**
11841ec0267Sriastradh  * amdgpu_vm_level_shift - return the addr shift for each level
119efa246c0Sriastradh  *
120efa246c0Sriastradh  * @adev: amdgpu_device pointer
12141ec0267Sriastradh  * @level: VMPT level
122efa246c0Sriastradh  *
12341ec0267Sriastradh  * Returns:
12441ec0267Sriastradh  * The number of bits the pfn needs to be right shifted for a level.
125efa246c0Sriastradh  */
amdgpu_vm_level_shift(struct amdgpu_device * adev,unsigned level)12641ec0267Sriastradh static unsigned amdgpu_vm_level_shift(struct amdgpu_device *adev,
12741ec0267Sriastradh 				      unsigned level)
128efa246c0Sriastradh {
12941ec0267Sriastradh 	unsigned shift = 0xff;
13041ec0267Sriastradh 
13141ec0267Sriastradh 	switch (level) {
13241ec0267Sriastradh 	case AMDGPU_VM_PDB2:
13341ec0267Sriastradh 	case AMDGPU_VM_PDB1:
13441ec0267Sriastradh 	case AMDGPU_VM_PDB0:
13541ec0267Sriastradh 		shift = 9 * (AMDGPU_VM_PDB0 - level) +
13641ec0267Sriastradh 			adev->vm_manager.block_size;
13741ec0267Sriastradh 		break;
13841ec0267Sriastradh 	case AMDGPU_VM_PTB:
13941ec0267Sriastradh 		shift = 0;
14041ec0267Sriastradh 		break;
14141ec0267Sriastradh 	default:
14241ec0267Sriastradh 		dev_err(adev->dev, "the level%d isn't supported.\n", level);
14341ec0267Sriastradh 	}
14441ec0267Sriastradh 
14541ec0267Sriastradh 	return shift;
146efa246c0Sriastradh }
147efa246c0Sriastradh 
148efa246c0Sriastradh /**
14941ec0267Sriastradh  * amdgpu_vm_num_entries - return the number of entries in a PD/PT
15041ec0267Sriastradh  *
15141ec0267Sriastradh  * @adev: amdgpu_device pointer
15241ec0267Sriastradh  * @level: VMPT level
15341ec0267Sriastradh  *
15441ec0267Sriastradh  * Returns:
15541ec0267Sriastradh  * The number of entries in a page directory or page table.
15641ec0267Sriastradh  */
amdgpu_vm_num_entries(struct amdgpu_device * adev,unsigned level)15741ec0267Sriastradh static unsigned amdgpu_vm_num_entries(struct amdgpu_device *adev,
15841ec0267Sriastradh 				      unsigned level)
15941ec0267Sriastradh {
16041ec0267Sriastradh 	unsigned shift = amdgpu_vm_level_shift(adev,
16141ec0267Sriastradh 					       adev->vm_manager.root_level);
16241ec0267Sriastradh 
16341ec0267Sriastradh 	if (level == adev->vm_manager.root_level)
16441ec0267Sriastradh 		/* For the root directory */
16541ec0267Sriastradh 		return round_up(adev->vm_manager.max_pfn, 1ULL << shift)
16641ec0267Sriastradh 			>> shift;
16741ec0267Sriastradh 	else if (level != AMDGPU_VM_PTB)
16841ec0267Sriastradh 		/* Everything in between */
16941ec0267Sriastradh 		return 512;
17041ec0267Sriastradh 	else
17141ec0267Sriastradh 		/* For the page tables on the leaves */
17241ec0267Sriastradh 		return AMDGPU_VM_PTE_COUNT(adev);
17341ec0267Sriastradh }
17441ec0267Sriastradh 
17541ec0267Sriastradh /**
17641ec0267Sriastradh  * amdgpu_vm_num_ats_entries - return the number of ATS entries in the root PD
17741ec0267Sriastradh  *
17841ec0267Sriastradh  * @adev: amdgpu_device pointer
17941ec0267Sriastradh  *
18041ec0267Sriastradh  * Returns:
18141ec0267Sriastradh  * The number of entries in the root page directory which needs the ATS setting.
18241ec0267Sriastradh  */
amdgpu_vm_num_ats_entries(struct amdgpu_device * adev)18341ec0267Sriastradh static unsigned amdgpu_vm_num_ats_entries(struct amdgpu_device *adev)
18441ec0267Sriastradh {
18541ec0267Sriastradh 	unsigned shift;
18641ec0267Sriastradh 
18741ec0267Sriastradh 	shift = amdgpu_vm_level_shift(adev, adev->vm_manager.root_level);
18841ec0267Sriastradh 	return AMDGPU_GMC_HOLE_START >> (shift + AMDGPU_GPU_PAGE_SHIFT);
18941ec0267Sriastradh }
19041ec0267Sriastradh 
19141ec0267Sriastradh /**
19241ec0267Sriastradh  * amdgpu_vm_entries_mask - the mask to get the entry number of a PD/PT
19341ec0267Sriastradh  *
19441ec0267Sriastradh  * @adev: amdgpu_device pointer
19541ec0267Sriastradh  * @level: VMPT level
19641ec0267Sriastradh  *
19741ec0267Sriastradh  * Returns:
19841ec0267Sriastradh  * The mask to extract the entry number of a PD/PT from an address.
19941ec0267Sriastradh  */
amdgpu_vm_entries_mask(struct amdgpu_device * adev,unsigned int level)20041ec0267Sriastradh static uint32_t amdgpu_vm_entries_mask(struct amdgpu_device *adev,
20141ec0267Sriastradh 				       unsigned int level)
20241ec0267Sriastradh {
20341ec0267Sriastradh 	if (level <= adev->vm_manager.root_level)
20441ec0267Sriastradh 		return 0xffffffff;
20541ec0267Sriastradh 	else if (level != AMDGPU_VM_PTB)
20641ec0267Sriastradh 		return 0x1ff;
20741ec0267Sriastradh 	else
20841ec0267Sriastradh 		return AMDGPU_VM_PTE_COUNT(adev) - 1;
20941ec0267Sriastradh }
21041ec0267Sriastradh 
21141ec0267Sriastradh /**
21241ec0267Sriastradh  * amdgpu_vm_bo_size - returns the size of the BOs in bytes
21341ec0267Sriastradh  *
21441ec0267Sriastradh  * @adev: amdgpu_device pointer
21541ec0267Sriastradh  * @level: VMPT level
21641ec0267Sriastradh  *
21741ec0267Sriastradh  * Returns:
21841ec0267Sriastradh  * The size of the BO for a page directory or page table in bytes.
21941ec0267Sriastradh  */
amdgpu_vm_bo_size(struct amdgpu_device * adev,unsigned level)22041ec0267Sriastradh static unsigned amdgpu_vm_bo_size(struct amdgpu_device *adev, unsigned level)
22141ec0267Sriastradh {
22241ec0267Sriastradh 	return AMDGPU_GPU_PAGE_ALIGN(amdgpu_vm_num_entries(adev, level) * 8);
22341ec0267Sriastradh }
22441ec0267Sriastradh 
22541ec0267Sriastradh /**
22641ec0267Sriastradh  * amdgpu_vm_bo_evicted - vm_bo is evicted
22741ec0267Sriastradh  *
22841ec0267Sriastradh  * @vm_bo: vm_bo which is evicted
22941ec0267Sriastradh  *
23041ec0267Sriastradh  * State for PDs/PTs and per VM BOs which are not at the location they should
23141ec0267Sriastradh  * be.
23241ec0267Sriastradh  */
amdgpu_vm_bo_evicted(struct amdgpu_vm_bo_base * vm_bo)23341ec0267Sriastradh static void amdgpu_vm_bo_evicted(struct amdgpu_vm_bo_base *vm_bo)
23441ec0267Sriastradh {
23541ec0267Sriastradh 	struct amdgpu_vm *vm = vm_bo->vm;
23641ec0267Sriastradh 	struct amdgpu_bo *bo = vm_bo->bo;
23741ec0267Sriastradh 
23841ec0267Sriastradh 	vm_bo->moved = true;
23941ec0267Sriastradh 	if (bo->tbo.type == ttm_bo_type_kernel)
24041ec0267Sriastradh 		list_move(&vm_bo->vm_status, &vm->evicted);
24141ec0267Sriastradh 	else
24241ec0267Sriastradh 		list_move_tail(&vm_bo->vm_status, &vm->evicted);
24341ec0267Sriastradh }
24441ec0267Sriastradh 
24541ec0267Sriastradh /**
24641ec0267Sriastradh  * amdgpu_vm_bo_relocated - vm_bo is reloacted
24741ec0267Sriastradh  *
24841ec0267Sriastradh  * @vm_bo: vm_bo which is relocated
24941ec0267Sriastradh  *
25041ec0267Sriastradh  * State for PDs/PTs which needs to update their parent PD.
25141ec0267Sriastradh  */
amdgpu_vm_bo_relocated(struct amdgpu_vm_bo_base * vm_bo)25241ec0267Sriastradh static void amdgpu_vm_bo_relocated(struct amdgpu_vm_bo_base *vm_bo)
25341ec0267Sriastradh {
25441ec0267Sriastradh 	list_move(&vm_bo->vm_status, &vm_bo->vm->relocated);
25541ec0267Sriastradh }
25641ec0267Sriastradh 
25741ec0267Sriastradh /**
25841ec0267Sriastradh  * amdgpu_vm_bo_moved - vm_bo is moved
25941ec0267Sriastradh  *
26041ec0267Sriastradh  * @vm_bo: vm_bo which is moved
26141ec0267Sriastradh  *
26241ec0267Sriastradh  * State for per VM BOs which are moved, but that change is not yet reflected
26341ec0267Sriastradh  * in the page tables.
26441ec0267Sriastradh  */
amdgpu_vm_bo_moved(struct amdgpu_vm_bo_base * vm_bo)26541ec0267Sriastradh static void amdgpu_vm_bo_moved(struct amdgpu_vm_bo_base *vm_bo)
26641ec0267Sriastradh {
26741ec0267Sriastradh 	list_move(&vm_bo->vm_status, &vm_bo->vm->moved);
26841ec0267Sriastradh }
26941ec0267Sriastradh 
27041ec0267Sriastradh /**
27141ec0267Sriastradh  * amdgpu_vm_bo_idle - vm_bo is idle
27241ec0267Sriastradh  *
27341ec0267Sriastradh  * @vm_bo: vm_bo which is now idle
27441ec0267Sriastradh  *
27541ec0267Sriastradh  * State for PDs/PTs and per VM BOs which have gone through the state machine
27641ec0267Sriastradh  * and are now idle.
27741ec0267Sriastradh  */
amdgpu_vm_bo_idle(struct amdgpu_vm_bo_base * vm_bo)27841ec0267Sriastradh static void amdgpu_vm_bo_idle(struct amdgpu_vm_bo_base *vm_bo)
27941ec0267Sriastradh {
28041ec0267Sriastradh 	list_move(&vm_bo->vm_status, &vm_bo->vm->idle);
28141ec0267Sriastradh 	vm_bo->moved = false;
28241ec0267Sriastradh }
28341ec0267Sriastradh 
28441ec0267Sriastradh /**
28541ec0267Sriastradh  * amdgpu_vm_bo_invalidated - vm_bo is invalidated
28641ec0267Sriastradh  *
28741ec0267Sriastradh  * @vm_bo: vm_bo which is now invalidated
28841ec0267Sriastradh  *
28941ec0267Sriastradh  * State for normal BOs which are invalidated and that change not yet reflected
29041ec0267Sriastradh  * in the PTs.
29141ec0267Sriastradh  */
amdgpu_vm_bo_invalidated(struct amdgpu_vm_bo_base * vm_bo)29241ec0267Sriastradh static void amdgpu_vm_bo_invalidated(struct amdgpu_vm_bo_base *vm_bo)
29341ec0267Sriastradh {
29441ec0267Sriastradh 	spin_lock(&vm_bo->vm->invalidated_lock);
29541ec0267Sriastradh 	list_move(&vm_bo->vm_status, &vm_bo->vm->invalidated);
29641ec0267Sriastradh 	spin_unlock(&vm_bo->vm->invalidated_lock);
29741ec0267Sriastradh }
29841ec0267Sriastradh 
29941ec0267Sriastradh /**
30041ec0267Sriastradh  * amdgpu_vm_bo_done - vm_bo is done
30141ec0267Sriastradh  *
30241ec0267Sriastradh  * @vm_bo: vm_bo which is now done
30341ec0267Sriastradh  *
30441ec0267Sriastradh  * State for normal BOs which are invalidated and that change has been updated
30541ec0267Sriastradh  * in the PTs.
30641ec0267Sriastradh  */
amdgpu_vm_bo_done(struct amdgpu_vm_bo_base * vm_bo)30741ec0267Sriastradh static void amdgpu_vm_bo_done(struct amdgpu_vm_bo_base *vm_bo)
30841ec0267Sriastradh {
30941ec0267Sriastradh 	spin_lock(&vm_bo->vm->invalidated_lock);
31041ec0267Sriastradh 	list_del_init(&vm_bo->vm_status);
31141ec0267Sriastradh 	spin_unlock(&vm_bo->vm->invalidated_lock);
31241ec0267Sriastradh }
31341ec0267Sriastradh 
31441ec0267Sriastradh /**
31541ec0267Sriastradh  * amdgpu_vm_bo_base_init - Adds bo to the list of bos associated with the vm
31641ec0267Sriastradh  *
31741ec0267Sriastradh  * @base: base structure for tracking BO usage in a VM
31841ec0267Sriastradh  * @vm: vm to which bo is to be added
31941ec0267Sriastradh  * @bo: amdgpu buffer object
32041ec0267Sriastradh  *
32141ec0267Sriastradh  * Initialize a bo_va_base structure and add it to the appropriate lists
32241ec0267Sriastradh  *
32341ec0267Sriastradh  */
amdgpu_vm_bo_base_init(struct amdgpu_vm_bo_base * base,struct amdgpu_vm * vm,struct amdgpu_bo * bo)32441ec0267Sriastradh static void amdgpu_vm_bo_base_init(struct amdgpu_vm_bo_base *base,
32541ec0267Sriastradh 				   struct amdgpu_vm *vm,
32641ec0267Sriastradh 				   struct amdgpu_bo *bo)
32741ec0267Sriastradh {
32841ec0267Sriastradh 	base->vm = vm;
32941ec0267Sriastradh 	base->bo = bo;
33041ec0267Sriastradh 	base->next = NULL;
33141ec0267Sriastradh 	INIT_LIST_HEAD(&base->vm_status);
33241ec0267Sriastradh 
33341ec0267Sriastradh 	if (!bo)
33441ec0267Sriastradh 		return;
33541ec0267Sriastradh 	base->next = bo->vm_bo;
33641ec0267Sriastradh 	bo->vm_bo = base;
33741ec0267Sriastradh 
33841ec0267Sriastradh 	if (bo->tbo.base.resv != vm->root.base.bo->tbo.base.resv)
33941ec0267Sriastradh 		return;
34041ec0267Sriastradh 
34141ec0267Sriastradh 	vm->bulk_moveable = false;
34241ec0267Sriastradh 	if (bo->tbo.type == ttm_bo_type_kernel && bo->parent)
34341ec0267Sriastradh 		amdgpu_vm_bo_relocated(base);
34441ec0267Sriastradh 	else
34541ec0267Sriastradh 		amdgpu_vm_bo_idle(base);
34641ec0267Sriastradh 
34741ec0267Sriastradh 	if (bo->preferred_domains &
34841ec0267Sriastradh 	    amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type))
34941ec0267Sriastradh 		return;
35041ec0267Sriastradh 
35141ec0267Sriastradh 	/*
35241ec0267Sriastradh 	 * we checked all the prerequisites, but it looks like this per vm bo
35341ec0267Sriastradh 	 * is currently evicted. add the bo to the evicted list to make sure it
35441ec0267Sriastradh 	 * is validated on next vm use to avoid fault.
35541ec0267Sriastradh 	 * */
35641ec0267Sriastradh 	amdgpu_vm_bo_evicted(base);
35741ec0267Sriastradh }
35841ec0267Sriastradh 
35941ec0267Sriastradh /**
36041ec0267Sriastradh  * amdgpu_vm_pt_parent - get the parent page directory
36141ec0267Sriastradh  *
36241ec0267Sriastradh  * @pt: child page table
36341ec0267Sriastradh  *
36441ec0267Sriastradh  * Helper to get the parent entry for the child page table. NULL if we are at
36541ec0267Sriastradh  * the root page directory.
36641ec0267Sriastradh  */
amdgpu_vm_pt_parent(struct amdgpu_vm_pt * pt)36741ec0267Sriastradh static struct amdgpu_vm_pt *amdgpu_vm_pt_parent(struct amdgpu_vm_pt *pt)
36841ec0267Sriastradh {
36941ec0267Sriastradh 	struct amdgpu_bo *parent = pt->base.bo->parent;
37041ec0267Sriastradh 
37141ec0267Sriastradh 	if (!parent)
37241ec0267Sriastradh 		return NULL;
37341ec0267Sriastradh 
37441ec0267Sriastradh 	return container_of(parent->vm_bo, struct amdgpu_vm_pt, base);
37541ec0267Sriastradh }
37641ec0267Sriastradh 
37741ec0267Sriastradh /*
37841ec0267Sriastradh  * amdgpu_vm_pt_cursor - state for for_each_amdgpu_vm_pt
37941ec0267Sriastradh  */
38041ec0267Sriastradh struct amdgpu_vm_pt_cursor {
38141ec0267Sriastradh 	uint64_t pfn;
38241ec0267Sriastradh 	struct amdgpu_vm_pt *parent;
38341ec0267Sriastradh 	struct amdgpu_vm_pt *entry;
38441ec0267Sriastradh 	unsigned level;
38541ec0267Sriastradh };
38641ec0267Sriastradh 
38741ec0267Sriastradh /**
38841ec0267Sriastradh  * amdgpu_vm_pt_start - start PD/PT walk
38941ec0267Sriastradh  *
39041ec0267Sriastradh  * @adev: amdgpu_device pointer
39141ec0267Sriastradh  * @vm: amdgpu_vm structure
39241ec0267Sriastradh  * @start: start address of the walk
39341ec0267Sriastradh  * @cursor: state to initialize
39441ec0267Sriastradh  *
39541ec0267Sriastradh  * Initialize a amdgpu_vm_pt_cursor to start a walk.
39641ec0267Sriastradh  */
amdgpu_vm_pt_start(struct amdgpu_device * adev,struct amdgpu_vm * vm,uint64_t start,struct amdgpu_vm_pt_cursor * cursor)39741ec0267Sriastradh static void amdgpu_vm_pt_start(struct amdgpu_device *adev,
39841ec0267Sriastradh 			       struct amdgpu_vm *vm, uint64_t start,
39941ec0267Sriastradh 			       struct amdgpu_vm_pt_cursor *cursor)
40041ec0267Sriastradh {
40141ec0267Sriastradh 	cursor->pfn = start;
40241ec0267Sriastradh 	cursor->parent = NULL;
40341ec0267Sriastradh 	cursor->entry = &vm->root;
40441ec0267Sriastradh 	cursor->level = adev->vm_manager.root_level;
40541ec0267Sriastradh }
40641ec0267Sriastradh 
40741ec0267Sriastradh /**
40841ec0267Sriastradh  * amdgpu_vm_pt_descendant - go to child node
40941ec0267Sriastradh  *
41041ec0267Sriastradh  * @adev: amdgpu_device pointer
41141ec0267Sriastradh  * @cursor: current state
41241ec0267Sriastradh  *
41341ec0267Sriastradh  * Walk to the child node of the current node.
41441ec0267Sriastradh  * Returns:
41541ec0267Sriastradh  * True if the walk was possible, false otherwise.
41641ec0267Sriastradh  */
amdgpu_vm_pt_descendant(struct amdgpu_device * adev,struct amdgpu_vm_pt_cursor * cursor)41741ec0267Sriastradh static bool amdgpu_vm_pt_descendant(struct amdgpu_device *adev,
41841ec0267Sriastradh 				    struct amdgpu_vm_pt_cursor *cursor)
41941ec0267Sriastradh {
42041ec0267Sriastradh 	unsigned mask, shift, idx;
42141ec0267Sriastradh 
42241ec0267Sriastradh 	if (!cursor->entry->entries)
42341ec0267Sriastradh 		return false;
42441ec0267Sriastradh 
42541ec0267Sriastradh 	BUG_ON(!cursor->entry->base.bo);
42641ec0267Sriastradh 	mask = amdgpu_vm_entries_mask(adev, cursor->level);
42741ec0267Sriastradh 	shift = amdgpu_vm_level_shift(adev, cursor->level);
42841ec0267Sriastradh 
42941ec0267Sriastradh 	++cursor->level;
43041ec0267Sriastradh 	idx = (cursor->pfn >> shift) & mask;
43141ec0267Sriastradh 	cursor->parent = cursor->entry;
43241ec0267Sriastradh 	cursor->entry = &cursor->entry->entries[idx];
43341ec0267Sriastradh 	return true;
43441ec0267Sriastradh }
43541ec0267Sriastradh 
43641ec0267Sriastradh /**
43741ec0267Sriastradh  * amdgpu_vm_pt_sibling - go to sibling node
43841ec0267Sriastradh  *
43941ec0267Sriastradh  * @adev: amdgpu_device pointer
44041ec0267Sriastradh  * @cursor: current state
44141ec0267Sriastradh  *
44241ec0267Sriastradh  * Walk to the sibling node of the current node.
44341ec0267Sriastradh  * Returns:
44441ec0267Sriastradh  * True if the walk was possible, false otherwise.
44541ec0267Sriastradh  */
amdgpu_vm_pt_sibling(struct amdgpu_device * adev,struct amdgpu_vm_pt_cursor * cursor)44641ec0267Sriastradh static bool amdgpu_vm_pt_sibling(struct amdgpu_device *adev,
44741ec0267Sriastradh 				 struct amdgpu_vm_pt_cursor *cursor)
44841ec0267Sriastradh {
44941ec0267Sriastradh 	unsigned shift, num_entries;
45041ec0267Sriastradh 
45141ec0267Sriastradh 	/* Root doesn't have a sibling */
45241ec0267Sriastradh 	if (!cursor->parent)
45341ec0267Sriastradh 		return false;
45441ec0267Sriastradh 
45541ec0267Sriastradh 	/* Go to our parents and see if we got a sibling */
45641ec0267Sriastradh 	shift = amdgpu_vm_level_shift(adev, cursor->level - 1);
45741ec0267Sriastradh 	num_entries = amdgpu_vm_num_entries(adev, cursor->level - 1);
45841ec0267Sriastradh 
45941ec0267Sriastradh 	if (cursor->entry == &cursor->parent->entries[num_entries - 1])
46041ec0267Sriastradh 		return false;
46141ec0267Sriastradh 
46241ec0267Sriastradh 	cursor->pfn += 1ULL << shift;
46341ec0267Sriastradh 	cursor->pfn &= ~((1ULL << shift) - 1);
46441ec0267Sriastradh 	++cursor->entry;
46541ec0267Sriastradh 	return true;
46641ec0267Sriastradh }
46741ec0267Sriastradh 
46841ec0267Sriastradh /**
46941ec0267Sriastradh  * amdgpu_vm_pt_ancestor - go to parent node
47041ec0267Sriastradh  *
47141ec0267Sriastradh  * @cursor: current state
47241ec0267Sriastradh  *
47341ec0267Sriastradh  * Walk to the parent node of the current node.
47441ec0267Sriastradh  * Returns:
47541ec0267Sriastradh  * True if the walk was possible, false otherwise.
47641ec0267Sriastradh  */
amdgpu_vm_pt_ancestor(struct amdgpu_vm_pt_cursor * cursor)47741ec0267Sriastradh static bool amdgpu_vm_pt_ancestor(struct amdgpu_vm_pt_cursor *cursor)
47841ec0267Sriastradh {
47941ec0267Sriastradh 	if (!cursor->parent)
48041ec0267Sriastradh 		return false;
48141ec0267Sriastradh 
48241ec0267Sriastradh 	--cursor->level;
48341ec0267Sriastradh 	cursor->entry = cursor->parent;
48441ec0267Sriastradh 	cursor->parent = amdgpu_vm_pt_parent(cursor->parent);
48541ec0267Sriastradh 	return true;
48641ec0267Sriastradh }
48741ec0267Sriastradh 
48841ec0267Sriastradh /**
48941ec0267Sriastradh  * amdgpu_vm_pt_next - get next PD/PT in hieratchy
49041ec0267Sriastradh  *
49141ec0267Sriastradh  * @adev: amdgpu_device pointer
49241ec0267Sriastradh  * @cursor: current state
49341ec0267Sriastradh  *
49441ec0267Sriastradh  * Walk the PD/PT tree to the next node.
49541ec0267Sriastradh  */
amdgpu_vm_pt_next(struct amdgpu_device * adev,struct amdgpu_vm_pt_cursor * cursor)49641ec0267Sriastradh static void amdgpu_vm_pt_next(struct amdgpu_device *adev,
49741ec0267Sriastradh 			      struct amdgpu_vm_pt_cursor *cursor)
49841ec0267Sriastradh {
49941ec0267Sriastradh 	/* First try a newborn child */
50041ec0267Sriastradh 	if (amdgpu_vm_pt_descendant(adev, cursor))
50141ec0267Sriastradh 		return;
50241ec0267Sriastradh 
50341ec0267Sriastradh 	/* If that didn't worked try to find a sibling */
50441ec0267Sriastradh 	while (!amdgpu_vm_pt_sibling(adev, cursor)) {
50541ec0267Sriastradh 		/* No sibling, go to our parents and grandparents */
50641ec0267Sriastradh 		if (!amdgpu_vm_pt_ancestor(cursor)) {
50741ec0267Sriastradh 			cursor->pfn = ~0ll;
50841ec0267Sriastradh 			return;
50941ec0267Sriastradh 		}
51041ec0267Sriastradh 	}
51141ec0267Sriastradh }
51241ec0267Sriastradh 
51341ec0267Sriastradh /**
51441ec0267Sriastradh  * amdgpu_vm_pt_first_dfs - start a deep first search
51541ec0267Sriastradh  *
51641ec0267Sriastradh  * @adev: amdgpu_device structure
51741ec0267Sriastradh  * @vm: amdgpu_vm structure
51841ec0267Sriastradh  * @start: optional cursor to start with
51941ec0267Sriastradh  * @cursor: state to initialize
52041ec0267Sriastradh  *
52141ec0267Sriastradh  * Starts a deep first traversal of the PD/PT tree.
52241ec0267Sriastradh  */
amdgpu_vm_pt_first_dfs(struct amdgpu_device * adev,struct amdgpu_vm * vm,struct amdgpu_vm_pt_cursor * start,struct amdgpu_vm_pt_cursor * cursor)52341ec0267Sriastradh static void amdgpu_vm_pt_first_dfs(struct amdgpu_device *adev,
52441ec0267Sriastradh 				   struct amdgpu_vm *vm,
52541ec0267Sriastradh 				   struct amdgpu_vm_pt_cursor *start,
52641ec0267Sriastradh 				   struct amdgpu_vm_pt_cursor *cursor)
52741ec0267Sriastradh {
52841ec0267Sriastradh 	if (start)
52941ec0267Sriastradh 		*cursor = *start;
53041ec0267Sriastradh 	else
53141ec0267Sriastradh 		amdgpu_vm_pt_start(adev, vm, 0, cursor);
53241ec0267Sriastradh 	while (amdgpu_vm_pt_descendant(adev, cursor));
53341ec0267Sriastradh }
53441ec0267Sriastradh 
53541ec0267Sriastradh /**
53641ec0267Sriastradh  * amdgpu_vm_pt_continue_dfs - check if the deep first search should continue
53741ec0267Sriastradh  *
53841ec0267Sriastradh  * @start: starting point for the search
53941ec0267Sriastradh  * @entry: current entry
54041ec0267Sriastradh  *
54141ec0267Sriastradh  * Returns:
54241ec0267Sriastradh  * True when the search should continue, false otherwise.
54341ec0267Sriastradh  */
amdgpu_vm_pt_continue_dfs(struct amdgpu_vm_pt_cursor * start,struct amdgpu_vm_pt * entry)54441ec0267Sriastradh static bool amdgpu_vm_pt_continue_dfs(struct amdgpu_vm_pt_cursor *start,
54541ec0267Sriastradh 				      struct amdgpu_vm_pt *entry)
54641ec0267Sriastradh {
54741ec0267Sriastradh 	return entry && (!start || entry != start->entry);
54841ec0267Sriastradh }
54941ec0267Sriastradh 
55041ec0267Sriastradh /**
55141ec0267Sriastradh  * amdgpu_vm_pt_next_dfs - get the next node for a deep first search
55241ec0267Sriastradh  *
55341ec0267Sriastradh  * @adev: amdgpu_device structure
55441ec0267Sriastradh  * @cursor: current state
55541ec0267Sriastradh  *
55641ec0267Sriastradh  * Move the cursor to the next node in a deep first search.
55741ec0267Sriastradh  */
amdgpu_vm_pt_next_dfs(struct amdgpu_device * adev,struct amdgpu_vm_pt_cursor * cursor)55841ec0267Sriastradh static void amdgpu_vm_pt_next_dfs(struct amdgpu_device *adev,
55941ec0267Sriastradh 				  struct amdgpu_vm_pt_cursor *cursor)
56041ec0267Sriastradh {
56141ec0267Sriastradh 	if (!cursor->entry)
56241ec0267Sriastradh 		return;
56341ec0267Sriastradh 
56441ec0267Sriastradh 	if (!cursor->parent)
56541ec0267Sriastradh 		cursor->entry = NULL;
56641ec0267Sriastradh 	else if (amdgpu_vm_pt_sibling(adev, cursor))
56741ec0267Sriastradh 		while (amdgpu_vm_pt_descendant(adev, cursor));
56841ec0267Sriastradh 	else
56941ec0267Sriastradh 		amdgpu_vm_pt_ancestor(cursor);
57041ec0267Sriastradh }
57141ec0267Sriastradh 
57241ec0267Sriastradh /*
57341ec0267Sriastradh  * for_each_amdgpu_vm_pt_dfs_safe - safe deep first search of all PDs/PTs
57441ec0267Sriastradh  */
57541ec0267Sriastradh #define for_each_amdgpu_vm_pt_dfs_safe(adev, vm, start, cursor, entry)		\
57641ec0267Sriastradh 	for (amdgpu_vm_pt_first_dfs((adev), (vm), (start), &(cursor)),		\
57741ec0267Sriastradh 	     (entry) = (cursor).entry, amdgpu_vm_pt_next_dfs((adev), &(cursor));\
57841ec0267Sriastradh 	     amdgpu_vm_pt_continue_dfs((start), (entry));			\
57941ec0267Sriastradh 	     (entry) = (cursor).entry, amdgpu_vm_pt_next_dfs((adev), &(cursor)))
58041ec0267Sriastradh 
58141ec0267Sriastradh /**
58241ec0267Sriastradh  * amdgpu_vm_get_pd_bo - add the VM PD to a validation list
583efa246c0Sriastradh  *
584efa246c0Sriastradh  * @vm: vm providing the BOs
58541ec0267Sriastradh  * @validated: head of validation list
58641ec0267Sriastradh  * @entry: entry to add
587efa246c0Sriastradh  *
588efa246c0Sriastradh  * Add the page directory to the list of BOs to
58941ec0267Sriastradh  * validate for command submission.
590efa246c0Sriastradh  */
amdgpu_vm_get_pd_bo(struct amdgpu_vm * vm,struct list_head * validated,struct amdgpu_bo_list_entry * entry)59141ec0267Sriastradh void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm,
59241ec0267Sriastradh 			 struct list_head *validated,
59341ec0267Sriastradh 			 struct amdgpu_bo_list_entry *entry)
594efa246c0Sriastradh {
59541ec0267Sriastradh 	entry->priority = 0;
59641ec0267Sriastradh 	entry->tv.bo = &vm->root.base.bo->tbo;
59741ec0267Sriastradh 	/* One for TTM and one for the CS job */
59841ec0267Sriastradh 	entry->tv.num_shared = 2;
59941ec0267Sriastradh 	entry->user_pages = NULL;
60041ec0267Sriastradh 	list_add(&entry->tv.head, validated);
601efa246c0Sriastradh }
602efa246c0Sriastradh 
603efa246c0Sriastradh /**
60441ec0267Sriastradh  * amdgpu_vm_del_from_lru_notify - update bulk_moveable flag
605efa246c0Sriastradh  *
60641ec0267Sriastradh  * @bo: BO which was removed from the LRU
607efa246c0Sriastradh  *
60841ec0267Sriastradh  * Make sure the bulk_moveable flag is updated when a BO is removed from the
60941ec0267Sriastradh  * LRU.
610efa246c0Sriastradh  */
amdgpu_vm_del_from_lru_notify(struct ttm_buffer_object * bo)61141ec0267Sriastradh void amdgpu_vm_del_from_lru_notify(struct ttm_buffer_object *bo)
612efa246c0Sriastradh {
61341ec0267Sriastradh 	struct amdgpu_bo *abo;
61441ec0267Sriastradh 	struct amdgpu_vm_bo_base *bo_base;
61541ec0267Sriastradh 
61641ec0267Sriastradh 	if (!amdgpu_bo_is_amdgpu_bo(bo))
61741ec0267Sriastradh 		return;
61841ec0267Sriastradh 
61941ec0267Sriastradh 	if (bo->mem.placement & TTM_PL_FLAG_NO_EVICT)
62041ec0267Sriastradh 		return;
62141ec0267Sriastradh 
62241ec0267Sriastradh 	abo = ttm_to_amdgpu_bo(bo);
62341ec0267Sriastradh 	if (!abo->parent)
62441ec0267Sriastradh 		return;
62541ec0267Sriastradh 	for (bo_base = abo->vm_bo; bo_base; bo_base = bo_base->next) {
62641ec0267Sriastradh 		struct amdgpu_vm *vm = bo_base->vm;
62741ec0267Sriastradh 
62841ec0267Sriastradh 		if (abo->tbo.base.resv == vm->root.base.bo->tbo.base.resv)
62941ec0267Sriastradh 			vm->bulk_moveable = false;
63041ec0267Sriastradh 	}
63141ec0267Sriastradh 
63241ec0267Sriastradh }
63341ec0267Sriastradh /**
63441ec0267Sriastradh  * amdgpu_vm_move_to_lru_tail - move all BOs to the end of LRU
63541ec0267Sriastradh  *
63641ec0267Sriastradh  * @adev: amdgpu device pointer
63741ec0267Sriastradh  * @vm: vm providing the BOs
63841ec0267Sriastradh  *
63941ec0267Sriastradh  * Move all BOs to the end of LRU and remember their positions to put them
64041ec0267Sriastradh  * together.
64141ec0267Sriastradh  */
amdgpu_vm_move_to_lru_tail(struct amdgpu_device * adev,struct amdgpu_vm * vm)64241ec0267Sriastradh void amdgpu_vm_move_to_lru_tail(struct amdgpu_device *adev,
64341ec0267Sriastradh 				struct amdgpu_vm *vm)
64441ec0267Sriastradh {
64541ec0267Sriastradh 	struct amdgpu_vm_bo_base *bo_base;
64641ec0267Sriastradh 
64741ec0267Sriastradh 	if (vm->bulk_moveable) {
64841ec0267Sriastradh 		spin_lock(&ttm_bo_glob.lru_lock);
64941ec0267Sriastradh 		ttm_bo_bulk_move_lru_tail(&vm->lru_bulk_move);
65041ec0267Sriastradh 		spin_unlock(&ttm_bo_glob.lru_lock);
65141ec0267Sriastradh 		return;
65241ec0267Sriastradh 	}
65341ec0267Sriastradh 
65441ec0267Sriastradh 	memset(&vm->lru_bulk_move, 0, sizeof(vm->lru_bulk_move));
65541ec0267Sriastradh 
65641ec0267Sriastradh 	spin_lock(&ttm_bo_glob.lru_lock);
65741ec0267Sriastradh 	list_for_each_entry(bo_base, &vm->idle, vm_status) {
65841ec0267Sriastradh 		struct amdgpu_bo *bo = bo_base->bo;
65941ec0267Sriastradh 
66041ec0267Sriastradh 		if (!bo->parent)
66141ec0267Sriastradh 			continue;
66241ec0267Sriastradh 
66341ec0267Sriastradh 		ttm_bo_move_to_lru_tail(&bo->tbo, &vm->lru_bulk_move);
66441ec0267Sriastradh 		if (bo->shadow)
66541ec0267Sriastradh 			ttm_bo_move_to_lru_tail(&bo->shadow->tbo,
66641ec0267Sriastradh 						&vm->lru_bulk_move);
66741ec0267Sriastradh 	}
66841ec0267Sriastradh 	spin_unlock(&ttm_bo_glob.lru_lock);
66941ec0267Sriastradh 
67041ec0267Sriastradh 	vm->bulk_moveable = true;
67141ec0267Sriastradh }
67241ec0267Sriastradh 
67341ec0267Sriastradh /**
67441ec0267Sriastradh  * amdgpu_vm_validate_pt_bos - validate the page table BOs
67541ec0267Sriastradh  *
67641ec0267Sriastradh  * @adev: amdgpu device pointer
67741ec0267Sriastradh  * @vm: vm providing the BOs
67841ec0267Sriastradh  * @validate: callback to do the validation
67941ec0267Sriastradh  * @param: parameter for the validation callback
68041ec0267Sriastradh  *
68141ec0267Sriastradh  * Validate the page table BOs on command submission if neccessary.
68241ec0267Sriastradh  *
68341ec0267Sriastradh  * Returns:
68441ec0267Sriastradh  * Validation result.
68541ec0267Sriastradh  */
amdgpu_vm_validate_pt_bos(struct amdgpu_device * adev,struct amdgpu_vm * vm,int (* validate)(void * p,struct amdgpu_bo * bo),void * param)68641ec0267Sriastradh int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm,
68741ec0267Sriastradh 			      int (*validate)(void *p, struct amdgpu_bo *bo),
68841ec0267Sriastradh 			      void *param)
68941ec0267Sriastradh {
69041ec0267Sriastradh 	struct amdgpu_vm_bo_base *bo_base, *tmp;
69141ec0267Sriastradh 	int r;
69241ec0267Sriastradh 
69341ec0267Sriastradh 	vm->bulk_moveable &= list_empty(&vm->evicted);
69441ec0267Sriastradh 
69541ec0267Sriastradh 	list_for_each_entry_safe(bo_base, tmp, &vm->evicted, vm_status) {
69641ec0267Sriastradh 		struct amdgpu_bo *bo = bo_base->bo;
69741ec0267Sriastradh 
69841ec0267Sriastradh 		r = validate(param, bo);
69941ec0267Sriastradh 		if (r)
70041ec0267Sriastradh 			return r;
70141ec0267Sriastradh 
70241ec0267Sriastradh 		if (bo->tbo.type != ttm_bo_type_kernel) {
70341ec0267Sriastradh 			amdgpu_vm_bo_moved(bo_base);
70441ec0267Sriastradh 		} else {
70541ec0267Sriastradh 			vm->update_funcs->map_table(bo);
70641ec0267Sriastradh 			if (bo->parent)
70741ec0267Sriastradh 				amdgpu_vm_bo_relocated(bo_base);
70841ec0267Sriastradh 			else
70941ec0267Sriastradh 				amdgpu_vm_bo_idle(bo_base);
71041ec0267Sriastradh 		}
71141ec0267Sriastradh 	}
71241ec0267Sriastradh 
71341ec0267Sriastradh 	amdgpu_vm_eviction_lock(vm);
71441ec0267Sriastradh 	vm->evicting = false;
71541ec0267Sriastradh 	amdgpu_vm_eviction_unlock(vm);
71641ec0267Sriastradh 
71741ec0267Sriastradh 	return 0;
71841ec0267Sriastradh }
71941ec0267Sriastradh 
72041ec0267Sriastradh /**
72141ec0267Sriastradh  * amdgpu_vm_ready - check VM is ready for updates
72241ec0267Sriastradh  *
72341ec0267Sriastradh  * @vm: VM to check
72441ec0267Sriastradh  *
72541ec0267Sriastradh  * Check if all VM PDs/PTs are ready for updates
72641ec0267Sriastradh  *
72741ec0267Sriastradh  * Returns:
72841ec0267Sriastradh  * True if eviction list is empty.
72941ec0267Sriastradh  */
amdgpu_vm_ready(struct amdgpu_vm * vm)73041ec0267Sriastradh bool amdgpu_vm_ready(struct amdgpu_vm *vm)
73141ec0267Sriastradh {
73241ec0267Sriastradh 	return list_empty(&vm->evicted);
73341ec0267Sriastradh }
73441ec0267Sriastradh 
73541ec0267Sriastradh /**
73641ec0267Sriastradh  * amdgpu_vm_clear_bo - initially clear the PDs/PTs
73741ec0267Sriastradh  *
73841ec0267Sriastradh  * @adev: amdgpu_device pointer
73941ec0267Sriastradh  * @vm: VM to clear BO from
74041ec0267Sriastradh  * @bo: BO to clear
74141ec0267Sriastradh  * @direct: use a direct update
74241ec0267Sriastradh  *
74341ec0267Sriastradh  * Root PD needs to be reserved when calling this.
74441ec0267Sriastradh  *
74541ec0267Sriastradh  * Returns:
74641ec0267Sriastradh  * 0 on success, errno otherwise.
74741ec0267Sriastradh  */
amdgpu_vm_clear_bo(struct amdgpu_device * adev,struct amdgpu_vm * vm,struct amdgpu_bo * bo,bool direct)74841ec0267Sriastradh static int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
74941ec0267Sriastradh 			      struct amdgpu_vm *vm,
75041ec0267Sriastradh 			      struct amdgpu_bo *bo,
75141ec0267Sriastradh 			      bool direct)
75241ec0267Sriastradh {
75341ec0267Sriastradh 	struct ttm_operation_ctx ctx = { true, false };
75441ec0267Sriastradh 	unsigned level = adev->vm_manager.root_level;
75541ec0267Sriastradh 	struct amdgpu_vm_update_params params;
75641ec0267Sriastradh 	struct amdgpu_bo *ancestor = bo;
75741ec0267Sriastradh 	unsigned entries, ats_entries;
75841ec0267Sriastradh 	uint64_t addr;
75941ec0267Sriastradh 	int r;
76041ec0267Sriastradh 
76141ec0267Sriastradh 	/* Figure out our place in the hierarchy */
76241ec0267Sriastradh 	if (ancestor->parent) {
76341ec0267Sriastradh 		++level;
76441ec0267Sriastradh 		while (ancestor->parent->parent) {
76541ec0267Sriastradh 			++level;
76641ec0267Sriastradh 			ancestor = ancestor->parent;
76741ec0267Sriastradh 		}
76841ec0267Sriastradh 	}
76941ec0267Sriastradh 
77041ec0267Sriastradh 	entries = amdgpu_bo_size(bo) / 8;
77141ec0267Sriastradh 	if (!vm->pte_support_ats) {
77241ec0267Sriastradh 		ats_entries = 0;
77341ec0267Sriastradh 
77441ec0267Sriastradh 	} else if (!bo->parent) {
77541ec0267Sriastradh 		ats_entries = amdgpu_vm_num_ats_entries(adev);
77641ec0267Sriastradh 		ats_entries = min(ats_entries, entries);
77741ec0267Sriastradh 		entries -= ats_entries;
77841ec0267Sriastradh 
77941ec0267Sriastradh 	} else {
78041ec0267Sriastradh 		struct amdgpu_vm_pt *pt;
78141ec0267Sriastradh 
78241ec0267Sriastradh 		pt = container_of(ancestor->vm_bo, struct amdgpu_vm_pt, base);
78341ec0267Sriastradh 		ats_entries = amdgpu_vm_num_ats_entries(adev);
78441ec0267Sriastradh 		if ((pt - vm->root.entries) >= ats_entries) {
78541ec0267Sriastradh 			ats_entries = 0;
78641ec0267Sriastradh 		} else {
78741ec0267Sriastradh 			ats_entries = entries;
78841ec0267Sriastradh 			entries = 0;
78941ec0267Sriastradh 		}
79041ec0267Sriastradh 	}
79141ec0267Sriastradh 
79241ec0267Sriastradh 	r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
79341ec0267Sriastradh 	if (r)
79441ec0267Sriastradh 		return r;
79541ec0267Sriastradh 
79641ec0267Sriastradh 	if (bo->shadow) {
79741ec0267Sriastradh 		r = ttm_bo_validate(&bo->shadow->tbo, &bo->shadow->placement,
79841ec0267Sriastradh 				    &ctx);
79941ec0267Sriastradh 		if (r)
80041ec0267Sriastradh 			return r;
80141ec0267Sriastradh 	}
80241ec0267Sriastradh 
80341ec0267Sriastradh 	r = vm->update_funcs->map_table(bo);
80441ec0267Sriastradh 	if (r)
80541ec0267Sriastradh 		return r;
80641ec0267Sriastradh 
80741ec0267Sriastradh 	memset(&params, 0, sizeof(params));
80841ec0267Sriastradh 	params.adev = adev;
80941ec0267Sriastradh 	params.vm = vm;
81041ec0267Sriastradh 	params.direct = direct;
81141ec0267Sriastradh 
81241ec0267Sriastradh 	r = vm->update_funcs->prepare(&params, AMDGPU_FENCE_OWNER_KFD, NULL);
81341ec0267Sriastradh 	if (r)
81441ec0267Sriastradh 		return r;
81541ec0267Sriastradh 
81641ec0267Sriastradh 	addr = 0;
81741ec0267Sriastradh 	if (ats_entries) {
81841ec0267Sriastradh 		uint64_t value = 0, flags;
81941ec0267Sriastradh 
82041ec0267Sriastradh 		flags = AMDGPU_PTE_DEFAULT_ATC;
82141ec0267Sriastradh 		if (level != AMDGPU_VM_PTB) {
82241ec0267Sriastradh 			/* Handle leaf PDEs as PTEs */
82341ec0267Sriastradh 			flags |= AMDGPU_PDE_PTE;
82441ec0267Sriastradh 			amdgpu_gmc_get_vm_pde(adev, level, &value, &flags);
82541ec0267Sriastradh 		}
82641ec0267Sriastradh 
82741ec0267Sriastradh 		r = vm->update_funcs->update(&params, bo, addr, 0, ats_entries,
82841ec0267Sriastradh 					     value, flags);
82941ec0267Sriastradh 		if (r)
83041ec0267Sriastradh 			return r;
83141ec0267Sriastradh 
83241ec0267Sriastradh 		addr += ats_entries * 8;
83341ec0267Sriastradh 	}
83441ec0267Sriastradh 
83541ec0267Sriastradh 	if (entries) {
83641ec0267Sriastradh 		uint64_t value = 0, flags = 0;
83741ec0267Sriastradh 
83841ec0267Sriastradh 		if (adev->asic_type >= CHIP_VEGA10) {
83941ec0267Sriastradh 			if (level != AMDGPU_VM_PTB) {
84041ec0267Sriastradh 				/* Handle leaf PDEs as PTEs */
84141ec0267Sriastradh 				flags |= AMDGPU_PDE_PTE;
84241ec0267Sriastradh 				amdgpu_gmc_get_vm_pde(adev, level,
84341ec0267Sriastradh 						      &value, &flags);
84441ec0267Sriastradh 			} else {
84541ec0267Sriastradh 				/* Workaround for fault priority problem on GMC9 */
84641ec0267Sriastradh 				flags = AMDGPU_PTE_EXECUTABLE;
84741ec0267Sriastradh 			}
84841ec0267Sriastradh 		}
84941ec0267Sriastradh 
85041ec0267Sriastradh 		r = vm->update_funcs->update(&params, bo, addr, 0, entries,
85141ec0267Sriastradh 					     value, flags);
85241ec0267Sriastradh 		if (r)
85341ec0267Sriastradh 			return r;
85441ec0267Sriastradh 	}
85541ec0267Sriastradh 
85641ec0267Sriastradh 	return vm->update_funcs->commit(&params, NULL);
85741ec0267Sriastradh }
85841ec0267Sriastradh 
85941ec0267Sriastradh /**
86041ec0267Sriastradh  * amdgpu_vm_bo_param - fill in parameters for PD/PT allocation
86141ec0267Sriastradh  *
86241ec0267Sriastradh  * @adev: amdgpu_device pointer
86341ec0267Sriastradh  * @vm: requesting vm
86441ec0267Sriastradh  * @level: the page table level
86541ec0267Sriastradh  * @direct: use a direct update
86641ec0267Sriastradh  * @bp: resulting BO allocation parameters
86741ec0267Sriastradh  */
amdgpu_vm_bo_param(struct amdgpu_device * adev,struct amdgpu_vm * vm,int level,bool direct,struct amdgpu_bo_param * bp)86841ec0267Sriastradh static void amdgpu_vm_bo_param(struct amdgpu_device *adev, struct amdgpu_vm *vm,
86941ec0267Sriastradh 			       int level, bool direct,
87041ec0267Sriastradh 			       struct amdgpu_bo_param *bp)
87141ec0267Sriastradh {
87241ec0267Sriastradh 	memset(bp, 0, sizeof(*bp));
87341ec0267Sriastradh 
87441ec0267Sriastradh 	bp->size = amdgpu_vm_bo_size(adev, level);
87541ec0267Sriastradh 	bp->byte_align = AMDGPU_GPU_PAGE_SIZE;
87641ec0267Sriastradh 	bp->domain = AMDGPU_GEM_DOMAIN_VRAM;
87741ec0267Sriastradh 	bp->domain = amdgpu_bo_get_preferred_pin_domain(adev, bp->domain);
87841ec0267Sriastradh 	bp->flags = AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS |
87941ec0267Sriastradh 		AMDGPU_GEM_CREATE_CPU_GTT_USWC;
88041ec0267Sriastradh 	if (vm->use_cpu_for_update)
88141ec0267Sriastradh 		bp->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
88241ec0267Sriastradh 	else if (!vm->root.base.bo || vm->root.base.bo->shadow)
88341ec0267Sriastradh 		bp->flags |= AMDGPU_GEM_CREATE_SHADOW;
88441ec0267Sriastradh 	bp->type = ttm_bo_type_kernel;
88541ec0267Sriastradh 	bp->no_wait_gpu = direct;
88641ec0267Sriastradh 	if (vm->root.base.bo)
88741ec0267Sriastradh 		bp->resv = vm->root.base.bo->tbo.base.resv;
88841ec0267Sriastradh }
88941ec0267Sriastradh 
89041ec0267Sriastradh /**
89141ec0267Sriastradh  * amdgpu_vm_alloc_pts - Allocate a specific page table
89241ec0267Sriastradh  *
89341ec0267Sriastradh  * @adev: amdgpu_device pointer
89441ec0267Sriastradh  * @vm: VM to allocate page tables for
89541ec0267Sriastradh  * @cursor: Which page table to allocate
89641ec0267Sriastradh  * @direct: use a direct update
89741ec0267Sriastradh  *
89841ec0267Sriastradh  * Make sure a specific page table or directory is allocated.
89941ec0267Sriastradh  *
90041ec0267Sriastradh  * Returns:
90141ec0267Sriastradh  * 1 if page table needed to be allocated, 0 if page table was already
90241ec0267Sriastradh  * allocated, negative errno if an error occurred.
90341ec0267Sriastradh  */
amdgpu_vm_alloc_pts(struct amdgpu_device * adev,struct amdgpu_vm * vm,struct amdgpu_vm_pt_cursor * cursor,bool direct)90441ec0267Sriastradh static int amdgpu_vm_alloc_pts(struct amdgpu_device *adev,
90541ec0267Sriastradh 			       struct amdgpu_vm *vm,
90641ec0267Sriastradh 			       struct amdgpu_vm_pt_cursor *cursor,
90741ec0267Sriastradh 			       bool direct)
90841ec0267Sriastradh {
90941ec0267Sriastradh 	struct amdgpu_vm_pt *entry = cursor->entry;
91041ec0267Sriastradh 	struct amdgpu_bo_param bp;
91141ec0267Sriastradh 	struct amdgpu_bo *pt;
91241ec0267Sriastradh 	int r;
91341ec0267Sriastradh 
91441ec0267Sriastradh 	if (cursor->level < AMDGPU_VM_PTB && !entry->entries) {
91541ec0267Sriastradh 		unsigned num_entries;
91641ec0267Sriastradh 
91741ec0267Sriastradh 		num_entries = amdgpu_vm_num_entries(adev, cursor->level);
91841ec0267Sriastradh 		entry->entries = kvmalloc_array(num_entries,
91941ec0267Sriastradh 						sizeof(*entry->entries),
92041ec0267Sriastradh 						GFP_KERNEL | __GFP_ZERO);
92141ec0267Sriastradh 		if (!entry->entries)
92241ec0267Sriastradh 			return -ENOMEM;
92341ec0267Sriastradh 	}
92441ec0267Sriastradh 
92541ec0267Sriastradh 	if (entry->base.bo)
92641ec0267Sriastradh 		return 0;
92741ec0267Sriastradh 
92841ec0267Sriastradh 	amdgpu_vm_bo_param(adev, vm, cursor->level, direct, &bp);
92941ec0267Sriastradh 
93041ec0267Sriastradh 	r = amdgpu_bo_create(adev, &bp, &pt);
93141ec0267Sriastradh 	if (r)
93241ec0267Sriastradh 		return r;
93341ec0267Sriastradh 
93441ec0267Sriastradh 	/* Keep a reference to the root directory to avoid
93541ec0267Sriastradh 	 * freeing them up in the wrong order.
93641ec0267Sriastradh 	 */
93741ec0267Sriastradh 	pt->parent = amdgpu_bo_ref(cursor->parent->base.bo);
93841ec0267Sriastradh 	amdgpu_vm_bo_base_init(&entry->base, vm, pt);
93941ec0267Sriastradh 
94041ec0267Sriastradh 	r = amdgpu_vm_clear_bo(adev, vm, pt, direct);
94141ec0267Sriastradh 	if (r)
94241ec0267Sriastradh 		goto error_free_pt;
94341ec0267Sriastradh 
94441ec0267Sriastradh 	return 0;
94541ec0267Sriastradh 
94641ec0267Sriastradh error_free_pt:
94741ec0267Sriastradh 	amdgpu_bo_unref(&pt->shadow);
94841ec0267Sriastradh 	amdgpu_bo_unref(&pt);
94941ec0267Sriastradh 	return r;
95041ec0267Sriastradh }
95141ec0267Sriastradh 
95241ec0267Sriastradh /**
95341ec0267Sriastradh  * amdgpu_vm_free_table - fre one PD/PT
95441ec0267Sriastradh  *
95541ec0267Sriastradh  * @entry: PDE to free
95641ec0267Sriastradh  */
amdgpu_vm_free_table(struct amdgpu_vm_pt * entry)95741ec0267Sriastradh static void amdgpu_vm_free_table(struct amdgpu_vm_pt *entry)
95841ec0267Sriastradh {
95941ec0267Sriastradh 	if (entry->base.bo) {
96041ec0267Sriastradh 		entry->base.bo->vm_bo = NULL;
96141ec0267Sriastradh 		list_del(&entry->base.vm_status);
96241ec0267Sriastradh 		amdgpu_bo_unref(&entry->base.bo->shadow);
96341ec0267Sriastradh 		amdgpu_bo_unref(&entry->base.bo);
96441ec0267Sriastradh 	}
96541ec0267Sriastradh 	kvfree(entry->entries);
96641ec0267Sriastradh 	entry->entries = NULL;
96741ec0267Sriastradh }
96841ec0267Sriastradh 
96941ec0267Sriastradh /**
97041ec0267Sriastradh  * amdgpu_vm_free_pts - free PD/PT levels
97141ec0267Sriastradh  *
97241ec0267Sriastradh  * @adev: amdgpu device structure
97341ec0267Sriastradh  * @vm: amdgpu vm structure
97441ec0267Sriastradh  * @start: optional cursor where to start freeing PDs/PTs
97541ec0267Sriastradh  *
97641ec0267Sriastradh  * Free the page directory or page table level and all sub levels.
97741ec0267Sriastradh  */
amdgpu_vm_free_pts(struct amdgpu_device * adev,struct amdgpu_vm * vm,struct amdgpu_vm_pt_cursor * start)97841ec0267Sriastradh static void amdgpu_vm_free_pts(struct amdgpu_device *adev,
97941ec0267Sriastradh 			       struct amdgpu_vm *vm,
98041ec0267Sriastradh 			       struct amdgpu_vm_pt_cursor *start)
98141ec0267Sriastradh {
98241ec0267Sriastradh 	struct amdgpu_vm_pt_cursor cursor;
98341ec0267Sriastradh 	struct amdgpu_vm_pt *entry;
98441ec0267Sriastradh 
98541ec0267Sriastradh 	vm->bulk_moveable = false;
98641ec0267Sriastradh 
98741ec0267Sriastradh 	for_each_amdgpu_vm_pt_dfs_safe(adev, vm, start, cursor, entry)
98841ec0267Sriastradh 		amdgpu_vm_free_table(entry);
98941ec0267Sriastradh 
99041ec0267Sriastradh 	if (start)
99141ec0267Sriastradh 		amdgpu_vm_free_table(start->entry);
99241ec0267Sriastradh }
99341ec0267Sriastradh 
99441ec0267Sriastradh /**
99541ec0267Sriastradh  * amdgpu_vm_check_compute_bug - check whether asic has compute vm bug
99641ec0267Sriastradh  *
99741ec0267Sriastradh  * @adev: amdgpu_device pointer
99841ec0267Sriastradh  */
amdgpu_vm_check_compute_bug(struct amdgpu_device * adev)99941ec0267Sriastradh void amdgpu_vm_check_compute_bug(struct amdgpu_device *adev)
100041ec0267Sriastradh {
100141ec0267Sriastradh 	const struct amdgpu_ip_block *ip_block;
100241ec0267Sriastradh 	bool has_compute_vm_bug;
100341ec0267Sriastradh 	struct amdgpu_ring *ring;
100441ec0267Sriastradh 	int i;
100541ec0267Sriastradh 
100641ec0267Sriastradh 	has_compute_vm_bug = false;
100741ec0267Sriastradh 
100841ec0267Sriastradh 	ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_GFX);
100941ec0267Sriastradh 	if (ip_block) {
101041ec0267Sriastradh 		/* Compute has a VM bug for GFX version < 7.
101141ec0267Sriastradh 		   Compute has a VM bug for GFX 8 MEC firmware version < 673.*/
101241ec0267Sriastradh 		if (ip_block->version->major <= 7)
101341ec0267Sriastradh 			has_compute_vm_bug = true;
101441ec0267Sriastradh 		else if (ip_block->version->major == 8)
101541ec0267Sriastradh 			if (adev->gfx.mec_fw_version < 673)
101641ec0267Sriastradh 				has_compute_vm_bug = true;
101741ec0267Sriastradh 	}
101841ec0267Sriastradh 
101941ec0267Sriastradh 	for (i = 0; i < adev->num_rings; i++) {
102041ec0267Sriastradh 		ring = adev->rings[i];
102141ec0267Sriastradh 		if (ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE)
102241ec0267Sriastradh 			/* only compute rings */
102341ec0267Sriastradh 			ring->has_compute_vm_bug = has_compute_vm_bug;
102441ec0267Sriastradh 		else
102541ec0267Sriastradh 			ring->has_compute_vm_bug = false;
102641ec0267Sriastradh 	}
102741ec0267Sriastradh }
102841ec0267Sriastradh 
102941ec0267Sriastradh /**
103041ec0267Sriastradh  * amdgpu_vm_need_pipeline_sync - Check if pipe sync is needed for job.
103141ec0267Sriastradh  *
103241ec0267Sriastradh  * @ring: ring on which the job will be submitted
103341ec0267Sriastradh  * @job: job to submit
103441ec0267Sriastradh  *
103541ec0267Sriastradh  * Returns:
103641ec0267Sriastradh  * True if sync is needed.
103741ec0267Sriastradh  */
amdgpu_vm_need_pipeline_sync(struct amdgpu_ring * ring,struct amdgpu_job * job)103841ec0267Sriastradh bool amdgpu_vm_need_pipeline_sync(struct amdgpu_ring *ring,
103941ec0267Sriastradh 				  struct amdgpu_job *job)
104041ec0267Sriastradh {
1041efa246c0Sriastradh 	struct amdgpu_device *adev = ring->adev;
104241ec0267Sriastradh 	unsigned vmhub = ring->funcs->vmhub;
104341ec0267Sriastradh 	struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
104441ec0267Sriastradh 	struct amdgpu_vmid *id;
104541ec0267Sriastradh 	bool gds_switch_needed;
104641ec0267Sriastradh 	bool vm_flush_needed = job->vm_needs_flush || ring->has_compute_vm_bug;
1047efa246c0Sriastradh 
104841ec0267Sriastradh 	if (job->vmid == 0)
104941ec0267Sriastradh 		return false;
105041ec0267Sriastradh 	id = &id_mgr->ids[job->vmid];
105141ec0267Sriastradh 	gds_switch_needed = ring->funcs->emit_gds_switch && (
105241ec0267Sriastradh 		id->gds_base != job->gds_base ||
105341ec0267Sriastradh 		id->gds_size != job->gds_size ||
105441ec0267Sriastradh 		id->gws_base != job->gws_base ||
105541ec0267Sriastradh 		id->gws_size != job->gws_size ||
105641ec0267Sriastradh 		id->oa_base != job->oa_base ||
105741ec0267Sriastradh 		id->oa_size != job->oa_size);
1058efa246c0Sriastradh 
105941ec0267Sriastradh 	if (amdgpu_vmid_had_gpu_reset(adev, id))
106041ec0267Sriastradh 		return true;
1061efa246c0Sriastradh 
106241ec0267Sriastradh 	return vm_flush_needed || gds_switch_needed;
1063efa246c0Sriastradh }
1064efa246c0Sriastradh 
1065efa246c0Sriastradh /**
1066efa246c0Sriastradh  * amdgpu_vm_flush - hardware flush the vm
1067efa246c0Sriastradh  *
1068efa246c0Sriastradh  * @ring: ring to use for flush
106941ec0267Sriastradh  * @job:  related job
107041ec0267Sriastradh  * @need_pipe_sync: is pipe sync needed
1071efa246c0Sriastradh  *
107241ec0267Sriastradh  * Emit a VM flush when it is necessary.
1073efa246c0Sriastradh  *
107441ec0267Sriastradh  * Returns:
107541ec0267Sriastradh  * 0 on success, errno otherwise.
1076efa246c0Sriastradh  */
amdgpu_vm_flush(struct amdgpu_ring * ring,struct amdgpu_job * job,bool need_pipe_sync)107741ec0267Sriastradh int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
107841ec0267Sriastradh 		    bool need_pipe_sync)
1079efa246c0Sriastradh {
108041ec0267Sriastradh 	struct amdgpu_device *adev = ring->adev;
108141ec0267Sriastradh 	unsigned vmhub = ring->funcs->vmhub;
108241ec0267Sriastradh 	struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
108341ec0267Sriastradh 	struct amdgpu_vmid *id = &id_mgr->ids[job->vmid];
108441ec0267Sriastradh 	bool gds_switch_needed = ring->funcs->emit_gds_switch && (
108541ec0267Sriastradh 		id->gds_base != job->gds_base ||
108641ec0267Sriastradh 		id->gds_size != job->gds_size ||
108741ec0267Sriastradh 		id->gws_base != job->gws_base ||
108841ec0267Sriastradh 		id->gws_size != job->gws_size ||
108941ec0267Sriastradh 		id->oa_base != job->oa_base ||
109041ec0267Sriastradh 		id->oa_size != job->oa_size);
109141ec0267Sriastradh 	bool vm_flush_needed = job->vm_needs_flush;
109241ec0267Sriastradh 	struct dma_fence *fence = NULL;
109341ec0267Sriastradh 	bool pasid_mapping_needed = false;
109441ec0267Sriastradh 	unsigned patch_offset = 0;
109541ec0267Sriastradh 	int r;
1096efa246c0Sriastradh 
109741ec0267Sriastradh 	if (amdgpu_vmid_had_gpu_reset(adev, id)) {
109841ec0267Sriastradh 		gds_switch_needed = true;
109941ec0267Sriastradh 		vm_flush_needed = true;
110041ec0267Sriastradh 		pasid_mapping_needed = true;
1101efa246c0Sriastradh 	}
1102efa246c0Sriastradh 
110341ec0267Sriastradh 	mutex_lock(&id_mgr->lock);
110441ec0267Sriastradh 	if (id->pasid != job->pasid || !id->pasid_mapping ||
110541ec0267Sriastradh 	    !dma_fence_is_signaled(id->pasid_mapping))
110641ec0267Sriastradh 		pasid_mapping_needed = true;
110741ec0267Sriastradh 	mutex_unlock(&id_mgr->lock);
1108efa246c0Sriastradh 
110941ec0267Sriastradh 	gds_switch_needed &= !!ring->funcs->emit_gds_switch;
111041ec0267Sriastradh 	vm_flush_needed &= !!ring->funcs->emit_vm_flush  &&
111141ec0267Sriastradh 			job->vm_pd_addr != AMDGPU_BO_INVALID_OFFSET;
111241ec0267Sriastradh 	pasid_mapping_needed &= adev->gmc.gmc_funcs->emit_pasid_mapping &&
111341ec0267Sriastradh 		ring->funcs->emit_wreg;
111441ec0267Sriastradh 
111541ec0267Sriastradh 	if (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync)
111641ec0267Sriastradh 		return 0;
111741ec0267Sriastradh 
111841ec0267Sriastradh 	if (ring->funcs->init_cond_exec)
111941ec0267Sriastradh 		patch_offset = amdgpu_ring_init_cond_exec(ring);
112041ec0267Sriastradh 
112141ec0267Sriastradh 	if (need_pipe_sync)
112241ec0267Sriastradh 		amdgpu_ring_emit_pipeline_sync(ring);
112341ec0267Sriastradh 
112441ec0267Sriastradh 	if (vm_flush_needed) {
112541ec0267Sriastradh 		trace_amdgpu_vm_flush(ring, job->vmid, job->vm_pd_addr);
112641ec0267Sriastradh 		amdgpu_ring_emit_vm_flush(ring, job->vmid, job->vm_pd_addr);
112741ec0267Sriastradh 	}
112841ec0267Sriastradh 
112941ec0267Sriastradh 	if (pasid_mapping_needed)
113041ec0267Sriastradh 		amdgpu_gmc_emit_pasid_mapping(ring, job->vmid, job->pasid);
113141ec0267Sriastradh 
113241ec0267Sriastradh 	if (vm_flush_needed || pasid_mapping_needed) {
113341ec0267Sriastradh 		r = amdgpu_fence_emit(ring, &fence, 0);
113441ec0267Sriastradh 		if (r)
113541ec0267Sriastradh 			return r;
113641ec0267Sriastradh 	}
113741ec0267Sriastradh 
113841ec0267Sriastradh 	if (vm_flush_needed) {
113941ec0267Sriastradh 		mutex_lock(&id_mgr->lock);
114041ec0267Sriastradh 		dma_fence_put(id->last_flush);
114141ec0267Sriastradh 		id->last_flush = dma_fence_get(fence);
114241ec0267Sriastradh 		id->current_gpu_reset_count =
114341ec0267Sriastradh 			atomic_read(&adev->gpu_reset_counter);
114441ec0267Sriastradh 		mutex_unlock(&id_mgr->lock);
114541ec0267Sriastradh 	}
114641ec0267Sriastradh 
114741ec0267Sriastradh 	if (pasid_mapping_needed) {
114841ec0267Sriastradh 		mutex_lock(&id_mgr->lock);
114941ec0267Sriastradh 		id->pasid = job->pasid;
115041ec0267Sriastradh 		dma_fence_put(id->pasid_mapping);
115141ec0267Sriastradh 		id->pasid_mapping = dma_fence_get(fence);
115241ec0267Sriastradh 		mutex_unlock(&id_mgr->lock);
115341ec0267Sriastradh 	}
115441ec0267Sriastradh 	dma_fence_put(fence);
115541ec0267Sriastradh 
115641ec0267Sriastradh 	if (ring->funcs->emit_gds_switch && gds_switch_needed) {
115741ec0267Sriastradh 		id->gds_base = job->gds_base;
115841ec0267Sriastradh 		id->gds_size = job->gds_size;
115941ec0267Sriastradh 		id->gws_base = job->gws_base;
116041ec0267Sriastradh 		id->gws_size = job->gws_size;
116141ec0267Sriastradh 		id->oa_base = job->oa_base;
116241ec0267Sriastradh 		id->oa_size = job->oa_size;
116341ec0267Sriastradh 		amdgpu_ring_emit_gds_switch(ring, job->vmid, job->gds_base,
116441ec0267Sriastradh 					    job->gds_size, job->gws_base,
116541ec0267Sriastradh 					    job->gws_size, job->oa_base,
116641ec0267Sriastradh 					    job->oa_size);
116741ec0267Sriastradh 	}
116841ec0267Sriastradh 
116941ec0267Sriastradh 	if (ring->funcs->patch_cond_exec)
117041ec0267Sriastradh 		amdgpu_ring_patch_cond_exec(ring, patch_offset);
117141ec0267Sriastradh 
117241ec0267Sriastradh 	/* the double SWITCH_BUFFER here *cannot* be skipped by COND_EXEC */
117341ec0267Sriastradh 	if (ring->funcs->emit_switch_buffer) {
117441ec0267Sriastradh 		amdgpu_ring_emit_switch_buffer(ring);
117541ec0267Sriastradh 		amdgpu_ring_emit_switch_buffer(ring);
117641ec0267Sriastradh 	}
117741ec0267Sriastradh 	return 0;
1178efa246c0Sriastradh }
1179efa246c0Sriastradh 
1180efa246c0Sriastradh /**
1181efa246c0Sriastradh  * amdgpu_vm_bo_find - find the bo_va for a specific vm & bo
1182efa246c0Sriastradh  *
1183efa246c0Sriastradh  * @vm: requested vm
1184efa246c0Sriastradh  * @bo: requested buffer object
1185efa246c0Sriastradh  *
118641ec0267Sriastradh  * Find @bo inside the requested vm.
1187efa246c0Sriastradh  * Search inside the @bos vm list for the requested vm
1188efa246c0Sriastradh  * Returns the found bo_va or NULL if none is found
1189efa246c0Sriastradh  *
1190efa246c0Sriastradh  * Object has to be reserved!
119141ec0267Sriastradh  *
119241ec0267Sriastradh  * Returns:
119341ec0267Sriastradh  * Found bo_va or NULL.
1194efa246c0Sriastradh  */
amdgpu_vm_bo_find(struct amdgpu_vm * vm,struct amdgpu_bo * bo)1195efa246c0Sriastradh struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm,
1196efa246c0Sriastradh 				       struct amdgpu_bo *bo)
1197efa246c0Sriastradh {
119841ec0267Sriastradh 	struct amdgpu_vm_bo_base *base;
1199efa246c0Sriastradh 
120041ec0267Sriastradh 	for (base = bo->vm_bo; base; base = base->next) {
120141ec0267Sriastradh 		if (base->vm != vm)
120241ec0267Sriastradh 			continue;
120341ec0267Sriastradh 
120441ec0267Sriastradh 		return container_of(base, struct amdgpu_bo_va, base);
1205efa246c0Sriastradh 	}
1206efa246c0Sriastradh 	return NULL;
1207efa246c0Sriastradh }
1208efa246c0Sriastradh 
1209efa246c0Sriastradh /**
121041ec0267Sriastradh  * amdgpu_vm_map_gart - Resolve gart mapping of addr
1211efa246c0Sriastradh  *
121241ec0267Sriastradh  * @pages_addr: optional DMA address to use for lookup
1213efa246c0Sriastradh  * @addr: the unmapped addr
1214efa246c0Sriastradh  *
1215efa246c0Sriastradh  * Look up the physical address of the page that the pte resolves
121641ec0267Sriastradh  * to.
121741ec0267Sriastradh  *
121841ec0267Sriastradh  * Returns:
121941ec0267Sriastradh  * The pointer for the page table entry.
1220efa246c0Sriastradh  */
1221ebef7fd5Sriastradh #ifdef __NetBSD__
amdgpu_vm_map_gart(const bus_dma_segment_t * pages_addr,uint64_t addr)1222ebef7fd5Sriastradh uint64_t amdgpu_vm_map_gart(const bus_dma_segment_t *pages_addr, uint64_t addr)
1223ebef7fd5Sriastradh #else
122441ec0267Sriastradh uint64_t amdgpu_vm_map_gart(const dma_addr_t *pages_addr, uint64_t addr)
1225ebef7fd5Sriastradh #endif
1226efa246c0Sriastradh {
1227efa246c0Sriastradh 	uint64_t result;
1228efa246c0Sriastradh 
1229efa246c0Sriastradh 	/* page table offset */
1230ebef7fd5Sriastradh #ifdef __NetBSD__
1231ebef7fd5Sriastradh 	KASSERT(pages_addr[addr >> PAGE_SHIFT].ds_len == PAGE_SIZE);
1232ebef7fd5Sriastradh 	result = pages_addr[addr >> PAGE_SHIFT].ds_addr;
1233ebef7fd5Sriastradh #else
123441ec0267Sriastradh 	result = pages_addr[addr >> PAGE_SHIFT];
1235ebef7fd5Sriastradh #endif
1236efa246c0Sriastradh 
1237efa246c0Sriastradh 	/* in case cpu page size != gpu page size*/
1238efa246c0Sriastradh 	result |= addr & (~PAGE_MASK);
1239efa246c0Sriastradh 
124041ec0267Sriastradh 	result &= 0xFFFFFFFFFFFFF000ULL;
124141ec0267Sriastradh 
1242efa246c0Sriastradh 	return result;
1243efa246c0Sriastradh }
1244efa246c0Sriastradh 
1245efa246c0Sriastradh /**
124641ec0267Sriastradh  * amdgpu_vm_update_pde - update a single level in the hierarchy
1247efa246c0Sriastradh  *
124841ec0267Sriastradh  * @params: parameters for the update
1249efa246c0Sriastradh  * @vm: requested vm
125041ec0267Sriastradh  * @entry: entry to update
1251efa246c0Sriastradh  *
125241ec0267Sriastradh  * Makes sure the requested entry in parent is up to date.
1253efa246c0Sriastradh  */
amdgpu_vm_update_pde(struct amdgpu_vm_update_params * params,struct amdgpu_vm * vm,struct amdgpu_vm_pt * entry)125441ec0267Sriastradh static int amdgpu_vm_update_pde(struct amdgpu_vm_update_params *params,
125541ec0267Sriastradh 				struct amdgpu_vm *vm,
125641ec0267Sriastradh 				struct amdgpu_vm_pt *entry)
1257efa246c0Sriastradh {
125841ec0267Sriastradh 	struct amdgpu_vm_pt *parent = amdgpu_vm_pt_parent(entry);
125941ec0267Sriastradh 	struct amdgpu_bo *bo = parent->base.bo, *pbo;
126041ec0267Sriastradh 	uint64_t pde, pt, flags;
126141ec0267Sriastradh 	unsigned level;
1262efa246c0Sriastradh 
126341ec0267Sriastradh 	for (level = 0, pbo = bo->parent; pbo; ++level)
126441ec0267Sriastradh 		pbo = pbo->parent;
1265efa246c0Sriastradh 
126641ec0267Sriastradh 	level += params->adev->vm_manager.root_level;
126741ec0267Sriastradh 	amdgpu_gmc_get_pde_for_bo(entry->base.bo, level, &pt, &flags);
126841ec0267Sriastradh 	pde = (entry - parent->entries) * 8;
126941ec0267Sriastradh 	return vm->update_funcs->update(params, bo, pde, pt, 1, 0, flags);
1270efa246c0Sriastradh }
1271efa246c0Sriastradh 
1272efa246c0Sriastradh /**
127341ec0267Sriastradh  * amdgpu_vm_invalidate_pds - mark all PDs as invalid
1274efa246c0Sriastradh  *
1275efa246c0Sriastradh  * @adev: amdgpu_device pointer
127641ec0267Sriastradh  * @vm: related vm
1277efa246c0Sriastradh  *
127841ec0267Sriastradh  * Mark all PD level as invalid after an error.
1279efa246c0Sriastradh  */
amdgpu_vm_invalidate_pds(struct amdgpu_device * adev,struct amdgpu_vm * vm)128041ec0267Sriastradh static void amdgpu_vm_invalidate_pds(struct amdgpu_device *adev,
128141ec0267Sriastradh 				     struct amdgpu_vm *vm)
128241ec0267Sriastradh {
128341ec0267Sriastradh 	struct amdgpu_vm_pt_cursor cursor;
128441ec0267Sriastradh 	struct amdgpu_vm_pt *entry;
128541ec0267Sriastradh 
128641ec0267Sriastradh 	for_each_amdgpu_vm_pt_dfs_safe(adev, vm, NULL, cursor, entry)
128741ec0267Sriastradh 		if (entry->base.bo && !entry->base.moved)
128841ec0267Sriastradh 			amdgpu_vm_bo_relocated(&entry->base);
128941ec0267Sriastradh }
129041ec0267Sriastradh 
129141ec0267Sriastradh /**
129241ec0267Sriastradh  * amdgpu_vm_update_pdes - make sure that all directories are valid
129341ec0267Sriastradh  *
129441ec0267Sriastradh  * @adev: amdgpu_device pointer
129541ec0267Sriastradh  * @vm: requested vm
129641ec0267Sriastradh  * @direct: submit directly to the paging queue
129741ec0267Sriastradh  *
129841ec0267Sriastradh  * Makes sure all directories are up to date.
129941ec0267Sriastradh  *
130041ec0267Sriastradh  * Returns:
130141ec0267Sriastradh  * 0 for success, error for failure.
130241ec0267Sriastradh  */
amdgpu_vm_update_pdes(struct amdgpu_device * adev,struct amdgpu_vm * vm,bool direct)130341ec0267Sriastradh int amdgpu_vm_update_pdes(struct amdgpu_device *adev,
130441ec0267Sriastradh 			  struct amdgpu_vm *vm, bool direct)
130541ec0267Sriastradh {
130641ec0267Sriastradh 	struct amdgpu_vm_update_params params;
130741ec0267Sriastradh 	int r;
130841ec0267Sriastradh 
130941ec0267Sriastradh 	if (list_empty(&vm->relocated))
131041ec0267Sriastradh 		return 0;
131141ec0267Sriastradh 
131241ec0267Sriastradh 	memset(&params, 0, sizeof(params));
131341ec0267Sriastradh 	params.adev = adev;
131441ec0267Sriastradh 	params.vm = vm;
131541ec0267Sriastradh 	params.direct = direct;
131641ec0267Sriastradh 
131741ec0267Sriastradh 	r = vm->update_funcs->prepare(&params, AMDGPU_FENCE_OWNER_VM, NULL);
131841ec0267Sriastradh 	if (r)
131941ec0267Sriastradh 		return r;
132041ec0267Sriastradh 
132141ec0267Sriastradh 	while (!list_empty(&vm->relocated)) {
132241ec0267Sriastradh 		struct amdgpu_vm_pt *entry;
132341ec0267Sriastradh 
132441ec0267Sriastradh 		entry = list_first_entry(&vm->relocated, struct amdgpu_vm_pt,
132541ec0267Sriastradh 					 base.vm_status);
132641ec0267Sriastradh 		amdgpu_vm_bo_idle(&entry->base);
132741ec0267Sriastradh 
132841ec0267Sriastradh 		r = amdgpu_vm_update_pde(&params, vm, entry);
132941ec0267Sriastradh 		if (r)
133041ec0267Sriastradh 			goto error;
133141ec0267Sriastradh 	}
133241ec0267Sriastradh 
133341ec0267Sriastradh 	r = vm->update_funcs->commit(&params, &vm->last_update);
133441ec0267Sriastradh 	if (r)
133541ec0267Sriastradh 		goto error;
133641ec0267Sriastradh 	return 0;
133741ec0267Sriastradh 
133841ec0267Sriastradh error:
133941ec0267Sriastradh 	amdgpu_vm_invalidate_pds(adev, vm);
134041ec0267Sriastradh 	return r;
134141ec0267Sriastradh }
134241ec0267Sriastradh 
134341ec0267Sriastradh /*
134441ec0267Sriastradh  * amdgpu_vm_update_flags - figure out flags for PTE updates
134541ec0267Sriastradh  *
134641ec0267Sriastradh  * Make sure to set the right flags for the PTEs at the desired level.
134741ec0267Sriastradh  */
amdgpu_vm_update_flags(struct amdgpu_vm_update_params * params,struct amdgpu_bo * bo,unsigned level,uint64_t pe,uint64_t addr,unsigned count,uint32_t incr,uint64_t flags)134841ec0267Sriastradh static void amdgpu_vm_update_flags(struct amdgpu_vm_update_params *params,
134941ec0267Sriastradh 				   struct amdgpu_bo *bo, unsigned level,
135041ec0267Sriastradh 				   uint64_t pe, uint64_t addr,
135141ec0267Sriastradh 				   unsigned count, uint32_t incr,
135241ec0267Sriastradh 				   uint64_t flags)
135341ec0267Sriastradh 
135441ec0267Sriastradh {
135541ec0267Sriastradh 	if (level != AMDGPU_VM_PTB) {
135641ec0267Sriastradh 		flags |= AMDGPU_PDE_PTE;
135741ec0267Sriastradh 		amdgpu_gmc_get_vm_pde(params->adev, level, &addr, &flags);
135841ec0267Sriastradh 
135941ec0267Sriastradh 	} else if (params->adev->asic_type >= CHIP_VEGA10 &&
136041ec0267Sriastradh 		   !(flags & AMDGPU_PTE_VALID) &&
136141ec0267Sriastradh 		   !(flags & AMDGPU_PTE_PRT)) {
136241ec0267Sriastradh 
136341ec0267Sriastradh 		/* Workaround for fault priority problem on GMC9 */
136441ec0267Sriastradh 		flags |= AMDGPU_PTE_EXECUTABLE;
136541ec0267Sriastradh 	}
136641ec0267Sriastradh 
136741ec0267Sriastradh 	params->vm->update_funcs->update(params, bo, pe, addr, count, incr,
136841ec0267Sriastradh 					 flags);
136941ec0267Sriastradh }
137041ec0267Sriastradh 
137141ec0267Sriastradh /**
137241ec0267Sriastradh  * amdgpu_vm_fragment - get fragment for PTEs
137341ec0267Sriastradh  *
137441ec0267Sriastradh  * @params: see amdgpu_vm_update_params definition
137541ec0267Sriastradh  * @start: first PTE to handle
137641ec0267Sriastradh  * @end: last PTE to handle
137741ec0267Sriastradh  * @flags: hw mapping flags
137841ec0267Sriastradh  * @frag: resulting fragment size
137941ec0267Sriastradh  * @frag_end: end of this fragment
138041ec0267Sriastradh  *
138141ec0267Sriastradh  * Returns the first possible fragment for the start and end address.
138241ec0267Sriastradh  */
amdgpu_vm_fragment(struct amdgpu_vm_update_params * params,uint64_t start,uint64_t end,uint64_t flags,unsigned int * frag,uint64_t * frag_end)138341ec0267Sriastradh static void amdgpu_vm_fragment(struct amdgpu_vm_update_params *params,
138441ec0267Sriastradh 			       uint64_t start, uint64_t end, uint64_t flags,
138541ec0267Sriastradh 			       unsigned int *frag, uint64_t *frag_end)
1386efa246c0Sriastradh {
1387efa246c0Sriastradh 	/**
1388efa246c0Sriastradh 	 * The MC L1 TLB supports variable sized pages, based on a fragment
1389efa246c0Sriastradh 	 * field in the PTE. When this field is set to a non-zero value, page
1390efa246c0Sriastradh 	 * granularity is increased from 4KB to (1 << (12 + frag)). The PTE
1391efa246c0Sriastradh 	 * flags are considered valid for all PTEs within the fragment range
1392efa246c0Sriastradh 	 * and corresponding mappings are assumed to be physically contiguous.
1393efa246c0Sriastradh 	 *
1394efa246c0Sriastradh 	 * The L1 TLB can store a single PTE for the whole fragment,
1395efa246c0Sriastradh 	 * significantly increasing the space available for translation
1396efa246c0Sriastradh 	 * caching. This leads to large improvements in throughput when the
1397efa246c0Sriastradh 	 * TLB is under pressure.
1398efa246c0Sriastradh 	 *
1399efa246c0Sriastradh 	 * The L2 TLB distributes small and large fragments into two
1400efa246c0Sriastradh 	 * asymmetric partitions. The large fragment cache is significantly
1401efa246c0Sriastradh 	 * larger. Thus, we try to use large fragments wherever possible.
1402efa246c0Sriastradh 	 * Userspace can support this by aligning virtual base address and
1403efa246c0Sriastradh 	 * allocation size to the fragment size.
140441ec0267Sriastradh 	 *
140541ec0267Sriastradh 	 * Starting with Vega10 the fragment size only controls the L1. The L2
140641ec0267Sriastradh 	 * is now directly feed with small/huge/giant pages from the walker.
1407efa246c0Sriastradh 	 */
140841ec0267Sriastradh 	unsigned max_frag;
1409efa246c0Sriastradh 
141041ec0267Sriastradh 	if (params->adev->asic_type < CHIP_VEGA10)
141141ec0267Sriastradh 		max_frag = params->adev->vm_manager.fragment_size;
141241ec0267Sriastradh 	else
141341ec0267Sriastradh 		max_frag = 31;
1414efa246c0Sriastradh 
1415efa246c0Sriastradh 	/* system pages are non continuously */
141641ec0267Sriastradh 	if (params->pages_addr) {
141741ec0267Sriastradh 		*frag = 0;
141841ec0267Sriastradh 		*frag_end = end;
1419efa246c0Sriastradh 		return;
1420efa246c0Sriastradh 	}
1421efa246c0Sriastradh 
142241ec0267Sriastradh 	/* This intentionally wraps around if no bit is set */
142341ec0267Sriastradh 	*frag = min((unsigned)ffs(start) - 1, (unsigned)fls64(end - start) - 1);
142441ec0267Sriastradh 	if (*frag >= max_frag) {
142541ec0267Sriastradh 		*frag = max_frag;
142641ec0267Sriastradh 		*frag_end = end & ~((1ULL << max_frag) - 1);
142741ec0267Sriastradh 	} else {
142841ec0267Sriastradh 		*frag_end = start + (1 << *frag);
1429efa246c0Sriastradh 	}
1430efa246c0Sriastradh }
1431efa246c0Sriastradh 
1432efa246c0Sriastradh /**
1433efa246c0Sriastradh  * amdgpu_vm_update_ptes - make sure that page tables are valid
1434efa246c0Sriastradh  *
143541ec0267Sriastradh  * @params: see amdgpu_vm_update_params definition
1436efa246c0Sriastradh  * @start: start of GPU address range
1437efa246c0Sriastradh  * @end: end of GPU address range
143841ec0267Sriastradh  * @dst: destination address to map to, the next dst inside the function
1439efa246c0Sriastradh  * @flags: mapping flags
1440efa246c0Sriastradh  *
144141ec0267Sriastradh  * Update the page tables in the range @start - @end.
1442efa246c0Sriastradh  *
144341ec0267Sriastradh  * Returns:
144441ec0267Sriastradh  * 0 for success, -EINVAL for failure.
1445efa246c0Sriastradh  */
amdgpu_vm_update_ptes(struct amdgpu_vm_update_params * params,uint64_t start,uint64_t end,uint64_t dst,uint64_t flags)144641ec0267Sriastradh static int amdgpu_vm_update_ptes(struct amdgpu_vm_update_params *params,
1447efa246c0Sriastradh 				 uint64_t start, uint64_t end,
144841ec0267Sriastradh 				 uint64_t dst, uint64_t flags)
1449efa246c0Sriastradh {
145041ec0267Sriastradh 	struct amdgpu_device *adev = params->adev;
145141ec0267Sriastradh 	struct amdgpu_vm_pt_cursor cursor;
145241ec0267Sriastradh 	uint64_t frag_start = start, frag_end;
145341ec0267Sriastradh 	unsigned int frag;
1454efa246c0Sriastradh 	int r;
1455efa246c0Sriastradh 
145641ec0267Sriastradh 	/* figure out the initial fragment */
145741ec0267Sriastradh 	amdgpu_vm_fragment(params, frag_start, end, flags, &frag, &frag_end);
145841ec0267Sriastradh 
145941ec0267Sriastradh 	/* walk over the address space and update the PTs */
146041ec0267Sriastradh 	amdgpu_vm_pt_start(adev, params->vm, start, &cursor);
146141ec0267Sriastradh 	while (cursor.pfn < end) {
146241ec0267Sriastradh 		unsigned shift, parent_shift, mask;
146341ec0267Sriastradh 		uint64_t incr, entry_end, pe_start;
146441ec0267Sriastradh 		struct amdgpu_bo *pt;
146541ec0267Sriastradh 
146641ec0267Sriastradh 		/* make sure that the page tables covering the address range are
146741ec0267Sriastradh 		 * actually allocated
146841ec0267Sriastradh 		 */
146941ec0267Sriastradh 		r = amdgpu_vm_alloc_pts(params->adev, params->vm, &cursor,
147041ec0267Sriastradh 					params->direct);
1471efa246c0Sriastradh 		if (r)
1472efa246c0Sriastradh 			return r;
1473efa246c0Sriastradh 
147441ec0267Sriastradh 		pt = cursor.entry->base.bo;
1475efa246c0Sriastradh 
147641ec0267Sriastradh 		/* The root level can't be a huge page */
147741ec0267Sriastradh 		if (cursor.level == adev->vm_manager.root_level) {
147841ec0267Sriastradh 			if (!amdgpu_vm_pt_descendant(adev, &cursor))
147941ec0267Sriastradh 				return -ENOENT;
148041ec0267Sriastradh 			continue;
1481efa246c0Sriastradh 		}
1482efa246c0Sriastradh 
148341ec0267Sriastradh 		shift = amdgpu_vm_level_shift(adev, cursor.level);
148441ec0267Sriastradh 		parent_shift = amdgpu_vm_level_shift(adev, cursor.level - 1);
148541ec0267Sriastradh 		if (adev->asic_type < CHIP_VEGA10 &&
148641ec0267Sriastradh 		    (flags & AMDGPU_PTE_VALID)) {
148741ec0267Sriastradh 			/* No huge page support before GMC v9 */
148841ec0267Sriastradh 			if (cursor.level != AMDGPU_VM_PTB) {
148941ec0267Sriastradh 				if (!amdgpu_vm_pt_descendant(adev, &cursor))
149041ec0267Sriastradh 					return -ENOENT;
149141ec0267Sriastradh 				continue;
149241ec0267Sriastradh 			}
149341ec0267Sriastradh 		} else if (frag < shift) {
149441ec0267Sriastradh 			/* We can't use this level when the fragment size is
149541ec0267Sriastradh 			 * smaller than the address shift. Go to the next
149641ec0267Sriastradh 			 * child entry and try again.
149741ec0267Sriastradh 			 */
149841ec0267Sriastradh 			if (!amdgpu_vm_pt_descendant(adev, &cursor))
149941ec0267Sriastradh 				return -ENOENT;
150041ec0267Sriastradh 			continue;
150141ec0267Sriastradh 		} else if (frag >= parent_shift &&
150241ec0267Sriastradh 			   cursor.level - 1 != adev->vm_manager.root_level) {
150341ec0267Sriastradh 			/* If the fragment size is even larger than the parent
150441ec0267Sriastradh 			 * shift we should go up one level and check it again
150541ec0267Sriastradh 			 * unless one level up is the root level.
150641ec0267Sriastradh 			 */
150741ec0267Sriastradh 			if (!amdgpu_vm_pt_ancestor(&cursor))
150841ec0267Sriastradh 				return -ENOENT;
150941ec0267Sriastradh 			continue;
1510efa246c0Sriastradh 		}
1511efa246c0Sriastradh 
151241ec0267Sriastradh 		/* Looks good so far, calculate parameters for the update */
151341ec0267Sriastradh 		incr = (uint64_t)AMDGPU_GPU_PAGE_SIZE << shift;
151441ec0267Sriastradh 		mask = amdgpu_vm_entries_mask(adev, cursor.level);
151541ec0267Sriastradh 		pe_start = ((cursor.pfn >> shift) & mask) * 8;
151641ec0267Sriastradh 		entry_end = (uint64_t)(mask + 1) << shift;
151741ec0267Sriastradh 		entry_end += cursor.pfn & ~(entry_end - 1);
151841ec0267Sriastradh 		entry_end = min(entry_end, end);
151941ec0267Sriastradh 
152041ec0267Sriastradh 		do {
152141ec0267Sriastradh 			uint64_t upd_end = min(entry_end, frag_end);
152241ec0267Sriastradh 			unsigned nptes = (upd_end - frag_start) >> shift;
152341ec0267Sriastradh 
152441ec0267Sriastradh 			amdgpu_vm_update_flags(params, pt, cursor.level,
152541ec0267Sriastradh 					       pe_start, dst, nptes, incr,
152641ec0267Sriastradh 					       flags | AMDGPU_PTE_FRAG(frag));
152741ec0267Sriastradh 
152841ec0267Sriastradh 			pe_start += nptes * 8;
152941ec0267Sriastradh 			dst += (uint64_t)nptes * AMDGPU_GPU_PAGE_SIZE << shift;
153041ec0267Sriastradh 
153141ec0267Sriastradh 			frag_start = upd_end;
153241ec0267Sriastradh 			if (frag_start >= frag_end) {
153341ec0267Sriastradh 				/* figure out the next fragment */
153441ec0267Sriastradh 				amdgpu_vm_fragment(params, frag_start, end,
153541ec0267Sriastradh 						   flags, &frag, &frag_end);
153641ec0267Sriastradh 				if (frag < shift)
153741ec0267Sriastradh 					break;
153841ec0267Sriastradh 			}
153941ec0267Sriastradh 		} while (frag_start < entry_end);
154041ec0267Sriastradh 
154141ec0267Sriastradh 		if (amdgpu_vm_pt_descendant(adev, &cursor)) {
154241ec0267Sriastradh 			/* Free all child entries.
154341ec0267Sriastradh 			 * Update the tables with the flags and addresses and free up subsequent
154441ec0267Sriastradh 			 * tables in the case of huge pages or freed up areas.
154541ec0267Sriastradh 			 * This is the maximum you can free, because all other page tables are not
154641ec0267Sriastradh 			 * completely covered by the range and so potentially still in use.
154741ec0267Sriastradh 			 */
154841ec0267Sriastradh 			while (cursor.pfn < frag_start) {
154941ec0267Sriastradh 				amdgpu_vm_free_pts(adev, params->vm, &cursor);
155041ec0267Sriastradh 				amdgpu_vm_pt_next(adev, &cursor);
1551efa246c0Sriastradh 			}
1552efa246c0Sriastradh 
155341ec0267Sriastradh 		} else if (frag >= shift) {
155441ec0267Sriastradh 			/* or just move on to the next on the same level. */
155541ec0267Sriastradh 			amdgpu_vm_pt_next(adev, &cursor);
155641ec0267Sriastradh 		}
1557efa246c0Sriastradh 	}
1558efa246c0Sriastradh 
1559efa246c0Sriastradh 	return 0;
1560efa246c0Sriastradh }
1561efa246c0Sriastradh 
1562efa246c0Sriastradh /**
1563efa246c0Sriastradh  * amdgpu_vm_bo_update_mapping - update a mapping in the vm page table
1564efa246c0Sriastradh  *
1565efa246c0Sriastradh  * @adev: amdgpu_device pointer
1566efa246c0Sriastradh  * @vm: requested vm
156741ec0267Sriastradh  * @direct: direct submission in a page fault
156841ec0267Sriastradh  * @exclusive: fence we need to sync to
156941ec0267Sriastradh  * @start: start of mapped range
157041ec0267Sriastradh  * @last: last mapped entry
157141ec0267Sriastradh  * @flags: flags for the entries
1572efa246c0Sriastradh  * @addr: addr to set the area to
157341ec0267Sriastradh  * @pages_addr: DMA addresses to use for mapping
1574efa246c0Sriastradh  * @fence: optional resulting fence
1575efa246c0Sriastradh  *
157641ec0267Sriastradh  * Fill in the page table entries between @start and @last.
1577efa246c0Sriastradh  *
157841ec0267Sriastradh  * Returns:
157941ec0267Sriastradh  * 0 for success, -EINVAL for failure.
1580efa246c0Sriastradh  */
amdgpu_vm_bo_update_mapping(struct amdgpu_device * adev,struct amdgpu_vm * vm,bool direct,struct dma_fence * exclusive,uint64_t start,uint64_t last,uint64_t flags,uint64_t addr,bus_dma_segment_t * pages_addr,struct dma_fence ** fence)1581efa246c0Sriastradh static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
158241ec0267Sriastradh 				       struct amdgpu_vm *vm, bool direct,
158341ec0267Sriastradh 				       struct dma_fence *exclusive,
158441ec0267Sriastradh 				       uint64_t start, uint64_t last,
158541ec0267Sriastradh 				       uint64_t flags, uint64_t addr,
1586ebef7fd5Sriastradh #ifdef __NetBSD__
1587ebef7fd5Sriastradh 				       bus_dma_segment_t *pages_addr,
1588ebef7fd5Sriastradh #else
158941ec0267Sriastradh 				       dma_addr_t *pages_addr,
1590ebef7fd5Sriastradh #endif
159141ec0267Sriastradh 				       struct dma_fence **fence)
159241ec0267Sriastradh {
159341ec0267Sriastradh 	struct amdgpu_vm_update_params params;
159441ec0267Sriastradh 	void *owner = AMDGPU_FENCE_OWNER_VM;
159541ec0267Sriastradh 	int r;
159641ec0267Sriastradh 
159741ec0267Sriastradh 	memset(&params, 0, sizeof(params));
159841ec0267Sriastradh 	params.adev = adev;
159941ec0267Sriastradh 	params.vm = vm;
160041ec0267Sriastradh 	params.direct = direct;
160141ec0267Sriastradh 	params.pages_addr = pages_addr;
160241ec0267Sriastradh 
160341ec0267Sriastradh 	/* sync to everything except eviction fences on unmapping */
160441ec0267Sriastradh 	if (!(flags & AMDGPU_PTE_VALID))
160541ec0267Sriastradh 		owner = AMDGPU_FENCE_OWNER_KFD;
160641ec0267Sriastradh 
160741ec0267Sriastradh 	amdgpu_vm_eviction_lock(vm);
160841ec0267Sriastradh 	if (vm->evicting) {
160941ec0267Sriastradh 		r = -EBUSY;
161041ec0267Sriastradh 		goto error_unlock;
161141ec0267Sriastradh 	}
161241ec0267Sriastradh 
161341ec0267Sriastradh 	r = vm->update_funcs->prepare(&params, owner, exclusive);
161441ec0267Sriastradh 	if (r)
161541ec0267Sriastradh 		goto error_unlock;
161641ec0267Sriastradh 
161741ec0267Sriastradh 	r = amdgpu_vm_update_ptes(&params, start, last + 1, addr, flags);
161841ec0267Sriastradh 	if (r)
161941ec0267Sriastradh 		goto error_unlock;
162041ec0267Sriastradh 
162141ec0267Sriastradh 	r = vm->update_funcs->commit(&params, fence);
162241ec0267Sriastradh 
162341ec0267Sriastradh error_unlock:
162441ec0267Sriastradh 	amdgpu_vm_eviction_unlock(vm);
162541ec0267Sriastradh 	return r;
162641ec0267Sriastradh }
162741ec0267Sriastradh 
162841ec0267Sriastradh /**
162941ec0267Sriastradh  * amdgpu_vm_bo_split_mapping - split a mapping into smaller chunks
163041ec0267Sriastradh  *
163141ec0267Sriastradh  * @adev: amdgpu_device pointer
163241ec0267Sriastradh  * @exclusive: fence we need to sync to
163341ec0267Sriastradh  * @pages_addr: DMA addresses to use for mapping
163441ec0267Sriastradh  * @vm: requested vm
163541ec0267Sriastradh  * @mapping: mapped range and flags to use for the update
163641ec0267Sriastradh  * @flags: HW flags for the mapping
163741ec0267Sriastradh  * @bo_adev: amdgpu_device pointer that bo actually been allocated
163841ec0267Sriastradh  * @nodes: array of drm_mm_nodes with the MC addresses
163941ec0267Sriastradh  * @fence: optional resulting fence
164041ec0267Sriastradh  *
164141ec0267Sriastradh  * Split the mapping into smaller chunks so that each update fits
164241ec0267Sriastradh  * into a SDMA IB.
164341ec0267Sriastradh  *
164441ec0267Sriastradh  * Returns:
164541ec0267Sriastradh  * 0 for success, -EINVAL for failure.
164641ec0267Sriastradh  */
amdgpu_vm_bo_split_mapping(struct amdgpu_device * adev,struct dma_fence * exclusive,bus_dma_segment_t * pages_addr,struct amdgpu_vm * vm,struct amdgpu_bo_va_mapping * mapping,uint64_t flags,struct amdgpu_device * bo_adev,struct drm_mm_node * nodes,struct dma_fence ** fence)164741ec0267Sriastradh static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev,
164841ec0267Sriastradh 				      struct dma_fence *exclusive,
1649ebef7fd5Sriastradh #ifdef __NetBSD__
1650ebef7fd5Sriastradh 				      bus_dma_segment_t *pages_addr,
1651ebef7fd5Sriastradh #else
165241ec0267Sriastradh 				      dma_addr_t *pages_addr,
1653ebef7fd5Sriastradh #endif
1654efa246c0Sriastradh 				      struct amdgpu_vm *vm,
1655efa246c0Sriastradh 				      struct amdgpu_bo_va_mapping *mapping,
165641ec0267Sriastradh 				      uint64_t flags,
165741ec0267Sriastradh 				      struct amdgpu_device *bo_adev,
165841ec0267Sriastradh 				      struct drm_mm_node *nodes,
165941ec0267Sriastradh 				      struct dma_fence **fence)
1660efa246c0Sriastradh {
166141ec0267Sriastradh 	unsigned min_linear_pages = 1 << adev->vm_manager.fragment_size;
166241ec0267Sriastradh 	uint64_t pfn, start = mapping->start;
1663efa246c0Sriastradh 	int r;
1664efa246c0Sriastradh 
1665efa246c0Sriastradh 	/* normally,bo_va->flags only contians READABLE and WIRTEABLE bit go here
1666efa246c0Sriastradh 	 * but in case of something, we filter the flags in first place
1667efa246c0Sriastradh 	 */
1668efa246c0Sriastradh 	if (!(mapping->flags & AMDGPU_PTE_READABLE))
1669efa246c0Sriastradh 		flags &= ~AMDGPU_PTE_READABLE;
1670efa246c0Sriastradh 	if (!(mapping->flags & AMDGPU_PTE_WRITEABLE))
1671efa246c0Sriastradh 		flags &= ~AMDGPU_PTE_WRITEABLE;
1672efa246c0Sriastradh 
167341ec0267Sriastradh 	/* Apply ASIC specific mapping flags */
167441ec0267Sriastradh 	amdgpu_gmc_get_vm_pte(adev, mapping, &flags);
167541ec0267Sriastradh 
1676efa246c0Sriastradh 	trace_amdgpu_vm_bo_update(mapping);
1677efa246c0Sriastradh 
167841ec0267Sriastradh 	pfn = mapping->offset >> PAGE_SHIFT;
167941ec0267Sriastradh 	if (nodes) {
168041ec0267Sriastradh 		while (pfn >= nodes->size) {
168141ec0267Sriastradh 			pfn -= nodes->size;
168241ec0267Sriastradh 			++nodes;
168341ec0267Sriastradh 		}
168441ec0267Sriastradh 	}
1685efa246c0Sriastradh 
168641ec0267Sriastradh 	do {
1687ebef7fd5Sriastradh #ifdef __NetBSD__
1688ebef7fd5Sriastradh 		bus_dma_segment_t *dma_addr = NULL;
1689ebef7fd5Sriastradh #else
169041ec0267Sriastradh 		dma_addr_t *dma_addr = NULL;
1691ebef7fd5Sriastradh #endif
169241ec0267Sriastradh 		uint64_t max_entries;
169341ec0267Sriastradh 		uint64_t addr, last;
1694efa246c0Sriastradh 
169541ec0267Sriastradh 		if (nodes) {
169641ec0267Sriastradh 			addr = nodes->start << PAGE_SHIFT;
169741ec0267Sriastradh 			max_entries = (nodes->size - pfn) *
169841ec0267Sriastradh 				AMDGPU_GPU_PAGES_IN_CPU_PAGE;
1699efa246c0Sriastradh 		} else {
170041ec0267Sriastradh 			addr = 0;
170141ec0267Sriastradh 			max_entries = S64_MAX;
1702efa246c0Sriastradh 		}
1703efa246c0Sriastradh 
170441ec0267Sriastradh 		if (pages_addr) {
170541ec0267Sriastradh 			uint64_t count;
1706efa246c0Sriastradh 
170741ec0267Sriastradh 			for (count = 1;
170841ec0267Sriastradh 			     count < max_entries / AMDGPU_GPU_PAGES_IN_CPU_PAGE;
170941ec0267Sriastradh 			     ++count) {
171041ec0267Sriastradh 				uint64_t idx = pfn + count;
1711efa246c0Sriastradh 
1712ebef7fd5Sriastradh #ifdef __NetBSD__
1713ebef7fd5Sriastradh 				KASSERT(pages_addr[idx].ds_len == PAGE_SIZE);
1714ebef7fd5Sriastradh 				if (pages_addr[idx].ds_addr !=
1715ebef7fd5Sriastradh 				    pages_addr[idx - 1].ds_addr + PAGE_SIZE)
1716ebef7fd5Sriastradh 					break;
1717ebef7fd5Sriastradh #else
171841ec0267Sriastradh 				if (pages_addr[idx] !=
171941ec0267Sriastradh 				    (pages_addr[idx - 1] + PAGE_SIZE))
172041ec0267Sriastradh 					break;
1721ebef7fd5Sriastradh #endif
1722efa246c0Sriastradh 			}
1723efa246c0Sriastradh 
172441ec0267Sriastradh 			if (count < min_linear_pages) {
172541ec0267Sriastradh 				addr = pfn << PAGE_SHIFT;
172641ec0267Sriastradh 				dma_addr = pages_addr;
172741ec0267Sriastradh 			} else {
1728ebef7fd5Sriastradh #ifdef __NetBSD__
1729ebef7fd5Sriastradh 				KASSERT(pages_addr[pfn].ds_len == PAGE_SIZE);
1730ebef7fd5Sriastradh 				addr = pages_addr[pfn].ds_addr;
1731ebef7fd5Sriastradh #else
173241ec0267Sriastradh 				addr = pages_addr[pfn];
1733ebef7fd5Sriastradh #endif
173441ec0267Sriastradh 				max_entries = count *
173541ec0267Sriastradh 					AMDGPU_GPU_PAGES_IN_CPU_PAGE;
1736efa246c0Sriastradh 			}
1737efa246c0Sriastradh 
173841ec0267Sriastradh 		} else if (flags & AMDGPU_PTE_VALID) {
173941ec0267Sriastradh 			addr += bo_adev->vm_manager.vram_base_offset;
174041ec0267Sriastradh 			addr += pfn << PAGE_SHIFT;
174141ec0267Sriastradh 		}
174241ec0267Sriastradh 
174341ec0267Sriastradh 		last = min((uint64_t)mapping->last, start + max_entries - 1);
174441ec0267Sriastradh 		r = amdgpu_vm_bo_update_mapping(adev, vm, false, exclusive,
174541ec0267Sriastradh 						start, last, flags, addr,
174641ec0267Sriastradh 						dma_addr, fence);
1747efa246c0Sriastradh 		if (r)
1748efa246c0Sriastradh 			return r;
174941ec0267Sriastradh 
175041ec0267Sriastradh 		pfn += (last - start + 1) / AMDGPU_GPU_PAGES_IN_CPU_PAGE;
175141ec0267Sriastradh 		if (nodes && nodes->size == pfn) {
175241ec0267Sriastradh 			pfn = 0;
175341ec0267Sriastradh 			++nodes;
175441ec0267Sriastradh 		}
175541ec0267Sriastradh 		start = last + 1;
175641ec0267Sriastradh 
175741ec0267Sriastradh 	} while (unlikely(start != mapping->last + 1));
175841ec0267Sriastradh 
175941ec0267Sriastradh 	return 0;
1760efa246c0Sriastradh }
1761efa246c0Sriastradh 
1762efa246c0Sriastradh /**
1763efa246c0Sriastradh  * amdgpu_vm_bo_update - update all BO mappings in the vm page table
1764efa246c0Sriastradh  *
1765efa246c0Sriastradh  * @adev: amdgpu_device pointer
1766efa246c0Sriastradh  * @bo_va: requested BO and VM object
176741ec0267Sriastradh  * @clear: if true clear the entries
1768efa246c0Sriastradh  *
1769efa246c0Sriastradh  * Fill in the page table entries for @bo_va.
1770efa246c0Sriastradh  *
177141ec0267Sriastradh  * Returns:
177241ec0267Sriastradh  * 0 for success, -EINVAL for failure.
1773efa246c0Sriastradh  */
amdgpu_vm_bo_update(struct amdgpu_device * adev,struct amdgpu_bo_va * bo_va,bool clear)177441ec0267Sriastradh int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va,
177541ec0267Sriastradh 			bool clear)
1776efa246c0Sriastradh {
177741ec0267Sriastradh 	struct amdgpu_bo *bo = bo_va->base.bo;
177841ec0267Sriastradh 	struct amdgpu_vm *vm = bo_va->base.vm;
1779efa246c0Sriastradh 	struct amdgpu_bo_va_mapping *mapping;
1780ebef7fd5Sriastradh #ifdef __NetBSD__
1781ebef7fd5Sriastradh 	bus_dma_segment_t *pages_addr = NULL;
1782ebef7fd5Sriastradh #else
178341ec0267Sriastradh 	dma_addr_t *pages_addr = NULL;
1784ebef7fd5Sriastradh #endif
178541ec0267Sriastradh 	struct ttm_mem_reg *mem;
178641ec0267Sriastradh 	struct drm_mm_node *nodes;
178741ec0267Sriastradh 	struct dma_fence *exclusive, **last_update;
178841ec0267Sriastradh 	uint64_t flags;
178941ec0267Sriastradh 	struct amdgpu_device *bo_adev = adev;
1790efa246c0Sriastradh 	int r;
1791efa246c0Sriastradh 
179241ec0267Sriastradh 	if (clear || !bo) {
179341ec0267Sriastradh 		mem = NULL;
179441ec0267Sriastradh 		nodes = NULL;
179541ec0267Sriastradh 		exclusive = NULL;
1796efa246c0Sriastradh 	} else {
179741ec0267Sriastradh 		struct ttm_dma_tt *ttm;
179841ec0267Sriastradh 
179941ec0267Sriastradh 		mem = &bo->tbo.mem;
180041ec0267Sriastradh 		nodes = mem->mm_node;
180141ec0267Sriastradh 		if (mem->mem_type == TTM_PL_TT) {
180241ec0267Sriastradh 			ttm = container_of(bo->tbo.ttm, struct ttm_dma_tt, ttm);
1803ebef7fd5Sriastradh #ifdef __NetBSD__
1804ebef7fd5Sriastradh 			pages_addr = ttm->dma_address->dm_segs;
1805ebef7fd5Sriastradh #else
180641ec0267Sriastradh 			pages_addr = ttm->dma_address;
1807ebef7fd5Sriastradh #endif
180841ec0267Sriastradh 		}
180941ec0267Sriastradh 		exclusive = bo->tbo.moving;
1810efa246c0Sriastradh 	}
1811efa246c0Sriastradh 
181241ec0267Sriastradh 	if (bo) {
181341ec0267Sriastradh 		flags = amdgpu_ttm_tt_pte_flags(adev, bo->tbo.ttm, mem);
181441ec0267Sriastradh 		bo_adev = amdgpu_ttm_adev(bo->tbo.bdev);
181541ec0267Sriastradh 	} else {
181641ec0267Sriastradh 		flags = 0x0;
181741ec0267Sriastradh 	}
1818efa246c0Sriastradh 
181941ec0267Sriastradh 	if (clear || (bo && bo->tbo.base.resv == vm->root.base.bo->tbo.base.resv))
182041ec0267Sriastradh 		last_update = &vm->last_update;
182141ec0267Sriastradh 	else
182241ec0267Sriastradh 		last_update = &bo_va->last_pt_update;
182341ec0267Sriastradh 
182441ec0267Sriastradh 	if (!clear && bo_va->base.moved) {
182541ec0267Sriastradh 		bo_va->base.moved = false;
1826efa246c0Sriastradh 		list_splice_init(&bo_va->valids, &bo_va->invalids);
182741ec0267Sriastradh 
182841ec0267Sriastradh 	} else if (bo_va->cleared != clear) {
182941ec0267Sriastradh 		list_splice_init(&bo_va->valids, &bo_va->invalids);
183041ec0267Sriastradh 	}
1831efa246c0Sriastradh 
1832efa246c0Sriastradh 	list_for_each_entry(mapping, &bo_va->invalids, list) {
183341ec0267Sriastradh 		r = amdgpu_vm_bo_split_mapping(adev, exclusive, pages_addr, vm,
183441ec0267Sriastradh 					       mapping, flags, bo_adev, nodes,
183541ec0267Sriastradh 					       last_update);
1836efa246c0Sriastradh 		if (r)
1837efa246c0Sriastradh 			return r;
1838efa246c0Sriastradh 	}
1839efa246c0Sriastradh 
184041ec0267Sriastradh 	/* If the BO is not in its preferred location add it back to
184141ec0267Sriastradh 	 * the evicted list so that it gets validated again on the
184241ec0267Sriastradh 	 * next command submission.
184341ec0267Sriastradh 	 */
184441ec0267Sriastradh 	if (bo && bo->tbo.base.resv == vm->root.base.bo->tbo.base.resv) {
184541ec0267Sriastradh 		uint32_t mem_type = bo->tbo.mem.mem_type;
184641ec0267Sriastradh 
184741ec0267Sriastradh 		if (!(bo->preferred_domains &
184841ec0267Sriastradh 		      amdgpu_mem_type_to_domain(mem_type)))
184941ec0267Sriastradh 			amdgpu_vm_bo_evicted(&bo_va->base);
185041ec0267Sriastradh 		else
185141ec0267Sriastradh 			amdgpu_vm_bo_idle(&bo_va->base);
185241ec0267Sriastradh 	} else {
185341ec0267Sriastradh 		amdgpu_vm_bo_done(&bo_va->base);
185441ec0267Sriastradh 	}
185541ec0267Sriastradh 
185641ec0267Sriastradh 	list_splice_init(&bo_va->invalids, &bo_va->valids);
185741ec0267Sriastradh 	bo_va->cleared = clear;
185841ec0267Sriastradh 
1859efa246c0Sriastradh 	if (trace_amdgpu_vm_bo_mapping_enabled()) {
1860efa246c0Sriastradh 		list_for_each_entry(mapping, &bo_va->valids, list)
1861efa246c0Sriastradh 			trace_amdgpu_vm_bo_mapping(mapping);
1862efa246c0Sriastradh 	}
1863efa246c0Sriastradh 
1864efa246c0Sriastradh 	return 0;
1865efa246c0Sriastradh }
1866efa246c0Sriastradh 
1867efa246c0Sriastradh /**
186841ec0267Sriastradh  * amdgpu_vm_update_prt_state - update the global PRT state
186941ec0267Sriastradh  *
187041ec0267Sriastradh  * @adev: amdgpu_device pointer
187141ec0267Sriastradh  */
amdgpu_vm_update_prt_state(struct amdgpu_device * adev)187241ec0267Sriastradh static void amdgpu_vm_update_prt_state(struct amdgpu_device *adev)
187341ec0267Sriastradh {
187441ec0267Sriastradh 	unsigned long flags;
187541ec0267Sriastradh 	bool enable;
187641ec0267Sriastradh 
187741ec0267Sriastradh 	spin_lock_irqsave(&adev->vm_manager.prt_lock, flags);
187841ec0267Sriastradh 	enable = !!atomic_read(&adev->vm_manager.num_prt_users);
187941ec0267Sriastradh 	adev->gmc.gmc_funcs->set_prt(adev, enable);
188041ec0267Sriastradh 	spin_unlock_irqrestore(&adev->vm_manager.prt_lock, flags);
188141ec0267Sriastradh }
188241ec0267Sriastradh 
188341ec0267Sriastradh /**
188441ec0267Sriastradh  * amdgpu_vm_prt_get - add a PRT user
188541ec0267Sriastradh  *
188641ec0267Sriastradh  * @adev: amdgpu_device pointer
188741ec0267Sriastradh  */
amdgpu_vm_prt_get(struct amdgpu_device * adev)188841ec0267Sriastradh static void amdgpu_vm_prt_get(struct amdgpu_device *adev)
188941ec0267Sriastradh {
189041ec0267Sriastradh 	if (!adev->gmc.gmc_funcs->set_prt)
189141ec0267Sriastradh 		return;
189241ec0267Sriastradh 
189341ec0267Sriastradh 	if (atomic_inc_return(&adev->vm_manager.num_prt_users) == 1)
189441ec0267Sriastradh 		amdgpu_vm_update_prt_state(adev);
189541ec0267Sriastradh }
189641ec0267Sriastradh 
189741ec0267Sriastradh /**
189841ec0267Sriastradh  * amdgpu_vm_prt_put - drop a PRT user
189941ec0267Sriastradh  *
190041ec0267Sriastradh  * @adev: amdgpu_device pointer
190141ec0267Sriastradh  */
amdgpu_vm_prt_put(struct amdgpu_device * adev)190241ec0267Sriastradh static void amdgpu_vm_prt_put(struct amdgpu_device *adev)
190341ec0267Sriastradh {
190441ec0267Sriastradh 	if (atomic_dec_return(&adev->vm_manager.num_prt_users) == 0)
190541ec0267Sriastradh 		amdgpu_vm_update_prt_state(adev);
190641ec0267Sriastradh }
190741ec0267Sriastradh 
190841ec0267Sriastradh /**
190941ec0267Sriastradh  * amdgpu_vm_prt_cb - callback for updating the PRT status
191041ec0267Sriastradh  *
191141ec0267Sriastradh  * @fence: fence for the callback
191241ec0267Sriastradh  * @_cb: the callback function
191341ec0267Sriastradh  */
amdgpu_vm_prt_cb(struct dma_fence * fence,struct dma_fence_cb * _cb)191441ec0267Sriastradh static void amdgpu_vm_prt_cb(struct dma_fence *fence, struct dma_fence_cb *_cb)
191541ec0267Sriastradh {
191641ec0267Sriastradh 	struct amdgpu_prt_cb *cb = container_of(_cb, struct amdgpu_prt_cb, cb);
191741ec0267Sriastradh 
191841ec0267Sriastradh 	amdgpu_vm_prt_put(cb->adev);
191941ec0267Sriastradh 	kfree(cb);
192041ec0267Sriastradh }
192141ec0267Sriastradh 
192241ec0267Sriastradh /**
192341ec0267Sriastradh  * amdgpu_vm_add_prt_cb - add callback for updating the PRT status
192441ec0267Sriastradh  *
192541ec0267Sriastradh  * @adev: amdgpu_device pointer
192641ec0267Sriastradh  * @fence: fence for the callback
192741ec0267Sriastradh  */
amdgpu_vm_add_prt_cb(struct amdgpu_device * adev,struct dma_fence * fence)192841ec0267Sriastradh static void amdgpu_vm_add_prt_cb(struct amdgpu_device *adev,
192941ec0267Sriastradh 				 struct dma_fence *fence)
193041ec0267Sriastradh {
193141ec0267Sriastradh 	struct amdgpu_prt_cb *cb;
193241ec0267Sriastradh 
193341ec0267Sriastradh 	if (!adev->gmc.gmc_funcs->set_prt)
193441ec0267Sriastradh 		return;
193541ec0267Sriastradh 
193641ec0267Sriastradh 	cb = kmalloc(sizeof(struct amdgpu_prt_cb), GFP_KERNEL);
193741ec0267Sriastradh 	if (!cb) {
193841ec0267Sriastradh 		/* Last resort when we are OOM */
193941ec0267Sriastradh 		if (fence)
194041ec0267Sriastradh 			dma_fence_wait(fence, false);
194141ec0267Sriastradh 
194241ec0267Sriastradh 		amdgpu_vm_prt_put(adev);
194341ec0267Sriastradh 	} else {
194441ec0267Sriastradh 		cb->adev = adev;
194541ec0267Sriastradh 		if (!fence || dma_fence_add_callback(fence, &cb->cb,
194641ec0267Sriastradh 						     amdgpu_vm_prt_cb))
194741ec0267Sriastradh 			amdgpu_vm_prt_cb(fence, &cb->cb);
194841ec0267Sriastradh 	}
194941ec0267Sriastradh }
195041ec0267Sriastradh 
195141ec0267Sriastradh /**
195241ec0267Sriastradh  * amdgpu_vm_free_mapping - free a mapping
195341ec0267Sriastradh  *
195441ec0267Sriastradh  * @adev: amdgpu_device pointer
195541ec0267Sriastradh  * @vm: requested vm
195641ec0267Sriastradh  * @mapping: mapping to be freed
195741ec0267Sriastradh  * @fence: fence of the unmap operation
195841ec0267Sriastradh  *
195941ec0267Sriastradh  * Free a mapping and make sure we decrease the PRT usage count if applicable.
196041ec0267Sriastradh  */
amdgpu_vm_free_mapping(struct amdgpu_device * adev,struct amdgpu_vm * vm,struct amdgpu_bo_va_mapping * mapping,struct dma_fence * fence)196141ec0267Sriastradh static void amdgpu_vm_free_mapping(struct amdgpu_device *adev,
196241ec0267Sriastradh 				   struct amdgpu_vm *vm,
196341ec0267Sriastradh 				   struct amdgpu_bo_va_mapping *mapping,
196441ec0267Sriastradh 				   struct dma_fence *fence)
196541ec0267Sriastradh {
196641ec0267Sriastradh 	if (mapping->flags & AMDGPU_PTE_PRT)
196741ec0267Sriastradh 		amdgpu_vm_add_prt_cb(adev, fence);
196841ec0267Sriastradh 	kfree(mapping);
196941ec0267Sriastradh }
197041ec0267Sriastradh 
197141ec0267Sriastradh /**
197241ec0267Sriastradh  * amdgpu_vm_prt_fini - finish all prt mappings
197341ec0267Sriastradh  *
197441ec0267Sriastradh  * @adev: amdgpu_device pointer
197541ec0267Sriastradh  * @vm: requested vm
197641ec0267Sriastradh  *
197741ec0267Sriastradh  * Register a cleanup callback to disable PRT support after VM dies.
197841ec0267Sriastradh  */
amdgpu_vm_prt_fini(struct amdgpu_device * adev,struct amdgpu_vm * vm)197941ec0267Sriastradh static void amdgpu_vm_prt_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
198041ec0267Sriastradh {
198141ec0267Sriastradh 	struct dma_resv *resv = vm->root.base.bo->tbo.base.resv;
198241ec0267Sriastradh 	struct dma_fence *excl, **shared;
198341ec0267Sriastradh 	unsigned i, shared_count;
198441ec0267Sriastradh 	int r;
198541ec0267Sriastradh 
198641ec0267Sriastradh 	r = dma_resv_get_fences_rcu(resv, &excl,
198741ec0267Sriastradh 					      &shared_count, &shared);
198841ec0267Sriastradh 	if (r) {
198941ec0267Sriastradh 		/* Not enough memory to grab the fence list, as last resort
199041ec0267Sriastradh 		 * block for all the fences to complete.
199141ec0267Sriastradh 		 */
199241ec0267Sriastradh 		dma_resv_wait_timeout_rcu(resv, true, false,
199341ec0267Sriastradh 						    MAX_SCHEDULE_TIMEOUT);
199441ec0267Sriastradh 		return;
199541ec0267Sriastradh 	}
199641ec0267Sriastradh 
199741ec0267Sriastradh 	/* Add a callback for each fence in the reservation object */
199841ec0267Sriastradh 	amdgpu_vm_prt_get(adev);
199941ec0267Sriastradh 	amdgpu_vm_add_prt_cb(adev, excl);
200041ec0267Sriastradh 
200141ec0267Sriastradh 	for (i = 0; i < shared_count; ++i) {
200241ec0267Sriastradh 		amdgpu_vm_prt_get(adev);
200341ec0267Sriastradh 		amdgpu_vm_add_prt_cb(adev, shared[i]);
200441ec0267Sriastradh 	}
200541ec0267Sriastradh 
200641ec0267Sriastradh 	kfree(shared);
200741ec0267Sriastradh }
200841ec0267Sriastradh 
200941ec0267Sriastradh /**
2010efa246c0Sriastradh  * amdgpu_vm_clear_freed - clear freed BOs in the PT
2011efa246c0Sriastradh  *
2012efa246c0Sriastradh  * @adev: amdgpu_device pointer
2013efa246c0Sriastradh  * @vm: requested vm
201441ec0267Sriastradh  * @fence: optional resulting fence (unchanged if no work needed to be done
201541ec0267Sriastradh  * or if an error occurred)
2016efa246c0Sriastradh  *
2017efa246c0Sriastradh  * Make sure all freed BOs are cleared in the PT.
2018efa246c0Sriastradh  * PTs have to be reserved and mutex must be locked!
201941ec0267Sriastradh  *
202041ec0267Sriastradh  * Returns:
202141ec0267Sriastradh  * 0 for success.
202241ec0267Sriastradh  *
2023efa246c0Sriastradh  */
amdgpu_vm_clear_freed(struct amdgpu_device * adev,struct amdgpu_vm * vm,struct dma_fence ** fence)2024efa246c0Sriastradh int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
202541ec0267Sriastradh 			  struct amdgpu_vm *vm,
202641ec0267Sriastradh 			  struct dma_fence **fence)
2027efa246c0Sriastradh {
2028efa246c0Sriastradh 	struct amdgpu_bo_va_mapping *mapping;
202941ec0267Sriastradh 	uint64_t init_pte_value = 0;
203041ec0267Sriastradh 	struct dma_fence *f = NULL;
2031efa246c0Sriastradh 	int r;
2032efa246c0Sriastradh 
2033efa246c0Sriastradh 	while (!list_empty(&vm->freed)) {
2034efa246c0Sriastradh 		mapping = list_first_entry(&vm->freed,
2035efa246c0Sriastradh 			struct amdgpu_bo_va_mapping, list);
2036efa246c0Sriastradh 		list_del(&mapping->list);
2037efa246c0Sriastradh 
203841ec0267Sriastradh 		if (vm->pte_support_ats &&
203941ec0267Sriastradh 		    mapping->start < AMDGPU_GMC_HOLE_START)
204041ec0267Sriastradh 			init_pte_value = AMDGPU_PTE_DEFAULT_ATC;
204141ec0267Sriastradh 
204241ec0267Sriastradh 		r = amdgpu_vm_bo_update_mapping(adev, vm, false, NULL,
204341ec0267Sriastradh 						mapping->start, mapping->last,
204441ec0267Sriastradh 						init_pte_value, 0, NULL, &f);
204541ec0267Sriastradh 		amdgpu_vm_free_mapping(adev, vm, mapping, f);
204641ec0267Sriastradh 		if (r) {
204741ec0267Sriastradh 			dma_fence_put(f);
204841ec0267Sriastradh 			return r;
2049efa246c0Sriastradh 		}
205041ec0267Sriastradh 	}
205141ec0267Sriastradh 
205241ec0267Sriastradh 	if (fence && f) {
205341ec0267Sriastradh 		dma_fence_put(*fence);
205441ec0267Sriastradh 		*fence = f;
205541ec0267Sriastradh 	} else {
205641ec0267Sriastradh 		dma_fence_put(f);
205741ec0267Sriastradh 	}
2058efa246c0Sriastradh 
2059efa246c0Sriastradh 	return 0;
2060efa246c0Sriastradh 
2061efa246c0Sriastradh }
2062efa246c0Sriastradh 
2063efa246c0Sriastradh /**
206441ec0267Sriastradh  * amdgpu_vm_handle_moved - handle moved BOs in the PT
2065efa246c0Sriastradh  *
2066efa246c0Sriastradh  * @adev: amdgpu_device pointer
2067efa246c0Sriastradh  * @vm: requested vm
2068efa246c0Sriastradh  *
206941ec0267Sriastradh  * Make sure all BOs which are moved are updated in the PTs.
2070efa246c0Sriastradh  *
207141ec0267Sriastradh  * Returns:
207241ec0267Sriastradh  * 0 for success.
207341ec0267Sriastradh  *
207441ec0267Sriastradh  * PTs have to be reserved!
2075efa246c0Sriastradh  */
amdgpu_vm_handle_moved(struct amdgpu_device * adev,struct amdgpu_vm * vm)207641ec0267Sriastradh int amdgpu_vm_handle_moved(struct amdgpu_device *adev,
207741ec0267Sriastradh 			   struct amdgpu_vm *vm)
2078efa246c0Sriastradh {
207941ec0267Sriastradh 	struct amdgpu_bo_va *bo_va, *tmp;
208041ec0267Sriastradh 	struct dma_resv *resv;
208141ec0267Sriastradh 	bool clear;
208241ec0267Sriastradh 	int r;
2083efa246c0Sriastradh 
208441ec0267Sriastradh 	list_for_each_entry_safe(bo_va, tmp, &vm->moved, base.vm_status) {
208541ec0267Sriastradh 		/* Per VM BOs never need to bo cleared in the page tables */
208641ec0267Sriastradh 		r = amdgpu_vm_bo_update(adev, bo_va, false);
208741ec0267Sriastradh 		if (r)
208841ec0267Sriastradh 			return r;
208941ec0267Sriastradh 	}
209041ec0267Sriastradh 
209141ec0267Sriastradh 	spin_lock(&vm->invalidated_lock);
2092efa246c0Sriastradh 	while (!list_empty(&vm->invalidated)) {
209341ec0267Sriastradh 		bo_va = list_first_entry(&vm->invalidated, struct amdgpu_bo_va,
209441ec0267Sriastradh 					 base.vm_status);
209541ec0267Sriastradh 		resv = bo_va->base.bo->tbo.base.resv;
209641ec0267Sriastradh 		spin_unlock(&vm->invalidated_lock);
209741ec0267Sriastradh 
209841ec0267Sriastradh 		/* Try to reserve the BO to avoid clearing its ptes */
209941ec0267Sriastradh 		if (!amdgpu_vm_debug && dma_resv_trylock(resv))
210041ec0267Sriastradh 			clear = false;
210141ec0267Sriastradh 		/* Somebody else is using the BO right now */
210241ec0267Sriastradh 		else
210341ec0267Sriastradh 			clear = true;
210441ec0267Sriastradh 
210541ec0267Sriastradh 		r = amdgpu_vm_bo_update(adev, bo_va, clear);
2106efa246c0Sriastradh 		if (r)
2107efa246c0Sriastradh 			return r;
2108efa246c0Sriastradh 
210941ec0267Sriastradh 		if (!clear)
211041ec0267Sriastradh 			dma_resv_unlock(resv);
211141ec0267Sriastradh 		spin_lock(&vm->invalidated_lock);
2112efa246c0Sriastradh 	}
211341ec0267Sriastradh 	spin_unlock(&vm->invalidated_lock);
2114efa246c0Sriastradh 
211541ec0267Sriastradh 	return 0;
2116efa246c0Sriastradh }
2117efa246c0Sriastradh 
2118efa246c0Sriastradh /**
2119efa246c0Sriastradh  * amdgpu_vm_bo_add - add a bo to a specific vm
2120efa246c0Sriastradh  *
2121efa246c0Sriastradh  * @adev: amdgpu_device pointer
2122efa246c0Sriastradh  * @vm: requested vm
2123efa246c0Sriastradh  * @bo: amdgpu buffer object
2124efa246c0Sriastradh  *
212541ec0267Sriastradh  * Add @bo into the requested vm.
2126efa246c0Sriastradh  * Add @bo to the list of bos associated with the vm
212741ec0267Sriastradh  *
212841ec0267Sriastradh  * Returns:
212941ec0267Sriastradh  * Newly added bo_va or NULL for failure
2130efa246c0Sriastradh  *
2131efa246c0Sriastradh  * Object has to be reserved!
2132efa246c0Sriastradh  */
amdgpu_vm_bo_add(struct amdgpu_device * adev,struct amdgpu_vm * vm,struct amdgpu_bo * bo)2133efa246c0Sriastradh struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev,
2134efa246c0Sriastradh 				      struct amdgpu_vm *vm,
2135efa246c0Sriastradh 				      struct amdgpu_bo *bo)
2136efa246c0Sriastradh {
2137efa246c0Sriastradh 	struct amdgpu_bo_va *bo_va;
2138efa246c0Sriastradh 
2139efa246c0Sriastradh 	bo_va = kzalloc(sizeof(struct amdgpu_bo_va), GFP_KERNEL);
2140efa246c0Sriastradh 	if (bo_va == NULL) {
2141efa246c0Sriastradh 		return NULL;
2142efa246c0Sriastradh 	}
214341ec0267Sriastradh 	amdgpu_vm_bo_base_init(&bo_va->base, vm, bo);
214441ec0267Sriastradh 
2145efa246c0Sriastradh 	bo_va->ref_count = 1;
2146efa246c0Sriastradh 	INIT_LIST_HEAD(&bo_va->valids);
2147efa246c0Sriastradh 	INIT_LIST_HEAD(&bo_va->invalids);
214841ec0267Sriastradh 
214941ec0267Sriastradh 	if (bo && amdgpu_xgmi_same_hive(adev, amdgpu_ttm_adev(bo->tbo.bdev)) &&
215041ec0267Sriastradh 	    (bo->preferred_domains & AMDGPU_GEM_DOMAIN_VRAM)) {
215141ec0267Sriastradh 		bo_va->is_xgmi = true;
215241ec0267Sriastradh 		mutex_lock(&adev->vm_manager.lock_pstate);
215341ec0267Sriastradh 		/* Power up XGMI if it can be potentially used */
215441ec0267Sriastradh 		if (++adev->vm_manager.xgmi_map_counter == 1)
215541ec0267Sriastradh 			amdgpu_xgmi_set_pstate(adev, 1);
215641ec0267Sriastradh 		mutex_unlock(&adev->vm_manager.lock_pstate);
215741ec0267Sriastradh 	}
2158efa246c0Sriastradh 
2159efa246c0Sriastradh 	return bo_va;
2160efa246c0Sriastradh }
2161efa246c0Sriastradh 
216241ec0267Sriastradh 
216341ec0267Sriastradh /**
216441ec0267Sriastradh  * amdgpu_vm_bo_insert_mapping - insert a new mapping
216541ec0267Sriastradh  *
216641ec0267Sriastradh  * @adev: amdgpu_device pointer
216741ec0267Sriastradh  * @bo_va: bo_va to store the address
216841ec0267Sriastradh  * @mapping: the mapping to insert
216941ec0267Sriastradh  *
217041ec0267Sriastradh  * Insert a new mapping into all structures.
217141ec0267Sriastradh  */
amdgpu_vm_bo_insert_map(struct amdgpu_device * adev,struct amdgpu_bo_va * bo_va,struct amdgpu_bo_va_mapping * mapping)217241ec0267Sriastradh static void amdgpu_vm_bo_insert_map(struct amdgpu_device *adev,
217341ec0267Sriastradh 				    struct amdgpu_bo_va *bo_va,
217441ec0267Sriastradh 				    struct amdgpu_bo_va_mapping *mapping)
217541ec0267Sriastradh {
217641ec0267Sriastradh 	struct amdgpu_vm *vm = bo_va->base.vm;
217741ec0267Sriastradh 	struct amdgpu_bo *bo = bo_va->base.bo;
217841ec0267Sriastradh 
217941ec0267Sriastradh 	mapping->bo_va = bo_va;
218041ec0267Sriastradh 	list_add(&mapping->list, &bo_va->invalids);
218141ec0267Sriastradh 	amdgpu_vm_it_insert(mapping, &vm->va);
218241ec0267Sriastradh 
218341ec0267Sriastradh 	if (mapping->flags & AMDGPU_PTE_PRT)
218441ec0267Sriastradh 		amdgpu_vm_prt_get(adev);
218541ec0267Sriastradh 
218641ec0267Sriastradh 	if (bo && bo->tbo.base.resv == vm->root.base.bo->tbo.base.resv &&
218741ec0267Sriastradh 	    !bo_va->base.moved) {
218841ec0267Sriastradh 		list_move(&bo_va->base.vm_status, &vm->moved);
218941ec0267Sriastradh 	}
219041ec0267Sriastradh 	trace_amdgpu_vm_bo_map(bo_va, mapping);
219141ec0267Sriastradh }
219241ec0267Sriastradh 
2193efa246c0Sriastradh /**
2194efa246c0Sriastradh  * amdgpu_vm_bo_map - map bo inside a vm
2195efa246c0Sriastradh  *
2196efa246c0Sriastradh  * @adev: amdgpu_device pointer
2197efa246c0Sriastradh  * @bo_va: bo_va to store the address
2198efa246c0Sriastradh  * @saddr: where to map the BO
2199efa246c0Sriastradh  * @offset: requested offset in the BO
220041ec0267Sriastradh  * @size: BO size in bytes
2201efa246c0Sriastradh  * @flags: attributes of pages (read/write/valid/etc.)
2202efa246c0Sriastradh  *
2203efa246c0Sriastradh  * Add a mapping of the BO at the specefied addr into the VM.
220441ec0267Sriastradh  *
220541ec0267Sriastradh  * Returns:
220641ec0267Sriastradh  * 0 for success, error for failure.
2207efa246c0Sriastradh  *
2208efa246c0Sriastradh  * Object has to be reserved and unreserved outside!
2209efa246c0Sriastradh  */
amdgpu_vm_bo_map(struct amdgpu_device * adev,struct amdgpu_bo_va * bo_va,uint64_t saddr,uint64_t offset,uint64_t size,uint64_t flags)2210efa246c0Sriastradh int amdgpu_vm_bo_map(struct amdgpu_device *adev,
2211efa246c0Sriastradh 		     struct amdgpu_bo_va *bo_va,
2212efa246c0Sriastradh 		     uint64_t saddr, uint64_t offset,
221341ec0267Sriastradh 		     uint64_t size, uint64_t flags)
221441ec0267Sriastradh {
221541ec0267Sriastradh 	struct amdgpu_bo_va_mapping *mapping, *tmp;
221641ec0267Sriastradh 	struct amdgpu_bo *bo = bo_va->base.bo;
221741ec0267Sriastradh 	struct amdgpu_vm *vm = bo_va->base.vm;
221841ec0267Sriastradh 	uint64_t eaddr;
221941ec0267Sriastradh 
222041ec0267Sriastradh 	/* validate the parameters */
222141ec0267Sriastradh 	if (saddr & AMDGPU_GPU_PAGE_MASK || offset & AMDGPU_GPU_PAGE_MASK ||
222241ec0267Sriastradh 	    size == 0 || size & AMDGPU_GPU_PAGE_MASK)
222341ec0267Sriastradh 		return -EINVAL;
222441ec0267Sriastradh 
222541ec0267Sriastradh 	/* make sure object fit at this offset */
222641ec0267Sriastradh 	eaddr = saddr + size - 1;
222741ec0267Sriastradh 	if (saddr >= eaddr ||
222841ec0267Sriastradh 	    (bo && offset + size > amdgpu_bo_size(bo)))
222941ec0267Sriastradh 		return -EINVAL;
223041ec0267Sriastradh 
223141ec0267Sriastradh 	saddr /= AMDGPU_GPU_PAGE_SIZE;
223241ec0267Sriastradh 	eaddr /= AMDGPU_GPU_PAGE_SIZE;
223341ec0267Sriastradh 
223441ec0267Sriastradh 	tmp = amdgpu_vm_it_iter_first(&vm->va, saddr, eaddr);
223541ec0267Sriastradh 	if (tmp) {
223641ec0267Sriastradh 		/* bo and tmp overlap, invalid addr */
223741ec0267Sriastradh 		dev_err(adev->dev, "bo %p va 0x%010"PRIx64"-0x%010"PRIx64" conflict with "
223843e663d0Sriastradh 			"0x%010"PRIx64"-0x%010"PRIx64"\n", bo, saddr, eaddr,
223941ec0267Sriastradh 			tmp->start, tmp->last + 1);
224041ec0267Sriastradh 		return -EINVAL;
224141ec0267Sriastradh 	}
224241ec0267Sriastradh 
224341ec0267Sriastradh 	mapping = kmalloc(sizeof(*mapping), GFP_KERNEL);
224441ec0267Sriastradh 	if (!mapping)
224541ec0267Sriastradh 		return -ENOMEM;
224641ec0267Sriastradh 
224741ec0267Sriastradh 	mapping->start = saddr;
224841ec0267Sriastradh 	mapping->last = eaddr;
224941ec0267Sriastradh 	mapping->offset = offset;
225041ec0267Sriastradh 	mapping->flags = flags;
225141ec0267Sriastradh 
225241ec0267Sriastradh 	amdgpu_vm_bo_insert_map(adev, bo_va, mapping);
225341ec0267Sriastradh 
225441ec0267Sriastradh 	return 0;
225541ec0267Sriastradh }
225641ec0267Sriastradh 
225741ec0267Sriastradh /**
225841ec0267Sriastradh  * amdgpu_vm_bo_replace_map - map bo inside a vm, replacing existing mappings
225941ec0267Sriastradh  *
226041ec0267Sriastradh  * @adev: amdgpu_device pointer
226141ec0267Sriastradh  * @bo_va: bo_va to store the address
226241ec0267Sriastradh  * @saddr: where to map the BO
226341ec0267Sriastradh  * @offset: requested offset in the BO
226441ec0267Sriastradh  * @size: BO size in bytes
226541ec0267Sriastradh  * @flags: attributes of pages (read/write/valid/etc.)
226641ec0267Sriastradh  *
226741ec0267Sriastradh  * Add a mapping of the BO at the specefied addr into the VM. Replace existing
226841ec0267Sriastradh  * mappings as we do so.
226941ec0267Sriastradh  *
227041ec0267Sriastradh  * Returns:
227141ec0267Sriastradh  * 0 for success, error for failure.
227241ec0267Sriastradh  *
227341ec0267Sriastradh  * Object has to be reserved and unreserved outside!
227441ec0267Sriastradh  */
amdgpu_vm_bo_replace_map(struct amdgpu_device * adev,struct amdgpu_bo_va * bo_va,uint64_t saddr,uint64_t offset,uint64_t size,uint64_t flags)227541ec0267Sriastradh int amdgpu_vm_bo_replace_map(struct amdgpu_device *adev,
227641ec0267Sriastradh 			     struct amdgpu_bo_va *bo_va,
227741ec0267Sriastradh 			     uint64_t saddr, uint64_t offset,
227841ec0267Sriastradh 			     uint64_t size, uint64_t flags)
2279efa246c0Sriastradh {
2280efa246c0Sriastradh 	struct amdgpu_bo_va_mapping *mapping;
228141ec0267Sriastradh 	struct amdgpu_bo *bo = bo_va->base.bo;
2282efa246c0Sriastradh 	uint64_t eaddr;
2283efa246c0Sriastradh 	int r;
2284efa246c0Sriastradh 
2285efa246c0Sriastradh 	/* validate the parameters */
2286efa246c0Sriastradh 	if (saddr & AMDGPU_GPU_PAGE_MASK || offset & AMDGPU_GPU_PAGE_MASK ||
2287efa246c0Sriastradh 	    size == 0 || size & AMDGPU_GPU_PAGE_MASK)
2288efa246c0Sriastradh 		return -EINVAL;
2289efa246c0Sriastradh 
2290efa246c0Sriastradh 	/* make sure object fit at this offset */
2291efa246c0Sriastradh 	eaddr = saddr + size - 1;
229241ec0267Sriastradh 	if (saddr >= eaddr ||
229341ec0267Sriastradh 	    (bo && offset + size > amdgpu_bo_size(bo)))
2294efa246c0Sriastradh 		return -EINVAL;
2295efa246c0Sriastradh 
229641ec0267Sriastradh 	/* Allocate all the needed memory */
229741ec0267Sriastradh 	mapping = kmalloc(sizeof(*mapping), GFP_KERNEL);
229841ec0267Sriastradh 	if (!mapping)
229941ec0267Sriastradh 		return -ENOMEM;
230041ec0267Sriastradh 
230141ec0267Sriastradh 	r = amdgpu_vm_bo_clear_mappings(adev, bo_va->base.vm, saddr, size);
230241ec0267Sriastradh 	if (r) {
230341ec0267Sriastradh 		kfree(mapping);
230441ec0267Sriastradh 		return r;
2305efa246c0Sriastradh 	}
2306efa246c0Sriastradh 
2307efa246c0Sriastradh 	saddr /= AMDGPU_GPU_PAGE_SIZE;
2308efa246c0Sriastradh 	eaddr /= AMDGPU_GPU_PAGE_SIZE;
2309efa246c0Sriastradh 
231041ec0267Sriastradh 	mapping->start = saddr;
231141ec0267Sriastradh 	mapping->last = eaddr;
2312efa246c0Sriastradh 	mapping->offset = offset;
2313efa246c0Sriastradh 	mapping->flags = flags;
2314efa246c0Sriastradh 
231541ec0267Sriastradh 	amdgpu_vm_bo_insert_map(adev, bo_va, mapping);
2316efa246c0Sriastradh 
2317efa246c0Sriastradh 	return 0;
2318efa246c0Sriastradh }
2319efa246c0Sriastradh 
2320efa246c0Sriastradh /**
2321efa246c0Sriastradh  * amdgpu_vm_bo_unmap - remove bo mapping from vm
2322efa246c0Sriastradh  *
2323efa246c0Sriastradh  * @adev: amdgpu_device pointer
2324efa246c0Sriastradh  * @bo_va: bo_va to remove the address from
2325efa246c0Sriastradh  * @saddr: where to the BO is mapped
2326efa246c0Sriastradh  *
2327efa246c0Sriastradh  * Remove a mapping of the BO at the specefied addr from the VM.
232841ec0267Sriastradh  *
232941ec0267Sriastradh  * Returns:
233041ec0267Sriastradh  * 0 for success, error for failure.
2331efa246c0Sriastradh  *
2332efa246c0Sriastradh  * Object has to be reserved and unreserved outside!
2333efa246c0Sriastradh  */
amdgpu_vm_bo_unmap(struct amdgpu_device * adev,struct amdgpu_bo_va * bo_va,uint64_t saddr)2334efa246c0Sriastradh int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
2335efa246c0Sriastradh 		       struct amdgpu_bo_va *bo_va,
2336efa246c0Sriastradh 		       uint64_t saddr)
2337efa246c0Sriastradh {
2338efa246c0Sriastradh 	struct amdgpu_bo_va_mapping *mapping;
233941ec0267Sriastradh 	struct amdgpu_vm *vm = bo_va->base.vm;
2340efa246c0Sriastradh 	bool valid = true;
2341efa246c0Sriastradh 
2342efa246c0Sriastradh 	saddr /= AMDGPU_GPU_PAGE_SIZE;
234341ec0267Sriastradh 
2344efa246c0Sriastradh 	list_for_each_entry(mapping, &bo_va->valids, list) {
234541ec0267Sriastradh 		if (mapping->start == saddr)
2346efa246c0Sriastradh 			break;
2347efa246c0Sriastradh 	}
2348efa246c0Sriastradh 
2349efa246c0Sriastradh 	if (&mapping->list == &bo_va->valids) {
2350efa246c0Sriastradh 		valid = false;
2351efa246c0Sriastradh 
2352efa246c0Sriastradh 		list_for_each_entry(mapping, &bo_va->invalids, list) {
235341ec0267Sriastradh 			if (mapping->start == saddr)
2354efa246c0Sriastradh 				break;
2355efa246c0Sriastradh 		}
2356efa246c0Sriastradh 
235741ec0267Sriastradh 		if (&mapping->list == &bo_va->invalids)
2358efa246c0Sriastradh 			return -ENOENT;
2359efa246c0Sriastradh 	}
236041ec0267Sriastradh 
2361efa246c0Sriastradh 	list_del(&mapping->list);
236241ec0267Sriastradh 	amdgpu_vm_it_remove(mapping, &vm->va);
236341ec0267Sriastradh 	mapping->bo_va = NULL;
2364efa246c0Sriastradh 	trace_amdgpu_vm_bo_unmap(bo_va, mapping);
2365efa246c0Sriastradh 
236641ec0267Sriastradh 	if (valid)
2367efa246c0Sriastradh 		list_add(&mapping->list, &vm->freed);
236841ec0267Sriastradh 	else
236941ec0267Sriastradh 		amdgpu_vm_free_mapping(adev, vm, mapping,
237041ec0267Sriastradh 				       bo_va->last_pt_update);
237141ec0267Sriastradh 
237241ec0267Sriastradh 	return 0;
237341ec0267Sriastradh }
237441ec0267Sriastradh 
237541ec0267Sriastradh /**
237641ec0267Sriastradh  * amdgpu_vm_bo_clear_mappings - remove all mappings in a specific range
237741ec0267Sriastradh  *
237841ec0267Sriastradh  * @adev: amdgpu_device pointer
237941ec0267Sriastradh  * @vm: VM structure to use
238041ec0267Sriastradh  * @saddr: start of the range
238141ec0267Sriastradh  * @size: size of the range
238241ec0267Sriastradh  *
238341ec0267Sriastradh  * Remove all mappings in a range, split them as appropriate.
238441ec0267Sriastradh  *
238541ec0267Sriastradh  * Returns:
238641ec0267Sriastradh  * 0 for success, error for failure.
238741ec0267Sriastradh  */
amdgpu_vm_bo_clear_mappings(struct amdgpu_device * adev,struct amdgpu_vm * vm,uint64_t saddr,uint64_t size)238841ec0267Sriastradh int amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev,
238941ec0267Sriastradh 				struct amdgpu_vm *vm,
239041ec0267Sriastradh 				uint64_t saddr, uint64_t size)
239141ec0267Sriastradh {
239241ec0267Sriastradh 	struct amdgpu_bo_va_mapping *before, *after, *tmp, *next;
239341ec0267Sriastradh 	LIST_HEAD(removed);
239441ec0267Sriastradh 	uint64_t eaddr;
239541ec0267Sriastradh 
239641ec0267Sriastradh 	eaddr = saddr + size - 1;
239741ec0267Sriastradh 	saddr /= AMDGPU_GPU_PAGE_SIZE;
239841ec0267Sriastradh 	eaddr /= AMDGPU_GPU_PAGE_SIZE;
239941ec0267Sriastradh 
240041ec0267Sriastradh 	/* Allocate all the needed memory */
240141ec0267Sriastradh 	before = kzalloc(sizeof(*before), GFP_KERNEL);
240241ec0267Sriastradh 	if (!before)
240341ec0267Sriastradh 		return -ENOMEM;
240441ec0267Sriastradh 	INIT_LIST_HEAD(&before->list);
240541ec0267Sriastradh 
240641ec0267Sriastradh 	after = kzalloc(sizeof(*after), GFP_KERNEL);
240741ec0267Sriastradh 	if (!after) {
240841ec0267Sriastradh 		kfree(before);
240941ec0267Sriastradh 		return -ENOMEM;
241041ec0267Sriastradh 	}
241141ec0267Sriastradh 	INIT_LIST_HEAD(&after->list);
241241ec0267Sriastradh 
241341ec0267Sriastradh 	/* Now gather all removed mappings */
241441ec0267Sriastradh 	tmp = amdgpu_vm_it_iter_first(&vm->va, saddr, eaddr);
241541ec0267Sriastradh 	while (tmp) {
241641ec0267Sriastradh 		/* Remember mapping split at the start */
241741ec0267Sriastradh 		if (tmp->start < saddr) {
241841ec0267Sriastradh 			before->start = tmp->start;
241941ec0267Sriastradh 			before->last = saddr - 1;
242041ec0267Sriastradh 			before->offset = tmp->offset;
242141ec0267Sriastradh 			before->flags = tmp->flags;
242241ec0267Sriastradh 			before->bo_va = tmp->bo_va;
242341ec0267Sriastradh 			list_add(&before->list, &tmp->bo_va->invalids);
242441ec0267Sriastradh 		}
242541ec0267Sriastradh 
242641ec0267Sriastradh 		/* Remember mapping split at the end */
242741ec0267Sriastradh 		if (tmp->last > eaddr) {
242841ec0267Sriastradh 			after->start = eaddr + 1;
242941ec0267Sriastradh 			after->last = tmp->last;
243041ec0267Sriastradh 			after->offset = tmp->offset;
243141ec0267Sriastradh 			after->offset += after->start - tmp->start;
243241ec0267Sriastradh 			after->flags = tmp->flags;
243341ec0267Sriastradh 			after->bo_va = tmp->bo_va;
243441ec0267Sriastradh 			list_add(&after->list, &tmp->bo_va->invalids);
243541ec0267Sriastradh 		}
243641ec0267Sriastradh 
243741ec0267Sriastradh 		list_del(&tmp->list);
243841ec0267Sriastradh 		list_add(&tmp->list, &removed);
243941ec0267Sriastradh 
244043e663d0Sriastradh 		tmp = amdgpu_vm_it_iter_next(&vm->va, tmp, saddr, eaddr);
244141ec0267Sriastradh 	}
244241ec0267Sriastradh 
244341ec0267Sriastradh 	/* And free them up */
244441ec0267Sriastradh 	list_for_each_entry_safe(tmp, next, &removed, list) {
244541ec0267Sriastradh 		amdgpu_vm_it_remove(tmp, &vm->va);
244641ec0267Sriastradh 		list_del(&tmp->list);
244741ec0267Sriastradh 
244841ec0267Sriastradh 		if (tmp->start < saddr)
244941ec0267Sriastradh 		    tmp->start = saddr;
245041ec0267Sriastradh 		if (tmp->last > eaddr)
245141ec0267Sriastradh 		    tmp->last = eaddr;
245241ec0267Sriastradh 
245341ec0267Sriastradh 		tmp->bo_va = NULL;
245441ec0267Sriastradh 		list_add(&tmp->list, &vm->freed);
245541ec0267Sriastradh 		trace_amdgpu_vm_bo_unmap(NULL, tmp);
245641ec0267Sriastradh 	}
245741ec0267Sriastradh 
245841ec0267Sriastradh 	/* Insert partial mapping before the range */
245941ec0267Sriastradh 	if (!list_empty(&before->list)) {
246041ec0267Sriastradh 		amdgpu_vm_it_insert(before, &vm->va);
246141ec0267Sriastradh 		if (before->flags & AMDGPU_PTE_PRT)
246241ec0267Sriastradh 			amdgpu_vm_prt_get(adev);
2463efa246c0Sriastradh 	} else {
246441ec0267Sriastradh 		kfree(before);
246541ec0267Sriastradh 	}
246641ec0267Sriastradh 
246741ec0267Sriastradh 	/* Insert partial mapping after the range */
246841ec0267Sriastradh 	if (!list_empty(&after->list)) {
246941ec0267Sriastradh 		amdgpu_vm_it_insert(after, &vm->va);
247041ec0267Sriastradh 		if (after->flags & AMDGPU_PTE_PRT)
247141ec0267Sriastradh 			amdgpu_vm_prt_get(adev);
247241ec0267Sriastradh 	} else {
247341ec0267Sriastradh 		kfree(after);
2474efa246c0Sriastradh 	}
2475efa246c0Sriastradh 
2476efa246c0Sriastradh 	return 0;
2477efa246c0Sriastradh }
2478efa246c0Sriastradh 
2479efa246c0Sriastradh /**
248041ec0267Sriastradh  * amdgpu_vm_bo_lookup_mapping - find mapping by address
248141ec0267Sriastradh  *
248241ec0267Sriastradh  * @vm: the requested VM
248341ec0267Sriastradh  * @addr: the address
248441ec0267Sriastradh  *
248541ec0267Sriastradh  * Find a mapping by it's address.
248641ec0267Sriastradh  *
248741ec0267Sriastradh  * Returns:
248841ec0267Sriastradh  * The amdgpu_bo_va_mapping matching for addr or NULL
248941ec0267Sriastradh  *
249041ec0267Sriastradh  */
amdgpu_vm_bo_lookup_mapping(struct amdgpu_vm * vm,uint64_t addr)249141ec0267Sriastradh struct amdgpu_bo_va_mapping *amdgpu_vm_bo_lookup_mapping(struct amdgpu_vm *vm,
249241ec0267Sriastradh 							 uint64_t addr)
249341ec0267Sriastradh {
249441ec0267Sriastradh 	return amdgpu_vm_it_iter_first(&vm->va, addr, addr);
249541ec0267Sriastradh }
249641ec0267Sriastradh 
249741ec0267Sriastradh /**
249841ec0267Sriastradh  * amdgpu_vm_bo_trace_cs - trace all reserved mappings
249941ec0267Sriastradh  *
250041ec0267Sriastradh  * @vm: the requested vm
250141ec0267Sriastradh  * @ticket: CS ticket
250241ec0267Sriastradh  *
250341ec0267Sriastradh  * Trace all mappings of BOs reserved during a command submission.
250441ec0267Sriastradh  */
amdgpu_vm_bo_trace_cs(struct amdgpu_vm * vm,struct ww_acquire_ctx * ticket)250541ec0267Sriastradh void amdgpu_vm_bo_trace_cs(struct amdgpu_vm *vm, struct ww_acquire_ctx *ticket)
250641ec0267Sriastradh {
250741ec0267Sriastradh 	struct amdgpu_bo_va_mapping *mapping;
250841ec0267Sriastradh 
250941ec0267Sriastradh 	if (!trace_amdgpu_vm_bo_cs_enabled())
251041ec0267Sriastradh 		return;
251141ec0267Sriastradh 
251241ec0267Sriastradh 	for (mapping = amdgpu_vm_it_iter_first(&vm->va, 0, U64_MAX); mapping;
251343e663d0Sriastradh 	     mapping = amdgpu_vm_it_iter_next(&vm->va, mapping, 0, U64_MAX)) {
251441ec0267Sriastradh 		if (mapping->bo_va && mapping->bo_va->base.bo) {
251541ec0267Sriastradh 			struct amdgpu_bo *bo;
251641ec0267Sriastradh 
251741ec0267Sriastradh 			bo = mapping->bo_va->base.bo;
251841ec0267Sriastradh 			if (dma_resv_locking_ctx(bo->tbo.base.resv) !=
251941ec0267Sriastradh 			    ticket)
252041ec0267Sriastradh 				continue;
252141ec0267Sriastradh 		}
252241ec0267Sriastradh 
252341ec0267Sriastradh 		trace_amdgpu_vm_bo_cs(mapping);
252441ec0267Sriastradh 	}
252541ec0267Sriastradh }
252641ec0267Sriastradh 
252741ec0267Sriastradh /**
2528efa246c0Sriastradh  * amdgpu_vm_bo_rmv - remove a bo to a specific vm
2529efa246c0Sriastradh  *
2530efa246c0Sriastradh  * @adev: amdgpu_device pointer
2531efa246c0Sriastradh  * @bo_va: requested bo_va
2532efa246c0Sriastradh  *
253341ec0267Sriastradh  * Remove @bo_va->bo from the requested vm.
2534efa246c0Sriastradh  *
2535efa246c0Sriastradh  * Object have to be reserved!
2536efa246c0Sriastradh  */
amdgpu_vm_bo_rmv(struct amdgpu_device * adev,struct amdgpu_bo_va * bo_va)2537efa246c0Sriastradh void amdgpu_vm_bo_rmv(struct amdgpu_device *adev,
2538efa246c0Sriastradh 		      struct amdgpu_bo_va *bo_va)
2539efa246c0Sriastradh {
2540efa246c0Sriastradh 	struct amdgpu_bo_va_mapping *mapping, *next;
254141ec0267Sriastradh 	struct amdgpu_bo *bo = bo_va->base.bo;
254241ec0267Sriastradh 	struct amdgpu_vm *vm = bo_va->base.vm;
254341ec0267Sriastradh 	struct amdgpu_vm_bo_base **base;
2544efa246c0Sriastradh 
254541ec0267Sriastradh 	if (bo) {
254641ec0267Sriastradh 		if (bo->tbo.base.resv == vm->root.base.bo->tbo.base.resv)
254741ec0267Sriastradh 			vm->bulk_moveable = false;
2548efa246c0Sriastradh 
254941ec0267Sriastradh 		for (base = &bo_va->base.bo->vm_bo; *base;
255041ec0267Sriastradh 		     base = &(*base)->next) {
255141ec0267Sriastradh 			if (*base != &bo_va->base)
255241ec0267Sriastradh 				continue;
255341ec0267Sriastradh 
255441ec0267Sriastradh 			*base = bo_va->base.next;
255541ec0267Sriastradh 			break;
255641ec0267Sriastradh 		}
255741ec0267Sriastradh 	}
255841ec0267Sriastradh 
255941ec0267Sriastradh 	spin_lock(&vm->invalidated_lock);
256041ec0267Sriastradh 	list_del(&bo_va->base.vm_status);
256141ec0267Sriastradh 	spin_unlock(&vm->invalidated_lock);
2562efa246c0Sriastradh 
2563efa246c0Sriastradh 	list_for_each_entry_safe(mapping, next, &bo_va->valids, list) {
2564efa246c0Sriastradh 		list_del(&mapping->list);
256541ec0267Sriastradh 		amdgpu_vm_it_remove(mapping, &vm->va);
256641ec0267Sriastradh 		mapping->bo_va = NULL;
2567efa246c0Sriastradh 		trace_amdgpu_vm_bo_unmap(bo_va, mapping);
2568efa246c0Sriastradh 		list_add(&mapping->list, &vm->freed);
2569efa246c0Sriastradh 	}
2570efa246c0Sriastradh 	list_for_each_entry_safe(mapping, next, &bo_va->invalids, list) {
2571efa246c0Sriastradh 		list_del(&mapping->list);
257241ec0267Sriastradh 		amdgpu_vm_it_remove(mapping, &vm->va);
257341ec0267Sriastradh 		amdgpu_vm_free_mapping(adev, vm, mapping,
257441ec0267Sriastradh 				       bo_va->last_pt_update);
2575efa246c0Sriastradh 	}
257641ec0267Sriastradh 
257741ec0267Sriastradh 	dma_fence_put(bo_va->last_pt_update);
257841ec0267Sriastradh 
257941ec0267Sriastradh 	if (bo && bo_va->is_xgmi) {
258041ec0267Sriastradh 		mutex_lock(&adev->vm_manager.lock_pstate);
258141ec0267Sriastradh 		if (--adev->vm_manager.xgmi_map_counter == 0)
258241ec0267Sriastradh 			amdgpu_xgmi_set_pstate(adev, 0);
258341ec0267Sriastradh 		mutex_unlock(&adev->vm_manager.lock_pstate);
258441ec0267Sriastradh 	}
258541ec0267Sriastradh 
2586efa246c0Sriastradh 	kfree(bo_va);
2587efa246c0Sriastradh }
2588efa246c0Sriastradh 
2589efa246c0Sriastradh /**
259041ec0267Sriastradh  * amdgpu_vm_evictable - check if we can evict a VM
259141ec0267Sriastradh  *
259241ec0267Sriastradh  * @bo: A page table of the VM.
259341ec0267Sriastradh  *
259441ec0267Sriastradh  * Check if it is possible to evict a VM.
259541ec0267Sriastradh  */
amdgpu_vm_evictable(struct amdgpu_bo * bo)259641ec0267Sriastradh bool amdgpu_vm_evictable(struct amdgpu_bo *bo)
259741ec0267Sriastradh {
259841ec0267Sriastradh 	struct amdgpu_vm_bo_base *bo_base = bo->vm_bo;
259941ec0267Sriastradh 
260041ec0267Sriastradh 	/* Page tables of a destroyed VM can go away immediately */
260141ec0267Sriastradh 	if (!bo_base || !bo_base->vm)
260241ec0267Sriastradh 		return true;
260341ec0267Sriastradh 
260441ec0267Sriastradh 	/* Don't evict VM page tables while they are busy */
260541ec0267Sriastradh 	if (!dma_resv_test_signaled_rcu(bo->tbo.base.resv, true))
260641ec0267Sriastradh 		return false;
260741ec0267Sriastradh 
260841ec0267Sriastradh 	/* Try to block ongoing updates */
260941ec0267Sriastradh 	if (!amdgpu_vm_eviction_trylock(bo_base->vm))
261041ec0267Sriastradh 		return false;
261141ec0267Sriastradh 
261241ec0267Sriastradh 	/* Don't evict VM page tables while they are updated */
261341ec0267Sriastradh 	if (!dma_fence_is_signaled(bo_base->vm->last_direct) ||
261441ec0267Sriastradh 	    !dma_fence_is_signaled(bo_base->vm->last_delayed)) {
261541ec0267Sriastradh 		amdgpu_vm_eviction_unlock(bo_base->vm);
261641ec0267Sriastradh 		return false;
261741ec0267Sriastradh 	}
261841ec0267Sriastradh 
261941ec0267Sriastradh 	bo_base->vm->evicting = true;
262041ec0267Sriastradh 	amdgpu_vm_eviction_unlock(bo_base->vm);
262141ec0267Sriastradh 	return true;
262241ec0267Sriastradh }
262341ec0267Sriastradh 
262441ec0267Sriastradh /**
2625efa246c0Sriastradh  * amdgpu_vm_bo_invalidate - mark the bo as invalid
2626efa246c0Sriastradh  *
2627efa246c0Sriastradh  * @adev: amdgpu_device pointer
2628efa246c0Sriastradh  * @bo: amdgpu buffer object
262941ec0267Sriastradh  * @evicted: is the BO evicted
2630efa246c0Sriastradh  *
263141ec0267Sriastradh  * Mark @bo as invalid.
2632efa246c0Sriastradh  */
amdgpu_vm_bo_invalidate(struct amdgpu_device * adev,struct amdgpu_bo * bo,bool evicted)2633efa246c0Sriastradh void amdgpu_vm_bo_invalidate(struct amdgpu_device *adev,
263441ec0267Sriastradh 			     struct amdgpu_bo *bo, bool evicted)
2635efa246c0Sriastradh {
263641ec0267Sriastradh 	struct amdgpu_vm_bo_base *bo_base;
2637efa246c0Sriastradh 
263841ec0267Sriastradh 	/* shadow bo doesn't have bo base, its validation needs its parent */
263941ec0267Sriastradh 	if (bo->parent && bo->parent->shadow == bo)
264041ec0267Sriastradh 		bo = bo->parent;
264141ec0267Sriastradh 
264241ec0267Sriastradh 	for (bo_base = bo->vm_bo; bo_base; bo_base = bo_base->next) {
264341ec0267Sriastradh 		struct amdgpu_vm *vm = bo_base->vm;
264441ec0267Sriastradh 
264541ec0267Sriastradh 		if (evicted && bo->tbo.base.resv == vm->root.base.bo->tbo.base.resv) {
264641ec0267Sriastradh 			amdgpu_vm_bo_evicted(bo_base);
264741ec0267Sriastradh 			continue;
2648efa246c0Sriastradh 		}
264941ec0267Sriastradh 
265041ec0267Sriastradh 		if (bo_base->moved)
265141ec0267Sriastradh 			continue;
265241ec0267Sriastradh 		bo_base->moved = true;
265341ec0267Sriastradh 
265441ec0267Sriastradh 		if (bo->tbo.type == ttm_bo_type_kernel)
265541ec0267Sriastradh 			amdgpu_vm_bo_relocated(bo_base);
265641ec0267Sriastradh 		else if (bo->tbo.base.resv == vm->root.base.bo->tbo.base.resv)
265741ec0267Sriastradh 			amdgpu_vm_bo_moved(bo_base);
265841ec0267Sriastradh 		else
265941ec0267Sriastradh 			amdgpu_vm_bo_invalidated(bo_base);
266041ec0267Sriastradh 	}
266141ec0267Sriastradh }
266241ec0267Sriastradh 
266341ec0267Sriastradh /**
266441ec0267Sriastradh  * amdgpu_vm_get_block_size - calculate VM page table size as power of two
266541ec0267Sriastradh  *
266641ec0267Sriastradh  * @vm_size: VM size
266741ec0267Sriastradh  *
266841ec0267Sriastradh  * Returns:
266941ec0267Sriastradh  * VM page table as power of two
267041ec0267Sriastradh  */
amdgpu_vm_get_block_size(uint64_t vm_size)267141ec0267Sriastradh static uint32_t amdgpu_vm_get_block_size(uint64_t vm_size)
267241ec0267Sriastradh {
267341ec0267Sriastradh 	/* Total bits covered by PD + PTs */
267441ec0267Sriastradh 	unsigned bits = ilog2(vm_size) + 18;
267541ec0267Sriastradh 
267641ec0267Sriastradh 	/* Make sure the PD is 4K in size up to 8GB address space.
267741ec0267Sriastradh 	   Above that split equal between PD and PTs */
267841ec0267Sriastradh 	if (vm_size <= 8)
267941ec0267Sriastradh 		return (bits - 9);
268041ec0267Sriastradh 	else
268141ec0267Sriastradh 		return ((bits + 3) / 2);
268241ec0267Sriastradh }
268341ec0267Sriastradh 
268441ec0267Sriastradh /**
268541ec0267Sriastradh  * amdgpu_vm_adjust_size - adjust vm size, block size and fragment size
268641ec0267Sriastradh  *
268741ec0267Sriastradh  * @adev: amdgpu_device pointer
268841ec0267Sriastradh  * @min_vm_size: the minimum vm size in GB if it's set auto
268941ec0267Sriastradh  * @fragment_size_default: Default PTE fragment size
269041ec0267Sriastradh  * @max_level: max VMPT level
269141ec0267Sriastradh  * @max_bits: max address space size in bits
269241ec0267Sriastradh  *
269341ec0267Sriastradh  */
amdgpu_vm_adjust_size(struct amdgpu_device * adev,uint32_t min_vm_size,uint32_t fragment_size_default,unsigned max_level,unsigned max_bits)269441ec0267Sriastradh void amdgpu_vm_adjust_size(struct amdgpu_device *adev, uint32_t min_vm_size,
269541ec0267Sriastradh 			   uint32_t fragment_size_default, unsigned max_level,
269641ec0267Sriastradh 			   unsigned max_bits)
269741ec0267Sriastradh {
269841ec0267Sriastradh 	unsigned int max_size = 1 << (max_bits - 30);
269941ec0267Sriastradh 	unsigned int vm_size;
270041ec0267Sriastradh 	uint64_t tmp;
270141ec0267Sriastradh 
270241ec0267Sriastradh 	/* adjust vm size first */
270341ec0267Sriastradh 	if (amdgpu_vm_size != -1) {
270441ec0267Sriastradh 		vm_size = amdgpu_vm_size;
270541ec0267Sriastradh 		if (vm_size > max_size) {
270641ec0267Sriastradh 			dev_warn(adev->dev, "VM size (%d) too large, max is %u GB\n",
270741ec0267Sriastradh 				 amdgpu_vm_size, max_size);
270841ec0267Sriastradh 			vm_size = max_size;
270941ec0267Sriastradh 		}
271041ec0267Sriastradh 	} else {
271141ec0267Sriastradh 		struct sysinfo si;
271241ec0267Sriastradh 		unsigned int phys_ram_gb;
271341ec0267Sriastradh 
271441ec0267Sriastradh 		/* Optimal VM size depends on the amount of physical
271541ec0267Sriastradh 		 * RAM available. Underlying requirements and
271641ec0267Sriastradh 		 * assumptions:
271741ec0267Sriastradh 		 *
271841ec0267Sriastradh 		 *  - Need to map system memory and VRAM from all GPUs
271941ec0267Sriastradh 		 *     - VRAM from other GPUs not known here
272041ec0267Sriastradh 		 *     - Assume VRAM <= system memory
272141ec0267Sriastradh 		 *  - On GFX8 and older, VM space can be segmented for
272241ec0267Sriastradh 		 *    different MTYPEs
272341ec0267Sriastradh 		 *  - Need to allow room for fragmentation, guard pages etc.
272441ec0267Sriastradh 		 *
272541ec0267Sriastradh 		 * This adds up to a rough guess of system memory x3.
272641ec0267Sriastradh 		 * Round up to power of two to maximize the available
272741ec0267Sriastradh 		 * VM size with the given page table size.
272841ec0267Sriastradh 		 */
272941ec0267Sriastradh 		si_meminfo(&si);
273041ec0267Sriastradh 		phys_ram_gb = ((uint64_t)si.totalram * si.mem_unit +
273141ec0267Sriastradh 			       (1 << 30) - 1) >> 30;
273241ec0267Sriastradh 		vm_size = roundup_pow_of_two(
273341ec0267Sriastradh 			min(max(phys_ram_gb * 3, min_vm_size), max_size));
273441ec0267Sriastradh 	}
273541ec0267Sriastradh 
273641ec0267Sriastradh 	adev->vm_manager.max_pfn = (uint64_t)vm_size << 18;
273741ec0267Sriastradh 
273841ec0267Sriastradh 	tmp = roundup_pow_of_two(adev->vm_manager.max_pfn);
273941ec0267Sriastradh 	if (amdgpu_vm_block_size != -1)
274041ec0267Sriastradh 		tmp >>= amdgpu_vm_block_size - 9;
274141ec0267Sriastradh 	tmp = DIV_ROUND_UP(fls64(tmp) - 1, 9) - 1;
274241ec0267Sriastradh 	adev->vm_manager.num_level = min(max_level, (unsigned)tmp);
274341ec0267Sriastradh 	switch (adev->vm_manager.num_level) {
274441ec0267Sriastradh 	case 3:
274541ec0267Sriastradh 		adev->vm_manager.root_level = AMDGPU_VM_PDB2;
274641ec0267Sriastradh 		break;
274741ec0267Sriastradh 	case 2:
274841ec0267Sriastradh 		adev->vm_manager.root_level = AMDGPU_VM_PDB1;
274941ec0267Sriastradh 		break;
275041ec0267Sriastradh 	case 1:
275141ec0267Sriastradh 		adev->vm_manager.root_level = AMDGPU_VM_PDB0;
275241ec0267Sriastradh 		break;
275341ec0267Sriastradh 	default:
275441ec0267Sriastradh 		dev_err(adev->dev, "VMPT only supports 2~4+1 levels\n");
275541ec0267Sriastradh 	}
275641ec0267Sriastradh 	/* block size depends on vm size and hw setup*/
275741ec0267Sriastradh 	if (amdgpu_vm_block_size != -1)
275841ec0267Sriastradh 		adev->vm_manager.block_size =
275941ec0267Sriastradh 			min((unsigned)amdgpu_vm_block_size, max_bits
276041ec0267Sriastradh 			    - AMDGPU_GPU_PAGE_SHIFT
276141ec0267Sriastradh 			    - 9 * adev->vm_manager.num_level);
276241ec0267Sriastradh 	else if (adev->vm_manager.num_level > 1)
276341ec0267Sriastradh 		adev->vm_manager.block_size = 9;
276441ec0267Sriastradh 	else
276541ec0267Sriastradh 		adev->vm_manager.block_size = amdgpu_vm_get_block_size(tmp);
276641ec0267Sriastradh 
276741ec0267Sriastradh 	if (amdgpu_vm_fragment_size == -1)
276841ec0267Sriastradh 		adev->vm_manager.fragment_size = fragment_size_default;
276941ec0267Sriastradh 	else
277041ec0267Sriastradh 		adev->vm_manager.fragment_size = amdgpu_vm_fragment_size;
277141ec0267Sriastradh 
277241ec0267Sriastradh 	DRM_INFO("vm size is %u GB, %u levels, block size is %u-bit, fragment size is %u-bit\n",
277341ec0267Sriastradh 		 vm_size, adev->vm_manager.num_level + 1,
277441ec0267Sriastradh 		 adev->vm_manager.block_size,
277541ec0267Sriastradh 		 adev->vm_manager.fragment_size);
277641ec0267Sriastradh }
277741ec0267Sriastradh 
277841ec0267Sriastradh /**
277941ec0267Sriastradh  * amdgpu_vm_wait_idle - wait for the VM to become idle
278041ec0267Sriastradh  *
278141ec0267Sriastradh  * @vm: VM object to wait for
278241ec0267Sriastradh  * @timeout: timeout to wait for VM to become idle
278341ec0267Sriastradh  */
amdgpu_vm_wait_idle(struct amdgpu_vm * vm,long timeout)278441ec0267Sriastradh long amdgpu_vm_wait_idle(struct amdgpu_vm *vm, long timeout)
278541ec0267Sriastradh {
278641ec0267Sriastradh 	timeout = dma_resv_wait_timeout_rcu(vm->root.base.bo->tbo.base.resv,
278741ec0267Sriastradh 					    true, true, timeout);
278841ec0267Sriastradh 	if (timeout <= 0)
278941ec0267Sriastradh 		return timeout;
279041ec0267Sriastradh 
279141ec0267Sriastradh 	timeout = dma_fence_wait_timeout(vm->last_direct, true, timeout);
279241ec0267Sriastradh 	if (timeout <= 0)
279341ec0267Sriastradh 		return timeout;
279441ec0267Sriastradh 
279541ec0267Sriastradh 	return dma_fence_wait_timeout(vm->last_delayed, true, timeout);
2796efa246c0Sriastradh }
2797efa246c0Sriastradh 
2798efa246c0Sriastradh /**
2799efa246c0Sriastradh  * amdgpu_vm_init - initialize a vm instance
2800efa246c0Sriastradh  *
2801efa246c0Sriastradh  * @adev: amdgpu_device pointer
2802efa246c0Sriastradh  * @vm: requested vm
280341ec0267Sriastradh  * @vm_context: Indicates if it GFX or Compute context
280441ec0267Sriastradh  * @pasid: Process address space identifier
2805efa246c0Sriastradh  *
280641ec0267Sriastradh  * Init @vm fields.
280741ec0267Sriastradh  *
280841ec0267Sriastradh  * Returns:
280941ec0267Sriastradh  * 0 for success, error for failure.
2810efa246c0Sriastradh  */
amdgpu_vm_init(struct amdgpu_device * adev,struct amdgpu_vm * vm,int vm_context,unsigned int pasid)281141ec0267Sriastradh int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
281241ec0267Sriastradh 		   int vm_context, unsigned int pasid)
2813efa246c0Sriastradh {
281441ec0267Sriastradh 	struct amdgpu_bo_param bp;
281541ec0267Sriastradh 	struct amdgpu_bo *root;
281641ec0267Sriastradh 	int r, i;
2817efa246c0Sriastradh 
28180d50c49dSriastradh #ifdef __NetBSD__
281943e663d0Sriastradh 	amdgpu_vm_it_init(&vm->va);
28200d50c49dSriastradh #else
282141ec0267Sriastradh 	vm->va = RB_ROOT_CACHED;
28220d50c49dSriastradh #endif
282341ec0267Sriastradh 	for (i = 0; i < AMDGPU_MAX_VMHUBS; i++)
282441ec0267Sriastradh 		vm->reserved_vmid[i] = NULL;
282541ec0267Sriastradh 	INIT_LIST_HEAD(&vm->evicted);
282641ec0267Sriastradh 	INIT_LIST_HEAD(&vm->relocated);
282741ec0267Sriastradh 	INIT_LIST_HEAD(&vm->moved);
282841ec0267Sriastradh 	INIT_LIST_HEAD(&vm->idle);
2829efa246c0Sriastradh 	INIT_LIST_HEAD(&vm->invalidated);
283041ec0267Sriastradh 	spin_lock_init(&vm->invalidated_lock);
2831efa246c0Sriastradh 	INIT_LIST_HEAD(&vm->freed);
2832efa246c0Sriastradh 
2833efa246c0Sriastradh 
283441ec0267Sriastradh 	/* create scheduler entities for page table updates */
283541ec0267Sriastradh 	r = drm_sched_entity_init(&vm->direct, DRM_SCHED_PRIORITY_NORMAL,
283641ec0267Sriastradh 				  adev->vm_manager.vm_pte_scheds,
283741ec0267Sriastradh 				  adev->vm_manager.vm_pte_num_scheds, NULL);
2838efa246c0Sriastradh 	if (r)
2839311f9dbbSriastradh 		goto error_free_destroylock;
284041ec0267Sriastradh 
284141ec0267Sriastradh 	r = drm_sched_entity_init(&vm->delayed, DRM_SCHED_PRIORITY_NORMAL,
284241ec0267Sriastradh 				  adev->vm_manager.vm_pte_scheds,
284341ec0267Sriastradh 				  adev->vm_manager.vm_pte_num_scheds, NULL);
284441ec0267Sriastradh 	if (r)
284541ec0267Sriastradh 		goto error_free_direct;
284641ec0267Sriastradh 
284741ec0267Sriastradh 	vm->pte_support_ats = false;
284841ec0267Sriastradh 	vm->is_compute_context = false;
284941ec0267Sriastradh 
285041ec0267Sriastradh 	if (vm_context == AMDGPU_VM_CONTEXT_COMPUTE) {
285141ec0267Sriastradh 		vm->use_cpu_for_update = !!(adev->vm_manager.vm_update_mode &
285241ec0267Sriastradh 						AMDGPU_VM_USE_CPU_FOR_COMPUTE);
285341ec0267Sriastradh 
285441ec0267Sriastradh 		if (adev->asic_type == CHIP_RAVEN)
285541ec0267Sriastradh 			vm->pte_support_ats = true;
285641ec0267Sriastradh 	} else {
285741ec0267Sriastradh 		vm->use_cpu_for_update = !!(adev->vm_manager.vm_update_mode &
285841ec0267Sriastradh 						AMDGPU_VM_USE_CPU_FOR_GFX);
285941ec0267Sriastradh 	}
286041ec0267Sriastradh 	DRM_DEBUG_DRIVER("VM update mode is %s\n",
286141ec0267Sriastradh 			 vm->use_cpu_for_update ? "CPU" : "SDMA");
286241ec0267Sriastradh 	WARN_ONCE((vm->use_cpu_for_update &&
286341ec0267Sriastradh 		   !amdgpu_gmc_vram_full_visible(&adev->gmc)),
286441ec0267Sriastradh 		  "CPU update of VM recommended only for large BAR system\n");
286541ec0267Sriastradh 
286641ec0267Sriastradh 	if (vm->use_cpu_for_update)
286741ec0267Sriastradh 		vm->update_funcs = &amdgpu_vm_cpu_funcs;
286841ec0267Sriastradh 	else
286941ec0267Sriastradh 		vm->update_funcs = &amdgpu_vm_sdma_funcs;
287041ec0267Sriastradh 	vm->last_update = NULL;
287141ec0267Sriastradh 	vm->last_direct = dma_fence_get_stub();
287241ec0267Sriastradh 	vm->last_delayed = dma_fence_get_stub();
287341ec0267Sriastradh 
287441ec0267Sriastradh 	mutex_init(&vm->eviction_lock);
287541ec0267Sriastradh 	vm->evicting = false;
287641ec0267Sriastradh 
287741ec0267Sriastradh 	amdgpu_vm_bo_param(adev, vm, adev->vm_manager.root_level, false, &bp);
287841ec0267Sriastradh 	if (vm_context == AMDGPU_VM_CONTEXT_COMPUTE)
287941ec0267Sriastradh 		bp.flags &= ~AMDGPU_GEM_CREATE_SHADOW;
288041ec0267Sriastradh 	r = amdgpu_bo_create(adev, &bp, &root);
288141ec0267Sriastradh 	if (r)
288241ec0267Sriastradh 		goto error_free_delayed;
288341ec0267Sriastradh 
288441ec0267Sriastradh 	r = amdgpu_bo_reserve(root, true);
288541ec0267Sriastradh 	if (r)
288641ec0267Sriastradh 		goto error_free_root;
288741ec0267Sriastradh 
288841ec0267Sriastradh 	r = dma_resv_reserve_shared(root->tbo.base.resv, 1);
288941ec0267Sriastradh 	if (r)
289041ec0267Sriastradh 		goto error_unreserve;
289141ec0267Sriastradh 
289241ec0267Sriastradh 	amdgpu_vm_bo_base_init(&vm->root.base, vm, root);
289341ec0267Sriastradh 
289441ec0267Sriastradh 	r = amdgpu_vm_clear_bo(adev, vm, root, false);
289541ec0267Sriastradh 	if (r)
289641ec0267Sriastradh 		goto error_unreserve;
289741ec0267Sriastradh 
289841ec0267Sriastradh 	amdgpu_bo_unreserve(vm->root.base.bo);
289941ec0267Sriastradh 
290041ec0267Sriastradh 	if (pasid) {
290141ec0267Sriastradh 		unsigned long flags;
290241ec0267Sriastradh 
290396323d83Sriastradh 		idr_preload(GFP_ATOMIC);
290441ec0267Sriastradh 		spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags);
290541ec0267Sriastradh 		r = idr_alloc(&adev->vm_manager.pasid_idr, vm, pasid, pasid + 1,
290641ec0267Sriastradh 			      GFP_ATOMIC);
290741ec0267Sriastradh 		spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
290896323d83Sriastradh 		idr_preload_end();
290941ec0267Sriastradh 		if (r < 0)
291041ec0267Sriastradh 			goto error_free_root;
291141ec0267Sriastradh 
291241ec0267Sriastradh 		vm->pasid = pasid;
291341ec0267Sriastradh 	}
291441ec0267Sriastradh 
291541ec0267Sriastradh 	INIT_KFIFO(vm->faults);
291641ec0267Sriastradh 
291741ec0267Sriastradh 	return 0;
291841ec0267Sriastradh 
291941ec0267Sriastradh error_unreserve:
292041ec0267Sriastradh 	amdgpu_bo_unreserve(vm->root.base.bo);
292141ec0267Sriastradh 
292241ec0267Sriastradh error_free_root:
292341ec0267Sriastradh 	amdgpu_bo_unref(&vm->root.base.bo->shadow);
292441ec0267Sriastradh 	amdgpu_bo_unref(&vm->root.base.bo);
292541ec0267Sriastradh 	vm->root.base.bo = NULL;
292641ec0267Sriastradh 
292741ec0267Sriastradh error_free_delayed:
292841ec0267Sriastradh 	dma_fence_put(vm->last_direct);
292941ec0267Sriastradh 	dma_fence_put(vm->last_delayed);
293041ec0267Sriastradh 	drm_sched_entity_destroy(&vm->delayed);
2931311f9dbbSriastradh 	mutex_destroy(&vm->eviction_lock);
293241ec0267Sriastradh 
293341ec0267Sriastradh error_free_direct:
293441ec0267Sriastradh 	drm_sched_entity_destroy(&vm->direct);
293541ec0267Sriastradh 
2936311f9dbbSriastradh error_free_destroylock:
2937311f9dbbSriastradh 	spin_lock_destroy(&vm->invalidated_lock);
2938311f9dbbSriastradh 
2939efa246c0Sriastradh 	return r;
2940efa246c0Sriastradh }
294141ec0267Sriastradh 
294241ec0267Sriastradh /**
294341ec0267Sriastradh  * amdgpu_vm_check_clean_reserved - check if a VM is clean
294441ec0267Sriastradh  *
294541ec0267Sriastradh  * @adev: amdgpu_device pointer
294641ec0267Sriastradh  * @vm: the VM to check
294741ec0267Sriastradh  *
294841ec0267Sriastradh  * check all entries of the root PD, if any subsequent PDs are allocated,
294941ec0267Sriastradh  * it means there are page table creating and filling, and is no a clean
295041ec0267Sriastradh  * VM
295141ec0267Sriastradh  *
295241ec0267Sriastradh  * Returns:
295341ec0267Sriastradh  *	0 if this VM is clean
295441ec0267Sriastradh  */
amdgpu_vm_check_clean_reserved(struct amdgpu_device * adev,struct amdgpu_vm * vm)295541ec0267Sriastradh static int amdgpu_vm_check_clean_reserved(struct amdgpu_device *adev,
295641ec0267Sriastradh 	struct amdgpu_vm *vm)
295741ec0267Sriastradh {
295841ec0267Sriastradh 	enum amdgpu_vm_level root = adev->vm_manager.root_level;
295941ec0267Sriastradh 	unsigned int entries = amdgpu_vm_num_entries(adev, root);
296041ec0267Sriastradh 	unsigned int i = 0;
296141ec0267Sriastradh 
296241ec0267Sriastradh 	if (!(vm->root.entries))
296341ec0267Sriastradh 		return 0;
296441ec0267Sriastradh 
296541ec0267Sriastradh 	for (i = 0; i < entries; i++) {
296641ec0267Sriastradh 		if (vm->root.entries[i].base.bo)
296741ec0267Sriastradh 			return -EINVAL;
2968efa246c0Sriastradh 	}
2969efa246c0Sriastradh 
2970efa246c0Sriastradh 	return 0;
2971efa246c0Sriastradh }
2972efa246c0Sriastradh 
2973efa246c0Sriastradh /**
297441ec0267Sriastradh  * amdgpu_vm_make_compute - Turn a GFX VM into a compute VM
297541ec0267Sriastradh  *
297641ec0267Sriastradh  * @adev: amdgpu_device pointer
297741ec0267Sriastradh  * @vm: requested vm
297841ec0267Sriastradh  * @pasid: pasid to use
297941ec0267Sriastradh  *
298041ec0267Sriastradh  * This only works on GFX VMs that don't have any BOs added and no
298141ec0267Sriastradh  * page tables allocated yet.
298241ec0267Sriastradh  *
298341ec0267Sriastradh  * Changes the following VM parameters:
298441ec0267Sriastradh  * - use_cpu_for_update
298541ec0267Sriastradh  * - pte_supports_ats
298641ec0267Sriastradh  * - pasid (old PASID is released, because compute manages its own PASIDs)
298741ec0267Sriastradh  *
298841ec0267Sriastradh  * Reinitializes the page directory to reflect the changed ATS
298941ec0267Sriastradh  * setting.
299041ec0267Sriastradh  *
299141ec0267Sriastradh  * Returns:
299241ec0267Sriastradh  * 0 for success, -errno for errors.
299341ec0267Sriastradh  */
amdgpu_vm_make_compute(struct amdgpu_device * adev,struct amdgpu_vm * vm,unsigned int pasid)299441ec0267Sriastradh int amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm,
299541ec0267Sriastradh 			   unsigned int pasid)
299641ec0267Sriastradh {
299741ec0267Sriastradh 	bool pte_support_ats = (adev->asic_type == CHIP_RAVEN);
299841ec0267Sriastradh 	int r;
299941ec0267Sriastradh 
300041ec0267Sriastradh 	r = amdgpu_bo_reserve(vm->root.base.bo, true);
300141ec0267Sriastradh 	if (r)
300241ec0267Sriastradh 		return r;
300341ec0267Sriastradh 
300441ec0267Sriastradh 	/* Sanity checks */
300541ec0267Sriastradh 	r = amdgpu_vm_check_clean_reserved(adev, vm);
300641ec0267Sriastradh 	if (r)
300741ec0267Sriastradh 		goto unreserve_bo;
300841ec0267Sriastradh 
300941ec0267Sriastradh 	if (pasid) {
301041ec0267Sriastradh 		unsigned long flags;
301141ec0267Sriastradh 
301296323d83Sriastradh 		idr_preload(GFP_ATOMIC);
301341ec0267Sriastradh 		spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags);
301441ec0267Sriastradh 		r = idr_alloc(&adev->vm_manager.pasid_idr, vm, pasid, pasid + 1,
301541ec0267Sriastradh 			      GFP_ATOMIC);
301641ec0267Sriastradh 		spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
301796323d83Sriastradh 		idr_preload_end();
301841ec0267Sriastradh 
301941ec0267Sriastradh 		if (r == -ENOSPC)
302041ec0267Sriastradh 			goto unreserve_bo;
302141ec0267Sriastradh 		r = 0;
302241ec0267Sriastradh 	}
302341ec0267Sriastradh 
302441ec0267Sriastradh 	/* Check if PD needs to be reinitialized and do it before
302541ec0267Sriastradh 	 * changing any other state, in case it fails.
302641ec0267Sriastradh 	 */
302741ec0267Sriastradh 	if (pte_support_ats != vm->pte_support_ats) {
302841ec0267Sriastradh 		vm->pte_support_ats = pte_support_ats;
302941ec0267Sriastradh 		r = amdgpu_vm_clear_bo(adev, vm, vm->root.base.bo, false);
303041ec0267Sriastradh 		if (r)
303141ec0267Sriastradh 			goto free_idr;
303241ec0267Sriastradh 	}
303341ec0267Sriastradh 
303441ec0267Sriastradh 	/* Update VM state */
303541ec0267Sriastradh 	vm->use_cpu_for_update = !!(adev->vm_manager.vm_update_mode &
303641ec0267Sriastradh 				    AMDGPU_VM_USE_CPU_FOR_COMPUTE);
303741ec0267Sriastradh 	DRM_DEBUG_DRIVER("VM update mode is %s\n",
303841ec0267Sriastradh 			 vm->use_cpu_for_update ? "CPU" : "SDMA");
303941ec0267Sriastradh 	WARN_ONCE((vm->use_cpu_for_update &&
304041ec0267Sriastradh 		   !amdgpu_gmc_vram_full_visible(&adev->gmc)),
304141ec0267Sriastradh 		  "CPU update of VM recommended only for large BAR system\n");
304241ec0267Sriastradh 
304341ec0267Sriastradh 	if (vm->use_cpu_for_update)
304441ec0267Sriastradh 		vm->update_funcs = &amdgpu_vm_cpu_funcs;
304541ec0267Sriastradh 	else
304641ec0267Sriastradh 		vm->update_funcs = &amdgpu_vm_sdma_funcs;
304741ec0267Sriastradh 	dma_fence_put(vm->last_update);
304841ec0267Sriastradh 	vm->last_update = NULL;
304941ec0267Sriastradh 	vm->is_compute_context = true;
305041ec0267Sriastradh 
305141ec0267Sriastradh 	if (vm->pasid) {
305241ec0267Sriastradh 		unsigned long flags;
305341ec0267Sriastradh 
305441ec0267Sriastradh 		spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags);
305541ec0267Sriastradh 		idr_remove(&adev->vm_manager.pasid_idr, vm->pasid);
305641ec0267Sriastradh 		spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
305741ec0267Sriastradh 
305841ec0267Sriastradh 		/* Free the original amdgpu allocated pasid
305941ec0267Sriastradh 		 * Will be replaced with kfd allocated pasid
306041ec0267Sriastradh 		 */
306141ec0267Sriastradh 		amdgpu_pasid_free(vm->pasid);
306241ec0267Sriastradh 		vm->pasid = 0;
306341ec0267Sriastradh 	}
306441ec0267Sriastradh 
306541ec0267Sriastradh 	/* Free the shadow bo for compute VM */
306641ec0267Sriastradh 	amdgpu_bo_unref(&vm->root.base.bo->shadow);
306741ec0267Sriastradh 
306841ec0267Sriastradh 	if (pasid)
306941ec0267Sriastradh 		vm->pasid = pasid;
307041ec0267Sriastradh 
307141ec0267Sriastradh 	goto unreserve_bo;
307241ec0267Sriastradh 
307341ec0267Sriastradh free_idr:
307441ec0267Sriastradh 	if (pasid) {
307541ec0267Sriastradh 		unsigned long flags;
307641ec0267Sriastradh 
307741ec0267Sriastradh 		spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags);
307841ec0267Sriastradh 		idr_remove(&adev->vm_manager.pasid_idr, pasid);
307941ec0267Sriastradh 		spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
308041ec0267Sriastradh 	}
308141ec0267Sriastradh unreserve_bo:
308241ec0267Sriastradh 	amdgpu_bo_unreserve(vm->root.base.bo);
308341ec0267Sriastradh 	return r;
308441ec0267Sriastradh }
308541ec0267Sriastradh 
308641ec0267Sriastradh /**
308741ec0267Sriastradh  * amdgpu_vm_release_compute - release a compute vm
308841ec0267Sriastradh  * @adev: amdgpu_device pointer
308941ec0267Sriastradh  * @vm: a vm turned into compute vm by calling amdgpu_vm_make_compute
309041ec0267Sriastradh  *
309141ec0267Sriastradh  * This is a correspondant of amdgpu_vm_make_compute. It decouples compute
309241ec0267Sriastradh  * pasid from vm. Compute should stop use of vm after this call.
309341ec0267Sriastradh  */
amdgpu_vm_release_compute(struct amdgpu_device * adev,struct amdgpu_vm * vm)309441ec0267Sriastradh void amdgpu_vm_release_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm)
309541ec0267Sriastradh {
309641ec0267Sriastradh 	if (vm->pasid) {
309741ec0267Sriastradh 		unsigned long flags;
309841ec0267Sriastradh 
309941ec0267Sriastradh 		spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags);
310041ec0267Sriastradh 		idr_remove(&adev->vm_manager.pasid_idr, vm->pasid);
310141ec0267Sriastradh 		spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
310241ec0267Sriastradh 	}
310341ec0267Sriastradh 	vm->pasid = 0;
310441ec0267Sriastradh 	vm->is_compute_context = false;
310541ec0267Sriastradh }
310641ec0267Sriastradh 
310741ec0267Sriastradh /**
3108efa246c0Sriastradh  * amdgpu_vm_fini - tear down a vm instance
3109efa246c0Sriastradh  *
3110efa246c0Sriastradh  * @adev: amdgpu_device pointer
3111efa246c0Sriastradh  * @vm: requested vm
3112efa246c0Sriastradh  *
311341ec0267Sriastradh  * Tear down @vm.
3114efa246c0Sriastradh  * Unbind the VM and remove all bos from the vm bo list
3115efa246c0Sriastradh  */
amdgpu_vm_fini(struct amdgpu_device * adev,struct amdgpu_vm * vm)3116efa246c0Sriastradh void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
3117efa246c0Sriastradh {
3118efa246c0Sriastradh 	struct amdgpu_bo_va_mapping *mapping, *tmp;
311941ec0267Sriastradh 	bool prt_fini_needed = !!adev->gmc.gmc_funcs->set_prt;
312041ec0267Sriastradh 	struct amdgpu_bo *root;
3121efa246c0Sriastradh 	int i;
3122efa246c0Sriastradh 
31233d10c246Sriastradh 	FINI_KFIFO(vm->faults);
31243d10c246Sriastradh 
312541ec0267Sriastradh 	amdgpu_amdkfd_gpuvm_destroy_cb(adev, vm);
312641ec0267Sriastradh 
312741ec0267Sriastradh 	root = amdgpu_bo_ref(vm->root.base.bo);
312841ec0267Sriastradh 	amdgpu_bo_reserve(root, true);
312941ec0267Sriastradh 	if (vm->pasid) {
313041ec0267Sriastradh 		unsigned long flags;
313141ec0267Sriastradh 
313241ec0267Sriastradh 		spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags);
313341ec0267Sriastradh 		idr_remove(&adev->vm_manager.pasid_idr, vm->pasid);
313441ec0267Sriastradh 		spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
313541ec0267Sriastradh 		vm->pasid = 0;
313641ec0267Sriastradh 	}
313741ec0267Sriastradh 
313841ec0267Sriastradh 	dma_fence_wait(vm->last_direct, false);
313941ec0267Sriastradh 	dma_fence_put(vm->last_direct);
314041ec0267Sriastradh 	dma_fence_wait(vm->last_delayed, false);
314141ec0267Sriastradh 	dma_fence_put(vm->last_delayed);
314241ec0267Sriastradh 
314341ec0267Sriastradh 	list_for_each_entry_safe(mapping, tmp, &vm->freed, list) {
314441ec0267Sriastradh 		if (mapping->flags & AMDGPU_PTE_PRT && prt_fini_needed) {
314541ec0267Sriastradh 			amdgpu_vm_prt_fini(adev, vm);
314641ec0267Sriastradh 			prt_fini_needed = false;
314741ec0267Sriastradh 		}
314841ec0267Sriastradh 
314941ec0267Sriastradh 		list_del(&mapping->list);
315041ec0267Sriastradh 		amdgpu_vm_free_mapping(adev, vm, mapping, NULL);
315141ec0267Sriastradh 	}
315241ec0267Sriastradh 
315341ec0267Sriastradh 	amdgpu_vm_free_pts(adev, vm, NULL);
315441ec0267Sriastradh 	amdgpu_bo_unreserve(root);
315541ec0267Sriastradh 	amdgpu_bo_unref(&root);
315641ec0267Sriastradh 	WARN_ON(vm->root.base.bo);
315741ec0267Sriastradh 
315841ec0267Sriastradh 	drm_sched_entity_destroy(&vm->direct);
315941ec0267Sriastradh 	drm_sched_entity_destroy(&vm->delayed);
316041ec0267Sriastradh 
316141ec0267Sriastradh 	if (!RB_EMPTY_ROOT(&vm->va.rb_root)) {
3162efa246c0Sriastradh 		dev_err(adev->dev, "still active bo inside vm\n");
3163efa246c0Sriastradh 	}
316441ec0267Sriastradh 	rbtree_postorder_for_each_entry_safe(mapping, tmp,
316541ec0267Sriastradh 					     &vm->va.rb_root, rb) {
316641ec0267Sriastradh 		/* Don't remove the mapping here, we don't want to trigger a
316741ec0267Sriastradh 		 * rebalance and the tree is about to be destroyed anyway.
316841ec0267Sriastradh 		 */
3169efa246c0Sriastradh 		list_del(&mapping->list);
3170efa246c0Sriastradh 		kfree(mapping);
3171efa246c0Sriastradh 	}
3172efa246c0Sriastradh 
317341ec0267Sriastradh 	dma_fence_put(vm->last_update);
317441ec0267Sriastradh 	for (i = 0; i < AMDGPU_MAX_VMHUBS; i++)
317541ec0267Sriastradh 		amdgpu_vmid_free_reserved(adev, vm, i);
317607eb61ceSriastradh 
31773d10c246Sriastradh 	mutex_destroy(&vm->eviction_lock);
317807eb61ceSriastradh 	spin_lock_destroy(&vm->invalidated_lock);
3179efa246c0Sriastradh }
3180efa246c0Sriastradh 
318141ec0267Sriastradh /**
318241ec0267Sriastradh  * amdgpu_vm_manager_init - init the VM manager
318341ec0267Sriastradh  *
318441ec0267Sriastradh  * @adev: amdgpu_device pointer
318541ec0267Sriastradh  *
318641ec0267Sriastradh  * Initialize the VM manager structures
318741ec0267Sriastradh  */
amdgpu_vm_manager_init(struct amdgpu_device * adev)318841ec0267Sriastradh void amdgpu_vm_manager_init(struct amdgpu_device *adev)
318941ec0267Sriastradh {
319041ec0267Sriastradh 	unsigned i;
319141ec0267Sriastradh 
319241ec0267Sriastradh 	amdgpu_vmid_mgr_init(adev);
319341ec0267Sriastradh 
319441ec0267Sriastradh 	adev->vm_manager.fence_context =
319541ec0267Sriastradh 		dma_fence_context_alloc(AMDGPU_MAX_RINGS);
319641ec0267Sriastradh 	for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
319741ec0267Sriastradh 		adev->vm_manager.seqno[i] = 0;
319841ec0267Sriastradh 
319941ec0267Sriastradh 	spin_lock_init(&adev->vm_manager.prt_lock);
320041ec0267Sriastradh 	atomic_set(&adev->vm_manager.num_prt_users, 0);
320141ec0267Sriastradh 
320241ec0267Sriastradh 	/* If not overridden by the user, by default, only in large BAR systems
320341ec0267Sriastradh 	 * Compute VM tables will be updated by CPU
320441ec0267Sriastradh 	 */
320541ec0267Sriastradh #ifdef CONFIG_X86_64
320641ec0267Sriastradh 	if (amdgpu_vm_update_mode == -1) {
320741ec0267Sriastradh 		if (amdgpu_gmc_vram_full_visible(&adev->gmc))
320841ec0267Sriastradh 			adev->vm_manager.vm_update_mode =
320941ec0267Sriastradh 				AMDGPU_VM_USE_CPU_FOR_COMPUTE;
321041ec0267Sriastradh 		else
321141ec0267Sriastradh 			adev->vm_manager.vm_update_mode = 0;
321241ec0267Sriastradh 	} else
321341ec0267Sriastradh 		adev->vm_manager.vm_update_mode = amdgpu_vm_update_mode;
321441ec0267Sriastradh #else
321541ec0267Sriastradh 	adev->vm_manager.vm_update_mode = 0;
321641ec0267Sriastradh #endif
321741ec0267Sriastradh 
321841ec0267Sriastradh 	idr_init(&adev->vm_manager.pasid_idr);
321941ec0267Sriastradh 	spin_lock_init(&adev->vm_manager.pasid_lock);
322041ec0267Sriastradh 
322141ec0267Sriastradh 	adev->vm_manager.xgmi_map_counter = 0;
322241ec0267Sriastradh 	mutex_init(&adev->vm_manager.lock_pstate);
3223efa246c0Sriastradh }
3224efa246c0Sriastradh 
3225efa246c0Sriastradh /**
3226efa246c0Sriastradh  * amdgpu_vm_manager_fini - cleanup VM manager
3227efa246c0Sriastradh  *
3228efa246c0Sriastradh  * @adev: amdgpu_device pointer
3229efa246c0Sriastradh  *
3230efa246c0Sriastradh  * Cleanup the VM manager and free resources.
3231efa246c0Sriastradh  */
amdgpu_vm_manager_fini(struct amdgpu_device * adev)3232efa246c0Sriastradh void amdgpu_vm_manager_fini(struct amdgpu_device *adev)
3233efa246c0Sriastradh {
323407eb61ceSriastradh 	mutex_destroy(&adev->vm_manager.lock_pstate);
323507eb61ceSriastradh 	spin_lock_destroy(&adev->vm_manager.pasid_lock);
323641ec0267Sriastradh 	WARN_ON(!idr_is_empty(&adev->vm_manager.pasid_idr));
323741ec0267Sriastradh 	idr_destroy(&adev->vm_manager.pasid_idr);
3238efa246c0Sriastradh 
323941ec0267Sriastradh 	amdgpu_vmid_mgr_fini(adev);
324041ec0267Sriastradh }
324141ec0267Sriastradh 
324241ec0267Sriastradh /**
324341ec0267Sriastradh  * amdgpu_vm_ioctl - Manages VMID reservation for vm hubs.
324441ec0267Sriastradh  *
324541ec0267Sriastradh  * @dev: drm device pointer
324641ec0267Sriastradh  * @data: drm_amdgpu_vm
324741ec0267Sriastradh  * @filp: drm file pointer
324841ec0267Sriastradh  *
324941ec0267Sriastradh  * Returns:
325041ec0267Sriastradh  * 0 for success, -errno for errors.
325141ec0267Sriastradh  */
amdgpu_vm_ioctl(struct drm_device * dev,void * data,struct drm_file * filp)325241ec0267Sriastradh int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
325341ec0267Sriastradh {
325441ec0267Sriastradh 	union drm_amdgpu_vm *args = data;
325541ec0267Sriastradh 	struct amdgpu_device *adev = dev->dev_private;
325641ec0267Sriastradh 	struct amdgpu_fpriv *fpriv = filp->driver_priv;
325741ec0267Sriastradh 	int r;
325841ec0267Sriastradh 
325941ec0267Sriastradh 	switch (args->in.op) {
326041ec0267Sriastradh 	case AMDGPU_VM_OP_RESERVE_VMID:
326141ec0267Sriastradh 		/* We only have requirement to reserve vmid from gfxhub */
326241ec0267Sriastradh 		r = amdgpu_vmid_alloc_reserved(adev, &fpriv->vm,
326341ec0267Sriastradh 					       AMDGPU_GFXHUB_0);
326441ec0267Sriastradh 		if (r)
326541ec0267Sriastradh 			return r;
326641ec0267Sriastradh 		break;
326741ec0267Sriastradh 	case AMDGPU_VM_OP_UNRESERVE_VMID:
326841ec0267Sriastradh 		amdgpu_vmid_free_reserved(adev, &fpriv->vm, AMDGPU_GFXHUB_0);
326941ec0267Sriastradh 		break;
327041ec0267Sriastradh 	default:
327141ec0267Sriastradh 		return -EINVAL;
327241ec0267Sriastradh 	}
327341ec0267Sriastradh 
327441ec0267Sriastradh 	return 0;
327541ec0267Sriastradh }
327641ec0267Sriastradh 
327741ec0267Sriastradh /**
327841ec0267Sriastradh  * amdgpu_vm_get_task_info - Extracts task info for a PASID.
327941ec0267Sriastradh  *
328041ec0267Sriastradh  * @adev: drm device pointer
328141ec0267Sriastradh  * @pasid: PASID identifier for VM
328241ec0267Sriastradh  * @task_info: task_info to fill.
328341ec0267Sriastradh  */
amdgpu_vm_get_task_info(struct amdgpu_device * adev,unsigned int pasid,struct amdgpu_task_info * task_info)328441ec0267Sriastradh void amdgpu_vm_get_task_info(struct amdgpu_device *adev, unsigned int pasid,
328541ec0267Sriastradh 			 struct amdgpu_task_info *task_info)
328641ec0267Sriastradh {
328741ec0267Sriastradh 	struct amdgpu_vm *vm;
328841ec0267Sriastradh 	unsigned long flags;
328941ec0267Sriastradh 
329041ec0267Sriastradh 	spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags);
329141ec0267Sriastradh 
329241ec0267Sriastradh 	vm = idr_find(&adev->vm_manager.pasid_idr, pasid);
329341ec0267Sriastradh 	if (vm)
329441ec0267Sriastradh 		*task_info = vm->task_info;
329541ec0267Sriastradh 
329641ec0267Sriastradh 	spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
329741ec0267Sriastradh }
329841ec0267Sriastradh 
329941ec0267Sriastradh /**
330041ec0267Sriastradh  * amdgpu_vm_set_task_info - Sets VMs task info.
330141ec0267Sriastradh  *
330241ec0267Sriastradh  * @vm: vm for which to set the info
330341ec0267Sriastradh  */
amdgpu_vm_set_task_info(struct amdgpu_vm * vm)330441ec0267Sriastradh void amdgpu_vm_set_task_info(struct amdgpu_vm *vm)
330541ec0267Sriastradh {
330641ec0267Sriastradh 	if (vm->task_info.pid)
330741ec0267Sriastradh 		return;
330841ec0267Sriastradh 
3309*e8e95709Sriastradh #ifdef __NetBSD__
3310*e8e95709Sriastradh 	vm->task_info.pid = curlwp->l_proc->p_pid;
3311*e8e95709Sriastradh 	vm->task_info.tgid = curlwp->l_lid;
3312*e8e95709Sriastradh 	strlcpy(vm->task_info.process_name, curlwp->l_proc->p_comm,
3313*e8e95709Sriastradh 	    sizeof vm->task_info.process_name);
3314*e8e95709Sriastradh 	if (curlwp->l_name)
3315*e8e95709Sriastradh 		strlcpy(vm->task_info.task_name, curlwp->l_name,
3316*e8e95709Sriastradh 		    sizeof vm->task_info.task_name);
3317*e8e95709Sriastradh #else
331841ec0267Sriastradh 	vm->task_info.pid = current->pid;
331941ec0267Sriastradh 	get_task_comm(vm->task_info.task_name, current);
332041ec0267Sriastradh 
332141ec0267Sriastradh 	if (current->group_leader->mm != current->mm)
332241ec0267Sriastradh 		return;
332341ec0267Sriastradh 
332441ec0267Sriastradh 	vm->task_info.tgid = current->group_leader->pid;
332541ec0267Sriastradh 	get_task_comm(vm->task_info.process_name, current->group_leader);
332643e663d0Sriastradh #endif
332741ec0267Sriastradh }
332841ec0267Sriastradh 
332941ec0267Sriastradh /**
333041ec0267Sriastradh  * amdgpu_vm_handle_fault - graceful handling of VM faults.
333141ec0267Sriastradh  * @adev: amdgpu device pointer
333241ec0267Sriastradh  * @pasid: PASID of the VM
333341ec0267Sriastradh  * @addr: Address of the fault
333441ec0267Sriastradh  *
333541ec0267Sriastradh  * Try to gracefully handle a VM fault. Return true if the fault was handled and
333641ec0267Sriastradh  * shouldn't be reported any more.
333741ec0267Sriastradh  */
amdgpu_vm_handle_fault(struct amdgpu_device * adev,unsigned int pasid,uint64_t addr)333841ec0267Sriastradh bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, unsigned int pasid,
333941ec0267Sriastradh 			    uint64_t addr)
334041ec0267Sriastradh {
334141ec0267Sriastradh 	struct amdgpu_bo *root;
334241ec0267Sriastradh 	uint64_t value, flags;
334341ec0267Sriastradh 	struct amdgpu_vm *vm;
334441ec0267Sriastradh 	long r;
334541ec0267Sriastradh 
334641ec0267Sriastradh 	spin_lock(&adev->vm_manager.pasid_lock);
334741ec0267Sriastradh 	vm = idr_find(&adev->vm_manager.pasid_idr, pasid);
334841ec0267Sriastradh 	if (vm)
334941ec0267Sriastradh 		root = amdgpu_bo_ref(vm->root.base.bo);
335041ec0267Sriastradh 	else
335141ec0267Sriastradh 		root = NULL;
335241ec0267Sriastradh 	spin_unlock(&adev->vm_manager.pasid_lock);
335341ec0267Sriastradh 
335441ec0267Sriastradh 	if (!root)
335541ec0267Sriastradh 		return false;
335641ec0267Sriastradh 
335741ec0267Sriastradh 	r = amdgpu_bo_reserve(root, true);
335841ec0267Sriastradh 	if (r)
335941ec0267Sriastradh 		goto error_unref;
336041ec0267Sriastradh 
336141ec0267Sriastradh 	/* Double check that the VM still exists */
336241ec0267Sriastradh 	spin_lock(&adev->vm_manager.pasid_lock);
336341ec0267Sriastradh 	vm = idr_find(&adev->vm_manager.pasid_idr, pasid);
336441ec0267Sriastradh 	if (vm && vm->root.base.bo != root)
336541ec0267Sriastradh 		vm = NULL;
336641ec0267Sriastradh 	spin_unlock(&adev->vm_manager.pasid_lock);
336741ec0267Sriastradh 	if (!vm)
336841ec0267Sriastradh 		goto error_unlock;
336941ec0267Sriastradh 
337041ec0267Sriastradh 	addr /= AMDGPU_GPU_PAGE_SIZE;
337141ec0267Sriastradh 	flags = AMDGPU_PTE_VALID | AMDGPU_PTE_SNOOPED |
337241ec0267Sriastradh 		AMDGPU_PTE_SYSTEM;
337341ec0267Sriastradh 
337441ec0267Sriastradh 	if (vm->is_compute_context) {
337541ec0267Sriastradh 		/* Intentionally setting invalid PTE flag
337641ec0267Sriastradh 		 * combination to force a no-retry-fault
337741ec0267Sriastradh 		 */
337841ec0267Sriastradh 		flags = AMDGPU_PTE_EXECUTABLE | AMDGPU_PDE_PTE |
337941ec0267Sriastradh 			AMDGPU_PTE_TF;
338041ec0267Sriastradh 		value = 0;
338141ec0267Sriastradh 
338241ec0267Sriastradh 	} else if (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_NEVER) {
338341ec0267Sriastradh 		/* Redirect the access to the dummy page */
338441ec0267Sriastradh 		value = adev->dummy_page_addr;
338541ec0267Sriastradh 		flags |= AMDGPU_PTE_EXECUTABLE | AMDGPU_PTE_READABLE |
338641ec0267Sriastradh 			AMDGPU_PTE_WRITEABLE;
338741ec0267Sriastradh 
338841ec0267Sriastradh 	} else {
338941ec0267Sriastradh 		/* Let the hw retry silently on the PTE */
339041ec0267Sriastradh 		value = 0;
339141ec0267Sriastradh 	}
339241ec0267Sriastradh 
339341ec0267Sriastradh 	r = amdgpu_vm_bo_update_mapping(adev, vm, true, NULL, addr, addr + 1,
339441ec0267Sriastradh 					flags, value, NULL, NULL);
339541ec0267Sriastradh 	if (r)
339641ec0267Sriastradh 		goto error_unlock;
339741ec0267Sriastradh 
339841ec0267Sriastradh 	r = amdgpu_vm_update_pdes(adev, vm, true);
339941ec0267Sriastradh 
340041ec0267Sriastradh error_unlock:
340141ec0267Sriastradh 	amdgpu_bo_unreserve(root);
340241ec0267Sriastradh 	if (r < 0)
340341ec0267Sriastradh 		DRM_ERROR("Can't handle page fault (%ld)\n", r);
340441ec0267Sriastradh 
340541ec0267Sriastradh error_unref:
340641ec0267Sriastradh 	amdgpu_bo_unref(&root);
340741ec0267Sriastradh 
340841ec0267Sriastradh 	return false;
3409efa246c0Sriastradh }
3410