目录

文章目录

  • 目录
  • 总线系统
  • PCIe 总线
    • PCIe 总线的传输速率
    • PCIe 总线的架构
  • PCIe 外设
    • PCIe 设备的枚举过程
    • PCIe 设备的编址方式
      • BDF(Bus-Device-Function)编号
      • BAR(Base Address Register)地址
  • Linux 上的 PCIe 设备
    • 查看 PCIe 设备的 BDF
    • 查看 PCIe 设备的 Vendor ID 和 Device ID
    • 查看 PCIe 设备的详细信息

总线系统

总线系统(Bus System),用于完成主机(CPU + Main Memory)和 I/O 外设(网卡、磁盘)等内部组件之间的通信。

从功能实现上,可以分为 3 种总线类型:

  1. 数据总线:用于在 CPU 与 Main Memory 或 I/O 设备之间传输数据。
  2. 地址总线:用于在 CPU 与 Main Memory 或 I/O 设备之间传输地址信息。
  3. 控制总线:用于在 CPU 与 Main Memory 或 I/O 设备之间传输控制信号。

从系统模块的角度,总线系统主要由 2 大部分组成:

  1. CPU 总线,又称为 FSB(Front Side Bus,前端总线)
  2. PCI/PCIe 总线

PCIe 总线

PCIe(Peripheral Component Interconnect Express,快速外设组件互连标准)是一种高速总线技术,用于统一连接 NIC、Disk、GPU 等多种类型的 I/O 外设。

PCIe 总线的传输速率

PCIe 使用 GT/s(Giga transmission per Second)作为传输速率的计量单位,区别于网络带宽的计量单位 Gbps(Giga bits per second)。因为 PCIe 协议具有 “行代码比“ 开销,根据不同的编码方案,会占用一定量的原始信道带宽。

所以,PCIe 带宽吞吐量的计算公式为:带宽 = 传输速率 x 行代码比。例如:PCIe 2.0 采用的编码方案是 8b/10b,含义是 10bits 数据里面,有 2bits 是额外的开销,实际上只传递了 8bits 的实际数据。所以,PCIe 2.0 每一条 Lane 的带宽为 5GT/s x 8b / 10b = 500MB/s,那么 PCIe 2.8 x 8 Lane 设备的总带宽就是 500MB/s x 8 = 4GB/s。

通常我们只需要关注实际的吞吐量数据,只是需要区分两者的差别。另外,PCIe 协议支持向前兼容的特性,如果设备支持 PCIe 4.0,但计算机主板支持只支持 PCIe 3.0,那么系统就只能以 3.0 的传输速率运行。

此外,与 PCIe 总线传输速率相关的参数还有以下几个:

  • MPS(Maximum Payload Size,最大有效载荷大小):决定了 PCIe 设备可以处理的最大的数据包大小。MPS 由 PCIe 设备的最大 TLP(Transaction Layer Packet,PCIe 事务层数据包)大小和主机的 MPS 参数中较小的一个确定。当数据包大小超过 MPS 时,需要进行 TLP 分片。
  • MRRS(Maximum Read Request Size,最大读请求大小):决定了 PCIe 设备可以发送的最大的读请求数据量。MRRS 由主机的 MRRS 参数和 PCIe 设备的 MRRS Capability 中较小的一个确定。
  • RCB(Read Completion Boundary,读完成边界):是 PCIe 设备接收的 TLP 的大小限制,即 TLP 读取操作必须是 RCB 的倍数。RCB 由 PCIe 设备的 RCBCR 寄存器设置。

上面 3 个参数的设置都可以影响到 PCIe 的性能。一般来说,提高 MPS、MRRS 可以增加 PCIe 性能,但也会增加延迟和 CPU 占用率。而调整 RCB 可以在一定程度上减小 DMA 操作带来的内存碎片化。

PCIe 总线的架构

相较于更早前的 PCI Bus 采用的共享并行互联架构,所有 I/O 设备共用一个总线带宽,导致整体性能不高。PCIe Bus 则采用了串行互联架构,以点对点的形式进行数据传输,也就是说每个 PCIe Devices 都有自己的专用连接,可以独享带宽,而不必向共享总线竞争带宽。

