summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/acpica/evxfgpe.c50
-rw-r--r--drivers/acpi/button.c25
-rw-r--r--include/acpi/acpixf.h5
3 files changed, 70 insertions, 10 deletions
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index 60dacec1b121..4074b5908db3 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -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)
/*******************************************************************************
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index b47301ee4c8a..d80276368b81 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -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 @@ err_remove_fs:
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);
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 49d1749f30bb..a4b562700151 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -726,6 +726,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))