Merge branch 'sfi-release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-sfi-2.6

* 'sfi-release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-sfi-2.6:
  SFI: remove unneeded includes
  sfi: Remove unused code
  SFI: Hook PCI MMCONFIG
  x86: add arch-specific SFI support
  SFI: add capability to parse ACPI tables
  SFI: add platform-independent core support
  SFI: create linux/sfi.h
  SFI: Simple Firmware Interface - MAINTAINERS, Kconfig
This commit is contained in:
Linus Torvalds 2009-09-23 09:34:07 -07:00
commit 746942d06a
16 changed files with 1120 additions and 4 deletions

View file

@ -4669,6 +4669,18 @@ L: linux-pci@vger.kernel.org
S: Supported S: Supported
F: drivers/pci/hotplug/shpchp* 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) SIMTEC EB110ATX (Chalice CATS)
P: Ben Dooks P: Ben Dooks
M: Vincent Sanders <support@simtec.co.uk> M: Vincent Sanders <support@simtec.co.uk>

View file

@ -1666,6 +1666,8 @@ source "kernel/power/Kconfig"
source "drivers/acpi/Kconfig" source "drivers/acpi/Kconfig"
source "drivers/sfi/Kconfig"
config X86_APM_BOOT config X86_APM_BOOT
bool bool
default y default y
@ -1861,7 +1863,7 @@ config PCI_DIRECT
config PCI_MMCONFIG config PCI_MMCONFIG
def_bool y 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 config PCI_OLPC
def_bool y def_bool y

View file

@ -56,6 +56,7 @@ obj-$(CONFIG_INTEL_TXT) += tboot.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-y += cpu/ obj-y += cpu/
obj-y += acpi/ obj-y += acpi/
obj-$(CONFIG_SFI) += sfi.o
obj-y += reboot.o obj-y += reboot.o
obj-$(CONFIG_MCA) += mca_32.o obj-$(CONFIG_MCA) += mca_32.o
obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_MSR) += msr.o

View file

@ -27,6 +27,7 @@
#include <linux/screen_info.h> #include <linux/screen_info.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/sfi.h>
#include <linux/apm_bios.h> #include <linux/apm_bios.h>
#include <linux/initrd.h> #include <linux/initrd.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
@ -985,6 +986,8 @@ void __init setup_arch(char **cmdline_p)
*/ */
acpi_boot_init(); acpi_boot_init();
sfi_init();
/* /*
* get boot-time SMP configuration: * get boot-time SMP configuration:
*/ */

122
arch/x86/kernel/sfi.c Normal file
View file

@ -0,0 +1,122 @@
/*
* sfi.c - x86 architecture SFI support.
*
* Copyright (c) 2009, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#define KMSG_COMPONENT "SFI"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/sfi.h>
#include <linux/io.h>
#include <asm/io_apic.h>
#include <asm/mpspec.h>
#include <asm/setup.h>
#include <asm/apic.h>
#ifdef CONFIG_X86_LOCAL_APIC
static unsigned long sfi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
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)
{
if (MAX_APICS - id <= 0) {
pr_warning("Processor #%d invalid (max %d)\n",
id, MAX_APICS);
return;
}
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
static u32 gsi_base;
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_register_ioapic(i, pentry->phys_addr, gsi_base);
gsi_base += io_apic_get_redir_entries(i);
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;
}

View file

@ -13,10 +13,12 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/sfi_acpi.h>
#include <linux/bitmap.h> #include <linux/bitmap.h>
#include <linux/sort.h> #include <linux/sort.h>
#include <asm/e820.h> #include <asm/e820.h>
#include <asm/pci_x86.h> #include <asm/pci_x86.h>
#include <asm/acpi.h>
#define PREFIX "PCI: " #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->start_bus_number,
(unsigned int)cfg->end_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); valid = is_mmconf_reserved(is_acpi_reserved, addr, size, i, cfg, 0);
if (valid) if (valid)
@ -608,7 +610,7 @@ static void __init __pci_mmcfg_init(int early)
} }
if (!known_bridge) 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); pci_mmcfg_reject_broken(early);

View file

@ -11,9 +11,9 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/acpi.h>
#include <asm/e820.h> #include <asm/e820.h>
#include <asm/pci_x86.h> #include <asm/pci_x86.h>
#include <acpi/acpi.h>
/* Assume systems with more busses have correct MCFG */ /* Assume systems with more busses have correct MCFG */
#define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))

View file

@ -11,6 +11,7 @@ obj-$(CONFIG_PARISC) += parisc/
obj-$(CONFIG_RAPIDIO) += rapidio/ obj-$(CONFIG_RAPIDIO) += rapidio/
obj-y += video/ obj-y += video/
obj-$(CONFIG_ACPI) += acpi/ obj-$(CONFIG_ACPI) += acpi/
obj-$(CONFIG_SFI) += sfi/
# PnP must come after ACPI since it will eventually need to check if acpi # PnP must come after ACPI since it will eventually need to check if acpi
# was used and do nothing if so # was used and do nothing if so
obj-$(CONFIG_PNP) += pnp/ obj-$(CONFIG_PNP) += pnp/

