[PATCH 2/8] drm/amdgpu: Add PASID management

Alex Deucher alexdeucher at gmail.com
Wed Sep 13 19:37:22 UTC 2017


On Tue, Sep 12, 2017 at 7:05 PM, Felix Kuehling <Felix.Kuehling at amd.com> wrote:
> 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 at amd.com>

Acked-by: Alex Deucher <alexander.deucher at amd.com>

> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c |  2 +
>  drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c |  2 +
>  drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c           |  2 +-
>  drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c            | 75 ++++++++++++++++++++++-
>  drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h            | 14 ++++-
>  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 b9dbbf9..dc7e25c 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 = {
>         .get_vmem_size = get_vmem_size,
>         .get_gpu_clock_counter = get_gpu_clock_counter,
>         .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz,
> +       .alloc_pasid = amdgpu_vm_alloc_pasid,
> +       .free_pasid = amdgpu_vm_free_pasid,
>         .program_sh_mem_settings = kgd_program_sh_mem_settings,
>         .set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
>         .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 309f241..c678c69 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 = {
>         .get_vmem_size = get_vmem_size,
>         .get_gpu_clock_counter = get_gpu_clock_counter,
>         .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz,
> +       .alloc_pasid = amdgpu_vm_alloc_pasid,
> +       .free_pasid = amdgpu_vm_free_pasid,
>         .program_sh_mem_settings = kgd_program_sh_mem_settings,
>         .set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
>         .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 d31777b..7045eec 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)
>         }
>
>         r = amdgpu_vm_init(adev, &fpriv->vm,
> -                          AMDGPU_VM_CONTEXT_GFX);
> +                          AMDGPU_VM_CONTEXT_GFX, 0);
>         if (r) {
>                 kfree(fpriv);
>                 goto out_suspend;
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
> index 87858f6..bdb9fe8 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
> @@ -27,12 +27,59 @@
>   */
>  #include <linux/dma-fence-array.h>
>  #include <linux/interval_tree_generic.h>
> +#include <linux/idr.h>
>  #include <drm/drmP.h>
>  #include <drm/amdgpu_drm.h>
>  #include "amdgpu.h"
>  #include "amdgpu_trace.h"
>
>  /*
> + * PASID manager
> + *
> + * PASIDs are global address space identifiers that can be shared
> + * between the GPU, an IOMMU and the driver. VMs on different devices
> + * may use the same PASID if they share the same address
> + * space. Therefore PASIDs are allocated using a global IDA. VMs are
> + * looked up from the PASID per amdgpu_device.
> + */
> +static DEFINE_IDA(amdgpu_vm_pasid_ida);
> +
> +/**
> + * amdgpu_vm_alloc_pasid - Allocate a PASID
> + * @bits: Maximum width of the PASID in bits, must be at least 1
> + *
> + * Allocates a PASID of the given width while keeping smaller PASIDs
> + * available if possible.
> + *
> + * Returns a positive integer on success. Returns %-EINVAL if bits==0.
> + * Returns %-ENOSPC if no PASID was available. Returns %-ENOMEM on
> + * memory allocation failure.
> + */
> +int amdgpu_vm_alloc_pasid(unsigned int bits)
> +{
> +       int pasid = -EINVAL;
> +
> +       for (bits = min(bits, 31U); bits > 0; bits--) {
> +               pasid = ida_simple_get(&amdgpu_vm_pasid_ida,
> +                                      1U << (bits - 1), 1U << bits,
> +                                      GFP_KERNEL);
> +               if (pasid != -ENOSPC)
> +                       break;
> +       }
> +
> +       return pasid;
> +}
> +
> +/**
> + * amdgpu_vm_free_pasid - Free a PASID
> + * @pasid: PASID to free
> + */
> +void amdgpu_vm_free_pasid(unsigned int pasid)
> +{
> +       ida_simple_remove(&amdgpu_vm_pasid_ida, pasid);
> +}
> +
> +/*
>   * GPUVM
>   * GPUVM is similar to the legacy gart on older asics, however
>   * rather than there being a single global gart table
> @@ -2543,7 +2590,7 @@ void amdgpu_vm_adjust_size(struct amdgpu_device *adev, uint64_t vm_size, uint32_
>   * Init @vm fields.
>   */
>  int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
> -                  int vm_context)
> +                  int vm_context, unsigned int pasid)
>  {
>         const unsigned align = min(AMDGPU_VM_PTB_ALIGN_SIZE,
>                 AMDGPU_VM_PTE_COUNT(adev) * 8);
> @@ -2624,6 +2671,19 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
>                         goto error_free_root;
>         }
>
> +       if (pasid) {
> +               unsigned long flags;
> +
> +               spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags);
> +               r = idr_alloc(&adev->vm_manager.pasid_idr, vm, pasid, pasid + 1,
> +                             GFP_ATOMIC);
> +               spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
> +               if (r < 0)
> +                       goto error_free_root;
> +
> +               vm->pasid = pasid;
> +       }
> +
>         return 0;
>
>  error_free_root:
> @@ -2677,6 +2737,14 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
>         bool prt_fini_needed = !!adev->gart.gart_funcs->set_prt;
>         int i;
>
> +       if (vm->pasid) {
> +               unsigned long flags;
> +
> +               spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags);
> +               idr_remove(&adev->vm_manager.pasid_idr, vm->pasid);
> +               spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
> +       }
> +
>         amd_sched_entity_fini(vm->entity.sched, &vm->entity);
>
>         if (!RB_EMPTY_ROOT(&vm->va)) {
> @@ -2756,6 +2824,8 @@ void amdgpu_vm_manager_init(struct amdgpu_device *adev)
>         adev->vm_manager.vm_update_mode = 0;
>  #endif
>
> +       idr_init(&adev->vm_manager.pasid_idr);
> +       spin_lock_init(&adev->vm_manager.pasid_lock);
>  }
>
>  /**
> @@ -2769,6 +2839,9 @@ void amdgpu_vm_manager_fini(struct amdgpu_device *adev)
>  {
>         unsigned i, j;
>
> +       WARN_ON(!idr_is_empty(&adev->vm_manager.pasid_idr));
> +       idr_destroy(&adev->vm_manager.pasid_idr);
> +
>         for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
>                 struct amdgpu_vm_id_manager *id_mgr =
>                         &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 cb6a622..dab466d 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
> @@ -25,6 +25,7 @@
>  #define __AMDGPU_VM_H__
>
>  #include <linux/rbtree.h>
> +#include <linux/idr.h>
>
>  #include "gpu_scheduler.h"
>  #include "amdgpu_sync.h"
> @@ -148,8 +149,9 @@ struct amdgpu_vm {
>         /* Scheduler entity for page table updates */
>         struct amd_sched_entity entity;
>
> -       /* client id */
> +       /* client id and PASID (TODO: replace client_id with PASID) */
>         u64                     client_id;
> +       unsigned int            pasid;
>         /* dedicated to vm */
>         struct amdgpu_vm_id     *reserved_vmid[AMDGPU_MAX_VMHUBS];
>
> @@ -220,12 +222,20 @@ struct amdgpu_vm_manager {
>          * BIT1[= 0] Compute updated by SDMA [= 1] by CPU
>          */
>         int                                     vm_update_mode;
> +
> +       /* PASID to VM mapping, will be used in interrupt context to
> +        * look up VM of a page fault
> +        */
> +       struct idr                              pasid_idr;
> +       spinlock_t                              pasid_lock;
>  };
>
> +int amdgpu_vm_alloc_pasid(unsigned int bits);
> +void amdgpu_vm_free_pasid(unsigned int pasid);
>  void amdgpu_vm_manager_init(struct amdgpu_device *adev);
>  void amdgpu_vm_manager_fini(struct amdgpu_device *adev);
>  int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
> -                  int vm_context);
> +                  int vm_context, unsigned int pasid);
>  void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm);
>  void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm,
>                          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 94277cb..f516fd1 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 {
>   *
>   * @get_max_engine_clock_in_mhz: Retrieves maximum GPU clock in MHz
>   *
> + * @alloc_pasid: Allocate a PASID
> + * @free_pasid: Free a PASID
> + *
>   * @program_sh_mem_settings: A function that should initiate the memory
>   * properties such as main aperture memory type (cache / non cached) and
>   * secondary aperture base address, size and memory type.
> @@ -160,6 +163,9 @@ struct kfd2kgd_calls {
>
>         uint32_t (*get_max_engine_clock_in_mhz)(struct kgd_dev *kgd);
>
> +       int (*alloc_pasid)(unsigned int bits);
> +       void (*free_pasid)(unsigned int pasid);
> +
>         /* Register access functions */
>         void (*program_sh_mem_settings)(struct kgd_dev *kgd, uint32_t vmid,
>                         uint32_t sh_mem_config, uint32_t sh_mem_ape1_base,
> --
> 2.7.4
>
> _______________________________________________
> amd-gfx mailing list
> amd-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx


More information about the amd-gfx mailing list