- switch to use scnprintf()
  - Add Granite Rapids-D support
 
 - synopsys: Make sure ECC error and counter registers are cleared during
   init/probing to avoid reporting stale errors
 
 - igen6: Add Wildcat Lake SoCs support
 
 - Make sure scrub features sysfs attributes are initialized properly
 
 - Allocate memory repair sysfs attributes statically to reduce stack
   usage
 
 - Fix DIMM module size computation for DIMMs with total capacity which
   is a non power-of-two number, in amd64_edac
 
 - Do not be too dramatic when reporting disabled memory controllers in
   igen6_edac
 
 - Add support to ie31200_edac for the following SoCs:
  - Core i5-14[67]00
  - Bartless Lake-S SoCs
  - Raptor Lake-HX
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEzv7L6UO9uDPlPSfHEsHwGGHeVUoFAmiHeDcACgkQEsHwGGHe
 VUrnzhAAryFKu8xWuwOE3eGaMW6oJhjKF8wPxLiCxxi6ZdQ/1uudFVnzwgozmkXo
 l10h41A3yc1ZdJqdqn54gF8PxbQ0E1MvbXfmBqZ/U+V+dv6zMwu9TygoPRIJ60ST
 aIxTBq2zoSii7ucGCBjbqClMTF3ZcH/Q2FzZoFbZyZd84snWSz0B9+S+937mtMhl
 9Y55sAgQuigQDQ71YZymAGyWi9E9J20wFk76vIHEboRIa5sS0iCU88Wb4PT+5iKf
 Qc/1gyqnd+6FO9O9ddrYpeDcaIicLShuGVNZNlJalD/JyTIOcP6XdEDa5J7TYp27
 7IcmfHSYmZ5eL0vrJfrIwbauEpRL9ZjWXS+uQjj8/K/gkPUsH/Sdldgldkd50GHV
 6L79XSzpy4yhlAr3BXU0o917qRVWOpbxr9E7l6VAFGBpLl5ewtZiV3W7/Su4rPd2
 zpUGBZvjxO8jmNQn49IPs/XotVQ2L+mT+KSxUMZAO2pV+dztSJELMFQQC0uAXiZc
 ApcrSkQxa4fsxU2Ukc1dLOJNkwxEC1ECcPsl2I9EE1cFoix7NP2E+G92D/V52VoZ
 QeVkxM7LHZCTH9tH1nrCZ+WJr8S2vZ+uY8jRl42P12xU4kcd3RWEtna18bX5oe++
 RlgchnXwutEPSgHYZVPocuaDD7C6eIvYzpaVezVl9dgbRLLx8u4=
 =PBTf
 -----END PGP SIGNATURE-----

Merge tag 'edac_updates_for_v6.17_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras

Pull EDAC updates from Borislav Petkov:

 - i10nm:
     - switch to using scnprintf()
     - Add Granite Rapids-D support

 - synopsys: Make sure ECC error and counter registers are cleared
   during init/probing to avoid reporting stale errors

 - igen6: Add Wildcat Lake SoCs support

 - Make sure scrub features sysfs attributes are initialized properly

 - Allocate memory repair sysfs attributes statically to reduce stack
   usage

 - Fix DIMM module size computation for DIMMs with total capacity which
   is a non power-of-two number, in amd64_edac

 - Do not be too dramatic when reporting disabled memory controllers in
   igen6_edac

 - Add support to ie31200_edac for the following SoCs:
     - Core i5-14[67]00
     - Bartless Lake-S SoCs
     - Raptor Lake-HX

* tag 'edac_updates_for_v6.17_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras:
  EDAC/{skx_common,i10nm}: Use scnprintf() for safer buffer handling
  EDAC/synopsys: Clear the ECC counters on init
  EDAC/ie31200: Add Intel Raptor Lake-HX SoCs support
  EDAC/igen6: Add Intel Wildcat Lake SoCs support
  EDAC/i10nm: Add Intel Granite Rapids-D support
  EDAC/mem_repair: Reduce stack usage in edac_mem_repair_get_desc()
  EDAC/igen6: Reduce log level to debug for absent memory controllers
  EDAC/ie31200: Document which CPUs correspond to each Raptor Lake-S device ID
  EDAC/ie31200: Enable support for Core i5-14600 and i7-14700
  ie31200/EDAC: Add Intel Bartlett Lake-S SoCs support
