aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/acpi/device_pm.c80
-rw-r--r--drivers/acpi/pci_root.c2
-rw-r--r--drivers/pci/pci-acpi.c60
-rw-r--r--include/acpi/acpi_bus.h21
-rw-r--r--include/linux/pci-acpi.h13
5 files changed, 101 insertions, 75 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
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index d388f13d48b4..e6ae603ed1a1 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -593,7 +593,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
593 if (no_aspm) 593 if (no_aspm)
594 pcie_no_aspm(); 594 pcie_no_aspm();
595 595
596 pci_acpi_add_bus_pm_notifier(device, root->bus); 596 pci_acpi_add_bus_pm_notifier(device);
597 if (device->wakeup.flags.run_wake) 597 if (device->wakeup.flags.run_wake)
598 device_set_run_wake(root->bus->bridge, true); 598 device_set_run_wake(root->bus->bridge, true);
599 599
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index ca4927ba8433..7b8b2298840a 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -18,31 +18,31 @@
18#include "pci.h" 18#include "pci.h"
19 19
20/** 20/**
21 * pci_acpi_wake_bus - Wake-up notification handler for root buses. 21 * pci_acpi_wake_bus - Root bus wakeup notification fork function.
22 * @handle: ACPI handle of a device the notification is for. 22 * @work: Work item to handle.
23 * @event: Type of the signaled event.
24 * @context: PCI root bus to wake up devices on.
25 */ 23 */
26static void pci_acpi_wake_bus(acpi_handle handle, u32 event, void *context) 24static void pci_acpi_wake_bus(struct work_struct *work)
27{ 25{
28 struct pci_bus *pci_bus = context; 26 struct acpi_device *adev;
27 struct acpi_pci_root *root;
29 28
30 if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_bus) 29 adev = container_of(work, struct acpi_device, wakeup.context.work);
31 pci_pme_wakeup_bus(pci_bus); 30 root = acpi_driver_data(adev);
31 pci_pme_wakeup_bus(root->bus);
32} 32}
33 33
34/** 34/**
35 * pci_acpi_wake_dev - Wake-up notification handler for PCI devices. 35 * pci_acpi_wake_dev - PCI device wakeup notification work function.
36 * @handle: ACPI handle of a device the notification is for. 36 * @handle: ACPI handle of a device the notification is for.
37 * @event: Type of the signaled event. 37 * @work: Work item to handle.
38 * @context: PCI device object to wake up.
39 */ 38 */
40static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context) 39static void pci_acpi_wake_dev(struct work_struct *work)
41{ 40{
42 struct pci_dev *pci_dev = context; 41 struct acpi_device_wakeup_context *context;
42 struct pci_dev *pci_dev;
43 43
44 if (event != ACPI_NOTIFY_DEVICE_WAKE || !pci_dev) 44 context = container_of(work, struct acpi_device_wakeup_context, work);
45 return; 45 pci_dev = to_pci_dev(context->dev);
46 46
47 if (pci_dev->pme_poll) 47 if (pci_dev->pme_poll)
48 pci_dev->pme_poll = false; 48 pci_dev->pme_poll = false;
@@ -65,23 +65,12 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
65} 65}
66 66
67/** 67/**
68 * pci_acpi_add_bus_pm_notifier - Register PM notifier for given PCI bus. 68 * pci_acpi_add_bus_pm_notifier - Register PM notifier for root PCI bus.
69 * @dev: ACPI device to add the notifier for. 69 * @dev: PCI root bridge ACPI device.
70 * @pci_bus: PCI bus to walk checking for PME status if an event is signaled.
71 */ 70 */
72acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev, 71acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev)
73 struct pci_bus *pci_bus)
74{ 72{
75 return acpi_add_pm_notifier(dev, pci_acpi_wake_bus, pci_bus); 73 return acpi_add_pm_notifier(dev, NULL, pci_acpi_wake_bus);
76}
77
78/**
79 * pci_acpi_remove_bus_pm_notifier - Unregister PCI bus PM notifier.
80 * @dev: ACPI device to remove the notifier from.
81 */
82acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev)
83{
84 return acpi_remove_pm_notifier(dev, pci_acpi_wake_bus);
85} 74}
86 75
87/** 76/**
@@ -92,16 +81,7 @@ acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev)
92acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev, 81acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev,
93 struct pci_dev *pci_dev) 82 struct pci_dev *pci_dev)
94{ 83{
95 return acpi_add_pm_notifier(dev, pci_acpi_wake_dev, pci_dev); 84 return acpi_add_pm_notifier(dev, &pci_dev->dev, pci_acpi_wake_dev);
96}
97
98/**
99 * pci_acpi_remove_pm_notifier - Unregister PCI device PM notifier.
100 * @dev: ACPI device to remove the notifier from.
101 */
102acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
103{
104 return acpi_remove_pm_notifier(dev, pci_acpi_wake_dev);
105} 85}
106 86
107phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle) 87phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index b5714580801a..99780d46abb6 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -315,12 +315,19 @@ struct acpi_device_wakeup_flags {
315 u8 notifier_present:1; /* Wake-up notify handler has been installed */ 315 u8 notifier_present:1; /* Wake-up notify handler has been installed */
316}; 316};
317 317
318struct acpi_device_wakeup_context {
319 struct work_struct work;
320 struct device *dev;
321};
322
318struct acpi_device_wakeup { 323struct acpi_device_wakeup {
319 acpi_handle gpe_device; 324 acpi_handle gpe_device;
320 u64 gpe_number; 325 u64 gpe_number;
321 u64 sleep_state; 326 u64 sleep_state;
322 struct list_head resources; 327 struct list_head resources;
323 struct acpi_device_wakeup_flags flags; 328 struct acpi_device_wakeup_flags flags;
329 struct acpi_device_wakeup_context context;
330 struct wakeup_source *ws;
324 int prepare_count; 331 int prepare_count;
325}; 332};
326 333
@@ -510,20 +517,18 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state);
510int acpi_disable_wakeup_device_power(struct acpi_device *dev); 517int acpi_disable_wakeup_device_power(struct acpi_device *dev);
511 518
512#ifdef CONFIG_PM 519#ifdef CONFIG_PM
513acpi_status acpi_add_pm_notifier(struct acpi_device *adev, 520acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,
514 acpi_notify_handler handler, void *context); 521 void (*work_func)(struct work_struct *work));
515acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, 522acpi_status acpi_remove_pm_notifier(struct acpi_device *adev);
516 acpi_notify_handler handler);
517int acpi_pm_device_sleep_state(struct device *, int *, int); 523int acpi_pm_device_sleep_state(struct device *, int *, int);
518#else 524#else
519static inline acpi_status acpi_add_pm_notifier(struct acpi_device *adev, 525static inline acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
520 acpi_notify_handler handler, 526 struct device *dev,
521 void *context) 527 void (*work_func)(struct work_struct *work))
522{ 528{
523 return AE_SUPPORT; 529 return AE_SUPPORT;
524} 530}
525static inline acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, 531static inline acpi_status acpi_remove_pm_notifier(struct acpi_device *adev)
526 acpi_notify_handler handler)
527{ 532{
528 return AE_SUPPORT; 533 return AE_SUPPORT;
529} 534}
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index 637a608ded0b..64dacb7288a6 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -11,12 +11,17 @@
11#include <linux/acpi.h> 11#include <linux/acpi.h>
12 12
13#ifdef CONFIG_ACPI 13#ifdef CONFIG_ACPI
14extern acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev, 14extern acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev);
15 struct pci_bus *pci_bus); 15static inline acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev)
16extern acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev); 16{
17 return acpi_remove_pm_notifier(dev);
18}
17extern acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev, 19extern acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev,
18 struct pci_dev *pci_dev); 20 struct pci_dev *pci_dev);
19extern acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev); 21static inline acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
22{
23 return acpi_remove_pm_notifier(dev);
24}
20extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle); 25extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle);
21 26
22static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) 27static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)