* [PATCH 00/12] vfio: selftests: Support for multi-device tests
@ 2025-10-08 23:25 David Matlack
2025-10-08 23:25 ` [PATCH 01/12] vfio: selftests: Split run.sh into separate scripts David Matlack
` (12 more replies)
0 siblings, 13 replies; 25+ messages in thread
From: David Matlack @ 2025-10-08 23:25 UTC (permalink / raw)
To: Alex Williamson
Cc: David Matlack, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
This series adds support for tests that use multiple devices, and adds
one new test, vfio_pci_device_init_perf_test, which measures parallel
device initialization time to demonstrate the improvement from commit
e908f58b6beb ("vfio/pci: Separate SR-IOV VF dev_set").
This series also breaks apart the monolithic vfio_util.h and
vfio_pci_device.c into separate files, to account for all the new code.
This required some code motion so the diffstat looks large. The final
layout is more granular and provides a better separation of the IOMMU
code from the device code.
C files:
- tools/testing/selftests/vfio/lib/libvfio.c
- tools/testing/selftests/vfio/lib/iommu.c
- tools/testing/selftests/vfio/lib/vfio_pci_device.c
- tools/testing/selftests/vfio/lib/vfio_pci_driver.c
H files:
- tools/testing/selftests/vfio/lib/include/libvfio.h
- tools/testing/selftests/vfio/lib/include/libvfio/assert.h
- tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
- tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
- tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_driver.h
Notably, vfio_util.h is now gone and replaced with libvfio.h.
This series is based on vfio next, and can be found on GitHub:
https://github.com/dmatlack/linux/tree/vfio/selftests/init_perf_test/v1
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Vipin Sharma <vipinsh@google.com>
Cc: Josh Hilke <jrhilke@google.com>
David Matlack (12):
vfio: selftests: Split run.sh into separate scripts
vfio: selftests: Allow passing multiple BDFs on the command line
vfio: selftests: Rename struct vfio_iommu_mode to iommu_mode
vfio: selftests: Introduce struct iommu
vfio: selftests: Support multiple devices in the same
container/iommufd
vfio: selftests: Eliminate overly chatty logging
vfio: selftests: Prefix logs with device BDF where relevant
vfio: selftests: Rename struct vfio_dma_region to dma_region
vfio: selftests: Move iommu_*() functions into iommu.c
vfio: selftests: Rename vfio_util.h to libvfio.h
vfio: selftests: Split libvfio.h into separate header files
vfio: selftests: Add vfio_pci_device_init_perf_test
tools/testing/selftests/vfio/Makefile | 3 +
.../selftests/vfio/lib/drivers/dsa/dsa.c | 36 +--
.../selftests/vfio/lib/drivers/ioat/ioat.c | 18 +-
.../selftests/vfio/lib/include/libvfio.h | 25 ++
.../vfio/lib/include/libvfio/assert.h | 53 ++++
.../vfio/lib/include/libvfio/iommu.h | 53 ++++
.../lib/include/libvfio/vfio_pci_device.h | 143 +++++++++
.../lib/include/libvfio/vfio_pci_driver.h | 98 ++++++
.../selftests/vfio/lib/include/vfio_util.h | 295 ------------------
tools/testing/selftests/vfio/lib/iommu.c | 219 +++++++++++++
tools/testing/selftests/vfio/lib/libvfio.c | 77 +++++
tools/testing/selftests/vfio/lib/libvfio.mk | 4 +-
.../selftests/vfio/lib/vfio_pci_device.c | 264 ++--------------
.../selftests/vfio/lib/vfio_pci_driver.c | 16 +-
tools/testing/selftests/vfio/run.sh | 109 -------
.../testing/selftests/vfio/scripts/cleanup.sh | 42 +++
tools/testing/selftests/vfio/scripts/lib.sh | 42 +++
tools/testing/selftests/vfio/scripts/run.sh | 16 +
tools/testing/selftests/vfio/scripts/setup.sh | 48 +++
.../selftests/vfio/vfio_dma_mapping_test.c | 4 +-
.../selftests/vfio/vfio_iommufd_setup_test.c | 2 +-
.../vfio/vfio_pci_device_init_perf_test.c | 163 ++++++++++
.../selftests/vfio/vfio_pci_device_test.c | 2 +-
.../selftests/vfio/vfio_pci_driver_test.c | 8 +-
24 files changed, 1051 insertions(+), 689 deletions(-)
create mode 100644 tools/testing/selftests/vfio/lib/include/libvfio.h
create mode 100644 tools/testing/selftests/vfio/lib/include/libvfio/assert.h
create mode 100644 tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
create mode 100644 tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
create mode 100644 tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_driver.h
delete mode 100644 tools/testing/selftests/vfio/lib/include/vfio_util.h
create mode 100644 tools/testing/selftests/vfio/lib/iommu.c
create mode 100644 tools/testing/selftests/vfio/lib/libvfio.c
delete mode 100755 tools/testing/selftests/vfio/run.sh
create mode 100755 tools/testing/selftests/vfio/scripts/cleanup.sh
create mode 100755 tools/testing/selftests/vfio/scripts/lib.sh
create mode 100755 tools/testing/selftests/vfio/scripts/run.sh
create mode 100755 tools/testing/selftests/vfio/scripts/setup.sh
create mode 100644 tools/testing/selftests/vfio/vfio_pci_device_init_perf_test.c
base-commit: 451bb96328981808463405d436bd58de16dd967d
prerequisite-patch-id: 2284290c5021a6efe82f911f0d86311b3f0c5794
--
2.51.0.710.ga91ca5db03-goog
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 01/12] vfio: selftests: Split run.sh into separate scripts
2025-10-08 23:25 [PATCH 00/12] vfio: selftests: Support for multi-device tests David Matlack
@ 2025-10-08 23:25 ` David Matlack
2025-11-10 3:21 ` Raghavendra Rao Ananta
2025-10-08 23:25 ` [PATCH 02/12] vfio: selftests: Allow passing multiple BDFs on the command line David Matlack
` (11 subsequent siblings)
12 siblings, 1 reply; 25+ messages in thread
From: David Matlack @ 2025-10-08 23:25 UTC (permalink / raw)
To: Alex Williamson
Cc: David Matlack, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
Split run.sh into separate scripts (setup.sh, run.sh, cleanup.sh) to
enable multi-device testing, and prepare for VFIO selftests
automatically detecting which devices to use for testing by storing
device metadata on the filesystem.
- setup.sh takes one or more BDFs as arguments and sets up each device.
Metadata about each device is stored on the filesystem in the
directory:
${TMPDIR:-/tmp}/vfio-selftests-devices
Within this directory is a directory for each BDF, and then files in
those directories that cleanup.sh uses to cleanup the device.
- run.sh runs a selftest by passing it the BDFs of all set up devices.
- cleanup.sh takes zero or more BDFs as arguments and cleans up each
device. If no BDFs are provided, it cleans up all devices.
This split enables multi-device testing by allowing multiple BDFs to be
set up and passed into tests:
For example:
$ tools/testing/selftests/vfio/scripts/setup.sh <BDF1> <BDF2>
$ tools/testing/selftests/vfio/scripts/setup.sh <BDF3>
$ tools/testing/selftests/vfio/scripts/run.sh echo
<BDF1> <BDF2> <BDF3>
$ tools/testing/selftests/vfio/scripts/cleanup.sh
If the future, VFIO selftests can automatically detect set up devices by
inspecting ${TMPDIR:-/tmp}/vfio-selftests-devices. This will avoid the
need for the run.sh script.
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/vfio/run.sh | 109 ------------------
.../testing/selftests/vfio/scripts/cleanup.sh | 42 +++++++
tools/testing/selftests/vfio/scripts/lib.sh | 42 +++++++
tools/testing/selftests/vfio/scripts/run.sh | 16 +++
tools/testing/selftests/vfio/scripts/setup.sh | 48 ++++++++
5 files changed, 148 insertions(+), 109 deletions(-)
delete mode 100755 tools/testing/selftests/vfio/run.sh
create mode 100755 tools/testing/selftests/vfio/scripts/cleanup.sh
create mode 100755 tools/testing/selftests/vfio/scripts/lib.sh
create mode 100755 tools/testing/selftests/vfio/scripts/run.sh
create mode 100755 tools/testing/selftests/vfio/scripts/setup.sh
diff --git a/tools/testing/selftests/vfio/run.sh b/tools/testing/selftests/vfio/run.sh
deleted file mode 100755
index 0476b6d7adc3..000000000000
--- a/tools/testing/selftests/vfio/run.sh
+++ /dev/null
@@ -1,109 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-# Global variables initialized in main() and then used during cleanup() when
-# the script exits.
-declare DEVICE_BDF
-declare NEW_DRIVER
-declare OLD_DRIVER
-declare OLD_NUMVFS
-declare DRIVER_OVERRIDE
-
-function write_to() {
- # Unfortunately set -x does not show redirects so use echo to manually
- # tell the user what commands are being run.
- echo "+ echo \"${2}\" > ${1}"
- echo "${2}" > ${1}
-}
-
-function bind() {
- write_to /sys/bus/pci/drivers/${2}/bind ${1}
-}
-
-function unbind() {
- write_to /sys/bus/pci/drivers/${2}/unbind ${1}
-}
-
-function set_sriov_numvfs() {
- write_to /sys/bus/pci/devices/${1}/sriov_numvfs ${2}
-}
-
-function set_driver_override() {
- write_to /sys/bus/pci/devices/${1}/driver_override ${2}
-}
-
-function clear_driver_override() {
- set_driver_override ${1} ""
-}
-
-function cleanup() {
- if [ "${NEW_DRIVER}" ]; then unbind ${DEVICE_BDF} ${NEW_DRIVER} ; fi
- if [ "${DRIVER_OVERRIDE}" ]; then clear_driver_override ${DEVICE_BDF} ; fi
- if [ "${OLD_DRIVER}" ]; then bind ${DEVICE_BDF} ${OLD_DRIVER} ; fi
- if [ "${OLD_NUMVFS}" ]; then set_sriov_numvfs ${DEVICE_BDF} ${OLD_NUMVFS} ; fi
-}
-
-function usage() {
- echo "usage: $0 [-d segment:bus:device.function] [-s] [-h] [cmd ...]" >&2
- echo >&2
- echo " -d: The BDF of the device to use for the test (required)" >&2
- echo " -h: Show this help message" >&2
- echo " -s: Drop into a shell rather than running a command" >&2
- echo >&2
- echo " cmd: The command to run and arguments to pass to it." >&2
- echo " Required when not using -s. The SBDF will be " >&2
- echo " appended to the argument list." >&2
- exit 1
-}
-
-function main() {
- local shell
-
- while getopts "d:hs" opt; do
- case $opt in
- d) DEVICE_BDF="$OPTARG" ;;
- s) shell=true ;;
- *) usage ;;
- esac
- done
-
- # Shift past all optional arguments.
- shift $((OPTIND - 1))
-
- # Check that the user passed in the command to run.
- [ ! "${shell}" ] && [ $# = 0 ] && usage
-
- # Check that the user passed in a BDF.
- [ "${DEVICE_BDF}" ] || usage
-
- trap cleanup EXIT
- set -e
-
- test -d /sys/bus/pci/devices/${DEVICE_BDF}
-
- if [ -f /sys/bus/pci/devices/${DEVICE_BDF}/sriov_numvfs ]; then
- OLD_NUMVFS=$(cat /sys/bus/pci/devices/${DEVICE_BDF}/sriov_numvfs)
- set_sriov_numvfs ${DEVICE_BDF} 0
- fi
-
- if [ -L /sys/bus/pci/devices/${DEVICE_BDF}/driver ]; then
- OLD_DRIVER=$(basename $(readlink -m /sys/bus/pci/devices/${DEVICE_BDF}/driver))
- unbind ${DEVICE_BDF} ${OLD_DRIVER}
- fi
-
- set_driver_override ${DEVICE_BDF} vfio-pci
- DRIVER_OVERRIDE=true
-
- bind ${DEVICE_BDF} vfio-pci
- NEW_DRIVER=vfio-pci
-
- echo
- if [ "${shell}" ]; then
- echo "Dropping into ${SHELL} with VFIO_SELFTESTS_BDF=${DEVICE_BDF}"
- VFIO_SELFTESTS_BDF=${DEVICE_BDF} ${SHELL}
- else
- "$@" ${DEVICE_BDF}
- fi
- echo
-}
-
-main "$@"
diff --git a/tools/testing/selftests/vfio/scripts/cleanup.sh b/tools/testing/selftests/vfio/scripts/cleanup.sh
new file mode 100755
index 000000000000..f436e4dabbcb
--- /dev/null
+++ b/tools/testing/selftests/vfio/scripts/cleanup.sh
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+source $(dirname ${BASH_SOURCE[0]})/lib.sh
+
+function cleanup_devices() {
+ local device_bdf
+ local device_dir
+
+ for device_bdf in "$@"; do
+ device_dir=${DEVICES_DIR}/${device_bdf}
+
+ if [ -f ${device_dir}/vfio-pci ]; then
+ unbind ${device_bdf} vfio-pci
+ fi
+
+ if [ -f ${device_dir}/driver_override ]; then
+ clear_driver_override ${device_bdf}
+ fi
+
+ if [ -f ${device_dir}/driver ]; then
+ bind ${device_bdf} $(cat ${device_dir}/driver)
+ fi
+
+ if [ -f ${device_dir}/sriov_numvfs ]; then
+ set_sriov_numvfs ${device_bdf} $(cat ${device_dir}/sriov_numvfs)
+ fi
+
+ rm -rf ${device_dir}
+ done
+
+ rm -rf ${DEVICES_DIR}
+}
+
+function main() {
+ if [ $# = 0 ]; then
+ cleanup_devices $(ls ${DEVICES_DIR})
+ else
+ cleanup_devices "$@"
+ fi
+}
+
+main "$@"
diff --git a/tools/testing/selftests/vfio/scripts/lib.sh b/tools/testing/selftests/vfio/scripts/lib.sh
new file mode 100755
index 000000000000..9f05f29c7b86
--- /dev/null
+++ b/tools/testing/selftests/vfio/scripts/lib.sh
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+readonly DEVICES_DIR="${TMPDIR:-/tmp}/vfio-selftests-devices"
+
+function write_to() {
+ # Unfortunately set -x does not show redirects so use echo to manually
+ # tell the user what commands are being run.
+ echo "+ echo \"${2}\" > ${1}"
+ echo "${2}" > ${1}
+}
+
+function get_driver() {
+ if [ -L /sys/bus/pci/devices/${1}/driver ]; then
+ basename $(readlink -m /sys/bus/pci/devices/${1}/driver)
+ fi
+}
+
+function bind() {
+ write_to /sys/bus/pci/drivers/${2}/bind ${1}
+}
+
+function unbind() {
+ write_to /sys/bus/pci/drivers/${2}/unbind ${1}
+}
+
+function set_sriov_numvfs() {
+ write_to /sys/bus/pci/devices/${1}/sriov_numvfs ${2}
+}
+
+function get_sriov_numvfs() {
+ if [ -f /sys/bus/pci/devices/${1}/sriov_numvfs ]; then
+ cat /sys/bus/pci/devices/${1}/sriov_numvfs
+ fi
+}
+
+function set_driver_override() {
+ write_to /sys/bus/pci/devices/${1}/driver_override ${2}
+}
+
+function clear_driver_override() {
+ set_driver_override ${1} ""
+}
diff --git a/tools/testing/selftests/vfio/scripts/run.sh b/tools/testing/selftests/vfio/scripts/run.sh
new file mode 100755
index 000000000000..da08753892c4
--- /dev/null
+++ b/tools/testing/selftests/vfio/scripts/run.sh
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+source $(dirname ${BASH_SOURCE[0]})/lib.sh
+
+function main() {
+ local device_bdfs=$(ls ${DEVICES_DIR})
+
+ if [ -z "${device_bdfs}" ]; then
+ echo "No devices found, skipping."
+ exit 4
+ fi
+
+ "$@" ${device_bdfs}
+}
+
+main "$@"
diff --git a/tools/testing/selftests/vfio/scripts/setup.sh b/tools/testing/selftests/vfio/scripts/setup.sh
new file mode 100755
index 000000000000..cd229442ef89
--- /dev/null
+++ b/tools/testing/selftests/vfio/scripts/setup.sh
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+set -e
+
+source $(dirname ${BASH_SOURCE[0]})/lib.sh
+
+function main() {
+ local device_bdf
+ local device_dir
+ local numvfs
+ local driver
+
+ if [ $# = 0 ]; then
+ echo "usage: $0 segment:bus:device.function ..." >&2
+ exit 1
+ fi
+
+ for device_bdf in "$@"; do
+ test -d /sys/bus/pci/devices/${device_bdf}
+
+ device_dir=${DEVICES_DIR}/${device_bdf}
+ if [ -d "${device_dir}" ]; then
+ echo "${device_bdf} has already been set up, exiting."
+ exit 0
+ fi
+
+ mkdir -p ${device_dir}
+
+ numvfs=$(get_sriov_numvfs ${device_bdf})
+ if [ "${numvfs}" ]; then
+ set_sriov_numvfs ${device_bdf} 0
+ echo ${numvfs} > ${device_dir}/sriov_numvfs
+ fi
+
+ driver=$(get_driver ${device_bdf})
+ if [ "${driver}" ]; then
+ unbind ${device_bdf} ${driver}
+ echo ${driver} > ${device_dir}/driver
+ fi
+
+ set_driver_override ${device_bdf} vfio-pci
+ touch ${device_dir}/driver_override
+
+ bind ${device_bdf} vfio-pci
+ touch ${device_dir}/vfio-pci
+ done
+}
+
+main "$@"
--
2.51.0.710.ga91ca5db03-goog
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 02/12] vfio: selftests: Allow passing multiple BDFs on the command line
2025-10-08 23:25 [PATCH 00/12] vfio: selftests: Support for multi-device tests David Matlack
2025-10-08 23:25 ` [PATCH 01/12] vfio: selftests: Split run.sh into separate scripts David Matlack
@ 2025-10-08 23:25 ` David Matlack
2025-11-10 3:45 ` Raghavendra Rao Ananta
2025-10-08 23:25 ` [PATCH 03/12] vfio: selftests: Rename struct vfio_iommu_mode to iommu_mode David Matlack
` (10 subsequent siblings)
12 siblings, 1 reply; 25+ messages in thread
From: David Matlack @ 2025-10-08 23:25 UTC (permalink / raw)
To: Alex Williamson
Cc: David Matlack, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
Add support for passing multiple device BDFs to a test via the command
line. This is a prerequisite for multi-device tests.
Single-device tests can continue using vfio_selftests_get_bdf(), which
will continue to return argv[argc - 1] (if it is a BDF string), or the
environment variable $VFIO_SELFTESTS_BDF otherwise.
For multi-device tests, a new helper called vfio_selftests_get_bdfs() is
introduced which will return an array of all BDFs found at the end of
argv[], as well as the number of BDFs found (passed back to the caller
via argument). The array of BDFs returned does not need to be freed by
the caller.
The environment variable VFIO_SELFTESTS_BDF continues to support only a
single BDF for the time being.
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../selftests/vfio/lib/include/vfio_util.h | 2 +
.../selftests/vfio/lib/vfio_pci_device.c | 58 +++++++++++++++----
2 files changed, 48 insertions(+), 12 deletions(-)
diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h
index ed31606e01b7..2acf119cbedb 100644
--- a/tools/testing/selftests/vfio/lib/include/vfio_util.h
+++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h
@@ -198,6 +198,8 @@ struct vfio_pci_device {
* If BDF cannot be determined then the test will exit with KSFT_SKIP.
*/
const char *vfio_selftests_get_bdf(int *argc, char *argv[]);
+char **vfio_selftests_get_bdfs(int *argc, char *argv[], int *nr_bdfs);
+
const char *vfio_pci_get_cdev_path(const char *bdf);
extern const char *default_iommu_mode;
diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
index 0921b2451ba5..f2fc5a52902b 100644
--- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c
+++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
@@ -566,29 +566,63 @@ static bool is_bdf(const char *str)
return count == 4 && length == strlen(str);
}
-const char *vfio_selftests_get_bdf(int *argc, char *argv[])
+static char **vfio_selftests_get_bdfs_cmdline(int *argc, char *argv[], int *nr_bdfs)
{
- char *bdf;
+ int i;
+
+ for (i = *argc - 1; i > 0 && is_bdf(argv[i]); i--)
+ continue;
+
+ i++;
+ *nr_bdfs = *argc - i;
+ *argc -= *nr_bdfs;
+
+ return *nr_bdfs ? &argv[i] : NULL;
+}
- if (*argc > 1 && is_bdf(argv[*argc - 1]))
- return argv[--(*argc)];
+static char **vfio_selftests_get_bdfs_env(int *argc, char *argv[], int *nr_bdfs)
+{
+ static char *bdf;
bdf = getenv("VFIO_SELFTESTS_BDF");
- if (bdf) {
- VFIO_ASSERT_TRUE(is_bdf(bdf), "Invalid BDF: %s\n", bdf);
- return bdf;
- }
+ if (!bdf)
+ return NULL;
+
+ *nr_bdfs = 1;
+ VFIO_ASSERT_TRUE(is_bdf(bdf), "Invalid BDF: %s\n", bdf);
+
+ return &bdf;
+}
+
+char **vfio_selftests_get_bdfs(int *argc, char *argv[], int *nr_bdfs)
+{
+ char **bdfs;
+
+ bdfs = vfio_selftests_get_bdfs_cmdline(argc, argv, nr_bdfs);
+ if (bdfs)
+ return bdfs;
+
+ bdfs = vfio_selftests_get_bdfs_env(argc, argv, nr_bdfs);
+ if (bdfs)
+ return bdfs;
- fprintf(stderr, "Unable to determine which device to use, skipping test.\n");
+ fprintf(stderr, "Unable to determine which device(s) to use, skipping test.\n");
fprintf(stderr, "\n");
fprintf(stderr, "To pass the device address via environment variable:\n");
fprintf(stderr, "\n");
- fprintf(stderr, " export VFIO_SELFTESTS_BDF=segment:bus:device.function\n");
+ fprintf(stderr, " export VFIO_SELFTESTS_BDF=\"segment:bus:device.function\"\n");
fprintf(stderr, " %s [options]\n", argv[0]);
fprintf(stderr, "\n");
- fprintf(stderr, "To pass the device address via argv:\n");
+ fprintf(stderr, "To pass the device address(es) via argv:\n");
fprintf(stderr, "\n");
- fprintf(stderr, " %s [options] segment:bus:device.function\n", argv[0]);
+ fprintf(stderr, " %s [options] segment:bus:device.function ...\n", argv[0]);
fprintf(stderr, "\n");
exit(KSFT_SKIP);
}
+
+const char *vfio_selftests_get_bdf(int *argc, char *argv[])
+{
+ int nr_bdfs;
+
+ return vfio_selftests_get_bdfs(argc, argv, &nr_bdfs)[0];
+}
--
2.51.0.710.ga91ca5db03-goog
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 03/12] vfio: selftests: Rename struct vfio_iommu_mode to iommu_mode
2025-10-08 23:25 [PATCH 00/12] vfio: selftests: Support for multi-device tests David Matlack
2025-10-08 23:25 ` [PATCH 01/12] vfio: selftests: Split run.sh into separate scripts David Matlack
2025-10-08 23:25 ` [PATCH 02/12] vfio: selftests: Allow passing multiple BDFs on the command line David Matlack
@ 2025-10-08 23:25 ` David Matlack
2025-10-08 23:25 ` [PATCH 04/12] vfio: selftests: Introduce struct iommu David Matlack
` (9 subsequent siblings)
12 siblings, 0 replies; 25+ messages in thread
From: David Matlack @ 2025-10-08 23:25 UTC (permalink / raw)
To: Alex Williamson
Cc: David Matlack, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
Rename struct vfio_iommu_mode to struct iommu_mode since the mode can
include iommufd. This also prepares for splitting out all the IOMMU code
into its own structs/helpers/files which are independent from the
vfio_pci_device code.
No function change intended.
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/vfio/lib/include/vfio_util.h | 4 ++--
tools/testing/selftests/vfio/lib/vfio_pci_device.c | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h
index 2acf119cbedb..5b8d5444f105 100644
--- a/tools/testing/selftests/vfio/lib/include/vfio_util.h
+++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h
@@ -47,7 +47,7 @@
VFIO_LOG_AND_EXIT(_fmt, ##__VA_ARGS__); \
} while (0)
-struct vfio_iommu_mode {
+struct iommu_mode {
const char *name;
const char *container_path;
unsigned long iommu_type;
@@ -163,7 +163,7 @@ struct vfio_pci_driver {
struct vfio_pci_device {
int fd;
- const struct vfio_iommu_mode *iommu_mode;
+ const struct iommu_mode *iommu_mode;
int group_fd;
int container_fd;
diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
index f2fc5a52902b..da8edf297a4d 100644
--- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c
+++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
@@ -411,7 +411,7 @@ const char *vfio_pci_get_cdev_path(const char *bdf)
}
/* Reminder: Keep in sync with FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(). */
-static const struct vfio_iommu_mode iommu_modes[] = {
+static const struct iommu_mode iommu_modes[] = {
{
.name = "vfio_type1_iommu",
.container_path = "/dev/vfio/vfio",
@@ -439,7 +439,7 @@ static const struct vfio_iommu_mode iommu_modes[] = {
const char *default_iommu_mode = "iommufd";
-static const struct vfio_iommu_mode *lookup_iommu_mode(const char *iommu_mode)
+static const struct iommu_mode *lookup_iommu_mode(const char *iommu_mode)
{
int i;
--
2.51.0.710.ga91ca5db03-goog
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 04/12] vfio: selftests: Introduce struct iommu
2025-10-08 23:25 [PATCH 00/12] vfio: selftests: Support for multi-device tests David Matlack
` (2 preceding siblings ...)
2025-10-08 23:25 ` [PATCH 03/12] vfio: selftests: Rename struct vfio_iommu_mode to iommu_mode David Matlack
@ 2025-10-08 23:25 ` David Matlack
2025-10-08 23:25 ` [PATCH 05/12] vfio: selftests: Support multiple devices in the same container/iommufd David Matlack
` (8 subsequent siblings)
12 siblings, 0 replies; 25+ messages in thread
From: David Matlack @ 2025-10-08 23:25 UTC (permalink / raw)
To: Alex Williamson
Cc: David Matlack, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
Introduce struct iommu, which logically represents either a VFIO
container or an iommufd IOAS, depending on which IOMMU mode is used by
the test.
This will be used in a subsequent commit to allow devices to be added to
the same container/iommufd.
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../selftests/vfio/lib/include/vfio_util.h | 16 ++---
.../selftests/vfio/lib/vfio_pci_device.c | 62 ++++++++++---------
2 files changed, 42 insertions(+), 36 deletions(-)
diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h
index 5b8d5444f105..14cd0bec45c0 100644
--- a/tools/testing/selftests/vfio/lib/include/vfio_util.h
+++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h
@@ -160,15 +160,19 @@ struct vfio_pci_driver {
int msi;
};
+struct iommu {
+ const struct iommu_mode *mode;
+ int container_fd;
+ int iommufd;
+ u32 ioas_id;
+ struct list_head dma_regions;
+};
+
struct vfio_pci_device {
int fd;
-
- const struct iommu_mode *iommu_mode;
int group_fd;
- int container_fd;
- int iommufd;
- u32 ioas_id;
+ struct iommu *iommu;
struct vfio_device_info info;
struct vfio_region_info config_space;
@@ -177,8 +181,6 @@ struct vfio_pci_device {
struct vfio_irq_info msi_info;
struct vfio_irq_info msix_info;
- struct list_head dma_regions;
-
/* eventfds for MSI and MSI-x interrupts */
int msi_eventfds[PCI_MSIX_FLAGS_QSIZE + 1];
diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
index da8edf297a4d..e4596a570422 100644
--- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c
+++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
@@ -32,7 +32,7 @@ iova_t __to_iova(struct vfio_pci_device *device, void *vaddr)
{
struct vfio_dma_region *region;
- list_for_each_entry(region, &device->dma_regions, link) {
+ list_for_each_entry(region, &device->iommu->dma_regions, link) {
if (vaddr < region->vaddr)
continue;
@@ -152,7 +152,7 @@ static void vfio_iommu_dma_map(struct vfio_pci_device *device,
.size = region->size,
};
- ioctl_assert(device->container_fd, VFIO_IOMMU_MAP_DMA, &args);
+ ioctl_assert(device->iommu->container_fd, VFIO_IOMMU_MAP_DMA, &args);
}
static void iommufd_dma_map(struct vfio_pci_device *device,
@@ -166,21 +166,21 @@ static void iommufd_dma_map(struct vfio_pci_device *device,
.user_va = (u64)region->vaddr,
.iova = region->iova,
.length = region->size,
- .ioas_id = device->ioas_id,
+ .ioas_id = device->iommu->ioas_id,
};
- ioctl_assert(device->iommufd, IOMMU_IOAS_MAP, &args);
+ ioctl_assert(device->iommu->iommufd, IOMMU_IOAS_MAP, &args);
}
void vfio_pci_dma_map(struct vfio_pci_device *device,
struct vfio_dma_region *region)
{
- if (device->iommufd)
+ if (device->iommu->iommufd)
iommufd_dma_map(device, region);
else
vfio_iommu_dma_map(device, region);
- list_add(®ion->link, &device->dma_regions);
+ list_add(®ion->link, &device->iommu->dma_regions);
}
static void vfio_iommu_dma_unmap(struct vfio_pci_device *device,
@@ -192,7 +192,7 @@ static void vfio_iommu_dma_unmap(struct vfio_pci_device *device,
.size = region->size,
};
- ioctl_assert(device->container_fd, VFIO_IOMMU_UNMAP_DMA, &args);
+ ioctl_assert(device->iommu->container_fd, VFIO_IOMMU_UNMAP_DMA, &args);
}
static void iommufd_dma_unmap(struct vfio_pci_device *device,
@@ -202,16 +202,16 @@ static void iommufd_dma_unmap(struct vfio_pci_device *device,
.size = sizeof(args),
.iova = region->iova,
.length = region->size,
- .ioas_id = device->ioas_id,
+ .ioas_id = device->iommu->ioas_id,
};
- ioctl_assert(device->iommufd, IOMMU_IOAS_UNMAP, &args);
+ ioctl_assert(device->iommu->iommufd, IOMMU_IOAS_UNMAP, &args);
}
void vfio_pci_dma_unmap(struct vfio_pci_device *device,
struct vfio_dma_region *region)
{
- if (device->iommufd)
+ if (device->iommu->iommufd)
iommufd_dma_unmap(device, region);
else
vfio_iommu_dma_unmap(device, region);
@@ -325,28 +325,28 @@ static void vfio_pci_group_setup(struct vfio_pci_device *device, const char *bdf
ioctl_assert(device->group_fd, VFIO_GROUP_GET_STATUS, &group_status);
VFIO_ASSERT_TRUE(group_status.flags & VFIO_GROUP_FLAGS_VIABLE);
- ioctl_assert(device->group_fd, VFIO_GROUP_SET_CONTAINER, &device->container_fd);
+ ioctl_assert(device->group_fd, VFIO_GROUP_SET_CONTAINER, &device->iommu->container_fd);
}
static void vfio_pci_container_setup(struct vfio_pci_device *device, const char *bdf)
{
- unsigned long iommu_type = device->iommu_mode->iommu_type;
- const char *path = device->iommu_mode->container_path;
+ unsigned long iommu_type = device->iommu->mode->iommu_type;
+ const char *path = device->iommu->mode->container_path;
int version;
int ret;
- device->container_fd = open(path, O_RDWR);
- VFIO_ASSERT_GE(device->container_fd, 0, "open(%s) failed\n", path);
+ device->iommu->container_fd = open(path, O_RDWR);
+ VFIO_ASSERT_GE(device->iommu->container_fd, 0, "open(%s) failed\n", path);
- version = ioctl(device->container_fd, VFIO_GET_API_VERSION);
+ version = ioctl(device->iommu->container_fd, VFIO_GET_API_VERSION);
VFIO_ASSERT_EQ(version, VFIO_API_VERSION, "Unsupported version: %d\n", version);
vfio_pci_group_setup(device, bdf);
- ret = ioctl(device->container_fd, VFIO_CHECK_EXTENSION, iommu_type);
+ ret = ioctl(device->iommu->container_fd, VFIO_CHECK_EXTENSION, iommu_type);
VFIO_ASSERT_GT(ret, 0, "VFIO IOMMU type %lu not supported\n", iommu_type);
- ioctl_assert(device->container_fd, VFIO_SET_IOMMU, (void *)iommu_type);
+ ioctl_assert(device->iommu->container_fd, VFIO_SET_IOMMU, (void *)iommu_type);
device->fd = ioctl(device->group_fd, VFIO_GROUP_GET_DEVICE_FD, bdf);
VFIO_ASSERT_GE(device->fd, 0);
@@ -499,12 +499,12 @@ static void vfio_pci_iommufd_setup(struct vfio_pci_device *device, const char *b
* used to check if iommufd is enabled. In practice open() will never
* return 0 unless stdin is closed.
*/
- device->iommufd = open("/dev/iommu", O_RDWR);
- VFIO_ASSERT_GT(device->iommufd, 0);
+ device->iommu->iommufd = open("/dev/iommu", O_RDWR);
+ VFIO_ASSERT_GT(device->iommu->iommufd, 0);
- vfio_device_bind_iommufd(device->fd, device->iommufd);
- device->ioas_id = iommufd_ioas_alloc(device->iommufd);
- vfio_device_attach_iommufd_pt(device->fd, device->ioas_id);
+ vfio_device_bind_iommufd(device->fd, device->iommu->iommufd);
+ device->iommu->ioas_id = iommufd_ioas_alloc(device->iommu->iommufd);
+ vfio_device_attach_iommufd_pt(device->fd, device->iommu->ioas_id);
}
struct vfio_pci_device *vfio_pci_device_init(const char *bdf, const char *iommu_mode)
@@ -514,11 +514,14 @@ struct vfio_pci_device *vfio_pci_device_init(const char *bdf, const char *iommu_
device = calloc(1, sizeof(*device));
VFIO_ASSERT_NOT_NULL(device);
- INIT_LIST_HEAD(&device->dma_regions);
+ device->iommu = calloc(1, sizeof(*device->iommu));
+ VFIO_ASSERT_NOT_NULL(device->iommu);
- device->iommu_mode = lookup_iommu_mode(iommu_mode);
+ INIT_LIST_HEAD(&device->iommu->dma_regions);
- if (device->iommu_mode->container_path)
+ device->iommu->mode = lookup_iommu_mode(iommu_mode);
+
+ if (device->iommu->mode->container_path)
vfio_pci_container_setup(device, bdf);
else
vfio_pci_iommufd_setup(device, bdf);
@@ -547,13 +550,14 @@ void vfio_pci_device_cleanup(struct vfio_pci_device *device)
VFIO_ASSERT_EQ(close(device->msi_eventfds[i]), 0);
}
- if (device->iommufd) {
- VFIO_ASSERT_EQ(close(device->iommufd), 0);
+ if (device->iommu->iommufd) {
+ VFIO_ASSERT_EQ(close(device->iommu->iommufd), 0);
} else {
VFIO_ASSERT_EQ(close(device->group_fd), 0);
- VFIO_ASSERT_EQ(close(device->container_fd), 0);
+ VFIO_ASSERT_EQ(close(device->iommu->container_fd), 0);
}
+ free(device->iommu);
free(device);
}
--
2.51.0.710.ga91ca5db03-goog
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 05/12] vfio: selftests: Support multiple devices in the same container/iommufd
2025-10-08 23:25 [PATCH 00/12] vfio: selftests: Support for multi-device tests David Matlack
` (3 preceding siblings ...)
2025-10-08 23:25 ` [PATCH 04/12] vfio: selftests: Introduce struct iommu David Matlack
@ 2025-10-08 23:25 ` David Matlack
2025-10-27 16:21 ` David Matlack
2025-10-08 23:25 ` [PATCH 06/12] vfio: selftests: Eliminate overly chatty logging David Matlack
` (7 subsequent siblings)
12 siblings, 1 reply; 25+ messages in thread
From: David Matlack @ 2025-10-08 23:25 UTC (permalink / raw)
To: Alex Williamson
Cc: David Matlack, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
Support tests that want to add multiple devices to the same
container/iommufd by decoupling struct vfio_pci_device from
struct iommu.
For backwards compatibility with existing tests, and to keep
single-device tests simple, vfio_pci_device_init() and
vfio_pci_device_cleanup() remain unchanged.
Multi-devices tests can now put multiple devices in the same
container/iommufd like so:
iommu = iommu_init(iommu_mode);
device1 = __vfio_pci_device_init(bdf1, iommu);
device2 = __vfio_pci_device_init(bdf2, iommu);
device3 = __vfio_pci_device_init(bdf3, iommu);
...
__vfio_pci_device_cleanup(device3);
__vfio_pci_device_cleanup(device2);
__vfio_pci_device_cleanup(device1);
iommu_cleanup(iommu);
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../selftests/vfio/lib/include/vfio_util.h | 7 ++
.../selftests/vfio/lib/vfio_pci_device.c | 107 ++++++++++++------
2 files changed, 80 insertions(+), 34 deletions(-)
diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h
index 14cd0bec45c0..8a01bcaa3ee8 100644
--- a/tools/testing/selftests/vfio/lib/include/vfio_util.h
+++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h
@@ -206,8 +206,15 @@ const char *vfio_pci_get_cdev_path(const char *bdf);
extern const char *default_iommu_mode;
+struct iommu *iommu_init(const char *iommu_mode);
+void iommu_cleanup(struct iommu *iommu);
+
+struct vfio_pci_device *__vfio_pci_device_init(const char *bdf, struct iommu *iommu);
struct vfio_pci_device *vfio_pci_device_init(const char *bdf, const char *iommu_mode);
+
+void __vfio_pci_device_cleanup(struct vfio_pci_device *device);
void vfio_pci_device_cleanup(struct vfio_pci_device *device);
+
void vfio_pci_device_reset(struct vfio_pci_device *device);
void vfio_pci_dma_map(struct vfio_pci_device *device,
diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
index e4596a570422..de3a8d4d74f0 100644
--- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c
+++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
@@ -330,23 +330,21 @@ static void vfio_pci_group_setup(struct vfio_pci_device *device, const char *bdf
static void vfio_pci_container_setup(struct vfio_pci_device *device, const char *bdf)
{
- unsigned long iommu_type = device->iommu->mode->iommu_type;
- const char *path = device->iommu->mode->container_path;
- int version;
+ struct iommu *iommu = device->iommu;
+ unsigned long iommu_type = iommu->mode->iommu_type;
int ret;
- device->iommu->container_fd = open(path, O_RDWR);
- VFIO_ASSERT_GE(device->iommu->container_fd, 0, "open(%s) failed\n", path);
-
- version = ioctl(device->iommu->container_fd, VFIO_GET_API_VERSION);
- VFIO_ASSERT_EQ(version, VFIO_API_VERSION, "Unsupported version: %d\n", version);
-
vfio_pci_group_setup(device, bdf);
- ret = ioctl(device->iommu->container_fd, VFIO_CHECK_EXTENSION, iommu_type);
+ ret = ioctl(iommu->container_fd, VFIO_CHECK_EXTENSION, iommu_type);
VFIO_ASSERT_GT(ret, 0, "VFIO IOMMU type %lu not supported\n", iommu_type);
- ioctl_assert(device->iommu->container_fd, VFIO_SET_IOMMU, (void *)iommu_type);
+ /*
+ * Allow multiple threads to race to set the IOMMU type on the
+ * container. The first will succeed and the rest should fail
+ * because the IOMMU type is already set.
+ */
+ (void)ioctl(iommu->container_fd, VFIO_SET_IOMMU, (void *)iommu_type);
device->fd = ioctl(device->group_fd, VFIO_GROUP_GET_DEVICE_FD, bdf);
VFIO_ASSERT_GE(device->fd, 0);
@@ -494,32 +492,53 @@ static void vfio_pci_iommufd_setup(struct vfio_pci_device *device, const char *b
VFIO_ASSERT_GE(device->fd, 0);
free((void *)cdev_path);
- /*
- * 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.
- */
- device->iommu->iommufd = open("/dev/iommu", O_RDWR);
- VFIO_ASSERT_GT(device->iommu->iommufd, 0);
-
vfio_device_bind_iommufd(device->fd, device->iommu->iommufd);
- device->iommu->ioas_id = iommufd_ioas_alloc(device->iommu->iommufd);
vfio_device_attach_iommufd_pt(device->fd, device->iommu->ioas_id);
}
-struct vfio_pci_device *vfio_pci_device_init(const char *bdf, const char *iommu_mode)
+struct iommu *iommu_init(const char *iommu_mode)
+{
+ const char *container_path;
+ struct iommu *iommu;
+ int version;
+
+ iommu = calloc(1, sizeof(*iommu));
+ VFIO_ASSERT_NOT_NULL(iommu);
+
+ INIT_LIST_HEAD(&iommu->dma_regions);
+
+ iommu->mode = lookup_iommu_mode(iommu_mode);
+
+ container_path = iommu->mode->container_path;
+ if (container_path) {
+ iommu->container_fd = open(container_path, O_RDWR);
+ VFIO_ASSERT_GE(iommu->container_fd, 0, "open(%s) failed\n", container_path);
+
+ 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);
+ }
+
+ return iommu;
+}
+
+struct vfio_pci_device *__vfio_pci_device_init(const char *bdf, struct iommu *iommu)
{
struct vfio_pci_device *device;
device = calloc(1, sizeof(*device));
VFIO_ASSERT_NOT_NULL(device);
- device->iommu = calloc(1, sizeof(*device->iommu));
- VFIO_ASSERT_NOT_NULL(device->iommu);
-
- INIT_LIST_HEAD(&device->iommu->dma_regions);
-
- device->iommu->mode = lookup_iommu_mode(iommu_mode);
+ device->iommu = iommu;
if (device->iommu->mode->container_path)
vfio_pci_container_setup(device, bdf);
@@ -532,7 +551,14 @@ struct vfio_pci_device *vfio_pci_device_init(const char *bdf, const char *iommu_
return device;
}
-void vfio_pci_device_cleanup(struct vfio_pci_device *device)
+struct vfio_pci_device *vfio_pci_device_init(const char *bdf, const char *iommu_mode)
+{
+ struct iommu *iommu = iommu_init(iommu_mode);
+
+ return __vfio_pci_device_init(bdf, iommu);
+}
+
+void __vfio_pci_device_cleanup(struct vfio_pci_device *device)
{
int i;
@@ -550,17 +576,30 @@ void vfio_pci_device_cleanup(struct vfio_pci_device *device)
VFIO_ASSERT_EQ(close(device->msi_eventfds[i]), 0);
}
- if (device->iommu->iommufd) {
- VFIO_ASSERT_EQ(close(device->iommu->iommufd), 0);
- } else {
+ if (device->group_fd)
VFIO_ASSERT_EQ(close(device->group_fd), 0);
- VFIO_ASSERT_EQ(close(device->iommu->container_fd), 0);
- }
- free(device->iommu);
free(device);
}
+void iommu_cleanup(struct iommu *iommu)
+{
+ if (iommu->iommufd)
+ VFIO_ASSERT_EQ(close(iommu->iommufd), 0);
+ else
+ VFIO_ASSERT_EQ(close(iommu->container_fd), 0);
+
+ free(iommu);
+}
+
+void vfio_pci_device_cleanup(struct vfio_pci_device *device)
+{
+ struct iommu *iommu = device->iommu;
+
+ __vfio_pci_device_cleanup(device);
+ iommu_cleanup(iommu);
+}
+
static bool is_bdf(const char *str)
{
unsigned int s, b, d, f;
--
2.51.0.710.ga91ca5db03-goog
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 06/12] vfio: selftests: Eliminate overly chatty logging
2025-10-08 23:25 [PATCH 00/12] vfio: selftests: Support for multi-device tests David Matlack
` (4 preceding siblings ...)
2025-10-08 23:25 ` [PATCH 05/12] vfio: selftests: Support multiple devices in the same container/iommufd David Matlack
@ 2025-10-08 23:25 ` David Matlack
2025-10-08 23:25 ` [PATCH 07/12] vfio: selftests: Prefix logs with device BDF where relevant David Matlack
` (6 subsequent siblings)
12 siblings, 0 replies; 25+ messages in thread
From: David Matlack @ 2025-10-08 23:25 UTC (permalink / raw)
To: Alex Williamson
Cc: David Matlack, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
Eliminate overly chatty logs that are printed during almost every test.
These logs are adding more noise than value. If a test cares about this
information it can log it itself. This is especially true as the VFIO
selftests gains support for multiple devices in a single test (which
multiplies all these logs).
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/vfio/lib/vfio_pci_driver.c | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_driver.c b/tools/testing/selftests/vfio/lib/vfio_pci_driver.c
index e5e8723ecb41..abb7a62a03ea 100644
--- a/tools/testing/selftests/vfio/lib/vfio_pci_driver.c
+++ b/tools/testing/selftests/vfio/lib/vfio_pci_driver.c
@@ -1,6 +1,4 @@
// SPDX-License-Identifier: GPL-2.0-only
-#include <stdio.h>
-
#include "../../../kselftest.h"
#include <vfio_util.h>
@@ -29,7 +27,6 @@ void vfio_pci_driver_probe(struct vfio_pci_device *device)
if (ops->probe(device))
continue;
- printf("Driver found: %s\n", ops->name);
device->driver.ops = ops;
}
}
@@ -58,17 +55,6 @@ void vfio_pci_driver_init(struct vfio_pci_device *device)
driver->ops->init(device);
driver->initialized = true;
-
- printf("%s: region: vaddr %p, iova 0x%lx, size 0x%lx\n",
- driver->ops->name,
- driver->region.vaddr,
- driver->region.iova,
- driver->region.size);
-
- printf("%s: max_memcpy_size 0x%lx, max_memcpy_count 0x%lx\n",
- driver->ops->name,
- driver->max_memcpy_size,
- driver->max_memcpy_count);
}
void vfio_pci_driver_remove(struct vfio_pci_device *device)
--
2.51.0.710.ga91ca5db03-goog
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 07/12] vfio: selftests: Prefix logs with device BDF where relevant
2025-10-08 23:25 [PATCH 00/12] vfio: selftests: Support for multi-device tests David Matlack
` (5 preceding siblings ...)
2025-10-08 23:25 ` [PATCH 06/12] vfio: selftests: Eliminate overly chatty logging David Matlack
@ 2025-10-08 23:25 ` David Matlack
2025-11-10 4:54 ` Raghavendra Rao Ananta
2025-10-08 23:25 ` [PATCH 08/12] vfio: selftests: Rename struct vfio_dma_region to dma_region David Matlack
` (5 subsequent siblings)
12 siblings, 1 reply; 25+ messages in thread
From: David Matlack @ 2025-10-08 23:25 UTC (permalink / raw)
To: Alex Williamson
Cc: David Matlack, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
Prefix log messages with the device's BDF where relevant. This will help
understanding VFIO selftests logs when tests are run with multiple
devices.
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../selftests/vfio/lib/drivers/dsa/dsa.c | 34 +++++++++----------
.../selftests/vfio/lib/drivers/ioat/ioat.c | 16 ++++-----
.../selftests/vfio/lib/include/vfio_util.h | 4 +++
.../selftests/vfio/lib/vfio_pci_device.c | 1 +
4 files changed, 30 insertions(+), 25 deletions(-)
diff --git a/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c b/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c
index 0ca2cbc2a316..8d667be80229 100644
--- a/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c
+++ b/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c
@@ -70,7 +70,7 @@ static int dsa_probe(struct vfio_pci_device *device)
return -EINVAL;
if (dsa_int_handle_request_required(device)) {
- printf("Device requires requesting interrupt handles\n");
+ dev_info(device, "Device requires requesting interrupt handles\n");
return -EINVAL;
}
@@ -91,23 +91,23 @@ static void dsa_check_sw_err(struct vfio_pci_device *device)
return;
}
- fprintf(stderr, "SWERR: 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n",
+ dev_err(device, "SWERR: 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n",
err.bits[0], err.bits[1], err.bits[2], err.bits[3]);
- fprintf(stderr, " valid: 0x%x\n", err.valid);
- fprintf(stderr, " overflow: 0x%x\n", err.overflow);
- fprintf(stderr, " desc_valid: 0x%x\n", err.desc_valid);
- fprintf(stderr, " wq_idx_valid: 0x%x\n", err.wq_idx_valid);
- fprintf(stderr, " batch: 0x%x\n", err.batch);
- fprintf(stderr, " fault_rw: 0x%x\n", err.fault_rw);
- fprintf(stderr, " priv: 0x%x\n", err.priv);
- fprintf(stderr, " error: 0x%x\n", err.error);
- fprintf(stderr, " wq_idx: 0x%x\n", err.wq_idx);
- fprintf(stderr, " operation: 0x%x\n", err.operation);
- fprintf(stderr, " pasid: 0x%x\n", err.pasid);
- fprintf(stderr, " batch_idx: 0x%x\n", err.batch_idx);
- fprintf(stderr, " invalid_flags: 0x%x\n", err.invalid_flags);
- fprintf(stderr, " fault_addr: 0x%lx\n", err.fault_addr);
+ dev_err(device, " valid: 0x%x\n", err.valid);
+ dev_err(device, " overflow: 0x%x\n", err.overflow);
+ dev_err(device, " desc_valid: 0x%x\n", err.desc_valid);
+ dev_err(device, " wq_idx_valid: 0x%x\n", err.wq_idx_valid);
+ dev_err(device, " batch: 0x%x\n", err.batch);
+ dev_err(device, " fault_rw: 0x%x\n", err.fault_rw);
+ dev_err(device, " priv: 0x%x\n", err.priv);
+ dev_err(device, " error: 0x%x\n", err.error);
+ dev_err(device, " wq_idx: 0x%x\n", err.wq_idx);
+ dev_err(device, " operation: 0x%x\n", err.operation);
+ dev_err(device, " pasid: 0x%x\n", err.pasid);
+ dev_err(device, " batch_idx: 0x%x\n", err.batch_idx);
+ dev_err(device, " invalid_flags: 0x%x\n", err.invalid_flags);
+ dev_err(device, " fault_addr: 0x%lx\n", err.fault_addr);
VFIO_FAIL("Software Error Detected!\n");
}
@@ -256,7 +256,7 @@ static int dsa_completion_wait(struct vfio_pci_device *device,
if (status == DSA_COMP_SUCCESS)
return 0;
- printf("Error detected during memcpy operation: 0x%x\n", status);
+ dev_info(device, "Error detected during memcpy operation: 0x%x\n", status);
return -1;
}
diff --git a/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c b/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c
index c3b91d9b1f59..e04dce1d544c 100644
--- a/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c
+++ b/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c
@@ -51,7 +51,7 @@ static int ioat_probe(struct vfio_pci_device *device)
r = 0;
break;
default:
- printf("ioat: Unsupported version: 0x%x\n", version);
+ dev_info(device, "ioat: Unsupported version: 0x%x\n", version);
r = -EINVAL;
}
return r;
@@ -135,13 +135,13 @@ static void ioat_handle_error(struct vfio_pci_device *device)
{
void *registers = ioat_channel_registers(device);
- printf("Error detected during memcpy operation!\n"
- " CHANERR: 0x%x\n"
- " CHANERR_INT: 0x%x\n"
- " DMAUNCERRSTS: 0x%x\n",
- readl(registers + IOAT_CHANERR_OFFSET),
- vfio_pci_config_readl(device, IOAT_PCI_CHANERR_INT_OFFSET),
- vfio_pci_config_readl(device, IOAT_PCI_DMAUNCERRSTS_OFFSET));
+ dev_info(device, "Error detected during memcpy operation!\n"
+ " CHANERR: 0x%x\n"
+ " CHANERR_INT: 0x%x\n"
+ " DMAUNCERRSTS: 0x%x\n",
+ readl(registers + IOAT_CHANERR_OFFSET),
+ vfio_pci_config_readl(device, IOAT_PCI_CHANERR_INT_OFFSET),
+ vfio_pci_config_readl(device, IOAT_PCI_DMAUNCERRSTS_OFFSET));
ioat_reset(device);
}
diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h
index 8a01bcaa3ee8..b7175d4c2132 100644
--- a/tools/testing/selftests/vfio/lib/include/vfio_util.h
+++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h
@@ -47,6 +47,9 @@
VFIO_LOG_AND_EXIT(_fmt, ##__VA_ARGS__); \
} while (0)
+#define dev_info(_dev, _fmt, ...) printf("%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)
+#define dev_err(_dev, _fmt, ...) fprintf(stderr, "%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)
+
struct iommu_mode {
const char *name;
const char *container_path;
@@ -169,6 +172,7 @@ struct iommu {
};
struct vfio_pci_device {
+ const char *bdf;
int fd;
int group_fd;
diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
index de3a8d4d74f0..1788e7892ee3 100644
--- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c
+++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
@@ -538,6 +538,7 @@ struct vfio_pci_device *__vfio_pci_device_init(const char *bdf, struct iommu *io
device = calloc(1, sizeof(*device));
VFIO_ASSERT_NOT_NULL(device);
+ device->bdf = bdf;
device->iommu = iommu;
if (device->iommu->mode->container_path)
--
2.51.0.710.ga91ca5db03-goog
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 08/12] vfio: selftests: Rename struct vfio_dma_region to dma_region
2025-10-08 23:25 [PATCH 00/12] vfio: selftests: Support for multi-device tests David Matlack
` (6 preceding siblings ...)
2025-10-08 23:25 ` [PATCH 07/12] vfio: selftests: Prefix logs with device BDF where relevant David Matlack
@ 2025-10-08 23:25 ` David Matlack
2025-10-08 23:25 ` [PATCH 09/12] vfio: selftests: Move iommu_*() functions into iommu.c David Matlack
` (4 subsequent siblings)
12 siblings, 0 replies; 25+ messages in thread
From: David Matlack @ 2025-10-08 23:25 UTC (permalink / raw)
To: Alex Williamson
Cc: David Matlack, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
Rename struct vfio_dma_region to dma_region. This is in preparation for
separating the VFIO PCI device library code from the IOMMU library code.
This name change also better reflects the fact that DMA mappings can be
managed by either VFIO or IOMMUFD. i.e. the "vfio_" prefix is
misleading.
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../testing/selftests/vfio/lib/include/vfio_util.h | 8 ++++----
tools/testing/selftests/vfio/lib/vfio_pci_device.c | 14 +++++++-------
.../testing/selftests/vfio/vfio_dma_mapping_test.c | 2 +-
.../testing/selftests/vfio/vfio_pci_driver_test.c | 6 +++---
4 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h
index b7175d4c2132..cce521212348 100644
--- a/tools/testing/selftests/vfio/lib/include/vfio_util.h
+++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h
@@ -77,7 +77,7 @@ typedef u64 iova_t;
#define INVALID_IOVA UINT64_MAX
-struct vfio_dma_region {
+struct dma_region {
struct list_head link;
void *vaddr;
iova_t iova;
@@ -151,7 +151,7 @@ struct vfio_pci_driver {
bool memcpy_in_progress;
/* Region to be used by the driver (e.g. for in-memory descriptors) */
- struct vfio_dma_region region;
+ struct dma_region region;
/* The maximum size that can be passed to memcpy_start(). */
u64 max_memcpy_size;
@@ -222,9 +222,9 @@ void vfio_pci_device_cleanup(struct vfio_pci_device *device);
void vfio_pci_device_reset(struct vfio_pci_device *device);
void vfio_pci_dma_map(struct vfio_pci_device *device,
- struct vfio_dma_region *region);
+ struct dma_region *region);
void vfio_pci_dma_unmap(struct vfio_pci_device *device,
- struct vfio_dma_region *region);
+ struct dma_region *region);
void vfio_pci_config_access(struct vfio_pci_device *device, bool write,
size_t config, size_t size, void *data);
diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
index 1788e7892ee3..c9cfba1dc62c 100644
--- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c
+++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
@@ -30,7 +30,7 @@
iova_t __to_iova(struct vfio_pci_device *device, void *vaddr)
{
- struct vfio_dma_region *region;
+ struct dma_region *region;
list_for_each_entry(region, &device->iommu->dma_regions, link) {
if (vaddr < region->vaddr)
@@ -142,7 +142,7 @@ static void vfio_pci_irq_get(struct vfio_pci_device *device, u32 index,
}
static void vfio_iommu_dma_map(struct vfio_pci_device *device,
- struct vfio_dma_region *region)
+ struct dma_region *region)
{
struct vfio_iommu_type1_dma_map args = {
.argsz = sizeof(args),
@@ -156,7 +156,7 @@ static void vfio_iommu_dma_map(struct vfio_pci_device *device,
}
static void iommufd_dma_map(struct vfio_pci_device *device,
- struct vfio_dma_region *region)
+ struct dma_region *region)
{
struct iommu_ioas_map args = {
.size = sizeof(args),
@@ -173,7 +173,7 @@ static void iommufd_dma_map(struct vfio_pci_device *device,
}
void vfio_pci_dma_map(struct vfio_pci_device *device,
- struct vfio_dma_region *region)
+ struct dma_region *region)
{
if (device->iommu->iommufd)
iommufd_dma_map(device, region);
@@ -184,7 +184,7 @@ void vfio_pci_dma_map(struct vfio_pci_device *device,
}
static void vfio_iommu_dma_unmap(struct vfio_pci_device *device,
- struct vfio_dma_region *region)
+ struct dma_region *region)
{
struct vfio_iommu_type1_dma_unmap args = {
.argsz = sizeof(args),
@@ -196,7 +196,7 @@ static void vfio_iommu_dma_unmap(struct vfio_pci_device *device,
}
static void iommufd_dma_unmap(struct vfio_pci_device *device,
- struct vfio_dma_region *region)
+ struct dma_region *region)
{
struct iommu_ioas_unmap args = {
.size = sizeof(args),
@@ -209,7 +209,7 @@ static void iommufd_dma_unmap(struct vfio_pci_device *device,
}
void vfio_pci_dma_unmap(struct vfio_pci_device *device,
- struct vfio_dma_region *region)
+ struct dma_region *region)
{
if (device->iommu->iommufd)
iommufd_dma_unmap(device, region);
diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c
index ab19c54a774d..680232777839 100644
--- a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c
+++ b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c
@@ -126,7 +126,7 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap)
{
const u64 size = variant->size ?: getpagesize();
const int flags = variant->mmap_flags;
- struct vfio_dma_region region;
+ struct dma_region region;
struct iommu_mapping mapping;
u64 mapping_size = size;
int rc;
diff --git a/tools/testing/selftests/vfio/vfio_pci_driver_test.c b/tools/testing/selftests/vfio/vfio_pci_driver_test.c
index 2dbd70b7db62..79128a0c278d 100644
--- a/tools/testing/selftests/vfio/vfio_pci_driver_test.c
+++ b/tools/testing/selftests/vfio/vfio_pci_driver_test.c
@@ -19,7 +19,7 @@ static const char *device_bdf;
} while (0)
static void region_setup(struct vfio_pci_device *device,
- struct vfio_dma_region *region, u64 size)
+ struct dma_region *region, u64 size)
{
const int flags = MAP_SHARED | MAP_ANONYMOUS;
const int prot = PROT_READ | PROT_WRITE;
@@ -36,7 +36,7 @@ static void region_setup(struct vfio_pci_device *device,
}
static void region_teardown(struct vfio_pci_device *device,
- struct vfio_dma_region *region)
+ struct dma_region *region)
{
vfio_pci_dma_unmap(device, region);
VFIO_ASSERT_EQ(munmap(region->vaddr, region->size), 0);
@@ -44,7 +44,7 @@ static void region_teardown(struct vfio_pci_device *device,
FIXTURE(vfio_pci_driver_test) {
struct vfio_pci_device *device;
- struct vfio_dma_region memcpy_region;
+ struct dma_region memcpy_region;
void *vaddr;
int msi_fd;
--
2.51.0.710.ga91ca5db03-goog
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 09/12] vfio: selftests: Move iommu_*() functions into iommu.c
2025-10-08 23:25 [PATCH 00/12] vfio: selftests: Support for multi-device tests David Matlack
` (7 preceding siblings ...)
2025-10-08 23:25 ` [PATCH 08/12] vfio: selftests: Rename struct vfio_dma_region to dma_region David Matlack
@ 2025-10-08 23:25 ` David Matlack
2025-10-08 23:25 ` [PATCH 10/12] vfio: selftests: Rename vfio_util.h to libvfio.h David Matlack
` (3 subsequent siblings)
12 siblings, 0 replies; 25+ messages in thread
From: David Matlack @ 2025-10-08 23:25 UTC (permalink / raw)
To: Alex Williamson
Cc: David Matlack, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
Move all the iommu_*() helper functions into their own file iommu.c.
This provides a better separation between the vfio_pci_device helper
code and the iommu code.
No function change intended.
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../selftests/vfio/lib/include/vfio_util.h | 37 ++-
tools/testing/selftests/vfio/lib/iommu.c | 219 ++++++++++++++++++
tools/testing/selftests/vfio/lib/libvfio.mk | 3 +-
.../selftests/vfio/lib/vfio_pci_device.c | 212 -----------------
4 files changed, 252 insertions(+), 219 deletions(-)
create mode 100644 tools/testing/selftests/vfio/lib/iommu.c
diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h
index cce521212348..c7932096ac2e 100644
--- a/tools/testing/selftests/vfio/lib/include/vfio_util.h
+++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h
@@ -7,6 +7,7 @@
#include <linux/vfio.h>
#include <linux/list.h>
#include <linux/pci_regs.h>
+#include <sys/ioctl.h>
#include "../../../kselftest.h"
@@ -47,6 +48,12 @@
VFIO_LOG_AND_EXIT(_fmt, ##__VA_ARGS__); \
} while (0)
+#define ioctl_assert(_fd, _op, _arg) do { \
+ void *__arg = (_arg); \
+ int __ret = ioctl((_fd), (_op), (__arg)); \
+ VFIO_ASSERT_EQ(__ret, 0, "ioctl(%s, %s, %s) returned %d\n", #_fd, #_op, #_arg, __ret); \
+} while (0)
+
#define dev_info(_dev, _fmt, ...) printf("%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)
#define dev_err(_dev, _fmt, ...) fprintf(stderr, "%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)
@@ -212,6 +219,10 @@ extern const char *default_iommu_mode;
struct iommu *iommu_init(const char *iommu_mode);
void iommu_cleanup(struct iommu *iommu);
+iova_t iommu_hva2iova(struct iommu *iommu, void *vaddr);
+iova_t __iommu_hva2iova(struct iommu *iommu, void *vaddr);
+void iommu_map(struct iommu *iommu, struct dma_region *region);
+void iommu_unmap(struct iommu *iommu, struct dma_region *region);
struct vfio_pci_device *__vfio_pci_device_init(const char *bdf, struct iommu *iommu);
struct vfio_pci_device *vfio_pci_device_init(const char *bdf, const char *iommu_mode);
@@ -221,10 +232,17 @@ void vfio_pci_device_cleanup(struct vfio_pci_device *device);
void vfio_pci_device_reset(struct vfio_pci_device *device);
-void vfio_pci_dma_map(struct vfio_pci_device *device,
- struct dma_region *region);
-void vfio_pci_dma_unmap(struct vfio_pci_device *device,
- struct dma_region *region);
+static inline void vfio_pci_dma_map(struct vfio_pci_device *device,
+ struct dma_region *region)
+{
+ return iommu_map(device->iommu, region);
+}
+
+static inline void vfio_pci_dma_unmap(struct vfio_pci_device *device,
+ struct dma_region *region)
+{
+ return iommu_unmap(device->iommu, region);
+}
void vfio_pci_config_access(struct vfio_pci_device *device, bool write,
size_t config, size_t size, void *data);
@@ -286,8 +304,15 @@ static inline void vfio_pci_msix_disable(struct vfio_pci_device *device)
vfio_pci_irq_disable(device, VFIO_PCI_MSIX_IRQ_INDEX);
}
-iova_t __to_iova(struct vfio_pci_device *device, void *vaddr);
-iova_t to_iova(struct vfio_pci_device *device, void *vaddr);
+static inline iova_t __to_iova(struct vfio_pci_device *device, void *vaddr)
+{
+ return __iommu_hva2iova(device->iommu, vaddr);
+}
+
+static inline iova_t to_iova(struct vfio_pci_device *device, void *vaddr)
+{
+ return iommu_hva2iova(device->iommu, vaddr);
+}
static inline bool vfio_pci_device_match(struct vfio_pci_device *device,
u16 vendor_id, u16 device_id)
diff --git a/tools/testing/selftests/vfio/lib/iommu.c b/tools/testing/selftests/vfio/lib/iommu.c
new file mode 100644
index 000000000000..a835b0d29abf
--- /dev/null
+++ b/tools/testing/selftests/vfio/lib/iommu.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <dirent.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/eventfd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <uapi/linux/types.h>
+#include <linux/limits.h>
+#include <linux/mman.h>
+#include <linux/types.h>
+#include <linux/vfio.h>
+#include <linux/iommufd.h>
+
+#include "../../../kselftest.h"
+#include <vfio_util.h>
+
+const char *default_iommu_mode = "iommufd";
+
+/* Reminder: Keep in sync with FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(). */
+static const struct iommu_mode iommu_modes[] = {
+ {
+ .name = "vfio_type1_iommu",
+ .container_path = "/dev/vfio/vfio",
+ .iommu_type = VFIO_TYPE1_IOMMU,
+ },
+ {
+ .name = "vfio_type1v2_iommu",
+ .container_path = "/dev/vfio/vfio",
+ .iommu_type = VFIO_TYPE1v2_IOMMU,
+ },
+ {
+ .name = "iommufd_compat_type1",
+ .container_path = "/dev/iommu",
+ .iommu_type = VFIO_TYPE1_IOMMU,
+ },
+ {
+ .name = "iommufd_compat_type1v2",
+ .container_path = "/dev/iommu",
+ .iommu_type = VFIO_TYPE1v2_IOMMU,
+ },
+ {
+ .name = "iommufd",
+ },
+};
+
+iova_t __iommu_hva2iova(struct iommu *iommu, void *vaddr)
+{
+ struct dma_region *region;
+
+ list_for_each_entry(region, &iommu->dma_regions, link) {
+ if (vaddr < region->vaddr)
+ continue;
+
+ if (vaddr >= region->vaddr + region->size)
+ continue;
+
+ return region->iova + (vaddr - region->vaddr);
+ }
+
+ return INVALID_IOVA;
+}
+
+iova_t iommu_hva2iova(struct iommu *iommu, void *vaddr)
+{
+ iova_t iova = __iommu_hva2iova(iommu, vaddr);
+
+ VFIO_ASSERT_NE(iova, INVALID_IOVA, "VA %p is not mapped\n", vaddr);
+ return iova;
+}
+
+static void vfio_iommu_dma_map(struct iommu *iommu, struct dma_region *region)
+{
+ struct vfio_iommu_type1_dma_map args = {
+ .argsz = sizeof(args),
+ .flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE,
+ .vaddr = (u64)region->vaddr,
+ .iova = region->iova,
+ .size = region->size,
+ };
+
+ ioctl_assert(iommu->container_fd, VFIO_IOMMU_MAP_DMA, &args);
+}
+
+static void iommufd_dma_map(struct iommu *iommu, struct dma_region *region)
+{
+ struct iommu_ioas_map args = {
+ .size = sizeof(args),
+ .flags = IOMMU_IOAS_MAP_READABLE |
+ IOMMU_IOAS_MAP_WRITEABLE |
+ IOMMU_IOAS_MAP_FIXED_IOVA,
+ .user_va = (u64)region->vaddr,
+ .iova = region->iova,
+ .length = region->size,
+ .ioas_id = iommu->ioas_id,
+ };
+
+ ioctl_assert(iommu->iommufd, IOMMU_IOAS_MAP, &args);
+}
+
+void iommu_map(struct iommu *iommu, struct dma_region *region)
+{
+ if (iommu->iommufd)
+ iommufd_dma_map(iommu, region);
+ else
+ vfio_iommu_dma_map(iommu, region);
+
+ list_add(®ion->link, &iommu->dma_regions);
+}
+
+static void vfio_iommu_dma_unmap(struct iommu *iommu, struct dma_region *region)
+{
+ struct vfio_iommu_type1_dma_unmap args = {
+ .argsz = sizeof(args),
+ .iova = region->iova,
+ .size = region->size,
+ };
+
+ ioctl_assert(iommu->container_fd, VFIO_IOMMU_UNMAP_DMA, &args);
+}
+
+static void iommufd_dma_unmap(struct iommu *iommu, struct dma_region *region)
+{
+ struct iommu_ioas_unmap args = {
+ .size = sizeof(args),
+ .iova = region->iova,
+ .length = region->size,
+ .ioas_id = iommu->ioas_id,
+ };
+
+ ioctl_assert(iommu->iommufd, IOMMU_IOAS_UNMAP, &args);
+}
+
+void iommu_unmap(struct iommu *iommu, struct dma_region *region)
+{
+ if (iommu->iommufd)
+ iommufd_dma_unmap(iommu, region);
+ else
+ vfio_iommu_dma_unmap(iommu, region);
+
+ list_del(®ion->link);
+}
+
+static const struct iommu_mode *lookup_iommu_mode(const char *iommu_mode)
+{
+ int i;
+
+ if (!iommu_mode)
+ iommu_mode = default_iommu_mode;
+
+ for (i = 0; i < ARRAY_SIZE(iommu_modes); i++) {
+ if (strcmp(iommu_mode, iommu_modes[i].name))
+ continue;
+
+ return &iommu_modes[i];
+ }
+
+ VFIO_FAIL("Unrecognized IOMMU mode: %s\n", iommu_mode);
+}
+
+static u32 iommufd_ioas_alloc(int iommufd)
+{
+ struct iommu_ioas_alloc args = {
+ .size = sizeof(args),
+ };
+
+ ioctl_assert(iommufd, IOMMU_IOAS_ALLOC, &args);
+ return args.out_ioas_id;
+}
+
+struct iommu *iommu_init(const char *iommu_mode)
+{
+ const char *container_path;
+ struct iommu *iommu;
+ int version;
+
+ iommu = calloc(1, sizeof(*iommu));
+ VFIO_ASSERT_NOT_NULL(iommu);
+
+ INIT_LIST_HEAD(&iommu->dma_regions);
+
+ iommu->mode = lookup_iommu_mode(iommu_mode);
+
+ container_path = iommu->mode->container_path;
+ if (container_path) {
+ iommu->container_fd = open(container_path, O_RDWR);
+ VFIO_ASSERT_GE(iommu->container_fd, 0, "open(%s) failed\n", container_path);
+
+ 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);
+ }
+
+ return iommu;
+}
+
+void iommu_cleanup(struct iommu *iommu)
+{
+ if (iommu->iommufd)
+ VFIO_ASSERT_EQ(close(iommu->iommufd), 0);
+ else
+ VFIO_ASSERT_EQ(close(iommu->container_fd), 0);
+
+ free(iommu);
+}
diff --git a/tools/testing/selftests/vfio/lib/libvfio.mk b/tools/testing/selftests/vfio/lib/libvfio.mk
index 5d11c3a89a28..1d53311e2610 100644
--- a/tools/testing/selftests/vfio/lib/libvfio.mk
+++ b/tools/testing/selftests/vfio/lib/libvfio.mk
@@ -3,7 +3,8 @@ ARCH ?= $(SUBARCH)
VFIO_DIR := $(selfdir)/vfio
-LIBVFIO_C := lib/vfio_pci_device.c
+LIBVFIO_C := lib/iommu.c
+LIBVFIO_C += lib/vfio_pci_device.c
LIBVFIO_C += lib/vfio_pci_driver.c
ifeq ($(ARCH:x86_64=x86),x86)
diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
index c9cfba1dc62c..b026b908dcd2 100644
--- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c
+++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
@@ -22,39 +22,6 @@
#define PCI_SYSFS_PATH "/sys/bus/pci/devices"
-#define ioctl_assert(_fd, _op, _arg) do { \
- void *__arg = (_arg); \
- int __ret = ioctl((_fd), (_op), (__arg)); \
- VFIO_ASSERT_EQ(__ret, 0, "ioctl(%s, %s, %s) returned %d\n", #_fd, #_op, #_arg, __ret); \
-} while (0)
-
-iova_t __to_iova(struct vfio_pci_device *device, void *vaddr)
-{
- struct dma_region *region;
-
- list_for_each_entry(region, &device->iommu->dma_regions, link) {
- if (vaddr < region->vaddr)
- continue;
-
- if (vaddr >= region->vaddr + region->size)
- continue;
-
- return region->iova + (vaddr - region->vaddr);
- }
-
- return INVALID_IOVA;
-}
-
-iova_t to_iova(struct vfio_pci_device *device, void *vaddr)
-{
- iova_t iova;
-
- iova = __to_iova(device, vaddr);
- VFIO_ASSERT_NE(iova, INVALID_IOVA, "%p is not mapped into device.\n", vaddr);
-
- return iova;
-}
-
static void vfio_pci_irq_set(struct vfio_pci_device *device,
u32 index, u32 vector, u32 count, int *fds)
{
@@ -141,84 +108,6 @@ static void vfio_pci_irq_get(struct vfio_pci_device *device, u32 index,
ioctl_assert(device->fd, VFIO_DEVICE_GET_IRQ_INFO, irq_info);
}
-static void vfio_iommu_dma_map(struct vfio_pci_device *device,
- struct dma_region *region)
-{
- struct vfio_iommu_type1_dma_map args = {
- .argsz = sizeof(args),
- .flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE,
- .vaddr = (u64)region->vaddr,
- .iova = region->iova,
- .size = region->size,
- };
-
- ioctl_assert(device->iommu->container_fd, VFIO_IOMMU_MAP_DMA, &args);
-}
-
-static void iommufd_dma_map(struct vfio_pci_device *device,
- struct dma_region *region)
-{
- struct iommu_ioas_map args = {
- .size = sizeof(args),
- .flags = IOMMU_IOAS_MAP_READABLE |
- IOMMU_IOAS_MAP_WRITEABLE |
- IOMMU_IOAS_MAP_FIXED_IOVA,
- .user_va = (u64)region->vaddr,
- .iova = region->iova,
- .length = region->size,
- .ioas_id = device->iommu->ioas_id,
- };
-
- ioctl_assert(device->iommu->iommufd, IOMMU_IOAS_MAP, &args);
-}
-
-void vfio_pci_dma_map(struct vfio_pci_device *device,
- struct dma_region *region)
-{
- if (device->iommu->iommufd)
- iommufd_dma_map(device, region);
- else
- vfio_iommu_dma_map(device, region);
-
- list_add(®ion->link, &device->iommu->dma_regions);
-}
-
-static void vfio_iommu_dma_unmap(struct vfio_pci_device *device,
- struct dma_region *region)
-{
- struct vfio_iommu_type1_dma_unmap args = {
- .argsz = sizeof(args),
- .iova = region->iova,
- .size = region->size,
- };
-
- ioctl_assert(device->iommu->container_fd, VFIO_IOMMU_UNMAP_DMA, &args);
-}
-
-static void iommufd_dma_unmap(struct vfio_pci_device *device,
- struct dma_region *region)
-{
- struct iommu_ioas_unmap args = {
- .size = sizeof(args),
- .iova = region->iova,
- .length = region->size,
- .ioas_id = device->iommu->ioas_id,
- };
-
- ioctl_assert(device->iommu->iommufd, IOMMU_IOAS_UNMAP, &args);
-}
-
-void vfio_pci_dma_unmap(struct vfio_pci_device *device,
- struct dma_region *region)
-{
- if (device->iommu->iommufd)
- iommufd_dma_unmap(device, region);
- else
- vfio_iommu_dma_unmap(device, region);
-
- list_del(®ion->link);
-}
-
static void vfio_pci_region_get(struct vfio_pci_device *device, int index,
struct vfio_region_info *info)
{
@@ -408,52 +297,6 @@ const char *vfio_pci_get_cdev_path(const char *bdf)
return cdev_path;
}
-/* Reminder: Keep in sync with FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(). */
-static const struct iommu_mode iommu_modes[] = {
- {
- .name = "vfio_type1_iommu",
- .container_path = "/dev/vfio/vfio",
- .iommu_type = VFIO_TYPE1_IOMMU,
- },
- {
- .name = "vfio_type1v2_iommu",
- .container_path = "/dev/vfio/vfio",
- .iommu_type = VFIO_TYPE1v2_IOMMU,
- },
- {
- .name = "iommufd_compat_type1",
- .container_path = "/dev/iommu",
- .iommu_type = VFIO_TYPE1_IOMMU,
- },
- {
- .name = "iommufd_compat_type1v2",
- .container_path = "/dev/iommu",
- .iommu_type = VFIO_TYPE1v2_IOMMU,
- },
- {
- .name = "iommufd",
- },
-};
-
-const char *default_iommu_mode = "iommufd";
-
-static const struct iommu_mode *lookup_iommu_mode(const char *iommu_mode)
-{
- int i;
-
- if (!iommu_mode)
- iommu_mode = default_iommu_mode;
-
- for (i = 0; i < ARRAY_SIZE(iommu_modes); i++) {
- if (strcmp(iommu_mode, iommu_modes[i].name))
- continue;
-
- return &iommu_modes[i];
- }
-
- VFIO_FAIL("Unrecognized IOMMU mode: %s\n", iommu_mode);
-}
-
static void vfio_device_bind_iommufd(int device_fd, int iommufd)
{
struct vfio_device_bind_iommufd args = {
@@ -464,16 +307,6 @@ static void vfio_device_bind_iommufd(int device_fd, int iommufd)
ioctl_assert(device_fd, VFIO_DEVICE_BIND_IOMMUFD, &args);
}
-static u32 iommufd_ioas_alloc(int iommufd)
-{
- struct iommu_ioas_alloc args = {
- .size = sizeof(args),
- };
-
- ioctl_assert(iommufd, IOMMU_IOAS_ALLOC, &args);
- return args.out_ioas_id;
-}
-
static void vfio_device_attach_iommufd_pt(int device_fd, u32 pt_id)
{
struct vfio_device_attach_iommufd_pt args = {
@@ -496,41 +329,6 @@ static void vfio_pci_iommufd_setup(struct vfio_pci_device *device, const char *b
vfio_device_attach_iommufd_pt(device->fd, device->iommu->ioas_id);
}
-struct iommu *iommu_init(const char *iommu_mode)
-{
- const char *container_path;
- struct iommu *iommu;
- int version;
-
- iommu = calloc(1, sizeof(*iommu));
- VFIO_ASSERT_NOT_NULL(iommu);
-
- INIT_LIST_HEAD(&iommu->dma_regions);
-
- iommu->mode = lookup_iommu_mode(iommu_mode);
-
- container_path = iommu->mode->container_path;
- if (container_path) {
- iommu->container_fd = open(container_path, O_RDWR);
- VFIO_ASSERT_GE(iommu->container_fd, 0, "open(%s) failed\n", container_path);
-
- 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);
- }
-
- return iommu;
-}
-
struct vfio_pci_device *__vfio_pci_device_init(const char *bdf, struct iommu *iommu)
{
struct vfio_pci_device *device;
@@ -583,16 +381,6 @@ void __vfio_pci_device_cleanup(struct vfio_pci_device *device)
free(device);
}
-void iommu_cleanup(struct iommu *iommu)
-{
- if (iommu->iommufd)
- VFIO_ASSERT_EQ(close(iommu->iommufd), 0);
- else
- VFIO_ASSERT_EQ(close(iommu->container_fd), 0);
-
- free(iommu);
-}
-
void vfio_pci_device_cleanup(struct vfio_pci_device *device)
{
struct iommu *iommu = device->iommu;
--
2.51.0.710.ga91ca5db03-goog
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 10/12] vfio: selftests: Rename vfio_util.h to libvfio.h
2025-10-08 23:25 [PATCH 00/12] vfio: selftests: Support for multi-device tests David Matlack
` (8 preceding siblings ...)
2025-10-08 23:25 ` [PATCH 09/12] vfio: selftests: Move iommu_*() functions into iommu.c David Matlack
@ 2025-10-08 23:25 ` David Matlack
2025-10-08 23:25 ` [PATCH 11/12] vfio: selftests: Split libvfio.h into separate header files David Matlack
` (2 subsequent siblings)
12 siblings, 0 replies; 25+ messages in thread
From: David Matlack @ 2025-10-08 23:25 UTC (permalink / raw)
To: Alex Williamson
Cc: David Matlack, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
Rename vfio_util.h to libvfio.h to match the name of libvfio.mk.
No functional change intended.
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c | 2 +-
tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c | 2 +-
.../selftests/vfio/lib/include/{vfio_util.h => libvfio.h} | 6 +++---
tools/testing/selftests/vfio/lib/iommu.c | 2 +-
tools/testing/selftests/vfio/lib/vfio_pci_device.c | 2 +-
tools/testing/selftests/vfio/lib/vfio_pci_driver.c | 2 +-
tools/testing/selftests/vfio/vfio_dma_mapping_test.c | 2 +-
tools/testing/selftests/vfio/vfio_iommufd_setup_test.c | 2 +-
tools/testing/selftests/vfio/vfio_pci_device_test.c | 2 +-
tools/testing/selftests/vfio/vfio_pci_driver_test.c | 2 +-
10 files changed, 12 insertions(+), 12 deletions(-)
rename tools/testing/selftests/vfio/lib/include/{vfio_util.h => libvfio.h} (98%)
diff --git a/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c b/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c
index 8d667be80229..a75d8ea46562 100644
--- a/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c
+++ b/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c
@@ -9,7 +9,7 @@
#include <linux/pci_ids.h>
#include <linux/sizes.h>
-#include <vfio_util.h>
+#include <libvfio.h>
#include "registers.h"
diff --git a/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c b/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c
index e04dce1d544c..ce147839b31f 100644
--- a/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c
+++ b/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c
@@ -7,7 +7,7 @@
#include <linux/pci_ids.h>
#include <linux/sizes.h>
-#include <vfio_util.h>
+#include <libvfio.h>
#include "hw.h"
#include "registers.h"
diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/libvfio.h
similarity index 98%
rename from tools/testing/selftests/vfio/lib/include/vfio_util.h
rename to tools/testing/selftests/vfio/lib/include/libvfio.h
index c7932096ac2e..8b72d9c62404 100644
--- a/tools/testing/selftests/vfio/lib/include/vfio_util.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-#ifndef SELFTESTS_VFIO_LIB_INCLUDE_VFIO_UTIL_H
-#define SELFTESTS_VFIO_LIB_INCLUDE_VFIO_UTIL_H
+#ifndef SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_H
+#define SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_H
#include <fcntl.h>
#include <string.h>
@@ -332,4 +332,4 @@ void vfio_pci_driver_memcpy_start(struct vfio_pci_device *device,
int vfio_pci_driver_memcpy_wait(struct vfio_pci_device *device);
void vfio_pci_driver_send_msi(struct vfio_pci_device *device);
-#endif /* SELFTESTS_VFIO_LIB_INCLUDE_VFIO_UTIL_H */
+#endif /* SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_H */
diff --git a/tools/testing/selftests/vfio/lib/iommu.c b/tools/testing/selftests/vfio/lib/iommu.c
index a835b0d29abf..682b4c9da625 100644
--- a/tools/testing/selftests/vfio/lib/iommu.c
+++ b/tools/testing/selftests/vfio/lib/iommu.c
@@ -18,7 +18,7 @@
#include <linux/iommufd.h>
#include "../../../kselftest.h"
-#include <vfio_util.h>
+#include <libvfio.h>
const char *default_iommu_mode = "iommufd";
diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
index b026b908dcd2..909c951eb52f 100644
--- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c
+++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
@@ -18,7 +18,7 @@
#include <linux/iommufd.h>
#include "../../../kselftest.h"
-#include <vfio_util.h>
+#include <libvfio.h>
#define PCI_SYSFS_PATH "/sys/bus/pci/devices"
diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_driver.c b/tools/testing/selftests/vfio/lib/vfio_pci_driver.c
index abb7a62a03ea..ca0e25efbfa1 100644
--- a/tools/testing/selftests/vfio/lib/vfio_pci_driver.c
+++ b/tools/testing/selftests/vfio/lib/vfio_pci_driver.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
#include "../../../kselftest.h"
-#include <vfio_util.h>
+#include <libvfio.h>
#ifdef __x86_64__
extern struct vfio_pci_driver_ops dsa_ops;
diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c
index 680232777839..5092c55a76e3 100644
--- a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c
+++ b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c
@@ -8,7 +8,7 @@
#include <linux/sizes.h>
#include <linux/vfio.h>
-#include <vfio_util.h>
+#include <libvfio.h>
#include "../kselftest_harness.h"
diff --git a/tools/testing/selftests/vfio/vfio_iommufd_setup_test.c b/tools/testing/selftests/vfio/vfio_iommufd_setup_test.c
index 3655106b912d..caf1c6291f3d 100644
--- a/tools/testing/selftests/vfio/vfio_iommufd_setup_test.c
+++ b/tools/testing/selftests/vfio/vfio_iommufd_setup_test.c
@@ -10,7 +10,7 @@
#include <sys/ioctl.h>
#include <unistd.h>
-#include <vfio_util.h>
+#include <libvfio.h>
#include "../kselftest_harness.h"
static const char iommu_dev_path[] = "/dev/iommu";
diff --git a/tools/testing/selftests/vfio/vfio_pci_device_test.c b/tools/testing/selftests/vfio/vfio_pci_device_test.c
index 7a270698e4d2..a44ab8041cb6 100644
--- a/tools/testing/selftests/vfio/vfio_pci_device_test.c
+++ b/tools/testing/selftests/vfio/vfio_pci_device_test.c
@@ -10,7 +10,7 @@
#include <linux/sizes.h>
#include <linux/vfio.h>
-#include <vfio_util.h>
+#include <libvfio.h>
#include "../kselftest_harness.h"
diff --git a/tools/testing/selftests/vfio/vfio_pci_driver_test.c b/tools/testing/selftests/vfio/vfio_pci_driver_test.c
index 79128a0c278d..fe107ba129d1 100644
--- a/tools/testing/selftests/vfio/vfio_pci_driver_test.c
+++ b/tools/testing/selftests/vfio/vfio_pci_driver_test.c
@@ -5,7 +5,7 @@
#include <linux/sizes.h>
#include <linux/vfio.h>
-#include <vfio_util.h>
+#include <libvfio.h>
#include "../kselftest_harness.h"
--
2.51.0.710.ga91ca5db03-goog
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 11/12] vfio: selftests: Split libvfio.h into separate header files
2025-10-08 23:25 [PATCH 00/12] vfio: selftests: Support for multi-device tests David Matlack
` (9 preceding siblings ...)
2025-10-08 23:25 ` [PATCH 10/12] vfio: selftests: Rename vfio_util.h to libvfio.h David Matlack
@ 2025-10-08 23:25 ` David Matlack
2025-10-08 23:25 ` [PATCH 12/12] vfio: selftests: Add vfio_pci_device_init_perf_test David Matlack
2025-11-05 19:06 ` [PATCH 00/12] vfio: selftests: Support for multi-device tests Alex Williamson
12 siblings, 0 replies; 25+ messages in thread
From: David Matlack @ 2025-10-08 23:25 UTC (permalink / raw)
To: Alex Williamson
Cc: David Matlack, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
Split out the contents of libvfio.h into separate header files, but keep
libvfio.h as the top-level include that all tests can use.
Put all new header files into a libvfio/ subdirectory to avoid future
name conflicts in include paths when libvfio is used by other selftests
like KVM.
No functional change intended.
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../selftests/vfio/lib/include/libvfio.h | 318 +-----------------
.../vfio/lib/include/libvfio/assert.h | 53 +++
.../vfio/lib/include/libvfio/iommu.h | 53 +++
.../lib/include/libvfio/vfio_pci_device.h | 143 ++++++++
.../lib/include/libvfio/vfio_pci_driver.h | 98 ++++++
tools/testing/selftests/vfio/lib/libvfio.c | 77 +++++
tools/testing/selftests/vfio/lib/libvfio.mk | 3 +-
.../selftests/vfio/lib/vfio_pci_device.c | 70 ----
8 files changed, 430 insertions(+), 385 deletions(-)
create mode 100644 tools/testing/selftests/vfio/lib/include/libvfio/assert.h
create mode 100644 tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
create mode 100644 tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
create mode 100644 tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_driver.h
create mode 100644 tools/testing/selftests/vfio/lib/libvfio.c
diff --git a/tools/testing/selftests/vfio/lib/include/libvfio.h b/tools/testing/selftests/vfio/lib/include/libvfio.h
index 8b72d9c62404..ddb0b3bf60e7 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio.h
@@ -2,201 +2,10 @@
#ifndef SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_H
#define SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_H
-#include <fcntl.h>
-#include <string.h>
-#include <linux/vfio.h>
-#include <linux/list.h>
-#include <linux/pci_regs.h>
-#include <sys/ioctl.h>
-
-#include "../../../kselftest.h"
-
-#define VFIO_LOG_AND_EXIT(...) do { \
- fprintf(stderr, " " __VA_ARGS__); \
- fprintf(stderr, "\n"); \
- exit(KSFT_FAIL); \
-} while (0)
-
-#define VFIO_ASSERT_OP(_lhs, _rhs, _op, ...) do { \
- typeof(_lhs) __lhs = (_lhs); \
- typeof(_rhs) __rhs = (_rhs); \
- \
- if (__lhs _op __rhs) \
- break; \
- \
- fprintf(stderr, "%s:%u: Assertion Failure\n\n", __FILE__, __LINE__); \
- fprintf(stderr, " Expression: " #_lhs " " #_op " " #_rhs "\n"); \
- fprintf(stderr, " Observed: %#lx %s %#lx\n", \
- (u64)__lhs, #_op, (u64)__rhs); \
- fprintf(stderr, " [errno: %d - %s]\n", errno, strerror(errno)); \
- VFIO_LOG_AND_EXIT(__VA_ARGS__); \
-} while (0)
-
-#define VFIO_ASSERT_EQ(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, ==, ##__VA_ARGS__)
-#define VFIO_ASSERT_NE(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, !=, ##__VA_ARGS__)
-#define VFIO_ASSERT_LT(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, <, ##__VA_ARGS__)
-#define VFIO_ASSERT_LE(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, <=, ##__VA_ARGS__)
-#define VFIO_ASSERT_GT(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, >, ##__VA_ARGS__)
-#define VFIO_ASSERT_GE(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, >=, ##__VA_ARGS__)
-#define VFIO_ASSERT_TRUE(_a, ...) VFIO_ASSERT_NE(false, (_a), ##__VA_ARGS__)
-#define VFIO_ASSERT_FALSE(_a, ...) VFIO_ASSERT_EQ(false, (_a), ##__VA_ARGS__)
-#define VFIO_ASSERT_NULL(_a, ...) VFIO_ASSERT_EQ(NULL, _a, ##__VA_ARGS__)
-#define VFIO_ASSERT_NOT_NULL(_a, ...) VFIO_ASSERT_NE(NULL, _a, ##__VA_ARGS__)
-
-#define VFIO_FAIL(_fmt, ...) do { \
- fprintf(stderr, "%s:%u: FAIL\n\n", __FILE__, __LINE__); \
- VFIO_LOG_AND_EXIT(_fmt, ##__VA_ARGS__); \
-} while (0)
-
-#define ioctl_assert(_fd, _op, _arg) do { \
- void *__arg = (_arg); \
- int __ret = ioctl((_fd), (_op), (__arg)); \
- VFIO_ASSERT_EQ(__ret, 0, "ioctl(%s, %s, %s) returned %d\n", #_fd, #_op, #_arg, __ret); \
-} while (0)
-
-#define dev_info(_dev, _fmt, ...) printf("%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)
-#define dev_err(_dev, _fmt, ...) fprintf(stderr, "%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)
-
-struct iommu_mode {
- const char *name;
- const char *container_path;
- unsigned long iommu_type;
-};
-
-/*
- * 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.
- */
-#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__)
-
-struct vfio_pci_bar {
- struct vfio_region_info info;
- void *vaddr;
-};
-
-typedef u64 iova_t;
-
-#define INVALID_IOVA UINT64_MAX
-
-struct dma_region {
- struct list_head link;
- void *vaddr;
- iova_t iova;
- u64 size;
-};
-
-struct vfio_pci_device;
-
-struct vfio_pci_driver_ops {
- const char *name;
-
- /**
- * @probe() - Check if the driver supports the given device.
- *
- * Return: 0 on success, non-0 on failure.
- */
- int (*probe)(struct vfio_pci_device *device);
-
- /**
- * @init() - Initialize the driver for @device.
- *
- * Must be called after device->driver.region has been initialized.
- */
- void (*init)(struct vfio_pci_device *device);
-
- /**
- * remove() - Deinitialize the driver for @device.
- */
- void (*remove)(struct vfio_pci_device *device);
-
- /**
- * memcpy_start() - Kick off @count repeated memcpy operations from
- * [@src, @src + @size) to [@dst, @dst + @size).
- *
- * Guarantees:
- * - The device will attempt DMA reads on [src, src + size).
- * - The device will attempt DMA writes on [dst, dst + size).
- * - The device will not generate any interrupts.
- *
- * memcpy_start() returns immediately, it does not wait for the
- * copies to complete.
- */
- void (*memcpy_start)(struct vfio_pci_device *device,
- iova_t src, iova_t dst, u64 size, u64 count);
-
- /**
- * memcpy_wait() - Wait until the memcpy operations started by
- * memcpy_start() have finished.
- *
- * Guarantees:
- * - All in-flight DMAs initiated by memcpy_start() are fully complete
- * before memcpy_wait() returns.
- *
- * Returns non-0 if the driver detects that an error occurred during the
- * memcpy, 0 otherwise.
- */
- int (*memcpy_wait)(struct vfio_pci_device *device);
-
- /**
- * send_msi() - Make the device send the MSI device->driver.msi.
- *
- * Guarantees:
- * - The device will send the MSI once.
- */
- void (*send_msi)(struct vfio_pci_device *device);
-};
-
-struct vfio_pci_driver {
- const struct vfio_pci_driver_ops *ops;
- bool initialized;
- bool memcpy_in_progress;
-
- /* Region to be used by the driver (e.g. for in-memory descriptors) */
- struct dma_region region;
-
- /* The maximum size that can be passed to memcpy_start(). */
- u64 max_memcpy_size;
-
- /* The maximum count that can be passed to memcpy_start(). */
- u64 max_memcpy_count;
-
- /* The MSI vector the device will signal in ops->send_msi(). */
- int msi;
-};
-
-struct iommu {
- const struct iommu_mode *mode;
- int container_fd;
- int iommufd;
- u32 ioas_id;
- struct list_head dma_regions;
-};
-
-struct vfio_pci_device {
- const char *bdf;
- int fd;
- int group_fd;
-
- struct iommu *iommu;
-
- struct vfio_device_info info;
- struct vfio_region_info config_space;
- struct vfio_pci_bar bars[PCI_STD_NUM_BARS];
-
- struct vfio_irq_info msi_info;
- struct vfio_irq_info msix_info;
-
- /* eventfds for MSI and MSI-x interrupts */
- int msi_eventfds[PCI_MSIX_FLAGS_QSIZE + 1];
-
- struct vfio_pci_driver driver;
-};
+#include <libvfio/assert.h>
+#include <libvfio/iommu.h>
+#include <libvfio/vfio_pci_driver.h>
+#include <libvfio/vfio_pci_device.h>
/*
* Return the BDF string of the device that the test should use.
@@ -213,123 +22,4 @@ struct vfio_pci_device {
const char *vfio_selftests_get_bdf(int *argc, char *argv[]);
char **vfio_selftests_get_bdfs(int *argc, char *argv[], int *nr_bdfs);
-const char *vfio_pci_get_cdev_path(const char *bdf);
-
-extern const char *default_iommu_mode;
-
-struct iommu *iommu_init(const char *iommu_mode);
-void iommu_cleanup(struct iommu *iommu);
-iova_t iommu_hva2iova(struct iommu *iommu, void *vaddr);
-iova_t __iommu_hva2iova(struct iommu *iommu, void *vaddr);
-void iommu_map(struct iommu *iommu, struct dma_region *region);
-void iommu_unmap(struct iommu *iommu, struct dma_region *region);
-
-struct vfio_pci_device *__vfio_pci_device_init(const char *bdf, struct iommu *iommu);
-struct vfio_pci_device *vfio_pci_device_init(const char *bdf, const char *iommu_mode);
-
-void __vfio_pci_device_cleanup(struct vfio_pci_device *device);
-void vfio_pci_device_cleanup(struct vfio_pci_device *device);
-
-void vfio_pci_device_reset(struct vfio_pci_device *device);
-
-static inline void vfio_pci_dma_map(struct vfio_pci_device *device,
- struct dma_region *region)
-{
- return iommu_map(device->iommu, region);
-}
-
-static inline void vfio_pci_dma_unmap(struct vfio_pci_device *device,
- struct dma_region *region)
-{
- return iommu_unmap(device->iommu, region);
-}
-
-void vfio_pci_config_access(struct vfio_pci_device *device, bool write,
- size_t config, size_t size, void *data);
-
-#define vfio_pci_config_read(_device, _offset, _type) ({ \
- _type __data; \
- vfio_pci_config_access((_device), false, _offset, sizeof(__data), &__data); \
- __data; \
-})
-
-#define vfio_pci_config_readb(_d, _o) vfio_pci_config_read(_d, _o, u8)
-#define vfio_pci_config_readw(_d, _o) vfio_pci_config_read(_d, _o, u16)
-#define vfio_pci_config_readl(_d, _o) vfio_pci_config_read(_d, _o, u32)
-
-#define vfio_pci_config_write(_device, _offset, _value, _type) do { \
- _type __data = (_value); \
- vfio_pci_config_access((_device), true, _offset, sizeof(_type), &__data); \
-} while (0)
-
-#define vfio_pci_config_writeb(_d, _o, _v) vfio_pci_config_write(_d, _o, _v, u8)
-#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_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);
-void vfio_pci_irq_trigger(struct vfio_pci_device *device, u32 index, u32 vector);
-
-static inline void fcntl_set_nonblock(int fd)
-{
- int r;
-
- r = fcntl(fd, F_GETFL, 0);
- VFIO_ASSERT_NE(r, -1, "F_GETFL failed for fd %d\n", fd);
-
- r = fcntl(fd, F_SETFL, r | O_NONBLOCK);
- VFIO_ASSERT_NE(r, -1, "F_SETFL O_NONBLOCK failed for fd %d\n", fd);
-}
-
-static inline void vfio_pci_msi_enable(struct vfio_pci_device *device,
- u32 vector, int count)
-{
- vfio_pci_irq_enable(device, VFIO_PCI_MSI_IRQ_INDEX, vector, count);
-}
-
-static inline void vfio_pci_msi_disable(struct vfio_pci_device *device)
-{
- vfio_pci_irq_disable(device, VFIO_PCI_MSI_IRQ_INDEX);
-}
-
-static inline void vfio_pci_msix_enable(struct vfio_pci_device *device,
- u32 vector, int count)
-{
- vfio_pci_irq_enable(device, VFIO_PCI_MSIX_IRQ_INDEX, vector, count);
-}
-
-static inline void vfio_pci_msix_disable(struct vfio_pci_device *device)
-{
- vfio_pci_irq_disable(device, VFIO_PCI_MSIX_IRQ_INDEX);
-}
-
-static inline iova_t __to_iova(struct vfio_pci_device *device, void *vaddr)
-{
- return __iommu_hva2iova(device->iommu, vaddr);
-}
-
-static inline iova_t to_iova(struct vfio_pci_device *device, void *vaddr)
-{
- return iommu_hva2iova(device->iommu, vaddr);
-}
-
-static inline bool vfio_pci_device_match(struct vfio_pci_device *device,
- u16 vendor_id, u16 device_id)
-{
- return (vendor_id == vfio_pci_config_readw(device, PCI_VENDOR_ID)) &&
- (device_id == vfio_pci_config_readw(device, PCI_DEVICE_ID));
-}
-
-void vfio_pci_driver_probe(struct vfio_pci_device *device);
-void vfio_pci_driver_init(struct vfio_pci_device *device);
-void vfio_pci_driver_remove(struct vfio_pci_device *device);
-int vfio_pci_driver_memcpy(struct vfio_pci_device *device,
- iova_t src, iova_t dst, u64 size);
-void vfio_pci_driver_memcpy_start(struct vfio_pci_device *device,
- iova_t src, iova_t dst, u64 size,
- u64 count);
-int vfio_pci_driver_memcpy_wait(struct vfio_pci_device *device);
-void vfio_pci_driver_send_msi(struct vfio_pci_device *device);
-
#endif /* SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_H */
diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/assert.h b/tools/testing/selftests/vfio/lib/include/libvfio/assert.h
new file mode 100644
index 000000000000..0f68af94a2ca
--- /dev/null
+++ b/tools/testing/selftests/vfio/lib/include/libvfio/assert.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_ASSERT_H
+#define SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_ASSERT_H
+
+#include <stdio.h>
+#include <sys/ioctl.h>
+
+#include "../../../kselftest.h"
+
+#define VFIO_LOG_AND_EXIT(...) do { \
+ fprintf(stderr, " " __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ exit(KSFT_FAIL); \
+} while (0)
+
+#define VFIO_ASSERT_OP(_lhs, _rhs, _op, ...) do { \
+ typeof(_lhs) __lhs = (_lhs); \
+ typeof(_rhs) __rhs = (_rhs); \
+ \
+ if (__lhs _op __rhs) \
+ break; \
+ \
+ fprintf(stderr, "%s:%u: Assertion Failure\n\n", __FILE__, __LINE__); \
+ fprintf(stderr, " Expression: " #_lhs " " #_op " " #_rhs "\n"); \
+ fprintf(stderr, " Observed: %#lx %s %#lx\n", \
+ (u64)__lhs, #_op, (u64)__rhs); \
+ fprintf(stderr, " [errno: %d - %s]\n", errno, strerror(errno)); \
+ VFIO_LOG_AND_EXIT(__VA_ARGS__); \
+} while (0)
+
+#define VFIO_ASSERT_EQ(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, ==, ##__VA_ARGS__)
+#define VFIO_ASSERT_NE(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, !=, ##__VA_ARGS__)
+#define VFIO_ASSERT_LT(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, <, ##__VA_ARGS__)
+#define VFIO_ASSERT_LE(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, <=, ##__VA_ARGS__)
+#define VFIO_ASSERT_GT(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, >, ##__VA_ARGS__)
+#define VFIO_ASSERT_GE(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, >=, ##__VA_ARGS__)
+#define VFIO_ASSERT_TRUE(_a, ...) VFIO_ASSERT_NE(false, (_a), ##__VA_ARGS__)
+#define VFIO_ASSERT_FALSE(_a, ...) VFIO_ASSERT_EQ(false, (_a), ##__VA_ARGS__)
+#define VFIO_ASSERT_NULL(_a, ...) VFIO_ASSERT_EQ(NULL, _a, ##__VA_ARGS__)
+#define VFIO_ASSERT_NOT_NULL(_a, ...) VFIO_ASSERT_NE(NULL, _a, ##__VA_ARGS__)
+
+#define VFIO_FAIL(_fmt, ...) do { \
+ fprintf(stderr, "%s:%u: FAIL\n\n", __FILE__, __LINE__); \
+ VFIO_LOG_AND_EXIT(_fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define ioctl_assert(_fd, _op, _arg) do { \
+ void *__arg = (_arg); \
+ int __ret = ioctl((_fd), (_op), (__arg)); \
+ VFIO_ASSERT_EQ(__ret, 0, "ioctl(%s, %s, %s) returned %d\n", #_fd, #_op, #_arg, __ret); \
+} while (0)
+
+#endif /* SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_ASSERT_H */
diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h b/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
new file mode 100644
index 000000000000..fdb88dc0a5c7
--- /dev/null
+++ b/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_IOMMU_H
+#define SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_IOMMU_H
+
+#include <linux/types.h>
+
+struct iommu_mode {
+ const char *name;
+ const char *container_path;
+ unsigned long iommu_type;
+};
+
+/*
+ * 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.
+ */
+#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__)
+
+typedef u64 iova_t;
+
+#define INVALID_IOVA UINT64_MAX
+
+struct dma_region {
+ struct list_head link;
+ void *vaddr;
+ iova_t iova;
+ u64 size;
+};
+
+struct iommu {
+ const struct iommu_mode *mode;
+ int container_fd;
+ int iommufd;
+ u32 ioas_id;
+ struct list_head dma_regions;
+};
+
+extern const char *default_iommu_mode;
+
+struct iommu *iommu_init(const char *iommu_mode);
+void iommu_cleanup(struct iommu *iommu);
+iova_t iommu_hva2iova(struct iommu *iommu, void *vaddr);
+iova_t __iommu_hva2iova(struct iommu *iommu, void *vaddr);
+void iommu_map(struct iommu *iommu, struct dma_region *region);
+void iommu_unmap(struct iommu *iommu, struct dma_region *region);
+
+#endif /* SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_IOMMU_H */
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
new file mode 100644
index 000000000000..0ef27f95d5f8
--- /dev/null
+++ b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_VFIO_PCI_DEVICE_H
+#define SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_VFIO_PCI_DEVICE_H
+
+#include <fcntl.h>
+#include <string.h>
+#include <linux/vfio.h>
+#include <linux/list.h>
+#include <linux/pci_regs.h>
+#include <sys/ioctl.h>
+
+#include <libvfio/assert.h>
+#include <libvfio/iommu.h>
+#include <libvfio/vfio_pci_driver.h>
+
+#define dev_info(_dev, _fmt, ...) printf("%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)
+#define dev_err(_dev, _fmt, ...) fprintf(stderr, "%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)
+
+struct vfio_pci_bar {
+ struct vfio_region_info info;
+ void *vaddr;
+};
+
+struct vfio_pci_device {
+ const char *bdf;
+ int fd;
+ int group_fd;
+
+ struct iommu *iommu;
+
+ struct vfio_device_info info;
+ struct vfio_region_info config_space;
+ struct vfio_pci_bar bars[PCI_STD_NUM_BARS];
+
+ struct vfio_irq_info msi_info;
+ struct vfio_irq_info msix_info;
+
+ /* eventfds for MSI and MSI-x interrupts */
+ int msi_eventfds[PCI_MSIX_FLAGS_QSIZE + 1];
+
+ struct vfio_pci_driver driver;
+};
+
+const char *vfio_pci_get_cdev_path(const char *bdf);
+
+struct vfio_pci_device *__vfio_pci_device_init(const char *bdf, struct iommu *iommu);
+struct vfio_pci_device *vfio_pci_device_init(const char *bdf, const char *iommu_mode);
+
+void __vfio_pci_device_cleanup(struct vfio_pci_device *device);
+void vfio_pci_device_cleanup(struct vfio_pci_device *device);
+
+void vfio_pci_device_reset(struct vfio_pci_device *device);
+
+static inline void vfio_pci_dma_map(struct vfio_pci_device *device,
+ struct dma_region *region)
+{
+ return iommu_map(device->iommu, region);
+}
+
+static inline void vfio_pci_dma_unmap(struct vfio_pci_device *device,
+ struct dma_region *region)
+{
+ return iommu_unmap(device->iommu, region);
+}
+
+void vfio_pci_config_access(struct vfio_pci_device *device, bool write,
+ size_t config, size_t size, void *data);
+
+#define vfio_pci_config_read(_device, _offset, _type) ({ \
+ _type __data; \
+ vfio_pci_config_access((_device), false, _offset, sizeof(__data), &__data); \
+ __data; \
+})
+
+#define vfio_pci_config_readb(_d, _o) vfio_pci_config_read(_d, _o, u8)
+#define vfio_pci_config_readw(_d, _o) vfio_pci_config_read(_d, _o, u16)
+#define vfio_pci_config_readl(_d, _o) vfio_pci_config_read(_d, _o, u32)
+
+#define vfio_pci_config_write(_device, _offset, _value, _type) do { \
+ _type __data = (_value); \
+ vfio_pci_config_access((_device), true, _offset, sizeof(_type), &__data); \
+} while (0)
+
+#define vfio_pci_config_writeb(_d, _o, _v) vfio_pci_config_write(_d, _o, _v, u8)
+#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_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);
+void vfio_pci_irq_trigger(struct vfio_pci_device *device, u32 index, u32 vector);
+
+static inline void fcntl_set_nonblock(int fd)
+{
+ int r;
+
+ r = fcntl(fd, F_GETFL, 0);
+ VFIO_ASSERT_NE(r, -1, "F_GETFL failed for fd %d\n", fd);
+
+ r = fcntl(fd, F_SETFL, r | O_NONBLOCK);
+ VFIO_ASSERT_NE(r, -1, "F_SETFL O_NONBLOCK failed for fd %d\n", fd);
+}
+
+static inline void vfio_pci_msi_enable(struct vfio_pci_device *device,
+ u32 vector, int count)
+{
+ vfio_pci_irq_enable(device, VFIO_PCI_MSI_IRQ_INDEX, vector, count);
+}
+
+static inline void vfio_pci_msi_disable(struct vfio_pci_device *device)
+{
+ vfio_pci_irq_disable(device, VFIO_PCI_MSI_IRQ_INDEX);
+}
+
+static inline void vfio_pci_msix_enable(struct vfio_pci_device *device,
+ u32 vector, int count)
+{
+ vfio_pci_irq_enable(device, VFIO_PCI_MSIX_IRQ_INDEX, vector, count);
+}
+
+static inline void vfio_pci_msix_disable(struct vfio_pci_device *device)
+{
+ vfio_pci_irq_disable(device, VFIO_PCI_MSIX_IRQ_INDEX);
+}
+
+static inline iova_t __to_iova(struct vfio_pci_device *device, void *vaddr)
+{
+ return __iommu_hva2iova(device->iommu, vaddr);
+}
+
+static inline iova_t to_iova(struct vfio_pci_device *device, void *vaddr)
+{
+ return iommu_hva2iova(device->iommu, vaddr);
+}
+
+static inline bool vfio_pci_device_match(struct vfio_pci_device *device,
+ u16 vendor_id, u16 device_id)
+{
+ return (vendor_id == vfio_pci_config_readw(device, PCI_VENDOR_ID)) &&
+ (device_id == vfio_pci_config_readw(device, PCI_DEVICE_ID));
+}
+
+#endif /* SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_VFIO_PCI_DEVICE_H */
diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_driver.h b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_driver.h
new file mode 100644
index 000000000000..6653e786e98a
--- /dev/null
+++ b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_driver.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_VFIO_PCI_DRIVER_H
+#define SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_VFIO_PCI_DRIVER_H
+
+#include <linux/types.h>
+#include <libvfio/iommu.h>
+
+struct vfio_pci_device;
+
+struct vfio_pci_driver_ops {
+ const char *name;
+
+ /**
+ * @probe() - Check if the driver supports the given device.
+ *
+ * Return: 0 on success, non-0 on failure.
+ */
+ int (*probe)(struct vfio_pci_device *device);
+
+ /**
+ * @init() - Initialize the driver for @device.
+ *
+ * Must be called after device->driver.region has been initialized.
+ */
+ void (*init)(struct vfio_pci_device *device);
+
+ /**
+ * remove() - Deinitialize the driver for @device.
+ */
+ void (*remove)(struct vfio_pci_device *device);
+
+ /**
+ * memcpy_start() - Kick off @count repeated memcpy operations from
+ * [@src, @src + @size) to [@dst, @dst + @size).
+ *
+ * Guarantees:
+ * - The device will attempt DMA reads on [src, src + size).
+ * - The device will attempt DMA writes on [dst, dst + size).
+ * - The device will not generate any interrupts.
+ *
+ * memcpy_start() returns immediately, it does not wait for the
+ * copies to complete.
+ */
+ void (*memcpy_start)(struct vfio_pci_device *device,
+ iova_t src, iova_t dst, u64 size, u64 count);
+
+ /**
+ * memcpy_wait() - Wait until the memcpy operations started by
+ * memcpy_start() have finished.
+ *
+ * Guarantees:
+ * - All in-flight DMAs initiated by memcpy_start() are fully complete
+ * before memcpy_wait() returns.
+ *
+ * Returns non-0 if the driver detects that an error occurred during the
+ * memcpy, 0 otherwise.
+ */
+ int (*memcpy_wait)(struct vfio_pci_device *device);
+
+ /**
+ * send_msi() - Make the device send the MSI device->driver.msi.
+ *
+ * Guarantees:
+ * - The device will send the MSI once.
+ */
+ void (*send_msi)(struct vfio_pci_device *device);
+};
+
+struct vfio_pci_driver {
+ const struct vfio_pci_driver_ops *ops;
+ bool initialized;
+ bool memcpy_in_progress;
+
+ /* Region to be used by the driver (e.g. for in-memory descriptors) */
+ struct dma_region region;
+
+ /* The maximum size that can be passed to memcpy_start(). */
+ u64 max_memcpy_size;
+
+ /* The maximum count that can be passed to memcpy_start(). */
+ u64 max_memcpy_count;
+
+ /* The MSI vector the device will signal in ops->send_msi(). */
+ int msi;
+};
+
+void vfio_pci_driver_probe(struct vfio_pci_device *device);
+void vfio_pci_driver_init(struct vfio_pci_device *device);
+void vfio_pci_driver_remove(struct vfio_pci_device *device);
+int vfio_pci_driver_memcpy(struct vfio_pci_device *device,
+ iova_t src, iova_t dst, u64 size);
+void vfio_pci_driver_memcpy_start(struct vfio_pci_device *device,
+ iova_t src, iova_t dst, u64 size,
+ u64 count);
+int vfio_pci_driver_memcpy_wait(struct vfio_pci_device *device);
+void vfio_pci_driver_send_msi(struct vfio_pci_device *device);
+
+#endif /* SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_VFIO_PCI_DRIVER_H */
diff --git a/tools/testing/selftests/vfio/lib/libvfio.c b/tools/testing/selftests/vfio/lib/libvfio.c
new file mode 100644
index 000000000000..fa5ef796842e
--- /dev/null
+++ b/tools/testing/selftests/vfio/lib/libvfio.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../../../kselftest.h"
+#include <libvfio.h>
+
+static bool is_bdf(const char *str)
+{
+ unsigned int s, b, d, f;
+ int length, count;
+
+ count = sscanf(str, "%4x:%2x:%2x.%2x%n", &s, &b, &d, &f, &length);
+ return count == 4 && length == strlen(str);
+}
+
+static char **vfio_selftests_get_bdfs_cmdline(int *argc, char *argv[], int *nr_bdfs)
+{
+ int i;
+
+ for (i = *argc - 1; i > 0 && is_bdf(argv[i]); i--)
+ continue;
+
+ i++;
+ *nr_bdfs = *argc - i;
+ *argc -= *nr_bdfs;
+
+ return *nr_bdfs ? &argv[i] : NULL;
+}
+
+static char **vfio_selftests_get_bdfs_env(int *argc, char *argv[], int *nr_bdfs)
+{
+ static char *bdf;
+
+ bdf = getenv("VFIO_SELFTESTS_BDF");
+ if (!bdf)
+ return NULL;
+
+ *nr_bdfs = 1;
+ VFIO_ASSERT_TRUE(is_bdf(bdf), "Invalid BDF: %s\n", bdf);
+
+ return &bdf;
+}
+
+char **vfio_selftests_get_bdfs(int *argc, char *argv[], int *nr_bdfs)
+{
+ char **bdfs;
+
+ bdfs = vfio_selftests_get_bdfs_cmdline(argc, argv, nr_bdfs);
+ if (bdfs)
+ return bdfs;
+
+ bdfs = vfio_selftests_get_bdfs_env(argc, argv, nr_bdfs);
+ if (bdfs)
+ return bdfs;
+
+ fprintf(stderr, "Unable to determine which device(s) to use, skipping test.\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "To pass the device address via environment variable:\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " export VFIO_SELFTESTS_BDF=\"segment:bus:device.function\"\n");
+ fprintf(stderr, " %s [options]\n", argv[0]);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "To pass the device address(es) via argv:\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " %s [options] segment:bus:device.function ...\n", argv[0]);
+ fprintf(stderr, "\n");
+ exit(KSFT_SKIP);
+}
+
+const char *vfio_selftests_get_bdf(int *argc, char *argv[])
+{
+ int nr_bdfs;
+
+ return vfio_selftests_get_bdfs(argc, argv, &nr_bdfs)[0];
+}
diff --git a/tools/testing/selftests/vfio/lib/libvfio.mk b/tools/testing/selftests/vfio/lib/libvfio.mk
index 1d53311e2610..6bcd89f7f8ee 100644
--- a/tools/testing/selftests/vfio/lib/libvfio.mk
+++ b/tools/testing/selftests/vfio/lib/libvfio.mk
@@ -3,7 +3,8 @@ ARCH ?= $(SUBARCH)
VFIO_DIR := $(selfdir)/vfio
-LIBVFIO_C := lib/iommu.c
+LIBVFIO_C := lib/libvfio.c
+LIBVFIO_C += lib/iommu.c
LIBVFIO_C += lib/vfio_pci_device.c
LIBVFIO_C += lib/vfio_pci_driver.c
diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
index 909c951eb52f..e5e08b28744d 100644
--- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c
+++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
@@ -388,73 +388,3 @@ void vfio_pci_device_cleanup(struct vfio_pci_device *device)
__vfio_pci_device_cleanup(device);
iommu_cleanup(iommu);
}
-
-static bool is_bdf(const char *str)
-{
- unsigned int s, b, d, f;
- int length, count;
-
- count = sscanf(str, "%4x:%2x:%2x.%2x%n", &s, &b, &d, &f, &length);
- return count == 4 && length == strlen(str);
-}
-
-static char **vfio_selftests_get_bdfs_cmdline(int *argc, char *argv[], int *nr_bdfs)
-{
- int i;
-
- for (i = *argc - 1; i > 0 && is_bdf(argv[i]); i--)
- continue;
-
- i++;
- *nr_bdfs = *argc - i;
- *argc -= *nr_bdfs;
-
- return *nr_bdfs ? &argv[i] : NULL;
-}
-
-static char **vfio_selftests_get_bdfs_env(int *argc, char *argv[], int *nr_bdfs)
-{
- static char *bdf;
-
- bdf = getenv("VFIO_SELFTESTS_BDF");
- if (!bdf)
- return NULL;
-
- *nr_bdfs = 1;
- VFIO_ASSERT_TRUE(is_bdf(bdf), "Invalid BDF: %s\n", bdf);
-
- return &bdf;
-}
-
-char **vfio_selftests_get_bdfs(int *argc, char *argv[], int *nr_bdfs)
-{
- char **bdfs;
-
- bdfs = vfio_selftests_get_bdfs_cmdline(argc, argv, nr_bdfs);
- if (bdfs)
- return bdfs;
-
- bdfs = vfio_selftests_get_bdfs_env(argc, argv, nr_bdfs);
- if (bdfs)
- return bdfs;
-
- fprintf(stderr, "Unable to determine which device(s) to use, skipping test.\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "To pass the device address via environment variable:\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " export VFIO_SELFTESTS_BDF=\"segment:bus:device.function\"\n");
- fprintf(stderr, " %s [options]\n", argv[0]);
- fprintf(stderr, "\n");
- fprintf(stderr, "To pass the device address(es) via argv:\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " %s [options] segment:bus:device.function ...\n", argv[0]);
- fprintf(stderr, "\n");
- exit(KSFT_SKIP);
-}
-
-const char *vfio_selftests_get_bdf(int *argc, char *argv[])
-{
- int nr_bdfs;
-
- return vfio_selftests_get_bdfs(argc, argv, &nr_bdfs)[0];
-}
--
2.51.0.710.ga91ca5db03-goog
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 12/12] vfio: selftests: Add vfio_pci_device_init_perf_test
2025-10-08 23:25 [PATCH 00/12] vfio: selftests: Support for multi-device tests David Matlack
` (10 preceding siblings ...)
2025-10-08 23:25 ` [PATCH 11/12] vfio: selftests: Split libvfio.h into separate header files David Matlack
@ 2025-10-08 23:25 ` David Matlack
2025-10-16 16:12 ` David Matlack
2025-11-05 19:06 ` [PATCH 00/12] vfio: selftests: Support for multi-device tests Alex Williamson
12 siblings, 1 reply; 25+ messages in thread
From: David Matlack @ 2025-10-08 23:25 UTC (permalink / raw)
To: Alex Williamson
Cc: David Matlack, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma,
Aaron Lewis
Add a new VFIO selftest for measuring the time it takes to run
vfio_pci_device_init() in parallel for one or more devices.
This test serves as manual regression test for the performance
improvement of commit e908f58b6beb ("vfio/pci: Separate SR-IOV VF
dev_set"). For example, when running this test with 64 VFs under the
same PF:
Before:
$ ./vfio_pci_device_init_perf_test -r vfio_pci_device_init_perf_test.iommufd.init 0000:1a:00.0 0000:1a:00.1 ...
...
Wall time: 6.653234463s
Min init time (per device): 0.101215344s
Max init time (per device): 6.652755941s
Avg init time (per device): 3.377609608s
After:
$ ./vfio_pci_device_init_perf_test -r vfio_pci_device_init_perf_test.iommufd.init 0000:1a:00.0 0000:1a:00.1 ...
...
Wall time: 0.122978332s
Min init time (per device): 0.108121915s
Max init time (per device): 0.122762761s
Avg init time (per device): 0.113816748s
This test does not make any assertions about performance, since any such
assertion is likely to be flaky due to system differences and random
noise. However this test can be fed into automation to detect
regressions, and can be used by developers in the future to measure
performance optimizations.
Suggested-by: Aaron Lewis <aaronlewis@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/vfio/Makefile | 3 +
.../vfio/vfio_pci_device_init_perf_test.c | 163 ++++++++++++++++++
2 files changed, 166 insertions(+)
create mode 100644 tools/testing/selftests/vfio/vfio_pci_device_init_perf_test.c
diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile
index 324ba0175a33..7b69375ee6ea 100644
--- a/tools/testing/selftests/vfio/Makefile
+++ b/tools/testing/selftests/vfio/Makefile
@@ -2,6 +2,7 @@ CFLAGS = $(KHDR_INCLUDES)
TEST_GEN_PROGS += vfio_dma_mapping_test
TEST_GEN_PROGS += vfio_iommufd_setup_test
TEST_GEN_PROGS += vfio_pci_device_test
+TEST_GEN_PROGS += vfio_pci_device_init_perf_test
TEST_GEN_PROGS += vfio_pci_driver_test
TEST_PROGS_EXTENDED := run.sh
include ../lib.mk
@@ -11,6 +12,8 @@ CFLAGS += -I$(top_srcdir)/tools/include
CFLAGS += -MD
CFLAGS += $(EXTRA_CFLAGS)
+LDFLAGS += -pthread
+
$(TEST_GEN_PROGS): %: %.o $(LIBVFIO_O)
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< $(LIBVFIO_O) $(LDLIBS) -o $@
diff --git a/tools/testing/selftests/vfio/vfio_pci_device_init_perf_test.c b/tools/testing/selftests/vfio/vfio_pci_device_init_perf_test.c
new file mode 100644
index 000000000000..b09005c0f27f
--- /dev/null
+++ b/tools/testing/selftests/vfio/vfio_pci_device_init_perf_test.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <pthread.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <linux/sizes.h>
+#include <linux/vfio.h>
+
+#include <libvfio.h>
+
+#include "../kselftest_harness.h"
+
+static char **device_bdfs;
+static int nr_devices;
+
+struct thread_args {
+ struct iommu *iommu;
+ int device_index;
+ struct timespec start;
+ struct timespec end;
+ pthread_barrier_t *barrier;
+};
+
+FIXTURE(vfio_pci_device_init_perf_test) {
+ pthread_t *threads;
+ pthread_barrier_t barrier;
+ struct thread_args *thread_args;
+ struct iommu *iommu;
+};
+
+FIXTURE_VARIANT(vfio_pci_device_init_perf_test) {
+ const char *iommu_mode;
+};
+
+#define FIXTURE_VARIANT_ADD_IOMMU_MODE(_iommu_mode) \
+FIXTURE_VARIANT_ADD(vfio_pci_device_init_perf_test, _iommu_mode) { \
+ .iommu_mode = #_iommu_mode, \
+}
+
+FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES();
+
+FIXTURE_SETUP(vfio_pci_device_init_perf_test)
+{
+ int i;
+
+ self->iommu = iommu_init(variant->iommu_mode);
+ self->threads = calloc(nr_devices, sizeof(self->threads[0]));
+ self->thread_args = calloc(nr_devices, sizeof(self->thread_args[0]));
+
+ pthread_barrier_init(&self->barrier, NULL, nr_devices);
+
+ for (i = 0; i < nr_devices; i++) {
+ self->thread_args[i].iommu = self->iommu;
+ self->thread_args[i].barrier = &self->barrier;
+ self->thread_args[i].device_index = i;
+ }
+}
+
+FIXTURE_TEARDOWN(vfio_pci_device_init_perf_test)
+{
+ iommu_cleanup(self->iommu);
+ free(self->threads);
+ free(self->thread_args);
+}
+
+static s64 to_ns(struct timespec ts)
+{
+ return (s64)ts.tv_nsec + 1000000000LL * (s64)ts.tv_sec;
+}
+
+static struct timespec to_timespec(s64 ns)
+{
+ struct timespec ts = {
+ .tv_nsec = ns % 1000000000LL,
+ .tv_sec = ns / 1000000000LL,
+ };
+
+ return ts;
+}
+
+static struct timespec timespec_sub(struct timespec a, struct timespec b)
+{
+ return to_timespec(to_ns(a) - to_ns(b));
+}
+
+static struct timespec timespec_min(struct timespec a, struct timespec b)
+{
+ return to_ns(a) < to_ns(b) ? a : b;
+}
+
+static struct timespec timespec_max(struct timespec a, struct timespec b)
+{
+ return to_ns(a) > to_ns(b) ? a : b;
+}
+
+static void *thread_main(void *__args)
+{
+ struct thread_args *args = __args;
+ struct vfio_pci_device *device;
+
+ pthread_barrier_wait(args->barrier);
+
+ clock_gettime(CLOCK_MONOTONIC, &args->start);
+ device = __vfio_pci_device_init(device_bdfs[args->device_index], args->iommu);
+ clock_gettime(CLOCK_MONOTONIC, &args->end);
+
+ pthread_barrier_wait(args->barrier);
+
+ __vfio_pci_device_cleanup(device);
+ return NULL;
+}
+
+TEST_F(vfio_pci_device_init_perf_test, init)
+{
+ struct timespec start = to_timespec(INT64_MAX), end = {};
+ struct timespec min = to_timespec(INT64_MAX);
+ struct timespec max = {};
+ struct timespec avg = {};
+ struct timespec wall_time;
+ s64 thread_ns = 0;
+ int i;
+
+ for (i = 0; i < nr_devices; i++) {
+ pthread_create(&self->threads[i], NULL, thread_main,
+ &self->thread_args[i]);
+ }
+
+ for (i = 0; i < nr_devices; i++) {
+ struct thread_args *args = &self->thread_args[i];
+ struct timespec init_time;
+
+ pthread_join(self->threads[i], NULL);
+
+ start = timespec_min(start, args->start);
+ end = timespec_max(end, args->end);
+
+ init_time = timespec_sub(args->end, args->start);
+ min = timespec_min(min, init_time);
+ max = timespec_max(max, init_time);
+ thread_ns += to_ns(init_time);
+ }
+
+ avg = to_timespec(thread_ns / nr_devices);
+ wall_time = timespec_sub(end, start);
+
+ printf("Wall time: %lu.%09lus\n",
+ wall_time.tv_sec, wall_time.tv_nsec);
+ printf("Min init time (per device): %lu.%09lus\n",
+ min.tv_sec, min.tv_nsec);
+ printf("Max init time (per device): %lu.%09lus\n",
+ max.tv_sec, max.tv_nsec);
+ printf("Avg init time (per device): %lu.%09lus\n",
+ avg.tv_sec, avg.tv_nsec);
+}
+
+int main(int argc, char *argv[])
+{
+ device_bdfs = vfio_selftests_get_bdfs(&argc, argv, &nr_devices);
+
+ printf("Number of devices: %d\n", nr_devices);
+
+ return test_harness_run(argc, argv);
+}
--
2.51.0.710.ga91ca5db03-goog
^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 12/12] vfio: selftests: Add vfio_pci_device_init_perf_test
2025-10-08 23:25 ` [PATCH 12/12] vfio: selftests: Add vfio_pci_device_init_perf_test David Matlack
@ 2025-10-16 16:12 ` David Matlack
0 siblings, 0 replies; 25+ messages in thread
From: David Matlack @ 2025-10-16 16:12 UTC (permalink / raw)
To: Alex Williamson
Cc: Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma, Aaron Lewis
On Wed, Oct 8, 2025 at 4:26 PM David Matlack <dmatlack@google.com> wrote:
>
> This test serves as manual regression test for the performance
> improvement of commit e908f58b6beb ("vfio/pci: Separate SR-IOV VF
> dev_set").
>
> This test does not make any assertions about performance, since any such
> assertion is likely to be flaky due to system differences and random
> noise. However this test can be fed into automation to detect
> regressions, and can be used by developers in the future to measure
> performance optimizations.
Perhaps this test can compare the time it takes to initialize a single
device against the time it takes to initialize all devices provided to
the test, and assert that they are within some range of each other. In
other words, assert that initializing N devices does not scale with
the number of devices. To avoid false negatives, the test can collect
each measurement N times and discard the outliers (e.g. only look at
the median or min time).
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 05/12] vfio: selftests: Support multiple devices in the same container/iommufd
2025-10-08 23:25 ` [PATCH 05/12] vfio: selftests: Support multiple devices in the same container/iommufd David Matlack
@ 2025-10-27 16:21 ` David Matlack
2025-11-07 3:37 ` Josh Hilke
0 siblings, 1 reply; 25+ messages in thread
From: David Matlack @ 2025-10-27 16:21 UTC (permalink / raw)
To: Alex Williamson; +Cc: Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
On Wed, Oct 8, 2025 at 4:26 PM David Matlack <dmatlack@google.com> wrote:
> For backwards compatibility with existing tests, and to keep
> single-device tests simple, vfio_pci_device_init() and
> vfio_pci_device_cleanup() remain unchanged.
>
> Multi-devices tests can now put multiple devices in the same
> container/iommufd like so:
>
> iommu = iommu_init(iommu_mode);
>
> device1 = __vfio_pci_device_init(bdf1, iommu);
> device2 = __vfio_pci_device_init(bdf2, iommu);
> device3 = __vfio_pci_device_init(bdf3, iommu);
After using this code internally for a few months, I think it would be
better to just require all tests to call iommu_init() and then
vfio_pci_device_init(). It is not really that much new code to add to
tests, and that will leave the function name __vfio_pci_device_init()
available for other use-cases (like [1]).
[1] https://lore.kernel.org/kvm/20251018000713.677779-20-vipinsh@google.com/
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 00/12] vfio: selftests: Support for multi-device tests
2025-10-08 23:25 [PATCH 00/12] vfio: selftests: Support for multi-device tests David Matlack
` (11 preceding siblings ...)
2025-10-08 23:25 ` [PATCH 12/12] vfio: selftests: Add vfio_pci_device_init_perf_test David Matlack
@ 2025-11-05 19:06 ` Alex Williamson
2025-11-05 21:03 ` David Matlack
12 siblings, 1 reply; 25+ messages in thread
From: Alex Williamson @ 2025-11-05 19:06 UTC (permalink / raw)
To: David Matlack
Cc: Alex Williamson, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
On Wed, 8 Oct 2025 23:25:19 +0000
David Matlack <dmatlack@google.com> wrote:
> This series adds support for tests that use multiple devices, and adds
> one new test, vfio_pci_device_init_perf_test, which measures parallel
> device initialization time to demonstrate the improvement from commit
> e908f58b6beb ("vfio/pci: Separate SR-IOV VF dev_set").
>
> This series also breaks apart the monolithic vfio_util.h and
> vfio_pci_device.c into separate files, to account for all the new code.
> This required some code motion so the diffstat looks large. The final
> layout is more granular and provides a better separation of the IOMMU
> code from the device code.
Hi David,
This series doesn't apply to mainline currently and I see you have some
self-comments that suggests this is still a WIP, so I'll drop it and
look for a v2. I believe
https://lore.kernel.org/kvm/20250912222525.2515416-2-dmatlack@google.com/
is still in play though and does apply. Thanks,
Alex
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 00/12] vfio: selftests: Support for multi-device tests
2025-11-05 19:06 ` [PATCH 00/12] vfio: selftests: Support for multi-device tests Alex Williamson
@ 2025-11-05 21:03 ` David Matlack
2025-11-05 21:54 ` Alex Williamson
0 siblings, 1 reply; 25+ messages in thread
From: David Matlack @ 2025-11-05 21:03 UTC (permalink / raw)
To: Alex Williamson
Cc: Alex Williamson, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
On Wed, Nov 5, 2025 at 11:06 AM Alex Williamson <alex@shazbot.org> wrote:
>
> On Wed, 8 Oct 2025 23:25:19 +0000
> David Matlack <dmatlack@google.com> wrote:
>
> > This series adds support for tests that use multiple devices, and adds
> > one new test, vfio_pci_device_init_perf_test, which measures parallel
> > device initialization time to demonstrate the improvement from commit
> > e908f58b6beb ("vfio/pci: Separate SR-IOV VF dev_set").
> >
> > This series also breaks apart the monolithic vfio_util.h and
> > vfio_pci_device.c into separate files, to account for all the new code.
> > This required some code motion so the diffstat looks large. The final
> > layout is more granular and provides a better separation of the IOMMU
> > code from the device code.
>
> Hi David,
>
> This series doesn't apply to mainline currently and I see you have some
> self-comments that suggests this is still a WIP, so I'll drop it and
> look for a v2.
Yes, I am going to send a v2 to address my self-comments. I'm also
looking at getting reviews of this series from some fellow Googlers on
the mailing list. Feel free to hold off for now.
> I believe
> https://lore.kernel.org/kvm/20250912222525.2515416-2-dmatlack@google.com/
> is still in play though and does apply. Thanks,
This series will need another revision as well to address Sean's
feedback, and I think can be merged via KVM maintainers.
That being said,
https://lore.kernel.org/kvm/20250922224857.2528737-1-dmatlack@google.com/
should apply and be ready to merge. It is a small prep patch for the
KVM selftests integration.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 00/12] vfio: selftests: Support for multi-device tests
2025-11-05 21:03 ` David Matlack
@ 2025-11-05 21:54 ` Alex Williamson
0 siblings, 0 replies; 25+ messages in thread
From: Alex Williamson @ 2025-11-05 21:54 UTC (permalink / raw)
To: David Matlack
Cc: Alex Williamson, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
On Wed, 5 Nov 2025 13:03:51 -0800
David Matlack <dmatlack@google.com> wrote:
> On Wed, Nov 5, 2025 at 11:06 AM Alex Williamson <alex@shazbot.org> wrote:
> >
> > On Wed, 8 Oct 2025 23:25:19 +0000
> > David Matlack <dmatlack@google.com> wrote:
> >
> > > This series adds support for tests that use multiple devices, and adds
> > > one new test, vfio_pci_device_init_perf_test, which measures parallel
> > > device initialization time to demonstrate the improvement from commit
> > > e908f58b6beb ("vfio/pci: Separate SR-IOV VF dev_set").
> > >
> > > This series also breaks apart the monolithic vfio_util.h and
> > > vfio_pci_device.c into separate files, to account for all the new code.
> > > This required some code motion so the diffstat looks large. The final
> > > layout is more granular and provides a better separation of the IOMMU
> > > code from the device code.
> >
> > Hi David,
> >
> > This series doesn't apply to mainline currently and I see you have some
> > self-comments that suggests this is still a WIP, so I'll drop it and
> > look for a v2.
>
> Yes, I am going to send a v2 to address my self-comments. I'm also
> looking at getting reviews of this series from some fellow Googlers on
> the mailing list. Feel free to hold off for now.
>
> > I believe
> > https://lore.kernel.org/kvm/20250912222525.2515416-2-dmatlack@google.com/
> > is still in play though and does apply. Thanks,
>
> This series will need another revision as well to address Sean's
> feedback, and I think can be merged via KVM maintainers.
>
> That being said,
> https://lore.kernel.org/kvm/20250922224857.2528737-1-dmatlack@google.com/
> should apply and be ready to merge. It is a small prep patch for the
> KVM selftests integration.
Oops, yes, that's the one I meant to reference. It links to the prior
one and I grabbed the wrong link from my local branch. Thanks for the
confirmation.
Alex
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 05/12] vfio: selftests: Support multiple devices in the same container/iommufd
2025-10-27 16:21 ` David Matlack
@ 2025-11-07 3:37 ` Josh Hilke
0 siblings, 0 replies; 25+ messages in thread
From: Josh Hilke @ 2025-11-07 3:37 UTC (permalink / raw)
To: David Matlack; +Cc: Alex Williamson, Jason Gunthorpe, kvm, Vipin Sharma
On Mon, Oct 27, 2025 at 09:21:57AM -0700, David Matlack wrote:
> On Wed, Oct 8, 2025 at 4:26 PM David Matlack <dmatlack@google.com> wrote:
>
> > For backwards compatibility with existing tests, and to keep
> > single-device tests simple, vfio_pci_device_init() and
> > vfio_pci_device_cleanup() remain unchanged.
> >
> > Multi-devices tests can now put multiple devices in the same
> > container/iommufd like so:
> >
> > iommu = iommu_init(iommu_mode);
> >
> > device1 = __vfio_pci_device_init(bdf1, iommu);
> > device2 = __vfio_pci_device_init(bdf2, iommu);
> > device3 = __vfio_pci_device_init(bdf3, iommu);
>
> After using this code internally for a few months, I think it would be
> better to just require all tests to call iommu_init() and then
> vfio_pci_device_init(). It is not really that much new code to add to
> tests, and that will leave the function name __vfio_pci_device_init()
> available for other use-cases (like [1]).
>
> [1] https://lore.kernel.org/kvm/20251018000713.677779-20-vipinsh@google.com/
I'm fine with that. I see what you're saying regarding [1].
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 01/12] vfio: selftests: Split run.sh into separate scripts
2025-10-08 23:25 ` [PATCH 01/12] vfio: selftests: Split run.sh into separate scripts David Matlack
@ 2025-11-10 3:21 ` Raghavendra Rao Ananta
2025-11-10 18:19 ` David Matlack
0 siblings, 1 reply; 25+ messages in thread
From: Raghavendra Rao Ananta @ 2025-11-10 3:21 UTC (permalink / raw)
To: David Matlack
Cc: Alex Williamson, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
On Thu, Oct 9, 2025 at 4:56 AM David Matlack <dmatlack@google.com> wrote:
>
> Split run.sh into separate scripts (setup.sh, run.sh, cleanup.sh) to
> enable multi-device testing, and prepare for VFIO selftests
> automatically detecting which devices to use for testing by storing
> device metadata on the filesystem.
>
> - setup.sh takes one or more BDFs as arguments and sets up each device.
> Metadata about each device is stored on the filesystem in the
> directory:
>
> ${TMPDIR:-/tmp}/vfio-selftests-devices
>
> Within this directory is a directory for each BDF, and then files in
> those directories that cleanup.sh uses to cleanup the device.
>
> - run.sh runs a selftest by passing it the BDFs of all set up devices.
>
> - cleanup.sh takes zero or more BDFs as arguments and cleans up each
> device. If no BDFs are provided, it cleans up all devices.
>
> This split enables multi-device testing by allowing multiple BDFs to be
> set up and passed into tests:
>
> For example:
>
> $ tools/testing/selftests/vfio/scripts/setup.sh <BDF1> <BDF2>
> $ tools/testing/selftests/vfio/scripts/setup.sh <BDF3>
> $ tools/testing/selftests/vfio/scripts/run.sh echo
> <BDF1> <BDF2> <BDF3>
> $ tools/testing/selftests/vfio/scripts/cleanup.sh
>
> If the future, VFIO selftests can automatically detect set up devices by
nit: s/If/In
> +function cleanup_devices() {
> + local device_bdf
> + local device_dir
> +
> + for device_bdf in "$@"; do
> + device_dir=${DEVICES_DIR}/${device_bdf}
> +
> + if [ -f ${device_dir}/vfio-pci ]; then
> + unbind ${device_bdf} vfio-pci
> + fi
> +
> + if [ -f ${device_dir}/driver_override ]; then
> + clear_driver_override ${device_bdf}
> + fi
> +
> + if [ -f ${device_dir}/driver ]; then
> + bind ${device_bdf} $(cat ${device_dir}/driver)
> + fi
> +
> + if [ -f ${device_dir}/sriov_numvfs ]; then
> + set_sriov_numvfs ${device_bdf} $(cat ${device_dir}/sriov_numvfs)
> + fi
> +
> + rm -rf ${device_dir}
> + done
> +
> + rm -rf ${DEVICES_DIR}
Since the cleanup.sh can potentially be run against a single device,
we should probably check if no devices exist under ${DEVICES_DIR}
before removing the entire dir.
> +}
> +
> +function main() {
> + if [ $# = 0 ]; then
> + cleanup_devices $(ls ${DEVICES_DIR})
> + else
> + cleanup_devices "$@"
> + fi
> +}
> +
> +main "$@"
> diff --git a/tools/testing/selftests/vfio/scripts/lib.sh b/tools/testing/selftests/vfio/scripts/lib.sh
> new file mode 100755
> index 000000000000..9f05f29c7b86
> --- /dev/null
> +++ b/tools/testing/selftests/vfio/scripts/lib.sh
> @@ -0,0 +1,42 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +
> +readonly DEVICES_DIR="${TMPDIR:-/tmp}/vfio-selftests-devices"
> +
> +function write_to() {
> + # Unfortunately set -x does not show redirects so use echo to manually
> + # tell the user what commands are being run.
> + echo "+ echo \"${2}\" > ${1}"
> + echo "${2}" > ${1}
> +}
> +
> +function get_driver() {
> + if [ -L /sys/bus/pci/devices/${1}/driver ]; then
> + basename $(readlink -m /sys/bus/pci/devices/${1}/driver)
> + fi
> +}
> +
> +function bind() {
> + write_to /sys/bus/pci/drivers/${2}/bind ${1}
> +}
Since these scripts reside within the selftests/vfio/ dir, and most of
these functions target PCI aspects, should we hardcode `vfio-pci` as
the driver instead of passing the arg around? This is a general
question/suggestion for the patch. We can even rename it to
<op>_vfio_pci() (bind_vfio_pci() for example) for better clarity.
> +
> +function unbind() {
> + write_to /sys/bus/pci/drivers/${2}/unbind ${1}
> +}
> +
> +function set_sriov_numvfs() {
> + write_to /sys/bus/pci/devices/${1}/sriov_numvfs ${2}
> +}
> +
Similar to get_sriov_numvfs(), shall we check the existence of the
'sriov_numvfs' first? In the current workflow, we indirectly check for
the file using get_sriov_numvfs() or look for 'sriov_numvfs' in the
${device_bdf}. However, an independent check would be cleaner and
safer (for any future references). WDYT?
> +function get_sriov_numvfs() {
> + if [ -f /sys/bus/pci/devices/${1}/sriov_numvfs ]; then
> + cat /sys/bus/pci/devices/${1}/sriov_numvfs
> + fi
> +}
> +
> +function main() {
> + local device_bdf
> + local device_dir
> + local numvfs
> + local driver
> +
> + if [ $# = 0 ]; then
> + echo "usage: $0 segment:bus:device.function ..." >&2
> + exit 1
> + fi
> +
> + for device_bdf in "$@"; do
> + test -d /sys/bus/pci/devices/${device_bdf}
> +
> + device_dir=${DEVICES_DIR}/${device_bdf}
> + if [ -d "${device_dir}" ]; then
> + echo "${device_bdf} has already been set up, exiting."
> + exit 0
> + fi
> +
> + mkdir -p ${device_dir}
> +
> + numvfs=$(get_sriov_numvfs ${device_bdf})
> + if [ "${numvfs}" ]; then
> + set_sriov_numvfs ${device_bdf} 0
> + echo ${numvfs} > ${device_dir}/sriov_numvfs
> + fi
> +
> + driver=$(get_driver ${device_bdf})
> + if [ "${driver}" ]; then
> + unbind ${device_bdf} ${driver}
> + echo ${driver} > ${device_dir}/driver
Sorry, what is the purpose of writing the driver's name to the
"driver" file? Isn't "unbind" sufficient?
> + fi
> +
Since vfio-pci can be built as a module that may not be loaded yet (or
even disabled), do you think it's worth checking before binding the
device to the driver? Of course, these operations would fail, but
would it be better if we informed users why?
> + set_driver_override ${device_bdf} vfio-pci
> + touch ${device_dir}/driver_override
> +
> + bind ${device_bdf} vfio-pci
> + touch ${device_dir}/vfio-pci
> + done
> +}
> +
> +main "$@"
> --
Thank you.
Raghavendra
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 02/12] vfio: selftests: Allow passing multiple BDFs on the command line
2025-10-08 23:25 ` [PATCH 02/12] vfio: selftests: Allow passing multiple BDFs on the command line David Matlack
@ 2025-11-10 3:45 ` Raghavendra Rao Ananta
2025-11-10 18:31 ` David Matlack
0 siblings, 1 reply; 25+ messages in thread
From: Raghavendra Rao Ananta @ 2025-11-10 3:45 UTC (permalink / raw)
To: David Matlack
Cc: Alex Williamson, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
On Thu, Oct 9, 2025 at 4:56 AM David Matlack <dmatlack@google.com> wrote:
> -const char *vfio_selftests_get_bdf(int *argc, char *argv[])
> +static char **vfio_selftests_get_bdfs_cmdline(int *argc, char *argv[], int *nr_bdfs)
> {
> - char *bdf;
> + int i;
> +
> + for (i = *argc - 1; i > 0 && is_bdf(argv[i]); i--)
> + continue;
> +
> + i++;
> + *nr_bdfs = *argc - i;
> + *argc -= *nr_bdfs;
Just curious, why update 'argc' (I know we had this before as well)?
> +
> + return *nr_bdfs ? &argv[i] : NULL;
> +}
>
> - if (*argc > 1 && is_bdf(argv[*argc - 1]))
> - return argv[--(*argc)];
> +static char **vfio_selftests_get_bdfs_env(int *argc, char *argv[], int *nr_bdfs)
> +{
> + static char *bdf;
>
> bdf = getenv("VFIO_SELFTESTS_BDF");
> - if (bdf) {
> - VFIO_ASSERT_TRUE(is_bdf(bdf), "Invalid BDF: %s\n", bdf);
> - return bdf;
> - }
> + if (!bdf)
> + return NULL;
> +
> + *nr_bdfs = 1;
> + VFIO_ASSERT_TRUE(is_bdf(bdf), "Invalid BDF: %s\n", bdf);
> +
> + return &bdf;
> +}
nit: Since vfio_selftests_get_bdfs_env() still returns a single BDF,
perhaps add a comment, as it contradicts the plurality in the
function's name?
Thank you.
Raghavendra
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 07/12] vfio: selftests: Prefix logs with device BDF where relevant
2025-10-08 23:25 ` [PATCH 07/12] vfio: selftests: Prefix logs with device BDF where relevant David Matlack
@ 2025-11-10 4:54 ` Raghavendra Rao Ananta
2025-11-10 18:28 ` David Matlack
0 siblings, 1 reply; 25+ messages in thread
From: Raghavendra Rao Ananta @ 2025-11-10 4:54 UTC (permalink / raw)
To: David Matlack
Cc: Alex Williamson, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
On Thu, Oct 9, 2025 at 4:56 AM David Matlack <dmatlack@google.com> wrote:
>
> Prefix log messages with the device's BDF where relevant. This will help
> understanding VFIO selftests logs when tests are run with multiple
> devices.
>
> Signed-off-by: David Matlack <dmatlack@google.com>
> ---
> .../selftests/vfio/lib/drivers/dsa/dsa.c | 34 +++++++++----------
> .../selftests/vfio/lib/drivers/ioat/ioat.c | 16 ++++-----
> .../selftests/vfio/lib/include/vfio_util.h | 4 +++
> .../selftests/vfio/lib/vfio_pci_device.c | 1 +
> 4 files changed, 30 insertions(+), 25 deletions(-)
>
> diff --git a/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c b/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c
> index 0ca2cbc2a316..8d667be80229 100644
> --- a/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c
> +++ b/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c
> @@ -70,7 +70,7 @@ static int dsa_probe(struct vfio_pci_device *device)
> return -EINVAL;
>
> if (dsa_int_handle_request_required(device)) {
> - printf("Device requires requesting interrupt handles\n");
> + dev_info(device, "Device requires requesting interrupt handles\n");
> return -EINVAL;
> }
>
> @@ -91,23 +91,23 @@ static void dsa_check_sw_err(struct vfio_pci_device *device)
> return;
> }
>
> - fprintf(stderr, "SWERR: 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n",
> + dev_err(device, "SWERR: 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n",
> err.bits[0], err.bits[1], err.bits[2], err.bits[3]);
>
> - fprintf(stderr, " valid: 0x%x\n", err.valid);
> - fprintf(stderr, " overflow: 0x%x\n", err.overflow);
> - fprintf(stderr, " desc_valid: 0x%x\n", err.desc_valid);
> - fprintf(stderr, " wq_idx_valid: 0x%x\n", err.wq_idx_valid);
> - fprintf(stderr, " batch: 0x%x\n", err.batch);
> - fprintf(stderr, " fault_rw: 0x%x\n", err.fault_rw);
> - fprintf(stderr, " priv: 0x%x\n", err.priv);
> - fprintf(stderr, " error: 0x%x\n", err.error);
> - fprintf(stderr, " wq_idx: 0x%x\n", err.wq_idx);
> - fprintf(stderr, " operation: 0x%x\n", err.operation);
> - fprintf(stderr, " pasid: 0x%x\n", err.pasid);
> - fprintf(stderr, " batch_idx: 0x%x\n", err.batch_idx);
> - fprintf(stderr, " invalid_flags: 0x%x\n", err.invalid_flags);
> - fprintf(stderr, " fault_addr: 0x%lx\n", err.fault_addr);
> + dev_err(device, " valid: 0x%x\n", err.valid);
> + dev_err(device, " overflow: 0x%x\n", err.overflow);
> + dev_err(device, " desc_valid: 0x%x\n", err.desc_valid);
> + dev_err(device, " wq_idx_valid: 0x%x\n", err.wq_idx_valid);
> + dev_err(device, " batch: 0x%x\n", err.batch);
> + dev_err(device, " fault_rw: 0x%x\n", err.fault_rw);
> + dev_err(device, " priv: 0x%x\n", err.priv);
> + dev_err(device, " error: 0x%x\n", err.error);
> + dev_err(device, " wq_idx: 0x%x\n", err.wq_idx);
> + dev_err(device, " operation: 0x%x\n", err.operation);
> + dev_err(device, " pasid: 0x%x\n", err.pasid);
> + dev_err(device, " batch_idx: 0x%x\n", err.batch_idx);
> + dev_err(device, " invalid_flags: 0x%x\n", err.invalid_flags);
> + dev_err(device, " fault_addr: 0x%lx\n", err.fault_addr);
>
> VFIO_FAIL("Software Error Detected!\n");
> }
> @@ -256,7 +256,7 @@ static int dsa_completion_wait(struct vfio_pci_device *device,
> if (status == DSA_COMP_SUCCESS)
> return 0;
>
> - printf("Error detected during memcpy operation: 0x%x\n", status);
> + dev_info(device, "Error detected during memcpy operation: 0x%x\n", status);
> return -1;
> }
>
> diff --git a/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c b/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c
> index c3b91d9b1f59..e04dce1d544c 100644
> --- a/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c
> +++ b/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c
> @@ -51,7 +51,7 @@ static int ioat_probe(struct vfio_pci_device *device)
> r = 0;
> break;
> default:
> - printf("ioat: Unsupported version: 0x%x\n", version);
> + dev_info(device, "ioat: Unsupported version: 0x%x\n", version);
> r = -EINVAL;
> }
> return r;
> @@ -135,13 +135,13 @@ static void ioat_handle_error(struct vfio_pci_device *device)
> {
> void *registers = ioat_channel_registers(device);
>
> - printf("Error detected during memcpy operation!\n"
> - " CHANERR: 0x%x\n"
> - " CHANERR_INT: 0x%x\n"
> - " DMAUNCERRSTS: 0x%x\n",
> - readl(registers + IOAT_CHANERR_OFFSET),
> - vfio_pci_config_readl(device, IOAT_PCI_CHANERR_INT_OFFSET),
> - vfio_pci_config_readl(device, IOAT_PCI_DMAUNCERRSTS_OFFSET));
> + dev_info(device, "Error detected during memcpy operation!\n"
> + " CHANERR: 0x%x\n"
> + " CHANERR_INT: 0x%x\n"
> + " DMAUNCERRSTS: 0x%x\n",
> + readl(registers + IOAT_CHANERR_OFFSET),
> + vfio_pci_config_readl(device, IOAT_PCI_CHANERR_INT_OFFSET),
> + vfio_pci_config_readl(device, IOAT_PCI_DMAUNCERRSTS_OFFSET));
>
> ioat_reset(device);
> }
> diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h
> index 8a01bcaa3ee8..b7175d4c2132 100644
> --- a/tools/testing/selftests/vfio/lib/include/vfio_util.h
> +++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h
> @@ -47,6 +47,9 @@
> VFIO_LOG_AND_EXIT(_fmt, ##__VA_ARGS__); \
> } while (0)
>
> +#define dev_info(_dev, _fmt, ...) printf("%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)
> +#define dev_err(_dev, _fmt, ...) fprintf(stderr, "%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)
> +
nit: For all the dev_info() replacements in this patch, the messages
sound like something went bad/wrong. Shouldn't they be dev_err()
instead, or were you just aiming for a 1:1 conversion?
Thank you.
Raghavendra
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 01/12] vfio: selftests: Split run.sh into separate scripts
2025-11-10 3:21 ` Raghavendra Rao Ananta
@ 2025-11-10 18:19 ` David Matlack
0 siblings, 0 replies; 25+ messages in thread
From: David Matlack @ 2025-11-10 18:19 UTC (permalink / raw)
To: Raghavendra Rao Ananta
Cc: Alex Williamson, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
On 2025-11-10 08:51 AM, Raghavendra Rao Ananta wrote:
> On Thu, Oct 9, 2025 at 4:56 AM David Matlack <dmatlack@google.com> wrote:
> >
> > If the future, VFIO selftests can automatically detect set up devices by
> nit: s/If/In
Ack
> > + rm -rf ${DEVICES_DIR}
> Since the cleanup.sh can potentially be run against a single device,
> we should probably check if no devices exist under ${DEVICES_DIR}
> before removing the entire dir.
Oof, good catch. Will fix in v2.
> > +function bind() {
> > + write_to /sys/bus/pci/drivers/${2}/bind ${1}
> > +}
> Since these scripts reside within the selftests/vfio/ dir, and most of
> these functions target PCI aspects, should we hardcode `vfio-pci` as
> the driver instead of passing the arg around? This is a general
> question/suggestion for the patch. We can even rename it to
> <op>_vfio_pci() (bind_vfio_pci() for example) for better clarity.
This function is also used to bind the device back to whatever driver it
was originally bound to in cleanup.sh. So "${2}" is not always
"vfio-pci".
> > +function set_sriov_numvfs() {
> > + write_to /sys/bus/pci/devices/${1}/sriov_numvfs ${2}
> > +}
> > +
> Similar to get_sriov_numvfs(), shall we check the existence of the
> 'sriov_numvfs' first? In the current workflow, we indirectly check for
> the file using get_sriov_numvfs() or look for 'sriov_numvfs' in the
> ${device_bdf}. However, an independent check would be cleaner and
> safer (for any future references). WDYT?
I don't think set_sriov_numvfs() should silently do nothing if
sriov_numvfs file does not exist. Calling set_sriov_numvfs() on a device
that does not support SR-IOV indicates a bug in the caller, so it should
fail IMO.
> > + driver=$(get_driver ${device_bdf})
> > + if [ "${driver}" ]; then
> > + unbind ${device_bdf} ${driver}
> > + echo ${driver} > ${device_dir}/driver
> Sorry, what is the purpose of writing the driver's name to the
> "driver" file? Isn't "unbind" sufficient?
So that cleanup.sh can bind the device back to this driver. The goal is
that cleanup.sh returns the device back to the state it was in before
setup.sh. i.e. cleanup.sh needs to undo everything done by setup.sh.
> > + fi
> > +
> Since vfio-pci can be built as a module that may not be loaded yet (or
> even disabled), do you think it's worth checking before binding the
> device to the driver? Of course, these operations would fail, but
> would it be better if we informed users why?
If that were to happen, I think it will be debuggable by the user.
write_to() in lib.sh always prints out what setup.sh and cleanup.sh are
trying to do. So the user will see something like:
echo BDF > /sys/bus/pci/drivers/vfio-pci/bind
Error: No such file or directory
And then the user can go investigate why /sys/bus/pci/drivers/ does not
exist. I think if we try to make the script diagnose why something
failed, that will be an endless game of whack-a-mole and the scripts
will start getting long and complex.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 07/12] vfio: selftests: Prefix logs with device BDF where relevant
2025-11-10 4:54 ` Raghavendra Rao Ananta
@ 2025-11-10 18:28 ` David Matlack
0 siblings, 0 replies; 25+ messages in thread
From: David Matlack @ 2025-11-10 18:28 UTC (permalink / raw)
To: Raghavendra Rao Ananta
Cc: Alex Williamson, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
On 2025-11-10 10:24 AM, Raghavendra Rao Ananta wrote:
> On Thu, Oct 9, 2025 at 4:56 AM David Matlack <dmatlack@google.com> wrote:
> > +#define dev_info(_dev, _fmt, ...) printf("%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)
> > +#define dev_err(_dev, _fmt, ...) fprintf(stderr, "%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)
> > +
> nit: For all the dev_info() replacements in this patch, the messages
> sound like something went bad/wrong. Shouldn't they be dev_err()
> instead, or were you just aiming for a 1:1 conversion?
Yeah I just wanted to do a 1:1 conversion in this patch:
printf(...) -> dev_info(...)
fprintf(stderr, ...) -> dev_err(...)
I can upgrade them in a separate patch in v2.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 02/12] vfio: selftests: Allow passing multiple BDFs on the command line
2025-11-10 3:45 ` Raghavendra Rao Ananta
@ 2025-11-10 18:31 ` David Matlack
0 siblings, 0 replies; 25+ messages in thread
From: David Matlack @ 2025-11-10 18:31 UTC (permalink / raw)
To: Raghavendra Rao Ananta
Cc: Alex Williamson, Jason Gunthorpe, Josh Hilke, kvm, Vipin Sharma
On 2025-11-10 09:15 AM, Raghavendra Rao Ananta wrote:
> On Thu, Oct 9, 2025 at 4:56 AM David Matlack <dmatlack@google.com> wrote:
> > -const char *vfio_selftests_get_bdf(int *argc, char *argv[])
> > +static char **vfio_selftests_get_bdfs_cmdline(int *argc, char *argv[], int *nr_bdfs)
> > {
> > - char *bdf;
> > + int i;
> > +
> > + for (i = *argc - 1; i > 0 && is_bdf(argv[i]); i--)
> > + continue;
> > +
> > + i++;
> > + *nr_bdfs = *argc - i;
> > + *argc -= *nr_bdfs;
> Just curious, why update 'argc' (I know we had this before as well)?
The idea is to parse out the BDFs from the command line, and then let
the test parse the rest of the command line. So we modify argc to remove
the BDFs from the command line, so the test doesn't try to use them for
something else.
> > +static char **vfio_selftests_get_bdfs_env(int *argc, char *argv[], int *nr_bdfs)
> > +{
> > + static char *bdf;
> >
> > bdf = getenv("VFIO_SELFTESTS_BDF");
> > - if (bdf) {
> > - VFIO_ASSERT_TRUE(is_bdf(bdf), "Invalid BDF: %s\n", bdf);
> > - return bdf;
> > - }
> > + if (!bdf)
> > + return NULL;
> > +
> > + *nr_bdfs = 1;
> > + VFIO_ASSERT_TRUE(is_bdf(bdf), "Invalid BDF: %s\n", bdf);
> > +
> > + return &bdf;
> > +}
> nit: Since vfio_selftests_get_bdfs_env() still returns a single BDF,
> perhaps add a comment, as it contradicts the plurality in the
> function's name?
Good point. I'll drop the plurality and make this function only return a
single BDF.
^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2025-11-10 18:31 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-08 23:25 [PATCH 00/12] vfio: selftests: Support for multi-device tests David Matlack
2025-10-08 23:25 ` [PATCH 01/12] vfio: selftests: Split run.sh into separate scripts David Matlack
2025-11-10 3:21 ` Raghavendra Rao Ananta
2025-11-10 18:19 ` David Matlack
2025-10-08 23:25 ` [PATCH 02/12] vfio: selftests: Allow passing multiple BDFs on the command line David Matlack
2025-11-10 3:45 ` Raghavendra Rao Ananta
2025-11-10 18:31 ` David Matlack
2025-10-08 23:25 ` [PATCH 03/12] vfio: selftests: Rename struct vfio_iommu_mode to iommu_mode David Matlack
2025-10-08 23:25 ` [PATCH 04/12] vfio: selftests: Introduce struct iommu David Matlack
2025-10-08 23:25 ` [PATCH 05/12] vfio: selftests: Support multiple devices in the same container/iommufd David Matlack
2025-10-27 16:21 ` David Matlack
2025-11-07 3:37 ` Josh Hilke
2025-10-08 23:25 ` [PATCH 06/12] vfio: selftests: Eliminate overly chatty logging David Matlack
2025-10-08 23:25 ` [PATCH 07/12] vfio: selftests: Prefix logs with device BDF where relevant David Matlack
2025-11-10 4:54 ` Raghavendra Rao Ananta
2025-11-10 18:28 ` David Matlack
2025-10-08 23:25 ` [PATCH 08/12] vfio: selftests: Rename struct vfio_dma_region to dma_region David Matlack
2025-10-08 23:25 ` [PATCH 09/12] vfio: selftests: Move iommu_*() functions into iommu.c David Matlack
2025-10-08 23:25 ` [PATCH 10/12] vfio: selftests: Rename vfio_util.h to libvfio.h David Matlack
2025-10-08 23:25 ` [PATCH 11/12] vfio: selftests: Split libvfio.h into separate header files David Matlack
2025-10-08 23:25 ` [PATCH 12/12] vfio: selftests: Add vfio_pci_device_init_perf_test David Matlack
2025-10-16 16:12 ` David Matlack
2025-11-05 19:06 ` [PATCH 00/12] vfio: selftests: Support for multi-device tests Alex Williamson
2025-11-05 21:03 ` David Matlack
2025-11-05 21:54 ` Alex Williamson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox