diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 75 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 14 |
5 files changed, 91 insertions, 4 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c index b9dbbf9cb8b0..dc7e25cce741 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c | |||
@@ -169,6 +169,8 @@ static const struct kfd2kgd_calls kfd2kgd = { | |||
169 | .get_vmem_size = get_vmem_size, | 169 | .get_vmem_size = get_vmem_size, |
170 | .get_gpu_clock_counter = get_gpu_clock_counter, | 170 | .get_gpu_clock_counter = get_gpu_clock_counter, |
171 | .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz, | 171 | .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz, |
172 | .alloc_pasid = amdgpu_vm_alloc_pasid, | ||
173 | .free_pasid = amdgpu_vm_free_pasid, | ||
172 | .program_sh_mem_settings = kgd_program_sh_mem_settings, | 174 | .program_sh_mem_settings = kgd_program_sh_mem_settings, |
173 | .set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping, | 175 | .set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping, |
174 | .init_pipeline = kgd_init_pipeline, | 176 | .init_pipeline = kgd_init_pipeline, |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c index 309f2419c6d8..c678c69936a0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c | |||
@@ -128,6 +128,8 @@ static const struct kfd2kgd_calls kfd2kgd = { | |||
128 | .get_vmem_size = get_vmem_size, | 128 | .get_vmem_size = get_vmem_size, |
129 | .get_gpu_clock_counter = get_gpu_clock_counter, | 129 | .get_gpu_clock_counter = get_gpu_clock_counter, |
130 | .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz, | 130 | .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz, |
131 | .alloc_pasid = amdgpu_vm_alloc_pasid, | ||
132 | .free_pasid = amdgpu_vm_free_pasid, | ||
131 | .program_sh_mem_settings = kgd_program_sh_mem_settings, | 133 | .program_sh_mem_settings = kgd_program_sh_mem_settings, |
132 | .set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping, | 134 | .set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping, |
133 | .init_pipeline = kgd_init_pipeline, | 135 | .init_pipeline = kgd_init_pipeline, |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index e16229000a98..79d9ab43d42c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | |||
@@ -825,7 +825,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) | |||
825 | } | 825 | } |
826 | 826 | ||
827 | r = amdgpu_vm_init(adev, &fpriv->vm, | 827 | r = amdgpu_vm_init(adev, &fpriv->vm, |
828 | AMDGPU_VM_CONTEXT_GFX); | 828 | AMDGPU_VM_CONTEXT_GFX, 0); |
829 | if (r) { | 829 | if (r) { |
830 | kfree(fpriv); | 830 | kfree(fpriv); |
831 | goto out_suspend; | 831 | goto out_suspend; |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 2196bca7331c..9b795915cab1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | |||
@@ -27,12 +27,59 @@ | |||
27 | */ | 27 | */ |
28 | #include <linux/dma-fence-array.h> | 28 | #include <linux/dma-fence-array.h> |
29 | #include <linux/interval_tree_generic.h> | 29 | #include <linux/interval_tree_generic.h> |
30 | #include <linux/idr.h> | ||
30 | #include <drm/drmP.h> | 31 | #include <drm/drmP.h> |
31 | #include <drm/amdgpu_drm.h> | 32 | #include <drm/amdgpu_drm.h> |
32 | #include "amdgpu.h" | 33 | #include "amdgpu.h" |
33 | #include "amdgpu_trace.h" | 34 | #include "amdgpu_trace.h" |
34 | 35 | ||
35 | /* | 36 | /* |
37 | * PASID manager | ||
38 | * | ||
39 | * PASIDs are global address space identifiers that can be shared | ||
40 | * between the GPU, an IOMMU and the driver. VMs on different devices | ||
41 | * may use the same PASID if they share the same address | ||
42 | * space. Therefore PASIDs are allocated using a global IDA. VMs are | ||
43 | * looked up from the PASID per amdgpu_device. | ||
44 | */ | ||
45 | static DEFINE_IDA(amdgpu_vm_pasid_ida); | ||
46 | |||
47 | /** | ||
48 | * amdgpu_vm_alloc_pasid - Allocate a PASID | ||
49 | * @bits: Maximum width of the PASID in bits, must be at least 1 | ||
50 | * | ||
51 | * Allocates a PASID of the given width while keeping smaller PASIDs | ||
52 | * available if possible. | ||
53 | * | ||
54 | * Returns a positive integer on success. Returns %-EINVAL if bits==0. | ||
55 | * Returns %-ENOSPC if no PASID was available. Returns %-ENOMEM on | ||
56 | * memory allocation failure. | ||
57 | */ | ||
58 | int amdgpu_vm_alloc_pasid(unsigned int bits) | ||
59 | { | ||
60 | int pasid = -EINVAL; | ||
61 | |||
62 | for (bits = min(bits, 31U); bits > 0; bits--) { | ||
63 | pasid = ida_simple_get(&amdgpu_vm_pasid_ida, | ||
64 | 1U << (bits - 1), 1U << bits, | ||
65 | GFP_KERNEL); | ||
66 | if (pasid != -ENOSPC) | ||
67 | break; | ||
68 | } | ||
69 | |||
70 | return pasid; | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * amdgpu_vm_free_pasid - Free a PASID | ||
75 | * @pasid: PASID to free | ||
76 | */ | ||
77 | void amdgpu_vm_free_pasid(unsigned int pasid) | ||
78 | { | ||
79 | ida_simple_remove(&amdgpu_vm_pasid_ida, pasid); | ||
80 | } | ||
81 | |||
82 | /* | ||
36 | * GPUVM | 83 | * GPUVM |
37 | * GPUVM is similar to the legacy gart on older asics, however | 84 | * GPUVM is similar to the legacy gart on older asics, however |
38 | * rather than there being a single global gart table | 85 | * rather than there being a single global gart table |
@@ -2539,7 +2586,7 @@ void amdgpu_vm_adjust_size(struct amdgpu_device *adev, uint64_t vm_size, uint32_ | |||
2539 | * Init @vm fields. | 2586 | * Init @vm fields. |
2540 | */ | 2587 | */ |
2541 | int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, | 2588 | int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, |
2542 | int vm_context) | 2589 | int vm_context, unsigned int pasid) |
2543 | { | 2590 | { |
2544 | const unsigned align = min(AMDGPU_VM_PTB_ALIGN_SIZE, | 2591 | const unsigned align = min(AMDGPU_VM_PTB_ALIGN_SIZE, |
2545 | AMDGPU_VM_PTE_COUNT(adev) * 8); | 2592 | AMDGPU_VM_PTE_COUNT(adev) * 8); |
@@ -2620,6 +2667,19 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, | |||
2620 | goto error_free_root; | 2667 | goto error_free_root; |
2621 | } | 2668 | } |
2622 | 2669 | ||
2670 | if (pasid) { | ||
2671 | unsigned long flags; | ||
2672 | |||
2673 | spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags); | ||
2674 | r = idr_alloc(&adev->vm_manager.pasid_idr, vm, pasid, pasid + 1, | ||
2675 | GFP_ATOMIC); | ||
2676 | spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags); | ||
2677 | if (r < 0) | ||
2678 | goto error_free_root; | ||
2679 | |||
2680 | vm->pasid = pasid; | ||
2681 | } | ||
2682 | |||
2623 | return 0; | 2683 | return 0; |
2624 | 2684 | ||
2625 | error_free_root: | 2685 | error_free_root: |
@@ -2673,6 +2733,14 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) | |||
2673 | bool prt_fini_needed = !!adev->gart.gart_funcs->set_prt; | 2733 | bool prt_fini_needed = !!adev->gart.gart_funcs->set_prt; |
2674 | int i; | 2734 | int i; |
2675 | 2735 | ||
2736 | if (vm->pasid) { | ||
2737 | unsigned long flags; | ||
2738 | |||
2739 | spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags); | ||
2740 | idr_remove(&adev->vm_manager.pasid_idr, vm->pasid); | ||
2741 | spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags); | ||
2742 | } | ||
2743 | |||
2676 | amd_sched_entity_fini(vm->entity.sched, &vm->entity); | 2744 | amd_sched_entity_fini(vm->entity.sched, &vm->entity); |
2677 | 2745 | ||
2678 | if (!RB_EMPTY_ROOT(&vm->va)) { | 2746 | if (!RB_EMPTY_ROOT(&vm->va)) { |
@@ -2752,6 +2820,8 @@ void amdgpu_vm_manager_init(struct amdgpu_device *adev) | |||
2752 | adev->vm_manager.vm_update_mode = 0; | 2820 | adev->vm_manager.vm_update_mode = 0; |
2753 | #endif | 2821 | #endif |
2754 | 2822 | ||
2823 | idr_init(&adev->vm_manager.pasid_idr); | ||
2824 | spin_lock_init(&adev->vm_manager.pasid_lock); | ||
2755 | } | 2825 | } |
2756 | 2826 | ||
2757 | /** | 2827 | /** |
@@ -2765,6 +2835,9 @@ void amdgpu_vm_manager_fini(struct amdgpu_device *adev) | |||
2765 | { | 2835 | { |
2766 | unsigned i, j; | 2836 | unsigned i, j; |
2767 | 2837 | ||
2838 | WARN_ON(!idr_is_empty(&adev->vm_manager.pasid_idr)); | ||
2839 | idr_destroy(&adev->vm_manager.pasid_idr); | ||
2840 | |||
2768 | for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) { | 2841 | for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) { |
2769 | struct amdgpu_vm_id_manager *id_mgr = | 2842 | struct amdgpu_vm_id_manager *id_mgr = |
2770 | &adev->vm_manager.id_mgr[i]; | 2843 | &adev->vm_manager.id_mgr[i]; |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index 48c58ae4bb3a..7873dfa8c0f9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | |||
@@ -25,6 +25,7 @@ | |||
25 | #define __AMDGPU_VM_H__ | 25 | #define __AMDGPU_VM_H__ |
26 | 26 | ||
27 | #include <linux/rbtree.h> | 27 | #include <linux/rbtree.h> |
28 | #include <linux/idr.h> | ||
28 | 29 | ||
29 | #include "gpu_scheduler.h" | 30 | #include "gpu_scheduler.h" |
30 | #include "amdgpu_sync.h" | 31 | #include "amdgpu_sync.h" |
@@ -148,8 +149,9 @@ struct amdgpu_vm { | |||
148 | /* Scheduler entity for page table updates */ | 149 | /* Scheduler entity for page table updates */ |
149 | struct amd_sched_entity entity; | 150 | struct amd_sched_entity entity; |
150 | 151 | ||
151 | /* client id */ | 152 | /* client id and PASID (TODO: replace client_id with PASID) */ |
152 | u64 client_id; | 153 | u64 client_id; |
154 | unsigned int pasid; | ||
153 | /* dedicated to vm */ | 155 | /* dedicated to vm */ |
154 | struct amdgpu_vm_id *reserved_vmid[AMDGPU_MAX_VMHUBS]; | 156 | struct amdgpu_vm_id *reserved_vmid[AMDGPU_MAX_VMHUBS]; |
155 | 157 | ||
@@ -220,12 +222,20 @@ struct amdgpu_vm_manager { | |||
220 | * BIT1[= 0] Compute updated by SDMA [= 1] by CPU | 222 | * BIT1[= 0] Compute updated by SDMA [= 1] by CPU |
221 | */ | 223 | */ |
222 | int vm_update_mode; | 224 | int vm_update_mode; |
225 | |||
226 | /* PASID to VM mapping, will be used in interrupt context to | ||
227 | * look up VM of a page fault | ||
228 | */ | ||
229 | struct idr pasid_idr; | ||
230 | spinlock_t pasid_lock; | ||
223 | }; | 231 | }; |
224 | 232 | ||
233 | int amdgpu_vm_alloc_pasid(unsigned int bits); | ||
234 | void amdgpu_vm_free_pasid(unsigned int pasid); | ||
225 | void amdgpu_vm_manager_init(struct amdgpu_device *adev); | 235 | void amdgpu_vm_manager_init(struct amdgpu_device *adev); |
226 | void amdgpu_vm_manager_fini(struct amdgpu_device *adev); | 236 | void amdgpu_vm_manager_fini(struct amdgpu_device *adev); |
227 | int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, | 237 | int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, |
228 | int vm_context); | 238 | int vm_context, unsigned int pasid); |
229 | void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm); | 239 | void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm); |
230 | void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm, | 240 | void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm, |
231 | struct list_head *validated, | 241 | struct list_head *validated, |