Skip to content

Commit 4741f2e

Browse files
committed
vfio-iommufd: Support iommufd for emulated VFIO devices
Emulated VFIO devices are calling vfio_register_emulated_iommu_dev() and consist of all the mdev drivers. Like the physical drivers, support for iommufd is provided by the driver supplying the correct standard ops. Provide ops from the core that duplicate what vfio_register_emulated_iommu_dev() does. Emulated drivers are where it is more likely to see variation in the iommfd support ops. For instance IDXD will probably need to setup both a iommfd_device context linked to a PASID and an iommufd_access context to support all their mdev operations. Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Kevin Tian <[email protected]> Reviewed-by: Alex Williamson <[email protected]> Tested-by: Alex Williamson <[email protected]> Tested-by: Nicolin Chen <[email protected]> Tested-by: Yi Liu <[email protected]> Tested-by: Lixiao Yang <[email protected]> Tested-by: Matthew Rosato <[email protected]> Tested-by: Yu He <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent a4d1f91 commit 4741f2e

File tree

8 files changed

+229
-94
lines changed

8 files changed

+229
-94
lines changed

drivers/gpu/drm/i915/gvt/kvmgt.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,6 +1484,9 @@ static const struct vfio_device_ops intel_vgpu_dev_ops = {
14841484
.mmap = intel_vgpu_mmap,
14851485
.ioctl = intel_vgpu_ioctl,
14861486
.dma_unmap = intel_vgpu_dma_unmap,
1487+
.bind_iommufd = vfio_iommufd_emulated_bind,
1488+
.unbind_iommufd = vfio_iommufd_emulated_unbind,
1489+
.attach_ioas = vfio_iommufd_emulated_attach_ioas,
14871490
};
14881491

14891492
static int intel_vgpu_probe(struct mdev_device *mdev)

drivers/s390/cio/vfio_ccw_ops.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,9 @@ static const struct vfio_device_ops vfio_ccw_dev_ops = {
588588
.ioctl = vfio_ccw_mdev_ioctl,
589589
.request = vfio_ccw_mdev_request,
590590
.dma_unmap = vfio_ccw_dma_unmap,
591+
.bind_iommufd = vfio_iommufd_emulated_bind,
592+
.unbind_iommufd = vfio_iommufd_emulated_unbind,
593+
.attach_ioas = vfio_iommufd_emulated_attach_ioas,
591594
};
592595

