1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved 4 */ 5 6 #include "qemu/osdep.h" 7 #include "hw/acpi/acpi_generic_initiator.h" 8 #include "hw/acpi/aml-build.h" 9 #include "hw/boards.h" 10 #include "hw/pci/pci_device.h" 11 #include "qemu/error-report.h" 12 13 typedef struct AcpiGenericInitiatorClass { 14 ObjectClass parent_class; 15 } AcpiGenericInitiatorClass; 16 17 OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericInitiator, acpi_generic_initiator, 18 ACPI_GENERIC_INITIATOR, OBJECT, 19 { TYPE_USER_CREATABLE }, 20 { NULL }) 21 22 OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericInitiator, ACPI_GENERIC_INITIATOR) 23 24 static void acpi_generic_initiator_init(Object *obj) 25 { 26 AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); 27 28 gi->node = MAX_NODES; 29 gi->pci_dev = NULL; 30 } 31 32 static void acpi_generic_initiator_finalize(Object *obj) 33 { 34 AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); 35 36 g_free(gi->pci_dev); 37 } 38 39 static void acpi_generic_initiator_set_pci_device(Object *obj, const char *val, 40 Error **errp) 41 { 42 AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); 43 44 gi->pci_dev = g_strdup(val); 45 } 46 47 static void acpi_generic_initiator_set_node(Object *obj, Visitor *v, 48 const char *name, void *opaque, 49 Error **errp) 50 { 51 AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); 52 MachineState *ms = MACHINE(qdev_get_machine()); 53 uint32_t value; 54 55 if (!visit_type_uint32(v, name, &value, errp)) { 56 return; 57 } 58 59 if (value >= MAX_NODES) { 60 error_printf("%s: Invalid NUMA node specified\n", 61 TYPE_ACPI_GENERIC_INITIATOR); 62 exit(1); 63 } 64 65 gi->node = value; 66 ms->numa_state->nodes[gi->node].has_gi = true; 67 } 68 69 static void acpi_generic_initiator_class_init(ObjectClass *oc, void *data) 70 { 71 object_class_property_add_str(oc, "pci-dev", NULL, 72 acpi_generic_initiator_set_pci_device); 73 object_class_property_add(oc, "node", "int", NULL, 74 acpi_generic_initiator_set_node, NULL, NULL); 75 } 76 77 /* 78 * ACPI 6.3: 79 * Table 5-78 Generic Initiator Affinity Structure 80 */ 81 static void 82 build_srat_generic_pci_initiator_affinity(GArray *table_data, int node, 83 PCIDeviceHandle *handle) 84 { 85 uint8_t index; 86 87 build_append_int_noprefix(table_data, 5, 1); /* Type */ 88 build_append_int_noprefix(table_data, 32, 1); /* Length */ 89 build_append_int_noprefix(table_data, 0, 1); /* Reserved */ 90 build_append_int_noprefix(table_data, 1, 1); /* Device Handle Type: PCI */ 91 build_append_int_noprefix(table_data, node, 4); /* Proximity Domain */ 92 93 /* Device Handle - PCI */ 94 build_append_int_noprefix(table_data, handle->segment, 2); 95 build_append_int_noprefix(table_data, handle->bdf, 2); 96 for (index = 0; index < 12; index++) { 97 build_append_int_noprefix(table_data, 0, 1); 98 } 99 100 build_append_int_noprefix(table_data, GEN_AFFINITY_ENABLED, 4); /* Flags */ 101 build_append_int_noprefix(table_data, 0, 4); /* Reserved */ 102 } 103 104 static int build_all_acpi_generic_initiators(Object *obj, void *opaque) 105 { 106 MachineState *ms = MACHINE(qdev_get_machine()); 107 AcpiGenericInitiator *gi; 108 GArray *table_data = opaque; 109 PCIDeviceHandle dev_handle; 110 PCIDevice *pci_dev; 111 Object *o; 112 113 if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_INITIATOR)) { 114 return 0; 115 } 116 117 gi = ACPI_GENERIC_INITIATOR(obj); 118 if (gi->node >= ms->numa_state->num_nodes) { 119 error_printf("%s: Specified node %d is invalid.\n", 120 TYPE_ACPI_GENERIC_INITIATOR, gi->node); 121 exit(1); 122 } 123 124 o = object_resolve_path_type(gi->pci_dev, TYPE_PCI_DEVICE, NULL); 125 if (!o) { 126 error_printf("%s: Specified device must be a PCI device.\n", 127 TYPE_ACPI_GENERIC_INITIATOR); 128 exit(1); 129 } 130 131 pci_dev = PCI_DEVICE(o); 132 133 dev_handle.segment = 0; 134 dev_handle.bdf = PCI_BUILD_BDF(pci_bus_num(pci_get_bus(pci_dev)), 135 pci_dev->devfn); 136 137 build_srat_generic_pci_initiator_affinity(table_data, 138 gi->node, &dev_handle); 139 140 return 0; 141 } 142 143 void build_srat_generic_pci_initiator(GArray *table_data) 144 { 145 object_child_foreach_recursive(object_get_root(), 146 build_all_acpi_generic_initiators, 147 table_data); 148 } 149