142a66677SAlex Deucher // SPDX-License-Identifier: MIT 242a66677SAlex Deucher /* 342a66677SAlex Deucher * Copyright 2023 Advanced Micro Devices, Inc. 442a66677SAlex Deucher * 542a66677SAlex Deucher * Permission is hereby granted, free of charge, to any person obtaining a 642a66677SAlex Deucher * copy of this software and associated documentation files (the "Software"), 742a66677SAlex Deucher * to deal in the Software without restriction, including without limitation 842a66677SAlex Deucher * the rights to use, copy, modify, merge, publish, distribute, sublicense, 942a66677SAlex Deucher * and/or sell copies of the Software, and to permit persons to whom the 1042a66677SAlex Deucher * Software is furnished to do so, subject to the following conditions: 1142a66677SAlex Deucher * 1242a66677SAlex Deucher * The above copyright notice and this permission notice shall be included in 1342a66677SAlex Deucher * all copies or substantial portions of the Software. 1442a66677SAlex Deucher * 1542a66677SAlex Deucher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1642a66677SAlex Deucher * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1742a66677SAlex Deucher * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1842a66677SAlex Deucher * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1942a66677SAlex Deucher * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2042a66677SAlex Deucher * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2142a66677SAlex Deucher * OTHER DEALINGS IN THE SOFTWARE. 2242a66677SAlex Deucher * 2342a66677SAlex Deucher */ 2442a66677SAlex Deucher 2542a66677SAlex Deucher #include <drm/drm_auth.h> 2642a66677SAlex Deucher #include <drm/drm_exec.h> 2742a66677SAlex Deucher #include <linux/pm_runtime.h> 2842a66677SAlex Deucher 2942a66677SAlex Deucher #include "amdgpu.h" 3042a66677SAlex Deucher #include "amdgpu_vm.h" 3142a66677SAlex Deucher #include "amdgpu_userq.h" 3242a66677SAlex Deucher #include "amdgpu_userq_fence.h" 3342a66677SAlex Deucher 3442a66677SAlex Deucher u32 amdgpu_userq_get_supported_ip_mask(struct amdgpu_device *adev) 3542a66677SAlex Deucher { 3642a66677SAlex Deucher int i; 3742a66677SAlex Deucher u32 userq_ip_mask = 0; 3842a66677SAlex Deucher 3942a66677SAlex Deucher for (i = 0; i < AMDGPU_HW_IP_NUM; i++) { 4042a66677SAlex Deucher if (adev->userq_funcs[i]) 4142a66677SAlex Deucher userq_ip_mask |= (1 << i); 4242a66677SAlex Deucher } 4342a66677SAlex Deucher 4442a66677SAlex Deucher return userq_ip_mask; 4542a66677SAlex Deucher } 4642a66677SAlex Deucher 4742a66677SAlex Deucher static int 4842a66677SAlex Deucher amdgpu_userq_unmap_helper(struct amdgpu_userq_mgr *uq_mgr, 4942a66677SAlex Deucher struct amdgpu_usermode_queue *queue) 5042a66677SAlex Deucher { 5142a66677SAlex Deucher struct amdgpu_device *adev = uq_mgr->adev; 5242a66677SAlex Deucher const struct amdgpu_userq_funcs *userq_funcs = 5342a66677SAlex Deucher adev->userq_funcs[queue->queue_type]; 5442a66677SAlex Deucher int r = 0; 5542a66677SAlex Deucher 5642a66677SAlex Deucher if (queue->state == AMDGPU_USERQ_STATE_MAPPED) { 5742a66677SAlex Deucher r = userq_funcs->unmap(uq_mgr, queue); 5842a66677SAlex Deucher if (r) 5942a66677SAlex Deucher queue->state = AMDGPU_USERQ_STATE_HUNG; 6042a66677SAlex Deucher else 6142a66677SAlex Deucher queue->state = AMDGPU_USERQ_STATE_UNMAPPED; 6242a66677SAlex Deucher } 6342a66677SAlex Deucher return r; 6442a66677SAlex Deucher } 6542a66677SAlex Deucher 6642a66677SAlex Deucher static int 6742a66677SAlex Deucher amdgpu_userq_map_helper(struct amdgpu_userq_mgr *uq_mgr, 6842a66677SAlex Deucher struct amdgpu_usermode_queue *queue) 6942a66677SAlex Deucher { 7042a66677SAlex Deucher struct amdgpu_device *adev = uq_mgr->adev; 7142a66677SAlex Deucher const struct amdgpu_userq_funcs *userq_funcs = 7242a66677SAlex Deucher adev->userq_funcs[queue->queue_type]; 7342a66677SAlex Deucher int r = 0; 7442a66677SAlex Deucher 7542a66677SAlex Deucher if (queue->state == AMDGPU_USERQ_STATE_UNMAPPED) { 7642a66677SAlex Deucher r = userq_funcs->map(uq_mgr, queue); 7742a66677SAlex Deucher if (r) { 7842a66677SAlex Deucher queue->state = AMDGPU_USERQ_STATE_HUNG; 7942a66677SAlex Deucher } else { 8042a66677SAlex Deucher queue->state = AMDGPU_USERQ_STATE_MAPPED; 8142a66677SAlex Deucher } 8242a66677SAlex Deucher } 8342a66677SAlex Deucher return r; 8442a66677SAlex Deucher } 8542a66677SAlex Deucher 8642a66677SAlex Deucher static void 8742a66677SAlex Deucher amdgpu_userq_wait_for_last_fence(struct amdgpu_userq_mgr *uq_mgr, 8842a66677SAlex Deucher struct amdgpu_usermode_queue *queue) 8942a66677SAlex Deucher { 9042a66677SAlex Deucher struct dma_fence *f = queue->last_fence; 9142a66677SAlex Deucher int ret; 9242a66677SAlex Deucher 9342a66677SAlex Deucher if (f && !dma_fence_is_signaled(f)) { 9442a66677SAlex Deucher ret = dma_fence_wait_timeout(f, true, msecs_to_jiffies(100)); 9542a66677SAlex Deucher if (ret <= 0) 968c97cdb1SSunil Khatri drm_file_err(uq_mgr->file, "Timed out waiting for fence=%llu:%llu\n", 97127e612bSSunil Khatri f->context, f->seqno); 9842a66677SAlex Deucher } 9942a66677SAlex Deucher } 10042a66677SAlex Deucher 10142a66677SAlex Deucher static void 10242a66677SAlex Deucher amdgpu_userq_cleanup(struct amdgpu_userq_mgr *uq_mgr, 10342a66677SAlex Deucher struct amdgpu_usermode_queue *queue, 10442a66677SAlex Deucher int queue_id) 10542a66677SAlex Deucher { 10642a66677SAlex Deucher struct amdgpu_device *adev = uq_mgr->adev; 10742a66677SAlex Deucher const struct amdgpu_userq_funcs *uq_funcs = adev->userq_funcs[queue->queue_type]; 10842a66677SAlex Deucher 10942a66677SAlex Deucher uq_funcs->mqd_destroy(uq_mgr, queue); 11042a66677SAlex Deucher amdgpu_userq_fence_driver_free(queue); 11142a66677SAlex Deucher idr_remove(&uq_mgr->userq_idr, queue_id); 11242a66677SAlex Deucher kfree(queue); 11342a66677SAlex Deucher } 11442a66677SAlex Deucher 11542a66677SAlex Deucher int 11642a66677SAlex Deucher amdgpu_userq_active(struct amdgpu_userq_mgr *uq_mgr) 11742a66677SAlex Deucher { 11842a66677SAlex Deucher struct amdgpu_usermode_queue *queue; 11942a66677SAlex Deucher int queue_id; 12042a66677SAlex Deucher int ret = 0; 12142a66677SAlex Deucher 12242a66677SAlex Deucher mutex_lock(&uq_mgr->userq_mutex); 12342a66677SAlex Deucher /* Resume all the queues for this process */ 12442a66677SAlex Deucher idr_for_each_entry(&uq_mgr->userq_idr, queue, queue_id) 12542a66677SAlex Deucher ret += queue->state == AMDGPU_USERQ_STATE_MAPPED; 12642a66677SAlex Deucher 12742a66677SAlex Deucher mutex_unlock(&uq_mgr->userq_mutex); 12842a66677SAlex Deucher return ret; 12942a66677SAlex Deucher } 13042a66677SAlex Deucher 13142a66677SAlex Deucher static struct amdgpu_usermode_queue * 13242a66677SAlex Deucher amdgpu_userq_find(struct amdgpu_userq_mgr *uq_mgr, int qid) 13342a66677SAlex Deucher { 13442a66677SAlex Deucher return idr_find(&uq_mgr->userq_idr, qid); 13542a66677SAlex Deucher } 13642a66677SAlex Deucher 13742a66677SAlex Deucher void 13842a66677SAlex Deucher amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *uq_mgr, 13942a66677SAlex Deucher struct amdgpu_eviction_fence_mgr *evf_mgr) 14042a66677SAlex Deucher { 14142a66677SAlex Deucher struct amdgpu_eviction_fence *ev_fence; 14242a66677SAlex Deucher 14342a66677SAlex Deucher retry: 14442a66677SAlex Deucher /* Flush any pending resume work to create ev_fence */ 14542a66677SAlex Deucher flush_delayed_work(&uq_mgr->resume_work); 14642a66677SAlex Deucher 14742a66677SAlex Deucher mutex_lock(&uq_mgr->userq_mutex); 14842a66677SAlex Deucher spin_lock(&evf_mgr->ev_fence_lock); 14942a66677SAlex Deucher ev_fence = evf_mgr->ev_fence; 15042a66677SAlex Deucher spin_unlock(&evf_mgr->ev_fence_lock); 15142a66677SAlex Deucher if (!ev_fence || dma_fence_is_signaled(&ev_fence->base)) { 15242a66677SAlex Deucher mutex_unlock(&uq_mgr->userq_mutex); 15342a66677SAlex Deucher /* 15442a66677SAlex Deucher * Looks like there was no pending resume work, 15542a66677SAlex Deucher * add one now to create a valid eviction fence 15642a66677SAlex Deucher */ 15742a66677SAlex Deucher schedule_delayed_work(&uq_mgr->resume_work, 0); 15842a66677SAlex Deucher goto retry; 15942a66677SAlex Deucher } 16042a66677SAlex Deucher } 16142a66677SAlex Deucher 16242a66677SAlex Deucher int amdgpu_userq_create_object(struct amdgpu_userq_mgr *uq_mgr, 16342a66677SAlex Deucher struct amdgpu_userq_obj *userq_obj, 16442a66677SAlex Deucher int size) 16542a66677SAlex Deucher { 16642a66677SAlex Deucher struct amdgpu_device *adev = uq_mgr->adev; 16742a66677SAlex Deucher struct amdgpu_bo_param bp; 16842a66677SAlex Deucher int r; 16942a66677SAlex Deucher 17042a66677SAlex Deucher memset(&bp, 0, sizeof(bp)); 17142a66677SAlex Deucher bp.byte_align = PAGE_SIZE; 17242a66677SAlex Deucher bp.domain = AMDGPU_GEM_DOMAIN_GTT; 17342a66677SAlex Deucher bp.flags = AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS | 17442a66677SAlex Deucher AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; 17542a66677SAlex Deucher bp.type = ttm_bo_type_kernel; 17642a66677SAlex Deucher bp.size = size; 17742a66677SAlex Deucher bp.resv = NULL; 17842a66677SAlex Deucher bp.bo_ptr_size = sizeof(struct amdgpu_bo); 17942a66677SAlex Deucher 18042a66677SAlex Deucher r = amdgpu_bo_create(adev, &bp, &userq_obj->obj); 18142a66677SAlex Deucher if (r) { 182c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Failed to allocate BO for userqueue (%d)", r); 18342a66677SAlex Deucher return r; 18442a66677SAlex Deucher } 18542a66677SAlex Deucher 18642a66677SAlex Deucher r = amdgpu_bo_reserve(userq_obj->obj, true); 18742a66677SAlex Deucher if (r) { 188c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Failed to reserve BO to map (%d)", r); 18942a66677SAlex Deucher goto free_obj; 19042a66677SAlex Deucher } 19142a66677SAlex Deucher 19242a66677SAlex Deucher r = amdgpu_ttm_alloc_gart(&(userq_obj->obj)->tbo); 19342a66677SAlex Deucher if (r) { 194c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Failed to alloc GART for userqueue object (%d)", r); 19542a66677SAlex Deucher goto unresv; 19642a66677SAlex Deucher } 19742a66677SAlex Deucher 19842a66677SAlex Deucher r = amdgpu_bo_kmap(userq_obj->obj, &userq_obj->cpu_ptr); 19942a66677SAlex Deucher if (r) { 200c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Failed to map BO for userqueue (%d)", r); 20142a66677SAlex Deucher goto unresv; 20242a66677SAlex Deucher } 20342a66677SAlex Deucher 20442a66677SAlex Deucher userq_obj->gpu_addr = amdgpu_bo_gpu_offset(userq_obj->obj); 20542a66677SAlex Deucher amdgpu_bo_unreserve(userq_obj->obj); 20642a66677SAlex Deucher memset(userq_obj->cpu_ptr, 0, size); 20742a66677SAlex Deucher return 0; 20842a66677SAlex Deucher 20942a66677SAlex Deucher unresv: 21042a66677SAlex Deucher amdgpu_bo_unreserve(userq_obj->obj); 21142a66677SAlex Deucher 21242a66677SAlex Deucher free_obj: 21342a66677SAlex Deucher amdgpu_bo_unref(&userq_obj->obj); 21442a66677SAlex Deucher return r; 21542a66677SAlex Deucher } 21642a66677SAlex Deucher 21742a66677SAlex Deucher void amdgpu_userq_destroy_object(struct amdgpu_userq_mgr *uq_mgr, 21842a66677SAlex Deucher struct amdgpu_userq_obj *userq_obj) 21942a66677SAlex Deucher { 22042a66677SAlex Deucher amdgpu_bo_kunmap(userq_obj->obj); 22142a66677SAlex Deucher amdgpu_bo_unref(&userq_obj->obj); 22242a66677SAlex Deucher } 22342a66677SAlex Deucher 22442a66677SAlex Deucher uint64_t 22542a66677SAlex Deucher amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr, 22642a66677SAlex Deucher struct amdgpu_db_info *db_info, 22742a66677SAlex Deucher struct drm_file *filp) 22842a66677SAlex Deucher { 22942a66677SAlex Deucher uint64_t index; 23042a66677SAlex Deucher struct drm_gem_object *gobj; 23142a66677SAlex Deucher struct amdgpu_userq_obj *db_obj = db_info->db_obj; 23242a66677SAlex Deucher int r, db_size; 23342a66677SAlex Deucher 23442a66677SAlex Deucher gobj = drm_gem_object_lookup(filp, db_info->doorbell_handle); 23542a66677SAlex Deucher if (gobj == NULL) { 236c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Can't find GEM object for doorbell\n"); 23742a66677SAlex Deucher return -EINVAL; 23842a66677SAlex Deucher } 23942a66677SAlex Deucher 24042a66677SAlex Deucher db_obj->obj = amdgpu_bo_ref(gem_to_amdgpu_bo(gobj)); 24142a66677SAlex Deucher drm_gem_object_put(gobj); 24242a66677SAlex Deucher 243bc5bab82SArunpravin Paneer Selvam r = amdgpu_bo_reserve(db_obj->obj, true); 24442a66677SAlex Deucher if (r) { 245c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "[Usermode queues] Failed to pin doorbell object\n"); 24642a66677SAlex Deucher goto unref_bo; 24742a66677SAlex Deucher } 24842a66677SAlex Deucher 249bc5bab82SArunpravin Paneer Selvam /* Pin the BO before generating the index, unpin in queue destroy */ 250bc5bab82SArunpravin Paneer Selvam r = amdgpu_bo_pin(db_obj->obj, AMDGPU_GEM_DOMAIN_DOORBELL); 25142a66677SAlex Deucher if (r) { 252c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "[Usermode queues] Failed to pin doorbell object\n"); 253bc5bab82SArunpravin Paneer Selvam goto unresv_bo; 25442a66677SAlex Deucher } 25542a66677SAlex Deucher 25642a66677SAlex Deucher switch (db_info->queue_type) { 25742a66677SAlex Deucher case AMDGPU_HW_IP_GFX: 25842a66677SAlex Deucher case AMDGPU_HW_IP_COMPUTE: 25942a66677SAlex Deucher case AMDGPU_HW_IP_DMA: 26042a66677SAlex Deucher db_size = sizeof(u64); 26142a66677SAlex Deucher break; 26242a66677SAlex Deucher 26342a66677SAlex Deucher case AMDGPU_HW_IP_VCN_ENC: 26442a66677SAlex Deucher db_size = sizeof(u32); 26542a66677SAlex Deucher db_info->doorbell_offset += AMDGPU_NAVI10_DOORBELL64_VCN0_1 << 1; 26642a66677SAlex Deucher break; 26742a66677SAlex Deucher 26842a66677SAlex Deucher case AMDGPU_HW_IP_VPE: 26942a66677SAlex Deucher db_size = sizeof(u32); 27042a66677SAlex Deucher db_info->doorbell_offset += AMDGPU_NAVI10_DOORBELL64_VPE << 1; 27142a66677SAlex Deucher break; 27242a66677SAlex Deucher 27342a66677SAlex Deucher default: 274c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "[Usermode queues] IP %d not support\n", 275c46a3762SSunil Khatri db_info->queue_type); 27642a66677SAlex Deucher r = -EINVAL; 27742a66677SAlex Deucher goto unpin_bo; 27842a66677SAlex Deucher } 27942a66677SAlex Deucher 28042a66677SAlex Deucher index = amdgpu_doorbell_index_on_bar(uq_mgr->adev, db_obj->obj, 28142a66677SAlex Deucher db_info->doorbell_offset, db_size); 28271353c1aSSunil Khatri drm_dbg_driver(adev_to_drm(uq_mgr->adev), 28371353c1aSSunil Khatri "[Usermode queues] doorbell index=%lld\n", index); 28442a66677SAlex Deucher amdgpu_bo_unreserve(db_obj->obj); 28542a66677SAlex Deucher return index; 28642a66677SAlex Deucher 28742a66677SAlex Deucher unpin_bo: 28842a66677SAlex Deucher amdgpu_bo_unpin(db_obj->obj); 289bc5bab82SArunpravin Paneer Selvam unresv_bo: 290bc5bab82SArunpravin Paneer Selvam amdgpu_bo_unreserve(db_obj->obj); 29142a66677SAlex Deucher unref_bo: 29242a66677SAlex Deucher amdgpu_bo_unref(&db_obj->obj); 29342a66677SAlex Deucher return r; 29442a66677SAlex Deucher } 29542a66677SAlex Deucher 29642a66677SAlex Deucher static int 29742a66677SAlex Deucher amdgpu_userq_destroy(struct drm_file *filp, int queue_id) 29842a66677SAlex Deucher { 29942a66677SAlex Deucher struct amdgpu_fpriv *fpriv = filp->driver_priv; 30042a66677SAlex Deucher struct amdgpu_userq_mgr *uq_mgr = &fpriv->userq_mgr; 30142a66677SAlex Deucher struct amdgpu_device *adev = uq_mgr->adev; 30242a66677SAlex Deucher struct amdgpu_usermode_queue *queue; 30342a66677SAlex Deucher int r = 0; 30442a66677SAlex Deucher 305f10eb185SArvind Yadav cancel_delayed_work_sync(&uq_mgr->resume_work); 30642a66677SAlex Deucher mutex_lock(&uq_mgr->userq_mutex); 30742a66677SAlex Deucher 30842a66677SAlex Deucher queue = amdgpu_userq_find(uq_mgr, queue_id); 30942a66677SAlex Deucher if (!queue) { 31071353c1aSSunil Khatri drm_dbg_driver(adev_to_drm(uq_mgr->adev), "Invalid queue id to destroy\n"); 31142a66677SAlex Deucher mutex_unlock(&uq_mgr->userq_mutex); 31242a66677SAlex Deucher return -EINVAL; 31342a66677SAlex Deucher } 31442a66677SAlex Deucher amdgpu_userq_wait_for_last_fence(uq_mgr, queue); 315bc5bab82SArunpravin Paneer Selvam r = amdgpu_bo_reserve(queue->db_obj.obj, true); 316bc5bab82SArunpravin Paneer Selvam if (!r) { 31742a66677SAlex Deucher amdgpu_bo_unpin(queue->db_obj.obj); 318bc5bab82SArunpravin Paneer Selvam amdgpu_bo_unreserve(queue->db_obj.obj); 319bc5bab82SArunpravin Paneer Selvam } 32042a66677SAlex Deucher amdgpu_bo_unref(&queue->db_obj.obj); 321bc5bab82SArunpravin Paneer Selvam r = amdgpu_userq_unmap_helper(uq_mgr, queue); 32242a66677SAlex Deucher amdgpu_userq_cleanup(uq_mgr, queue, queue_id); 32342a66677SAlex Deucher mutex_unlock(&uq_mgr->userq_mutex); 32442a66677SAlex Deucher 32542a66677SAlex Deucher pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 32642a66677SAlex Deucher pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 32742a66677SAlex Deucher 32842a66677SAlex Deucher return r; 32942a66677SAlex Deucher } 33042a66677SAlex Deucher 33142a66677SAlex Deucher static int amdgpu_userq_priority_permit(struct drm_file *filp, 33242a66677SAlex Deucher int priority) 33342a66677SAlex Deucher { 33442a66677SAlex Deucher if (priority < AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_HIGH) 33542a66677SAlex Deucher return 0; 33642a66677SAlex Deucher 33742a66677SAlex Deucher if (capable(CAP_SYS_NICE)) 33842a66677SAlex Deucher return 0; 33942a66677SAlex Deucher 34042a66677SAlex Deucher if (drm_is_current_master(filp)) 34142a66677SAlex Deucher return 0; 34242a66677SAlex Deucher 34342a66677SAlex Deucher return -EACCES; 34442a66677SAlex Deucher } 34542a66677SAlex Deucher 34642a66677SAlex Deucher static int 34742a66677SAlex Deucher amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) 34842a66677SAlex Deucher { 34942a66677SAlex Deucher struct amdgpu_fpriv *fpriv = filp->driver_priv; 35042a66677SAlex Deucher struct amdgpu_userq_mgr *uq_mgr = &fpriv->userq_mgr; 35142a66677SAlex Deucher struct amdgpu_device *adev = uq_mgr->adev; 35242a66677SAlex Deucher const struct amdgpu_userq_funcs *uq_funcs; 35342a66677SAlex Deucher struct amdgpu_usermode_queue *queue; 35442a66677SAlex Deucher struct amdgpu_db_info db_info; 35542a66677SAlex Deucher bool skip_map_queue; 35642a66677SAlex Deucher uint64_t index; 35742a66677SAlex Deucher int qid, r = 0; 35842a66677SAlex Deucher int priority = 35942a66677SAlex Deucher (args->in.flags & AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_MASK) >> 36042a66677SAlex Deucher AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_SHIFT; 36142a66677SAlex Deucher 36242a66677SAlex Deucher /* Usermode queues are only supported for GFX IP as of now */ 36342a66677SAlex Deucher if (args->in.ip_type != AMDGPU_HW_IP_GFX && 36442a66677SAlex Deucher args->in.ip_type != AMDGPU_HW_IP_DMA && 36542a66677SAlex Deucher args->in.ip_type != AMDGPU_HW_IP_COMPUTE) { 366c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Usermode queue doesn't support IP type %u\n", 367c46a3762SSunil Khatri args->in.ip_type); 36842a66677SAlex Deucher return -EINVAL; 36942a66677SAlex Deucher } 37042a66677SAlex Deucher 37142a66677SAlex Deucher r = amdgpu_userq_priority_permit(filp, priority); 37242a66677SAlex Deucher if (r) 37342a66677SAlex Deucher return r; 37442a66677SAlex Deucher 37542a66677SAlex Deucher if ((args->in.flags & AMDGPU_USERQ_CREATE_FLAGS_QUEUE_SECURE) && 37642a66677SAlex Deucher (args->in.ip_type != AMDGPU_HW_IP_GFX) && 37742a66677SAlex Deucher (args->in.ip_type != AMDGPU_HW_IP_COMPUTE) && 37842a66677SAlex Deucher !amdgpu_is_tmz(adev)) { 379c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Secure only supported on GFX/Compute queues\n"); 38042a66677SAlex Deucher return -EINVAL; 38142a66677SAlex Deucher } 38242a66677SAlex Deucher 38342a66677SAlex Deucher r = pm_runtime_get_sync(adev_to_drm(adev)->dev); 38442a66677SAlex Deucher if (r < 0) { 385c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "pm_runtime_get_sync() failed for userqueue create\n"); 38642a66677SAlex Deucher pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 38742a66677SAlex Deucher return r; 38842a66677SAlex Deucher } 38942a66677SAlex Deucher 39042a66677SAlex Deucher /* 39142a66677SAlex Deucher * There could be a situation that we are creating a new queue while 39242a66677SAlex Deucher * the other queues under this UQ_mgr are suspended. So if there is any 39342a66677SAlex Deucher * resume work pending, wait for it to get done. 39442a66677SAlex Deucher * 39542a66677SAlex Deucher * This will also make sure we have a valid eviction fence ready to be used. 39642a66677SAlex Deucher */ 397*96a86dcbSJesse.Zhang mutex_lock(&adev->userq_mutex); 39842a66677SAlex Deucher amdgpu_userq_ensure_ev_fence(&fpriv->userq_mgr, &fpriv->evf_mgr); 39942a66677SAlex Deucher 40042a66677SAlex Deucher uq_funcs = adev->userq_funcs[args->in.ip_type]; 40142a66677SAlex Deucher if (!uq_funcs) { 402c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Usermode queue is not supported for this IP (%u)\n", 403c46a3762SSunil Khatri args->in.ip_type); 40442a66677SAlex Deucher r = -EINVAL; 40542a66677SAlex Deucher goto unlock; 40642a66677SAlex Deucher } 40742a66677SAlex Deucher 40842a66677SAlex Deucher queue = kzalloc(sizeof(struct amdgpu_usermode_queue), GFP_KERNEL); 40942a66677SAlex Deucher if (!queue) { 410c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Failed to allocate memory for queue\n"); 41142a66677SAlex Deucher r = -ENOMEM; 41242a66677SAlex Deucher goto unlock; 41342a66677SAlex Deucher } 41442a66677SAlex Deucher queue->doorbell_handle = args->in.doorbell_handle; 41542a66677SAlex Deucher queue->queue_type = args->in.ip_type; 41642a66677SAlex Deucher queue->vm = &fpriv->vm; 41742a66677SAlex Deucher queue->priority = priority; 41842a66677SAlex Deucher 41942a66677SAlex Deucher db_info.queue_type = queue->queue_type; 42042a66677SAlex Deucher db_info.doorbell_handle = queue->doorbell_handle; 42142a66677SAlex Deucher db_info.db_obj = &queue->db_obj; 42242a66677SAlex Deucher db_info.doorbell_offset = args->in.doorbell_offset; 42342a66677SAlex Deucher 42442a66677SAlex Deucher /* Convert relative doorbell offset into absolute doorbell index */ 42542a66677SAlex Deucher index = amdgpu_userq_get_doorbell_index(uq_mgr, &db_info, filp); 42642a66677SAlex Deucher if (index == (uint64_t)-EINVAL) { 427c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Failed to get doorbell for queue\n"); 42842a66677SAlex Deucher kfree(queue); 42942a66677SAlex Deucher goto unlock; 43042a66677SAlex Deucher } 43142a66677SAlex Deucher 43242a66677SAlex Deucher queue->doorbell_index = index; 43342a66677SAlex Deucher xa_init_flags(&queue->fence_drv_xa, XA_FLAGS_ALLOC); 43442a66677SAlex Deucher r = amdgpu_userq_fence_driver_alloc(adev, queue); 43542a66677SAlex Deucher if (r) { 436c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Failed to alloc fence driver\n"); 43742a66677SAlex Deucher goto unlock; 43842a66677SAlex Deucher } 43942a66677SAlex Deucher 44042a66677SAlex Deucher r = uq_funcs->mqd_create(uq_mgr, &args->in, queue); 44142a66677SAlex Deucher if (r) { 442c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Failed to create Queue\n"); 44342a66677SAlex Deucher amdgpu_userq_fence_driver_free(queue); 44442a66677SAlex Deucher kfree(queue); 44542a66677SAlex Deucher goto unlock; 44642a66677SAlex Deucher } 44742a66677SAlex Deucher 44842a66677SAlex Deucher 44942a66677SAlex Deucher qid = idr_alloc(&uq_mgr->userq_idr, queue, 1, AMDGPU_MAX_USERQ_COUNT, GFP_KERNEL); 45042a66677SAlex Deucher if (qid < 0) { 451c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Failed to allocate a queue id\n"); 45242a66677SAlex Deucher amdgpu_userq_fence_driver_free(queue); 45342a66677SAlex Deucher uq_funcs->mqd_destroy(uq_mgr, queue); 45442a66677SAlex Deucher kfree(queue); 45542a66677SAlex Deucher r = -ENOMEM; 45642a66677SAlex Deucher goto unlock; 45742a66677SAlex Deucher } 45842a66677SAlex Deucher 45942a66677SAlex Deucher /* don't map the queue if scheduling is halted */ 46042a66677SAlex Deucher if (adev->userq_halt_for_enforce_isolation && 46142a66677SAlex Deucher ((queue->queue_type == AMDGPU_HW_IP_GFX) || 46242a66677SAlex Deucher (queue->queue_type == AMDGPU_HW_IP_COMPUTE))) 46342a66677SAlex Deucher skip_map_queue = true; 46442a66677SAlex Deucher else 46542a66677SAlex Deucher skip_map_queue = false; 46642a66677SAlex Deucher if (!skip_map_queue) { 46742a66677SAlex Deucher r = amdgpu_userq_map_helper(uq_mgr, queue); 46842a66677SAlex Deucher if (r) { 469c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Failed to map Queue\n"); 47042a66677SAlex Deucher idr_remove(&uq_mgr->userq_idr, qid); 47142a66677SAlex Deucher amdgpu_userq_fence_driver_free(queue); 47242a66677SAlex Deucher uq_funcs->mqd_destroy(uq_mgr, queue); 47342a66677SAlex Deucher kfree(queue); 47442a66677SAlex Deucher goto unlock; 47542a66677SAlex Deucher } 47642a66677SAlex Deucher } 47742a66677SAlex Deucher 47842a66677SAlex Deucher 47942a66677SAlex Deucher args->out.queue_id = qid; 48042a66677SAlex Deucher 48142a66677SAlex Deucher unlock: 48242a66677SAlex Deucher mutex_unlock(&uq_mgr->userq_mutex); 483*96a86dcbSJesse.Zhang mutex_unlock(&adev->userq_mutex); 48442a66677SAlex Deucher 48542a66677SAlex Deucher return r; 48642a66677SAlex Deucher } 48742a66677SAlex Deucher 48842a66677SAlex Deucher int amdgpu_userq_ioctl(struct drm_device *dev, void *data, 48942a66677SAlex Deucher struct drm_file *filp) 49042a66677SAlex Deucher { 49142a66677SAlex Deucher union drm_amdgpu_userq *args = data; 49242a66677SAlex Deucher int r; 49342a66677SAlex Deucher 49442a66677SAlex Deucher switch (args->in.op) { 49542a66677SAlex Deucher case AMDGPU_USERQ_OP_CREATE: 49642a66677SAlex Deucher if (args->in.flags & ~(AMDGPU_USERQ_CREATE_FLAGS_QUEUE_PRIORITY_MASK | 49742a66677SAlex Deucher AMDGPU_USERQ_CREATE_FLAGS_QUEUE_SECURE)) 49842a66677SAlex Deucher return -EINVAL; 49942a66677SAlex Deucher r = amdgpu_userq_create(filp, args); 50042a66677SAlex Deucher if (r) 501c46a3762SSunil Khatri drm_file_err(filp, "Failed to create usermode queue\n"); 50242a66677SAlex Deucher break; 50342a66677SAlex Deucher 50442a66677SAlex Deucher case AMDGPU_USERQ_OP_FREE: 50542a66677SAlex Deucher if (args->in.ip_type || 50642a66677SAlex Deucher args->in.doorbell_handle || 50742a66677SAlex Deucher args->in.doorbell_offset || 50842a66677SAlex Deucher args->in.flags || 50942a66677SAlex Deucher args->in.queue_va || 51042a66677SAlex Deucher args->in.queue_size || 51142a66677SAlex Deucher args->in.rptr_va || 51242a66677SAlex Deucher args->in.wptr_va || 51342a66677SAlex Deucher args->in.wptr_va || 51442a66677SAlex Deucher args->in.mqd || 51542a66677SAlex Deucher args->in.mqd_size) 51642a66677SAlex Deucher return -EINVAL; 51742a66677SAlex Deucher r = amdgpu_userq_destroy(filp, args->in.queue_id); 51842a66677SAlex Deucher if (r) 519c46a3762SSunil Khatri drm_file_err(filp, "Failed to destroy usermode queue\n"); 52042a66677SAlex Deucher break; 52142a66677SAlex Deucher 52242a66677SAlex Deucher default: 52371353c1aSSunil Khatri drm_dbg_driver(dev, "Invalid user queue op specified: %d\n", args->in.op); 52442a66677SAlex Deucher return -EINVAL; 52542a66677SAlex Deucher } 52642a66677SAlex Deucher 52742a66677SAlex Deucher return r; 52842a66677SAlex Deucher } 52942a66677SAlex Deucher 53042a66677SAlex Deucher static int 53142a66677SAlex Deucher amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr) 53242a66677SAlex Deucher { 53342a66677SAlex Deucher struct amdgpu_usermode_queue *queue; 53442a66677SAlex Deucher int queue_id; 53542a66677SAlex Deucher int ret = 0, r; 53642a66677SAlex Deucher 53742a66677SAlex Deucher /* Resume all the queues for this process */ 53842a66677SAlex Deucher idr_for_each_entry(&uq_mgr->userq_idr, queue, queue_id) { 53942a66677SAlex Deucher r = amdgpu_userq_map_helper(uq_mgr, queue); 54042a66677SAlex Deucher if (r) 54142a66677SAlex Deucher ret = r; 54242a66677SAlex Deucher } 54342a66677SAlex Deucher 54442a66677SAlex Deucher if (ret) 545c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Failed to map all the queues\n"); 54642a66677SAlex Deucher return ret; 54742a66677SAlex Deucher } 54842a66677SAlex Deucher 54942a66677SAlex Deucher static int 55042a66677SAlex Deucher amdgpu_userq_validate_vm_bo(void *_unused, struct amdgpu_bo *bo) 55142a66677SAlex Deucher { 55242a66677SAlex Deucher struct ttm_operation_ctx ctx = { false, false }; 55342a66677SAlex Deucher int ret; 55442a66677SAlex Deucher 55542a66677SAlex Deucher amdgpu_bo_placement_from_domain(bo, bo->allowed_domains); 55642a66677SAlex Deucher 55742a66677SAlex Deucher ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); 55842a66677SAlex Deucher if (ret) 55942a66677SAlex Deucher DRM_ERROR("Fail to validate\n"); 56042a66677SAlex Deucher 56142a66677SAlex Deucher return ret; 56242a66677SAlex Deucher } 56342a66677SAlex Deucher 56442a66677SAlex Deucher static int 56542a66677SAlex Deucher amdgpu_userq_validate_bos(struct amdgpu_userq_mgr *uq_mgr) 56642a66677SAlex Deucher { 56742a66677SAlex Deucher struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr); 56842a66677SAlex Deucher struct amdgpu_vm *vm = &fpriv->vm; 56942a66677SAlex Deucher struct amdgpu_device *adev = uq_mgr->adev; 57042a66677SAlex Deucher struct amdgpu_bo_va *bo_va; 57142a66677SAlex Deucher struct ww_acquire_ctx *ticket; 57242a66677SAlex Deucher struct drm_exec exec; 57342a66677SAlex Deucher struct amdgpu_bo *bo; 57442a66677SAlex Deucher struct dma_resv *resv; 57542a66677SAlex Deucher bool clear, unlock; 57642a66677SAlex Deucher int ret = 0; 57742a66677SAlex Deucher 57842a66677SAlex Deucher drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 0); 57942a66677SAlex Deucher drm_exec_until_all_locked(&exec) { 58042a66677SAlex Deucher ret = amdgpu_vm_lock_pd(vm, &exec, 2); 58142a66677SAlex Deucher drm_exec_retry_on_contention(&exec); 58242a66677SAlex Deucher if (unlikely(ret)) { 583c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Failed to lock PD\n"); 58442a66677SAlex Deucher goto unlock_all; 58542a66677SAlex Deucher } 58642a66677SAlex Deucher 58742a66677SAlex Deucher /* Lock the done list */ 58842a66677SAlex Deucher list_for_each_entry(bo_va, &vm->done, base.vm_status) { 58942a66677SAlex Deucher bo = bo_va->base.bo; 59042a66677SAlex Deucher if (!bo) 59142a66677SAlex Deucher continue; 59242a66677SAlex Deucher 59342a66677SAlex Deucher ret = drm_exec_lock_obj(&exec, &bo->tbo.base); 59442a66677SAlex Deucher drm_exec_retry_on_contention(&exec); 59542a66677SAlex Deucher if (unlikely(ret)) 59642a66677SAlex Deucher goto unlock_all; 59742a66677SAlex Deucher } 59842a66677SAlex Deucher } 59942a66677SAlex Deucher 60042a66677SAlex Deucher spin_lock(&vm->status_lock); 60142a66677SAlex Deucher while (!list_empty(&vm->moved)) { 60242a66677SAlex Deucher bo_va = list_first_entry(&vm->moved, struct amdgpu_bo_va, 60342a66677SAlex Deucher base.vm_status); 60442a66677SAlex Deucher spin_unlock(&vm->status_lock); 60542a66677SAlex Deucher 60642a66677SAlex Deucher /* Per VM BOs never need to bo cleared in the page tables */ 60742a66677SAlex Deucher ret = amdgpu_vm_bo_update(adev, bo_va, false); 60842a66677SAlex Deucher if (ret) 60942a66677SAlex Deucher goto unlock_all; 61042a66677SAlex Deucher spin_lock(&vm->status_lock); 61142a66677SAlex Deucher } 61242a66677SAlex Deucher 61342a66677SAlex Deucher ticket = &exec.ticket; 61442a66677SAlex Deucher while (!list_empty(&vm->invalidated)) { 61542a66677SAlex Deucher bo_va = list_first_entry(&vm->invalidated, struct amdgpu_bo_va, 61642a66677SAlex Deucher base.vm_status); 61742a66677SAlex Deucher resv = bo_va->base.bo->tbo.base.resv; 61842a66677SAlex Deucher spin_unlock(&vm->status_lock); 61942a66677SAlex Deucher 62042a66677SAlex Deucher bo = bo_va->base.bo; 62142a66677SAlex Deucher ret = amdgpu_userq_validate_vm_bo(NULL, bo); 62242a66677SAlex Deucher if (ret) { 623c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Failed to validate BO\n"); 62442a66677SAlex Deucher goto unlock_all; 62542a66677SAlex Deucher } 62642a66677SAlex Deucher 62742a66677SAlex Deucher /* Try to reserve the BO to avoid clearing its ptes */ 62842a66677SAlex Deucher if (!adev->debug_vm && dma_resv_trylock(resv)) { 62942a66677SAlex Deucher clear = false; 63042a66677SAlex Deucher unlock = true; 63142a66677SAlex Deucher /* The caller is already holding the reservation lock */ 63297c39b4dSDan Carpenter } else if (dma_resv_locking_ctx(resv) == ticket) { 63342a66677SAlex Deucher clear = false; 63442a66677SAlex Deucher unlock = false; 63542a66677SAlex Deucher /* Somebody else is using the BO right now */ 63642a66677SAlex Deucher } else { 63742a66677SAlex Deucher clear = true; 63842a66677SAlex Deucher unlock = false; 63942a66677SAlex Deucher } 64042a66677SAlex Deucher 64142a66677SAlex Deucher ret = amdgpu_vm_bo_update(adev, bo_va, clear); 64242a66677SAlex Deucher 64342a66677SAlex Deucher if (unlock) 64442a66677SAlex Deucher dma_resv_unlock(resv); 64542a66677SAlex Deucher if (ret) 64642a66677SAlex Deucher goto unlock_all; 64742a66677SAlex Deucher 64842a66677SAlex Deucher spin_lock(&vm->status_lock); 64942a66677SAlex Deucher } 65042a66677SAlex Deucher spin_unlock(&vm->status_lock); 65142a66677SAlex Deucher 65242a66677SAlex Deucher ret = amdgpu_eviction_fence_replace_fence(&fpriv->evf_mgr, &exec); 65342a66677SAlex Deucher if (ret) 654c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Failed to replace eviction fence\n"); 65542a66677SAlex Deucher 65642a66677SAlex Deucher unlock_all: 65742a66677SAlex Deucher drm_exec_fini(&exec); 65842a66677SAlex Deucher return ret; 65942a66677SAlex Deucher } 66042a66677SAlex Deucher 66142a66677SAlex Deucher static void amdgpu_userq_restore_worker(struct work_struct *work) 66242a66677SAlex Deucher { 66342a66677SAlex Deucher struct amdgpu_userq_mgr *uq_mgr = work_to_uq_mgr(work, resume_work.work); 66442a66677SAlex Deucher struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr); 66542a66677SAlex Deucher int ret; 66642a66677SAlex Deucher 66742a66677SAlex Deucher flush_work(&fpriv->evf_mgr.suspend_work.work); 66842a66677SAlex Deucher 66942a66677SAlex Deucher mutex_lock(&uq_mgr->userq_mutex); 67042a66677SAlex Deucher 67142a66677SAlex Deucher ret = amdgpu_userq_validate_bos(uq_mgr); 67242a66677SAlex Deucher if (ret) { 673c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Failed to validate BOs to restore\n"); 67442a66677SAlex Deucher goto unlock; 67542a66677SAlex Deucher } 67642a66677SAlex Deucher 67742a66677SAlex Deucher ret = amdgpu_userq_restore_all(uq_mgr); 67842a66677SAlex Deucher if (ret) { 679c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Failed to restore all queues\n"); 68042a66677SAlex Deucher goto unlock; 68142a66677SAlex Deucher } 68242a66677SAlex Deucher 68342a66677SAlex Deucher unlock: 68442a66677SAlex Deucher mutex_unlock(&uq_mgr->userq_mutex); 68542a66677SAlex Deucher } 68642a66677SAlex Deucher 68742a66677SAlex Deucher static int 68842a66677SAlex Deucher amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr) 68942a66677SAlex Deucher { 69042a66677SAlex Deucher struct amdgpu_usermode_queue *queue; 69142a66677SAlex Deucher int queue_id; 69242a66677SAlex Deucher int ret = 0, r; 69342a66677SAlex Deucher 69442a66677SAlex Deucher /* Try to unmap all the queues in this process ctx */ 69542a66677SAlex Deucher idr_for_each_entry(&uq_mgr->userq_idr, queue, queue_id) { 69642a66677SAlex Deucher r = amdgpu_userq_unmap_helper(uq_mgr, queue); 69742a66677SAlex Deucher if (r) 69842a66677SAlex Deucher ret = r; 69942a66677SAlex Deucher } 70042a66677SAlex Deucher 70142a66677SAlex Deucher if (ret) 702c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Couldn't unmap all the queues\n"); 70342a66677SAlex Deucher return ret; 70442a66677SAlex Deucher } 70542a66677SAlex Deucher 70642a66677SAlex Deucher static int 70742a66677SAlex Deucher amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr) 70842a66677SAlex Deucher { 70942a66677SAlex Deucher struct amdgpu_usermode_queue *queue; 71042a66677SAlex Deucher int queue_id, ret; 71142a66677SAlex Deucher 71242a66677SAlex Deucher idr_for_each_entry(&uq_mgr->userq_idr, queue, queue_id) { 71342a66677SAlex Deucher struct dma_fence *f = queue->last_fence; 71442a66677SAlex Deucher 71542a66677SAlex Deucher if (!f || dma_fence_is_signaled(f)) 71642a66677SAlex Deucher continue; 71742a66677SAlex Deucher ret = dma_fence_wait_timeout(f, true, msecs_to_jiffies(100)); 71842a66677SAlex Deucher if (ret <= 0) { 7198c97cdb1SSunil Khatri drm_file_err(uq_mgr->file, "Timed out waiting for fence=%llu:%llu\n", 72042a66677SAlex Deucher f->context, f->seqno); 72142a66677SAlex Deucher return -ETIMEDOUT; 72242a66677SAlex Deucher } 72342a66677SAlex Deucher } 72442a66677SAlex Deucher 72542a66677SAlex Deucher return 0; 72642a66677SAlex Deucher } 72742a66677SAlex Deucher 72842a66677SAlex Deucher void 72942a66677SAlex Deucher amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr, 73042a66677SAlex Deucher struct amdgpu_eviction_fence *ev_fence) 73142a66677SAlex Deucher { 73242a66677SAlex Deucher int ret; 73342a66677SAlex Deucher struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr); 73442a66677SAlex Deucher struct amdgpu_eviction_fence_mgr *evf_mgr = &fpriv->evf_mgr; 73542a66677SAlex Deucher 73642a66677SAlex Deucher /* Wait for any pending userqueue fence work to finish */ 73742a66677SAlex Deucher ret = amdgpu_userq_wait_for_signal(uq_mgr); 73842a66677SAlex Deucher if (ret) { 739c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Not evicting userqueue, timeout waiting for work\n"); 74042a66677SAlex Deucher return; 74142a66677SAlex Deucher } 74242a66677SAlex Deucher 74342a66677SAlex Deucher ret = amdgpu_userq_evict_all(uq_mgr); 74442a66677SAlex Deucher if (ret) { 745c46a3762SSunil Khatri drm_file_err(uq_mgr->file, "Failed to evict userqueue\n"); 74642a66677SAlex Deucher return; 74742a66677SAlex Deucher } 74842a66677SAlex Deucher 74942a66677SAlex Deucher /* Signal current eviction fence */ 75042a66677SAlex Deucher amdgpu_eviction_fence_signal(evf_mgr, ev_fence); 75142a66677SAlex Deucher 75242a66677SAlex Deucher if (evf_mgr->fd_closing) { 753f10eb185SArvind Yadav cancel_delayed_work_sync(&uq_mgr->resume_work); 75442a66677SAlex Deucher return; 75542a66677SAlex Deucher } 75642a66677SAlex Deucher 75742a66677SAlex Deucher /* Schedule a resume work */ 75842a66677SAlex Deucher schedule_delayed_work(&uq_mgr->resume_work, 0); 75942a66677SAlex Deucher } 76042a66677SAlex Deucher 76130ff7580SSunil Khatri int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *file_priv, 76230ff7580SSunil Khatri struct amdgpu_device *adev) 76342a66677SAlex Deucher { 76442a66677SAlex Deucher mutex_init(&userq_mgr->userq_mutex); 76542a66677SAlex Deucher idr_init_base(&userq_mgr->userq_idr, 1); 76642a66677SAlex Deucher userq_mgr->adev = adev; 76730ff7580SSunil Khatri userq_mgr->file = file_priv; 76842a66677SAlex Deucher 76942a66677SAlex Deucher mutex_lock(&adev->userq_mutex); 77042a66677SAlex Deucher list_add(&userq_mgr->list, &adev->userq_mgr_list); 77142a66677SAlex Deucher mutex_unlock(&adev->userq_mutex); 77242a66677SAlex Deucher 77342a66677SAlex Deucher INIT_DELAYED_WORK(&userq_mgr->resume_work, amdgpu_userq_restore_worker); 77442a66677SAlex Deucher return 0; 77542a66677SAlex Deucher } 77642a66677SAlex Deucher 77742a66677SAlex Deucher void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr) 77842a66677SAlex Deucher { 77942a66677SAlex Deucher struct amdgpu_device *adev = userq_mgr->adev; 78042a66677SAlex Deucher struct amdgpu_usermode_queue *queue; 78142a66677SAlex Deucher struct amdgpu_userq_mgr *uqm, *tmp; 78242a66677SAlex Deucher uint32_t queue_id; 78342a66677SAlex Deucher 784f10eb185SArvind Yadav cancel_delayed_work_sync(&userq_mgr->resume_work); 78542a66677SAlex Deucher 786648a0dc0SJesse.Zhang mutex_lock(&adev->userq_mutex); 78742a66677SAlex Deucher mutex_lock(&userq_mgr->userq_mutex); 78842a66677SAlex Deucher idr_for_each_entry(&userq_mgr->userq_idr, queue, queue_id) { 78942a66677SAlex Deucher amdgpu_userq_wait_for_last_fence(userq_mgr, queue); 79042a66677SAlex Deucher amdgpu_userq_unmap_helper(userq_mgr, queue); 79142a66677SAlex Deucher amdgpu_userq_cleanup(userq_mgr, queue, queue_id); 79242a66677SAlex Deucher } 793648a0dc0SJesse.Zhang 79442a66677SAlex Deucher list_for_each_entry_safe(uqm, tmp, &adev->userq_mgr_list, list) { 79542a66677SAlex Deucher if (uqm == userq_mgr) { 79642a66677SAlex Deucher list_del(&uqm->list); 79742a66677SAlex Deucher break; 79842a66677SAlex Deucher } 79942a66677SAlex Deucher } 80042a66677SAlex Deucher idr_destroy(&userq_mgr->userq_idr); 80142a66677SAlex Deucher mutex_unlock(&userq_mgr->userq_mutex); 802648a0dc0SJesse.Zhang mutex_unlock(&adev->userq_mutex); 80342a66677SAlex Deucher mutex_destroy(&userq_mgr->userq_mutex); 80442a66677SAlex Deucher } 80542a66677SAlex Deucher 80642a66677SAlex Deucher int amdgpu_userq_suspend(struct amdgpu_device *adev) 80742a66677SAlex Deucher { 80842a66677SAlex Deucher u32 ip_mask = amdgpu_userq_get_supported_ip_mask(adev); 80942a66677SAlex Deucher struct amdgpu_usermode_queue *queue; 81042a66677SAlex Deucher struct amdgpu_userq_mgr *uqm, *tmp; 81142a66677SAlex Deucher int queue_id; 81242a66677SAlex Deucher int ret = 0, r; 81342a66677SAlex Deucher 81442a66677SAlex Deucher if (!ip_mask) 81542a66677SAlex Deucher return 0; 81642a66677SAlex Deucher 81742a66677SAlex Deucher mutex_lock(&adev->userq_mutex); 81842a66677SAlex Deucher list_for_each_entry_safe(uqm, tmp, &adev->userq_mgr_list, list) { 81942a66677SAlex Deucher cancel_delayed_work_sync(&uqm->resume_work); 820c5e02d65SAlex Deucher mutex_lock(&uqm->userq_mutex); 82142a66677SAlex Deucher idr_for_each_entry(&uqm->userq_idr, queue, queue_id) { 82242a66677SAlex Deucher r = amdgpu_userq_unmap_helper(uqm, queue); 82342a66677SAlex Deucher if (r) 82442a66677SAlex Deucher ret = r; 82542a66677SAlex Deucher } 826c5e02d65SAlex Deucher mutex_unlock(&uqm->userq_mutex); 82742a66677SAlex Deucher } 82842a66677SAlex Deucher mutex_unlock(&adev->userq_mutex); 82942a66677SAlex Deucher return ret; 83042a66677SAlex Deucher } 83142a66677SAlex Deucher 83242a66677SAlex Deucher int amdgpu_userq_resume(struct amdgpu_device *adev) 83342a66677SAlex Deucher { 83442a66677SAlex Deucher u32 ip_mask = amdgpu_userq_get_supported_ip_mask(adev); 83542a66677SAlex Deucher struct amdgpu_usermode_queue *queue; 83642a66677SAlex Deucher struct amdgpu_userq_mgr *uqm, *tmp; 83742a66677SAlex Deucher int queue_id; 83842a66677SAlex Deucher int ret = 0, r; 83942a66677SAlex Deucher 84042a66677SAlex Deucher if (!ip_mask) 84142a66677SAlex Deucher return 0; 84242a66677SAlex Deucher 84342a66677SAlex Deucher mutex_lock(&adev->userq_mutex); 84442a66677SAlex Deucher list_for_each_entry_safe(uqm, tmp, &adev->userq_mgr_list, list) { 845c5e02d65SAlex Deucher mutex_lock(&uqm->userq_mutex); 84642a66677SAlex Deucher idr_for_each_entry(&uqm->userq_idr, queue, queue_id) { 84742a66677SAlex Deucher r = amdgpu_userq_map_helper(uqm, queue); 84842a66677SAlex Deucher if (r) 84942a66677SAlex Deucher ret = r; 85042a66677SAlex Deucher } 851c5e02d65SAlex Deucher mutex_unlock(&uqm->userq_mutex); 85242a66677SAlex Deucher } 85342a66677SAlex Deucher mutex_unlock(&adev->userq_mutex); 85442a66677SAlex Deucher return ret; 85542a66677SAlex Deucher } 85642a66677SAlex Deucher 85742a66677SAlex Deucher int amdgpu_userq_stop_sched_for_enforce_isolation(struct amdgpu_device *adev, 85842a66677SAlex Deucher u32 idx) 85942a66677SAlex Deucher { 86042a66677SAlex Deucher u32 ip_mask = amdgpu_userq_get_supported_ip_mask(adev); 86142a66677SAlex Deucher struct amdgpu_usermode_queue *queue; 86242a66677SAlex Deucher struct amdgpu_userq_mgr *uqm, *tmp; 86342a66677SAlex Deucher int queue_id; 86442a66677SAlex Deucher int ret = 0, r; 86542a66677SAlex Deucher 86642a66677SAlex Deucher /* only need to stop gfx/compute */ 86742a66677SAlex Deucher if (!(ip_mask & ((1 << AMDGPU_HW_IP_GFX) | (1 << AMDGPU_HW_IP_COMPUTE)))) 86842a66677SAlex Deucher return 0; 86942a66677SAlex Deucher 87042a66677SAlex Deucher mutex_lock(&adev->userq_mutex); 87142a66677SAlex Deucher if (adev->userq_halt_for_enforce_isolation) 87242a66677SAlex Deucher dev_warn(adev->dev, "userq scheduling already stopped!\n"); 87342a66677SAlex Deucher adev->userq_halt_for_enforce_isolation = true; 87442a66677SAlex Deucher list_for_each_entry_safe(uqm, tmp, &adev->userq_mgr_list, list) { 87542a66677SAlex Deucher cancel_delayed_work_sync(&uqm->resume_work); 876482d4853SAlex Deucher mutex_lock(&uqm->userq_mutex); 87742a66677SAlex Deucher idr_for_each_entry(&uqm->userq_idr, queue, queue_id) { 87842a66677SAlex Deucher if (((queue->queue_type == AMDGPU_HW_IP_GFX) || 87942a66677SAlex Deucher (queue->queue_type == AMDGPU_HW_IP_COMPUTE)) && 88042a66677SAlex Deucher (queue->xcp_id == idx)) { 88142a66677SAlex Deucher r = amdgpu_userq_unmap_helper(uqm, queue); 88242a66677SAlex Deucher if (r) 88342a66677SAlex Deucher ret = r; 88442a66677SAlex Deucher } 88542a66677SAlex Deucher } 886482d4853SAlex Deucher mutex_unlock(&uqm->userq_mutex); 88742a66677SAlex Deucher } 88842a66677SAlex Deucher mutex_unlock(&adev->userq_mutex); 88942a66677SAlex Deucher return ret; 89042a66677SAlex Deucher } 89142a66677SAlex Deucher 89242a66677SAlex Deucher int amdgpu_userq_start_sched_for_enforce_isolation(struct amdgpu_device *adev, 89342a66677SAlex Deucher u32 idx) 89442a66677SAlex Deucher { 89542a66677SAlex Deucher u32 ip_mask = amdgpu_userq_get_supported_ip_mask(adev); 89642a66677SAlex Deucher struct amdgpu_usermode_queue *queue; 89742a66677SAlex Deucher struct amdgpu_userq_mgr *uqm, *tmp; 89842a66677SAlex Deucher int queue_id; 89942a66677SAlex Deucher int ret = 0, r; 90042a66677SAlex Deucher 90142a66677SAlex Deucher /* only need to stop gfx/compute */ 90242a66677SAlex Deucher if (!(ip_mask & ((1 << AMDGPU_HW_IP_GFX) | (1 << AMDGPU_HW_IP_COMPUTE)))) 90342a66677SAlex Deucher return 0; 90442a66677SAlex Deucher 90542a66677SAlex Deucher mutex_lock(&adev->userq_mutex); 90642a66677SAlex Deucher if (!adev->userq_halt_for_enforce_isolation) 90742a66677SAlex Deucher dev_warn(adev->dev, "userq scheduling already started!\n"); 90842a66677SAlex Deucher adev->userq_halt_for_enforce_isolation = false; 90942a66677SAlex Deucher list_for_each_entry_safe(uqm, tmp, &adev->userq_mgr_list, list) { 910482d4853SAlex Deucher mutex_lock(&uqm->userq_mutex); 91142a66677SAlex Deucher idr_for_each_entry(&uqm->userq_idr, queue, queue_id) { 91242a66677SAlex Deucher if (((queue->queue_type == AMDGPU_HW_IP_GFX) || 91342a66677SAlex Deucher (queue->queue_type == AMDGPU_HW_IP_COMPUTE)) && 91442a66677SAlex Deucher (queue->xcp_id == idx)) { 91542a66677SAlex Deucher r = amdgpu_userq_map_helper(uqm, queue); 91642a66677SAlex Deucher if (r) 91742a66677SAlex Deucher ret = r; 91842a66677SAlex Deucher } 91942a66677SAlex Deucher } 920482d4853SAlex Deucher mutex_unlock(&uqm->userq_mutex); 92142a66677SAlex Deucher } 92242a66677SAlex Deucher mutex_unlock(&adev->userq_mutex); 92342a66677SAlex Deucher return ret; 92442a66677SAlex Deucher } 925