Blame view

drivers/vfio/vfio_iommu_type1.c 59.8 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2
3
4
5
6
7
  /*
   * VFIO: IOMMU DMA mapping support for Type1 IOMMU
   *
   * Copyright (C) 2012 Red Hat, Inc.  All rights reserved.
   *     Author: Alex Williamson <alex.williamson@redhat.com>
   *
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
   * Derived from original vfio:
   * Copyright 2010 Cisco Systems, Inc.  All rights reserved.
   * Author: Tom Lyon, pugs@cisco.com
   *
   * We arbitrarily define a Type1 IOMMU as one matching the below code.
   * It could be called the x86 IOMMU as it's designed for AMD-Vi & Intel
   * VT-d, but that makes it harder to re-use as theoretically anyone
   * implementing a similar IOMMU could make use of this.  We expect the
   * IOMMU to support the IOMMU API and have few to no restrictions around
   * the IOVA range that can be mapped.  The Type1 IOMMU is currently
   * optimized for relatively static mappings of a userspace process with
   * userpsace pages pinned into memory.  We also assume devices and IOMMU
   * domains are PCI based as the IOMMU API is still centered around a
   * device/bus interface rather than a group interface.
   */
  
  #include <linux/compat.h>
  #include <linux/device.h>
  #include <linux/fs.h>
  #include <linux/iommu.h>
  #include <linux/module.h>
  #include <linux/mm.h>
cd9b22685   Alex Williamson   vfio: Convert typ...
30
  #include <linux/rbtree.h>
3f07c0144   Ingo Molnar   sched/headers: Pr...
31
  #include <linux/sched/signal.h>
6e84f3152   Ingo Molnar   sched/headers: Pr...
32
  #include <linux/sched/mm.h>
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
33
34
35
36
  #include <linux/slab.h>
  #include <linux/uaccess.h>
  #include <linux/vfio.h>
  #include <linux/workqueue.h>
a54eb5504   Kirti Wankhede   vfio iommu type1:...
37
  #include <linux/mdev.h>
c086de818   Kirti Wankhede   vfio iommu: Add b...
38
  #include <linux/notifier.h>
5d7049921   Eric Auger   vfio/type1: Allow...
39
  #include <linux/dma-iommu.h>
9d72f87ba   Eric Auger   vfio/type1: Check...
40
  #include <linux/irqdomain.h>
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
41
42
43
44
45
46
47
48
49
50
  
  #define DRIVER_VERSION  "0.2"
  #define DRIVER_AUTHOR   "Alex Williamson <alex.williamson@redhat.com>"
  #define DRIVER_DESC     "Type1 IOMMU driver for VFIO"
  
  static bool allow_unsafe_interrupts;
  module_param_named(allow_unsafe_interrupts,
  		   allow_unsafe_interrupts, bool, S_IRUGO | S_IWUSR);
  MODULE_PARM_DESC(allow_unsafe_interrupts,
  		 "Enable VFIO IOMMU support for on platforms without interrupt remapping support.");
5c6c2b21e   Alex Williamson   vfio: Provide mod...
51
52
53
54
55
  static bool disable_hugepages;
  module_param_named(disable_hugepages,
  		   disable_hugepages, bool, S_IRUGO | S_IWUSR);
  MODULE_PARM_DESC(disable_hugepages,
  		 "Disable VFIO IOMMU support for IOMMU hugepages.");
492855939   Alex Williamson   vfio/type1: Limit...
56
57
58
59
  static unsigned int dma_entry_limit __read_mostly = U16_MAX;
  module_param_named(dma_entry_limit, dma_entry_limit, uint, 0644);
  MODULE_PARM_DESC(dma_entry_limit,
  		 "Maximum number of user DMA mappings per container (65535).");
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
60
  struct vfio_iommu {
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
61
  	struct list_head	domain_list;
1108696ae   Shameer Kolothum   vfio/type1: Intro...
62
  	struct list_head	iova_list;
a54eb5504   Kirti Wankhede   vfio iommu type1:...
63
  	struct vfio_domain	*external_domain; /* domain for external user */
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
64
  	struct mutex		lock;
cd9b22685   Alex Williamson   vfio: Convert typ...
65
  	struct rb_root		dma_list;
c086de818   Kirti Wankhede   vfio iommu: Add b...
66
  	struct blocking_notifier_head notifier;
492855939   Alex Williamson   vfio/type1: Limit...
67
  	unsigned int		dma_avail;
f5c9eceba   Will Deacon   vfio/iommu_type1:...
68
69
  	bool			v2;
  	bool			nesting;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
70
71
72
73
74
  };
  
  struct vfio_domain {
  	struct iommu_domain	*domain;
  	struct list_head	next;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
75
  	struct list_head	group_list;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
76
  	int			prot;		/* IOMMU_CACHE */
6fe1010d6   Alex Williamson   vfio/type1: DMA u...
77
  	bool			fgsp;		/* Fine-grained super pages */
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
78
79
80
  };
  
  struct vfio_dma {
cd9b22685   Alex Williamson   vfio: Convert typ...
81
  	struct rb_node		node;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
82
83
  	dma_addr_t		iova;		/* Device address */
  	unsigned long		vaddr;		/* Process virtual addr */
166fd7d94   Alex Williamson   vfio: hugepage su...
84
  	size_t			size;		/* Map size (bytes) */
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
85
  	int			prot;		/* IOMMU_READ/WRITE */
a54eb5504   Kirti Wankhede   vfio iommu type1:...
86
  	bool			iommu_mapped;
48d8476b4   Alex Williamson   vfio/type1: Fix t...
87
  	bool			lock_cap;	/* capable(CAP_IPC_LOCK) */
8f0d5bb95   Kirti Wankhede   vfio iommu type1:...
88
  	struct task_struct	*task;
a54eb5504   Kirti Wankhede   vfio iommu type1:...
89
  	struct rb_root		pfn_list;	/* Ex-user pinned pfn list */
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
90
91
92
93
94
  };
  
  struct vfio_group {
  	struct iommu_group	*iommu_group;
  	struct list_head	next;
7bd50f0cd   Lu Baolu   vfio/type1: Add d...
95
  	bool			mdev_group;	/* An mdev group */
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
96
  };
1108696ae   Shameer Kolothum   vfio/type1: Intro...
97
98
99
100
101
  struct vfio_iova {
  	struct list_head	list;
  	dma_addr_t		start;
  	dma_addr_t		end;
  };
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
102
  /*
a54eb5504   Kirti Wankhede   vfio iommu type1:...
103
104
105
106
107
108
109
110
   * Guest RAM pinning working set or DMA target
   */
  struct vfio_pfn {
  	struct rb_node		node;
  	dma_addr_t		iova;		/* Device address */
  	unsigned long		pfn;		/* Host pfn */
  	atomic_t		ref_count;
  };
6bd06f5a4   Suravee Suthikulpanit   vfio/type1: Adopt...
111
112
113
114
115
116
  struct vfio_regions {
  	struct list_head list;
  	dma_addr_t iova;
  	phys_addr_t phys;
  	size_t len;
  };
a54eb5504   Kirti Wankhede   vfio iommu type1:...
117
118
119
120
121
122
  #define IS_IOMMU_CAP_DOMAIN_IN_CONTAINER(iommu)	\
  					(!list_empty(&iommu->domain_list))
  
  static int put_pfn(unsigned long pfn, int prot);
  
  /*
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
123
124
125
   * This code handles mapping and unmapping of user data buffers
   * into DMA'ble space using the IOMMU
   */
cd9b22685   Alex Williamson   vfio: Convert typ...
126
127
128
129
130
131
132
133
134
135
  static struct vfio_dma *vfio_find_dma(struct vfio_iommu *iommu,
  				      dma_addr_t start, size_t size)
  {
  	struct rb_node *node = iommu->dma_list.rb_node;
  
  	while (node) {
  		struct vfio_dma *dma = rb_entry(node, struct vfio_dma, node);
  
  		if (start + size <= dma->iova)
  			node = node->rb_left;
166fd7d94   Alex Williamson   vfio: hugepage su...
136
  		else if (start >= dma->iova + dma->size)
cd9b22685   Alex Williamson   vfio: Convert typ...
137
138
139
140
141
142
143
  			node = node->rb_right;
  		else
  			return dma;
  	}
  
  	return NULL;
  }
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
144
  static void vfio_link_dma(struct vfio_iommu *iommu, struct vfio_dma *new)
cd9b22685   Alex Williamson   vfio: Convert typ...
145
146
147
148
149
150
151
  {
  	struct rb_node **link = &iommu->dma_list.rb_node, *parent = NULL;
  	struct vfio_dma *dma;
  
  	while (*link) {
  		parent = *link;
  		dma = rb_entry(parent, struct vfio_dma, node);
166fd7d94   Alex Williamson   vfio: hugepage su...
152
  		if (new->iova + new->size <= dma->iova)
cd9b22685   Alex Williamson   vfio: Convert typ...
153
154
155
156
157
158
159
160
  			link = &(*link)->rb_left;
  		else
  			link = &(*link)->rb_right;
  	}
  
  	rb_link_node(&new->node, parent, link);
  	rb_insert_color(&new->node, &iommu->dma_list);
  }
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
161
  static void vfio_unlink_dma(struct vfio_iommu *iommu, struct vfio_dma *old)
cd9b22685   Alex Williamson   vfio: Convert typ...
162
163
164
  {
  	rb_erase(&old->node, &iommu->dma_list);
  }
a54eb5504   Kirti Wankhede   vfio iommu type1:...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  /*
   * Helper Functions for host iova-pfn list
   */
  static struct vfio_pfn *vfio_find_vpfn(struct vfio_dma *dma, dma_addr_t iova)
  {
  	struct vfio_pfn *vpfn;
  	struct rb_node *node = dma->pfn_list.rb_node;
  
  	while (node) {
  		vpfn = rb_entry(node, struct vfio_pfn, node);
  
  		if (iova < vpfn->iova)
  			node = node->rb_left;
  		else if (iova > vpfn->iova)
  			node = node->rb_right;
  		else
  			return vpfn;
  	}
  	return NULL;
  }
  
  static void vfio_link_pfn(struct vfio_dma *dma,
  			  struct vfio_pfn *new)
  {
  	struct rb_node **link, *parent = NULL;
  	struct vfio_pfn *vpfn;
  
  	link = &dma->pfn_list.rb_node;
  	while (*link) {
  		parent = *link;
  		vpfn = rb_entry(parent, struct vfio_pfn, node);
  
  		if (new->iova < vpfn->iova)
  			link = &(*link)->rb_left;
  		else
  			link = &(*link)->rb_right;
  	}
  
  	rb_link_node(&new->node, parent, link);
  	rb_insert_color(&new->node, &dma->pfn_list);
  }
  
  static void vfio_unlink_pfn(struct vfio_dma *dma, struct vfio_pfn *old)
  {
  	rb_erase(&old->node, &dma->pfn_list);
  }
  
  static int vfio_add_to_pfn_list(struct vfio_dma *dma, dma_addr_t iova,
  				unsigned long pfn)
  {
  	struct vfio_pfn *vpfn;
  
  	vpfn = kzalloc(sizeof(*vpfn), GFP_KERNEL);
  	if (!vpfn)
  		return -ENOMEM;
  
  	vpfn->iova = iova;
  	vpfn->pfn = pfn;
  	atomic_set(&vpfn->ref_count, 1);
  	vfio_link_pfn(dma, vpfn);
  	return 0;
  }
  
  static void vfio_remove_from_pfn_list(struct vfio_dma *dma,
  				      struct vfio_pfn *vpfn)
  {
  	vfio_unlink_pfn(dma, vpfn);
  	kfree(vpfn);
  }
  
  static struct vfio_pfn *vfio_iova_get_vfio_pfn(struct vfio_dma *dma,
  					       unsigned long iova)
  {
  	struct vfio_pfn *vpfn = vfio_find_vpfn(dma, iova);
  
  	if (vpfn)
  		atomic_inc(&vpfn->ref_count);
  	return vpfn;
  }
  
  static int vfio_iova_put_vfio_pfn(struct vfio_dma *dma, struct vfio_pfn *vpfn)
  {
  	int ret = 0;
  
  	if (atomic_dec_and_test(&vpfn->ref_count)) {
  		ret = put_pfn(vpfn->pfn, dma->prot);
  		vfio_remove_from_pfn_list(dma, vpfn);
  	}
  	return ret;
  }
48d8476b4   Alex Williamson   vfio/type1: Fix t...
255
  static int vfio_lock_acct(struct vfio_dma *dma, long npage, bool async)
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
256
  {
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
257
  	struct mm_struct *mm;
0cfef2b74   Alex Williamson   vfio/type1: Remov...
258
  	int ret;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
259

3624a2486   Kirti Wankhede   vfio iommu type1:...
260
  	if (!npage)
0cfef2b74   Alex Williamson   vfio/type1: Remov...
261
  		return 0;
3624a2486   Kirti Wankhede   vfio iommu type1:...
262

48d8476b4   Alex Williamson   vfio/type1: Fix t...
263
  	mm = async ? get_task_mm(dma->task) : dma->task->mm;
3624a2486   Kirti Wankhede   vfio iommu type1:...
264
  	if (!mm)
0cfef2b74   Alex Williamson   vfio/type1: Remov...
265
  		return -ESRCH; /* process exited */
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
266

0cfef2b74   Alex Williamson   vfio/type1: Remov...
267
268
  	ret = down_write_killable(&mm->mmap_sem);
  	if (!ret) {
79eb597cb   Daniel Jordan   mm: add account_l...
269
270
  		ret = __account_locked_vm(mm, abs(npage), npage > 0, dma->task,
  					  dma->lock_cap);
0cfef2b74   Alex Williamson   vfio/type1: Remov...
271
  		up_write(&mm->mmap_sem);
6c38c055c   Alex Williamson   vfio/type1: Resto...
272
  	}
48d8476b4   Alex Williamson   vfio/type1: Fix t...
273
  	if (async)
3624a2486   Kirti Wankhede   vfio iommu type1:...
274
  		mmput(mm);
0cfef2b74   Alex Williamson   vfio/type1: Remov...
275
276
  
  	return ret;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
277
278
279
280
281
282
283
284
285
286
287
288
  }
  
  /*
   * Some mappings aren't backed by a struct page, for example an mmap'd
   * MMIO range for our own or another device.  These use a different
   * pfn conversion and shouldn't be tracked as locked pages.
   */
  static bool is_invalid_reserved_pfn(unsigned long pfn)
  {
  	if (pfn_valid(pfn)) {
  		bool reserved;
  		struct page *tail = pfn_to_page(pfn);
668f9abbd   David Rientjes   mm: close PageTai...
289
  		struct page *head = compound_head(tail);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
290
291
292
293
  		reserved = !!(PageReserved(head));
  		if (head != tail) {
  			/*
  			 * "head" is not a dangling pointer
668f9abbd   David Rientjes   mm: close PageTai...
294
  			 * (compound_head takes care of that)
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
  			 * but the hugepage may have been split
  			 * from under us (and we may not hold a
  			 * reference count on the head page so it can
  			 * be reused before we run PageReferenced), so
  			 * we've to check PageTail before returning
  			 * what we just read.
  			 */
  			smp_rmb();
  			if (PageTail(tail))
  				return reserved;
  		}
  		return PageReserved(tail);
  	}
  
  	return true;
  }
  
  static int put_pfn(unsigned long pfn, int prot)
  {
  	if (!is_invalid_reserved_pfn(pfn)) {
  		struct page *page = pfn_to_page(pfn);
  		if (prot & IOMMU_WRITE)
  			SetPageDirty(page);
  		put_page(page);
  		return 1;
  	}
  	return 0;
  }
270c35d07   Ajay Kaher   vfio/type1: Suppo...
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
  static int follow_fault_pfn(struct vm_area_struct *vma, struct mm_struct *mm,
  			    unsigned long vaddr, unsigned long *pfn,
  			    bool write_fault)
  {
  	int ret;
  
  	ret = follow_pfn(vma, vaddr, pfn);
  	if (ret) {
  		bool unlocked = false;
  
  		ret = fixup_user_fault(NULL, mm, vaddr,
  				       FAULT_FLAG_REMOTE |
  				       (write_fault ?  FAULT_FLAG_WRITE : 0),
  				       &unlocked);
  		if (unlocked)
  			return -EAGAIN;
  
  		if (ret)
  			return ret;
  
  		ret = follow_pfn(vma, vaddr, pfn);
  	}
  
  	return ret;
  }
ea85cf353   Kirti Wankhede   vfio iommu type1:...
348
349
  static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr,
  			 int prot, unsigned long *pfn)
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
350
351
352
  {
  	struct page *page[1];
  	struct vm_area_struct *vma;
94db151dc   Dan Williams   vfio: disable fil...
353
  	struct vm_area_struct *vmas[1];
bb94b55af   Jason Gunthorpe   vfio: Use get_use...
354
  	unsigned int flags = 0;
ea85cf353   Kirti Wankhede   vfio iommu type1:...
355
  	int ret;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
356

bb94b55af   Jason Gunthorpe   vfio: Use get_use...
357
358
359
360
  	if (prot & IOMMU_WRITE)
  		flags |= FOLL_WRITE;
  
  	down_read(&mm->mmap_sem);
ea85cf353   Kirti Wankhede   vfio iommu type1:...
361
  	if (mm == current->mm) {
932f4a630   Ira Weiny   mm/gup: replace g...
362
363
  		ret = get_user_pages(vaddr, 1, flags | FOLL_LONGTERM, page,
  				     vmas);
ea85cf353   Kirti Wankhede   vfio iommu type1:...
364
  	} else {
ea85cf353   Kirti Wankhede   vfio iommu type1:...
365
  		ret = get_user_pages_remote(NULL, mm, vaddr, 1, flags, page,
94db151dc   Dan Williams   vfio: disable fil...
366
367
368
369
370
371
372
373
374
375
376
377
  					    vmas, NULL);
  		/*
  		 * The lifetime of a vaddr_get_pfn() page pin is
  		 * userspace-controlled. In the fs-dax case this could
  		 * lead to indefinite stalls in filesystem operations.
  		 * Disallow attempts to pin fs-dax pages via this
  		 * interface.
  		 */
  		if (ret > 0 && vma_is_fsdax(vmas[0])) {
  			ret = -EOPNOTSUPP;
  			put_page(page[0]);
  		}
ea85cf353   Kirti Wankhede   vfio iommu type1:...
378
  	}
bb94b55af   Jason Gunthorpe   vfio: Use get_use...
379
  	up_read(&mm->mmap_sem);
ea85cf353   Kirti Wankhede   vfio iommu type1:...
380
381
  
  	if (ret == 1) {
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
382
383
384
  		*pfn = page_to_pfn(page[0]);
  		return 0;
  	}
ea85cf353   Kirti Wankhede   vfio iommu type1:...
385
  	down_read(&mm->mmap_sem);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
386

6cf5354c1   Andrey Konovalov   vfio/type1: untag...
387
  	vaddr = untagged_addr(vaddr);
270c35d07   Ajay Kaher   vfio/type1: Suppo...
388
  retry:
ea85cf353   Kirti Wankhede   vfio iommu type1:...
389
  	vma = find_vma_intersection(mm, vaddr, vaddr + 1);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
390
391
  
  	if (vma && vma->vm_flags & VM_PFNMAP) {
270c35d07   Ajay Kaher   vfio/type1: Suppo...
392
393
394
395
396
397
  		ret = follow_fault_pfn(vma, mm, vaddr, pfn, prot & IOMMU_WRITE);
  		if (ret == -EAGAIN)
  			goto retry;
  
  		if (!ret && !is_invalid_reserved_pfn(*pfn))
  			ret = -EFAULT;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
398
  	}
ea85cf353   Kirti Wankhede   vfio iommu type1:...
399
  	up_read(&mm->mmap_sem);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
400
401
  	return ret;
  }
166fd7d94   Alex Williamson   vfio: hugepage su...
402
403
404
405
406
  /*
   * Attempt to pin pages.  We really don't want to track all the pfns and
   * the iommu can only map chunks of consecutive pfns anyway, so get the
   * first page and all consecutive pages with the same locking.
   */
8f0d5bb95   Kirti Wankhede   vfio iommu type1:...
407
  static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr,
7cb671e7a   Alex Williamson   vfio/type1: Reduc...
408
  				  long npage, unsigned long *pfn_base,
48d8476b4   Alex Williamson   vfio/type1: Fix t...
409
  				  unsigned long limit)
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
410
  {
7cb671e7a   Alex Williamson   vfio/type1: Reduc...
411
  	unsigned long pfn = 0;
6c38c055c   Alex Williamson   vfio/type1: Resto...
412
  	long ret, pinned = 0, lock_acct = 0;
89c29def6   Alex Williamson   Revert "vfio/type...
413
  	bool rsvd;
a54eb5504   Kirti Wankhede   vfio iommu type1:...
414
  	dma_addr_t iova = vaddr - dma->vaddr + dma->iova;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
415

6c38c055c   Alex Williamson   vfio/type1: Resto...
416
417
  	/* This code path is only user initiated */
  	if (!current->mm)
166fd7d94   Alex Williamson   vfio: hugepage su...
418
  		return -ENODEV;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
419

6c38c055c   Alex Williamson   vfio/type1: Resto...
420
  	ret = vaddr_get_pfn(current->mm, vaddr, dma->prot, pfn_base);
166fd7d94   Alex Williamson   vfio: hugepage su...
421
  	if (ret)
6c38c055c   Alex Williamson   vfio/type1: Resto...
422
  		return ret;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
423

6c38c055c   Alex Williamson   vfio/type1: Resto...
424
  	pinned++;
89c29def6   Alex Williamson   Revert "vfio/type...
425
  	rsvd = is_invalid_reserved_pfn(*pfn_base);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
426

a54eb5504   Kirti Wankhede   vfio iommu type1:...
427
428
429
430
  	/*
  	 * Reserved pages aren't counted against the user, externally pinned
  	 * pages are already counted against the user.
  	 */
89c29def6   Alex Williamson   Revert "vfio/type...
431
  	if (!rsvd && !vfio_find_vpfn(dma, iova)) {
48d8476b4   Alex Williamson   vfio/type1: Fix t...
432
  		if (!dma->lock_cap && current->mm->locked_vm + 1 > limit) {
a54eb5504   Kirti Wankhede   vfio iommu type1:...
433
434
435
436
  			put_pfn(*pfn_base, dma->prot);
  			pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded
  ", __func__,
  					limit << PAGE_SHIFT);
6c38c055c   Alex Williamson   vfio/type1: Resto...
437
  			return -ENOMEM;
a54eb5504   Kirti Wankhede   vfio iommu type1:...
438
439
  		}
  		lock_acct++;
5c6c2b21e   Alex Williamson   vfio: Provide mod...
440
  	}
6c38c055c   Alex Williamson   vfio/type1: Resto...
441
442
  	if (unlikely(disable_hugepages))
  		goto out;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
443

6c38c055c   Alex Williamson   vfio/type1: Resto...
444
445
446
  	/* Lock all the consecutive pages from pfn_base */
  	for (vaddr += PAGE_SIZE, iova += PAGE_SIZE; pinned < npage;
  	     pinned++, vaddr += PAGE_SIZE, iova += PAGE_SIZE) {
6c38c055c   Alex Williamson   vfio/type1: Resto...
447
448
449
  		ret = vaddr_get_pfn(current->mm, vaddr, dma->prot, &pfn);
  		if (ret)
  			break;
89c29def6   Alex Williamson   Revert "vfio/type...
450
451
  		if (pfn != *pfn_base + pinned ||
  		    rsvd != is_invalid_reserved_pfn(pfn)) {
6c38c055c   Alex Williamson   vfio/type1: Resto...
452
453
454
  			put_pfn(pfn, dma->prot);
  			break;
  		}
166fd7d94   Alex Williamson   vfio: hugepage su...
455

89c29def6   Alex Williamson   Revert "vfio/type...
456
  		if (!rsvd && !vfio_find_vpfn(dma, iova)) {
48d8476b4   Alex Williamson   vfio/type1: Fix t...
457
  			if (!dma->lock_cap &&
6c38c055c   Alex Williamson   vfio/type1: Resto...
458
  			    current->mm->locked_vm + lock_acct + 1 > limit) {
a54eb5504   Kirti Wankhede   vfio iommu type1:...
459
  				put_pfn(pfn, dma->prot);
6c38c055c   Alex Williamson   vfio/type1: Resto...
460
461
462
  				pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded
  ",
  					__func__, limit << PAGE_SHIFT);
0cfef2b74   Alex Williamson   vfio/type1: Remov...
463
464
  				ret = -ENOMEM;
  				goto unpin_out;
a54eb5504   Kirti Wankhede   vfio iommu type1:...
465
  			}
6c38c055c   Alex Williamson   vfio/type1: Resto...
466
  			lock_acct++;
166fd7d94   Alex Williamson   vfio: hugepage su...
467
468
  		}
  	}
6c38c055c   Alex Williamson   vfio/type1: Resto...
469
  out:
48d8476b4   Alex Williamson   vfio/type1: Fix t...
470
  	ret = vfio_lock_acct(dma, lock_acct, false);
0cfef2b74   Alex Williamson   vfio/type1: Remov...
471
472
473
  
  unpin_out:
  	if (ret) {
89c29def6   Alex Williamson   Revert "vfio/type...
474
475
476
477
  		if (!rsvd) {
  			for (pfn = *pfn_base ; pinned ; pfn++, pinned--)
  				put_pfn(pfn, dma->prot);
  		}
0cfef2b74   Alex Williamson   vfio/type1: Remov...
478
479
480
  
  		return ret;
  	}
166fd7d94   Alex Williamson   vfio: hugepage su...
481

6c38c055c   Alex Williamson   vfio/type1: Resto...
482
  	return pinned;
166fd7d94   Alex Williamson   vfio: hugepage su...
483
  }
a54eb5504   Kirti Wankhede   vfio iommu type1:...
484
485
486
  static long vfio_unpin_pages_remote(struct vfio_dma *dma, dma_addr_t iova,
  				    unsigned long pfn, long npage,
  				    bool do_accounting)
166fd7d94   Alex Williamson   vfio: hugepage su...
487
  {
a54eb5504   Kirti Wankhede   vfio iommu type1:...
488
  	long unlocked = 0, locked = 0;
166fd7d94   Alex Williamson   vfio: hugepage su...
489
  	long i;
6c38c055c   Alex Williamson   vfio/type1: Resto...
490
  	for (i = 0; i < npage; i++, iova += PAGE_SIZE) {
a54eb5504   Kirti Wankhede   vfio iommu type1:...
491
492
  		if (put_pfn(pfn++, dma->prot)) {
  			unlocked++;
6c38c055c   Alex Williamson   vfio/type1: Resto...
493
  			if (vfio_find_vpfn(dma, iova))
a54eb5504   Kirti Wankhede   vfio iommu type1:...
494
495
496
497
498
  				locked++;
  		}
  	}
  
  	if (do_accounting)
48d8476b4   Alex Williamson   vfio/type1: Fix t...
499
  		vfio_lock_acct(dma, locked - unlocked, true);
a54eb5504   Kirti Wankhede   vfio iommu type1:...
500
501
502
503
504
505
506
  
  	return unlocked;
  }
  
  static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr,
  				  unsigned long *pfn_base, bool do_accounting)
  {
a54eb5504   Kirti Wankhede   vfio iommu type1:...
507
508
  	struct mm_struct *mm;
  	int ret;
a54eb5504   Kirti Wankhede   vfio iommu type1:...
509
510
511
512
513
514
  
  	mm = get_task_mm(dma->task);
  	if (!mm)
  		return -ENODEV;
  
  	ret = vaddr_get_pfn(mm, vaddr, dma->prot, pfn_base);
80dbe1fba   Alex Williamson   vfio/type1: Prune...
515
  	if (!ret && do_accounting && !is_invalid_reserved_pfn(*pfn_base)) {
48d8476b4   Alex Williamson   vfio/type1: Fix t...
516
  		ret = vfio_lock_acct(dma, 1, true);
0cfef2b74   Alex Williamson   vfio/type1: Remov...
517
518
  		if (ret) {
  			put_pfn(*pfn_base, dma->prot);
80dbe1fba   Alex Williamson   vfio/type1: Prune...
519
520
521
522
523
524
  			if (ret == -ENOMEM)
  				pr_warn("%s: Task %s (%d) RLIMIT_MEMLOCK "
  					"(%ld) exceeded
  ", __func__,
  					dma->task->comm, task_pid_nr(dma->task),
  					task_rlimit(dma->task, RLIMIT_MEMLOCK));
0cfef2b74   Alex Williamson   vfio/type1: Remov...
525
526
  		}
  	}
a54eb5504   Kirti Wankhede   vfio iommu type1:...
527
528
529
530
531
532
533
534
535
536
537
538
539
540
  	mmput(mm);
  	return ret;
  }
  
  static int vfio_unpin_page_external(struct vfio_dma *dma, dma_addr_t iova,
  				    bool do_accounting)
  {
  	int unlocked;
  	struct vfio_pfn *vpfn = vfio_find_vpfn(dma, iova);
  
  	if (!vpfn)
  		return 0;
  
  	unlocked = vfio_iova_put_vfio_pfn(dma, vpfn);
166fd7d94   Alex Williamson   vfio: hugepage su...
541
542
  
  	if (do_accounting)
48d8476b4   Alex Williamson   vfio/type1: Fix t...
543
  		vfio_lock_acct(dma, -unlocked, true);
166fd7d94   Alex Williamson   vfio: hugepage su...
544
545
546
  
  	return unlocked;
  }
