错误检测和纠正 (EDAC) 设备

EDAC 子系统中使用的主要概念

有几个需要注意的事项,这些事项并不明显,例如插槽、*插槽集存储体芯片选择行通道等...

这些是许多被抛出的术语,它们的含义并不总是人们认为的含义(不可思议!)。 为了创建共同的讨论基础,将建立术语及其定义。

  • 内存设备

内存条上的单个 DRAM 芯片。这些设备通常每个输出 4 位和 8 位(x4、x8)。 将多个这些设备并行分组可提供内存控制器期望的位数:通常为 72 位,以便提供 64 位 + 8 位 ECC 数据。

  • 内存条

一个印刷电路板,并行聚合多个内存设备。 一般来说,这是现场可更换单元 (FRU),在出现过多错误时会更换。 最常见的是,它也被称为 DIMM(双列直插式内存模块)。

  • 内存插槽

主板上接受单个内存条的物理连接器。 在多个数据表中也称为“插槽”。

  • 通道

一个内存控制器通道,负责与一组 DIMM 通信。 每个通道都有自己独立的控制(命令)和数据总线,可以独立使用或与其他通道分组使用。

  • 分支

它通常是全缓冲 DIMM 内存控制器上的最高层级。 通常,它包含两个通道。 同一分支上的两个通道可以以单模式或锁步模式使用。 启用锁步后,缓存线将加倍,但这通常会带来一些性能损失。 此外,当发生错误时,通常不可能仅指向一个内存条,因为错误纠正代码是使用两个 DIMM 而不是一个 DIMM 计算的。 因此,它能够纠正比单模式下更多的错误。

  • 单通道

内存控制器访问的数据仅包含在一个 dimm 中。 例如,如果数据宽度为 64 位,则数据将使用一个 64 位并行访问流向 CPU。 通常与 SDR、DDR、DDR2 和 DDR3 内存一起使用。 FB-DIMM 和 RAMBUS 使用不同的通道概念,因此此概念不适用于此处。

  • 双通道

内存控制器访问的数据大小会交织到两个 dimm 中,同时访问。 例如,如果 DIMM 宽度为 64 位(使用 ECC 为 72 位),则数据将使用 128 位并行访问流向 CPU。

  • 芯片选择行

这是用于选择要访问的 DRAM 级别的 DRAM 信号的名称。 单通道的常见芯片选择行是 64 位,双通道是 128 位。 它可能对内存控制器不可见,因为某些 DIMM 类型具有内存缓冲区,该缓冲区可以隐藏内存控制器的直接访问。

  • 单秩条

单秩条具有 1 行芯片选择内存。 主板通常将两个芯片选择引脚驱动到内存条。 单秩条将仅占用这些行中的一行。 另一个将未使用。

  • 双秩条

双秩条具有两行芯片选择,用于访问不同的内存设备组。 这两行不能同时访问。

  • 双面条

已弃用术语,请参阅双秩条

双面条具有两行芯片选择,用于访问不同的内存设备组。 这两行不能同时访问。“双面”与内存设备是否安装在内存条的两侧无关。

  • 插槽集

单个内存访问所需的所有内存条或芯片选择行跨越的所有内存条。 一个插槽集具有两个芯片选择行,如果使用双面条,则它们将占用这些芯片选择行。

  • 存储体

由于在需要区分芯片选择行和插槽集时含义不明确,因此避免使用此术语。

  • 高带宽内存 (HBM)

HBM 是一种新型内存类型,具有低功耗和超宽通信通道。 它使用通过称为“硅通孔”或 TSV 的微观导线互连的垂直堆叠内存芯片(DRAM 芯片)。

多个 HBM 芯片堆叠通过称为“中间层”的超快速互连连接到 CPU 或 GPU。 因此,HBM 的特性几乎与片上集成 RAM 没有区别。

内存控制器

大多数 EDAC 核心都专注于进行内存控制器错误检测。 edac_mc_alloc()。 它在内部使用结构体 mem_ctl_info 来描述内存控制器,该结构体对于 EDAC 驱动程序是不透明的。 只有 EDAC 核心允许触碰它。

enum dev_type

描述内存条上使用的内存 DRAM 芯片的类型

