zephyr/doc/kernel/microkernel/microkernel_task_irqs.rst
Andrew Boie 583126adf9 microkernel: remove task_irq_free() API
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>
2016-02-05 20:25:21 -05:00

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.