错误检测和纠正 (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 是一种新型内存,具有低功耗和超宽通信通道。它使用垂直堆叠的内存芯片(DRAM 芯片),这些芯片通过称为“硅通孔”或 TSV 的微观导线互连。
多个 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
宽 I/O 2。
MEM_HBM2
高带宽内存 Gen 2。
MEM_HBM3
高带宽内存 Gen 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
SW 渐进式(顺序)擦洗
SCRUB_SW_SRC
仅软件擦洗错误
SCRUB_SW_PROG_SRC
从错误开始的渐进式软件擦洗
SCRUB_SW_TUNABLE
软件擦洗频率可调
SCRUB_HW_PROG
HW 渐进式(顺序)擦洗
SCRUB_HW_SRC
仅硬件擦洗错误
SCRUB_HW_PROG_SRC
从错误开始的渐进式硬件擦洗
SCRUB_HW_TUNABLE
硬件擦洗频率可调
-
enum edac_mc_layer_type¶
内存控制器层次结构层
常量
EDAC_MC_LAYER_BRANCH
内存层命名为“分支”
EDAC_MC_LAYER_CHANNEL
内存层命名为“通道”
EDAC_MC_LAYER_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 阵列的信息
定义:
struct rank_info {
int chan_idx;
struct csrow_info *csrow;
struct dimm_info *dimm;
u32 ce_count;
};
成员
chan_idx
阵列所在的通道号(通常为 0 或 1)
csrow
指向芯片选择行结构(父结构)的指针。阵列的位置由 (csrow->csrow_idx, chan_idx) 向量给出。
dimm
指向 DIMM 结构的指针,DIMM 标签信息存储在该结构中。
ce_count
此阵列的可纠正错误数
描述
- FIXME:目前,EDAC 核心模型将假设每个阵列一个 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 edac_scrub_ops¶
擦洗设备操作(所有元素都是可选的)
定义:
struct edac_scrub_ops {
int (*read_addr)(struct device *dev, void *drv_data, u64 *base);
int (*read_size)(struct device *dev, void *drv_data, u64 *size);
int (*write_addr)(struct device *dev, void *drv_data, u64 base);
int (*write_size)(struct device *dev, void *drv_data, u64 size);
int (*get_enabled_bg)(struct device *dev, void *drv_data, bool *enable);
int (*set_enabled_bg)(struct device *dev, void *drv_data, bool enable);
int (*get_min_cycle)(struct device *dev, void *drv_data, u32 *min);
int (*get_max_cycle)(struct device *dev, void *drv_data, u32 *max);
int (*get_cycle_duration)(struct device *dev, void *drv_data, u32 *cycle);
int (*set_cycle_duration)(struct device *dev, void *drv_data, u32 cycle);
};
成员
read_addr
读取擦洗范围的基地址。
read_size
读取擦洗范围的偏移量。
write_addr
设置擦洗范围的基地址。
write_size
设置擦洗范围的偏移量。
get_enabled_bg
检查当前是否正在执行后台擦洗。
set_enabled_bg
启动或停止后台擦洗。
get_min_cycle
以秒为单位获取支持的最小擦洗周期持续时间。
get_max_cycle
以秒为单位获取支持的最大擦洗周期持续时间。
get_cycle_duration
以秒为单位获取当前的擦洗周期持续时间。
set_cycle_duration
以秒为单位设置当前的擦洗周期持续时间。
-
struct edac_ecs_ops¶
ECS 设备操作(所有元素都是可选的)
定义:
struct edac_ecs_ops {
int (*get_log_entry_type)(struct device *dev, void *drv_data, int fru_id, u32 *val);
int (*set_log_entry_type)(struct device *dev, void *drv_data, int fru_id, u32 val);
int (*get_mode)(struct device *dev, void *drv_data, int fru_id, u32 *val);
int (*set_mode)(struct device *dev, void *drv_data, int fru_id, u32 val);
int (*reset)(struct device *dev, void *drv_data, int fru_id, u32 val);
int (*get_threshold)(struct device *dev, void *drv_data, int fru_id, u32 *threshold);
int (*set_threshold)(struct device *dev, void *drv_data, int fru_id, u32 threshold);
};
成员
get_log_entry_type
读取日志条目类型值。
set_log_entry_type
设置日志条目类型值。
get_mode
读取模式值。
set_mode
设置模式值。
reset
重置 ECS 计数器。
get_threshold
读取每千兆位存储单元的阈值计数。
set_threshold
设置每千兆位存储单元的阈值计数。
-
struct edac_mem_repair_ops¶
内存修复操作(除了 do_repair、set_hpa/set_dpa 之外,所有元素都是可选的)
定义:
struct edac_mem_repair_ops {
int (*get_repair_type)(struct device *dev, void *drv_data, const char **type);
int (*get_persist_mode)(struct device *dev, void *drv_data, bool *persist);
int (*set_persist_mode)(struct device *dev, void *drv_data, bool persist);
int (*get_repair_safe_when_in_use)(struct device *dev, void *drv_data, bool *safe);
int (*get_hpa)(struct device *dev, void *drv_data, u64 *hpa);
int (*set_hpa)(struct device *dev, void *drv_data, u64 hpa);
int (*get_min_hpa)(struct device *dev, void *drv_data, u64 *hpa);
int (*get_max_hpa)(struct device *dev, void *drv_data, u64 *hpa);
int (*get_dpa)(struct device *dev, void *drv_data, u64 *dpa);
int (*set_dpa)(struct device *dev, void *drv_data, u64 dpa);
int (*get_min_dpa)(struct device *dev, void *drv_data, u64 *dpa);
int (*get_max_dpa)(struct device *dev, void *drv_data, u64 *dpa);
int (*get_nibble_mask)(struct device *dev, void *drv_data, u32 *val);
int (*set_nibble_mask)(struct device *dev, void *drv_data, u32 val);
int (*get_bank_group)(struct device *dev, void *drv_data, u32 *val);
int (*set_bank_group)(struct device *dev, void *drv_data, u32 val);
int (*get_bank)(struct device *dev, void *drv_data, u32 *val);
int (*set_bank)(struct device *dev, void *drv_data, u32 val);
int (*get_rank)(struct device *dev, void *drv_data, u32 *val);
int (*set_rank)(struct device *dev, void *drv_data, u32 val);
int (*get_row)(struct device *dev, void *drv_data, u32 *val);
int (*set_row)(struct device *dev, void *drv_data, u32 val);
int (*get_column)(struct device *dev, void *drv_data, u32 *val);
int (*set_column)(struct device *dev, void *drv_data, u32 val);
int (*get_channel)(struct device *dev, void *drv_data, u32 *val);
int (*set_channel)(struct device *dev, void *drv_data, u32 val);
int (*get_sub_channel)(struct device *dev, void *drv_data, u32 *val);
int (*set_sub_channel)(struct device *dev, void *drv_data, u32 val);
int (*do_repair)(struct device *dev, void *drv_data, u32 val);
};
成员
get_repair_type
获取内存修复类型,在 enum edac_mem_repair_function 中列出。
get_persist_mode
获取当前的持久模式。false - 软件修复类型(临时修复)。true - 硬件内存修复类型(永久修复)。
set_persist_mode
设置内存修复实例的持久模式。
get_repair_safe_when_in_use
获取在修复操作期间是否可以访问存储介质并保留数据。
get_hpa
获取要修复的内存的当前主机物理地址 (HPA)。
set_hpa
设置要修复的内存的主机物理地址 (HPA)。
get_min_hpa
获取支持的最小主机物理地址 (HPA)。
get_max_hpa
获取支持的最大主机物理地址 (HPA)。
get_dpa
获取要修复的内存的当前设备物理地址 (DPA)。
set_dpa
设置要修复的内存的设备物理地址 (DPA)。在某些系统配置状态下(例如,在配置地址解码器之前),内存设备(例如 CXL)可能在主机物理地址映射中没有活动映射。因此,必须使用设备特定的物理寻址方案(使用设备物理地址 (DPA))来标识要修复的内存。用于修复操作的 DPA 和其他控制属性将显示在相关的错误记录中。
get_min_dpa
获取支持的最小设备物理地址 (DPA)。
get_max_dpa
获取支持的最大设备物理地址 (DPA)。
get_nibble_mask
获取要修复的内存的当前半字节掩码。
set_nibble_mask
设置要修复的内存的半字节掩码。
get_bank_group
获取要修复的内存的当前存储组。
set_bank_group
设置要修复的内存的存储组。
get_bank
获取要修复的内存的当前存储体。
set_bank
设置要修复的内存的存储体。
get_rank
获取要修复的内存的当前等级。
set_rank
设置要修复的内存的等级。
get_row
获取要修复的内存的当前行。
set_row
设置要修复的内存的行。
get_column
获取要修复的内存的当前列。
set_column
设置要修复的内存的列。
get_channel
获取要修复的内存的当前通道。
set_channel
设置要修复的内存的通道。
get_sub_channel
获取要修复的内存的当前子通道。
set_sub_channel
设置要修复的内存的子通道。
do_repair
对为要修复的内存设置的 HPA/DPA 和其他控制属性执行内存修复操作。
描述
除了 do_repair 和至少一个 set_hpa/set_dpa 之外,所有元素都是可选的。
-
struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num, unsigned int n_layers, struct edac_mc_layer *layers, unsigned int sz_pvt)¶
分配并部分填充一个 struct
mem_ctl_info
。
参数
unsigned int mc_num
内存控制器编号
unsigned int n_layers
MC 层次结构的层数
struct edac_mc_layer *layers
描述每个层,就像内存控制器看到的那样
unsigned int sz_pvt
所需的私有存储空间的大小
描述
一切都作为一大块进行 kmalloc'ed - 更高效。只有当所有结构都具有相同的生存期时才能使用 - 否则您必须分配并初始化自己的结构。
使用 edac_mc_free()
释放由此函数分配的 mc 结构。
注意
驱动程序以不同的方式处理多等级内存:在某些驱动程序中,一个多等级内存条被映射为一个条目,而在另一些驱动程序中,单个多等级内存条将被映射到多个条目中。目前,此函数将在这种情况下分配多个 struct dimm_info,因为对多个等级进行分组需要更改驱动程序。
返回
成功时,返回指向 struct 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
指向 struct 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
指向 struct 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
struct 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 控制器的机制。它将使用 struct 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’ 控制信息结构体分配内存的函数。
参数
unsigned int sz_pvt
struct
edac_pci_ctl_info
中私有信息的大小。const char *edac_pci_name
PCI 设备的名字
描述
芯片驱动程序将为每个它要控制/注册到 EDAC CORE 的 edac_pci 分配一个这样的结构体。
返回
成功时返回指向 struct edac_pci_ctl_info
的指针;否则返回 NULL
。
-
void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci)¶
在 pci 控制结构上的最后一个操作。
参数
struct edac_pci_ctl_info *pci
指向 struct
edac_pci_ctl_info
的指针
描述
调用 remove sysfs 信息,这将注销此控制结构体的 kobj。当 kobj 的引用计数变为零时,将调用其 release 函数,然后使用 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
指向 struct
device
的指针;const char *mod_name
PCI 设备的名字
描述
用于 PCI 奇偶校验轮询设备的通用构造函数。一些系统有多个 PCI 总线域。对于只有一个域的系统,此 API 将提供一个通用轮询器。
此例程使用默认值调用通用设备的 edac_pci_alloc_ctl_info()
返回
- 成功时返回指向 struct
edac_pci_ctl_info
的指针,失败时返回NULL
。 失败。
-
void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci)¶
参数
struct edac_pci_ctl_info *pci
指向 struct
edac_pci_ctl_info
的指针
描述
通用 EDAC PCI 轮询设备的释放函数
-
int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci)¶
参数
struct edac_pci_ctl_info *pci
指向 struct
edac_pci_ctl_info
的指针
描述
为指定的 EDAC PCI 设备创建控件/属性
-
void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci)¶
参数
struct edac_pci_ctl_info *pci
指向 struct
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 的代码提供了注册 EDAC 类型设备的功能,这些设备不是标准内存或 PCI 设备,例如
CPU 缓存(L1 和 L2)
DMA 引擎
核心 CPU 交换机
Fabric 交换单元
PCIe 接口控制器
可以监控错误等的其他 EDAC/ECC 类型设备。
它允许 2 级层次结构。
例如,缓存可以由 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 结构的 struct
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
指向 struct
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
指向 struct
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
指向 struct
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
指向 struct
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 X 2GB 秩)。这创建了一个总共 4096 位的 DRAM 数据总线。
虽然 UMC 接口一个 16GB(8high 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 值完全填充后跟随 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
│ ├── ..