arch/x86: Enable support for IOAPIC devices

On platforms with multiple IOAPICs the GSI base must not be
linear, which is currently assumed by acpi_create_madt_ioapic_from_hw().

Integrate the existing struct device DEVICE_PATH_IOAPIC type and allow
to assign custom GSI bases for each IOAPIC. Write out the IOAPIC devices
into the MADT table if any.

For now, since no platform adds IOAPIC devices, the existing behaviour
remains the same. Allows to get rid of soc_get_ioapic_info().

Change-Id: Ie13d4f5c4f0704f0935974f90e5b7cf24e94aab3
Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/85226
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
This commit is contained in:
Patrick Rudolph 2024-11-21 08:50:40 +01:00 committed by Lean Sheng Tan
commit b04ecb2a5f
5 changed files with 66 additions and 0 deletions

View file

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <assert.h>
#include <acpi/acpi.h>
#include <arch/ioapic.h>
#include <arch/smp/mpspec.h>
@ -226,6 +227,8 @@ int acpi_create_srat_x2apic(acpi_srat_x2apic_t *x2apic, u32 node, u32 apic)
unsigned long acpi_arch_fill_madt(acpi_madt_t *madt, unsigned long current)
{
struct device *dev = NULL;
madt->lapic_addr = cpu_get_lapic_addr();
if (CONFIG(ACPI_HAVE_PCAT_8259))
@ -237,5 +240,21 @@ unsigned long acpi_arch_fill_madt(acpi_madt_t *madt, unsigned long current)
if (CONFIG(ACPI_COMMON_MADT_IOAPIC))
current = acpi_create_madt_ioapic_gsi0_default(current);
while ((dev = dev_find_path(dev, DEVICE_PATH_IOAPIC)) != NULL) {
/*
CONFIG(ACPI_COMMON_MADT_IOAPIC) adds the IOAPIC with gsi_base = 0 above.
Make sure to not add it twice when it's also part of the devicetree.
Currently no SoC adds ioapic_gsi0 to the devicetree.
TODO: Add the ioapic_gsi0 to the device-tree on all SoCs and remove this check.
*/
assert(!CONFIG(ACPI_COMMON_MADT_IOAPIC) || dev->path.ioapic.gsi_base != 0);
assert(dev->path.ioapic.addr);
current += acpi_create_madt_ioapic((void *)(uintptr_t)current,
dev->path.ioapic.ioapic_id,
dev->path.ioapic.addr,
dev->path.ioapic.gsi_base);
}
return current;
}

View file

@ -16,6 +16,9 @@ unsigned int ioapic_get_max_vectors(uintptr_t ioapic_base);
void ioapic_set_max_vectors(uintptr_t ioapic_base, int mre_count);
void ioapic_lock_max_vectors(uintptr_t ioapic_base);
struct device *ioapic_create_dev(struct device *parent,
const uintptr_t ioapic_base,
const u32 gsi_base);
void setup_ioapic(uintptr_t ioapic_base, u8 ioapic_id);
void register_new_ioapic(uintptr_t ioapic_base);
void register_new_ioapic_gsi0(uintptr_t ioapic_base);

View file

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <assert.h>
#include <device/device.h>
#include <device/mmio.h>
#include <arch/ioapic.h>
#include <console/console.h>
@ -174,6 +175,44 @@ void ioapic_set_boot_config(uintptr_t ioapic_base, bool irq_on_fsb)
}
}
/**
* Create a new IOAPIC device under the given device.
*
* @param parent The parent device. A PCI domain or PCI device (in case of PCI IOAPIC).
* @param ioapic_base The IOAPIC base address
* @param gsi_base Platform specific GSI base
* @return Pointer to the device struct.
*/
struct device *ioapic_create_dev(struct device *parent,
const uintptr_t ioapic_base,
const u32 gsi_base)
{
struct device_path path = {0};
struct device *dev;
if (!parent)
return NULL;
struct bus *bus = alloc_bus(parent);
if (!bus)
return NULL;
if (gsi_base == 0)
register_new_ioapic_gsi0(ioapic_base);
else
register_new_ioapic(ioapic_base);
path.type = DEVICE_PATH_IOAPIC;
path.ioapic.ioapic_id = get_ioapic_id(ioapic_base);
path.ioapic.addr = ioapic_base;
path.ioapic.gsi_base = gsi_base;
dev = alloc_dev(bus, &path);
assert(dev);
return dev;
}
void setup_ioapic(uintptr_t ioapic_base, u8 ioapic_id)
{
set_ioapic_id(ioapic_base, ioapic_id);

View file

@ -130,6 +130,9 @@ static int path_eq(const struct device_path *path1,
case DEVICE_PATH_CPU_BUS:
equal = (path1->cpu_bus.id == path2->cpu_bus.id);
break;
case DEVICE_PATH_IOAPIC:
equal = (path1->ioapic.ioapic_id == path2->ioapic.ioapic_id);
break;
case DEVICE_PATH_GENERIC:
equal = (path1->generic.id == path2->generic.id) &&
(path1->generic.subid == path2->generic.subid);

View file

@ -85,7 +85,9 @@ struct apic_path {
};
struct ioapic_path {
uintptr_t addr;
unsigned int ioapic_id;
unsigned int gsi_base;
};
struct cpu_cluster_path {