具体而言,PCIe 总线架构由以下几个部分组成:

  • PCIe Root Complex(RC,根聚合体):位于主板之上,通过 CPU Bus 与 CPU 和 Main Memory 互联,充当 CPU、Main Memory、PCIe Bus 之间通信的枢纽,并实现各类外设总线的聚合。

  • PCIe Switch:作为 PCle Hub and Switch,连接 PCIe RC 和多个 PCIe Devices,使得 PCIe Bus 具有良好的扩展性。

  • PCIe Endpoint:接入到 PCIe Bus 上的 PCIe Device,可以分为 2 种类型:

    1. Lagacy PCl-E Endpoint:指兼容 PCIe 标准的 PCI / PCI-X Device。
    2. Native PCl-E Endpoint:指标准的 PCle Device。
  • PCI/PCI-X Bridge:作为 PCI/PCI-X Bus 和 PCIe Bus 之间的桥接,以此支持标准的 PCI/PCI-X Devices。

PCIe 总线的工作原理如下:

  1. PCIe Root Complex 发送一个 TLP 到 PCIe Bus。
  2. PCIe Switch 接收 TLP 并进行路由,将 TLP 转发到 Target PCIe Device。
  3. PCIe Device 接收到 TLP 后返回 TLP Response。
  4. PCIe Switch 接收 TLP Response 后返回给 PCIe Root Complex。

PCIe 外设

  • PCIe 设备的接口类型

  • PCIe 设备的体积类型

    • LP(半高)
    • FH(全高)
    • HL(半长)
    • FL(全长)
    • SW(单宽)
    • DW(双宽)
  • PCIe 设备的插槽:PCIe Bus 支持对 PCI/PCI-X Bus 的软件兼容,但主板上的接口插槽却不兼容,因为 PCIe 是串行接口,针数会更少,插槽会更短。

PCIe 设备的枚举过程

PCIe Bus 是一个树状结构,所以 PCIe Devices 的枚举算法采用了深度优先遍历算法,即:对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。

  1. 主机起电后,操作系统首先扫描 Bus0(Root Complex 与 Host Bridge 相连的 PCIe Bus 定为 Bus0)。随后发现 Bridge1,将 Bridge1 下游的 PCIe Bus 定为 Bus1。初始化 Bridge 1 的配置空间,并 Bridge1 的 Primary Bus Number 和 Secondary Bus Number 寄存器分别设置成 0 和 1,表明 Bridge1 的上游总线是 Bus0,下游总线是 Bus1。由于还无法确定 Bridge1 下挂载设备的具体情况,系统先暂时将 Subordinate Bus Number 设为 0xFF。

  2. 操作系统开始扫描 Bus1。随后发现 Bridge3,并识别为一个 PCIe Switch 类型。系统将 Bridge3 下游的 PCIe Bus 定为 Bus 2,并将 Bridge3 的 Primary Bus Number 和 Secondary Bus Number 寄存器分别设置成 1 和 2。一样暂时把 Bridge3 的 Subordinate Bus Number 设为 0xFF。

  3. 操作系统继续扫描 Bus2。随后发现 Bridge4。继续扫描,随后发现 Bridge4 下面挂载了 NVMe SSD 设备。将 Bridge4 下游的 PCIe Bus 定为 Bus3,并将 Bridge4 的 Primary Bus Number 和 Secondary Bus Number 寄存器分别设置成 2 和 3。另外,因为 Bus3 下游是 PCIe Endpoint,不会再有下游总线了,因此 Bridge4 的 Subordinate Bus Number 的值可以确定为 3。

  4. 完成 Bus3 的扫描后,操作系统返回到 Bus2 继续扫描,随后发现 Bridge5。继续扫描,随后发现 Bridge5 下面挂载的 NIC 设备。将 Bridge5 下游的 PCIe Bus 设置为 Bus4,并将 Bridge5 的 Primary Bus Number 和 Secondary Bus Number 寄存器分别设置成 2 和 4。另外,同样因为 Bus4 上挂在的是 PCIe Endpoint,所以 Bridge5 的 Subordinate Bus Number 的值可以确定为 4。

  5. 除了 Bridge4 和 Bridge5 以外,Bus2 下面已经遍历完毕,因此返回到 Bridge3。因为 Bus4 是挂载在 Bridge3 下游的最后一个 Bus Number,所以将 Bridge3 的 Subordinate Bus Number 设置为 4。Bridge3 的下游设备都已经扫描完毕,继续返回到 Bridge1,同样将 Bridge1 的 Subordinate Bus Number 设置为 4。

  6. 系统返回到 Bus0 继续扫描,会发现 Bridge2,将 Bridge2 下游的 PCIe Bus 定为 Bus5。并将 Bridge2 的 Primary Bus Number 和 Secondary Bus Number 寄存器分别设置成 0 和 5。由于 Graphics Card 也是 PCIe Endpoint,因此 Bridge2 的 Subordinate Bus Number 的值可以确定为 5。

