Re: [PATCH v2 1/3] EDAC/loongson: Encode node and MC info into mc_idx
Huacai Chen <[email protected]>
| Newsgroups | org.kernel.vger.linux-edac,dev.linux.lists.loongarch,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <CAAhV-H7Fz4TTdpUn1z8hRx5QOBDAhrScLFa2DOcMY=iRwcWk1Q@mail.gmail.com> |
On Thu, Aug 6, 2026 at 9:36 AM Qunqin Zhao <[email protected]> wrote: > > > 在 2026/8/5 21:43, Huacai Chen 写道: > > Hi, Qunqin, > > > > On Wed, Aug 5, 2026 at 5:09 PM Qunqin Zhao <[email protected]> wrote: > >> 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 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 (mcs-per-node) is obtained > >> from firmware via ACPI _DSD property, with a default of 4 for backward > >> compatibility. Validate that the firmware-provided value is non-zero to > >> prevent division by zero. The node and MC IDs are decoded from mc_idx: > >> node = mc_idx / mcs_per_node > >> mc = mc_idx % mcs_per_node > >> > >> 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 | 35 ++++++++++++++++++++++++++++++----- > >> 1 file changed, 30 insertions(+), 5 deletions(-) > >> > >> diff --git a/drivers/edac/loongson_edac.c b/drivers/edac/loongson_edac.c > >> index 38745800ed..abfc1e60e0 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 mcs_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] = {0}; > >> + int new, add, node, mc; > >> > >> new = read_ecc(mci); > >> add = new - pvt->last_ce_count; > >> @@ -52,8 +56,14 @@ static void edac_check(struct mem_ctl_info *mci) > >> if (add <= 0) > >> return; > >> > >> + if (pvt->mc_idx_valid) { > >> + node = mci->mc_idx / pvt->mcs_per_node; > >> + mc = mci->mc_idx % pvt->mcs_per_node; > >> + snprintf(other_detail, sizeof(other_detail), "node:%d mc:%d", node, mc); > >> + } > >> + > >> 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 +82,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 mcs_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->mcs_per_node = mcs_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 mcs_per_node, mc_idx_u32; > > Why do we need mc_idx_u32? The code in V1 doesn't work? > > V1 works. This is purely to fix the issue reported by sashiko: > > "The mc_idx field is defined as an int in struct mem_ctl_info, but > device_property_read_u32() expects a u32 *. Should this be read into a > temporary u32 variable first?" > > Should we ignore it? I think we should ignore it, because: 1, it is impossible that mc_idx exceeds 2^31; 2, if mc_idx really exceeds 2^31, use mc_idx_u32 is still wrong when assign it to mci->mc_idx. Huacai > > > > >> int ret; > >> + bool mc_idx_valid = true; > >> > >> vbase = devm_platform_ioremap_resource(pdev, 0); > >> if (IS_ERR(vbase)) > >> @@ -102,7 +118,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 +129,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", &mc_idx_u32)) { > >> + mci->mc_idx = edac_device_alloc_index(); > >> + mc_idx_valid = false; > >> + } else { > >> + mci->mc_idx = mc_idx_u32; > >> + } > >> + > >> + if (device_property_read_u32(dev, "mc-per-node", &mcs_per_node) || mcs_per_node == 0) > > The property should also be mcs-per-node. > > OK > > Thanks. > > > Huacai > > > >> + mcs_per_node = 4; > >> + > >> + pvt_init(mci, vbase, mc_idx_valid, mcs_per_node); > >> dimm_config_init(mci); > >> > >> ret = edac_mc_add_mc(mci); > >> -- > >> 2.47.3 > >> > >> >