PCIe是一种高速串行总线,用于连接计算机内部的各种设备。在PCIe中,有四种不同的设备类型:Switch、Bridge、Root Complex和EndPoint。本篇文章将介绍这四种设备类型的基础知识。
1. Switch
Switch是PCIe中最常见的设备类型之一,它可以将一个PCIe总线分成多个子总线。Switch可以将数据从一个端点设备传输到另一个端点设备,同时还可以控制数据的流向和速度。Switch通常用于连接多个设备,以便它们可以共享PCIe总线的带宽。
2. Bridge
Bridge是另一种常见的PCIe设备类型,它可以连接两个不同的PCIe总线。Bridge可以将数据从一个PCIe总线传输到另一个PCIe总线,同时还可以控制数据的流向和速度。Bridge通常用于连接不同类型的设备,例如将PCIe总线连接到PCI总线或其他类型的总线。
3. Root Complex
Root Complex是PCIe总线的起点,它通常是计算机主板上的芯片组。Root Complex负责控制PCIe总线上的所有设备,包括Switch和EndPoint。Root Complex还负责初始化PCIe总线上的所有设备,并为它们分配资源,例如内存地址和中断。
4. EndPoint
EndPoint是PCIe总线上的最终设备,它通常是计算机内部的各种设备,例如显卡、网卡、声卡等。EndPoint负责接收和发送数据,并将数据传输到其他设备或主机内存中。EndPoint还可以向Root Complex请求资源,例如内存地址和中断。
总之,Switch、Bridge、Root Complex和EndPoint是PCIe总线中的四种不同设备类型,它们各自扮演着不同的角色,共同构成了PCIe总线的基础架构。了解这些设备类型的基础知识,有助于我们更好地理解PCIe总线的工作原理和应用场景。
lane:指pcie设备物理层传输线的一对差分线(差分对),是一个纯粹的、准确的物理实现(Physical);
link:指pcie设备的传输通道,是一个概括的概念(比如AXI总线可以指整个AXI传输通道),pcie设备间的link可以包含多个lane;
Link初始化以及link建立过程(或者称之为链路训练,Link Training)是在设备上电或者链路重新建立链接是发生的。
在PCIe控制器中,把PCIe的地址等分成32块regions (Regions 0 to 31),cpu以及外部DMA可以通过region映射向PCIE link发出写请求,可用配置(conguration space),以及数据传输(memory space)
PCI总线规定访问配置空间总线事务,使用ID号进行寻址。PCI设备ID号由总线号(Bus Number)、设备号(Device Number)和功能号(Function Number)。其中总线号在HOST主桥遍历PCI总线树时确定,在一颗PCI总线树上,总线号由系统软件决定,通常与HOST主桥直接相连接的PCI总线编号为0,系统软件使用DFS(Depth-First Search)算法扫描PCI总线树上的所有PCI总线,并依次编号。一条PCI总线的设备号由PCI设备的IDSEL信号与PCI总线地址线的连接关系确定,功能号与PCI设备的具体设计有关。一个PCIe系统最多有256条Bus,每条Bus上最多可以挂在32个设备,每个PCIe设备最多有8个功能设备。
从cpu角度理解PCIe-云社区-华为云
在XX处理器中的HOST主桥中,与PCIE设备配置相关的寄存器由CFG_ADDR、CFG_DATA等组成。系统软件使用CFG_ADDR(CFG_ADDR寄存器结构如图 2所示)和CFG_DATA寄存器访问PCIe设备的配置空间,这些寄存器都是采取同一编址(所有内存寄存器都使用存储器映射方式进行寻址)。当处理器访问PCIe配置空间时,首先需要在CFG_ADD寄存器中设置这个PCIe设备对应的总线号、设备号、功能号和寄存器偏移,然后使能Enable位,之后当处理器对CFG_DATA读写访问时,HOST主桥将这个存储器读写访问转换成PCIe配置读写请求,并且发送到PCIe总线上。如果Enable位没有使能,那么CPU对寄存器的访问也就是一个普通IO的访问,而不能让HOST转换成总线请求访问,访问PCIe配置空间时按照PCIe总线标准配置TLP请求,CFG_DATA是读取的数据或者待写入的数据。
既然CPU能够直接通过寄存器访问配置空间,为啥还会出现配置空间在存储域地址的映射这一说法呢?下面给出详细解答。
Intel(Intel是PCIe龙头老大,最新的PCIe的规范总是它最先尝试的)实现的PCI规范使用IO空间的CF8h和CFCh来分别作为索引和数据寄存器,这种方法可以访问所有PCI设备的255 bytes配置寄存器。Intel Chipsets目前仍然支持这种访PCI配置空间的方法。
PCIe规范在PCI规范的基础上,将配置空间扩展到4K bytes,至于为什么扩展到4K,具体可以参考PCIe规范,这些配置CFG_ADDR和CFG_DATA寄存器方法仍然可以访问所有PCIe设备配置空间的头255 bytes,但是该方法访问不了剩下的(255B~4K)配置空间。
Intel Chipset通过将配置空间映射到内存地址空间,PCIe配置空间可以像对映射范围内的内存进行read/write来访问了。这种映射是由北桥芯片来完成的,但是不同芯片的映射方式也是不同的。目前我查看了ARM芯片的datasheet,确实是这样的方式。
PCIe规范为每个PCIe设备添加了更多的配置寄存器,空间为4K,尽管CFG_ADDR和CFG_DATA寄存器方法仍然能够访问lower 255 bytes,但是必须提供另外一种方法来访问剩下的(255B~4K)range寄存器。Intel的解决方案是使用了预留256MB内存地址空间,对这段内存的任何访问都会发起PCIe 配置cycle。由于4K的配置空间是directly mapped to memory的,那么PCIe规范必须保证所有的PCIe设备的配置空间占用不同的内存地址,按照PCIe规范,支持最多256个bus,每个Bus支持最多32个PCIe devices,每个device支持最多8个function,也就是说:占用内存的最大值为:256 * 32 * 8 * 4K = 256MB。图 3是ARM Cortex-A9 datasheet内存地址分配局部图。被PCIe配置空间占用的256M内存空间会屏蔽掉DRAM使用该段内存区,这些地址都由CPU出厂时已经固化好了。
有些CPU没有直接指定PCIe配置空间的地址范围,需要读取某个寄存器的值BaseAddr,这个值就说PCIe配置寄存器在内存区域映射的基地址。访问PCIe设备配置空间时候需要手动计算访问PCIe配置空间的地址。计算发放如下:
SIZE_PER_FUNC = 4K = 1000h
SIZE_PER_DEVICE = 4K * 8 = 8000h
SIZE_PER_BUS = 4K *8* 32 = 100000h
访问总线号为busNo,设备号为DevNo,功能号为funcNo的offset寄存器的计算公式是:
Memory Address = BaseAddr+ busNo * SIZE_PER_BUS+ devNo * SIZE_PER_DEVICE+ funcNo * SIZE_PER_FUNC+ offset
访问PCIe配置空间就需要通过总线号、设备号、功能号、寄存器偏移进行转换成内存地址。转换函数如图 2所示。
前256Bytes可以通过寄存器方式访问,后面的256B~4k必须通过映射才能访问,映射无非就是把配置空间映射到存储地址空间,或者把PCIe设备空间映射到存储地址空间。下面开始讨论映射关系。
地址映射关系
PCIe在存储域地址空间分为三部分,PCIe控制器本身的寄存器、PCIe设备的配置空间、PCIe设备空间。寄存器和配置空间由处理器本身决定存储地址范围,本款处理器地址范围如图5所示,配置空间地址、寄存器地址、内存地址都已经确定。PCIe设备空间需要编程人员去配置Outbound和Inbound寄存器组,确定映射关系
Outbound在PCIe控制器中扮演的角色是将存储地址翻译到PCIe域的PCIe地址,Inbound是将PCIe地址翻译成存储地址,图6是一个完整的RC和EP模型地址翻译模型,图中的地址数字仅仅代表一种形态,具体地址应该是什么在后文中讲解。当cpu需要访问EP的内存空间时,首先应该将存储地址转换成PCIe地址,在根据TLP到达指定的EP,进而将PCIe地址转换成EP端的存储地址。
PCIe地址到存储地址之间的映射关系由三个寄存器决定(有两个寄存器组应该是32个寄存器)OB_SIZE、OB_OFFSET_INDEXn、OB_OFFSETn_HI,n的范围是0~31。在PCIe控制器中是把PCIe地址等分成32块regions (Regions 0 to 31),每个regions的大小是可以通过编程设置OB_SIZE寄存器确定大小,大小有1, 2, 4, or 8 MB,那么通过Outbound能够翻译的地址最大为8M*32=256M。存储域地址中有5位作为识别32个regions的index,OB_SIZE的大小决定这5位在32位地址上的位置。当OB_SIZE等于0,1,2,3时,index在存储地址中对应的位置是Bits[24:20], bits[25:21], bits[26:22], and bits[27:23],每个regions翻倍,是不是对应的地址应该按翻倍对齐呢,翻倍就是左移一位数据。
扫描PCIe树
扫描树的流程如下:
1) 建立存储地址到PCIe地址映射 (映射方式上面段落已经讲解了,固定的PCIe配置空间映射)
2) 分配PCIe总线号
3) 分配设备号
4) 访问配置空间 (这里有一个原则读者需要注意,对PCIe设备配置空间访问时,一定要确定总线号、设备号、功能号、寄存器,不然无法找到设备)
5) 读写BAR0确定PCIe设备1空间大小
6) 分配PCIe地址