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

EDAC/{skx_common,imh}: Add EDAC driver for Intel Diamond Rapids servers

Intel Diamond Rapids CPUs include Integrated Memory and I/O Hubs (IMH).
The memory controllers within the IMHs provide memory stacks to the
processor. Create a new driver for this IMH-based memory controllers
rather than applying additional patches to the existing i10nm_edac.c
for the following reasons:

1) The memory controllers are not presented as PCI devices; instead,
the detection and all their registers have been transitioned to
MMIO-based memory spaces.

2) Validation processes are costly. Modifications to i10nm_edac would
require extensive validation checks against multiple platforms,
including Ice Lake, Sapphire Rapids, Emerald Rapids, Granite Rapids,
Sierra Forest, and Grand Ridge.

3) Future Intel CPUs will likely only need patches on top of this new
EDAC driver. Validation can be limited to Diamond Rapids servers
and future Intel CPU generations.

[Tony: Fix kerneldoc for struct local_reg]
[randconfig: Added dependencies on NFIT and DMI]

Tested-by: Yi Lai <yi1.lai@intel.com>
Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Link: https://patch.msgid.link/20251119134132.2389472-5-qiuxu.zhuo@intel.com

authored by

Qiuxu Zhuo and committed by
Tony Luck
9fc67b11 d4839582