至此,系统完成了对 PCIe Bus 的扫描,将 PCIe Devices 都枚举了出来,操作系统通过这一过程获得了一个完整的 PCIe 设备拓扑结构。

PCIe 设备的编址方式

BDF(Bus-Device-Function)编号

CPU 要访问一个 PCIe Device 就必须要知道它的总线编号。

PCIe 标准支持在一台 Host 上创建最多 256 个 PCIe Bus,每条 Bus 最多可以支持 32 个 PCIe Device,每个 Device 最多可以支持 8 个 Functions。所以 PCIe 设备的总线编号由 Bus Number(范围是 0~255)、Device Number(范围是 0~31)、Function Number(范围是 0~7)这 3 个部分组成,简称 BDF。

例如:BDF 0000:01:00.0 表示位于 Bus0、Device1、Func0 的 PCIe 设备。

BAR(Base Address Register)地址

CPU 除了需要支持 PCIe Device 得 BDF 之外,还需要从 PCIe Device 的 BAR(Base Address Register,基地址寄存器)知道它所拥有的内存空间的地址范围。Device 的 Driver 需要通过 “基地址+寄存器偏移量“ 的方式来访问 Device 的内存空间并完成相应的配置操作。

下图是一个 PCIe Device 的 Configuration Space(配置空间),具有 6 个 BARs,分布在 0x0010 ~ 0x0028 这 24Bytes 中。在操作系统启动时,就会将这些 BARs 完成解析,并以文件系统的方式供用户态 Application 读取。

更进一步的,PCIe Device 会根据不同的目录将这 6 个 BARs 划分为不同的 Region,以 Intel 82599 网卡为例子。其拥有的 6 个 BAR 被分成了 3 块 Regions,各占 64bits:

  1. Memory BAR:指向 Main Memory 的一个地址,表示数据存储空间,对应 Device Memory(数据缓冲寄存器、状态寄存器)。支持进行 mmap() 映射,如果 Application 希望操作 PCIe 设备,就必须 mmap() 这个地址空间。

  2. I/O BAR:指向 Main Memory 的一个地址,表示 I/O 空间,对应 Device Register。CPU 可以通过专门的 CPU 指令来操作网卡设备。

  3. MSI-X BAR:指向 Main Memory 的一个地址,表示 MSI-X 空间。用来配置 MSI-X 中断向量。

在有了 Memory BAR 和 I/O BAR 之后,CPU 就可以通过 2 种不同的方式来访问 Device 了。其中 Memory BAR 是必须的,而 IO BAR 是可选的。

  1. 通过 I/O 空间,结合专用的 CPU 指令进行访问。例如:in、out 指令。Intel x86 CPU 的 in、out 的语法如下:
IN 累加器, {端口号 | DX}
OUT {端口号 | DX}, 累加器
  1. 通过 Memory 空间,进行数据读写,实现上更加容易。

下面以 Memory BAR 为例,介绍 Application 访问 Device 的流程。PCIe Device 的 Memory 空间关联到 PF Memory,存放的是 PF 的控制与状态信息。以 NVMe 为例,对 NVMe 的控制以及获取其工作状态都可以通过访问它的 Memory 空间来实现。

