基础协议之pcie部分
一、tlp包的包头
在pcie的系统中,tlp包的包头的结构有许多部分是相似的,通过掌握这些常规的包头,能帮助理解在pcie总线上各个设备之间如何进行数据的收发。
通用的字段
通用字段 | 作用 |
---|---|
fmt | 决定了包头是3dw还是3dw,tlp包是否包含数据 |
type | 决定tlp包的类型,比如mrd、mwr、cfg、msg、cpl、cpld |
tc | traffic class,用于决定tlp包处理的优先级,3bit,数值越大优先级越高 |
attr | 属性,3bit,需要注意3个bit不是连在一起,attr[2]表示的是id的一种排序方法。attr[1]表示tlp包的传输是保序还是乱序,保序要求严格按照tlp的顺序。attr[0]表示是否需要cache一致性,在进行大量数据传输的时候,可以选择关闭cache,提高效率。 |
td | tlp digest该字段为1的时候需要在tlp包的最末尾添加ecrc,0不需要添加 |
ep | tlp包错误信号 |
at | address type,表示地址类型,是否需要进行地址的转换 |
length | 用于mwr,cpl,msg包,10bit,0-1024dw,1-1023表示对应数量的dw。tlp的起始地址和结束地址不能跨4k边界 |
first/last dw be | 用于表示第一个dw和最后一个dw有效的字节,每一位对应一个字节。 |
内存请求tlp包头结构
对于内存请求包的包头如上图所示,3dw和4dw对应的可访问的地址空间是不同的。
-
request id
其中这个request id由3部分组成:分别是bus_num[7:0]、device_num[4:0]、func_num[2:0]决定。pcie端点设备在上电时候会被rc进行枚举,并分配对应的id,每个设备的id在上电时确定。
-
tag
这个表示是由请求方产生的,可以和request id组成一个唯一的id,保证唯一性,可以用来识别应答信息,用于包过滤。
对于mwr和mrd tlp包,他们的包头信息基本是一致的,同样包括了常规字段和requester id等。
但是读内存请求mrd是一个非转发non-posted的包,需要一个独立的反馈事务来获取反馈回来的数据。
mwr tlp包是一个转发包posted,写tlp包中需要包含数据。
完成包cpl、cpld包头
完成包的包头结构如下:
除了第一个dw的常规字段外,还有一些特殊的字段,需要掌握一下:
字段 | 作用 |
---|---|
completer id | 指示是由谁反馈的数据 |
requester id | 指示是谁请求的数据 |
completion status | 3bit完成状态,000是成功,001是不支持,010是配置请求重试,100是忽略 |
byte count | 指的是剩余未反馈数据的字节数量 |
routing tag | 从请求包当中复制的表示信号 |
lower address | 第一个有效字节地址的低7bit |
二. 具体的tlp组包分析
2.1 内存读请求mwr
假设系统的一些参数如下:
- pcie的最大负载为mps=512 字节;
- 系统边界rcb=128字节
- 需要读取的地址起始地址:0x0010_00f8
- 需要读取的长度:272字节
- 请求id号request id:0x0001;
- 回复者id号completer id:0x1000;
- 标识tag:0x00;
基于上面的消息我们就能来模拟一个tlp包的传输了。
首先需要产生一个读请求包,所以可以确定ftm字段和type字段的值。
然后是tc,attr等字段,都保持为0就可以了。
然后需要注意的是要读取的数据长度为272字节,刚好是68个dw,所以在长度这里需要填入dw的长度,也就是0x44=0b00_0100_0100;由于读取的长度刚好是dw的整数倍,因为在first dw be和last dw be里面都填1,表示第一个和最后一个dw的数据中的每个字节都有效。
然后把tag、id填写到tlp包中,最后是填写入地址就可以了。
因此,得到的最终的这个mrd包的结果如下:
当rc(root complex)接收到这个读请求包之后,就会从内存当中读取数据,并把这些数据组成一个一个的tlp包通过id路由的方式,发送给端点的pcie设备。
2.2 cpld
cpld包的包头结构如下:
第一个cpld包:
首先确定cpld包的类型,确定fmt字段和type字段的值。
然后看第一个包能够发送多少数据,因为要读取的数据的地址是0x0010_00f8。由于不能跨rc界,因此第一次能够读取的数据个数为8字节,所以第一个tlp包的长度为8/4=2dw。
然后是需要填写当前还剩下多少字节没有返回,由于第一个tlp还没有返回数据,因此还剩下272个字节没有发送,所以这里需要填入272。
status的值,需要根据返回的状态来确定,正确返回需要填写3’b000。
然后依次把请求者id和回复者id还有tag进行一个填写。
最后还需要关心的是一个lower address字段,该字段应该填入第一个有效字节的地址的低7位,也就是0x0010_00f8的低7位,也就是0x78。
然后在cpld的包头后面,跟上从内存当中读出的数据就好了。
因此可以得到第一个cpld包的内容如下:
第二个cpld包:
第一个cpld包返回了8字节的数据,还剩下274字节的数据。
根据最大负载的mps=512字节,所以还剩下的数据小于最大负载。然后再考虑rcb,再保证不跨rcb的情况下能传输的最大长度就是两个rcb的长度也就是256字节。因此,本次传输的数据的长度就是256字节,换算成dw就是256/4=64=0x40。本次传输的起始地址是接着上一个包的结束地址,也就是0x0010_0100,可以构成第2个cpld包。
关键参数:
- 长度64dw
- 剩余的count 264字节
- lower address,第一个有效字节低7位也就是0x00
第三个cpld包:
在上一个包返回了256个字节后,还剩下8个字节的数据没有发送,因此在本包中,还需要完成最后的这8个字节的发送,本次发送的起始地址是0x0010_0200,发送的长度是2个dw
这样就完成了本次请求的全部的cpld包的返回了。
三、未完待续
下章将继续介绍fpga pcie ip设置和使用。
欢迎关注知乎:北京不北
欢迎+v:beijing_bubei
欢迎关注douyin:near.x (北京不北)
获得免费答疑,长期技术交流。
四、参考文献
https://blog.csdn.net/qq_41332806/article/details/115338533
发表评论