Use broadcast SIPI to startup siblings

The current code for initializing AP cpus has several shortcomings:

- it assumes APIC IDs are sequential
- it uses only the BSP for determining the AP count, which is bad if
  there's more than one physical CPU, and CPUs are of different type

Note that the new code call cpu->ops->init() in parallel, and therefore
some CPU code needs to be changed to address that. One example are old
Intel HT enabled CPUs which can't do microcode update in parallel.

Change-Id: Ic48a1ebab6a7c52aa76765f497268af09fa38c25
Signed-off-by: Sven Schnelle <svens@stackframe.org>
Reviewed-on: http://review.coreboot.org/1139
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
This commit is contained in:
Sven Schnelle
2012-06-17 10:32:55 +02:00
committed by Ronald G. Minnich
parent 9ed1456eff
commit 042c1461fb
25 changed files with 143 additions and 519 deletions

View File

@@ -3,10 +3,6 @@ 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.

View File

@@ -158,30 +158,6 @@ 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 */

View File

@@ -9,6 +9,7 @@
#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)
@@ -234,7 +235,11 @@ static void set_cpu_ops(struct device *cpu)
cpu->ops = driver ? driver->ops : NULL;
}
void cpu_initialize(void)
#if CONFIG_SMP
static spinlock_t start_cpu_lock = SPIN_LOCK_UNLOCKED;
#endif
void cpu_initialize(struct bus *cpu_bus, int index)
{
/* Because we busy wait at the printk spinlock.
* It is important to keep the number of printed messages
@@ -242,17 +247,22 @@ void cpu_initialize(void)
* disabled.
*/
struct device *cpu;
struct cpu_info *info;
struct cpuinfo_x86 c;
struct device_path cpu_path;
unsigned char id = lapicid();
info = cpu_info();
cpu_path.type = DEVICE_PATH_APIC;
cpu_path.apic.apic_id = id;
cpu_path.apic.index = index;
printk(BIOS_INFO, "Initializing CPU #%ld\n", info->index);
cpu = info->cpu;
if (!cpu) {
die("CPU: missing cpu device structure");
}
#if CONFIG_SMP
spin_lock(&start_cpu_lock);
#endif
cpu = alloc_find_dev(cpu_bus, &cpu_path);
#if CONFIG_SMP
spin_unlock(&start_cpu_lock);
#endif
printk(BIOS_DEBUG, "Initializing CPU #%d\n", id);
/* Find what type of cpu we are dealing with */
identify_cpu(cpu);
@@ -276,7 +286,6 @@ void cpu_initialize(void)
printk(BIOS_DEBUG, "Using generic cpu ops (good)\n");
}
/* Initialize the cpu */
if (cpu->ops && cpu->ops->init) {
cpu->enabled = 1;
@@ -284,7 +293,7 @@ void cpu_initialize(void)
cpu->ops->init(cpu);
}
printk(BIOS_INFO, "CPU #%ld initialized\n", info->index);
printk(BIOS_INFO, "CPU #%d initialized\n", id);
return;
}