NVMe 命令下发的基本操作是:

  1. Host 写 doorbell 寄存器,此时使用 PCIe Memory 写请求。如下图所示,Host 发出一个 MWr(Memory Write)请求,该请求经过 PCIe Switch 到达要访问的 NVMe SSD 设备。

  1. NVMe 读取命令操作,这个请求会被 PCIe Endpoint 接收并执行。如下图所示,此时 NVMe SSD 作为请求者,发出一个 MRd(Memory Read)请求,该请求经过 PCIe Switch 到达 Host CPU。Host CPU 作为完成者会返回一个 CplD(事务完成包),将访问结果返回给 NVMe SSD。

同样,NVMe 的其他操作都是通过 PCIe Memory 访问的方式来进行的。

Linux 上的 PCIe 设备

如下图,查看 Linux 操作系统上的一个 PCIe 设备,具有以下文件:

  • config:设备的 Configuration Space,二进制,可读写。
  • device:设备的 Device ID,只读。
  • vendor:设备的 Vendor ID,只读。
  • driver:设备驱动程序的目录。
  • enable:设备是否正常使能,可读写;
  • irq:设备分到的中断号,只读;
  • local_cpulist:和设备处于同一个 NUMA Node 的 CPU 清单,用于实现 NUMA 亲和性。
  • local_cpu:和 local_cpulist 的作用一样,以掩码的方式给出。
  • numa_node:设备所属的 NUMA node,只读。
  • resource:设备的 BARs 记录,只读。
  • resource0…N:某个 BAR 空间,二进制,只读。
  • sriov_numfs:设备的 VFs 数量。
  • sriov_totalvfs:与 sriov_numfs 作用相同。
  • subsystem_device:PCIe 子系统设备 ID,只读。
  • subsystem_vendor:PCIe 子系统厂商 ID,只读。

查看 PCIe 设备的 BDF

下图黄色方框中的 PCIe 设备是 Bejing Starblaze Technology Co., LTD. 推出的 STAR1000 系列 NVMe SSD 设备,其中 9d32 是 Starblaze 在 PCI-SIG 组织的注册码,1000 是设备系列号。

STAR1000 的 BDF 分别为 0x3C、0x00、0x0,即:3C:00.0,与之对应的上游端口是 00:1d.0。

查看 PCIe 设备的 Vendor ID 和 Device ID

下图可以看到一个 NVMe Controller 的详细信息:

  • Vendor ID:供应商识别字段,由 PCI SIG 分配。
  • Device ID:设备识别字段,由供应商分配。
  • Class Code:表示这是一个 NVMe SSD 设备。
  • First Capability Pointer:指向 Device Capability 的入口,从 0x40 地址开始依次是 Power management、MSI 中断、链路控制与状态、MSI-X 中断等特性组。

查看 PCIe 设备的详细信息

下图中展示了指定 PCIe 设备的详细信息。其中可以看见该设备的 Memory BAR 空间,一段的大小是 1MB,另一段的大小是 256KB。系统可以通过 Memory 空间访问设备。

