diff options
Diffstat (limited to 'drivers/clocksource/timer-marco.c')
-rw-r--r-- | drivers/clocksource/timer-marco.c | 98 |
1 files changed, 53 insertions, 45 deletions
diff --git a/drivers/clocksource/timer-marco.c b/drivers/clocksource/timer-marco.c index 62876baa3ab9..09a17d9a6594 100644 --- a/drivers/clocksource/timer-marco.c +++ b/drivers/clocksource/timer-marco.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/interrupt.h> | 10 | #include <linux/interrupt.h> |
11 | #include <linux/clockchips.h> | 11 | #include <linux/clockchips.h> |
12 | #include <linux/clocksource.h> | 12 | #include <linux/clocksource.h> |
13 | #include <linux/cpu.h> | ||
13 | #include <linux/bitops.h> | 14 | #include <linux/bitops.h> |
14 | #include <linux/irq.h> | 15 | #include <linux/irq.h> |
15 | #include <linux/clk.h> | 16 | #include <linux/clk.h> |
@@ -18,7 +19,6 @@ | |||
18 | #include <linux/of_irq.h> | 19 | #include <linux/of_irq.h> |
19 | #include <linux/of_address.h> | 20 | #include <linux/of_address.h> |
20 | #include <linux/sched_clock.h> | 21 | #include <linux/sched_clock.h> |
21 | #include <asm/localtimer.h> | ||
22 | #include <asm/mach/time.h> | 22 | #include <asm/mach/time.h> |
23 | 23 | ||
24 | #define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000 | 24 | #define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000 |
@@ -151,13 +151,7 @@ static void sirfsoc_clocksource_resume(struct clocksource *cs) | |||
151 | BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); | 151 | BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); |
152 | } | 152 | } |
153 | 153 | ||
154 | static struct clock_event_device sirfsoc_clockevent = { | 154 | static struct clock_event_device __percpu *sirfsoc_clockevent; |
155 | .name = "sirfsoc_clockevent", | ||
156 | .rating = 200, | ||
157 | .features = CLOCK_EVT_FEAT_ONESHOT, | ||
158 | .set_mode = sirfsoc_timer_set_mode, | ||
159 | .set_next_event = sirfsoc_timer_set_next_event, | ||
160 | }; | ||
161 | 155 | ||
162 | static struct clocksource sirfsoc_clocksource = { | 156 | static struct clocksource sirfsoc_clocksource = { |
163 | .name = "sirfsoc_clocksource", | 157 | .name = "sirfsoc_clocksource", |
@@ -173,11 +167,8 @@ static struct irqaction sirfsoc_timer_irq = { | |||
173 | .name = "sirfsoc_timer0", | 167 | .name = "sirfsoc_timer0", |
174 | .flags = IRQF_TIMER | IRQF_NOBALANCING, | 168 | .flags = IRQF_TIMER | IRQF_NOBALANCING, |
175 | .handler = sirfsoc_timer_interrupt, | 169 | .handler = sirfsoc_timer_interrupt, |
176 | .dev_id = &sirfsoc_clockevent, | ||
177 | }; | 170 | }; |
178 | 171 | ||
179 | #ifdef CONFIG_LOCAL_TIMERS | ||
180 | |||
181 | static struct irqaction sirfsoc_timer1_irq = { | 172 | static struct irqaction sirfsoc_timer1_irq = { |
182 | .name = "sirfsoc_timer1", | 173 | .name = "sirfsoc_timer1", |
183 | .flags = IRQF_TIMER | IRQF_NOBALANCING, | 174 | .flags = IRQF_TIMER | IRQF_NOBALANCING, |
@@ -186,24 +177,28 @@ static struct irqaction sirfsoc_timer1_irq = { | |||
186 | 177 | ||
187 | static int sirfsoc_local_timer_setup(struct clock_event_device *ce) | 178 | static int sirfsoc_local_timer_setup(struct clock_event_device *ce) |
188 | { | 179 | { |
189 | /* Use existing clock_event for cpu 0 */ | 180 | int cpu = smp_processor_id(); |
190 | if (!smp_processor_id()) | 181 | struct irqaction *action; |
191 | return 0; | 182 | |
183 | if (cpu == 0) | ||
184 | action = &sirfsoc_timer_irq; | ||
185 | else | ||
186 | action = &sirfsoc_timer1_irq; | ||
192 | 187 | ||
193 | ce->irq = sirfsoc_timer1_irq.irq; | 188 | ce->irq = action->irq; |
194 | ce->name = "local_timer"; | 189 | ce->name = "local_timer"; |
195 | ce->features = sirfsoc_clockevent.features; | 190 | ce->features = CLOCK_EVT_FEAT_ONESHOT; |
196 | ce->rating = sirfsoc_clockevent.rating; | 191 | ce->rating = 200; |
197 | ce->set_mode = sirfsoc_timer_set_mode; | 192 | ce->set_mode = sirfsoc_timer_set_mode; |
198 | ce->set_next_event = sirfsoc_timer_set_next_event; | 193 | ce->set_next_event = sirfsoc_timer_set_next_event; |
199 | ce->shift = sirfsoc_clockevent.shift; | 194 | clockevents_calc_mult_shift(ce, CLOCK_TICK_RATE, 60); |
200 | ce->mult = sirfsoc_clockevent.mult; | 195 | ce->max_delta_ns = clockevent_delta2ns(-2, ce); |
201 | ce->max_delta_ns = sirfsoc_clockevent.max_delta_ns; | 196 | ce->min_delta_ns = clockevent_delta2ns(2, ce); |
202 | ce->min_delta_ns = sirfsoc_clockevent.min_delta_ns; | 197 | ce->cpumask = cpumask_of(cpu); |
203 | 198 | ||
204 | sirfsoc_timer1_irq.dev_id = ce; | 199 | action->dev_id = ce; |
205 | BUG_ON(setup_irq(ce->irq, &sirfsoc_timer1_irq)); | 200 | BUG_ON(setup_irq(ce->irq, action)); |
206 | irq_set_affinity(sirfsoc_timer1_irq.irq, cpumask_of(1)); | 201 | irq_set_affinity(action->irq, cpumask_of(cpu)); |
207 | 202 | ||
208 | clockevents_register_device(ce); | 203 | clockevents_register_device(ce); |
209 | return 0; | 204 | return 0; |
@@ -211,31 +206,48 @@ static int sirfsoc_local_timer_setup(struct clock_event_device *ce) | |||
211 | 206 | ||
212 | static void sirfsoc_local_timer_stop(struct clock_event_device *ce) | 207 | static void sirfsoc_local_timer_stop(struct clock_event_device *ce) |
213 | { | 208 | { |
209 | int cpu = smp_processor_id(); | ||
210 | |||
214 | sirfsoc_timer_count_disable(1); | 211 | sirfsoc_timer_count_disable(1); |
215 | 212 | ||
216 | remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq); | 213 | if (cpu == 0) |
214 | remove_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq); | ||
215 | else | ||
216 | remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq); | ||
217 | } | 217 | } |
218 | 218 | ||
219 | static struct local_timer_ops sirfsoc_local_timer_ops = { | 219 | static int sirfsoc_cpu_notify(struct notifier_block *self, |
220 | .setup = sirfsoc_local_timer_setup, | 220 | unsigned long action, void *hcpu) |
221 | .stop = sirfsoc_local_timer_stop, | 221 | { |
222 | /* | ||
223 | * Grab cpu pointer in each case to avoid spurious | ||
224 | * preemptible warnings | ||
225 | */ | ||
226 | switch (action & ~CPU_TASKS_FROZEN) { | ||
227 | case CPU_STARTING: | ||
228 | sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent)); | ||
229 | break; | ||
230 | case CPU_DYING: | ||
231 | sirfsoc_local_timer_stop(this_cpu_ptr(sirfsoc_clockevent)); | ||
232 | break; | ||
233 | } | ||
234 | |||
235 | return NOTIFY_OK; | ||
236 | } | ||
237 | |||
238 | static struct notifier_block sirfsoc_cpu_nb = { | ||
239 | .notifier_call = sirfsoc_cpu_notify, | ||
222 | }; | 240 | }; |
223 | #endif /* CONFIG_LOCAL_TIMERS */ | ||
224 | 241 | ||
225 | static void __init sirfsoc_clockevent_init(void) | 242 | static void __init sirfsoc_clockevent_init(void) |
226 | { | 243 | { |
227 | clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60); | 244 | sirfsoc_clockevent = alloc_percpu(struct clock_event_device); |
228 | 245 | BUG_ON(!sirfsoc_clockevent); | |
229 | sirfsoc_clockevent.max_delta_ns = | 246 | |
230 | clockevent_delta2ns(-2, &sirfsoc_clockevent); | 247 | BUG_ON(register_cpu_notifier(&sirfsoc_cpu_nb)); |
231 | sirfsoc_clockevent.min_delta_ns = | 248 | |
232 | clockevent_delta2ns(2, &sirfsoc_clockevent); | 249 | /* Immediately configure the timer on the boot CPU */ |
233 | 250 | sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent)); | |
234 | sirfsoc_clockevent.cpumask = cpumask_of(0); | ||
235 | clockevents_register_device(&sirfsoc_clockevent); | ||
236 | #ifdef CONFIG_LOCAL_TIMERS | ||
237 | local_timer_register(&sirfsoc_local_timer_ops); | ||
238 | #endif | ||
239 | } | 251 | } |
240 | 252 | ||
241 | /* initialize the kernel jiffy timer source */ | 253 | /* initialize the kernel jiffy timer source */ |
@@ -273,8 +285,6 @@ static void __init sirfsoc_marco_timer_init(void) | |||
273 | 285 | ||
274 | BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE)); | 286 | BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE)); |
275 | 287 | ||
276 | BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq)); | ||
277 | |||
278 | sirfsoc_clockevent_init(); | 288 | sirfsoc_clockevent_init(); |
279 | } | 289 | } |
280 | 290 | ||
@@ -288,11 +298,9 @@ static void __init sirfsoc_of_timer_init(struct device_node *np) | |||
288 | if (!sirfsoc_timer_irq.irq) | 298 | if (!sirfsoc_timer_irq.irq) |
289 | panic("No irq passed for timer0 via DT\n"); | 299 | panic("No irq passed for timer0 via DT\n"); |
290 | 300 | ||
291 | #ifdef CONFIG_LOCAL_TIMERS | ||
292 | sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1); | 301 | sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1); |
293 | if (!sirfsoc_timer1_irq.irq) | 302 | if (!sirfsoc_timer1_irq.irq) |
294 | panic("No irq passed for timer1 via DT\n"); | 303 | panic("No irq passed for timer1 via DT\n"); |
295 | #endif | ||
296 | 304 | ||
297 | sirfsoc_marco_timer_init(); | 305 | sirfsoc_marco_timer_init(); |
298 | } | 306 | } |