PCIE学习(一):PCIE基本知识
书籍:
https://github.com/ljgibbslf/Chinese-Translation-of-PCI-Express-Technology-/blob/main/2%20PCIe%20%E4%BD%93%E7%B3%BB%E7%BB%93%E6%9E%84%E6%A6%82%E8%BF%B0.md
PCIE和板卡
点对点的方式连接两个设备。
FPGA中的PCIE享有独立的IO,BANK,因为其配置复杂。
A7系列支持2.0
KU部分支持3.0
KU+部分支持4.0
通过高速BANK可以引出能连接高速设备的IO(GTX和GTH);
在XILINX 7Z035 FGG676中有两个这样的BANK,每个BANK提供四对高速收发器,所以总的来说是8对高速收发器;
我所使用的开发板:
光口两个各用一对;
PCIEX4用了四对;
SATA两个各用了一对;
https://docs.amd.com/v/u/en-US/ug476_7Series_Transceivers
根端口
https://blog.csdn.net/u013253075/article/details/119045277
可见PCIE设备写入设备并不需要直接通过CPU(DMA);
PCIe拓扑特征:图的顶部是一个CPU。这里要说明的一点是,CPU被认为是PCle层次结构的顶层。PCle只允许简单的树结构,这意味着不允许循环或其他复杂的拓扑结构。这样做是为了保持与PCI软件的向后兼容性,PCI软件使用一个简单的配置方案来跟踪拓扑,不支持复杂的环境。为了保持这种兼容性,软件必须能够与以前相同的方式生成配置周期,总线拓扑也必须与以前相同。因此,软件期望找到的所有配置寄存器仍然在那里,并且以它们始终具有的方式运行。
在上图PCIe系统中有几种设备类型,Root Complex、Switch、Bridge、Endpoint等,下面分别介绍其概念。
Root Complex:
简称RC(根端口),CPU和PCle总线之间的接口,可能包含几个组件(处理器接口、DRAM接口等),甚至可能包含几个芯片。RC位于PCI倒立树拓扑的“根”,并代表CPU与系统的其余部分进行通信。但是,规范并没有仔细定义它,而是给出了必需和可选功能的列表。从广义上讲,RC可以理解为系统CPU和PCle拓扑之间的接口,PCle端口在配置空间中被标记为“根端口”。
Bridge:
桥提供了与其他总线(如PCI或PCI- x,甚至是另一个PCle总线)的接口。如图中显示的桥接有时被称为“转发桥接”,它允许旧的PCI或PCIX卡插入新系统。相反的类型或“反向桥接”允许一个新的PCle卡插入一个旧的PCI系统。
Switch:ID和路由
http://www.ssdfans.com/?p=8216
https://www.pcietech.com/186.html/
提供扩展或聚合能力,并允许更多的设备连接到一个PCle端口。它们充当包路由器,根据地址、ID或其他路由信息(隐含路由数据包)识别给定包需要走哪条路径。是一种PCIe转PCIe的桥。
Switch有一个上游端口(靠近RC)和若干个下游端口,每个端口其实是一个Bridge,都是有一个Configuration的,每个Configuration描述了其下面连接设备空间映射的范围,分别由Memory Base和Memory Limit来表示。对上游端口,其Configuration描述的地址范围是它下游所有设备的映射空间范围,而对每个下游端口的Configuration,描述了连接它端口设备的映射空间范围。
ID路由,故名思意,是依靠目标设备的ID来作为目标地址的。即用Bus Number、Device Number和Function Number进行路由寻址。基于ID的路由方式主要用于配置读写请求,以及完成报文。
地址路由:选择地址写入具体的数据;
隐含路由:根据驱动里的要求读取标志以知晓写到具体的哪个设备中;
Endpoint:
网卡,显卡,声卡;可以被主板连接火挂载;支持Type0配置空间;
处于PCIe总线系统拓扑结构中的最末端,一般作为总线操作的发起者(initiator,类似于PCI总线中的主机)或者终结者(Completers,类似于PCI总线中的从机)。
显然,Endpoint只能接受来自上级拓扑的数据包或者向上级拓扑发送数据包。细分Endpoint类型的话,分为Lagacy PCIe Endpoint和Native PCIe Endpoint,Lagacy PCIe Endpoint是指那些原本准备设计为PCI-X总线接口的设备,但是却被改为PCIe接口的设备。
而Native PCIe Endpoint则是标准的PCIe设备。
其中,Lagacy PCIe Endpoint可以使用一些在Native PCIe Endpoint禁止使用的操作,如IO Space和Locked Request等。
Native PCIe Endpoint则全部通过Memory Map来进行操作,因此,Native PCIe Endpoint也被称为Memory Mapped Devices(MMIO Devices)
配置空间:Type0和Type1
https://blog.csdn.net/yhb1047818384/article/details/106676528
http://www.ssdfans.com/?p=8210
PCI标准配置空间分type0和type1两种。type0主要是针对PCI的endpoint设备,type1主要是针对PCI bridge, switch。
如上图所示,type0和type1有一些共同的寄存器描述。
Device ID: 设备ID, 表示该PCI设备的设备号,只读。
Vendor ID: 厂商ID, 表示生产该设备的厂商的编号,只读。
Status: pci设备状态寄存器,用于保存pci设备的状态,如中断状态或运行产生错误时的状态。
Class Code:设备类型(大类),决定使用什么驱动去访问这个设备;设备分类信息, 表示pci设备属于哪一种类别,如网卡,存储卡,显卡等。需要重点关注的一个寄存器,之前定位过一个问题,pci设备资源分配失败,就是因为将class code设置为0, 而那张卡是pcie 网卡, class code应该设置为2。
Revision ID: 设备版本ID, 表示PCI设备的版本号。该寄存器可以被认为是Device ID寄存器的扩展。 只读。
BIST: 可选,用于内部自检。
Header type: PCI设备头类型寄存器,表示该设备时pci EP设备还是PCI 桥设备。PCI配置空间时type0还是type1就是由该寄存器定义。
Lantency Timer: 在PCI总线中,多个设备共享同一条总线带宽,该寄存器用来控制PCI设备占用PCI总线的时间。PCIe设备不需要使用该寄存器,该寄存器的值必须为0。因为PCIe总线的仲裁方法与PCI总线不同,使用的连接方法也与PCI总线不同。
Cache line size: cache缓存大小。对于PCIe设备,该寄存器的值无意义。
Expansion Rom Base Address: 扩展ROM映射基地址寄存器。分配给ROM使用,用于PCI设备在处理器还没有运行操作系统之前,完成基本的初始化设置。
Base Address register: BAR地址寄存器负责PCI设备内部空间的映射。用于计算机与主板的通信。
BAR空间:通过TLP包和BAR交互是慢速交互,用于设置配置信息,而数据交互主要还是DMA
https://blog.csdn.net/u013253075/article/details/119361574
http://www.ssdfans.com/?p=8210
32位:六个BAR空间
64位:三个BAR空间
BAR(Base Address Register)空间是在PCIe设备中的。BAR是一组特殊的寄存器,用于定义设备的内存和I/O地址空间。这些地址是设备和主机系统通信的基础。
当PCIe设备被系统初始化时,主机的操作系统会读取设备的配置空间,其中包括多个BAR字段。这些字段被操作系统用来映射到主机的地址空间中,从而操作系统和CPU可以通过这些映射的地址访问PCIe设备的内存或I/O端口。这使得主机能够读取或写入设备的特定区域,进行数据交换或控制设备操作。
总结来说,BAR空间被定义在PCIe设备中,但是它通过配置过程被映射到上位机的地址空间中,使得上位机可以通过这些映射的地址与设备进行交互。
只要上位机希望往这部分地址范围写入数据的时候都会使用TLP包进行交互。
TLP包:位于传输层事务部分。
总之:BAR地址寄存器负责PCI设备内部空间的映射, 有了这个映射,CPU可以做到对pcie设备空间的访问。
为什么需要BAR?
系统中的每个设备中,对地址空间的大小和访问方式可能有不同的需求,例如,一个设备可能有256字节的内部寄存器/存储,应该可以通过IO地址空间访问,而另一个设备可能有16KB的内部寄存器/存储,应该可以通过基于MMIO的设备访问。哪些地址应该使用哪种方式(IO或Memory)来访问它们的内部位置,这是系统软件(即BIOS和OS内核)的工作。因此设备必须为系统软件提供一种方法来确定设备的地址空间需求。这种需求就是是通过配置空间头部中的Base Address register (BAR)实现的。
一旦系统软件知道设备在地址空间方面的需求,系统软件将分配一个适当类型(IO, NP-MMIO或P-MMIO)的可用地址范围给该设备。
如下图所示,Type 0报头有6个bar可用(每个bar的大小为32位),而Type 1头只有2个bar可用。Type 1报头在所有网桥设备中都可以找到,这意味着每个switch端口都有Type 1报头。Type 0报头在非网桥设备中,比如end point。
DMA传递:
https://blog.csdn.net/yundanfengqing_nuc/article/details/82992367
需要操作的基地址+包长度+读写标志 由此组成包发送给下位机(FPGA),
FPGA接收后解析,讲地址,所需长度的数据打包(TLP),传给根端口,根端口将其写入某个位置;
CPLD包:响应读指令包含数据的包。
如果申请的BAR空间过大,将可能注册失败,需要考虑具体的配核驱动。
蓝屏:访问了不该访问的地址。
上位机只能看到BAR,而PCIE设备可以看到上位机软件所有内存空间。
PCIe 层级
PCIe 设备内部层次包括:
-
设备核心层以及它与事务层的接口。设备核心层实现设备的主要功能。如果设备是一个端点,那么它最多可以包含 8 个功能(function),每个功能实现自己的配置空间。如果设备是一个交换机,那么它的核心由数据包路由逻辑和为了实现路由的内部总线构成。如果设备是一个 RC,那么其核心会实现一个虚拟的 PCI 总线 0,在这个虚拟的 PCI 总线 0中存在着所有的芯片组嵌入式端点以及虚拟桥。
-
事务层。事务层负责在发送端产生 TLP(Transaction Layer Packet,事务层包),在接收端对 TLP 进行译码。这一层也负责 QoS(Quality of Service,服务质量)、流量控制以及事务排序。所有的这四个事务层的功能将在本书的第二部分进行讲解。
-
数据链路层。数据链路层负责在发送端产生 DLLP(Data Link Layer Packet,数据链路层包),在接收端对 DLLP 进行译码。这一层也负责链路错误检测以及修正,这个数据链路层功能被称为 Ack/Nak 协议。这两个数据链路层功能会在本书的第三部分进行讲解。
-
物理层。物理层负责在发送端产生字符序列包,在接收端对字符序列包进行译码。这一层将处理上述三种类型的包(TLP、DLLP、字符序列包)在物理链路上的发送与接收。数据包在发送端要经过字节条带化逻辑、扰码器、8b/10b 编码器(对于 Gen1/Gen2)或是 128b/130b 编码器(对于 Gen3)以及数据包并串转换模块的处理。最终数据包以训练后的链路速率在所有通道上按照时钟以差分形式输出。在物理层的接收端,数据包处理包括串行地接收差分形式的比特信号,将其转换为数字信号形式,然后将输入比特流做串并转换。这个操作基于来源于 CDR(Clock and Data Recovery,时钟数据恢复)电路所提供的恢复时钟。接收下来的数据包要经过弹性缓存、8b/10b 解码器(对于 Gen1/Gen2)或者 128b/130b 解码器(对于 Gen3)、解扰器以及字节交换恢复逻辑。最终,物理层的 LTSSM(Link Training and Status State Machine,链路训练状态机)负责进行链路初始化以及训练。所有这些物理层功能将在本书的第四部分进行讲解。
每个 PCIe 接口都支持这些层的功能,包括交换机端口,如图2‑13 所示。在早期大家经常会产生一个疑问,那就是一个交换机端口是否还需要实现所有的层次呢,毕竟它通常只用于转发数据包。答案是需要,因为对包的内容进行解析来确定它们的路由是需要查看数据包的内部细节的,而这件事情是在事务层中完成的。
原则上,本设备上的每个层都与链路对端设备的各自对应层进行通信,例如本设备的事务层与对端的事务层通信、本设备的数据链路层与对端的数据链路层通信。上面的两层通过在数据包内添加一串特定的比特信息,产生一个接收端的对应层可以识别的字段样式来实现对应层之间的通信。数据包通过其他层的转发,从而做到到达或者离开链路。物理层也直接与另一个设备中的物理层通信,但是方式与此不同。
在我们讲的更深入之前,先大致了解一下这些层是如何交互的。从广义上说,设备所发出的请求包或者完成包是在事务层进行组包的,组包所用到的信息是由设备核心层所提供的,有时我们将设备核心层称为软件层(尽管协议规范中并没有使用这一术语)。它提供的组包信息通常包括期望的命令类型、目标设备的地址、请求的属性特征等等。刚组好的数据包会被存入一个被称为虚拟通道缓存,直到这个包可以被发往下一个层级。当这个包被向下发给数据链路层后,数据链路层会在数据包中加入额外的信息以供对端的接收方进行错误检查,而且这个数据包会在本地储存下来,这样我们就可以在对端检测到传输出错时重新发送这个数据包。当数据包到达物理层后,它被编码,并使用链路上的所有可用的通道、以差分信号的形式进行传输。
接收端对物理层的输入比特进行解码,检查本层级所能发现的错误,如果没有检查到错误,那么就将接收到的数据包向上转发到数据链路层。在数据链路层,数据包进行不同于物理层的错误检查,如果没有发现错误就向上转发给事务层。在事务层数据包被缓存,检查错误,并拆解成原始信息(命令、属性等),以便将这些数据传输到接收设备的核心层。接下来,让我们更深入的探索每一个层必须要做什么才能让上述过程正常工作,这个操作过程在图2‑14 进行了展示。我们从最顶端开始。
设备核心层是一个设备的核心功能,例如网络接口或是硬盘驱动控制器。它并不是 PCIe 协议规范中所定义的一个层级,但是我们可以把它当做一个 PCIe 的层级,这是因为它位于事务层的上方,而且它是所有请求的源头或是目的地。它为事务层提供了需要发送的请求信息,其中的信息包括事务类型、地址、需要传输的数据量等等。当事务层接收到输入数据包时,它也是事务层向上转发输入数据包信息的目的地。
2.2.2 事务层(Transaction Layer):通过解析事务层的包可以实现更底层的操作,以更好地实现应用层。
https://blog.csdn.net/qq_31799983/article/details/104733490
https://github.com/ljgibbslf/Chinese-Translation-of-PCI-Express-Technology-/blob/main/2%20PCIe%20%E4%BD%93%E7%B3%BB%E7%BB%93%E6%9E%84%E6%A6%82%E8%BF%B0.md
为了响应来自软件层的请求,事务层生成出站数据包(outbound packet)。它也会检查入站数据包(inbound packet),并将入站数据包内包含的信息向上转发给软件层。
事务层支持非报告式请求(non‐posted transaction)的拆分事务协议,并将入站完成包(inbound Completion)与先前传输的出站非报告式请求包关联起来,
即知道这个完成包是对应到哪个非报告式请求包。事务层所处理的事务使用的数据包种类为 TLP,TLP 可以分为四个请求种类:
-
内存(Memory)
-
IO
-
配置(Configuration)
-
消息( Messages)
前三种在 PCI 和 PCI-X 中就已经得到支持,但是消息是 PCIe 中的一个新的请求种类。一个请求包向目标设备传送命令,目标设备作为响应请求而发回的一个或多个完成包,这二者组合起来就是对一个事务的定义,即一个事务由一个请求包以及所有返回的完成包共同组成。
如表2‑2 列出了 PCIe 请求的类型。
表2‑2 PCIe请求类型
这些请求还可以被归为两类,如上表的右边一列:非报告和报告(non‐posted and posted)。对于非报告式请求,发起方首先向完成方发送一个请求数据包,完成方应该产生一个完成包作为响应。读者们应该认出来了,这就是从 PCI-X 那里继承来的拆分事务协议。例如,所有的读请求都是非报告式的,因为这个读请求所请求的数据需要通过完成包来返回给发起方。可能令你感到出乎意料,IO 写请求和配置写请求也是非报告式的。尽管它们在发送给目标设备的命令中就已经包含了要写入目标设备的数据,但是这两种请求依然需要目标设备在写入完成后返回完成包,以此来让发起方确认数据被正确无误的写入到目的设备中。
与上述的请求相反地,内存写请求和消息请求都是报告式的,这意味着完成方在完成这些请求后不需要向发起方返回完成包 TLP。报告式事务对整体性能提升是有好处的,因为发起方不需要等待响应,也不需要承担对完成包进行处理的额外开销。这里做出的取舍就是发起方无法得到写请求是否被正确无误的完成的反馈信息。报告式这种操作行为继承自 PCI,它依然被认为是一个不错的操作方法,虽然无法得到反馈信息,但是发生错误的可能性比较小并且使用报告式得到的性能提升也比较明显。需要注意的是,尽管它们不要求返回完成包,报告式写操作仍然要参与数据链路层的 Ack/Nak 协议,以此来保证较为可靠的数据包传输。关于这一点的更多内容,请见第十章“Ack/Nak 协议”。
存储器:DMA读写的请求
IO:包含:写BAR和读BAR的操作请求;PIO操作,配置寄存器触发某些信号
配置:IP核自动完成,上电时BIOS扫描配置注册BAR空间;
消息:产生中断,配置信息报告的请求,在IP核中已被屏蔽,仅提供管脚1产生;Riffa中已封装代为处理,主要负责传递错误报告,事件报告,标志信息等
传统中断使用管脚的配置产生;标准PCIE设备要求使用消息中断;
TLP帧结构:
https://blog.csdn.net/qq_39815222/article/details/121732888
PCIe 请求包和完成包的包类型被罗列在表2‑3 中。
表2‑3 PCIe 的 TLP 类型
TLPs 起始于发送方的事务层,终止于接收方的事务层,如图2‑15 所示。当 TLP 途经发送方的数据链路层以及物理层时,这两层分别会向数据包中添加一些信息,接收方的数据链路层和物理层会分别根据发送方对应层所添加的信息来进行校验,以此确认数据包是否在链路传输中依旧保持正确没有出错。
图2‑15 TLP 的起点与目的地
TLP 组包. 如图2‑16 展示了一个封装完成的 TLP 的各个部分是如何在链路上进行传输的,我们可以从中发现这个数据包中的不同部分是分别由不同的层来添加的。为了更容易看出这个数据包是怎么构成的,我们将 TLP 的不同部分用不同的颜色进行标识,以此来表示对应的部分是由哪一层添加的:红色代表事务层,蓝色代表数据链路层,绿色代表物理层。
图2‑16 TLP 组包形式
设备核心层负责将组成 TLP 的核心部分的信息发送给事务层,即上图中的首部和数据。每个 TLP 都会有一个首部,而有些 TLP 会没有数据部分,例如读请求。
事务层还可以选择添加 ECRC(End-to-End CRC, 端到端 CRC)字段,这个 ECRC 由事务层进行计算并附加在数据包的后面。CRC 的意思是循环冗余校验码,它被几乎所有的串行传输架构所使用,原因很简单,它实现起来比较简单同时又能提供很强的错误检测功能。CRC 还可以检测“突发错误”,即一串重复的错误比特,这一串比特的长度取决于 CRC 的长度(对于 PCIe 来说是 32比特)。因为这种类型的错误在发送一长串比特时会遇到,因此 CRC 的这种特性非常适用于串行传输。ECRC 字段区域在通过发送方和接收方之间的任何服务点(服务点(service point),通常指的是交换机或者根组件的端口这些有 TLP 路由功能的地方)时都不改变,这使得目的端可以用它来验证在整个传输过程中都没有发生错误。
对于 TLP 的传输,TLP 的核心部分由事务层转发至数据链路层,数据链路层负责在 TLP 中添加一个序列号和另外一个被称为 LCRC(Link CRC, 链路CRC) CRC 字段区域。LCRC 被对端接收方用来进行错误检查,并将链路上传输的每个数据包的检查结果都汇报给发送方。善于思考的读者可能会有疑问,如果 LCRC 已经证明了这次链路传输是无差错的,而 LCRC 又是数据包必需含有的字段,那么 ECRC 还有什么作用呢?这个疑问的回答是,还使用 ECRC 是因为还有一个地方的传输错误没有被检查,那就是负责路由数据包的设备内部。当一个数据包到达一个端口,并进行错误和路由检查,然后当它被从另一个端口发出时,设备会计算出一个新的 LCRC 值并添加在数据包中,新的LCRC 会取代老的 LCRC 。内部端口之间的转发可能会遇到 PCIe 协议没有检查到的错误,这时候就需要 ECRC 来发挥它的作用了。这里可以理解为,当 TLP 到达交换机的一个接收端口时,交换机会在接收端口对其 LCRC 进行校验,然后根据路由信息对数据包进行转发,但是这个转发过程中是不对 LCRC 进行校验的,直到转发到对应的输出端口,然后在输出端口给数据包加上新的 LCRC 后发送出去,不难发现因为在内部转发过程中不对 LCRC 进行校验,因此若转发过程中出现了错误则就需要通过更内层封装的 ECRC 来进行校验了,否则内部转发过程是否出错将无从可知。
最后,数据链路层封装好的数据包被转发给物理层,物理层将其他一些字符添加到数据包中,这些字符可以让接收方知道接下来将会接收什么(例如标识一个数据包的开始或结尾)。对于前两代的 PCIe,物理层将在数据包的头和尾添加控制字符。而在第三代 PCIe 中不再使用控制字符,而是在数据包中添加一些额外的比特来提供关于数据包的信息。经过这些处理后,数据包被编码,然后在链路上所有可用通道中以差分形式传输。
TLP 拆包. 当对端的接收方看到了输入的比特流时,它需要对此前组包时添加的那些部分进行识别和剥除,这样就能恢复出发送方设备的设备核心层的原始请求信息。如图2‑17 所示,物理层将会确认当前比特流中是否存在正确的“起始”、“结束”或者其他字符,并将它们剥除,然后将剥除了这些字符后的 TLP 转发给数据链路层。数据链路层将首先进行 LCRC 以及序列号的错误校验。如果并未发现错误,那么数据链路层将会把 LCRC 和序列号从 TLP 剥除,并将 TLP 转发给事务层。如果接收方是一个交换机,那么将在事务层对这个数据包进行解析评估,从它的数据包头中找到路由信息来确定这个数据包要被转发到哪一个端口。即使这个交换机并不是 TLP 最终的目的地,它也可以对这个 TLP 进行 ECRC 校验以及在发现错误时进行 ECRC 错误汇报。但是,交换机不能更改这个 TLP 中的 ECRC,这是希望最终的目标设备也可以检测到这个 ECRC 错误。
如果目标设备有能力并且启用了 ECRC 校验的功能,那么它将对 ECRC 进行错误校验。若 TLP 到达了最终的目的设备,而且校验无错,那么在事务层中将把这个 ECRC 字段剥除,使得整个数据包只剩下首部和数据部分,并将这些剩余部分转发给软件层。
PCIE发展历史
PCIE术语