How to work kernel irq thread in kernel Linux? - c

I have seen in mmc driver the function devm_request_threaded_irq used to launch sdhci_msm_pwr_irq like following :
ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
sdhci_msm_pwr_irq, IRQF_ONESHOT,
dev_name(&pdev->dev), host);
But when I call rmmod I have not seen an release or stop of this irq thread. Can you explain me how this thread works ?

Removal of the sdhci-msm module results in the module's module_exit handler function being called, which will call platform_device_unregister to unregister itself as a platform device driver. (Most of that is hidden by the macro call module_platform_driver(sdhci_msm_driver); in "drivers/mmc/host/sdhci-msm.c".)
When the platform driver is unregistered, all devices that were successfully probed will be removed automatically. The driver's "remove" handler sdhci_msm_remove will be called automatically for each successfully probed device.
So you may be wondering why sdhci_msm_remove doesn't free the interrupt allocated by the devm_request_threaded_irq call in the "probe" function sdhci_msm_probe? The answer is that it doesn't need to because the interrupt was allocated as a "managed device resource" (see below).
devm_request_threaded_irq is a "device resource managed" ("devres") wrapper around the request_threaded_irq function. Any devres-managed resources get cleaned up automatically when the probed device is being removed. (The clean-up of devres-managed resources happens after the "remove" handler returns.) For devres-managed interrupt resources, the clean-up results in the free_irq function being called automatically to free the interrupt.

Related

How to Exit HardFault handler (cortex-m4) properly

I am running on SOC using cortex-m4, when one of the HW components fail it raises bus-fault that cause Hard-Fault.
I want in the hard fault handler not only to print some registers and reset, I want instead to open UART connection to the device, the problem is that UART driver is using interrupts and I cannot open UART driver from Hard-Fault handler (cant call from within ISR)
Is there anyway to leave the hard-fault handler in a smart way (not including having the hard-fault raise a flag, then return and then the main() function will call the uart-driver) ?

How could we sleep when we are executing a syscall that execute in interrupt mode

