Skip to content

Linux IRQ Subsystem Fundamentals

The Linux IRQ subsystem provides a generic interrupt handling framework that separates hardware interrupt controllers from driver interrupt handlers.

This abstraction allows the same driver model to work across different CPU architectures and interrupt controller implementations.


IRQ Architecture Overview

A hardware interrupt passes through multiple software layers before reaching a driver ISR.

Hardware IRQ
IRQ Controller
irq_chip
irq_desc
irq_action
Driver ISR

Linux refers to this architecture as the Generic IRQ Subsystem.


IRQ Controller

An IRQ controller is hardware responsible for delivering interrupts to CPUs.

Examples:

  • ARM GIC
  • RISC-V PLIC
  • x86 APIC
  • GPIO Interrupt Controllers

Responsibilities:

  • Detect interrupt requests
  • Route interrupts to CPUs
  • Manage interrupt priorities
  • Acknowledge interrupt completion

irq_chip

Linux abstracts interrupt controller operations through irq_chip.

Simplified model:

struct irq_chip {
    const char *name;

    void (*irq_ack)(int irq);
    void (*irq_eoi)(int irq);
};

Responsibilities:

  • IRQ acknowledge
  • IRQ masking
  • IRQ unmasking
  • End-of-interrupt notification

The driver does not directly communicate with interrupt controller hardware.

Instead:

Driver
Generic IRQ Core
irq_chip
IRQ Controller

irq_desc

Each Linux IRQ is represented by an IRQ descriptor.

Simplified model:

struct irq_desc {
    int irq;

    enum irq_trigger_type trigger;

    struct irq_chip *chip;

    struct irq_action *action;
};

Responsibilities:

  • Store IRQ metadata
  • Associate IRQ controller
  • Track registered handlers
  • Manage IRQ state

Conceptually:

IRQ Number
irq_desc

irq_action

An irq_action represents a registered interrupt handler.

Simplified model:

struct irq_action {
    irq_handler_t handler;

    const char *name;

    void *dev_id;
};

Responsibilities:

  • Store ISR callback
  • Store driver private data
  • Associate handler name

Conceptually:

irq_desc
irq_action
ISR

IRQ Registration Flow

Driver registration:

request_irq(
        irq,
        handler,
        flags,
        name,
        dev_id);

Conceptually:

request_irq()
allocate irq_action
attach to irq_desc

Result:

irq_desc
irq_action
ISR

IRQ Dispatch Flow

When an interrupt occurs:

Hardware IRQ
IRQ Controller
irq_chip
irq_desc
irq_action
ISR

A simplified dispatch sequence:

irq_trigger()
irq_dispatch()
irq_ack()
ISR
irq_eoi()

irqreturn_t

Linux interrupt handlers return irqreturn_t.

typedef enum {
    IRQ_NONE = 0,
    IRQ_HANDLED,
    IRQ_WAKE_THREAD,
} irqreturn_t;

IRQ_NONE

The interrupt does not belong to the current handler.

return IRQ_NONE;

Typically used with shared IRQs.


IRQ_HANDLED

The interrupt was successfully processed.

return IRQ_HANDLED;

Most common return value.


IRQ_WAKE_THREAD

Request execution of a threaded interrupt handler.

return IRQ_WAKE_THREAD;

Used with:

request_threaded_irq()

IRQ Context

Interrupt handlers execute in IRQ context.

Characteristics:

  • Preempt normal execution
  • Execute with strict timing requirements
  • Must not sleep

Not allowed:

msleep();
mutex_lock();
wait_for_completion();

Typical ISR work:

Read status
Acknowledge interrupt
Collect minimal data
Schedule deferred work
Return quickly

IRQ Context vs Process Context

Property IRQ Context Process Context
Can sleep No Yes
Can use mutex No Yes
Can call msleep No Yes
Interrupt latency sensitive Yes No
Typical users ISR Workqueue, kthread, system calls

Shared IRQ Concept

Multiple devices may share the same Linux IRQ.

Conceptually:

IRQ17
 ├── Device A
 ├── Device B
 └── Device C

Linux manages this through multiple irq_action objects attached to a single IRQ descriptor.

This topic is typically encountered together with:

  • IRQ_NONE
  • request_threaded_irq()
  • Shared IRQ handling

Relationship to Bottom Half

Linux interrupt processing is divided into:

Top Half
Bottom Half

Top Half:

ISR

Bottom Half:

Workqueue
Threaded IRQ

The Generic IRQ Subsystem provides the foundation for deferred interrupt processing.

This leads naturally to:

  • Workqueue-based interrupt handling
  • Threaded IRQs
  • request_threaded_irq()

which are common patterns in Linux device drivers.