拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Linux 内核 PCI 主机桥的 ACPI 设计规则:_CRS、ECAM 与地址空间保留机制

Linux 内核 PCI 主机桥的 ACPI 设计规则_CRS、ECAM 与地址空间保留机制【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux本文基于 Linux 内核仓库中的 Documentation/PCI/acpi-info.rst 展开围绕ACPI 命名空间应当如何描述 PCI 主机桥这一主题讲清 _CRS 为何是正确的地址空间保留机制、PNP0A03/PNP0A08 设备应声明哪些资源、ECAM 空间如何通过 MCFG 表或 _CBA 方法报告并结合 drivers/acpi/pci_root.c 与 drivers/acpi/pci_mcfg.c 的源码解析验证这些规则在内核中的落地方式。读完之后读者应能判断一份 ACPI DSDT 中的 PCI 主机桥描述是否符合规范并理解内核启动时解析这些对象的实际逻辑。一、总则除非有别的发现途径ACPI 命名空间必须描述一切原文档开宗明义给出了一条通用规则ACPI 命名空间应当描述操作系统OS可能用到的所有硬件除非存在其他机制让 OS 发现它们。这条规则的规范依据来自ACPI 6.2 第 6.1 节对于位于不可枚举总线如 ISA 总线上的设备OSPM 枚举它们的标识符而 ACPI 系统固件必须为每个设备提供 _HID 对象使 OSPM 得以完成枚举ACPI 6.2 第 3.7 节OS 枚举主板设备的方式就是遍历 ACPI 命名空间、查找带有硬件 ID 的设备。每个经 ACPI 枚举的设备都包含 ACPI 定义的对象来报告硬件资源[_PRS] 报告设备可能占用的资源[_CRS] 报告当前正在使用的资源[_SRS] 用于配置这些资源。信息由即插即用操作系统OSPM用于配置设备。这条规则的直接推论就是 PCI 主机桥的处境PCI 主机桥不存在标准的硬件枚举机制。没有任何像 PCI 枚举那样的标准硬件通路能让 OS 自己找到主机桥因此 ACPI 命名空间必须逐个描述每个主机桥并且要描述三件事主机桥本身的描述设备对象及其 _HID访问其下方 PCI 配置空间的方法主机桥转发到 PCI 总线的地址空间窗口用 _CRS 声明遗留 INTx 中断的路由方式用 _PRT 声明。而主机桥之下的 PCI 设备一般不需要通过 ACPI 描述——OS 可以借助标准 PCI 枚举机制发现它们通过配置访问发现和识别设备、读取并尺寸化其 BAR。ACPI 只在三种情况下才描述 PCI 设备固件为它们提供电源管理功能固件为它们提供热插拔功能设备的 INTx 中断经由平台中断控制器连接需要 _PRT 来描述这些连接关系。二、_CRS一个泛化的 PCI BARACPI 的资源描述通过 ACPI 命名空间中设备的 _CRS 对象完成ACPI 6.2 第 3.7 节。原文档给出了一个关键类比_CRS 就像一个泛化的 PCI BAR即使 OS 没有对应设备的驱动程序它读取 _CRS 就能弄清楚设备正在消耗什么资源。这一点为什么重要因为它保证了向后兼容一个老 OS 在面对包含它尚不认识的新设备的系统时仍然可以正确工作。新设备可能什么都不做但老 OS 至少能保证没有任何资源与它们冲突。ACPI 6.2 第 6.2 节对此有对应说明OSPM 使用设备配置对象为经 ACPI 枚举的硬件配置资源枚举设备时调用 _PRS 确定资源需求也可调用 _CRS 查询当前资源配置设备可以消费资源如遗留键盘、提供资源如专有 PCI 桥或两者兼具除非另有说明设备资源被假定取自设备层次中最近的匹配上层资源。由此引出第二条重要原则MCFG、HPET、ECDT 等静态表不是地址空间保留机制。静态表的存在目的是让 OS 在引导早期、尚不能解析 ACPI 命名空间之前就必须知道的信息。而一旦定义了新的静态表老 OS 需要即使完全忽略该表也能正确运行——_CRS 之所以能做到这一点是因为它是通用的、被老 OS 所理解的静态表则做不到。因此凡是需要保留一块地址空间不让 OS 分配出去的场景正确答案都是 ACPI 命名空间中的 _CRS而不是某个静态表。对于 OS 预期要管理的不可发现设备non-discoverable device它会被赋予特定的 _HID/_CID告诉 OS 应绑定哪个驱动_CRS 则告诉 OS 和驱动设备寄存器在哪里。三、PCI 主机桥设备模型PNP0A03 / PNP0A08PCI 主机桥是 _HID 为PNP0A03PCI 主机桥或PNP0A08PCIe 主机桥的 ACPI 设备。原文档要求其 _CRS 必须描述它们消耗的全部地址空间具体包括两大类_CRS 应包含的内容说明转发到 PCI 总线的全部窗口桥下方 PCI 设备使用的 MMIO/IO 空间窗口主机桥自身的、不转发到 PCI 的寄存器例如决定桥下方总线范围的 secondary/subordinate bus 寄存器、描述窗口的窗口寄存器ECAM 空间ECAM 由主机桥消耗因此也要包含在内后两类寄存器都是设备相关、非架构化的non-architected内容所以通用的 PNP0A03/PNP0A08 驱动只能经由 _PRS/_CRS/_SRS 来管理它们因为这些对象恰好承载了设备特有的细节。源码印证内核如何识别并解析主机桥在 drivers/acpi/pci_root.c 中ACPI 驱动 ID 表精确对应文档所述的两个 HID外加 CXL 主机桥 ACPI0016static const struct acpi_device_id pci_root_ids[] { {PNP0A03, 0}, {PNP0A08, 0}, {ACPI0016, 0}, { } };见 drivers/acpi/pci_root.c#L44-L46。在 acpi_pci_root_add() 中内核对该设备的解析顺序体现了文档中_CRS 承载总线范围的要求评估 _SEG 确定 PCI 域号drivers/acpi/pci_root.c#L653-L660acpi_evaluate_integer(handle, METHOD_NAME__SEG, ...)失败且不是 AE_NOT_FOUND则报 cant evaluate _SEG 并返回 -ENODEV——这印证了 PCI Firmware 规范含 _CBA 的命名空间对象必须同时含 _SEG的约束在代码层面的体现优先从 _CRS 取 secondary 总线范围取不到再退回 _BBNdrivers/acpi/pci_root.c#L662-L686代码注释明确写道解释 _CBAMMCONFIG 基地址需要下游总线范围的起止值所以它确实应该写在 _CRS 里若 _CRS 中没有只能假定 [_BBN-0xFF] 或 [0-0xFF]并打出FW_BUG no secondary bus range in _CRS的固件缺陷警告。这与原文档bus 0 对应 MCFG/_CBA 基地址即使 _CRS 报告的总线范围不从 0 开始的要求严丝合缝按 HID 标记桥类型drivers/acpi/pci_root.c#L702-L708PNP0A08→ACPI_BRIDGE_TYPE_PCIEACPI0016→ACPI_BRIDGE_TYPE_CXL其余假设非 PCIe 主机桥获取 MCFG 地址root-mcfg_addr acpi_pci_root_get_mcfg_addr(handle);drivers/acpi/pci_root.c#L700随后通过 _OSC 协商 PCIe 特性控制权再调用pci_acpi_scan_root()扫描根桥、创建 PCI 命名空间。四、Consumer/Producer 位一段兼容性历史ACPI 定义了 Consumer/Producer 位来区分桥寄存器Consumer设备自身消费与桥窗口Producer转发给下游。但早期 BIOS 没有正确使用该位其后果被 ACPI 规范固化为QWord/DWord/Word 地址空间描述符General Flags 的 Bit [0] 被忽略ACPI 6.2 第 6.4.3.5 节扩展地址空间描述符ECRSBit [0] 为 Consumer/Producer1 表示设备消费该资源0 表示设备产生并消费该资源ACPI 6.2 第 19.6.43 节亦说明 ResourceConsumer/ResourceProducer 语义未指定时假定 ResourceConsumer。由此产生的直接规则是操作系统必须假定所有 QWord/DWord/Word 描述符都是窗口window。在扩展地址空间描述符出现之前Consumer/Producer 机制的失效意味着根本无法在 PNP0A03/PNP0A08 设备本体内描述桥寄存器。当时的变通方案是把桥寄存器包括 ECAM 空间放进 PNP0C02 catch-all 设备中描述。由于除 ECAM 外桥寄存器空间本来就是设备相关的通用 PNP0A03/PNP0A08 驱动即内核中的drivers/acpi/pci_root.c并不需要知道它们。对新架构的建议是应当可以在 PNP0A03 设备中用 Consumer 扩展地址空间描述符来描述桥寄存器包括 ECAM尽管 PCI Firmware 3.2 第 4.1.2 节的严格解读可能不允许这么做。但要特别注意老 x86 和 ia64 内核会把所有地址空间描述符包括 Consumer 的扩展地址空间描述符都当作窗口因此在那两种架构上采用这种描述方式是不安全的。PNP0C02 主板资源设备的规则PNP0C02 motherboard 设备本质上是一个 catch-all除了别把这些资源挪作他用之外没有编程模型。因此一个 PNP0C02 的 _CRS 应当声明满足以下两个条件的地址空间未被 ACPI 命名空间中任何其他设备对象的 _CRS 声明不应被 OS 分配给别的东西。PCI Firmware 3.2 第 4.1.2 节进一步要求如果 OS 原生不理解 MMCFG 区域的保留固件必须保留它MCFG 表或 _CBA 方法报告的地址范围必须通过声明主板资源来保留——在大多数系统上它出现在 ACPI 命名空间根部\_SB之下一个 _HID 为 PNP0C02 的节点中且这些资源不应同时出现在根 PCI 总线的 _CRS 中。这些资源可选地以 reserved memory 形式出现在 Int15 E820 或 EFIGetMemoryMap 中但必须始终通过 ACPI 作为主板资源报告。内核对 PNP0C02 的识别可参见 drivers/acpi/scan.c#L2247 中的PNP0C02, /* Motherboard resource */驱动匹配项。五、ECAMMCFG 与 _CBA 的分工PCI Express 规范PCIe 4.0 第 7.2.2 节要求除非存在标准的固件配置访问接口例如 ia64 SAL 接口否则必须实现增强型配置访问方法ECAM。主机桥消耗 ECAM 内存地址空间并把内存访问转换为 PCI 配置访问。规范定义了 ECAM 地址空间的布局与功能只有地址空间的基地址是设备相关的。ACPI OS 通过两条途径学习该基地址机制适用对象依据MCFG 静态表非热插拔主机桥MCFG 是静态表热插拔无法更新它PCI Firmware 3.2 第 4.1.2 节MCFG 用于在引导时向 OS 通报非热移除 PCI Segment Group 的基地址PC 兼容系统必须提供_CBA 控制方法位于 PNP0A03 设备内可热插拔主机桥PCI Firmware 3.2 第 4.1.3 节_CBA 返回 64 位内存映射配置基地址处理器相对地址求值结果为 Integer出现 _CBA 的主机桥对象必须同时含对应的 _SEG 方法两条途径共有的语义基地址始终对应 bus 0即使桥下方经 _CRS 报告的总线范围并不从 0 开始。源码印证_CBA 优先于 MCFG在 drivers/acpi/pci_mcfg.c 中内核解析 ECAM 基地址的顺序与上述分工完全一致——第 254 行的注释即/* Use address from _CBA if present, otherwise lookup MCFG */drivers/acpi/pci_mcfg.c#L254先尝试在主机桥 ACPI 设备上求值 _CBA 方法方法不存在时才回退到 MCFG 表查找而acpi_mcfg_allocation结构则用于承载从表中解析出的各段分配。调用入口正是 acpi_pci_root_add() 中的acpi_pci_root_get_mcfg_addr()。六、规范依据索引原文档的全部论述均可追溯到以下规范条目便于读者继续深入核对ACPI 6.2 第 6.1 节不可枚举总线上的设备必须由固件提供 _HID 供 OSPM 枚举ACPI 6.2 第 3.7 节OS 通过遍历命名空间枚举主板设备每设备含 _PRS/_CRS/_SRS 对象ACPI 6.2 第 6.2 节OSPM 调用 _PRS 确定资源需求、调用 _CRS 查询当前配置、调用 _SRS 设置资源设备可消费/提供/兼具资源ACPI 6.2 第 6.4.3.5 节QWord/DWord/Word 描述符 General Flags Bit [0] 忽略扩展描述符 Bit [0] 为 Consumer/ProducerACPI 6.2 第 19.6.43 节ResourceConsumer/ResourceProducer 语义PCI Firmware 3.2 第 4.1.2 节MMCFG 区域必须由固件经 PNP0C02 主板资源保留MCFG 表用于引导时通报非热移除 Segment Group 基地址PCI Firmware 3.2 第 4.1.3 节_CBA 为可热插拔主机桥返回 64 位 MMCFG 基地址且必须伴随 _SEGPCI Express 4.0 第 7.2.2 节PC 兼容系统或无架构特定固件配置访问接口的系统必须实现 ECAM。七、小结面向固件与驱动开发者的检查清单结合原文档与内核源码一份合规的 PCI 主机桥 ACPI 描述应满足每个主机桥都是命名空间中的 PNP0A03/PNP0A08 设备并声明访问配置空间的方法与 _PRT 中断路由其 _CRS 完整覆盖转发到 PCI 的全部窗口、桥自身寄存器以及 ECAM 空间桥寄存器在旧架构上应放入 PNP0C02 主板资源设备且 ECAM 范围不得同时出现在根 PCI 总线 _CRS 中非热插拔桥的 ECAM 基地址写入 MCFG 表可热插拔桥在设备内提供 _CBA与 _SEG 并存_CRS 中必须可解析出 secondary 总线范围否则内核只会降级假定 [_BBN-0xFF]/[0-0xFF] 并上报 FW_BUG所有需要保留的地址空间都通过 _CRS主板资源表达而不是发明新的静态表。相关延伸阅读可参考同目录下的 PCI 子系统总览、PCI sysfs 接口 与 PCI 文档索引它们与本文共同构成了 Linux 内核 PCI 与固件交互的文档体系。【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门