ia64/xen-unstable

changeset 17826:c7d361cf5793

x86: Default ACPI reboot method.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jun 10 14:51:00 2008 +0100 (2008-06-10)
parents 57b8c74c35ef
children 4c1e740e392c
files xen/arch/x86/shutdown.c xen/drivers/acpi/Makefile xen/drivers/acpi/reboot.c xen/include/xen/acpi.h
line diff
     1.1 --- a/xen/arch/x86/shutdown.c	Tue Jun 10 14:17:20 2008 +0100
     1.2 +++ b/xen/arch/x86/shutdown.c	Tue Jun 10 14:51:00 2008 +0100
     1.3 @@ -14,6 +14,7 @@
     1.4  #include <xen/irq.h>
     1.5  #include <xen/console.h>
     1.6  #include <xen/shutdown.h>
     1.7 +#include <xen/acpi.h>
     1.8  #include <asm/msr.h>
     1.9  #include <asm/regs.h>
    1.10  #include <asm/mc146818rtc.h>
    1.11 @@ -23,13 +24,54 @@
    1.12  #include <asm/mpspec.h>
    1.13  #include <asm/tboot.h>
    1.14  
    1.15 -/* reboot_str: comma-separated list of reboot options. */
    1.16 -static char __initdata reboot_str[10] = "";
    1.17 -string_param("reboot", reboot_str);
    1.18 +enum reboot_type {
    1.19 +        BOOT_TRIPLE = 't',
    1.20 +        BOOT_KBD = 'k',
    1.21 +        BOOT_ACPI = 'a',
    1.22 +#ifdef CONFIG_X86_32
    1.23 +        BOOT_BIOS = 'b',
    1.24 +#endif
    1.25 +};
    1.26  
    1.27  static long no_idt[2];
    1.28  static int reboot_mode;
    1.29  
    1.30 +/*
    1.31 + * reboot=b[ios] | t[riple] | k[bd] | [, [w]arm | [c]old]
    1.32 + * warm   Don't set the cold reboot flag
    1.33 + * cold   Set the cold reboot flag
    1.34 + * bios   Reboot by jumping through the BIOS (only for X86_32)
    1.35 + * triple Force a triple fault (init)
    1.36 + * kbd    Use the keyboard controller. cold reset (default)
    1.37 + * acpi   Use the RESET_REG in the FADT
    1.38 + */
    1.39 +static enum reboot_type reboot_type = BOOT_ACPI;
    1.40 +static void __init set_reboot_type(char *str)
    1.41 +{
    1.42 +    for ( ; ; )
    1.43 +    {
    1.44 +        switch ( *str )
    1.45 +        {
    1.46 +        case 'w': /* "warm" reboot (no memory testing etc) */
    1.47 +            reboot_mode = 0x1234;
    1.48 +            break;
    1.49 +        case 'c': /* "cold" reboot (with memory testing etc) */
    1.50 +            reboot_mode = 0x0;
    1.51 +            break;
    1.52 +        case 'b':
    1.53 +        case 'a':
    1.54 +        case 'k':
    1.55 +        case 't':
    1.56 +            reboot_type = *str;
    1.57 +            break;
    1.58 +        }
    1.59 +        if ( (str = strchr(str, ',')) == NULL )
    1.60 +            break;
    1.61 +        str++;
    1.62 +    }
    1.63 +}
    1.64 +custom_param("reboot", set_reboot_type);
    1.65 +
    1.66  static inline void kb_wait(void)
    1.67  {
    1.68      int i;
    1.69 @@ -56,8 +98,6 @@ void machine_halt(void)
    1.70  
    1.71  #ifdef __i386__
    1.72  
    1.73 -static int reboot_thru_bios;
    1.74 -
    1.75  /* The following code and data reboots the machine by switching to real
    1.76     mode and jumping to the BIOS reset entry point, as if the CPU has
    1.77     really been reset.  The previous version asked the keyboard
    1.78 @@ -192,67 +232,11 @@ static void machine_real_restart(const u
    1.79                                            MAX_LENGTH)));
    1.80  }
    1.81  
    1.82 -#else /* __x86_64__ */
    1.83 -
    1.84 -#define machine_real_restart(x, y)
    1.85 -#define reboot_thru_bios 0
    1.86 -
    1.87 -#endif
    1.88 -
    1.89 -void machine_restart(void)
    1.90 -{
    1.91 -    int i;
    1.92 -
    1.93 -    watchdog_disable();
    1.94 -    console_start_sync();
    1.95 -
    1.96 -    local_irq_enable();
    1.97 -
    1.98 -    /* Ensure we are the boot CPU. */
    1.99 -    if ( get_apic_id() != boot_cpu_physical_apicid )
   1.100 -    {
   1.101 -        /* Send IPI to the boot CPU (logical cpu 0). */
   1.102 -        on_selected_cpus(cpumask_of_cpu(0), (void *)machine_restart,
   1.103 -                         NULL, 1, 0);
   1.104 -        for ( ; ; )
   1.105 -            halt();
   1.106 -    }
   1.107 -
   1.108 -    smp_send_stop();
   1.109 -
   1.110 -    if ( tboot_in_measured_env() )
   1.111 -        tboot_shutdown(TB_SHUTDOWN_REBOOT);
   1.112 -
   1.113 -    /* Rebooting needs to touch the page at absolute address 0. */
   1.114 -    *((unsigned short *)__va(0x472)) = reboot_mode;
   1.115 -
   1.116 -    if ( reboot_thru_bios <= 0 )
   1.117 -    {
   1.118 -        for ( ; ; )
   1.119 -        {
   1.120 -            /* Pulse the keyboard reset line. */
   1.121 -            for ( i = 0; i < 100; i++ )
   1.122 -            {
   1.123 -                kb_wait();
   1.124 -                udelay(50);
   1.125 -                outb(0xfe,0x64); /* pulse reset low */
   1.126 -                udelay(50);
   1.127 -            }
   1.128 -
   1.129 -            /* That didn't work - force a triple fault.. */
   1.130 -            __asm__ __volatile__("lidt %0": "=m" (no_idt));
   1.131 -            __asm__ __volatile__("int3");
   1.132 -        }
   1.133 -    }
   1.134 -    machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
   1.135 -}
   1.136 -
   1.137 -#ifndef reboot_thru_bios
   1.138  static int __init set_bios_reboot(struct dmi_system_id *d)
   1.139  {
   1.140 -    if ( !reboot_thru_bios )
   1.141 +    if ( reboot_type != BOOT_BIOS )
   1.142      {
   1.143 -        reboot_thru_bios = 1;
   1.144 +        reboot_type = BOOT_BIOS;
   1.145          printk("%s series board detected. "
   1.146                 "Selecting BIOS-method for reboots.\n", d->ident);
   1.147      }
   1.148 @@ -294,45 +278,76 @@ static struct dmi_system_id __initdata r
   1.149      },
   1.150      { }
   1.151  };
   1.152 -#endif
   1.153  
   1.154  static int __init reboot_init(void)
   1.155  {
   1.156 -    const char *str;
   1.157 -
   1.158 -    for ( str = reboot_str; *str != '\0'; str++ )
   1.159 -    {
   1.160 -        switch ( *str )
   1.161 -        {
   1.162 -        case 'n': /* no reboot */
   1.163 -            opt_noreboot = 1;
   1.164 -            break;
   1.165 -        case 'w': /* "warm" reboot (no memory testing etc) */
   1.166 -            reboot_mode = 0x1234;
   1.167 -            break;
   1.168 -        case 'c': /* "cold" reboot (with memory testing etc) */
   1.169 -            reboot_mode = 0x0;
   1.170 -            break;
   1.171 -#ifndef reboot_thru_bios
   1.172 -        case 'b': /* "bios" reboot by jumping through the BIOS */
   1.173 -            reboot_thru_bios = 1;
   1.174 -            break;
   1.175 -        case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */
   1.176 -            reboot_thru_bios = -1;
   1.177 -            break;
   1.178 -#endif
   1.179 -        }
   1.180 -        if ( (str = strchr(str, ',')) == NULL )
   1.181 -            break;
   1.182 -    }
   1.183 -
   1.184 -#ifndef reboot_thru_bios
   1.185      dmi_check_system(reboot_dmi_table);
   1.186 -#endif
   1.187      return 0;
   1.188  }
   1.189  __initcall(reboot_init);
   1.190  
   1.191 +#else /* __x86_64__ */
   1.192 +
   1.193 +#define machine_real_restart(x, y)
   1.194 +
   1.195 +#endif
   1.196 +
   1.197 +void machine_restart(void)
   1.198 +{
   1.199 +    int i;
   1.200 +
   1.201 +    watchdog_disable();
   1.202 +    console_start_sync();
   1.203 +
   1.204 +    local_irq_enable();
   1.205 +
   1.206 +    /* Ensure we are the boot CPU. */
   1.207 +    if ( get_apic_id() != boot_cpu_physical_apicid )
   1.208 +    {
   1.209 +        /* Send IPI to the boot CPU (logical cpu 0). */
   1.210 +        on_selected_cpus(cpumask_of_cpu(0), (void *)machine_restart,
   1.211 +                         NULL, 1, 0);
   1.212 +        for ( ; ; )
   1.213 +            halt();
   1.214 +    }
   1.215 +
   1.216 +    smp_send_stop();
   1.217 +
   1.218 +    if ( tboot_in_measured_env() )
   1.219 +        tboot_shutdown(TB_SHUTDOWN_REBOOT);
   1.220 +
   1.221 +    /* Rebooting needs to touch the page at absolute address 0. */
   1.222 +    *((unsigned short *)__va(0x472)) = reboot_mode;
   1.223 +
   1.224 +    for ( ; ; )
   1.225 +    {
   1.226 +        switch ( reboot_type )
   1.227 +        {
   1.228 +        case BOOT_KBD:
   1.229 +            /* Pulse the keyboard reset line. */
   1.230 +            for ( i = 0; i < 100; i++ )
   1.231 +            {
   1.232 +                kb_wait();
   1.233 +                udelay(50);
   1.234 +                outb(0xfe,0x64); /* pulse reset low */
   1.235 +                udelay(50);
   1.236 +            }
   1.237 +            /* fall through */
   1.238 +        case BOOT_TRIPLE:
   1.239 +            asm volatile ( "lidt %0 ; int3" : "=m" (no_idt) );
   1.240 +            break;
   1.241 +        case BOOT_BIOS:
   1.242 +            machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
   1.243 +            break;
   1.244 +        case BOOT_ACPI:
   1.245 +            acpi_reboot();
   1.246 +            break;
   1.247 +        }
   1.248 +
   1.249 +        reboot_type = BOOT_KBD;
   1.250 +    }
   1.251 +}
   1.252 +
   1.253  /*
   1.254   * Local variables:
   1.255   * mode: C
     2.1 --- a/xen/drivers/acpi/Makefile	Tue Jun 10 14:17:20 2008 +0100
     2.2 +++ b/xen/drivers/acpi/Makefile	Tue Jun 10 14:51:00 2008 +0100
     2.3 @@ -6,3 +6,4 @@ obj-y += numa.o
     2.4  obj-y += osl.o
     2.5  
     2.6  obj-$(x86) += hwregs.o
     2.7 +obj-$(x86) += reboot.o
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/xen/drivers/acpi/reboot.c	Tue Jun 10 14:51:00 2008 +0100
     3.3 @@ -0,0 +1,37 @@
     3.4 +#include <xen/config.h>
     3.5 +#include <xen/pci.h>
     3.6 +#include <acpi/acpi.h>
     3.7 +
     3.8 +void acpi_reboot(void)
     3.9 +{
    3.10 +	struct acpi_generic_address *rr;
    3.11 +	u8 reset_value;
    3.12 +
    3.13 +	rr = &acpi_gbl_FADT.reset_register;
    3.14 +
    3.15 +	/* Is the reset register supported? */
    3.16 +	if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) ||
    3.17 +	    (rr->bit_width != 8) || (rr->bit_offset != 0))
    3.18 +		return;
    3.19 +
    3.20 +	reset_value = acpi_gbl_FADT.reset_value;
    3.21 +
    3.22 +	/* The reset register can only exist in I/O, Memory or PCI config space
    3.23 +	 * on a device on bus 0. */
    3.24 +	switch (rr->space_id) {
    3.25 +	case ACPI_ADR_SPACE_PCI_CONFIG:
    3.26 +		printk("Resetting with ACPI PCI RESET_REG.");
    3.27 +		/* Write the value that resets us. */
    3.28 +		pci_conf_write8(0,
    3.29 +				(rr->address >> 32) & 31,
    3.30 +				(rr->address >> 16) & 7,
    3.31 +				(rr->address & 255),
    3.32 +				reset_value);
    3.33 +		break;
    3.34 +	case ACPI_ADR_SPACE_SYSTEM_MEMORY:
    3.35 +	case ACPI_ADR_SPACE_SYSTEM_IO:
    3.36 +		printk("ACPI MEMORY or I/O RESET_REG.");
    3.37 +		acpi_hw_low_level_write(8, reset_value, rr);
    3.38 +		break;
    3.39 +	}
    3.40 +}
     4.1 --- a/xen/include/xen/acpi.h	Tue Jun 10 14:17:20 2008 +0100
     4.2 +++ b/xen/include/xen/acpi.h	Tue Jun 10 14:51:00 2008 +0100
     4.3 @@ -441,4 +441,6 @@ static inline int acpi_get_pxm(acpi_hand
     4.4  
     4.5  extern int pnpacpi_disabled;
     4.6  
     4.7 +void acpi_reboot(void);
     4.8 +
     4.9  #endif /*_LINUX_ACPI_H*/