首页/目录/全部文章

全部文章

八个专题的源码、算法与协议笔记都在这里。

笔记列表

BAR、桥窗口与地址资源分配

BAR、桥窗口与地址资源分配

1. 三种地址

PCI 资源分析必须区分:

  1. 设备 BAR 中保存的 PCI Bus Address;
  2. Root Complex outbound window 接收的 CPU Physical Address;
  3. 内核struct resource记录的 CPU 侧资源区间。

Host Bridge window 的 offset 用于pcibios_resource_to_bus()pcibios_bus_to_resource()转换。RK3588 上还需由 DWC iATU 把 CPU 地址窗口变成 PCIe Memory/IO/CFG 事务。

2. BAR 探测

probe.c中的pci_read_bases()读取 BAR。标准 BAR 大小探测通常是:

1
2
3
4
5
保存 BAR
写全 1
读回硬件实现的地址掩码
恢复 BAR
由掩码计算 size

代码还需处理:

  • I/O BAR 与 Memory BAR;
  • 32 位与成对的 64 位 BAR;
  • Prefetchable 属性;
  • Expansion ROM;
  • 固件已分配、未分配及冲突资源;
  • 桥窗口和 SR-IOV VF BAR。

探测时必须谨慎控制PCI_COMMAND_MEMORY/IO解码,避免设备把探测值当成有效地址响应。

3. Host 窗口

控制器驱动解析 DT ranges或 ACPI _CRS,将窗口加入pci_host_bridge->windows。Root Bus 注册时转换为pci_bus可用资源池。

bus.c提供:

  • pci_add_resource_offset():登记窗口及 CPU/PCI offset;
  • pci_bus_add_resource():向总线加入资源;
  • pci_bus_alloc_resource():在父窗口中按大小、对齐和 flags 分配。

它只提供资源树操作原语,不负责整棵拓扑的分配策略。

4. 两阶段桥资源算法

PCI_PROBE_ONLY路径通常执行:

1
2
3
4
5
6
7
pci_bus_size_bridges(root)
-> 自底向上统计每座桥下游需求
-> 计算 IO/MEM/PREFETCH 窗口大小和对齐

pci_bus_assign_resources(root)
-> 自顶向下从父窗口分配桥窗口
-> 再分配下游设备 BAR

setup-bus.c负责全树策略。桥窗口必须先覆盖下游 BAR,且 64 位 prefetch 窗口、CardBus、热插拔预留空间及资源重分配会改变 sizing。

pci_assign_unassigned_bus_resources()位于setup-bus.c:2538,用于新增设备或局部 rescan 后的未分配资源。

5. 单 BAR 落地

setup-res.c负责:

1
2
3
4
5
6
7
pci_assign_resource(dev, bar)
-> 选择父资源窗口
-> pci_bus_alloc_resource()
-> pci_update_resource()
-> CPU resource 转换为 bus address
-> 写 BAR/ROM 配置寄存器
-> claim 到 iomem/ioport resource tree

64 位 BAR 写入时要考虑高低 32 位顺序及 decode 状态。若写回读验不一致,代码会报告 BAR 更新失败;此时不能只看lspci显示的数值,还应检查 Host window 与 iATU 是否覆盖该区间。

6. Claim 与 Assign 的区别

  • Claim:接受固件已有地址,并尝试挂入内核资源树;
  • Assign:内核选择新地址并写回设备;
  • PCI_PROBE_ONLY常用于固件资源不可随意改变的平台;
  • pci=realloc=on允许在桥窗口不足等情况下尝试重分配;
  • CONFIG_PCI_REALLOC_ENABLE_AUTO可在 SR-IOV BAR 缺少空间时自动开启策略。

资源冲突并不一定表示 BAR 本身错误,也可能是 DT ranges、固件保留区或两个 Host Bridge 窗口重叠。

7. 驱动使用资源

功能驱动典型顺序:

1
2
3
4
5
pci_enable_device_mem()
-> pci_request_regions()
-> dma_set_mask_and_coherent()
-> pci_set_master()
-> pci_iomap()/devm_pci_iomap_regions()

pci_enable_device*()增加 enable 计数并设置 Command 寄存器的 I/O 或 MEM decode;pci_set_master()设置 Bus Master 位。仅完成枚举不会自动授权某个功能驱动使用全部 BAR。

remove 顺序应反向执行,并先停止设备 DMA:

1
2
3
4
5
stop DMA/IRQ
-> pci_clear_master()
-> unmap
-> pci_release_regions()
-> pci_disable_device()

8. RK3588 DWC iATU

DWC Host 使用 outbound iATU:

  • CFG0:访问直连下游设备配置空间;
  • CFG1:访问桥后多级总线;
  • MEM/IO:CPU 对 BAR 的访问转换为 PCIe TLP。

因此“Link Up 但 VID 读为0xffffffff”常查 CFG ATU;“可以枚举但 BAR MMIO 超时”常查 MEM window、DT ranges及 outbound ATU,而不是重复修改枚举逻辑。

9. 常见故障

现象 重点检查
BAR ... no space Host ranges大小、桥窗口、64 位/32 位约束
can't claim BAR iomem 冲突、固件保留、重复窗口
桥后设备无资源 subordinate bridge window sizing
BAR 可见但访问异常 DWC outbound iATU、设备供电、MEM decode
VF 创建失败 -ENOSPC SR-IOV VF BAR 与上游桥预留空间

INTx、MSI 与 MSI-X 中断路径

INTx、MSI 与 MSI-X 中断路径

1. 三种中断模型

模型 硬件行为 Linux 特点
INTx 设备断言 INTA#~INTD#,电平触发且可共享 需桥 swizzle 和平台 IRQ 映射
MSI 设备向特定地址写入消息数据 1、2、4…个向量,Capability 内保存消息
MSI-X 设备通过 BAR 内 Table/PBA 发送消息 向量更多,每项可独立屏蔽

MSI/MSI-X不是“额外的一根中断线”,而是设备发出的 Memory Write。Root Complex/ITS/MSI 控制器把消息转换成 CPU IRQ。

2. 目录分工

drivers/pci/msi/

  • msi.c:MSI/MSI-X Capability、向量申请/释放、屏蔽和状态恢复;
  • pcidev_msi.c:PCI 设备与通用 MSI Core 的连接;
  • irqdomain.c:PCI MSI irqdomain 分配;
  • legacy.c:没有层次 irqdomain 时的架构兼容路径;
  • msi.h:内部描述符与辅助声明。

通用 MSI 框架还位于kernel/irq/msi.c;平台 ITS/中断控制器不在drivers/pci

3. 驱动申请主链

现代驱动应使用:

1
2
3
4
5
6
7
8
9
10
pci_alloc_irq_vectors_affinity(dev, min, max, flags, affd)
-> 按 flags 优先尝试 MSI-X
-> 失败后尝试 MSI
-> 必要时回退 INTx
-> 返回实际向量数

