diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2008-02-07 01:01:26 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2008-02-14 00:22:08 -0500 |
commit | 960c65e88452e761e257c6a20062c91c3e7fa5ac (patch) | |
tree | 75c2be5c6b87c685ae85c70dbeebc2b30a07256f /arch/sh | |
parent | 9216f194e4b1a967996f0335cfe2ac42df4438b7 (diff) |
sh: fix xtime_lock deadlocking.
move update_process_times() out from under xtime_lock.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh')
-rw-r--r-- | arch/sh/kernel/time_32.c | 19 | ||||
-rw-r--r-- | arch/sh/kernel/time_64.c | 31 |
2 files changed, 32 insertions, 18 deletions
diff --git a/arch/sh/kernel/time_32.c b/arch/sh/kernel/time_32.c index 2bc04bfee738..7281342c044d 100644 --- a/arch/sh/kernel/time_32.c +++ b/arch/sh/kernel/time_32.c | |||
@@ -120,10 +120,6 @@ static long last_rtc_update; | |||
120 | */ | 120 | */ |
121 | void handle_timer_tick(void) | 121 | void handle_timer_tick(void) |
122 | { | 122 | { |
123 | do_timer(1); | ||
124 | #ifndef CONFIG_SMP | ||
125 | update_process_times(user_mode(get_irq_regs())); | ||
126 | #endif | ||
127 | if (current->pid) | 123 | if (current->pid) |
128 | profile_tick(CPU_PROFILING); | 124 | profile_tick(CPU_PROFILING); |
129 | 125 | ||
@@ -133,6 +129,16 @@ void handle_timer_tick(void) | |||
133 | #endif | 129 | #endif |
134 | 130 | ||
135 | /* | 131 | /* |
132 | * Here we are in the timer irq handler. We just have irqs locally | ||
133 | * disabled but we don't know if the timer_bh is running on the other | ||
134 | * CPU. We need to avoid to SMP race with it. NOTE: we don' t need | ||
135 | * the irq version of write_lock because as just said we have irq | ||
136 | * locally disabled. -arca | ||
137 | */ | ||
138 | write_seqlock(&xtime_lock); | ||
139 | do_timer(1); | ||
140 | |||
141 | /* | ||
136 | * If we have an externally synchronized Linux clock, then update | 142 | * If we have an externally synchronized Linux clock, then update |
137 | * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be | 143 | * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be |
138 | * called as close as possible to 500 ms before the new second starts. | 144 | * called as close as possible to 500 ms before the new second starts. |
@@ -147,6 +153,11 @@ void handle_timer_tick(void) | |||
147 | /* do it again in 60s */ | 153 | /* do it again in 60s */ |
148 | last_rtc_update = xtime.tv_sec - 600; | 154 | last_rtc_update = xtime.tv_sec - 600; |
149 | } | 155 | } |
156 | write_sequnlock(&xtime_lock); | ||
157 | |||
158 | #ifndef CONFIG_SMP | ||
159 | update_process_times(user_mode(get_irq_regs())); | ||
160 | #endif | ||
150 | } | 161 | } |
151 | #endif /* !CONFIG_GENERIC_CLOCKEVENTS */ | 162 | #endif /* !CONFIG_GENERIC_CLOCKEVENTS */ |
152 | 163 | ||
diff --git a/arch/sh/kernel/time_64.c b/arch/sh/kernel/time_64.c index f819ba38a6ce..898977ee2030 100644 --- a/arch/sh/kernel/time_64.c +++ b/arch/sh/kernel/time_64.c | |||
@@ -229,15 +229,22 @@ static long last_rtc_update; | |||
229 | static inline void do_timer_interrupt(void) | 229 | static inline void do_timer_interrupt(void) |
230 | { | 230 | { |
231 | unsigned long long current_ctc; | 231 | unsigned long long current_ctc; |
232 | |||
233 | if (current->pid) | ||
234 | profile_tick(CPU_PROFILING); | ||
235 | |||
236 | /* | ||
237 | * Here we are in the timer irq handler. We just have irqs locally | ||
238 | * disabled but we don't know if the timer_bh is running on the other | ||
239 | * CPU. We need to avoid to SMP race with it. NOTE: we don' t need | ||
240 | * the irq version of write_lock because as just said we have irq | ||
241 | * locally disabled. -arca | ||
242 | */ | ||
243 | write_lock(&xtime_lock); | ||
232 | asm ("getcon cr62, %0" : "=r" (current_ctc)); | 244 | asm ("getcon cr62, %0" : "=r" (current_ctc)); |
233 | ctc_last_interrupt = (unsigned long) current_ctc; | 245 | ctc_last_interrupt = (unsigned long) current_ctc; |
234 | 246 | ||
235 | do_timer(1); | 247 | do_timer(1); |
236 | #ifndef CONFIG_SMP | ||
237 | update_process_times(user_mode(get_irq_regs())); | ||
238 | #endif | ||
239 | if (current->pid) | ||
240 | profile_tick(CPU_PROFILING); | ||
241 | 248 | ||
242 | #ifdef CONFIG_HEARTBEAT | 249 | #ifdef CONFIG_HEARTBEAT |
243 | if (sh_mv.mv_heartbeat != NULL) | 250 | if (sh_mv.mv_heartbeat != NULL) |
@@ -259,6 +266,11 @@ static inline void do_timer_interrupt(void) | |||
259 | /* do it again in 60 s */ | 266 | /* do it again in 60 s */ |
260 | last_rtc_update = xtime.tv_sec - 600; | 267 | last_rtc_update = xtime.tv_sec - 600; |
261 | } | 268 | } |
269 | write_unlock(&xtime_lock); | ||
270 | |||
271 | #ifndef CONFIG_SMP | ||
272 | update_process_times(user_mode(get_irq_regs())); | ||
273 | #endif | ||
262 | } | 274 | } |
263 | 275 | ||
264 | /* | 276 | /* |
@@ -275,16 +287,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id) | |||
275 | timer_status &= ~0x100; | 287 | timer_status &= ~0x100; |
276 | ctrl_outw(timer_status, TMU0_TCR); | 288 | ctrl_outw(timer_status, TMU0_TCR); |
277 | 289 | ||
278 | /* | ||
279 | * Here we are in the timer irq handler. We just have irqs locally | ||
280 | * disabled but we don't know if the timer_bh is running on the other | ||
281 | * CPU. We need to avoid to SMP race with it. NOTE: we don' t need | ||
282 | * the irq version of write_lock because as just said we have irq | ||
283 | * locally disabled. -arca | ||
284 | */ | ||
285 | write_lock(&xtime_lock); | ||
286 | do_timer_interrupt(); | 290 | do_timer_interrupt(); |
287 | write_unlock(&xtime_lock); | ||
288 | 291 | ||
289 | return IRQ_HANDLED; | 292 | return IRQ_HANDLED; |
290 | } | 293 | } |