2014-06-13 19:22:22 +08:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2014 Intel Corporation; author Matt Fleming
|
|
|
|
* Copyright (c) 2014 Red Hat, Inc., Mark Salter <msalter@redhat.com>
|
|
|
|
*/
|
|
|
|
#include <linux/efi.h>
|
|
|
|
#include <linux/reboot.h>
|
|
|
|
|
2014-06-13 19:39:55 +08:00
|
|
|
int efi_reboot_quirk_mode = -1;
|
|
|
|
|
2014-06-13 19:22:22 +08:00
|
|
|
void efi_reboot(enum reboot_mode reboot_mode, const char *__unused)
|
|
|
|
{
|
2016-04-26 04:06:59 +08:00
|
|
|
const char *str[] = { "cold", "warm", "shutdown", "platform" };
|
|
|
|
int efi_mode, cap_reset_mode;
|
2014-06-13 19:22:22 +08:00
|
|
|
|
|
|
|
if (!efi_enabled(EFI_RUNTIME_SERVICES))
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (reboot_mode) {
|
|
|
|
case REBOOT_WARM:
|
|
|
|
case REBOOT_SOFT:
|
|
|
|
efi_mode = EFI_RESET_WARM;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
efi_mode = EFI_RESET_COLD;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-06-13 19:39:55 +08:00
|
|
|
/*
|
|
|
|
* If a quirk forced an EFI reset mode, always use that.
|
|
|
|
*/
|
|
|
|
if (efi_reboot_quirk_mode != -1)
|
|
|
|
efi_mode = efi_reboot_quirk_mode;
|
|
|
|
|
2016-04-26 04:06:59 +08:00
|
|
|
if (efi_capsule_pending(&cap_reset_mode)) {
|
|
|
|
if (efi_mode != cap_reset_mode)
|
|
|
|
printk(KERN_CRIT "efi: %s reset requested but pending "
|
|
|
|
"capsule update requires %s reset... Performing "
|
|
|
|
"%s reset.\n", str[efi_mode], str[cap_reset_mode],
|
|
|
|
str[cap_reset_mode]);
|
|
|
|
efi_mode = cap_reset_mode;
|
|
|
|
}
|
|
|
|
|
2014-06-13 19:22:22 +08:00
|
|
|
efi.reset_system(efi_mode, EFI_SUCCESS, 0, NULL);
|
|
|
|
}
|
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>
2014-06-13 19:35:21 +08:00
|
|
|
|
|
|
|
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);
|