request_irq in I2C driver causes kernel to freeze during probe, but if done later - no problem!
From: Russell King - ARM Linux <hidden>
Date: 2010-03-27 09:16:02
On Sat, Mar 27, 2010 at 01:22:54AM +0100, Ulf Samuelsson wrote:
Russell King - ARM Linux skrev:quoted
On Sat, Mar 27, 2010 at 12:16:58AM +0100, Ulf Samuelsson wrote:quoted
If the interrupt is executing, then we would see some I2C communication as a result, but we do not see this, before the kernel freezes. The interrupt is (and should be) called on the falling edge of the interrupt. I am currently scratching my head, and need help with ideas...Do you always return IRQ_HANDLED from this handler, or do you return IRQ_NONE if it does no work? If you always return IRQ_HANDLED even if no work was done, it could be that you're spinning on this interrupt, and because you're returning IRQ_HANDLED, the core interrupt handling code thinks progress is being made. If you return IRQ_NONE, then the "bad IRQ" detection code will kick in and disable the IRQ, which should result in some further progress.Thanks for fast reply. This is my interrupt routine, which always return IRQ_HANDLED. sysfs shows that "mxt->invalid_irq_counter" is never incremented even after I successfully enable the interrupt in sysfs. mxt->dwork will always access the I2C bus but we dont see that. static irqreturn_t mxt_irq_handler(int irq, void *_mxt) { struct mxt_data *mxt = _mxt; unsigned long flags; mxt->irq_counter++; spin_lock_irqsave(&mxt->lock, flags); if (mxt_valid_interrupt()) { /* Macro, always returning 1 on these boards */ cancel_delayed_work(&mxt->dwork); schedule_delayed_work(&mxt->dwork, 0); mxt->valid_irq_counter++; } else { mxt->invalid_irq_counter++; } spin_unlock_irqrestore(&mxt->lock, flags); return IRQ_HANDLED;
So yes, you're going to spin indefinitely when you receive the first valid interrupt. 1. Your device raises an interrupt. 2. The CPU gets interrupted. 3. The kernel reads the IRQ number and calls your handler. 4. The handler schedules the delayed work and returns. 5. The kernel checks for any further pending interrupt, and finds the same interrupt is still raised, and calls your handler. 6. The handler schedules the delayed work and returns. 7. The kernel checks for any further pending interrupt, and finds the same interrupt is still raised, and calls your handler. 8. The handler schedules the delayed work and returns. 9. The kernel checks for any further pending interrupt, and finds the same interrupt is still raised, and calls your handler. 10. The handler schedules the delayed work and returns. 11. The kernel checks for any further pending interrupt, and finds the same interrupt is still raised, and calls your handler. ... You must clear the interrupt, or disable the interrupt source. Or make use of the kernel's threaded IRQs which will deal with the interrupt masking and running your handler in thread context for you.