diff options
| author | Paul Walmsley <paul@pwsan.com> | 2011-01-15 23:32:01 -0500 |
|---|---|---|
| committer | Paul Walmsley <paul@pwsan.com> | 2011-01-18 14:04:12 -0500 |
| commit | d8328f3b85f34c0dc5866f10bf6e7842fb511d62 (patch) | |
| tree | cce2477423a170a77d0ca7364fb0f2329038220c | |
| parent | e78bf5e6cbe837daa6ab628a5f679548742994d3 (diff) | |
OMAP: counter_32k: init clocksource as part of machine timer init
After commit dc548fbbd2ecd0fc3b02301d551e5f8e19ae58fd ("ARM: omap: convert
sched_clock() to use new infrastructure"), OMAPs that use the 32KiHz
"synchronization timer" as their clocksource crash during boot:
[ 0.000000] OMAP clockevent source: GPTIMER1 at 32768 Hz
[ 0.000000] Unable to handle kernel NULL pointer dereference at virtual address 00000000
[ 0.000000] pgd = c0004000
[ 0.000000] [00000000] *pgd=00000000
[ 0.000000] Internal error: Oops: 80000005 [#1] SMP
[ 0.000000] last sysfs file:
[ 0.000000] Modules linked in:
[ 0.000000] CPU: 0 Tainted: G W (2.6.37-07734-g2467802 #7)
[ 0.000000] PC is at 0x0
[ 0.000000] LR is at sched_clock_poll+0x2c/0x3c
[ 0.000000] pc : [<00000000>] lr : [<c0060b74>] psr: 600001d3
[ 0.000000] sp : c058bfd0 ip : c058a000 fp : 00000000
[ 0.000000] r10: 00000000 r9 : 411fc092 r8 : 800330c8
[ 0.000000] r7 : c05a08e0 r6 : c0034c48 r5 : c05ffc40 r4 : c0034c4c
[ 0.000000] r3 : c05ffe6c r2 : c05a0bc0 r1 : c059f098 r0 : 00000000
[ 0.000000] Flags: nZCv IRQs off FIQs off Mode SVC_32 ISA ARM Segment kernel
[ 0.000000] Control: 10c53c7f Table: 8000404a DAC: 00000017
This is due to the recent ARM init_sched_clock() changes and the late
initialization of the counter_32k clock source. More information here:
http://marc.info/?l=linux-omap&m=129513468605208&w=2
Fix by initializing the counter_32k clocksource during the machine timer
initialization.
Reported-by: Russell King <rmk+kernel@arm.linux.org.uk>
Tested-by: Thomas Weber <weber@corscience.de>
Signed-off-by: Paul Walmsley <paul@pwsan.com>
| -rw-r--r-- | arch/arm/mach-omap1/time.c | 7 | ||||
| -rw-r--r-- | arch/arm/mach-omap2/timer-gp.c | 10 | ||||
| -rw-r--r-- | arch/arm/plat-omap/counter_32k.c | 3 | ||||
| -rw-r--r-- | arch/arm/plat-omap/include/plat/common.h | 1 |
4 files changed, 17 insertions, 4 deletions
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c index ed7a61ff916..6ec65e59999 100644 --- a/arch/arm/mach-omap1/time.c +++ b/arch/arm/mach-omap1/time.c | |||
| @@ -244,6 +244,13 @@ static void __init omap_timer_init(void) | |||
| 244 | 244 | ||
| 245 | omap_init_mpu_timer(rate); | 245 | omap_init_mpu_timer(rate); |
| 246 | omap_init_clocksource(rate); | 246 | omap_init_clocksource(rate); |
| 247 | /* | ||
| 248 | * XXX Since this file seems to deal mostly with the MPU timer, | ||
| 249 | * this doesn't seem like the correct place for the sync timer | ||
| 250 | * clocksource init. | ||
| 251 | */ | ||
| 252 | if (!cpu_is_omap7xx() && !cpu_is_omap15xx()) | ||
| 253 | omap_init_clocksource_32k(); | ||
| 247 | } | 254 | } |
| 248 | 255 | ||
| 249 | struct sys_timer omap_timer = { | 256 | struct sys_timer omap_timer = { |
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c index 4e48e786bec..7b7c2683ae7 100644 --- a/arch/arm/mach-omap2/timer-gp.c +++ b/arch/arm/mach-omap2/timer-gp.c | |||
| @@ -42,6 +42,8 @@ | |||
| 42 | 42 | ||
| 43 | #include "timer-gp.h" | 43 | #include "timer-gp.h" |
| 44 | 44 | ||
| 45 | #include <plat/common.h> | ||
| 46 | |||
| 45 | /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */ | 47 | /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */ |
| 46 | #define MAX_GPTIMER_ID 12 | 48 | #define MAX_GPTIMER_ID 12 |
| 47 | 49 | ||
| @@ -176,10 +178,14 @@ static void __init omap2_gp_clockevent_init(void) | |||
| 176 | /* | 178 | /* |
| 177 | * When 32k-timer is enabled, don't use GPTimer for clocksource | 179 | * When 32k-timer is enabled, don't use GPTimer for clocksource |
| 178 | * instead, just leave default clocksource which uses the 32k | 180 | * instead, just leave default clocksource which uses the 32k |
| 179 | * sync counter. See clocksource setup in see plat-omap/common.c. | 181 | * sync counter. See clocksource setup in plat-omap/counter_32k.c |
| 180 | */ | 182 | */ |
| 181 | 183 | ||
| 182 | static inline void __init omap2_gp_clocksource_init(void) {} | 184 | static void __init omap2_gp_clocksource_init(void) |
| 185 | { | ||
| 186 | omap_init_clocksource_32k(); | ||
| 187 | } | ||
| 188 | |||
| 183 | #else | 189 | #else |
| 184 | /* | 190 | /* |
| 185 | * clocksource | 191 | * clocksource |
diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c index ea4644021fb..0367998ff68 100644 --- a/arch/arm/plat-omap/counter_32k.c +++ b/arch/arm/plat-omap/counter_32k.c | |||
| @@ -160,7 +160,7 @@ void read_persistent_clock(struct timespec *ts) | |||
| 160 | *ts = *tsp; | 160 | *ts = *tsp; |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | static int __init omap_init_clocksource_32k(void) | 163 | int __init omap_init_clocksource_32k(void) |
| 164 | { | 164 | { |
| 165 | static char err[] __initdata = KERN_ERR | 165 | static char err[] __initdata = KERN_ERR |
| 166 | "%s: can't register clocksource!\n"; | 166 | "%s: can't register clocksource!\n"; |
| @@ -195,7 +195,6 @@ static int __init omap_init_clocksource_32k(void) | |||
| 195 | } | 195 | } |
| 196 | return 0; | 196 | return 0; |
| 197 | } | 197 | } |
| 198 | arch_initcall(omap_init_clocksource_32k); | ||
| 199 | 198 | ||
| 200 | #endif /* !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) */ | 199 | #endif /* !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) */ |
| 201 | 200 | ||
diff --git a/arch/arm/plat-omap/include/plat/common.h b/arch/arm/plat-omap/include/plat/common.h index 6b8088ec74a..84c707f713b 100644 --- a/arch/arm/plat-omap/include/plat/common.h +++ b/arch/arm/plat-omap/include/plat/common.h | |||
| @@ -35,6 +35,7 @@ struct sys_timer; | |||
| 35 | 35 | ||
| 36 | extern void omap_map_common_io(void); | 36 | extern void omap_map_common_io(void); |
| 37 | extern struct sys_timer omap_timer; | 37 | extern struct sys_timer omap_timer; |
| 38 | extern int __init omap_init_clocksource_32k(void); | ||
| 38 | 39 | ||
| 39 | extern void omap_reserve(void); | 40 | extern void omap_reserve(void); |
| 40 | 41 | ||