pci_irq_vector(dev, nr)
-> Linux IRQ number

request_irq()/request_threaded_irq()

入口pci_alloc_irq_vectors_affinity()位于msi/msi.c:1011,释放入口pci_free_irq_vectors()位于 1064 行。

申请成功不等于 handler 已安装。正确错误路径必须在已成功request_irq()的范围内逐个释放,再调用pci_free_irq_vectors()

4. MSI 初始化

msi_capability_init()位于msi.c:430,主要工作包括:

  1. 限制请求向量数为设备支持的 2 的幂;
  2. 建立 MSI descriptors;
  3. 从 MSI domain 分配 Linux IRQ;
  4. 组织 Message Address/Data;
  5. 写 MSI Capability;
  6. 关闭 INTx 并使能 MSI。

多消息 MSI 的向量数和对齐受 Capability 限制。驱动不能假设请求max_vecs就一定得到相同数量。

5. MSI-X 初始化

msix_capability_init()位于msi.c:617

  1. 从 MSI-X Capability 得到 Table/PBA 所在 BAR 和 offset;
  2. 映射 Table;
  3. 分配 descriptors 与 IRQ;
  4. 为每个 Table Entry 写 Message Address/Data;
  5. 清 Mask 并设置 MSI-X Enable。

MSI-X Table 位于设备 BAR,不能作为普通业务寄存器随意覆盖。设备复位或 D3 状态转换后,PCI Core/驱动需恢复相关状态。

6. IRQ Domain

在层次中断域系统中:

1
2
3
4
5
PCI function MSI descriptor
-> PCI MSI domain
-> parent MSI domain
-> ARM GIC ITS 或 DWC 内建 MSI 控制器
-> CPU interrupt

pci_msi_setup_msi_irqs()位于msi/irqdomain.c:11。实际消息地址和数据由父中断域irq_chip组合生成,PCI Core 不应硬编码 ARM64 ITS 寄存器。

7. INTx 路由

INTx 需要:

  • 读取设备 Interrupt Pin;
  • 跨桥执行 swizzle;
  • 通过 DT interrupt-map、ACPI _PRT或平台 hook 映射;
  • 设置pdev->irq并使用共享 IRQ。

RK3588 DTS 中 PCIe 节点包含四项interrupt-map。Rockchip DWC 驱动建立 legacy interrupt domain,系统 IRQ handler 再分发 INTA~INTD。

8. RK3588 两种 MSI 形态

DWC Host 可以使用:

  1. DWC 自带 MSI controller:DWC 寄存器接收 MSI,统一系统 IRQ 进入dw_handle_msi_irq()
  2. 外部 MSI parent/ARM GIC ITS:由 DT 和 irqdomain 决定。

分析具体板卡必须看最终 DTS 和启动日志,不能仅凭CONFIG_PCI_MSI=y判断走哪条硬件路径。

9. 电源与错误恢复

  • suspend 前屏蔽业务中断并停止 DMA;
  • pci_save_state()保存标准与扩展能力状态;
  • resume/slot reset 后恢复 MSI/MSI-X,再允许设备产生中断;
  • AER recovery 的slot_reset()之后,驱动通常需要重建设备寄存器和队列;
  • surprise removal 后不可再访问 MSI-X Table BAR。

10. 排障

现象 检查
只能获得 1 个向量 Capability 上限、MSI 2 的幂约束、domain 空间
-ENOSPC irqdomain/ITS ID、DWC 向量、CPU affinity 限制
MSI 无中断但 INTx 正常 MSI parent、消息地址路由、DWC MSI mask/status
中断风暴 handler 未清设备状态、INTx 电平未 deassert
resume 后无中断 MSI/MSI-X 状态或设备内部队列未恢复

可用lspci -vv查看 MSI/MSI-X Enable,/proc/interrupts确认 IRQ 是否计数;两者分别证明“配置已打开”和“CPU 实际收到”,含义不同。

PCI 设备使能、电源管理、复位与恢复

PCI 设备使能、电源管理、复位与恢复

1. 枚举不等于可用

枚举完成只说明配置空间可访问并创建了pci_dev。功能驱动通常还要:

1
2
3
4
5
pci_enable_device_mem()
-> dma_set_mask_and_coherent()
-> pci_request_regions()
-> pci_set_master()
-> 分配 DMA/IRQ 并初始化设备

pci_enable_device()位于pci.c:2163pci_disable_device()位于 2351 行。Core 维护 enable 计数,多个调用者必须成对释放。

2. Command 寄存器

  • PCI_COMMAND_IO允许 I/O Port decode;
  • PCI_COMMAND_MEMORY允许 MMIO BAR decode;
  • PCI_COMMAND_MASTER允许设备主动发起 DMA;
  • pci_set_master()位于pci.c:4587
  • pci_clear_master()位于 4598 行。

设备移除或严重错误时应先停止硬件队列,再 clear master。只清 Bus Master 位不能保证设备内部 DMA 状态机已经停止。

3. PCI PM 状态

常见状态:

  • D0:完全工作;
  • D1/D2:可选中间状态;
  • D3hot:配置空间仍通常可访问;
  • D3cold:辅助电源可能关闭,配置空间不可访问。

pci_set_power_state()位于pci.c:1556。实际转换会综合 PM Capability、平台固件、父桥电源及 runtime PM。d3cold_allowed仅表示策略允许,不保证平台一定实现 D3cold。

4. 状态保存与恢复

pci_save_state()位于pci.c:1755pci_restore_state()位于 1871 行。保存内容除标准配置头外,还可包含 MSI、PCIe Capability、AER、SR-IOV、ATS 等扩展状态。

恢复顺序的核心原则:

  1. 上游桥和链路先可访问;
  2. 恢复 BAR、Command 及扩展能力;
  3. 重建设备私有寄存器、队列和 DMA;
  4. 最后解屏蔽中断。

PCI Core 无法保存厂商私有 MMIO 寄存器,必须由功能驱动 suspend/resume 回调处理。

5. 驱动 PM 回调

pci-driver.c将 Driver Core PM 映射到 PCI 驱动。现代驱动通过driver.pmdev_pm_ops实现 suspend、resume、freeze、thaw、poweroff、restore 和 runtime PM。

系统休眠与 runtime suspend 的约束不同:

  • runtime PM 需处理随时唤醒和引用计数;
  • system suspend 还涉及 wakeup、noirq 阶段和父子设备顺序;
  • 桥下设备必须先于上游桥 suspend,恢复顺序相反。

6. 复位方法

pci_reset_function()位于pci.c:5595。Core 会探测可用方法,常见包括:

方法 粒度与风险
Function Level Reset 仅 Function,优先使用
AF FLR PCI AF Capability 提供的功能级复位
PM reset D3hot→D0,可能受设备 PM 实现限制
Secondary Bus Reset 影响桥下所有设备
Slot reset 由 Hotplug/平台实现,影响物理槽
Vendor reset 由 quirk 或设备驱动提供

