aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/device_pm.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-07-22 19:00:45 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-07-22 19:00:45 -0400
commitc072530f391e33bd22ed0638c08f07528f154493 (patch)
tree559f1730fb64797831086b2e41feded7d72e7226 /drivers/acpi/device_pm.c
parent28cb5ef16e578bbca0a562b09f12c8c98ca92720 (diff)
ACPI / PM: Revork the handling of ACPI device wakeup notifications
Since ACPI wakeup GPEs are going to be enabled during system suspend as well as for runtime wakeup by a subsequent patch and the same notify handlers will be used in both cases, rework the ACPI device wakeup notification framework so that the part specific to physical devices is always run asynchronously from the PM workqueue. This prevents runtime resume callbacks for those devices from being run during system suspend and resume which may not be appropriate, among other things. Also make ACPI device wakeup notification handling a bit more robust agaist subsequent removal of ACPI device objects, whould that ever happen, and create a wakeup source object for each ACPI device configured for wakeup so that wakeup notifications for those devices can wake up the system from the "freeze" sleep state. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/device_pm.c')
-rw-r--r--drivers/acpi/device_pm.c80
1 files changed, 58 insertions, 22 deletions
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index 49a51277f81d..366de0b0c39b 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -367,29 +367,61 @@ EXPORT_SYMBOL(acpi_bus_power_manageable);
367#ifdef CONFIG_PM 367#ifdef CONFIG_PM
368static DEFINE_MUTEX(acpi_pm_notifier_lock); 368static DEFINE_MUTEX(acpi_pm_notifier_lock);
369 369
370static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
371{
372 struct acpi_device *adev;
373
374 if (val != ACPI_NOTIFY_DEVICE_WAKE)
375 return;
376
377 adev = acpi_bus_get_acpi_device(handle);
378 if (!adev)
379 return;
380
381 mutex_lock(&acpi_pm_notifier_lock);
382
383 if (adev->wakeup.flags.notifier_present) {
384 __pm_wakeup_event(adev->wakeup.ws, 0);
385 if (adev->wakeup.context.work.func)
386 queue_pm_work(&adev->wakeup.context.work);
387 }
388
389 mutex_unlock(&acpi_pm_notifier_lock);
390
391 acpi_bus_put_acpi_device(adev);
392}
393
370/** 394/**
371 * acpi_add_pm_notifier - Register PM notifier for given ACPI device. 395 * acpi_add_pm_notifier - Register PM notify handler for given ACPI device.
372 * @adev: ACPI device to add the notifier for. 396 * @adev: ACPI device to add the notify handler for.
373 * @context: Context information to pass to the notifier routine. 397 * @dev: Device to generate a wakeup event for while handling the notification.
398 * @work_func: Work function to execute when handling the notification.
374 * 399 *
375 * NOTE: @adev need not be a run-wake or wakeup device to be a valid source of 400 * NOTE: @adev need not be a run-wake or wakeup device to be a valid source of
376 * PM wakeup events. For example, wakeup events may be generated for bridges 401 * PM wakeup events. For example, wakeup events may be generated for bridges
377 * if one of the devices below the bridge is signaling wakeup, even if the 402 * if one of the devices below the bridge is signaling wakeup, even if the
378 * bridge itself doesn't have a wakeup GPE associated with it. 403 * bridge itself doesn't have a wakeup GPE associated with it.
379 */ 404 */
380acpi_status acpi_add_pm_notifier(struct acpi_device *adev, 405acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,
381 acpi_notify_handler handler, void *context) 406 void (*work_func)(struct work_struct *work))
382{ 407{
383 acpi_status status = AE_ALREADY_EXISTS; 408 acpi_status status = AE_ALREADY_EXISTS;
384 409
410 if (!dev && !work_func)
411 return AE_BAD_PARAMETER;
412
385 mutex_lock(&acpi_pm_notifier_lock); 413 mutex_lock(&acpi_pm_notifier_lock);
386 414
387 if (adev->wakeup.flags.notifier_present) 415 if (adev->wakeup.flags.notifier_present)
388 goto out; 416 goto out;
389 417
390 status = acpi_install_notify_handler(adev->handle, 418 adev->wakeup.ws = wakeup_source_register(dev_name(&adev->dev));
391 ACPI_SYSTEM_NOTIFY, 419 adev->wakeup.context.dev = dev;
392 handler, context); 420 if (work_func)
421 INIT_WORK(&adev->wakeup.context.work, work_func);
422
423 status = acpi_install_notify_handler(adev->handle, ACPI_SYSTEM_NOTIFY,
424 acpi_pm_notify_handler, NULL);
393 if (ACPI_FAILURE(status)) 425 if (ACPI_FAILURE(status))
394 goto out; 426 goto out;
395 427
@@ -404,8 +436,7 @@ acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
404 * acpi_remove_pm_notifier - Unregister PM notifier from given ACPI device. 436 * acpi_remove_pm_notifier - Unregister PM notifier from given ACPI device.
405 * @adev: ACPI device to remove the notifier from. 437 * @adev: ACPI device to remove the notifier from.
406 */ 438 */
407acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, 439acpi_status acpi_remove_pm_notifier(struct acpi_device *adev)
408 acpi_notify_handler handler)
409{ 440{
410 acpi_status status = AE_BAD_PARAMETER; 441 acpi_status status = AE_BAD_PARAMETER;
411 442
@@ -416,10 +447,17 @@ acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
416 447
417 status = acpi_remove_notify_handler(adev->handle, 448 status = acpi_remove_notify_handler(adev->handle,
418 ACPI_SYSTEM_NOTIFY, 449 ACPI_SYSTEM_NOTIFY,
419 handler); 450 acpi_pm_notify_handler);
420 if (ACPI_FAILURE(status)) 451 if (ACPI_FAILURE(status))
421 goto out; 452 goto out;
422 453
454 if (adev->wakeup.context.work.func) {
455 cancel_work_sync(&adev->wakeup.context.work);
456 adev->wakeup.context.work.func = NULL;
457 }
458 adev->wakeup.context.dev = NULL;
459 wakeup_source_unregister(adev->wakeup.ws);
460
423 adev->wakeup.flags.notifier_present = false; 461 adev->wakeup.flags.notifier_present = false;
424 462
425 out: 463 out:
@@ -602,16 +640,15 @@ EXPORT_SYMBOL(acpi_pm_device_sleep_state);
602 640
603#ifdef CONFIG_PM_RUNTIME 641#ifdef CONFIG_PM_RUNTIME
604/** 642/**
605 * acpi_wakeup_device - Wakeup notification handler for ACPI devices. 643 * acpi_pm_notify_work_func - ACPI devices wakeup notification work function.
606 * @handle: ACPI handle of the device the notification is for. 644 * @work: Work item to handle.
607 * @event: Type of the signaled event.
608 * @context: Device corresponding to @handle.
609 */ 645 */
610static void acpi_wakeup_device(acpi_handle handle, u32 event, void *context) 646static void acpi_pm_notify_work_func(struct work_struct *work)
611{ 647{
612 struct device *dev = context; 648 struct device *dev;
613 649
614 if (event == ACPI_NOTIFY_DEVICE_WAKE && dev) { 650 dev = container_of(work, struct acpi_device_wakeup_context, work)->dev;
651 if (dev) {
615 pm_wakeup_event(dev, 0); 652 pm_wakeup_event(dev, 0);
616 pm_runtime_resume(dev); 653 pm_runtime_resume(dev);
617 } 654 }
@@ -677,8 +714,7 @@ int acpi_pm_device_run_wake(struct device *phys_dev, bool enable)
677} 714}
678EXPORT_SYMBOL(acpi_pm_device_run_wake); 715EXPORT_SYMBOL(acpi_pm_device_run_wake);
679#else 716#else
680static inline void acpi_wakeup_device(acpi_handle handle, u32 event, 717static inline void acpi_pm_notify_work_func(struct work_struct *work) {}
681 void *context) {}
682#endif /* CONFIG_PM_RUNTIME */ 718#endif /* CONFIG_PM_RUNTIME */
683 719
684#ifdef CONFIG_PM_SLEEP 720#ifdef CONFIG_PM_SLEEP
@@ -1048,7 +1084,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
1048 if (dev->pm_domain) 1084 if (dev->pm_domain)
1049 return -EEXIST; 1085 return -EEXIST;
1050 1086
1051 acpi_add_pm_notifier(adev, acpi_wakeup_device, dev); 1087 acpi_add_pm_notifier(adev, dev, acpi_pm_notify_work_func);
1052 dev->pm_domain = &acpi_general_pm_domain; 1088 dev->pm_domain = &acpi_general_pm_domain;
1053 if (power_on) { 1089 if (power_on) {
1054 acpi_dev_pm_full_power(adev); 1090 acpi_dev_pm_full_power(adev);
@@ -1076,7 +1112,7 @@ void acpi_dev_pm_detach(struct device *dev, bool power_off)
1076 1112
1077 if (adev && dev->pm_domain == &acpi_general_pm_domain) { 1113 if (adev && dev->pm_domain == &acpi_general_pm_domain) {
1078 dev->pm_domain = NULL; 1114 dev->pm_domain = NULL;
1079 acpi_remove_pm_notifier(adev, acpi_wakeup_device); 1115 acpi_remove_pm_notifier(adev);
1080 if (power_off) { 1116 if (power_off) {
1081 /* 1117 /*
1082 * If the device's PM QoS resume latency limit or flags 1118 * If the device's PM QoS resume latency limit or flags