summaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/time-armada-370-xp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clocksource/time-armada-370-xp.c')
-rw-r--r--drivers/clocksource/time-armada-370-xp.c87
1 files changed, 43 insertions, 44 deletions
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c
index 44c4fff2f58c..0198504ef6b0 100644
--- a/drivers/clocksource/time-armada-370-xp.c
+++ b/drivers/clocksource/time-armada-370-xp.c
@@ -32,6 +32,7 @@
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/clk.h>
+#include <linux/cpu.h>
#include <linux/timer.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
@@ -41,9 +42,8 @@
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/sched_clock.h>
-
-#include <asm/localtimer.h>
#include <linux/percpu.h>
+
/*
* Timer block registers.
*/
@@ -82,7 +82,7 @@ static bool timer25Mhz = true;
*/
static u32 ticks_per_jiffy;
-static struct clock_event_device __percpu **percpu_armada_370_xp_evt;
+static struct clock_event_device __percpu *armada_370_xp_evt;
static void timer_ctrl_clrset(u32 clr, u32 set)
{
@@ -157,21 +157,14 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode,
}
}
-static struct clock_event_device armada_370_xp_clkevt = {
- .name = "armada_370_xp_per_cpu_tick",
- .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
- .shift = 32,
- .rating = 300,
- .set_next_event = armada_370_xp_clkevt_next_event,
- .set_mode = armada_370_xp_clkevt_mode,
-};
+static int armada_370_xp_clkevt_irq;
static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id)
{
/*
* ACK timer interrupt and call event handler.
*/
- struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+ struct clock_event_device *evt = dev_id;
writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
evt->event_handler(evt);
@@ -187,42 +180,55 @@ static int armada_370_xp_timer_setup(struct clock_event_device *evt)
u32 clr = 0, set = 0;
int cpu = smp_processor_id();
- /* Use existing clock_event for cpu 0 */
- if (!smp_processor_id())
- return 0;
-
if (timer25Mhz)
set = TIMER0_25MHZ;
else
clr = TIMER0_25MHZ;
local_timer_ctrl_clrset(clr, set);
- evt->name = armada_370_xp_clkevt.name;
- evt->irq = armada_370_xp_clkevt.irq;
- evt->features = armada_370_xp_clkevt.features;
- evt->shift = armada_370_xp_clkevt.shift;
- evt->rating = armada_370_xp_clkevt.rating,
+ evt->name = "armada_370_xp_per_cpu_tick",
+ evt->features = CLOCK_EVT_FEAT_ONESHOT |
+ CLOCK_EVT_FEAT_PERIODIC;
+ evt->shift = 32,
+ evt->rating = 300,
evt->set_next_event = armada_370_xp_clkevt_next_event,
evt->set_mode = armada_370_xp_clkevt_mode,
+ evt->irq = armada_370_xp_clkevt_irq;
evt->cpumask = cpumask_of(cpu);
- *__this_cpu_ptr(percpu_armada_370_xp_evt) = evt;
-
clockevents_config_and_register(evt, timer_clk, 1, 0xfffffffe);
enable_percpu_irq(evt->irq, 0);
return 0;
}
-static void armada_370_xp_timer_stop(struct clock_event_device *evt)
+static void armada_370_xp_timer_stop(struct clock_event_device *evt)
{
evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
disable_percpu_irq(evt->irq);
}
-static struct local_timer_ops armada_370_xp_local_timer_ops = {
- .setup = armada_370_xp_timer_setup,
- .stop = armada_370_xp_timer_stop,
+static int armada_370_xp_timer_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ /*
+ * Grab cpu pointer in each case to avoid spurious
+ * preemptible warnings
+ */
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_STARTING:
+ armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt));
+ break;
+ case CPU_DYING:
+ armada_370_xp_timer_stop(this_cpu_ptr(armada_370_xp_evt));
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block armada_370_xp_timer_cpu_nb = {
+ .notifier_call = armada_370_xp_timer_cpu_notify,
};
static void __init armada_370_xp_timer_common_init(struct device_node *np)
@@ -235,7 +241,7 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np)
local_base = of_iomap(np, 1);
if (timer25Mhz)
- set = TIMER0_25MHZ;
+ set = TIMER0_25MHZ;
else
clr = TIMER0_25MHZ;
timer_ctrl_clrset(clr, set);
@@ -245,7 +251,7 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np)
* We use timer 0 as clocksource, and private(local) timer 0
* for clockevents
*/
- armada_370_xp_clkevt.irq = irq_of_parse_and_map(np, 4);
+ armada_370_xp_clkevt_irq = irq_of_parse_and_map(np, 4);
ticks_per_jiffy = (timer_clk + HZ / 2) / HZ;
@@ -268,28 +274,21 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np)
"armada_370_xp_clocksource",
timer_clk, 300, 32, clocksource_mmio_readl_down);
- /* Register the clockevent on the private timer of CPU 0 */
- armada_370_xp_clkevt.cpumask = cpumask_of(0);
- clockevents_config_and_register(&armada_370_xp_clkevt,
- timer_clk, 1, 0xfffffffe);
+ register_cpu_notifier(&armada_370_xp_timer_cpu_nb);
- percpu_armada_370_xp_evt = alloc_percpu(struct clock_event_device *);
+ armada_370_xp_evt = alloc_percpu(struct clock_event_device);
/*
* Setup clockevent timer (interrupt-driven).
*/
- *__this_cpu_ptr(percpu_armada_370_xp_evt) = &armada_370_xp_clkevt;
- res = request_percpu_irq(armada_370_xp_clkevt.irq,
+ res = request_percpu_irq(armada_370_xp_clkevt_irq,
armada_370_xp_timer_interrupt,
- armada_370_xp_clkevt.name,
- percpu_armada_370_xp_evt);
- if (!res) {
- enable_percpu_irq(armada_370_xp_clkevt.irq, 0);
-#ifdef CONFIG_LOCAL_TIMERS
- local_timer_register(&armada_370_xp_local_timer_ops);
-#endif
- }
+ "armada_370_xp_per_cpu_tick",
+ armada_370_xp_evt);
+ /* Immediately configure the timer on the boot CPU */
+ if (!res)
+ armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt));
}
static void __init armada_xp_timer_init(struct device_node *np)