qemu/hw/acpi/pci.c
Jonathan Cameron f74e78220d acpi/pci: Move Generic Initiator object handling into acpi/pci.*
Whilst ACPI SRAT Generic Initiator Afinity Structures are able to refer to
both PCI and ACPI Device Handles, the QEMU implementation only implements
the PCI Device Handle case.  For now move the code into the existing
hw/acpi/pci.c file and header.  If support for ACPI Device Handles is
added in the future, perhaps this will be moved again.

Also push the struct AcpiGenericInitiator down into the c file as not
used outside pci.c.

Suggested-by: Igor Mammedov <imammedo@redhat.com>
Tested-by: "Huang, Ying" <ying.huang@intel.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Message-Id: <20240916171017.1841767-7-Jonathan.Cameron@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2024-11-04 16:03:24 -05:00

185 lines
5.7 KiB
C

/*
* Support for generating PCI related ACPI tables and passing them to Guests
*
* Copyright (C) 2006 Fabrice Bellard
* Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
* Copyright (C) 2013-2019 Red Hat Inc
* Copyright (C) 2019 Intel Corporation
*
* Author: Wei Yang <richardw.yang@linux.intel.com>
* Author: Michael S. Tsirkin <mst@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qom/object_interfaces.h"
#include "qapi/error.h"
#include "hw/boards.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/pci.h"
#include "hw/pci/pci_device.h"
#include "hw/pci/pcie_host.h"
/*
* PCI Firmware Specification, Revision 3.0
* 4.1.2 MCFG Table Description.
*/
void build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info,
const char *oem_id, const char *oem_table_id)
{
AcpiTable table = { .sig = "MCFG", .rev = 1,
.oem_id = oem_id, .oem_table_id = oem_table_id };
acpi_table_begin(&table, table_data);
/* Reserved */
build_append_int_noprefix(table_data, 0, 8);
/*
* Memory Mapped Enhanced Configuration Space Base Address Allocation
* Structure
*/
/* Base address, processor-relative */
build_append_int_noprefix(table_data, info->base, 8);
/* PCI segment group number */
build_append_int_noprefix(table_data, 0, 2);
/* Starting PCI Bus number */
build_append_int_noprefix(table_data, 0, 1);
/* Final PCI Bus number */
build_append_int_noprefix(table_data, PCIE_MMCFG_BUS(info->size - 1), 1);
/* Reserved */
build_append_int_noprefix(table_data, 0, 4);
acpi_table_end(linker, &table);
}
typedef struct AcpiGenericInitiator {
/* private */
Object parent;
/* public */
char *pci_dev;
uint16_t node;
} AcpiGenericInitiator;
typedef struct AcpiGenericInitiatorClass {
ObjectClass parent_class;
} AcpiGenericInitiatorClass;
#define TYPE_ACPI_GENERIC_INITIATOR "acpi-generic-initiator"
OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericInitiator, acpi_generic_initiator,
ACPI_GENERIC_INITIATOR, OBJECT,
{ TYPE_USER_CREATABLE },
{ NULL })
OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericInitiator, ACPI_GENERIC_INITIATOR)
static void acpi_generic_initiator_init(Object *obj)
{
AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
gi->node = MAX_NODES;
gi->pci_dev = NULL;
}
static void acpi_generic_initiator_finalize(Object *obj)
{
AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
g_free(gi->pci_dev);
}
static void acpi_generic_initiator_set_pci_device(Object *obj, const char *val,
Error **errp)
{
AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
gi->pci_dev = g_strdup(val);
}
static void acpi_generic_initiator_set_node(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
MachineState *ms = MACHINE(qdev_get_machine());
uint32_t value;
if (!visit_type_uint32(v, name, &value, errp)) {
return;
}
if (value >= MAX_NODES) {
error_printf("%s: Invalid NUMA node specified\n",
TYPE_ACPI_GENERIC_INITIATOR);
exit(1);
}
gi->node = value;
ms->numa_state->nodes[gi->node].has_gi = true;
}
static void acpi_generic_initiator_class_init(ObjectClass *oc, void *data)
{
object_class_property_add_str(oc, "pci-dev", NULL,
acpi_generic_initiator_set_pci_device);
object_class_property_add(oc, "node", "int", NULL,
acpi_generic_initiator_set_node, NULL, NULL);
}
static int build_acpi_generic_initiator(Object *obj, void *opaque)
{
MachineState *ms = MACHINE(qdev_get_machine());
AcpiGenericInitiator *gi;
GArray *table_data = opaque;
int32_t devfn;
uint8_t bus;
Object *o;
if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_INITIATOR)) {
return 0;
}
gi = ACPI_GENERIC_INITIATOR(obj);
if (gi->node >= ms->numa_state->num_nodes) {
error_printf("%s: Specified node %d is invalid.\n",
TYPE_ACPI_GENERIC_INITIATOR, gi->node);
exit(1);
}
o = object_resolve_path_type(gi->pci_dev, TYPE_PCI_DEVICE, NULL);
if (!o) {
error_printf("%s: Specified device must be a PCI device.\n",
TYPE_ACPI_GENERIC_INITIATOR);
exit(1);
}
bus = object_property_get_uint(o, "busnr", &error_fatal);
devfn = object_property_get_uint(o, "addr", &error_fatal);
/* devfn is constrained in PCI to be 8 bit but storage is an int32_t */
assert(devfn >= 0 && devfn < PCI_DEVFN_MAX);
build_srat_pci_generic_initiator(table_data, gi->node, 0, bus, devfn);
return 0;
}
void build_srat_generic_pci_initiator(GArray *table_data)
{
object_child_foreach_recursive(object_get_root(),
build_acpi_generic_initiator,
table_data);
}