首页 理论教育PCIExpressTLP×12.2.1DMA写使用

PCIExpressTLP×12.2.1DMA写使用

【摘要】:当软件启动DMA写过程后,DMA控制逻辑将组织存储器写TLP发送给RC。Capric卡使用4DW长度的TLP头,即使用64位地址编码格式。本节使用M保存TLP中使用的实际长度,其值如公式12-4所示。当M大于0x20时,Capric卡进行DMA写时需要发送多个存储器写请求TLP,而M小于或等于0x20时仅需要发送1个存储器写请求TLP。

软件启动DMA写过程后,DMA控制逻辑将组织存储器写TLP发送给RC。PCIe总线使用Posted总线事务发送存储器写TLP。Capric卡使用4DW长度的TLP头,即使用64位地址编码格式。存储器写TLP由一个通用TLP头加上若干数据字段组成,存储器写TLP格式如图12-2所示。

978-7-111-29822-9-Part02-161.jpg

图12-2 存储器写请求TLP

1.DMA写操作使用的实际长度

DMA写逻辑首先从WR_DMA_ADR寄存器中获得起始地址A(A31A30...A1A0),然后从WR_DMA_SIZE寄存器中获得传送长度L(L15L14...L1L0),并由A和L,通过计算获得本次DMA写的结束地址B(B31B30...B1B0),其值如公式12-3所示。

B=A+L-1 (12-3)

系统软件需要保证B的计算结果不会出现进位,而DMA写逻辑由公式12-3获得本次数据传送的地址范围A~B。在存储器读写TLP中,Length字段以DW为单位,因此向A~B这段数据区域进行DMA写时,Capric卡实际上需要向Head4(A)~Tail4(B)这段数据区域进行DMA写操作,同时使用TLP的First DW BE和Last DW BE字段进行对界处理。

如果一次DMA写操作向0xFFF0-0003~0xFFF0-0200这段区域传送数据时,虽然这段数据区域的长度为0x1FE字节[86],但是由于TLP的Length字段以DW为基本单位,因此Capric卡需要向0xFFF0-0000~0xFFF0-0203这段区域进行写操作,然后通过First DW BE和Last DW BE字段屏蔽0xFFF0-0000~0xFFF0-0002和0xFFF0-0201~0xFFF0-0203这两段数据区域。

因此在L中存放的长度(A~B数据区域的长度)并不是该TLP使用的实际长度。在该TLP中使用的实际长度为Head4(A)~Tail4(B)这段数据区域的长度。本节使用M(M15M14...M1M0)保存TLP中使用的实际长度,其值如公式12-4所示。

M=Tail4B)-Head4A+1)≫2 (12-4)

使用以上公式可以较为方便地得出DMA写操作使用的实际长度,但是公式12-3和公式12-4中使用了多个32位的加法器,非常耗费FPGA的内部资源。为此本次设计使用了另外一种算法计算M的值,如公式12-5所示。

M′=Head4(00A1A0+00L1L0+3)-Head4(00A1A0))

M=L≫2+M′≫2 (12-5)

我们可以使用公式12-5计算0xFFF0-0003~0xFFF0-0200这段区域使用的实际长度M。在这段区域中,A为0xFFF0-0003,而L=0x1FE,因此M′等于8,而M=0x7F+0x2=0x81。该结果与公式12-4计算结果相等。但是在公式12-5中,M′的计算仅使用4位加法器,其实现代价比公式12-4所耗费的资源少得多,更为重要的是计算速度也比公式12-4快得多。

在LogiCORE中,Max_Payload_Size Supported参数的最大值为512B。但是链路两端经过协商后,实际确认的Max_Payload_Size参数可能小于512B,在多数x86处理器系统中,该参数为128B,因此下文假设Max_Payload_Size参数为128B。

当M大于0x20(即数据区域的实际长度超过128B)时,Capric卡进行DMA写时需要发送多个存储器写请求TLP,而M小于或等于0x20时仅需要发送1个存储器写请求TLP。下文分别讨论这两种情况。

2.M小于或等于0x20

Capric卡向数据区域[A31A30...A1A0~B31B30...B1B0]进行DMA写操作时,如果通过公式12-5的计算发现M小于或等于0x20,DMA控制逻辑将组织1个或者2个存储器写TLP传递给LogiCORE。

如果这个TLP所传递的数据区域跨越了4KB边界,将组织2个存储器写TLP,因为PCIe总线规定被传送的数据区域不能跨越4KB边界;如果没有跨越4KB边界,Capric卡组织1个存储器写TLP。我们首先讨论这段数据区域没有跨越4KB边界的情况,此时这个存储器写TLP的各个字段如下所示。

●Fmt字段为0b10或者0b11,表示使用3DW或者4DW的TLP头,而且带有数据。在Capric中,Fmt字段为0b011。

●Type字段为0b00000,表示当前TLP为存储器写TLP。

●TC字段为0b000,表示传送类型为TC0。

●TD位为0b0,表示当前TLP不含有ECRC信息。

●EP位为0b0,表示当前TLP是正常的,没有出现完整性问题。

