MIPS: cevt-r4k: Cleanup c0_compare_interrupt.
[linux-drm-fsl-dcu.git] / arch / mips / kernel / cevt-r4k.c
index 82bd2b278a243602dbf4c7ec15f8366af1ecf059..d70c4d893219ebe2bff50341025c5c3fb4f750ca 100644 (file)
@@ -37,6 +37,24 @@ 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_r6;
@@ -50,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",
 };