diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2007-10-16 18:20:48 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-10-17 13:28:47 -0400 |
commit | b0d4056dd6f16eca63114d0c252b214449a13cca (patch) | |
tree | 50c55bdd330574fcdb718e4192d02b91f2aaa551 /arch/mips/kernel/time.c | |
parent | 60b0d65541b581955279221e060f8a0a221151b4 (diff) |
[MIPS] Probe for usability of cp0 compare interrupt.
Some processors offer the option of using the interrupt on which
normally the count / compare interrupt would be signaled as a normal
interupt pin. Previously this required some ugly hackery for each
system which is much easier done by a quick and simple probe.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/time.c')
-rw-r--r-- | arch/mips/kernel/time.c | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 05b365167a0..e4b5e647b14 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c | |||
@@ -391,6 +391,50 @@ static void mips_event_handler(struct clock_event_device *dev) | |||
391 | { | 391 | { |
392 | } | 392 | } |
393 | 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 | |||
394 | void __cpuinit mips_clockevent_init(void) | 438 | void __cpuinit mips_clockevent_init(void) |
395 | { | 439 | { |
396 | uint64_t mips_freq = mips_hpt_frequency; | 440 | uint64_t mips_freq = mips_hpt_frequency; |
@@ -412,6 +456,9 @@ void __cpuinit mips_clockevent_init(void) | |||
412 | return; | 456 | return; |
413 | #endif | 457 | #endif |
414 | 458 | ||
459 | if (!c0_compare_int_usable()) | ||
460 | return; | ||
461 | |||
415 | cd = &per_cpu(mips_clockevent_device, cpu); | 462 | cd = &per_cpu(mips_clockevent_device, cpu); |
416 | 463 | ||
417 | cd->name = "MIPS"; | 464 | cd->name = "MIPS"; |