[coreboot] Patch set updated for coreboot: f0e2c29 Revert "Use broadcast SIPI to startup siblings"

Sven Schnelle (svens@stackframe.org) gerrit at coreboot.org
Mon Jul 30 21:38:59 CEST 2012


Sven Schnelle (svens at stackframe.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1381

-gerrit

commit f0e2c2931c8f3536d9c38b19d5ffc6981f07ae0d
Author: Sven Schnelle <svens at stackframe.org>
Date:   Sun Jul 29 19:18:03 2012 +0200

    Revert "Use broadcast SIPI to startup siblings"
    
    This reverts commit 042c1461fb777e583e5de48edf9326e47ee5595f.
    
    It turned out that sending IPIs via broadcast doesn't work on
    Sandybridge. We tried to come up with a solution, but didn't
    found any so far. So revert the code for now until we have
    a working solution.
    
    Change-Id: I7dd1cba5a4c1e4b0af366b20e8263b1f6f4b9714
    Signed-off-by: Sven Schnelle <svens at stackframe.org>
---
 src/arch/x86/Kconfig                         |    4 +
 src/arch/x86/include/arch/cpu.h              |   24 ++
 src/arch/x86/lib/cpu.c                       |   20 +-
 src/cpu/intel/hyperthreading/intel_sibling.c |   65 +++++
 src/cpu/intel/model_1067x/model_1067x_init.c |    4 +
 src/cpu/intel/model_106cx/Kconfig            |    4 +-
 src/cpu/intel/model_106cx/model_106cx_init.c |    4 +
 src/cpu/intel/model_206ax/Kconfig            |    1 +
 src/cpu/intel/model_206ax/acpi.c             |    9 +-
 src/cpu/intel/model_206ax/model_206ax_init.c |   55 ++++
 src/cpu/intel/model_6ex/Kconfig              |    1 +
 src/cpu/intel/model_6ex/model_6ex_init.c     |    3 +
 src/cpu/intel/model_6fx/Kconfig              |    1 +
 src/cpu/intel/model_6fx/model_6fx_init.c     |    3 +
 src/cpu/intel/model_f2x/model_f2x_init.c     |    3 +
 src/cpu/intel/model_f3x/model_f3x_init.c     |    3 +
 src/cpu/intel/model_f4x/model_f4x_init.c     |    3 +
 src/cpu/intel/socket_LGA771/Kconfig          |    1 +
 src/cpu/x86/lapic/lapic_cpu_init.c           |  366 +++++++++++++++++++++-----
 src/cpu/x86/lapic/secondary.S                |   20 +-
 src/cpu/x86/pae/pgtbl.c                      |   12 -
 src/drivers/i2c/w83795/w83795.c              |    5 +-
 src/include/cpu/cpu.h                        |    6 +-
 src/include/cpu/x86/lapic.h                  |   15 +-
 src/include/device/path.h                    |    1 -
 25 files changed, 508 insertions(+), 125 deletions(-)

diff --git a/src/arch/x86/Kconfig b/src/arch/x86/Kconfig
index 4dfbe70..6d56ec6 100644
--- a/src/arch/x86/Kconfig
+++ b/src/arch/x86/Kconfig
@@ -3,6 +3,10 @@ menu "Architecture (x86)"
 # This is an SMP option. It relates to starting up APs.
 # It is usually set in mainboard/*/Kconfig.
 # TODO: Improve description.
+config AP_IN_SIPI_WAIT
+	bool
+	default n
+	depends on ARCH_X86
 
 # Aligns 16bit entry code in bootblock so that hyper-threading CPUs
 # can boot AP CPUs to enable their shared caches.
diff --git a/src/arch/x86/include/arch/cpu.h b/src/arch/x86/include/arch/cpu.h
index 0fe5ea5..0dc92fb 100644
--- a/src/arch/x86/include/arch/cpu.h
+++ b/src/arch/x86/include/arch/cpu.h
@@ -158,6 +158,30 @@ struct cpu_driver {
 struct device;
 struct cpu_driver *find_cpu_driver(struct device *cpu);
 
+struct cpu_info {
+	device_t cpu;
+	unsigned long index;
+};
+
+static inline struct cpu_info *cpu_info(void)
+{
+	struct cpu_info *ci;
+	__asm__("andl %%esp,%0; "
+		"orl  %2, %0 "
+		:"=r" (ci)
+		: "0" (~(CONFIG_STACK_SIZE - 1)),
+		"r" (CONFIG_STACK_SIZE - sizeof(struct cpu_info))
+	);
+	return ci;
+}
+
+static inline unsigned long cpu_index(void)
+{
+	struct cpu_info *ci;
+	ci = cpu_info();
+	return ci->index;
+}
+
 struct cpuinfo_x86 {
         uint8_t    x86;            /* CPU family */
         uint8_t    x86_vendor;     /* CPU vendor */
diff --git a/src/arch/x86/lib/cpu.c b/src/arch/x86/lib/cpu.c
index 7cd955e..98ede06 100644
--- a/src/arch/x86/lib/cpu.c
+++ b/src/arch/x86/lib/cpu.c
@@ -9,7 +9,6 @@
 #include <device/path.h>
 #include <device/device.h>
 #include <smp/spinlock.h>
-#include <cpu/x86/lapic.h>
 
 /* Standard macro to see if a specific flag is changeable */
 static inline int flag_is_changeable_p(uint32_t flag)
@@ -235,7 +234,7 @@ static void set_cpu_ops(struct device *cpu)
 	cpu->ops = driver ? driver->ops : NULL;
 }
 
-void cpu_initialize(struct bus *cpu_bus, int index)
+void cpu_initialize(void)
 {
 	/* Because we busy wait at the printk spinlock.
 	 * It is important to keep the number of printed messages
@@ -243,17 +242,17 @@ void cpu_initialize(struct bus *cpu_bus, int index)
 	 * disabled.
 	 */
 	struct device *cpu;
+	struct cpu_info *info;
 	struct cpuinfo_x86 c;
-	struct device_path cpu_path;
-	unsigned char id = lapicid();
 
-	cpu_path.type = DEVICE_PATH_APIC;
-	cpu_path.apic.apic_id = id;
+	info = cpu_info();
 
-	cpu = alloc_find_dev(cpu_bus, &cpu_path);
-	cpu->path.apic.index = index;
+	printk(BIOS_INFO, "Initializing CPU #%ld\n", info->index);
 
-	printk(BIOS_DEBUG, "Initializing CPU #%d\n", id);
+	cpu = info->cpu;
+	if (!cpu) {
+		die("CPU: missing cpu device structure");
+	}
 
 	/* Find what type of cpu we are dealing with */
 	identify_cpu(cpu);
@@ -277,6 +276,7 @@ void cpu_initialize(struct bus *cpu_bus, int index)
 		printk(BIOS_DEBUG, "Using generic cpu ops (good)\n");
 	}
 
+
 	/* Initialize the cpu */
 	if (cpu->ops && cpu->ops->init) {
 		cpu->enabled = 1;
@@ -284,7 +284,7 @@ void cpu_initialize(struct bus *cpu_bus, int index)
 		cpu->ops->init(cpu);
 	}
 
-	printk(BIOS_INFO, "CPU #%d initialized\n", id);
+	printk(BIOS_INFO, "CPU #%ld initialized\n", info->index);
 
 	return;
 }
diff --git a/src/cpu/intel/hyperthreading/intel_sibling.c b/src/cpu/intel/hyperthreading/intel_sibling.c
index 8377cd0..b9a9ae7 100644
--- a/src/cpu/intel/hyperthreading/intel_sibling.c
+++ b/src/cpu/intel/hyperthreading/intel_sibling.c
@@ -7,6 +7,13 @@
 #include <smp/spinlock.h>
 #include <assert.h>
 
+#if !CONFIG_SERIAL_CPU_INIT
+#error Intel hyper-threading requires serialized cpu init
+#endif
+
+static int first_time = 1;
+static int disable_siblings = !CONFIG_LOGICAL_CPUS;
+
 /* Return true if running thread does not have the smallest lapic ID
  * within a CPU core.
  */
@@ -27,3 +34,61 @@ int intel_ht_sibling(void)
 	threads = (apic_ids / core_ids);
 	return !!(lapicid() & (threads-1));
 }
