summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/i386/Kconfig18
-rw-r--r--arch/i386/kernel/Makefile1
-rw-r--r--arch/i386/kernel/reboot.c2
-rw-r--r--arch/i386/kernel/reboot_fixups.c56
-rw-r--r--include/linux/reboot_fixups.h10
5 files changed, 87 insertions, 0 deletions
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 17a0cbce6f3..99b4f294a52 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -653,6 +653,24 @@ config I8K
Say Y if you intend to run this kernel on a Dell Inspiron 8000.
Say N otherwise.
+config X86_REBOOTFIXUPS
+ bool "Enable X86 board specific fixups for reboot"
+ depends on X86
+ default n
+ ---help---
+ This enables chipset and/or board specific fixups to be done
+ in order to get reboot to work correctly. This is only needed on
+ some combinations of hardware and BIOS. The symptom, for which
+ this config is intended, is when reboot ends with a stalled/hung
+ system.
+
+ Currently, the only fixup is for the Geode GX1/CS5530A/TROM2.1.
+ combination.
+
+ Say Y if you want to enable the fixup. Currently, it's safe to
+ enable this option even if you don't need it.
+ Say N otherwise.
+
config MICROCODE
tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support"
---help---
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index aacdae6f372..0fbcfe00dd8 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o
obj-$(CONFIG_X86_MPPARSE) += mpparse.o
obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o
obj-$(CONFIG_X86_IO_APIC) += io_apic.o
+obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups.o
obj-$(CONFIG_X86_NUMAQ) += numaq.o
obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o
obj-$(CONFIG_KPROBES) += kprobes.o
diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c
index 3d7e994563d..6dc27eb70ee 100644
--- a/arch/i386/kernel/reboot.c
+++ b/arch/i386/kernel/reboot.c
@@ -13,6 +13,7 @@
#include <asm/uaccess.h>
#include <asm/apic.h>
#include "mach_reboot.h"
+#include <linux/reboot_fixups.h>
/*
* Power off function, if any
@@ -348,6 +349,7 @@ void machine_restart(char * __unused)
/* rebooting needs to touch the page at absolute addr 0 */
*((unsigned short *)__va(0x472)) = reboot_mode;
for (;;) {
+ mach_reboot_fixups(); /* for board specific fixups */
mach_reboot();
/* That didn't work - force a triple fault.. */
__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 00000000000..1b183b378c2
--- /dev/null
+++ b/arch/i386/kernel/reboot_fixups.c
@@ -0,0 +1,56 @@
+/*
+ * linux/arch/i386/kernel/reboot_fixups.c
+ *
+ * This is a good place to put board specific reboot fixups.
+ *
+ * List of supported fixups:
+ * geode-gx1/cs5530a - Jaya Kumar <jayalk@intworks.biz>
+ *
+ */
+
+#include <asm/delay.h>
+#include <linux/pci.h>
+
+static void cs5530a_warm_reset(struct pci_dev *dev)
+{
+ /* writing 1 to the reset control register, 0x44 causes the
+ cs5530a to perform a system warm reset */
+ pci_write_config_byte(dev, 0x44, 0x1);
+ udelay(50); /* shouldn't get here but be safe and spin-a-while */
+ return;
+}
+
+struct device_fixup {
+ unsigned int vendor;
+ unsigned int device;
+ void (*reboot_fixup)(struct pci_dev *);
+};
+
+static struct device_fixup fixups_table[] = {
+{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, cs5530a_warm_reset },
+};
+
+/*
+ * we see if any fixup is available for our current hardware. if there
+ * is a fixup, we call it and we expect to never return from it. if we
+ * do return, we keep looking and then eventually fall back to the
+ * standard mach_reboot on return.
+ */
+void mach_reboot_fixups(void)
+{
+ struct device_fixup *cur;
+ struct pci_dev *dev;
+ int i;
+
+ for (i=0; i < (sizeof(fixups_table)/sizeof(fixups_table[0])); i++) {
+ cur = &(fixups_table[i]);
+ dev = pci_get_device(cur->vendor, cur->device, 0);
+ if (!dev)
+ continue;
+
+ cur->reboot_fixup(dev);
+ }
+
+ printk(KERN_WARNING "No reboot fixup found for your hardware\n");
+}
+
diff --git a/include/linux/reboot_fixups.h b/include/linux/reboot_fixups.h
new file mode 100644
index 00000000000..480ea2d489d
--- /dev/null
+++ b/include/linux/reboot_fixups.h
@@ -0,0 +1,10 @@
+#ifndef _LINUX_REBOOT_FIXUPS_H
+#define _LINUX_REBOOT_FIXUPS_H
+
+#ifdef CONFIG_X86_REBOOTFIXUPS
+extern void mach_reboot_fixups(void);
+#else
+#define mach_reboot_fixups() ((void)(0))
+#endif
+
+#endif /* _LINUX_REBOOT_FIXUPS_H */