diff options
author | Xinyu Chen <xinyu.chen@freescale.com> | 2012-03-16 09:42:34 +0800 |
---|---|---|
committer | Xinyu Chen <xinyu.chen@freescale.com> | 2012-03-16 09:54:46 +0800 |
commit | 4b5cdefdbcb3eb0c01efc714e2b7fe6d8fb5ca21 (patch) | |
tree | 63fa92f684fa43a7975fa70c5855c43b0d316ac0 | |
parent | 779beac355abcaffdefc958feec5b0a2992d850d (diff) |
ENGR00175844 irq: enable IRQF_EARLY_RESUME irq when dpm_suspend_noirq failed
The dpm_suspend_noirq routing calls suspend_device_irqs()
first to disable all the irq no matter what flags it has.
Then it enumerates the device driver on dpm_suspend_list to
call their suspend_noirq pm callback. If any dev suspend
failed, it will call dpm_resume_noirq to re-enable all
the irq without IRQF_EARLY_RESUME, and return failed.
If dpm_suspend_noirq() return failed, then no syscore_resume()
can be called, that means the irq with flag IRQF_EARLY_RESUME,
can not be re-enabled on this case.
error = dpm_suspend_noirq(PMSG_SUSPEND);
if (error) {
..
goto Platform_finish;
}
....
error = syscore_suspend();
if (!error) {
...
syscore_resume();
}
...
dpm_resume_noirq(PMSG_RESUME);
Platform_finish:
if (suspend_ops->finish)
suspend_ops->finish();
So we must enable all the irqs no matter it's IRQF_EARLY_RESUME
or not.
Otherwise the GPIO power key who's irq has flag of IRQF_EARLY_RESUME
will be disabled forever when some device failed to suspend.
Signed-off-by: Xinyu Chen <xinyu.chen@freescale.com>
-rw-r--r-- | drivers/base/power/main.c | 4 | ||||
-rw-r--r-- | include/linux/interrupt.h | 2 | ||||
-rw-r--r-- | kernel/irq/pm.c | 3 |
3 files changed, 7 insertions, 2 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 93a5a81ebfa3..b4e94fce22d1 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -870,8 +870,10 @@ int dpm_suspend_noirq(pm_message_t state) put_device(dev); } mutex_unlock(&dpm_list_mtx); - if (error) + if (error) { + resume_irqs(true); dpm_resume_noirq(resume_event(state)); + } else dpm_show_time(starttime, state, "late"); return error; diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index b9490bf39399..61ace3b6f482 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -216,6 +216,7 @@ extern void enable_irq(unsigned int irq); #ifdef CONFIG_GENERIC_HARDIRQS extern void suspend_device_irqs(void); extern void resume_device_irqs(void); +extern void resume_irqs(bool); #ifdef CONFIG_PM_SLEEP extern int check_wakeup_irqs(void); #else @@ -224,6 +225,7 @@ static inline int check_wakeup_irqs(void) { return 0; } #else static inline void suspend_device_irqs(void) { }; static inline void resume_device_irqs(void) { }; +extern inline void resume_irqs(bool) { }; static inline int check_wakeup_irqs(void) { return 0; } #endif diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index fe4b09cf829c..bbf72985efd1 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -40,7 +40,7 @@ void suspend_device_irqs(void) } EXPORT_SYMBOL_GPL(suspend_device_irqs); -static void resume_irqs(bool want_early) +void resume_irqs(bool want_early) { struct irq_desc *desc; int irq; @@ -58,6 +58,7 @@ static void resume_irqs(bool want_early) raw_spin_unlock_irqrestore(&desc->lock, flags); } } +EXPORT_SYMBOL_GPL(resume_irqs); /** * irq_pm_syscore_ops - enable interrupt lines early |