aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/time.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2007-10-18 12:48:11 -0400
committerRalf Baechle <ralf@linux-mips.org>2007-10-18 13:11:47 -0400
commit42f77542f4a1c104bb6fbba2e18e04e84415a96b (patch)
tree79b58e2d3e93abacbdd535684e2627231d2e0ffc /arch/mips/kernel/time.c
parent2cfa7660dbf94a61b9d43edaa84be454f9dc25fc (diff)
[MIPS] time: Move R4000 clockevent device code to separate configurable file
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/time.c')
-rw-r--r--arch/mips/kernel/time.c241
1 files changed, 0 insertions, 241 deletions
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index abadb8cb77c0..ea7cfe766a8e 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -81,14 +81,6 @@ static cycle_t null_hpt_read(void)
81} 81}
82 82
83/* 83/*
84 * Timer ack for an R4k-compatible timer of a known frequency.
85 */
86static void c0_timer_ack(void)
87{
88 write_c0_compare(read_c0_compare());
89}
90
91/*
92 * High precision timer functions for a R4k-compatible timer. 84 * High precision timer functions for a R4k-compatible timer.
93 */ 85 */
94static cycle_t c0_hpt_read(void) 86static cycle_t c0_hpt_read(void)
@@ -126,35 +118,6 @@ int (*perf_irq)(void) = null_perf_irq;
126EXPORT_SYMBOL(perf_irq); 118EXPORT_SYMBOL(perf_irq);
127 119
128/* 120/*
129 * Timer interrupt
130 */
131int cp0_compare_irq;
132
133/*
134 * Performance counter IRQ or -1 if shared with timer
135 */
136int cp0_perfcount_irq;
137EXPORT_SYMBOL_GPL(cp0_perfcount_irq);
138
139/*
140 * Possibly handle a performance counter interrupt.
141 * Return true if the timer interrupt should not be checked
142 */
143static inline int handle_perf_irq(int r2)
144{
145 /*
146 * The performance counter overflow interrupt may be shared with the
147 * timer interrupt (cp0_perfcount_irq < 0). If it is and a
148 * performance counter has overflowed (perf_irq() == IRQ_HANDLED)
149 * and we can't reliably determine if a counter interrupt has also
150 * happened (!r2) then don't check for a timer interrupt.
151 */
152 return (cp0_perfcount_irq < 0) &&
153 perf_irq() == IRQ_HANDLED &&
154 !r2;
155}
156
157/*
158 * time_init() - it does the following things. 121 * time_init() - it does the following things.
159 * 122 *
160 * 1) plat_time_init() - 123 * 1) plat_time_init() -
@@ -219,84 +182,6 @@ struct clocksource clocksource_mips = {
219 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 182 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
220}; 183};
221 184
222static int mips_next_event(unsigned long delta,
223 struct clock_event_device *evt)
224{
225 unsigned int cnt;
226 int res;
227
228#ifdef CONFIG_MIPS_MT_SMTC
229 {
230 unsigned long flags, vpflags;
231 local_irq_save(flags);
232 vpflags = dvpe();
233#endif
234 cnt = read_c0_count();
235 cnt += delta;
236 write_c0_compare(cnt);
237 res = ((long)(read_c0_count() - cnt ) > 0) ? -ETIME : 0;
238#ifdef CONFIG_MIPS_MT_SMTC
239 evpe(vpflags);
240 local_irq_restore(flags);
241 }
242#endif
243 return res;
244}
245
246static void mips_set_mode(enum clock_event_mode mode,
247 struct clock_event_device *evt)
248{
249 /* Nothing to do ... */
250}
251
252static DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device);
253static int cp0_timer_irq_installed;
254
255static irqreturn_t timer_interrupt(int irq, void *dev_id)
256{
257 const int r2 = cpu_has_mips_r2;
258 struct clock_event_device *cd;
259 int cpu = smp_processor_id();
260
261 /*
262 * Suckage alert:
263 * Before R2 of the architecture there was no way to see if a
264 * performance counter interrupt was pending, so we have to run
265 * the performance counter interrupt handler anyway.
266 */
267 if (handle_perf_irq(r2))
268 goto out;
269
270 /*
271 * The same applies to performance counter interrupts. But with the
272 * above we now know that the reason we got here must be a timer
273 * interrupt. Being the paranoiacs we are we check anyway.
274 */
275 if (!r2 || (read_c0_cause() & (1 << 30))) {
276 c0_timer_ack();
277#ifdef CONFIG_MIPS_MT_SMTC
278 if (cpu_data[cpu].vpe_id)
279 goto out;
280 cpu = 0;
281#endif
282 cd = &per_cpu(mips_clockevent_device, cpu);
283 cd->event_handler(cd);
284 }
285
286out:
287 return IRQ_HANDLED;
288}
289
290static struct irqaction timer_irqaction = {
291 .handler = timer_interrupt,
292#ifdef CONFIG_MIPS_MT_SMTC
293 .flags = IRQF_DISABLED,
294#else
295 .flags = IRQF_DISABLED | IRQF_PERCPU,
296#endif
297 .name = "timer",
298};
299
300static void __init init_mips_clocksource(void) 185static void __init init_mips_clocksource(void)
301{ 186{
302 u64 temp; 187 u64 temp;
@@ -336,8 +221,6 @@ static void smtc_set_mode(enum clock_event_mode mode,
336{ 221{
337} 222}
338 223
339int dummycnt[NR_CPUS];
340
341static void mips_broadcast(cpumask_t mask) 224static void mips_broadcast(cpumask_t mask)
342{ 225{
343 unsigned int cpu; 226 unsigned int cpu;
@@ -378,113 +261,6 @@ static void setup_smtc_dummy_clockevent_device(void)
378} 261}
379#endif 262#endif
380 263
381static void mips_event_handler(struct clock_event_device *dev)
382{
383}
384
385/*
386 * FIXME: This doesn't hold for the relocated E9000 compare interrupt.
387 */
388static int c0_compare_int_pending(void)
389{
390 return (read_c0_cause() >> cp0_compare_irq) & 0x100;
391}
392
393static int c0_compare_int_usable(void)
394{
395 const unsigned int delta = 0x300000;
396 unsigned int cnt;
397
398 /*
399 * IP7 already pending? Try to clear it by acking the timer.
400 */
401 if (c0_compare_int_pending()) {
402 write_c0_compare(read_c0_compare());
403 irq_disable_hazard();
404 if (c0_compare_int_pending())
405 return 0;
406 }
407
408 cnt = read_c0_count();
409 cnt += delta;
410 write_c0_compare(cnt);
411
412 while ((long)(read_c0_count() - cnt) <= 0)
413 ; /* Wait for expiry */
414
415 if (!c0_compare_int_pending())
416 return 0;
417
418 write_c0_compare(read_c0_compare());
419 irq_disable_hazard();
420 if (c0_compare_int_pending())
421 return 0;
422
423 /*
424 * Feels like a real count / compare timer.
425 */
426 return 1;
427}
428
429void __cpuinit mips_clockevent_init(void)
430{
431 uint64_t mips_freq = mips_hpt_frequency;
432 unsigned int cpu = smp_processor_id();
433 struct clock_event_device *cd;
434 unsigned int irq = MIPS_CPU_IRQ_BASE + 7;
435
436 if (!cpu_has_counter)
437 return;
438
439#ifdef CONFIG_MIPS_MT_SMTC
440 setup_smtc_dummy_clockevent_device();
441
442 /*
443 * On SMTC we only register VPE0's compare interrupt as clockevent
444 * device.
445 */
446 if (cpu)
447 return;
448#endif
449
450 if (!c0_compare_int_usable())
451 return;
452
453 cd = &per_cpu(mips_clockevent_device, cpu);
454
455 cd->name = "MIPS";
456 cd->features = CLOCK_EVT_FEAT_ONESHOT;
457
458 /* Calculate the min / max delta */
459 cd->mult = div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32);
460 cd->shift = 32;
461 cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
462 cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
463
464 cd->rating = 300;
465 cd->irq = irq;
466#ifdef CONFIG_MIPS_MT_SMTC
467 cd->cpumask = CPU_MASK_ALL;
468#else
469 cd->cpumask = cpumask_of_cpu(cpu);
470#endif
471 cd->set_next_event = mips_next_event;
472 cd->set_mode = mips_set_mode;
473 cd->event_handler = mips_event_handler;
474
475 clockevents_register_device(cd);
476
477 if (!cp0_timer_irq_installed) {
478#ifdef CONFIG_MIPS_MT_SMTC
479#define CPUCTR_IMASKBIT (0x100 << cp0_compare_irq)
480 setup_irq_smtc(irq, &timer_irqaction, CPUCTR_IMASKBIT);
481#else
482 setup_irq(irq, &timer_irqaction);
483#endif /* CONFIG_MIPS_MT_SMTC */
484 cp0_timer_irq_installed = 1;
485 }
486}
487
488void __init time_init(void) 264void __init time_init(void)
489{ 265{
490 plat_time_init(); 266 plat_time_init();
@@ -511,25 +287,8 @@ void __init time_init(void)
511 printk("Using %u.%03u MHz high precision timer.\n", 287 printk("Using %u.%03u MHz high precision timer.\n",
512 ((mips_hpt_frequency + 500) / 1000) / 1000, 288 ((mips_hpt_frequency + 500) / 1000) / 1000,
513 ((mips_hpt_frequency + 500) / 1000) % 1000); 289 ((mips_hpt_frequency + 500) / 1000) % 1000);
514
515#ifdef CONFIG_IRQ_CPU
516 setup_irq(MIPS_CPU_IRQ_BASE + 7, &timer_irqaction);
517#endif
518 } 290 }
519 291
520 /*
521 * Call board specific timer interrupt setup.
522 *
523 * this pointer must be setup in machine setup routine.
524 *
525 * Even if a machine chooses to use a low-level timer interrupt,
526 * it still needs to setup the timer_irqaction.
527 * In that case, it might be better to set timer_irqaction.handler
528 * to be NULL function so that we are sure the high-level code
529 * is not invoked accidentally.
530 */
531 plat_timer_setup(&timer_irqaction);
532
533 init_mips_clocksource(); 292 init_mips_clocksource();
534 mips_clockevent_init(); 293 mips_clockevent_init();
535} 294}