PCI、PCIe 一篇搞定

43 篇文章 44 订阅
42 篇文章 6 订阅

文章目录

缩略词

缩写全拼解释
ISAIndustry Standard Architecture工业标准结构
PCIPeripheral Component Interconnect外围器件互联
PCIePCI Express
PCI-SIGPCI 特殊兴趣组织

历史

PCIe 是继 ISA 和 PCI 总线之后的第三代 I/O 总线,最开始被称为 3GIO,由 Intel 在 2001 年提出,2002 年 PCI-SIG 审核后公布了第一版规范,并更名为 PCI Express。
第一代总线一般指 ISA、EISA、VESA 和 Micro Platforms,第二代总线一般指 PCI、AGP 和 PCI-X。
由于 PCIe 是从 PCI/PCI-X 继承发展而来,PCIe 在软件上几乎是全完兼容 PCI/PCI-X 的。在硬件层面上,可以借助 PCIe to PCI/PCI-X 桥来与其完成对接。
在这里插入图片描述

—— PCIe扫盲——PCIe简介
—— 《PCI Express 体系结构解读》
—— 深入PCI与PCIe之一:硬件篇

PCI

PCI 标准的特点

  1. 它是并行总线
    在一个时钟周期内 32 bit 同时被传输,引脚定义如下
    在这里插入图片描述
    在一个时钟周期内,按照协议,传输一次地址或一次数据。
  2. PCI 空间与处理器空间隔离
    PCI 设备具有独立的地址空间,即 PCI 总线地址空间,该空间与存储器地址空间通过 Host Bridge 隔离。
    处理器需要通过 HOST 主桥才能访问 PCI 设备,PCI 设备需要通过 HOST 主桥才能访问内存。
    换句话说,处理器访问 PCI 设备时,必须通过 HOST 主桥进行地址转换,PCI 设备访问内存时,也需要通过 HOST 主桥进行地址转换。HOST 主桥的一个重要作用就是将处理器访问的内存地址转换为 PCI 总线地址。
  3. 共享总线机制
    PCI 设备通过仲裁获得 PCI 总线的使用权后,才能进行数据传送。在 PCI 总线上进行数据传送,并不需要处理器进行干预。
  4. 扩展性强
    PCI 总线具有很强的扩展性,在 PCI 总线中,Root Bridge 可以直接连出一条 PCI 总线,这条总线也是该 Root Bridge 所管理的第一条 PCI 总线,该总线还可以通过 PCI 桥扩展出一系列 PCI 总线,并以 Root Bridge 为根节点,形成一颗 PCI 总线树。在同一条 PCI 总线上的设备间可以直接通信,并不会影响其它 PCI 总线上设备间的数据通信。隶属于同一颗 PCI 总线树上的 PCI 设备也可以直接通信,但需要通过 PCI 桥进行数据转发。

从 PCI 到 PCIe

PCI 后期越来越不能适应高速发展的数据传输需求,PCI-X 和 AGP 走了两条不同的路,PCI-X 不断提高时钟频率,AGP 通过在一个时钟周期内传输两次数据来提速(时钟上下沿进行数据传输,类似 DDR)。
随着频率的提高,PCI 并行传输干扰异常严重,甚至成为不可跨越的坎。
从 PCI 到 PCIe 最大的改变是由并行改为了串行,通过差分信号传输
在这里插入图片描述
相同内容通过一正一反镜像传输,干扰可以很快被发现和纠正,从而可以将传输频率大幅提升。
加上 PCI 是半双工(地址/数据线太多,不得不复用),而串行可以全双工。
并且 PCIe 采用串行方式后,布线简单,线路还可以加长,甚至变成线缆连出机箱,另外多个 lane 还可以整合成为更高带宽的线路。
速度对比:
PCI 传输: 33MHz x 4B = 133MB/s
PCIe 1.0 x1: 2.5GHz x 1b = 2.5Gb/s = 2500Mb/s = 250MB/s (知道为什么不是 2500M / 8 = 312.5MB 吗?)

PCIe 和 PCI 差异

  1. PCI 是总线结构,PCIe 是点对点结构。一个典型的 PCIe 系统框图如下
    在这里插入图片描述
    一个典型的结构是一个 root port 和一个 endpoint 直接组成一个点对点连接对,而 Switch 可以同时连接几个 endpoint。
    一个 root port 和一个 endpoint 对就需要一个单独的 PCI bus。
    而 PCI 是在同一个总线上的设备共享同一个 bus number。
    过去主板上的 PCI 插槽都公用一个 PCI bus,而现在的 PCIe 插槽却连在芯片组不同的 root port 上。
  2. PCIe 的连接是由不同的 lane 来连接的
    这些 lane 可以合在一起提供更高的带宽。譬如两个 l lane 可以合成 2 lane 的连接,写作 x2,两个 x2 可以变成 x4。
  3. PCI 配置空间从 256B 扩展为 4k,同时提供了 PCIe memory map 访问方式。

PCIe

PCIe 1.0 和 2.0 采用 8b/10b 编码方式,这意味着一个字节(8bit)需要用(10bit)传输,这就是为什么 2.5GHz 时钟,每时钟 1b 数据。结果不是 312.5MB/s 而是 250MB/s。
PCIe 3.0 和 4.0 采用 128b/130b 编码,减少了浪费(overhead),所以才能在 8GHz 时钟下带宽达到 1GB/s(而不是 800MHB/s)。
在这里插入图片描述

PCI 细节

PCI 总线作为处理器系统的局部总线,其主要目的是为了连接外部设备,而不是作为处理器的系统总线连接 Cache 和 内存。
PCI 总线作为系统总线的延伸,其设计考虑了许多与处理器相关的内存,如处理器的 Cache 一致性。
在这里插入图片描述
图中与 PCI 总线相关的模块包括:HOST 主桥、PCI 总线、PCI 桥、PCI 设备。
PCI 总线由 HOST 主桥和 PCI 桥推出,HOST 主桥与内存控制器在同一级总线上,因此 PCI 设备可以方便地通过 HOST 主桥访问内存,即进行 DMA 操作。
PCI 设备的 DMA 操作需要与 Cache 进行一致性操作,当 PCI 设备通过 HOST 主桥访问内存时,Cache 一致性模块将进行地址监听,并根据监听的结果改变 Cache 的状态。

HOST 主桥

HOST 主桥是一个很特别的桥片,用来隔离存储器域和 PCI 总线域,管理 PCI 总线域,并完成处理器与 PCI 设备间的数据交换。处理器与 PCI 设备间的数据交换主要由“处理器访问 PCI 设备的地址空间”和“PCI设备使用 DMA 访问内存”这两部分组成。
每一颗 HOST 主桥都管理一颗 PCI 总线树,在同一颗 PCI 总线树上的所有 PCI 设备属于同一个 PCI 总线域。
在这颗总线树上的所有 PCI 设备的配置空间都由 HOST 主桥通过配置读写总线周期访问。
如果 HOST 主桥支持 PCI V3.0 规范的 Peer-to-Perr 数据传送方式,那么分属不同 PCI 总线域的 PCI 设备可以直接进行数据交换(PCIe 只有在同一颗树下的才行)。

PCI 总线

一个 HOST 主桥管理一颗 PCI 总树,一颗 PCI 总树可能包含多个 PCI 总线。
PCI 总线由 HOST 主桥和 PCI 桥管理。

PCI 设备

在 PCI 总线中有三类设备:PCI 主设备、PCI 从设备、桥设备。
(HOST 主桥并不是 PCI 设备(这也是为什么 lspci 命令并不会列出 HOST 主桥设备的原因?)。PCI 规范也没有规定如何设计 HOST 主桥。)
其中 PCI 从设备只能被动地接收来自 HOST 主桥或其它 PCI 设备的读写请求;
PCI 主设备可以通过总线仲裁获得 PCI 总线的使用权,主动地向其它 PCI 设备或者内存发起读写请求。
桥设备的主要作用是管理下游的 PCI 总线,并转发上下游总线之间的总线事务。它包括 PCI 桥、PCI-to-ISA 桥,PCI 桥的存在使 PCI 总线极具扩展性,处理器系统可以使用 PCI 桥进一步扩展 PCI 总线。PCI 桥可以连接两条 PCI 总线,上游 PCI 总线和下游 PCI 总线,这两个总线属于同一个 PCI 总线域,使用 PCI 桥扩展的所有 PCI 总线都属于同一个 PCI 总线域。
其中对 PCI 设备配置空间的访问可以从上游总线转发到下游总线,而数据传送可以双方向进行。
一个 PCI 设备可以既是主设备也是从设备,但在同一时刻,这个 PCI 设备要么是主设备要么是从设备。PCI 总线规范将 PCI 主从设备统称为 PCI Agent 设备。常见的 PCI 网卡、显卡、声卡等设备都是 PCI Agent 设备。

HOST 处理器

PCI 总线规定在同一时刻内,在一颗 PCI 总线树上有且只有一个 HOST 处理器。这个 HOST 处理器可以通过 HOST 主桥,发起 PCI 总线的配置请求总线事务,并对 PCI 总线上的设备和桥片进行配置。
在 PCI 总线中,HOST 处理器是一个较为模糊的概念。在 SMP 处理器系统中,所有 CPU 都可以通过 HOST 主桥访问其下的 PCI 总线树,这些 CPU 都可以作为 HOST 处理器。但是值得注意的是,PCI 总线树的实际管理者是 HOST 主桥,而不是 HOST 处理器。

PCI 总线的负载

PCI 总线能挂接的负载与总线频率相关,总线频率越高,能挂载的负载越少。
在这里插入图片描述

PCI 总线的信号定义

PCI 总线是一条共享总线,在一条 PCI 总线上可以挂接多个 PCI 设备。这些设备通过一系列信号与 PCI 总线相连,这些信号包括:地址/数据信号、控制信号、仲裁信号、中断信号等。
PCI 总线是一个同步总线,每一个设备都具有一个 CLK 信号,其发送设备与接收设备使用这个 CLK 信号进行同步数据传递。PCI 总线可以使用 33MHz 或者 66MHz 的时钟频率,而 PCI-X 总线可以使用 133MHz、266MHz或者533MHz的时钟频率。
除了 RST#、INTA~D#、PME#和 CLKRUN#等信号之外,PCI 设备使用的绝大多数信号都使用这个 CLK 信号进行同步。其中 RST# 是复位信号,而 PCI 设备使用 INTA~D#信号进行中断请求。

地址和数据信号

在 PCI 总线中,与地址和数据相关的信号如下
(1)AD[31:0]信号
  PCI 总线复用地址与数据信号。PCI 总线事务在启动后的第一个时钟周期传送地址,这个地址是 PCI 总线域的存储器地址或者 I/O 地址;而在下一个时钟周期传送数据。传送地址的时钟周期也被称为地址周期,传送数据的时钟周期也被称为数据周期。PCI 总线支持突发传送,即在一个地址周期之后,可以紧跟多个数据周期(类似于 I2C 的连续读和连续写)。
(2)PAR信号
  PCI 总线使用奇偶校验机制,保证地址和数据信号在进行数据传递时的正确性。PAR 信号是 AD[31:0] 和 C/BE[3:0] 的奇偶校验信号。
(3)C/BE[3:0]#信号
  PCI 总线复用命令与字节选通引脚。在地址周期中,C/BE[3:0]# 信号表示 PCI 总线的命令。而在数据周期中,C/BE[3:0]# 引脚输出字节选通信号,其中 C/BE3、C/BE2、C/BE1、C/BE0 与数据的字节 3、2、1、0 对应,使用这组信号可以对 PCI 设备进行单个字节、字和双字访问。
以下给出常用的总线事务类型
在这里插入图片描述
在这里插入图片描述

接口控制信号

在 PCI 总线中,接口控制信号的主要作用是保证数据的正常传递,并根据 PCI 主从设备的状态,暂停、终止或者正常完成当前总线事务。其主要信号如下
(1)FRAME# 信号
  该信号指示一个 PCI 总线事务的开始与结束。当 PCI 设备获得总线的使用权后,将置该信号有效,即置为低,启动 PCI 总线事务,当结束总线事务时,将置该信号无效,即置为高。PCI 设备(和 HOST 主桥)只有通过仲裁获得当前 PCI 总线的使用权后,才能驱动该信号。
(2)IRDY# 信号
  该信号由 PCI 主设备(和 HOST 主桥)驱动,该信号有效时表示 PCI 主设备的数据已经准备完毕。如果当前 PCI 总线事务为写事务,表示数据已经在 AD[31:0] 上有效;如果为读事务,表示 PCI 目标(接收)设备已经准备好接收缓冲,目标(发送)设备可以将数据发送到 AD[31:0] 上。
(3)TRDY# 信号
  该信号由目标设备驱动,该信号有效时表示目标设备已经将数据准备完毕。如果当前 PCI 总线事务为写事务,表示目标设备已经准备好接收缓冲,可以将 AD[31:0] 上的数据写入目标设备;如果为读事务,表示 PCI 设备需要的数据已经在 AD[31:0] 上有效。
  该信号可以和 IRD# 信号联合使用,在 PCI 总线事务上插入等待周期,对 PCI 总线的数据进行控制。
(4)STOP# 信号
  该信号有效时表示目标设备请求主设备停止当前 PCI 总线事务。一个 PCI 总线事务除了可以正常结束外,目标设备还可以使用该信号终止当前 PCI 总线事务。
(5)IDSEL 信号
  PCI 总线在进行配置读写总线事务时,使用该信号选择 PCI 目标设备。
IDSEL 信号与 PCI 设备的设备号相关,相当于 PCI 设备配置空间的片选信号。
(6)DEVSEL# 信号
  该信号有效时表示 PCI 总线的目标设备准备好,该信号与 TRDY# 信号的不同之处在于该信号有效仅表示目标设备已经完成了地址译码。目标设备使用该信号通知 PCI 主设备,其访问对象在当前 PCI 总线上,但是并不表示目标设备可以与主设备进行数据交换。
PCI 总线规范根据设备的译码速度,将 PCI 设备分为快速、中速、慢速三种。

仲裁信号

在这里插入图片描述
在一颗 PCI 总线树中,每一条 PCI 总线上都有一个总线仲裁器。一个处理器体系可以使用 PCI 桥扩展出一条新的 PCI 总线,这条新的 PCI 总线也需要一个总线仲裁器,通常在 PCI 桥中集成了这个总线仲裁器。多数 HOST 主桥也集成了一个 PCI 总线仲裁器。
PCI 主设备使用 PCI 总线进行数据传递时,需要首先置 REQ# 信号有效,向 PCI 总线仲裁器发出总线申请,当 PCI 总线仲裁器允许 PCI 主设备获得 PCI 总线的使用权后,将置 GNT# 信号为有效,并将其发送给指定的 PCI 主设备。而 PCI 主设备在获得总线使用权后,可以置 FRAME# 信号有效,与 PCI 从设备进行数据通信。

中断请求信号

PCI 总线提供了 INTA#、INTB#、INTC#、INTD# 四个中断请求信号,PCI 设备借助这些中断请求信号,使用电平触发方式向处理器提交中断请求。当这些中断请求信号为低时,PCI 设备将向处理器提交中断请求;当处理器执行中断服务程序清除 PCI 设备的中断请求后,PCI 设备将该信号置高,结束当前终端请求。
INTx 这组信号为开漏输出,当所有的驱动源不驱动该信号时,该信号由上拉电阻驱动为高。
PCI 总线规定单功能设备只能使用 INTA# 信号,而多功能设备才能使用 INTB#/C#/D# 信号。PCI 设备的这些中断请求信号可以通过某种规则进行线与,之后与中断控制器的中断请求信号线相连。而处理器系统需要预先知道这个规则,以便正确处理来自不同 PCI 设备的中断请求。这个规则也被称为中断路由表。

PCI 总线的存储器读写总线事务

总线的基本任务时实现数据传送,将一组数据从一个设备传送到另一个设备,当然总线也可以将一个设备的数据广播到多个设备。在处理器系统中,这些数据传送都要依赖一定的规则,PCI 总线也不例外。
PCI 总线使用单端并行数据线,采用地址译码方式进行数据传递,而采用 ID 译码方式进行配置信息的传递。其中地址译码方式使用地址信号,而 ID 译码方式使用 PCI 设备的 ID 号,包括 Bus Number、Device Number、Function Number 和 Register Number。
PCI 设备只有在系统软件初始化配置空间之后,才能够被其它主设备访问。
当 PCI 设备的配置空间被初始化之后,该设备在当前的 PCI 总线树上将拥有一个独立的 PCI 总线地址空间,即 BAR(Base Address Register)寄存器所描述的空间。
处理器与 PCI 设备进行数据交换,或者 PCI 设备之间进行存储器数据交换时,都将通过 PCI 总线地址完成。
PCI 设备与内存进行 DMA 操作时,使用的也是 PCI 总线域的地址,而不是存储器域的地址。此时 HOST 主桥将完成 PCI 总线地址到存储器域地址的转换。
PCI 总线支持以下几类存储器读写事务
(1)HOST 处理器对 PCI 设备的 BAR 空间进行数据读写,BAR 空间可以使用存储器或 I/O 译码方式。
(2)PCI 设备之间的数据传递。
(3)PCI 设备对主存储器进行读写,即 DMA 读写操作。DMA 读写操作在所有处理器系统中都较为常见,也是 PCI 总线数据传送的重点。在多数情况下,DMA 读写操作结束后将伴随着中断的产生。PCI 设备可以使用 INTA#、INTB#、INTC#、INTD# 信号提交中断请求,也可以使用 MSI 机制提交中断请求。

PCI 总线事务的时序

