Merge branches 'acpi-numa', 'acpi-tables' and 'acpi-osi'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 16 May 2016 14:45:25 +0000 (16:45 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 16 May 2016 14:45:25 +0000 (16:45 +0200)
* acpi-numa:
  ACPI / SRAT: fix SRAT parsing order with both LAPIC and X2APIC present

* acpi-tables:
  ACPI / tables: Fix DSDT override mechanism
  ACPI / tables: Convert initrd table override to table upgrade mechanism
  ACPI / x86: Cleanup initrd related code
  ACPI / tables: Move table override mechanisms to tables.c

* acpi-osi:
  ACPI / osi: Collect _OSI handling into one single file
  ACPI / osi: Cleanup coding style issues before creating a separate OSI source file
  ACPI / osi: Cleanup OSI handling code to use bool
  ACPI / osi: Fix default _OSI(Darwin) support
  ACPI / osi: Add acpi_osi=!! to allow reverting acpi_osi=!
  ACPI / osi: Cleanup _OSI("Linux") related code before introducing new support
  ACPI / osi: Fix an issue that acpi_osi=!* cannot disable ACPICA internal strings

Conflicts:
drivers/acpi/internal.h

12 files changed:
Documentation/acpi/initrd_table_override.txt
Documentation/kernel-parameters.txt
arch/x86/kernel/setup.c
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/blacklist.c
drivers/acpi/internal.h
drivers/acpi/numa.c
drivers/acpi/osi.c [new file with mode: 0644]
drivers/acpi/osl.c
drivers/acpi/tables.c
include/linux/acpi.h

index 35c3f5415476dcebd3e3397f719dcc8de5cc41a2..eb651a6aa28505769a38f68fa253e2a56be3ddef 100644 (file)
@@ -1,5 +1,5 @@
-Overriding ACPI tables via initrd
-=================================
+Upgrading ACPI tables via initrd
+================================
 
 1) Introduction (What is this about)
 2) What is this for
@@ -9,12 +9,14 @@ Overriding ACPI tables via initrd
 1) What is this about
 ---------------------
 
-If the ACPI_INITRD_TABLE_OVERRIDE compile option is true, it is possible to
-override nearly any ACPI table provided by the BIOS with an instrumented,
-modified one.
+If the ACPI_TABLE_UPGRADE compile option is true, it is possible to
+upgrade the ACPI execution environment that is defined by the ACPI tables
+via upgrading the ACPI tables provided by the BIOS with an instrumented,
+modified, more recent version one, or installing brand new ACPI tables.
 
-For a full list of ACPI tables that can be overridden, take a look at
-the char *table_sigs[MAX_ACPI_SIGNATURE]; definition in drivers/acpi/osl.c
+For a full list of ACPI tables that can be upgraded/installed, take a look
+at the char *table_sigs[MAX_ACPI_SIGNATURE]; definition in
+drivers/acpi/tables.c.
 All ACPI tables iasl (Intel's ACPI compiler and disassembler) knows should
 be overridable, except:
    - ACPI_SIG_RSDP (has a signature of 6 bytes)
@@ -25,17 +27,20 @@ Both could get implemented as well.
 2) What is this for
 -------------------
 
-Please keep in mind that this is a debug option.
-ACPI tables should not get overridden for productive use.
-If BIOS ACPI tables are overridden the kernel will get tainted with the
-TAINT_OVERRIDDEN_ACPI_TABLE flag.
-Complain to your platform/BIOS vendor if you find a bug which is so sever
-that a workaround is not accepted in the Linux kernel.
+Complain to your platform/BIOS vendor if you find a bug which is so severe
+that a workaround is not accepted in the Linux kernel. And this facility
+allows you to upgrade the buggy tables before your platform/BIOS vendor
+releases an upgraded BIOS binary.
 
-Still, it can and should be enabled in any kernel, because:
-  - There is no functional change with not instrumented initrds
-  - It provides a powerful feature to easily debug and test ACPI BIOS table
-    compatibility with the Linux kernel.
+This facility can be used by platform/BIOS vendors to provide a Linux
+compatible environment without modifying the underlying platform firmware.
+
+This facility also provides a powerful feature to easily debug and test
+ACPI BIOS table compatibility with the Linux kernel by modifying old
+platform provided ACPI tables or inserting new ACPI tables.
+
+It can and should be enabled in any kernel because there is no functional
+change with not instrumented initrds.
 
 
 3) How does it work
@@ -50,23 +55,31 @@ iasl -d *.dat
 # For example add this statement into a _PRT (PCI Routing Table) function
 # of the DSDT:
 Store("HELLO WORLD", debug)
+# And increase the OEM Revision. For example, before modification:
+DefinitionBlock ("DSDT.aml", "DSDT", 2, "INTEL ", "TEMPLATE", 0x00000000)
+# After modification:
+DefinitionBlock ("DSDT.aml", "DSDT", 2, "INTEL ", "TEMPLATE", 0x00000001)
 iasl -sa dsdt.dsl
 # Add the raw ACPI tables to an uncompressed cpio archive.
-# They must be put into a /kernel/firmware/acpi directory inside the
-# cpio archive.
-# The uncompressed cpio archive must be the first.
-# Other, typically compressed cpio archives, must be
-# concatenated on top of the uncompressed one.
+# They must be put into a /kernel/firmware/acpi directory inside the cpio
+# archive. Note that if the table put here matches a platform table
+# (similar Table Signature, and similar OEMID, and similar OEM Table ID)
+# with a more recent OEM Revision, the platform table will be upgraded by
+# this table. If the table put here doesn't match a platform table
+# (dissimilar Table Signature, or dissimilar OEMID, or dissimilar OEM Table
+# ID), this table will be appended.
 mkdir -p kernel/firmware/acpi
 cp dsdt.aml kernel/firmware/acpi
-# A maximum of: #define ACPI_OVERRIDE_TABLES 10
-# tables are  currently allowed (see osl.c):
+# A maximum of "NR_ACPI_INITRD_TABLES (64)" tables are currently allowed
+# (see osl.c):
 iasl -sa facp.dsl
 iasl -sa ssdt1.dsl
 cp facp.aml kernel/firmware/acpi
 cp ssdt1.aml kernel/firmware/acpi
-# Create the uncompressed cpio archive and concatenate the original initrd
-# on top:
+# The uncompressed cpio archive must be the first. Other, typically
+# compressed cpio archives, must be concatenated on top of the uncompressed
+# one. Following command creates the uncompressed cpio archive and
+# concatenates the original initrd on top:
 find kernel | cpio -H newc --create > /boot/instrumented_initrd
 cat /boot/initrd >>/boot/instrumented_initrd
 # reboot with increased acpi debug level, e.g. boot params:
index 0b3de80ec8f69c1aef9dfaa59fb86c14395ba43e..c48f387109e8f06884c5782e80cbc7e7e55b2e47 100644 (file)
@@ -312,6 +312,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        acpi_osi=!*             # remove all strings
                        acpi_osi=!              # disable all built-in OS vendor
                                                  strings
+                       acpi_osi=!!             # enable all built-in OS vendor
+                                                 strings
                        acpi_osi=               # disable all strings
 
                        'acpi_osi=!' can be used in combination with single or
index 2367ae07eb76db48964ef311e6cdc50f8751ecee..c4e7b3991b60d4f9dc416e925c996e870969a6c2 100644 (file)
@@ -398,6 +398,11 @@ static void __init reserve_initrd(void)
 
        memblock_free(ramdisk_image, ramdisk_end - ramdisk_image);
 }