+648 -26
+12
drivers/edac/Kconfig
··· 283 283 system has non-volatile DIMMs you should also manually 284 284 select CONFIG_ACPI_NFIT. 285 285 286 + config EDAC_IMH 287 + tristate "Intel Integrated Memory/IO Hub MC" 288 + depends on X86_64 && X86_MCE_INTEL && ACPI 289 + depends on ACPI_NFIT || !ACPI_NFIT # if ACPI_NFIT=m, EDAC_IMH can't be y 290 + select DMI 291 + select ACPI_ADXL 292 + help 293 + Support for error detection and correction the Intel 294 + Integrated Memory/IO Hub Memory Controller. This MC IP is 295 + first used on the Diamond Rapids servers but may appear on 296 + others in the future. 297 + 286 298 config EDAC_PND2 287 299 tristate "Intel Pondicherry2" 288 300 depends on PCI && X86_64 && X86_MCE_INTEL
+3
drivers/edac/Makefile
··· 65 65 i10nm_edac-y := i10nm_base.o 66 66 obj-$(CONFIG_EDAC_I10NM) += i10nm_edac.o skx_edac_common.o 67 67 68 + imh_edac-y := imh_base.o 69 + obj-$(CONFIG_EDAC_IMH) += imh_edac.o skx_edac_common.o 70 + 68 71 obj-$(CONFIG_EDAC_HIGHBANK_MC) += highbank_mc_edac.o 69 72 obj-$(CONFIG_EDAC_HIGHBANK_L2) += highbank_l2_edac.o 70 73
+562
drivers/edac/imh_base.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Driver for Intel(R) servers with Integrated Memory/IO Hub-based memory controller. 4 + * Copyright (c) 2025, Intel Corporation. 5 + */ 6 + 7 + #include <linux/kernel.h> 8 + #include <linux/io.h> 9 + #include <asm/cpu_device_id.h> 10 + #include <asm/intel-family.h> 11 + #include <asm/mce.h> 12 + #include <asm/cpu.h> 13 + #include "edac_module.h" 14 + #include "skx_common.h" 15 + 16 + #define IMH_REVISION "v0.0.1" 17 + #define EDAC_MOD_STR "imh_edac" 18 + 19 + /* Debug macros */ 20 + #define imh_printk(level, fmt, arg...) \ 21 + edac_printk(level, "imh", fmt, ##arg) 22 + 23 + /* Configuration Agent(Ubox) */ 24 + #define MMIO_BASE_H(reg) (((u64)GET_BITFIELD(reg, 0, 29)) << 23) 25 + #define SOCKET_ID(reg) GET_BITFIELD(reg, 0, 3) 26 + 27 + /* PUNIT */ 28 + #define DDR_IMC_BITMAP(reg) GET_BITFIELD(reg, 23, 30) 29 + 30 + /* Memory Controller */ 31 + #define ECC_ENABLED(reg) GET_BITFIELD(reg, 2, 2) 32 + #define DIMM_POPULATED(reg) GET_BITFIELD(reg, 15, 15) 33 + 34 + /* System Cache Agent(SCA) */ 35 + #define TOLM(reg) (((u64)GET_BITFIELD(reg, 16, 31)) << 16) 36 + #define TOHM(reg) (((u64)GET_BITFIELD(reg, 16, 51)) << 16) 37 + 38 + /** 39 + * struct local_reg - A register as described in the local package view. 40 + * 41 + * @pkg: (input) The package where the register is located. 42 + * @pbase: (input) The IP MMIO base physical address in the local package view. 43 + * @size: (input) The IP MMIO size. 44 + * @offset: (input) The register offset from the IP MMIO base @pbase. 45 + * @width: (input) The register width in byte. 46 + * @vbase: (internal) The IP MMIO base virtual address. 47 + * @val: (output) The register value. 48 + */ 49 + struct local_reg { 50 + int pkg; 51 + u64 pbase; 52 + u32 size; 53 + u32 offset; 54 + u8 width; 55 + void __iomem *vbase; 56 + u64 val; 57 + }; 58 + 59 + #define DEFINE_LOCAL_REG(name, cfg, package, north, ip_name, ip_idx, reg_name) \ 60 + struct local_reg name = { \ 61 + .pkg = package, \ 62 + .pbase = (north ? (cfg)->mmio_base_l_north : \ 63 + (cfg)->mmio_base_l_south) + \ 64 + (cfg)->ip_name##_base + \ 65 + (cfg)->ip_name##_size * (ip_idx), \ 66 + .size = (cfg)->ip_name##_size, \ 67 + .offset = (cfg)->ip_name##_reg_##reg_name##_offset, \ 68 + .width = (cfg)->ip_name##_reg_##reg_name##_width, \ 69 + } 70 + 71 + static u64 readx(void __iomem *addr, u8 width) 72 + { 73 + switch (width) { 74 + case 1: 75 + return readb(addr); 76 + case 2: 77 + return readw(addr); 78 + case 4: 79 + return readl(addr); 80 + case 8: 81 + return readq(addr); 82 + default: 83 + imh_printk(KERN_ERR, "Invalid reg 0x%p width %d\n", addr, width); 84 + return 0; 85 + } 86 + } 87 + 88 + static void __read_local_reg(void *reg) 89 + { 90 + struct local_reg *r = (struct local_reg *)reg; 91 + 92 + r->val = readx(r->vbase + r->offset, r->width); 93 + } 94 + 95 + /* Read a local-view register. */ 96 + static bool read_local_reg(struct local_reg *reg) 97 + { 98 + int cpu; 99 + 100 + /* Get the target CPU in the package @reg->pkg. */ 101 + for_each_online_cpu(cpu) { 102 + if (reg->pkg == topology_physical_package_id(cpu)) 103 + break; 104 + } 105 + 106 + if (cpu >= nr_cpu_ids) 107 + return false; 108 + 109 + reg->vbase = ioremap(reg->pbase, reg->size); 110 + if (!reg->vbase) { 111 + imh_printk(KERN_ERR, "Failed to ioremap 0x%llx\n", reg->pbase); 112 + return false; 113 + } 114 + 115 + /* Get the target CPU to read the register. */ 116 + smp_call_function_single(cpu, __read_local_reg, reg, 1); 117 + iounmap(reg->vbase); 118 + 119 + return true; 120 + } 121 + 122 + /* Get the bitmap of memory controller instances in package @pkg. */ 123 + static u32 get_imc_bitmap(struct res_config *cfg, int pkg, bool north) 124 + { 125 + DEFINE_LOCAL_REG(reg, cfg, pkg, north, pcu, 0, capid3); 126 + 127 + if (!read_local_reg(&reg)) 128 + return 0; 129 + 130 + edac_dbg(2, "Pkg%d %s mc instances bitmap 0x%llx (reg 0x%llx)\n", 131 + pkg, north ? "north" : "south", 132 + DDR_IMC_BITMAP(reg.val), reg.val); 133 + 134 + return DDR_IMC_BITMAP(reg.val); 135 + } 136 + 137 + static void imc_release(struct device *dev) 138 + { 139 + edac_dbg(2, "imc device %s released\n", dev_name(dev)); 140 + kfree(dev); 141 + } 142 + 143 + static int __get_ddr_munits(struct res_config *cfg, struct skx_dev *d, 144 + bool north, int lmc) 145 + { 146 + unsigned long size = cfg->ddr_chan_mmio_sz * cfg->ddr_chan_num; 147 + unsigned long bitmap = get_imc_bitmap(cfg, d->pkg, north); 148 + void __iomem *mbase; 149 + struct device *dev; 150 + int i, rc, pmc; 151 + u64 base; 152 + 153 + for_each_set_bit(i, &bitmap, sizeof(bitmap) * 8) { 154 + base = north ? d->mmio_base_h_north : d->mmio_base_h_south; 155 + base += cfg->ddr_imc_base + size * i; 156 + 157 + edac_dbg(2, "Pkg%d mc%d mmio base 0x%llx size 0x%lx\n", 158 + d->pkg, lmc, base, size); 159 + 160 + /* Set up the imc MMIO. */ 161 + mbase = ioremap(base, size); 162 + if (!mbase) { 163 + imh_printk(KERN_ERR, "Failed to ioremap 0x%llx\n", base); 164 + return -ENOMEM; 165 + } 166 + 167 + d->imc[lmc].mbase = mbase; 168 + d->imc[lmc].lmc = lmc; 169 + 170 + /* Create the imc device instance. */ 171 + dev = kzalloc(sizeof(*dev), GFP_KERNEL); 172 + if (!dev) 173 + return -ENOMEM; 174 + 175 + dev->release = imc_release; 176 + device_initialize(dev); 177 + rc = dev_set_name(dev, "0x%llx", base); 178 + if (rc) { 179 + imh_printk(KERN_ERR, "Failed to set dev name\n"); 180 + put_device(dev); 181 + return rc; 182 + } 183 + 184 + d->imc[lmc].dev = dev; 185 + 186 + /* Set up the imc index mapping. */ 187 + pmc = north ? i : 8 + i; 188 + skx_set_mc_mapping(d, pmc, lmc); 189 + 190 + lmc++; 191 + } 192 + 193 + return lmc; 194 + } 195 + 196 + static bool get_ddr_munits(struct res_config *cfg, struct skx_dev *d) 197 + { 198 + int lmc = __get_ddr_munits(cfg, d, true, 0); 199 + 200 + if (lmc < 0) 201 + return false; 202 + 203 + lmc = __get_ddr_munits(cfg, d, false, lmc); 204 + if (lmc <= 0) 205 + return false; 206 + 207 + return true; 208 + } 209 + 210 + static bool get_socket_id(struct res_config *cfg, struct skx_dev *d) 211 + { 212 + DEFINE_LOCAL_REG(reg, cfg, d->pkg, true, ubox, 0, socket_id); 213 + u8 src_id; 214 + int i; 215 + 216 + if (!read_local_reg(&reg)) 217 + return false; 218 + 219 + src_id = SOCKET_ID(reg.val); 220 + edac_dbg(2, "socket id 0x%x (reg 0x%llx)\n", src_id, reg.val); 221 + 222 + for (i = 0; i < cfg->ddr_imc_num; i++) 223 + d->imc[i].src_id = src_id; 224 + 225 + return true; 226 + } 227 + 228 + /* Get TOLM (Top Of Low Memory) and TOHM (Top Of High Memory) parameters. */ 229 + static bool imh_get_tolm_tohm(struct res_config *cfg, u64 *tolm, u64 *tohm) 230 + { 231 + DEFINE_LOCAL_REG(reg, cfg, 0, true, sca, 0, tolm); 232 + 233 + if (!read_local_reg(&reg)) 234 + return false; 235 + 236 + *tolm = TOLM(reg.val); 237 + edac_dbg(2, "tolm 0x%llx (reg 0x%llx)\n", *tolm, reg.val); 238 + 239 + DEFINE_LOCAL_REG(reg2, cfg, 0, true, sca, 0, tohm); 240 + 241 + if (!read_local_reg(&reg2)) 242 + return false; 243 + 244 + *tohm = TOHM(reg2.val); 245 + edac_dbg(2, "tohm 0x%llx (reg 0x%llx)\n", *tohm, reg2.val); 246 + 247 + return true; 248 + } 249 + 250 + /* Get the system-view MMIO_BASE_H for {north,south}-IMH. */ 251 + static int imh_get_all_mmio_base_h(struct res_config *cfg, struct list_head *edac_list) 252 + { 253 + int i, n = topology_max_packages(), imc_num = cfg->ddr_imc_num + cfg->hbm_imc_num; 254 + struct skx_dev *d; 255 + 256 + for (i = 0; i < n; i++) { 257 + d = kzalloc(struct_size(d, imc, imc_num), GFP_KERNEL); 258 + if (!d) 259 + return -ENOMEM; 260 + 261 + DEFINE_LOCAL_REG(reg, cfg, i, true, ubox, 0, mmio_base); 262 + 263 + /* Get MMIO_BASE_H for the north-IMH. */ 264 + if (!read_local_reg(&reg) || !reg.val) { 265 + kfree(d); 266 + imh_printk(KERN_ERR, "Pkg%d has no north mmio_base_h\n", i); 267 + return -ENODEV; 268 + } 269 + 270 + d->mmio_base_h_north = MMIO_BASE_H(reg.val); 271 + edac_dbg(2, "Pkg%d north mmio_base_h 0x%llx (reg 0x%llx)\n", 272 + i, d->mmio_base_h_north, reg.val); 273 + 274 + /* Get MMIO_BASE_H for the south-IMH (optional). */ 275 + DEFINE_LOCAL_REG(reg2, cfg, i, false, ubox, 0, mmio_base); 276 + 277 + if (read_local_reg(&reg2)) { 278 + d->mmio_base_h_south = MMIO_BASE_H(reg2.val); 279 + edac_dbg(2, "Pkg%d south mmio_base_h 0x%llx (reg 0x%llx)\n", 280 + i, d->mmio_base_h_south, reg2.val); 281 + } 282 + 283 + d->pkg = i; 284 + d->num_imc = imc_num; 285 + skx_init_mc_mapping(d); 286 + list_add_tail(&d->list, edac_list); 287 + } 288 + 289 + return 0; 290 + } 291 + 292 + /* Get the number of per-package memory controllers. */ 293 + static int imh_get_imc_num(struct res_config *cfg) 294 + { 295 + int imc_num = hweight32(get_imc_bitmap(cfg, 0, true)) + 296 + hweight32(get_imc_bitmap(cfg, 0, false)); 297 + 298 + if (!imc_num) { 299 + imh_printk(KERN_ERR, "Invalid mc number\n"); 300 + return -ENODEV; 301 + } 302 + 303 + if (cfg->ddr_imc_num != imc_num) { 304 + /* 305 + * Update the configuration data to reflect the number of 306 + * present DDR memory controllers. 307 + */ 308 + cfg->ddr_imc_num = imc_num; 309 + edac_dbg(2, "Set ddr mc number %d\n", imc_num); 310 + } 311 + 312 + return 0; 313 + } 314 + 315 + /* Get all memory controllers' parameters. */ 316 + static int imh_get_munits(struct res_config *cfg, struct list_head *edac_list) 317 + { 318 + struct skx_imc *imc; 319 + struct skx_dev *d; 320 + u8 mc = 0; 321 + int i; 322 + 323 + list_for_each_entry(d, edac_list, list) { 324 + if (!get_ddr_munits(cfg, d)) { 325 + imh_printk(KERN_ERR, "No mc found\n"); 326 + return -ENODEV; 327 + } 328 + 329 + if (!get_socket_id(cfg, d)) { 330 + imh_printk(KERN_ERR, "Failed to get socket id\n"); 331 + return -ENODEV; 332 + } 333 + 334 + for (i = 0; i < cfg->ddr_imc_num; i++) { 335 + imc = &d->imc[i]; 336 + if (!imc->mbase) 337 + continue; 338 + 339 + imc->chan_mmio_sz = cfg->ddr_chan_mmio_sz; 340 + imc->num_channels = cfg->ddr_chan_num; 341 + imc->num_dimms = cfg->ddr_dimm_num; 342 + imc->mc = mc++; 343 + } 344 + } 345 + 346 + return 0; 347 + } 348 + 349 + /* Helpers to read memory controller registers */ 350 + static u64 read_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width) 351 + { 352 + return readx(imc->mbase + imc->chan_mmio_sz * chan + offset, width); 353 + } 354 + 355 + static u32 read_imc_mcmtr(struct res_config *cfg, struct skx_imc *imc, int chan) 356 + { 357 + return (u32)read_imc_reg(imc, chan, cfg->ddr_reg_mcmtr_offset, cfg->ddr_reg_mcmtr_width); 358 + } 359 + 360 + static u32 read_imc_dimmmtr(struct res_config *cfg, struct skx_imc *imc, int chan, int dimm) 361 + { 362 + return (u32)read_imc_reg(imc, chan, cfg->ddr_reg_dimmmtr_offset + 363 + cfg->ddr_reg_dimmmtr_width * dimm, 364 + cfg->ddr_reg_dimmmtr_width); 365 + } 366 + 367 + static bool ecc_enabled(u32 mcmtr) 368 + { 369 + return (bool)ECC_ENABLED(mcmtr); 370 + } 371 + 372 + static bool dimm_populated(u32 dimmmtr) 373 + { 374 + return (bool)DIMM_POPULATED(dimmmtr); 375 + } 376 + 377 + /* Get each DIMM's configurations of the memory controller @mci. */ 378 + static int imh_get_dimm_config(struct mem_ctl_info *mci, struct res_config *cfg) 379 + { 380 + struct skx_pvt *pvt = mci->pvt_info; 381 + struct skx_imc *imc = pvt->imc; 382 + struct dimm_info *dimm; 383 + u32 mcmtr, dimmmtr; 384 + int i, j, ndimms; 385 + 386 + for (i = 0; i < imc->num_channels; i++) { 387 + if (!imc->mbase) 388 + continue; 389 + 390 + mcmtr = read_imc_mcmtr(cfg, imc, i); 391 + 392 + for (ndimms = 0, j = 0; j < imc->num_dimms; j++) { 393 + dimmmtr = read_imc_dimmmtr(cfg, imc, i, j); 394 + edac_dbg(1, "mcmtr 0x%x dimmmtr 0x%x (mc%d ch%d dimm%d)\n", 395 + mcmtr, dimmmtr, imc->mc, i, j); 396 + 397 + if (!dimm_populated(dimmmtr)) 398 + continue; 399 + 400 + dimm = edac_get_dimm(mci, i, j, 0); 401 + ndimms += skx_get_dimm_info(dimmmtr, 0, 0, dimm, 402 + imc, i, j, cfg); 403 + } 404 + 405 + if (ndimms && !ecc_enabled(mcmtr)) { 406 + imh_printk(KERN_ERR, "ECC is disabled on mc%d ch%d\n", 407 + imc->mc, i); 408 + return -ENODEV; 409 + } 410 + } 411 + 412 + return 0; 413 + } 414 + 415 + /* Register all memory controllers to the EDAC core. */ 416 + static int imh_register_mci(struct res_config *cfg, struct list_head *edac_list) 417 + { 418 + struct skx_imc *imc; 419 + struct skx_dev *d; 420 + int i, rc; 421 + 422 + list_for_each_entry(d, edac_list, list) { 423 + for (i = 0; i < cfg->ddr_imc_num; i++) { 424 + imc = &d->imc[i]; 425 + if (!imc->mbase) 426 + continue; 427 + 428 + rc = skx_register_mci(imc, imc->dev, 429 + dev_name(imc->dev), 430 + "Intel IMH-based Socket", 431 + EDAC_MOD_STR, 432 + imh_get_dimm_config, cfg); 433 + if (rc) 434 + return rc; 435 + } 436 + } 437 + 438 + return 0; 439 + } 440 + 441 + static struct res_config dmr_cfg = { 442 + .type = DMR, 443 + .support_ddr5 = true, 444 + .mmio_base_l_north = 0xf6800000, 445 + .mmio_base_l_south = 0xf6000000, 446 + .ddr_chan_num = 1, 447 + .ddr_dimm_num = 2, 448 + .ddr_imc_base = 0x39b000, 449 + .ddr_chan_mmio_sz = 0x8000, 450 + .ddr_reg_mcmtr_offset = 0x360, 451 + .ddr_reg_mcmtr_width = 4, 452 + .ddr_reg_dimmmtr_offset = 0x370, 453 + .ddr_reg_dimmmtr_width = 4, 454 + .ubox_base = 0x0, 455 + .ubox_size = 0x2000, 456 + .ubox_reg_mmio_base_offset = 0x580, 457 + .ubox_reg_mmio_base_width = 4, 458 + .ubox_reg_socket_id_offset = 0x1080, 459 + .ubox_reg_socket_id_width = 4, 460 + .pcu_base = 0x3000, 461 + .pcu_size = 0x10000, 462 + .pcu_reg_capid3_offset = 0x290, 463 + .pcu_reg_capid3_width = 4, 464 + .sca_base = 0x24c000, 465 + .sca_size = 0x2500, 466 + .sca_reg_tolm_offset = 0x2100, 467 + .sca_reg_tolm_width = 8, 468 + .sca_reg_tohm_offset = 0x2108, 469 + .sca_reg_tohm_width = 8, 470 + }; 471 + 472 + static const struct x86_cpu_id imh_cpuids[] = { 473 + X86_MATCH_VFM(INTEL_DIAMONDRAPIDS_X, &dmr_cfg), 474 + {} 475 + }; 476 + MODULE_DEVICE_TABLE(x86cpu, imh_cpuids); 477 + 478 + static struct notifier_block imh_mce_dec = { 479 + .notifier_call = skx_mce_check_error, 480 + .priority = MCE_PRIO_EDAC, 481 + }; 482 + 483 + static int __init imh_init(void) 484 + { 485 + const struct x86_cpu_id *id; 486 + struct list_head *edac_list; 487 + struct res_config *cfg; 488 + const char *owner; 489 + u64 tolm, tohm; 490 + int rc; 491 + 492 + edac_dbg(2, "\n"); 493 + 494 + if (ghes_get_devices()) 495 + return -EBUSY; 496 + 497 + owner = edac_get_owner(); 498 + if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR))) 499 + return -EBUSY; 500 + 501 + if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) 502 + return -ENODEV; 503 + 504 + id = x86_match_cpu(imh_cpuids); 505 + if (!id) 506 + return -ENODEV; 507 + cfg = (struct res_config *)id->driver_data; 508 + skx_set_res_cfg(cfg); 509 + 510 + if (!imh_get_tolm_tohm(cfg, &tolm, &tohm)) 511 + return -ENODEV; 512 + 513 + skx_set_hi_lo(tolm, tohm); 514 + 515 + rc = imh_get_imc_num(cfg); 516 + if (rc < 0) 517 + goto fail; 518 + 519 + edac_list = skx_get_edac_list(); 520 + 521 + rc = imh_get_all_mmio_base_h(cfg, edac_list); 522 + if (rc) 523 + goto fail; 524 + 525 + rc = imh_get_munits(cfg, edac_list); 526 + if (rc) 527 + goto fail; 528 + 529 + rc = imh_register_mci(cfg, edac_list); 530 + if (rc) 531 + goto fail; 532 + 533 + rc = skx_adxl_get(); 534 + if (rc) 535 + goto fail; 536 + 537 + opstate_init(); 538 + mce_register_decode_chain(&imh_mce_dec); 539 + 540 + imh_printk(KERN_INFO, "%s\n", IMH_REVISION); 541 + 542 + return 0; 543 + fail: 544 + skx_remove(); 545 + return rc; 546 + } 547 + 548 + static void __exit imh_exit(void) 549 + { 550 + edac_dbg(2, "\n"); 551 + 552 + mce_unregister_decode_chain(&imh_mce_dec); 553 + skx_adxl_put(); 554 + skx_remove(); 555 + } 556 + 557 + module_init(imh_init); 558 + module_exit(imh_exit); 559 + 560 + MODULE_LICENSE("GPL"); 561 + MODULE_AUTHOR("Qiuxu Zhuo"); 562 + MODULE_DESCRIPTION("MC Driver for Intel servers using IMH-based memory controller");
+6 -2
drivers/edac/skx_common.c
··· 124 124 } 125 125 EXPORT_SYMBOL_GPL(skx_adxl_put); 126 126 127 - static void skx_init_mc_mapping(struct skx_dev *d) 127 + void skx_init_mc_mapping(struct skx_dev *d) 128 128 { 129 129 /* 130 130 * By default, the BIOS presents all memory controllers within each ··· 135 135 for (int i = 0; i < d->num_imc; i++) 136 136 d->imc[i].mc_mapping = i; 137 137 } 138 + EXPORT_SYMBOL_GPL(skx_init_mc_mapping); 138 139 139 140 void skx_set_mc_mapping(struct skx_dev *d, u8 pmc, u8 lmc) 140 141 { ··· 824 823 if (d->imc[i].mbase) 825 824 iounmap(d->imc[i].mbase); 826 825 826 + if (d->imc[i].dev) 827 + put_device(d->imc[i].dev); 828 + 827 829 for (j = 0; j < d->imc[i].num_channels; j++) { 828 830 if (d->imc[i].chan[j].cdev) 829 831 pci_dev_put(d->imc[i].chan[j].cdev); ··· 850 846 /* 851 847 * Debug feature. 852 848 * Exercise the address decode logic by writing an address to 853 - * /sys/kernel/debug/edac/{skx,i10nm}_test/addr. 849 + * /sys/kernel/debug/edac/{skx,i10nm,imh}_test/addr. 854 850 */ 855 851 static struct dentry *skx_test; 856 852
+65 -24
drivers/edac/skx_common.h
··· 121 121 * memory controllers on the die. 122 122 */ 123 123 struct skx_dev { 124 - struct list_head list; 124 + /* {skx,i10nm}_edac */ 125 125 u8 bus[4]; 126 126 int seg; 127 127 struct pci_dev *sad_all; 128 128 struct pci_dev *util_all; 129 - struct pci_dev *uracu; /* for i10nm CPU */ 130 - struct pci_dev *pcu_cr3; /* for HBM memory detection */ 129 + struct pci_dev *uracu; 130 + struct pci_dev *pcu_cr3; 131 131 u32 mcroute; 132 + 133 + /* imh_edac */ 134 + /* System-view MMIO base physical addresses. */ 135 + u64 mmio_base_h_north; 136 + u64 mmio_base_h_south; 137 + int pkg; 138 + 132 139 int num_imc; 140 + struct list_head list; 133 141 struct skx_imc { 142 + /* i10nm_edac */ 143 + struct pci_dev *mdev; 144 + 145 + /* imh_edac */ 146 + struct device *dev; 147 + 134 148 struct mem_ctl_info *mci; 135 - struct pci_dev *mdev; /* for i10nm CPU */ 136 - void __iomem *mbase; /* for i10nm CPU */ 137 - int chan_mmio_sz; /* for i10nm CPU */ 149 + void __iomem *mbase; 150 + int chan_mmio_sz; 138 151 int num_channels; /* channels per memory controller */ 139 152 int num_dimms; /* dimms per channel */ 140 153 bool hbm_mc; ··· 191 178 SKX, 192 179 I10NM, 193 180 SPR, 194 - GNR 181 + GNR, 182 + DMR, 195 183 }; 196 184 197 185 enum { ··· 251 237 252 238 struct res_config { 253 239 enum type type; 254 - /* Configuration agent device ID */ 255 - unsigned int decs_did; 256 - /* Default bus number configuration register offset */ 257 - int busno_cfg_offset; 258 240 /* DDR memory controllers per socket */ 259 241 int ddr_imc_num; 260 242 /* DDR channels per DDR memory controller */ ··· 268 258 /* Per HBM channel memory-mapped I/O size */ 269 259 int hbm_chan_mmio_sz; 270 260 bool support_ddr5; 271 - /* SAD device BDF */ 272 - struct pci_bdf sad_all_bdf; 273 - /* PCU device BDF */ 274 - struct pci_bdf pcu_cr3_bdf; 275 - /* UTIL device BDF */ 276 - struct pci_bdf util_all_bdf; 277 - /* URACU device BDF */ 278 - struct pci_bdf uracu_bdf; 279 - /* DDR mdev device BDF */ 280 - struct pci_bdf ddr_mdev_bdf; 281 - /* HBM mdev device BDF */ 282 - struct pci_bdf hbm_mdev_bdf; 283 - int sad_all_offset; 284 261 /* RRL register sets per DDR channel */ 285 262 struct reg_rrl *reg_rrl_ddr; 286 263 /* RRL register sets per HBM channel */ 287 264 struct reg_rrl *reg_rrl_hbm[2]; 265 + union { 266 + /* {skx,i10nm}_edac */ 267 + struct { 268 + /* Configuration agent device ID */ 269 + unsigned int decs_did; 270 + /* Default bus number configuration register offset */ 271 + int busno_cfg_offset; 272 + struct pci_bdf sad_all_bdf; 273 + struct pci_bdf pcu_cr3_bdf; 274 + struct pci_bdf util_all_bdf; 275 + struct pci_bdf uracu_bdf; 276 + struct pci_bdf ddr_mdev_bdf; 277 + struct pci_bdf hbm_mdev_bdf; 278 + int sad_all_offset; 279 + }; 280 + /* imh_edac */ 281 + struct { 282 + /* MMIO base physical address in local package view */ 283 + u64 mmio_base_l_north; 284 + u64 mmio_base_l_south; 285 + u64 ddr_imc_base; 286 + u64 ddr_reg_mcmtr_offset; 287 + u8 ddr_reg_mcmtr_width; 288 + u64 ddr_reg_dimmmtr_offset; 289 + u8 ddr_reg_dimmmtr_width; 290 + u64 ubox_base; 291 + u32 ubox_size; 292 + u32 ubox_reg_mmio_base_offset; 293 + u8 ubox_reg_mmio_base_width; 294 + u32 ubox_reg_socket_id_offset; 295 + u8 ubox_reg_socket_id_width; 296 + u64 pcu_base; 297 + u32 pcu_size; 298 + u32 pcu_reg_capid3_offset; 299 + u8 pcu_reg_capid3_width; 300 + u64 sca_base; 301 + u32 sca_size; 302 + u32 sca_reg_tolm_offset; 303 + u8 sca_reg_tolm_width; 304 + u32 sca_reg_tohm_offset; 305 + u8 sca_reg_tohm_width; 306 + }; 307 + }; 288 308 }; 289 309 290 310 typedef int (*get_dimm_config_f)(struct mem_ctl_info *mci, ··· 327 287 void skx_set_decode(skx_decode_f decode, skx_show_retry_log_f show_retry_log); 328 288 void skx_set_mem_cfg(bool mem_cfg_2lm); 329 289 void skx_set_res_cfg(struct res_config *cfg); 290 + void skx_init_mc_mapping(struct skx_dev *d); 330 291 void skx_set_mc_mapping(struct skx_dev *d, u8 pmc, u8 lmc); 331 292 332 293 int skx_get_src_id(struct skx_dev *d, int off, u8 *id);