+
+void intel_sibling_init(device_t cpu)
+{
+	unsigned i, siblings;
+	struct cpuid_result result;
+
+	/* On the bootstrap processor see if I want sibling cpus enabled */
+	if (first_time) {
+		first_time = 0;
+		get_option(&disable_siblings, "hyper_threading");
+	}
+	result = cpuid(1);
+	/* Is hyperthreading supported */
+	if (!(result.edx & (1 << 28))) {
+		return;
+	}
+	/* See how many sibling cpus we have */
+	siblings = (result.ebx >> 16) & 0xff;
+	if (siblings < 1) {
+		siblings = 1;
+	}
+
+	printk(BIOS_DEBUG, "CPU: %u %d siblings\n",
+		cpu->path.apic.apic_id,
+		siblings);
+
+	/* See if I am a sibling cpu */
+	if (cpu->path.apic.apic_id & (siblings -1)) {
+		if (disable_siblings) {
+			cpu->enabled = 0;
+		}
+		return;
+	}
+
+	/* I am the primary cpu start up my siblings */
+	for(i = 1; i < siblings; i++) {
+		struct device_path cpu_path;
+		device_t new;
+		/* Build the cpu device path */
+		cpu_path.type = DEVICE_PATH_APIC;
+		cpu_path.apic.apic_id = cpu->path.apic.apic_id + i;
+
+
+		/* Allocate new cpu device structure iff sibling CPU
+		 * was not in static device tree.
+		 */
+		new = alloc_find_dev(cpu->bus, &cpu_path);
+
+		if (!new) {
+			continue;
+		}
+
+		printk(BIOS_DEBUG, "CPU: %u has sibling %u\n",
+			cpu->path.apic.apic_id,
+			new->path.apic.apic_id);
+	}
+}
+
diff --git a/src/cpu/intel/model_1067x/model_1067x_init.c b/src/cpu/intel/model_1067x/model_1067x_init.c
index ddd1381..c6d716d9 100644
--- a/src/cpu/intel/model_1067x/model_1067x_init.c
+++ b/src/cpu/intel/model_1067x/model_1067x_init.c
@@ -29,6 +29,7 @@
 #include <cpu/x86/lapic.h>
 #include <cpu/intel/microcode.h>
 #include <cpu/intel/speedstep.h>
+#include <cpu/intel/hyperthreading.h>
 #include <cpu/x86/cache.h>
 #include <cpu/x86/name.h>
 
@@ -220,6 +221,9 @@ static void model_1067x_init(device_t cpu)
 
 	/* PIC thermal sensor control */
 	configure_pic_thermal_sensors();
