diff options
Diffstat (limited to 'drivers/pci')
-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 |
3 files changed, 285 insertions, 0 deletions
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); |