[PATCH 1/3] EDAC/loongson: Encode node and MC info into mc_idx
Qunqin Zhao <[email protected]> Thu, 30 Jul 2026 14:30:33 +0800
| Newsgroups | dev.linux.lists.loongarch,org.kernel.vger.linux-edac,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
From: Wang Jinwei <[email protected]> On Loongson multi-node systems, memory controllers are distributed across multiple nodes. Encode node and MC information into mc_idx so that sysfs entries uniquely identify each controller. The driver gets mc-idx from ACPI _DSD property 'mc-idx' if firmware provides it. If not, it falls back to edac_device_alloc_index() for legacy firmware compatibility. The number of memory controllers per node (mc-per-node) is obtained from firmware via ACPI _DSD property, with a default of 4 for backward compatibility. The node and MC IDs are decoded from mc_idx: node = mc_idx / mc_per_node mc = mc_idx % mc_per_node For example, with mc-per-node=4: mc-idx 0-3 -> node0 mc0-mc3 mc-idx 4-7 -> node1 mc0-mc3 ... mc-idx 28-31 -> node7 mc0-mc3 The dmesg output looks like this: Before: (no _DSD mc-idx) EDAC MC3: 510 CE error on MC#3Channel#0_DIMM#0 (channel:0 slot:0 page:0x0 offset:0x0 grain:8 syndrome:0x0) After: (_DSD mc-idx) EDAC MC3: 510 CE error on MC#3Channel#0_DIMM#0 (channel:0 slot:0 page:0x0 offset:0x0 grain:8 syndrome:0x0 - node:0 mc:3) Cc: Yulong Wang <[email protected]> Cc: Dongyan Qian <[email protected]> Cc: Chao Li <[email protected]> Signed-off-by: Wang Jinwei <[email protected]> Signed-off-by: Qunqin Zhao <[email protected]> --- drivers/edac/loongson_edac.c | 38 +++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/drivers/edac/loongson_edac.c b/drivers/edac/loongson_edac.c index 38745800ed..f2452e98f5 100644 --- a/drivers/edac/loongson_edac.c +++ b/drivers/edac/loongson_edac.c @@ -9,6 +9,7 @@ #include <linux/io-64-nonatomic-lo-hi.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/property.h> #include "edac_module.h" #define ECC_CS_COUNT_REG 0x18 @@ -23,6 +24,8 @@ struct loongson_edac_pvt { * register state. */ int last_ce_count; + int mc_per_node; + bool mc_idx_valid; }; static int read_ecc(struct mem_ctl_info *mci) @@ -44,7 +47,8 @@ static int read_ecc(struct mem_ctl_info *mci) static void edac_check(struct mem_ctl_info *mci) { struct loongson_edac_pvt *pvt = mci->pvt_info; - int new, add; + char other_detail[64]; + int new, add, node, mc; new = read_ecc(mci); add = new - pvt->last_ce_count; @@ -52,8 +56,17 @@ static void edac_check(struct mem_ctl_info *mci) if (add <= 0) return; + if (pvt->mc_idx_valid) { + node = mci->mc_idx / pvt->mc_per_node; + mc = mci->mc_idx % pvt->mc_per_node; + snprintf(other_detail, sizeof(other_detail), + "node:%d mc:%d", node, mc); + } else { + other_detail[0] = '\0'; + } + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, add, - 0, 0, 0, 0, 0, -1, "error", ""); + 0, 0, 0, 0, 0, -1, "error", other_detail); } static void dimm_config_init(struct mem_ctl_info *mci) @@ -72,20 +85,26 @@ static void dimm_config_init(struct mem_ctl_info *mci) dimm->grain = 8; } -static void pvt_init(struct mem_ctl_info *mci, void __iomem *vbase) +static void pvt_init(struct mem_ctl_info *mci, void __iomem *vbase, + bool mc_idx_valid, int mc_per_node) { struct loongson_edac_pvt *pvt = mci->pvt_info; pvt->ecc_base = vbase; pvt->last_ce_count = read_ecc(mci); + pvt->mc_idx_valid = mc_idx_valid; + pvt->mc_per_node = mc_per_node; } static int edac_probe(struct platform_device *pdev) { struct edac_mc_layer layers[2]; struct mem_ctl_info *mci; + struct device *dev = &pdev->dev; void __iomem *vbase; + u32 mc_per_node; int ret; + bool mc_idx_valid; vbase = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(vbase)) @@ -102,7 +121,6 @@ static int edac_probe(struct platform_device *pdev) if (mci == NULL) return -ENOMEM; - mci->mc_idx = edac_device_alloc_index(); mci->mtype_cap = MEM_FLAG_RDDR4; mci->edac_ctl_cap = EDAC_FLAG_NONE; mci->edac_cap = EDAC_FLAG_NONE; @@ -114,7 +132,17 @@ static int edac_probe(struct platform_device *pdev) mci->error_desc.grain = 8; mci->edac_check = edac_check; - pvt_init(mci, vbase); + if (device_property_read_u32(dev, "mc-idx", &mci->mc_idx)) { + mci->mc_idx = edac_device_alloc_index(); + mc_idx_valid = false; + } else { + mc_idx_valid = true; + } + + if (device_property_read_u32(dev, "mc-per-node", &mc_per_node)) + mc_per_node = 4; + + pvt_init(mci, vbase, mc_idx_valid, mc_per_node); dimm_config_init(mci); ret = edac_mc_add_mc(mci); base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482 -- 2.47.2