xref: /openbmc/linux/drivers/gpu/drm/amd/amdkfd/kfd_process.c (revision ed4543328f7108e1047b83b96ca7f7208747d930)
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