diff --git a/src/acpi/acpi_apic.c b/src/acpi/acpi_apic.c index fe0459b559..1862195e7f 100644 --- a/src/acpi/acpi_apic.c +++ b/src/acpi/acpi_apic.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ +#include #include #include #include @@ -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; } diff --git a/src/arch/x86/include/arch/ioapic.h b/src/arch/x86/include/arch/ioapic.h index 530128a580..6c19ed0ede 100644 --- a/src/arch/x86/include/arch/ioapic.h +++ b/src/arch/x86/include/arch/ioapic.h @@ -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); diff --git a/src/arch/x86/ioapic.c b/src/arch/x86/ioapic.c index 5bb2adb584..4cde7c7f51 100644 --- a/src/arch/x86/ioapic.c +++ b/src/arch/x86/ioapic.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #include +#include #include #include #include @@ -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); diff --git a/src/device/device_const.c b/src/device/device_const.c index 9f3443e94c..2aef907447 100644 --- a/src/device/device_const.c +++ b/src/device/device_const.c @@ -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); diff --git a/src/include/device/path.h b/src/include/device/path.h index d8ef88033b..8e9ec3bdd5 100644 --- a/src/include/device/path.h +++ b/src/include/device/path.h @@ -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 {