From: Qiuxu Zhuo <[email protected]>

commit 1032095053b34d474aa20f2625d97dd306e0991b upstream.

The skx_edac driver wrongly uses the mtr register to retrieve two fields
close_pg and bank_xor_enable. Fix it by using the correct mcmtr register
to get the two fields.

Cc: <[email protected]>
Signed-off-by: Qiuxu Zhuo <[email protected]>
Reported-by: Matthew Riley <[email protected]>
Acked-by: Aristeu Rozanski <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
 drivers/edac/i10nm_base.c |    2 +-
 drivers/edac/skx_base.c   |   20 ++++++++------------
 drivers/edac/skx_common.c |    6 +++---
 drivers/edac/skx_common.h |    2 +-
 4 files changed, 13 insertions(+), 17 deletions(-)

--- a/drivers/edac/i10nm_base.c
+++ b/drivers/edac/i10nm_base.c
@@ -161,7 +161,7 @@ static int i10nm_get_dimm_config(struct
                                 mtr, mcddrtcfg, imc->mc, i, j);
 
                        if (IS_DIMM_PRESENT(mtr))
-                               ndimms += skx_get_dimm_info(mtr, 0, dimm,
+                               ndimms += skx_get_dimm_info(mtr, 0, 0, dimm,
                                                            imc, i, j);
                        else if (IS_NVDIMM_PRESENT(mcddrtcfg, j))
                                ndimms += skx_get_nvdimm_info(dimm, imc, i, j,
--- a/drivers/edac/skx_base.c
+++ b/drivers/edac/skx_base.c
@@ -163,27 +163,23 @@ static const struct x86_cpu_id skx_cpuid
 };
 MODULE_DEVICE_TABLE(x86cpu, skx_cpuids);
 
-#define SKX_GET_MTMTR(dev, reg) \
-       pci_read_config_dword((dev), 0x87c, &(reg))
-
-static bool skx_check_ecc(struct pci_dev *pdev)
+static bool skx_check_ecc(u32 mcmtr)
 {
-       u32 mtmtr;
-
-       SKX_GET_MTMTR(pdev, mtmtr);
-
-       return !!GET_BITFIELD(mtmtr, 2, 2);
+       return !!GET_BITFIELD(mcmtr, 2, 2);
 }
 
 static int skx_get_dimm_config(struct mem_ctl_info *mci)
 {
        struct skx_pvt *pvt = mci->pvt_info;
+       u32 mtr, mcmtr, amap, mcddrtcfg;
        struct skx_imc *imc = pvt->imc;
-       u32 mtr, amap, mcddrtcfg;
        struct dimm_info *dimm;
        int i, j;
        int ndimms;
 
+       /* Only the mcmtr on the first channel is effective */
+       pci_read_config_dword(imc->chan[0].cdev, 0x87c, &mcmtr);
+
        for (i = 0; i < SKX_NUM_CHANNELS; i++) {
                ndimms = 0;
                pci_read_config_dword(imc->chan[i].cdev, 0x8C, &amap);
@@ -193,14 +189,14 @@ static int skx_get_dimm_config(struct me
                        pci_read_config_dword(imc->chan[i].cdev,
                                              0x80 + 4 * j, &mtr);
                        if (IS_DIMM_PRESENT(mtr)) {
-                               ndimms += skx_get_dimm_info(mtr, amap, dimm, 
imc, i, j);
+                               ndimms += skx_get_dimm_info(mtr, mcmtr, amap, 
dimm, imc, i, j);
                        } else if (IS_NVDIMM_PRESENT(mcddrtcfg, j)) {
                                ndimms += skx_get_nvdimm_info(dimm, imc, i, j,
                                                              EDAC_MOD_STR);
                                nvdimm_count++;
                        }
                }
-               if (ndimms && !skx_check_ecc(imc->chan[0].cdev)) {
+               if (ndimms && !skx_check_ecc(mcmtr)) {
                        skx_printk(KERN_ERR, "ECC is disabled on imc %d\n", 
imc->mc);
                        return -ENODEV;
                }
--- a/drivers/edac/skx_common.c
+++ b/drivers/edac/skx_common.c
@@ -304,7 +304,7 @@ static int skx_get_dimm_attr(u32 reg, in
 #define numrow(reg)    skx_get_dimm_attr(reg, 2, 4, 12, 1, 6, "rows")
 #define numcol(reg)    skx_get_dimm_attr(reg, 0, 1, 10, 0, 2, "cols")
 
-int skx_get_dimm_info(u32 mtr, u32 amap, struct dimm_info *dimm,
+int skx_get_dimm_info(u32 mtr, u32 mcmtr, u32 amap, struct dimm_info *dimm,
                      struct skx_imc *imc, int chan, int dimmno)
 {
        int  banks = 16, ranks, rows, cols, npages;
@@ -324,8 +324,8 @@ int skx_get_dimm_info(u32 mtr, u32 amap,
                 imc->mc, chan, dimmno, size, npages,
                 banks, 1 << ranks, rows, cols);
 
-       imc->chan[chan].dimms[dimmno].close_pg = GET_BITFIELD(mtr, 0, 0);
-       imc->chan[chan].dimms[dimmno].bank_xor_enable = GET_BITFIELD(mtr, 9, 9);
+       imc->chan[chan].dimms[dimmno].close_pg = GET_BITFIELD(mcmtr, 0, 0);
+       imc->chan[chan].dimms[dimmno].bank_xor_enable = GET_BITFIELD(mcmtr, 9, 
9);
        imc->chan[chan].dimms[dimmno].fine_grain_bank = GET_BITFIELD(amap, 0, 
0);
        imc->chan[chan].dimms[dimmno].rowbits = rows;
        imc->chan[chan].dimms[dimmno].colbits = cols;
--- a/drivers/edac/skx_common.h
+++ b/drivers/edac/skx_common.h
@@ -128,7 +128,7 @@ int skx_get_all_bus_mappings(unsigned in
 
 int skx_get_hi_lo(unsigned int did, int off[], u64 *tolm, u64 *tohm);
 
-int skx_get_dimm_info(u32 mtr, u32 amap, struct dimm_info *dimm,
+int skx_get_dimm_info(u32 mtr, u32 mcmtr, u32 amap, struct dimm_info *dimm,
                      struct skx_imc *imc, int chan, int dimmno);
 
 int skx_get_nvdimm_info(struct dimm_info *dimm, struct skx_imc *imc,


Reply via email to