学习笔记——PCIe

本文为学习笔记,故只对知识点依据自己的理解作概要总结,方便以后复习激活记忆

如有错误,欢迎指正!

一、编址

学习PCIe关键要弄清楚采用PCIe的计算机系统中是怎么编址的,这样才能理解DMA、P2P DMA等通信是如何进行的

PCIe计算机硬件系统结构

上图是一个采用NUMA架构的PCIe计算机硬件系统结构。为了方便理解,CPU的结构是基于Intel的Sky Lake架构抽象得到,主要表达CPU内部各个硬件电路的关系,并非硬件实际电路结构。GPU为PCIe版GPU,并且两个NUMA节点下的GPU使用的是NvLink桥接器进行直接连接。此外,假设操作系统为Linux 64位操作系统

在这样一个计算机系统中,总共有三个地址空间:虚拟地址空间,物理地址空间,PCIe总线地址空间

虚拟地址空间

虚拟地址空间是操作系统虚拟出来的一个地址空间,每个进程都有这样的一个虚拟地址空间,并且相互独立。直观来讲,这个地址空间就是编程时看到的地址空间,比如使用C语言的printf函数输出某个变量的地址,这个地址就是虚拟地址。这么设计的目的就在于可以在有限的内存资源中虚拟出非常庞大的内存资源来给进程使用;并且由于采用相同的地址空间,操作系统在进行管理的时候也非常方便

Linux 64位系统虚拟地址空间

上图展示了Linux 64位系统中每个进程的虚拟地址空间的结构。其中,内核空间在地址的高位,用户空间在地址的低位,中间的地址不做使用,如果程序访问这段地址则会产生无效访问的错误。

物理地址空间

本文所描述的物理地址空间采用MMIO技术,即把I/O设备和内存放在同一个地址空间内统一编址,在绝大部分架构以及未启用IOMMU的情况下,使用MMIO地址的PCIe设备的PCIe总线地址和物理地址相同(这部分会在下面的PCIe总线地址空间中详细说明)。此外,多个NUMA节点是统一编址,也就是说多个NUMA节点中的物理地址空间处于一个空间,编址不能冲突

也就是说在物理地址空间中,一个地址可能表示内存中的一个字节的地址,也可能表示的是PCIe设备中设备存储上的一个字节的地址,并且统一编址,统一寻址,互相占有各自的区域,互不影响

下图是物理地址空间的一个例子(不同系统架构中的编址可能会有所不同)

物理地址空间

PCIe总线地址空间

PCIe总线地址空间中有两种地址类型:MMIO地址和I、O端口地址,这两种地址类型拥有两个独立的地址空间,即使地址重复也互不影响,要想明白这一点,需要学习PCIe设备上的一个重要结构——基地址寄存器(BAR)

BAR是PCIe设备上的一个寄存器(在终端节点上有6个,PCIe Switch上有2个),存储了一些PCIe设备的关键配置信息,其中最主要的就是PCIe设备的地址类型和地址

那么,BAR上的值是怎么来的呢?在计算机进入BIOS后,BIOS会执行程序,使用深度优先算法进行PCIe树的遍历,遍历到叶子节点即中断节点时,终端节点会初始化自己的BAR,指定所需要的地址空间的大小以及地址类型,程序会分配给该PCIe设备一个首地址并将其存入BAR中,如果是请求I/O端口地址类型则从I/O端口地址类型中分配一段不冲突的地址,如果是MMIO类型则分配一段物理地址(相等的情况下),然后下一次分配将进行移位确保同地址类型的地址不会产生冲突。当一个PCIe Switch下的所有中断节点分配完毕,则初始化PCIe Switch的BAR,在里面存上其所管理的PCIe设备的地址和大小,实际使用时就根据PCIe Switch BAR中的信息进行寻路

上述讨论的MMIO类型的分配是在MMIO地址和物理地址相等的情况下,如果是不相等的情况下(某些架构以及启用了IOMMU的情况下),分配的是物理地址经过映射后的地址

也就是说在绝大部分架构以及不启用IOMMU的情况下,PCIe地址空间中的MMIO类型的地址空间和物理地址空间是相同的

二、寻址

本节以几个具体操作为例来讲解如下图所示的计算机系统中的寻址

CPU运行程序时访问内存

CPU在运行程序时,当CPU运行到从内存中取数据的指令,CPU就会试图去访问内存

由于在访问内存或Cache的时候,需要给内存控制器或缓存控制器物理地址,才能进行访问

因此,需要先得到想访问单元的物理地址。但是,程序中的地址均为虚拟地址,所以CPU需要先把地址交给MMU,MMU中存有TLB(快表)和页表基地址,MMU获得地址后先查询TLB,如果TLB未命中则根据页表基地址去内存中取该进程的页表进行查询,最终将其转化为物理地址

在转化完物理地址之后,首先将物理地址交给缓存控制器,缓存控制器会用不同的方法来使用物理地址(可能部分使用可能全部使用,取决于查找方法),依次查找L1、L2、L3 Cache(存取速度由高到低)

