From 880a66275ef4d1e08e5d4dcf4cec768de18c68ef Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 20 Jul 2017 03:43:12 +0200 Subject: ACPI / PM / EC: Flush all EC work in acpi_freeze_sync() Commit eed4d47efe95 (ACPI / sleep: Ignore spurious SCI wakeups from suspend-to-idle) introduced acpi_freeze_sync() whose purpose is to flush all of the processing of possible wakeup events signaled via the ACPI SCI. However, it doesn't flush the query workqueue used by the EC driver, so the events generated by the EC may not be processed timely which leads to issues (increased overhead at least, lost events possibly). To fix that introduce acpi_ec_flush_work() that will flush all of the outstanding EC work and call it from acpi_freeze_sync(). Fixes: eed4d47efe95 (ACPI / sleep: Ignore spurious SCI wakeups from suspend-to-idle) Signed-off-by: Rafael J. Wysocki --- drivers/acpi/internal.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/acpi/internal.h') diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 9531d3276f65..58dd7ab3c653 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -193,6 +193,10 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, void *data); void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit); +#ifdef CONFIG_PM_SLEEP +void acpi_ec_flush_work(void); +#endif + /*-------------------------------------------------------------------------- Suspend/Resume -- cgit v1.2.3 From 98529b9272e06a7767034fb8a32e43cdecda240a Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 16 Aug 2017 15:29:49 +0800 Subject: ACPI: EC: Fix regression related to wrong ECDT initialization order 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 Tested-by: Feng Chenzhou Signed-off-by: Lv Zheng [ rjw: Changelog ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 17 +++++++---------- drivers/acpi/internal.h | 1 - drivers/acpi/scan.c | 1 - 3 files changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers/acpi/internal.h') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 62068a5e814f..ae3d6d152633 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -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 */ diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 58dd7ab3c653..3f5af4d7a739 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -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, diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 33897298f03e..70fd5502c284 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -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; -- cgit v1.2.3