aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-07-14 16:41:41 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-07-23 17:13:19 -0400
commitbd9b2f9aff26c185c1f8e0cd08a850ee4ace391a (patch)
treed566da1fdad50aad82a8538e626827c1fe44ae21 /drivers/acpi
parent9c14cc44575ab7faae6bcb5821e6cad5f0d8238d (diff)
ACPI / scan: No implicit wake notification for buttons
The ACPI device enumeration code in Linux assumes that buttons always are wakeup devices, so it calls acpi_setup_gpe_for_wake() for them which leads to undesirable side effects. Namely, that function sets up implicit device wake notification mechanism for a given GPE if there is no handler method in the ACPI namespace, which from the ACPICA's perspective means that there always is a way to handle that GPE if enabled. However, we don't handle wake notify events for buttons, so if there are no handler methods for their GPEs in the namespace, enabling a button GPE at run time leads to a GPE storm in some cases (the GPE triggers, ACPICA carries out the implicit wake notification for it which isn't handled, so the GPE triggers again and so on). To prevent that from happening use acpi_mark_gpe_for_wake() instead of acpi_setup_gpe_for_wake() for buttons which will cause ACPICA to only enable button GPEs if there are handler methods for the in the namespace. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/scan.c29
1 files changed, 16 insertions, 13 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index f775fa0d850f..0afa66050370 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1421,14 +1421,13 @@ static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
1421 wakeup->sleep_state = sleep_state; 1421 wakeup->sleep_state = sleep_state;
1422 } 1422 }
1423 } 1423 }
1424 acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number);
1425 1424
1426 out: 1425 out:
1427 kfree(buffer.pointer); 1426 kfree(buffer.pointer);
1428 return err; 1427 return err;
1429} 1428}
1430 1429
1431static void acpi_bus_set_run_wake_flags(struct acpi_device *device) 1430static void acpi_wakeup_gpe_init(struct acpi_device *device)
1432{ 1431{
1433 struct acpi_device_id button_device_ids[] = { 1432 struct acpi_device_id button_device_ids[] = {
1434 {"PNP0C0C", 0}, 1433 {"PNP0C0C", 0},
@@ -1436,29 +1435,33 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
1436 {"PNP0C0E", 0}, 1435 {"PNP0C0E", 0},
1437 {"", 0}, 1436 {"", 0},
1438 }; 1437 };
1438 struct acpi_device_wakeup *wakeup = &device->wakeup;
1439 acpi_status status; 1439 acpi_status status;
1440 acpi_event_status event_status; 1440 acpi_event_status event_status;
1441 1441
1442 device->wakeup.flags.notifier_present = 0; 1442 wakeup->flags.notifier_present = 0;
1443 1443
1444 /* Power button, Lid switch always enable wakeup */ 1444 /* Power button, Lid switch always enable wakeup */
1445 if (!acpi_match_device_ids(device, button_device_ids)) { 1445 if (!acpi_match_device_ids(device, button_device_ids)) {
1446 device->wakeup.flags.run_wake = 1; 1446 wakeup->flags.run_wake = 1;
1447 if (!acpi_match_device_ids(device, &button_device_ids[1])) { 1447 if (!acpi_match_device_ids(device, &button_device_ids[1])) {
1448 /* Do not use Lid/sleep button for S5 wakeup */ 1448 /* Do not use Lid/sleep button for S5 wakeup */
1449 if (device->wakeup.sleep_state == ACPI_STATE_S5) 1449 if (wakeup->sleep_state == ACPI_STATE_S5)
1450 device->wakeup.sleep_state = ACPI_STATE_S4; 1450 wakeup->sleep_state = ACPI_STATE_S4;
1451 } 1451 }
1452 acpi_mark_gpe_for_wake(wakeup->gpe_device, wakeup->gpe_number);
1452 device_set_wakeup_capable(&device->dev, true); 1453 device_set_wakeup_capable(&device->dev, true);
1453 return; 1454 return;
1454 } 1455 }
1455 1456
1456 status = acpi_get_gpe_status(device->wakeup.gpe_device, 1457 acpi_setup_gpe_for_wake(device->handle, wakeup->gpe_device,
1457 device->wakeup.gpe_number, 1458 wakeup->gpe_number);
1458 &event_status); 1459 status = acpi_get_gpe_status(wakeup->gpe_device, wakeup->gpe_number,
1459 if (status == AE_OK) 1460 &event_status);
1460 device->wakeup.flags.run_wake = 1461 if (ACPI_FAILURE(status))
1461 !!(event_status & ACPI_EVENT_FLAG_HANDLE); 1462 return;
1463
1464 wakeup->flags.run_wake = !!(event_status & ACPI_EVENT_FLAG_HANDLE);
1462} 1465}
1463 1466
1464static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device) 1467static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
@@ -1478,7 +1481,7 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
1478 1481
1479 device->wakeup.flags.valid = 1; 1482 device->wakeup.flags.valid = 1;
1480 device->wakeup.prepare_count = 0; 1483 device->wakeup.prepare_count = 0;
1481 acpi_bus_set_run_wake_flags(device); 1484 acpi_wakeup_gpe_init(device);
1482 /* Call _PSW/_DSW object to disable its ability to wake the sleeping 1485 /* Call _PSW/_DSW object to disable its ability to wake the sleeping
1483 * system for the ACPI device with the _PRW object. 1486 * system for the ACPI device with the _PRW object.
1484 * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW. 1487 * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW.