aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2007-12-12 12:35:19 -0500
committerPaul Mackerras <paulus@samba.org>2007-12-21 06:13:35 -0500
commit7ac5dde99eb9fefdb526973c600075b7c5703a86 (patch)
tree3ea3277339990880697d2ce89197293b7a0a2277
parentcbea92383d0d55fb4b4eb5833488bfee325254d6 (diff)
[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: Scott Wood <scottwood@freescale.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/kernel/time.c39
-rw-r--r--drivers/macintosh/via-pmu.c48
-rw-r--r--include/asm-powerpc/machdep.h13
3 files changed, 58 insertions, 42 deletions
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 85cf317c9069..5cd3db5cae41 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -629,6 +629,45 @@ void wakeup_decrementer(void)
629 set_dec(ticks); 629 set_dec(ticks);
630} 630}
631 631
632#ifdef CONFIG_SUSPEND
633void generic_suspend_disable_irqs(void)
634{
635 preempt_disable();
636
637 /* Disable the decrementer, so that it doesn't interfere
638 * with suspending.
639 */
640
641 set_dec(0x7fffffff);
642 local_irq_disable();
643 set_dec(0x7fffffff);
644}
645
646void generic_suspend_enable_irqs(void)
647{
648 wakeup_decrementer();
649
650 local_irq_enable();
651 preempt_enable();
652}
653
654/* Overrides the weak version in kernel/power/main.c */
655void arch_suspend_disable_irqs(void)
656{
657 if (ppc_md.suspend_disable_irqs)
658 ppc_md.suspend_disable_irqs();
659 generic_suspend_disable_irqs();
660}
661
662/* Overrides the weak version in kernel/power/main.c */
663void arch_suspend_enable_irqs(void)
664{
665 generic_suspend_enable_irqs();
666 if (ppc_md.suspend_enable_irqs)
667 ppc_md.suspend_enable_irqs();
668}
669#endif
670
632#ifdef CONFIG_SMP 671#ifdef CONFIG_SMP
633void __init smp_space_timers(unsigned int max_cpus) 672void __init smp_space_timers(unsigned int max_cpus)
634{ 673{
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 8f98257e6a15..7e77ac7e3705 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -197,12 +197,6 @@ static int proc_read_options(char *page, char **start, off_t off,
197static int proc_write_options(struct file *file, const char __user *buffer, 197static int proc_write_options(struct file *file, const char __user *buffer,
198 unsigned long count, void *data); 198 unsigned long count, void *data);
199 199
200#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
201static void powerbook_sleep_init_3400(void);
202#else
203#define powerbook_sleep_init_3400() do { } while (0)
204#endif
205
206#ifdef CONFIG_ADB 200#ifdef CONFIG_ADB
207struct adb_driver via_pmu_driver = { 201struct adb_driver via_pmu_driver = {
208 "PMU", 202 "PMU",
@@ -450,10 +444,6 @@ static int __init via_pmu_start(void)
450 pmu_poll(); 444 pmu_poll();
451 } while (pmu_state != idle); 445 } while (pmu_state != idle);
452 446
453 /* Do allocations and ioremaps that will be needed for sleep */
454 if (pmu_kind == PMU_OHARE_BASED)
455 powerbook_sleep_init_3400();
456
457 return 0; 447 return 0;
458} 448}
459 449
@@ -2168,13 +2158,7 @@ pmu_release(struct inode *inode, struct file *file)
2168} 2158}
2169 2159
2170#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) 2160#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
2171/* 2161static void pmac_suspend_disable_irqs(void)
2172 * overrides the weak arch_suspend_disable_irqs in kernel/power/main.c
2173 *
2174 * XXX: Once Scott Wood's patch is merged, this needs to use the ppc_md
2175 * hooks that patch adds!
2176 */
2177void arch_suspend_disable_irqs(void)
2178{ 2162{
2179#ifdef CONFIG_PMAC_BACKLIGHT 2163#ifdef CONFIG_PMAC_BACKLIGHT
2180 /* Tell backlight code not to muck around with the chip anymore */ 2164 /* Tell backlight code not to muck around with the chip anymore */
@@ -2184,18 +2168,6 @@ void arch_suspend_disable_irqs(void)
2184 /* Call platform functions marked "on sleep" */ 2168 /* Call platform functions marked "on sleep" */
2185 pmac_pfunc_i2c_suspend(); 2169 pmac_pfunc_i2c_suspend();
2186 pmac_pfunc_base_suspend(); 2170 pmac_pfunc_base_suspend();
2187
2188 /* Stop preemption */
2189 preempt_disable();
2190
2191 /* Make sure the decrementer won't interrupt us */
2192 asm volatile("mtdec %0" : : "r" (0x7fffffff));
2193 /* Make sure any pending DEC interrupt occurring while we did
2194 * the above didn't re-enable the DEC */
2195 mb();
2196 asm volatile("mtdec %0" : : "r" (0x7fffffff));
2197
2198 local_irq_disable();
2199} 2171}
2200 2172
2201static int powerbook_sleep(suspend_state_t state) 2173static int powerbook_sleep(suspend_state_t state)
@@ -2244,25 +2216,13 @@ static int powerbook_sleep(suspend_state_t state)
2244 return 0; 2216 return 0;
2245} 2217}
2246 2218
2247/* 2219static void pmac_suspend_enable_irqs(void)
2248 * overrides the weak arch_suspend_enable_irqs in kernel/power/main.c
2249 *
2250 * XXX: Once Scott Wood's patch is merged, this needs to use the ppc_md
2251 * hooks that patch adds!
2252 */
2253void arch_suspend_enable_irqs(void)
2254{ 2220{
2255 /* Force a poll of ADB interrupts */ 2221 /* Force a poll of ADB interrupts */
2256 adb_int_pending = 1; 2222 adb_int_pending = 1;
2257 via_pmu_interrupt(0, NULL); 2223 via_pmu_interrupt(0, NULL);
2258 2224
2259 /* Restart jiffies & scheduling */
2260 wakeup_decrementer();
2261
2262 /* Re-enable local CPU interrupts */
2263 local_irq_enable();
2264 mdelay(10); 2225 mdelay(10);
2265 preempt_enable();
2266 2226
2267 /* Call platform functions marked "on wake" */ 2227 /* Call platform functions marked "on wake" */
2268 pmac_pfunc_base_resume(); 2228 pmac_pfunc_base_resume();
@@ -2282,6 +2242,10 @@ static struct platform_suspend_ops pmu_pm_ops = {
2282 2242
2283static int register_pmu_pm_ops(void) 2243static int register_pmu_pm_ops(void)
2284{ 2244{
2245 if (pmu_kind == PMU_OHARE_BASED)
2246 powerbook_sleep_init_3400();
2247 ppc_md.suspend_disable_irqs = pmac_suspend_disable_irqs;
2248 ppc_md.suspend_enable_irqs = pmac_suspend_enable_irqs;
2285 suspend_set_ops(&pmu_pm_ops); 2249 suspend_set_ops(&pmu_pm_ops);
2286 2250
2287 return 0; 2251 return 0;
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
index 79c704ed5381..0872ec228c1e 100644
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -251,6 +251,16 @@ struct machdep_calls {
251 */ 251 */
252 void (*machine_kexec)(struct kimage *image); 252 void (*machine_kexec)(struct kimage *image);
253#endif /* CONFIG_KEXEC */ 253#endif /* CONFIG_KEXEC */
254
255#ifdef CONFIG_SUSPEND
256 /* These are called to disable and enable, respectively, IRQs when
257 * entering a suspend state. If NULL, then the generic versions
258 * will be called. The generic versions disable/enable the
259 * decrementer along with interrupts.
260 */
261 void (*suspend_disable_irqs)(void);
262 void (*suspend_enable_irqs)(void);
263#endif
254}; 264};
255 265
256extern void power4_idle(void); 266extern void power4_idle(void);
@@ -347,5 +357,8 @@ static inline void log_error(char *buf, unsigned int err_type, int fatal)
347#define machine_late_initcall(mach,fn) __define_machine_initcall(mach,"7",fn,7) 357#define machine_late_initcall(mach,fn) __define_machine_initcall(mach,"7",fn,7)
348#define machine_late_initcall_sync(mach,fn) __define_machine_initcall(mach,"7s",fn,7s) 358#define machine_late_initcall_sync(mach,fn) __define_machine_initcall(mach,"7s",fn,7s)
349 359
360void generic_suspend_disable_irqs(void);
361void generic_suspend_enable_irqs(void);
362
350#endif /* __KERNEL__ */ 363#endif /* __KERNEL__ */
351#endif /* _ASM_POWERPC_MACHDEP_H */ 364#endif /* _ASM_POWERPC_MACHDEP_H */