diff options
Diffstat (limited to 'arch/sparc/kernel/leon_kernel.c')
-rw-r--r-- | arch/sparc/kernel/leon_kernel.c | 98 |
1 files changed, 55 insertions, 43 deletions
diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index 35e43673c453..77c1b916e4dd 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c @@ -10,6 +10,8 @@ #include <linux/of_platform.h> #include <linux/interrupt.h> #include <linux/of_device.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> #include <asm/oplib.h> #include <asm/timer.h> @@ -84,7 +86,7 @@ void leon_eirq_setup(unsigned int eirq) sparc_leon_eirq = eirq; } -static inline unsigned long get_irqmask(unsigned int irq) +unsigned long leon_get_irqmask(unsigned int irq) { unsigned long mask; @@ -210,7 +212,7 @@ unsigned int leon_build_device_irq(unsigned int real_irq, unsigned long mask; irq = 0; - mask = get_irqmask(real_irq); + mask = leon_get_irqmask(real_irq); if (mask == 0) goto out; @@ -250,7 +252,38 @@ void leon_update_virq_handling(unsigned int virq, irq_set_chip_data(virq, (void *)mask); } -void __init leon_init_timers(irq_handler_t counter_fn) +static u32 leon_cycles_offset(void) +{ + u32 rld, val, off; + rld = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld); + val = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val); + off = rld - val; + return rld - val; +} + +#ifdef CONFIG_SMP + +/* smp clockevent irq */ +irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused) +{ + struct clock_event_device *ce; + int cpu = smp_processor_id(); + + leon_clear_profile_irq(cpu); + + ce = &per_cpu(sparc32_clockevent, cpu); + + irq_enter(); + if (ce->event_handler) + ce->event_handler(ce); + irq_exit(); + + return IRQ_HANDLED; +} + +#endif /* CONFIG_SMP */ + +void __init leon_init_timers(void) { int irq, eirq; struct device_node *rootnp, *np, *nnp; @@ -260,6 +293,14 @@ void __init leon_init_timers(irq_handler_t counter_fn) int ampopts; int err; + sparc_config.get_cycles_offset = leon_cycles_offset; + sparc_config.cs_period = 1000000 / HZ; + sparc_config.features |= FEAT_L10_CLOCKSOURCE; + +#ifndef CONFIG_SMP + sparc_config.features |= FEAT_L10_CLOCKEVENT; +#endif + leondebug_irq_disable = 0; leon_debug_irqout = 0; master_l10_counter = (unsigned int *)&dummy_master_l10_counter; @@ -369,7 +410,7 @@ void __init leon_init_timers(irq_handler_t counter_fn) leon_eirq_setup(eirq); irq = _leon_build_device_irq(NULL, leon3_gptimer_irq+leon3_gptimer_idx); - err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); + 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(); @@ -386,7 +427,7 @@ void __init leon_init_timers(irq_handler_t counter_fn) */ local_irq_save(flags); patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */ - local_flush_cache_all(); + local_ops->cache_all(); local_irq_restore(flags); } #endif @@ -401,7 +442,7 @@ void __init leon_init_timers(irq_handler_t counter_fn) /* Install per-cpu IRQ handler for broadcasted ticker */ irq = leon_build_device_irq(leon3_ticker_irq, handle_percpu_irq, "per-cpu", 0); - err = request_irq(irq, leon_percpu_timer_interrupt, + err = request_irq(irq, leon_percpu_timer_ce_interrupt, IRQF_PERCPU | IRQF_TIMER, "ticker", NULL); if (err) { @@ -422,13 +463,12 @@ bad: return; } -void leon_clear_clock_irq(void) +static void leon_clear_clock_irq(void) { } -void leon_load_profile_irq(int cpu, unsigned int limit) +static void leon_load_profile_irq(int cpu, unsigned int limit) { - BUG(); } void __init leon_trans_init(struct device_node *dp) @@ -457,25 +497,6 @@ void __init leon_node_init(struct device_node *dp, struct device_node ***nextp) } #ifdef CONFIG_SMP - -void leon_set_cpu_int(int cpu, int level) -{ - unsigned long mask; - mask = get_irqmask(level); - LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->force[cpu], mask); -} - -static void leon_clear_ipi(int cpu, int level) -{ - unsigned long mask; - mask = get_irqmask(level); - LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->force[cpu], mask<<16); -} - -static void leon_set_udt(int cpu) -{ -} - void leon_clear_profile_irq(int cpu) { } @@ -483,7 +504,7 @@ void leon_clear_profile_irq(int cpu) void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu) { unsigned long mask, flags, *addr; - mask = get_irqmask(irq_nr); + mask = leon_get_irqmask(irq_nr); spin_lock_irqsave(&leon_irq_lock, flags); addr = (unsigned long *)LEON_IMASK(cpu); LEON3_BYPASS_STORE_PA(addr, (LEON3_BYPASS_LOAD_PA(addr) | mask)); @@ -494,20 +515,11 @@ void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu) void __init leon_init_IRQ(void) { - sparc_irq_config.init_timers = leon_init_timers; - sparc_irq_config.build_device_irq = _leon_build_device_irq; - - BTFIXUPSET_CALL(clear_clock_irq, leon_clear_clock_irq, - BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(load_profile_irq, leon_load_profile_irq, - BTFIXUPCALL_NOP); - -#ifdef CONFIG_SMP - BTFIXUPSET_CALL(set_cpu_int, leon_set_cpu_int, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(clear_cpu_int, leon_clear_ipi, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(set_irq_udt, leon_set_udt, BTFIXUPCALL_NORM); -#endif - + sparc_config.init_timers = leon_init_timers; + sparc_config.build_device_irq = _leon_build_device_irq; + sparc_config.clock_rate = 1000000; + sparc_config.clear_clock_irq = leon_clear_clock_irq; + sparc_config.load_profile_irq = leon_load_profile_irq; } void __init leon_init(void) |