This commit is contained in:
Linus Torvalds 2025-07-29 16:30:38 -07:00
commit d7223aed30
6 changed files with 138 additions and 100 deletions

View file

@ -62,6 +62,7 @@
((GET_BITFIELD(reg, 0, 10) << 12) + 0x140000) ((GET_BITFIELD(reg, 0, 10) << 12) + 0x140000)
#define I10NM_GNR_IMC_MMIO_OFFSET 0x24c000 #define I10NM_GNR_IMC_MMIO_OFFSET 0x24c000
#define I10NM_GNR_D_IMC_MMIO_OFFSET 0x206000
#define I10NM_GNR_IMC_MMIO_SIZE 0x4000 #define I10NM_GNR_IMC_MMIO_SIZE 0x4000
#define I10NM_HBM_IMC_MMIO_SIZE 0x9000 #define I10NM_HBM_IMC_MMIO_SIZE 0x9000
#define I10NM_DDR_IMC_CH_CNT(reg) GET_BITFIELD(reg, 21, 24) #define I10NM_DDR_IMC_CH_CNT(reg) GET_BITFIELD(reg, 21, 24)
@ -343,7 +344,7 @@ static void show_retry_rd_err_log(struct decoded_addr *res, char *msg,
status_mask = rrl->over_mask | rrl->uc_mask | rrl->v_mask; status_mask = rrl->over_mask | rrl->uc_mask | rrl->v_mask;
n = snprintf(msg, len, " retry_rd_err_log["); n = scnprintf(msg, len, " retry_rd_err_log[");
for (i = 0; i < rrl->set_num; i++) { for (i = 0; i < rrl->set_num; i++) {
scrub = (rrl->modes[i] == FRE_SCRUB || rrl->modes[i] == LRE_SCRUB); scrub = (rrl->modes[i] == FRE_SCRUB || rrl->modes[i] == LRE_SCRUB);
if (scrub_err != scrub) if (scrub_err != scrub)
@ -355,9 +356,9 @@ static void show_retry_rd_err_log(struct decoded_addr *res, char *msg,
log = read_imc_reg(imc, ch, offset, width); log = read_imc_reg(imc, ch, offset, width);
if (width == 4) if (width == 4)
n += snprintf(msg + n, len - n, "%.8llx ", log); n += scnprintf(msg + n, len - n, "%.8llx ", log);
else else
n += snprintf(msg + n, len - n, "%.16llx ", log); n += scnprintf(msg + n, len - n, "%.16llx ", log);
/* Clear RRL status if RRL in Linux control mode. */ /* Clear RRL status if RRL in Linux control mode. */
if (retry_rd_err_log == 2 && !j && (log & status_mask)) if (retry_rd_err_log == 2 && !j && (log & status_mask))
@ -367,10 +368,10 @@ static void show_retry_rd_err_log(struct decoded_addr *res, char *msg,
/* Move back one space. */ /* Move back one space. */
n--; n--;
n += snprintf(msg + n, len - n, "]"); n += scnprintf(msg + n, len - n, "]");
if (len - n > 0) { if (len - n > 0) {
n += snprintf(msg + n, len - n, " correrrcnt["); n += scnprintf(msg + n, len - n, " correrrcnt[");
for (i = 0; i < rrl->cecnt_num && len - n > 0; i++) { for (i = 0; i < rrl->cecnt_num && len - n > 0; i++) {
offset = rrl->cecnt_offsets[i]; offset = rrl->cecnt_offsets[i];
width = rrl->cecnt_widths[i]; width = rrl->cecnt_widths[i];
@ -378,20 +379,20 @@ static void show_retry_rd_err_log(struct decoded_addr *res, char *msg,
/* CPUs {ICX,SPR} encode two counters per 4-byte CORRERRCNT register. */ /* CPUs {ICX,SPR} encode two counters per 4-byte CORRERRCNT register. */
if (res_cfg->type <= SPR) { if (res_cfg->type <= SPR) {
n += snprintf(msg + n, len - n, "%.4llx %.4llx ", n += scnprintf(msg + n, len - n, "%.4llx %.4llx ",
corr & 0xffff, corr >> 16); corr & 0xffff, corr >> 16);
} else { } else {
/* CPUs {GNR} encode one counter per CORRERRCNT register. */ /* CPUs {GNR} encode one counter per CORRERRCNT register. */
if (width == 4) if (width == 4)
n += snprintf(msg + n, len - n, "%.8llx ", corr); n += scnprintf(msg + n, len - n, "%.8llx ", corr);
else else
n += snprintf(msg + n, len - n, "%.16llx ", corr); n += scnprintf(msg + n, len - n, "%.16llx ", corr);
} }
} }
/* Move back one space. */ /* Move back one space. */
n--; n--;
n += snprintf(msg + n, len - n, "]"); n += scnprintf(msg + n, len - n, "]");
} }
} }
@ -687,6 +688,14 @@ static struct pci_dev *get_gnr_mdev(struct skx_dev *d, int logical_idx, int *phy
return NULL; return NULL;
} }
static u32 get_gnr_imc_mmio_offset(void)
{
if (boot_cpu_data.x86_vfm == INTEL_GRANITERAPIDS_D)
return I10NM_GNR_D_IMC_MMIO_OFFSET;
return I10NM_GNR_IMC_MMIO_OFFSET;
}
/** /**
* get_ddr_munit() - Get the resource of the i-th DDR memory controller. * get_ddr_munit() - Get the resource of the i-th DDR memory controller.
* *
@ -715,7 +724,7 @@ static struct pci_dev *get_ddr_munit(struct skx_dev *d, int i, u32 *offset, unsi
return NULL; return NULL;
*offset = I10NM_GET_IMC_MMIO_OFFSET(reg) + *offset = I10NM_GET_IMC_MMIO_OFFSET(reg) +
I10NM_GNR_IMC_MMIO_OFFSET + get_gnr_imc_mmio_offset() +
physical_idx * I10NM_GNR_IMC_MMIO_SIZE; physical_idx * I10NM_GNR_IMC_MMIO_SIZE;
*size = I10NM_GNR_IMC_MMIO_SIZE; *size = I10NM_GNR_IMC_MMIO_SIZE;
@ -1030,6 +1039,7 @@ static const struct x86_cpu_id i10nm_cpuids[] = {
X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X, &spr_cfg), X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X, &spr_cfg),
X86_MATCH_VFM(INTEL_EMERALDRAPIDS_X, &spr_cfg), X86_MATCH_VFM(INTEL_EMERALDRAPIDS_X, &spr_cfg),
X86_MATCH_VFM(INTEL_GRANITERAPIDS_X, &gnr_cfg), X86_MATCH_VFM(INTEL_GRANITERAPIDS_X, &gnr_cfg),
X86_MATCH_VFM(INTEL_GRANITERAPIDS_D, &gnr_cfg),
X86_MATCH_VFM(INTEL_ATOM_CRESTMONT_X, &gnr_cfg), X86_MATCH_VFM(INTEL_ATOM_CRESTMONT_X, &gnr_cfg),
X86_MATCH_VFM(INTEL_ATOM_CRESTMONT, &gnr_cfg), X86_MATCH_VFM(INTEL_ATOM_CRESTMONT, &gnr_cfg),
X86_MATCH_VFM(INTEL_ATOM_DARKMONT_X, &gnr_cfg), X86_MATCH_VFM(INTEL_ATOM_DARKMONT_X, &gnr_cfg),

View file

@ -87,14 +87,31 @@
#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_10 0x3eca #define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_10 0x3eca
/* Raptor Lake-S */ /* Raptor Lake-S */
#define PCI_DEVICE_ID_INTEL_IE31200_RPL_S_1 0xa703 #define PCI_DEVICE_ID_INTEL_IE31200_RPL_S_1 0xa703 /* 8P+8E, e.g. i7-13700 */
#define PCI_DEVICE_ID_INTEL_IE31200_RPL_S_2 0x4640 #define PCI_DEVICE_ID_INTEL_IE31200_RPL_S_2 0x4640 /* 6P+8E, e.g. i5-13500, i5-13600, i5-14500 */
#define PCI_DEVICE_ID_INTEL_IE31200_RPL_S_3 0x4630 #define PCI_DEVICE_ID_INTEL_IE31200_RPL_S_3 0x4630 /* 4P+0E, e.g. i3-13100E */
#define PCI_DEVICE_ID_INTEL_IE31200_RPL_S_4 0xa700 #define PCI_DEVICE_ID_INTEL_IE31200_RPL_S_4 0xa700 /* 8P+16E, e.g. i9-13900, i9-14900 */
#define PCI_DEVICE_ID_INTEL_IE31200_RPL_S_5 0xa740 /* 8P+12E, e.g. i7-14700 */
#define PCI_DEVICE_ID_INTEL_IE31200_RPL_S_6 0xa704 /* 6P+8E, e.g. i5-14600 */
/* Raptor Lake-HX */
#define PCI_DEVICE_ID_INTEL_IE31200_RPL_HX_1 0xa702 /* 8P+16E, e.g. i9-13950HX */
/* Alder Lake-S */ /* Alder Lake-S */
#define PCI_DEVICE_ID_INTEL_IE31200_ADL_S_1 0x4660 #define PCI_DEVICE_ID_INTEL_IE31200_ADL_S_1 0x4660
/* Bartlett Lake-S */
#define PCI_DEVICE_ID_INTEL_IE31200_BTL_S_1 0x4639
#define PCI_DEVICE_ID_INTEL_IE31200_BTL_S_2 0x463c
#define PCI_DEVICE_ID_INTEL_IE31200_BTL_S_3 0x4642
#define PCI_DEVICE_ID_INTEL_IE31200_BTL_S_4 0x4643
#define PCI_DEVICE_ID_INTEL_IE31200_BTL_S_5 0xa731
#define PCI_DEVICE_ID_INTEL_IE31200_BTL_S_6 0xa732
#define PCI_DEVICE_ID_INTEL_IE31200_BTL_S_7 0xa733
#define PCI_DEVICE_ID_INTEL_IE31200_BTL_S_8 0xa741
#define PCI_DEVICE_ID_INTEL_IE31200_BTL_S_9 0xa744
#define PCI_DEVICE_ID_INTEL_IE31200_BTL_S_10 0xa745
#define IE31200_RANKS_PER_CHANNEL 8 #define IE31200_RANKS_PER_CHANNEL 8
#define IE31200_DIMMS_PER_CHANNEL 2 #define IE31200_DIMMS_PER_CHANNEL 2
#define IE31200_CHANNELS 2 #define IE31200_CHANNELS 2
@ -740,7 +757,20 @@ static const struct pci_device_id ie31200_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_2), (kernel_ulong_t)&rpl_s_cfg}, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_2), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_3), (kernel_ulong_t)&rpl_s_cfg}, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_3), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_4), (kernel_ulong_t)&rpl_s_cfg}, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_4), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_5), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_6), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_HX_1), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_ADL_S_1), (kernel_ulong_t)&rpl_s_cfg}, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_ADL_S_1), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_1), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_2), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_3), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_4), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_5), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_6), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_7), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_8), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_9), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_10), (kernel_ulong_t)&rpl_s_cfg},
{ 0, } /* 0 terminated list. */ { 0, } /* 0 terminated list. */
}; };
MODULE_DEVICE_TABLE(pci, ie31200_pci_tbl); MODULE_DEVICE_TABLE(pci, ie31200_pci_tbl);

