Kyösti Mälkki (kyosti.malkki@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/300
-gerrit
commit fbfb2728b181dadd6d0d9ecb5b1f52d033e04cf1 Author: Kyösti Mälkki kyosti.malkki@gmail.com Date: Tue Jan 31 17:24:12 2012 +0200
IOAPIC: Divide setup_ioapic() in two parts.
Currently some southbridge codes implement the init_ioapic() part locally and do not implement the load_vectors() part at all. I suspect that load_vectors() should always be called to enable IOAPIC interrupt routes before OS.
Revised init_ioapic() to log on a critical level if one tries to change an already assigned (non-zero) APIC ID, or when the APIC ID is not assigned.
Change-Id: Ic5e860b9b669ecd1e9ddac4bbb92d80bdb9c2fca Signed-off-by: Kyösti Mälkki kyosti.malkki@gmail.com --- src/arch/x86/lib/ioapic.c | 151 +++++++++++++++++++++++++++++++++----------- 1 files changed, 113 insertions(+), 38 deletions(-)
diff --git a/src/arch/x86/lib/ioapic.c b/src/arch/x86/lib/ioapic.c index 81d964c..7d166b9 100644 --- a/src/arch/x86/lib/ioapic.c +++ b/src/arch/x86/lib/ioapic.c @@ -34,6 +34,11 @@ static void io_apic_write(u32 ioapic_base, u32 reg, u32 value) write32(ioapic_base + 0x10, value); }
+/** + * Clear all IOAPIC vectors. + * + * @param ioapic_base IOAPIC base address + */ void clear_ioapic(u32 ioapic_base) { u32 low, high; @@ -64,24 +69,84 @@ void clear_ioapic(u32 ioapic_base) } }
-void setup_ioapic(u32 ioapic_base, u8 ioapic_id) +/** + * Assign IOAPIC with an ID and set delivery type. + * + * @param ioapic_base IOAPIC base address + * @param new_id If non-zero (1-15), assign new apic ID. + * If zero, use previously assigned apic ID. + * @param delivery If 0x0, deliver interrupts on APIC serial bus + * If 0x1, deliver interrupts on FSB + */ +static void init_ioapic(u32 ioapic_base, u8 new_id, u8 delivery) { - u32 bsp_lapicid = lapicid(); - u32 low, high; - u32 i, ioapic_interrupts; + u8 loud = 0; + u8 active_id; + u32 reg32;
- printk(BIOS_DEBUG, "IOAPIC: Initializing IOAPIC at 0x%08x\n", - ioapic_base); - printk(BIOS_DEBUG, "IOAPIC: Bootstrap Processor Local APIC = 0x%02x\n", - bsp_lapicid); + reg32 = io_apic_read(ioapic_base, 0x00); + active_id = (reg32 >> 24) & 0xf; + + /* Changing a previously assigned ID and attempting + * to use ID=0 here are logged at a critical level. + */ + if ( ((active_id && new_id) && (active_id != new_id)) || + !(active_id || new_id)) + loud = 1; + + if (!new_id) { + printk(loud ? BIOS_CRIT : BIOS_DEBUG, + "IOAPIC: 0x%08x using old ID = %d\n", + ioapic_base, active_id); + + } else { + reg32 &= 0xf0ffffff; + reg32 |= (new_id & 0xf) << 24; + io_apic_write(ioapic_base, 0x00, reg32); + + printk(loud ? BIOS_CRIT : BIOS_DEBUG, + "IOAPIC: 0x%08x changing ID = %d->%d\n", + ioapic_base, active_id, new_id); + + reg32 = io_apic_read(ioapic_base, 0x00); + active_id = (reg32 >> 24) & 0xf; + if (active_id != new_id) + printk(BIOS_CRIT, + "IOAPIC: 0x%08x changing ID failed (%d!=%d)\n", + ioapic_base, active_id, new_id); + }
- if (ioapic_id) { - printk(BIOS_DEBUG, "IOAPIC: ID = 0x%02x\n", ioapic_id); - /* Set IOAPIC ID if it has been specified. */ - io_apic_write(ioapic_base, 0x00, - (io_apic_read(ioapic_base, 0x00) & 0xf0ffffff) | - (ioapic_id << 24)); + /* Assign interrupt delivery type. */ + reg32 = io_apic_read(ioapic_base, 0x03); + switch (delivery) { + case 0: + printk(BIOS_DEBUG, "IOAPIC: Delivery is on APIC serial bus\n"); + reg32 = 0x00; + break; + case 1: + printk(BIOS_DEBUG, "IOAPIC: Delivery is on FSB\n"); + reg32 = 0x01; + break; + default: + printk(BIOS_CRIT, "IOAPIC: Delivery is reverted to FSB\n"); + reg32 = 0x01; + break; } + io_apic_write(ioapic_base, 0x03, reg32); +} + +/** + * Fill IOAPIC vectors all targeting the same processor. + * Virtual Wire Mode on vector 0 is enabled, others remain disabled. + * + * + * @param ioapic_base IOAPIC base address + * @param bsp_lapicid APIC ID of a CPU to receive the interrupts + */ +static void load_vectors(u32 ioapic_base, u8 bsp_lapicid) +{ + u32 low, high; + u32 i, ioapic_interrupts;
/* Read the available number of interrupts. */ ioapic_interrupts = (io_apic_read(ioapic_base, 0x01) >> 16) & 0xff; @@ -89,28 +154,6 @@ void setup_ioapic(u32 ioapic_base, u8 ioapic_id) ioapic_interrupts = 24; printk(BIOS_DEBUG, "IOAPIC: %d interrupts\n", ioapic_interrupts);
-// XXX this decision should probably be made elsewhere, and -// it's the C3, not the EPIA this depends on. -#if CONFIG_EPIA_VT8237R_INIT -#define IOAPIC_INTERRUPTS_ON_APIC_SERIAL_BUS -#else -#define IOAPIC_INTERRUPTS_ON_FSB -#endif - -#ifdef IOAPIC_INTERRUPTS_ON_FSB - /* - * For the Pentium 4 and above APICs deliver their interrupts - * on the front side bus, enable that. - */ - printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on FSB\n"); - io_apic_write(ioapic_base, 0x03, - io_apic_read(ioapic_base, 0x03) | (1 << 0)); -#endif -#ifdef IOAPIC_INTERRUPTS_ON_APIC_SERIAL_BUS - printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on APIC serial bus\n"); - io_apic_write(ioapic_base, 0x03, 0); -#endif - /* Enable Virtual Wire Mode. */ low = ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT; high = bsp_lapicid << (56 - 32); @@ -125,10 +168,8 @@ void setup_ioapic(u32 ioapic_base, u8 ioapic_id)
printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n", 0, high, low); - low = DISABLED; high = NONE; - for (i = 1; i < ioapic_interrupts; i++) { io_apic_write(ioapic_base, i * 2 + 0x10, low); io_apic_write(ioapic_base, i * 2 + 0x11, high); @@ -137,3 +178,37 @@ void setup_ioapic(u32 ioapic_base, u8 ioapic_id) i, high, low); } } + +// XXX this decision should probably be made elsewhere, and +// it's the C3, not the EPIA this depends on. + +#if CONFIG_EPIA_VT8237R_INIT +#define CONFIG_IOAPIC_DELIVERY_TYPE 0 +#else +#define CONFIG_IOAPIC_DELIVERY_TYPE 1 +#endif + +/** + * Assign IOAPIC with an ID + * + * Compile-time options from mainboard Kconfig can affect the + * chosen IOAPIC operational mode. + * + * @param ioapic_base IOAPIC base address + * @param new_id If non-zero (1-15), assign new apic ID. + * If zero, use previously assigned apic ID. + */ +void setup_ioapic(u32 ioapic_base, u8 new_id) +{ + u8 bsp_lapicid = lapicid(); + u8 ioapic_dt = CONFIG_IOAPIC_DELIVERY_TYPE; + + printk(BIOS_DEBUG, "IOAPIC: Initializing IOAPIC at 0x%08x\n", + ioapic_base); + init_ioapic(ioapic_base, new_id, ioapic_dt); + + printk(BIOS_DEBUG, "IOAPIC: Bootstrap Processor Local APIC ID = %d\n", + bsp_lapicid); + load_vectors(ioapic_base, bsp_lapicid); +} +