Sfoglia il codice sorgente

[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>
Ralf Baechle 17 anni fa
parent
commit
b0d4056dd6
1 ha cambiato i file con 47 aggiunte e 0 eliminazioni
  1. 47 0
      arch/mips/kernel/time.c

+ 47 - 0
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";