View file

@ -275,6 +275,9 @@ static struct work_struct ecclog_work;
#define DID_PTL_H_SKU2 0xb001 #define DID_PTL_H_SKU2 0xb001
#define DID_PTL_H_SKU3 0xb002 #define DID_PTL_H_SKU3 0xb002
/* Compute die IDs for Wildcat Lake with IBECC */
#define DID_WCL_SKU1 0xfd00
static int get_mchbar(struct pci_dev *pdev, u64 *mchbar) static int get_mchbar(struct pci_dev *pdev, u64 *mchbar)
{ {
union { union {
@ -569,6 +572,17 @@ static struct res_config mtl_p_cfg = {
.err_addr_to_imc_addr = adl_err_addr_to_imc_addr, .err_addr_to_imc_addr = adl_err_addr_to_imc_addr,
}; };
static struct res_config wcl_cfg = {
.machine_check = true,
.num_imc = 1,
.imc_base = 0xd800,
.ibecc_base = 0xd400,
.ibecc_error_log_offset = 0x170,
.ibecc_available = mtl_p_ibecc_available,
.err_addr_to_sys_addr = adl_err_addr_to_sys_addr,
.err_addr_to_imc_addr = adl_err_addr_to_imc_addr,
};
static struct pci_device_id igen6_pci_tbl[] = { static struct pci_device_id igen6_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, DID_EHL_SKU5), (kernel_ulong_t)&ehl_cfg }, { PCI_VDEVICE(INTEL, DID_EHL_SKU5), (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU6), (kernel_ulong_t)&ehl_cfg }, { PCI_VDEVICE(INTEL, DID_EHL_SKU6), (kernel_ulong_t)&ehl_cfg },
@ -622,6 +636,7 @@ static struct pci_device_id igen6_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU1), (kernel_ulong_t)&mtl_p_cfg }, { PCI_VDEVICE(INTEL, DID_PTL_H_SKU1), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU2), (kernel_ulong_t)&mtl_p_cfg }, { PCI_VDEVICE(INTEL, DID_PTL_H_SKU2), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU3), (kernel_ulong_t)&mtl_p_cfg }, { PCI_VDEVICE(INTEL, DID_PTL_H_SKU3), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_WCL_SKU1), (kernel_ulong_t)&wcl_cfg },
{ }, { },
}; };
MODULE_DEVICE_TABLE(pci, igen6_pci_tbl); MODULE_DEVICE_TABLE(pci, igen6_pci_tbl);
@ -1351,7 +1366,7 @@ static int igen6_register_mcis(struct pci_dev *pdev, u64 mchbar)
} }
if (lmc < res_cfg->num_imc) { if (lmc < res_cfg->num_imc) {
igen6_printk(KERN_WARNING, "Expected %d mcs, but only %d detected.", igen6_printk(KERN_DEBUG, "Expected %d mcs, but only %d detected.",
res_cfg->num_imc, lmc); res_cfg->num_imc, lmc);
res_cfg->num_imc = lmc; res_cfg->num_imc = lmc;
} }