复位前必须确认设备未被其它 Function、VF 或用户共享。多功能设备即使支持单 Function reset,也可能共享不可见硬件资源。

7. Reset 锁

调用pci_reset_function_locked()要求调用者先完成设备锁定/排他检查。VFIO 等用户尤其需要:

  • 阻止并发配置访问;
  • 禁止新 DMA;
  • 验证 IOMMU 映射和 IRQ 已撤销;
  • reset 后恢复到可重新初始化而非“继续原队列”的状态。

sysfs reset属性最终也进入 PCI reset 框架,但并非所有设备都会暴露该属性。

8. AER 错误恢复

功能驱动可提供struct pci_error_handlers

1
2
3
4
error_detected()
-> mmio_enabled()
-> slot_reset()
-> resume()

错误严重度和各驱动返回值决定是否需要 reset、断开设备或继续。slot_reset()后设备通常相当于刚上电,必须重新配置私有寄存器;不能只返回PCI_ERS_RESULT_RECOVERED

9. Surprise Removal

设备意外消失时,配置读可能返回全 1。此时:

  • 不反复读 BAR/MMIO;
  • 禁止重新提交 DMA;
  • 中断 handler 识别设备 gone 状态;
  • remove 路径等待工作队列和引用释放;
  • 上游热插拔逻辑负责拓扑注销。

10. RK3588 控制器 PM

Rockchip DWC 控制器自身还要管理 regulator、clock、reset、PHY、PERST#和 LTSSM。控制器 resume 成功且 Link Up 后,PCI Core 才能恢复下游设备。功能驱动 PM 正常而控制器链路未恢复时,所有配置读仍会失败。

SR-IOV、ATS、PRI、PASID 与 IOMMU 虚拟化

SR-IOV、ATS、PRI、PASID 与 IOMMU 虚拟化

1. 能力边界

这些机制解决的问题不同:

机制 作用
SR-IOV 一个 Physical Function 在硬件中创建多个 Virtual Function
ATS 设备缓存 IOMMU 地址翻译结果
PRI 设备遇到缺页时向系统发 Page Request
PASID 在同一 Requester ID 下区分多个进程地址空间
IOMMU 做 DMA 地址翻译、权限与隔离
VFIO 把隔离后的设备安全交给用户态/VMM

drivers/pci实现 PCI Capability 管理,不实现完整 IOMMU 或 VFIO;后两者分别位于drivers/iommudrivers/vfio

2. SR-IOV 数据模型

PF 的 SR-IOV Extended Capability 描述:

  • TotalVFs、InitialVFs、NumVFs;
  • First VF Offset 与 VF Stride;
  • VF Device ID;
  • VF BAR;
  • VF Enable、VF MSE、ARI 等控制位。

VF 的 BDF 由 PF Routing ID 加 offset/stride 计算。VF 是可匹配普通pci_driverpci_dev,但配置空间和资源由 PF/SR-IOV 能力约束。

3. 启用主链

iov.c关键入口:

  • pci_enable_sriov():1119 行;
  • sriov_enable():633 行;
  • pci_iov_add_virtfn():315 行;
  • pci_disable_sriov():1136 行;
  • sriov_disable():754 行。

流程可概括为:

1
2
3
4
5
6
7
8
PF driver 或 sysfs sriov_numvfs
-> 校验 PF 状态、VF 数量和驱动回调
-> 检查/分配 VF BAR
-> 写 NumVFs 与 VF Enable
-> 为每个 VF 计算 devfn
-> pci_iov_add_virtfn()
-> 创建 pci_dev 并加入设备模型
-> VF driver probe

禁用时必须先确认 VF 未被占用,再逆序移除 VF、关闭 VF Enable,并释放关联关系。

4. PF 驱动职责

硬件仅提供 VF 机制,PF 驱动仍要:

  • 实现sriov_configure或调用pci_enable_sriov()
  • 分配队列、doorbell、MSI-X 等共享资源;
  • 配置 VF MAC/VLAN/权限;
  • 提供 PF↔VF mailbox;
  • 在 remove、AER、suspend 前妥善关闭 VF。

PCI Core 不理解网卡或加速器的内部资源,因此“VF 已出现在 lspci”不等于 VF 可以正常收发。

5. VF BAR 与桥窗口

VF BAR 表示整组 VF aperture。固件未为其预留足够空间时,启用会失败。可检查:

  • PF SR-IOV Capability 中 VF BAR 大小;
  • Root Port/桥窗口;
  • 64 位 prefetchable window;
  • pci=realloc=onCONFIG_PCI_REALLOC_ENABLE_AUTO
  • BAR 是否被其它资源冲突占用。

6. ATS

ats.c中:

  • pci_enable_ats():56 行;
  • pci_disable_ats():94 行;
  • pci_restore_ats_state():109 行。

ATS 允许设备的 Address Translation Cache 保存 IOVA→PA 翻译。页大小参数必须与 IOMMU 支持一致。撤销映射时,IOMMU 和设备 ATC 必须完成失效同步,否则设备可能继续使用旧权限。

7. PRI

关键入口:

  • pci_enable_pri():196 行;
  • pci_disable_pri():242 行;
  • pci_reset_pri():295 行。

PRI 允许设备提交 Page Request,从而支持可缺页共享虚拟内存。启用前要求 IOMMU、设备和上层驱动都能处理请求队列、超时及终止,不能仅设置 Capability 位。

8. PASID

关键入口:

  • pci_enable_pasid():361 行;
  • pci_disable_pasid():407 行;
  • pci_pasid_features():460 行。

PASID 将进程/地址空间标签随事务携带。它与 SVA 的安全边界依赖 IOMMU:设备可发出的 PASID 范围、绑定生命周期和进程退出必须同步。

9. 安全顺序

设备直通或共享虚拟地址时应遵循:

1
2
3
4
5
6
7
8
建立 IOMMU domain 与映射
-> 配置 PASID/PRI/ATS
-> 最后允许 Bus Master 和设备队列

停止设备队列并禁止 Bus Master
-> 停止 PRI/PASID/ATS
-> flush ATC/IOTLB
-> 解除映射与 domain

顺序错误可能让设备 DMA 到已释放或已重新授权的内存。

10. RK3588 适用性

RK3588 Root Complex 驱动存在并不代表板载控制器或终端设备支持 SR-IOV/ATS/PASID。还需同时满足:

  • Endpoint 暴露相应 Capability;
  • 上游拓扑允许 ARI/ACS 等需要的路由和隔离;
  • RK3588 PCIe 对应 IOMMU/SMMU stream 已正确接入;
  • defconfig 启用PCI_IOV/PCI_ATS/PCI_PRI/PCI_PASID
  • PF 驱动实现硬件资源配置。

