From: Omar Elghoul <oelghoul@linux.ibm.com>
To: linux-s390@vger.kernel.org, linux-kernel@vger.kernel.org,
kvm@vger.kernel.org
Cc: oelghoul@linux.ibm.com, hca@linux.ibm.com, gor@linux.ibm.com,
agordeev@linux.ibm.com, borntraeger@linux.ibm.com,
svens@linux.ibm.com, schnelle@linux.ibm.com,
mjrosato@linux.ibm.com, alifm@linux.ibm.com,
farman@linux.ibm.com, gbayer@linux.ibm.com, pasic@linux.ibm.com,
alex@shazbot.org, frankja@linux.ibm.com, imbrenda@linux.ibm.com
Subject: [PATCH v9 2/4] s390/pci: Reuse FMB buffer and preserve state in device re-enablement
Date: Wed, 7 Oct 2026 09:59:24 -0400 [thread overview]
Message-ID: <20261007135926.82935-3-oelghoul@linux.ibm.com> (raw)
In-Reply-To: <20261007135926.82935-1-oelghoul@linux.ibm.com>
Don't free the FMB buffer when disabling measurement in
zpci_fmb_disable_device(). Instead, make the buffer persistent for the
lifetime of the device and reuse it across enable/disable cycles. Defer
freeing the buffer until teardown in zpci_release_device().
Introduce the bool fmb_requested to struct zpci_dev to track whether FMB
enablement has been requested. This decouples tracking the enablement
from whether the buffer had been previously allocated, allowing us to
account for implicit disablement by firmware in zpci_disable_device().
Audit the only consumer of zdev->fmb and update its liveness check to
reflect this change.
Separate the buffer allocation and measurement enablement step into the
new function zpci_fmb_reenable_device(), which allocates the FMB buffer
on first use, zeroes it on reuse, resets the software IOMMU counters,
and enables measurement. Make zpci_fmb_enable_device() delegate to this
function, and call the latter from zpci_reenable_device() when
fmb_requested is true.
Signed-off-by: Omar Elghoul <oelghoul@linux.ibm.com>
---
arch/s390/include/asm/pci.h | 2 +
arch/s390/pci/pci.c | 106 +++++++++++++++++++++++-------------
arch/s390/pci/pci_debug.c | 2 +-
3 files changed, 70 insertions(+), 40 deletions(-)
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
index 88a125b92bdd..77c8c49ba6c8 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 fmb_requested; /* desired FMB enablement state */
u8 version;
enum pci_bus_speed max_bus_speed;
@@ -351,6 +352,7 @@ 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_reenable_device(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 c055a9ad0972..bda91d79bafd 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -167,43 +167,13 @@ 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)
{
- u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_SET_MEASURE);
- struct zpci_iommu_ctrs *ctrs;
- struct zpci_fib fib = {0};
- unsigned long flags;
- u8 cc, status;
-
lockdep_assert_held(&zdev->fmb_lock);
- if (zdev->fmb || sizeof(*zdev->fmb) < zdev->fmb_length)
+ if (zdev->fmb_requested || 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);
-
- /* reset software counters */
- spin_lock_irqsave(&zdev->dom_lock, flags);
- ctrs = zpci_get_iommu_ctrs(zdev);
- if (ctrs) {
- atomic64_set(&ctrs->mapped_pages, 0);
- atomic64_set(&ctrs->unmapped_pages, 0);
- atomic64_set(&ctrs->global_rpcits, 0);
- atomic64_set(&ctrs->sync_map_rpcits, 0);
- atomic64_set(&ctrs->sync_rpcits, 0);
- }
- spin_unlock_irqrestore(&zdev->dom_lock, flags);
-
-
- 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;
+ zdev->fmb_requested = true;
+ return zpci_fmb_reenable_device(zdev);
}
/* Modify PCI: Disable PCI function measurement */
@@ -215,22 +185,68 @@ int zpci_fmb_disable_device(struct zpci_dev *zdev)
lockdep_assert_held(&zdev->fmb_lock);
- if (!zdev->fmb)
+ if (!zdev->fmb_requested)
return -EINVAL;
+ zdev->fmb_requested = false;
fib.gd = zdev->gisa;
/* Function measurement is disabled if fmb address is zero */
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 0;
+}
+EXPORT_SYMBOL_GPL(zpci_fmb_disable_device);
+
+/* Re-enable PCI function measurement: clear the software IOMMU counters
+ * and (re-)enable the FMB. This function is used to restore the desired
+ * FMB enablement state when measurement may be implicitly disabled by
+ * firmware (i.e., via CLP in zpci_disable_device())
+ */
+int zpci_fmb_reenable_device(struct zpci_dev *zdev)
+{
+ u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_SET_MEASURE);
+ struct zpci_iommu_ctrs *ctrs;
+ struct zpci_fib fib = {0};
+ unsigned long flags;
+ u8 cc, status;
+
+ lockdep_assert_held(&zdev->fmb_lock);
+
+ 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 the zdev lives */
+ memset(zdev->fmb, 0, sizeof(*zdev->fmb));
}
- return cc ? -EIO : 0;
+
+ /* reset software counters */
+ spin_lock_irqsave(&zdev->dom_lock, flags);
+ ctrs = zpci_get_iommu_ctrs(zdev);
+ if (ctrs) {
+ atomic64_set(&ctrs->mapped_pages, 0);
+ atomic64_set(&ctrs->unmapped_pages, 0);
+ atomic64_set(&ctrs->global_rpcits, 0);
+ atomic64_set(&ctrs->sync_map_rpcits, 0);
+ atomic64_set(&ctrs->sync_rpcits, 0);
+ }
+ spin_unlock_irqrestore(&zdev->dom_lock, flags);
+
+ fib.fmb_addr = virt_to_phys(zdev->fmb);
+ fib.gd = zdev->gisa;
+ cc = zpci_mod_fc(req, &fib, &status);
+ if (cc)
+ return -EIO;
+
+ return 0;
}
+EXPORT_SYMBOL_GPL(zpci_fmb_reenable_device);
static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len)
{
@@ -737,8 +753,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->fmb_requested)
+ zpci_fmb_reenable_device(zdev);
return rc;
}
@@ -1003,6 +1025,12 @@ void zpci_release_device(struct kref *kref)
if (zdev->has_resources)
zpci_cleanup_bus_resources(zdev);
+ if (zdev->fmb) {
+ zdev->fmb_requested = 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..9a960310d4dd 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->fmb_requested) {
mutex_unlock(&zdev->fmb_lock);
seq_puts(m, "FMB statistics disabled\n");
return 0;
--
2.56.0
next prev parent reply other threads:[~2026-10-07 13:59 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-07 13:59 [PATCH v9 0/4] vfio-pci/zdev: Improved zPCI Function Measurement Support Omar Elghoul
2026-10-07 13:59 ` [PATCH v9 1/4] s390/pci: Hold fmb_lock when enabling or disabling PCI devices Omar Elghoul
2026-10-07 14:13 ` sashiko-bot
2026-10-07 13:59 ` Omar Elghoul [this message]
2026-10-07 14:11 ` [PATCH v9 2/4] s390/pci: Reuse FMB buffer and preserve state in device re-enablement sashiko-bot
2026-10-07 13:59 ` [PATCH v9 3/4] s390/pci: Fence FMB enable/disable via debugfs for passthrough devices Omar Elghoul
2026-10-07 14:06 ` sashiko-bot
2026-10-07 13:59 ` [PATCH v9 4/4] vfio-pci/zdev: Add VFIO FMB device features Omar Elghoul
2026-10-07 14:07 ` sashiko-bot
2026-10-07 14:24 ` Omar Elghoul
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261007135926.82935-3-oelghoul@linux.ibm.com \
--to=oelghoul@linux.ibm.com \
--cc=agordeev@linux.ibm.com \
--cc=alex@shazbot.org \
--cc=alifm@linux.ibm.com \
--cc=borntraeger@linux.ibm.com \
--cc=farman@linux.ibm.com \
--cc=frankja@linux.ibm.com \
--cc=gbayer@linux.ibm.com \
--cc=gor@linux.ibm.com \
--cc=hca@linux.ibm.com \
--cc=imbrenda@linux.ibm.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-s390@vger.kernel.org \
--cc=mjrosato@linux.ibm.com \
--cc=pasic@linux.ibm.com \
--cc=schnelle@linux.ibm.com \
--cc=svens@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox