PCIE 基础

参考资料

相关书籍下载方式:
链接:https://pan.baidu.com/s/1zzWWt9ujVTr9oJSaJNP_mA
提取码:ahax


PCIE总线概述

注:由于自己是软件人员,关注重点更靠近X86环境下PCIE的状态和作用,本来很多部分都是由FPGA和硬件人员注重关心,但软件人员最好也知道些,也知道其所以然。

PCIE金手指接口及说明

PCIE金手指接口 or 备用地址 or 中文版接口说明

PCIE速率

GT/s —— Giga transation per second (千兆传输/秒),即每一秒内传输的次数。重点在于描述物理层通信协议的速率属性,可以不和链路宽度等关联。

image.png

参考PCIE2.0/PCIE3.0/PCIE4.0/PCIE5.0接口的带宽、速率计算PCIE扫盲

image.png

PCIE带宽计算: 吞吐量 = 传输速率 * 编码方案
比如,PCIE4.0是16 GT/s,128b/130b编码,所以 1Lane吞吐率 = 16*128/130=15.7GBps=1.96GMByte/s

端到端数据传输

  • PCIE使用端到端链接
  • TX和RX使用差分信号,且TX/RX分开
  • 使用GT(Gigatransfer) 计算峰值带宽 GT=总线频率x数据位宽x2
  • PCIE链路使用串行方式进行数据传输

PCIE总线信号

这里只需要看PCIE X1信号即可
image.png

电源信号

参考PCI-Express接口供电能力详解,可知:

  • 接口本身最高的供电能力为75W
  • 接口看到有5根+12V和3根3.3V针脚(+3.3V aux可选)。
  • 文档中规定了每根针脚最高通过电流为1.1A, 因此所说的75W限制其实是,12V x (5 x 1.1A) = 66W再加上3.3V x (3 x 1A) = 9.9W,一共75.9W
  • 另外,PCIE插槽也分多种类插槽: | 电压 | 10W插槽 | 25W插槽 | 75W插槽 | | —- | —- | —- | —- | | +3.3V | 3A | 3A | 3A | | +12V | 0.5A | 2.1A | 5.5A |

PCIE主要使用Vcc供电,Vaux-3.3V主要是电源管理相关,为了降低功耗和缩短恢复时间使用。

RESET#信号和WAKE#信号(可选)

CPU通过RESET#信号来复位PCIE内部逻辑
WAKE# PCIE设备休眠时,Vcc不进行供电。PCIE设备使用该信号让主机给PCIE进行供电唤醒。-必须支持Vaux供电

REFCLK+/REFCLK-

主板使用外部晶振给PCIE插槽提供参考时钟,设备作为Add-in卡与PCIE链接/或者内置PCIE模块,来与处理器进行同步。
时钟值: 100MHz

注:配置空间中 LINK Control Registers中”Common Clock Configuration”位

  • 0 - 默认值,表示设备与链路对端使用时钟异步
  • 1 - 表示设备与链路对端使用时钟同步

SMBUS与JTAG

支持SMBUS和JTAG信号

PRSTN1#和PRSTN2#信号

两个信号用来进行热插拔, Add-in卡中信号相连,插槽中PRSTN1接地,PRSTN2上拉
image.png

  • 状态1-没插卡: 插槽中PRSTN1接地为低,PRSTN2上拉为高
  • 状态2-插卡:Add-in卡短接,所以PRSTN1=PRSTN2为低
  • 状态3-拔卡:恢复到没插卡状态,插槽中PRSTN1接地为低,PRSTN2上拉为高

且PCIE这两个信号使用长短针设计,可以保证在其他金手指插上后才能接触。拔出时优先断开。

PCIE总线层次结构

image.png

  • 核心层:产生数据和接受数据
  • 事物层:定义了PCIE总线使用总线事物,接收核心层的数据,封装成TLB数据包传输到数据链路层
  • 链路层:报数报文的可靠性,添加SeqNum和CRC前后缀,使用ACK/NAK来保证报文可靠传输
  • 物理层:链接PCIE设备的物理设备,以及链路训练,识别等。

PCIE链路拓展

因为PCIE设备只支持端对端的传输,所以必须使用Switch进行拓展。

SWITCH是一个特殊的设备,**支持1个上游端口-链接RC或上层SWITCH,2-n个下游端口-链接EP**。
image.png

