[PATCH 3/4] drm/amdkfd: Add CWSR support
Oded Gabbay
oded.gabbay at gmail.com
Sun Nov 19 13:37:47 UTC 2017
On Tue, Nov 14, 2017 at 11:41 PM, Felix Kuehling <Felix.Kuehling at amd.com> wrote:
> This hardware feature allows the GPU to preempt shader execution in
> the middle of a compute wave, save the state and restore it later
> to resume execution.
>
> Memory for saving the state is allocated per queue in user mode and
> the address and size passed to the create_queue ioctl. The size
Is this a correct description?
It seems to me the memory is allocated at kfd_process_init_cwsr() and
the address is saved internally and not passed in the create_ioctl.
Which begs the question, why indeed it is not allocated by the user
and then passed through the create_ioctl function ?
> depends on the number of waves that can be in flight simultaneously
> on a given ASIC.
>
> Signed-off-by: Shaoyun.liu <shaoyun.liu at amd.com>
> Signed-off-by: Yong Zhao <yong.zhao at amd.com>
> Signed-off-by: Felix Kuehling <Felix.Kuehling at amd.com>
> ---
> drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 7 +-
> drivers/gpu/drm/amd/amdkfd/kfd_device.c | 20 ++++-
> .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 6 ++
> drivers/gpu/drm/amd/amdkfd/kfd_module.c | 4 +
> drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c | 27 +++++++
> drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 31 +++++++-
> drivers/gpu/drm/amd/amdkfd/kfd_process.c | 87 +++++++++++++++++++++-
> include/uapi/linux/kfd_ioctl.h | 3 +-
> 8 files changed, 179 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
> index 505d391..2a4612d 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
> @@ -117,7 +117,7 @@ static int kfd_open(struct inode *inode, struct file *filep)
> return -EPERM;
> }
>
> - process = kfd_create_process(current);
> + process = kfd_create_process(filep);
> if (IS_ERR(process))
> return PTR_ERR(process);
>
> @@ -206,6 +206,7 @@ static int set_queue_properties_from_user(struct queue_properties *q_properties,
> q_properties->ctx_save_restore_area_address =
> args->ctx_save_restore_address;
> q_properties->ctx_save_restore_area_size = args->ctx_save_restore_size;
> + q_properties->ctl_stack_size = args->ctl_stack_size;
> if (args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE ||
> args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE_AQL)
> q_properties->type = KFD_QUEUE_TYPE_COMPUTE;
> @@ -1088,6 +1089,10 @@ static int kfd_mmap(struct file *filp, struct vm_area_struct *vma)
> KFD_MMAP_EVENTS_MASK) {
> vma->vm_pgoff = vma->vm_pgoff ^ KFD_MMAP_EVENTS_MASK;
> return kfd_event_mmap(process, vma);
> + } else if ((vma->vm_pgoff & KFD_MMAP_RESERVED_MEM_MASK) ==
> + KFD_MMAP_RESERVED_MEM_MASK) {
> + vma->vm_pgoff = vma->vm_pgoff ^ KFD_MMAP_RESERVED_MEM_MASK;
> + return kfd_reserved_mem_mmap(process, vma);
> }
>
> return -EFAULT;
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
> index 621a3b5..4f05eac 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
> @@ -27,6 +27,7 @@
> #include "kfd_priv.h"
> #include "kfd_device_queue_manager.h"
> #include "kfd_pm4_headers_vi.h"
> +#include "cwsr_trap_handler_gfx8.asm"
>
> #define MQD_SIZE_ALIGNED 768
>
> @@ -38,7 +39,8 @@ static const struct kfd_device_info kaveri_device_info = {
> .ih_ring_entry_size = 4 * sizeof(uint32_t),
> .event_interrupt_class = &event_interrupt_class_cik,
> .num_of_watch_points = 4,
> - .mqd_size_aligned = MQD_SIZE_ALIGNED
> + .mqd_size_aligned = MQD_SIZE_ALIGNED,
> + .supports_cwsr = false,
> };
>
> static const struct kfd_device_info carrizo_device_info = {
> @@ -49,7 +51,8 @@ static const struct kfd_device_info carrizo_device_info = {
> .ih_ring_entry_size = 4 * sizeof(uint32_t),
> .event_interrupt_class = &event_interrupt_class_cik,
> .num_of_watch_points = 4,
> - .mqd_size_aligned = MQD_SIZE_ALIGNED
> + .mqd_size_aligned = MQD_SIZE_ALIGNED,
> + .supports_cwsr = true,
> };
>
> struct kfd_deviceid {
> @@ -212,6 +215,17 @@ static int iommu_invalid_ppr_cb(struct pci_dev *pdev, int pasid,
> return AMD_IOMMU_INV_PRI_RSP_INVALID;
> }
>
> +static void kfd_cwsr_init(struct kfd_dev *kfd)
> +{
> + if (cwsr_enable && kfd->device_info->supports_cwsr) {
> + BUILD_BUG_ON(sizeof(cwsr_trap_gfx8_hex) > PAGE_SIZE);
> +
> + kfd->cwsr_isa = cwsr_trap_gfx8_hex;
> + kfd->cwsr_isa_size = sizeof(cwsr_trap_gfx8_hex);
> + kfd->cwsr_enabled = true;
> + }
> +}
> +
> bool kgd2kfd_device_init(struct kfd_dev *kfd,
> const struct kgd2kfd_shared_resources *gpu_resources)
> {
> @@ -286,6 +300,8 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
> goto device_iommu_pasid_error;
> }
>
> + kfd_cwsr_init(kfd);
> +
> if (kfd_resume(kfd))
> goto kfd_resume_error;
>
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
> index e202921..5c06502 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
> @@ -173,6 +173,9 @@ static int create_queue_nocpsch(struct device_queue_manager *dqm,
> *allocated_vmid = qpd->vmid;
> q->properties.vmid = qpd->vmid;
>
> + q->properties.tba_addr = qpd->tba_addr;
> + q->properties.tma_addr = qpd->tma_addr;
> +
> if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE)
> retval = create_compute_queue_nocpsch(dqm, q, qpd);
> else if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
> @@ -846,6 +849,9 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
> }
>
> dqm->asic_ops.init_sdma_vm(dqm, q, qpd);
> +
> + q->properties.tba_addr = qpd->tba_addr;
> + q->properties.tma_addr = qpd->tma_addr;
> retval = mqd->init_mqd(mqd, &q->mqd, &q->mqd_mem_obj,
> &q->gart_mqd_addr, &q->properties);
> if (retval)
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_module.c b/drivers/gpu/drm/amd/amdkfd/kfd_module.c
> index 6c5a9ca..4b2423b 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_module.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_module.c
> @@ -49,6 +49,10 @@ module_param(sched_policy, int, 0444);
> MODULE_PARM_DESC(sched_policy,
> "Scheduling policy (0 = HWS (Default), 1 = HWS without over-subscription, 2 = Non-HWS (Used for debugging only)");
>
> +int cwsr_enable = 1;
> +module_param(cwsr_enable, int, 0444);
> +MODULE_PARM_DESC(cwsr_enable, "CWSR enable (0 = Off, 1 = On (Default))");
> +
> int max_num_of_queues_per_device = KFD_MAX_NUM_OF_QUEUES_PER_DEVICE_DEFAULT;
> module_param(max_num_of_queues_per_device, int, 0444);
> MODULE_PARM_DESC(max_num_of_queues_per_device,
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
> index 2ba7cea..00e1f1a 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
> @@ -89,6 +89,28 @@ static int init_mqd(struct mqd_manager *mm, void **mqd,
> if (q->format == KFD_QUEUE_FORMAT_AQL)
> m->cp_hqd_iq_rptr = 1;
>
> + if (q->tba_addr) {
> + m->compute_tba_lo = lower_32_bits(q->tba_addr >> 8);
> + m->compute_tba_hi = upper_32_bits(q->tba_addr >> 8);
> + m->compute_tma_lo = lower_32_bits(q->tma_addr >> 8);
> + m->compute_tma_hi = upper_32_bits(q->tma_addr >> 8);
Why the >> 8 on the addresses ?
> + m->compute_pgm_rsrc2 |=
> + (1 << COMPUTE_PGM_RSRC2__TRAP_PRESENT__SHIFT);
> + }
> +
> + if (mm->dev->cwsr_enabled && q->ctx_save_restore_area_address) {
> + m->cp_hqd_persistent_state |=
> + (1 << CP_HQD_PERSISTENT_STATE__QSWITCH_MODE__SHIFT);
> + m->cp_hqd_ctx_save_base_addr_lo =
> + lower_32_bits(q->ctx_save_restore_area_address);
> + m->cp_hqd_ctx_save_base_addr_hi =
> + upper_32_bits(q->ctx_save_restore_area_address);
> + m->cp_hqd_ctx_save_size = q->ctx_save_restore_area_size;
> + m->cp_hqd_cntl_stack_size = q->ctl_stack_size;
> + m->cp_hqd_cntl_stack_offset = q->ctl_stack_size;
> + m->cp_hqd_wg_state_offset = q->ctl_stack_size;
Just wanted to make sure the last two lines are not copy-paste error
from the third line
> + }
> +
> *mqd = m;
> if (gart_addr)
> *gart_addr = addr;
> @@ -167,6 +189,11 @@ static int __update_mqd(struct mqd_manager *mm, void *mqd,
> 2 << CP_HQD_PQ_CONTROL__SLOT_BASED_WPTR__SHIFT;
> }
>
> + if (mm->dev->cwsr_enabled && q->ctx_save_restore_area_address)
> + m->cp_hqd_ctx_save_control =
> + atc_bit << CP_HQD_CTX_SAVE_CONTROL__ATC__SHIFT |
> + mtype << CP_HQD_CTX_SAVE_CONTROL__MTYPE__SHIFT;
> +
> q->is_active = (q->queue_size > 0 &&
> q->queue_address != 0 &&
> q->queue_percent > 0);
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> index 4750473..a668764 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> @@ -41,6 +41,7 @@
>
> #define KFD_MMAP_DOORBELL_MASK 0x8000000000000
> #define KFD_MMAP_EVENTS_MASK 0x4000000000000
> +#define KFD_MMAP_RESERVED_MEM_MASK 0x2000000000000
>
> /*
> * When working with cp scheduler we should assign the HIQ manually or via
> @@ -63,6 +64,15 @@
> #define KFD_MAX_NUM_OF_QUEUES_PER_PROCESS 1024
>
> /*
> + * Size of the per-process TBA+TMA buffer: 2 pages
> + *
> + * The first page is the TBA used for the CWSR ISA code. The second
> + * page is used as TMA for daisy changing a user-mode trap handler.
> + */
> +#define KFD_CWSR_TBA_TMA_SIZE (PAGE_SIZE * 2)
> +#define KFD_CWSR_TMA_OFFSET PAGE_SIZE
> +
> +/*
> * Kernel module parameter to specify maximum number of supported queues per
> * device
> */
> @@ -78,6 +88,8 @@ extern int max_num_of_queues_per_device;
> /* Kernel module parameter to specify the scheduling policy */
> extern int sched_policy;
>
> +extern int cwsr_enable;
> +
> /*
> * Kernel module parameter to specify whether to send sigterm to HSA process on
> * unhandled exception
> @@ -131,6 +143,7 @@ struct kfd_device_info {
> size_t ih_ring_entry_size;
> uint8_t num_of_watch_points;
> uint16_t mqd_size_aligned;
> + bool supports_cwsr;
> };
>
> struct kfd_mem_obj {
> @@ -200,6 +213,11 @@ struct kfd_dev {
>
> /* Debug manager */
> struct kfd_dbgmgr *dbgmgr;
> +
> + /* CWSR */
> + bool cwsr_enabled;
> + const void *cwsr_isa;
> + unsigned int cwsr_isa_size;
> };
>
> /* KGD2KFD callbacks */
> @@ -332,6 +350,9 @@ struct queue_properties {
> uint32_t eop_ring_buffer_size;
> uint64_t ctx_save_restore_area_address;
> uint32_t ctx_save_restore_area_size;
> + uint32_t ctl_stack_size;
> + uint64_t tba_addr;
> + uint64_t tma_addr;
> };
>
> /**
> @@ -439,6 +460,11 @@ struct qcm_process_device {
> uint32_t num_gws;
> uint32_t num_oac;
> uint32_t sh_hidden_private_base;
> +
> + /* CWSR memory */
> + void *cwsr_kaddr;
> + uint64_t tba_addr;
> + uint64_t tma_addr;
> };
>
>
> @@ -563,7 +589,7 @@ struct amdkfd_ioctl_desc {
>
> void kfd_process_create_wq(void);
> void kfd_process_destroy_wq(void);
> -struct kfd_process *kfd_create_process(const struct task_struct *);
> +struct kfd_process *kfd_create_process(struct file *filep);
> struct kfd_process *kfd_get_process(const struct task_struct *);
> struct kfd_process *kfd_lookup_process_by_pasid(unsigned int pasid);
>
> @@ -577,6 +603,9 @@ struct kfd_process_device *kfd_get_process_device_data(struct kfd_dev *dev,
> struct kfd_process_device *kfd_create_process_device_data(struct kfd_dev *dev,
> struct kfd_process *p);
>
> +int kfd_reserved_mem_mmap(struct kfd_process *process,
> + struct vm_area_struct *vma);
> +
> /* Process device data iterator */
> struct kfd_process_device *kfd_get_first_process_device_data(
> struct kfd_process *p);
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
> index 1bb9b26..39f4c19 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
> @@ -28,6 +28,7 @@
> #include <linux/amd-iommu.h>
> #include <linux/notifier.h>
> #include <linux/compat.h>
> +#include <linux/mman.h>
>
> struct mm_struct;
>
> @@ -53,6 +54,8 @@ struct kfd_process_release_work {
>
> static struct kfd_process *find_process(const struct task_struct *thread);
> static struct kfd_process *create_process(const struct task_struct *thread);
> +static int kfd_process_init_cwsr(struct kfd_process *p, struct file *filep);
> +
>
> void kfd_process_create_wq(void)
> {
> @@ -68,9 +71,10 @@ void kfd_process_destroy_wq(void)
> }
> }
>
> -struct kfd_process *kfd_create_process(const struct task_struct *thread)
> +struct kfd_process *kfd_create_process(struct file *filep)
> {
> struct kfd_process *process;
> + struct task_struct *thread = current;
>
> if (!thread->mm)
> return ERR_PTR(-EINVAL);
> @@ -101,6 +105,8 @@ struct kfd_process *kfd_create_process(const struct task_struct *thread)
>
> up_write(&thread->mm->mmap_sem);
>
> + kfd_process_init_cwsr(process, filep);
> +
> return process;
> }
>
> @@ -168,6 +174,11 @@ static void kfd_process_wq_release(struct work_struct *work)
> amd_iommu_unbind_pasid(pdd->dev->pdev, p->pasid);
>
> list_del(&pdd->per_device_list);
> +
> + if (pdd->qpd.cwsr_kaddr)
> + free_pages((unsigned long)pdd->qpd.cwsr_kaddr,
> + get_order(KFD_CWSR_TBA_TMA_SIZE));
> +
> kfree(pdd);
> }
>
> @@ -260,6 +271,46 @@ static const struct mmu_notifier_ops kfd_process_mmu_notifier_ops = {
> .release = kfd_process_notifier_release,
> };
>
> +static int kfd_process_init_cwsr(struct kfd_process *p, struct file *filep)
> +{
> + int err = 0;
> + unsigned long offset;
> + struct kfd_process_device *temp, *pdd = NULL;
> + struct kfd_dev *dev = NULL;
> + struct qcm_process_device *qpd = NULL;
> +
> + mutex_lock(&p->mutex);
> + list_for_each_entry_safe(pdd, temp, &p->per_device_data,
> + per_device_list) {
> + dev = pdd->dev;
> + qpd = &pdd->qpd;
> + if (!dev->cwsr_enabled || qpd->cwsr_kaddr)
> + continue;
> + offset = (dev->id | KFD_MMAP_RESERVED_MEM_MASK) << PAGE_SHIFT;
> + qpd->tba_addr = (int64_t)vm_mmap(filep, 0,
> + KFD_CWSR_TBA_TMA_SIZE, PROT_READ | PROT_EXEC,
> + MAP_SHARED, offset);
> +
> + if (IS_ERR_VALUE(qpd->tba_addr)) {
> + pr_err("Failure to set tba address. error -%d.\n",
> + (int)qpd->tba_addr);
> + err = qpd->tba_addr;
> + qpd->tba_addr = 0;
> + qpd->cwsr_kaddr = NULL;
> + goto out;
> + }
> +
> + memcpy(qpd->cwsr_kaddr, dev->cwsr_isa, dev->cwsr_isa_size);
> +
> + qpd->tma_addr = qpd->tba_addr + KFD_CWSR_TMA_OFFSET;
> + pr_debug("set tba :0x%llx, tma:0x%llx, cwsr_kaddr:%p for pqm.\n",
> + qpd->tba_addr, qpd->tma_addr, qpd->cwsr_kaddr);
> + }
> +out:
> + mutex_unlock(&p->mutex);
> + return err;
> +}
> +
> static struct kfd_process *create_process(const struct task_struct *thread)
> {
> struct kfd_process *process;
> @@ -535,3 +586,37 @@ struct kfd_process *kfd_lookup_process_by_pasid(unsigned int pasid)
>
> return p;
> }
> +
> +int kfd_reserved_mem_mmap(struct kfd_process *process,
> + struct vm_area_struct *vma)
> +{
> + struct kfd_dev *dev = kfd_device_by_id(vma->vm_pgoff);
> + struct kfd_process_device *pdd;
> + struct qcm_process_device *qpd;
> +
> + if (!dev)
> + return -EINVAL;
> + if ((vma->vm_end - vma->vm_start) != KFD_CWSR_TBA_TMA_SIZE) {
> + pr_err("Incorrect CWSR mapping size.\n");
> + return -EINVAL;
> + }
> +
> + pdd = kfd_get_process_device_data(dev, process);
> + if (!pdd)
> + return -EINVAL;
> + qpd = &pdd->qpd;
> +
> + qpd->cwsr_kaddr = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
> + get_order(KFD_CWSR_TBA_TMA_SIZE));
> + if (!qpd->cwsr_kaddr) {
> + pr_err("Error allocating per process CWSR buffer.\n");
> + return -ENOMEM;
> + }
> +
> + vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND
> + | VM_NORESERVE | VM_DONTDUMP | VM_PFNMAP;
> + /* Mapping pages to user process */
> + return remap_pfn_range(vma, vma->vm_start,
> + PFN_DOWN(__pa(qpd->cwsr_kaddr)),
> + KFD_CWSR_TBA_TMA_SIZE, vma->vm_page_prot);
> +}
> diff --git a/include/uapi/linux/kfd_ioctl.h b/include/uapi/linux/kfd_ioctl.h
> index 731d0df..7039f16 100644
> --- a/include/uapi/linux/kfd_ioctl.h
> +++ b/include/uapi/linux/kfd_ioctl.h
> @@ -58,7 +58,8 @@ struct kfd_ioctl_create_queue_args {
> __u64 eop_buffer_address; /* to KFD */
> __u64 eop_buffer_size; /* to KFD */
> __u64 ctx_save_restore_address; /* to KFD */
> - __u64 ctx_save_restore_size; /* to KFD */
> + __u32 ctx_save_restore_size; /* to KFD */
> + __u32 ctl_stack_size; /* to KFD */
> };
>
> struct kfd_ioctl_destroy_queue_args {
> --
> 2.7.4
>
More information about the amd-gfx
mailing list