在PCIe总线中,有些TLP含有Data Payload,如存储器写请求、存储器读完成TLP等。在PCIe总线中,TLP含有的Data Payload大小与Max_Payload_Size、Max_Read_Request_Size和RCB参数相关。下文将分别介绍这些参数的使用。

5.4.1 Max_Payload_Size参数

PCIe总线规定在TLP报文中,数据有效负载的最大值为4KB,但是PCIe设备并不一定能够发送这么大的数据报文。PCIe设备含有“Max_Payload_Size”和“Max_Payload_Size Supported”参数,这两个参数分别在Device Capability寄存器和Device Control寄存器中定义。

“Max_Payload_Size Supported”参数存放在一个PCIe设备中,TLP有效负载的最大值,该参数由PCIe设备的硬件逻辑确定,系统软件不能改写该参数。而Max_Payload_Size参数存放PCIe设备实际使用的,TLP有效负载的最大值。该参数由PCIe链路两端的设备协商决定,是PCIe设备进行数据传送时,实际使用的参数。

PCIe设备发送数据报文时,使用Max_Payload_Size参数决定TLP的最大有效负载。当PCIe设备的所传送的数据大小超过Max_Payload_Size参数时,这段数据将被分割为多个TLP进行发送。当PCIe设备接收TLP时,该TLP的最大有效负载也不能超过Max_Payload_Size参数,如果接收的TLP,其Length字段超过Max_Payload_Size参数,该PCIe设备将认为该TLP非法。

RC或者EP在发送存储器读完成TLP时,这个存储器读完成TLP的最大Payload也不能超过Max_Payload_Size参数,如果超过该参数,PCIe设备需要发送多个读完成报文。值得注意的是,这些读完成报文需要满足RCB参数的要求,有关RCB参数的详细说明见下文。

在实际应用中,尽管有些PCIe设备的Max_Payload_Size Supported参数可以为256B、512B、1024B或者更高,但是如果PCIe链路的对端设备可以支持的Max_Payload_Size参数为128B时,系统软件将使用对端设备的Max_Payload_Size Supported参数,初始化该设备的Max_Payload_Size参数,即选用PCIe链路两端最小的Max_Payload_Size Supported参数初始化Max_Payload_Size参数。

在多数x86处理器系统的MCH或者ICH中,Max_Payload_Size Supported参数为128B。这也意味着在x86处理器中,与MCH或者ICH直接相连的PCIe设备进行DMA读写时,数据的有效负载不能超过128B。而在PowerPC处理器系统中,该参数大多为256B。

目前在大多数EP中,Max_Payload_Size Supported参数不大于512B,因为在大多数处理器系统的RC中,Max_Payload_Size Supported参数也不大于512B。因此即便EP支持较大的Max_Payload_Size Supported参数,并不会提高数据传送效率。

而Max_Payload_Size参数的大小与PCIe链路的传送效率成正比,该参数越大,PCIe链路带宽的利用率越高,该参数越小,PCIe链路带宽的利用率越低。

PCIe总线规范规定,对于实时性要求较高的PCIe设备,Max_Payload_Size参数不应设置过大,因此这个参数有时会低于PCIe链路允许使用的最大值。

5.4.2 Max_Read_Request_Size参数

Max_Read_Request_Size参数由PCIe设备决定,该参数规定了PCIe设备一次能从目标设备读取多少数据。

Max_Read_Request_Size参数在Device Control寄存器中定义。该参数与存储器读请求TLP的Length字段相关,其中Length字段不能大于Max_Read_Request_Size参数。在存储器读请求TLP中,Length字段表示需要从目标设备读取多少数据。

值得注意的是,Max_Read_Request_Size参数与Max_Payload_Size参数间没有直接联系,Max_Payload_Size参数仅与存储器写请求和存储器读完成报文相关。

PCIe总线规定存储器读请求,其读取的数据长度不能超过Max_Read_Request_Size参数,即存储器读TLP中的Length字段不能大于这个参数。如果一次存储器读操作需要读取的数据范围大于Max_Read_Request_Size参数时,该PCIe设备需要向目标设备发送多个存储器读请求TLP。

PCIe总线规定Max_Read_Request_Size参数的最大值为4KB,但是系统软件需要根据硬件特性决定该参数的值。因为PCIe总线规定EP在进行存储器读请求时,需要具有足够大的缓冲接收来自目标设备的数据。

如果一个EP的Max_Read_Request_Size参数被设置为4KB,而且这个EP每发出一个4KB大小存储器读请求时,EP都需要准备一个4KB大小的缓冲[1]。这对于绝大多数EP,这都是一个相当苛刻的条件。为此在实际设计中,一个EP会对Max_Read_Request_Size参数的大小进行限制。

