When requested on the command-line, by adding topology=on to the virtio-iommu device, provide the IOMMU topology in the virtio config space. It describes which endpoints are managed by the IOMMU - all PCI devices - and allows to support: * virtio-iommu for platforms without ACPI or DT (e.g. microvm), * virtio-iommu for ACPI platforms, temporarily. A new ACPI table will be introduced to handle those, but this provides a boot method in the meantime.
Signed-off-by: Jean-Philippe Brucker <jean-phili...@linaro.org> --- include/hw/virtio/virtio-iommu.h | 3 +++ hw/virtio/virtio-iommu.c | 40 ++++++++++++++++++++++++++++---- hw/virtio/trace-events | 4 ++-- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/include/hw/virtio/virtio-iommu.h b/include/hw/virtio/virtio-iommu.h index ae57efab1f3..7ba1dacf75d 100644 --- a/include/hw/virtio/virtio-iommu.h +++ b/include/hw/virtio/virtio-iommu.h @@ -49,6 +49,7 @@ typedef struct VirtIOIOMMU { VirtQueue *req_vq; VirtQueue *event_vq; struct virtio_iommu_config config; + struct virtio_iommu_topo_pci_range pci_topo; uint64_t features; GHashTable *as_by_busptr; IOMMUPciBus *iommu_pcibus_by_bus_num[PCI_BUS_MAX]; @@ -59,6 +60,8 @@ typedef struct VirtIOIOMMU { QemuMutex mutex; GTree *endpoints; bool boot_bypass; + /* Declare topology in config space */ + bool topology; } VirtIOIOMMU; #endif diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 3b821fc005d..08ab457ccf1 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -731,15 +731,24 @@ unlock: static void virtio_iommu_get_config(VirtIODevice *vdev, uint8_t *config_data) { + off_t offset; VirtIOIOMMU *dev = VIRTIO_IOMMU(vdev); struct virtio_iommu_config *config = &dev->config; + struct virtio_iommu_topo_pci_range *pci_topo = &dev->pci_topo; trace_virtio_iommu_get_config(config->page_size_mask, config->input_range.start, config->input_range.end, config->domain_range.end, - config->probe_size); - memcpy(config_data, &dev->config, sizeof(struct virtio_iommu_config)); + config->probe_size, + config->topo_config.offset, + config->topo_config.count); + memcpy(config_data, config, sizeof(*config)); + + offset = config->topo_config.offset; + if (offset) { + memcpy(config_data + offset, pci_topo, sizeof(*pci_topo)); + } } static void virtio_iommu_set_config(VirtIODevice *vdev, @@ -747,12 +756,14 @@ static void virtio_iommu_set_config(VirtIODevice *vdev, { struct virtio_iommu_config config; - memcpy(&config, config_data, sizeof(struct virtio_iommu_config)); + memcpy(&config, config_data, sizeof(config)); trace_virtio_iommu_set_config(config.page_size_mask, config.input_range.start, config.input_range.end, config.domain_range.end, - config.probe_size); + config.probe_size, + config.topo_config.offset, + config.topo_config.count); } static uint64_t virtio_iommu_get_features(VirtIODevice *vdev, uint64_t f, @@ -776,9 +787,10 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOIOMMU *s = VIRTIO_IOMMU(dev); + size_t aligned_config_size = QEMU_ALIGN_UP(sizeof(s->config), 8); virtio_init(vdev, "virtio-iommu", VIRTIO_ID_IOMMU, - sizeof(struct virtio_iommu_config)); + aligned_config_size + sizeof(s->pci_topo)); memset(s->iommu_pcibus_by_bus_num, 0, sizeof(s->iommu_pcibus_by_bus_num)); @@ -791,6 +803,12 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) s->config.domain_range.end = 32; s->config.probe_size = VIOMMU_PROBE_SIZE; + if (s->topology) { + s->config.topo_config.offset = aligned_config_size; + s->config.topo_config.count = 1; + virtio_add_feature(&s->features, VIRTIO_IOMMU_F_TOPOLOGY); + } + virtio_add_feature(&s->features, VIRTIO_RING_F_EVENT_IDX); virtio_add_feature(&s->features, VIRTIO_RING_F_INDIRECT_DESC); virtio_add_feature(&s->features, VIRTIO_F_VERSION_1); @@ -810,6 +828,17 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) } else { error_setg(errp, "VIRTIO-IOMMU is not attached to any PCI bus!"); } + + if (s->topology) { + s->pci_topo = (struct virtio_iommu_topo_pci_range) { + .type = cpu_to_le16(VIRTIO_IOMMU_TOPO_PCI_RANGE), + .length = cpu_to_le16(sizeof(s->pci_topo)), + .endpoint_start = 0, + .segment = 0, + .bdf_start = 0, + .bdf_end = 0xffff, + }; + } } static void virtio_iommu_device_unrealize(DeviceState *dev) @@ -965,6 +994,7 @@ static const VMStateDescription vmstate_virtio_iommu = { static Property virtio_iommu_properties[] = { DEFINE_PROP_LINK("primary-bus", VirtIOIOMMU, primary_bus, "PCI", PCIBus *), DEFINE_PROP_BOOL("boot-bypass", VirtIOIOMMU, boot_bypass, true), + DEFINE_PROP_BOOL("topology", VirtIOIOMMU, topology, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 045e89cae69..6c5830ca47c 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -59,8 +59,8 @@ virtio_mmio_setting_irq(int level) "virtio_mmio setting IRQ %d" virtio_iommu_device_reset(void) "reset!" virtio_iommu_get_features(uint64_t features) "device supports features=0x%"PRIx64 virtio_iommu_device_status(uint8_t status) "driver status = %d" -virtio_iommu_get_config(uint64_t page_size_mask, uint64_t start, uint64_t end, uint32_t domain_range, uint32_t probe_size) "page_size_mask=0x%"PRIx64" start=0x%"PRIx64" end=0x%"PRIx64" domain_range=%d probe_size=0x%x" -virtio_iommu_set_config(uint64_t page_size_mask, uint64_t start, uint64_t end, uint32_t domain_range, uint32_t probe_size) "page_size_mask=0x%"PRIx64" start=0x%"PRIx64" end=0x%"PRIx64" domain_bits=%d probe_size=0x%x" +virtio_iommu_get_config(uint64_t page_size_mask, uint64_t start, uint64_t end, uint32_t domain_range, uint32_t probe_size, uint16_t topo_offset, uint16_t topo_count) "page_size_mask=0x%"PRIx64" start=0x%"PRIx64" end=0x%"PRIx64" domain_range=%d probe_size=0x%x topo_off=0x%x topo_count=%u" +virtio_iommu_set_config(uint64_t page_size_mask, uint64_t start, uint64_t end, uint32_t domain_range, uint32_t probe_size, uint16_t topo_offset, uint16_t topo_count) "page_size_mask=0x%"PRIx64" start=0x%"PRIx64" end=0x%"PRIx64" domain_bits=%d probe_size=0x%x topo_off=0x%x topo_count=%u" virtio_iommu_attach(uint32_t domain_id, uint32_t ep_id) "domain=%d endpoint=%d" virtio_iommu_detach(uint32_t domain_id, uint32_t ep_id) "domain=%d endpoint=%d" virtio_iommu_map(uint32_t domain_id, uint64_t virt_start, uint64_t virt_end, uint64_t phys_start, uint32_t flags) "domain=%d virt_start=0x%"PRIx64" virt_end=0x%"PRIx64 " phys_start=0x%"PRIx64" flags=%d" -- 2.28.0