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>
This commit is contained in:
@@ -29,13 +29,11 @@ config X2APIC_ONLY
|
|||||||
prompt "Set X2APIC mode"
|
prompt "Set X2APIC mode"
|
||||||
bool
|
bool
|
||||||
depends on PARALLEL_MP
|
depends on PARALLEL_MP
|
||||||
depends on !AP_IN_SIPI_WAIT
|
|
||||||
|
|
||||||
config X2APIC_RUNTIME
|
config X2APIC_RUNTIME
|
||||||
prompt "Support both XAPIC and X2APIC"
|
prompt "Support both XAPIC and X2APIC"
|
||||||
bool
|
bool
|
||||||
depends on PARALLEL_MP
|
depends on PARALLEL_MP
|
||||||
depends on !AP_IN_SIPI_WAIT
|
|
||||||
|
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
ramstage-y += lapic_cpu_init.c
|
ramstage-$(CONFIG_AP_IN_SIPI_WAIT) += lapic_cpu_stop.c
|
||||||
ramstage-$(CONFIG_SMP) += secondary.S
|
ramstage-$(CONFIG_LEGACY_SMP_INIT) += lapic_cpu_init.c
|
||||||
|
ramstage-$(CONFIG_LEGACY_SMP_INIT) += secondary.S
|
||||||
|
|
||||||
bootblock-$(CONFIG_UDELAY_LAPIC) += apic_timer.c
|
bootblock-$(CONFIG_UDELAY_LAPIC) += apic_timer.c
|
||||||
romstage-$(CONFIG_UDELAY_LAPIC) += apic_timer.c
|
romstage-$(CONFIG_UDELAY_LAPIC) += apic_timer.c
|
||||||
ramstage-$(CONFIG_UDELAY_LAPIC) += apic_timer.c
|
ramstage-$(CONFIG_UDELAY_LAPIC) += apic_timer.c
|
||||||
|
@@ -6,7 +6,6 @@
|
|||||||
#include <cpu/x86/smi_deprecated.h>
|
#include <cpu/x86/smi_deprecated.h>
|
||||||
#include <acpi/acpi.h>
|
#include <acpi/acpi.h>
|
||||||
#include <delay.h>
|
#include <delay.h>
|
||||||
#include <halt.h>
|
|
||||||
#include <lib.h>
|
#include <lib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <symbols.h>
|
#include <symbols.h>
|
||||||
@@ -283,73 +282,6 @@ static int start_cpu(struct device *cpu)
|
|||||||
return result;
|
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 */
|
/* C entry point of secondary cpus */
|
||||||
asmlinkage void secondary_cpu_init(unsigned int index)
|
asmlinkage void secondary_cpu_init(unsigned int index)
|
||||||
{
|
{
|
||||||
|
70
src/cpu/x86/lapic/lapic_cpu_stop.c
Normal file
70
src/cpu/x86/lapic/lapic_cpu_stop.c
Normal file
@@ -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();
|
||||||
|
}
|
@@ -159,7 +159,7 @@ static __always_inline unsigned int lapicid(void)
|
|||||||
|
|
||||||
#if !CONFIG(AP_IN_SIPI_WAIT)
|
#if !CONFIG(AP_IN_SIPI_WAIT)
|
||||||
/* If we need to go back to sipi wait, we use the long non-inlined version of
|
/* 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)
|
static __always_inline void stop_this_cpu(void)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user