+
+static void __init early_initrd_acpi_init(void)
+{
+       early_acpi_table_init((void *)initrd_start, initrd_end - initrd_start);
+}
 #else
 static void __init early_reserve_initrd(void)
 {
@@ -405,6 +410,9 @@ static void __init early_reserve_initrd(void)
 static void __init reserve_initrd(void)
 {
 }
+static void __init early_initrd_acpi_init(void)
+{
+}
 #endif /* CONFIG_BLK_DEV_INITRD */
 
 static void __init parse_setup_data(void)
@@ -1138,9 +1146,7 @@ void __init setup_arch(char **cmdline_p)
 
        reserve_initrd();
 
-#if defined(CONFIG_ACPI) && defined(CONFIG_BLK_DEV_INITRD)
-       acpi_initrd_override((void *)initrd_start, initrd_end - initrd_start);
-#endif
+       early_initrd_acpi_init();
 
        vsmp_init();
 
index 82b96ee8624c2b2713e981e9d9c4b0aefb9ae811..b225c4b9ba140bd17eee6f9a19b2f09198c043a0 100644 (file)
@@ -311,12 +311,12 @@ config ACPI_CUSTOM_DSDT
        bool
        default ACPI_CUSTOM_DSDT_FILE != ""
 
-config ACPI_INITRD_TABLE_OVERRIDE
-       bool "ACPI tables override via initrd"
+config ACPI_TABLE_UPGRADE
+       bool "Allow upgrading ACPI tables via initrd"
        depends on BLK_DEV_INITRD && X86
-       default n
+       default y
        help
-         This option provides functionality to override arbitrary ACPI tables
+         This option provides functionality to upgrade arbitrary ACPI tables
          via initrd. No functional change if no ACPI tables are passed via
          initrd, therefore it's safe to say Y.
          See Documentation/acpi/initrd_table_override.txt for details
index 5a65f85cf7a7c062f9055bce386040695d8945d8..251ce85a66fbb4460e6c379d39f7ddd0e2062ce8 100644 (file)
@@ -18,7 +18,7 @@ obj-$(CONFIG_ACPI)            += acpi.o \
                                        acpica/
 
 # All the builtin files are in the "acpi." module_param namespace.
-acpi-y                         += osl.o utils.o reboot.o
+acpi-y                         += osi.o osl.o utils.o reboot.o
 acpi-y                         += nvs.o
 
 # Power management related files
index 96809cd99ace8c539e5f842639e98ba4bd22502e..bdc67bad61a75b8c823973ea822b7c9feafed28c 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Check to see if the given machine has a known bad ACPI BIOS
  *  or if the BIOS is too old.
- *  Check given machine against acpi_osi_dmi_table[].
+ *  Check given machine against acpi_rev_dmi_table[].
  *
  *  Copyright (C) 2004 Len Brown <len.brown@intel.com>
  *  Copyright (C) 2002 Andy Grover <andrew.grover@intel.com>
@@ -47,7 +47,7 @@ struct acpi_blacklist_item {
        u32 is_critical_error;
 };
 
-static struct dmi_system_id acpi_osi_dmi_table[] __initdata;
+static struct dmi_system_id acpi_rev_dmi_table[] __initdata;
 
 /*
  * POLICY: If *anything* doesn't work, put it on the blacklist.
@@ -128,36 +128,12 @@ int __init acpi_blacklisted(void)
                }
        }
 
-       dmi_check_system(acpi_osi_dmi_table);
+       (void)early_acpi_osi_init();
+       dmi_check_system(acpi_rev_dmi_table);
 
        return blacklisted;
 }
 #ifdef CONFIG_DMI
-static int __init dmi_enable_osi_linux(const struct dmi_system_id *d)
-{
-       acpi_dmi_osi_linux(1, d);       /* enable */
-       return 0;
-}
-static int __init dmi_disable_osi_vista(const struct dmi_system_id *d)
-{
-       printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
-       acpi_osi_setup("!Windows 2006");
-       acpi_osi_setup("!Windows 2006 SP1");
-       acpi_osi_setup("!Windows 2006 SP2");
-       return 0;
-}
-static int __init dmi_disable_osi_win7(const struct dmi_system_id *d)
-{
-       printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
-       acpi_osi_setup("!Windows 2009");
-       return 0;
-}
-static int __init dmi_disable_osi_win8(const struct dmi_system_id *d)
-{
-       printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
-       acpi_osi_setup("!Windows 2012");
-       return 0;
-}
 #ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE
 static int __init dmi_enable_rev_override(const struct dmi_system_id *d)
 {
@@ -168,169 +144,7 @@ static int __init dmi_enable_rev_override(const struct dmi_system_id *d)
 }
 #endif
 
