]> pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
x86: attempt reboot via port CF9 if we have standard PCI ports
authorH. Peter Anvin <hpa@zytor.com>
Wed, 12 Nov 2008 00:19:48 +0000 (16:19 -0800)
committerH. Peter Anvin <hpa@zytor.com>
Wed, 12 Nov 2008 00:19:48 +0000 (16:19 -0800)
Impact: Changes reboot behavior.

If port CF9 seems to be safe to touch, attempt it before trying the
keyboard controller.  Port CF9 is not available on all chipsets (a
significant but decreasing number of modern chipsets don't implement
it), but port CF9 itself should in general be safe to poke (no ill
effects if unimplemented) on any system which has PCI Configuration
Method #1 or #2, as it falls inside the PCI configuration port range
in both cases.  No chipset without PCI is known to have port CF9,
either, although an explicit "pci=bios" would mean we miss this and
therefore don't use port CF9.  An explicit "reboot=pci" can be used to
force the use of port CF9.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
arch/x86/include/asm/emergency-restart.h
arch/x86/kernel/reboot.c
arch/x86/pci/direct.c
arch/x86/pci/pci.h

index 94826cf874557acedd7afe248daa588a0c6383dd..cc70c1c78ca47545bb7b927f878d3cb02275f142 100644 (file)
@@ -8,7 +8,9 @@ enum reboot_type {
        BOOT_BIOS = 'b',
 #endif
        BOOT_ACPI = 'a',
-       BOOT_EFI = 'e'
+       BOOT_EFI = 'e',
+       BOOT_CF9 = 'p',
+       BOOT_CF9_COND = 'q',
 };
 
 extern enum reboot_type reboot_type;
index 34f8d37ae3c5e8bdebcac7af466036f95f222acb..ddc93891cdcd64faf7187b366b5e3426f3f83932 100644 (file)
@@ -29,14 +29,17 @@ 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_CF9_COND;
 int reboot_force;
 
 #if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
 static int reboot_cpu = -1;
 #endif
 
-/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old]
+/* This is set by the PCI code if either type 1 or type 2 PCI is detected */
+bool port_cf9_safe = false;
+
+/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
    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)
@@ -45,6 +48,7 @@ static int reboot_cpu = -1;
    kbd    Use the keyboard controller. cold reset (default)
    acpi   Use the RESET_REG in the FADT
    efi    Use efi reset_system runtime service
+   pci    Use the so-called "PCI reset register", CF9
    force  Avoid anything that could hang.
  */
 static int __init reboot_setup(char *str)
@@ -79,6 +83,7 @@ static int __init reboot_setup(char *str)
                case 'k':
                case 't':
                case 'e':
+               case 'p':
                        reboot_type = *str;
                        break;
 
@@ -379,28 +384,43 @@ static void native_machine_emergency_restart(void)
                        load_idt(&no_idt);
                        __asm__ __volatile__("int3");
 
-                       reboot_type = BOOT_KBD;
+                       reboot_type = BOOT_CF9_COND;
                        break;
 
 #ifdef CONFIG_X86_32
                case BOOT_BIOS:
                        machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
 
-                       reboot_type = BOOT_KBD;
+                       reboot_type = BOOT_CF9_COND;
                        break;
 #endif
 
                case BOOT_ACPI:
                        acpi_reboot();
-                       reboot_type = BOOT_KBD;
+                       reboot_type = BOOT_CF9_COND;
                        break;
 
-
                case BOOT_EFI:
                        if (efi_enabled)
-                               efi.reset_system(reboot_mode ? EFI_RESET_WARM : EFI_RESET_COLD,
+                               efi.reset_system(reboot_mode ?
+                                                EFI_RESET_WARM :
+                                                EFI_RESET_COLD,
                                                 EFI_SUCCESS, 0, NULL);
+                       reboot_type = BOOT_CF9_COND;
+                       break;
+
+               case BOOT_CF9:
+                       port_cf9_safe = true;
+                       /* fall through */
 
+               case BOOT_CF9_COND:
+                       if (port_cf9_safe) {
+                               u8 cf9 = inb(0xcf9) & ~6;
+                               outb(cf9|2, 0xcf9); /* Request hard reset */
+                               udelay(50);
+                               outb(cf9|6, 0xcf9); /* Actually do the reset */
+                               udelay(50);
+                       }
                        reboot_type = BOOT_KBD;
                        break;
                }
index 9915293500fb69ebdae0b8d80b69155f180f1274..9a5af6c8fbe9fc445fdca3358b90666c9ecae7bb 100644 (file)
@@ -173,7 +173,7 @@ static int pci_conf2_write(unsigned int seg, unsigned int bus,
 
 #undef PCI_CONF2_ADDRESS
 
-static struct pci_raw_ops pci_direct_conf2 = {
+struct pci_raw_ops pci_direct_conf2 = {
        .read =         pci_conf2_read,
        .write =        pci_conf2_write,
 };
@@ -289,6 +289,7 @@ int __init pci_direct_probe(void)
 
        if (pci_check_type1()) {
                raw_pci_ops = &pci_direct_conf1;
+               port_cf9_safe = true;
                return 1;
        }
        release_resource(region);
@@ -305,6 +306,7 @@ int __init pci_direct_probe(void)
 
        if (pci_check_type2()) {
                raw_pci_ops = &pci_direct_conf2;
+               port_cf9_safe = true;
                return 2;
        }
 
index 15b9cf6be729c0c7cddee3ff54d1ce9809f32d58..1959018aac025ea3a38048973e6cc7a107396684 100644 (file)
@@ -96,6 +96,7 @@ extern struct pci_raw_ops *raw_pci_ops;
 extern struct pci_raw_ops *raw_pci_ext_ops;
 
 extern struct pci_raw_ops pci_direct_conf1;
+extern bool port_cf9_safe;
 
 /* arch_initcall level */
 extern int pci_direct_probe(void);