162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2015 Advanced Micro Devices, Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 1262306a36Sopenharmony_ci * all copies or substantial portions of the Software. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1562306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1662306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1762306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1862306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1962306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2062306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * Authors: monk liu <monk.liu@amd.com> 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <drm/drm_auth.h> 2662306a36Sopenharmony_ci#include <drm/drm_drv.h> 2762306a36Sopenharmony_ci#include "amdgpu.h" 2862306a36Sopenharmony_ci#include "amdgpu_sched.h" 2962306a36Sopenharmony_ci#include "amdgpu_ras.h" 3062306a36Sopenharmony_ci#include <linux/nospec.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define to_amdgpu_ctx_entity(e) \ 3362306a36Sopenharmony_ci container_of((e), struct amdgpu_ctx_entity, entity) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ciconst unsigned int amdgpu_ctx_num_entities[AMDGPU_HW_IP_NUM] = { 3662306a36Sopenharmony_ci [AMDGPU_HW_IP_GFX] = 1, 3762306a36Sopenharmony_ci [AMDGPU_HW_IP_COMPUTE] = 4, 3862306a36Sopenharmony_ci [AMDGPU_HW_IP_DMA] = 2, 3962306a36Sopenharmony_ci [AMDGPU_HW_IP_UVD] = 1, 4062306a36Sopenharmony_ci [AMDGPU_HW_IP_VCE] = 1, 4162306a36Sopenharmony_ci [AMDGPU_HW_IP_UVD_ENC] = 1, 4262306a36Sopenharmony_ci [AMDGPU_HW_IP_VCN_DEC] = 1, 4362306a36Sopenharmony_ci [AMDGPU_HW_IP_VCN_ENC] = 1, 4462306a36Sopenharmony_ci [AMDGPU_HW_IP_VCN_JPEG] = 1, 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cibool amdgpu_ctx_priority_is_valid(int32_t ctx_prio) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci switch (ctx_prio) { 5062306a36Sopenharmony_ci case AMDGPU_CTX_PRIORITY_VERY_LOW: 5162306a36Sopenharmony_ci case AMDGPU_CTX_PRIORITY_LOW: 5262306a36Sopenharmony_ci case AMDGPU_CTX_PRIORITY_NORMAL: 5362306a36Sopenharmony_ci case AMDGPU_CTX_PRIORITY_HIGH: 5462306a36Sopenharmony_ci case AMDGPU_CTX_PRIORITY_VERY_HIGH: 5562306a36Sopenharmony_ci return true; 5662306a36Sopenharmony_ci default: 5762306a36Sopenharmony_ci case AMDGPU_CTX_PRIORITY_UNSET: 5862306a36Sopenharmony_ci /* UNSET priority is not valid and we don't carry that 5962306a36Sopenharmony_ci * around, but set it to NORMAL in the only place this 6062306a36Sopenharmony_ci * function is called, amdgpu_ctx_ioctl(). 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_ci return false; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic enum drm_sched_priority 6762306a36Sopenharmony_ciamdgpu_ctx_to_drm_sched_prio(int32_t ctx_prio) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci switch (ctx_prio) { 7062306a36Sopenharmony_ci case AMDGPU_CTX_PRIORITY_UNSET: 7162306a36Sopenharmony_ci pr_warn_once("AMD-->DRM context priority value UNSET-->NORMAL"); 7262306a36Sopenharmony_ci return DRM_SCHED_PRIORITY_NORMAL; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci case AMDGPU_CTX_PRIORITY_VERY_LOW: 7562306a36Sopenharmony_ci return DRM_SCHED_PRIORITY_MIN; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci case AMDGPU_CTX_PRIORITY_LOW: 7862306a36Sopenharmony_ci return DRM_SCHED_PRIORITY_MIN; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci case AMDGPU_CTX_PRIORITY_NORMAL: 8162306a36Sopenharmony_ci return DRM_SCHED_PRIORITY_NORMAL; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci case AMDGPU_CTX_PRIORITY_HIGH: 8462306a36Sopenharmony_ci return DRM_SCHED_PRIORITY_HIGH; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci case AMDGPU_CTX_PRIORITY_VERY_HIGH: 8762306a36Sopenharmony_ci return DRM_SCHED_PRIORITY_HIGH; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* This should not happen as we sanitized userspace provided priority 9062306a36Sopenharmony_ci * already, WARN if this happens. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci default: 9362306a36Sopenharmony_ci WARN(1, "Invalid context priority %d\n", ctx_prio); 9462306a36Sopenharmony_ci return DRM_SCHED_PRIORITY_NORMAL; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic int amdgpu_ctx_priority_permit(struct drm_file *filp, 10062306a36Sopenharmony_ci int32_t priority) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci /* NORMAL and below are accessible by everyone */ 10362306a36Sopenharmony_ci if (priority <= AMDGPU_CTX_PRIORITY_NORMAL) 10462306a36Sopenharmony_ci return 0; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (capable(CAP_SYS_NICE)) 10762306a36Sopenharmony_ci return 0; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (drm_is_current_master(filp)) 11062306a36Sopenharmony_ci return 0; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return -EACCES; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic enum amdgpu_gfx_pipe_priority amdgpu_ctx_prio_to_gfx_pipe_prio(int32_t prio) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci switch (prio) { 11862306a36Sopenharmony_ci case AMDGPU_CTX_PRIORITY_HIGH: 11962306a36Sopenharmony_ci case AMDGPU_CTX_PRIORITY_VERY_HIGH: 12062306a36Sopenharmony_ci return AMDGPU_GFX_PIPE_PRIO_HIGH; 12162306a36Sopenharmony_ci default: 12262306a36Sopenharmony_ci return AMDGPU_GFX_PIPE_PRIO_NORMAL; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic enum amdgpu_ring_priority_level amdgpu_ctx_sched_prio_to_ring_prio(int32_t prio) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci switch (prio) { 12962306a36Sopenharmony_ci case AMDGPU_CTX_PRIORITY_HIGH: 13062306a36Sopenharmony_ci return AMDGPU_RING_PRIO_1; 13162306a36Sopenharmony_ci case AMDGPU_CTX_PRIORITY_VERY_HIGH: 13262306a36Sopenharmony_ci return AMDGPU_RING_PRIO_2; 13362306a36Sopenharmony_ci default: 13462306a36Sopenharmony_ci return AMDGPU_RING_PRIO_0; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic unsigned int amdgpu_ctx_get_hw_prio(struct amdgpu_ctx *ctx, u32 hw_ip) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct amdgpu_device *adev = ctx->mgr->adev; 14162306a36Sopenharmony_ci unsigned int hw_prio; 14262306a36Sopenharmony_ci int32_t ctx_prio; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci ctx_prio = (ctx->override_priority == AMDGPU_CTX_PRIORITY_UNSET) ? 14562306a36Sopenharmony_ci ctx->init_priority : ctx->override_priority; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci switch (hw_ip) { 14862306a36Sopenharmony_ci case AMDGPU_HW_IP_GFX: 14962306a36Sopenharmony_ci case AMDGPU_HW_IP_COMPUTE: 15062306a36Sopenharmony_ci hw_prio = amdgpu_ctx_prio_to_gfx_pipe_prio(ctx_prio); 15162306a36Sopenharmony_ci break; 15262306a36Sopenharmony_ci case AMDGPU_HW_IP_VCE: 15362306a36Sopenharmony_ci case AMDGPU_HW_IP_VCN_ENC: 15462306a36Sopenharmony_ci hw_prio = amdgpu_ctx_sched_prio_to_ring_prio(ctx_prio); 15562306a36Sopenharmony_ci break; 15662306a36Sopenharmony_ci default: 15762306a36Sopenharmony_ci hw_prio = AMDGPU_RING_PRIO_DEFAULT; 15862306a36Sopenharmony_ci break; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci hw_ip = array_index_nospec(hw_ip, AMDGPU_HW_IP_NUM); 16262306a36Sopenharmony_ci if (adev->gpu_sched[hw_ip][hw_prio].num_scheds == 0) 16362306a36Sopenharmony_ci hw_prio = AMDGPU_RING_PRIO_DEFAULT; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci return hw_prio; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci/* Calculate the time spend on the hw */ 16962306a36Sopenharmony_cistatic ktime_t amdgpu_ctx_fence_time(struct dma_fence *fence) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct drm_sched_fence *s_fence; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (!fence) 17462306a36Sopenharmony_ci return ns_to_ktime(0); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* When the fence is not even scheduled it can't have spend time */ 17762306a36Sopenharmony_ci s_fence = to_drm_sched_fence(fence); 17862306a36Sopenharmony_ci if (!test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &s_fence->scheduled.flags)) 17962306a36Sopenharmony_ci return ns_to_ktime(0); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* When it is still running account how much already spend */ 18262306a36Sopenharmony_ci if (!test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &s_fence->finished.flags)) 18362306a36Sopenharmony_ci return ktime_sub(ktime_get(), s_fence->scheduled.timestamp); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci return ktime_sub(s_fence->finished.timestamp, 18662306a36Sopenharmony_ci s_fence->scheduled.timestamp); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic ktime_t amdgpu_ctx_entity_time(struct amdgpu_ctx *ctx, 19062306a36Sopenharmony_ci struct amdgpu_ctx_entity *centity) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci ktime_t res = ns_to_ktime(0); 19362306a36Sopenharmony_ci uint32_t i; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci spin_lock(&ctx->ring_lock); 19662306a36Sopenharmony_ci for (i = 0; i < amdgpu_sched_jobs; i++) { 19762306a36Sopenharmony_ci res = ktime_add(res, amdgpu_ctx_fence_time(centity->fences[i])); 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci spin_unlock(&ctx->ring_lock); 20062306a36Sopenharmony_ci return res; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int amdgpu_ctx_init_entity(struct amdgpu_ctx *ctx, u32 hw_ip, 20462306a36Sopenharmony_ci const u32 ring) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct drm_gpu_scheduler **scheds = NULL, *sched = NULL; 20762306a36Sopenharmony_ci struct amdgpu_device *adev = ctx->mgr->adev; 20862306a36Sopenharmony_ci struct amdgpu_ctx_entity *entity; 20962306a36Sopenharmony_ci enum drm_sched_priority drm_prio; 21062306a36Sopenharmony_ci unsigned int hw_prio, num_scheds; 21162306a36Sopenharmony_ci int32_t ctx_prio; 21262306a36Sopenharmony_ci int r; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci entity = kzalloc(struct_size(entity, fences, amdgpu_sched_jobs), 21562306a36Sopenharmony_ci GFP_KERNEL); 21662306a36Sopenharmony_ci if (!entity) 21762306a36Sopenharmony_ci return -ENOMEM; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci ctx_prio = (ctx->override_priority == AMDGPU_CTX_PRIORITY_UNSET) ? 22062306a36Sopenharmony_ci ctx->init_priority : ctx->override_priority; 22162306a36Sopenharmony_ci entity->hw_ip = hw_ip; 22262306a36Sopenharmony_ci entity->sequence = 1; 22362306a36Sopenharmony_ci hw_prio = amdgpu_ctx_get_hw_prio(ctx, hw_ip); 22462306a36Sopenharmony_ci drm_prio = amdgpu_ctx_to_drm_sched_prio(ctx_prio); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci hw_ip = array_index_nospec(hw_ip, AMDGPU_HW_IP_NUM); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (!(adev)->xcp_mgr) { 22962306a36Sopenharmony_ci scheds = adev->gpu_sched[hw_ip][hw_prio].sched; 23062306a36Sopenharmony_ci num_scheds = adev->gpu_sched[hw_ip][hw_prio].num_scheds; 23162306a36Sopenharmony_ci } else { 23262306a36Sopenharmony_ci struct amdgpu_fpriv *fpriv; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci fpriv = container_of(ctx->ctx_mgr, struct amdgpu_fpriv, ctx_mgr); 23562306a36Sopenharmony_ci r = amdgpu_xcp_select_scheds(adev, hw_ip, hw_prio, fpriv, 23662306a36Sopenharmony_ci &num_scheds, &scheds); 23762306a36Sopenharmony_ci if (r) 23862306a36Sopenharmony_ci goto cleanup_entity; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* disable load balance if the hw engine retains context among dependent jobs */ 24262306a36Sopenharmony_ci if (hw_ip == AMDGPU_HW_IP_VCN_ENC || 24362306a36Sopenharmony_ci hw_ip == AMDGPU_HW_IP_VCN_DEC || 24462306a36Sopenharmony_ci hw_ip == AMDGPU_HW_IP_UVD_ENC || 24562306a36Sopenharmony_ci hw_ip == AMDGPU_HW_IP_UVD) { 24662306a36Sopenharmony_ci sched = drm_sched_pick_best(scheds, num_scheds); 24762306a36Sopenharmony_ci scheds = &sched; 24862306a36Sopenharmony_ci num_scheds = 1; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci r = drm_sched_entity_init(&entity->entity, drm_prio, scheds, num_scheds, 25262306a36Sopenharmony_ci &ctx->guilty); 25362306a36Sopenharmony_ci if (r) 25462306a36Sopenharmony_ci goto error_free_entity; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* It's not an error if we fail to install the new entity */ 25762306a36Sopenharmony_ci if (cmpxchg(&ctx->entities[hw_ip][ring], NULL, entity)) 25862306a36Sopenharmony_ci goto cleanup_entity; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cicleanup_entity: 26362306a36Sopenharmony_ci drm_sched_entity_fini(&entity->entity); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cierror_free_entity: 26662306a36Sopenharmony_ci kfree(entity); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci return r; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic ktime_t amdgpu_ctx_fini_entity(struct amdgpu_device *adev, 27262306a36Sopenharmony_ci struct amdgpu_ctx_entity *entity) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci ktime_t res = ns_to_ktime(0); 27562306a36Sopenharmony_ci int i; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (!entity) 27862306a36Sopenharmony_ci return res; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci for (i = 0; i < amdgpu_sched_jobs; ++i) { 28162306a36Sopenharmony_ci res = ktime_add(res, amdgpu_ctx_fence_time(entity->fences[i])); 28262306a36Sopenharmony_ci dma_fence_put(entity->fences[i]); 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci amdgpu_xcp_release_sched(adev, entity); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci kfree(entity); 28862306a36Sopenharmony_ci return res; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic int amdgpu_ctx_get_stable_pstate(struct amdgpu_ctx *ctx, 29262306a36Sopenharmony_ci u32 *stable_pstate) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci struct amdgpu_device *adev = ctx->mgr->adev; 29562306a36Sopenharmony_ci enum amd_dpm_forced_level current_level; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci current_level = amdgpu_dpm_get_performance_level(adev); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci switch (current_level) { 30062306a36Sopenharmony_ci case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: 30162306a36Sopenharmony_ci *stable_pstate = AMDGPU_CTX_STABLE_PSTATE_STANDARD; 30262306a36Sopenharmony_ci break; 30362306a36Sopenharmony_ci case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: 30462306a36Sopenharmony_ci *stable_pstate = AMDGPU_CTX_STABLE_PSTATE_MIN_SCLK; 30562306a36Sopenharmony_ci break; 30662306a36Sopenharmony_ci case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: 30762306a36Sopenharmony_ci *stable_pstate = AMDGPU_CTX_STABLE_PSTATE_MIN_MCLK; 30862306a36Sopenharmony_ci break; 30962306a36Sopenharmony_ci case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: 31062306a36Sopenharmony_ci *stable_pstate = AMDGPU_CTX_STABLE_PSTATE_PEAK; 31162306a36Sopenharmony_ci break; 31262306a36Sopenharmony_ci default: 31362306a36Sopenharmony_ci *stable_pstate = AMDGPU_CTX_STABLE_PSTATE_NONE; 31462306a36Sopenharmony_ci break; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic int amdgpu_ctx_init(struct amdgpu_ctx_mgr *mgr, int32_t priority, 32062306a36Sopenharmony_ci struct drm_file *filp, struct amdgpu_ctx *ctx) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci struct amdgpu_fpriv *fpriv = filp->driver_priv; 32362306a36Sopenharmony_ci u32 current_stable_pstate; 32462306a36Sopenharmony_ci int r; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci r = amdgpu_ctx_priority_permit(filp, priority); 32762306a36Sopenharmony_ci if (r) 32862306a36Sopenharmony_ci return r; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci memset(ctx, 0, sizeof(*ctx)); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci kref_init(&ctx->refcount); 33362306a36Sopenharmony_ci ctx->mgr = mgr; 33462306a36Sopenharmony_ci spin_lock_init(&ctx->ring_lock); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci ctx->reset_counter = atomic_read(&mgr->adev->gpu_reset_counter); 33762306a36Sopenharmony_ci ctx->reset_counter_query = ctx->reset_counter; 33862306a36Sopenharmony_ci ctx->generation = amdgpu_vm_generation(mgr->adev, &fpriv->vm); 33962306a36Sopenharmony_ci ctx->init_priority = priority; 34062306a36Sopenharmony_ci ctx->override_priority = AMDGPU_CTX_PRIORITY_UNSET; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci r = amdgpu_ctx_get_stable_pstate(ctx, ¤t_stable_pstate); 34362306a36Sopenharmony_ci if (r) 34462306a36Sopenharmony_ci return r; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (mgr->adev->pm.stable_pstate_ctx) 34762306a36Sopenharmony_ci ctx->stable_pstate = mgr->adev->pm.stable_pstate_ctx->stable_pstate; 34862306a36Sopenharmony_ci else 34962306a36Sopenharmony_ci ctx->stable_pstate = current_stable_pstate; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci ctx->ctx_mgr = &(fpriv->ctx_mgr); 35262306a36Sopenharmony_ci return 0; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic int amdgpu_ctx_set_stable_pstate(struct amdgpu_ctx *ctx, 35662306a36Sopenharmony_ci u32 stable_pstate) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci struct amdgpu_device *adev = ctx->mgr->adev; 35962306a36Sopenharmony_ci enum amd_dpm_forced_level level; 36062306a36Sopenharmony_ci u32 current_stable_pstate; 36162306a36Sopenharmony_ci int r; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci mutex_lock(&adev->pm.stable_pstate_ctx_lock); 36462306a36Sopenharmony_ci if (adev->pm.stable_pstate_ctx && adev->pm.stable_pstate_ctx != ctx) { 36562306a36Sopenharmony_ci r = -EBUSY; 36662306a36Sopenharmony_ci goto done; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci r = amdgpu_ctx_get_stable_pstate(ctx, ¤t_stable_pstate); 37062306a36Sopenharmony_ci if (r || (stable_pstate == current_stable_pstate)) 37162306a36Sopenharmony_ci goto done; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci switch (stable_pstate) { 37462306a36Sopenharmony_ci case AMDGPU_CTX_STABLE_PSTATE_NONE: 37562306a36Sopenharmony_ci level = AMD_DPM_FORCED_LEVEL_AUTO; 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci case AMDGPU_CTX_STABLE_PSTATE_STANDARD: 37862306a36Sopenharmony_ci level = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD; 37962306a36Sopenharmony_ci break; 38062306a36Sopenharmony_ci case AMDGPU_CTX_STABLE_PSTATE_MIN_SCLK: 38162306a36Sopenharmony_ci level = AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK; 38262306a36Sopenharmony_ci break; 38362306a36Sopenharmony_ci case AMDGPU_CTX_STABLE_PSTATE_MIN_MCLK: 38462306a36Sopenharmony_ci level = AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK; 38562306a36Sopenharmony_ci break; 38662306a36Sopenharmony_ci case AMDGPU_CTX_STABLE_PSTATE_PEAK: 38762306a36Sopenharmony_ci level = AMD_DPM_FORCED_LEVEL_PROFILE_PEAK; 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci default: 39062306a36Sopenharmony_ci r = -EINVAL; 39162306a36Sopenharmony_ci goto done; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci r = amdgpu_dpm_force_performance_level(adev, level); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (level == AMD_DPM_FORCED_LEVEL_AUTO) 39762306a36Sopenharmony_ci adev->pm.stable_pstate_ctx = NULL; 39862306a36Sopenharmony_ci else 39962306a36Sopenharmony_ci adev->pm.stable_pstate_ctx = ctx; 40062306a36Sopenharmony_cidone: 40162306a36Sopenharmony_ci mutex_unlock(&adev->pm.stable_pstate_ctx_lock); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return r; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic void amdgpu_ctx_fini(struct kref *ref) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct amdgpu_ctx *ctx = container_of(ref, struct amdgpu_ctx, refcount); 40962306a36Sopenharmony_ci struct amdgpu_ctx_mgr *mgr = ctx->mgr; 41062306a36Sopenharmony_ci struct amdgpu_device *adev = mgr->adev; 41162306a36Sopenharmony_ci unsigned i, j, idx; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (!adev) 41462306a36Sopenharmony_ci return; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) { 41762306a36Sopenharmony_ci for (j = 0; j < AMDGPU_MAX_ENTITY_NUM; ++j) { 41862306a36Sopenharmony_ci ktime_t spend; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci spend = amdgpu_ctx_fini_entity(adev, ctx->entities[i][j]); 42162306a36Sopenharmony_ci atomic64_add(ktime_to_ns(spend), &mgr->time_spend[i]); 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (drm_dev_enter(adev_to_drm(adev), &idx)) { 42662306a36Sopenharmony_ci amdgpu_ctx_set_stable_pstate(ctx, ctx->stable_pstate); 42762306a36Sopenharmony_ci drm_dev_exit(idx); 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci kfree(ctx); 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ciint amdgpu_ctx_get_entity(struct amdgpu_ctx *ctx, u32 hw_ip, u32 instance, 43462306a36Sopenharmony_ci u32 ring, struct drm_sched_entity **entity) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci int r; 43762306a36Sopenharmony_ci struct drm_sched_entity *ctx_entity; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (hw_ip >= AMDGPU_HW_IP_NUM) { 44062306a36Sopenharmony_ci DRM_ERROR("unknown HW IP type: %d\n", hw_ip); 44162306a36Sopenharmony_ci return -EINVAL; 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci /* Right now all IPs have only one instance - multiple rings. */ 44562306a36Sopenharmony_ci if (instance != 0) { 44662306a36Sopenharmony_ci DRM_DEBUG("invalid ip instance: %d\n", instance); 44762306a36Sopenharmony_ci return -EINVAL; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if (ring >= amdgpu_ctx_num_entities[hw_ip]) { 45162306a36Sopenharmony_ci DRM_DEBUG("invalid ring: %d %d\n", hw_ip, ring); 45262306a36Sopenharmony_ci return -EINVAL; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (ctx->entities[hw_ip][ring] == NULL) { 45662306a36Sopenharmony_ci r = amdgpu_ctx_init_entity(ctx, hw_ip, ring); 45762306a36Sopenharmony_ci if (r) 45862306a36Sopenharmony_ci return r; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci ctx_entity = &ctx->entities[hw_ip][ring]->entity; 46262306a36Sopenharmony_ci r = drm_sched_entity_error(ctx_entity); 46362306a36Sopenharmony_ci if (r) { 46462306a36Sopenharmony_ci DRM_DEBUG("error entity %p\n", ctx_entity); 46562306a36Sopenharmony_ci return r; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci *entity = ctx_entity; 46962306a36Sopenharmony_ci return 0; 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic int amdgpu_ctx_alloc(struct amdgpu_device *adev, 47362306a36Sopenharmony_ci struct amdgpu_fpriv *fpriv, 47462306a36Sopenharmony_ci struct drm_file *filp, 47562306a36Sopenharmony_ci int32_t priority, 47662306a36Sopenharmony_ci uint32_t *id) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr; 47962306a36Sopenharmony_ci struct amdgpu_ctx *ctx; 48062306a36Sopenharmony_ci int r; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); 48362306a36Sopenharmony_ci if (!ctx) 48462306a36Sopenharmony_ci return -ENOMEM; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci mutex_lock(&mgr->lock); 48762306a36Sopenharmony_ci r = idr_alloc(&mgr->ctx_handles, ctx, 1, AMDGPU_VM_MAX_NUM_CTX, GFP_KERNEL); 48862306a36Sopenharmony_ci if (r < 0) { 48962306a36Sopenharmony_ci mutex_unlock(&mgr->lock); 49062306a36Sopenharmony_ci kfree(ctx); 49162306a36Sopenharmony_ci return r; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci *id = (uint32_t)r; 49562306a36Sopenharmony_ci r = amdgpu_ctx_init(mgr, priority, filp, ctx); 49662306a36Sopenharmony_ci if (r) { 49762306a36Sopenharmony_ci idr_remove(&mgr->ctx_handles, *id); 49862306a36Sopenharmony_ci *id = 0; 49962306a36Sopenharmony_ci kfree(ctx); 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci mutex_unlock(&mgr->lock); 50262306a36Sopenharmony_ci return r; 50362306a36Sopenharmony_ci} 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cistatic void amdgpu_ctx_do_release(struct kref *ref) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct amdgpu_ctx *ctx; 50862306a36Sopenharmony_ci u32 i, j; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci ctx = container_of(ref, struct amdgpu_ctx, refcount); 51162306a36Sopenharmony_ci for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) { 51262306a36Sopenharmony_ci for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) { 51362306a36Sopenharmony_ci if (!ctx->entities[i][j]) 51462306a36Sopenharmony_ci continue; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci drm_sched_entity_destroy(&ctx->entities[i][j]->entity); 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci amdgpu_ctx_fini(ref); 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic int amdgpu_ctx_free(struct amdgpu_fpriv *fpriv, uint32_t id) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr; 52662306a36Sopenharmony_ci struct amdgpu_ctx *ctx; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci mutex_lock(&mgr->lock); 52962306a36Sopenharmony_ci ctx = idr_remove(&mgr->ctx_handles, id); 53062306a36Sopenharmony_ci if (ctx) 53162306a36Sopenharmony_ci kref_put(&ctx->refcount, amdgpu_ctx_do_release); 53262306a36Sopenharmony_ci mutex_unlock(&mgr->lock); 53362306a36Sopenharmony_ci return ctx ? 0 : -EINVAL; 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic int amdgpu_ctx_query(struct amdgpu_device *adev, 53762306a36Sopenharmony_ci struct amdgpu_fpriv *fpriv, uint32_t id, 53862306a36Sopenharmony_ci union drm_amdgpu_ctx_out *out) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct amdgpu_ctx *ctx; 54162306a36Sopenharmony_ci struct amdgpu_ctx_mgr *mgr; 54262306a36Sopenharmony_ci unsigned reset_counter; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci if (!fpriv) 54562306a36Sopenharmony_ci return -EINVAL; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci mgr = &fpriv->ctx_mgr; 54862306a36Sopenharmony_ci mutex_lock(&mgr->lock); 54962306a36Sopenharmony_ci ctx = idr_find(&mgr->ctx_handles, id); 55062306a36Sopenharmony_ci if (!ctx) { 55162306a36Sopenharmony_ci mutex_unlock(&mgr->lock); 55262306a36Sopenharmony_ci return -EINVAL; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* TODO: these two are always zero */ 55662306a36Sopenharmony_ci out->state.flags = 0x0; 55762306a36Sopenharmony_ci out->state.hangs = 0x0; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* determine if a GPU reset has occured since the last call */ 56062306a36Sopenharmony_ci reset_counter = atomic_read(&adev->gpu_reset_counter); 56162306a36Sopenharmony_ci /* TODO: this should ideally return NO, GUILTY, or INNOCENT. */ 56262306a36Sopenharmony_ci if (ctx->reset_counter_query == reset_counter) 56362306a36Sopenharmony_ci out->state.reset_status = AMDGPU_CTX_NO_RESET; 56462306a36Sopenharmony_ci else 56562306a36Sopenharmony_ci out->state.reset_status = AMDGPU_CTX_UNKNOWN_RESET; 56662306a36Sopenharmony_ci ctx->reset_counter_query = reset_counter; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci mutex_unlock(&mgr->lock); 56962306a36Sopenharmony_ci return 0; 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci#define AMDGPU_RAS_COUNTE_DELAY_MS 3000 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic int amdgpu_ctx_query2(struct amdgpu_device *adev, 57562306a36Sopenharmony_ci struct amdgpu_fpriv *fpriv, uint32_t id, 57662306a36Sopenharmony_ci union drm_amdgpu_ctx_out *out) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct amdgpu_ras *con = amdgpu_ras_get_context(adev); 57962306a36Sopenharmony_ci struct amdgpu_ctx *ctx; 58062306a36Sopenharmony_ci struct amdgpu_ctx_mgr *mgr; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (!fpriv) 58362306a36Sopenharmony_ci return -EINVAL; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci mgr = &fpriv->ctx_mgr; 58662306a36Sopenharmony_ci mutex_lock(&mgr->lock); 58762306a36Sopenharmony_ci ctx = idr_find(&mgr->ctx_handles, id); 58862306a36Sopenharmony_ci if (!ctx) { 58962306a36Sopenharmony_ci mutex_unlock(&mgr->lock); 59062306a36Sopenharmony_ci return -EINVAL; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci out->state.flags = 0x0; 59462306a36Sopenharmony_ci out->state.hangs = 0x0; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (ctx->reset_counter != atomic_read(&adev->gpu_reset_counter)) 59762306a36Sopenharmony_ci out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_RESET; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (ctx->generation != amdgpu_vm_generation(adev, &fpriv->vm)) 60062306a36Sopenharmony_ci out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_VRAMLOST; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (atomic_read(&ctx->guilty)) 60362306a36Sopenharmony_ci out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_GUILTY; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci if (amdgpu_in_reset(adev)) 60662306a36Sopenharmony_ci out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_RESET_IN_PROGRESS; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (adev->ras_enabled && con) { 60962306a36Sopenharmony_ci /* Return the cached values in O(1), 61062306a36Sopenharmony_ci * and schedule delayed work to cache 61162306a36Sopenharmony_ci * new vaues. 61262306a36Sopenharmony_ci */ 61362306a36Sopenharmony_ci int ce_count, ue_count; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci ce_count = atomic_read(&con->ras_ce_count); 61662306a36Sopenharmony_ci ue_count = atomic_read(&con->ras_ue_count); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci if (ce_count != ctx->ras_counter_ce) { 61962306a36Sopenharmony_ci ctx->ras_counter_ce = ce_count; 62062306a36Sopenharmony_ci out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_RAS_CE; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (ue_count != ctx->ras_counter_ue) { 62462306a36Sopenharmony_ci ctx->ras_counter_ue = ue_count; 62562306a36Sopenharmony_ci out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_RAS_UE; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci schedule_delayed_work(&con->ras_counte_delay_work, 62962306a36Sopenharmony_ci msecs_to_jiffies(AMDGPU_RAS_COUNTE_DELAY_MS)); 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci mutex_unlock(&mgr->lock); 63362306a36Sopenharmony_ci return 0; 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic int amdgpu_ctx_stable_pstate(struct amdgpu_device *adev, 63762306a36Sopenharmony_ci struct amdgpu_fpriv *fpriv, uint32_t id, 63862306a36Sopenharmony_ci bool set, u32 *stable_pstate) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci struct amdgpu_ctx *ctx; 64162306a36Sopenharmony_ci struct amdgpu_ctx_mgr *mgr; 64262306a36Sopenharmony_ci int r; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (!fpriv) 64562306a36Sopenharmony_ci return -EINVAL; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci mgr = &fpriv->ctx_mgr; 64862306a36Sopenharmony_ci mutex_lock(&mgr->lock); 64962306a36Sopenharmony_ci ctx = idr_find(&mgr->ctx_handles, id); 65062306a36Sopenharmony_ci if (!ctx) { 65162306a36Sopenharmony_ci mutex_unlock(&mgr->lock); 65262306a36Sopenharmony_ci return -EINVAL; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci if (set) 65662306a36Sopenharmony_ci r = amdgpu_ctx_set_stable_pstate(ctx, *stable_pstate); 65762306a36Sopenharmony_ci else 65862306a36Sopenharmony_ci r = amdgpu_ctx_get_stable_pstate(ctx, stable_pstate); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci mutex_unlock(&mgr->lock); 66162306a36Sopenharmony_ci return r; 66262306a36Sopenharmony_ci} 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ciint amdgpu_ctx_ioctl(struct drm_device *dev, void *data, 66562306a36Sopenharmony_ci struct drm_file *filp) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci int r; 66862306a36Sopenharmony_ci uint32_t id, stable_pstate; 66962306a36Sopenharmony_ci int32_t priority; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci union drm_amdgpu_ctx *args = data; 67262306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 67362306a36Sopenharmony_ci struct amdgpu_fpriv *fpriv = filp->driver_priv; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci id = args->in.ctx_id; 67662306a36Sopenharmony_ci priority = args->in.priority; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci /* For backwards compatibility, we need to accept ioctls with garbage 67962306a36Sopenharmony_ci * in the priority field. Garbage values in the priority field, result 68062306a36Sopenharmony_ci * in the priority being set to NORMAL. 68162306a36Sopenharmony_ci */ 68262306a36Sopenharmony_ci if (!amdgpu_ctx_priority_is_valid(priority)) 68362306a36Sopenharmony_ci priority = AMDGPU_CTX_PRIORITY_NORMAL; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci switch (args->in.op) { 68662306a36Sopenharmony_ci case AMDGPU_CTX_OP_ALLOC_CTX: 68762306a36Sopenharmony_ci r = amdgpu_ctx_alloc(adev, fpriv, filp, priority, &id); 68862306a36Sopenharmony_ci args->out.alloc.ctx_id = id; 68962306a36Sopenharmony_ci break; 69062306a36Sopenharmony_ci case AMDGPU_CTX_OP_FREE_CTX: 69162306a36Sopenharmony_ci r = amdgpu_ctx_free(fpriv, id); 69262306a36Sopenharmony_ci break; 69362306a36Sopenharmony_ci case AMDGPU_CTX_OP_QUERY_STATE: 69462306a36Sopenharmony_ci r = amdgpu_ctx_query(adev, fpriv, id, &args->out); 69562306a36Sopenharmony_ci break; 69662306a36Sopenharmony_ci case AMDGPU_CTX_OP_QUERY_STATE2: 69762306a36Sopenharmony_ci r = amdgpu_ctx_query2(adev, fpriv, id, &args->out); 69862306a36Sopenharmony_ci break; 69962306a36Sopenharmony_ci case AMDGPU_CTX_OP_GET_STABLE_PSTATE: 70062306a36Sopenharmony_ci if (args->in.flags) 70162306a36Sopenharmony_ci return -EINVAL; 70262306a36Sopenharmony_ci r = amdgpu_ctx_stable_pstate(adev, fpriv, id, false, &stable_pstate); 70362306a36Sopenharmony_ci if (!r) 70462306a36Sopenharmony_ci args->out.pstate.flags = stable_pstate; 70562306a36Sopenharmony_ci break; 70662306a36Sopenharmony_ci case AMDGPU_CTX_OP_SET_STABLE_PSTATE: 70762306a36Sopenharmony_ci if (args->in.flags & ~AMDGPU_CTX_STABLE_PSTATE_FLAGS_MASK) 70862306a36Sopenharmony_ci return -EINVAL; 70962306a36Sopenharmony_ci stable_pstate = args->in.flags & AMDGPU_CTX_STABLE_PSTATE_FLAGS_MASK; 71062306a36Sopenharmony_ci if (stable_pstate > AMDGPU_CTX_STABLE_PSTATE_PEAK) 71162306a36Sopenharmony_ci return -EINVAL; 71262306a36Sopenharmony_ci r = amdgpu_ctx_stable_pstate(adev, fpriv, id, true, &stable_pstate); 71362306a36Sopenharmony_ci break; 71462306a36Sopenharmony_ci default: 71562306a36Sopenharmony_ci return -EINVAL; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci return r; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistruct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci struct amdgpu_ctx *ctx; 72462306a36Sopenharmony_ci struct amdgpu_ctx_mgr *mgr; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if (!fpriv) 72762306a36Sopenharmony_ci return NULL; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci mgr = &fpriv->ctx_mgr; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci mutex_lock(&mgr->lock); 73262306a36Sopenharmony_ci ctx = idr_find(&mgr->ctx_handles, id); 73362306a36Sopenharmony_ci if (ctx) 73462306a36Sopenharmony_ci kref_get(&ctx->refcount); 73562306a36Sopenharmony_ci mutex_unlock(&mgr->lock); 73662306a36Sopenharmony_ci return ctx; 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ciint amdgpu_ctx_put(struct amdgpu_ctx *ctx) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci if (ctx == NULL) 74262306a36Sopenharmony_ci return -EINVAL; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci kref_put(&ctx->refcount, amdgpu_ctx_do_release); 74562306a36Sopenharmony_ci return 0; 74662306a36Sopenharmony_ci} 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ciuint64_t amdgpu_ctx_add_fence(struct amdgpu_ctx *ctx, 74962306a36Sopenharmony_ci struct drm_sched_entity *entity, 75062306a36Sopenharmony_ci struct dma_fence *fence) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci struct amdgpu_ctx_entity *centity = to_amdgpu_ctx_entity(entity); 75362306a36Sopenharmony_ci uint64_t seq = centity->sequence; 75462306a36Sopenharmony_ci struct dma_fence *other = NULL; 75562306a36Sopenharmony_ci unsigned idx = 0; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci idx = seq & (amdgpu_sched_jobs - 1); 75862306a36Sopenharmony_ci other = centity->fences[idx]; 75962306a36Sopenharmony_ci WARN_ON(other && !dma_fence_is_signaled(other)); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci dma_fence_get(fence); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci spin_lock(&ctx->ring_lock); 76462306a36Sopenharmony_ci centity->fences[idx] = fence; 76562306a36Sopenharmony_ci centity->sequence++; 76662306a36Sopenharmony_ci spin_unlock(&ctx->ring_lock); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci atomic64_add(ktime_to_ns(amdgpu_ctx_fence_time(other)), 76962306a36Sopenharmony_ci &ctx->mgr->time_spend[centity->hw_ip]); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci dma_fence_put(other); 77262306a36Sopenharmony_ci return seq; 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_cistruct dma_fence *amdgpu_ctx_get_fence(struct amdgpu_ctx *ctx, 77662306a36Sopenharmony_ci struct drm_sched_entity *entity, 77762306a36Sopenharmony_ci uint64_t seq) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci struct amdgpu_ctx_entity *centity = to_amdgpu_ctx_entity(entity); 78062306a36Sopenharmony_ci struct dma_fence *fence; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci spin_lock(&ctx->ring_lock); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (seq == ~0ull) 78562306a36Sopenharmony_ci seq = centity->sequence - 1; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (seq >= centity->sequence) { 78862306a36Sopenharmony_ci spin_unlock(&ctx->ring_lock); 78962306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci if (seq + amdgpu_sched_jobs < centity->sequence) { 79462306a36Sopenharmony_ci spin_unlock(&ctx->ring_lock); 79562306a36Sopenharmony_ci return NULL; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci fence = dma_fence_get(centity->fences[seq & (amdgpu_sched_jobs - 1)]); 79962306a36Sopenharmony_ci spin_unlock(&ctx->ring_lock); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci return fence; 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_cistatic void amdgpu_ctx_set_entity_priority(struct amdgpu_ctx *ctx, 80562306a36Sopenharmony_ci struct amdgpu_ctx_entity *aentity, 80662306a36Sopenharmony_ci int hw_ip, 80762306a36Sopenharmony_ci int32_t priority) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci struct amdgpu_device *adev = ctx->mgr->adev; 81062306a36Sopenharmony_ci unsigned int hw_prio; 81162306a36Sopenharmony_ci struct drm_gpu_scheduler **scheds = NULL; 81262306a36Sopenharmony_ci unsigned num_scheds; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci /* set sw priority */ 81562306a36Sopenharmony_ci drm_sched_entity_set_priority(&aentity->entity, 81662306a36Sopenharmony_ci amdgpu_ctx_to_drm_sched_prio(priority)); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci /* set hw priority */ 81962306a36Sopenharmony_ci if (hw_ip == AMDGPU_HW_IP_COMPUTE || hw_ip == AMDGPU_HW_IP_GFX) { 82062306a36Sopenharmony_ci hw_prio = amdgpu_ctx_get_hw_prio(ctx, hw_ip); 82162306a36Sopenharmony_ci hw_prio = array_index_nospec(hw_prio, AMDGPU_RING_PRIO_MAX); 82262306a36Sopenharmony_ci scheds = adev->gpu_sched[hw_ip][hw_prio].sched; 82362306a36Sopenharmony_ci num_scheds = adev->gpu_sched[hw_ip][hw_prio].num_scheds; 82462306a36Sopenharmony_ci drm_sched_entity_modify_sched(&aentity->entity, scheds, 82562306a36Sopenharmony_ci num_scheds); 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_civoid amdgpu_ctx_priority_override(struct amdgpu_ctx *ctx, 83062306a36Sopenharmony_ci int32_t priority) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci int32_t ctx_prio; 83362306a36Sopenharmony_ci unsigned i, j; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci ctx->override_priority = priority; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci ctx_prio = (ctx->override_priority == AMDGPU_CTX_PRIORITY_UNSET) ? 83862306a36Sopenharmony_ci ctx->init_priority : ctx->override_priority; 83962306a36Sopenharmony_ci for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) { 84062306a36Sopenharmony_ci for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) { 84162306a36Sopenharmony_ci if (!ctx->entities[i][j]) 84262306a36Sopenharmony_ci continue; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci amdgpu_ctx_set_entity_priority(ctx, ctx->entities[i][j], 84562306a36Sopenharmony_ci i, ctx_prio); 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ciint amdgpu_ctx_wait_prev_fence(struct amdgpu_ctx *ctx, 85162306a36Sopenharmony_ci struct drm_sched_entity *entity) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci struct amdgpu_ctx_entity *centity = to_amdgpu_ctx_entity(entity); 85462306a36Sopenharmony_ci struct dma_fence *other; 85562306a36Sopenharmony_ci unsigned idx; 85662306a36Sopenharmony_ci long r; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci spin_lock(&ctx->ring_lock); 85962306a36Sopenharmony_ci idx = centity->sequence & (amdgpu_sched_jobs - 1); 86062306a36Sopenharmony_ci other = dma_fence_get(centity->fences[idx]); 86162306a36Sopenharmony_ci spin_unlock(&ctx->ring_lock); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci if (!other) 86462306a36Sopenharmony_ci return 0; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci r = dma_fence_wait(other, true); 86762306a36Sopenharmony_ci if (r < 0 && r != -ERESTARTSYS) 86862306a36Sopenharmony_ci DRM_ERROR("Error (%ld) waiting for fence!\n", r); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci dma_fence_put(other); 87162306a36Sopenharmony_ci return r; 87262306a36Sopenharmony_ci} 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_civoid amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr, 87562306a36Sopenharmony_ci struct amdgpu_device *adev) 87662306a36Sopenharmony_ci{ 87762306a36Sopenharmony_ci unsigned int i; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci mgr->adev = adev; 88062306a36Sopenharmony_ci mutex_init(&mgr->lock); 88162306a36Sopenharmony_ci idr_init_base(&mgr->ctx_handles, 1); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) 88462306a36Sopenharmony_ci atomic64_set(&mgr->time_spend[i], 0); 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_cilong amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout) 88862306a36Sopenharmony_ci{ 88962306a36Sopenharmony_ci struct amdgpu_ctx *ctx; 89062306a36Sopenharmony_ci struct idr *idp; 89162306a36Sopenharmony_ci uint32_t id, i, j; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci idp = &mgr->ctx_handles; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci mutex_lock(&mgr->lock); 89662306a36Sopenharmony_ci idr_for_each_entry(idp, ctx, id) { 89762306a36Sopenharmony_ci for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) { 89862306a36Sopenharmony_ci for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) { 89962306a36Sopenharmony_ci struct drm_sched_entity *entity; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (!ctx->entities[i][j]) 90262306a36Sopenharmony_ci continue; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci entity = &ctx->entities[i][j]->entity; 90562306a36Sopenharmony_ci timeout = drm_sched_entity_flush(entity, timeout); 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci mutex_unlock(&mgr->lock); 91062306a36Sopenharmony_ci return timeout; 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_civoid amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci struct amdgpu_ctx *ctx; 91662306a36Sopenharmony_ci struct idr *idp; 91762306a36Sopenharmony_ci uint32_t id, i, j; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci idp = &mgr->ctx_handles; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci idr_for_each_entry(idp, ctx, id) { 92262306a36Sopenharmony_ci if (kref_read(&ctx->refcount) != 1) { 92362306a36Sopenharmony_ci DRM_ERROR("ctx %p is still alive\n", ctx); 92462306a36Sopenharmony_ci continue; 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) { 92862306a36Sopenharmony_ci for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) { 92962306a36Sopenharmony_ci struct drm_sched_entity *entity; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci if (!ctx->entities[i][j]) 93262306a36Sopenharmony_ci continue; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci entity = &ctx->entities[i][j]->entity; 93562306a36Sopenharmony_ci drm_sched_entity_fini(entity); 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci } 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_civoid amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci struct amdgpu_ctx *ctx; 94462306a36Sopenharmony_ci struct idr *idp; 94562306a36Sopenharmony_ci uint32_t id; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci amdgpu_ctx_mgr_entity_fini(mgr); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci idp = &mgr->ctx_handles; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci idr_for_each_entry(idp, ctx, id) { 95262306a36Sopenharmony_ci if (kref_put(&ctx->refcount, amdgpu_ctx_fini) != 1) 95362306a36Sopenharmony_ci DRM_ERROR("ctx %p is still alive\n", ctx); 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci idr_destroy(&mgr->ctx_handles); 95762306a36Sopenharmony_ci mutex_destroy(&mgr->lock); 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_civoid amdgpu_ctx_mgr_usage(struct amdgpu_ctx_mgr *mgr, 96162306a36Sopenharmony_ci ktime_t usage[AMDGPU_HW_IP_NUM]) 96262306a36Sopenharmony_ci{ 96362306a36Sopenharmony_ci struct amdgpu_ctx *ctx; 96462306a36Sopenharmony_ci unsigned int hw_ip, i; 96562306a36Sopenharmony_ci uint32_t id; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci /* 96862306a36Sopenharmony_ci * This is a little bit racy because it can be that a ctx or a fence are 96962306a36Sopenharmony_ci * destroyed just in the moment we try to account them. But that is ok 97062306a36Sopenharmony_ci * since exactly that case is explicitely allowed by the interface. 97162306a36Sopenharmony_ci */ 97262306a36Sopenharmony_ci mutex_lock(&mgr->lock); 97362306a36Sopenharmony_ci for (hw_ip = 0; hw_ip < AMDGPU_HW_IP_NUM; ++hw_ip) { 97462306a36Sopenharmony_ci uint64_t ns = atomic64_read(&mgr->time_spend[hw_ip]); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci usage[hw_ip] = ns_to_ktime(ns); 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci idr_for_each_entry(&mgr->ctx_handles, ctx, id) { 98062306a36Sopenharmony_ci for (hw_ip = 0; hw_ip < AMDGPU_HW_IP_NUM; ++hw_ip) { 98162306a36Sopenharmony_ci for (i = 0; i < amdgpu_ctx_num_entities[hw_ip]; ++i) { 98262306a36Sopenharmony_ci struct amdgpu_ctx_entity *centity; 98362306a36Sopenharmony_ci ktime_t spend; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci centity = ctx->entities[hw_ip][i]; 98662306a36Sopenharmony_ci if (!centity) 98762306a36Sopenharmony_ci continue; 98862306a36Sopenharmony_ci spend = amdgpu_ctx_entity_time(ctx, centity); 98962306a36Sopenharmony_ci usage[hw_ip] = ktime_add(usage[hw_ip], spend); 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci mutex_unlock(&mgr->lock); 99462306a36Sopenharmony_ci} 995