@@ -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 */
@@ -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 */
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 <nicolinc@nvidia.com> --- hw/arm/virt-acpi-build.c | 28 ++++++++++++++++++++++++---- include/hw/arm/virt.h | 13 +++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-)