]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
x86/reboot: Add EFI reboot quirk for ACPI Hardware Reduced flag
authorMatt Fleming <matt.fleming@intel.com>
Fri, 13 Jun 2014 11:39:55 +0000 (12:39 +0100)
committerLuis Henriques <luis.henriques@canonical.com>
Tue, 12 May 2015 08:36:34 +0000 (09:36 +0100)
commit 44be28e9dd9880dca3e2cbf7a844f2114e67f2cb upstream.

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>
Cc: Ben Hutchings <ben@decadent.org.uk>
[ luis: backported to 3.16:
  - move changes from quirks.c into efi.c
  - adjusted context ]
Signed-off-by: Luis Henriques <luis.henriques@canonical.com>
arch/x86/include/asm/efi.h
arch/x86/kernel/reboot.c
arch/x86/platform/efi/efi.c
drivers/firmware/efi/reboot.c
include/linux/efi.h

index 1eb5f6433ad8aa6c0abc314a25b7fc8a5df707b3..81396a9a9277ddce75789a4a54245ab56e6e01fc 100644 (file)
@@ -156,6 +156,9 @@ static inline efi_status_t efi_thunk_set_virtual_address_map(
        return EFI_SUCCESS;
 }
 #endif /* CONFIG_EFI_MIXED */
+
+extern bool efi_reboot_required(void);
+
 #else
 /*
  * IF EFI is not configured, have the EFI calls return -ENOSYS.
@@ -168,6 +171,10 @@ static inline efi_status_t efi_thunk_set_virtual_address_map(
 #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 */
index 7c138543c500bd2fe5163fedad92b4f7e8440477..587be13be0be1b0fe04bb8b833e39d121880b8a7 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/mc146818rtc.h>
 #include <asm/realmode.h>
 #include <asm/x86_init.h>
+#include <asm/efi.h>
 
 /*
  * Power off function, if any
@@ -411,12 +412,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);
index 87fc96bcc13ceb1b4d90895e35528dda85641954..53a324606d113c8b278678974f79795290d821ba 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/io.h>
 #include <linux/reboot.h>
 #include <linux/bcd.h>
+#include <linux/acpi.h>
 
 #include <asm/setup.h>
 #include <asm/efi.h>
@@ -1340,3 +1341,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;
+}
index e9eeeb3c6345b64b294c54948f60024beb4de78b..9c59d1c795d1f2d6787b9a3a248f384e4017e8f1 100644 (file)
@@ -5,6 +5,8 @@
 #include <linux/efi.h>
 #include <linux/reboot.h>
 
+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);
 }
 
index 2539aff318088acfbb182b2c5d6caad6541e311c..b3fac7c1656c77655e180897a2fcd24eb652db18 100644 (file)
@@ -876,6 +876,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 */