PCI: Introduce platform_pci_power_manageable function
authorRafael J. Wysocki <rjw@sisk.pl>
Mon, 7 Jul 2008 01:32:02 +0000 (03:32 +0200)
committerJesse Barnes <jbarnes@virtuousgeek.org>
Mon, 7 Jul 2008 23:25:10 +0000 (16:25 -0700)
Introduce function pointer platform_pci_power_manageable to be used
by the platform-related code to point to a function allowing us to
check if given device is power manageable by the platform.

Introduce acpi_pci_power_manageable() playing that role for ACPI.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
drivers/pci/pci-acpi.c
drivers/pci/pci.c
drivers/pci/pci.h

index 056ea80ee27a6bf6ca0be58cf2321c323901dd89..e4df71ab79b3508df99a1d57c5489966f737c7cc 100644 (file)
@@ -215,7 +215,6 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
 }
 EXPORT_SYMBOL(pci_osc_control_set);
 
-#ifdef CONFIG_ACPI_SLEEP
 /*
  * _SxD returns the D-state with the highest power
  * (lowest D-state number) supported in the S-state "x".
@@ -259,7 +258,13 @@ static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev)
        }
        return PCI_POWER_ERROR;
 }
-#endif
+
+static bool acpi_pci_power_manageable(struct pci_dev *dev)
+{
+       acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
+
+       return handle ? acpi_bus_power_manageable(handle) : false;
+}
 
 static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
 {
@@ -290,6 +295,11 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
        return -EINVAL;
 }
 
+static struct pci_platform_pm_ops acpi_pci_platform_pm = {
+       .is_manageable = acpi_pci_power_manageable,
+       .set_state = acpi_pci_set_power_state,
+       .choose_state = acpi_pci_choose_state,
+};
 
 /* ACPI bus type */
 static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
@@ -341,10 +351,7 @@ static int __init acpi_pci_init(void)
        ret = register_acpi_bus_type(&acpi_pci_bus);
        if (ret)
                return 0;
-#ifdef CONFIG_ACPI_SLEEP
-       platform_pci_choose_state = acpi_pci_choose_state;
-#endif
-       platform_pci_set_power_state = acpi_pci_set_power_state;
+       pci_set_platform_pm(&acpi_pci_platform_pm);
        return 0;
 }
 arch_initcall(acpi_pci_init);
index 8e8ecc1da93d85b4404cd18dd07f21954fe2596f..f8074525267cabfb25f808e945bd107e77575832 100644 (file)
@@ -376,7 +376,32 @@ pci_restore_bars(struct pci_dev *dev)
                pci_update_resource(dev, &dev->resource[i], i);
 }
 
-int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t);
+static struct pci_platform_pm_ops *pci_platform_pm;
+
+int pci_set_platform_pm(struct pci_platform_pm_ops *ops)
+{
+       if (!ops->is_manageable || !ops->set_state || !ops->choose_state)
+               return -EINVAL;
+       pci_platform_pm = ops;
+       return 0;
+}
+
+static inline bool platform_pci_power_manageable(struct pci_dev *dev)
+{
+       return pci_platform_pm ? pci_platform_pm->is_manageable(dev) : false;
+}
+
+static inline int platform_pci_set_power_state(struct pci_dev *dev,
+                                                pci_power_t t)
+{
+       return pci_platform_pm ? pci_platform_pm->set_state(dev, t) : -ENOSYS;
+}
+
+static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev)
+{
+       return pci_platform_pm ?
+                       pci_platform_pm->choose_state(dev) : PCI_POWER_ERROR;
+}
 
 /**
  * pci_set_power_state - Set the power state of a PCI device
@@ -479,8 +504,7 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
         * Give firmware a chance to be called, such as ACPI _PRx, _PSx
         * Firmware method after native method ?
         */
-       if (platform_pci_set_power_state)
-               platform_pci_set_power_state(dev, state);
+       platform_pci_set_power_state(dev, state);
 
        dev->current_state = state;
 
@@ -505,8 +529,6 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
        return 0;
 }
 
-pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev);
 /**
  * pci_choose_state - Choose the power state of a PCI device
  * @dev: PCI device to be suspended
@@ -524,11 +546,9 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
        if (!pci_find_capability(dev, PCI_CAP_ID_PM))
                return PCI_D0;
 
-       if (platform_pci_choose_state) {
-               ret = platform_pci_choose_state(dev);
-               if (ret != PCI_POWER_ERROR)
-                       return ret;
-       }
+       ret = platform_pci_choose_state(dev);
+       if (ret != PCI_POWER_ERROR)
+               return ret;
 
        switch (state.event) {
        case PM_EVENT_ON:
index e0eff35825a6ec33cbb4562ae9cb42b666db8a98..0cd2e719933b11c46d8742f07af7f2201264fb89 100644 (file)
@@ -5,10 +5,28 @@ extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
 extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
 extern void pci_cleanup_rom(struct pci_dev *dev);
 
-/* Firmware callbacks */
-extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev);
-extern int (*platform_pci_set_power_state)(struct pci_dev *dev,
-                                               pci_power_t state);
+/**
+ * Firmware PM callbacks
+ *
+ * @is_manageable - returns 'true' if given device is power manageable by the
+ *                  platform firmware
+ *
+ * @set_state - invokes the platform firmware to set the device's power state
+ *
+ * @choose_state - returns PCI power state of given device preferred by the
+ *                 platform; to be used during system-wide transitions from a
+ *                 sleeping state to the working state and vice versa
+ *
+ * If given platform is generally capable of power managing PCI devices, all of
+ * these callbacks are mandatory.
+ */
+struct pci_platform_pm_ops {
+       bool (*is_manageable)(struct pci_dev *dev);
+       int (*set_state)(struct pci_dev *dev, pci_power_t state);
+       pci_power_t (*choose_state)(struct pci_dev *dev);
+};
+
+extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops);
 
 extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val);
 extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val);