+
+	/* Start up my cpu siblings */
+	intel_sibling_init(cpu);
 }
 
 static struct device_operations cpu_dev_ops = {
diff --git a/src/cpu/intel/model_106cx/Kconfig b/src/cpu/intel/model_106cx/Kconfig
index 2ef7392..103ed50 100644
--- a/src/cpu/intel/model_106cx/Kconfig
+++ b/src/cpu/intel/model_106cx/Kconfig
@@ -3,12 +3,10 @@ config CPU_INTEL_MODEL_106CX
 	select SMP
 	select SSE2
 	select UDELAY_LAPIC
-
-if CPU_INTEL_MODEL_106CX
+	select AP_IN_SIPI_WAIT
 
 config CPU_ADDR_BITS
 	int
 	default 32
 
-endif
 
diff --git a/src/cpu/intel/model_106cx/model_106cx_init.c b/src/cpu/intel/model_106cx/model_106cx_init.c
index 8d2ef3d..4bf2924 100644
--- a/src/cpu/intel/model_106cx/model_106cx_init.c
+++ b/src/cpu/intel/model_106cx/model_106cx_init.c
@@ -27,6 +27,7 @@
 #include <cpu/x86/lapic.h>
 #include <cpu/intel/microcode.h>
 #include <cpu/intel/speedstep.h>
+#include <cpu/intel/hyperthreading.h>
 #include <cpu/x86/cache.h>
 #include <cpu/x86/name.h>
 #include <usbdebug.h>
@@ -177,6 +178,9 @@ static void model_106cx_init(device_t cpu)
 	configure_misc();
 
 	/* TODO: PIC thermal sensor control */
+
+	/* Start up my cpu siblings */
+	intel_sibling_init(cpu);
 }
 
 static struct device_operations cpu_dev_ops = {
diff --git a/src/cpu/intel/model_206ax/Kconfig b/src/cpu/intel/model_206ax/Kconfig
index a8419d5..9cc6edd 100644
--- a/src/cpu/intel/model_206ax/Kconfig
+++ b/src/cpu/intel/model_206ax/Kconfig
@@ -13,6 +13,7 @@ config CPU_SPECIFIC_OPTIONS
 	select UDELAY_LAPIC
 	select SMM_TSEG
 	select MICROCODE_IN_CBFS
+	#select AP_IN_SIPI_WAIT
 
 config BOOTBLOCK_CPU_INIT
 	string
diff --git a/src/cpu/intel/model_206ax/acpi.c b/src/cpu/intel/model_206ax/acpi.c
index f66df51..c8c30a4 100644
--- a/src/cpu/intel/model_206ax/acpi.c
+++ b/src/cpu/intel/model_206ax/acpi.c
@@ -26,7 +26,6 @@
 #include <arch/acpigen.h>
 #include <arch/cpu.h>
 #include <cpu/x86/msr.h>
-#include <cpu/x86/lapic.h>
 #include <cpu/intel/acpi.h>
 #include <cpu/intel/speedstep.h>
 #include <cpu/intel/turbo.h>
@@ -89,8 +88,8 @@ static int generate_cstate_entries(acpi_cstate_t *cstates,
 
 static int generate_C_state_entries(void)
 {
+	struct cpu_info *info;
 	struct cpu_driver *cpu;
-	struct device *cpu_dev;
 	int len, lenif;
 	device_t lapic;
 	struct cpu_intel_model_206ax_config *conf = NULL;
@@ -104,10 +103,10 @@ static int generate_C_state_entries(void)
 		return 0;
 
 	/* Find CPU map of supported C-states */
-	cpu_dev = dev_find_lapic(lapicid());
-	if (!cpu_dev)
+	info = cpu_info();
+	if (!info)
 		return 0;
-	cpu = find_cpu_driver(cpu_dev);
+	cpu = find_cpu_driver(info->cpu);
 	if (!cpu || !cpu->cstates)
 		return 0;
 
diff --git a/src/cpu/intel/model_206ax/model_206ax_init.c b/src/cpu/intel/model_206ax/model_206ax_init.c
index 2ad8012..9676ad1 100644
--- a/src/cpu/intel/model_206ax/model_206ax_init.c
+++ b/src/cpu/intel/model_206ax/model_206ax_init.c
@@ -430,6 +430,58 @@ static void configure_mca(void)
 static unsigned ehci_debug_addr;
 #endif
 
+/*
+ * Initialize any extra cores/threads in this package.
+ */
+static void intel_cores_init(device_t cpu)
+{
+	struct cpuid_result result;
+	unsigned cores, threads, i;
+
+	result = cpuid_ext(0xb, 0); /* Threads per core */
+	threads = result.ebx & 0xff;
+
+	result = cpuid_ext(0xb, 1); /* Cores per package */
+	cores = result.ebx & 0xff;
+
+	/* Only initialize extra cores from BSP */
+	if (cpu->path.apic.apic_id)
+		return;
+
+	printk(BIOS_DEBUG, "CPU: %u has %u cores %u threads\n",
+	       cpu->path.apic.apic_id, cores, threads);
+
+	for (i = 1; i < cores; ++i) {
+		struct device_path cpu_path;
+		device_t new;
+
+		/* Build the cpu device path */
+		cpu_path.type = DEVICE_PATH_APIC;
+		cpu_path.apic.apic_id =
+			cpu->path.apic.apic_id + i;
+
+		/* Update APIC ID if no hyperthreading */
+		if (threads == 1)
+			cpu_path.apic.apic_id <<= 1;
+
+		/* Allocate the new cpu device structure */
+		new = alloc_dev(cpu->bus, &cpu_path);
+		if (!new)
+			continue;
+
+		printk(BIOS_DEBUG, "CPU: %u has core %u\n",
+		       cpu->path.apic.apic_id,
+		       new->path.apic.apic_id);
+
+		/* Start the new cpu */
+		if (!start_cpu(new)) {
+			/* Record the error in cpu? */
+			printk(BIOS_ERR, "CPU %u would not start!\n",
+			       new->path.apic.apic_id);
+		}
+	}
+}
+
 static void model_206ax_init(device_t cpu)
 {
 	char processor_name[49];
@@ -491,6 +543,9 @@ static void model_206ax_init(device_t cpu)
 
 	/* Enable Turbo */
 	enable_turbo();
+
+	/* Start up extra cores */
+	intel_cores_init(cpu);
 }
 
 static struct device_operations cpu_dev_ops = {
diff --git a/src/cpu/intel/model_6ex/Kconfig b/src/cpu/intel/model_6ex/Kconfig
index c3faa39..31d24bd 100644
--- a/src/cpu/intel/model_6ex/Kconfig
+++ b/src/cpu/intel/model_6ex/Kconfig
@@ -3,3 +3,4 @@ config CPU_INTEL_MODEL_6EX
 	select SMP
 	select SSE2
 	select UDELAY_LAPIC
+	select AP_IN_SIPI_WAIT
diff --git a/src/cpu/intel/model_6ex/model_6ex_init.c b/src/cpu/intel/model_6ex/model_6ex_init.c
index a0afd2e..1c8c72b 100644
--- a/src/cpu/intel/model_6ex/model_6ex_init.c
+++ b/src/cpu/intel/model_6ex/model_6ex_init.c
@@ -205,6 +205,9 @@ static void model_6ex_init(device_t cpu)
 
 	/* PIC thermal sensor control */
 	configure_pic_thermal_sensors();
+
+	/* Start up my cpu siblings */
+	intel_sibling_init(cpu);
 }
 
 static struct device_operations cpu_dev_ops = {
diff --git a/src/cpu/intel/model_6fx/Kconfig b/src/cpu/intel/model_6fx/Kconfig
index 065cdd9..851685c 100644
--- a/src/cpu/intel/model_6fx/Kconfig
+++ b/src/cpu/intel/model_6fx/Kconfig
@@ -3,3 +3,4 @@ config CPU_INTEL_MODEL_6FX
 	select SMP
 	select SSE2
 	select UDELAY_LAPIC
+	select AP_IN_SIPI_WAIT
diff --git a/src/cpu/intel/model_6fx/model_6fx_init.c b/src/cpu/intel/model_6fx/model_6fx_init.c
index c5d7a6b..106719e 100644
--- a/src/cpu/intel/model_6fx/model_6fx_init.c
+++ b/src/cpu/intel/model_6fx/model_6fx_init.c
@@ -243,6 +243,9 @@ static void model_6fx_init(device_t cpu)
 
 	/* PIC thermal sensor control */
 	configure_pic_thermal_sensors();
+
+	/* Start up my cpu siblings */
+	intel_sibling_init(cpu);
 }
 
 static struct device_operations cpu_dev_ops = {
diff --git a/src/cpu/intel/model_f2x/model_f2x_init.c b/src/cpu/intel/model_f2x/model_f2x_init.c
index fa9e05f..8fd8abc 100644
--- a/src/cpu/intel/model_f2x/model_f2x_init.c
+++ b/src/cpu/intel/model_f2x/model_f2x_init.c
@@ -60,6 +60,9 @@ static void model_f2x_init(device_t cpu)
 
 	/* Enable the local cpu apics */
 	setup_lapic();
+
+	/* Start up my cpu siblings */
+	intel_sibling_init(cpu);
 };
 
 static struct device_operations cpu_dev_ops = {
diff --git a/src/cpu/intel/model_f3x/model_f3x_init.c b/src/cpu/intel/model_f3x/model_f3x_init.c
index dd2a45f..2504ba9 100644
--- a/src/cpu/intel/model_f3x/model_f3x_init.c
+++ b/src/cpu/intel/model_f3x/model_f3x_init.c
@@ -43,6 +43,9 @@ static void model_f3x_init(device_t cpu)
 
 	/* Enable the local cpu apics */
 	setup_lapic();
+
+	/* Start up my cpu siblings */
+	intel_sibling_init(cpu);
 };
 
 static struct device_operations cpu_dev_ops = {
diff --git a/src/cpu/intel/model_f4x/model_f4x_init.c b/src/cpu/intel/model_f4x/model_f4x_init.c
index af7d9d2..f3f0b2a 100644
--- a/src/cpu/intel/model_f4x/model_f4x_init.c
+++ b/src/cpu/intel/model_f4x/model_f4x_init.c
@@ -51,6 +51,9 @@ static void model_f4x_init(device_t cpu)
 
 	/* Enable the local cpu apics */
 	setup_lapic();
+
+	/* Start up my cpu siblings */
+	intel_sibling_init(cpu);
 };
 
 static struct device_operations cpu_dev_ops = {
diff --git a/src/cpu/intel/socket_LGA771/Kconfig b/src/cpu/intel/socket_LGA771/Kconfig
index f549210..62bd17b 100644
--- a/src/cpu/intel/socket_LGA771/Kconfig
+++ b/src/cpu/intel/socket_LGA771/Kconfig
@@ -3,3 +3,4 @@ config CPU_INTEL_SOCKET_LGA771
         select CPU_INTEL_MODEL_6FX
 	select SSE2
 	select MMX
+	select AP_IN_SIPI_WAIT
diff --git a/src/cpu/x86/lapic/lapic_cpu_init.c b/src/cpu/x86/lapic/lapic_cpu_init.c
index b6dc560..d61547d 100644
--- a/src/cpu/x86/lapic/lapic_cpu_init.c
+++ b/src/cpu/x86/lapic/lapic_cpu_init.c
@@ -60,28 +60,31 @@ static void copy_secondary_start_to_1m_below(void)
 	printk(BIOS_DEBUG, "start_eip=0x%08lx, code_size=0x%08lx\n", (long unsigned int)AP_SIPI_VECTOR, code_size);
 }
 
-static struct bus *current_cpu_bus;
-
-static int lapic_start_cpus(struct bus *cpu_bus)
+static int lapic_start_cpu(unsigned long apicid)
 {
 	int timeout;
 	unsigned long send_status, accept_status;
-	int maxlvt;
+	int j, num_starts, maxlvt;
 
 	/*
 	 * Starting actual IPI sequence...
 	 */
 
-	current_cpu_bus = cpu_bus;
-
 	printk(BIOS_SPEW, "Asserting INIT.\n");
 
-	/* Send INIT SIPI to target chip */
-	lapic_write_around(LAPIC_ICR2, 0);
-	lapic_write_around(LAPIC_ICR, LAPIC_INT_ASSERT
-				| LAPIC_DM_INIT | LAPIC_DEST_ALLBUT);
+	/*
+	 * Turn INIT on target chip
+	 */
+	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
+
+	/*
+	 * Send IPI
+	 */
+
+	lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_INT_ASSERT
+				| LAPIC_DM_INIT);
 
-	printk(BIOS_DEBUG, "Waiting for send to finish...\n");
+	printk(BIOS_SPEW, "Waiting for send to finish...\n");
 	timeout = 0;
 	do {
 		printk(BIOS_SPEW, "+");
@@ -89,66 +92,106 @@ static int lapic_start_cpus(struct bus *cpu_bus)
 		send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
 	} while (send_status && (timeout++ < 1000));
 	if (timeout >= 1000) {
-		printk(BIOS_DEBUG, "First apic write timed out. Disabling\n");
+		printk(BIOS_ERR, "CPU %ld: First apic write timed out. Disabling\n",
+			 apicid);
 		// too bad.
-		printk(BIOS_DEBUG, "ESR is 0x%lx\n", lapic_read(LAPIC_ESR));
+		printk(BIOS_ERR, "ESR is 0x%lx\n", lapic_read(LAPIC_ESR));
 		if (lapic_read(LAPIC_ESR)) {
-			printk(BIOS_DEBUG, "Try to reset ESR\n");
+			printk(BIOS_ERR, "Try to reset ESR\n");
 			lapic_write_around(LAPIC_ESR, 0);
-			printk(BIOS_DEBUG, "ESR is 0x%lx\n", lapic_read(LAPIC_ESR));
+			printk(BIOS_ERR, "ESR is 0x%lx\n", lapic_read(LAPIC_ESR));
 		}
 		return 0;
 	}
+#if !CONFIG_CPU_AMD_MODEL_10XXX && !CONFIG_CPU_INTEL_MODEL_206AX
+	mdelay(10);
+#endif
 
-	maxlvt = 4;
-
-	printk(BIOS_SPEW, "Sending STARTUP.\n");
-	lapic_read_around(LAPIC_SPIV);
-	lapic_write(LAPIC_ESR, 0);
-	lapic_read(LAPIC_ESR);
-	printk(BIOS_SPEW, "After apic_write.\n");
-
-	/*
-	 * STARTUP IPI
-	 */
+	printk(BIOS_SPEW, "Deasserting INIT.\n");
 
 	/* Target chip */
-	lapic_write_around(LAPIC_ICR2, 0);
-
-	/* Boot on the stack */
-	/* Kick the second */
-	lapic_write_around(LAPIC_ICR, LAPIC_INT_ASSERT | LAPIC_DM_STARTUP | LAPIC_DEST_ALLBUT
-			   | ((AP_SIPI_VECTOR >> 12) & 0xff));
+	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
 
-	/*
-	 * Give the other CPU some time to accept the IPI.
-	 */
-	udelay(300);
+	/* Send IPI */
+	lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_DM_INIT);
 
-	printk(BIOS_DEBUG, "Startup point 1.\n");
-
-	printk(BIOS_DEBUG, "Waiting for send to finish...\n");
+	printk(BIOS_SPEW, "Waiting for send to finish...\n");
 	timeout = 0;
 	do {
-		printk(BIOS_DEBUG, "+");
+		printk(BIOS_SPEW, "+");
 		udelay(100);
 		send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
 	} while (send_status && (timeout++ < 1000));
+	if (timeout >= 1000) {
+		printk(BIOS_ERR, "CPU %ld: Second apic write timed out. Disabling\n",
+			 apicid);
+		// too bad.
+		return 0;
+	}
+
+#if !CONFIG_CPU_AMD_MODEL_10XXX
+	num_starts = 2;
+#else
+	num_starts = 1;
+#endif
 
 	/*
-	 * Give the other CPU some time to accept the IPI.
-	 */
-	udelay(200);
-	/*
-	 * Due to the Pentium erratum 3AP.
+	 * Run STARTUP IPI loop.
 	 */
-	if (maxlvt > 3) {
+	printk(BIOS_SPEW, "#startup loops: %d.\n", num_starts);
+
+	maxlvt = 4;
+
+	for (j = 1; j <= num_starts; j++) {
+		printk(BIOS_SPEW, "Sending STARTUP #%d to %lu.\n", j, apicid);
 		lapic_read_around(LAPIC_SPIV);
 		lapic_write(LAPIC_ESR, 0);
+		lapic_read(LAPIC_ESR);
+		printk(BIOS_SPEW, "After apic_write.\n");
+
+		/*
+		 * STARTUP IPI
+		 */
+
+		/* Target chip */
+		lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
+
+		/* Boot on the stack */
+		/* Kick the second */
+		lapic_write_around(LAPIC_ICR, LAPIC_DM_STARTUP
+					| (AP_SIPI_VECTOR >> 12));
+
+		/*
+		 * Give the other CPU some time to accept the IPI.
+		 */
+		udelay(300);
+
+		printk(BIOS_SPEW, "Startup point 1.\n");
+
+		printk(BIOS_SPEW, "Waiting for send to finish...\n");
+		timeout = 0;
+		do {
+			printk(BIOS_SPEW, "+");
+			udelay(100);
+			send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
+		} while (send_status && (timeout++ < 1000));
+
+		/*
+		 * Give the other CPU some time to accept the IPI.
+		 */
+		udelay(200);
+		/*
+		 * Due to the Pentium erratum 3AP.
+		 */
+		if (maxlvt > 3) {
+			lapic_read_around(LAPIC_SPIV);
+			lapic_write(LAPIC_ESR, 0);
+		}
+		accept_status = (lapic_read(LAPIC_ESR) & 0xEF);
+		if (send_status || accept_status)
+			break;
 	}
-	accept_status = (lapic_read(LAPIC_ESR) & 0xEF);
-
-	printk(BIOS_DEBUG, "After Startup.\n");
+	printk(BIOS_SPEW, "After Startup.\n");
 	if (send_status)
 		printk(BIOS_WARNING, "APIC never delivered???\n");
 	if (accept_status)
@@ -158,34 +201,156 @@ static int lapic_start_cpus(struct bus *cpu_bus)
 	return 1;
 }
 
-
 /* Number of cpus that are currently running in coreboot */
 static atomic_t active_cpus = ATOMIC_INIT(1);
 
+/* start_cpu_lock covers last_cpu_index and secondary_stack.
+ * Only starting one cpu at a time let's me remove the logic
+ * for select the stack from assembly language.
+ *
+ * In addition communicating by variables to the cpu I
+ * am starting allows me to veryify it has started before
+ * start_cpu returns.
+ */
+
+static spinlock_t start_cpu_lock = SPIN_LOCK_UNLOCKED;
+static unsigned last_cpu_index = 0;
 volatile unsigned long secondary_stack;
-extern unsigned char _estack[];
 
-static void stop_all_ap_cpus(void)
+int start_cpu(device_t cpu)
+{
+	extern unsigned char _estack[];
+	struct cpu_info *info;
+	unsigned long stack_end;
+	unsigned long apicid;
+	unsigned long index;
+	unsigned long count;
+	int result;
+
+	spin_lock(&start_cpu_lock);
+
+	/* Get the cpu's apicid */
+	apicid = cpu->path.apic.apic_id;
+
+	/* Get an index for the new processor */
+	index = ++last_cpu_index;
+
+	/* Find end of the new processors stack */
+	stack_end = ((unsigned long)_estack) - (CONFIG_STACK_SIZE*index) - sizeof(struct cpu_info);
+
+	/* Record the index and which cpu structure we are using */
+	info = (struct cpu_info *)stack_end;
+	info->index = index;
+	info->cpu   = cpu;
+
+	/* Advertise the new stack to start_cpu */
+	secondary_stack = stack_end;
+
+	/* Until the cpu starts up report the cpu is not enabled */
+	cpu->enabled = 0;
+	cpu->initialized = 0;
+
+	/* Start the cpu */
+	result = lapic_start_cpu(apicid);
+
+	if (result) {
+		result = 0;
+		/* Wait 1s or until the new cpu calls in */
+		for(count = 0; count < 100000 ; count++) {
+			if (secondary_stack == 0) {
+				result = 1;
+				break;
+			}
+			udelay(10);
+	}
+	}
+	secondary_stack = 0;
+	spin_unlock(&start_cpu_lock);
+	return result;
+}
+
+#if CONFIG_AP_IN_SIPI_WAIT
+
+/**
+ * Sending INIT IPI to self is equivalent of asserting #INIT with a bit of delay.
+ * An undefined number of instruction cycles will complete. All global locks
+ * must be released before INIT IPI and no printk is allowed after this.
+ * De-asserting INIT IPI is a no-op on later Intel CPUs.
+ *
+ * If you set DEBUG_HALT_SELF to 1, printk's after INIT IPI are enabled
+ * but running thread may halt without releasing the lock and effectively
+ * deadlock other CPUs.
+ */
+#define DEBUG_HALT_SELF 0
+
+/**
+ * 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)
 {
-	unsigned long send_status;
 	int timeout;
-	/* send an LAPIC INIT to all but myself */
-	lapic_write_around(LAPIC_ICR2, 0);
-	lapic_write_around(LAPIC_ICR, LAPIC_INT_ASSERT | LAPIC_DM_INIT | LAPIC_DEST_ALLBUT);
+	unsigned long send_status;
+	unsigned long id;
+
+	id = lapic_read(LAPIC_ID) >> 24;
+
+	printk(BIOS_DEBUG, "CPU %ld going down...\n", id);
+
+	/* send an LAPIC INIT to myself */
+	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(id));
+	lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_INT_ASSERT | LAPIC_DM_INIT);
 
 	/* wait for the ipi send to finish */
