Original URL: http://blog.csdn.net/skyflying2012/article/details/8265869
Today, when writing a touchscreen driver, using the DISABLE_IRQ shutdown interrupt in the interrupt handling function found that the kernel hung up after the interrupt processing, and then discovered that the DISABLE_IRQ closed interrupt and waited for the interrupt to be processed and returned, and Disable_irq_ Nosync returns immediately. In the interrupt handler, you should use Disable_irq_nosync to turn off interrupts first look at Disable_irq_nosync, which is explained in the kernel code:
/** * Disable_irq_nosync-disable an IRQ without waiting * @irq: Interrupt to disable * * Disable the selected interrupt line. Disablesand enables is * Nested. * Unlike DISABLE_IRQ (), this function doesnot ensure existing * Instances of the IRQ handler has completed before returning. * * This function is called from IRQ context. */ void Disable_irq_nosync (unsigned int IRQ) { struct Irq_desc *desc = Irq_to_desc (IRQ); unsigned long flags;
if (!DESC) Return
Chip_bus_lock (IRQ, DESC); Spin_lock_irqsave (&desc->lock, flags); __DISABLE_IRQ (DESC, IRQ, false); Spin_unlock_irqrestore (&desc->lock, flags); Chip_bus_sync_unlock (IRQ, DESC); }
|
The program returns after the interrupt is closed, and if it is in the interrupt handler, the interrupt handler will continue to execute.
/** * Disable_irq-disable an IRQ and wait for completion * @irq: Interrupt to disable * * Disable the selected interrupt line. Enables and disables are * Nested. * This function waits-pending IRQ handlers for this interrupt * to complete before returning. If You use the This function while * Holding a resource the IRQ handler may need you'll deadlock. * * This function is Called-with care-from IRQ context. */ void Disable_irq (Unsignedint IRQ) { struct Irq_desc *desc = irq_desc + IRQ; if (irq>= Nr_irqs) Return Disable_irq_nosync (IRQ); if (desc->action) SYNCHRONIZE_IRQ (IRQ); }
|
Closes the interrupt and waits for the interrupt to be processed and returned. As you can see from the code, DISABLE_IRQ first called Disable_irq_nosync and then detects if Desc->action is 1. In the interrupt handler, the action is set to 1, so enter the SYNCHRONIZE_IRQ function.
/** * Synchronize_irq-wait for pending IRQ handlers (on other CPUs) * @irq: Interrupt number to wait for * * This function waits-pending IRQ handlers for this interrupt * to complete before returning. If You use the This function while * Holding a resource the IRQ handler may need you'll deadlock. * * This function is Called-with care-from IRQ context. */ void Synchronize_irq (Unsignedint IRQ) { struct Irq_desc *desc= irq_to_desc (IRQ); unsigned int status; if (!DESC) Return do { unsigned long flags; /* * Wait until we ' re out of the A critical section. This might * Give the wrong answer due to the lack of memory barriers. */ while (desc->status& irq_inprogress) Cpu_relax (); /* Ok, that's indicated we ' re done:double-check carefully. */ Spin_lock_irqsave (&desc->lock, flags); Status = desc->status; Spin_unlock_irqrestore (&desc->lock, flags); /* Oops, that failed? */ } while (status & Irq_inprogress); /* * We made sure that no HARDIRQ handler is running. Now verify * That's no threaded handlers is active. */ Wait_event (Desc->wait_for_threads,!atomic_read (&desc->threads_active)); }
|
Note that the function is waiting for the end of the interrupt handler, which is the main difference between DISABLE_IRQ and Disable_irq_nosync. But what happens when you call in an interrupt handler function? The irq_inprogress is set by __SETUP_IRQ before entering the interrupt handler, so the program is stuck in the while loop and the kernel is exclusive, which causes the system to die.
Summary:
Because the SYNCHRONIZE_IRQ function is called in DISABLE_IRQ to wait for the interrupt to return, the DISABLE_IRQ cannot be used in the interrupt handler, which causes the CPU to be SYNCHRONIZE_IRQ exclusive and the system crashes.
"Go" interrupt processing function without DISABLE_IRQ and use Disable_irq_nosync reason