#ifdef CONFIG_PM
 static DEFINE_MUTEX(acpi_pm_notifier_lock);
 
+static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
+{
+       struct acpi_device *adev;
+
+       if (val != ACPI_NOTIFY_DEVICE_WAKE)
+               return;
+
+       adev = acpi_bus_get_acpi_device(handle);
+       if (!adev)
+               return;
+
+       mutex_lock(&acpi_pm_notifier_lock);
+
+       if (adev->wakeup.flags.notifier_present) {
+               __pm_wakeup_event(adev->wakeup.ws, 0);
+               if (adev->wakeup.context.work.func)
+                       queue_pm_work(&adev->wakeup.context.work);
+       }
+
+       mutex_unlock(&acpi_pm_notifier_lock);
+
+       acpi_bus_put_acpi_device(adev);
+}
+
 /**
- * acpi_add_pm_notifier - Register PM notifier for given ACPI device.
- * @adev: ACPI device to add the notifier for.
- * @context: Context information to pass to the notifier routine.
+ * acpi_add_pm_notifier - Register PM notify handler for given ACPI device.
+ * @adev: ACPI device to add the notify handler for.
+ * @dev: Device to generate a wakeup event for while handling the notification.
+ * @work_func: Work function to execute when handling the notification.
  *
  * NOTE: @adev need not be a run-wake or wakeup device to be a valid source of
  * PM wakeup events.  For example, wakeup events may be generated for bridges
  * if one of the devices below the bridge is signaling wakeup, even if the
  * bridge itself doesn't have a wakeup GPE associated with it.
  */
-acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
-                                acpi_notify_handler handler, void *context)
+acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,
+                                void (*work_func)(struct work_struct *work))
 {
        acpi_status status = AE_ALREADY_EXISTS;
 
+       if (!dev && !work_func)
+               return AE_BAD_PARAMETER;
+
        mutex_lock(&acpi_pm_notifier_lock);
 
        if (adev->wakeup.flags.notifier_present)
                goto out;
 
-       status = acpi_install_notify_handler(adev->handle,
-                                            ACPI_SYSTEM_NOTIFY,
-                                            handler, context);
+       adev->wakeup.ws = wakeup_source_register(dev_name(&adev->dev));
+       adev->wakeup.context.dev = dev;
+       if (work_func)
+               INIT_WORK(&adev->wakeup.context.work, work_func);
+
+       status = acpi_install_notify_handler(adev->handle, ACPI_SYSTEM_NOTIFY,
+                                            acpi_pm_notify_handler, NULL);
        if (ACPI_FAILURE(status))
                goto out;
 
  * acpi_remove_pm_notifier - Unregister PM notifier from given ACPI device.
  * @adev: ACPI device to remove the notifier from.
  */
-acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
-                                   acpi_notify_handler handler)
+acpi_status acpi_remove_pm_notifier(struct acpi_device *adev)
 {
        acpi_status status = AE_BAD_PARAMETER;
 
 
        status = acpi_remove_notify_handler(adev->handle,
                                            ACPI_SYSTEM_NOTIFY,
-                                           handler);
+                                           acpi_pm_notify_handler);
        if (ACPI_FAILURE(status))
                goto out;
 
+       if (adev->wakeup.context.work.func) {
+               cancel_work_sync(&adev->wakeup.context.work);
+               adev->wakeup.context.work.func = NULL;
+       }
+       adev->wakeup.context.dev = NULL;
+       wakeup_source_unregister(adev->wakeup.ws);
+
        adev->wakeup.flags.notifier_present = false;
 
  out:
 
 #ifdef CONFIG_PM_RUNTIME
 /**
- * acpi_wakeup_device - Wakeup notification handler for ACPI devices.
- * @handle: ACPI handle of the device the notification is for.
- * @event: Type of the signaled event.
- * @context: Device corresponding to @handle.
+ * acpi_pm_notify_work_func - ACPI devices wakeup notification work function.
+ * @work: Work item to handle.
  */