+#if DEBUG_HALT_SELF
 	printk(BIOS_SPEW, "Waiting for send to finish...\n");
+#endif
 	timeout = 0;
 	do {
+#if DEBUG_HALT_SELF
 		printk(BIOS_SPEW, "+");
+#endif
 		udelay(100);
 		send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
 	} while (send_status && (timeout++ < 1000));
 	if (timeout >= 1000) {
+#if DEBUG_HALT_SELF
 		printk(BIOS_ERR, "timed out\n");
+#endif
 	}
 	mdelay(10);
+
+#if DEBUG_HALT_SELF
+	printk(BIOS_SPEW, "Deasserting INIT.\n");
+#endif
+	/* Deassert the LAPIC INIT */
+	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(id));
+	lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_DM_INIT);
+
+#if DEBUG_HALT_SELF
+	printk(BIOS_SPEW, "Waiting for send to finish...\n");
+#endif
+	timeout = 0;
+	do {
+#if DEBUG_HALT_SELF
+		printk(BIOS_SPEW, "+");
+#endif
+		udelay(100);
+		send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
+	} while (send_status && (timeout++ < 1000));
+	if (timeout >= 1000) {
+#if DEBUG_HALT_SELF
+		printk(BIOS_ERR, "timed out\n");
+#endif
+	}
+
+	while(1) {
+		hlt();
+	}
 }
