diff options
author | Kyösti Mälkki <kyosti.malkki@gmail.com> | 2021-05-29 22:50:22 +0300 |
---|---|---|
committer | Kyösti Mälkki <kyosti.malkki@gmail.com> | 2021-06-10 17:51:51 +0000 |
commit | 36c90179f0c7ef0d11ca78a109bd563b3ec0e0a9 (patch) | |
tree | 4283ee34bfff7b053fae614c66fe380282a668fa | |
parent | 68fe11beb0c27c2ae995ab0fa190960d8813e32c (diff) |
cpu/x86/lapic: Separate stop_this_cpu()
Function is needed with PARALLEL_MP and excluding guard will
be added to the source file.
The incompatibilities with X2APIC_SUPPORT have been fixed
so the exclusion is removed here too.
Change-Id: I5696da4dfe98579a3b37a027966b6758f22574aa
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55193
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
-rw-r--r-- | src/cpu/x86/Kconfig | 2 | ||||
-rw-r--r-- | src/cpu/x86/lapic/Makefile.inc | 6 | ||||
-rw-r--r-- | src/cpu/x86/lapic/lapic_cpu_init.c | 68 | ||||
-rw-r--r-- | src/cpu/x86/lapic/lapic_cpu_stop.c | 70 | ||||
-rw-r--r-- | src/include/cpu/x86/lapic.h | 2 |
5 files changed, 75 insertions, 73 deletions
diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig index d7057ad861..84b1fc1297 100644 --- a/src/cpu/x86/Kconfig +++ b/src/cpu/x86/Kconfig @@ -29,13 +29,11 @@ config X2APIC_ONLY prompt "Set X2APIC mode" bool depends on PARALLEL_MP - depends on !AP_IN_SIPI_WAIT config X2APIC_RUNTIME prompt "Support both XAPIC and X2APIC" bool depends on PARALLEL_MP - depends on !AP_IN_SIPI_WAIT endchoice diff --git a/src/cpu/x86/lapic/Makefile.inc b/src/cpu/x86/lapic/Makefile.inc index 8e89d29f68..91a41f76a5 100644 --- a/src/cpu/x86/lapic/Makefile.inc +++ b/src/cpu/x86/lapic/Makefile.inc @@ -1,5 +1,7 @@ -ramstage-y += lapic_cpu_init.c -ramstage-$(CONFIG_SMP) += secondary.S +ramstage-$(CONFIG_AP_IN_SIPI_WAIT) += lapic_cpu_stop.c +ramstage-$(CONFIG_LEGACY_SMP_INIT) += lapic_cpu_init.c +ramstage-$(CONFIG_LEGACY_SMP_INIT) += secondary.S + bootblock-$(CONFIG_UDELAY_LAPIC) += apic_timer.c romstage-$(CONFIG_UDELAY_LAPIC) += apic_timer.c ramstage-$(CONFIG_UDELAY_LAPIC) += apic_timer.c diff --git a/src/cpu/x86/lapic/lapic_cpu_init.c b/src/cpu/x86/lapic/lapic_cpu_init.c index d01fb91a19..9b5825a6a8 100644 --- a/src/cpu/x86/lapic/lapic_cpu_init.c +++ b/src/cpu/x86/lapic/lapic_cpu_init.c @@ -6,7 +6,6 @@ #include <cpu/x86/smi_deprecated.h> #include <acpi/acpi.h> #include <delay.h> -#include <halt.h> #include <lib.h> #include <string.h> #include <symbols.h> @@ -283,73 +282,6 @@ static int start_cpu(struct device *cpu) 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 - -#if DEBUG_HALT_SELF -#define dprintk(LEVEL, args...) do { printk(LEVEL, ##args); } while (0) -#else -#define dprintk(LEVEL, args...) do { } while (0) -#endif - -static void wait_for_ipi_completion_without_printk(const int timeout_ms) -{ - int loops = timeout_ms * 10; - uint32_t send_status; - - /* wait for the ipi send to finish */ - dprintk(BIOS_SPEW, "Waiting for send to finish...\n"); - do { - dprintk(BIOS_SPEW, "+"); - udelay(100); - send_status = lapic_busy(); - } while (send_status && (--loops > 0)); - - if (send_status) - dprintk(BIOS_ERR, "timed out\n"); -} - -/** - * 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) -{ - const int timeout_100ms = 100; - unsigned long id = lapicid(); - - printk(BIOS_DEBUG, "CPU %ld going down...\n", id); - - /* send an LAPIC INIT to myself */ - lapic_send_ipi(LAPIC_INT_LEVELTRIG | LAPIC_INT_ASSERT | LAPIC_DM_INIT, id); - wait_for_ipi_completion_without_printk(timeout_100ms); - - mdelay(10); - - dprintk(BIOS_SPEW, "Deasserting INIT.\n"); - - /* Deassert the LAPIC INIT */ - lapic_send_ipi(LAPIC_INT_LEVELTRIG | LAPIC_DM_INIT, id); - wait_for_ipi_completion_without_printk(timeout_100ms); - - halt(); -} -#endif - /* C entry point of secondary cpus */ asmlinkage void secondary_cpu_init(unsigned int index) { diff --git a/src/cpu/x86/lapic/lapic_cpu_stop.c b/src/cpu/x86/lapic/lapic_cpu_stop.c new file mode 100644 index 0000000000..e933ce4c47 --- /dev/null +++ b/src/cpu/x86/lapic/lapic_cpu_stop.c @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <console/console.h> +#include <cpu/x86/lapic.h> +#include <delay.h> +#include <halt.h> + +/** + * 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 + +#if DEBUG_HALT_SELF +#define dprintk(LEVEL, args...) do { printk(LEVEL, ##args); } while (0) +#else +#define dprintk(LEVEL, args...) do { } while (0) +#endif + +static void wait_for_ipi_completion_without_printk(const int timeout_ms) +{ + int loops = timeout_ms * 10; + uint32_t send_status; + + /* wait for the ipi send to finish */ + dprintk(BIOS_SPEW, "Waiting for send to finish...\n"); + do { + dprintk(BIOS_SPEW, "+"); + udelay(100); + send_status = lapic_busy(); + } while (send_status && (--loops > 0)); + + if (send_status) + dprintk(BIOS_ERR, "timed out\n"); +} + +/** + * 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) +{ + const int timeout_100ms = 100; + unsigned long id = lapicid(); + + printk(BIOS_DEBUG, "CPU %ld going down...\n", id); + + /* send an LAPIC INIT to myself */ + lapic_send_ipi(LAPIC_INT_LEVELTRIG | LAPIC_INT_ASSERT | LAPIC_DM_INIT, id); + wait_for_ipi_completion_without_printk(timeout_100ms); + + mdelay(10); + + dprintk(BIOS_SPEW, "Deasserting INIT.\n"); + + /* Deassert the LAPIC INIT */ + lapic_send_ipi(LAPIC_INT_LEVELTRIG | LAPIC_DM_INIT, id); + wait_for_ipi_completion_without_printk(timeout_100ms); + + halt(); +} diff --git a/src/include/cpu/x86/lapic.h b/src/include/cpu/x86/lapic.h index 4647877ae9..d5e5edca9a 100644 --- a/src/include/cpu/x86/lapic.h +++ b/src/include/cpu/x86/lapic.h @@ -159,7 +159,7 @@ static __always_inline unsigned int lapicid(void) #if !CONFIG(AP_IN_SIPI_WAIT) /* If we need to go back to sipi wait, we use the long non-inlined version of - * this function in lapic_cpu_init.c + * this function in lapic_cpu_stop.c */ static __always_inline void stop_this_cpu(void) { |