[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>
This commit is contained in:
committed by
Russell King
parent
36fe6a83b4
commit
ebc67da65f
@@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 {
|
|||||||
#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 */
|
||||||
|
Reference in New Issue
Block a user