a54eb5504   Kirti Wankhede   vfio iommu type1:...
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
  static int vfio_iommu_type1_pin_pages(void *iommu_data,
  				      unsigned long *user_pfn,
  				      int npage, int prot,
  				      unsigned long *phys_pfn)
  {
  	struct vfio_iommu *iommu = iommu_data;
  	int i, j, ret;
  	unsigned long remote_vaddr;
  	struct vfio_dma *dma;
  	bool do_accounting;
  
  	if (!iommu || !user_pfn || !phys_pfn)
  		return -EINVAL;
  
  	/* Supported for v2 version only */
  	if (!iommu->v2)
  		return -EACCES;
  
  	mutex_lock(&iommu->lock);
c086de818   Kirti Wankhede   vfio iommu: Add b...
566
  	/* Fail if notifier list is empty */
be068fa23   Lu Baolu   vfio/type1: Handl...
567
  	if (!iommu->notifier.head) {
a54eb5504   Kirti Wankhede   vfio iommu type1:...
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
  		ret = -EINVAL;
  		goto pin_done;
  	}
  
  	/*
  	 * If iommu capable domain exist in the container then all pages are
  	 * already pinned and accounted. Accouting should be done if there is no
  	 * iommu capable domain in the container.
  	 */
  	do_accounting = !IS_IOMMU_CAP_DOMAIN_IN_CONTAINER(iommu);
  
  	for (i = 0; i < npage; i++) {
  		dma_addr_t iova;
  		struct vfio_pfn *vpfn;
  
  		iova = user_pfn[i] << PAGE_SHIFT;
2b8bb1d77   Kirti Wankhede   vfio iommu type1:...
584
  		dma = vfio_find_dma(iommu, iova, PAGE_SIZE);
a54eb5504   Kirti Wankhede   vfio iommu type1:...
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
  		if (!dma) {
  			ret = -EINVAL;
  			goto pin_unwind;
  		}
  
  		if ((dma->prot & prot) != prot) {
  			ret = -EPERM;
  			goto pin_unwind;
  		}
  
  		vpfn = vfio_iova_get_vfio_pfn(dma, iova);
  		if (vpfn) {
  			phys_pfn[i] = vpfn->pfn;
  			continue;
  		}
08e90b299   Yan Zhao   vfio: avoid possi...
600
  		remote_vaddr = dma->vaddr + (iova - dma->iova);
a54eb5504   Kirti Wankhede   vfio iommu type1:...
601
602
  		ret = vfio_pin_page_external(dma, remote_vaddr, &phys_pfn[i],
  					     do_accounting);
80dbe1fba   Alex Williamson   vfio/type1: Prune...
603
  		if (ret)
a54eb5504   Kirti Wankhede   vfio iommu type1:...
604
  			goto pin_unwind;
a54eb5504   Kirti Wankhede   vfio iommu type1:...
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
  
  		ret = vfio_add_to_pfn_list(dma, iova, phys_pfn[i]);
  		if (ret) {
  			vfio_unpin_page_external(dma, iova, do_accounting);
  			goto pin_unwind;
  		}
  	}
  
  	ret = i;
  	goto pin_done;
  
  pin_unwind:
  	phys_pfn[i] = 0;
  	for (j = 0; j < i; j++) {
  		dma_addr_t iova;
  
  		iova = user_pfn[j] << PAGE_SHIFT;
2b8bb1d77   Kirti Wankhede   vfio iommu type1:...
622
  		dma = vfio_find_dma(iommu, iova, PAGE_SIZE);
a54eb5504   Kirti Wankhede   vfio iommu type1:...
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
  		vfio_unpin_page_external(dma, iova, do_accounting);
  		phys_pfn[j] = 0;
  	}
  pin_done:
  	mutex_unlock(&iommu->lock);
  	return ret;
  }
  
  static int vfio_iommu_type1_unpin_pages(void *iommu_data,
  					unsigned long *user_pfn,
  					int npage)
  {
  	struct vfio_iommu *iommu = iommu_data;
  	bool do_accounting;
  	int i;
  
  	if (!iommu || !user_pfn)
  		return -EINVAL;
  
  	/* Supported for v2 version only */
  	if (!iommu->v2)
  		return -EACCES;
  
  	mutex_lock(&iommu->lock);
a54eb5504   Kirti Wankhede   vfio iommu type1:...
647
648
649
650
651
652
  	do_accounting = !IS_IOMMU_CAP_DOMAIN_IN_CONTAINER(iommu);
  	for (i = 0; i < npage; i++) {
  		struct vfio_dma *dma;
  		dma_addr_t iova;
  
  		iova = user_pfn[i] << PAGE_SHIFT;
2b8bb1d77   Kirti Wankhede   vfio iommu type1:...
653
  		dma = vfio_find_dma(iommu, iova, PAGE_SIZE);
a54eb5504   Kirti Wankhede   vfio iommu type1:...
654
655
656
657
658
659
660
661
662
  		if (!dma)
  			goto unpin_exit;
  		vfio_unpin_page_external(dma, iova, do_accounting);
  	}
  
  unpin_exit:
  	mutex_unlock(&iommu->lock);
  	return i > npage ? npage : (i > 0 ? i : -EINVAL);
  }
6bd06f5a4   Suravee Suthikulpanit   vfio/type1: Adopt...
663
  static long vfio_sync_unpin(struct vfio_dma *dma, struct vfio_domain *domain,
a7d20dc19   Will Deacon   iommu: Introduce ...
664
665
  			    struct list_head *regions,
  			    struct iommu_iotlb_gather *iotlb_gather)
6bd06f5a4   Suravee Suthikulpanit   vfio/type1: Adopt...
666
667
668
  {
  	long unlocked = 0;
  	struct vfio_regions *entry, *next;
a7d20dc19   Will Deacon   iommu: Introduce ...
669
  	iommu_tlb_sync(domain->domain, iotlb_gather);
6bd06f5a4   Suravee Suthikulpanit   vfio/type1: Adopt...
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
  
  	list_for_each_entry_safe(entry, next, regions, list) {
  		unlocked += vfio_unpin_pages_remote(dma,
  						    entry->iova,
  						    entry->phys >> PAGE_SHIFT,
  						    entry->len >> PAGE_SHIFT,
  						    false);
  		list_del(&entry->list);
  		kfree(entry);
  	}
  
  	cond_resched();
  
  	return unlocked;
  }
  
  /*
   * Generally, VFIO needs to unpin remote pages after each IOTLB flush.
   * Therefore, when using IOTLB flush sync interface, VFIO need to keep track
   * of these regions (currently using a list).
   *
   * This value specifies maximum number of regions for each IOTLB flush sync.
   */
  #define VFIO_IOMMU_TLB_SYNC_MAX		512
  
  static size_t unmap_unpin_fast(struct vfio_domain *domain,
  			       struct vfio_dma *dma, dma_addr_t *iova,
  			       size_t len, phys_addr_t phys, long *unlocked,
  			       struct list_head *unmapped_list,
a7d20dc19   Will Deacon   iommu: Introduce ...
699
700
  			       int *unmapped_cnt,
  			       struct iommu_iotlb_gather *iotlb_gather)
6bd06f5a4   Suravee Suthikulpanit   vfio/type1: Adopt...
701
702
703
704
705
  {
  	size_t unmapped = 0;
  	struct vfio_regions *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
  
  	if (entry) {
a7d20dc19   Will Deacon   iommu: Introduce ...
706
707
  		unmapped = iommu_unmap_fast(domain->domain, *iova, len,
  					    iotlb_gather);
6bd06f5a4   Suravee Suthikulpanit   vfio/type1: Adopt...
708
709
710
711
  
  		if (!unmapped) {
  			kfree(entry);
  		} else {
6bd06f5a4   Suravee Suthikulpanit   vfio/type1: Adopt...
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
  			entry->iova = *iova;
  			entry->phys = phys;
  			entry->len  = unmapped;
  			list_add_tail(&entry->list, unmapped_list);
  
  			*iova += unmapped;
  			(*unmapped_cnt)++;
  		}
  	}
  
  	/*
  	 * Sync if the number of fast-unmap regions hits the limit
  	 * or in case of errors.
  	 */
  	if (*unmapped_cnt >= VFIO_IOMMU_TLB_SYNC_MAX || !unmapped) {
a7d20dc19   Will Deacon   iommu: Introduce ...
727
728
  		*unlocked += vfio_sync_unpin(dma, domain, unmapped_list,
  					     iotlb_gather);
6bd06f5a4   Suravee Suthikulpanit   vfio/type1: Adopt...
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
  		*unmapped_cnt = 0;
  	}
  
  	return unmapped;
  }
  
  static size_t unmap_unpin_slow(struct vfio_domain *domain,
  			       struct vfio_dma *dma, dma_addr_t *iova,
  			       size_t len, phys_addr_t phys,
  			       long *unlocked)
  {
  	size_t unmapped = iommu_unmap(domain->domain, *iova, len);
  
  	if (unmapped) {
  		*unlocked += vfio_unpin_pages_remote(dma, *iova,
  						     phys >> PAGE_SHIFT,
  						     unmapped >> PAGE_SHIFT,
  						     false);
  		*iova += unmapped;
  		cond_resched();
  	}
  	return unmapped;
  }
a54eb5504   Kirti Wankhede   vfio iommu type1:...
752
753
  static long vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma,
  			     bool do_accounting)
166fd7d94   Alex Williamson   vfio: hugepage su...
754
  {
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
755
756
  	dma_addr_t iova = dma->iova, end = dma->iova + dma->size;
  	struct vfio_domain *domain, *d;
6bd06f5a4   Suravee Suthikulpanit   vfio/type1: Adopt...
757
  	LIST_HEAD(unmapped_region_list);
a7d20dc19   Will Deacon   iommu: Introduce ...
758
  	struct iommu_iotlb_gather iotlb_gather;
6bd06f5a4   Suravee Suthikulpanit   vfio/type1: Adopt...
759
  	int unmapped_region_cnt = 0;
166fd7d94   Alex Williamson   vfio: hugepage su...
760
  	long unlocked = 0;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
761
  	if (!dma->size)
a54eb5504   Kirti Wankhede   vfio iommu type1:...
762
763
764
765
  		return 0;
  
  	if (!IS_IOMMU_CAP_DOMAIN_IN_CONTAINER(iommu))
  		return 0;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
766
767
768
769
770
771
772
773
774
  	/*
  	 * We use the IOMMU to track the physical addresses, otherwise we'd
  	 * need a much more complicated tracking system.  Unfortunately that
  	 * means we need to use one of the iommu domains to figure out the
  	 * pfns to unpin.  The rest need to be unmapped in advance so we have
  	 * no iommu translations remaining when the pages are unpinned.
  	 */
  	domain = d = list_first_entry(&iommu->domain_list,
  				      struct vfio_domain, next);
c5e668875   Alex Williamson   vfio/type1: Add c...
775
  	list_for_each_entry_continue(d, &iommu->domain_list, next) {
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
776
  		iommu_unmap(d->domain, dma->iova, dma->size);
c5e668875   Alex Williamson   vfio/type1: Add c...
777
778
  		cond_resched();
  	}
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
779

a7d20dc19   Will Deacon   iommu: Introduce ...
780
  	iommu_iotlb_gather_init(&iotlb_gather);
166fd7d94   Alex Williamson   vfio: hugepage su...
781
  	while (iova < end) {
6fe1010d6   Alex Williamson   vfio/type1: DMA u...
782
783
  		size_t unmapped, len;
  		phys_addr_t phys, next;
166fd7d94   Alex Williamson   vfio: hugepage su...
784

1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
785
  		phys = iommu_iova_to_phys(domain->domain, iova);
166fd7d94   Alex Williamson   vfio: hugepage su...
786
787
788
  		if (WARN_ON(!phys)) {
  			iova += PAGE_SIZE;
  			continue;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
789
  		}
166fd7d94   Alex Williamson   vfio: hugepage su...
790

6fe1010d6   Alex Williamson   vfio/type1: DMA u...
791
792
793
794
795
796
797
798
799
800
801
  		/*
  		 * To optimize for fewer iommu_unmap() calls, each of which
  		 * may require hardware cache flushing, try to find the
  		 * largest contiguous physical memory chunk to unmap.
  		 */
  		for (len = PAGE_SIZE;
  		     !domain->fgsp && iova + len < end; len += PAGE_SIZE) {
  			next = iommu_iova_to_phys(domain->domain, iova + len);
  			if (next != phys + len)
  				break;
  		}
6bd06f5a4   Suravee Suthikulpanit   vfio/type1: Adopt...
802
803
804
805
806
807
  		/*
  		 * First, try to use fast unmap/unpin. In case of failure,
  		 * switch to slow unmap/unpin path.
  		 */
  		unmapped = unmap_unpin_fast(domain, dma, &iova, len, phys,
  					    &unlocked, &unmapped_region_list,
a7d20dc19   Will Deacon   iommu: Introduce ...
808
809
  					    &unmapped_region_cnt,
  					    &iotlb_gather);
6bd06f5a4   Suravee Suthikulpanit   vfio/type1: Adopt...
810
811
812
813
814
815
  		if (!unmapped) {
  			unmapped = unmap_unpin_slow(domain, dma, &iova, len,
  						    phys, &unlocked);
  			if (WARN_ON(!unmapped))
  				break;
  		}
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
816
  	}
166fd7d94   Alex Williamson   vfio: hugepage su...
817

a54eb5504   Kirti Wankhede   vfio iommu type1:...
818
  	dma->iommu_mapped = false;
6bd06f5a4   Suravee Suthikulpanit   vfio/type1: Adopt...
819

a7d20dc19   Will Deacon   iommu: Introduce ...
820
821
822
823
  	if (unmapped_region_cnt) {
  		unlocked += vfio_sync_unpin(dma, domain, &unmapped_region_list,
  					    &iotlb_gather);
  	}
6bd06f5a4   Suravee Suthikulpanit   vfio/type1: Adopt...
824

a54eb5504   Kirti Wankhede   vfio iommu type1:...
825
  	if (do_accounting) {
48d8476b4   Alex Williamson   vfio/type1: Fix t...
826
  		vfio_lock_acct(dma, -unlocked, true);
a54eb5504   Kirti Wankhede   vfio iommu type1:...
827
828
829
  		return 0;
  	}
  	return unlocked;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
830
  }
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
831
  static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