常量

DEV_UNKNOWN

无法确定,或者 MC 不支持检测它

DEV_X1

1 位用于数据

DEV_X2

2 位用于数据

DEV_X4

4 位用于数据

DEV_X8

8 位用于数据

DEV_X16

16 位用于数据

DEV_X32

32 位用于数据

DEV_X64

64 位用于数据

描述

典型值为 x4 和 x8。

enum hw_event_mc_err_type

检测到的错误类型

常量

HW_EVENT_ERR_CORRECTED

已纠正错误 - 表示检测到 ECC 已纠正的错误

HW_EVENT_ERR_UNCORRECTED

未纠正错误 - 表示 ECC 无法纠正的错误,但它不是致命的(可能是在未使用的内存区域,或者内存控制器可以从该错误中恢复,例如,通过重新尝试该操作)。

HW_EVENT_ERR_DEFERRED

延迟错误 - 表示处理不紧急的不可纠正错误。 这可能是由于硬件数据中毒,其中系统可以继续运行直到消耗中毒数据。 也可以采取预防措施,例如离线页面等。

HW_EVENT_ERR_FATAL

致命错误 - 无法恢复的未纠正错误。

HW_EVENT_ERR_INFO

信息性 - CPER 规范定义了第四种类型的错误:信息性日志。

enum mem_type

内存类型。 有关更详细的参考,请参阅http://en.wikipedia.org/wiki/DRAM

常量

MEM_EMPTY

空 csrow

MEM_RESERVED

保留 csrow 类型

MEM_UNKNOWN

未知 csrow 类型

MEM_FPM

FPM - 快速页面模式,在 1995 年之前的系统上使用。

MEM_EDO

EDO - 扩展数据输出,在 1998 年之前的系统上使用。

MEM_BEDO

BEDO - 突发扩展数据输出,一种 EDO 变体。

MEM_SDR

SDR - 单数据速率 SDRAM http://en.wikipedia.org/wiki/Synchronous_dynamic_random-access_memory 它们使用 3 个引脚进行芯片选择:引脚 0 和 2 用于秩 0;引脚 1 和 3 用于秩 1(如果内存是双秩的)。

MEM_RDR

注册 SDR SDRAM

MEM_DDR

双数据速率 SDRAM http://en.wikipedia.org/wiki/DDR_SDRAM

MEM_RDDR

寄存式双倍数据速率 SDRAM:这是 DDR 内存的一种变体。寄存式内存内部有一个缓冲区,对内存控制器隐藏了部分内存细节。

MEM_RMBS

Rambus DRAM,用于少数 Pentium III/IV 控制器。

MEM_DDR2

DDR2 RAM,如 JEDEC JESD79-2F 中所述。这些内存被标记为“PC2-”,而不是“PC”,以区别于 DDR。

MEM_FB_DDR2

全缓冲 DDR2,如 JEDEC 标准 205 和 JESD206 中所述。这些内存通过 DIMM 插槽访问,而不是通过片选信号访问。

MEM_RDDR2

寄存式 DDR2 RAM:这是 DDR2 内存的一种变体。

MEM_XDR

Rambus XDR:它是原始 RAMBUS 内存的演变,旨在与 DDR2 竞争。没有在任何 x86 架构上使用,但 cell_edac PPC 内存控制器使用它。

MEM_DDR3

DDR3 RAM

MEM_RDDR3

寄存式 DDR3 RAM:这是 DDR3 内存的一种变体。

MEM_LRDDR3

降负载 DDR3 内存。

MEM_LPDDR3

低功耗 DDR3 内存。

MEM_DDR4

无缓冲 DDR4 RAM

MEM_RDDR4

寄存式 DDR4 RAM:这是 DDR4 内存的一种变体。

MEM_LRDDR4

降负载 DDR4 内存。

MEM_LPDDR4

低功耗 DDR4 内存。

MEM_DDR5

无缓冲 DDR5 RAM

MEM_RDDR5

寄存式 DDR5 RAM

MEM_LRDDR5

降负载 DDR5 内存。

MEM_NVDIMM

非易失性 RAM

MEM_WIO2

Wide I/O 2。

MEM_HBM2

