From: Keir Fraser Date: Tue, 10 Jun 2008 13:51:00 +0000 (+0100) Subject: x86: Default ACPI reboot method. X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~14200^2~58 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=4c8dd0578f57886e1ecb6ddae53d1be6e7772607;p=xen.git x86: Default ACPI reboot method. Signed-off-by: Keir Fraser --- diff --git a/xen/arch/x86/shutdown.c b/xen/arch/x86/shutdown.c index 74f7075e5f..c2d08533c8 100644 --- a/xen/arch/x86/shutdown.c +++ b/xen/arch/x86/shutdown.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -23,13 +24,54 @@ #include #include -/* reboot_str: comma-separated list of reboot options. */ -static char __initdata reboot_str[10] = ""; -string_param("reboot", reboot_str); +enum reboot_type { + BOOT_TRIPLE = 't', + BOOT_KBD = 'k', + BOOT_ACPI = 'a', +#ifdef CONFIG_X86_32 + BOOT_BIOS = 'b', +#endif +}; static long no_idt[2]; static int reboot_mode; +/* + * reboot=b[ios] | t[riple] | k[bd] | [, [w]arm | [c]old] + * warm Don't set the cold reboot flag + * cold Set the cold reboot flag + * bios Reboot by jumping through the BIOS (only for X86_32) + * triple Force a triple fault (init) + * kbd Use the keyboard controller. cold reset (default) + * acpi Use the RESET_REG in the FADT + */ +static enum reboot_type reboot_type = BOOT_ACPI; +static void __init set_reboot_type(char *str) +{ + for ( ; ; ) + { + switch ( *str ) + { + case 'w': /* "warm" reboot (no memory testing etc) */ + reboot_mode = 0x1234; + break; + case 'c': /* "cold" reboot (with memory testing etc) */ + reboot_mode = 0x0; + break; + case 'b': + case 'a': + case 'k': + case 't': + reboot_type = *str; + break; + } + if ( (str = strchr(str, ',')) == NULL ) + break; + str++; + } +} +custom_param("reboot", set_reboot_type); + static inline void kb_wait(void) { int i; @@ -56,8 +98,6 @@ void machine_halt(void) #ifdef __i386__ -static int reboot_thru_bios; - /* The following code and data reboots the machine by switching to real mode and jumping to the BIOS reset entry point, as if the CPU has really been reset. The previous version asked the keyboard @@ -192,67 +232,11 @@ static void machine_real_restart(const unsigned char *code, unsigned length) MAX_LENGTH))); } -#else /* __x86_64__ */ - -#define machine_real_restart(x, y) -#define reboot_thru_bios 0 - -#endif - -void machine_restart(void) -{ - int i; - - watchdog_disable(); - console_start_sync(); - - local_irq_enable(); - - /* Ensure we are the boot CPU. */ - if ( get_apic_id() != boot_cpu_physical_apicid ) - { - /* Send IPI to the boot CPU (logical cpu 0). */ - on_selected_cpus(cpumask_of_cpu(0), (void *)machine_restart, - NULL, 1, 0); - for ( ; ; ) - halt(); - } - - smp_send_stop(); - - if ( tboot_in_measured_env() ) - tboot_shutdown(TB_SHUTDOWN_REBOOT); - - /* Rebooting needs to touch the page at absolute address 0. */ - *((unsigned short *)__va(0x472)) = reboot_mode; - - if ( reboot_thru_bios <= 0 ) - { - for ( ; ; ) - { - /* Pulse the keyboard reset line. */ - for ( i = 0; i < 100; i++ ) - { - kb_wait(); - udelay(50); - outb(0xfe,0x64); /* pulse reset low */ - udelay(50); - } - - /* That didn't work - force a triple fault.. */ - __asm__ __volatile__("lidt %0": "=m" (no_idt)); - __asm__ __volatile__("int3"); - } - } - machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); -} - -#ifndef reboot_thru_bios static int __init set_bios_reboot(struct dmi_system_id *d) { - if ( !reboot_thru_bios ) + if ( reboot_type != BOOT_BIOS ) { - reboot_thru_bios = 1; + reboot_type = BOOT_BIOS; printk("%s series board detected. " "Selecting BIOS-method for reboots.\n", d->ident); } @@ -294,44 +278,75 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { }, { } }; -#endif static int __init reboot_init(void) { - const char *str; + dmi_check_system(reboot_dmi_table); + return 0; +} +__initcall(reboot_init); + +#else /* __x86_64__ */ + +#define machine_real_restart(x, y) + +#endif + +void machine_restart(void) +{ + int i; + + watchdog_disable(); + console_start_sync(); - for ( str = reboot_str; *str != '\0'; str++ ) + local_irq_enable(); + + /* Ensure we are the boot CPU. */ + if ( get_apic_id() != boot_cpu_physical_apicid ) { - switch ( *str ) + /* Send IPI to the boot CPU (logical cpu 0). */ + on_selected_cpus(cpumask_of_cpu(0), (void *)machine_restart, + NULL, 1, 0); + for ( ; ; ) + halt(); + } + + smp_send_stop(); + + if ( tboot_in_measured_env() ) + tboot_shutdown(TB_SHUTDOWN_REBOOT); + + /* Rebooting needs to touch the page at absolute address 0. */ + *((unsigned short *)__va(0x472)) = reboot_mode; + + for ( ; ; ) + { + switch ( reboot_type ) { - case 'n': /* no reboot */ - opt_noreboot = 1; - break; - case 'w': /* "warm" reboot (no memory testing etc) */ - reboot_mode = 0x1234; - break; - case 'c': /* "cold" reboot (with memory testing etc) */ - reboot_mode = 0x0; + case BOOT_KBD: + /* Pulse the keyboard reset line. */ + for ( i = 0; i < 100; i++ ) + { + kb_wait(); + udelay(50); + outb(0xfe,0x64); /* pulse reset low */ + udelay(50); + } + /* fall through */ + case BOOT_TRIPLE: + asm volatile ( "lidt %0 ; int3" : "=m" (no_idt) ); break; -#ifndef reboot_thru_bios - case 'b': /* "bios" reboot by jumping through the BIOS */ - reboot_thru_bios = 1; + case BOOT_BIOS: + machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); break; - case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */ - reboot_thru_bios = -1; + case BOOT_ACPI: + acpi_reboot(); break; -#endif } - if ( (str = strchr(str, ',')) == NULL ) - break; - } -#ifndef reboot_thru_bios - dmi_check_system(reboot_dmi_table); -#endif - return 0; + reboot_type = BOOT_KBD; + } } -__initcall(reboot_init); /* * Local variables: diff --git a/xen/drivers/acpi/Makefile b/xen/drivers/acpi/Makefile index 25618e4e68..cc6acbe5dd 100644 --- a/xen/drivers/acpi/Makefile +++ b/xen/drivers/acpi/Makefile @@ -6,3 +6,4 @@ obj-y += numa.o obj-y += osl.o obj-$(x86) += hwregs.o +obj-$(x86) += reboot.o diff --git a/xen/drivers/acpi/reboot.c b/xen/drivers/acpi/reboot.c new file mode 100644 index 0000000000..ae03526f17 --- /dev/null +++ b/xen/drivers/acpi/reboot.c @@ -0,0 +1,37 @@ +#include +#include +#include + +void acpi_reboot(void) +{ + struct acpi_generic_address *rr; + u8 reset_value; + + rr = &acpi_gbl_FADT.reset_register; + + /* Is the reset register supported? */ + if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) || + (rr->bit_width != 8) || (rr->bit_offset != 0)) + return; + + reset_value = acpi_gbl_FADT.reset_value; + + /* The reset register can only exist in I/O, Memory or PCI config space + * on a device on bus 0. */ + switch (rr->space_id) { + case ACPI_ADR_SPACE_PCI_CONFIG: + printk("Resetting with ACPI PCI RESET_REG."); + /* Write the value that resets us. */ + pci_conf_write8(0, + (rr->address >> 32) & 31, + (rr->address >> 16) & 7, + (rr->address & 255), + reset_value); + break; + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + case ACPI_ADR_SPACE_SYSTEM_IO: + printk("ACPI MEMORY or I/O RESET_REG."); + acpi_hw_low_level_write(8, reset_value, rr); + break; + } +} diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h index a9f46c6c55..faf1bfe2d6 100644 --- a/xen/include/xen/acpi.h +++ b/xen/include/xen/acpi.h @@ -441,4 +441,6 @@ static inline int acpi_get_pxm(acpi_handle handle) extern int pnpacpi_disabled; +void acpi_reboot(void); + #endif /*_LINUX_ACPI_H*/