Path: blob/master/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c
26517 views
/*1* Copyright 2016-2018 Advanced Micro Devices, Inc.2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included in11* all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR17* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19* OTHER DEALINGS IN THE SOFTWARE.20*/2122#include <linux/dma-fence.h>23#include <linux/spinlock.h>24#include <linux/atomic.h>25#include <linux/stacktrace.h>26#include <linux/sched.h>27#include <linux/slab.h>28#include <linux/sched/mm.h>29#include "amdgpu_amdkfd.h"30#include "kfd_svm.h"3132static const struct dma_fence_ops amdkfd_fence_ops;33static atomic_t fence_seq = ATOMIC_INIT(0);3435/* Eviction Fence36* Fence helper functions to deal with KFD memory eviction.37* Big Idea - Since KFD submissions are done by user queues, a BO cannot be38* evicted unless all the user queues for that process are evicted.39*40* All the BOs in a process share an eviction fence. When process X wants41* to map VRAM memory but TTM can't find enough space, TTM will attempt to42* evict BOs from its LRU list. TTM checks if the BO is valuable to evict43* by calling ttm_device_funcs->eviction_valuable().44*45* ttm_device_funcs->eviction_valuable() - will return false if the BO belongs46* to process X. Otherwise, it will return true to indicate BO can be47* evicted by TTM.48*49* If ttm_device_funcs->eviction_valuable returns true, then TTM will continue50* the evcition process for that BO by calling ttm_bo_evict --> amdgpu_bo_move51* --> amdgpu_copy_buffer(). This sets up job in GPU scheduler.52*53* GPU Scheduler (amd_sched_main) - sets up a cb (fence_add_callback) to54* nofity when the BO is free to move. fence_add_callback --> enable_signaling55* --> amdgpu_amdkfd_fence.enable_signaling56*57* amdgpu_amdkfd_fence.enable_signaling - Start a work item that will quiesce58* user queues and signal fence. The work item will also start another delayed59* work item to restore BOs60*/6162struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context,63struct mm_struct *mm,64struct svm_range_bo *svm_bo)65{66struct amdgpu_amdkfd_fence *fence;6768fence = kzalloc(sizeof(*fence), GFP_KERNEL);69if (fence == NULL)70return NULL;7172/* This reference gets released in amdkfd_fence_release */73mmgrab(mm);74fence->mm = mm;75get_task_comm(fence->timeline_name, current);76spin_lock_init(&fence->lock);77fence->svm_bo = svm_bo;78dma_fence_init(&fence->base, &amdkfd_fence_ops, &fence->lock,79context, atomic_inc_return(&fence_seq));8081return fence;82}8384struct amdgpu_amdkfd_fence *to_amdgpu_amdkfd_fence(struct dma_fence *f)85{86struct amdgpu_amdkfd_fence *fence;8788if (!f)89return NULL;9091fence = container_of(f, struct amdgpu_amdkfd_fence, base);92if (f->ops == &amdkfd_fence_ops)93return fence;9495return NULL;96}9798static const char *amdkfd_fence_get_driver_name(struct dma_fence *f)99{100return "amdgpu_amdkfd_fence";101}102103static const char *amdkfd_fence_get_timeline_name(struct dma_fence *f)104{105struct amdgpu_amdkfd_fence *fence = to_amdgpu_amdkfd_fence(f);106107return fence->timeline_name;108}109110/**111* amdkfd_fence_enable_signaling - This gets called when TTM wants to evict112* a KFD BO and schedules a job to move the BO.113* If fence is already signaled return true.114* If fence is not signaled schedule a evict KFD process work item.115*116* @f: dma_fence117*/118static bool amdkfd_fence_enable_signaling(struct dma_fence *f)119{120struct amdgpu_amdkfd_fence *fence = to_amdgpu_amdkfd_fence(f);121122if (!fence)123return false;124125if (dma_fence_is_signaled(f))126return true;127128if (!fence->svm_bo) {129if (!kgd2kfd_schedule_evict_and_restore_process(fence->mm, f))130return true;131} else {132if (!svm_range_schedule_evict_svm_bo(fence))133return true;134}135return false;136}137138/**139* amdkfd_fence_release - callback that fence can be freed140*141* @f: dma_fence142*143* This function is called when the reference count becomes zero.144* Drops the mm_struct reference and RCU schedules freeing up the fence.145*/146static void amdkfd_fence_release(struct dma_fence *f)147{148struct amdgpu_amdkfd_fence *fence = to_amdgpu_amdkfd_fence(f);149150/* Unconditionally signal the fence. The process is getting151* terminated.152*/153if (WARN_ON(!fence))154return; /* Not an amdgpu_amdkfd_fence */155156mmdrop(fence->mm);157kfree_rcu(f, rcu);158}159160/**161* amdkfd_fence_check_mm - Check whether to prevent eviction of @f by @mm162*163* @f: [IN] fence164* @mm: [IN] mm that needs to be verified165*166* Check if @mm is same as that of the fence @f, if same return TRUE else167* return FALSE.168* For svm bo, which support vram overcommitment, always return FALSE.169*/170bool amdkfd_fence_check_mm(struct dma_fence *f, struct mm_struct *mm)171{172struct amdgpu_amdkfd_fence *fence = to_amdgpu_amdkfd_fence(f);173174if (!fence)175return false;176else if (fence->mm == mm && !fence->svm_bo)177return true;178179return false;180}181182static const struct dma_fence_ops amdkfd_fence_ops = {183.get_driver_name = amdkfd_fence_get_driver_name,184.get_timeline_name = amdkfd_fence_get_timeline_name,185.enable_signaling = amdkfd_fence_enable_signaling,186.release = amdkfd_fence_release,187};188189190