高带宽内存第 2 代。

MEM_HBM3

高带宽内存第 3 代。

enum edac_type

错误检测和纠正能力及模式

常量

EDAC_UNKNOWN

未知是否支持 ECC

EDAC_NONE

不支持 ECC

EDAC_RESERVED

保留的 ECC 类型

EDAC_PARITY

检测奇偶校验错误

EDAC_EC

错误检查 - 无纠正

EDAC_SECDED

单比特错误纠正,双比特检测

EDAC_S2ECD2ED

Chipkill x2 设备 - 这些设备存在吗?

EDAC_S4ECD4ED

Chipkill x4 设备

EDAC_S8ECD8ED

Chipkill x8 设备

EDAC_S16ECD16ED

Chipkill x16 设备

enum scrub_type

擦洗功能

常量

SCRUB_UNKNOWN

未知是否支持擦洗器

SCRUB_NONE

无擦洗器

SCRUB_SW_PROG

软件渐进式(顺序)擦洗

SCRUB_SW_SRC

仅擦洗软件错误

SCRUB_SW_PROG_SRC

从错误开始的渐进式软件擦洗

SCRUB_SW_TUNABLE

软件擦洗频率可调

SCRUB_HW_PROG

硬件渐进式(顺序)擦洗

SCRUB_HW_SRC

仅擦洗硬件错误

SCRUB_HW_PROG_SRC

从错误开始的渐进式硬件擦洗

SCRUB_HW_TUNABLE

硬件擦洗频率可调

enum edac_mc_layer_type

内存控制器层次结构层

常量

EDAC_MC_LAYER_BRANCH

内存层命名为“branch”

EDAC_MC_LAYER_CHANNEL

内存层命名为“channel”

EDAC_MC_LAYER_SLOT

内存层命名为“slot”

EDAC_MC_LAYER_CHIP_SELECT

内存层命名为“片选”

EDAC_MC_LAYER_ALL_MEM

内存布局未知。所有内存都映射为单个内存区域。这用于从固件驱动的驱动程序中检索错误。

描述

驱动程序使用此枚举来告诉 edac_mc_sysfs 在描述内存条位置时应使用的名称。

struct edac_mc_layer

描述内存控制器层次结构

定义:

struct edac_mc_layer {
    enum edac_mc_layer_type type;
    unsigned size;
    bool is_virt_csrow;
};

成员

type

层类型

size

每层的组件数量。例如,如果通道层有两个通道,则 size = 2

is_virt_csrow

当启用旧 API 兼容模式时,此层是“csrow”的一部分。否则,它是一个通道

struct rank_info

包含一个 DIMM rank 的信息

定义:

struct rank_info {
    int chan_idx;
    struct csrow_info *csrow;
    struct dimm_info *dimm;
    u32 ce_count;
};

成员

chan_idx

rank 所在的通道号(通常为 0 或 1)

csrow

指向片选行结构(父结构)的指针。rank 的位置由 (csrow->csrow_idx, chan_idx) 向量给出。

dimm

指向 DIMM 结构的指针,其中存储了 DIMM 标签信息。

ce_count

此 rank 的可纠正错误数

描述

FIXME:目前,EDAC 核心模型将假设每个 rank 有一个 DIMM。

这是一个错误的假设,但这使此补丁更容易。此系列中的后续补丁将解决此问题。

struct edac_raw_error_desc

原始错误报告结构

定义:

struct edac_raw_error_desc {
    char location[LOCATION_SIZE];
    char label[(EDAC_MC_LABEL_LEN + 1 + sizeof(OTHER_LABEL)) * EDAC_MAX_LABELS];
    long grain;
    u16 error_count;
    enum hw_event_mc_err_type type;
    int top_layer;
    int mid_layer;
    int low_layer;
    unsigned long page_frame_number;
    unsigned long offset_in_page;
    unsigned long syndrome;
    const char *msg;
    const char *other_detail;
};

成员

location

错误的位置

label

受影响的 DIMM 的标签

grain

错误报告的最小粒度,以字节为单位

error_count

相同类型的错误数

type

错误的严重程度(CE/UE/Fatal)

top_layer

错误的顶层(layer[0])

mid_layer

