Subject: [PATCH 3/4] [MIPS] Allow platform to override default timer and performance counter interrupts

From: Thomas Koeller <[email-masked]>
Date: Tue, 18 Dec 2007 01:26:50 +0100

While there was a platform hook for setting the compare timer interrupt
before, it was implemented in a somewhat arkward way, and no such hook
existed for the performance counter interrupt. This change aims at a
cleaner solution, by using the platform-supplied values right from the
beginning instead of setting up the standard irq first, and then
ignoring it.

Signed-off-by: Thomas Koeller <[email-masked]>

diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
index 24a2d90..3b1407e 100644
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -9,6 +9,7 @@
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
 #include <linux/percpu.h>
+#include <linux/kernel.h>
 
 #include <asm/smtc_ipi.h>
 #include <asm/time.h>
@@ -76,8 +77,8 @@ static irqreturn_t c0_compare_interrupt(int irq, void 
*dev_id)
 {
 	const int r2 = cpu_has_mips_r2;
 	struct clock_event_device *cd;
-	int cpu = smp_processor_id();
-
+	const int cpu = smp_processor_id();
+	
 	/*
 	 * Suckage alert:
 	 * Before R2 of the architecture there was no way to see if a
@@ -169,9 +170,6 @@ 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;
@@ -183,7 +181,8 @@ static int c0_compare_int_usable(void)
 	unsigned int cnt;
 
 	/*
-	 * IP7 already pending?  Try to clear it by acking the timer.
+	 * Compare interrupt already pending?
+	 * Try to clear it by acking the timer.
 	 */
 	if (c0_compare_int_pending()) {
 		write_c0_compare(read_c0_count());
@@ -221,8 +220,8 @@ static int c0_compare_int_usable(void)
 
 int __cpuinit mips_clockevent_init(void)
 {
-	uint64_t mips_freq = mips_hpt_frequency;
-	unsigned int cpu = smp_processor_id();
+	const uint64_t mips_freq = mips_hpt_frequency;
+	const unsigned int cpu = smp_processor_id();
 	struct clock_event_device *cd;
 	unsigned int irq;
 
@@ -240,17 +239,12 @@ int __cpuinit mips_clockevent_init(void)
 		return 0;
 #endif
 
-	if (!c0_compare_int_usable())
+	if (!c0_compare_int_usable()) {
+		pr_crit("MIPS compare interrupt not working - no timer clock\n");
 		return -ENXIO;
+	}
 
-	/*
-	 * With vectored interrupts things are getting platform specific.
-	 * get_c0_compare_int is a hook to allow a platform to return the
-	 * interrupt number of it's liking.
-	 */
 	irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
-	if (get_c0_compare_int)
-		irq = get_c0_compare_int();
 
 	cd = &per_cpu(mips_clockevent_device, cpu);
 
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index fcae667..268247d 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -1281,6 +1281,20 @@ extern void flush_tlb_handlers(void);
  */
 int cp0_compare_irq;
 
+unsigned int __init __weak
+get_c0_compare_int(void)
+{
+	return cpu_has_mips_r2 ?
+		(read_c0_intctl() >> 29) & 7 : CP0_LEGACY_COMPARE_IRQ;
+}
+
+unsigned int __init __weak
+get_c0_perfcount_int(void)
+{
+	return cpu_has_mips_r2 ?
+		(read_c0_intctl() >> 26) & 7 : -1;
+}
+
 /*
  * Performance counter IRQ or -1 if shared with timer
  */
@@ -1352,21 +1366,11 @@ void __init per_cpu_trap_init(void)
 			set_c0_cause(CAUSEF_IV);
 	}
 
-	/*
-	 * Before R2 both interrupt numbers were fixed to 7, so on R2 only:
-	 *
-	 *  o read IntCtl.IPTI to determine the timer interrupt
-	 *  o read IntCtl.IPPCI to determine the performance counter interrupt
-	 */
-	if (cpu_has_mips_r2) {
-		cp0_compare_irq = (read_c0_intctl() >> 29) & 7;
-		cp0_perfcount_irq = (read_c0_intctl() >> 26) & 7;
-		if (cp0_perfcount_irq == cp0_compare_irq)
-			cp0_perfcount_irq = -1;
-	} else {
-		cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ;
+	/* Set up timer & performance counter interrupts */
+	cp0_compare_irq = get_c0_compare_int();
+	cp0_perfcount_irq = get_c0_perfcount_int();
+	if (cp0_perfcount_irq == cp0_compare_irq)
 		cp0_perfcount_irq = -1;
-	}
 
 #ifdef CONFIG_MIPS_MT_SMTC
 	}
diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h
index 7717934..be0d157 100644
--- a/include/asm-mips/time.h
+++ b/include/asm-mips/time.h
@@ -59,7 +59,8 @@ extern int (*perf_irq)(void);
  */
 #ifdef CONFIG_CEVT_R4K
 extern int mips_clockevent_init(void);
-extern unsigned int __weak get_c0_compare_int(void);
+extern unsigned int get_c0_compare_int(void);
+extern unsigned int get_c0_perfcount_int(void);
 #else
 static inline int mips_clockevent_init(void)
 {
-- 
1.5.3.6