1f13a944cSWei Yang /* 2f13a944cSWei Yang * Support for generating PCI related ACPI tables and passing them to Guests 3f13a944cSWei Yang * 4f13a944cSWei Yang * Copyright (C) 2006 Fabrice Bellard 5f13a944cSWei Yang * Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net> 6f13a944cSWei Yang * Copyright (C) 2013-2019 Red Hat Inc 7f13a944cSWei Yang * Copyright (C) 2019 Intel Corporation 8f13a944cSWei Yang * 9f13a944cSWei Yang * Author: Wei Yang <richardw.yang@linux.intel.com> 10f13a944cSWei Yang * Author: Michael S. Tsirkin <mst@redhat.com> 11f13a944cSWei Yang * 12f13a944cSWei Yang * This program is free software; you can redistribute it and/or modify 13f13a944cSWei Yang * it under the terms of the GNU General Public License as published by 14f13a944cSWei Yang * the Free Software Foundation; either version 2 of the License, or 15f13a944cSWei Yang * (at your option) any later version. 16f13a944cSWei Yang 17f13a944cSWei Yang * This program is distributed in the hope that it will be useful, 18f13a944cSWei Yang * but WITHOUT ANY WARRANTY; without even the implied warranty of 19f13a944cSWei Yang * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20f13a944cSWei Yang * GNU General Public License for more details. 21f13a944cSWei Yang 22f13a944cSWei Yang * You should have received a copy of the GNU General Public License along 23f13a944cSWei Yang * with this program; if not, see <http://www.gnu.org/licenses/>. 24f13a944cSWei Yang */ 25f13a944cSWei Yang 26f13a944cSWei Yang #include "qemu/osdep.h" 27f74e7822SJonathan Cameron #include "qemu/error-report.h" 28f74e7822SJonathan Cameron #include "qom/object_interfaces.h" 29f74e7822SJonathan Cameron #include "qapi/error.h" 30f74e7822SJonathan Cameron #include "hw/boards.h" 31f13a944cSWei Yang #include "hw/acpi/aml-build.h" 32f13a944cSWei Yang #include "hw/acpi/pci.h" 33*a82fe829SJonathan Cameron #include "hw/pci/pci_bridge.h" 34f74e7822SJonathan Cameron #include "hw/pci/pci_device.h" 35f13a944cSWei Yang #include "hw/pci/pcie_host.h" 36f13a944cSWei Yang 37e4610781SWei Yang /* 38e4610781SWei Yang * PCI Firmware Specification, Revision 3.0 39e4610781SWei Yang * 4.1.2 MCFG Table Description. 40e4610781SWei Yang */ 41578bc7a0SIgor Mammedov void build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info, 42578bc7a0SIgor Mammedov const char *oem_id, const char *oem_table_id) 43578bc7a0SIgor Mammedov { 44578bc7a0SIgor Mammedov AcpiTable table = { .sig = "MCFG", .rev = 1, 45578bc7a0SIgor Mammedov .oem_id = oem_id, .oem_table_id = oem_table_id }; 46578bc7a0SIgor Mammedov 47578bc7a0SIgor Mammedov acpi_table_begin(&table, table_data); 48578bc7a0SIgor Mammedov 49e4610781SWei Yang /* Reserved */ 50e4610781SWei Yang build_append_int_noprefix(table_data, 0, 8); 51e4610781SWei Yang /* 52e4610781SWei Yang * Memory Mapped Enhanced Configuration Space Base Address Allocation 53e4610781SWei Yang * Structure 54e4610781SWei Yang */ 55e4610781SWei Yang /* Base address, processor-relative */ 56e4610781SWei Yang build_append_int_noprefix(table_data, info->base, 8); 57e4610781SWei Yang /* PCI segment group number */ 58e4610781SWei Yang build_append_int_noprefix(table_data, 0, 2); 59e4610781SWei Yang /* Starting PCI Bus number */ 60e4610781SWei Yang build_append_int_noprefix(table_data, 0, 1); 61e4610781SWei Yang /* Final PCI Bus number */ 62e4610781SWei Yang build_append_int_noprefix(table_data, PCIE_MMCFG_BUS(info->size - 1), 1); 63e4610781SWei Yang /* Reserved */ 64e4610781SWei Yang build_append_int_noprefix(table_data, 0, 4); 65f13a944cSWei Yang 66578bc7a0SIgor Mammedov acpi_table_end(linker, &table); 67f13a944cSWei Yang } 68f74e7822SJonathan Cameron 69f74e7822SJonathan Cameron typedef struct AcpiGenericInitiator { 70f74e7822SJonathan Cameron /* private */ 71f74e7822SJonathan Cameron Object parent; 72f74e7822SJonathan Cameron 73f74e7822SJonathan Cameron /* public */ 74f74e7822SJonathan Cameron char *pci_dev; 75f74e7822SJonathan Cameron uint16_t node; 76f74e7822SJonathan Cameron } AcpiGenericInitiator; 77f74e7822SJonathan Cameron 78f74e7822SJonathan Cameron typedef struct AcpiGenericInitiatorClass { 79f74e7822SJonathan Cameron ObjectClass parent_class; 80f74e7822SJonathan Cameron } AcpiGenericInitiatorClass; 81f74e7822SJonathan Cameron 82f74e7822SJonathan Cameron #define TYPE_ACPI_GENERIC_INITIATOR "acpi-generic-initiator" 83f74e7822SJonathan Cameron 84f74e7822SJonathan Cameron OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericInitiator, acpi_generic_initiator, 85f74e7822SJonathan Cameron ACPI_GENERIC_INITIATOR, OBJECT, 86f74e7822SJonathan Cameron { TYPE_USER_CREATABLE }, 87f74e7822SJonathan Cameron { NULL }) 88f74e7822SJonathan Cameron 89f74e7822SJonathan Cameron OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericInitiator, ACPI_GENERIC_INITIATOR) 90f74e7822SJonathan Cameron 91f74e7822SJonathan Cameron static void acpi_generic_initiator_init(Object *obj) 92f74e7822SJonathan Cameron { 93f74e7822SJonathan Cameron AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); 94f74e7822SJonathan Cameron 95f74e7822SJonathan Cameron gi->node = MAX_NODES; 96f74e7822SJonathan Cameron gi->pci_dev = NULL; 97f74e7822SJonathan Cameron } 98f74e7822SJonathan Cameron 99f74e7822SJonathan Cameron static void acpi_generic_initiator_finalize(Object *obj) 100f74e7822SJonathan Cameron { 101f74e7822SJonathan Cameron AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); 102f74e7822SJonathan Cameron 103f74e7822SJonathan Cameron g_free(gi->pci_dev); 104f74e7822SJonathan Cameron } 105f74e7822SJonathan Cameron 106f74e7822SJonathan Cameron static void acpi_generic_initiator_set_pci_device(Object *obj, const char *val, 107f74e7822SJonathan Cameron Error **errp) 108f74e7822SJonathan Cameron { 109f74e7822SJonathan Cameron AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); 110f74e7822SJonathan Cameron 111f74e7822SJonathan Cameron gi->pci_dev = g_strdup(val); 112f74e7822SJonathan Cameron } 113f74e7822SJonathan Cameron 114f74e7822SJonathan Cameron static void acpi_generic_initiator_set_node(Object *obj, Visitor *v, 115f74e7822SJonathan Cameron const char *name, void *opaque, 116f74e7822SJonathan Cameron Error **errp) 117f74e7822SJonathan Cameron { 118f74e7822SJonathan Cameron AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); 119f74e7822SJonathan Cameron MachineState *ms = MACHINE(qdev_get_machine()); 120f74e7822SJonathan Cameron uint32_t value; 121f74e7822SJonathan Cameron 122f74e7822SJonathan Cameron if (!visit_type_uint32(v, name, &value, errp)) { 123f74e7822SJonathan Cameron return; 124f74e7822SJonathan Cameron } 125f74e7822SJonathan Cameron 126f74e7822SJonathan Cameron if (value >= MAX_NODES) { 127f74e7822SJonathan Cameron error_printf("%s: Invalid NUMA node specified\n", 128f74e7822SJonathan Cameron TYPE_ACPI_GENERIC_INITIATOR); 129f74e7822SJonathan Cameron exit(1); 130f74e7822SJonathan Cameron } 131f74e7822SJonathan Cameron 132f74e7822SJonathan Cameron gi->node = value; 133f74e7822SJonathan Cameron ms->numa_state->nodes[gi->node].has_gi = true; 134f74e7822SJonathan Cameron } 135f74e7822SJonathan Cameron 136f74e7822SJonathan Cameron static void acpi_generic_initiator_class_init(ObjectClass *oc, void *data) 137f74e7822SJonathan Cameron { 138f74e7822SJonathan Cameron object_class_property_add_str(oc, "pci-dev", NULL, 139f74e7822SJonathan Cameron acpi_generic_initiator_set_pci_device); 140f74e7822SJonathan Cameron object_class_property_add(oc, "node", "int", NULL, 141f74e7822SJonathan Cameron acpi_generic_initiator_set_node, NULL, NULL); 142f74e7822SJonathan Cameron } 143f74e7822SJonathan Cameron 144f74e7822SJonathan Cameron static int build_acpi_generic_initiator(Object *obj, void *opaque) 145f74e7822SJonathan Cameron { 146f74e7822SJonathan Cameron MachineState *ms = MACHINE(qdev_get_machine()); 147f74e7822SJonathan Cameron AcpiGenericInitiator *gi; 148f74e7822SJonathan Cameron GArray *table_data = opaque; 149f74e7822SJonathan Cameron int32_t devfn; 150f74e7822SJonathan Cameron uint8_t bus; 151f74e7822SJonathan Cameron Object *o; 152f74e7822SJonathan Cameron 153f74e7822SJonathan Cameron if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_INITIATOR)) { 154f74e7822SJonathan Cameron return 0; 155f74e7822SJonathan Cameron } 156f74e7822SJonathan Cameron 157f74e7822SJonathan Cameron gi = ACPI_GENERIC_INITIATOR(obj); 158f74e7822SJonathan Cameron if (gi->node >= ms->numa_state->num_nodes) { 159f74e7822SJonathan Cameron error_printf("%s: Specified node %d is invalid.\n", 160f74e7822SJonathan Cameron TYPE_ACPI_GENERIC_INITIATOR, gi->node); 161f74e7822SJonathan Cameron exit(1); 162f74e7822SJonathan Cameron } 163f74e7822SJonathan Cameron 164f74e7822SJonathan Cameron o = object_resolve_path_type(gi->pci_dev, TYPE_PCI_DEVICE, NULL); 165f74e7822SJonathan Cameron if (!o) { 166f74e7822SJonathan Cameron error_printf("%s: Specified device must be a PCI device.\n", 167f74e7822SJonathan Cameron TYPE_ACPI_GENERIC_INITIATOR); 168f74e7822SJonathan Cameron exit(1); 169f74e7822SJonathan Cameron } 170f74e7822SJonathan Cameron 171f74e7822SJonathan Cameron bus = object_property_get_uint(o, "busnr", &error_fatal); 172f74e7822SJonathan Cameron devfn = object_property_get_uint(o, "addr", &error_fatal); 173f74e7822SJonathan Cameron /* devfn is constrained in PCI to be 8 bit but storage is an int32_t */ 174f74e7822SJonathan Cameron assert(devfn >= 0 && devfn < PCI_DEVFN_MAX); 175f74e7822SJonathan Cameron 176f74e7822SJonathan Cameron build_srat_pci_generic_initiator(table_data, gi->node, 0, bus, devfn); 177f74e7822SJonathan Cameron 178f74e7822SJonathan Cameron return 0; 179f74e7822SJonathan Cameron } 180f74e7822SJonathan Cameron 181*a82fe829SJonathan Cameron typedef struct AcpiGenericPort { 182*a82fe829SJonathan Cameron /* private */ 183*a82fe829SJonathan Cameron Object parent; 184*a82fe829SJonathan Cameron 185*a82fe829SJonathan Cameron /* public */ 186*a82fe829SJonathan Cameron char *pci_bus; 187*a82fe829SJonathan Cameron uint32_t node; 188*a82fe829SJonathan Cameron } AcpiGenericPort; 189*a82fe829SJonathan Cameron 190*a82fe829SJonathan Cameron typedef struct AcpiGenericPortClass { 191*a82fe829SJonathan Cameron ObjectClass parent_class; 192*a82fe829SJonathan Cameron } AcpiGenericPortClass; 193*a82fe829SJonathan Cameron 194*a82fe829SJonathan Cameron #define TYPE_ACPI_GENERIC_PORT "acpi-generic-port" 195*a82fe829SJonathan Cameron 196*a82fe829SJonathan Cameron OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericPort, acpi_generic_port, 197*a82fe829SJonathan Cameron ACPI_GENERIC_PORT, OBJECT, 198*a82fe829SJonathan Cameron { TYPE_USER_CREATABLE }, 199*a82fe829SJonathan Cameron { NULL }) 200*a82fe829SJonathan Cameron 201*a82fe829SJonathan Cameron OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericPort, ACPI_GENERIC_PORT) 202*a82fe829SJonathan Cameron 203*a82fe829SJonathan Cameron static void acpi_generic_port_init(Object *obj) 204*a82fe829SJonathan Cameron { 205*a82fe829SJonathan Cameron AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj); 206*a82fe829SJonathan Cameron 207*a82fe829SJonathan Cameron gp->node = MAX_NODES; 208*a82fe829SJonathan Cameron gp->pci_bus = NULL; 209*a82fe829SJonathan Cameron } 210*a82fe829SJonathan Cameron 211*a82fe829SJonathan Cameron static void acpi_generic_port_finalize(Object *obj) 212*a82fe829SJonathan Cameron { 213*a82fe829SJonathan Cameron AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj); 214*a82fe829SJonathan Cameron 215*a82fe829SJonathan Cameron g_free(gp->pci_bus); 216*a82fe829SJonathan Cameron } 217*a82fe829SJonathan Cameron 218*a82fe829SJonathan Cameron static void acpi_generic_port_set_pci_bus(Object *obj, const char *val, 219*a82fe829SJonathan Cameron Error **errp) 220*a82fe829SJonathan Cameron { 221*a82fe829SJonathan Cameron AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj); 222*a82fe829SJonathan Cameron 223*a82fe829SJonathan Cameron gp->pci_bus = g_strdup(val); 224*a82fe829SJonathan Cameron } 225*a82fe829SJonathan Cameron 226*a82fe829SJonathan Cameron static void acpi_generic_port_set_node(Object *obj, Visitor *v, 227*a82fe829SJonathan Cameron const char *name, void *opaque, 228*a82fe829SJonathan Cameron Error **errp) 229*a82fe829SJonathan Cameron { 230*a82fe829SJonathan Cameron AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj); 231*a82fe829SJonathan Cameron uint32_t value; 232*a82fe829SJonathan Cameron 233*a82fe829SJonathan Cameron if (!visit_type_uint32(v, name, &value, errp)) { 234*a82fe829SJonathan Cameron return; 235*a82fe829SJonathan Cameron } 236*a82fe829SJonathan Cameron 237*a82fe829SJonathan Cameron if (value >= MAX_NODES) { 238*a82fe829SJonathan Cameron error_printf("%s: Invalid NUMA node specified\n", 239*a82fe829SJonathan Cameron TYPE_ACPI_GENERIC_INITIATOR); 240*a82fe829SJonathan Cameron exit(1); 241*a82fe829SJonathan Cameron } 242*a82fe829SJonathan Cameron 243*a82fe829SJonathan Cameron gp->node = value; 244*a82fe829SJonathan Cameron } 245*a82fe829SJonathan Cameron 246*a82fe829SJonathan Cameron static void acpi_generic_port_class_init(ObjectClass *oc, void *data) 247*a82fe829SJonathan Cameron { 248*a82fe829SJonathan Cameron object_class_property_add_str(oc, "pci-bus", NULL, 249*a82fe829SJonathan Cameron acpi_generic_port_set_pci_bus); 250*a82fe829SJonathan Cameron object_class_property_set_description(oc, "pci-bus", 251*a82fe829SJonathan Cameron "PCI Bus of the host bridge associated with this GP affinity structure"); 252*a82fe829SJonathan Cameron object_class_property_add(oc, "node", "int", NULL, 253*a82fe829SJonathan Cameron acpi_generic_port_set_node, NULL, NULL); 254*a82fe829SJonathan Cameron object_class_property_set_description(oc, "node", 255*a82fe829SJonathan Cameron "The NUMA node like ID to index HMAT/SLIT NUMA properties involving GP"); 256*a82fe829SJonathan Cameron } 257*a82fe829SJonathan Cameron 258*a82fe829SJonathan Cameron static int build_acpi_generic_port(Object *obj, void *opaque) 259*a82fe829SJonathan Cameron { 260*a82fe829SJonathan Cameron MachineState *ms = MACHINE(qdev_get_machine()); 261*a82fe829SJonathan Cameron const char *hid = "ACPI0016"; 262*a82fe829SJonathan Cameron GArray *table_data = opaque; 263*a82fe829SJonathan Cameron AcpiGenericPort *gp; 264*a82fe829SJonathan Cameron uint32_t uid; 265*a82fe829SJonathan Cameron Object *o; 266*a82fe829SJonathan Cameron 267*a82fe829SJonathan Cameron if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_PORT)) { 268*a82fe829SJonathan Cameron return 0; 269*a82fe829SJonathan Cameron } 270*a82fe829SJonathan Cameron 271*a82fe829SJonathan Cameron gp = ACPI_GENERIC_PORT(obj); 272*a82fe829SJonathan Cameron 273*a82fe829SJonathan Cameron if (gp->node >= ms->numa_state->num_nodes) { 274*a82fe829SJonathan Cameron error_printf("%s: node %d is invalid.\n", 275*a82fe829SJonathan Cameron TYPE_ACPI_GENERIC_PORT, gp->node); 276*a82fe829SJonathan Cameron exit(1); 277*a82fe829SJonathan Cameron } 278*a82fe829SJonathan Cameron 279*a82fe829SJonathan Cameron o = object_resolve_path_type(gp->pci_bus, TYPE_PXB_CXL_BUS, NULL); 280*a82fe829SJonathan Cameron if (!o) { 281*a82fe829SJonathan Cameron error_printf("%s: device must be a CXL host bridge.\n", 282*a82fe829SJonathan Cameron TYPE_ACPI_GENERIC_PORT); 283*a82fe829SJonathan Cameron exit(1); 284*a82fe829SJonathan Cameron } 285*a82fe829SJonathan Cameron 286*a82fe829SJonathan Cameron uid = object_property_get_uint(o, "acpi_uid", &error_fatal); 287*a82fe829SJonathan Cameron build_srat_acpi_generic_port(table_data, gp->node, hid, uid); 288*a82fe829SJonathan Cameron 289*a82fe829SJonathan Cameron return 0; 290*a82fe829SJonathan Cameron } 291*a82fe829SJonathan Cameron 292*a82fe829SJonathan Cameron void build_srat_generic_affinity_structures(GArray *table_data) 293f74e7822SJonathan Cameron { 294f74e7822SJonathan Cameron object_child_foreach_recursive(object_get_root(), 295f74e7822SJonathan Cameron build_acpi_generic_initiator, 296f74e7822SJonathan Cameron table_data); 297*a82fe829SJonathan Cameron object_child_foreach_recursive(object_get_root(), build_acpi_generic_port, 298*a82fe829SJonathan Cameron table_data); 299f74e7822SJonathan Cameron } 300