diff options
author | Tony Lindgren <tony@atomide.com> | 2006-06-18 11:26:58 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2006-06-18 11:26:58 -0400 |
commit | ebc67da65fda03cbe5b4019d91229287fddd5c6e (patch) | |
tree | 7f1f77aa0525eecfca86f066d64938c62794e663 | |
parent | 36fe6a83b4a52276eebb929ff94896fa65d83401 (diff) |
[ARM] 3554/1: ARM: Fix dyntick locking
Patch from Tony Lindgren
This patch fixes some dyntick locking issues on ARM as pointed
out by Russell King.
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | arch/arm/kernel/irq.c | 4 | ||||
-rw-r--r-- | arch/arm/kernel/time.c | 24 | ||||
-rw-r--r-- | include/asm-arm/mach/time.h | 1 |
3 files changed, 20 insertions, 9 deletions
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 2d5896b36181..bcc19fbb32df 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c | |||
@@ -342,10 +342,10 @@ __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs) | |||
342 | 342 | ||
343 | #ifdef CONFIG_NO_IDLE_HZ | 343 | #ifdef CONFIG_NO_IDLE_HZ |
344 | if (!(action->flags & SA_TIMER) && system_timer->dyn_tick != NULL) { | 344 | if (!(action->flags & SA_TIMER) && system_timer->dyn_tick != NULL) { |
345 | write_seqlock(&xtime_lock); | 345 | spin_lock(&system_timer->dyn_tick->lock); |
346 | if (system_timer->dyn_tick->state & DYN_TICK_ENABLED) | 346 | if (system_timer->dyn_tick->state & DYN_TICK_ENABLED) |
347 | system_timer->dyn_tick->handler(irq, 0, regs); | 347 | system_timer->dyn_tick->handler(irq, 0, regs); |
348 | write_sequnlock(&xtime_lock); | 348 | spin_unlock(&system_timer->dyn_tick->lock); |
349 | } | 349 | } |
350 | #endif | 350 | #endif |
351 | 351 | ||
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index d6bd435a6857..9c12d4fefbd3 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c | |||
@@ -379,7 +379,7 @@ static int timer_dyn_tick_enable(void) | |||
379 | int ret = -ENODEV; | 379 | int ret = -ENODEV; |
380 | 380 | ||
381 | if (dyn_tick) { | 381 | if (dyn_tick) { |
382 | write_seqlock_irqsave(&xtime_lock, flags); | 382 | spin_lock_irqsave(&dyn_tick->lock, flags); |
383 | ret = 0; | 383 | ret = 0; |
384 | if (!(dyn_tick->state & DYN_TICK_ENABLED)) { | 384 | if (!(dyn_tick->state & DYN_TICK_ENABLED)) { |
385 | ret = dyn_tick->enable(); | 385 | ret = dyn_tick->enable(); |
@@ -387,7 +387,7 @@ static int timer_dyn_tick_enable(void) | |||
387 | if (ret == 0) | 387 | if (ret == 0) |
388 | dyn_tick->state |= DYN_TICK_ENABLED; | 388 | dyn_tick->state |= DYN_TICK_ENABLED; |
389 | } | 389 | } |
390 | write_sequnlock_irqrestore(&xtime_lock, flags); | 390 | spin_unlock_irqrestore(&dyn_tick->lock, flags); |
391 | } | 391 | } |
392 | 392 | ||
393 | return ret; | 393 | return ret; |
@@ -400,7 +400,7 @@ static int timer_dyn_tick_disable(void) | |||
400 | int ret = -ENODEV; | 400 | int ret = -ENODEV; |
401 | 401 | ||
402 | if (dyn_tick) { | 402 | if (dyn_tick) { |
403 | write_seqlock_irqsave(&xtime_lock, flags); | 403 | spin_lock_irqsave(&dyn_tick->lock, flags); |
404 | ret = 0; | 404 | ret = 0; |
405 | if (dyn_tick->state & DYN_TICK_ENABLED) { | 405 | if (dyn_tick->state & DYN_TICK_ENABLED) { |
406 | ret = dyn_tick->disable(); | 406 | ret = dyn_tick->disable(); |
@@ -408,7 +408,7 @@ static int timer_dyn_tick_disable(void) | |||
408 | if (ret == 0) | 408 | if (ret == 0) |
409 | dyn_tick->state &= ~DYN_TICK_ENABLED; | 409 | dyn_tick->state &= ~DYN_TICK_ENABLED; |
410 | } | 410 | } |
411 | write_sequnlock_irqrestore(&xtime_lock, flags); | 411 | spin_unlock_irqrestore(&dyn_tick->lock, flags); |
412 | } | 412 | } |
413 | 413 | ||
414 | return ret; | 414 | return ret; |
@@ -422,15 +422,20 @@ static int timer_dyn_tick_disable(void) | |||
422 | void timer_dyn_reprogram(void) | 422 | void timer_dyn_reprogram(void) |
423 | { | 423 | { |
424 | struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick; | 424 | struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick; |
425 | unsigned long next, seq; | 425 | unsigned long next, seq, flags; |
426 | 426 | ||
427 | if (dyn_tick && (dyn_tick->state & DYN_TICK_ENABLED)) { | 427 | if (!dyn_tick) |
428 | return; | ||
429 | |||
430 | spin_lock_irqsave(&dyn_tick->lock, flags); | ||
431 | if (dyn_tick->state & DYN_TICK_ENABLED) { | ||
428 | next = next_timer_interrupt(); | 432 | next = next_timer_interrupt(); |
429 | do { | 433 | do { |
430 | seq = read_seqbegin(&xtime_lock); | 434 | seq = read_seqbegin(&xtime_lock); |
431 | dyn_tick->reprogram(next_timer_interrupt() - jiffies); | 435 | dyn_tick->reprogram(next - jiffies); |
432 | } while (read_seqretry(&xtime_lock, seq)); | 436 | } while (read_seqretry(&xtime_lock, seq)); |
433 | } | 437 | } |
438 | spin_unlock_irqrestore(&dyn_tick->lock, flags); | ||
434 | } | 439 | } |
435 | 440 | ||
436 | static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf) | 441 | static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf) |
@@ -499,5 +504,10 @@ void __init time_init(void) | |||
499 | if (system_timer->offset == NULL) | 504 | if (system_timer->offset == NULL) |
500 | system_timer->offset = dummy_gettimeoffset; | 505 | system_timer->offset = dummy_gettimeoffset; |
501 | system_timer->init(); | 506 | system_timer->init(); |
507 | |||
508 | #ifdef CONFIG_NO_IDLE_HZ | ||
509 | if (system_timer->dyn_tick) | ||
510 | system_timer->dyn_tick->lock = SPIN_LOCK_UNLOCKED; | ||
511 | #endif | ||
502 | } | 512 | } |
503 | 513 | ||
diff --git a/include/asm-arm/mach/time.h b/include/asm-arm/mach/time.h index 96c6db7dd0e1..9f28073559e8 100644 --- a/include/asm-arm/mach/time.h +++ b/include/asm-arm/mach/time.h | |||
@@ -50,6 +50,7 @@ struct sys_timer { | |||
50 | #define DYN_TICK_ENABLED (1 << 1) | 50 | #define DYN_TICK_ENABLED (1 << 1) |
51 | 51 | ||
52 | struct dyn_tick_timer { | 52 | struct dyn_tick_timer { |
53 | spinlock_t lock; | ||
53 | unsigned int state; /* Current state */ | 54 | unsigned int state; /* Current state */ |
54 | int (*enable)(void); /* Enables dynamic tick */ | 55 | int (*enable)(void); /* Enables dynamic tick */ |
55 | int (*disable)(void); /* Disables dynamic tick */ | 56 | int (*disable)(void); /* Disables dynamic tick */ |