-static void acpi_wakeup_device(acpi_handle handle, u32 event, void *context)
+static void acpi_pm_notify_work_func(struct work_struct *work)
 {
-       struct device *dev = context;
+       struct device *dev;
 
-       if (event == ACPI_NOTIFY_DEVICE_WAKE && dev) {
+       dev = container_of(work, struct acpi_device_wakeup_context, work)->dev;
+       if (dev) {
                pm_wakeup_event(dev, 0);
                pm_runtime_resume(dev);
        }
 }
 EXPORT_SYMBOL(acpi_pm_device_run_wake);
 #else
-static inline void acpi_wakeup_device(acpi_handle handle, u32 event,
-                                     void *context) {}
+static inline void acpi_pm_notify_work_func(struct work_struct *work) {}
 #endif /* CONFIG_PM_RUNTIME */
 
 #ifdef CONFIG_PM_SLEEP
        if (dev->pm_domain)
                return -EEXIST;
 
-       acpi_add_pm_notifier(adev, acpi_wakeup_device, dev);
+       acpi_add_pm_notifier(adev, dev, acpi_pm_notify_work_func);
        dev->pm_domain = &acpi_general_pm_domain;
        if (power_on) {
                acpi_dev_pm_full_power(adev);
 
        if (adev && dev->pm_domain == &acpi_general_pm_domain) {
                dev->pm_domain = NULL;
-               acpi_remove_pm_notifier(adev, acpi_wakeup_device);
+               acpi_remove_pm_notifier(adev);
                if (power_off) {
                        /*
                         * If the device's PM QoS resume latency limit or flags
 
        if (no_aspm)
                pcie_no_aspm();
 
-       pci_acpi_add_bus_pm_notifier(device, root->bus);
+       pci_acpi_add_bus_pm_notifier(device);
        if (device->wakeup.flags.run_wake)
                device_set_run_wake(root->bus->bridge, true);
 
 
 #include "pci.h"
 
 /**
- * pci_acpi_wake_bus - Wake-up notification handler for root buses.
- * @handle: ACPI handle of a device the notification is for.
- * @event: Type of the signaled event.
- * @context: PCI root bus to wake up devices on.
+ * pci_acpi_wake_bus - Root bus wakeup notification fork function.
+ * @work: Work item to handle.
  */
-static void pci_acpi_wake_bus(acpi_handle handle, u32 event, void *context)
+static void pci_acpi_wake_bus(struct work_struct *work)
 {
-       struct pci_bus *pci_bus = context;
+       struct acpi_device *adev;
+       struct acpi_pci_root *root;
 
-       if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_bus)
-               pci_pme_wakeup_bus(pci_bus);
+       adev = container_of(work, struct acpi_device, wakeup.context.work);
+       root = acpi_driver_data(adev);
+       pci_pme_wakeup_bus(root->bus);
 }
 
 /**
- * pci_acpi_wake_dev - Wake-up notification handler for PCI devices.
+ * pci_acpi_wake_dev - PCI device wakeup notification work function.
  * @handle: ACPI handle of a device the notification is for.
- * @event: Type of the signaled event.
- * @context: PCI device object to wake up.
+ * @work: Work item to handle.
  */
-static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
+static void pci_acpi_wake_dev(struct work_struct *work)
 {
-       struct pci_dev *pci_dev = context;
+       struct acpi_device_wakeup_context *context;
+       struct pci_dev *pci_dev;
 
-       if (event != ACPI_NOTIFY_DEVICE_WAKE || !pci_dev)
-               return;
+       context = container_of(work, struct acpi_device_wakeup_context, work);
+       pci_dev = to_pci_dev(context->dev);
 
        if (pci_dev->pme_poll)
                pci_dev->pme_poll = false;
 }
 
 /**
- * pci_acpi_add_bus_pm_notifier - Register PM notifier for given PCI bus.
- * @dev: ACPI device to add the notifier for.
- * @pci_bus: PCI bus to walk checking for PME status if an event is signaled.
+ * pci_acpi_add_bus_pm_notifier - Register PM notifier for root PCI bus.
+ * @dev: PCI root bridge ACPI device.
  */
-acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev,
-                                        struct pci_bus *pci_bus)
+acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev)
 {
-       return acpi_add_pm_notifier(dev, pci_acpi_wake_bus, pci_bus);
-}
-
-/**
- * pci_acpi_remove_bus_pm_notifier - Unregister PCI bus PM notifier.
- * @dev: ACPI device to remove the notifier from.
- */
-acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev)
-{
-       return acpi_remove_pm_notifier(dev, pci_acpi_wake_bus);
+       return acpi_add_pm_notifier(dev, NULL, pci_acpi_wake_bus);
 }
 
 /**
 acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev,
                                     struct pci_dev *pci_dev)
 {
-       return acpi_add_pm_notifier(dev, pci_acpi_wake_dev, pci_dev);
-}
-
-/**
- * pci_acpi_remove_pm_notifier - Unregister PCI device PM notifier.
- * @dev: ACPI device to remove the notifier from.
- */
-acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
-{
-       return acpi_remove_pm_notifier(dev, pci_acpi_wake_dev);
+       return acpi_add_pm_notifier(dev, &pci_dev->dev, pci_acpi_wake_dev);
 }
 
 phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
 
        u8 notifier_present:1;  /* Wake-up notify handler has been installed */
 };
 
+struct acpi_device_wakeup_context {
+       struct work_struct work;
+       struct device *dev;
+};
+
 struct acpi_device_wakeup {
        acpi_handle gpe_device;
        u64 gpe_number;
        u64 sleep_state;
        struct list_head resources;
        struct acpi_device_wakeup_flags flags;
+       struct acpi_device_wakeup_context context;
+       struct wakeup_source *ws;
        int prepare_count;
 };
 
 int acpi_disable_wakeup_device_power(struct acpi_device *dev);
 
 #ifdef CONFIG_PM
-acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
-                                acpi_notify_handler handler, void *context);
-acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
-                                   acpi_notify_handler handler);
+acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,
+                                void (*work_func)(struct work_struct *work));
+acpi_status acpi_remove_pm_notifier(struct acpi_device *adev);
 int acpi_pm_device_sleep_state(struct device *, int *, int);
 #else
 static inline acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
-                                              acpi_notify_handler handler,
-                                              void *context)
+                                              struct device *dev,
+                                              void (*work_func)(struct work_struct *work))
 {
        return AE_SUPPORT;
 }
-static inline acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
-                                                 acpi_notify_handler handler)
+static inline acpi_status acpi_remove_pm_notifier(struct acpi_device *adev)
 {
        return AE_SUPPORT;
 }
 
 #include <linux/acpi.h>
 
 #ifdef CONFIG_ACPI
-extern acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev,
-                                                struct pci_bus *pci_bus);
-extern acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev);
+extern acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev);
+static inline acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev)
+{
+       return acpi_remove_pm_notifier(dev);
+}
 extern acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev,
                                             struct pci_dev *pci_dev);
-extern acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev);
+static inline acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
+{
+       return acpi_remove_pm_notifier(dev);
+}
 extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle);
 
 static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)