18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2015 Advanced Micro Devices, Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 128c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 158c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 178c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 188c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 198c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 208c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Authors: monk liu <monk.liu@amd.com> 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <drm/drm_auth.h> 268c2ecf20Sopenharmony_ci#include "amdgpu.h" 278c2ecf20Sopenharmony_ci#include "amdgpu_sched.h" 288c2ecf20Sopenharmony_ci#include "amdgpu_ras.h" 298c2ecf20Sopenharmony_ci#include <linux/nospec.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define to_amdgpu_ctx_entity(e) \ 328c2ecf20Sopenharmony_ci container_of((e), struct amdgpu_ctx_entity, entity) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ciconst unsigned int amdgpu_ctx_num_entities[AMDGPU_HW_IP_NUM] = { 358c2ecf20Sopenharmony_ci [AMDGPU_HW_IP_GFX] = 1, 368c2ecf20Sopenharmony_ci [AMDGPU_HW_IP_COMPUTE] = 4, 378c2ecf20Sopenharmony_ci [AMDGPU_HW_IP_DMA] = 2, 388c2ecf20Sopenharmony_ci [AMDGPU_HW_IP_UVD] = 1, 398c2ecf20Sopenharmony_ci [AMDGPU_HW_IP_VCE] = 1, 408c2ecf20Sopenharmony_ci [AMDGPU_HW_IP_UVD_ENC] = 1, 418c2ecf20Sopenharmony_ci [AMDGPU_HW_IP_VCN_DEC] = 1, 428c2ecf20Sopenharmony_ci [AMDGPU_HW_IP_VCN_ENC] = 1, 438c2ecf20Sopenharmony_ci [AMDGPU_HW_IP_VCN_JPEG] = 1, 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int amdgpu_ctx_priority_permit(struct drm_file *filp, 478c2ecf20Sopenharmony_ci enum drm_sched_priority priority) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci if (priority < 0 || priority >= DRM_SCHED_PRIORITY_COUNT) 508c2ecf20Sopenharmony_ci return -EINVAL; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* NORMAL and below are accessible by everyone */ 538c2ecf20Sopenharmony_ci if (priority <= DRM_SCHED_PRIORITY_NORMAL) 548c2ecf20Sopenharmony_ci return 0; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (capable(CAP_SYS_NICE)) 578c2ecf20Sopenharmony_ci return 0; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (drm_is_current_master(filp)) 608c2ecf20Sopenharmony_ci return 0; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci return -EACCES; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic enum gfx_pipe_priority amdgpu_ctx_sched_prio_to_compute_prio(enum drm_sched_priority prio) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci switch (prio) { 688c2ecf20Sopenharmony_ci case DRM_SCHED_PRIORITY_HIGH: 698c2ecf20Sopenharmony_ci case DRM_SCHED_PRIORITY_KERNEL: 708c2ecf20Sopenharmony_ci return AMDGPU_GFX_PIPE_PRIO_HIGH; 718c2ecf20Sopenharmony_ci default: 728c2ecf20Sopenharmony_ci return AMDGPU_GFX_PIPE_PRIO_NORMAL; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic unsigned int amdgpu_ctx_prio_sched_to_hw(struct amdgpu_device *adev, 778c2ecf20Sopenharmony_ci enum drm_sched_priority prio, 788c2ecf20Sopenharmony_ci u32 hw_ip) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci unsigned int hw_prio; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci hw_prio = (hw_ip == AMDGPU_HW_IP_COMPUTE) ? 838c2ecf20Sopenharmony_ci amdgpu_ctx_sched_prio_to_compute_prio(prio) : 848c2ecf20Sopenharmony_ci AMDGPU_RING_PRIO_DEFAULT; 858c2ecf20Sopenharmony_ci hw_ip = array_index_nospec(hw_ip, AMDGPU_HW_IP_NUM); 868c2ecf20Sopenharmony_ci if (adev->gpu_sched[hw_ip][hw_prio].num_scheds == 0) 878c2ecf20Sopenharmony_ci hw_prio = AMDGPU_RING_PRIO_DEFAULT; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci return hw_prio; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic int amdgpu_ctx_init_entity(struct amdgpu_ctx *ctx, u32 hw_ip, 938c2ecf20Sopenharmony_ci const u32 ring) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct amdgpu_device *adev = ctx->adev; 968c2ecf20Sopenharmony_ci struct amdgpu_ctx_entity *entity; 978c2ecf20Sopenharmony_ci struct drm_gpu_scheduler **scheds = NULL, *sched = NULL; 988c2ecf20Sopenharmony_ci unsigned num_scheds = 0; 998c2ecf20Sopenharmony_ci unsigned int hw_prio; 1008c2ecf20Sopenharmony_ci enum drm_sched_priority priority; 1018c2ecf20Sopenharmony_ci int r; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci entity = kcalloc(1, offsetof(typeof(*entity), fences[amdgpu_sched_jobs]), 1048c2ecf20Sopenharmony_ci GFP_KERNEL); 1058c2ecf20Sopenharmony_ci if (!entity) 1068c2ecf20Sopenharmony_ci return -ENOMEM; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci entity->sequence = 1; 1098c2ecf20Sopenharmony_ci priority = (ctx->override_priority == DRM_SCHED_PRIORITY_UNSET) ? 1108c2ecf20Sopenharmony_ci ctx->init_priority : ctx->override_priority; 1118c2ecf20Sopenharmony_ci hw_prio = amdgpu_ctx_prio_sched_to_hw(adev, priority, hw_ip); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci hw_ip = array_index_nospec(hw_ip, AMDGPU_HW_IP_NUM); 1148c2ecf20Sopenharmony_ci scheds = adev->gpu_sched[hw_ip][hw_prio].sched; 1158c2ecf20Sopenharmony_ci num_scheds = adev->gpu_sched[hw_ip][hw_prio].num_scheds; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* disable load balance if the hw engine retains context among dependent jobs */ 1188c2ecf20Sopenharmony_ci if (hw_ip == AMDGPU_HW_IP_VCN_ENC || 1198c2ecf20Sopenharmony_ci hw_ip == AMDGPU_HW_IP_VCN_DEC || 1208c2ecf20Sopenharmony_ci hw_ip == AMDGPU_HW_IP_UVD_ENC || 1218c2ecf20Sopenharmony_ci hw_ip == AMDGPU_HW_IP_UVD) { 1228c2ecf20Sopenharmony_ci sched = drm_sched_pick_best(scheds, num_scheds); 1238c2ecf20Sopenharmony_ci scheds = &sched; 1248c2ecf20Sopenharmony_ci num_scheds = 1; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci r = drm_sched_entity_init(&entity->entity, priority, scheds, num_scheds, 1288c2ecf20Sopenharmony_ci &ctx->guilty); 1298c2ecf20Sopenharmony_ci if (r) 1308c2ecf20Sopenharmony_ci goto error_free_entity; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci ctx->entities[hw_ip][ring] = entity; 1338c2ecf20Sopenharmony_ci return 0; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cierror_free_entity: 1368c2ecf20Sopenharmony_ci kfree(entity); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci return r; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int amdgpu_ctx_init(struct amdgpu_device *adev, 1428c2ecf20Sopenharmony_ci enum drm_sched_priority priority, 1438c2ecf20Sopenharmony_ci struct drm_file *filp, 1448c2ecf20Sopenharmony_ci struct amdgpu_ctx *ctx) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci int r; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci r = amdgpu_ctx_priority_permit(filp, priority); 1498c2ecf20Sopenharmony_ci if (r) 1508c2ecf20Sopenharmony_ci return r; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci memset(ctx, 0, sizeof(*ctx)); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci ctx->adev = adev; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci kref_init(&ctx->refcount); 1578c2ecf20Sopenharmony_ci spin_lock_init(&ctx->ring_lock); 1588c2ecf20Sopenharmony_ci mutex_init(&ctx->lock); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci ctx->reset_counter = atomic_read(&adev->gpu_reset_counter); 1618c2ecf20Sopenharmony_ci ctx->reset_counter_query = ctx->reset_counter; 1628c2ecf20Sopenharmony_ci ctx->vram_lost_counter = atomic_read(&adev->vram_lost_counter); 1638c2ecf20Sopenharmony_ci ctx->init_priority = priority; 1648c2ecf20Sopenharmony_ci ctx->override_priority = DRM_SCHED_PRIORITY_UNSET; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci return 0; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic void amdgpu_ctx_fini_entity(struct amdgpu_ctx_entity *entity) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci int i; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (!entity) 1758c2ecf20Sopenharmony_ci return; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci for (i = 0; i < amdgpu_sched_jobs; ++i) 1788c2ecf20Sopenharmony_ci dma_fence_put(entity->fences[i]); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci kfree(entity); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic void amdgpu_ctx_fini(struct kref *ref) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci struct amdgpu_ctx *ctx = container_of(ref, struct amdgpu_ctx, refcount); 1868c2ecf20Sopenharmony_ci struct amdgpu_device *adev = ctx->adev; 1878c2ecf20Sopenharmony_ci unsigned i, j; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (!adev) 1908c2ecf20Sopenharmony_ci return; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) { 1938c2ecf20Sopenharmony_ci for (j = 0; j < AMDGPU_MAX_ENTITY_NUM; ++j) { 1948c2ecf20Sopenharmony_ci amdgpu_ctx_fini_entity(ctx->entities[i][j]); 1958c2ecf20Sopenharmony_ci ctx->entities[i][j] = NULL; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci mutex_destroy(&ctx->lock); 2008c2ecf20Sopenharmony_ci kfree(ctx); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ciint amdgpu_ctx_get_entity(struct amdgpu_ctx *ctx, u32 hw_ip, u32 instance, 2048c2ecf20Sopenharmony_ci u32 ring, struct drm_sched_entity **entity) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci int r; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (hw_ip >= AMDGPU_HW_IP_NUM) { 2098c2ecf20Sopenharmony_ci DRM_ERROR("unknown HW IP type: %d\n", hw_ip); 2108c2ecf20Sopenharmony_ci return -EINVAL; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* Right now all IPs have only one instance - multiple rings. */ 2148c2ecf20Sopenharmony_ci if (instance != 0) { 2158c2ecf20Sopenharmony_ci DRM_DEBUG("invalid ip instance: %d\n", instance); 2168c2ecf20Sopenharmony_ci return -EINVAL; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (ring >= amdgpu_ctx_num_entities[hw_ip]) { 2208c2ecf20Sopenharmony_ci DRM_DEBUG("invalid ring: %d %d\n", hw_ip, ring); 2218c2ecf20Sopenharmony_ci return -EINVAL; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (ctx->entities[hw_ip][ring] == NULL) { 2258c2ecf20Sopenharmony_ci r = amdgpu_ctx_init_entity(ctx, hw_ip, ring); 2268c2ecf20Sopenharmony_ci if (r) 2278c2ecf20Sopenharmony_ci return r; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci *entity = &ctx->entities[hw_ip][ring]->entity; 2318c2ecf20Sopenharmony_ci return 0; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic int amdgpu_ctx_alloc(struct amdgpu_device *adev, 2358c2ecf20Sopenharmony_ci struct amdgpu_fpriv *fpriv, 2368c2ecf20Sopenharmony_ci struct drm_file *filp, 2378c2ecf20Sopenharmony_ci enum drm_sched_priority priority, 2388c2ecf20Sopenharmony_ci uint32_t *id) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr; 2418c2ecf20Sopenharmony_ci struct amdgpu_ctx *ctx; 2428c2ecf20Sopenharmony_ci int r; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); 2458c2ecf20Sopenharmony_ci if (!ctx) 2468c2ecf20Sopenharmony_ci return -ENOMEM; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci mutex_lock(&mgr->lock); 2498c2ecf20Sopenharmony_ci r = idr_alloc(&mgr->ctx_handles, ctx, 1, AMDGPU_VM_MAX_NUM_CTX, GFP_KERNEL); 2508c2ecf20Sopenharmony_ci if (r < 0) { 2518c2ecf20Sopenharmony_ci mutex_unlock(&mgr->lock); 2528c2ecf20Sopenharmony_ci kfree(ctx); 2538c2ecf20Sopenharmony_ci return r; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci *id = (uint32_t)r; 2578c2ecf20Sopenharmony_ci r = amdgpu_ctx_init(adev, priority, filp, ctx); 2588c2ecf20Sopenharmony_ci if (r) { 2598c2ecf20Sopenharmony_ci idr_remove(&mgr->ctx_handles, *id); 2608c2ecf20Sopenharmony_ci *id = 0; 2618c2ecf20Sopenharmony_ci kfree(ctx); 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci mutex_unlock(&mgr->lock); 2648c2ecf20Sopenharmony_ci return r; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic void amdgpu_ctx_do_release(struct kref *ref) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct amdgpu_ctx *ctx; 2708c2ecf20Sopenharmony_ci u32 i, j; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci ctx = container_of(ref, struct amdgpu_ctx, refcount); 2738c2ecf20Sopenharmony_ci for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) { 2748c2ecf20Sopenharmony_ci for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) { 2758c2ecf20Sopenharmony_ci if (!ctx->entities[i][j]) 2768c2ecf20Sopenharmony_ci continue; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci drm_sched_entity_destroy(&ctx->entities[i][j]->entity); 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci amdgpu_ctx_fini(ref); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int amdgpu_ctx_free(struct amdgpu_fpriv *fpriv, uint32_t id) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr; 2888c2ecf20Sopenharmony_ci struct amdgpu_ctx *ctx; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci mutex_lock(&mgr->lock); 2918c2ecf20Sopenharmony_ci ctx = idr_remove(&mgr->ctx_handles, id); 2928c2ecf20Sopenharmony_ci if (ctx) 2938c2ecf20Sopenharmony_ci kref_put(&ctx->refcount, amdgpu_ctx_do_release); 2948c2ecf20Sopenharmony_ci mutex_unlock(&mgr->lock); 2958c2ecf20Sopenharmony_ci return ctx ? 0 : -EINVAL; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic int amdgpu_ctx_query(struct amdgpu_device *adev, 2998c2ecf20Sopenharmony_ci struct amdgpu_fpriv *fpriv, uint32_t id, 3008c2ecf20Sopenharmony_ci union drm_amdgpu_ctx_out *out) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci struct amdgpu_ctx *ctx; 3038c2ecf20Sopenharmony_ci struct amdgpu_ctx_mgr *mgr; 3048c2ecf20Sopenharmony_ci unsigned reset_counter; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (!fpriv) 3078c2ecf20Sopenharmony_ci return -EINVAL; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci mgr = &fpriv->ctx_mgr; 3108c2ecf20Sopenharmony_ci mutex_lock(&mgr->lock); 3118c2ecf20Sopenharmony_ci ctx = idr_find(&mgr->ctx_handles, id); 3128c2ecf20Sopenharmony_ci if (!ctx) { 3138c2ecf20Sopenharmony_ci mutex_unlock(&mgr->lock); 3148c2ecf20Sopenharmony_ci return -EINVAL; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* TODO: these two are always zero */ 3188c2ecf20Sopenharmony_ci out->state.flags = 0x0; 3198c2ecf20Sopenharmony_ci out->state.hangs = 0x0; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* determine if a GPU reset has occured since the last call */ 3228c2ecf20Sopenharmony_ci reset_counter = atomic_read(&adev->gpu_reset_counter); 3238c2ecf20Sopenharmony_ci /* TODO: this should ideally return NO, GUILTY, or INNOCENT. */ 3248c2ecf20Sopenharmony_ci if (ctx->reset_counter_query == reset_counter) 3258c2ecf20Sopenharmony_ci out->state.reset_status = AMDGPU_CTX_NO_RESET; 3268c2ecf20Sopenharmony_ci else 3278c2ecf20Sopenharmony_ci out->state.reset_status = AMDGPU_CTX_UNKNOWN_RESET; 3288c2ecf20Sopenharmony_ci ctx->reset_counter_query = reset_counter; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci mutex_unlock(&mgr->lock); 3318c2ecf20Sopenharmony_ci return 0; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic int amdgpu_ctx_query2(struct amdgpu_device *adev, 3358c2ecf20Sopenharmony_ci struct amdgpu_fpriv *fpriv, uint32_t id, 3368c2ecf20Sopenharmony_ci union drm_amdgpu_ctx_out *out) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct amdgpu_ctx *ctx; 3398c2ecf20Sopenharmony_ci struct amdgpu_ctx_mgr *mgr; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (!fpriv) 3428c2ecf20Sopenharmony_ci return -EINVAL; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci mgr = &fpriv->ctx_mgr; 3458c2ecf20Sopenharmony_ci mutex_lock(&mgr->lock); 3468c2ecf20Sopenharmony_ci ctx = idr_find(&mgr->ctx_handles, id); 3478c2ecf20Sopenharmony_ci if (!ctx) { 3488c2ecf20Sopenharmony_ci mutex_unlock(&mgr->lock); 3498c2ecf20Sopenharmony_ci return -EINVAL; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci out->state.flags = 0x0; 3538c2ecf20Sopenharmony_ci out->state.hangs = 0x0; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (ctx->reset_counter != atomic_read(&adev->gpu_reset_counter)) 3568c2ecf20Sopenharmony_ci out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_RESET; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (ctx->vram_lost_counter != atomic_read(&adev->vram_lost_counter)) 3598c2ecf20Sopenharmony_ci out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_VRAMLOST; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (atomic_read(&ctx->guilty)) 3628c2ecf20Sopenharmony_ci out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_GUILTY; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci mutex_unlock(&mgr->lock); 3658c2ecf20Sopenharmony_ci return 0; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ciint amdgpu_ctx_ioctl(struct drm_device *dev, void *data, 3698c2ecf20Sopenharmony_ci struct drm_file *filp) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci int r; 3728c2ecf20Sopenharmony_ci uint32_t id; 3738c2ecf20Sopenharmony_ci enum drm_sched_priority priority; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci union drm_amdgpu_ctx *args = data; 3768c2ecf20Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 3778c2ecf20Sopenharmony_ci struct amdgpu_fpriv *fpriv = filp->driver_priv; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci id = args->in.ctx_id; 3808c2ecf20Sopenharmony_ci r = amdgpu_to_sched_priority(args->in.priority, &priority); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* For backwards compatibility reasons, we need to accept 3838c2ecf20Sopenharmony_ci * ioctls with garbage in the priority field */ 3848c2ecf20Sopenharmony_ci if (r == -EINVAL) 3858c2ecf20Sopenharmony_ci priority = DRM_SCHED_PRIORITY_NORMAL; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci switch (args->in.op) { 3888c2ecf20Sopenharmony_ci case AMDGPU_CTX_OP_ALLOC_CTX: 3898c2ecf20Sopenharmony_ci r = amdgpu_ctx_alloc(adev, fpriv, filp, priority, &id); 3908c2ecf20Sopenharmony_ci args->out.alloc.ctx_id = id; 3918c2ecf20Sopenharmony_ci break; 3928c2ecf20Sopenharmony_ci case AMDGPU_CTX_OP_FREE_CTX: 3938c2ecf20Sopenharmony_ci r = amdgpu_ctx_free(fpriv, id); 3948c2ecf20Sopenharmony_ci break; 3958c2ecf20Sopenharmony_ci case AMDGPU_CTX_OP_QUERY_STATE: 3968c2ecf20Sopenharmony_ci r = amdgpu_ctx_query(adev, fpriv, id, &args->out); 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci case AMDGPU_CTX_OP_QUERY_STATE2: 3998c2ecf20Sopenharmony_ci r = amdgpu_ctx_query2(adev, fpriv, id, &args->out); 4008c2ecf20Sopenharmony_ci break; 4018c2ecf20Sopenharmony_ci default: 4028c2ecf20Sopenharmony_ci return -EINVAL; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci return r; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistruct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct amdgpu_ctx *ctx; 4118c2ecf20Sopenharmony_ci struct amdgpu_ctx_mgr *mgr; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (!fpriv) 4148c2ecf20Sopenharmony_ci return NULL; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci mgr = &fpriv->ctx_mgr; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci mutex_lock(&mgr->lock); 4198c2ecf20Sopenharmony_ci ctx = idr_find(&mgr->ctx_handles, id); 4208c2ecf20Sopenharmony_ci if (ctx) 4218c2ecf20Sopenharmony_ci kref_get(&ctx->refcount); 4228c2ecf20Sopenharmony_ci mutex_unlock(&mgr->lock); 4238c2ecf20Sopenharmony_ci return ctx; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ciint amdgpu_ctx_put(struct amdgpu_ctx *ctx) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci if (ctx == NULL) 4298c2ecf20Sopenharmony_ci return -EINVAL; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci kref_put(&ctx->refcount, amdgpu_ctx_do_release); 4328c2ecf20Sopenharmony_ci return 0; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_civoid amdgpu_ctx_add_fence(struct amdgpu_ctx *ctx, 4368c2ecf20Sopenharmony_ci struct drm_sched_entity *entity, 4378c2ecf20Sopenharmony_ci struct dma_fence *fence, uint64_t* handle) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct amdgpu_ctx_entity *centity = to_amdgpu_ctx_entity(entity); 4408c2ecf20Sopenharmony_ci uint64_t seq = centity->sequence; 4418c2ecf20Sopenharmony_ci struct dma_fence *other = NULL; 4428c2ecf20Sopenharmony_ci unsigned idx = 0; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci idx = seq & (amdgpu_sched_jobs - 1); 4458c2ecf20Sopenharmony_ci other = centity->fences[idx]; 4468c2ecf20Sopenharmony_ci if (other) 4478c2ecf20Sopenharmony_ci BUG_ON(!dma_fence_is_signaled(other)); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci dma_fence_get(fence); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci spin_lock(&ctx->ring_lock); 4528c2ecf20Sopenharmony_ci centity->fences[idx] = fence; 4538c2ecf20Sopenharmony_ci centity->sequence++; 4548c2ecf20Sopenharmony_ci spin_unlock(&ctx->ring_lock); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci dma_fence_put(other); 4578c2ecf20Sopenharmony_ci if (handle) 4588c2ecf20Sopenharmony_ci *handle = seq; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistruct dma_fence *amdgpu_ctx_get_fence(struct amdgpu_ctx *ctx, 4628c2ecf20Sopenharmony_ci struct drm_sched_entity *entity, 4638c2ecf20Sopenharmony_ci uint64_t seq) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci struct amdgpu_ctx_entity *centity = to_amdgpu_ctx_entity(entity); 4668c2ecf20Sopenharmony_ci struct dma_fence *fence; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci spin_lock(&ctx->ring_lock); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (seq == ~0ull) 4718c2ecf20Sopenharmony_ci seq = centity->sequence - 1; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (seq >= centity->sequence) { 4748c2ecf20Sopenharmony_ci spin_unlock(&ctx->ring_lock); 4758c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (seq + amdgpu_sched_jobs < centity->sequence) { 4808c2ecf20Sopenharmony_ci spin_unlock(&ctx->ring_lock); 4818c2ecf20Sopenharmony_ci return NULL; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci fence = dma_fence_get(centity->fences[seq & (amdgpu_sched_jobs - 1)]); 4858c2ecf20Sopenharmony_ci spin_unlock(&ctx->ring_lock); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci return fence; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic void amdgpu_ctx_set_entity_priority(struct amdgpu_ctx *ctx, 4918c2ecf20Sopenharmony_ci struct amdgpu_ctx_entity *aentity, 4928c2ecf20Sopenharmony_ci int hw_ip, 4938c2ecf20Sopenharmony_ci enum drm_sched_priority priority) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci struct amdgpu_device *adev = ctx->adev; 4968c2ecf20Sopenharmony_ci unsigned int hw_prio; 4978c2ecf20Sopenharmony_ci struct drm_gpu_scheduler **scheds = NULL; 4988c2ecf20Sopenharmony_ci unsigned num_scheds; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci /* set sw priority */ 5018c2ecf20Sopenharmony_ci drm_sched_entity_set_priority(&aentity->entity, priority); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci /* set hw priority */ 5048c2ecf20Sopenharmony_ci if (hw_ip == AMDGPU_HW_IP_COMPUTE) { 5058c2ecf20Sopenharmony_ci hw_prio = amdgpu_ctx_prio_sched_to_hw(adev, priority, 5068c2ecf20Sopenharmony_ci AMDGPU_HW_IP_COMPUTE); 5078c2ecf20Sopenharmony_ci hw_prio = array_index_nospec(hw_prio, AMDGPU_RING_PRIO_MAX); 5088c2ecf20Sopenharmony_ci scheds = adev->gpu_sched[hw_ip][hw_prio].sched; 5098c2ecf20Sopenharmony_ci num_scheds = adev->gpu_sched[hw_ip][hw_prio].num_scheds; 5108c2ecf20Sopenharmony_ci drm_sched_entity_modify_sched(&aentity->entity, scheds, 5118c2ecf20Sopenharmony_ci num_scheds); 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_civoid amdgpu_ctx_priority_override(struct amdgpu_ctx *ctx, 5168c2ecf20Sopenharmony_ci enum drm_sched_priority priority) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci enum drm_sched_priority ctx_prio; 5198c2ecf20Sopenharmony_ci unsigned i, j; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci ctx->override_priority = priority; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci ctx_prio = (ctx->override_priority == DRM_SCHED_PRIORITY_UNSET) ? 5248c2ecf20Sopenharmony_ci ctx->init_priority : ctx->override_priority; 5258c2ecf20Sopenharmony_ci for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) { 5268c2ecf20Sopenharmony_ci for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) { 5278c2ecf20Sopenharmony_ci if (!ctx->entities[i][j]) 5288c2ecf20Sopenharmony_ci continue; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci amdgpu_ctx_set_entity_priority(ctx, ctx->entities[i][j], 5318c2ecf20Sopenharmony_ci i, ctx_prio); 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ciint amdgpu_ctx_wait_prev_fence(struct amdgpu_ctx *ctx, 5378c2ecf20Sopenharmony_ci struct drm_sched_entity *entity) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci struct amdgpu_ctx_entity *centity = to_amdgpu_ctx_entity(entity); 5408c2ecf20Sopenharmony_ci struct dma_fence *other; 5418c2ecf20Sopenharmony_ci unsigned idx; 5428c2ecf20Sopenharmony_ci long r; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci spin_lock(&ctx->ring_lock); 5458c2ecf20Sopenharmony_ci idx = centity->sequence & (amdgpu_sched_jobs - 1); 5468c2ecf20Sopenharmony_ci other = dma_fence_get(centity->fences[idx]); 5478c2ecf20Sopenharmony_ci spin_unlock(&ctx->ring_lock); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (!other) 5508c2ecf20Sopenharmony_ci return 0; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci r = dma_fence_wait(other, true); 5538c2ecf20Sopenharmony_ci if (r < 0 && r != -ERESTARTSYS) 5548c2ecf20Sopenharmony_ci DRM_ERROR("Error (%ld) waiting for fence!\n", r); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci dma_fence_put(other); 5578c2ecf20Sopenharmony_ci return r; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_civoid amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci mutex_init(&mgr->lock); 5638c2ecf20Sopenharmony_ci idr_init(&mgr->ctx_handles); 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cilong amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct amdgpu_ctx *ctx; 5698c2ecf20Sopenharmony_ci struct idr *idp; 5708c2ecf20Sopenharmony_ci uint32_t id, i, j; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci idp = &mgr->ctx_handles; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci mutex_lock(&mgr->lock); 5758c2ecf20Sopenharmony_ci idr_for_each_entry(idp, ctx, id) { 5768c2ecf20Sopenharmony_ci for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) { 5778c2ecf20Sopenharmony_ci for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) { 5788c2ecf20Sopenharmony_ci struct drm_sched_entity *entity; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (!ctx->entities[i][j]) 5818c2ecf20Sopenharmony_ci continue; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci entity = &ctx->entities[i][j]->entity; 5848c2ecf20Sopenharmony_ci timeout = drm_sched_entity_flush(entity, timeout); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci mutex_unlock(&mgr->lock); 5898c2ecf20Sopenharmony_ci return timeout; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_civoid amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci struct amdgpu_ctx *ctx; 5958c2ecf20Sopenharmony_ci struct idr *idp; 5968c2ecf20Sopenharmony_ci uint32_t id, i, j; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci idp = &mgr->ctx_handles; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci idr_for_each_entry(idp, ctx, id) { 6018c2ecf20Sopenharmony_ci if (kref_read(&ctx->refcount) != 1) { 6028c2ecf20Sopenharmony_ci DRM_ERROR("ctx %p is still alive\n", ctx); 6038c2ecf20Sopenharmony_ci continue; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) { 6078c2ecf20Sopenharmony_ci for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) { 6088c2ecf20Sopenharmony_ci struct drm_sched_entity *entity; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci if (!ctx->entities[i][j]) 6118c2ecf20Sopenharmony_ci continue; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci entity = &ctx->entities[i][j]->entity; 6148c2ecf20Sopenharmony_ci drm_sched_entity_fini(entity); 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci} 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_civoid amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci struct amdgpu_ctx *ctx; 6238c2ecf20Sopenharmony_ci struct idr *idp; 6248c2ecf20Sopenharmony_ci uint32_t id; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci amdgpu_ctx_mgr_entity_fini(mgr); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci idp = &mgr->ctx_handles; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci idr_for_each_entry(idp, ctx, id) { 6318c2ecf20Sopenharmony_ci if (kref_put(&ctx->refcount, amdgpu_ctx_fini) != 1) 6328c2ecf20Sopenharmony_ci DRM_ERROR("ctx %p is still alive\n", ctx); 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci idr_destroy(&mgr->ctx_handles); 6368c2ecf20Sopenharmony_ci mutex_destroy(&mgr->lock); 6378c2ecf20Sopenharmony_ci} 638