xref: /qemu/hw/acpi/pci.c (revision a82fe82916432091ca6fcbd7f357cccf35f6e80d)
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