Linux 操作系统原理 — PCIe 总线标准相关推荐

  1. Linux 操作系统原理 — 内存 — 基于 MMU 硬件单元的虚/实地址映射技术

    目录 文章目录 目录 前文列表 物理地址与虚拟地址 内存空间的组织方式 虚拟地址空间的编址 内核态地址空间 用户态地址空间 内-外存空间的交换与虚拟存储空间之间的映射关系 缺页异常 前文列表 < ...

  2. Linux 操作系统原理 — 系统结构

    目录 文章目录 目录 Linux 系统架构 Linux 内核 内存管理 进程管理 文件系统 设备驱动程序 网络接口 Shell Linux 系统架构 Linux 系统一般有 4 个主要部分:内核.Sh ...

  3. Linux 操作系统原理 — 内存 — 内存分配算法

    目录 文章目录 目录 前文列表 内存碎片 伙伴(Buddy)分配算法 Slab 算法 虚拟内存的分配 内核态内存分配 vmalloc 函数 kmalloc 用户态内存分配 malloc 申请内存 用户 ...

  4. Linux 操作系统原理 — 内存 — 基于局部性原理实现的内/外存交换技术

    目录 文章目录 目录 前文列表 基于局部性原理实现的内-外存交换技术 局部性原理 Swap 交换分区 前文列表 <Linux 操作系统原理 - 内存 - 物理存储器与虚拟存储器> < ...

  5. Linux 操作系统原理 — 内存 — 页式管理、段式管理与段页式管理

    目录 文章目录 目录 前文列表 页式管理 快表 多级页表 基于页表的虚实地址转换原理 应用 TLB 快表提升虚实地址转换速度 页式虚拟存储器工作的全过程 缺页中断 为什么 Linux 默认页大小是 4 ...

  6. linux的原理和运用,Linux操作系统原理与应用_内存寻址

    原标题:Linux操作系统原理与应用_内存寻址 第五讲今天上线啦. 在本次课程中,陈老师详细的讲解了有关于内存寻址的演变的相关知识. 第一部分中,介绍了关于内存寻址的相关背景知识.内存寻址-操作系统设 ...

  7. Linux 操作系统原理 — 多处理器架构

    目录 文章目录 目录 计算平台体系结构 单核 CPU 和超线程 多核架构的出现 SMP 对称多处理结构 NUMA 非统一内存访问结构 MPP 大规模并行处理结构 Linux 上的 NUMA 基本对象概 ...

  8. linux操作系统原理_Linux后台开发C++学习路线技能加点,已拿鹅厂offer

    大家好我是lemon,最近在知乎经常被邀请回答类似如何学习C++和C++后台开发应该具体储备哪些基础技能的问题,围观原文链接: 非常详细的 Linux C/C++ 学习路线总结!助我拿下腾讯offer ...

  9. Linux 操作系统原理 — 文件系统 —文件

    目录 文章目录 目录 文件的类型 常规文件 ASCII 码文件 二进制文件 设备文件 字符设备文件 块设备文件 目录文件 其他文件 文件的构造方式 文件的属性 文件的操作 目录的操作 文件的类型 常规 ...

最新文章

  1. centos 安装 NTFS支持
  2. 使用AWSTATS自动分析Nginx日志
  3. python操作string类型的key的代码
  4. android笔记之在WebView中显示ProgressBar的两种方法
  5. 应用程序标准输入输出、Shell、程序界面的关系
  6. 一体台式计算机名称,【一体台式电脑】一体台式电脑品牌推荐,台式一体机电脑哪款好_什么值得买...
  7. 作者:褚金翔(1979-),男,中国农业科学院农业环境与可持续发展研究所助理研究员。...
  8. 22 SD配置-主数据-定义付款条款
  9. 【Flink】Unable to retrieve any partitions with KafkaTopicsDescriptor: Fixed Topics ([xxx)]
  10. 网上路径的图片有时候遍历不出来_最短路径问题(1)——Dijkstra算法
  11. java声明时间为什么类型_JAVA--类的声明周期
  12. cv2图像显示的像素值0-10-255和显示
  13. Struts(十一):OGNL表达式(二)
  14. 和i77700性能一样的服务器cpu,Intel八代i7 8700K和七代i7 7700K性能对比测验
  15. 自上而下 or 自下而上?企业部署RPA的2种策略
  16. 前端学起来特别吃力,新人入前端怎么学?
  17. OpenHarmony 软总线lite 源码分析
  18. 微型计算机常见接口设备,微型计算机的外部设备和内部设备各有哪些?
  19. 11s到1s,性能优化之首屏加载
  20. SQL Server Management Studio

热门文章

  1. python 网络编程是什么_什么是网络编程-Python 网络编程-嗨客网
  2. Windows驱动_WSK驱动之二WSK的操作
  3. 高通MDM平台开发入门
  4. 从开辟蓝海到保卫蓝海(一)
  5. 计算机在通风网络中的应用,计算机在矿井通风中应用.doc
  6. WIN 64位注册大漠dm.dll(regsvr32)解决失败方法
  7. Web前端教程学习笔记1.2-2022.10.17始
  8. UEM“探针”技术及用户体验管理
  9. Python写一个简洁拼写检查器
  10. 什么是防关联浏览器?