* [PATCH] ACPI: button: Report wakeup key only for power button wakeups
@ 2026-08-06 12:27 Baorui Liu
2026-08-07 14:12 ` Rafael J. Wysocki (Intel)
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Baorui Liu @ 2026-08-06 12:27 UTC (permalink / raw)
To: Rafael J . Wysocki
Cc: Len Brown, Mario Limonciello, linux-acpi, linux-kernel,
acpica-devel, Baorui Liu
Commit 16f70feaabe9 ("ACPI: button: trigger wakeup key events")
makes the ACPI power button driver report KEY_WAKEUP from its resume
callback. However, that callback is run whenever the ACPI button device
is resumed, regardless of the actual system wakeup source.
As a result, userspace may receive a KEY_WAKEUP event after resumes
caused by unrelated wakeup sources.
Avoid reporting the input event from acpi_button_resume(). Instead,
report it only when the ACPI fixed power button status indicates that
the power button was the wakeup source.
Fixes: 16f70feaabe9 ("ACPI: button: trigger wakeup key events")
Signed-off-by: Baorui Liu <baorliu@amd.com>
---
drivers/acpi/button.c | 23 +++++++++++++++--------
drivers/acpi/sleep.c | 21 +++++++++++++++++++++
drivers/acpi/sleep.h | 1 +
drivers/acpi/x86/s2idle.c | 4 +++-
include/acpi/button.h | 5 +++++
5 files changed, 45 insertions(+), 9 deletions(-)
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 3836ee75dd66..700510f6e5d0 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -480,6 +480,21 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
event, ++button->pushed);
}
+void acpi_power_button_wakeup(struct acpi_device *device)
+{
+ struct acpi_button *button = acpi_driver_data(device);
+ struct input_dev *input;
+
+ if (button->type == ACPI_BUTTON_TYPE_POWER) {
+ input = button->input;
+ input_report_key(input, KEY_WAKEUP, 1);
+ input_sync(input);
+ input_report_key(input, KEY_WAKEUP, 0);
+ input_sync(input);
+ }
+}
+EXPORT_SYMBOL(acpi_power_button_wakeup);
+
static void acpi_button_notify_run(void *data)
{
acpi_button_notify(NULL, ACPI_BUTTON_NOTIFY_STATUS, data);
@@ -503,7 +518,6 @@ static int acpi_button_suspend(struct device *dev)
static int acpi_button_resume(struct device *dev)
{
struct acpi_button *button = dev_get_drvdata(dev);
- struct input_dev *input;
button->suspended = false;
if (button->type == ACPI_BUTTON_TYPE_LID) {
@@ -512,13 +526,6 @@ static int acpi_button_resume(struct device *dev)
acpi_lid_initialize_state(button);
}
- if (button->type == ACPI_BUTTON_TYPE_POWER) {
- input = button->input;
- input_report_key(input, KEY_WAKEUP, 1);
- input_sync(input);
- input_report_key(input, KEY_WAKEUP, 0);
- input_sync(input);
- }
return 0;
}
#endif
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 132a9df98471..26bbecd0c166 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -22,6 +22,7 @@
#include <linux/syscore_ops.h>
#include <asm/io.h>
#include <trace/events/power.h>
+#include <acpi/button.h>
#include "internal.h"
#include "sleep.h"
@@ -518,6 +519,7 @@ static void acpi_pm_finish(void)
NULL, -1);
if (pwr_btn_adev) {
pm_wakeup_event(&pwr_btn_adev->dev, 0);
+ acpi_power_button_wakeup(pwr_btn_adev);
acpi_dev_put(pwr_btn_adev);
}
}
@@ -818,6 +820,24 @@ bool acpi_s2idle_wake(void)
return false;
}
+void acpi_s2idle_restore_check_powerkey(void)
+{
+ struct acpi_device *pwr_btn_adev;
+ acpi_event_status pwr_btn_status = ACPI_EVENT_FLAG_DISABLED;
+
+ acpi_get_event_status(ACPI_EVENT_POWER_BUTTON, &pwr_btn_status);
+
+ if (pwr_btn_status & ACPI_EVENT_FLAG_STATUS_SET) {
+ pwr_btn_adev = acpi_dev_get_first_match_dev(ACPI_BUTTON_HID_POWERF,
+ NULL, -1);
+ if (pwr_btn_adev) {
+ pm_wakeup_event(&pwr_btn_adev->dev, 0);
+ acpi_power_button_wakeup(pwr_btn_adev);
+ acpi_dev_put(pwr_btn_adev);
+ }
+ }
+}
+
void acpi_s2idle_restore(void)
{
/*
@@ -849,6 +869,7 @@ static const struct platform_s2idle_ops acpi_s2idle_ops = {
.begin = acpi_s2idle_begin,
.prepare = acpi_s2idle_prepare,
.wake = acpi_s2idle_wake,
+ .restore_early = acpi_s2idle_restore_check_powerkey,
.restore = acpi_s2idle_restore,
.end = acpi_s2idle_end,
};
diff --git a/drivers/acpi/sleep.h b/drivers/acpi/sleep.h
index 9c3cb109c5d2..50382c90446c 100644
--- a/drivers/acpi/sleep.h
+++ b/drivers/acpi/sleep.h
@@ -18,6 +18,7 @@ static inline acpi_status acpi_set_waking_vector(u32 wakeup_address)
extern int acpi_s2idle_begin(void);
extern int acpi_s2idle_prepare(void);
extern bool acpi_s2idle_wake(void);
+extern void acpi_s2idle_restore_check_powerkey(void);
extern void acpi_s2idle_restore(void);
extern void acpi_s2idle_end(void);
diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c
index b6b1dd76a06b..ce6663c1ef70 100644
--- a/drivers/acpi/x86/s2idle.c
+++ b/drivers/acpi/x86/s2idle.c
@@ -598,8 +598,10 @@ static void acpi_s2idle_restore_early_lps0(void)
{
struct acpi_s2idle_dev_ops *handler;
- if (!lps0_device_handle || sleep_no_lps0)
+ if (!lps0_device_handle || sleep_no_lps0) {
+ acpi_s2idle_restore_check_powerkey();
return;
+ }
list_for_each_entry(handler, &lps0_s2idle_devops_head, list_node)
if (handler->restore)
diff --git a/include/acpi/button.h b/include/acpi/button.h
index af2fce5d2ee3..3cbf3272371e 100644
--- a/include/acpi/button.h
+++ b/include/acpi/button.h
@@ -8,11 +8,16 @@
#if IS_ENABLED(CONFIG_ACPI_BUTTON)
extern int acpi_lid_open(void);
+extern void acpi_power_button_wakeup(struct acpi_device *device);
#else
static inline int acpi_lid_open(void)
{
return 1;
}
+
+static inline void acpi_power_button_wakeup(struct acpi_device *device)
+{
+}
#endif /* IS_ENABLED(CONFIG_ACPI_BUTTON) */
#endif /* ACPI_BUTTON_H */
base-commit: 4d823c9d06aaa91476b58e56e4d44c4112da2811
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH] ACPI: button: Report wakeup key only for power button wakeups 2026-08-06 12:27 [PATCH] ACPI: button: Report wakeup key only for power button wakeups Baorui Liu @ 2026-08-07 14:12 ` Rafael J. Wysocki (Intel) 2026-08-19 8:55 ` [PATCH v2 0/1] " Baorui.Liu 2026-08-20 7:07 ` [PATCH] " kernel test robot 2 siblings, 0 replies; 6+ messages in thread From: Rafael J. Wysocki (Intel) @ 2026-08-07 14:12 UTC (permalink / raw) To: Baorui Liu Cc: Rafael J . Wysocki, Len Brown, Mario Limonciello, linux-acpi, linux-kernel, acpica-devel On Thu, Aug 6, 2026 at 2:28 PM Baorui Liu <baorliu@amd.com> wrote: > > Commit 16f70feaabe9 ("ACPI: button: trigger wakeup key events") > makes the ACPI power button driver report KEY_WAKEUP from its resume > callback. However, that callback is run whenever the ACPI button device > is resumed, regardless of the actual system wakeup source. > > As a result, userspace may receive a KEY_WAKEUP event after resumes > caused by unrelated wakeup sources. So why is this a problem in practice? > Avoid reporting the input event from acpi_button_resume(). Instead, > report it only when the ACPI fixed power button status indicates that > the power button was the wakeup source. But power buttons need not be fixed event devices and there are also sleep buttons that can generate KEY_WAKEUP, and what about lids? > Fixes: 16f70feaabe9 ("ACPI: button: trigger wakeup key events") > Signed-off-by: Baorui Liu <baorliu@amd.com> > --- > drivers/acpi/button.c | 23 +++++++++++++++-------- > drivers/acpi/sleep.c | 21 +++++++++++++++++++++ > drivers/acpi/sleep.h | 1 + > drivers/acpi/x86/s2idle.c | 4 +++- > include/acpi/button.h | 5 +++++ > 5 files changed, 45 insertions(+), 9 deletions(-) > > diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c > index 3836ee75dd66..700510f6e5d0 100644 > --- a/drivers/acpi/button.c > +++ b/drivers/acpi/button.c > @@ -480,6 +480,21 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data) > event, ++button->pushed); > } > > +void acpi_power_button_wakeup(struct acpi_device *device) > +{ > + struct acpi_button *button = acpi_driver_data(device); > + struct input_dev *input; > + > + if (button->type == ACPI_BUTTON_TYPE_POWER) { > + input = button->input; > + input_report_key(input, KEY_WAKEUP, 1); > + input_sync(input); > + input_report_key(input, KEY_WAKEUP, 0); > + input_sync(input); > + } > +} > +EXPORT_SYMBOL(acpi_power_button_wakeup); > + > static void acpi_button_notify_run(void *data) > { > acpi_button_notify(NULL, ACPI_BUTTON_NOTIFY_STATUS, data); > @@ -503,7 +518,6 @@ static int acpi_button_suspend(struct device *dev) > static int acpi_button_resume(struct device *dev) > { > struct acpi_button *button = dev_get_drvdata(dev); > - struct input_dev *input; > > button->suspended = false; > if (button->type == ACPI_BUTTON_TYPE_LID) { > @@ -512,13 +526,6 @@ static int acpi_button_resume(struct device *dev) > acpi_lid_initialize_state(button); > } > > - if (button->type == ACPI_BUTTON_TYPE_POWER) { > - input = button->input; > - input_report_key(input, KEY_WAKEUP, 1); > - input_sync(input); > - input_report_key(input, KEY_WAKEUP, 0); > - input_sync(input); > - } > return 0; > } > #endif > diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c > index 132a9df98471..26bbecd0c166 100644 > --- a/drivers/acpi/sleep.c > +++ b/drivers/acpi/sleep.c > @@ -22,6 +22,7 @@ > #include <linux/syscore_ops.h> > #include <asm/io.h> > #include <trace/events/power.h> > +#include <acpi/button.h> > > #include "internal.h" > #include "sleep.h" > @@ -518,6 +519,7 @@ static void acpi_pm_finish(void) > NULL, -1); > if (pwr_btn_adev) { > pm_wakeup_event(&pwr_btn_adev->dev, 0); > + acpi_power_button_wakeup(pwr_btn_adev); > acpi_dev_put(pwr_btn_adev); > } > } > @@ -818,6 +820,24 @@ bool acpi_s2idle_wake(void) > return false; > } > > +void acpi_s2idle_restore_check_powerkey(void) > +{ > + struct acpi_device *pwr_btn_adev; > + acpi_event_status pwr_btn_status = ACPI_EVENT_FLAG_DISABLED; > + > + acpi_get_event_status(ACPI_EVENT_POWER_BUTTON, &pwr_btn_status); > + > + if (pwr_btn_status & ACPI_EVENT_FLAG_STATUS_SET) { > + pwr_btn_adev = acpi_dev_get_first_match_dev(ACPI_BUTTON_HID_POWERF, > + NULL, -1); > + if (pwr_btn_adev) { > + pm_wakeup_event(&pwr_btn_adev->dev, 0); > + acpi_power_button_wakeup(pwr_btn_adev); > + acpi_dev_put(pwr_btn_adev); > + } > + } > +} > + > void acpi_s2idle_restore(void) > { > /* > @@ -849,6 +869,7 @@ static const struct platform_s2idle_ops acpi_s2idle_ops = { > .begin = acpi_s2idle_begin, > .prepare = acpi_s2idle_prepare, > .wake = acpi_s2idle_wake, > + .restore_early = acpi_s2idle_restore_check_powerkey, > .restore = acpi_s2idle_restore, > .end = acpi_s2idle_end, > }; > diff --git a/drivers/acpi/sleep.h b/drivers/acpi/sleep.h > index 9c3cb109c5d2..50382c90446c 100644 > --- a/drivers/acpi/sleep.h > +++ b/drivers/acpi/sleep.h > @@ -18,6 +18,7 @@ static inline acpi_status acpi_set_waking_vector(u32 wakeup_address) > extern int acpi_s2idle_begin(void); > extern int acpi_s2idle_prepare(void); > extern bool acpi_s2idle_wake(void); > +extern void acpi_s2idle_restore_check_powerkey(void); > extern void acpi_s2idle_restore(void); > extern void acpi_s2idle_end(void); > > diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c > index b6b1dd76a06b..ce6663c1ef70 100644 > --- a/drivers/acpi/x86/s2idle.c > +++ b/drivers/acpi/x86/s2idle.c > @@ -598,8 +598,10 @@ static void acpi_s2idle_restore_early_lps0(void) > { > struct acpi_s2idle_dev_ops *handler; > > - if (!lps0_device_handle || sleep_no_lps0) > + if (!lps0_device_handle || sleep_no_lps0) { > + acpi_s2idle_restore_check_powerkey(); > return; > + } > > list_for_each_entry(handler, &lps0_s2idle_devops_head, list_node) > if (handler->restore) > diff --git a/include/acpi/button.h b/include/acpi/button.h > index af2fce5d2ee3..3cbf3272371e 100644 > --- a/include/acpi/button.h > +++ b/include/acpi/button.h > @@ -8,11 +8,16 @@ > > #if IS_ENABLED(CONFIG_ACPI_BUTTON) > extern int acpi_lid_open(void); > +extern void acpi_power_button_wakeup(struct acpi_device *device); > #else > static inline int acpi_lid_open(void) > { > return 1; > } > + > +static inline void acpi_power_button_wakeup(struct acpi_device *device) > +{ > +} > #endif /* IS_ENABLED(CONFIG_ACPI_BUTTON) */ > > #endif /* ACPI_BUTTON_H */ > > base-commit: 4d823c9d06aaa91476b58e56e4d44c4112da2811 > -- > 2.34.1 > ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 0/1] ACPI: button: Report wakeup key only for power button wakeups 2026-08-06 12:27 [PATCH] ACPI: button: Report wakeup key only for power button wakeups Baorui Liu 2026-08-07 14:12 ` Rafael J. Wysocki (Intel) @ 2026-08-19 8:55 ` Baorui.Liu 2026-08-19 8:55 ` [PATCH v2 1/1] " Baorui.Liu 2026-08-20 7:07 ` [PATCH] " kernel test robot 2 siblings, 1 reply; 6+ messages in thread From: Baorui.Liu @ 2026-08-19 8:55 UTC (permalink / raw) To: rafael Cc: lenb, robert.moore, linux-acpi, linux-kernel, acpica-devel, Baorui.Liu This v2 addresses the review feedback on v1 by documenting the practical impact and by avoiding KEY_WAKEUP reporting from generic ACPI sleep resume paths. Problem reproduced on an AMD Android 15 Xen guest. Input device mapping: event0: LNXPWRBN Power Button, KEY_POWER + KEY_WAKEUP event1: LNXSLPBN Sleep Button, KEY_SLEEP Runtime trigger mapping: xl trigger android power -> event0 KEY_POWER xl trigger android sleep -> event1 KEY_SLEEP without-fix kernel: 6.6.118-android15-14-maybe-dirty-gc3c82a22502d echo mem > /sys/power/state xl trigger android s3resume /dev/input/event0 reports KEY_WAKEUP DOWN/UP. with-fix v2 kernel: 6.6.118-android15-14-maybe-dirty-g5b231ece911d The same non-power-button S3 resume path no longer reports KEY_WAKEUP from /dev/input/event0. This was verified twice; both event0 logs are empty. The dmesg log confirms that the test path is S3 suspend/resume: PM: suspend entry (deep) ACPI: PM: Preparing to enter system sleep state S3 ACPI: PM: Waking up from system sleep state S3 Resume cause unknown PM: suspend exit A positive-control power-button S3 wake was attempted in the Xen guest: echo mem > /sys/power/state xl trigger android power The guest remained suspended/offline and was recovered with: xl trigger android s3resume Therefore, xl trigger android power is not a reliable S3 wake source in this Xen setup. That run is not used as positive-control power-button wake evidence; it only confirms runtime input-device mapping. Changes in v2: - Add test evidence showing the practical impact. - Track pending wakeup reporting in the ACPI button driver. - Report KEY_WAKEUP only if a power-button event/notify is observed while the ACPI button device is suspended. - Stop synthesizing Power Button KEY_WAKEUP events from generic ACPI sleep resume paths. ACPI: button: Report wakeup key only for power button wakeups drivers/acpi/button.c | 38 ++++++++++++++++------------- drivers/acpi/sleep.c | 56 +++---------------------------------------- include/acpi/button.h | 5 ---- 3 files changed, 24 insertions(+), 75 deletions(-) -- 2.34.1 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 1/1] ACPI: button: Report wakeup key only for power button wakeups 2026-08-19 8:55 ` [PATCH v2 0/1] " Baorui.Liu @ 2026-08-19 8:55 ` Baorui.Liu 2026-09-09 14:41 ` Rafael J. Wysocki (Intel) 0 siblings, 1 reply; 6+ messages in thread From: Baorui.Liu @ 2026-08-19 8:55 UTC (permalink / raw) To: rafael Cc: lenb, robert.moore, linux-acpi, linux-kernel, acpica-devel, Baorui.Liu The ACPI button driver reports KEY_WAKEUP from the Power Button input device to let userspace know that the system was resumed by a power button wakeup. However, reporting KEY_WAKEUP from generic system resume paths can make userspace observe a Power Button wakeup even when the system was resumed by a different wake source. This is reproducible on an AMD Android 15 Xen guest. With a kernel without this fix, a non-power-button S3 resume: echo mem > /sys/power/state xl trigger android s3resume makes the Power Button input device report KEY_WAKEUP. The same test on a kernel with this fix no longer reports KEY_WAKEUP from the Power Button input device. Track whether a power button event/notify is observed while the ACPI button device is suspended, and report KEY_WAKEUP on resume only in that case. Do not synthesize a Power Button input event from generic ACPI sleep resume code. Signed-off-by: Baorui.Liu <baorliu@amd.com> --- drivers/acpi/button.c | 38 ++++++++++++++++------------- drivers/acpi/sleep.c | 56 +++---------------------------------------- include/acpi/button.h | 5 ---- 3 files changed, 24 insertions(+), 75 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 8d2843bece29..f9b6b7fff5bd 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -175,6 +175,7 @@ struct acpi_button { int last_state; ktime_t last_time; bool suspended; + bool wakeup_pending; bool lid_state_initialized; }; @@ -452,6 +453,9 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data) acpi_pm_wakeup_event(&device->dev); button = acpi_driver_data(device); + if (button->type == ACPI_BUTTON_TYPE_POWER && button->suspended) + button->wakeup_pending = true; + if (button->suspended) return; @@ -468,23 +472,6 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data) event, ++button->pushed); } -void acpi_power_button_wakeup(struct acpi_device *device) -{ - struct acpi_button *button = acpi_driver_data(device); - struct input_dev *input; - - if (button->type == ACPI_BUTTON_TYPE_POWER) { - input = button->input; - input_report_key(input, KEY_WAKEUP, 1); - input_sync(input); - input_report_key(input, KEY_WAKEUP, 0); - input_sync(input); - } - - return; -} -EXPORT_SYMBOL(acpi_power_button_wakeup); - static void acpi_button_notify_run(void *data) { acpi_button_notify(NULL, ACPI_BUTTON_NOTIFY_STATUS, data); @@ -492,6 +479,12 @@ static void acpi_button_notify_run(void *data) static u32 acpi_button_event(void *data) { + struct acpi_device *device = data; + struct acpi_button *button = acpi_driver_data(device); + + if (button->type == ACPI_BUTTON_TYPE_POWER && button->suspended) + button->wakeup_pending = true; + acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_button_notify_run, data); return ACPI_INTERRUPT_HANDLED; } @@ -503,11 +496,13 @@ static int acpi_button_suspend(struct device *dev) struct acpi_button *button = acpi_driver_data(device); button->suspended = true; + button->wakeup_pending = false; return 0; } static int acpi_button_resume(struct device *dev) { + struct input_dev *input; struct acpi_device *device = to_acpi_device(dev); struct acpi_button *button = acpi_driver_data(device); @@ -518,6 +513,15 @@ static int acpi_button_resume(struct device *dev) acpi_lid_initialize_state(device); } + if (button->type == ACPI_BUTTON_TYPE_POWER && button->wakeup_pending) { + input = button->input; + input_report_key(input, KEY_WAKEUP, 1); + input_sync(input); + input_report_key(input, KEY_WAKEUP, 0); + input_sync(input); + button->wakeup_pending = false; + } + return 0; } #endif diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 0adfcd0fb55e..d655248c20d4 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -22,7 +22,6 @@ #include <linux/syscore_ops.h> #include <asm/io.h> #include <trace/events/power.h> -#include <acpi/button.h> #include "internal.h" #include "sleep.h" @@ -105,8 +104,6 @@ u32 acpi_target_system_state(void) } EXPORT_SYMBOL_GPL(acpi_target_system_state); -static bool pwr_btn_event_pending; - /* * The ACPI specification wants us to save NVS memory regions during hibernation * and to restore them during the subsequent resume. Windows does that also for @@ -463,7 +460,6 @@ static int acpi_pm_prepare(void) */ static void acpi_pm_finish(void) { - struct acpi_device *pwr_btn_adev; u32 acpi_state = acpi_target_sleep_state; acpi_ec_unblock_transactions(); @@ -482,24 +478,6 @@ static void acpi_pm_finish(void) acpi_target_sleep_state = ACPI_STATE_S0; acpi_resume_power_resources(); - - /* If we were woken with the fixed power button, provide a small - * hint to userspace in the form of a wakeup event on the fixed power - * button device (if it can be found). - * - * We delay the event generation til now, as the PM layer requires - * timekeeping to be running before we generate events. */ - if (!pwr_btn_event_pending) - return; - - pwr_btn_event_pending = false; - pwr_btn_adev = acpi_dev_get_first_match_dev(ACPI_BUTTON_HID_POWERF, - NULL, -1); - if (pwr_btn_adev) { - pm_wakeup_event(&pwr_btn_adev->dev, 0); - acpi_power_button_wakeup(pwr_btn_adev); - acpi_dev_put(pwr_btn_adev); - } } /** @@ -604,27 +582,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state) /* Reprogram control registers */ acpi_leave_sleep_state_prep(acpi_state); - /* ACPI 3.0 specs (P62) says that it's the responsibility - * of the OSPM to clear the status bit [ implying that the - * POWER_BUTTON event should not reach userspace ] - * - * However, we do generate a small hint for userspace in the form of - * a wakeup event. We flag this condition for now and generate the - * event later, as we're currently too early in resume to be able to - * generate wakeup events. - */ - if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) { - acpi_event_status pwr_btn_status = ACPI_EVENT_FLAG_DISABLED; - - acpi_get_event_status(ACPI_EVENT_POWER_BUTTON, &pwr_btn_status); - - if (pwr_btn_status & ACPI_EVENT_FLAG_STATUS_SET) { - acpi_clear_event(ACPI_EVENT_POWER_BUTTON); - /* Flag for later */ - pwr_btn_event_pending = true; - } - } - /* * Disable all GPE and clear their status bits before interrupts are * enabled. Some GPEs (like wakeup GPEs) have no handlers and this can @@ -797,19 +754,12 @@ bool acpi_s2idle_wake(void) void acpi_s2idle_restore_check_powerkey(void) { - struct acpi_device *pwr_btn_adev; acpi_event_status pwr_btn_status = ACPI_EVENT_FLAG_DISABLED; + acpi_get_event_status(ACPI_EVENT_POWER_BUTTON, &pwr_btn_status); - if (pwr_btn_status & ACPI_EVENT_FLAG_STATUS_SET) { - pwr_btn_adev = acpi_dev_get_first_match_dev(ACPI_BUTTON_HID_POWERF, - NULL, -1); - if (pwr_btn_adev) { - pm_wakeup_event(&pwr_btn_adev->dev, 0); - acpi_power_button_wakeup(pwr_btn_adev); - acpi_dev_put(pwr_btn_adev); - } - } + if (pwr_btn_status & ACPI_EVENT_FLAG_STATUS_SET) + acpi_clear_event(ACPI_EVENT_POWER_BUTTON); } void acpi_s2idle_restore(void) diff --git a/include/acpi/button.h b/include/acpi/button.h index be02d3ff2896..af2fce5d2ee3 100644 --- a/include/acpi/button.h +++ b/include/acpi/button.h @@ -8,16 +8,11 @@ #if IS_ENABLED(CONFIG_ACPI_BUTTON) extern int acpi_lid_open(void); -extern void acpi_power_button_wakeup(struct acpi_device *device); #else static inline int acpi_lid_open(void) { return 1; } -static inline void acpi_power_button_wakeup(struct acpi_device *device) -{ - return; -} #endif /* IS_ENABLED(CONFIG_ACPI_BUTTON) */ #endif /* ACPI_BUTTON_H */ -- 2.34.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/1] ACPI: button: Report wakeup key only for power button wakeups 2026-08-19 8:55 ` [PATCH v2 1/1] " Baorui.Liu @ 2026-09-09 14:41 ` Rafael J. Wysocki (Intel) 0 siblings, 0 replies; 6+ messages in thread From: Rafael J. Wysocki (Intel) @ 2026-09-09 14:41 UTC (permalink / raw) To: Baorui.Liu Cc: rafael, lenb, robert.moore, linux-acpi, linux-kernel, acpica-devel On Wed, Aug 19, 2026 at 10:56 AM Baorui.Liu <baorliu@amd.com> wrote: > > The ACPI button driver reports KEY_WAKEUP from the Power Button input > device to let userspace know that the system was resumed by a power > button wakeup. > > However, reporting KEY_WAKEUP from generic system resume paths can make > userspace observe a Power Button wakeup even when the system was resumed > by a different wake source. > > This is reproducible on an AMD Android 15 Xen guest. With a kernel > without this fix, a non-power-button S3 resume: > > echo mem > /sys/power/state > xl trigger android s3resume > > makes the Power Button input device report KEY_WAKEUP. The same test on > a kernel with this fix no longer reports KEY_WAKEUP from the Power Button > input device. > > Track whether a power button event/notify is observed while the ACPI > button device is suspended, and report KEY_WAKEUP on resume only in that > case. Do not synthesize a Power Button input event from generic ACPI > sleep resume code. > > Signed-off-by: Baorui.Liu <baorliu@amd.com> This doesn't apply on top of 7.3-rc2 for me, so please rebase and resend it. When you resend it, don't add a cover letter (cover letters are only needed for patch series, not for individual patches). If there is information in the cover letter that is not covered by the patch changelog, it can be copied there. Thanks! > --- > drivers/acpi/button.c | 38 ++++++++++++++++------------- > drivers/acpi/sleep.c | 56 +++---------------------------------------- > include/acpi/button.h | 5 ---- > 3 files changed, 24 insertions(+), 75 deletions(-) > > diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c > index 8d2843bece29..f9b6b7fff5bd 100644 > --- a/drivers/acpi/button.c > +++ b/drivers/acpi/button.c > @@ -175,6 +175,7 @@ struct acpi_button { > int last_state; > ktime_t last_time; > bool suspended; > + bool wakeup_pending; > bool lid_state_initialized; > }; > > @@ -452,6 +453,9 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data) > acpi_pm_wakeup_event(&device->dev); > > button = acpi_driver_data(device); > + if (button->type == ACPI_BUTTON_TYPE_POWER && button->suspended) > + button->wakeup_pending = true; > + > if (button->suspended) > return; > > @@ -468,23 +472,6 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data) > event, ++button->pushed); > } > > -void acpi_power_button_wakeup(struct acpi_device *device) > -{ > - struct acpi_button *button = acpi_driver_data(device); > - struct input_dev *input; > - > - if (button->type == ACPI_BUTTON_TYPE_POWER) { > - input = button->input; > - input_report_key(input, KEY_WAKEUP, 1); > - input_sync(input); > - input_report_key(input, KEY_WAKEUP, 0); > - input_sync(input); > - } > - > - return; > -} > -EXPORT_SYMBOL(acpi_power_button_wakeup); > - > static void acpi_button_notify_run(void *data) > { > acpi_button_notify(NULL, ACPI_BUTTON_NOTIFY_STATUS, data); > @@ -492,6 +479,12 @@ static void acpi_button_notify_run(void *data) > > static u32 acpi_button_event(void *data) > { > + struct acpi_device *device = data; > + struct acpi_button *button = acpi_driver_data(device); > + > + if (button->type == ACPI_BUTTON_TYPE_POWER && button->suspended) > + button->wakeup_pending = true; > + > acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_button_notify_run, data); > return ACPI_INTERRUPT_HANDLED; > } > @@ -503,11 +496,13 @@ static int acpi_button_suspend(struct device *dev) > struct acpi_button *button = acpi_driver_data(device); > > button->suspended = true; > + button->wakeup_pending = false; > return 0; > } > > static int acpi_button_resume(struct device *dev) > { > + struct input_dev *input; > struct acpi_device *device = to_acpi_device(dev); > struct acpi_button *button = acpi_driver_data(device); > > @@ -518,6 +513,15 @@ static int acpi_button_resume(struct device *dev) > acpi_lid_initialize_state(device); > } > > + if (button->type == ACPI_BUTTON_TYPE_POWER && button->wakeup_pending) { > + input = button->input; > + input_report_key(input, KEY_WAKEUP, 1); > + input_sync(input); > + input_report_key(input, KEY_WAKEUP, 0); > + input_sync(input); > + button->wakeup_pending = false; > + } > + > return 0; > } > #endif > diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c > index 0adfcd0fb55e..d655248c20d4 100644 > --- a/drivers/acpi/sleep.c > +++ b/drivers/acpi/sleep.c > @@ -22,7 +22,6 @@ > #include <linux/syscore_ops.h> > #include <asm/io.h> > #include <trace/events/power.h> > -#include <acpi/button.h> > > #include "internal.h" > #include "sleep.h" > @@ -105,8 +104,6 @@ u32 acpi_target_system_state(void) > } > EXPORT_SYMBOL_GPL(acpi_target_system_state); > > -static bool pwr_btn_event_pending; > - > /* > * The ACPI specification wants us to save NVS memory regions during hibernation > * and to restore them during the subsequent resume. Windows does that also for > @@ -463,7 +460,6 @@ static int acpi_pm_prepare(void) > */ > static void acpi_pm_finish(void) > { > - struct acpi_device *pwr_btn_adev; > u32 acpi_state = acpi_target_sleep_state; > > acpi_ec_unblock_transactions(); > @@ -482,24 +478,6 @@ static void acpi_pm_finish(void) > acpi_target_sleep_state = ACPI_STATE_S0; > > acpi_resume_power_resources(); > - > - /* If we were woken with the fixed power button, provide a small > - * hint to userspace in the form of a wakeup event on the fixed power > - * button device (if it can be found). > - * > - * We delay the event generation til now, as the PM layer requires > - * timekeeping to be running before we generate events. */ > - if (!pwr_btn_event_pending) > - return; > - > - pwr_btn_event_pending = false; > - pwr_btn_adev = acpi_dev_get_first_match_dev(ACPI_BUTTON_HID_POWERF, > - NULL, -1); > - if (pwr_btn_adev) { > - pm_wakeup_event(&pwr_btn_adev->dev, 0); > - acpi_power_button_wakeup(pwr_btn_adev); > - acpi_dev_put(pwr_btn_adev); > - } > } > > /** > @@ -604,27 +582,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state) > /* Reprogram control registers */ > acpi_leave_sleep_state_prep(acpi_state); > > - /* ACPI 3.0 specs (P62) says that it's the responsibility > - * of the OSPM to clear the status bit [ implying that the > - * POWER_BUTTON event should not reach userspace ] > - * > - * However, we do generate a small hint for userspace in the form of > - * a wakeup event. We flag this condition for now and generate the > - * event later, as we're currently too early in resume to be able to > - * generate wakeup events. > - */ > - if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) { > - acpi_event_status pwr_btn_status = ACPI_EVENT_FLAG_DISABLED; > - > - acpi_get_event_status(ACPI_EVENT_POWER_BUTTON, &pwr_btn_status); > - > - if (pwr_btn_status & ACPI_EVENT_FLAG_STATUS_SET) { > - acpi_clear_event(ACPI_EVENT_POWER_BUTTON); > - /* Flag for later */ > - pwr_btn_event_pending = true; > - } > - } > - > /* > * Disable all GPE and clear their status bits before interrupts are > * enabled. Some GPEs (like wakeup GPEs) have no handlers and this can > @@ -797,19 +754,12 @@ bool acpi_s2idle_wake(void) > > void acpi_s2idle_restore_check_powerkey(void) > { > - struct acpi_device *pwr_btn_adev; > acpi_event_status pwr_btn_status = ACPI_EVENT_FLAG_DISABLED; > + > acpi_get_event_status(ACPI_EVENT_POWER_BUTTON, &pwr_btn_status); > > - if (pwr_btn_status & ACPI_EVENT_FLAG_STATUS_SET) { > - pwr_btn_adev = acpi_dev_get_first_match_dev(ACPI_BUTTON_HID_POWERF, > - NULL, -1); > - if (pwr_btn_adev) { > - pm_wakeup_event(&pwr_btn_adev->dev, 0); > - acpi_power_button_wakeup(pwr_btn_adev); > - acpi_dev_put(pwr_btn_adev); > - } > - } > + if (pwr_btn_status & ACPI_EVENT_FLAG_STATUS_SET) > + acpi_clear_event(ACPI_EVENT_POWER_BUTTON); > } > > void acpi_s2idle_restore(void) > diff --git a/include/acpi/button.h b/include/acpi/button.h > index be02d3ff2896..af2fce5d2ee3 100644 > --- a/include/acpi/button.h > +++ b/include/acpi/button.h > @@ -8,16 +8,11 @@ > > #if IS_ENABLED(CONFIG_ACPI_BUTTON) > extern int acpi_lid_open(void); > -extern void acpi_power_button_wakeup(struct acpi_device *device); > #else > static inline int acpi_lid_open(void) > { > return 1; > } > -static inline void acpi_power_button_wakeup(struct acpi_device *device) > -{ > - return; > -} > #endif /* IS_ENABLED(CONFIG_ACPI_BUTTON) */ > > #endif /* ACPI_BUTTON_H */ > -- > 2.34.1 > ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] ACPI: button: Report wakeup key only for power button wakeups 2026-08-06 12:27 [PATCH] ACPI: button: Report wakeup key only for power button wakeups Baorui Liu 2026-08-07 14:12 ` Rafael J. Wysocki (Intel) 2026-08-19 8:55 ` [PATCH v2 0/1] " Baorui.Liu @ 2026-08-20 7:07 ` kernel test robot 2 siblings, 0 replies; 6+ messages in thread From: kernel test robot @ 2026-08-20 7:07 UTC (permalink / raw) To: Baorui Liu, Rafael J . Wysocki Cc: oe-kbuild-all, Len Brown, Mario Limonciello, linux-acpi, linux-kernel, acpica-devel, Baorui Liu Hi Baorui, kernel test robot noticed the following build warnings: [auto build test WARNING on 4d823c9d06aaa91476b58e56e4d44c4112da2811] url: https://github.com/intel-lab-lkp/linux/commits/Baorui-Liu/ACPI-button-Report-wakeup-key-only-for-power-button-wakeups/20260806-202732 base: 4d823c9d06aaa91476b58e56e4d44c4112da2811 patch link: https://lore.kernel.org/r/20260806122732.533-1-baorliu%40amd.com patch subject: [PATCH] ACPI: button: Report wakeup key only for power button wakeups config: csky-allmodconfig (https://download.01.org/0day-ci/archive/20260820/202608201432.sqYAY4nF-lkp@intel.com/config) compiler: csky-linux-gcc (GCC) 16.1.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260820/202608201432.sqYAY4nF-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202608201432.sqYAY4nF-lkp@intel.com/ All warnings (new ones prefixed by >>): In file included from drivers/gpu/drm/nouveau/nouveau_connector.c:27: >> include/acpi/button.h:18:52: warning: 'struct acpi_device' declared inside parameter list will not be visible outside of this definition or declaration 18 | static inline void acpi_power_button_wakeup(struct acpi_device *device) | ^~~~~~~~~~~ vim +18 include/acpi/button.h 17 > 18 static inline void acpi_power_button_wakeup(struct acpi_device *device) 19 { 20 } 21 #endif /* IS_ENABLED(CONFIG_ACPI_BUTTON) */ 22 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-09-09 14:42 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-08-06 12:27 [PATCH] ACPI: button: Report wakeup key only for power button wakeups Baorui Liu 2026-08-07 14:12 ` Rafael J. Wysocki (Intel) 2026-08-19 8:55 ` [PATCH v2 0/1] " Baorui.Liu 2026-08-19 8:55 ` [PATCH v2 1/1] " Baorui.Liu 2026-09-09 14:41 ` Rafael J. Wysocki (Intel) 2026-08-20 7:07 ` [PATCH] " kernel test robot
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).