aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2008-11-11 19:19:48 -0500
committerH. Peter Anvin <hpa@zytor.com>2008-11-11 19:19:48 -0500
commit14d7ca5c575853664d8fe4f225a77b8df1b7de7d (patch)
tree0d16169c5fde30712109c3a316652d0525646f4f
parentd3ec5cae0921611ceae06464ef6291012dd9849f (diff)
x86: attempt reboot via port CF9 if we have standard PCI ports
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>
-rw-r--r--arch/x86/include/asm/emergency-restart.h4
-rw-r--r--arch/x86/kernel/reboot.c34
-rw-r--r--arch/x86/pci/direct.c4
-rw-r--r--arch/x86/pci/pci.h1
4 files changed, 34 insertions, 9 deletions
diff --git a/arch/x86/include/asm/emergency-restart.h b/arch/x86/include/asm/emergency-restart.h
index 94826cf87455..cc70c1c78ca4 100644
--- a/arch/x86/include/asm/emergency-restart.h
+++ b/arch/x86/include/asm/emergency-restart.h
@@ -8,7 +8,9 @@ enum reboot_type {
8 BOOT_BIOS = 'b', 8 BOOT_BIOS = 'b',
9#endif 9#endif
10 BOOT_ACPI = 'a', 10 BOOT_ACPI = 'a',
11 BOOT_EFI = 'e' 11 BOOT_EFI = 'e',
12 BOOT_CF9 = 'p',
13 BOOT_CF9_COND = 'q',
12}; 14};
13 15
14extern enum reboot_type reboot_type; 16extern enum reboot_type reboot_type;
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 34f8d37ae3c5..ddc93891cdcd 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -29,14 +29,17 @@ EXPORT_SYMBOL(pm_power_off);
29 29
30static const struct desc_ptr no_idt = {}; 30static const struct desc_ptr no_idt = {};
31static int reboot_mode; 31static int reboot_mode;
32enum reboot_type reboot_type = BOOT_KBD; 32enum reboot_type reboot_type = BOOT_CF9_COND;
33int reboot_force; 33int reboot_force;
34 34
35#if defined(CONFIG_X86_32) && defined(CONFIG_SMP) 35#if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
36static int reboot_cpu = -1; 36static int reboot_cpu = -1;
37#endif 37#endif
38 38
39/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] 39/* This is set by the PCI code if either type 1 or type 2 PCI is detected */
40bool port_cf9_safe = false;
41
42/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
40 warm Don't set the cold reboot flag 43 warm Don't set the cold reboot flag
41 cold Set the cold reboot flag 44 cold Set the cold reboot flag
42 bios Reboot by jumping through the BIOS (only for X86_32) 45 bios Reboot by jumping through the BIOS (only for X86_32)
@@ -45,6 +48,7 @@ static int reboot_cpu = -1;
45 kbd Use the keyboard controller. cold reset (default) 48 kbd Use the keyboard controller. cold reset (default)
46 acpi Use the RESET_REG in the FADT 49 acpi Use the RESET_REG in the FADT
47 efi Use efi reset_system runtime service 50 efi Use efi reset_system runtime service
51 pci Use the so-called "PCI reset register", CF9
48 force Avoid anything that could hang. 52 force Avoid anything that could hang.
49 */ 53 */
50static int __init reboot_setup(char *str) 54static int __init reboot_setup(char *str)
@@ -79,6 +83,7 @@ static int __init reboot_setup(char *str)
79 case 'k': 83 case 'k':
80 case 't': 84 case 't':
81 case 'e': 85 case 'e':
86 case 'p':
82 reboot_type = *str; 87 reboot_type = *str;
83 break; 88 break;
84 89
@@ -379,28 +384,43 @@ static void native_machine_emergency_restart(void)
379 load_idt(&no_idt); 384 load_idt(&no_idt);
380 __asm__ __volatile__("int3"); 385 __asm__ __volatile__("int3");
381 386
382 reboot_type = BOOT_KBD; 387 reboot_type = BOOT_CF9_COND;
383 break; 388 break;
384 389
385#ifdef CONFIG_X86_32 390#ifdef CONFIG_X86_32
386 case BOOT_BIOS: 391 case BOOT_BIOS:
387 machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); 392 machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
388 393
389 reboot_type = BOOT_KBD; 394 reboot_type = BOOT_CF9_COND;
390 break; 395 break;
391#endif 396#endif
392 397
393 case BOOT_ACPI: 398 case BOOT_ACPI:
394 acpi_reboot(); 399 acpi_reboot();
395 reboot_type = BOOT_KBD; 400 reboot_type = BOOT_CF9_COND;
396 break; 401 break;
397 402
398
399 case BOOT_EFI: 403 case BOOT_EFI:
400 if (efi_enabled) 404 if (efi_enabled)
401 efi.reset_system(reboot_mode ? EFI_RESET_WARM : EFI_RESET_COLD, 405 efi.reset_system(reboot_mode ?
406 EFI_RESET_WARM :
407 EFI_RESET_COLD,
402 EFI_SUCCESS, 0, NULL); 408 EFI_SUCCESS, 0, NULL);
409 reboot_type = BOOT_CF9_COND;
410 break;
411
412 case BOOT_CF9:
413 port_cf9_safe = true;
414 /* fall through */
403 415
416 case BOOT_CF9_COND:
417 if (port_cf9_safe) {
418 u8 cf9 = inb(0xcf9) & ~6;
419 outb(cf9|2, 0xcf9); /* Request hard reset */
420 udelay(50);
421 outb(cf9|6, 0xcf9); /* Actually do the reset */
422 udelay(50);
423 }
404 reboot_type = BOOT_KBD; 424 reboot_type = BOOT_KBD;
405 break; 425 break;
406 } 426 }
diff --git a/arch/x86/pci/direct.c b/arch/x86/pci/direct.c
index 9915293500fb..9a5af6c8fbe9 100644
--- a/arch/x86/pci/direct.c
+++ b/arch/x86/pci/direct.c
@@ -173,7 +173,7 @@ static int pci_conf2_write(unsigned int seg, unsigned int bus,
173 173
174#undef PCI_CONF2_ADDRESS 174#undef PCI_CONF2_ADDRESS
175 175
176static struct pci_raw_ops pci_direct_conf2 = { 176struct pci_raw_ops pci_direct_conf2 = {
177 .read = pci_conf2_read, 177 .read = pci_conf2_read,
178 .write = pci_conf2_write, 178 .write = pci_conf2_write,
179}; 179};
@@ -289,6 +289,7 @@ int __init pci_direct_probe(void)
289 289
290 if (pci_check_type1()) { 290 if (pci_check_type1()) {
291 raw_pci_ops = &pci_direct_conf1; 291 raw_pci_ops = &pci_direct_conf1;
292 port_cf9_safe = true;
292 return 1; 293 return 1;
293 } 294 }
294 release_resource(region); 295 release_resource(region);
@@ -305,6 +306,7 @@ int __init pci_direct_probe(void)
305 306
306 if (pci_check_type2()) { 307 if (pci_check_type2()) {
307 raw_pci_ops = &pci_direct_conf2; 308 raw_pci_ops = &pci_direct_conf2;
309 port_cf9_safe = true;
308 return 2; 310 return 2;
309 } 311 }
310 312
diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h
index 15b9cf6be729..1959018aac02 100644
--- a/arch/x86/pci/pci.h
+++ b/arch/x86/pci/pci.h
@@ -96,6 +96,7 @@ extern struct pci_raw_ops *raw_pci_ops;
96extern struct pci_raw_ops *raw_pci_ext_ops; 96extern struct pci_raw_ops *raw_pci_ext_ops;
97 97
98extern struct pci_raw_ops pci_direct_conf1; 98extern struct pci_raw_ops pci_direct_conf1;
99extern bool port_cf9_safe;
99 100
100/* arch_initcall level */ 101/* arch_initcall level */
101extern int pci_direct_probe(void); 102extern int pci_direct_probe(void);