summaryrefslogtreecommitdiff
path: root/src/cpu/intel/haswell/haswell_init.c
diff options
context:
space:
mode:
authorAaron Durbin <adurbin@chromium.org>2013-01-15 08:27:05 -0600
committerRonald G. Minnich <rminnich@gmail.com>2013-03-19 05:15:22 +0100
commit305b1f0d30b68c310d4dfa7e1a5f432769a65b31 (patch)
tree2f2846f6ca998bf27ac69d817b97c50ded36a845 /src/cpu/intel/haswell/haswell_init.c
parent98ffb426f40593f930388c006f8058c199defff4 (diff)
downloadcoreboot-305b1f0d30b68c310d4dfa7e1a5f432769a65b31.tar.xz
haswell: Parallel AP bringup
This patch parallelizes the AP startup for Haswell-based devices. It does not touch the generic secondary startup code. Instead it provides its own MP support matching up with the Haswell BWG. It seemed to be too much trouble to support the old startup way and this new way. Because of that parallel loading is the only thing supported. A couple of things to note: 1. Micrcode needs to be loaded twice. Once before MTRR and caching is enabled. And a second time after SMM relocation. 2. The sipi_vector is entirely self-contained. Once it is loaded and written back to RAM the APs do not access memory outside of the sipi_vector load location until a sync up in ramstage. 3. SMM relocation is kicked off by an IPI to self w/ SMI set as the destination mode. The following are timings from cbmem with dev mode disabled and recovery mode enabled to boot directly into the kernel. This was done on the baskingridge CRB with a 4-core 8-thread CPU and 2 DIMMs 1GiB each. The kernel has console enabled on the serial port. Entry 70 is the device initialization, and that is where the APs are brought up. With these two examples it looks to shave off ~200 ms of boot time. Before: 1:55,382 2:57,606 (2,223) 3:3,108,983 (3,051,377) 4:3,110,084 (1,101) 8:3,113,109 (3,024) 9:3,156,694 (43,585) 10:3,156,815 (120) 30:3,157,110 (295) 40:3,158,180 (1,069) 50:3,160,157 (1,977) 60:3,160,366 (208) 70:4,221,044 (1,060,677) 75:4,221,062 (18) 80:4,227,185 (6,122) 90:4,227,669 (484) 99:4,265,596 (37,927) 1000:4,267,822 (2,225) 1001:4,268,507 (685) 1002:4,268,780 (272) 1003:4,398,676 (129,896) 1004:4,398,979 (303) 1100:7,477,601 (3,078,621) 1101:7,480,210 (2,608) After: 1:49,518 2:51,778 (2,259) 3:3,081,186 (3,029,407) 4:3,082,252 (1,066) 8:3,085,137 (2,884) 9:3,130,339 (45,202) 10:3,130,518 (178) 30:3,130,544 (26) 40:3,131,125 (580) 50:3,133,023 (1,897) 60:3,133,278 (255) 70:4,009,259 (875,980) 75:4,009,273 (13) 80:4,015,947 (6,674) 90:4,016,430 (482) 99:4,056,265 (39,835) 1000:4,058,492 (2,226) 1001:4,059,176 (684) 1002:4,059,450 (273) 1003:4,189,333 (129,883) 1004:4,189,770 (436) 1100:7,262,358 (3,072,588) 1101:7,263,926 (1,567) Booted the baskingridge board as noted above. Also analyzed serial messages with pcserial enabled. Change-Id: Ifedc7f787953647c228b11afdb725686e38c4098 Signed-off-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: http://review.coreboot.org/2779 Tested-by: build bot (Jenkins) Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Diffstat (limited to 'src/cpu/intel/haswell/haswell_init.c')
-rw-r--r--src/cpu/intel/haswell/haswell_init.c145
1 files changed, 50 insertions, 95 deletions
diff --git a/src/cpu/intel/haswell/haswell_init.c b/src/cpu/intel/haswell/haswell_init.c
index 9e62b31eb9..82430b750d 100644
--- a/src/cpu/intel/haswell/haswell_init.c
+++ b/src/cpu/intel/haswell/haswell_init.c
@@ -442,71 +442,30 @@ 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 threads_per_package, threads_per_core, i;
-
- /* Logical processors (threads) per core */
- result = cpuid_ext(0xb, 0);
- threads_per_core = result.ebx & 0xffff;
-
- /* Logical processors (threads) per package */
- result = cpuid_ext(0xb, 1);
- threads_per_package = result.ebx & 0xffff;
-
- /* Only initialize extra cores from BSP */
- if (cpu->path.apic.apic_id)
- return;
-
- printk(BIOS_DEBUG, "CPU: %u has %u cores, %u threads per core\n",
- cpu->path.apic.apic_id, threads_per_package/threads_per_core,
- threads_per_core);
-
- for (i = 1; i < threads_per_package; ++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_per_core == 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);
-
-#if CONFIG_SMP && CONFIG_MAX_CPUS > 1
- /* 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);
- }
-#endif
- }
-}
-
-static void bsp_init_before_ap_bringup(void)
+static void bsp_init_before_ap_bringup(struct bus *cpu_bus)
{
+ struct device_path cpu_path;
+ struct cpu_info *info;
char processor_name[49];
/* Print processor name */
fill_processor_name(processor_name);
printk(BIOS_INFO, "CPU: %s.\n", processor_name);
+ /* Ensure the local apic is enabled */
+ enable_lapic();
+
+ /* Set the device path of the boot cpu. */
+ cpu_path.type = DEVICE_PATH_APIC;
+ cpu_path.apic.apic_id = lapicid();
+
+ /* Find the device structure for the boot cpu. */
+ info = cpu_info();
+ info->cpu = alloc_find_dev(cpu_bus, &cpu_path);
+
+ if (info->index != 0)
+ printk(BIOS_CRIT, "BSP index(%d) != 0!\n", info->index);
+
#if CONFIG_USBDEBUG
// Is this caution really needed?
if(!ehci_debug_addr)
@@ -523,23 +482,12 @@ static void bsp_init_before_ap_bringup(void)
set_ehci_debug(ehci_debug_addr);
#endif
- enable_lapic();
-}
-
-static void ap_init(device_t cpu)
-{
- /* Microcode needs to be loaded before caching is enabled. */
- intel_update_microcode_from_cbfs();
-
- /* Turn on caching if we haven't already */
- x86_enable_cache();
- x86_setup_fixed_mtrrs();
- x86_setup_var_mtrrs(cpuid_eax(0x80000008) & 0xff, 2);
-
- enable_lapic();
+ /* Call through the cpu driver's initialization. */
+ cpu_initialize(0);
}
-static void cpu_common_init(device_t cpu)
+/* All CPUs including BSP will run the following function. */
+static void haswell_init(device_t cpu)
{
/* Clear out pending MCEs */
configure_mca();
@@ -572,33 +520,40 @@ static void cpu_common_init(device_t cpu)
void bsp_init_and_start_aps(struct bus *cpu_bus)
{
+ int max_cpus;
+ int num_aps;
+ const void *microcode_patch;
+
/* Perform any necesarry BSP initialization before APs are brought up.
* This call alos allows the BSP to prepare for any secondary effects
* from calling cpu_initialize() such as smm_init(). */
- bsp_init_before_ap_bringup();
-
- /*
- * This calls into the gerneic initialize_cpus() which attempts to
- * start APs on the APIC bus in the devicetree. No APs get started
- * because there is only the BSP and a placeholder (disabled) in the
- * devicetree. initialize_cpus() also does SMM initialization by way
- * of smm_init(). It will eventually call cpu_initialize(0) which calls
- * dev_ops->init(). For Haswell the dev_ops->init() starts up the APs
- * by way of intel_cores_init().
- */
- initialize_cpus(cpu_bus);
-}
+ bsp_init_before_ap_bringup(cpu_bus);
-static void haswell_init(device_t cpu)
-{
- if (cpu->path.apic.apic_id == 0) {
- cpu_common_init(cpu);
- /* Start up extra cores */
- intel_cores_init(cpu);
- } else {
- ap_init(cpu);
- cpu_common_init(cpu);
+ microcode_patch = intel_microcode_find();
+
+ /* This needs to be called after the mtrr setup so the BSP mtrrs
+ * can be mirrored by the APs. */
+ if (setup_ap_init(cpu_bus, &max_cpus, microcode_patch)) {
+ printk(BIOS_CRIT, "AP setup initialization failed. "
+ "No APs will be brought up.\n");
+ return;
+ }
+
+ num_aps = max_cpus - 1;
+ if (start_aps(cpu_bus, num_aps)) {
+ printk(BIOS_CRIT, "AP startup failed. Trying to continue.\n");
}
+
+ if (smm_initialize()) {
+ printk(BIOS_CRIT, "SMM Initialiazation failed...\n");
+ return;
+ }
+
+ /* Release APs to perform SMM relocation. */
+ release_aps_for_smm_relocation();
+
+ /* After SMM relocation a 2nd microcode load is required. */
+ intel_microcode_load_unlocked(microcode_patch);
}
static struct device_operations cpu_dev_ops = {