另外,还有两个端口(与数据流向有关):

  • Egress:发送数据端口(数据离开switch端口)
  • Igress:接收数据端口(数据进入switch端口)

注:这两个概念是相对的,比如上层的swtich的Egress是下层switch的Igress。

image.png

cross Link(了解):
多个主机间通过PCIE互联,将上游端口和上游端口对接。
image.png

PCIE设备初始化-复位

PCIE支持两种复位方式:传统复位方式和FLR复位方式(可选)

  • 传统复位方式:Cold,Warm,Hot Reset
  • FLR复位:可以给PCIE设备配置空间提供一个寄存器,该寄存器的Function Level Reset写1时,PCIE设备单纯复位内部逻辑.不影响LTSSM链路训练状态机。

传统复位介绍:

  • Cold复位:Vcc上电后,RESET#信号触发,无条件进入初始状态。
  • Warm复位:用户自定义,比如使用watchdog进行复位等。
  • HotReset:当PCIE设备异常时,可通过软件进行复位,比如通过桥设备复位子设备,

PCIE设备组成部分

PCIE主要由:RC Switch,PCIE-to-PCI桥,EP组成

基于PCIe架构的处理器系统

不同处理器架构,PCIE体系结构实现不同,这里Intel X86为例:
image.png
虚拟PCI:提供CPU地址域域PCI地址域转换。
FSB-to-Pcie桥:FSB兼容PCIE,因此可以直接转换。
在X86上,我们将:PCIE总线端口,地址转换,存储器控制器 统称为RC。所以X86上所有外设都是链接在PCIE上转的。

image.png
注:RC可以引出多个PCIE端口,称为多端口RC

在X86上,RC由ICH和MCH组成:

  • ICH(Input/Output Controller Hub,输入/输出控制集线器)
  • MCH(Memory Controller Hub,内存控制器集线器)

RC的组成结构

PCIE总线没有规定RC的设计,所以五花八门的。这里重点关注X86的PCIE设计;
以X86为例,RC由:

  • PCI的HOST主桥作用:地址转换和隔离
  • RCRB 管理存储器系统的寄存器组
  • Event Collector 处理PCIE设备的消息报文和PME消息
  • MR-IOV/SR-IOV相关

SWITCH桥-难点

因为PCIE使用端对端传输,所以需要PCIE SWITCH进行链路拓展-简单说就是PCIE HUB
image.png

  • switch由多少端口,就有多少虚拟PCI桥
  • switch内部有一条虚拟的PCI总线,用于链接各个虚拟PCI桥
  • 系统软件初始化时,需要为这条虚拟PCI总线分配编号

TC和VC

为了保证报文得QoS,PCIE采用虚拟多通路方式:

  • 每一条数据链路存在8个VC,
  • 报文头有3-bit得TC(Traffic Class)标签-8类
  • 8个TC和8个VC由软件绑定,属于 “多对一”

PCIE设备配置空间

X86使用CONFIG_ADDRESS寄存器与CONFIG_DATA寄存器访问PCIE 0x00-0xFF配置空间
使用ECAM方式访问0x100-0xFFF配置空间

首先PCIE设备也有PCI的0X00-0X3F基础配置空间-必须支持
image.png
这里注意:0x34的Capabilities Pointer指向了0x40-0xFF的配置空间

其次PCIE设备也支持0x40-0xFF的配置空间-必须支持(可选使用)
image.png
根据ID不同来区分不同的功能,主要关心的是:电源管理,MSI/MSI-X管理

最后PCIE设备可选支持0x100-0xFFF 4K大小的拓展配置空间-可选

