diff options
Diffstat (limited to 'arch/i386')
-rw-r--r-- | arch/i386/Kconfig | 18 | ||||
-rw-r--r-- | arch/i386/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/i386/kernel/reboot.c | 2 | ||||
-rw-r--r-- | arch/i386/kernel/reboot_fixups.c | 56 |
4 files changed, 77 insertions, 0 deletions
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 17a0cbce6f30..99b4f294a52d 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig | |||
@@ -653,6 +653,24 @@ config I8K | |||
653 | Say Y if you intend to run this kernel on a Dell Inspiron 8000. | 653 | Say Y if you intend to run this kernel on a Dell Inspiron 8000. |
654 | Say N otherwise. | 654 | Say N otherwise. |
655 | 655 | ||
656 | config X86_REBOOTFIXUPS | ||
657 | bool "Enable X86 board specific fixups for reboot" | ||
658 | depends on X86 | ||
659 | default n | ||
660 | ---help--- | ||
661 | This enables chipset and/or board specific fixups to be done | ||
662 | in order to get reboot to work correctly. This is only needed on | ||
663 | some combinations of hardware and BIOS. The symptom, for which | ||
664 | this config is intended, is when reboot ends with a stalled/hung | ||
665 | system. | ||
666 | |||
667 | Currently, the only fixup is for the Geode GX1/CS5530A/TROM2.1. | ||
668 | combination. | ||
669 | |||
670 | Say Y if you want to enable the fixup. Currently, it's safe to | ||
671 | enable this option even if you don't need it. | ||
672 | Say N otherwise. | ||
673 | |||
656 | config MICROCODE | 674 | config MICROCODE |
657 | tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support" | 675 | tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support" |
658 | ---help--- | 676 | ---help--- |
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index aacdae6f372d..0fbcfe00dd8d 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile | |||
@@ -23,6 +23,7 @@ obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o | |||
23 | obj-$(CONFIG_X86_MPPARSE) += mpparse.o | 23 | obj-$(CONFIG_X86_MPPARSE) += mpparse.o |
24 | obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o | 24 | obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o |
25 | obj-$(CONFIG_X86_IO_APIC) += io_apic.o | 25 | obj-$(CONFIG_X86_IO_APIC) += io_apic.o |
26 | obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups.o | ||
26 | obj-$(CONFIG_X86_NUMAQ) += numaq.o | 27 | obj-$(CONFIG_X86_NUMAQ) += numaq.o |
27 | obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o | 28 | obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o |
28 | obj-$(CONFIG_KPROBES) += kprobes.o | 29 | obj-$(CONFIG_KPROBES) += kprobes.o |
diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c index 3d7e994563df..6dc27eb70ee7 100644 --- a/arch/i386/kernel/reboot.c +++ b/arch/i386/kernel/reboot.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <asm/uaccess.h> | 13 | #include <asm/uaccess.h> |
14 | #include <asm/apic.h> | 14 | #include <asm/apic.h> |
15 | #include "mach_reboot.h" | 15 | #include "mach_reboot.h" |
16 | #include <linux/reboot_fixups.h> | ||
16 | 17 | ||
17 | /* | 18 | /* |
18 | * Power off function, if any | 19 | * Power off function, if any |
@@ -348,6 +349,7 @@ void machine_restart(char * __unused) | |||
348 | /* rebooting needs to touch the page at absolute addr 0 */ | 349 | /* rebooting needs to touch the page at absolute addr 0 */ |
349 | *((unsigned short *)__va(0x472)) = reboot_mode; | 350 | *((unsigned short *)__va(0x472)) = reboot_mode; |
350 | for (;;) { | 351 | for (;;) { |
352 | mach_reboot_fixups(); /* for board specific fixups */ | ||
351 | mach_reboot(); | 353 | mach_reboot(); |
352 | /* That didn't work - force a triple fault.. */ | 354 | /* That didn't work - force a triple fault.. */ |
353 | __asm__ __volatile__("lidt %0": :"m" (no_idt)); | 355 | __asm__ __volatile__("lidt %0": :"m" (no_idt)); |
diff --git a/arch/i386/kernel/reboot_fixups.c b/arch/i386/kernel/reboot_fixups.c new file mode 100644 index 000000000000..1b183b378c2c --- /dev/null +++ b/arch/i386/kernel/reboot_fixups.c | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * linux/arch/i386/kernel/reboot_fixups.c | ||
3 | * | ||
4 | * This is a good place to put board specific reboot fixups. | ||
5 | * | ||
6 | * List of supported fixups: | ||
7 | * geode-gx1/cs5530a - Jaya Kumar <jayalk@intworks.biz> | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <asm/delay.h> | ||
12 | #include <linux/pci.h> | ||
13 | |||
14 | static void cs5530a_warm_reset(struct pci_dev *dev) | ||
15 | { | ||
16 | /* writing 1 to the reset control register, 0x44 causes the | ||
17 | cs5530a to perform a system warm reset */ | ||
18 | pci_write_config_byte(dev, 0x44, 0x1); | ||
19 | udelay(50); /* shouldn't get here but be safe and spin-a-while */ | ||
20 | return; | ||
21 | } | ||
22 | |||
23 | struct device_fixup { | ||
24 | unsigned int vendor; | ||
25 | unsigned int device; | ||
26 | void (*reboot_fixup)(struct pci_dev *); | ||
27 | }; | ||
28 | |||
29 | static struct device_fixup fixups_table[] = { | ||
30 | { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, cs5530a_warm_reset }, | ||
31 | }; | ||
32 | |||
33 | /* | ||
34 | * we see if any fixup is available for our current hardware. if there | ||
35 | * is a fixup, we call it and we expect to never return from it. if we | ||
36 | * do return, we keep looking and then eventually fall back to the | ||
37 | * standard mach_reboot on return. | ||
38 | */ | ||
39 | void mach_reboot_fixups(void) | ||
40 | { | ||
41 | struct device_fixup *cur; | ||
42 | struct pci_dev *dev; | ||
43 | int i; | ||
44 | |||
45 | for (i=0; i < (sizeof(fixups_table)/sizeof(fixups_table[0])); i++) { | ||
46 | cur = &(fixups_table[i]); | ||
47 | dev = pci_get_device(cur->vendor, cur->device, 0); | ||
48 | if (!dev) | ||
49 | continue; | ||
50 | |||
51 | cur->reboot_fixup(dev); | ||
52 | } | ||
53 | |||
54 | printk(KERN_WARNING "No reboot fixup found for your hardware\n"); | ||
55 | } | ||
56 | |||