-static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
-       {
-       .callback = dmi_disable_osi_vista,
-       .ident = "Fujitsu Siemens",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"),
-               },
-       },
-       {
-       /*
-        * There have a NVIF method in MSI GX723 DSDT need call by Nvidia
-        * driver (e.g. nouveau) when user press brightness hotkey.
-        * Currently, nouveau driver didn't do the job and it causes there
-        * have a infinite while loop in DSDT when user press hotkey.
-        * We add MSI GX723's dmi information to this table for workaround
-        * this issue.
-        * Will remove MSI GX723 from the table after nouveau grows support.
-        */
-       .callback = dmi_disable_osi_vista,
-       .ident = "MSI GX723",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "GX723"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_vista,
-       .ident = "Sony VGN-NS10J_S",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NS10J_S"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_vista,
-       .ident = "Sony VGN-SR290J",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR290J"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_vista,
-       .ident = "VGN-NS50B_L",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NS50B_L"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_vista,
-       .ident = "VGN-SR19XN",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR19XN"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_vista,
-       .ident = "Toshiba Satellite L355",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
-                    DMI_MATCH(DMI_PRODUCT_VERSION, "Satellite L355"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win7,
-       .ident = "ASUS K50IJ",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "K50IJ"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_vista,
-       .ident = "Toshiba P305D",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P305D"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_vista,
-       .ident = "Toshiba NB100",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "NB100"),
-               },
-       },
-
-       /*
-        * The wireless hotkey does not work on those machines when
-        * returning true for _OSI("Windows 2012")
-        */
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "Dell Inspiron 7737",
-       .matches = {
-                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                   DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7737"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "Dell Inspiron 7537",
-       .matches = {
-                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                   DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7537"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "Dell Inspiron 5437",
-       .matches = {
-                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                   DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5437"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "Dell Inspiron 3437",
-       .matches = {
-                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                   DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 3437"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "Dell Vostro 3446",
-       .matches = {
-                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                   DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3446"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "Dell Vostro 3546",
-       .matches = {
-                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                   DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3546"),
-               },
-       },
-
-       /*
-        * BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
-        * Linux ignores it, except for the machines enumerated below.
-        */
-
-       /*
-        * Without this this EEEpc exports a non working WMI interface, with
-        * this it exports a working "good old" eeepc_laptop interface, fixing
-        * both brightness control, and rfkill not working.
-        */
-       {
-       .callback = dmi_enable_osi_linux,
-       .ident = "Asus EEE PC 1015PX",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "1015PX"),
-               },
-       },
-
+static struct dmi_system_id acpi_rev_dmi_table[] __initdata = {
 #ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE
        /*
         * DELL XPS 13 (2015) switches sound between HDA and I2S
index 7c188472d9c276f985f06f6c658e7329b7f2423b..9bb0773d39bfd14f87f0e8dbfe5a1ed31b54162d 100644 (file)
@@ -20,7 +20,8 @@
 
 #define PREFIX "ACPI: "
 
-void acpi_initrd_initialize_tables(void);
+int early_acpi_osi_init(void);
+int acpi_osi_init(void);
 acpi_status acpi_os_initialize1(void);
 void init_acpi_device_notify(void);
 int acpi_scan_init(void);
index 72b6e9ef0ae9bedbf72ea0a3438f1f4395308136..d176e0ece47041c851f287563f31d4a8fbae6288 100644 (file)
@@ -327,10 +327,18 @@ int __init acpi_numa_init(void)
 
        /* SRAT: Static Resource Affinity Table */
        if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
-               acpi_table_parse_srat(ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY,
-                                    acpi_parse_x2apic_affinity, 0);
-               acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
-                                    acpi_parse_processor_affinity, 0);
+               struct acpi_subtable_proc srat_proc[2];
+
+               memset(srat_proc, 0, sizeof(srat_proc));
+               srat_proc[0].id = ACPI_SRAT_TYPE_CPU_AFFINITY;
+               srat_proc[0].handler = acpi_parse_processor_affinity;
+               srat_proc[1].id = ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY;
+               srat_proc[1].handler = acpi_parse_x2apic_affinity;
+
+               acpi_table_parse_entries_array(ACPI_SIG_SRAT,
+                                       sizeof(struct acpi_table_srat),
+                                       srat_proc, ARRAY_SIZE(srat_proc), 0);
+
                cnt = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
                                            acpi_parse_memory_affinity,
                                            NR_NODE_MEMBLKS);
diff --git a/drivers/acpi/osi.c b/drivers/acpi/osi.c
new file mode 100644 (file)
index 0000000..849f9d2
--- /dev/null
@@ -0,0 +1,522 @@
+/*
+ *  osi.c - _OSI implementation
+ *
+ *  Copyright (C) 2016 Intel Corporation
+ *    Author: Lv Zheng <lv.zheng@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+/* Uncomment next line to get verbose printout */
+/* #define DEBUG */
+#define pr_fmt(fmt) "ACPI: " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+
+#include "internal.h"
+
+
+#define OSI_STRING_LENGTH_MAX  64
+#define OSI_STRING_ENTRIES_MAX 16
+
+struct acpi_osi_entry {
+       char string[OSI_STRING_LENGTH_MAX];
+       bool enable;
+};
+
+static struct acpi_osi_config {
+       u8              default_disabling;
+       unsigned int    linux_enable:1;
+       unsigned int    linux_dmi:1;
+       unsigned int    linux_cmdline:1;
+       unsigned int    darwin_enable:1;
+       unsigned int    darwin_dmi:1;
+       unsigned int    darwin_cmdline:1;
+} osi_config;
+
+static struct acpi_osi_config osi_config;
+static struct acpi_osi_entry
+osi_setup_entries[OSI_STRING_ENTRIES_MAX] __initdata = {
+       {"Module Device", true},
+       {"Processor Device", true},
+       {"3.0 _SCP Extensions", true},
+       {"Processor Aggregator Device", true},
+};
+
+static u32 acpi_osi_handler(acpi_string interface, u32 supported)
+{
+       if (!strcmp("Linux", interface)) {
+               pr_notice_once(FW_BUG
+                       "BIOS _OSI(Linux) query %s%s\n",
+                       osi_config.linux_enable ? "honored" : "ignored",
+                       osi_config.linux_cmdline ? " via cmdline" :
+                       osi_config.linux_dmi ? " via DMI" : "");
+       }
+       if (!strcmp("Darwin", interface)) {
+               pr_notice_once(
+                       "BIOS _OSI(Darwin) query %s%s\n",
+                       osi_config.darwin_enable ? "honored" : "ignored",
+                       osi_config.darwin_cmdline ? " via cmdline" :
+                       osi_config.darwin_dmi ? " via DMI" : "");
+       }
+
+       return supported;
+}
+
+void __init acpi_osi_setup(char *str)
+{
+       struct acpi_osi_entry *osi;
+       bool enable = true;
+       int i;
+
+       if (!acpi_gbl_create_osi_method)
+               return;
+
+       if (str == NULL || *str == '\0') {
+               pr_info("_OSI method disabled\n");
+               acpi_gbl_create_osi_method = FALSE;
+               return;
+       }
+
+       if (*str == '!') {
+               str++;
+               if (*str == '\0') {
+                       /* Do not override acpi_osi=!* */
+                       if (!osi_config.default_disabling)
+                               osi_config.default_disabling =
+                                       ACPI_DISABLE_ALL_VENDOR_STRINGS;
+                       return;
+               } else if (*str == '*') {
+                       osi_config.default_disabling = ACPI_DISABLE_ALL_STRINGS;
+                       for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
+                               osi = &osi_setup_entries[i];
+                               osi->enable = false;
+                       }
+                       return;
+               } else if (*str == '!') {
+                       osi_config.default_disabling = 0;
+                       return;
+               }
+               enable = false;
+       }
+
+       for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
+               osi = &osi_setup_entries[i];
+               if (!strcmp(osi->string, str)) {
+                       osi->enable = enable;
+                       break;
+               } else if (osi->string[0] == '\0') {
+                       osi->enable = enable;
+                       strncpy(osi->string, str, OSI_STRING_LENGTH_MAX);
+                       break;
+               }
+       }
+}
+
+static void __init __acpi_osi_setup_darwin(bool enable)
+{
+       osi_config.darwin_enable = !!enable;
+       if (enable) {
+               acpi_osi_setup("!");
+               acpi_osi_setup("Darwin");
+       } else {
+               acpi_osi_setup("!!");
+               acpi_osi_setup("!Darwin");
+       }
+}
+
+static void __init acpi_osi_setup_darwin(bool enable)
+{
+       /* Override acpi_osi_dmi_blacklisted() */
+       osi_config.darwin_dmi = 0;
+       osi_config.darwin_cmdline = 1;
+       __acpi_osi_setup_darwin(enable);
+}
+
+/*
+ * The story of _OSI(Linux)
+ *
+ * From pre-history through Linux-2.6.22, Linux responded TRUE upon a BIOS
+ * OSI(Linux) query.
+ *
+ * Unfortunately, reference BIOS writers got wind of this and put
+ * OSI(Linux) in their example code, quickly exposing this string as
+ * ill-conceived and opening the door to an un-bounded number of BIOS
+ * incompatibilities.
+ *
+ * For example, OSI(Linux) was used on resume to re-POST a video card on
+ * one system, because Linux at that time could not do a speedy restore in
+ * its native driver. But then upon gaining quick native restore
+ * capability, Linux has no way to tell the BIOS to skip the time-consuming
+ * POST -- putting Linux at a permanent performance disadvantage. On
+ * another system, the BIOS writer used OSI(Linux) to infer native OS
+ * support for IPMI!  On other systems, OSI(Linux) simply got in the way of
+ * Linux claiming to be compatible with other operating systems, exposing
+ * BIOS issues such as skipped device initialization.
+ *
+ * So "Linux" turned out to be a really poor chose of OSI string, and from
+ * Linux-2.6.23 onward we respond FALSE.
+ *
+ * BIOS writers should NOT query _OSI(Linux) on future systems. Linux will
+ * complain on the console when it sees it, and return FALSE. To get Linux
+ * to return TRUE for your system  will require a kernel source update to
+ * add a DMI entry, or boot with "acpi_osi=Linux"
+ */
+static void __init __acpi_osi_setup_linux(bool enable)
+{
+       osi_config.linux_enable = !!enable;
+       if (enable)
+               acpi_osi_setup("Linux");
+       else
+               acpi_osi_setup("!Linux");
+}
+
+static void __init acpi_osi_setup_linux(bool enable)
+{
+       /* Override acpi_osi_dmi_blacklisted() */
+       osi_config.linux_dmi = 0;
+       osi_config.linux_cmdline = 1;
+       __acpi_osi_setup_linux(enable);
+}
+
+/*
+ * Modify the list of "OS Interfaces" reported to BIOS via _OSI
+ *
+ * empty string disables _OSI
+ * string starting with '!' disables that string
+ * otherwise string is added to list, augmenting built-in strings
+ */
+static void __init acpi_osi_setup_late(void)
+{
+       struct acpi_osi_entry *osi;
+       char *str;
+       int i;
+       acpi_status status;
+
+       if (osi_config.default_disabling) {
+               status = acpi_update_interfaces(osi_config.default_disabling);
+               if (ACPI_SUCCESS(status))
+                       pr_info("Disabled all _OSI OS vendors%s\n",
+                               osi_config.default_disabling ==
+                               ACPI_DISABLE_ALL_STRINGS ?
+                               " and feature groups" : "");
+       }
+
+       for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
+               osi = &osi_setup_entries[i];
+               str = osi->string;
+               if (*str == '\0')
+                       break;
+               if (osi->enable) {
+                       status = acpi_install_interface(str);
+                       if (ACPI_SUCCESS(status))
+                               pr_info("Added _OSI(%s)\n", str);
+               } else {
+                       status = acpi_remove_interface(str);
+                       if (ACPI_SUCCESS(status))
+                               pr_info("Deleted _OSI(%s)\n", str);
+               }
+       }
+}
+
+static int __init osi_setup(char *str)
+{
+       if (str && !strcmp("Linux", str))
+               acpi_osi_setup_linux(true);
+       else if (str && !strcmp("!Linux", str))
+               acpi_osi_setup_linux(false);
+       else if (str && !strcmp("Darwin", str))
+               acpi_osi_setup_darwin(true);
+       else if (str && !strcmp("!Darwin", str))
+               acpi_osi_setup_darwin(false);
+       else
+               acpi_osi_setup(str);
+
+       return 1;
+}
+__setup("acpi_osi=", osi_setup);
+
+bool acpi_osi_is_win8(void)
+{
+       return acpi_gbl_osi_data >= ACPI_OSI_WIN_8;
+}
+EXPORT_SYMBOL(acpi_osi_is_win8);
+
+static void __init acpi_osi_dmi_darwin(bool enable,
+                                      const struct dmi_system_id *d)
+{
+       pr_notice("DMI detected to setup _OSI(\"Darwin\"): %s\n", d->ident);
+       osi_config.darwin_dmi = 1;
+       __acpi_osi_setup_darwin(enable);
+}
+
+void __init acpi_osi_dmi_linux(bool enable, const struct dmi_system_id *d)
+{
+       pr_notice("DMI detected to setup _OSI(\"Linux\"): %s\n", d->ident);
+       osi_config.linux_dmi = 1;
+       __acpi_osi_setup_linux(enable);
+}
+
+static int __init dmi_enable_osi_darwin(const struct dmi_system_id *d)
+{
+       acpi_osi_dmi_darwin(true, d);
+
+       return 0;
+}
+
+static int __init dmi_enable_osi_linux(const struct dmi_system_id *d)
+{
+       acpi_osi_dmi_linux(true, d);
+
+       return 0;
+}
+
+static int __init dmi_disable_osi_vista(const struct dmi_system_id *d)
+{
+       pr_notice("DMI detected: %s\n", d->ident);
+       acpi_osi_setup("!Windows 2006");
+       acpi_osi_setup("!Windows 2006 SP1");
+       acpi_osi_setup("!Windows 2006 SP2");
+
+       return 0;
+}
+
+static int __init dmi_disable_osi_win7(const struct dmi_system_id *d)
+{
+       pr_notice("DMI detected: %s\n", d->ident);
+       acpi_osi_setup("!Windows 2009");
+
+       return 0;
+}
+
+static int __init dmi_disable_osi_win8(const struct dmi_system_id *d)
+{
+       pr_notice("DMI detected: %s\n", d->ident);
+       acpi_osi_setup("!Windows 2012");
+
+       return 0;
+}
+
+/*
+ * Linux default _OSI response behavior is determined by this DMI table.
+ *
+ * Note that _OSI("Linux")/_OSI("Darwin") determined here can be overridden
+ * by acpi_osi=!Linux/acpi_osi=!Darwin command line options.
+ */
+static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
+       {
+       .callback = dmi_disable_osi_vista,
+       .ident = "Fujitsu Siemens",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"),
+               },
+       },
+       {
+       /*
+        * There have a NVIF method in MSI GX723 DSDT need call by Nvidia
+        * driver (e.g. nouveau) when user press brightness hotkey.
+        * Currently, nouveau driver didn't do the job and it causes there
+        * have a infinite while loop in DSDT when user press hotkey.
+        * We add MSI GX723's dmi information to this table for workaround
+        * this issue.
+        * Will remove MSI GX723 from the table after nouveau grows support.
+        */
+       .callback = dmi_disable_osi_vista,
+       .ident = "MSI GX723",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "GX723"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_vista,
+       .ident = "Sony VGN-NS10J_S",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NS10J_S"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_vista,
+       .ident = "Sony VGN-SR290J",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR290J"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_vista,
+       .ident = "VGN-NS50B_L",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NS50B_L"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_vista,
+       .ident = "VGN-SR19XN",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR19XN"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_vista,
+       .ident = "Toshiba Satellite L355",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+                    DMI_MATCH(DMI_PRODUCT_VERSION, "Satellite L355"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_win7,
+       .ident = "ASUS K50IJ",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "K50IJ"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_vista,
+       .ident = "Toshiba P305D",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P305D"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_vista,
+       .ident = "Toshiba NB100",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "NB100"),
+               },
+       },
+
+       /*
+        * The wireless hotkey does not work on those machines when
+        * returning true for _OSI("Windows 2012")
+        */
+       {
+       .callback = dmi_disable_osi_win8,
+       .ident = "Dell Inspiron 7737",
+       .matches = {
+                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                   DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7737"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_win8,
+       .ident = "Dell Inspiron 7537",
+       .matches = {
+                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                   DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7537"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_win8,
+       .ident = "Dell Inspiron 5437",
+       .matches = {
+                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                   DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5437"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_win8,
+       .ident = "Dell Inspiron 3437",
+       .matches = {
+                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                   DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 3437"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_win8,
+       .ident = "Dell Vostro 3446",
+       .matches = {
+                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                   DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3446"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_win8,
+       .ident = "Dell Vostro 3546",
+       .matches = {
+                   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                   DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3546"),
+               },
+       },
+
+       /*
+        * BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
+        * Linux ignores it, except for the machines enumerated below.
+        */
+
+       /*
+        * Without this this EEEpc exports a non working WMI interface, with
+        * this it exports a working "good old" eeepc_laptop interface, fixing
+        * both brightness control, and rfkill not working.
+        */
+       {
+       .callback = dmi_enable_osi_linux,
+       .ident = "Asus EEE PC 1015PX",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "1015PX"),
+               },
+       },
+
+       /*
+        * Enable _OSI("Darwin") for all apple platforms.
+        */
+       {
+       .callback = dmi_enable_osi_darwin,
+       .ident = "Apple hardware",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+               },
+       },
+       {
+       .callback = dmi_enable_osi_darwin,
+       .ident = "Apple hardware",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
+               },
+       },
+       {}
+};
+
+static __init void acpi_osi_dmi_blacklisted(void)
+{
+       dmi_check_system(acpi_osi_dmi_table);
+}
+
+int __init early_acpi_osi_init(void)
+{
+       acpi_osi_dmi_blacklisted();
+
+       return 0;
+}
+
+int __init acpi_osi_init(void)
+{
+       acpi_install_interface_handler(acpi_osi_handler);
+       acpi_osi_setup_late();
+
+       return 0;
+}
index bef06c9503cdccb9321cb3045a1592a0153922ca..b108f1358a32b54931cbf9640410851ab7f736c1 100644 (file)
@@ -56,10 +56,6 @@ struct acpi_os_dpc {
        struct work_struct work;
 };
 
