diff options
Diffstat (limited to 'arch/mips/kernel/time.c')
-rw-r--r-- | arch/mips/kernel/time.c | 262 |
1 files changed, 0 insertions, 262 deletions
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index e4b5e647b142..ea7cfe766a8e 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c | |||
@@ -72,14 +72,6 @@ int update_persistent_clock(struct timespec now) | |||
72 | return rtc_mips_set_mmss(now.tv_sec); | 72 | return rtc_mips_set_mmss(now.tv_sec); |
73 | } | 73 | } |
74 | 74 | ||
75 | /* how many counter cycles in a jiffy */ | ||
76 | static unsigned long cycles_per_jiffy __read_mostly; | ||
77 | |||
78 | /* | ||
79 | * Null timer ack for systems not needing one (e.g. i8254). | ||
80 | */ | ||
81 | static void null_timer_ack(void) { /* nothing */ } | ||
82 | |||
83 | /* | 75 | /* |
84 | * Null high precision timer functions for systems lacking one. | 76 | * Null high precision timer functions for systems lacking one. |
85 | */ | 77 | */ |
@@ -89,14 +81,6 @@ static cycle_t null_hpt_read(void) | |||
89 | } | 81 | } |
90 | 82 | ||
91 | /* | 83 | /* |
92 | * Timer ack for an R4k-compatible timer of a known frequency. | ||
93 | */ | ||
94 | static void c0_timer_ack(void) | ||
95 | { | ||
96 | write_c0_compare(read_c0_compare()); | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * High precision timer functions for a R4k-compatible timer. | 84 | * High precision timer functions for a R4k-compatible timer. |
101 | */ | 85 | */ |
102 | static cycle_t c0_hpt_read(void) | 86 | static cycle_t c0_hpt_read(void) |
@@ -105,7 +89,6 @@ static cycle_t c0_hpt_read(void) | |||
105 | } | 89 | } |
106 | 90 | ||
107 | int (*mips_timer_state)(void); | 91 | int (*mips_timer_state)(void); |
108 | void (*mips_timer_ack)(void); | ||
109 | 92 | ||
110 | /* | 93 | /* |
111 | * local_timer_interrupt() does profiling and process accounting | 94 | * local_timer_interrupt() does profiling and process accounting |
@@ -135,35 +118,6 @@ int (*perf_irq)(void) = null_perf_irq; | |||
135 | EXPORT_SYMBOL(perf_irq); | 118 | EXPORT_SYMBOL(perf_irq); |
136 | 119 | ||
137 | /* | 120 | /* |
138 | * Timer interrupt | ||
139 | */ | ||
140 | int cp0_compare_irq; | ||
141 | |||
142 | /* | ||
143 | * Performance counter IRQ or -1 if shared with timer | ||
144 | */ | ||
145 | int cp0_perfcount_irq; | ||
146 | EXPORT_SYMBOL_GPL(cp0_perfcount_irq); | ||
147 | |||
148 | /* | ||
149 | * Possibly handle a performance counter interrupt. | ||
150 | * Return true if the timer interrupt should not be checked | ||
151 | */ | ||
152 | static inline int handle_perf_irq(int r2) | ||
153 | { | ||
154 | /* | ||
155 | * The performance counter overflow interrupt may be shared with the | ||
156 | * timer interrupt (cp0_perfcount_irq < 0). If it is and a | ||
157 | * performance counter has overflowed (perf_irq() == IRQ_HANDLED) | ||
158 | * and we can't reliably determine if a counter interrupt has also | ||
159 | * happened (!r2) then don't check for a timer interrupt. | ||
160 | */ | ||
161 | return (cp0_perfcount_irq < 0) && | ||
162 | perf_irq() == IRQ_HANDLED && | ||
163 | !r2; | ||
164 | } | ||
165 | |||
166 | /* | ||
167 | * time_init() - it does the following things. | 121 | * time_init() - it does the following things. |
168 | * | 122 | * |
169 | * 1) plat_time_init() - | 123 | * 1) plat_time_init() - |
@@ -228,84 +182,6 @@ struct clocksource clocksource_mips = { | |||
228 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 182 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
229 | }; | 183 | }; |
230 | 184 | ||
231 | static int mips_next_event(unsigned long delta, | ||
232 | struct clock_event_device *evt) | ||
233 | { | ||
234 | unsigned int cnt; | ||
235 | int res; | ||
236 | |||
237 | #ifdef CONFIG_MIPS_MT_SMTC | ||
238 | { | ||
239 | unsigned long flags, vpflags; | ||
240 | local_irq_save(flags); | ||
241 | vpflags = dvpe(); | ||
242 | #endif | ||
243 | cnt = read_c0_count(); | ||
244 | cnt += delta; | ||
245 | write_c0_compare(cnt); | ||
246 | res = ((long)(read_c0_count() - cnt ) > 0) ? -ETIME : 0; | ||
247 | #ifdef CONFIG_MIPS_MT_SMTC | ||
248 | evpe(vpflags); | ||
249 | local_irq_restore(flags); | ||
250 | } | ||
251 | #endif | ||
252 | return res; | ||
253 | } | ||
254 | |||
255 | static void mips_set_mode(enum clock_event_mode mode, | ||
256 | struct clock_event_device *evt) | ||
257 | { | ||
258 | /* Nothing to do ... */ | ||
259 | } | ||
260 | |||
261 | static DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); | ||
262 | static int cp0_timer_irq_installed; | ||
263 | |||
264 | static irqreturn_t timer_interrupt(int irq, void *dev_id) | ||
265 | { | ||
266 | const int r2 = cpu_has_mips_r2; | ||
267 | struct clock_event_device *cd; | ||
268 | int cpu = smp_processor_id(); | ||
269 | |||
270 | /* | ||
271 | * Suckage alert: | ||
272 | * Before R2 of the architecture there was no way to see if a | ||
273 | * performance counter interrupt was pending, so we have to run | ||
274 | * the performance counter interrupt handler anyway. | ||
275 | */ | ||
276 | if (handle_perf_irq(r2)) | ||
277 | goto out; | ||
278 | |||
279 | /* | ||
280 | * The same applies to performance counter interrupts. But with the | ||
281 | * above we now know that the reason we got here must be a timer | ||
282 | * interrupt. Being the paranoiacs we are we check anyway. | ||
283 | */ | ||
284 | if (!r2 || (read_c0_cause() & (1 << 30))) { | ||
285 | c0_timer_ack(); | ||
286 | #ifdef CONFIG_MIPS_MT_SMTC | ||
287 | if (cpu_data[cpu].vpe_id) | ||
288 | goto out; | ||
289 | cpu = 0; | ||
290 | #endif | ||
291 | cd = &per_cpu(mips_clockevent_device, cpu); | ||
292 | cd->event_handler(cd); | ||
293 | } | ||
294 | |||
295 | out: | ||
296 | return IRQ_HANDLED; | ||
297 | } | ||
298 | |||
299 | static struct irqaction timer_irqaction = { | ||
300 | .handler = timer_interrupt, | ||
301 | #ifdef CONFIG_MIPS_MT_SMTC | ||
302 | .flags = IRQF_DISABLED, | ||
303 | #else | ||
304 | .flags = IRQF_DISABLED | IRQF_PERCPU, | ||
305 | #endif | ||
306 | .name = "timer", | ||
307 | }; | ||
308 | |||
309 | static void __init init_mips_clocksource(void) | 185 | static void __init init_mips_clocksource(void) |
310 | { | 186 | { |
311 | u64 temp; | 187 | u64 temp; |
@@ -345,8 +221,6 @@ static void smtc_set_mode(enum clock_event_mode mode, | |||
345 | { | 221 | { |
346 | } | 222 | } |
347 | 223 | ||
348 | int dummycnt[NR_CPUS]; | ||
349 | |||
350 | static void mips_broadcast(cpumask_t mask) | 224 | static void mips_broadcast(cpumask_t mask) |
351 | { | 225 | { |
352 | unsigned int cpu; | 226 | unsigned int cpu; |
@@ -387,113 +261,6 @@ static void setup_smtc_dummy_clockevent_device(void) | |||
387 | } | 261 | } |
388 | #endif | 262 | #endif |
389 | 263 | ||
390 | static void mips_event_handler(struct clock_event_device *dev) | ||
391 | { | ||
392 | } | ||
393 | |||
394 | /* | ||
395 | * FIXME: This doesn't hold for the relocated E9000 compare interrupt. | ||
396 | */ | ||
397 | static int c0_compare_int_pending(void) | ||
398 | { | ||
399 | return (read_c0_cause() >> cp0_compare_irq) & 0x100; | ||
400 | } | ||
401 | |||
402 | static int c0_compare_int_usable(void) | ||
403 | { | ||
404 | const unsigned int delta = 0x300000; | ||
405 | unsigned int cnt; | ||
406 | |||
407 | /* | ||
408 | * IP7 already pending? Try to clear it by acking the timer. | ||
409 | */ | ||
410 | if (c0_compare_int_pending()) { | ||
411 | write_c0_compare(read_c0_compare()); | ||
412 | irq_disable_hazard(); | ||
413 | if (c0_compare_int_pending()) | ||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | cnt = read_c0_count(); | ||
418 | cnt += delta; | ||
419 | write_c0_compare(cnt); | ||
420 | |||
421 | while ((long)(read_c0_count() - cnt) <= 0) | ||
422 | ; /* Wait for expiry */ | ||
423 | |||
424 | if (!c0_compare_int_pending()) | ||
425 | return 0; | ||
426 | |||
427 | write_c0_compare(read_c0_compare()); | ||
428 | irq_disable_hazard(); | ||
429 | if (c0_compare_int_pending()) | ||
430 | return 0; | ||
431 | |||
432 | /* | ||
433 | * Feels like a real count / compare timer. | ||
434 | */ | ||
435 | return 1; | ||
436 | } | ||
437 | |||
438 | void __cpuinit mips_clockevent_init(void) | ||
439 | { | ||
440 | uint64_t mips_freq = mips_hpt_frequency; | ||
441 | unsigned int cpu = smp_processor_id(); | ||
442 | struct clock_event_device *cd; | ||
443 | unsigned int irq = MIPS_CPU_IRQ_BASE + 7; | ||
444 | |||
445 | if (!cpu_has_counter) | ||
446 | return; | ||
447 | |||
448 | #ifdef CONFIG_MIPS_MT_SMTC | ||
449 | setup_smtc_dummy_clockevent_device(); | ||
450 | |||
451 | /* | ||
452 | * On SMTC we only register VPE0's compare interrupt as clockevent | ||
453 | * device. | ||
454 | */ | ||
455 | if (cpu) | ||
456 | return; | ||
457 | #endif | ||
458 | |||
459 | if (!c0_compare_int_usable()) | ||
460 | return; | ||
461 | |||
462 | cd = &per_cpu(mips_clockevent_device, cpu); | ||
463 | |||
464 | cd->name = "MIPS"; | ||
465 | cd->features = CLOCK_EVT_FEAT_ONESHOT; | ||
466 | |||
467 | /* Calculate the min / max delta */ | ||
468 | cd->mult = div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32); | ||
469 | cd->shift = 32; | ||
470 | cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); | ||
471 | cd->min_delta_ns = clockevent_delta2ns(0x300, cd); | ||
472 | |||
473 | cd->rating = 300; | ||
474 | cd->irq = irq; | ||
475 | #ifdef CONFIG_MIPS_MT_SMTC | ||
476 | cd->cpumask = CPU_MASK_ALL; | ||
477 | #else | ||
478 | cd->cpumask = cpumask_of_cpu(cpu); | ||
479 | #endif | ||
480 | cd->set_next_event = mips_next_event; | ||
481 | cd->set_mode = mips_set_mode; | ||
482 | cd->event_handler = mips_event_handler; | ||
483 | |||
484 | clockevents_register_device(cd); | ||
485 | |||
486 | if (!cp0_timer_irq_installed) { | ||
487 | #ifdef CONFIG_MIPS_MT_SMTC | ||
488 | #define CPUCTR_IMASKBIT (0x100 << cp0_compare_irq) | ||
489 | setup_irq_smtc(irq, &timer_irqaction, CPUCTR_IMASKBIT); | ||
490 | #else | ||
491 | setup_irq(irq, &timer_irqaction); | ||
492 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
493 | cp0_timer_irq_installed = 1; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | void __init time_init(void) | 264 | void __init time_init(void) |
498 | { | 265 | { |
499 | plat_time_init(); | 266 | plat_time_init(); |
@@ -512,14 +279,6 @@ void __init time_init(void) | |||
512 | if (!clocksource_mips.read) { | 279 | if (!clocksource_mips.read) { |
513 | /* No external high precision timer -- use R4k. */ | 280 | /* No external high precision timer -- use R4k. */ |
514 | clocksource_mips.read = c0_hpt_read; | 281 | clocksource_mips.read = c0_hpt_read; |
515 | |||
516 | if (!mips_timer_state) { | ||
517 | /* No external timer interrupt -- use R4k. */ | ||
518 | mips_timer_ack = c0_timer_ack; | ||
519 | /* Calculate cache parameters. */ | ||
520 | cycles_per_jiffy = | ||
521 | (mips_hpt_frequency + HZ / 2) / HZ; | ||
522 | } | ||
523 | } | 282 | } |
524 | if (!mips_hpt_frequency) | 283 | if (!mips_hpt_frequency) |
525 | mips_hpt_frequency = calibrate_hpt(); | 284 | mips_hpt_frequency = calibrate_hpt(); |
@@ -528,29 +287,8 @@ void __init time_init(void) | |||
528 | printk("Using %u.%03u MHz high precision timer.\n", | 287 | printk("Using %u.%03u MHz high precision timer.\n", |
529 | ((mips_hpt_frequency + 500) / 1000) / 1000, | 288 | ((mips_hpt_frequency + 500) / 1000) / 1000, |
530 | ((mips_hpt_frequency + 500) / 1000) % 1000); | 289 | ((mips_hpt_frequency + 500) / 1000) % 1000); |
531 | |||
532 | #ifdef CONFIG_IRQ_CPU | ||
533 | setup_irq(MIPS_CPU_IRQ_BASE + 7, &timer_irqaction); | ||
534 | #endif | ||
535 | } | 290 | } |
536 | 291 | ||
537 | if (!mips_timer_ack) | ||
538 | /* No timer interrupt ack (e.g. i8254). */ | ||
539 | mips_timer_ack = null_timer_ack; | ||
540 | |||
541 | /* | ||
542 | * Call board specific timer interrupt setup. | ||
543 | * | ||
544 | * this pointer must be setup in machine setup routine. | ||
545 | * | ||
546 | * Even if a machine chooses to use a low-level timer interrupt, | ||
547 | * it still needs to setup the timer_irqaction. | ||
548 | * In that case, it might be better to set timer_irqaction.handler | ||
549 | * to be NULL function so that we are sure the high-level code | ||
550 | * is not invoked accidentally. | ||
551 | */ | ||
552 | plat_timer_setup(&timer_irqaction); | ||
553 | |||
554 | init_mips_clocksource(); | 292 | init_mips_clocksource(); |
555 | mips_clockevent_init(); | 293 | mips_clockevent_init(); |
556 | } | 294 | } |