aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2008-07-06 21:35:26 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2008-07-07 19:26:33 -0400
commit404cc2d8ce41ed4031958fba8e633767e8a2e028 (patch)
treed679e1ea92d6ae8e72309c02197fd5f1480651fb
parenteb9d0fe40e313c0a74115ef456a2e43a6c8da72f (diff)
PCI PM: Introduce pci_prepare_to_sleep and pci_back_from_sleep
Introduce functions pci_prepare_to_sleep() and pci_back_from_sleep(), to be used by the PCI drivers that want to place their devices into the lowest power state appropiate for them (PCI_D3hot, if the device is not supposed to wake up the system, or the deepest state from which the wake-up is possible, otherwise) while the system is being prepared to go into a sleeping state and to put them back into D0 during the subsequent transition to the working state. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
-rw-r--r--drivers/pci/pci.c83
-rw-r--r--include/linux/pci.h2
2 files changed, 85 insertions, 0 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index a6b1b6f96abc..1b0ec45e9934 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1147,6 +1147,87 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable)
1147} 1147}
1148 1148
1149/** 1149/**
1150 * pci_prepare_to_sleep - prepare PCI device for system-wide transition into
1151 * a sleep state
1152 * @dev: Device to handle.
1153 *
1154 * Choose the power state appropriate for the device depending on whether
1155 * it can wake up the system and/or is power manageable by the platform
1156 * (PCI_D3hot is the default) and put the device into that state.
1157 */
1158int pci_prepare_to_sleep(struct pci_dev *dev)
1159{
1160 pci_power_t target_state = PCI_D3hot;
1161 int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
1162 int error;
1163
1164 if (platform_pci_power_manageable(dev)) {
1165 /*
1166 * Call the platform to choose the target state of the device
1167 * and enable wake-up from this state if supported.
1168 */
1169 pci_power_t state = platform_pci_choose_state(dev);
1170
1171 switch (state) {
1172 case PCI_POWER_ERROR:
1173 case PCI_UNKNOWN:
1174 break;
1175 case PCI_D1:
1176 case PCI_D2:
1177 if (pci_no_d1d2(dev))
1178 break;
1179 default:
1180 target_state = state;
1181 pci_enable_wake(dev, target_state, true);
1182 }
1183 } else if (device_may_wakeup(&dev->dev)) {
1184 /*
1185 * Find the deepest state from which the device can generate
1186 * wake-up events, make it the target state and enable device
1187 * to generate PME#.
1188 */
1189 u16 pmc;
1190
1191 if (!pm)
1192 return -EIO;
1193
1194 pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc);
1195 if (pmc & PCI_PM_CAP_PME_MASK) {
1196 if (!(pmc & PCI_PM_CAP_PME_D3)) {
1197 /* Device cannot generate PME# from D3_hot */
1198 if (pmc & PCI_PM_CAP_PME_D2)
1199 target_state = PCI_D2;
1200 else if (pmc & PCI_PM_CAP_PME_D1)
1201 target_state = PCI_D1;
1202 else
1203 target_state = PCI_D0;
1204 }
1205 pci_pme_active(dev, pm, true);
1206 }
1207 }
1208
1209 error = pci_set_power_state(dev, target_state);
1210
1211 if (error)
1212 pci_enable_wake(dev, target_state, false);
1213
1214 return error;
1215}
1216
1217/**
1218 * pci_back_from_sleep - turn PCI device on during system-wide transition into
1219 * the working state a sleep state
1220 * @dev: Device to handle.
1221 *
1222 * Disable device's sytem wake-up capability and put it into D0.
1223 */
1224int pci_back_from_sleep(struct pci_dev *dev)
1225{
1226 pci_enable_wake(dev, PCI_D0, false);
1227 return pci_set_power_state(dev, PCI_D0);
1228}
1229
1230/**
1150 * pci_pm_init - Initialize PM functions of given PCI device 1231 * pci_pm_init - Initialize PM functions of given PCI device
1151 * @dev: PCI device to handle. 1232 * @dev: PCI device to handle.
1152 */ 1233 */
@@ -1853,5 +1934,7 @@ EXPORT_SYMBOL(pci_set_power_state);
1853EXPORT_SYMBOL(pci_save_state); 1934EXPORT_SYMBOL(pci_save_state);
1854EXPORT_SYMBOL(pci_restore_state); 1935EXPORT_SYMBOL(pci_restore_state);
1855EXPORT_SYMBOL(pci_enable_wake); 1936EXPORT_SYMBOL(pci_enable_wake);
1937EXPORT_SYMBOL(pci_prepare_to_sleep);
1938EXPORT_SYMBOL(pci_back_from_sleep);
1856EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state); 1939EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);
1857 1940
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 4c80dc3f2990..52ac06dcce98 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -632,6 +632,8 @@ int pci_restore_state(struct pci_dev *dev);
632int pci_set_power_state(struct pci_dev *dev, pci_power_t state); 632int pci_set_power_state(struct pci_dev *dev, pci_power_t state);
633pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state); 633pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);
634int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable); 634int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable);
635int pci_prepare_to_sleep(struct pci_dev *dev);
636int pci_back_from_sleep(struct pci_dev *dev);
635 637
636/* Functions for PCI Hotplug drivers to use */ 638/* Functions for PCI Hotplug drivers to use */
637int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap); 639int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap);