Loading arch/arm/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -859,6 +859,7 @@ source "kernel/time/Kconfig" config SMP bool "Symmetric Multi-Processing (EXPERIMENTAL)" depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP) depends on GENERIC_CLOCKEVENTS select USE_GENERIC_SMP_HELPERS help This enables support for systems with more than one CPU. If you have Loading arch/arm/include/asm/localtimer.h 0 → 100644 +51 −0 Original line number Diff line number Diff line /* * arch/arm/include/asm/localtimer.h * * Copyright (C) 2004-2005 ARM Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #ifndef __ASM_ARM_LOCALTIMER_H #define __ASM_ARM_LOCALTIMER_H struct clock_event_device; /* * Setup a per-cpu timer, whether it be a local timer or dummy broadcast */ void percpu_timer_setup(void); /* * Called from assembly, this is the local timer IRQ handler */ asmlinkage void do_local_timer(struct pt_regs *); #ifdef CONFIG_LOCAL_TIMERS /* * Platform provides this to acknowledge a local timer IRQ. * Returns true if the local timer IRQ is to be processed. */ int local_timer_ack(void); /* * Stop a local timer interrupt. */ void local_timer_stop(void); /* * Setup a local timer interrupt for a CPU. */ void local_timer_setup(struct clock_event_device *); #else static inline void local_timer_stop(void) { } #endif #endif arch/arm/include/asm/smp.h +0 −40 Original line number Diff line number Diff line Loading @@ -55,11 +55,6 @@ extern void smp_store_cpu_info(unsigned int cpuid); */ extern void smp_cross_call(const struct cpumask *mask); /* * Broadcast a clock event to other CPUs. */ extern void smp_timer_broadcast(const struct cpumask *mask); /* * Boot a secondary CPU, and assign it the specified idle task. * This also gives us the initial stack to use for this CPU. Loading Loading @@ -100,44 +95,9 @@ extern void arch_send_call_function_single_ipi(int cpu); extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); #define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask /* * Local timer interrupt handling function (can be IPI'ed). */ extern void local_timer_interrupt(void); #ifdef CONFIG_LOCAL_TIMERS /* * Stop a local timer interrupt. */ extern void local_timer_stop(void); /* * Platform provides this to acknowledge a local timer IRQ */ extern int local_timer_ack(void); #else static inline void local_timer_stop(void) { } #endif /* * Setup a local timer interrupt for a CPU. */ extern void local_timer_setup(void); /* * show local interrupt info */ extern void show_local_irqs(struct seq_file *); /* * Called from assembly, this is the local timer IRQ handler */ asmlinkage void do_local_timer(struct pt_regs *); #endif /* ifndef __ASM_ARM_SMP_H */ arch/arm/kernel/smp.c +48 −8 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ #include <linux/smp.h> #include <linux/seq_file.h> #include <linux/irq.h> #include <linux/percpu.h> #include <linux/clockchips.h> #include <asm/atomic.h> #include <asm/cacheflush.h> Loading @@ -32,6 +34,7 @@ #include <asm/processor.h> #include <asm/tlbflush.h> #include <asm/ptrace.h> #include <asm/localtimer.h> /* * as from 2.5, kernels no longer have an init_tasks structure Loading Loading @@ -274,9 +277,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void) local_fiq_enable(); /* * Setup local timer for this CPU. * Setup the percpu timer for this CPU. */ local_timer_setup(); percpu_timer_setup(); calibrate_delay(); Loading Loading @@ -383,10 +386,16 @@ void show_local_irqs(struct seq_file *p) seq_putc(p, '\n'); } /* * Timer (local or broadcast) support */ static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent); static void ipi_timer(void) { struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent); irq_enter(); local_timer_interrupt(); evt->event_handler(evt); irq_exit(); } Loading @@ -405,6 +414,42 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs) } #endif #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST static void smp_timer_broadcast(const struct cpumask *mask) { send_ipi_message(mask, IPI_TIMER); } static void broadcast_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { } static void local_timer_setup(struct clock_event_device *evt) { evt->name = "dummy_timer"; evt->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_DUMMY; evt->rating = 400; evt->mult = 1; evt->set_mode = broadcast_timer_set_mode; evt->broadcast = smp_timer_broadcast; clockevents_register_device(evt); } #endif void __cpuinit percpu_timer_setup(void) { unsigned int cpu = smp_processor_id(); struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); evt->cpumask = cpumask_of(cpu); local_timer_setup(evt); } static DEFINE_SPINLOCK(stop_lock); /* Loading Loading @@ -501,11 +546,6 @@ void smp_send_reschedule(int cpu) send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); } void smp_timer_broadcast(const struct cpumask *mask) { send_ipi_message(mask, IPI_TIMER); } void smp_send_stop(void) { cpumask_t mask = cpu_online_map; Loading arch/arm/mach-realview/localtimer.c +14 −56 Original line number Diff line number Diff line Loading @@ -11,10 +11,8 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/smp.h> #include <linux/jiffies.h> #include <linux/percpu.h> #include <linux/clockchips.h> #include <linux/irq.h> #include <linux/io.h> Loading @@ -24,18 +22,6 @@ #include <mach/hardware.h> #include <asm/irq.h> static DEFINE_PER_CPU(struct clock_event_device, local_clockevent); /* * Used on SMP for either the local timer or IPI_TIMER */ void local_timer_interrupt(void) { struct clock_event_device *clk = &__get_cpu_var(local_clockevent); clk->event_handler(clk); } #ifdef CONFIG_LOCAL_TIMERS /* set up by the platform code */ Loading @@ -44,7 +30,7 @@ void __iomem *twd_base; static unsigned long mpcore_timer_rate; static void local_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *clk) struct clock_event_device *evt) { unsigned long ctrl; Loading Loading @@ -140,32 +126,29 @@ static void __cpuinit twd_calibrate_rate(void) /* * Setup the local clock events for a CPU. */ void __cpuinit local_timer_setup(void) void __cpuinit local_timer_setup(struct clock_event_device *evt) { unsigned int cpu = smp_processor_id(); struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); unsigned long flags; twd_calibrate_rate(); clk->name = "local_timer"; clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; clk->rating = 350; clk->set_mode = local_timer_set_mode; clk->set_next_event = local_timer_set_next_event; clk->irq = IRQ_LOCALTIMER; clk->cpumask = cpumask_of(cpu); clk->shift = 20; clk->mult = div_sc(mpcore_timer_rate, NSEC_PER_SEC, clk->shift); clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk); clk->min_delta_ns = clockevent_delta2ns(0xf, clk); evt->name = "local_timer"; evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; evt->rating = 350; evt->set_mode = local_timer_set_mode; evt->set_next_event = local_timer_set_next_event; evt->irq = IRQ_LOCALTIMER; evt->shift = 20; evt->mult = div_sc(mpcore_timer_rate, NSEC_PER_SEC, evt->shift); evt->max_delta_ns = clockevent_delta2ns(0xffffffff, evt); evt->min_delta_ns = clockevent_delta2ns(0xf, evt); /* Make sure our local interrupt controller has this enabled */ local_irq_save(flags); get_irq_chip(IRQ_LOCALTIMER)->unmask(IRQ_LOCALTIMER); local_irq_restore(flags); clockevents_register_device(clk); clockevents_register_device(evt); } /* Loading @@ -176,29 +159,4 @@ void __cpuexit local_timer_stop(void) __raw_writel(0, twd_base + TWD_TIMER_CONTROL); } #else /* CONFIG_LOCAL_TIMERS */ static void dummy_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *clk) { } void __cpuinit local_timer_setup(void) { unsigned int cpu = smp_processor_id(); struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); clk->name = "dummy_timer"; clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_DUMMY; clk->rating = 400; clk->mult = 1; clk->set_mode = dummy_timer_set_mode; clk->broadcast = smp_timer_broadcast; clk->cpumask = cpumask_of(cpu); clockevents_register_device(clk); } #endif /* !CONFIG_LOCAL_TIMERS */ #endif /* CONFIG_LOCAL_TIMERS */ Loading
arch/arm/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -859,6 +859,7 @@ source "kernel/time/Kconfig" config SMP bool "Symmetric Multi-Processing (EXPERIMENTAL)" depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP) depends on GENERIC_CLOCKEVENTS select USE_GENERIC_SMP_HELPERS help This enables support for systems with more than one CPU. If you have Loading
arch/arm/include/asm/localtimer.h 0 → 100644 +51 −0 Original line number Diff line number Diff line /* * arch/arm/include/asm/localtimer.h * * Copyright (C) 2004-2005 ARM Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #ifndef __ASM_ARM_LOCALTIMER_H #define __ASM_ARM_LOCALTIMER_H struct clock_event_device; /* * Setup a per-cpu timer, whether it be a local timer or dummy broadcast */ void percpu_timer_setup(void); /* * Called from assembly, this is the local timer IRQ handler */ asmlinkage void do_local_timer(struct pt_regs *); #ifdef CONFIG_LOCAL_TIMERS /* * Platform provides this to acknowledge a local timer IRQ. * Returns true if the local timer IRQ is to be processed. */ int local_timer_ack(void); /* * Stop a local timer interrupt. */ void local_timer_stop(void); /* * Setup a local timer interrupt for a CPU. */ void local_timer_setup(struct clock_event_device *); #else static inline void local_timer_stop(void) { } #endif #endif
arch/arm/include/asm/smp.h +0 −40 Original line number Diff line number Diff line Loading @@ -55,11 +55,6 @@ extern void smp_store_cpu_info(unsigned int cpuid); */ extern void smp_cross_call(const struct cpumask *mask); /* * Broadcast a clock event to other CPUs. */ extern void smp_timer_broadcast(const struct cpumask *mask); /* * Boot a secondary CPU, and assign it the specified idle task. * This also gives us the initial stack to use for this CPU. Loading Loading @@ -100,44 +95,9 @@ extern void arch_send_call_function_single_ipi(int cpu); extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); #define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask /* * Local timer interrupt handling function (can be IPI'ed). */ extern void local_timer_interrupt(void); #ifdef CONFIG_LOCAL_TIMERS /* * Stop a local timer interrupt. */ extern void local_timer_stop(void); /* * Platform provides this to acknowledge a local timer IRQ */ extern int local_timer_ack(void); #else static inline void local_timer_stop(void) { } #endif /* * Setup a local timer interrupt for a CPU. */ extern void local_timer_setup(void); /* * show local interrupt info */ extern void show_local_irqs(struct seq_file *); /* * Called from assembly, this is the local timer IRQ handler */ asmlinkage void do_local_timer(struct pt_regs *); #endif /* ifndef __ASM_ARM_SMP_H */
arch/arm/kernel/smp.c +48 −8 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ #include <linux/smp.h> #include <linux/seq_file.h> #include <linux/irq.h> #include <linux/percpu.h> #include <linux/clockchips.h> #include <asm/atomic.h> #include <asm/cacheflush.h> Loading @@ -32,6 +34,7 @@ #include <asm/processor.h> #include <asm/tlbflush.h> #include <asm/ptrace.h> #include <asm/localtimer.h> /* * as from 2.5, kernels no longer have an init_tasks structure Loading Loading @@ -274,9 +277,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void) local_fiq_enable(); /* * Setup local timer for this CPU. * Setup the percpu timer for this CPU. */ local_timer_setup(); percpu_timer_setup(); calibrate_delay(); Loading Loading @@ -383,10 +386,16 @@ void show_local_irqs(struct seq_file *p) seq_putc(p, '\n'); } /* * Timer (local or broadcast) support */ static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent); static void ipi_timer(void) { struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent); irq_enter(); local_timer_interrupt(); evt->event_handler(evt); irq_exit(); } Loading @@ -405,6 +414,42 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs) } #endif #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST static void smp_timer_broadcast(const struct cpumask *mask) { send_ipi_message(mask, IPI_TIMER); } static void broadcast_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { } static void local_timer_setup(struct clock_event_device *evt) { evt->name = "dummy_timer"; evt->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_DUMMY; evt->rating = 400; evt->mult = 1; evt->set_mode = broadcast_timer_set_mode; evt->broadcast = smp_timer_broadcast; clockevents_register_device(evt); } #endif void __cpuinit percpu_timer_setup(void) { unsigned int cpu = smp_processor_id(); struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); evt->cpumask = cpumask_of(cpu); local_timer_setup(evt); } static DEFINE_SPINLOCK(stop_lock); /* Loading Loading @@ -501,11 +546,6 @@ void smp_send_reschedule(int cpu) send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); } void smp_timer_broadcast(const struct cpumask *mask) { send_ipi_message(mask, IPI_TIMER); } void smp_send_stop(void) { cpumask_t mask = cpu_online_map; Loading
arch/arm/mach-realview/localtimer.c +14 −56 Original line number Diff line number Diff line Loading @@ -11,10 +11,8 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/smp.h> #include <linux/jiffies.h> #include <linux/percpu.h> #include <linux/clockchips.h> #include <linux/irq.h> #include <linux/io.h> Loading @@ -24,18 +22,6 @@ #include <mach/hardware.h> #include <asm/irq.h> static DEFINE_PER_CPU(struct clock_event_device, local_clockevent); /* * Used on SMP for either the local timer or IPI_TIMER */ void local_timer_interrupt(void) { struct clock_event_device *clk = &__get_cpu_var(local_clockevent); clk->event_handler(clk); } #ifdef CONFIG_LOCAL_TIMERS /* set up by the platform code */ Loading @@ -44,7 +30,7 @@ void __iomem *twd_base; static unsigned long mpcore_timer_rate; static void local_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *clk) struct clock_event_device *evt) { unsigned long ctrl; Loading Loading @@ -140,32 +126,29 @@ static void __cpuinit twd_calibrate_rate(void) /* * Setup the local clock events for a CPU. */ void __cpuinit local_timer_setup(void) void __cpuinit local_timer_setup(struct clock_event_device *evt) { unsigned int cpu = smp_processor_id(); struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); unsigned long flags; twd_calibrate_rate(); clk->name = "local_timer"; clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; clk->rating = 350; clk->set_mode = local_timer_set_mode; clk->set_next_event = local_timer_set_next_event; clk->irq = IRQ_LOCALTIMER; clk->cpumask = cpumask_of(cpu); clk->shift = 20; clk->mult = div_sc(mpcore_timer_rate, NSEC_PER_SEC, clk->shift); clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk); clk->min_delta_ns = clockevent_delta2ns(0xf, clk); evt->name = "local_timer"; evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; evt->rating = 350; evt->set_mode = local_timer_set_mode; evt->set_next_event = local_timer_set_next_event; evt->irq = IRQ_LOCALTIMER; evt->shift = 20; evt->mult = div_sc(mpcore_timer_rate, NSEC_PER_SEC, evt->shift); evt->max_delta_ns = clockevent_delta2ns(0xffffffff, evt); evt->min_delta_ns = clockevent_delta2ns(0xf, evt); /* Make sure our local interrupt controller has this enabled */ local_irq_save(flags); get_irq_chip(IRQ_LOCALTIMER)->unmask(IRQ_LOCALTIMER); local_irq_restore(flags); clockevents_register_device(clk); clockevents_register_device(evt); } /* Loading @@ -176,29 +159,4 @@ void __cpuexit local_timer_stop(void) __raw_writel(0, twd_base + TWD_TIMER_CONTROL); } #else /* CONFIG_LOCAL_TIMERS */ static void dummy_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *clk) { } void __cpuinit local_timer_setup(void) { unsigned int cpu = smp_processor_id(); struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); clk->name = "dummy_timer"; clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_DUMMY; clk->rating = 400; clk->mult = 1; clk->set_mode = dummy_timer_set_mode; clk->broadcast = smp_timer_broadcast; clk->cpumask = cpumask_of(cpu); clockevents_register_device(clk); } #endif /* !CONFIG_LOCAL_TIMERS */ #endif /* CONFIG_LOCAL_TIMERS */