-#ifdef CONFIG_ACPI_CUSTOM_DSDT
-#include CONFIG_ACPI_CUSTOM_DSDT_FILE
-#endif
-
 #ifdef ENABLE_DEBUGGER
 #include <linux/kdb.h>
 
@@ -96,72 +92,6 @@ struct acpi_ioremap {
 static LIST_HEAD(acpi_ioremaps);
 static DEFINE_MUTEX(acpi_ioremap_lock);
 
-static void __init acpi_osi_setup_late(void);
-
-/*
- * The story of _OSI(Linux)
- *
- * From pre-history through Linux-2.6.22,
- * Linux responded TRUE upon a BIOS OSI(Linux) query.
- *
- * Unfortunately, reference BIOS writers got wind of this
- * and put OSI(Linux) in their example code, quickly exposing
- * this string as ill-conceived and opening the door to
- * an un-bounded number of BIOS incompatibilities.
- *
- * For example, OSI(Linux) was used on resume to re-POST a
- * video card on one system, because Linux at that time
- * could not do a speedy restore in its native driver.
- * But then upon gaining quick native restore capability,
- * Linux has no way to tell the BIOS to skip the time-consuming
- * POST -- putting Linux at a permanent performance disadvantage.
- * On another system, the BIOS writer used OSI(Linux)
- * to infer native OS support for IPMI!  On other systems,
- * OSI(Linux) simply got in the way of Linux claiming to
- * be compatible with other operating systems, exposing
- * BIOS issues such as skipped device initialization.
- *
- * So "Linux" turned out to be a really poor chose of
- * OSI string, and from Linux-2.6.23 onward we respond FALSE.
- *
- * BIOS writers should NOT query _OSI(Linux) on future systems.
- * Linux will complain on the console when it sees it, and return FALSE.
- * To get Linux to return TRUE for your system  will require
- * a kernel source update to add a DMI entry,
- * or boot with "acpi_osi=Linux"
- */
-
-static struct osi_linux {
-       unsigned int    enable:1;
-       unsigned int    dmi:1;
-       unsigned int    cmdline:1;
-       unsigned int    default_disabling:1;
-} osi_linux = {0, 0, 0, 0};
-
-static u32 acpi_osi_handler(acpi_string interface, u32 supported)
-{
-       if (!strcmp("Linux", interface)) {
-
-               printk_once(KERN_NOTICE FW_BUG PREFIX
-                       "BIOS _OSI(Linux) query %s%s\n",
-                       osi_linux.enable ? "honored" : "ignored",
-                       osi_linux.cmdline ? " via cmdline" :
-                       osi_linux.dmi ? " via DMI" : "");
-       }
-
-       if (!strcmp("Darwin", interface)) {
-               /*
-                * Apple firmware will behave poorly if it receives positive
-                * answers to "Darwin" and any other OS. Respond positively
-                * to Darwin and then disable all other vendor strings.
-                */
-               acpi_update_interfaces(ACPI_DISABLE_ALL_VENDOR_STRINGS);
-               supported = ACPI_UINT32_MAX;
-       }
-
-       return supported;
-}
-
 static void __init acpi_request_region (struct acpi_generic_address *gas,
        unsigned int length, char *desc)
 {
@@ -602,280 +532,6 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
        return AE_OK;
 }
 
-static void acpi_table_taint(struct acpi_table_header *table)
-{
-       pr_warn(PREFIX
-               "Override [%4.4s-%8.8s], this is unsafe: tainting kernel\n",
-               table->signature, table->oem_table_id);
-       add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
-}
-
-#ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
-#include <linux/earlycpio.h>
-#include <linux/memblock.h>
-
-static u64 acpi_tables_addr;
-static int all_tables_size;
-
-/* Copied from acpica/tbutils.c:acpi_tb_checksum() */
-static u8 __init acpi_table_checksum(u8 *buffer, u32 length)
-{
-       u8 sum = 0;
-       u8 *end = buffer + length;
-
-       while (buffer < end)
-               sum = (u8) (sum + *(buffer++));
-       return sum;
-}
-
-/* All but ACPI_SIG_RSDP and ACPI_SIG_FACS: */
-static const char * const table_sigs[] = {
-       ACPI_SIG_BERT, ACPI_SIG_CPEP, ACPI_SIG_ECDT, ACPI_SIG_EINJ,
-       ACPI_SIG_ERST, ACPI_SIG_HEST, ACPI_SIG_MADT, ACPI_SIG_MSCT,
-       ACPI_SIG_SBST, ACPI_SIG_SLIT, ACPI_SIG_SRAT, ACPI_SIG_ASF,
-       ACPI_SIG_BOOT, ACPI_SIG_DBGP, ACPI_SIG_DMAR, ACPI_SIG_HPET,
-       ACPI_SIG_IBFT, ACPI_SIG_IVRS, ACPI_SIG_MCFG, ACPI_SIG_MCHI,
-       ACPI_SIG_SLIC, ACPI_SIG_SPCR, ACPI_SIG_SPMI, ACPI_SIG_TCPA,
-       ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT, ACPI_SIG_WDDT,
-       ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT,
-       ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, NULL };
-
-#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header)
-
-#define ACPI_OVERRIDE_TABLES 64
-static struct cpio_data __initdata acpi_initrd_files[ACPI_OVERRIDE_TABLES];
-static DECLARE_BITMAP(acpi_initrd_installed, ACPI_OVERRIDE_TABLES);
-
-#define MAP_CHUNK_SIZE   (NR_FIX_BTMAPS << PAGE_SHIFT)
-
-void __init acpi_initrd_override(void *data, size_t size)
-{
-       int sig, no, table_nr = 0, total_offset = 0;
-       long offset = 0;
-       struct acpi_table_header *table;
-       char cpio_path[32] = "kernel/firmware/acpi/";
-       struct cpio_data file;
-
-       if (data == NULL || size == 0)
-               return;
-
-       for (no = 0; no < ACPI_OVERRIDE_TABLES; no++) {
-               file = find_cpio_data(cpio_path, data, size, &offset);
-               if (!file.data)
-                       break;
-
-               data += offset;
-               size -= offset;
-
-               if (file.size < sizeof(struct acpi_table_header)) {
-                       pr_err("ACPI OVERRIDE: Table smaller than ACPI header [%s%s]\n",
-                               cpio_path, file.name);
-                       continue;
-               }
-
-               table = file.data;
-
-               for (sig = 0; table_sigs[sig]; sig++)
-                       if (!memcmp(table->signature, table_sigs[sig], 4))
-                               break;
-
-               if (!table_sigs[sig]) {
-                       pr_err("ACPI OVERRIDE: Unknown signature [%s%s]\n",
-                               cpio_path, file.name);
-                       continue;
-               }
-               if (file.size != table->length) {
-                       pr_err("ACPI OVERRIDE: File length does not match table length [%s%s]\n",
-                               cpio_path, file.name);
-                       continue;
-               }
-               if (acpi_table_checksum(file.data, table->length)) {
-                       pr_err("ACPI OVERRIDE: Bad table checksum [%s%s]\n",
-                               cpio_path, file.name);
-                       continue;
-               }
-
-               pr_info("%4.4s ACPI table found in initrd [%s%s][0x%x]\n",
-                       table->signature, cpio_path, file.name, table->length);
-
-               all_tables_size += table->length;
-               acpi_initrd_files[table_nr].data = file.data;
-               acpi_initrd_files[table_nr].size = file.size;
-               table_nr++;
-       }
-       if (table_nr == 0)
-               return;
-
-       acpi_tables_addr =
-               memblock_find_in_range(0, max_low_pfn_mapped << PAGE_SHIFT,
-                                      all_tables_size, PAGE_SIZE);
-       if (!acpi_tables_addr) {
-               WARN_ON(1);
-               return;
-       }
-       /*
-        * Only calling e820_add_reserve does not work and the
-        * tables are invalid (memory got used) later.
-        * memblock_reserve works as expected and the tables won't get modified.
-        * But it's not enough on X86 because ioremap will
-        * complain later (used by acpi_os_map_memory) that the pages
-        * that should get mapped are not marked "reserved".
-        * Both memblock_reserve and e820_add_region (via arch_reserve_mem_area)
-        * works fine.
-        */
-       memblock_reserve(acpi_tables_addr, all_tables_size);
-       arch_reserve_mem_area(acpi_tables_addr, all_tables_size);
-
-       /*
-        * early_ioremap only can remap 256k one time. If we map all
-        * tables one time, we will hit the limit. Need to map chunks
-        * one by one during copying the same as that in relocate_initrd().
-        */
-       for (no = 0; no < table_nr; no++) {
-               unsigned char *src_p = acpi_initrd_files[no].data;
-               phys_addr_t size = acpi_initrd_files[no].size;
-               phys_addr_t dest_addr = acpi_tables_addr + total_offset;
-               phys_addr_t slop, clen;
-               char *dest_p;
-
-               total_offset += size;
-
-               while (size) {
-                       slop = dest_addr & ~PAGE_MASK;
-                       clen = size;
-                       if (clen > MAP_CHUNK_SIZE - slop)
-                               clen = MAP_CHUNK_SIZE - slop;
-                       dest_p = early_ioremap(dest_addr & PAGE_MASK,
-                                                clen + slop);
-                       memcpy(dest_p + slop, src_p, clen);
-                       early_iounmap(dest_p, clen + slop);
-                       src_p += clen;
-                       dest_addr += clen;
-                       size -= clen;
-               }
-       }
-}
-
-acpi_status
-acpi_os_physical_table_override(struct acpi_table_header *existing_table,
-                               acpi_physical_address *address, u32 *length)
-{
-       int table_offset = 0;
-       int table_index = 0;
-       struct acpi_table_header *table;
-       u32 table_length;
-
-       *length = 0;
-       *address = 0;
-       if (!acpi_tables_addr)
-               return AE_OK;
-
-       while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) {
-               table = acpi_os_map_memory(acpi_tables_addr + table_offset,
-                                          ACPI_HEADER_SIZE);
-               if (table_offset + table->length > all_tables_size) {
-                       acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
-                       WARN_ON(1);
-                       return AE_OK;
-               }
-
-               table_length = table->length;
-
-               /* Only override tables matched */
-               if (test_bit(table_index, acpi_initrd_installed) ||
-                   memcmp(existing_table->signature, table->signature, 4) ||
-                   memcmp(table->oem_table_id, existing_table->oem_table_id,
-                          ACPI_OEM_TABLE_ID_SIZE)) {
-                       acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
-                       goto next_table;
-               }
-
-               *length = table_length;
-               *address = acpi_tables_addr + table_offset;
-               acpi_table_taint(existing_table);
-               acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
-               set_bit(table_index, acpi_initrd_installed);
-               break;
-
-next_table:
-               table_offset += table_length;
-               table_index++;
-       }
-       return AE_OK;
-}
-
-void __init acpi_initrd_initialize_tables(void)
-{
-       int table_offset = 0;
-       int table_index = 0;
-       u32 table_length;
-       struct acpi_table_header *table;
-
-       if (!acpi_tables_addr)
-               return;
-
-       while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) {
-               table = acpi_os_map_memory(acpi_tables_addr + table_offset,
-                                          ACPI_HEADER_SIZE);
-               if (table_offset + table->length > all_tables_size) {
-                       acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
-                       WARN_ON(1);
-                       return;
-               }
-
-               table_length = table->length;
-
-               /* Skip RSDT/XSDT which should only be used for override */
-               if (test_bit(table_index, acpi_initrd_installed) ||
-                   ACPI_COMPARE_NAME(table->signature, ACPI_SIG_RSDT) ||
-                   ACPI_COMPARE_NAME(table->signature, ACPI_SIG_XSDT)) {
-                       acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
-                       goto next_table;
-               }
-
-               acpi_table_taint(table);
-               acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
-               acpi_install_table(acpi_tables_addr + table_offset, TRUE);
-               set_bit(table_index, acpi_initrd_installed);
-next_table:
-               table_offset += table_length;
-               table_index++;
-       }
-}
-#else
-acpi_status
-acpi_os_physical_table_override(struct acpi_table_header *existing_table,
-                               acpi_physical_address *address,
-                               u32 *table_length)
-{
-       *table_length = 0;
-       *address = 0;
-       return AE_OK;
-}
-
-void __init acpi_initrd_initialize_tables(void)
-{
-}
-#endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */
-
-acpi_status
-acpi_os_table_override(struct acpi_table_header *existing_table,
-                      struct acpi_table_header **new_table)
-{
-       if (!existing_table || !new_table)
-               return AE_BAD_PARAMETER;
-
-       *new_table = NULL;
-
-#ifdef CONFIG_ACPI_CUSTOM_DSDT
-       if (strncmp(existing_table->signature, "DSDT", 4) == 0)
-               *new_table = (struct acpi_table_header *)AmlCode;
-#endif
-       if (*new_table != NULL)
-               acpi_table_taint(existing_table);
-       return AE_OK;
-}
-
 static irqreturn_t acpi_irq(int irq, void *dev_id)
 {
        u32 handled;
@@ -1717,156 +1373,6 @@ static int __init acpi_os_name_setup(char *str)
 
 __setup("acpi_os_name=", acpi_os_name_setup);
 
-#define        OSI_STRING_LENGTH_MAX 64        /* arbitrary */
-#define        OSI_STRING_ENTRIES_MAX 16       /* arbitrary */
-
-struct osi_setup_entry {
-       char string[OSI_STRING_LENGTH_MAX];
-       bool enable;
-};
-
-static struct osi_setup_entry
-               osi_setup_entries[OSI_STRING_ENTRIES_MAX] __initdata = {
-       {"Module Device", true},
-       {"Processor Device", true},
-       {"3.0 _SCP Extensions", true},
-       {"Processor Aggregator Device", true},
-};
-
-void __init acpi_osi_setup(char *str)
-{
-       struct osi_setup_entry *osi;
-       bool enable = true;
-       int i;
-
-       if (!acpi_gbl_create_osi_method)
-               return;
-
-       if (str == NULL || *str == '\0') {
-               printk(KERN_INFO PREFIX "_OSI method disabled\n");
-               acpi_gbl_create_osi_method = FALSE;
-               return;
-       }
-
-       if (*str == '!') {
-               str++;
-               if (*str == '\0') {
-                       osi_linux.default_disabling = 1;
-                       return;
-               } else if (*str == '*') {
-                       acpi_update_interfaces(ACPI_DISABLE_ALL_STRINGS);
-                       for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
-                               osi = &osi_setup_entries[i];
-                               osi->enable = false;
-                       }
-                       return;
-               }
-               enable = false;
-       }
-
-       for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
-               osi = &osi_setup_entries[i];
-               if (!strcmp(osi->string, str)) {
-                       osi->enable = enable;
-                       break;
-               } else if (osi->string[0] == '\0') {
-                       osi->enable = enable;
-                       strncpy(osi->string, str, OSI_STRING_LENGTH_MAX);
-                       break;
-               }
-       }
-}
-
-static void __init set_osi_linux(unsigned int enable)
-{
-       if (osi_linux.enable != enable)
-               osi_linux.enable = enable;
-
-       if (osi_linux.enable)
-               acpi_osi_setup("Linux");
-       else
-               acpi_osi_setup("!Linux");
-
-       return;
-}
-
-static void __init acpi_cmdline_osi_linux(unsigned int enable)
-{
-       osi_linux.cmdline = 1;  /* cmdline set the default and override DMI */
-       osi_linux.dmi = 0;
-       set_osi_linux(enable);
-
-       return;
-}
-
-void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
-{
-       printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
-
-       if (enable == -1)
-               return;
-
-       osi_linux.dmi = 1;      /* DMI knows that this box asks OSI(Linux) */
-       set_osi_linux(enable);
-
-       return;
-}
-
-/*
- * Modify the list of "OS Interfaces" reported to BIOS via _OSI
- *
- * empty string disables _OSI
- * string starting with '!' disables that string
- * otherwise string is added to list, augmenting built-in strings
- */
-static void __init acpi_osi_setup_late(void)
-{
-       struct osi_setup_entry *osi;
-       char *str;
-       int i;
-       acpi_status status;
-
-       if (osi_linux.default_disabling) {
-               status = acpi_update_interfaces(ACPI_DISABLE_ALL_VENDOR_STRINGS);
-
-               if (ACPI_SUCCESS(status))
-                       printk(KERN_INFO PREFIX "Disabled all _OSI OS vendors\n");
-       }
-
-       for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
-               osi = &osi_setup_entries[i];
-               str = osi->string;
-
-               if (*str == '\0')
-                       break;
-               if (osi->enable) {
-                       status = acpi_install_interface(str);
-
-                       if (ACPI_SUCCESS(status))
-                               printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
-               } else {
-                       status = acpi_remove_interface(str);
-
-                       if (ACPI_SUCCESS(status))
-                               printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
-               }
-       }
-}
-
-static int __init osi_setup(char *str)
-{
-       if (str && !strcmp("Linux", str))
-               acpi_cmdline_osi_linux(1);
-       else if (str && !strcmp("!Linux", str))
-               acpi_cmdline_osi_linux(0);
-       else
-               acpi_osi_setup(str);
-
-       return 1;
-}
-
-__setup("acpi_osi=", osi_setup);
-
 /*
  * Disable the auto-serialization of named objects creation methods.
  *
@@ -1986,12 +1492,6 @@ int acpi_resources_are_enforced(void)
 }
 EXPORT_SYMBOL(acpi_resources_are_enforced);
 
-bool acpi_osi_is_win8(void)
-{
-       return acpi_gbl_osi_data >= ACPI_OSI_WIN_8;
-}
-EXPORT_SYMBOL(acpi_osi_is_win8);
-
 /*
  * Deallocate the memory for a spinlock.
  */
