错误检测和纠正 (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 *edac_mc_del_mc(struct device *dev)¶
删除与 dev 关联的 mci 结构的 sysfs 条目,并从全局列表中删除 mci 结构。
-
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 device *dev
指向表示要移除的 edac_pci 结构的 ‘
struct device
’ 的指针
描述
移除指定 edac_pci 结构的 sysfs 条目,然后从全局列表中移除 edac_pci 结构。
返回
指向已移除的 edac_pci 结构的指针,如果未找到设备则返回
NULL
参数
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_attribute
、edac_device_block
、edac_device_instance
和 edac_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
│ ├── ..