* [PATCH v10 0/5] vfio-pci/zdev: Improved zPCI Function Measurement Support
@ 2026-10-20 21:24 Omar Elghoul
2026-10-20 21:24 ` [PATCH v10 1/5] s390/pci: Hold fmb_lock when enabling or disabling PCI devices Omar Elghoul
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Omar Elghoul @ 2026-10-20 21:24 UTC (permalink / raw)
To: linux-s390, linux-kernel, kvm
Cc: oelghoul, hca, gor, agordeev, borntraeger, svens, schnelle,
mjrosato, alifm, farman, gbayer, pasic, alex, frankja, imbrenda
Hi,
This patch series improves support for function measurement for zPCI
passthrough devices on s390.
Changelog
=========
v9 -> v10:
* Patches 2/5 and 3/5:
- Split the old 2/4 into two patches; the new patch 2/5 reuses one FMB
buffer per device, and 3/5 improves FMB state management
- Rework FMB management functions to decouple requesting enablement or
disablement from managing the user's intended state
- Preserve measurement state in pcibios_enable_device()
v8 -> v9:
* Patch 2/4:
- Remove the intermediate disable step from zpci_fmb_reenable_device()
for more uniform semantics
- Rename fmb_enabled to fmb_requested with the intent of tracking the
desired status of FMB enablement
- Make zpci_fmb_enable_device() delegate to zpci_fmb_reenable_device()
* Patch 4/4:
- Set fmb_requested when the user enables measurement
v7 -> v8:
* Patch 2/4:
- Replace the fmb_enabled bitfield in struct zpci_dev with a dedicated
bool to avoid future tearing bugs
- Rewrite commit message for a more natural flow
* Patch 4/4:
- Replace mutex_lock/unlock() in vfio_pci_zdev_feature_fmb_read() with
a scoped_guard()
v6 -> v7:
* Patch 2/4:
- Don't re-enable FMB if it wasn't already enabled
v5 -> v6:
* Patch 2/4:
- Rework the FMB re-enablement code to reuse the same buffer again
- Make the FMB buffer persistent once allocated for as long as the
device's lifetime to accommodate an architectural quirk
* Patch 4/4:
- Update the liveness check to use the new FMB enabled bool
v4 -> v5:
* Typo in the cover letter
* Swap the ordering of patches 3/4 and 4/4 to ease merging (i.e., to
ensure the three s390 patches are ordered before the VFIO patch)
* Patch 2/4:
- Drop the refactor of zpci_fmb_enable_device() and the separation of
zpci_fmb_clear_iommu_ctrs() and zpci_fmb_do_enable()
- Allocate a new buffer in zpci_fmb_reenable_device() rather than
reusing the same buffer to avoid firmware edge cases
* Patch 3/4 (previously 4/4):
- Avoid reading from userspace while holding kzdev_lock unnecessarily
* Patch 4/4 (previously 3/4):
- Drop allowing usercopy of the FMB when initializing the kmem_cache
- Avoid copying to userspace while holding fmb_lock unnecessarily
- Restore the FMB bounce buffer to achieve this one
- Clarify uAPI documentation and ensure it accurately describes the
behavior of the VFIO features
v3 -> v4:
* Patch 2/4:
- Replace mutex_lock/unlock in zpci_reenable_device() with a guard
* Patch 3/4:
- Allow usercopy of the FMB when initializing its kmem_cache
- Move the guard in vfio_pci_zdev_feature_fmb_enable() lower to only
protect the FMB
- Ensure vfio_pci_zdev_feature_fmb_enable() fails on double-enable for
consistency with the documentation
- Eliminate the bounce buffer in vfio_pci_zdev_feature_fmb_read()
- Replace the void pointer with __aligned_u64 in the FMB read uAPI
structure
v2 -> v3:
* Patch 1/4 (new patch):
- Fix race conditions in pcibios_enable/disable_device() with regard to
the FMB enable/disable
- Assert that fmb_lock is held within zpci_fmb_enable_device() and
zpci_fmb_disable_device()
* Patch 2/4 (previously 1/3):
- Move the FMB enable logic into a static function zpci_fmb_do_enable()
to reduce code duplication between zpci_fmb_enable_device() and
zpci_fmb_reenable_device()
- Reword commit message to use the imperative voice more consistently
* Patch 3/4 (previously 2/3):
- Split the previous VFIO feature into a SET-only and a GET-only feature
for enabling/disabling and reading the FMB respectively
- Remove FMB definitions from the VFIO uAPI and instead treat it as an
opaque structure
* Patch 4/4 (previously 3/3):
- Clarify goto label name to reduce misunderstandings
v1 -> v2:
* Patch 1/3:
- Address a possible race condition in zpci_reenable_device() caused by
calling zpci_fmb_reenable_device() without holding fmb_lock
- Assert that fmb_lock is held within zpci_fmb_reenable_device()
* Patch 3/3:
- Address a possible race condition in pci_perf_seq_write() caused by
consuming zdev->kzdev without holding kzdev_lock
Motivation
==========
The firmware on s390x machines allows for tracking a variety of statistics
relating to zPCI devices in a function measurement block (FMB). However,
the kernel currently lacks a structured mechanism of sharing this
information with userspace, beyond /sys/kernel/debug/pci/ID/statistics.
This can lead to shortcomings when running a guest on KVM with PCI
passthrough devices, as QEMU is unable to provide an accurate FMB snapshot
to the guest.
Proposal
========
We propose adding a new VFIO device feature to zPCI passthrough devices,
allowing userspace programs to read the latest FMB snapshot as it is
written by the firmware. We ensure that function measurement enablement is
preserved across device resets on the host. Furthermore, we guard against
host tampering with the FMB via sysfs when the zPCI device is in
passthrough to protect the VM's state.
I'd appreciate some feedback on these patches.
Thanks in advance.
Omar Elghoul (5):
s390/pci: Hold fmb_lock when enabling or disabling PCI devices
s390/pci: Reuse FMB buffer across enable and disable cycles
s390/pci: Improve function measurement state management
s390/pci: Fence FMB enable/disable via debugfs for passthrough devices
vfio-pci/zdev: Add VFIO FMB device features
arch/s390/include/asm/pci.h | 7 ++-
arch/s390/pci/pci.c | 102 ++++++++++++++++++++++++-------
arch/s390/pci/pci_debug.c | 15 ++++-
drivers/vfio/pci/vfio_pci_core.c | 4 ++
drivers/vfio/pci/vfio_pci_priv.h | 18 ++++++
drivers/vfio/pci/vfio_pci_zdev.c | 60 ++++++++++++++++++
include/uapi/linux/vfio.h | 29 +++++++++
7 files changed, 207 insertions(+), 28 deletions(-)
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v10 1/5] s390/pci: Hold fmb_lock when enabling or disabling PCI devices
2026-10-20 21:24 [PATCH v10 0/5] vfio-pci/zdev: Improved zPCI Function Measurement Support Omar Elghoul
@ 2026-10-20 21:24 ` Omar Elghoul
2026-10-20 21:24 ` [PATCH v10 2/5] s390/pci: Reuse FMB buffer across enable and disable cycles Omar Elghoul
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Omar Elghoul @ 2026-10-20 21:24 UTC (permalink / raw)
To: linux-s390, linux-kernel, kvm
Cc: oelghoul, hca, gor, agordeev, borntraeger, svens, schnelle,
mjrosato, alifm, farman, gbayer, pasic, alex, frankja, imbrenda,
stable
Ensure that fmb_lock is held by pcibios_enable_device() and
pcibios_disable_device() when calling zpci_fmb_enable_device() or
zpci_fmb_disable_device(), respectively. Additionally, assert that the
fmb_lock is held within the latter two functions to prevent future race
conditions regarding new callers.
Fixes: af0a8a8453f7 ("s390/pci: implement pcibios_add_device")
Fixes: 944239c59e93 ("s390/pci: implement pcibios_release_device")
Cc: stable@vger.kernel.org
Signed-off-by: Omar Elghoul <oelghoul@linux.ibm.com>
Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
---
arch/s390/pci/pci.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index d64c544b32b0..c055a9ad0972 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -173,6 +173,8 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev)
unsigned long flags;
u8 cc, status;
+ lockdep_assert_held(&zdev->fmb_lock);
+
if (zdev->fmb || sizeof(*zdev->fmb) < zdev->fmb_length)
return -EINVAL;
@@ -211,6 +213,8 @@ int zpci_fmb_disable_device(struct zpci_dev *zdev)
struct zpci_fib fib = {0};
u8 cc, status;
+ lockdep_assert_held(&zdev->fmb_lock);
+
if (!zdev->fmb)
return -EINVAL;
@@ -639,7 +643,9 @@ int pcibios_enable_device(struct pci_dev *pdev, int mask)
struct zpci_dev *zdev = to_zpci(pdev);
zpci_debug_init_device(zdev, dev_name(&pdev->dev));
+ mutex_lock(&zdev->fmb_lock);
zpci_fmb_enable_device(zdev);
+ mutex_unlock(&zdev->fmb_lock);
return pci_enable_resources(pdev, mask);
}
@@ -648,7 +654,9 @@ void pcibios_disable_device(struct pci_dev *pdev)
{
struct zpci_dev *zdev = to_zpci(pdev);
+ mutex_lock(&zdev->fmb_lock);
zpci_fmb_disable_device(zdev);
+ mutex_unlock(&zdev->fmb_lock);
zpci_debug_exit_device(zdev);
}
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v10 2/5] s390/pci: Reuse FMB buffer across enable and disable cycles
2026-10-20 21:24 [PATCH v10 0/5] vfio-pci/zdev: Improved zPCI Function Measurement Support Omar Elghoul
2026-10-20 21:24 ` [PATCH v10 1/5] s390/pci: Hold fmb_lock when enabling or disabling PCI devices Omar Elghoul
@ 2026-10-20 21:24 ` Omar Elghoul
2026-10-20 21:24 ` [PATCH v10 3/5] s390/pci: Improve function measurement state management Omar Elghoul
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Omar Elghoul @ 2026-10-20 21:24 UTC (permalink / raw)
To: linux-s390, linux-kernel, kvm
Cc: oelghoul, hca, gor, agordeev, borntraeger, svens, schnelle,
mjrosato, alifm, farman, gbayer, pasic, alex, frankja, imbrenda
Allocate the FMB once upon first enable and keep it for the lifetime of
the zdev instead of freeing it on every disable. Track the enablement
state in the new statistics_on bool, since a non-null FMB no longer
implies that measurement is enabled. Defer freeing the buffer until
device teardown in zpci_release_device().
Drop the alignment warning after allocating the FMB buffer due to it
already being guaranteed by the kmem_cache.
Audit the only consumer of the FMB (pci_perf_show) and update its
liveness check to be aware of this change.
Signed-off-by: Omar Elghoul <oelghoul@linux.ibm.com>
---
arch/s390/include/asm/pci.h | 1 +
arch/s390/pci/pci.c | 41 ++++++++++++++++++++++---------------
arch/s390/pci/pci_debug.c | 2 +-
3 files changed, 27 insertions(+), 17 deletions(-)
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
index 88a125b92bdd..f4fea1c34746 100644
--- a/arch/s390/include/asm/pci.h
+++ b/arch/s390/include/asm/pci.h
@@ -208,6 +208,7 @@ struct zpci_dev {
struct zpci_fmb *fmb;
u16 fmb_update; /* update interval */
u16 fmb_length;
+ bool statistics_on;
u8 version;
enum pci_bus_speed max_bus_speed;
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index c055a9ad0972..2a7e1ca0fa12 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -175,13 +175,17 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev)
lockdep_assert_held(&zdev->fmb_lock);
- if (zdev->fmb || sizeof(*zdev->fmb) < zdev->fmb_length)
+ if (zdev->statistics_on || sizeof(*zdev->fmb) < zdev->fmb_length)
return -EINVAL;
- zdev->fmb = kmem_cache_zalloc(zdev_fmb_cache, GFP_KERNEL);
- if (!zdev->fmb)
- return -ENOMEM;
- WARN_ON((u64) zdev->fmb & 0xf);
+ if (!zdev->fmb) {
+ zdev->fmb = kmem_cache_zalloc(zdev_fmb_cache, GFP_KERNEL);
+ if (!zdev->fmb)
+ return -ENOMEM;
+ } else {
+ /* reuse the same FMB buffer for as long as the zdev lives */
+ memset(zdev->fmb, 0, sizeof(*zdev->fmb));
+ }
/* reset software counters */
spin_lock_irqsave(&zdev->dom_lock, flags);
@@ -199,11 +203,11 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev)
fib.fmb_addr = virt_to_phys(zdev->fmb);
fib.gd = zdev->gisa;
cc = zpci_mod_fc(req, &fib, &status);
- if (cc) {
- kmem_cache_free(zdev_fmb_cache, zdev->fmb);
- zdev->fmb = NULL;
- }
- return cc ? -EIO : 0;
+ if (cc)
+ return -EIO;
+
+ zdev->statistics_on = true;
+ return 0;
}
/* Modify PCI: Disable PCI function measurement */
@@ -215,7 +219,7 @@ int zpci_fmb_disable_device(struct zpci_dev *zdev)
lockdep_assert_held(&zdev->fmb_lock);
- if (!zdev->fmb)
+ if (!zdev->statistics_on)
return -EINVAL;
fib.gd = zdev->gisa;
@@ -224,12 +228,11 @@ int zpci_fmb_disable_device(struct zpci_dev *zdev)
cc = zpci_mod_fc(req, &fib, &status);
if (cc == 3) /* Function already gone. */
cc = 0;
+ if (cc)
+ return -EIO;
- if (!cc) {
- kmem_cache_free(zdev_fmb_cache, zdev->fmb);
- zdev->fmb = NULL;
- }
- return cc ? -EIO : 0;
+ zdev->statistics_on = false;
+ return 0;
}
static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len)
@@ -1003,6 +1006,12 @@ void zpci_release_device(struct kref *kref)
if (zdev->has_resources)
zpci_cleanup_bus_resources(zdev);
+ if (zdev->fmb) {
+ zdev->statistics_on = false;
+ kmem_cache_free(zdev_fmb_cache, zdev->fmb);
+ zdev->fmb = NULL;
+ }
+
zpci_bus_device_unregister(zdev);
zpci_destroy_iommu(zdev);
zpci_dbg(3, "rem fid:%x\n", zdev->fid);
diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c
index c7ed7bf254b5..419c6a9200a2 100644
--- a/arch/s390/pci/pci_debug.c
+++ b/arch/s390/pci/pci_debug.c
@@ -97,7 +97,7 @@ static int pci_perf_show(struct seq_file *m, void *v)
return 0;
mutex_lock(&zdev->fmb_lock);
- if (!zdev->fmb) {
+ if (!zdev->statistics_on || !zdev->fmb) {
mutex_unlock(&zdev->fmb_lock);
seq_puts(m, "FMB statistics disabled\n");
return 0;
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v10 3/5] s390/pci: Improve function measurement state management
2026-10-20 21:24 [PATCH v10 0/5] vfio-pci/zdev: Improved zPCI Function Measurement Support Omar Elghoul
2026-10-20 21:24 ` [PATCH v10 1/5] s390/pci: Hold fmb_lock when enabling or disabling PCI devices Omar Elghoul
2026-10-20 21:24 ` [PATCH v10 2/5] s390/pci: Reuse FMB buffer across enable and disable cycles Omar Elghoul
@ 2026-10-20 21:24 ` Omar Elghoul
2026-10-20 21:24 ` [PATCH v10 4/5] s390/pci: Fence FMB enable/disable via debugfs for passthrough devices Omar Elghoul
2026-10-20 21:24 ` [PATCH v10 5/5] vfio-pci/zdev: Add VFIO FMB device features Omar Elghoul
4 siblings, 0 replies; 6+ messages in thread
From: Omar Elghoul @ 2026-10-20 21:24 UTC (permalink / raw)
To: linux-s390, linux-kernel, kvm
Cc: oelghoul, hca, gor, agordeev, borntraeger, svens, schnelle,
mjrosato, alifm, farman, gbayer, pasic, alex, frankja, imbrenda
When a zPCI function is disabled and re-enabled, the firmware implicitly
disables function measurement while the kernel still believes it is
enabled, leading to a disconnect between the user-visible state and the
actual device state.
Make statistics_on represent the requested state instead. Introduce the
functions zpci_fmb_request_on() and off(), which call zpci_fmb_enable()
or disable() to perform the actual firmware change. This decouples the
enablement or disablement from managing the user's desired state.
Preserve the state in pcibios_enable_device(), pcibios_disable_device(),
and zpci_reenable_device(), so measurement is restored automatically
after a re-enable. New devices start with measurement on by default,
unchanged from before.
Signed-off-by: Omar Elghoul <oelghoul@linux.ibm.com>
---
arch/s390/include/asm/pci.h | 8 +++--
arch/s390/pci/pci.c | 63 ++++++++++++++++++++++++++++++-------
arch/s390/pci/pci_debug.c | 4 +--
3 files changed, 58 insertions(+), 17 deletions(-)
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
index f4fea1c34746..dd7a17955362 100644
--- a/arch/s390/include/asm/pci.h
+++ b/arch/s390/include/asm/pci.h
@@ -208,7 +208,7 @@ struct zpci_dev {
struct zpci_fmb *fmb;
u16 fmb_update; /* update interval */
u16 fmb_length;
- bool statistics_on;
+ bool statistics_on; /* desired FMB enablement */
u8 version;
enum pci_bus_speed max_bus_speed;
@@ -350,8 +350,10 @@ int zpci_create_parent_msi_domain(struct zpci_bus *zbus);
void zpci_remove_parent_msi_domain(struct zpci_bus *zbus);
/* FMB */
-int zpci_fmb_enable_device(struct zpci_dev *);
-int zpci_fmb_disable_device(struct zpci_dev *);
+int zpci_fmb_request_on(struct zpci_dev *zdev);
+int zpci_fmb_request_off(struct zpci_dev *zdev);
+int zpci_fmb_enable(struct zpci_dev *zdev);
+int zpci_fmb_disable(struct zpci_dev *zdev);
/* Debug */
int zpci_debug_init(void);
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 2a7e1ca0fa12..98a4e938865a 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -165,7 +165,37 @@ int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas)
}
/* Modify PCI: Set PCI function measurement parameters */
-int zpci_fmb_enable_device(struct zpci_dev *zdev)
+int zpci_fmb_request_on(struct zpci_dev *zdev)
+{
+ lockdep_assert_held(&zdev->fmb_lock);
+
+ if (zdev->statistics_on && zdev->fmb)
+ return -EINVAL;
+
+ /*
+ * Record the user's intent first. If the enable fails, the flag stays set
+ * so we can retry enabling the FMB upon the next device (re-)enable. The
+ * consumer can detect that a measurement sample was never written if the
+ * timestamp is still zero, or if the FMB pointer is null.
+ */
+ zdev->statistics_on = true;
+ return zpci_fmb_enable(zdev);
+}
+
+/* Modify PCI: Disable PCI function measurement */
+int zpci_fmb_request_off(struct zpci_dev *zdev)
+{
+ lockdep_assert_held(&zdev->fmb_lock);
+
+ if (!zdev->statistics_on)
+ return -EINVAL;
+
+ zdev->statistics_on = false;
+ return zpci_fmb_disable(zdev);
+}
+EXPORT_SYMBOL_GPL(zpci_fmb_request_off);
+
+int zpci_fmb_enable(struct zpci_dev *zdev)
{
u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_SET_MEASURE);
struct zpci_iommu_ctrs *ctrs;
@@ -175,7 +205,7 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev)
lockdep_assert_held(&zdev->fmb_lock);
- if (zdev->statistics_on || sizeof(*zdev->fmb) < zdev->fmb_length)
+ if (sizeof(*zdev->fmb) < zdev->fmb_length)
return -EINVAL;
if (!zdev->fmb) {
@@ -206,12 +236,11 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev)
if (cc)
return -EIO;
- zdev->statistics_on = true;
return 0;
}
+EXPORT_SYMBOL_GPL(zpci_fmb_enable);
-/* Modify PCI: Disable PCI function measurement */
-int zpci_fmb_disable_device(struct zpci_dev *zdev)
+int zpci_fmb_disable(struct zpci_dev *zdev)
{
u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_SET_MEASURE);
struct zpci_fib fib = {0};
@@ -219,9 +248,6 @@ int zpci_fmb_disable_device(struct zpci_dev *zdev)
lockdep_assert_held(&zdev->fmb_lock);
- if (!zdev->statistics_on)
- return -EINVAL;
-
fib.gd = zdev->gisa;
/* Function measurement is disabled if fmb address is zero */
@@ -231,7 +257,6 @@ int zpci_fmb_disable_device(struct zpci_dev *zdev)
if (cc)
return -EIO;
- zdev->statistics_on = false;
return 0;
}
@@ -647,7 +672,8 @@ int pcibios_enable_device(struct pci_dev *pdev, int mask)
zpci_debug_init_device(zdev, dev_name(&pdev->dev));
mutex_lock(&zdev->fmb_lock);
- zpci_fmb_enable_device(zdev);
+ if (zdev->statistics_on)
+ zpci_fmb_enable(zdev);
mutex_unlock(&zdev->fmb_lock);
return pci_enable_resources(pdev, mask);
@@ -658,7 +684,8 @@ void pcibios_disable_device(struct pci_dev *pdev)
struct zpci_dev *zdev = to_zpci(pdev);
mutex_lock(&zdev->fmb_lock);
- zpci_fmb_disable_device(zdev);
+ if (zdev->statistics_on)
+ zpci_fmb_disable(zdev);
mutex_unlock(&zdev->fmb_lock);
zpci_debug_exit_device(zdev);
}
@@ -740,8 +767,14 @@ int zpci_reenable_device(struct zpci_dev *zdev)
}
rc = zpci_iommu_register_ioat(zdev, &status);
- if (rc)
+ if (rc) {
zpci_disable_device(zdev);
+ return rc;
+ }
+
+ guard(mutex)(&zdev->fmb_lock);
+ if (zdev->statistics_on)
+ zpci_fmb_enable(zdev);
return rc;
}
@@ -850,6 +883,12 @@ struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
goto error;
zdev->state = state;
+ /*
+ * Measurement is on by default for new functions, this will be honored
+ * by pcibios_enable_device().
+ */
+ zdev->statistics_on = true;
+
mutex_init(&zdev->state_lock);
mutex_init(&zdev->fmb_lock);
mutex_init(&zdev->kzdev_lock);
diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c
index 419c6a9200a2..e479763858cd 100644
--- a/arch/s390/pci/pci_debug.c
+++ b/arch/s390/pci/pci_debug.c
@@ -156,10 +156,10 @@ static ssize_t pci_perf_seq_write(struct file *file, const char __user *ubuf,
mutex_lock(&zdev->fmb_lock);
switch (val) {
case 0:
- rc = zpci_fmb_disable_device(zdev);
+ rc = zpci_fmb_request_off(zdev);
break;
case 1:
- rc = zpci_fmb_enable_device(zdev);
+ rc = zpci_fmb_request_on(zdev);
break;
}
mutex_unlock(&zdev->fmb_lock);
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v10 4/5] s390/pci: Fence FMB enable/disable via debugfs for passthrough devices
2026-10-20 21:24 [PATCH v10 0/5] vfio-pci/zdev: Improved zPCI Function Measurement Support Omar Elghoul
` (2 preceding siblings ...)
2026-10-20 21:24 ` [PATCH v10 3/5] s390/pci: Improve function measurement state management Omar Elghoul
@ 2026-10-20 21:24 ` Omar Elghoul
2026-10-20 21:24 ` [PATCH v10 5/5] vfio-pci/zdev: Add VFIO FMB device features Omar Elghoul
4 siblings, 0 replies; 6+ messages in thread
From: Omar Elghoul @ 2026-10-20 21:24 UTC (permalink / raw)
To: linux-s390, linux-kernel, kvm
Cc: oelghoul, hca, gor, agordeev, borntraeger, svens, schnelle,
mjrosato, alifm, farman, gbayer, pasic, alex, frankja, imbrenda
Introduce a fence over enabling or disabling FMB via debugfs when the zPCI
device is associated with a KVM. This will prevent processes on the host
from tampering with the FMB while the guest is still using it, which may
cause partial counter resets and inconsistent reads which have no parallel
in the architecture.
For VFIO devices that are not associated with a KVM (i.e., for userspace
drivers other than QEMU), this fence does not take effect.
Signed-off-by: Omar Elghoul <oelghoul@linux.ibm.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com>
---
arch/s390/pci/pci_debug.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c
index e479763858cd..21d08410799e 100644
--- a/arch/s390/pci/pci_debug.c
+++ b/arch/s390/pci/pci_debug.c
@@ -153,6 +153,12 @@ static ssize_t pci_perf_seq_write(struct file *file, const char __user *ubuf,
if (rc)
return rc;
+ mutex_lock(&zdev->kzdev_lock);
+ if (zdev->kzdev) {
+ rc = -EPERM;
+ goto out_unlock_kzdev;
+ }
+
mutex_lock(&zdev->fmb_lock);
switch (val) {
case 0:
@@ -163,6 +169,9 @@ static ssize_t pci_perf_seq_write(struct file *file, const char __user *ubuf,
break;
}
mutex_unlock(&zdev->fmb_lock);
+
+out_unlock_kzdev:
+ mutex_unlock(&zdev->kzdev_lock);
return rc ? rc : count;
}
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v10 5/5] vfio-pci/zdev: Add VFIO FMB device features
2026-10-20 21:24 [PATCH v10 0/5] vfio-pci/zdev: Improved zPCI Function Measurement Support Omar Elghoul
` (3 preceding siblings ...)
2026-10-20 21:24 ` [PATCH v10 4/5] s390/pci: Fence FMB enable/disable via debugfs for passthrough devices Omar Elghoul
@ 2026-10-20 21:24 ` Omar Elghoul
4 siblings, 0 replies; 6+ messages in thread
From: Omar Elghoul @ 2026-10-20 21:24 UTC (permalink / raw)
To: linux-s390, linux-kernel, kvm
Cc: oelghoul, hca, gor, agordeev, borntraeger, svens, schnelle,
mjrosato, alifm, farman, gbayer, pasic, alex, frankja, imbrenda
Introduce new VFIO features for zPCI devices to provide FMB passthrough to
userspace.
Allow the user to enable or disable the FMB using the SET-only feature
VFIO_DEVICE_FEATURE_ZPCI_FMB_ENABLE. Likewise allow the user to read the
latest FMB using the GET-only feature VFIO_DEVICE_FEATURE_ZPCI_FMB_READ
in the case when the FMB is enabled.
Signed-off-by: Omar Elghoul <oelghoul@linux.ibm.com>
---
drivers/vfio/pci/vfio_pci_core.c | 4 +++
drivers/vfio/pci/vfio_pci_priv.h | 18 ++++++++++
drivers/vfio/pci/vfio_pci_zdev.c | 60 ++++++++++++++++++++++++++++++++
include/uapi/linux/vfio.h | 29 +++++++++++++++
4 files changed, 111 insertions(+)
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index 6757054e9d87..3c827a77725b 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -1627,6 +1627,10 @@ int vfio_pci_core_ioctl_feature(struct vfio_device *device, u32 flags,
return vfio_pci_core_feature_dma_buf(vdev, flags, arg, argsz);
case VFIO_DEVICE_FEATURE_ZPCI_ERROR:
return vfio_pci_zdev_feature_err(device, flags, arg, argsz);
+ case VFIO_DEVICE_FEATURE_ZPCI_FMB_ENABLE:
+ return vfio_pci_zdev_feature_fmb_enable(vdev, flags, arg, argsz);
+ case VFIO_DEVICE_FEATURE_ZPCI_FMB_READ:
+ return vfio_pci_zdev_feature_fmb_read(vdev, flags, arg, argsz);
default:
return -ENOTTY;
}
diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h
index 4e7162234a2e..e04d7e9d0c30 100644
--- a/drivers/vfio/pci/vfio_pci_priv.h
+++ b/drivers/vfio/pci/vfio_pci_priv.h
@@ -95,6 +95,10 @@ int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev);
void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev);
int vfio_pci_zdev_feature_err(struct vfio_device *device, u32 flags,
void __user *arg, size_t argsz);
+int vfio_pci_zdev_feature_fmb_enable(struct vfio_pci_core_device *vdev, u32 flags,
+ void __user *arg, size_t argsz);
+int vfio_pci_zdev_feature_fmb_read(struct vfio_pci_core_device *vdev, u32 flags,
+ void __user *arg, size_t argsz);
#else
static inline int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev,
struct vfio_info_cap *caps)
@@ -116,6 +120,20 @@ static inline int vfio_pci_zdev_feature_err(struct vfio_device *device,
{
return -ENOTTY;
}
+
+static inline int vfio_pci_zdev_feature_fmb_enable(struct vfio_pci_core_device *vdev,
+ u32 flags, void __user *arg,
+ size_t argsz)
+{
+ return -ENOTTY;
+}
+
+static inline int vfio_pci_zdev_feature_fmb_read(struct vfio_pci_core_device *vdev,
+ u32 flags, void __user *arg,
+ size_t argsz)
+{
+ return -ENOTTY;
+}
#endif
static inline bool vfio_pci_is_vga(struct pci_dev *pdev)
diff --git a/drivers/vfio/pci/vfio_pci_zdev.c b/drivers/vfio/pci/vfio_pci_zdev.c
index f47f36314a1c..c2afe60111d7 100644
--- a/drivers/vfio/pci/vfio_pci_zdev.c
+++ b/drivers/vfio/pci/vfio_pci_zdev.c
@@ -219,3 +219,63 @@ void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev)
if (zpci_kvm_hook.kvm_unregister)
zpci_kvm_hook.kvm_unregister(zdev);
}
+
+int vfio_pci_zdev_feature_fmb_enable(struct vfio_pci_core_device *vdev, u32 flags,
+ void __user *arg, size_t argsz)
+{
+ struct zpci_dev *zdev;
+ struct vfio_device_feature_zpci_fmb_enable fmb_enable;
+ int ret;
+
+ ret = vfio_check_feature(flags, argsz, VFIO_DEVICE_FEATURE_SET, sizeof(fmb_enable));
+ if (ret != 1)
+ return ret;
+
+ zdev = to_zpci(vdev->pdev);
+ if (!zdev)
+ return -ENODEV;
+
+ if (copy_from_user(&fmb_enable, arg, sizeof(fmb_enable)))
+ return -EFAULT;
+
+ guard(mutex)(&zdev->fmb_lock);
+
+ if (fmb_enable.enabled) {
+ zdev->statistics_on = true;
+ return zpci_fmb_enable(zdev);
+ }
+
+ return zpci_fmb_request_off(zdev);
+}
+
+int vfio_pci_zdev_feature_fmb_read(struct vfio_pci_core_device *vdev, u32 flags,
+ void __user *arg, size_t argsz)
+{
+ struct zpci_dev *zdev;
+ struct vfio_device_feature_zpci_fmb_read fmb_read;
+ struct zpci_fmb fmb_bounce;
+ int ret;
+
+ ret = vfio_check_feature(flags, argsz, VFIO_DEVICE_FEATURE_GET, sizeof(fmb_read));
+ if (ret != 1)
+ return ret;
+
+ zdev = to_zpci(vdev->pdev);
+ if (!zdev)
+ return -ENODEV;
+
+ if (copy_from_user(&fmb_read, arg, sizeof(fmb_read)))
+ return -EFAULT;
+ if (!fmb_read.data)
+ return -EINVAL;
+
+ scoped_guard(mutex, &zdev->fmb_lock) {
+ if (!zdev->statistics_on || !zdev->fmb)
+ return -ENOMSG;
+ memcpy(&fmb_bounce, zdev->fmb, zdev->fmb_length);
+ }
+
+ if (copy_to_user(u64_to_user_ptr(fmb_read.data), &fmb_bounce, zdev->fmb_length))
+ return -EFAULT;
+ return 0;
+}
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index e41437fa17ad..a8d501e42ef9 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -1555,6 +1555,35 @@ struct vfio_device_feature_zpci_err {
#define VFIO_DEVICE_FEATURE_ZPCI_ERROR 13
+/**
+ * Upon VFIO_DEVICE_FEATURE_SET, enable or disable FMB for the VFIO zPCI device.
+ *
+ * enabled is treated as a bool, so any non-zero value evaluates to true. Nested
+ * enabling resets the FMB counters to zero, and nested disabling fails.
+ *
+ * Returns: 0 on success, -1 and errno set appropriately on error.
+ */
+#define VFIO_DEVICE_FEATURE_ZPCI_FMB_ENABLE 14
+
+struct vfio_device_feature_zpci_fmb_enable {
+ __u8 enabled;
+};
+
+/**
+ * Upon VFIO_DEVICE_FEATURE_GET, provide FMB passthrough for VFIO zPCI devices.
+ *
+ * The user-provided buffer must be at least fmb_length large, where fmb_length
+ * is reported in VFIO_DEVICE_INFO_CAP_ZPCI_BASE.
+ *
+ * Returns: 0 on success, -1 and errno set appropriately on error. errno==ENOMSG
+ * when the FMB is not enabled.
+ */
+#define VFIO_DEVICE_FEATURE_ZPCI_FMB_READ 15
+
+struct vfio_device_feature_zpci_fmb_read {
+ __aligned_u64 data;
+};
+
/* -------- API for Type1 VFIO IOMMU -------- */
/**
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-10-20 21:24 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-20 21:24 [PATCH v10 0/5] vfio-pci/zdev: Improved zPCI Function Measurement Support Omar Elghoul
2026-10-20 21:24 ` [PATCH v10 1/5] s390/pci: Hold fmb_lock when enabling or disabling PCI devices Omar Elghoul
2026-10-20 21:24 ` [PATCH v10 2/5] s390/pci: Reuse FMB buffer across enable and disable cycles Omar Elghoul
2026-10-20 21:24 ` [PATCH v10 3/5] s390/pci: Improve function measurement state management Omar Elghoul
2026-10-20 21:24 ` [PATCH v10 4/5] s390/pci: Fence FMB enable/disable via debugfs for passthrough devices Omar Elghoul
2026-10-20 21:24 ` [PATCH v10 5/5] vfio-pci/zdev: Add VFIO FMB device features Omar Elghoul
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®