Go back to SIPI WAIT state for those CPUS defining the newly introduced
authorStefan Reinauer <stepan@coresystems.de>
Sat, 2 Aug 2008 15:15:23 +0000 (15:15 +0000)
committerStefan Reinauer <stepan@openbios.org>
Sat, 2 Aug 2008 15:15:23 +0000 (15:15 +0000)
CONFIG_AP_IN_SIPI_WAIT flag. Newer Intel CPUs need this to operate with
multiple cores.

Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
Acked-by: Peter Stuge <peter@stuge.se>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3465 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1

src/config/Options.lb
src/cpu/x86/lapic/lapic_cpu_init.c
src/include/cpu/x86/lapic.h

index 0ed6a7d83091adc5a5b1a8d16eda1a1dd86c616a..b685bf883193ffc0d87c811edc65985207229962 100644 (file)
@@ -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
index 0bc8bbaf07af3cd56c1959e8b108967d7fcac46f..022d3722be1bf9c6b4da8f880c064edd5f290099 100644 (file)
@@ -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");
index e2c214694289128c3c249ce6d8138c82884b47f7..66b40fc7b6c69f6f5b72dfcf42a5f3462e55325d 100644 (file)
@@ -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);
 }