--- /dev/null
+From 83e68189745ad931c2afd45d8ee3303929233e7f Mon Sep 17 00:00:00 2001
+From: Matt Fleming <matt.fleming@intel.com>
+Date: Wed, 14 Nov 2012 09:42:35 +0000
+Subject: efi: Make 'efi_enabled' a function to query EFI facilities
+
+From: Matt Fleming <matt.fleming@intel.com>
+
+commit 83e68189745ad931c2afd45d8ee3303929233e7f upstream.
+
+Originally 'efi_enabled' indicated whether a kernel was booted from
+EFI firmware. Over time its semantics have changed, and it now
+indicates whether or not we are booted on an EFI machine with
+bit-native firmware, e.g. 64-bit kernel with 64-bit firmware.
+
+The immediate motivation for this patch is the bug report at,
+
+ https://bugs.launchpad.net/ubuntu-cdimage/+bug/1040557
+
+which details how running a platform driver on an EFI machine that is
+designed to run under BIOS can cause the machine to become
+bricked. Also, the following report,
+
+ https://bugzilla.kernel.org/show_bug.cgi?id=47121
+
+details how running said driver can also cause Machine Check
+Exceptions. Drivers need a new means of detecting whether they're
+running on an EFI machine, as sadly the expression,
+
+ if (!efi_enabled)
+
+hasn't been a sufficient condition for quite some time.
+
+Users actually want to query 'efi_enabled' for different reasons -
+what they really want access to is the list of available EFI
+facilities.
+
+For instance, the x86 reboot code needs to know whether it can invoke
+the ResetSystem() function provided by the EFI runtime services, while
+the ACPI OSL code wants to know whether the EFI config tables were
+mapped successfully. There are also checks in some of the platform
+driver code to simply see if they're running on an EFI machine (which
+would make it a bad idea to do BIOS-y things).
+
+This patch is a prereq for the samsung-laptop fix patch.
+
+Cc: David Airlie <airlied@linux.ie>
+Cc: Corentin Chary <corentincj@iksaif.net>
+Cc: Matthew Garrett <mjg59@srcf.ucam.org>
+Cc: Dave Jiang <dave.jiang@intel.com>
+Cc: Olof Johansson <olof@lixom.net>
+Cc: Peter Jones <pjones@redhat.com>
+Cc: Colin Ian King <colin.king@canonical.com>
+Cc: Steve Langasek <steve.langasek@canonical.com>
+Cc: Tony Luck <tony.luck@intel.com>
+Cc: Konrad Rzeszutek Wilk <konrad@kernel.org>
+Cc: Rafael J. Wysocki <rjw@sisk.pl>
+Signed-off-by: Matt Fleming <matt.fleming@intel.com>
+Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/include/asm/efi.h | 1
+ arch/x86/kernel/reboot.c | 2 -
+ arch/x86/kernel/setup.c | 28 ++++++++--------
+ arch/x86/platform/efi/efi.c | 57 +++++++++++++++++++--------------
+ drivers/acpi/osl.c | 2 -
+ drivers/firmware/dmi_scan.c | 2 -
+ drivers/firmware/efivars.c | 4 +-
+ drivers/firmware/iscsi_ibft_find.c | 2 -
+ drivers/gpu/drm/radeon/radeon_device.c | 3 +
+ drivers/platform/x86/ibm_rtl.c | 2 -
+ drivers/scsi/isci/init.c | 2 -
+ include/linux/efi.h | 24 ++++++++++---
+ init/main.c | 4 +-
+ 13 files changed, 79 insertions(+), 54 deletions(-)
+
+--- a/arch/x86/include/asm/efi.h
++++ b/arch/x86/include/asm/efi.h
+@@ -94,6 +94,7 @@ extern void __iomem *efi_ioremap(unsigne
+ #endif /* CONFIG_X86_32 */
+
+ extern int add_efi_memmap;
++extern unsigned long x86_efi_facility;
+ extern void efi_set_executable(efi_memory_desc_t *md, bool executable);
+ extern int efi_memblock_x86_reserve_range(void);
+ extern void efi_call_phys_prelog(void);
+--- a/arch/x86/kernel/reboot.c
++++ b/arch/x86/kernel/reboot.c
+@@ -619,7 +619,7 @@ static void native_machine_emergency_res
+ break;
+
+ case BOOT_EFI:
+- if (efi_enabled)
++ if (efi_enabled(EFI_RUNTIME_SERVICES))
+ efi.reset_system(reboot_mode ?
+ EFI_RESET_WARM :
+ EFI_RESET_COLD,
+--- a/arch/x86/kernel/setup.c
++++ b/arch/x86/kernel/setup.c
+@@ -818,15 +818,15 @@ void __init setup_arch(char **cmdline_p)
+ #ifdef CONFIG_EFI
+ if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
+ "EL32", 4)) {
+- efi_enabled = 1;
+- efi_64bit = false;
++ set_bit(EFI_BOOT, &x86_efi_facility);
+ } else if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
+ "EL64", 4)) {
+- efi_enabled = 1;
+- efi_64bit = true;
++ set_bit(EFI_BOOT, &x86_efi_facility);
++ set_bit(EFI_64BIT, &x86_efi_facility);
+ }
+- if (efi_enabled && efi_memblock_x86_reserve_range())
+- efi_enabled = 0;
++
++ if (efi_enabled(EFI_BOOT))
++ efi_memblock_x86_reserve_range();
+ #endif
+
+ x86_init.oem.arch_setup();
+@@ -899,7 +899,7 @@ void __init setup_arch(char **cmdline_p)
+
+ finish_e820_parsing();
+
+- if (efi_enabled)
++ if (efi_enabled(EFI_BOOT))
+ efi_init();
+
+ dmi_scan_machine();
+@@ -982,7 +982,7 @@ void __init setup_arch(char **cmdline_p)
+ * The EFI specification says that boot service code won't be called
+ * after ExitBootServices(). This is, in fact, a lie.
+ */
+- if (efi_enabled)
++ if (efi_enabled(EFI_MEMMAP))
+ efi_reserve_boot_services();
+
+ /* preallocate 4k for mptable mpc */
+@@ -1119,7 +1119,7 @@ void __init setup_arch(char **cmdline_p)
+
+ #ifdef CONFIG_VT
+ #if defined(CONFIG_VGA_CONSOLE)
+- if (!efi_enabled || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
++ if (!efi_enabled(EFI_BOOT) || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
+ conswitchp = &vga_con;
+ #elif defined(CONFIG_DUMMY_CONSOLE)
+ conswitchp = &dummy_con;
+@@ -1136,14 +1136,14 @@ void __init setup_arch(char **cmdline_p)
+ arch_init_ideal_nops();
+
+ #ifdef CONFIG_EFI
+- /* Once setup is done above, disable efi_enabled on mismatched
+- * firmware/kernel archtectures since there is no support for
+- * runtime services.
++ /* Once setup is done above, unmap the EFI memory map on
++ * mismatched firmware/kernel archtectures since there is no
++ * support for runtime services.
+ */
+- if (efi_enabled && IS_ENABLED(CONFIG_X86_64) != efi_64bit) {
++ if (efi_enabled(EFI_BOOT) &&
++ IS_ENABLED(CONFIG_X86_64) != efi_enabled(EFI_64BIT)) {
+ pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
+ efi_unmap_memmap();
+- efi_enabled = 0;
+ }
+ #endif
+ }
+--- a/arch/x86/platform/efi/efi.c
++++ b/arch/x86/platform/efi/efi.c
+@@ -50,9 +50,6 @@
+
+ #define EFI_DEBUG 1
+
+-int efi_enabled;
+-EXPORT_SYMBOL(efi_enabled);
+-
+ struct efi __read_mostly efi = {
+ .mps = EFI_INVALID_TABLE_ADDR,
+ .acpi = EFI_INVALID_TABLE_ADDR,
+@@ -68,19 +65,28 @@ EXPORT_SYMBOL(efi);
+
+ struct efi_memory_map memmap;
+
+-bool efi_64bit;
+-
+ static struct efi efi_phys __initdata;
+ static efi_system_table_t efi_systab __initdata;
+
+ static inline bool efi_is_native(void)
+ {
+- return IS_ENABLED(CONFIG_X86_64) == efi_64bit;
++ return IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT);
++}
++
++unsigned long x86_efi_facility;
++
++/*
++ * Returns 1 if 'facility' is enabled, 0 otherwise.
++ */
++int efi_enabled(int facility)
++{
++ return test_bit(facility, &x86_efi_facility) != 0;
+ }
++EXPORT_SYMBOL(efi_enabled);
+
+ static int __init setup_noefi(char *arg)
+ {
+- efi_enabled = 0;
++ clear_bit(EFI_BOOT, &x86_efi_facility);
+ return 0;
+ }
+ early_param("noefi", setup_noefi);
+@@ -425,6 +431,7 @@ void __init efi_reserve_boot_services(vo
+
+ void __init efi_unmap_memmap(void)
+ {
++ clear_bit(EFI_MEMMAP, &x86_efi_facility);
+ if (memmap.map) {
+ early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
+ memmap.map = NULL;
+@@ -459,7 +466,7 @@ void __init efi_free_boot_services(void)
+
+ static int __init efi_systab_init(void *phys)
+ {
+- if (efi_64bit) {
++ if (efi_enabled(EFI_64BIT)) {
+ efi_system_table_64_t *systab64;
+ u64 tmp = 0;
+
+@@ -551,7 +558,7 @@ static int __init efi_config_init(u64 ta
+ void *config_tables, *tablep;
+ int i, sz;
+
+- if (efi_64bit)
++ if (efi_enabled(EFI_64BIT))
+ sz = sizeof(efi_config_table_64_t);
+ else
+ sz = sizeof(efi_config_table_32_t);
+@@ -571,7 +578,7 @@ static int __init efi_config_init(u64 ta
+ efi_guid_t guid;
+ unsigned long table;
+
+- if (efi_64bit) {
++ if (efi_enabled(EFI_64BIT)) {
+ u64 table64;
+ guid = ((efi_config_table_64_t *)tablep)->guid;
+ table64 = ((efi_config_table_64_t *)tablep)->table;
+@@ -683,7 +690,6 @@ void __init efi_init(void)
+ if (boot_params.efi_info.efi_systab_hi ||
+ boot_params.efi_info.efi_memmap_hi) {
+ pr_info("Table located above 4GB, disabling EFI.\n");
+- efi_enabled = 0;
+ return;
+ }
+ efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab;
+@@ -693,10 +699,10 @@ void __init efi_init(void)
+ ((__u64)boot_params.efi_info.efi_systab_hi<<32));
+ #endif
+
+- if (efi_systab_init(efi_phys.systab)) {
+- efi_enabled = 0;
++ if (efi_systab_init(efi_phys.systab))
+ return;
+- }
++
++ set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility);
+
+ /*
+ * Show what we know for posterity
+@@ -714,10 +720,10 @@ void __init efi_init(void)
+ efi.systab->hdr.revision >> 16,
+ efi.systab->hdr.revision & 0xffff, vendor);
+
+- if (efi_config_init(efi.systab->tables, efi.systab->nr_tables)) {
+- efi_enabled = 0;
++ if (efi_config_init(efi.systab->tables, efi.systab->nr_tables))
+ return;
+- }
++
++ set_bit(EFI_CONFIG_TABLES, &x86_efi_facility);
+
+ /*
+ * Note: We currently don't support runtime services on an EFI
+@@ -726,15 +732,17 @@ void __init efi_init(void)
+
+ if (!efi_is_native())
+ pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n");
+- else if (efi_runtime_init()) {
+- efi_enabled = 0;
+- return;
++ else {
++ if (efi_runtime_init())
++ return;
++ set_bit(EFI_RUNTIME_SERVICES, &x86_efi_facility);
+ }
+
+- if (efi_memmap_init()) {
+- efi_enabled = 0;
++ if (efi_memmap_init())
+ return;
+- }
++
++ set_bit(EFI_MEMMAP, &x86_efi_facility);
++
+ #ifdef CONFIG_X86_32
+ if (efi_is_native()) {
+ x86_platform.get_wallclock = efi_get_time;
+@@ -943,6 +951,9 @@ u64 efi_mem_attributes(unsigned long phy
+ efi_memory_desc_t *md;
+ void *p;
+
++ if (!efi_enabled(EFI_MEMMAP))
++ return 0;
++
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ md = p;
+ if ((md->phys_addr <= phys_addr) &&
+--- a/drivers/acpi/osl.c
++++ b/drivers/acpi/osl.c
+@@ -250,7 +250,7 @@ acpi_physical_address __init acpi_os_get
+ return acpi_rsdp;
+ #endif
+
+- if (efi_enabled) {
++ if (efi_enabled(EFI_CONFIG_TABLES)) {
+ if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
+ return efi.acpi20;
+ else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
+--- a/drivers/firmware/dmi_scan.c
++++ b/drivers/firmware/dmi_scan.c
+@@ -471,7 +471,7 @@ void __init dmi_scan_machine(void)
+ char __iomem *p, *q;
+ int rc;
+
+- if (efi_enabled) {
++ if (efi_enabled(EFI_CONFIG_TABLES)) {
+ if (efi.smbios == EFI_INVALID_TABLE_ADDR)
+ goto error;
+
+--- a/drivers/firmware/efivars.c
++++ b/drivers/firmware/efivars.c
+@@ -1224,7 +1224,7 @@ efivars_init(void)
+ printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
+ EFIVARS_DATE);
+
+- if (!efi_enabled)
++ if (!efi_enabled(EFI_RUNTIME_SERVICES))
+ return 0;
+
+ /* For now we'll register the efi directory at /sys/firmware/efi */
+@@ -1262,7 +1262,7 @@ err_put:
+ static void __exit
+ efivars_exit(void)
+ {
+- if (efi_enabled) {
++ if (efi_enabled(EFI_RUNTIME_SERVICES)) {
+ unregister_efivars(&__efivars);
+ kobject_put(efi_kobj);
+ }
+--- a/drivers/firmware/iscsi_ibft_find.c
++++ b/drivers/firmware/iscsi_ibft_find.c
+@@ -99,7 +99,7 @@ unsigned long __init find_ibft_region(un
+ /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will
+ * only use ACPI for this */
+
+- if (!efi_enabled)
++ if (!efi_enabled(EFI_BOOT))
+ find_ibft_in_mem();
+
+ if (ibft_addr) {
+--- a/drivers/gpu/drm/radeon/radeon_device.c
++++ b/drivers/gpu/drm/radeon/radeon_device.c
+@@ -358,7 +358,8 @@ bool radeon_card_posted(struct radeon_de
+ {
+ uint32_t reg;
+
+- if (efi_enabled && rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE)
++ if (efi_enabled(EFI_BOOT) &&
++ rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE)
+ return false;
+
+ /* first check CRTCs */
+--- a/drivers/platform/x86/ibm_rtl.c
++++ b/drivers/platform/x86/ibm_rtl.c
+@@ -244,7 +244,7 @@ static int __init ibm_rtl_init(void) {
+ if (force)
+ pr_warn("module loaded by force\n");
+ /* first ensure that we are running on IBM HW */
+- else if (efi_enabled || !dmi_check_system(ibm_rtl_dmi_table))
++ else if (efi_enabled(EFI_BOOT) || !dmi_check_system(ibm_rtl_dmi_table))
+ return -ENODEV;
+
+ /* Get the address for the Extended BIOS Data Area */
+--- a/drivers/scsi/isci/init.c
++++ b/drivers/scsi/isci/init.c
+@@ -470,7 +470,7 @@ static int __devinit isci_pci_probe(stru
+ return -ENOMEM;
+ pci_set_drvdata(pdev, pci_info);
+
+- if (efi_enabled)
++ if (efi_enabled(EFI_RUNTIME_SERVICES))
+ orom = isci_get_efi_var(pdev);
+
+ if (!orom)
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -539,18 +539,30 @@ extern int __init efi_setup_pcdp_console
+ #endif
+
+ /*
+- * We play games with efi_enabled so that the compiler will, if possible, remove
+- * EFI-related code altogether.
++ * We play games with efi_enabled so that the compiler will, if
++ * possible, remove EFI-related code altogether.
+ */
++#define EFI_BOOT 0 /* Were we booted from EFI? */
++#define EFI_SYSTEM_TABLES 1 /* Can we use EFI system tables? */
++#define EFI_CONFIG_TABLES 2 /* Can we use EFI config tables? */
++#define EFI_RUNTIME_SERVICES 3 /* Can we use runtime services? */
++#define EFI_MEMMAP 4 /* Can we use EFI memory map? */
++#define EFI_64BIT 5 /* Is the firmware 64-bit? */
++
+ #ifdef CONFIG_EFI
+ # ifdef CONFIG_X86
+- extern int efi_enabled;
+- extern bool efi_64bit;
++extern int efi_enabled(int facility);
+ # else
+-# define efi_enabled 1
++static inline int efi_enabled(int facility)
++{
++ return 1;
++}
+ # endif
+ #else
+-# define efi_enabled 0
++static inline int efi_enabled(int facility)
++{
++ return 0;
++}
+ #endif
+
+ /*
+--- a/init/main.c
++++ b/init/main.c
+@@ -602,7 +602,7 @@ asmlinkage void __init start_kernel(void
+ pidmap_init();
+ anon_vma_init();
+ #ifdef CONFIG_X86
+- if (efi_enabled)
++ if (efi_enabled(EFI_RUNTIME_SERVICES))
+ efi_enter_virtual_mode();
+ #endif
+ thread_info_cache_init();
+@@ -630,7 +630,7 @@ asmlinkage void __init start_kernel(void
+ acpi_early_init(); /* before LAPIC and SMP init */
+ sfi_init_late();
+
+- if (efi_enabled)
++ if (efi_enabled(EFI_RUNTIME_SERVICES))
+ efi_free_boot_services();
+
+ ftrace_init();