Request_threaded_irq behavior explanation

I browsed the web, but did not find a convincing answer to a couple of related questions that I have regarding the request_threaded_irq function.

Question1: First, I read this article regarding threaded IRQs:

http://lwn.net/Articles/302043/

and there is one line that I don’t understand:

"Converting an interrupt to threaded makes sense only when the code handler uses it, integrating tasklet / softirq functionality and simplifying locking."

As far as I understand, if we went for the “traditional” half / lower half approach, we would need to spin-lock or disable the local IRQ to interfere with the general data. But I don’t understand how thread interrupts would simplify the need for locking by integrating tasklet / softirq functionality.

Question2: Secondly, what advantage (if any) does the request_threaded_handler method have over the bottom half base based on work_queue? In both cases, it seems that the "work" is delayed by a dedicated thread. So what is the difference?

Question3: Finally, in the following prototype:

int request_threaded_irq(unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn, unsigned long irqflags, const char *devname, void *dev_id) 

Is it possible that the IRQ “handler” part is continuously triggered by the corresponding IRQ (for example, high-speed UART receive characters), even if the “thread_fn” (writing rx'd bytes to the circular buffer) part of the interrupt handler is busy with IRQ processing from previous awakenings? So, did the handler try to "wake up" the already running "thread_fn"? How will working irq thread_fn work in this case?

I would really appreciate if someone would help me figure this out.

Thanks, VJ

+4
source share
4 answers
  • Previously, the lower half was not a task , but could not block . The only difference was that interrupts were disabled. The console or softirq allow different interlocks between the ISR driver stream and the user API ( ioctl() , read() and write() ).
  • I think the work queue almost equivalent. However, tasklet / ksoftirq has high priority and is used by all ISR-based functions on this processor. This can improve planning opportunities. In addition, there is not much for the driver; everything is already embedded in the kernel ISR handler code.
  • You have to handle this. You can usually use ping-pong or kfifo , as you suggest. handler must be greedy and receive all data from UART before returning IRQ_WAKE_THREAD .
+2
source

In question # 3, when threadedirq is activated, the corresponding interrupt string is masked / disabled. when threadedirq runs and completes it, it comes to the end. therefore, there will be no interruption when the corresponding threadedirq is executed.

+2
source

In question 2, the creation IRQ flow is configured with a higher priority, unlike jobs. In kernel/irq/manage.c you will see the following code for creating kernel threads for IRQ streaming:

  static const struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO/2, }; t = kthread_create(irq_thread, new, "irq/%d-%s", irq, new->name); if (IS_ERR(t)) { ret = PTR_ERR(t); goto out_mput; } sched_setscheduler_nocheck(t, SCHED_FIFO, &param); 

Here you can see that the kernel thread scheduling policy is set to RT one ( SCHED_FIFO ), and the thread priority is set to MAX_USER_RT_PRIO/2 , which is higher than normal processes.

In question 3, the described situation may also occur during normal interruptions. Typically, kernel interrupts are disabled during ISR execution. During ISR execution, characters can continue to populate the device buffer, and the device can and must continue to acknowledge the interrupt, even when interrupts are disabled.

The device’s task is to ensure that the IRQ string is supported until all characters are read and the ISR processing is complete. It is also important that the interrupt be triggered by the level or depending on the design that was recorded by the interrupt controller.

Finally, the device / peripheral must have a FIFO of sufficient size so that characters transmitted at high speed are not lost in a slow ISR. The ISR should also be designed to read as many characters as possible when it is running.

Actually, what I saw, the controller will have a FIFO of a certain size X , and when the FIFO is filled with X/2 , it will kill the interrupt, which will cause the ISR to run out of data. ISR reads as much as possible and then clears the interrupt. Meanwhile, if the FIFO is still X/2 , the device will support the interrupt string, which will cause the ISR to run again.

+2
source

The original work of converting hard / soft handlers to threading handlers was done by Thomas Glakner and the team when creating PREEMPT_RT Linux (the so-called Linux-as-a-RTOS) (it is not part of the backbone). To really run Linux as RTOS, we cannot put up with a situation where the interrupt handler interrupts the most critical thread rt (app); but how can we ensure that the application flow even blocks the interrupt? Providing it with (interrupt) streaming, scheduled (SCHED_FIFO) and having a lower priority than the application stream (rtprio interrupt flows by default are 50). Thus, the application thread "rt" SCHED_FIFO with rtprio of 60 can "preempt" (close enough for it to work) even the interrupt stream. This should answer your questions. 2.

Wrt to Qs 3: As others have said, your code should handle this situation. Having said that, PL will notice that the key point of using a thread handler is that you can do work that (possibly) blocks (sleeps). If your "lower half" of work is not guaranteed to be blocked and should be fast, use traditional "top-half / bh" handlers. How can we do this? Simple: don't use request_threaded_irq () just calling request_irq () - the comment in the code clearly says (third parameter):

 * @thread_fn: Function called from the irq handler thread * If NULL, no irq thread is created" 

Alternatively, you can pass the IRQF_NO_THREAD flag to request_irq.

(BTW, a quick check with cscope in the kernel source tree 3.14.23 shows that request_irq () is called 1502 times [gives us processing without interrupting an interrupt], ​​and request_threaded_irq () [stream interrupts] is explicitly called 204 times).

0
source

All Articles