diff options
Diffstat (limited to 'drivers/gpu')
| -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 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 6 |
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 | */ | ||
| 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, |
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, |
