aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd
diff options
context:
space:
mode:
authorFelix Kuehling <Felix.Kuehling@amd.com>2017-08-25 20:40:26 -0400
committerAlex Deucher <alexander.deucher@amd.com>2017-09-26 13:07:02 -0400
commit02208441cc3a5110191996bb129db39ff10e7395 (patch)
treebb228597c2413583efc368295dcb2b5ad173b135 /drivers/gpu/drm/amd
parentca290da8f6345c8e8e180256fbe092c751fa9654 (diff)
drm/amdgpu: Add PASID management
Allows assigning a PASID to a VM for identifying VMs involved in page faults. The global PASID manager is also exported in the KFD interface so that AMDGPU and KFD can share the PASID space. PASIDs of different sizes can be requested. On APUs, the PASID size is deterined by the capabilities of the IOMMU. So KFD must be able to allocate PASIDs in a smaller range. Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Oded Gabbay <oded.gabbay@gmail.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c75
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h14
-rw-r--r--drivers/gpu/drm/amd/include/kgd_kfd_interface.h6
6 files changed, 97 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 */
45static 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 */
58int 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 */
77void 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 */
2541int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, 2588int 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
2625error_free_root: 2685error_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
233int amdgpu_vm_alloc_pasid(unsigned int bits);
234void amdgpu_vm_free_pasid(unsigned int pasid);
225void amdgpu_vm_manager_init(struct amdgpu_device *adev); 235void amdgpu_vm_manager_init(struct amdgpu_device *adev);
226void amdgpu_vm_manager_fini(struct amdgpu_device *adev); 236void amdgpu_vm_manager_fini(struct amdgpu_device *adev);
227int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, 237int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
228 int vm_context); 238 int vm_context, unsigned int pasid);
229void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm); 239void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm);
230void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm, 240void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm,
231 struct list_head *validated, 241 struct list_head *validated,
diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
index 94277cb734d2..f516fd10e6ba 100644
--- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
+++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
@@ -112,6 +112,9 @@ struct tile_config {
112 * 112 *
113 * @get_max_engine_clock_in_mhz: Retrieves maximum GPU clock in MHz 113 * @get_max_engine_clock_in_mhz: Retrieves maximum GPU clock in MHz
114 * 114 *
115 * @alloc_pasid: Allocate a PASID
116 * @free_pasid: Free a PASID
117 *
115 * @program_sh_mem_settings: A function that should initiate the memory 118 * @program_sh_mem_settings: A function that should initiate the memory
116 * properties such as main aperture memory type (cache / non cached) and 119 * properties such as main aperture memory type (cache / non cached) and
117 * secondary aperture base address, size and memory type. 120 * secondary aperture base address, size and memory type.
@@ -160,6 +163,9 @@ struct kfd2kgd_calls {
160 163
161 uint32_t (*get_max_engine_clock_in_mhz)(struct kgd_dev *kgd); 164 uint32_t (*get_max_engine_clock_in_mhz)(struct kgd_dev *kgd);
162 165
166 int (*alloc_pasid)(unsigned int bits);
167 void (*free_pasid)(unsigned int pasid);
168
163 /* Register access functions */ 169 /* Register access functions */
164 void (*program_sh_mem_settings)(struct kgd_dev *kgd, uint32_t vmid, 170 void (*program_sh_mem_settings)(struct kgd_dev *kgd, uint32_t vmid,
165 uint32_t sh_mem_config, uint32_t sh_mem_ape1_base, 171 uint32_t sh_mem_config, uint32_t sh_mem_ape1_base,