832
  {
a54eb5504   Kirti Wankhede   vfio iommu type1:...
833
  	vfio_unmap_unpin(iommu, dma, true);
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
834
  	vfio_unlink_dma(iommu, dma);
8f0d5bb95   Kirti Wankhede   vfio iommu type1:...
835
  	put_task_struct(dma->task);
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
836
  	kfree(dma);
492855939   Alex Williamson   vfio/type1: Limit...
837
  	iommu->dma_avail++;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
838
  }
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
839

1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
840
841
842
  static unsigned long vfio_pgsize_bitmap(struct vfio_iommu *iommu)
  {
  	struct vfio_domain *domain;
4644321fd   Eric Auger   vfio/type1: handl...
843
  	unsigned long bitmap = ULONG_MAX;
166fd7d94   Alex Williamson   vfio: hugepage su...
844

1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
845
846
  	mutex_lock(&iommu->lock);
  	list_for_each_entry(domain, &iommu->domain_list, next)
d16e0faab   Robin Murphy   iommu: Allow sele...
847
  		bitmap &= domain->domain->pgsize_bitmap;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
848
  	mutex_unlock(&iommu->lock);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
849

4644321fd   Eric Auger   vfio/type1: handl...
850
851
852
853
854
855
856
857
858
859
860
861
  	/*
  	 * In case the IOMMU supports page sizes smaller than PAGE_SIZE
  	 * we pretend PAGE_SIZE is supported and hide sub-PAGE_SIZE sizes.
  	 * That way the user will be able to map/unmap buffers whose size/
  	 * start address is aligned with PAGE_SIZE. Pinning code uses that
  	 * granularity while iommu driver can use the sub-PAGE_SIZE size
  	 * to map the buffer.
  	 */
  	if (bitmap & ~PAGE_MASK) {
  		bitmap &= PAGE_MASK;
  		bitmap |= PAGE_SIZE;
  	}
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
862
  	return bitmap;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
863
864
865
866
867
  }
  
  static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
  			     struct vfio_iommu_type1_dma_unmap *unmap)
  {
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
868
  	uint64_t mask;
c086de818   Kirti Wankhede   vfio iommu: Add b...
869
  	struct vfio_dma *dma, *dma_last = NULL;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
870
  	size_t unmapped = 0;
c086de818   Kirti Wankhede   vfio iommu: Add b...
871
  	int ret = 0, retries = 0;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
872

1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
873
  	mask = ((uint64_t)1 << __ffs(vfio_pgsize_bitmap(iommu))) - 1;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
874
875
876
  
  	if (unmap->iova & mask)
  		return -EINVAL;
f5bfdbf25   Alex Williamson   vfio/type1: Fix m...
877
  	if (!unmap->size || unmap->size & mask)
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
878
  		return -EINVAL;
58fec830f   Alex Williamson   vfio/type1: Fix u...
879
  	if (unmap->iova + unmap->size - 1 < unmap->iova ||
71a7d3d78   Dan Carpenter   vfio/type1: silen...
880
881
  	    unmap->size > SIZE_MAX)
  		return -EINVAL;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
882

73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
883
  	WARN_ON(mask & PAGE_MASK);
c086de818   Kirti Wankhede   vfio iommu: Add b...
884
  again:
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
885
  	mutex_lock(&iommu->lock);
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
  	/*
  	 * vfio-iommu-type1 (v1) - User mappings were coalesced together to
  	 * avoid tracking individual mappings.  This means that the granularity
  	 * of the original mapping was lost and the user was allowed to attempt
  	 * to unmap any range.  Depending on the contiguousness of physical
  	 * memory and page sizes supported by the IOMMU, arbitrary unmaps may
  	 * or may not have worked.  We only guaranteed unmap granularity
  	 * matching the original mapping; even though it was untracked here,
  	 * the original mappings are reflected in IOMMU mappings.  This
  	 * resulted in a couple unusual behaviors.  First, if a range is not
  	 * able to be unmapped, ex. a set of 4k pages that was mapped as a
  	 * 2M hugepage into the IOMMU, the unmap ioctl returns success but with
  	 * a zero sized unmap.  Also, if an unmap request overlaps the first
  	 * address of a hugepage, the IOMMU will unmap the entire hugepage.
  	 * This also returns success and the returned unmap size reflects the
  	 * actual size unmapped.
  	 *
  	 * We attempt to maintain compatibility with this "v1" interface, but
  	 * we take control out of the hands of the IOMMU.  Therefore, an unmap
  	 * request offset from the beginning of the original mapping will
  	 * return success with zero sized unmap.  And an unmap request covering
  	 * the first iova of mapping will unmap the entire range.
  	 *
  	 * The v2 version of this interface intends to be more deterministic.
  	 * Unmap requests must fully cover previous mappings.  Multiple
  	 * mappings may still be unmaped by specifying large ranges, but there
  	 * must not be any previous mappings bisected by the range.  An error
  	 * will be returned if these conditions are not met.  The v2 interface
  	 * will only return success and a size of zero if there were no
  	 * mappings within the range.
  	 */
  	if (iommu->v2) {
7c03f4284   Kirti Wankhede   vfio iommu type1:...
918
  		dma = vfio_find_dma(iommu, unmap->iova, 1);
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
919
920
921
922
923
924
925
926
927
928
  		if (dma && dma->iova != unmap->iova) {
  			ret = -EINVAL;
  			goto unlock;
  		}
  		dma = vfio_find_dma(iommu, unmap->iova + unmap->size - 1, 0);
  		if (dma && dma->iova + dma->size != unmap->iova + unmap->size) {
  			ret = -EINVAL;
  			goto unlock;
  		}
  	}
166fd7d94   Alex Williamson   vfio: hugepage su...
929
  	while ((dma = vfio_find_dma(iommu, unmap->iova, unmap->size))) {
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
930
  		if (!iommu->v2 && unmap->iova > dma->iova)
166fd7d94   Alex Williamson   vfio: hugepage su...
931
  			break;
8f0d5bb95   Kirti Wankhede   vfio iommu type1:...
932
933
934
935
936
937
  		/*
  		 * Task with same address space who mapped this iova range is
  		 * allowed to unmap the iova range.
  		 */
  		if (dma->task->mm != current->mm)
  			break;
c086de818   Kirti Wankhede   vfio iommu: Add b...
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
  
  		if (!RB_EMPTY_ROOT(&dma->pfn_list)) {
  			struct vfio_iommu_type1_dma_unmap nb_unmap;
  
  			if (dma_last == dma) {
  				BUG_ON(++retries > 10);
  			} else {
  				dma_last = dma;
  				retries = 0;
  			}
  
  			nb_unmap.iova = dma->iova;
  			nb_unmap.size = dma->size;
  
  			/*
  			 * Notify anyone (mdev vendor drivers) to invalidate and
  			 * unmap iovas within the range we're about to unmap.
  			 * Vendor drivers MUST unpin pages in response to an
  			 * invalidation.
  			 */
  			mutex_unlock(&iommu->lock);
  			blocking_notifier_call_chain(&iommu->notifier,
  						    VFIO_IOMMU_NOTIFY_DMA_UNMAP,
  						    &nb_unmap);
  			goto again;
  		}
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
964
965
  		unmapped += dma->size;
  		vfio_remove_dma(iommu, dma);
166fd7d94   Alex Williamson   vfio: hugepage su...
966
  	}
cd9b22685   Alex Williamson   vfio: Convert typ...
967

1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
968
  unlock:
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
969
  	mutex_unlock(&iommu->lock);
166fd7d94   Alex Williamson   vfio: hugepage su...
970

1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
971
  	/* Report how much was unmapped */
166fd7d94   Alex Williamson   vfio: hugepage su...
972
973
974
975
  	unmap->size = unmapped;
  
  	return ret;
  }
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
976
977
978
979
980
981
982
983
984
  static int vfio_iommu_map(struct vfio_iommu *iommu, dma_addr_t iova,
  			  unsigned long pfn, long npage, int prot)
  {
  	struct vfio_domain *d;
  	int ret;
  
  	list_for_each_entry(d, &iommu->domain_list, next) {
  		ret = iommu_map(d->domain, iova, (phys_addr_t)pfn << PAGE_SHIFT,
  				npage << PAGE_SHIFT, prot | d->prot);
7a30423a9   Joerg Roedel   vfio/type1: Remov...
985
986
  		if (ret)
  			goto unwind;
c5e668875   Alex Williamson   vfio/type1: Add c...
987
988
  
  		cond_resched();
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
989
990
991
992
993
994
995
  	}
  
  	return 0;
  
  unwind:
  	list_for_each_entry_continue_reverse(d, &iommu->domain_list, next)
  		iommu_unmap(d->domain, iova, npage << PAGE_SHIFT);
166fd7d94   Alex Williamson   vfio: hugepage su...
996

cd9b22685   Alex Williamson   vfio: Convert typ...
997
  	return ret;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
998
  }
8f0d5bb95   Kirti Wankhede   vfio iommu type1:...
999
1000
1001
1002
1003
1004
1005
  static int vfio_pin_map_dma(struct vfio_iommu *iommu, struct vfio_dma *dma,
  			    size_t map_size)
  {
  	dma_addr_t iova = dma->iova;
  	unsigned long vaddr = dma->vaddr;
  	size_t size = map_size;
  	long npage;
7cb671e7a   Alex Williamson   vfio/type1: Reduc...
1006
  	unsigned long pfn, limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
8f0d5bb95   Kirti Wankhede   vfio iommu type1:...
1007
1008
1009
1010
1011
  	int ret = 0;
  
  	while (size) {
  		/* Pin a contiguous chunk of memory */
  		npage = vfio_pin_pages_remote(dma, vaddr + dma->size,
48d8476b4   Alex Williamson   vfio/type1: Fix t...
1012
  					      size >> PAGE_SHIFT, &pfn, limit);
8f0d5bb95   Kirti Wankhede   vfio iommu type1:...
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
  		if (npage <= 0) {
  			WARN_ON(!npage);
  			ret = (int)npage;
  			break;
  		}
  
  		/* Map it! */
  		ret = vfio_iommu_map(iommu, iova + dma->size, pfn, npage,
  				     dma->prot);
  		if (ret) {
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1023
1024
  			vfio_unpin_pages_remote(dma, iova + dma->size, pfn,
  						npage, true);
8f0d5bb95   Kirti Wankhede   vfio iommu type1:...
1025
1026
1027
1028
1029
1030
  			break;
  		}
  
  		size -= npage << PAGE_SHIFT;
  		dma->size += npage << PAGE_SHIFT;
  	}
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1031
  	dma->iommu_mapped = true;
8f0d5bb95   Kirti Wankhede   vfio iommu type1:...
1032
1033
1034
1035
1036
  	if (ret)
  		vfio_remove_dma(iommu, dma);
  
  	return ret;
  }
