写在前面:
1、本文参考来源PCIe 6.2,2024.02.25
2、仅作为个人学习记录和分享,转载请注明出处
3、个人能力有限,协议的理解均基于个人,如有错误还望指出
目录
一、通用类型包的排序规则说明
1、前置说明
此部分的排序规则适用于PCIe协议中的所有类型,包括Memory、IO、配置和消息,除了UIO和Flow-Through IDE流。注意排序规则只适用于使用同一个TC的TLP包,即不讨论不同的VC之间的包的顺序,因为在TC-VC的映射规则中,TC不允许映射到多个VC上,且不同的VC之间的包传输顺序不受此规则约束。
2、排序规则表及各个顺序说明
排序规则如表1所示。表中列表示先发起的传输,行表示随后发起的传输。行列的交点中的值说明了两个传输之间是否可以出现后发起的超越先发起的情况。其中Yes说明在阻塞产生时,后发起的传输必须被允许超越先发起的传输,避免死锁。Y/N表示后发起的传输可选择性的超越先发起的传输,即可超越或者阻塞。No表示后发起的传输不允许超越先发起的传输,即遵守生产者-消费者的强排序模型。
表1 排序规则表
行传输能否超越列传输 | Posted请求(Col 2) | Non-Posted请求 | 完成包(Col 5) | ||
读请求(Col 3) | 包含数据的NPR(Col 4) | ||||
Posted请求(Row A) | a)No b)Y/N | Yes | Yes | a)Y/N b)Yes | |
Non-Posted请求 | 读请求(Row B) | a)No b)Y/N | Y/N | Y/N | Y/N |
包含数据的NPR(Row C) | a)No b)Y/N | Y/N | Y/N | Y/N | |
完成包(Row D) | a)No b)Y/N | Yes | Yes | a)Y/N b)No |
表中各个术语和情况说明:
Posted请求:Memory写请求或者消息请求
Read请求:配置读请求、IO读请求或者Memory读请求
包含数据的NPR:配置写请求、IO写请求、原子请求或者DMWr
A2a:PR不允许超越另一个PR,除非A2b的情况出现
A2b:携带RO置1的PR允许超越另一个PR。携带IDO置1的PR允许超越另一个PR,如果两个Requester ID(FM下包括Requester Segment)不同的话,额外的,如果Requester ID相同时但两者同时包含PASID且PASID不相同的时(IDO置1),也允许超越
A3/A4:PR必须被允许超越NPR请求来避免死锁
A5a:PR允许超越completion除了A5b的情况出现时
A5b:传统PCI模式下,从PCIe到PCI/PCIX桥的传输,PR必须能够超越completion来避免死锁
B2a:读请求不允许超越PR,除非B2b的情况出现
B2b:携带IDO置1的读请求在两者Requester ID(FM下,包括Requester Segment)相同的情况下允许超越另一个PR,此外,当两者均包含PASID且PASID不相同时(IDO置1且Reuquester ID相同),也允许读请求超越另一个PR
C2a:携带数据的NPR不允许超越PR,除非出现C2b的情况
C2b:携带数据且RO置1的NPR可以超越PR,当两者的Reuqester ID(FM下包括Requester Segment)不同时和Requester ID相同且均包含PASID但是PASID不同
B3/B4/C3/C4:NPR允许超越另一个NPR
B5/C5:NPR允许超越completion
D2a:completion不允许超越PR除非D2b的情况出现
D2b:IO或者配置写的completion允许超越PR;携带RO置1的completion允许超越PR;携带IDO置1且两者Completer ID跟Reuqester ID不相同的情况下允许completer超越PR
D3/D4:completion必须能够超越NPR来避免死锁
D5a:包含不同的Transaction ID的completion允许互相超越
D5b:携带相同的Transaction ID的completion不允许互相超越
补充:Attr[2:0]说明:
Attr[2] | Attr[1] | 排序类型 | 排序模型 |
---|---|---|---|
0 | 0 | 默认排序 | PCI强排序模型 |
0 | 1 | 宽松排序(RO) | PCI-X宽松排序模型 |
1 | 0 | 基于ID的排序(IDO) | 基于Reuqester/Completer ID的独立的排序 |
1 | 1 | 宽松排序+ID排序 | 宽松排序和ID排序两者之间为逻辑或 |
Attr[1]不适用且必须清零:配置请求+IO请求+Memory请求(触发中断的)+消息请求
Attr[2]对配置请求和IO请求属于保留位。对completion来说,不需要拷贝request中的IDO为。如果Completer的IDO使能了的话,则建议对所有completion置1IDO。
不允许组合Memory读请求或者不同请求的完成包
No Snoop包不影响排序要求或者说排序行为。
Ep不可以阻塞completion的接收。
3、三种排序模型说明
3.1 生产者-消费者 强排序模型
此排序模型表示为严格按照命令产生和到达的顺序进行处理,对所有类型(PR-NPR-Completion)的TLP包同等处理,当前任一类型包产生阻塞后,其后产生的任何类型的包均无法发出。
3.2 宽松排序
此排序模型就是在生产者-消费者 强排序模型的基础上增加RO(Relaxing Ordering)的开关配置,来允许部分包在强排序的基础上超越先产生的包进行传输。如表1中A2b的情况。
3.3 基于ID的排序
此排序模型跟RO类似,也是在前排序的基础上增加IDO(ID-Based Ordering)的开关,来让不同的ID的TLP包产生超越的行为。如表1中A2b的情况
4、相关寄存器
图1 Device Control Register
图2 Device Control 2 Register
Enable Relaxed Ordering:此寄存器的属性为RW。当此寄存器置1时表示允许置1 Attr[1]来表示此TLP采用RO排序规则进行传输。默认值为1b。
IDO Request Enable:此寄存器属性为RW。当此寄存器置1时表示允许Request的Attr[2]允许置1来表示此请求采用IDO排序规则进行传输。Ep允许实现此能力。对VF来说跟其从属的PF一致。默认值为0b。
IDO Completion Enable:此寄存器的属性为RW。当此寄存器置1时表示允许Completion的Attr[2]允许置1来表示此完成包采用IDO排序规则进行传输。Ep允许实现此能力。对VF来说跟其从属的PF一致。默认值为0b。
二、UIO类型包的排序规则说明
UIO的全称为Unordered IO,主要是支持Requester管理顺序模型的请求/完成类型的集合(支持VC),6.1上新提出的定义。UIO跟Non-UIO不可以在同一个TC/VC上进行混合,且不允许两者之间存在排序依赖关系。
表2 UIO TLP排序规则
行能否超越列 | UIO PR-FC TLP(Col U1) | UIO NPR-FC TLP(Col U2) | UIO Completion(Col U3) |
UIO PR-FC TLP(Row UA) | Yes/No | Yes/No | Yes/No |
UIO NPR-FC TLP(Row UB) | Yes/No | Yes/No | Yes/No |
UIO Completion(Row UC) | Yes | Yes | Yes/No |
UIO完成包必须允许能够超越UIO请求;UIO允许其他情况的任意重排序。
UIO TLP的避免死锁的规则如表3和表4所示。
表3 下游端口的UIO接收依赖规则
行是否独立于列 | 出口传输 | |||
UIO Mmeory Write Request(Col 1) | Other UIO Mmeory Request(Col 2) | UIO Completion(Col 3) | ||
入口接收 | UIO Mmeory Write Request(Row A) | Yes/No | Yes/No | Yes/No |
Other UIO Mmeory Request(Row B) | Yes/No | Yes/No | Yes/No | |
UIO Completion(Row C) | Yes | Yes | Yes/No |
表4 上游端口的UIO接收依赖规则
行是否独立于列 | 出口传输 | |||
UIO Mmeory Write Request(Col 1) | Other UIO Mmeory Request(Col 2) | UIO Completion(Col 3) | ||
入口接收 | UIO Mmeory Write Request(Row A) | Yes | Yes | Yes/No |
Other UIO Mmeory Request(Row B) | Yes | Yes | Yes/No | |
UIO Completion(Row C) | Yes | Yes | Yes |
下游端口包含RP和Switch下游端口;上游端口包含Switch上游端口和Ep的上游端口
三、一些补充说明
1、对正常TLP的读写更新排序和颗粒度补充说明
作为更新排序的一个例子,假设数据块位于主机内存中,主机CPU首先写入位置A,然后写入另一个位置B。使用单个读事务读取该数据块的请求程序不能保证按照顺序观察这些更新。换句话说,无论位置A和B在数据块中的位置如何,请求者可能在位置B中观察到更新的值,而在位置A中观察到旧的值。除非Completer对更新顺序做出自己的保证(在本规范之外),否则依赖于更新顺序的Requester必须在启动对位置a的后续读取以返回其更新值之前,通过一个读事务观察对位置B的更新。
作为更新粒度的一个例子,如果主机CPU向主机内存写入一个QW,那么从主机内存读取该QW的请求程序可能会看到QW的一部分更新了,而另一部分包含旧值。强烈建议主机平台保证,当主机CPU将对齐的DW或对齐的QW写入主机内存时,PCI Express读取观察到的更新粒度不会小于DW。
2、对UIO读写更新排序和颗粒度的补充说明
如果requester使用UIO读请求来从Completer访问一块数据,并且此数据同时被UIO写命令进行更新,那么其观察到的结果可能为写完成后的或者完全没有操作写之前的。但是特别的对64B对齐的数据块来说,其需要为写完成后的数据。对于写来说也是一致的,也就是说对64B对齐的数据块,其操作必须是一致的,不可以处于完成了部分另一部分未完成的情况。允许实现64B更小的粒度