Interrupt Handling
11.2 Generic Interrupt Controller
Older versions of the ARM architecture allowed implementers considerable freedom in their external interrupt controller, with no agreement over the number or types of interrupts or the software model to be used to interface to the interrupt controller block. GIC architecture provides a much more tightly controlled specification, with a much greater degree of
consistency between parts from different manufacturers. This enables interrupt handler code to be more portable.
GIC architecture defines a Generic Interrupt Controller (GIC) which comprises a set of hardware resources for managing interrupts in a single or multi-core system. The GIC provides memory mapped registers which can be used to manage interrupt sources and behavior and (in multi-core systems) for routing interrupts to individual processors. It enables software to mask, enable and disable interrupts from individual sources, to prioritize (in hardware) individual sources and to generate software interrupts. It also provides support for the TrustZone Security Extensions described in Chapter 26 Security. The GIC accepts interrupts asserted at the system level and can signal them to each processor it is connected to, potentially resulting in an IRQ or FIQ exception being taken.
From a software perspective, a GIC has two major functional blocks: Distributor
which is shared between all processors in a multiprocessor system. This is used for configuring things like prioritization and routing, as well as providing global enabling/disabling of individual interrupts.
CPU Interface
which is each processor’s private channel for handling interrupts. This is where you find out which interrupt has been triggered and notify when you have completed processing an interrupt.
Each interrupt can be considered to be in one of four states: • Inactive
• Pending – this means that the interrupt source has been asserted, but is waiting to be handled by a processor
• Active – this describes an interrupt that has been acknowledged by a processor and is currently being serviced
• Active and pending – this describes the situation where a processor is servicing the interrupt and the GIC also has a pending interrupt from the same source.
Interrupts can be of a number of different types
What follows is a brief overview of GIC terminology and its usage model. Software Generated Interrupt (SGI)
This is generated by writing to a dedicated register, the Software Generated Interrupt Register (ICDSGIR). It is most commonly used for inter-processor communication.
Private Peripheral Interrupt (PPI)
Interrupt Handling
Shared peripheral Interrupt (SPI)
This is generated by a peripheral that the Interrupt Controller can route to more than one processor.
Interrupts can either be edge-triggered (considered to be asserted when the Interrupt Controller detects a rising edge on the relevant input – and to remain asserted until cleared) or
level-sensitive (considered to be asserted only when the relevant input to the Interrupt Controller is high).
The source of an individual interrupt can be determined using an ID number. The GIC assigns a specified range of ID values to different types of interrupt.
The processor hardware then compares the interrupt priority with the current interrupt priority for the processor. If the interrupt has sufficient priority, an interrupt exception request is signaled.
11.2.1 Configuration
Access to the Generic Interrupt Controller registers is memory-mapped. In an MPCore cluster which uses the GIC, this is done using an interface private to each processor (See Handling interrupts in an SMP system on page 23-5 for further details).
Within the distributor you have series of configuration registers, the number depending on how many external interrupts are implemented:
• The Interrupt Configuration Registers configure individual interrupt sources as edge or level sensitive.
• The Interrupt Priority Registers set priority values for individual interrupts. A lower value indicates a higher priority.
The CPU interfaces provide per-processor instances of registers for interrupt handling, as opposed to configuration:
• The Priority Mask Register that prevents interrupts below a certain priority level from being delivered to a processor. Interrupts of the lowest priority are always disabled. • The Binary Point Register that enables a configurable number of the least significant bits
of the priority value to be ignored for pre-emption purposes. This enables interrupts to be configured such that groups of interrupts with similar levels of priority do not pre-empt each other, but are still handled in priority order if triggered simultaneously.
Implementation sequence
This section describes the implementation sequence.
1. Enable the distributor using the Distributor Control Register.
2. Enable and set priority of SPIs using the Enable Set and Priority Level registers. The reset priority level of interrupts might be too low for them to be delivered.
3. Enable the CPU Interface using the CPU Interface Control Register.
4. Set Priority Mask Register (the reset value prevents all interrupts from being delivered). 5. Enable and set priority of Private Peripheral Interrupts and Software Generated Interrupts
using the Enable Set and Priority Level registers. These operations are performed in the Distributor Priority Level Registers. These registers are banked providing a separate copy for each processor.
6. Clear the I bit in CPSR. 11.2.2 Interrupt handling
When the processor takes the interrupt exception, it reads the Interrupt Acknowledge Register (ICCIAR), to acknowledge the interrupt. This read returns an interrupt ID, which is used to select the correct interrupt handler. When the GIC sees this read, it changes the state of the interrupt from pending to active or to active and pending, as appropriate. If no interrupt is currently pending, a pre-defined “spurious” ID is returned.
If an interrupt was made active, the interrupt controller then de-asserts the IRQ input to the processor. This means that the interrupt service routine can now re-enable interrupts. This enables the arrival of a higher-priority interrupt to pre-empt processing of the current one. When the interrupt service routine has completed handling the interrupt, it signals this by writing to the End of Interrupt Register (ICCEOIR) in the GIC. Until this is done, new signaling of that interrupt (and any interrupts of lower priority) will not be detected.
• Interrupt numbers ID1020-ID1023 are reserved for special purposes, including signaling “spurious” interrupts.
• Interrupt ID values in the range ID32-ID1019 are used for SPIs.
• Interrupt numbers ID0-ID31 are used for interrupts that are private to a processor interface. In MPCore systems (or non-MPCore GICs implemented with more than one processor interface) these numbers are banked on a per processor basis. ID0-ID15 are used for SGIs and ID16-ID31 are used for PPIs.
Further reading
We will return to the subject of the GIC in Chapter 23, where we describe its implementation within an ARM MPCore processor. More detailed information on GIC behavior can be found in the TRMs for the individual processors and in the ARM Generic Interrupt Controller Architecture specification.