]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ACPI: button: Enable wakeup GPEs for ACPI buttons at probe time
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 22 May 2026 14:52:10 +0000 (16:52 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 25 May 2026 07:52:34 +0000 (09:52 +0200)
Prior to commit 57c31e6d620f ("ACPI: scan: Use acpi_setup_gpe_for_wake()
for buttons"), ACPI button wakeup GPEs having handler methods remained
enabled after acpi_wakeup_gpe_init(), but currently they are not enabled
because acpi_setup_gpe_for_wake() disables them.

That causes function keys to stop working on some systems [1] and there
may be other related issues elsewhere.

To address that, make the ACPI button driver enable wakeup GPEs for ACPI
buttons so long as they have handler methods.  While this does not
restore the old behavior exactly (the ACPI button driver needs to be
bound to the button devices for the GPEs to be enabled), it should be
sufficient to restore the missing functionality.

For this purpose, introduce acpi_enable_gpe_cond() that enables
a GPE if its dispatch type matches the supplied one and modify
acpi_button_probe() to use that function for enabling the GPEs in
question.

Fixes: 57c31e6d620f ("ACPI: scan: Use acpi_setup_gpe_for_wake() for buttons")
Reported-by: Nick <nick@kousu.ca>
Closes: https://lore.kernel.org/linux-acpi/E2OXET.4X5GTP37VTNC3@kousu.ca/ [1]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Nick <nick@kousu.ca>
Cc: 7.0+ <stable@vger.kernel.org> # 7.0+
Link: https://patch.msgid.link/9629117.CDJkKcVGEf@rafael.j.wysocki
drivers/acpi/acpica/evxfgpe.c
drivers/acpi/button.c
include/acpi/acpixf.h

index 60dacec1b121fda1afd77dc1ebe82fd1175090da..4074b5908db308322f38faddc19ef1c77819fc67 100644 (file)
@@ -78,18 +78,22 @@ ACPI_EXPORT_SYMBOL(acpi_update_all_gpes)
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_enable_gpe
+ * FUNCTION:    acpi_enable_gpe_cond
  *
  * PARAMETERS:  gpe_device          - Parent GPE Device. NULL for GPE0/GPE1
  *              gpe_number          - GPE level within the GPE block
+ *              dispatch_type       - GPE dispatch type to match
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
- *              hardware-enabled.
+ * DESCRIPTION: Add a reference to a GPE so long as its dispatch type matches
+ *              the supplied one, or it is different from ACPI_GPE_DISPATCH_NONE
+ *              if the supplied one is ACPI_GPE_DISPATCH_MASK. On the first
+ *              reference, the GPE is hardware-enabled.
  *
  ******************************************************************************/
-acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
+acpi_status acpi_enable_gpe_cond(acpi_handle gpe_device, u32 gpe_number,
+                                u8 dispatch_type)
 {
        acpi_status status = AE_BAD_PARAMETER;
        struct acpi_gpe_event_info *gpe_event_info;
@@ -100,14 +104,18 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
        flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
 
        /*
-        * Ensure that we have a valid GPE number and that there is some way
-        * of handling the GPE (handler or a GPE method). In other words, we
-        * won't allow a valid GPE to be enabled if there is no way to handle it.
+        * Ensure that we have a valid GPE number and that the dispatch type of
+        * the GPE matches the supplied one (or it is not ACPI_GPE_DISPATCH_NONE
+        * if the supplied one is ACPI_GPE_DISPATCH_MASK).
         */
        gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
        if (gpe_event_info) {
-               if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
-                   ACPI_GPE_DISPATCH_NONE) {
+               if (dispatch_type == ACPI_GPE_DISPATCH_MASK)
+                       dispatch_type = ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags);
+               else if (dispatch_type != ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags))
+                       dispatch_type = ACPI_GPE_DISPATCH_NONE;
+
+               if (dispatch_type != ACPI_GPE_DISPATCH_NONE) {
                        status = acpi_ev_add_gpe_reference(gpe_event_info, TRUE);
                        if (ACPI_SUCCESS(status) &&
                            ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
@@ -128,6 +136,30 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
        acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
        return_ACPI_STATUS(status);
 }
+ACPI_EXPORT_SYMBOL(acpi_enable_gpe_cond)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_enable_gpe
+ *
+ * PARAMETERS:  gpe_device          - Parent GPE Device. NULL for GPE0/GPE1
+ *              gpe_number          - GPE level within the GPE block
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
+ *              hardware-enabled.
+ *
+ ******************************************************************************/
+acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
+{
+       /*
+        * Ensure that there is some way of handling the GPE (handler or a GPE
+        * method). In other words, we won't allow a valid GPE to be enabled if
+        * there is no way to handle it.
+        */
+       return acpi_enable_gpe_cond(gpe_device, gpe_number, ACPI_GPE_DISPATCH_MASK);
+}
 ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
 
 /*******************************************************************************
index 7c2e1a422ba01a018b0405cd04299cf8d0e06e98..e8dd306e17edbba696f6d28a1812d914021da2d0 100644 (file)
@@ -179,6 +179,7 @@ struct acpi_button {
        ktime_t last_time;
        bool suspended;
        bool lid_state_initialized;
+       bool gpe_enabled;
 };
 
 static struct acpi_device *lid_device;
@@ -646,6 +647,21 @@ static int acpi_button_probe(struct platform_device *pdev)
                status = acpi_install_notify_handler(device->handle,
                                                     ACPI_ALL_NOTIFY, handler,
                                                     button);
+               if (ACPI_SUCCESS(status) && device->wakeup.flags.valid) {
+                       acpi_status st;
+
+                       /*
+                        * If the wakeup GPE has a handler method, enable it in
+                        * case it is also used for signaling runtime events.
+                        */
+                       st = acpi_enable_gpe_cond(device->wakeup.gpe_device,
+                                                  device->wakeup.gpe_number,
+                                                  ACPI_GPE_DISPATCH_METHOD);
+                       button->gpe_enabled = ACPI_SUCCESS(st);
+                       if (button->gpe_enabled)
+                               dev_dbg(button->dev, "Enabled ACPI GPE%02llx\n",
+                                       device->wakeup.gpe_number);
+               }
                break;
        }
        if (ACPI_FAILURE(status)) {
@@ -689,6 +705,12 @@ static void acpi_button_remove(struct platform_device *pdev)
                                                acpi_button_event);
                break;
        default:
+               if (button->gpe_enabled) {
+                       dev_dbg(button->dev, "Disabling ACPI GPE%02llx\n",
+                               adev->wakeup.gpe_number);
+                       acpi_disable_gpe(adev->wakeup.gpe_device,
+                                        adev->wakeup.gpe_number);
+               }
                acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY,
                                           button->type == ACPI_BUTTON_TYPE_LID ?
                                                acpi_lid_notify :
index 49d1749f30bbc9e93d25a5d265cdbac727d91184..a4b5627001516105879f9ac5f4e1323696b63b86 100644 (file)
@@ -725,6 +725,11 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
  */
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_update_all_gpes(void))
 
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+                               acpi_enable_gpe_cond(acpi_handle gpe_device,
+                                                    u32 gpe_number,
+                                                    u8 dispatch_type))
+
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
                                acpi_enable_gpe(acpi_handle gpe_device,
                                                u32 gpe_number))