xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/nouveau/nouveau_svm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright 2018 Red Hat Inc.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Permission is hereby granted, free of charge, to any person obtaining a
5*4882a593Smuzhiyun  * copy of this software and associated documentation files (the "Software"),
6*4882a593Smuzhiyun  * to deal in the Software without restriction, including without limitation
7*4882a593Smuzhiyun  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*4882a593Smuzhiyun  * and/or sell copies of the Software, and to permit persons to whom the
9*4882a593Smuzhiyun  * Software is furnished to do so, subject to the following conditions:
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * The above copyright notice and this permission notice shall be included in
12*4882a593Smuzhiyun  * all copies or substantial portions of the Software.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*4882a593Smuzhiyun  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17*4882a593Smuzhiyun  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18*4882a593Smuzhiyun  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19*4882a593Smuzhiyun  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20*4882a593Smuzhiyun  * OTHER DEALINGS IN THE SOFTWARE.
21*4882a593Smuzhiyun  */
22*4882a593Smuzhiyun #include "nouveau_svm.h"
23*4882a593Smuzhiyun #include "nouveau_drv.h"
24*4882a593Smuzhiyun #include "nouveau_chan.h"
25*4882a593Smuzhiyun #include "nouveau_dmem.h"
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include <nvif/notify.h>
28*4882a593Smuzhiyun #include <nvif/object.h>
29*4882a593Smuzhiyun #include <nvif/vmm.h>
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #include <nvif/class.h>
32*4882a593Smuzhiyun #include <nvif/clb069.h>
33*4882a593Smuzhiyun #include <nvif/ifc00d.h>
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #include <linux/sched/mm.h>
36*4882a593Smuzhiyun #include <linux/sort.h>
37*4882a593Smuzhiyun #include <linux/hmm.h>
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun struct nouveau_svm {
40*4882a593Smuzhiyun 	struct nouveau_drm *drm;
41*4882a593Smuzhiyun 	struct mutex mutex;
42*4882a593Smuzhiyun 	struct list_head inst;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	struct nouveau_svm_fault_buffer {
45*4882a593Smuzhiyun 		int id;
46*4882a593Smuzhiyun 		struct nvif_object object;
47*4882a593Smuzhiyun 		u32 entries;
48*4882a593Smuzhiyun 		u32 getaddr;
49*4882a593Smuzhiyun 		u32 putaddr;
50*4882a593Smuzhiyun 		u32 get;
51*4882a593Smuzhiyun 		u32 put;
52*4882a593Smuzhiyun 		struct nvif_notify notify;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 		struct nouveau_svm_fault {
55*4882a593Smuzhiyun 			u64 inst;
56*4882a593Smuzhiyun 			u64 addr;
57*4882a593Smuzhiyun 			u64 time;
58*4882a593Smuzhiyun 			u32 engine;
59*4882a593Smuzhiyun 			u8  gpc;
60*4882a593Smuzhiyun 			u8  hub;
61*4882a593Smuzhiyun 			u8  access;
62*4882a593Smuzhiyun 			u8  client;
63*4882a593Smuzhiyun 			u8  fault;
64*4882a593Smuzhiyun 			struct nouveau_svmm *svmm;
65*4882a593Smuzhiyun 		} **fault;
66*4882a593Smuzhiyun 		int fault_nr;
67*4882a593Smuzhiyun 	} buffer[1];
68*4882a593Smuzhiyun };
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun #define SVM_DBG(s,f,a...) NV_DEBUG((s)->drm, "svm: "f"\n", ##a)
71*4882a593Smuzhiyun #define SVM_ERR(s,f,a...) NV_WARN((s)->drm, "svm: "f"\n", ##a)
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun struct nouveau_pfnmap_args {
74*4882a593Smuzhiyun 	struct nvif_ioctl_v0 i;
75*4882a593Smuzhiyun 	struct nvif_ioctl_mthd_v0 m;
76*4882a593Smuzhiyun 	struct nvif_vmm_pfnmap_v0 p;
77*4882a593Smuzhiyun };
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun struct nouveau_ivmm {
80*4882a593Smuzhiyun 	struct nouveau_svmm *svmm;
81*4882a593Smuzhiyun 	u64 inst;
82*4882a593Smuzhiyun 	struct list_head head;
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun static struct nouveau_ivmm *
nouveau_ivmm_find(struct nouveau_svm * svm,u64 inst)86*4882a593Smuzhiyun nouveau_ivmm_find(struct nouveau_svm *svm, u64 inst)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	struct nouveau_ivmm *ivmm;
89*4882a593Smuzhiyun 	list_for_each_entry(ivmm, &svm->inst, head) {
90*4882a593Smuzhiyun 		if (ivmm->inst == inst)
91*4882a593Smuzhiyun 			return ivmm;
92*4882a593Smuzhiyun 	}
93*4882a593Smuzhiyun 	return NULL;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun #define SVMM_DBG(s,f,a...)                                                     \
97*4882a593Smuzhiyun 	NV_DEBUG((s)->vmm->cli->drm, "svm-%p: "f"\n", (s), ##a)
98*4882a593Smuzhiyun #define SVMM_ERR(s,f,a...)                                                     \
99*4882a593Smuzhiyun 	NV_WARN((s)->vmm->cli->drm, "svm-%p: "f"\n", (s), ##a)
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun int
nouveau_svmm_bind(struct drm_device * dev,void * data,struct drm_file * file_priv)102*4882a593Smuzhiyun nouveau_svmm_bind(struct drm_device *dev, void *data,
103*4882a593Smuzhiyun 		  struct drm_file *file_priv)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	struct nouveau_cli *cli = nouveau_cli(file_priv);
106*4882a593Smuzhiyun 	struct drm_nouveau_svm_bind *args = data;
107*4882a593Smuzhiyun 	unsigned target, cmd, priority;
108*4882a593Smuzhiyun 	unsigned long addr, end;
109*4882a593Smuzhiyun 	struct mm_struct *mm;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	args->va_start &= PAGE_MASK;
112*4882a593Smuzhiyun 	args->va_end = ALIGN(args->va_end, PAGE_SIZE);
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	/* Sanity check arguments */
115*4882a593Smuzhiyun 	if (args->reserved0 || args->reserved1)
116*4882a593Smuzhiyun 		return -EINVAL;
117*4882a593Smuzhiyun 	if (args->header & (~NOUVEAU_SVM_BIND_VALID_MASK))
118*4882a593Smuzhiyun 		return -EINVAL;
119*4882a593Smuzhiyun 	if (args->va_start >= args->va_end)
120*4882a593Smuzhiyun 		return -EINVAL;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	cmd = args->header >> NOUVEAU_SVM_BIND_COMMAND_SHIFT;
123*4882a593Smuzhiyun 	cmd &= NOUVEAU_SVM_BIND_COMMAND_MASK;
124*4882a593Smuzhiyun 	switch (cmd) {
125*4882a593Smuzhiyun 	case NOUVEAU_SVM_BIND_COMMAND__MIGRATE:
126*4882a593Smuzhiyun 		break;
127*4882a593Smuzhiyun 	default:
128*4882a593Smuzhiyun 		return -EINVAL;
129*4882a593Smuzhiyun 	}
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	priority = args->header >> NOUVEAU_SVM_BIND_PRIORITY_SHIFT;
132*4882a593Smuzhiyun 	priority &= NOUVEAU_SVM_BIND_PRIORITY_MASK;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	/* FIXME support CPU target ie all target value < GPU_VRAM */
135*4882a593Smuzhiyun 	target = args->header >> NOUVEAU_SVM_BIND_TARGET_SHIFT;
136*4882a593Smuzhiyun 	target &= NOUVEAU_SVM_BIND_TARGET_MASK;
137*4882a593Smuzhiyun 	switch (target) {
138*4882a593Smuzhiyun 	case NOUVEAU_SVM_BIND_TARGET__GPU_VRAM:
139*4882a593Smuzhiyun 		break;
140*4882a593Smuzhiyun 	default:
141*4882a593Smuzhiyun 		return -EINVAL;
142*4882a593Smuzhiyun 	}
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	/*
145*4882a593Smuzhiyun 	 * FIXME: For now refuse non 0 stride, we need to change the migrate
146*4882a593Smuzhiyun 	 * kernel function to handle stride to avoid to create a mess within
147*4882a593Smuzhiyun 	 * each device driver.
148*4882a593Smuzhiyun 	 */
149*4882a593Smuzhiyun 	if (args->stride)
150*4882a593Smuzhiyun 		return -EINVAL;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	/*
153*4882a593Smuzhiyun 	 * Ok we are ask to do something sane, for now we only support migrate
154*4882a593Smuzhiyun 	 * commands but we will add things like memory policy (what to do on
155*4882a593Smuzhiyun 	 * page fault) and maybe some other commands.
156*4882a593Smuzhiyun 	 */
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	mm = get_task_mm(current);
159*4882a593Smuzhiyun 	if (!mm) {
160*4882a593Smuzhiyun 		return -EINVAL;
161*4882a593Smuzhiyun 	}
162*4882a593Smuzhiyun 	mmap_read_lock(mm);
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (!cli->svm.svmm) {
165*4882a593Smuzhiyun 		mmap_read_unlock(mm);
166*4882a593Smuzhiyun 		mmput(mm);
167*4882a593Smuzhiyun 		return -EINVAL;
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	for (addr = args->va_start, end = args->va_end; addr < end;) {
171*4882a593Smuzhiyun 		struct vm_area_struct *vma;
172*4882a593Smuzhiyun 		unsigned long next;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 		vma = find_vma_intersection(mm, addr, end);
175*4882a593Smuzhiyun 		if (!vma)
176*4882a593Smuzhiyun 			break;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 		addr = max(addr, vma->vm_start);
179*4882a593Smuzhiyun 		next = min(vma->vm_end, end);
180*4882a593Smuzhiyun 		/* This is a best effort so we ignore errors */
181*4882a593Smuzhiyun 		nouveau_dmem_migrate_vma(cli->drm, cli->svm.svmm, vma, addr,
182*4882a593Smuzhiyun 					 next);
183*4882a593Smuzhiyun 		addr = next;
184*4882a593Smuzhiyun 	}
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	/*
187*4882a593Smuzhiyun 	 * FIXME Return the number of page we have migrated, again we need to
188*4882a593Smuzhiyun 	 * update the migrate API to return that information so that we can
189*4882a593Smuzhiyun 	 * report it to user space.
190*4882a593Smuzhiyun 	 */
191*4882a593Smuzhiyun 	args->result = 0;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	mmap_read_unlock(mm);
194*4882a593Smuzhiyun 	mmput(mm);
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	return 0;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun /* Unlink channel instance from SVMM. */
200*4882a593Smuzhiyun void
nouveau_svmm_part(struct nouveau_svmm * svmm,u64 inst)201*4882a593Smuzhiyun nouveau_svmm_part(struct nouveau_svmm *svmm, u64 inst)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	struct nouveau_ivmm *ivmm;
204*4882a593Smuzhiyun 	if (svmm) {
205*4882a593Smuzhiyun 		mutex_lock(&svmm->vmm->cli->drm->svm->mutex);
206*4882a593Smuzhiyun 		ivmm = nouveau_ivmm_find(svmm->vmm->cli->drm->svm, inst);
207*4882a593Smuzhiyun 		if (ivmm) {
208*4882a593Smuzhiyun 			list_del(&ivmm->head);
209*4882a593Smuzhiyun 			kfree(ivmm);
210*4882a593Smuzhiyun 		}
211*4882a593Smuzhiyun 		mutex_unlock(&svmm->vmm->cli->drm->svm->mutex);
212*4882a593Smuzhiyun 	}
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun /* Link channel instance to SVMM. */
216*4882a593Smuzhiyun int
nouveau_svmm_join(struct nouveau_svmm * svmm,u64 inst)217*4882a593Smuzhiyun nouveau_svmm_join(struct nouveau_svmm *svmm, u64 inst)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun 	struct nouveau_ivmm *ivmm;
220*4882a593Smuzhiyun 	if (svmm) {
221*4882a593Smuzhiyun 		if (!(ivmm = kmalloc(sizeof(*ivmm), GFP_KERNEL)))
222*4882a593Smuzhiyun 			return -ENOMEM;
223*4882a593Smuzhiyun 		ivmm->svmm = svmm;
224*4882a593Smuzhiyun 		ivmm->inst = inst;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 		mutex_lock(&svmm->vmm->cli->drm->svm->mutex);
227*4882a593Smuzhiyun 		list_add(&ivmm->head, &svmm->vmm->cli->drm->svm->inst);
228*4882a593Smuzhiyun 		mutex_unlock(&svmm->vmm->cli->drm->svm->mutex);
229*4882a593Smuzhiyun 	}
230*4882a593Smuzhiyun 	return 0;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun /* Invalidate SVMM address-range on GPU. */
234*4882a593Smuzhiyun void
nouveau_svmm_invalidate(struct nouveau_svmm * svmm,u64 start,u64 limit)235*4882a593Smuzhiyun nouveau_svmm_invalidate(struct nouveau_svmm *svmm, u64 start, u64 limit)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	if (limit > start) {
238*4882a593Smuzhiyun 		bool super = svmm->vmm->vmm.object.client->super;
239*4882a593Smuzhiyun 		svmm->vmm->vmm.object.client->super = true;
240*4882a593Smuzhiyun 		nvif_object_mthd(&svmm->vmm->vmm.object, NVIF_VMM_V0_PFNCLR,
241*4882a593Smuzhiyun 				 &(struct nvif_vmm_pfnclr_v0) {
242*4882a593Smuzhiyun 					.addr = start,
243*4882a593Smuzhiyun 					.size = limit - start,
244*4882a593Smuzhiyun 				 }, sizeof(struct nvif_vmm_pfnclr_v0));
245*4882a593Smuzhiyun 		svmm->vmm->vmm.object.client->super = super;
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun static int
nouveau_svmm_invalidate_range_start(struct mmu_notifier * mn,const struct mmu_notifier_range * update)250*4882a593Smuzhiyun nouveau_svmm_invalidate_range_start(struct mmu_notifier *mn,
251*4882a593Smuzhiyun 				    const struct mmu_notifier_range *update)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun 	struct nouveau_svmm *svmm =
254*4882a593Smuzhiyun 		container_of(mn, struct nouveau_svmm, notifier);
255*4882a593Smuzhiyun 	unsigned long start = update->start;
256*4882a593Smuzhiyun 	unsigned long limit = update->end;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	if (!mmu_notifier_range_blockable(update))
259*4882a593Smuzhiyun 		return -EAGAIN;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	SVMM_DBG(svmm, "invalidate %016lx-%016lx", start, limit);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	mutex_lock(&svmm->mutex);
264*4882a593Smuzhiyun 	if (unlikely(!svmm->vmm))
265*4882a593Smuzhiyun 		goto out;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	/*
268*4882a593Smuzhiyun 	 * Ignore invalidation callbacks for device private pages since
269*4882a593Smuzhiyun 	 * the invalidation is handled as part of the migration process.
270*4882a593Smuzhiyun 	 */
271*4882a593Smuzhiyun 	if (update->event == MMU_NOTIFY_MIGRATE &&
272*4882a593Smuzhiyun 	    update->migrate_pgmap_owner == svmm->vmm->cli->drm->dev)
273*4882a593Smuzhiyun 		goto out;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	if (limit > svmm->unmanaged.start && start < svmm->unmanaged.limit) {
276*4882a593Smuzhiyun 		if (start < svmm->unmanaged.start) {
277*4882a593Smuzhiyun 			nouveau_svmm_invalidate(svmm, start,
278*4882a593Smuzhiyun 						svmm->unmanaged.limit);
279*4882a593Smuzhiyun 		}
280*4882a593Smuzhiyun 		start = svmm->unmanaged.limit;
281*4882a593Smuzhiyun 	}
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	nouveau_svmm_invalidate(svmm, start, limit);
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun out:
286*4882a593Smuzhiyun 	mutex_unlock(&svmm->mutex);
287*4882a593Smuzhiyun 	return 0;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun 
nouveau_svmm_free_notifier(struct mmu_notifier * mn)290*4882a593Smuzhiyun static void nouveau_svmm_free_notifier(struct mmu_notifier *mn)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun 	kfree(container_of(mn, struct nouveau_svmm, notifier));
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun static const struct mmu_notifier_ops nouveau_mn_ops = {
296*4882a593Smuzhiyun 	.invalidate_range_start = nouveau_svmm_invalidate_range_start,
297*4882a593Smuzhiyun 	.free_notifier = nouveau_svmm_free_notifier,
298*4882a593Smuzhiyun };
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun void
nouveau_svmm_fini(struct nouveau_svmm ** psvmm)301*4882a593Smuzhiyun nouveau_svmm_fini(struct nouveau_svmm **psvmm)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	struct nouveau_svmm *svmm = *psvmm;
304*4882a593Smuzhiyun 	if (svmm) {
305*4882a593Smuzhiyun 		mutex_lock(&svmm->mutex);
306*4882a593Smuzhiyun 		svmm->vmm = NULL;
307*4882a593Smuzhiyun 		mutex_unlock(&svmm->mutex);
308*4882a593Smuzhiyun 		mmu_notifier_put(&svmm->notifier);
309*4882a593Smuzhiyun 		*psvmm = NULL;
310*4882a593Smuzhiyun 	}
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun int
nouveau_svmm_init(struct drm_device * dev,void * data,struct drm_file * file_priv)314*4882a593Smuzhiyun nouveau_svmm_init(struct drm_device *dev, void *data,
315*4882a593Smuzhiyun 		  struct drm_file *file_priv)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun 	struct nouveau_cli *cli = nouveau_cli(file_priv);
318*4882a593Smuzhiyun 	struct nouveau_svmm *svmm;
319*4882a593Smuzhiyun 	struct drm_nouveau_svm_init *args = data;
320*4882a593Smuzhiyun 	int ret;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	/* We need to fail if svm is disabled */
323*4882a593Smuzhiyun 	if (!cli->drm->svm)
324*4882a593Smuzhiyun 		return -ENOSYS;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	/* Allocate tracking for SVM-enabled VMM. */
327*4882a593Smuzhiyun 	if (!(svmm = kzalloc(sizeof(*svmm), GFP_KERNEL)))
328*4882a593Smuzhiyun 		return -ENOMEM;
329*4882a593Smuzhiyun 	svmm->vmm = &cli->svm;
330*4882a593Smuzhiyun 	svmm->unmanaged.start = args->unmanaged_addr;
331*4882a593Smuzhiyun 	svmm->unmanaged.limit = args->unmanaged_addr + args->unmanaged_size;
332*4882a593Smuzhiyun 	mutex_init(&svmm->mutex);
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	/* Check that SVM isn't already enabled for the client. */
335*4882a593Smuzhiyun 	mutex_lock(&cli->mutex);
336*4882a593Smuzhiyun 	if (cli->svm.cli) {
337*4882a593Smuzhiyun 		ret = -EBUSY;
338*4882a593Smuzhiyun 		goto out_free;
339*4882a593Smuzhiyun 	}
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	/* Allocate a new GPU VMM that can support SVM (managed by the
342*4882a593Smuzhiyun 	 * client, with replayable faults enabled).
343*4882a593Smuzhiyun 	 *
344*4882a593Smuzhiyun 	 * All future channel/memory allocations will make use of this
345*4882a593Smuzhiyun 	 * VMM instead of the standard one.
346*4882a593Smuzhiyun 	 */
347*4882a593Smuzhiyun 	ret = nvif_vmm_ctor(&cli->mmu, "svmVmm",
348*4882a593Smuzhiyun 			    cli->vmm.vmm.object.oclass, true,
349*4882a593Smuzhiyun 			    args->unmanaged_addr, args->unmanaged_size,
350*4882a593Smuzhiyun 			    &(struct gp100_vmm_v0) {
351*4882a593Smuzhiyun 				.fault_replay = true,
352*4882a593Smuzhiyun 			    }, sizeof(struct gp100_vmm_v0), &cli->svm.vmm);
353*4882a593Smuzhiyun 	if (ret)
354*4882a593Smuzhiyun 		goto out_free;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	mmap_write_lock(current->mm);
357*4882a593Smuzhiyun 	svmm->notifier.ops = &nouveau_mn_ops;
358*4882a593Smuzhiyun 	ret = __mmu_notifier_register(&svmm->notifier, current->mm);
359*4882a593Smuzhiyun 	if (ret)
360*4882a593Smuzhiyun 		goto out_mm_unlock;
361*4882a593Smuzhiyun 	/* Note, ownership of svmm transfers to mmu_notifier */
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	cli->svm.svmm = svmm;
364*4882a593Smuzhiyun 	cli->svm.cli = cli;
365*4882a593Smuzhiyun 	mmap_write_unlock(current->mm);
366*4882a593Smuzhiyun 	mutex_unlock(&cli->mutex);
367*4882a593Smuzhiyun 	return 0;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun out_mm_unlock:
370*4882a593Smuzhiyun 	mmap_write_unlock(current->mm);
371*4882a593Smuzhiyun out_free:
372*4882a593Smuzhiyun 	mutex_unlock(&cli->mutex);
373*4882a593Smuzhiyun 	kfree(svmm);
374*4882a593Smuzhiyun 	return ret;
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun /* Issue fault replay for GPU to retry accesses that faulted previously. */
378*4882a593Smuzhiyun static void
nouveau_svm_fault_replay(struct nouveau_svm * svm)379*4882a593Smuzhiyun nouveau_svm_fault_replay(struct nouveau_svm *svm)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun 	SVM_DBG(svm, "replay");
382*4882a593Smuzhiyun 	WARN_ON(nvif_object_mthd(&svm->drm->client.vmm.vmm.object,
383*4882a593Smuzhiyun 				 GP100_VMM_VN_FAULT_REPLAY,
384*4882a593Smuzhiyun 				 &(struct gp100_vmm_fault_replay_vn) {},
385*4882a593Smuzhiyun 				 sizeof(struct gp100_vmm_fault_replay_vn)));
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun /* Cancel a replayable fault that could not be handled.
389*4882a593Smuzhiyun  *
390*4882a593Smuzhiyun  * Cancelling the fault will trigger recovery to reset the engine
391*4882a593Smuzhiyun  * and kill the offending channel (ie. GPU SIGSEGV).
392*4882a593Smuzhiyun  */
393*4882a593Smuzhiyun static void
nouveau_svm_fault_cancel(struct nouveau_svm * svm,u64 inst,u8 hub,u8 gpc,u8 client)394*4882a593Smuzhiyun nouveau_svm_fault_cancel(struct nouveau_svm *svm,
395*4882a593Smuzhiyun 			 u64 inst, u8 hub, u8 gpc, u8 client)
396*4882a593Smuzhiyun {
397*4882a593Smuzhiyun 	SVM_DBG(svm, "cancel %016llx %d %02x %02x", inst, hub, gpc, client);
398*4882a593Smuzhiyun 	WARN_ON(nvif_object_mthd(&svm->drm->client.vmm.vmm.object,
399*4882a593Smuzhiyun 				 GP100_VMM_VN_FAULT_CANCEL,
400*4882a593Smuzhiyun 				 &(struct gp100_vmm_fault_cancel_v0) {
401*4882a593Smuzhiyun 					.hub = hub,
402*4882a593Smuzhiyun 					.gpc = gpc,
403*4882a593Smuzhiyun 					.client = client,
404*4882a593Smuzhiyun 					.inst = inst,
405*4882a593Smuzhiyun 				 }, sizeof(struct gp100_vmm_fault_cancel_v0)));
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun static void
nouveau_svm_fault_cancel_fault(struct nouveau_svm * svm,struct nouveau_svm_fault * fault)409*4882a593Smuzhiyun nouveau_svm_fault_cancel_fault(struct nouveau_svm *svm,
410*4882a593Smuzhiyun 			       struct nouveau_svm_fault *fault)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun 	nouveau_svm_fault_cancel(svm, fault->inst,
413*4882a593Smuzhiyun 				      fault->hub,
414*4882a593Smuzhiyun 				      fault->gpc,
415*4882a593Smuzhiyun 				      fault->client);
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun static int
nouveau_svm_fault_cmp(const void * a,const void * b)419*4882a593Smuzhiyun nouveau_svm_fault_cmp(const void *a, const void *b)
420*4882a593Smuzhiyun {
421*4882a593Smuzhiyun 	const struct nouveau_svm_fault *fa = *(struct nouveau_svm_fault **)a;
422*4882a593Smuzhiyun 	const struct nouveau_svm_fault *fb = *(struct nouveau_svm_fault **)b;
423*4882a593Smuzhiyun 	int ret;
424*4882a593Smuzhiyun 	if ((ret = (s64)fa->inst - fb->inst))
425*4882a593Smuzhiyun 		return ret;
426*4882a593Smuzhiyun 	if ((ret = (s64)fa->addr - fb->addr))
427*4882a593Smuzhiyun 		return ret;
428*4882a593Smuzhiyun 	/*XXX: atomic? */
429*4882a593Smuzhiyun 	return (fa->access == 0 || fa->access == 3) -
430*4882a593Smuzhiyun 	       (fb->access == 0 || fb->access == 3);
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun static void
nouveau_svm_fault_cache(struct nouveau_svm * svm,struct nouveau_svm_fault_buffer * buffer,u32 offset)434*4882a593Smuzhiyun nouveau_svm_fault_cache(struct nouveau_svm *svm,
435*4882a593Smuzhiyun 			struct nouveau_svm_fault_buffer *buffer, u32 offset)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun 	struct nvif_object *memory = &buffer->object;
438*4882a593Smuzhiyun 	const u32 instlo = nvif_rd32(memory, offset + 0x00);
439*4882a593Smuzhiyun 	const u32 insthi = nvif_rd32(memory, offset + 0x04);
440*4882a593Smuzhiyun 	const u32 addrlo = nvif_rd32(memory, offset + 0x08);
441*4882a593Smuzhiyun 	const u32 addrhi = nvif_rd32(memory, offset + 0x0c);
442*4882a593Smuzhiyun 	const u32 timelo = nvif_rd32(memory, offset + 0x10);
443*4882a593Smuzhiyun 	const u32 timehi = nvif_rd32(memory, offset + 0x14);
444*4882a593Smuzhiyun 	const u32 engine = nvif_rd32(memory, offset + 0x18);
445*4882a593Smuzhiyun 	const u32   info = nvif_rd32(memory, offset + 0x1c);
446*4882a593Smuzhiyun 	const u64   inst = (u64)insthi << 32 | instlo;
447*4882a593Smuzhiyun 	const u8     gpc = (info & 0x1f000000) >> 24;
448*4882a593Smuzhiyun 	const u8     hub = (info & 0x00100000) >> 20;
449*4882a593Smuzhiyun 	const u8  client = (info & 0x00007f00) >> 8;
450*4882a593Smuzhiyun 	struct nouveau_svm_fault *fault;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	//XXX: i think we're supposed to spin waiting */
453*4882a593Smuzhiyun 	if (WARN_ON(!(info & 0x80000000)))
454*4882a593Smuzhiyun 		return;
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	nvif_mask(memory, offset + 0x1c, 0x80000000, 0x00000000);
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	if (!buffer->fault[buffer->fault_nr]) {
459*4882a593Smuzhiyun 		fault = kmalloc(sizeof(*fault), GFP_KERNEL);
460*4882a593Smuzhiyun 		if (WARN_ON(!fault)) {
461*4882a593Smuzhiyun 			nouveau_svm_fault_cancel(svm, inst, hub, gpc, client);
462*4882a593Smuzhiyun 			return;
463*4882a593Smuzhiyun 		}
464*4882a593Smuzhiyun 		buffer->fault[buffer->fault_nr] = fault;
465*4882a593Smuzhiyun 	}
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	fault = buffer->fault[buffer->fault_nr++];
468*4882a593Smuzhiyun 	fault->inst   = inst;
469*4882a593Smuzhiyun 	fault->addr   = (u64)addrhi << 32 | addrlo;
470*4882a593Smuzhiyun 	fault->time   = (u64)timehi << 32 | timelo;
471*4882a593Smuzhiyun 	fault->engine = engine;
472*4882a593Smuzhiyun 	fault->gpc    = gpc;
473*4882a593Smuzhiyun 	fault->hub    = hub;
474*4882a593Smuzhiyun 	fault->access = (info & 0x000f0000) >> 16;
475*4882a593Smuzhiyun 	fault->client = client;
476*4882a593Smuzhiyun 	fault->fault  = (info & 0x0000001f);
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	SVM_DBG(svm, "fault %016llx %016llx %02x",
479*4882a593Smuzhiyun 		fault->inst, fault->addr, fault->access);
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun struct svm_notifier {
483*4882a593Smuzhiyun 	struct mmu_interval_notifier notifier;
484*4882a593Smuzhiyun 	struct nouveau_svmm *svmm;
485*4882a593Smuzhiyun };
486*4882a593Smuzhiyun 
nouveau_svm_range_invalidate(struct mmu_interval_notifier * mni,const struct mmu_notifier_range * range,unsigned long cur_seq)487*4882a593Smuzhiyun static bool nouveau_svm_range_invalidate(struct mmu_interval_notifier *mni,
488*4882a593Smuzhiyun 					 const struct mmu_notifier_range *range,
489*4882a593Smuzhiyun 					 unsigned long cur_seq)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun 	struct svm_notifier *sn =
492*4882a593Smuzhiyun 		container_of(mni, struct svm_notifier, notifier);
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	/*
495*4882a593Smuzhiyun 	 * serializes the update to mni->invalidate_seq done by caller and
496*4882a593Smuzhiyun 	 * prevents invalidation of the PTE from progressing while HW is being
497*4882a593Smuzhiyun 	 * programmed. This is very hacky and only works because the normal
498*4882a593Smuzhiyun 	 * notifier that does invalidation is always called after the range
499*4882a593Smuzhiyun 	 * notifier.
500*4882a593Smuzhiyun 	 */
501*4882a593Smuzhiyun 	if (mmu_notifier_range_blockable(range))
502*4882a593Smuzhiyun 		mutex_lock(&sn->svmm->mutex);
503*4882a593Smuzhiyun 	else if (!mutex_trylock(&sn->svmm->mutex))
504*4882a593Smuzhiyun 		return false;
505*4882a593Smuzhiyun 	mmu_interval_set_seq(mni, cur_seq);
506*4882a593Smuzhiyun 	mutex_unlock(&sn->svmm->mutex);
507*4882a593Smuzhiyun 	return true;
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun static const struct mmu_interval_notifier_ops nouveau_svm_mni_ops = {
511*4882a593Smuzhiyun 	.invalidate = nouveau_svm_range_invalidate,
512*4882a593Smuzhiyun };
513*4882a593Smuzhiyun 
nouveau_hmm_convert_pfn(struct nouveau_drm * drm,struct hmm_range * range,struct nouveau_pfnmap_args * args)514*4882a593Smuzhiyun static void nouveau_hmm_convert_pfn(struct nouveau_drm *drm,
515*4882a593Smuzhiyun 				    struct hmm_range *range,
516*4882a593Smuzhiyun 				    struct nouveau_pfnmap_args *args)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun 	struct page *page;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	/*
521*4882a593Smuzhiyun 	 * The address prepared here is passed through nvif_object_ioctl()
522*4882a593Smuzhiyun 	 * to an eventual DMA map in something like gp100_vmm_pgt_pfn()
523*4882a593Smuzhiyun 	 *
524*4882a593Smuzhiyun 	 * This is all just encoding the internal hmm representation into a
525*4882a593Smuzhiyun 	 * different nouveau internal representation.
526*4882a593Smuzhiyun 	 */
527*4882a593Smuzhiyun 	if (!(range->hmm_pfns[0] & HMM_PFN_VALID)) {
528*4882a593Smuzhiyun 		args->p.phys[0] = 0;
529*4882a593Smuzhiyun 		return;
530*4882a593Smuzhiyun 	}
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	page = hmm_pfn_to_page(range->hmm_pfns[0]);
533*4882a593Smuzhiyun 	/*
534*4882a593Smuzhiyun 	 * Only map compound pages to the GPU if the CPU is also mapping the
535*4882a593Smuzhiyun 	 * page as a compound page. Otherwise, the PTE protections might not be
536*4882a593Smuzhiyun 	 * consistent (e.g., CPU only maps part of a compound page).
537*4882a593Smuzhiyun 	 * Note that the underlying page might still be larger than the
538*4882a593Smuzhiyun 	 * CPU mapping (e.g., a PUD sized compound page partially mapped with
539*4882a593Smuzhiyun 	 * a PMD sized page table entry).
540*4882a593Smuzhiyun 	 */
541*4882a593Smuzhiyun 	if (hmm_pfn_to_map_order(range->hmm_pfns[0])) {
542*4882a593Smuzhiyun 		unsigned long addr = args->p.addr;
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 		args->p.page = hmm_pfn_to_map_order(range->hmm_pfns[0]) +
545*4882a593Smuzhiyun 				PAGE_SHIFT;
546*4882a593Smuzhiyun 		args->p.size = 1UL << args->p.page;
547*4882a593Smuzhiyun 		args->p.addr &= ~(args->p.size - 1);
548*4882a593Smuzhiyun 		page -= (addr - args->p.addr) >> PAGE_SHIFT;
549*4882a593Smuzhiyun 	}
550*4882a593Smuzhiyun 	if (is_device_private_page(page))
551*4882a593Smuzhiyun 		args->p.phys[0] = nouveau_dmem_page_addr(page) |
552*4882a593Smuzhiyun 				NVIF_VMM_PFNMAP_V0_V |
553*4882a593Smuzhiyun 				NVIF_VMM_PFNMAP_V0_VRAM;
554*4882a593Smuzhiyun 	else
555*4882a593Smuzhiyun 		args->p.phys[0] = page_to_phys(page) |
556*4882a593Smuzhiyun 				NVIF_VMM_PFNMAP_V0_V |
557*4882a593Smuzhiyun 				NVIF_VMM_PFNMAP_V0_HOST;
558*4882a593Smuzhiyun 	if (range->hmm_pfns[0] & HMM_PFN_WRITE)
559*4882a593Smuzhiyun 		args->p.phys[0] |= NVIF_VMM_PFNMAP_V0_W;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun 
nouveau_range_fault(struct nouveau_svmm * svmm,struct nouveau_drm * drm,struct nouveau_pfnmap_args * args,u32 size,unsigned long hmm_flags,struct svm_notifier * notifier)562*4882a593Smuzhiyun static int nouveau_range_fault(struct nouveau_svmm *svmm,
563*4882a593Smuzhiyun 			       struct nouveau_drm *drm,
564*4882a593Smuzhiyun 			       struct nouveau_pfnmap_args *args, u32 size,
565*4882a593Smuzhiyun 			       unsigned long hmm_flags,
566*4882a593Smuzhiyun 			       struct svm_notifier *notifier)
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun 	unsigned long timeout =
569*4882a593Smuzhiyun 		jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
570*4882a593Smuzhiyun 	/* Have HMM fault pages within the fault window to the GPU. */
571*4882a593Smuzhiyun 	unsigned long hmm_pfns[1];
572*4882a593Smuzhiyun 	struct hmm_range range = {
573*4882a593Smuzhiyun 		.notifier = &notifier->notifier,
574*4882a593Smuzhiyun 		.start = notifier->notifier.interval_tree.start,
575*4882a593Smuzhiyun 		.end = notifier->notifier.interval_tree.last + 1,
576*4882a593Smuzhiyun 		.default_flags = hmm_flags,
577*4882a593Smuzhiyun 		.hmm_pfns = hmm_pfns,
578*4882a593Smuzhiyun 		.dev_private_owner = drm->dev,
579*4882a593Smuzhiyun 	};
580*4882a593Smuzhiyun 	struct mm_struct *mm = notifier->notifier.mm;
581*4882a593Smuzhiyun 	int ret;
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	while (true) {
584*4882a593Smuzhiyun 		if (time_after(jiffies, timeout))
585*4882a593Smuzhiyun 			return -EBUSY;
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 		range.notifier_seq = mmu_interval_read_begin(range.notifier);
588*4882a593Smuzhiyun 		mmap_read_lock(mm);
589*4882a593Smuzhiyun 		ret = hmm_range_fault(&range);
590*4882a593Smuzhiyun 		mmap_read_unlock(mm);
591*4882a593Smuzhiyun 		if (ret) {
592*4882a593Smuzhiyun 			if (ret == -EBUSY)
593*4882a593Smuzhiyun 				continue;
594*4882a593Smuzhiyun 			return ret;
595*4882a593Smuzhiyun 		}
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 		mutex_lock(&svmm->mutex);
598*4882a593Smuzhiyun 		if (mmu_interval_read_retry(range.notifier,
599*4882a593Smuzhiyun 					    range.notifier_seq)) {
600*4882a593Smuzhiyun 			mutex_unlock(&svmm->mutex);
601*4882a593Smuzhiyun 			continue;
602*4882a593Smuzhiyun 		}
603*4882a593Smuzhiyun 		break;
604*4882a593Smuzhiyun 	}
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	nouveau_hmm_convert_pfn(drm, &range, args);
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	svmm->vmm->vmm.object.client->super = true;
609*4882a593Smuzhiyun 	ret = nvif_object_ioctl(&svmm->vmm->vmm.object, args, size, NULL);
610*4882a593Smuzhiyun 	svmm->vmm->vmm.object.client->super = false;
611*4882a593Smuzhiyun 	mutex_unlock(&svmm->mutex);
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	return ret;
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun static int
nouveau_svm_fault(struct nvif_notify * notify)617*4882a593Smuzhiyun nouveau_svm_fault(struct nvif_notify *notify)
618*4882a593Smuzhiyun {
619*4882a593Smuzhiyun 	struct nouveau_svm_fault_buffer *buffer =
620*4882a593Smuzhiyun 		container_of(notify, typeof(*buffer), notify);
621*4882a593Smuzhiyun 	struct nouveau_svm *svm =
622*4882a593Smuzhiyun 		container_of(buffer, typeof(*svm), buffer[buffer->id]);
623*4882a593Smuzhiyun 	struct nvif_object *device = &svm->drm->client.device.object;
624*4882a593Smuzhiyun 	struct nouveau_svmm *svmm;
625*4882a593Smuzhiyun 	struct {
626*4882a593Smuzhiyun 		struct nouveau_pfnmap_args i;
627*4882a593Smuzhiyun 		u64 phys[1];
628*4882a593Smuzhiyun 	} args;
629*4882a593Smuzhiyun 	unsigned long hmm_flags;
630*4882a593Smuzhiyun 	u64 inst, start, limit;
631*4882a593Smuzhiyun 	int fi, fn;
632*4882a593Smuzhiyun 	int replay = 0, ret;
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	/* Parse available fault buffer entries into a cache, and update
635*4882a593Smuzhiyun 	 * the GET pointer so HW can reuse the entries.
636*4882a593Smuzhiyun 	 */
637*4882a593Smuzhiyun 	SVM_DBG(svm, "fault handler");
638*4882a593Smuzhiyun 	if (buffer->get == buffer->put) {
639*4882a593Smuzhiyun 		buffer->put = nvif_rd32(device, buffer->putaddr);
640*4882a593Smuzhiyun 		buffer->get = nvif_rd32(device, buffer->getaddr);
641*4882a593Smuzhiyun 		if (buffer->get == buffer->put)
642*4882a593Smuzhiyun 			return NVIF_NOTIFY_KEEP;
643*4882a593Smuzhiyun 	}
644*4882a593Smuzhiyun 	buffer->fault_nr = 0;
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 	SVM_DBG(svm, "get %08x put %08x", buffer->get, buffer->put);
647*4882a593Smuzhiyun 	while (buffer->get != buffer->put) {
648*4882a593Smuzhiyun 		nouveau_svm_fault_cache(svm, buffer, buffer->get * 0x20);
649*4882a593Smuzhiyun 		if (++buffer->get == buffer->entries)
650*4882a593Smuzhiyun 			buffer->get = 0;
651*4882a593Smuzhiyun 	}
652*4882a593Smuzhiyun 	nvif_wr32(device, buffer->getaddr, buffer->get);
653*4882a593Smuzhiyun 	SVM_DBG(svm, "%d fault(s) pending", buffer->fault_nr);
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	/* Sort parsed faults by instance pointer to prevent unnecessary
656*4882a593Smuzhiyun 	 * instance to SVMM translations, followed by address and access
657*4882a593Smuzhiyun 	 * type to reduce the amount of work when handling the faults.
658*4882a593Smuzhiyun 	 */
659*4882a593Smuzhiyun 	sort(buffer->fault, buffer->fault_nr, sizeof(*buffer->fault),
660*4882a593Smuzhiyun 	     nouveau_svm_fault_cmp, NULL);
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	/* Lookup SVMM structure for each unique instance pointer. */
663*4882a593Smuzhiyun 	mutex_lock(&svm->mutex);
664*4882a593Smuzhiyun 	for (fi = 0, svmm = NULL; fi < buffer->fault_nr; fi++) {
665*4882a593Smuzhiyun 		if (!svmm || buffer->fault[fi]->inst != inst) {
666*4882a593Smuzhiyun 			struct nouveau_ivmm *ivmm =
667*4882a593Smuzhiyun 				nouveau_ivmm_find(svm, buffer->fault[fi]->inst);
668*4882a593Smuzhiyun 			svmm = ivmm ? ivmm->svmm : NULL;
669*4882a593Smuzhiyun 			inst = buffer->fault[fi]->inst;
670*4882a593Smuzhiyun 			SVM_DBG(svm, "inst %016llx -> svm-%p", inst, svmm);
671*4882a593Smuzhiyun 		}
672*4882a593Smuzhiyun 		buffer->fault[fi]->svmm = svmm;
673*4882a593Smuzhiyun 	}
674*4882a593Smuzhiyun 	mutex_unlock(&svm->mutex);
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	/* Process list of faults. */
677*4882a593Smuzhiyun 	args.i.i.version = 0;
678*4882a593Smuzhiyun 	args.i.i.type = NVIF_IOCTL_V0_MTHD;
679*4882a593Smuzhiyun 	args.i.m.version = 0;
680*4882a593Smuzhiyun 	args.i.m.method = NVIF_VMM_V0_PFNMAP;
681*4882a593Smuzhiyun 	args.i.p.version = 0;
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	for (fi = 0; fn = fi + 1, fi < buffer->fault_nr; fi = fn) {
684*4882a593Smuzhiyun 		struct svm_notifier notifier;
685*4882a593Smuzhiyun 		struct mm_struct *mm;
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 		/* Cancel any faults from non-SVM channels. */
688*4882a593Smuzhiyun 		if (!(svmm = buffer->fault[fi]->svmm)) {
689*4882a593Smuzhiyun 			nouveau_svm_fault_cancel_fault(svm, buffer->fault[fi]);
690*4882a593Smuzhiyun 			continue;
691*4882a593Smuzhiyun 		}
692*4882a593Smuzhiyun 		SVMM_DBG(svmm, "addr %016llx", buffer->fault[fi]->addr);
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 		/* We try and group handling of faults within a small
695*4882a593Smuzhiyun 		 * window into a single update.
696*4882a593Smuzhiyun 		 */
697*4882a593Smuzhiyun 		start = buffer->fault[fi]->addr;
698*4882a593Smuzhiyun 		limit = start + PAGE_SIZE;
699*4882a593Smuzhiyun 		if (start < svmm->unmanaged.limit)
700*4882a593Smuzhiyun 			limit = min_t(u64, limit, svmm->unmanaged.start);
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 		/*
703*4882a593Smuzhiyun 		 * Prepare the GPU-side update of all pages within the
704*4882a593Smuzhiyun 		 * fault window, determining required pages and access
705*4882a593Smuzhiyun 		 * permissions based on pending faults.
706*4882a593Smuzhiyun 		 */
707*4882a593Smuzhiyun 		args.i.p.addr = start;
708*4882a593Smuzhiyun 		args.i.p.page = PAGE_SHIFT;
709*4882a593Smuzhiyun 		args.i.p.size = PAGE_SIZE;
710*4882a593Smuzhiyun 		/*
711*4882a593Smuzhiyun 		 * Determine required permissions based on GPU fault
712*4882a593Smuzhiyun 		 * access flags.
713*4882a593Smuzhiyun 		 * XXX: atomic?
714*4882a593Smuzhiyun 		 */
715*4882a593Smuzhiyun 		switch (buffer->fault[fi]->access) {
716*4882a593Smuzhiyun 		case 0: /* READ. */
717*4882a593Smuzhiyun 			hmm_flags = HMM_PFN_REQ_FAULT;
718*4882a593Smuzhiyun 			break;
719*4882a593Smuzhiyun 		case 3: /* PREFETCH. */
720*4882a593Smuzhiyun 			hmm_flags = 0;
721*4882a593Smuzhiyun 			break;
722*4882a593Smuzhiyun 		default:
723*4882a593Smuzhiyun 			hmm_flags = HMM_PFN_REQ_FAULT | HMM_PFN_REQ_WRITE;
724*4882a593Smuzhiyun 			break;
725*4882a593Smuzhiyun 		}
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 		mm = svmm->notifier.mm;
728*4882a593Smuzhiyun 		if (!mmget_not_zero(mm)) {
729*4882a593Smuzhiyun 			nouveau_svm_fault_cancel_fault(svm, buffer->fault[fi]);
730*4882a593Smuzhiyun 			continue;
731*4882a593Smuzhiyun 		}
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 		notifier.svmm = svmm;
734*4882a593Smuzhiyun 		ret = mmu_interval_notifier_insert(&notifier.notifier, mm,
735*4882a593Smuzhiyun 						   args.i.p.addr, args.i.p.size,
736*4882a593Smuzhiyun 						   &nouveau_svm_mni_ops);
737*4882a593Smuzhiyun 		if (!ret) {
738*4882a593Smuzhiyun 			ret = nouveau_range_fault(svmm, svm->drm, &args.i,
739*4882a593Smuzhiyun 				sizeof(args), hmm_flags, &notifier);
740*4882a593Smuzhiyun 			mmu_interval_notifier_remove(&notifier.notifier);
741*4882a593Smuzhiyun 		}
742*4882a593Smuzhiyun 		mmput(mm);
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun 		limit = args.i.p.addr + args.i.p.size;
745*4882a593Smuzhiyun 		for (fn = fi; ++fn < buffer->fault_nr; ) {
746*4882a593Smuzhiyun 			/* It's okay to skip over duplicate addresses from the
747*4882a593Smuzhiyun 			 * same SVMM as faults are ordered by access type such
748*4882a593Smuzhiyun 			 * that only the first one needs to be handled.
749*4882a593Smuzhiyun 			 *
750*4882a593Smuzhiyun 			 * ie. WRITE faults appear first, thus any handling of
751*4882a593Smuzhiyun 			 * pending READ faults will already be satisfied.
752*4882a593Smuzhiyun 			 * But if a large page is mapped, make sure subsequent
753*4882a593Smuzhiyun 			 * fault addresses have sufficient access permission.
754*4882a593Smuzhiyun 			 */
755*4882a593Smuzhiyun 			if (buffer->fault[fn]->svmm != svmm ||
756*4882a593Smuzhiyun 			    buffer->fault[fn]->addr >= limit ||
757*4882a593Smuzhiyun 			    (buffer->fault[fi]->access == 0 /* READ. */ &&
758*4882a593Smuzhiyun 			     !(args.phys[0] & NVIF_VMM_PFNMAP_V0_V)) ||
759*4882a593Smuzhiyun 			    (buffer->fault[fi]->access != 0 /* READ. */ &&
760*4882a593Smuzhiyun 			     buffer->fault[fi]->access != 3 /* PREFETCH. */ &&
761*4882a593Smuzhiyun 			     !(args.phys[0] & NVIF_VMM_PFNMAP_V0_W)))
762*4882a593Smuzhiyun 				break;
763*4882a593Smuzhiyun 		}
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun 		/* If handling failed completely, cancel all faults. */
766*4882a593Smuzhiyun 		if (ret) {
767*4882a593Smuzhiyun 			while (fi < fn) {
768*4882a593Smuzhiyun 				struct nouveau_svm_fault *fault =
769*4882a593Smuzhiyun 					buffer->fault[fi++];
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun 				nouveau_svm_fault_cancel_fault(svm, fault);
772*4882a593Smuzhiyun 			}
773*4882a593Smuzhiyun 		} else
774*4882a593Smuzhiyun 			replay++;
775*4882a593Smuzhiyun 	}
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 	/* Issue fault replay to the GPU. */
778*4882a593Smuzhiyun 	if (replay)
779*4882a593Smuzhiyun 		nouveau_svm_fault_replay(svm);
780*4882a593Smuzhiyun 	return NVIF_NOTIFY_KEEP;
781*4882a593Smuzhiyun }
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun static struct nouveau_pfnmap_args *
nouveau_pfns_to_args(void * pfns)784*4882a593Smuzhiyun nouveau_pfns_to_args(void *pfns)
785*4882a593Smuzhiyun {
786*4882a593Smuzhiyun 	return container_of(pfns, struct nouveau_pfnmap_args, p.phys);
787*4882a593Smuzhiyun }
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun u64 *
nouveau_pfns_alloc(unsigned long npages)790*4882a593Smuzhiyun nouveau_pfns_alloc(unsigned long npages)
791*4882a593Smuzhiyun {
792*4882a593Smuzhiyun 	struct nouveau_pfnmap_args *args;
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 	args = kzalloc(struct_size(args, p.phys, npages), GFP_KERNEL);
795*4882a593Smuzhiyun 	if (!args)
796*4882a593Smuzhiyun 		return NULL;
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	args->i.type = NVIF_IOCTL_V0_MTHD;
799*4882a593Smuzhiyun 	args->m.method = NVIF_VMM_V0_PFNMAP;
800*4882a593Smuzhiyun 	args->p.page = PAGE_SHIFT;
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun 	return args->p.phys;
803*4882a593Smuzhiyun }
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun void
nouveau_pfns_free(u64 * pfns)806*4882a593Smuzhiyun nouveau_pfns_free(u64 *pfns)
807*4882a593Smuzhiyun {
808*4882a593Smuzhiyun 	struct nouveau_pfnmap_args *args = nouveau_pfns_to_args(pfns);
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	kfree(args);
811*4882a593Smuzhiyun }
812*4882a593Smuzhiyun 
813*4882a593Smuzhiyun void
nouveau_pfns_map(struct nouveau_svmm * svmm,struct mm_struct * mm,unsigned long addr,u64 * pfns,unsigned long npages)814*4882a593Smuzhiyun nouveau_pfns_map(struct nouveau_svmm *svmm, struct mm_struct *mm,
815*4882a593Smuzhiyun 		 unsigned long addr, u64 *pfns, unsigned long npages)
816*4882a593Smuzhiyun {
817*4882a593Smuzhiyun 	struct nouveau_pfnmap_args *args = nouveau_pfns_to_args(pfns);
818*4882a593Smuzhiyun 	int ret;
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun 	args->p.addr = addr;
821*4882a593Smuzhiyun 	args->p.size = npages << PAGE_SHIFT;
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun 	mutex_lock(&svmm->mutex);
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun 	svmm->vmm->vmm.object.client->super = true;
826*4882a593Smuzhiyun 	ret = nvif_object_ioctl(&svmm->vmm->vmm.object, args, sizeof(*args) +
827*4882a593Smuzhiyun 				npages * sizeof(args->p.phys[0]), NULL);
828*4882a593Smuzhiyun 	svmm->vmm->vmm.object.client->super = false;
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 	mutex_unlock(&svmm->mutex);
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun static void
nouveau_svm_fault_buffer_fini(struct nouveau_svm * svm,int id)834*4882a593Smuzhiyun nouveau_svm_fault_buffer_fini(struct nouveau_svm *svm, int id)
835*4882a593Smuzhiyun {
836*4882a593Smuzhiyun 	struct nouveau_svm_fault_buffer *buffer = &svm->buffer[id];
837*4882a593Smuzhiyun 	nvif_notify_put(&buffer->notify);
838*4882a593Smuzhiyun }
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun static int
nouveau_svm_fault_buffer_init(struct nouveau_svm * svm,int id)841*4882a593Smuzhiyun nouveau_svm_fault_buffer_init(struct nouveau_svm *svm, int id)
842*4882a593Smuzhiyun {
843*4882a593Smuzhiyun 	struct nouveau_svm_fault_buffer *buffer = &svm->buffer[id];
844*4882a593Smuzhiyun 	struct nvif_object *device = &svm->drm->client.device.object;
845*4882a593Smuzhiyun 	buffer->get = nvif_rd32(device, buffer->getaddr);
846*4882a593Smuzhiyun 	buffer->put = nvif_rd32(device, buffer->putaddr);
847*4882a593Smuzhiyun 	SVM_DBG(svm, "get %08x put %08x (init)", buffer->get, buffer->put);
848*4882a593Smuzhiyun 	return nvif_notify_get(&buffer->notify);
849*4882a593Smuzhiyun }
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun static void
nouveau_svm_fault_buffer_dtor(struct nouveau_svm * svm,int id)852*4882a593Smuzhiyun nouveau_svm_fault_buffer_dtor(struct nouveau_svm *svm, int id)
853*4882a593Smuzhiyun {
854*4882a593Smuzhiyun 	struct nouveau_svm_fault_buffer *buffer = &svm->buffer[id];
855*4882a593Smuzhiyun 	int i;
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	if (buffer->fault) {
858*4882a593Smuzhiyun 		for (i = 0; buffer->fault[i] && i < buffer->entries; i++)
859*4882a593Smuzhiyun 			kfree(buffer->fault[i]);
860*4882a593Smuzhiyun 		kvfree(buffer->fault);
861*4882a593Smuzhiyun 	}
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	nouveau_svm_fault_buffer_fini(svm, id);
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun 	nvif_notify_dtor(&buffer->notify);
866*4882a593Smuzhiyun 	nvif_object_dtor(&buffer->object);
867*4882a593Smuzhiyun }
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun static int
nouveau_svm_fault_buffer_ctor(struct nouveau_svm * svm,s32 oclass,int id)870*4882a593Smuzhiyun nouveau_svm_fault_buffer_ctor(struct nouveau_svm *svm, s32 oclass, int id)
871*4882a593Smuzhiyun {
872*4882a593Smuzhiyun 	struct nouveau_svm_fault_buffer *buffer = &svm->buffer[id];
873*4882a593Smuzhiyun 	struct nouveau_drm *drm = svm->drm;
874*4882a593Smuzhiyun 	struct nvif_object *device = &drm->client.device.object;
875*4882a593Smuzhiyun 	struct nvif_clb069_v0 args = {};
876*4882a593Smuzhiyun 	int ret;
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun 	buffer->id = id;
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun 	ret = nvif_object_ctor(device, "svmFaultBuffer", 0, oclass, &args,
881*4882a593Smuzhiyun 			       sizeof(args), &buffer->object);
882*4882a593Smuzhiyun 	if (ret < 0) {
883*4882a593Smuzhiyun 		SVM_ERR(svm, "Fault buffer allocation failed: %d", ret);
884*4882a593Smuzhiyun 		return ret;
885*4882a593Smuzhiyun 	}
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun 	nvif_object_map(&buffer->object, NULL, 0);
888*4882a593Smuzhiyun 	buffer->entries = args.entries;
889*4882a593Smuzhiyun 	buffer->getaddr = args.get;
890*4882a593Smuzhiyun 	buffer->putaddr = args.put;
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun 	ret = nvif_notify_ctor(&buffer->object, "svmFault", nouveau_svm_fault,
893*4882a593Smuzhiyun 			       true, NVB069_V0_NTFY_FAULT, NULL, 0, 0,
894*4882a593Smuzhiyun 			       &buffer->notify);
895*4882a593Smuzhiyun 	if (ret)
896*4882a593Smuzhiyun 		return ret;
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 	buffer->fault = kvzalloc(sizeof(*buffer->fault) * buffer->entries, GFP_KERNEL);
899*4882a593Smuzhiyun 	if (!buffer->fault)
900*4882a593Smuzhiyun 		return -ENOMEM;
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun 	return nouveau_svm_fault_buffer_init(svm, id);
903*4882a593Smuzhiyun }
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun void
nouveau_svm_resume(struct nouveau_drm * drm)906*4882a593Smuzhiyun nouveau_svm_resume(struct nouveau_drm *drm)
907*4882a593Smuzhiyun {
908*4882a593Smuzhiyun 	struct nouveau_svm *svm = drm->svm;
909*4882a593Smuzhiyun 	if (svm)
910*4882a593Smuzhiyun 		nouveau_svm_fault_buffer_init(svm, 0);
911*4882a593Smuzhiyun }
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun void
nouveau_svm_suspend(struct nouveau_drm * drm)914*4882a593Smuzhiyun nouveau_svm_suspend(struct nouveau_drm *drm)
915*4882a593Smuzhiyun {
916*4882a593Smuzhiyun 	struct nouveau_svm *svm = drm->svm;
917*4882a593Smuzhiyun 	if (svm)
918*4882a593Smuzhiyun 		nouveau_svm_fault_buffer_fini(svm, 0);
919*4882a593Smuzhiyun }
920*4882a593Smuzhiyun 
921*4882a593Smuzhiyun void
nouveau_svm_fini(struct nouveau_drm * drm)922*4882a593Smuzhiyun nouveau_svm_fini(struct nouveau_drm *drm)
923*4882a593Smuzhiyun {
924*4882a593Smuzhiyun 	struct nouveau_svm *svm = drm->svm;
925*4882a593Smuzhiyun 	if (svm) {
926*4882a593Smuzhiyun 		nouveau_svm_fault_buffer_dtor(svm, 0);
927*4882a593Smuzhiyun 		kfree(drm->svm);
928*4882a593Smuzhiyun 		drm->svm = NULL;
929*4882a593Smuzhiyun 	}
930*4882a593Smuzhiyun }
931*4882a593Smuzhiyun 
932*4882a593Smuzhiyun void
nouveau_svm_init(struct nouveau_drm * drm)933*4882a593Smuzhiyun nouveau_svm_init(struct nouveau_drm *drm)
934*4882a593Smuzhiyun {
935*4882a593Smuzhiyun 	static const struct nvif_mclass buffers[] = {
936*4882a593Smuzhiyun 		{   VOLTA_FAULT_BUFFER_A, 0 },
937*4882a593Smuzhiyun 		{ MAXWELL_FAULT_BUFFER_A, 0 },
938*4882a593Smuzhiyun 		{}
939*4882a593Smuzhiyun 	};
940*4882a593Smuzhiyun 	struct nouveau_svm *svm;
941*4882a593Smuzhiyun 	int ret;
942*4882a593Smuzhiyun 
943*4882a593Smuzhiyun 	/* Disable on Volta and newer until channel recovery is fixed,
944*4882a593Smuzhiyun 	 * otherwise clients will have a trivial way to trash the GPU
945*4882a593Smuzhiyun 	 * for everyone.
946*4882a593Smuzhiyun 	 */
947*4882a593Smuzhiyun 	if (drm->client.device.info.family > NV_DEVICE_INFO_V0_PASCAL)
948*4882a593Smuzhiyun 		return;
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun 	if (!(drm->svm = svm = kzalloc(sizeof(*drm->svm), GFP_KERNEL)))
951*4882a593Smuzhiyun 		return;
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun 	drm->svm->drm = drm;
954*4882a593Smuzhiyun 	mutex_init(&drm->svm->mutex);
955*4882a593Smuzhiyun 	INIT_LIST_HEAD(&drm->svm->inst);
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun 	ret = nvif_mclass(&drm->client.device.object, buffers);
958*4882a593Smuzhiyun 	if (ret < 0) {
959*4882a593Smuzhiyun 		SVM_DBG(svm, "No supported fault buffer class");
960*4882a593Smuzhiyun 		nouveau_svm_fini(drm);
961*4882a593Smuzhiyun 		return;
962*4882a593Smuzhiyun 	}
963*4882a593Smuzhiyun 
964*4882a593Smuzhiyun 	ret = nouveau_svm_fault_buffer_ctor(svm, buffers[ret].oclass, 0);
965*4882a593Smuzhiyun 	if (ret) {
966*4882a593Smuzhiyun 		nouveau_svm_fini(drm);
967*4882a593Smuzhiyun 		return;
968*4882a593Smuzhiyun 	}
969*4882a593Smuzhiyun 
970*4882a593Smuzhiyun 	SVM_DBG(svm, "Initialised");
971*4882a593Smuzhiyun }
972