Commit 1ffbc51a authored by Andreas Larsson's avatar Andreas Larsson Committed by David S. Miller

sparc32, leon: Remove separate "ticker" timer for SMP

This reduces the need from two timers to one timer.

Moreover, without this patch, when the "ticker" timer triggers timer_cs_read via
tick_periodic it reads the value of the usual timer it can get an wrapped timer
value without timer_cs_internal_counter having been updated leading to the clock
going backwards. This effectively hangs one cpu that gets stuck in
update_wall_time with an offset slightly smaller than 0xffffffffffffffff.
Signed-off-by: default avatarAndreas Larsson <andreas@gaisler.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 117a0c5f
...@@ -135,7 +135,7 @@ static inline int sparc_leon3_cpuid(void) ...@@ -135,7 +135,7 @@ static inline int sparc_leon3_cpuid(void)
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
# define LEON3_IRQ_IPI_DEFAULT 13 # define LEON3_IRQ_IPI_DEFAULT 13
# define LEON3_IRQ_TICKER (leon3_ticker_irq) # define LEON3_IRQ_TICKER (leon3_gptimer_irq)
# define LEON3_IRQ_CROSS_CALL 15 # define LEON3_IRQ_CROSS_CALL 15
#endif #endif
......
...@@ -47,6 +47,7 @@ struct amba_prom_registers { ...@@ -47,6 +47,7 @@ struct amba_prom_registers {
#define LEON3_GPTIMER_LD 4 #define LEON3_GPTIMER_LD 4
#define LEON3_GPTIMER_IRQEN 8 #define LEON3_GPTIMER_IRQEN 8
#define LEON3_GPTIMER_SEPIRQ 8 #define LEON3_GPTIMER_SEPIRQ 8
#define LEON3_GPTIMER_TIMERS 0x7
#define LEON23_REG_TIMER_CONTROL_EN 0x00000001 /* 1 = enable counting */ #define LEON23_REG_TIMER_CONTROL_EN 0x00000001 /* 1 = enable counting */
/* 0 = hold scalar and counter */ /* 0 = hold scalar and counter */
......
...@@ -38,7 +38,6 @@ static DEFINE_SPINLOCK(leon_irq_lock); ...@@ -38,7 +38,6 @@ static DEFINE_SPINLOCK(leon_irq_lock);
unsigned long leon3_gptimer_irq; /* interrupt controller irq number */ unsigned long leon3_gptimer_irq; /* interrupt controller irq number */
unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */ unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */
int leon3_ticker_irq; /* Timer ticker IRQ */
unsigned int sparc_leon_eirq; unsigned int sparc_leon_eirq;
#define LEON_IMASK(cpu) (&leon3_irqctrl_regs->mask[cpu]) #define LEON_IMASK(cpu) (&leon3_irqctrl_regs->mask[cpu])
#define LEON_IACK (&leon3_irqctrl_regs->iclear) #define LEON_IACK (&leon3_irqctrl_regs->iclear)
...@@ -278,6 +277,9 @@ irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused) ...@@ -278,6 +277,9 @@ irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused)
leon_clear_profile_irq(cpu); leon_clear_profile_irq(cpu);
if (cpu == boot_cpu_id)
timer_interrupt(irq, NULL);
ce = &per_cpu(sparc32_clockevent, cpu); ce = &per_cpu(sparc32_clockevent, cpu);
irq_enter(); irq_enter();
...@@ -299,6 +301,7 @@ void __init leon_init_timers(void) ...@@ -299,6 +301,7 @@ void __init leon_init_timers(void)
int icsel; int icsel;
int ampopts; int ampopts;
int err; int err;
u32 config;
sparc_config.get_cycles_offset = leon_cycles_offset; sparc_config.get_cycles_offset = leon_cycles_offset;
sparc_config.cs_period = 1000000 / HZ; sparc_config.cs_period = 1000000 / HZ;
...@@ -377,23 +380,6 @@ void __init leon_init_timers(void) ...@@ -377,23 +380,6 @@ void __init leon_init_timers(void)
LEON3_BYPASS_STORE_PA( LEON3_BYPASS_STORE_PA(
&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, 0); &leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, 0);
#ifdef CONFIG_SMP
leon3_ticker_irq = leon3_gptimer_irq + 1 + leon3_gptimer_idx;
if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) &
(1<<LEON3_GPTIMER_SEPIRQ))) {
printk(KERN_ERR "timer not configured with separate irqs\n");
BUG();
}
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].val,
0);
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].rld,
(((1000000/HZ) - 1)));
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl,
0);
#endif
/* /*
* The IRQ controller may (if implemented) consist of multiple * The IRQ controller may (if implemented) consist of multiple
* IRQ controllers, each mapped on a 4Kb boundary. * IRQ controllers, each mapped on a 4Kb boundary.
...@@ -416,13 +402,6 @@ void __init leon_init_timers(void) ...@@ -416,13 +402,6 @@ void __init leon_init_timers(void)
if (eirq != 0) if (eirq != 0)
leon_eirq_setup(eirq); leon_eirq_setup(eirq);
irq = _leon_build_device_irq(NULL, leon3_gptimer_irq+leon3_gptimer_idx);
err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
if (err) {
printk(KERN_ERR "unable to attach timer IRQ%d\n", irq);
prom_halt();
}
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
{ {
unsigned long flags; unsigned long flags;
...@@ -439,30 +418,31 @@ void __init leon_init_timers(void) ...@@ -439,30 +418,31 @@ void __init leon_init_timers(void)
} }
#endif #endif
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, config = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config);
LEON3_GPTIMER_EN | if (config & (1 << LEON3_GPTIMER_SEPIRQ))
LEON3_GPTIMER_RL | leon3_gptimer_irq += leon3_gptimer_idx;
LEON3_GPTIMER_LD | else if ((config & LEON3_GPTIMER_TIMERS) > 1)
LEON3_GPTIMER_IRQEN); pr_warn("GPTIMER uses shared irqs, using other timers of the same core will fail.\n");
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* Install per-cpu IRQ handler for broadcasted ticker */ /* Install per-cpu IRQ handler for broadcasted ticker */
irq = leon_build_device_irq(leon3_ticker_irq, handle_percpu_irq, irq = leon_build_device_irq(leon3_gptimer_irq, handle_percpu_irq,
"per-cpu", 0); "per-cpu", 0);
err = request_irq(irq, leon_percpu_timer_ce_interrupt, err = request_irq(irq, leon_percpu_timer_ce_interrupt,
IRQF_PERCPU | IRQF_TIMER, "ticker", IRQF_PERCPU | IRQF_TIMER, "timer", NULL);
NULL); #else
irq = _leon_build_device_irq(NULL, leon3_gptimer_irq);
err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
#endif
if (err) { if (err) {
printk(KERN_ERR "unable to attach ticker IRQ%d\n", irq); pr_err("Unable to attach timer IRQ%d\n", irq);
prom_halt(); prom_halt();
} }
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl,
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl,
LEON3_GPTIMER_EN | LEON3_GPTIMER_EN |
LEON3_GPTIMER_RL | LEON3_GPTIMER_RL |
LEON3_GPTIMER_LD | LEON3_GPTIMER_LD |
LEON3_GPTIMER_IRQEN); LEON3_GPTIMER_IRQEN);
#endif
return; return;
bad: bad:
printk(KERN_ERR "No Timer/irqctrl found\n"); printk(KERN_ERR "No Timer/irqctrl found\n");
......
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