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 定义了一个消费者/生产者位,以区分桥接寄存器(“消费者”)和桥接孔径(“生产者”)[4, 5],但早期的 BIOS 没有正确使用该位。结果是,当前的 ACPI 规范仅为扩展地址空间描述符定义了消费者/生产者;在较旧的 QWord/DWord/Word 地址空间描述符中应忽略该位。因此,操作系统必须假设所有 QWord/DWord/Word 描述符都是窗口。
在添加扩展地址空间描述符之前,消费者/生产者位的失败意味着无法在 PNP0A03/PNP0A08 设备本身中描述桥接寄存器。解决方法是在 PNP0C02 全局捕获设备中描述桥接寄存器(包括 ECAM 空间)[6]。除了 ECAM 之外,桥接寄存器空间无论如何都是特定于设备的,因此通用的 PNP0A03/PNP0A08 驱动程序 (pci_root.c) 不需要了解它。
新的架构应该能够在 PNP0A03 设备中使用“消费者”扩展地址空间描述符来表示桥接寄存器,包括 ECAM,尽管对 [6] 的严格解释可能会禁止这样做。旧的 x86 和 ia64 内核假设所有地址空间描述符,包括“消费者”扩展地址空间描述符,都是窗口,因此在这些架构上以这种方式描述桥接寄存器是不安全的。
PNP0C02 “主板”设备基本上是一个全局捕获。除了“不要将这些资源用于其他任何用途”之外,没有其他编程模型。因此,PNP0C02 _CRS 应该声明任何(1)ACPI 命名空间中任何其他设备对象下的 _CRS 未声明的地址空间,并且 (2) 不应由操作系统分配给其他内容的地址空间。
除非有用于配置访问的标准固件接口,例如 ia64 SAL 接口 [7],否则 PCIe 规范需要增强配置访问方法 (ECAM)。主桥消耗 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] 消费者/生产者
1 – 此设备消耗此资源
0 – 此设备生成并消耗此资源
- [5] ACPI 6.2,第 19.6.43 节
ResourceUsage 指定内存范围是否由此设备消耗 (ResourceConsumer) 或传递给子设备 (ResourceProducer)。如果未指定任何内容,则假定为 ResourceConsumer。
- [6] PCI 固件 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 固件 3.2,第 4.1.2 节
MCFG 表是一个 ACPI 表,用于传达与在启动时可供操作系统使用的 PCI 段组中的非热插拔 PCI 段组范围相对应的基址。这对于 PC 兼容系统是必需的。
MCFG 表仅用于传达与在启动时可供系统使用的 PCI 段组相对应的基址。
- [9] PCI 固件 3.2,第 4.1.3 节
_CBA(内存映射配置基址)控制方法是一个可选的 ACPI 对象,它返回热插拔主桥的 64 位内存映射配置基址。_CBA 返回的基址是处理器相关地址。_CBA 控制方法的求值结果为整数。
此控制方法出现在主桥对象下。当 _CBA 方法出现在活动的主桥对象下时,操作系统会评估此结构,以标识与 _CRS 方法中指定的总线编号范围的 PCI 段组对应的内存映射配置基址。包含 _CBA 方法的 ACPI 命名空间对象也必须包含相应的 _SEG 方法。