On subsystem reset of the s390 PCI host bridge (TYPE_S390_PCI_HOST_BRIDGE),
child buses S390PCIBus and PCIBus are reset in order. Because S390PCIBus
devices are reset first via the legacy reset hook, IOMMU mappings are torn
down before the PCI device itself is reset. For a PCI passthrough device
this opens a window where the device may issue DMA to addresses that no
longer have valid IOMMU mappings, causing an error (PEC 0x7) on the host.

The QEMU reset documentation (docs/devel/reset.rst) specifies that IOMMUs
should perform teardown in the resettable 'exit' phase, after all devices
have completed their 'hold' phase. Move the S390PCIBusDevice reset logic
from the legacy reset hook to the resettable exit phase to close this
window.

Fixes: 3e5cfba3ca0a ("s390x/pci: introduce S390PCIBusDevice qdev")
Cc: [email protected]
Signed-off-by: Farhan Ali <[email protected]>
---
v1: https://lore.kernel.org/all/[email protected]/
v1 -> v2
  - Change to s390_pci_device_reset() to resettable exit function. 

 hw/s390x/s390-pci-bus.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 2724b27ec2..a24ec98c1e 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -1777,9 +1777,9 @@ static void s390_pci_device_realize(DeviceState *dev, 
Error **errp)
     zpci->fmb.format = ZPCI_FMB_FORMAT;
 }
 
-static void s390_pci_device_reset(DeviceState *dev)
+static void s390_pci_device_reset_exit(Object *obj, ResetType type)
 {
-    S390PCIBusDevice *pbdev = S390_PCI_DEVICE(dev);
+    S390PCIBusDevice *pbdev = S390_PCI_DEVICE(obj);
 
     switch (pbdev->state) {
     case ZPCI_FS_RESERVED:
@@ -2010,10 +2010,11 @@ static const VMStateDescription s390_pci_device_vmstate 
= {
 static void s390_pci_device_class_init(ObjectClass *klass, const void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
 
     dc->desc = "zpci device";
     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-    device_class_set_legacy_reset(dc, s390_pci_device_reset);
+    rc->phases.exit = s390_pci_device_reset_exit;
     dc->bus_type = TYPE_S390_PCI_BUS;
     dc->realize = s390_pci_device_realize;
     device_class_set_props(dc, s390_pci_device_properties);
-- 
2.43.0


Reply via email to