@@ -1788,6 +1788,12 @@ static void spapr_phb_unrealize(DeviceState *dev, Error **errp)
memory_region_del_subregion(&sphb->iommu_root, &sphb->msiwindow);
+ /*
+ * An attached PCI device may have memory listeners, eg. VFIO PCI. We have
+ * unmapped all sections. Remove the listeners now, before destroying the
+ * address space.
+ */
+ address_space_remove_listeners(&sphb->iommu_as);
address_space_destroy(&sphb->iommu_as);
qbus_set_hotplug_handler(BUS(phb->bus), NULL, &error_abort);
@@ -1757,6 +1757,16 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name);
*/
void address_space_destroy(AddressSpace *as);
+/**
+ * address_space_remove_listeners: unregister all listeners of an address space
+ *
+ * Removes all callbacks previously registered with memory_listener_register()
+ * for @as.
+ *
+ * @as: an initialized #AddressSpace
+ */
+void address_space_remove_listeners(AddressSpace *as);
+
/**
* address_space_rw: read from or write to an address space.
*
@@ -2723,6 +2723,13 @@ void memory_listener_unregister(MemoryListener *listener)
listener->address_space = NULL;
}
+void address_space_remove_listeners(AddressSpace *as)
+{
+ while (!QTAILQ_EMPTY(&as->listeners)) {
+ memory_listener_unregister(QTAILQ_FIRST(&as->listeners));
+ }
+}
+
void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
{
memory_region_ref(root);