Skip to content

Commit 10a08fd

Browse files
committed
ACPI: PM: Set up EC GPE for system wakeup from drivers that need it
The EC GPE needs to be set up for system wakeup only if there is a driver depending on it, either intel-hid or intel-vbtn, bound to a button device that is expected to wake up the system from sleep (such as the power button on some Dell systems, like the XPS13 9360). It doesn't need to be set up for waking up the system from sleep in any other cases and whether or not it is expected to wake up the system from sleep doesn't depend on whether or not the LPS0 device is present in the ACPI namespace. For this reason, rearrange the ACPI suspend-to-idle code to make the drivers depending on the EC GPE wakeup take care of setting it up and decouple that from the LPS0 device handling. While at it, make intel-hid and intel-vbtn prepare for system wakeup only if they are allowed to wake up the system from sleep by user space (via sysfs). [Note that acpi_ec_mark_gpe_for_wake() and acpi_ec_set_gpe_wake_mask() are there to prevent the EC GPE from being disabled by the acpi_enable_all_wakeup_gpes() call in acpi_s2idle_prepare(), so on systems with either intel-hid or intel-vbtn this change doesn't affect any interactions with the hardware or platform firmware.] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
1 parent b605c44 commit 10a08fd

File tree

7 files changed

+45
-22
lines changed

7 files changed

+45
-22
lines changed

drivers/acpi/ec.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <linux/list.h>
2626
#include <linux/spinlock.h>
2727
#include <linux/slab.h>
28+
#include <linux/suspend.h>
2829
#include <linux/acpi.h>
2930
#include <linux/dmi.h>
3031
#include <asm/io.h>
@@ -1048,17 +1049,21 @@ void acpi_ec_unblock_transactions(void)
10481049
acpi_ec_start(first_ec, true);
10491050
}
10501051

1052+
#ifdef CONFIG_PM_SLEEP
10511053
void acpi_ec_mark_gpe_for_wake(void)
10521054
{
10531055
if (first_ec && !ec_no_wakeup)
10541056
acpi_mark_gpe_for_wake(NULL, first_ec->gpe);
10551057
}
1058+
EXPORT_SYMBOL_GPL(acpi_ec_mark_gpe_for_wake);
10561059

10571060
void acpi_ec_set_gpe_wake_mask(u8 action)
10581061
{
1059-
if (first_ec && !ec_no_wakeup)
1062+
if (pm_suspend_no_platform() && first_ec && !ec_no_wakeup)
10601063
acpi_set_gpe_wake_mask(NULL, first_ec->gpe, action);
10611064
}
1065+
EXPORT_SYMBOL_GPL(acpi_ec_set_gpe_wake_mask);
1066+
#endif
10621067

10631068
bool acpi_ec_dispatch_gpe(void)
10641069
{

drivers/acpi/internal.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,6 @@ void acpi_ec_ecdt_probe(void);
194194
void acpi_ec_dsdt_probe(void);
195195
void acpi_ec_block_transactions(void);
196196
void acpi_ec_unblock_transactions(void);
197-
void acpi_ec_mark_gpe_for_wake(void);
198-
void acpi_ec_set_gpe_wake_mask(u8 action);
199197
bool acpi_ec_dispatch_gpe(void);
200198
int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
201199
acpi_handle handle, acpi_ec_query_func func,

drivers/acpi/sleep.c

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -930,8 +930,6 @@ static int lps0_device_attach(struct acpi_device *adev,
930930

931931
acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n",
932932
bitmask);
933-
934-
acpi_ec_mark_gpe_for_wake();
935933
} else {
936934
acpi_handle_debug(adev->handle,
937935
"_DSM function 0 evaluation failed\n");
@@ -960,8 +958,6 @@ static int acpi_s2idle_prepare(void)
960958
if (lps0_device_handle) {
961959
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF);
962960
acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY);
963-
964-
acpi_ec_set_gpe_wake_mask(ACPI_GPE_ENABLE);
965961
}
966962

967963
if (acpi_sci_irq_valid())
@@ -979,10 +975,7 @@ static int acpi_s2idle_prepare(void)
979975

