diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdkfd/kfd_process.c')
| -rw-r--r-- | drivers/gpu/drm/amd/amdkfd/kfd_process.c | 273 |
1 files changed, 189 insertions, 84 deletions
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index a085faac9fe1..219d08f092db 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -68,7 +68,6 @@ static struct workqueue_struct *kfd_restore_wq; static struct kfd_process *find_process(const struct task_struct *thread, bool ref); static void kfd_process_ref_release(struct kref *ref); -static struct kfd_process *create_process(const struct task_struct *thread); static void evict_process_worker(struct work_struct *work); static void restore_process_worker(struct work_struct *work); @@ -825,6 +824,102 @@ static void kfd_process_device_destroy_ib_mem(struct kfd_process_device *pdd) kfd_process_free_gpuvm(qpd->ib_mem, pdd, &qpd->ib_kaddr); } +int kfd_create_process_sysfs(struct kfd_process *process) +{ + struct kfd_process *primary_process; + int ret; + + if (process->kobj) { + pr_warn("kobject already exists for the kfd_process\n"); + return -EINVAL; + } + + process->kobj = kfd_alloc_struct(process->kobj); + if (!process->kobj) { + pr_warn("Creating procfs kobject failed"); + return -ENOMEM; + } + + if (process->context_id == KFD_CONTEXT_ID_PRIMARY) + ret = kobject_init_and_add(process->kobj, &procfs_type, + procfs.kobj, "%d", + (int)process->lead_thread->pid); + else { + primary_process = kfd_lookup_process_by_mm(process->lead_thread->mm); + if (!primary_process) + return -ESRCH; + + ret = kobject_init_and_add(process->kobj, &procfs_type, + primary_process->kobj, "context_%u", + process->context_id); + kfd_unref_process(primary_process); + } + + if (ret) { + pr_warn("Creating procfs pid directory failed"); + kobject_put(process->kobj); + return ret; + } + + kfd_sysfs_create_file(process->kobj, &process->attr_pasid, + "pasid"); + + process->kobj_queues = kobject_create_and_add("queues", + process->kobj); + if (!process->kobj_queues) + pr_warn("Creating KFD proc/queues folder failed"); + + kfd_procfs_add_sysfs_stats(process); + kfd_procfs_add_sysfs_files(process); + kfd_procfs_add_sysfs_counters(process); + + return 0; +} + +static int kfd_process_alloc_id(struct kfd_process *process) +{ + int ret; + struct kfd_process *primary_process; + + /* already assign 0xFFFF when create */ + if (process->context_id == KFD_CONTEXT_ID_PRIMARY) + return 0; + + primary_process = kfd_lookup_process_by_mm(process->lead_thread->mm); + if (!primary_process) + return -ESRCH; + + /* id range: KFD_CONTEXT_ID_MIN to 0xFFFE */ + ret = ida_alloc_range(&primary_process->id_table, KFD_CONTEXT_ID_MIN, + KFD_CONTEXT_ID_PRIMARY - 1, GFP_KERNEL); + if (ret < 0) + goto out; + + process->context_id = ret; + ret = 0; + +out: + kfd_unref_process(primary_process); + + return ret; +} + +static void kfd_process_free_id(struct kfd_process *process) +{ + struct kfd_process *primary_process; + + if (process->context_id != KFD_CONTEXT_ID_PRIMARY) + return; + + primary_process = kfd_lookup_process_by_mm(process->lead_thread->mm); + if (!primary_process) + return; + + ida_free(&primary_process->id_table, process->context_id); + + kfd_unref_process(primary_process); +} + struct kfd_process *kfd_create_process(struct task_struct *thread) { struct kfd_process *process; @@ -833,12 +928,6 @@ struct kfd_process *kfd_create_process(struct task_struct *thread) if (!(thread->mm && mmget_not_zero(thread->mm))) return ERR_PTR(-EINVAL); - /* Only the pthreads threading model is supported. */ - if (thread->group_leader->mm != thread->mm) { - mmput(thread->mm); - return ERR_PTR(-EINVAL); - } - /* If the process just called exec(3), it is possible that the * cleanup of the kfd_process (following the release of the mm * of the old process image) is still in the cleanup work queue. @@ -854,6 +943,12 @@ struct kfd_process *kfd_create_process(struct task_struct *thread) */ mutex_lock(&kfd_processes_mutex); + if (kfd_gpu_node_num() <= 0) { + pr_warn("no gpu node! Cannot create KFD process"); + process = ERR_PTR(-EINVAL); + goto out; + } + if (kfd_is_locked(NULL)) { pr_debug("KFD is locked! Cannot create process"); process = ERR_PTR(-EINVAL); @@ -867,38 +962,16 @@ struct kfd_process *kfd_create_process(struct task_struct *thread) if (process) { pr_debug("Process already found\n"); } else { - process = create_process(thread); + process = create_process(thread, true); if (IS_ERR(process)) goto out; if (!procfs.kobj) goto out; - process->kobj = kfd_alloc_struct(process->kobj); - if (!process->kobj) { - pr_warn("Creating procfs kobject failed"); - goto out; - } - ret = kobject_init_and_add(process->kobj, &procfs_type, - procfs.kobj, "%d", - (int)process->lead_thread->pid); - if (ret) { - pr_warn("Creating procfs pid directory failed"); - kobject_put(process->kobj); - goto out; - } - - kfd_sysfs_create_file(process->kobj, &process->attr_pasid, - "pasid"); - - process->kobj_queues = kobject_create_and_add("queues", - process->kobj); - if (!process->kobj_queues) - pr_warn("Creating KFD proc/queues folder failed"); - - kfd_procfs_add_sysfs_stats(process); - kfd_procfs_add_sysfs_files(process); - kfd_procfs_add_sysfs_counters(process); + ret = kfd_create_process_sysfs(process); + if (ret) + pr_warn("Failed to create sysfs entry for the kfd_process"); kfd_debugfs_add_process(process); @@ -911,31 +984,13 @@ out: return process; } -struct kfd_process *kfd_get_process(const struct task_struct *thread) -{ - struct kfd_process *process; - - if (!thread->mm) - return ERR_PTR(-EINVAL); - - /* Only the pthreads threading model is supported. */ - if (thread->group_leader->mm != thread->mm) - return ERR_PTR(-EINVAL); - - process = find_process(thread, false); - if (!process) - return ERR_PTR(-EINVAL); - - return process; -} - static struct kfd_process *find_process_by_mm(const struct mm_struct *mm) { struct kfd_process *process; hash_for_each_possible_rcu(kfd_processes_table, process, kfd_processes, (uintptr_t)mm) - if (process->mm == mm) + if (process->mm == mm && process->context_id == KFD_CONTEXT_ID_PRIMARY) return process; return NULL; @@ -1076,7 +1131,7 @@ static void kfd_process_destroy_pdds(struct kfd_process *p) if (pdd->dev->kfd->shared_resources.enable_mes && pdd->proc_ctx_cpu_ptr) - amdgpu_amdkfd_free_gtt_mem(pdd->dev->adev, + amdgpu_amdkfd_free_kernel_mem(pdd->dev->adev, &pdd->proc_ctx_bo); /* * before destroying pdd, make sure to report availability @@ -1175,7 +1230,11 @@ static void kfd_process_wq_release(struct work_struct *work) if (ef) dma_fence_signal(ef); - kfd_process_remove_sysfs(p); + if (p->context_id != KFD_CONTEXT_ID_PRIMARY) + kfd_process_free_id(p); + else + ida_destroy(&p->id_table); + kfd_debugfs_remove_process(p); kfd_process_kunmap_signal_bo(p); @@ -1191,6 +1250,11 @@ static void kfd_process_wq_release(struct work_struct *work) put_task_struct(p->lead_thread); + /* the last step is removing process entries under /sys + * to indicate the process has been terminated. + */ + kfd_process_remove_sysfs(p); + kfree(p); } @@ -1215,10 +1279,30 @@ static void kfd_process_free_notifier(struct mmu_notifier *mn) kfd_unref_process(container_of(mn, struct kfd_process, mmu_notifier)); } -static void kfd_process_notifier_release_internal(struct kfd_process *p) +static void kfd_process_table_remove(struct kfd_process *p) +{ + mutex_lock(&kfd_processes_mutex); + /* + * Do early return if table is empty. + * + * This could potentially happen if this function is called concurrently + * by mmu_notifier and by kfd_cleanup_pocesses. + * + */ + if (hash_empty(kfd_processes_table)) { + mutex_unlock(&kfd_processes_mutex); + return; + } + hash_del_rcu(&p->kfd_processes); + mutex_unlock(&kfd_processes_mutex); + synchronize_srcu(&kfd_processes_srcu); +} + +void kfd_process_notifier_release_internal(struct kfd_process *p) { int i; + kfd_process_table_remove(p); cancel_delayed_work_sync(&p->eviction_work); cancel_delayed_work_sync(&p->restore_work); @@ -1260,7 +1344,8 @@ static void kfd_process_notifier_release_internal(struct kfd_process *p) srcu_read_unlock(&kfd_processes_srcu, idx); } - mmu_notifier_put(&p->mmu_notifier); + if (p->context_id == KFD_CONTEXT_ID_PRIMARY) + mmu_notifier_put(&p->mmu_notifier); } static void kfd_process_notifier_release(struct mmu_notifier *mn, @@ -1276,22 +1361,6 @@ static void kfd_process_notifier_release(struct mmu_notifier *mn, if (WARN_ON(p->mm != mm)) return; - mutex_lock(&kfd_processes_mutex); - /* - * Do early return if table is empty. - * - * This could potentially happen if this function is called concurrently - * by mmu_notifier and by kfd_cleanup_pocesses. - * - */ - if (hash_empty(kfd_processes_table)) { - mutex_unlock(&kfd_processes_mutex); - return; - } - hash_del_rcu(&p->kfd_processes); - mutex_unlock(&kfd_processes_mutex); - synchronize_srcu(&kfd_processes_srcu); - kfd_process_notifier_release_internal(p); } @@ -1492,7 +1561,8 @@ bool kfd_process_xnack_mode(struct kfd_process *p, bool supported) * management and memory-manager-related preemptions or * even deadlocks. */ - if (KFD_GC_VERSION(dev) >= IP_VERSION(10, 1, 1)) + if (KFD_GC_VERSION(dev) >= IP_VERSION(10, 1, 1) && + KFD_GC_VERSION(dev) < IP_VERSION(12, 1, 0)) return false; if (dev->kfd->noretry) @@ -1516,7 +1586,7 @@ void kfd_process_set_trap_debug_flag(struct qcm_process_device *qpd, * On return the kfd_process is fully operational and will be freed when the * mm is released */ -static struct kfd_process *create_process(const struct task_struct *thread) +struct kfd_process *create_process(const struct task_struct *thread, bool primary) { struct kfd_process *process; struct mmu_notifier *mn; @@ -1532,6 +1602,7 @@ static struct kfd_process *create_process(const struct task_struct *thread) process->lead_thread = thread->group_leader; process->n_pdds = 0; process->queues_paused = false; + INIT_DELAYED_WORK(&process->eviction_work, evict_process_worker); INIT_DELAYED_WORK(&process->restore_work, restore_process_worker); process->last_restore_timestamp = get_jiffies_64(); @@ -1575,12 +1646,22 @@ static struct kfd_process *create_process(const struct task_struct *thread) * After this point, mmu_notifier_put will trigger the cleanup by * dropping the last process reference in the free_notifier. */ - mn = mmu_notifier_get(&kfd_process_mmu_notifier_ops, process->mm); - if (IS_ERR(mn)) { - err = PTR_ERR(mn); - goto err_register_notifier; + if (primary) { + process->context_id = KFD_CONTEXT_ID_PRIMARY; + mn = mmu_notifier_get(&kfd_process_mmu_notifier_ops, process->mm); + if (IS_ERR(mn)) { + err = PTR_ERR(mn); + goto err_register_notifier; + } + BUG_ON(mn != &process->mmu_notifier); + ida_init(&process->id_table); + } + + err = kfd_process_alloc_id(process); + if (err) { + pr_err("Creating kfd process: failed to alloc an id\n"); + goto err_alloc_id; } - BUG_ON(mn != &process->mmu_notifier); kfd_unref_process(process); get_task_struct(process->lead_thread); @@ -1589,6 +1670,8 @@ static struct kfd_process *create_process(const struct task_struct *thread) return process; +err_alloc_id: + kfd_process_free_id(process); err_register_notifier: hash_del_rcu(&process->kfd_processes); svm_range_list_fini(process); @@ -1880,6 +1963,27 @@ struct kfd_process *kfd_lookup_process_by_mm(const struct mm_struct *mm) return p; } +/* This increments the process->ref counter. */ +struct kfd_process *kfd_lookup_process_by_id(const struct mm_struct *mm, u16 id) +{ + struct kfd_process *p, *ret_p = NULL; + unsigned int temp; + + int idx = srcu_read_lock(&kfd_processes_srcu); + + hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) { + if (p->mm == mm && p->context_id == id) { + kref_get(&p->ref); + ret_p = p; + break; + } + } + + srcu_read_unlock(&kfd_processes_srcu, idx); + + return ret_p; +} + /* kfd_process_evict_queues - Evict all user queues of a process * * Eviction is reference-counted per process-device. This means multiple @@ -1987,18 +2091,18 @@ kfd_process_gpuid_from_node(struct kfd_process *p, struct kfd_node *node, return -EINVAL; } -static int signal_eviction_fence(struct kfd_process *p) +static bool signal_eviction_fence(struct kfd_process *p) { struct dma_fence *ef; - int ret; + bool ret; rcu_read_lock(); ef = dma_fence_get_rcu_safe(&p->ef); rcu_read_unlock(); if (!ef) - return -EINVAL; + return true; - ret = dma_fence_signal(ef); + ret = dma_fence_check_and_signal(ef); dma_fence_put(ef); return ret; @@ -2179,7 +2283,8 @@ int kfd_process_drain_interrupts(struct kfd_process_device *pdd) */ if (KFD_GC_VERSION(pdd->dev->kfd) == IP_VERSION(9, 4, 3) || KFD_GC_VERSION(pdd->dev->kfd) == IP_VERSION(9, 4, 4) || - KFD_GC_VERSION(pdd->dev->kfd) == IP_VERSION(9, 5, 0)) { + KFD_GC_VERSION(pdd->dev->kfd) == IP_VERSION(9, 5, 0) || + KFD_GC_VERSION(pdd->dev->kfd) == IP_VERSION(12, 1, 0)) { node_id = ffs(pdd->dev->interrupt_bitmap) - 1; irq_drain_fence[3] |= node_id << 16; } |