View file

@ -286,17 +286,26 @@ static umode_t mem_repair_attr_visible(struct kobject *kobj, struct attribute *a
return 0; return 0;
} }
#define MR_ATTR_RO(_name, _instance) \ static const struct device_attribute mem_repair_dev_attr[] = {
((struct edac_mem_repair_dev_attr) { .dev_attr = __ATTR_RO(_name), \ [MR_TYPE] = __ATTR_RO(repair_type),
.instance = _instance }) [MR_PERSIST_MODE] = __ATTR_RW(persist_mode),
[MR_SAFE_IN_USE] = __ATTR_RO(repair_safe_when_in_use),
#define MR_ATTR_WO(_name, _instance) \ [MR_HPA] = __ATTR_RW(hpa),
((struct edac_mem_repair_dev_attr) { .dev_attr = __ATTR_WO(_name), \ [MR_MIN_HPA] = __ATTR_RO(min_hpa),
.instance = _instance }) [MR_MAX_HPA] = __ATTR_RO(max_hpa),
[MR_DPA] = __ATTR_RW(dpa),
#define MR_ATTR_RW(_name, _instance) \ [MR_MIN_DPA] = __ATTR_RO(min_dpa),
((struct edac_mem_repair_dev_attr) { .dev_attr = __ATTR_RW(_name), \ [MR_MAX_DPA] = __ATTR_RO(max_dpa),
.instance = _instance }) [MR_NIBBLE_MASK] = __ATTR_RW(nibble_mask),
[MR_BANK_GROUP] = __ATTR_RW(bank_group),
[MR_BANK] = __ATTR_RW(bank),
[MR_RANK] = __ATTR_RW(rank),
[MR_ROW] = __ATTR_RW(row),
[MR_COLUMN] = __ATTR_RW(column),
[MR_CHANNEL] = __ATTR_RW(channel),
[MR_SUB_CHANNEL] = __ATTR_RW(sub_channel),
[MEM_DO_REPAIR] = __ATTR_WO(repair)
};
static int mem_repair_create_desc(struct device *dev, static int mem_repair_create_desc(struct device *dev,
const struct attribute_group **attr_groups, const struct attribute_group **attr_groups,
@ -305,34 +314,13 @@ static int mem_repair_create_desc(struct device *dev,
struct edac_mem_repair_context *ctx; struct edac_mem_repair_context *ctx;
struct attribute_group *group; struct attribute_group *group;
int i; int i;
struct edac_mem_repair_dev_attr dev_attr[] = {
[MR_TYPE] = MR_ATTR_RO(repair_type, instance),
[MR_PERSIST_MODE] = MR_ATTR_RW(persist_mode, instance),
[MR_SAFE_IN_USE] = MR_ATTR_RO(repair_safe_when_in_use, instance),
[MR_HPA] = MR_ATTR_RW(hpa, instance),
[MR_MIN_HPA] = MR_ATTR_RO(min_hpa, instance),
[MR_MAX_HPA] = MR_ATTR_RO(max_hpa, instance),
[MR_DPA] = MR_ATTR_RW(dpa, instance),
[MR_MIN_DPA] = MR_ATTR_RO(min_dpa, instance),
[MR_MAX_DPA] = MR_ATTR_RO(max_dpa, instance),
[MR_NIBBLE_MASK] = MR_ATTR_RW(nibble_mask, instance),
[MR_BANK_GROUP] = MR_ATTR_RW(bank_group, instance),
[MR_BANK] = MR_ATTR_RW(bank, instance),
[MR_RANK] = MR_ATTR_RW(rank, instance),
[MR_ROW] = MR_ATTR_RW(row, instance),
[MR_COLUMN] = MR_ATTR_RW(column, instance),
[MR_CHANNEL] = MR_ATTR_RW(channel, instance),
[MR_SUB_CHANNEL] = MR_ATTR_RW(sub_channel, instance),
[MEM_DO_REPAIR] = MR_ATTR_WO(repair, instance)
};
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx) if (!ctx)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < MR_MAX_ATTRS; i++) { for (i = 0; i < MR_MAX_ATTRS; i++) {
memcpy(&ctx->mem_repair_dev_attr[i], ctx->mem_repair_dev_attr[i].dev_attr = mem_repair_dev_attr[i];
&dev_attr[i], sizeof(dev_attr[i])); ctx->mem_repair_dev_attr[i].instance = instance;
sysfs_attr_init(&ctx->mem_repair_dev_attr[i].dev_attr.attr); sysfs_attr_init(&ctx->mem_repair_dev_attr[i].dev_attr.attr);
ctx->mem_repair_attrs[i] = ctx->mem_repair_attrs[i] =
&ctx->mem_repair_dev_attr[i].dev_attr.attr; &ctx->mem_repair_dev_attr[i].dev_attr.attr;

View file

@ -670,12 +670,12 @@ static void skx_mce_output_error(struct mem_ctl_info *mci,
} }
if (res->decoded_by_adxl) { if (res->decoded_by_adxl) {
len = snprintf(skx_msg, MSG_SIZE, "%s%s err_code:0x%04x:0x%04x %s", len = scnprintf(skx_msg, MSG_SIZE, "%s%s err_code:0x%04x:0x%04x %s",
overflow ? " OVERFLOW" : "", overflow ? " OVERFLOW" : "",
(uncorrected_error && recoverable) ? " recoverable" : "", (uncorrected_error && recoverable) ? " recoverable" : "",
mscod, errcode, adxl_msg); mscod, errcode, adxl_msg);
} else { } else {
len = snprintf(skx_msg, MSG_SIZE, len = scnprintf(skx_msg, MSG_SIZE,
"%s%s err_code:0x%04x:0x%04x ProcessorSocketId:0x%x MemoryControllerId:0x%x PhysicalRankId:0x%x Row:0x%x Column:0x%x Bank:0x%x BankGroup:0x%x", "%s%s err_code:0x%04x:0x%04x ProcessorSocketId:0x%x MemoryControllerId:0x%x PhysicalRankId:0x%x Row:0x%x Column:0x%x Bank:0x%x BankGroup:0x%x",
overflow ? " OVERFLOW" : "", overflow ? " OVERFLOW" : "",
(uncorrected_error && recoverable) ? " recoverable" : "", (uncorrected_error && recoverable) ? " recoverable" : "",

View file

@ -332,20 +332,26 @@ struct synps_edac_priv {
#endif #endif
}; };
enum synps_platform_type {
ZYNQ,
ZYNQMP,
SYNPS,
};
/** /**
* struct synps_platform_data - synps platform data structure. * struct synps_platform_data - synps platform data structure.
* @platform: Identifies the target hardware platform
* @get_error_info: Get EDAC error info. * @get_error_info: Get EDAC error info.
* @get_mtype: Get mtype. * @get_mtype: Get mtype.
* @get_dtype: Get dtype. * @get_dtype: Get dtype.
* @get_ecc_state: Get ECC state.
* @get_mem_info: Get EDAC memory info * @get_mem_info: Get EDAC memory info
* @quirks: To differentiate IPs. * @quirks: To differentiate IPs.
*/ */
struct synps_platform_data { struct synps_platform_data {
enum synps_platform_type platform;
int (*get_error_info)(struct synps_edac_priv *priv); int (*get_error_info)(struct synps_edac_priv *priv);
enum mem_type (*get_mtype)(const void __iomem *base); enum mem_type (*get_mtype)(const void __iomem *base);
enum dev_type (*get_dtype)(const void __iomem *base); enum dev_type (*get_dtype)(const void __iomem *base);
bool (*get_ecc_state)(void __iomem *base);
#ifdef CONFIG_EDAC_DEBUG #ifdef CONFIG_EDAC_DEBUG
u64 (*get_mem_info)(struct synps_edac_priv *priv); u64 (*get_mem_info)(struct synps_edac_priv *priv);
#endif #endif
@ -720,51 +726,38 @@ static enum dev_type zynqmp_get_dtype(const void __iomem *base)
return dt; return dt;
} }
/** static bool get_ecc_state(struct synps_edac_priv *priv)
* zynq_get_ecc_state - Return the controller ECC enable/disable status.
* @base: DDR memory controller base address.
*
* Get the ECC enable/disable status of the controller.
*
* Return: true if enabled, otherwise false.
*/
static bool zynq_get_ecc_state(void __iomem *base)
{ {
u32 ecctype, clearval;
enum dev_type dt; enum dev_type dt;
u32 ecctype;
dt = zynq_get_dtype(base); if (priv->p_data->platform == ZYNQ) {
if (dt == DEV_UNKNOWN) dt = zynq_get_dtype(priv->baseaddr);
return false; if (dt == DEV_UNKNOWN)
return false;
ecctype = readl(base + SCRUB_OFST) & SCRUB_MODE_MASK; ecctype = readl(priv->baseaddr + SCRUB_OFST) & SCRUB_MODE_MASK;
if ((ecctype == SCRUB_MODE_SECDED) && (dt == DEV_X2)) if (ecctype == SCRUB_MODE_SECDED && dt == DEV_X2) {
return true; clearval = ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_UE_ERR;
writel(clearval, priv->baseaddr + ECC_CTRL_OFST);
writel(0x0, priv->baseaddr + ECC_CTRL_OFST);
return true;
}
} else {
dt = zynqmp_get_dtype(priv->baseaddr);
if (dt == DEV_UNKNOWN)
return false;
return false; ecctype = readl(priv->baseaddr + ECC_CFG0_OFST) & SCRUB_MODE_MASK;
} if (ecctype == SCRUB_MODE_SECDED &&
(dt == DEV_X2 || dt == DEV_X4 || dt == DEV_X8)) {
/** clearval = readl(priv->baseaddr + ECC_CLR_OFST) |
* zynqmp_get_ecc_state - Return the controller ECC enable/disable status. ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT |
* @base: DDR memory controller base address. ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT;
* writel(clearval, priv->baseaddr + ECC_CLR_OFST);
* Get the ECC enable/disable status for the controller. return true;
* }
* Return: a ECC status boolean i.e true/false - enabled/disabled. }
*/
static bool zynqmp_get_ecc_state(void __iomem *base)
{
enum dev_type dt;
u32 ecctype;
dt = zynqmp_get_dtype(base);
if (dt == DEV_UNKNOWN)
return false;
ecctype = readl(base + ECC_CFG0_OFST) & SCRUB_MODE_MASK;
if ((ecctype == SCRUB_MODE_SECDED) &&
((dt == DEV_X2) || (dt == DEV_X4) || (dt == DEV_X8)))
return true;
return false; return false;
} }
@ -934,18 +927,18 @@ static int setup_irq(struct mem_ctl_info *mci,
} }
static const struct synps_platform_data zynq_edac_def = { static const struct synps_platform_data zynq_edac_def = {
.platform = ZYNQ,
.get_error_info = zynq_get_error_info, .get_error_info = zynq_get_error_info,
.get_mtype = zynq_get_mtype, .get_mtype = zynq_get_mtype,
.get_dtype = zynq_get_dtype, .get_dtype = zynq_get_dtype,
.get_ecc_state = zynq_get_ecc_state,
.quirks = 0, .quirks = 0,
}; };
static const struct synps_platform_data zynqmp_edac_def = { static const struct synps_platform_data zynqmp_edac_def = {
.platform = ZYNQMP,
.get_error_info = zynqmp_get_error_info, .get_error_info = zynqmp_get_error_info,
.get_mtype = zynqmp_get_mtype, .get_mtype = zynqmp_get_mtype,
.get_dtype = zynqmp_get_dtype, .get_dtype = zynqmp_get_dtype,
.get_ecc_state = zynqmp_get_ecc_state,
#ifdef CONFIG_EDAC_DEBUG #ifdef CONFIG_EDAC_DEBUG
.get_mem_info = zynqmp_get_mem_info, .get_mem_info = zynqmp_get_mem_info,
#endif #endif
@ -957,10 +950,10 @@ static const struct synps_platform_data zynqmp_edac_def = {
}; };
static const struct synps_platform_data synopsys_edac_def = { static const struct synps_platform_data synopsys_edac_def = {
.platform = SYNPS,
.get_error_info = zynqmp_get_error_info, .get_error_info = zynqmp_get_error_info,
.get_mtype = zynqmp_get_mtype, .get_mtype = zynqmp_get_mtype,
.get_dtype = zynqmp_get_dtype, .get_dtype = zynqmp_get_dtype,
.get_ecc_state = zynqmp_get_ecc_state,
.quirks = (DDR_ECC_INTR_SUPPORT | DDR_ECC_INTR_SELF_CLEAR .quirks = (DDR_ECC_INTR_SUPPORT | DDR_ECC_INTR_SELF_CLEAR
#ifdef CONFIG_EDAC_DEBUG #ifdef CONFIG_EDAC_DEBUG
| DDR_ECC_DATA_POISON_SUPPORT | DDR_ECC_DATA_POISON_SUPPORT
@ -1390,10 +1383,6 @@ static int mc_probe(struct platform_device *pdev)
if (!p_data) if (!p_data)
return -ENODEV; return -ENODEV;
if (!p_data->get_ecc_state(baseaddr)) {
edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n");
return -ENXIO;
}
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = SYNPS_EDAC_NR_CSROWS; layers[0].size = SYNPS_EDAC_NR_CSROWS;
@ -1413,6 +1402,12 @@ static int mc_probe(struct platform_device *pdev)
priv = mci->pvt_info; priv = mci->pvt_info;
priv->baseaddr = baseaddr; priv->baseaddr = baseaddr;
priv->p_data = p_data; priv->p_data = p_data;
if (!get_ecc_state(priv)) {
edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n");
rc = -ENODEV;
goto free_edac_mc;
}
spin_lock_init(&priv->reglock); spin_lock_init(&priv->reglock);
mc_init(mci, pdev); mc_init(mci, pdev);