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

ARM: 7565/1: sched: stop sched_clock() during suspend

The scheduler imposes a requirement to sched_clock()
which is to stop the clock during suspend, if we don't
do that any RT thread will be rescheduled in the future
which might cause any sort of problems.

This became an issue on OMAP when we converted omap-i2c.c
to use threaded IRQs, it turned out that depending on how
much time we spent on suspend, the I2C IRQ thread would
end up being rescheduled so far in the future that I2C
transfers would timeout and, because omap_hsmmc depends
on an I2C-connected device to detect if an MMC card is
inserted in the slot, our rootfs would just vanish.

arch/arm/kernel/sched_clock.c already had an optional
implementation (sched_clock_needs_suspend()) which would
handle scheduler's requirement properly, what this patch
does is simply to make that implementation non-optional.

Note that this has the side-effect that printk timings
won't reflect the actual time spent on suspend so other
methods to measure that will have to be used.

This has been tested with beagleboard XM (OMAP3630) and
pandaboard rev A3 (OMAP4430). Suspend to RAM is now working
after this patch.

Thanks to Kevin Hilman for helping out with debugging.

Acked-by: Kevin Hilman <khilman@ti.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by

Felipe Balbi 2 and committed by
Russell King
6a4dae5e b43b1ffa

+4 -16
-2
arch/arm/include/asm/sched_clock.h
··· 10 10 11 11 extern void sched_clock_postinit(void); 12 12 extern void setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate); 13 - extern void setup_sched_clock_needs_suspend(u32 (*read)(void), int bits, 14 - unsigned long rate); 15 13 16 14 #endif
+4 -14
arch/arm/kernel/sched_clock.c
··· 107 107 update_sched_clock(); 108 108 } 109 109 110 - void __init setup_sched_clock_needs_suspend(u32 (*read)(void), int bits, 111 - unsigned long rate) 112 - { 113 - setup_sched_clock(read, bits, rate); 114 - cd.needs_suspend = true; 115 - } 116 - 117 110 void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate) 118 111 { 119 112 unsigned long r, w; ··· 182 189 static int sched_clock_suspend(void) 183 190 { 184 191 sched_clock_poll(sched_clock_timer.data); 185 - if (cd.needs_suspend) 186 - cd.suspended = true; 192 + cd.suspended = true; 187 193 return 0; 188 194 } 189 195 190 196 static void sched_clock_resume(void) 191 197 { 192 - if (cd.needs_suspend) { 193 - cd.epoch_cyc = read_sched_clock(); 194 - cd.epoch_cyc_copy = cd.epoch_cyc; 195 - cd.suspended = false; 196 - } 198 + cd.epoch_cyc = read_sched_clock(); 199 + cd.epoch_cyc_copy = cd.epoch_cyc; 200 + cd.suspended = false; 197 201 } 198 202 199 203 static struct syscore_ops sched_clock_ops = {