diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2007-10-16 23:20:48 +0100 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-10-17 18:28:47 +0100 |
commit | b0d4056dd6f16eca63114d0c252b214449a13cca (patch) | |
tree | 50c55bdd330574fcdb718e4192d02b91f2aaa551 /arch | |
parent | 60b0d65541b581955279221e060f8a0a221151b4 (diff) | |
download | blackbird-op-linux-b0d4056dd6f16eca63114d0c252b214449a13cca.tar.gz blackbird-op-linux-b0d4056dd6f16eca63114d0c252b214449a13cca.zip |
[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')
-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 05b365167a09..e4b5e647b142 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) { } +/* + * FIXME: This doesn't hold for the relocated E9000 compare interrupt. + */ +static int c0_compare_int_pending(void) +{ + return (read_c0_cause() >> cp0_compare_irq) & 0x100; +} + +static int c0_compare_int_usable(void) +{ + const unsigned int delta = 0x300000; + unsigned int cnt; + + /* + * IP7 already pending? Try to clear it by acking the timer. + */ + if (c0_compare_int_pending()) { + write_c0_compare(read_c0_compare()); + irq_disable_hazard(); + if (c0_compare_int_pending()) + return 0; + } + + cnt = read_c0_count(); + cnt += delta; + write_c0_compare(cnt); + + while ((long)(read_c0_count() - cnt) <= 0) + ; /* Wait for expiry */ + + if (!c0_compare_int_pending()) + return 0; + + write_c0_compare(read_c0_compare()); + irq_disable_hazard(); + if (c0_compare_int_pending()) + return 0; + + /* + * Feels like a real count / compare timer. + */ + return 1; +} + void __cpuinit mips_clockevent_init(void) { uint64_t mips_freq = mips_hpt_frequency; @@ -412,6 +456,9 @@ void __cpuinit mips_clockevent_init(void) return; #endif + if (!c0_compare_int_usable()) + return; + cd = &per_cpu(mips_clockevent_device, cpu); cd->name = "MIPS"; |