一个 PCI 总线事务的访问时序如下图所示,与 PCI 总线事务相关的控制信号有 FRAME#、IRDY#、TRDY#、DEVSEL# 等信号。
在这里插入图片描述
当一个 PCI 主设备需要使用 PCI 总线时,首先需要发送 REQ# 信号,通过总线仲裁获得总线使用权,即 GNT# 信号有效后,使用以下步骤完成一个完整 PCI 总线事务,对目标设备进行存储器或者 I/O 地址空间的读写访问。
(1)当 PCI 主设备获得总线使用权之后,将在 CLK1 的上升沿置 FRAME# 信号有效,启动 PCI 总线事务。当 PCI 总线事务结束后,FRAME# 信号将被置为无效。
(2)PCI 总线周期的第一个时钟周期(CLK1 的上升沿到 CLK2 的上升沿之间)为地址周期。在地址周期中,PCI 主设备将访问的目的设备的地址和总线命令分别驱动到 AD[31:0] 和 C/BE[3:0] 信号上。如果当前总线命令是配置读写,那么 IDSEL 信号线被置为有效,IDSEL 信号与 PCI 总线的 AD[31:11] 相连
(3)当 IRDY#、TRDY# 和 DEVSEL# 信号都有效后,总线事务将使用数据周期进行数据传递。当 IRDY# 和 TRDY# 信号没有同时有效时,PCI 总线不能进行数据传递,PCI 总线使用这两个信号进行传送控制。
(4)PCI 总线支持突发周期,因此在地址周期之后可以有多个数据周期,可以传送多组数据。而目标设备并不知道突发周期的长度,如果目标设备不能继续接收数据时,可以 disconnect(断连)当前总线事务。

Posted 和 Non-Posted 传送方式

PCI 总线规定了两类数据传送方式,Posted 和 Non-Posted。
Posted 方式指 PCI 主设备向 PCI 目标设备进行数据传递时,当数据到达 PCI 桥后,即由 PCI 桥接管来自上游总线的事务,并将其转发到下游总线。好处是,在数据还没有到达最终的目的地之前,PCI 总线就可以结束当前总线事务,从而在一定程度上解决了 PCI 总线的拥塞问题。
Non-Posted 方式是指 PCI 主设备向 PCI 目标设备进行数据传递时,数据必须到达最终目的地之后,才能结束当前总线事务。缺点是,PCI 总线在没有结束当前事务时必须等待。
PCI 总线规定只有存储器写请求可以采用 Posted 方式,而存储器读请求、I/O 读写请求、配置读写请求只能采用 Non-Posted 方式。
下面以上面结构框图中的 PCI 设备 11 向存储器进行 DMA 写操作为例,说明 Posted 方式实现过程。

  1. PCI 设备 11 进行 DMA 写操作时使用存储器写总线事务,当 PCI 设备 11 获得 PCI 总线 x1 的使用权后,将发送存储器写总线事务到 PCI 总线 x1 上。
  2. 当 PCI 桥 1 发现这个总线事务的地址不在该桥管理的地址范围内,将首先接收这个总线事务,并结束 PCI 总线 x1 的总线事务。
  3. 此时 PCI 总线 x1 使用的资源已经被释放,PCI 设备 11 和 PCI 设备 12 可以使用 PCI 总线 x1 进行通信。
  4. PCI 桥 1 获得 PCI 总线 x0 的使用权后,将转发这个存储器写总线事务到 PCI 总线 x0 上
  5. 之后,HOST 主桥 x 将接收这个存储器写总线事务,并最终将数据写入主存储器。
HOST 处理器访问 PCI 设备

HOST 处理器对 PCI 设备的数据访问主要包括两方面

  • 处理器向 PCI 设备发起存储器和 I/O 读写请求。(内存空间、I/O 空间)
  • 处理器对 PCI 设备进行配置读写。(配置空间)

在 PCI 设备的配置空间中,共有 6 个 BAR 寄存器,每一个 BAR 寄存器都与 PCI 设备使用的一组 PCI 总线地址空间对应,BAR 寄存器记录这组地址空间的基地址。将与 BAR 寄存器对应的 PCI 总线地址空间称为 BAR 空间,在 BAR 空间中可以存放 I/O 地址空间,也可以存放存储器(内存)地址空间。注意,在 BAR 寄存器中存放地是 PCI 设备使用的“PCI 总线域”的物理地址,而不是“存储器域”的物理地址。
HOST 处理器访问 PCI 设备 I/O 地址空间的过程,与访问存储器地址空间略有不同。
访问 I/O 地址空间:
有些处理器,如 x86 处理器,具有独立的 I/O 地址空间,x86 处理器可以将 PCI 设备使用的 I/O 地址映射到存储器域的 I/O 地址空间中,之后处理器可以使用 IN、OUT 等指令对存储器域的 I/O 地址进行访问,HOST 主桥会将存储器域的 I/O 地址转换为 PCI 总线域的 I/O 地址,最后使用 PCI 总线的 I/O 总线事务对 PCI 设备的 I/O 地址进行读写访问。在 x86 处理器中,存储器域的 I/O 地址与 PCI 总线域的 I/O 地址相同。
对于没有独立 I/O 地址空间的处理器,如 PowerPC 处理器,需要在 HOST 主桥初始化时,将 PCI 设备使用的 I/O 地址空间映射为处理器的存储器地址空间。PowerPC 处理器对这段“处理器域”的存储器空间进行读写访问时,HOST 主桥会将存储器域的存储器地址转换为 PCI 总线域的 I/O 地址。
访问存储器地址:
HOST 处理器在初始化时,需要将 PCI 设备使用的 BAR 空间映射到“存储器域”的存储器地址空间。
HOST 主桥将“存储器域”的读写请求翻译为 PCI 总线的存储器读写总线事务之后,再发送给目标设备。
总结:

  • HOST 主桥相当于一个网关,上面是广域网,下面是局域网
  • HOST 主桥上面是存储器域,下面是 PCI 域;上面是 CPU 的世界,下面是 PCI 的世界;上面通行使用存储器域地址(内存地址),下面通行使用 PCI 地址
  • 通信经过网关需要进行地址转换,网关有隔离和转换功能

以上面的结构框图为例说明处理器如何通过 HOST 主桥和 PCI 桥 1 对 PCI 设备 11 进行存储器读写操作。当处理器对 PCI 设备 11 进行存储器写操作时,这些数据需要通过 HOST 主桥 x 和 PCI 桥 x1,最终到达 PCI 设备 11,其访问步骤如下

  1. 首先处理器将要传递的数据放入通用寄存器中,之后向 PCI 设备 11 映射到的存储器域的地址进行写操作。
  2. HOST 主桥 x 接收来自处理器的存储器写请求,之后处理器结束当前存储器写操作,释放系统总线。
  3. HOST 主桥 x 将存储器域的存储器地址转换为 PCI 总线域的 PCI 总线地址。并向 PCI 总线 x0 发起 PCI 写请求总线事务。(注意:虽然在许多处理器系统中,存储器地址和 PCI 总线地址完全相等,但其含义完全不同。)
  4. PCI 总线 x0 上的 PCI 设备 01、PCI 设备 02 和 PCI 桥 1 将同时监听这个 PCI 写总线事务。最后 PCI 桥 x1 接收这个写总线事务,并结束来自 PCI 总线 x0 的 PCI 总线事务。
  5. PCI 桥 x1 向 PCI 总线 x1 发起新的 PCI 总线写总线事务。
  6. PCI 总线 x1 上的 PCI 设备 11 和 PCI 设备 12 同时监听这个 PCI 写总线事务。最后 PCI 设备 11 通过地址译码方式接收这个写总线事务,并结束来自 PCI 总线 x1 上的 PCI 总线事务。
PCI 设备读写主存储器

PCI 设备与存储器直接进行数据交换的过程被称为 DMA。与其它总线的 DMA 过程类似,PCI 设备进行 DMA 操作时,需要获得数据传送的目的地址和传送大小。
支持 DMA 传递的 PCI 设备可以在其 BAR 空间中设置两个寄存器,分别保存这个目标地址和传送大小。这两个寄存器也是 PCI 设备 DMA 控制器的组成部件。
PCI 设备进行 DMA 操作时,使用的目的地址是 PCI 总线域的物理地址,而不是存储器域的物理地址,因为 PCI 设备并不能识别存储器域的物理地址,而仅能识别 PCI 总线域的物理地址。HOST 主桥负责完成 PCI 总线地址到存储器域地址的转换。
许多处理器允许 PCI 设备访问所有存储器域地址空间,但有些处理器可以设置 PCI 设备所能访问的存储器域地址空间,从而对存储器域地址空间进行保护。
下面以 PCI 设备 11 向主存储器写数据为例,说明 PCI 设备如何进行 DMA 写操作

  1. PCI 设备 11 将存储器写请求发向 PCI 总线 x1,写请求使用的地址为 PCI 总线域的地址。
  2. PCI 总线 x1 上的所有设备监听这个请求,因为 PCI 设备 11 是向处理器的存储器写数据,所以 PCI 总线 x1 上的 PCI Agent 设备都不会接收这个数据请求。
  3. PCI 桥 x1 发现当前总线事务使用的 PCI 总线地址不是其下游设备使用的 PCI 总线地址,则接收这个数据请求。此时 PCI 桥 x1 将结束来自 PCI 设备 11 的 Posted 存储器写请求,并将这个数据请求推到上游 PCI 总线上,即 PCI 总线 x0 上。
  4. PCI 总线 x0 上的所有 PCI 设备包括 HOST 主桥将监听这个请求。PCI 总线 x0 上的 PCI Agent 设备也不会接收这个数据请求,此时这个数据请求将由 HOST 主桥 x 接收,并结束 PCI 桥 1 的 Posted 存储器写请求。
  5. HOST 主桥 x 发现这个数据请求是发向存储器的,则将来自 PCI 总线 x0 的 PCI 总线地址转换为存储器地址(liyongjun:应该反过来,先转换,后发现),之后通过存储器控制器将数据写入存储器,完成 PCI 设备的 DMA 写操作。

PCI 总线的中断机制

PCI 总线使用 INTA#、INTB#、INTC#、INTD# 信号向处理器发出中断请求。这些中断请求信号为低电平有效,并与处理器的中断控制器连接。在 PCI 体系结构中,这些中断信号属于边带信号(Sideband Signals),PCI 总线规范并没有明确规定在一个处理器系统中如何使用这些信号,因为这些信号对于 PCI 总线是可选信号。PCI 设备还可以使用 MSI 机制向处理器提交中断请求,而不使用这组中断信号。
在这里插入图片描述
在一个处理器系统中,多数 PCI 设备仅使用 INTA# 信号,很少使用 INTB# 和 INTC# 信号,而 INTD# 信号更是极少使用。在 PCI 设备配置空间的 Interrupt Pin 寄存器记录该设备究竟使用哪个 INTx 信号。
多数情况下,在嵌入式处理器系统中,PCI 设备仅使用 INTA# 信号进行中断请求,所以只要将这些 INTA# 信号挂接到中断控制器的独立 IRQ_PIN# 引脚上即可。这样每一个 PCI 设备都可以独占一个单独的中断引脚。

中断请求的同步

在 PCI 总线中,INTx 信号是一个异步信号。所谓异步是指 INTx 信号的传递并不与 PCI 总线的数据传送同步,即 INTx 信号的传递与 PCI 设备使用的 CLK# 信号无关。这个“异步”信号给系统软件的设计带来了一定的麻烦。
系统软件程序员需要注意“异步”这种事件,因为几乎所有“异步”事件都会带来系统的“同步”问题。
还是以上面的结构框图为例,当 PCI 设备 11 使用 DMA 方式,将一组数据写入存储器,该设备在最后一个数据离开 PCI 设备 11 的发送 FIFO 时,会认为 DMA 写操作已经完成。此时这个设备将通过 INTx 信号,通知处理器 DMA 写操作完成。
此时处理器(驱动程序的中断服务例程)需要注意,因为 INTx 信号是一个异步信号,当处理器收到 INTx 信号时,并不意味着 PCI 设备 11 已经将数据写入存储器中,因为 PCI 设备 11 的数据传递需要通过 PCI 桥 1 和 HOST 主桥,最终才能到达存储器控制器。
PCI 总线并不知道这个 INTx 信号何时被处理器处理,很有可能处理器已经接收到 INTx 信号,开始执行中断处理程序时,该 PCI 设备还没有完全将数据写入存储器。
因为“PCI 设备向处理器提交中断请求”与“将数据写入存储器”分别使用了两个不同的路径,处理器系统无法保证哪个信息率先到达。从而在处理器系统中存在“中断同步”的问题,PCI 总线提供了以下两种方法解决这个同步问题。
(1)PCI 设备保证在数据到达目的地之后,再提交中断请求。
如果 PCI 设备采用 Posted 写总线事务,PCI 设备无法单纯通过硬件逻辑判断数据什么时候写入到存储器。此时为了保证数据到达目的地后才提交中断请求,PCI 设备需要使用“读刷新”的方法保证数据已经到达目的地。具体方法是向 DMA 写的数据区域发出一个读请求。
PCI 总线规范要求 HOST 主桥和 PCI 桥必须保证这种读操作可以刷新写操作,但问题是,没有多少芯片设计者愿意提供这种机制,因为这将极大地增加他们地设计难度,并且使用这种方法也将增加中断请求地延时。
(2)中断服务例程使用“读刷新”方法
中断服务例程在使用“PCI 设备写入存储器”的这些数据之前,需要对这个 PCI 设备进行读操作。这个读操作也可以强制将数据最终写入存储器,实际上是将数据写入到存储器控制器中。
这种方法也是绝大多数处理器系统采用的方法。程序员在编写中断服务例程时,往往都是先读取 PCI 设备的中断状态寄存器,判断中断产生原因之后,才对 PCI 设备写入的数据进行操作。这个读取中断状态寄存器的过程,一方面可以获得设备的中断状态,另一方面可以保证 DMA 写的数据最终到达存储器。
这里也再次提醒系统程序员注意 PCI 总线的“异步”中断所带来的数据完整性问题。在一个操作系统中,即便中断处理程序没有首先读取 PCI 设备的寄存器,也多半不会出问题,因为在操作系统中,一个 PCI 设备从提交中断到处理器开始执行设备的中断服务例程,所需要的时间较长,处理器系统基本上可以保证此时数据已经写入。但是如果系统程序员不这样做,这个驱动程序依然有 Bug,尽管这些 Bug 因为各种机缘巧合,始终不能够暴露出来,而一旦这些 Bug 被暴露出来将难以定位。
PCI 总线 V2.2 规范还定义了一种新的中断机制,即 MSI 中断机制。MSI 中断机制采用存储器写总线事务向处理器系统提交中断请求,其实现机制是向 HOST 处理器指定的一个存储器地址写指定的数据。这个存储器地址一般是中断控制器规定的某段存储器地址范围,而且数据也是事先安排好的数据,通常含有中断向量号。
HOST 主桥会将 MSI 这个特殊的存储器写总线事务翻译为中断请求,提交给处理器。

PCI 总线的桥与配置

在 PCI 体系结构中,含有两类桥,HOST 主桥和 PCI 桥。在每一个 PCI 设备中(包括 PCI 桥)都含有一个配置空间。这个配置空间由 HOST 主桥管理,而 PCI 桥可以转发来自 HOST 主桥的配置访问。在 PCI 总线中,PCI Agent 设备使用的配置空间与 PCI 桥使用的配置空间有些差别,但这些配置空间都是由处理器通过 HOST 主桥管理的。
HOST 主桥管理 PCI 设备的配置空间。

存储器域与 PCI 总线域

在这里插入图片描述
本书中将 CPU 域和 DRAM 域统称为存储器域。存储器域包括 CPU 内部的通用寄存器、存储器映像寻址的寄存器、主存储器空间和外部设备空间。
CPU 域地址空间指 CPU 所能直接访问的地址空间集合(在本书中,CPU、处理器与处理器系统的概念不同。如 MPC8548 处理器的内核是 E500 V25,本书将这个处理器内核称为 CPU;处理器由一个或者多个 CPU、外部 Cache、中断控制器和 DRAM 控制器组成;而处理器系统由一个或者多个处理器和外部设备组成)。CPU 域仅在 CPU 内核中有效,CPU 访问主存储器时,首先将读写命令放入读写指令缓冲中,然后将这个命令发送到 DRAM 控制器或者 HOST 主桥。DRAM 控制器或者 HOST 主桥将 CPU 地址转换为 DRAM 或者 PCI 总线地址,分别进入 DRAM 域或者 PCI 总线域后,再访问相应的地址空间。
DRAM 域地址空间指 DRAM 控制器能够访问的地址空间集合。
在多数处理器系统中,DRAM 域空间是 CPU 域空间的一部分(除此之外,CPU 域还包含外部设备空间),但也有例外,比如显卡控制器可能会借用一部分主存储器空间,这些被借用的空间不能被 CPU 访问,而只能被 DRAM 控制器,更为准确地说是显卡通过 DRAM 控制器访问,因此这段空间不属于 CPU 域,严格地讲,这段空间属于外部设备域。(liyongjun:这不就是我之前研究的 CMA 嘛)
值得注意的是,存储器域的外部设备空间,在 PCI 总线域中还有一个地址映射。当处理器访问 PCI 设备时,首先访问的是这个设备在存储器域上的 PCI 设备空间,之后 HOST 主桥将这个存储器域的 PCI 总线地址转换为 PCI 总线域的物理地址。
在一个处理器系统中,CPU 能够访问的 PCI 总线地址一定在存储器域中具有地址映射;PCI 设备能够访问的存储器域地址也一定在 PCI 总线域中具有地址映射。 这个映射存在于 HOST 主桥中。
PCI 设备使用的地址空间保存在各自的 PCI 配置寄存器中,即 BAR 寄存器中。这些 PCI 总线地址空间需要在初始化时映射成为存储器域的存储器地址空间,保存在 HOST 主桥中,之后处理器才能访问这些地址空间。
在 32 位的 PCI 总线中,每一个 PCI 总线域的地址范围都是 0x00000000~0xffffffff,PCI 总线 x 域上的 PCI 总线地址 0x00000000 与 PCI 总线 y 域上的 PCI 总线地址 0x00000000 并不相同,而且这两个 PCI 总线地址经过 HOST 主桥反向映射后,得到的存储器地址也不相同。

