From 8562c99cdd30217dea3609e268572f8764f401a5 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 13 Jun 2014 12:22:22 +0100 Subject: efi/reboot: Add generic wrapper around EfiResetSystem() Implement efi_reboot(), which is really just a wrapper around the EfiResetSystem() EFI runtime service, but it does at least allow us to funnel all callers through a single location. It also simplifies the callsites since users no longer need to check to see whether EFI_RUNTIME_SERVICES are enabled. Cc: Tony Luck Tested-by: Mark Salter Signed-off-by: Matt Fleming --- arch/x86/kernel/reboot.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'arch/x86/kernel/reboot.c') diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 52b1157c53e..09e709fd183 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -528,11 +528,7 @@ static void native_machine_emergency_restart(void) break; case BOOT_EFI: - if (efi_enabled(EFI_RUNTIME_SERVICES)) - efi.reset_system(reboot_mode == REBOOT_WARM ? - EFI_RESET_WARM : - EFI_RESET_COLD, - EFI_SUCCESS, 0, NULL); + efi_reboot(reboot_mode, NULL); reboot_type = BOOT_BIOS; break; -- cgit v1.2.3-70-g09d2 From 44be28e9dd9880dca3e2cbf7a844f2114e67f2cb Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 13 Jun 2014 12:39:55 +0100 Subject: x86/reboot: Add EFI reboot quirk for ACPI Hardware Reduced flag It appears that the BayTrail-T class of hardware requires EFI in order to powerdown and reboot and no other reliable method exists. This quirk is generally applicable to all hardware that has the ACPI Hardware Reduced bit set, since usually ACPI would be the preferred method. Cc: Len Brown Cc: Mark Salter Cc: "Rafael J. Wysocki" Signed-off-by: Matt Fleming --- arch/x86/include/asm/efi.h | 6 ++++++ arch/x86/kernel/reboot.c | 18 ++++++++++++++++-- arch/x86/platform/efi/quirks.c | 23 +++++++++++++++++++++++ drivers/firmware/efi/reboot.c | 8 ++++++++ include/linux/efi.h | 1 + 5 files changed, 54 insertions(+), 2 deletions(-) (limited to 'arch/x86/kernel/reboot.c') diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 9043f365ebf..044a2fd3c5f 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -183,6 +183,8 @@ extern struct efi_config *efi_early; #define efi_call_early(f, ...) \ efi_early->call(efi_early->f, __VA_ARGS__); +extern bool efi_reboot_required(void); + #else /* * IF EFI is not configured, have the EFI calls return -ENOSYS. @@ -195,6 +197,10 @@ extern struct efi_config *efi_early; #define efi_call5(_f, _a1, _a2, _a3, _a4, _a5) (-ENOSYS) #define efi_call6(_f, _a1, _a2, _a3, _a4, _a5, _a6) (-ENOSYS) static inline void parse_efi_setup(u64 phys_addr, u32 data_len) {} +static inline bool efi_reboot_required(void) +{ + return false; +} #endif /* CONFIG_EFI */ #endif /* _ASM_X86_EFI_H */ diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 09e709fd183..17962e667a9 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -28,6 +28,7 @@ #include #include #include +#include /* * Power off function, if any @@ -401,12 +402,25 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { static int __init reboot_init(void) { + int rv; + /* * Only do the DMI check if reboot_type hasn't been overridden * on the command line */ - if (reboot_default) - dmi_check_system(reboot_dmi_table); + if (!reboot_default) + return 0; + + /* + * The DMI quirks table takes precedence. If no quirks entry + * matches and the ACPI Hardware Reduced bit is set, force EFI + * reboot. + */ + rv = dmi_check_system(reboot_dmi_table); + + if (!rv && efi_reboot_required()) + reboot_type = BOOT_EFI; + return 0; } core_initcall(reboot_init); diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index b4cb9182f15..1c7380da65f 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -265,3 +266,25 @@ void __init efi_apply_memmap_quirks(void) if (is_uv_system()) set_bit(EFI_OLD_MEMMAP, &efi.flags); } + +/* + * For most modern platforms the preferred method of powering off is via + * ACPI. However, there are some that are known to require the use of + * EFI runtime services and for which ACPI does not work at all. + * + * Using EFI is a last resort, to be used only if no other option + * exists. + */ +bool efi_reboot_required(void) +{ + if (!acpi_gbl_reduced_hardware) + return false; + + efi_reboot_quirk_mode = EFI_RESET_WARM; + return true; +} + +bool efi_poweroff_required(void) +{ + return !!acpi_gbl_reduced_hardware; +} diff --git a/drivers/firmware/efi/reboot.c b/drivers/firmware/efi/reboot.c index e9eeeb3c634..9c59d1c795d 100644 --- a/drivers/firmware/efi/reboot.c +++ b/drivers/firmware/efi/reboot.c @@ -5,6 +5,8 @@ #include #include +int efi_reboot_quirk_mode = -1; + void efi_reboot(enum reboot_mode reboot_mode, const char *__unused) { int efi_mode; @@ -22,6 +24,12 @@ void efi_reboot(enum reboot_mode reboot_mode, const char *__unused) break; } + /* + * If a quirk forced an EFI reset mode, always use that. + */ + if (efi_reboot_quirk_mode != -1) + efi_mode = efi_reboot_quirk_mode; + efi.reset_system(efi_mode, EFI_SUCCESS, 0, NULL); } diff --git a/include/linux/efi.h b/include/linux/efi.h index 9917f58ee83..bac0f93dc47 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -878,6 +878,7 @@ extern void efi_reserve_boot_services(void); extern int efi_get_fdt_params(struct efi_fdt_params *params, int verbose); extern struct efi_memory_map memmap; +extern int efi_reboot_quirk_mode; extern bool efi_poweroff_required(void); /* Iterate through an efi_memory_map */ -- cgit v1.2.3-70-g09d2