EDAC changes for v5.3
-----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJdI2fNAAoJEKurIx+X31iBJVoP/jSJbSY49IcJ7st8uolxJ9d9 84ol7TNBnKeKeUXxrQom2hJsqUnQzaUgw3FKfxX0hmYG5Q9xGS8c+BlW4Giei+Ur baGLO7/UEudWcaez3yOQF+R+yVfsLEATN7gSHcrG81aDyR0F6sMPVCOJOj3hqqnY pZpfxR2+52Xx+Bt8KUUQziCK8qghQYKqHUQUz7R83L0gbbx5+hTAT08h4FCxE8Vx fhntQuteJ2PfYgXlmfv+ZLE4HSHaAlokOnVXJhK+7tMdwDD2we+pL0zr5XdbkZYc If6p9LgJinMe5P5gJSvxT1idWmomKIQqazaC17ff/anLRySrzi9F2oPAGtVI2tvK NekoO3oo4s+xONXfe7Q922rIGt/4vZj6tcqBuMYCOAU7TJGQRqDeEl4+T+aIZNMB 9QBFUfKupy7XZ3H5rJTrYaXFPyYkdRGu5ODEHvwnpRiu+uD1UaTR57iyK5kjToGY mcK3nVad2X1foMOQW33jVAhxGJ+sz2YB/XgQuNnqpUFKktLQ8Es1CSgzB02GvW2b OBJiFCZybMKtBnTEVINYc/dcZ6uOUQ17BwKoR4szFGQLWrzbnfe7as5fa0uyj3ib BEbWcDM3KCDMRWAE/VwgyGzH3lg4QP1mE7uRdLfMb5JhIbQvHjo7T0bUBzUy5/Mf 4P9CWweplIi82Q0f2q7r =5hCV -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
947fbd4ca9
|
@ -5828,6 +5828,12 @@ L: linux-edac@vger.kernel.org
|
|||
S: Maintained
|
||||
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
|
||||
M: Tony Luck <tony.luck@intel.com>
|
||||
L: linux-edac@vger.kernel.org
|
||||
|
|
|
@ -539,6 +539,14 @@ sdramedac {
|
|||
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 {
|
||||
compatible = "altr,socfpga-s10-usb-ecc",
|
||||
"altr,socfpga-usb-ecc";
|
||||
|
|
|
@ -56,6 +56,17 @@ osc1 {
|
|||
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
|
|||
select ARCH_HAS_PTE_SPECIAL
|
||||
select ARCH_HAS_MMIOWB
|
||||
select HAVE_EBPF_JIT if 64BIT
|
||||
select EDAC_SUPPORT
|
||||
|
||||
config MMU
|
||||
def_bool y
|
||||
|
|
|
@ -460,6 +460,12 @@ config EDAC_ALTERA_SDMMC
|
|||
Support for error detection and correction on the
|
||||
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
|
||||
tristate "Synopsys DDR Memory Controller"
|
||||
depends on ARCH_ZYNQ || ARCH_ZYNQMP
|
||||
|
|
|
@ -79,6 +79,7 @@ obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o
|
|||
obj-$(CONFIG_EDAC_THUNDERX) += thunderx_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_XGENE) += xgene_edac.o
|
||||
obj-$(CONFIG_EDAC_TI) += ti_edac.o
|
||||
|
|
|
@ -1223,8 +1223,31 @@ static const struct edac_device_prv_data ocramecc_data = {
|
|||
.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 = {
|
||||
.setup = altr_check_ecc_deps,
|
||||
.setup = altr_check_ocram_deps_init,
|
||||
.ce_clear_mask = ALTR_A10_ECC_SERRPENA,
|
||||
.ue_clear_mask = ALTR_A10_ECC_DERRPENA,
|
||||
.irq_status_mask = A10_SYSMGR_ECC_INTSTAT_OCRAM,
|
||||
|
@ -1234,7 +1257,7 @@ static const struct edac_device_prv_data a10_ocramecc_data = {
|
|||
.ue_set_mask = ALTR_A10_ECC_TDERRA,
|
||||
.set_err_ofst = ALTR_A10_ECC_INTTEST_OFST,
|
||||
.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
|
||||
* functions and FPGA contents are stored in OCRAM. Prefer
|
||||
|
@ -1560,8 +1583,12 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
|
|||
dci->mod_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);
|
||||
#endif
|
||||
if (!altdev->sb_irq) {
|
||||
edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB SBIRQ alloc\n");
|
||||
rc = -ENODEV;
|
||||
|
@ -1576,6 +1603,15 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
|
|||
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);
|
||||
if (!altdev->db_irq) {
|
||||
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)
|
|||
edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n");
|
||||
goto err_release_group_1;
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = edac_device_add_device(dci);
|
||||
if (rc) {
|
||||
|
|
|
@ -281,15 +281,11 @@ static int aspeed_probe(struct platform_device *pdev)
|
|||
struct device *dev = &pdev->dev;
|
||||
struct edac_mc_layer layers[2];
|
||||
struct mem_ctl_info *mci;
|
||||
struct device_node *np;
|
||||
struct resource *res;
|
||||
void __iomem *regs;
|
||||
u32 reg04;
|
||||
int rc;
|
||||
|
||||
/* setup regmap */
|
||||
np = dev->of_node;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENOENT;
|
||||
|
|
|
@ -118,23 +118,23 @@ edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent,
|
|||
EXPORT_SYMBOL_GPL(edac_debugfs_create_file);
|
||||
|
||||
/* Wrapper for debugfs_create_x8() */
|
||||
struct dentry *edac_debugfs_create_x8(const char *name, umode_t mode,
|
||||
struct dentry *parent, u8 *value)
|
||||
void edac_debugfs_create_x8(const char *name, umode_t mode,
|
||||
struct dentry *parent, u8 *value)
|
||||
{
|
||||
if (!parent)
|
||||
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);
|
||||
|
||||
/* Wrapper for debugfs_create_x16() */
|
||||
struct dentry *edac_debugfs_create_x16(const char *name, umode_t mode,
|
||||
struct dentry *parent, u16 *value)
|
||||
void edac_debugfs_create_x16(const char *name, umode_t mode,
|
||||
struct dentry *parent, u16 *value)
|
||||
{
|
||||
if (!parent)
|
||||
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);
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
static int edac_mc_log_ue = 1;
|
||||
static int edac_mc_log_ce = 1;
|
||||
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 */
|
||||
int edac_mc_get_log_ue(void)
|
||||
|
@ -45,30 +45,30 @@ int edac_mc_get_panic_on_ue(void)
|
|||
}
|
||||
|
||||
/* this is temporary */
|
||||
int edac_mc_get_poll_msec(void)
|
||||
unsigned int edac_mc_get_poll_msec(void)
|
||||
{
|
||||
return edac_mc_poll_msec;
|
||||
}
|
||||
|
||||
static int edac_set_poll_msec(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
unsigned long l;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (!val)
|
||||
return -EINVAL;
|
||||
|
||||
ret = kstrtoul(val, 0, &l);
|
||||
ret = kstrtouint(val, 0, &i);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (l < 1000)
|
||||
if (i < 1000)
|
||||
return -EINVAL;
|
||||
|
||||
*((unsigned long *)kp->arg) = l;
|
||||
*((unsigned int *)kp->arg) = i;
|
||||
|
||||
/* notify edac_mc engine to reset the poll period */
|
||||
edac_mc_reset_delay_period(l);
|
||||
edac_mc_reset_delay_period(i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ MODULE_PARM_DESC(edac_mc_log_ue,
|
|||
module_param(edac_mc_log_ce, int, 0644);
|
||||
MODULE_PARM_DESC(edac_mc_log_ce,
|
||||
"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);
|
||||
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)
|
|||
static int edac_create_csrow_object(struct mem_ctl_info *mci,
|
||||
struct csrow_info *csrow, int index)
|
||||
{
|
||||
int err;
|
||||
|
||||
csrow->dev.type = &csrow_attr_type;
|
||||
csrow->dev.groups = csrow_dev_groups;
|
||||
device_initialize(&csrow->dev);
|
||||
|
@ -415,7 +417,11 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
|
|||
edac_dbg(0, "creating (virtual) csrow node %s\n",
|
||||
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 */
|
||||
|
@ -443,7 +449,8 @@ static int edac_create_csrow_objects(struct mem_ctl_info *mci)
|
|||
csrow = mci->csrows[i];
|
||||
if (!nr_pages_per_csrow(csrow))
|
||||
continue;
|
||||
put_device(&mci->csrows[i]->dev);
|
||||
|
||||
device_del(&mci->csrows[i]->dev);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -645,9 +652,11 @@ static int edac_create_dimm_object(struct mem_ctl_info *mci,
|
|||
dev_set_drvdata(&dimm->dev, dimm);
|
||||
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;
|
||||
}
|
||||
|
@ -928,6 +937,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
|
|||
err = device_add(&mci->dev);
|
||||
if (err < 0) {
|
||||
edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev));
|
||||
put_device(&mci->dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
@ -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_panic_on_ue(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 len);
|
||||
|
@ -78,10 +78,10 @@ edac_debugfs_create_dir_at(const char *dirname, struct dentry *parent);
|
|||
struct dentry *
|
||||
edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent,
|
||||
void *data, const struct file_operations *fops);
|
||||
struct dentry *
|
||||
edac_debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, u8 *value);
|
||||
struct dentry *
|
||||
edac_debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent, u16 *value);
|
||||
void edac_debugfs_create_x8(const char *name, umode_t mode,
|
||||
struct dentry *parent, u8 *value);
|
||||
void edac_debugfs_create_x16(const char *name, umode_t mode,
|
||||
struct dentry *parent, u16 *value);
|
||||
#else
|
||||
static inline void edac_debugfs_init(void) { }
|
||||
static inline void edac_debugfs_exit(void) { }
|
||||
|
@ -92,12 +92,10 @@ edac_debugfs_create_dir_at(const char *dirname, struct dentry *parent) { return
|
|||
static inline struct dentry *
|
||||
edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent,
|
||||
void *data, const struct file_operations *fops) { return NULL; }
|
||||
static inline struct dentry *
|
||||
edac_debugfs_create_x8(const char *name, umode_t mode,
|
||||
struct dentry *parent, u8 *value) { return NULL; }
|
||||
static inline struct dentry *
|
||||
edac_debugfs_create_x16(const char *name, umode_t mode,
|
||||
struct dentry *parent, u16 *value) { return NULL; }
|
||||
static inline void edac_debugfs_create_x8(const char *name, umode_t mode,
|
||||
struct dentry *parent, u8 *value) { }
|
||||
static inline void edac_debugfs_create_x16(const char *name, umode_t mode,
|
||||
struct dentry *parent, u16 *value) { }
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
@ -124,6 +124,8 @@ static int i10nm_get_all_munits(void)
|
|||
|
||||
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_ICELAKE_X, 0, 0 },
|
||||
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ICELAKE_XEON_D, 0, 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(x86cpu, i10nm_cpuids);
|
||||
|
@ -166,9 +168,9 @@ static int i10nm_get_dimm_config(struct mem_ctl_info *mci)
|
|||
ndimms += skx_get_nvdimm_info(dimm, imc, i, j,
|
||||
EDAC_MOD_STR);
|
||||
}
|
||||
if (ndimms && !i10nm_check_ecc(imc, 0)) {
|
||||
i10nm_printk(KERN_ERR, "ECC is disabled on imc %d\n",
|
||||
imc->mc);
|
||||
if (ndimms && !i10nm_check_ecc(imc, i)) {
|
||||
i10nm_printk(KERN_ERR, "ECC is disabled on imc %d channel %d\n",
|
||||
imc->mc, i);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
@ -265,7 +267,7 @@ static int __init i10nm_init(void)
|
|||
goto fail;
|
||||
|
||||
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)
|
||||
goto fail;
|
||||
|
||||
|
|
|
@ -20,11 +20,13 @@
|
|||
* 0c08: Xeon E3-1200 v3 Processor DRAM Controller
|
||||
* 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
|
||||
* 3e..: 8th/9th Gen Core Processor Host Bridge/DRAM Registers
|
||||
*
|
||||
* 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/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
|
||||
* 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):
|
||||
* "
|
||||
|
@ -61,6 +63,26 @@
|
|||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_8 0x1918
|
||||
#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_RANKS 8
|
||||
#define IE31200_RANKS_PER_CHANNEL 4
|
||||
|
@ -381,10 +403,10 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx)
|
|||
u32 addr_decode, mad_offset;
|
||||
|
||||
/*
|
||||
* Kaby Lake seems to work like Skylake. Please re-visit this logic
|
||||
* when adding new CPU support.
|
||||
* Kaby Lake, Coffee Lake seem to work like Skylake. Please re-visit
|
||||
* 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");
|
||||
|
||||
|
@ -542,36 +564,26 @@ static void ie31200_remove_one(struct pci_dev *pdev)
|
|||
}
|
||||
|
||||
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_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
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_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
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_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. */
|
||||
{ PCI_VEND_DEV(INTEL, IE31200_HB_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
|
||||
{ PCI_VEND_DEV(INTEL, IE31200_HB_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 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_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 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_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 },
|
||||
{ PCI_VEND_DEV(INTEL, IE31200_HB_CFL_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
|
||||
{ PCI_VEND_DEV(INTEL, IE31200_HB_CFL_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 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_CFL_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 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_CFL_8), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 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 },
|
||||
{ 0, } /* 0 terminated list. */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, ie31200_pci_tbl);
|
||||
|
||||
|
|
|
@ -1511,7 +1511,6 @@ static int knl_get_dimm_capacity(struct sbridge_pvt *pvt, u64 *mc_sizes)
|
|||
sad_actual_size[mc] += tad_size;
|
||||
}
|
||||
}
|
||||
tad_base = tad_limit+1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
// 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)
|
|||
}
|
||||
|
||||
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)
|
||||
goto fail;
|
||||
rc = skx_get_node_id(d, &node_id);
|
||||
|
|
|
@ -136,11 +136,11 @@ void skx_set_decode(skx_decode_f 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;
|
||||
|
||||
if (pci_read_config_dword(d->util_all, 0xf0, ®)) {
|
||||
if (pci_read_config_dword(d->util_all, off, ®)) {
|
||||
skx_printk(KERN_ERR, "Failed to read src id\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ int __init skx_adxl_get(void);
|
|||
void __exit skx_adxl_put(void);
|
||||
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_all_bus_mappings(unsigned int did, int off, enum type,
|
||||
|
|
Loading…
Reference in New Issue