41000000-5fffffff : MEM
  41000000-410fffff : PCI Bus 0000:01
    41000000-41007fff : 0000:01:00.0
      41000000-41007fff : 0000:01:00.0
  41100000-412fffff : PCI Bus 0000:01
    41100000-411fffff : 0000:01:00.0
      41100000-411fffff : 0000:01:00.0
    41200000-41200fff : 0000:01:00.0
      41200000-41200fff : 0000:01:00.0
61000000-7fffffff : MEM
  61000000-610fffff : PCI Bus 0001:01
    61000000-61007fff : 0001:01:00.0
      61000000-61007fff : 0001:01:00.0
  61100000-612fffff : PCI Bus 0001:01
    61100000-611fffff : 0001:01:00.0
      61100000-611fffff : 0001:01:00.0
    61200000-61200fff : 0001:01:00.0
      61200000-61200fff : 0001:01:00.0
HOST 主桥

主要以 PowerPC 处理器为例说明 HOST 主桥的实现机制,因为在 PowerPC 处理器中,HOST 主桥的实现比较完整,尤其是 PCI 总线域与存储器域的映射关系比较明晰。
在这里插入图片描述
MPC8548 处理器的 L1 Cache 在 E500 V2 内核中,而 L2 Cache 与 FSB 直接相连(MPC8548 也将 FSB 称为 CCB(Core Complex Bus)),不属于 E500 内核。有些高端 PowerPC 处理器的 L2 Cache 也在 CPU 中,而 L3 Cache 与 CCB 总线直接相连。
在 MPC8548 处理器中,所有外部设备,如以太网控制器、DDR 控制器和 OCeaN 连接的总线控制器都与 SoC 平台总线直接连接。而 SoC 平台总线通过 Cache 共享一致性模块与 FSB 连接。
在 MPC8548 处理器中,有一个 32 位的 PCI 总线控制器、一个 64 位的 PCI/PCI-X 总线控制器,还有多个 PCIe 总线控制器。MPC8548 处理器使用 OCeaN 连接这些 PCI、PCI-X 和 PCIe 总线控制器。
在 MPC8548 处理器系统中,PCI 设备进行 DMA 操作时,首先通过 OCeaN,之后经过 SoC 平台总线到达 DDR 控制器。
OCeaN 是 MPC8548 处理器中连接快速外设使用的交叉互连总线,不仅可以连接 PCI、PCI-X 和 PCIe 总线控制器,而且可以连接 RapidIO 总线控制器。使用 OCeaN 进行互连的总线控制器可以直接通信,而不需要通过 SoC 平台总线。
比如,来自 HOST 主桥 1 的数据报文可以通过 OCeaN 直接发向 HOST 主桥 2,而不需要将数据通过 SoC 平台总线进行转发,从而减轻了 SoC 平台总线的负担。
在这里插入图片描述
在 MPC8548 处理器中,有两个 HOST 主桥,分别是 HOST 主桥 1 和 HOST 主桥 2,其中 HOST 主桥 1 可以支持 PCI-X 总线,而 HOST 主桥 2 只能支持 PCI 总线。此外该处理器还含有多个 PCIe 总线控制器。从软件层面上看,PCIe 总线控制器与 PCI/PCI-X 总线控制器功能类似。
在 MPC8548 处理器的 HOST 主桥中,定义了一系列与系统软件相关的寄存器。后面将介绍这些寄存器,说明这个 HOST 主桥的功能。

PCI 设备配置空间的访问机制

访问配置空间,使用 ID 号进行寻址。PCI 设备的 ID 号由总线号(Bus Number)、设备号(Device Number)和功能号(Function Number)组成。
总线号在 HOST 主桥遍历 PCI 总线树时确定。在一棵 PCI 总线树上,有几个 PCI 桥(包括 HOST 主桥),就有几条 PCI 总线。在一棵 PCI 总线树中,总线号由系统软件决定,通常与 HOST 主桥直接相连的 PCI 总线编号为 0,系统软件使用 DFS(Depth-First Search)算法扫描 PCI 总线树上的所有 PCI 总线,并依次进行编号。
一条 PCI 总线的设备号由 PCI 设备的 IDSEL 信号与 PCI 总线地址线的连接关系确定。
功能号与 PCI 设备的具体设计相关。在一个 PCI 设备中最多有 8 个功能设备,而且
每一个功能设备都有各自的 PCI 配置空间
,不过在绝大多数 PCI 设备中只有一个功能设备。
HOST 主桥使用寄存器号,访问 PCI 设备配置空间的某个寄存器。
在 MPC8548 处理器的 HOST 主桥中,与 PCI 设备配置空间相关的寄存器有 CFG_ADDR、CFG_DATA 和 INT_ACK。系统软件使用 CFG_ADDR 和 CFG_DATA 寄存器访问 PCI 设备的配置空间,而使用 INT_ACK 寄存器访问挂接在 PCI 总线上的中断控制器的中断向量。
在这里插入图片描述
在 MPC8548 处理器中,所有内部寄存器都使用存储器映射方式进行寻址,并存放在以 BASE_ADDR 变量为起始地址的 “1MB 连续的物理地址空间”中。PowerPC 处理器可以通过 BASE_ADDR + Offset 的方式访问上表中的寄存器。
MPC8548 处理器使用 CFG_ADDR 寄存器和 CFG_DATA 寄存器访问 PCI 设备的配置空间,其中使用 CFG_ADDR 寄存器保存 PCI 设备的 ID 号和寄存器号,该寄存器的各个字段的详细说明如下

  • Enable 位。当该位为 1 时,HOST 主桥使能对 PCI 设备配置空间的访问,当 HOST 处理器对 CFG_DATA 寄存器进行访问时,HOST 主桥将对这个寄存器的访问转换为 PCI 配置读写总线事务并发送到 PCI 总线上。
  • Bus Number 字段记录 PCI 设备所在的总线号。
  • Device Number 字段记录 PCI 设备的设备号。
  • Function Number 字段记录 PCI 设备的功能号。
  • Register Number 字段记录 PCI 设备的配置寄存器号。
存储器域地址空间到 PCI 总线域地址空间的转换

MPC8548 处理器使用 ATMU(Address Translation and Mapping Unit)寄存器组进行存储器域到 PCI 总线域,以及 PCI 总线域到存储器域的地址映射。
ATMU 寄存器组由两大组寄存器组成,分别为 Outbound 和 Inbound 寄存器组。其中 Outbound 寄存器组将存储器域的地址转换为 PCI 总线域的地址,而 Inbound 寄存器组将 PCI 总线域的地址转换为存储器域的地址。
只有当 CPU 读写访问的地址访问在 Outbound 寄存器组管理的地址空间之内时,HOST 主桥才能接收 CPU 的读写访问,并将 CPU 在存储器域上的读写访问转换为 PCI 总线域上的读写访问。
CPU 对存储器域的地址访问,首先使用 CCB 总线事务,如果所访问的地址在 Cache 中命中,则从 Cache 中直接获得数据,否则将从存储器域中获取数据。而在绝大多数情况下,外部设备使用的地址空间是不可 Cache 的,所以发向 PCI 设备的 CCB 总线事务通常不会与 Cache 进行数据交换。如果 CCB 总线事务使用的地址在 HOST 主桥的 Outbound 寄存器窗口中命中,HOST 主桥将接收这个 CCB 总线事务,并将其转换为 PCI 总线事务之后,再发送到 PCI 总线上。

x86 处理器的 HOST 主桥

x86 处理器使用南北桥结构连接 CPU 和 PCI 设备。其中北桥(North Bridge)连接快速设备,如显卡和内存条,并推出 PCI 总线,HOST 主桥包含在北桥中。而南桥(South Bridge)连接慢速设备。
在这里插入图片描述
目前 Intel 对南北桥架构进行了升级,其中北桥被升级为 MCH(Memory Controller Hub),而南桥被升级为 ICH(I/O Controller Hub)。MCH 中集成了存储器控制器、显卡控制器和 HOST-to-PCIe 主桥,并通过 Hub Link 与 ICH 相连;而在 ICH 中集成了一些相对低速的总线接口,如 USB 总线和一些低带宽的 PCIe 总线接口。在 Intel 的 Nehalem 处理器系统中,MCH 被一分为二,存储器控制器和显卡控制器已经与 CPU 内核集成在一个 DIE 中,而 MCH 剩余部分与 ICH 合并称为 PCH(Peripheral Controller Hub)。但从体系结构的角度上看,这些升级与整合并不重要。

PCI 桥

PCI 总线的电气特性决定了在一条 PCI 总线上挂接的负载个数有限,当 PCI 总线需要连接多个 PCI 设备时,需要使用 PCI 桥进行总线扩展,扩展出的 PCI 总线可以连接其它 PCI 设备,包括 PCI 桥。
在一颗 PCI 总线树上,最多可以挂接 256 个 PCI 设备,包括 PCI 桥。
在这里插入图片描述
PCI 桥作为一个特殊的 PCI 设备,具有独立的配置空间。PCI 桥的配置空间可以管理其下 PCI 总线子树的 PCI 设备。PCI 桥的配置空间在系统软件遍历 PCI 总线树时进行配置,系统软件不需要专门的驱动程序设置 PCI 桥的使用方法,这也是 PCI 桥被称为透明桥的主要原因。
PCI 桥跨接在两个 PCI 总线之间,其中距离 HOST 主桥较近的 PCI 总线被称为该桥片的上游总线(Primary Bus),距离 HOST 主桥较远的 PCI 总线被称为该桥片的下游总线(Secondary Bus)。
如上图,PCI 总线 x0 和 x1 分别是 PCI 桥 1 的上游和下游总线,这两条总线间的数据通信需要通过 PCI 桥 1。
当 PCI 桥出现故障时,其下的设备不能将数据传递给上游总线,但是并不影响 PCI 桥下游设备间的通信。如,当 PCI 桥 1 出现故障时,PCI 设备 11、PCI 设备 21、PCI 设备 22 将不能与 PCI 设备 01 和存储器进行通信,但 PCI 设备 21 和 PCI 设备 22 之间的同学可以正常进行。(疑问:11 和 21 是不是也不能通信了?应该是)
PCI 桥对于理解 PCI 和 PCIe 总线都非常重要。在 PCIe 总线中,虽然在物理结构上并不含有 PCI 桥,但是与 PCI 桥相关的知识在 PCIe 总线中无处不在,比如在 PCIe 总线的 Switch 中,每一个端口都与一个虚拟 PCI 桥对应,Switch 使用这个虚拟 PCI 桥管理其下 PCI 总线子树的地址空间。
有了上面知识的铺垫,再来看下图 PCIe 的拓扑,就好理解多了。
之前没有 PCI 桥的知识储备,看下面这张图真的是云里雾里的。
在这里插入图片描述

PCI Agent 设备的配置空间

在一个具体的处理器应用中,PCI 设备通常将 PCI 配置信息存放在 EEPROM 中,PCI 设备进行上电初始化时,将 EEPROM 中的信息读到 PCI 设备的 配置空间中作为初始值。这个过程由硬件逻辑完成,绝大多数 PCI 设备使用这种方式初始化其配置空间。
在 x86 处理器中,系统软件使用 CONFIG_ADDR 和 CONFIG_DATA 寄存器,读取 PCI 设备配置空间的这些初始化信息,然后根据处理器系统的实际情况使用 DFS 算法,初始化处理器系统中所有 PCI 设备的配置空间。
在 PCI Agent 设备的配置空间中包含了许多寄存器,这些寄存器决定了该设备在 PCI 总线中的使用方法。
在这里插入图片描述

(1)Device ID 和 Vendor ID 寄存器
这两个寄存器的值由 PCISIG 分配,只读。其中 Vendor ID 代表 PCI 设备的生产厂商,而 Device ID 代表这个厂商所生产的具体设备。如 Intel 公司基于 82571EB 芯片的系列网卡,其 Vendor ID 为 0x8086,而 Device ID 为 0x105E。其中 0x8086 代表 Intel,0x105E 代表 82571EB 网卡芯片。当 Vendor ID 寄存器为 0xFFFF 时,表示为无效 Vendor ID。
(2)Revision ID 和 Class Code 寄存器
只读。Class Code 寄存器记载 PCI 设备的分类,该寄存器由三个字段组成,分别是 Base Class Code、Sub Class Code 和 Interface。其中 Base Class Code 将 PCI 设备分类为显卡、网卡、PCI 桥等设备;Sub Class Code 对这些设备进一步细分;而 Interface 定义编程接口。
(3)Header Type 寄存器
只读,由 8 位组成。
第 7 位为 1 表示当前 PCI 设备是多功能设备,为 0 表示为单功能设备。
第 6~0 位表示当前配置空间的类型,为 0 表示该设备使用 PCI Agent 设备的配置空间,普通 PCI 设备都使用这种配置头;为 1 表示使用 PCI 桥的配置空间,PCI 桥使用这种配置头。
(4)Cache Line Size 寄存器
可读可写。该寄存器由系统软件设置。
该寄存器记录 HOST 处理器使用的 Cache Line 长度。在 PCI 设备运行过程中,只有其硬件逻辑才会使用该寄存器,比如 PCI 设备的硬件逻辑需要得知处理器系统 Cache 行的大小,才能进行存储器写并无效总线事务。
如果 PCI 设备不支持与 Cache 相关的总线事务,系统软件可以不设置改寄存器,此时该寄存器为初始值 0x00。对于 PCIe 设备,该寄存器的值无意义,因为 PCIe 设备在进行数据传送时,在其报文中含有一次数据传送的大小,PCIe 总线控制器可以使用这个“大小”,判断数据区域与 Cache 行的对应关系。
(5)Subsystem ID 和 Subsystem Vendor ID 寄存器
(6)Expansion ROM base address 寄存器
有些 PCI 设备在处理器还没有运行操作系统之前,就需要完成基本的初始化设置,比如显卡、键盘和硬盘等设备。为了实现这个“预先执行”功能,PCI 设备需要提供一段 ROM 程序,而处理器在初始化过程中将运行这段 ROM 程序,初始化这些 PCI 设备。Expansion ROM base address 记载这段 ROM 程序的基地址。
(7)Interrupt Line 寄存器
这个寄存器是系统软件对 PCI 设备进行配置时写入的,该寄存器记录当前 PCI 设备使用的中断向量号,设备驱动程序可以通过这个寄存器,判断当前 PCI 设备使用处理器系统中的哪个中断向量号,并将驱动程序的中断服务例程注册到操作系统中。
liyongjun 总结:操作系统(HOST 主桥)分配给每个 PCI 设备一个中断向量号,将这个中断号写入 PCI 设备配置空间 Interrupt Line 寄存器中。然后驱动程序读取该寄存器,使用 irq_register(),将该中断号和中断服务程序绑定。
目前在绝大多数处理器系统中,并没有使用该寄存器存放 PCI 设备使用的中断向量号。。。
(8)Interrupt Pin 寄存器
这个寄存器保存 PCI 设备使用的中断引脚。PCI 总线提供了四个中断引脚:INTA#、INTB#、INTC# 和 INTD#。Interrupt Pin 寄存器为 1 时表示使用 INTA# 引脚向中断控制器提交中断请求,为 2 表示使用 INTB#。。。
如果 PCI 设备只有一个子设备时,该设备只能使用 INTA#。如果 PCI 设备不使用这些中断引脚,向处理器提交中断请求时,该寄存器的值必须为 0。值得注意的是,虽然在 PCIe 设备中并不含有 INTA~D# 信号,但是依然可以使用该寄存器,因为 PCIe 设备可以使用 INTx 中断消息,模拟 PCI 设备的 INTA~D# 信号。
(9)Base Address Register 0~5 寄存器
该组寄存器简称为 BAR 寄存器,BAR 寄存器保存 PCI 设备使用的地址空间的基地址,该基地址保存的是该设备在 PCI 总线域中的地址。其中每一个设备最多可以有 6 个基址空间,但多数设备不会使用这么多组地址空间。
在 PCI 设备复位后,该寄存器将存放 PCI 设备需要使用的基址空间大小(一般来说 PCI 设备使用 EEPROM 保存 BAR 寄存器的初始值)、这段空间是 I/O 空间还是存储器空间、如果是存储器空间该空间是否可预取。
系统软件对 PCI 总线进行配置时,首先获得 BAR 寄存器中的初始化信息,之后根据处理器系统的配置,将合理的基地址写入相应的 BAR 寄存器中。系统软件还可以使用该寄存器,获得 PCI 设备使用的 BAR 空间的长度,其方法是向 BAR 寄存器写入0xFFFFFFFF,之后再读取该寄存器。
处理器访问 PCI 设备的 BAR 空间时,需要使用 BAR 寄存器提供的基地址。值得注意的是,BAR 寄存器存放的是 PCI 总线域的地址,因此处理器系统并不能直接使用“BAR 寄存器值 + 偏移”的方式访问 PCI 设备的寄存器空间,而需要将 PCI 总线域的地址转换为存储器域的地址。
在 Linux 系统中,一个处理器系统使用 BAR 空间的正确方式如源代码

pciaddr = pci_resource_start(pdev, 1);
regs = ioremap(pciaddr, CP_REGS_SIZE);

在 Linux 系统中,使用 pci_dev->resource[bar].start 参数保存 BAR 寄存器在存储器域的地址。在编写 Linux 设备驱动程序时,必须使用 pci_resource_start 函数获得 BAR 空间对应的存储器域的物理地址,而不能使用从 BAR 寄存器中读出的地址。
当驱动程序获得 BAR 空间在存储器域的物理地址后,再使用 ioremap 函数将这个物理地址转换为虚拟地址。
Linux 系统直接使用 BAR 空间的方法是正确的,如源代码

pci_read_config_dword(pdev, 1, &pciaddr);
regs = ioremap(pciaddr, BAR_SIZE);