980976
static void acpi_s2idle_wake(void)
981977
{
982-
if (!lps0_device_handle)
983-
return;
984-
985-
if (pm_debug_messages_on)
978+
if (lps0_device_handle && pm_debug_messages_on)
986979
lpi_check_constraints();
987980

988981
/*
@@ -1031,8 +1024,6 @@ static void acpi_s2idle_restore(void)
10311024
disable_irq_wake(acpi_sci_irq);
10321025

10331026
if (lps0_device_handle) {
1034-
acpi_ec_set_gpe_wake_mask(ACPI_GPE_DISABLE);
1035-
10361027
acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT);
10371028
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON);
10381029
}
@@ -1081,7 +1072,7 @@ bool acpi_s2idle_wakeup(void)
10811072

10821073
bool acpi_sleep_no_ec_events(void)
10831074
{
1084-
return !s2idle_in_progress || !lps0_device_handle;
1075+
return !s2idle_in_progress;
10851076
}
10861077

10871078
#ifdef CONFIG_PM_SLEEP

drivers/platform/x86/intel-hid.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,12 @@ static void intel_button_array_enable(struct device *device, bool enable)
253253

254254
static int intel_hid_pm_prepare(struct device *device)
255255
{
256-
struct intel_hid_priv *priv = dev_get_drvdata(device);
256+
if (device_may_wakeup(device)) {
257+
struct intel_hid_priv *priv = dev_get_drvdata(device);
257258

258-
priv->wakeup_mode = true;
259+
priv->wakeup_mode = true;
260+
acpi_ec_set_gpe_wake_mask(ACPI_GPE_ENABLE);
261+
}
259262
return 0;
260263
}
261264

@@ -270,9 +273,12 @@ static int intel_hid_pl_suspend_handler(struct device *device)
270273

271274
static int intel_hid_pl_resume_handler(struct device *device)
272275
{
273-
struct intel_hid_priv *priv = dev_get_drvdata(device);
276+
if (device_may_wakeup(device)) {
277+
struct intel_hid_priv *priv = dev_get_drvdata(device);
274278

275-
priv->wakeup_mode = false;
279+
acpi_ec_set_gpe_wake_mask(ACPI_GPE_DISABLE);
280+
priv->wakeup_mode = false;
281+
}
276282
if (pm_resume_via_firmware()) {
277283
intel_hid_set_enable(device, true);
278284
intel_button_array_enable(device, true);
@@ -491,6 +497,12 @@ static int intel_hid_probe(struct platform_device *device)
491497
}
492498

493499
device_init_wakeup(&device->dev, true);
500+
/*
501+
* In order for system wakeup to work, the EC GPE has to be marked as
502+
* a wakeup one, so do that here (this setting will persist, but it has
503+
* no effect until the wakeup mask is set for the EC GPE).
504+
*/
505+
acpi_ec_mark_gpe_for_wake();
494506
return 0;
495507

496508
err_remove_notify:

drivers/platform/x86/intel-vbtn.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,12 @@ static int intel_vbtn_probe(struct platform_device *device)
176176
return -EBUSY;
177177

178178
device_init_wakeup(&device->dev, true);
179+
/*
180+
* In order for system wakeup to work, the EC GPE has to be marked as
181+
* a wakeup one, so do that here (this setting will persist, but it has
182+
* no effect until the wakeup mask is set for the EC GPE).
183+
*/
184+
acpi_ec_mark_gpe_for_wake();
179185
return 0;
180186
}
181187

@@ -195,17 +201,23 @@ static int intel_vbtn_remove(struct platform_device *device)
195201

196202
static int intel_vbtn_pm_prepare(struct device *dev)
197203
{
198-
struct intel_vbtn_priv *priv = dev_get_drvdata(dev);
204+
if (device_may_wakeup(dev)) {
205+
struct intel_vbtn_priv *priv = dev_get_drvdata(dev);
199206

200-
priv->wakeup_mode = true;
207+
priv->wakeup_mode = true;
208+
acpi_ec_set_gpe_wake_mask(ACPI_GPE_ENABLE);
209+
}
201210
return 0;
202211
}
203212

204213
static int intel_vbtn_pm_resume(struct device *dev)
205214
{
206-
struct intel_vbtn_priv *priv = dev_get_drvdata(dev);
215+
if (device_may_wakeup(dev)) {
216+
struct intel_vbtn_priv *priv = dev_get_drvdata(dev);
207217

208-
priv->wakeup_mode = false;
218+
acpi_ec_set_gpe_wake_mask(ACPI_GPE_DISABLE);
219+
priv->wakeup_mode = false;
220+
}
209221
return 0;
210222
}
211223

include/linux/acpi.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,8 @@ int acpi_subsys_suspend_noirq(struct device *dev);
931931
int acpi_subsys_suspend(struct device *dev);
932932
int acpi_subsys_freeze(struct device *dev);
933933
int acpi_subsys_poweroff(struct device *dev);
934+
void acpi_ec_mark_gpe_for_wake(void);
935+
void acpi_ec_set_gpe_wake_mask(u8 action);
934936
#else
935937
static inline int acpi_subsys_prepare(struct device *dev) { return 0; }
936938
static inline void acpi_subsys_complete(struct device *dev) {}
@@ -939,6 +941,8 @@ static inline int acpi_subsys_suspend_noirq(struct device *dev) { return 0; }
939941
static inline int acpi_subsys_suspend(struct device *dev) { return 0; }
940942
static inline int acpi_subsys_freeze(struct device *dev) { return 0; }
941943
static inline int acpi_subsys_poweroff(struct device *dev) { return 0; }
944+
static inline void acpi_ec_mark_gpe_for_wake(void) {}
945+
static inline void acpi_ec_set_gpe_wake_mask(u8 action) {}
942946
#endif
943947

944948
#ifdef CONFIG_ACPI

include/linux/suspend.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ static inline void pm_set_suspend_via_firmware(void) {}
335335
static inline void pm_set_resume_via_firmware(void) {}
336336
static inline bool pm_suspend_via_firmware(void) { return false; }
337337
static inline bool pm_resume_via_firmware(void) { return false; }
338+
static inline bool pm_suspend_no_platform(void) { return false; }
338339
static inline bool pm_suspend_default_s2idle(void) { return false; }
339340

340341
static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {}

0 commit comments

Comments
 (0)