On 10/26/26 1:13 PM, Farhan Ali wrote:
> 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]>

Thanks Farhan - I think this looks good, but I believe there's still
something off here that could either be fixed in this patch or with a
2nd patch before this one.

My concern is the interplay between the unplug_requested flag and the
FMB -- I think in the unlikely event we pcihost_reset() when
unplug_requested is set we would now miss freeing the FMB timer because
we won't actually end up driving s390_pci_device_reset_exit().  That's
because pcihost_reset is still operating on the legacy interface (i.e.
it gets run during the hold phase so the device gets removed from the
bus before the exit phase)

I think the simple answer would be to make sure the FMB timer is freed
in s390_pcihost_unplug() e.g. by calling fmb_timer_free() during
TYPE_S390_PCI_DEVICE handling.  If it was already called before there
will be no timer to cancel and the FMB will just get re-zero'd one last
time.

Could you take a closer look?

Thanks,
Matt

> ---
> 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);


Reply via email to