Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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

+17 −7
Original line number Diff line number Diff line
@@ -379,7 +379,7 @@ 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();
@@ -387,7 +387,7 @@ static int timer_dyn_tick_enable(void)
			if (ret == 0)
				dyn_tick->state |= DYN_TICK_ENABLED;
		}
		write_sequnlock_irqrestore(&xtime_lock, flags);
		spin_unlock_irqrestore(&dyn_tick->lock, flags);
	}

	return ret;
@@ -400,7 +400,7 @@ 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();
@@ -408,7 +408,7 @@ static int timer_dyn_tick_disable(void)
			if (ret == 0)
				dyn_tick->state &= ~DYN_TICK_ENABLED;
		}
		write_sequnlock_irqrestore(&xtime_lock, flags);
		spin_unlock_irqrestore(&dyn_tick->lock, flags);
	}

	return ret;
@@ -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)
@@ -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 −0
Original line number Diff line number Diff line
@@ -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 */