summaryrefslogtreecommitdiff
path: root/arch/mips/kernel/time.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2007-10-16 23:20:48 +0100
committerRalf Baechle <ralf@linux-mips.org>2007-10-17 18:28:47 +0100
commitb0d4056dd6f16eca63114d0c252b214449a13cca (patch)
tree50c55bdd330574fcdb718e4192d02b91f2aaa551 /arch/mips/kernel/time.c
parent60b0d65541b581955279221e060f8a0a221151b4 (diff)
downloadlinux-b0d4056dd6f16eca63114d0c252b214449a13cca.tar.gz
[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.c47
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";