diff options
-rw-r--r-- | drivers/acpi/Makefile | 2 | ||||
-rw-r--r-- | drivers/acpi/reboot.c | 50 | ||||
-rw-r--r-- | include/acpi/reboot.h | 14 |
3 files changed, 59 insertions, 7 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 40b0fcae4c78..4efbe598c817 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile | |||
@@ -21,7 +21,7 @@ obj-$(CONFIG_X86) += blacklist.o | |||
21 | # | 21 | # |
22 | # ACPI Core Subsystem (Interpreter) | 22 | # ACPI Core Subsystem (Interpreter) |
23 | # | 23 | # |
24 | obj-y += osl.o utils.o \ | 24 | obj-y += osl.o utils.o reboot.o\ |
25 | dispatcher/ events/ executer/ hardware/ \ | 25 | dispatcher/ events/ executer/ hardware/ \ |
26 | namespace/ parser/ resources/ tables/ \ | 26 | namespace/ parser/ resources/ tables/ \ |
27 | utilities/ | 27 | utilities/ |
diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c new file mode 100644 index 000000000000..a6b662c00b67 --- /dev/null +++ b/drivers/acpi/reboot.c | |||
@@ -0,0 +1,50 @@ | |||
1 | |||
2 | #include <linux/pci.h> | ||
3 | #include <linux/acpi.h> | ||
4 | #include <acpi/reboot.h> | ||
5 | |||
6 | void acpi_reboot(void) | ||
7 | { | ||
8 | struct acpi_generic_address *rr; | ||
9 | struct pci_bus *bus0; | ||
10 | u8 reset_value; | ||
11 | unsigned int devfn; | ||
12 | |||
13 | if (acpi_disabled) | ||
14 | return; | ||
15 | |||
16 | rr = &acpi_gbl_FADT.reset_register; | ||
17 | |||
18 | /* Is the reset register supported? */ | ||
19 | if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) || | ||
20 | rr->bit_width != 8 || rr->bit_offset != 0) | ||
21 | return; | ||
22 | |||
23 | reset_value = acpi_gbl_FADT.reset_value; | ||
24 | |||
25 | /* The reset register can only exist in I/O, Memory or PCI config space | ||
26 | * on a device on bus 0. */ | ||
27 | switch (rr->space_id) { | ||
28 | case ACPI_ADR_SPACE_PCI_CONFIG: | ||
29 | /* The reset register can only live on bus 0. */ | ||
30 | bus0 = pci_find_bus(0, 0); | ||
31 | if (!bus0) | ||
32 | return; | ||
33 | /* Form PCI device/function pair. */ | ||
34 | devfn = PCI_DEVFN((rr->address >> 32) & 0xffff, | ||
35 | (rr->address >> 16) & 0xffff); | ||
36 | printk(KERN_DEBUG "Resetting with ACPI PCI RESET_REG."); | ||
37 | /* Write the value that resets us. */ | ||
38 | pci_bus_write_config_byte(bus0, devfn, | ||
39 | (rr->address & 0xffff), reset_value); | ||
40 | break; | ||
41 | |||
42 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | ||
43 | case ACPI_ADR_SPACE_SYSTEM_IO: | ||
44 | printk(KERN_DEBUG "ACPI MEMORY or I/O RESET_REG.\n"); | ||
45 | acpi_hw_low_level_write(8, reset_value, rr); | ||
46 | break; | ||
47 | } | ||
48 | /* Wait ten seconds */ | ||
49 | acpi_os_stall(10000000); | ||
50 | } | ||
diff --git a/include/acpi/reboot.h b/include/acpi/reboot.h index 8857f57e0b78..0419184ce886 100644 --- a/include/acpi/reboot.h +++ b/include/acpi/reboot.h | |||
@@ -1,9 +1,11 @@ | |||
1 | #ifndef __ACPI_REBOOT_H | ||
2 | #define __ACPI_REBOOT_H | ||
3 | |||
4 | #ifdef CONFIG_ACPI | ||
5 | extern void acpi_reboot(void); | ||
6 | #else | ||
7 | static inline void acpi_reboot(void) { } | ||
8 | #endif | ||
1 | 9 | ||
2 | /* | ||
3 | * Dummy placeholder to make the EFI patches apply to the x86 tree. | ||
4 | * Andrew/Len, please just kill this file if you encounter it. | ||
5 | */ | ||
6 | #ifndef acpi_reboot | ||
7 | # define acpi_reboot() do { } while (0) | ||
8 | #endif | 10 | #endif |
9 | 11 | ||