pci_device_reset(pbdev->pdev);
}
-static void s390_pci_reset_cb(void *opaque)
-{
- S390PCIBusDevice *pbdev = opaque;
-
- pci_device_reset(pbdev->pdev);
-}
-
static void s390_pci_perform_unplug(S390PCIBusDevice *pbdev)
{
HotplugHandler *hotplug_ctrl;
if (pbdev->pft == ZPCI_PFT_ISM) {
notifier_remove(&pbdev->shutdown_notifier);
- qemu_unregister_reset(s390_pci_reset_cb, pbdev);
}
/* Unplug the PCI device */
if (pbdev->pft == ZPCI_PFT_ISM) {
pbdev->shutdown_notifier.notify = s390_pci_shutdown_notifier;
qemu_register_shutdown_notifier(&pbdev->shutdown_notifier);
- qemu_register_reset(s390_pci_reset_cb, pbdev);
}
} else {
pbdev->fh |= FH_SHM_EMUL;
pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, s->bus_no, 1);
}
+void s390_pci_ism_reset(void)
+{
+ S390pciState *s = s390_get_phb();
+
+ S390PCIBusDevice *pbdev, *next;
+
+ /* Trigger reset event for each passthrough ISM device currently in-use */
+ QTAILQ_FOREACH_SAFE(pbdev, &s->zpci_devs, link, next) {
+ if (pbdev->interp && pbdev->pft == ZPCI_PFT_ISM &&
+ pbdev->fh & FH_MASK_ENABLE) {
+ s390_pci_kvm_aif_disable(pbdev);
+
+ pci_device_reset(pbdev->pdev);
+ }
+ }
+}
+
static void s390_pcihost_reset(DeviceState *dev)
{
S390pciState *s = S390_PCI_HOST_BRIDGE(dev);
DeviceState *dev;
int i;
+ /*
+ * ISM firmware is sensitive to unexpected changes to the IOMMU, which can
+ * occur during reset of the vfio-pci device (unmap of entire aperture).
+ * Ensure any passthrough ISM devices are reset now, while CPUs are paused
+ * but before vfio-pci cleanup occurs.
+ */
+ s390_pci_ism_reset();
+
for (i = 0; i < ARRAY_SIZE(reset_dev_types); i++) {
dev = DEVICE(object_resolve_path_type("", reset_dev_types[i], NULL));
if (dev) {