+#endif
 
 #ifdef __SSE3__
 static __inline__ __attribute__((always_inline)) unsigned long readcr4(void)
@@ -208,21 +373,66 @@ static __inline__ __attribute__((always_inline)) void writecr4(unsigned long Dat
 #endif
 
 /* C entry point of secondary cpus */
-void secondary_cpu_init(int index)
+void secondary_cpu_init(void)
 {
+	atomic_inc(&active_cpus);
+#if CONFIG_SERIAL_CPU_INIT
+	spin_lock(&start_cpu_lock);
+#endif
+
 #ifdef __SSE3__
-        /*
-         * Seems that CR4 was cleared when AP start via lapic_start_cpu()
-         * Turn on CR4.OSFXSR and CR4.OSXMMEXCPT when SSE options enabled
-         */
-        u32 cr4_val;
-        cr4_val = readcr4();
-        cr4_val |= (1 << 9 | 1 << 10);
-        writecr4(cr4_val);
+	/*
+	 * Seems that CR4 was cleared when AP start via lapic_start_cpu()
+	 * Turn on CR4.OSFXSR and CR4.OSXMMEXCPT when SSE options enabled
+	 */
+	u32 cr4_val;
+	cr4_val = readcr4();
+	cr4_val |= (1 << 9 | 1 << 10);
+	writecr4(cr4_val);
 #endif
-	atomic_inc(&active_cpus);
-	cpu_initialize(current_cpu_bus, index);
+	cpu_initialize();
+#if CONFIG_SERIAL_CPU_INIT
+	spin_unlock(&start_cpu_lock);
+#endif
+
 	atomic_dec(&active_cpus);
+
+	stop_this_cpu();
+}
+
+static void start_other_cpus(struct bus *cpu_bus, device_t bsp_cpu)
+{
+	device_t cpu;
+	/* Loop through the cpus once getting them started */
+
+	for(cpu = cpu_bus->children; cpu ; cpu = cpu->sibling) {
+		if (cpu->path.type != DEVICE_PATH_APIC) {
+			continue;
+		}
+	#if !CONFIG_SERIAL_CPU_INIT
+		if(cpu==bsp_cpu) {
+			continue;
+		}
+	#endif
+
+		if (!cpu->enabled) {
+			continue;
+		}
+
+		if (cpu->initialized) {
+			continue;
+		}
+
+		if (!start_cpu(cpu)) {
+			/* Record the error in cpu? */
+			printk(BIOS_ERR, "CPU 0x%02x would not start!\n",
+				cpu->path.apic.apic_id);
+		}
+#if CONFIG_SERIAL_CPU_INIT
+		udelay(10);
+#endif
+	}
+
 }
 
 static void wait_other_cpus_stop(struct bus *cpu_bus)
@@ -255,7 +465,6 @@ static void wait_other_cpus_stop(struct bus *cpu_bus)
 				cpu->path.apic.apic_id);
 		}
 	}
