2026/4/6 7:28:05
网站建设
项目流程
北京城乡与建设厅官方网站查询,北京seo网站结构优化,苏州优化方式,网站推广的方法ppt想必大家因为硬件配置差异#xff0c;而引发的嵌入式驱动问题比比皆是#xff0c;也都不陌生。前段时间#xff0c;前端反馈不同板子的 Wi-Fi 模块表现完全不同#xff1a;同一款芯片#xff0c;在有的板子上正常#xff0c;在有的板子上却因为 PCIe BAR 空间大小超出 So…想必大家因为硬件配置差异而引发的嵌入式驱动问题比比皆是也都不陌生。前段时间前端反馈不同板子的 Wi-Fi 模块表现完全不同同一款芯片在有的板子上正常在有的板子上却因为 PCIe BAR 空间大小超出 SoC DTS 限制而发生 Dump。当然这个问题最终通过排查 strapping pin 解决了但让我也意识到 PCIe 协议的复杂。今天我们从这个案例出发聊聊 PCIe 底层那些事儿PCIe 配置空间和 MSI 中断机制。1. 案发现场2MB 还是 32MB事情是这样的。我们在调试一款基于 Qualcomm QCA206x 的 Wi-Fi 设备时遇到了一个 Crash。从现场 dump 出来的 PCIe 配置空间数据来看出现了一个令人差异的现象左边的板子BAR0 空间读出来是 2MB 。右边的板子BAR0 空间读出来竟然是 32MB 。具体如下图所示由于 SoC 的 PCIe DTS 限制了分配空间的大小32MB 的需求超出了预设范围导致驱动加载失败并触发系统 Dump。解决方案经过查阅 QCA206x 的 Datasheet我们发现这款芯片的 PCIe BAR Size 是硬件可配的。问题的根源在于 GPIO_54 和 GPIO_53 这两个 strapping pin 的配置不同基于如上的问题我们以“打破砂锅问到底”的精神来探一探 PCIe 的相关知识系统是如何知道设备需要 2MB 还是 32MB 空间的PCIe 配置空间里到底藏着什么秘密伴随 PCIe 出现的 MSI/MSI-X 中断又是如何协同工作的接下来我们进入正题。2.PCI 配置空间PCIe 设备并不像传统内存那样直接被 CPU 访问它拥有自己独立的配置空间Configuration Space。PCIe 为每个 Function 定义了一个 4KB 大小的配置空间用于设备发现、能力描述和资源配置。但这 4KB 并不映射到系统物理内存而是 CPU 通过 PCIe Host Controller 间接访问的。我们最关注的 BARBase Address Register就住在这里。配置空间中的 BAR 寄存器仅用于描述设备所需的地址窗口其指向的 BAR 空间属于 PCIe MMIOMemory Mapped Input/Output资源而不属于配置空间本身。PCIe 枚举的核心流程几乎完全围绕配置空间的各个区域展开。下面我们详细讲一讲 PCIe 配置空间的每个区域。2.1 0x000–0x03F16 DWs 64 BytesPCI Configuration Header标准头这是 PCI / PCIe 共用、最关键的 64 字节Header它决定了设备的“身份”。PCIe 配置空间头有如下两种类型Type 0 header用于非桥设备Endpoint比如我们的 Wi-Fi 网卡。它直接告诉你“我需要多少 BAR 空间我支持什么中断”。Type 1 header用于 Bridge/Switch。它主要描述“我下面管理了谁我要转发哪些地址”。如上图所示Type 0 和 Type 1 用于区分 Function 在拓扑中的角色。Type 0 Header 用于非桥设备Endpoint描述其自身所需的 BAR 和中断能力而 Type 1 Header 用于桥和交换端口描述其对下游总线的管理能力包括 Bus 号分配和地址窗口转发。操作系统在 PCIe 枚举过程中正是通过 Header Type 判断设备角色并据此决定资源分配与拓扑展开。简单总结Type 0 描述“我是谁”Type 1 描述“我下面还有谁”。2.2 0x040–0x0FF48 DWs 192 BytesCapabilities 区兼容 PCI 的能力链这是 PCIe 为了向后兼容 PCI 而保留的结构。在这个区域内各种 Capability 以链表方式存在每个 Capability 都有Capability IDNext Pointer常见的 Capability 包括Power ManagementMSI / MSI-XMSI / MSI-X 就是在这里定义的PCI Express CapabilityVendor Specific Capability2.3 0x100–0xFFF960 DWs 3840 BytesPCIe Extended Configuration SpacePCIe 专属Extended Capability 也是链表结构从 0x100 开始每个 Extended Capability 有Capability IDVersionNext Pointer3. 从 INTx 到 MSI-X中断的进化史在排查 Wi-Fi 驱动问题时中断机制往往是另一个重灾区。一次 Wi-Fi Rx 吞吐异常背后的真相 —— 从 DMA mask、IOMMU 到 SWIOTLB 的完整内核复盘3.1INTx中断机制的困境在 MSI 出现之前PC 系统一直沿用基于引脚的中断机制Pin-based Interrupts也就是我们常说的 INTx 或传统中断Legacy Interrupts。其工作原理为它的工作原理非常直观PCI 设备通过物理中断线INTA#、INTB#、INTC#、INTD#向中断控制器如经典的 8259A发送电平信号中断控制器收到信号后再通知 CPU 进行处理。然而随着系统日益复杂这种机制逐渐暴露出了相关弊端中断资源匮乏整个系统只有有限的中断线随着外设的增多中断共享变得不可避免。性能损耗当多个设备共享同一中断线时CPU必须轮询Polling所有挂在该线上的设备才能确认究竟是谁触发了中断效率极低。3.2 变革MSI 的诞生带内信令为了打破这种物理连线的困境PCI 2.2 规范1998年首次引入了 MSIMessage Signaled Interrupts消息信号中断作为一种可选功能。中断不再依赖专用的物理信号线传递。采用“带内信令”机制通过内存写入事务Memory Write Transaction来发送中断消息。设备只需向一个特定的内存地址写入特定的数据值这个写操作本身就代表了一个中断请求。3.3 进阶MSI-X 的高性能扩展现代系统随着高性能设备如多队列网卡、NVMe 存储的爆发MSI 原有的 32 个中断向量限制变得不够用。为此PCI 3.0 规范2004年推出了 MSI 的扩展版本 —— MSI-X。这里的“X”即代表 eXtended扩展与增强。MSI-X 相比 MSI 在以下三个关键维度实现了显著增强中断向量数量MSI 最多仅支持 32 个中断向量而 MSI-X 将这一上限大幅提升至 2048 个。分配灵活性MSI 比较“死板”强制要求分配的中断号必须连续MSI-X 则打破了这一限制允许分配一组不连续的中断向量。信息存储位置MSI 的中断信息受限于 PCI 配置空间的大小而 MSI-X 改为使用专门的 MSI-X 表MSI-X Table存放该表位于容量更大的 PCI BAR 空间中。下图也展示不同类型 PCIe 设备的中断投递过程。3.4 MSI/MSI-X 功能结构体PCIe 设备有两种功能结构体MSI 功能结构体或者 MSI-X 功能结构体。通常情况下一个 PCIe 设备仅包含一种结构体或者为 MSI 功能结构体或者为 MSI-X 功能结构体。PCIe 设备提交 MSI/MSI-X 中断时都是向 MSI/MSI-X 功能结构体中的 Message Address 的地址写 Message Data 数据。同时MSI 功能结构体是通过功能链表存储在 PCIe 配置空间中具体如下所示具体过程为位于标准 Type 0非桥设备或 Type 1桥设备配置头中的 Capabilities Pointer配置空间的 34h 偏移处存储一个 8 位的偏移值它指向设备配置空间PCI Configuration Space的 40h ~ FFh 区域中的某个位置。这个位置存放着链表中的第一个 Capability 结构体例如电源管理、MSI 或 PCI Express Capability。地址对齐指向的地址必须是 DWORD 对齐的因此该值的最低两位始终为 0,。无效值00h-3Fh 不是有效的指针值因为这段空间被标准的 PCI 配置头占用。Capabilities Pointer 是整个链表的入口。它指向的第一个结构体以及随后的每一个结构体都遵循标准格式从而允许软件遍历Byte 0Capability ID标识该能力的类型例如01h 电源管理05h MSI10h PCI Express Capability。Byte 1Next Capability Pointer指向链表中下一个 Capability 结构体的偏移地址。如果这是链表的最后一项则该字段为 00h。通过这种机制系统软件可以从 Header 中的 Capabilities Pointer 开始顺藤摸瓜找到设备支持的所有 PCI 兼容能力。备注只有当 PCI Status Register偏移 06h中的 Capabilities List 位Bit 4被置为 1 时Capabilities Pointer 才是有效的。如果该位为 0表示设备没有实现扩展能力链表软件应忽略此指针通常读回为 0。PCI Status Register 的位置如上图左上角红框所示。接下来我们以 ASPM 为例子来展示下 PCI 功能链表的工作机制如下所示3.4.1 MSI 功能结构体MSI 功能结构有 32-bits 和 64-bits 两种使用 Masking 机制使能或者禁止某个中断源。具体结构如下图所示PCIe 总线规定当一个设备使用 MSI 中断时最多可以使用 32 个中断向量从而一个设备最多可以发送 32 种中断请求。Mask Bits 字段由 32 位组成其中每一位对应一种中断请求。当相应位为 1 时表示对应的中断请求被屏蔽为 0 时表示允许该中断请求。系统软件可读写该字段系统初始化时该字段为全 0表示允许所有中断请求。3.4.2 MSI-X 功能结构MSI-X 功能结构比 MSI 功能结构略微复杂一些。在该结构中使用 MSI-X Table 存放该设备使用的所有 Message Address 和 Message Data 字段这个表格存放在该设备的 BAR 空间中从而 PCIe 设备可以使用 MSI-X 机制时中断向量号可以并不连续也可以申请更多的中断向量号。MSI-X 功能结构如下图所示Table BIRBAR Indicator Register该字段存放 MSI-X Table 所在的位置PCIe 总线规范规定 MSI-X Table 存放在设备的 BAR 空间中。该字段表示设备使用 BAR0~5 寄存器中的哪个空间存放 MSI-X Table。该字段由三位组成其中 06000~0101 与 BAR0 ~ 5 空间一一对应。Table Offset该字段存放 MSI-X Table 在相应 BAR 空间中的偏移。PBAPending Bit ArrayBIR该字段存放 Pending Table 在 PCIe 设备的哪个 BAR 空间中。在通常情况下Pending Table 和 MSI-X Table 存放在 PCIe 设备的同一个 BAR 空间中。PBA Offset该字段存放 Pending Table 在相应 BAR 空间中的偏移。3.4.2.1 MSI-X Table StructureMSI-X Table Structure 的组成如下所示MSI-X Table Structure 由多个 Entry 组成其中每个 Entry 与一个中断请求对应。其中每个 Entry 中有四个参数其含义如下所示Msg Addr当 MSI-X Enable 位有效时该字段存放 MSI-X memory write 事务的目的地址的低 32-bit该双字的 31:2 字段有效系统软件可读写1:0 字段复位时为 0PCIe 设备可以根据需要将这个字段设为只读或者可读写。不同的处理器填入该寄存器的数据并不相同。Msg Upper Addr该字段可读写存放 MSI-X memory write 事务的目的地址的高 32-bit。Msg Data该字段可读写存放 MSI-X 报文使用的数据。其定义与处理器系统使用的中断控制器和 PCIe 设备相关。Vector Control该字段可读写该字段只有第 0 位即 Per Vector Mask 位有效其他位保留。当该位为 1 时PCIe 设备不能使用该 Entry 提交中断请求为 0 时可以提交中断请求。该位在复位时为 0。Per Vector Mask 位的使用方法与 MSI 机制的 Mask 位类似。3.4.2.2 MSI-X PBA StructureMSI-X PBA Structure 的组成如下图所示QWORD是8个字节在 MSI-X PBA Structure 中一个 Entry 由 64-bit 组成其中每一位与 MSI-X Table Structure 中的一个 Entry 对应即 MSI-X PBA Structure 中的每一个 Entry 与 MSI-X Table Structure 的 64 个 Entry 对应。与 MSI 机制类似Pending 位需要与 Per Vector Mask 位配置使用。当 Per Vector Mask 位为 1 时PCIe 设备不能立即发送 MSI-X 中断请求而是将对应的 Pending 位置 1当系统软件将 Per Vector Mask 位清零时 PCIe 设备需要提交 MSI-X 中断请求同时将 Pending 位清零。4. MSI 到底是谁的能力前面我们聊了PCIe MSI/MSI-X 的历史和实现过程相比大家也和我有类似的问题MSI 是中断控制器的能力还是 PCIe 的能力一个 SoC 如何实现 MSI 中断的能力下面我们就详细的讲一讲。4.1 先说结论这是一个典型的“协议定义”与“系统落地”的视角差异。MSI 在“协议定义上”属于 PCIe 能力但在“系统实现上”它必须由中断控制器来真正完成。换句话说PCIe 负责“如何发 MSI”中断控制器负责“MSI 到来后如何变成中断”。这两个角色缺一不可。4.2 协议视角MSI 是谁定义的从协议归属上看MSI 毫无疑问是 PCI/PCIe 规范的一部分。这也是为什么我们在驱动开发时看到的 MSI/MSI-X Capability 结构体静静地躺在 PCIe Configuration Space 中。从 PCIe 设备Endpoint视角看MSI 是什么对设备而言MSI 极其简单它甚至不觉得自己是在“发中断”。设备只做三件事在配置空间里暴露 MSI Capability。保存系统分配的 MSI target address 和 Data。需要中断时向 Address 发起一次 Memory Write TLP。到此为止PCIe 设备的责任就结束了。那么发了 MSI就一定有中断吗不一定。这里有一个残酷的真相MSI 本质上只是一次“写操作”。如果这次 Write 没有被任何硬件模块捕获那么断信号永远不会产生。4.4 系统视角真正“拥有 MSI 能力”的是谁答案非常明确中断控制器Interrupt Controller。在 SoC 的系统架构中MSI 的“终点”必须是中断控制器如 ARM GICv3。核心逻辑链条如下PCIe Device 发起 Memory WriteMSI数据流经总线到达某个特定地址Doorbell触发硬件逻辑生成中断信号给 CPU谁能把一次 Memory Write 转换成一个 CPU 可感知的中断事件只有中断控制器。它必须具备“理解 MSI 写”的能力暴露 Doorbell它在总线上占据一段地址空间。解析 Frame它规定了写入什么数据代表哪个中断号。4.5 那 PCIe 控制器 RC在演什么角色很多人误以为 RCRoot Complex是 MSI 的所有者其实不然。RC 只是“转运站”和“地址接入者”。它负责接收来自 EP 的 MSI Write TLP。透传通过 iATU地址转换单元将 TLP 转发出去。路由确保这次 Write 被送到正确的 SoC 地址即中断控制器的 Doorbell 地址。RC 既不决定中断号也不维护中断状态更不直接拉动 CPU 的中断线。那么如果 SoC 要“支持 MSI”能力应集成在哪具体如下所以真正“拥有 MSI 处理能力”的硬核组件只能是中断控制器。接下来我们讲讲 PCIe BAR。5. PCIe BAR 机制详解从原理到实现在 PCIe 设备驱动开发与系统架构中BAR (Base Address Register) 是主机Host与设备Device交互的基石。负责把设备资源“挂载”到主机地址空间。BAR 的本质并不是设备内部的物理存储本身而是设备向系统发出的一个“资源请求窗口”。资源映射它是 CPU 访问设备内部资源如寄存器、片上 RAM、Doorbell 机制、MSI-X Table 等的桥梁。工作流程在枚举过程中设备通过 BAR 告诉系统“我需要一段多大的地址空间类型是内存Memory还是 I/O”操作系统OS分配一段系统总线地址Physical Address这段地址被填入 BAR 中即映射。之后 CPU 访问这段主机地址经由 ioremap 得到的虚拟地址PCIe 控制器会将请求捕获并路由给设备TLP最终设备响应请求。5.1 系统如何计算 BAR 空间大小回到文章最开始的 Bug为什么不同 Strapping Pin 会导致 BAR 大小读出来不同系统到底是怎么算出 BAR 大小的这涉及到 BAR 的探测机制——“写全 1 探测法” 。写全 1软件OS 枚举阶段向 BAR 寄存器写入 0xFFFF_FFFF。回读硬件会将不可写的低位代表大小强制拉低只有可写的高位保留为 1 。计算通过公式 Size ~(ReadBack ~0xF) 1 算出大小 。在我们的案例中QCA206x 芯片根据 Strapping Pin 的电平在硬件底层改变了 BAR 寄存器中可写位的掩码。当 Pin 配置为 00 时硬件逻辑锁住了更多低位导致算出来是 2MB。当 Pin 配置为 10 时释放了高位算出来是 32MB 。由于驱动和 DTS 没匹配上这个硬件变化自然就 Crash 了。5.2 Type 0 Header 与位定义当 BAR 的大小确定后我们来看 BAR 寄存器内部的具体定义以 Type 0 Header 为例。BAR 的低位Bit 0~3决定了这段空间的“属性”而高位决定了“基地址”。上图中 BAR0 的低位解释如下典型 PCI/PCIe Type 0 header BARbit0I/O 空间还是 Memory 空间0 Memory BARMMIO1 I/O BAR现代 PCIe 上很少用bit1~bit2地址解码类型Memory BAR 才有00 32-bit decoding10 64-bit decoding01 低 1MB历史保留bit3Prefetchable0 non-prefetchable1 prefetchable含义是这段区域允许预取/缓存、读无副作用、可被 CPU/桥预取缓存典型为显存/窗口映射内存。设备寄存器通常是 non-prefetchable。bit4 以上基地址对齐强制因为低位被类型占用而且 BAR 必须按大小对齐5.364-bit BAR 扩展随着显卡显存和 AI 加速器内存的增大32 位地址空间4GB已无法满足需求。PCIe 规范通过组合两个相邻的 32 位 BAR 来实现 64 位寻址。组合机制BAR n偶数索引存储 64 位地址的低 32 位。BAR n1奇数索引存储 64 位地址的高 32 位。当 OS 扫描到 BAR n 的 Bit 1~2 为 10 (64-bit decoding) 时它会自动将 BAR n 和 BAR n1 视为一个整体对。BAR n 负责处理低位地址与属性位。BAR n1 单纯用于扩展高位地址范围。在你的驱动生涯中有没有遇到过类似的坑呢欢迎在评论区分享你的经历。独行者速众行者远。连接 · 交流 · 共创。欢迎加入微信群聊Join US保持联系保持好奇。若二维码过期或群满请添加微信19901741315备注“入群”拉你一把。