diff options
Diffstat (limited to 'arch/x86/kernel/tboot.c')
-rw-r--r-- | arch/x86/kernel/tboot.c | 58 |
1 files changed, 47 insertions, 11 deletions
diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c index c2e760ca7b0..86c9f91b48a 100644 --- a/arch/x86/kernel/tboot.c +++ b/arch/x86/kernel/tboot.c @@ -22,11 +22,14 @@ #include <linux/dma_remapping.h> #include <linux/init_task.h> #include <linux/spinlock.h> +#include <linux/delay.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/dmar.h> +#include <linux/cpu.h> #include <linux/pfn.h> #include <linux/mm.h> +#include <linux/tboot.h> #include <asm/trampoline.h> #include <asm/processor.h> @@ -36,7 +39,6 @@ #include <asm/fixmap.h> #include <asm/proto.h> #include <asm/setup.h> -#include <asm/tboot.h> #include <asm/e820.h> #include <asm/io.h> @@ -154,13 +156,10 @@ static int map_tboot_pages(unsigned long vaddr, unsigned long start_pfn, return 0; } -void tboot_create_trampoline(void) +static void tboot_create_trampoline(void) { u32 map_base, map_size; - if (!tboot_enabled()) - return; - /* Create identity map for tboot shutdown code. */ map_base = PFN_DOWN(tboot->tboot_base); map_size = PFN_UP(tboot->tboot_size); @@ -295,21 +294,58 @@ void tboot_sleep(u8 sleep_state, u32 pm1a_control, u32 pm1b_control) tboot_shutdown(acpi_shutdown_map[sleep_state]); } -int tboot_wait_for_aps(int num_aps) +static atomic_t ap_wfs_count; + +static int tboot_wait_for_aps(int num_aps) { unsigned long timeout; + timeout = AP_WAIT_TIMEOUT*HZ; + while (atomic_read((atomic_t *)&tboot->num_in_wfs) != num_aps && + timeout) { + mdelay(1); + timeout--; + } + + if (timeout) + pr_warning("tboot wait for APs timeout\n"); + + return !(atomic_read((atomic_t *)&tboot->num_in_wfs) == num_aps); +} + +static int __cpuinit tboot_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + switch (action) { + case CPU_DYING: + atomic_inc(&ap_wfs_count); + if (num_online_cpus() == 1) + if (tboot_wait_for_aps(atomic_read(&ap_wfs_count))) + return NOTIFY_BAD; + break; + } + return NOTIFY_OK; +} + +static struct notifier_block tboot_cpu_notifier __cpuinitdata = +{ + .notifier_call = tboot_cpu_callback, +}; + +static __init int tboot_late_init(void) +{ if (!tboot_enabled()) return 0; - timeout = jiffies + AP_WAIT_TIMEOUT*HZ; - while (atomic_read((atomic_t *)&tboot->num_in_wfs) != num_aps && - time_before(jiffies, timeout)) - cpu_relax(); + tboot_create_trampoline(); - return time_before(jiffies, timeout) ? 0 : 1; + atomic_set(&ap_wfs_count, 0); + register_hotcpu_notifier(&tboot_cpu_notifier); + return 0; } +late_initcall(tboot_late_init); + /* * TXT configuration registers (offsets from TXT_{PUB, PRIV}_CONFIG_REGS_BASE) */ |