这里截取PCI主桥的一段配置说明,或者参考PCIe设备在一个系统中是如何发现与访问的

  1. Host 主桥配置
  2. (base) baiy@baiy-All-Series:u-boot-2020.07$ sudo lspci -s 00:00.0 -vv
  3. 00:00.0 Host bridge: Intel Corporation Xeon E7 v3/Xeon E5 v3/Core i7 DMI2 (rev 02)
  4. Subsystem: Intel Corporation Xeon E7 v3/Xeon E5 v3/Core i7 DMI2
  5. Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
  6. Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
  7. Interrupt: pin A routed to IRQ 0
  8. NUMA node: 0
  9. Capabilities: [90] Express (v2) Root Port (Slot-), MSI 00
  10. DevCap: MaxPayload 128 bytes, PhantFunc 0
  11. ExtTag- RBE+
  12. DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
  13. RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
  14. MaxPayload 128 bytes, MaxReadReq 128 bytes
  15. DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr- TransPend-
  16. LnkCap: Port #0, Speed 5GT/s, Width x4, ASPM L1, Exit Latency L0s <512ns, L1 <16us
  17. ClockPM- Surprise+ LLActRep+ BwNot+ ASPMOptComp+
  18. LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- CommClk-
  19. ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
  20. LnkSta: Speed unknown, Width x0, TrErr- Train- SlotClk- DLActive- BWMgmt- ABWMgmt-
  21. RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna- CRSVisible-
  22. RootCap: CRSVisible-
  23. RootSta: PME ReqID 0000, PMEStatus- PMEPending-
  24. DevCap2: Completion Timeout: Range BCD, TimeoutDis+, LTR-, OBFF Not Supported ARIFwd-
  25. DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR-, OBFF Disabled ARIFwd-
  26. LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance- SpeedDis-
  27. Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
  28. Compliance De-emphasis: -6dB
  29. LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete-, EqualizationPhase1-
  30. EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
  31. Capabilities: [e0] Power Management version 3
  32. Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
  33. Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
  34. Capabilities: [100 v1] Vendor Specific Information: ID=0002 Rev=0 Len=00c <?>
  35. Capabilities: [144 v1] Vendor Specific Information: ID=0004 Rev=1 Len=03c <?>
  36. Capabilities: [1d0 v1] Vendor Specific Information: ID=0003 Rev=1 Len=00a <?>
  37. Capabilities: [280 v1] Vendor Specific Information: ID=0005 Rev=3 Len=018 <?>
  38. Capabilities: [300 v1] Vendor Specific Information: ID=0008 Rev=0 Len=038 <?>
  39. (base) baiy@baiy-All-Series:u-boot-2020.07$ sudo lspci -s 00:00.0 -xxxx
  40. 00:00.0 Host bridge: Intel Corporation Xeon E7 v3/Xeon E5 v3/Core i7 DMI2 (rev 02)
  41. 00: 86 80 00 2f 00 04 10 00 02 00 00 06 10 00 00 00
  42. 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  43. 20: 00 00 00 00 00 00 00 00 00 00 00 00 86 80 00 00
  44. 30: 00 00 00 00 90 00 00 00 00 00 00 00 00 01 00 00 # Capabilities Pointer = 0x90
  45. 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  46. 50: 00 e0 ff fb 00 00 00 00 00 00 00 00 00 00 00 00
  47. 60: 05 90 02 01 00 00 00 00 00 00 00 00 00 00 00 00
  48. 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  49. 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  50. 90: 10 e0 42 00 00 80 00 00 00 00 00 00 42 38 7a 00 # 0x90的ID=10,next=0xe0
  51. a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  52. b0: 00 00 00 00 9e 13 00 00 00 00 00 00 06 00 00 00
  53. c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  54. d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  55. e0: 01 00 03 00 08 00 00 00 00 00 00 00 00 00 00 00 # 0xe0的ID=0x01,next=0x00-结束
  56. f0: 00 00 00 00 00 00 00 00 09 00 00 00 00 00 00 00

PCIE支持多少种Capability?

  1. // linux-5.7.14/include/uapi/linux/pci_regs.h
  2. /* Capability lists */
  3. #define PCI_CAP_LIST_ID 0 /* Capability ID */
  4. #define PCI_CAP_ID_PM 0x01 /* Power Management */
  5. #define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */
  6. #define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */
  7. #define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */
  8. #define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */
  9. #define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */
  10. #define PCI_CAP_ID_PCIX 0x07 /* PCI-X */
  11. #define PCI_CAP_ID_HT 0x08 /* HyperTransport */
  12. #define PCI_CAP_ID_VNDR 0x09 /* Vendor-Specific */
  13. #define PCI_CAP_ID_DBG 0x0A /* Debug port */
  14. #define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */
  15. #define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */
  16. #define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */
  17. #define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */
  18. #define PCI_CAP_ID_SECDEV 0x0F /* Secure Device */
  19. #define PCI_CAP_ID_EXP 0x10 /* PCI Express */
  20. #define PCI_CAP_ID_MSIX 0x11 /* MSI-X */
  21. #define PCI_CAP_ID_SATA 0x12 /* SATA Data/Index Conf. */
  22. #define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */
  23. #define PCI_CAP_ID_EA 0x14 /* PCI Enhanced Allocation */
  24. #define PCI_CAP_ID_MAX PCI_CAP_ID_EA

