MIPS: cevt-r4k: Cleanup c0_compare_interrupt.
[linux-drm-fsl-dcu.git] / arch / mips / kernel / cevt-r4k.c
index 6acaad0480af366830c77be996e9dba57fd8ad95..d70c4d893219ebe2bff50341025c5c3fb4f750ca 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/percpu.h>
 #include <linux/smp.h>
 #include <linux/irq.h>
-#include <linux/irqchip/mips-gic.h>
 
 #include <asm/time.h>
 #include <asm/cevt-r4k.h>
@@ -38,9 +37,27 @@ void mips_set_clock_mode(enum clock_event_mode mode,
 DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device);
 int cp0_timer_irq_installed;
 
+/*
+ * Possibly handle a performance counter interrupt.
+ * Return true if the timer interrupt should not be checked
+ */
+static inline int handle_perf_irq(int r2)
+{
+       /*
+        * The performance counter overflow interrupt may be shared with the
+        * timer interrupt (cp0_perfcount_irq < 0). If it is and a
+        * performance counter has overflowed (perf_irq() == IRQ_HANDLED)
+        * and we can't reliably determine if a counter interrupt has also
+        * happened (!r2) then don't check for a timer interrupt.
+        */
+       return (cp0_perfcount_irq < 0) &&
+               perf_irq() == IRQ_HANDLED &&
+               !r2;
+}
+
 irqreturn_t c0_compare_interrupt(int irq, void *dev_id)
 {
-       const int r2 = cpu_has_mips_r2;
+       const int r2 = cpu_has_mips_r2_r6;
        struct clock_event_device *cd;
        int cpu = smp_processor_id();
 
@@ -51,27 +68,32 @@ irqreturn_t c0_compare_interrupt(int irq, void *dev_id)
         * the performance counter interrupt handler anyway.
         */
        if (handle_perf_irq(r2))
-               goto out;
+               return IRQ_HANDLED;
 
        /*
         * The same applies to performance counter interrupts.  But with the
         * above we now know that the reason we got here must be a timer
         * interrupt.  Being the paranoiacs we are we check anyway.
         */
-       if (!r2 || (read_c0_cause() & (1 << 30))) {
+       if (!r2 || (read_c0_cause() & CAUSEF_TI)) {
                /* Clear Count/Compare Interrupt */
                write_c0_compare(read_c0_compare());
                cd = &per_cpu(mips_clockevent_device, cpu);
                cd->event_handler(cd);
+
+               return IRQ_HANDLED;
        }
 
-out:
-       return IRQ_HANDLED;
+       return IRQ_NONE;
 }
 
 struct irqaction c0_compare_irqaction = {
        .handler = c0_compare_interrupt,
-       .flags = IRQF_PERCPU | IRQF_TIMER,
+       /*
+        * IRQF_SHARED: The timer interrupt may be shared with other interrupts
+        * such as perf counter and FDC interrupts.
+        */
+       .flags = IRQF_PERCPU | IRQF_TIMER | IRQF_SHARED,
        .name = "timer",
 };
 
@@ -85,10 +107,7 @@ void mips_event_handler(struct clock_event_device *dev)
  */
 static int c0_compare_int_pending(void)
 {
-#ifdef CONFIG_MIPS_GIC
-       if (gic_present)
-               return gic_get_timer_pending();
-#endif
+       /* When cpu_has_mips_r2, this checks Cause.TI instead of Cause.IP7 */
        return (read_c0_cause() >> cp0_compare_irq_shift) & (1ul << CAUSEB_IP);
 }