* [RFC PATCH 1/6] selftests/vfio: allow selecting IOMMU backend from environment
2026-07-03 3:28 [RFC PATCH 0/6] selftests/vfio: Add sPAPR TCE v2 coverage Narayana Murty N
@ 2026-07-03 3:28 ` Narayana Murty N
2026-07-03 3:28 ` [RFC PATCH 2/6] selftests/vfio: add sPAPR TCE v2 IOMMU mode Narayana Murty N
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Narayana Murty N @ 2026-07-03 3:28 UTC (permalink / raw)
To: alex, dmatlack, shuah
Cc: amastro, rananta, nnmlinux, kvm, linux-kselftest, linux-kernel,
vaibhav, sbhat, harshpb
Add support for selecting the IOMMU mode through the environment
variable VFIO_SELFTESTS_IOMMU_MODE. This allows tests to be run
with different IOMMU backends without modifying test code.
The environment variable is validated against the list of supported
modes. On PowerPC, this includes the sPAPR TCE v2 mode which will
be added in a subsequent patch.
If the environment variable is not set, tests use their default
mode, preserving existing behavior.
Signed-off-by: Narayana Murty N <nnmlinux@linux.ibm.com>
---
.../selftests/vfio/lib/include/libvfio.h | 9 +++++
tools/testing/selftests/vfio/lib/libvfio.c | 39 +++++++++++++++++++
.../selftests/vfio/vfio_pci_device_test.c | 4 +-
3 files changed, 50 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/vfio/lib/include/libvfio.h b/tools/testing/selftests/vfio/lib/include/libvfio.h
index 07862b470777..c0b4a2ab06c5 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio.h
@@ -24,6 +24,15 @@
const char *vfio_selftests_get_bdf(int *argc, char *argv[]);
char **vfio_selftests_get_bdfs(int *argc, char *argv[], int *nr_bdfs);
+/*
+ * Return the IOMMU mode string from the environment variable
+ * $VFIO_SELFTESTS_IOMMU_MODE.
+ *
+ * Returns NULL if the environment variable is not set, allowing
+ * tests to use their default mode.
+ */
+const char *vfio_selftests_get_iommu_mode(void);
+
/*
* Reserve virtual address space of size at an address satisfying
* (vaddr % align) == offset.
diff --git a/tools/testing/selftests/vfio/lib/libvfio.c b/tools/testing/selftests/vfio/lib/libvfio.c
index 3a3d1ed635c1..617c8dc7288c 100644
--- a/tools/testing/selftests/vfio/lib/libvfio.c
+++ b/tools/testing/selftests/vfio/lib/libvfio.c
@@ -101,3 +101,42 @@ void *mmap_reserve(size_t size, size_t align, size_t offset)
return map_align;
}
+
+static const char *get_iommu_mode_env(void)
+{
+ const char *mode;
+ static const char * const valid_modes[] = {
+ MODE_VFIO_TYPE1_IOMMU,
+ MODE_VFIO_TYPE1V2_IOMMU,
+ MODE_IOMMUFD_COMPAT_TYPE1,
+ MODE_IOMMUFD_COMPAT_TYPE1V2,
+ MODE_IOMMUFD,
+#ifdef __powerpc__
+ MODE_VFIO_SPAPR_TCE_V2_IOMMU,
+#endif
+ };
+ int i;
+
+ mode = getenv("VFIO_SELFTESTS_IOMMU_MODE");
+ if (!mode)
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(valid_modes); i++) {
+ if (!strcmp(mode, valid_modes[i]))
+ return mode;
+ }
+
+ fprintf(stderr, "Invalid VFIO_SELFTESTS_IOMMU_MODE: %s\n", mode);
+ fprintf(stderr, "Valid modes are:\n");
+ for (i = 0; i < ARRAY_SIZE(valid_modes); i++)
+ fprintf(stderr, " %s\n", valid_modes[i]);
+ exit(KSFT_SKIP);
+}
+
+const char *vfio_selftests_get_iommu_mode(void)
+{
+ return get_iommu_mode_env();
+}
+
+ return map_align;
+}
diff --git a/tools/testing/selftests/vfio/vfio_pci_device_test.c b/tools/testing/selftests/vfio/vfio_pci_device_test.c
index 93c11fd5e081..45b8bf60527a 100644
--- a/tools/testing/selftests/vfio/vfio_pci_device_test.c
+++ b/tools/testing/selftests/vfio/vfio_pci_device_test.c
@@ -29,7 +29,7 @@ FIXTURE(vfio_pci_device_test) {
FIXTURE_SETUP(vfio_pci_device_test)
{
- self->iommu = iommu_init(default_iommu_mode);
+ self->iommu = iommu_init(vfio_selftests_get_iommu_mode());
self->device = vfio_pci_device_init(device_bdf, self->iommu);
}
@@ -121,7 +121,7 @@ FIXTURE_VARIANT_ADD(vfio_pci_irq_test, msix) {
FIXTURE_SETUP(vfio_pci_irq_test)
{
- self->iommu = iommu_init(default_iommu_mode);
+ self->iommu = iommu_init(vfio_selftests_get_iommu_mode());
self->device = vfio_pci_device_init(device_bdf, self->iommu);
}
--
2.51.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [RFC PATCH 2/6] selftests/vfio: add sPAPR TCE v2 IOMMU mode
2026-07-03 3:28 [RFC PATCH 0/6] selftests/vfio: Add sPAPR TCE v2 coverage Narayana Murty N
2026-07-03 3:28 ` [RFC PATCH 1/6] selftests/vfio: allow selecting IOMMU backend from environment Narayana Murty N
@ 2026-07-03 3:28 ` Narayana Murty N
2026-07-03 3:28 ` [RFC PATCH 3/6] selftests/vfio: add sPAPR TCE v2 DMA window helpers Narayana Murty N
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Narayana Murty N @ 2026-07-03 3:28 UTC (permalink / raw)
To: alex, dmatlack, shuah
Cc: amastro, rananta, nnmlinux, kvm, linux-kselftest, linux-kernel,
vaibhav, sbhat, harshpb
Add a PowerPC-specific VFIO selftest IOMMU mode for sPAPR TCE v2.
The new mode uses the legacy VFIO container interface with
VFIO_SPAPR_TCE_v2_IOMMU. It does not use iommufd or VFIO cdev.
On PowerPC, generate the sPAPR TCE v2 fixture variant so the tests exercise
the backend that is valid for this platform.
Signed-off-by: Narayana Murty N <nnmlinux@linux.ibm.com>
---
tools/testing/selftests/vfio/lib/include/libvfio/iommu.h | 8 ++++++++
tools/testing/selftests/vfio/lib/iommu.c | 7 +++++++
2 files changed, 15 insertions(+)
diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h b/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
index e9a3386a4719..ba027a7270d0 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
@@ -66,17 +66,25 @@ struct iommu_iova_range *iommu_iova_ranges(struct iommu *iommu, u32 *nranges);
#define MODE_IOMMUFD_COMPAT_TYPE1 "iommufd_compat_type1"
#define MODE_IOMMUFD_COMPAT_TYPE1V2 "iommufd_compat_type1v2"
#define MODE_IOMMUFD "iommufd"
+#ifdef __powerpc__
+#define MODE_VFIO_SPAPR_TCE_V2_IOMMU "vfio_spapr_tce_v2_iommu"
+#endif
/*
* Generator for VFIO selftests fixture variants that replicate across all
* possible IOMMU modes. Tests must define FIXTURE_VARIANT_ADD_IOMMU_MODE()
* which should then use FIXTURE_VARIANT_ADD() to create the variant.
*/
+#ifdef __powerpc__
+#define FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(...) \
+FIXTURE_VARIANT_ADD_IOMMU_MODE(vfio_spapr_tce_v2_iommu, ##__VA_ARGS__)
+#else
#define FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(...) \
FIXTURE_VARIANT_ADD_IOMMU_MODE(vfio_type1_iommu, ##__VA_ARGS__); \
FIXTURE_VARIANT_ADD_IOMMU_MODE(vfio_type1v2_iommu, ##__VA_ARGS__); \
FIXTURE_VARIANT_ADD_IOMMU_MODE(iommufd_compat_type1, ##__VA_ARGS__); \
FIXTURE_VARIANT_ADD_IOMMU_MODE(iommufd_compat_type1v2, ##__VA_ARGS__); \
FIXTURE_VARIANT_ADD_IOMMU_MODE(iommufd, ##__VA_ARGS__)
+#endif
#endif /* SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_IOMMU_H */
diff --git a/tools/testing/selftests/vfio/lib/iommu.c b/tools/testing/selftests/vfio/lib/iommu.c
index 035dac069d60..e86457a715bf 100644
--- a/tools/testing/selftests/vfio/lib/iommu.c
+++ b/tools/testing/selftests/vfio/lib/iommu.c
@@ -47,6 +47,13 @@ static const struct iommu_mode iommu_modes[] = {
{
.name = MODE_IOMMUFD,
},
+#ifdef __powerpc__
+ {
+ .name = MODE_VFIO_SPAPR_TCE_V2_IOMMU,
+ .container_path = "/dev/vfio/vfio",
+ .iommu_type = VFIO_SPAPR_TCE_v2_IOMMU,
+ },
+#endif
};
static const struct iommu_mode *lookup_iommu_mode(const char *iommu_mode)
--
2.51.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [RFC PATCH 3/6] selftests/vfio: add sPAPR TCE v2 DMA window helpers
2026-07-03 3:28 [RFC PATCH 0/6] selftests/vfio: Add sPAPR TCE v2 coverage Narayana Murty N
2026-07-03 3:28 ` [RFC PATCH 1/6] selftests/vfio: allow selecting IOMMU backend from environment Narayana Murty N
2026-07-03 3:28 ` [RFC PATCH 2/6] selftests/vfio: add sPAPR TCE v2 IOMMU mode Narayana Murty N
@ 2026-07-03 3:28 ` Narayana Murty N
2026-07-03 3:28 ` [RFC PATCH 4/6] selftests/vfio: Exercise sPAPR DDW path for hugepage DMA mappings Narayana Murty N
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Narayana Murty N @ 2026-07-03 3:28 UTC (permalink / raw)
To: alex, dmatlack, shuah
Cc: amastro, rananta, nnmlinux, kvm, linux-kselftest, linux-kernel,
vaibhav, sbhat, harshpb
Add helper support for sPAPR TCE v2 DMA windows in the VFIO selftest
library.
Track the platform default DMA window separately from selftest-created
dynamic DMA windows. The default window is discovered with
VFIO_IOMMU_SPAPR_TCE_GET_INFO and is not removed during cleanup.
Add helpers to create and remove DDWs, return the active IOVA range, and
register/unregister memory around DMA map/unmap operations. Window
selection is done before IOVA allocation; the map path only validates,
registers memory, and calls VFIO_IOMMU_MAP_DMA.
Signed-off-by: Narayana Murty N <nnmlinux@linux.ibm.com>
---
.../vfio/lib/include/libvfio/iommu.h | 18 ++
tools/testing/selftests/vfio/lib/iommu.c | 273 +++++++++++++++++-
tools/testing/selftests/vfio/lib/libvfio.c | 2 -
3 files changed, 288 insertions(+), 5 deletions(-)
diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h b/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
index ba027a7270d0..c9b9ab929f1f 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
@@ -24,12 +24,26 @@ struct dma_region {
u64 size;
};
+struct spapr_tce_window {
+ u64 start;
+ u64 size;
+ u32 page_shift;
+ bool valid;
+ bool dynamic;
+ bool remove_on_cleanup;
+};
+
struct iommu {
const struct iommu_mode *mode;
int container_fd;
int iommufd;
u32 ioas_id;
struct list_head dma_regions;
+#ifdef __powerpc__
+ struct spapr_tce_window default_window;
+ struct spapr_tce_window ddw_window;
+ struct spapr_tce_window *active_window;
+#endif
};
struct iommu *iommu_init(const char *iommu_mode);
@@ -61,6 +75,10 @@ iova_t iommu_hva2iova(struct iommu *iommu, void *vaddr);
struct iommu_iova_range *iommu_iova_ranges(struct iommu *iommu, u32 *nranges);
+int iommu_prepare_dma_window(struct iommu *iommu, u64 min_size,
+ u64 page_size, bool force_dynamic);
+bool iommu_supports_unmap_all(struct iommu *iommu);
+
#define MODE_VFIO_TYPE1_IOMMU "vfio_type1_iommu"
#define MODE_VFIO_TYPE1V2_IOMMU "vfio_type1v2_iommu"
#define MODE_IOMMUFD_COMPAT_TYPE1 "iommufd_compat_type1"
diff --git a/tools/testing/selftests/vfio/lib/iommu.c b/tools/testing/selftests/vfio/lib/iommu.c
index e86457a715bf..19d19bb45a14 100644
--- a/tools/testing/selftests/vfio/lib/iommu.c
+++ b/tools/testing/selftests/vfio/lib/iommu.c
@@ -16,9 +16,11 @@
#include <linux/types.h>
#include <linux/vfio.h>
#include <linux/iommufd.h>
+#include <linux/sizes.h>
#include "../../../kselftest.h"
#include <libvfio.h>
+#include <limits.h>
const char *default_iommu_mode = MODE_IOMMUFD;
@@ -93,6 +95,233 @@ int __iommu_hva2iova(struct iommu *iommu, void *vaddr, iova_t *iova)
return -ENOENT;
}
+#ifdef __powerpc__
+static bool iommu_is_spapr_tce_v2(struct iommu *iommu)
+{
+ return !!(iommu->mode->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU);
+}
+
+static u32 page_size_to_shift(u64 page_size)
+{
+ return __builtin_ctzll(page_size);
+}
+
+static int spapr_tce_read_default_window(struct iommu *iommu)
+{
+ struct vfio_iommu_spapr_tce_info info = {
+ .argsz = sizeof(info),
+ };
+
+ if (iommu->default_window.valid)
+ return 0;
+
+ if (ioctl(iommu->container_fd, VFIO_IOMMU_SPAPR_TCE_GET_INFO, &info))
+ return -errno;
+
+ iommu->default_window.start = info.dma32_window_start;
+ iommu->default_window.size = info.dma32_window_size;
+ iommu->default_window.page_shift = page_size_to_shift(getpagesize());
+ iommu->default_window.valid = true;
+ iommu->default_window.dynamic = false;
+ iommu->default_window.remove_on_cleanup = false;
+
+ return 0;
+}
+
+static int spapr_tce_create_ddw(struct iommu *iommu, u64 min_size, u32 page_shift)
+{
+ struct vfio_iommu_spapr_tce_create create = {
+ .argsz = sizeof(create),
+ .page_shift = page_shift,
+ .levels = 1,
+ .window_size = min_size,
+ };
+
+ if (ioctl(iommu->container_fd, VFIO_IOMMU_SPAPR_TCE_CREATE, &create))
+ return -errno;
+
+ iommu->ddw_window.start = create.start_addr;
+ iommu->ddw_window.size = create.window_size;
+ iommu->ddw_window.page_shift = page_shift;
+ iommu->ddw_window.valid = true;
+ iommu->ddw_window.dynamic = true;
+ iommu->ddw_window.remove_on_cleanup = true;
+
+ return 0;
+}
+
+static int spapr_tce_remove_window(struct iommu *iommu, struct spapr_tce_window *window)
+{
+ struct vfio_iommu_spapr_tce_remove remove = {
+ .argsz = sizeof(remove),
+ .start_addr = window->start,
+ };
+
+ if (!window->valid || !window->remove_on_cleanup)
+ return 0;
+
+ if (ioctl(iommu->container_fd, VFIO_IOMMU_SPAPR_TCE_REMOVE, &remove))
+ return -errno;
+
+ window->valid = false;
+ return 0;
+}
+
+static bool spapr_tce_window_satisfies(struct spapr_tce_window *window,
+ u64 min_size, u32 page_shift,
+ bool require_dynamic)
+{
+ if (!window || !window->valid)
+ return false;
+
+ if (require_dynamic && !window->dynamic)
+ return false;
+
+ if (window->size < min_size)
+ return false;
+
+ if (window->page_shift != page_shift)
+ return false;
+
+ return true;
+}
+
+static struct iommu_iova_range *spapr_tce_iova_ranges(struct iommu *iommu, u32 *nranges)
+{
+ struct iommu_iova_range *ranges;
+ int ret;
+
+ if (!iommu->active_window) {
+ ret = iommu_prepare_dma_window(iommu, SZ_1G, getpagesize(), false);
+ if (ret)
+ return NULL;
+ }
+
+ ranges = calloc(1, sizeof(*ranges));
+ VFIO_ASSERT_NOT_NULL(ranges);
+
+ ranges[0].start = iommu->active_window->start;
+ ranges[0].last = iommu->active_window->start + iommu->active_window->size - 1;
+
+ *nranges = 1;
+ return ranges;
+}
+
+static bool spapr_tce_iova_inside_window(struct iommu *iommu, struct dma_region *region)
+{
+ struct spapr_tce_window *window = iommu->active_window;
+
+ if (!window || !window->valid)
+ return false;
+
+ if (region->iova < window->start)
+ return false;
+
+ if (region->iova + region->size > window->start + window->size)
+ return false;
+
+ return true;
+}
+
+static int spapr_register_memory(struct iommu *iommu, struct dma_region *region)
+{
+ struct vfio_iommu_spapr_register_memory args = {
+ .argsz = sizeof(args),
+ .vaddr = (u64)region->vaddr,
+ .size = region->size,
+ };
+
+ if (ioctl(iommu->container_fd, VFIO_IOMMU_SPAPR_REGISTER_MEMORY, &args))
+ return -errno;
+
+ return 0;
+}
+
+static int spapr_unregister_memory(struct iommu *iommu, struct dma_region *region)
+{
+ struct vfio_iommu_spapr_register_memory args = {
+ .argsz = sizeof(args),
+ .vaddr = (u64)region->vaddr,
+ .size = region->size,
+ };
+
+ if (ioctl(iommu->container_fd, VFIO_IOMMU_SPAPR_UNREGISTER_MEMORY, &args))
+ return -errno;
+
+ return 0;
+}
+
+int iommu_prepare_dma_window(struct iommu *iommu, u64 min_size,
+ u64 page_size, bool force_dynamic)
+{
+ u32 page_shift;
+ int ret;
+
+ if (!iommu_is_spapr_tce_v2(iommu))
+ return 0;
+
+ if (!page_size)
+ page_size = getpagesize();
+
+ page_shift = page_size_to_shift(page_size);
+
+ ret = spapr_tce_read_default_window(iommu);
+ if (ret)
+ return ret;
+
+ /*
+ * Normal mapping path:
+ * use default window when it satisfies the request.
+ */
+ if (!force_dynamic &&
+ spapr_tce_window_satisfies(&iommu->default_window,
+ min_size, page_shift, false)) {
+ iommu->active_window = &iommu->default_window;
+ return 0;
+ }
+
+ /*
+ * Dynamic path:
+ * use existing DDW if it already satisfies the request.
+ */
+ if (spapr_tce_window_satisfies(&iommu->ddw_window,
+ min_size, page_shift, true)) {
+ iommu->active_window = &iommu->ddw_window;
+ return 0;
+ }
+
+ /*
+ * Neither default nor DDW is sufficient.
+ * Remove only the selftest-created DDW, then create a new DDW.
+ */
+ ret = spapr_tce_remove_window(iommu, &iommu->ddw_window);
+ if (ret)
+ return ret;
+
+ ret = spapr_tce_create_ddw(iommu, min_size, page_shift);
+ if (ret)
+ return ret;
+
+ iommu->active_window = &iommu->ddw_window;
+ return 0;
+}
+#else
+int iommu_prepare_dma_window(struct iommu *iommu, u64 min_size,
+ u64 page_size, bool force_dynamic)
+{
+ return 0;
+}
+#endif
+
+bool iommu_supports_unmap_all(struct iommu *iommu)
+{
+#ifdef __powerpc__
+ if (iommu_is_spapr_tce_v2(iommu))
+ return false;
+#endif
+ return true;
+}
+
iova_t iommu_hva2iova(struct iommu *iommu, void *vaddr)
{
iova_t iova;
@@ -113,9 +342,27 @@ static int vfio_iommu_map(struct iommu *iommu, struct dma_region *region)
.iova = region->iova,
.size = region->size,
};
+ int ret;
- if (ioctl(iommu->container_fd, VFIO_IOMMU_MAP_DMA, &args))
+#ifdef __powerpc__
+ if (iommu_is_spapr_tce_v2(iommu)) {
+ if (!spapr_tce_iova_inside_window(iommu, region))
+ return -EINVAL;
+
+ ret = spapr_register_memory(iommu, region);
+ if (ret)
+ return ret;
+ }
+#endif
+
+ ret = ioctl(iommu->container_fd, VFIO_IOMMU_MAP_DMA, &args);
+ if (ret) {
+#ifdef __powerpc__
+ if (iommu_is_spapr_tce_v2(iommu))
+ spapr_unregister_memory(iommu, region);
+#endif
return -errno;
+ }
return 0;
}
@@ -177,8 +424,18 @@ static int __vfio_iommu_unmap(int fd, u64 iova, u64 size, u32 flags, u64 *unmapp
static int vfio_iommu_unmap(struct iommu *iommu, struct dma_region *region,
u64 *unmapped)
{
- return __vfio_iommu_unmap(iommu->container_fd, region->iova,
- region->size, 0, unmapped);
+ int ret;
+
+ ret = __vfio_iommu_unmap(iommu->container_fd, region->iova,
+ region->size, 0, unmapped);
+ if (ret)
+ return ret;
+#ifdef __powerpc__
+ if (iommu_is_spapr_tce_v2(iommu))
+ ret = spapr_unregister_memory(iommu, region);
+#endif
+
+ return ret;
}
static int __iommufd_unmap(int fd, u64 iova, u64 length, u32 ioas_id, u64 *unmapped)
@@ -324,6 +581,11 @@ static struct iommu_iova_range *vfio_iommu_iova_ranges(struct iommu *iommu,
struct vfio_info_cap_header *hdr;
struct iommu_iova_range *ranges = NULL;
+#ifdef __powerpc__
+ if (iommu_is_spapr_tce_v2(iommu))
+ return spapr_tce_iova_ranges(iommu, nranges);
+#endif
+
info = vfio_iommu_get_info(iommu->container_fd);
hdr = vfio_iommu_info_cap_hdr(info, VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE);
VFIO_ASSERT_NOT_NULL(hdr);
@@ -462,6 +724,11 @@ struct iommu *iommu_init(const char *iommu_mode)
void iommu_cleanup(struct iommu *iommu)
{
+#ifdef __powerpc__
+ if (iommu_is_spapr_tce_v2(iommu))
+ spapr_tce_remove_window(iommu, &iommu->ddw_window);
+#endif
+
if (iommu->iommufd)
VFIO_ASSERT_EQ(close(iommu->iommufd), 0);
else
diff --git a/tools/testing/selftests/vfio/lib/libvfio.c b/tools/testing/selftests/vfio/lib/libvfio.c
index 617c8dc7288c..12f731963b05 100644
--- a/tools/testing/selftests/vfio/lib/libvfio.c
+++ b/tools/testing/selftests/vfio/lib/libvfio.c
@@ -138,5 +138,3 @@ const char *vfio_selftests_get_iommu_mode(void)
return get_iommu_mode_env();
}
- return map_align;
-}
--
2.51.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [RFC PATCH 4/6] selftests/vfio: Exercise sPAPR DDW path for hugepage DMA mappings
2026-07-03 3:28 [RFC PATCH 0/6] selftests/vfio: Add sPAPR TCE v2 coverage Narayana Murty N
` (2 preceding siblings ...)
2026-07-03 3:28 ` [RFC PATCH 3/6] selftests/vfio: add sPAPR TCE v2 DMA window helpers Narayana Murty N
@ 2026-07-03 3:28 ` Narayana Murty N
2026-07-03 3:28 ` [RFC PATCH 5/6] selftests/vfio: Accept sPAPR errno for DMA range overflow Narayana Murty N
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Narayana Murty N @ 2026-07-03 3:28 UTC (permalink / raw)
To: alex, dmatlack, shuah
Cc: amastro, rananta, nnmlinux, kvm, linux-kselftest, linux-kernel,
vaibhav, sbhat, harshpb
Prepare the DMA window before IOVA allocation in the DMA mapping tests.
Anonymous mappings use the default sPAPR DMA window. HugeTLB mappings force
a DDW with the requested page size, allowing the test to exercise DDW
creation, mapping, unmapping, and cleanup.
Skip gracefully when hugepage allocation fails or when the platform does
not support the requested DDW characteristics. Also skip unmap-all when
the backend cannot pair it with the sPAPR memory unregister flow.
Signed-off-by: Narayana Murty N <nnmlinux@linux.ibm.com>
---
.../selftests/vfio/vfio_dma_mapping_test.c | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c
index 7d0de8c79de1..4411fdbd56da 100644
--- a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c
+++ b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <stdio.h>
+#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
@@ -119,8 +120,19 @@ FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous_hugetlb_1gb, SZ_1G, MAP_HUGETLB |
FIXTURE_SETUP(vfio_dma_mapping_test)
{
+ const u64 page_size = variant->size ?: getpagesize();
+ const bool force_dynamic = !!variant->size;
+ int ret;
+
self->iommu = iommu_init(variant->iommu_mode);
self->device = vfio_pci_device_init(device_bdf, self->iommu);
+
+ ret = iommu_prepare_dma_window(self->iommu, page_size, page_size,
+ force_dynamic);
+ if (ret)
+ SKIP(return, "DMA window unavailable: %s (%d)\n",
+ strerror(-ret), -ret);
+
self->iova_allocator = iova_allocator_init(self->iommu);
}
@@ -227,6 +239,7 @@ FIXTURE_SETUP(vfio_dma_map_limit_test)
u64 region_size = getpagesize();
iova_t last_iova;
u32 nranges;
+ int ret;
/*
* Over-allocate mmap by double the size to provide enough backing vaddr
@@ -236,6 +249,13 @@ FIXTURE_SETUP(vfio_dma_map_limit_test)
self->iommu = iommu_init(variant->iommu_mode);
self->device = vfio_pci_device_init(device_bdf, self->iommu);
+
+ ret = iommu_prepare_dma_window(self->iommu, region_size, region_size,
+ false);
+ if (ret)
+ SKIP(return, "DMA window unavailable: %s (%d)\n",
+ strerror(-ret), -ret);
+
region->vaddr = mmap(NULL, self->mmap_size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
ASSERT_NE(region->vaddr, MAP_FAILED);
@@ -277,6 +297,8 @@ TEST_F(vfio_dma_map_limit_test, unmap_all)
u64 unmapped;
int rc;
+ if (!iommu_supports_unmap_all(self->iommu))
+ SKIP(return, "IOMMU backend does not support unmap-all\n");
iommu_map(self->iommu, region);
ASSERT_EQ(region->iova, to_iova(self->device, region->vaddr));
--
2.51.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [RFC PATCH 5/6] selftests/vfio: Accept sPAPR errno for DMA range overflow
2026-07-03 3:28 [RFC PATCH 0/6] selftests/vfio: Add sPAPR TCE v2 coverage Narayana Murty N
` (3 preceding siblings ...)
2026-07-03 3:28 ` [RFC PATCH 4/6] selftests/vfio: Exercise sPAPR DDW path for hugepage DMA mappings Narayana Murty N
@ 2026-07-03 3:28 ` Narayana Murty N
2026-07-03 3:28 ` [RFC PATCH 6/6] selftests/vfio: Enable VFIO selftests on ppc64 and ppc64le Narayana Murty N
2026-07-03 8:28 ` [RFC PATCH 0/6] selftests/vfio: Add sPAPR TCE v2 coverage Harsh Prateek Bora
6 siblings, 0 replies; 8+ messages in thread
From: Narayana Murty N @ 2026-07-03 3:28 UTC (permalink / raw)
To: alex, dmatlack, shuah
Cc: amastro, rananta, nnmlinux, kvm, linux-kselftest, linux-kernel,
vaibhav, sbhat, harshpb
Accept sPAPR errno for DMA range overflow
The DMA map limit test expects an overflowing IOVA range to fail with
-EOVERFLOW. That matches the Type1 and iommufd paths.
On sPAPR TCE v2, the same invalid range is rejected as outside the active
TCE window and currently returns -ENXIO. Treat that as the expected ppc
result for this RFC while keeping the existing -EOVERFLOW expectation for
other backends.
This keeps the overflow test enabled for sPAPR TCE v2 instead of skipping
it.
Signed-off-by: Narayana Murty N <nnmlinux@linux.ibm.com>
---
tools/testing/selftests/vfio/vfio_dma_mapping_test.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c
index 4411fdbd56da..cd2d3276a46c 100644
--- a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c
+++ b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c
@@ -316,10 +316,18 @@ TEST_F(vfio_dma_map_limit_test, overflow)
region->size = self->mmap_size;
rc = __iommu_map(self->iommu, region);
+#ifdef __powerpc__
+ ASSERT_EQ(rc, -ENXIO);
+#else
ASSERT_EQ(rc, -EOVERFLOW);
+#endif
rc = __iommu_unmap(self->iommu, region, NULL);
+#ifdef __powerpc__
+ ASSERT_EQ(rc, -ENXIO);
+#else
ASSERT_EQ(rc, -EOVERFLOW);
+#endif
}
int main(int argc, char *argv[])
--
2.51.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [RFC PATCH 6/6] selftests/vfio: Enable VFIO selftests on ppc64 and ppc64le
2026-07-03 3:28 [RFC PATCH 0/6] selftests/vfio: Add sPAPR TCE v2 coverage Narayana Murty N
` (4 preceding siblings ...)
2026-07-03 3:28 ` [RFC PATCH 5/6] selftests/vfio: Accept sPAPR errno for DMA range overflow Narayana Murty N
@ 2026-07-03 3:28 ` Narayana Murty N
2026-07-03 8:28 ` [RFC PATCH 0/6] selftests/vfio: Add sPAPR TCE v2 coverage Harsh Prateek Bora
6 siblings, 0 replies; 8+ messages in thread
From: Narayana Murty N @ 2026-07-03 3:28 UTC (permalink / raw)
To: alex, dmatlack, shuah
Cc: amastro, rananta, nnmlinux, kvm, linux-kselftest, linux-kernel,
vaibhav, sbhat, harshpb
Enable VFIO selftests to build on ppc64 and ppc64le made the changes to
Makefile to include ppc64 and ppc64le.
With sPAPR TCE v2 support added to the VFIO selftest library, PowerPC
systems can run the DMA mapping tests against the legacy VFIO container
backend.
Signed-off-by: Narayana Murty N <nnmlinux@linux.ibm.com>
---
tools/testing/selftests/vfio/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile
index 2c32c48db509..8fd6afd334e5 100644
--- a/tools/testing/selftests/vfio/Makefile
+++ b/tools/testing/selftests/vfio/Makefile
@@ -1,6 +1,6 @@
ARCH ?= $(shell uname -m)
-ifeq (,$(filter $(ARCH),aarch64 arm64 x86 x86_64))
+ifeq (,$(filter $(ARCH),aarch64 arm64 x86 x86_64 ppc64 ppc64le))
# Do nothing on unsupported architectures
include ../lib.mk
else
--
2.51.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [RFC PATCH 0/6] selftests/vfio: Add sPAPR TCE v2 coverage
2026-07-03 3:28 [RFC PATCH 0/6] selftests/vfio: Add sPAPR TCE v2 coverage Narayana Murty N
` (5 preceding siblings ...)
2026-07-03 3:28 ` [RFC PATCH 6/6] selftests/vfio: Enable VFIO selftests on ppc64 and ppc64le Narayana Murty N
@ 2026-07-03 8:28 ` Harsh Prateek Bora
6 siblings, 0 replies; 8+ messages in thread
From: Harsh Prateek Bora @ 2026-07-03 8:28 UTC (permalink / raw)
To: Narayana Murty N, alex, dmatlack, shuah, linuxppc-dev
Cc: amastro, rananta, kvm, linux-kselftest, linux-kernel, vaibhav,
sbhat
+ linuxppc-dev
On 03/07/26 8:58 am, Narayana Murty N wrote:
> This RFC adds PowerPC sPAPR TCE v2 support to VFIO selftests.
>
> The series adds a selftest IOMMU mode for the legacy VFIO container
> backend, adds helpers for default and dynamic DMA windows, and exercises
> the sPAPR DDW path through the DMA mapping tests.
>
> sPAPR TCE v2 remains a legacy VFIO container backend. This series does
> not add iommufd or VFIO cdev support for sPAPR.
>
> The main points are
> 1. add VFIO_SELFTESTS_IOMMU_MODE for selecting a backend
> 2. add vfio_spapr_tce_v2_iommu as the PowerPC VFIO backend
> 3. preserve the platform default DMA window
> 4. create and tear down only selftest-created DDWs
> 5. prepare the DMA window before IOVA allocation
> 6. exercise DDW creation for hugepage DMA mappings
> 7. accept sPAPR-specific errno for invalid DMA ranges
>
> Example:
>
> VFIO_SELFTESTS_IOMMU_MODE=vfio_spapr_tce_v2_iommu
> ./vfio_dma_mapping_test <BDF>
>
> Observed coverage includes anonymous mappings through the default window
> and 2MB hugetlb mappings through a DDW. 1GB hugetlb mappings may skip when
> the platform rejects the requested DDW characteristics.
>
> Feedback is requested from the VFIO and PowerPC communities on:
> 1. whether the sPAPR TCE v2 helpers should remain in the common VFIO
> selftest library or move into a sPAPR-specific test helper?
> 2. whether DDW setup through hugepage mappings is the right initial
> coverage?
> 3. whether the sPAPR-specific overflow errno expectation should be
> accepted, skipped, or hidden behind a backend helper?
> 4. whether PowerPC should generate only the sPAPR TCE v2 fixture variants,
> or keep the generic IOMMU-mode matrix and skip unsupported modes.
>
> TODO: vfio_spapr_tce_v1_iommu yet to be covered.
>
> Narayana Murty N (6):
> selftests/vfio: allow selecting IOMMU backend from environment
> selftests/vfio: add sPAPR TCE v2 IOMMU mode
> selftests/vfio: add sPAPR TCE v2 DMA window helpers
> selftests/vfio: Exercise sPAPR DDW path for hugepage DMA mappings
> selftests/vfio: Accept sPAPR errno for DMA range overflow
> selftests/vfio: Enable VFIO selftests on ppc64 and ppc64le
>
> .../selftests/vfio/lib/include/libvfio.h | 9 +
> .../vfio/lib/include/libvfio/iommu.h | 26 ++
> tools/testing/selftests/vfio/lib/iommu.c | 280 +++++++++++++++++-
> tools/testing/selftests/vfio/lib/libvfio.c | 37 +++
> .../selftests/vfio/vfio_dma_mapping_test.c | 30 ++
> .../selftests/vfio/vfio_pci_device_test.c | 4 +-
> tools/testing/selftests/vfio/Makefile | 2 +-
> 7 files changed, 382 insertions(+), 6 deletions(-)
>
^ permalink raw reply [flat|nested] 8+ messages in thread