●Attr字段为0b00,表示当前TLP不使用Relaxed Ordering,由硬件完成Cache一致性操作。有关Cache一致性的处理见第3.3节和第12.3.6节,而Relaxed Ordering的描述见第11.4节。

●AT字段为0b00,表示不进行地址转换。

●Length字段由公式12-5计算而来,其值与M相等,单位为DW,最大值为0x20,即128B。假定在Capric卡中,Max_Payload_Size参数为128B。在x86处理器系统中,多数RC的Max_Payload_Size参数为128B。

●Address字段为A31A30...A2。Address字段为DW对界的,共由30位组成。

●当M不等于1时,Last DW BE字段与TLP报文的结束地址有关,更准确地讲,与B1和B0位有关,如下所示。

B1B0=0b11,则Last DW BE字段为0x1111。

B1B0=0b10,则Last DW BE字段为0x0111。

B1B0=0b01,则Last DW BE字段为0x0011。(www.chuimin.cn)

B1B0=0b00,则Last DW BE字段为0x0001。

●当M不等于1时,First DW BE字段与TLP报文的起始地址有关,更准确地讲,与A1和A0位有关,如下所示。

A1A0=0b00,则First DW BE字段为0x1111。

A1A0=0b01,则First DW BE字段为0x1110。

A1A0=0b10,则First DW BE字段为0x1100。

A1A0=0b11,则First DW BE字段为0x1000。

当M等于1时,Last DW BE字段必须为0b0000;First DW BE字段的计算与A1A0和B1B0相关,其中(First DW BE)A1A0~(First DW BE)B1B0字段为1,其他位为0。这两个字段的关系如表12-2所示。

表12-2 First DW BE与A1A0,B1B0之间的关系

978-7-111-29822-9-Part02-162.jpg

(续)

978-7-111-29822-9-Part02-163.jpg

值得注意的是,当M小于或等于0x20时,TLP所传递的报文,其数据区域依然可能会跨越4KB边界。如Capric卡向0xFFFF-0FFF~0xFFFF-1000数据区域进行DMA写时,虽然M等于0x2(实际长度只有两个字节),但是Capric卡需要使用两个存储器写请求TLP,分别向0xFFFF-0FFF~0xFFFF-00-0FFF和0xFFFF-1000~0xFFFF-1000这两段数据进行写操作。

由此可以发现,当Capric卡对A~B这段数据区域[87]进行DMA写时,首先需要判断这段区域是否跨越4 KB边界[88]。如果跨越则需要向A~Tail4096(A)和Head4096(B)~B这两段数据区域进行写操作,这两段数据区域一定都小于0x20,因此采用上文描述的方法组织TLP报文即可。

3.M大于0x20

如果M大于0x20,此时Capric卡进行一次DMA写操作时,LogiCORE需要向RC发送多个存储器写请求TLP。我们假设Capric卡需要向[A31A30...A1A0~B31B30...B1B0]这段数据区域进行DMA写操作,而且这段数据区域的M大于0x20。此时DMA写逻辑需要进行拆包操作。这个拆包操作需要遵循以下原则。

(1)TLP传递的数据区域不能跨越4KB边界。

为此Capric卡首先需要分析A~B这段是否跨越4KB边界。值得注意的是,在Capric卡中,一次DMA写的长度小于2048,因此其传递的数据区域至多会跨越一个4KB边界。此时需要向A~Tail4096(A)和Head4096(B)~B这两段数据区域进行写操作,而且这两段数据区域的M都可能大于0x20。下文采用的拆包方法可以保证在不进行4KB边界检查的情况下,保证拆分后的TLP不会跨越4KB边界。

(2)尽量减少拆分后TLP的总个数。

比如,可以将0x1000~10FF这段数据区域拆分为0x1000~107F和0x1080~0x10FF,尽量利用Max_Payload_Size参数,而不使用更多的TLP进行数据传递。

(3)拆分后的TLP尽量不跨越Cache行边界。虽然PCIe总线规范并没有规定拆分TLP的方法。但是将0x1000~10FF这段数据区域拆分为0x1000~0x107E,0x107F~0x108F和0x1090~0x10FF,从原理上讲是可行的,可是并不合理。

在Capric卡中,为了简化设计,当M大于0x20时将采用以下规则进行拆包处理。

●第一个TLP的起始地址必须为0xA31A30...A2,而其他TLP的起始地址必须为0x80字节对界。

●最后一个TLP的结束地址必须为0xB31B30...B2,而其他TLP的结束地址必须为0x80字节对界。

根据以上规则,我们可以将A31A30...A1A0~B31B30...B1B0这段数据区域划分为多个数据区域,其中每一个区域的Length字段不超过0x20,而且每段数据区域以128B对界。

A31A30...A1A0~Tail128(A)

Head128(A+128)~Tail128(A+128)

Head128(A+n×128)~Tail128(A+n×128)

Head128(B)~B31B30...B1B0

以上这些数据区域的M都小于或等于0x20,而且都不会跨越128B边界,因此也不可能跨越4KB边界。向这些数据区域传送数据时,TLP各字段的设置参见M小于或等于0x20的情况。当Capric卡将这些存储器写请求TLP发送完毕后,可以向处理器提交中断请求。