summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/amdkfd/kfd_process.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/amdkfd/kfd_process.c')
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process.c273
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;
}