blob: 73089a24f04b637c886b5177cdd852791ae04d83 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Matt Fleming8562c992014-06-13 12:22:22 +01002/*
3 * Copyright (C) 2014 Intel Corporation; author Matt Fleming
4 * Copyright (c) 2014 Red Hat, Inc., Mark Salter <msalter@redhat.com>
5 */
6#include <linux/efi.h>
7#include <linux/reboot.h>
8
Colin Ian King68ee51c2017-08-25 16:50:17 +01009static void (*orig_pm_power_off)(void);
Hans de Goedeb6a37802017-08-18 20:49:39 +010010
Matt Fleming44be28e2014-06-13 12:39:55 +010011int efi_reboot_quirk_mode = -1;
12
Matt Fleming8562c992014-06-13 12:22:22 +010013void efi_reboot(enum reboot_mode reboot_mode, const char *__unused)
14{
Matt Flemingf0133f32016-04-25 21:06:59 +010015 const char *str[] = { "cold", "warm", "shutdown", "platform" };
16 int efi_mode, cap_reset_mode;
Matt Fleming8562c992014-06-13 12:22:22 +010017
Ard Biesheuvel9b42f762020-01-23 13:12:14 +010018 if (!efi_rt_services_supported(EFI_RT_SUPPORTED_RESET_SYSTEM))
Matt Fleming8562c992014-06-13 12:22:22 +010019 return;
20
21 switch (reboot_mode) {
22 case REBOOT_WARM:
23 case REBOOT_SOFT:
24 efi_mode = EFI_RESET_WARM;
25 break;
26 default:
27 efi_mode = EFI_RESET_COLD;
28 break;
29 }
30
Matt Fleming44be28e2014-06-13 12:39:55 +010031 /*
32 * If a quirk forced an EFI reset mode, always use that.
33 */
34 if (efi_reboot_quirk_mode != -1)
35 efi_mode = efi_reboot_quirk_mode;
36
Matt Flemingf0133f32016-04-25 21:06:59 +010037 if (efi_capsule_pending(&cap_reset_mode)) {
38 if (efi_mode != cap_reset_mode)
39 printk(KERN_CRIT "efi: %s reset requested but pending "
40 "capsule update requires %s reset... Performing "
41 "%s reset.\n", str[efi_mode], str[cap_reset_mode],
42 str[cap_reset_mode]);
43 efi_mode = cap_reset_mode;
44 }
45
Matt Fleming8562c992014-06-13 12:22:22 +010046 efi.reset_system(efi_mode, EFI_SUCCESS, 0, NULL);
47}
Matt Fleming0c5ed612014-06-13 12:35:21 +010048
49bool __weak efi_poweroff_required(void)
50{
51 return false;
52}
53
54static void efi_power_off(void)
55{
56 efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
Hans de Goedeb6a37802017-08-18 20:49:39 +010057 /*
58 * The above call should not return, if it does fall back to
59 * the original power off method (typically ACPI poweroff).
60 */
61 if (orig_pm_power_off)
62 orig_pm_power_off();
Matt Fleming0c5ed612014-06-13 12:35:21 +010063}
64
65static int __init efi_shutdown_init(void)
66{
Ard Biesheuvel9b42f762020-01-23 13:12:14 +010067 if (!efi_rt_services_supported(EFI_RT_SUPPORTED_RESET_SYSTEM))
Matt Fleming0c5ed612014-06-13 12:35:21 +010068 return -ENODEV;
69
Hans de Goedeb6a37802017-08-18 20:49:39 +010070 if (efi_poweroff_required()) {
71 orig_pm_power_off = pm_power_off;
Matt Fleming0c5ed612014-06-13 12:35:21 +010072 pm_power_off = efi_power_off;
Hans de Goedeb6a37802017-08-18 20:49:39 +010073 }
Matt Fleming0c5ed612014-06-13 12:35:21 +010074
75 return 0;
76}
77late_initcall(efi_shutdown_init);