1d87f36a0SRajneesh Bhardwaj // SPDX-License-Identifier: GPL-2.0 OR MIT
219f6d2a6SOded Gabbay /*
3d87f36a0SRajneesh Bhardwaj * Copyright 2014-2022 Advanced Micro Devices, Inc.
419f6d2a6SOded Gabbay *
519f6d2a6SOded Gabbay * Permission is hereby granted, free of charge, to any person obtaining a
619f6d2a6SOded Gabbay * copy of this software and associated documentation files (the "Software"),
719f6d2a6SOded Gabbay * to deal in the Software without restriction, including without limitation
819f6d2a6SOded Gabbay * the rights to use, copy, modify, merge, publish, distribute, sublicense,
919f6d2a6SOded Gabbay * and/or sell copies of the Software, and to permit persons to whom the
1019f6d2a6SOded Gabbay * Software is furnished to do so, subject to the following conditions:
1119f6d2a6SOded Gabbay *
1219f6d2a6SOded Gabbay * The above copyright notice and this permission notice shall be included in
1319f6d2a6SOded Gabbay * all copies or substantial portions of the Software.
1419f6d2a6SOded Gabbay *
1519f6d2a6SOded Gabbay * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1619f6d2a6SOded Gabbay * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1719f6d2a6SOded Gabbay * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1819f6d2a6SOded Gabbay * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1919f6d2a6SOded Gabbay * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2019f6d2a6SOded Gabbay * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2119f6d2a6SOded Gabbay * OTHER DEALINGS IN THE SOFTWARE.
2219f6d2a6SOded Gabbay */
2319f6d2a6SOded Gabbay
2419f6d2a6SOded Gabbay #include <linux/mutex.h>
2519f6d2a6SOded Gabbay #include <linux/log2.h>
2619f6d2a6SOded Gabbay #include <linux/sched.h>
276e84f315SIngo Molnar #include <linux/sched/mm.h>
28c7b1243eSFelix Kuehling #include <linux/sched/task.h>
2932cb59f3SMukul Joshi #include <linux/mmu_context.h>
3019f6d2a6SOded Gabbay #include <linux/slab.h>
3119f6d2a6SOded Gabbay #include <linux/notifier.h>
32dd59239aSAlexey Skidanov #include <linux/compat.h>
33373d7080SFelix Kuehling #include <linux/mman.h>
34b84394e2SFelix Kuehling #include <linux/file.h>
359593f4d6SRajneesh Bhardwaj #include <linux/pm_runtime.h>
365b87245fSAmber Lin #include "amdgpu_amdkfd.h"
37ffa02269SAlex Sierra #include "amdgpu.h"
38dd59239aSAlexey Skidanov
3919f6d2a6SOded Gabbay struct mm_struct;
4019f6d2a6SOded Gabbay
4119f6d2a6SOded Gabbay #include "kfd_priv.h"
42403575c4SFelix Kuehling #include "kfd_device_queue_manager.h"
4342de677fSPhilip Yang #include "kfd_svm.h"
44c7f21978SPhilip Yang #include "kfd_smi_events.h"
450ab2d753SJonathan Kim #include "kfd_debug.h"
4619f6d2a6SOded Gabbay
4719f6d2a6SOded Gabbay /*
4819f6d2a6SOded Gabbay * List of struct kfd_process (field kfd_process).
4919f6d2a6SOded Gabbay * Unique/indexed by mm_struct*
5019f6d2a6SOded Gabbay */
5164d1c3a4SFelix Kuehling DEFINE_HASHTABLE(kfd_processes_table, KFD_PROCESS_TABLE_SIZE);
52fe1f05dfSMukul Joshi DEFINE_MUTEX(kfd_processes_mutex);
5319f6d2a6SOded Gabbay
5464d1c3a4SFelix Kuehling DEFINE_SRCU(kfd_processes_srcu);
5519f6d2a6SOded Gabbay
561679ae8fSFelix Kuehling /* For process termination handling */
5719f6d2a6SOded Gabbay static struct workqueue_struct *kfd_process_wq;
5819f6d2a6SOded Gabbay
591679ae8fSFelix Kuehling /* Ordered, single-threaded workqueue for restoring evicted
601679ae8fSFelix Kuehling * processes. Restoring multiple processes concurrently under memory
611679ae8fSFelix Kuehling * pressure can lead to processes blocking each other from validating
621679ae8fSFelix Kuehling * their BOs and result in a live-lock situation where processes
631679ae8fSFelix Kuehling * remain evicted indefinitely.
641679ae8fSFelix Kuehling */
651679ae8fSFelix Kuehling static struct workqueue_struct *kfd_restore_wq;
661679ae8fSFelix Kuehling
67011bbb03SRajneesh Bhardwaj static struct kfd_process *find_process(const struct task_struct *thread,
68011bbb03SRajneesh Bhardwaj bool ref);
69abb208a8SFelix Kuehling static void kfd_process_ref_release(struct kref *ref);
700029cab3SJason Gunthorpe static struct kfd_process *create_process(const struct task_struct *thread);
71373d7080SFelix Kuehling
7226103436SFelix Kuehling static void evict_process_worker(struct work_struct *work);
7326103436SFelix Kuehling static void restore_process_worker(struct work_struct *work);
7426103436SFelix Kuehling
7568df0f19SLang Yu static void kfd_process_device_destroy_cwsr_dgpu(struct kfd_process_device *pdd);
7668df0f19SLang Yu
77de9f26bbSKent Russell struct kfd_procfs_tree {
78de9f26bbSKent Russell struct kobject *kobj;
79de9f26bbSKent Russell };
80de9f26bbSKent Russell
81de9f26bbSKent Russell static struct kfd_procfs_tree procfs;
82de9f26bbSKent Russell
8332cb59f3SMukul Joshi /*
8432cb59f3SMukul Joshi * Structure for SDMA activity tracking
8532cb59f3SMukul Joshi */
8632cb59f3SMukul Joshi struct kfd_sdma_activity_handler_workarea {
8732cb59f3SMukul Joshi struct work_struct sdma_activity_work;
8832cb59f3SMukul Joshi struct kfd_process_device *pdd;
8932cb59f3SMukul Joshi uint64_t sdma_activity_counter;
9032cb59f3SMukul Joshi };
9132cb59f3SMukul Joshi
92d69fd951SMukul Joshi struct temp_sdma_queue_list {
93818b0324SMukul Joshi uint64_t __user *rptr;
94d69fd951SMukul Joshi uint64_t sdma_val;
95d69fd951SMukul Joshi unsigned int queue_id;
96d69fd951SMukul Joshi struct list_head list;
97d69fd951SMukul Joshi };
98d69fd951SMukul Joshi
kfd_sdma_activity_worker(struct work_struct * work)9932cb59f3SMukul Joshi static void kfd_sdma_activity_worker(struct work_struct *work)
10032cb59f3SMukul Joshi {
10132cb59f3SMukul Joshi struct kfd_sdma_activity_handler_workarea *workarea;
10232cb59f3SMukul Joshi struct kfd_process_device *pdd;
10332cb59f3SMukul Joshi uint64_t val;
10432cb59f3SMukul Joshi struct mm_struct *mm;
10532cb59f3SMukul Joshi struct queue *q;
10632cb59f3SMukul Joshi struct qcm_process_device *qpd;
10732cb59f3SMukul Joshi struct device_queue_manager *dqm;
10832cb59f3SMukul Joshi int ret = 0;
109d69fd951SMukul Joshi struct temp_sdma_queue_list sdma_q_list;
110d69fd951SMukul Joshi struct temp_sdma_queue_list *sdma_q, *next;
11132cb59f3SMukul Joshi
11232cb59f3SMukul Joshi workarea = container_of(work, struct kfd_sdma_activity_handler_workarea,
11332cb59f3SMukul Joshi sdma_activity_work);
11432cb59f3SMukul Joshi
11532cb59f3SMukul Joshi pdd = workarea->pdd;
1162652bda7SColin Ian King if (!pdd)
1172652bda7SColin Ian King return;
11832cb59f3SMukul Joshi dqm = pdd->dev->dqm;
11932cb59f3SMukul Joshi qpd = &pdd->qpd;
1202652bda7SColin Ian King if (!dqm || !qpd)
12132cb59f3SMukul Joshi return;
122d69fd951SMukul Joshi /*
123d69fd951SMukul Joshi * Total SDMA activity is current SDMA activity + past SDMA activity
124d69fd951SMukul Joshi * Past SDMA count is stored in pdd.
125d69fd951SMukul Joshi * To get the current activity counters for all active SDMA queues,
126d69fd951SMukul Joshi * we loop over all SDMA queues and get their counts from user-space.
127d69fd951SMukul Joshi *
128d69fd951SMukul Joshi * We cannot call get_user() with dqm_lock held as it can cause
129d69fd951SMukul Joshi * a circular lock dependency situation. To read the SDMA stats,
130d69fd951SMukul Joshi * we need to do the following:
131d69fd951SMukul Joshi *
132d69fd951SMukul Joshi * 1. Create a temporary list of SDMA queue nodes from the qpd->queues_list,
133d69fd951SMukul Joshi * with dqm_lock/dqm_unlock().
134d69fd951SMukul Joshi * 2. Call get_user() for each node in temporary list without dqm_lock.
135d69fd951SMukul Joshi * Save the SDMA count for each node and also add the count to the total
136d69fd951SMukul Joshi * SDMA count counter.
137d69fd951SMukul Joshi * Its possible, during this step, a few SDMA queue nodes got deleted
138d69fd951SMukul Joshi * from the qpd->queues_list.
139d69fd951SMukul Joshi * 3. Do a second pass over qpd->queues_list to check if any nodes got deleted.
140d69fd951SMukul Joshi * If any node got deleted, its SDMA count would be captured in the sdma
141d69fd951SMukul Joshi * past activity counter. So subtract the SDMA counter stored in step 2
142d69fd951SMukul Joshi * for this node from the total SDMA count.
143d69fd951SMukul Joshi */
144d69fd951SMukul Joshi INIT_LIST_HEAD(&sdma_q_list.list);
14532cb59f3SMukul Joshi
146d69fd951SMukul Joshi /*
147d69fd951SMukul Joshi * Create the temp list of all SDMA queues
148d69fd951SMukul Joshi */
149d69fd951SMukul Joshi dqm_lock(dqm);
150d69fd951SMukul Joshi
151d69fd951SMukul Joshi list_for_each_entry(q, &qpd->queues_list, list) {
152d69fd951SMukul Joshi if ((q->properties.type != KFD_QUEUE_TYPE_SDMA) &&
153d69fd951SMukul Joshi (q->properties.type != KFD_QUEUE_TYPE_SDMA_XGMI))
154d69fd951SMukul Joshi continue;
155d69fd951SMukul Joshi
156d69fd951SMukul Joshi sdma_q = kzalloc(sizeof(struct temp_sdma_queue_list), GFP_KERNEL);
157d69fd951SMukul Joshi if (!sdma_q) {
158d69fd951SMukul Joshi dqm_unlock(dqm);
159d69fd951SMukul Joshi goto cleanup;
160d69fd951SMukul Joshi }
161d69fd951SMukul Joshi
162d69fd951SMukul Joshi INIT_LIST_HEAD(&sdma_q->list);
163818b0324SMukul Joshi sdma_q->rptr = (uint64_t __user *)q->properties.read_ptr;
164d69fd951SMukul Joshi sdma_q->queue_id = q->properties.queue_id;
165d69fd951SMukul Joshi list_add_tail(&sdma_q->list, &sdma_q_list.list);
166d69fd951SMukul Joshi }
167d69fd951SMukul Joshi
168d69fd951SMukul Joshi /*
169d69fd951SMukul Joshi * If the temp list is empty, then no SDMA queues nodes were found in
170d69fd951SMukul Joshi * qpd->queues_list. Return the past activity count as the total sdma
171d69fd951SMukul Joshi * count
172d69fd951SMukul Joshi */
173d69fd951SMukul Joshi if (list_empty(&sdma_q_list.list)) {
174d69fd951SMukul Joshi workarea->sdma_activity_counter = pdd->sdma_past_activity_counter;
175d69fd951SMukul Joshi dqm_unlock(dqm);
17632cb59f3SMukul Joshi return;
17732cb59f3SMukul Joshi }
17832cb59f3SMukul Joshi
179d69fd951SMukul Joshi dqm_unlock(dqm);
180d69fd951SMukul Joshi
181d69fd951SMukul Joshi /*
182d69fd951SMukul Joshi * Get the usage count for each SDMA queue in temp_list.
183d69fd951SMukul Joshi */
184d69fd951SMukul Joshi mm = get_task_mm(pdd->process->lead_thread);
185d69fd951SMukul Joshi if (!mm)
186d69fd951SMukul Joshi goto cleanup;
187d69fd951SMukul Joshi
1889555152bSDave Airlie kthread_use_mm(mm);
18932cb59f3SMukul Joshi
190d69fd951SMukul Joshi list_for_each_entry(sdma_q, &sdma_q_list.list, list) {
19132cb59f3SMukul Joshi val = 0;
192d69fd951SMukul Joshi ret = read_sdma_queue_counter(sdma_q->rptr, &val);
193d69fd951SMukul Joshi if (ret) {
194d69fd951SMukul Joshi pr_debug("Failed to read SDMA queue active counter for queue id: %d",
195d69fd951SMukul Joshi sdma_q->queue_id);
196d69fd951SMukul Joshi } else {
197d69fd951SMukul Joshi sdma_q->sdma_val = val;
19832cb59f3SMukul Joshi workarea->sdma_activity_counter += val;
19932cb59f3SMukul Joshi }
20032cb59f3SMukul Joshi }
20132cb59f3SMukul Joshi
2029555152bSDave Airlie kthread_unuse_mm(mm);
20332cb59f3SMukul Joshi mmput(mm);
204d69fd951SMukul Joshi
205d69fd951SMukul Joshi /*
206d69fd951SMukul Joshi * Do a second iteration over qpd_queues_list to check if any SDMA
207d69fd951SMukul Joshi * nodes got deleted while fetching SDMA counter.
208d69fd951SMukul Joshi */
209d69fd951SMukul Joshi dqm_lock(dqm);
210d69fd951SMukul Joshi
211d69fd951SMukul Joshi workarea->sdma_activity_counter += pdd->sdma_past_activity_counter;
212d69fd951SMukul Joshi
213d69fd951SMukul Joshi list_for_each_entry(q, &qpd->queues_list, list) {
214d69fd951SMukul Joshi if (list_empty(&sdma_q_list.list))
215d69fd951SMukul Joshi break;
216d69fd951SMukul Joshi
217d69fd951SMukul Joshi if ((q->properties.type != KFD_QUEUE_TYPE_SDMA) &&
218d69fd951SMukul Joshi (q->properties.type != KFD_QUEUE_TYPE_SDMA_XGMI))
219d69fd951SMukul Joshi continue;
220d69fd951SMukul Joshi
221d69fd951SMukul Joshi list_for_each_entry_safe(sdma_q, next, &sdma_q_list.list, list) {
222818b0324SMukul Joshi if (((uint64_t __user *)q->properties.read_ptr == sdma_q->rptr) &&
223d69fd951SMukul Joshi (sdma_q->queue_id == q->properties.queue_id)) {
224d69fd951SMukul Joshi list_del(&sdma_q->list);
225d69fd951SMukul Joshi kfree(sdma_q);
226d69fd951SMukul Joshi break;
227d69fd951SMukul Joshi }
228d69fd951SMukul Joshi }
229d69fd951SMukul Joshi }
230d69fd951SMukul Joshi
231d69fd951SMukul Joshi dqm_unlock(dqm);
232d69fd951SMukul Joshi
233d69fd951SMukul Joshi /*
234d69fd951SMukul Joshi * If temp list is not empty, it implies some queues got deleted
235d69fd951SMukul Joshi * from qpd->queues_list during SDMA usage read. Subtract the SDMA
236d69fd951SMukul Joshi * count for each node from the total SDMA count.
237d69fd951SMukul Joshi */
238d69fd951SMukul Joshi list_for_each_entry_safe(sdma_q, next, &sdma_q_list.list, list) {
239d69fd951SMukul Joshi workarea->sdma_activity_counter -= sdma_q->sdma_val;
240d69fd951SMukul Joshi list_del(&sdma_q->list);
241d69fd951SMukul Joshi kfree(sdma_q);
242d69fd951SMukul Joshi }
243d69fd951SMukul Joshi
244d69fd951SMukul Joshi return;
245d69fd951SMukul Joshi
246d69fd951SMukul Joshi cleanup:
247d69fd951SMukul Joshi list_for_each_entry_safe(sdma_q, next, &sdma_q_list.list, list) {
248d69fd951SMukul Joshi list_del(&sdma_q->list);
249d69fd951SMukul Joshi kfree(sdma_q);
250d69fd951SMukul Joshi }
25132cb59f3SMukul Joshi }
25232cb59f3SMukul Joshi
253f2fa07b3SRamesh Errabolu /**
254bbe04decSIsabella Basso * kfd_get_cu_occupancy - Collect number of waves in-flight on this device
255f2fa07b3SRamesh Errabolu * by current process. Translates acquired wave count into number of compute units
256f2fa07b3SRamesh Errabolu * that are occupied.
257f2fa07b3SRamesh Errabolu *
258bbe04decSIsabella Basso * @attr: Handle of attribute that allows reporting of wave count. The attribute
259f2fa07b3SRamesh Errabolu * handle encapsulates GPU device it is associated with, thereby allowing collection
260f2fa07b3SRamesh Errabolu * of waves in flight, etc
261f2fa07b3SRamesh Errabolu * @buffer: Handle of user provided buffer updated with wave count
262f2fa07b3SRamesh Errabolu *
263f2fa07b3SRamesh Errabolu * Return: Number of bytes written to user buffer or an error value
264f2fa07b3SRamesh Errabolu */
kfd_get_cu_occupancy(struct attribute * attr,char * buffer)265f2fa07b3SRamesh Errabolu static int kfd_get_cu_occupancy(struct attribute *attr, char *buffer)
266f2fa07b3SRamesh Errabolu {
267f2fa07b3SRamesh Errabolu int cu_cnt;
268f2fa07b3SRamesh Errabolu int wave_cnt;
269f2fa07b3SRamesh Errabolu int max_waves_per_cu;
2708dc1db31SMukul Joshi struct kfd_node *dev = NULL;
271f2fa07b3SRamesh Errabolu struct kfd_process *proc = NULL;
272f2fa07b3SRamesh Errabolu struct kfd_process_device *pdd = NULL;
273f2fa07b3SRamesh Errabolu
274f2fa07b3SRamesh Errabolu pdd = container_of(attr, struct kfd_process_device, attr_cu_occupancy);
275f2fa07b3SRamesh Errabolu dev = pdd->dev;
276f2fa07b3SRamesh Errabolu if (dev->kfd2kgd->get_cu_occupancy == NULL)
277f2fa07b3SRamesh Errabolu return -EINVAL;
278f2fa07b3SRamesh Errabolu
279f2fa07b3SRamesh Errabolu cu_cnt = 0;
280f2fa07b3SRamesh Errabolu proc = pdd->process;
281f2fa07b3SRamesh Errabolu if (pdd->qpd.queue_count == 0) {
282f2fa07b3SRamesh Errabolu pr_debug("Gpu-Id: %d has no active queues for process %d\n",
283f2fa07b3SRamesh Errabolu dev->id, proc->pasid);
284f2fa07b3SRamesh Errabolu return snprintf(buffer, PAGE_SIZE, "%d\n", cu_cnt);
285f2fa07b3SRamesh Errabolu }
286f2fa07b3SRamesh Errabolu
287f2fa07b3SRamesh Errabolu /* Collect wave count from device if it supports */
288f2fa07b3SRamesh Errabolu wave_cnt = 0;
289f2fa07b3SRamesh Errabolu max_waves_per_cu = 0;
2903356c38dSGraham Sider dev->kfd2kgd->get_cu_occupancy(dev->adev, proc->pasid, &wave_cnt,
291e2069a7bSMukul Joshi &max_waves_per_cu, 0);
292f2fa07b3SRamesh Errabolu
293f2fa07b3SRamesh Errabolu /* Translate wave count to number of compute units */
294f2fa07b3SRamesh Errabolu cu_cnt = (wave_cnt + (max_waves_per_cu - 1)) / max_waves_per_cu;
295f2fa07b3SRamesh Errabolu return snprintf(buffer, PAGE_SIZE, "%d\n", cu_cnt);
296f2fa07b3SRamesh Errabolu }
297f2fa07b3SRamesh Errabolu
kfd_procfs_show(struct kobject * kobj,struct attribute * attr,char * buffer)298de9f26bbSKent Russell static ssize_t kfd_procfs_show(struct kobject *kobj, struct attribute *attr,
299de9f26bbSKent Russell char *buffer)
300de9f26bbSKent Russell {
301de9f26bbSKent Russell if (strcmp(attr->name, "pasid") == 0) {
302de9f26bbSKent Russell struct kfd_process *p = container_of(attr, struct kfd_process,
303de9f26bbSKent Russell attr_pasid);
304d4566deeSMukul Joshi
305d4566deeSMukul Joshi return snprintf(buffer, PAGE_SIZE, "%d\n", p->pasid);
306d4566deeSMukul Joshi } else if (strncmp(attr->name, "vram_", 5) == 0) {
307d4566deeSMukul Joshi struct kfd_process_device *pdd = container_of(attr, struct kfd_process_device,
308d4566deeSMukul Joshi attr_vram);
3094c332037SPhilip Yang return snprintf(buffer, PAGE_SIZE, "%llu\n", atomic64_read(&pdd->vram_usage));
31032cb59f3SMukul Joshi } else if (strncmp(attr->name, "sdma_", 5) == 0) {
31132cb59f3SMukul Joshi struct kfd_process_device *pdd = container_of(attr, struct kfd_process_device,
31232cb59f3SMukul Joshi attr_sdma);
31332cb59f3SMukul Joshi struct kfd_sdma_activity_handler_workarea sdma_activity_work_handler;
31432cb59f3SMukul Joshi
31538e3d796SYuan Can INIT_WORK_ONSTACK(&sdma_activity_work_handler.sdma_activity_work,
31632cb59f3SMukul Joshi kfd_sdma_activity_worker);
31732cb59f3SMukul Joshi
31832cb59f3SMukul Joshi sdma_activity_work_handler.pdd = pdd;
3195960e022SMukul Joshi sdma_activity_work_handler.sdma_activity_counter = 0;
32032cb59f3SMukul Joshi
32132cb59f3SMukul Joshi schedule_work(&sdma_activity_work_handler.sdma_activity_work);
32232cb59f3SMukul Joshi
32332cb59f3SMukul Joshi flush_work(&sdma_activity_work_handler.sdma_activity_work);
32438e3d796SYuan Can destroy_work_on_stack(&sdma_activity_work_handler.sdma_activity_work);
32532cb59f3SMukul Joshi
32632cb59f3SMukul Joshi return snprintf(buffer, PAGE_SIZE, "%llu\n",
32732cb59f3SMukul Joshi (sdma_activity_work_handler.sdma_activity_counter)/
32832cb59f3SMukul Joshi SDMA_ACTIVITY_DIVISOR);
329de9f26bbSKent Russell } else {
330de9f26bbSKent Russell pr_err("Invalid attribute");
331de9f26bbSKent Russell return -EINVAL;
332de9f26bbSKent Russell }
333de9f26bbSKent Russell
334d4566deeSMukul Joshi return 0;
335de9f26bbSKent Russell }
336de9f26bbSKent Russell
kfd_procfs_kobj_release(struct kobject * kobj)337de9f26bbSKent Russell static void kfd_procfs_kobj_release(struct kobject *kobj)
338de9f26bbSKent Russell {
339de9f26bbSKent Russell kfree(kobj);
340de9f26bbSKent Russell }
341de9f26bbSKent Russell
342de9f26bbSKent Russell static const struct sysfs_ops kfd_procfs_ops = {
343de9f26bbSKent Russell .show = kfd_procfs_show,
344de9f26bbSKent Russell };
345de9f26bbSKent Russell
3464fa01c63SThomas Weißschuh static const struct kobj_type procfs_type = {
347de9f26bbSKent Russell .release = kfd_procfs_kobj_release,
348de9f26bbSKent Russell .sysfs_ops = &kfd_procfs_ops,
349de9f26bbSKent Russell };
350de9f26bbSKent Russell
kfd_procfs_init(void)351de9f26bbSKent Russell void kfd_procfs_init(void)
352de9f26bbSKent Russell {
353de9f26bbSKent Russell int ret = 0;
354de9f26bbSKent Russell
355de9f26bbSKent Russell procfs.kobj = kfd_alloc_struct(procfs.kobj);
356de9f26bbSKent Russell if (!procfs.kobj)
357de9f26bbSKent Russell return;
358de9f26bbSKent Russell
359de9f26bbSKent Russell ret = kobject_init_and_add(procfs.kobj, &procfs_type,
360de9f26bbSKent Russell &kfd_device->kobj, "proc");
361de9f26bbSKent Russell if (ret) {
362de9f26bbSKent Russell pr_warn("Could not create procfs proc folder");
363de9f26bbSKent Russell /* If we fail to create the procfs, clean up */
364de9f26bbSKent Russell kfd_procfs_shutdown();
365de9f26bbSKent Russell }
366de9f26bbSKent Russell }
367de9f26bbSKent Russell
kfd_procfs_shutdown(void)368de9f26bbSKent Russell void kfd_procfs_shutdown(void)
369de9f26bbSKent Russell {
370de9f26bbSKent Russell if (procfs.kobj) {
371de9f26bbSKent Russell kobject_del(procfs.kobj);
372de9f26bbSKent Russell kobject_put(procfs.kobj);
373de9f26bbSKent Russell procfs.kobj = NULL;
374de9f26bbSKent Russell }
375de9f26bbSKent Russell }
37619f6d2a6SOded Gabbay
kfd_procfs_queue_show(struct kobject * kobj,struct attribute * attr,char * buffer)3776d220a7eSAmber Lin static ssize_t kfd_procfs_queue_show(struct kobject *kobj,
3786d220a7eSAmber Lin struct attribute *attr, char *buffer)
3796d220a7eSAmber Lin {
3806d220a7eSAmber Lin struct queue *q = container_of(kobj, struct queue, kobj);
3816d220a7eSAmber Lin
3826d220a7eSAmber Lin if (!strcmp(attr->name, "size"))
3836d220a7eSAmber Lin return snprintf(buffer, PAGE_SIZE, "%llu",
3846d220a7eSAmber Lin q->properties.queue_size);
3856d220a7eSAmber Lin else if (!strcmp(attr->name, "type"))
3866d220a7eSAmber Lin return snprintf(buffer, PAGE_SIZE, "%d", q->properties.type);
3876d220a7eSAmber Lin else if (!strcmp(attr->name, "gpuid"))
3886d220a7eSAmber Lin return snprintf(buffer, PAGE_SIZE, "%u", q->device->id);
3896d220a7eSAmber Lin else
3906d220a7eSAmber Lin pr_err("Invalid attribute");
3916d220a7eSAmber Lin
3926d220a7eSAmber Lin return 0;
3936d220a7eSAmber Lin }
3946d220a7eSAmber Lin
kfd_procfs_stats_show(struct kobject * kobj,struct attribute * attr,char * buffer)3954327bed2SPhilip Cox static ssize_t kfd_procfs_stats_show(struct kobject *kobj,
3964327bed2SPhilip Cox struct attribute *attr, char *buffer)
3974327bed2SPhilip Cox {
3984327bed2SPhilip Cox if (strcmp(attr->name, "evicted_ms") == 0) {
3994327bed2SPhilip Cox struct kfd_process_device *pdd = container_of(attr,
4004327bed2SPhilip Cox struct kfd_process_device,
4014327bed2SPhilip Cox attr_evict);
4024327bed2SPhilip Cox uint64_t evict_jiffies;
4034327bed2SPhilip Cox
4044327bed2SPhilip Cox evict_jiffies = atomic64_read(&pdd->evict_duration_counter);
4054327bed2SPhilip Cox
4064327bed2SPhilip Cox return snprintf(buffer,
4074327bed2SPhilip Cox PAGE_SIZE,
4084327bed2SPhilip Cox "%llu\n",
4094327bed2SPhilip Cox jiffies64_to_msecs(evict_jiffies));
410f2fa07b3SRamesh Errabolu
411f2fa07b3SRamesh Errabolu /* Sysfs handle that gets CU occupancy is per device */
412f2fa07b3SRamesh Errabolu } else if (strcmp(attr->name, "cu_occupancy") == 0) {
413f2fa07b3SRamesh Errabolu return kfd_get_cu_occupancy(attr, buffer);
414f2fa07b3SRamesh Errabolu } else {
4154327bed2SPhilip Cox pr_err("Invalid attribute");
416f2fa07b3SRamesh Errabolu }
4174327bed2SPhilip Cox
4184327bed2SPhilip Cox return 0;
4194327bed2SPhilip Cox }
4206d220a7eSAmber Lin
kfd_sysfs_counters_show(struct kobject * kobj,struct attribute * attr,char * buf)421751580b3SPhilip Yang static ssize_t kfd_sysfs_counters_show(struct kobject *kobj,
422751580b3SPhilip Yang struct attribute *attr, char *buf)
423751580b3SPhilip Yang {
424751580b3SPhilip Yang struct kfd_process_device *pdd;
425751580b3SPhilip Yang
426751580b3SPhilip Yang if (!strcmp(attr->name, "faults")) {
427751580b3SPhilip Yang pdd = container_of(attr, struct kfd_process_device,
428751580b3SPhilip Yang attr_faults);
429751580b3SPhilip Yang return sysfs_emit(buf, "%llu\n", READ_ONCE(pdd->faults));
430751580b3SPhilip Yang }
431751580b3SPhilip Yang if (!strcmp(attr->name, "page_in")) {
432751580b3SPhilip Yang pdd = container_of(attr, struct kfd_process_device,
433751580b3SPhilip Yang attr_page_in);
434751580b3SPhilip Yang return sysfs_emit(buf, "%llu\n", READ_ONCE(pdd->page_in));
435751580b3SPhilip Yang }
436751580b3SPhilip Yang if (!strcmp(attr->name, "page_out")) {
437751580b3SPhilip Yang pdd = container_of(attr, struct kfd_process_device,
438751580b3SPhilip Yang attr_page_out);
439751580b3SPhilip Yang return sysfs_emit(buf, "%llu\n", READ_ONCE(pdd->page_out));
440751580b3SPhilip Yang }
441751580b3SPhilip Yang return 0;
442751580b3SPhilip Yang }
443751580b3SPhilip Yang
4446d220a7eSAmber Lin static struct attribute attr_queue_size = {
4456d220a7eSAmber Lin .name = "size",
4466d220a7eSAmber Lin .mode = KFD_SYSFS_FILE_MODE
4476d220a7eSAmber Lin };
4486d220a7eSAmber Lin
4496d220a7eSAmber Lin static struct attribute attr_queue_type = {
4506d220a7eSAmber Lin .name = "type",
4516d220a7eSAmber Lin .mode = KFD_SYSFS_FILE_MODE
4526d220a7eSAmber Lin };
4536d220a7eSAmber Lin
4546d220a7eSAmber Lin static struct attribute attr_queue_gpuid = {
4556d220a7eSAmber Lin .name = "gpuid",
4566d220a7eSAmber Lin .mode = KFD_SYSFS_FILE_MODE
4576d220a7eSAmber Lin };
4586d220a7eSAmber Lin
4596d220a7eSAmber Lin static struct attribute *procfs_queue_attrs[] = {
4606d220a7eSAmber Lin &attr_queue_size,
4616d220a7eSAmber Lin &attr_queue_type,
4626d220a7eSAmber Lin &attr_queue_gpuid,
4636d220a7eSAmber Lin NULL
4646d220a7eSAmber Lin };
4655fea167eSGreg Kroah-Hartman ATTRIBUTE_GROUPS(procfs_queue);
4666d220a7eSAmber Lin
4676d220a7eSAmber Lin static const struct sysfs_ops procfs_queue_ops = {
4686d220a7eSAmber Lin .show = kfd_procfs_queue_show,
4696d220a7eSAmber Lin };
4706d220a7eSAmber Lin
4714fa01c63SThomas Weißschuh static const struct kobj_type procfs_queue_type = {
4726d220a7eSAmber Lin .sysfs_ops = &procfs_queue_ops,
4735fea167eSGreg Kroah-Hartman .default_groups = procfs_queue_groups,
4746d220a7eSAmber Lin };
4756d220a7eSAmber Lin
4764327bed2SPhilip Cox static const struct sysfs_ops procfs_stats_ops = {
4774327bed2SPhilip Cox .show = kfd_procfs_stats_show,
4784327bed2SPhilip Cox };
4794327bed2SPhilip Cox
4804fa01c63SThomas Weißschuh static const struct kobj_type procfs_stats_type = {
4814327bed2SPhilip Cox .sysfs_ops = &procfs_stats_ops,
482dcdb4d90SPhilip Yang .release = kfd_procfs_kobj_release,
4834327bed2SPhilip Cox };
4844327bed2SPhilip Cox
485751580b3SPhilip Yang static const struct sysfs_ops sysfs_counters_ops = {
486751580b3SPhilip Yang .show = kfd_sysfs_counters_show,
487751580b3SPhilip Yang };
488751580b3SPhilip Yang
4894fa01c63SThomas Weißschuh static const struct kobj_type sysfs_counters_type = {
490751580b3SPhilip Yang .sysfs_ops = &sysfs_counters_ops,
491751580b3SPhilip Yang .release = kfd_procfs_kobj_release,
492751580b3SPhilip Yang };
493751580b3SPhilip Yang
kfd_procfs_add_queue(struct queue * q)4946d220a7eSAmber Lin int kfd_procfs_add_queue(struct queue *q)
4956d220a7eSAmber Lin {
4966d220a7eSAmber Lin struct kfd_process *proc;
4976d220a7eSAmber Lin int ret;
4986d220a7eSAmber Lin
4996d220a7eSAmber Lin if (!q || !q->process)
5006d220a7eSAmber Lin return -EINVAL;
5016d220a7eSAmber Lin proc = q->process;
5026d220a7eSAmber Lin
5036d220a7eSAmber Lin /* Create proc/<pid>/queues/<queue id> folder */
5046d220a7eSAmber Lin if (!proc->kobj_queues)
5056d220a7eSAmber Lin return -EFAULT;
5066d220a7eSAmber Lin ret = kobject_init_and_add(&q->kobj, &procfs_queue_type,
5076d220a7eSAmber Lin proc->kobj_queues, "%u", q->properties.queue_id);
5086d220a7eSAmber Lin if (ret < 0) {
5096d220a7eSAmber Lin pr_warn("Creating proc/<pid>/queues/%u failed",
5106d220a7eSAmber Lin q->properties.queue_id);
5116d220a7eSAmber Lin kobject_put(&q->kobj);
5126d220a7eSAmber Lin return ret;
5136d220a7eSAmber Lin }
5146d220a7eSAmber Lin
5156d220a7eSAmber Lin return 0;
5166d220a7eSAmber Lin }
5176d220a7eSAmber Lin
kfd_sysfs_create_file(struct kobject * kobj,struct attribute * attr,char * name)51875ae84c8SPhilip Yang static void kfd_sysfs_create_file(struct kobject *kobj, struct attribute *attr,
51932cb59f3SMukul Joshi char *name)
52032cb59f3SMukul Joshi {
52175ae84c8SPhilip Yang int ret;
52232cb59f3SMukul Joshi
52375ae84c8SPhilip Yang if (!kobj || !attr || !name)
52475ae84c8SPhilip Yang return;
52532cb59f3SMukul Joshi
52632cb59f3SMukul Joshi attr->name = name;
52732cb59f3SMukul Joshi attr->mode = KFD_SYSFS_FILE_MODE;
52832cb59f3SMukul Joshi sysfs_attr_init(attr);
52932cb59f3SMukul Joshi
53075ae84c8SPhilip Yang ret = sysfs_create_file(kobj, attr);
53175ae84c8SPhilip Yang if (ret)
53275ae84c8SPhilip Yang pr_warn("Create sysfs %s/%s failed %d", kobj->name, name, ret);
53332cb59f3SMukul Joshi }
53432cb59f3SMukul Joshi
kfd_procfs_add_sysfs_stats(struct kfd_process * p)53575ae84c8SPhilip Yang static void kfd_procfs_add_sysfs_stats(struct kfd_process *p)
5364327bed2SPhilip Cox {
53775ae84c8SPhilip Yang int ret;
5386ae27841SAlex Sierra int i;
5394327bed2SPhilip Cox char stats_dir_filename[MAX_SYSFS_FILENAME_LEN];
5404327bed2SPhilip Cox
54175ae84c8SPhilip Yang if (!p || !p->kobj)
54275ae84c8SPhilip Yang return;
5434327bed2SPhilip Cox
5444327bed2SPhilip Cox /*
5454327bed2SPhilip Cox * Create sysfs files for each GPU:
5464327bed2SPhilip Cox * - proc/<pid>/stats_<gpuid>/
5474327bed2SPhilip Cox * - proc/<pid>/stats_<gpuid>/evicted_ms
548f2fa07b3SRamesh Errabolu * - proc/<pid>/stats_<gpuid>/cu_occupancy
5494327bed2SPhilip Cox */
5506ae27841SAlex Sierra for (i = 0; i < p->n_pdds; i++) {
5516ae27841SAlex Sierra struct kfd_process_device *pdd = p->pdds[i];
5524327bed2SPhilip Cox
5534327bed2SPhilip Cox snprintf(stats_dir_filename, MAX_SYSFS_FILENAME_LEN,
5544327bed2SPhilip Cox "stats_%u", pdd->dev->id);
55575ae84c8SPhilip Yang pdd->kobj_stats = kfd_alloc_struct(pdd->kobj_stats);
55675ae84c8SPhilip Yang if (!pdd->kobj_stats)
55775ae84c8SPhilip Yang return;
5584327bed2SPhilip Cox
55975ae84c8SPhilip Yang ret = kobject_init_and_add(pdd->kobj_stats,
5604327bed2SPhilip Cox &procfs_stats_type,
5614327bed2SPhilip Cox p->kobj,
5624327bed2SPhilip Cox stats_dir_filename);
5634327bed2SPhilip Cox
5644327bed2SPhilip Cox if (ret) {
5654327bed2SPhilip Cox pr_warn("Creating KFD proc/stats_%s folder failed",
5664327bed2SPhilip Cox stats_dir_filename);
56775ae84c8SPhilip Yang kobject_put(pdd->kobj_stats);
56875ae84c8SPhilip Yang pdd->kobj_stats = NULL;
56975ae84c8SPhilip Yang return;
5704327bed2SPhilip Cox }
5714327bed2SPhilip Cox
57275ae84c8SPhilip Yang kfd_sysfs_create_file(pdd->kobj_stats, &pdd->attr_evict,
57375ae84c8SPhilip Yang "evicted_ms");
574f2fa07b3SRamesh Errabolu /* Add sysfs file to report compute unit occupancy */
57575ae84c8SPhilip Yang if (pdd->dev->kfd2kgd->get_cu_occupancy)
57675ae84c8SPhilip Yang kfd_sysfs_create_file(pdd->kobj_stats,
57775ae84c8SPhilip Yang &pdd->attr_cu_occupancy,
57875ae84c8SPhilip Yang "cu_occupancy");
579f2fa07b3SRamesh Errabolu }
5804327bed2SPhilip Cox }
5814327bed2SPhilip Cox
kfd_procfs_add_sysfs_counters(struct kfd_process * p)582751580b3SPhilip Yang static void kfd_procfs_add_sysfs_counters(struct kfd_process *p)
583751580b3SPhilip Yang {
584751580b3SPhilip Yang int ret = 0;
585751580b3SPhilip Yang int i;
586751580b3SPhilip Yang char counters_dir_filename[MAX_SYSFS_FILENAME_LEN];
587751580b3SPhilip Yang
588751580b3SPhilip Yang if (!p || !p->kobj)
589751580b3SPhilip Yang return;
590751580b3SPhilip Yang
591751580b3SPhilip Yang /*
592751580b3SPhilip Yang * Create sysfs files for each GPU which supports SVM
593751580b3SPhilip Yang * - proc/<pid>/counters_<gpuid>/
594751580b3SPhilip Yang * - proc/<pid>/counters_<gpuid>/faults
595751580b3SPhilip Yang * - proc/<pid>/counters_<gpuid>/page_in
596751580b3SPhilip Yang * - proc/<pid>/counters_<gpuid>/page_out
597751580b3SPhilip Yang */
598751580b3SPhilip Yang for_each_set_bit(i, p->svms.bitmap_supported, p->n_pdds) {
599751580b3SPhilip Yang struct kfd_process_device *pdd = p->pdds[i];
600751580b3SPhilip Yang struct kobject *kobj_counters;
601751580b3SPhilip Yang
602751580b3SPhilip Yang snprintf(counters_dir_filename, MAX_SYSFS_FILENAME_LEN,
603751580b3SPhilip Yang "counters_%u", pdd->dev->id);
604751580b3SPhilip Yang kobj_counters = kfd_alloc_struct(kobj_counters);
605751580b3SPhilip Yang if (!kobj_counters)
606751580b3SPhilip Yang return;
607751580b3SPhilip Yang
608751580b3SPhilip Yang ret = kobject_init_and_add(kobj_counters, &sysfs_counters_type,
609751580b3SPhilip Yang p->kobj, counters_dir_filename);
610751580b3SPhilip Yang if (ret) {
611751580b3SPhilip Yang pr_warn("Creating KFD proc/%s folder failed",
612751580b3SPhilip Yang counters_dir_filename);
613751580b3SPhilip Yang kobject_put(kobj_counters);
614751580b3SPhilip Yang return;
615751580b3SPhilip Yang }
616751580b3SPhilip Yang
617751580b3SPhilip Yang pdd->kobj_counters = kobj_counters;
618751580b3SPhilip Yang kfd_sysfs_create_file(kobj_counters, &pdd->attr_faults,
619751580b3SPhilip Yang "faults");
620751580b3SPhilip Yang kfd_sysfs_create_file(kobj_counters, &pdd->attr_page_in,
621751580b3SPhilip Yang "page_in");
622751580b3SPhilip Yang kfd_sysfs_create_file(kobj_counters, &pdd->attr_page_out,
623751580b3SPhilip Yang "page_out");
624751580b3SPhilip Yang }
625751580b3SPhilip Yang }
6264327bed2SPhilip Cox
kfd_procfs_add_sysfs_files(struct kfd_process * p)62775ae84c8SPhilip Yang static void kfd_procfs_add_sysfs_files(struct kfd_process *p)
628d4566deeSMukul Joshi {
6296ae27841SAlex Sierra int i;
630d4566deeSMukul Joshi
63175ae84c8SPhilip Yang if (!p || !p->kobj)
63275ae84c8SPhilip Yang return;
633d4566deeSMukul Joshi
63432cb59f3SMukul Joshi /*
63532cb59f3SMukul Joshi * Create sysfs files for each GPU:
63632cb59f3SMukul Joshi * - proc/<pid>/vram_<gpuid>
63732cb59f3SMukul Joshi * - proc/<pid>/sdma_<gpuid>
63832cb59f3SMukul Joshi */
6396ae27841SAlex Sierra for (i = 0; i < p->n_pdds; i++) {
6406ae27841SAlex Sierra struct kfd_process_device *pdd = p->pdds[i];
6416ae27841SAlex Sierra
64232cb59f3SMukul Joshi snprintf(pdd->vram_filename, MAX_SYSFS_FILENAME_LEN, "vram_%u",
643d4566deeSMukul Joshi pdd->dev->id);
64475ae84c8SPhilip Yang kfd_sysfs_create_file(p->kobj, &pdd->attr_vram,
64575ae84c8SPhilip Yang pdd->vram_filename);
64632cb59f3SMukul Joshi
64732cb59f3SMukul Joshi snprintf(pdd->sdma_filename, MAX_SYSFS_FILENAME_LEN, "sdma_%u",
64832cb59f3SMukul Joshi pdd->dev->id);
64975ae84c8SPhilip Yang kfd_sysfs_create_file(p->kobj, &pdd->attr_sdma,
65075ae84c8SPhilip Yang pdd->sdma_filename);
651d4566deeSMukul Joshi }
652d4566deeSMukul Joshi }
653d4566deeSMukul Joshi
kfd_procfs_del_queue(struct queue * q)6546d220a7eSAmber Lin void kfd_procfs_del_queue(struct queue *q)
6556d220a7eSAmber Lin {
6566d220a7eSAmber Lin if (!q)
6576d220a7eSAmber Lin return;
6586d220a7eSAmber Lin
6596d220a7eSAmber Lin kobject_del(&q->kobj);
6606d220a7eSAmber Lin kobject_put(&q->kobj);
6616d220a7eSAmber Lin }
6626d220a7eSAmber Lin
kfd_process_create_wq(void)6631679ae8fSFelix Kuehling int kfd_process_create_wq(void)
66419f6d2a6SOded Gabbay {
66519f6d2a6SOded Gabbay if (!kfd_process_wq)
666fd320bf6SBhaktipriya Shridhar kfd_process_wq = alloc_workqueue("kfd_process_wq", 0, 0);
6671679ae8fSFelix Kuehling if (!kfd_restore_wq)
6681679ae8fSFelix Kuehling kfd_restore_wq = alloc_ordered_workqueue("kfd_restore_wq", 0);
6691679ae8fSFelix Kuehling
6701679ae8fSFelix Kuehling if (!kfd_process_wq || !kfd_restore_wq) {
6711679ae8fSFelix Kuehling kfd_process_destroy_wq();
6721679ae8fSFelix Kuehling return -ENOMEM;
6731679ae8fSFelix Kuehling }
6741679ae8fSFelix Kuehling
6751679ae8fSFelix Kuehling return 0;
67619f6d2a6SOded Gabbay }
67719f6d2a6SOded Gabbay
kfd_process_destroy_wq(void)67819f6d2a6SOded Gabbay void kfd_process_destroy_wq(void)
67919f6d2a6SOded Gabbay {
68019f6d2a6SOded Gabbay if (kfd_process_wq) {
68119f6d2a6SOded Gabbay destroy_workqueue(kfd_process_wq);
68219f6d2a6SOded Gabbay kfd_process_wq = NULL;
68319f6d2a6SOded Gabbay }
6841679ae8fSFelix Kuehling if (kfd_restore_wq) {
6851679ae8fSFelix Kuehling destroy_workqueue(kfd_restore_wq);
6861679ae8fSFelix Kuehling kfd_restore_wq = NULL;
6871679ae8fSFelix Kuehling }
68819f6d2a6SOded Gabbay }
68919f6d2a6SOded Gabbay
kfd_process_free_gpuvm(struct kgd_mem * mem,struct kfd_process_device * pdd,void ** kptr)690f35751b8SFelix Kuehling static void kfd_process_free_gpuvm(struct kgd_mem *mem,
691cb8dc232SPhilip Yang struct kfd_process_device *pdd, void **kptr)
692f35751b8SFelix Kuehling {
6938dc1db31SMukul Joshi struct kfd_node *dev = pdd->dev;
694f35751b8SFelix Kuehling
695cb8dc232SPhilip Yang if (kptr && *kptr) {
6964e2d1044SFelix Kuehling amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(mem);
697cb8dc232SPhilip Yang *kptr = NULL;
69868df0f19SLang Yu }
69968df0f19SLang Yu
700dff63da9SGraham Sider amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(dev->adev, mem, pdd->drm_priv);
701dff63da9SGraham Sider amdgpu_amdkfd_gpuvm_free_memory_of_gpu(dev->adev, mem, pdd->drm_priv,
702d4ec4bdcSFelix Kuehling NULL);
703f35751b8SFelix Kuehling }
704f35751b8SFelix Kuehling
705f35751b8SFelix Kuehling /* kfd_process_alloc_gpuvm - Allocate GPU VM for the KFD process
706f35751b8SFelix Kuehling * This function should be only called right after the process
707f35751b8SFelix Kuehling * is created and when kfd_processes_mutex is still being held
708f35751b8SFelix Kuehling * to avoid concurrency. Because of that exclusiveness, we do
709f35751b8SFelix Kuehling * not need to take p->mutex.
710f35751b8SFelix Kuehling */
kfd_process_alloc_gpuvm(struct kfd_process_device * pdd,uint64_t gpu_va,uint32_t size,uint32_t flags,struct kgd_mem ** mem,void ** kptr)711f35751b8SFelix Kuehling static int kfd_process_alloc_gpuvm(struct kfd_process_device *pdd,
712f35751b8SFelix Kuehling uint64_t gpu_va, uint32_t size,
71368df0f19SLang Yu uint32_t flags, struct kgd_mem **mem, void **kptr)
714f35751b8SFelix Kuehling {
7158dc1db31SMukul Joshi struct kfd_node *kdev = pdd->dev;
716f35751b8SFelix Kuehling int err;
717f35751b8SFelix Kuehling
718dff63da9SGraham Sider err = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(kdev->adev, gpu_va, size,
719011bbb03SRajneesh Bhardwaj pdd->drm_priv, mem, NULL,
720011bbb03SRajneesh Bhardwaj flags, false);
721f35751b8SFelix Kuehling if (err)
722f35751b8SFelix Kuehling goto err_alloc_mem;
723f35751b8SFelix Kuehling
724dff63da9SGraham Sider err = amdgpu_amdkfd_gpuvm_map_memory_to_gpu(kdev->adev, *mem,
7254d30a83cSChristian König pdd->drm_priv);
726f35751b8SFelix Kuehling if (err)
727f35751b8SFelix Kuehling goto err_map_mem;
728f35751b8SFelix Kuehling
729dff63da9SGraham Sider err = amdgpu_amdkfd_gpuvm_sync_memory(kdev->adev, *mem, true);
730f35751b8SFelix Kuehling if (err) {
731f35751b8SFelix Kuehling pr_debug("Sync memory failed, wait interrupted by user signal\n");
732f35751b8SFelix Kuehling goto sync_memory_failed;
733f35751b8SFelix Kuehling }
734f35751b8SFelix Kuehling
735f35751b8SFelix Kuehling if (kptr) {
7364e2d1044SFelix Kuehling err = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(
73768df0f19SLang Yu (struct kgd_mem *)*mem, kptr, NULL);
738f35751b8SFelix Kuehling if (err) {
739f35751b8SFelix Kuehling pr_debug("Map GTT BO to kernel failed\n");
74068df0f19SLang Yu goto sync_memory_failed;
741f35751b8SFelix Kuehling }
742f35751b8SFelix Kuehling }
743f35751b8SFelix Kuehling
744f35751b8SFelix Kuehling return err;
745f35751b8SFelix Kuehling
746f35751b8SFelix Kuehling sync_memory_failed:
747dff63da9SGraham Sider amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(kdev->adev, *mem, pdd->drm_priv);
748f35751b8SFelix Kuehling
749f35751b8SFelix Kuehling err_map_mem:
750dff63da9SGraham Sider amdgpu_amdkfd_gpuvm_free_memory_of_gpu(kdev->adev, *mem, pdd->drm_priv,
751d4ec4bdcSFelix Kuehling NULL);
752f35751b8SFelix Kuehling err_alloc_mem:
75368df0f19SLang Yu *mem = NULL;
754f35751b8SFelix Kuehling *kptr = NULL;
755f35751b8SFelix Kuehling return err;
756f35751b8SFelix Kuehling }
757f35751b8SFelix Kuehling
758552764b6SFelix Kuehling /* kfd_process_device_reserve_ib_mem - Reserve memory inside the
759552764b6SFelix Kuehling * process for IB usage The memory reserved is for KFD to submit
760552764b6SFelix Kuehling * IB to AMDGPU from kernel. If the memory is reserved
761552764b6SFelix Kuehling * successfully, ib_kaddr will have the CPU/kernel
762552764b6SFelix Kuehling * address. Check ib_kaddr before accessing the memory.
763552764b6SFelix Kuehling */
kfd_process_device_reserve_ib_mem(struct kfd_process_device * pdd)764552764b6SFelix Kuehling static int kfd_process_device_reserve_ib_mem(struct kfd_process_device *pdd)
765552764b6SFelix Kuehling {
766552764b6SFelix Kuehling struct qcm_process_device *qpd = &pdd->qpd;
7671d251d90SYong Zhao uint32_t flags = KFD_IOC_ALLOC_MEM_FLAGS_GTT |
7681d251d90SYong Zhao KFD_IOC_ALLOC_MEM_FLAGS_NO_SUBSTITUTE |
7691d251d90SYong Zhao KFD_IOC_ALLOC_MEM_FLAGS_WRITABLE |
7701d251d90SYong Zhao KFD_IOC_ALLOC_MEM_FLAGS_EXECUTABLE;
77168df0f19SLang Yu struct kgd_mem *mem;
772552764b6SFelix Kuehling void *kaddr;
773552764b6SFelix Kuehling int ret;
774552764b6SFelix Kuehling
775552764b6SFelix Kuehling if (qpd->ib_kaddr || !qpd->ib_base)
776552764b6SFelix Kuehling return 0;
777552764b6SFelix Kuehling
778552764b6SFelix Kuehling /* ib_base is only set for dGPU */
779552764b6SFelix Kuehling ret = kfd_process_alloc_gpuvm(pdd, qpd->ib_base, PAGE_SIZE, flags,
78068df0f19SLang Yu &mem, &kaddr);
781552764b6SFelix Kuehling if (ret)
782552764b6SFelix Kuehling return ret;
783552764b6SFelix Kuehling
78468df0f19SLang Yu qpd->ib_mem = mem;
785552764b6SFelix Kuehling qpd->ib_kaddr = kaddr;
786552764b6SFelix Kuehling
787552764b6SFelix Kuehling return 0;
788552764b6SFelix Kuehling }
789552764b6SFelix Kuehling
kfd_process_device_destroy_ib_mem(struct kfd_process_device * pdd)79068df0f19SLang Yu static void kfd_process_device_destroy_ib_mem(struct kfd_process_device *pdd)
79168df0f19SLang Yu {
79268df0f19SLang Yu struct qcm_process_device *qpd = &pdd->qpd;
79368df0f19SLang Yu
79468df0f19SLang Yu if (!qpd->ib_kaddr || !qpd->ib_base)
79568df0f19SLang Yu return;
79668df0f19SLang Yu
797cb8dc232SPhilip Yang kfd_process_free_gpuvm(qpd->ib_mem, pdd, &qpd->ib_kaddr);
79868df0f19SLang Yu }
79968df0f19SLang Yu
kfd_create_process(struct task_struct * thread)8000ab2d753SJonathan Kim struct kfd_process *kfd_create_process(struct task_struct *thread)
80119f6d2a6SOded Gabbay {
80219f6d2a6SOded Gabbay struct kfd_process *process;
803de9f26bbSKent Russell int ret;
80419f6d2a6SOded Gabbay
8050ab2d753SJonathan Kim if (!(thread->mm && mmget_not_zero(thread->mm)))
80619f6d2a6SOded Gabbay return ERR_PTR(-EINVAL);
80719f6d2a6SOded Gabbay
80819f6d2a6SOded Gabbay /* Only the pthreads threading model is supported. */
8090ab2d753SJonathan Kim if (thread->group_leader->mm != thread->mm) {
8100ab2d753SJonathan Kim mmput(thread->mm);
81119f6d2a6SOded Gabbay return ERR_PTR(-EINVAL);
8120ab2d753SJonathan Kim }
81319f6d2a6SOded Gabbay
81419f6d2a6SOded Gabbay /*
81519f6d2a6SOded Gabbay * take kfd processes mutex before starting of process creation
81619f6d2a6SOded Gabbay * so there won't be a case where two threads of the same process
81719f6d2a6SOded Gabbay * create two kfd_process structures
81819f6d2a6SOded Gabbay */
81919f6d2a6SOded Gabbay mutex_lock(&kfd_processes_mutex);
82019f6d2a6SOded Gabbay
821fe1f05dfSMukul Joshi if (kfd_is_locked()) {
822fe1f05dfSMukul Joshi pr_debug("KFD is locked! Cannot create process");
823aa02d433SFelix Kuehling process = ERR_PTR(-EINVAL);
824aa02d433SFelix Kuehling goto out;
825fe1f05dfSMukul Joshi }
826fe1f05dfSMukul Joshi
82719f6d2a6SOded Gabbay /* A prior open of /dev/kfd could have already created the process. */
828011bbb03SRajneesh Bhardwaj process = find_process(thread, false);
829de9f26bbSKent Russell if (process) {
83079775b62SKent Russell pr_debug("Process already found\n");
831de9f26bbSKent Russell } else {
8326c49ba40SLancelot SIX /* If the process just called exec(3), it is possible that the
8336c49ba40SLancelot SIX * cleanup of the kfd_process (following the release of the mm
8346c49ba40SLancelot SIX * of the old process image) is still in the cleanup work queue.
8356c49ba40SLancelot SIX * Make sure to drain any job before trying to recreate any
8366c49ba40SLancelot SIX * resource for this process.
8376c49ba40SLancelot SIX */
8386c49ba40SLancelot SIX flush_workqueue(kfd_process_wq);
8396c49ba40SLancelot SIX
8400029cab3SJason Gunthorpe process = create_process(thread);
8410029cab3SJason Gunthorpe if (IS_ERR(process))
8420029cab3SJason Gunthorpe goto out;
8430029cab3SJason Gunthorpe
844de9f26bbSKent Russell if (!procfs.kobj)
845de9f26bbSKent Russell goto out;
846de9f26bbSKent Russell
847de9f26bbSKent Russell process->kobj = kfd_alloc_struct(process->kobj);
848de9f26bbSKent Russell if (!process->kobj) {
849de9f26bbSKent Russell pr_warn("Creating procfs kobject failed");
850de9f26bbSKent Russell goto out;
851de9f26bbSKent Russell }
852de9f26bbSKent Russell ret = kobject_init_and_add(process->kobj, &procfs_type,
853de9f26bbSKent Russell procfs.kobj, "%d",
854de9f26bbSKent Russell (int)process->lead_thread->pid);
855de9f26bbSKent Russell if (ret) {
856de9f26bbSKent Russell pr_warn("Creating procfs pid directory failed");
857dc2f832eSBernard Zhao kobject_put(process->kobj);
858de9f26bbSKent Russell goto out;
859de9f26bbSKent Russell }
860de9f26bbSKent Russell
86175ae84c8SPhilip Yang kfd_sysfs_create_file(process->kobj, &process->attr_pasid,
86275ae84c8SPhilip Yang "pasid");
8636d220a7eSAmber Lin
8646d220a7eSAmber Lin process->kobj_queues = kobject_create_and_add("queues",
8656d220a7eSAmber Lin process->kobj);
8666d220a7eSAmber Lin if (!process->kobj_queues)
8676d220a7eSAmber Lin pr_warn("Creating KFD proc/queues folder failed");
868d4566deeSMukul Joshi
86975ae84c8SPhilip Yang kfd_procfs_add_sysfs_stats(process);
87075ae84c8SPhilip Yang kfd_procfs_add_sysfs_files(process);
871751580b3SPhilip Yang kfd_procfs_add_sysfs_counters(process);
87212fb1ad7SJonathan Kim
87312fb1ad7SJonathan Kim init_waitqueue_head(&process->wait_irq_drain);
874de9f26bbSKent Russell }
875de9f26bbSKent Russell out:
8760f899fd4SFelix Kuehling if (!IS_ERR(process))
8770f899fd4SFelix Kuehling kref_get(&process->ref);
87819f6d2a6SOded Gabbay mutex_unlock(&kfd_processes_mutex);
8790ab2d753SJonathan Kim mmput(thread->mm);
88019f6d2a6SOded Gabbay
88119f6d2a6SOded Gabbay return process;
88219f6d2a6SOded Gabbay }
88319f6d2a6SOded Gabbay
kfd_get_process(const struct task_struct * thread)88419f6d2a6SOded Gabbay struct kfd_process *kfd_get_process(const struct task_struct *thread)
88519f6d2a6SOded Gabbay {
88619f6d2a6SOded Gabbay struct kfd_process *process;
88719f6d2a6SOded Gabbay
8884eacc26bSKent Russell if (!thread->mm)
88919f6d2a6SOded Gabbay return ERR_PTR(-EINVAL);
89019f6d2a6SOded Gabbay
89119f6d2a6SOded Gabbay /* Only the pthreads threading model is supported. */
89219f6d2a6SOded Gabbay if (thread->group_leader->mm != thread->mm)
89319f6d2a6SOded Gabbay return ERR_PTR(-EINVAL);
89419f6d2a6SOded Gabbay
895011bbb03SRajneesh Bhardwaj process = find_process(thread, false);
896e47cb828SWei Lu if (!process)
897e47cb828SWei Lu return ERR_PTR(-EINVAL);
89819f6d2a6SOded Gabbay
89919f6d2a6SOded Gabbay return process;
90019f6d2a6SOded Gabbay }
90119f6d2a6SOded Gabbay
find_process_by_mm(const struct mm_struct * mm)90219f6d2a6SOded Gabbay static struct kfd_process *find_process_by_mm(const struct mm_struct *mm)
90319f6d2a6SOded Gabbay {
90419f6d2a6SOded Gabbay struct kfd_process *process;
90519f6d2a6SOded Gabbay
90619f6d2a6SOded Gabbay hash_for_each_possible_rcu(kfd_processes_table, process,
90719f6d2a6SOded Gabbay kfd_processes, (uintptr_t)mm)
90819f6d2a6SOded Gabbay if (process->mm == mm)
90919f6d2a6SOded Gabbay return process;
91019f6d2a6SOded Gabbay
91119f6d2a6SOded Gabbay return NULL;
91219f6d2a6SOded Gabbay }
91319f6d2a6SOded Gabbay
find_process(const struct task_struct * thread,bool ref)914011bbb03SRajneesh Bhardwaj static struct kfd_process *find_process(const struct task_struct *thread,
915011bbb03SRajneesh Bhardwaj bool ref)
91619f6d2a6SOded Gabbay {
91719f6d2a6SOded Gabbay struct kfd_process *p;
91819f6d2a6SOded Gabbay int idx;
91919f6d2a6SOded Gabbay
92019f6d2a6SOded Gabbay idx = srcu_read_lock(&kfd_processes_srcu);
92119f6d2a6SOded Gabbay p = find_process_by_mm(thread->mm);
922011bbb03SRajneesh Bhardwaj if (p && ref)
923011bbb03SRajneesh Bhardwaj kref_get(&p->ref);
92419f6d2a6SOded Gabbay srcu_read_unlock(&kfd_processes_srcu, idx);
92519f6d2a6SOded Gabbay
92619f6d2a6SOded Gabbay return p;
92719f6d2a6SOded Gabbay }
92819f6d2a6SOded Gabbay
kfd_unref_process(struct kfd_process * p)929abb208a8SFelix Kuehling void kfd_unref_process(struct kfd_process *p)
930abb208a8SFelix Kuehling {
931abb208a8SFelix Kuehling kref_put(&p->ref, kfd_process_ref_release);
932abb208a8SFelix Kuehling }
933abb208a8SFelix Kuehling
934011bbb03SRajneesh Bhardwaj /* This increments the process->ref counter. */
kfd_lookup_process_by_pid(struct pid * pid)935011bbb03SRajneesh Bhardwaj struct kfd_process *kfd_lookup_process_by_pid(struct pid *pid)
936011bbb03SRajneesh Bhardwaj {
937011bbb03SRajneesh Bhardwaj struct task_struct *task = NULL;
938011bbb03SRajneesh Bhardwaj struct kfd_process *p = NULL;
939011bbb03SRajneesh Bhardwaj
940011bbb03SRajneesh Bhardwaj if (!pid) {
941011bbb03SRajneesh Bhardwaj task = current;
942011bbb03SRajneesh Bhardwaj get_task_struct(task);
943011bbb03SRajneesh Bhardwaj } else {
944011bbb03SRajneesh Bhardwaj task = get_pid_task(pid, PIDTYPE_PID);
945011bbb03SRajneesh Bhardwaj }
946011bbb03SRajneesh Bhardwaj
947011bbb03SRajneesh Bhardwaj if (task) {
948011bbb03SRajneesh Bhardwaj p = find_process(task, true);
949011bbb03SRajneesh Bhardwaj put_task_struct(task);
950011bbb03SRajneesh Bhardwaj }
951011bbb03SRajneesh Bhardwaj
952011bbb03SRajneesh Bhardwaj return p;
953011bbb03SRajneesh Bhardwaj }
9546ae27841SAlex Sierra
kfd_process_device_free_bos(struct kfd_process_device * pdd)95552b29d73SFelix Kuehling static void kfd_process_device_free_bos(struct kfd_process_device *pdd)
95652b29d73SFelix Kuehling {
95752b29d73SFelix Kuehling struct kfd_process *p = pdd->process;
95852b29d73SFelix Kuehling void *mem;
95952b29d73SFelix Kuehling int id;
9606ae27841SAlex Sierra int i;
96152b29d73SFelix Kuehling
96252b29d73SFelix Kuehling /*
96352b29d73SFelix Kuehling * Remove all handles from idr and release appropriate
96452b29d73SFelix Kuehling * local memory object
96552b29d73SFelix Kuehling */
96652b29d73SFelix Kuehling idr_for_each_entry(&pdd->alloc_idr, mem, id) {
96752b29d73SFelix Kuehling
9686ae27841SAlex Sierra for (i = 0; i < p->n_pdds; i++) {
9696ae27841SAlex Sierra struct kfd_process_device *peer_pdd = p->pdds[i];
9706ae27841SAlex Sierra
971b40a6ab2SFelix Kuehling if (!peer_pdd->drm_priv)
97252b29d73SFelix Kuehling continue;
9735b87245fSAmber Lin amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(
974dff63da9SGraham Sider peer_pdd->dev->adev, mem, peer_pdd->drm_priv);
97552b29d73SFelix Kuehling }
97652b29d73SFelix Kuehling
977dff63da9SGraham Sider amdgpu_amdkfd_gpuvm_free_memory_of_gpu(pdd->dev->adev, mem,
978d4ec4bdcSFelix Kuehling pdd->drm_priv, NULL);
97952b29d73SFelix Kuehling kfd_process_device_remove_obj_handle(pdd, id);
98052b29d73SFelix Kuehling }
98152b29d73SFelix Kuehling }
98252b29d73SFelix Kuehling
98368df0f19SLang Yu /*
98468df0f19SLang Yu * Just kunmap and unpin signal BO here. It will be freed in
98568df0f19SLang Yu * kfd_process_free_outstanding_kfd_bos()
98668df0f19SLang Yu */
kfd_process_kunmap_signal_bo(struct kfd_process * p)98768df0f19SLang Yu static void kfd_process_kunmap_signal_bo(struct kfd_process *p)
98868df0f19SLang Yu {
98968df0f19SLang Yu struct kfd_process_device *pdd;
9908dc1db31SMukul Joshi struct kfd_node *kdev;
99168df0f19SLang Yu void *mem;
99268df0f19SLang Yu
99368df0f19SLang Yu kdev = kfd_device_by_id(GET_GPU_ID(p->signal_handle));
99468df0f19SLang Yu if (!kdev)
99568df0f19SLang Yu return;
99668df0f19SLang Yu
99768df0f19SLang Yu mutex_lock(&p->mutex);
99868df0f19SLang Yu
99968df0f19SLang Yu pdd = kfd_get_process_device_data(kdev, p);
100068df0f19SLang Yu if (!pdd)
100168df0f19SLang Yu goto out;
100268df0f19SLang Yu
100368df0f19SLang Yu mem = kfd_process_device_translate_handle(
100468df0f19SLang Yu pdd, GET_IDR_HANDLE(p->signal_handle));
100568df0f19SLang Yu if (!mem)
100668df0f19SLang Yu goto out;
100768df0f19SLang Yu
10084e2d1044SFelix Kuehling amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(mem);
100968df0f19SLang Yu
101068df0f19SLang Yu out:
101168df0f19SLang Yu mutex_unlock(&p->mutex);
101268df0f19SLang Yu }
101368df0f19SLang Yu
kfd_process_free_outstanding_kfd_bos(struct kfd_process * p)101452b29d73SFelix Kuehling static void kfd_process_free_outstanding_kfd_bos(struct kfd_process *p)
101552b29d73SFelix Kuehling {
10166ae27841SAlex Sierra int i;
101752b29d73SFelix Kuehling
10186ae27841SAlex Sierra for (i = 0; i < p->n_pdds; i++)
10196ae27841SAlex Sierra kfd_process_device_free_bos(p->pdds[i]);
102052b29d73SFelix Kuehling }
102152b29d73SFelix Kuehling
kfd_process_destroy_pdds(struct kfd_process * p)1022de1450a5SFelix Kuehling static void kfd_process_destroy_pdds(struct kfd_process *p)
102319f6d2a6SOded Gabbay {
10246ae27841SAlex Sierra int i;
102519f6d2a6SOded Gabbay
10266ae27841SAlex Sierra for (i = 0; i < p->n_pdds; i++) {
10276ae27841SAlex Sierra struct kfd_process_device *pdd = p->pdds[i];
10286ae27841SAlex Sierra
10296027b1bfSYong Zhao pr_debug("Releasing pdd (topology id %d) for process (pasid 0x%x)\n",
103094a1ee09SOded Gabbay pdd->dev->id, p->pasid);
103194a1ee09SOded Gabbay
103268df0f19SLang Yu kfd_process_device_destroy_cwsr_dgpu(pdd);
103368df0f19SLang Yu kfd_process_device_destroy_ib_mem(pdd);
103468df0f19SLang Yu
1035bf47afbaSOak Zeng if (pdd->drm_file) {
10365b87245fSAmber Lin amdgpu_amdkfd_gpuvm_release_process_vm(
1037dff63da9SGraham Sider pdd->dev->adev, pdd->drm_priv);
1038b84394e2SFelix Kuehling fput(pdd->drm_file);
1039bf47afbaSOak Zeng }
1040403575c4SFelix Kuehling
1041f35751b8SFelix Kuehling if (pdd->qpd.cwsr_kaddr && !pdd->qpd.cwsr_base)
1042373d7080SFelix Kuehling free_pages((unsigned long)pdd->qpd.cwsr_kaddr,
1043373d7080SFelix Kuehling get_order(KFD_CWSR_TBA_TMA_SIZE));
1044373d7080SFelix Kuehling
104552b29d73SFelix Kuehling idr_destroy(&pdd->alloc_idr);
104652b29d73SFelix Kuehling
10472105a15aSShashank Sharma kfd_free_process_doorbells(pdd->dev->kfd, pdd);
104859d7115dSMukul Joshi
1049*60b57dc7SJesse.zhang@amd.com if (pdd->dev->kfd->shared_resources.enable_mes &&
1050*60b57dc7SJesse.zhang@amd.com pdd->proc_ctx_cpu_ptr)
1051cc009e61SMukul Joshi amdgpu_amdkfd_free_gtt_mem(pdd->dev->adev,
105230ceb873SPhilip Yang &pdd->proc_ctx_bo);
10539593f4d6SRajneesh Bhardwaj /*
10549593f4d6SRajneesh Bhardwaj * before destroying pdd, make sure to report availability
10559593f4d6SRajneesh Bhardwaj * for auto suspend
10569593f4d6SRajneesh Bhardwaj */
10579593f4d6SRajneesh Bhardwaj if (pdd->runtime_inuse) {
1058d69a3b76SMukul Joshi pm_runtime_mark_last_busy(adev_to_drm(pdd->dev->adev)->dev);
1059d69a3b76SMukul Joshi pm_runtime_put_autosuspend(adev_to_drm(pdd->dev->adev)->dev);
10609593f4d6SRajneesh Bhardwaj pdd->runtime_inuse = false;
10619593f4d6SRajneesh Bhardwaj }
10629593f4d6SRajneesh Bhardwaj
106319f6d2a6SOded Gabbay kfree(pdd);
10646ae27841SAlex Sierra p->pdds[i] = NULL;
106519f6d2a6SOded Gabbay }
10666ae27841SAlex Sierra p->n_pdds = 0;
1067de1450a5SFelix Kuehling }
kfd_process_remove_sysfs(struct kfd_process * p)1068de1450a5SFelix Kuehling
1069751580b3SPhilip Yang static void kfd_process_remove_sysfs(struct kfd_process *p)
1070de1450a5SFelix Kuehling {
1071751580b3SPhilip Yang struct kfd_process_device *pdd;
10726ae27841SAlex Sierra int i;
1073de1450a5SFelix Kuehling
1074751580b3SPhilip Yang if (!p->kobj)
1075751580b3SPhilip Yang return;
1076751580b3SPhilip Yang
1077de9f26bbSKent Russell sysfs_remove_file(p->kobj, &p->attr_pasid);
10786d220a7eSAmber Lin kobject_del(p->kobj_queues);
10796d220a7eSAmber Lin kobject_put(p->kobj_queues);
10806d220a7eSAmber Lin p->kobj_queues = NULL;
1081d4566deeSMukul Joshi
10826ae27841SAlex Sierra for (i = 0; i < p->n_pdds; i++) {
1083751580b3SPhilip Yang pdd = p->pdds[i];
10846ae27841SAlex Sierra
1085d4566deeSMukul Joshi sysfs_remove_file(p->kobj, &pdd->attr_vram);
108632cb59f3SMukul Joshi sysfs_remove_file(p->kobj, &pdd->attr_sdma);
1087dcdb4d90SPhilip Yang
1088dcdb4d90SPhilip Yang sysfs_remove_file(pdd->kobj_stats, &pdd->attr_evict);
1089dcdb4d90SPhilip Yang if (pdd->dev->kfd2kgd->get_cu_occupancy)
1090dcdb4d90SPhilip Yang sysfs_remove_file(pdd->kobj_stats,
1091dcdb4d90SPhilip Yang &pdd->attr_cu_occupancy);
10924327bed2SPhilip Cox kobject_del(pdd->kobj_stats);
10934327bed2SPhilip Cox kobject_put(pdd->kobj_stats);
10944327bed2SPhilip Cox pdd->kobj_stats = NULL;
109532cb59f3SMukul Joshi }
1096d4566deeSMukul Joshi
1097751580b3SPhilip Yang for_each_set_bit(i, p->svms.bitmap_supported, p->n_pdds) {
1098751580b3SPhilip Yang pdd = p->pdds[i];
1099751580b3SPhilip Yang
1100751580b3SPhilip Yang sysfs_remove_file(pdd->kobj_counters, &pdd->attr_faults);
1101751580b3SPhilip Yang sysfs_remove_file(pdd->kobj_counters, &pdd->attr_page_in);
1102751580b3SPhilip Yang sysfs_remove_file(pdd->kobj_counters, &pdd->attr_page_out);
1103751580b3SPhilip Yang kobject_del(pdd->kobj_counters);
1104751580b3SPhilip Yang kobject_put(pdd->kobj_counters);
1105751580b3SPhilip Yang pdd->kobj_counters = NULL;
1106751580b3SPhilip Yang }
1107751580b3SPhilip Yang
1108de9f26bbSKent Russell kobject_del(p->kobj);
1109de9f26bbSKent Russell kobject_put(p->kobj);
1110de9f26bbSKent Russell p->kobj = NULL;
1111de9f26bbSKent Russell }
1112de9f26bbSKent Russell
1113751580b3SPhilip Yang /* No process locking is needed in this function, because the process
1114751580b3SPhilip Yang * is not findable any more. We must assume that no other thread is
1115751580b3SPhilip Yang * using it any more, otherwise we couldn't safely free the process
1116751580b3SPhilip Yang * structure in the end.
kfd_process_wq_release(struct work_struct * work)1117751580b3SPhilip Yang */
1118751580b3SPhilip Yang static void kfd_process_wq_release(struct work_struct *work)
1119751580b3SPhilip Yang {
1120751580b3SPhilip Yang struct kfd_process *p = container_of(work, struct kfd_process,
1121751580b3SPhilip Yang release_work);
112268df0f19SLang Yu
112374097f9fSPhilip Yang kfd_process_dequeue_from_all_devices(p);
112474097f9fSPhilip Yang pqm_uninit(&p->pqm);
112574097f9fSPhilip Yang
112674097f9fSPhilip Yang /* Signal the eviction fence after user mode queues are
112774097f9fSPhilip Yang * destroyed. This allows any BOs to be freed without
112874097f9fSPhilip Yang * triggering pointless evictions or waiting for fences.
112974097f9fSPhilip Yang */
113074097f9fSPhilip Yang dma_fence_signal(p->ef);
113174097f9fSPhilip Yang
1132751580b3SPhilip Yang kfd_process_remove_sysfs(p);
1133de1450a5SFelix Kuehling
113468df0f19SLang Yu kfd_process_kunmap_signal_bo(p);
113552b29d73SFelix Kuehling kfd_process_free_outstanding_kfd_bos(p);
113642de677fSPhilip Yang svm_range_list_fini(p);
113752b29d73SFelix Kuehling
1138de1450a5SFelix Kuehling kfd_process_destroy_pdds(p);
1139403575c4SFelix Kuehling dma_fence_put(p->ef);
114019f6d2a6SOded Gabbay
1141f3a39818SAndrew Lewycky kfd_event_free_process(p);
1142f3a39818SAndrew Lewycky
114319f6d2a6SOded Gabbay kfd_pasid_free(p->pasid);
114419f6d2a6SOded Gabbay mutex_destroy(&p->mutex);
114519f6d2a6SOded Gabbay
1146c7b1243eSFelix Kuehling put_task_struct(p->lead_thread);
1147c7b1243eSFelix Kuehling
114819f6d2a6SOded Gabbay kfree(p);
11495ce10687SFelix Kuehling }
kfd_process_ref_release(struct kref * ref)115019f6d2a6SOded Gabbay
11515ce10687SFelix Kuehling static void kfd_process_ref_release(struct kref *ref)
11525ce10687SFelix Kuehling {
11535ce10687SFelix Kuehling struct kfd_process *p = container_of(ref, struct kfd_process, ref);
11545ce10687SFelix Kuehling
11555ce10687SFelix Kuehling INIT_WORK(&p->release_work, kfd_process_wq_release);
11565ce10687SFelix Kuehling queue_work(kfd_process_wq, &p->release_work);
115719f6d2a6SOded Gabbay }
kfd_process_alloc_notifier(struct mm_struct * mm)115819f6d2a6SOded Gabbay
11593248b6d3SFelix Kuehling static struct mmu_notifier *kfd_process_alloc_notifier(struct mm_struct *mm)
11603248b6d3SFelix Kuehling {
11613248b6d3SFelix Kuehling int idx = srcu_read_lock(&kfd_processes_srcu);
11623248b6d3SFelix Kuehling struct kfd_process *p = find_process_by_mm(mm);
11633248b6d3SFelix Kuehling
11643248b6d3SFelix Kuehling srcu_read_unlock(&kfd_processes_srcu, idx);
11653248b6d3SFelix Kuehling
11663248b6d3SFelix Kuehling return p ? &p->mmu_notifier : ERR_PTR(-ESRCH);
11673248b6d3SFelix Kuehling }
kfd_process_free_notifier(struct mmu_notifier * mn)11683248b6d3SFelix Kuehling
1169471f3902SJason Gunthorpe static void kfd_process_free_notifier(struct mmu_notifier *mn)
117019f6d2a6SOded Gabbay {
1171471f3902SJason Gunthorpe kfd_unref_process(container_of(mn, struct kfd_process, mmu_notifier));
117219f6d2a6SOded Gabbay }
kfd_process_notifier_release_internal(struct kfd_process * p)117319f6d2a6SOded Gabbay
117422e3d934SDavid Belanger static void kfd_process_notifier_release_internal(struct kfd_process *p)
117522e3d934SDavid Belanger {
117621889582SJonathan Kim int i;
117721889582SJonathan Kim
117822e3d934SDavid Belanger cancel_delayed_work_sync(&p->eviction_work);
117922e3d934SDavid Belanger cancel_delayed_work_sync(&p->restore_work);
118022e3d934SDavid Belanger
118121889582SJonathan Kim for (i = 0; i < p->n_pdds; i++) {
118221889582SJonathan Kim struct kfd_process_device *pdd = p->pdds[i];
118321889582SJonathan Kim
118421889582SJonathan Kim /* re-enable GFX OFF since runtime enable with ttmp setup disabled it. */
118521889582SJonathan Kim if (!kfd_dbg_is_rlc_restore_supported(pdd->dev) && p->runtime_info.ttmp_setup)
118621889582SJonathan Kim amdgpu_gfx_off_ctrl(pdd->dev->adev, true);
118721889582SJonathan Kim }
118821889582SJonathan Kim
118922e3d934SDavid Belanger /* Indicate to other users that MM is no longer valid */
119022e3d934SDavid Belanger p->mm = NULL;
11910ab2d753SJonathan Kim kfd_dbg_trap_disable(p);
11920ab2d753SJonathan Kim
11930ab2d753SJonathan Kim if (atomic_read(&p->debugged_process_count) > 0) {
11940ab2d753SJonathan Kim struct kfd_process *target;
11950ab2d753SJonathan Kim unsigned int temp;
11960ab2d753SJonathan Kim int idx = srcu_read_lock(&kfd_processes_srcu);
11970ab2d753SJonathan Kim
11980ab2d753SJonathan Kim hash_for_each_rcu(kfd_processes_table, temp, target, kfd_processes) {
11990ab2d753SJonathan Kim if (target->debugger_process && target->debugger_process == p) {
12000ab2d753SJonathan Kim mutex_lock_nested(&target->mutex, 1);
12010ab2d753SJonathan Kim kfd_dbg_trap_disable(target);
12020ab2d753SJonathan Kim mutex_unlock(&target->mutex);
12030ab2d753SJonathan Kim if (atomic_read(&p->debugged_process_count) == 0)
12040ab2d753SJonathan Kim break;
12050ab2d753SJonathan Kim }
12060ab2d753SJonathan Kim }
12070ab2d753SJonathan Kim
12080ab2d753SJonathan Kim srcu_read_unlock(&kfd_processes_srcu, idx);
12090ab2d753SJonathan Kim }
121022e3d934SDavid Belanger
121122e3d934SDavid Belanger mmu_notifier_put(&p->mmu_notifier);
121222e3d934SDavid Belanger }
kfd_process_notifier_release(struct mmu_notifier * mn,struct mm_struct * mm)121322e3d934SDavid Belanger
121419f6d2a6SOded Gabbay static void kfd_process_notifier_release(struct mmu_notifier *mn,
121519f6d2a6SOded Gabbay struct mm_struct *mm)
121619f6d2a6SOded Gabbay {
121719f6d2a6SOded Gabbay struct kfd_process *p;
121819f6d2a6SOded Gabbay
121919f6d2a6SOded Gabbay /*
122019f6d2a6SOded Gabbay * The kfd_process structure can not be free because the
122119f6d2a6SOded Gabbay * mmu_notifier srcu is read locked
122219f6d2a6SOded Gabbay */
122319f6d2a6SOded Gabbay p = container_of(mn, struct kfd_process, mmu_notifier);
122432fa8219SFelix Kuehling if (WARN_ON(p->mm != mm))
122532fa8219SFelix Kuehling return;
122619f6d2a6SOded Gabbay
122719f6d2a6SOded Gabbay mutex_lock(&kfd_processes_mutex);
122822e3d934SDavid Belanger /*
122922e3d934SDavid Belanger * Do early return if table is empty.
123022e3d934SDavid Belanger *
123122e3d934SDavid Belanger * This could potentially happen if this function is called concurrently
123222e3d934SDavid Belanger * by mmu_notifier and by kfd_cleanup_pocesses.
123322e3d934SDavid Belanger *
123422e3d934SDavid Belanger */
123522e3d934SDavid Belanger if (hash_empty(kfd_processes_table)) {
123622e3d934SDavid Belanger mutex_unlock(&kfd_processes_mutex);
123722e3d934SDavid Belanger return;
123822e3d934SDavid Belanger }
123919f6d2a6SOded Gabbay hash_del_rcu(&p->kfd_processes);
124019f6d2a6SOded Gabbay mutex_unlock(&kfd_processes_mutex);
124119f6d2a6SOded Gabbay synchronize_srcu(&kfd_processes_srcu);
124219f6d2a6SOded Gabbay
124322e3d934SDavid Belanger kfd_process_notifier_release_internal(p);
124419f6d2a6SOded Gabbay }
124519f6d2a6SOded Gabbay
124619f6d2a6SOded Gabbay static const struct mmu_notifier_ops kfd_process_mmu_notifier_ops = {
124719f6d2a6SOded Gabbay .release = kfd_process_notifier_release,
12483248b6d3SFelix Kuehling .alloc_notifier = kfd_process_alloc_notifier,
1249471f3902SJason Gunthorpe .free_notifier = kfd_process_free_notifier,
125019f6d2a6SOded Gabbay };
125119f6d2a6SOded Gabbay
125222e3d934SDavid Belanger /*
125322e3d934SDavid Belanger * This code handles the case when driver is being unloaded before all
125422e3d934SDavid Belanger * mm_struct are released. We need to safely free the kfd_process and
125522e3d934SDavid Belanger * avoid race conditions with mmu_notifier that might try to free them.
125622e3d934SDavid Belanger *
kfd_cleanup_processes(void)125722e3d934SDavid Belanger */
125822e3d934SDavid Belanger void kfd_cleanup_processes(void)
125922e3d934SDavid Belanger {
126022e3d934SDavid Belanger struct kfd_process *p;
126122e3d934SDavid Belanger struct hlist_node *p_temp;
126222e3d934SDavid Belanger unsigned int temp;
126322e3d934SDavid Belanger HLIST_HEAD(cleanup_list);
126422e3d934SDavid Belanger
126522e3d934SDavid Belanger /*
126622e3d934SDavid Belanger * Move all remaining kfd_process from the process table to a
126722e3d934SDavid Belanger * temp list for processing. Once done, callback from mmu_notifier
126822e3d934SDavid Belanger * release will not see the kfd_process in the table and do early return,
126922e3d934SDavid Belanger * avoiding double free issues.
127022e3d934SDavid Belanger */
127122e3d934SDavid Belanger mutex_lock(&kfd_processes_mutex);
127222e3d934SDavid Belanger hash_for_each_safe(kfd_processes_table, temp, p_temp, p, kfd_processes) {
127322e3d934SDavid Belanger hash_del_rcu(&p->kfd_processes);
127422e3d934SDavid Belanger synchronize_srcu(&kfd_processes_srcu);
127522e3d934SDavid Belanger hlist_add_head(&p->kfd_processes, &cleanup_list);
127622e3d934SDavid Belanger }
127722e3d934SDavid Belanger mutex_unlock(&kfd_processes_mutex);
127822e3d934SDavid Belanger
127922e3d934SDavid Belanger hlist_for_each_entry_safe(p, p_temp, &cleanup_list, kfd_processes)
128022e3d934SDavid Belanger kfd_process_notifier_release_internal(p);
128122e3d934SDavid Belanger
128222e3d934SDavid Belanger /*
128322e3d934SDavid Belanger * Ensures that all outstanding free_notifier get called, triggering
128422e3d934SDavid Belanger * the release of the kfd_process struct.
128522e3d934SDavid Belanger */
128622e3d934SDavid Belanger mmu_notifier_synchronize();
128722e3d934SDavid Belanger }
kfd_process_init_cwsr_apu(struct kfd_process * p,struct file * filep)128822e3d934SDavid Belanger
12890ab2d753SJonathan Kim int kfd_process_init_cwsr_apu(struct kfd_process *p, struct file *filep)
1290373d7080SFelix Kuehling {
1291373d7080SFelix Kuehling unsigned long offset;
12926ae27841SAlex Sierra int i;
1293373d7080SFelix Kuehling
12940ab2d753SJonathan Kim if (p->has_cwsr)
12950ab2d753SJonathan Kim return 0;
12960ab2d753SJonathan Kim
12976ae27841SAlex Sierra for (i = 0; i < p->n_pdds; i++) {
12988dc1db31SMukul Joshi struct kfd_node *dev = p->pdds[i]->dev;
12996ae27841SAlex Sierra struct qcm_process_device *qpd = &p->pdds[i]->qpd;
1300f35751b8SFelix Kuehling
13018dc1db31SMukul Joshi if (!dev->kfd->cwsr_enabled || qpd->cwsr_kaddr || qpd->cwsr_base)
1302373d7080SFelix Kuehling continue;
1303f35751b8SFelix Kuehling
130429453755SYong Zhao offset = KFD_MMAP_TYPE_RESERVED_MEM | KFD_MMAP_GPU_ID(dev->id);
1305373d7080SFelix Kuehling qpd->tba_addr = (int64_t)vm_mmap(filep, 0,
1306373d7080SFelix Kuehling KFD_CWSR_TBA_TMA_SIZE, PROT_READ | PROT_EXEC,
1307373d7080SFelix Kuehling MAP_SHARED, offset);
1308373d7080SFelix Kuehling
1309373d7080SFelix Kuehling if (IS_ERR_VALUE(qpd->tba_addr)) {
1310c0ede1f8SYong Zhao int err = qpd->tba_addr;
1311c0ede1f8SYong Zhao
13124312b60fSLijo Lazar dev_err(dev->adev->dev,
13134312b60fSLijo Lazar "Failure to set tba address. error %d.\n", err);
1314373d7080SFelix Kuehling qpd->tba_addr = 0;
1315373d7080SFelix Kuehling qpd->cwsr_kaddr = NULL;
1316c0ede1f8SYong Zhao return err;
1317373d7080SFelix Kuehling }
1318373d7080SFelix Kuehling
13198dc1db31SMukul Joshi memcpy(qpd->cwsr_kaddr, dev->kfd->cwsr_isa, dev->kfd->cwsr_isa_size);
1320373d7080SFelix Kuehling
132150cff45eSJay Cornwall kfd_process_set_trap_debug_flag(qpd, p->debug_trap_enabled);
132250cff45eSJay Cornwall
1323373d7080SFelix Kuehling qpd->tma_addr = qpd->tba_addr + KFD_CWSR_TMA_OFFSET;
1324373d7080SFelix Kuehling pr_debug("set tba :0x%llx, tma:0x%llx, cwsr_kaddr:%p for pqm.\n",
1325373d7080SFelix Kuehling qpd->tba_addr, qpd->tma_addr, qpd->cwsr_kaddr);
1326373d7080SFelix Kuehling }
1327c0ede1f8SYong Zhao
13280ab2d753SJonathan Kim p->has_cwsr = true;
13290ab2d753SJonathan Kim
1330c0ede1f8SYong Zhao return 0;
1331373d7080SFelix Kuehling }
1332373d7080SFelix Kuehling
1333f35751b8SFelix Kuehling static int kfd_process_device_init_cwsr_dgpu(struct kfd_process_device *pdd)
1334f35751b8SFelix Kuehling {
13358dc1db31SMukul Joshi struct kfd_node *dev = pdd->dev;
1336f35751b8SFelix Kuehling struct qcm_process_device *qpd = &pdd->qpd;
13371d251d90SYong Zhao uint32_t flags = KFD_IOC_ALLOC_MEM_FLAGS_GTT
13381d251d90SYong Zhao | KFD_IOC_ALLOC_MEM_FLAGS_NO_SUBSTITUTE
13391d251d90SYong Zhao | KFD_IOC_ALLOC_MEM_FLAGS_EXECUTABLE;
134068df0f19SLang Yu struct kgd_mem *mem;
1341f35751b8SFelix Kuehling void *kaddr;
1342f35751b8SFelix Kuehling int ret;
1343f35751b8SFelix Kuehling
13448dc1db31SMukul Joshi if (!dev->kfd->cwsr_enabled || qpd->cwsr_kaddr || !qpd->cwsr_base)
1345f35751b8SFelix Kuehling return 0;
1346f35751b8SFelix Kuehling
1347f35751b8SFelix Kuehling /* cwsr_base is only set for dGPU */
1348f35751b8SFelix Kuehling ret = kfd_process_alloc_gpuvm(pdd, qpd->cwsr_base,
134968df0f19SLang Yu KFD_CWSR_TBA_TMA_SIZE, flags, &mem, &kaddr);
1350f35751b8SFelix Kuehling if (ret)
1351f35751b8SFelix Kuehling return ret;
1352f35751b8SFelix Kuehling
135368df0f19SLang Yu qpd->cwsr_mem = mem;
1354f35751b8SFelix Kuehling qpd->cwsr_kaddr = kaddr;
1355f35751b8SFelix Kuehling qpd->tba_addr = qpd->cwsr_base;
1356f35751b8SFelix Kuehling
13578dc1db31SMukul Joshi memcpy(qpd->cwsr_kaddr, dev->kfd->cwsr_isa, dev->kfd->cwsr_isa_size);
1358f35751b8SFelix Kuehling
135950cff45eSJay Cornwall kfd_process_set_trap_debug_flag(&pdd->qpd,
136050cff45eSJay Cornwall pdd->process->debug_trap_enabled);
136150cff45eSJay Cornwall
1362f35751b8SFelix Kuehling qpd->tma_addr = qpd->tba_addr + KFD_CWSR_TMA_OFFSET;
1363f35751b8SFelix Kuehling pr_debug("set tba :0x%llx, tma:0x%llx, cwsr_kaddr:%p for pqm.\n",
1364f35751b8SFelix Kuehling qpd->tba_addr, qpd->tma_addr, qpd->cwsr_kaddr);
1365f35751b8SFelix Kuehling
1366f35751b8SFelix Kuehling return 0;
kfd_process_device_destroy_cwsr_dgpu(struct kfd_process_device * pdd)1367f35751b8SFelix Kuehling }
1368f35751b8SFelix Kuehling
136968df0f19SLang Yu static void kfd_process_device_destroy_cwsr_dgpu(struct kfd_process_device *pdd)
137068df0f19SLang Yu {
13718dc1db31SMukul Joshi struct kfd_node *dev = pdd->dev;
137268df0f19SLang Yu struct qcm_process_device *qpd = &pdd->qpd;
137368df0f19SLang Yu
13748dc1db31SMukul Joshi if (!dev->kfd->cwsr_enabled || !qpd->cwsr_kaddr || !qpd->cwsr_base)
137568df0f19SLang Yu return;
137668df0f19SLang Yu
1377cb8dc232SPhilip Yang kfd_process_free_gpuvm(qpd->cwsr_mem, pdd, &qpd->cwsr_kaddr);
137868df0f19SLang Yu }
137968df0f19SLang Yu
13807c9631afSJay Cornwall void kfd_process_set_trap_handler(struct qcm_process_device *qpd,
13817c9631afSJay Cornwall uint64_t tba_addr,
13827c9631afSJay Cornwall uint64_t tma_addr)
13837c9631afSJay Cornwall {
13847c9631afSJay Cornwall if (qpd->cwsr_kaddr) {
13857c9631afSJay Cornwall /* KFD trap handler is bound, record as second-level TBA/TMA
13867c9631afSJay Cornwall * in first-level TMA. First-level trap will jump to second.
13877c9631afSJay Cornwall */
13887c9631afSJay Cornwall uint64_t *tma =
13897c9631afSJay Cornwall (uint64_t *)(qpd->cwsr_kaddr + KFD_CWSR_TMA_OFFSET);
13907c9631afSJay Cornwall tma[0] = tba_addr;
13917c9631afSJay Cornwall tma[1] = tma_addr;
13927c9631afSJay Cornwall } else {
13937c9631afSJay Cornwall /* No trap handler bound, bind as first-level TBA/TMA. */
13947c9631afSJay Cornwall qpd->tba_addr = tba_addr;
13957c9631afSJay Cornwall qpd->tma_addr = tma_addr;
13967c9631afSJay Cornwall }
kfd_process_xnack_mode(struct kfd_process * p,bool supported)13977c9631afSJay Cornwall }
13987c9631afSJay Cornwall
1399063e33c5SAlex Sierra bool kfd_process_xnack_mode(struct kfd_process *p, bool supported)
1400063e33c5SAlex Sierra {
1401063e33c5SAlex Sierra int i;
1402063e33c5SAlex Sierra
1403063e33c5SAlex Sierra /* On most GFXv9 GPUs, the retry mode in the SQ must match the
1404063e33c5SAlex Sierra * boot time retry setting. Mixing processes with different
1405063e33c5SAlex Sierra * XNACK/retry settings can hang the GPU.
1406063e33c5SAlex Sierra *
1407063e33c5SAlex Sierra * Different GPUs can have different noretry settings depending
1408063e33c5SAlex Sierra * on HW bugs or limitations. We need to find at least one
1409063e33c5SAlex Sierra * XNACK mode for this process that's compatible with all GPUs.
1410063e33c5SAlex Sierra * Fortunately GPUs with retry enabled (noretry=0) can run code
1411063e33c5SAlex Sierra * built for XNACK-off. On GFXv9 it may perform slower.
1412063e33c5SAlex Sierra *
1413063e33c5SAlex Sierra * Therefore applications built for XNACK-off can always be
1414063e33c5SAlex Sierra * supported and will be our fallback if any GPU does not
1415063e33c5SAlex Sierra * support retry.
1416063e33c5SAlex Sierra */
1417063e33c5SAlex Sierra for (i = 0; i < p->n_pdds; i++) {
14188dc1db31SMukul Joshi struct kfd_node *dev = p->pdds[i]->dev;
1419063e33c5SAlex Sierra
1420063e33c5SAlex Sierra /* Only consider GFXv9 and higher GPUs. Older GPUs don't
1421063e33c5SAlex Sierra * support the SVM APIs and don't need to be considered
1422063e33c5SAlex Sierra * for the XNACK mode selection.
1423063e33c5SAlex Sierra */
1424046e674bSGraham Sider if (!KFD_IS_SOC15(dev))
1425063e33c5SAlex Sierra continue;
1426063e33c5SAlex Sierra /* Aldebaran can always support XNACK because it can support
1427063e33c5SAlex Sierra * per-process XNACK mode selection. But let the dev->noretry
1428063e33c5SAlex Sierra * setting still influence the default XNACK mode.
1429063e33c5SAlex Sierra */
143024294e7bSPhilip Yang if (supported && KFD_SUPPORT_XNACK_PER_PROCESS(dev))
1431063e33c5SAlex Sierra continue;
1432063e33c5SAlex Sierra
1433063e33c5SAlex Sierra /* GFXv10 and later GPUs do not support shader preemption
1434063e33c5SAlex Sierra * during page faults. This can lead to poor QoS for queue
1435063e33c5SAlex Sierra * management and memory-manager-related preemptions or
1436063e33c5SAlex Sierra * even deadlocks.
1437063e33c5SAlex Sierra */
1438046e674bSGraham Sider if (KFD_GC_VERSION(dev) >= IP_VERSION(10, 1, 1))
1439063e33c5SAlex Sierra return false;
1440063e33c5SAlex Sierra
14418dc1db31SMukul Joshi if (dev->kfd->noretry)
1442063e33c5SAlex Sierra return false;
1443063e33c5SAlex Sierra }
1444063e33c5SAlex Sierra
1445063e33c5SAlex Sierra return true;
1446063e33c5SAlex Sierra }
1447063e33c5SAlex Sierra
144850cff45eSJay Cornwall void kfd_process_set_trap_debug_flag(struct qcm_process_device *qpd,
144950cff45eSJay Cornwall bool enabled)
145050cff45eSJay Cornwall {
145150cff45eSJay Cornwall if (qpd->cwsr_kaddr) {
145250cff45eSJay Cornwall uint64_t *tma =
145350cff45eSJay Cornwall (uint64_t *)(qpd->cwsr_kaddr + KFD_CWSR_TMA_OFFSET);
145450cff45eSJay Cornwall tma[2] = enabled;
145550cff45eSJay Cornwall }
145650cff45eSJay Cornwall }
145750cff45eSJay Cornwall
14580029cab3SJason Gunthorpe /*
14590029cab3SJason Gunthorpe * On return the kfd_process is fully operational and will be freed when the
create_process(const struct task_struct * thread)14600029cab3SJason Gunthorpe * mm is released
14610029cab3SJason Gunthorpe */
14620029cab3SJason Gunthorpe static struct kfd_process *create_process(const struct task_struct *thread)
146319f6d2a6SOded Gabbay {
146419f6d2a6SOded Gabbay struct kfd_process *process;
14653248b6d3SFelix Kuehling struct mmu_notifier *mn;
146619f6d2a6SOded Gabbay int err = -ENOMEM;
146719f6d2a6SOded Gabbay
146819f6d2a6SOded Gabbay process = kzalloc(sizeof(*process), GFP_KERNEL);
146919f6d2a6SOded Gabbay if (!process)
147019f6d2a6SOded Gabbay goto err_alloc_process;
147119f6d2a6SOded Gabbay
14720029cab3SJason Gunthorpe kref_init(&process->ref);
14730029cab3SJason Gunthorpe mutex_init(&process->mutex);
14740029cab3SJason Gunthorpe process->mm = thread->mm;
14750029cab3SJason Gunthorpe process->lead_thread = thread->group_leader;
14766ae27841SAlex Sierra process->n_pdds = 0;
1477cd9f7910SDavid Yat Sin process->queues_paused = false;
14780029cab3SJason Gunthorpe INIT_DELAYED_WORK(&process->eviction_work, evict_process_worker);
14790029cab3SJason Gunthorpe INIT_DELAYED_WORK(&process->restore_work, restore_process_worker);
14800029cab3SJason Gunthorpe process->last_restore_timestamp = get_jiffies_64();
1481c3eb12dfSFelix Kuehling err = kfd_event_init_process(process);
1482c3eb12dfSFelix Kuehling if (err)
1483c3eb12dfSFelix Kuehling goto err_event_init;
14840029cab3SJason Gunthorpe process->is_32bit_user_mode = in_compat_syscall();
14850ab2d753SJonathan Kim process->debug_trap_enabled = false;
14860ab2d753SJonathan Kim process->debugger_process = NULL;
14870ab2d753SJonathan Kim process->exception_enable_mask = 0;
14880ab2d753SJonathan Kim atomic_set(&process->debugged_process_count, 0);
1489c2d2588cSJonathan Kim sema_init(&process->runtime_enable_sema, 0);
14900029cab3SJason Gunthorpe
149119f6d2a6SOded Gabbay process->pasid = kfd_pasid_alloc();
1492c3eb12dfSFelix Kuehling if (process->pasid == 0) {
1493c3eb12dfSFelix Kuehling err = -ENOSPC;
149419f6d2a6SOded Gabbay goto err_alloc_pasid;
1495c3eb12dfSFelix Kuehling }
149619f6d2a6SOded Gabbay
149745102048SBen Goz err = pqm_init(&process->pqm, process);
149845102048SBen Goz if (err != 0)
149945102048SBen Goz goto err_process_pqm_init;
150045102048SBen Goz
1501dd59239aSAlexey Skidanov /* init process apertures*/
1502b312b2b2SDan Carpenter err = kfd_init_apertures(process);
1503b312b2b2SDan Carpenter if (err != 0)
15047a10d63fSGeert Uytterhoeven goto err_init_apertures;
1505dd59239aSAlexey Skidanov
1506063e33c5SAlex Sierra /* Check XNACK support after PDDs are created in kfd_init_apertures */
1507063e33c5SAlex Sierra process->xnack_enabled = kfd_process_xnack_mode(process, false);
1508063e33c5SAlex Sierra
150942de677fSPhilip Yang err = svm_range_list_init(process);
151042de677fSPhilip Yang if (err)
151142de677fSPhilip Yang goto err_init_svm_range_list;
151242de677fSPhilip Yang
15133248b6d3SFelix Kuehling /* alloc_notifier needs to find the process in the hash table */
15140029cab3SJason Gunthorpe hash_add_rcu(kfd_processes_table, &process->kfd_processes,
15150029cab3SJason Gunthorpe (uintptr_t)process->mm);
1516c0ede1f8SYong Zhao
15170593ad21SPhilip Yang /* Avoid free_notifier to start kfd_process_wq_release if
15180593ad21SPhilip Yang * mmu_notifier_get failed because of pending signal.
15190593ad21SPhilip Yang */
15200593ad21SPhilip Yang kref_get(&process->ref);
15210593ad21SPhilip Yang
15223248b6d3SFelix Kuehling /* MMU notifier registration must be the last call that can fail
15233248b6d3SFelix Kuehling * because after this point we cannot unwind the process creation.
15243248b6d3SFelix Kuehling * After this point, mmu_notifier_put will trigger the cleanup by
15253248b6d3SFelix Kuehling * dropping the last process reference in the free_notifier.
15263248b6d3SFelix Kuehling */
15273248b6d3SFelix Kuehling mn = mmu_notifier_get(&kfd_process_mmu_notifier_ops, process->mm);
15283248b6d3SFelix Kuehling if (IS_ERR(mn)) {
15293248b6d3SFelix Kuehling err = PTR_ERR(mn);
15303248b6d3SFelix Kuehling goto err_register_notifier;
15313248b6d3SFelix Kuehling }
15323248b6d3SFelix Kuehling BUG_ON(mn != &process->mmu_notifier);
15333248b6d3SFelix Kuehling
15340593ad21SPhilip Yang kfd_unref_process(process);
15353248b6d3SFelix Kuehling get_task_struct(process->lead_thread);
15363248b6d3SFelix Kuehling
153744b87bb0SJonathan Kim INIT_WORK(&process->debug_event_workarea, debug_event_write_work_handler);
153844b87bb0SJonathan Kim
153919f6d2a6SOded Gabbay return process;
154019f6d2a6SOded Gabbay
15410029cab3SJason Gunthorpe err_register_notifier:
15423248b6d3SFelix Kuehling hash_del_rcu(&process->kfd_processes);
154342de677fSPhilip Yang svm_range_list_fini(process);
154442de677fSPhilip Yang err_init_svm_range_list:
154552b29d73SFelix Kuehling kfd_process_free_outstanding_kfd_bos(process);
1546c0ede1f8SYong Zhao kfd_process_destroy_pdds(process);
15477a10d63fSGeert Uytterhoeven err_init_apertures:
1548dd59239aSAlexey Skidanov pqm_uninit(&process->pqm);
154945102048SBen Goz err_process_pqm_init:
155019f6d2a6SOded Gabbay kfd_pasid_free(process->pasid);
155119f6d2a6SOded Gabbay err_alloc_pasid:
1552c3eb12dfSFelix Kuehling kfd_event_free_process(process);
1553c3eb12dfSFelix Kuehling err_event_init:
15540029cab3SJason Gunthorpe mutex_destroy(&process->mutex);
155519f6d2a6SOded Gabbay kfree(process);
155619f6d2a6SOded Gabbay err_alloc_process:
155719f6d2a6SOded Gabbay return ERR_PTR(err);
155819f6d2a6SOded Gabbay }
155919f6d2a6SOded Gabbay
15608dc1db31SMukul Joshi struct kfd_process_device *kfd_get_process_device_data(struct kfd_node *dev,
1561093c7d8cSAlexey Skidanov struct kfd_process *p)
156219f6d2a6SOded Gabbay {
15636ae27841SAlex Sierra int i;
156419f6d2a6SOded Gabbay
15656ae27841SAlex Sierra for (i = 0; i < p->n_pdds; i++)
15666ae27841SAlex Sierra if (p->pdds[i]->dev == dev)
15676ae27841SAlex Sierra return p->pdds[i];
1568733fa1f7SYong Zhao
1569733fa1f7SYong Zhao return NULL;
kfd_create_process_device_data(struct kfd_node * dev,struct kfd_process * p)1570093c7d8cSAlexey Skidanov }
1571093c7d8cSAlexey Skidanov
15728dc1db31SMukul Joshi struct kfd_process_device *kfd_create_process_device_data(struct kfd_node *dev,
1573093c7d8cSAlexey Skidanov struct kfd_process *p)
1574093c7d8cSAlexey Skidanov {
1575093c7d8cSAlexey Skidanov struct kfd_process_device *pdd = NULL;
1576093c7d8cSAlexey Skidanov
15776ae27841SAlex Sierra if (WARN_ON_ONCE(p->n_pdds >= MAX_GPU_INSTANCE))
15786ae27841SAlex Sierra return NULL;
157919f6d2a6SOded Gabbay pdd = kzalloc(sizeof(*pdd), GFP_KERNEL);
15802d9b36f9SFelix Kuehling if (!pdd)
15812d9b36f9SFelix Kuehling return NULL;
15822d9b36f9SFelix Kuehling
158319f6d2a6SOded Gabbay pdd->dev = dev;
158445102048SBen Goz INIT_LIST_HEAD(&pdd->qpd.queues_list);
158545102048SBen Goz INIT_LIST_HEAD(&pdd->qpd.priv_queue_list);
158645102048SBen Goz pdd->qpd.dqm = dev->dqm;
1587b20cd0dfSFelix Kuehling pdd->qpd.pqm = &p->pqm;
158826103436SFelix Kuehling pdd->qpd.evicted = 0;
1589b8020b03SJoseph Greathouse pdd->qpd.mapped_gws_queue = false;
15909fd3f1bfSFelix Kuehling pdd->process = p;
1591733fa1f7SYong Zhao pdd->bound = PDD_UNBOUND;
15929fd3f1bfSFelix Kuehling pdd->already_dequeued = false;
15939593f4d6SRajneesh Bhardwaj pdd->runtime_inuse = false;
15944c332037SPhilip Yang atomic64_set(&pdd->vram_usage, 0);
159532cb59f3SMukul Joshi pdd->sdma_past_activity_counter = 0;
1596bef153b7SDavid Yat Sin pdd->user_gpu_id = dev->id;
15974327bed2SPhilip Cox atomic64_set(&pdd->evict_duration_counter, 0);
1598cc009e61SMukul Joshi
15996ae27841SAlex Sierra p->pdds[p->n_pdds++] = pdd;
16000de4ec9aSJonathan Kim if (kfd_dbg_is_per_vmid_supported(pdd->dev))
16010de4ec9aSJonathan Kim pdd->spi_dbg_override = pdd->dev->kfd2kgd->disable_debug_trap(
16020de4ec9aSJonathan Kim pdd->dev->adev,
16030de4ec9aSJonathan Kim false,
16040de4ec9aSJonathan Kim 0);
160519f6d2a6SOded Gabbay
160652b29d73SFelix Kuehling /* Init idr used for memory handle translation */
160752b29d73SFelix Kuehling idr_init(&pdd->alloc_idr);
160852b29d73SFelix Kuehling
160919f6d2a6SOded Gabbay return pdd;
1610b84394e2SFelix Kuehling }
1611403575c4SFelix Kuehling
1612b84394e2SFelix Kuehling /**
1613b84394e2SFelix Kuehling * kfd_process_device_init_vm - Initialize a VM for a process-device
1614b84394e2SFelix Kuehling *
1615b84394e2SFelix Kuehling * @pdd: The process-device
1616b84394e2SFelix Kuehling * @drm_file: Optional pointer to a DRM file descriptor
1617b84394e2SFelix Kuehling *
1618b84394e2SFelix Kuehling * If @drm_file is specified, it will be used to acquire the VM from
1619b84394e2SFelix Kuehling * that file descriptor. If successful, the @pdd takes ownership of
1620b84394e2SFelix Kuehling * the file descriptor.
1621b84394e2SFelix Kuehling *
1622b84394e2SFelix Kuehling * If @drm_file is NULL, a new VM is created.
1623b84394e2SFelix Kuehling *
1624b84394e2SFelix Kuehling * Returns 0 on success, -errno on failure.
1625b84394e2SFelix Kuehling */
1626b84394e2SFelix Kuehling int kfd_process_device_init_vm(struct kfd_process_device *pdd,
1627b84394e2SFelix Kuehling struct file *drm_file)
1628b84394e2SFelix Kuehling {
162923b02b0eSPhilip Yang struct amdgpu_fpriv *drv_priv;
163023b02b0eSPhilip Yang struct amdgpu_vm *avm;
1631b84394e2SFelix Kuehling struct kfd_process *p;
16328dc1db31SMukul Joshi struct kfd_node *dev;
1633b84394e2SFelix Kuehling int ret;
1634b84394e2SFelix Kuehling
1635f45e6b9dSFelix Kuehling if (!drm_file)
1636f45e6b9dSFelix Kuehling return -EINVAL;
1637f45e6b9dSFelix Kuehling
1638b40a6ab2SFelix Kuehling if (pdd->drm_priv)
1639f45e6b9dSFelix Kuehling return -EBUSY;
1640b84394e2SFelix Kuehling
164123b02b0eSPhilip Yang ret = amdgpu_file_to_fpriv(drm_file, &drv_priv);
164223b02b0eSPhilip Yang if (ret)
kfd_process_device_init_vm(struct kfd_process_device * pdd,struct file * drm_file)164323b02b0eSPhilip Yang return ret;
164423b02b0eSPhilip Yang avm = &drv_priv->vm;
164523b02b0eSPhilip Yang
1646b84394e2SFelix Kuehling p = pdd->process;
1647b84394e2SFelix Kuehling dev = pdd->dev;
1648b84394e2SFelix Kuehling
164923b02b0eSPhilip Yang ret = amdgpu_amdkfd_gpuvm_acquire_process_vm(dev->adev, avm,
165041d82649SPhilip Yang &p->kgd_process_info,
165141d82649SPhilip Yang &p->ef);
1652b84394e2SFelix Kuehling if (ret) {
16534312b60fSLijo Lazar dev_err(dev->adev->dev, "Failed to create process VM object\n");
1654b84394e2SFelix Kuehling return ret;
1655b84394e2SFelix Kuehling }
1656b40a6ab2SFelix Kuehling pdd->drm_priv = drm_file->private_data;
16578fde0248SPhilip Yang atomic64_set(&pdd->tlb_seq, 0);
1658f40c6912SYong Zhao
1659552764b6SFelix Kuehling ret = kfd_process_device_reserve_ib_mem(pdd);
1660552764b6SFelix Kuehling if (ret)
1661552764b6SFelix Kuehling goto err_reserve_ib_mem;
1662f35751b8SFelix Kuehling ret = kfd_process_device_init_cwsr_dgpu(pdd);
1663f35751b8SFelix Kuehling if (ret)
1664f35751b8SFelix Kuehling goto err_init_cwsr;
1665f35751b8SFelix Kuehling
166623b02b0eSPhilip Yang ret = amdgpu_amdkfd_gpuvm_set_vm_pasid(dev->adev, avm, p->pasid);
166741d82649SPhilip Yang if (ret)
166841d82649SPhilip Yang goto err_set_pasid;
166941d82649SPhilip Yang
1670b84394e2SFelix Kuehling pdd->drm_file = drm_file;
1671b84394e2SFelix Kuehling
1672b84394e2SFelix Kuehling return 0;
1673f35751b8SFelix Kuehling
167441d82649SPhilip Yang err_set_pasid:
167541d82649SPhilip Yang kfd_process_device_destroy_cwsr_dgpu(pdd);
1676f35751b8SFelix Kuehling err_init_cwsr:
1677cb8dc232SPhilip Yang kfd_process_device_destroy_ib_mem(pdd);
1678552764b6SFelix Kuehling err_reserve_ib_mem:
1679b40a6ab2SFelix Kuehling pdd->drm_priv = NULL;
168023b02b0eSPhilip Yang amdgpu_amdkfd_gpuvm_destroy_cb(dev->adev, avm);
1681f35751b8SFelix Kuehling
1682f35751b8SFelix Kuehling return ret;
168319f6d2a6SOded Gabbay }
168419f6d2a6SOded Gabbay
168519f6d2a6SOded Gabbay /*
168619f6d2a6SOded Gabbay * Direct the IOMMU to bind the process (specifically the pasid->mm)
168719f6d2a6SOded Gabbay * to the device.
168819f6d2a6SOded Gabbay * Unbinding occurs when the process dies or the device is removed.
168919f6d2a6SOded Gabbay *
169019f6d2a6SOded Gabbay * Assumes that the process lock is held.
169119f6d2a6SOded Gabbay */
16928dc1db31SMukul Joshi struct kfd_process_device *kfd_bind_process_to_device(struct kfd_node *dev,
169319f6d2a6SOded Gabbay struct kfd_process *p)
169419f6d2a6SOded Gabbay {
1695093c7d8cSAlexey Skidanov struct kfd_process_device *pdd;
1696b17f068aSOded Gabbay int err;
169719f6d2a6SOded Gabbay
1698093c7d8cSAlexey Skidanov pdd = kfd_get_process_device_data(dev, p);
1699093c7d8cSAlexey Skidanov if (!pdd) {
17004312b60fSLijo Lazar dev_err(dev->adev->dev, "Process device data doesn't exist\n");
170119f6d2a6SOded Gabbay return ERR_PTR(-ENOMEM);
1702093c7d8cSAlexey Skidanov }
170319f6d2a6SOded Gabbay
1704b40a6ab2SFelix Kuehling if (!pdd->drm_priv)
1705f45e6b9dSFelix Kuehling return ERR_PTR(-ENODEV);
1706f45e6b9dSFelix Kuehling
17079593f4d6SRajneesh Bhardwaj /*
17089593f4d6SRajneesh Bhardwaj * signal runtime-pm system to auto resume and prevent
kfd_bind_process_to_device(struct kfd_node * dev,struct kfd_process * p)17099593f4d6SRajneesh Bhardwaj * further runtime suspend once device pdd is created until
17109593f4d6SRajneesh Bhardwaj * pdd is destroyed.
17119593f4d6SRajneesh Bhardwaj */
17129593f4d6SRajneesh Bhardwaj if (!pdd->runtime_inuse) {
1713d69a3b76SMukul Joshi err = pm_runtime_get_sync(adev_to_drm(dev->adev)->dev);
17141c1ada37SAlex Deucher if (err < 0) {
1715d69a3b76SMukul Joshi pm_runtime_put_autosuspend(adev_to_drm(dev->adev)->dev);
17169593f4d6SRajneesh Bhardwaj return ERR_PTR(err);
17179593f4d6SRajneesh Bhardwaj }
17181c1ada37SAlex Deucher }
17199593f4d6SRajneesh Bhardwaj
17209593f4d6SRajneesh Bhardwaj /*
17219593f4d6SRajneesh Bhardwaj * make sure that runtime_usage counter is incremented just once
17229593f4d6SRajneesh Bhardwaj * per pdd
17239593f4d6SRajneesh Bhardwaj */
17249593f4d6SRajneesh Bhardwaj pdd->runtime_inuse = true;
1725b84394e2SFelix Kuehling
172619f6d2a6SOded Gabbay return pdd;
172719f6d2a6SOded Gabbay }
172819f6d2a6SOded Gabbay
172952b29d73SFelix Kuehling /* Create specific handle mapped to mem from process local memory idr
173052b29d73SFelix Kuehling * Assumes that the process lock is held.
173152b29d73SFelix Kuehling */
173252b29d73SFelix Kuehling int kfd_process_device_create_obj_handle(struct kfd_process_device *pdd,
173352b29d73SFelix Kuehling void *mem)
173452b29d73SFelix Kuehling {
173552b29d73SFelix Kuehling return idr_alloc(&pdd->alloc_idr, mem, 0, 0, GFP_KERNEL);
173652b29d73SFelix Kuehling }
173752b29d73SFelix Kuehling
173852b29d73SFelix Kuehling /* Translate specific handle from process local memory idr
173952b29d73SFelix Kuehling * Assumes that the process lock is held.
174052b29d73SFelix Kuehling */
174152b29d73SFelix Kuehling void *kfd_process_device_translate_handle(struct kfd_process_device *pdd,
174252b29d73SFelix Kuehling int handle)
174352b29d73SFelix Kuehling {
174452b29d73SFelix Kuehling if (handle < 0)
174552b29d73SFelix Kuehling return NULL;
174652b29d73SFelix Kuehling
174752b29d73SFelix Kuehling return idr_find(&pdd->alloc_idr, handle);
174852b29d73SFelix Kuehling }
kfd_process_device_create_obj_handle(struct kfd_process_device * pdd,void * mem)174952b29d73SFelix Kuehling
175052b29d73SFelix Kuehling /* Remove specific handle from process local memory idr
175152b29d73SFelix Kuehling * Assumes that the process lock is held.
175252b29d73SFelix Kuehling */
175352b29d73SFelix Kuehling void kfd_process_device_remove_obj_handle(struct kfd_process_device *pdd,
175452b29d73SFelix Kuehling int handle)
175552b29d73SFelix Kuehling {
175652b29d73SFelix Kuehling if (handle >= 0)
175752b29d73SFelix Kuehling idr_remove(&pdd->alloc_idr, handle);
175852b29d73SFelix Kuehling }
175952b29d73SFelix Kuehling
1760abb208a8SFelix Kuehling /* This increments the process->ref counter. */
1761c7b6bac9SFenghua Yu struct kfd_process *kfd_lookup_process_by_pasid(u32 pasid)
1762f3a39818SAndrew Lewycky {
176382c16b42SYong Zhao struct kfd_process *p, *ret_p = NULL;
1764f3a39818SAndrew Lewycky unsigned int temp;
1765f3a39818SAndrew Lewycky
1766f3a39818SAndrew Lewycky int idx = srcu_read_lock(&kfd_processes_srcu);
1767f3a39818SAndrew Lewycky
1768f3a39818SAndrew Lewycky hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) {
1769f3a39818SAndrew Lewycky if (p->pasid == pasid) {
kfd_process_device_remove_obj_handle(struct kfd_process_device * pdd,int handle)1770abb208a8SFelix Kuehling kref_get(&p->ref);
177182c16b42SYong Zhao ret_p = p;
1772f3a39818SAndrew Lewycky break;
1773f3a39818SAndrew Lewycky }
1774f3a39818SAndrew Lewycky }
1775f3a39818SAndrew Lewycky
1776f3a39818SAndrew Lewycky srcu_read_unlock(&kfd_processes_srcu, idx);
1777f3a39818SAndrew Lewycky
kfd_lookup_process_by_pasid(u32 pasid)177882c16b42SYong Zhao return ret_p;
1779f3a39818SAndrew Lewycky }
1780373d7080SFelix Kuehling
178126103436SFelix Kuehling /* This increments the process->ref counter. */
178226103436SFelix Kuehling struct kfd_process *kfd_lookup_process_by_mm(const struct mm_struct *mm)
178326103436SFelix Kuehling {
178426103436SFelix Kuehling struct kfd_process *p;
178526103436SFelix Kuehling
178626103436SFelix Kuehling int idx = srcu_read_lock(&kfd_processes_srcu);
178726103436SFelix Kuehling
178826103436SFelix Kuehling p = find_process_by_mm(mm);
178926103436SFelix Kuehling if (p)
179026103436SFelix Kuehling kref_get(&p->ref);
179126103436SFelix Kuehling
179226103436SFelix Kuehling srcu_read_unlock(&kfd_processes_srcu, idx);
179326103436SFelix Kuehling
179426103436SFelix Kuehling return p;
179526103436SFelix Kuehling }
179626103436SFelix Kuehling
17970aeaaf64SFelix Kuehling /* kfd_process_evict_queues - Evict all user queues of a process
179826103436SFelix Kuehling *
kfd_lookup_process_by_mm(const struct mm_struct * mm)179926103436SFelix Kuehling * Eviction is reference-counted per process-device. This means multiple
180026103436SFelix Kuehling * evictions from different sources can be nested safely.
180126103436SFelix Kuehling */
1802c7f21978SPhilip Yang int kfd_process_evict_queues(struct kfd_process *p, uint32_t trigger)
180326103436SFelix Kuehling {
180426103436SFelix Kuehling int r = 0;
18056ae27841SAlex Sierra int i;
180626103436SFelix Kuehling unsigned int n_evicted = 0;
180726103436SFelix Kuehling
18086ae27841SAlex Sierra for (i = 0; i < p->n_pdds; i++) {
18096ae27841SAlex Sierra struct kfd_process_device *pdd = p->pdds[i];
18104312b60fSLijo Lazar struct device *dev = pdd->dev->adev->dev;
18116ae27841SAlex Sierra
1812d6e924adSMukul Joshi kfd_smi_event_queue_eviction(pdd->dev, p->lead_thread->pid,
1813c7f21978SPhilip Yang trigger);
1814c7f21978SPhilip Yang
181526103436SFelix Kuehling r = pdd->dev->dqm->ops.evict_process_queues(pdd->dev->dqm,
181626103436SFelix Kuehling &pdd->qpd);
1817b8c20c74Sshaoyunl /* evict return -EIO if HWS is hang or asic is resetting, in this case
1818b8c20c74Sshaoyunl * we would like to set all the queues to be in evicted state to prevent
1819b8c20c74Sshaoyunl * them been add back since they actually not be saved right now.
1820b8c20c74Sshaoyunl */
1821b8c20c74Sshaoyunl if (r && r != -EIO) {
18224312b60fSLijo Lazar dev_err(dev, "Failed to evict process queues\n");
182326103436SFelix Kuehling goto fail;
182426103436SFelix Kuehling }
182526103436SFelix Kuehling n_evicted++;
182626103436SFelix Kuehling }
182726103436SFelix Kuehling
182826103436SFelix Kuehling return r;
182926103436SFelix Kuehling
183026103436SFelix Kuehling fail:
183126103436SFelix Kuehling /* To keep state consistent, roll back partial eviction by
183226103436SFelix Kuehling * restoring queues
183326103436SFelix Kuehling */
18346ae27841SAlex Sierra for (i = 0; i < p->n_pdds; i++) {
18356ae27841SAlex Sierra struct kfd_process_device *pdd = p->pdds[i];
18366ae27841SAlex Sierra
183726103436SFelix Kuehling if (n_evicted == 0)
183826103436SFelix Kuehling break;
1839c7f21978SPhilip Yang
1840d6e924adSMukul Joshi kfd_smi_event_queue_restore(pdd->dev, p->lead_thread->pid);
1841c7f21978SPhilip Yang
184226103436SFelix Kuehling if (pdd->dev->dqm->ops.restore_process_queues(pdd->dev->dqm,
184326103436SFelix Kuehling &pdd->qpd))
18444312b60fSLijo Lazar dev_err(pdd->dev->adev->dev,
18454312b60fSLijo Lazar "Failed to restore queues\n");
184626103436SFelix Kuehling
184726103436SFelix Kuehling n_evicted--;
184826103436SFelix Kuehling }
184926103436SFelix Kuehling
185026103436SFelix Kuehling return r;
185126103436SFelix Kuehling }
185226103436SFelix Kuehling
18530aeaaf64SFelix Kuehling /* kfd_process_restore_queues - Restore all user queues of a process */
18546b95e797SFelix Kuehling int kfd_process_restore_queues(struct kfd_process *p)
185526103436SFelix Kuehling {
185626103436SFelix Kuehling int r, ret = 0;
18576ae27841SAlex Sierra int i;
185826103436SFelix Kuehling
18596ae27841SAlex Sierra for (i = 0; i < p->n_pdds; i++) {
18606ae27841SAlex Sierra struct kfd_process_device *pdd = p->pdds[i];
18614312b60fSLijo Lazar struct device *dev = pdd->dev->adev->dev;
18626ae27841SAlex Sierra
1863d6e924adSMukul Joshi kfd_smi_event_queue_restore(pdd->dev, p->lead_thread->pid);
1864c7f21978SPhilip Yang
186526103436SFelix Kuehling r = pdd->dev->dqm->ops.restore_process_queues(pdd->dev->dqm,
186626103436SFelix Kuehling &pdd->qpd);
186726103436SFelix Kuehling if (r) {
18684312b60fSLijo Lazar dev_err(dev, "Failed to restore process queues\n");
kfd_process_restore_queues(struct kfd_process * p)186926103436SFelix Kuehling if (!ret)
187026103436SFelix Kuehling ret = r;
187126103436SFelix Kuehling }
187226103436SFelix Kuehling }
187326103436SFelix Kuehling
187426103436SFelix Kuehling return ret;
187526103436SFelix Kuehling }
187626103436SFelix Kuehling
18772aeb742bSAlex Sierra int kfd_process_gpuidx_from_gpuid(struct kfd_process *p, uint32_t gpu_id)
18782aeb742bSAlex Sierra {
18792aeb742bSAlex Sierra int i;
18802aeb742bSAlex Sierra
18812aeb742bSAlex Sierra for (i = 0; i < p->n_pdds; i++)
1882d763d803SRajneesh Bhardwaj if (p->pdds[i] && gpu_id == p->pdds[i]->user_gpu_id)
18832aeb742bSAlex Sierra return i;
18842aeb742bSAlex Sierra return -EINVAL;
18852aeb742bSAlex Sierra }
18862aeb742bSAlex Sierra
1887cda0f85bSFelix Kuehling int
18885fb34bd9SAlex Sierra kfd_process_gpuid_from_node(struct kfd_process *p, struct kfd_node *node,
1889cda0f85bSFelix Kuehling uint32_t *gpuid, uint32_t *gpuidx)
1890cda0f85bSFelix Kuehling {
kfd_process_gpuidx_from_gpuid(struct kfd_process * p,uint32_t gpu_id)1891cda0f85bSFelix Kuehling int i;
1892cda0f85bSFelix Kuehling
1893cda0f85bSFelix Kuehling for (i = 0; i < p->n_pdds; i++)
18945fb34bd9SAlex Sierra if (p->pdds[i] && p->pdds[i]->dev == node) {
1895d763d803SRajneesh Bhardwaj *gpuid = p->pdds[i]->user_gpu_id;
1896cda0f85bSFelix Kuehling *gpuidx = i;
1897cda0f85bSFelix Kuehling return 0;
1898cda0f85bSFelix Kuehling }
1899cda0f85bSFelix Kuehling return -EINVAL;
1900cda0f85bSFelix Kuehling }
1901cda0f85bSFelix Kuehling
kfd_process_gpuid_from_node(struct kfd_process * p,struct kfd_node * node,uint32_t * gpuid,uint32_t * gpuidx)190226103436SFelix Kuehling static void evict_process_worker(struct work_struct *work)
190326103436SFelix Kuehling {
190426103436SFelix Kuehling int ret;
190526103436SFelix Kuehling struct kfd_process *p;
190626103436SFelix Kuehling struct delayed_work *dwork;
190726103436SFelix Kuehling
190826103436SFelix Kuehling dwork = to_delayed_work(work);
190926103436SFelix Kuehling
191026103436SFelix Kuehling /* Process termination destroys this worker thread. So during the
191126103436SFelix Kuehling * lifetime of this thread, kfd_process p will be valid
191226103436SFelix Kuehling */
191326103436SFelix Kuehling p = container_of(dwork, struct kfd_process, eviction_work);
191426103436SFelix Kuehling WARN_ONCE(p->last_eviction_seqno != p->ef->seqno,
191526103436SFelix Kuehling "Eviction fence mismatch\n");
191626103436SFelix Kuehling
191726103436SFelix Kuehling /* Narrow window of overlap between restore and evict work
191826103436SFelix Kuehling * item is possible. Once amdgpu_amdkfd_gpuvm_restore_process_bos
191926103436SFelix Kuehling * unreserves KFD BOs, it is possible to evicted again. But
192026103436SFelix Kuehling * restore has few more steps of finish. So lets wait for any
192126103436SFelix Kuehling * previous restore work to complete
192226103436SFelix Kuehling */
192326103436SFelix Kuehling flush_delayed_work(&p->restore_work);
192426103436SFelix Kuehling
19256027b1bfSYong Zhao pr_debug("Started evicting pasid 0x%x\n", p->pasid);
1926c7f21978SPhilip Yang ret = kfd_process_evict_queues(p, KFD_QUEUE_EVICTION_TRIGGER_TTM);
192726103436SFelix Kuehling if (!ret) {
192826103436SFelix Kuehling dma_fence_signal(p->ef);
192926103436SFelix Kuehling dma_fence_put(p->ef);
193026103436SFelix Kuehling p->ef = NULL;
19311679ae8fSFelix Kuehling queue_delayed_work(kfd_restore_wq, &p->restore_work,
193226103436SFelix Kuehling msecs_to_jiffies(PROCESS_RESTORE_TIME_MS));
193326103436SFelix Kuehling
19346027b1bfSYong Zhao pr_debug("Finished evicting pasid 0x%x\n", p->pasid);
193526103436SFelix Kuehling } else
19366027b1bfSYong Zhao pr_err("Failed to evict queues of pasid 0x%x\n", p->pasid);
193726103436SFelix Kuehling }
193826103436SFelix Kuehling
193926103436SFelix Kuehling static void restore_process_worker(struct work_struct *work)
194026103436SFelix Kuehling {
194126103436SFelix Kuehling struct delayed_work *dwork;
194226103436SFelix Kuehling struct kfd_process *p;
194326103436SFelix Kuehling int ret = 0;
194426103436SFelix Kuehling
194526103436SFelix Kuehling dwork = to_delayed_work(work);
194626103436SFelix Kuehling
194726103436SFelix Kuehling /* Process termination destroys this worker thread. So during the
194826103436SFelix Kuehling * lifetime of this thread, kfd_process p will be valid
194926103436SFelix Kuehling */
195026103436SFelix Kuehling p = container_of(dwork, struct kfd_process, restore_work);
19516027b1bfSYong Zhao pr_debug("Started restoring pasid 0x%x\n", p->pasid);
195226103436SFelix Kuehling
restore_process_worker(struct work_struct * work)195326103436SFelix Kuehling /* Setting last_restore_timestamp before successful restoration.
195426103436SFelix Kuehling * Otherwise this would have to be set by KGD (restore_process_bos)
195526103436SFelix Kuehling * before KFD BOs are unreserved. If not, the process can be evicted
195626103436SFelix Kuehling * again before the timestamp is set.
195726103436SFelix Kuehling * If restore fails, the timestamp will be set again in the next
195826103436SFelix Kuehling * attempt. This would mean that the minimum GPU quanta would be
195926103436SFelix Kuehling * PROCESS_ACTIVE_TIME_MS - (time to execute the following two
196026103436SFelix Kuehling * functions)
196126103436SFelix Kuehling */
196226103436SFelix Kuehling
196326103436SFelix Kuehling p->last_restore_timestamp = get_jiffies_64();
19640ab2d753SJonathan Kim /* VMs may not have been acquired yet during debugging. */
19650ab2d753SJonathan Kim if (p->kgd_process_info)
19665b87245fSAmber Lin ret = amdgpu_amdkfd_gpuvm_restore_process_bos(p->kgd_process_info,
196726103436SFelix Kuehling &p->ef);
196826103436SFelix Kuehling if (ret) {
19696027b1bfSYong Zhao pr_debug("Failed to restore BOs of pasid 0x%x, retry after %d ms\n",
197026103436SFelix Kuehling p->pasid, PROCESS_BACK_OFF_TIME_MS);
19711679ae8fSFelix Kuehling ret = queue_delayed_work(kfd_restore_wq, &p->restore_work,
197226103436SFelix Kuehling msecs_to_jiffies(PROCESS_BACK_OFF_TIME_MS));
197326103436SFelix Kuehling WARN(!ret, "reschedule restore work failed\n");
197426103436SFelix Kuehling return;
197526103436SFelix Kuehling }
197626103436SFelix Kuehling
19776b95e797SFelix Kuehling ret = kfd_process_restore_queues(p);
197826103436SFelix Kuehling if (!ret)
19796027b1bfSYong Zhao pr_debug("Finished restoring pasid 0x%x\n", p->pasid);
198026103436SFelix Kuehling else
19816027b1bfSYong Zhao pr_err("Failed to restore queues of pasid 0x%x\n", p->pasid);
198226103436SFelix Kuehling }
198326103436SFelix Kuehling
198426103436SFelix Kuehling void kfd_suspend_all_processes(void)
198526103436SFelix Kuehling {
198626103436SFelix Kuehling struct kfd_process *p;
198726103436SFelix Kuehling unsigned int temp;
198826103436SFelix Kuehling int idx = srcu_read_lock(&kfd_processes_srcu);
198926103436SFelix Kuehling
19908a491bb3SPhilip Cox WARN(debug_evictions, "Evicting all processes");
199126103436SFelix Kuehling hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) {
199226103436SFelix Kuehling cancel_delayed_work_sync(&p->eviction_work);
1993bb13d763SJonathan Kim flush_delayed_work(&p->restore_work);
199426103436SFelix Kuehling
1995c7f21978SPhilip Yang if (kfd_process_evict_queues(p, KFD_QUEUE_EVICTION_TRIGGER_SUSPEND))
19966027b1bfSYong Zhao pr_err("Failed to suspend process 0x%x\n", p->pasid);
199726103436SFelix Kuehling dma_fence_signal(p->ef);
kfd_suspend_all_processes(void)199826103436SFelix Kuehling dma_fence_put(p->ef);
199926103436SFelix Kuehling p->ef = NULL;
200026103436SFelix Kuehling }
200126103436SFelix Kuehling srcu_read_unlock(&kfd_processes_srcu, idx);
200226103436SFelix Kuehling }
200326103436SFelix Kuehling
200426103436SFelix Kuehling int kfd_resume_all_processes(void)
200526103436SFelix Kuehling {
200626103436SFelix Kuehling struct kfd_process *p;
200726103436SFelix Kuehling unsigned int temp;
200826103436SFelix Kuehling int ret = 0, idx = srcu_read_lock(&kfd_processes_srcu);
200926103436SFelix Kuehling
201026103436SFelix Kuehling hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) {
20111679ae8fSFelix Kuehling if (!queue_delayed_work(kfd_restore_wq, &p->restore_work, 0)) {
201226103436SFelix Kuehling pr_err("Restore process %d failed during resume\n",
201326103436SFelix Kuehling p->pasid);
201426103436SFelix Kuehling ret = -EFAULT;
201526103436SFelix Kuehling }
201626103436SFelix Kuehling }
201726103436SFelix Kuehling srcu_read_unlock(&kfd_processes_srcu, idx);
kfd_resume_all_processes(void)201826103436SFelix Kuehling return ret;
201926103436SFelix Kuehling }
202026103436SFelix Kuehling
20218dc1db31SMukul Joshi int kfd_reserved_mem_mmap(struct kfd_node *dev, struct kfd_process *process,
2022373d7080SFelix Kuehling struct vm_area_struct *vma)
2023373d7080SFelix Kuehling {
2024373d7080SFelix Kuehling struct kfd_process_device *pdd;
2025373d7080SFelix Kuehling struct qcm_process_device *qpd;
2026373d7080SFelix Kuehling
2027373d7080SFelix Kuehling if ((vma->vm_end - vma->vm_start) != KFD_CWSR_TBA_TMA_SIZE) {
20284312b60fSLijo Lazar dev_err(dev->adev->dev, "Incorrect CWSR mapping size.\n");
2029373d7080SFelix Kuehling return -EINVAL;
2030373d7080SFelix Kuehling }
2031373d7080SFelix Kuehling
2032373d7080SFelix Kuehling pdd = kfd_get_process_device_data(dev, process);
2033373d7080SFelix Kuehling if (!pdd)
2034373d7080SFelix Kuehling return -EINVAL;
kfd_reserved_mem_mmap(struct kfd_node * dev,struct kfd_process * process,struct vm_area_struct * vma)2035373d7080SFelix Kuehling qpd = &pdd->qpd;
2036373d7080SFelix Kuehling
2037373d7080SFelix Kuehling qpd->cwsr_kaddr = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
2038373d7080SFelix Kuehling get_order(KFD_CWSR_TBA_TMA_SIZE));
2039373d7080SFelix Kuehling if (!qpd->cwsr_kaddr) {
20404312b60fSLijo Lazar dev_err(dev->adev->dev,
20414312b60fSLijo Lazar "Error allocating per process CWSR buffer.\n");
2042373d7080SFelix Kuehling return -ENOMEM;
2043373d7080SFelix Kuehling }
2044373d7080SFelix Kuehling
20451c71222eSSuren Baghdasaryan vm_flags_set(vma, VM_IO | VM_DONTCOPY | VM_DONTEXPAND
20461c71222eSSuren Baghdasaryan | VM_NORESERVE | VM_DONTDUMP | VM_PFNMAP);
2047373d7080SFelix Kuehling /* Mapping pages to user process */
2048373d7080SFelix Kuehling return remap_pfn_range(vma, vma->vm_start,
2049373d7080SFelix Kuehling PFN_DOWN(__pa(qpd->cwsr_kaddr)),
2050373d7080SFelix Kuehling KFD_CWSR_TBA_TMA_SIZE, vma->vm_page_prot);
2051373d7080SFelix Kuehling }
2052851a645eSFelix Kuehling
20533543b055SEric Huang void kfd_flush_tlb(struct kfd_process_device *pdd, enum TLB_FLUSH_TYPE type)
2054403575c4SFelix Kuehling {
2055bffa91daSChristian König struct amdgpu_vm *vm = drm_priv_to_vm(pdd->drm_priv);
2056bffa91daSChristian König uint64_t tlb_seq = amdgpu_vm_tlb_seq(vm);
20578dc1db31SMukul Joshi struct kfd_node *dev = pdd->dev;
2058c4050ff1SLijo Lazar uint32_t xcc_mask = dev->xcc_mask;
2059f87f6864SMukul Joshi int xcc = 0;
2060403575c4SFelix Kuehling
20618fde0248SPhilip Yang /*
20628fde0248SPhilip Yang * It can be that we race and lose here, but that is extremely unlikely
20638fde0248SPhilip Yang * and the worst thing which could happen is that we flush the changes
20648fde0248SPhilip Yang * into the TLB once more which is harmless.
20658fde0248SPhilip Yang */
kfd_flush_tlb(struct kfd_process_device * pdd,enum TLB_FLUSH_TYPE type)20668fde0248SPhilip Yang if (atomic64_xchg(&pdd->tlb_seq, tlb_seq) == tlb_seq)
2067bffa91daSChristian König return;
2068bffa91daSChristian König
2069403575c4SFelix Kuehling if (dev->dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) {
2070403575c4SFelix Kuehling /* Nothing to flush until a VMID is assigned, which
2071403575c4SFelix Kuehling * only happens when the first queue is created.
2072403575c4SFelix Kuehling */
2073403575c4SFelix Kuehling if (pdd->qpd.vmid)
20746bfc7c7eSGraham Sider amdgpu_amdkfd_flush_gpu_tlb_vmid(dev->adev,
2075ffa02269SAlex Sierra pdd->qpd.vmid);
2076403575c4SFelix Kuehling } else {
2077c4050ff1SLijo Lazar for_each_inst(xcc, xcc_mask)
2078c4050ff1SLijo Lazar amdgpu_amdkfd_flush_gpu_tlb_pasid(
2079c4050ff1SLijo Lazar dev->adev, pdd->process->pasid, type, xcc);
2080403575c4SFelix Kuehling }
2081403575c4SFelix Kuehling }
2082403575c4SFelix Kuehling
208312fb1ad7SJonathan Kim /* assumes caller holds process lock. */
208412fb1ad7SJonathan Kim int kfd_process_drain_interrupts(struct kfd_process_device *pdd)
208512fb1ad7SJonathan Kim {
208612fb1ad7SJonathan Kim uint32_t irq_drain_fence[8];
2087d4300362SMukul Joshi uint8_t node_id = 0;
208812fb1ad7SJonathan Kim int r = 0;
208912fb1ad7SJonathan Kim
209012fb1ad7SJonathan Kim if (!KFD_IS_SOC15(pdd->dev))
209112fb1ad7SJonathan Kim return 0;
209212fb1ad7SJonathan Kim
209312fb1ad7SJonathan Kim pdd->process->irq_drain_is_open = true;
209412fb1ad7SJonathan Kim
209512fb1ad7SJonathan Kim memset(irq_drain_fence, 0, sizeof(irq_drain_fence));
209612fb1ad7SJonathan Kim irq_drain_fence[0] = (KFD_IRQ_FENCE_SOURCEID << 8) |
kfd_process_drain_interrupts(struct kfd_process_device * pdd)209712fb1ad7SJonathan Kim KFD_IRQ_FENCE_CLIENTID;
209812fb1ad7SJonathan Kim irq_drain_fence[3] = pdd->process->pasid;
209912fb1ad7SJonathan Kim
2100d4300362SMukul Joshi /*
2101d4300362SMukul Joshi * For GFX 9.4.3, send the NodeId also in IH cookie DW[3]
2102d4300362SMukul Joshi */
2103d4300362SMukul Joshi if (KFD_GC_VERSION(pdd->dev->kfd) == IP_VERSION(9, 4, 3)) {
2104d4300362SMukul Joshi node_id = ffs(pdd->dev->interrupt_bitmap) - 1;
2105d4300362SMukul Joshi irq_drain_fence[3] |= node_id << 16;
2106d4300362SMukul Joshi }
2107d4300362SMukul Joshi
210812fb1ad7SJonathan Kim /* ensure stale irqs scheduled KFD interrupts and send drain fence. */
210912fb1ad7SJonathan Kim if (amdgpu_amdkfd_send_close_event_drain_irq(pdd->dev->adev,
211012fb1ad7SJonathan Kim irq_drain_fence)) {
211112fb1ad7SJonathan Kim pdd->process->irq_drain_is_open = false;
211212fb1ad7SJonathan Kim return 0;
211312fb1ad7SJonathan Kim }
211412fb1ad7SJonathan Kim
211512fb1ad7SJonathan Kim r = wait_event_interruptible(pdd->process->wait_irq_drain,
211612fb1ad7SJonathan Kim !READ_ONCE(pdd->process->irq_drain_is_open));
211712fb1ad7SJonathan Kim if (r)
211812fb1ad7SJonathan Kim pdd->process->irq_drain_is_open = false;
211912fb1ad7SJonathan Kim
212012fb1ad7SJonathan Kim return r;
212112fb1ad7SJonathan Kim }
212212fb1ad7SJonathan Kim
212312fb1ad7SJonathan Kim void kfd_process_close_interrupt_drain(unsigned int pasid)
212412fb1ad7SJonathan Kim {
212512fb1ad7SJonathan Kim struct kfd_process *p;
212612fb1ad7SJonathan Kim
212712fb1ad7SJonathan Kim p = kfd_lookup_process_by_pasid(pasid);
212812fb1ad7SJonathan Kim
212912fb1ad7SJonathan Kim if (!p)
213012fb1ad7SJonathan Kim return;
213112fb1ad7SJonathan Kim
213212fb1ad7SJonathan Kim WRITE_ONCE(p->irq_drain_is_open, false);
213312fb1ad7SJonathan Kim wake_up_all(&p->wait_irq_drain);
213412fb1ad7SJonathan Kim kfd_unref_process(p);
213512fb1ad7SJonathan Kim }
kfd_process_close_interrupt_drain(unsigned int pasid)213612fb1ad7SJonathan Kim
2137c2d2588cSJonathan Kim struct send_exception_work_handler_workarea {
2138c2d2588cSJonathan Kim struct work_struct work;
2139c2d2588cSJonathan Kim struct kfd_process *p;
2140c2d2588cSJonathan Kim unsigned int queue_id;
2141c2d2588cSJonathan Kim uint64_t error_reason;
2142c2d2588cSJonathan Kim };
2143c2d2588cSJonathan Kim
2144c2d2588cSJonathan Kim static void send_exception_work_handler(struct work_struct *work)
2145c2d2588cSJonathan Kim {
2146c2d2588cSJonathan Kim struct send_exception_work_handler_workarea *workarea;
2147c2d2588cSJonathan Kim struct kfd_process *p;
2148c2d2588cSJonathan Kim struct queue *q;
2149c2d2588cSJonathan Kim struct mm_struct *mm;
2150c2d2588cSJonathan Kim struct kfd_context_save_area_header __user *csa_header;
2151c2d2588cSJonathan Kim uint64_t __user *err_payload_ptr;
2152c2d2588cSJonathan Kim uint64_t cur_err;
2153c2d2588cSJonathan Kim uint32_t ev_id;
2154c2d2588cSJonathan Kim
2155c2d2588cSJonathan Kim workarea = container_of(work,
2156c2d2588cSJonathan Kim struct send_exception_work_handler_workarea,
send_exception_work_handler(struct work_struct * work)2157c2d2588cSJonathan Kim work);
2158c2d2588cSJonathan Kim p = workarea->p;
2159c2d2588cSJonathan Kim
2160c2d2588cSJonathan Kim mm = get_task_mm(p->lead_thread);
2161c2d2588cSJonathan Kim
2162c2d2588cSJonathan Kim if (!mm)
2163c2d2588cSJonathan Kim return;
2164c2d2588cSJonathan Kim
2165c2d2588cSJonathan Kim kthread_use_mm(mm);
2166c2d2588cSJonathan Kim
2167c2d2588cSJonathan Kim q = pqm_get_user_queue(&p->pqm, workarea->queue_id);
2168c2d2588cSJonathan Kim
2169c2d2588cSJonathan Kim if (!q)
2170c2d2588cSJonathan Kim goto out;
2171c2d2588cSJonathan Kim
2172c2d2588cSJonathan Kim csa_header = (void __user *)q->properties.ctx_save_restore_area_address;
2173c2d2588cSJonathan Kim
2174c2d2588cSJonathan Kim get_user(err_payload_ptr, (uint64_t __user **)&csa_header->err_payload_addr);
2175c2d2588cSJonathan Kim get_user(cur_err, err_payload_ptr);
2176c2d2588cSJonathan Kim cur_err |= workarea->error_reason;
2177c2d2588cSJonathan Kim put_user(cur_err, err_payload_ptr);
2178c2d2588cSJonathan Kim get_user(ev_id, &csa_header->err_event_id);
2179c2d2588cSJonathan Kim
2180c2d2588cSJonathan Kim kfd_set_event(p, ev_id);
2181c2d2588cSJonathan Kim
2182c2d2588cSJonathan Kim out:
2183c2d2588cSJonathan Kim kthread_unuse_mm(mm);
2184c2d2588cSJonathan Kim mmput(mm);
2185c2d2588cSJonathan Kim }
2186c2d2588cSJonathan Kim
2187c2d2588cSJonathan Kim int kfd_send_exception_to_runtime(struct kfd_process *p,
2188c2d2588cSJonathan Kim unsigned int queue_id,
2189c2d2588cSJonathan Kim uint64_t error_reason)
2190c2d2588cSJonathan Kim {
2191c2d2588cSJonathan Kim struct send_exception_work_handler_workarea worker;
2192c2d2588cSJonathan Kim
2193c2d2588cSJonathan Kim INIT_WORK_ONSTACK(&worker.work, send_exception_work_handler);
2194c2d2588cSJonathan Kim
2195c2d2588cSJonathan Kim worker.p = p;
2196c2d2588cSJonathan Kim worker.queue_id = queue_id;
2197c2d2588cSJonathan Kim worker.error_reason = error_reason;
2198c2d2588cSJonathan Kim
2199c2d2588cSJonathan Kim schedule_work(&worker.work);
kfd_send_exception_to_runtime(struct kfd_process * p,unsigned int queue_id,uint64_t error_reason)2200c2d2588cSJonathan Kim flush_work(&worker.work);
2201c2d2588cSJonathan Kim destroy_work_on_stack(&worker.work);
2202c2d2588cSJonathan Kim
2203c2d2588cSJonathan Kim return 0;
2204c2d2588cSJonathan Kim }
2205c2d2588cSJonathan Kim
2206bef153b7SDavid Yat Sin struct kfd_process_device *kfd_process_device_data_by_id(struct kfd_process *p, uint32_t gpu_id)
2207bef153b7SDavid Yat Sin {
2208bef153b7SDavid Yat Sin int i;
2209bef153b7SDavid Yat Sin
2210bef153b7SDavid Yat Sin if (gpu_id) {
2211bef153b7SDavid Yat Sin for (i = 0; i < p->n_pdds; i++) {
2212bef153b7SDavid Yat Sin struct kfd_process_device *pdd = p->pdds[i];
2213bef153b7SDavid Yat Sin
2214bef153b7SDavid Yat Sin if (pdd->user_gpu_id == gpu_id)
2215bef153b7SDavid Yat Sin return pdd;
2216bef153b7SDavid Yat Sin }
2217bef153b7SDavid Yat Sin }
2218bef153b7SDavid Yat Sin return NULL;
kfd_process_device_data_by_id(struct kfd_process * p,uint32_t gpu_id)2219bef153b7SDavid Yat Sin }
2220bef153b7SDavid Yat Sin
2221bef153b7SDavid Yat Sin int kfd_process_get_user_gpu_id(struct kfd_process *p, uint32_t actual_gpu_id)
2222bef153b7SDavid Yat Sin {
2223bef153b7SDavid Yat Sin int i;
2224bef153b7SDavid Yat Sin
2225bef153b7SDavid Yat Sin if (!actual_gpu_id)
2226bef153b7SDavid Yat Sin return 0;
2227bef153b7SDavid Yat Sin
2228bef153b7SDavid Yat Sin for (i = 0; i < p->n_pdds; i++) {
2229bef153b7SDavid Yat Sin struct kfd_process_device *pdd = p->pdds[i];
2230bef153b7SDavid Yat Sin
2231bef153b7SDavid Yat Sin if (pdd->dev->id == actual_gpu_id)
2232bef153b7SDavid Yat Sin return pdd->user_gpu_id;
2233bef153b7SDavid Yat Sin }
2234bef153b7SDavid Yat Sin return -EINVAL;
2235bef153b7SDavid Yat Sin }
2236bef153b7SDavid Yat Sin
2237851a645eSFelix Kuehling #if defined(CONFIG_DEBUG_FS)
2238851a645eSFelix Kuehling
2239851a645eSFelix Kuehling int kfd_debugfs_mqds_by_process(struct seq_file *m, void *data)
2240851a645eSFelix Kuehling {
2241851a645eSFelix Kuehling struct kfd_process *p;
2242851a645eSFelix Kuehling unsigned int temp;
2243851a645eSFelix Kuehling int r = 0;
2244851a645eSFelix Kuehling
2245851a645eSFelix Kuehling int idx = srcu_read_lock(&kfd_processes_srcu);
2246851a645eSFelix Kuehling
2247851a645eSFelix Kuehling hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) {
22486027b1bfSYong Zhao seq_printf(m, "Process %d PASID 0x%x:\n",
2249851a645eSFelix Kuehling p->lead_thread->tgid, p->pasid);
2250851a645eSFelix Kuehling
2251851a645eSFelix Kuehling mutex_lock(&p->mutex);
kfd_debugfs_mqds_by_process(struct seq_file * m,void * data)2252851a645eSFelix Kuehling r = pqm_debugfs_mqds(m, &p->pqm);
2253851a645eSFelix Kuehling mutex_unlock(&p->mutex);
2254851a645eSFelix Kuehling
2255851a645eSFelix Kuehling if (r)
2256851a645eSFelix Kuehling break;
2257851a645eSFelix Kuehling }
2258851a645eSFelix Kuehling
2259851a645eSFelix Kuehling srcu_read_unlock(&kfd_processes_srcu, idx);
2260851a645eSFelix Kuehling
2261851a645eSFelix Kuehling return r;
2262851a645eSFelix Kuehling }
2263851a645eSFelix Kuehling
2264851a645eSFelix Kuehling #endif
2265