错误的中间层(layer[1])

low_layer

错误的底层(layer[2])

page_frame_number

发生错误的页面

offset_in_page

页面偏移

syndrome

错误的综合症(如果未知或综合症不适用,则为 0)

msg

错误消息

other_detail

关于错误的其他驱动程序特定详细信息

struct dimm_info *edac_get_dimm(struct mem_ctl_info *mci, int layer0, int layer1, int layer2)

从 [layer0,layer1,layer2] 位置给定的内存控制器获取 DIMM 信息

参数

struct mem_ctl_info *mci

MC 描述符结构 mem_ctl_info

int layer0

layer0 位置

int layer1

layer1 位置。如果 n_layers < 2,则未使用

int layer2

layer2 位置。如果 n_layers < 3,则未使用

描述

对于 1 层,此函数返回“dimms[layer0]”;

对于 2 层,此函数类似于分配一个二维数组并返回“dimms[layer0][layer1]”;

对于 3 层,此函数类似于分配一个三维数组并返回“dimms[layer0][layer1][layer2]”;

struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num, unsigned int n_layers, struct edac_mc_layer *layers, unsigned int sz_pvt)

分配并部分填充一个 mem_ctl_info 结构体。

参数

unsigned int mc_num

内存控制器号

unsigned int n_layers

MC 层次结构层的数量

struct edac_mc_layer *layers

描述内存控制器看到的每一层

unsigned int sz_pvt

所需的私有存储大小

描述

所有内容都作为一大块 kmalloc,效率更高。只有当所有结构具有相同的生命周期时才可以使用,否则必须分配并初始化自己的结构。

使用 edac_mc_free() 释放此函数分配的 mc 结构。

注意

驱动程序以不同的方式处理多 rank 内存:在某些驱动程序中,一个多 rank 内存条映射为一个条目,而在其他驱动程序中,一个多 rank 内存条会映射到多个条目。目前,此函数将在这种情况下分配多个 struct dimm_info,因为对多个 rank 进行分组需要更改驱动程序。

返回

成功时,返回指向结构体 mem_ctl_info 指针的指针;否则返回 NULL

const char *edac_get_owner(void)

返回 EDAC MC 的所有者的 mod_name

参数

void

无参数

返回

当 EDAC MC 被拥有时,返回指向 mod_name 字符串的指针。否则返回 NULL。

void edac_mc_free(struct mem_ctl_info *mci)

释放先前分配的 mci 结构

参数

struct mem_ctl_info *mci

指向 mem_ctl_info 结构的指针

bool edac_has_mcs(void)

检查是否已分配任何 MC。

参数

void

无参数

返回

如果 MC 实例已成功注册,则为 True。否则为 False。

struct mem_ctl_info *edac_mc_find(int idx)

搜索索引为 idx 的 mem_ctl_info 结构。

参数

int idx

要查找的索引

描述

如果找到,则返回指向该结构的指针。否则返回 NULL。

struct mem_ctl_info *find_mci_by_dev(struct device *dev)

扫描控制器列表,查找管理 dev 设备的控制器。

参数

struct device *dev

指向与 MCI 相关的 struct device 的指针

返回

成功时,返回指向结构体 mem_ctl_info 的指针;否则返回 NULL

struct mem_ctl_info *edac_mc_del_mc(struct device *dev)

删除与 dev 关联的 mci 结构的 sysfs 条目,并从全局列表中删除 mci 结构。

参数

struct device *dev

指向表示要删除的 mci 结构的 device 结构的指针。

返回

指向已删除的 mci 结构的指针,如果未找到设备,则返回 NULL

int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)

用于识别哪个 csrow 包含内存页的辅助例程。

参数

struct mem_ctl_info *mci

指向 mem_ctl_info 结构的指针

unsigned long page

要查找的内存页

返回

成功时,返回 csrow。如果未找到,则返回 -1。

void edac_raw_mc_handle_error(struct edac_raw_error_desc *e)

向用户空间报告内存事件,而不执行任何操作来发现错误位置。

参数

struct edac_raw_error_desc *e

错误描述

描述

此原始函数在内部由 edac_mc_handle_error() 使用。只有当硬件错误直接来自 BIOS 时,才应直接调用它,例如在 APEI GHES 驱动程序的情况下。

