diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2009-05-17 13:58:34 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-05-17 13:58:34 -0400 |
commit | bc28248ee25e5c239cbe6afca35a100b08401de5 (patch) | |
tree | 89fb6944170bc85b5c9261cd7c7dba6954994cc3 | |
parent | ee348d5a1d810bc9958cabb7c27302aab235d36e (diff) |
[ARM] smp: move core localtimer support out of platform specific files
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/localtimer.h | 51 | ||||
-rw-r--r-- | arch/arm/include/asm/smp.h | 40 | ||||
-rw-r--r-- | arch/arm/kernel/smp.c | 56 | ||||
-rw-r--r-- | arch/arm/mach-realview/localtimer.c | 70 | ||||
-rw-r--r-- | arch/arm/mach-realview/platsmp.c | 14 |
6 files changed, 121 insertions, 111 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e60ec54df334..ef4f860d5041 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -859,6 +859,7 @@ source "kernel/time/Kconfig" | |||
859 | config SMP | 859 | config SMP |
860 | bool "Symmetric Multi-Processing (EXPERIMENTAL)" | 860 | bool "Symmetric Multi-Processing (EXPERIMENTAL)" |
861 | depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP) | 861 | depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP) |
862 | depends on GENERIC_CLOCKEVENTS | ||
862 | select USE_GENERIC_SMP_HELPERS | 863 | select USE_GENERIC_SMP_HELPERS |
863 | help | 864 | help |
864 | This enables support for systems with more than one CPU. If you have | 865 | This enables support for systems with more than one CPU. If you have |
diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h new file mode 100644 index 000000000000..3f8c9ebb646c --- /dev/null +++ b/arch/arm/include/asm/localtimer.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * arch/arm/include/asm/localtimer.h | ||
3 | * | ||
4 | * Copyright (C) 2004-2005 ARM Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | #ifndef __ASM_ARM_LOCALTIMER_H | ||
11 | #define __ASM_ARM_LOCALTIMER_H | ||
12 | |||
13 | struct clock_event_device; | ||
14 | |||
15 | /* | ||
16 | * Setup a per-cpu timer, whether it be a local timer or dummy broadcast | ||
17 | */ | ||
18 | void percpu_timer_setup(void); | ||
19 | |||
20 | /* | ||
21 | * Called from assembly, this is the local timer IRQ handler | ||
22 | */ | ||
23 | asmlinkage void do_local_timer(struct pt_regs *); | ||
24 | |||
25 | |||
26 | #ifdef CONFIG_LOCAL_TIMERS | ||
27 | /* | ||
28 | * Platform provides this to acknowledge a local timer IRQ. | ||
29 | * Returns true if the local timer IRQ is to be processed. | ||
30 | */ | ||
31 | int local_timer_ack(void); | ||
32 | |||
33 | /* | ||
34 | * Stop a local timer interrupt. | ||
35 | */ | ||
36 | void local_timer_stop(void); | ||
37 | |||
38 | /* | ||
39 | * Setup a local timer interrupt for a CPU. | ||
40 | */ | ||
41 | void local_timer_setup(struct clock_event_device *); | ||
42 | |||
43 | #else | ||
44 | |||
45 | static inline void local_timer_stop(void) | ||
46 | { | ||
47 | } | ||
48 | |||
49 | #endif | ||
50 | |||
51 | #endif | ||
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index 5995935338e1..608f2d533ff2 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h | |||
@@ -56,11 +56,6 @@ extern void smp_store_cpu_info(unsigned int cpuid); | |||
56 | extern void smp_cross_call(const struct cpumask *mask); | 56 | extern void smp_cross_call(const struct cpumask *mask); |
57 | 57 | ||
58 | /* | 58 | /* |
59 | * Broadcast a clock event to other CPUs. | ||
60 | */ | ||
61 | extern void smp_timer_broadcast(const struct cpumask *mask); | ||
62 | |||
63 | /* | ||
64 | * Boot a secondary CPU, and assign it the specified idle task. | 59 | * Boot a secondary CPU, and assign it the specified idle task. |
65 | * This also gives us the initial stack to use for this CPU. | 60 | * This also gives us the initial stack to use for this CPU. |
66 | */ | 61 | */ |
@@ -101,43 +96,8 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); | |||
101 | #define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask | 96 | #define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask |
102 | 97 | ||
103 | /* | 98 | /* |
104 | * Local timer interrupt handling function (can be IPI'ed). | ||
105 | */ | ||
106 | extern void local_timer_interrupt(void); | ||
107 | |||
108 | #ifdef CONFIG_LOCAL_TIMERS | ||
109 | |||
110 | /* | ||
111 | * Stop a local timer interrupt. | ||
112 | */ | ||
113 | extern void local_timer_stop(void); | ||
114 | |||
115 | /* | ||
116 | * Platform provides this to acknowledge a local timer IRQ | ||
117 | */ | ||
118 | extern int local_timer_ack(void); | ||
119 | |||
120 | #else | ||
121 | |||
122 | static inline void local_timer_stop(void) | ||
123 | { | ||
124 | } | ||
125 | |||
126 | #endif | ||
127 | |||
128 | /* | ||
129 | * Setup a local timer interrupt for a CPU. | ||
130 | */ | ||
131 | extern void local_timer_setup(void); | ||
132 | |||
133 | /* | ||
134 | * show local interrupt info | 99 | * show local interrupt info |
135 | */ | 100 | */ |
136 | extern void show_local_irqs(struct seq_file *); | 101 | extern void show_local_irqs(struct seq_file *); |
137 | 102 | ||
138 | /* | ||
139 | * Called from assembly, this is the local timer IRQ handler | ||
140 | */ | ||
141 | asmlinkage void do_local_timer(struct pt_regs *); | ||
142 | |||
143 | #endif /* ifndef __ASM_ARM_SMP_H */ | 103 | #endif /* ifndef __ASM_ARM_SMP_H */ |
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 6014dfd22af4..91130e218aef 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <linux/smp.h> | 22 | #include <linux/smp.h> |
23 | #include <linux/seq_file.h> | 23 | #include <linux/seq_file.h> |
24 | #include <linux/irq.h> | 24 | #include <linux/irq.h> |
25 | #include <linux/percpu.h> | ||
26 | #include <linux/clockchips.h> | ||
25 | 27 | ||
26 | #include <asm/atomic.h> | 28 | #include <asm/atomic.h> |
27 | #include <asm/cacheflush.h> | 29 | #include <asm/cacheflush.h> |
@@ -32,6 +34,7 @@ | |||
32 | #include <asm/processor.h> | 34 | #include <asm/processor.h> |
33 | #include <asm/tlbflush.h> | 35 | #include <asm/tlbflush.h> |
34 | #include <asm/ptrace.h> | 36 | #include <asm/ptrace.h> |
37 | #include <asm/localtimer.h> | ||
35 | 38 | ||
36 | /* | 39 | /* |
37 | * as from 2.5, kernels no longer have an init_tasks structure | 40 | * as from 2.5, kernels no longer have an init_tasks structure |
@@ -274,9 +277,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void) | |||
274 | local_fiq_enable(); | 277 | local_fiq_enable(); |
275 | 278 | ||
276 | /* | 279 | /* |
277 | * Setup local timer for this CPU. | 280 | * Setup the percpu timer for this CPU. |
278 | */ | 281 | */ |
279 | local_timer_setup(); | 282 | percpu_timer_setup(); |
280 | 283 | ||
281 | calibrate_delay(); | 284 | calibrate_delay(); |
282 | 285 | ||
@@ -383,10 +386,16 @@ void show_local_irqs(struct seq_file *p) | |||
383 | seq_putc(p, '\n'); | 386 | seq_putc(p, '\n'); |
384 | } | 387 | } |
385 | 388 | ||
389 | /* | ||
390 | * Timer (local or broadcast) support | ||
391 | */ | ||
392 | static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent); | ||
393 | |||
386 | static void ipi_timer(void) | 394 | static void ipi_timer(void) |
387 | { | 395 | { |
396 | struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent); | ||
388 | irq_enter(); | 397 | irq_enter(); |
389 | local_timer_interrupt(); | 398 | evt->event_handler(evt); |
390 | irq_exit(); | 399 | irq_exit(); |
391 | } | 400 | } |
392 | 401 | ||
@@ -405,6 +414,42 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs) | |||
405 | } | 414 | } |
406 | #endif | 415 | #endif |
407 | 416 | ||
417 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST | ||
418 | static void smp_timer_broadcast(const struct cpumask *mask) | ||
419 | { | ||
420 | send_ipi_message(mask, IPI_TIMER); | ||
421 | } | ||
422 | |||
423 | static void broadcast_timer_set_mode(enum clock_event_mode mode, | ||
424 | struct clock_event_device *evt) | ||
425 | { | ||
426 | } | ||
427 | |||
428 | static void local_timer_setup(struct clock_event_device *evt) | ||
429 | { | ||
430 | evt->name = "dummy_timer"; | ||
431 | evt->features = CLOCK_EVT_FEAT_ONESHOT | | ||
432 | CLOCK_EVT_FEAT_PERIODIC | | ||
433 | CLOCK_EVT_FEAT_DUMMY; | ||
434 | evt->rating = 400; | ||
435 | evt->mult = 1; | ||
436 | evt->set_mode = broadcast_timer_set_mode; | ||
437 | evt->broadcast = smp_timer_broadcast; | ||
438 | |||
439 | clockevents_register_device(evt); | ||
440 | } | ||
441 | #endif | ||
442 | |||
443 | void __cpuinit percpu_timer_setup(void) | ||
444 | { | ||
445 | unsigned int cpu = smp_processor_id(); | ||
446 | struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); | ||
447 | |||
448 | evt->cpumask = cpumask_of(cpu); | ||
449 | |||
450 | local_timer_setup(evt); | ||
451 | } | ||
452 | |||
408 | static DEFINE_SPINLOCK(stop_lock); | 453 | static DEFINE_SPINLOCK(stop_lock); |
409 | 454 | ||
410 | /* | 455 | /* |
@@ -501,11 +546,6 @@ void smp_send_reschedule(int cpu) | |||
501 | send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); | 546 | send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); |
502 | } | 547 | } |
503 | 548 | ||
504 | void smp_timer_broadcast(const struct cpumask *mask) | ||
505 | { | ||
506 | send_ipi_message(mask, IPI_TIMER); | ||
507 | } | ||
508 | |||
509 | void smp_send_stop(void) | 549 | void smp_send_stop(void) |
510 | { | 550 | { |
511 | cpumask_t mask = cpu_online_map; | 551 | cpumask_t mask = cpu_online_map; |
diff --git a/arch/arm/mach-realview/localtimer.c b/arch/arm/mach-realview/localtimer.c index 1c01d13460f0..cd98e7acd94d 100644 --- a/arch/arm/mach-realview/localtimer.c +++ b/arch/arm/mach-realview/localtimer.c | |||
@@ -11,10 +11,8 @@ | |||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
14 | #include <linux/device.h> | ||
15 | #include <linux/smp.h> | 14 | #include <linux/smp.h> |
16 | #include <linux/jiffies.h> | 15 | #include <linux/jiffies.h> |
17 | #include <linux/percpu.h> | ||
18 | #include <linux/clockchips.h> | 16 | #include <linux/clockchips.h> |
19 | #include <linux/irq.h> | 17 | #include <linux/irq.h> |
20 | #include <linux/io.h> | 18 | #include <linux/io.h> |
@@ -24,18 +22,6 @@ | |||
24 | #include <mach/hardware.h> | 22 | #include <mach/hardware.h> |
25 | #include <asm/irq.h> | 23 | #include <asm/irq.h> |
26 | 24 | ||
27 | static DEFINE_PER_CPU(struct clock_event_device, local_clockevent); | ||
28 | |||
29 | /* | ||
30 | * Used on SMP for either the local timer or IPI_TIMER | ||
31 | */ | ||
32 | void local_timer_interrupt(void) | ||
33 | { | ||
34 | struct clock_event_device *clk = &__get_cpu_var(local_clockevent); | ||
35 | |||
36 | clk->event_handler(clk); | ||
37 | } | ||
38 | |||
39 | #ifdef CONFIG_LOCAL_TIMERS | 25 | #ifdef CONFIG_LOCAL_TIMERS |
40 | 26 | ||
41 | /* set up by the platform code */ | 27 | /* set up by the platform code */ |
@@ -44,7 +30,7 @@ void __iomem *twd_base; | |||
44 | static unsigned long mpcore_timer_rate; | 30 | static unsigned long mpcore_timer_rate; |
45 | 31 | ||
46 | static void local_timer_set_mode(enum clock_event_mode mode, | 32 | static void local_timer_set_mode(enum clock_event_mode mode, |
47 | struct clock_event_device *clk) | 33 | struct clock_event_device *evt) |
48 | { | 34 | { |
49 | unsigned long ctrl; | 35 | unsigned long ctrl; |
50 | 36 | ||
@@ -140,32 +126,29 @@ static void __cpuinit twd_calibrate_rate(void) | |||
140 | /* | 126 | /* |
141 | * Setup the local clock events for a CPU. | 127 | * Setup the local clock events for a CPU. |
142 | */ | 128 | */ |
143 | void __cpuinit local_timer_setup(void) | 129 | void __cpuinit local_timer_setup(struct clock_event_device *evt) |
144 | { | 130 | { |
145 | unsigned int cpu = smp_processor_id(); | ||
146 | struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); | ||
147 | unsigned long flags; | 131 | unsigned long flags; |
148 | 132 | ||
149 | twd_calibrate_rate(); | 133 | twd_calibrate_rate(); |
150 | 134 | ||
151 | clk->name = "local_timer"; | 135 | evt->name = "local_timer"; |
152 | clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; | 136 | evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; |
153 | clk->rating = 350; | 137 | evt->rating = 350; |
154 | clk->set_mode = local_timer_set_mode; | 138 | evt->set_mode = local_timer_set_mode; |
155 | clk->set_next_event = local_timer_set_next_event; | 139 | evt->set_next_event = local_timer_set_next_event; |
156 | clk->irq = IRQ_LOCALTIMER; | 140 | evt->irq = IRQ_LOCALTIMER; |
157 | clk->cpumask = cpumask_of(cpu); | 141 | evt->shift = 20; |
158 | clk->shift = 20; | 142 | evt->mult = div_sc(mpcore_timer_rate, NSEC_PER_SEC, evt->shift); |
159 | clk->mult = div_sc(mpcore_timer_rate, NSEC_PER_SEC, clk->shift); | 143 | evt->max_delta_ns = clockevent_delta2ns(0xffffffff, evt); |
160 | clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk); | 144 | evt->min_delta_ns = clockevent_delta2ns(0xf, evt); |
161 | clk->min_delta_ns = clockevent_delta2ns(0xf, clk); | ||
162 | 145 | ||
163 | /* Make sure our local interrupt controller has this enabled */ | 146 | /* Make sure our local interrupt controller has this enabled */ |
164 | local_irq_save(flags); | 147 | local_irq_save(flags); |
165 | get_irq_chip(IRQ_LOCALTIMER)->unmask(IRQ_LOCALTIMER); | 148 | get_irq_chip(IRQ_LOCALTIMER)->unmask(IRQ_LOCALTIMER); |
166 | local_irq_restore(flags); | 149 | local_irq_restore(flags); |
167 | 150 | ||
168 | clockevents_register_device(clk); | 151 | clockevents_register_device(evt); |
169 | } | 152 | } |
170 | 153 | ||
171 | /* | 154 | /* |
@@ -176,29 +159,4 @@ void __cpuexit local_timer_stop(void) | |||
176 | __raw_writel(0, twd_base + TWD_TIMER_CONTROL); | 159 | __raw_writel(0, twd_base + TWD_TIMER_CONTROL); |
177 | } | 160 | } |
178 | 161 | ||
179 | #else /* CONFIG_LOCAL_TIMERS */ | 162 | #endif /* CONFIG_LOCAL_TIMERS */ |
180 | |||
181 | static void dummy_timer_set_mode(enum clock_event_mode mode, | ||
182 | struct clock_event_device *clk) | ||
183 | { | ||
184 | } | ||
185 | |||
186 | void __cpuinit local_timer_setup(void) | ||
187 | { | ||
188 | unsigned int cpu = smp_processor_id(); | ||
189 | struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); | ||
190 | |||
191 | clk->name = "dummy_timer"; | ||
192 | clk->features = CLOCK_EVT_FEAT_ONESHOT | | ||
193 | CLOCK_EVT_FEAT_PERIODIC | | ||
194 | CLOCK_EVT_FEAT_DUMMY; | ||
195 | clk->rating = 400; | ||
196 | clk->mult = 1; | ||
197 | clk->set_mode = dummy_timer_set_mode; | ||
198 | clk->broadcast = smp_timer_broadcast; | ||
199 | clk->cpumask = cpumask_of(cpu); | ||
200 | |||
201 | clockevents_register_device(clk); | ||
202 | } | ||
203 | |||
204 | #endif /* !CONFIG_LOCAL_TIMERS */ | ||
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index 30a9c68591f6..b34d3a57ce93 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <asm/cacheflush.h> | 19 | #include <asm/cacheflush.h> |
20 | #include <mach/hardware.h> | 20 | #include <mach/hardware.h> |
21 | #include <asm/mach-types.h> | 21 | #include <asm/mach-types.h> |
22 | #include <asm/localtimer.h> | ||
22 | 23 | ||
23 | #include <mach/board-eb.h> | 24 | #include <mach/board-eb.h> |
24 | #include <mach/board-pb11mp.h> | 25 | #include <mach/board-pb11mp.h> |
@@ -217,13 +218,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
217 | if (max_cpus > ncores) | 218 | if (max_cpus > ncores) |
218 | max_cpus = ncores; | 219 | max_cpus = ncores; |
219 | 220 | ||
220 | #if defined(CONFIG_LOCAL_TIMERS) || defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) | ||
221 | /* | ||
222 | * Enable the local timer or broadcast device for the boot CPU. | ||
223 | */ | ||
224 | local_timer_setup(); | ||
225 | #endif | ||
226 | |||
227 | /* | 221 | /* |
228 | * Initialise the present map, which describes the set of CPUs | 222 | * Initialise the present map, which describes the set of CPUs |
229 | * actually populated at the present time. | 223 | * actually populated at the present time. |
@@ -239,6 +233,12 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
239 | * WFI | 233 | * WFI |
240 | */ | 234 | */ |
241 | if (max_cpus > 1) { | 235 | if (max_cpus > 1) { |
236 | /* | ||
237 | * Enable the local timer or broadcast device for the | ||
238 | * boot CPU, but only if we have more than one CPU. | ||
239 | */ | ||
240 | percpu_timer_setup(); | ||
241 | |||
242 | scu_enable(); | 242 | scu_enable(); |
243 | poke_milo(); | 243 | poke_milo(); |
244 | } | 244 | } |