@@ -99,7 +99,12 @@ static void pcibus_machine_done(Notifier *notifier, void *data)
for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
if (bus->devices[i]) {
- pci_init_bus_master(bus->devices[i]);
+ PCIDevice *pci_dev = bus->devices[i];
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
+ pci_init_bus_master(pci_dev);
+ if (pc->bus_master_ready) {
+ pc->bus_master_ready(pci_dev);
+ }
}
}
}
@@ -1845,6 +1845,14 @@ static void virtio_pci_exit(PCIDevice *pci_dev)
address_space_destroy(&proxy->modern_as);
}
+static void virtio_pci_bus_master_ready(PCIDevice *pci_dev)
+{
+ VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);
+ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
+
+ virtio_device_reset_dma_as(vdev);
+}
+
static void virtio_pci_reset(DeviceState *qdev)
{
VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev);
@@ -1904,6 +1912,7 @@ static void virtio_pci_class_init(ObjectClass *klass, void *data)
dc->props = virtio_pci_properties;
k->realize = virtio_pci_realize;
k->exit = virtio_pci_exit;
+ k->bus_master_ready = virtio_pci_bus_master_ready;
k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
k->revision = VIRTIO_PCI_ABI_VERSION;
k->class_id = PCI_CLASS_OTHERS;
@@ -2594,6 +2594,25 @@ bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev)
return virtio_bus_ioeventfd_enabled(vbus);
}
+void virtio_device_reset_dma_as(VirtIODevice *vdev)
+{
+ DeviceState *qdev = DEVICE(vdev);
+ BusState *qbus = BUS(qdev_get_parent_bus(qdev));
+ VirtioBusState *bus = VIRTIO_BUS(qbus);
+ VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
+ bool has_iommu = virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
+
+ if (klass->get_dma_as != NULL && has_iommu) {
+ vdev->dma_as = klass->get_dma_as(qbus->parent);
+ } else {
+ vdev->dma_as = &address_space_memory;
+ }
+
+ memory_listener_unregister(&vdev->listener);
+ memory_listener_register(&vdev->listener, vdev->dma_as);
+}
+
+
static const TypeInfo virtio_device_info = {
.name = TYPE_VIRTIO_DEVICE,
.parent = TYPE_DEVICE,
@@ -207,6 +207,7 @@ typedef struct PCIDeviceClass {
void (*realize)(PCIDevice *dev, Error **errp);
int (*init)(PCIDevice *dev);/* TODO convert to realize() and remove */
+ void (*bus_master_ready)(PCIDevice *dev);
PCIUnregisterFunc *exit;
PCIConfigReadFunc *config_read;
PCIConfigWriteFunc *config_write;
@@ -283,6 +283,7 @@ void virtio_device_stop_ioeventfd(VirtIODevice *vdev);
int virtio_device_grab_ioeventfd(VirtIODevice *vdev);
void virtio_device_release_ioeventfd(VirtIODevice *vdev);
bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev);
+void virtio_device_reset_dma_as(VirtIODevice *vdev);
EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
void virtio_queue_host_notifier_read(EventNotifier *n);
void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx,
After commit 96a8821d2141 ("virtio: unbreak virtio-pci with IOMMU after caching ring translations"), IOMMU was required to be created in advance. This is because we can only get the correct dma_as after pci IOMMU (e.g intel_iommu) was initialized. This is suboptimal and inconvenient for user. This patch releases this by: - introduce a bus_master_ready method for PCIDeviceClass and trigger this during pci_init_bus_master - implement virtio-pci method and 1) reset the dma_as 2) re-register the memory listener to the new dma_as Cc: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Jason Wang <jasowang@redhat.com> --- Changes from v1: - only call bus_master_ready() from pcibus_machine_done() to avoid break hotplug. --- hw/pci/pci.c | 7 ++++++- hw/virtio/virtio-pci.c | 9 +++++++++ hw/virtio/virtio.c | 19 +++++++++++++++++++ include/hw/pci/pci.h | 1 + include/hw/virtio/virtio.h | 1 + 5 files changed, 36 insertions(+), 1 deletion(-)