diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2008-02-07 15:01:26 +0900 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2008-02-14 14:22:08 +0900 |
commit | 960c65e88452e761e257c6a20062c91c3e7fa5ac (patch) | |
tree | 75c2be5c6b87c685ae85c70dbeebc2b30a07256f /arch | |
parent | 9216f194e4b1a967996f0335cfe2ac42df4438b7 (diff) | |
download | linux-960c65e88452e761e257c6a20062c91c3e7fa5ac.tar.bz2 |
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')
-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; */ void handle_timer_tick(void) { - do_timer(1); -#ifndef CONFIG_SMP - update_process_times(user_mode(get_irq_regs())); -#endif if (current->pid) profile_tick(CPU_PROFILING); @@ -133,6 +129,16 @@ void handle_timer_tick(void) #endif /* + * Here we are in the timer irq handler. We just have irqs locally + * disabled but we don't know if the timer_bh is running on the other + * CPU. We need to avoid to SMP race with it. NOTE: we don' t need + * the irq version of write_lock because as just said we have irq + * locally disabled. -arca + */ + write_seqlock(&xtime_lock); + do_timer(1); + + /* * If we have an externally synchronized Linux clock, then update * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be * called as close as possible to 500 ms before the new second starts. @@ -147,6 +153,11 @@ void handle_timer_tick(void) /* do it again in 60s */ last_rtc_update = xtime.tv_sec - 600; } + write_sequnlock(&xtime_lock); + +#ifndef CONFIG_SMP + update_process_times(user_mode(get_irq_regs())); +#endif } #endif /* !CONFIG_GENERIC_CLOCKEVENTS */ 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; static inline void do_timer_interrupt(void) { unsigned long long current_ctc; + + if (current->pid) + profile_tick(CPU_PROFILING); + + /* + * Here we are in the timer irq handler. We just have irqs locally + * disabled but we don't know if the timer_bh is running on the other + * CPU. We need to avoid to SMP race with it. NOTE: we don' t need + * the irq version of write_lock because as just said we have irq + * locally disabled. -arca + */ + write_lock(&xtime_lock); asm ("getcon cr62, %0" : "=r" (current_ctc)); ctc_last_interrupt = (unsigned long) current_ctc; do_timer(1); -#ifndef CONFIG_SMP - update_process_times(user_mode(get_irq_regs())); -#endif - if (current->pid) - profile_tick(CPU_PROFILING); #ifdef CONFIG_HEARTBEAT if (sh_mv.mv_heartbeat != NULL) @@ -259,6 +266,11 @@ static inline void do_timer_interrupt(void) /* do it again in 60 s */ last_rtc_update = xtime.tv_sec - 600; } + write_unlock(&xtime_lock); + +#ifndef CONFIG_SMP + update_process_times(user_mode(get_irq_regs())); +#endif } /* @@ -275,16 +287,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id) timer_status &= ~0x100; ctrl_outw(timer_status, TMU0_TCR); - /* - * Here we are in the timer irq handler. We just have irqs locally - * disabled but we don't know if the timer_bh is running on the other - * CPU. We need to avoid to SMP race with it. NOTE: we don' t need - * the irq version of write_lock because as just said we have irq - * locally disabled. -arca - */ - write_lock(&xtime_lock); do_timer_interrupt(); - write_unlock(&xtime_lock); return IRQ_HANDLED; } |