3. AER错误处理概述:AER Capability结构、错误分类与严重性

高级错误报告(Advanced Error Reporting, AER)是PCIe规范中定义的一套标准化错误报告与处理机制,它扩展了传统PCI的INTx/MSI中断错误上报方式,为驱动开发者提供了更精细的错误分类、更丰富的错误状态寄存器以及可配置的错误严重性等级。在将传统MSI中断驱动移植到支持AER的PCIe驱动时,理解AER Capability结构、错误分类及严重性映射是正确配置错误处理流程的前提。

核心概念: AER并非替代MSI中断,而是在MSI/MSI-X中断之上叠加了一层错误源分类与状态报告逻辑。驱动注册AER回调后,当PCIe设备检测到错误,硬件会通过AER Capability记录错误状态,并通过MSI中断通知驱动,驱动再通过读取AER寄存器完成错误源定位与恢复。

3.1 AER Capability结构

每个支持AER的PCIe功能(Function)在其配置空间中包含一个独立的AER Capability结构,该结构通过Capability ID(0x0001)和Next Capability Pointer串联在PCIe能力链表中。AER Capability结构由一组标准寄存器组成,用于控制错误报告行为、记录错误状态以及提供错误源标识。

3.1.1 AER Capability寄存器布局

偏移地址 寄存器名称 宽度 功能描述
0x00 PCIe Capability ID + Next Cap Pointer 16位 + 8位 标识AER Capability,指向下一个Capability
0x04 Uncorrectable Error Status Register (UESR) 32位 记录已发生的不可纠正错误类型(写1清零)
0x08 Uncorrectable Error Mask Register (UEMR) 32位 屏蔽特定不可纠正错误的报告(1=屏蔽)
0x0C Uncorrectable Error Severity Register (UESR) 32位 定义不可纠正错误的严重性(0=非致命,1=致命)
0x10 Correctable Error Status Register (CESR) 32位 记录已发生的可纠正错误类型(写1清零)
0x14 Correctable Error Mask Register (CEMR) 32位 屏蔽特定可纠正错误的报告(1=屏蔽)
0x18 Advanced Error Capabilities and Control Register (AECCR) 32位 控制AER功能,如First Error Pointer、ECRC Generation/Check等
0x1C Header Log Register (HLR) 128位 记录导致错误的TLP头部信息(用于诊断)
0x2C Root Error Command Register (RECR) 32位 仅Root Complex使用,控制错误转发行为
0x30 Root Error Status Register (RESR) 32位 仅Root Complex使用,汇总下游设备错误状态
0x38 Error Source Identification Register (ESIR) 32位 标识产生错误的Requester ID(Bus/Device/Function)
0x3C TLP Prefix Log Register (TPL) 128位 记录错误TLP的前缀信息(可选)
驱动移植要点: 在Linux内核中,AER Capability的基地址通过 pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR) 获取。驱动在初始化阶段需要读取UESR/CESR清零历史错误状态,并配置UEMR/CEMR以决定哪些错误需要上报。

3.1.2 AER Capability结构SVG图

AER Capability结构寄存器布局 AER Capability Header (Cap ID=0x0001, Next Ptr) Uncorrectable Error Status Register (UESR) - 32位 Uncorrectable Error Mask Register (UEMR) - 32位 Uncorrectable Error Severity Register (UESR) - 32位 Correctable Error Status Register (CESR) - 32位 Correctable Error Mask Register (CEMR) - 32位 Advanced Error Capabilities and Control Register (AECCR) - 32位 Header Log Register (HLR) - 128位 (4个32位寄存器) Root Error Command Register (RECR) - 32位 (仅Root Complex) Root Error Status Register (RESR) - 32位 (仅Root Complex) Error Source Identification Register (ESIR) - 32位 TLP Prefix Log Register (TPL) - 128位 (可选) 红色:不可纠正错误 绿色:可纠正错误 紫色/橙色:控制与日志 青色:Root Complex专用

3.2 错误分类:可纠正错误与不可纠正错误

PCIe AER将错误分为两大类:可纠正错误(Correctable Errors)和不可纠正错误(Uncorrectable Errors)。这种分类决定了驱动在收到错误通知后应采取的处理策略——是仅记录日志并继续运行,还是需要触发复位或热复位流程。

3.2.1 可纠正错误(Correctable Errors)

可纠正错误是指硬件能够通过重传、ECC纠错等机制自动恢复的错误,不会导致数据损坏或链路中断。驱动通常只需记录错误计数,无需采取恢复动作。

错误类型 错误码(Bit位置) 描述 典型触发场景
Receiver Error Bit 0 接收端检测到物理层错误(如8b/10b解码错误) 信号完整性差、链路噪声
Bad TLP Bit 6 接收到的TLP格式错误或CRC校验失败 链路瞬态错误、发送端逻辑错误
Bad DLLP Bit 7 接收到的DLLP格式错误或CRC校验失败 链路层协议错误
REPLAY_NUM Rollover Bit 8 重试计数器溢出,表明链路持续错误 链路严重不稳定
Replay Timer Timeout Bit 12 重传定时器超时,TLP未得到确认 链路拥塞或对端无响应
Advisory Non-Fatal Bit 13 指示一个非致命不可纠正错误已被纠正 ECC纠正了单比特错误
Corrected Internal Error Bit 14 设备内部错误已被内部机制纠正 内部RAM ECC纠正
Header Log Overflow Bit 15 Header Log寄存器溢出,新错误覆盖旧记录 连续多个错误未及时读取

3.2.2 不可纠正错误(Uncorrectable Errors)

不可纠正错误是指硬件无法自动恢复的错误,可能导致数据损坏或链路功能异常。根据严重性,不可纠正错误又分为非致命(Non-Fatal)和致命(Fatal)两类。

