commit 03ce38b4f5fc9d43820c669cba7bd8c03e3bdc02 Author: Alex Deucher Date: Wed Dec 1 16:17:13 2021 -0500 drm/amdgpu/UAPI: add new CTX OP for setting profile modes Add a new CTX ioctl operation to set profile modes. When creating traces for tools like RGP or using SPM or doing performance profiling, it's required to enable a special stable profiling power state on the GPU. These profiling states set fixed clocks and disable certain other power features like powergating which may impact the results. Historically, these profiles were enabled via sysfs, but this adds an interface to enable it via the CTX ioctl from the application. Since the power state is global only one application can set it at a time, so if multiple applications try and use it only the first will get it, the ioctl will return -EBUSY for others. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index c5cfe2926ca1..95b8908bd2e5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1097,6 +1097,9 @@ struct amdgpu_device { struct amdgpu_reset_control *reset_cntl; uint32_t ip_versions[MAX_HWIP][HWIP_MAX_INSTANCE]; + + struct mutex pstate_profile_ctx_lock; + struct amdgpu_ctx *pstate_profile_ctx; }; static inline struct amdgpu_device *drm_to_adev(struct drm_device *ddev) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index 468003583b2a..bf8a5939e444 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -237,6 +237,7 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev, ctx->vram_lost_counter = atomic_read(&adev->vram_lost_counter); ctx->init_priority = priority; ctx->override_priority = AMDGPU_CTX_PRIORITY_UNSET; + ctx->pstate_profile = AMDGPU_CTX_PSTATE_PROFILE_NONE; return 0; } @@ -255,6 +256,67 @@ static void amdgpu_ctx_fini_entity(struct amdgpu_ctx_entity *entity) kfree(entity); } +static int amdgpu_ctx_do_set_pstate_profile(struct amdgpu_ctx *ctx, + u32 pstate_profile) +{ + struct amdgpu_device *adev = ctx->adev; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + enum amd_dpm_forced_level level, current_level; + int r = 0; + + if (!ctx) + return -EINVAL; + + mutex_lock(&adev->pstate_profile_ctx_lock); + if (adev->pstate_profile_ctx && adev->pstate_profile_ctx != ctx) { + r = -EBUSY; + goto done; + } + + switch (pstate_profile) { + case AMDGPU_CTX_PSTATE_PROFILE_NONE: + level = AMD_DPM_FORCED_LEVEL_AUTO; + break; + case AMDGPU_CTX_PSTATE_PROFILE_STANDARD: + level = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD; + break; + case AMDGPU_CTX_PSTATE_PROFILE_MIN_SCLK: + level = AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK; + break; + case AMDGPU_CTX_PSTATE_PROFILE_MIN_MCLK: + level = AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK; + break; + case AMDGPU_CTX_PSTATE_PROFILE_PEAK: + level = AMD_DPM_FORCED_LEVEL_PROFILE_PEAK; + break; + default: + r = -EINVAL; + goto done; + } + + if (pp_funcs->get_performance_level) + current_level = amdgpu_dpm_get_performance_level(adev); + else + current_level = adev->pm.dpm.forced_level; + + if ((current_level != level) && pp_funcs->force_performance_level) { + mutex_lock(&adev->pm.mutex); + r = amdgpu_dpm_force_performance_level(adev, level); + if (!r) + adev->pm.dpm.forced_level = level; + mutex_unlock(&adev->pm.mutex); + } + + if (level == AMD_DPM_FORCED_LEVEL_AUTO) + adev->pstate_profile_ctx = NULL; + else + adev->pstate_profile_ctx = ctx; +done: + mutex_unlock(&adev->pstate_profile_ctx_lock); + + return r; +} + static void amdgpu_ctx_fini(struct kref *ref) { struct amdgpu_ctx *ctx = container_of(ref, struct amdgpu_ctx, refcount); @@ -270,7 +332,7 @@ static void amdgpu_ctx_fini(struct kref *ref) ctx->entities[i][j] = NULL; } } - + amdgpu_ctx_do_set_pstate_profile(ctx, AMDGPU_CTX_PSTATE_PROFILE_NONE); mutex_destroy(&ctx->lock); kfree(ctx); } @@ -467,11 +529,38 @@ static int amdgpu_ctx_query2(struct amdgpu_device *adev, return 0; } + + +static int amdgpu_ctx_set_pstate_profile(struct amdgpu_device *adev, + struct amdgpu_fpriv *fpriv, uint32_t id, + u32 pstate_profile) +{ + struct amdgpu_ctx *ctx; + struct amdgpu_ctx_mgr *mgr; + int r; + + if (!fpriv) + return -EINVAL; + + mgr = &fpriv->ctx_mgr; + mutex_lock(&mgr->lock); + ctx = idr_find(&mgr->ctx_handles, id); + if (!ctx) { + mutex_unlock(&mgr->lock); + return -EINVAL; + } + + r = amdgpu_ctx_do_set_pstate_profile(ctx, pstate_profile); + + mutex_unlock(&mgr->lock); + return r; +} + int amdgpu_ctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { int r; - uint32_t id; + uint32_t id, pstate_profile; int32_t priority; union drm_amdgpu_ctx *args = data; @@ -500,6 +589,14 @@ int amdgpu_ctx_ioctl(struct drm_device *dev, void *data, case AMDGPU_CTX_OP_QUERY_STATE2: r = amdgpu_ctx_query2(adev, fpriv, id, &args->out); break; + case AMDGPU_CTX_OP_SET_PSTATE_PROFILE: + if (args->in.flags & ~AMDGPU_CTX_PSTATE_PROFILE_FLAGS_MASK) + return -EINVAL; + pstate_profile = args->in.flags & AMDGPU_CTX_PSTATE_PROFILE_FLAGS_MASK; + if (pstate_profile > AMDGPU_CTX_PSTATE_PROFILE_PEAK) + return -EINVAL; + r = amdgpu_ctx_set_pstate_profile(adev, fpriv, id, pstate_profile); + break; default: return -EINVAL; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h index a44b8b8ed39c..7007ec9450dd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h @@ -53,6 +53,7 @@ struct amdgpu_ctx { atomic_t guilty; unsigned long ras_counter_ce; unsigned long ras_counter_ue; + uint32_t pstate_profile; }; struct amdgpu_ctx_mgr { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index a1c14466f23d..c72e6153239a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3452,6 +3452,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, init_rwsem(&adev->reset_sem); mutex_init(&adev->psp.mutex); mutex_init(&adev->notifier_lock); + mutex_init(&adev->pstate_profile_ctx_lock); r = amdgpu_device_init_apu_flags(adev); if (r) diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index b9d68339103d..a4c2f7dc2f77 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -206,6 +206,7 @@ union drm_amdgpu_bo_list { #define AMDGPU_CTX_OP_FREE_CTX 2 #define AMDGPU_CTX_OP_QUERY_STATE 3 #define AMDGPU_CTX_OP_QUERY_STATE2 4 +#define AMDGPU_CTX_OP_SET_PSTATE_PROFILE 5 /* GPU reset status */ #define AMDGPU_CTX_NO_RESET 0 @@ -238,6 +239,14 @@ union drm_amdgpu_bo_list { #define AMDGPU_CTX_PRIORITY_HIGH 512 #define AMDGPU_CTX_PRIORITY_VERY_HIGH 1023 +/* select a profiling pstate for perfmon tools */ +#define AMDGPU_CTX_PSTATE_PROFILE_FLAGS_MASK 0xf +#define AMDGPU_CTX_PSTATE_PROFILE_NONE 0 +#define AMDGPU_CTX_PSTATE_PROFILE_STANDARD 1 +#define AMDGPU_CTX_PSTATE_PROFILE_MIN_SCLK 2 +#define AMDGPU_CTX_PSTATE_PROFILE_MIN_MCLK 3 +#define AMDGPU_CTX_PSTATE_PROFILE_PEAK 4 + struct drm_amdgpu_ctx_in { /** AMDGPU_CTX_OP_* */ __u32 op;