在 Linux 中,使用 pci_read_config_dword 函数获得的是 PCI 总线域的物理地址。
在 pci_dev->resource[bar].start 参数中保存的地址已经经过 PCI 总线域到存储器域的地址转换。
(10)Command 寄存器
该寄存器为 PCI 设备的命令寄存器,在初始化时,其值为 0,此时这个 PCI 设备除了能够接收配置请求总线事务之外,不能访问该设备的存储器或者 I/O 空间。
(liyongjun:突然悟了,PCI 设备自身没有内存,所以要借助 HOST 处理器的内存。需要使用多大的内,由 BAR 寄存器告知处理器,处理器会分配给它,并将地址范围再次写入 BAR 寄存器中,只不过这个地址范围被 HOST 主桥转换过,是 PCI 总线域的地址。PCI 设备有数据时,直接使用 DMA 控制器将数据写入到这段内存空间,然后再向处理器发送一个中断,通知处理器去取数据)
系统软件需要合理设置该寄存器之后,才能访问该设备的存储器或者 I/O 空间。在 Linux 中,设备驱动程序调用 pci_enable_device 函数,使能该寄存器的 I/O 和 Memory Space 为之后,才能访问该设备的存储器或者 I/O 地址空间。Command 寄存器的各位的含义如下表
在这里插入图片描述
在这里插入图片描述
(11)Status 寄存器
该寄存器的绝大多数位都是只读位,保存 PCI 设备的状态
(12)Latency Timer 寄存器
PCIe 设备不需要使用该寄存器,该寄存器的值必须为 0。

PCI 桥的配置空间

PCI 桥使用的配置空间如下所示,PCI 桥作为一个 PCI 设备,使用的许多配置寄存器与 PCI Agent 的寄存器是类似的,如 Device ID、Vendor ID、Status、Command、Interrupt Pin、Interrupt Line 寄存器等。下面只介绍在 PCI 桥中与 PCI Agent 的配置空间不相同的寄存器。
在这里插入图片描述
与 PCI Agent 设备不同,在 PCI 桥中只含有两个 BAR 寄存器,即 Base Address Register 0~1 寄存器。在 PCI 桥中,这两个寄存器是可选的。如果在 PCI 桥中不存在私有寄存器,那么可以不使用这两个寄存器设置 BAR 空间,这两个 BAR 寄存器初始化为 0。
在大多数 PCI 桥中都不存在私有寄存器,操作系统也不需要为 PCI 桥提供专门的驱动程序,这也是这类桥被称为透明桥的原因。
在 PCI 桥的配置空间中,有许多寄存器是 PCI 桥所特有的。PCI 桥除了作为 PCI 设备之外,还需要管理其下连接的 PCI 总线子树使用的各类资源,即 Secondary Bus 所连接 PCI 总线子树使用的资源。这些资源包括存储器、I/O 地址空间和总线号。
在 PCI 桥中,与 Secondary bus 相关的寄存器包括两大类。一类寄存器管理 Secondary Bus 之下 PCI 子树的总线号,如 Secondary 和 Subordinate Bus Number 寄存器;另一类寄存器管理下游 PCI 总线的 I/O 和存储器地址空间,如 I/O 和 Memory Limit、I/O 和 Memory Base 寄存器。在 PCI 桥中还使用 Primary Bus 寄存器保存上游的 PCI 总线号。
(1)Subordinate Bus Number、Secondary Bus Number 和 Primary Bus Number 寄存器
Subordinate Bus Number 寄存器存放当前 PCI 子树中,编号最大的 PCI 总线号。而 Secondary Bus Number 寄存器存放当前 PCI 桥下游总线号,Primary Bus Number 寄存器存放该 PCI 桥的上游总线号。
Subordinate Bus Number、Secondary Bus Number 和 Primary Bus Number 寄存器在初始化时必须为 0,系统软件将根据这几个寄存器是否为 0,判断 PCI 桥是否被配置过。
不同的操作系统使用不同的 Bootloader 引导,有的 Bootloader 可能会对 PCI 总线树进行遍历,此时操作系统不必重新遍历 PCI 总线树。在 x86 处理器系统中,BIOS 会遍历处理器系统中的所有 PCI 总线树,操作系统可以直接使用 BIOS 的结果,也可以重新遍历 PCI 总线树。而 PowerPC 处理器系统中的 Bootloader,如 u-boot 并没有完全遍历 PCI 总线树,此时操作系统必须重新遍历 PCI 总线树。
(2)Secondary Status 寄存器
记录下游总线的状态
(3)Secondary Latency Timer 寄存器
(4)I/O Limit 和 I/O Base 寄存器
PCI 桥使用这两个寄存器,存放 PCI 子树中所有设备使用的 I/O 地址空间集合的基地址和大小。
(5)Memory Limit 和 Memory Base 寄存器
PCI 桥使用这两个寄存器,存放 PCI 子树中所有设备使用的 存储器 地址空间集合的基地址和大小。
(6)Prefetchable Memory Limit 和 Prefetchable Memory Base 寄存器
(7)I/O Base Upper 16 Bits and I/O Limit Upper 16 寄存器
(8)Bridge Control Register
该寄存器用来管理 PCI 桥的 Secondary Bus,其主要位的描述如下

  • Secondary Bus Reset 位,第 6 位,可读写。当该位为 1 时,将使用下游总线提供的 RST# 信号复位与 PCI 桥的下游总线连接的 PCI 设备。

PCI 总线的配置

PCI 总线定义了两类配置请求,一类是 Type 00h 配置请求,另一类是 Type 01h 配置请求。PCI 总线使用这些配置请求访问 PCI 总线树上的设备配置空间,包括 PCI 桥和 PCI Agent 设备的配置空间。
其中 HOST 主桥和 PCI 桥使用 Type 00h 配置请求访问与 HOST 主桥或者 PCI 桥直接相连的 PCI Agent 设备或者 PCI 桥;
而 HOST 主桥和 PCI 桥使用 Type 01h 配置请求,访问没有与其直接相连(需要至少穿越一个 PCI 桥)的 PCI Agent 设备或者 PCI 桥。
当 x86 处理器对 CONFIG_DATA 寄存器进行读写操作时,HOST 主桥将决定向 PCI 总线发送 Type 00h 配置请求还是 Type 01 配置请求。在 PCI 总线事务的地址周期中,这两种配置请求总线事务的不同反映在 AD[31:0] 信号线上。
处理器首先将目标 PCI 设备的 ID 号保存在 CONFIG_ADDRESS 寄存器中,之后 HOST 主桥根据该寄存器的 Bus Number 字段,决定是产生 Type 00h 配置请求,还是 Type 01h 配置请求。当 Bus Number 字段为 0 时,将产生 Type 00h 配置请求,因为与 HOST 主桥直接相连的总线号为 0;大于 0 时,将产生 Type 01h 配置请求。


liyongjun 感悟:
任何一个控制器(PCI 控制器、DDR 控制器、I2C 控制器、SPI 控制器),在 CPU 面前,都被视为一组寄存器。想要让控制器干活,读写它的寄存器就好了。
任何一个外设(PCI 设备、DDR、I2C 设备、SPI 设备),在其控制器面前,都被视为一组寄存器。想要让设备干活,读写它的寄存器就好了。
控制器相当于一个功能函数,寄存就是它对外(CPU)提供的接口。内部函数实现操作外设的功能。
外设相当于一个功能函数,寄存器就是它对外(控制器)提供的接口。内部函数实现从大千世界捞数据的功能(使用 ADC 采集电平,进而将一个个高低电平转换为网络数据、温度数据、距离数据等等)。
因为你无法使用刀子划开控制器或者外设来窥探它内部实现的逻辑(就像合作伙伴不会提供其函数源码),所以控制器或者外设会提供它的接口文档(Datasheet)——寄存器说明、读写时序说明,以及会尽可能充分地描述其内部实现原理(不过,再怎么详尽,也无法百分之百透彻精确地描述其内部构造和运作过程)。不过,尽管这样,Datasheet 仍然是我们能够了解这个器件最好的途径。


在地址周期中,HOST 主桥将 CONFIG_ADDRESS 寄存器的内容复制到 PCI 总线的 AD[31:0] 信号线中。CONFIG_ADDRESS 寄存器与 Type 01h 配置请求的对应关系如下图所示
在这里插入图片描述
可以看到,CONFIG_ADDRESS 寄存器的内容基本上是原封不动地复制到 PCI 总线的 AD[31:0] 信号线上的。其中 Enable 位不被复制,而是让 AD 总线的第 0 位为 1,表示当前配置请求是 Type 01h。
如果 HOST 主桥或者 PCI 桥发起的是 Type 00h 配置请求,CONFIG_ADDRESS 寄存器与 AD[31:0] 的转换如下图所示
在这里插入图片描述
处理器对 CONFIG_DATA 寄存器进行读写时,处理器将 CONFIG_ADDRESS 寄存器中的 Function Number 和 Register Number 字段复制到 PCI 的 AD 总线的第 10~2 位;将 AD 总线的第 1~0 位赋值为 0b00,表示 Type 00h。
而 AD[31:11] 与 CONFIG_ADDRESS 的 Device Number 字段相关,在 Type 00h 类型的地址周期中,AD[31:11] 位有且只有一位为 1,每一位选通一个 PCI 设备的配置空间。PCI 设备配置空间的片选信号是 IDSEL,因此 AD[31:11] 的每一根线连接一个 PCI 设备的 IDSEL 信号。
在 CONFIG_ADDRESS 寄存器中 Device Number 字段一共有 5 位,可以表示 32 个设备,而 AD[31:11] 只有 21 位。所以在一条总线上最多只能挂接 21 个 PCI 设备,这在实际的应用中已经足够了。
在这里插入图片描述

PCI 总线的数据交换

PCI Agent 设备之间以及 HOST 处理器和 PCI Agent 设备之间可以使用存储器读写和 I/O 读写等总线事务进行数据传送。在大多数情况下,PCI 桥不直接与 PCI 设备或者 HOST 主桥进行数据交换,而仅转发来自 PCI Agent 设备或者 HOST 主桥的数据。
PCI Agent 设备间的数据交换并不是本章讨论的重点。本章侧重讲述 PCI Agent 设备使用 DMA 机制读写主存储器的数据,以及 HOST 处理器如何访问 PCI 设备的 BAR 空间。

PCI 设备 BAR 空间的初始化

在 PCI Agent 设备进行数据传送之前,系统软件需要初始化 PCI Agent 设备的 BAR0~5 寄存器和 PCI 桥的 Base、Limit 寄存器。系统软件使用 DFS 算法对 PCI 总线进行遍历时,完成这些寄存器的初始化,即分配这些设备在 PCI 总线域的地址空间。当这些寄存器初始化完毕后,PCI 设备可以使用 PCI 总线地址进行数据传递。
PCI 设备访问存储器域的地址空间,即进行 DMA 操作时,是首先访问该存储器地址空间对应的 PCI 总线地址空间,之后通过 HOST 主桥将这个 PCI 总线地址空间转换为存储器地址空间,再由 DDR 控制器对存储器进行读写访问。
liyongjun疑问:PCI 设备如何知道向哪个存储器域地址空间写数据呢?
想到的答案是:无需知道,它只要知道有一块空间是属于它的,它往里面写内容就行了。让处理器和 HOST 主桥去 care 地址如何转换。

不同的处理器系统采用不同的机制实现存储器域和 PCI 总线域的转换。如 PowerPC 处理器使用 Outbound 寄存器组实现存储器域到 PCI 总线域之间的地址转换,使用 Inbound 寄存器组实现 PCI 总线域到存储器域之间的地址转换。
而 x86 处理器没有这种地址空间域的转换机制,因此从 PCI 设备的角度来看,PCI 设备可以直接访问存储器地址;从处理器的角度来看,处理器可以直接访问 PCI 总线地址空间。但需要注意,在 x86 处理器的 HOST 主桥中仍然有存储器域与 PCI 总线域这个概念,只是在 x86 处理器的 HOST 主桥中,存储器域的存储器地址与 PCI 总线地址相等,这种“简单相等”也是一种映射关系。

存储器地址与 PCI 总线地址的转换

假设在一个 32 位处理器中,存储器域的 0xF0000000~0xF7FFFFFF(共 128MB)这段物理地址空间与 PCI 总线的地址空间存在映射关系。
为简化起见,假定在存储器域中只映射了 PCI 设备的存储器地址空间,而不映射 PCI 设备的 I/O 地址空间。而 PCI 设备的 BAR 空间使用 0x70000000~0x77FFFFFF 这段 PCI 总线域的存储器地址空间。
在这里插入图片描述
当 PCI 设备使用 DMA 机制访问存储器域地址空间时,处理器系统同样需要将存储器域的地址空间反向映射到 PCI 总线地址空间。
假设在一个处理器系统中,主存储器大小为 2GB,其在存储器域的地址范围为 0x00000000~0x7FFFFFFF,而这段地址在 PCI 总线域中对应的 PCI 总线地址空间为 0x80000000~0xFFFFFFFF。
因此 PCI 设备进行 DMA 操作时,必须使用 0x80000000~0xFFFFFFFF 这段 PCI 总线域的地址,HOST 主桥才能认领这个 PCI 总线事务,并将这个总线事务使用的 PCI 总线地址转换为存储器地址,并与 0x00000000~0x7FFFFFFF 这段存储器区域进行数据传递。
在一个实际的处理器系统中,很少有系统软件采用这样的方法,“简单相等”才是最常用的映射方法。

PCI 设备 BAR 寄存器和 PCI 桥 Base、Limit 寄存器的初始化

PCI 桥的 Base、Limit 寄存器保存“该桥所管理的 PCI 子树”的存储器或者 I/O 空间的基地址和长度。值得注意的是,PCI 桥也是 PCI 总线上的一个设备,在其配置空间中也有 BAR 寄存器,不过这里不对 PCI 桥的 BAR 寄存器进行说明,因为在多数情况下透明桥并不使用其内部的 BAR 寄存器。
以下面这张图为例,说明 BAR、Base、Limit 寄存器的初始化过程,其中存储器域和 PCI 总线域的映射关系如上图所示。
在这里插入图片描述
在 PCI 设备的 BAR 寄存器中,包含该设备使用的 PCI 总线域的地址范围。在 PCI 设备的配置空间中共有 6 个 BAR 寄存器,因此一个 PCI 设备最多可以使用 6 组 32 位的 PCI 总线地址空间,或者 3 组 64 位的 PCI 总线地址空间。目前多数 PCI 设备仅使用存储器地址空间。
为简化起见,首先假定在图3-2 所示的 PCI 总线树中,所有 PCI Agent 设备只使用了 BAR0 寄存器,其申请的数据空间大小为 16MB(即 0x1000000B)而且不可预读,而且 PCI 桥不占用 PCI 总线地址空间,即 PCI 桥不含有 BAR 空间。并且假定当前 HOST 主桥已经完成了对 PCI 总线树的编号。
根据以上假设,该 PCI 总线树的遍历过程如下
(1)系统软件根据 DFS 算法,首先寻找第一组 PCI 设备,分别为 PCI 设备 31 和PCI 设备 32,并根据这两个 PCI 设备需要的 PCI 空间大小,从 PCI 总线地址空间(0x70000000~0x77FFFFFF)中,为这两个 PCI 设备的 BAR0 寄存器分配基地址,分别为 0x70000000 和 0x71000000。
(2)当系统软件完成 PCI 总线 3 下所有设备的 BAR 空间的分配后,将初始化 PCI 桥 3 的配置空间。这个桥片的 Memory Base 寄存器保存其下所有 PCI 设备使用的“PCI 总线域地址空间的基地址”,而 Memory Limit 寄存器保存其下 PCI 设备使用的“PCI 总线域地址空间的大小”。系统软件将 Memory Base 寄存器赋值为 0x70000000,而将 Memory Limit 寄存器赋值为 0x2000000。
(3)系统软件回溯到 PCI 总线 2,并找到 PCI 总线 2 上的 PCI 设备 21,并将 PCI 设备 21 的 BAR0 寄存器赋值为 0x72000000。
(4)完成 PCI 总线 2 的遍历后,系统软件初始化 PCI 桥 2 的配置寄存器,将 Memory Base 寄存器赋值为 0x70000000,Memory Limit 寄存器赋值为 0x3000000。
(5)系统软件回溯到 PCI 总线 1,并找到 PCI 设备 11,并将这个设备的 BAR0 寄存器赋值为 0x73000000。并将 PCI 桥 1 的 Memory Base 寄存器赋值为 0x70000000,Memory Limit 寄存器赋值为 0x4000000。
(6)系统软件回溯到 PCI 总线 0,并在这条总线上发现另外一个 PCI 桥,即 PCI 桥 4。并使用 DFS 算法继续变量 PCI 桥 4。首先系统软件将遍历 PCI 总线 4,并发现 PCI 设备 41 和 PCI 设备 42,并将这两个 PCI 设备的 BAR0 寄存器分别赋值为 0x74000000 和 0x75000000。
(7)系统软件初始化 PCI 桥 4 的配置寄存器,将 Memory Base 寄存器赋值为 0x74000000,Memory Limit 寄存器赋值为 0x2000000。系统软件再次回到 PCI 总线 0,这一次系统软件没有发现新的 PCI 桥,于是将初始化这条总线上的所有 PCI 设备。(liyongjun:所以,在一个总线上,会优先变量 PCI 桥,再遍历 PCI 设备)
(8)PCI 总线 0 上只有一个 PCI 设备,即 PCI 设备 01。系统软件将这个设备的 BAR0 寄存器赋值为 0x76000000,并结束整个 DFS 遍历过程。

PCI 设备的数据传递

