From 294446a137aa0477db4c8eb09071b42020e1fe2f Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Sat, 14 Apr 2018 11:48:27 +0200 Subject: x86/mpspec: order the I/O APICs by the APIC Id Linux (4.16) assumes that the PIT interrupt is connected to the pin 0 of the IOAPIC[0] and panics otherwise. This might be a Linux bug. The MP Specification 1.4 does seem to mandate sequential ordering for bus entries, but not for the I/O APICs. Change-Id: Ibf823eb5b3a29e4590cba915069cdfe5f780edcd Signed-off-by: Lubomir Rintel Reviewed-on: https://review.coreboot.org/25799 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin --- src/arch/x86/mpspec.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/arch/x86/mpspec.c b/src/arch/x86/mpspec.c index 7541eeb493..8280171ac6 100644 --- a/src/arch/x86/mpspec.c +++ b/src/arch/x86/mpspec.c @@ -524,6 +524,22 @@ void *mptable_finalize(struct mp_config_table *mc) return smp_next_mpe_entry(mc); } +static const struct device *find_next_ioapic(unsigned int last_ioapic_id) +{ + const struct device *dev; + const struct device *result = NULL; + unsigned int ioapic_id = MAX_APICS; + + for (dev = all_devices; dev; dev = dev->next) { + if (dev->path.type == DEVICE_PATH_IOAPIC && + dev->path.ioapic.ioapic_id > last_ioapic_id && + dev->path.ioapic.ioapic_id <= ioapic_id) { + result = dev; + } + } + return result; +} + unsigned long __weak write_smp_table(unsigned long addr) { struct drivers_generic_ioapic_config *ioapic_config; @@ -535,6 +551,7 @@ unsigned long __weak write_smp_table(unsigned long addr) void *tmp, *v; int isaioapic = -1, have_fixed_entries; const struct pci_irq_info *pci_irq_info; + unsigned int ioapic_id = 0; v = smp_write_floating_table(addr, 0); mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN); @@ -545,17 +562,17 @@ unsigned long __weak write_smp_table(unsigned long addr) mptable_write_buses(mc, NULL, &isa_bus); - for (dev = all_devices; dev; dev = dev->next) { - if (dev->path.type != DEVICE_PATH_IOAPIC) - continue; - + while ((dev = find_next_ioapic(ioapic_id))) { ioapic_config = dev->chip_info; if (!ioapic_config) { printk(BIOS_ERR, "%s has no config, ignoring\n", dev_path(dev)); + ioapic_id++; continue; } - smp_write_ioapic(mc, dev->path.ioapic.ioapic_id, + + ioapic_id = dev->path.ioapic.ioapic_id; + smp_write_ioapic(mc, ioapic_id, ioapic_config->version, ioapic_config->base); -- cgit v1.2.3