ARM64 上一个核挂了中断可以迁移到其他核吗

原始问题:ARM64 上一个核挂了(nocmt, 不执行指令了),那么中断可以迁移到其他核上吗? · 2026-08-05

结论

分两种截然不同的情况,答案不同:

场景 能否迁移 机制
正常 CPU hotplug 下线(CPU 还活着、能执行指令) ✅ 可以 软件主动迁移:irq_migrate_all_off_this_cpu()
核挂死(不执行指令,如 hard lockup / 断电 / 死循环关中断) ⚠️ 基本不能(软件路径失效,硬件路由仍指向死核) 依赖硬件路由 + 活核软件介入,且 PPI 物理上不可迁移

一、正常 hotplug:软件主动迁移(可迁移)

被下线 CPU 自己执行 __cpu_disable()(运行在被下线核上):

arch/arm64/kernel/smp.c:302-327
    __cpu_disable()
    ├── set_cpu_online(cpu, false)
    ├── ipi_teardown(cpu)
    └── irq_migrate_all_off_this_cpu()

irq_migrate_all_off_this_cpu()(kernel/irq/cpuhotplug.c:171)遍历所有 active IRQ,逐个调用 migrate_one_irq()(kernel/irq/cpuhotplug.c:53):

  1. 跳过 per-cpu 中断(irqd_is_per_cpu,即 PPI/SGI 类);
  2. 对普通中断(SPI),用当前 affinity 掩码 ∩ cpu_online_mask 选新目标;若 affinity 里没有在线核,则强制改到 cpu_online_mask(brokeaff = true);
  3. 调用 chip->irq_set_affinity。

GICv3 的实现是 gic_set_affinity()(drivers/irqchip/irq-gic-v3.c:1769):

cpu = cpumask_any_and(mask_val, cpu_online_mask);
...
offset = convert_offset_index(d, GICD_IROUTER, &index);
reg = gic_dist_base(d) + offset + (index * 8);
val = gic_cpu_to_affinity(cpu);
gic_write_irouter(val, reg);   /* 重写中断路由寄存器 */

即:重写 GICD_IROUTERn,把该 SPI 的路由从下线核改指到在线核。之后中断直接由新目标核接收。注意这个流程的前提是 CPU 还活着——它要在自己身上执行完这套代码。

二、核挂死(不执行指令):迁移基本失效

如果核真的挂死(不取指、不响应中断、不响应 IPI),__cpu_disable() 永远执行不到,软件迁移路径直接失效。此时能否”迁移”取决于三层:

1. SPI(共享外设中断):路由仍指向死核,除非活核介入

2. PPI(私有外设中断):物理上不可迁移

3. SGI / IPI:死等

三、硬件层面的”多目标路由”例外

GICv3 的 GICD_IROUTERn 支持把 SPI 配置为多 PE 目标:

若驱动/平台把中断配成多目标(如 irq_set_affinity 指定多个 CPU),即使其中一个目标挂死,其他目标仍能收到并处理——这是唯一不依赖软件迁移的硬件级”容错”。但 Linux 默认对普通 SPI 使用单目标路由,gic_set_affinity() 中 cpumask_any_and 也只选一个核。

四、与 TLBI 的联系(呼应你上一个问题)

死核对系统最大的威胁不是”中断没人处理”,而是破坏一致性协议:

机制 依赖 死核后果
broadcast TLBI(vmalle1is 等) 所有核响应 DVM 广播并完成本地刷 TLB 死核不响应 → TLBI 无法确认完成(DSB ISH 语义被破坏)→ 该核可能残留 stale TLB,后续引用已释放内存
IPI(smp_call_function) 目标核响应并回 ACK 死等 → 活锁
中断路由 GIC 分发器 SPI 卡死/丢失,PPI 永久无人处理

这正是 arm64 社区的一贯态度:宁可 panic 整个系统(NMI watchdog / pseudo-NMI),也不允许在”某核不响应”的状态下继续运行——因为任何需要全核参与的同步原语(TLBI、IPI、fence)都会在死核处断链,静默运行只会积累内存一致性错误。

五、工程建议(OLK 分支视角)

  1. 区分”软件下线”与”硬件死亡”:echo 0 > /sys/devices/system/cpu/cpuN/online 是安全路径,中断迁移由 irq_migrate_all_off_this_cpu 保证;若用 cpuset 隔离 + isolcpus,隔离核上的中断需要手工 smp_affinity 或 irqbalance 处理。
  2. 若需要”挂死核不 panic 系统”:必须有硬件级保证(如 PSCI CPU_OFF 之前该核已完成退出、且 GIC 路由已改指),否则应触发 panic——这与 upstream 的做法一致。
  3. 关注 GICv3 的 1-of-N 配置:对关键中断(如存储/网络控制器)可评估多目标路由,但注意 gic_set_affinity 当前只选单核,需要厂商补丁或平台驱动配合。

参考代码位置(OLK-6.6 基线 c98e10d93310):

⚠️ 免责声明

本站内容均由 AI 基于公开知识辅助生成,仅供学习参考,请勿直接引用作为依据。作者不对信息的准确性、完整性及适用性作保证,亦不对因使用本站内容产生的任何损失承担责任。