5.4.3 RCB参数

RCB位在Link Control寄存器中定义。RCB位决定了RCB参数的值,在PCIe总线中,RCB参数的大小为64B或者128B,如果一个PCIe设备没有设置RCB的大小[2],则RC的RCB参数缺省值为64B,而其他PCIe设备的RCB参数的缺省值为128B。PCIe总线规定RC的RCB参数的值为64B或者128B,其他PCIe设备的RCB参数为128B。

在PCIe总线中,一个存储器读请求TLP可能收到目标设备发出的多个完成报文后,才能完成一次存储器读操作。因为在PCIe总线中,一个存储器读请求最多可以请求4KB大小的数据报文,而目标设备可能会使用多个存储器读完成TLP才能将数据传递完毕。

当一个EP向RC或者其他EP读取数据时,这个EP首先向RC或者其他EP发送存储器读请求TLP;之后由RC或者其他EP发送存储器读完成TLP,将数据传递给这个EP。

如果存储器读完成报文所传递数据的地址范围没有跨越RCB参数的边界,那么数据发送端只能使用一个存储器完成报文将数据传递给请求方,否则可以使用多个存储器读完成TLP。

假定一个EP向地址范围为0xFFFF-0000~0xFFFF-0010这段区域进行DMA读操作,RC收到这个存储器读请求TLP后,将组织存储器读完成TLP,由于这段区域并没有跨越RCB边界,因此RC只能使用一个存储器读完成TLP完成数据传递。

如果存储器读完成报文所传递数据的地址范围跨越了RCB边界,那么数据发送端(目标设备)可以使用一个或者多个完成报文进行数据传递。数据发送端使用多个存储器读完成报文完成数据传递时,需要遵循以下原则。

  • 第一个完成报文所传送的数据,其起始地址与要求的起始地址相同。其结束地址或者为要求的结束地址(使用一个完成报文传递所有数据),或者为RCB参数的整数倍(使用多个完成报文传递数据)。
  • 最后一个完成报文的起始地址或者为要求的起始地址(使用一个完成报文传递所有数据),或者为RCB参数的整数倍(使用多个完成报文传递数据)。其结束地址必须为要求的结束地址。
  • 中间的完成报文的起始地址和结束地址必须为RCB参数的整数倍。

当RC或者EP需要使用多个存储器读完成报文将0xFFFE-FFF0~0xFFFF-00C7之间的数据发送给数据请求方时,可以将这些完成报文按照表5?9方式组织。

5?9 存储器读完成报文的拆分方法

方式1

方式2

方式3

0xFFFE-FFF0~0xFFFE-FFFF

0xFFFE-FFF0~0xFFFE-FFFF

0xFFFE-FFF0~0xFFFE-FFFF

0xFFFF-0000~0xFFFF-003F

0xFFFF-0000~0xFFFF-007F

0xFFFF-0000~0xFFFF-00C7

0xFFFF-0040~0xFFFF-007F

0xFFFF-0080~0xFFFF-00C7

0xFFFF-0080~0xFFFF-00BF

0xFFFF-00C0~0xFFFF-00C7

上表提供的方式仅供参考,目标设备还可以使用其他拆分方法发送存储器读完成TLP。PCIe总线使用多个完成报文实现一次数据读请求的主要原因是考虑Cache行长度和流量控制。在多数x86处理器系统中,存储器读完成报文的数据长度为一个Cache行,即一次传送64B。除此之外,较短的数据完成报文占用流量控制的资源较少,而且可以有效避免数据拥塞。

5.5 小结

本章重点介绍PCIe总线的事务层。在PCIe总线层次结构中,事务层最易理解,同时也与系统软件直接相关。




[1] 这是流量控制Infinite FC Unit的要求,详见第9.3.2节。

[2] 有些PCIe设备可能没有Link Control寄存器。

