diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index dd27d7ba2ee2..d18ec3671fda 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -21,6 +21,7 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include #include #include #include @@ -3216,6 +3217,84 @@ static int kfd_ioctl_create_process(struct file *filep, struct kfd_process *p, v return 0; } +static inline uint32_t profile_lock_device(struct kfd_process *p, + uint32_t gpu_id, uint32_t op) +{ + struct kfd_process_device *pdd; + struct kfd_dev *kfd; + int status = -EINVAL; + + if (!p) + return -EINVAL; + + mutex_lock(&p->mutex); + pdd = kfd_process_device_data_by_id(p, gpu_id); + mutex_unlock(&p->mutex); + + if (!pdd || !pdd->dev || !pdd->dev->kfd) + return -EINVAL; + + kfd = pdd->dev->kfd; + + mutex_lock(&kfd->profiler_lock); + if (op == 1) { + if (!kfd->profiler_process) { + kfd->profiler_process = p; + status = 0; + } else if (kfd->profiler_process == p) { + status = -EALREADY; + } else { + status = -EBUSY; + } + } else if (op == 0 && kfd->profiler_process == p) { + kfd->profiler_process = NULL; + status = 0; + } + mutex_unlock(&kfd->profiler_lock); + + return status; +} + +static inline int kfd_profiler_pmc(struct kfd_process *p, + struct kfd_ioctl_pmc_settings *args) +{ + struct kfd_process_device *pdd; + struct device_queue_manager *dqm; + int status; + + /* Check if we have the correct permissions. */ + if (!perfmon_capable()) + return -EPERM; + + /* Lock/Unlock the device based on the parameter given in OP */ + status = profile_lock_device(p, args->gpu_id, args->lock); + if (status != 0) + return status; + + /* Enable/disable perfcount if requested */ + mutex_lock(&p->mutex); + pdd = kfd_process_device_data_by_id(p, args->gpu_id); + dqm = pdd->dev->dqm; + mutex_unlock(&p->mutex); + + dqm->ops.set_perfcount(dqm, args->perfcount_enable); + return status; +} + +static int kfd_ioctl_profiler(struct file *filep, struct kfd_process *p, void *data) +{ + struct kfd_ioctl_profiler_args *args = data; + + switch (args->op) { + case KFD_IOC_PROFILER_VERSION: + args->version = KFD_IOC_PROFILER_VERSION_NUM; + return 0; + case KFD_IOC_PROFILER_PMC: + return kfd_profiler_pmc(p, &args->pmc); + } + return -EINVAL; +} + #define AMDKFD_IOCTL_DEF(ioctl, _func, _flags) \ [_IOC_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, \ .validate = NULL, .cmd_drv = 0, .name = #ioctl} @@ -3342,6 +3421,9 @@ static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = { AMDKFD_IOCTL_DEF(AMDKFD_IOC_CREATE_PROCESS, kfd_ioctl_create_process, 0), + + AMDKFD_IOCTL_DEF(AMDKFD_IOC_PROFILER, + kfd_ioctl_profiler, 0), }; #define AMDKFD_CORE_IOCTL_COUNT ARRAY_SIZE(amdkfd_ioctls) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index b7f8f7ff8198..d649d8603e28 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -936,6 +936,9 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, svm_range_set_max_pages(kfd->adev); + kfd->profiler_process = NULL; + mutex_init(&kfd->profiler_lock); + kfd->init_complete = true; dev_info(kfd_device, "added device %x:%x\n", kfd->adev->pdev->vendor, kfd->adev->pdev->device); @@ -971,6 +974,7 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd) ida_destroy(&kfd->doorbell_ida); kfd_gtt_sa_fini(kfd); amdgpu_amdkfd_free_kernel_mem(kfd->adev, &kfd->gtt_mem); + mutex_destroy(&kfd->profiler_lock); } kfree(kfd); 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 a9ac575537e5..c64a1e19fa3f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -324,6 +324,29 @@ static int remove_queue_mes_on_reset_option(struct device_queue_manager *dqm, st return r; } +static void set_perfcount(struct device_queue_manager *dqm, int enable) +{ + struct device_process_node *cur; + struct qcm_process_device *qpd; + struct queue *q; + struct mqd_update_info minfo = { 0 }; + + if (!dqm) + return; + + minfo.update_flag = (enable == 1 ? UPDATE_FLAG_PERFCOUNT_ENABLE : + UPDATE_FLAG_PERFCOUNT_DISABLE); + dqm_lock(dqm); + list_for_each_entry(cur, &dqm->queues, list) { + qpd = cur->qpd; + list_for_each_entry(q, &qpd->queues_list, list) { + pqm_update_mqd(qpd->pqm, q->properties.queue_id, + &minfo); + } + } + dqm_unlock(dqm); +} + static int remove_queue_mes(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd) { @@ -3113,6 +3136,7 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev) dqm->ops.reset_queues = reset_queues_cpsch; dqm->ops.get_queue_checkpoint_info = get_queue_checkpoint_info; dqm->ops.checkpoint_mqd = checkpoint_mqd; + dqm->ops.set_perfcount = set_perfcount; break; case KFD_SCHED_POLICY_NO_HWS: /* initialize dqm for no cp scheduling */ @@ -3133,6 +3157,7 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev) dqm->ops.get_wave_state = get_wave_state; dqm->ops.get_queue_checkpoint_info = get_queue_checkpoint_info; dqm->ops.checkpoint_mqd = checkpoint_mqd; + dqm->ops.set_perfcount = set_perfcount; break; default: dev_err(dev->adev->dev, "Invalid scheduling policy %d\n", dqm->sched_policy); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index a0323501c6b9..e0b6a47e7722 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -199,6 +199,8 @@ struct device_queue_manager_ops { const struct queue *q, void *mqd, void *ctl_stack); + void (*set_perfcount)(struct device_queue_manager *dqm, + int enable); }; struct device_queue_manager_asic_ops { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c index 77fb41e2486a..8e8ec266ca46 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c @@ -123,10 +123,9 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, */ m->cp_hqd_hq_scheduler0 = 1 << 14; - if (q->format == KFD_QUEUE_FORMAT_AQL) { + if (q->format == KFD_QUEUE_FORMAT_AQL) m->cp_hqd_aql_control = 1 << CP_HQD_AQL_CONTROL__CONTROL0__SHIFT; - } if (mm->dev->kfd->cwsr_enabled) { m->cp_hqd_persistent_state |= @@ -141,6 +140,12 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, m->cp_hqd_wg_state_offset = q->ctl_stack_size; } + mutex_lock(&mm->dev->kfd->profiler_lock); + if (mm->dev->kfd->profiler_process != NULL) + m->compute_perfcount_enable = 1; + + mutex_unlock(&mm->dev->kfd->profiler_lock); + *mqd = m; if (gart_addr) *gart_addr = addr; @@ -220,6 +225,13 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, if (mm->dev->kfd->cwsr_enabled) m->cp_hqd_ctx_save_control = 0; + if (minfo) { + if (minfo->update_flag == UPDATE_FLAG_PERFCOUNT_ENABLE) + m->compute_perfcount_enable = 1; + else if (minfo->update_flag == UPDATE_FLAG_PERFCOUNT_DISABLE) + m->compute_perfcount_enable = 0; + } + update_cu_mask(mm, mqd, minfo); set_priority(m, q); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c index a1e3cf2384dd..7568e7ed5244 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c @@ -163,10 +163,9 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, if (amdgpu_amdkfd_have_atomics_support(mm->dev->adev)) m->cp_hqd_hq_status0 |= 1 << 29; - if (q->format == KFD_QUEUE_FORMAT_AQL) { + if (q->format == KFD_QUEUE_FORMAT_AQL) m->cp_hqd_aql_control = 1 << CP_HQD_AQL_CONTROL__CONTROL0__SHIFT; - } if (mm->dev->kfd->cwsr_enabled) { m->cp_hqd_persistent_state |= @@ -181,6 +180,11 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, m->cp_hqd_wg_state_offset = q->ctl_stack_size; } + mutex_lock(&mm->dev->kfd->profiler_lock); + if (mm->dev->kfd->profiler_process != NULL) + m->compute_perfcount_enable = 1; + mutex_unlock(&mm->dev->kfd->profiler_lock); + *mqd = m; if (gart_addr) *gart_addr = addr; @@ -258,6 +262,12 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, } if (mm->dev->kfd->cwsr_enabled) m->cp_hqd_ctx_save_control = 0; + if (minfo) { + if (minfo->update_flag == UPDATE_FLAG_PERFCOUNT_ENABLE) + m->compute_perfcount_enable = 1; + else if (minfo->update_flag == UPDATE_FLAG_PERFCOUNT_DISABLE) + m->compute_perfcount_enable = 0; + } update_cu_mask(mm, mqd, minfo); set_priority(m, q); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c index b3e122d7876e..8c815f129614 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c @@ -138,10 +138,9 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, if (amdgpu_amdkfd_have_atomics_support(mm->dev->adev)) m->cp_hqd_hq_status0 |= 1 << 29; - if (q->format == KFD_QUEUE_FORMAT_AQL) { + if (q->format == KFD_QUEUE_FORMAT_AQL) m->cp_hqd_aql_control = 1 << CP_HQD_AQL_CONTROL__CONTROL0__SHIFT; - } if (mm->dev->kfd->cwsr_enabled) { m->cp_hqd_persistent_state |= @@ -156,6 +155,11 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, m->cp_hqd_wg_state_offset = q->ctl_stack_size; } + mutex_lock(&mm->dev->kfd->profiler_lock); + if (mm->dev->kfd->profiler_process != NULL) + m->compute_perfcount_enable = 1; + mutex_unlock(&mm->dev->kfd->profiler_lock); + *mqd = m; if (gart_addr) *gart_addr = addr; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c index e8f97de9d6e4..56a7679ca98d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -227,10 +227,9 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, m->cp_hqd_aql_control = 1 << CP_HQD_AQL_CONTROL__CONTROL0__SHIFT; - if (q->tba_addr) { + if (q->tba_addr) m->compute_pgm_rsrc2 |= (1 << COMPUTE_PGM_RSRC2__TRAP_PRESENT__SHIFT); - } if (mm->dev->kfd->cwsr_enabled && q->ctx_save_restore_area_address) { m->cp_hqd_persistent_state |= @@ -245,6 +244,11 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, m->cp_hqd_wg_state_offset = q->ctl_stack_size; } + mutex_lock(&mm->dev->kfd->profiler_lock); + if (mm->dev->kfd->profiler_process != NULL) + m->compute_perfcount_enable = 1; + mutex_unlock(&mm->dev->kfd->profiler_lock); + *mqd = m; if (gart_addr) *gart_addr = addr; @@ -327,6 +331,13 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, if (mm->dev->kfd->cwsr_enabled && q->ctx_save_restore_area_address) m->cp_hqd_ctx_save_control = 0; + if (minfo) { + if (minfo->update_flag == UPDATE_FLAG_PERFCOUNT_ENABLE) + m->compute_perfcount_enable = 1; + else if (minfo->update_flag == UPDATE_FLAG_PERFCOUNT_DISABLE) + m->compute_perfcount_enable = 0; + } + if (KFD_GC_VERSION(mm->dev) != IP_VERSION(9, 4, 3) && KFD_GC_VERSION(mm->dev) != IP_VERSION(9, 4, 4) && KFD_GC_VERSION(mm->dev) != IP_VERSION(9, 5, 0)) 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 431a20323146..c86779af323b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c @@ -148,6 +148,11 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, m->cp_hqd_wg_state_offset = q->ctl_stack_size; } + mutex_lock(&mm->dev->kfd->profiler_lock); + if (mm->dev->kfd->profiler_process != NULL) + m->compute_perfcount_enable = 1; + mutex_unlock(&mm->dev->kfd->profiler_lock); + *mqd = m; if (gart_addr) *gart_addr = addr; @@ -230,6 +235,12 @@ static void __update_mqd(struct mqd_manager *mm, void *mqd, m->cp_hqd_ctx_save_control = atc_bit << CP_HQD_CTX_SAVE_CONTROL__ATC__SHIFT | mtype << CP_HQD_CTX_SAVE_CONTROL__MTYPE__SHIFT; + if (minfo) { + if (minfo->update_flag == UPDATE_FLAG_PERFCOUNT_ENABLE) + m->compute_perfcount_enable = 1; + else if (minfo->update_flag == UPDATE_FLAG_PERFCOUNT_DISABLE) + m->compute_perfcount_enable = 0; + } update_cu_mask(mm, mqd, minfo); set_priority(m, q); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 9fe5c66d8013..903386e0740b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -383,6 +383,11 @@ struct kfd_dev { int kfd_dev_lock; atomic_t kfd_processes_count; + + /* Lock for profiler process */ + struct mutex profiler_lock; + /* Process currently holding the lock */ + struct kfd_process *profiler_process; }; enum kfd_mempool { @@ -556,6 +561,8 @@ enum mqd_update_flag { UPDATE_FLAG_DBG_WA_ENABLE = 1, UPDATE_FLAG_DBG_WA_DISABLE = 2, UPDATE_FLAG_IS_GWS = 4, /* quirk for gfx9 IP */ + UPDATE_FLAG_PERFCOUNT_ENABLE = 5, + UPDATE_FLAG_PERFCOUNT_DISABLE = 6, }; struct mqd_update_info { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 9228e4a949ed..1a8cb512dfe3 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -1106,6 +1106,16 @@ static void kfd_process_free_outstanding_kfd_bos(struct kfd_process *p) kfd_process_device_free_bos(p->pdds[i]); } +static void kfd_process_profiler_release(struct kfd_process *p, struct kfd_process_device *pdd) +{ + mutex_lock(&pdd->dev->kfd->profiler_lock); + if (pdd->dev->kfd->profiler_process == p) { + pdd->qpd.dqm->ops.set_perfcount(pdd->qpd.dqm, 0); + pdd->dev->kfd->profiler_process = NULL; + } + mutex_unlock(&pdd->dev->kfd->profiler_lock); +} + static void kfd_process_destroy_pdds(struct kfd_process *p) { int i; @@ -1117,6 +1127,7 @@ static void kfd_process_destroy_pdds(struct kfd_process *p) pr_debug("Releasing pdd (topology id %d, for pid %d)\n", pdd->dev->id, p->lead_thread->pid); + kfd_process_profiler_release(p, pdd); kfd_process_device_destroy_cwsr_dgpu(pdd); kfd_process_device_destroy_ib_mem(pdd); diff --git a/include/uapi/linux/kfd_ioctl.h b/include/uapi/linux/kfd_ioctl.h index e72359370857..cc3ed0765c83 100644 --- a/include/uapi/linux/kfd_ioctl.h +++ b/include/uapi/linux/kfd_ioctl.h @@ -1558,6 +1558,29 @@ struct kfd_ioctl_dbg_trap_args { }; }; +#define KFD_IOC_PROFILER_VERSION_NUM 1 +enum kfd_profiler_ops { + KFD_IOC_PROFILER_PMC = 0, + KFD_IOC_PROFILER_VERSION = 2, +}; + +/** + * Enables/Disables GPU Specific profiler settings + */ +struct kfd_ioctl_pmc_settings { + __u32 gpu_id; /* This is the user_gpu_id */ + __u32 lock; /* Lock GPU for Profiling */ + __u32 perfcount_enable; /* Force Perfcount Enable for queues on GPU */ +}; + +struct kfd_ioctl_profiler_args { + __u32 op; /* kfd_profiler_op */ + union { + struct kfd_ioctl_pmc_settings pmc; + __u32 version; /* KFD_IOC_PROFILER_VERSION_NUM */ + }; +}; + #define AMDKFD_IOCTL_BASE 'K' #define AMDKFD_IO(nr) _IO(AMDKFD_IOCTL_BASE, nr) #define AMDKFD_IOR(nr, type) _IOR(AMDKFD_IOCTL_BASE, nr, type) @@ -1681,7 +1704,10 @@ struct kfd_ioctl_dbg_trap_args { #define AMDKFD_IOC_CREATE_PROCESS \ AMDKFD_IO(0x27) +#define AMDKFD_IOC_PROFILER \ + AMDKFD_IOWR(0x28, struct kfd_ioctl_profiler_args) + #define AMDKFD_COMMAND_START 0x01 -#define AMDKFD_COMMAND_END 0x28 +#define AMDKFD_COMMAND_END 0x29 #endif