diff options
-rw-r--r-- | arch/arm/common/gic.c | 52 | ||||
-rw-r--r-- | arch/arm/include/asm/hardware/gic.h | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/localtimer.h | 16 | ||||
-rw-r--r-- | arch/arm/include/asm/smp_twd.h | 2 | ||||
-rw-r--r-- | arch/arm/kernel/smp.c | 16 | ||||
-rw-r--r-- | arch/arm/kernel/smp_twd.c | 47 | ||||
-rw-r--r-- | arch/arm/mach-exynos4/mct.c | 7 | ||||
-rw-r--r-- | arch/arm/mach-msm/timer.c | 69 |
8 files changed, 99 insertions, 111 deletions
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index bbea0168779b..a2b320503931 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include <asm/irq.h> | 35 | #include <asm/irq.h> |
36 | #include <asm/mach/irq.h> | 36 | #include <asm/mach/irq.h> |
37 | #include <asm/hardware/gic.h> | 37 | #include <asm/hardware/gic.h> |
38 | #include <asm/localtimer.h> | ||
39 | 38 | ||
40 | static DEFINE_SPINLOCK(irq_controller_lock); | 39 | static DEFINE_SPINLOCK(irq_controller_lock); |
41 | 40 | ||
@@ -259,32 +258,6 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) | |||
259 | irq_set_chained_handler(irq, gic_handle_cascade_irq); | 258 | irq_set_chained_handler(irq, gic_handle_cascade_irq); |
260 | } | 259 | } |
261 | 260 | ||
262 | #ifdef CONFIG_LOCAL_TIMERS | ||
263 | #define gic_ppi_handler percpu_timer_handler | ||
264 | #else | ||
265 | static irqreturn_t gic_ppi_handler(int irq, void *dev_id) | ||
266 | { | ||
267 | return IRQ_NONE; | ||
268 | } | ||
269 | #endif | ||
270 | |||
271 | #define PPI_IRQACT(nr) \ | ||
272 | { \ | ||
273 | .handler = gic_ppi_handler, \ | ||
274 | .flags = IRQF_PERCPU | IRQF_TIMER, \ | ||
275 | .irq = nr, \ | ||
276 | .name = "PPI-" # nr, \ | ||
277 | } | ||
278 | |||
279 | static struct irqaction ppi_irqaction_template[16] __initdata = { | ||
280 | PPI_IRQACT(0), PPI_IRQACT(1), PPI_IRQACT(2), PPI_IRQACT(3), | ||
281 | PPI_IRQACT(4), PPI_IRQACT(5), PPI_IRQACT(6), PPI_IRQACT(7), | ||
282 | PPI_IRQACT(8), PPI_IRQACT(9), PPI_IRQACT(10), PPI_IRQACT(11), | ||
283 | PPI_IRQACT(12), PPI_IRQACT(13), PPI_IRQACT(14), PPI_IRQACT(15), | ||
284 | }; | ||
285 | |||
286 | static struct irqaction *ppi_irqaction; | ||
287 | |||
288 | static void __init gic_dist_init(struct gic_chip_data *gic, | 261 | static void __init gic_dist_init(struct gic_chip_data *gic, |
289 | unsigned int irq_start) | 262 | unsigned int irq_start) |
290 | { | 263 | { |
@@ -325,16 +298,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic, | |||
325 | BUG(); | 298 | BUG(); |
326 | 299 | ||
327 | ppi_base = gic->irq_offset + 32 - nrppis; | 300 | ppi_base = gic->irq_offset + 32 - nrppis; |
328 | |||
329 | ppi_irqaction = kmemdup(&ppi_irqaction_template[16 - nrppis], | ||
330 | sizeof(*ppi_irqaction) * nrppis, | ||
331 | GFP_KERNEL); | ||
332 | |||
333 | if (nrppis && !ppi_irqaction) { | ||
334 | pr_err("GIC: Can't allocate PPI memory"); | ||
335 | nrppis = 0; | ||
336 | ppi_base = 0; | ||
337 | } | ||
338 | } | 301 | } |
339 | 302 | ||
340 | pr_info("Configuring GIC with %d sources (%d PPIs)\n", | 303 | pr_info("Configuring GIC with %d sources (%d PPIs)\n", |
@@ -377,17 +340,12 @@ static void __init gic_dist_init(struct gic_chip_data *gic, | |||
377 | */ | 340 | */ |
378 | for (i = 0; i < nrppis; i++) { | 341 | for (i = 0; i < nrppis; i++) { |
379 | int ppi = i + ppi_base; | 342 | int ppi = i + ppi_base; |
380 | int err; | ||
381 | 343 | ||
382 | irq_set_percpu_devid(ppi); | 344 | irq_set_percpu_devid(ppi); |
383 | irq_set_chip_and_handler(ppi, &gic_chip, | 345 | irq_set_chip_and_handler(ppi, &gic_chip, |
384 | handle_percpu_devid_irq); | 346 | handle_percpu_devid_irq); |
385 | irq_set_chip_data(ppi, gic); | 347 | irq_set_chip_data(ppi, gic); |
386 | set_irq_flags(ppi, IRQF_VALID | IRQF_NOAUTOEN); | 348 | set_irq_flags(ppi, IRQF_VALID | IRQF_NOAUTOEN); |
387 | |||
388 | err = setup_percpu_irq(ppi, &ppi_irqaction[i]); | ||
389 | if (err) | ||
390 | pr_err("GIC: can't setup PPI%d (%d)\n", ppi, err); | ||
391 | } | 349 | } |
392 | 350 | ||
393 | for (i = irq_start + nrppis; i < irq_limit; i++) { | 351 | for (i = irq_start + nrppis; i < irq_limit; i++) { |
@@ -448,16 +406,6 @@ void __cpuinit gic_secondary_init(unsigned int gic_nr) | |||
448 | gic_cpu_init(&gic_data[gic_nr]); | 406 | gic_cpu_init(&gic_data[gic_nr]); |
449 | } | 407 | } |
450 | 408 | ||
451 | void __cpuinit gic_enable_ppi(unsigned int irq) | ||
452 | { | ||
453 | unsigned long flags; | ||
454 | |||
455 | local_irq_save(flags); | ||
456 | irq_set_status_flags(irq, IRQ_NOPROBE); | ||
457 | gic_unmask_irq(irq_get_irq_data(irq)); | ||
458 | local_irq_restore(flags); | ||
459 | } | ||
460 | |||
461 | #ifdef CONFIG_SMP | 409 | #ifdef CONFIG_SMP |
462 | void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) | 410 | void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) |
463 | { | 411 | { |
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h index 435d3f86c708..2dadd50a77d2 100644 --- a/arch/arm/include/asm/hardware/gic.h +++ b/arch/arm/include/asm/hardware/gic.h | |||
@@ -40,7 +40,6 @@ void gic_init(unsigned int, unsigned int, void __iomem *, void __iomem *); | |||
40 | void gic_secondary_init(unsigned int); | 40 | void gic_secondary_init(unsigned int); |
41 | void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); | 41 | void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); |
42 | void gic_raise_softirq(const struct cpumask *mask, unsigned int irq); | 42 | void gic_raise_softirq(const struct cpumask *mask, unsigned int irq); |
43 | void gic_enable_ppi(unsigned int); | ||
44 | 43 | ||
45 | struct gic_chip_data { | 44 | struct gic_chip_data { |
46 | unsigned int irq_offset; | 45 | unsigned int irq_offset; |
diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h index 5c8acb4c4040..f5e1cec7e35c 100644 --- a/arch/arm/include/asm/localtimer.h +++ b/arch/arm/include/asm/localtimer.h | |||
@@ -19,26 +19,20 @@ struct clock_event_device; | |||
19 | */ | 19 | */ |
20 | void percpu_timer_setup(void); | 20 | void percpu_timer_setup(void); |
21 | 21 | ||
22 | /* | ||
23 | * Per-cpu timer IRQ handler | ||
24 | */ | ||
25 | irqreturn_t percpu_timer_handler(int irq, void *dev_id); | ||
26 | |||
27 | #ifdef CONFIG_LOCAL_TIMERS | 22 | #ifdef CONFIG_LOCAL_TIMERS |
28 | 23 | ||
29 | #ifdef CONFIG_HAVE_ARM_TWD | 24 | #ifdef CONFIG_HAVE_ARM_TWD |
30 | 25 | ||
31 | #include "smp_twd.h" | 26 | #include "smp_twd.h" |
32 | 27 | ||
33 | #define local_timer_ack() twd_timer_ack() | 28 | #define local_timer_stop(c) twd_timer_stop((c)) |
34 | 29 | ||
35 | #else | 30 | #else |
36 | 31 | ||
37 | /* | 32 | /* |
38 | * Platform provides this to acknowledge a local timer IRQ. | 33 | * Stop the local timer |
39 | * Returns true if the local timer IRQ is to be processed. | ||
40 | */ | 34 | */ |
41 | int local_timer_ack(void); | 35 | void local_timer_stop(struct clock_event_device *); |
42 | 36 | ||
43 | #endif | 37 | #endif |
44 | 38 | ||
@@ -53,6 +47,10 @@ static inline int local_timer_setup(struct clock_event_device *evt) | |||
53 | { | 47 | { |
54 | return -ENXIO; | 48 | return -ENXIO; |
55 | } | 49 | } |
50 | |||
51 | static inline void local_timer_stop(struct clock_event_device *evt) | ||
52 | { | ||
53 | } | ||
56 | #endif | 54 | #endif |
57 | 55 | ||
58 | #endif | 56 | #endif |
diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h index fed9981fba08..ef9ffba97ad8 100644 --- a/arch/arm/include/asm/smp_twd.h +++ b/arch/arm/include/asm/smp_twd.h | |||
@@ -22,7 +22,7 @@ struct clock_event_device; | |||
22 | 22 | ||
23 | extern void __iomem *twd_base; | 23 | extern void __iomem *twd_base; |
24 | 24 | ||
25 | int twd_timer_ack(void); | ||
26 | void twd_timer_setup(struct clock_event_device *); | 25 | void twd_timer_setup(struct clock_event_device *); |
26 | void twd_timer_stop(struct clock_event_device *); | ||
27 | 27 | ||
28 | #endif | 28 | #endif |
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 917ed2fa4e4c..a96c08cd6125 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c | |||
@@ -473,20 +473,6 @@ static void ipi_timer(void) | |||
473 | irq_exit(); | 473 | irq_exit(); |
474 | } | 474 | } |
475 | 475 | ||
476 | #ifdef CONFIG_LOCAL_TIMERS | ||
477 | irqreturn_t percpu_timer_handler(int irq, void *dev_id) | ||
478 | { | ||
479 | struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent); | ||
480 | |||
481 | if (local_timer_ack()) { | ||
482 | evt->event_handler(evt); | ||
483 | return IRQ_HANDLED; | ||
484 | } | ||
485 | |||
486 | return IRQ_NONE; | ||
487 | } | ||
488 | #endif | ||
489 | |||
490 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST | 476 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST |
491 | static void smp_timer_broadcast(const struct cpumask *mask) | 477 | static void smp_timer_broadcast(const struct cpumask *mask) |
492 | { | 478 | { |
@@ -537,7 +523,7 @@ static void percpu_timer_stop(void) | |||
537 | unsigned int cpu = smp_processor_id(); | 523 | unsigned int cpu = smp_processor_id(); |
538 | struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); | 524 | struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); |
539 | 525 | ||
540 | evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); | 526 | local_timer_stop(evt); |
541 | } | 527 | } |
542 | #endif | 528 | #endif |
543 | 529 | ||
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 01c186222f3b..a8a6682d6b52 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
20 | 20 | ||
21 | #include <asm/smp_twd.h> | 21 | #include <asm/smp_twd.h> |
22 | #include <asm/localtimer.h> | ||
22 | #include <asm/hardware/gic.h> | 23 | #include <asm/hardware/gic.h> |
23 | 24 | ||
24 | /* set up by the platform code */ | 25 | /* set up by the platform code */ |
@@ -26,6 +27,8 @@ void __iomem *twd_base; | |||
26 | 27 | ||
27 | static unsigned long twd_timer_rate; | 28 | static unsigned long twd_timer_rate; |
28 | 29 | ||
30 | static struct clock_event_device __percpu **twd_evt; | ||
31 | |||
29 | static void twd_set_mode(enum clock_event_mode mode, | 32 | static void twd_set_mode(enum clock_event_mode mode, |
30 | struct clock_event_device *clk) | 33 | struct clock_event_device *clk) |
31 | { | 34 | { |
@@ -80,6 +83,12 @@ int twd_timer_ack(void) | |||
80 | return 0; | 83 | return 0; |
81 | } | 84 | } |
82 | 85 | ||
86 | void twd_timer_stop(struct clock_event_device *clk) | ||
87 | { | ||
88 | twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk); | ||
89 | disable_percpu_irq(clk->irq); | ||
90 | } | ||
91 | |||
83 | static void __cpuinit twd_calibrate_rate(void) | 92 | static void __cpuinit twd_calibrate_rate(void) |
84 | { | 93 | { |
85 | unsigned long count; | 94 | unsigned long count; |
@@ -119,11 +128,43 @@ static void __cpuinit twd_calibrate_rate(void) | |||
119 | } | 128 | } |
120 | } | 129 | } |
121 | 130 | ||
131 | static irqreturn_t twd_handler(int irq, void *dev_id) | ||
132 | { | ||
133 | struct clock_event_device *evt = *(struct clock_event_device **)dev_id; | ||
134 | |||
135 | if (twd_timer_ack()) { | ||
136 | evt->event_handler(evt); | ||
137 | return IRQ_HANDLED; | ||
138 | } | ||
139 | |||
140 | return IRQ_NONE; | ||
141 | } | ||
142 | |||
122 | /* | 143 | /* |
123 | * Setup the local clock events for a CPU. | 144 | * Setup the local clock events for a CPU. |
124 | */ | 145 | */ |
125 | void __cpuinit twd_timer_setup(struct clock_event_device *clk) | 146 | void __cpuinit twd_timer_setup(struct clock_event_device *clk) |
126 | { | 147 | { |
148 | struct clock_event_device **this_cpu_clk; | ||
149 | |||
150 | if (!twd_evt) { | ||
151 | int err; | ||
152 | |||
153 | twd_evt = alloc_percpu(struct clock_event_device *); | ||
154 | if (!twd_evt) { | ||
155 | pr_err("twd: can't allocate memory\n"); | ||
156 | return; | ||
157 | } | ||
158 | |||
159 | err = request_percpu_irq(clk->irq, twd_handler, | ||
160 | "twd", twd_evt); | ||
161 | if (err) { | ||
162 | pr_err("twd: can't register interrupt %d (%d)\n", | ||
163 | clk->irq, err); | ||
164 | return; | ||
165 | } | ||
166 | } | ||
167 | |||
127 | twd_calibrate_rate(); | 168 | twd_calibrate_rate(); |
128 | 169 | ||
129 | clk->name = "local_timer"; | 170 | clk->name = "local_timer"; |
@@ -137,8 +178,10 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk) | |||
137 | clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk); | 178 | clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk); |
138 | clk->min_delta_ns = clockevent_delta2ns(0xf, clk); | 179 | clk->min_delta_ns = clockevent_delta2ns(0xf, clk); |
139 | 180 | ||
181 | this_cpu_clk = __this_cpu_ptr(twd_evt); | ||
182 | *this_cpu_clk = clk; | ||
183 | |||
140 | clockevents_register_device(clk); | 184 | clockevents_register_device(clk); |
141 | 185 | ||
142 | /* Make sure our local interrupt controller has this enabled */ | 186 | enable_percpu_irq(clk->irq, 0); |
143 | gic_enable_ppi(clk->irq); | ||
144 | } | 187 | } |
diff --git a/arch/arm/mach-exynos4/mct.c b/arch/arm/mach-exynos4/mct.c index 1ae059b7ad7b..85a1bb79f11c 100644 --- a/arch/arm/mach-exynos4/mct.c +++ b/arch/arm/mach-exynos4/mct.c | |||
@@ -380,9 +380,11 @@ static void exynos4_mct_tick_init(struct clock_event_device *evt) | |||
380 | 380 | ||
381 | if (cpu == 0) { | 381 | if (cpu == 0) { |
382 | mct_tick0_event_irq.dev_id = &mct_tick[cpu]; | 382 | mct_tick0_event_irq.dev_id = &mct_tick[cpu]; |
383 | evt->irq = IRQ_MCT_L0; | ||
383 | setup_irq(IRQ_MCT_L0, &mct_tick0_event_irq); | 384 | setup_irq(IRQ_MCT_L0, &mct_tick0_event_irq); |
384 | } else { | 385 | } else { |
385 | mct_tick1_event_irq.dev_id = &mct_tick[cpu]; | 386 | mct_tick1_event_irq.dev_id = &mct_tick[cpu]; |
387 | evt->irq = IRQ_MCT_L1; | ||
386 | setup_irq(IRQ_MCT_L1, &mct_tick1_event_irq); | 388 | setup_irq(IRQ_MCT_L1, &mct_tick1_event_irq); |
387 | irq_set_affinity(IRQ_MCT_L1, cpumask_of(1)); | 389 | irq_set_affinity(IRQ_MCT_L1, cpumask_of(1)); |
388 | } | 390 | } |
@@ -394,9 +396,10 @@ void __cpuinit local_timer_setup(struct clock_event_device *evt) | |||
394 | exynos4_mct_tick_init(evt); | 396 | exynos4_mct_tick_init(evt); |
395 | } | 397 | } |
396 | 398 | ||
397 | int local_timer_ack(void) | 399 | void local_timer_stop(struct clock_event_device *evt) |
398 | { | 400 | { |
399 | return 0; | 401 | evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); |
402 | disable_irq(evt->irq); | ||
400 | } | 403 | } |
401 | 404 | ||
402 | #endif /* CONFIG_LOCAL_TIMERS */ | 405 | #endif /* CONFIG_LOCAL_TIMERS */ |
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 63621f152c98..afeeca52fc66 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c | |||
@@ -71,12 +71,16 @@ enum timer_location { | |||
71 | struct msm_clock { | 71 | struct msm_clock { |
72 | struct clock_event_device clockevent; | 72 | struct clock_event_device clockevent; |
73 | struct clocksource clocksource; | 73 | struct clocksource clocksource; |
74 | struct irqaction irq; | 74 | unsigned int irq; |
75 | void __iomem *regbase; | 75 | void __iomem *regbase; |
76 | uint32_t freq; | 76 | uint32_t freq; |
77 | uint32_t shift; | 77 | uint32_t shift; |
78 | void __iomem *global_counter; | 78 | void __iomem *global_counter; |
79 | void __iomem *local_counter; | 79 | void __iomem *local_counter; |
80 | union { | ||
81 | struct clock_event_device *evt; | ||
82 | struct clock_event_device __percpu **percpu_evt; | ||
83 | }; | ||
80 | }; | 84 | }; |
81 | 85 | ||
82 | enum { | 86 | enum { |
@@ -87,13 +91,10 @@ enum { | |||
87 | 91 | ||
88 | 92 | ||
89 | static struct msm_clock msm_clocks[]; | 93 | static struct msm_clock msm_clocks[]; |
90 | static struct clock_event_device *local_clock_event; | ||
91 | 94 | ||
92 | static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) | 95 | static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) |
93 | { | 96 | { |
94 | struct clock_event_device *evt = dev_id; | 97 | struct clock_event_device *evt = *(struct clock_event_device **)dev_id; |
95 | if (smp_processor_id() != 0) | ||
96 | evt = local_clock_event; | ||
97 | if (evt->event_handler == NULL) | 98 | if (evt->event_handler == NULL) |
98 | return IRQ_HANDLED; | 99 | return IRQ_HANDLED; |
99 | evt->event_handler(evt); | 100 | evt->event_handler(evt); |
@@ -171,13 +172,7 @@ static struct msm_clock msm_clocks[] = { | |||
171 | .mask = CLOCKSOURCE_MASK(32), | 172 | .mask = CLOCKSOURCE_MASK(32), |
172 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 173 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
173 | }, | 174 | }, |
174 | .irq = { | 175 | .irq = INT_GP_TIMER_EXP, |
175 | .name = "gp_timer", | ||
176 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING, | ||
177 | .handler = msm_timer_interrupt, | ||
178 | .dev_id = &msm_clocks[0].clockevent, | ||
179 | .irq = INT_GP_TIMER_EXP | ||
180 | }, | ||
181 | .freq = GPT_HZ, | 176 | .freq = GPT_HZ, |
182 | }, | 177 | }, |
183 | [MSM_CLOCK_DGT] = { | 178 | [MSM_CLOCK_DGT] = { |
@@ -196,13 +191,7 @@ static struct msm_clock msm_clocks[] = { | |||
196 | .mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)), | 191 | .mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)), |
197 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 192 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
198 | }, | 193 | }, |
199 | .irq = { | 194 | .irq = INT_DEBUG_TIMER_EXP, |
200 | .name = "dg_timer", | ||
201 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING, | ||
202 | .handler = msm_timer_interrupt, | ||
203 | .dev_id = &msm_clocks[1].clockevent, | ||
204 | .irq = INT_DEBUG_TIMER_EXP | ||
205 | }, | ||
206 | .freq = DGT_HZ >> MSM_DGT_SHIFT, | 195 | .freq = DGT_HZ >> MSM_DGT_SHIFT, |
207 | .shift = MSM_DGT_SHIFT, | 196 | .shift = MSM_DGT_SHIFT, |
208 | } | 197 | } |
@@ -261,10 +250,30 @@ static void __init msm_timer_init(void) | |||
261 | printk(KERN_ERR "msm_timer_init: clocksource_register " | 250 | printk(KERN_ERR "msm_timer_init: clocksource_register " |
262 | "failed for %s\n", cs->name); | 251 | "failed for %s\n", cs->name); |
263 | 252 | ||
264 | res = setup_irq(clock->irq.irq, &clock->irq); | 253 | ce->irq = clock->irq; |
254 | if (cpu_is_msm8x60() || cpu_is_msm8960()) { | ||
255 | clock->percpu_evt = alloc_percpu(struct clock_event_device *); | ||
256 | if (!clock->percpu_evt) { | ||
257 | pr_err("msm_timer_init: memory allocation " | ||
258 | "failed for %s\n", ce->name); | ||
259 | continue; | ||
260 | } | ||
261 | |||
262 | *__this_cpu_ptr(clock->percpu_evt) = ce; | ||
263 | res = request_percpu_irq(ce->irq, msm_timer_interrupt, | ||
264 | ce->name, clock->percpu_evt); | ||
265 | if (!res) | ||
266 | enable_percpu_irq(ce->irq, 0); | ||
267 | } else { | ||
268 | clock->evt = ce; | ||
269 | res = request_irq(ce->irq, msm_timer_interrupt, | ||
270 | IRQF_TIMER | IRQF_NOBALANCING | IRQF_TRIGGER_RISING, | ||
271 | ce->name, &clock->evt); | ||
272 | } | ||
273 | |||
265 | if (res) | 274 | if (res) |
266 | printk(KERN_ERR "msm_timer_init: setup_irq " | 275 | pr_err("msm_timer_init: request_irq failed for %s\n", |
267 | "failed for %s\n", cs->name); | 276 | ce->name); |
268 | 277 | ||
269 | clockevents_register_device(ce); | 278 | clockevents_register_device(ce); |
270 | } | 279 | } |
@@ -273,6 +282,7 @@ static void __init msm_timer_init(void) | |||
273 | #ifdef CONFIG_SMP | 282 | #ifdef CONFIG_SMP |
274 | int __cpuinit local_timer_setup(struct clock_event_device *evt) | 283 | int __cpuinit local_timer_setup(struct clock_event_device *evt) |
275 | { | 284 | { |
285 | static bool local_timer_inited; | ||
276 | struct msm_clock *clock = &msm_clocks[MSM_GLOBAL_TIMER]; | 286 | struct msm_clock *clock = &msm_clocks[MSM_GLOBAL_TIMER]; |
277 | 287 | ||
278 | /* Use existing clock_event for cpu 0 */ | 288 | /* Use existing clock_event for cpu 0 */ |
@@ -281,12 +291,13 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt) | |||
281 | 291 | ||
282 | writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); | 292 | writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); |
283 | 293 | ||
284 | if (!local_clock_event) { | 294 | if (!local_timer_inited) { |
285 | writel(0, clock->regbase + TIMER_ENABLE); | 295 | writel(0, clock->regbase + TIMER_ENABLE); |
286 | writel(0, clock->regbase + TIMER_CLEAR); | 296 | writel(0, clock->regbase + TIMER_CLEAR); |
287 | writel(~0, clock->regbase + TIMER_MATCH_VAL); | 297 | writel(~0, clock->regbase + TIMER_MATCH_VAL); |
298 | local_timer_inited = true; | ||
288 | } | 299 | } |
289 | evt->irq = clock->irq.irq; | 300 | evt->irq = clock->irq; |
290 | evt->name = "local_timer"; | 301 | evt->name = "local_timer"; |
291 | evt->features = CLOCK_EVT_FEAT_ONESHOT; | 302 | evt->features = CLOCK_EVT_FEAT_ONESHOT; |
292 | evt->rating = clock->clockevent.rating; | 303 | evt->rating = clock->clockevent.rating; |
@@ -298,17 +309,17 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt) | |||
298 | clockevent_delta2ns(0xf0000000 >> clock->shift, evt); | 309 | clockevent_delta2ns(0xf0000000 >> clock->shift, evt); |
299 | evt->min_delta_ns = clockevent_delta2ns(4, evt); | 310 | evt->min_delta_ns = clockevent_delta2ns(4, evt); |
300 | 311 | ||
301 | local_clock_event = evt; | 312 | *__this_cpu_ptr(clock->percpu_evt) = evt; |
302 | 313 | enable_percpu_irq(evt->irq, 0); | |
303 | gic_enable_ppi(clock->irq.irq); | ||
304 | 314 | ||
305 | clockevents_register_device(evt); | 315 | clockevents_register_device(evt); |
306 | return 0; | 316 | return 0; |
307 | } | 317 | } |
308 | 318 | ||
309 | inline int local_timer_ack(void) | 319 | void local_timer_stop(struct clock_event_device *evt) |
310 | { | 320 | { |
311 | return 1; | 321 | evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); |
322 | disable_percpu_irq(evt->irq); | ||
312 | } | 323 | } |
313 | 324 | ||
314 | #endif | 325 | #endif |