xref: /linux/arch/x86/kernel/reboot_fixups_32.c (revision 2b8232ce512105e28453f301d1510de8363bccd1)
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  * geode-gx/lx/cs5536 - Andres Salomon <dilinger@debian.org>
9  *
10  */
11 
12 #include <asm/delay.h>
13 #include <linux/pci.h>
14 #include <linux/interrupt.h>
15 #include <asm/reboot_fixups.h>
16 #include <asm/msr.h>
17 
18 static void cs5530a_warm_reset(struct pci_dev *dev)
19 {
20 	/* writing 1 to the reset control register, 0x44 causes the
21 	cs5530a to perform a system warm reset */
22 	pci_write_config_byte(dev, 0x44, 0x1);
23 	udelay(50); /* shouldn't get here but be safe and spin-a-while */
24 	return;
25 }
26 
27 static void cs5536_warm_reset(struct pci_dev *dev)
28 {
29 	/*
30 	 * 6.6.2.12 Soft Reset (DIVIL_SOFT_RESET)
31 	 * writing 1 to the LSB of this MSR causes a hard reset.
32 	 */
33 	wrmsrl(0x51400017, 1ULL);
34 	udelay(50); /* shouldn't get here but be safe and spin a while */
35 }
36 
37 struct device_fixup {
38 	unsigned int vendor;
39 	unsigned int device;
40 	void (*reboot_fixup)(struct pci_dev *);
41 };
42 
43 static struct device_fixup fixups_table[] = {
44 { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, cs5530a_warm_reset },
45 { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, cs5536_warm_reset },
46 };
47 
48 /*
49  * we see if any fixup is available for our current hardware. if there
50  * is a fixup, we call it and we expect to never return from it. if we
51  * do return, we keep looking and then eventually fall back to the
52  * standard mach_reboot on return.
53  */
54 void mach_reboot_fixups(void)
55 {
56 	struct device_fixup *cur;
57 	struct pci_dev *dev;
58 	int i;
59 
60 	/* we can be called from sysrq-B code. In such a case it is
61 	 * prohibited to dig PCI */
62 	if (in_interrupt())
63 		return;
64 
65 	for (i=0; i < ARRAY_SIZE(fixups_table); i++) {
66 		cur = &(fixups_table[i]);
67 		dev = pci_get_device(cur->vendor, cur->device, NULL);
68 		if (!dev)
69 			continue;
70 
71 		cur->reboot_fixup(dev);
72 	}
73 }
74 
75