PCI 设备的数据传递使用地址译码方式,当一个存储器读写总线事务到达 PCI 总线时,在这条总线上的所有 PCI 设备将进行地址译码,如果当前总线事务使用的地址在某个 PCI 设备的 BAR 空间中时,该 PCI 设备将使能 DEVSEL# 信号,认领这个总线事务。
PCI 桥使用的正向译码方式与 PCI 设备使用的正向译码方式有所不同。当一个总线事务是从 PCI 桥的 Primary Bus 到 Secondary Bus 时,PCI 桥使用的正向译码方式与 PCI 设备使用的方式类似。如果该总线事务使用的地址在 PCI 桥任意一个 Memory Base 窗口中命中时,该 PCI 桥将使用正向译码方式接收该总线事务,并根据实际情况决定是否将这个总线事务转发到 Secondary Bus。
在这里插入图片描述
当一个总线事务是从 PCI 桥的 Secondary Bus 到 Primary Bus 时,如果该总线事务使用的地址没有在 PCI 桥所有的 Memory Base 窗口命中,表明当前总线事务不是访问该 PCI 桥管理的 PCI 子树中的设备,因此 PCI 桥将接收当前总线事务,并根据实际情况决定是否将这个总线事务转发到 Primary Bus。
以图 3-2 为例,当 PCI 设备 11 访问主存储器空间时,首先将存储器读写总线事务发送到 PCI 总线 1 上,而这个存储器地址显然不会在 PCI 总线 1 的任何 PCI 设备的 BAR 空间中,此时 PCI 桥 1 将认领这个 PCI 总线的数据请求,并将这个总线事务转发到 PCI 总线 0 上。最后 HOST 主桥将接收这个总线事务,并将 PCI 总线地址转换为存储器域的地址,与主存储器进行读写操作。在 PowerPC 处理器中,如果当前存储器读写总线事务使用的地址在 Inbound 窗口内,HOST 主桥将接收这个总线事务,并将其转换为存储器域的读写总线事务,与主存储器进行数据交换。

处理器到 PCI 设备的数据传送

下面以图 3-2 所示的处理器系统为例,说明处理器向 PCI 设备 11 进行存储器写的数据传送过程。PCI 设备 11 在 PCI 总线域的地址范围是 0x73000000~0x73FFFFFF。这段空间在存储器域中对应的地址范围是 0xF3000000~0xF3FFFFFF。下面假设处理器使用存储器写指令,访问 0xF3000008 这个存储器地址,其步骤如下
(1)存储器域将 0xF3000008 这个地址发向 HOST 主桥,0xF0000000~0xF7FFFFFF 这段地址已经由 HOST 主桥映射到 PCI 总线域地址空间,所以 HOST 主桥认为这是一个对 PCI 设备的访问。因此 HOST 主桥将首先接管这个存储器写请求。
(2)HOST 主桥将存储器域的地址 0xF3000008 转换为 PCI 总线域的地址 0x73000008,并通过总线仲裁获得 PCI 总线 0 的使用权,启动 PCI 存储器写周期,将这个存储器写总线事务发送到 PCI 总线 0 上。
(3)PCI 总线 0 上的 PCI 桥 1 发现 0x73000008 在自己管理的地址范围内,于是接管这个存储器写请求,并通过总线仲裁逻辑获得 PCI 总线 1 的使用权,并将这个请求转发到 PCI 总线 1 上。
(4)PCI 总线 1 的 PCI 设备 11 发现 0x73000008 在自己的 BAR0 寄存器中命中,于是接收这个 PCI 写请求,并完成存储器写总线事务。

PCI 设备的 DMA 操作

下面以图 3-2 所示的处理器系统为例,说明 PCI 设备 11 向存储器进行 DMA 写的数据传送过程。PCI 设备的 DMA 写使用 Posted 方式,而 DMA 读使用 Non-Posted 方式,本节只介绍写。
假定 PCI 设备 11 需要将一组数据发送到 0x10000000~0x1000FFFF 这段存储器域的地址空间中。
PCI 设备 11 并不能直接操作 0x10000000~0x1000FFFF 这段存储器域的地址空间,需要对 PCI 总线域的地址空间 0x90000000~0x9000FFFF 进行写操作,因为 PCI 总线地址空间 0x90000000~0x9000FFFF 已经被 HOST 主桥映射到 0x10000000~0x1000FFFF 这段存储器域。这个 DMA 写操作流程如下
(1)首先 PCI 设备 11 通过总线仲裁逻辑获得 PCI 总线 1 的使用权,之后将存储器写总线事务发送到 PCI 总线 1 上。值得注意的是,这个存储器写总线事务的目的地址是 PCI 总线域的地址空间 0x90000000~0x9000FFFF,这个地址是主存储器在 PCI 总线域的地址映射。(liyongjun疑问,HOST 主桥保存这份映射,而 PCI 设备 11 又是如何知道这个映射关系的呢?)

11:
PCI 设备通过 DMA 向内存写数据时,PCI 设备发出的地址为 PCI 总线地址,我的问题是,PCI 设备如何知道 PCI 总线地址和内存总线地址的映射关系呢?我知道这个映射关系是存储在 HOST 主桥中的,PCI 设备是如何知道这个映射关系的呢?
AI:
PCI设备通过DMA向内存写数据时,需要知道PCI总线地址和内存总线地址的映射关系。这个映射关系存储在主机主桥中的PCI配置空间中的PCI Base Address Register(BAR)中。
主机主桥是PCI总线和系统总线(如PCIe或PCI-X)之间的桥接器。它负责管理PCI设备和系统总线之间的通信。当PCI设备插入主机时,主机主桥会为该设备分配一个唯一的PCI总线地址,并将该地址配置给设备。
PCI设备可以通过PCI配置空间访问该配置信息。PCI配置空间是一组寄存器,存储在设备的内存空间中。通过读取和写入这些寄存器,设备可以获取分配给它的PCI总线地址,并了解PCI总线地址和内存总线地址的映射关系。
设备可以使用PCI配置空间中的BAR寄存器来获取映射关系。每个BAR寄存器包含一个地址掩码和一个基地址。设备读取该寄存器,获得基地址并与地址掩码进行逻辑与运算,以获取映射到内存总线的地址范围。
通过BAR寄存器,设备可以确定映射关系,并使用正确的地址访问内存。这使得设备能够使用DMA直接向内存写入数据,而不需要主机的干预。
总结起来,PCI设备通过访问PCI配置空间中的BAR寄存器来获取PCI总线地址和内存总线地址的映射关系。这种映射关系由主机主桥进行配置,并通过BAR寄存器向设备公开。
11:
我知道的是 BAR 寄存器中保存 内存总线地址到 PCI 总线地址映射后的 PCI 总线基地址,难道还保存着 PCI 总线地址到内存总线地址映射后的 PCI 总线基地址?
AI:
是的,您说得对。PCI设备通过BAR(Base Address Register)寄存器来了解PCI总线地址和内存总线地址的映射关系。每个PCI设备都有多个BAR寄存器,其中包含了PCI总线地址到内存总线地址的映射信息
BAR寄存器中的值指示了PCI设备在PCI总线上的地址范围,并提供了与内存总线上对应地址的映射。PCI设备可以通过读取BAR寄存器中的值来获取PCI总线地址到内存总线地址的映射关系。
具体而言,当PCI设备需要向内存写入数据时,它会使用DMA(Direct Memory Access)进行传输。在进行DMA传输之前,PCI设备会读取相应的BAR寄存器来获取映射关系,从而知道应该将数据写入哪个内存地址。
因此,PCI设备通过读取BAR寄存器中的值来了解PCI总线地址到内存总线地址的映射关系,从而确定数据应该写入的内存地址。

(2)。。。 略

与 Cache 相关的 PCI 总线事务

PCI 总线规范定义了一系列与 Cache 相关的总线事务,以提高 PCI 设备与主存储器进行数据交换的效率,即 DMA 读写效率。当 PCI 设备使用 DMA 方式向存储器进行读写操作时,一定需要经过 HOST 主桥,而 HOST 主桥通过 FSB 总线向存储器控制器进行读写操作时,需要进行 Cache 共享一致性操作。
PowerPC 处理器,如 MPC8548 处理器,可以使用 Inbound 寄存器的 RTT 字段和 WTT 字段,设置在 PCI 设备进行 DMA 操作时,是否需要进行 Cache 一致性操作,是否可以将数据直接写入 Cache 中。
HOST 主桥 PIWARn 寄存器中有 RTT 字段和 WTT 字段,在 Inbound 窗口中可以规定 PCI 设备访问主存储器时,是否需要进行 Cache 一致性操作(Cache Lock and Allocate),在进行 DMA 写操作时,数据是否可以直接进入 Cache。该字段是 PowerPC 处理器对 PCI 总线规范的有效补充,由于该字段的存在,PowerPC 处理器的 PCI 设备可以将数据直接写入 Cache,也可以视情况决定 DMA 操作是否需要进行 Cache 共享一致性操作。

Cache 一致性的基本概念

PCI 设备对可 Cache 的存储器空间进行 DMA 读写操作的过程较为复杂,本节仅介绍在 Cache Memory 系统中与 PCI 设备进行 DMA 操作相关的一些最为基础的概念。

  1. Cache 一致性协议
    多数 SMP 处理器系统使用 MESI 协议处理多个处理器之间的 Cache 一致性。该协议也称为 Illinois protocol,在 SMP 处理器系统中得到广泛应用。MESI 协议使用四个状态位描述每一个 Cache 行。
  • M(Modified)位。M 位为 1 时表示当前 Cache 行中包含的数据与存储器中的数据不一致,而且它仅在本 CPU 的 Cache 中有效,不在其它 CPU 的 Cache 中存在副本,在这个 Cache 行中的数据是当前处理器系统中最新的数据副本。当 CPU 对这个 Cache 行进行替换操作时,必然会引发系统总线的写周期,将 Cache 行中数据与内存中的数据进行同步。
  • E(Exclusive)位。E 位为 1 时表示当前 Cache 行中包含的数据有效,而且该数据仅在当前 CPU 的 Cache 中有效,而不在其它 CPU 的 Cache 中存在副本。在该 Cache 行中的数据是当前处理器系统中最新的数据副本,而且与存储器中的数据一致。
  • S(Shared)位。S 位为 1 表示 Cache 行中包含的数据有效,而且在当前 CPU 和至少其它一个 CPU 中具有副本。在该 Cache 行中的数据是当前处理器系统中最新的数据副本,而且与存储器中的数据一致。
  • I(Invalid)位。I 位为 1 表示当前 Cache 行中没有有效数据或者该 Cache 行没有使能。MESI 协议在进行 Cache 行替换时,优先使用 I 位为 1 的 Cache 行。

在一个处理器系统中,主设备(CPU 或者外部设备)进行存储器访问时,将试图从存储器系统(主存储器或者其它 CPU 的 Cache)中获得最新的数据副本。如果该主设备访问的数据没有在本地命中时,将从其它 CPU 的 Cache 中获得数据,如果这些数据仍然没有在其它 CPU 的 Cache 中命中,主存储器将提供数据。外设设备进行存储器访问时,也需要进行 Cache 共享一致性。
在 MOESI (MESI 的变种)模型中,“Probe Read”表示主设备从其它 CPU 中获取数据的目的是为了读取数据;而“Probe Write”表示主设备从其它 CPU 中获取数据副本的目的是为了写入数据;“Read Hit”和“Write Hit”表示主设备在本地 Cache 中获得数据副本;“Read Miss”和“Write Miss”表示主设备没有在本地 Cache 中获得数据副本;“Probe Read Hit”和“Probe Write Hit”表示主设备在其它 CPU 的 Cache 中获得数据副本。
本节为简便起见,仅介绍 CPU 进行存储器写和与 O 状态相关的 Cache 行状态迁移。
当 CPU 对一段存储器进行写操作时,如果这些数据在本地 Cache 中命中时,其状态可能为 E、S、M 或者 O。

  • 状态为 E 或者 M 时,数据将直接写入到 Cache 中,并将状态改为 M。
  • 状态为 S 时,数据将直接写入到 Cache 中,并将状态改为 M,同时其它 CPU 保存该数据副本的 Cache 行状态将从 S 或者 O 迁移到 I(Probe Write Hit)。
  • 状态为 O 时,数据将直接写入到 Cache 中,并将状态改为 M,同时其它 CPU 保存该数据副本的 Cache 行状态将从 S 迁移到 I(Probe Write Hit)。

当 CPU A 对一段存储器进行写操作时,如果这些数据没有在本地 Cache 中命中,而在其它 CPU,如 CPU B 的 Cache 中命中时,其状态可能为 E、S、M 或者 O。其中 CPU A 使用 CPU B 在同意 Cache 共享域中。

  • Cache 行状态为 E 时,CPU B 将该 Cache 行状态改为 I;而 CPU A 将从本地申请一个新的 Cache 行,将数据写入,并该 Cache 行状态更新为 M。
  • Cache 行状态为 S 时,CPU B 将该 Cache 行状态改为 I,而且具有同样副本的其他 CPU 的 Cache 行也需要将状态改为 I;而 CPU A 将从本地申请一个 Cache 行,将数据写入,并该 Cache 行状态更新为 M。
  • Cache 行状态为 M 时,CPU B 将原 Cache 行中的数据回写到主存储器,并将该 Cache 行状态改为 I,具有同样数据副本的其他 CPU 的 Cache 行也需要将状态从 S 更改为 I;CPU A 将从本地申请一个 Cache 行,将数据写入,并该 Cache 行状态更新为 M。
    Cache 行状态可以从 M 迁移到 O。例如当 CPU A 读取的数据从 CPU B 中命中时,如果在 CPU B 中 Cache 行的状态为 M 时,将迁移到 O,同时 CPU B 将数据传送给 CPU A 新申请的 Cache 行中,而且 CPU A 的 Cache 行状态将被更改为 S。
  1. HIT# 和 HITM# 信号
    在 SMP 处理器系统中,每一个 CPU 都使用 HIT# 和 HITM# 信号反映 HOST 主桥访问的地址是否在各自的 Cache 中命中。当 HOST 主桥访问存储器时,CPU 将驱动 HIT# 和 HITM# 信号,其描述如下
    在这里插入图片描述
    HIT# 和 HITM# 信号是 FSB 中非常重要的两个信号,各个 CPU 的 HIT# 和 HITM# 信号通过“线与”方式直接相连。
PCI 设备对不可 Cache 的存储器空间进行 DMA 读写
  1. x86 处理器
    x86 处理器使用 MTRR(Memory Type Range Register)寄存器设置存储器空间的属性,如果存储器空间为“可 Cache 空间”,x86 处理器还可以进一步设置这段空间为“Write Through”、“Write Combining”、“Write Protect”和“Write Back”。但是这些设置与 PCI 设备进行 DMA 操作时,是否进行 Cache 一致性操作并没有直接关系。
    在 x86 处理器系统中,一个 PCI 设备进行 DMA 写操作,可以将数据从 PCI 设备写入到主存储器中。这个数据首先需要通过 HOST 主桥,然后经过 FSB 发送到存储器控制器。虽然在 x86 处理器系统中,CPU 知道这个存储器区域是否为“可 Cache 的”,但是 HOST 主桥并不知道 PCI 设备访问的存储器地址是否为“可 Cache 的”,因此都需要使用“Cache 一致”的 FSB 总线传送事务进行存储器写操作,从而数据在发向 FSB 时,CPU 必须要进行总线监听,通知 FSB 总线这段空间是“不可 Cache 的”。
    在 x86 处理器中,PCI 设备向不可 Cache 的存储器空间进行读操作时,CPU 也必须进行 Cache 共享一致性操作,而这种没有必要的 Cache 共享一致性操作将影响 PCI 总线的传送效率。当 PCI 设备所访问的存储器空间没有在 CPU 的 Cache 命中时,CPU 会通知 FSB,数据没有在 Cache 中命中,此时 PCI 设备访问的数据将从存储器中直接读出。
    在 x86 处理器系统中,无论 PCI 设备访问的存储器空间是否为“不可 Cache 的”,都需要进行 Cache 共享一致性操作。这也是 PCI 总线在 x86 处理器使用中的一个问题。而 PCIe 总线通过在数据报文中设置“Snooping”位解决了这个问题。
  2. PowerPC 处理器
    在 MPC8548 处理器中,HOST 主桥可以通过 PIW ARn 寄存器的 RTT 字段和 WTT 字段预知 PCI 设备访问的存储器空间是否为可 Cache 空间。当 HOST 主桥访问“不可 Cache 空间”时,可以使用 FSB 总线的“不进行 Cache 一致性”的总线事务。
    此时 PowerPC 处理器不会在 FSB 总线中进行 Cache 一致性操作,即忽略 FSB 总线事务的 Snoop Phase。PCI 设备进行 DMA 写时,数据将直接进入主存储器,而 PCI 设备进行 DMA 读时,所读取的数据直接从主存储器获得。PowerPC 处理器可以忽略 CPU 进行总线监听的动作,从而提高了 FSB 传送效率。
PCI 设备对可 Cache 的存储器空间进行 DMA 读写

如果访问的数据在 Cache 中命中,CPU 会通知 FSB 总线,PCI 设备所访问的数据在 Cache 中。
如果 Cache 行的状态为 E,Response Agent 将提供数据,而 CPU 不必改变 Cache 行状态。Snoopy Agent 可以直接将数据提供给 HOST 主桥,无疑数据访问的延时更短。

PCI 设备进行 DMA 写时发生 Cache 命中,如果命中的 Cache 行状态为 E,PCI 设备(通过 HOST 主桥)写入存储器的信息比 Cache 行中的数据新,而且 PCI 设备在进行 DMA 写操作之前,存储器域 Cache 中数据一致,此时 CPU 进需要在 Snoop Phase 使无效(Invalidate)这个 Cache 行,然后 FSB 总线事务将数据写入存储器即可。当然如果 FSB 总线事务可以将数据直接写入 Cache,并将 Cache 行的状态更改为 M,也可以提高 DMA 写的效率

预读机制

无论 Cache 的命中率有多高,总有发生 Cache 行 Miss 的情况,使用预读机制可以在一定程度上降低 Cache 行失效带来的影响。
预读机制包括指令预读、数据预读、外部设备的预读队列和操作系统提供的预读策略(prefetch函数?)。

指令预读