9b77e5c79   Shameer Kolothum   vfio/type1: check...
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
  /*
   * Check dma map request is within a valid iova range
   */
  static bool vfio_iommu_iova_dma_valid(struct vfio_iommu *iommu,
  				      dma_addr_t start, dma_addr_t end)
  {
  	struct list_head *iova = &iommu->iova_list;
  	struct vfio_iova *node;
  
  	list_for_each_entry(node, iova, list) {
  		if (start >= node->start && end <= node->end)
  			return true;
  	}
  
  	/*
  	 * Check for list_empty() as well since a container with
  	 * a single mdev device will have an empty list.
  	 */
  	return list_empty(iova);
  }
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1057
1058
1059
  static int vfio_dma_do_map(struct vfio_iommu *iommu,
  			   struct vfio_iommu_type1_dma_map *map)
  {
c8dbca165   Alex Williamson   vfio/iommu_type1:...
1060
  	dma_addr_t iova = map->iova;
166fd7d94   Alex Williamson   vfio: hugepage su...
1061
  	unsigned long vaddr = map->vaddr;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1062
1063
1064
  	size_t size = map->size;
  	int ret = 0, prot = 0;
  	uint64_t mask;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1065
  	struct vfio_dma *dma;
166fd7d94   Alex Williamson   vfio: hugepage su...
1066

c8dbca165   Alex Williamson   vfio/iommu_type1:...
1067
1068
1069
  	/* Verify that none of our __u64 fields overflow */
  	if (map->size != size || map->vaddr != vaddr || map->iova != iova)
  		return -EINVAL;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1070

1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1071
  	mask = ((uint64_t)1 << __ffs(vfio_pgsize_bitmap(iommu))) - 1;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1072

c8dbca165   Alex Williamson   vfio/iommu_type1:...
1073
  	WARN_ON(mask & PAGE_MASK);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1074
1075
1076
1077
1078
  	/* READ/WRITE from device perspective */
  	if (map->flags & VFIO_DMA_MAP_FLAG_WRITE)
  		prot |= IOMMU_WRITE;
  	if (map->flags & VFIO_DMA_MAP_FLAG_READ)
  		prot |= IOMMU_READ;
c8dbca165   Alex Williamson   vfio/iommu_type1:...
1079
  	if (!prot || !size || (size | iova | vaddr) & mask)
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1080
  		return -EINVAL;
c8dbca165   Alex Williamson   vfio/iommu_type1:...
1081
1082
  	/* Don't allow IOVA or virtual address wrap */
  	if (iova + size - 1 < iova || vaddr + size - 1 < vaddr)
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1083
1084
1085
  		return -EINVAL;
  
  	mutex_lock(&iommu->lock);
c8dbca165   Alex Williamson   vfio/iommu_type1:...
1086
  	if (vfio_find_dma(iommu, iova, size)) {
8f0d5bb95   Kirti Wankhede   vfio iommu type1:...
1087
1088
  		ret = -EEXIST;
  		goto out_unlock;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1089
  	}
492855939   Alex Williamson   vfio/type1: Limit...
1090
1091
1092
1093
  	if (!iommu->dma_avail) {
  		ret = -ENOSPC;
  		goto out_unlock;
  	}
9b77e5c79   Shameer Kolothum   vfio/type1: check...
1094
1095
1096
1097
  	if (!vfio_iommu_iova_dma_valid(iommu, iova, iova + size - 1)) {
  		ret = -EINVAL;
  		goto out_unlock;
  	}
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1098
1099
  	dma = kzalloc(sizeof(*dma), GFP_KERNEL);
  	if (!dma) {
8f0d5bb95   Kirti Wankhede   vfio iommu type1:...
1100
1101
  		ret = -ENOMEM;
  		goto out_unlock;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1102
  	}
492855939   Alex Williamson   vfio/type1: Limit...
1103
  	iommu->dma_avail--;
c8dbca165   Alex Williamson   vfio/iommu_type1:...
1104
1105
  	dma->iova = iova;
  	dma->vaddr = vaddr;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1106
  	dma->prot = prot;
48d8476b4   Alex Williamson   vfio/type1: Fix t...
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
  
  	/*
  	 * We need to be able to both add to a task's locked memory and test
  	 * against the locked memory limit and we need to be able to do both
  	 * outside of this call path as pinning can be asynchronous via the
  	 * external interfaces for mdev devices.  RLIMIT_MEMLOCK requires a
  	 * task_struct and VM locked pages requires an mm_struct, however
  	 * holding an indefinite mm reference is not recommended, therefore we
  	 * only hold a reference to a task.  We could hold a reference to
  	 * current, however QEMU uses this call path through vCPU threads,
  	 * which can be killed resulting in a NULL mm and failure in the unmap
  	 * path when called via a different thread.  Avoid this problem by
  	 * using the group_leader as threads within the same group require
  	 * both CLONE_THREAD and CLONE_VM and will therefore use the same
  	 * mm_struct.
  	 *
  	 * Previously we also used the task for testing CAP_IPC_LOCK at the
  	 * time of pinning and accounting, however has_capability() makes use
  	 * of real_cred, a copy-on-write field, so we can't guarantee that it
  	 * matches group_leader, or in fact that it might not change by the
  	 * time it's evaluated.  If a process were to call MAP_DMA with
  	 * CAP_IPC_LOCK but later drop it, it doesn't make sense that they
  	 * possibly see different results for an iommu_mapped vfio_dma vs
  	 * externally mapped.  Therefore track CAP_IPC_LOCK in vfio_dma at the
  	 * time of calling MAP_DMA.
  	 */
  	get_task_struct(current->group_leader);
  	dma->task = current->group_leader;
  	dma->lock_cap = capable(CAP_IPC_LOCK);
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1136
  	dma->pfn_list = RB_ROOT;
166fd7d94   Alex Williamson   vfio: hugepage su...
1137

1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1138
1139
  	/* Insert zero-sized and grow as we map chunks of it */
  	vfio_link_dma(iommu, dma);
166fd7d94   Alex Williamson   vfio: hugepage su...
1140

a54eb5504   Kirti Wankhede   vfio iommu type1:...
1141
1142
1143
1144
1145
  	/* Don't pin and map if container doesn't contain IOMMU capable domain*/
  	if (!IS_IOMMU_CAP_DOMAIN_IN_CONTAINER(iommu))
  		dma->size = size;
  	else
  		ret = vfio_pin_map_dma(iommu, dma, size);
8f0d5bb95   Kirti Wankhede   vfio iommu type1:...
1146
  out_unlock:
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
  	mutex_unlock(&iommu->lock);
  	return ret;
  }
  
  static int vfio_bus_type(struct device *dev, void *data)
  {
  	struct bus_type **bus = data;
  
  	if (*bus && *bus != dev->bus)
  		return -EINVAL;
  
  	*bus = dev->bus;
  
  	return 0;
  }
  
  static int vfio_iommu_replay(struct vfio_iommu *iommu,
  			     struct vfio_domain *domain)
  {
667a59aa5   Alex Williamson   vfio/type1: Add p...
1166
  	struct vfio_domain *d = NULL;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1167
  	struct rb_node *n;
7cb671e7a   Alex Williamson   vfio/type1: Reduc...
1168
  	unsigned long limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1169
1170
1171
  	int ret;
  
  	/* Arbitrarily pick the first domain in the list for lookups */
667a59aa5   Alex Williamson   vfio/type1: Add p...
1172
1173
1174
  	if (!list_empty(&iommu->domain_list))
  		d = list_first_entry(&iommu->domain_list,
  				     struct vfio_domain, next);
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1175
  	n = rb_first(&iommu->dma_list);
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1176
1177
1178
1179
1180
1181
1182
1183
  	for (; n; n = rb_next(n)) {
  		struct vfio_dma *dma;
  		dma_addr_t iova;
  
  		dma = rb_entry(n, struct vfio_dma, node);
  		iova = dma->iova;
  
  		while (iova < dma->iova + dma->size) {
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1184
  			phys_addr_t phys;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1185
  			size_t size;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1186

a54eb5504   Kirti Wankhede   vfio iommu type1:...
1187
1188
1189
  			if (dma->iommu_mapped) {
  				phys_addr_t p;
  				dma_addr_t i;
667a59aa5   Alex Williamson   vfio/type1: Add p...
1190
1191
1192
1193
  				if (WARN_ON(!d)) { /* mapped w/o a domain?! */
  					ret = -EINVAL;
  					goto unwind;
  				}
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
  				phys = iommu_iova_to_phys(d->domain, iova);
  
  				if (WARN_ON(!phys)) {
  					iova += PAGE_SIZE;
  					continue;
  				}
  
  				size = PAGE_SIZE;
  				p = phys + size;
  				i = iova + size;
  				while (i < dma->iova + dma->size &&
  				       p == iommu_iova_to_phys(d->domain, i)) {
  					size += PAGE_SIZE;
  					p += PAGE_SIZE;
  					i += PAGE_SIZE;
  				}
  			} else {
  				unsigned long pfn;
  				unsigned long vaddr = dma->vaddr +
  						     (iova - dma->iova);
  				size_t n = dma->iova + dma->size - iova;
  				long npage;
  
  				npage = vfio_pin_pages_remote(dma, vaddr,
  							      n >> PAGE_SHIFT,
48d8476b4   Alex Williamson   vfio/type1: Fix t...
1219
  							      &pfn, limit);
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1220
1221
1222
  				if (npage <= 0) {
  					WARN_ON(!npage);
  					ret = (int)npage;
667a59aa5   Alex Williamson   vfio/type1: Add p...
1223
  					goto unwind;
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1224
1225
1226
1227
  				}
  
  				phys = pfn << PAGE_SHIFT;
  				size = npage << PAGE_SHIFT;
166fd7d94   Alex Williamson   vfio: hugepage su...
1228
  			}
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1229
1230
  			ret = iommu_map(domain->domain, iova, phys,
  					size, dma->prot | domain->prot);
667a59aa5   Alex Williamson   vfio/type1: Add p...
1231
1232
1233
1234
1235
1236
1237
1238
  			if (ret) {
  				if (!dma->iommu_mapped)
  					vfio_unpin_pages_remote(dma, iova,
  							phys >> PAGE_SHIFT,
  							size >> PAGE_SHIFT,
  							true);
  				goto unwind;
  			}
d93b3ac0e   Antonios Motakis   VFIO: vfio_iommu_...
1239

1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1240
1241
  			iova += size;
  		}
667a59aa5   Alex Williamson   vfio/type1: Add p...
1242
1243
1244
1245
1246
  	}
  
  	/* All dmas are now mapped, defer to second tree walk for unwind */
  	for (n = rb_first(&iommu->dma_list); n; n = rb_next(n)) {
  		struct vfio_dma *dma = rb_entry(n, struct vfio_dma, node);
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1247
  		dma->iommu_mapped = true;
166fd7d94   Alex Williamson   vfio: hugepage su...
1248
  	}
667a59aa5   Alex Williamson   vfio/type1: Add p...
1249

1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1250
  	return 0;
667a59aa5   Alex Williamson   vfio/type1: Add p...
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
  
  unwind:
  	for (; n; n = rb_prev(n)) {
  		struct vfio_dma *dma = rb_entry(n, struct vfio_dma, node);
  		dma_addr_t iova;
  
  		if (dma->iommu_mapped) {
  			iommu_unmap(domain->domain, dma->iova, dma->size);
  			continue;
  		}
  
  		iova = dma->iova;
  		while (iova < dma->iova + dma->size) {
  			phys_addr_t phys, p;
  			size_t size;
  			dma_addr_t i;
  
  			phys = iommu_iova_to_phys(domain->domain, iova);
  			if (!phys) {
  				iova += PAGE_SIZE;
  				continue;
  			}
  
  			size = PAGE_SIZE;
  			p = phys + size;
  			i = iova + size;
  			while (i < dma->iova + dma->size &&
  			       p == iommu_iova_to_phys(domain->domain, i)) {
  				size += PAGE_SIZE;
  				p += PAGE_SIZE;
  				i += PAGE_SIZE;
  			}
  
  			iommu_unmap(domain->domain, iova, size);
  			vfio_unpin_pages_remote(dma, iova, phys >> PAGE_SHIFT,
  						size >> PAGE_SHIFT, true);
  		}
  	}
  
  	return ret;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1291
  }
6fe1010d6   Alex Williamson   vfio/type1: DMA u...
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
  /*
   * We change our unmap behavior slightly depending on whether the IOMMU
   * supports fine-grained superpages.  IOMMUs like AMD-Vi will use a superpage
   * for practically any contiguous power-of-two mapping we give it.  This means
   * we don't need to look for contiguous chunks ourselves to make unmapping
   * more efficient.  On IOMMUs with coarse-grained super pages, like Intel VT-d
   * with discrete 2M/1G/512G/1T superpages, identifying contiguous chunks
   * significantly boosts non-hugetlbfs mappings and doesn't seem to hurt when
   * hugetlbfs is in use.
   */
  static void vfio_test_domain_fgsp(struct vfio_domain *domain)
  {
  	struct page *pages;
  	int ret, order = get_order(PAGE_SIZE * 2);
  
  	pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
  	if (!pages)
  		return;
  
  	ret = iommu_map(domain->domain, 0, page_to_phys(pages), PAGE_SIZE * 2,
  			IOMMU_READ | IOMMU_WRITE | domain->prot);
  	if (!ret) {
  		size_t unmapped = iommu_unmap(domain->domain, 0, PAGE_SIZE);
  
  		if (unmapped == PAGE_SIZE)
  			iommu_unmap(domain->domain, PAGE_SIZE, PAGE_SIZE);
  		else
  			domain->fgsp = true;
  	}
  
  	__free_pages(pages, order);
  }
7896c998f   Kirti Wankhede   vfio iommu type1:...
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
  static struct vfio_group *find_iommu_group(struct vfio_domain *domain,
  					   struct iommu_group *iommu_group)
  {
  	struct vfio_group *g;
  
  	list_for_each_entry(g, &domain->group_list, next) {
  		if (g->iommu_group == iommu_group)
  			return g;
  	}
  
  	return NULL;
  }
b09d6e473   Shameer Kolothum   vfio/type1: remov...
1336
1337
  static bool vfio_iommu_has_sw_msi(struct list_head *group_resv_regions,
  				  phys_addr_t *base)
5d7049921   Eric Auger   vfio/type1: Allow...
1338
  {
b09d6e473   Shameer Kolothum   vfio/type1: remov...
1339
  	struct iommu_resv_region *region;
5d7049921   Eric Auger   vfio/type1: Allow...
1340
  	bool ret = false;
b09d6e473   Shameer Kolothum   vfio/type1: remov...
1341
  	list_for_each_entry(region, group_resv_regions, list) {
f203f7f1d   Robin Murphy   vfio/type1: Give ...
1342
1343
1344
1345
1346
1347
1348
1349
1350
  		/*
  		 * The presence of any 'real' MSI regions should take
  		 * precedence over the software-managed one if the
  		 * IOMMU driver happens to advertise both types.
  		 */
  		if (region->type == IOMMU_RESV_MSI) {
  			ret = false;
  			break;
  		}
9d3a4de4c   Robin Murphy   iommu: Disambigua...
1351
  		if (region->type == IOMMU_RESV_SW_MSI) {
5d7049921   Eric Auger   vfio/type1: Allow...
1352
1353
  			*base = region->start;
  			ret = true;
5d7049921   Eric Auger   vfio/type1: Allow...
1354
1355
  		}
  	}
b09d6e473   Shameer Kolothum   vfio/type1: remov...
1356

5d7049921   Eric Auger   vfio/type1: Allow...
1357
1358
  	return ret;
  }