错误类型 错误码(Bit位置) 默认严重性 描述
Undefined Bit 0 致命 未定义的内部错误
Data Link Protocol Error Bit 4 致命 数据链路层协议序列错误
Surprise Down Error Bit 5 致命 设备意外断开(热插拔异常)
Poisoned TLP Bit 12 非致命 TLP被标记为中毒(数据损坏)
Flow Control Protocol Error Bit 13 致命 流控制协议错误
Completion Timeout Bit 14 非致命 请求者等待Completion超时
Completer Abort Bit 15 非致命 完成者主动中止请求
Unexpected Completion Bit 16 非致命 收到与未完成请求不匹配的Completion
Receiver Overflow Bit 17 致命 接收缓冲区溢出
Malformed TLP Bit 18 致命 TLP格式违反PCIe规范
ECRC Error Bit 19 非致命 端到端CRC校验失败
Unsupported Request Bit 20 非致命 请求类型不被设备支持
ACS Violation Bit 21 非致命 访问控制服务(ACS)权限违规
Uncorrectable Internal Error Bit 22 致命 设备内部不可纠正错误
MC Blocked TLP Bit 23 非致命 多播TLP被阻塞
AtomicOp Egress Blocked Bit 24 非致命 原子操作被出口阻塞
TLP Prefix Blocked Bit 25 非致命 TLP前缀被阻塞
严重性可编程: 驱动可以通过修改Uncorrectable Error Severity Register(UESR)来改变不可纠正错误的严重性分类。例如,默认非致命的Completion Timeout可以被重新配置为致命错误,从而触发更激进的处理流程(如链路复位)。但修改严重性需要谨慎,错误的配置可能导致系统不必要的复位或错误漏报。

3.3 错误严重性:非致命与致命

不可纠正错误的严重性决定了驱动和系统软件在检测到错误后的响应策略。AER规范定义了两种严重性等级,并通过UESR寄存器中的对应位来配置。

3.3.1 非致命错误(Non-Fatal Error)

  • 定义: 错误影响了当前事务,但设备功能仍然可用,链路保持正常。
  • 驱动行为: 记录错误日志,尝试恢复受影响的事务(如重发请求),继续提供服务。
  • 系统影响: 通常不会触发系统复位,仅上报到OS错误处理框架(如Linux的AER驱动)。
  • 典型例子: Completion Timeout、Poisoned TLP、Unsupported Request。

3.3.2 致命错误(Fatal Error)

  • 定义: 错误导致设备功能不可用或链路完整性受损,需要复位恢复。
  • 驱动行为: 立即停止设备I/O操作,触发链路复位或功能级复位(FLR),重新初始化设备。
  • 系统影响: 可能导致整个PCIe域的重置,影响同一总线上的其他设备。
  • 典型例子: Malformed TLP、Receiver Overflow、Surprise Down Error。

3.3.3 错误严重性处理流程SVG图

AER错误严重性处理流程 PCIe设备检测到错误 错误是否可纠正? 是 硬件自动纠正 记录错误计数 继续正常运行 否 读取UESR寄存器 检查UESR严重性 非致命 or 致命? 非致命 记录日志,尝试恢复 致命 触发链路复位 说明:驱动通过读取UESR寄存器判断错误类型,再根据UESR中的严重性配置决定处理策略

3.4 AER错误处理与MSI中断的协同

在PCIe驱动中,AER错误处理并非独立的中断源,而是通过MSI/MSI-X中断向量来通知驱动。驱动在初始化时需要完成以下配置步骤:

  1. 分配MSI/MSI-X中断向量: 调用 pci_alloc_irq_vectors() 分配至少一个中断向量用于AER错误通知。
  2. 注册AER回调: 通过 pci_enable_pcie_error_reporting() 启用设备AER功能,并注册 struct pci_error_handlers 结构体中的回调函数(如 error_detected、slot_reset、resume)。
  3. 配置错误掩码: 根据驱动需求设置UEMR和CEMR,屏蔽不需要上报的错误类型。
  4. 清零历史状态: 写入UESR和CESR清零遗留错误状态位。
关键代码示例: 在Linux驱动中,AER回调注册通常如下:
static const struct pci_error_handlers mydev_err_handler = {
    .error_detected = mydev_error_detected,
    .slot_reset     = mydev_slot_reset,
    .resume         = mydev_resume,
};

static int mydev_probe(struct pci_dev *pdev, ...)
{
    // 1. 启用PCIe AER
    pci_enable_pcie_error_reporting(pdev);
    
    // 2. 分配MSI中断向量
    ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
    
    // 3. 注册错误处理回调
    pdev->error_handler = &mydev_err_handler;
    
    // 4. 清零AER状态寄存器
    pci_write_config_dword(pdev, pdev->aer_cap + PCI_ERR_UNCOR_STATUS, 0xFFFFFFFF);
    pci_write_config_dword(pdev, pdev->aer_cap + PCI_ERR_COR_STATUS, 0xFFFFFFFF);
}

3.5 本章小结

知识点 核心内容 驱动移植关注点
AER Capability结构 包含UESR/UEMR/UESR、CESR/CEMR、HLR等寄存器 通过 pci_find_ext_capability() 获取基地址
可纠正错误 硬件自动恢复,驱动只需记录计数 配置CEMR屏蔽不关心的错误,避免中断风暴
不可纠正错误 分为非致命和致命,通过UESR配置 非致命:记录+恢复;致命:复位+重新初始化
严重性可编程 驱动可修改UESR改变错误严重性 谨慎修改,避免系统不稳定
与MSI协同 AER通过MSI中断通知驱动 先分配MSI向量,再注册AER回调