RT-Thread RTOS
An open source embedded real-time operating system
PIC and PCI MSI

MSI / MSI-X at the PIC layer

PCI message-signalled interrupts need an interrupt controller that can allocate a vector, build the MSI message (address + data), and deliver it into the same virtual IRQ space as wired IRQs.

PCI enable path: PCI MSI and MSI-X. Wiring to PIC: this page.


What the MSI-capable PIC must do

Responsibility Typical rt_pic_ops
Hand out a virtual IRQ per MSI/MSI-X vector **irq_alloc_msi** / **irq_free_msi**
Tell PCI what to write to the device **irq_compose_msi_msg**, **irq_write_msi_msg**
Mask / unmask at hardware Often **irq_mask/irq_unmask** + **rt_pci_msi_*** helpers
Reach the CPU interrupt architecture Usually cascade to a parent PIC line (PIC cascade and routing) or a dedicated status ISR that demuxes bits

The PIC driver does not replace PCI config-space MSI capability setup — that stays in **pci/msi/**. The PIC side owns vector backing and message programming.


Call flow (PCI → PIC)

pci/msi: rt_pci_msi_setup_irqs(pdev, nvec, type)
|
v
pdev->msi_pic->ops->irq_alloc_msi(pic, msi_desc)
| reserve hw line / table entry
| rt_pic_config_irq → virtual irq
| optional rt_pic_cascade(child_pirq, parent_irq)
|
v
irq_compose_msi_msg(pirq, &msg) → rt_pci_msi_write_msg
|
v
Driver: rt_pic_attach_irq(virtual_irq, handler, …)

**struct rt_pci_device::msi_pic** must point at the **struct rt_pic** that implements these ops (from DT **msi-parent**, **msi-map**, or board setup).


Implementing <tt>irq_alloc_msi</tt>

Typical steps inside the provider:

  1. Pick a free hwirq / table index (bitmap or hardware allocator).
  2. **rt_pic_config_irq(pic, index, hwirq)** — obtain global virtual IRQ for **rt_pic_attach_irq**.
  3. If this PIC is not CPU-root: **parent_irq = parent_pic->ops->irq_map(...)** then **rt_pic_cascade(pirq, parent_irq)** so the parent line fires when MSI is triggered.
  4. Store **msi_desc** on **pirq** if the PCI layer needs it for mask/unmask.
  5. Return virtual IRQ (not hwirq) to **pci/msi/irq.c**.

**irq_free_msi**: **rt_pic_uncascade**, release index, clear bitmap.


<tt>irq_compose_msi_msg</tt>

Fill **struct rt_pci_msi_msg**:

Field Meaning
**address_lo / address_hi** Doorbell or MSI frame write target
**data** Vector data written by device

SoC-specific: address may be a dedicated MSI window or a parent SPI doorbell — implement per TRM, not in the generic framework.


MSI vs MSI-X

MSI MSI-X
Vectors Often power-of-two block, may need contiguous virtual IRQs Per-table-entry allocation common
Table Config space Often BAR-mapped table — map BAR before unmask
PIC Same ops; PCI layer passes count / type Same ops; one **irq_alloc_msi** per entry typical

DT (optional)

Platforms may describe:

  • **msi-parent** — phandle to MSI-capable interrupt controller
  • **msi-map / msi-map-mask** — map PCI requester ID to controller + specifier

Parsing is SoC-specific; result must be **pdev->msi_pic** before **rt_pci_msi_enable**.


Pitfalls

Issue Mitigation
**RT_PCI_MSI disabled** Ops stubbed; PCI MSI APIs no-op
**msi_pic NULL** Set in host/PCI probe before enable
Return hwirq to PCI Return virtual IRQ from **irq_alloc_msi**
No parent link MSI never reaches CPU — cascade or demux ISR
MSI-X table unmapped Enable only after BAR iomap in PCI setup

See also