Rockchip 常用 defconfig 中未显式启用全部上述功能,因此部署前应以最终.config而非通用 ARM64 defconfig 为准。

PCI Endpoint 框架、Function 与 ConfigFS

PCI Endpoint 框架、Function 与 ConfigFS

1. Host 与 Endpoint

RC 模式扫描总线、分配 BAR 并驱动对端设备;EP 模式则让本 SoC 在另一台 Host 看来是一张 PCIe 卡。Endpoint Framework 分为:

1
2
3
EPC driver       硬件控制器:BAR、地址窗口、IRQ、链路
EPF driver 对外功能:测试、NTB、厂商协议
ConfigFS 用户配置:创建 Function、绑定 EPC

核心对象为struct pci_epcstruct pci_epf及二者之间的pci_epf_link关系。

2. 目录组成

文件 职责
endpoint/pci-epc-core.c EPC 注册、start/stop、BAR、映射和 IRQ API
endpoint/pci-epc-mem.c EPC outbound 地址空间分配器
endpoint/pci-epf-core.c EPF device/driver 总线、bind/unbind
endpoint/pci-ep-cfs.c ConfigFS 控制平面
endpoint/functions/pci-epf-test.c 测试 Function
endpoint/functions/pci-epf-ntb.c NTB Function
endpoint/functions/pci-epf-vntb.c Virtual NTB

需要特别区分:本树controller/dwc/pcie-dw-ep-rockchip.c虽然复用pcie-designware-ep.c的 DWC EP 底层能力,但它没有注册标准pci_epc。它提供厂商 misc 设备/dev/pcie_ep及 ioctl/mmap/DMA 接口,因此不能直接通过本章所述 ConfigFS 组装 EPF。标准 EPC/EPF 框架和 Rockchip 厂商 EP 数据面是两条并存的软件路径。

3. EPC 注册

控制器驱动准备struct pci_epc_ops并调用devm_pci_epc_create()pci_epc_create()。ops 典型包括:

  • write_header
  • set_bar/clear_bar
  • map_addr/unmap_addr
  • raise_irq
  • start/stop
  • get_features

EPC Core 只做锁、参数校验和转发,实际寄存器与 iATU 编程由控制器实现。

4. EPF 生命周期

1
2
3
4
5
6
7
8
9
pci_epf_create("pci_epf_test")
-> EPF driver match/probe
-> pci_epc_add_epf()
-> pci_epf_bind()
-> EPF 分配 BAR/内存
-> pci_epc_write_header()
-> pci_epc_set_bar()
-> pci_epc_map_addr()
-> pci_epc_start()

pci_epf_bind()位于pci-epf-core.c:91。解绑时必须先停止对端访问,再撤销映射、BAR 和内存;Host 可能仍缓存 BAR 或保持 DMA,产品协议应提供停机握手。

5. EPC 操作入口

pci-epc-core.c中:

  • pci_epc_start():192 行;
  • pci_epc_stop():175 行;
  • pci_epc_write_header():563 行;
  • pci_epc_set_bar():522 行;
  • pci_epc_map_addr():461 行。

这些 API 按 Function Number/Virtual Function Number 定位功能。并非所有 EPC 都支持所有 BAR 大小、64 位 BAR、MSI-X 或多 Function,EPF 应先查询 features。

6. 地址方向

EP 视角容易混淆:

  • inbound:Host 访问 EP BAR,EPC 将 PCIe 地址映射到 EP 本地内存;
  • outbound:EP CPU/DMA 访问 Host 地址,EPC 将本地窗口映射为 PCIe Memory TLP;
  • BAR 本身只描述 Host 可见 aperture,不自动分配业务协议缓冲;
  • DWC iATU region 数量有限,映射生命周期必须受锁和引用约束。

7. 中断

EPF 可调用pci_epc_raise_irq()向 Host 发:

  • Legacy INTx;
  • MSI;
  • MSI-X。

Host 必须先完成相应 Capability 配置。EP 不能在 Host 尚未启用 MSI 时直接假设消息地址有效;链路重训或 Host reset 后也需重新建立状态。

8. ConfigFS

启用CONFIG_PCI_ENDPOINT_CONFIGFS后,一般通过 ConfigFS:

  1. 在 functions 下创建某类 EPF 实例;
  2. 设置 vendor/device ID、BAR 等属性;
  3. 在 controllers 下将 Function 链接到 EPC;
  4. 写 start 启动链路/功能。

ConfigFS 是配置和组装接口,不是高速数据通道。数据面由 BAR 共享内存、DMA、doorbell 和 Function 定义的协议完成。

9. pci_epf_test

测试 Function 通常提供:

  • BAR 读写校验;
  • EP→Host、Host→EP copy;
  • Legacy/MSI/MSI-X 触发;
  • checksum 和状态寄存器。

Host 侧测试驱动不在本目录 Core 中。测试通过只能证明当前 BAR/IRQ/DMA 路径基本可用,不能替代掉电恢复、并发、IOMMU 和恶意输入测试。

10. RK3588 注意事项

  • RC 与 EP compatible、DTS 节点和驱动不同,不能同时把同一控制器当两种角色;
  • rockchip_linux_defconfig含 DWC EP 和 DMA test,而具体产品配置可能裁剪;
  • RK3588 EP demo DTS 使用rockchip,rk3588-pcie-std-ep或厂商 EP compatible;
  • 本树该 compatible 匹配的pcie-dw-ep-rockchip.c注册/dev/pcie_ep,应用接口应参考同目录《rockchip-pcie-ep应用层数据传输接口》,不能假定存在 ConfigFS EPC controller;
  • PERST#在 EP 模式通常由 Host 控制,方向与 RC 模式不同;
  • refclk、PHY mode、lane mapping、供电及 link training 必须先正确,之后才讨论 ConfigFS 或厂商 misc 控制面。

11. 安全边界

Host 可写 EP BAR,所有长度、offset、opcode 都应视为不可信;EP 发起 outbound DMA 时必须限制 Host 地址范围。共享内存状态机应有版本、长度、所有权和超时字段,避免 Host reset 后继续消费旧 descriptor。

RK3588 DesignWare PCIe 控制器详细分析

RK3588 DesignWare PCIe 控制器详细分析

1. 软件分层

RK3588 PCIe RC 的主路径为:

1
2
3
4
pcie-dw-rockchip.c             Rockchip glue
-> pcie-designware.c DWC DBI/iATU/链路公共操作
-> pcie-designware-host.c Host Bridge、MSI、CFG访问
-> drivers/pci/probe.c PCI Core 枚举和资源

controller/pcie-rockchip-host.c对应较早 Rockchip 自有 PCIe IP。RK3588 DTS compatible 为"rockchip,rk3588-pcie", "snps,dw-pcie",匹配pcie-dw-rockchip.c,不能按文件名相似就选旧驱动。

2. 平台匹配

