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>
#define efi_call_early(f, ...) \
efi_early->call(efi_early->f, __VA_ARGS__);
#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.
#else
/*
* IF EFI is not configured, have the EFI calls return -ENOSYS.
#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) {}
#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 */
#endif /* CONFIG_EFI */
#endif /* _ASM_X86_EFI_H */
#include <linux/mc146818rtc.h>
#include <asm/realmode.h>
#include <asm/x86_init.h>
#include <linux/mc146818rtc.h>
#include <asm/realmode.h>
#include <asm/x86_init.h>
/*
* Power off function, if any
/*
* Power off function, if any
static int __init reboot_init(void)
{
static int __init reboot_init(void)
{
/*
* Only do the DMI check if reboot_type hasn't been overridden
* on the command line
*/
/*
* 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);
return 0;
}
core_initcall(reboot_init);
#include <linux/slab.h>
#include <linux/memblock.h>
#include <linux/bootmem.h>
#include <linux/slab.h>
#include <linux/memblock.h>
#include <linux/bootmem.h>
#include <asm/efi.h>
#include <asm/uv/uv.h>
#include <asm/efi.h>
#include <asm/uv/uv.h>
if (is_uv_system())
set_bit(EFI_OLD_MEMMAP, &efi.flags);
}
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;
+}
#include <linux/efi.h>
#include <linux/reboot.h>
#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;
void efi_reboot(enum reboot_mode reboot_mode, const char *__unused)
{
int efi_mode;
+ /*
+ * 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);
}
efi.reset_system(efi_mode, EFI_SUCCESS, 0, NULL);
}
extern int efi_get_fdt_params(struct efi_fdt_params *params, int verbose);
extern struct efi_memory_map memmap;
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 */
extern bool efi_poweroff_required(void);
/* Iterate through an efi_memory_map */