錯誤檢測和糾正 (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 *find_mci_by_dev(struct device *dev)

掃描控制器列表,查詢管理 dev 裝置的控制器。

引數

struct device *dev

指向與 MCI 相關的 struct device 的指標

返回

成功時,返回指向 struct 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

指向 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 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

指向 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_attributeedac_device_blockedac_device_instanceedac_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
│   ├── ..