aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2011-07-22 07:52:37 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2011-10-23 08:32:33 -0400
commit28af690a284dfcb627bd69d0963db1c0f412cb8c (patch)
tree6daa595281c87b5bfee4cca79492a724deb1cfbc /arch/arm
parent292b293ceef2eda1f96f0c90b96e954d7bdabd1c (diff)
ARM: gic, local timers: use the request_percpu_irq() interface
This patch remove the hardcoded link between local timers and PPIs, and convert the PPI users (TWD, MCT and MSM timers) to the new *_percpu_irq interface. Also some collateral cleanup (local_timer_ack() is gone, and the interrupt handler is strictly private to each driver). PPIs are now useable for more than just the local timers. Additional testing by David Brown (msm8250 and msm8660) and Shawn Guo (imx6q). Cc: David Brown <davidb@codeaurora.org> Cc: Thomas Gleixner <tglx@linutronix.de> Acked-by: David Brown <davidb@codeaurora.org> Tested-by: David Brown <davidb@codeaurora.org> Tested-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/common/gic.c52
-rw-r--r--arch/arm/include/asm/hardware/gic.h1
-rw-r--r--arch/arm/include/asm/localtimer.h16
-rw-r--r--arch/arm/include/asm/smp_twd.h2
-rw-r--r--arch/arm/kernel/smp.c16
-rw-r--r--arch/arm/kernel/smp_twd.c47
-rw-r--r--arch/arm/mach-exynos4/mct.c7
-rw-r--r--arch/arm/mach-msm/timer.c69
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
40static DEFINE_SPINLOCK(irq_controller_lock); 39static 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
265static 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
279static 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
286static struct irqaction *ppi_irqaction;
287
288static void __init gic_dist_init(struct gic_chip_data *gic, 261static 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
451void __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
462void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) 410void 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 *);
40void gic_secondary_init(unsigned int); 40void gic_secondary_init(unsigned int);
41void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); 41void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
42void gic_raise_softirq(const struct cpumask *mask, unsigned int irq); 42void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
43void gic_enable_ppi(unsigned int);
44 43
45struct gic_chip_data { 44struct 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 */
20void percpu_timer_setup(void); 20void percpu_timer_setup(void);
21 21
22/*
23 * Per-cpu timer IRQ handler
24 */
25irqreturn_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 */
41int local_timer_ack(void); 35void 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
51static 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
23extern void __iomem *twd_base; 23extern void __iomem *twd_base;
24 24
25int twd_timer_ack(void);
26void twd_timer_setup(struct clock_event_device *); 25void twd_timer_setup(struct clock_event_device *);
26void 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
477irqreturn_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
491static void smp_timer_broadcast(const struct cpumask *mask) 477static 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
27static unsigned long twd_timer_rate; 28static unsigned long twd_timer_rate;
28 29
30static struct clock_event_device __percpu **twd_evt;
31
29static void twd_set_mode(enum clock_event_mode mode, 32static 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
86void 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
83static void __cpuinit twd_calibrate_rate(void) 92static 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
131static 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 */
125void __cpuinit twd_timer_setup(struct clock_event_device *clk) 146void __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
397int local_timer_ack(void) 399void 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 {
71struct msm_clock { 71struct 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
82enum { 86enum {
@@ -87,13 +91,10 @@ enum {
87 91
88 92
89static struct msm_clock msm_clocks[]; 93static struct msm_clock msm_clocks[];
90static struct clock_event_device *local_clock_event;
91 94
92static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) 95static 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
274int __cpuinit local_timer_setup(struct clock_event_device *evt) 283int __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
309inline int local_timer_ack(void) 319void 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