void edac_mc_handle_error(const enum hw_event_mc_err_type type, struct mem_ctl_info *mci, const u16 error_count, const unsigned long page_frame_number, const unsigned long offset_in_page, const unsigned long syndrome, const int top_layer, const int mid_layer, const int low_layer, const char *msg, const char *other_detail)

向用户空间报告内存事件。

参数

const enum hw_event_mc_err_type type

错误的严重程度(CE/UE/Fatal)

struct mem_ctl_info *mci

指向 mem_ctl_info 结构的指针

const u16 error_count

相同类型错误的数量

const unsigned long page_frame_number

发生错误的内存页

const unsigned long offset_in_page

错误在页面内的偏移量

const unsigned long syndrome

ECC 校验子

const int top_layer

内存层 [0] 位置

const int mid_layer

内存层 [1] 位置

const int low_layer

内存层 [2] 位置

const char *msg

对最终用户有意义的消息,用于解释事件

const char *other_detail

有关事件的技术细节,可能有助于硬件制造商和 EDAC 开发人员分析事件

PCI 控制器

EDAC 子系统提供了一种通过调用 edac_pci_alloc_ctl_info() 来处理 PCI 控制器的机制。它将使用结构体 edac_pci_ctl_info 来描述 PCI 控制器。

struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt, const char *edac_pci_name)

用于 'edac_pci' 控制信息结构的 alloc() 函数。

参数

unsigned int sz_pvt

结构体 edac_pci_ctl_info 中私有信息的大小

const char *edac_pci_name

PCI 设备的名称

描述

芯片驱动程序将为每个它将要控制/注册到 EDAC CORE 的 edac_pci 分配一个这些结构。

返回

成功时返回指向 edac_pci_ctl_info 结构体的指针;否则返回 NULL

void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci)

对 pci 控制结构体的最后操作。

参数

struct edac_pci_ctl_info *pci

指向 edac_pci_ctl_info 结构体的指针

描述

调用移除 sysfs 信息的操作,这将注销此控制结构的 kobj。当该 kobj 的引用计数变为零时,其释放函数将被调用,然后使用 kfree() 释放内存。

int edac_pci_alloc_index(void)

分配一个唯一的 PCI 索引号

参数

void

无参数

返回

已分配的索引号

int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)

将 ‘edac_dev’ 结构体插入到 edac_pci 全局列表,并创建与 edac_pci 结构体关联的 sysfs 条目。

参数

struct edac_pci_ctl_info *pci

要添加到列表中的 edac_device 结构体的指针

int edac_idx

要分配给 ‘edac_pci’ 结构体的唯一数字标识符。

返回

成功时返回 0,失败时返回错误代码

struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev)

参数

struct device *dev

指向表示要移除的 edac_pci 结构的 ‘struct device’ 的指针

描述

移除指定 edac_pci 结构的 sysfs 条目,然后从全局列表中移除 edac_pci 结构。

返回

指向已移除的 edac_pci 结构的指针,如果未找到设备则返回 NULL

struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev, const char *mod_name)

参数

struct device *dev

指向 device 结构体的指针;

const char *mod_name

PCI 设备的名称

描述

用于 PCI 奇偶校验轮询设备的通用构造函数。某些系统有多个 PCI 总线域。对于只有一个域的系统,此 API 将提供一个通用的轮询器。

此例程使用默认值调用通用设备的 edac_pci_alloc_ctl_info()

返回

成功时返回指向 edac_pci_ctl_info 结构体的指针,失败时返回 NULL

失败。

void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci)

参数

struct edac_pci_ctl_info *pci

指向 edac_pci_ctl_info 结构体的指针

描述

通用 EDAC PCI 轮询设备的释放函数

int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci)

参数

struct edac_pci_ctl_info *pci

指向 edac_pci_ctl_info 结构体的指针

描述

为指定的 EDAC PCI 设备创建控件/属性

void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci)

参数

struct edac_pci_ctl_info *pci

指向 edac_pci_ctl_info 结构体的指针

描述

移除此 EDAC PCI 设备的控件和属性

