Commit 7ac5dde9 authored by Scott Wood's avatar Scott Wood Committed by Paul Mackerras

[POWERPC] Implement arch disable/enable irq hooks.

These hooks ensure that a decrementer interrupt is not pending when
suspending; otherwise, problems may occur on 6xx/7xx/7xxx-based
systems (except for powermacs, which use a separate suspend path).
For example, with deep sleep on the 831x, a pending decrementer will
cause a system freeze because the SoC thinks the decrementer interrupt
would have woken the system, but the core must have interrupts
disabled due to the setup required for deep sleep.

Changed via-pmu.c to use the new ppc_md hooks, and made the arch_*
functions call the generic_* functions unconditionally.  -- paulus
Signed-off-by: default avatarScott Wood <scottwood@freescale.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent cbea9238
...@@ -629,6 +629,45 @@ void wakeup_decrementer(void) ...@@ -629,6 +629,45 @@ void wakeup_decrementer(void)
set_dec(ticks); set_dec(ticks);
} }
#ifdef CONFIG_SUSPEND
void generic_suspend_disable_irqs(void)
{
preempt_disable();
/* Disable the decrementer, so that it doesn't interfere
* with suspending.
*/
set_dec(0x7fffffff);
local_irq_disable();
set_dec(0x7fffffff);
}
void generic_suspend_enable_irqs(void)
{
wakeup_decrementer();
local_irq_enable();
preempt_enable();
}
/* Overrides the weak version in kernel/power/main.c */
void arch_suspend_disable_irqs(void)
{
if (ppc_md.suspend_disable_irqs)
ppc_md.suspend_disable_irqs();
generic_suspend_disable_irqs();
}
/* Overrides the weak version in kernel/power/main.c */
void arch_suspend_enable_irqs(void)
{
generic_suspend_enable_irqs();
if (ppc_md.suspend_enable_irqs)
ppc_md.suspend_enable_irqs();
}
#endif
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
void __init smp_space_timers(unsigned int max_cpus) void __init smp_space_timers(unsigned int max_cpus)
{ {
......
...@@ -197,12 +197,6 @@ static int proc_read_options(char *page, char **start, off_t off, ...@@ -197,12 +197,6 @@ static int proc_read_options(char *page, char **start, off_t off,
static int proc_write_options(struct file *file, const char __user *buffer, static int proc_write_options(struct file *file, const char __user *buffer,
unsigned long count, void *data); unsigned long count, void *data);
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
static void powerbook_sleep_init_3400(void);
#else
#define powerbook_sleep_init_3400() do { } while (0)
#endif
#ifdef CONFIG_ADB #ifdef CONFIG_ADB
struct adb_driver via_pmu_driver = { struct adb_driver via_pmu_driver = {
"PMU", "PMU",
...@@ -450,10 +444,6 @@ static int __init via_pmu_start(void) ...@@ -450,10 +444,6 @@ static int __init via_pmu_start(void)
pmu_poll(); pmu_poll();
} while (pmu_state != idle); } while (pmu_state != idle);
/* Do allocations and ioremaps that will be needed for sleep */
if (pmu_kind == PMU_OHARE_BASED)
powerbook_sleep_init_3400();
return 0; return 0;
} }
...@@ -2168,13 +2158,7 @@ pmu_release(struct inode *inode, struct file *file) ...@@ -2168,13 +2158,7 @@ pmu_release(struct inode *inode, struct file *file)
} }
#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
/* static void pmac_suspend_disable_irqs(void)
* overrides the weak arch_suspend_disable_irqs in kernel/power/main.c
*
* XXX: Once Scott Wood's patch is merged, this needs to use the ppc_md
* hooks that patch adds!
*/
void arch_suspend_disable_irqs(void)
{ {
#ifdef CONFIG_PMAC_BACKLIGHT #ifdef CONFIG_PMAC_BACKLIGHT
/* Tell backlight code not to muck around with the chip anymore */ /* Tell backlight code not to muck around with the chip anymore */
...@@ -2184,18 +2168,6 @@ void arch_suspend_disable_irqs(void) ...@@ -2184,18 +2168,6 @@ void arch_suspend_disable_irqs(void)
/* Call platform functions marked "on sleep" */ /* Call platform functions marked "on sleep" */
pmac_pfunc_i2c_suspend(); pmac_pfunc_i2c_suspend();
pmac_pfunc_base_suspend(); pmac_pfunc_base_suspend();
/* Stop preemption */
preempt_disable();
/* Make sure the decrementer won't interrupt us */
asm volatile("mtdec %0" : : "r" (0x7fffffff));
/* Make sure any pending DEC interrupt occurring while we did
* the above didn't re-enable the DEC */
mb();
asm volatile("mtdec %0" : : "r" (0x7fffffff));
local_irq_disable();
} }
static int powerbook_sleep(suspend_state_t state) static int powerbook_sleep(suspend_state_t state)
...@@ -2244,25 +2216,13 @@ static int powerbook_sleep(suspend_state_t state) ...@@ -2244,25 +2216,13 @@ static int powerbook_sleep(suspend_state_t state)
return 0; return 0;
} }
/* static void pmac_suspend_enable_irqs(void)
* overrides the weak arch_suspend_enable_irqs in kernel/power/main.c
*
* XXX: Once Scott Wood's patch is merged, this needs to use the ppc_md
* hooks that patch adds!
*/
void arch_suspend_enable_irqs(void)
{ {
/* Force a poll of ADB interrupts */ /* Force a poll of ADB interrupts */
adb_int_pending = 1; adb_int_pending = 1;
via_pmu_interrupt(0, NULL); via_pmu_interrupt(0, NULL);
/* Restart jiffies & scheduling */
wakeup_decrementer();
/* Re-enable local CPU interrupts */
local_irq_enable();
mdelay(10); mdelay(10);
preempt_enable();
/* Call platform functions marked "on wake" */ /* Call platform functions marked "on wake" */
pmac_pfunc_base_resume(); pmac_pfunc_base_resume();
...@@ -2282,6 +2242,10 @@ static struct platform_suspend_ops pmu_pm_ops = { ...@@ -2282,6 +2242,10 @@ static struct platform_suspend_ops pmu_pm_ops = {
static int register_pmu_pm_ops(void) static int register_pmu_pm_ops(void)
{ {
if (pmu_kind == PMU_OHARE_BASED)
powerbook_sleep_init_3400();
ppc_md.suspend_disable_irqs = pmac_suspend_disable_irqs;
ppc_md.suspend_enable_irqs = pmac_suspend_enable_irqs;
suspend_set_ops(&pmu_pm_ops); suspend_set_ops(&pmu_pm_ops);
return 0; return 0;
......
...@@ -251,6 +251,16 @@ struct machdep_calls { ...@@ -251,6 +251,16 @@ struct machdep_calls {
*/ */
void (*machine_kexec)(struct kimage *image); void (*machine_kexec)(struct kimage *image);
#endif /* CONFIG_KEXEC */ #endif /* CONFIG_KEXEC */
#ifdef CONFIG_SUSPEND
/* These are called to disable and enable, respectively, IRQs when
* entering a suspend state. If NULL, then the generic versions
* will be called. The generic versions disable/enable the
* decrementer along with interrupts.
*/
void (*suspend_disable_irqs)(void);
void (*suspend_enable_irqs)(void);
#endif
}; };
extern void power4_idle(void); extern void power4_idle(void);
...@@ -347,5 +357,8 @@ static inline void log_error(char *buf, unsigned int err_type, int fatal) ...@@ -347,5 +357,8 @@ static inline void log_error(char *buf, unsigned int err_type, int fatal)
#define machine_late_initcall(mach,fn) __define_machine_initcall(mach,"7",fn,7) #define machine_late_initcall(mach,fn) __define_machine_initcall(mach,"7",fn,7)
#define machine_late_initcall_sync(mach,fn) __define_machine_initcall(mach,"7s",fn,7s) #define machine_late_initcall_sync(mach,fn) __define_machine_initcall(mach,"7s",fn,7s)
void generic_suspend_disable_irqs(void);
void generic_suspend_enable_irqs(void);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_MACHDEP_H */ #endif /* _ASM_POWERPC_MACHDEP_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment