Commit ebc67da6 authored by Tony Lindgren's avatar Tony Lindgren Committed by Russell King

[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: default avatarTony Lindgren <tony@atomide.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 36fe6a83
...@@ -342,10 +342,10 @@ __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs) ...@@ -342,10 +342,10 @@ __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs)
#ifdef CONFIG_NO_IDLE_HZ #ifdef CONFIG_NO_IDLE_HZ
if (!(action->flags & SA_TIMER) && system_timer->dyn_tick != NULL) { 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) if (system_timer->dyn_tick->state & DYN_TICK_ENABLED)
system_timer->dyn_tick->handler(irq, 0, regs); system_timer->dyn_tick->handler(irq, 0, regs);
write_sequnlock(&xtime_lock); spin_unlock(&system_timer->dyn_tick->lock);
} }
#endif #endif
......
...@@ -379,7 +379,7 @@ static int timer_dyn_tick_enable(void) ...@@ -379,7 +379,7 @@ static int timer_dyn_tick_enable(void)
int ret = -ENODEV; int ret = -ENODEV;
if (dyn_tick) { if (dyn_tick) {
write_seqlock_irqsave(&xtime_lock, flags); spin_lock_irqsave(&dyn_tick->lock, flags);
ret = 0; ret = 0;
if (!(dyn_tick->state & DYN_TICK_ENABLED)) { if (!(dyn_tick->state & DYN_TICK_ENABLED)) {
ret = dyn_tick->enable(); ret = dyn_tick->enable();
...@@ -387,7 +387,7 @@ static int timer_dyn_tick_enable(void) ...@@ -387,7 +387,7 @@ static int timer_dyn_tick_enable(void)
if (ret == 0) if (ret == 0)
dyn_tick->state |= DYN_TICK_ENABLED; dyn_tick->state |= DYN_TICK_ENABLED;
} }
write_sequnlock_irqrestore(&xtime_lock, flags); spin_unlock_irqrestore(&dyn_tick->lock, flags);
} }
return ret; return ret;
...@@ -400,7 +400,7 @@ static int timer_dyn_tick_disable(void) ...@@ -400,7 +400,7 @@ static int timer_dyn_tick_disable(void)
int ret = -ENODEV; int ret = -ENODEV;
if (dyn_tick) { if (dyn_tick) {
write_seqlock_irqsave(&xtime_lock, flags); spin_lock_irqsave(&dyn_tick->lock, flags);
ret = 0; ret = 0;
if (dyn_tick->state & DYN_TICK_ENABLED) { if (dyn_tick->state & DYN_TICK_ENABLED) {
ret = dyn_tick->disable(); ret = dyn_tick->disable();
...@@ -408,7 +408,7 @@ static int timer_dyn_tick_disable(void) ...@@ -408,7 +408,7 @@ static int timer_dyn_tick_disable(void)
if (ret == 0) if (ret == 0)
dyn_tick->state &= ~DYN_TICK_ENABLED; dyn_tick->state &= ~DYN_TICK_ENABLED;
} }
write_sequnlock_irqrestore(&xtime_lock, flags); spin_unlock_irqrestore(&dyn_tick->lock, flags);
} }
return ret; return ret;
...@@ -422,15 +422,20 @@ static int timer_dyn_tick_disable(void) ...@@ -422,15 +422,20 @@ static int timer_dyn_tick_disable(void)
void timer_dyn_reprogram(void) void timer_dyn_reprogram(void)
{ {
struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick; 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(); next = next_timer_interrupt();
do { do {
seq = read_seqbegin(&xtime_lock); seq = read_seqbegin(&xtime_lock);
dyn_tick->reprogram(next_timer_interrupt() - jiffies); dyn_tick->reprogram(next - jiffies);
} while (read_seqretry(&xtime_lock, seq)); } 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) static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
...@@ -499,5 +504,10 @@ void __init time_init(void) ...@@ -499,5 +504,10 @@ void __init time_init(void)
if (system_timer->offset == NULL) if (system_timer->offset == NULL)
system_timer->offset = dummy_gettimeoffset; system_timer->offset = dummy_gettimeoffset;
system_timer->init(); system_timer->init();
#ifdef CONFIG_NO_IDLE_HZ
if (system_timer->dyn_tick)
system_timer->dyn_tick->lock = SPIN_LOCK_UNLOCKED;
#endif
} }
...@@ -50,6 +50,7 @@ struct sys_timer { ...@@ -50,6 +50,7 @@ struct sys_timer {
#define DYN_TICK_ENABLED (1 << 1) #define DYN_TICK_ENABLED (1 << 1)
struct dyn_tick_timer { struct dyn_tick_timer {
spinlock_t lock;
unsigned int state; /* Current state */ unsigned int state; /* Current state */
int (*enable)(void); /* Enables dynamic tick */ int (*enable)(void); /* Enables dynamic tick */
int (*disable)(void); /* Disables dynamic tick */ int (*disable)(void); /* Disables dynamic tick */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment