136 lines
4.7 KiB
ReStructuredText
136 lines
4.7 KiB
ReStructuredText
|
.. _interrupts_v2:
|
||
|
|
||
|
Interrupts [TBD]
|
||
|
################
|
||
|
|
||
|
Concepts
|
||
|
********
|
||
|
|
||
|
:abbr:`ISRs (Interrupt Service Routines)` are functions
|
||
|
that execute in response to a hardware or software interrupt.
|
||
|
They are used to preempt the execution of the current thread,
|
||
|
allowing the response to occur with very low overhead.
|
||
|
Thread execution resumes only once all ISR work has been completed.
|
||
|
|
||
|
Any number of ISRs can be utilized by an application, subject to
|
||
|
any hardware constraints imposed by the underlying hardware.
|
||
|
Each ISR has the following key properties:
|
||
|
|
||
|
* The **:abbr:`IRQ (Interrupt ReQuest)` signal** that triggers the ISR.
|
||
|
* The **priority level** associated with the IRQ.
|
||
|
* The **address of the function** that is invoked to handle the interrupt.
|
||
|
* The **argument value** that is passed to that function.
|
||
|
|
||
|
An :abbr:`IDT (Interrupt Descriptor Table)` is used to associate
|
||
|
a given interrupt source with a given ISR.
|
||
|
Only a single ISR can be associated with a specific IRQ at any given time.
|
||
|
|
||
|
Multiple ISRs can utilize the same function to process interrupts,
|
||
|
allowing a single function to service a device that generates
|
||
|
multiple types of interrupts or to service multiple devices
|
||
|
(usually of the same type). The argument value passed to an ISR's function
|
||
|
can be used to allow the function to determine which interrupt has been
|
||
|
signaled.
|
||
|
|
||
|
The kernel provides a default ISR for all unused IDT entries. This ISR
|
||
|
generates a fatal system error if an unexpected interrupt is signaled.
|
||
|
|
||
|
The kernel supports interrupt nesting. This allows an ISR to be preempted
|
||
|
in mid-execution if a higher priority interrupt is signaled. The lower
|
||
|
priority ISR resumes execution once the higher priority ISR has completed
|
||
|
its processing.
|
||
|
|
||
|
The kernel allows a thread to temporarily lock out the execution
|
||
|
of ISRs, either individually or collectively, should the need arise.
|
||
|
The collective lock can be applied repeatedly; that is, the lock can
|
||
|
be applied when it is already in effect. The collective lock must be
|
||
|
unlocked an equal number of times before interrupts are again processed
|
||
|
by the kernel.
|
||
|
|
||
|
Examples
|
||
|
********
|
||
|
|
||
|
Installing an ISR
|
||
|
=================
|
||
|
|
||
|
It's important to note that IRQ_CONNECT() is not a C function and does
|
||
|
some inline assembly magic behind the scenes. All its arguments must be known
|
||
|
at build time. Drivers that have multiple instances may need to define
|
||
|
per-instance config functions to configure the interrupt for that instance.
|
||
|
|
||
|
The following code illustrates how to install an ISR:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
#define MY_DEV_IRQ 24 /* device uses IRQ 24 */
|
||
|
#define MY_DEV_PRIO 2 /* device uses interrupt priority 2 */
|
||
|
/* argument passed to my_isr(), in this case a pointer to the device */
|
||
|
#define MY_ISR_ARG DEVICE_GET(my_device)
|
||
|
#define MY_IRQ_FLAGS 0 /* IRQ flags. Unused on non-x86 */
|
||
|
|
||
|
void my_isr(void *arg)
|
||
|
{
|
||
|
... /* ISR code */
|
||
|
}
|
||
|
|
||
|
void my_isr_installer(void)
|
||
|
{
|
||
|
...
|
||
|
IRQ_CONNECT(MY_DEV_IRQ, MY_DEV_PRIO, my_isr, MY_ISR_ARG, MY_IRQ_FLAGS);
|
||
|
irq_enable(MY_DEV_IRQ); /* enable IRQ */
|
||
|
...
|
||
|
}
|
||
|
|
||
|
Offloading ISR Work
|
||
|
*******************
|
||
|
|
||
|
Interrupt service routines should generally be kept short
|
||
|
to ensure predictable system operation.
|
||
|
In situations where time consuming processing is required
|
||
|
an ISR can quickly restore the kernel's ability to respond
|
||
|
to other interrupts by offloading some or all of the interrupt-related
|
||
|
processing work to a thread.
|
||
|
|
||
|
The kernel provides a variety of mechanisms to allow an ISR to offload work
|
||
|
to a thread.
|
||
|
|
||
|
1. An ISR can signal a helper thread to do interrupt-related work
|
||
|
using a kernel object, such as a fifo, lifo, or semaphore.
|
||
|
|
||
|
2. An ISR can signal the kernel's system workqueue to do interrupt-related
|
||
|
work by sending an event that has an associated event handler.
|
||
|
|
||
|
When an ISR offloads work to a thread there is typically a single
|
||
|
context switch to that thread when the ISR completes.
|
||
|
Thus, interrupt-related processing usually continues almost immediately.
|
||
|
Additional intermediate context switches may be required
|
||
|
to execute a currently executing cooperative thread
|
||
|
or any higher-priority threads that are ready to run.
|
||
|
|
||
|
Suggested Uses
|
||
|
**************
|
||
|
|
||
|
Use an ISR to perform interrupt processing that requires a very rapid
|
||
|
response, and which can be done quickly and without blocking.
|
||
|
|
||
|
.. note::
|
||
|
Interrupt processing that is time consuming, or which involves blocking,
|
||
|
should be handed off to a thread. See `Offloading ISR Work`_ for
|
||
|
a description of various techniques that can be used in an application.
|
||
|
|
||
|
Configuration Options
|
||
|
*********************
|
||
|
|
||
|
[TBD]
|
||
|
|
||
|
APIs
|
||
|
****
|
||
|
|
||
|
These are the interrupt-related Application Program Interfaces.
|
||
|
|
||
|
* :cpp:func:`irq_enable()`
|
||
|
* :cpp:func:`irq_disable()`
|
||
|
* :cpp:func:`irq_lock()`
|
||
|
* :cpp:func:`irq_unlock()`
|
||
|
* :cpp:func:`k_am_in_isr()`
|