| Improve our reboot handling for compatibility with Windows. Upstream in .38? |
| |
| diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c |
| index c495aa8..c770e66 100644 |
| |
| |
| @@ -34,7 +34,7 @@ EXPORT_SYMBOL(pm_power_off); |
| |
| static const struct desc_ptr no_idt = {}; |
| static int reboot_mode; |
| -enum reboot_type reboot_type = BOOT_KBD; |
| +enum reboot_type reboot_type = BOOT_ACPI; |
| int reboot_force; |
| |
| #if defined(CONFIG_X86_32) && defined(CONFIG_SMP) |
| @@ -538,9 +538,23 @@ void __attribute__((weak)) mach_reboot_fixups(void) |
| { |
| } |
| |
| +/* |
| + * Windows does the following on reboot: |
| + * 1) If the FADT has the ACPI reboot register flag set, try it |
| + * 2) If still alive, write to the keyboard controller |
| + * 3) If still alive, write to the ACPI reboot register again |
| + * 4) Ig still alive, write to the keyboard controller again |
| + * |
| + * If the machine is still alive at this stage, it gives up. We default to |
| + * following the same pattern, except that if we're still alive after (4) we'll |
| + * try to force a triple fault and then cycle between hitting the keyboard |
| + * controller and doing that |
| + */ |
| static void native_machine_emergency_restart(void) |
| { |
| int i; |
| + int attempt = 0; |
| + int orig_reboot_type = reboot_type; |
| |
| if (reboot_emergency) |
| emergency_vmx_disable_all(); |
| @@ -562,6 +576,13 @@ static void native_machine_emergency_restart(void) |
| outb(0xfe, 0x64); /* pulse reset low */ |
| udelay(50); |
| } |
| + if (attempt == 0 && orig_reboot_type == BOOT_ACPI) { |
| + attempt = 1; |
| + reboot_type = BOOT_ACPI; |
| + } else { |
| + reboot_type = BOOT_TRIPLE; |
| + } |
| + break; |
| |
| case BOOT_TRIPLE: |
| load_idt(&no_idt); |
| diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c |
| index 50cc3be..c6a4e63 100644 |
| |
| |
| @@ -82,12 +82,11 @@ acpi_status acpi_reset(void) |
| /* |
| * For I/O space, write directly to the OSL. This bypasses the port |
| * validation mechanism, which may block a valid write to the reset |
| - * register. |
| + * register. Spec section 4.7.3.6 requires register width to be 8. |
| */ |
| status = |
| acpi_os_write_port((acpi_io_address) reset_reg->address, |
| - acpi_gbl_FADT.reset_value, |
| - reset_reg->bit_width); |
| + acpi_gbl_FADT.reset_value, 8); |
| } else { |
| /* Write the reset value to the reset register */ |
| |
| diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c |
| index 93f9114..a6c77e8b 100644 |
| |
| |
| @@ -15,9 +15,15 @@ void acpi_reboot(void) |
| |
| 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) |
| + /* ACPI reset register was only introduced with v2 of the FADT */ |
| + |
| + if (acpi_gbl_FADT.header.revision < 2) |
| + return; |
| + |
| + /* Is the reset register supported? The spec says we should be |
| + * checking the bit width and bit offset, but Windows ignores |
| + * these fields */ |
| + if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER)) |
| return; |
| |
| reset_value = acpi_gbl_FADT.reset_value; |
| @@ -45,6 +51,4 @@ void acpi_reboot(void) |
| acpi_reset(); |
| break; |
| } |
| - /* Wait ten seconds */ |
| - acpi_os_stall(10000000); |
| } |