@@ -68,3 +68,102 @@ static void acpi_generic_initiator_class_init(ObjectClass *oc, void *data)
object_class_property_add(oc, "host-nodes", "int", NULL,
acpi_generic_initiator_set_host_nodes, NULL, NULL);
}
+
+static int acpi_generic_initiator_list(Object *obj, void *opaque)
+{
+ GSList **list = opaque;
+
+ if (object_dynamic_cast(obj, TYPE_ACPI_GENERIC_INITIATOR)) {
+ *list = g_slist_append(*list, ACPI_GENERIC_INITIATOR(obj));
+ }
+
+ object_child_foreach(obj, acpi_generic_initiator_list, opaque);
+ return 0;
+}
+
+/*
+ * Identify Generic Initiator objects and link them into the list which is
+ * returned to the caller.
+ *
+ * Note: it is the caller's responsibility to free the list to avoid
+ * memory leak.
+ */
+static GSList *acpi_generic_initiator_get_list(void)
+{
+ GSList *list = NULL;
+
+ object_child_foreach(object_get_root(),
+ acpi_generic_initiator_list, &list);
+ return list;
+}
+
+/*
+ * ACPI 6.3:
+ * Table 5-78 Generic Initiator Affinity Structure
+ */
+static void
+build_srat_generic_pci_initiator_affinity(GArray *table_data, int node,
+ PCIDeviceHandle *handle)
+{
+ uint8_t index;
+
+ build_append_int_noprefix(table_data, 5, 1); /* Type */
+ build_append_int_noprefix(table_data, 32, 1); /* Length */
+ build_append_int_noprefix(table_data, 0, 1); /* Reserved */
+ build_append_int_noprefix(table_data, 1, 1); /* Device Handle Type: PCI */
+ build_append_int_noprefix(table_data, node, 4); /* Proximity Domain */
+
+ /* Device Handle - PCI */
+ build_append_int_noprefix(table_data, handle->segment, 2);
+ build_append_int_noprefix(table_data, handle->bdf, 2);
+ for (index = 0; index < 12; index++) {
+ build_append_int_noprefix(table_data, 0, 1);
+ }
+
+ build_append_int_noprefix(table_data, GEN_AFFINITY_ENABLED, 4); /* Flags */
+ build_append_int_noprefix(table_data, 0, 4); /* Reserved */
+}
+
+void build_srat_generic_pci_initiator(GArray *table_data)
+{
+ GSList *gi_list, *list = acpi_generic_initiator_get_list();
+ AcpiGenericInitiator *gi;
+
+ for (gi_list = list; gi_list; gi_list = gi_list->next) {
+ Object *o;
+ uint16_t node;
+ PCIDevice *pci_dev;
+ bool node_specified = false;
+
+ gi = gi_list->data;
+
+ o = object_resolve_path_type(gi->pci_dev, TYPE_PCI_DEVICE, NULL);
+ if (!o) {
+ error_printf("Specified device must be a PCI device.\n");
+ exit(1);
+ }
+ pci_dev = PCI_DEVICE(o);
+
+ for (node = 0; (node = find_next_bit(gi->host_nodes,
+ MAX_NODES, node)) != MAX_NODES; node++)
+ {
+ PCIDeviceHandle dev_handle;
+ dev_handle.segment = 0;
+ dev_handle.bdf = PCI_BUILD_BDF(pci_bus_num(pci_get_bus(pci_dev)),
+ pci_dev->devfn);
+ build_srat_generic_pci_initiator_affinity(table_data,
+ node, &dev_handle);
+ node_specified = true;
+ }
+
+ if (!node_specified) {
+ error_report("Generic Initiator device 0:%x:%x.%x has no associated"
+ " NUMA node.", pci_bus_num(pci_get_bus(pci_dev)),
+ PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn));
+ error_printf("Specify NUMA node with -host-nodes option.\n");
+ exit(1);
+ }
+ }
+
+ g_slist_free(list);
+}
@@ -58,6 +58,7 @@
#include "migration/vmstate.h"
#include "hw/acpi/ghes.h"
#include "hw/acpi/viot.h"
+#include "hw/acpi/acpi-generic-initiator.h"
#define ARM_SPI_BASE 32
@@ -558,6 +559,8 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
}
}
+ build_srat_generic_pci_initiator(table_data);
+
if (ms->nvdimms_state->is_enabled) {
nvdimm_build_srat(table_data);
}
@@ -24,4 +24,30 @@ typedef struct AcpiGenericInitiatorClass {
ObjectClass parent_class;
} AcpiGenericInitiatorClass;
+/*
+ * ACPI 6.3:
+ * Table 5-81 Flags – Generic Initiator Affinity Structure
+ */
+typedef enum {
+ GEN_AFFINITY_ENABLED = (1 << 0), /*
+ * If clear, the OSPM ignores the contents
+ * of the Generic Initiator/Port Affinity
+ * Structure. This allows system firmware
+ * to populate the SRAT with a static
+ * number of structures, but only enable
+ * them as necessary.
+ */
+} GenericAffinityFlags;
+
+/*
+ * ACPI 6.3:
+ * Table 5-80 Device Handle - PCI
+ */
+typedef struct PCIDeviceHandle {
+ uint16_t segment;
+ uint16_t bdf;
+} PCIDeviceHandle;
+
+void build_srat_generic_pci_initiator(GArray *table_data);
+
#endif