#include "hw/acpi/generic_event_device.h"
#include "hw/acpi/tpm.h"
#include "hw/acpi/hmat.h"
+#include "hw/arm/smmuv3.h"
#include "hw/cxl/cxl.h"
#include "hw/pci/pcie_host.h"
#include "hw/pci/pci.h"
return sdev.rc_smmu_idmaps->len;
}
+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->rc_smmu_idmaps,
+ AcpiIortIdMapping, 0);
+ AcpiIortIdMapping *map_b = &g_array_index(sdev_b->rc_smmu_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.rc_smmu_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.rc_smmu_idmaps, idmap);
+ g_array_append_val(sdev_blob, sdev);
+ return 0;
+}
+
+/*
+ * Populate the struct AcpiIortSMMUv3Dev for all SMMUv3 devices and
+ * return the total number of idmaps.
+ */
+static int 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);
+ /*
+ * Since each SMMUv3 dev is assocaited with specific host bridge,
+ * total number of idmaps equals to total number of smmuv3 devices.
+ */
+ return sdev_blob->len;
+}
+
/* Compute ID ranges (RIDs) from RC that are directed to the ITS Group node */
static void create_rc_its_idmaps(GArray *its_idmaps, GArray *smmuv3_devs)
{
if (vms->legacy_smmuv3_present) {
rc_smmu_idmaps_len = populate_smmuv3_legacy_dev(smmuv3_devs);
+ } else {
+ rc_smmu_idmaps_len = populate_smmuv3_dev(smmuv3_devs);
}
num_smmus = smmuv3_devs->len;