diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/acpi/internal.h | 2 | ||||
| -rw-r--r-- | drivers/acpi/pci_bind.c | 14 | ||||
| -rw-r--r-- | drivers/acpi/pci_root.c | 8 | ||||
| -rw-r--r-- | drivers/acpi/scan.c | 1 | ||||
| -rw-r--r-- | drivers/pci/pci-acpi.c | 211 | ||||
| -rw-r--r-- | drivers/pci/pci.c | 67 | ||||
| -rw-r--r-- | drivers/pci/pci.h | 7 |
7 files changed, 307 insertions, 3 deletions
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index cb28e0502acc..9c4c962e46e3 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h | |||
| @@ -36,8 +36,6 @@ static inline int acpi_debug_init(void) { return 0; } | |||
| 36 | int acpi_power_init(void); | 36 | int acpi_power_init(void); |
| 37 | int acpi_device_sleep_wake(struct acpi_device *dev, | 37 | int acpi_device_sleep_wake(struct acpi_device *dev, |
| 38 | int enable, int sleep_state, int dev_state); | 38 | int enable, int sleep_state, int dev_state); |
| 39 | int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state); | ||
| 40 | int acpi_disable_wakeup_device_power(struct acpi_device *dev); | ||
| 41 | int acpi_power_get_inferred_state(struct acpi_device *device); | 39 | int acpi_power_get_inferred_state(struct acpi_device *device); |
| 42 | int acpi_power_transition(struct acpi_device *device, int state); | 40 | int acpi_power_transition(struct acpi_device *device, int state); |
| 43 | extern int acpi_power_nocheck; | 41 | extern int acpi_power_nocheck; |
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index a5a77b78a723..2ef04098cc1d 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c | |||
| @@ -26,7 +26,9 @@ | |||
| 26 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
| 27 | #include <linux/types.h> | 27 | #include <linux/types.h> |
| 28 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
| 29 | #include <linux/pci-acpi.h> | ||
| 29 | #include <linux/acpi.h> | 30 | #include <linux/acpi.h> |
| 31 | #include <linux/pm_runtime.h> | ||
| 30 | #include <acpi/acpi_bus.h> | 32 | #include <acpi/acpi_bus.h> |
| 31 | #include <acpi/acpi_drivers.h> | 33 | #include <acpi/acpi_drivers.h> |
| 32 | 34 | ||
| @@ -38,7 +40,13 @@ static int acpi_pci_unbind(struct acpi_device *device) | |||
| 38 | struct pci_dev *dev; | 40 | struct pci_dev *dev; |
| 39 | 41 | ||
| 40 | dev = acpi_get_pci_dev(device->handle); | 42 | dev = acpi_get_pci_dev(device->handle); |
| 41 | if (!dev || !dev->subordinate) | 43 | if (!dev) |
| 44 | goto out; | ||
| 45 | |||
| 46 | device_set_run_wake(&dev->dev, false); | ||
| 47 | pci_acpi_remove_pm_notifier(device); | ||
| 48 | |||
| 49 | if (!dev->subordinate) | ||
| 42 | goto out; | 50 | goto out; |
| 43 | 51 | ||
| 44 | acpi_pci_irq_del_prt(dev->subordinate); | 52 | acpi_pci_irq_del_prt(dev->subordinate); |
| @@ -62,6 +70,10 @@ static int acpi_pci_bind(struct acpi_device *device) | |||
| 62 | if (!dev) | 70 | if (!dev) |
| 63 | return 0; | 71 | return 0; |
| 64 | 72 | ||
| 73 | pci_acpi_add_pm_notifier(device, dev); | ||
| 74 | if (device->wakeup.flags.run_wake) | ||
| 75 | device_set_run_wake(&dev->dev, true); | ||
| 76 | |||
| 65 | /* | 77 | /* |
| 66 | * Install the 'bind' function to facilitate callbacks for | 78 | * Install the 'bind' function to facilitate callbacks for |
| 67 | * children of the P2P bridge. | 79 | * children of the P2P bridge. |
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 64f55b6db73c..9cd8bedb1e5a 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <linux/proc_fs.h> | 30 | #include <linux/proc_fs.h> |
| 31 | #include <linux/spinlock.h> | 31 | #include <linux/spinlock.h> |
| 32 | #include <linux/pm.h> | 32 | #include <linux/pm.h> |
| 33 | #include <linux/pm_runtime.h> | ||
| 33 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
| 34 | #include <linux/pci-acpi.h> | 35 | #include <linux/pci-acpi.h> |
| 35 | #include <linux/acpi.h> | 36 | #include <linux/acpi.h> |
| @@ -528,6 +529,10 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) | |||
| 528 | if (flags != base_flags) | 529 | if (flags != base_flags) |
| 529 | acpi_pci_osc_support(root, flags); | 530 | acpi_pci_osc_support(root, flags); |
| 530 | 531 | ||
| 532 | pci_acpi_add_bus_pm_notifier(device, root->bus); | ||
| 533 | if (device->wakeup.flags.run_wake) | ||
| 534 | device_set_run_wake(root->bus->bridge, true); | ||
| 535 | |||
| 531 | return 0; | 536 | return 0; |
| 532 | 537 | ||
| 533 | end: | 538 | end: |
| @@ -549,6 +554,9 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type) | |||
| 549 | { | 554 | { |
| 550 | struct acpi_pci_root *root = acpi_driver_data(device); | 555 | struct acpi_pci_root *root = acpi_driver_data(device); |
| 551 | 556 | ||
| 557 | device_set_run_wake(root->bus->bridge, false); | ||
| 558 | pci_acpi_remove_bus_pm_notifier(device); | ||
| 559 | |||
| 552 | kfree(root); | 560 | kfree(root); |
| 553 | return 0; | 561 | return 0; |
| 554 | } | 562 | } |
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 7491a52ad97a..fb7fc24fe727 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
| @@ -753,6 +753,7 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) | |||
| 753 | acpi_event_status event_status; | 753 | acpi_event_status event_status; |
| 754 | 754 | ||
| 755 | device->wakeup.run_wake_count = 0; | 755 | device->wakeup.run_wake_count = 0; |
| 756 | device->wakeup.flags.notifier_present = 0; | ||
| 756 | 757 | ||
| 757 | /* Power button, Lid switch always enable wakeup */ | 758 | /* Power button, Lid switch always enable wakeup */ |
| 758 | if (!acpi_match_device_ids(device, button_device_ids)) { | 759 | if (!acpi_match_device_ids(device, button_device_ids)) { |
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 7e2829538a4c..c0c73913833d 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c | |||
| @@ -16,8 +16,144 @@ | |||
| 16 | #include <acpi/acpi_bus.h> | 16 | #include <acpi/acpi_bus.h> |
| 17 | 17 | ||
| 18 | #include <linux/pci-acpi.h> | 18 | #include <linux/pci-acpi.h> |
| 19 | #include <linux/pm_runtime.h> | ||
| 19 | #include "pci.h" | 20 | #include "pci.h" |
| 20 | 21 | ||
| 22 | static DEFINE_MUTEX(pci_acpi_pm_notify_mtx); | ||
| 23 | |||
| 24 | /** | ||
| 25 | * pci_acpi_wake_bus - Wake-up notification handler for root buses. | ||
| 26 | * @handle: ACPI handle of a device the notification is for. | ||
| 27 | * @event: Type of the signaled event. | ||
| 28 | * @context: PCI root bus to wake up devices on. | ||
| 29 | */ | ||
| 30 | static void pci_acpi_wake_bus(acpi_handle handle, u32 event, void *context) | ||
| 31 | { | ||
| 32 | struct pci_bus *pci_bus = context; | ||
| 33 | |||
| 34 | if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_bus) | ||
| 35 | pci_pme_wakeup_bus(pci_bus); | ||
| 36 | } | ||
| 37 | |||
| 38 | /** | ||
| 39 | * pci_acpi_wake_dev - Wake-up notification handler for PCI devices. | ||
| 40 | * @handle: ACPI handle of a device the notification is for. | ||
| 41 | * @event: Type of the signaled event. | ||
| 42 | * @context: PCI device object to wake up. | ||
| 43 | */ | ||
| 44 | static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context) | ||
| 45 | { | ||
| 46 | struct pci_dev *pci_dev = context; | ||
| 47 | |||
| 48 | if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_dev) { | ||
| 49 | pci_check_pme_status(pci_dev); | ||
| 50 | pm_runtime_resume(&pci_dev->dev); | ||
| 51 | if (pci_dev->subordinate) | ||
| 52 | pci_pme_wakeup_bus(pci_dev->subordinate); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | /** | ||
| 57 | * add_pm_notifier - Register PM notifier for given ACPI device. | ||
| 58 | * @dev: ACPI device to add the notifier for. | ||
| 59 | * @context: PCI device or bus to check for PME status if an event is signaled. | ||
| 60 | * | ||
| 61 | * NOTE: @dev need not be a run-wake or wake-up device to be a valid source of | ||
| 62 | * PM wake-up events. For example, wake-up events may be generated for bridges | ||
| 63 | * if one of the devices below the bridge is signaling PME, even if the bridge | ||
| 64 | * itself doesn't have a wake-up GPE associated with it. | ||
| 65 | */ | ||
| 66 | static acpi_status add_pm_notifier(struct acpi_device *dev, | ||
| 67 | acpi_notify_handler handler, | ||
| 68 | void *context) | ||
| 69 | { | ||
| 70 | acpi_status status = AE_ALREADY_EXISTS; | ||
| 71 | |||
| 72 | mutex_lock(&pci_acpi_pm_notify_mtx); | ||
| 73 | |||
| 74 | if (dev->wakeup.flags.notifier_present) | ||
| 75 | goto out; | ||
| 76 | |||
| 77 | status = acpi_install_notify_handler(dev->handle, | ||
| 78 | ACPI_SYSTEM_NOTIFY, | ||
| 79 | handler, context); | ||
| 80 | if (ACPI_FAILURE(status)) | ||
| 81 | goto out; | ||
| 82 | |||
| 83 | dev->wakeup.flags.notifier_present = true; | ||
| 84 | |||
| 85 | out: | ||
| 86 | mutex_unlock(&pci_acpi_pm_notify_mtx); | ||
| 87 | return status; | ||
| 88 | } | ||
| 89 | |||
| 90 | /** | ||
| 91 | * remove_pm_notifier - Unregister PM notifier from given ACPI device. | ||
| 92 | * @dev: ACPI device to remove the notifier from. | ||
| 93 | */ | ||
| 94 | static acpi_status remove_pm_notifier(struct acpi_device *dev, | ||
| 95 | acpi_notify_handler handler) | ||
| 96 | { | ||
| 97 | acpi_status status = AE_BAD_PARAMETER; | ||
| 98 | |||
| 99 | mutex_lock(&pci_acpi_pm_notify_mtx); | ||
| 100 | |||
| 101 | if (!dev->wakeup.flags.notifier_present) | ||
| 102 | goto out; | ||
| 103 | |||
| 104 | status = acpi_remove_notify_handler(dev->handle, | ||
| 105 | ACPI_SYSTEM_NOTIFY, | ||
| 106 | handler); | ||
| 107 | if (ACPI_FAILURE(status)) | ||
| 108 | goto out; | ||
| 109 | |||
| 110 | dev->wakeup.flags.notifier_present = false; | ||
| 111 | |||
| 112 | out: | ||
| 113 | mutex_unlock(&pci_acpi_pm_notify_mtx); | ||
| 114 | return status; | ||
| 115 | } | ||
| 116 | |||
| 117 | /** | ||
| 118 | * pci_acpi_add_bus_pm_notifier - Register PM notifier for given PCI bus. | ||
| 119 | * @dev: ACPI device to add the notifier for. | ||
| 120 | * @pci_bus: PCI bus to walk checking for PME status if an event is signaled. | ||
| 121 | */ | ||
| 122 | acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev, | ||
| 123 | struct pci_bus *pci_bus) | ||
| 124 | { | ||
| 125 | return add_pm_notifier(dev, pci_acpi_wake_bus, pci_bus); | ||
| 126 | } | ||
| 127 | |||
| 128 | /** | ||
| 129 | * pci_acpi_remove_bus_pm_notifier - Unregister PCI bus PM notifier. | ||
| 130 | * @dev: ACPI device to remove the notifier from. | ||
| 131 | */ | ||
| 132 | acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev) | ||
| 133 | { | ||
| 134 | return remove_pm_notifier(dev, pci_acpi_wake_bus); | ||
| 135 | } | ||
| 136 | |||
| 137 | /** | ||
| 138 | * pci_acpi_add_pm_notifier - Register PM notifier for given PCI device. | ||
| 139 | * @dev: ACPI device to add the notifier for. | ||
| 140 | * @pci_dev: PCI device to check for the PME status if an event is signaled. | ||
| 141 | */ | ||
| 142 | acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev, | ||
| 143 | struct pci_dev *pci_dev) | ||
| 144 | { | ||
| 145 | return add_pm_notifier(dev, pci_acpi_wake_dev, pci_dev); | ||
| 146 | } | ||
| 147 | |||
| 148 | /** | ||
| 149 | * pci_acpi_remove_pm_notifier - Unregister PCI device PM notifier. | ||
| 150 | * @dev: ACPI device to remove the notifier from. | ||
| 151 | */ | ||
| 152 | acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev) | ||
| 153 | { | ||
| 154 | return remove_pm_notifier(dev, pci_acpi_wake_dev); | ||
| 155 | } | ||
| 156 | |||
| 21 | /* | 157 | /* |
| 22 | * _SxD returns the D-state with the highest power | 158 | * _SxD returns the D-state with the highest power |
| 23 | * (lowest D-state number) supported in the S-state "x". | 159 | * (lowest D-state number) supported in the S-state "x". |
| @@ -131,12 +267,87 @@ static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) | |||
| 131 | return 0; | 267 | return 0; |
| 132 | } | 268 | } |
| 133 | 269 | ||
| 270 | /** | ||
| 271 | * acpi_dev_run_wake - Enable/disable wake-up for given device. | ||
| 272 | * @phys_dev: Device to enable/disable the platform to wake-up the system for. | ||
| 273 | * @enable: Whether enable or disable the wake-up functionality. | ||
| 274 | * | ||
| 275 | * Find the ACPI device object corresponding to @pci_dev and try to | ||
| 276 | * enable/disable the GPE associated with it. | ||
| 277 | */ | ||
| 278 | static int acpi_dev_run_wake(struct device *phys_dev, bool enable) | ||
| 279 | { | ||
| 280 | struct acpi_device *dev; | ||
| 281 | acpi_handle handle; | ||
| 282 | int error = -ENODEV; | ||
| 283 | |||
| 284 | if (!device_run_wake(phys_dev)) | ||
| 285 | return -EINVAL; | ||
| 286 | |||
| 287 | handle = DEVICE_ACPI_HANDLE(phys_dev); | ||
| 288 | if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &dev))) { | ||
| 289 | dev_dbg(phys_dev, "ACPI handle has no context in %s!\n", | ||
| 290 | __func__); | ||
| 291 | return -ENODEV; | ||
| 292 | } | ||
| 293 | |||
| 294 | if (enable) { | ||
| 295 | if (!dev->wakeup.run_wake_count++) { | ||
| 296 | acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0); | ||
| 297 | acpi_enable_gpe(dev->wakeup.gpe_device, | ||
| 298 | dev->wakeup.gpe_number, | ||
| 299 | ACPI_GPE_TYPE_RUNTIME); | ||
| 300 | } | ||
| 301 | } else if (dev->wakeup.run_wake_count > 0) { | ||
| 302 | if (!--dev->wakeup.run_wake_count) { | ||
| 303 | acpi_disable_gpe(dev->wakeup.gpe_device, | ||
| 304 | dev->wakeup.gpe_number, | ||
| 305 | ACPI_GPE_TYPE_RUNTIME); | ||
| 306 | acpi_disable_wakeup_device_power(dev); | ||
| 307 | } | ||
| 308 | } else { | ||
| 309 | error = -EALREADY; | ||
| 310 | } | ||
| 311 | |||
| 312 | return error; | ||
| 313 | } | ||
| 314 | |||
| 315 | static void acpi_pci_propagate_run_wake(struct pci_bus *bus, bool enable) | ||
| 316 | { | ||
| 317 | while (bus->parent) { | ||
| 318 | struct pci_dev *bridge = bus->self; | ||
| 319 | |||
| 320 | if (bridge->pme_interrupt) | ||
| 321 | return; | ||
| 322 | if (!acpi_dev_run_wake(&bridge->dev, enable)) | ||
| 323 | return; | ||
| 324 | bus = bus->parent; | ||
| 325 | } | ||
| 326 | |||
| 327 | /* We have reached the root bus. */ | ||
| 328 | if (bus->bridge) | ||
| 329 | acpi_dev_run_wake(bus->bridge, enable); | ||
| 330 | } | ||
| 331 | |||
| 332 | static int acpi_pci_run_wake(struct pci_dev *dev, bool enable) | ||
| 333 | { | ||
| 334 | if (dev->pme_interrupt) | ||
| 335 | return 0; | ||
| 336 | |||
| 337 | if (!acpi_dev_run_wake(&dev->dev, enable)) | ||
| 338 | return 0; | ||
| 339 | |||
| 340 | acpi_pci_propagate_run_wake(dev->bus, enable); | ||
| 341 | return 0; | ||
| 342 | } | ||
| 343 | |||
| 134 | static struct pci_platform_pm_ops acpi_pci_platform_pm = { | 344 | static struct pci_platform_pm_ops acpi_pci_platform_pm = { |
| 135 | .is_manageable = acpi_pci_power_manageable, | 345 | .is_manageable = acpi_pci_power_manageable, |
| 136 | .set_state = acpi_pci_set_power_state, | 346 | .set_state = acpi_pci_set_power_state, |
| 137 | .choose_state = acpi_pci_choose_state, | 347 | .choose_state = acpi_pci_choose_state, |
| 138 | .can_wakeup = acpi_pci_can_wakeup, | 348 | .can_wakeup = acpi_pci_can_wakeup, |
| 139 | .sleep_wake = acpi_pci_sleep_wake, | 349 | .sleep_wake = acpi_pci_sleep_wake, |
| 350 | .run_wake = acpi_pci_run_wake, | ||
| 140 | }; | 351 | }; |
| 141 | 352 | ||
| 142 | /* ACPI bus type */ | 353 | /* ACPI bus type */ |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 5723446544fd..df55a2f351b3 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/pm_wakeup.h> | 20 | #include <linux/pm_wakeup.h> |
| 21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
| 22 | #include <linux/device.h> | 22 | #include <linux/device.h> |
| 23 | #include <linux/pm_runtime.h> | ||
| 23 | #include <asm/setup.h> | 24 | #include <asm/setup.h> |
| 24 | #include "pci.h" | 25 | #include "pci.h" |
| 25 | 26 | ||
| @@ -462,6 +463,12 @@ static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable) | |||
| 462 | pci_platform_pm->sleep_wake(dev, enable) : -ENODEV; | 463 | pci_platform_pm->sleep_wake(dev, enable) : -ENODEV; |
| 463 | } | 464 | } |
| 464 | 465 | ||
| 466 | static inline int platform_pci_run_wake(struct pci_dev *dev, bool enable) | ||
| 467 | { | ||
| 468 | return pci_platform_pm ? | ||
| 469 | pci_platform_pm->run_wake(dev, enable) : -ENODEV; | ||
| 470 | } | ||
| 471 | |||
| 465 | /** | 472 | /** |
| 466 | * pci_raw_set_power_state - Use PCI PM registers to set the power state of | 473 | * pci_raw_set_power_state - Use PCI PM registers to set the power state of |
| 467 | * given PCI device | 474 | * given PCI device |
| @@ -1230,6 +1237,31 @@ bool pci_check_pme_status(struct pci_dev *dev) | |||
| 1230 | } | 1237 | } |
| 1231 | 1238 | ||
| 1232 | /** | 1239 | /** |
| 1240 | * pci_pme_wakeup - Wake up a PCI device if its PME Status bit is set. | ||
| 1241 | * @dev: Device to handle. | ||
| 1242 | * @ign: Ignored. | ||
| 1243 | * | ||
| 1244 | * Check if @dev has generated PME and queue a resume request for it in that | ||
| 1245 | * case. | ||
| 1246 | */ | ||
| 1247 | static int pci_pme_wakeup(struct pci_dev *dev, void *ign) | ||
| 1248 | { | ||
| 1249 | if (pci_check_pme_status(dev)) | ||
| 1250 | pm_request_resume(&dev->dev); | ||
| 1251 | return 0; | ||
| 1252 | } | ||
| 1253 | |||
| 1254 | /** | ||
| 1255 | * pci_pme_wakeup_bus - Walk given bus and wake up devices on it, if necessary. | ||
| 1256 | * @bus: Top bus of the subtree to walk. | ||
| 1257 | */ | ||
| 1258 | void pci_pme_wakeup_bus(struct pci_bus *bus) | ||
| 1259 | { | ||
| 1260 | if (bus) | ||
| 1261 | pci_walk_bus(bus, pci_pme_wakeup, NULL); | ||
| 1262 | } | ||
| 1263 | |||
| 1264 | /** | ||
| 1233 | * pci_pme_capable - check the capability of PCI device to generate PME# | 1265 | * pci_pme_capable - check the capability of PCI device to generate PME# |
| 1234 | * @dev: PCI device to handle. | 1266 | * @dev: PCI device to handle. |
| 1235 | * @state: PCI state from which device will issue PME#. | 1267 | * @state: PCI state from which device will issue PME#. |
| @@ -1434,6 +1466,41 @@ int pci_back_from_sleep(struct pci_dev *dev) | |||
| 1434 | } | 1466 | } |
| 1435 | 1467 | ||
| 1436 | /** | 1468 | /** |
| 1469 | * pci_dev_run_wake - Check if device can generate run-time wake-up events. | ||
| 1470 | * @dev: Device to check. | ||
| 1471 | * | ||
| 1472 | * Return true if the device itself is cabable of generating wake-up events | ||
| 1473 | * (through the platform or using the native PCIe PME) or if the device supports | ||
| 1474 | * PME and one of its upstream bridges can generate wake-up events. | ||
| 1475 | */ | ||
| 1476 | bool pci_dev_run_wake(struct pci_dev *dev) | ||
| 1477 | { | ||
| 1478 | struct pci_bus *bus = dev->bus; | ||
| 1479 | |||
| 1480 | if (device_run_wake(&dev->dev)) | ||
| 1481 | return true; | ||
| 1482 | |||
| 1483 | if (!dev->pme_support) | ||
| 1484 | return false; | ||
| 1485 | |||
| 1486 | while (bus->parent) { | ||
| 1487 | struct pci_dev *bridge = bus->self; | ||
| 1488 | |||
| 1489 | if (device_run_wake(&bridge->dev)) | ||
| 1490 | return true; | ||
| 1491 | |||
| 1492 | bus = bus->parent; | ||
| 1493 | } | ||
| 1494 | |||
| 1495 | /* We have reached the root bus. */ | ||
| 1496 | if (bus->bridge) | ||
| 1497 | return device_run_wake(bus->bridge); | ||
| 1498 | |||
| 1499 | return false; | ||
| 1500 | } | ||
| 1501 | EXPORT_SYMBOL_GPL(pci_dev_run_wake); | ||
| 1502 | |||
| 1503 | /** | ||
| 1437 | * pci_pm_init - Initialize PM functions of given PCI device | 1504 | * pci_pm_init - Initialize PM functions of given PCI device |
| 1438 | * @dev: PCI device to handle. | 1505 | * @dev: PCI device to handle. |
| 1439 | */ | 1506 | */ |
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index b95b0a077d31..286c50821949 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
| @@ -35,6 +35,10 @@ int pci_probe_reset_function(struct pci_dev *dev); | |||
| 35 | * | 35 | * |
| 36 | * @sleep_wake: enables/disables the system wake up capability of given device | 36 | * @sleep_wake: enables/disables the system wake up capability of given device |
| 37 | * | 37 | * |
| 38 | * @run_wake: enables/disables the platform to generate run-time wake-up events | ||
| 39 | * for given device (the device's wake-up capability has to be | ||
| 40 | * enabled by @sleep_wake for this feature to work) | ||
| 41 | * | ||
| 38 | * If given platform is generally capable of power managing PCI devices, all of | 42 | * If given platform is generally capable of power managing PCI devices, all of |
| 39 | * these callbacks are mandatory. | 43 | * these callbacks are mandatory. |
| 40 | */ | 44 | */ |
| @@ -44,12 +48,15 @@ struct pci_platform_pm_ops { | |||
| 44 | pci_power_t (*choose_state)(struct pci_dev *dev); | 48 | pci_power_t (*choose_state)(struct pci_dev *dev); |
| 45 | bool (*can_wakeup)(struct pci_dev *dev); | 49 | bool (*can_wakeup)(struct pci_dev *dev); |
| 46 | int (*sleep_wake)(struct pci_dev *dev, bool enable); | 50 | int (*sleep_wake)(struct pci_dev *dev, bool enable); |
| 51 | int (*run_wake)(struct pci_dev *dev, bool enable); | ||
| 47 | }; | 52 | }; |
| 48 | 53 | ||
| 49 | extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops); | 54 | extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops); |
| 50 | extern void pci_update_current_state(struct pci_dev *dev, pci_power_t state); | 55 | extern void pci_update_current_state(struct pci_dev *dev, pci_power_t state); |
| 51 | extern void pci_disable_enabled_device(struct pci_dev *dev); | 56 | extern void pci_disable_enabled_device(struct pci_dev *dev); |
| 52 | extern bool pci_check_pme_status(struct pci_dev *dev); | 57 | extern bool pci_check_pme_status(struct pci_dev *dev); |
| 58 | extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign); | ||
| 59 | extern void pci_pme_wakeup_bus(struct pci_bus *bus); | ||
| 53 | extern void pci_pm_init(struct pci_dev *dev); | 60 | extern void pci_pm_init(struct pci_dev *dev); |
| 54 | extern void platform_pci_wakeup_init(struct pci_dev *dev); | 61 | extern void platform_pci_wakeup_init(struct pci_dev *dev); |
| 55 | extern void pci_allocate_cap_save_buffers(struct pci_dev *dev); | 62 | extern void pci_allocate_cap_save_buffers(struct pci_dev *dev); |
