ACPI support fixes for 7.1-rc6

Fix three issues in the ACPI button driver: a possible crash due to
 a button press after unloading the driver (introduced during the 6.15
 development cycle), function keys breakage on Toshiba Tecra X40 due to
 missing ACPI events (introduced during the 7.0 development cycle), and
 a missing probe rollback path item that has not been added by mistake
 during a recent update.
 -----BEGIN PGP SIGNATURE-----
 
 iQFGBAABCAAwFiEEcM8Aw/RY0dgsiRUR7l+9nS/U47UFAmoYhl8SHHJqd0Byand5
 c29ja2kubmV0AAoJEO5fvZ0v1OO1mfsH/A4/8aBIuxemIAoyoAQwwjQGoIkdhDDV
 vyHBpOxzXwlOB0dCi/vuVdkMX+ADt2/0roh82mnXRiIv47CF/ePrQSnLiIvtN32b
 cY7xbSN8n7d2Vjp5k3cWBU/CL1tCGq6c/DEnFzMwtzhkt7qCuaDDfedqjg1/dZvg
 IrbexlAveRO9Qhtep8wCrxJsmZULXFcQe2qSMS82UkbqeJzR4lz3ovLocdEQqP9Q
 YRipKrv4M5/3H63ajbxJQZaP87WY731tM4Ny2zxO05dek9b70o+dHyjRGMRqqYZD
 eTKo8ck90aLNsjiXXC6eqVOkcxZv3kbLkpY4Exblmmp0lBnzszhRe0w=
 =Th+J
 -----END PGP SIGNATURE-----

Merge tag 'acpi-7.1-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull ACPI support fixes from Rafael Wysocki:
 "Fix three issues in the ACPI button driver: a possible crash due to a
  button press after unloading the driver (introduced during the 6.15
  development cycle), function keys breakage on Toshiba Tecra X40 due to
  missing ACPI events (introduced during the 7.0 development cycle), and
  a missing probe rollback path item that has not been added by mistake
  during a recent update"

* tag 'acpi-7.1-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  ACPI: button: Add missing device class clearing on probe failures
  ACPI: button: Enable wakeup GPEs for ACPI buttons at probe time
  ACPI: button: Fix ACPI GPE handler leak during removal
This commit is contained in:
Linus Torvalds 2026-05-28 13:45:10 -07:00
commit 8fde5d1d47
3 changed files with 70 additions and 10 deletions

View 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)
/*******************************************************************************

View 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)) {
@ -671,6 +687,7 @@ static int acpi_button_probe(struct platform_device *pdev)
acpi_button_remove_fs(button);
err_free_button:
kfree(button);
memset(acpi_device_class(device), 0, sizeof(acpi_device_class));
return error;
}
@ -689,7 +706,13 @@ static void acpi_button_remove(struct platform_device *pdev)
acpi_button_event);
break;
default:
acpi_remove_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
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 :
acpi_button_notify);

View 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))