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"
33a82fe829SJonathan 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 */
build_mcfg(GArray * table_data,BIOSLinker * linker,AcpiMcfgInfo * info,const char * oem_id,const char * oem_table_id)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;
75cf2181aeSJonathan Cameron uint32_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
OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericInitiator,ACPI_GENERIC_INITIATOR)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
acpi_generic_initiator_finalize(Object * obj)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
acpi_generic_initiator_set_pci_device(Object * obj,const char * val,Error ** errp)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
acpi_generic_initiator_set_node(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)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
acpi_generic_initiator_class_init(ObjectClass * oc,void * data)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);
140*df37d496SJonathan Cameron object_class_property_set_description(oc, "pci-dev",
141*df37d496SJonathan Cameron "PCI device to associate with the node");
142f74e7822SJonathan Cameron object_class_property_add(oc, "node", "int", NULL,
143f74e7822SJonathan Cameron acpi_generic_initiator_set_node, NULL, NULL);
144*df37d496SJonathan Cameron object_class_property_set_description(oc, "node",
145*df37d496SJonathan Cameron "NUMA node associated with the PCI device");
146f74e7822SJonathan Cameron }
147f74e7822SJonathan Cameron
build_acpi_generic_initiator(Object * obj,void * opaque)148f74e7822SJonathan Cameron static int build_acpi_generic_initiator(Object *obj, void *opaque)
149f74e7822SJonathan Cameron {
150f74e7822SJonathan Cameron MachineState *ms = MACHINE(qdev_get_machine());
151f74e7822SJonathan Cameron AcpiGenericInitiator *gi;
152f74e7822SJonathan Cameron GArray *table_data = opaque;
153f74e7822SJonathan Cameron int32_t devfn;
154f74e7822SJonathan Cameron uint8_t bus;
155f74e7822SJonathan Cameron Object *o;
156f74e7822SJonathan Cameron
157f74e7822SJonathan Cameron if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_INITIATOR)) {
158f74e7822SJonathan Cameron return 0;
159f74e7822SJonathan Cameron }
160f74e7822SJonathan Cameron
161f74e7822SJonathan Cameron gi = ACPI_GENERIC_INITIATOR(obj);
162f74e7822SJonathan Cameron if (gi->node >= ms->numa_state->num_nodes) {
163f74e7822SJonathan Cameron error_printf("%s: Specified node %d is invalid.\n",
164f74e7822SJonathan Cameron TYPE_ACPI_GENERIC_INITIATOR, gi->node);
165f74e7822SJonathan Cameron exit(1);
166f74e7822SJonathan Cameron }
167f74e7822SJonathan Cameron
168f74e7822SJonathan Cameron o = object_resolve_path_type(gi->pci_dev, TYPE_PCI_DEVICE, NULL);
169f74e7822SJonathan Cameron if (!o) {
170f74e7822SJonathan Cameron error_printf("%s: Specified device must be a PCI device.\n",
171f74e7822SJonathan Cameron TYPE_ACPI_GENERIC_INITIATOR);
172f74e7822SJonathan Cameron exit(1);
173f74e7822SJonathan Cameron }
174f74e7822SJonathan Cameron
175f74e7822SJonathan Cameron bus = object_property_get_uint(o, "busnr", &error_fatal);
176f74e7822SJonathan Cameron devfn = object_property_get_uint(o, "addr", &error_fatal);
177f74e7822SJonathan Cameron /* devfn is constrained in PCI to be 8 bit but storage is an int32_t */
178f74e7822SJonathan Cameron assert(devfn >= 0 && devfn < PCI_DEVFN_MAX);
179f74e7822SJonathan Cameron
180f74e7822SJonathan Cameron build_srat_pci_generic_initiator(table_data, gi->node, 0, bus, devfn);
181f74e7822SJonathan Cameron
182f74e7822SJonathan Cameron return 0;
183f74e7822SJonathan Cameron }
184f74e7822SJonathan Cameron
185a82fe829SJonathan Cameron typedef struct AcpiGenericPort {
186a82fe829SJonathan Cameron /* private */
187a82fe829SJonathan Cameron Object parent;
188a82fe829SJonathan Cameron
189a82fe829SJonathan Cameron /* public */
190a82fe829SJonathan Cameron char *pci_bus;
191a82fe829SJonathan Cameron uint32_t node;
192a82fe829SJonathan Cameron } AcpiGenericPort;
193a82fe829SJonathan Cameron
194a82fe829SJonathan Cameron typedef struct AcpiGenericPortClass {
195a82fe829SJonathan Cameron ObjectClass parent_class;
196a82fe829SJonathan Cameron } AcpiGenericPortClass;
197a82fe829SJonathan Cameron
198a82fe829SJonathan Cameron #define TYPE_ACPI_GENERIC_PORT "acpi-generic-port"
199a82fe829SJonathan Cameron
200a82fe829SJonathan Cameron OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericPort, acpi_generic_port,
201a82fe829SJonathan Cameron ACPI_GENERIC_PORT, OBJECT,
202a82fe829SJonathan Cameron { TYPE_USER_CREATABLE },
203a82fe829SJonathan Cameron { NULL })
204a82fe829SJonathan Cameron
OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericPort,ACPI_GENERIC_PORT)205a82fe829SJonathan Cameron OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericPort, ACPI_GENERIC_PORT)
206a82fe829SJonathan Cameron
207a82fe829SJonathan Cameron static void acpi_generic_port_init(Object *obj)
208a82fe829SJonathan Cameron {
209a82fe829SJonathan Cameron AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
210a82fe829SJonathan Cameron
211a82fe829SJonathan Cameron gp->node = MAX_NODES;
212a82fe829SJonathan Cameron gp->pci_bus = NULL;
213a82fe829SJonathan Cameron }
214a82fe829SJonathan Cameron
acpi_generic_port_finalize(Object * obj)215a82fe829SJonathan Cameron static void acpi_generic_port_finalize(Object *obj)
216a82fe829SJonathan Cameron {
217a82fe829SJonathan Cameron AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
218a82fe829SJonathan Cameron
219a82fe829SJonathan Cameron g_free(gp->pci_bus);
220a82fe829SJonathan Cameron }
221a82fe829SJonathan Cameron
acpi_generic_port_set_pci_bus(Object * obj,const char * val,Error ** errp)222a82fe829SJonathan Cameron static void acpi_generic_port_set_pci_bus(Object *obj, const char *val,
223a82fe829SJonathan Cameron Error **errp)
224a82fe829SJonathan Cameron {
225a82fe829SJonathan Cameron AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
226a82fe829SJonathan Cameron
227a82fe829SJonathan Cameron gp->pci_bus = g_strdup(val);
228a82fe829SJonathan Cameron }
229a82fe829SJonathan Cameron
acpi_generic_port_set_node(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)230a82fe829SJonathan Cameron static void acpi_generic_port_set_node(Object *obj, Visitor *v,
231a82fe829SJonathan Cameron const char *name, void *opaque,
232a82fe829SJonathan Cameron Error **errp)
233a82fe829SJonathan Cameron {
234a82fe829SJonathan Cameron AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
235a82fe829SJonathan Cameron uint32_t value;
236a82fe829SJonathan Cameron
237a82fe829SJonathan Cameron if (!visit_type_uint32(v, name, &value, errp)) {
238a82fe829SJonathan Cameron return;
239a82fe829SJonathan Cameron }
240a82fe829SJonathan Cameron
241a82fe829SJonathan Cameron if (value >= MAX_NODES) {
242a82fe829SJonathan Cameron error_printf("%s: Invalid NUMA node specified\n",
243a82fe829SJonathan Cameron TYPE_ACPI_GENERIC_INITIATOR);
244a82fe829SJonathan Cameron exit(1);
245a82fe829SJonathan Cameron }
246a82fe829SJonathan Cameron
247a82fe829SJonathan Cameron gp->node = value;
248a82fe829SJonathan Cameron }
249a82fe829SJonathan Cameron
acpi_generic_port_class_init(ObjectClass * oc,void * data)250a82fe829SJonathan Cameron static void acpi_generic_port_class_init(ObjectClass *oc, void *data)
251a82fe829SJonathan Cameron {
252a82fe829SJonathan Cameron object_class_property_add_str(oc, "pci-bus", NULL,
253a82fe829SJonathan Cameron acpi_generic_port_set_pci_bus);
254a82fe829SJonathan Cameron object_class_property_set_description(oc, "pci-bus",
255a82fe829SJonathan Cameron "PCI Bus of the host bridge associated with this GP affinity structure");
256a82fe829SJonathan Cameron object_class_property_add(oc, "node", "int", NULL,
257a82fe829SJonathan Cameron acpi_generic_port_set_node, NULL, NULL);
258a82fe829SJonathan Cameron object_class_property_set_description(oc, "node",
259a82fe829SJonathan Cameron "The NUMA node like ID to index HMAT/SLIT NUMA properties involving GP");
260a82fe829SJonathan Cameron }
261a82fe829SJonathan Cameron
build_acpi_generic_port(Object * obj,void * opaque)262a82fe829SJonathan Cameron static int build_acpi_generic_port(Object *obj, void *opaque)
263a82fe829SJonathan Cameron {
264a82fe829SJonathan Cameron MachineState *ms = MACHINE(qdev_get_machine());
265a82fe829SJonathan Cameron const char *hid = "ACPI0016";
266a82fe829SJonathan Cameron GArray *table_data = opaque;
267a82fe829SJonathan Cameron AcpiGenericPort *gp;
268a82fe829SJonathan Cameron uint32_t uid;
269a82fe829SJonathan Cameron Object *o;
270a82fe829SJonathan Cameron
271a82fe829SJonathan Cameron if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_PORT)) {
272a82fe829SJonathan Cameron return 0;
273a82fe829SJonathan Cameron }
274a82fe829SJonathan Cameron
275a82fe829SJonathan Cameron gp = ACPI_GENERIC_PORT(obj);
276a82fe829SJonathan Cameron
277a82fe829SJonathan Cameron if (gp->node >= ms->numa_state->num_nodes) {
278a82fe829SJonathan Cameron error_printf("%s: node %d is invalid.\n",
279a82fe829SJonathan Cameron TYPE_ACPI_GENERIC_PORT, gp->node);
280a82fe829SJonathan Cameron exit(1);
281a82fe829SJonathan Cameron }
282a82fe829SJonathan Cameron
283a82fe829SJonathan Cameron o = object_resolve_path_type(gp->pci_bus, TYPE_PXB_CXL_BUS, NULL);
284a82fe829SJonathan Cameron if (!o) {
285a82fe829SJonathan Cameron error_printf("%s: device must be a CXL host bridge.\n",
286a82fe829SJonathan Cameron TYPE_ACPI_GENERIC_PORT);
287a82fe829SJonathan Cameron exit(1);
288a82fe829SJonathan Cameron }
289a82fe829SJonathan Cameron
290a82fe829SJonathan Cameron uid = object_property_get_uint(o, "acpi_uid", &error_fatal);
291a82fe829SJonathan Cameron build_srat_acpi_generic_port(table_data, gp->node, hid, uid);
292a82fe829SJonathan Cameron
293a82fe829SJonathan Cameron return 0;
294a82fe829SJonathan Cameron }
295a82fe829SJonathan Cameron
build_srat_generic_affinity_structures(GArray * table_data)296a82fe829SJonathan Cameron void build_srat_generic_affinity_structures(GArray *table_data)
297f74e7822SJonathan Cameron {
298f74e7822SJonathan Cameron object_child_foreach_recursive(object_get_root(),
299f74e7822SJonathan Cameron build_acpi_generic_initiator,
300f74e7822SJonathan Cameron table_data);
301a82fe829SJonathan Cameron object_child_foreach_recursive(object_get_root(), build_acpi_generic_port,
302a82fe829SJonathan Cameron table_data);
303f74e7822SJonathan Cameron }
304