指令预读是指在 CPU 执行某段程序时,根据程序的执行情况,提前将指令从主存储器预读到指令 Cache 中,从而当 CPU 需要执行这段程序时,不需要从主存储器,而是从指令 Cache 中获取指令,从而极大缩短了 CPU 获取指令的延时。
在一段程序中,存在大量的分支预测指令,因而在某种程度上增加了指令预读的难度。

数据预读

数据预读是指在处理器进行运算时,提前通知存储器系统将运算过程中需要的数据准备好,而当处理器需要这些数据时,可以直接从 Cache 中获得这些数据。
但是在某些特殊情况下,采用预读机制有可能会降低效率。首先在一个较为复杂的应用中,很有可能预读的数据没有被充分利用,一个程序可能会按照不同的分支执行,而执行每一个分支所使用的数据并不相同。其次预读的数据即使是有效的,这些预读的数据也可能会污染整个 Cache 资源,在大规模并行任务的执行过程中,有可能引发 Cache 颠簸,从而极大地降低系统效率。
处理器提供了软件预读和硬件预读两种方式。
软件预读
软件预读指令都有一个共同的特点,就是在处理器真正需要数据之前,向存储器发出预读请求,这个预读请求不需要等待数据真正到达存储器之后,就可以执行完毕(预读指令在一个时钟周期内就可以执行完毕)。从而处理器可以继续执行其它指令,以实现存储器访问与处理器运算同步进行,从而提高了程序的整体执行效率。
在这里插入图片描述
这段源代码的作用是将 int 类型的数组 a 和数组 b 的每一项进行相乘,然后赋值给 ip。代码中并没有使用预读机制进行优化,因此这段程序在执行时会因为 a[i] 和 b[i] 中的数据不在处理器的 Cache 中,而必须启动存储器读操作。因此这段程序在执行过程中,必须等待存储器中的数据到达后才能继续,从而降低了程序的执行效率。为此将程序进行改动
在这里插入图片描述
以上程序对变量 ip 赋值之前,首先预读数组 a 和 b,当对变量 ip 赋值时,数组 a 和 b 中的数据已经在 Cache 中,因而不需要再次进行存储器操作,从而在一定程度上提高了代码的执行效率。
由以上程序可以发现,采用软件预读机制可以有效地对矩阵运算进行优化,因为矩阵运算进行数据访问时非常有规律,便于程序员或编译器进行优化,但是并不是所有程序都能如此方便地使用软件预读机制。此外预读指令本身也需要占用一个机器周期(还是指令周期?)。
硬件预读
采用硬件预读的优点是不需要软件进行干预,也不需要浪费一条预读指令来进行预读。大多数硬件预读仅支持存储器到 Cache 的预读,并在程序执行过程中,利用数据的局部性原理进行硬件预读。其中最简单的硬件预读机制是 OBL(One Block Lookahead)机制,采用这种机制,当程序对数据块 b 进行读取出现 Cache Miss 时,将数据块 b 从存储器更新到 Cache 中,同时对数据块 b + 1 也进行预读并将其放入 Cache 中;如果数据块 b + 1 已经在 Cache 中,则不进行预读。

PCI 总线的预读机制

在一个处理器系统中,预读的目标设备并不仅限于存储器,程序员还可以根据实际需要对外部设备进行预读。但并不是所有的外部设备都支持预读,只有“well-behavior”存储器支持预读。处理器使用的内部存储器,如基于 SDRAM、DDR-SDRAM 或者 SRAM 的主存储器是“well-behavior” 存储器,有些外部设备也是“well-behavior” 存储器。这些“well-behavior” 存储器具有以下特点。
(1)对这些存储器设备进行读操作时不会改变存储器的内容。显然主存储器具有这种性质。如果一个主存储器的一个数据为 0,那么读取这个数据 100 次也不会将这个结果变为 1。但是在外部设备中,一些使用存储器映像寻址的寄存器具有读清除的功能。比如某些中断状态寄存器。当设备含有未处理的中断请求时,该寄存器的中断状态为 1,对此寄存器进行读操作时,硬件将自动地把该中断位清零

(2)对“well-behavior” 存储器的多次读操作,可以合并为一次读操作。如向这个设备的地址 n、n + 4、n + 8、n + 12 地址处进行四个双字的读操作,可以合并为对 n 地址的一次突发读操作(大小为 4 个双字)。

PCIe 细节

PCIe 总线由若干层次组成,包括事务层、数据链路层和物理层。
PCIe 总线使用数据报文进行数据传递,这些数据报文需要通过 PCIe 总线的这些层次。PCIe 总线的这种数据传递方式与互联网使用 TCP/IP 协议进行数据传递有类似之处。
实际上,在互联网中存在的许多概念也存在于 PCIe 总线中,如交换、路由和仲裁机制等,不过两者实现上的最大不同在于前者主要使用软件程序实现其协议栈,而后者使用硬件逻辑实现。
半导体工艺的逐步提高,使得更多的软件算法可以使用硬件逻辑来实现,这给从事集成电路设计的工程师带来了巨大的挑战,因为他们使用 Verilog/VHDL 程序编写的算法,之前是使用 C 或 C++ 这样的高级语言实现的。
(C:send_byte(data), VHDL: clk、data)
PCIe 总线在系统软件级与 PCI 总线兼容,基于 PCI 总线的系统软件几乎可以不经修改直接移植到 PCIe 总线中。绝大多数 PCI/PCI-X 总线使用的总线事务都被 PCIe 总线保留,而 PCI 设备使用的配置空间也被 PCIe 总线继承。基于 PCI 体系结构的系统编程模型,几乎可以在没有本质变化的前提下,直接在 PCIe 体系结构中使用。
但是从体系系统的角度上看,PCIe 总线还是增加了一些新的特性,其中一些特性不仅是称呼上的变化,而且在功能上也得到了增强。如在 PCIe 体系结构中出现的 RC(Root Complex)。RC 的主要功能与 PCI 总线中的 HOST 主桥类似,但是在 HOST 主桥的基础上增加了许多功能。
在不同处理器系统中,RC 的实现方式不同,因此仅仅用 PCIe 总线控制器来称呼 RC 是不够的,实际上 PCIe 总线规范对 RC 并没有一个合适的解释。Intel 并没有使用 PCIe 总线控制器,而是使用 RC 管理 PCIe 总线。在 x86 处理器体系结构中,RC 并不仅仅管理 PCIe 设备的数据访问,而且还包含访问控制、错误处理和虚拟化技术等一系列内容。因此用 PCIe 总线控制器统称 RC,在 x86 处理器体系结构中并不合适。
虽然从系统软件的角度来看,PCI 总线与 PCIe 总线基本一致。但是从硬件设计的角度来看 PCIe 总线完全不同于 PCI 总线,基于 PCIe 总线各类设备的硬件设计难度远大于基于 PCI 总线的对应设备的设计难度。
PCI 总线使用并行总线结构,在同一条总线上的所有外部设备共享总线带宽,而 PCIe 总线使用了高速差分总线,并采用端到端的连接方式,因此在每一条 PCIe 链路中只能连接两个设备。这使得 PCIe 与 PCI 总线采用的拓扑结构有所不同。PCIe 总线除了在连接方式上与 PCI 总线不同之外,还使用了一些在网络通信中使用的技术,如支持多种数据路由方式,基于多通路的数据传递方式,基于报文的数据传送方式,并充分考虑了在数据传送中出现的服务质量QoS(Quality of Service)问题。

PCIe 总线的基础知识

PCIe 总线使用端到端的连接方式,在一条 PCIe 链路的两端只能各连接一个设备,这两个设备互为数据发送端和数据接收端。PCIe 总线除了总线链路外,还具有多个层次,发送端发送数据时将通过这些层次,而接收端接收数据时也使用这些层次。PCIe 总线使用的层次结构与网络协议栈较为类似。
PCIe 总线相当于网线,相当于物理层之下的第 0 层。

端到端的数据传递

PCIe 链路使用“端到端的数据传送方式”,发送端和接收端中都含有 TX(发送逻辑)和 RX(接收逻辑),其结构图如下
在这里插入图片描述
如上图所示,在 PCIe 总线的物理链路的一个数据通路(Lane)中,有两组差分信号,共 4 根信号线。其中发送端的 TX 部件与接收端的 RX 部件使用一组差分信号连接,该链路也被称为发送端的发送链路,也是接收端的接收链路;而发送端的 RX 部件与接收端的 TX 部件使用另一组差分信号连接,该链路称为发送端的接收链接,也是接收端的发送链路。
一个 PCIe 链路可以由多个 Lane 组成。
高速差分信号电气规范要求其发送端串接一个电容,以进行 AC 耦合。该电容也被称为 AC 耦合电容。PCIe 链路使用差分信号进行数据传送,一个差分信号由 D+ 和 D- 两根信号组成,信号接收端通过比较这两个信号的差值,判断发送端发送的是逻辑 “1” 还是逻辑 “0”。
在这里插入图片描述
与单端信号相比,差分信号抗干扰的能力更强,因为差分信号在布线时要求 “等长”、“等宽”、“贴近”,而且在同层。因此外部干扰噪声将被 “同值” 而且 “同时” 加载到 D+ 和 D- 两根信号上,其差值在理想情况下为 0,对信号的逻辑值产生的影响较小。因此差分信号可以使用更高的总线频率。
此外使用差分信号能有效抑制电磁干扰(EMI,Electro Magnetic Interference)。因为差分信号 D+ 与 D- 距离很近而且信号幅值相等、极性相反,这两根线与地线间耦合电磁场的幅值相等,将相互抵消,因此差分信号对外界的电磁干扰较小。当然差分信号的缺点也是显而易见的,一是差分信号使用两根信号传送一位数据;二是差分信号的布线相对严格一些。
PCIe 链路可以由多条 Lane 组成,目前 PCIe 链路可以支持 1、2、4、8、12、16 和 32 个 Lane,即 x1、x2、x4、x8、x12、x16 和 x32 宽度的 PCIe 链路。每一个 Lane 上使用的总线频率与 PCIe 总线使用的版本相关。

PCIe传输速率和有效带宽计算方式:
PCIe是串行总线,PCIe1.0的线上比特传输速率为2.5Gb/s,物理层使用8/10编码,即8比特的数据,实际在物理线路上是需要传输10比特的,因此:
PCIe1.0 x 1的带宽=(2.5Gb/s )/ 10bit =250MB/s
这是单条Lane的带宽,有几条Lane,那么整个带宽就是250MB乘以Lane的数目。
PCIe2.0的线上比特传输速率在PCIe1.0的基础上翻了一倍,为5Gb/s,物理层同样使用8/10编码,所以:
PCIe2.0 x 1的带宽=(5Gb/s )/ 10bit = 500MB/s

同样,有多少条Lane,带宽就是500MB/s乘以Lane的数目。
PCIe3.0的线上比特传输速率没有在PCIe2.0的基础上翻倍,不是10Gb/s,而是8Gb/s,但物理层使用的是128/130编码进行数据传输,所以:
PCIe3.0 x 1的带宽=(8Gb/s)/ 8bit = 1GB/s
同样,有多少条Lane,带宽就是1GB/s乘以Lane的数目。
由于采用了128/130编码,128比特的数据,只额外增加了2bit的开销,有效数据传输比率增大,虽然线上比特传输率没有翻倍,但有效数据带宽还是在PCIe2.0的基础上做到翻倍。
这里值得一提的是,上面算出的数据带宽已经考虑到8/10或者128/130编码,因此,大家在算带宽的时候,没有必要再考虑线上编码的问题了。
—— https://www.elecfans.com/d/2208020.html

PCIe 链路使用串行方式进行数据传送,然而在芯片内部,数据总线仍然是并行的,因此 PCIe 链路接口需要进行串并转换,这种串并转换将产生较大的延时。除此之外 PCIe 总线的数据报文需要经过事务层、链路层、物理层,这些数据报文在穿越这些层次时,也将带来延时。
在基于 PCIe 总线的设备中,x1 的 PCIe 链路最为常见。

PCIe 总线物理链路间的数据传递使用基于时钟的同步传送机制,但是在物理链路上并没有时钟线,PCIe 总线的接收端含有时钟恢复模块 CDR(Clock Data Recovery),CDR 将从接收报文中提取接收时钟,从而进行同步数据传递,PCIe 设备进行链路训练时将完成时钟的提取工作。

物理层发送数据所依据的 Tx 时钟必须随数据发送到接收方,以便接收方以此时钟为基准接收数据。但是,物理层并不将 Tx 时钟本身发送到传输线上(没有专门的时钟线),而是将之融入物理包的位流中,由接收方借助本地的锁相环(PLL)电路从接收位流中还原出这个时钟,作为数据接收时钟。
为此发送逻辑设置 8/10b 编码器,将乱序后的每个 8 位字符编码为 10 位,称为符号,也称为符号字节(Sbyte),目的是保证位流中 1 到 0 和 0 到 1 的跳变沿有足够的密度,使接收方 PLL 电路能够从接收位流中抽取出时钟。
由于将每个字节扩展为 10 位符号,在传输性能上会损失 25%。
10 位符号由并-串转换器转换为串行位流,即在各通路上对包进行串行化。串行位流送到电气物理层的差分发送器,将包差分发送到通路上。
8b/10b 编码的主要目的是将串行数据的位发送时钟嵌入到串行位流中,在链路上省去随数据一起发送的时钟信号线,还避免了 2.5GHz 的高频时钟信号产生的 EMI 噪声(liyongjun疑问:采用差分信号不是可以减弱 EMI 吗)。另外,没有了时钟线,也就不需要考虑时钟线与通路信号线布线长度的匹配问题,使两端口之间链路的布线工作容易得多。
优越性具体包括:
(1)嵌入时钟
(2)保证位流中不会含有多于 5 个的连续 1 或 0
(3)DC 平衡
(4)错误检测,即检查自链路初始化以来,被发送的 1 和 0 总数之间的差值是否接近 0
—— 《PCI、PCI-X 和 PCI Express 的原理及体系结构》

值得注意的是,在一个 PCIe 设备中除了需要从报文中提取时钟外,还使用了 REFCLK+ 和 REFCLK- 信号对作为本地参考时钟

PCIe 总线使用的信号

PCIe 设备使用两种电源信号供电,分别是 Vcc 与 Vaux,其额定电压为 3.3V。其中 Vcc 为主电源,PCIe 设备使用的主要逻辑模块均使用 Vcc 供电,而一些与电源管理相关的逻辑使用 Vaux 供电。
PCIe 链路的最大宽度为 x32,但在实际应用中,x32 的链路宽度极少使用。一般提供 x16 的 PCIe 插槽,并使用 16 对 PETxx 信号用于发送链路,另外 16 对 PERxx 信号用于接收链路。除此之外,PCIe 总线还使用了下列辅助信号。

  1. PERST# 信号
    该信号为全局复位信号,由处理器系统提供,处理器系统需要为 PCIe 插槽和 PCIe 设备提供该复位信号。
  2. REFCLK+ 和 REFCLK- 信号
    在一个处理器系统中,可能含有许多 PCIe 设备,这些设备可以作为 Add-In 卡与 PCIe 插槽连接,也可以作为内置模块,与处理器系统提供的 PCIe 链路直接相连,而不需要经过 PCIe 插槽。PCIe 设备与 PCIe 插槽都具有 REFCLK+ 和 REFCLK- 信号,其中 PCIe 插槽使用这组信号与处理器系统同步。
    在一个处理器系统中,通常采用专用逻辑向 PCIe 插槽提供 REFCLK+ 和 REFCLK- 信号,如下图所示,其中 100MHz 的时钟源由晶振提供,并经过一个 “一推多” 的差分时钟驱动器生成多个同相位的时钟源,与 PCIe 插槽一一对应连接。
    在这里插入图片描述
    PCIe 插槽需要使用参考时钟,其频率范围为 100MHz ± 300ppm,处理器系统需要为每一个 PCIe 插槽、MCH、ICH 和 Switch 提供参考时钟。
    当 PCIe 设备作为 Add-In 卡连接在 PCIe 插槽时,可以直接使用 PCIe 插槽提供的 REFCLK+ 和 REFCLK- 信号,也可以使用独立的参考时钟,只要这个参考时钟在 100MHz ± 300ppm 范围内即可。内置的 PCIe 设备与 Add-In 卡在处理 REFCLK+ 和 REFCLK- 信号时使用的方法类似,但是 PCIe 设备可以使用独立的参考时钟,而不使用 REFCLK+ 和 REFCLK- 信号。
    在一个处理器系统中,如果使用 PCIe 链路进行机箱到机箱间的互连,因为参考时钟可以异步设置,机箱到机箱之间进行数据传送时仅需要差分信号线即可,而不需要参考时钟,从而极大地降低了连接难度。
  3. WAKE# 信号
    当 PCIe 设备进入休眠状态,主电源已经停止供电时,PCIe 设备使用该信号向处理器系统提交唤醒请求,使处理器系统重新为该 PCIe 设备提供主电源 Vcc。WAKE# 信号是可选的。
    WAKE# 是一个 Open Drain 信号,一个处理器的所有 PCIe 设备可以将 WAKE# 信号进行线与后,统一发送给处理器系统的电源控制器。当某个 PCIe 设备需要被唤醒时,该设备首先置 WAKE# 信号为有效,然后在经过一段延时之后,处理器系统开始为该设备提供主电源 Vcc,并使用 PERST# 信号对该设备进行复位操作(liyongjun疑问:驱动需要重新加载吗?)。此时 WAKE# 信号需要始终保存低,当主电源 Vcc 上电完成之后,PERST# 信号也将置为无效并结束复位,WAKE# 信号也将随之置为无效,结束整个唤醒过程。
  4. JTAG 信号
    JTAG(Joint Test Action Group)是一种国际标准测试协议,主要用于芯片内部测试。目前绝大多数器件都支持 JTAG 测试标准。
    JTAG 信号由 TRST#、TCK、TDI、TDO 和 TMS 信号组成。其中 TRST# 为复位信号;TCK 为时钟信号;TDI 和 TDO 分别与数据输入和数据输出对应;而 TMS 信号为模式选择。
    JTAG 允许多个器件通过 JTAG 接口串联在一起,并形成一个 JTAG 链。目前 FPGA 和 EPLD 可以借用 JTAG 接口实现在线编程(In-System Programming, ISP)功能。处理器也可以使用 JTAG 接口进行系统级调试,如设置断点、读取内部寄存器和存储器等一系列操作。除此之外 JTAG 接口也可以用作 “逆向工程”,分析一个产品的实现细节,因此在正式产品中,一般不保留 JTAG 接口。
  5. PRSNT1# 和 PRSNT2# 信号
    PRSNT1# 和 PRSNT2# 信号与 PCIe 设备的热拔插相关。
    当 Add-In 卡没有插入时,处理器主板的 PRSNT2# 信号由上拉电阻接为高,而当 Add-In 卡插入时,主板的 PRSNT2# 信号与 PRSNT1# 信号通过 Add-In 卡连通,此时 PRSNT2# 信号为低。处理器主板的热插拔控制逻辑将捕获这个 “低电平”,得知 Add-In 卡已插入,从而触发系统软件进行相应处理。
    值得注意的是,在实现热拔插功能时,Add-In 卡需要使用 “长短针” 结构。
