Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] ppc32: Fix cpufreq vs. sleep issue

Recent kernels occasionally trigger a PMU timeout on some mac laptops,
typically on wakeup from sleep. This seem to be caused by either a too big
latency caused by the cpufreq switch on wakeup from sleep or by an
interrupt beeing lost due to the reset of the interrupt controller done
during wakeup.

This patch makes that code more robust by stopping PMU auto poll activity
around cpufreq changes on machines that use the PMU for such changes (long
latency switching involving a CPU hard reset and flush of all caches) and
by removing the reset of the open pic interrupt controller on wakeup (that
can cause the loss of an interrupt and Darwin doesn't do it, so it must not
be necessary).

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Benjamin Herrenschmidt and committed by
Linus Torvalds
b16eeb47 49f384b8

+9 -7
+4
arch/ppc/platforms/pmac_cpufreq.c
··· 271 271 #ifdef DEBUG_FREQ 272 272 printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); 273 273 #endif 274 + pmu_suspend(); 275 + 274 276 /* Disable all interrupt sources on openpic */ 275 277 pic_prio = openpic_get_priority(); 276 278 openpic_set_priority(0xf); ··· 346 344 #ifdef DEBUG_FREQ 347 345 debug_calc_bogomips(); 348 346 #endif 347 + 348 + pmu_resume(); 349 349 350 350 preempt_enable(); 351 351
+1 -3
arch/ppc/syslib/open_pic.c
··· 275 275 } 276 276 #endif 277 277 278 - #if defined(CONFIG_EPIC_SERIAL_MODE) || defined(CONFIG_PM) 278 + #if defined(CONFIG_EPIC_SERIAL_MODE) 279 279 static void openpic_reset(void) 280 280 { 281 281 openpic_setfield(&OpenPIC->Global.Global_Configuration0, ··· 992 992 spin_unlock_irqrestore(&openpic_setup_lock, flags); 993 993 return 0; 994 994 } 995 - 996 - openpic_reset(); 997 995 998 996 /* OpenPIC sometimes seem to need some time to be fully back up... */ 999 997 do {
+4 -4
drivers/macintosh/via-pmu.c
··· 2421 2421 2422 2422 /* Re-enable local CPU interrupts */ 2423 2423 local_irq_enable(); 2424 - mdelay(100); 2424 + mdelay(10); 2425 2425 preempt_enable(); 2426 2426 2427 2427 /* Re-enable clock spreading on some machines */ ··· 2549 2549 return ret; 2550 2550 } 2551 2551 2552 - printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); 2552 + /* Stop environment and ADB interrupts */ 2553 + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0); 2554 + pmu_wait_complete(&req); 2553 2555 2554 2556 /* Tell PMU what events will wake us up */ 2555 2557 pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS, ··· 2612 2610 pmu_wait_complete(&req); 2613 2611 pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask); 2614 2612 pmu_wait_complete(&req); 2615 - 2616 - printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); 2617 2613 2618 2614 pmac_wakeup_devices(); 2619 2615