跳到主要内容

IRQ 解析与注册

IRQ 路径使用 domain 化的 IrqId 作为运行时注册 key。FDT、ACPI、PCI、manual/static 注册都会先得到一个 BindingInfo,再经 register_*_with_info 注册到 rdriverdrive 只把 ACPI/FDT probe metadata 交给 resolver,不把平台 IRQ route/source 记录混进自己的设备 registry。

核心源码:

源码职责
drivers/ax-driver/src/binding_info.rsBindingInfoBindingIrqBindingIrqSourcePciIrqRequirement
drivers/ax-driver/src/binding_resolver.rsFDT/ACPI/PCI IRQ binding 解析入口
drivers/interface/rdif-base/src/irq.rsIrqIdIrqSource 类型
components/irq-framework/AcpiGsiRoute、IRQ domain 框架

BindingInfo 模型

BindingInfo 是 probe 阶段携带的 IRQ 元数据,可以携带已经解析好的 IrqId,也可以携带待平台解析的 firmware source:

pub struct BindingInfo {
irq: Option<BindingIrq>,
}

pub enum BindingIrq {
Id(IrqId), // 已解析的 domain IRQ ID
Source(BindingIrqSource), // 待平台解析的 firmware source
}

pub enum BindingIrqSource {
AcpiGsi(u32), // ACPI 裸 GSI
AcpiGsiRoute(AcpiGsiRoute), // ACPI GSI route(含 trigger/polarity/controller)
FdtInterrupt(FdtIrqSpec), // FDT interrupt specifier
}

pub struct FdtIrqSpec {
pub controller: DeviceId, // interrupt-parent 对应的 intc 设备
pub cells: Vec<u32>, // interrupt specifier cells
}

关键边界:generic driver probe 不调用 rdif_intc::setup_irq_by_fdt() 取得裸数字,避免把 GIC/PLIC/PCH 等控制器本地线号混进 legacy IRQ namespace。

解析时序

这个边界让平台 IRQ namespace 解析留在平台 resolver 侧:

各来源解析规则

FDT 设备

FDT 设备读取第一个 interrupts() 项并连同 interrupt-parent 保存为 BindingIrq::fdt_interrupt_with_controller(...)FdtIrqSpec.controller 是 interrupt-parent phandle 解析后对应的 DeviceId(已注册的 rdif-intc 设备),cells 是原始 interrupt specifier。运行时在注册 handler 前调用 ax_hal::irq::resolve_irq_source(...),由平台 IRQ resolver 解析并执行 interrupt-controller setup。

ACPI 设备

ACPI PCI INTx route 保存为 BindingIrq::acpi_gsi_route(...),保留 trigger、polarity、controller 和 input 等元数据。x86 IOAPIC 等平台 resolver 使用这些信息执行控制器 setup,而不是把 route flatten 成裸 GSI。普通 ACPI 设备读取第一个 AcpiGsiRoute,先从 registry 查询匹配的 ACPI GSI Intc,调用 setup_irq_by_acpi(route) 取得 irq number。

PCI endpoint

PCI 设备先在枚举阶段计算 INTx swizzle route,再由 ax-driver::pci::resolve_intx_binding() 按以下顺序返回 BindingIrq

  1. ACPI route(_PRT 表)
  2. FDT interrupt-map
  3. 已注册 legacy route
  4. interrupt_line 配置空间 fallback

静态或未 domain 化平台仍可返回 legacy IRQ 作为兼容入口。PCI endpoint 的 IRQ 有 optional/required 之分:

pub enum PciIrqRequirement {
Optional, // 无中断也可注册为 None
Required, // 必须解析出 IRQ,否则 probe error
}

Manual / Static

无中断的设备注册为 BindingInfo::empty()irq = None)。静态平台可以直接使用 BindingInfo::with_irq_id(IrqId)with_irq(legacy_irq) 携带已解析的 IRQ。

上层 IRQ 注册

ax-runtimeax-halax-net-ng、StarryOS usbfs 等上层以 IrqId 注册 handler。需要处理 firmware source 的地方应先经 resolve_irq_source(...),不应自行做 usize 算术换算。

网络 IRQ 的 runtime 适配遵循同一方向。ax-net-ng 只暴露网络领域自己的 EthernetIrqActionEthernetIrqOutcome 和注册错误类型,不再在公开 registrar trait 中泄漏 HAL IRQ 细节。ax-runtime 持有 HAL IRQ registration,并把 EthernetIrqAction 放入 boxed HAL callback;因此网络 runtime 只描述“是否需要唤醒 poll 方”,HAL 注册形态留在 ArceOS runtime 边界内。

rdif 内部 IRQ 事件

部分 rdif-* 能力接口(如 rdif-blockrdif-displayrdif-inputrdif-vsock)的 Interface trait 提供 handle_irq() 方法。这些方法只确认中断源并返回可 poll 的 queue mask 或事件,不做 OS wake、不阻塞、不持有 OS 锚,也不在中断上下文推进慢路径完成。

例如 rdif-blockIrqSourceInfo { id, queues } 描述该硬件事件 source 可能影响的 queue mask,它不是平台 FDT/PCI IRQ source,也不写入 rdriveBindingInfo。收到事件后,runtime 或 task-side wrapper 再对相应 queue 调用 poll_request()