-	stop_all_ap_cpus();
 	printk(BIOS_DEBUG, "All AP CPUs stopped (%ld loops)\n", loopcount);
 }
 
@@ -264,6 +473,10 @@ static void wait_other_cpus_stop(struct bus *cpu_bus)
 void initialize_cpus(struct bus *cpu_bus)
 {
 	struct device_path cpu_path;
+	struct cpu_info *info;
+
+	/* Find the info struct for this cpu */
+	info = cpu_info();
 
 #if NEED_LAPIC == 1
 	/* Ensure the local apic is enabled */
@@ -278,6 +491,9 @@ void initialize_cpus(struct bus *cpu_bus)
 	cpu_path.cpu.id       = 0;
 #endif
 
+	/* Find the device structure for the boot cpu */
+	info->cpu = alloc_find_dev(cpu_bus, &cpu_path);
+
 #if CONFIG_SMP
 	copy_secondary_start_to_1m_below(); // why here? In case some day we can start core1 in amd_sibling_init
 #endif
@@ -288,11 +504,21 @@ void initialize_cpus(struct bus *cpu_bus)
 
 	cpus_ready_for_init();
 
+#if CONFIG_SMP
+	#if !CONFIG_SERIAL_CPU_INIT
+	/* start all aps at first, so we can init ECC all together */
+	start_other_cpus(cpu_bus, info->cpu);
+	#endif
+#endif
+
 	/* Initialize the bootstrap processor */
-	cpu_initialize(cpu_bus, 0);
+	cpu_initialize();
 
 #if CONFIG_SMP
-	lapic_start_cpus(cpu_bus);
+	#if CONFIG_SERIAL_CPU_INIT
+	start_other_cpus(cpu_bus, info->cpu);
+	#endif
+
 	/* Now wait the rest of the cpus stop*/
 	wait_other_cpus_stop(cpu_bus);
 #endif
diff --git a/src/cpu/x86/lapic/secondary.S b/src/cpu/x86/lapic/secondary.S
index e6650ec..ec1bd9c 100644
--- a/src/cpu/x86/lapic/secondary.S
+++ b/src/cpu/x86/lapic/secondary.S
@@ -2,7 +2,8 @@
 #include <cpu/x86/lapic_def.h>
 
 	.text
-	.globl _secondary_start, _secondary_start_end, cpucount, ap_protected_start
+	.globl _secondary_start, _secondary_start_end
+	.balign 4096
 _secondary_start:
 	.code16
 	cli
@@ -49,22 +50,13 @@ __ap_protected_start:
 	/* Load the Interrupt descriptor table */
 	lidt	idtarg
 
-	/* increment our cpu index */
-	movl	$1, %eax
-	lock	xadd %eax, cpucount
-	movl	%eax, %ecx
-
-	/* assign stack for this specific cpu */
-	mov	$_stack, %esp
-	mov	$CONFIG_STACK_SIZE, %ebx
-	mul	%ebx
-	add	%eax, %esp
+	/* Set the stack pointer, and flag that we are done */
+	xorl	%eax, %eax
+	movl	secondary_stack, %esp
+	movl	%eax, secondary_stack
 
-	pushl	%ecx
 	call	secondary_cpu_init
 1:	hlt
 	jmp	1b
 
-cpucount:
-	.long	1
 .code32
diff --git a/src/cpu/x86/pae/pgtbl.c b/src/cpu/x86/pae/pgtbl.c
index 7aa17c2..814c5f1 100644
--- a/src/cpu/x86/pae/pgtbl.c
+++ b/src/cpu/x86/pae/pgtbl.c
@@ -3,10 +3,8 @@
 */
 
 #include <console/console.h>
-#include <device/device.h>
 #include <cpu/cpu.h>
 #include <cpu/x86/pae.h>
-#include <cpu/x86/lapic.h>
 #include <string.h>
 
 static void paging_off(void)
@@ -45,14 +43,6 @@ static void paging_on(void *pdp)
 		);
 }
 