PCIE总线的事务层(重点)

image.png


PCIE总线链路层和物理层

PCIE链路层

链路层作用:监控物理层的状态,保证TLP数据的准确传输

PCIE链路层状态

链路层通过物理层监控PCIE状态,并维护Data Link Control and Management State Machine (DLCMSM) 状态机
image.png

  • DLCMSM三种状态分别代表: 未链接,链接中,可使用
  • DLCMSM根据链接状态,向事务层设置标记: DL_Down和DL_Up

DLLP格式

DLLP数据产生于链路层,终止于链路层,目的是保证TLP有效传输,
image.png

PCIE TLP数据传输

image.png

链路层源设备和目标设备在一条PCIE的两端;
数据传输过程:

  • 链路层将事务层的TLP报文 加上数据包序列号和LCRC,放入REPLAY BUFFER-用户自定义buffer;
    序列号:发送端12位计数器 NEXT_TRANSMIT_SEQ,在DL_INACTIVATE->DL_ACTIVATE时为0,每发送一条,计数加1
  • 接收端12位计数器NEXT_RCV_SEQ,在接收到TLP报文时,对比计数器值与TLP 数据包序列号。
  • 接收端接收一定量的数据/或者超时后,统一回复一次ACK DLLP;太频繁影响性能。
  • 如果序列号比较正确,且CRC正确,接收端回复ACK DLLP,发送端则清除已发送buffer
  • 如果序列号比较错误,或者CRC错误,

image.png


PCIE的链路训练过程

参考硬件设备识别扫盲篇PCIe设备发现过程
1、PCIE 链路训练、枚举扫描、配置BAR的顺序?
上电复位后,首先进行链路训练,之后进行枚举扫描、最后进行基地址寄存器BAR的配置。
完成基地址配置后,就可以通过memory TLP读写进行寄存器的访问了。
2、链路训练、枚举扫描、配置BAR的过程
PCIE首先进行链路训练,上电复位后,链路训练状态机进入L0状态时链路训练完成后进入gen1模式,如果双方支持更高的速率,则立即进行gen2/3、4速率的训练,当链路训练状态机再次进入L0状态,链路训练完成。
链路训练完成开始进行枚举扫描,枚举扫描主要目的是CPU需要知道系统中有哪些PCIE 设备,并且为每个设备分配总线号。PCIE的配置读TLP报文中包含响应设备的bus_number、function_number以及device_number,因此PCIE设备需要知道自己的bus_number是多少。
枚举扫描过程中,CPU会通过配置读TLP读取PCIE配置空间的的verdor id和头标类型寄存器以及其他配置寄存器,此时PCIE返回的读返回TLP报文中complete_id(bus_number、function_number、device_number)为全0,因此此时PCIE不知道自己的bus_number。枚举过程中,CPU完成对PCIE的配置读后,会发起配置写TLP,此时PCIE接受到CPU发来的配第一次置写TLP,会从TLP中解析出bus_number字段存下来。随后的配置读TLP返回中,就会使用bus_number、和function_number和device_number拼接成complete_id。
枚举扫描完成后,会配置基地址寄存器,给PCIE分配地址空间。通过对BA0/1、BAR2/3等基地址寄存器先进行写全32’hffff_ffff,得到信息确认PCIE想申请32bit地址还是64bit地址以及向获得的地址空间,从而分配基地址。

image.png

https://blog.csdn.net/qq_24722893/article/details/109272114

https://m.sohu.com/a/234024205_781333
https://www.sohu.com/a/234290359_781333
https://www.sohu.com/a/234436659_781333

PCIE得复位机制

基础介绍

参考 传统的复位方式FLR

FLR

PCIe总线自V2.0加入了功能层复位(Function Level Reset,FLR)的功能。该功能主要针对的是支持多个功能的PCIe设备(Multi-Fun PCIe Device),可以实现只对特定的Function复位,而其他的Function不受影响。当然,该功能是可选的,并非强制的(SRIOV得PF是必须得)。软件可以通过查询配置空间中的设备功能寄存器(Device Capability Register)来查询该PCIe设备是否支持FLR。如下图所示:

