老男孩读 pcie

之一1
在这里插入图片描述

2

RC的内部实现很复杂,PCIe Spec也没有规定RC该做什么,还是不该做什么。我们也不需要知道那么多,只需清楚:它一般实现了一条内部PCIe总线(BUS 0),以及通过若干个PCIe bridge,扩展出一些PCIe Port,如下图所示:

在这里插入图片描述

PCIe Endpoint,就是PCIe终端设备,比如PCIe SSD,PCIe网卡等等,而Legacy Endpoint,接口是PCIe,但是内部的行为却和传统的PCI或者PCI-x一样(比如支持IO空间)。这些Endpoint可以直接连在RC上,也可以通过Switch连到PCIe总线上。Switch用于扩展链路,提供更多的端口用以连接Endpoint。拿USB打比方,我们计算机主板上提供的USB口有限,如果你要连接很多USB设备,比如无线网卡、无线鼠标、USB摄像头、USB打印机、U盘等等,这时候不够用,怎么办?我会去找马云,向它买个USB HUB,下面这个就不错:

每个Switch内部,也是有一根内部PCIe总线的,然后通过若干个Bridge,扩展出若干个下游端口,如下图所示:
在这里插入图片描述

3
在这里插入图片描述

在这里插入图片描述

4
一个TLP,最多只能携带4KB有效数据,因此,上例子,如果Endpoint需要读16KB的数据,RC必须返回4个CplD给Endpoint。注意,Endpoint只需发1个MRd就可以了。
5
在这里插入图片描述
在这里插入图片描述

对一个PCIe设备来说,它开放给Host访问的设备空间首先会映射到Host的内存空间,Host如果想访问设备的某个空间,TLP Header当中的地址应该设置为该访问空间在Host内存的映射地址。如果Host内存空间小于4GB,则Memory读写TLP的Header大小为3DW,大于4GB,则为4DW。那是因为,对4GB内存空间,32bit的地址用1DW就可以表示,该地址位于Byte8-11;而4GB以上的内存空间,需要2DW表示地址,该地址位于Byte8-15。

Memory TLP的目标是通过内存地址告知的,而源是通过”Requester ID”告知。每个设备在PCIe系统中都有唯一的ID,该ID由总线(Bus)、设备(Device)、功能(Function)三者唯一确定。这个后面也会专门讲,这里只需知道一个PCIe组成有唯一的ID,不管是RC,Switch还是Endpoint。

endpoint type0

Endpoint和Switch的配置(Configuration)格式不一样,分别为Type 0和 Type 1来表示。配置可以认为是一个Endpoint或者Switch的一个标准空间,这段空间在初始化时也需要映射到Host的内存空间。与设备的其他空间不同,该空间是标准化的,即不管哪个厂家生产的设备,都需要有这么段空间,而且哪个地方放什么东西,都是协议规定好的,Host按协议访问这部分空间。由于每个设备ID唯一,而其Configuration又是固定好的,因此,Host访问PCIe设备的配置空间,只需指定目标设备的ID就可以了,不需要内存地址。

Configuration TLP
6

整个配置空间就是一系列寄存器的集合,其中Type 0是Endpoint的配置,Type 1是Bridge(PCIe时代就是Switch)的配置,都由两部分组成:64 Bytes的Header+192Bytes的Capability结构,后者是设备告诉Host它有多牛逼,都会什么绝活。

进入PCIe时代,PCIe能耐更大,192 Bytes不足以罗列它的绝活。为了保持后向兼容,又要不把绝活落下,怎么办?很简单,我扩展后者的空间,整个配置空间由256 Bytes扩展成4KB,前面256 Bytes保持不变:

在这里插入图片描述

在这里插入图片描述
一个PCIe设备,可能有若干个内部空间(属性可能不一样,比如有些可预读,有些不可预读)需要映射到内存空间,设备出厂时,这些空间的大小和属性都写在Configuration BAR寄存器里面,然后上电后,系统软件读取这些BAR,分别为其分配对应的系统内存空间,并把相应的内存基地址写回到BAR。(BAR的地址其实是PCI总线域的地址,CPU访问的是存储器域的地址,CPU访问PCIe设备时,需要把总线域地址转换成存储器域的地址。

在这里插入图片描述

来个例子,看一下一个PCIe设备,系统软件是如何为其分配映射空间的。
endpoint 的bar

在这里插入图片描述

上电时,系统软件首先会读取PCIe设备的BAR0,得到数据:
step1 读bar
在这里插入图片描述

然后系统软件往该BAR0写入全1,得到:
step2 写全1 到bar
在这里插入图片描述

BAR寄存器有些bit是只读的,是PCIe设备在出厂前就固定好的bit,写全1进去,如果值保持不变,就说明这些bit是厂家固化好的,这些固化好的bit提供了这块内部空间的一些信息:

怎么解读?低12没变,表明该设备空间大小是4KB(2的12次方),然后低4位表明了该存储空间的一些属性(IO映射还是内存映射,32bit地址还是64bit地址,能否预取?做过单片机的人可能知道,有些寄存器只要一读,数据就会清掉,因此,对这样的空间,是不能预读的,因为预读会改变原来的值),这些都是PCIe设备在出厂前都设置好的,提供给系统软件的信息。

然后系统软件根据这些信息,在系统内存空间找到这样一块地方来映射这4KB的空间,把分配的基地址写入到BAR0:

step3 将内存空间的基地址写 bar
在这里插入图片描述

从而最终完成了该PCIe空间的映射。一个PCIe设备可能有若干个内部空间需要开放出来,系统软件依次读取BAR1,BAR2。。。,直到BAR5,完成所有内部空间的映射。

上面主要讲了Endpoint的BAR,Switch也有两个BAR,今天不打算讲,下节讲TLP路由,再回过头来讲。继续说配置空间。

前面说每个PCIe设备都有一个配置空间,其实这样说是不准确的,而是每个PCIe设备至少有一个配置空间。一个PCIe设备,它可能具有多个功能(function),比如既能当硬盘,还能当网卡。每个功能对应一个配置空间。

因此,在整个PCIe系统中,只要知道了Bus+Device+Function,就能找到对应的Function。寻址基本单元是功能(function),它的ID就由Bus+Device+Function组成 (BDF)。一个PCIe系统,可以最多有256条Bus,每条Bus上可以挂最多32个Device,而每个Device最多又能实现8个Function,而每个Function对应着4KB的配置空间。上电的时候,这些配置空间都是需要映射到Host的内存空间,因此,需要占用内存空间是:256328*4KB =256MB。在这个动辄4GB、8GB内存的时代,256MB算不了什么。

因此,在整个PCIe系统中,只要知道了Bus+Device+Function,就能找到对应的Function。寻址基本单元是功能(function),它的ID就由Bus+Device+Function组成 (BDF)。一个PCIe系统,可以最多有256条Bus,每条Bus上可以挂最多32个Device,而每个Device最多又能实现8个Function,而每个Function对应着4KB的配置空间。上电的时候,这些配置空间都是需要映射到Host的内存空间,因此,需要占用内存空间是:256328*4KB =256MB。在这个动辄4GB、8GB内存的时代,256MB算不了什么。

zhi7

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值