| 1 | // SPDX-License-Identifier: GPL-2.0 | 
|---|
| 2 | /* | 
|---|
| 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 |  | 
|---|
| 9 | static struct sys_off_handler *efi_sys_off_handler; | 
|---|
| 10 |  | 
|---|
| 11 | int efi_reboot_quirk_mode = -1; | 
|---|
| 12 |  | 
|---|
| 13 | void efi_reboot(enum reboot_mode reboot_mode, const char *__unused) | 
|---|
| 14 | { | 
|---|
| 15 | const char *str[] = { "cold", "warm", "shutdown", "platform"}; | 
|---|
| 16 | int efi_mode, cap_reset_mode; | 
|---|
| 17 |  | 
|---|
| 18 | if (!efi_rt_services_supported(EFI_RT_SUPPORTED_RESET_SYSTEM)) | 
|---|
| 19 | 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 |  | 
|---|
| 31 | /* | 
|---|
| 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 |  | 
|---|
| 37 | if (efi_capsule_pending(reset_type: &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 |  | 
|---|
| 46 | efi.reset_system(efi_mode, EFI_SUCCESS, 0, NULL); | 
|---|
| 47 | } | 
|---|
| 48 |  | 
|---|
| 49 | bool __weak efi_poweroff_required(void) | 
|---|
| 50 | { | 
|---|
| 51 | return false; | 
|---|
| 52 | } | 
|---|
| 53 |  | 
|---|
| 54 | static int efi_power_off(struct sys_off_data *data) | 
|---|
| 55 | { | 
|---|
| 56 | efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL); | 
|---|
| 57 |  | 
|---|
| 58 | return NOTIFY_DONE; | 
|---|
| 59 | } | 
|---|
| 60 |  | 
|---|
| 61 | static int __init efi_shutdown_init(void) | 
|---|
| 62 | { | 
|---|
| 63 | if (!efi_rt_services_supported(EFI_RT_SUPPORTED_RESET_SYSTEM)) | 
|---|
| 64 | return -ENODEV; | 
|---|
| 65 |  | 
|---|
| 66 | if (efi_poweroff_required()) { | 
|---|
| 67 | /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */ | 
|---|
| 68 | efi_sys_off_handler = | 
|---|
| 69 | register_sys_off_handler(mode: SYS_OFF_MODE_POWER_OFF, | 
|---|
| 70 | SYS_OFF_PRIO_FIRMWARE + 1, | 
|---|
| 71 | callback: efi_power_off, NULL); | 
|---|
| 72 | if (IS_ERR(ptr: efi_sys_off_handler)) | 
|---|
| 73 | return PTR_ERR(ptr: efi_sys_off_handler); | 
|---|
| 74 | } | 
|---|
| 75 |  | 
|---|
| 76 | return 0; | 
|---|
| 77 | } | 
|---|
| 78 | late_initcall(efi_shutdown_init); | 
|---|
| 79 |  | 
|---|