5.4 TLP中与数据负载相关的参数的更多相关文章

  1. 在MyBatis中查询数据、涉及多参数的数据访问操作、插入数据时获取数据自增长的id、关联表查询操作、动态SQL、关于配置MyBatis映射没有代码提示的解决方案

    1. 单元测试 在单元测试中,每个测试方法都需要执行相同的前置代码和后置代码,则可以自定义2个方法,分别在这2个方法中执行前置代码和后置代码,并为这2个方法添加@Before和@After注解,然后, ...

  2. 论Scrapy中的数据持久化

    引入 Scrapy的数据持久化,主要包括存储到数据库.文件以及内置数据存储. 那我们今天就来讲讲如何把Scrapy中的数据存储到数据库和文件当中. 终端指令存储 保证爬虫文件的parse方法中有可迭代 ...

  3. 以使用QSqlQuery向数据库中插入数据为例,做一个小结

    背景: 最近在使用Qt+SQLite写一个本地数据库管理程序(使用者不懂SQL),在写向数据库中插入数据的 相关的函数时,我遇到了几个问题(暂时就这些): 1.向指定字段插入指定数据时,读取到的数据都 ...

  4. SQLyog中创建数据表及相关查询方法

    USE du; /*1.创建账务表 id name mony*/ CREATE TABLE zhangwu(id INT PRIMARY KEY AUTO_INCREMENT, sname VARCH ...

  5. sqlserver中的数据导到mysql相关

    一.在sqlserver中生成数据表脚本,粘贴到记事本中,如下语法要进行替换 1.int IDENTITY (1, 1) NOT NULL——>id int unsigned NOT NULL ...

  6. 『现学现忘』Docker基础 — 30、Docker中数据卷相关命令

    目录 1.Volume命令说明 2.Volume命令的使用 (1)创建数据卷 (2)查看本地数据卷列表 (3)打印myVolume数据卷的详细信息 (4)删除数据卷 (5)删除所有未使用的数据卷 3. ...

  7. 查看linux中swap内存的相关参数

    内容主要来源于:linux的内存回收和交换 各项命令查看的linux环境是:Linux SUSE-33 2.6.32.12-0.7-defaul zone? 内存管理的相关逻辑都是以zone为单位的, ...

  8. 一步一步在Windows中使用MyCat负载均衡 上篇

    传统关系型数据库的分布式开发通常需要自己做,不仅耗时耗力而且效果不是很理想,当想快速搭建时,最初想到的是看有没有第三方,网上牛人还是很多的,做得比较好的其中之一Mycat,它是开源的分布式数据库系统, ...

  9. 一步一步在Windows中使用MyCat负载均衡 下篇

    之前在 一步一步在Windows中使用MyCat负载均衡 上篇 中已经讲了如何配置出MyCat.下面讲其相关的使用. 五.配置MyCat-eye 对于MyCat监控官网还提供一个MyCat-eye w ...

随机推荐

  1. nagios的安装

    Nagios通常由一个主程序(Nagios).一个插件程序(Nagios-plugins)和四个可选的ADDON(NRPE.NSCA. NSClient++和NDOUtils)组成.Nagios的监控 ...

  2. js中的深拷贝与浅拷贝

    对象的深拷贝于浅拷贝 对于基本类型,浅拷贝过程就是对值的复制,这个过程会开辟出一个新的内存空间,将值复制到新的内存空间.而对于引用类型来书,浅拷贝过程就是对指针的复制,这个过程并没有开辟新的堆内存空间 ...

  3. redis通过pipeline提升吞吐量

    案例目标 简单介绍 redis pipeline 的机制,结合一段实例说明pipeline 在提升吞吐量方面发生的效用. 案例背景 应用系统在数据推送或事件处理过程中,往往出现数据流经过多个网元: 然 ...

  4. 二维数组int[3][2]在内存中的分布方式

  5. 面向对象编程之super内置函数的用法

    先来看一段代码: 定义一个名叫People的父类,又定义了一个叫Teacher的老师类和一个叫Student的学生类 来继承People的类,并根据这两个子类实例化出两个对象s1和t1. class ...

  6. 前端开发-DOM

    文档对象模型(Document Object Model,DOM)是一种用于HTML和XML文档的编程接口.它给文档提供了一种结构化的表示方法,可以改变文档的内容和呈现方式.我们最为关心的是,DOM把 ...

  7. 禁掉或启用firefox 的 javascript 脚本

    老版本的firefox可以直接在“选项”页设置启用或禁用javascript 脚本 新版的Firefox中,我找了半天,没有找到,看来是没法直接设置了 于是在 地址栏键入 about:config 搜 ...

  8. 洛谷 [P1024]一元三次方程求解

    一道水题然而坑点很多. #include <iostream> #include <cstdio> #include <algorithm> #include &l ...

  9. main函数的实现解析

    main函数的传参的实现,其实也是一个解析字符串的过程:将每个word后一个空格改为“/0”,将单词提取出来. 就是这么简单. 废话不多说,直接上代码: #include<stdio.h> ...

  10. Hive metastore整体代码分析及详解

    从上一篇对Hive metastore表结构的简要分析中,我再根据数据设计的实体对象,再进行整个代码结构的总结.那么我们先打开metadata的目录,其目录结构: 可以看到,整个hivemeta的目录 ...