PCIe 总线的层次结构

PCIe 总线采用串行连接方式,并使用数据包(Packet)进行数据传输,采用这种结构有效去除了在 PCI 总线中存在的一些边带信号,如 INTx 和 PME# 等信号。
在 PCIe 总线中,数据报文在接收和发送过程中,需要通过多个层次,包括事务层、数据链路层和物理层。PCIe 总线的层次结构如下图所示
在这里插入图片描述
PCIe 总线的层次组成结构与网络中的层次结构有类似之处,但是 PCIe 总线的各个层次都是使用硬件逻辑实现的。在 PCIe 体系结构中,数据报文首先在设备的核心层(Device Core)中产生,然后再经过该设备的事务层(Transaction Layer)、数据链路层(Data Link Layer)和物理层(Physical Layer),最终发送出去。而接收端的数据也需要通过物理层、数据链路层和事务层,并最终到达核心层。

  1. 事务层
    事务层定义了 PCIe 总线使用总线事务,其中多数总线事务与 PCI 总线兼容。这些总线事务可以通过 Switch 等设备传送到其它 PCIe 设备或者 RC。
    事务层接收来自 PCIe 设备核心层的数据,并将其封装为 TLP(Transaction Layer Packet)后,发向数据链路层。此外事务层还可以从数据链路层中接收数据报文,然后转发至 PCIe 设备的核心层。
  2. 数据链路层
    数据链路层保证来自发送端事务层的报文可以可靠、完整地发送到接收端的数据链路层。
    来自事务层的报文在通过数据链路层时,将被添加 Sequence Number 前缀和 CRC 后缀。数据链路层使用 ACK/NAK 协议保证报文的可靠传递。
  3. 物理层
    物理层时 PCIe 总线的最底层,将 PCIe 设备连接在一起。PCIe 总线的物理电气特性决定了 PCIe 链路只能使用端到端的连接方式。PCIe 总线的物理层为 PCIe 设备间的数据通信提供传送介质,为数据传递提供可靠的物理环境。
    物理层是 PCIe 体系结构中最重要,也是最难实现的部分。PCIe 总线的物理层定义了 LTSSM(Link Training and Status State Machine)状态机,PCIe 链路使用该状态机管理链路状态,并进行链路训练、链路恢复和电源管理。
    对于系统软件而言,物理层几乎不可见,但是系统程序员仍有必要较为深入地理解物理层的工作原理。
PCIe 链路的扩展

PCIe 链路使用端到端的数据传送方式。在一条 PCIe 链路中,这两个端口是完全对等的,而且一个 PCIe 链路的一端只能连接一个设备。因此 PCIe 链路必须使用 Switch 扩展 PCIe 链路后,才能连接多个设备。使用 Switch 进行链路扩展的实例如下图所示
在这里插入图片描述
在 PCIe 总线中,Switch 是一个特殊的设备,该设备由 1 个上游端口和 2~n 个下游端口组成。PCIe 总线规定,在一个 Switch 中可以与 RC 直接或间接相连的端口为上游端口,在 PCIe 总线中,RC 的位置一般在上方,这也是上游端口这个称呼的由来。在 Switch 中,除了上游端口外,其它所有端口都被称为下游端口。下游端口一般与 EP 相连,或者连接下一级 Switch 继续扩展 PCIe 链路。其中与上游端口相连的 PCIe 链路被称为上游链路,与下游端口相连的 PCIe 链路被称为下游链路。
上游链路和下游链路是相对的概念。如上图,Switch 与 EP2 连接的 PCIe 链路,对于 EP2 而言是上游链路,而对于 Switch 而言是下游链路。
图中,Switch 中含有 3 个端口,其中一个是上游端口(Upstream Port),而其它两个为下游端口(Downstream Port)。其中,上游端口与 RC 或者其它 Switch 的下游端口相连,而下游端口与 EP 或者其它 Switch 的上游端口相连。
在 Switch 中,还有两个与端口相关的概念,分别是 Egress 端口和 Ingress 端口。这两个端口与通过 Switch 的数据流向有关。其中 Egress 端口指发送端口,即数据离开 Switch 使用的端口;Ingress 端口指接收端口,即数据进入 Switch 使用的端口。Egress 端口和 Ingress 端口与上下游端口没有对应关系。

PCIe 体系结构的组成部件

PCIe 总线作为处理器系统的局部总线,主要目的是连接外部设备。使用 RC、Switch、PCIe-toPCI 桥这些基本模块连接 PCIe 和 PCI 设备。
在 PCIe 总线中,基于 PCIe 总线的设备,也称为 EP(EndPoint)。
在这里插入图片描述
在上图结构中,RC 由两个 FSB-to-PCIe 桥和存储器控制器组成。
虚拟 PCI 桥的作用只是分离存储器域与 PCI 总线域,并不会改变信号的电气特性。RC 与处理器通过 FSB 连接。
在 PCI 总线 0 上有一个存储器控制器和两个 FSB-to-PCIe 桥。这两个 FSB-to-PCIe 桥分别推出一个 x16 和 x8 的 PCIe 链路,其中 x16 的 PCIe 链路连接显卡控制器(GFX),其编号为 PCI 总线 1;x8 的 PCIe 链路连接一个 Switch 进行 PCIe 链路扩展。而存储器控制器作为 PCI 总线 0 的一个 Agent 设备,连接 DDR 插槽或者颗粒。
Switch 可以将 1 个 x8 的 PCIe 端口扩展为 4 个 x2 的 PCIe 端口,其中每一个 PCIe 端口都可以挂接 EP。

PCIe 体系结构的组成部件

基于 PCIe 总线的通用处理器结构

在不同的处理器系统中,RC 的实现有较大差异。PCIe 总线规范并没有规定 RC 的实现细则。在有些处理器系统中,RC 相当于 PCIe 主桥,也有的处理器系统也将 PCIe 主桥成为 PCIe 总线控制器。而在 x86 处理器系统中,RC 除了包含 PCIe 总线控制器之外,还包含一些其它组成部件。
如果一个 RC 中可以提供多个 PCIe 端口,这种 RC 也被称为多端口 RC。如 MPC8572 处理器的 RC 可以直接提供 3 条 PCIe 链路,因此可以直接连接 3 个 EP。
在这里插入图片描述

RC 的组成结构

RC 是 PCIe 体系结构的一个重要组成部件,也是一个较为混乱的概念。在上图中,RC 包括存储器控制器、两个 FSB-to-PCIe 桥。
如果将 RC 中的其它功能忽略,RC 的主要功能与 PCI 总线中的 HOST 主桥类似,其主要作用是完成存储器域到 PCI 总线域的地址转换。
但是 RC 与 HOST 主桥并不相同,RC 除了完成地址空间的转换之外,还需要完成物理信号的转换。在 PowerPC 处理器的 RC 中,来自 OCeaN 或者 FSB 的信号协议与 PCIe 总线信号使用的电气特性并不兼容,使用的总线事务也并不相同,因此必须进行信号协议和总线事务的转换。

Switch

从系统软件的角度上看,每一个 PCIe 链路都占用一个 PCI 总线号,但是一条 PCIe 链路只能连接一个 PCI 设备、Switch、EP 或者 PCIe 桥片。
一个 PCIe 链路需要挂接多个 EP 时,需要使用 Switch 进行链路扩展。
在 PCIe 体系结构中,Swicth 的设计难度仅次于 RC,Switch 也是 PCIe 体系结构的核心所在。从系统软件的角度上看,Switch 内部由多个 PCI-to-PCI 桥组成,其中每一个上游和下游端口都对应一个虚拟 PCI 桥。在一个 Switch 中,有多少个端口,在其内部就有多少个虚拟 PCI 桥,就有多少个 PCI 桥配置空间。值得注意的是,在 Switch 内部,还具有一条虚拟的 PCI 总线,用于连接各个虚拟 PCI 桥。系统软件在初始化 Switch 时,需要为这条虚拟 PCI 总线编号。
在这里插入图片描述
PCIe 总线中的 Switch 与网络中的 Switch 功能并不相同,而与网络中的 Route 功能接近。
Switch 需要处理 PCIe 总线传输过程中的 QoS 问题。PCIe 总线的 QoS 要求 PCIe 总线区别对待优先权不同的数据报文,无论 PCIe 总线的某一个链路多么拥塞,优先级高的报文都可以获得额定的数据带宽。PCIe 总线需要保证优先级较高的报文优先到达。PCIe 总线采用虚拟多通路 VC 技术,并在这些数据报文中设定一个 TC(Traffic Class)标签,该标签由 3 位组成,将数据报文根据优先权分为 8 类,这 8 类数据报文可以根据需要选择不同的 VC 进行传递。
在 PCIe 总线中,每一条数据链路上最多可以支持 8 个独立的 VC。每个 VC 可以设置独立的缓冲,用来接收和发送数据报文。在 PCIe 体系结构中,TC 和 VC 紧密相连,TC 与 VC 之间的关系是 “多对一”。
TC 可以由软件设置,系统软件可以选择某类 TC 由哪个 VC 进行传递。其中一个 VC 可以传递 TC 不相同的数据报文,而 TC 相同的数据报文在指定一个 VC 传递之后,不能再使用其它 VC。
在许多处理器系统中,Switch 和 RC 仅支持一个 VC。
下面以一个简单的例子说明如何使用 TC 标签和多个 VC,以保证数据传送的服务质量。
将 PCIe 总线的端到端数据传递过程模拟为使用汽车将一批货物从 A 点运送到 B 点。如果不考虑服务质量,可以使用一辆汽车运送所有这些货物,经过多次往返就可以将所有货物从 A 点运到 B 点。但是这样做会耽误一些需要在指定时间内到达 B 点的货物。有些货物,如急救物资、EMS 等其它优先级较高的货物,必须及时从 A 运送到 B。这些急救物资的运送应该有别于其它普通物资的运送。
为此首先将不同种类的货物进行分类,将急救物资定义为 TC3 类货物,EMS 定义为 TC2 类货物,平信定义为 TC1 类货物,一般包裹定义为 TC0 类货物,我们最多可以提供 8 种 TC 类标签进行货物分类。
之后使用 8 辆汽车,分别是 VC0~VC7 运送这些货物,其中 VC7 的速度最快,VC0 的速度最慢。当发生堵车事件时,VC7 优先行驶,VC0 最后行驶。然后使用 VC3 运送急救物资,VC2 运送 EMS,VC1 运送平信,VC0 运送普通包裹。当然使用 VC0 哦挺尸运送平信和普通包裹也是可以的,但是平信或者普通包裹不能会用一种以上的汽车运送,如平信如果使用了 VC1 运输,就不能使用 VC0。因为 TC 与 VC 的对应关系是 “多对一” 的关系。
采用这种分类运输的方法,可以做到在 A 点到 B 点带宽有限的情况下,仍然可以保证急救物资和 EMS 可以及时到达 B 点,从而提高了服务质量。

VC 和端口仲裁

在 Switch 中存在多个端口,其中来自不同 Ingress 端口的报文可以发向同一个 Egress 端口,因此 Switch 必须要解决端口仲裁和路由选径的问题。所谓端口仲裁指来自不同 Ingress 端口的报文到达同一个 Egress 端口,报文的通过顺序。
在这里插入图片描述
在一个 Switch 中设有仲裁器,该仲裁器规定了数据报文通过 Switch 的规则。在 PCIe 总线中存在两种仲裁机制,分别是基于 VC 和基于端口的仲裁机制。端口仲裁机制主要针对 RC 和 Switch,当多个 Ingress 端口需要向同一个 Egress 端口发送数据报文时需要进行端口仲裁。具体地讲,在 PCIe 体系结构中有三个端口,需要进行端口仲裁。

  • Switch 的 Egress 端口。当 EP A 和 EP B 同时访问 EP C,D 或者 DDR-SDRAM 时,需要通过 Switch 的 Egress 端口 C。此时 Switch 需要进行端口仲裁确定是 EP A 的数据报文还是 EP B 的数据报文优先通过 Egress 端口 C。
  • 多端口 RC 的 Egress 端口。当 RC 的端口 1 和端口 3 同时访问 EP C 时,RC 的端口 2 需要进行端口仲裁,决定来自 RC 哪个端口的数据可以率先通过。
  • RC 通往主存储器的端口。当 RC 的端口 1、端口 2 和端口 3 同时访问 DDR 控制器时,这些数据报文将通过 RC 的 Egress 端口 4,此时需要进行端口仲裁。

PCIe 设备的扩展配置空间

PCI 设备使用基本配置空间,这个基本配置空间由 64 个字节组成,其地址范围为 0x00~0x3F,这 64 个字节是所有 PCI 设备必须支持的,事实上,许多 PCI 设备也仅支持这 64 个配置寄存器。
此外 PCI/PCI-X 和 PCIe 设备还扩展了 0x40~0xFF 这段配置空间,在这段空间主要存放一些与 MSI 或者 MSI-X 中断机制和电源管理相关的 Capability 结构。其中所有能够提交中断请求的 PCIe 设备,必须支持 MSI 或者 MSI-X Capability 结构。

PCIe 总线的事务层

事务层是 PCIe 总线层次结构的最高层,该层次将接收 PCIe 设备核心层的数据请求,并将其转换为 PCIe 总线事务,PCIe 总线使用的这些总线事务在 TLP 头中定义。
PCIe 总线继承了 PCI/PCI-X 总线的大多数总线事务,如存储器读写、I/O 读写、配置读写总线事务,并增加了 Message 总线事务和原子操作等总线事务。
在 PCIe 总线中,不同的总线事务采用的路由方式不同。PCIe 总线继承了 PCI 总线的地址路由和 ID 路由方式,并添加了 “隐式路由” 方式。
PCIe 总线使用的数据报文首先在事务层中形成,这个数据报文也被称为事务层数据报文,即 TLP。TLP 在经过数据链路层时被加上 Sequence Number 前缀和 CRC 后缀,然后发向物理层。

TLP 格式

在这里插入图片描述
一个完整的 TLP 由 1 个或者多个 TLP Prefix、TLP Head、Data Payload(数据有效负载)和 TLP Digest 组成。TLP 头是 TLP 最重要的标志,不同的 TLP 其头的定义并不相同。TLP 头包含了当前 TLP 的总线事务类型、路由信息等一系列信息。在一个 TLP 中,Data Payload 的长度可变,最小为 0,最大为 1024 DW。
TLP Digest 是一个可选项,一个 TLP 是否需要 TLP Digest 由 TLP Head 决定。
在这里插入图片描述
TLP Head 由 3 个或者 4 个双字(DW)组成。其中第一个双字中保存通用 TLP 头,其它字段与通用 TLP 头的 Type 字段相关。一个通用 TLP 头由 Fmt、Type、TC、Length 等字段组成。
如果存储器读写 TLP 支持 64 位地址模式时,TLP 头的长度为 4DW,否则为 3DW。