rk_pcie_of_match位于pcie-dw-rockchip.c:918,RK3588 项在 936 行。平台驱动通过module_platform_driver()注册,probe 为rk_pcie_probe()(1880 行)。

本厂商树支持CONFIG_PCIE_RK_THREADED_INIT:打开后 probe 可用kthread_run()执行rk_pcie_really_probe()。这会改变启动日志时序,依赖 PCIe 设备很早出现的驱动需注意异步初始化影响。

3. Probe 主链

1
2
3
4
5
6
7
8
9
10
11
rk_pcie_probe()
-> [线程或直接] rk_pcie_really_probe()
-> 匹配 SoC data
-> rk_pcie_resource_get()
-> rk_pcie_hardware_io_config()
-> rk_pcie_host_config()
-> dw_pcie_host_init()
-> 分配/配置 pci_host_bridge
-> MSI/INTx 与 RC setup
-> start_link
-> pci_host_probe()

本树关键位置:

  • rk_pcie_resource_get():646 行;
  • rk_pcie_hardware_io_config():1476 行;
  • rk_pcie_host_config():1601 行;
  • rk_pcie_really_probe():1728 行;
  • dw_pcie_host_init()pcie-designware-host.c:385

4. 平台资源

Rockchip glue 负责通用 PCI Core 不理解的资源:

  • DBI/APB 等寄存器窗口;
  • clocks 与 resets;
  • regulators;
  • PHY 与 lane mode;
  • PERST#、WAKE#等 GPIO;
  • GRF/系统寄存器;
  • legacy/sys IRQ;
  • 可选 DMA test 和平台扩展。

错误路径必须逆序撤销。PHY 未退出或时钟提前关闭时,不应继续读 DBI/APB。

5. 硬件初始化与链路

rk_pcie_hardware_io_config()完成平台上电、时钟、reset、PHY 和 GPIO 时序;rk_pcie_establish_link()位于 353 行,并作为dw_pcie_ops.start_link使用。

典型链路流程:

1
2
3
4
5
6
7
保持 Endpoint PERST#
-> 打开电源/refclk/PHY
-> 配置 RC mode、lane、速率
-> 释放控制器 reset
-> 释放 PERST#
-> 使能 LTSSM
-> 等待 Data Link Layer Link Active

PERST#释放到配置访问必须满足设备时序。某些 NVMe/Wi-Fi 上电慢,简单增加扫描重试只能掩盖电源或时序问题。

rk_pcie_link_up()位于 246 行,用平台状态判断 Link。Link Up 只是物理/数据链路条件,不保证配置 iATU、BAR window 或 MSI 正确。

6. DWC Host 公共层

dw_pcie_host_init()负责:

  1. 从 DT/平台资源建立 Host Bridge windows;
  2. 建立pci_ops
  3. 初始化 MSI domain(若使用 DWC MSI);
  4. dw_pcie_setup_rc()配置 Root Complex;
  5. 启动链路;
  6. 调用pci_host_probe()

dw_pcie_setup_rc()位于pcie-designware-host.c:694。跨平台公共代码不应直接加入 RK3588 regulator/GPIO 逻辑,这些应留在 Rockchip ops。

7. 配置空间访问

  • Root Port 自身配置通常通过 DBI;
  • 直连下游 BDF 使用 CFG0;
  • 桥后 BDF 使用 CFG1;
  • DWC 临时或固定配置 outbound iATU,再发起 CPU MMIO 读写;
  • 无 Completion/Unsupported Request 最终表现为 PCI BIOS 错误码或全 1。

若 Bus 0 Root Port 可见而 Bus 1 Device 0 不可见,应同时检查 Link 和 CFG0 ATU,而非search.c

8. 地址窗口

DT ranges定义 CPU→PCI I/O/MEM 窗口,DWC outbound iATU真正执行转换。BAR 分配必须落在窗口内。Inbound 方向还可能涉及控制器自身 DMA/EP 模式,不能把 RC outbound 和 EP BAR inbound 混为一谈。

9. 中断

  • Legacy INTx:DTS interrupt-map描述 INTA~INTD,Rockchip 建立 domain 并由系统 IRQ 分发;
  • MSI/MSI-X:由 DWC MSI controller 或外部 parent domain接收;
  • rk_pcie_sys_irq_handler()位于 837 行,处理平台系统事件,不等同于所有 Endpoint MSI handler。

10. 电源管理

rockchip_dw_pcie_pm_ops位于 2263 行。Suspend/resume 必须协调:

  1. 停止下游设备和 DMA;
  2. 保存 PCI 配置;
  3. 停止链路、PHY、clock/power;
  4. resume 时恢复平台硬件与 RC;
  5. 重新建立 Link;
  6. 恢复 PCI 配置和功能驱动。

本树 resume 路径会再次调用硬件配置、Host 配置或链路建立函数,排障时应区分首次 probe 与 resume 日志。

11. RK3588 控制器实例

SoC DTS定义:

  • PCIe 3.0 x4:pcie3x4
  • PCIe 3.0 x2:pcie3x2
  • PCIe 2.0 x1:pcie2x1l0/l1/l2

具体板级 DTS 通常只 enable 实际布线的节点,并补 regulator、reset GPIO、pinctrl、PHY。SoC 有节点不表示板上端口已启用。

12. Bring-up 分层检查

1
2
3
4
5
6
7
电源/时钟/复位/PHY
-> LTSSM 与 Link Up
-> Root Port DBI
-> CFG0 读取 Endpoint VID
-> BAR 与 MEM iATU
-> MSI/INTx
-> 设备驱动 DMA

每层成功后再查下一层。这样可避免把“PHY 未锁定”误判为 PCI Core 枚举 bug,或把“MSI domain 错误”误判为 NVMe 队列逻辑问题。

PCI Sysfs、Proc 与用户态控制接口

PCI Sysfs、Proc 与用户态控制接口

1. 设备目录

每个 Function 通常位于:

1
/sys/bus/pci/devices/0000:bb:dd.f/

pci-sysfs.c创建主要属性,proc.c提供历史/proc/bus/pci接口。现代管理和诊断应优先使用 sysfs、libpci/lspci 及驱动专用接口。

2. 身份与拓扑属性

常见只读属性:

  • vendordevice
  • subsystem_vendorsubsystem_device
  • classrevision
  • irq
  • modalias
  • max_link_speed/width
  • current_link_speed/width
  • 桥的secondary_bus_number/subordinate_bus_number
  • numa_nodelocal_cpulist等拓扑信息。

modalias用于 udev/module loader 查找匹配模块,但最终仍由pci_bus_match()按 ID 表确认。

3. 配置空间

config是二进制属性,大小由设备配置空间决定,通常为 256 B 或 PCIe 4 KiB。读写权限受 capability、内核 lockdown 和文件 mode 限制。

直接写配置空间可能:

  • 改写 BAR 导致资源树与硬件不一致;
  • 关闭 Bus Master 或使能未知 DMA;
  • 改变 AER/ASPM/链路状态;
  • 破坏正在运行的驱动。