EDAC 块

EDAC 子系统还提供了一种通用机制,可以通过 edac_device_alloc_ctl_info() 函数报告硬件其他部分的错误。

结构体 edac_dev_sysfs_block_attributeedac_device_blockedac_device_instanceedac_device_ctl_info 在 sysfs 中提供了一种通用的或抽象的 ‘edac_device’ 表示。

这组结构体以及实现其 API 的代码,用于注册非标准内存或 PCI 的 EDAC 类型设备,例如:

  • CPU 缓存(L1 和 L2)

  • DMA 引擎

  • 核心 CPU 开关

  • Fabric 交换单元

  • PCIe 接口控制器

  • 其他可监测错误的 EDAC/ECC 类型设备等。

它允许两级层次结构。

例如,缓存可以由 L1、L2 和 L3 级别的缓存组成。每个 CPU 核心都有自己的 L1 缓存,同时共享 L2 和可能的 L3 缓存。在这种情况下,这些可以通过以下 sysfs 节点表示:

/sys/devices/system/edac/..

pci/            <existing pci directory (if available)>
mc/             <existing memory device directory>
cpu/cpu0/..     <L1 and L2 block directory>
        /L1-cache/ce_count
                 /ue_count
        /L2-cache/ce_count
                 /ue_count
cpu/cpu1/..     <L1 and L2 block directory>
        /L1-cache/ce_count
                 /ue_count
        /L2-cache/ce_count
                 /ue_count
...

the L1 and L2 directories would be "edac_device_block's"
int edac_device_add_device(struct edac_device_ctl_info *edac_dev)

将 ‘edac_dev’ 结构体插入到 edac_device 全局列表,并创建与 edac_device 结构体关联的 sysfs 条目。

参数

struct edac_device_ctl_info *edac_dev

指向要添加到 ‘edac_device’ 列表中的 edac_device 结构体的指针。

返回

成功时返回 0,失败时返回错误代码

struct edac_device_ctl_info *edac_device_del_device(struct device *dev)

移除指定 edac_device 结构的 sysfs 条目,然后从全局列表中移除 edac_device 结构。

参数

struct device *dev

指向表示要移除的 edac 设备结构的 device 结构体的指针。

返回

指向已移除的 edac_device 结构的指针,如果未找到设备则返回 NULL

void edac_device_handle_ce_count(struct edac_device_ctl_info *edac_dev, unsigned int count, int inst_nr, int block_nr, const char *msg)

记录可纠正错误。

参数

struct edac_device_ctl_info *edac_dev

指向 edac_device_ctl_info 结构体的指针

unsigned int count

要记录的错误数量。

int inst_nr

发生 CE 错误的实例编号

int block_nr

发生 CE 错误的块编号

const char *msg

要打印的消息

void edac_device_handle_ue_count(struct edac_device_ctl_info *edac_dev, unsigned int count, int inst_nr, int block_nr, const char *msg)

记录不可纠正错误。

参数

struct edac_device_ctl_info *edac_dev

指向 edac_device_ctl_info 结构体的指针

unsigned int count

要记录的错误数量。

int inst_nr

发生 CE 错误的实例编号

int block_nr

发生 CE 错误的块编号

const char *msg

要打印的消息

void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev, int inst_nr, int block_nr, const char *msg)

记录单个可纠正错误

参数

struct edac_device_ctl_info *edac_dev

指向 edac_device_ctl_info 结构体的指针

int inst_nr

发生 CE 错误的实例编号

int block_nr

发生 CE 错误的块编号

const char *msg

要打印的消息

void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev, int inst_nr, int block_nr, const char *msg)

记录单个不可纠正错误

参数

struct edac_device_ctl_info *edac_dev

指向 edac_device_ctl_info 结构体的指针

int inst_nr

发生UE错误的实例编号

int block_nr

发生UE错误的块编号

const char *msg

要打印的消息

int edac_device_alloc_index(void)

分配唯一的设备索引号

参数

void

无参数

返回

已分配的索引号

异构系统支持

AMD 异构系统是通过自定义 xGMI 链路连接 CPU 和 GPU 的数据结构而构建的。因此,可以像访问 CPU 节点上的数据结构一样访问 GPU 节点上的数据结构。

