PCI PM: Introduce __pci_[start|complete]_power_transition() (rev. 2)
[linux-2.6.git] / drivers / pci / pci.c
index 979ceb1..de54fd6 100644 (file)
@@ -540,6 +540,53 @@ void pci_update_current_state(struct pci_dev *dev, pci_power_t state)
 }
 
 /**
+ * pci_platform_power_transition - Use platform to change device power state
+ * @dev: PCI device to handle.
+ * @state: State to put the device into.
+ */
+static int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state)
+{
+       int error;
+
+       if (platform_pci_power_manageable(dev)) {
+               error = platform_pci_set_power_state(dev, state);
+               if (!error)
+                       pci_update_current_state(dev, state);
+       } else {
+               error = -ENODEV;
+               /* Fall back to PCI_D0 if native PM is not supported */
+               pci_update_current_state(dev, PCI_D0);
+       }
+
+       return error;
+}
+
+/**
+ * __pci_start_power_transition - Start power transition of a PCI device
+ * @dev: PCI device to handle.
+ * @state: State to put the device into.
+ */
+static void __pci_start_power_transition(struct pci_dev *dev, pci_power_t state)
+{
+       if (state == PCI_D0)
+               pci_platform_power_transition(dev, PCI_D0);
+}
+
+/**
+ * __pci_complete_power_transition - Complete power transition of a PCI device
+ * @dev: PCI device to handle.
+ * @state: State to put the device into.
+ *
+ * This function should not be called directly by device drivers.
+ */
+int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state)
+{
+       return state > PCI_D0 ?
+                       pci_platform_power_transition(dev, state) : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(__pci_complete_power_transition);
+
+/**
  * pci_set_power_state - Set the power state of a PCI device
  * @dev: PCI device to handle.
  * @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
@@ -575,16 +622,8 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
        if (dev->current_state == state)
                return 0;
 
-       if (state == PCI_D0) {
-               /*
-                * Allow the platform to change the state, for example via ACPI
-                * _PR0, _PS0 and some such, but do not trust it.
-                */
-               int ret = platform_pci_power_manageable(dev) ?
-                       platform_pci_set_power_state(dev, PCI_D0) : 0;
-               if (!ret)
-                       pci_update_current_state(dev, PCI_D0);
-       }
+       __pci_start_power_transition(dev, state);
+
        /* This device is quirked not to be put into D3, so
           don't put it in D3 */
        if (state == PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3))
@@ -592,14 +631,8 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
 
        error = pci_raw_set_power_state(dev, state);
 
-       if (state > PCI_D0 && platform_pci_power_manageable(dev)) {
-               /* Allow the platform to finalize the transition */
-               int ret = platform_pci_set_power_state(dev, state);
-               if (!ret) {
-                       pci_update_current_state(dev, state);
-                       error = 0;
-               }
-       }
+       if (!__pci_complete_power_transition(dev, state))
+               error = 0;
 
        return error;
 }