From: David Matlack <dmatlack@google.com>
To: Samiullah Khawaja <skhawaja@google.com>
Cc: Aex Williamson <alex@shazbot.org>, Shuah Khan <shuah@kernel.org>,
Alex Mastro <amastro@fb.com>,
Raghavendra Rao Ananta <rananta@google.com>,
kvm@vger.kernel.org, linux-kselftest@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH 1/2] vfio: selftests: Add support of creating multiple iommus from iommufd
Date: Fri, 8 May 2026 18:17:19 +0000 [thread overview]
Message-ID: <af4or28EA6PGEd12@google.com> (raw)
In-Reply-To: <20260505221518.619123-2-skhawaja@google.com>
On 2026-05-05 10:14 PM, Samiullah Khawaja wrote:
> IOMMUFD allows creating multiple IOAS and HWPTs under one iommufd, Add
> API to init a struct iommu using an already opened iommufd. The API
> internally creates a new IOAS and also a new HWPT as an option based on
> the flags passed to the function.
>
> Signed-off-by: Samiullah Khawaja <skhawaja@google.com>
> ---
> .../vfio/lib/include/libvfio/iommu.h | 5 ++
> .../lib/include/libvfio/vfio_pci_device.h | 2 +
> tools/testing/selftests/vfio/lib/iommu.c | 62 +++++++++++++++++--
> .../selftests/vfio/lib/vfio_pci_device.c | 22 ++++++-
> 4 files changed, 84 insertions(+), 7 deletions(-)
>
> diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h b/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
> index e9a3386a4719..89249a294920 100644
> --- a/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
> +++ b/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
> @@ -9,6 +9,9 @@
>
> typedef u64 iova_t;
>
> +/* Create IOMMU with page tables */
> +#define IOMMUFD_IOMMU_INIT_CREATE_PT 1
> +
> struct iommu_mode {
> const char *name;
> const char *container_path;
> @@ -29,10 +32,12 @@ struct iommu {
> int container_fd;
> int iommufd;
> u32 ioas_id;
> + u32 hwpt_id;
> struct list_head dma_regions;
> };
>
> struct iommu *iommu_init(const char *iommu_mode);
> +struct iommu *iommufd_iommu_init(int iommufd, u32 dev_id, u32 flags);
> void iommu_cleanup(struct iommu *iommu);
>
> int __iommu_map(struct iommu *iommu, struct dma_region *region);
> diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
> index 2858885a89bb..1143ceb6a9b8 100644
> --- a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
> +++ b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
> @@ -19,6 +19,7 @@ struct vfio_pci_device {
> const char *bdf;
> int fd;
> int group_fd;
> + u32 dev_id;
Please introduce an initialize this field in its own patch and, in the
commit message, explain why it is being added and how it will be used.
>
> struct iommu *iommu;
>
> @@ -65,6 +66,7 @@ void vfio_pci_config_access(struct vfio_pci_device *device, bool write,
> #define vfio_pci_config_writew(_d, _o, _v) vfio_pci_config_write(_d, _o, _v, u16)
> #define vfio_pci_config_writel(_d, _o, _v) vfio_pci_config_write(_d, _o, _v, u32)
>
> +void vfio_pci_device_attach_iommu(struct vfio_pci_device *device, struct iommu *iommu);
> void vfio_pci_irq_enable(struct vfio_pci_device *device, u32 index,
> u32 vector, int count);
> void vfio_pci_irq_disable(struct vfio_pci_device *device, u32 index);
> diff --git a/tools/testing/selftests/vfio/lib/iommu.c b/tools/testing/selftests/vfio/lib/iommu.c
> index 035dac069d60..644c049cf9f0 100644
> --- a/tools/testing/selftests/vfio/lib/iommu.c
> +++ b/tools/testing/selftests/vfio/lib/iommu.c
> @@ -408,6 +408,18 @@ struct iommu_iova_range *iommu_iova_ranges(struct iommu *iommu, u32 *nranges)
> return ranges;
> }
>
> +static u32 iommufd_hwpt_alloc(struct iommu *iommu, u32 dev_id)
> +{
> + struct iommu_hwpt_alloc args = {
> + .size = sizeof(args),
> + .pt_id = iommu->ioas_id,
> + .dev_id = dev_id,
> + };
> +
> + ioctl_assert(iommu->iommufd, IOMMU_HWPT_ALLOC, &args);
> + return args.out_hwpt_id;
> +}
> +
> static u32 iommufd_ioas_alloc(int iommufd)
> {
> struct iommu_ioas_alloc args = {
> @@ -418,11 +430,9 @@ static u32 iommufd_ioas_alloc(int iommufd)
> return args.out_ioas_id;
> }
>
> -struct iommu *iommu_init(const char *iommu_mode)
> +static struct iommu *iommu_alloc(const char *iommu_mode)
> {
> - const char *container_path;
> struct iommu *iommu;
> - int version;
>
> iommu = calloc(1, sizeof(*iommu));
> VFIO_ASSERT_NOT_NULL(iommu);
> @@ -430,6 +440,16 @@ struct iommu *iommu_init(const char *iommu_mode)
> INIT_LIST_HEAD(&iommu->dma_regions);
>
> iommu->mode = lookup_iommu_mode(iommu_mode);
> + return iommu;
> +}
> +
> +struct iommu *iommu_init(const char *iommu_mode)
> +{
> + const char *container_path;
> + struct iommu *iommu;
> + int version;
> +
> + iommu = iommu_alloc(iommu_mode);
>
> container_path = iommu->mode->container_path;
> if (container_path) {
> @@ -453,10 +473,44 @@ struct iommu *iommu_init(const char *iommu_mode)
> return iommu;
> }
>
> +struct iommu *iommufd_iommu_init(int iommufd, u32 dev_id, u32 flags)
> +{
> + struct iommu *iommu;
> +
> + iommu = iommu_alloc("iommufd");
Use MODE_IOMMUFD instead of string literal.
> +
> + iommu->iommufd = dup(iommufd);
> + VFIO_ASSERT_GT(iommu->iommufd, 0);
> +
> + iommu->ioas_id = iommufd_ioas_alloc(iommu->iommufd);
Please avoid duplicating this code. e.g. Something like this:
diff --git a/tools/testing/selftests/vfio/lib/iommu.c b/tools/testing/selftests/vfio/lib/iommu.c
index 644c049cf9f0..4909cda5c840 100644
--- a/tools/testing/selftests/vfio/lib/iommu.c
+++ b/tools/testing/selftests/vfio/lib/iommu.c
@@ -443,6 +443,19 @@ static struct iommu *iommu_alloc(const char *iommu_mode)
return iommu;
}
+static void iommufd_init(struct iommu *iommu, int iommufd)
+{
+ /*
+ * Require device->iommufd to be >0 so that a simple non-0 check can be
+ * used to check if iommufd is enabled. In practice open() will never
+ * return 0 unless stdin is closed.
+ */
+ VFIO_ASSERT_GT(iommufd, 0);
+
+ iommu->iommufd = iommufd;
+ iommu->ioas_id = iommufd_ioas_alloc(iommu->iommufd);
+}
+
struct iommu *iommu_init(const char *iommu_mode)
{
const char *container_path;
@@ -459,15 +472,7 @@ struct iommu *iommu_init(const char *iommu_mode)
version = ioctl(iommu->container_fd, VFIO_GET_API_VERSION);
VFIO_ASSERT_EQ(version, VFIO_API_VERSION, "Unsupported version: %d\n", version);
} else {
- /*
- * Require device->iommufd to be >0 so that a simple non-0 check can be
- * used to check if iommufd is enabled. In practice open() will never
- * return 0 unless stdin is closed.
- */
- iommu->iommufd = open("/dev/iommu", O_RDWR);
- VFIO_ASSERT_GT(iommu->iommufd, 0);
-
- iommu->ioas_id = iommufd_ioas_alloc(iommu->iommufd);
+ iommufd_init(iommu, open("/dev/iommu", O_RDWR));
}
return iommu;
@@ -478,11 +483,7 @@ struct iommu *iommufd_iommu_init(int iommufd, u32 dev_id, u32 flags)
struct iommu *iommu;
iommu = iommu_alloc("iommufd");
-
- iommu->iommufd = dup(iommufd);
- VFIO_ASSERT_GT(iommu->iommufd, 0);
-
- iommu->ioas_id = iommufd_ioas_alloc(iommu->iommufd);
+ iommufd_init(iommu, dup(iommufd));
if (flags & IOMMUFD_IOMMU_INIT_CREATE_PT)
iommu->hwpt_id = iommufd_hwpt_alloc(iommu, dev_id);
> +
> + if (flags & IOMMUFD_IOMMU_INIT_CREATE_PT)
> + iommu->hwpt_id = iommufd_hwpt_alloc(iommu, dev_id);
Does this need to be part of iommufd_iommu_init()? Maybe it would be
better to expose a separate helper to allocate a HWPT for a given struct
iommu *.
This would enable use of HWPTs in iommus constructed by iommu_init() as
well, which someone may want to do in the future.
If you go this route, please introduce this in its own commit.
> +
> + return iommu;
> +}
> +
> +static void iommufd_cleanup(struct iommu *iommu)
> +{
> + struct iommu_destroy args = {
> + .size = sizeof(args),
> + };
> +
> + if (iommu->hwpt_id) {
> + args.id = iommu->hwpt_id;
> + ioctl_assert(iommu->iommufd, IOMMU_DESTROY, &args);
> + }
> +
> + args.id = iommu->ioas_id;
> + ioctl_assert(iommu->iommufd, IOMMU_DESTROY, &args);
Please create a helper function to do IOMMU_DESTROY ioctl. Then here you
can just do:
if (iommu->hwpt_id)
iommufd_iommu_destroy(iommu, iommu->hwpt_id);
iommfd_iommu_destroy(iommu, iommu->ioas_id);
> +
> + VFIO_ASSERT_EQ(close(iommu->iommufd), 0);
> +}
> +
> void iommu_cleanup(struct iommu *iommu)
> {
> if (iommu->iommufd)
> - VFIO_ASSERT_EQ(close(iommu->iommufd), 0);
> + iommufd_cleanup(iommu);
> else
> VFIO_ASSERT_EQ(close(iommu->container_fd), 0);
>
> diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
> index fc75e04ef010..e2b71fe63cae 100644
> --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c
> +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
> @@ -322,7 +322,7 @@ const char *vfio_pci_get_cdev_path(const char *bdf)
> return cdev_path;
> }
>
> -static void vfio_device_bind_iommufd(int device_fd, int iommufd)
> +static int vfio_device_bind_iommufd(int device_fd, int iommufd)
> {
> struct vfio_device_bind_iommufd args = {
> .argsz = sizeof(args),
> @@ -330,6 +330,7 @@ static void vfio_device_bind_iommufd(int device_fd, int iommufd)
> };
>
> ioctl_assert(device_fd, VFIO_DEVICE_BIND_IOMMUFD, &args);
> + return args.out_devid;
> }
>
> static void vfio_device_attach_iommufd_pt(int device_fd, u32 pt_id)
> @@ -342,6 +343,21 @@ static void vfio_device_attach_iommufd_pt(int device_fd, u32 pt_id)
> ioctl_assert(device_fd, VFIO_DEVICE_ATTACH_IOMMUFD_PT, &args);
> }
>
> +void vfio_pci_device_attach_iommu(struct vfio_pci_device *device, struct iommu *iommu)
> +{
> + u32 pt_id = iommu->ioas_id;
> +
> + /* Only iommufd supports changing struct iommu attachments */
> + VFIO_ASSERT_TRUE(iommu->iommufd);
> +
> + if (iommu->hwpt_id)
> + pt_id = iommu->hwpt_id;
nit: This can be folded into the variable declaration.
const u32 pt_id = iommu->hwpt_id ?: iommu->ioas_id;
> +
> + VFIO_ASSERT_NE(pt_id, 0);
Why is this check needed?
> + vfio_device_attach_iommufd_pt(device->fd, pt_id);
> + device->iommu = iommu;
> +}
Please introduce vfio_pci_device_attach_iommu() in its own patch.
> +
> static void vfio_pci_iommufd_setup(struct vfio_pci_device *device, const char *bdf)
> {
> const char *cdev_path = vfio_pci_get_cdev_path(bdf);
> @@ -350,8 +366,8 @@ static void vfio_pci_iommufd_setup(struct vfio_pci_device *device, const char *b
> VFIO_ASSERT_GE(device->fd, 0);
> free((void *)cdev_path);
>
> - vfio_device_bind_iommufd(device->fd, device->iommu->iommufd);
> - vfio_device_attach_iommufd_pt(device->fd, device->iommu->ioas_id);
> + device->dev_id = vfio_device_bind_iommufd(device->fd, device->iommu->iommufd);
> + vfio_pci_device_attach_iommu(device, device->iommu);
> }
>
> struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu *iommu)
> --
> 2.54.0.545.g6539524ca2-goog
>
next prev parent reply other threads:[~2026-05-08 18:17 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-05 22:14 [PATCH 0/2] vfio: selftests: Add iommufd multi iommu test Samiullah Khawaja
2026-05-05 22:14 ` [PATCH 1/2] vfio: selftests: Add support of creating multiple iommus from iommufd Samiullah Khawaja
2026-05-08 18:17 ` David Matlack [this message]
2026-05-11 20:21 ` Samiullah Khawaja
2026-05-11 20:59 ` David Matlack
2026-05-11 21:41 ` Samiullah Khawaja
2026-05-05 22:14 ` [PATCH 2/2] vfio: selftests: Add iommufd multi iommu test Samiullah Khawaja
2026-05-08 20:14 ` David Matlack
2026-05-11 20:53 ` Samiullah Khawaja
2026-05-11 21:10 ` David Matlack
2026-05-11 21:27 ` Samiullah Khawaja
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=af4or28EA6PGEd12@google.com \
--to=dmatlack@google.com \
--cc=alex@shazbot.org \
--cc=amastro@fb.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=rananta@google.com \
--cc=shuah@kernel.org \
--cc=skhawaja@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.