7bd50f0cd   Lu Baolu   vfio/type1: Add d...
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
  static struct device *vfio_mdev_get_iommu_device(struct device *dev)
  {
  	struct device *(*fn)(struct device *dev);
  	struct device *iommu_device;
  
  	fn = symbol_get(mdev_get_iommu_device);
  	if (fn) {
  		iommu_device = fn(dev);
  		symbol_put(mdev_get_iommu_device);
  
  		return iommu_device;
  	}
  
  	return NULL;
  }
  
  static int vfio_mdev_attach_domain(struct device *dev, void *data)
  {
  	struct iommu_domain *domain = data;
  	struct device *iommu_device;
  
  	iommu_device = vfio_mdev_get_iommu_device(dev);
  	if (iommu_device) {
  		if (iommu_dev_feature_enabled(iommu_device, IOMMU_DEV_FEAT_AUX))
  			return iommu_aux_attach_device(domain, iommu_device);
  		else
  			return iommu_attach_device(domain, iommu_device);
  	}
  
  	return -EINVAL;
  }
  
  static int vfio_mdev_detach_domain(struct device *dev, void *data)
  {
  	struct iommu_domain *domain = data;
  	struct device *iommu_device;
  
  	iommu_device = vfio_mdev_get_iommu_device(dev);
  	if (iommu_device) {
  		if (iommu_dev_feature_enabled(iommu_device, IOMMU_DEV_FEAT_AUX))
  			iommu_aux_detach_device(domain, iommu_device);
  		else
  			iommu_detach_device(domain, iommu_device);
  	}
  
  	return 0;
  }
  
  static int vfio_iommu_attach_group(struct vfio_domain *domain,
  				   struct vfio_group *group)
  {
  	if (group->mdev_group)
  		return iommu_group_for_each_dev(group->iommu_group,
  						domain->domain,
  						vfio_mdev_attach_domain);
  	else
  		return iommu_attach_group(domain->domain, group->iommu_group);
  }
  
  static void vfio_iommu_detach_group(struct vfio_domain *domain,
  				    struct vfio_group *group)
  {
  	if (group->mdev_group)
  		iommu_group_for_each_dev(group->iommu_group, domain->domain,
  					 vfio_mdev_detach_domain);
  	else
  		iommu_detach_group(domain->domain, group->iommu_group);
  }
be068fa23   Lu Baolu   vfio/type1: Handl...
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
  static bool vfio_bus_is_mdev(struct bus_type *bus)
  {
  	struct bus_type *mdev_bus;
  	bool ret = false;
  
  	mdev_bus = symbol_get(mdev_bus_type);
  	if (mdev_bus) {
  		ret = (bus == mdev_bus);
  		symbol_put(mdev_bus_type);
  	}
  
  	return ret;
  }
  
  static int vfio_mdev_iommu_device(struct device *dev, void *data)
  {
  	struct device **old = data, *new;
  
  	new = vfio_mdev_get_iommu_device(dev);
  	if (!new || (*old && *old != new))
  		return -EINVAL;
  
  	*old = new;
  
  	return 0;
  }
1108696ae   Shameer Kolothum   vfio/type1: Intro...
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
  /*
   * This is a helper function to insert an address range to iova list.
   * The list is initially created with a single entry corresponding to
   * the IOMMU domain geometry to which the device group is attached.
   * The list aperture gets modified when a new domain is added to the
   * container if the new aperture doesn't conflict with the current one
   * or with any existing dma mappings. The list is also modified to
   * exclude any reserved regions associated with the device group.
   */
  static int vfio_iommu_iova_insert(struct list_head *head,
  				  dma_addr_t start, dma_addr_t end)
  {
  	struct vfio_iova *region;
  
  	region = kmalloc(sizeof(*region), GFP_KERNEL);
  	if (!region)
  		return -ENOMEM;
  
  	INIT_LIST_HEAD(&region->list);
  	region->start = start;
  	region->end = end;
  
  	list_add_tail(&region->list, head);
  	return 0;
  }
  
  /*
   * Check the new iommu aperture conflicts with existing aper or with any
   * existing dma mappings.
   */
  static bool vfio_iommu_aper_conflict(struct vfio_iommu *iommu,
  				     dma_addr_t start, dma_addr_t end)
  {
  	struct vfio_iova *first, *last;
  	struct list_head *iova = &iommu->iova_list;
  
  	if (list_empty(iova))
  		return false;
  
  	/* Disjoint sets, return conflict */
  	first = list_first_entry(iova, struct vfio_iova, list);
  	last = list_last_entry(iova, struct vfio_iova, list);
  	if (start > last->end || end < first->start)
  		return true;
  
  	/* Check for any existing dma mappings below the new start */
  	if (start > first->start) {
  		if (vfio_find_dma(iommu, first->start, start - first->start))
  			return true;
  	}
  
  	/* Check for any existing dma mappings beyond the new end */
  	if (end < last->end) {
  		if (vfio_find_dma(iommu, end + 1, last->end - end))
  			return true;
  	}
  
  	return false;
  }
  
  /*
   * Resize iommu iova aperture window. This is called only if the new
   * aperture has no conflict with existing aperture and dma mappings.
   */
  static int vfio_iommu_aper_resize(struct list_head *iova,
  				  dma_addr_t start, dma_addr_t end)
  {
  	struct vfio_iova *node, *next;
  
  	if (list_empty(iova))
  		return vfio_iommu_iova_insert(iova, start, end);
  
  	/* Adjust iova list start */
  	list_for_each_entry_safe(node, next, iova, list) {
  		if (start < node->start)
  			break;
  		if (start >= node->start && start < node->end) {
  			node->start = start;
  			break;
  		}
  		/* Delete nodes before new start */
  		list_del(&node->list);
  		kfree(node);
  	}
  
  	/* Adjust iova list end */
  	list_for_each_entry_safe(node, next, iova, list) {
  		if (end > node->end)
  			continue;
  		if (end > node->start && end <= node->end) {
  			node->end = end;
  			continue;
  		}
  		/* Delete nodes after new end */
  		list_del(&node->list);
  		kfree(node);
  	}
  
  	return 0;
  }
af029169b   Shameer Kolothum   vfio/type1: Check...
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
  /*
   * Check reserved region conflicts with existing dma mappings
   */
  static bool vfio_iommu_resv_conflict(struct vfio_iommu *iommu,
  				     struct list_head *resv_regions)
  {
  	struct iommu_resv_region *region;
  
  	/* Check for conflict with existing dma mappings */
  	list_for_each_entry(region, resv_regions, list) {
  		if (region->type == IOMMU_RESV_DIRECT_RELAXABLE)
  			continue;
  
  		if (vfio_find_dma(iommu, region->start, region->length))
  			return true;
  	}
  
  	return false;
  }
  
  /*
   * Check iova region overlap with  reserved regions and
   * exclude them from the iommu iova range
   */
  static int vfio_iommu_resv_exclude(struct list_head *iova,
  				   struct list_head *resv_regions)
  {
  	struct iommu_resv_region *resv;
  	struct vfio_iova *n, *next;
  
  	list_for_each_entry(resv, resv_regions, list) {
  		phys_addr_t start, end;
  
  		if (resv->type == IOMMU_RESV_DIRECT_RELAXABLE)
  			continue;
  
  		start = resv->start;
  		end = resv->start + resv->length - 1;
  
  		list_for_each_entry_safe(n, next, iova, list) {
  			int ret = 0;
  
  			/* No overlap */
  			if (start > n->end || end < n->start)
  				continue;
  			/*
  			 * Insert a new node if current node overlaps with the
  			 * reserve region to exlude that from valid iova range.
  			 * Note that, new node is inserted before the current
  			 * node and finally the current node is deleted keeping
  			 * the list updated and sorted.
  			 */
  			if (start > n->start)
  				ret = vfio_iommu_iova_insert(&n->list, n->start,
  							     start - 1);
  			if (!ret && end < n->end)
  				ret = vfio_iommu_iova_insert(&n->list, end + 1,
  							     n->end);
  			if (ret)
  				return ret;
  
  			list_del(&n->list);
  			kfree(n);
  		}
  	}
  
  	if (list_empty(iova))
  		return -EINVAL;
  
  	return 0;
  }
  
  static void vfio_iommu_resv_free(struct list_head *resv_regions)
  {
  	struct iommu_resv_region *n, *next;
  
  	list_for_each_entry_safe(n, next, resv_regions, list) {
  		list_del(&n->list);
  		kfree(n);
  	}
  }