When I am executing a system call to do write or something else, the ISR corresponded to the exception is executing in interrupt mode (on cortex-m3 the IPSR register is having a non-zero value, 0xb). And what I have learned is that when we execute a code in an interrupt mode we can not sleep, we can not use functions that might block ...
My question is that: is there any kind of a mechanism with which the ISR could still executing in interrupt mode and in the same time it could use functions that might block, or is there any kind of trick is implemented.
Caveat: This is more of a comment than an answer but is too big to fit in a comment or series of comments.
TL;DR: Needing to sleep or execute a blocking operation from an ISR is a fundamental misdesign. This seems like an XY problem: https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem
Doing sleep [even in application code] is generally a code smell. Why do you feel you need to sleep [vs. some event/completion driven mechanism]?
Please edit your question and add clarification [i.e. don't just add comments]
When I am executing a system call to do write or something else
What is your application doing? A write to what device? What "something else"?
What is the architecture/board, kernel/distro? (e.g. Raspberry Pi running Raspian? nvidia Jetson? Beaglebone? Xilinx FPGA with petalinux?)
What is the H/W device and where did the device driver come from? Did you write the device driver yourself or is it a standard one that comes with the kernel/distro? If you wrote it, please post it in your question.
Is the device configured properly? (e.g.) Are the DTB entries correct?
Is the device a block device, such as a disk controller? Or, is it a character device, such as a UART? Does the device transfer data via DMA? Or, does it transfer data by reading/writing to/from an IO port?
What do you mean by "exception"? Generally, exception is an abnormal condition (e.g. segfault, bus error, etc.). Please describe the exact context/scenario for which this occurs.
Generally, an ISR does little things. (e.g.) Grab [and save] status from the device. Clear/rearm the interrupt in the interrupt controller. Start the next queued transfer request. Wake up the sleeping base level task (usually the task that executed the syscall [waiting on a completion event in kernel mode]).
More elaborate actions are generally deferred and handled in the interrupt's "bottom half" handler and/or tasklet. Or, the base level is woken up and it handles the remaining processing.
What kernel subsystems are involved? Are you using platform drivers? Are you interfacing from within the DMA device driver framework? Are message buses involved (e.g. I2C, SPI, etc.)?
Interrupt and device handling in the linux kernel is somewhat different than what one might do in a "bare metal" system or RTOS (e.g. FreeRTOS). So, if you're coming from those environments, you'll need to think about restructuring your driver code [and/or application code].
What are your requirements for device throughput and latency?
You may wish to consult a good book on linux device driver design. And, you may wish to consult the kernel's Documentation subdirectory.
If you're able to provide more information, I may be able to help you further.
UPDATE:
A system call is not really in the same class as a hardware interrupt as far as the kernel is concerned, even if the CPU hardware uses the same sort of exception vector mechanisms for handling both hardware and software interrupts. The kernel treats the system call as a transition from user mode to kernel mode. – Ian Abbott
This is a succinct/great explanation. The "mode" or "context" has little to do with how we got/get there from a H/W mechanism.
The CPU doesn't really "understand" interrupt mode [as defined by the kernel]. It understands "supervisor" vs "user" privilege level [sometimes called "mode"].
When executing at user privilege level, an interrupt/exception will notice the transition from "user" level to "supvervisor" level. It may have a special register that specifies the address of the [initial] supervisor stack pointer. Atomically, it swaps in the value, pushing the user SP onto the new kernel stack.
If the interrupt is interrupting a CPU that is already at supervisor level, the existing [supervisor] SP will be used unchanged.
Note that x86 has privilege "ring" levels. User mode is ring 3 and the highest [most privileged] level is ring 0. For arm, some arches can have a "hypervisor" privilege level [which is higher privilege than "supervisor" privilege].
The setup of the mode/context is handled in arch/arm/kernel/entry-*.S code.
An svc is a synchronous interrupt [generated by a special CPU instruction]. The resulting context is the context of the currently executing thread. It is analogous to "call function in kernel mode". The resulting context is "kernel thread mode". At that point, it's not terribly useful to think of it as an "interrupt" anymore.
In fact, on some arches, the syscall instruction/mechanism doesn't use the interrupt vector table. It may have a fixed address or use a "call gate" mechanism (e.g. x86).
Each thread has its own stack which is different than the initial/interrupt stack.
Thus, once the entry code has established the context/mode, it is not executing in "interrupt mode". So, the full range of kernel functions is available to it.
An interrupt from a H/W device is asynchronous [may occur at any time the CPU's internal interrupt enable flag is set]. It may interrupt a userspace application [executing in application mode] OR kernel thread mode OR an existing ISR executing in interrupt mode [from another interrupt]. The resulting ISR is executing in "interrupt mode" or "ISR mode".
Because the ISR can interrupt a kernel thread, it may not do certain things. For example, if the CPU were in [kernel] thread mode, and it was in the middle of a kmalloc call [GFP_KERNEL], the ISR would see partial state and any action that tried to adjust the kernel's heap would result in corruption of the heap.
This is a design choice by linux for speed.
Kernel ISRs may be classified as "fast interrupts". The ISR executes with the CPU interrupt enable [IE] flag cleared. No normal H/W interrupt may interrupt the ISR.
So, if another H/W device asserts its interrupt request line [in the external interrupt controller], that request will be "pending". That is, the request line has been asserted but the CPU has not acknowledged it [and the CPU has not jumped via the interrupt table].
The request will remain pending until the CPU allows further interrupts by asserting IE. Or, the CPU may clear the pending interrupt without taking action by clearing the pending interrupt in the interrupt controller.
For a "slow" interrupt ISR, the interrupt entry code will clear the interrupt in the external interrupt controller. It will then rearm interrupts by setting IE and call the ISR. This ISR can be interrupted by other [higher priority] interrupts. The result is a "stacked" interrupt.
I have been searching all over the places, I come to the conclusion is that the interrupts have a higher priority than some of exceptions in the Linux kernel.
An exception [synchronous interrupt] can be interrupted if the IE flag is enabled. An svc is treated differently but after the entry code is executed, the IE flag is set, so the actual syscall code [executing in kernel thread mode] can be interrupted by a H/W interrupt.
Or, in limited circumstances, the kernel code can generate an exception (e.g. a page fault caused by a kernel action [which is usually deemed fatal]).
but I am still looking on how exactly the context switching happen when executing an exception and letting the processor to execute in a thread mode while the SVCall exception is pending (was preempted and have not returned yet)... I think when I understand that, it would be more clear to me.
I think you have to be very careful with the terminology. In particular, when combining terms from disparate sources. Although user mode, kernel thread mode, or interrupt mode can be considered a context [in the dictionary sense of the word], context switching usually means that the current thread is suspended, the scheduler selects a new thread to run and resumes it. That is separate from the user-to-kernel transition.
And if there is any recommended resources about that for ARM-Cortex-M3/4, it would be nice
Here is something: https://interrupt.memfault.com/blog/arm-cortex-m-exceptions-and-nvic But, be very careful in applying the terminology therein. What it considers "pending" only exists in the kernel during the entry code. What is more relevant is what the kernel does to set up mode/context and the terms are not equivalent.
So, from the kernel's standpoint, it's probably better to not consider an svc as "pending".

Can a shared interrupt line in Linux have different interrupt handlers?

Can an interrupt line shared by different drivers have different unique interrupt handlers? For example, would something like this be possible?
on driver1 : request_irq(irq, &handler1, IRQF_SHARED,"dev1", dev1);
on driver2 : request_irq(irq, &handler2, IRQF_SHARED,"dev2", dev2);
If all drivers that want to share this IRQ are requesting it with IRQF_SHARED this works - If only one of them does not set that flag, i.e. wants the IRQ exclusively, your request_irq will fail.
Another precondition is that your handler needs to be able to recognise somehow from the hardware whether it was his device that triggered the IRQ or not. This determines the return value of the handler.
The kernel will call all handlers that share the IRQ in sequence until it found one that actually handled it.

interrupt handling by C code

I am trying to disable interrupts through C code but stuck at request_irq(). One argument to request_irq() is flag and SA_INTERRUPT flag is now deprecated. Can anyone tell me alternative to SA_INTERRUPT?. I am using kernel version 3.8.
Any other alternative to request_irq() for disabling interrupts?
request_irq() does not "disable" an interrupt. It is called by a driver that wants to attach an interrupt service routine to an IRQ. The flag is IRQF_SHARED if the interrupt is shared or 0 otherwise.
Here is an example from a driver for Realtek 8169 PCIe network adapter: http://lxr.free-electrons.com/source/drivers/net/ethernet/realtek/r8169.c
retval = request_irq(pdev->irq, rtl8169_interrupt,
(tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED,
dev->name, dev);
In the example above, rtl8169_interrupt is the interrupt service routine (ISR) that will be invoked each time an IRQ is raised.
It is the job of the ISR to find out if the interrupt was indeed fired by the "owned" device (relevant for shared interrupts) then if the device indeed fired the interrupt, the ISR reads interrupt status then clears the interrupt.

Can I use free_irq in a software interrupt context?

The kernel documentation says about free_irq the following :
This function must not be called from interrupt context.
Does it include software interrupts?
How can I free an IRQ in a software IRQ function?
Thanks for your help,
Yes, that rule includes softirq context. The fact that you think you need to call free_irq() from softirq context is an indication that your design is a bit out of the ordinary -- in normal cases, free_irq() is used when a device being shut down, which is almost always from process context.
However if you really need to do it, the thing to do would be to defer it to process context via schedule_work() or some similar workqueue function. Of course you can't wait in your softirq for that deferred work to complete, so you'll have to defer any other work that comes after freeing the IRQ also.
It might be possible to give a better answer if you gave a bit more information about why you're trying to call free_irq() from interrupt context.

Resources