With the soon to be introduced user-creatable SMMUv3 devices for virt, it is possible to have multiple SMMUv3 devices associated with different PCIe root complexes.
Update IORT nodes accordingly. An example IORT Id mappings for a Qemu virt machine with two PCIe Root Complexes each assocaited with a SMMUv3 will be something like below, -device arm-smmuv3,primary-bus=pcie.0,id=smmuv3.0 -device arm-smmuv3,primary-bus=pcie.1,id=smmuv3.1 ... +--------------------+ +--------------------+ | Root Complex 0 | | Root Complex 1 | | | | | | Requestor IDs | | Requestor IDs | | 0x0000 - 0x00FF | | 0x0100 - 0x01FF | +---------+----------+ +---------+----------+ | | | | | Stream ID Mapping | v v +--------------------+ +--------------------+ | SMMUv3 Node 0 | | SMMUv3 Node 1 | | | | | | Stream IDs 0x0000- | | Stream IDs 0x0100- | | 0x00FF mapped from | | 0x01FF mapped from | | RC0 Requestor IDs | | RC1 Requestor IDs | +--------------------+ +--------------------+ | | | | +----------------+---------------+ | |Device ID Mapping v +----------------------------+ | ITS Node 0 | | | | Device IDs: | | 0x0000 - 0x00FF (from RC0) | | 0x0100 - 0x01FF (from RC1) | | 0x0200 - 0xFFFF (No SMMU) | +----------------------------+ Tested-by: Nathan Chen <nath...@nvidia.com> Signed-off-by: Shameer Kolothum <shameerali.kolothum.th...@huawei.com> --- hw/arm/virt-acpi-build.c | 55 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index d39506179a..72b79100ce 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -43,6 +43,7 @@ #include "hw/acpi/generic_event_device.h" #include "hw/acpi/tpm.h" #include "hw/acpi/hmat.h" +#include "hw/arm/smmuv3.h" #include "hw/pci/pcie_host.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bus.h" @@ -296,6 +297,58 @@ populate_smmuv3_legacy_dev(GArray *sdev_blob) g_array_append_val(sdev_blob, sdev); } +static int smmuv3_dev_idmap_compare(gconstpointer a, gconstpointer b) +{ + AcpiIortSMMUv3Dev *sdev_a = (AcpiIortSMMUv3Dev *)a; + AcpiIortSMMUv3Dev *sdev_b = (AcpiIortSMMUv3Dev *)b; + AcpiIortIdMapping *map_a = &g_array_index(sdev_a->idmaps, + AcpiIortIdMapping, 0); + AcpiIortIdMapping *map_b = &g_array_index(sdev_b->idmaps, + AcpiIortIdMapping, 0); + return map_a->input_base - map_b->input_base; +} + +static int iort_smmuv3_devices(Object *obj, void *opaque) +{ + VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine()); + GArray *sdev_blob = opaque; + AcpiIortIdMapping idmap; + PlatformBusDevice *pbus; + AcpiIortSMMUv3Dev sdev; + int min_bus, max_bus; + SysBusDevice *sbdev; + PCIBus *bus; + + if (!object_dynamic_cast(obj, TYPE_ARM_SMMUV3)) { + return 0; + } + + bus = PCI_BUS(object_property_get_link(obj, "primary-bus", &error_abort)); + pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev); + sbdev = SYS_BUS_DEVICE(obj); + sdev.base = platform_bus_get_mmio_addr(pbus, sbdev, 0); + sdev.base += vms->memmap[VIRT_PLATFORM_BUS].base; + sdev.irq = platform_bus_get_irqn(pbus, sbdev, 0); + sdev.irq += vms->irqmap[VIRT_PLATFORM_BUS]; + sdev.irq += ARM_SPI_BASE; + + pci_bus_range(bus, &min_bus, &max_bus); + sdev.idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping)); + idmap.input_base = min_bus << 8, + idmap.id_count = (max_bus - min_bus + 1) << 8, + g_array_append_val(sdev.idmaps, idmap); + g_array_append_val(sdev_blob, sdev); + return 0; +} + +static void populate_smmuv3_dev(GArray *sdev_blob) +{ + object_child_foreach_recursive(object_get_root(), + iort_smmuv3_devices, sdev_blob); + /* Sort the smmuv3 devices(if any) by smmu idmap input_base */ + g_array_sort(sdev_blob, smmuv3_dev_idmap_compare); +} + /* * Input Output Remapping Table (IORT) * Conforms to "IO Remapping Table System Software on ARM Platforms", @@ -320,6 +373,8 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) nb_nodes = 2; /* RC, ITS */ if (vms->legacy_smmuv3_present) { populate_smmuv3_legacy_dev(smmuv3_devs); + } else { + populate_smmuv3_dev(smmuv3_devs); } num_smmus = smmuv3_devs->len; -- 2.47.0