Commit 947fbd4c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'please-pull-for_5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras

Pull EDAC updates from Tony Luck:
 "All the bits that Boris had queued in his tree plus four patches to
  add support for Intel Icelake Xeon and then fix a few corner cases"

* tag 'please-pull-for_5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras:
  EDAC: Fix global-out-of-bounds write when setting edac_mc_poll_msec
  EDAC, skx, i10nm: Fix source ID register offset
  EDAC, i10nm: Check ECC enabling status per channel
  EDAC, i10nm: Add Intel additional Ice-Lake support
  EDAC: Make edac_debugfs_create_x*() return void
  EDAC/aspeed: Remove set but not used variable 'np'
  EDAC/ie31200: Reformat PCI device table
  EDAC/ie31200: Add Intel Coffee Lake CPU support
  EDAC/sifive: Add EDAC platform driver for SiFive SoCs
  EDAC/sb_edac: Remove redundant update of tad_base
  arm64: dts: stratix10: Add SDMMC EDAC node
  EDAC/altera: Add Stratix10 SDMMC support
  arm64: dts: stratix10: Add OCRAM EDAC node
  EDAC/altera: Add Stratix10 OCRAM ECC support
  EDAC/sysfs: Drop device references properly
  EDAC/sysfs: Fix memory leak when creating a csrow object
