ACPI: EC: Fix regression related to wrong ECDT initialization order
authorLv Zheng <lv.zheng@intel.com>
Wed, 16 Aug 2017 07:29:49 +0000 (15:29 +0800)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 17 Aug 2017 18:52:19 +0000 (20:52 +0200)
Commit 2a5708409e4e (ACPI / EC: Fix a gap that ECDT EC cannot handle
EC events) introduced acpi_ec_ecdt_start(), but that function is
invoked before acpi_ec_query_init(), which is too early.  This causes
the kernel to crash if an EC event occurs after boot, when ec_query_wq
is not valid:

 BUG: unable to handle kernel NULL pointer dereference at 0000000000000102
 ...
 Workqueue: events acpi_ec_event_handler
 task: ffff9f539790dac0 task.stack: ffffb437c0e10000
 RIP: 0010:__queue_work+0x32/0x430

Normally, the DSDT EC should always be valid, so acpi_ec_ecdt_start()
is actually a no-op in the majority of cases.  However, commit
c712bb58d827 (ACPI / EC: Add support to skip boot stage DSDT probe)
caused the probing of the DSDT EC as the "boot EC" to be skipped when
the ECDT EC is valid and uncovered the bug.

Fix this issue by invoking acpi_ec_ecdt_start() after acpi_ec_query_init()
in acpi_ec_init().

Link: https://jira01.devtools.intel.com/browse/LCK-4348
Fixes: 2a5708409e4e (ACPI / EC: Fix a gap that ECDT EC cannot handle EC events)
Fixes: c712bb58d827 (ACPI / EC: Add support to skip boot stage DSDT probe)
Reported-by: Wang Wendy <wendy.wang@intel.com>
Tested-by: Feng Chenzhou <chenzhoux.feng@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
[ rjw: Changelog ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/ec.c
drivers/acpi/internal.h
drivers/acpi/scan.c

index 62068a5e814f026a44e212bd2b93941590a3fe53..ae3d6d15263307c2c159fd459d09bc93ef66fa03 100644 (file)
@@ -1741,7 +1741,7 @@ error:
  * functioning ECDT EC first in order to handle the events.
  * https://bugzilla.kernel.org/show_bug.cgi?id=115021
  */
-int __init acpi_ec_ecdt_start(void)
+static int __init acpi_ec_ecdt_start(void)
 {
        acpi_handle handle;
 
@@ -2003,20 +2003,17 @@ static inline void acpi_ec_query_exit(void)
 int __init acpi_ec_init(void)
 {
        int result;
+       int ecdt_fail, dsdt_fail;
 
        /* register workqueue for _Qxx evaluations */
        result = acpi_ec_query_init();
        if (result)
-               goto err_exit;
-       /* Now register the driver for the EC */
-       result = acpi_bus_register_driver(&acpi_ec_driver);
-       if (result)
-               goto err_exit;
+               return result;
 
-err_exit:
-       if (result)
-               acpi_ec_query_exit();
-       return result;
+       /* Drivers must be started after acpi_ec_query_init() */
+       ecdt_fail = acpi_ec_ecdt_start();
+       dsdt_fail = acpi_bus_register_driver(&acpi_ec_driver);
+       return ecdt_fail && dsdt_fail ? -ENODEV : 0;
 }
 
 /* EC driver currently not unloadable */
index 58dd7ab3c6538bd490b45e2e420c3d822ecf8c3e..3f5af4d7a73989f86cdcc80c1e8e7b949a975702 100644 (file)
@@ -185,7 +185,6 @@ typedef int (*acpi_ec_query_func) (void *data);
 int acpi_ec_init(void);
 int acpi_ec_ecdt_probe(void);
 int acpi_ec_dsdt_probe(void);
-int acpi_ec_ecdt_start(void);
 void acpi_ec_block_transactions(void);
 void acpi_ec_unblock_transactions(void);
 int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
index 33897298f03e3ed680272ba6f4109077d434a0d8..70fd5502c2843a7cb0338245767a3c7dc2aeb308 100644 (file)
@@ -2084,7 +2084,6 @@ int __init acpi_scan_init(void)
 
        acpi_gpe_apply_masked_gpes();
        acpi_update_all_gpes();
-       acpi_ec_ecdt_start();
 
        acpi_scan_initialized = true;