diff options
| -rw-r--r-- | drivers/acpi/device_pm.c | 80 | ||||
| -rw-r--r-- | drivers/acpi/pci_root.c | 2 | ||||
| -rw-r--r-- | drivers/pci/pci-acpi.c | 60 | ||||
| -rw-r--r-- | include/acpi/acpi_bus.h | 21 | ||||
| -rw-r--r-- | include/linux/pci-acpi.h | 13 |
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 |
| 368 | static DEFINE_MUTEX(acpi_pm_notifier_lock); | 368 | static DEFINE_MUTEX(acpi_pm_notifier_lock); |
| 369 | 369 | ||
| 370 | static 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 | */ |
| 380 | acpi_status acpi_add_pm_notifier(struct acpi_device *adev, | 405 | acpi_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 | */ |
| 407 | acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, | 439 | acpi_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 | */ |
| 610 | static void acpi_wakeup_device(acpi_handle handle, u32 event, void *context) | 646 | static 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 | } |
| 678 | EXPORT_SYMBOL(acpi_pm_device_run_wake); | 715 | EXPORT_SYMBOL(acpi_pm_device_run_wake); |
| 679 | #else | 716 | #else |
| 680 | static inline void acpi_wakeup_device(acpi_handle handle, u32 event, | 717 | static 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 | */ |
| 26 | static void pci_acpi_wake_bus(acpi_handle handle, u32 event, void *context) | 24 | static 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 | */ |
| 40 | static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context) | 39 | static 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 | */ |
| 72 | acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev, | 71 | acpi_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 | */ | ||
| 82 | acpi_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) | |||
| 92 | acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev, | 81 | acpi_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 | */ | ||
| 102 | acpi_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 | ||
| 107 | phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle) | 87 | phys_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 | ||
| 318 | struct acpi_device_wakeup_context { | ||
| 319 | struct work_struct work; | ||
| 320 | struct device *dev; | ||
| 321 | }; | ||
| 322 | |||
| 318 | struct acpi_device_wakeup { | 323 | struct 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); | |||
| 510 | int acpi_disable_wakeup_device_power(struct acpi_device *dev); | 517 | int acpi_disable_wakeup_device_power(struct acpi_device *dev); |
| 511 | 518 | ||
| 512 | #ifdef CONFIG_PM | 519 | #ifdef CONFIG_PM |
| 513 | acpi_status acpi_add_pm_notifier(struct acpi_device *adev, | 520 | acpi_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)); |
| 515 | acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, | 522 | acpi_status acpi_remove_pm_notifier(struct acpi_device *adev); |
| 516 | acpi_notify_handler handler); | ||
| 517 | int acpi_pm_device_sleep_state(struct device *, int *, int); | 523 | int acpi_pm_device_sleep_state(struct device *, int *, int); |
| 518 | #else | 524 | #else |
| 519 | static inline acpi_status acpi_add_pm_notifier(struct acpi_device *adev, | 525 | static 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 | } |
| 525 | static inline acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, | 531 | static 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 |
| 14 | extern acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev, | 14 | extern acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev); |
| 15 | struct pci_bus *pci_bus); | 15 | static inline acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev) |
| 16 | extern acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev); | 16 | { |
| 17 | return acpi_remove_pm_notifier(dev); | ||
| 18 | } | ||
| 17 | extern acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev, | 19 | extern acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev, |
| 18 | struct pci_dev *pci_dev); | 20 | struct pci_dev *pci_dev); |
| 19 | extern acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev); | 21 | static inline acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev) |
| 22 | { | ||
| 23 | return acpi_remove_pm_notifier(dev); | ||
| 24 | } | ||
| 20 | extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle); | 25 | extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle); |
| 21 | 26 | ||
| 22 | static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) | 27 | static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) |
