summaryrefslogtreecommitdiff
path: root/drivers/acpi
diff options
context:
space:
mode:
authorLv Zheng <lv.zheng@intel.com>2016-04-11 10:13:33 +0800
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-04-18 23:59:09 +0200
commit5d8813271f8a7c86027afb2ef554f2a5a9ba7c15 (patch)
tree75e3ea3cafe1b4be9ce00a7352ce75ca0c9fb7a4 /drivers/acpi
parentaf06f8b7a102417e93dc57ee7affb9fedcf5d83f (diff)
ACPI / tables: Convert initrd table override to table upgrade mechanism
This patch converts the initrd table override mechanism to the table upgrade mechanism by restricting its usage to the tables released with compatibility and more recent revision. This use case has been encouraged by the ACPI specification: 1. OEMID: An OEM-supplied string that identifies the OEM. 2. OEM Table ID: An OEM-supplied string that the OEM uses to identify the particular data table. This field is particularly useful when defining a definition block to distinguish definition block functions. OEM assigns each dissimilar table a new OEM Table Id. 3. OEM Revision: An OEM-supplied revision number. Larger numbers are assumed to be newer revisions. For OEMs, good practices will ensure consistency when assigning OEMID and OEM Table ID fields in any table. The intent of these fields is to allow for a binary control system that support services can use. Because many support function can be automated, it is useful when a tool can programatically determine which table release is a compatible and more recent revision of a prior table on the same OEMID and OEM Table ID. The facility can now be used by the vendors to upgrade wrong tables for bug fixing purpose, thus lockdep disabling taint is not suitable for it and it should be a default 'y' option to implement the spec encouraged use case. Note that, by implementing table upgrade inside of ACPICA itself, it is possible to remove acpi_table_initrd_override() and tables can be upgraded by acpi_install_table() automatically. Though current ACPICA impelentation hasn't implemented this, this patched changes the table flag setting timing to allow this to be implemented in ACPICA without changing the code here. Documentation of initrd override mechanism is upgraded accordingly. Original-by: Octavian Purdila <octavian.purdila@intel.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/Kconfig8
-rw-r--r--drivers/acpi/tables.c48
2 files changed, 38 insertions, 18 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 82b96ee8624c..b225c4b9ba14 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -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
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 2e74dbf45dd4..08795fbde3fa 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -442,7 +442,7 @@ static void acpi_table_taint(struct acpi_table_header *table)
add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
}
-#ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
+#ifdef CONFIG_ACPI_TABLE_UPGRADE
static u64 acpi_tables_addr;
static int all_tables_size;
@@ -471,9 +471,9 @@ static const char * const table_sigs[] = {
#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 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)
@@ -488,7 +488,7 @@ static void __init acpi_table_initrd_init(void *data, size_t size)
if (data == NULL || size == 0)
return;
- for (no = 0; no < ACPI_OVERRIDE_TABLES; no++) {
+ for (no = 0; no < NR_ACPI_INITRD_TABLES; no++) {
file = find_cpio_data(cpio_path, data, size, &offset);
if (!file.data)
break;
@@ -611,19 +611,30 @@ acpi_table_initrd_override(struct acpi_table_header *existing_table,
table_length = table->length;
/* Only override tables matched */
- if (test_bit(table_index, acpi_initrd_installed) ||
- memcmp(existing_table->signature, table->signature, 4) ||
+ 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;
- acpi_table_taint(existing_table);
+ 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);
- set_bit(table_index, acpi_initrd_installed);
break;
next_table:
@@ -655,17 +666,26 @@ static void __init acpi_table_initrd_scan(void)
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) ||
+ 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;
+ }
- acpi_table_taint(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);
- set_bit(table_index, acpi_initrd_installed);
next_table:
table_offset += table_length;
table_index++;
@@ -689,7 +709,7 @@ acpi_table_initrd_override(struct acpi_table_header *existing_table,
static void __init acpi_table_initrd_scan(void)
{
}
-#endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */
+#endif /* CONFIG_ACPI_TABLE_UPGRADE */
acpi_status
acpi_os_physical_table_override(struct acpi_table_header *existing_table,