因此在线设备优先使用内核 API 或驱动接口,不把setpci作为永久配置方案。

4. BAR 与 ROM

  • resource:文本形式列出所有资源起止地址和 flags;
  • resourceN:可 mmap 的 BAR 二进制文件;
  • resourceN_wc:允许 write-combining 的变体;
  • rom:Expansion ROM;
  • resourceN_resize:Resizable BAR 控制,只有支持且安全时出现。

用户态 mmap BAR 不能绕过设备所有权。设备已绑定内核驱动时,并发访问私有寄存器可能破坏驱动状态。

5. 设备控制属性

enable

写 1/0通过 PCI Core 增减设备 enable 状态。它不是完整的驱动初始化/停机接口,不能代替 unbind、停止 DMA 和资源释放。

remove

写 1触发逻辑移除:

1
2
pci_lock_rescan_remove()
-> pci_stop_and_remove_bus_device_locked()

它不会物理断电,且桥设备移除会递归影响下游。

rescan

总线或设备 rescan 会重新读取配置空间并加入新 Function。前提是控制器、链路、电源已就绪。

reset

若设备存在安全 reset 方法,会出现reset属性。写入会触发功能复位,但不保证应用或驱动状态自动恢复。

driver_override

指定仅允许匹配某驱动名。它本身不会自动 unbind/rebind;常用于 VFIO,但必须同时完成 IOMMU group 和设备隔离检查。

6. 驱动绑定

1
2
3
4
5
/sys/bus/pci/drivers/<driver>/
bind
unbind
new_id
remove_id
  • unbind调用当前驱动 remove;
  • bind尝试绑定指定 BDF;
  • new_id临时向驱动加入动态 PCI ID;
  • 动态 ID 不会让不兼容硬件突然兼容,错误绑定可能造成 MMIO/DMA 破坏。

7. SR-IOV

PF 设备可能暴露:

  • sriov_totalvfs
  • sriov_numvfs
  • sriov_drivers_autoprobe

sriov_numvfs会创建/删除 VF。删除前必须解绑或停止 VF 用户;资源不足时应检查 VF BAR 和桥窗口。

8. PCI Slot 与 Hotplug

Hotplug Core 在:

1
/sys/bus/pci/slots/<slot>/

按后端能力提供powerattentionlatchadaptertest等属性。并非每个 BDF 都有物理 slot,也不是每个 M.2 连接器都支持软件控电。

9. /proc/bus/pci

CONFIG_PROC_FSproc.c提供兼容枚举和配置访问。它主要服务历史 ABI;新代码不应依赖其目录布局来判断热插拔或设备所有权。

10. 常用诊断

1
2
3
4
5
6
lspci -nn
lspci -t
lspci -vv -s <BDF>
readlink /sys/bus/pci/devices/<BDF>/driver
cat /sys/bus/pci/devices/<BDF>/resource
cat /proc/interrupts

lspci展示配置空间快照;dmesg 展示内核过程;二者不能替代 PHY/clock/regulator 等平台状态检查。

11. 并发与权限

removerescan、bind/unbind、SR-IOV 和 reset 都是有破坏性的控制操作,应:

  • 限制为管理员;
  • 先停业务和 DMA;
  • 串行化自动化脚本;
  • 验证目标 BDF,避免桥级操作波及整棵子树;
  • 不在不可信容器中暴露可写 PCI sysfs。

PCIe Port 服务、错误恢复与高级能力

PCIe Port 服务、错误恢复与高级能力

1. Capability 组织

PCI 配置空间有两类链表:

  • 传统 Capability:前 256 B,例如 PM、MSI、MSI-X、PCIe;
  • Extended Capability:PCIe 扩展空间,例如 AER、DPC、ATS、SR-IOV、DOE、PTM。

pci_find_capability()pci_find_ext_capability()负责定位。Capability 链来自硬件,内核必须防御循环、非法 offset 和截断配置空间。

2. PCIe Port Bus

pcie/portdrv_pci.c以普通pci_driver绑定 Root Port、Upstream/Downstream Port 或 RCEC;portdrv_core.c再把一个端口拆成逻辑服务设备:

1
2
3
4
5
6
PCIe port pci_dev
-> pcie_port_device_register()
-> PME service
-> AER service
-> Hotplug service
-> DPC service

每个服务通过pcie_port_service_driver独立绑定和处理 IRQ。PCIe 端口服务与网卡/NVMe 等 Function 驱动不是同一种 driver。

3. AER

pcie/aer.c处理 Root Error Status、Correctable/Uncorrectable Error Status 和 Header Log。典型流程:

1
2
3
4
5
AER interrupt/message
-> 读取并清 Root/AER status
-> 定位错误源 Requester ID
-> 记录 correctable/non-fatal/fatal
-> 非致命/致命错误进入 pcie_do_recovery()

pcie/err.c沿受影响层级调用功能驱动的pci_error_handlers。Correctable 错误通常只记账,Fatal 错误可能需要 DPC、链路 reset 或移除设备。

4. DPC

Downstream Port Containment 在下游严重错误时快速关闭流量,避免坏事务继续扩散。pcie/dpc.c作为端口服务处理触发原因、RP PIO 日志和恢复。

DPC 与 AER互补:

  • AER描述和报告错误;
  • DPC隔离故障链路;
  • 错误恢复框架决定驱动回调和 reset;
  • ACPI EDR 可与固件协作恢复。

5. ASPM

pcie/aspm.c管理:

  • L0s;
  • L1;
  • Clock Power Management;
  • L1 Substates(L1.1/L1.2)。

策略通过pcie_aspm.policy和内核参数影响,但实际启用取决于链路两端能力、latency、L1SS、CLKREQ#和 quirk。只看 Endpoint Capability 不够,必须检查上游 Port。

RK3588 厂商树还有aspm_ext.c扩展接口。它并非上游通用 ABI,移植新内核时应单独审查。

6. PME、PTM 与 RCEC

  • pme.c:处理 PCIe 原生 PME 唤醒;
  • ptm.c:Precision Time Measurement 层级配置;
  • rcec.c:Root Complex Event Collector 与 RCiEP 错误关联;
  • edr.c:ACPI Error Disconnect Recover。

RK3588 常见 DT 启动不使用 ACPI EDR,但 AER/PME 是否可用仍取决于最终配置和端口能力。

7. DOE

doe.c实现 Data Object Exchange mailbox。一个设备可有多个 DOE mailbox,每个 mailbox 缓存支持的 Vendor/Protocol。

1
2
3
4
5
6
7
pci_doe_submit_task()
-> 专用 ordered workqueue
-> 写 request object
-> GO
-> 等待 READY/ERROR
-> 读取 response object
-> completion callback

pci_doe_submit_task()位于 586 行。DOE 事务可睡眠且有超时/abort,不应在原子上下文同步等待。上层 SPDM/CXL 等协议必须验证响应长度和协议 ID。