如果均未命中,则将物理地址交给内存控制器。内存控制器判断该物理地址是否在同一个NUMA节点上

如果在:则将该读写请求加入到内存控制器内部的请求队列中,出队列时执行操作

如果不在:则将该读写请求转发给UPI接口,UPI接口进行UPI协议封装后寻路发出,到达目的NUMA节点后,目的NUMA节点的UPI接口解封装,将请求转发给内存控制器,内存控制器将请求加入请求队列,当出队列时如果是写操作则直接写入并返回确认,如果是读操作则将数据发送给UPI接口,UPI接口封装后发回,接收到之后解封装,然后将数据存到L1 Cache中(一次一个缓存行,CPU读取数据时会进行缓存行填充)

DMA

DMA首先开始于I/O设备向CPU发送中断信号,这个信号会发送到CPU中的中断处理器,然后CPU在合适的时间响应中断(五级流水CPU会在指令周期结束的时候响应)。

CPU响应中断之后,CPU执行中断程序。中断程序读取DMA上的中断状态寄存器发现是DMA请求,之后会对I/O设备的DMA引擎进行编程设置,之后DMA引擎就直接跟内存进行数据交互,不需要CPU做任何操作,直到编程设置的DMA传输的数据量全部传输完毕,DMA引擎会向CPU发送中断信号,CPU响应中断后执行中断程序,中断程序读取中断状态寄存器发现DMA结束,则结束本次DMA

在这个过程中,无论是CPU跟I/O设备交互进行控制,还是I/O设备与内存交互进行数据存取,都涉及到Transaction Layer Packet(TLP)

CPU访问DMA引擎:CPU首先发送DMA控制信息(包含物理地址)到RC,RC根据控制信息生成TLP,地址是该I/O设备的PCIe总线地址,所以如果是启用了IOMMU的话,会在到达RC之前对地址进行映射,将物理地址转化成PCIe总线地址,如果是未启用IOMMU并且架构是正常的架构,无需转换,物理地址即PCIe总线地址。然后RC发送TLP,TLP在PCIe总线上经由PCIe Switch进行寻路,最终找到该I/O设备。该I/O设备的PCIe接口接收到TLP之后解包,分析信息之后将CPU需要的控制数据形成TLP包发到PCIe总线上,TLP包经过寻路,最终到达RC,然后RC解包,之后将数据发到CPU的寄存器中

DMA引擎访问内存:在进行完DMA引擎编程后,DMA引擎将直接和内存进行交互,不需要CPU核心进行控制。以I/O设备使用DMA引擎向内存写入数据为例,DMA引擎根据内存的物理地址(如果启用了IOMMU则为映射后的物理地址)形成TLP,将目的地址写为该地址,源地址写为I/O设备的PCIe总线地址空间中的指定存储单元的地址(每个TLP发送完之后进行移位,并将字节数减去相应数量)。之后将TLP发送出去,TLP在PCIe总线上进行寻路,由于是内存的地址,最终找到RC。RC进行解包之后,如果启用IOMMU则进行反映射,将映射后的物理地址反映射回原本的物理地址,如果是正常架构并且未启用IOMMU则直接使用传入的目的地址。然后生成请求发送给内存控制器,内存控制器将请求加入到请求队列,最终等到出队列时执行数据的写入操作

P2P DMA

P2P DMA指的是两个PCIe设备直接进行类似DMA的操作,直接进行数据交互,不需要走内存也不需要CPU在传输的过程中进行控制干预,但是仍需要CPU进行中断响应(目前所有的常规架构下DMA都需要),一个典型的例子就是GPU Direct RDMA,这个功能能实现的基础是PCIe协议在实现的时候保留了一些字段,这些字段可以供厂商使用。实现一些自定义的功能,所以其在传输的时候就是互相发TLP(正常情况下),但是NVIDIA不是这样,其在PCIe的基础上构建了一套自己的非标准协议,以实现NVIDIA硬件间特有的高性能的P2P DMA,所以GPU Direct RDMA和P2P Copy(GPU与GPU之间的P2P DMA)基于的是NVIDIA实现的非标准协议

此外,NVIDIA提供了GPU间无需CPU处理中断的完全不需要CPU进行干预的通信——P2P Access,这种通信方式不属于P2P DMA,并且其基于标准的PCIe协议。其原理是当GPU发出一个LD/ST指令时,这个指令访问的地址为非本GPU的显存的地址的时候,GPU上的PCIe接口会将这个访问变为TLP发到PCIe总线上

此外,在GPU和某些NIC(比如CX系列)中有MMU单元,因为这些PCIe设备中使用虚拟地址,所以需要把进程或者QP中的虚拟地址转换成PCIe总线地址(大部分情况下页表中存的是MMIO类型的地址)

在这个过程中,寻址使用的一直都是PCIe总线地址,但是如果跨RC的话需要进行IOMMU映射(如果需要)

  • 38
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值