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 */ | 
