diff options
-rw-r--r-- | drivers/pci/pci-acpi.c | 19 | ||||
-rw-r--r-- | drivers/pci/pci.c | 40 | ||||
-rw-r--r-- | drivers/pci/pci.h | 26 |
3 files changed, 65 insertions, 20 deletions
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 056ea80ee27a..e4df71ab79b3 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c | |||
@@ -215,7 +215,6 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) | |||
215 | } | 215 | } |
216 | EXPORT_SYMBOL(pci_osc_control_set); | 216 | EXPORT_SYMBOL(pci_osc_control_set); |
217 | 217 | ||
218 | #ifdef CONFIG_ACPI_SLEEP | ||
219 | /* | 218 | /* |
220 | * _SxD returns the D-state with the highest power | 219 | * _SxD returns the D-state with the highest power |
221 | * (lowest D-state number) supported in the S-state "x". | 220 | * (lowest D-state number) supported in the S-state "x". |
@@ -259,7 +258,13 @@ static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev) | |||
259 | } | 258 | } |
260 | return PCI_POWER_ERROR; | 259 | return PCI_POWER_ERROR; |
261 | } | 260 | } |
262 | #endif | 261 | |
262 | static bool acpi_pci_power_manageable(struct pci_dev *dev) | ||
263 | { | ||
264 | acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); | ||
265 | |||
266 | return handle ? acpi_bus_power_manageable(handle) : false; | ||
267 | } | ||
263 | 268 | ||
264 | static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) | 269 | static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) |
265 | { | 270 | { |
@@ -290,6 +295,11 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
290 | return -EINVAL; | 295 | return -EINVAL; |
291 | } | 296 | } |
292 | 297 | ||
298 | static struct pci_platform_pm_ops acpi_pci_platform_pm = { | ||
299 | .is_manageable = acpi_pci_power_manageable, | ||
300 | .set_state = acpi_pci_set_power_state, | ||
301 | .choose_state = acpi_pci_choose_state, | ||
302 | }; | ||
293 | 303 | ||
294 | /* ACPI bus type */ | 304 | /* ACPI bus type */ |
295 | static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) | 305 | static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) |
@@ -341,10 +351,7 @@ static int __init acpi_pci_init(void) | |||
341 | ret = register_acpi_bus_type(&acpi_pci_bus); | 351 | ret = register_acpi_bus_type(&acpi_pci_bus); |
342 | if (ret) | 352 | if (ret) |
343 | return 0; | 353 | return 0; |
344 | #ifdef CONFIG_ACPI_SLEEP | 354 | pci_set_platform_pm(&acpi_pci_platform_pm); |
345 | platform_pci_choose_state = acpi_pci_choose_state; | ||
346 | #endif | ||
347 | platform_pci_set_power_state = acpi_pci_set_power_state; | ||
348 | return 0; | 355 | return 0; |
349 | } | 356 | } |
350 | arch_initcall(acpi_pci_init); | 357 | arch_initcall(acpi_pci_init); |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 8e8ecc1da93d..f8074525267c 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -376,7 +376,32 @@ pci_restore_bars(struct pci_dev *dev) | |||
376 | pci_update_resource(dev, &dev->resource[i], i); | 376 | pci_update_resource(dev, &dev->resource[i], i); |
377 | } | 377 | } |
378 | 378 | ||
379 | int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t); | 379 | static struct pci_platform_pm_ops *pci_platform_pm; |
380 | |||
381 | int pci_set_platform_pm(struct pci_platform_pm_ops *ops) | ||
382 | { | ||
383 | if (!ops->is_manageable || !ops->set_state || !ops->choose_state) | ||
384 | return -EINVAL; | ||
385 | pci_platform_pm = ops; | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static inline bool platform_pci_power_manageable(struct pci_dev *dev) | ||
390 | { | ||
391 | return pci_platform_pm ? pci_platform_pm->is_manageable(dev) : false; | ||
392 | } | ||
393 | |||
394 | static inline int platform_pci_set_power_state(struct pci_dev *dev, | ||
395 | pci_power_t t) | ||
396 | { | ||
397 | return pci_platform_pm ? pci_platform_pm->set_state(dev, t) : -ENOSYS; | ||
398 | } | ||
399 | |||
400 | static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev) | ||
401 | { | ||
402 | return pci_platform_pm ? | ||
403 | pci_platform_pm->choose_state(dev) : PCI_POWER_ERROR; | ||
404 | } | ||
380 | 405 | ||
381 | /** | 406 | /** |
382 | * pci_set_power_state - Set the power state of a PCI device | 407 | * pci_set_power_state - Set the power state of a PCI device |
@@ -479,8 +504,7 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
479 | * Give firmware a chance to be called, such as ACPI _PRx, _PSx | 504 | * Give firmware a chance to be called, such as ACPI _PRx, _PSx |
480 | * Firmware method after native method ? | 505 | * Firmware method after native method ? |
481 | */ | 506 | */ |
482 | if (platform_pci_set_power_state) | 507 | platform_pci_set_power_state(dev, state); |
483 | platform_pci_set_power_state(dev, state); | ||
484 | 508 | ||
485 | dev->current_state = state; | 509 | dev->current_state = state; |
486 | 510 | ||
@@ -505,8 +529,6 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
505 | return 0; | 529 | return 0; |
506 | } | 530 | } |
507 | 531 | ||
508 | pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev); | ||
509 | |||
510 | /** | 532 | /** |
511 | * pci_choose_state - Choose the power state of a PCI device | 533 | * pci_choose_state - Choose the power state of a PCI device |
512 | * @dev: PCI device to be suspended | 534 | * @dev: PCI device to be suspended |
@@ -524,11 +546,9 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) | |||
524 | if (!pci_find_capability(dev, PCI_CAP_ID_PM)) | 546 | if (!pci_find_capability(dev, PCI_CAP_ID_PM)) |
525 | return PCI_D0; | 547 | return PCI_D0; |
526 | 548 | ||
527 | if (platform_pci_choose_state) { | 549 | ret = platform_pci_choose_state(dev); |
528 | ret = platform_pci_choose_state(dev); | 550 | if (ret != PCI_POWER_ERROR) |
529 | if (ret != PCI_POWER_ERROR) | 551 | return ret; |
530 | return ret; | ||
531 | } | ||
532 | 552 | ||
533 | switch (state.event) { | 553 | switch (state.event) { |
534 | case PM_EVENT_ON: | 554 | case PM_EVENT_ON: |
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index e0eff35825a6..0cd2e719933b 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
@@ -5,10 +5,28 @@ extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); | |||
5 | extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); | 5 | extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); |
6 | extern void pci_cleanup_rom(struct pci_dev *dev); | 6 | extern void pci_cleanup_rom(struct pci_dev *dev); |
7 | 7 | ||
8 | /* Firmware callbacks */ | 8 | /** |
9 | extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev); | 9 | * Firmware PM callbacks |
10 | extern int (*platform_pci_set_power_state)(struct pci_dev *dev, | 10 | * |
11 | pci_power_t state); | 11 | * @is_manageable - returns 'true' if given device is power manageable by the |
12 | * platform firmware | ||
13 | * | ||
14 | * @set_state - invokes the platform firmware to set the device's power state | ||
15 | * | ||
16 | * @choose_state - returns PCI power state of given device preferred by the | ||
17 | * platform; to be used during system-wide transitions from a | ||
18 | * sleeping state to the working state and vice versa | ||
19 | * | ||
20 | * If given platform is generally capable of power managing PCI devices, all of | ||
21 | * these callbacks are mandatory. | ||
22 | */ | ||
23 | struct pci_platform_pm_ops { | ||
24 | bool (*is_manageable)(struct pci_dev *dev); | ||
25 | int (*set_state)(struct pci_dev *dev, pci_power_t state); | ||
26 | pci_power_t (*choose_state)(struct pci_dev *dev); | ||
27 | }; | ||
28 | |||
29 | extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops); | ||
12 | 30 | ||
13 | extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); | 31 | extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); |
14 | extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val); | 32 | extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val); |