1108696ae   Shameer Kolothum   vfio/type1: Intro...
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
  static void vfio_iommu_iova_free(struct list_head *iova)
  {
  	struct vfio_iova *n, *next;
  
  	list_for_each_entry_safe(n, next, iova, list) {
  		list_del(&n->list);
  		kfree(n);
  	}
  }
  
  static int vfio_iommu_iova_get_copy(struct vfio_iommu *iommu,
  				    struct list_head *iova_copy)
  {
  	struct list_head *iova = &iommu->iova_list;
  	struct vfio_iova *n;
  	int ret;
  
  	list_for_each_entry(n, iova, list) {
  		ret = vfio_iommu_iova_insert(iova_copy, n->start, n->end);
  		if (ret)
  			goto out_free;
  	}
  
  	return 0;
  
  out_free:
  	vfio_iommu_iova_free(iova_copy);
  	return ret;
  }
  
  static void vfio_iommu_iova_insert_copy(struct vfio_iommu *iommu,
  					struct list_head *iova_copy)
  {
  	struct list_head *iova = &iommu->iova_list;
  
  	vfio_iommu_iova_free(iova);
  
  	list_splice_tail(iova_copy, iova);
  }
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1673
1674
1675
1676
  static int vfio_iommu_type1_attach_group(void *iommu_data,
  					 struct iommu_group *iommu_group)
  {
  	struct vfio_iommu *iommu = iommu_data;
7896c998f   Kirti Wankhede   vfio iommu type1:...
1677
  	struct vfio_group *group;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1678
  	struct vfio_domain *domain, *d;
be068fa23   Lu Baolu   vfio/type1: Handl...
1679
  	struct bus_type *bus = NULL;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1680
  	int ret;
9d72f87ba   Eric Auger   vfio/type1: Check...
1681
  	bool resv_msi, msi_remap;
95f89e090   Joerg Roedel   vfio/type1: Initi...
1682
  	phys_addr_t resv_msi_base = 0;
1108696ae   Shameer Kolothum   vfio/type1: Intro...
1683
1684
  	struct iommu_domain_geometry geo;
  	LIST_HEAD(iova_copy);
af029169b   Shameer Kolothum   vfio/type1: Check...
1685
  	LIST_HEAD(group_resv_regions);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1686

73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1687
  	mutex_lock(&iommu->lock);
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1688
  	list_for_each_entry(d, &iommu->domain_list, next) {
7896c998f   Kirti Wankhede   vfio iommu type1:...
1689
  		if (find_iommu_group(d, iommu_group)) {
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1690
  			mutex_unlock(&iommu->lock);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1691
1692
1693
  			return -EINVAL;
  		}
  	}
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1694
1695
1696
1697
1698
1699
  	if (iommu->external_domain) {
  		if (find_iommu_group(iommu->external_domain, iommu_group)) {
  			mutex_unlock(&iommu->lock);
  			return -EINVAL;
  		}
  	}
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
  	group = kzalloc(sizeof(*group), GFP_KERNEL);
  	domain = kzalloc(sizeof(*domain), GFP_KERNEL);
  	if (!group || !domain) {
  		ret = -ENOMEM;
  		goto out_free;
  	}
  
  	group->iommu_group = iommu_group;
  
  	/* Determine bus_type in order to allocate a domain */
  	ret = iommu_group_for_each_dev(iommu_group, &bus, vfio_bus_type);
  	if (ret)
  		goto out_free;
be068fa23   Lu Baolu   vfio/type1: Handl...
1713
1714
  	if (vfio_bus_is_mdev(bus)) {
  		struct device *iommu_device = NULL;
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1715

be068fa23   Lu Baolu   vfio/type1: Handl...
1716
1717
1718
1719
1720
1721
  		group->mdev_group = true;
  
  		/* Determine the isolation type */
  		ret = iommu_group_for_each_dev(iommu_group, &iommu_device,
  					       vfio_mdev_iommu_device);
  		if (ret || !iommu_device) {
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1722
1723
1724
  			if (!iommu->external_domain) {
  				INIT_LIST_HEAD(&domain->group_list);
  				iommu->external_domain = domain;
be068fa23   Lu Baolu   vfio/type1: Handl...
1725
  			} else {
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1726
  				kfree(domain);
be068fa23   Lu Baolu   vfio/type1: Handl...
1727
  			}
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1728
1729
1730
1731
  
  			list_add(&group->next,
  				 &iommu->external_domain->group_list);
  			mutex_unlock(&iommu->lock);
be068fa23   Lu Baolu   vfio/type1: Handl...
1732

a54eb5504   Kirti Wankhede   vfio iommu type1:...
1733
1734
  			return 0;
  		}
be068fa23   Lu Baolu   vfio/type1: Handl...
1735
1736
  
  		bus = iommu_device->bus;
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1737
  	}
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1738
1739
1740
1741
1742
  	domain->domain = iommu_domain_alloc(bus);
  	if (!domain->domain) {
  		ret = -EIO;
  		goto out_free;
  	}
f5c9eceba   Will Deacon   vfio/iommu_type1:...
1743
1744
1745
1746
1747
1748
1749
1750
  	if (iommu->nesting) {
  		int attr = 1;
  
  		ret = iommu_domain_set_attr(domain->domain, DOMAIN_ATTR_NESTING,
  					    &attr);
  		if (ret)
  			goto out_domain;
  	}
7bd50f0cd   Lu Baolu   vfio/type1: Add d...
1751
  	ret = vfio_iommu_attach_group(domain, group);
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1752
1753
  	if (ret)
  		goto out_domain;
1108696ae   Shameer Kolothum   vfio/type1: Intro...
1754
1755
1756
1757
1758
1759
1760
1761
  	/* Get aperture info */
  	iommu_domain_get_attr(domain->domain, DOMAIN_ATTR_GEOMETRY, &geo);
  
  	if (vfio_iommu_aper_conflict(iommu, geo.aperture_start,
  				     geo.aperture_end)) {
  		ret = -EINVAL;
  		goto out_detach;
  	}
af029169b   Shameer Kolothum   vfio/type1: Check...
1762
1763
1764
1765
1766
1767
1768
1769
  	ret = iommu_get_group_resv_regions(iommu_group, &group_resv_regions);
  	if (ret)
  		goto out_detach;
  
  	if (vfio_iommu_resv_conflict(iommu, &group_resv_regions)) {
  		ret = -EINVAL;
  		goto out_detach;
  	}
1108696ae   Shameer Kolothum   vfio/type1: Intro...
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
  	/*
  	 * We don't want to work on the original iova list as the list
  	 * gets modified and in case of failure we have to retain the
  	 * original list. Get a copy here.
  	 */
  	ret = vfio_iommu_iova_get_copy(iommu, &iova_copy);
  	if (ret)
  		goto out_detach;
  
  	ret = vfio_iommu_aper_resize(&iova_copy, geo.aperture_start,
  				     geo.aperture_end);
  	if (ret)
  		goto out_detach;
af029169b   Shameer Kolothum   vfio/type1: Check...
1783
1784
1785
  	ret = vfio_iommu_resv_exclude(&iova_copy, &group_resv_regions);
  	if (ret)
  		goto out_detach;
b09d6e473   Shameer Kolothum   vfio/type1: remov...
1786
  	resv_msi = vfio_iommu_has_sw_msi(&group_resv_regions, &resv_msi_base);
5d7049921   Eric Auger   vfio/type1: Allow...
1787

1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1788
1789
  	INIT_LIST_HEAD(&domain->group_list);
  	list_add(&group->next, &domain->group_list);
db406cc0a   Robin Murphy   vfio/type1: Cope ...
1790
1791
  	msi_remap = irq_domain_check_msi_remap() ||
  		    iommu_capable(bus, IOMMU_CAP_INTR_REMAP);
9d72f87ba   Eric Auger   vfio/type1: Check...
1792
1793
  
  	if (!allow_unsafe_interrupts && !msi_remap) {
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1794
1795
1796
1797
1798
1799
  		pr_warn("%s: No interrupt remapping support.  Use the module param \"allow_unsafe_interrupts\" to enable VFIO IOMMU support on this platform
  ",
  		       __func__);
  		ret = -EPERM;
  		goto out_detach;
  	}
eb165f058   Joerg Roedel   vfio: Convert to ...
1800
  	if (iommu_capable(bus, IOMMU_CAP_CACHE_COHERENCY))
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1801
  		domain->prot |= IOMMU_CACHE;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1802
  	/*
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1803
1804
1805
1806
1807
  	 * Try to match an existing compatible domain.  We don't want to
  	 * preclude an IOMMU driver supporting multiple bus_types and being
  	 * able to include different bus_types in the same IOMMU domain, so
  	 * we test whether the domains use the same iommu_ops rather than
  	 * testing if they're on the same bus_type.
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1808
  	 */
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1809
1810
1811
  	list_for_each_entry(d, &iommu->domain_list, next) {
  		if (d->domain->ops == domain->domain->ops &&
  		    d->prot == domain->prot) {
7bd50f0cd   Lu Baolu   vfio/type1: Add d...
1812
1813
  			vfio_iommu_detach_group(domain, group);
  			if (!vfio_iommu_attach_group(d, group)) {
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1814
1815
1816
  				list_add(&group->next, &d->group_list);
  				iommu_domain_free(domain->domain);
  				kfree(domain);
1108696ae   Shameer Kolothum   vfio/type1: Intro...
1817
  				goto done;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1818
  			}
7bd50f0cd   Lu Baolu   vfio/type1: Add d...
1819
  			ret = vfio_iommu_attach_group(domain, group);
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1820
1821
1822
  			if (ret)
  				goto out_domain;
  		}
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1823
  	}
6fe1010d6   Alex Williamson   vfio/type1: DMA u...
1824
  	vfio_test_domain_fgsp(domain);
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1825
1826
1827
1828
  	/* replay mappings on new domains */
  	ret = vfio_iommu_replay(iommu, domain);
  	if (ret)
  		goto out_detach;
2c9f1af52   Wei Yongjun   vfio/type1: Fix e...
1829
1830
1831
1832
1833
  	if (resv_msi) {
  		ret = iommu_get_msi_cookie(domain->domain, resv_msi_base);
  		if (ret)
  			goto out_detach;
  	}
5d7049921   Eric Auger   vfio/type1: Allow...
1834

1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1835
  	list_add(&domain->next, &iommu->domain_list);
1108696ae   Shameer Kolothum   vfio/type1: Intro...
1836
1837
1838
  done:
  	/* Delete the old one and insert new iova list */
  	vfio_iommu_iova_insert_copy(iommu, &iova_copy);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1839
  	mutex_unlock(&iommu->lock);
af029169b   Shameer Kolothum   vfio/type1: Check...
1840
  	vfio_iommu_resv_free(&group_resv_regions);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1841
1842
  
  	return 0;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1843
1844
  
  out_detach:
7bd50f0cd   Lu Baolu   vfio/type1: Add d...
1845
  	vfio_iommu_detach_group(domain, group);
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1846
1847
  out_domain:
  	iommu_domain_free(domain->domain);
1108696ae   Shameer Kolothum   vfio/type1: Intro...
1848
  	vfio_iommu_iova_free(&iova_copy);
af029169b   Shameer Kolothum   vfio/type1: Check...
1849
  	vfio_iommu_resv_free(&group_resv_regions);
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
  out_free:
  	kfree(domain);
  	kfree(group);
  	mutex_unlock(&iommu->lock);
  	return ret;
  }
  
  static void vfio_iommu_unmap_unpin_all(struct vfio_iommu *iommu)
  {
  	struct rb_node *node;
  
  	while ((node = rb_first(&iommu->dma_list)))
  		vfio_remove_dma(iommu, rb_entry(node, struct vfio_dma, node));
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1863
  }
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
  static void vfio_iommu_unmap_unpin_reaccount(struct vfio_iommu *iommu)
  {
  	struct rb_node *n, *p;
  
  	n = rb_first(&iommu->dma_list);
  	for (; n; n = rb_next(n)) {
  		struct vfio_dma *dma;
  		long locked = 0, unlocked = 0;
  
  		dma = rb_entry(n, struct vfio_dma, node);
  		unlocked += vfio_unmap_unpin(iommu, dma, false);
  		p = rb_first(&dma->pfn_list);
  		for (; p; p = rb_next(p)) {
  			struct vfio_pfn *vpfn = rb_entry(p, struct vfio_pfn,
  							 node);
  
  			if (!is_invalid_reserved_pfn(vpfn->pfn))
  				locked++;
  		}
48d8476b4   Alex Williamson   vfio/type1: Fix t...
1883
  		vfio_lock_acct(dma, locked - unlocked, true);
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
  	}
  }
  
  static void vfio_sanity_check_pfn_list(struct vfio_iommu *iommu)
  {
  	struct rb_node *n;
  
  	n = rb_first(&iommu->dma_list);
  	for (; n; n = rb_next(n)) {
  		struct vfio_dma *dma;
  
  		dma = rb_entry(n, struct vfio_dma, node);
  
  		if (WARN_ON(!RB_EMPTY_ROOT(&dma->pfn_list)))
  			break;
  	}
3cedd7d75   Kirti Wankhede   vfio iommu type1:...
1900
1901
  	/* mdev vendor driver must unregister notifier */
  	WARN_ON(iommu->notifier.head);
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1902
  }
f45daadfe   Shameer Kolothum   vfio/type1: Updat...
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
  /*
   * Called when a domain is removed in detach. It is possible that
   * the removed domain decided the iova aperture window. Modify the
   * iova aperture with the smallest window among existing domains.
   */
  static void vfio_iommu_aper_expand(struct vfio_iommu *iommu,
  				   struct list_head *iova_copy)
  {
  	struct vfio_domain *domain;
  	struct iommu_domain_geometry geo;
  	struct vfio_iova *node;
  	dma_addr_t start = 0;
  	dma_addr_t end = (dma_addr_t)~0;
  
  	if (list_empty(iova_copy))
  		return;
  
  	list_for_each_entry(domain, &iommu->domain_list, next) {
  		iommu_domain_get_attr(domain->domain, DOMAIN_ATTR_GEOMETRY,
  				      &geo);
  		if (geo.aperture_start > start)
  			start = geo.aperture_start;
  		if (geo.aperture_end < end)
  			end = geo.aperture_end;
  	}
  
  	/* Modify aperture limits. The new aper is either same or bigger */
  	node = list_first_entry(iova_copy, struct vfio_iova, list);
  	node->start = start;
  	node = list_last_entry(iova_copy, struct vfio_iova, list);
  	node->end = end;
  }
  
  /*
   * Called when a group is detached. The reserved regions for that
   * group can be part of valid iova now. But since reserved regions
   * may be duplicated among groups, populate the iova valid regions
   * list again.
   */
  static int vfio_iommu_resv_refresh(struct vfio_iommu *iommu,
  				   struct list_head *iova_copy)
  {
  	struct vfio_domain *d;
  	struct vfio_group *g;
  	struct vfio_iova *node;
  	dma_addr_t start, end;
  	LIST_HEAD(resv_regions);
  	int ret;
  
  	if (list_empty(iova_copy))
  		return -EINVAL;
  
  	list_for_each_entry(d, &iommu->domain_list, next) {
  		list_for_each_entry(g, &d->group_list, next) {
  			ret = iommu_get_group_resv_regions(g->iommu_group,
  							   &resv_regions);
  			if (ret)
  				goto done;
  		}
  	}
  
  	node = list_first_entry(iova_copy, struct vfio_iova, list);
  	start = node->start;
  	node = list_last_entry(iova_copy, struct vfio_iova, list);
  	end = node->end;
  
  	/* purge the iova list and create new one */
  	vfio_iommu_iova_free(iova_copy);
  
  	ret = vfio_iommu_aper_resize(iova_copy, start, end);
  	if (ret)
  		goto done;
  
  	/* Exclude current reserved regions from iova ranges */
  	ret = vfio_iommu_resv_exclude(iova_copy, &resv_regions);
  done:
  	vfio_iommu_resv_free(&resv_regions);
  	return ret;
  }
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1982
1983
1984
1985
  static void vfio_iommu_type1_detach_group(void *iommu_data,
  					  struct iommu_group *iommu_group)
  {
  	struct vfio_iommu *iommu = iommu_data;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
1986
  	struct vfio_domain *domain;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1987
  	struct vfio_group *group;
f45daadfe   Shameer Kolothum   vfio/type1: Updat...
1988
  	LIST_HEAD(iova_copy);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
1989
1990
  
  	mutex_lock(&iommu->lock);
a54eb5504   Kirti Wankhede   vfio iommu type1:...
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
  	if (iommu->external_domain) {
  		group = find_iommu_group(iommu->external_domain, iommu_group);
  		if (group) {
  			list_del(&group->next);
  			kfree(group);
  
  			if (list_empty(&iommu->external_domain->group_list)) {
  				vfio_sanity_check_pfn_list(iommu);
  
  				if (!IS_IOMMU_CAP_DOMAIN_IN_CONTAINER(iommu))
  					vfio_iommu_unmap_unpin_all(iommu);
  
  				kfree(iommu->external_domain);
  				iommu->external_domain = NULL;
  			}
  			goto detach_group_done;
  		}
  	}
f45daadfe   Shameer Kolothum   vfio/type1: Updat...
2009
2010
2011
2012
2013
2014
  	/*
  	 * Get a copy of iova list. This will be used to update
  	 * and to replace the current one later. Please note that
  	 * we will leave the original list as it is if update fails.
  	 */
  	vfio_iommu_iova_get_copy(iommu, &iova_copy);
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
2015
  	list_for_each_entry(domain, &iommu->domain_list, next) {
7896c998f   Kirti Wankhede   vfio iommu type1:...
2016
2017
2018
  		group = find_iommu_group(domain, iommu_group);
  		if (!group)
  			continue;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
2019

7bd50f0cd   Lu Baolu   vfio/type1: Add d...
2020
  		vfio_iommu_detach_group(domain, group);
7896c998f   Kirti Wankhede   vfio iommu type1:...
2021
2022
2023
  		list_del(&group->next);
  		kfree(group);
  		/*
a54eb5504   Kirti Wankhede   vfio iommu type1:...
2024
2025
2026
2027
2028
  		 * Group ownership provides privilege, if the group list is
  		 * empty, the domain goes away. If it's the last domain with
  		 * iommu and external domain doesn't exist, then all the
  		 * mappings go away too. If it's the last domain with iommu and
  		 * external domain exist, update accounting
7896c998f   Kirti Wankhede   vfio iommu type1:...
2029
2030
  		 */
  		if (list_empty(&domain->group_list)) {
a54eb5504   Kirti Wankhede   vfio iommu type1:...
2031
2032
2033
2034
2035
2036
  			if (list_is_singular(&iommu->domain_list)) {
  				if (!iommu->external_domain)
  					vfio_iommu_unmap_unpin_all(iommu);
  				else
  					vfio_iommu_unmap_unpin_reaccount(iommu);
  			}
7896c998f   Kirti Wankhede   vfio iommu type1:...
2037
2038
2039
  			iommu_domain_free(domain->domain);
  			list_del(&domain->next);
  			kfree(domain);
f45daadfe   Shameer Kolothum   vfio/type1: Updat...
2040
  			vfio_iommu_aper_expand(iommu, &iova_copy);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2041
  		}
a54eb5504   Kirti Wankhede   vfio iommu type1:...
2042
  		break;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2043
  	}
f45daadfe   Shameer Kolothum   vfio/type1: Updat...
2044
2045
2046
2047
  	if (!vfio_iommu_resv_refresh(iommu, &iova_copy))
  		vfio_iommu_iova_insert_copy(iommu, &iova_copy);
  	else
  		vfio_iommu_iova_free(&iova_copy);
a54eb5504   Kirti Wankhede   vfio iommu type1:...
2048
  detach_group_done:
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2049
2050
2051
2052
2053
2054
  	mutex_unlock(&iommu->lock);
  }
  
  static void *vfio_iommu_type1_open(unsigned long arg)
  {
  	struct vfio_iommu *iommu;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2055
2056
2057
  	iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
  	if (!iommu)
  		return ERR_PTR(-ENOMEM);
f5c9eceba   Will Deacon   vfio/iommu_type1:...
2058
2059
2060
2061
2062
  	switch (arg) {
  	case VFIO_TYPE1_IOMMU:
  		break;
  	case VFIO_TYPE1_NESTING_IOMMU:
  		iommu->nesting = true;
544c05a60   Gustavo A. R. Silva   vfio: Mark expect...
2063
  		/* fall through */
f5c9eceba   Will Deacon   vfio/iommu_type1:...
2064
2065
2066
2067
2068
2069
2070
  	case VFIO_TYPE1v2_IOMMU:
  		iommu->v2 = true;
  		break;
  	default:
  		kfree(iommu);
  		return ERR_PTR(-EINVAL);
  	}
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
2071
  	INIT_LIST_HEAD(&iommu->domain_list);
1108696ae   Shameer Kolothum   vfio/type1: Intro...
2072
  	INIT_LIST_HEAD(&iommu->iova_list);
cd9b22685   Alex Williamson   vfio: Convert typ...
2073
  	iommu->dma_list = RB_ROOT;
492855939   Alex Williamson   vfio/type1: Limit...
2074
  	iommu->dma_avail = dma_entry_limit;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2075
  	mutex_init(&iommu->lock);
c086de818   Kirti Wankhede   vfio iommu: Add b...
2076
  	BLOCKING_INIT_NOTIFIER_HEAD(&iommu->notifier);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2077
2078
2079
  
  	return iommu;
  }
