mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 11:11:45 -04:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6: PCI PM: Make pci_prepare_to_sleep() disable wake-up if needed radeonfb: Use __pci_complete_power_transition() PCI PM: Introduce __pci_[start|complete]_power_transition() (rev. 2) PCI PM: Restore config spaces of all devices during early resume PCI PM: Make pci_set_power_state() handle devices with no PM support PCI PM: Put devices into low power states during late suspend (rev. 2) PCI PM: Move pci_restore_standard_config to pci-driver.c PCI PM: Use pci_set_power_state during early resume PCI PM: Consistently use variable name "error" for pm call return values kexec: Change kexec jump code ordering PM: Change hibernation code ordering PM: Change suspend code ordering PM: Rework handling of interrupts during suspend-resume PM: Introduce functions for suspending and resuming device interrupts
This commit is contained in:
commit
53d8f67082
18 changed files with 461 additions and 256 deletions
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/pm.h>
|
||||
#include <linux/resume-trace.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "../base.h"
|
||||
#include "power.h"
|
||||
|
|
@ -349,7 +350,8 @@ static int resume_device_noirq(struct device *dev, pm_message_t state)
|
|||
* Execute the appropriate "noirq resume" callback for all devices marked
|
||||
* as DPM_OFF_IRQ.
|
||||
*
|
||||
* Must be called with interrupts disabled and only one CPU running.
|
||||
* Must be called under dpm_list_mtx. Device drivers should not receive
|
||||
* interrupts while it's being executed.
|
||||
*/
|
||||
static void dpm_power_up(pm_message_t state)
|
||||
{
|
||||
|
|
@ -370,14 +372,13 @@ static void dpm_power_up(pm_message_t state)
|
|||
* device_power_up - Turn on all devices that need special attention.
|
||||
* @state: PM transition of the system being carried out.
|
||||
*
|
||||
* Power on system devices, then devices that required we shut them down
|
||||
* with interrupts disabled.
|
||||
*
|
||||
* Must be called with interrupts disabled.
|
||||
* Call the "early" resume handlers and enable device drivers to receive
|
||||
* interrupts.
|
||||
*/
|
||||
void device_power_up(pm_message_t state)
|
||||
{
|
||||
dpm_power_up(state);
|
||||
resume_device_irqs();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_power_up);
|
||||
|
||||
|
|
@ -602,16 +603,17 @@ static int suspend_device_noirq(struct device *dev, pm_message_t state)
|
|||
* device_power_down - Shut down special devices.
|
||||
* @state: PM transition of the system being carried out.
|
||||
*
|
||||
* Power down devices that require interrupts to be disabled.
|
||||
* Then power down system devices.
|
||||
* Prevent device drivers from receiving interrupts and call the "late"
|
||||
* suspend handlers.
|
||||
*
|
||||
* Must be called with interrupts disabled and only one CPU running.
|
||||
* Must be called under dpm_list_mtx.
|
||||
*/
|
||||
int device_power_down(pm_message_t state)
|
||||
{
|
||||
struct device *dev;
|
||||
int error = 0;
|
||||
|
||||
suspend_device_irqs();
|
||||
list_for_each_entry_reverse(dev, &dpm_list, power.entry) {
|
||||
error = suspend_device_noirq(dev, state);
|
||||
if (error) {
|
||||
|
|
@ -621,7 +623,7 @@ int device_power_down(pm_message_t state)
|
|||
dev->power.status = DPM_OFF_IRQ;
|
||||
}
|
||||
if (error)
|
||||
dpm_power_up(resume_event(state));
|
||||
device_power_up(resume_event(state));
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_power_down);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/pm.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "base.h"
|
||||
|
||||
|
|
@ -369,6 +370,13 @@ int sysdev_suspend(pm_message_t state)
|
|||
struct sysdev_driver *drv, *err_drv;
|
||||
int ret;
|
||||
|
||||
pr_debug("Checking wake-up interrupts\n");
|
||||
|
||||
/* Return error code if there are any wake-up interrupts pending */
|
||||
ret = check_wakeup_irqs();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pr_debug("Suspending System Devices\n");
|
||||
|
||||
list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
|
||||
|
|
|
|||
|
|
@ -352,53 +352,60 @@ static int pci_legacy_suspend(struct device *dev, pm_message_t state)
|
|||
{
|
||||
struct pci_dev * pci_dev = to_pci_dev(dev);
|
||||
struct pci_driver * drv = pci_dev->driver;
|
||||
int i = 0;
|
||||
|
||||
pci_dev->state_saved = false;
|
||||
|
||||
if (drv && drv->suspend) {
|
||||
pci_power_t prev = pci_dev->current_state;
|
||||
int error;
|
||||
|
||||
pci_dev->state_saved = false;
|
||||
error = drv->suspend(pci_dev, state);
|
||||
suspend_report_result(drv->suspend, error);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
i = drv->suspend(pci_dev, state);
|
||||
suspend_report_result(drv->suspend, i);
|
||||
if (i)
|
||||
return i;
|
||||
|
||||
if (pci_dev->state_saved)
|
||||
goto Fixup;
|
||||
|
||||
if (pci_dev->current_state != PCI_D0
|
||||
if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
|
||||
&& pci_dev->current_state != PCI_UNKNOWN) {
|
||||
WARN_ONCE(pci_dev->current_state != prev,
|
||||
"PCI PM: Device state not saved by %pF\n",
|
||||
drv->suspend);
|
||||
goto Fixup;
|
||||
}
|
||||
}
|
||||
|
||||
pci_save_state(pci_dev);
|
||||
/*
|
||||
* This is for compatibility with existing code with legacy PM support.
|
||||
*/
|
||||
pci_pm_set_unknown_state(pci_dev);
|
||||
|
||||
Fixup:
|
||||
pci_fixup_device(pci_fixup_suspend, pci_dev);
|
||||
|
||||
return i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci_legacy_suspend_late(struct device *dev, pm_message_t state)
|
||||
{
|
||||
struct pci_dev * pci_dev = to_pci_dev(dev);
|
||||
struct pci_driver * drv = pci_dev->driver;
|
||||
int i = 0;
|
||||
|
||||
if (drv && drv->suspend_late) {
|
||||
i = drv->suspend_late(pci_dev, state);
|
||||
suspend_report_result(drv->suspend_late, i);
|
||||
pci_power_t prev = pci_dev->current_state;
|
||||
int error;
|
||||
|
||||
error = drv->suspend_late(pci_dev, state);
|
||||
suspend_report_result(drv->suspend_late, error);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
|
||||
&& pci_dev->current_state != PCI_UNKNOWN) {
|
||||
WARN_ONCE(pci_dev->current_state != prev,
|
||||
"PCI PM: Device state not saved by %pF\n",
|
||||
drv->suspend_late);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
|
||||
if (!pci_dev->state_saved)
|
||||
pci_save_state(pci_dev);
|
||||
|
||||
pci_pm_set_unknown_state(pci_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci_legacy_resume_early(struct device *dev)
|
||||
|
|
@ -423,6 +430,23 @@ static int pci_legacy_resume(struct device *dev)
|
|||
|
||||
/* Auxiliary functions used by the new power management framework */
|
||||
|
||||
/**
|
||||
* pci_restore_standard_config - restore standard config registers of PCI device
|
||||
* @pci_dev: PCI device to handle
|
||||
*/
|
||||
static int pci_restore_standard_config(struct pci_dev *pci_dev)
|
||||
{
|
||||
pci_update_current_state(pci_dev, PCI_UNKNOWN);
|
||||
|
||||
if (pci_dev->current_state != PCI_D0) {
|
||||
int error = pci_set_power_state(pci_dev, PCI_D0);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
return pci_dev->state_saved ? pci_restore_state(pci_dev) : 0;
|
||||
}
|
||||
|
||||
static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev)
|
||||
{
|
||||
pci_restore_standard_config(pci_dev);
|
||||
|
|
@ -443,7 +467,6 @@ static void pci_pm_default_suspend(struct pci_dev *pci_dev)
|
|||
/* Disable non-bridge devices without PM support */
|
||||
if (!pci_is_bridge(pci_dev))
|
||||
pci_disable_enabled_device(pci_dev);
|
||||
pci_save_state(pci_dev);
|
||||
}
|
||||
|
||||
static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev)
|
||||
|
|
@ -493,13 +516,13 @@ static int pci_pm_suspend(struct device *dev)
|
|||
if (pci_has_legacy_pm_support(pci_dev))
|
||||
return pci_legacy_suspend(dev, PMSG_SUSPEND);
|
||||
|
||||
pci_dev->state_saved = false;
|
||||
|
||||
if (!pm) {
|
||||
pci_pm_default_suspend(pci_dev);
|
||||
goto Fixup;
|
||||
}
|
||||
|
||||
pci_dev->state_saved = false;
|
||||
|
||||
if (pm->suspend) {
|
||||
pci_power_t prev = pci_dev->current_state;
|
||||
int error;
|
||||
|
|
@ -509,24 +532,14 @@ static int pci_pm_suspend(struct device *dev)
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
if (pci_dev->state_saved)
|
||||
goto Fixup;
|
||||
|
||||
if (pci_dev->current_state != PCI_D0
|
||||
if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
|
||||
&& pci_dev->current_state != PCI_UNKNOWN) {
|
||||
WARN_ONCE(pci_dev->current_state != prev,
|
||||
"PCI PM: State of device not saved by %pF\n",
|
||||
pm->suspend);
|
||||
goto Fixup;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pci_dev->state_saved) {
|
||||
pci_save_state(pci_dev);
|
||||
if (!pci_is_bridge(pci_dev))
|
||||
pci_prepare_to_sleep(pci_dev);
|
||||
}
|
||||
|
||||
Fixup:
|
||||
pci_fixup_device(pci_fixup_suspend, pci_dev);
|
||||
|
||||
|
|
@ -536,21 +549,43 @@ static int pci_pm_suspend(struct device *dev)
|
|||
static int pci_pm_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
struct device_driver *drv = dev->driver;
|
||||
int error = 0;
|
||||
struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
||||
|
||||
if (pci_has_legacy_pm_support(pci_dev))
|
||||
return pci_legacy_suspend_late(dev, PMSG_SUSPEND);
|
||||
|
||||
if (drv && drv->pm && drv->pm->suspend_noirq) {
|
||||
error = drv->pm->suspend_noirq(dev);
|
||||
suspend_report_result(drv->pm->suspend_noirq, error);
|
||||
if (!pm) {
|
||||
pci_save_state(pci_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!error)
|
||||
pci_pm_set_unknown_state(pci_dev);
|
||||
if (pm->suspend_noirq) {
|
||||
pci_power_t prev = pci_dev->current_state;
|
||||
int error;
|
||||
|
||||
return error;
|
||||
error = pm->suspend_noirq(dev);
|
||||
suspend_report_result(pm->suspend_noirq, error);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0
|
||||
&& pci_dev->current_state != PCI_UNKNOWN) {
|
||||
WARN_ONCE(pci_dev->current_state != prev,
|
||||
"PCI PM: State of device not saved by %pF\n",
|
||||
pm->suspend_noirq);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pci_dev->state_saved) {
|
||||
pci_save_state(pci_dev);
|
||||
if (!pci_is_bridge(pci_dev))
|
||||
pci_prepare_to_sleep(pci_dev);
|
||||
}
|
||||
|
||||
pci_pm_set_unknown_state(pci_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci_pm_resume_noirq(struct device *dev)
|
||||
|
|
@ -617,13 +652,13 @@ static int pci_pm_freeze(struct device *dev)
|
|||
if (pci_has_legacy_pm_support(pci_dev))
|
||||
return pci_legacy_suspend(dev, PMSG_FREEZE);
|
||||
|
||||
pci_dev->state_saved = false;
|
||||
|
||||
if (!pm) {
|
||||
pci_pm_default_suspend(pci_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pci_dev->state_saved = false;
|
||||
|
||||
if (pm->freeze) {
|
||||
int error;
|
||||
|
||||
|
|
@ -633,9 +668,6 @@ static int pci_pm_freeze(struct device *dev)
|
|||
return error;
|
||||
}
|
||||
|
||||
if (!pci_dev->state_saved)
|
||||
pci_save_state(pci_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -643,20 +675,25 @@ static int pci_pm_freeze_noirq(struct device *dev)
|
|||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
struct device_driver *drv = dev->driver;
|
||||
int error = 0;
|
||||
|
||||
if (pci_has_legacy_pm_support(pci_dev))
|
||||
return pci_legacy_suspend_late(dev, PMSG_FREEZE);
|
||||
|
||||
if (drv && drv->pm && drv->pm->freeze_noirq) {
|
||||
int error;
|
||||
|
||||
error = drv->pm->freeze_noirq(dev);
|
||||
suspend_report_result(drv->pm->freeze_noirq, error);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
if (!error)
|
||||
pci_pm_set_unknown_state(pci_dev);
|
||||
if (!pci_dev->state_saved)
|
||||
pci_save_state(pci_dev);
|
||||
|
||||
return error;
|
||||
pci_pm_set_unknown_state(pci_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci_pm_thaw_noirq(struct device *dev)
|
||||
|
|
@ -699,46 +736,56 @@ static int pci_pm_poweroff(struct device *dev)
|
|||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
||||
int error = 0;
|
||||
|
||||
if (pci_has_legacy_pm_support(pci_dev))
|
||||
return pci_legacy_suspend(dev, PMSG_HIBERNATE);
|
||||
|
||||
pci_dev->state_saved = false;
|
||||
|
||||
if (!pm) {
|
||||
pci_pm_default_suspend(pci_dev);
|
||||
goto Fixup;
|
||||
}
|
||||
|
||||
pci_dev->state_saved = false;
|
||||
|
||||
if (pm->poweroff) {
|
||||
int error;
|
||||
|
||||
error = pm->poweroff(dev);
|
||||
suspend_report_result(pm->poweroff, error);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
Fixup:
|
||||
pci_fixup_device(pci_fixup_suspend, pci_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci_pm_poweroff_noirq(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
struct device_driver *drv = dev->driver;
|
||||
|
||||
if (pci_has_legacy_pm_support(to_pci_dev(dev)))
|
||||
return pci_legacy_suspend_late(dev, PMSG_HIBERNATE);
|
||||
|
||||
if (!drv || !drv->pm)
|
||||
return 0;
|
||||
|
||||
if (drv->pm->poweroff_noirq) {
|
||||
int error;
|
||||
|
||||
error = drv->pm->poweroff_noirq(dev);
|
||||
suspend_report_result(drv->pm->poweroff_noirq, error);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
if (!pci_dev->state_saved && !pci_is_bridge(pci_dev))
|
||||
pci_prepare_to_sleep(pci_dev);
|
||||
|
||||
Fixup:
|
||||
pci_fixup_device(pci_fixup_suspend, pci_dev);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int pci_pm_poweroff_noirq(struct device *dev)
|
||||
{
|
||||
struct device_driver *drv = dev->driver;
|
||||
int error = 0;
|
||||
|
||||
if (pci_has_legacy_pm_support(to_pci_dev(dev)))
|
||||
return pci_legacy_suspend_late(dev, PMSG_HIBERNATE);
|
||||
|
||||
if (drv && drv->pm && drv->pm->poweroff_noirq) {
|
||||
error = drv->pm->poweroff_noirq(dev);
|
||||
suspend_report_result(drv->pm->poweroff_noirq, error);
|
||||
}
|
||||
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci_pm_restore_noirq(struct device *dev)
|
||||
|
|
|
|||
|
|
@ -426,7 +426,6 @@ static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable)
|
|||
* given PCI device
|
||||
* @dev: PCI device to handle.
|
||||
* @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
|
||||
* @wait: If 'true', wait for the device to change its power state
|
||||
*
|
||||
* RETURN VALUE:
|
||||
* -EINVAL if the requested state is invalid.
|
||||
|
|
@ -435,12 +434,15 @@ static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable)
|
|||
* 0 if device already is in the requested state.
|
||||
* 0 if device's power state has been successfully changed.
|
||||
*/
|
||||
static int
|
||||
pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait)
|
||||
static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
|
||||
{
|
||||
u16 pmcsr;
|
||||
bool need_restore = false;
|
||||
|
||||
/* Check if we're already there */
|
||||
if (dev->current_state == state)
|
||||
return 0;
|
||||
|
||||
if (!dev->pm_cap)
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -451,10 +453,7 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait)
|
|||
* Can enter D0 from any state, but if we can only go deeper
|
||||
* to sleep if we're already in a low power state
|
||||
*/
|
||||
if (dev->current_state == state) {
|
||||
/* we're already there */
|
||||
return 0;
|
||||
} else if (state != PCI_D0 && dev->current_state <= PCI_D3cold
|
||||
if (state != PCI_D0 && dev->current_state <= PCI_D3cold
|
||||
&& dev->current_state > state) {
|
||||
dev_err(&dev->dev, "invalid power transition "
|
||||
"(from state %d to %d)\n", dev->current_state, state);
|
||||
|
|
@ -481,10 +480,8 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait)
|
|||
break;
|
||||
case PCI_UNKNOWN: /* Boot-up */
|
||||
if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot
|
||||
&& !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) {
|
||||
&& !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET))
|
||||
need_restore = true;
|
||||
wait = true;
|
||||
}
|
||||
/* Fall-through: force to D0 */
|
||||
default:
|
||||
pmcsr = 0;
|
||||
|
|
@ -494,9 +491,6 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait)
|
|||
/* enter specified state */
|
||||
pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
|
||||
|
||||
if (!wait)
|
||||
return 0;
|
||||
|
||||
/* Mandatory power management transition delays */
|
||||
/* see PCI PM 1.1 5.6.1 table 18 */
|
||||
if (state == PCI_D3hot || dev->current_state == PCI_D3hot)
|
||||
|
|
@ -521,7 +515,7 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state, bool wait)
|
|||
if (need_restore)
|
||||
pci_restore_bars(dev);
|
||||
|
||||
if (wait && dev->bus->self)
|
||||
if (dev->bus->self)
|
||||
pcie_aspm_pm_state_change(dev->bus->self);
|
||||
|
||||
return 0;
|
||||
|
|
@ -545,6 +539,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.
|
||||
|
|
@ -577,30 +618,21 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
|
|||
*/
|
||||
return 0;
|
||||
|
||||
if (state == PCI_D0 && platform_pci_power_manageable(dev)) {
|
||||
/*
|
||||
* 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_set_power_state(dev, PCI_D0);
|
||||
if (!ret)
|
||||
pci_update_current_state(dev, PCI_D0);
|
||||
}
|
||||
/* Check if we're already there */
|
||||
if (dev->current_state == state)
|
||||
return 0;
|
||||
|
||||
__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))
|
||||
return 0;
|
||||
|
||||
error = pci_raw_set_power_state(dev, state, true);
|
||||
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;
|
||||
}
|
||||
|
|
@ -1231,7 +1263,7 @@ int pci_prepare_to_sleep(struct pci_dev *dev)
|
|||
if (target_state == PCI_POWER_ERROR)
|
||||
return -EIO;
|
||||
|
||||
pci_enable_wake(dev, target_state, true);
|
||||
pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev));
|
||||
|
||||
error = pci_set_power_state(dev, target_state);
|
||||
|
||||
|
|
@ -1380,50 +1412,6 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
|
|||
"unable to preallocate PCI-X save buffer\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_restore_standard_config - restore standard config registers of PCI device
|
||||
* @dev: PCI device to handle
|
||||
*
|
||||
* This function assumes that the device's configuration space is accessible.
|
||||
* If the device needs to be powered up, the function will wait for it to
|
||||
* change the state.
|
||||
*/
|
||||
int pci_restore_standard_config(struct pci_dev *dev)
|
||||
{
|
||||
pci_power_t prev_state;
|
||||
int error;
|
||||
|
||||
pci_update_current_state(dev, PCI_D0);
|
||||
|
||||
prev_state = dev->current_state;
|
||||
if (prev_state == PCI_D0)
|
||||
goto Restore;
|
||||
|
||||
error = pci_raw_set_power_state(dev, PCI_D0, false);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* This assumes that we won't get a bus in B2 or B3 from the BIOS, but
|
||||
* we've made this assumption forever and it appears to be universally
|
||||
* satisfied.
|
||||
*/
|
||||
switch(prev_state) {
|
||||
case PCI_D3cold:
|
||||
case PCI_D3hot:
|
||||
mdelay(pci_pm_d3_delay);
|
||||
break;
|
||||
case PCI_D2:
|
||||
udelay(PCI_PM_D2_DELAY);
|
||||
break;
|
||||
}
|
||||
|
||||
pci_update_current_state(dev, PCI_D0);
|
||||
|
||||
Restore:
|
||||
return dev->state_saved ? pci_restore_state(dev) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_enable_ari - enable ARI forwarding if hardware support it
|
||||
* @dev: the PCI device
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ extern void pci_disable_enabled_device(struct pci_dev *dev);
|
|||
extern void pci_pm_init(struct pci_dev *dev);
|
||||
extern void platform_pci_wakeup_init(struct pci_dev *dev);
|
||||
extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
|
||||
extern int pci_restore_standard_config(struct pci_dev *dev);
|
||||
|
||||
static inline bool pci_is_bridge(struct pci_dev *pci_dev)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2582,7 +2582,7 @@ static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
|
|||
* calling pci_set_power_state()
|
||||
*/
|
||||
radeonfb_whack_power_state(rinfo, PCI_D2);
|
||||
pci_set_power_state(rinfo->pdev, PCI_D2);
|
||||
__pci_complete_power_transition(rinfo->pdev, PCI_D2);
|
||||
} else {
|
||||
printk(KERN_DEBUG "radeonfb (%s): switching to D0 state...\n",
|
||||
pci_name(rinfo->pdev));
|
||||
|
|
|
|||
|
|
@ -39,12 +39,6 @@ static int xen_suspend(void *data)
|
|||
|
||||
BUG_ON(!irqs_disabled());
|
||||
|
||||
err = device_power_down(PMSG_SUSPEND);
|
||||
if (err) {
|
||||
printk(KERN_ERR "xen_suspend: device_power_down failed: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
err = sysdev_suspend(PMSG_SUSPEND);
|
||||
if (err) {
|
||||
printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
|
||||
|
|
@ -69,7 +63,6 @@ static int xen_suspend(void *data)
|
|||
xen_mm_unpin_all();
|
||||
|
||||
sysdev_resume();
|
||||
device_power_up(PMSG_RESUME);
|
||||
|
||||
if (!*cancelled) {
|
||||
xen_irq_resume();
|
||||
|
|
@ -108,6 +101,12 @@ static void do_suspend(void)
|
|||
/* XXX use normal device tree? */
|
||||
xenbus_suspend();
|
||||
|
||||
err = device_power_down(PMSG_SUSPEND);
|
||||
if (err) {
|
||||
printk(KERN_ERR "device_power_down failed: %d\n", err);
|
||||
goto resume_devices;
|
||||
}
|
||||
|
||||
err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
|
||||
if (err) {
|
||||
printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
|
||||
|
|
@ -120,6 +119,9 @@ static void do_suspend(void)
|
|||
} else
|
||||
xenbus_suspend_cancel();
|
||||
|
||||
device_power_up(PMSG_RESUME);
|
||||
|
||||
resume_devices:
|
||||
device_resume(PMSG_RESUME);
|
||||
|
||||
/* Make sure timer events get retriggered on all CPUs */
|
||||
|
|
|
|||
Loading…
Reference in a new issue