593596
struct mdev_driver vfio_ccw_mdev_driver = {

drivers/s390/crypto/vfio_ap_ops.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1805,6 +1805,9 @@ static const struct vfio_device_ops vfio_ap_matrix_dev_ops = {
18051805
.close_device = vfio_ap_mdev_close_device,
18061806
.ioctl = vfio_ap_mdev_ioctl,
18071807
.dma_unmap = vfio_ap_mdev_dma_unmap,
1808+
.bind_iommufd = vfio_iommufd_emulated_bind,
1809+
.unbind_iommufd = vfio_iommufd_emulated_unbind,
1810+
.attach_ioas = vfio_iommufd_emulated_attach_ioas,
18081811
};
18091812

18101813
static struct mdev_driver vfio_ap_matrix_driver = {

drivers/vfio/container.c

Lines changed: 19 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -540,113 +540,41 @@ void vfio_group_unuse_container(struct vfio_group *group)
540540
fput(group->opened_file);
541541
}
542542

543-
/*
544-
* Pin contiguous user pages and return their associated host pages for local
545-
* domain only.
546-
* @device [in] : device
547-
* @iova [in] : starting IOVA of user pages to be pinned.
548-
* @npage [in] : count of pages to be pinned. This count should not
549-
* be greater than VFIO_PIN_PAGES_MAX_ENTRIES.
550-
* @prot [in] : protection flags
551-
* @pages[out] : array of host pages
552-
* Return error or number of pages pinned.
553-
*
554-
* A driver may only call this function if the vfio_device was created
555-
* by vfio_register_emulated_iommu_dev().
556-
*/
557-
int vfio_pin_pages(struct vfio_device *device, dma_addr_t iova,
558-
int npage, int prot, struct page **pages)
543+
int vfio_container_pin_pages(struct vfio_container *container,
544+
struct iommu_group *iommu_group, dma_addr_t iova,
545+
int npage, int prot, struct page **pages)
559546
{
560-
struct vfio_container *container;
561-
struct vfio_group *group = device->group;
562-
struct vfio_iommu_driver *driver;
563-
int ret;
564-
565-
if (!pages || !npage || !vfio_assert_device_open(device))
566-
return -EINVAL;
547+
struct vfio_iommu_driver *driver = container->iommu_driver;
567548

568549
if (npage > VFIO_PIN_PAGES_MAX_ENTRIES)
569550
return -E2BIG;
570551

571-
/* group->container cannot change while a vfio device is open */
572-
container = group->container;
573-
driver = container->iommu_driver;
574-
if (likely(driver && driver->ops->pin_pages))
575-
ret = driver->ops->pin_pages(container->iommu_data,
576-
group->iommu_group, iova,
577-
npage, prot, pages);
578-
else
579-
ret = -ENOTTY;
580-
581-
return ret;
552+
if (unlikely(!driver || !driver->ops->pin_pages))
553+
return -ENOTTY;
554+
return driver->ops->pin_pages(container->iommu_data, iommu_group, iova,
555+
npage, prot, pages);
582556
}
583-
EXPORT_SYMBOL(vfio_pin_pages);
584557

585-
/*
586-
* Unpin contiguous host pages for local domain only.
587-
* @device [in] : device
588-
* @iova [in] : starting address of user pages to be unpinned.
589-
* @npage [in] : count of pages to be unpinned. This count should not
590-
* be greater than VFIO_PIN_PAGES_MAX_ENTRIES.
591-
*/
592-
void vfio_unpin_pages(struct vfio_device *device, dma_addr_t iova, int npage)
558+
void vfio_container_unpin_pages(struct vfio_container *container,
559+
dma_addr_t iova, int npage)
593560
{
594-
struct vfio_container *container;
595-
struct vfio_iommu_driver *driver;
596-
597561
if (WARN_ON(npage <= 0 || npage > VFIO_PIN_PAGES_MAX_ENTRIES))
598562
return;
599563

600-
if (WARN_ON(!vfio_assert_device_open(device)))
601-
return;
602-
603-
/* group->container cannot change while a vfio device is open */
604-
container = device->group->container;
605-
driver = container->iommu_driver;
606-
607-
driver->ops->unpin_pages(container->iommu_data, iova, npage);
564+
container->iommu_driver->ops->unpin_pages(container->iommu_data, iova,
565+
npage);
608566
}
609-
EXPORT_SYMBOL(vfio_unpin_pages);
610567

611-
/*
612-
* This interface allows the CPUs to perform some sort of virtual DMA on
613-
* behalf of the device.
614-
*
615-
* CPUs read/write from/into a range of IOVAs pointing to user space memory
616-
* into/from a kernel buffer.
617-
*
618-
* As the read/write of user space memory is conducted via the CPUs and is
619-
* not a real device DMA, it is not necessary to pin the user space memory.
620-
*
621-
* @device [in] : VFIO device
622-
* @iova [in] : base IOVA of a user space buffer
623-
* @data [in] : pointer to kernel buffer
624-
* @len [in] : kernel buffer length
625-
* @write : indicate read or write
626-
* Return error code on failure or 0 on success.
627-
*/
628-
int vfio_dma_rw(struct vfio_device *device, dma_addr_t iova, void *data,
629-
size_t len, bool write)
568+
int vfio_container_dma_rw(struct vfio_container *container, dma_addr_t iova,
569+
void *data, size_t len, bool write)
630570
{
631-
struct vfio_container *container;
632-
struct vfio_iommu_driver *driver;
633-
int ret = 0;
634-
635-
if (!data || len <= 0 || !vfio_assert_device_open(device))
636-
return -EINVAL;
637-
638-
/* group->container cannot change while a vfio device is open */
639-
container = device->group->container;
640-
driver = container->iommu_driver;
571+
struct vfio_iommu_driver *driver = container->iommu_driver;
641572

642-
if (likely(driver && driver->ops->dma_rw))
643-
ret = driver->ops->dma_rw(container->iommu_data,
644-
iova, data, len, write);
645-
else
646-
ret = -ENOTTY;
647-
return ret;
573+
if (unlikely(!driver || !driver->ops->dma_rw))
574+
return -ENOTTY;
575+
return driver->ops->dma_rw(container->iommu_data, iova, data, len,
576+
write);
648577
}
649-
EXPORT_SYMBOL(vfio_dma_rw);
650578

651579
int __init vfio_container_init(void)
652580
{

drivers/vfio/iommufd.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,61 @@ int vfio_iommufd_physical_attach_ioas(struct vfio_device *vdev, u32 *pt_id)
9898
return 0;
9999
}
100100
EXPORT_SYMBOL_GPL(vfio_iommufd_physical_attach_ioas);
101+
102+
/*
103+
* The emulated standard ops mean that vfio_device is going to use the
104+
* "mdev path" and will call vfio_pin_pages()/vfio_dma_rw(). Drivers using this
105+
* ops set should call vfio_register_emulated_iommu_dev().
106+
*/
107+
108+
static void vfio_emulated_unmap(void *data, unsigned long iova,
109+
unsigned long length)
110+
{
111+
struct vfio_device *vdev = data;
112+
113+
vdev->ops->dma_unmap(vdev, iova, length);
114+
}
115+
116+
static const struct iommufd_access_ops vfio_user_ops = {
117+
.needs_pin_pages = 1,
118+
.unmap = vfio_emulated_unmap,
119+
};
120+
121+
int vfio_iommufd_emulated_bind(struct vfio_device *vdev,
122+
struct iommufd_ctx *ictx, u32 *out_device_id)
123+
{
124+
lockdep_assert_held(&vdev->dev_set->lock);
125+
126+
vdev->iommufd_ictx = ictx;
127+
iommufd_ctx_get(ictx);
128+
return 0;
129+
}
130+
EXPORT_SYMBOL_GPL(vfio_iommufd_emulated_bind);
131+
132+
void vfio_iommufd_emulated_unbind(struct vfio_device *vdev)
133+
{
134+
lockdep_assert_held(&vdev->dev_set->lock);
135+
136+
if (vdev->iommufd_access) {
137+
iommufd_access_destroy(vdev->iommufd_access);
138+
vdev->iommufd_access = NULL;
139+
}
140+
iommufd_ctx_put(vdev->iommufd_ictx);
141+
vdev->iommufd_ictx = NULL;
142+
}
143+
EXPORT_SYMBOL_GPL(vfio_iommufd_emulated_unbind);
144+
145+
int vfio_iommufd_emulated_attach_ioas(struct vfio_device *vdev, u32 *pt_id)
146+
{
147+
struct iommufd_access *user;
148+
149+
lockdep_assert_held(&vdev->dev_set->lock);
150+
151+
user = iommufd_access_create(vdev->iommufd_ictx, *pt_id, &vfio_user_ops,
152+
vdev);
153+
if (IS_ERR(user))
154+
return PTR_ERR(user);
155+
vdev->iommufd_access = user;
156+
return 0;
157+
}
158+
EXPORT_SYMBOL_GPL(vfio_iommufd_emulated_attach_ioas);

drivers/vfio/vfio.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,6 @@ struct vfio_iommu_driver {
111111
int vfio_register_iommu_driver(const struct vfio_iommu_driver_ops *ops);
112112
void vfio_unregister_iommu_driver(const struct vfio_iommu_driver_ops *ops);
113113

114-
bool vfio_assert_device_open(struct vfio_device *device);
115-
116114
struct vfio_container *vfio_container_from_file(struct file *filep);
117115
int vfio_group_use_container(struct vfio_group *group);
118116
void vfio_group_unuse_container(struct vfio_group *group);
@@ -121,6 +119,14 @@ int vfio_container_attach_group(struct vfio_container *container,
121119
void vfio_group_detach_container(struct vfio_group *group);
122120
void vfio_device_container_register(struct vfio_device *device);
123121
void vfio_device_container_unregister(struct vfio_device *device);
122+
int vfio_container_pin_pages(struct vfio_container *container,
123+
struct iommu_group *iommu_group, dma_addr_t iova,
124+
int npage, int prot, struct page **pages);
125+
void vfio_container_unpin_pages(struct vfio_container *container,
126+
dma_addr_t iova, int npage);
127+
int vfio_container_dma_rw(struct vfio_container *container, dma_addr_t iova,
128+
void *data, size_t len, bool write);
129+
124130
int __init vfio_container_init(void);
125131
void vfio_container_cleanup(void);
126132

drivers/vfio/vfio_main.c

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,7 @@ static int vfio_group_ioctl_set_container(struct vfio_group *group,
770770
static const struct file_operations vfio_device_fops;
771771

772772
/* true if the vfio_device has open_device() called but not close_device() */
773-
bool vfio_assert_device_open(struct vfio_device *device)
773+
static bool vfio_assert_device_open(struct vfio_device *device)
774774
{
775775
return !WARN_ON_ONCE(!READ_ONCE(device->open_count));
776776
}
@@ -1876,6 +1876,126 @@ int vfio_set_irqs_validate_and_prepare(struct vfio_irq_set *hdr, int num_irqs,
18761876
}
18771877
EXPORT_SYMBOL(vfio_set_irqs_validate_and_prepare);
18781878

1879+
/*
1880+
* Pin contiguous user pages and return their associated host pages for local
1881+
* domain only.
1882+
* @device [in] : device
1883+
* @iova [in] : starting IOVA of user pages to be pinned.
1884+
* @npage [in] : count of pages to be pinned. This count should not
1885+
* be greater than VFIO_PIN_PAGES_MAX_ENTRIES.
1886+
* @prot [in] : protection flags
1887+
* @pages[out] : array of host pages
1888+
* Return error or number of pages pinned.
1889+
*
1890+
* A driver may only call this function if the vfio_device was created
1891+
* by vfio_register_emulated_iommu_dev() due to vfio_container_pin_pages().
1892+
*/
1893+
int vfio_pin_pages(struct vfio_device *device, dma_addr_t iova,
1894+
int npage, int prot, struct page **pages)
1895+
{
1896+
/* group->container cannot change while a vfio device is open */
1897+
if (!pages || !npage || WARN_ON(!vfio_assert_device_open(device)))
1898+
return -EINVAL;
1899+
if (device->group->container)
1900+
return vfio_container_pin_pages(device->group->container,
1901+
device->group->iommu_group,
1902+
iova, npage, prot, pages);
1903+
if (device->iommufd_access) {
1904+
int ret;
1905+
1906+
if (iova > ULONG_MAX)
1907+
return -EINVAL;
1908+
/*
1909+
* VFIO ignores the sub page offset, npages is from the start of
1910+
* a PAGE_SIZE chunk of IOVA. The caller is expected to recover
1911+
* the sub page offset by doing:
1912+
* pages[0] + (iova % PAGE_SIZE)
1913+
*/
1914+
ret = iommufd_access_pin_pages(
1915+
device->iommufd_access, ALIGN_DOWN(iova, PAGE_SIZE),
1916+
npage * PAGE_SIZE, pages,
1917+
(prot & IOMMU_WRITE) ? IOMMUFD_ACCESS_RW_WRITE : 0);
1918+
if (ret)
1919+
return ret;
1920+
return npage;
1921+
}
1922+
return -EINVAL;
1923+
}
1924+
EXPORT_SYMBOL(vfio_pin_pages);
1925+
1926+
/*
1927+
* Unpin contiguous host pages for local domain only.
1928+
* @device [in] : device
1929+
* @iova [in] : starting address of user pages to be unpinned.
1930+
* @npage [in] : count of pages to be unpinned. This count should not
1931+
* be greater than VFIO_PIN_PAGES_MAX_ENTRIES.
1932+
*/
1933+
void vfio_unpin_pages(struct vfio_device *device, dma_addr_t iova, int npage)
1934+
{
1935+
if (WARN_ON(!vfio_assert_device_open(device)))
1936+
return;
1937+
1938+
if (device->group->container) {
1939+
vfio_container_unpin_pages(device->group->container, iova,
1940+
npage);
1941+
return;
1942+
}
1943+
if (device->iommufd_access) {
1944+
if (WARN_ON(iova > ULONG_MAX))
1945+
return;
1946+
iommufd_access_unpin_pages(device->iommufd_access,
1947+
ALIGN_DOWN(iova, PAGE_SIZE),
1948+
npage * PAGE_SIZE);
1949+
return;
1950+
}
1951+
}
1952+
EXPORT_SYMBOL(vfio_unpin_pages);
1953+
1954+
/*
1955+
* This interface allows the CPUs to perform some sort of virtual DMA on
1956+
* behalf of the device.
1957+
*
1958+
* CPUs read/write from/into a range of IOVAs pointing to user space memory
1959+
* into/from a kernel buffer.
1960+
*
1961+
* As the read/write of user space memory is conducted via the CPUs and is
1962+
* not a real device DMA, it is not necessary to pin the user space memory.
1963+
*
1964+
* @device [in] : VFIO device
1965+
* @iova [in] : base IOVA of a user space buffer
1966+
* @data [in] : pointer to kernel buffer
1967+
* @len [in] : kernel buffer length
1968+
* @write : indicate read or write
1969+
* Return error code on failure or 0 on success.
1970+
*/
1971+
int vfio_dma_rw(struct vfio_device *device, dma_addr_t iova, void *data,
1972+
size_t len, bool write)
1973+
{
1974+
if (!data || len <= 0 || !vfio_assert_device_open(device))
1975+
return -EINVAL;
1976+
1977+
if (device->group->container)
1978+
return vfio_container_dma_rw(device->group->container, iova,
1979+
data, len, write);
1980+
1981+
if (device->iommufd_access) {
1982+
unsigned int flags = 0;
1983+
1984+
if (iova > ULONG_MAX)
1985+
return -EINVAL;
1986+
1987+
/* VFIO historically tries to auto-detect a kthread */
1988+
if (!current->mm)
1989+
flags |= IOMMUFD_ACCESS_RW_KTHREAD;
1990+
if (write)
1991+
flags |= IOMMUFD_ACCESS_RW_WRITE;
1992+
return iommufd_access_rw(device->iommufd_access, iova, data,
1993+
len, flags);
1994+
}
1995+
return -EINVAL;
1996+
}
1997+
EXPORT_SYMBOL(vfio_dma_rw);
1998+
18791999
/*
18802000
* Module/class support
18812001
*/

0 commit comments

Comments
 (0)