aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2010-02-17 17:44:58 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2010-02-22 19:21:19 -0500
commit6cbf82148ff286ec22a55be6836c3a5bffc489c1 (patch)
tree77b1b0097f9c2389d56734ec4c022611aa1bd9db /drivers/pci
parent552be54cc4232dc5acc49ccb372129d6f1b6923f (diff)
PCI PM: Run-time callbacks for PCI bus type
Introduce run-time PM callbacks for the PCI bus type. Make the new callbacks work in analogy with the existing system sleep PM callbacks, so that the drivers already converted to struct dev_pm_ops can use their suspend and resume routines for run-time PM without modifications. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/pci-driver.c160
-rw-r--r--drivers/pci/pci.c43
-rw-r--r--drivers/pci/pci.h1
3 files changed, 171 insertions, 33 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
22struct pci_dynid { 23struct 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 */
416static 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
429static 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 */
527static 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
540static 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
546static void pci_pm_default_resume(struct pci_dev *pci_dev) 553static 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
600static int pci_pm_suspend(struct device *dev) 625static 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
961static 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
994static 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
1009static 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
934const struct dev_pm_ops pci_dev_pm_ops = { 1037const 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 df55a2f351b..d62a5de8167 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 */
1323int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) 1324int __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}
1366EXPORT_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 */
1482int 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);
2978EXPORT_SYMBOL(pci_restore_state); 3010EXPORT_SYMBOL(pci_restore_state);
2979EXPORT_SYMBOL(pci_pme_capable); 3011EXPORT_SYMBOL(pci_pme_capable);
2980EXPORT_SYMBOL(pci_pme_active); 3012EXPORT_SYMBOL(pci_pme_active);
2981EXPORT_SYMBOL(pci_enable_wake);
2982EXPORT_SYMBOL(pci_wake_from_d3); 3013EXPORT_SYMBOL(pci_wake_from_d3);
2983EXPORT_SYMBOL(pci_target_state); 3014EXPORT_SYMBOL(pci_target_state);
2984EXPORT_SYMBOL(pci_prepare_to_sleep); 3015EXPORT_SYMBOL(pci_prepare_to_sleep);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 286c5082194..4eb10f48d27 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);
55extern void pci_update_current_state(struct pci_dev *dev, pci_power_t state); 55extern void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
56extern void pci_disable_enabled_device(struct pci_dev *dev); 56extern void pci_disable_enabled_device(struct pci_dev *dev);
57extern bool pci_check_pme_status(struct pci_dev *dev); 57extern bool pci_check_pme_status(struct pci_dev *dev);
58extern int pci_finish_runtime_suspend(struct pci_dev *dev);
58extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign); 59extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
59extern void pci_pme_wakeup_bus(struct pci_bus *bus); 60extern void pci_pme_wakeup_bus(struct pci_bus *bus);
60extern void pci_pm_init(struct pci_dev *dev); 61extern void pci_pm_init(struct pci_dev *dev);