1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <console/console.h>
4 #include <cpu/x86/lapic.h>
10 * Sending INIT IPI to self is equivalent of asserting #INIT with a bit of
12 * An undefined number of instruction cycles will complete. All global locks
13 * must be released before INIT IPI and no printk is allowed after this.
14 * De-asserting INIT IPI is a no-op on later Intel CPUs.
16 * If you set DEBUG_HALT_SELF to 1, printk's after INIT IPI are enabled
17 * but running thread may halt without releasing the lock and effectively
18 * deadlock other CPUs.
20 #define DEBUG_HALT_SELF 0
23 #define dprintk(LEVEL, args...) do { printk(LEVEL, ##args); } while (0)
25 #define dprintk(LEVEL, args...) do { } while (0)
28 static void wait_for_ipi_completion_without_printk(const int timeout_ms
)
30 int loops
= timeout_ms
* 10;
33 /* wait for the ipi send to finish */
34 dprintk(BIOS_SPEW
, "Waiting for send to finish...\n");
36 dprintk(BIOS_SPEW
, "+");
38 send_status
= lapic_busy();
39 } while (send_status
&& (--loops
> 0));
42 dprintk(BIOS_ERR
, "timed out\n");
46 * Normally this function is defined in lapic.h as an always inline function
47 * that just keeps the CPU in a hlt() loop. This does not work on all CPUs.
48 * I think all hyperthreading CPUs might need this version, but I could only
49 * verify this on the Intel Core Duo
51 void stop_this_cpu(void)
53 const int timeout_100ms
= 100;
54 unsigned long id
= lapicid();
56 printk(BIOS_DEBUG
, "CPU %ld going down...\n", id
);
58 /* send an LAPIC INIT to myself */
59 lapic_send_ipi_self(LAPIC_INT_LEVELTRIG
| LAPIC_INT_ASSERT
| LAPIC_DM_INIT
);
60 wait_for_ipi_completion_without_printk(timeout_100ms
);
64 dprintk(BIOS_SPEW
, "Deasserting INIT.\n");
66 /* Deassert the LAPIC INIT */
67 lapic_send_ipi_self(LAPIC_INT_LEVELTRIG
| LAPIC_DM_INIT
);
68 wait_for_ipi_completion_without_printk(timeout_100ms
);