6. PCI 主桥的 ACPI 考量¶
一般规则是,除非操作系统有其他方法可以找到它,否则 ACPI 命名空间应描述操作系统可能使用的所有内容 [1, 2]。
例如,没有标准硬件机制来枚举 PCI 主桥,因此 ACPI 命名空间必须描述每个主桥、访问其下方 PCI 配置空间的方法、主桥转发到 PCI 的地址空间窗口(使用 _CRS),以及传统 INTx 中断的路由(使用 _PRT)。
PCI 设备(位于主桥下方)通常不需要通过 ACPI 描述。操作系统可以通过标准 PCI 枚举机制发现它们,使用配置访问来发现和识别设备,并读取和确定其 BAR 的大小。然而,如果 ACPI 为 PCI 设备提供电源管理或热插拔功能,或者如果设备的 INTx 中断由平台中断控制器连接,并且需要 _PRT 来描述这些连接,那么 ACPI 可能会描述 PCI 设备。
ACPI 资源描述通过 ACPI 命名空间中设备的 _CRS 对象完成 [2]。_CRS 就像一个通用化的 PCI BAR:操作系统可以读取 _CRS 并确定正在消耗什么资源,即使它没有设备的驱动程序 [3]。这很重要,因为这意味着旧的操作系统即使在具有操作系统未知的新设备的系统上也能正常工作。新设备可能什么也做不了,但操作系统至少可以确保没有资源与它们冲突。
像 MCFG、HPET、ECDT 等静态表不是用于保留地址空间的机制。静态表用于操作系统在启动早期、在解析 ACPI 命名空间之前需要了解的事物。如果定义了新表,旧的操作系统需要正确运行,即使它忽略该表。_CRS 允许这样做,因为它具有通用性并被旧的操作系统理解;而静态表则不能。
如果操作系统预期管理通过 ACPI 描述的不可发现设备,则该设备将具有特定的 _HID/_CID,告诉操作系统绑定哪个驱动程序,而 _CRS 则告诉操作系统和驱动程序设备的寄存器在哪里。
PCI 主桥是 PNP0A03 或 PNP0A08 设备。它们的 _CRS 应描述它们所消耗的所有地址空间。这包括它们转发到 PCI 总线的所有窗口,以及未转发到 PCI 的主桥自身的寄存器。主桥寄存器包括诸如确定桥下总线范围的辅助/从属总线寄存器、描述孔径的窗口寄存器等。这些都是设备特定的、非架构化的东西,因此 PNP0A03/PNP0A08 驱动程序管理它们的唯一方法是通过包含设备特定详细信息的 _PRS/_CRS/_SRS。主桥寄存器还包括 ECAM 空间,因为它被主桥消耗。
ACPI 定义了一个 Consumer/Producer 位来区分桥接寄存器(“Consumer”)和桥接孔径(“Producer”)[4, 5],但早期的 BIOSes 没有正确使用该位。结果是,当前的 ACPI 规范仅为扩展地址空间描述符定义了 Consumer/Producer 位;在旧的 QWord/DWord/Word 地址空间描述符中应忽略该位。因此,操作系统必须假定所有 QWord/DWord/Word 描述符都是窗口。
在添加扩展地址空间描述符之前,Consumer/Producer 的失败意味着无法在 PNP0A03/PNP0A08 设备本身中描述桥接寄存器。解决方法是在 PNP0C02 包罗万象的设备中描述桥接寄存器(包括 ECAM 空间)[6]。除了 ECAM,桥接寄存器空间都是设备特定的,因此通用的 PNP0A03/PNP0A08 驱动程序 (pci_root.c) 不需要了解它。
新架构应该能够在 PNP0A03 设备中使用“Consumer”扩展地址空间描述符来描述桥接寄存器,包括 ECAM,尽管对 [6] 的严格解释可能禁止这样做。旧的 x86 和 ia64 内核假定所有地址空间描述符,包括“Consumer”扩展地址空间描述符,都是窗口,因此在这些架构上以这种方式描述桥接寄存器是不安全的。
PNP0C02 “主板”设备基本上是一个包罗万象的设备。除了“不要将这些资源用于其他任何目的”之外,没有它们的编程模型。因此,PNP0C02 _CRS 应该声明任何(1)未被 ACPI 命名空间中任何其他设备对象下的 _CRS 声明,且(2)不应由操作系统分配给其他事物的地址空间。
PCIe 规范要求使用增强配置访问方法 (ECAM),除非存在用于配置访问的标准固件接口,例如 ia64 SAL 接口 [7]。主桥消耗 ECAM 内存地址空间并将内存访问转换为 PCI 配置访问。该规范定义了 ECAM 地址空间布局和功能;只有地址空间的基址是设备特定的。ACPI 操作系统从静态 MCFG 表或 PNP0A03 设备中的 _CBA 方法学习基址。
MCFG 表必须描述非热插拔主桥的 ECAM 空间 [8]。由于 MCFG 是一个静态表,无法通过热插拔更新,因此 PNP0A03 设备中的 _CBA 方法描述了热插拔主桥的 ECAM 空间 [9]。请注意,对于 MCFG 和 _CBA,基址始终对应于总线 0,即使桥下总线范围(通过 _CRS 报告)不从 0 开始。
- [1] ACPI 6.2,第 6.1 节
对于任何位于不可枚举总线类型(例如 ISA 总线)上的设备,OSPM 会枚举设备的标识符,并且 ACPI 系统固件必须为每个设备提供一个 _HID 对象……以使 OSPM 能够做到这一点。
- [2] ACPI 6.2,第 3.7 节
操作系统只需读取 ACPI 命名空间,查找具有硬件 ID 的设备即可枚举主板设备。
ACPI 枚举的每个设备在 ACPI 命名空间中都包含 ACPI 定义的对象,这些对象报告设备可能占用的硬件资源 [_PRS]、报告设备当前使用的资源的对象 [_CRS] 以及用于配置这些资源的对象 [_SRS]。这些信息由即插即用操作系统 (OSPM) 用于配置设备。
- [3] ACPI 6.2,第 6.2 节
OSPM 使用设备配置对象来配置通过 ACPI 枚举的设备的硬件资源。设备配置对象提供有关当前和可能的资源要求、共享资源之间的关系以及配置硬件资源的方法的信息。
当 OSPM 枚举设备时,它会调用 _PRS 来确定设备的资源要求。它还可以调用 _CRS 来查找设备的当前资源设置。使用此信息,即插即用系统确定设备应消耗哪些资源,并通过调用设备的 _SRS 控制方法来设置这些资源。
在 ACPI 中,设备可以消耗资源(例如,传统键盘),提供资源(例如,专有 PCI 桥),或两者兼而有之。除非另有说明,否则设备资源被假定取自设备层次结构中设备上方最近的匹配资源。
- [4] ACPI 6.2,第 6.4.3.5.1、2、3、4 节
- QWord/DWord/Word 地址空间描述符 (.1, .2, .3)
通用标志:位 [0] 忽略
- 扩展地址空间描述符 (.4)
通用标志:位 [0] 消费者/生产者 (Consumer/Producer)
1 – 此设备消耗此资源
0 – 此设备生成并消耗此资源
- [5] ACPI 6.2,第 19.6.43 节
ResourceUsage 指定内存范围是由此设备消耗 (ResourceConsumer) 还是传递给子设备 (ResourceProducer)。如果未指定,则假定为 ResourceConsumer。
- [6] PCI Firmware 3.2,第 4.1.2 节
如果操作系统不原生理解保留 MMCFG 区域,则 MMCFG 区域必须由固件保留。MCFG 表中报告的地址范围或由 _CBA 方法(参见第 4.1.3 节)报告的地址范围必须通过声明主板资源来保留。对于大多数系统,主板资源将出现在 ACPI 命名空间的根部(_SB 下),位于具有 EISAID (PNP0C02) _HID 的节点中,并且在这种情况下,不应在根 PCI 总线的 _CRS 中声明资源。资源可以选择通过 Int15 E820 或 EFIGetMemoryMap 作为保留内存返回,但必须始终通过 ACPI 报告为主板资源。
- [7] PCI Express 4.0,第 7.2.2 节
对于与 PC 兼容或未实现允许访问配置空间的处理器架构特定固件接口标准的系统,需要本节中定义的 ECAM。
- [8] PCI Firmware 3.2,第 4.1.2 节
MCFG 表是一个 ACPI 表,用于在启动时向操作系统传达 PCI 段组内非热插拔 PCI 段组范围对应的基址。这对于 PC 兼容系统是必需的。
MCFG 表仅用于传达系统启动时可用的 PCI 段组对应的基址。
- [9] PCI Firmware 3.2,第 4.1.3 节
_CBA(内存映射配置基址)控制方法是一个可选的 ACPI 对象,它返回支持热插拔的主桥的 64 位内存映射配置基址。_CBA 返回的基址是处理器相关地址。_CBA 控制方法评估为一个整数。
此控制方法出现在主桥对象下。当 _CBA 方法出现在活动主桥对象下时,操作系统评估此结构以识别与 _CRS 方法中指定的总线号范围对应的 PCI 段组的内存映射配置基址。包含 _CBA 方法的 ACPI 命名空间对象也必须包含相应的 _SEG 方法。