之前看Synopsys的IP: 错误理解:支持FLR方式的PCIe设备需要在其BAR空间中提供一个寄存器,当系统软件对该寄存器的Function LevelReset位写1时,PCIe设备将使用FLR方式复位PCIe设备的内部逻辑。
这种做法好像很无语,因为标准规定:100ms内必须完成FLR复位,在内核代码 pci_flr中根本没 用户自定的操作接口,只能按照标准版本去进行FLR, 不允许有自定义的操作。

FLR的应用场景

在一个大规模的并行处理系统中,系统软件使用分区的概念管理所以硬件资源,包括处理器资源和所以IO资源,这些IO资源中通常会包含PCIe设备。

在这种处理器系统中,任务在指定的分区中运行,当这个任务执行完毕后,系统软件需要调整硬件资源的分区。此时受到影响的PCIe设备需要使用FLR方式复位内部的逻辑,以免造成对新的分区的资源污染,并保护之前任务的结果。

当PCIe设备使用FLR方式进行复位时,有些与PCIe链路相关的状态和寄存器并不会被复位
Ø Sticky Registers。与传统的复位方式相同,FLR方式不能复位这些寄存器,但是系统软件对部分Sticky Registers进行修改。当Vaux(备用电源)被移除后,这些寄存器中的保存的数据才会丢失。
Ø HwIint类型的寄存器。在PCIe设备中,有效配置寄存器的属性为HwIint,这些寄存器的值由芯片的配置引脚决定,后者上电复位后从EEPROM中获取。Cold和Warm Reset可以复位这些寄存器,然后从EEPROM中从新获取数据,但是使用FLR方式不能复位这些寄存器。
Ø 此外,还有一些特殊的配置寄存器不能被FLR方式复位,如Max_Payload_Size、RCB和一些与电源管理、流量控制和链路控制直接相关的寄存器。
Ø FLR方式不会影响LTSSM状态机。

FLR的机制

FLR只复位对应Function的内部状态和寄存器(使其暂时不变化,Making it quiescent),但是并不影响Sticky bits、有硬件初始化的值(Hardware-initialized bits)和链路专用寄存器(比如Captured Power,ASPM Control、Max Payload Size以及VC等寄存器)。

如果该设备在FLR前,发出了Assert INTx中断消息,必须在开始FLR之前在发出对应的Deassert INTx消息,除非该INTx已经被与其他Function共享了。当收到FLR后,该Function的所有的其他功能都应被立即停止(Required to cease)。
此外,PCIe Spec还明确给出了FLR的完成时间应在100ms以内

PCIe Spec还明确规定了,当某个Function处于FLR状态时的一些特性:
· 该Function不能有任何与外界通信的(外部)接口;
· 该Function必须将任何软件可读取的状态(可能包括加密信息等)打乱。换句话说,任何内部存储都必须被清零或者随机化;
· 该Function必须可以被另一个Diver配置为一般模式;
· 该Function必须为其收到的包含有FLR信息的配置写(Configuration Write)返回一个Completion,然后再进行FLR操作。

在进入FLR状态后,还需要:
· 该Function接收到的任何请求都应该被直接丢弃,且不登记(Logging),也不报错误。但是FC Credits必须要被更新,以维持链路的正常操作;
· 该Function接收到的任何Completion都应该被当做Unexpected Completions,然后直接丢弃,且不登记,也不报错。

FLR复位代码实现

pcie_has_flr检测 Device Capabilities Register (Offset 04h) 是否支持flr功能
image.png
pcie_flr 给Device Control Register (Offset 08h) bit[15]写1,然后轮训60s检测是否能重新读取到command配置
image.png

  1. pci_reset_function
  2. __pci_reset_function_locked(dev);
  3. pcie_has_flr
  4. pcie_flr
  5. pci_wait_for_pending_transaction(dev) // 读取PCIE的状态寄存器,判断是否在pending状态
  6. pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR); // 1复位
  7. pci_dev_wait
  8. not ready %dms after %s; waiting
  9. not ready %dms after %s; giving up

image.png

PASID-TBD

注:主要是IO虚拟化用到了这部分,所以需要简单看下。

PASID(进程地址空间ID Process Address Space ID)是一项可选功能,可在 多个进程之间共享单个Endpoint设备 ,同时为每个进程提供完整的64位虚拟地址空间。 实际上,此功能增加了对TLP前缀的支持,该TLP前缀包含可以添加到内存事务TLP的20位地址空间。

PASID TLP Prefix

参考:PCI Express Base_r5_1 P618页,6.20章节

PASID Extended Capability Structure