Skip to content

Commit 056daec

Browse files
committed
Merge tag 'for-linus-iommufd' of git://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd
Pull iommufd updates from Jason Gunthorpe: "This is a pretty consequential cycle for iommufd, though this pull is not too big. It is based on a shared branch with VFIO that introduces VFIO_DEVICE_FEATURE_DMA_BUF a DMABUF exporter for VFIO device's MMIO PCI BARs. This was a large multiple series journey over the last year and a half. Based on that work IOMMUFD gains support for VFIO DMABUF's in its existing IOMMU_IOAS_MAP_FILE, which closes the last major gap to support PCI peer to peer transfers within VMs. In Joerg's iommu tree we have the "generic page table" work which aims to consolidate all the duplicated page table code in every iommu driver into a single algorithm. This will be used by iommufd to implement unique page table operations to start adding new features and improve performance. In here: - Expand IOMMU_IOAS_MAP_FILE to accept a DMABUF exported from VFIO. This is the first step to broader DMABUF support in iommufd, right now it only works with VFIO. This closes the last functional gap with classic VFIO type 1 to safely support PCI peer to peer DMA by mapping the VFIO device's MMIO into the IOMMU. - Relax SMMUv3 restrictions on nesting domains to better support qemu's sequence to have an identity mapping before the vSID is established" * tag 'for-linus-iommufd' of git://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd: iommu/arm-smmu-v3-iommufd: Allow attaching nested domain for GBPA cases iommufd/selftest: Add some tests for the dmabuf flow iommufd: Accept a DMABUF through IOMMU_IOAS_MAP_FILE iommufd: Have iopt_map_file_pages convert the fd to a file iommufd: Have pfn_reader process DMABUF iopt_pages iommufd: Allow MMIO pages in a batch iommufd: Allow a DMABUF to be revoked iommufd: Do not map/unmap revoked DMABUFs iommufd: Add DMABUF to iopt_pages vfio/pci: Add vfio_pci_dma_buf_iommufd_map()
2 parents a3ebb59 + 5185c4d commit 056daec

14 files changed

Lines changed: 808 additions & 71 deletions

