summaryrefslogtreecommitdiffstats
path: root/drivers/firmware/efi
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2014-06-13 12:35:21 +0100
committerMatt Fleming <matt.fleming@intel.com>2014-07-18 21:23:52 +0100
commit0c5ed61adbdbf2ca5de934642d5be1e971c498c1 (patch)
tree99c8e1a6e69d58b3902118dcfcd8a261b67ff254 /drivers/firmware/efi
parent8562c99cdd30217dea3609e268572f8764f401a5 (diff)
downloadlinux-0c5ed61adbdbf2ca5de934642d5be1e971c498c1.tar.bz2
efi/reboot: Allow powering off machines using EFI
Not only can EfiResetSystem() be used to reboot, it can also be used to power down machines. By and large, this functionality doesn't work very well across the range of EFI machines in the wild, so it should definitely only be used as a last resort. In an ideal world, this wouldn't be needed at all. Unfortunately, we're starting to see machines where EFI is the *only* reliable way to power down, and nothing else, not PCI, not ACPI, works. efi_poweroff_required() should be implemented on a per-architecture basis, since exactly when we should be using EFI runtime services is a platform-specific decision. There's no analogue for reboot because each architecture handles reboot very differently - the x86 code in particular is pretty complex. Patches to enable this for specific classes of hardware will be submitted separately. Tested-by: Mark Salter <msalter@redhat.com> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Diffstat (limited to 'drivers/firmware/efi')
-rw-r--r--drivers/firmware/efi/reboot.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/drivers/firmware/efi/reboot.c b/drivers/firmware/efi/reboot.c
index 81bf925f70f5..e9eeeb3c6345 100644
--- a/drivers/firmware/efi/reboot.c
+++ b/drivers/firmware/efi/reboot.c
@@ -24,3 +24,25 @@ void efi_reboot(enum reboot_mode reboot_mode, const char *__unused)
efi.reset_system(efi_mode, EFI_SUCCESS, 0, NULL);
}
+
+bool __weak efi_poweroff_required(void)
+{
+ return false;
+}
+
+static void efi_power_off(void)
+{
+ efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
+}
+
+static int __init efi_shutdown_init(void)
+{
+ if (!efi_enabled(EFI_RUNTIME_SERVICES))
+ return -ENODEV;
+
+ if (efi_poweroff_required())
+ pm_power_off = efi_power_off;
+
+ return 0;
+}
+late_initcall(efi_shutdown_init);