| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright 2014 Advanced Micro Devices, Inc. | 
|  | 3 | * | 
|  | 4 | * Permission is hereby granted, free of charge, to any person obtaining a | 
|  | 5 | * copy of this software and associated documentation files (the "Software"), | 
|  | 6 | * to deal in the Software without restriction, including without limitation | 
|  | 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | 
|  | 8 | * and/or sell copies of the Software, and to permit persons to whom the | 
|  | 9 | * Software is furnished to do so, subject to the following conditions: | 
|  | 10 | * | 
|  | 11 | * The above copyright notice and this permission notice shall be included in | 
|  | 12 | * all copies or substantial portions of the Software. | 
|  | 13 | * | 
|  | 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
|  | 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
|  | 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | 
|  | 17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | 
|  | 18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | 
|  | 19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | 
|  | 20 | * OTHER DEALINGS IN THE SOFTWARE. | 
|  | 21 | */ | 
|  | 22 |  | 
|  | 23 | #include <linux/mutex.h> | 
|  | 24 | #include <linux/log2.h> | 
|  | 25 | #include <linux/sched.h> | 
| Ingo Molnar | 6e84f31 | 2017-02-08 18:51:29 +0100 | [diff] [blame] | 26 | #include <linux/sched/mm.h> | 
| Felix Kuehling | c7b1243 | 2017-11-27 18:29:50 -0500 | [diff] [blame] | 27 | #include <linux/sched/task.h> | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 28 | #include <linux/slab.h> | 
| Oded Gabbay | b17f068 | 2014-07-17 00:06:27 +0300 | [diff] [blame] | 29 | #include <linux/amd-iommu.h> | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 30 | #include <linux/notifier.h> | 
| Alexey Skidanov | dd59239 | 2014-11-18 13:56:23 +0200 | [diff] [blame] | 31 | #include <linux/compat.h> | 
| Felix Kuehling | 373d708 | 2017-11-14 16:41:19 -0500 | [diff] [blame] | 32 | #include <linux/mman.h> | 
| Alexey Skidanov | dd59239 | 2014-11-18 13:56:23 +0200 | [diff] [blame] | 33 |  | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 34 | struct mm_struct; | 
|  | 35 |  | 
|  | 36 | #include "kfd_priv.h" | 
| Felix Kuehling | 403575c | 2018-02-06 20:32:44 -0500 | [diff] [blame^] | 37 | #include "kfd_device_queue_manager.h" | 
| Ben Goz | c3447e8 | 2015-05-20 18:05:44 +0300 | [diff] [blame] | 38 | #include "kfd_dbgmgr.h" | 
| Felix Kuehling | 64d1c3a | 2017-12-08 19:22:12 -0500 | [diff] [blame] | 39 | #include "kfd_iommu.h" | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 40 |  | 
|  | 41 | /* | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 42 | * List of struct kfd_process (field kfd_process). | 
|  | 43 | * Unique/indexed by mm_struct* | 
|  | 44 | */ | 
| Felix Kuehling | 64d1c3a | 2017-12-08 19:22:12 -0500 | [diff] [blame] | 45 | DEFINE_HASHTABLE(kfd_processes_table, KFD_PROCESS_TABLE_SIZE); | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 46 | static DEFINE_MUTEX(kfd_processes_mutex); | 
|  | 47 |  | 
| Felix Kuehling | 64d1c3a | 2017-12-08 19:22:12 -0500 | [diff] [blame] | 48 | DEFINE_SRCU(kfd_processes_srcu); | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 49 |  | 
|  | 50 | static struct workqueue_struct *kfd_process_wq; | 
|  | 51 |  | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 52 | static struct kfd_process *find_process(const struct task_struct *thread); | 
| Felix Kuehling | abb208a | 2017-11-27 18:29:52 -0500 | [diff] [blame] | 53 | static void kfd_process_ref_release(struct kref *ref); | 
| Yong Zhao | c0ede1f | 2017-11-27 18:29:56 -0500 | [diff] [blame] | 54 | static struct kfd_process *create_process(const struct task_struct *thread, | 
|  | 55 | struct file *filep); | 
| Felix Kuehling | 373d708 | 2017-11-14 16:41:19 -0500 | [diff] [blame] | 56 | static int kfd_process_init_cwsr(struct kfd_process *p, struct file *filep); | 
|  | 57 |  | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 58 |  | 
|  | 59 | void kfd_process_create_wq(void) | 
|  | 60 | { | 
|  | 61 | if (!kfd_process_wq) | 
| Bhaktipriya Shridhar | fd320bf | 2016-05-29 21:14:11 +0530 | [diff] [blame] | 62 | kfd_process_wq = alloc_workqueue("kfd_process_wq", 0, 0); | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 63 | } | 
|  | 64 |  | 
|  | 65 | void kfd_process_destroy_wq(void) | 
|  | 66 | { | 
|  | 67 | if (kfd_process_wq) { | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 68 | destroy_workqueue(kfd_process_wq); | 
|  | 69 | kfd_process_wq = NULL; | 
|  | 70 | } | 
|  | 71 | } | 
|  | 72 |  | 
| Felix Kuehling | 373d708 | 2017-11-14 16:41:19 -0500 | [diff] [blame] | 73 | struct kfd_process *kfd_create_process(struct file *filep) | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 74 | { | 
|  | 75 | struct kfd_process *process; | 
| Felix Kuehling | 373d708 | 2017-11-14 16:41:19 -0500 | [diff] [blame] | 76 | struct task_struct *thread = current; | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 77 |  | 
| Kent Russell | 4eacc26b | 2017-08-15 23:00:06 -0400 | [diff] [blame] | 78 | if (!thread->mm) | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 79 | return ERR_PTR(-EINVAL); | 
|  | 80 |  | 
|  | 81 | /* Only the pthreads threading model is supported. */ | 
|  | 82 | if (thread->group_leader->mm != thread->mm) | 
|  | 83 | return ERR_PTR(-EINVAL); | 
|  | 84 |  | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 85 | /* | 
|  | 86 | * take kfd processes mutex before starting of process creation | 
|  | 87 | * so there won't be a case where two threads of the same process | 
|  | 88 | * create two kfd_process structures | 
|  | 89 | */ | 
|  | 90 | mutex_lock(&kfd_processes_mutex); | 
|  | 91 |  | 
|  | 92 | /* A prior open of /dev/kfd could have already created the process. */ | 
|  | 93 | process = find_process(thread); | 
|  | 94 | if (process) | 
| Kent Russell | 79775b6 | 2017-08-15 23:00:05 -0400 | [diff] [blame] | 95 | pr_debug("Process already found\n"); | 
| Yong Zhao | c0ede1f | 2017-11-27 18:29:56 -0500 | [diff] [blame] | 96 | else | 
|  | 97 | process = create_process(thread, filep); | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 98 |  | 
|  | 99 | mutex_unlock(&kfd_processes_mutex); | 
|  | 100 |  | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 101 | return process; | 
|  | 102 | } | 
|  | 103 |  | 
|  | 104 | struct kfd_process *kfd_get_process(const struct task_struct *thread) | 
|  | 105 | { | 
|  | 106 | struct kfd_process *process; | 
|  | 107 |  | 
| Kent Russell | 4eacc26b | 2017-08-15 23:00:06 -0400 | [diff] [blame] | 108 | if (!thread->mm) | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 109 | return ERR_PTR(-EINVAL); | 
|  | 110 |  | 
|  | 111 | /* Only the pthreads threading model is supported. */ | 
|  | 112 | if (thread->group_leader->mm != thread->mm) | 
|  | 113 | return ERR_PTR(-EINVAL); | 
|  | 114 |  | 
|  | 115 | process = find_process(thread); | 
|  | 116 |  | 
|  | 117 | return process; | 
|  | 118 | } | 
|  | 119 |  | 
|  | 120 | static struct kfd_process *find_process_by_mm(const struct mm_struct *mm) | 
|  | 121 | { | 
|  | 122 | struct kfd_process *process; | 
|  | 123 |  | 
|  | 124 | hash_for_each_possible_rcu(kfd_processes_table, process, | 
|  | 125 | kfd_processes, (uintptr_t)mm) | 
|  | 126 | if (process->mm == mm) | 
|  | 127 | return process; | 
|  | 128 |  | 
|  | 129 | return NULL; | 
|  | 130 | } | 
|  | 131 |  | 
|  | 132 | static struct kfd_process *find_process(const struct task_struct *thread) | 
|  | 133 | { | 
|  | 134 | struct kfd_process *p; | 
|  | 135 | int idx; | 
|  | 136 |  | 
|  | 137 | idx = srcu_read_lock(&kfd_processes_srcu); | 
|  | 138 | p = find_process_by_mm(thread->mm); | 
|  | 139 | srcu_read_unlock(&kfd_processes_srcu, idx); | 
|  | 140 |  | 
|  | 141 | return p; | 
|  | 142 | } | 
|  | 143 |  | 
| Felix Kuehling | abb208a | 2017-11-27 18:29:52 -0500 | [diff] [blame] | 144 | void kfd_unref_process(struct kfd_process *p) | 
|  | 145 | { | 
|  | 146 | kref_put(&p->ref, kfd_process_ref_release); | 
|  | 147 | } | 
|  | 148 |  | 
| Felix Kuehling | de1450a | 2017-11-27 18:29:55 -0500 | [diff] [blame] | 149 | static void kfd_process_destroy_pdds(struct kfd_process *p) | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 150 | { | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 151 | struct kfd_process_device *pdd, *temp; | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 152 |  | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 153 | list_for_each_entry_safe(pdd, temp, &p->per_device_data, | 
| Felix Kuehling | de1450a | 2017-11-27 18:29:55 -0500 | [diff] [blame] | 154 | per_device_list) { | 
|  | 155 | pr_debug("Releasing pdd (topology id %d) for process (pasid %d)\n", | 
| Oded Gabbay | 94a1ee0 | 2015-02-24 10:51:59 +0200 | [diff] [blame] | 156 | pdd->dev->id, p->pasid); | 
|  | 157 |  | 
| Felix Kuehling | 403575c | 2018-02-06 20:32:44 -0500 | [diff] [blame^] | 158 | if (pdd->vm) | 
|  | 159 | pdd->dev->kfd2kgd->destroy_process_vm( | 
|  | 160 | pdd->dev->kgd, pdd->vm); | 
|  | 161 |  | 
| Yong Zhao | 733fa1f | 2017-09-20 18:10:14 -0400 | [diff] [blame] | 162 | list_del(&pdd->per_device_list); | 
| Felix Kuehling | 373d708 | 2017-11-14 16:41:19 -0500 | [diff] [blame] | 163 |  | 
|  | 164 | if (pdd->qpd.cwsr_kaddr) | 
|  | 165 | free_pages((unsigned long)pdd->qpd.cwsr_kaddr, | 
|  | 166 | get_order(KFD_CWSR_TBA_TMA_SIZE)); | 
|  | 167 |  | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 168 | kfree(pdd); | 
|  | 169 | } | 
| Felix Kuehling | de1450a | 2017-11-27 18:29:55 -0500 | [diff] [blame] | 170 | } | 
|  | 171 |  | 
|  | 172 | /* No process locking is needed in this function, because the process | 
|  | 173 | * is not findable any more. We must assume that no other thread is | 
|  | 174 | * using it any more, otherwise we couldn't safely free the process | 
|  | 175 | * structure in the end. | 
|  | 176 | */ | 
|  | 177 | static void kfd_process_wq_release(struct work_struct *work) | 
|  | 178 | { | 
|  | 179 | struct kfd_process *p = container_of(work, struct kfd_process, | 
|  | 180 | release_work); | 
| Felix Kuehling | de1450a | 2017-11-27 18:29:55 -0500 | [diff] [blame] | 181 |  | 
| Felix Kuehling | 64d1c3a | 2017-12-08 19:22:12 -0500 | [diff] [blame] | 182 | kfd_iommu_unbind_process(p); | 
| Felix Kuehling | de1450a | 2017-11-27 18:29:55 -0500 | [diff] [blame] | 183 |  | 
|  | 184 | kfd_process_destroy_pdds(p); | 
| Felix Kuehling | 403575c | 2018-02-06 20:32:44 -0500 | [diff] [blame^] | 185 | dma_fence_put(p->ef); | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 186 |  | 
| Andrew Lewycky | f3a3981 | 2015-05-10 12:15:46 +0300 | [diff] [blame] | 187 | kfd_event_free_process(p); | 
|  | 188 |  | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 189 | kfd_pasid_free(p->pasid); | 
| Felix Kuehling | a91e70e | 2017-08-26 02:00:57 -0400 | [diff] [blame] | 190 | kfd_free_process_doorbells(p); | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 191 |  | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 192 | mutex_destroy(&p->mutex); | 
|  | 193 |  | 
| Felix Kuehling | c7b1243 | 2017-11-27 18:29:50 -0500 | [diff] [blame] | 194 | put_task_struct(p->lead_thread); | 
|  | 195 |  | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 196 | kfree(p); | 
| Felix Kuehling | 5ce1068 | 2017-11-27 18:29:51 -0500 | [diff] [blame] | 197 | } | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 198 |  | 
| Felix Kuehling | 5ce1068 | 2017-11-27 18:29:51 -0500 | [diff] [blame] | 199 | static void kfd_process_ref_release(struct kref *ref) | 
|  | 200 | { | 
|  | 201 | struct kfd_process *p = container_of(ref, struct kfd_process, ref); | 
|  | 202 |  | 
|  | 203 | INIT_WORK(&p->release_work, kfd_process_wq_release); | 
|  | 204 | queue_work(kfd_process_wq, &p->release_work); | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 205 | } | 
|  | 206 |  | 
|  | 207 | static void kfd_process_destroy_delayed(struct rcu_head *rcu) | 
|  | 208 | { | 
| Felix Kuehling | 5ce1068 | 2017-11-27 18:29:51 -0500 | [diff] [blame] | 209 | struct kfd_process *p = container_of(rcu, struct kfd_process, rcu); | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 210 |  | 
| Felix Kuehling | abb208a | 2017-11-27 18:29:52 -0500 | [diff] [blame] | 211 | kfd_unref_process(p); | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 212 | } | 
|  | 213 |  | 
|  | 214 | static void kfd_process_notifier_release(struct mmu_notifier *mn, | 
|  | 215 | struct mm_struct *mm) | 
|  | 216 | { | 
|  | 217 | struct kfd_process *p; | 
| Ben Goz | a82918f | 2015-03-25 13:12:20 +0200 | [diff] [blame] | 218 | struct kfd_process_device *pdd = NULL; | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 219 |  | 
|  | 220 | /* | 
|  | 221 | * The kfd_process structure can not be free because the | 
|  | 222 | * mmu_notifier srcu is read locked | 
|  | 223 | */ | 
|  | 224 | p = container_of(mn, struct kfd_process, mmu_notifier); | 
| Felix Kuehling | 32fa821 | 2017-08-15 23:00:12 -0400 | [diff] [blame] | 225 | if (WARN_ON(p->mm != mm)) | 
|  | 226 | return; | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 227 |  | 
|  | 228 | mutex_lock(&kfd_processes_mutex); | 
|  | 229 | hash_del_rcu(&p->kfd_processes); | 
|  | 230 | mutex_unlock(&kfd_processes_mutex); | 
|  | 231 | synchronize_srcu(&kfd_processes_srcu); | 
|  | 232 |  | 
| Ben Goz | 4510204 | 2014-07-17 01:04:10 +0300 | [diff] [blame] | 233 | mutex_lock(&p->mutex); | 
|  | 234 |  | 
| Yair Shachar | 062c567 | 2017-11-01 19:21:29 -0400 | [diff] [blame] | 235 | /* Iterate over all process device data structures and if the | 
|  | 236 | * pdd is in debug mode, we should first force unregistration, | 
|  | 237 | * then we will be able to destroy the queues | 
|  | 238 | */ | 
|  | 239 | list_for_each_entry(pdd, &p->per_device_data, per_device_list) { | 
|  | 240 | struct kfd_dev *dev = pdd->dev; | 
|  | 241 |  | 
|  | 242 | mutex_lock(kfd_get_dbgmgr_mutex()); | 
|  | 243 | if (dev && dev->dbgmgr && dev->dbgmgr->pasid == p->pasid) { | 
|  | 244 | if (!kfd_dbgmgr_unregister(dev->dbgmgr, p)) { | 
|  | 245 | kfd_dbgmgr_destroy(dev->dbgmgr); | 
|  | 246 | dev->dbgmgr = NULL; | 
|  | 247 | } | 
|  | 248 | } | 
|  | 249 | mutex_unlock(kfd_get_dbgmgr_mutex()); | 
|  | 250 | } | 
|  | 251 |  | 
| Felix Kuehling | 9fd3f1bf | 2017-09-27 00:09:52 -0400 | [diff] [blame] | 252 | kfd_process_dequeue_from_all_devices(p); | 
| Ben Goz | 4510204 | 2014-07-17 01:04:10 +0300 | [diff] [blame] | 253 | pqm_uninit(&p->pqm); | 
|  | 254 |  | 
| Felix Kuehling | 5ce1068 | 2017-11-27 18:29:51 -0500 | [diff] [blame] | 255 | /* Indicate to other users that MM is no longer valid */ | 
|  | 256 | p->mm = NULL; | 
|  | 257 |  | 
| Ben Goz | 4510204 | 2014-07-17 01:04:10 +0300 | [diff] [blame] | 258 | mutex_unlock(&p->mutex); | 
|  | 259 |  | 
| Felix Kuehling | 5ce1068 | 2017-11-27 18:29:51 -0500 | [diff] [blame] | 260 | mmu_notifier_unregister_no_release(&p->mmu_notifier, mm); | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 261 | mmu_notifier_call_srcu(&p->rcu, &kfd_process_destroy_delayed); | 
|  | 262 | } | 
|  | 263 |  | 
|  | 264 | static const struct mmu_notifier_ops kfd_process_mmu_notifier_ops = { | 
|  | 265 | .release = kfd_process_notifier_release, | 
|  | 266 | }; | 
|  | 267 |  | 
| Felix Kuehling | 373d708 | 2017-11-14 16:41:19 -0500 | [diff] [blame] | 268 | static int kfd_process_init_cwsr(struct kfd_process *p, struct file *filep) | 
|  | 269 | { | 
| Felix Kuehling | 373d708 | 2017-11-14 16:41:19 -0500 | [diff] [blame] | 270 | unsigned long  offset; | 
| Yong Zhao | c0ede1f | 2017-11-27 18:29:56 -0500 | [diff] [blame] | 271 | struct kfd_process_device *pdd = NULL; | 
| Felix Kuehling | 373d708 | 2017-11-14 16:41:19 -0500 | [diff] [blame] | 272 | struct kfd_dev *dev = NULL; | 
|  | 273 | struct qcm_process_device *qpd = NULL; | 
|  | 274 |  | 
| Yong Zhao | c0ede1f | 2017-11-27 18:29:56 -0500 | [diff] [blame] | 275 | list_for_each_entry(pdd, &p->per_device_data, per_device_list) { | 
| Felix Kuehling | 373d708 | 2017-11-14 16:41:19 -0500 | [diff] [blame] | 276 | dev = pdd->dev; | 
|  | 277 | qpd = &pdd->qpd; | 
|  | 278 | if (!dev->cwsr_enabled || qpd->cwsr_kaddr) | 
|  | 279 | continue; | 
|  | 280 | offset = (dev->id | KFD_MMAP_RESERVED_MEM_MASK) << PAGE_SHIFT; | 
|  | 281 | qpd->tba_addr = (int64_t)vm_mmap(filep, 0, | 
|  | 282 | KFD_CWSR_TBA_TMA_SIZE, PROT_READ | PROT_EXEC, | 
|  | 283 | MAP_SHARED, offset); | 
|  | 284 |  | 
|  | 285 | if (IS_ERR_VALUE(qpd->tba_addr)) { | 
| Yong Zhao | c0ede1f | 2017-11-27 18:29:56 -0500 | [diff] [blame] | 286 | int err = qpd->tba_addr; | 
|  | 287 |  | 
|  | 288 | pr_err("Failure to set tba address. error %d.\n", err); | 
| Felix Kuehling | 373d708 | 2017-11-14 16:41:19 -0500 | [diff] [blame] | 289 | qpd->tba_addr = 0; | 
|  | 290 | qpd->cwsr_kaddr = NULL; | 
| Yong Zhao | c0ede1f | 2017-11-27 18:29:56 -0500 | [diff] [blame] | 291 | return err; | 
| Felix Kuehling | 373d708 | 2017-11-14 16:41:19 -0500 | [diff] [blame] | 292 | } | 
|  | 293 |  | 
|  | 294 | memcpy(qpd->cwsr_kaddr, dev->cwsr_isa, dev->cwsr_isa_size); | 
|  | 295 |  | 
|  | 296 | qpd->tma_addr = qpd->tba_addr + KFD_CWSR_TMA_OFFSET; | 
|  | 297 | pr_debug("set tba :0x%llx, tma:0x%llx, cwsr_kaddr:%p for pqm.\n", | 
|  | 298 | qpd->tba_addr, qpd->tma_addr, qpd->cwsr_kaddr); | 
|  | 299 | } | 
| Yong Zhao | c0ede1f | 2017-11-27 18:29:56 -0500 | [diff] [blame] | 300 |  | 
|  | 301 | return 0; | 
| Felix Kuehling | 373d708 | 2017-11-14 16:41:19 -0500 | [diff] [blame] | 302 | } | 
|  | 303 |  | 
| Yong Zhao | c0ede1f | 2017-11-27 18:29:56 -0500 | [diff] [blame] | 304 | static struct kfd_process *create_process(const struct task_struct *thread, | 
|  | 305 | struct file *filep) | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 306 | { | 
|  | 307 | struct kfd_process *process; | 
|  | 308 | int err = -ENOMEM; | 
|  | 309 |  | 
|  | 310 | process = kzalloc(sizeof(*process), GFP_KERNEL); | 
|  | 311 |  | 
|  | 312 | if (!process) | 
|  | 313 | goto err_alloc_process; | 
|  | 314 |  | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 315 | process->pasid = kfd_pasid_alloc(); | 
|  | 316 | if (process->pasid == 0) | 
|  | 317 | goto err_alloc_pasid; | 
|  | 318 |  | 
| Felix Kuehling | a91e70e | 2017-08-26 02:00:57 -0400 | [diff] [blame] | 319 | if (kfd_alloc_process_doorbells(process) < 0) | 
|  | 320 | goto err_alloc_doorbells; | 
|  | 321 |  | 
| Felix Kuehling | 5ce1068 | 2017-11-27 18:29:51 -0500 | [diff] [blame] | 322 | kref_init(&process->ref); | 
|  | 323 |  | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 324 | mutex_init(&process->mutex); | 
|  | 325 |  | 
|  | 326 | process->mm = thread->mm; | 
|  | 327 |  | 
|  | 328 | /* register notifier */ | 
|  | 329 | process->mmu_notifier.ops = &kfd_process_mmu_notifier_ops; | 
| Yong Zhao | c0ede1f | 2017-11-27 18:29:56 -0500 | [diff] [blame] | 330 | err = mmu_notifier_register(&process->mmu_notifier, process->mm); | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 331 | if (err) | 
|  | 332 | goto err_mmu_notifier; | 
|  | 333 |  | 
|  | 334 | hash_add_rcu(kfd_processes_table, &process->kfd_processes, | 
|  | 335 | (uintptr_t)process->mm); | 
|  | 336 |  | 
|  | 337 | process->lead_thread = thread->group_leader; | 
| Felix Kuehling | c7b1243 | 2017-11-27 18:29:50 -0500 | [diff] [blame] | 338 | get_task_struct(process->lead_thread); | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 339 |  | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 340 | INIT_LIST_HEAD(&process->per_device_data); | 
|  | 341 |  | 
| Andrew Lewycky | f3a3981 | 2015-05-10 12:15:46 +0300 | [diff] [blame] | 342 | kfd_event_init_process(process); | 
|  | 343 |  | 
| Ben Goz | 4510204 | 2014-07-17 01:04:10 +0300 | [diff] [blame] | 344 | err = pqm_init(&process->pqm, process); | 
|  | 345 | if (err != 0) | 
|  | 346 | goto err_process_pqm_init; | 
|  | 347 |  | 
| Alexey Skidanov | dd59239 | 2014-11-18 13:56:23 +0200 | [diff] [blame] | 348 | /* init process apertures*/ | 
| Andy Lutomirski | 10f1685 | 2016-03-22 14:25:19 -0700 | [diff] [blame] | 349 | process->is_32bit_user_mode = in_compat_syscall(); | 
| Dan Carpenter | b312b2b | 2017-06-14 13:58:53 +0300 | [diff] [blame] | 350 | err = kfd_init_apertures(process); | 
|  | 351 | if (err != 0) | 
| Geert Uytterhoeven | 7a10d63 | 2017-06-01 12:28:38 +0200 | [diff] [blame] | 352 | goto err_init_apertures; | 
| Alexey Skidanov | dd59239 | 2014-11-18 13:56:23 +0200 | [diff] [blame] | 353 |  | 
| Yong Zhao | c0ede1f | 2017-11-27 18:29:56 -0500 | [diff] [blame] | 354 | err = kfd_process_init_cwsr(process, filep); | 
|  | 355 | if (err) | 
|  | 356 | goto err_init_cwsr; | 
|  | 357 |  | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 358 | return process; | 
|  | 359 |  | 
| Yong Zhao | c0ede1f | 2017-11-27 18:29:56 -0500 | [diff] [blame] | 360 | err_init_cwsr: | 
|  | 361 | kfd_process_destroy_pdds(process); | 
| Geert Uytterhoeven | 7a10d63 | 2017-06-01 12:28:38 +0200 | [diff] [blame] | 362 | err_init_apertures: | 
| Alexey Skidanov | dd59239 | 2014-11-18 13:56:23 +0200 | [diff] [blame] | 363 | pqm_uninit(&process->pqm); | 
| Ben Goz | 4510204 | 2014-07-17 01:04:10 +0300 | [diff] [blame] | 364 | err_process_pqm_init: | 
|  | 365 | hash_del_rcu(&process->kfd_processes); | 
|  | 366 | synchronize_rcu(); | 
|  | 367 | mmu_notifier_unregister_no_release(&process->mmu_notifier, process->mm); | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 368 | err_mmu_notifier: | 
| Oded Gabbay | 7fd5e03 | 2016-06-23 17:54:29 +0300 | [diff] [blame] | 369 | mutex_destroy(&process->mutex); | 
| Felix Kuehling | a91e70e | 2017-08-26 02:00:57 -0400 | [diff] [blame] | 370 | kfd_free_process_doorbells(process); | 
|  | 371 | err_alloc_doorbells: | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 372 | kfd_pasid_free(process->pasid); | 
|  | 373 | err_alloc_pasid: | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 374 | kfree(process); | 
|  | 375 | err_alloc_process: | 
|  | 376 | return ERR_PTR(err); | 
|  | 377 | } | 
|  | 378 |  | 
|  | 379 | struct kfd_process_device *kfd_get_process_device_data(struct kfd_dev *dev, | 
| Alexey Skidanov | 093c7d8 | 2014-11-18 14:00:04 +0200 | [diff] [blame] | 380 | struct kfd_process *p) | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 381 | { | 
|  | 382 | struct kfd_process_device *pdd = NULL; | 
|  | 383 |  | 
|  | 384 | list_for_each_entry(pdd, &p->per_device_data, per_device_list) | 
|  | 385 | if (pdd->dev == dev) | 
| Yong Zhao | 733fa1f | 2017-09-20 18:10:14 -0400 | [diff] [blame] | 386 | return pdd; | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 387 |  | 
| Yong Zhao | 733fa1f | 2017-09-20 18:10:14 -0400 | [diff] [blame] | 388 | return NULL; | 
| Alexey Skidanov | 093c7d8 | 2014-11-18 14:00:04 +0200 | [diff] [blame] | 389 | } | 
|  | 390 |  | 
|  | 391 | struct kfd_process_device *kfd_create_process_device_data(struct kfd_dev *dev, | 
|  | 392 | struct kfd_process *p) | 
|  | 393 | { | 
|  | 394 | struct kfd_process_device *pdd = NULL; | 
|  | 395 |  | 
|  | 396 | pdd = kzalloc(sizeof(*pdd), GFP_KERNEL); | 
| Felix Kuehling | 2d9b36f | 2017-11-27 18:29:54 -0500 | [diff] [blame] | 397 | if (!pdd) | 
|  | 398 | return NULL; | 
|  | 399 |  | 
|  | 400 | pdd->dev = dev; | 
|  | 401 | INIT_LIST_HEAD(&pdd->qpd.queues_list); | 
|  | 402 | INIT_LIST_HEAD(&pdd->qpd.priv_queue_list); | 
|  | 403 | pdd->qpd.dqm = dev->dqm; | 
|  | 404 | pdd->qpd.pqm = &p->pqm; | 
|  | 405 | pdd->process = p; | 
|  | 406 | pdd->bound = PDD_UNBOUND; | 
|  | 407 | pdd->already_dequeued = false; | 
|  | 408 | list_add(&pdd->per_device_list, &p->per_device_data); | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 409 |  | 
| Felix Kuehling | 403575c | 2018-02-06 20:32:44 -0500 | [diff] [blame^] | 410 | /* Create the GPUVM context for this specific device */ | 
|  | 411 | if (dev->kfd2kgd->create_process_vm(dev->kgd, &pdd->vm, | 
|  | 412 | &p->kgd_process_info, &p->ef)) { | 
|  | 413 | pr_err("Failed to create process VM object\n"); | 
|  | 414 | goto err_create_pdd; | 
|  | 415 | } | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 416 | return pdd; | 
| Felix Kuehling | 403575c | 2018-02-06 20:32:44 -0500 | [diff] [blame^] | 417 |  | 
|  | 418 | err_create_pdd: | 
|  | 419 | list_del(&pdd->per_device_list); | 
|  | 420 | kfree(pdd); | 
|  | 421 | return NULL; | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 422 | } | 
|  | 423 |  | 
|  | 424 | /* | 
|  | 425 | * Direct the IOMMU to bind the process (specifically the pasid->mm) | 
|  | 426 | * to the device. | 
|  | 427 | * Unbinding occurs when the process dies or the device is removed. | 
|  | 428 | * | 
|  | 429 | * Assumes that the process lock is held. | 
|  | 430 | */ | 
|  | 431 | struct kfd_process_device *kfd_bind_process_to_device(struct kfd_dev *dev, | 
|  | 432 | struct kfd_process *p) | 
|  | 433 | { | 
| Alexey Skidanov | 093c7d8 | 2014-11-18 14:00:04 +0200 | [diff] [blame] | 434 | struct kfd_process_device *pdd; | 
| Oded Gabbay | b17f068 | 2014-07-17 00:06:27 +0300 | [diff] [blame] | 435 | int err; | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 436 |  | 
| Alexey Skidanov | 093c7d8 | 2014-11-18 14:00:04 +0200 | [diff] [blame] | 437 | pdd = kfd_get_process_device_data(dev, p); | 
|  | 438 | if (!pdd) { | 
|  | 439 | pr_err("Process device data doesn't exist\n"); | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 440 | return ERR_PTR(-ENOMEM); | 
| Alexey Skidanov | 093c7d8 | 2014-11-18 14:00:04 +0200 | [diff] [blame] | 441 | } | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 442 |  | 
| Felix Kuehling | 64d1c3a | 2017-12-08 19:22:12 -0500 | [diff] [blame] | 443 | err = kfd_iommu_bind_process_to_device(pdd); | 
|  | 444 | if (err) | 
| Oded Gabbay | b17f068 | 2014-07-17 00:06:27 +0300 | [diff] [blame] | 445 | return ERR_PTR(err); | 
|  | 446 |  | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 447 | return pdd; | 
|  | 448 | } | 
|  | 449 |  | 
| Kent Russell | 8eabaf5 | 2017-08-15 23:00:04 -0400 | [diff] [blame] | 450 | struct kfd_process_device *kfd_get_first_process_device_data( | 
|  | 451 | struct kfd_process *p) | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 452 | { | 
|  | 453 | return list_first_entry(&p->per_device_data, | 
|  | 454 | struct kfd_process_device, | 
|  | 455 | per_device_list); | 
|  | 456 | } | 
|  | 457 |  | 
| Kent Russell | 8eabaf5 | 2017-08-15 23:00:04 -0400 | [diff] [blame] | 458 | struct kfd_process_device *kfd_get_next_process_device_data( | 
|  | 459 | struct kfd_process *p, | 
| Oded Gabbay | 19f6d2a | 2014-07-16 23:25:31 +0300 | [diff] [blame] | 460 | struct kfd_process_device *pdd) | 
|  | 461 | { | 
|  | 462 | if (list_is_last(&pdd->per_device_list, &p->per_device_data)) | 
|  | 463 | return NULL; | 
|  | 464 | return list_next_entry(pdd, per_device_list); | 
|  | 465 | } | 
|  | 466 |  | 
|  | 467 | bool kfd_has_process_device_data(struct kfd_process *p) | 
|  | 468 | { | 
|  | 469 | return !(list_empty(&p->per_device_data)); | 
|  | 470 | } | 
| Andrew Lewycky | f3a3981 | 2015-05-10 12:15:46 +0300 | [diff] [blame] | 471 |  | 
| Felix Kuehling | abb208a | 2017-11-27 18:29:52 -0500 | [diff] [blame] | 472 | /* This increments the process->ref counter. */ | 
| Andrew Lewycky | f3a3981 | 2015-05-10 12:15:46 +0300 | [diff] [blame] | 473 | struct kfd_process *kfd_lookup_process_by_pasid(unsigned int pasid) | 
|  | 474 | { | 
| Yong Zhao | 82c16b4 | 2017-11-27 18:29:53 -0500 | [diff] [blame] | 475 | struct kfd_process *p, *ret_p = NULL; | 
| Andrew Lewycky | f3a3981 | 2015-05-10 12:15:46 +0300 | [diff] [blame] | 476 | unsigned int temp; | 
|  | 477 |  | 
|  | 478 | int idx = srcu_read_lock(&kfd_processes_srcu); | 
|  | 479 |  | 
|  | 480 | hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) { | 
|  | 481 | if (p->pasid == pasid) { | 
| Felix Kuehling | abb208a | 2017-11-27 18:29:52 -0500 | [diff] [blame] | 482 | kref_get(&p->ref); | 
| Yong Zhao | 82c16b4 | 2017-11-27 18:29:53 -0500 | [diff] [blame] | 483 | ret_p = p; | 
| Andrew Lewycky | f3a3981 | 2015-05-10 12:15:46 +0300 | [diff] [blame] | 484 | break; | 
|  | 485 | } | 
|  | 486 | } | 
|  | 487 |  | 
|  | 488 | srcu_read_unlock(&kfd_processes_srcu, idx); | 
|  | 489 |  | 
| Yong Zhao | 82c16b4 | 2017-11-27 18:29:53 -0500 | [diff] [blame] | 490 | return ret_p; | 
| Andrew Lewycky | f3a3981 | 2015-05-10 12:15:46 +0300 | [diff] [blame] | 491 | } | 
| Felix Kuehling | 373d708 | 2017-11-14 16:41:19 -0500 | [diff] [blame] | 492 |  | 
|  | 493 | int kfd_reserved_mem_mmap(struct kfd_process *process, | 
|  | 494 | struct vm_area_struct *vma) | 
|  | 495 | { | 
|  | 496 | struct kfd_dev *dev = kfd_device_by_id(vma->vm_pgoff); | 
|  | 497 | struct kfd_process_device *pdd; | 
|  | 498 | struct qcm_process_device *qpd; | 
|  | 499 |  | 
|  | 500 | if (!dev) | 
|  | 501 | return -EINVAL; | 
|  | 502 | if ((vma->vm_end - vma->vm_start) != KFD_CWSR_TBA_TMA_SIZE) { | 
|  | 503 | pr_err("Incorrect CWSR mapping size.\n"); | 
|  | 504 | return -EINVAL; | 
|  | 505 | } | 
|  | 506 |  | 
|  | 507 | pdd = kfd_get_process_device_data(dev, process); | 
|  | 508 | if (!pdd) | 
|  | 509 | return -EINVAL; | 
|  | 510 | qpd = &pdd->qpd; | 
|  | 511 |  | 
|  | 512 | qpd->cwsr_kaddr = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, | 
|  | 513 | get_order(KFD_CWSR_TBA_TMA_SIZE)); | 
|  | 514 | if (!qpd->cwsr_kaddr) { | 
|  | 515 | pr_err("Error allocating per process CWSR buffer.\n"); | 
|  | 516 | return -ENOMEM; | 
|  | 517 | } | 
|  | 518 |  | 
|  | 519 | vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND | 
|  | 520 | | VM_NORESERVE | VM_DONTDUMP | VM_PFNMAP; | 
|  | 521 | /* Mapping pages to user process */ | 
|  | 522 | return remap_pfn_range(vma, vma->vm_start, | 
|  | 523 | PFN_DOWN(__pa(qpd->cwsr_kaddr)), | 
|  | 524 | KFD_CWSR_TBA_TMA_SIZE, vma->vm_page_prot); | 
|  | 525 | } | 
| Felix Kuehling | 851a645 | 2017-11-27 18:29:49 -0500 | [diff] [blame] | 526 |  | 
| Felix Kuehling | 403575c | 2018-02-06 20:32:44 -0500 | [diff] [blame^] | 527 | void kfd_flush_tlb(struct kfd_process_device *pdd) | 
|  | 528 | { | 
|  | 529 | struct kfd_dev *dev = pdd->dev; | 
|  | 530 | const struct kfd2kgd_calls *f2g = dev->kfd2kgd; | 
|  | 531 |  | 
|  | 532 | if (dev->dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) { | 
|  | 533 | /* Nothing to flush until a VMID is assigned, which | 
|  | 534 | * only happens when the first queue is created. | 
|  | 535 | */ | 
|  | 536 | if (pdd->qpd.vmid) | 
|  | 537 | f2g->invalidate_tlbs_vmid(dev->kgd, pdd->qpd.vmid); | 
|  | 538 | } else { | 
|  | 539 | f2g->invalidate_tlbs(dev->kgd, pdd->process->pasid); | 
|  | 540 | } | 
|  | 541 | } | 
|  | 542 |  | 
| Felix Kuehling | 851a645 | 2017-11-27 18:29:49 -0500 | [diff] [blame] | 543 | #if defined(CONFIG_DEBUG_FS) | 
|  | 544 |  | 
|  | 545 | int kfd_debugfs_mqds_by_process(struct seq_file *m, void *data) | 
|  | 546 | { | 
|  | 547 | struct kfd_process *p; | 
|  | 548 | unsigned int temp; | 
|  | 549 | int r = 0; | 
|  | 550 |  | 
|  | 551 | int idx = srcu_read_lock(&kfd_processes_srcu); | 
|  | 552 |  | 
|  | 553 | hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) { | 
|  | 554 | seq_printf(m, "Process %d PASID %d:\n", | 
|  | 555 | p->lead_thread->tgid, p->pasid); | 
|  | 556 |  | 
|  | 557 | mutex_lock(&p->mutex); | 
|  | 558 | r = pqm_debugfs_mqds(m, &p->pqm); | 
|  | 559 | mutex_unlock(&p->mutex); | 
|  | 560 |  | 
|  | 561 | if (r) | 
|  | 562 | break; | 
|  | 563 | } | 
|  | 564 |  | 
|  | 565 | srcu_read_unlock(&kfd_processes_srcu, idx); | 
|  | 566 |  | 
|  | 567 | return r; | 
|  | 568 | } | 
|  | 569 |  | 
|  | 570 | #endif |