# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1213105860 -3600
# Node ID c7d361cf579372b7b5e9168892beadc6304bb4c9
# Parent 57b8c74c35ef682838ad3c93974e740bea3ba40d
x86: Default ACPI reboot method.
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
xen/arch/x86/shutdown.c | 219 ++++++++++++++++++++++++----------------------
xen/drivers/acpi/Makefile | 1
xen/drivers/acpi/reboot.c | 37 +++++++
xen/include/xen/acpi.h | 2
4 files changed, 157 insertions(+), 102 deletions(-)
diff -r 57b8c74c35ef -r c7d361cf5793 xen/arch/x86/shutdown.c
--- a/xen/arch/x86/shutdown.c Tue Jun 10 14:17:20 2008 +0100
+++ b/xen/arch/x86/shutdown.c Tue Jun 10 14:51:00 2008 +0100
@@ -14,6 +14,7 @@
#include <xen/irq.h>
#include <xen/console.h>
#include <xen/shutdown.h>
+#include <xen/acpi.h>
#include <asm/msr.h>
#include <asm/regs.h>
#include <asm/mc146818rtc.h>
@@ -23,12 +24,53 @@
#include <asm/mpspec.h>
#include <asm/tboot.h>
-/* 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)
{
@@ -55,8 +97,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
@@ -192,10 +232,63 @@ static void machine_real_restart(const u
MAX_LENGTH)));
}
+static int __init set_bios_reboot(struct dmi_system_id *d)
+{
+ if ( reboot_type != BOOT_BIOS )
+ {
+ reboot_type = BOOT_BIOS;
+ printk("%s series board detected. "
+ "Selecting BIOS-method for reboots.\n", d->ident);
+ }
+ return 0;
+}
+
+static struct dmi_system_id __initdata reboot_dmi_table[] = {
+ { /* Handle problems with rebooting on Dell 1300's */
+ .callback = set_bios_reboot,
+ .ident = "Dell PowerEdge 1300",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
+ },
+ },
+ { /* Handle problems with rebooting on Dell 300's */
+ .callback = set_bios_reboot,
+ .ident = "Dell PowerEdge 300",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
+ },
+ },
+ { /* Handle problems with rebooting on Dell 2400's */
+ .callback = set_bios_reboot,
+ .ident = "Dell PowerEdge 2400",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
+ },
+ },
+ { /* Handle problems with rebooting on HP laptops */
+ .callback = set_bios_reboot,
+ .ident = "HP Compaq Laptop",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"),
+ },
+ },
+ { }
+};
+
+static int __init reboot_init(void)
+{
+ dmi_check_system(reboot_dmi_table);
+ return 0;
+}
+__initcall(reboot_init);
+
#else /* __x86_64__ */
#define machine_real_restart(x, y)
-#define reboot_thru_bios 0
#endif
@@ -226,10 +319,11 @@ void machine_restart(void)
/* Rebooting needs to touch the page at absolute address 0. */
*((unsigned short *)__va(0x472)) = reboot_mode;
- if ( reboot_thru_bios <= 0 )
- {
- for ( ; ; )
+ for ( ; ; )
+ {
+ switch ( reboot_type )
{
+ case BOOT_KBD:
/* Pulse the keyboard reset line. */
for ( i = 0; i < 100; i++ )
{
@@ -238,100 +332,21 @@ void machine_restart(void)
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");
+ /* fall through */
+ case BOOT_TRIPLE:
+ asm volatile ( "lidt %0 ; int3" : "=m" (no_idt) );
+ break;
+ case BOOT_BIOS:
+ machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
+ break;
+ case BOOT_ACPI:
+ acpi_reboot();
+ break;
}
- }
- 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 )
- {
- reboot_thru_bios = 1;
- printk("%s series board detected. "
- "Selecting BIOS-method for reboots.\n", d->ident);
- }
- return 0;
-}
-
-static struct dmi_system_id __initdata reboot_dmi_table[] = {
- { /* Handle problems with rebooting on Dell 1300's */
- .callback = set_bios_reboot,
- .ident = "Dell PowerEdge 1300",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
- DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
- },
- },
- { /* Handle problems with rebooting on Dell 300's */
- .callback = set_bios_reboot,
- .ident = "Dell PowerEdge 300",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
- DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
- },
- },
- { /* Handle problems with rebooting on Dell 2400's */
- .callback = set_bios_reboot,
- .ident = "Dell PowerEdge 2400",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
- DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
- },
- },
- { /* Handle problems with rebooting on HP laptops */
- .callback = set_bios_reboot,
- .ident = "HP Compaq Laptop",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"),
- },
- },
- { }
-};
-#endif
-
-static int __init reboot_init(void)
-{
- const char *str;
-
- for ( str = reboot_str; *str != '\0'; str++ )
- {
- switch ( *str )
- {
- 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;
- break;
-#ifndef reboot_thru_bios
- case 'b': /* "bios" reboot by jumping through the BIOS */
- reboot_thru_bios = 1;
- break;
- case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */
- reboot_thru_bios = -1;
- break;
-#endif
- }
- if ( (str = strchr(str, ',')) == NULL )
- break;
- }
-
-#ifndef reboot_thru_bios
- dmi_check_system(reboot_dmi_table);
-#endif
- return 0;
-}
-__initcall(reboot_init);
+
+ reboot_type = BOOT_KBD;
+ }
+}
/*
* Local variables:
diff -r 57b8c74c35ef -r c7d361cf5793 xen/drivers/acpi/Makefile
--- a/xen/drivers/acpi/Makefile Tue Jun 10 14:17:20 2008 +0100
+++ b/xen/drivers/acpi/Makefile Tue Jun 10 14:51:00 2008 +0100
@@ -6,3 +6,4 @@ obj-y += osl.o
obj-y += osl.o
obj-$(x86) += hwregs.o
+obj-$(x86) += reboot.o
diff -r 57b8c74c35ef -r c7d361cf5793 xen/drivers/acpi/reboot.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/acpi/reboot.c Tue Jun 10 14:51:00 2008 +0100
@@ -0,0 +1,37 @@
+#include <xen/config.h>
+#include <xen/pci.h>
+#include <acpi/acpi.h>
+
+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 -r 57b8c74c35ef -r c7d361cf5793 xen/include/xen/acpi.h
--- a/xen/include/xen/acpi.h Tue Jun 10 14:17:20 2008 +0100
+++ b/xen/include/xen/acpi.h Tue Jun 10 14:51:00 2008 +0100
@@ -441,4 +441,6 @@ static inline int acpi_get_pxm(acpi_hand
extern int pnpacpi_disabled;
+void acpi_reboot(void);
+
#endif /*_LINUX_ACPI_H*/
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|