If the interrupt and the timeout happen roughly at the same
time, we can get into a situation where the timer function
is run while the interrupt has already been processed. In
this case, the timer function might end up doing an add_timer
on an already pending timer, causing a BUG_ON() to trigger.

Instead, just skip the whole timeout operation if we see that
the timer is pending. The spinlock ensures that the only way
that happens is if we already started a new operation and thus
the timeout can be ignored.

Signed-off-by: Benjamin Herrenschmidt <b...@kernel.crashing.org>
---
 arch/powerpc/platforms/powermac/low_i2c.c |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/powerpc/platforms/powermac/low_i2c.c 
b/arch/powerpc/platforms/powermac/low_i2c.c
index f991dbb..fc536f2 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -366,11 +366,20 @@ static void kw_i2c_timeout(unsigned long data)
        unsigned long flags;
 
        spin_lock_irqsave(&host->lock, flags);
+
+       /*
+        * If the timer is pending, that means we raced with the
+        * irq, in which case we just return
+        */
+       if (timer_pending(&host->timeout_timer))
+               goto skip;
+
        kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr));
        if (host->state != state_idle) {
                host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
                add_timer(&host->timeout_timer);
        }
+ skip:
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
-- 
1.7.9.5

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to