diff options
-rw-r--r-- | drivers/pci/pci.c | 83 | ||||
-rw-r--r-- | include/linux/pci.h | 2 |
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 | */ | ||
1158 | int 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 | */ | ||
1224 | int 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); | |||
1853 | EXPORT_SYMBOL(pci_save_state); | 1934 | EXPORT_SYMBOL(pci_save_state); |
1854 | EXPORT_SYMBOL(pci_restore_state); | 1935 | EXPORT_SYMBOL(pci_restore_state); |
1855 | EXPORT_SYMBOL(pci_enable_wake); | 1936 | EXPORT_SYMBOL(pci_enable_wake); |
1937 | EXPORT_SYMBOL(pci_prepare_to_sleep); | ||
1938 | EXPORT_SYMBOL(pci_back_from_sleep); | ||
1856 | EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state); | 1939 | EXPORT_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); | |||
632 | int pci_set_power_state(struct pci_dev *dev, pci_power_t state); | 632 | int pci_set_power_state(struct pci_dev *dev, pci_power_t state); |
633 | pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state); | 633 | pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state); |
634 | int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable); | 634 | int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable); |
635 | int pci_prepare_to_sleep(struct pci_dev *dev); | ||
636 | int 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 */ |
637 | int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap); | 639 | int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap); |