mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 13:11:40 +00:00
Merge branch 'pm-sleep'
* pm-sleep: PM / hibernate: fix a comment typo input: i8042: Avoid resetting controller on system suspend/resume PM / PCI / ACPI: Kick devices that might have been reset by firmware PM / sleep: Add flags to indicate platform firmware involvement PM / sleep: Drop pm_request_idle() from pm_generic_complete() PCI / PM: Avoid resuming more devices during system suspend PM / wakeup: wakeup_source_create: use kstrdup_const PM / sleep: Report interrupt that caused system wakeup
This commit is contained in:
commit
9bb4064ca3
@ -256,3 +256,15 @@ Description:
|
|||||||
Writing a "1" enables this printing while writing a "0"
|
Writing a "1" enables this printing while writing a "0"
|
||||||
disables it. The default value is "0". Reading from this file
|
disables it. The default value is "0". Reading from this file
|
||||||
will display the current value.
|
will display the current value.
|
||||||
|
|
||||||
|
What: /sys/power/pm_wakeup_irq
|
||||||
|
Date: April 2015
|
||||||
|
Contact: Alexandra Yates <alexandra.yates@linux.intel.org>
|
||||||
|
Description:
|
||||||
|
The /sys/power/pm_wakeup_irq file reports to user space the IRQ
|
||||||
|
number of the first wakeup interrupt (that is, the first
|
||||||
|
interrupt from an IRQ line armed for system wakeup) seen by the
|
||||||
|
kernel during the most recent system suspend/resume cycle.
|
||||||
|
|
||||||
|
This output is useful for system wakeup diagnostics of spurious
|
||||||
|
wakeup interrupts.
|
||||||
|
@ -664,7 +664,7 @@ static struct dev_pm_domain acpi_lpss_pm_domain = {
|
|||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
.prepare = acpi_subsys_prepare,
|
.prepare = acpi_subsys_prepare,
|
||||||
.complete = acpi_subsys_complete,
|
.complete = pm_complete_with_resume_check,
|
||||||
.suspend = acpi_subsys_suspend,
|
.suspend = acpi_subsys_suspend,
|
||||||
.suspend_late = acpi_lpss_suspend_late,
|
.suspend_late = acpi_lpss_suspend_late,
|
||||||
.resume_early = acpi_lpss_resume_early,
|
.resume_early = acpi_lpss_resume_early,
|
||||||
|
@ -962,23 +962,6 @@ int acpi_subsys_prepare(struct device *dev)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(acpi_subsys_prepare);
|
EXPORT_SYMBOL_GPL(acpi_subsys_prepare);
|
||||||
|
|
||||||
/**
|
|
||||||
* acpi_subsys_complete - Finalize device's resume during system resume.
|
|
||||||
* @dev: Device to handle.
|
|
||||||
*/
|
|
||||||
void acpi_subsys_complete(struct device *dev)
|
|
||||||
{
|
|
||||||
pm_generic_complete(dev);
|
|
||||||
/*
|
|
||||||
* If the device had been runtime-suspended before the system went into
|
|
||||||
* the sleep state it is going out of and it has never been resumed till
|
|
||||||
* now, resume it in case the firmware powered it up.
|
|
||||||
*/
|
|
||||||
if (dev->power.direct_complete)
|
|
||||||
pm_request_resume(dev);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(acpi_subsys_complete);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* acpi_subsys_suspend - Run the device driver's suspend callback.
|
* acpi_subsys_suspend - Run the device driver's suspend callback.
|
||||||
* @dev: Device to handle.
|
* @dev: Device to handle.
|
||||||
@ -1047,7 +1030,7 @@ static struct dev_pm_domain acpi_general_pm_domain = {
|
|||||||
.runtime_resume = acpi_subsys_runtime_resume,
|
.runtime_resume = acpi_subsys_runtime_resume,
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
.prepare = acpi_subsys_prepare,
|
.prepare = acpi_subsys_prepare,
|
||||||
.complete = acpi_subsys_complete,
|
.complete = pm_complete_with_resume_check,
|
||||||
.suspend = acpi_subsys_suspend,
|
.suspend = acpi_subsys_suspend,
|
||||||
.suspend_late = acpi_subsys_suspend_late,
|
.suspend_late = acpi_subsys_suspend_late,
|
||||||
.resume_early = acpi_subsys_resume_early,
|
.resume_early = acpi_subsys_resume_early,
|
||||||
|
@ -487,6 +487,8 @@ static int acpi_suspend_begin(suspend_state_t pm_state)
|
|||||||
pr_err("ACPI does not support sleep state S%u\n", acpi_state);
|
pr_err("ACPI does not support sleep state S%u\n", acpi_state);
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
if (acpi_state > ACPI_STATE_S1)
|
||||||
|
pm_set_suspend_via_firmware();
|
||||||
|
|
||||||
acpi_pm_start(acpi_state);
|
acpi_pm_start(acpi_state);
|
||||||
return 0;
|
return 0;
|
||||||
@ -522,6 +524,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
|
|||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
pr_info(PREFIX "Low-level resume complete\n");
|
pr_info(PREFIX "Low-level resume complete\n");
|
||||||
|
pm_set_resume_via_firmware();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
trace_suspend_resume(TPS("acpi_suspend"), acpi_state, false);
|
trace_suspend_resume(TPS("acpi_suspend"), acpi_state, false);
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
|
#include <linux/suspend.h>
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
/**
|
/**
|
||||||
@ -296,11 +297,27 @@ void pm_generic_complete(struct device *dev)
|
|||||||
|
|
||||||
if (drv && drv->pm && drv->pm->complete)
|
if (drv && drv->pm && drv->pm->complete)
|
||||||
drv->pm->complete(dev);
|
drv->pm->complete(dev);
|
||||||
|
|
||||||
/*
|
|
||||||
* Let runtime PM try to suspend devices that haven't been in use before
|
|
||||||
* going into the system-wide sleep state we're resuming from.
|
|
||||||
*/
|
|
||||||
pm_request_idle(dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pm_complete_with_resume_check - Complete a device power transition.
|
||||||
|
* @dev: Device to handle.
|
||||||
|
*
|
||||||
|
* Complete a device power transition during a system-wide power transition and
|
||||||
|
* optionally schedule a runtime resume of the device if the system resume in
|
||||||
|
* progress has been initated by the platform firmware and the device had its
|
||||||
|
* power.direct_complete flag set.
|
||||||
|
*/
|
||||||
|
void pm_complete_with_resume_check(struct device *dev)
|
||||||
|
{
|
||||||
|
pm_generic_complete(dev);
|
||||||
|
/*
|
||||||
|
* If the device had been runtime-suspended before the system went into
|
||||||
|
* the sleep state it is going out of and it has never been resumed till
|
||||||
|
* now, resume it in case the firmware powered it up.
|
||||||
|
*/
|
||||||
|
if (dev->power.direct_complete && pm_resume_via_firmware())
|
||||||
|
pm_request_resume(dev);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(pm_complete_with_resume_check);
|
||||||
#endif /* CONFIG_PM_SLEEP */
|
#endif /* CONFIG_PM_SLEEP */
|
||||||
|
@ -25,6 +25,9 @@
|
|||||||
*/
|
*/
|
||||||
bool events_check_enabled __read_mostly;
|
bool events_check_enabled __read_mostly;
|
||||||
|
|
||||||
|
/* First wakeup IRQ seen by the kernel in the last cycle. */
|
||||||
|
unsigned int pm_wakeup_irq __read_mostly;
|
||||||
|
|
||||||
/* If set and the system is suspending, terminate the suspend. */
|
/* If set and the system is suspending, terminate the suspend. */
|
||||||
static bool pm_abort_suspend __read_mostly;
|
static bool pm_abort_suspend __read_mostly;
|
||||||
|
|
||||||
@ -91,7 +94,7 @@ struct wakeup_source *wakeup_source_create(const char *name)
|
|||||||
if (!ws)
|
if (!ws)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
wakeup_source_prepare(ws, name ? kstrdup(name, GFP_KERNEL) : NULL);
|
wakeup_source_prepare(ws, name ? kstrdup_const(name, GFP_KERNEL) : NULL);
|
||||||
return ws;
|
return ws;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(wakeup_source_create);
|
EXPORT_SYMBOL_GPL(wakeup_source_create);
|
||||||
@ -154,7 +157,7 @@ void wakeup_source_destroy(struct wakeup_source *ws)
|
|||||||
|
|
||||||
wakeup_source_drop(ws);
|
wakeup_source_drop(ws);
|
||||||
wakeup_source_record(ws);
|
wakeup_source_record(ws);
|
||||||
kfree(ws->name);
|
kfree_const(ws->name);
|
||||||
kfree(ws);
|
kfree(ws);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(wakeup_source_destroy);
|
EXPORT_SYMBOL_GPL(wakeup_source_destroy);
|
||||||
@ -868,6 +871,15 @@ EXPORT_SYMBOL_GPL(pm_system_wakeup);
|
|||||||
void pm_wakeup_clear(void)
|
void pm_wakeup_clear(void)
|
||||||
{
|
{
|
||||||
pm_abort_suspend = false;
|
pm_abort_suspend = false;
|
||||||
|
pm_wakeup_irq = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pm_system_irq_wakeup(unsigned int irq_number)
|
||||||
|
{
|
||||||
|
if (pm_wakeup_irq == 0) {
|
||||||
|
pm_wakeup_irq = irq_number;
|
||||||
|
pm_system_wakeup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/i8042.h>
|
#include <linux/i8042.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/suspend.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
|
||||||
@ -1170,7 +1171,8 @@ static int i8042_pm_suspend(struct device *dev)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
i8042_controller_reset(true);
|
if (pm_suspend_via_firmware())
|
||||||
|
i8042_controller_reset(true);
|
||||||
|
|
||||||
/* Set up serio interrupts for system wakeup. */
|
/* Set up serio interrupts for system wakeup. */
|
||||||
for (i = 0; i < I8042_NUM_PORTS; i++) {
|
for (i = 0; i < I8042_NUM_PORTS; i++) {
|
||||||
@ -1183,8 +1185,17 @@ static int i8042_pm_suspend(struct device *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int i8042_pm_resume_noirq(struct device *dev)
|
||||||
|
{
|
||||||
|
if (!pm_resume_via_firmware())
|
||||||
|
i8042_interrupt(0, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int i8042_pm_resume(struct device *dev)
|
static int i8042_pm_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
|
bool force_reset;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < I8042_NUM_PORTS; i++) {
|
for (i = 0; i < I8042_NUM_PORTS; i++) {
|
||||||
@ -1195,11 +1206,21 @@ static int i8042_pm_resume(struct device *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On resume from S2R we always try to reset the controller
|
* If platform firmware was not going to be involved in suspend, we did
|
||||||
* to bring it in a sane state. (In case of S2D we expect
|
* not restore the controller state to whatever it had been at boot
|
||||||
* BIOS to reset the controller for us.)
|
* time, so we do not need to do anything.
|
||||||
*/
|
*/
|
||||||
return i8042_controller_resume(true);
|
if (!pm_suspend_via_firmware())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We only need to reset the controller if we are resuming after handing
|
||||||
|
* off control to the platform firmware, otherwise we can simply restore
|
||||||
|
* the mode.
|
||||||
|
*/
|
||||||
|
force_reset = pm_resume_via_firmware();
|
||||||
|
|
||||||
|
return i8042_controller_resume(force_reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int i8042_pm_thaw(struct device *dev)
|
static int i8042_pm_thaw(struct device *dev)
|
||||||
@ -1223,6 +1244,7 @@ static int i8042_pm_restore(struct device *dev)
|
|||||||
|
|
||||||
static const struct dev_pm_ops i8042_pm_ops = {
|
static const struct dev_pm_ops i8042_pm_ops = {
|
||||||
.suspend = i8042_pm_suspend,
|
.suspend = i8042_pm_suspend,
|
||||||
|
.resume_noirq = i8042_pm_resume_noirq,
|
||||||
.resume = i8042_pm_resume,
|
.resume = i8042_pm_resume,
|
||||||
.thaw = i8042_pm_thaw,
|
.thaw = i8042_pm_thaw,
|
||||||
.poweroff = i8042_pm_reset,
|
.poweroff = i8042_pm_reset,
|
||||||
|
@ -684,10 +684,16 @@ static int pci_pm_prepare(struct device *dev)
|
|||||||
return pci_dev_keep_suspended(to_pci_dev(dev));
|
return pci_dev_keep_suspended(to_pci_dev(dev));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pci_pm_complete(struct device *dev)
|
||||||
|
{
|
||||||
|
pci_dev_complete_resume(to_pci_dev(dev));
|
||||||
|
pm_complete_with_resume_check(dev);
|
||||||
|
}
|
||||||
|
|
||||||
#else /* !CONFIG_PM_SLEEP */
|
#else /* !CONFIG_PM_SLEEP */
|
||||||
|
|
||||||
#define pci_pm_prepare NULL
|
#define pci_pm_prepare NULL
|
||||||
|
#define pci_pm_complete NULL
|
||||||
|
|
||||||
#endif /* !CONFIG_PM_SLEEP */
|
#endif /* !CONFIG_PM_SLEEP */
|
||||||
|
|
||||||
@ -1218,6 +1224,7 @@ static int pci_pm_runtime_idle(struct device *dev)
|
|||||||
|
|
||||||
static const struct dev_pm_ops pci_dev_pm_ops = {
|
static const struct dev_pm_ops pci_dev_pm_ops = {
|
||||||
.prepare = pci_pm_prepare,
|
.prepare = pci_pm_prepare,
|
||||||
|
.complete = pci_pm_complete,
|
||||||
.suspend = pci_pm_suspend,
|
.suspend = pci_pm_suspend,
|
||||||
.resume = pci_pm_resume,
|
.resume = pci_pm_resume,
|
||||||
.freeze = pci_pm_freeze,
|
.freeze = pci_pm_freeze,
|
||||||
|
@ -1710,15 +1710,7 @@ static void pci_pme_list_scan(struct work_struct *work)
|
|||||||
mutex_unlock(&pci_pme_list_mutex);
|
mutex_unlock(&pci_pme_list_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void __pci_pme_active(struct pci_dev *dev, bool enable)
|
||||||
* pci_pme_active - enable or disable PCI device's PME# function
|
|
||||||
* @dev: PCI device to handle.
|
|
||||||
* @enable: 'true' to enable PME# generation; 'false' to disable it.
|
|
||||||
*
|
|
||||||
* The caller must verify that the device is capable of generating PME# before
|
|
||||||
* calling this function with @enable equal to 'true'.
|
|
||||||
*/
|
|
||||||
void pci_pme_active(struct pci_dev *dev, bool enable)
|
|
||||||
{
|
{
|
||||||
u16 pmcsr;
|
u16 pmcsr;
|
||||||
|
|
||||||
@ -1732,6 +1724,19 @@ void pci_pme_active(struct pci_dev *dev, bool enable)
|
|||||||
pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
|
pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
|
||||||
|
|
||||||
pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
|
pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pci_pme_active - enable or disable PCI device's PME# function
|
||||||
|
* @dev: PCI device to handle.
|
||||||
|
* @enable: 'true' to enable PME# generation; 'false' to disable it.
|
||||||
|
*
|
||||||
|
* The caller must verify that the device is capable of generating PME# before
|
||||||
|
* calling this function with @enable equal to 'true'.
|
||||||
|
*/
|
||||||
|
void pci_pme_active(struct pci_dev *dev, bool enable)
|
||||||
|
{
|
||||||
|
__pci_pme_active(dev, enable);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PCI (as opposed to PCIe) PME requires that the device have
|
* PCI (as opposed to PCIe) PME requires that the device have
|
||||||
@ -2032,17 +2037,60 @@ EXPORT_SYMBOL_GPL(pci_dev_run_wake);
|
|||||||
* reconfigured due to wakeup settings difference between system and runtime
|
* reconfigured due to wakeup settings difference between system and runtime
|
||||||
* suspend and the current power state of it is suitable for the upcoming
|
* suspend and the current power state of it is suitable for the upcoming
|
||||||
* (system) transition.
|
* (system) transition.
|
||||||
|
*
|
||||||
|
* If the device is not configured for system wakeup, disable PME for it before
|
||||||
|
* returning 'true' to prevent it from waking up the system unnecessarily.
|
||||||
*/
|
*/
|
||||||
bool pci_dev_keep_suspended(struct pci_dev *pci_dev)
|
bool pci_dev_keep_suspended(struct pci_dev *pci_dev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pci_dev->dev;
|
struct device *dev = &pci_dev->dev;
|
||||||
|
|
||||||
if (!pm_runtime_suspended(dev)
|
if (!pm_runtime_suspended(dev)
|
||||||
|| (device_can_wakeup(dev) && !device_may_wakeup(dev))
|
|| pci_target_state(pci_dev) != pci_dev->current_state
|
||||||
|| platform_pci_need_resume(pci_dev))
|
|| platform_pci_need_resume(pci_dev))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return pci_target_state(pci_dev) == pci_dev->current_state;
|
/*
|
||||||
|
* At this point the device is good to go unless it's been configured
|
||||||
|
* to generate PME at the runtime suspend time, but it is not supposed
|
||||||
|
* to wake up the system. In that case, simply disable PME for it
|
||||||
|
* (it will have to be re-enabled on exit from system resume).
|
||||||
|
*
|
||||||
|
* If the device's power state is D3cold and the platform check above
|
||||||
|
* hasn't triggered, the device's configuration is suitable and we don't
|
||||||
|
* need to manipulate it at all.
|
||||||
|
*/
|
||||||
|
spin_lock_irq(&dev->power.lock);
|
||||||
|
|
||||||
|
if (pm_runtime_suspended(dev) && pci_dev->current_state < PCI_D3cold &&
|
||||||
|
!device_may_wakeup(dev))
|
||||||
|
__pci_pme_active(pci_dev, false);
|
||||||
|
|
||||||
|
spin_unlock_irq(&dev->power.lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pci_dev_complete_resume - Finalize resume from system sleep for a device.
|
||||||
|
* @pci_dev: Device to handle.
|
||||||
|
*
|
||||||
|
* If the device is runtime suspended and wakeup-capable, enable PME for it as
|
||||||
|
* it might have been disabled during the prepare phase of system suspend if
|
||||||
|
* the device was not configured for system wakeup.
|
||||||
|
*/
|
||||||
|
void pci_dev_complete_resume(struct pci_dev *pci_dev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pci_dev->dev;
|
||||||
|
|
||||||
|
if (!pci_dev_run_wake(pci_dev))
|
||||||
|
return;
|
||||||
|
|
||||||
|
spin_lock_irq(&dev->power.lock);
|
||||||
|
|
||||||
|
if (pm_runtime_suspended(dev) && pci_dev->current_state < PCI_D3cold)
|
||||||
|
__pci_pme_active(pci_dev, true);
|
||||||
|
|
||||||
|
spin_unlock_irq(&dev->power.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pci_config_pm_runtime_get(struct pci_dev *pdev)
|
void pci_config_pm_runtime_get(struct pci_dev *pdev)
|
||||||
|
@ -75,6 +75,7 @@ void pci_disable_enabled_device(struct pci_dev *dev);
|
|||||||
int pci_finish_runtime_suspend(struct pci_dev *dev);
|
int pci_finish_runtime_suspend(struct pci_dev *dev);
|
||||||
int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
|
int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
|
||||||
bool pci_dev_keep_suspended(struct pci_dev *dev);
|
bool pci_dev_keep_suspended(struct pci_dev *dev);
|
||||||
|
void pci_dev_complete_resume(struct pci_dev *pci_dev);
|
||||||
void pci_config_pm_runtime_get(struct pci_dev *dev);
|
void pci_config_pm_runtime_get(struct pci_dev *dev);
|
||||||
void pci_config_pm_runtime_put(struct pci_dev *dev);
|
void pci_config_pm_runtime_put(struct pci_dev *dev);
|
||||||
void pci_pm_init(struct pci_dev *dev);
|
void pci_pm_init(struct pci_dev *dev);
|
||||||
|
@ -732,6 +732,7 @@ extern int pm_generic_poweroff_noirq(struct device *dev);
|
|||||||
extern int pm_generic_poweroff_late(struct device *dev);
|
extern int pm_generic_poweroff_late(struct device *dev);
|
||||||
extern int pm_generic_poweroff(struct device *dev);
|
extern int pm_generic_poweroff(struct device *dev);
|
||||||
extern void pm_generic_complete(struct device *dev);
|
extern void pm_generic_complete(struct device *dev);
|
||||||
|
extern void pm_complete_with_resume_check(struct device *dev);
|
||||||
|
|
||||||
#else /* !CONFIG_PM_SLEEP */
|
#else /* !CONFIG_PM_SLEEP */
|
||||||
|
|
||||||
|
@ -202,6 +202,36 @@ struct platform_freeze_ops {
|
|||||||
extern void suspend_set_ops(const struct platform_suspend_ops *ops);
|
extern void suspend_set_ops(const struct platform_suspend_ops *ops);
|
||||||
extern int suspend_valid_only_mem(suspend_state_t state);
|
extern int suspend_valid_only_mem(suspend_state_t state);
|
||||||
|
|
||||||
|
extern unsigned int pm_suspend_global_flags;
|
||||||
|
|
||||||
|
#define PM_SUSPEND_FLAG_FW_SUSPEND (1 << 0)
|
||||||
|
#define PM_SUSPEND_FLAG_FW_RESUME (1 << 1)
|
||||||
|
|
||||||
|
static inline void pm_suspend_clear_flags(void)
|
||||||
|
{
|
||||||
|
pm_suspend_global_flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pm_set_suspend_via_firmware(void)
|
||||||
|
{
|
||||||
|
pm_suspend_global_flags |= PM_SUSPEND_FLAG_FW_SUSPEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pm_set_resume_via_firmware(void)
|
||||||
|
{
|
||||||
|
pm_suspend_global_flags |= PM_SUSPEND_FLAG_FW_RESUME;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool pm_suspend_via_firmware(void)
|
||||||
|
{
|
||||||
|
return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_SUSPEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool pm_resume_via_firmware(void)
|
||||||
|
{
|
||||||
|
return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_RESUME);
|
||||||
|
}
|
||||||
|
|
||||||
/* Suspend-to-idle state machnine. */
|
/* Suspend-to-idle state machnine. */
|
||||||
enum freeze_state {
|
enum freeze_state {
|
||||||
FREEZE_STATE_NONE, /* Not suspended/suspending. */
|
FREEZE_STATE_NONE, /* Not suspended/suspending. */
|
||||||
@ -241,6 +271,12 @@ extern int pm_suspend(suspend_state_t state);
|
|||||||
#else /* !CONFIG_SUSPEND */
|
#else /* !CONFIG_SUSPEND */
|
||||||
#define suspend_valid_only_mem NULL
|
#define suspend_valid_only_mem NULL
|
||||||
|
|
||||||
|
static inline void pm_suspend_clear_flags(void) {}
|
||||||
|
static inline void pm_set_suspend_via_firmware(void) {}
|
||||||
|
static inline void pm_set_resume_via_firmware(void) {}
|
||||||
|
static inline bool pm_suspend_via_firmware(void) { return false; }
|
||||||
|
static inline bool pm_resume_via_firmware(void) { return false; }
|
||||||
|
|
||||||
static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {}
|
static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {}
|
||||||
static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; }
|
static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; }
|
||||||
static inline bool idle_should_freeze(void) { return false; }
|
static inline bool idle_should_freeze(void) { return false; }
|
||||||
@ -387,10 +423,12 @@ extern int unregister_pm_notifier(struct notifier_block *nb);
|
|||||||
|
|
||||||
/* drivers/base/power/wakeup.c */
|
/* drivers/base/power/wakeup.c */
|
||||||
extern bool events_check_enabled;
|
extern bool events_check_enabled;
|
||||||
|
extern unsigned int pm_wakeup_irq;
|
||||||
|
|
||||||
extern bool pm_wakeup_pending(void);
|
extern bool pm_wakeup_pending(void);
|
||||||
extern void pm_system_wakeup(void);
|
extern void pm_system_wakeup(void);
|
||||||
extern void pm_wakeup_clear(void);
|
extern void pm_wakeup_clear(void);
|
||||||
|
extern void pm_system_irq_wakeup(unsigned int irq_number);
|
||||||
extern bool pm_get_wakeup_count(unsigned int *count, bool block);
|
extern bool pm_get_wakeup_count(unsigned int *count, bool block);
|
||||||
extern bool pm_save_wakeup_count(unsigned int count);
|
extern bool pm_save_wakeup_count(unsigned int count);
|
||||||
extern void pm_wakep_autosleep_enabled(bool set);
|
extern void pm_wakep_autosleep_enabled(bool set);
|
||||||
@ -440,6 +478,7 @@ static inline int unregister_pm_notifier(struct notifier_block *nb)
|
|||||||
static inline bool pm_wakeup_pending(void) { return false; }
|
static inline bool pm_wakeup_pending(void) { return false; }
|
||||||
static inline void pm_system_wakeup(void) {}
|
static inline void pm_system_wakeup(void) {}
|
||||||
static inline void pm_wakeup_clear(void) {}
|
static inline void pm_wakeup_clear(void) {}
|
||||||
|
static inline void pm_system_irq_wakeup(unsigned int irq_number) {}
|
||||||
|
|
||||||
static inline void lock_system_sleep(void) {}
|
static inline void lock_system_sleep(void) {}
|
||||||
static inline void unlock_system_sleep(void) {}
|
static inline void unlock_system_sleep(void) {}
|
||||||
|
@ -21,7 +21,7 @@ bool irq_pm_check_wakeup(struct irq_desc *desc)
|
|||||||
desc->istate |= IRQS_SUSPENDED | IRQS_PENDING;
|
desc->istate |= IRQS_SUSPENDED | IRQS_PENDING;
|
||||||
desc->depth++;
|
desc->depth++;
|
||||||
irq_disable(desc);
|
irq_disable(desc);
|
||||||
pm_system_wakeup();
|
pm_system_irq_wakeup(irq_desc_get_irq(desc));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -733,7 +733,7 @@ int hibernate(void)
|
|||||||
* contents of memory is restored from the saved image.
|
* contents of memory is restored from the saved image.
|
||||||
*
|
*
|
||||||
* If this is successful, control reappears in the restored target kernel in
|
* If this is successful, control reappears in the restored target kernel in
|
||||||
* hibernation_snaphot() which returns to hibernate(). Otherwise, the routine
|
* hibernation_snapshot() which returns to hibernate(). Otherwise, the routine
|
||||||
* attempts to recover gracefully and make the kernel return to the normal mode
|
* attempts to recover gracefully and make the kernel return to the normal mode
|
||||||
* of operation.
|
* of operation.
|
||||||
*/
|
*/
|
||||||
|
@ -272,6 +272,22 @@ static inline void pm_print_times_init(void)
|
|||||||
{
|
{
|
||||||
pm_print_times_enabled = !!initcall_debug;
|
pm_print_times_enabled = !!initcall_debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t pm_wakeup_irq_show(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
return pm_wakeup_irq ? sprintf(buf, "%u\n", pm_wakeup_irq) : -ENODATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t pm_wakeup_irq_store(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr,
|
||||||
|
const char *buf, size_t n)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
power_attr(pm_wakeup_irq);
|
||||||
|
|
||||||
#else /* !CONFIG_PM_SLEEP_DEBUG */
|
#else /* !CONFIG_PM_SLEEP_DEBUG */
|
||||||
static inline void pm_print_times_init(void) {}
|
static inline void pm_print_times_init(void) {}
|
||||||
#endif /* CONFIG_PM_SLEEP_DEBUG */
|
#endif /* CONFIG_PM_SLEEP_DEBUG */
|
||||||
@ -604,6 +620,7 @@ static struct attribute * g[] = {
|
|||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_PM_SLEEP_DEBUG
|
#ifdef CONFIG_PM_SLEEP_DEBUG
|
||||||
&pm_print_times_attr.attr,
|
&pm_print_times_attr.attr,
|
||||||
|
&pm_wakeup_irq_attr.attr,
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_FREEZER
|
#ifdef CONFIG_FREEZER
|
||||||
|
@ -35,6 +35,9 @@
|
|||||||
const char *pm_labels[] = { "mem", "standby", "freeze", NULL };
|
const char *pm_labels[] = { "mem", "standby", "freeze", NULL };
|
||||||
const char *pm_states[PM_SUSPEND_MAX];
|
const char *pm_states[PM_SUSPEND_MAX];
|
||||||
|
|
||||||
|
unsigned int pm_suspend_global_flags;
|
||||||
|
EXPORT_SYMBOL_GPL(pm_suspend_global_flags);
|
||||||
|
|
||||||
static const struct platform_suspend_ops *suspend_ops;
|
static const struct platform_suspend_ops *suspend_ops;
|
||||||
static const struct platform_freeze_ops *freeze_ops;
|
static const struct platform_freeze_ops *freeze_ops;
|
||||||
static DECLARE_WAIT_QUEUE_HEAD(suspend_freeze_wait_head);
|
static DECLARE_WAIT_QUEUE_HEAD(suspend_freeze_wait_head);
|
||||||
@ -493,6 +496,7 @@ static int enter_state(suspend_state_t state)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
pr_debug("PM: Preparing system for sleep (%s)\n", pm_states[state]);
|
pr_debug("PM: Preparing system for sleep (%s)\n", pm_states[state]);
|
||||||
|
pm_suspend_clear_flags();
|
||||||
error = suspend_prepare(state);
|
error = suspend_prepare(state);
|
||||||
if (error)
|
if (error)
|
||||||
goto Unlock;
|
goto Unlock;
|
||||||
|
Loading…
Reference in New Issue
Block a user