aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2014-06-13 07:39:55 -0400
committerMatt Fleming <matt.fleming@intel.com>2014-07-18 16:23:52 -0400
commit44be28e9dd9880dca3e2cbf7a844f2114e67f2cb (patch)
tree8f0ed71cd35b242fc546ccdd9da58f7c0f6363a2
parent0c5ed61adbdbf2ca5de934642d5be1e971c498c1 (diff)
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 <len.brown@intel.com> Cc: Mark Salter <msalter@redhat.com> Cc: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
-rw-r--r--arch/x86/include/asm/efi.h6
-rw-r--r--arch/x86/kernel/reboot.c18
-rw-r--r--arch/x86/platform/efi/quirks.c23
-rw-r--r--drivers/firmware/efi/reboot.c8
-rw-r--r--include/linux/efi.h1
5 files changed, 54 insertions, 2 deletions
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 9043f365ebf5..044a2fd3c5fe 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;
183#define efi_call_early(f, ...) \ 183#define efi_call_early(f, ...) \
184 efi_early->call(efi_early->f, __VA_ARGS__); 184 efi_early->call(efi_early->f, __VA_ARGS__);
185 185
186extern bool efi_reboot_required(void);
187
186#else 188#else
187/* 189/*
188 * IF EFI is not configured, have the EFI calls return -ENOSYS. 190 * IF EFI is not configured, have the EFI calls return -ENOSYS.
@@ -195,6 +197,10 @@ extern struct efi_config *efi_early;
195#define efi_call5(_f, _a1, _a2, _a3, _a4, _a5) (-ENOSYS) 197#define efi_call5(_f, _a1, _a2, _a3, _a4, _a5) (-ENOSYS)
196#define efi_call6(_f, _a1, _a2, _a3, _a4, _a5, _a6) (-ENOSYS) 198#define efi_call6(_f, _a1, _a2, _a3, _a4, _a5, _a6) (-ENOSYS)
197static inline void parse_efi_setup(u64 phys_addr, u32 data_len) {} 199static inline void parse_efi_setup(u64 phys_addr, u32 data_len) {}
200static inline bool efi_reboot_required(void)
201{
202 return false;
203}
198#endif /* CONFIG_EFI */ 204#endif /* CONFIG_EFI */
199 205
200#endif /* _ASM_X86_EFI_H */ 206#endif /* _ASM_X86_EFI_H */
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 09e709fd1830..17962e667a91 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -28,6 +28,7 @@
28#include <linux/mc146818rtc.h> 28#include <linux/mc146818rtc.h>
29#include <asm/realmode.h> 29#include <asm/realmode.h>
30#include <asm/x86_init.h> 30#include <asm/x86_init.h>
31#include <asm/efi.h>
31 32
32/* 33/*
33 * Power off function, if any 34 * Power off function, if any
@@ -401,12 +402,25 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
401 402
402static int __init reboot_init(void) 403static int __init reboot_init(void)
403{ 404{
405 int rv;
406
404 /* 407 /*
405 * Only do the DMI check if reboot_type hasn't been overridden 408 * Only do the DMI check if reboot_type hasn't been overridden
406 * on the command line 409 * on the command line
407 */ 410 */
408 if (reboot_default) 411 if (!reboot_default)
409 dmi_check_system(reboot_dmi_table); 412 return 0;
413
414 /*
415 * The DMI quirks table takes precedence. If no quirks entry
416 * matches and the ACPI Hardware Reduced bit is set, force EFI
417 * reboot.
418 */
419 rv = dmi_check_system(reboot_dmi_table);
420
421 if (!rv && efi_reboot_required())
422 reboot_type = BOOT_EFI;
423
410 return 0; 424 return 0;
411} 425}
412core_initcall(reboot_init); 426core_initcall(reboot_init);
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index b4cb9182f155..1c7380da65ff 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -7,6 +7,7 @@
7#include <linux/slab.h> 7#include <linux/slab.h>
8#include <linux/memblock.h> 8#include <linux/memblock.h>
9#include <linux/bootmem.h> 9#include <linux/bootmem.h>
10#include <linux/acpi.h>
10#include <asm/efi.h> 11#include <asm/efi.h>
11#include <asm/uv/uv.h> 12#include <asm/uv/uv.h>
12 13
@@ -265,3 +266,25 @@ void __init efi_apply_memmap_quirks(void)
265 if (is_uv_system()) 266 if (is_uv_system())
266 set_bit(EFI_OLD_MEMMAP, &efi.flags); 267 set_bit(EFI_OLD_MEMMAP, &efi.flags);
267} 268}
269
270/*
271 * For most modern platforms the preferred method of powering off is via
272 * ACPI. However, there are some that are known to require the use of
273 * EFI runtime services and for which ACPI does not work at all.
274 *
275 * Using EFI is a last resort, to be used only if no other option
276 * exists.
277 */
278bool efi_reboot_required(void)
279{
280 if (!acpi_gbl_reduced_hardware)
281 return false;
282
283 efi_reboot_quirk_mode = EFI_RESET_WARM;
284 return true;
285}
286
287bool efi_poweroff_required(void)
288{
289 return !!acpi_gbl_reduced_hardware;
290}
diff --git a/drivers/firmware/efi/reboot.c b/drivers/firmware/efi/reboot.c
index e9eeeb3c6345..9c59d1c795d1 100644
--- a/drivers/firmware/efi/reboot.c
+++ b/drivers/firmware/efi/reboot.c
@@ -5,6 +5,8 @@
5#include <linux/efi.h> 5#include <linux/efi.h>
6#include <linux/reboot.h> 6#include <linux/reboot.h>
7 7
8int efi_reboot_quirk_mode = -1;
9
8void efi_reboot(enum reboot_mode reboot_mode, const char *__unused) 10void efi_reboot(enum reboot_mode reboot_mode, const char *__unused)
9{ 11{
10 int efi_mode; 12 int efi_mode;
@@ -22,6 +24,12 @@ void efi_reboot(enum reboot_mode reboot_mode, const char *__unused)
22 break; 24 break;
23 } 25 }
24 26
27 /*
28 * If a quirk forced an EFI reset mode, always use that.
29 */
30 if (efi_reboot_quirk_mode != -1)
31 efi_mode = efi_reboot_quirk_mode;
32
25 efi.reset_system(efi_mode, EFI_SUCCESS, 0, NULL); 33 efi.reset_system(efi_mode, EFI_SUCCESS, 0, NULL);
26} 34}
27 35
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 9917f58ee83e..bac0f93dc473 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -878,6 +878,7 @@ extern void efi_reserve_boot_services(void);
878extern int efi_get_fdt_params(struct efi_fdt_params *params, int verbose); 878extern int efi_get_fdt_params(struct efi_fdt_params *params, int verbose);
879extern struct efi_memory_map memmap; 879extern struct efi_memory_map memmap;
880 880
881extern int efi_reboot_quirk_mode;
881extern bool efi_poweroff_required(void); 882extern bool efi_poweroff_required(void);
882 883
883/* Iterate through an efi_memory_map */ 884/* Iterate through an efi_memory_map */