a54eb5504   Kirti Wankhede   vfio iommu type1:...
2080
2081
2082
2083
2084
2085
2086
  static void vfio_release_domain(struct vfio_domain *domain, bool external)
  {
  	struct vfio_group *group, *group_tmp;
  
  	list_for_each_entry_safe(group, group_tmp,
  				 &domain->group_list, next) {
  		if (!external)
7bd50f0cd   Lu Baolu   vfio/type1: Add d...
2087
  			vfio_iommu_detach_group(domain, group);
a54eb5504   Kirti Wankhede   vfio iommu type1:...
2088
2089
2090
2091
2092
2093
2094
  		list_del(&group->next);
  		kfree(group);
  	}
  
  	if (!external)
  		iommu_domain_free(domain->domain);
  }
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2095
2096
2097
  static void vfio_iommu_type1_release(void *iommu_data)
  {
  	struct vfio_iommu *iommu = iommu_data;
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
2098
  	struct vfio_domain *domain, *domain_tmp;
a54eb5504   Kirti Wankhede   vfio iommu type1:...
2099
2100
2101
2102
2103
2104
  
  	if (iommu->external_domain) {
  		vfio_release_domain(iommu->external_domain, true);
  		vfio_sanity_check_pfn_list(iommu);
  		kfree(iommu->external_domain);
  	}
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2105

1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
2106
  	vfio_iommu_unmap_unpin_all(iommu);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2107

1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
2108
2109
  	list_for_each_entry_safe(domain, domain_tmp,
  				 &iommu->domain_list, next) {
a54eb5504   Kirti Wankhede   vfio iommu type1:...
2110
  		vfio_release_domain(domain, false);
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
2111
2112
  		list_del(&domain->next);
  		kfree(domain);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2113
  	}
1108696ae   Shameer Kolothum   vfio/type1: Intro...
2114
2115
  
  	vfio_iommu_iova_free(&iommu->iova_list);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2116
2117
  	kfree(iommu);
  }
aa4293182   Alex Williamson   vfio/type1: Add e...
2118
2119
2120
2121
2122
2123
2124
2125
2126
  static int vfio_domains_have_iommu_cache(struct vfio_iommu *iommu)
  {
  	struct vfio_domain *domain;
  	int ret = 1;
  
  	mutex_lock(&iommu->lock);
  	list_for_each_entry(domain, &iommu->domain_list, next) {
  		if (!(domain->prot & IOMMU_CACHE)) {
  			ret = 0;
f5bfdbf25   Alex Williamson   vfio/type1: Fix m...
2127
  			break;
aa4293182   Alex Williamson   vfio/type1: Add e...
2128
  		}
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2129
  	}
aa4293182   Alex Williamson   vfio/type1: Add e...
2130
  	mutex_unlock(&iommu->lock);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2131

aa4293182   Alex Williamson   vfio/type1: Add e...
2132
  	return ret;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2133
  }
a71707200   Shameer Kolothum   vfio/type1: Add I...
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
  static int vfio_iommu_iova_add_cap(struct vfio_info_cap *caps,
  		 struct vfio_iommu_type1_info_cap_iova_range *cap_iovas,
  		 size_t size)
  {
  	struct vfio_info_cap_header *header;
  	struct vfio_iommu_type1_info_cap_iova_range *iova_cap;
  
  	header = vfio_info_cap_add(caps, size,
  				   VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE, 1);
  	if (IS_ERR(header))
  		return PTR_ERR(header);
  
  	iova_cap = container_of(header,
  				struct vfio_iommu_type1_info_cap_iova_range,
  				header);
  	iova_cap->nr_iovas = cap_iovas->nr_iovas;
  	memcpy(iova_cap->iova_ranges, cap_iovas->iova_ranges,
  	       cap_iovas->nr_iovas * sizeof(*cap_iovas->iova_ranges));
  	return 0;
  }
  
  static int vfio_iommu_iova_build_caps(struct vfio_iommu *iommu,
  				      struct vfio_info_cap *caps)
  {
  	struct vfio_iommu_type1_info_cap_iova_range *cap_iovas;
  	struct vfio_iova *iova;
  	size_t size;
  	int iovas = 0, i = 0, ret;
  
  	mutex_lock(&iommu->lock);
  
  	list_for_each_entry(iova, &iommu->iova_list, list)
  		iovas++;
  
  	if (!iovas) {
  		/*
  		 * Return 0 as a container with a single mdev device
  		 * will have an empty list
  		 */
  		ret = 0;
  		goto out_unlock;
  	}
  
  	size = sizeof(*cap_iovas) + (iovas * sizeof(*cap_iovas->iova_ranges));
  
  	cap_iovas = kzalloc(size, GFP_KERNEL);
  	if (!cap_iovas) {
  		ret = -ENOMEM;
  		goto out_unlock;
  	}
  
  	cap_iovas->nr_iovas = iovas;
  
  	list_for_each_entry(iova, &iommu->iova_list, list) {
  		cap_iovas->iova_ranges[i].start = iova->start;
  		cap_iovas->iova_ranges[i].end = iova->end;
  		i++;
  	}
  
  	ret = vfio_iommu_iova_add_cap(caps, cap_iovas, size);
  
  	kfree(cap_iovas);
  out_unlock:
  	mutex_unlock(&iommu->lock);
  	return ret;
  }
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2200
2201
2202
2203
2204
2205
2206
2207
2208
  static long vfio_iommu_type1_ioctl(void *iommu_data,
  				   unsigned int cmd, unsigned long arg)
  {
  	struct vfio_iommu *iommu = iommu_data;
  	unsigned long minsz;
  
  	if (cmd == VFIO_CHECK_EXTENSION) {
  		switch (arg) {
  		case VFIO_TYPE1_IOMMU:
1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
2209
  		case VFIO_TYPE1v2_IOMMU:
f5c9eceba   Will Deacon   vfio/iommu_type1:...
2210
  		case VFIO_TYPE1_NESTING_IOMMU:
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2211
  			return 1;
aa4293182   Alex Williamson   vfio/type1: Add e...
2212
2213
2214
2215
  		case VFIO_DMA_CC_IOMMU:
  			if (!iommu)
  				return 0;
  			return vfio_domains_have_iommu_cache(iommu);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2216
2217
2218
2219
2220
  		default:
  			return 0;
  		}
  	} else if (cmd == VFIO_IOMMU_GET_INFO) {
  		struct vfio_iommu_type1_info info;
a71707200   Shameer Kolothum   vfio/type1: Add I...
2221
2222
2223
  		struct vfio_info_cap caps = { .buf = NULL, .size = 0 };
  		unsigned long capsz;
  		int ret;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2224
2225
  
  		minsz = offsetofend(struct vfio_iommu_type1_info, iova_pgsizes);
a71707200   Shameer Kolothum   vfio/type1: Add I...
2226
2227
  		/* For backward compatibility, cannot require this */
  		capsz = offsetofend(struct vfio_iommu_type1_info, cap_offset);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2228
2229
2230
2231
2232
  		if (copy_from_user(&info, (void __user *)arg, minsz))
  			return -EFAULT;
  
  		if (info.argsz < minsz)
  			return -EINVAL;
a71707200   Shameer Kolothum   vfio/type1: Add I...
2233
2234
2235
2236
  		if (info.argsz >= capsz) {
  			minsz = capsz;
  			info.cap_offset = 0; /* output, no-recopy necessary */
  		}
d4f50ee2f   Pierre Morel   vfio/iommu_type1:...
2237
  		info.flags = VFIO_IOMMU_INFO_PGSIZES;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2238

1ef3e2bc0   Alex Williamson   vfio/iommu_type1:...
2239
  		info.iova_pgsizes = vfio_pgsize_bitmap(iommu);
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2240

a71707200   Shameer Kolothum   vfio/type1: Add I...
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
  		ret = vfio_iommu_iova_build_caps(iommu, &caps);
  		if (ret)
  			return ret;
  
  		if (caps.size) {
  			info.flags |= VFIO_IOMMU_INFO_CAPS;
  
  			if (info.argsz < sizeof(info) + caps.size) {
  				info.argsz = sizeof(info) + caps.size;
  			} else {
  				vfio_info_cap_shift(&caps, sizeof(info));
  				if (copy_to_user((void __user *)arg +
  						sizeof(info), caps.buf,
  						caps.size)) {
  					kfree(caps.buf);
  					return -EFAULT;
  				}
  				info.cap_offset = sizeof(info);
  			}
  
  			kfree(caps.buf);
  		}
8160c4e45   Michael S. Tsirkin   vfio: fix ioctl e...
2263
2264
  		return copy_to_user((void __user *)arg, &info, minsz) ?
  			-EFAULT : 0;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
  
  	} else if (cmd == VFIO_IOMMU_MAP_DMA) {
  		struct vfio_iommu_type1_dma_map map;
  		uint32_t mask = VFIO_DMA_MAP_FLAG_READ |
  				VFIO_DMA_MAP_FLAG_WRITE;
  
  		minsz = offsetofend(struct vfio_iommu_type1_dma_map, size);
  
  		if (copy_from_user(&map, (void __user *)arg, minsz))
  			return -EFAULT;
  
  		if (map.argsz < minsz || map.flags & ~mask)
  			return -EINVAL;
  
  		return vfio_dma_do_map(iommu, &map);
  
  	} else if (cmd == VFIO_IOMMU_UNMAP_DMA) {
  		struct vfio_iommu_type1_dma_unmap unmap;
166fd7d94   Alex Williamson   vfio: hugepage su...
2283
  		long ret;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2284
2285
2286
2287
2288
2289
2290
2291
  
  		minsz = offsetofend(struct vfio_iommu_type1_dma_unmap, size);
  
  		if (copy_from_user(&unmap, (void __user *)arg, minsz))
  			return -EFAULT;
  
  		if (unmap.argsz < minsz || unmap.flags)
  			return -EINVAL;
166fd7d94   Alex Williamson   vfio: hugepage su...
2292
2293
2294
  		ret = vfio_dma_do_unmap(iommu, &unmap);
  		if (ret)
  			return ret;
8160c4e45   Michael S. Tsirkin   vfio: fix ioctl e...
2295
2296
  		return copy_to_user((void __user *)arg, &unmap, minsz) ?
  			-EFAULT : 0;
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2297
2298
2299
2300
  	}
  
  	return -ENOTTY;
  }
c086de818   Kirti Wankhede   vfio iommu: Add b...
2301
  static int vfio_iommu_type1_register_notifier(void *iommu_data,
22195cbd3   Jike Song   vfio: vfio_regist...
2302
  					      unsigned long *events,
c086de818   Kirti Wankhede   vfio iommu: Add b...
2303
2304
2305
  					      struct notifier_block *nb)
  {
  	struct vfio_iommu *iommu = iommu_data;
22195cbd3   Jike Song   vfio: vfio_regist...
2306
2307
2308
2309
2310
2311
  	/* clear known events */
  	*events &= ~VFIO_IOMMU_NOTIFY_DMA_UNMAP;
  
  	/* refuse to register if still events remaining */
  	if (*events)
  		return -EINVAL;
c086de818   Kirti Wankhede   vfio iommu: Add b...
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
  	return blocking_notifier_chain_register(&iommu->notifier, nb);
  }
  
  static int vfio_iommu_type1_unregister_notifier(void *iommu_data,
  						struct notifier_block *nb)
  {
  	struct vfio_iommu *iommu = iommu_data;
  
  	return blocking_notifier_chain_unregister(&iommu->notifier, nb);
  }
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2322
  static const struct vfio_iommu_driver_ops vfio_iommu_driver_ops_type1 = {
c086de818   Kirti Wankhede   vfio iommu: Add b...
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
  	.name			= "vfio-iommu-type1",
  	.owner			= THIS_MODULE,
  	.open			= vfio_iommu_type1_open,
  	.release		= vfio_iommu_type1_release,
  	.ioctl			= vfio_iommu_type1_ioctl,
  	.attach_group		= vfio_iommu_type1_attach_group,
  	.detach_group		= vfio_iommu_type1_detach_group,
  	.pin_pages		= vfio_iommu_type1_pin_pages,
  	.unpin_pages		= vfio_iommu_type1_unpin_pages,
  	.register_notifier	= vfio_iommu_type1_register_notifier,
  	.unregister_notifier	= vfio_iommu_type1_unregister_notifier,
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2334
2335
2336
2337
  };
  
  static int __init vfio_iommu_type1_init(void)
  {
73fa0d10d   Alex Williamson   vfio: Type1 IOMMU...
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
  	return vfio_register_iommu_driver(&vfio_iommu_driver_ops_type1);
  }
  
  static void __exit vfio_iommu_type1_cleanup(void)
  {
  	vfio_unregister_iommu_driver(&vfio_iommu_driver_ops_type1);
  }
  
  module_init(vfio_iommu_type1_init);
  module_exit(vfio_iommu_type1_cleanup);
  
  MODULE_VERSION(DRIVER_VERSION);
  MODULE_LICENSE("GPL v2");
  MODULE_AUTHOR(DRIVER_AUTHOR);
  MODULE_DESCRIPTION(DRIVER_DESC);