无论Request TLP,还是作为回应的Completion TLP,它们模样都差不多:
TLP主要由三部分组成:Header,Data和CRC。TLP都是生于发送端的事务层(Transaction Layer),终于接收端的事务层。
每个TLP都有一个Header,跟动物一样,没有头就活不了,所以TLP可以没手没脚,但不能没有头。事务层根据上层请求内容,生成TLP Header。Header内容包括发送者的相关信息、目标地址(该TLP要发给谁)、TLP类型(前面提到的诸如Memory read,Memory Write之类的)、数据长度(如果有的话)等等。
Data Payload域,用以放有效载荷数据。该域不是必须的,因为并不是每个TLP都必须携带数据的,比如Memory Read TLP,它只是一个请求,数据是由目标设备通过Completion TLP返回的。后面我们会整理哪些TLP需要携带数据,哪些TLP不带数据的。前面也提到,一个TLP最大载重是4KB,数据长度大于4KB的话,就需要分几个TLP传输。
ECRC(End to End CRC)域,它对之前的Header和Data(如果有的话)生成一个CRC,在接收端然后根据收到的TLP,重新生成Header和Data(如果有的话)的CRC,和收到的CRC比较,一样则说明数据在传输过程中没有出错,否则就有错。它也是可选的,可以设置不加CRC。
Data域和CRC域没有什么好说的,有花头的是Header域,我们要深入其中看看。
一个Header大小可以是3DW,也可以是4DW。以4DW的Header为例,TLP的Header长下面样子:
红色区域为所有TLP Header公共部分,所有Header都有这些;其它则是跟具体的TLP相关。
稍微解释一下:
Fmt:Format, 表明该TLP是否带有数据,Header是3DW还是4DW;
Type:TLP类型,上一节提到的,Memory Read, Memory Write, Configuration Read, Configuration Write, Message和Completion,等等;
R: Reserved,为0;
TC: Traffic Class,TLP也分三六九等,优先级高的先得到服务。这里是3比特,说明可以分为8个等级,0-7,TC默认是0,数字越大,优先级越高;
Attr: Attrbiute, 属性,前后共三个bit,先不说;
TH: TLP Processing Hints,先不说;
TD: TLP Digest,之前说ECRC可选,如果这个这个bit置起来,说明该TLP包含ECRC,接收端应该做CRC校验;
EP: Poisoned data, 有毒的数据,远离,哈哈;
AT: Address Type,地址种类,先不说;
Length: Payload数据长度,10个bit,最大1024,单位DW,所以TLP最大数据长度是4KB; 该长度总是DW的整数倍,如果TLP的数据不是DW的整数倍(不是4Byte的整数倍),则需要用到下面两个域:
Last DW BE 和 1st DW BE。
我觉得,到目前为止,对于Header,我们只需知道它大概有什么内容,没有必要记住每个域是什么。
这里重点讲讲Fmt和Type,看看不同的TLP(精简版的,Native PCIe设备所有)其Fmt和Type应该怎样编码:
TLP |
Fmt |
Type |
Comment |
Memory Read Request |
000=3DW,no data 001=4DW,no data |
0 0000 |
3DW或者4DW是指Header大小,Memory Read不带数据 |
Memory Write Request |
010=3DW,with data 011=4DW,with data |
0 0000 |
Memory Write必须带数据 |
Configuration Type 0 Read Request |
000=3DW,no data |
0 0100 |
读Endpoint的Configuration,不带数据,Header总是3DW |
Configuration Type 0 Write Request |
010=3DW,with data |
0 0100 |
写Endpoint的Configuration,带数据,Header总是3DW |
Configuration Type 1 Read Request |
000=3DW,no data |
0 0101 |
读Switch的Configuration,不带数据,Header总是3DW |
Configuration Type 1 Write Request |
010=3DW,with data |
0 0101 |
写Switch的Configuration,带数据,Header总是3DW |
Message Request |
001 = 4DW, no data |
1 0rrr |
Message的Header总是4DW |
Message Request with Data |
011 = 4DW, with data |
1 0rrr |
Message的Header总是4DW |
Completion |
000=3DW,no data |
0 1010 |
Completion的Header总是3DW |
Completion with Data |
010=3DW,with data |
0 1010 |
Completion的Header总是3DW |
从上可以看出,Configuration和Completion 的TLP(以C打头的TLP),其Header大小总是3字节;Message TLP的Header总是4字节;而Memory相关的TLP取决于地址空间的大小,地址空间小于4GB的,Header大小为3DW,大于4GB的,Header大小则为4DW。
上面介绍了几个TLP Header的通用部分,下面分别介绍具体TLP的Header。
-
Memory TLP
有两个重要的东西在前面没有提到,那就是TLP的源和目标,即,该TLP是哪里产生的,它要到哪里去,它们都包含在Header里面的。因为不同的TLP类型,寻址方式不同,因此要具体TLP具体来看这两个东西。
对一个PCIe设备来说,它开放给Host访问的设备空间首先会映射到Host的内存空间,Host如果想访问设备的某个空间,TLP Header当中的地址应该设置为该访问空间在Host内存的映射地址。如果Host内存空间小于4GB,则Memory读写TLP的Header大小为3DW,大于4GB,则为4DW。那是因为,对4GB内存空间,32bit的地址用1DW就可以表示,该地址位于Byte8-11;而4GB以上的内存空间,需要2DW表示地址,该地址位于Byte8-15。
该TLP经过Switch的时候,Switch会根据地址信息,把该TLP转发到目标设备。之所以能唯一的找到目标设备,那是因为不同的Endpoint设备空间会映射到Host内存空间的不同位置。
关于TLP路由,后面还会专门讲。
Memory TLP的目标是通过内存地址告知的,而源是通过”Requester ID”告知。每个设备在PCIe系统中都有唯一的ID,该ID由总线(Bus)、设备(Device)、功能(Function)三者唯一确定。这个后面也会专门讲,这里只需知道一个PCIe组成有唯一的ID,不管是RC,Switch还是Endpoint。
-
Configuration TLP
Endpoint和Switch的配置(Configuration)格式不一样,分别为Type 0和 Type 1来表示。配置可以认为是一个Endpoint或者Switch的一个标准空间,这段空间在初始化时也需要映射到Host的内存空间。与设备的其他空间不同,该空间是标准化的,即不管哪个厂家生产的设备,都需要有这么段空间,而且哪个地方放什么东西,都是协议规定好的,Host按协议访问这部分空间。由于每个设备ID唯一,而其Configuration又是固定好的,因此,Host访问PCIe设备的配置空间,只需指定目标设备的ID就可以了,不需要内存地址。
下面是访问Endpoint的配置空间的TLP Header (Type 0):
Bus Number + Device + Function就唯一决定了目标设备; Ext Reg Number + Register Number相当于配置空间的偏移。找到了设备,然后指定了配置空间的偏移,就能找到具体想访问的配置空间的某个位置。
-
Message TLP
Message TLP用以传输中断、错误、电源管理等信息,取代PCI时代的边带信号传输。Message TLP的Header 大小总是4DW。
Message Code来指定该Message的类型,具体如下:
不同的Message Code,最后两个DW的意义也不同,这里不展开。
-
Completion TLP
有non-posted request TLP,才有Completion TLP。有因才有果。前面看到,Requester 的TLP当中都有Requester ID和Tag,来告诉接收者发起者是谁。那么响应者的目标地址就很简单,照抄发起者的源地址就可以了。因此,Completion TLP的Header如下:
Completion TLP,一方面,可以返回请求者的数据,比如作为Memory或者Configuration Read的响应;另一方面,还可以返回该事务(Transaction)的状态,因此,在Completion TLP的Header里面有一个Completion Status,用以返回事务状态: