I am writing a Linux device driver which needs to wait for an interrupt (triggered by changes in a GPIO line), and, once the interrupt happens, disable the interrupt until certain conditions are met.
I have tried calling disable_irq_nosync from the handler. Later, when I want to process this interrupt again, I would call enable_irq to reenable it. However I have found that if the GPIO changes while the interrupt is disabled, this seem to be internally detected by the kernel and would result in the interrupt firing immediately as soon as I call enable_irq.
Why is this happening, and how can I avoid it?
Related
Basic question about linux interrupt handling
In my driver i disable the interrupt line of a peripheral and do some processing, during this time peripheral is sending interrupt. when i enable the interrupt line i received the pending interrupt which happened during that time.
is this correct understanding?
If yes how can i discard those interrupt which came during the interrupt disable period.
I can implement some work around using some delay, looking for linux API or clean way to do this.
Before enabling the interrupt we can set
desc = irq_to_desc(client->irq);
desc->istate &= ~IRQS_PENDING;
and enable the interrupt line it will clear all the pending interrupt, but the code says we should never modify these variable.
Thank you
May be I did not understood but I think what you must do is:
disable interupt on the device directly and not using kernel interrupt handling routines
the poll your device, fetching all event. may be you should do this in a threaded interrupt handler
when finished re-enable interrupts on the device
I read some related posts:
(1) From Robert Love: http://permalink.gmane.org/gmane.linux.kernel.kernelnewbies/1791
You cannot sleep in an interrupt handler because interrupts do not have a backing
process context, and thus there is nothing to reschedule back into. In other
words, interrupt handlers are not associated with a task, so there is nothing to
"put to sleep" and (more importantly) "nothing to wake up". They must run
atomically.
(2) From Which context are softirq and tasklet in?
If sleep is allowed, then the linux cannot schedule them and finally cause a
kernel panic with a dequeue_task error. The interrupt context does not even
have a data structure describing the register info, so they can never be scheduled
by linux. If it is designed to have that structure and can be scheduled, the
performance for interrupt handling process will be effected.
So in my understanding, interrupt handlers run in interrupt context, and can not sleep, that is to say, can not perform the context switch as normal processes do with backing mechanism.
But a interrupt handler can be interrupted by another interrupt. And when the second interrupt handler finishes its work, control flow would jump back to the first interrupt handler.
How is this "restoring" implemented without normal context switch? Is it like normal function calls with all the registers and other related stuff stored in a certain stack?
The short answer is that an interrupt handler, if it can be interrupted by an interrupt, is interrupted precisely the same way anything else is interrupted by an interrupt.
Say process X is running. If process X is interrupted, then the interrupt handler runs. To the extent there is a context, it's still process X, though it's now running interrupt code in the kernel (think of the state as X->interrupt if you like). If another interrupt occurs, then the interrupt is interrupted, but there is still no special process context. The state is now X->first_interrupt->second_interrupt. When the second interrupt finishes, the first interrupt will resume just as X will resume when the first interrupt finishes. Still, the only process context is process X.
You can describe these as context switches, but they aren't like process context switches. They're more analogous to entering and exiting the kernel -- the process context stays the same but the execution level and unit of code can change.
The interrupt routine will store some CPU state and registers before enter real interrupt handler, and will restore these information before returning to interrupted task. Normally, this kind of storing and restoring is not called context-switch, as the context of interrupted process is not changed.
As of 2020, interrupts (hard IRQ here) in Linux do not nest on a local CPU in general. This is at least mentioned twice by group/maintainer actively contributing to Linux kernel:
From NAPI updates written by Jakub Kicinski in 2020:
…Because normal interrupts don't nest in Linux, the system can't service any new interrupt while it's already processing one.
And from Bootlin in 2022:
…Interrupt handlers are run with all interrupts disabled on the local CPU…
So this question is probably less relevant nowadays, at least for Linux kernel.
I have been working on irq handlers using the regmap irq chip implementation.
I have seen that there is high incosistency with the irq handlers execution. Especially if the irq is generated continuously during suspend. The irq chokes and never clears the interrupt source i.e handler never runs at times. Even if the handler runs half way and the system sleeps, it does not continue on resume.
Its creating serious issues. How do I handle this?
Regmap entirely uses threaded irqs. In addition, I was using i2c calls in the nested calls which are again threaded irqs. Due to this, I would always remain in user space and not in irq context. I2c tranfer has schedule in it and that brings in a completely different execution flow. In addition, there were problems in wake enabling the irq.
I'm trying to better understand the interaction between the "return IRQ_HANDLED" statement used in a GPIO pin-based interrupt handler (top-half) and the GPIO pin hardware. In particular, consider the hypothetical situation wherein a device has pulled a GPIO pin low to indicate that it needs attention. This causes the associated (top half) interrupt handler to be invoked. Now assume that the top-half handler queues up some work and then returns with "return IRQ_HANDLED" but that for whatever reason the interrupt has not been cleared on the device that generated it (i.e. the device is holding the GPIO pin in the low state). Does invocation of "return IRQ_HANDLED" cause the interrupt to be regenerated? I ask this in the context of the following article:
http://www.makelinux.net/books/lkd2/ch06lev1sec4
"Reentrancy and Interrupt Handlers
Interrupt handlers in Linux need not be reentrant. When a given interrupt handler is executing, the corresponding interrupt line is masked out on all processors, preventing another interrupt on the same line from being received. Normally all other interrupts are enabled, so other interrupts are serviced, but the current line is always disabled. Consequently, the same interrupt handler is never invoked concurrently to service a nested interrupt. This greatly simplifies writing your interrupt handler."
The above comment indicates that upon invocation of an interrupt handler, the interrupt line for that interrupt is masked. I'm trying to figure out if the invocation of "return IRQ_HANDLED" is what unmasks the interrupt line. And, with respect to the hypothetical case described above, what would happen if I "return IRQ_HANDLED" yet the device has not really had its interrupt cleared and hence is still holding the GPIO pin in a low (triggered) state. More specifically, will this cause the interrupt to be generated again such that the processor never has a chance to do the work queued when the interrupt first occurred. I.e., would this lead to an interrupt storm wherein the processor could be interrupted endlessly thus not allowing any useful processing to occur. I should add that I ask this question in the context of a single CPU linux ARM9 system (Phytec LPC3180) running kernel 2.6.10.
Thanks in advance,
Jim
PS: I'm not clear as to the difference between enabling/disabling an interrupt (in particular, an interrupt associated with a particular GPIO pin) and masking/unmasking the same GPIO interrupt.
I am following the Linux Device Drivers. When it introduces spinlocks, it gives the following example:
Your driver is executing and has just taken out a lock that controls access to its device. While the lock is held, the device issues an interrupt, which causes your interrupt handler to run. The interrupt handler, before accessing the device, must also obtain the lock. Taking out a spinlock in an interrupt handler is a legitimate thing to do; that is one of the reasons that spinlock operations do not sleep. But what happens if the interrupt routine executes in the same processor as the code that took out the lock originally? While the interrupt handler is spinning, the noninterrupt code will not be able to run to release the lock. That processor will spin forever.
I don't understand why if the interrupt handler is spinning, the noninterrupt code cannot be executed.
Is it because the routine in the interrupt handler cannot be preempted? If so, is that to say the interrupt routine must be atomic?
Is it because the routine in the interrupt handler cannot be preempted?
Not by process-context code.
If so, is that to say the interrupt routine must be atomic?
It could be interrupted by a higher priority interrupt or a NMI (or by SMM).