summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/edac/aspeed-sdram-edac.txt9
-rw-r--r--MAINTAINERS11
-rw-r--r--arch/arm/boot/dts/aspeed-g6.dtsi6
-rw-r--r--drivers/edac/Kconfig22
-rw-r--r--drivers/edac/Makefile2
-rw-r--r--drivers/edac/amd64_edac.c34
-rw-r--r--drivers/edac/amd76x_edac.c1
-rw-r--r--drivers/edac/aspeed_edac.c7
-rw-r--r--drivers/edac/e752x_edac.c1
-rw-r--r--drivers/edac/e7xxx_edac.c1
-rw-r--r--drivers/edac/edac_device.h11
-rw-r--r--drivers/edac/edac_mc.c4
-rw-r--r--drivers/edac/i10nm_base.c39
-rw-r--r--drivers/edac/i3000_edac.c1
-rw-r--r--drivers/edac/i3200_edac.c1
-rw-r--r--drivers/edac/i5000_edac.c2
-rw-r--r--drivers/edac/i5400_edac.c2
-rw-r--r--drivers/edac/i82443bxgx_edac.c1
-rw-r--r--drivers/edac/i82860_edac.c1
-rw-r--r--drivers/edac/i82875p_edac.c1
-rw-r--r--drivers/edac/i82975x_edac.c1
-rw-r--r--drivers/edac/ie31200_edac.c1
-rw-r--r--drivers/edac/igen6_edac.c977
-rw-r--r--drivers/edac/mv64x60_edac.c883
-rw-r--r--drivers/edac/mv64x60_edac.h114
-rw-r--r--drivers/edac/r82600_edac.c1
-rw-r--r--drivers/edac/skx_base.c6
-rw-r--r--drivers/edac/skx_common.c23
-rw-r--r--drivers/edac/skx_common.h16
-rw-r--r--drivers/edac/synopsys_edac.c3
-rw-r--r--drivers/edac/x38_edac.c1
-rw-r--r--include/linux/edac.h16
32 files changed, 1119 insertions, 1080 deletions
diff --git a/Documentation/devicetree/bindings/edac/aspeed-sdram-edac.txt b/Documentation/devicetree/bindings/edac/aspeed-sdram-edac.txt
index 6a0f3d90d682..8ca9e0a049d8 100644
--- a/Documentation/devicetree/bindings/edac/aspeed-sdram-edac.txt
+++ b/Documentation/devicetree/bindings/edac/aspeed-sdram-edac.txt
@@ -1,6 +1,6 @@
-Aspeed AST2500 SoC EDAC node
+Aspeed BMC SoC EDAC node
-The Aspeed AST2500 SoC supports DDR3 and DDR4 memory with and without ECC (error
+The Aspeed BMC SoC supports DDR3 and DDR4 memory with and without ECC (error
correction check).
The memory controller supports SECDED (single bit error correction, double bit
@@ -11,7 +11,10 @@ Note, the bootloader must configure ECC mode in the memory controller.
Required properties:
-- compatible: should be "aspeed,ast2500-sdram-edac"
+- compatible: should be one of
+ - "aspeed,ast2400-sdram-edac"
+ - "aspeed,ast2500-sdram-edac"
+ - "aspeed,ast2600-sdram-edac"
- reg: sdram controller register set should be <0x1e6e0000 0x174>
- interrupts: should be AVIC interrupt #0
diff --git a/MAINTAINERS b/MAINTAINERS
index fb75813e23d4..38c1a1146a20 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2485,7 +2485,7 @@ F: drivers/clk/socfpga/
ARM/SOCFPGA EDAC SUPPORT
M: Dinh Nguyen <dinguyen@kernel.org>
S: Maintained
-F: drivers/edac/altera_edac.
+F: drivers/edac/altera_edac.[ch]
ARM/SPREADTRUM SoC SUPPORT
M: Orson Zhai <orsonzhai@gmail.com>
@@ -6370,6 +6370,13 @@ L: linux-edac@vger.kernel.org
S: Maintained
F: drivers/edac/ie31200_edac.c
+EDAC-IGEN6
+M: Tony Luck <tony.luck@intel.com>
+R: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
+L: linux-edac@vger.kernel.org
+S: Maintained
+F: drivers/edac/igen6_edac.c
+
EDAC-MPC85XX
M: Johannes Thumshirn <morbidrsa@gmail.com>
L: linux-edac@vger.kernel.org
@@ -6419,7 +6426,7 @@ EDAC-SKYLAKE
M: Tony Luck <tony.luck@intel.com>
L: linux-edac@vger.kernel.org
S: Maintained
-F: drivers/edac/skx_*.c
+F: drivers/edac/skx_*.[ch]
EDAC-TI
M: Tero Kristo <t-kristo@ti.com>
diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
index b58220a49cbd..74367ee96f20 100644
--- a/arch/arm/boot/dts/aspeed-g6.dtsi
+++ b/arch/arm/boot/dts/aspeed-g6.dtsi
@@ -69,6 +69,12 @@
always-on;
};
+ edac: sdram@1e6e0000 {
+ compatible = "aspeed,ast2600-sdram-edac", "syscon";
+ reg = <0x1e6e0000 0x174>;
+ interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
ahb {
compatible = "simple-bus";
#address-cells = <1>;
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 7a47680d6f07..81c42664f21b 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -269,6 +269,15 @@ config EDAC_PND2
first used on the Apollo Lake platform and Denverton
micro-server but may appear on others in the future.
+config EDAC_IGEN6
+ tristate "Intel client SoC Integrated MC"
+ depends on PCI && X86_64 && PCI_MMCONFIG && ARCH_HAVE_NMI_SAFE_CMPXCHG
+ help
+ Support for error detection and correction on the Intel
+ client SoC Integrated Memory Controller using In-Band ECC IP.
+ This In-Band ECC is first used on the Elkhart Lake SoC but
+ may appear on others in the future.
+
config EDAC_MPC85XX
bool "Freescale MPC83xx / MPC85xx"
depends on FSL_SOC && EDAC=y
@@ -283,13 +292,6 @@ config EDAC_LAYERSCAPE
Support for error detection and correction on Freescale memory
controllers on Layerscape SoCs.
-config EDAC_MV64X60
- tristate "Marvell MV64x60"
- depends on MV64X60
- help
- Support for error detection and correction on the Marvell
- MV64360 and MV64460 chipsets.
-
config EDAC_PASEMI
tristate "PA Semi PWRficient"
depends on PPC_PASEMI && PCI
@@ -515,10 +517,10 @@ config EDAC_QCOM
health, you should probably say 'Y' here.
config EDAC_ASPEED
- tristate "Aspeed AST 2500 SoC"
- depends on MACH_ASPEED_G5
+ tristate "Aspeed AST BMC SoC"
+ depends on ARCH_ASPEED
help
- Support for error detection and correction on the Aspeed AST 2500 SoC.
+ Support for error detection and correction on the Aspeed AST BMC SoC.
First, ECC must be configured in the bootloader. Then, this driver
will expose error counters via the EDAC kernel framework.
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 3a849168780d..464d3d8d850a 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_EDAC_I7300) += i7300_edac.o
obj-$(CONFIG_EDAC_I7CORE) += i7core_edac.o
obj-$(CONFIG_EDAC_SBRIDGE) += sb_edac.o
obj-$(CONFIG_EDAC_PND2) += pnd2_edac.o
+obj-$(CONFIG_EDAC_IGEN6) += igen6_edac.o
obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o
obj-$(CONFIG_EDAC_E752X) += e752x_edac.o
obj-$(CONFIG_EDAC_I82443BXGX) += i82443bxgx_edac.o
@@ -64,7 +65,6 @@ obj-$(CONFIG_EDAC_SKX) += skx_edac.o
i10nm_edac-y := skx_common.o i10nm_base.o
obj-$(CONFIG_EDAC_I10NM) += i10nm_edac.o
-obj-$(CONFIG_EDAC_MV64X60) += mv64x60_edac.o
obj-$(CONFIG_EDAC_CELL) += cell_edac.o
obj-$(CONFIG_EDAC_PPC4XX) += ppc4xx_edac.o
obj-$(CONFIG_EDAC_AMD8111) += amd8111_edac.o
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 1362274d840b..15b0d39d2845 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -18,6 +18,9 @@ static struct amd64_family_type *fam_type;
/* Per-node stuff */
static struct ecc_settings **ecc_stngs;
+/* Device for the PCI component */
+static struct device *pci_ctl_dev;
+
/*
* Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing
* bandwidth to a valid bit pattern. The 'set' operation finds the 'matching-
@@ -2461,14 +2464,11 @@ static int map_err_sym_to_channel(int err_sym, int sym_size)
case 0x20:
case 0x21:
return 0;
- break;
case 0x22:
case 0x23:
return 1;
- break;
default:
return err_sym >> 4;
- break;
}
/* x8 symbols */
else
@@ -2478,17 +2478,12 @@ static int map_err_sym_to_channel(int err_sym, int sym_size)
WARN(1, KERN_ERR "Invalid error symbol: 0x%x\n",
err_sym);
return -1;
- break;
-
case 0x11:
return 0;
- break;
case 0x12:
return 1;
- break;
default:
return err_sym >> 3;
- break;
}
return -1;
}
@@ -2683,6 +2678,9 @@ reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 pci_id1, u16 pci_id2)
return -ENODEV;
}
+ if (!pci_ctl_dev)
+ pci_ctl_dev = &pvt->F0->dev;
+
edac_dbg(1, "F0: %s\n", pci_name(pvt->F0));
edac_dbg(1, "F3: %s\n", pci_name(pvt->F3));
edac_dbg(1, "F6: %s\n", pci_name(pvt->F6));
@@ -2707,6 +2705,9 @@ reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 pci_id1, u16 pci_id2)
return -ENODEV;
}
+ if (!pci_ctl_dev)
+ pci_ctl_dev = &pvt->F2->dev;
+
edac_dbg(1, "F1: %s\n", pci_name(pvt->F1));
edac_dbg(1, "F2: %s\n", pci_name(pvt->F2));
edac_dbg(1, "F3: %s\n", pci_name(pvt->F3));
@@ -3623,21 +3624,10 @@ static void remove_one_instance(unsigned int nid)
static void setup_pci_device(void)
{
- struct mem_ctl_info *mci;
- struct amd64_pvt *pvt;
-
if (pci_ctl)
return;
- mci = edac_mc_find(0);
- if (!mci)
- return;
-
- pvt = mci->pvt_info;
- if (pvt->umc)
- pci_ctl = edac_pci_create_generic_ctl(&pvt->F0->dev, EDAC_MOD_STR);
- else
- pci_ctl = edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR);
+ pci_ctl = edac_pci_create_generic_ctl(pci_ctl_dev, EDAC_MOD_STR);
if (!pci_ctl) {
pr_warn("%s(): Unable to create PCI control\n", __func__);
pr_warn("%s(): PCI error report via EDAC not set\n", __func__);
@@ -3716,6 +3706,8 @@ static int __init amd64_edac_init(void)
return 0;
err_pci:
+ pci_ctl_dev = NULL;
+
msrs_free(msrs);
msrs = NULL;
@@ -3745,6 +3737,8 @@ static void __exit amd64_edac_exit(void)
kfree(ecc_stngs);
ecc_stngs = NULL;
+ pci_ctl_dev = NULL;
+
msrs_free(msrs);
msrs = NULL;
}
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c
index 9c6e326b4c14..2a49f68a7cf9 100644
--- a/drivers/edac/amd76x_edac.c
+++ b/drivers/edac/amd76x_edac.c
@@ -179,7 +179,6 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
static void amd76x_check(struct mem_ctl_info *mci)
{
struct amd76x_error_info info;
- edac_dbg(3, "\n");
amd76x_get_error_info(mci, &info);
amd76x_process_error_info(mci, &info, 1);
}
diff --git a/drivers/edac/aspeed_edac.c b/drivers/edac/aspeed_edac.c
index fde809efc520..a46da56d6d54 100644
--- a/drivers/edac/aspeed_edac.c
+++ b/drivers/edac/aspeed_edac.c
@@ -239,7 +239,7 @@ static int init_csrows(struct mem_ctl_info *mci)
int rc;
/* retrieve info about physical memory from device tree */
- np = of_find_node_by_path("/memory");
+ np = of_find_node_by_name(NULL, "memory");
if (!np) {
dev_err(mci->pdev, "dt: missing /memory node\n");
return -ENODEV;
@@ -375,10 +375,13 @@ static int aspeed_remove(struct platform_device *pdev)
static const struct of_device_id aspeed_of_match[] = {
+ { .compatible = "aspeed,ast2400-sdram-edac" },
{ .compatible = "aspeed,ast2500-sdram-edac" },
+ { .compatible = "aspeed,ast2600-sdram-edac" },
{},
};
+MODULE_DEVICE_TABLE(of, aspeed_of_match);
static struct platform_driver aspeed_driver = {
.driver = {
@@ -392,5 +395,5 @@ module_platform_driver(aspeed_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Stefan Schaeckeler <sschaeck@cisco.com>");
-MODULE_DESCRIPTION("Aspeed AST2500 EDAC driver");
+MODULE_DESCRIPTION("Aspeed BMC SoC EDAC driver");
MODULE_VERSION("1.0");
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 313d08018166..ac7c9b42d4c7 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -980,7 +980,6 @@ static void e752x_check(struct mem_ctl_info *mci)
{
struct e752x_error_info info;
- edac_dbg(3, "\n");
e752x_get_error_info(mci, &info);
e752x_process_error_info(mci, &info, 1);
}
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c
index 75d7ce62b3be..497e710fca3d 100644
--- a/drivers/edac/e7xxx_edac.c
+++ b/drivers/edac/e7xxx_edac.c
@@ -333,7 +333,6 @@ static void e7xxx_check(struct mem_ctl_info *mci)
{
struct e7xxx_error_info info;
- edac_dbg(3, "\n");
e7xxx_get_error_info(mci, &info);
e7xxx_process_error_info(mci, &info, 1);
}
diff --git a/drivers/edac/edac_device.h b/drivers/edac/edac_device.h
index c4c0e0bdce14..fc2d2c218064 100644
--- a/drivers/edac/edac_device.h
+++ b/drivers/edac/edac_device.h
@@ -258,7 +258,7 @@ extern struct edac_device_ctl_info *edac_device_alloc_ctl_info(
extern void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info);
/**
- * edac_device_add_device: Insert the 'edac_dev' structure into the
+ * edac_device_add_device - Insert the 'edac_dev' structure into the
* edac_device global list and create sysfs entries associated with
* edac_device structure.
*
@@ -271,9 +271,8 @@ extern void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info);
extern int edac_device_add_device(struct edac_device_ctl_info *edac_dev);
/**
- * edac_device_del_device:
- * Remove sysfs entries for specified edac_device structure and
- * then remove edac_device structure from global list
+ * edac_device_del_device - Remove sysfs entries for specified edac_device
+ * structure and then remove edac_device structure from global list
*
* @dev:
* Pointer to struct &device representing the edac device
@@ -286,7 +285,7 @@ extern int edac_device_add_device(struct edac_device_ctl_info *edac_dev);
extern struct edac_device_ctl_info *edac_device_del_device(struct device *dev);
/**
- * Log correctable errors.
+ * edac_device_handle_ce_count - Log correctable errors.
*
* @edac_dev: pointer to struct &edac_device_ctl_info
* @inst_nr: number of the instance where the CE error happened
@@ -299,7 +298,7 @@ void edac_device_handle_ce_count(struct edac_device_ctl_info *edac_dev,
const char *msg);
/**
- * Log uncorrectable errors.
+ * edac_device_handle_ue_count - Log uncorrectable errors.
*
* @edac_dev: pointer to struct &edac_device_ctl_info
* @inst_nr: number of the instance where the CE error happened
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 01ff71f7b645..f6d462d0be2d 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -158,10 +158,14 @@ const char * const edac_mem_types[] = {
[MEM_DDR3] = "Unbuffered-DDR3",
[MEM_RDDR3] = "Registered-DDR3",
[MEM_LRDDR3] = "Load-Reduced-DDR3-RAM",
+ [MEM_LPDDR3] = "Low-Power-DDR3-RAM",
[MEM_DDR4] = "Unbuffered-DDR4",
[MEM_RDDR4] = "Registered-DDR4",
+ [MEM_LPDDR4] = "Low-Power-DDR4-RAM",
[MEM_LRDDR4] = "Load-Reduced-DDR4-RAM",
+ [MEM_DDR5] = "Unbuffered-DDR5",
[MEM_NVDIMM] = "Non-volatile-RAM",
+ [MEM_WIO2] = "Wide-IO-2",
};
EXPORT_SYMBOL_GPL(edac_mem_types);
diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c
index c8d11da85bec..238a4ad1e526 100644
--- a/drivers/edac/i10nm_base.c
+++ b/drivers/edac/i10nm_base.c
@@ -6,27 +6,32 @@
*/
#include <linux/kernel.h>
+#include <linux/io.h>
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
#include <asm/mce.h>
#include "edac_module.h"
#include "skx_common.h"
-#define I10NM_REVISION "v0.0.3"
+#define I10NM_REVISION "v0.0.4"
#define EDAC_MOD_STR "i10nm_edac"
/* Debug macros */
#define i10nm_printk(level, fmt, arg...) \
edac_printk(level, "i10nm", fmt, ##arg)
-#define I10NM_GET_SCK_BAR(d, reg) \
+#define I10NM_GET_SCK_BAR(d, reg) \
pci_read_config_dword((d)->uracu, 0xd0, &(reg))
#define I10NM_GET_IMC_BAR(d, i, reg) \
pci_read_config_dword((d)->uracu, 0xd8 + (i) * 4, &(reg))
#define I10NM_GET_DIMMMTR(m, i, j) \
- (*(u32 *)((m)->mbase + 0x2080c + (i) * 0x4000 + (j) * 4))
+ readl((m)->mbase + 0x2080c + (i) * (m)->chan_mmio_sz + (j) * 4)
#define I10NM_GET_MCDDRTCFG(m, i, j) \
- (*(u32 *)((m)->mbase + 0x20970 + (i) * 0x4000 + (j) * 4))
+ readl((m)->mbase + 0x20970 + (i) * (m)->chan_mmio_sz + (j) * 4)
+#define I10NM_GET_MCMTR(m, i) \
+ readl((m)->mbase + 0x20ef8 + (i) * (m)->chan_mmio_sz)
+#define I10NM_GET_AMAP(m, i) \
+ readl((m)->mbase + 0x20814 + (i) * (m)->chan_mmio_sz)
#define I10NM_GET_SCK_MMIO_BASE(reg) (GET_BITFIELD(reg, 0, 28) << 23)
#define I10NM_GET_IMC_MMIO_OFFSET(reg) (GET_BITFIELD(reg, 0, 10) << 12)
@@ -126,12 +131,22 @@ static struct res_config i10nm_cfg0 = {
.type = I10NM,
.decs_did = 0x3452,
.busno_cfg_offset = 0xcc,
+ .ddr_chan_mmio_sz = 0x4000,
};
static struct res_config i10nm_cfg1 = {
.type = I10NM,
.decs_did = 0x3452,
.busno_cfg_offset = 0xd0,
+ .ddr_chan_mmio_sz = 0x4000,
+};
+
+static struct res_config spr_cfg = {
+ .type = SPR,
+ .decs_did = 0x3252,
+ .busno_cfg_offset = 0xd0,
+ .ddr_chan_mmio_sz = 0x8000,
+ .support_ddr5 = true,
};
static const struct x86_cpu_id i10nm_cpuids[] = {
@@ -140,6 +155,7 @@ static const struct x86_cpu_id i10nm_cpuids[] = {
X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(ICELAKE_X, X86_STEPPINGS(0x0, 0x3), &i10nm_cfg0),
X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(ICELAKE_X, X86_STEPPINGS(0x4, 0xf), &i10nm_cfg1),
X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(ICELAKE_D, X86_STEPPINGS(0x0, 0xf), &i10nm_cfg1),
+ X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SAPPHIRERAPIDS_X, X86_STEPPINGS(0x0, 0xf), &spr_cfg),
{}
};
MODULE_DEVICE_TABLE(x86cpu, i10nm_cpuids);
@@ -148,18 +164,19 @@ static bool i10nm_check_ecc(struct skx_imc *imc, int chan)
{
u32 mcmtr;
- mcmtr = *(u32 *)(imc->mbase + 0x20ef8 + chan * 0x4000);
+ mcmtr = I10NM_GET_MCMTR(imc, chan);
edac_dbg(1, "ch%d mcmtr reg %x\n", chan, mcmtr);
return !!GET_BITFIELD(mcmtr, 2, 2);
}
-static int i10nm_get_dimm_config(struct mem_ctl_info *mci)
+static int i10nm_get_dimm_config(struct mem_ctl_info *mci,
+ struct res_config *cfg)
{
struct skx_pvt *pvt = mci->pvt_info;
struct skx_imc *imc = pvt->imc;
+ u32 mtr, amap, mcddrtcfg;
struct dimm_info *dimm;
- u32 mtr, mcddrtcfg;
int i, j, ndimms;
for (i = 0; i < I10NM_NUM_CHANNELS; i++) {
@@ -167,6 +184,7 @@ static int i10nm_get_dimm_config(struct mem_ctl_info *mci)
continue;
ndimms = 0;
+ amap = I10NM_GET_AMAP(imc, i);
for (j = 0; j < I10NM_NUM_DIMMS; j++) {
dimm = edac_get_dimm(mci, i, j, 0);
mtr = I10NM_GET_DIMMMTR(imc, i, j);
@@ -175,8 +193,8 @@ static int i10nm_get_dimm_config(struct mem_ctl_info *mci)
mtr, mcddrtcfg, imc->mc, i, j);
if (IS_DIMM_PRESENT(mtr))
- ndimms += skx_get_dimm_info(mtr, 0, 0, dimm,
- imc, i, j);
+ ndimms += skx_get_dimm_info(mtr, 0, amap, dimm,
+ imc, i, j, cfg);
else if (IS_NVDIMM_PRESENT(mcddrtcfg, j))
ndimms += skx_get_nvdimm_info(dimm, imc, i, j,
EDAC_MOD_STR);
@@ -300,10 +318,11 @@ static int __init i10nm_init(void)
d->imc[i].lmc = i;
d->imc[i].src_id = src_id;
d->imc[i].node_id = node_id;
+ d->imc[i].chan_mmio_sz = cfg->ddr_chan_mmio_sz;
rc = skx_register_mci(&d->imc[i], d->imc[i].mdev,
"Intel_10nm Socket", EDAC_MOD_STR,
- i10nm_get_dimm_config);
+ i10nm_get_dimm_config, cfg);
if (rc < 0)
goto fail;
}
diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c
index 5c1eea96230c..9065bc4386ff 100644
--- a/drivers/edac/i3000_edac.c
+++ b/drivers/edac/i3000_edac.c
@@ -273,7 +273,6 @@ static void i3000_check(struct mem_ctl_info *mci)
{
struct i3000_error_info info;
- edac_dbg(1, "MC%d\n", mci->mc_idx);
i3000_get_error_info(mci, &info);
i3000_process_error_info(mci, &info, 1);
}
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c
index a8988db6d423..afccdebf5ac1 100644
--- a/drivers/edac/i3200_edac.c
+++ b/drivers/edac/i3200_edac.c
@@ -253,7 +253,6 @@ static void i3200_check(struct mem_ctl_info *mci)
{
struct i3200_error_info info;
- edac_dbg(1, "MC%d\n", mci->mc_idx);
i3200_get_and_clear_error_info(mci, &info);
i3200_process_error_info(mci, &info);
}
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
index 1a6f69c859ab..ba46057d4220 100644
--- a/drivers/edac/i5000_edac.c
+++ b/drivers/edac/i5000_edac.c
@@ -765,7 +765,7 @@ static void i5000_clear_error(struct mem_ctl_info *mci)
static void i5000_check_error(struct mem_ctl_info *mci)
{
struct i5000_error_info info;
- edac_dbg(4, "MC%d\n", mci->mc_idx);
+
i5000_get_error_info(mci, &info);
i5000_process_error_info(mci, &info, 1);
}
diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c
index 92d63eb533ae..f76624ee82ef 100644
--- a/drivers/edac/i5400_edac.c
+++ b/drivers/edac/i5400_edac.c
@@ -686,7 +686,7 @@ static void i5400_clear_error(struct mem_ctl_info *mci)
static void i5400_check_error(struct mem_ctl_info *mci)
{
struct i5400_error_info info;
- edac_dbg(4, "MC%d\n", mci->mc_idx);
+
i5400_get_error_info(mci, &info);
i5400_process_error_info(mci, &info);
}
diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c
index a2ca929e2168..933dcf3cfdff 100644
--- a/drivers/edac/i82443bxgx_edac.c
+++ b/drivers/edac/i82443bxgx_edac.c
@@ -176,7 +176,6 @@ static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci)
{
struct i82443bxgx_edacmc_error_info info;
- edac_dbg(1, "MC%d\n", mci->mc_idx);
i82443bxgx_edacmc_get_error_info(mci, &info);
i82443bxgx_edacmc_process_error_info(mci, &info, 1);
}
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c
index 3e3a80ffb322..fbec90d00f1e 100644
--- a/drivers/edac/i82860_edac.c
+++ b/drivers/edac/i82860_edac.c
@@ -135,7 +135,6 @@ static void i82860_check(struct mem_ctl_info *mci)
{
struct i82860_error_info info;
- edac_dbg(1, "MC%d\n", mci->mc_idx);
i82860_get_error_info(mci, &info);
i82860_process_error_info(mci, &info, 1);
}
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index ceac925af38c..553880b9fc12 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
@@ -262,7 +262,6 @@ static void i82875p_check(struct mem_ctl_info *mci)
{
struct i82875p_error_info info;
- edac_dbg(1, "MC%d\n", mci->mc_idx);
i82875p_get_error_info(mci, &info);
i82875p_process_error_info(mci, &info, 1);
}
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
index 6be99e0d850d..d99f005832cf 100644
--- a/drivers/edac/i82975x_edac.c
+++ b/drivers/edac/i82975x_edac.c
@@ -330,7 +330,6 @@ static void i82975x_check(struct mem_ctl_info *mci)
{
struct i82975x_error_info info;
- edac_dbg(1, "MC%d\n", mci->mc_idx);
i82975x_get_error_info(mci, &info);
i82975x_process_error_info(mci, &info, 1);
}
diff --git a/drivers/edac/ie31200_edac.c b/drivers/edac/ie31200_edac.c
index c47963240b65..9a9ff5ad611a 100644
--- a/drivers/edac/ie31200_edac.c
+++ b/drivers/edac/ie31200_edac.c
@@ -333,7 +333,6 @@ static void ie31200_check(struct mem_ctl_info *mci)
{
struct ie31200_error_info info;
- edac_dbg(1, "MC%d\n", mci->mc_idx);
ie31200_get_and_clear_error_info(mci, &info);
ie31200_process_error_info(mci, &info);
}
diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c
new file mode 100644
index 000000000000..6be9986fc6bd
--- /dev/null
+++ b/drivers/edac/igen6_edac.c
@@ -0,0 +1,977 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Intel client SoC with integrated memory controller using IBECC
+ *
+ * Copyright (C) 2020 Intel Corporation
+ *
+ * The In-Band ECC (IBECC) IP provides ECC protection to all or specific
+ * regions of the physical memory space. It's used for memory controllers
+ * that don't support the out-of-band ECC which often needs an additional
+ * storage device to each channel for storing ECC data.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/irq_work.h>
+#include <linux/llist.h>
+#include <linux/genalloc.h>
+#include <linux/edac.h>
+#include <linux/bits.h>
+#include <linux/io.h>
+#include <asm/mach_traps.h>
+#include <asm/nmi.h>
+
+#include "edac_mc.h"
+#include "edac_module.h"
+
+#define IGEN6_REVISION "v2.4"
+
+#define EDAC_MOD_STR "igen6_edac"
+#define IGEN6_NMI_NAME "igen6_ibecc"
+
+/* Debug macros */
+#define igen6_printk(level, fmt, arg...) \
+ edac_printk(level, "igen6", fmt, ##arg)
+
+#define igen6_mc_printk(mci, level, fmt, arg...) \
+ edac_mc_chipset_printk(mci, level, "igen6", fmt, ##arg)
+
+#define GET_BITFIELD(v, lo, hi) (((v) & GENMASK_ULL(hi, lo)) >> (lo))
+
+#define NUM_IMC 1 /* Max memory controllers */
+#define NUM_CHANNELS 2 /* Max channels */
+#define NUM_DIMMS 2 /* Max DIMMs per channel */
+
+#define _4GB BIT_ULL(32)
+
+/* Size of physical memory */
+#define TOM_OFFSET 0xa0
+/* Top of low usable DRAM */
+#define TOLUD_OFFSET 0xbc
+/* Capability register C */
+#define CAPID_C_OFFSET 0xec
+#define CAPID_C_IBECC BIT(15)
+
+/* Error Status */
+#define ERRSTS_OFFSET 0xc8
+#define ERRSTS_CE BIT_ULL(6)
+#define ERRSTS_UE BIT_ULL(7)
+
+/* Error Command */
+#define ERRCMD_OFFSET 0xca
+#define ERRCMD_CE BIT_ULL(6)
+#define ERRCMD_UE BIT_ULL(7)
+
+/* IBECC MMIO base address */
+#define IBECC_BASE (res_cfg->ibecc_base)
+#define IBECC_ACTIVATE_OFFSET IBECC_BASE
+#define IBECC_ACTIVATE_EN BIT(0)
+
+/* IBECC error log */
+#define ECC_ERROR_LOG_OFFSET (IBECC_BASE + 0x170)
+#define ECC_ERROR_LOG_CE BIT_ULL(62)
+#define ECC_ERROR_LOG_UE BIT_ULL(63)
+#define ECC_ERROR_LOG_ADDR_SHIFT 5
+#define ECC_ERROR_LOG_ADDR(v) GET_BITFIELD(v, 5, 38)
+#define ECC_ERROR_LOG_SYND(v) GET_BITFIELD(v, 46, 61)
+
+/* Host MMIO base address */
+#define MCHBAR_OFFSET 0x48
+#define MCHBAR_EN BIT_ULL(0)
+#define MCHBAR_BASE(v) (GET_BITFIELD(v, 16, 38) << 16)
+#define MCHBAR_SIZE 0x10000
+
+/* Parameters for the channel decode stage */
+#define MAD_INTER_CHANNEL_OFFSET 0x5000
+#define MAD_INTER_CHANNEL_DDR_TYPE(v) GET_BITFIELD(v, 0, 2)
+#define MAD_INTER_CHANNEL_ECHM(v) GET_BITFIELD(v, 3, 3)
+#define MAD_INTER_CHANNEL_CH_L_MAP(v) GET_BITFIELD(v, 4, 4)
+#define MAD_INTER_CHANNEL_CH_S_SIZE(v) ((u64)GET_BITFIELD(v, 12, 19) << 29)
+
+/* Parameters for DRAM decode stage */
+#define MAD_INTRA_CH0_OFFSET 0x5004
+#define MAD_INTRA_CH_DIMM_L_MAP(v) GET_BITFIELD(v, 0, 0)
+
+/* DIMM characteristics */
+#define MAD_DIMM_CH0_OFFSET 0x500c
+#define MAD_DIMM_CH_DIMM_L_SIZE(v) ((u64)GET_BITFIELD(v, 0, 6) << 29)
+#define MAD_DIMM_CH_DLW(v) GET_BITFIELD(v, 7, 8)
+#define MAD_DIMM_CH_DIMM_S_SIZE(v) ((u64)GET_BITFIELD(v, 16, 22) << 29)
+#define MAD_DIMM_CH_DSW(v) GET_BITFIELD(v, 24, 25)
+
+/* Hash for channel selection */
+#define CHANNEL_HASH_OFFSET 0X5024
+/* Hash for enhanced channel selection */
+#define CHANNEL_EHASH_OFFSET 0X5028
+#define CHANNEL_HASH_MASK(v) (GET_BITFIELD(v, 6, 19) << 6)
+#define CHANNEL_HASH_LSB_MASK_BIT(v) GET_BITFIELD(v, 24, 26)
+#define CHANNEL_HASH_MODE(v) GET_BITFIELD(v, 28, 28)
+
+static struct res_config {
+ int num_imc;
+ u32 ibecc_base;
+ bool (*ibecc_available)(struct pci_dev *pdev);
+ /* Convert error address logged in IBECC to system physical address */
+ u64 (*err_addr_to_sys_addr)(u64 eaddr);
+ /* Convert error address logged in IBECC to integrated memory controller address */
+ u64 (*err_addr_to_imc_addr)(u64 eaddr);
+} *res_cfg;
+
+struct igen6_imc {
+ int mc;
+ struct mem_ctl_info *mci;
+ struct pci_dev *pdev;
+ struct device dev;
+ void __iomem *window;
+ u64 ch_s_size;
+ int ch_l_map;
+ u64 dimm_s_size[NUM_CHANNELS];
+ u64 dimm_l_size[NUM_CHANNELS];
+ int dimm_l_map[NUM_CHANNELS];
+};
+
+static struct igen6_pvt {
+ struct igen6_imc imc[NUM_IMC];
+} *igen6_pvt;
+
+/* The top of low usable DRAM */
+static u32 igen6_tolud;
+/* The size of physical memory */
+static u64 igen6_tom;
+
+struct decoded_addr {
+ int mc;
+ u64 imc_addr;
+ u64 sys_addr;
+ int channel_idx;
+ u64 channel_addr;
+ int sub_channel_idx;
+ u64 sub_channel_addr;
+};
+
+struct ecclog_node {
+ struct llist_node llnode;
+ int mc;
+ u64 ecclog;
+};
+
+/*
+ * In the NMI handler, the driver uses the lock-less memory allocator
+ * to allocate memory to store the IBECC error logs and links the logs
+ * to the lock-less list. Delay printk() and the work of error reporting
+ * to EDAC core in a worker.
+ */
+#define ECCLOG_POOL_SIZE PAGE_SIZE
+static LLIST_HEAD(ecclog_llist);
+static struct gen_pool *ecclog_pool;
+static char ecclog_buf[ECCLOG_POOL_SIZE];
+static struct irq_work ecclog_irq_work;
+static struct work_struct ecclog_work;
+
+/* Compute die IDs for Elkhart Lake with IBECC */
+#define DID_EHL_SKU5 0x4514
+#define DID_EHL_SKU6 0x4528
+#define DID_EHL_SKU7 0x452a
+#define DID_EHL_SKU8 0x4516
+#define DID_EHL_SKU9 0x452c
+#define DID_EHL_SKU10 0x452e
+#define DID_EHL_SKU11 0x4532
+#define DID_EHL_SKU12 0x4518
+#define DID_EHL_SKU13 0x451a
+#define DID_EHL_SKU14 0x4534
+#define DID_EHL_SKU15 0x4536
+
+static boo