Commit 746942d0 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents c11f6c82 c602c65b
......@@ -4669,6 +4669,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>
......
......@@ -1666,6 +1666,8 @@ source "kernel/power/Kconfig"
source "drivers/acpi/Kconfig"
source "drivers/sfi/Kconfig"
config X86_APM_BOOT
bool
default y
......@@ -1861,7 +1863,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
......
......@@ -56,6 +56,7 @@ obj-$(CONFIG_INTEL_TXT) += tboot.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
......
......@@ -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>
......@@ -985,6 +986,8 @@ void __init setup_arch(char **cmdline_p)
*/
acpi_boot_init();
sfi_init();
/*
* get boot-time SMP configuration:
*/
......
/*
* 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;
}
......@@ -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);
......
......@@ -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))
......
......@@ -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/
......
#
# 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.
obj-y += sfi_acpi.o
obj-y += sfi_core.o
/* 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;
}
/* 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)))