Skip to content

Commit

Permalink
[ARM] 3554/1: ARM: Fix dyntick locking
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Tony Lindgren authored and Russell King committed Jun 18, 2006
1 parent 36fe6a8 commit ebc67da
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 9 deletions.
4 changes: 2 additions & 2 deletions arch/arm/kernel/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,10 +342,10 @@ __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs)

#ifdef CONFIG_NO_IDLE_HZ
if (!(action->flags & SA_TIMER) && system_timer->dyn_tick != NULL) {
write_seqlock(&xtime_lock);
spin_lock(&system_timer->dyn_tick->lock);
if (system_timer->dyn_tick->state & DYN_TICK_ENABLED)
system_timer->dyn_tick->handler(irq, 0, regs);
write_sequnlock(&xtime_lock);
spin_unlock(&system_timer->dyn_tick->lock);
}
#endif

Expand Down
24 changes: 17 additions & 7 deletions arch/arm/kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,15 +379,15 @@ static int timer_dyn_tick_enable(void)
int ret = -ENODEV;

if (dyn_tick) {
write_seqlock_irqsave(&xtime_lock, flags);
spin_lock_irqsave(&dyn_tick->lock, flags);
ret = 0;
if (!(dyn_tick->state & DYN_TICK_ENABLED)) {
ret = dyn_tick->enable();

if (ret == 0)
dyn_tick->state |= DYN_TICK_ENABLED;
}
write_sequnlock_irqrestore(&xtime_lock, flags);
spin_unlock_irqrestore(&dyn_tick->lock, flags);
}

return ret;
Expand All @@ -400,15 +400,15 @@ static int timer_dyn_tick_disable(void)
int ret = -ENODEV;

if (dyn_tick) {
write_seqlock_irqsave(&xtime_lock, flags);
spin_lock_irqsave(&dyn_tick->lock, flags);
ret = 0;
if (dyn_tick->state & DYN_TICK_ENABLED) {
ret = dyn_tick->disable();

if (ret == 0)
dyn_tick->state &= ~DYN_TICK_ENABLED;
}
write_sequnlock_irqrestore(&xtime_lock, flags);
spin_unlock_irqrestore(&dyn_tick->lock, flags);
}

return ret;
Expand All @@ -422,15 +422,20 @@ static int timer_dyn_tick_disable(void)
void timer_dyn_reprogram(void)
{
struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
unsigned long next, seq;
unsigned long next, seq, flags;

if (dyn_tick && (dyn_tick->state & DYN_TICK_ENABLED)) {
if (!dyn_tick)
return;

spin_lock_irqsave(&dyn_tick->lock, flags);
if (dyn_tick->state & DYN_TICK_ENABLED) {
next = next_timer_interrupt();
do {
seq = read_seqbegin(&xtime_lock);
dyn_tick->reprogram(next_timer_interrupt() - jiffies);
dyn_tick->reprogram(next - jiffies);
} while (read_seqretry(&xtime_lock, seq));
}
spin_unlock_irqrestore(&dyn_tick->lock, flags);
}

static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
Expand Down Expand Up @@ -499,5 +504,10 @@ void __init time_init(void)
if (system_timer->offset == NULL)
system_timer->offset = dummy_gettimeoffset;
system_timer->init();

#ifdef CONFIG_NO_IDLE_HZ
if (system_timer->dyn_tick)
system_timer->dyn_tick->lock = SPIN_LOCK_UNLOCKED;
#endif
}

1 change: 1 addition & 0 deletions include/asm-arm/mach/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ struct sys_timer {
#define DYN_TICK_ENABLED (1 << 1)

struct dyn_tick_timer {
spinlock_t lock;
unsigned int state; /* Current state */
int (*enable)(void); /* Enables dynamic tick */
int (*disable)(void); /* Disables dynamic tick */
Expand Down

0 comments on commit ebc67da

Please sign in to comment.