diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/config/Options.lb | 5 | ||||
-rw-r--r-- | src/cpu/x86/lapic/lapic_cpu_init.c | 69 | ||||
-rw-r--r-- | src/include/cpu/x86/lapic.h | 8 |
3 files changed, 80 insertions, 2 deletions
diff --git a/src/config/Options.lb b/src/config/Options.lb index 0ed6a7d830..b685bf8831 100644 --- a/src/config/Options.lb +++ b/src/config/Options.lb @@ -574,6 +574,11 @@ define CONFIG_LOGICAL_CPUS export always comment "Should multiple cpus per die be enabled?" end +define CONFIG_AP_IN_SIPI_WAIT + default 0 + export always + comment "Should application processors go to SIPI wait state after initialization? (Required for Intel Core Duo)" +end define HAVE_MP_TABLE default none export used diff --git a/src/cpu/x86/lapic/lapic_cpu_init.c b/src/cpu/x86/lapic/lapic_cpu_init.c index 0bc8bbaf07..022d3722be 100644 --- a/src/cpu/x86/lapic/lapic_cpu_init.c +++ b/src/cpu/x86/lapic/lapic_cpu_init.c @@ -1,6 +1,7 @@ /* 2005.12 yhlu add coreboot_ram cross the vga font buffer handling 2005.12 yhlu add _RAMBASE above 1M support for SMP + 2008.05 stepan add support for going back to sipi wait state */ #include <cpu/x86/lapic.h> @@ -16,6 +17,7 @@ #if CONFIG_SMP == 1 +#if _RAMBASE >= 0x100000 /* This is a lot more paranoid now, since Linux can NOT handle * being told there is a CPU when none exists. So any errors * will return 0, meaning no CPU. @@ -27,6 +29,7 @@ static unsigned long get_valid_start_eip(unsigned long orig_start_eip) { return (unsigned long)orig_start_eip & 0xffff; // 16 bit to avoid 0xa0000 } +#endif static void copy_secondary_start_to_1m_below(void) { @@ -277,9 +280,73 @@ int start_cpu(device_t cpu) return result; } +#if CONFIG_AP_IN_SIPI_WAIT == 1 +/** + * Normally this function is defined in lapic.h as an always inline function + * that just keeps the CPU in a hlt() loop. This does not work on all CPUs. + * I think all hyperthreading CPUs might need this version, but I could only + * verify this on the Intel Core Duo + */ +void stop_this_cpu(void) +{ + int timeout; + unsigned long send_status; + unsigned long lapicid; + + lapicid = lapic_read(LAPIC_ID) >> 24; + + printk_debug("CPU %d going down...\n", lapicid); + + /* send an LAPIC INIT to myself */ + lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(lapicid)); + lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_INT_ASSERT | LAPIC_DM_INIT); + + /* wait for the ipi send to finish */ +#if 0 + // When these two printk_spew calls are not removed, the + // machine will hang when log level is SPEW. Why? + printk_spew("Waiting for send to finish...\n"); +#endif + timeout = 0; + do { +#if 0 + printk_spew("+"); +#endif + udelay(100); + send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY; + } while (send_status && (timeout++ < 1000)); + if (timeout >= 1000) { + printk_err("timed out\n"); + } + mdelay(10); + + printk_spew("Deasserting INIT.\n"); + /* Deassert the LAPIC INIT */ + lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(lapicid)); + lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_DM_INIT); + + printk_spew("Waiting for send to finish...\n"); + timeout = 0; + do { + printk_spew("+"); + udelay(100); + send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY; + } while (send_status && (timeout++ < 1000)); + if (timeout >= 1000) { + printk_err("timed out\n"); + } + + while(1) { + hlt(); + } +} +#endif + /* C entry point of secondary cpus */ void secondary_cpu_init(void) { + unsigned long cpunum; + atomic_inc(&active_cpus); #if SERIAL_CPU_INIT == 1 #if CONFIG_MAX_CPUS>2 @@ -294,6 +361,7 @@ void secondary_cpu_init(void) #endif atomic_dec(&active_cpus); + stop_this_cpu(); } @@ -356,7 +424,6 @@ static void wait_other_cpus_stop(struct bus *cpu_bus) if (!cpu->initialized) { printk_err("CPU 0x%02x did not initialize!\n", cpu->path.u.apic.apic_id); -#warning "FIXME do I need a mainboard_cpu_fixup function?" } } printk_debug("All AP CPUs stopped\n"); diff --git a/src/include/cpu/x86/lapic.h b/src/include/cpu/x86/lapic.h index e2c2146942..66b40fc7b6 100644 --- a/src/include/cpu/x86/lapic.h +++ b/src/include/cpu/x86/lapic.h @@ -51,6 +51,11 @@ static inline __attribute__((always_inline)) unsigned long lapicid(void) return lapic_read(LAPIC_ID) >> 24; } + +#if CONFIG_AP_IN_SIPI_WAIT != 1 +/* If we need to go back to sipi wait, we use the long non-inlined version of + * this function in lapic_cpu_init.c + */ static inline __attribute__((always_inline)) void stop_this_cpu(void) { @@ -59,6 +64,7 @@ static inline __attribute__((always_inline)) void stop_this_cpu(void) hlt(); } } +#endif #if ! defined (__ROMCC__) @@ -98,7 +104,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz } -extern inline void lapic_write_atomic(unsigned long reg, unsigned long v) +static inline void lapic_write_atomic(unsigned long reg, unsigned long v) { xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE+reg), v); } |