diff options
Diffstat (limited to 'hw/acpi/viot.c')
-rw-r--r-- | hw/acpi/viot.c | 107 |
1 files changed, 68 insertions, 39 deletions
diff --git a/hw/acpi/viot.c b/hw/acpi/viot.c index c1af75206e..4e0bf69067 100644 --- a/hw/acpi/viot.c +++ b/hw/acpi/viot.c @@ -10,17 +10,40 @@ #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" -struct viot_pci_ranges { - GArray *blob; - size_t count; - uint16_t output_node; +struct viot_pci_host_range { + int min_bus; + int max_bus; }; +static void build_pci_host_range(GArray *table_data, int min_bus, int max_bus, + uint16_t output_node) +{ + /* Type */ + build_append_int_noprefix(table_data, 1 /* PCI range */, 1); + /* Reserved */ + build_append_int_noprefix(table_data, 0, 1); + /* Length */ + build_append_int_noprefix(table_data, 24, 2); + /* Endpoint start */ + build_append_int_noprefix(table_data, PCI_BUILD_BDF(min_bus, 0), 4); + /* PCI Segment start */ + build_append_int_noprefix(table_data, 0, 2); + /* PCI Segment end */ + build_append_int_noprefix(table_data, 0, 2); + /* PCI BDF start */ + build_append_int_noprefix(table_data, PCI_BUILD_BDF(min_bus, 0), 2); + /* PCI BDF end */ + build_append_int_noprefix(table_data, PCI_BUILD_BDF(max_bus, 0xff), 2); + /* Output node */ + build_append_int_noprefix(table_data, output_node, 2); + /* Reserved */ + build_append_int_noprefix(table_data, 0, 6); +} + /* Build PCI range for a given PCI host bridge */ -static int build_pci_range_node(Object *obj, void *opaque) +static int enumerate_pci_host_bridges(Object *obj, void *opaque) { - struct viot_pci_ranges *pci_ranges = opaque; - GArray *blob = pci_ranges->blob; + GArray *pci_host_ranges = opaque; if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) { PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus; @@ -30,34 +53,31 @@ static int build_pci_range_node(Object *obj, void *opaque) pci_bus_range(bus, &min_bus, &max_bus); - /* Type */ - build_append_int_noprefix(blob, 1 /* PCI range */, 1); - /* Reserved */ - build_append_int_noprefix(blob, 0, 1); - /* Length */ - build_append_int_noprefix(blob, 24, 2); - /* Endpoint start */ - build_append_int_noprefix(blob, PCI_BUILD_BDF(min_bus, 0), 4); - /* PCI Segment start */ - build_append_int_noprefix(blob, 0, 2); - /* PCI Segment end */ - build_append_int_noprefix(blob, 0, 2); - /* PCI BDF start */ - build_append_int_noprefix(blob, PCI_BUILD_BDF(min_bus, 0), 2); - /* PCI BDF end */ - build_append_int_noprefix(blob, PCI_BUILD_BDF(max_bus, 0xff), 2); - /* Output node */ - build_append_int_noprefix(blob, pci_ranges->output_node, 2); - /* Reserved */ - build_append_int_noprefix(blob, 0, 6); - - pci_ranges->count++; + const struct viot_pci_host_range pci_host_range = { + .min_bus = min_bus, + .max_bus = max_bus, + }; + g_array_append_val(pci_host_ranges, pci_host_range); } } return 0; } +static gint pci_host_range_compare(gconstpointer a, gconstpointer b) +{ + struct viot_pci_host_range *range_a = (struct viot_pci_host_range *)a; + struct viot_pci_host_range *range_b = (struct viot_pci_host_range *)b; + + if (range_a->min_bus < range_b->min_bus) { + return -1; + } else if (range_a->min_bus > range_b->min_bus) { + return 1; + } else { + return 0; + } +} + /* * Generate a VIOT table with one PCI-based virtio-iommu that manages PCI * endpoints. @@ -72,19 +92,22 @@ void build_viot(MachineState *ms, GArray *table_data, BIOSLinker *linker, int viommu_off = 48; AcpiTable table = { .sig = "VIOT", .rev = 0, .oem_id = oem_id, .oem_table_id = oem_table_id }; - struct viot_pci_ranges pci_ranges = { - .output_node = viommu_off, - .blob = g_array_new(false, true /* clear */, 1), - }; + GArray *pci_host_ranges = g_array_new(false, true, + sizeof(struct viot_pci_host_range)); + struct viot_pci_host_range *pci_host_range; + int i; /* Build the list of PCI ranges that this viommu manages */ - object_child_foreach_recursive(OBJECT(ms), build_pci_range_node, - &pci_ranges); + object_child_foreach_recursive(OBJECT(ms), enumerate_pci_host_bridges, + pci_host_ranges); + + /* Sort the pci host ranges by min_bus */ + g_array_sort(pci_host_ranges, pci_host_range_compare); /* ACPI table header */ acpi_table_begin(&table, table_data); /* Node count */ - build_append_int_noprefix(table_data, pci_ranges.count + 1, 2); + build_append_int_noprefix(table_data, pci_host_ranges->len + 1, 2); /* Node offset */ build_append_int_noprefix(table_data, viommu_off, 2); /* Reserved */ @@ -105,9 +128,15 @@ void build_viot(MachineState *ms, GArray *table_data, BIOSLinker *linker, build_append_int_noprefix(table_data, 0, 8); /* PCI ranges found above */ - g_array_append_vals(table_data, pci_ranges.blob->data, - pci_ranges.blob->len); - g_array_free(pci_ranges.blob, true); + for (i = 0; i < pci_host_ranges->len; i++) { + pci_host_range = &g_array_index(pci_host_ranges, + struct viot_pci_host_range, i); + + build_pci_host_range(table_data, pci_host_range->min_bus, + pci_host_range->max_bus, viommu_off); + } + + g_array_free(pci_host_ranges, true); acpi_table_end(linker, &table); } |