Home PCIe 错误机制
Post
Cancel

PCIe 错误机制

PCI总线中定义两个边带信号(PERR#和SERR#)来处理总线错误。 其中PERR#主要对应的是普通数据奇偶校检错误(Parity Error),而SERR#主要对应的是系统错误(System Error)。具体如下:

  • 普通的数据奇偶校检错误——通过PERR#报告
  • 在多任务事务(Multi-task Transaction,又称为Special Cycles)时的奇偶校检错误——通过SERR#报告
  • 地址和命令的奇偶校检错误——通过SERR#报告
  • 其他错误——通过SERR#报告

一个简单的例子如下图所示:

PCI错误信号

PCIe作为一种高速串行总线,取消了PCI总线中的这两个边带信号,采用错误消息的方式来实现错误报告。 但是,在软件层面上,PCIe仍是兼容PCI总线的

在PCIe总线的错误报告机制中,有如下四个比较重要的概念:

  • 错误检测(Error Detection):指的是检测某个错误是否存在的过程。
  • 错误登记(Error Logging):指的是将相关寄存器(配置空间中的)的对应位置位,以等待软件中的相关错误处理程序来处理该错误。
  • 错误报告(Error Reporting):通知系统某个(或多个)错误发生了。在PCIe总线中, 发生错误的设备会通过错误消息(Error Message)逐级将错误信息发送至Root,Root接收到错误消息后,会产生对应的中断通知系统。
  • 错误发送(Error Signaling):指的是通过发送错误消息(或者带有UR,CA的Completion和Poisoned TLP)来传递错误信息的过程。 “Poisoned TLP”是PCIe总线错误报告机制中的Error Forwarding的方式

PCIe总线Spec定义了两个错误报告等级第一个为基本的(Baseline Capability),是所有PCIe设备都需要支持的功能。 第二个是可选的,称之为高级错误报告(Advanced Error Reporting Capability)(AER)。

在基本的错误报告机制中,有两组相关的配置寄存器(配置空间中),分别为:

  1. 兼容PCI总线的寄存器(PCI-compatible Registers)
  2. PCIe总线中新增的寄存器(PCI Express Capability Registers)

高级错误报告机制(AER)中,又使用了一组专用的配置寄存器(配置空间中)。借助AER可以获得更多的错误信息,有助于软件定位错误源和分析错误原因。

PCIe总线的错误可以分为(Correctable Errors)和不可校正错误(Uncorrectable Errors)。 其中,可校正错误可以自动地被硬件识别并被自动的校正或恢复。而不可校正错误又被分为非致命的(Non-Fatal)和致命的(Fatal)。 非致命的错误一般有设备驱动软件(Device Specific Software)直接处理,且链路(Link)可恢复,甚至链路上的数据有可能得到恢复(不丢失数据)。 致命的错误只能由系统软件(System Software)处理,且一般需要进行复位等操作,因此链路上的数据必然会丢失。

错误检测机制

PCIe总线错误检测囊括了链路(Link)上的错误以及包传递过程中的错误,如下图所示。用户设计的应用程序层中的错误不属于链路传输中的错误, 不应当通过PCIe的错误检测与处理机制处理,一般可借助设备特殊中断(Device Specific Interrupt)等合适的方式进行报告与处理。

PCIe错误上报概览

包传递过程的错误主要通过CRC编码来检测。PCIe定义了两种CRC——LCRC和ECRC。 其中LCRC(Link CRC)由数据链路层产生和校检,用于检测从一端的数据链路层发送到另一端的数据链路层的TLP是否发生的错误。 而ECRC(End-to-end CRC)由事务层产生和校检,且ECRC是可选的。

有人可能会质疑ECRC存在的必要性,因为LCRC已经对TLP进行了CRC校检,在此基础上多加一层ECRC可能是没有必要的。 这里来简单地说明一下,一般情况下(尤其是没有Switch的简单PCIe总线系统中),ECRC的确是没有必要存在的。 ECRC主要为解决Switch中传输的可能存在的传输错误问题的, 如果用户的设计中并没有Switch(只是简单的Root与Endpoint的端对端直连),完全可以不使用ECRC。

如下图所示,假设来自Endpoint的TLP被正确地传输到Switch的Downstream输入端口(Ingress Port), Downstream输入端口中的数据链路层也完成了对其的LCRC校检,且未发现错误。然后Switch会将该LCRC移除, 并添加新的序列号(Sequence Number),随后重新计算LCRC,再将该TLP发送至Switch的Upstream输出端口(Egress Port)。 显然,在此过程中TLP是不受保护的,一旦期间数据传输遇到错误等异常,可能会导致重新计算LCRC前的数据已经受到了破坏,且仅仅使用LCRC是无法发现这样的错误的。

PCIeRCRC必要性示例

需要注意的是,ECRC是AER中的一部分,要想使用ECRC,该PCIe设备必须是支持AER的。

如果按照错误产生的层(Layer)来分,则可以分为物理层错误,数据链路层错误和事务层错误

物理层错误(Physical Layer Errors)主要有:

  • 8b/10b编解码异常
  • Framing异常(8b/10b编码中是可选的,128b/130b中是必选的)
  • Elastic Buffer错误(可选的)
  • 起始字符失锁(Loss of Symbol Lock)或者通道对齐失锁(Lane Deskew)(可选的)

数据链路层错误(Data Link Layer Errors)主要有:

  • LCRC校检失败
  • 序列号(Sequence Number)异常
  • DLLP中的16-bit CRC校检失败
  • 链路层协议错误(Link Layer Protocol Errors)

事务层错误(Transaction Layer Errors)主要有:

  • ERCR校检失败(可选的)
  • 异常的TLP(Malformed TLP)(即TLP的格式异常)
  • 流量控制协议异常(Flow Control Protocol Violation)
  • 不支持的请求
  • 数据损坏(Data Corruption,又称为Poisoned Packet)
  • Completer Abort(可选的)
  • 接收端溢出(Receiver Overflow)(可选的)
  • 返回包超时(Completion Timeout)
  • 不对应的返回包(Unexpected Completion,即Completion与发出的Request不一致)

当接收端的物理层检测到TLP存在错误时,如果再将该TLP继续传送至数据链路层和事务层必然也会发现错误。 而过多的错误会让错误分析与处理变得困难。因此,没有必要在向上传递该TLP,而是将其直接扔掉,并报告相应的错误。

然而,即使这样,PCIe总线的错误报告中也有很多错误源自同一个错误源。因此需要对错误进行优先级排序, 使得错误源(最底层的错误)的优先级更高,能够最先得到处理。PCIe总线中的错误优先级排序如下(优先级从高到低):

  • 不可更正的内部错误(Uncorrectable Internal Error)
  • 接收端Buffer溢出
  • 流量控制协议错误
  • ECRC校检失败
  • 异常的TLP(Malformed TLP)
  • AtomicOp Egress Blocked
  • TLP包头异常(TLP Prefix Blocked)
  • 访问控制服务(Access Control Services,ACS)异常
  • MC(Multi-cast) Blocked TLP
  • 不支持的请求(Unsupported Request,UR),Completer Abort(CA)或者不对应的返回包(Unexpected Completion)
  • 接收到损坏的数据包(Poisoned Packet)

错误源

ECRC

前面的文章中提到过,ECRC是可选的,主要用于包含有Switch的PCIe总线系统中。且只有支持AER的PCIe设备才有能力支持ECRC功能。 配置软件通过检查配置空间,确认PCIe设备的某个功能(Function)支持ECRC后, 可以通过向错误功能控制寄存器(Error Capability and Control Register)中的响应为写0或者1来禁止或者使能ECRC功能。

如果使能了ECRC功能,可以通过TLP包头中的TD(TLP Digest,ECRC也被称为Digest)为来标记当前的TLP是否使用ECRC,如下图所示。 需要特别注意的是,如果TD为1(表示使用ECRC),但是TLP中却没有ECRC;或者TD为0,TLP中却包含了ECRC,则会被判定为TLP格式错误,即Malformed TLP错误。

PCIe_ECRC

ECRC是基于TLP的包头和数据(Header and Data Payload)计算的,接收端会重新基于这些内容计算并与收到的TLP中的ECRC(发送端计算的)作对比, 如果不一致,则认为数据传输过程中发生了问题,数据被破坏了,进而产生ECRC校检错误。 需要注意的是,在TLP包头中,有两位实际上是不参与ERCR计算的——Type域的bit0和EP位。 这两位通常被称为Variant bits,且在ECRC计算的时候,这两位的对应位置始终被认为是1,而非使用实际的数值。

当接收端(Completer)接收到的请求(Request)TLP中存在ECRC校检错误时,接收端通常会选择不对该请求发送返回TLP(Completion), 并将ECRC错误状态位(配置空间中的)置位。发送端由于长时间未接收到Completion,进而会产生Completion超时错误(Timeout Error)。 而大部分发送端,会选择重新发送先前的请求Request。

当发送端(Requester)在发送完请求后收到了来自接收端返回的TLP(Completion)时,却发现该Completion TLP中存在ECRC校检错误, 会将ECRC错误状态位(配置空间中的)置位。发送端可以选择重新发送先前的请求Request,还可以选择通过特殊功能中断(Function Specific Interrupt)向系统报告错误。

以上两种情况中,如果使能了错误消息报告功能的话,不可校正的非致命错误消息(Uncorrectable Non-fatal Error Message)会被发送至系统。

Data Poisoning(Poisoned Data or Error Forwarding)

Data Poisoning也被称为错误传递(Error Forwarding),指的是在已知TLP Data Payload被破坏(Corrupted)的情况下, 该TLP仍然被发送至其他的PCIe设备。此时,该TLP包头的EP位(Error Poisoned)被置位为1,表明该TLP已经被破坏。如下图所示:

PCIe_ErrorPoisoned

既然都已经知道该TLP Data Payload被破坏了,为什么还要再将其进一步传递呢?实际上,这样做主要是针对某些特殊的应用的:

  • 便于发送端(Request)和系统分析错误:假设发送端(Request)向接收端(Completer)发送了读数据请求, 接收端从某个内存设备中读取数据后通过Completion返回数据给发送端。但是在此过程中发生了错误, 接收端(Completer)因此不向发送端(Request)返回Completion,则发送端只会产生Completion Timeout错误, 却难以分析错误原因。如果接收端返回Poisoned Completion TLP给发送端(TLP包头中EP为1), 则发送端至少可以确认接收端正确地接收到了其发出的请求(Request)。
  • 便于发现Switch(或其他桥设备)中的错误:假设TLP中的Data Payload是在Switch中被破坏的,采用错误传递的方式有助于发现该错误。
  • 有些应用允许接收存在错误的数据:比如实时的音频或者视频传输,其宁可接收到有些许错误的数据,也需要尽量保证数据传输的实时性。
  • 数据可能通过应用层恢复:有些应用可能采用了特殊的编码 ,该编码可以恢复某些被破坏的数据(如ECC可恢复1位的错误)。

需要特别注意的是,错误传递(Data Poisoning or Error Forwarding)只是针对TLP中的Data Payload是否被破坏,和TLP包头的内容无关。 也就是说错误传递只是针对那些带有Data Payload的TLP的,如Memory、Configuration、I/O写或者带有返回数据的Completion。 PCIe Spec没有定义对没有Data Payload的TLP,其TLP包头中的EP却为1的情况,应当如何处理。

注:需要注意的是,Poisoning操作只能在事务层进行。原因很简单:数据链路层和物理层在任何情况下,都不会检查TLP包头的内容,更不会修改TLP包头。

事务(Transaction )错误

事务错误主要包括不支持的请求(Unsupported Request)、Completer Abort、非预期的Completion和Completion超时。 该错误类型主要通过返回的Completion TLP包头中的Compl. Status告知Requester,如下图所示。

PCIe_Transaction错误1

PCIe_Transaction错误2

不支持的请求(Unsupported Request)主要包括:

  1. 请求类型不被当前PCIe设备支持
  2. 消息中使用了不支持或者未定义的消息编码
  3. 请求的地址空间超出(或者不在)设备的地址空间中
  4. 针对Completer的IO或者存储映射控制空间(Memory-mapped Control Space)进行的Poisoned写操作(EP=1)
  5. Root或者Switch的Downstream端口接收到针对其二级总线(Secondary Bus)上的不存在的设备的配置请求(Configuration Request)
  6. Endpoint接收到Type1型的配置请求
  7. Completion中使用了保留的Completion状态编码(参考上面的表格)
  8. 设备(的某个功能,Function)处于D1、D2或者D3hot电源管理状态时,却接收到了除了配置请求和消息之外的内容

Completer Abort(CA)主要包括:

  1. Completer接收的特殊请求,只有在违背其规则的情况下才能对该请求进行响应(返回Completion)
  2. 因为某些恒定的错误状态(Permanent Error Condition),导致Completer无法响应接收到的请求
  3. Completer接收到存在访问控制服务错误(Access Control Services Error,ACS Error)的请求
  4. PCIe-to-PCI桥接收到针对其连接的PCI设备的请求,但是该PCI设备无法处理该请求

非预期的Completion主要包括:

  1. Requester接收到的Completion和其发出的Request不一致

Completion超时

所有的PCIe设备都必须支持Completion超时定时器,除非该设备只是用于初始化配置事务的。 需要注意的是,PCIe设备必须能够针对多个事务(Transaction)分别计时。 PCIe 1.x和2.0的Spec建议超时时间最好设置为10ms至50ms之间,对于一些特殊情况,超时时间最低可设置为30us。 PCIe 2.1 Spec开始,增加了第二设备控制寄存器(Device Control Register 2)用于查看和控制超时时间的值。如下图所示:

PCIe_Completion超时寄存器

如果,某个请求对应多个Completion,那么除了最后一个Completion,其他的Completion不会造成该请求的定时器停止计时。

链路流量控制相关的错误主要有:

  1. 在FC初始化时,链路相邻设备无法完成针对任何一个VC的,最小的FC Credits的交换更新(Advertises)
  2. 链路相邻设备交换更新(Advertises)的FC Credits超过了最大值(Data Payload最大为2047,Header最大为127)
  3. 链路相邻设备交换更新时,FC Credits为非零值,且该链路的FC Credits之前已经被初始化为无限值了
  4. 接收端Buffer溢出,导致数据丢失(可选的,但是如果使能,则认为是Fatal Error)

异常的TLP(Malformed TLP)

异常的TLP(Malformed TLP)错误主要有:

  1. Data Payload超过了最大值(Max Payload Size)
  2. 数据长度(Data Length)与包头中的长度值不一致
  3. 存储地址起始位置跨越了4KB边界(Naturally-aligned 4KB Boundary)
  4. TD(TLP Digest)的值与ECRC是否使用不一致
  5. 字节使能冲突(Byte Enable Violation)
  6. 未定义的类型值(Type Field Values)
  7. Completion违反了RCB(Read Completion Boundary)值
  8. 针对非配置请求返回的Completion中的状态为配置请求重试状态(Configuration Request Retry Status)
  9. TC域包含了一个未被分配到当前使能的VC的值(也被称为TC Filtering)
  10. IO或者配置请求冲突(可选的)
  11. 中断Emulation消息向下发送(可选的)
  12. TLP前缀错误(具体请参考PCIe Spec V2.0的2.2~2.6相关章节)

内部错误(Internal Errors)

一般指的是Switch等桥设备内部产生的错误

错误报告机制

PCIe总线有三种错误报告方式,分别是:

  1. Completions:通过Completion中的状态位向Requestor返回错误信息
  2. Poisoned Packet(又称为错误传递,Error Forwarding):告知接收端当前TLP的Data Payload已经被破坏
  3. Error Message(错误消息):向主机报告错误信息

PCIe错误报告机制1

PCIe错误报告机制2

为了兼容PCI总线的错误报告机制(使用PERR#和SERR#),PCIe设备会自动将CA、UR和Poisoned TLP转换为对应的错误信息。

PCIe错误报告机制3

PCIe设备的配置空间中的状态与控制寄存器如上图所示,通过这些寄存器可以 使能(或禁止)通过错误消息(Error Message)发送错误报告、查询错误状态信息,以及链路训练和初始化状态等

默认的错误分类如下表所示

PCIe错误报告机制4

这些错误类型可以通过设备控制寄存器(Device Control Register)中的相关位,进行使能或者禁止

PCIe错误报告机制5

也可以通过设备状态寄存器(Device Status Registers)相关位查询错误状态: PCIe错误报告机制6

当然,当Root接收到错误消息后,怎么处理还要取决于Root Control Register的设置: PCIe错误报告机制7

链路错误(Link Errors)一般发生在物理层与数据链路层通信的过程中。 对于Downstream的设备,如果链路上发生了Fatal错误,此时,该设备并不能够向Root报告错误。 这种情况下,需要Upstream设备向Root来报告错误。为了消除链路错误,一般需要对链路进行重新训练(Retrain)。 如下图所示,在链路控制寄存器中,可以通过往Retrain Link这一位写1,来强制进行链路重训练。 PCIe错误报告机制8

当发起重训练请求后,软件可以检查链路状态寄存器(Link Status Register)中的Link Training位, 来确认链路训练是否已经完成,如下图所示。当该位为1时,表明链路训练尚未完成(或者还没有开始),如果链路训练已经完成,硬件会自动将该位清零。 PCIe错误报告机制9

PCIe总线的错误登记与报告的流程图如下图所示: PCIe错误报告机制10

This post is licensed under CC BY 4.0 by the author.

PCIe TLP包路由

PCIe 高级错误机制AER