diff options
Diffstat (limited to 'drivers')
39 files changed, 757 insertions, 8 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index bc4205d..ccfa259f 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/acpi/ac.c b/drivers/acpi/ac.c index 0df8fcb..98b9690 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -37,6 +37,8 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#define PREFIX "ACPI: " + #define ACPI_AC_CLASS "ac_adapter" #define ACPI_AC_DEVICE_NAME "AC Adapter" #define ACPI_AC_FILE_STATE "state" diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 58b4517..f8c3d1b 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -45,6 +45,8 @@ #include <linux/power_supply.h> #endif +#define PREFIX "ACPI: " + #define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF #define ACPI_BATTERY_CLASS "battery" diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 0c4ca4d..e56b2a7 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -34,6 +34,8 @@ #include <acpi/acpi_bus.h> #include <linux/dmi.h> +#include "internal.h" + enum acpi_blacklist_predicates { all_versions, less_than_or_equal, diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 9195deb..d295bdc 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -33,6 +33,8 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#define PREFIX "ACPI: " + #define ACPI_BUTTON_CLASS "button" #define ACPI_BUTTON_FILE_INFO "info" #define ACPI_BUTTON_FILE_STATE "state" diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c index 332fe4b..6c9ee68 100644 --- a/drivers/acpi/cm_sbs.c +++ b/drivers/acpi/cm_sbs.c @@ -28,6 +28,8 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#define PREFIX "ACPI: " + ACPI_MODULE_NAME("cm_sbs"); #define ACPI_AC_CLASS "ac_adapter" #define ACPI_BATTERY_CLASS "battery" diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index fe0cdf8..5f2c3c0 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -35,6 +35,8 @@ #include <acpi/acpi_drivers.h> #include <acpi/container.h> +#define PREFIX "ACPI: " + #define ACPI_CONTAINER_DEVICE_NAME "ACPI container device" #define ACPI_CONTAINER_CLASS "container" diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index efb959d..9a85566 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -33,6 +33,8 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#define PREFIX "ACPI: " + #define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver" ACPI_MODULE_NAME("dock"); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 391f331..5180f0f 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -47,7 +47,6 @@ #define ACPI_EC_DEVICE_NAME "Embedded Controller" #define ACPI_EC_FILE_INFO "info" -#undef PREFIX #define PREFIX "ACPI: EC: " /* EC status register */ diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index aeb7e5f..c511071 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -14,6 +14,8 @@ #include <net/netlink.h> #include <net/genetlink.h> +#include "internal.h" + #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("event"); diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 53698ea..f419849 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -34,6 +34,8 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#define PREFIX "ACPI: " + #define ACPI_FAN_CLASS "fan" #define ACPI_FAN_FILE_STATE "state" diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index a8a5c29..dc36a44 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -12,6 +12,8 @@ #include <linux/rwsem.h> #include <linux/acpi.h> +#include "internal.h" + #define ACPI_GLUE_DEBUG 0 #if ACPI_GLUE_DEBUG #define DBG(x...) printk(PREFIX x) diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 11a69b5..074cf86 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -1,4 +1,24 @@ -/* For use by Linux/ACPI infrastructure, not drivers */ +/* + * acpi/internal.h + * For use by Linux/ACPI infrastructure, not drivers + * + * 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 PREFIX "ACPI: " int init_acpi_device_notify(void); int acpi_scan_init(void); diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index d440ccd..202dd0c 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -30,6 +30,8 @@ #include <linux/acpi.h> #include <acpi/acpi_bus.h> +#define PREFIX "ACPI: " + #define ACPI_NUMA 0x80000000 #define _COMPONENT ACPI_NUMA ACPI_MODULE_NAME("numa"); diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index b794eb8..843699e 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -40,6 +40,8 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#define PREFIX "ACPI: " + #define _COMPONENT ACPI_PCI_COMPONENT ACPI_MODULE_NAME("pci_irq"); diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 16e0f9d..394ae89 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -43,6 +43,8 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#define PREFIX "ACPI: " + #define _COMPONENT ACPI_PCI_COMPONENT ACPI_MODULE_NAME("pci_link"); #define ACPI_PCI_LINK_CLASS "pci_irq_routing" diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 31b961c..3112221 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -36,6 +36,8 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#define PREFIX "ACPI: " + #define _COMPONENT ACPI_PCI_COMPONENT ACPI_MODULE_NAME("pci_root"); #define ACPI_PCI_ROOT_CLASS "pci_bridge" diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 5a09bf3..22b2979 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -43,9 +43,10 @@ #include <linux/seq_file.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> - #include "sleep.h" +#define PREFIX "ACPI: " + #define _COMPONENT ACPI_POWER_COMPONENT ACPI_MODULE_NAME("power"); #define ACPI_POWER_CLASS "power_resource" diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 2cc4b30..b4a1ab2 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -59,6 +59,8 @@ #include <acpi/acpi_drivers.h> #include <acpi/processor.h> +#define PREFIX "ACPI: " + #define ACPI_PROCESSOR_CLASS "processor" #define ACPI_PROCESSOR_DEVICE_NAME "Processor" #define ACPI_PROCESSOR_FILE_INFO "info" diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 66393d5..22aab1f 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -60,6 +60,8 @@ #include <acpi/processor.h> #include <asm/processor.h> +#define PREFIX "ACPI: " + #define ACPI_PROCESSOR_CLASS "processor" #define _COMPONENT ACPI_PROCESSOR_COMPONENT ACPI_MODULE_NAME("processor_idle"); diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 60e543d..11088cf 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -39,6 +39,8 @@ #include <acpi/acpi_drivers.h> #include <acpi/processor.h> +#define PREFIX "ACPI: " + #define ACPI_PROCESSOR_CLASS "processor" #define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" #define _COMPONENT ACPI_PROCESSOR_COMPONENT diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 31adda1..3e3181c 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -40,6 +40,8 @@ #include <acpi/processor.h> #include <acpi/acpi_drivers.h> +#define PREFIX "ACPI: " + #define ACPI_PROCESSOR_CLASS "processor" #define _COMPONENT ACPI_PROCESSOR_COMPONENT ACPI_MODULE_NAME("processor_thermal"); diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index ae39797..b366b9c 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -41,6 +41,8 @@ #include <acpi/acpi_drivers.h> #include <acpi/processor.h> +#define PREFIX "ACPI: " + #define ACPI_PROCESSOR_CLASS "processor" #define _COMPONENT ACPI_PROCESSOR_COMPONENT ACPI_MODULE_NAME("processor_throttling"); diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 4b214b7..52b9db8 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -46,6 +46,8 @@ #include "sbshc.h" +#define PREFIX "ACPI: " + #define ACPI_SBS_CLASS "sbs" #define ACPI_AC_CLASS "ac_adapter" #define ACPI_BATTERY_CLASS "battery" diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index 0619734..d933980 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -15,6 +15,8 @@ #include <linux/interrupt.h> #include "sbshc.h" +#define PREFIX "ACPI: " + #define ACPI_SMB_HC_CLASS "smbus_host_controller" #define ACPI_SMB_HC_DEVICE_NAME "ACPI SMBus HC" diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index 9c61ab2..d112829 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -31,6 +31,8 @@ #include <acpi/acpi_drivers.h> +#define PREFIX "ACPI: " + #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("system"); diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 646d39c..f336bca7 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -213,6 +213,9 @@ acpi_table_parse_entries(char *id, unsigned long table_end; acpi_size tbl_size; + if (acpi_disabled) + return -ENODEV; + if (!handler) return -EINVAL; @@ -277,6 +280,9 @@ int __init acpi_table_parse(char *id, acpi_table_handler handler) struct acpi_table_header *table = NULL; acpi_size tbl_size; + if (acpi_disabled) + return -ENODEV; + if (!handler) return -EINVAL; diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 564ea14..65f6781 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -47,6 +47,8 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#define PREFIX "ACPI: " + #define ACPI_THERMAL_CLASS "thermal_zone" #define ACPI_THERMAL_DEVICE_NAME "Thermal Zone" #define ACPI_THERMAL_FILE_STATE "state" diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index f844941..811fec1 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -30,6 +30,8 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#include "internal.h" + #define _COMPONENT ACPI_BUS_COMPONENT ACPI_MODULE_NAME("utils"); diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 60ea984..9b578b5 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -44,6 +44,8 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#define PREFIX "ACPI: " + #define ACPI_VIDEO_CLASS "video" #define ACPI_VIDEO_BUS_NAME "Video Bus" #define ACPI_VIDEO_DEVICE_NAME "Video Device" diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 7cd2b63..7032f25 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -38,6 +38,8 @@ #include <linux/dmi.h> #include <linux/pci.h> +#define PREFIX "ACPI: " + ACPI_MODULE_NAME("video"); #define _COMPONENT ACPI_VIDEO_COMPONENT diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index ab99783..47aa593 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -35,8 +35,7 @@ #include <linux/interrupt.h> #include <linux/tboot.h> -#undef PREFIX -#define PREFIX "DMAR:" +#define PREFIX "DMAR: " /* No locks are needed as DMA remapping hardware unit * list is constructed at boot time and hotplug of diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 218b9a1..eabddc9c 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -700,7 +700,7 @@ static int acpi_fujitsu_add(struct acpi_device *device) goto end; } - printk(KERN_INFO PREFIX "%s [%s] (%s)\n", + printk(KERN_INFO "ACPI: %s [%s] (%s)\n", acpi_device_name(device), acpi_device_bid(device), !device->power.state ? "on" : "off"); @@ -874,7 +874,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) goto end; } - printk(KERN_INFO PREFIX "%s [%s] (%s)\n", + printk(KERN_INFO "ACPI: %s [%s] (%s)\n", acpi_device_name(device), acpi_device_bid(device), !device->power.state ? "on" : "off"); diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index f215a59..177f8d7 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -42,7 +42,6 @@ MODULE_LICENSE("GPL"); #define ACPI_WMI_CLASS "wmi" -#undef PREFIX #define PREFIX "ACPI: WMI: " static DEFINE_MUTEX(wmi_data_lock); diff --git a/drivers/sfi/Kconfig b/drivers/sfi/Kconfig new file mode 100644 index 0000000..dd11512 --- /dev/null +++ b/drivers/sfi/Kconfig @@ -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. diff --git a/drivers/sfi/Makefile b/drivers/sfi/Makefile new file mode 100644 index 0000000..2343732 --- /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 0000000..34aba30 --- /dev/null +++ b/drivers/sfi/sfi_acpi.c @@ -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; +} diff --git a/drivers/sfi/sfi_core.c b/drivers/sfi/sfi_core.c new file mode 100644 index 0000000..d3b4968 --- /dev/null +++ b/drivers/sfi/sfi_core.c @@ -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(); +} diff --git a/drivers/sfi/sfi_core.h b/drivers/sfi/sfi_core.h new file mode 100644 index 0000000..da82d39 --- /dev/null +++ b/drivers/sfi/sfi_core.h @@ -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); |