8. P2PDMA

p2pdma.c允许一个 PCI 设备的 BAR 内存直接供其它 PCI 设备 DMA:

  1. provider 通过pci_p2pdma_add_resource()发布 BAR 区域;
  2. Core 计算 provider 与 clients 的拓扑距离;
  3. 分配 P2P pages/scatterlist;
  4. client DMA 直接访问 provider。

它并不保证跨 Root Port 工作。许多 Root Complex 会阻止或重定向 P2P,安全默认是同一上游桥下使用。启用前还需确认 ACS/IOMMU 路径不会破坏事务。

9. VPD 与 VC

  • vpd.c通过 VPD Capability 访问只读/可写字段,并处理设备忙和超时;
  • vc.c配置 Virtual Channel 资源;
  • 两者都依赖设备正确实现 Capability,quirk 可限制损坏或超慢的 VPD。

VPD 写操作可能修改设备持久信息,不应作为普通运行时数据通道。

10. Quirks

quirks.c按阶段运行 fixup:

  • EARLY;
  • HEADER;
  • FINAL;
  • ENABLE;
  • RESUME/RESUME_EARLY;
  • SUSPEND。

匹配可基于 vendor/device/class。Quirk 用于硬件/固件缺陷,不应把板级电源时序或业务驱动逻辑无条件塞入通用 PCI Core。新增 quirk 要限定最小 ID 范围并说明为何标准路径不适用。

11. 安全与诊断

  • AER status 多为 W1C,先保存再清;
  • 不无限重试 Surprise Down 后的配置访问;
  • ASPM 问题先用策略关闭验证,再定位 CLKREQ#/L1SS;
  • DPC 后必须等待链路和驱动恢复完成;
  • DOE/P2P 输入和地址都按不可信处理;
  • pci=noaerpcie_aspm=off适合隔离问题,不是最终修复。

RK3588 PCIe 配置、DTS 与故障排查

RK3588 PCIe 配置、DTS 与故障排查

1. 内核配置

本树rockchip_linux_defconfig主要启用:

1
2
3
4
5
6
7
8
9
10
CONFIG_PCI=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCIEASPM_POWERSAVE=y
CONFIG_PCIEASPM_EXT=y
CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_GPIO=y
CONFIG_PCIE_ROCKCHIP_HOST=y
CONFIG_PCIE_DW_ROCKCHIP=y
CONFIG_PCIE_DW_DMATEST=y
CONFIG_PCIE_DW_ROCKCHIP_EP=y

不同产品 defconfig 有差异。rockchip_electric_defconfig未启用全部热插拔/EP 测试,rockchip_cpcem_linux_defconfig还启用厂商 Endpoint Function。最终判断必须查看构建生成的.config

2. DTS 控制器

RK3588 SoC DTS包含:

节点 典型能力
pcie3x4@fe150000 Gen3 x4
pcie3x2@fe160000 Gen3 x2
pcie2x1l0@fe170000 Gen2 x1
pcie2x1l1@fe180000 Gen2 x1
pcie2x1l2@fe190000 Gen2 x1

节点 compatible 为rockchip,rk3588-pciesnps,dw-pcie。板级 DTS 通过&pcie...选择实际端口并补充供电、GPIO、pinctrl 和 PHY。

3. 关键 DTS 属性

应结合 binding 核对:

  • regreg-names:DBI/APB/config 等窗口;
  • ranges:CPU→PCI I/O/MEM 地址;
  • bus-range
  • interruptsinterrupt-names
  • interrupt-map:legacy INTA~INTD;
  • msi-mapmsi-parent
  • clocksclock-names
  • resetsreset-names
  • physphy-names
  • num-lanes、最大链路速率;
  • reset-gpios
  • vpcie regulator/supply;
  • status = "okay"

属性名称应以本树 binding 和驱动实际devm_*_get()为准,不能直接照搬其它 BSP。

4. PHY 与 Lane 复用

RK3588 PCIe 3.0 lane 由共享 PHY 和 GRF 控制,x4/x2/多个 x1 组合受硬件 mode、板级走线和 DTS 约束。若 lane mode 错误:

  • PHY 可能 probe 成功;
  • 控制器寄存器可读;
  • 但 LTSSM 无法稳定进入 L0。

还应检查 refclk 方向、100 MHz 时钟质量、SSC、AC coupling 和 lane polarity。

5. 上电时序

推荐观测顺序:

1
2
3
4
5
6
7
8
9
Endpoint 电源稳定
-> refclk 稳定
-> PHY 初始化
-> RC reset 释放
-> Endpoint PERST# 释放
-> LTSSM Enable
-> Link L0
-> 等待设备完成内部初始化
-> 配置空间读取

NVMe、Wi-Fi、PCIe Switch 的稳定时间不同。GPIO 极性或 regulator enable 错误会表现为永久 Detect/Polling。

6. 分层故障树

A. 控制器不 probe

检查:

  • DTS status/compatible;
  • 驱动是否编入;
  • clock/reset/regulator/PHY 获取错误;
  • deferred probe 依赖;
  • threaded init 是否延后日志。

检查:

  • Endpoint 电源;
  • PERST#极性和时序;
  • refclk;
  • PHY lane mode;
  • LTSSM 状态;
  • Gen1 强制降速能否建立链路;
  • SI、连接器和走线。

检查:

  • CFG0 outbound iATU;
  • bus-range;
  • 首次 VID/DID 读结果;
  • Endpoint 是否仍返回 CRS;
  • Device 0/Function 0 路由;
  • 控制器系统错误状态。

D. 能枚举但 BAR 分配失败

检查:

  • DTS ranges容量;
  • bridge MEM/prefetch window;
  • 32/64 位 BAR;
  • 资源冲突;
  • SR-IOV VF BAR;
  • 是否需要pci=realloc=on进行验证。

E. BAR 可访问但业务中断失败

检查:

  • MSI/MSI-X Enable;
  • IRQ domain 与 parent;
  • DWC MSI status/mask;
  • /proc/interrupts计数;
  • handler 是否清设备状态;
  • INTx interrupt-map

F. 中断正常但 DMA 失败

检查:

  • pci_set_master()
  • DMA mask;
  • IOMMU/SMMU stream ID;
  • cache coherency;
  • descriptor 地址和 endian;
  • 设备是否报告 Completion Timeout/AER。

7. 常用证据

1
2
3
4
5
6
dmesg | 关注 rockchip-dw-pcie、link、AER、BAR、MSI
lspci -nn -t
lspci -vv -s <BDF>
cat /sys/bus/pci/devices/<BDF>/resource
cat /proc/iomem
cat /proc/interrupts

厂商树的pcie-dw-rockchip.c已包含额外[PCIe DEBUG]日志;量产前应控制日志级别,避免在热路径持续打印。

