Skip to content

Day79 - IRQ Subsystem Fundamentals

Objective

Understand the architecture of the Linux Generic IRQ Subsystem and how interrupts are dispatched from IRQ controllers to driver interrupt service routines.

This lab extends the GPIO IRQ simulation framework introduced in Day78.


Lab1 - irq_desc and irq_action

Goal

Separate interrupt handler information from irq_desc.

Before Day79:

irq_desc
 ├─ handler
 ├─ dev_id
 └─ name

After Day79:

irq_desc
irq_action
        ├─ handler
        ├─ dev_id
        └─ name

irq_action

struct irq_action {
    irq_handler_t handler;
    const char *name;
    void *dev_id;
};

Represents a driver registered interrupt handler.


irq_desc

struct irq_desc {
    int irq;
    enum irq_trigger_type trigger;
    struct irq_action *action;
};

Represents a Linux IRQ descriptor.


request_irq()

Registers a new interrupt action.

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

Responsibilities:

  • Allocate irq_action
  • Store ISR information
  • Attach action to irq_desc

free_irq()

Removes the registered action.

free_irq(
        irq,
        dev_id);

Responsibilities:

  • Locate matching action
  • Release action memory
  • Clear irq_desc ownership

Lab2 - IRQ Dispatch Flow

Goal

Introduce a Generic IRQ dispatch layer.

Instead of calling ISR directly:

irq_trigger()
ISR

use:

irq_trigger()
irq_dispatch()
ISR

irq_dispatch()

static irqreturn_t irq_dispatch(
        struct irq_desc *desc);

Responsibilities:

  • Validate descriptor
  • Locate irq_action
  • Invoke ISR

Test

Trigger IRQ twice.

Expected output:

[TRIGGER] irq=100
[DISPATCH] irq=100 (button)
[ISR] irq=100 count=1

[TRIGGER] irq=100
[DISPATCH] irq=100 (button)
[ISR] irq=100 count=2

Lab3 - irq_chip Simulation

Goal

Introduce IRQ controller abstraction.

Linux drivers do not communicate directly with hardware interrupt controllers.

Linux uses:

irq_chip

to abstract controller-specific operations.


irq_chip

struct irq_chip {
    const char *name;
    void (*irq_ack)(int irq);
    void (*irq_eoi)(int irq);
};

ACK and EOI

Acknowledge interrupt:

irq_ack()

End of interrupt:

irq_eoi()

Simulation:

static void sim_irq_ack(int irq);
static void sim_irq_eoi(int irq);

Updated Dispatch Flow

irq_trigger()
irq_dispatch()
irq_chip->irq_ack()
ISR
irq_chip->irq_eoi()

Test

Expected output:

[TRIGGER] irq=100
[DISPATCH] irq=100 (button)

[CHIP] ack irq=100

[ISR] irq=100 count=1

[CHIP] eoi irq=100

Lab4 - irqreturn_t

Goal

Understand Linux interrupt handler return values.


irqreturn_t

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

IRQ_NONE

Interrupt does not belong to this handler.

return IRQ_NONE;

Output:

[IRQ] not handled

IRQ_HANDLED

Interrupt successfully handled.

return IRQ_HANDLED;

Output:

[IRQ] handled

IRQ_WAKE_THREAD

Used by threaded IRQs.

return IRQ_WAKE_THREAD;

Will be used in Day80.


Final Architecture

After completing all labs:

IRQ Controller
irq_chip
irq_desc
irq_action
ISR

Key Learning Points

Linux IRQ Layering

Linux separates:

  • IRQ controller operations
  • IRQ descriptor management
  • Driver interrupt handlers

This improves portability and scalability.


Generic IRQ Dispatch

Interrupt dispatch is managed by the Generic IRQ Subsystem.

irq_trigger()
irq_dispatch()
irq_action
ISR

Interrupt Result Reporting

ISRs communicate handling results through:

IRQ_NONE
IRQ_HANDLED
IRQ_WAKE_THREAD

rather than traditional error codes.


Preparation for Day80

The current framework will be extended with:

Top Half
IRQ_WAKE_THREAD
Bottom Half

Workqueue

Threaded IRQ

in the next lesson.