17
drivers/sfi/Kconfig Normal file
View file

@ -0,0 +1,17 @@
#
# 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. Kernel SFI support is required to
boot on SFI-only platforms. Currently, all SFI-only platforms are
based on the 2nd generation Intel Atom processor platform,
code-named Moorestown.
For more information, see http://simplefirmware.org
Say 'Y' here to enable the kernel to boot on SFI-only platforms.

3
drivers/sfi/Makefile Normal file
View file

@ -0,0 +1,3 @@
obj-y += sfi_acpi.o
obj-y += sfi_core.o

175
drivers/sfi/sfi_acpi.c Normal file
View file

@ -0,0 +1,175 @@
/* sfi_acpi.c Simple Firmware Interface - ACPI extensions */
/*
This file is provided under a dual BSD/GPLv2 license. When using or
redistributing this file, you may do so under either license.
GPL LICENSE SUMMARY
Copyright(c) 2009 Intel Corporation. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation.
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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution
in the file called LICENSE.GPL.
BSD LICENSE
Copyright(c) 2009 Intel Corporation. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Intel Corporation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
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 MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
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 DAMAGE.
*/
#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)
{
struct sfi_table_key xsdt_key = { .sig = SFI_SIG_XSDT };
sfi_table_parse(SFI_SIG_XSDT, NULL, NULL, sfi_acpi_parse_xsdt);
/* Only call the get_table to keep the table mapped */
xsdt_va = (struct acpi_table_xsdt *)sfi_get_table(&xsdt_key);
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;
}

407
drivers/sfi/sfi_core.c Normal file
View file

@ -0,0 +1,407 @@
/* sfi_core.c Simple Firmware Interface - core internals */
/*
This file is provided under a dual BSD/GPLv2 license. When using or
redistributing this file, you may do so under either license.
GPL LICENSE SUMMARY
Copyright(c) 2009 Intel Corporation. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation.
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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution
in the file called LICENSE.GPL.
BSD LICENSE
Copyright(c) 2009 Intel Corporation. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Intel Corporation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
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 MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
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 DAMAGE.
*/
#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/errno.h>
#include <linux/types.h>
#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/sfi.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
*/
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();
}

70
drivers/sfi/sfi_core.h Normal file
View file

@ -0,0 +1,70 @@
/* sfi_core.h Simple Firmware Interface, internal header */
/*
This file is provided under a dual BSD/GPLv2 license. When using or
redistributing this file, you may do so under either license.
GPL LICENSE SUMMARY
Copyright(c) 2009 Intel Corporation. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation.
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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution
in the file called LICENSE.GPL.
BSD LICENSE
Copyright(c) 2009 Intel Corporation. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Intel Corporation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
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 MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
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 DAMAGE.
*/
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);
struct sfi_table_header *sfi_get_table(struct sfi_table_key *key);
extern void sfi_put_table(struct sfi_table_header *table);

206
include/linux/sfi.h Normal file
View file

@ -0,0 +1,206 @@
/* sfi.h Simple Firmware Interface */
/*
This file is provided under a dual BSD/GPLv2 license. When using or
redistributing this file, you may do so under either license.
GPL LICENSE SUMMARY
Copyright(c) 2009 Intel Corporation. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation.
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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution
in the file called LICENSE.GPL.
BSD LICENSE
Copyright(c) 2009 Intel Corporation. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Intel Corporation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
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 MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
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 DAMAGE.
*/
#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*/

93
include/linux/sfi_acpi.h Normal file
View file

@ -0,0 +1,93 @@
/* sfi.h Simple Firmware Interface */
/*
This file is provided under a dual BSD/GPLv2 license. When using or
redistributing this file, you may do so under either license.
GPL LICENSE SUMMARY
Copyright(c) 2009 Intel Corporation. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation.
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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution
in the file called LICENSE.GPL.
BSD LICENSE
Copyright(c) 2009 Intel Corporation. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Intel Corporation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
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 MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
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 DAMAGE.
*/
#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*/

View file

@ -68,6 +68,7 @@
#include <linux/async.h> #include <linux/async.h>
#include <linux/kmemcheck.h> #include <linux/kmemcheck.h>
#include <linux/kmemtrace.h> #include <linux/kmemtrace.h>
#include <linux/sfi.h>
#include <linux/shmem_fs.h> #include <linux/shmem_fs.h>
#include <trace/boot.h> #include <trace/boot.h>
@ -689,6 +690,7 @@ asmlinkage void __init start_kernel(void)
check_bugs(); check_bugs();
acpi_early_init(); /* before LAPIC and SMP init */ acpi_early_init(); /* before LAPIC and SMP init */
sfi_init_late();
ftrace_init(); ftrace_init();