ACPI / init: Make it possible to override _REV
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 2 Jul 2015 23:06:00 +0000 (01:06 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 2 Jul 2015 23:06:00 +0000 (01:06 +0200)
The platform firmware on some systems expects Linux to return "5" as
the supported ACPI revision which makes it expose system configuration
information in a special way.

For example, based on what ACPI exports as the supported revision,
Dell XPS 13 (2015) configures its audio device to either work in HDA
mode or in I2S mode, where the former is supposed to be used on Linux
until the latter is fully supported (in the kernel as well as in user
space).

Since ACPI 6 mandates that _REV should return "2" if ACPI 2 or later
is supported by the OS, a subsequent change will make that happen, so
make it possible to override that on systems where "5" is expected to
be returned for Linux to work correctly one them (such as the Dell
machine mentioned above).

Original-by: Dominik Brodowski <linux@dominikbrodowski.net>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Documentation/kernel-parameters.txt
drivers/acpi/Kconfig
drivers/acpi/blacklist.c
drivers/acpi/internal.h
drivers/acpi/osl.c

index 61ab1628a057cc2c4d8b11d892d834f7e5f7773a..180102480fc06dc8b0c4d048d7f0cc75ac6c5702 100644 (file)
@@ -274,6 +274,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        acpi_os_name=   [HW,ACPI] Tell ACPI BIOS the name of the OS
                        Format: To spoof as Windows 98: ="Microsoft Windows"
 
+       acpi_rev_override [ACPI] Override the _REV object to return 5 (instead
+                       of 2 which is mandated by ACPI 6) as the supported ACPI
+                       specification revision (when using this switch, it may
+                       be necessary to carry out a cold reboot _twice_ in a
+                       row to make it take effect on the platform firmware).
+
        acpi_osi=       [HW,ACPI] Modify list of supported OS interface strings
                        acpi_osi="string1"      # add string1
                        acpi_osi="!string2"     # remove string2
index ab2cbb51c6aaccde0ec2f97af343383c6f360dff..2b652f1d4edb9279ba576cfde69262666fab5d58 100644 (file)
@@ -77,6 +77,26 @@ config ACPI_PROCFS_POWER
 
          Say N to delete power /proc/acpi/ directories that have moved to /sys/
 
+config ACPI_REV_OVERRIDE_POSSIBLE
+       bool "Allow supported ACPI revision to be overriden"
+       depends on X86
+       default y
+       help
+         The platform firmware on some systems expects Linux to return "5" as
+         the supported ACPI revision which makes it expose system configuration
+         information in a special way.
+
+         For example, based on what ACPI exports as the supported revision,
+         Dell XPS 13 (2015) configures its audio device to either work in HDA
+         mode or in I2S mode, where the former is supposed to be used on Linux
+         until the latter is fully supported (in the kernel as well as in user
+         space).
+
+         This option enables a DMI-based quirk for the above Dell machine (so
+         that HDA audio is exposed by the platform firmware to the kernel) and
+         makes it possible to force the kernel to return "5" as the supported
+         ACPI revision via the "acpi_rev_override" command line switch.
+
 config ACPI_EC_DEBUGFS
        tristate "EC read/write access through /sys/kernel/debug/ec"
        default n
index 1d1791935c318c71148a5da573effe51f9031a15..278dc4be992a49b7663223a5c6bf2215699f4c20 100644 (file)
@@ -162,6 +162,15 @@ static int __init dmi_disable_osi_win8(const struct dmi_system_id *d)
        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)
+{
+       printk(KERN_NOTICE PREFIX "DMI detected: %s (force ACPI _REV to 5)\n",
+              d->ident);
+       acpi_rev_override_setup(NULL);
+       return 0;
+}
+#endif
 
 static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
        {
@@ -325,6 +334,23 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
                     DMI_MATCH(DMI_PRODUCT_NAME, "1015PX"),
                },
        },
+
+#ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE
+       /*
+        * DELL XPS 13 (2015) switches sound between HDA and I2S
+        * depending on the ACPI _REV callback. If userspace supports
+        * I2S sufficiently (or if you do not care about sound), you
+        * can safely disable this quirk.
+        */
+       {
+        .callback = dmi_enable_rev_override,
+        .ident = "DELL XPS 13 (2015)",
+        .matches = {
+                     DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                     DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343"),
+               },
+       },
+#endif
        {}
 };
 
index ba4a61e964be4d1d2abdb59bfab85a25aa3048c4..42f3042888293cc3cc7f3c07994e6a18eb67d90c 100644 (file)
@@ -58,6 +58,7 @@ void acpi_cmos_rtc_init(void);
 #else
 static inline void acpi_cmos_rtc_init(void) {}
 #endif
+int acpi_rev_override_setup(char *str);
 
 extern bool acpi_force_hot_remove;
 
index 39748bb3a5430111b8cf4723462eb837137b0213..37e592798cd5212d76074fdac28ac7ac27181702 100644 (file)
@@ -537,6 +537,19 @@ acpi_os_get_physical_address(void *virt, acpi_physical_address * phys)
 }
 #endif
 
+#ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE
+static bool acpi_rev_override;
+
+int __init acpi_rev_override_setup(char *str)
+{
+       acpi_rev_override = true;
+       return 1;
+}
+__setup("acpi_rev_override", acpi_rev_override_setup);
+#else
+#define acpi_rev_override      false
+#endif
+
 #define ACPI_MAX_OVERRIDE_LEN 100
 
 static char acpi_os_name[ACPI_MAX_OVERRIDE_LEN];
@@ -555,6 +568,11 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
                *new_val = acpi_os_name;
        }
 
+       if (!memcmp(init_val->name, "_REV", 4) && acpi_rev_override) {
+               printk(KERN_INFO PREFIX "Overriding _REV return value to 5\n");
+               *new_val = (char *)5;
+       }
+
        return AE_OK;
 }