Blob Blame History Raw
From 76380636280b46541a9d2fe5aac497475bfbcde8 Mon Sep 17 00:00:00 2001
From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
Date: Wed, 19 Jul 2017 14:41:58 +0200
Subject: [PATCH] ACPI / EC: Add parameter to force disable the GPE on suspend
Git-commit: 76380636280b46541a9d2fe5aac497475bfbcde8
Patch-mainline: v4.13-rc3
References: bsc#1051510

After commit 8110dd281e15 (ACPI / sleep: EC-based wakeup from
suspend-to-idle on recent systems) the configuration of GPEs,
including the EC one, is not changed during suspend-to-idle on
recent systems.  That's in order to make system wakeup events
generated by the EC work, in particular.

However, on some of the systems in question (for example on Dell
XPS13 9365), in addition to generating system wakeup events the
EC generates a heartbeat sequence of interrupts that have nothing
to do with wakeup while suspended, and the Low Power Idle S0 _DSM
interface doesn't change that behavior.

The users of those systems may prefer to disable the EC GPE during
system suspend, for the cost of non-functional power button wakeup
or similar, but currently there is no way to do that.

For this reason, add a new module parameter, ec_no_wakeup, for the
EC driver module that, if set, will cause the EC GPE to be disabled
during system suspend and re-enabled during the subsequent system
resume.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=192591#c106
Amends: 8110dd281e15 (ACPI / sleep: EC-based wakeup from suspend-to-idle on recent systems)
Reported-and-tested-by: Patrik Kullman <patrik.kullman@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Takashi Iwai <tiwai@suse.de>

---
 drivers/acpi/ec.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 20d9e9f0e231..8ab4df64b8be 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -151,6 +151,10 @@ static bool ec_freeze_events __read_mostly = false;
 module_param(ec_freeze_events, bool, 0644);
 MODULE_PARM_DESC(ec_freeze_events, "Disabling event handling during suspend/resume");
 
+static bool ec_no_wakeup __read_mostly;
+module_param(ec_no_wakeup, bool, 0644);
+MODULE_PARM_DESC(ec_no_wakeup, "Do not wake up from suspend-to-idle");
+
 struct acpi_ec_query_handler {
 	struct list_head node;
 	acpi_ec_query_func func;
@@ -1880,6 +1884,32 @@ static int acpi_ec_suspend(struct device *dev)
 	return 0;
 }
 
+static int acpi_ec_suspend_noirq(struct device *dev)
+{
+	struct acpi_ec *ec = acpi_driver_data(to_acpi_device(dev));
+
+	/*
+	 * The SCI handler doesn't run at this point, so the GPE can be
+	 * masked at the low level without side effects.
+	 */
+	if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) &&
+	    ec->reference_count >= 1)
+		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
+
+	return 0;
+}
+
+static int acpi_ec_resume_noirq(struct device *dev)
+{
+	struct acpi_ec *ec = acpi_driver_data(to_acpi_device(dev));
+
+	if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) &&
+	    ec->reference_count >= 1)
+		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
+
+	return 0;
+}
+
 static int acpi_ec_resume(struct device *dev)
 {
 	struct acpi_ec *ec =
@@ -1891,6 +1921,7 @@ static int acpi_ec_resume(struct device *dev)
 #endif
 
 static const struct dev_pm_ops acpi_ec_pm = {
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend_noirq, acpi_ec_resume_noirq)
 	SET_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend, acpi_ec_resume)
 };
 
-- 
2.18.0