Merge tag 'for-linus-hmm' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma
[sfrench/cifs-2.6.git] / drivers / gpu / drm / amd / amdkfd / kfd_process.c
index 0c6ac043ae3cc54cad8284e3eda06eb027361d22..40e3fc0c6942120b83e724038a537ed11f756e9f 100644 (file)
@@ -62,8 +62,8 @@ static struct workqueue_struct *kfd_restore_wq;
 
 static struct kfd_process *find_process(const struct task_struct *thread);
 static void kfd_process_ref_release(struct kref *ref);
-static struct kfd_process *create_process(const struct task_struct *thread,
-                                       struct file *filep);
+static struct kfd_process *create_process(const struct task_struct *thread);
+static int kfd_process_init_cwsr_apu(struct kfd_process *p, struct file *filep);
 
 static void evict_process_worker(struct work_struct *work);
 static void restore_process_worker(struct work_struct *work);
@@ -289,7 +289,15 @@ struct kfd_process *kfd_create_process(struct file *filep)
        if (process) {
                pr_debug("Process already found\n");
        } else {
-               process = create_process(thread, filep);
+               process = create_process(thread);
+               if (IS_ERR(process))
+                       goto out;
+
+               ret = kfd_process_init_cwsr_apu(process, filep);
+               if (ret) {
+                       process = ERR_PTR(ret);
+                       goto out;
+               }
 
                if (!procfs.kobj)
                        goto out;
@@ -478,11 +486,9 @@ static void kfd_process_ref_release(struct kref *ref)
        queue_work(kfd_process_wq, &p->release_work);
 }
 
-static void kfd_process_destroy_delayed(struct rcu_head *rcu)
+static void kfd_process_free_notifier(struct mmu_notifier *mn)
 {
-       struct kfd_process *p = container_of(rcu, struct kfd_process, rcu);
-
-       kfd_unref_process(p);
+       kfd_unref_process(container_of(mn, struct kfd_process, mmu_notifier));
 }
 
 static void kfd_process_notifier_release(struct mmu_notifier *mn,
@@ -534,12 +540,12 @@ static void kfd_process_notifier_release(struct mmu_notifier *mn,
 
        mutex_unlock(&p->mutex);
 
-       mmu_notifier_unregister_no_release(&p->mmu_notifier, mm);
-       mmu_notifier_call_srcu(&p->rcu, &kfd_process_destroy_delayed);
+       mmu_notifier_put(&p->mmu_notifier);
 }
 
 static const struct mmu_notifier_ops kfd_process_mmu_notifier_ops = {
        .release = kfd_process_notifier_release,
+       .free_notifier = kfd_process_free_notifier,
 };
 
 static int kfd_process_init_cwsr_apu(struct kfd_process *p, struct file *filep)
@@ -609,81 +615,69 @@ static int kfd_process_device_init_cwsr_dgpu(struct kfd_process_device *pdd)
        return 0;
 }
 
-static struct kfd_process *create_process(const struct task_struct *thread,
-                                       struct file *filep)
+/*
+ * 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 *process;
        int err = -ENOMEM;
 
        process = kzalloc(sizeof(*process), GFP_KERNEL);
-
        if (!process)
                goto err_alloc_process;
 
-       process->pasid = kfd_pasid_alloc();
-       if (process->pasid == 0)
-               goto err_alloc_pasid;
-
-       if (kfd_alloc_process_doorbells(process) < 0)
-               goto err_alloc_doorbells;
-
        kref_init(&process->ref);
-
        mutex_init(&process->mutex);
-
        process->mm = thread->mm;
-
-       /* register notifier */
-       process->mmu_notifier.ops = &kfd_process_mmu_notifier_ops;
-       err = mmu_notifier_register(&process->mmu_notifier, process->mm);
-       if (err)
-               goto err_mmu_notifier;
-
-       hash_add_rcu(kfd_processes_table, &process->kfd_processes,
-                       (uintptr_t)process->mm);
-
        process->lead_thread = thread->group_leader;
-       get_task_struct(process->lead_thread);
-
        INIT_LIST_HEAD(&process->per_device_data);
-
+       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();
        kfd_event_init_process(process);
+       process->is_32bit_user_mode = in_compat_syscall();
+
+       process->pasid = kfd_pasid_alloc();
+       if (process->pasid == 0)
+               goto err_alloc_pasid;
+
+       if (kfd_alloc_process_doorbells(process) < 0)
+               goto err_alloc_doorbells;
 
        err = pqm_init(&process->pqm, process);
        if (err != 0)
                goto err_process_pqm_init;
 
        /* init process apertures*/
-       process->is_32bit_user_mode = in_compat_syscall();
        err = kfd_init_apertures(process);
        if (err != 0)
                goto err_init_apertures;
 
-       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();
-
-       err = kfd_process_init_cwsr_apu(process, filep);
+       /* Must be last, have to use release destruction after this */
+       process->mmu_notifier.ops = &kfd_process_mmu_notifier_ops;
+       err = mmu_notifier_register(&process->mmu_notifier, process->mm);
        if (err)
-               goto err_init_cwsr;
+               goto err_register_notifier;
+
+       get_task_struct(process->lead_thread);
+       hash_add_rcu(kfd_processes_table, &process->kfd_processes,
+                       (uintptr_t)process->mm);
 
        return process;
 
-err_init_cwsr:
+err_register_notifier:
        kfd_process_free_outstanding_kfd_bos(process);
        kfd_process_destroy_pdds(process);
 err_init_apertures:
        pqm_uninit(&process->pqm);
 err_process_pqm_init:
-       hash_del_rcu(&process->kfd_processes);
-       synchronize_rcu();
-       mmu_notifier_unregister_no_release(&process->mmu_notifier, process->mm);
-err_mmu_notifier:
-       mutex_destroy(&process->mutex);
        kfd_free_process_doorbells(process);
 err_alloc_doorbells:
        kfd_pasid_free(process->pasid);
 err_alloc_pasid:
+       mutex_destroy(&process->mutex);
        kfree(process);
 err_alloc_process:
        return ERR_PTR(err);