aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorStephen Boyd <sboyd@codeaurora.org>2013-02-15 19:02:20 -0500
committerStephen Boyd <sboyd@codeaurora.org>2013-06-24 20:45:58 -0400
commita894fcc2d01a89e6fe3da0845a4d80a5312e1124 (patch)
tree90029c9dacd4b5f53583b09d516480cb138fb364 /arch/arm/kernel
parent3d53ceeca7bae807e5aba0935347f3757127a821 (diff)
ARM: smp_twd: Divorce smp_twd from local timer API
Separate the smp_twd timers from the local timer API. This will allow us to remove ARM local timer support in the near future and gets us closer to moving this driver to drivers/clocksource. Tested-by: Mark Rutland <mark.rutland@arm.com> Acked-by: Marc Zyngier <marc.zyngier@arm.com> Cc: Russell King <linux@arm.linux.org.uk> Cc: Tony Lindgren <tony@atomide.com> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/smp_twd.c64
1 files changed, 43 insertions, 21 deletions
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 90525d9d290b..aac1495b44de 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -11,6 +11,7 @@
11#include <linux/init.h> 11#include <linux/init.h>
12#include <linux/kernel.h> 12#include <linux/kernel.h>
13#include <linux/clk.h> 13#include <linux/clk.h>
14#include <linux/cpu.h>
14#include <linux/delay.h> 15#include <linux/delay.h>
15#include <linux/device.h> 16#include <linux/device.h>
16#include <linux/err.h> 17#include <linux/err.h>
@@ -24,7 +25,6 @@
24 25
25#include <asm/smp_plat.h> 26#include <asm/smp_plat.h>
26#include <asm/smp_twd.h> 27#include <asm/smp_twd.h>
27#include <asm/localtimer.h>
28 28
29/* set up by the platform code */ 29/* set up by the platform code */
30static void __iomem *twd_base; 30static void __iomem *twd_base;
@@ -33,7 +33,7 @@ static struct clk *twd_clk;
33static unsigned long twd_timer_rate; 33static unsigned long twd_timer_rate;
34static DEFINE_PER_CPU(bool, percpu_setup_called); 34static DEFINE_PER_CPU(bool, percpu_setup_called);
35 35
36static struct clock_event_device __percpu **twd_evt; 36static struct clock_event_device __percpu *twd_evt;
37static int twd_ppi; 37static int twd_ppi;
38 38
39static void twd_set_mode(enum clock_event_mode mode, 39static void twd_set_mode(enum clock_event_mode mode,
@@ -90,8 +90,10 @@ static int twd_timer_ack(void)
90 return 0; 90 return 0;
91} 91}
92 92
93static void twd_timer_stop(struct clock_event_device *clk) 93static void twd_timer_stop(void)
94{ 94{
95 struct clock_event_device *clk = __this_cpu_ptr(twd_evt);
96
95 twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk); 97 twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
96 disable_percpu_irq(clk->irq); 98 disable_percpu_irq(clk->irq);
97} 99}
@@ -106,7 +108,7 @@ static void twd_update_frequency(void *new_rate)
106{ 108{
107 twd_timer_rate = *((unsigned long *) new_rate); 109 twd_timer_rate = *((unsigned long *) new_rate);
108 110
109 clockevents_update_freq(*__this_cpu_ptr(twd_evt), twd_timer_rate); 111 clockevents_update_freq(__this_cpu_ptr(twd_evt), twd_timer_rate);
110} 112}
111 113
112static int twd_rate_change(struct notifier_block *nb, 114static int twd_rate_change(struct notifier_block *nb,
@@ -132,7 +134,7 @@ static struct notifier_block twd_clk_nb = {
132 134
133static int twd_clk_init(void) 135static int twd_clk_init(void)
134{ 136{
135 if (twd_evt && *__this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk)) 137 if (twd_evt && __this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk))
136 return clk_notifier_register(twd_clk, &twd_clk_nb); 138 return clk_notifier_register(twd_clk, &twd_clk_nb);
137 139
138 return 0; 140 return 0;
@@ -151,7 +153,7 @@ static void twd_update_frequency(void *data)
151{ 153{
152 twd_timer_rate = clk_get_rate(twd_clk); 154 twd_timer_rate = clk_get_rate(twd_clk);
153 155
154 clockevents_update_freq(*__this_cpu_ptr(twd_evt), twd_timer_rate); 156 clockevents_update_freq(__this_cpu_ptr(twd_evt), twd_timer_rate);
155} 157}
156 158
157static int twd_cpufreq_transition(struct notifier_block *nb, 159static int twd_cpufreq_transition(struct notifier_block *nb,
@@ -177,7 +179,7 @@ static struct notifier_block twd_cpufreq_nb = {
177 179
178static int twd_cpufreq_init(void) 180static int twd_cpufreq_init(void)
179{ 181{
180 if (twd_evt && *__this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk)) 182 if (twd_evt && __this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk))
181 return cpufreq_register_notifier(&twd_cpufreq_nb, 183 return cpufreq_register_notifier(&twd_cpufreq_nb,
182 CPUFREQ_TRANSITION_NOTIFIER); 184 CPUFREQ_TRANSITION_NOTIFIER);
183 185
@@ -228,7 +230,7 @@ static void __cpuinit twd_calibrate_rate(void)
228 230
229static irqreturn_t twd_handler(int irq, void *dev_id) 231static irqreturn_t twd_handler(int irq, void *dev_id)
230{ 232{
231 struct clock_event_device *evt = *(struct clock_event_device **)dev_id; 233 struct clock_event_device *evt = dev_id;
232 234
233 if (twd_timer_ack()) { 235 if (twd_timer_ack()) {
234 evt->event_handler(evt); 236 evt->event_handler(evt);
@@ -265,9 +267,9 @@ static void twd_get_clock(struct device_node *np)
265/* 267/*
266 * Setup the local clock events for a CPU. 268 * Setup the local clock events for a CPU.
267 */ 269 */
268static int __cpuinit twd_timer_setup(struct clock_event_device *clk) 270static void __cpuinit twd_timer_setup(void)
269{ 271{
270 struct clock_event_device **this_cpu_clk; 272 struct clock_event_device *clk = __this_cpu_ptr(twd_evt);
271 int cpu = smp_processor_id(); 273 int cpu = smp_processor_id();
272 274
273 /* 275 /*
@@ -276,9 +278,9 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
276 */ 278 */
277 if (per_cpu(percpu_setup_called, cpu)) { 279 if (per_cpu(percpu_setup_called, cpu)) {
278 __raw_writel(0, twd_base + TWD_TIMER_CONTROL); 280 __raw_writel(0, twd_base + TWD_TIMER_CONTROL);
279 clockevents_register_device(*__this_cpu_ptr(twd_evt)); 281 clockevents_register_device(clk);
280 enable_percpu_irq(clk->irq, 0); 282 enable_percpu_irq(clk->irq, 0);
281 return 0; 283 return;
282 } 284 }
283 per_cpu(percpu_setup_called, cpu) = true; 285 per_cpu(percpu_setup_called, cpu) = true;
284 286
@@ -297,27 +299,37 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
297 clk->set_mode = twd_set_mode; 299 clk->set_mode = twd_set_mode;
298 clk->set_next_event = twd_set_next_event; 300 clk->set_next_event = twd_set_next_event;
299 clk->irq = twd_ppi; 301 clk->irq = twd_ppi;
300 302 clk->cpumask = cpumask_of(cpu);
301 this_cpu_clk = __this_cpu_ptr(twd_evt);
302 *this_cpu_clk = clk;
303 303
304 clockevents_config_and_register(clk, twd_timer_rate, 304 clockevents_config_and_register(clk, twd_timer_rate,
305 0xf, 0xffffffff); 305 0xf, 0xffffffff);
306 enable_percpu_irq(clk->irq, 0); 306 enable_percpu_irq(clk->irq, 0);
307}
307 308
308 return 0; 309static int __cpuinit twd_timer_cpu_notify(struct notifier_block *self,
310 unsigned long action, void *hcpu)
311{
312 switch (action & ~CPU_TASKS_FROZEN) {
313 case CPU_STARTING:
314 twd_timer_setup();
315 break;
316 case CPU_DYING:
317 twd_timer_stop();
318 break;
319 }
320
321 return NOTIFY_OK;
309} 322}
310 323
311static struct local_timer_ops twd_lt_ops __cpuinitdata = { 324static struct notifier_block twd_timer_cpu_nb __cpuinitdata = {
312 .setup = twd_timer_setup, 325 .notifier_call = twd_timer_cpu_notify,
313 .stop = twd_timer_stop,
314}; 326};
315 327
316static int __init twd_local_timer_common_register(struct device_node *np) 328static int __init twd_local_timer_common_register(struct device_node *np)
317{ 329{
318 int err; 330 int err;
319 331
320 twd_evt = alloc_percpu(struct clock_event_device *); 332 twd_evt = alloc_percpu(struct clock_event_device);
321 if (!twd_evt) { 333 if (!twd_evt) {
322 err = -ENOMEM; 334 err = -ENOMEM;
323 goto out_free; 335 goto out_free;
@@ -329,12 +341,22 @@ static int __init twd_local_timer_common_register(struct device_node *np)
329 goto out_free; 341 goto out_free;
330 } 342 }
331 343
332 err = local_timer_register(&twd_lt_ops); 344 err = register_cpu_notifier(&twd_timer_cpu_nb);
333 if (err) 345 if (err)
334 goto out_irq; 346 goto out_irq;
335 347
336 twd_get_clock(np); 348 twd_get_clock(np);
337 349
350 /*
351 * Immediately configure the timer on the boot CPU, unless we need
352 * jiffies to be incrementing to calibrate the rate in which case
353 * setup the timer in late_time_init.
354 */
355 if (twd_timer_rate)
356 twd_timer_setup();
357 else
358 late_time_init = twd_timer_setup;
359
338 return 0; 360 return 0;
339 361
340out_irq: 362out_irq: