本系列文章将完整描述rk3588 pcie驱动内容。涉及pcie协议相关的内容请参考王齐的 《PCIExpress体系结构导读》。本文是整个系列的前置内容,主要讲述pcie控制器自身在linux pci子系统中的抽象,后面在讲述pcie设备的整个枚举流程时这些抽象部件会再次出现。
1、rk3588 pcie控制器抽象
RK3588的PCIe控制器内部构成,可以理解为一个从软件到硬件的层级结构。
1.1、软件抽象层:Linux内核PCI子系统
在Linux内核中,PCIe控制器被抽象为以下几个核心数据结构,它们是理解整个架构的基础:
它负责管理该控制器下的所有总线和设备,并提供访问配置空间方法。
- pci_host_bridge(主机桥):这是整个PCIe树的软件起点,在RK3588的驱动中,它代表了一个PCIe控制器实例(例如pcie@fe150000节点),
- pci_bus(总线):代表一条PCIe总线,通过pci_host_bridge创建根总线(Root Bus,通常是Bus 0),之后通过桥设备级联出更多的子总线形成树状结构。
- pci_dev(设备):代表总线上的一个具体设备,比如根端口(Root Port)或终端设备(Endpoint),在枚举过程中,内核会为每个发现的设备创建此结构。
1.2、硬件层:RK3588 PCIe控制器
RK3588的PCIe控制器基于Synopsys DesignWare PCIe IP构建,其内部包含多个关键硬件模块:
- Root Complex(RC,根复合体):这是PCIe拓扑的根节点,负责连接CPU/内存子系统与PCIe链路,RK3588的每个PCIe控制器内部都包含一个RC。
- Root Port(RP,根端口):这是RC内部的一个逻辑端口,可以理解为PCIe总线树的"出口",每个Root Port下会挂载一条独立的PCIe总线,
- iATU(内部地址转换单元):这是DesignWare PCIe IP的核心地址映射引擎,它负责在CPU的物理地址空间和PCIe的总线地址空间之间进行转换。
RK3588的控制器支持多个iATU Region(如8 ATU inbound regions,8 ATU outbound regions),用于高效地管理地址映射。
1.3、host bridge
Host Bridge(主机桥):是整个PCIe域的软件抽象(struct pci_host_bridge),代表一个PCIe控制器(Root Complex)。
它负责创建并管理根总线(Bus 0),并提供配置空间访问方法(pci_ops),它本身不是一个挂在总线上的PCI设备,因此不会出现在Bus 0的设备列表中。
Bus 0(根总线):Host Bridge创建的第一条PCIe总线,也是整个PCIe树的根。
它由pci_host_bridge通过pci_register_host_bridge()创建,其总线号通常为0(但也可以由设备树指定其他起始号)
Bus 0上的设备包括Root Port,Bus 1上的设备包括PCIe交换机上行端口,以及直接连接的端点设备(Endpoint)等。
分析下面rk3588的pcie拓扑结构:
lspci -t
-[0000:00]---00.0-[01-ff]----00.0
lspci -nn
00:00.0PCI bridge[0604]: Rockchip Electronics Co., Ltd Device [1d87:3588] (rev 01)
01:00.0 Processing accelerators [1200]: Huawei Technologies Co., Ltd. Device [19e5:d500] (rev 23)
00:00.0:位于Bus 0,设备 0,功能 0,是一个PCI 桥(Root Port),来自Rockchip RK3588
01:00.0:位于Bus 1,设备 0,功能 0,是一个处理加速器(Endpoint),来自华为AScend
分析下面rk3588的pcie拓扑结构:
[root@OpenEuler ~]# lspci -t
-+-[0000:00]-
+-[0002:20]---00.0-[21]----00.0
\-[0003:30]---00.0-[31]----00.0
-+-[0000:00]-
表示Domain 0000,Bus 00的根总线,它是系统的主PCI域,但总线下方没有列出任何设备
+-[0002:20]---00.0-[21]----00.0
这是一个独立的PCI域:
[0002:20]:Domain 0002,Bus 20的根总线,该根总线为RK3588内部PCIe 控制器的Root Complex内部总线
---00.0:该总线上有一个设备,地址为00.0(设备 0,功能 0),是RK3588 PCIe控制器内部的Root Port
-[21]:这个设备是一个PCI桥(Root Port),它的下游总线号是21
----00.0:在总线21上有一个端点设备,地址为00.0
\-[0003:30]---00.0-[31]----00.0
结构与上面完全类似:
[0003:30]:Domain 0003,Bus 30的根总线
---00.0:总线30上的桥设备(Root Port)
-[31]:下游总线31
----00.0:总线31上的端点设备
在PCIe体系结构中,Root Complex(RC)通常包含一个或多个Root Port,每个Root Port在PCI配置空间中表现为一个PCI-to-PCI桥设备。
PCI-to-PCI桥(简称P2P桥)是PCI/PCIe体系结构中的核心组件,用于连接两条PCI总线,实现总线间的地址转换、事务转发和资源隔离。
Linux内核在枚举PCIe总线时,会将Root Port识别为标准的PCI桥,并赋予它们独立的BDF(总线号:设备号.功能号)
[root@OpenEuler ~]# lspci -nn
0002:20:00.0PCI bridge[0604]: Rockchip Electronics Co., Ltd Device [1d87:3588] (rev 01)
0002:21:00.0 Ethernet controller [0200]: Device [1f0a:6801] (rev 01)
0003:30:00.0PCI bridge[0604]: Rockchip Electronics Co., Ltd Device [1d87:3588] (rev 01)
0003:31:00.0 Network controller [0280]: Broadcom Inc. and subsidiaries Device [14e4:449d] (rev 02)
通过上述打印信息可知,root port本质就是一个pci桥设备。
1.4、root port
在Linux PCI子系统中,Host Bridge本身不是PCI设备,因此不会出现在lspci列表中,它是软件抽象,代表整个PCIe控制器(Root Complex)。
Root Port是Host Bridge内部的一个逻辑端口,它会作为PCI桥设备出现在根总线上。
根据PCIe规范,Root Port被定义为一个PCI-PCI 桥(PCI-to-PCI Bridge),具有以下核心属性:
每个Root Port管理一条独立的PCIe链路。
- Device/Port Type:在PCIe Capability寄存器的Capabilities字段中,类型编码为0x4(PCI_EXP_TYPE_ROOT_PORT)
- 功能定位:它是Root Complex的出口,负责将CPU/内存子系统与下游PCIe链路连接起来,一个Root Complex可以包含多个Root Port,
- 配置空间:Root Port使用Type 1配置空间头部(与PCI-PCI桥相同)包含Primary Bus、Secondary Bus、Subordinate Bus等寄存器,
以及Memory Base/Limit,I/O Base/Limit 等资源窗口寄存器。
1.5、pcie协议中RC示意图
pcie协议中配置拓扑图,结合上面的文字描述,更加容易理解RC的内部构造。
注意:对于pcie switch,其上下游端口都是一个pci-to-pci桥。
提示:对于pcie RC结构中的host bridge,root port的理解一定要准确,因为在后面的linux内核pci子系统中会去创建host bridge,root port等数据结构,这里理解清楚了分析代码时就不会困惑了。
1.6、type 0/1配置空间
pcie协议 type 0/1 配置空间详细如下:
其中关键的寄存器的说明在驱动代码中遇到时再进行详细说明,这里不再赘述,感兴趣的同学可以参考其他文章先行查看了解。