Overview
An interrupt is a hardware signalling mechanism used by peripherals to asynchronously notify the processor of events. At the electrical level, a device asserts a signal—traditionally through a physical interrupt pin, or in modern PCIe systems through MSI/MSI-X messages.
Hardware flow for a line-based interrupt:
+-----------+ IRQ Line +----------------+ Vector +---------+
| Device |------------>| Interrupt Ctrl |---------->| CPU |
| (e.g WiFi)| | (APIC/GIC) | | Core n |
+-----------+ +----------------+ +---------+
(asserts level/edge) (maps line→vector) |
v
Interrupt Entry
Device Asserts Interrupt Line
A peripheral detects an event and asserts its interrupt line. This line is wired into the GIC’s Distributor (or Redistributor for PPIs/SGIs).
The device keeps the line asserted until the driver later clears the cause in its MMIO registers.
What does “assert” mean electrically?
Drive the interrupt line to its active electrical state
Depending on the design, active state can be:
- Active-high → line goes from LOW (0) to HIGH (1)
- Active-low → line goes from HIGH (1) to LOW (0)
Most ARM SoCs and GIC configurations use active-high signalling. So,
device asserts the interrupt line → device drives the IRQ signal wire HIGH
device deasserts the interrupt line → device drives the IRQ signal wire LOW again
Level-triggered Interrupts
For a level-triggered interrupt:
- Assert = hold the line HIGH
- Deassert = bring the line LOW
The device keeps the line HIGH as long as the internal interrupt condition is present. Device Driver clears the internal condition after handling the interrupt.
The GIC samples the line to detect the interrupt:
HIGH → Pending
LOW → Not pending
Edge-triggered Interrupts
For rising-edge triggered interrupts:
Assert = quick transition from LOW → HIGH (Voltage 0V → 3.3V)
After that, the state of the line DOES NOT MATTER
GIC includes edge detectors. When the pulse arrives in the interrupt line, the edge detector identifies a LOW → HIGH transition and latches interrupt pending (stores a pending bit in flip-flop) for that interrupt ID. Even though the interrupt line is LOW again, the GIC keeps the interrupt Pending.
ARM Generic Interrupt Controller (GIC)
GIC abstracts hardware interrupt handling into two broad responsibilities:
- Global interrupt management: Routing, prioritisation, and grouping of interrupts that originate from any device in the SoC.
- Per-CPU interrupt interaction: Deciding when a core should take an exception, providing the Interrupt ID to software, and handling acknowledgements/EOI.
To support these responsibilities, every GIC consists of:
- Distributor (GICD)- shared global controller
- Redistributors (GICR)- per-core interrupt controllers (GICv3+ only)
- CPU Interface (CPUIF)- one logical interface per core (hardware registers or system registers depending on version)
- Optional MSI hardware (ITS) — for MSI/MSI-X style delivery of LPIs (GICv3+)
Distributor: Global state
The Distributor is the global bookkeeper. Shared Peripheral Interrupts (SPIs)—the vast majority of SoC external device interrupts—terminate here. Its primary functions are:
Interrupt State Machine
Each interrupt has per-interrupt state:
- Pending — the line asserted or event signalled
- Active — software has acknowledged it
- Active+Pending — an additional event arrived while CPU handling the interrupt
- Inactive
The Distributor owns this state machine for all SPIs.
Priority and Grouping
The Distributor stores:
- interrupt priority
- routing affinity (target CPU(s))
- trigger type (edge/level)
- enable/disable state
The priority value is global across the system. Lower numerical value means higher priority.
Target CPU Selection
For each SPI, the Distributor contains a target mask that identifies which cores may receive it.
Role in the Delivery Path
When an interrupt line asserts, the Distributor:
- Marks it Pending
- Evaluates whether it is routed to a given CPU
- Notifies the appropriate CPU Interface
This is where the “global” arbitration happens, but it leaves local CPU-level filtering to the CPU Interface.
Redistributor (GICv3+): Per Core State
The redistributor holds per-CPU configuration for interrupts that do not need global distribution.
Redistributors also manage LPI configuration tables for systems that support MSI/MSI-X style interrupts through ITS.
CPU Interface: Per Core Local Arbitration and exception signalling
When an interrupt has passed all global checks, the last gatekeeper is the CPU Interface. This component ensures that a core only takes an interrupt when the architectural rules permit it.
There are two major variants:
GICv2 CPU Interface — memory-mapped registers (ICCIAR, ICCEOIR, ICCPMR, ICCICTR, etc.)
GICv3 CPU Interface — system registers (ICC_IAR1_EL1, ICC_EOIR1_EL1, ICC_PMR_EL1, ICC_CTLR_EL1, etc.)
Priority Mask Filtering
Each core has a Priority Mask Register (PMR).
The CPU Interface checks:
interrupt_priority < PMR ?
If true, the CPU Interface signals the IRQ to the core.
This filtering happens per core.
Acknowledgement Path
When the kernel’s low-level handler reads the Interrupt Acknowledgement Register (IAR):
The CPU Interface selects the highest priority pending interrupt targeted at this core.
It returns the Interrupt ID to software.
It transitions the interrupt from Pending → Active (or Active+Pending → Active).
For GICv2: ICCIAR -> read gives interrupt ID`
For GICv3: ICC_IAR1_EL1 -> read gives interrupt ID
This read is the architectural handshake indicating that software is ready to start handling the interrupt.
Signalling the Core
Once an interrupt passes priority filtering, the CPU Interface asserts:
a physical IRQ/FIQ pin (GICv2), or an architectural exception injection (GICv3)
The CPU core now takes the IRQ exception and jumps to its exception vector.
End of Interrupt (EOI) Path
When software writes the Interrupt ID to the EOI register:
Interrupt transitions from Active → Inactive
CPU Interface becomes free to deliver another interrupt
Note:
EOI does not clear the device's internal condition, if the device interrupt line is still asserted (level-triggered), the Distributor re-enters Pending immediately. This condition is called Interrupt storm. The device driver must clear the device's internal condition before EOI to avoid such condition.
If the device asserts the interrupt line (edge-triggered) before EOI, then GIC latches an interrupt pending again and the state transitions from Active → Active+Pending. After EOI, GIC begins the delivery of the next IRQ signal. Edge-triggered interrupts do NOT count pulses; they only guarantee at most one extra delivery if a new edge occurs while the first one is Active.
ITS and LPIs (GIC v3)
Modern SoCs use Message Signaled Interrupts (MSI/MSI-X) for PCIe and on-chip DMA engines. GICv3 introduces:
ITS (Interrupt Translation Service)
LPIs (Locality-specific Peripheral Interrupts)
The ITS performs translation of MSI messages into interrupt IDs, and Redistributors deliver these LPIs directly to CPU Interfaces.
Interrupt Delivery
For an SPI-style interrupt:
- Device asserts interrupt line → Distributor marks Pending
- Distributor checks routing → forwards to target CPU Interface
- CPU Interface compares interrupt priority with PMR
- If allowed, CPU Interface signals IRQ to core
- Core takes exception → kernel reads IAR → interrupt becomes Active
- Kernel ISR runs → clears device condition
- Kernel writes EOI → interrupt becomes Inactive
Linux IRQ Number vs. GIC Interrupt ID
GIC Interrupt ID (Hardware concept)
This is the hardware number defined by the ARM GIC architecture.
This ID is what:
- The Distributor tracks
- The CPU Interface returns in IAR Register
- The kernel writes back in EOI Register
When hardware raises an interrupt, the CPU sees this Interrupt ID.
How a device asserting an interrupt line maps to a Interrupt ID?
- Interrupt ID numbers are defined by the GIC architecture.
- SGIs (0–15)
- PPIs (16–31)
- SPIs (32 onwards)
- The SoC designer connects each peripheral’s interrupt output pin to a specific GIC input line.
- The mapping between device interrupt pin → GIC Interrupt ID is static.
If SoC connects:
WiFi → SPI line 10
Ethernet → SPI line 7
USB → SPI line 15
Then GIC Interrupt ID for SPI line N = 32 + N:
WiFi = Interrupt ID 42 (32 + 10)
Ethernet = Interrupt ID 39 (32 + 7)
USB = Interrupt ID 47 (32 + 15)
Linux IRQ Number (Software concept)
In Linux, interrupts are abstracted through a larger, architecture-independent space.
- They can be allocated dynamically
- They can represent: GIC interrupt IDs, MSI vectors, virtual IRQs
In other words, Linux IRQ numbers are logical IDs used by kernel subsystems and device drivers.
Interrupt Masking and Affinity
GIC Hardware Masking (GIC enable/disable)
This disables/enables delivery at the GIC Distributor, meaning:
masked → device asserts interrupt line, but Distributor ignores it
unmasked → GIC registers Pending and routes it normally
This is actual hardware gating.
Linux calls into the GIC driver’s low-level ops.
Linux IRQ Masking (Software Masking)
Implemented in Linux IRQ desc.
The interrupt is still delivered from GIC, but Linux ignores it.
IRQ Affinity
GIC Distributor holds target CPU information and routes Pending interrupts only to those CPUs.
Linux calls into the GIC driver’s low-level ops to set the affinity mask.

Top comments (0)