diff options
Diffstat (limited to 'drivers/pci/pci-driver.c')
-rw-r--r-- | drivers/pci/pci-driver.c | 160 |
1 files changed, 133 insertions, 27 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index e5d47be3c6d..f9a0aec3abc 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 |