11. 引导中断

作者:

11.1. 概述

在 PCI Express 上,中断由 MSI 或入站中断消息(Assert_INTx/Deassert_INTx)表示。给定核心 IO 中的集成 IO-APIC 将来自 PCI Express 的传统中断消息转换为 MSI 中断。如果 IO-APIC 被禁用(通过 IO-APIC 表项中的掩码位),则消息会被路由到传统 PCH。这种带内中断机制传统上对于不支持 IO-APIC 的系统和引导过程是必需的。英特尔过去曾使用“引导中断”一词来描述这种机制。此外,PCI Express 协议描述了这种用于 I/O 设备发出 PCI 风格电平中断的带内传统有线中断 INTx 机制。接下来的段落描述了核心 IO 处理 INTx 消息路由到 PCH 的问题以及 BIOS 和操作系统中的缓解措施。

11.2. 问题

当带内传统 INTx 消息被转发到 PCH 时,它们会触发一个新的中断,而操作系统很可能缺少相应的处理程序。当一个中断长时间未被处理时,Linux 内核会将其记录为虚假中断(Spurious Interrupts)。当 IRQ 达到特定计数并出现“无人关心”(nobody cared)错误时,Linux 内核会禁用该 IRQ。这个被禁用的 IRQ 现在会阻止可能共享同一 IRQ 线的现有中断的有效使用。

irq 19: nobody cared (try booting with the "irqpoll" option)
CPU: 0 PID: 2988 Comm: irq/34-nipalk Tainted: 4.14.87-rt49-02410-g4a640ec-dirty #1
Hardware name: National Instruments NI PXIe-8880/NI PXIe-8880, BIOS 2.1.5f1 01/09/2020
Call Trace:

<IRQ>
 ? dump_stack+0x46/0x5e
 ? __report_bad_irq+0x2e/0xb0
 ? note_interrupt+0x242/0x290
 ? nNIKAL100_memoryRead16+0x8/0x10 [nikal]
 ? handle_irq_event_percpu+0x55/0x70
 ? handle_irq_event+0x4f/0x80
 ? handle_fasteoi_irq+0x81/0x180
 ? handle_irq+0x1c/0x30
 ? do_IRQ+0x41/0xd0
 ? common_interrupt+0x84/0x84
</IRQ>

handlers:
irq_default_primary_handler threaded usb_hcd_irq
Disabling IRQ #19

11.3. 条件

目前,使用线程化中断(threaded interrupts)是最有可能触发此问题的情况。线程化中断可能在 IRQ 处理程序唤醒后无法重新启用。这些“一次性”(one shot)条件意味着线程化中断需要保持中断线被屏蔽,直到线程处理程序运行完毕。特别是在处理高数据率中断时,线程需要运行完成;否则,由于发出中断的设备中断仍然活跃,一些处理程序最终会发生堆栈溢出(stack overflows)。

11.4. 受影响的芯片组

传统中断转发机制目前存在于许多设备中,包括但不限于 AMD/ATI、Broadcom 和 Intel 的芯片组。通过以下缓解措施所做的更改已应用于 drivers/pci/quirks.c。

从 ICX 开始,核心 IO 设备中不再有任何 IO-APIC。IO-APIC 只存在于 PCH 中。连接到核心 IO 的 PCIe 根端口的设备将使用原生的 MSI/MSI-X 机制。

11.5. 缓解措施

缓解措施以 PCI quirk 的形式存在。首选方法是首先识别并利用一种方式来禁用路由到 PCH。在这种情况下,可以添加一个用于禁用引导中断生成的 quirk。 [1]

Intel® 6300ESB I/O 控制器集线器
备用基地址寄存器

BIE: 引导中断启用

0

引导中断已启用。

1

引导中断已禁用。

基于 Intel® Sandy Bridge 至 Sky Lake 的 Xeon 服务器
一致性接口协议中断控制
dis_intx_route2pch/dis_intx_route2ich/dis_intx_route2dmi2

当此位被设置时,从 Intel® Quick Data DMA/PCI Express 端口接收到的本地 INTx 消息不会路由到传统 PCH——它们要么通过集成 IO-APIC 转换为 MSI(如果 IO-APIC 掩码位在相应条目中清除),要么不导致任何进一步操作(当掩码位设置时)。

在无法直接禁用路由的情况下,另一种方法是利用 PCI 中断引脚到 INTx 路由表,以便默认将中断处理程序重定向到重新路由的中断线。因此,在无法禁用此 INTx 路由的芯片组上,Linux 内核会将有效中断重新路由到其传统中断。这种处理程序的重定向将防止虚假中断检测的发生,虚假中断检测通常会因未处理计数过多而禁用 IRQ 线。 [2]

配置选项 X86_REROUTE_FOR_BROKEN_BOOT_IRQS 用于启用(或禁用)将中断处理程序重定向到 PCH 中断线。此选项可以通过 pci=ioapicreroute 或 pci=noioapicreroute 进行覆盖。 [3]

11.6. 更多文档

在几份数据手册(下面的 6300ESB 和 6700PXH)中有关于传统中断处理的概述。虽然大体相同,但它提供了关于其随芯片组处理演变的见解。

11.6.1. 禁用引导中断的示例

11.6.2. 处理程序重新路由的示例

如果您有任何未解答的传统 PCI 中断问题,请给我发邮件。

此致,

Sean V Kelley sean.v.kelley@linux.intel.com