diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pci-driver.c | 160 | ||||
-rw-r--r-- | drivers/pci/pci.c | 43 | ||||
-rw-r--r-- | drivers/pci/pci.h | 1 |
3 files changed, 171 insertions, 33 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index e5d47be3c6d7..f9a0aec3abcf 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
19 | #include <linux/cpu.h> | 19 | #include <linux/cpu.h> |
20 | #include <linux/pm_runtime.h> | ||
20 | #include "pci.h" | 21 | #include "pci.h" |
21 | 22 | ||
22 | struct pci_dynid { | 23 | struct pci_dynid { |
@@ -404,6 +405,35 @@ static void pci_device_shutdown(struct device *dev) | |||
404 | pci_msix_shutdown(pci_dev); | 405 | pci_msix_shutdown(pci_dev); |
405 | } | 406 | } |
406 | 407 | ||
408 | #ifdef CONFIG_PM_OPS | ||
409 | |||
410 | /* Auxiliary functions used for system resume and run-time resume. */ | ||
411 | |||
412 | /** | ||
413 | * pci_restore_standard_config - restore standard config registers of PCI device | ||
414 | * @pci_dev: PCI device to handle | ||
415 | */ | ||
416 | static int pci_restore_standard_config(struct pci_dev *pci_dev) | ||
417 | { | ||
418 | pci_update_current_state(pci_dev, PCI_UNKNOWN); | ||
419 | |||
420 | if (pci_dev->current_state != PCI_D0) { | ||
421 | int error = pci_set_power_state(pci_dev, PCI_D0); | ||
422 | if (error) | ||
423 | return error; | ||
424 | } | ||
425 | |||
426 | return pci_restore_state(pci_dev); | ||
427 | } | ||
428 | |||
429 | static void pci_pm_default_resume_early(struct pci_dev *pci_dev) | ||
430 | { | ||
431 | pci_restore_standard_config(pci_dev); | ||
432 | pci_fixup_device(pci_fixup_resume_early, pci_dev); | ||
433 | } | ||
434 | |||
435 | #endif | ||
436 | |||
407 | #ifdef CONFIG_PM_SLEEP | 437 | #ifdef CONFIG_PM_SLEEP |
408 | 438 | ||
409 | /* | 439 | /* |
@@ -520,29 +550,6 @@ static int pci_legacy_resume(struct device *dev) | |||
520 | 550 | ||
521 | /* Auxiliary functions used by the new power management framework */ | 551 | /* Auxiliary functions used by the new power management framework */ |
522 | 552 | ||
523 | /** | ||
524 | * pci_restore_standard_config - restore standard config registers of PCI device | ||
525 | * @pci_dev: PCI device to handle | ||
526 | */ | ||
527 | static int pci_restore_standard_config(struct pci_dev *pci_dev) | ||
528 | { | ||
529 | pci_update_current_state(pci_dev, PCI_UNKNOWN); | ||
530 | |||
531 | if (pci_dev->current_state != PCI_D0) { | ||
532 | int error = pci_set_power_state(pci_dev, PCI_D0); | ||
533 | if (error) | ||
534 | return error; | ||
535 | } | ||
536 | |||
537 | return pci_restore_state(pci_dev); | ||
538 | } | ||
539 | |||
540 | static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev) | ||
541 | { | ||
542 | pci_restore_standard_config(pci_dev); | ||
543 | pci_fixup_device(pci_fixup_resume_early, pci_dev); | ||
544 | } | ||
545 | |||
546 | static void pci_pm_default_resume(struct pci_dev *pci_dev) | 553 | static void pci_pm_default_resume(struct pci_dev *pci_dev) |
547 | { | 554 | { |
548 | pci_fixup_device(pci_fixup_resume, pci_dev); | 555 | pci_fixup_device(pci_fixup_resume, pci_dev); |
@@ -581,6 +588,17 @@ static int pci_pm_prepare(struct device *dev) | |||
581 | struct device_driver *drv = dev->driver; | 588 | struct device_driver *drv = dev->driver; |
582 | int error = 0; | 589 | int error = 0; |
583 | 590 | ||
591 | /* | ||
592 | * PCI devices suspended at run time need to be resumed at this | ||
593 | * point, because in general it is necessary to reconfigure them for | ||
594 | * system suspend. Namely, if the device is supposed to wake up the | ||
595 | * system from the sleep state, we may need to reconfigure it for this | ||
596 | * purpose. In turn, if the device is not supposed to wake up the | ||
597 | * system from the sleep state, we'll have to prevent it from signaling | ||
598 | * wake-up. | ||
599 | */ | ||
600 | pm_runtime_resume(dev); | ||
601 | |||
584 | if (drv && drv->pm && drv->pm->prepare) | 602 | if (drv && drv->pm && drv->pm->prepare) |
585 | error = drv->pm->prepare(dev); | 603 | error = drv->pm->prepare(dev); |
586 | 604 | ||
@@ -595,6 +613,13 @@ static void pci_pm_complete(struct device *dev) | |||
595 | drv->pm->complete(dev); | 613 | drv->pm->complete(dev); |
596 | } | 614 | } |
597 | 615 | ||
616 | #else /* !CONFIG_PM_SLEEP */ | ||
617 | |||
618 | #define pci_pm_prepare NULL | ||
619 | #define pci_pm_complete NULL | ||
620 | |||
621 | #endif /* !CONFIG_PM_SLEEP */ | ||
622 | |||
598 | #ifdef CONFIG_SUSPEND | 623 | #ifdef CONFIG_SUSPEND |
599 | 624 | ||
600 | static int pci_pm_suspend(struct device *dev) | 625 | static int pci_pm_suspend(struct device *dev) |
@@ -681,7 +706,7 @@ static int pci_pm_resume_noirq(struct device *dev) | |||
681 | struct device_driver *drv = dev->driver; | 706 | struct device_driver *drv = dev->driver; |
682 | int error = 0; | 707 | int error = 0; |
683 | 708 | ||
684 | pci_pm_default_resume_noirq(pci_dev); | 709 | pci_pm_default_resume_early(pci_dev); |
685 | 710 | ||
686 | if (pci_has_legacy_pm_support(pci_dev)) | 711 | if (pci_has_legacy_pm_support(pci_dev)) |
687 | return pci_legacy_resume_early(dev); | 712 | return pci_legacy_resume_early(dev); |
@@ -879,7 +904,7 @@ static int pci_pm_restore_noirq(struct device *dev) | |||
879 | struct device_driver *drv = dev->driver; | 904 | struct device_driver *drv = dev->driver; |
880 | int error = 0; | 905 | int error = 0; |
881 | 906 | ||
882 | pci_pm_default_resume_noirq(pci_dev); | 907 | pci_pm_default_resume_early(pci_dev); |
883 | 908 | ||
884 | if (pci_has_legacy_pm_support(pci_dev)) | 909 | if (pci_has_legacy_pm_support(pci_dev)) |
885 | return pci_legacy_resume_early(dev); | 910 | return pci_legacy_resume_early(dev); |
@@ -931,6 +956,84 @@ static int pci_pm_restore(struct device *dev) | |||
931 | 956 | ||
932 | #endif /* !CONFIG_HIBERNATION */ | 957 | #endif /* !CONFIG_HIBERNATION */ |
933 | 958 | ||
959 | #ifdef CONFIG_PM_RUNTIME | ||
960 | |||
961 | static int pci_pm_runtime_suspend(struct device *dev) | ||
962 | { | ||
963 | struct pci_dev *pci_dev = to_pci_dev(dev); | ||
964 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | ||
965 | pci_power_t prev = pci_dev->current_state; | ||
966 | int error; | ||
967 | |||
968 | if (!pm || !pm->runtime_suspend) | ||
969 | return -ENOSYS; | ||
970 | |||
971 | error = pm->runtime_suspend(dev); | ||
972 | suspend_report_result(pm->runtime_suspend, error); | ||
973 | if (error) | ||
974 | return error; | ||
975 | |||
976 | pci_fixup_device(pci_fixup_suspend, pci_dev); | ||
977 | |||
978 | if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0 | ||
979 | && pci_dev->current_state != PCI_UNKNOWN) { | ||
980 | WARN_ONCE(pci_dev->current_state != prev, | ||
981 | "PCI PM: State of device not saved by %pF\n", | ||
982 | pm->runtime_suspend); | ||
983 | return 0; | ||
984 | } | ||
985 | |||
986 | if (!pci_dev->state_saved) | ||
987 | pci_save_state(pci_dev); | ||
988 | |||
989 | pci_finish_runtime_suspend(pci_dev); | ||
990 | |||
991 | return 0; | ||
992 | } | ||
993 | |||
994 | static int pci_pm_runtime_resume(struct device *dev) | ||
995 | { | ||
996 | struct pci_dev *pci_dev = to_pci_dev(dev); | ||
997 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | ||
998 | |||
999 | if (!pm || !pm->runtime_resume) | ||
1000 | return -ENOSYS; | ||
1001 | |||
1002 | pci_pm_default_resume_early(pci_dev); | ||
1003 | __pci_enable_wake(pci_dev, PCI_D0, true, false); | ||
1004 | pci_fixup_device(pci_fixup_resume, pci_dev); | ||
1005 | |||
1006 | return pm->runtime_resume(dev); | ||
1007 | } | ||
1008 | |||
1009 | static int pci_pm_runtime_idle(struct device *dev) | ||
1010 | { | ||
1011 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | ||
1012 | |||
1013 | if (!pm) | ||
1014 | return -ENOSYS; | ||
1015 | |||
1016 | if (pm->runtime_idle) { | ||
1017 | int ret = pm->runtime_idle(dev); | ||
1018 | if (ret) | ||
1019 | return ret; | ||
1020 | } | ||
1021 | |||
1022 | pm_runtime_suspend(dev); | ||
1023 | |||
1024 | return 0; | ||
1025 | } | ||
1026 | |||
1027 | #else /* !CONFIG_PM_RUNTIME */ | ||
1028 | |||
1029 | #define pci_pm_runtime_suspend NULL | ||
1030 | #define pci_pm_runtime_resume NULL | ||
1031 | #define pci_pm_runtime_idle NULL | ||
1032 | |||
1033 | #endif /* !CONFIG_PM_RUNTIME */ | ||
1034 | |||
1035 | #ifdef CONFIG_PM_OPS | ||
1036 | |||
934 | const struct dev_pm_ops pci_dev_pm_ops = { | 1037 | const struct dev_pm_ops pci_dev_pm_ops = { |
935 | .prepare = pci_pm_prepare, | 1038 | .prepare = pci_pm_prepare, |
936 | .complete = pci_pm_complete, | 1039 | .complete = pci_pm_complete, |
@@ -946,15 +1049,18 @@ const struct dev_pm_ops pci_dev_pm_ops = { | |||
946 | .thaw_noirq = pci_pm_thaw_noirq, | 1049 | .thaw_noirq = pci_pm_thaw_noirq, |
947 | .poweroff_noirq = pci_pm_poweroff_noirq, | 1050 | .poweroff_noirq = pci_pm_poweroff_noirq, |
948 | .restore_noirq = pci_pm_restore_noirq, | 1051 | .restore_noirq = pci_pm_restore_noirq, |
1052 | .runtime_suspend = pci_pm_runtime_suspend, | ||
1053 | .runtime_resume = pci_pm_runtime_resume, | ||
1054 | .runtime_idle = pci_pm_runtime_idle, | ||
949 | }; | 1055 | }; |
950 | 1056 | ||
951 | #define PCI_PM_OPS_PTR (&pci_dev_pm_ops) | 1057 | #define PCI_PM_OPS_PTR (&pci_dev_pm_ops) |
952 | 1058 | ||
953 | #else /* !CONFIG_PM_SLEEP */ | 1059 | #else /* !COMFIG_PM_OPS */ |
954 | 1060 | ||
955 | #define PCI_PM_OPS_PTR NULL | 1061 | #define PCI_PM_OPS_PTR NULL |
956 | 1062 | ||
957 | #endif /* !CONFIG_PM_SLEEP */ | 1063 | #endif /* !COMFIG_PM_OPS */ |
958 | 1064 | ||
959 | /** | 1065 | /** |
960 | * __pci_register_driver - register a new pci driver | 1066 | * __pci_register_driver - register a new pci driver |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index df55a2f351b3..d62a5de81672 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -1302,9 +1302,10 @@ void pci_pme_active(struct pci_dev *dev, bool enable) | |||
1302 | } | 1302 | } |
1303 | 1303 | ||
1304 | /** | 1304 | /** |
1305 | * pci_enable_wake - enable PCI device as wakeup event source | 1305 | * __pci_enable_wake - enable PCI device as wakeup event source |
1306 | * @dev: PCI device affected | 1306 | * @dev: PCI device affected |
1307 | * @state: PCI state from which device will issue wakeup events | 1307 | * @state: PCI state from which device will issue wakeup events |
1308 | * @runtime: True if the events are to be generated at run time | ||
1308 | * @enable: True to enable event generation; false to disable | 1309 | * @enable: True to enable event generation; false to disable |
1309 | * | 1310 | * |
1310 | * This enables the device as a wakeup event source, or disables it. | 1311 | * This enables the device as a wakeup event source, or disables it. |
@@ -1320,11 +1321,12 @@ void pci_pme_active(struct pci_dev *dev, bool enable) | |||
1320 | * Error code depending on the platform is returned if both the platform and | 1321 | * Error code depending on the platform is returned if both the platform and |
1321 | * the native mechanism fail to enable the generation of wake-up events | 1322 | * the native mechanism fail to enable the generation of wake-up events |
1322 | */ | 1323 | */ |
1323 | int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) | 1324 | int __pci_enable_wake(struct pci_dev *dev, pci_power_t state, |
1325 | bool runtime, bool enable) | ||
1324 | { | 1326 | { |
1325 | int ret = 0; | 1327 | int ret = 0; |
1326 | 1328 | ||
1327 | if (enable && !device_may_wakeup(&dev->dev)) | 1329 | if (enable && !runtime && !device_may_wakeup(&dev->dev)) |
1328 | return -EINVAL; | 1330 | return -EINVAL; |
1329 | 1331 | ||
1330 | /* Don't do the same thing twice in a row for one device. */ | 1332 | /* Don't do the same thing twice in a row for one device. */ |
@@ -1344,19 +1346,24 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) | |||
1344 | pci_pme_active(dev, true); | 1346 | pci_pme_active(dev, true); |
1345 | else | 1347 | else |
1346 | ret = 1; | 1348 | ret = 1; |
1347 | error = platform_pci_sleep_wake(dev, true); | 1349 | error = runtime ? platform_pci_run_wake(dev, true) : |
1350 | platform_pci_sleep_wake(dev, true); | ||
1348 | if (ret) | 1351 | if (ret) |
1349 | ret = error; | 1352 | ret = error; |
1350 | if (!ret) | 1353 | if (!ret) |
1351 | dev->wakeup_prepared = true; | 1354 | dev->wakeup_prepared = true; |
1352 | } else { | 1355 | } else { |
1353 | platform_pci_sleep_wake(dev, false); | 1356 | if (runtime) |
1357 | platform_pci_run_wake(dev, false); | ||
1358 | else | ||
1359 | platform_pci_sleep_wake(dev, false); | ||
1354 | pci_pme_active(dev, false); | 1360 | pci_pme_active(dev, false); |
1355 | dev->wakeup_prepared = false; | 1361 | dev->wakeup_prepared = false; |
1356 | } | 1362 | } |
1357 | 1363 | ||
1358 | return ret; | 1364 | return ret; |
1359 | } | 1365 | } |
1366 | EXPORT_SYMBOL(__pci_enable_wake); | ||
1360 | 1367 | ||
1361 | /** | 1368 | /** |
1362 | * pci_wake_from_d3 - enable/disable device to wake up from D3_hot or D3_cold | 1369 | * pci_wake_from_d3 - enable/disable device to wake up from D3_hot or D3_cold |
@@ -1466,6 +1473,31 @@ int pci_back_from_sleep(struct pci_dev *dev) | |||
1466 | } | 1473 | } |
1467 | 1474 | ||
1468 | /** | 1475 | /** |
1476 | * pci_finish_runtime_suspend - Carry out PCI-specific part of runtime suspend. | ||
1477 | * @dev: PCI device being suspended. | ||
1478 | * | ||
1479 | * Prepare @dev to generate wake-up events at run time and put it into a low | ||
1480 | * power state. | ||
1481 | */ | ||
1482 | int pci_finish_runtime_suspend(struct pci_dev *dev) | ||
1483 | { | ||
1484 | pci_power_t target_state = pci_target_state(dev); | ||
1485 | int error; | ||
1486 | |||
1487 | if (target_state == PCI_POWER_ERROR) | ||
1488 | return -EIO; | ||
1489 | |||
1490 | __pci_enable_wake(dev, target_state, true, pci_dev_run_wake(dev)); | ||
1491 | |||
1492 | error = pci_set_power_state(dev, target_state); | ||
1493 | |||
1494 | if (error) | ||
1495 | __pci_enable_wake(dev, target_state, true, false); | ||
1496 | |||
1497 | return error; | ||
1498 | } | ||
1499 | |||
1500 | /** | ||
1469 | * pci_dev_run_wake - Check if device can generate run-time wake-up events. | 1501 | * pci_dev_run_wake - Check if device can generate run-time wake-up events. |
1470 | * @dev: Device to check. | 1502 | * @dev: Device to check. |
1471 | * | 1503 | * |
@@ -2978,7 +3010,6 @@ EXPORT_SYMBOL(pci_save_state); | |||
2978 | EXPORT_SYMBOL(pci_restore_state); | 3010 | EXPORT_SYMBOL(pci_restore_state); |
2979 | EXPORT_SYMBOL(pci_pme_capable); | 3011 | EXPORT_SYMBOL(pci_pme_capable); |
2980 | EXPORT_SYMBOL(pci_pme_active); | 3012 | EXPORT_SYMBOL(pci_pme_active); |
2981 | EXPORT_SYMBOL(pci_enable_wake); | ||
2982 | EXPORT_SYMBOL(pci_wake_from_d3); | 3013 | EXPORT_SYMBOL(pci_wake_from_d3); |
2983 | EXPORT_SYMBOL(pci_target_state); | 3014 | EXPORT_SYMBOL(pci_target_state); |
2984 | EXPORT_SYMBOL(pci_prepare_to_sleep); | 3015 | EXPORT_SYMBOL(pci_prepare_to_sleep); |
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 286c50821949..4eb10f48d270 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
@@ -55,6 +55,7 @@ extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops); | |||
55 | 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); |
56 | extern void pci_disable_enabled_device(struct pci_dev *dev); | 56 | extern void pci_disable_enabled_device(struct pci_dev *dev); |
57 | 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_finish_runtime_suspend(struct pci_dev *dev); | ||
58 | extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign); | 59 | extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign); |
59 | extern void pci_pme_wakeup_bus(struct pci_bus *bus); | 60 | extern void pci_pme_wakeup_bus(struct pci_bus *bus); |
60 | extern void pci_pm_init(struct pci_dev *dev); | 61 | extern void pci_pm_init(struct pci_dev *dev); |