powerpc/pmac: Don't add_timer() twice
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 <benh@kernel.crashing.org>
This commit is contained in:
parent
2ef822c553
commit
3027691e58
1 changed files with 9 additions and 0 deletions
|
@ -366,11 +366,20 @@ static void kw_i2c_timeout(unsigned long data)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&host->lock, 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));
|
kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr));
|
||||||
if (host->state != state_idle) {
|
if (host->state != state_idle) {
|
||||||
host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
|
host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
|
||||||
add_timer(&host->timeout_timer);
|
add_timer(&host->timeout_timer);
|
||||||
}
|
}
|
||||||
|
skip:
|
||||||
spin_unlock_irqrestore(&host->lock, flags);
|
spin_unlock_irqrestore(&host->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue