* [PATCH v2 1/4] lib/igt_pci: Add raw configuration space helpers
2026-09-21 14:37 [PATCH v2 0/4] Add PCI configuration tests for SR-IOV VFs Piórkowski, Piotr
@ 2026-09-21 14:37 ` Piórkowski, Piotr
2026-09-22 11:00 ` Bernatowicz, Marcin
2026-09-21 14:37 ` [PATCH v2 2/4] tests/sriov_pci_config: Add VF core config checks Piórkowski, Piotr
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Piórkowski, Piotr @ 2026-09-21 14:37 UTC (permalink / raw)
To: igt-dev; +Cc: Piotr Piórkowski
From: Piotr Piórkowski <piotr.piorkowski@intel.com>
Add helpers to read raw PCI configuration space from sysfs and access
its contents.
Provide little-endian u16/u32 readers and standard and extended
capability lookup helpers for configuration-space buffers.
v2:
- Validate malformed and cyclic capability chains.
- Add unit tests for capability lookup and malformed chains.
Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com>
Assisted-by: GPT-5.6 Luna
---
lib/igt_pci.c | 90 +++++++++++++++++++++++++++++++++++++++++++
lib/igt_pci.h | 8 +++-
lib/tests/igt_pci.c | 66 +++++++++++++++++++++++++++++++
lib/tests/meson.build | 1 +
4 files changed, 164 insertions(+), 1 deletion(-)
create mode 100644 lib/tests/igt_pci.c
diff --git a/lib/igt_pci.c b/lib/igt_pci.c
index b63550b390..7cc9f2dfd6 100644
--- a/lib/igt_pci.c
+++ b/lib/igt_pci.c
@@ -8,6 +8,7 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
+#include <linux/pci_regs.h>
#include <string.h>
#include <unistd.h>
#include <pciaccess.h>
@@ -61,6 +62,95 @@ int find_pci_cap_offset(struct pci_device *dev, enum pci_cap_id cap_id)
return find_pci_cap_offset_at(dev, cap_id, PCI_CAPS_START);
}
+/**
+ * igt_pci_config_raw_read:
+ * @pci_slot: PCI device BDF (e.g. "0000:01:00.0")
+ * @buffer: destination buffer
+ * @length: number of configuration-space bytes to read
+ *
+ * Read raw PCI configuration space through the device sysfs config attribute.
+ *
+ * Returns 0 on success, otherwise a negative errno-like value.
+ */
+int igt_pci_config_raw_read(const char *pci_slot, void *buffer, size_t length)
+{
+ char path[PATH_MAX];
+ ssize_t ret;
+ int err;
+ int fd;
+
+ if (!pci_slot || !buffer || !length)
+ return -EINVAL;
+
+ snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/config", pci_slot);
+ fd = open(path, O_RDONLY | O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ ret = pread(fd, buffer, length, 0);
+ err = errno;
+ close(fd);
+ if (ret < 0)
+ return -err;
+
+ return (size_t)ret == length ? 0 : -EIO;
+}
+
+uint16_t igt_pci_config_raw_read_u16(const uint8_t *config, unsigned int offset)
+{
+ return config[offset] | (config[offset + 1] << 8);
+}
+
+uint32_t igt_pci_config_raw_read_u32(const uint8_t *config, unsigned int offset)
+{
+ return igt_pci_config_raw_read_u16(config, offset) |
+ ((uint32_t)igt_pci_config_raw_read_u16(config, offset + 2) << 16);
+}
+
+int igt_pci_config_raw_find_cap_offset(const uint8_t *config, uint8_t cap_id)
+{
+ unsigned int offset = config[PCI_CAPS_START];
+ unsigned int loop = (PCI_CFG_SPACE_SIZE - PCI_TYPE0_1_HEADER_SIZE) / 2;
+
+ while (offset && loop--) {
+ if (offset < PCI_TYPE0_1_HEADER_SIZE ||
+ offset > PCI_CFG_SPACE_SIZE - 2 || offset & 3)
+ return -EINVAL;
+
+ if (config[offset] == cap_id)
+ return offset;
+
+ offset = config[offset + 1];
+ }
+
+ return offset ? -ELOOP : 0;
+}
+
+int igt_pci_config_raw_find_ext_cap_offset(const uint8_t *config, uint16_t cap_id)
+{
+ unsigned int offset = PCI_EXT_CAPS_START;
+ unsigned int loop = (PCI_EXT_CFG_SPACE_SIZE - offset) / 4;
+
+ while (loop) {
+ uint32_t header = igt_pci_config_raw_read_u32(config, offset);
+
+ loop--;
+
+ if (!header)
+ return 0;
+ if ((header & 0xffff) == cap_id)
+ return offset;
+
+ offset = (header >> 20) & 0xffc;
+ if (!offset)
+ return 0;
+ if (offset < PCI_EXT_CAPS_START || offset >= PCI_EXT_CFG_SPACE_SIZE)
+ return -EINVAL;
+ }
+
+ return -ELOOP;
+}
+
static int open_pci_driver_dir(const char *driver)
{
char path[PATH_MAX];
diff --git a/lib/igt_pci.h b/lib/igt_pci.h
index 509345b2d8..628cc24766 100644
--- a/lib/igt_pci.h
+++ b/lib/igt_pci.h
@@ -15,7 +15,8 @@ struct pci_device;
#define PCI_TYPE0_1_HEADER_SIZE 0x40
#define PCI_CAPS_START 0x34
-#define PCI_CFG_SPACE_SIZE 0x100
+#define PCI_EXT_CAPS_START 0x100
+#define PCI_EXT_CFG_SPACE_SIZE 0x1000
enum pci_cap_id {
PCI_EXPRESS_CAP_ID = 0x10
@@ -27,6 +28,11 @@ enum pci_cap_id {
#define PCI_SLOT_PWR_CTRL_PRESENT (1 << 1)
int find_pci_cap_offset(struct pci_device *dev, enum pci_cap_id cap_id);
+int igt_pci_config_raw_read(const char *pci_slot, void *buffer, size_t length);
+uint16_t igt_pci_config_raw_read_u16(const uint8_t *config, unsigned int offset);
+uint32_t igt_pci_config_raw_read_u32(const uint8_t *config, unsigned int offset);
+int igt_pci_config_raw_find_cap_offset(const uint8_t *config, uint8_t cap_id);
+int igt_pci_config_raw_find_ext_cap_offset(const uint8_t *config, uint16_t cap_id);
int igt_pci_device_unbind(const char *pci_slot);
int igt_pci_driver_bind(const char *driver, const char *pci_slot);
int igt_pci_driver_unbind(const char *driver, const char *pci_slot);
diff --git a/lib/tests/igt_pci.c b/lib/tests/igt_pci.c
new file mode 100644
index 0000000000..191edb95c5
--- /dev/null
+++ b/lib/tests/igt_pci.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include <errno.h>
+#include <linux/pci_regs.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "igt_core.h"
+#include "igt_pci.h"
+
+static void write_u32(uint8_t *config, unsigned int offset, uint32_t value)
+{
+ config[offset] = value;
+ config[offset + 1] = value >> 8;
+ config[offset + 2] = value >> 16;
+ config[offset + 3] = value >> 24;
+}
+
+static void test_cap(void)
+{
+ uint8_t config[PCI_CFG_SPACE_SIZE] = {};
+
+ config[PCI_CAPS_START] = PCI_TYPE0_1_HEADER_SIZE;
+ config[PCI_TYPE0_1_HEADER_SIZE] = 0xaa;
+ igt_assert_eq(igt_pci_config_raw_find_cap_offset(config, 0xaa),
+ PCI_TYPE0_1_HEADER_SIZE);
+
+ config[PCI_CAPS_START] = 0xff;
+ igt_assert_eq(igt_pci_config_raw_find_cap_offset(config, 0xaa), -EINVAL);
+
+ config[PCI_CAPS_START] = PCI_TYPE0_1_HEADER_SIZE;
+ config[PCI_TYPE0_1_HEADER_SIZE] = 0xbb;
+ config[PCI_TYPE0_1_HEADER_SIZE + 1] = PCI_TYPE0_1_HEADER_SIZE;
+ igt_assert_eq(igt_pci_config_raw_find_cap_offset(config, 0xaa), -ELOOP);
+}
+
+static void test_ext_cap(void)
+{
+ uint8_t config[PCI_EXT_CFG_SPACE_SIZE] = {};
+ unsigned int offset;
+
+ write_u32(config, PCI_EXT_CAPS_START, 0xaa);
+ igt_assert_eq(igt_pci_config_raw_find_ext_cap_offset(config, 0xaa),
+ PCI_EXT_CAPS_START);
+
+ write_u32(config, PCI_EXT_CAPS_START,
+ 0xbb | (PCI_EXT_CAPS_START << 20));
+ igt_assert_eq(igt_pci_config_raw_find_ext_cap_offset(config, 0xaa), -ELOOP);
+
+ memset(config, 0, sizeof(config));
+ for (offset = PCI_EXT_CAPS_START;
+ offset < PCI_EXT_CFG_SPACE_SIZE - sizeof(uint32_t);
+ offset += sizeof(uint32_t))
+ write_u32(config, offset, 0xbb | ((offset + sizeof(uint32_t)) << 20));
+
+ igt_assert_eq(igt_pci_config_raw_find_ext_cap_offset(config, 0xaa), 0);
+}
+
+int igt_simple_main()
+{
+ test_cap();
+ test_ext_cap();
+}
\ No newline at end of file
diff --git a/lib/tests/meson.build b/lib/tests/meson.build
index f1db66d07c..0a7c903f16 100644
--- a/lib/tests/meson.build
+++ b/lib/tests/meson.build
@@ -19,6 +19,7 @@ lib_tests = [
'igt_invalid_subtest_name',
'igt_nesting',
'igt_no_exit',
+ 'igt_pci',
'igt_runnercomms_packets',
'igt_segfault',
'igt_simulation',
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v2 1/4] lib/igt_pci: Add raw configuration space helpers
2026-09-21 14:37 ` [PATCH v2 1/4] lib/igt_pci: Add raw configuration space helpers Piórkowski, Piotr
@ 2026-09-22 11:00 ` Bernatowicz, Marcin
0 siblings, 0 replies; 9+ messages in thread
From: Bernatowicz, Marcin @ 2026-09-22 11:00 UTC (permalink / raw)
To: Piórkowski, Piotr, igt-dev
On 9/21/2026 4:37 PM, Piórkowski, Piotr wrote:
> From: Piotr Piórkowski <piotr.piorkowski@intel.com>
>
> Add helpers to read raw PCI configuration space from sysfs and access
> its contents.
> Provide little-endian u16/u32 readers and standard and extended
> capability lookup helpers for configuration-space buffers.
>
> v2:
> - Validate malformed and cyclic capability chains.
> - Add unit tests for capability lookup and malformed chains.
>
> Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com>
> Assisted-by: GPT-5.6 Luna
> ---
> lib/igt_pci.c | 90 +++++++++++++++++++++++++++++++++++++++++++
> lib/igt_pci.h | 8 +++-
> lib/tests/igt_pci.c | 66 +++++++++++++++++++++++++++++++
> lib/tests/meson.build | 1 +
> 4 files changed, 164 insertions(+), 1 deletion(-)
> create mode 100644 lib/tests/igt_pci.c
>
> diff --git a/lib/igt_pci.c b/lib/igt_pci.c
> index b63550b390..7cc9f2dfd6 100644
> --- a/lib/igt_pci.c
> +++ b/lib/igt_pci.c
> @@ -8,6 +8,7 @@
> #include <errno.h>
> #include <fcntl.h>
> #include <limits.h>
> +#include <linux/pci_regs.h>
> #include <string.h>
> #include <unistd.h>
> #include <pciaccess.h>
> @@ -61,6 +62,95 @@ int find_pci_cap_offset(struct pci_device *dev, enum pci_cap_id cap_id)
> return find_pci_cap_offset_at(dev, cap_id, PCI_CAPS_START);
> }
>
> +/**
> + * igt_pci_config_raw_read:
> + * @pci_slot: PCI device BDF (e.g. "0000:01:00.0")
> + * @buffer: destination buffer
> + * @length: number of configuration-space bytes to read
> + *
> + * Read raw PCI configuration space through the device sysfs config attribute.
> + *
> + * Returns 0 on success, otherwise a negative errno-like value.
> + */
> +int igt_pci_config_raw_read(const char *pci_slot, void *buffer, size_t length)
> +{
> + char path[PATH_MAX];
> + ssize_t ret;
> + int err;
> + int fd;
> +
> + if (!pci_slot || !buffer || !length)
> + return -EINVAL;
> +
> + snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/config", pci_slot);
> + fd = open(path, O_RDONLY | O_CLOEXEC);
> + if (fd < 0)
> + return -errno;
> +
> + ret = pread(fd, buffer, length, 0);
> + err = errno;
> + close(fd);
> + if (ret < 0)
> + return -err;
> +
> + return (size_t)ret == length ? 0 : -EIO;
> +}
> +
> +uint16_t igt_pci_config_raw_read_u16(const uint8_t *config, unsigned int offset)
> +{
> + return config[offset] | (config[offset + 1] << 8);
> +}
> +
> +uint32_t igt_pci_config_raw_read_u32(const uint8_t *config, unsigned int offset)
> +{
> + return igt_pci_config_raw_read_u16(config, offset) |
> + ((uint32_t)igt_pci_config_raw_read_u16(config, offset + 2) << 16);
> +}
> +
> +int igt_pci_config_raw_find_cap_offset(const uint8_t *config, uint8_t cap_id)
> +{
> + unsigned int offset = config[PCI_CAPS_START];
> + unsigned int loop = (PCI_CFG_SPACE_SIZE - PCI_TYPE0_1_HEADER_SIZE) / 2;
> +
> + while (offset && loop--) {
> + if (offset < PCI_TYPE0_1_HEADER_SIZE ||
> + offset > PCI_CFG_SPACE_SIZE - 2 || offset & 3)
> + return -EINVAL;
> +
> + if (config[offset] == cap_id)
> + return offset;
> +
> + offset = config[offset + 1];
> + }
> +
> + return offset ? -ELOOP : 0;
> +}
Can we consolidate/reuse the loop logic into a common helper shared by
igt_pci_config_raw_find_cap_offset
and find_pci_cap_offset_at ?
There's also a discrepancy in low-2-bit handling - those bits should be
masked off, not validated/rejected.
> +
> +int igt_pci_config_raw_find_ext_cap_offset(const uint8_t *config, uint16_t cap_id)
> +{
> + unsigned int offset = PCI_EXT_CAPS_START;
> + unsigned int loop = (PCI_EXT_CFG_SPACE_SIZE - offset) / 4;
> +
> + while (loop) {
> + uint32_t header = igt_pci_config_raw_read_u32(config, offset);
> +
> + loop--;
> +
> + if (!header)
> + return 0;
> + if ((header & 0xffff) == cap_id)
> + return offset;
> +
> + offset = (header >> 20) & 0xffc;
> + if (!offset)
> + return 0;
> + if (offset < PCI_EXT_CAPS_START || offset >= PCI_EXT_CFG_SPACE_SIZE)
> + return -EINVAL;
> + }
> +
> + return -ELOOP;
> +}
> +
Maybe it's worth to check a special-case an all-0xffffffff header (what
you get back when extended config space isn't implemented/accessible)
instead of walking it as real data?
> static int open_pci_driver_dir(const char *driver)
> {
> char path[PATH_MAX];
> diff --git a/lib/igt_pci.h b/lib/igt_pci.h
> index 509345b2d8..628cc24766 100644
> --- a/lib/igt_pci.h
> +++ b/lib/igt_pci.h
> @@ -15,7 +15,8 @@ struct pci_device;
>
> #define PCI_TYPE0_1_HEADER_SIZE 0x40
> #define PCI_CAPS_START 0x34
> -#define PCI_CFG_SPACE_SIZE 0x100
> +#define PCI_EXT_CAPS_START 0x100
> +#define PCI_EXT_CFG_SPACE_SIZE 0x1000
>
> enum pci_cap_id {
> PCI_EXPRESS_CAP_ID = 0x10
> @@ -27,6 +28,11 @@ enum pci_cap_id {
> #define PCI_SLOT_PWR_CTRL_PRESENT (1 << 1)
>
> int find_pci_cap_offset(struct pci_device *dev, enum pci_cap_id cap_id);
> +int igt_pci_config_raw_read(const char *pci_slot, void *buffer, size_t length);
> +uint16_t igt_pci_config_raw_read_u16(const uint8_t *config, unsigned int offset);
> +uint32_t igt_pci_config_raw_read_u32(const uint8_t *config, unsigned int offset);
> +int igt_pci_config_raw_find_cap_offset(const uint8_t *config, uint8_t cap_id);
> +int igt_pci_config_raw_find_ext_cap_offset(const uint8_t *config, uint16_t cap_id);
> int igt_pci_device_unbind(const char *pci_slot);
> int igt_pci_driver_bind(const char *driver, const char *pci_slot);
> int igt_pci_driver_unbind(const char *driver, const char *pci_slot);
> diff --git a/lib/tests/igt_pci.c b/lib/tests/igt_pci.c
> new file mode 100644
> index 0000000000..191edb95c5
> --- /dev/null
> +++ b/lib/tests/igt_pci.c
> @@ -0,0 +1,66 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +
> +#include <errno.h>
> +#include <linux/pci_regs.h>
> +#include <stdint.h>
> +#include <string.h>
> +
> +#include "igt_core.h"
> +#include "igt_pci.h"
> +
> +static void write_u32(uint8_t *config, unsigned int offset, uint32_t value)
> +{
> + config[offset] = value;
> + config[offset + 1] = value >> 8;
> + config[offset + 2] = value >> 16;
> + config[offset + 3] = value >> 24;
> +}
> +
> +static void test_cap(void)
> +{
> + uint8_t config[PCI_CFG_SPACE_SIZE] = {};
> +
> + config[PCI_CAPS_START] = PCI_TYPE0_1_HEADER_SIZE;
> + config[PCI_TYPE0_1_HEADER_SIZE] = 0xaa;
> + igt_assert_eq(igt_pci_config_raw_find_cap_offset(config, 0xaa),
> + PCI_TYPE0_1_HEADER_SIZE);
> +
> + config[PCI_CAPS_START] = 0xff;
> + igt_assert_eq(igt_pci_config_raw_find_cap_offset(config, 0xaa), -EINVAL);
> +
> + config[PCI_CAPS_START] = PCI_TYPE0_1_HEADER_SIZE;
> + config[PCI_TYPE0_1_HEADER_SIZE] = 0xbb;
> + config[PCI_TYPE0_1_HEADER_SIZE + 1] = PCI_TYPE0_1_HEADER_SIZE;
> + igt_assert_eq(igt_pci_config_raw_find_cap_offset(config, 0xaa), -ELOOP);
> +}
> +
> +static void test_ext_cap(void)
> +{
> + uint8_t config[PCI_EXT_CFG_SPACE_SIZE] = {};
> + unsigned int offset;
> +
> + write_u32(config, PCI_EXT_CAPS_START, 0xaa);
> + igt_assert_eq(igt_pci_config_raw_find_ext_cap_offset(config, 0xaa),
> + PCI_EXT_CAPS_START);
> +
> + write_u32(config, PCI_EXT_CAPS_START,
> + 0xbb | (PCI_EXT_CAPS_START << 20));
> + igt_assert_eq(igt_pci_config_raw_find_ext_cap_offset(config, 0xaa), -ELOOP);
> +
> + memset(config, 0, sizeof(config));
> + for (offset = PCI_EXT_CAPS_START;
> + offset < PCI_EXT_CFG_SPACE_SIZE - sizeof(uint32_t);
> + offset += sizeof(uint32_t))
> + write_u32(config, offset, 0xbb | ((offset + sizeof(uint32_t)) << 20));
> +
> + igt_assert_eq(igt_pci_config_raw_find_ext_cap_offset(config, 0xaa), 0);
> +}
> +
> +int igt_simple_main()
> +{
> + test_cap();
> + test_ext_cap();
> +}
> \ No newline at end of file
> diff --git a/lib/tests/meson.build b/lib/tests/meson.build
> index f1db66d07c..0a7c903f16 100644
> --- a/lib/tests/meson.build
> +++ b/lib/tests/meson.build
> @@ -19,6 +19,7 @@ lib_tests = [
> 'igt_invalid_subtest_name',
> 'igt_nesting',
> 'igt_no_exit',
> + 'igt_pci',
> 'igt_runnercomms_packets',
> 'igt_segfault',
> 'igt_simulation',
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 2/4] tests/sriov_pci_config: Add VF core config checks
2026-09-21 14:37 [PATCH v2 0/4] Add PCI configuration tests for SR-IOV VFs Piórkowski, Piotr
2026-09-21 14:37 ` [PATCH v2 1/4] lib/igt_pci: Add raw configuration space helpers Piórkowski, Piotr
@ 2026-09-21 14:37 ` Piórkowski, Piotr
2026-09-28 12:46 ` [v2,2/4] " Laguna, Lukasz
2026-09-21 14:37 ` [PATCH v2 3/4] tests/sriov_pci_config: Add optional capability checks Piórkowski, Piotr
2026-09-21 14:37 ` [PATCH v2 4/4] intel-ci: Block igt@sriov_pci_config.* Piórkowski, Piotr
3 siblings, 1 reply; 9+ messages in thread
From: Piórkowski, Piotr @ 2026-09-21 14:37 UTC (permalink / raw)
To: igt-dev; +Cc: Piotr Piórkowski
From: Piotr Piórkowski <piotr.piorkowski@intel.com>
Add checks for PCI configuration fields required by SR-IOV VFs.
Cover the common header, BARs, and PCI Express capability fields.
v2:
- Enable the VF and read its configuration once in the fixture.
- Restore driver autoprobe state and disable the VF during cleanup.
- Clarify test documentation and shorten runtime descriptions.
- Remove redundant informational messages.
Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com>
Assisted-by: GPT-5.6 Luna
---
tests/meson.build | 1 +
tests/sriov_pci_config.c | 210 +++++++++++++++++++++++++++++++++++++++
2 files changed, 211 insertions(+)
create mode 100644 tests/sriov_pci_config.c
diff --git a/tests/meson.build b/tests/meson.build
index bee2b94224..51c84c99f0 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -74,6 +74,7 @@ test_progs = [
'meta_test',
'prime_vgem',
'sriov_basic',
+ 'sriov_pci_config',
'syncobj_basic',
'syncobj_eventfd',
'syncobj_wait',
diff --git a/tests/sriov_pci_config.c b/tests/sriov_pci_config.c
new file mode 100644
index 0000000000..9f410ef23a
--- /dev/null
+++ b/tests/sriov_pci_config.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright(c) 2026 Intel Corporation. All rights reserved.
+ */
+
+#include <linux/pci_regs.h>
+
+#include "drmtest.h"
+#include "igt.h"
+#include "igt_pci.h"
+#include "igt_sriov_device.h"
+
+#define VF_PCI_EXP_DEVSTA_EPRD (1 << 6)
+#define VF_PCI_EXP_LNKSTA2_DEEMPHASIS (1 << 0)
+
+/**
+ * TEST: SR-IOV PCI configuration
+ * Category: Core
+ * Mega feature: SR-IOV
+ * Sub-category: PCI configuration
+ * Functionality: SR-IOV-related PCI configuration space
+ * Description: Validate PCI configuration fields required for SR-IOV,
+ * including Virtual Functions.
+ *
+ * SUBTEST: vf-common-header
+ * Description: Validate that the VF Vendor ID and Device ID read as 0xffff,
+ * and that the I/O, Memory, and INTx Disable bits in Command, the Immediate
+ * Readiness and Interrupt Status bits in Status, the Header Layout bits in
+ * Header Type, and the BIST Completion Code are all zero.
+ *
+ * SUBTEST: vf-bars
+ * Description: Validate that VF BAR address bits read as zero. The BAR type
+ * and attribute bits are static and may remain set; the upper dword of a
+ * 64-bit BAR must read as zero.
+ *
+ * SUBTEST: vf-pcie-capabilities
+ * Description: Validate that FLR is supported, and Phantom Functions Supported,
+ * Auxiliary Power Detected, Emergency Power Reduction Detected, Current Link
+ * Speed, Negotiated Link Width, and Link Autonomous Bandwidth Status are all
+ * zero.
+ *
+ * SUBTEST: vf-pcie-capabilities-2
+ * Description: Validate that the Current De-emphasis Level field in Link
+ * Status 2 is RsvdZ and therefore reads as zero for PCIe Capability Version 2
+ * and later.
+ */
+
+IGT_TEST_DESCRIPTION("Validate PCI configuration fields required for SR-IOV, "
+ "including Virtual Functions");
+
+static int pf_fd = -1;
+static bool autoprobe;
+static uint8_t vf_config[PCI_EXT_CFG_SPACE_SIZE];
+
+static void read_vf_config(uint8_t *config)
+{
+ char *vf_slot;
+ int ret;
+
+ vf_slot = igt_sriov_get_vf_pci_slot_alloc(pf_fd, 1);
+ igt_assert(vf_slot);
+ ret = igt_pci_config_raw_read(vf_slot, config, PCI_EXT_CFG_SPACE_SIZE);
+ free(vf_slot);
+ igt_assert_f(!ret, "Failed to read VF config space (%d)\n", ret);
+}
+
+static void check_vf_common_header(const uint8_t *config)
+{
+ uint16_t command = igt_pci_config_raw_read_u16(config, PCI_COMMAND);
+ uint16_t status = igt_pci_config_raw_read_u16(config, PCI_STATUS);
+ uint16_t vendor_id = igt_pci_config_raw_read_u16(config, PCI_VENDOR_ID);
+ uint16_t device_id = igt_pci_config_raw_read_u16(config, PCI_DEVICE_ID);
+
+ igt_assert_f(vendor_id == 0xffff, "Vendor ID: expected 0xffff, got 0x%04x\n", vendor_id);
+ igt_assert_f(device_id == 0xffff, "Device ID: expected 0xffff, got 0x%04x\n", device_id);
+ igt_assert_f(!(command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+ PCI_COMMAND_INTX_DISABLE)),
+ "Command: expected I/O, Memory, and INTx Disable bits clear, got 0x%04x\n",
+ command);
+ igt_assert_f(!(status & (PCI_STATUS_IMM_READY | PCI_STATUS_INTERRUPT)),
+ "Status: expected Immediate Readiness and Interrupt Status bits clear, got 0x%04x\n",
+ status);
+ igt_assert_f(!(config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MASK),
+ "Header Type: expected Header Layout 0, got 0x%02x\n",
+ config[PCI_HEADER_TYPE]);
+ igt_assert_f(!(config[PCI_BIST] & PCI_BIST_CODE_MASK),
+ "BIST: expected Completion Code 0, got 0x%02x\n", config[PCI_BIST]);
+}
+
+static void check_vf_bars(const uint8_t *config)
+{
+ for (int bar = 0; bar < 6; bar++) {
+ uint32_t value =
+ igt_pci_config_raw_read_u32(config,
+ PCI_BASE_ADDRESS_0 + bar * sizeof(uint32_t));
+ bool is_mem64 = !(value & PCI_BASE_ADDRESS_SPACE) &&
+ (value & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+ PCI_BASE_ADDRESS_MEM_TYPE_64;
+
+ /* Only the address bits are hardwired to zero; type/attribute bits are static. */
+ igt_assert_f(!(value & ~0xfu), "BAR%d: expected address 0x00000000, got 0x%08x\n",
+ bar, value);
+
+ /* The upper dword of a 64-bit BAR holds pure address bits, no type bits. */
+ if (is_mem64) {
+ unsigned int upper_offset = PCI_BASE_ADDRESS_0 +
+ (bar + 1) * sizeof(uint32_t);
+ uint32_t upper =
+ igt_pci_config_raw_read_u32(config, upper_offset);
+
+ igt_assert_f(!upper, "BAR%d (upper): expected 0x00000000, got 0x%08x\n",
+ bar + 1, upper);
+ bar++;
+ }
+ }
+}
+
+static int get_pcie_cap(const uint8_t *config)
+{
+ int pcie_cap = igt_pci_config_raw_find_cap_offset(config, PCI_CAP_ID_EXP);
+
+ igt_assert_f(pcie_cap > 0, "VF has no PCI Express capability (%d)\n", pcie_cap);
+
+ return pcie_cap;
+}
+
+static void check_vf_pcie_capabilities(const uint8_t *config)
+{
+ int pcie_cap = get_pcie_cap(config);
+ uint32_t pcie_devcap = igt_pci_config_raw_read_u32(config, pcie_cap + PCI_EXP_DEVCAP);
+ uint16_t pcie_devsta = igt_pci_config_raw_read_u16(config, pcie_cap + PCI_EXP_DEVSTA);
+ uint16_t pcie_lnksta = igt_pci_config_raw_read_u16(config, pcie_cap + PCI_EXP_LNKSTA);
+
+ igt_assert_f(pcie_devcap & PCI_EXP_DEVCAP_FLR,
+ "Device Capabilities: FLR bit is clear (0x%08x)\n", pcie_devcap);
+ igt_assert_f(!(pcie_devcap & PCI_EXP_DEVCAP_PHANTOM),
+ "Device Capabilities: Phantom Functions Supported must be zero (0x%08x)\n",
+ pcie_devcap);
+ igt_assert_f(!(pcie_devsta & (PCI_EXP_DEVSTA_AUXPD |
+ VF_PCI_EXP_DEVSTA_EPRD)),
+ "Device Status: Aux Power Detected or Emergency Power Reduction Detected is set (0x%04x)\n",
+ pcie_devsta);
+ igt_assert_f(!(pcie_lnksta & (PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW |
+ PCI_EXP_LNKSTA_LABS)),
+ "Link Status: Current Link Speed, Negotiated Link Width, or Link Autonomous Bandwidth Status is set (0x%04x)\n",
+ pcie_lnksta);
+}
+
+static void check_vf_pcie_capabilities_2(const uint8_t *config)
+{
+ int pcie_cap = get_pcie_cap(config);
+ uint16_t flags = igt_pci_config_raw_read_u16(config, pcie_cap + PCI_EXP_FLAGS);
+ uint16_t lnksta2;
+
+ if ((flags & PCI_EXP_FLAGS_VERS) < 2)
+ igt_skip("PCI Express Capability Version 2 is not present\n");
+
+ lnksta2 = igt_pci_config_raw_read_u16(config, pcie_cap + PCI_EXP_LNKSTA2);
+ igt_assert_f(!(lnksta2 & VF_PCI_EXP_LNKSTA2_DEEMPHASIS),
+ "Link Status 2: Current De-emphasis Level must be zero (0x%04x)\n",
+ lnksta2);
+}
+
+int igt_main()
+{
+ igt_fixture() {
+ pf_fd = drm_open_driver(DRIVER_ANY);
+ igt_require(igt_sriov_is_pf(pf_fd));
+ igt_require(igt_sriov_vfs_supported(pf_fd));
+ igt_require(igt_sriov_get_enabled_vfs(pf_fd) == 0);
+ autoprobe = igt_sriov_is_driver_autoprobe_enabled(pf_fd);
+ igt_sriov_install_exit_handler(pf_fd, NULL, NULL);
+ igt_sriov_disable_driver_autoprobe(pf_fd);
+ igt_sriov_enable_vfs(pf_fd, 1);
+ igt_require_f(!igt_pci_system_reinit(), "Failed to refresh PCI state\n");
+ read_vf_config(vf_config);
+ }
+
+ igt_describe("Validate the VF PCI common header");
+ igt_subtest("vf-common-header") {
+ check_vf_common_header(vf_config);
+ }
+
+ igt_describe("Validate the VF BARs");
+ igt_subtest("vf-bars") {
+ check_vf_bars(vf_config);
+ }
+
+ igt_describe("Validate the VF PCI Express capability");
+ igt_subtest("vf-pcie-capabilities") {
+ check_vf_pcie_capabilities(vf_config);
+ }
+
+ igt_describe("Validate the VF PCI Express Capability Version 2 fields");
+ igt_subtest("vf-pcie-capabilities-2") {
+ check_vf_pcie_capabilities_2(vf_config);
+ }
+ igt_fixture() {
+ igt_abort_on_f(pf_fd < 0, "Device is not accessible\n");
+ igt_sriov_disable_vfs(pf_fd);
+ igt_abort_on_f(igt_sriov_get_enabled_vfs(pf_fd) > 0,
+ "Failed to disable VF(s)\n");
+ autoprobe ? igt_sriov_enable_driver_autoprobe(pf_fd) :
+ igt_sriov_disable_driver_autoprobe(pf_fd);
+ igt_abort_on_f(autoprobe != igt_sriov_is_driver_autoprobe_enabled(pf_fd),
+ "Failed to restore sriov_drivers_autoprobe value\n");
+ igt_sriov_clear_exit_handler();
+ close(pf_fd);
+ }
+}
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [v2,2/4] tests/sriov_pci_config: Add VF core config checks
2026-09-21 14:37 ` [PATCH v2 2/4] tests/sriov_pci_config: Add VF core config checks Piórkowski, Piotr
@ 2026-09-28 12:46 ` Laguna, Lukasz
0 siblings, 0 replies; 9+ messages in thread
From: Laguna, Lukasz @ 2026-09-28 12:46 UTC (permalink / raw)
To: Piórkowski, Piotr, igt-dev
On 9/21/2026 16:37, Piórkowski, Piotr wrote:
> From: Piotr Piórkowski <piotr.piorkowski@intel.com>
>
> Add checks for PCI configuration fields required by SR-IOV VFs.
> Cover the common header, BARs, and PCI Express capability fields.
>
> v2:
> - Enable the VF and read its configuration once in the fixture.
> - Restore driver autoprobe state and disable the VF during cleanup.
> - Clarify test documentation and shorten runtime descriptions.
> - Remove redundant informational messages.
>
> Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com>
> Assisted-by: GPT-5.6 Luna
> ---
> tests/meson.build | 1 +
> tests/sriov_pci_config.c | 210 +++++++++++++++++++++++++++++++++++++++
> 2 files changed, 211 insertions(+)
> create mode 100644 tests/sriov_pci_config.c
>
> diff --git a/tests/meson.build b/tests/meson.build
> index bee2b94224..51c84c99f0 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -74,6 +74,7 @@ test_progs = [
> 'meta_test',
> 'prime_vgem',
> 'sriov_basic',
> + 'sriov_pci_config',
> 'syncobj_basic',
> 'syncobj_eventfd',
> 'syncobj_wait',
> diff --git a/tests/sriov_pci_config.c b/tests/sriov_pci_config.c
> new file mode 100644
> index 0000000000..9f410ef23a
> --- /dev/null
> +++ b/tests/sriov_pci_config.c
> @@ -0,0 +1,210 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright(c) 2026 Intel Corporation. All rights reserved.
> + */
> +
> +#include <linux/pci_regs.h>
> +
> +#include "drmtest.h"
> +#include "igt.h"
> +#include "igt_pci.h"
> +#include "igt_sriov_device.h"
> +
> +#define VF_PCI_EXP_DEVSTA_EPRD (1 << 6)
> +#define VF_PCI_EXP_LNKSTA2_DEEMPHASIS (1 << 0)
> +
> +/**
> + * TEST: SR-IOV PCI configuration
> + * Category: Core
> + * Mega feature: SR-IOV
> + * Sub-category: PCI configuration
> + * Functionality: SR-IOV-related PCI configuration space
> + * Description: Validate PCI configuration fields required for SR-IOV,
> + * including Virtual Functions.
> + *
> + * SUBTEST: vf-common-header
> + * Description: Validate that the VF Vendor ID and Device ID read as 0xffff,
> + * and that the I/O, Memory, and INTx Disable bits in Command, the Immediate
> + * Readiness and Interrupt Status bits in Status, the Header Layout bits in
> + * Header Type, and the BIST Completion Code are all zero.
> + *
> + * SUBTEST: vf-bars
> + * Description: Validate that VF BAR address bits read as zero. The BAR type
> + * and attribute bits are static and may remain set; the upper dword of a
> + * 64-bit BAR must read as zero.
> + *
> + * SUBTEST: vf-pcie-capabilities
> + * Description: Validate that FLR is supported, and Phantom Functions Supported,
> + * Auxiliary Power Detected, Emergency Power Reduction Detected, Current Link
> + * Speed, Negotiated Link Width, and Link Autonomous Bandwidth Status are all
> + * zero.
> + *
> + * SUBTEST: vf-pcie-capabilities-2
> + * Description: Validate that the Current De-emphasis Level field in Link
> + * Status 2 is RsvdZ and therefore reads as zero for PCIe Capability Version 2
> + * and later.
> + */
> +
> +IGT_TEST_DESCRIPTION("Validate PCI configuration fields required for SR-IOV, "
> + "including Virtual Functions");
> +
> +static int pf_fd = -1;
> +static bool autoprobe;
> +static uint8_t vf_config[PCI_EXT_CFG_SPACE_SIZE];
What reason for not defining them in main?
> +
> +static void read_vf_config(uint8_t *config)
> +{
> + char *vf_slot;
> + int ret;
> +
> + vf_slot = igt_sriov_get_vf_pci_slot_alloc(pf_fd, 1);
> + igt_assert(vf_slot);
> + ret = igt_pci_config_raw_read(vf_slot, config, PCI_EXT_CFG_SPACE_SIZE);
> + free(vf_slot);
> + igt_assert_f(!ret, "Failed to read VF config space (%d)\n", ret);
> +}
> +
> +static void check_vf_common_header(const uint8_t *config)
> +{
> + uint16_t command = igt_pci_config_raw_read_u16(config, PCI_COMMAND);
> + uint16_t status = igt_pci_config_raw_read_u16(config, PCI_STATUS);
> + uint16_t vendor_id = igt_pci_config_raw_read_u16(config, PCI_VENDOR_ID);
> + uint16_t device_id = igt_pci_config_raw_read_u16(config, PCI_DEVICE_ID);
> +
> + igt_assert_f(vendor_id == 0xffff, "Vendor ID: expected 0xffff, got 0x%04x\n", vendor_id);
> + igt_assert_f(device_id == 0xffff, "Device ID: expected 0xffff, got 0x%04x\n", device_id);
> + igt_assert_f(!(command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
> + PCI_COMMAND_INTX_DISABLE)),
> + "Command: expected I/O, Memory, and INTx Disable bits clear, got 0x%04x\n",
> + command);
> + igt_assert_f(!(status & (PCI_STATUS_IMM_READY | PCI_STATUS_INTERRUPT)),
> + "Status: expected Immediate Readiness and Interrupt Status bits clear, got 0x%04x\n",
> + status);
> + igt_assert_f(!(config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MASK),
> + "Header Type: expected Header Layout 0, got 0x%02x\n",
> + config[PCI_HEADER_TYPE]);
> + igt_assert_f(!(config[PCI_BIST] & PCI_BIST_CODE_MASK),
> + "BIST: expected Completion Code 0, got 0x%02x\n", config[PCI_BIST]);
> +}
> +
> +static void check_vf_bars(const uint8_t *config)
> +{
> + for (int bar = 0; bar < 6; bar++) {
> + uint32_t value =
> + igt_pci_config_raw_read_u32(config,
> + PCI_BASE_ADDRESS_0 + bar * sizeof(uint32_t));
> + bool is_mem64 = !(value & PCI_BASE_ADDRESS_SPACE) &&
> + (value & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
> + PCI_BASE_ADDRESS_MEM_TYPE_64;
> +
> + /* Only the address bits are hardwired to zero; type/attribute bits are static. */
> + igt_assert_f(!(value & ~0xfu), "BAR%d: expected address 0x00000000, got 0x%08x\n",
> + bar, value);
> +
> + /* The upper dword of a 64-bit BAR holds pure address bits, no type bits. */
> + if (is_mem64) {
> + unsigned int upper_offset = PCI_BASE_ADDRESS_0 +
> + (bar + 1) * sizeof(uint32_t);
> + uint32_t upper =
> + igt_pci_config_raw_read_u32(config, upper_offset);
> +
> + igt_assert_f(!upper, "BAR%d (upper): expected 0x00000000, got 0x%08x\n",
> + bar + 1, upper);
> + bar++;
> + }
> + }
> +}
> +
> +static int get_pcie_cap(const uint8_t *config)
> +{
> + int pcie_cap = igt_pci_config_raw_find_cap_offset(config, PCI_CAP_ID_EXP);
> +
> + igt_assert_f(pcie_cap > 0, "VF has no PCI Express capability (%d)\n", pcie_cap);
> +
> + return pcie_cap;
> +}
> +
> +static void check_vf_pcie_capabilities(const uint8_t *config)
> +{
> + int pcie_cap = get_pcie_cap(config);
> + uint32_t pcie_devcap = igt_pci_config_raw_read_u32(config, pcie_cap + PCI_EXP_DEVCAP);
> + uint16_t pcie_devsta = igt_pci_config_raw_read_u16(config, pcie_cap + PCI_EXP_DEVSTA);
> + uint16_t pcie_lnksta = igt_pci_config_raw_read_u16(config, pcie_cap + PCI_EXP_LNKSTA);
> +
> + igt_assert_f(pcie_devcap & PCI_EXP_DEVCAP_FLR,
> + "Device Capabilities: FLR bit is clear (0x%08x)\n", pcie_devcap);
> + igt_assert_f(!(pcie_devcap & PCI_EXP_DEVCAP_PHANTOM),
> + "Device Capabilities: Phantom Functions Supported must be zero (0x%08x)\n",
> + pcie_devcap);
> + igt_assert_f(!(pcie_devsta & (PCI_EXP_DEVSTA_AUXPD |
> + VF_PCI_EXP_DEVSTA_EPRD)),
> + "Device Status: Aux Power Detected or Emergency Power Reduction Detected is set (0x%04x)\n",
> + pcie_devsta);
> + igt_assert_f(!(pcie_lnksta & (PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW |
> + PCI_EXP_LNKSTA_LABS)),
> + "Link Status: Current Link Speed, Negotiated Link Width, or Link Autonomous Bandwidth Status is set (0x%04x)\n",
> + pcie_lnksta);
> +}
> +
> +static void check_vf_pcie_capabilities_2(const uint8_t *config)
> +{
> + int pcie_cap = get_pcie_cap(config);
> + uint16_t flags = igt_pci_config_raw_read_u16(config, pcie_cap + PCI_EXP_FLAGS);
> + uint16_t lnksta2;
> +
> + if ((flags & PCI_EXP_FLAGS_VERS) < 2)
> + igt_skip("PCI Express Capability Version 2 is not present\n");
> +
> + lnksta2 = igt_pci_config_raw_read_u16(config, pcie_cap + PCI_EXP_LNKSTA2);
> + igt_assert_f(!(lnksta2 & VF_PCI_EXP_LNKSTA2_DEEMPHASIS),
> + "Link Status 2: Current De-emphasis Level must be zero (0x%04x)\n",
> + lnksta2);
> +}
> +
> +int igt_main()
> +{
> + igt_fixture() {
> + pf_fd = drm_open_driver(DRIVER_ANY);
> + igt_require(igt_sriov_is_pf(pf_fd));
> + igt_require(igt_sriov_vfs_supported(pf_fd));
> + igt_require(igt_sriov_get_enabled_vfs(pf_fd) == 0);
> + autoprobe = igt_sriov_is_driver_autoprobe_enabled(pf_fd);
> + igt_sriov_install_exit_handler(pf_fd, NULL, NULL);
Can you add a new line here?
> + igt_sriov_disable_driver_autoprobe(pf_fd);
> + igt_sriov_enable_vfs(pf_fd, 1);
> + igt_require_f(!igt_pci_system_reinit(), "Failed to refresh PCI state\n");
> + read_vf_config(vf_config);
> + }
> +
> + igt_describe("Validate the VF PCI common header");
> + igt_subtest("vf-common-header") {
> + check_vf_common_header(vf_config);
> + }
> +
> + igt_describe("Validate the VF BARs");
> + igt_subtest("vf-bars") {
> + check_vf_bars(vf_config);
> + }
> +
> + igt_describe("Validate the VF PCI Express capability");
> + igt_subtest("vf-pcie-capabilities") {
> + check_vf_pcie_capabilities(vf_config);
> + }
> +
> + igt_describe("Validate the VF PCI Express Capability Version 2 fields");
> + igt_subtest("vf-pcie-capabilities-2") {
> + check_vf_pcie_capabilities_2(vf_config);
> + }
> + igt_fixture() {
> + igt_abort_on_f(pf_fd < 0, "Device is not accessible\n");
> + igt_sriov_disable_vfs(pf_fd);
> + igt_abort_on_f(igt_sriov_get_enabled_vfs(pf_fd) > 0,
> + "Failed to disable VF(s)\n");
> + autoprobe ? igt_sriov_enable_driver_autoprobe(pf_fd) :
> + igt_sriov_disable_driver_autoprobe(pf_fd);
> + igt_abort_on_f(autoprobe != igt_sriov_is_driver_autoprobe_enabled(pf_fd),
> + "Failed to restore sriov_drivers_autoprobe value\n");
> + igt_sriov_clear_exit_handler();
> + close(pf_fd);
> + }
> +}
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 3/4] tests/sriov_pci_config: Add optional capability checks
2026-09-21 14:37 [PATCH v2 0/4] Add PCI configuration tests for SR-IOV VFs Piórkowski, Piotr
2026-09-21 14:37 ` [PATCH v2 1/4] lib/igt_pci: Add raw configuration space helpers Piórkowski, Piotr
2026-09-21 14:37 ` [PATCH v2 2/4] tests/sriov_pci_config: Add VF core config checks Piórkowski, Piotr
@ 2026-09-21 14:37 ` Piórkowski, Piotr
2026-09-28 12:49 ` [v2,3/4] " Laguna, Lukasz
2026-09-21 14:37 ` [PATCH v2 4/4] intel-ci: Block igt@sriov_pci_config.* Piórkowski, Piotr
3 siblings, 1 reply; 9+ messages in thread
From: Piórkowski, Piotr @ 2026-09-21 14:37 UTC (permalink / raw)
To: igt-dev; +Cc: Piotr Piórkowski
From: Piotr Piórkowski <piotr.piorkowski@intel.com>
Add subtests for the optional Power Management, Advanced Error
Reporting, and Address Translation Service capabilities.
Skip an optional-capability subtest when the capability is not exposed
by the VF.
Validate the VF ROZ fields required by the SR-IOV specification,
including Power Management Data Select/Data, AER status/mask/severity
fields, and ATS Queue Depth/STU.
v2:
- Reuse the VF configuration captured by the common fixture.
- Use PCI register definitions available from linux/pci_regs.h.
- Simplify optional-capability skips and runtime descriptions.
- Remove redundant informational messages.
Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com>
Assisted-by: GPT-5.6 Luna
---
tests/sriov_pci_config.c | 110 +++++++++++++++++++++++++++++++++++++++
1 file changed, 110 insertions(+)
diff --git a/tests/sriov_pci_config.c b/tests/sriov_pci_config.c
index 9f410ef23a..a3d7e86b58 100644
--- a/tests/sriov_pci_config.c
+++ b/tests/sriov_pci_config.c
@@ -43,6 +43,21 @@
* Description: Validate that the Current De-emphasis Level field in Link
* Status 2 is RsvdZ and therefore reads as zero for PCIe Capability Version 2
* and later.
+ *
+ * SUBTEST: vf-power-management-capability
+ * Description: Validate that Data Select in Power Management Control and
+ * Power Management Data are ROZ and therefore read as zero when the optional
+ * Power Management capability is present.
+ *
+ * SUBTEST: vf-advanced-error-reporting
+ * Description: Validate that the specified ROZ bits in AER Uncorrectable
+ * Error Status, Mask, and Severity, and Correctable Error Status read as zero
+ * when the optional AER capability is present.
+ *
+ * SUBTEST: vf-ats-capability
+ * Description: Validate that ATS Queue Depth and the Smallest Translation Unit
+ * (STU) are ROZ and therefore read as zero when the optional ATS capability
+ * is present.
*/
IGT_TEST_DESCRIPTION("Validate PCI configuration fields required for SR-IOV, "
@@ -161,6 +176,85 @@ static void check_vf_pcie_capabilities_2(const uint8_t *config)
lnksta2);
}
+static int get_optional_cap(const uint8_t *config, uint8_t cap_id, const char *name)
+{
+ int cap = igt_pci_config_raw_find_cap_offset(config, cap_id);
+
+ igt_assert_f(cap >= 0, "Invalid VF PCI capability list (%d)\n", cap);
+ if (!cap)
+ igt_skip("%s\n", name);
+
+ return cap;
+}
+
+static int get_optional_ext_cap(const uint8_t *config, uint16_t cap_id, const char *name)
+{
+ int cap = igt_pci_config_raw_find_ext_cap_offset(config, cap_id);
+
+ igt_assert_f(cap >= 0, "Invalid VF extended capability list (%d)\n", cap);
+ if (!cap)
+ igt_skip("%s\n", name);
+
+ return cap;
+}
+
+static void check_vf_power_management_capability(const uint8_t *config)
+{
+ int pm_cap = get_optional_cap(config, PCI_CAP_ID_PM,
+ "Power Management capability is not present");
+ uint16_t pm_ctrl = igt_pci_config_raw_read_u16(config, pm_cap + PCI_PM_CTRL);
+ uint8_t pm_data = config[pm_cap + PCI_PM_DATA_REGISTER];
+
+ igt_assert_f(!(pm_ctrl & PCI_PM_CTRL_DATA_SEL_MASK),
+ "Power Management Control: Data Select must be zero (0x%04x)\n", pm_ctrl);
+ igt_assert_f(!pm_data, "Power Management Data: expected 0x00, got 0x%02x\n", pm_data);
+}
+
+static void check_vf_advanced_error_reporting(const uint8_t *config)
+{
+ const uint32_t uncor_roz = PCI_ERR_UNC_DLP | PCI_ERR_UNC_SURPDN |
+ PCI_ERR_UNC_FCP | PCI_ERR_UNC_RX_OVER |
+ PCI_ERR_UNC_MALF_TLP | PCI_ERR_UNC_ECRC;
+ const uint32_t cor_roz = PCI_ERR_COR_RCVR | PCI_ERR_COR_BAD_TLP |
+ PCI_ERR_COR_REP_ROLL | PCI_ERR_COR_REP_TIMER;
+ int aer_cap = get_optional_ext_cap(config, PCI_EXT_CAP_ID_ERR,
+ "Advanced Error Reporting capability is not present");
+ uint32_t uncor_status = igt_pci_config_raw_read_u32(config,
+ aer_cap + PCI_ERR_UNCOR_STATUS);
+ uint32_t uncor_mask = igt_pci_config_raw_read_u32(config,
+ aer_cap + PCI_ERR_UNCOR_MASK);
+ uint32_t uncor_severity = igt_pci_config_raw_read_u32(config,
+ aer_cap + PCI_ERR_UNCOR_SEVER);
+ uint32_t cor_status = igt_pci_config_raw_read_u32(config,
+ aer_cap + PCI_ERR_COR_STATUS);
+
+ igt_assert_f(!(uncor_status & uncor_roz),
+ "AER Uncorrectable Error Status: VF ROZ bits are set (0x%08x)\n",
+ uncor_status);
+ igt_assert_f(!(uncor_mask & uncor_roz),
+ "AER Uncorrectable Error Mask: VF ROZ bits are set (0x%08x)\n",
+ uncor_mask);
+ igt_assert_f(!(uncor_severity & uncor_roz),
+ "AER Uncorrectable Error Severity: VF ROZ bits are set (0x%08x)\n",
+ uncor_severity);
+ igt_assert_f(!(cor_status & cor_roz),
+ "AER Correctable Error Status: VF ROZ bits are set (0x%08x)\n",
+ cor_status);
+}
+
+static void check_vf_ats_capability(const uint8_t *config)
+{
+ int ats_cap = get_optional_ext_cap(config, PCI_EXT_CAP_ID_ATS,
+ "ATS capability is not present");
+ uint16_t ats_capability = igt_pci_config_raw_read_u16(config, ats_cap + PCI_ATS_CAP);
+ uint16_t ats_control = igt_pci_config_raw_read_u16(config, ats_cap + PCI_ATS_CTRL);
+
+ igt_assert_f(!PCI_ATS_CAP_QDEP(ats_capability),
+ "ATS Capability: Queue Depth must be zero (0x%04x)\n", ats_capability);
+ igt_assert_f(!PCI_ATS_CTRL_STU(ats_control),
+ "ATS Control: STU must be zero (0x%04x)\n", ats_control);
+}
+
int igt_main()
{
igt_fixture() {
@@ -195,6 +289,22 @@ int igt_main()
igt_subtest("vf-pcie-capabilities-2") {
check_vf_pcie_capabilities_2(vf_config);
}
+
+ igt_describe("Validate the optional VF Power Management capability");
+ igt_subtest("vf-power-management-capability") {
+ check_vf_power_management_capability(vf_config);
+ }
+
+ igt_describe("Validate the optional VF AER capability");
+ igt_subtest("vf-advanced-error-reporting") {
+ check_vf_advanced_error_reporting(vf_config);
+ }
+
+ igt_describe("Validate the optional VF ATS capability");
+ igt_subtest("vf-ats-capability") {
+ check_vf_ats_capability(vf_config);
+ }
+
igt_fixture() {
igt_abort_on_f(pf_fd < 0, "Device is not accessible\n");
igt_sriov_disable_vfs(pf_fd);
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [v2,3/4] tests/sriov_pci_config: Add optional capability checks
2026-09-21 14:37 ` [PATCH v2 3/4] tests/sriov_pci_config: Add optional capability checks Piórkowski, Piotr
@ 2026-09-28 12:49 ` Laguna, Lukasz
0 siblings, 0 replies; 9+ messages in thread
From: Laguna, Lukasz @ 2026-09-28 12:49 UTC (permalink / raw)
To: Piórkowski, Piotr, igt-dev
On 9/21/2026 16:37, Piórkowski, Piotr wrote:
> From: Piotr Piórkowski <piotr.piorkowski@intel.com>
>
> Add subtests for the optional Power Management, Advanced Error
> Reporting, and Address Translation Service capabilities.
> Skip an optional-capability subtest when the capability is not exposed
> by the VF.
> Validate the VF ROZ fields required by the SR-IOV specification,
> including Power Management Data Select/Data, AER status/mask/severity
> fields, and ATS Queue Depth/STU.
>
> v2:
> - Reuse the VF configuration captured by the common fixture.
> - Use PCI register definitions available from linux/pci_regs.h.
> - Simplify optional-capability skips and runtime descriptions.
> - Remove redundant informational messages.
>
> Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com>
> Assisted-by: GPT-5.6 Luna
LGTM,
Reviewed-by: Lukasz Laguna <lukasz.laguna@intel.com>
> ---
> tests/sriov_pci_config.c | 110 +++++++++++++++++++++++++++++++++++++++
> 1 file changed, 110 insertions(+)
>
> diff --git a/tests/sriov_pci_config.c b/tests/sriov_pci_config.c
> index 9f410ef23a..a3d7e86b58 100644
> --- a/tests/sriov_pci_config.c
> +++ b/tests/sriov_pci_config.c
> @@ -43,6 +43,21 @@
> * Description: Validate that the Current De-emphasis Level field in Link
> * Status 2 is RsvdZ and therefore reads as zero for PCIe Capability Version 2
> * and later.
> + *
> + * SUBTEST: vf-power-management-capability
> + * Description: Validate that Data Select in Power Management Control and
> + * Power Management Data are ROZ and therefore read as zero when the optional
> + * Power Management capability is present.
> + *
> + * SUBTEST: vf-advanced-error-reporting
> + * Description: Validate that the specified ROZ bits in AER Uncorrectable
> + * Error Status, Mask, and Severity, and Correctable Error Status read as zero
> + * when the optional AER capability is present.
> + *
> + * SUBTEST: vf-ats-capability
> + * Description: Validate that ATS Queue Depth and the Smallest Translation Unit
> + * (STU) are ROZ and therefore read as zero when the optional ATS capability
> + * is present.
> */
>
> IGT_TEST_DESCRIPTION("Validate PCI configuration fields required for SR-IOV, "
> @@ -161,6 +176,85 @@ static void check_vf_pcie_capabilities_2(const uint8_t *config)
> lnksta2);
> }
>
> +static int get_optional_cap(const uint8_t *config, uint8_t cap_id, const char *name)
> +{
> + int cap = igt_pci_config_raw_find_cap_offset(config, cap_id);
> +
> + igt_assert_f(cap >= 0, "Invalid VF PCI capability list (%d)\n", cap);
> + if (!cap)
> + igt_skip("%s\n", name);
> +
> + return cap;
> +}
> +
> +static int get_optional_ext_cap(const uint8_t *config, uint16_t cap_id, const char *name)
> +{
> + int cap = igt_pci_config_raw_find_ext_cap_offset(config, cap_id);
> +
> + igt_assert_f(cap >= 0, "Invalid VF extended capability list (%d)\n", cap);
> + if (!cap)
> + igt_skip("%s\n", name);
> +
> + return cap;
> +}
> +
> +static void check_vf_power_management_capability(const uint8_t *config)
> +{
> + int pm_cap = get_optional_cap(config, PCI_CAP_ID_PM,
> + "Power Management capability is not present");
> + uint16_t pm_ctrl = igt_pci_config_raw_read_u16(config, pm_cap + PCI_PM_CTRL);
> + uint8_t pm_data = config[pm_cap + PCI_PM_DATA_REGISTER];
> +
> + igt_assert_f(!(pm_ctrl & PCI_PM_CTRL_DATA_SEL_MASK),
> + "Power Management Control: Data Select must be zero (0x%04x)\n", pm_ctrl);
> + igt_assert_f(!pm_data, "Power Management Data: expected 0x00, got 0x%02x\n", pm_data);
> +}
> +
> +static void check_vf_advanced_error_reporting(const uint8_t *config)
> +{
> + const uint32_t uncor_roz = PCI_ERR_UNC_DLP | PCI_ERR_UNC_SURPDN |
> + PCI_ERR_UNC_FCP | PCI_ERR_UNC_RX_OVER |
> + PCI_ERR_UNC_MALF_TLP | PCI_ERR_UNC_ECRC;
> + const uint32_t cor_roz = PCI_ERR_COR_RCVR | PCI_ERR_COR_BAD_TLP |
> + PCI_ERR_COR_REP_ROLL | PCI_ERR_COR_REP_TIMER;
> + int aer_cap = get_optional_ext_cap(config, PCI_EXT_CAP_ID_ERR,
> + "Advanced Error Reporting capability is not present");
> + uint32_t uncor_status = igt_pci_config_raw_read_u32(config,
> + aer_cap + PCI_ERR_UNCOR_STATUS);
> + uint32_t uncor_mask = igt_pci_config_raw_read_u32(config,
> + aer_cap + PCI_ERR_UNCOR_MASK);
> + uint32_t uncor_severity = igt_pci_config_raw_read_u32(config,
> + aer_cap + PCI_ERR_UNCOR_SEVER);
> + uint32_t cor_status = igt_pci_config_raw_read_u32(config,
> + aer_cap + PCI_ERR_COR_STATUS);
> +
> + igt_assert_f(!(uncor_status & uncor_roz),
> + "AER Uncorrectable Error Status: VF ROZ bits are set (0x%08x)\n",
> + uncor_status);
> + igt_assert_f(!(uncor_mask & uncor_roz),
> + "AER Uncorrectable Error Mask: VF ROZ bits are set (0x%08x)\n",
> + uncor_mask);
> + igt_assert_f(!(uncor_severity & uncor_roz),
> + "AER Uncorrectable Error Severity: VF ROZ bits are set (0x%08x)\n",
> + uncor_severity);
> + igt_assert_f(!(cor_status & cor_roz),
> + "AER Correctable Error Status: VF ROZ bits are set (0x%08x)\n",
> + cor_status);
> +}
> +
> +static void check_vf_ats_capability(const uint8_t *config)
> +{
> + int ats_cap = get_optional_ext_cap(config, PCI_EXT_CAP_ID_ATS,
> + "ATS capability is not present");
> + uint16_t ats_capability = igt_pci_config_raw_read_u16(config, ats_cap + PCI_ATS_CAP);
> + uint16_t ats_control = igt_pci_config_raw_read_u16(config, ats_cap + PCI_ATS_CTRL);
> +
> + igt_assert_f(!PCI_ATS_CAP_QDEP(ats_capability),
> + "ATS Capability: Queue Depth must be zero (0x%04x)\n", ats_capability);
> + igt_assert_f(!PCI_ATS_CTRL_STU(ats_control),
> + "ATS Control: STU must be zero (0x%04x)\n", ats_control);
> +}
> +
> int igt_main()
> {
> igt_fixture() {
> @@ -195,6 +289,22 @@ int igt_main()
> igt_subtest("vf-pcie-capabilities-2") {
> check_vf_pcie_capabilities_2(vf_config);
> }
> +
> + igt_describe("Validate the optional VF Power Management capability");
> + igt_subtest("vf-power-management-capability") {
> + check_vf_power_management_capability(vf_config);
> + }
> +
> + igt_describe("Validate the optional VF AER capability");
> + igt_subtest("vf-advanced-error-reporting") {
> + check_vf_advanced_error_reporting(vf_config);
> + }
> +
> + igt_describe("Validate the optional VF ATS capability");
> + igt_subtest("vf-ats-capability") {
> + check_vf_ats_capability(vf_config);
> + }
> +
> igt_fixture() {
> igt_abort_on_f(pf_fd < 0, "Device is not accessible\n");
> igt_sriov_disable_vfs(pf_fd);
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 4/4] intel-ci: Block igt@sriov_pci_config.*
2026-09-21 14:37 [PATCH v2 0/4] Add PCI configuration tests for SR-IOV VFs Piórkowski, Piotr
` (2 preceding siblings ...)
2026-09-21 14:37 ` [PATCH v2 3/4] tests/sriov_pci_config: Add optional capability checks Piórkowski, Piotr
@ 2026-09-21 14:37 ` Piórkowski, Piotr
2026-09-28 12:50 ` [v2,4/4] " Laguna, Lukasz
3 siblings, 1 reply; 9+ messages in thread
From: Piórkowski, Piotr @ 2026-09-21 14:37 UTC (permalink / raw)
To: igt-dev; +Cc: Piotr Piórkowski
From: Piotr Piórkowski <piotr.piorkowski@intel.com>
This test is intended for HW verification and does not need to run in
recurring CI runs.
Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com>
Assisted-by: GPT-5.6 Luna
---
tests/intel-ci/xe.blocklist.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/tests/intel-ci/xe.blocklist.txt b/tests/intel-ci/xe.blocklist.txt
index 0f68df95d5..0a7e63c5ec 100644
--- a/tests/intel-ci/xe.blocklist.txt
+++ b/tests/intel-ci/xe.blocklist.txt
@@ -116,6 +116,7 @@ igt@sriov_basic@bind-unbind-vf$
##################################################################
# SR-IOV tests for HW checkout, not suited for recurring CI runs
##################################################################
+igt@sriov_pci_config.*
igt@xe_sriov_ggtt.*
##################################################################
# Chamelium V1 HDMI receiver supports a maximum resolution
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [v2,4/4] intel-ci: Block igt@sriov_pci_config.*
2026-09-21 14:37 ` [PATCH v2 4/4] intel-ci: Block igt@sriov_pci_config.* Piórkowski, Piotr
@ 2026-09-28 12:50 ` Laguna, Lukasz
0 siblings, 0 replies; 9+ messages in thread
From: Laguna, Lukasz @ 2026-09-28 12:50 UTC (permalink / raw)
To: Piórkowski, Piotr, igt-dev
On 9/21/2026 16:37, Piórkowski, Piotr wrote:
> From: Piotr Piórkowski <piotr.piorkowski@intel.com>
>
> This test is intended for HW verification and does not need to run in
> recurring CI runs.
>
> Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com>
> Assisted-by: GPT-5.6 Luna
LGTM,
Reviewed-by: Lukasz Laguna <lukasz.laguna@intel.com>
> ---
> tests/intel-ci/xe.blocklist.txt | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/tests/intel-ci/xe.blocklist.txt b/tests/intel-ci/xe.blocklist.txt
> index 0f68df95d5..0a7e63c5ec 100644
> --- a/tests/intel-ci/xe.blocklist.txt
> +++ b/tests/intel-ci/xe.blocklist.txt
> @@ -116,6 +116,7 @@ igt@sriov_basic@bind-unbind-vf$
> ##################################################################
> # SR-IOV tests for HW checkout, not suited for recurring CI runs
> ##################################################################
> +igt@sriov_pci_config.*
> igt@xe_sriov_ggtt.*
> ##################################################################
> # Chamelium V1 HDMI receiver supports a maximum resolution
^ permalink raw reply [flat|nested] 9+ messages in thread