Each pxb bus created for a nested SMMU has a reserved bus number, allowing a hotplug device to attach to the bus in a later stage.
Read it out to apply to the id_count calculation. Signed-off-by: Nicolin Chen <nicol...@nvidia.com> --- hw/arm/virt-acpi-build.c | 28 ++++++++++++++++++++++++---- include/hw/arm/virt.h | 13 +++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index d5e72800f6..91f53f90ca 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -236,6 +236,12 @@ build_iort_id_mapping(GArray *table_data, uint32_t input_base, build_append_int_noprefix(table_data, flags, 4); /* Flags */ } +struct AcpiIortIdMappingVM { + VirtMachineState *vms; + GArray *smmu_idmaps; +}; +typedef struct AcpiIortIdMappingVM AcpiIortIdMappingVM; + struct AcpiIortIdMapping { uint32_t input_base; uint32_t id_count; @@ -246,21 +252,34 @@ typedef struct AcpiIortIdMapping AcpiIortIdMapping; static int iort_host_bridges(Object *obj, void *opaque) { - GArray *idmap_blob = opaque; + AcpiIortIdMappingVM *idmap_vm = opaque; + VirtMachineState *vms = idmap_vm->vms; if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) { PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus; if (bus && !pci_bus_bypass_iommu(bus)) { + VirtNestedSmmu *nested_smmu = find_nested_smmu_by_pci_bus(vms, bus); int min_bus, max_bus; - pci_bus_range(bus, &min_bus, &max_bus); + if (vms->iommu == VIRT_IOMMU_NESTED_SMMUV3) { + /* PCI host bridge hehind a nested SMMU has reserved buses */ + if (nested_smmu) { + min_bus = pci_bus_num(nested_smmu->pci_bus); + max_bus = min_bus + nested_smmu->reserved_bus_nums - 1; + } else { + /* Not connected to a nested SMMU */ + return 0; + } + } else { + pci_bus_range(bus, &min_bus, &max_bus); + } AcpiIortIdMapping idmap = { .input_base = min_bus << 8, .id_count = (max_bus - min_bus + 1) << 8, }; - g_array_append_val(idmap_blob, idmap); + g_array_append_val(idmap_vm->smmu_idmaps, idmap); } } @@ -331,6 +350,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) uint32_t id = 0; GArray *smmu_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping)); GArray *its_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping)); + AcpiIortIdMappingVM idmap_vm = { .vms = vms, .smmu_idmaps = smmu_idmaps, }; AcpiTable table = { .sig = "IORT", .rev = 5, .oem_id = vms->oem_id, .oem_table_id = vms->oem_table_id }; @@ -341,7 +361,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) AcpiIortIdMapping next_range = {0}; object_child_foreach_recursive(object_get_root(), - iort_host_bridges, smmu_idmaps); + iort_host_bridges, &idmap_vm); nb_nodes = 3; /* RC, ITS, SMMUv3 */ diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index dfbc4bba3c..7ac392eb88 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -259,4 +259,17 @@ find_nested_smmu_by_sysfs(VirtMachineState *vms, char *node) return NULL; } +static inline VirtNestedSmmu * +find_nested_smmu_by_pci_bus(VirtMachineState *vms, PCIBus *pci_bus) +{ + VirtNestedSmmu *nested_smmu; + + QLIST_FOREACH(nested_smmu, &vms->nested_smmu_list, next) { + if (nested_smmu->pci_bus == pci_bus) { + return nested_smmu; + } + } + return NULL; +} + #endif /* QEMU_ARM_VIRT_H */ -- 2.43.0