[PATCH v11 3/5] s390/pci: Reuse FMB buffer across enable and disable cycles
From: Omar Elghoul
Date: Wed Oct 28 2026 - 12:03:13 EST
Allocate the FMB once upon first enable and keep it for the lifetime of
the zdev instead of freeing it on every disable. 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.
Signed-off-by: Omar Elghoul <oelghoul@xxxxxxxxxxxxx>
---
arch/s390/pci/pci.c | 31 +++++++++++++++----------------
1 file changed, 15 insertions(+), 16 deletions(-)
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 5889dd227009..a7e548a83bc1 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -211,13 +211,17 @@ int zpci_fmb_enable(struct zpci_dev *zdev)
lockdep_assert_held(&zdev->fmb_lock);
- if (zdev->fmb || sizeof(*zdev->fmb) < zdev->fmb_length)
+ if (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);
@@ -235,10 +239,6 @@ int zpci_fmb_enable(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;
}
@@ -251,9 +251,6 @@ int zpci_fmb_disable(struct zpci_dev *zdev)
lockdep_assert_held(&zdev->fmb_lock);
- if (!zdev->fmb)
- return -EINVAL;
-
fib.gd = zdev->gisa;
/* Function measurement is disabled if fmb address is zero */
@@ -261,10 +258,6 @@ int zpci_fmb_disable(struct zpci_dev *zdev)
if (cc == 3) /* Function already gone. */
cc = 0;
- if (!cc) {
- kmem_cache_free(zdev_fmb_cache, zdev->fmb);
- zdev->fmb = NULL;
- }
return cc ? -EIO : 0;
}
@@ -1053,6 +1046,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);
--
2.56.0