summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXinyu Chen <xinyu.chen@freescale.com>2012-03-16 09:42:34 +0800
committerXinyu Chen <xinyu.chen@freescale.com>2012-03-16 09:54:46 +0800
commit4b5cdefdbcb3eb0c01efc714e2b7fe6d8fb5ca21 (patch)
tree63fa92f684fa43a7975fa70c5855c43b0d316ac0
parent779beac355abcaffdefc958feec5b0a2992d850d (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.c4
-rw-r--r--include/linux/interrupt.h2
-rw-r--r--kernel/irq/pm.c3
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