-static int cpu_index(void)
-{
-	device_t dev = dev_find_lapic(lapicid());
-	if (!dev)
-		return -1;
-	return dev->path.apic.index;
-}
-
 void *map_2M_page(unsigned long page)
 {
 	struct pde {
@@ -70,9 +60,7 @@ void *map_2M_page(unsigned long page)
 	unsigned long window;
 	void *result;
 	int i;
-
 	index = cpu_index();
-
 	if ((index < 0) || (index >= CONFIG_MAX_CPUS)) {
 		return MAPPING_ERROR;
 	}
diff --git a/src/drivers/i2c/w83795/w83795.c b/src/drivers/i2c/w83795/w83795.c
index 12be4da..392471a 100644
--- a/src/drivers/i2c/w83795/w83795.c
+++ b/src/drivers/i2c/w83795/w83795.c
@@ -22,7 +22,6 @@
 #include <console/console.h>
 #include <device/device.h>
 #include "southbridge/amd/cimx/sb700/smbus.h" /*SMBUS_IO_BASE*/
-#include <cpu/x86/lapic.h>
 #include "w83795.h"
 
 static u32 w83795_set_bank(u8 bank)
@@ -225,8 +224,10 @@ static void w83795_init(w83795_fan_mode_t mode, u8 dts_src)
 static void w83795_hwm_init(device_t dev)
 {
 	struct device *cpu;
+	struct cpu_info *info;
 
-	cpu = dev_find_lapic(lapicid());
+	info = cpu_info();
+	cpu = info->cpu;
 	if (!cpu)
 		die("CPU: missing cpu device structure");
 
diff --git a/src/include/cpu/cpu.h b/src/include/cpu/cpu.h
index 9765dfd..c2113c1 100644
--- a/src/include/cpu/cpu.h
+++ b/src/include/cpu/cpu.h
@@ -4,12 +4,10 @@
 #include <arch/cpu.h>
 
 #if !defined(__ROMCC__)
-void cpu_initialize(struct bus *cpu_bus, int index);
+void cpu_initialize(void);
 struct bus;
 void initialize_cpus(struct bus *cpu_bus);
-void secondary_cpu_init(int index);
-
-extern unsigned int cpucount;
+void secondary_cpu_init(void);
 
 #if !CONFIG_WAIT_BEFORE_CPUS_INIT
 	#define cpus_ready_for_init() do {} while(0)
diff --git a/src/include/cpu/x86/lapic.h b/src/include/cpu/x86/lapic.h
index 5c48025..078f2a7 100644
--- a/src/include/cpu/x86/lapic.h
+++ b/src/include/cpu/x86/lapic.h
@@ -52,13 +52,20 @@ static inline __attribute__((always_inline)) unsigned long lapicid(void)
 }
 
 #ifndef __ROMCC__
+#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)
 {
-       /* Called by an AP when it is ready to halt and wait for a new task */
-       for(;;) {
-               hlt();
-       }
+	/* Called by an AP when it is ready to halt and wait for a new task */
+	for(;;) {
+		hlt();
+	}
 }
+#else
+void stop_this_cpu(void);
+#endif
 
 #if !defined(__PRE_RAM__)
 
diff --git a/src/include/device/path.h b/src/include/device/path.h
index 3dc7625..5af761e 100644
--- a/src/include/device/path.h
+++ b/src/include/device/path.h
@@ -41,7 +41,6 @@ struct apic_path
 	unsigned apic_id;
 	unsigned node_id;
 	unsigned core_id;
-	unsigned index;
 };
 
 struct ioapic_path




More information about the coreboot mailing list