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
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;
}
}
......
// 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, &reg)) {
if (pci_read_config_dword(d->util_all, off, &reg)) {
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,
......
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