Re: [PATCH v3 3/3] EDAC/loongson: Add CS4-7 timeout filter for cross-node access

Huacai Chen <[email protected]>
Newsgroups org.kernel.vger.linux-edac,dev.linux.lists.loongarch,org.kernel.vger.linux-kernel
Message-ID <CAAhV-H4fYO3QA2ouqFT46qKNs-P0KokAUf3hj=FKZZt+WumtXw@mail.gmail.com>
On Fri, Aug 14, 2026 at 3:33 PM Qunqin Zhao <[email protected]> wrote:
>
>
> 在 2026/8/12 14:41, Qunqin Zhao 写道:
>
>
> > On Loongson 3C6000 multi-node systems, when the EDAC driver running
> > on one node accesses the memory controller registers of another node,
> > the read operation may timeout and return random values. This causes
> > false CE error reports because the random values in CS0-3 (low 32 bits)
> > are misinterpreted as valid ECC error counts.
> >
> > For cross-node accesses, check CS4-7 (high 32 bits) of the ECC
> > count register. If the valid-cs-bits firmware property is set and
> > the high bits are non-zero, it indicates a timeout or random value,
> > so skip the report and return the previous count.
> >
> > To avoid undefined behavior on 8-CS systems where valid_cs_bits=64,
> > guard the shift with a bounds check (valid_cs_bits < 64).
> >
> > Signed-off-by: Wusheng <[email protected]>
> > Signed-off-by: Wang Jinwei <[email protected]>
> > Signed-off-by: Qunqin Zhao <[email protected]>
> > ---
> >   drivers/edac/loongson_edac.c | 25 ++++++++++++++++++++-----
> >   1 file changed, 20 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/edac/loongson_edac.c b/drivers/edac/loongson_edac.c
> > index a3776a8501..eb36b708e6 100644
> > --- a/drivers/edac/loongson_edac.c
> > +++ b/drivers/edac/loongson_edac.c
> > @@ -27,6 +27,7 @@ struct loongson_edac_pvt {
> >        */
> >       int last_ce_count;
> >       int mcs_per_node;
> > +     int valid_cs_bits;
>
> Thanks for the pointer. I've reviewed the Sashiko report and address each
> finding below.
>
> [Severity: Medium]
>
>
>  > The valid-cs-bits device property is parsed as a u32, but it is stored
>  > here as a signed int.
>  >
>  > If the device tree specifies a value >= 0x80000000, it would be cast to a
>  > negative integer. This could bypass the bounds check in read_ecc()
> where it
>  > checks pvt->valid_cs_bits < 64, resulting in a right-shift by a negative
>  > amount.
>  >
>  > Could this be declared as a u32 instead to avoid undefined behavior?
>
> I'll change `int valid_cs_bits` to `u32` in the struct and
> in the `pvt_init()` parameter.
If you really want to do this, please do the same changes for mcs_per_node.

Huacai

> >       bool mc_idx_valid;
> >   };
> >
> > @@ -37,11 +38,21 @@ static int read_ecc(struct mem_ctl_info *mci)
> >       int cs;
> >
> >       ecc = readq(pvt->ecc_base + ECC_CS_COUNT_REG);
> > -     /* cs0 -- cs3 */
> > +     /* Discard the read value if any invalid bit is set to 1 */
> > +     if (pvt->valid_cs_bits < 64 && (ecc >> pvt->valid_cs_bits)) {
> > +             edac_mc_printk(mci, KERN_DEBUG, "ECC read invalid, skip: 0x%llx\n", ecc);
> > +             return pvt->last_ce_count;
> > +     }
> [Severity: Medium]
>
>  > If the hardware read times out during probe, this will return the
>  > uninitialized pvt->last_ce_count (which is 0 since pvt_info is
>  > zero-allocated).
>  >
>  > Since pvt_init() uses this to set the baseline error count:
>  >
>  > drivers/edac/loongson_edac.c:pvt_init() {
>  >     ...
>  >     pvt->last_ce_count = read_ecc(mci);
>  > }
>  >
>  > Does this incorrectly set the baseline count to 0 if a timeout occurs
> on the
>  > first read? If so, on the next successful poll, the entire historical
> error
>  > count since system reset would be subtracted by 0 and falsely reported as
>  > newly occurred errors.
>
> This cannot be fixed in software:
>
> 1. Waiting for a "correct" read during probe could hang the kernel.
> 2. A bounded retry cannot guarantee correctness - all reads within the
> window
>     could still return bogus values.
> 3. The only thing software can do is print a debug message when a suspicious
>     value is detected, which this patch already does.
> > +
> > +     /* cs0 -- cs7 */
> >       cs = ecc & 0xff;
> >       cs += (ecc >> 8) & 0xff;
> >       cs += (ecc >> 16) & 0xff;
> >       cs += (ecc >> 24) & 0xff;
> > +     cs += (ecc >> 32) & 0xff;
> > +     cs += (ecc >> 40) & 0xff;
> > +     cs += (ecc >> 48) & 0xff;
> > +     cs += (ecc >> 56) & 0xff;
> >
> >       return cs;
> >   }
> > @@ -111,14 +122,15 @@ static void dimm_config_init(struct mem_ctl_info *mci)
> >   }
> >
> >   static void pvt_init(struct mem_ctl_info *mci, void __iomem *vbase,
> > -                  bool mc_idx_valid, int mcs_per_node)
> > +                  bool mc_idx_valid, int mcs_per_node, int valid_cs_bits)
> >   {
> >       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;
> > +     pvt->valid_cs_bits = valid_cs_bits;
> > +     pvt->last_ce_count = read_ecc(mci);
> >   }
> >
> >   static int edac_probe(struct platform_device *pdev)
> > @@ -127,7 +139,7 @@ static int edac_probe(struct platform_device *pdev)
> >       struct mem_ctl_info *mci;
> >       struct device *dev = &pdev->dev;
> >       void __iomem *vbase;
> > -     u32 mcs_per_node;
> > +     u32 mcs_per_node, valid_cs_bits;
> >       int ret;
> >       bool mc_idx_valid = true;
> >
> > @@ -165,7 +177,10 @@ static int edac_probe(struct platform_device *pdev)
> >       if (device_property_read_u32(dev, "mcs-per-node", &mcs_per_node) || mcs_per_node == 0)
> >               mcs_per_node = 4;
> >
> > -     pvt_init(mci, vbase, mc_idx_valid, mcs_per_node);
> > +     if (device_property_read_u32(dev, "valid-cs-bits", &valid_cs_bits))
> > +             valid_cs_bits = 32;
> [Severity: High]
>
>  > On older 8-CS systems lacking the valid-cs-bits firmware property, this
>  > defaults to 32.
>  >
>  > If a correctable error occurs on CS4-CS7 on these systems, the
> hardware ECC
>  > register will populate the upper 32 bits. The timeout filter in
> read_ecc()
>  > will incorrectly interpret this as a timeout and discard the read.
>  >
>  > Because the hardware ECC register is cumulative and cannot be
> cleared, the
>  > upper bits will remain non-zero permanently. Will this cause every
> subsequent
>  > poll to be discarded, effectively deadlocking EDAC error reporting
> for all
>  > chip selects on that node?
>
> This concern does not apply for two reasons:
>
> 1. There are no 8-CS systems at this point, so backward compatibility with
>     8-CS firmware is not something we need to account for. The
> `valid-cs-bits`
>     default of 32 matches the 4-CS hardware that the current firmware
> targets.
>
> 2. On 8-CS systems, all 64 bits of the register are valid counter bits, so
>     software cannot distinguish a correct read from a bogus one. Determining
>     whether a read is valid on such systems requires a hardware
> mechanism; no
>     software-only check can do it.
>
> Please let me know if this addresses your concerns; otherwise I'll send a v4
> with the Finding 1 fix.
>
> Thanks,
> Qunqin
> > +
> > +     pvt_init(mci, vbase, mc_idx_valid, mcs_per_node, valid_cs_bits);
> >       dimm_config_init(mci);
> >
> >       ret = edac_mc_add_mc(mci);
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.