File tree

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ static void arm_smmu_make_nested_domain_ste(
9999
int arm_smmu_attach_prepare_vmaster(struct arm_smmu_attach_state *state,
100100
struct arm_smmu_nested_domain *nested_domain)
101101
{
102+
unsigned int cfg =
103+
FIELD_GET(STRTAB_STE_0_CFG, le64_to_cpu(nested_domain->ste[0]));
102104
struct arm_smmu_vmaster *vmaster;
103105
unsigned long vsid;
104106
int ret;
@@ -107,8 +109,17 @@ int arm_smmu_attach_prepare_vmaster(struct arm_smmu_attach_state *state,
107109

108110
ret = iommufd_viommu_get_vdev_id(&nested_domain->vsmmu->core,
109111
state->master->dev, &vsid);
110-
if (ret)
112+
/*
113+
* Attaching to a translate nested domain must allocate a vDEVICE prior,
114+
* as CD/ATS invalidations and vevents require a vSID to work properly.
115+
* A abort/bypass domain is allowed to attach w/o vmaster for GBPA case.
116+
*/
117+
if (ret) {
118+
if (cfg == STRTAB_STE_0_CFG_ABORT ||
119+
cfg == STRTAB_STE_0_CFG_BYPASS)
120+
return 0;
111121
return ret;
122+
}
112123

113124
vmaster = kzalloc(sizeof(*vmaster), GFP_KERNEL);
114125
if (!vmaster)

drivers/iommu/iommufd/io_pagetable.c

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
* The datastructure uses the iopt_pages to optimize the storage of the PFNs
99
* between the domains and xarray.
1010
*/
11+
#include <linux/dma-buf.h>
1112
#include <linux/err.h>
1213
#include <linux/errno.h>
14+
#include <linux/file.h>
1315
#include <linux/iommu.h>
1416
#include <linux/iommufd.h>
1517
#include <linux/lockdep.h>
@@ -284,6 +286,9 @@ static int iopt_alloc_area_pages(struct io_pagetable *iopt,
284286
case IOPT_ADDRESS_FILE:
285287
start = elm->start_byte + elm->pages->start;
286288
break;
289+
case IOPT_ADDRESS_DMABUF:
290+
start = elm->start_byte + elm->pages->dmabuf.start;
291+
break;
287292
}
288293
rc = iopt_alloc_iova(iopt, dst_iova, start, length);
289294
if (rc)
@@ -468,25 +473,53 @@ int iopt_map_user_pages(struct iommufd_ctx *ictx, struct io_pagetable *iopt,
468473
* @iopt: io_pagetable to act on
469474
* @iova: If IOPT_ALLOC_IOVA is set this is unused on input and contains
470475
* the chosen iova on output. Otherwise is the iova to map to on input
471-
* @file: file to map
476+
* @fd: fdno of a file to map
472477
* @start: map file starting at this byte offset
473478
* @length: Number of bytes to map
474479
* @iommu_prot: Combination of IOMMU_READ/WRITE/etc bits for the mapping
475480
* @flags: IOPT_ALLOC_IOVA or zero
476481
*/
477482
int iopt_map_file_pages(struct iommufd_ctx *ictx, struct io_pagetable *iopt,
478-
unsigned long *iova, struct file *file,
479-
unsigned long start, unsigned long length,
480-
int iommu_prot, unsigned int flags)
483+
unsigned long *iova, int fd, unsigned long start,
484+
unsigned long length, int iommu_prot,
485+
unsigned int flags)
481486
{
482487
struct iopt_pages *pages;
488+
struct dma_buf *dmabuf;
489+
unsigned long start_byte;
490+
unsigned long last;
491+
492+
if (!length)
493+
return -EINVAL;
494+
if (check_add_overflow(start, length - 1, &last))
495+
return -EOVERFLOW;
496+
497+
start_byte = start - ALIGN_DOWN(start, PAGE_SIZE);
498+
dmabuf = dma_buf_get(fd);
499+
if (!IS_ERR(dmabuf)) {
500+
pages = iopt_alloc_dmabuf_pages(ictx, dmabuf, start_byte, start,
501+
length,
502+
iommu_prot & IOMMU_WRITE);
503+
if (IS_ERR(pages)) {
504+
dma_buf_put(dmabuf);
505+
return PTR_ERR(pages);
506+
}
507+
} else {
508+
struct file *file;
509+
510+
file = fget(fd);
511+
if (!file)
512+
return -EBADF;
513+
514+
pages = iopt_alloc_file_pages(file, start_byte, start, length,
515+
iommu_prot & IOMMU_WRITE);
516+
fput(file);
517+
if (IS_ERR(pages))
518+
return PTR_ERR(pages);
519+
}
483520

484-
pages = iopt_alloc_file_pages(file, start, length,
485-
iommu_prot & IOMMU_WRITE);
486-
if (IS_ERR(pages))
487-
return PTR_ERR(pages);
488521
return iopt_map_common(ictx, iopt, pages, iova, length,
489-
start - pages->start, iommu_prot, flags);
522+
start_byte, iommu_prot, flags);
490523
}
491524

492525
struct iova_bitmap_fn_arg {
@@ -961,9 +994,15 @@ static void iopt_unfill_domain(struct io_pagetable *iopt,
961994
WARN_ON(!area->storage_domain);
962995
if (area->storage_domain == domain)
963996
area->storage_domain = storage_domain;
997+
if (iopt_is_dmabuf(pages)) {
998+
if (!iopt_dmabuf_revoked(pages))
999+
iopt_area_unmap_domain(area, domain);
1000+
iopt_dmabuf_untrack_domain(pages, area, domain);
1001+
}
9641002
mutex_unlock(&pages->mutex);
9651003

966-
iopt_area_unmap_domain(area, domain);
1004+
if (!iopt_is_dmabuf(pages))
1005+
iopt_area_unmap_domain(area, domain);
9671006
}
9681007
return;
9691008
}
@@ -980,6 +1019,8 @@ static void iopt_unfill_domain(struct io_pagetable *iopt,
9801019
WARN_ON(area->storage_domain != domain);
9811020
area->storage_domain = NULL;
9821021
iopt_area_unfill_domain(area, pages, domain);
1022+
if (iopt_is_dmabuf(pages))
1023+
iopt_dmabuf_untrack_domain(pages, area, domain);
9831024
mutex_unlock(&pages->mutex);
9841025
}
9851026
}
@@ -1009,10 +1050,16 @@ static int iopt_fill_domain(struct io_pagetable *iopt,
10091050
if (!pages)
10101051
continue;
10111052

1012-
mutex_lock(&pages->mutex);
1053+
guard(mutex)(&pages->mutex);
1054+
if (iopt_is_dmabuf(pages)) {
1055+
rc = iopt_dmabuf_track_domain(pages, area, domain);
1056+
if (rc)
1057+
goto out_unfill;
1058+
}
10131059
rc = iopt_area_fill_domain(area, domain);
10141060
if (rc) {
1015-
mutex_unlock(&pages->mutex);
1061+
if (iopt_is_dmabuf(pages))
1062+
iopt_dmabuf_untrack_domain(pages, area, domain);
10161063
goto out_unfill;
10171064
}
10181065
if (!area->storage_domain) {
@@ -1021,7 +1068,6 @@ static int iopt_fill_domain(struct io_pagetable *iopt,
10211068
interval_tree_insert(&area->pages_node,
10221069
&pages->domains_itree);
10231070
}
1024-
mutex_unlock(&pages->mutex);
10251071
}
10261072
return 0;
10271073

@@ -1042,6 +1088,8 @@ static int iopt_fill_domain(struct io_pagetable *iopt,
10421088
area->storage_domain = NULL;
10431089
}
10441090
iopt_area_unfill_domain(area, pages, domain);
1091+
if (iopt_is_dmabuf(pages))
1092+
iopt_dmabuf_untrack_domain(pages, area, domain);
10451093
mutex_unlock(&pages->mutex);
10461094
}
10471095
return rc;
@@ -1252,6 +1300,10 @@ static int iopt_area_split(struct iopt_area *area, unsigned long iova)
12521300
if (!pages || area->prevent_access)
12531301
return -EBUSY;
12541302

1303+
/* Maintaining the domains_itree below is a bit complicated */
1304+
if (iopt_is_dmabuf(pages))
1305+
return -EOPNOTSUPP;
1306+
12551307
if (new_start & (alignment - 1) ||
12561308
iopt_area_start_byte(area, new_start) & (alignment - 1))
12571309
return -EINVAL;

drivers/iommu/iommufd/io_pagetable.h

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifndef __IO_PAGETABLE_H
66
#define __IO_PAGETABLE_H
77

8+
#include <linux/dma-buf.h>
89
#include <linux/interval_tree.h>
910
#include <linux/kref.h>
1011
#include <linux/mutex.h>
@@ -69,6 +70,16 @@ void iopt_area_unfill_domain(struct iopt_area *area, struct iopt_pages *pages,
6970
void iopt_area_unmap_domain(struct iopt_area *area,
7071
struct iommu_domain *domain);
7172

73+
int iopt_dmabuf_track_domain(struct iopt_pages *pages, struct iopt_area *area,
74+
struct iommu_domain *domain);
75+
void iopt_dmabuf_untrack_domain(struct iopt_pages *pages,
76+
struct iopt_area *area,
77+
struct iommu_domain *domain);
78+
int iopt_dmabuf_track_all_domains(struct iopt_area *area,
79+
struct iopt_pages *pages);
80+
void iopt_dmabuf_untrack_all_domains(struct iopt_area *area,
81+
struct iopt_pages *pages);
82+
7283
static inline unsigned long iopt_area_index(struct iopt_area *area)
7384
{
7485
return area->pages_node.start;
@@ -179,7 +190,22 @@ enum {
179190

180191
enum iopt_address_type {
181192
IOPT_ADDRESS_USER = 0,
182-
IOPT_ADDRESS_FILE = 1,
193+
IOPT_ADDRESS_FILE,
194+
IOPT_ADDRESS_DMABUF,
195+
};
196+
197+
struct iopt_pages_dmabuf_track {
198+
struct iommu_domain *domain;
199+
struct iopt_area *area;
200+
struct list_head elm;
201+
};
202+
203+
struct iopt_pages_dmabuf {
204+
struct dma_buf_attachment *attach;
205+
struct dma_buf_phys_vec phys;
206+
/* Always PAGE_SIZE aligned */
207+
unsigned long start;
208+
struct list_head tracker;
183209
};
184210

185211
/*
@@ -209,6 +235,8 @@ struct iopt_pages {
209235
struct file *file;
210236
unsigned long start;
211237
};
238+
/* IOPT_ADDRESS_DMABUF */
239+
struct iopt_pages_dmabuf dmabuf;
212240
};
213241
bool writable:1;
214242
u8 account_mode;
@@ -220,10 +248,32 @@ struct iopt_pages {
220248
struct rb_root_cached domains_itree;
221249
};
222250

251+
static inline bool iopt_is_dmabuf(struct iopt_pages *pages)
252+
{
253+
if (!IS_ENABLED(CONFIG_DMA_SHARED_BUFFER))
254+
return false;
255+
return pages->type == IOPT_ADDRESS_DMABUF;
256+
}
257+
258+
static inline bool iopt_dmabuf_revoked(struct iopt_pages *pages)
259+
{
260+
lockdep_assert_held(&pages->mutex);
261+
if (iopt_is_dmabuf(pages))
262+
return pages->dmabuf.phys.len == 0;
263+
return false;
264+
}
265+
223266
struct iopt_pages *iopt_alloc_user_pages(void __user *uptr,
224267
unsigned long length, bool writable);
225-
struct iopt_pages *iopt_alloc_file_pages(struct file *file, unsigned long start,
268+
struct iopt_pages *iopt_alloc_file_pages(struct file *file,
269+
unsigned long start_byte,
270+
unsigned long start,
226271
unsigned long length, bool writable);
272+
struct iopt_pages *iopt_alloc_dmabuf_pages(struct iommufd_ctx *ictx,
273+
struct dma_buf *dmabuf,
274+
unsigned long start_byte,
275+
unsigned long start,
276+
unsigned long length, bool writable);
227277
void iopt_release_pages(struct kref *kref);
228278
static inline void iopt_put_pages(struct iopt_pages *pages)
229279
{

drivers/iommu/iommufd/ioas.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,6 @@ int iommufd_ioas_map_file(struct iommufd_ucmd *ucmd)
207207
unsigned long iova = cmd->iova;
208208
struct iommufd_ioas *ioas;
209209
unsigned int flags = 0;
210-
struct file *file;
211210
int rc;
212211

213212
if (cmd->flags &
@@ -229,11 +228,7 @@ int iommufd_ioas_map_file(struct iommufd_ucmd *ucmd)
229228
if (!(cmd->flags & IOMMU_IOAS_MAP_FIXED_IOVA))
230229
flags = IOPT_ALLOC_IOVA;
231230

232-
file = fget(cmd->fd);
233-
if (!file)
234-
return -EBADF;
235-
236-
rc = iopt_map_file_pages(ucmd->ictx, &ioas->iopt, &iova, file,
231+
rc = iopt_map_file_pages(ucmd->ictx, &ioas->iopt, &iova, cmd->fd,
237232
cmd->start, cmd->length,
238233
conv_iommu_prot(cmd->flags), flags);
239234
if (rc)
@@ -243,7 +238,6 @@ int iommufd_ioas_map_file(struct iommufd_ucmd *ucmd)
243238
rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd));
244239
out_put:
245240
iommufd_put_object(ucmd->ictx, &ioas->obj);
246-
fput(file);
247241
return rc;
248242
}
249243

drivers/iommu/iommufd/iommufd_private.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ struct iommu_domain;
1919
struct iommu_group;
2020
struct iommu_option;
2121
struct iommufd_device;
22+
struct dma_buf_attachment;
23+
struct dma_buf_phys_vec;
2224

2325
struct iommufd_sw_msi_map {
2426
struct list_head sw_msi_item;
@@ -108,7 +110,7 @@ int iopt_map_user_pages(struct iommufd_ctx *ictx, struct io_pagetable *iopt,
108110
unsigned long length, int iommu_prot,
109111
unsigned int flags);
110112
int iopt_map_file_pages(struct iommufd_ctx *ictx, struct io_pagetable *iopt,
111-
unsigned long *iova, struct file *file,
113+
unsigned long *iova, int fd,
112114
unsigned long start, unsigned long length,
113115
int iommu_prot, unsigned int flags);
114116
int iopt_map_pages(struct io_pagetable *iopt, struct list_head *pages_list,
@@ -504,6 +506,8 @@ void iommufd_device_pre_destroy(struct iommufd_object *obj);
504506
void iommufd_device_destroy(struct iommufd_object *obj);
505507
int iommufd_get_hw_info(struct iommufd_ucmd *ucmd);
506508

509+
struct device *iommufd_global_device(void);
510+
507511
struct iommufd_access {
508512
struct iommufd_object obj;
509513
struct iommufd_ctx *ictx;
@@ -713,6 +717,8 @@ bool iommufd_should_fail(void);
713717
int __init iommufd_test_init(void);
714718
void iommufd_test_exit(void);
715719
bool iommufd_selftest_is_mock_dev(struct device *dev);
720+
int iommufd_test_dma_buf_iommufd_map(struct dma_buf_attachment *attachment,
721+
struct dma_buf_phys_vec *phys);
716722
#else
717723
static inline void iommufd_test_syz_conv_iova_id(struct iommufd_ucmd *ucmd,
718724
unsigned int ioas_id,
@@ -734,5 +740,11 @@ static inline bool iommufd_selftest_is_mock_dev(struct device *dev)
734740
{
735741
return false;
736742
}
743+
static inline int
744+
iommufd_test_dma_buf_iommufd_map(struct dma_buf_attachment *attachment,
745+
struct dma_buf_phys_vec *phys)
746+
{
747+
return -EOPNOTSUPP;
748+
}
737749
#endif
738750
#endif

drivers/iommu/iommufd/iommufd_test.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ enum {
2929
IOMMU_TEST_OP_PASID_REPLACE,
3030
IOMMU_TEST_OP_PASID_DETACH,
3131
IOMMU_TEST_OP_PASID_CHECK_HWPT,
32+
IOMMU_TEST_OP_DMABUF_GET,
33+
IOMMU_TEST_OP_DMABUF_REVOKE,
3234
};
3335

3436
enum {
@@ -184,6 +186,14 @@ struct iommu_test_cmd {
184186
__u32 hwpt_id;
185187
/* @id is stdev_id */
186188
} pasid_check;
189+
struct {
190+
__u32 length;
191+
__u32 open_flags;
192+
} dmabuf_get;
193+
struct {
194+
__s32 dmabuf_fd;
195+
__u32 revoked;
196+
} dmabuf_revoke;
187197
};
188198
__u32 last;
189199
};

0 commit comments

Comments
 (0)