MI200 加速器是数据中心 GPU。它们有 2 个数据结构,每个 GPU 数据结构包含四个统一内存控制器 (UMC)。每个 UMC 包含八个通道。每个 UMC 通道控制一个 128 位 HBM2e (2GB) 通道(相当于 8 个 2GB 存储单元)。 这创建了一个总共 4096 位的 DRAM 数据总线。

虽然 UMC 接口的是一个 16GB (8高 x 2GB DRAM) HBM 堆栈,但每个 UMC 通道都接口 2GB 的 DRAM(表示为存储单元)。

AMD GPU 节点上的内存控制器可以在 EDAC 中表示如下

GPU DF / GPU 节点 -> EDAC MC GPU UMC -> EDAC CSROW GPU UMC 通道 -> EDAC 通道

例如:一个异构系统,其中 1 个 AMD CPU 通过 xGMI 连接到 4 个 MI200 (Aldebaran) GPU。

一些更详细的异构硬件信息

  • CPU UMC(统一内存控制器)与 GPU UMC 大致相同。它们有芯片选择(csrows)和通道。但是,出于性能、物理布局或其他原因,布局有所不同。

  • CPU UMC 使用 1 个通道,在这种情况下,UMC = EDAC 通道。这符合市场宣传。 CPU 有 X 个内存通道等。

  • CPU UMC 最多使用 4 个芯片选择,所以 UMC 芯片选择 = EDAC CSROW。

  • GPU UMC 使用 1 个芯片选择,所以 UMC = EDAC CSROW。

  • GPU UMC 使用 8 个通道,所以 UMC 通道 = EDAC 通道。

EDAC 子系统通过调用 CPU 和 GPU 的系统特定操作来提供处理 AMD 异构系统的机制。

AMD GPU 节点基于 PCI 层次结构按顺序枚举,并且假定第一个 GPU 节点的节点 ID 值在后者完全填充后,跟随 CPU 节点的节点 ID 值

$ ls /sys/devices/system/edac/mc/
        mc0   - CPU MC node 0
        mc1  |
        mc2  |- GPU card[0] => node 0(mc1), node 1(mc2)
        mc3  |
        mc4  |- GPU card[1] => node 0(mc3), node 1(mc4)
        mc5  |
        mc6  |- GPU card[2] => node 0(mc5), node 1(mc6)
        mc7  |
        mc8  |- GPU card[3] => node 0(mc7), node 1(mc8)

例如,一个异构系统,其中一个 AMD CPU 通过 xGMI 连接到四个 MI200 (Aldebaran) GPU。此拓扑可以通过以下 sysfs 条目表示

/sys/devices/system/edac/mc/..

CPU                     # CPU node
├── mc 0

GPU Nodes are enumerated sequentially after CPU nodes have been populated
GPU card 1              # Each MI200 GPU has 2 nodes/mcs
├── mc 1                # GPU node 0 == mc1, Each MC node has 4 UMCs/CSROWs
│   ├── csrow 0         # UMC 0
│   │   ├── channel 0   # Each UMC has 8 channels
│   │   ├── channel 1   # size of each channel is 2 GB, so each UMC has 16 GB
│   │   ├── channel 2
│   │   ├── channel 3
│   │   ├── channel 4
│   │   ├── channel 5
│   │   ├── channel 6
│   │   ├── channel 7
│   ├── csrow 1         # UMC 1
│   │   ├── channel 0
│   │   ├── ..
│   │   ├── channel 7
│   ├── ..              ..
│   ├── csrow 3         # UMC 3
│   │   ├── channel 0
│   │   ├── ..
│   │   ├── channel 7
│   ├── rank 0
│   ├── ..              ..
│   ├── rank 31         # total 32 ranks/dimms from 4 UMCs
├
├── mc 2                # GPU node 1 == mc2
│   ├── ..              # each GPU has total 64 GB

GPU card 2
├── mc 3
│   ├── ..
├── mc 4
│   ├── ..

GPU card 3
├── mc 5
│   ├── ..
├── mc 6
│   ├── ..

GPU card 4
├── mc 7
│   ├── ..
├── mc 8
│   ├── ..