mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-13 15:51:57 +00:00
This is being removed for a few reasons: - AFAICT this is the only API in Zephyr that follows an allocate/free model. - There are no public APIs in the interrupt subsystem for releasing or reconfiguring an interrupt. This code was relying on arch-specific private APIs. If we really want to keep this capability we should make these APIs public and consistent across arches. - The use-case for this API is not clear, as Zephyr is not intended for hot-pluggable peripherals. Built-in hardware tends to need its interrupt for its entire life cycle. - The current implementation of dynamic interrupts on x86 does not support freeing a dynamic IRQ that was reserved with irq_connect_dynamic(), causing this code not to work. To add this would require reimplementing _get_dynamic_stub() to use a bitfield or set of bitfields to track unused stubs rather than the simple counter it uses now. Change-Id: I7a03c134fb3498b91a1816318a88b293e26b846c Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
121 lines
3.9 KiB
ReStructuredText
121 lines
3.9 KiB
ReStructuredText
.. _microkernel_task_irqs:
|
|
|
|
Interrupt Services
|
|
##################
|
|
|
|
Concepts
|
|
********
|
|
|
|
The microkernel's task IRQ objects allow interrupts to be serviced
|
|
by tasks, rather than interrupt service routines (ISRs).
|
|
This allows a microkernel project to have task-level device drivers,
|
|
in addition to interrupt-level device drivers.
|
|
|
|
Any number of task IRQs can be defined in a microkernel system.
|
|
Each task IRQ has a numeric identifier that uniquely identifies it.
|
|
These identifiers range from 0 to N-1, where N is the total number
|
|
of task IRQs in the system.
|
|
|
|
A task that wants to service interrupts from a device
|
|
must first allocate a task IRQ and bind it to the device's interrupt source
|
|
by specifying the IRQ and interrupt priority level
|
|
assigned to that device by the system designer.
|
|
Once a task IRQ has been allocated by a task
|
|
it cannot be utilized by other tasks;
|
|
this prevents other tasks from interfering with the proper processing
|
|
of interrupts from that device.
|
|
|
|
When an interrupt is generated by the device, the kernel
|
|
runs an ISR that masks the interrupt and signals the occurrence
|
|
of the interrupt to the associated task IRQ.
|
|
The task can then use the task IRQ to recognize that
|
|
an interrupt has occurred
|
|
and then take action to service the interrupt.
|
|
At some point during interrupt servicing
|
|
the task must instruct the task IRQ to acknowledge the interrupt;
|
|
this causes the kernel to unmask the interrupt
|
|
so that future interrupts can be detected.
|
|
|
|
Purpose
|
|
*******
|
|
|
|
Use a task IRQ when the work required to process an interrupt
|
|
cannot be done in an ISR, either because it takes a long time
|
|
or it requires the processing routine to block.
|
|
|
|
Usage
|
|
*****
|
|
|
|
Configuring Task IRQs
|
|
=====================
|
|
|
|
Set the :option:`MAX_NUM_TASK_IRQS` configuration option
|
|
to specify the number of task IRQs allowed in the project.
|
|
|
|
The default value of zero for this option disables task IRQs.
|
|
|
|
.. note::
|
|
Unlike most other microkernel object types, task-level IRQs are defined
|
|
as a group using a configuration option, rather than as individual
|
|
public objects in an MDEF or private objects in a source file.
|
|
|
|
Example: Allocating a Task IRQ
|
|
==============================
|
|
|
|
This code associates a task IRQ with interrupts generated by a device.
|
|
Interrupts from that device are then enabled
|
|
so they can be processed using the task IRQ.
|
|
|
|
.. code-block:: c
|
|
|
|
#define FOO_DEVICE 2 /* device "foo" uses task IRQ object 2 */
|
|
#define FOO_IRQ 37 /* device "foo" uses IRQ 37 */
|
|
#define FOO_PRIO 3 /* device "foo" uses interrupt priority 3 */
|
|
#define FOO_IRQ_FLAGS 0 /* device "foo" IRQ flags. Unused on non-x86 */
|
|
|
|
if (task_irq_alloc(FOO_DEVICE, FOO_IRQ, FOO_PRIO, FOO_IRQ_FLAGS) ==
|
|
INVALID_VECTOR) {
|
|
/* The task IRQ or the interrupt source is not available */
|
|
printf("Task IRQ allocation failed!");
|
|
}
|
|
|
|
Example: Servicing Interrupts using a Task IRQ
|
|
==============================================
|
|
|
|
This code allows a task to wait for an interrupt from a device,
|
|
acknowledge the interrupt, and take the necessary steps to service it.
|
|
|
|
.. code-block:: c
|
|
|
|
task_irq_wait(FOO_DEVICE, TICKS_UNLIMITED);
|
|
|
|
/* Device interrupt is now masked */
|
|
/* Do pre-acknowledgement device processing (if any) */
|
|
|
|
task_irq_ack(FOO_DEVICE);
|
|
|
|
/* Device interrupt is now unmasked */
|
|
/* Do post-acknowledgement device processing (if any) */
|
|
|
|
The steps required to service a device are device-specific.
|
|
In some cases all processing may need to be completed
|
|
before the interrupt is acknowledged,
|
|
while in other cases no processing at all should be done
|
|
until the interrupt is acknowledged.
|
|
Some devices may require processing both before and after acknowledgement.
|
|
|
|
|
|
APIs
|
|
****
|
|
|
|
The following task IRQ APIs are provided by :file:`microkernel.h`:
|
|
|
|
:cpp:func:`task_irq_alloc()`
|
|
Binds a task IRQ to a device and enables interrupts.
|
|
|
|
:cpp:func:`task_irq_ack()`
|
|
Acknowledges an interrupt and re-enables the interrupt.
|
|
|
|
:c:func:`task_irq_wait()`
|
|
Waits for an interrupt to occur within a specified time period.
|