parents 6b04014f d8655e76
...@@ -5828,6 +5828,12 @@ L: linux-edac@vger.kernel.org ...@@ -5828,6 +5828,12 @@ L: linux-edac@vger.kernel.org
S: Maintained S: Maintained
F: drivers/edac/sb_edac.c F: drivers/edac/sb_edac.c
EDAC-SIFIVE
M: Yash Shah <yash.shah@sifive.com>
L: linux-edac@vger.kernel.org
S: Supported
F: drivers/edac/sifive_edac.c
EDAC-SKYLAKE EDAC-SKYLAKE
M: Tony Luck <tony.luck@intel.com> M: Tony Luck <tony.luck@intel.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
......
...@@ -539,6 +539,14 @@ sdramedac { ...@@ -539,6 +539,14 @@ sdramedac {
interrupts = <16 4>; interrupts = <16 4>;
}; };
ocram-ecc@ff8cc000 {
compatible = "altr,socfpga-s10-ocram-ecc",
"altr,socfpga-a10-ocram-ecc";
reg = <0xff8cc000 0x100>;
altr,ecc-parent = <&ocram>;
interrupts = <1 4>;
};
usb0-ecc@ff8c4000 { usb0-ecc@ff8c4000 {
compatible = "altr,socfpga-s10-usb-ecc", compatible = "altr,socfpga-s10-usb-ecc",
"altr,socfpga-usb-ecc"; "altr,socfpga-usb-ecc";
......
...@@ -56,6 +56,17 @@ osc1 { ...@@ -56,6 +56,17 @@ osc1 {
clock-frequency = <25000000>; clock-frequency = <25000000>;
}; };
}; };
eccmgr {
sdmmca-ecc@ff8c8c00 {
compatible = "altr,socfpga-s10-sdmmc-ecc",
"altr,socfpga-sdmmc-ecc";
reg = <0xff8c8c00 0x100>;
altr,ecc-parent = <&mmc>;
interrupts = <14 4>,
<15 4>;
};
};
}; };
}; };
......
...@@ -50,6 +50,7 @@ config RISCV ...@@ -50,6 +50,7 @@ config RISCV
select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_PTE_SPECIAL
select ARCH_HAS_MMIOWB select ARCH_HAS_MMIOWB
select HAVE_EBPF_JIT if 64BIT select HAVE_EBPF_JIT if 64BIT
select EDAC_SUPPORT
config MMU config MMU
def_bool y def_bool y
......
...@@ -460,6 +460,12 @@ config EDAC_ALTERA_SDMMC ...@@ -460,6 +460,12 @@ config EDAC_ALTERA_SDMMC
Support for error detection and correction on the Support for error detection and correction on the
Altera SDMMC FIFO Memory for Altera SoCs. Altera SDMMC FIFO Memory for Altera SoCs.
config EDAC_SIFIVE
bool "Sifive platform EDAC driver"
depends on EDAC=y && RISCV
help
Support for error detection and correction on the SiFive SoCs.
config EDAC_SYNOPSYS config EDAC_SYNOPSYS
tristate "Synopsys DDR Memory Controller" tristate "Synopsys DDR Memory Controller"
depends on ARCH_ZYNQ || ARCH_ZYNQMP depends on ARCH_ZYNQ || ARCH_ZYNQMP
......
...@@ -79,6 +79,7 @@ obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o ...@@ -79,6 +79,7 @@ obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o
obj-$(CONFIG_EDAC_THUNDERX) += thunderx_edac.o obj-$(CONFIG_EDAC_THUNDERX) += thunderx_edac.o
obj-$(CONFIG_EDAC_ALTERA) += altera_edac.o obj-$(CONFIG_EDAC_ALTERA) += altera_edac.o
obj-$(CONFIG_EDAC_SIFIVE) += sifive_edac.o
obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o
obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o
obj-$(CONFIG_EDAC_TI) += ti_edac.o obj-$(CONFIG_EDAC_TI) += ti_edac.o
......
...@@ -1223,8 +1223,31 @@ static const struct edac_device_prv_data ocramecc_data = { ...@@ -1223,8 +1223,31 @@ static const struct edac_device_prv_data ocramecc_data = {
.inject_fops = &altr_edac_device_inject_fops, .inject_fops = &altr_edac_device_inject_fops,
}; };
static int __maybe_unused
altr_check_ocram_deps_init(struct altr_edac_device_dev *device)
{
void __iomem *base = device->base;
int ret;
ret = altr_check_ecc_deps(device);
if (ret)
return ret;
/* Verify OCRAM has been initialized */
if (!ecc_test_bits(ALTR_A10_ECC_INITCOMPLETEA,
(base + ALTR_A10_ECC_INITSTAT_OFST)))
return -ENODEV;
/* Enable IRQ on Single Bit Error */
writel(ALTR_A10_ECC_SERRINTEN, (base + ALTR_A10_ECC_ERRINTENS_OFST));
/* Ensure all writes complete */
wmb();
return 0;
}
static const struct edac_device_prv_data a10_ocramecc_data = { static const struct edac_device_prv_data a10_ocramecc_data = {
.setup = altr_check_ecc_deps, .setup = altr_check_ocram_deps_init,
.ce_clear_mask = ALTR_A10_ECC_SERRPENA, .ce_clear_mask = ALTR_A10_ECC_SERRPENA,
.ue_clear_mask = ALTR_A10_ECC_DERRPENA, .ue_clear_mask = ALTR_A10_ECC_DERRPENA,
.irq_status_mask = A10_SYSMGR_ECC_INTSTAT_OCRAM, .irq_status_mask = A10_SYSMGR_ECC_INTSTAT_OCRAM,
...@@ -1234,7 +1257,7 @@ static const struct edac_device_prv_data a10_ocramecc_data = { ...@@ -1234,7 +1257,7 @@ static const struct edac_device_prv_data a10_ocramecc_data = {
.ue_set_mask = ALTR_A10_ECC_TDERRA, .ue_set_mask = ALTR_A10_ECC_TDERRA,
.set_err_ofst = ALTR_A10_ECC_INTTEST_OFST, .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST,
.ecc_irq_handler = altr_edac_a10_ecc_irq, .ecc_irq_handler = altr_edac_a10_ecc_irq,
.inject_fops = &altr_edac_a10_device_inject_fops, .inject_fops = &altr_edac_a10_device_inject2_fops,
/* /*
* OCRAM panic on uncorrectable error because sleep/resume * OCRAM panic on uncorrectable error because sleep/resume
* functions and FPGA contents are stored in OCRAM. Prefer * functions and FPGA contents are stored in OCRAM. Prefer
...@@ -1560,8 +1583,12 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) ...@@ -1560,8 +1583,12 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
dci->mod_name = ecc_name; dci->mod_name = ecc_name;
dci->dev_name = ecc_name; dci->dev_name = ecc_name;
/* Update the IRQs for PortB */ /* Update the PortB IRQs - A10 has 4, S10 has 2, Index accordingly */
#ifdef CONFIG_ARCH_STRATIX10
altdev->sb_irq = irq_of_parse_and_map(np, 1);
#else
altdev->sb_irq = irq_of_parse_and_map(np, 2); altdev->sb_irq = irq_of_parse_and_map(np, 2);
#endif
if (!altdev->sb_irq) { if (!altdev->sb_irq) {
edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB SBIRQ alloc\n"); edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB SBIRQ alloc\n");
rc = -ENODEV; rc = -ENODEV;
...@@ -1576,6 +1603,15 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) ...@@ -1576,6 +1603,15 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
goto err_release_group_1; goto err_release_group_1;
} }
#ifdef CONFIG_ARCH_STRATIX10
/* Use IRQ to determine SError origin instead of assigning IRQ */
rc = of_property_read_u32_index(np, "interrupts", 1, &altdev->db_irq);
if (rc) {
edac_printk(KERN_ERR, EDAC_DEVICE,
"Error PortB DBIRQ alloc\n");
goto err_release_group_1;
}
#else
altdev->db_irq = irq_of_parse_and_map(np, 3); altdev->db_irq = irq_of_parse_and_map(np, 3);
if (!altdev->db_irq) { if (!altdev->db_irq) {
edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB DBIRQ alloc\n"); edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB DBIRQ alloc\n");
...@@ -1590,6 +1626,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) ...@@ -1590,6 +1626,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n"); edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n");
goto err_release_group_1; goto err_release_group_1;
} }
#endif
rc = edac_device_add_device(dci); rc = edac_device_add_device(dci);
if (rc) { if (rc) {
......
...@@ -281,15 +281,11 @@ static int aspeed_probe(struct platform_device *pdev) ...@@ -281,15 +281,11 @@ static int aspeed_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct edac_mc_layer layers[2]; struct edac_mc_layer layers[2];
struct mem_ctl_info *mci; struct mem_ctl_info *mci;
struct device_node *np;
struct resource *res; struct resource *res;
void __iomem *regs; void __iomem *regs;
u32 reg04; u32 reg04;
int rc; int rc;
/* setup regmap */
np = dev->of_node;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) if (!res)
return -ENOENT; return -ENOENT;
......
...@@ -118,23 +118,23 @@ edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent, ...@@ -118,23 +118,23 @@ edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent,
EXPORT_SYMBOL_GPL(edac_debugfs_create_file); EXPORT_SYMBOL_GPL(edac_debugfs_create_file);
/* Wrapper for debugfs_create_x8() */ /* Wrapper for debugfs_create_x8() */
struct dentry *edac_debugfs_create_x8(const char *name, umode_t mode, void edac_debugfs_create_x8(const char *name, umode_t mode,
struct dentry *parent, u8 *value) struct dentry *parent, u8 *value)
{ {
if (!parent) if (!parent)
parent = edac_debugfs; parent = edac_debugfs;
return debugfs_create_x8(name, mode, parent, value); debugfs_create_x8(name, mode, parent, value);
} }
EXPORT_SYMBOL_GPL(edac_debugfs_create_x8); EXPORT_SYMBOL_GPL(edac_debugfs_create_x8);
/* Wrapper for debugfs_create_x16() */ /* Wrapper for debugfs_create_x16() */
struct dentry *edac_debugfs_create_x16(const char *name, umode_t mode, void edac_debugfs_create_x16(const char *name, umode_t mode,
struct dentry *parent, u16 *value) struct dentry *parent, u16 *value)
{ {
if (!parent) if (!parent)
parent = edac_debugfs; parent = edac_debugfs;
return debugfs_create_x16(name, mode, parent, value); debugfs_create_x16(name, mode, parent, value);
} }
EXPORT_SYMBOL_GPL(edac_debugfs_create_x16); EXPORT_SYMBOL_GPL(edac_debugfs_create_x16);
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
static int edac_mc_log_ue = 1; static int edac_mc_log_ue = 1;
static int edac_mc_log_ce = 1; static int edac_mc_log_ce = 1;
static int edac_mc_panic_on_ue; static int edac_mc_panic_on_ue;
static int edac_mc_poll_msec = 1000; static unsigned int edac_mc_poll_msec = 1000;
/* Getter functions for above */ /* Getter functions for above */
int edac_mc_get_log_ue(void) int edac_mc_get_log_ue(void)
...@@ -45,30 +45,30 @@ int edac_mc_get_panic_on_ue(void) ...@@ -45,30 +45,30 @@ int edac_mc_get_panic_on_ue(void)
} }
/* this is temporary */ /* this is temporary */
int edac_mc_get_poll_msec(void) unsigned int edac_mc_get_poll_msec(void)
{ {
return edac_mc_poll_msec; return edac_mc_poll_msec;
} }
static int edac_set_poll_msec(const char *val, const struct kernel_param *kp) static int edac_set_poll_msec(const char *val, const struct kernel_param *kp)
{ {
unsigned long l; unsigned int i;
int ret; int ret;
if (!val) if (!val)
return -EINVAL; return -EINVAL;
ret = kstrtoul(val, 0, &l); ret = kstrtouint(val, 0, &i);
if (ret) if (ret)
return ret; return ret;
if (l < 1000) if (i < 1000)
return -EINVAL; return -EINVAL;
*((unsigned long *)kp->arg) = l; *((unsigned int *)kp->arg) = i;
/* notify edac_mc engine to reset the poll period */ /* notify edac_mc engine to reset the poll period */
edac_mc_reset_delay_period(l); edac_mc_reset_delay_period(i);
return 0; return 0;
} }
...@@ -82,7 +82,7 @@ MODULE_PARM_DESC(edac_mc_log_ue, ...@@ -82,7 +82,7 @@ MODULE_PARM_DESC(edac_mc_log_ue,
module_param(edac_mc_log_ce, int, 0644); module_param(edac_mc_log_ce, int, 0644);
MODULE_PARM_DESC(edac_mc_log_ce, MODULE_PARM_DESC(edac_mc_log_ce,
"Log correctable error to console: 0=off 1=on"); "Log correctable error to console: 0=off 1=on");
module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_int, module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_uint,
&edac_mc_poll_msec, 0644); &edac_mc_poll_msec, 0644);
MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds"); MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
...@@ -404,6 +404,8 @@ static inline int nr_pages_per_csrow(struct csrow_info *csrow) ...@@ -404,6 +404,8 @@ static inline int nr_pages_per_csrow(struct csrow_info *csrow)
static int edac_create_csrow_object(struct mem_ctl_info *mci, static int edac_create_csrow_object(struct mem_ctl_info *mci,
struct csrow_info *csrow, int index) struct csrow_info *csrow, int index)
{ {
int err;
csrow->dev.type = &csrow_attr_type; csrow->dev.type = &csrow_attr_type;
csrow->dev.groups = csrow_dev_groups; csrow->dev.groups = csrow_dev_groups;
device_initialize(&csrow->dev); device_initialize(&csrow->dev);
...@@ -415,7 +417,11 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci, ...@@ -415,7 +417,11 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
edac_dbg(0, "creating (virtual) csrow node %s\n", edac_dbg(0, "creating (virtual) csrow node %s\n",
dev_name(&csrow->dev)); dev_name(&csrow->dev));
return device_add(&csrow->dev); err = device_add(&csrow->dev);
if (err)
put_device(&csrow->dev);
return err;
} }
/* Create a CSROW object under specifed edac_mc_device */ /* Create a CSROW object under specifed edac_mc_device */
...@@ -443,7 +449,8 @@ static int edac_create_csrow_objects(struct mem_ctl_info *mci) ...@@ -443,7 +449,8 @@ static int edac_create_csrow_objects(struct mem_ctl_info *mci)
csrow = mci->csrows[i]; csrow = mci->csrows[i];
if (!nr_pages_per_csrow(csrow)) if (!nr_pages_per_csrow(csrow))
continue; continue;
put_device(&mci->csrows[i]->dev);
device_del(&mci->csrows[i]->dev);
} }
return err; return err;
...@@ -646,8 +653,10 @@ static int edac_create_dimm_object(struct mem_ctl_info *mci, ...@@ -646,8 +653,10 @@ static int edac_create_dimm_object(struct mem_ctl_info *mci,
pm_runtime_forbid(&mci->dev); pm_runtime_forbid(&mci->dev);
err = device_add(&dimm->dev); err = device_add(&dimm->dev);
if (err)
put_device(&dimm->dev);
edac_dbg(0, "creating rank/dimm device %s\n", dev_name(&dimm->dev)); edac_dbg(0, "created rank/dimm device %s\n", dev_name(&dimm->dev));
return err; return err;
} }
...@@ -928,6 +937,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci, ...@@ -928,6 +937,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
err = device_add(&mci->dev); err = device_add(&mci->dev);
if (err < 0) { if (err < 0) {
edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev)); edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev));
put_device(&mci->dev);
goto out; goto out;
} }
......
...@@ -36,7 +36,7 @@ extern int edac_mc_get_log_ue(void); ...@@ -36,7 +36,7 @@ extern int edac_mc_get_log_ue(void);
extern int edac_mc_get_log_ce(void); extern int edac_mc_get_log_ce(void);
extern int edac_mc_get_panic_on_ue(void); extern int edac_mc_get_panic_on_ue(void);
extern int edac_get_poll_msec(void); extern int edac_get_poll_msec(void);
extern int edac_mc_get_poll_msec(void); extern unsigned int edac_mc_get_poll_msec(void);
unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf, unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf,
unsigned len); unsigned len);
...@@ -78,10 +78,10 @@ edac_debugfs_create_dir_at(const char *dirname, struct dentry *parent); ...@@ -78,10 +78,10 @@ edac_debugfs_create_dir_at(const char *dirname, struct dentry *parent);
struct dentry * struct dentry *
edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent, edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent,
void *data, const struct file_operations *fops); void *data, const struct file_operations *fops);
struct dentry * void edac_debugfs_create_x8(const char *name, umode_t mode,
edac_debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, u8 *value); struct dentry *parent, u8 *value);
struct dentry * void edac_debugfs_create_x16(const char *name, umode_t mode,
edac_debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent, u16 *value); struct dentry *parent, u16 *value);
#else #else
static inline void edac_debugfs_init(void) { } static inline void edac_debugfs_init(void) { }
static inline void edac_debugfs_exit(void) { } static inline void edac_debugfs_exit(void) { }
...@@ -92,12 +92,10 @@ edac_debugfs_create_dir_at(const char *dirname, struct dentry *parent) { return ...@@ -92,12 +92,10 @@ edac_debugfs_create_dir_at(const char *dirname, struct dentry *parent) { return
static inline struct dentry * static inline struct dentry *
edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent, edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent,
void *data, const struct file_operations *fops) { return NULL; } void *data, const struct file_operations *fops) { return NULL; }
static inline struct dentry * static inline void edac_debugfs_create_x8(const char *name, umode_t mode,
edac_debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, u8 *value) { }
struct dentry *parent, u8 *value) { return NULL; } static inline void edac_debugfs_create_x16(const char *name, umode_t mode,
static inline struct dentry * struct dentry *parent, u16 *value) { }
edac_debugfs_create_x16(const char *name, umode_t mode,
struct dentry *parent, u16 *value) { return NULL; }
#endif #endif
/* /*
......
...@@ -124,6 +124,8 @@ static int i10nm_get_all_munits(void) ...@@ -124,6 +124,8 @@ static int i10nm_get_all_munits(void)
static const struct x86_cpu_id i10nm_cpuids[] = { static const struct x86_cpu_id i10nm_cpuids[] = {
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_TREMONT_X, 0, 0 }, { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_TREMONT_X, 0, 0 },
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ICELAKE_X, 0, 0 },
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ICELAKE_XEON_D, 0, 0 },
{ } { }
}; };
MODULE_DEVICE_TABLE(x86cpu, i10nm_cpuids); MODULE_DEVICE_TABLE(x86cpu, i10nm_cpuids);
...@@ -166,9 +168,9 @@ static int i10nm_get_dimm_config(struct mem_ctl_info *mci) ...@@ -166,9 +168,9 @@ static int i10nm_get_dimm_config(struct mem_ctl_info *mci)
ndimms += skx_get_nvdimm_info(dimm, imc, i, j, ndimms += skx_get_nvdimm_info(dimm, imc, i, j,
EDAC_MOD_STR); EDAC_MOD_STR);
} }
if (ndimms && !i10nm_check_ecc(imc, 0)) { if (ndimms && !i10nm_check_ecc(imc, i)) {
i10nm_printk(KERN_ERR, "ECC is disabled on imc %d\n", i10nm_printk(KERN_ERR, "ECC is disabled on imc %d channel %d\n",
imc->mc); imc->mc, i);
return -ENODEV; return -ENODEV;
} }
} }
...@@ -265,7 +267,7 @@ static int __init i10nm_init(void) ...@@ -265,7 +267,7 @@ static int __init i10nm_init(void)
goto fail; goto fail;
list_for_each_entry(d, i10nm_edac_list, list) { list_for_each_entry(d, i10nm_edac_list, list) {
rc = skx_get_src_id(d, &src_id); rc = skx_get_src_id(d, 0xf8, &src_id);
if (rc < 0) if (rc < 0)
goto fail; goto fail;
......
...@@ -20,11 +20,13 @@ ...@@ -20,11 +20,13 @@
* 0c08: Xeon E3-1200 v3 Processor DRAM Controller * 0c08: Xeon E3-1200 v3 Processor DRAM Controller
* 1918: Xeon E3-1200 v5 Skylake Host Bridge/DRAM Registers * 1918: Xeon E3-1200 v5 Skylake Host Bridge/DRAM Registers
* 5918: Xeon E3-1200 Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers * 5918: Xeon E3-1200 Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers
* 3e..: 8th/9th Gen Core Processor Host Bridge/DRAM Registers
* *
* Based on Intel specification: * Based on Intel specification:
* http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e3-1200v3-vol-2-datasheet.pdf * http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e3-1200v3-vol-2-datasheet.pdf
* http://www.intel.com/content/www/us/en/processors/xeon/xeon-e3-1200-family-vol-2-datasheet.html * http://www.intel.com/content/www/us/en/processors/xeon/xeon-e3-1200-family-vol-2-datasheet.html
* http://www.intel.com/content/www/us/en/processors/core/7th-gen-core-family-mobile-h-processor-lines-datasheet-vol-2.html * http://www.intel.com/content/www/us/en/processors/core/7th-gen-core-family-mobile-h-processor-lines-datasheet-vol-2.html
* https://www.intel.com/content/www/us/en/products/docs/processors/core/8th-gen-core-family-datasheet-vol-2.html
* *
* According to the above datasheet (p.16): * According to the above datasheet (p.16):
* " * "
...@@ -61,6 +63,26 @@ ...@@ -61,6 +63,26 @@
#define PCI_DEVICE_ID_INTEL_IE31200_HB_8 0x1918 #define PCI_DEVICE_ID_INTEL_IE31200_HB_8 0x1918
#define PCI_DEVICE_ID_INTEL_IE31200_HB_9 0x5918 #define PCI_DEVICE_ID_INTEL_IE31200_HB_9 0x5918
/* Coffee Lake-S */
#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK 0x3e00
#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_1 0x3e0f
#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_2 0x3e18
#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_3 0x3e1f
#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_4 0x3e30
#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_5 0x3e31
#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_6 0x3e32
#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_7 0x3e33
#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_8 0x3ec2
#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_9 0x3ec6
#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_10 0x3eca
/* Test if HB is for Skylake or later. */
#define DEVICE_ID_SKYLAKE_OR_LATER(did) \
(((did) == PCI_DEVICE_ID_INTEL_IE31200_HB_8) || \
((did) == PCI_DEVICE_ID_INTEL_IE31200_HB_9) || \
(((did) & PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK) == \
PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK))
#define IE31200_DIMMS 4 #define IE31200_DIMMS 4
#define IE31200_RANKS 8 #define IE31200_RANKS 8
#define IE31200_RANKS_PER_CHANNEL 4 #define IE31200_RANKS_PER_CHANNEL 4
...@@ -381,10 +403,10 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx) ...@@ -381,10 +403,10 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx)
u32 addr_decode, mad_offset; u32 addr_decode, mad_offset;
/* /*
* Kaby Lake seems to work like Skylake. Please re-visit this logic * Kaby Lake, Coffee Lake seem to work like Skylake. Please re-visit
* when adding new CPU support. * this logic when adding new CPU support.
*/ */
bool skl = (pdev->device >= PCI_DEVICE_ID_INTEL_IE31200_HB_8); bool skl = DEVICE_ID_SKYLAKE_OR_LATER(pdev->device);
edac_dbg(0, "MC:\n"); edac_dbg(0, "MC:\n");
...@@ -542,36 +564,26 @@ static void ie31200_remove_one(struct pci_dev *pdev) ...@@ -542,36 +564,26 @@ static void ie31200_remove_one(struct pci_dev *pdev)
} }
static const struct pci_device_id ie31200_pci_tbl[] = { static const struct pci_device_id ie31200_pci_tbl[] = {
{ { PCI_VEND_DEV(INTEL, IE31200_HB_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
PCI_VEND_DEV(INTEL, IE31200_HB_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0, { PCI_VEND_DEV(INTEL, IE31200_HB_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
IE31200}, { PCI_VEND_DEV(INTEL, IE31200_HB_3), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
{ { PCI_VEND_DEV(INTEL, IE31200_HB_4), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
PCI_VEND_DEV(INTEL, IE31200_HB_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0, { PCI_VEND_DEV(INTEL, IE31200_HB_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
IE31200}, { PCI_VEND_DEV(INTEL, IE31200_HB_6), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
{ { PCI_VEND_DEV(INTEL, IE31200_HB_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
PCI_VEND_DEV(INTEL, IE31200_HB_3), PCI_ANY_ID, PCI_ANY_ID, 0, 0, { PCI_VEND_DEV(INTEL, IE31200_HB_8), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
IE31200}, { PCI_VEND_DEV(INTEL, IE31200_HB_9), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
{ { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
PCI_VEND_DEV(INTEL, IE31200_HB_4), PCI_ANY_ID, PCI_ANY_ID, 0, 0, { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
IE31200}, { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_3), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
{ { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_4), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
PCI_VEND_DEV(INTEL, IE31200_HB_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0, { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
IE31200}, { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_6), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
{ { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
PCI_VEND_DEV(INTEL, IE31200_HB_6), PCI_ANY_ID, PCI_ANY_ID, 0, 0, { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_8), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
IE31200}, { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_9), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
{ { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_10), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
PCI_VEND_DEV(INTEL, IE31200_HB_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0, { 0, } /* 0 terminated list. */
IE31200},
{
PCI_VEND_DEV(INTEL, IE31200_HB_8), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
IE31200},
{
PCI_VEND_DEV(INTEL, IE31200_HB_9), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
IE31200},
{
0,
} /* 0 terminated list. */
}; };
MODULE_DEVICE_TABLE(pci, ie31200_pci_tbl); MODULE_DEVICE_TABLE(pci, ie31200_pci_tbl);
......
...@@ -1511,7 +1511,6 @@ static int knl_get_dimm_capacity(struct sbridge_pvt *pvt, u64 *mc_sizes) ...@@ -1511,7 +1511,6 @@ static int knl_get_dimm_capacity(struct sbridge_pvt *pvt, u64 *mc_sizes)
sad_actual_size[mc] += tad_size; sad_actual_size[mc] += tad_size;
} }
} }
tad_base = tad_limit+1;
} }
} }
......
// SPDX-License-Identifier: GPL-2.0
/*
* SiFive Platform EDAC Driver
*
* Copyright (C) 2018-2019 SiFive, Inc.
*
* This driver is partially based on octeon_edac-pc.c
*
*/
#include <linux/edac.h>
#include <linux/platform_device.h>
#include "edac_module.h"
#include <asm/sifive_l2_cache.h>
#define DRVNAME "sifive_edac"
struct sifive_edac_priv {
struct notifier_block notifier;
struct edac_device_ctl_info *dci;
};
/**
* EDAC error callback
*
* @event: non-zero if unrecoverable.
*/
static
int ecc_err_event(struct notifier_block *this, unsigned long event, void *ptr)
{
const char *msg = (char *)ptr;
struct sifive_edac_priv *p;
p = container_of(this, struct sifive_edac_priv, notifier);
if (event == SIFIVE_L2_ERR_TYPE_UE)
edac_device_handle_ue(p->dci, 0, 0, msg);
else if (event == SIFIVE_L2_ERR_TYPE_CE)
edac_device_handle_ce(p->dci, 0, 0, msg);
return NOTIFY_OK;
}
static int ecc_register(struct platform_device *pdev)
{
struct sifive_edac_priv *p;
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
p->notifier.notifier_call = ecc_err_event;
platform_set_drvdata(pdev, p);
p->dci = edac_device_alloc_ctl_info(0, "sifive_ecc", 1, "sifive_ecc",
1, 1, NULL, 0,
edac_device_alloc_index());
if (IS_ERR(p->dci))
return PTR_ERR(p->dci);
p->dci->dev = &pdev->dev;
p->dci->mod_name = "Sifive ECC Manager";
p->dci->ctl_name = dev_name(&pdev->dev);
p->dci->dev_name = dev_name(&pdev->dev);
if (edac_device_add_device(p->dci)) {
dev_err(p->dci->dev, "failed to register with EDAC core\n");
goto err;
}
register_sifive_l2_error_notifier(&p->notifier);
return 0;
err:
edac_device_free_ctl_info(p->dci);
return -ENXIO;
}
static int ecc_unregister(struct platform_device *pdev)
{
struct sifive_edac_priv *p = platform_get_drvdata(pdev);
unregister_sifive_l2_error_notifier(&p->notifier);
edac_device_del_device(&pdev->dev);
edac_device_free_ctl_info(p->dci);
return 0;
}
static struct platform_device *sifive_pdev;
static int __init sifive_edac_init(void)
{
int ret;
sifive_pdev = platform_device_register_simple(DRVNAME, 0, NULL, 0);
if (IS_ERR(sifive_pdev))
return PTR_ERR(sifive_pdev);
ret = ecc_register(sifive_pdev);
if (ret)
platform_device_unregister(sifive_pdev);
return ret;
}
static void __exit sifive_edac_exit(void)
{
ecc_unregister(sifive_pdev);
platform_device_unregister(sifive_pdev);
}
module_init(sifive_edac_init);
module_exit(sifive_edac_exit);
MODULE_AUTHOR("SiFive Inc.");
MODULE_DESCRIPTION("SiFive platform EDAC driver");
MODULE_LICENSE("GPL v2");
...@@ -639,7 +639,7 @@ static int __init skx_init(void) ...@@ -639,7 +639,7 @@ static int __init skx_init(void)
} }
list_for_each_entry(d, skx_edac_list, list) { list_for_each_entry(d, skx_edac_list, list) {
rc = skx_get_src_id(d, &src_id); rc = skx_get_src_id(d, 0xf0, &src_id);
if (rc < 0) if (rc < 0)
goto fail; goto fail;
rc = skx_get_node_id(d, &node_id); rc = skx_get_node_id(d, &node_id);
......
...@@ -136,11 +136,11 @@ void skx_set_decode(skx_decode_f decode) ...@@ -136,11 +136,11 @@ void skx_set_decode(skx_decode_f decode)
skx_decode = decode; skx_decode = decode;
} }
int skx_get_src_id(struct skx_dev *d, u8 *id) int skx_get_src_id(struct skx_dev *d, int off, u8 *id)
{ {
u32 reg; u32 reg;
if (pci_read_config_dword(d->util_all, 0xf0, &reg)) { if (pci_read_config_dword(d->util_all, off, &reg)) {
skx_printk(KERN_ERR, "Failed to read src id\n"); skx_printk(KERN_ERR, "Failed to read src id\n");
return -ENODEV; return -ENODEV;
} }
......
...@@ -118,7 +118,7 @@ int __init skx_adxl_get(void); ...@@ -118,7 +118,7 @@ int __init skx_adxl_get(void);
void __exit skx_adxl_put(void); void __exit skx_adxl_put(void);
void skx_set_decode(skx_decode_f decode); void skx_set_decode(skx_decode_f decode);
int skx_get_src_id(struct skx_dev *d, u8 *id); int skx_get_src_id(struct skx_dev *d, int off, u8 *id);
int skx_get_node_id(struct skx_dev *d, u8 *id); int skx_get_node_id(struct skx_dev *d, u8 *id);
int skx_get_all_bus_mappings(unsigned int did, int off, enum type, int skx_get_all_bus_mappings(unsigned int did, int off, enum type,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment