summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2009-08-03 17:30:52 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2009-08-03 17:30:52 +1000
commit98cebbeed1de0545692f2604c6962e84ed55886d (patch)
tree9af3e85528f432ede53eb27d48d4dcacdbf279e3
parentfca689b14e89a595027d19b99a32175e40655b2d (diff)
parenta3c9535ed75f522070b826152c2c2f4f79338d96 (diff)
Merge commit 'sfi/sfi-test'
-rw-r--r--Documentation/kernel-parameters.txt5
-rw-r--r--MAINTAINERS12
-rw-r--r--arch/x86/Kconfig4
-rw-r--r--arch/x86/include/asm/io_apic.h2
-rw-r--r--arch/x86/kernel/Makefile1
-rw-r--r--arch/x86/kernel/acpi/boot.c2
-rw-r--r--arch/x86/kernel/apic/io_apic.c3
-rw-r--r--arch/x86/kernel/setup.c3
-rw-r--r--arch/x86/kernel/sfi.c191
-rw-r--r--arch/x86/pci/mmconfig-shared.c6
-rw-r--r--arch/x86/pci/mmconfig_32.c2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/sfi/Kconfig14
-rw-r--r--drivers/sfi/Makefile3
-rw-r--r--drivers/sfi/sfi_acpi.c151
-rw-r--r--drivers/sfi/sfi_core.c406
-rw-r--r--drivers/sfi/sfi_core.h51
-rw-r--r--include/linux/sfi.h187
-rw-r--r--include/linux/sfi_acpi.h74
-rw-r--r--init/main.c2
20 files changed, 1113 insertions, 7 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index bf214e580b86..ace9b32095b2 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -93,6 +93,7 @@ parameter is applicable:
SECURITY Different security models are enabled.
SELINUX SELinux support is enabled.
SERIAL Serial support is enabled.
+ SFI Simple Firmware Interface
SH SuperH architecture is enabled.
SMP The kernel is an SMP kernel.
SPARC Sparc architecture is enabled.
@@ -2206,6 +2207,10 @@ and is between 256 and 4096 characters. It is defined in the file
If enabled at boot time, /selinux/disable can be used
later to disable prior to initial policy load.
+ sfi= [SFI,X86] Simple Firmware Interface
+ Format: { "off" }
+ off -- disable SFI
+
serialnumber [BUGS=X86-32]
shapers= [NET]
diff --git a/MAINTAINERS b/MAINTAINERS
index 860ef92f6a82..8967b242a704 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4602,6 +4602,18 @@ L: linux-pci@vger.kernel.org
S: Supported
F: drivers/pci/hotplug/shpchp*
+SIMPLE FIRMWARE INTERFACE (SFI)
+P: Len Brown
+M: lenb@kernel.org
+L: sfi-devel@simplefirmware.org
+W: http://simplefirmware.org/
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-sfi-2.6.git
+S: Supported
+F: arch/x86/kernel/*sfi*
+F: drivers/sfi/
+F: include/linux/sfi*.h
+
+
SIMTEC EB110ATX (Chalice CATS)
P: Ben Dooks
M: Vincent Sanders <support@simtec.co.uk>
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 14c506cfae22..7f9749f2a8cd 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1685,6 +1685,8 @@ source "kernel/power/Kconfig"
source "drivers/acpi/Kconfig"
+source "drivers/sfi/Kconfig"
+
config X86_APM_BOOT
bool
default y
@@ -1880,7 +1882,7 @@ config PCI_DIRECT
config PCI_MMCONFIG
def_bool y
- depends on X86_32 && PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
+ depends on X86_32 && PCI && (ACPI || SFI) && (PCI_GOMMCONFIG || PCI_GOANY)
config PCI_OLPC
def_bool y
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h
index 54c29c694507..932778388c43 100644
--- a/arch/x86/include/asm/io_apic.h
+++ b/arch/x86/include/asm/io_apic.h
@@ -150,7 +150,7 @@ extern int timer_through_8259;
#define io_apic_assign_pci_irqs \
(mp_irq_entries && !skip_ioapic_setup && io_apic_irqs)
-extern u8 uniq_ioapic_id(u8 id);
+extern u8 unique_ioapic_id(u8 id);
extern int io_apic_get_unique_id(int ioapic, int apic_id);
extern int io_apic_get_version(int ioapic);
extern int io_apic_get_redir_entries(int ioapic);
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 430d5b24af7b..6321afaafb26 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -55,6 +55,7 @@ obj-y += step.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-y += cpu/
obj-y += acpi/
+obj-$(CONFIG_SFI) += sfi.o
obj-y += reboot.o
obj-$(CONFIG_MCA) += mca_32.o
obj-$(CONFIG_X86_MSR) += msr.o
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index a7f9e89741c2..716724515e6e 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -892,7 +892,7 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
mp_ioapics[idx].apicaddr = address;
set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
- mp_ioapics[idx].apicid = uniq_ioapic_id(id);
+ mp_ioapics[idx].apicid = unique_ioapic_id(id);
mp_ioapics[idx].apicver = io_apic_get_version(idx);
/*
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index c2cf1b2d60d3..d6db676d7cfc 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -3935,7 +3935,7 @@ int io_apic_set_pci_routing(struct device *dev, int irq,
return __io_apic_set_pci_routing(dev, irq, irq_attr);
}
-u8 __init uniq_ioapic_id(u8 id)
+u8 __init unique_ioapic_id(u8 id)
{
#ifdef CONFIG_X86_32
if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
@@ -3946,6 +3946,7 @@ u8 __init uniq_ioapic_id(u8 id)
#else
int i;
DECLARE_BITMAP(used, 256);
+
bitmap_zero(used, 256);
for (i = 0; i < nr_ioapics; i++) {
struct mpc_ioapic *ia = &mp_ioapics[i];
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index f6dfb763718e..5b0ff4b18022 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -27,6 +27,7 @@
#include <linux/screen_info.h>
#include <linux/ioport.h>
#include <linux/acpi.h>
+#include <linux/sfi.h>
#include <linux/apm_bios.h>
#include <linux/initrd.h>
#include <linux/bootmem.h>
@@ -990,6 +991,8 @@ void __init setup_arch(char **cmdline_p)
*/
acpi_boot_init();
+ sfi_init();
+
#if defined(CONFIG_X86_MPPARSE) || defined(CONFIG_X86_VISWS)
/*
* get boot-time SMP configuration:
diff --git a/arch/x86/kernel/sfi.c b/arch/x86/kernel/sfi.c
new file mode 100644
index 000000000000..70d5a6638e50
--- /dev/null
+++ b/arch/x86/kernel/sfi.c
@@ -0,0 +1,191 @@
+/*
+ * sfi.c - SFI Boot Support (refer acpi/boot.c)
+ *
+ * Copyright (C) 2008-2009 Intel Corporation
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#define KMSG_COMPONENT "SFI"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/bootmem.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/init.h>
+#include <linux/efi.h>
+#include <linux/irq.h>
+#include <linux/sfi.h>
+#include <linux/io.h>
+
+#include <asm/io_apic.h>
+#include <asm/pgtable.h>
+#include <asm/mpspec.h>
+#include <asm/setup.h>
+#include <asm/apic.h>
+#include <asm/e820.h>
+
+#ifdef CONFIG_X86_LOCAL_APIC
+static unsigned long sfi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
+#endif
+
+#ifdef CONFIG_X86_IO_APIC
+static struct mp_ioapic_routing {
+ int gsi_base;
+ int gsi_end;
+} mp_ioapic_routing[MAX_IO_APICS];
+
+static u32 gsi_base;
+#endif
+
+#ifdef CONFIG_X86_LOCAL_APIC
+void __init mp_sfi_register_lapic_address(unsigned long address)
+{
+ mp_lapic_addr = address;
+
+ set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr);
+ if (boot_cpu_physical_apicid == -1U)
+ boot_cpu_physical_apicid = read_apic_id();
+
+ pr_info("Boot CPU = %d\n", boot_cpu_physical_apicid);
+}
+
+/* All CPUs enumerated by SFI must be present and enabled */
+void __cpuinit mp_sfi_register_lapic(u8 id)
+{
+ int boot_cpu = 0;
+
+ if (MAX_APICS - id <= 0) {
+ pr_warning("Processor #%d invalid (max %d)\n",
+ id, MAX_APICS);
+ return;
+ }
+
+ if (id == boot_cpu_physical_apicid)
+ boot_cpu = 1;
+ pr_info("registering lapic[%d]\n", id);
+
+ generic_processor_info(id, GET_APIC_VERSION(apic_read(APIC_LVR)));
+}
+
+static int __init sfi_parse_cpus(struct sfi_table_header *table)
+{
+ struct sfi_table_simple *sb;
+ struct sfi_cpu_table_entry *pentry;
+ int i;
+ int cpu_num;
+
+ sb = (struct sfi_table_simple *)table;
+ cpu_num = SFI_GET_NUM_ENTRIES(sb, struct sfi_cpu_table_entry);
+ pentry = (struct sfi_cpu_table_entry *)sb->pentry;
+
+ for (i = 0; i < cpu_num; i++) {
+ mp_sfi_register_lapic(pentry->apic_id);
+ pentry++;
+ }
+
+ smp_found_config = 1;
+ return 0;
+}
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+#ifdef CONFIG_X86_IO_APIC
+void __init mp_sfi_register_ioapic(u8 id, u32 paddr)
+{
+ int idx = 0;
+
+ if (nr_ioapics >= MAX_IO_APICS) {
+ pr_warning("WARNING: Max # of I/O APICs (%d) exceeded "
+ "(found %d), skipping!\n", MAX_IO_APICS, nr_ioapics);
+ return;
+ }
+
+ if (!paddr) {
+ pr_warning("WARNING: Bogus (zero) I/O APIC address"
+ " found in IOAPIC table, skipping!\n");
+ return;
+ }
+
+ idx = nr_ioapics;
+ mp_ioapics[idx].type = MP_IOAPIC;
+ mp_ioapics[idx].flags = MPC_APIC_USABLE;
+ mp_ioapics[idx].apicaddr = paddr;
+
+ set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, paddr);
+ mp_ioapics[idx].apicid = unique_ioapic_id(id);
+ if (mp_ioapics[idx].apicid == -1)
+ return;
+ mp_ioapics[idx].apicver = io_apic_get_version(idx);
+
+ /*
+ * Build basic GSI lookup table to facilitate gsi->io_apic lookups
+ * and to prevent reprogramming of IOAPIC pins (PCI GSIs).
+ */
+ mp_ioapic_routing[idx].gsi_base = gsi_base;
+ mp_ioapic_routing[idx].gsi_end = gsi_base +
+ io_apic_get_redir_entries(idx);
+ gsi_base = mp_ioapic_routing[idx].gsi_end + 1;
+
+ pr_info("IOAPIC[%d]: apic_id %d, version %d, address 0x%x, "
+ "GSI %d-%d\n",
+ idx, mp_ioapics[idx].apicid,
+ mp_ioapics[idx].apicver, (u32)mp_ioapics[idx].apicaddr,
+ mp_ioapic_routing[idx].gsi_base,
+ mp_ioapic_routing[idx].gsi_end);
+
+ nr_ioapics++;
+}
+
+static int __init sfi_parse_ioapic(struct sfi_table_header *table)
+{
+ struct sfi_table_simple *sb;
+ struct sfi_apic_table_entry *pentry;
+ int i, num;
+
+ sb = (struct sfi_table_simple *)table;
+ num = SFI_GET_NUM_ENTRIES(sb, struct sfi_apic_table_entry);
+ pentry = (struct sfi_apic_table_entry *)sb->pentry;
+
+ for (i = 0; i < num; i++) {
+ mp_sfi_register_ioapic(i, pentry->phys_addr);
+ pentry++;
+ }
+
+ WARN(pic_mode, KERN_WARNING
+ "SFI: pic_mod shouldn't be 1 when IOAPIC table is present\n");
+ pic_mode = 0;
+ return 0;
+}
+#endif /* CONFIG_X86_IO_APIC */
+
+/*
+ * sfi_platform_init(): register lapics & io-apics
+ */
+int __init sfi_platform_init(void)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+ mp_sfi_register_lapic_address(sfi_lapic_addr);
+ sfi_table_parse(SFI_SIG_CPUS, NULL, NULL, sfi_parse_cpus);
+#endif
+#ifdef CONFIG_X86_IO_APIC
+ sfi_table_parse(SFI_SIG_APIC, NULL, NULL, sfi_parse_ioapic);
+#endif
+ return 0;
+}
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index b707a0141d3b..602c172d3bd5 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -13,10 +13,12 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/acpi.h>
+#include <linux/sfi_acpi.h>
#include <linux/bitmap.h>
#include <linux/sort.h>
#include <asm/e820.h>
#include <asm/pci_x86.h>
+#include <asm/acpi.h>
#define PREFIX "PCI: "
@@ -493,7 +495,7 @@ static void __init pci_mmcfg_reject_broken(int early)
(unsigned int)cfg->start_bus_number,
(unsigned int)cfg->end_bus_number);
- if (!early)
+ if (!early && !acpi_disabled)
valid = is_mmconf_reserved(is_acpi_reserved, addr, size, i, cfg, 0);
if (valid)
@@ -608,7 +610,7 @@ static void __init __pci_mmcfg_init(int early)
}
if (!known_bridge)
- acpi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
+ acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
pci_mmcfg_reject_broken(early);
diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c
index 8b2d561046a3..f10a7e94a84c 100644
--- a/arch/x86/pci/mmconfig_32.c
+++ b/arch/x86/pci/mmconfig_32.c
@@ -11,9 +11,9 @@
#include <linux/pci.h>
#include <linux/init.h>
-#include <linux/acpi.h>
#include <asm/e820.h>
#include <asm/pci_x86.h>
+#include <acpi/acpi.h>
/* Assume systems with more busses have correct MCFG */
#define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))
diff --git a/drivers/Makefile b/drivers/Makefile
index bc4205d2fc3c..ccfa259fa848 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_PARISC) += parisc/
obj-$(CONFIG_RAPIDIO) += rapidio/
obj-y += video/
obj-$(CONFIG_ACPI) += acpi/
+obj-$(CONFIG_SFI) += sfi/
# PnP must come after ACPI since it will eventually need to check if acpi
# was used and do nothing if so
obj-$(CONFIG_PNP) += pnp/
diff --git a/drivers/sfi/Kconfig b/drivers/sfi/Kconfig
new file mode 100644
index 000000000000..24e72866891e
--- /dev/null
+++ b/drivers/sfi/Kconfig
@@ -0,0 +1,14 @@
+#
+# SFI Configuration
+#
+
+menuconfig SFI
+ bool "SFI (Simple Firmware Interface) Support"
+ ---help---
+ The Simple Firmware Interface (SFI) provides a lightweight method
+ for platform firmware to pass information to the operating system
+ via static tables in memory.
+
+ For more information, see http://simplefirmware.org
+
+ Say 'Y' here to enable the kernel to boot on SFI-only platforms.
diff --git a/drivers/sfi/Makefile b/drivers/sfi/Makefile
new file mode 100644
index 000000000000..2343732aefeb
--- /dev/null
+++ b/drivers/sfi/Makefile
@@ -0,0 +1,3 @@
+obj-y += sfi_acpi.o
+obj-y += sfi_core.o
+
diff --git a/drivers/sfi/sfi_acpi.c b/drivers/sfi/sfi_acpi.c
new file mode 100644
index 000000000000..5643c641f6c4
--- /dev/null
+++ b/drivers/sfi/sfi_acpi.c
@@ -0,0 +1,151 @@
+/* sfi_acpi.c Simple Firmware Interface - ACPI extensions */
+
+/*
+ * Copyright (C) 2009, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#define KMSG_COMPONENT "SFI"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <acpi/acpi.h>
+
+#include <linux/sfi.h>
+#include "sfi_core.h"
+
+/*
+ * SFI can access ACPI-defined tables via an optional ACPI XSDT.
+ *
+ * This allows re-use, and avoids re-definition, of standard tables.
+ * For example, the "MCFG" table is defined by PCI, reserved by ACPI,
+ * and is expected to be present many SFI-only systems.
+ */
+
+static struct acpi_table_xsdt *xsdt_va __read_mostly;
+
+#define XSDT_GET_NUM_ENTRIES(ptable, entry_type) \
+ ((ptable->header.length - sizeof(struct acpi_table_header)) / \
+ (sizeof(entry_type)))
+
+static inline struct sfi_table_header *acpi_to_sfi_th(
+ struct acpi_table_header *th)
+{
+ return (struct sfi_table_header *)th;
+}
+
+static inline struct acpi_table_header *sfi_to_acpi_th(
+ struct sfi_table_header *th)
+{
+ return (struct acpi_table_header *)th;
+}
+
+/*
+ * sfi_acpi_parse_xsdt()
+ *
+ * Parse the ACPI XSDT for later access by sfi_acpi_table_parse().
+ */
+static int __init sfi_acpi_parse_xsdt(struct sfi_table_header *th)
+{
+ struct sfi_table_key key = SFI_ANY_KEY;
+ int tbl_cnt, i;
+ void *ret;
+
+ xsdt_va = (struct acpi_table_xsdt *)th;
+ tbl_cnt = XSDT_GET_NUM_ENTRIES(xsdt_va, u64);
+ for (i = 0; i < tbl_cnt; i++) {
+ ret = sfi_check_table(xsdt_va->table_offset_entry[i], &key);
+ if (IS_ERR(ret)) {
+ disable_sfi();
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int __init sfi_acpi_init(void)
+{
+ sfi_table_parse(SFI_SIG_XSDT, NULL, NULL, sfi_acpi_parse_xsdt);
+ return 0;
+}
+
+static struct acpi_table_header *sfi_acpi_get_table(struct sfi_table_key *key)
+{
+ u32 tbl_cnt, i;
+ void *ret;
+
+ tbl_cnt = XSDT_GET_NUM_ENTRIES(xsdt_va, u64);
+ for (i = 0; i < tbl_cnt; i++) {
+ ret = sfi_check_table(xsdt_va->table_offset_entry[i], key);
+ if (!IS_ERR(ret) && ret)
+ return sfi_to_acpi_th(ret);
+ }
+
+ return NULL;
+}
+
+static void sfi_acpi_put_table(struct acpi_table_header *table)
+{
+ sfi_put_table(acpi_to_sfi_th(table));
+}
+
+/*
+ * sfi_acpi_table_parse()
+ *
+ * Find specified table in XSDT, run handler on it and return its return value
+ */
+int sfi_acpi_table_parse(char *signature, char *oem_id, char *oem_table_id,
+ int(*handler)(struct acpi_table_header *))
+{
+ struct acpi_table_header *table = NULL;
+ struct sfi_table_key key;
+ int ret = 0;
+
+ if (sfi_disabled)
+ return -1;
+
+ key.sig = signature;
+ key.oem_id = oem_id;
+ key.oem_table_id = oem_table_id;
+
+ table = sfi_acpi_get_table(&key);
+ if (!table)
+ return -EINVAL;
+
+ ret = handler(table);
+ sfi_acpi_put_table(table);
+ return ret;
+}
diff --git a/drivers/sfi/sfi_core.c b/drivers/sfi/sfi_core.c
new file mode 100644
index 000000000000..62e2f98a1c41
--- /dev/null
+++ b/drivers/sfi/sfi_core.c
@@ -0,0 +1,406 @@
+/* sfi_core.c Simple Firmware Interface - core internals */
+
+/*
+ * Copyright (C) 2009, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#define KMSG_COMPONENT "SFI"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/bootmem.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/acpi.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/sfi.h>
+#include <linux/smp.h>
+
+#include <asm/pgtable.h>
+
+#include "sfi_core.h"
+
+#define ON_SAME_PAGE(addr1, addr2) \
+ (((unsigned long)(addr1) & PAGE_MASK) == \
+ ((unsigned long)(addr2) & PAGE_MASK))
+#define TABLE_ON_PAGE(page, table, size) (ON_SAME_PAGE(page, table) && \
+ ON_SAME_PAGE(page, table + size))
+
+int sfi_disabled __read_mostly;
+EXPORT_SYMBOL(sfi_disabled);
+
+static u64 syst_pa __read_mostly;
+static struct sfi_table_simple *syst_va __read_mostly;
+
+/*
+ * FW creates and saves the SFI tables in memory. When these tables get
+ * used, they may need to be mapped to virtual address space, and the mapping
+ * can happen before or after the ioremap() is ready, so a flag is needed
+ * to indicating this
+ */
+static u32 sfi_use_ioremap __read_mostly;
+
+static void __iomem *sfi_map_memory(u64 phys, u32 size)
+{
+ if (!phys || !size)
+ return NULL;
+
+ if (sfi_use_ioremap)
+ return ioremap(phys, size);
+ else
+ return early_ioremap(phys, size);
+}
+
+static void sfi_unmap_memory(void __iomem *virt, u32 size)
+{
+ if (!virt || !size)
+ return;
+
+ if (sfi_use_ioremap)
+ iounmap(virt);
+ else
+ early_iounmap(virt, size);
+}
+
+static void sfi_print_table_header(unsigned long long pa,
+ struct sfi_table_header *header)
+{
+ pr_info("%4.4s %llX, %04X (v%d %6.6s %8.8s)\n",
+ header->sig, pa,
+ header->len, header->rev, header->oem_id,
+ header->oem_table_id);
+}
+
+/*
+ * sfi_verify_table()
+ * Sanity check table lengh, calculate checksum
+ */
+static __init int sfi_verify_table(struct sfi_table_header *table)
+{
+
+ u8 checksum = 0;
+ u8 *puchar = (u8 *)table;
+ u32 length = table->len;
+
+ /* Sanity check table length against arbitrary 1MB limit */
+ if (length > 0x100000) {
+ pr_err("Invalid table length 0x%x\n", length);
+ return -1;
+ }
+
+ while (length--)
+ checksum += *puchar++;
+
+ if (checksum) {
+ pr_err("Checksum %2.2X should be %2.2X\n",
+ table->csum, table->csum - checksum);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * sfi_map_table()
+ *
+ * Return address of mapped table
+ * Check for common case that we can re-use mapping to SYST,
+ * which requires syst_pa, syst_va to be initialized.
+ */
+struct sfi_table_header *sfi_map_table(u64 pa)
+{
+ struct sfi_table_header *th;
+ u32 length;
+
+ if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header)))
+ th = sfi_map_memory(pa, sizeof(struct sfi_table_header));
+ else
+ th = (void *)syst_va + (pa - syst_pa);
+
+ /* If table fits on same page as its header, we are done */
+ if (TABLE_ON_PAGE(th, th, th->len))
+ return th;
+
+ /* Entire table does not fit on same page as SYST */
+ length = th->len;
+ if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header)))
+ sfi_unmap_memory(th, sizeof(struct sfi_table_header));
+
+ return sfi_map_memory(pa, length);
+}
+
+/*
+ * sfi_unmap_table()
+ *
+ * Undoes effect of sfi_map_table() by unmapping table
+ * if it did not completely fit on same page as SYST.
+ */
+void sfi_unmap_table(struct sfi_table_header *th)
+{
+ if (!TABLE_ON_PAGE(syst_va, th, th->len))
+ sfi_unmap_memory(th, TABLE_ON_PAGE(th, th, th->len) ?
+ sizeof(*th) : th->len);
+}
+
+static int sfi_table_check_key(struct sfi_table_header *th,
+ struct sfi_table_key *key)
+{
+
+ if (strncmp(th->sig, key->sig, SFI_SIGNATURE_SIZE)
+ || (key->oem_id && strncmp(th->oem_id,
+ key->oem_id, SFI_OEM_ID_SIZE))
+ || (key->oem_table_id && strncmp(th->oem_table_id,
+ key->oem_table_id, SFI_OEM_TABLE_ID_SIZE)))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * This function will be used in 2 cases:
+ * 1. used to enumerate and verify the tables addressed by SYST/XSDT,
+ * thus no signature will be given (in kernel boot phase)
+ * 2. used to parse one specific table, signature must exist, and
+ * the mapped virt address will be returned, and the virt space
+ * will be released by call sfi_put_table() later
+ *
+ * Return value:
+ * NULL: when can't find a table matching the key
+ * ERR_PTR(error): error value
+ * virt table address: when a matched table is found
+ */
+struct sfi_table_header *sfi_check_table(u64 pa, struct sfi_table_key *key)
+{
+ struct sfi_table_header *th;
+ void *ret = NULL;
+
+ th = sfi_map_table(pa);
+ if (!th)
+ return ERR_PTR(-ENOMEM);
+
+ if (!key->sig) {
+ sfi_print_table_header(pa, th);
+ if (sfi_verify_table(th))
+ ret = ERR_PTR(-EINVAL);
+ } else {
+ if (!sfi_table_check_key(th, key))
+ return th; /* Success */
+ }
+
+ sfi_unmap_table(th);
+ return ret;
+}
+
+/*
+ * sfi_get_table()
+ *
+ * Search SYST for the specified table with the signature in
+ * the key, and return the mapped table
+ */
+static struct sfi_table_header *sfi_get_table(struct sfi_table_key *key)
+{
+ struct sfi_table_header *th;
+ u32 tbl_cnt, i;
+
+ tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
+ for (i = 0; i < tbl_cnt; i++) {
+ th = sfi_check_table(syst_va->pentry[i], key);
+ if (!IS_ERR(th) && th)
+ return th;
+ }
+
+ return NULL;
+}
+
+void sfi_put_table(struct sfi_table_header *th)
+{
+ sfi_unmap_table(th);
+}
+
+/* Find table with signature, run handler on it */
+int sfi_table_parse(char *signature, char *oem_id, char *oem_table_id,
+ sfi_table_handler handler)
+{
+ struct sfi_table_header *table = NULL;
+ struct sfi_table_key key;
+ int ret = -EINVAL;
+
+ if (sfi_disabled || !handler || !signature)
+ goto exit;
+
+ key.sig = signature;
+ key.oem_id = oem_id;
+ key.oem_table_id = oem_table_id;
+
+ table = sfi_get_table(&key);
+ if (!table)
+ goto exit;
+
+ ret = handler(table);
+ sfi_put_table(table);
+exit:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sfi_table_parse);
+
+/*
+ * sfi_parse_syst()
+ * Checksum all the tables in SYST and print their headers
+ *
+ * success: set syst_va, return 0
+ */
+static int __init sfi_parse_syst(void)
+{
+ struct sfi_table_key key = SFI_ANY_KEY;
+ int tbl_cnt, i;
+ void *ret;
+
+ syst_va = sfi_map_memory(syst_pa, sizeof(struct sfi_table_simple));
+ if (!syst_va)
+ return -ENOMEM;
+
+ tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
+ for (i = 0; i < tbl_cnt; i++) {
+ ret = sfi_check_table(syst_va->pentry[i], &key);
+ if (IS_ERR(ret))
+ return PTR_ERR(ret);
+ }
+
+ return 0;
+}
+
+/*
+ * The OS finds the System Table by searching 16-byte boundaries between
+ * physical address 0x000E0000 and 0x000FFFFF. The OS shall search this region
+ * starting at the low address and shall stop searching when the 1st valid SFI
+ * System Table is found.
+ *
+ * success: set syst_pa, return 0
+ * fail: return -1
+ */
+static __init int sfi_find_syst(void)
+{
+ unsigned long offset, len;
+ void *start;
+
+ len = SFI_SYST_SEARCH_END - SFI_SYST_SEARCH_BEGIN;
+ start = sfi_map_memory(SFI_SYST_SEARCH_BEGIN, len);
+ if (!start)
+ return -1;
+
+ for (offset = 0; offset < len; offset += 16) {
+ struct sfi_table_header *syst_hdr;
+
+ syst_hdr = start + offset;
+ if (strncmp(syst_hdr->sig, SFI_SIG_SYST,
+ SFI_SIGNATURE_SIZE))
+ continue;
+
+ if (syst_hdr->len > PAGE_SIZE)
+ continue;
+
+ sfi_print_table_header(SFI_SYST_SEARCH_BEGIN + offset,
+ syst_hdr);
+
+ if (sfi_verify_table(syst_hdr))
+ continue;
+
+ /*
+ * Enforce SFI spec mandate that SYST reside within a page.
+ */
+ if (!ON_SAME_PAGE(syst_pa, syst_pa + syst_hdr->len)) {
+ pr_info("SYST 0x%llx + 0x%x crosses page\n",
+ syst_pa, syst_hdr->len);
+ continue;
+ }
+
+ /* Success */
+ syst_pa = SFI_SYST_SEARCH_BEGIN + offset;
+ sfi_unmap_memory(start, len);
+ return 0;
+ }
+
+ sfi_unmap_memory(start, len);
+ return -1;
+}
+
+void __init sfi_init(void)
+{
+ if (!acpi_disabled)
+ disable_sfi();
+
+ if (sfi_disabled)
+ return;
+
+ pr_info("Simple Firmware Interface v0.7 http://simplefirmware.org\n");
+
+ if (sfi_find_syst() || sfi_parse_syst() || sfi_platform_init())
+ disable_sfi();
+
+ return;
+}
+
+void __init sfi_init_late(void)
+{
+ int length;
+
+ if (sfi_disabled)
+ return;
+
+ length = syst_va->header.len;
+ sfi_unmap_memory(syst_va, sizeof(struct sfi_table_simple));
+
+ /* Use ioremap now after it is ready */
+ sfi_use_ioremap = 1;
+ syst_va = sfi_map_memory(syst_pa, length);
+
+ sfi_acpi_init();
+}
+
+static int __init sfi_parse_cmdline(char *arg)
+{
+ if (!arg)
+ return -EINVAL;
+
+ if (!strcmp(arg, "off"))
+ sfi_disabled = 1;
+
+ return 0;
+}
+
+early_param("sfi", sfi_parse_cmdline);
diff --git a/drivers/sfi/sfi_core.h b/drivers/sfi/sfi_core.h
new file mode 100644
index 000000000000..41d8757e0101
--- /dev/null
+++ b/drivers/sfi/sfi_core.h
@@ -0,0 +1,51 @@
+/* sfi_core.h Simple Firmware Interface, internal header */
+
+/*
+ * Copyright (C) 2009, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+struct sfi_table_key{
+ char *sig;
+ char *oem_id;
+ char *oem_table_id;
+};
+
+#define SFI_ANY_KEY { .sig = NULL, .oem_id = NULL, .oem_table_id = NULL }
+
+extern int __init sfi_acpi_init(void);
+extern struct sfi_table_header *sfi_check_table(u64 paddr,
+ struct sfi_table_key *key);
+extern void sfi_put_table(struct sfi_table_header *table);
diff --git a/include/linux/sfi.h b/include/linux/sfi.h
new file mode 100644
index 000000000000..241dd7f09268
--- /dev/null
+++ b/include/linux/sfi.h
@@ -0,0 +1,187 @@
+/* sfi.h Simple Firmware Interface */
+
+/*
+ * Copyright (C) 2009, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#ifndef _LINUX_SFI_H
+#define _LINUX_SFI_H
+
+/* Table signatures reserved by the SFI specification */
+#define SFI_SIG_SYST "SYST"
+#define SFI_SIG_FREQ "FREQ"
+#define SFI_SIG_IDLE "IDLE"
+#define SFI_SIG_CPUS "CPUS"
+#define SFI_SIG_MTMR "MTMR"
+#define SFI_SIG_MRTC "MRTC"
+#define SFI_SIG_MMAP "MMAP"
+#define SFI_SIG_APIC "APIC"
+#define SFI_SIG_XSDT "XSDT"
+#define SFI_SIG_WAKE "WAKE"
+#define SFI_SIG_SPIB "SPIB"
+#define SFI_SIG_I2CB "I2CB"
+#define SFI_SIG_GPEM "GPEM"
+
+#define SFI_SIGNATURE_SIZE 4
+#define SFI_OEM_ID_SIZE 6
+#define SFI_OEM_TABLE_ID_SIZE 8
+
+#define SFI_SYST_SEARCH_BEGIN 0x000E0000
+#define SFI_SYST_SEARCH_END 0x000FFFFF
+
+#define SFI_GET_NUM_ENTRIES(ptable, entry_type) \
+ ((ptable->header.len - sizeof(struct sfi_table_header)) / \
+ (sizeof(entry_type)))
+/*
+ * Table structures must be byte-packed to match the SFI specification,
+ * as they are provided by the BIOS.
+ */
+struct sfi_table_header {
+ char sig[SFI_SIGNATURE_SIZE];
+ u32 len;
+ u8 rev;
+ u8 csum;
+ char oem_id[SFI_OEM_ID_SIZE];
+ char oem_table_id[SFI_OEM_TABLE_ID_SIZE];
+} __packed;
+
+struct sfi_table_simple {
+ struct sfi_table_header header;
+ u64 pentry[1];
+} __packed;
+
+/* Comply with UEFI spec 2.1 */
+struct sfi_mem_entry {
+ u32 type;
+ u64 phys_start;
+ u64 virt_start;
+ u64 pages;
+ u64 attrib;
+} __packed;
+
+struct sfi_cpu_table_entry {
+ u32 apic_id;
+} __packed;
+
+struct sfi_cstate_table_entry {
+ u32 hint; /* MWAIT hint */
+ u32 latency; /* latency in ms */
+} __packed;
+
+struct sfi_apic_table_entry {
+ u64 phys_addr; /* phy base addr for APIC reg */
+} __packed;
+
+struct sfi_freq_table_entry {
+ u32 freq_mhz; /* in MHZ */
+ u32 latency; /* transition latency in ms */
+ u32 ctrl_val; /* value to write to PERF_CTL */
+} __packed;
+
+struct sfi_wake_table_entry {
+ u64 phys_addr; /* pointer to where the wake vector locates */
+} __packed;
+
+struct sfi_timer_table_entry {
+ u64 phys_addr; /* phy base addr for the timer */
+ u32 freq_hz; /* in HZ */
+ u32 irq;
+} __packed;
+
+struct sfi_rtc_table_entry {
+ u64 phys_addr; /* phy base addr for the RTC */
+ u32 irq;
+} __packed;
+
+struct sfi_spi_table_entry {
+ u16 host_num; /* attached to host 0, 1...*/
+ u16 cs; /* chip select */
+ u16 irq_info;
+ char name[16];
+ u8 dev_info[10];
+} __packed;
+
+struct sfi_i2c_table_entry {
+ u16 host_num;
+ u16 addr; /* slave addr */
+ u16 irq_info;
+ char name[16];
+ u8 dev_info[10];
+} __packed;
+
+struct sfi_gpe_table_entry {
+ u16 logical_id; /* logical id */
+ u16 phys_id; /* physical GPE id */
+} __packed;
+
+
+typedef int (*sfi_table_handler) (struct sfi_table_header *table);
+
+#ifdef CONFIG_SFI
+extern void __init sfi_init(void);
+extern int __init sfi_platform_init(void);
+extern void __init sfi_init_late(void);
+extern int sfi_table_parse(char *signature, char *oem_id, char *oem_table_id,
+ sfi_table_handler handler);
+
+extern int sfi_disabled;
+static inline void disable_sfi(void)
+{
+ sfi_disabled = 1;
+}
+
+#else /* !CONFIG_SFI */
+
+static inline void sfi_init(void)
+{
+}
+
+static inline void sfi_init_late(void)
+{
+}
+
+#define sfi_disabled 0
+
+static inline int sfi_table_parse(char *signature, char *oem_id,
+ char *oem_table_id,
+ sfi_table_handler handler)
+{
+ return -1;
+}
+
+#endif /* CONFIG_SFI */
+
+#endif /*_LINUX_SFI_H*/
diff --git a/include/linux/sfi_acpi.h b/include/linux/sfi_acpi.h
new file mode 100644
index 000000000000..aa5cbdc682a2
--- /dev/null
+++ b/include/linux/sfi_acpi.h
@@ -0,0 +1,74 @@
+/* sfi.h Simple Firmware Interface */
+
+/*
+ * Copyright (C) 2009, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#ifndef _LINUX_SFI_ACPI_H
+#define _LINUX_SFI_ACPI_H
+
+#ifdef CONFIG_SFI
+#include <acpi/acpi.h> /* struct acpi_table_header */
+
+extern int sfi_acpi_table_parse(char *signature, char *oem_id,
+ char *oem_table_id,
+ int (*handler)(struct acpi_table_header *));
+
+static inline int acpi_sfi_table_parse(char *signature,
+ int (*handler)(struct acpi_table_header *))
+{
+ if (!acpi_table_parse(signature, handler))
+ return 0;
+
+ return sfi_acpi_table_parse(signature, NULL, NULL, handler);
+}
+#else /* !CONFIG_SFI */
+
+static inline int sfi_acpi_table_parse(char *signature, char *oem_id,
+ char *oem_table_id,
+ int (*handler)(struct acpi_table_header *))
+{
+ return -1;
+}
+
+static inline int acpi_sfi_table_parse(char *signature,
+ int (*handler)(struct acpi_table_header *))
+{
+ return acpi_table_parse(signature, handler);
+}
+#endif /* CONFIG_SFI */
+
+#endif /*_LINUX_SFI_ACPI_H*/
diff --git a/init/main.c b/init/main.c
index bfec01d77315..59f911c3135c 100644
--- a/init/main.c
+++ b/init/main.c
@@ -68,6 +68,7 @@
#include <linux/async.h>
#include <linux/kmemcheck.h>
#include <linux/kmemtrace.h>
+#include <linux/sfi.h>
#include <trace/boot.h>
#include <asm/io.h>
@@ -683,6 +684,7 @@ asmlinkage void __init start_kernel(void)
check_bugs();
acpi_early_init(); /* before LAPIC and SMP init */
+ sfi_init_late();
ftrace_init();