Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

EDAC/i10nm: Add Intel Sapphire Rapids server support

The Sapphire Rapids CPU model shares the same memory controller
architecture with Ice Lake server. There are some configurations
different from Ice Lake server as below:
- The device ID for configuration agent.
- The size for per channel memory-mapped I/O.
- The DDR5 memory support.
So add the above configurations and the Sapphire Rapids CPU model
ID for EDAC support.

Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>

authored by

Qiuxu Zhuo and committed by
Tony Luck
479f58dd bc1c99a5

+58 -21
+25 -9
drivers/edac/i10nm_base.c
··· 13 13 #include "edac_module.h" 14 14 #include "skx_common.h" 15 15 16 - #define I10NM_REVISION "v0.0.3" 16 + #define I10NM_REVISION "v0.0.4" 17 17 #define EDAC_MOD_STR "i10nm_edac" 18 18 19 19 /* Debug macros */ ··· 25 25 #define I10NM_GET_IMC_BAR(d, i, reg) \ 26 26 pci_read_config_dword((d)->uracu, 0xd8 + (i) * 4, &(reg)) 27 27 #define I10NM_GET_DIMMMTR(m, i, j) \ 28 - readl((m)->mbase + 0x2080c + (i) * 0x4000 + (j) * 4) 28 + readl((m)->mbase + 0x2080c + (i) * (m)->chan_mmio_sz + (j) * 4) 29 29 #define I10NM_GET_MCDDRTCFG(m, i, j) \ 30 - readl((m)->mbase + 0x20970 + (i) * 0x4000 + (j) * 4) 30 + readl((m)->mbase + 0x20970 + (i) * (m)->chan_mmio_sz + (j) * 4) 31 31 #define I10NM_GET_MCMTR(m, i) \ 32 - readl((m)->mbase + 0x20ef8 + (i) * 0x4000) 32 + readl((m)->mbase + 0x20ef8 + (i) * (m)->chan_mmio_sz) 33 + #define I10NM_GET_AMAP(m, i) \ 34 + readl((m)->mbase + 0x20814 + (i) * (m)->chan_mmio_sz) 33 35 34 36 #define I10NM_GET_SCK_MMIO_BASE(reg) (GET_BITFIELD(reg, 0, 28) << 23) 35 37 #define I10NM_GET_IMC_MMIO_OFFSET(reg) (GET_BITFIELD(reg, 0, 10) << 12) ··· 131 129 .type = I10NM, 132 130 .decs_did = 0x3452, 133 131 .busno_cfg_offset = 0xcc, 132 + .ddr_chan_mmio_sz = 0x4000, 134 133 }; 135 134 136 135 static struct res_config i10nm_cfg1 = { 137 136 .type = I10NM, 138 137 .decs_did = 0x3452, 139 138 .busno_cfg_offset = 0xd0, 139 + .ddr_chan_mmio_sz = 0x4000, 140 + }; 141 + 142 + static struct res_config spr_cfg = { 143 + .type = SPR, 144 + .decs_did = 0x3252, 145 + .busno_cfg_offset = 0xd0, 146 + .ddr_chan_mmio_sz = 0x8000, 147 + .support_ddr5 = true, 140 148 }; 141 149 142 150 static const struct x86_cpu_id i10nm_cpuids[] = { ··· 155 143 X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(ICELAKE_X, X86_STEPPINGS(0x0, 0x3), &i10nm_cfg0), 156 144 X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(ICELAKE_X, X86_STEPPINGS(0x4, 0xf), &i10nm_cfg1), 157 145 X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(ICELAKE_D, X86_STEPPINGS(0x0, 0xf), &i10nm_cfg1), 146 + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SAPPHIRERAPIDS_X, X86_STEPPINGS(0x0, 0xf), &spr_cfg), 158 147 {} 159 148 }; 160 149 MODULE_DEVICE_TABLE(x86cpu, i10nm_cpuids); ··· 170 157 return !!GET_BITFIELD(mcmtr, 2, 2); 171 158 } 172 159 173 - static int i10nm_get_dimm_config(struct mem_ctl_info *mci) 160 + static int i10nm_get_dimm_config(struct mem_ctl_info *mci, 161 + struct res_config *cfg) 174 162 { 175 163 struct skx_pvt *pvt = mci->pvt_info; 176 164 struct skx_imc *imc = pvt->imc; 165 + u32 mtr, amap, mcddrtcfg; 177 166 struct dimm_info *dimm; 178 - u32 mtr, mcddrtcfg; 179 167 int i, j, ndimms; 180 168 181 169 for (i = 0; i < I10NM_NUM_CHANNELS; i++) { ··· 184 170 continue; 185 171 186 172 ndimms = 0; 173 + amap = I10NM_GET_AMAP(imc, i); 187 174 for (j = 0; j < I10NM_NUM_DIMMS; j++) { 188 175 dimm = edac_get_dimm(mci, i, j, 0); 189 176 mtr = I10NM_GET_DIMMMTR(imc, i, j); ··· 193 178 mtr, mcddrtcfg, imc->mc, i, j); 194 179 195 180 if (IS_DIMM_PRESENT(mtr)) 196 - ndimms += skx_get_dimm_info(mtr, 0, 0, dimm, 197 - imc, i, j); 181 + ndimms += skx_get_dimm_info(mtr, 0, amap, dimm, 182 + imc, i, j, cfg); 198 183 else if (IS_NVDIMM_PRESENT(mcddrtcfg, j)) 199 184 ndimms += skx_get_nvdimm_info(dimm, imc, i, j, 200 185 EDAC_MOD_STR); ··· 318 303 d->imc[i].lmc = i; 319 304 d->imc[i].src_id = src_id; 320 305 d->imc[i].node_id = node_id; 306 + d->imc[i].chan_mmio_sz = cfg->ddr_chan_mmio_sz; 321 307 322 308 rc = skx_register_mci(&d->imc[i], d->imc[i].mdev, 323 309 "Intel_10nm Socket", EDAC_MOD_STR, 324 - i10nm_get_dimm_config); 310 + i10nm_get_dimm_config, cfg); 325 311 if (rc < 0) 326 312 goto fail; 327 313 }
+3 -3
drivers/edac/skx_base.c
··· 174 174 return !!GET_BITFIELD(mcmtr, 2, 2); 175 175 } 176 176 177 - static int skx_get_dimm_config(struct mem_ctl_info *mci) 177 + static int skx_get_dimm_config(struct mem_ctl_info *mci, struct res_config *cfg) 178 178 { 179 179 struct skx_pvt *pvt = mci->pvt_info; 180 180 u32 mtr, mcmtr, amap, mcddrtcfg; ··· 195 195 pci_read_config_dword(imc->chan[i].cdev, 196 196 0x80 + 4 * j, &mtr); 197 197 if (IS_DIMM_PRESENT(mtr)) { 198 - ndimms += skx_get_dimm_info(mtr, mcmtr, amap, dimm, imc, i, j); 198 + ndimms += skx_get_dimm_info(mtr, mcmtr, amap, dimm, imc, i, j, cfg); 199 199 } else if (IS_NVDIMM_PRESENT(mcddrtcfg, j)) { 200 200 ndimms += skx_get_nvdimm_info(dimm, imc, i, j, 201 201 EDAC_MOD_STR); ··· 702 702 d->imc[i].node_id = node_id; 703 703 rc = skx_register_mci(&d->imc[i], d->imc[i].chan[0].cdev, 704 704 "Skylake Socket", EDAC_MOD_STR, 705 - skx_get_dimm_config); 705 + skx_get_dimm_config, cfg); 706 706 if (rc < 0) 707 707 goto fail; 708 708 }
+18 -5
drivers/edac/skx_common.c
··· 304 304 #define numcol(reg) skx_get_dimm_attr(reg, 0, 1, 10, 0, 2, "cols") 305 305 306 306 int skx_get_dimm_info(u32 mtr, u32 mcmtr, u32 amap, struct dimm_info *dimm, 307 - struct skx_imc *imc, int chan, int dimmno) 307 + struct skx_imc *imc, int chan, int dimmno, 308 + struct res_config *cfg) 308 309 { 309 - int banks = 16, ranks, rows, cols, npages; 310 + int banks, ranks, rows, cols, npages; 311 + enum mem_type mtype; 310 312 u64 size; 311 313 312 314 ranks = numrank(mtr); 313 315 rows = numrow(mtr); 314 316 cols = numcol(mtr); 317 + 318 + if (cfg->support_ddr5 && (amap & 0x8)) { 319 + banks = 32; 320 + mtype = MEM_DDR5; 321 + } else { 322 + banks = 16; 323 + mtype = MEM_DDR4; 324 + } 315 325 316 326 /* 317 327 * Compute size in 8-byte (2^3) words, then shift to MiB (2^20) ··· 342 332 dimm->nr_pages = npages; 343 333 dimm->grain = 32; 344 334 dimm->dtype = get_width(mtr); 345 - dimm->mtype = MEM_DDR4; 335 + dimm->mtype = mtype; 346 336 dimm->edac_mode = EDAC_SECDED; /* likely better than this */ 347 337 snprintf(dimm->label, sizeof(dimm->label), "CPU_SrcID#%u_MC#%u_Chan#%u_DIMM#%u", 348 338 imc->src_id, imc->lmc, chan, dimmno); ··· 400 390 401 391 int skx_register_mci(struct skx_imc *imc, struct pci_dev *pdev, 402 392 const char *ctl_name, const char *mod_str, 403 - get_dimm_config_f get_dimm_config) 393 + get_dimm_config_f get_dimm_config, 394 + struct res_config *cfg) 404 395 { 405 396 struct mem_ctl_info *mci; 406 397 struct edac_mc_layer layers[2]; ··· 436 425 } 437 426 438 427 mci->mtype_cap = MEM_FLAG_DDR4 | MEM_FLAG_NVDIMM; 428 + if (cfg->support_ddr5) 429 + mci->mtype_cap |= MEM_FLAG_DDR5; 439 430 mci->edac_ctl_cap = EDAC_FLAG_NONE; 440 431 mci->edac_cap = EDAC_FLAG_NONE; 441 432 mci->mod_name = mod_str; 442 433 mci->dev_name = pci_name(pdev); 443 434 mci->ctl_page_to_phys = NULL; 444 435 445 - rc = get_dimm_config(mci); 436 + rc = get_dimm_config(mci, cfg); 446 437 if (rc < 0) 447 438 goto fail; 448 439
+12 -4
drivers/edac/skx_common.h
··· 59 59 struct mem_ctl_info *mci; 60 60 struct pci_dev *mdev; /* for i10nm CPU */ 61 61 void __iomem *mbase; /* for i10nm CPU */ 62 + int chan_mmio_sz; /* for i10nm CPU */ 62 63 u8 mc; /* system wide mc# */ 63 64 u8 lmc; /* socket relative mc# */ 64 65 u8 src_id, node_id; ··· 83 82 84 83 enum type { 85 84 SKX, 86 - I10NM 85 + I10NM, 86 + SPR 87 87 }; 88 88 89 89 enum { ··· 120 118 unsigned int decs_did; 121 119 /* Default bus number configuration register offset */ 122 120 int busno_cfg_offset; 121 + /* Per DDR channel memory-mapped I/O size */ 122 + int ddr_chan_mmio_sz; 123 + bool support_ddr5; 123 124 }; 124 125 125 - typedef int (*get_dimm_config_f)(struct mem_ctl_info *mci); 126 + typedef int (*get_dimm_config_f)(struct mem_ctl_info *mci, 127 + struct res_config *cfg); 126 128 typedef bool (*skx_decode_f)(struct decoded_addr *res); 127 129 typedef void (*skx_show_retry_log_f)(struct decoded_addr *res, char *msg, int len); 128 130 ··· 142 136 int skx_get_hi_lo(unsigned int did, int off[], u64 *tolm, u64 *tohm); 143 137 144 138 int skx_get_dimm_info(u32 mtr, u32 mcmtr, u32 amap, struct dimm_info *dimm, 145 - struct skx_imc *imc, int chan, int dimmno); 139 + struct skx_imc *imc, int chan, int dimmno, 140 + struct res_config *cfg); 146 141 147 142 int skx_get_nvdimm_info(struct dimm_info *dimm, struct skx_imc *imc, 148 143 int chan, int dimmno, const char *mod_str); 149 144 150 145 int skx_register_mci(struct skx_imc *imc, struct pci_dev *pdev, 151 146 const char *ctl_name, const char *mod_str, 152 - get_dimm_config_f get_dimm_config); 147 + get_dimm_config_f get_dimm_config, 148 + struct res_config *cfg); 153 149 154 150 int skx_mce_check_error(struct notifier_block *nb, unsigned long val, 155 151 void *data);