Fmt 和 Type 字段确认当前 TLP 使用的总线事务,TLP 头的大小是由 3 个双字还是 4 个双字组成,当前 TLP 是否包含有效负载。具体如下表
在这里插入图片描述
其中,所有读请求 TLP 都不带数据,而写请求 TLP 带数据,而其它 TLP 可能带数据也可能不带数据,如完成报文可能含有数据,也可能仅含有完成标志而并不携带数据。
在 TLP 的 Type 字段中存放 TLP 的类型,即 PCIe 总线支持的总线事务。该字段共由 5 位组成,其含义如下
在这里插入图片描述
存储器读和写请求,IO 读和写请求,以及配置读和写请求,它们的 type 字段值相等,如存储器读和写请求的 Type 字段都为 0b00000。此时 PCIe 总线规范用 Fmt 字段区分读写请求,当 Fmt 字段是 “带数据” 的报文,一定是 “写报文”;当 Fmt 字段是 “不带数据” 的报文,一定是 “读报文”。
PCIe 总线的数据报文传送方式与 PCI 总线数据传送有类似之处。其中存储器写 TLP 使用 Posted 方式进行传送,而其它总线事务使用 Non-Posted 方式。
当 PCIe 设备进行存储器读、I/O 读写或者配置读写请求时,首先向目标设备发送数据读写请求 TLP,当目标设备收到这些读写请求 TLP 后,将数据和完成信息通过完成报文(Cpl 或者 CplD)发送给源设备。
其中存储器读、I/O 读和配置读需要使用 CplD 报文,因为目标设备需要将数据传递给源设备;而 I/O 写和配置写需要使用 Cpl 报文,因为目标设备不需要将任何数据传递给源设备,但是需要通知源设备,写操作已经完成,数据已经成功地传递给目标设备。
在 PCIe 总线中,进行存储器或者 I/O 写操作时,数据与数据包头一起传递;而进行存储器或者 I/O 读操作时,源设备首先向目标设备发送读请求 TLP,而目标设备在准备好数据后,向源设备发出完成报文。
与 PCI 总线不同,PCIe 总线规范定义了 Msg 报文,即消息报文,分别为 Msg 和 MsgD。这两种报文的区别在于一个报文可以传递数据,一个不能传递数据。
当一个 PCIe 设备对存储器进行 DMA 读操作时,如果传送的数据非常大,比如 512MB,Cache 的一致性操作不但不会提高 DMA 写的效率,反而会降低。因为这个 DMA 读访问的数据在绝大多数情况下,并不会在 Cache 中命中,但是 FSB 依然需要使用 Snoop Phase 进行总线监听。而处理器在进行 Cache 一致性操作时仍然需要占用一定的时钟周期,即在 Snoop Phase 中占用的时钟周期。
对于这类情况,一个较好的做法是,首先使用软件指令保证 Cache 与主存储器的一致性,并置 “No Snoop Attributte” 位为 1,然后再进行 DMA 读操作。同理使用这种方法对一段较大的数据区域进行 DMA 写时,也可以提高效率。(liyongjun:结合WiFi Tx Rx 仔细研究一下)
除此之外,当 PCIe 设备访问的存储器,不是 “可 Cache 空间” 时,也可以通过设置 “No Snoop Attribute” 位,避免 FSB 的 Cache 共享一致性操作,从而提高 FSB 的效率。“No Snoop Attribute” 位是 PCIe 总线针对 PCI 总线的不足做出的重要改动。
Length 字段用来描述 TLP 的有效负载(Data Payload)大小。TLP 的 Data Payload 大小在 1B ~ 4096B 之间
当 PCI 设备进行 DMA 写操作,将 PCI 设备中 4KB 大小的数据传送到主存储器时,这个 PCI 设备的 DMA 控制器将存放传送的目的地址和传送大小,然后启动 DMA 写操作,将数据写入到主存储器。由于 PCI 总线是一条共享总线,因此传送 4 KB 大小的数据,可能会使用若干个 PCI 总线写事务才能完成,而每一个 PCI 总线写事务都不知道 DMA 控制器何时才能将数据传送完毕。
如果这些总线写事务还通过一系列 PCI 桥才能到达存储器,在这个路径上的每一个 PCI 桥也无法预知这个 DMA 操作何时才能结束,那么这种 “不可预知” 将导致 PCI 总线的带宽不能被充分利用,而且极易做成 PCI 桥数据缓冲的浪费。
而 PCIe 总线通过 TLP 的 Length 字段,可以有效避免 PCIe 链路带宽的浪费。值得注意的是,Length 字段以 DW 为单位,其最小单位为 1 个 DW。如果 PCIe 主设备传送的单位小于 1 个 DW 或者传送的数据并不以 DW 对齐时,需要使用字节使能字段,即 “DW BE” 字段。

TLP 的路由

TLP 的路由是指 TLP 通过 Switch 或者 PCIe 桥片时采用哪条路径,最终到达 EP 或者 RC 的方法。
PCIe 总线一共定义了三种路由方法,分别是基于地址(Address)的路由,基于 ID 的路由和隐式路由(Implicit)方式。
存储器和 I/O 读写请求 TLP 使用基于地址的路由方式,这种方式使用 TLP 中的 Address 字段进行路由选径,最终到达目的地。
而配置读写报文、Cpl 和 CplD 报文使用基于 ID 的路由方式,这种方式使用 PCI 总线号进行路由选径。
而隐式路由方式主要用于 Message 报文的传递。在 PCIe 总线中定义了一系列消息报文,包括 “INTx Interrupt Signaling”、“Power Management Messages” 和 “Error Signal Messages” 等报文。隐式路由方式是指从下游端口到上游端口进行数据传递使用的路由方式,或用于 RC 向 EP 发出广播报文。

基于地址的路由

在 PCIe 总线中,存储器读写和 I/O 读写 TLP 使用基于地址的路由方式。PCIe 设备使用的地址路由方式与 PCI 设备使用的地址路由方式类似(通过判断配置空间中能够接收的地址范围)。只是 PCIe 设备使用 TLP 进行数据传送,而 PCI 设备使用总线周期进行数据传送。
在这里插入图片描述
上图中的配置寄存器描述了该虚拟 PCI-to-PCI 桥下游 PCI 子树使用的三组空间范围,分别为 I/O、存储器和可预取的存储器空间,分别用 Base 和 Limit 两类寄存器描述。TLP 使用基于地址的路由时,一定要通过查询这组寄存器之后,再决定传送路径。
在这里插入图片描述
TLP1 是一个存储器或者 I/O 请求 TLP,由 RC 发出,并通过一个 Switch 发向 EP1。存储器和 I/O 读写请求 TLP 使用这种地址路由方式。TLP1 将从 Switch 的上游端口传送到下游端口。具体过程如下:
当 TLP1 从 RC 发向 EP1 时,这个 TLP1 为 I/O 或者存储器报文,其中 TLP1 目的地址在 EP1 的 BAR 空间中。当处理器访问 EP 的 BAR 空间时,需要使用该类 TLP。值得注意的是,这个数据报文在通过 RC 时需要进行地址转换。
TLP1 首先通过 PCI Bus0 发向 Switch,并通过 Switch 的 Upstream 端口到达 P-PI 桥片,P-PI 桥片首先根据配置寄存器中的 Base 和 Limit 寄存器决定是否接收 TLP1。如果 Switch 不接收 TLP1,则将该 TLP 作为不支持的请求处理,此时如果 TLP1 需要回应报文,Switch 将发出完成报文,该报文的状态为 Unsupported Request。
如果 Switch 接收 TLP1,则表示 TLP1 所访问的地址在该 Switch 下游端口所连接的 EP 或者 Switch 中,此时 Switch 将 TLP1 从 PCI Bus0 推至 PCI Bus1 中,即穿越 P-PI 桥片。TLP1 到达 PCI Bus1 后将同时查找 P-P2 和 P-P3 桥片配置寄存器中的 Base 和 Limit 寄存器,决定是 P-P2 还是 P-P3 桥片接收 TLP1。本示例中将使用 P-P2 桥片接收 TLP1,并将 TLP1 推至 PCI Bus 2,而 PCI Bus2 上的 EP1 将接收 TLP1,完成整个地址路由。

基于 ID 的路由

在 PCIe 总线中,基于ID 的路由方式主要用于配置读写请求 TLP、Cpl 和 CplD 报文。
(liyongjun:想想也是,读写配置空间,肯定使用 ID 路由方式比较好,因为 BAR 空间有可能还未初始化,想使用地址路由也无法使用)
基于 ID 路由的 TLP,使用 Bus Nuber、Device Number、Function Number 进行路由寻址。

隐式路由

在这里插入图片描述
使用隐式路由方式的 TLP,其 Route 字段为 “000”,“011”,“100” 或者 “101”。

如果 Switch 的上游端口接收了一条来自 RC 的广播消息,则将该报文发向所有的下游端口;如果 Switch 的下游端口接收了一条发向 RC 的消息报文时,Switch 将此报文直接转发到上游端口,直至 RC。

消息请求报文

在 PCIe 总线中,多数消息报文使用隐式路由方式,其中 Byte 0 字段为通用 TLP 头,而 Byte 4 的第 3 字节中存放 Message Code 字段。
PCIe 总线规定了以下几类消息报文

  • INTx 中断消息报文(INTx Interrupt Signaling)
  • 电源管理消息报文
  • 错误消息报文
  • 锁定事务消息报文
  • 插槽电源限制消息报文
  • Vendor-Defined Messages
INTx 中断消息报文

在 PCIe 总线中,PCIe 设备可以使用 legacy 中断方式提交中断请求,此时需要使用 INTx 中断消息报文向 RC 通知中断事件。
例如,在 PCIe 桥片上挂接的 PCI 设备可能并不支持 MSI 中断机制,因此需要使用 INTx 中断信号提交中断请求,此时 PCIe 桥需要将 INTx 信号转换为 INTx 中断消息报文(liyongjun:MT7916),并向 RC 提交中断请求。
在 PCIe 总线中,共有 8 种 INTx 中断消息报文
在这里插入图片描述

PCIe 总线的数据链路层与物理层

与事务层不同,数据链路层主要处理端到端的数据传送。在事务层中,源设备与目标设备间的传送距离较长,设备之间可能经过若干级 Switch;而在数据链路层中,源设备与目标设备在一条 PCIe 链路的两端(liyongjun:醍醐灌顶,类比于网络协议)(liyongjun:数据链路层,关键字:相邻)。
物理层是 PCIe 总线的最底层,也是 PCIe 总线体系结构的核心。在物理层中涉及许多与差分信号传递有关的模拟电路知识。

物理层简介

物理层主要由物理层逻辑模块和物理层电气模块组成,逻辑模块包括 8/10b 编码、链路训练等一些基础的内容,物理层包括差分信号的处理。
物理层的电气模块与差分信号的工作原理密切相关,这部分原理包括一系列与信号完整性相关的课题,信号完整性所追求的目标如下

  • 保证发送的信号可以被接收端正确接收
  • 保证发送的信号不会影响其它信号
  • 保证发送的信号不会损坏接收器件
  • 保证发送的信号不会产生较大的 EMI 电磁噪声。
PCIe 链路的差分信号

所有信号的传递都需要一个电流回路,流入一个节点的电流总和等于流出这个节点的电流总和。单端信号使用地平面作为电流回路,而这个地平面并不是稳定的,极易收到干扰。减缓噪声的有效方法是为器件的电源提供退耦电容,在电路设计中,该方法极为普及。
即便如此,单端信号使用的地平面仍不足以信赖,仍会给单端信号的传递带来不小的干扰。
其次,单端信号容易受到其它信号的干扰,当单端信号频率较高时,信号在传递过程中衰减较大,而采用差分信号可以有效避免使用单端信号的这些问题。
差分信号对要求等长且平行走线,而且在实际的 PCB 中,最好做到同层等长,因为不同层间的特性阻抗并不完全相等,有一定误差。

PCIe 总线的链路训练与电源管理

PCIe 总线进行链路训练时将初始化 PCIe 设备的物理层、发送接收模块和相关的链路状态信息,当链路训练成功结束后,PCIe 链路两端的设备可以进行正常的数据交换。
链路训练的过程由硬件逻辑完成,无需系统软件的参与。
PCIe 总线进行链路训练的主要目的是初始化 PCIe 链路的物理层、端口配置信息、相应的链路状态,并了解链路对端的拓扑结构,以便 PCIe 链路两端的设备进行数据通信。
一条 PCIe 总线提供的链路带宽可以是 x1、x2、x4、x8、x12 或者 x16,但是在这个 PCIe 链路上所挂接的 PCIe 设备并不会完全使用这些链路。如一个 x4 的 PCIe 设备可能会连接到 x16 的 PCIe 链路上。此时该 PCIe 设备在进行链路训练时,必须通知对端链路该设备实际使用的链路状态。
PCIe 链路两端的设备所使用的 Lane 可以错序连接,称之为 “Lane Reversal”。
并且,在相同的 Lane 上,差分信号的极性也可以错序连接,称之为 “Polarity Inversion”
在这里插入图片描述
PCIe 总线提供这些连接方式的主要目的是为了方便 PCB 走线,因为差分信号要求在 PCB 中等长而且等距。在一个系统中,存在多路差分信号时,PCB 布线较为困难。使用上述两个功能,便于 PCB Layout 工程师根据实际情况为差分信号选择更为合理的走线路径,从而降低 PCB 的层数。
PCIe 链路进行链路训练时,需要了解 PCIe 链路两端的连接拓扑结构。一条 PCI 链路可能使用多个 Lane 进行数据交换,而数据报文经过不同 Lane 的延时并不完全相同。PCIe 总线进行链路训练时,需要处理这些不同 Lane 的延时差异,并进行补偿。
PCIe 总线在链路训练过程中,还需要确定数据传送速率。

流量控制

流量控制(Flow Control)的概念起源于网络通信。
从数据传输的角度来看,整个网络中具有两类资源,一类是数据通路,另一类是数据缓冲。
在网络节点中含有缓冲区,暂存在这个节点中没有处理完毕的报文。
最初在网络设备中只为一条链路提供了一个缓冲区,如下图所示
在这里插入图片描述
数据报文 B 在经过 Node3 时发现由于 Node3 正在向 Node 4 发送一个数据报文 A。从而数据报文 B 到达 Node 3 后,由于 Node 4 的接收缓冲被数据报文 A 占用,而无法继续传递。
此时虽然在整个数据通路中,Node 4 和 Node 5 之间的通路是空闲的,但是报文 B 还是无法通过 Node 3 和 4,因为在 Node 4 中只有一个数据缓冲,而这个数据缓冲正在被报文 A 使用。
为了解决这个问题,在现代网络节点中设置了多个虚通路 VC,不同的数据报文可以使用不同的通路进行传递。从而有效解决了单数据通路带来的问题,基于多通路的数据传递如下图所示
在这里插入图片描述
所谓多通路就是指每一个节点内设置两个以上的缓冲
报文 A 经过 Node 1~5 时使用缓冲 2 进行缓存,然后进行数据传递,而报文 B 使用缓存 1 进行缓存。因此虽然报文 A 因为某种原因不能继续传递,也只是将报文阻塞在缓冲 2 中,而不影响报文 B 的数据传递。
所谓 VC 是指缓冲到缓冲之间的传递通路。如上图例子中含有两个 VC,分别是 VC1 和 VC2。其中 VC 1 对应节点间缓冲 1 到缓冲 1 的数据传递,而 VC2 对应缓冲 2 到缓冲 2 的数据传递。VC 间的数据传递,如 Node 1 的缓冲 1、2 到 Node 2 的缓冲 1、2,都要使用实际的物理链路 “链路 1”,这也是将 VC 称为 “虚” 通路的主要原因

假设报文 A 和 B 属于相同种类的报文,并且适用不同的 VC 传递,Node 4 已经阻塞了报文 A,阻塞报文 A 的原因在很大概率上也会对报文 B 适用。此时两个虚通路都被同一种类型的报文阻塞,其它报文将无法通过。因此在实际应用中,相同类型的数据报文多使用同一个 VC 进行数据传递。
目前多通路技术的应用已经普遍应用到网络传输中,虚通路是一种防止节点拥塞的有效方法。

流量控制的基本原理

目前流量控制从理论到实现大多基于多通道技术。
流量控制的主要作用是在发送端和接收端进行数据传递时,合理地使用物理链路,避免因为接收端缓冲区容量不足而丢弃来自发送端的数据,从而要求发送端重新发送已经发送过的报文,并最终有效地利用网络带宽。
目前,几乎所有流量控制算法的核心都是根据接收端缓冲区的容量,向发送端提供反馈(liyongjun:TCP window size)。而发送端根据这个反馈,决定向接收端发送多少数据。这些流量控制算法都力求发送的每一个数据报文都能够被接收端正确接收,而不会被接收端因为缓冲不足而丢弃。
使用流量控制机制并不能提高网络的峰值带宽,相反还会降低网络的带宽,但是可以有效减少数据报文的重新发送,从而保证网络带宽被充分利用(liyongjun:例子:列车员、空姐)。

在这里插入图片描述
假设 Node 1 与 Node 2 之间共存在 5 个 VC,即在链路 1 的两端设置了 5 组缓存。而这 5 个 VC 共享一个物理通路,即链路 1。

MSI 和 MSI-X 中断机制

在 PCI 总线中,所有需要提交中断请求的设备,必须能够通过 INTx 引脚提交中断请求,而 MSI 机制是一个可选机制。
而在 PCIe 总线中,PCIe 设备必须支持 MSI 或者 MSI-X 中断请求机制,而可以不支持 INTx 中断消息。
在 PCIe 总线中,MSI 和 MSI-X 中断机制使用存储器写请求 TLP 向处理器提交中断请求。PCIe 设备在提交 MSI 中断请求时,都是向 MSI/MSI-X Capability 结构中的 Message Address 的地址写 Message Data 数据,从而组成一个存储器写 TLP,向处理器提交中断请求。
有些 PCIe 设备还可以支持 Legacy 中断方式(通过发送 Assert_INTx 和 Deassert_INTx 消息报文进行中断请求,即虚拟中断线方式)。主要原因是,在 PCIe 体系结构中,存在许多 PCI 设备,这些设备通过 PCIe 桥连接到 PCIe 总线中,这些 PCI 设备可能并不支持 MSI/MSI-X 中断机制,因此必须使用 INTx 信号进行中断请求。
MSI 中断机制最多只能支持 32 个中断请求,而且要求中断向量连续。

  • 4
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
xdma pcie驱动是一种用于处理PCI Express总线设备的驱动程序。PCI Express是一种用于在计算机系统中进行高速数据传输的总线标准。xdma pcie驱动可用于控制和管理与PCI Express总线设备通信的过程。 xdma pcie驱动的调用过程一般包括以下步骤: 1. 程序初始化:首先,需要在程序中进行xdma pcie驱动的初始化设置。这通常包括加载驱动程序、建立与设备的通信连接等操作。 2. 配置设备:在驱动初始化后,需要进行设备配置。设置设备寄存器值、中断控制等参数,以确保设备在通信过程中的正常工作。 3. 发送数据:当设备配置完成后,可以通过调用驱动程序提供的接口来发送数据。这通常需要指定设备的物理地址和要发送的数据内容。 4. 接收数据:类似地,通过调用驱动程序提供的接口,可以接收来自设备的数据。同样需要指定设备的物理地址和要接收的数据长度。 5. 数据处理:在接收到数据后,可以对其进行处理。例如,可以进行数据的解析、计算、存储等操作,以满足实际应用的需求。 6. 终止:在完成数据处理后,需要终止与设备的通信,并释放相关资源。这通常包括关闭驱动程序、断开与设备的连接等操作。 总之,xdma pcie驱动的调用过程涉及到驱动程序的初始化、设备配置、数据的发送和接收、数据的处理以及终止等步骤。通过调用驱动程序提供的接口,可以实现与PCI Express设备的高速数据传输和交互。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Li-Yongjun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值