8. 内核参数的定位用途

  • pci=nomsi:验证 MSI 路径;
  • pcie_aspm=off:验证 ASPM/CLKREQ#;
  • pci=realloc=on:验证资源窗口;
  • pci=pcie_bus_safe等:验证 MPS/MRRS;
  • pcie_port_pm=off:部分版本用于端口 PM 隔离。

参数能改变现象不等于根因已修复,应回到 DTS、电气、资源或驱动状态机。

9. 安全注意

  • 不对正在 DMA 的设备执行 sysfs remove/reset;
  • 不用devmem修改 DWC/GRF 寄存器作为长期方案;
  • IOMMU 未隔离前不把 Endpoint 交给不可信用户;
  • 热拔前停止业务、解绑驱动并确认供电控制;
  • 自动恢复应限制重试次数,防止坏链路造成无限 reset 风暴。

OF、ACPI、ECAM 与配置空间后端

OF、ACPI、ECAM 与配置空间后端

1. 分层边界

PCI Core 通过struct pci_ops读取配置空间,并不要求 Host 一定使用 ECAM。固件/平台层的任务是:

  1. 描述或发现 Host Bridge;
  2. 提供 bus number 与 CPU/PCI resource windows;
  3. 建立配置空间访问后端;
  4. 描述 INTx/MSI 与 IOMMU 拓扑;
  5. 最终调用pci_host_probe()

RK3588 常用 DT + DWC iATU 路径;标准 ECAM 和 ACPI MCFG 是其它可选后端,三者不能混为一套实现。

2. Device Tree:of.c

of.c把 DT PCI 节点转换为 PCI Core 可用信息,主要包括:

  • domain/segment 与 bus-range;
  • ranges中的 I/O、MEM、Prefetchable MEM 窗口;
  • CPU 地址与 PCI Bus Address offset;
  • interrupt-map中的 INTx 路由;
  • MSI domain;
  • OF 节点与扫描所得pci_dev关联;
  • 最大链路速率等通用属性。

关键辅助函数:

  • devm_of_pci_bridge_init()of.c:591
  • of_pci_get_max_link_speed():619 行;
  • of_irq_parse_and_map_pci():529 行;
  • pci_host_bridge_of_msi_domain():79 行。

解析 DT 只建立软件描述,不能替代 regulator、clock、reset、PHY 和链路训练。

3. ranges地址转换

一个 DT range 同时包含:

1
2
3
4
PCI child address
CPU parent physical address
size
space type/flags

Core 将其登记为 Host Bridge window,并保存 offset。BAR 资源在 Linux 中通常以 CPU 物理地址表示,写回 BAR 时再转换为 PCI Bus Address。DWC Host 还需配置 outbound iATU,使 CPU 实际访问与该转换一致。

常见错误:

  • child/parent 地址填反;
  • 32 位窗口无法容纳 64 位 BAR;
  • Prefetchable flag 丢失;
  • 多个 Host 的 CPU 窗口重叠;
  • DT range 正确但 iATU region 未覆盖。

4. INTx、MSI 与 IOMMU 固件描述

  • interrupt-map按 BDF/Interrupt Pin 映射 INTA~INTD;
  • msi-parentmsi-map选择 MSI domain;
  • iommu-map把 PCI Requester ID 映射为 IOMMU Stream ID;
  • 三者都与 BDF/rid 路由相关,但分别管理线中断、消息中断和 DMA 翻译。

只修正 MSI 映射不会解决 IOMMU fault;只看到 IOMMU group 也不能证明 Endpoint IRQ 正常。

5. 通用 ECAM:ecam.c

ECAM 为每个 Function 提供标准 MMIO 配置窗口:

1
offset = bus << 20 | device << 15 | function << 12 | register

主要入口:

  • pci_ecam_create()ecam.c:42
  • pci_ecam_map_bus():191 行。

pci_ecam_create()验证 bus range、计算窗口大小并映射资源;pci_generic_config_read/write再通过map_bus返回的地址访问配置空间。

ECAM 映射通常只用于 Configuration Space,不能当作设备 BAR Memory Space。

6. ACPI 与 MCFG

ACPI 系统通常通过:

  • MCFG:给出 PCI Segment 的 ECAM 地址;
  • _CRS:Host Bridge I/O/MEM windows;
  • _PRT:INTx 路由;
  • _OSC:固件与 OS 协商 AER、Hotplug、PME 等原生控制;
  • _DSM:平台或 EDR 等扩展协作。

本目录pci-acpi.c处理 PCI 设备 ACPI companion、PM/唤醒及平台协作。架构 ACPI PCI root 创建逻辑还分布在drivers/acpi/pci_root.c等目录,不能仅阅读drivers/pci/pci-acpi.c就认为覆盖完整 Host 枚举。

acpi_pci_root_get_mcfg_addr()位于pci-acpi.c:108,用于获取 Root 对应 MCFG 信息。

7. 非标准 ECAM Quirk

部分控制器对 Root Port 和下游配置空间使用不同访问方式,不能直接套标准 ECAM。ARM64 ACPI + PCI quirks 下,本树会编入pcie-dw-rockchip-acpi.c

  • rk_pcie_ecam_init():78 行;
  • rk_pcie_ecam_map_bus():153 行;
  • Root Port 可转向 DBI;
  • 下游 BDF 通过 DWC iATU/MCFG 窗口访问。

这属于 ACPI MCFG quirk,不等于 RK3588 DT 启动的pcie-dw-rockchip.c主路径。

8. RK3588 DT 主链

1
2
3
4
5
6
7
8
rk3588*.dtsi PCIe node
-> platform_device
-> rk_pcie_probe()
-> 解析 Rockchip/DWC 资源
-> dw_pcie_host_init()
-> devm_of_pci_bridge_init()/Host windows
-> DWC pci_ops(DBI + CFG0/CFG1 iATU)
-> pci_host_probe()

配置访问后端的选择由 Host 驱动决定。虽然 DTS compatible 含snps,dw-pcie,并不表示该节点自动走ecam.c的标准pci_ecam_map_bus()

9. 排障判据

现象 固件/后端检查
Root Port 不出现 Host probe、DBI、bus-range、domain
Root Port 有而 Endpoint 无 CFG0/CFG1 map、iATU、链路
BAR 地址异常 DT ranges/_CRS 与 offset
INTx 无法触发 interrupt-map/_PRT 和 swizzle
MSI 申请失败 msi-map/msi-parent 与 IRQ domain
DMA IOMMU fault iommu-map、RID/Stream ID
AER/Hotplug 未接管 ACPI _OSC 或pcie_ports=策略

10. 修改原则

  • 平台电源和 PHY 差异放控制器 glue;
  • 通用 DT 解析留在of.c
  • 标准 ECAM 保持规范寻址;
  • 非标准配置访问用受限 compatible/ACPI quirk;
  • 不为修一块板而改变所有 Host Bridge 的通用扫描规则。