@@ -2157,8 +1657,7 @@ acpi_status __init acpi_os_initialize1(void)
        BUG_ON(!kacpid_wq);
        BUG_ON(!kacpi_notify_wq);
        BUG_ON(!kacpi_hotplug_wq);
-       acpi_install_interface_handler(acpi_osi_handler);
-       acpi_osi_setup_late();
+       acpi_osi_init();
        return AE_OK;
 }
 
index f49c02442d65c2d2c07fffa97ac79c2df305e917..a372f9eaa15deb8999abc60a4f0de2d7a9579cdd 100644 (file)
 #include <linux/errno.h>
 #include <linux/acpi.h>
 #include <linux/bootmem.h>
+#include <linux/earlycpio.h>
+#include <linux/memblock.h>
 #include "internal.h"
 
+#ifdef CONFIG_ACPI_CUSTOM_DSDT
+#include CONFIG_ACPI_CUSTOM_DSDT_FILE
+#endif
+
 #define ACPI_MAX_TABLES                128
 
 static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
@@ -433,6 +439,314 @@ static void __init check_multiple_madt(void)
        return;
 }
 
+static void acpi_table_taint(struct acpi_table_header *table)
+{
+       pr_warn("Override [%4.4s-%8.8s], this is unsafe: tainting kernel\n",
+               table->signature, table->oem_table_id);
+       add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
+}
+
+#ifdef CONFIG_ACPI_TABLE_UPGRADE
+static u64 acpi_tables_addr;
+static int all_tables_size;
+
+/* Copied from acpica/tbutils.c:acpi_tb_checksum() */
+static u8 __init acpi_table_checksum(u8 *buffer, u32 length)
+{
+       u8 sum = 0;
+       u8 *end = buffer + length;
+
+       while (buffer < end)
+               sum = (u8) (sum + *(buffer++));
+       return sum;
+}
+
+/* All but ACPI_SIG_RSDP and ACPI_SIG_FACS: */
+static const char * const table_sigs[] = {
+       ACPI_SIG_BERT, ACPI_SIG_CPEP, ACPI_SIG_ECDT, ACPI_SIG_EINJ,
+       ACPI_SIG_ERST, ACPI_SIG_HEST, ACPI_SIG_MADT, ACPI_SIG_MSCT,
+       ACPI_SIG_SBST, ACPI_SIG_SLIT, ACPI_SIG_SRAT, ACPI_SIG_ASF,
+       ACPI_SIG_BOOT, ACPI_SIG_DBGP, ACPI_SIG_DMAR, ACPI_SIG_HPET,
+       ACPI_SIG_IBFT, ACPI_SIG_IVRS, ACPI_SIG_MCFG, ACPI_SIG_MCHI,
+       ACPI_SIG_SLIC, ACPI_SIG_SPCR, ACPI_SIG_SPMI, ACPI_SIG_TCPA,
+       ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT, ACPI_SIG_WDDT,
+       ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT,
+       ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, NULL };
+
+#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header)
+
+#define NR_ACPI_INITRD_TABLES 64
+static struct cpio_data __initdata acpi_initrd_files[NR_ACPI_INITRD_TABLES];
+static DECLARE_BITMAP(acpi_initrd_installed, NR_ACPI_INITRD_TABLES);
+
+#define MAP_CHUNK_SIZE   (NR_FIX_BTMAPS << PAGE_SHIFT)
+
+static void __init acpi_table_initrd_init(void *data, size_t size)
+{
+       int sig, no, table_nr = 0, total_offset = 0;
+       long offset = 0;
+       struct acpi_table_header *table;
+       char cpio_path[32] = "kernel/firmware/acpi/";
+       struct cpio_data file;
+
+       if (data == NULL || size == 0)
+               return;
+
+       for (no = 0; no < NR_ACPI_INITRD_TABLES; no++) {
+               file = find_cpio_data(cpio_path, data, size, &offset);
+               if (!file.data)
+                       break;
+
+               data += offset;
+               size -= offset;
+
+               if (file.size < sizeof(struct acpi_table_header)) {
+                       pr_err("ACPI OVERRIDE: Table smaller than ACPI header [%s%s]\n",
+                               cpio_path, file.name);
+                       continue;
+               }
+
+               table = file.data;
+
+               for (sig = 0; table_sigs[sig]; sig++)
+                       if (!memcmp(table->signature, table_sigs[sig], 4))
+                               break;
+
+               if (!table_sigs[sig]) {
+                       pr_err("ACPI OVERRIDE: Unknown signature [%s%s]\n",
+                               cpio_path, file.name);
+                       continue;
+               }
+               if (file.size != table->length) {
+                       pr_err("ACPI OVERRIDE: File length does not match table length [%s%s]\n",
+                               cpio_path, file.name);
+                       continue;
+               }
+               if (acpi_table_checksum(file.data, table->length)) {
+                       pr_err("ACPI OVERRIDE: Bad table checksum [%s%s]\n",
+                               cpio_path, file.name);
+                       continue;
+               }
+
+               pr_info("%4.4s ACPI table found in initrd [%s%s][0x%x]\n",
+                       table->signature, cpio_path, file.name, table->length);
+
+               all_tables_size += table->length;
+               acpi_initrd_files[table_nr].data = file.data;
+               acpi_initrd_files[table_nr].size = file.size;
+               table_nr++;
+       }
+       if (table_nr == 0)
+               return;
+
+       acpi_tables_addr =
+               memblock_find_in_range(0, max_low_pfn_mapped << PAGE_SHIFT,
+                                      all_tables_size, PAGE_SIZE);
+       if (!acpi_tables_addr) {
+               WARN_ON(1);
+               return;
+       }
+       /*
+        * Only calling e820_add_reserve does not work and the
+        * tables are invalid (memory got used) later.
+        * memblock_reserve works as expected and the tables won't get modified.
+        * But it's not enough on X86 because ioremap will
+        * complain later (used by acpi_os_map_memory) that the pages
+        * that should get mapped are not marked "reserved".
+        * Both memblock_reserve and e820_add_region (via arch_reserve_mem_area)
+        * works fine.
+        */
+       memblock_reserve(acpi_tables_addr, all_tables_size);
+       arch_reserve_mem_area(acpi_tables_addr, all_tables_size);
+
+       /*
+        * early_ioremap only can remap 256k one time. If we map all
+        * tables one time, we will hit the limit. Need to map chunks
+        * one by one during copying the same as that in relocate_initrd().
+        */
+       for (no = 0; no < table_nr; no++) {
+               unsigned char *src_p = acpi_initrd_files[no].data;
+               phys_addr_t size = acpi_initrd_files[no].size;
+               phys_addr_t dest_addr = acpi_tables_addr + total_offset;
+               phys_addr_t slop, clen;
+               char *dest_p;
+
+               total_offset += size;
+
+               while (size) {
+                       slop = dest_addr & ~PAGE_MASK;
+                       clen = size;
+                       if (clen > MAP_CHUNK_SIZE - slop)
+                               clen = MAP_CHUNK_SIZE - slop;
+                       dest_p = early_ioremap(dest_addr & PAGE_MASK,
+                                                clen + slop);
+                       memcpy(dest_p + slop, src_p, clen);
+                       early_iounmap(dest_p, clen + slop);
+                       src_p += clen;
+                       dest_addr += clen;
+                       size -= clen;
+               }
+       }
+}
+
+static acpi_status
+acpi_table_initrd_override(struct acpi_table_header *existing_table,
+                          acpi_physical_address *address, u32 *length)
+{
+       int table_offset = 0;
+       int table_index = 0;
+       struct acpi_table_header *table;
+       u32 table_length;
+
+       *length = 0;
+       *address = 0;
+       if (!acpi_tables_addr)
+               return AE_OK;
+
+       while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) {
+               table = acpi_os_map_memory(acpi_tables_addr + table_offset,
+                                          ACPI_HEADER_SIZE);
+               if (table_offset + table->length > all_tables_size) {
+                       acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
+                       WARN_ON(1);
+                       return AE_OK;
+               }
+
+               table_length = table->length;
+
+               /* Only override tables matched */
+               if (memcmp(existing_table->signature, table->signature, 4) ||
+                   memcmp(table->oem_id, existing_table->oem_id,
+                          ACPI_OEM_ID_SIZE) ||
+                   memcmp(table->oem_table_id, existing_table->oem_table_id,
+                          ACPI_OEM_TABLE_ID_SIZE)) {
+                       acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
+                       goto next_table;
+               }
+               /*
+                * Mark the table to avoid being used in
+                * acpi_table_initrd_scan() and check the revision.
+                */
+               if (test_and_set_bit(table_index, acpi_initrd_installed) ||
+                   existing_table->oem_revision >= table->oem_revision) {
+                       acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
+                       goto next_table;
+               }
+
+               *length = table_length;
+               *address = acpi_tables_addr + table_offset;
+               pr_info("Table Upgrade: override [%4.4s-%6.6s-%8.8s]\n",
+                       table->signature, table->oem_id,
+                       table->oem_table_id);
+               acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
+               break;
+
+next_table:
+               table_offset += table_length;
+               table_index++;
+       }
+       return AE_OK;
+}
+
+static void __init acpi_table_initrd_scan(void)
+{
+       int table_offset = 0;
+       int table_index = 0;
+       u32 table_length;
+       struct acpi_table_header *table;
+
+       if (!acpi_tables_addr)
+               return;
+
+       while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) {
+               table = acpi_os_map_memory(acpi_tables_addr + table_offset,
+                                          ACPI_HEADER_SIZE);
+               if (table_offset + table->length > all_tables_size) {
+                       acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
+                       WARN_ON(1);
+                       return;
+               }
+
+               table_length = table->length;
+
+               /* Skip RSDT/XSDT which should only be used for override */
+               if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_RSDT) ||
+                   ACPI_COMPARE_NAME(table->signature, ACPI_SIG_XSDT)) {
+                       acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
+                       goto next_table;
+               }
+               /*
+                * Mark the table to avoid being used in
+                * acpi_table_initrd_override(). Though this is not possible
+                * because override is disabled in acpi_install_table().
+                */
+               if (test_and_set_bit(table_index, acpi_initrd_installed)) {
+                       acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
+                       goto next_table;
+               }
+
+               pr_info("Table Upgrade: install [%4.4s-%6.6s-%8.8s]\n",
+                       table->signature, table->oem_id,
+                       table->oem_table_id);
+               acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
+               acpi_install_table(acpi_tables_addr + table_offset, TRUE);
+next_table:
+               table_offset += table_length;
+               table_index++;
+       }
+}
+#else
+static void __init acpi_table_initrd_init(void *data, size_t size)
+{
+}
+
+static acpi_status
+acpi_table_initrd_override(struct acpi_table_header *existing_table,
+                          acpi_physical_address *address,
+                          u32 *table_length)
+{
+       *table_length = 0;
+       *address = 0;
+       return AE_OK;
+}
+
+static void __init acpi_table_initrd_scan(void)
+{
+}
+#endif /* CONFIG_ACPI_TABLE_UPGRADE */
+
+acpi_status
+acpi_os_physical_table_override(struct acpi_table_header *existing_table,
+                               acpi_physical_address *address,
+                               u32 *table_length)
+{
+       return acpi_table_initrd_override(existing_table, address,
+                                         table_length);
+}
+
+acpi_status
+acpi_os_table_override(struct acpi_table_header *existing_table,
+                      struct acpi_table_header **new_table)
+{
+       if (!existing_table || !new_table)
+               return AE_BAD_PARAMETER;
+
+       *new_table = NULL;
+
+#ifdef CONFIG_ACPI_CUSTOM_DSDT
+       if (strncmp(existing_table->signature, "DSDT", 4) == 0)
+               *new_table = (struct acpi_table_header *)AmlCode;
+#endif
+       if (*new_table != NULL)
+               acpi_table_taint(existing_table);
+       return AE_OK;
+}
+
+void __init early_acpi_table_init(void *data, size_t size)
+{
+       acpi_table_initrd_init(data, size);
+}
+
 /*
  * acpi_table_init()
  *
@@ -457,7 +771,7 @@ int __init acpi_table_init(void)
        status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
        if (ACPI_FAILURE(status))
                return -EINVAL;
-       acpi_initrd_initialize_tables();
+       acpi_table_initrd_scan();
 
        check_multiple_madt();
        return 0;
index 4d2e67f633b60e088d0ccc04554f6784c482a52e..b25690bceab63411386eaa449e70a7fae5485618 100644 (file)
@@ -190,14 +190,6 @@ static inline int acpi_debugger_notify_command_complete(void)
 }
 #endif
 
-#ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
-void acpi_initrd_override(void *data, size_t size);
-#else
-static inline void acpi_initrd_override(void *data, size_t size)
-{
-}
-#endif
-
 #define BAD_MADT_ENTRY(entry, end) (                                       \
                (!entry) || (unsigned long)entry + sizeof(*entry) > end ||  \
                ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
@@ -216,6 +208,7 @@ void acpi_boot_table_init (void);
 int acpi_mps_check (void);
 int acpi_numa_init (void);
 
+void early_acpi_table_init(void *data, size_t size);
 int acpi_table_init (void);
 int acpi_table_parse(char *id, acpi_tbl_table_handler handler);
 int __init acpi_parse_entries(char *id, unsigned long table_size,
@@ -360,7 +353,6 @@ extern bool wmi_has_guid(const char *guid);
 extern char acpi_video_backlight_string[];
 extern long acpi_is_video_device(acpi_handle handle);
 extern int acpi_blacklisted(void);
-extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d);
 extern void acpi_osi_setup(char *str);
 extern bool acpi_osi_is_win8(void);
 
@@ -597,6 +589,7 @@ static inline const char *acpi_dev_name(struct acpi_device *adev)
        return NULL;
 }
 
+static inline void early_acpi_table_init(void *data, size_t size) { }
 static inline void acpi_early_init(void) { }
 static inline void acpi_subsystem_init(void) { }