RT-Thread RTOS
An open source embedded real-time operating system
PIC virtual IRQ domain

Virtual IRQ allocation (<tt>pic.c</tt>)

How RT-Thread turns many interrupt controllers into one global IRQ space drivers can use.


Global table <tt>_pirq_hash[]</tt>

  • Size: **MAX_HANDLERS** (Kconfig, default 256)
  • Each slot is a **struct rt_pic_irq** with **irq**, **hwirq**, **pic**, ISR list, optional **parent**

Allocation pointer **_pirq_hash_idx**:

Region Indices Purpose
IPI 0 … RT_MAX_IPI-1 SMP inter-processor interrupts
PIC domains _pirq_hash_idx upward Each **rt_pic_linear_irq** takes a contiguous block

**rt_pic_config_ipi** uses fixed low indices. Peripheral IRQs come from **rt_pic_config_irq**.


Per-controller window

**rt_pic_linear_irq(pic, irq_nr)** (under global lock):

pic->irq_start = _pirq_hash_idx; /* first virtual IRQ for this PIC */
pic->irq_nr = irq_nr;
pic->pirqs = &_pirq_hash[pic->irq_start];
_pirq_hash_idx += irq_nr;

Example (GICv2 with 988 SPIs):

  • **irq_nr = max_irq + 1 - 32** (SGI/PPI handled separately)
  • Virtual IRQs might be **[RT_MAX_IPI, RT_MAX_IPI + irq_nr)**
  • **irq_index = hwirq - 32** for SPI hwirq 32 → index 0

Mapping API

int rt_pic_config_irq(struct rt_pic *pic, int irq_index, int hwirq);
int rt_pic_config_ipi(struct rt_pic *pic, int ipi_index, int hwirq);
Input Meaning
**irq_index** Offset within this PIC's window
**hwirq** Hardware ID in that controller
Return value Global virtual IRQ = **pic->irq_start + irq_index**

Lookup:

API Returns
**rt_pic_find_irq(pic, irq_index)** **&pic->pirqs[irq_index]**
**rt_pic_find_pirq(pic, virtual_irq)** **pirq** if **virtual_irq** in range
**irq2pirq(irq)** Global lookup for **rt_pic_irq_*** wrappers

<tt>struct rt_pic_irq</tt> fields

Field Role
**irq** Virtual IRQ (global); **-1** = slot unused
**hwirq** Controller-specific line
**mode** Edge/level (RT_IRQ_MODE_*)
**pic** Owning **struct rt_pic ***
**parent** Cascade parent **pirq**
**children_nodes** Routed children if **RT_PIC_F_IRQ_ROUTING**
**isr** Handler chain

IPI vs device IRQ

IPI Device IRQ
Config **rt_pic_config_ipi** **rt_pic_config_irq** or **irq_map**
Affinity All CPUs set in **config_ipi** Per **irq_set_affinity**
Dispatch GIC trap reads hwirq < 16 → **rt_pic_find_ipi** hwirq ≥ 32 → **rt_pic_find_irq**

Debug

With MSH: **list_irq** / **list_irq all** ( **pic.c** ) dumps virtual IRQ, PIC name, hwirq, mode, handlers.

**rt_pic_linear_irq** comment: intended for production PIC registration; **rt_pic_cancel_irq** only for failed init teardown.


Pitfalls

Issue Mitigation
**MAX_HANDLERS too small** Sum all PIC **irq_nr** + IPI + headroom
Use hwirq as **rt_pic_attach_irq argument** Always use virtual irq from **rt_dm_dev_get_irq** / **irq_map**
Re-**config_irq** on busy slot **config_pirq** asserts empty ISR lists if PIC changes

See also