From 7b5c7e83ac405ff9ecbdd92b37a477f4288f8814 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 9 Dec 2025 17:36:59 +0300 Subject: [PATCH 1/9] EDAC/i5000: Fix snprintf() size calculation in calculate_dimm_size() The snprintf() can't really overflow because we're writing a max of 42 bytes to a PAGE_SIZE buffer. But the limit calculation doesn't take the first 11 bytes that we wrote into consideration so the limit is not correct. Just fix it for correctness even though it doesn't affect runtime. Fixes: 64e1fdaf55d6 ("i5000_edac: Fix the logic that retrieves memory information") Signed-off-by: Dan Carpenter Signed-off-by: Tony Luck Reviewed-by: Qiuxu Zhuo Link: https://patch.msgid.link/07cd652c51e77aad5a8350e1a7cd9407e5bbe373.1765290801.git.dan.carpenter@linaro.org --- drivers/edac/i5000_edac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c index 4a1bebc1ff14..471b8540d18b 100644 --- a/drivers/edac/i5000_edac.c +++ b/drivers/edac/i5000_edac.c @@ -1111,6 +1111,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt) n = snprintf(p, space, " "); p += n; + space -= n; for (branch = 0; branch < MAX_BRANCHES; branch++) { n = snprintf(p, space, " branch %d | ", branch); p += n; From 72f12683611344853ab030fe7d19b23970ed2bd8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 9 Dec 2025 17:37:04 +0300 Subject: [PATCH 2/9] EDAC/i5400: Fix snprintf() limit calculation in calculate_dimm_size() The snprintf() can't really overflow because we're writing a max of 42 bytes to a PAGE_SIZE buffer. But my static checker complains because the limit calculation doesn't take the first 11 space characters that we wrote into the buffer into consideration. Fix this for the sake of correctness even though it doesn't affect runtime. Also delete an earlier "space -= n;" which was not used. Fixes: 68d086f89b80 ("i5400_edac: improve debug messages to better represent the filled memory") Signed-off-by: Dan Carpenter Signed-off-by: Tony Luck Reviewed-by: Qiuxu Zhuo Link: https://patch.msgid.link/ccd06b91748e7ed8e33eeb2ff1e7b98700879304.1765290801.git.dan.carpenter@linaro.org --- drivers/edac/i5400_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c index b5cf25905b05..fb49a1d1df11 100644 --- a/drivers/edac/i5400_edac.c +++ b/drivers/edac/i5400_edac.c @@ -1026,13 +1026,13 @@ static void calculate_dimm_size(struct i5400_pvt *pvt) space -= n; } - space -= n; edac_dbg(2, "%s\n", mem_buffer); p = mem_buffer; space = PAGE_SIZE; n = snprintf(p, space, " "); p += n; + space -= n; for (branch = 0; branch < MAX_BRANCHES; branch++) { n = snprintf(p, space, " branch %d | ", branch); p += n; From 41ca2155d62b0b0d217f59e1bce18362d0c2446f Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Mon, 24 Nov 2025 14:54:56 +0800 Subject: [PATCH 3/9] EDAC/igen6: Add two Intel Amston Lake SoCs support Intel Amston Lake SoCs with IBECC (In-Band ECC) capability share the same IBECC registers as Alder Lake-N SoCs. Add two new compute die IDs for Amston Lake SoC products to enable EDAC support. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Tested-by: Jianfeng Gao Link: https://patch.msgid.link/20251124065457.3630949-2-qiuxu.zhuo@intel.com --- drivers/edac/igen6_edac.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c index 553c31a2d922..d29cfc7fad93 100644 --- a/drivers/edac/igen6_edac.c +++ b/drivers/edac/igen6_edac.c @@ -246,6 +246,8 @@ static struct work_struct ecclog_work; /* Compute did IDs for Amston Lake with IBECC */ #define DID_ASL_SKU1 0x464a +#define DID_ASL_SKU2 0x4646 +#define DID_ASL_SKU3 0x4652 /* Compute die IDs for Raptor Lake-P with IBECC */ #define DID_RPL_P_SKU1 0xa706 @@ -618,6 +620,8 @@ static struct pci_device_id igen6_pci_tbl[] = { { PCI_VDEVICE(INTEL, DID_ADL_N_SKU12), (kernel_ulong_t)&adl_n_cfg }, { PCI_VDEVICE(INTEL, DID_AZB_SKU1), (kernel_ulong_t)&adl_n_cfg }, { PCI_VDEVICE(INTEL, DID_ASL_SKU1), (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ASL_SKU2), (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ASL_SKU3), (kernel_ulong_t)&adl_n_cfg }, { PCI_VDEVICE(INTEL, DID_RPL_P_SKU1), (kernel_ulong_t)&rpl_p_cfg }, { PCI_VDEVICE(INTEL, DID_RPL_P_SKU2), (kernel_ulong_t)&rpl_p_cfg }, { PCI_VDEVICE(INTEL, DID_RPL_P_SKU3), (kernel_ulong_t)&rpl_p_cfg }, From 4b720906efa34e1f68e3b2f7061c294e1889525b Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Fri, 19 Dec 2025 12:29:56 +0800 Subject: [PATCH 4/9] EDAC/igen6: Make masks of {MCHBAR, TOM, TOUUD, ECC_ERROR_LOG} configurable The masks used to retrieve base addresses from {MCHBAR, TOM, TOUUD, ECC_ERROR_LOG} registers can be CPU model-specific. Currently, igen6_edac hard-codes these masks with the most significant bit at 38, while some CPUs have extended the most significant bit to bit 41 or bit 45. Systems with more than 512GB (2^39) memory need this extension to get correct masks. But all CPUs currently supported by igen6_edac support max memory less than 512GB (e.g., max memory size for Raptor Lake systems is 192GB, for Alder Lake systems is 128GB, ...), which means the previous hard-coded most significant bit 38 still works properly. So backporting this patch to stable kernels is not necessary. To make these masks reflect the CPUs' real support and easily support future Intel client CPUs supported by igen6_edac that have more than 512GB memory, add four new fields to structure res_config to make these masks CPU model-specific and configure them properly. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Tested-by: Jianfeng Gao Link: https://patch.msgid.link/20251219042956.3232568-3-qiuxu.zhuo@intel.com --- drivers/edac/igen6_edac.c | 65 +++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c index d29cfc7fad93..717862dc4765 100644 --- a/drivers/edac/igen6_edac.c +++ b/drivers/edac/igen6_edac.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -79,15 +80,11 @@ #define ECC_ERROR_LOG_OFFSET (IBECC_BASE + res_cfg->ibecc_error_log_offset) #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_ADDR45(v) GET_BITFIELD(v, 5, 45) #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 */ @@ -129,6 +126,14 @@ static struct res_config { bool machine_check; /* The number of present memory controllers. */ int num_imc; + /* Host MMIO configuration */ + u64 reg_mchbar_mask; + /* Top of memory */ + u64 reg_tom_mask; + /* Top of upper usable DRAM */ + u64 reg_touud_mask; + /* IBECC error log */ + u64 reg_eccerrlog_addr_mask; u32 imc_base; u32 cmf_base; u32 cmf_size; @@ -305,7 +310,8 @@ static int get_mchbar(struct pci_dev *pdev, u64 *mchbar) return -ENODEV; } - *mchbar = MCHBAR_BASE(u.v); + *mchbar = u.v & res_cfg->reg_mchbar_mask; + edac_dbg(2, "MCHBAR 0x%llx (reg 0x%llx)\n", *mchbar, u.v); return 0; } @@ -481,11 +487,15 @@ static u64 adl_err_addr_to_imc_addr(u64 eaddr, int mc) static u64 rpl_p_err_addr(u64 ecclog) { - return ECC_ERROR_LOG_ADDR45(ecclog); + return field_get(res_cfg->reg_eccerrlog_addr_mask, ecclog); } static struct res_config ehl_cfg = { .num_imc = 1, + .reg_mchbar_mask = GENMASK_ULL(38, 16), + .reg_tom_mask = GENMASK_ULL(38, 20), + .reg_touud_mask = GENMASK_ULL(38, 20), + .reg_eccerrlog_addr_mask = GENMASK_ULL(38, 5), .imc_base = 0x5000, .ibecc_base = 0xdc00, .ibecc_available = ehl_ibecc_available, @@ -496,6 +506,10 @@ static struct res_config ehl_cfg = { static struct res_config icl_cfg = { .num_imc = 1, + .reg_mchbar_mask = GENMASK_ULL(38, 16), + .reg_tom_mask = GENMASK_ULL(38, 20), + .reg_touud_mask = GENMASK_ULL(38, 20), + .reg_eccerrlog_addr_mask = GENMASK_ULL(38, 5), .imc_base = 0x5000, .ibecc_base = 0xd800, .ibecc_error_log_offset = 0x170, @@ -507,6 +521,10 @@ static struct res_config icl_cfg = { static struct res_config tgl_cfg = { .machine_check = true, .num_imc = 2, + .reg_mchbar_mask = GENMASK_ULL(38, 17), + .reg_tom_mask = GENMASK_ULL(38, 20), + .reg_touud_mask = GENMASK_ULL(38, 20), + .reg_eccerrlog_addr_mask = GENMASK_ULL(38, 5), .imc_base = 0x5000, .cmf_base = 0x11000, .cmf_size = 0x800, @@ -521,6 +539,10 @@ static struct res_config tgl_cfg = { static struct res_config adl_cfg = { .machine_check = true, .num_imc = 2, + .reg_mchbar_mask = GENMASK_ULL(41, 17), + .reg_tom_mask = GENMASK_ULL(41, 20), + .reg_touud_mask = GENMASK_ULL(41, 20), + .reg_eccerrlog_addr_mask = GENMASK_ULL(45, 5), .imc_base = 0xd800, .ibecc_base = 0xd400, .ibecc_error_log_offset = 0x68, @@ -532,6 +554,10 @@ static struct res_config adl_cfg = { static struct res_config adl_n_cfg = { .machine_check = true, .num_imc = 1, + .reg_mchbar_mask = GENMASK_ULL(41, 17), + .reg_tom_mask = GENMASK_ULL(41, 20), + .reg_touud_mask = GENMASK_ULL(41, 20), + .reg_eccerrlog_addr_mask = GENMASK_ULL(45, 5), .imc_base = 0xd800, .ibecc_base = 0xd400, .ibecc_error_log_offset = 0x68, @@ -543,6 +569,10 @@ static struct res_config adl_n_cfg = { static struct res_config rpl_p_cfg = { .machine_check = true, .num_imc = 2, + .reg_mchbar_mask = GENMASK_ULL(41, 17), + .reg_tom_mask = GENMASK_ULL(41, 20), + .reg_touud_mask = GENMASK_ULL(41, 20), + .reg_eccerrlog_addr_mask = GENMASK_ULL(45, 5), .imc_base = 0xd800, .ibecc_base = 0xd400, .ibecc_error_log_offset = 0x68, @@ -555,6 +585,10 @@ static struct res_config rpl_p_cfg = { static struct res_config mtl_ps_cfg = { .machine_check = true, .num_imc = 2, + .reg_mchbar_mask = GENMASK_ULL(41, 17), + .reg_tom_mask = GENMASK_ULL(41, 20), + .reg_touud_mask = GENMASK_ULL(41, 20), + .reg_eccerrlog_addr_mask = GENMASK_ULL(38, 5), .imc_base = 0xd800, .ibecc_base = 0xd400, .ibecc_error_log_offset = 0x170, @@ -566,6 +600,10 @@ static struct res_config mtl_ps_cfg = { static struct res_config mtl_p_cfg = { .machine_check = true, .num_imc = 2, + .reg_mchbar_mask = GENMASK_ULL(41, 17), + .reg_tom_mask = GENMASK_ULL(41, 20), + .reg_touud_mask = GENMASK_ULL(41, 20), + .reg_eccerrlog_addr_mask = GENMASK_ULL(38, 5), .imc_base = 0xd800, .ibecc_base = 0xd400, .ibecc_error_log_offset = 0x170, @@ -577,6 +615,10 @@ static struct res_config mtl_p_cfg = { static struct res_config wcl_cfg = { .machine_check = true, .num_imc = 1, + .reg_mchbar_mask = GENMASK_ULL(41, 17), + .reg_tom_mask = GENMASK_ULL(41, 20), + .reg_touud_mask = GENMASK_ULL(41, 20), + .reg_eccerrlog_addr_mask = GENMASK_ULL(38, 5), .imc_base = 0xd800, .ibecc_base = 0xd400, .ibecc_error_log_offset = 0x170, @@ -908,8 +950,8 @@ static void ecclog_work_cb(struct work_struct *work) if (res_cfg->err_addr) eaddr = res_cfg->err_addr(node->ecclog); else - eaddr = ECC_ERROR_LOG_ADDR(node->ecclog) << - ECC_ERROR_LOG_ADDR_SHIFT; + eaddr = node->ecclog & res_cfg->reg_eccerrlog_addr_mask; + res.mc = node->mc; res.sys_addr = res_cfg->err_addr_to_sys_addr(eaddr, res.mc); res.imc_addr = res_cfg->err_addr_to_imc_addr(eaddr, res.mc); @@ -1129,8 +1171,7 @@ static int debugfs_u64_set(void *data, u64 val) pr_warn_once("Fake error to 0x%llx injected via debugfs\n", val); - val >>= ECC_ERROR_LOG_ADDR_SHIFT; - ecclog = (val << ECC_ERROR_LOG_ADDR_SHIFT) | ECC_ERROR_LOG_CE; + ecclog = (val & res_cfg->reg_eccerrlog_addr_mask) | ECC_ERROR_LOG_CE; if (!ecclog_gen_pool_add(0, ecclog)) irq_work_queue(&ecclog_irq_work); @@ -1196,7 +1237,7 @@ static int igen6_pci_setup(struct pci_dev *pdev, u64 *mchbar) goto fail; } - igen6_tom = u.v & GENMASK_ULL(38, 20); + igen6_tom = u.v & res_cfg->reg_tom_mask; if (get_mchbar(pdev, mchbar)) goto fail; @@ -1207,7 +1248,7 @@ static int igen6_pci_setup(struct pci_dev *pdev, u64 *mchbar) else if (pci_read_config_dword(pdev, TOUUD_OFFSET + 4, &u.v_hi)) edac_dbg(2, "Failed to read upper TOUUD\n"); else - igen6_touud = u.v & GENMASK_ULL(38, 20); + igen6_touud = u.v & res_cfg->reg_touud_mask; #endif return 0; From 4c36e6106997b6ad8f4a279b4bdbca3ed6f53c6c Mon Sep 17 00:00:00 2001 From: Lili Li Date: Mon, 24 Nov 2025 21:15:37 +0800 Subject: [PATCH 5/9] EDAC/igen6: Add more Intel Panther Lake-H SoCs support Add more Intel Panther Lake-H SoC compute die IDs for EDAC support. Signed-off-by: Lili Li Signed-off-by: Tony Luck Reviewed-by: Qiuxu Zhuo Link: https://patch.msgid.link/20251124131537.3633983-1-qiuxu.zhuo@intel.com --- drivers/edac/igen6_edac.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c index 717862dc4765..045c20179cd3 100644 --- a/drivers/edac/igen6_edac.c +++ b/drivers/edac/igen6_edac.c @@ -281,6 +281,16 @@ static struct work_struct ecclog_work; #define DID_PTL_H_SKU1 0xb000 #define DID_PTL_H_SKU2 0xb001 #define DID_PTL_H_SKU3 0xb002 +#define DID_PTL_H_SKU4 0xb003 +#define DID_PTL_H_SKU5 0xb004 +#define DID_PTL_H_SKU6 0xb005 +#define DID_PTL_H_SKU7 0xb008 +#define DID_PTL_H_SKU8 0xb011 +#define DID_PTL_H_SKU9 0xb014 +#define DID_PTL_H_SKU10 0xb015 +#define DID_PTL_H_SKU11 0xb028 +#define DID_PTL_H_SKU12 0xb029 +#define DID_PTL_H_SKU13 0xb02a /* Compute die IDs for Wildcat Lake with IBECC */ #define DID_WCL_SKU1 0xfd00 @@ -682,6 +692,16 @@ static struct pci_device_id igen6_pci_tbl[] = { { PCI_VDEVICE(INTEL, DID_PTL_H_SKU1), (kernel_ulong_t)&mtl_p_cfg }, { PCI_VDEVICE(INTEL, DID_PTL_H_SKU2), (kernel_ulong_t)&mtl_p_cfg }, { PCI_VDEVICE(INTEL, DID_PTL_H_SKU3), (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU4), (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU5), (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU6), (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU7), (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU8), (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU9), (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU10), (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU11), (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU12), (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU13), (kernel_ulong_t)&mtl_p_cfg }, { PCI_VDEVICE(INTEL, DID_WCL_SKU1), (kernel_ulong_t)&wcl_cfg }, { }, }; From 0923a618a78fe4e329d79d6d50f8db2620845d39 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Mon, 1 Jul 2024 15:21:18 +0800 Subject: [PATCH 6/9] RAS/AMD/ATL: Remove an unneeded semicolon Remove an unneeded semicolon. No functional changes. Detected by Coccinelle. Signed-off-by: Chen Ni Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20240701072118.846277-1-nichen@iscas.ac.cn --- drivers/ras/amd/atl/denormalize.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ras/amd/atl/denormalize.c b/drivers/ras/amd/atl/denormalize.c index 1a525cfa983c..d45ce753e636 100644 --- a/drivers/ras/amd/atl/denormalize.c +++ b/drivers/ras/amd/atl/denormalize.c @@ -683,7 +683,7 @@ static int denorm_addr_df4_np2(struct addr_ctx *ctx) default: atl_debug_on_bad_intlv_mode(ctx); return -EINVAL; - }; + } if (ctx->map.num_intlv_sockets == 1) { hash_pa8 = BIT_ULL(shift_value) & ctx->ret_addr; From c816ba1dcd931b9db8d66c71e1ae34ddcdbf968f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 4 Dec 2025 11:02:25 +0100 Subject: [PATCH 7/9] EDAC/amd64: Avoid a -Wformat-security warning Using a variable as a format string causes a (default-disabled) warning: drivers/edac/amd64_edac.c: In function 'per_family_init': drivers/edac/amd64_edac.c:3914:17: error: format not a string literal and no format arguments [-Werror=format-security] 3914 | scnprintf(pvt->ctl_name, sizeof(pvt->ctl_name), tmp_name); | ^~~~~~~~~ The code here is safe, but in order to enable the warning by default in the future, change this instance to pass the name indirectly. Fixes: e9abd990aefd ("EDAC/amd64: Generate ctl_name string at runtime") Signed-off-by: Arnd Bergmann Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Avadhut Naik Reviewed-by: Qiuxu Zhuo Reviewed-by: Yazen Ghannam Link: https://patch.msgid.link/20251204100231.1034557-1-arnd@kernel.org --- drivers/edac/amd64_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 2391f3469961..63fca0ee2c23 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -3911,7 +3911,7 @@ static int per_family_init(struct amd64_pvt *pvt) } if (tmp_name) - scnprintf(pvt->ctl_name, sizeof(pvt->ctl_name), tmp_name); + scnprintf(pvt->ctl_name, sizeof(pvt->ctl_name), "%s", tmp_name); else scnprintf(pvt->ctl_name, sizeof(pvt->ctl_name), "F%02Xh_M%02Xh", pvt->fam, pvt->model); From 83b314e9c8824501e6fed7b313fdae9469da0d6f Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Thu, 29 Jan 2026 00:29:27 -0800 Subject: [PATCH 8/9] EDAC/i82443bxgx: Remove driver that has been marked broken since 2007 The history of this driver is pretty amusing. It was marked broken in 2007 in 28f96eeafc89 ("drivers/edac-new-i82443bxgz-mc-driver: mark as broken"). It was then fixed in 2008 in 53a2fe5804e8 ("edac: make i82443bxgx_edac coexist with intel_agp"), but the dependency on BROKEN was never removed. Given that this was never fixed in the last ~18 years, it is obvious there is no demand for this driver. Remove it and move the former maintainer to the CREDITS file. Signed-off-by: Ethan Nelson-Moore Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260129082937.48740-1-enelsonmoore@gmail.com --- CREDITS | 4 + MAINTAINERS | 6 - drivers/edac/Kconfig | 8 - drivers/edac/Makefile | 1 - drivers/edac/i82443bxgx_edac.c | 462 --------------------------------- 5 files changed, 4 insertions(+), 477 deletions(-) delete mode 100644 drivers/edac/i82443bxgx_edac.c diff --git a/CREDITS b/CREDITS index b735b8c58102..b007f9a71a87 100644 --- a/CREDITS +++ b/CREDITS @@ -3766,6 +3766,10 @@ S: 10 Stockalls Place S: Minto, NSW, 2566 S: Australia +N: Tim Small +E: tim@buttersideup.com +D: Intel 82443BX/GX (440BX/GX chipset) EDAC driver + N: Stephen Smalley E: sds@tycho.nsa.gov D: portions of the Linux Security Module (LSM) framework and security modules diff --git a/MAINTAINERS b/MAINTAINERS index 5b11839cba9d..4de00ed0955c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9089,12 +9089,6 @@ L: linux-edac@vger.kernel.org S: Maintained F: drivers/edac/i7core_edac.c -EDAC-I82443BXGX -M: Tim Small -L: linux-edac@vger.kernel.org -S: Maintained -F: drivers/edac/i82443bxgx_edac.c - EDAC-I82975X M: "Arvind R." L: linux-edac@vger.kernel.org diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 81e40543ffd8..b1dfb657f1b2 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -150,14 +150,6 @@ config EDAC_E752X Support for error detection and correction on the Intel E7520, E7525, E7320 server chipsets. -config EDAC_I82443BXGX - tristate "Intel 82443BX/GX (440BX/GX)" - depends on PCI && X86_32 - depends on BROKEN - help - Support for error detection and correction on the Intel - 82443BX/GX memory controllers (440BX/GX chipsets). - config EDAC_I82875P tristate "Intel 82875p (D82875P, E7210)" depends on PCI && X86_32 diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 8429b1e856bc..4f6a46321b32 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -38,7 +38,6 @@ 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 obj-$(CONFIG_EDAC_I82875P) += i82875p_edac.o obj-$(CONFIG_EDAC_I82975X) += i82975x_edac.o obj-$(CONFIG_EDAC_I3000) += i3000_edac.o diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c deleted file mode 100644 index 933dcf3cfdff..000000000000 --- a/drivers/edac/i82443bxgx_edac.c +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Intel 82443BX/GX (440BX/GX chipset) Memory Controller EDAC kernel - * module (C) 2006 Tim Small - * - * This file may be distributed under the terms of the GNU General - * Public License. - * - * Written by Tim Small , based on work by Linux - * Networx, Thayne Harbaugh, Dan Hollis and - * others. - * - * 440GX fix by Jason Uhlenkott . - * - * Written with reference to 82443BX Host Bridge Datasheet: - * http://download.intel.com/design/chipsets/datashts/29063301.pdf - * references to this document given in []. - * - * This module doesn't support the 440LX, but it may be possible to - * make it do so (the 440LX's register definitions are different, but - * not completely so - I haven't studied them in enough detail to know - * how easy this would be). - */ - -#include -#include - -#include -#include - - -#include -#include "edac_module.h" - -#define EDAC_MOD_STR "i82443bxgx_edac" - -/* The 82443BX supports SDRAM, or EDO (EDO for mobile only), "Memory - * Size: 8 MB to 512 MB (1GB with Registered DIMMs) with eight memory - * rows" "The 82443BX supports multiple-bit error detection and - * single-bit error correction when ECC mode is enabled and - * single/multi-bit error detection when correction is disabled. - * During writes to the DRAM, the 82443BX generates ECC for the data - * on a QWord basis. Partial QWord writes require a read-modify-write - * cycle when ECC is enabled." -*/ - -/* "Additionally, the 82443BX ensures that the data is corrected in - * main memory so that accumulation of errors is prevented. Another - * error within the same QWord would result in a double-bit error - * which is unrecoverable. This is known as hardware scrubbing since - * it requires no software intervention to correct the data in memory." - */ - -/* [Also see page 100 (section 4.3), "DRAM Interface"] - * [Also see page 112 (section 4.6.1.4), ECC] - */ - -#define I82443BXGX_NR_CSROWS 8 -#define I82443BXGX_NR_CHANS 1 -#define I82443BXGX_NR_DIMMS 4 - -/* 82443 PCI Device 0 */ -#define I82443BXGX_NBXCFG 0x50 /* 32bit register starting at this PCI - * config space offset */ -#define I82443BXGX_NBXCFG_OFFSET_NON_ECCROW 24 /* Array of bits, zero if - * row is non-ECC */ -#define I82443BXGX_NBXCFG_OFFSET_DRAM_FREQ 12 /* 2 bits,00=100MHz,10=66 MHz */ - -#define I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY 7 /* 2 bits: */ -#define I82443BXGX_NBXCFG_INTEGRITY_NONE 0x0 /* 00 = Non-ECC */ -#define I82443BXGX_NBXCFG_INTEGRITY_EC 0x1 /* 01 = EC (only) */ -#define I82443BXGX_NBXCFG_INTEGRITY_ECC 0x2 /* 10 = ECC */ -#define I82443BXGX_NBXCFG_INTEGRITY_SCRUB 0x3 /* 11 = ECC + HW Scrub */ - -#define I82443BXGX_NBXCFG_OFFSET_ECC_DIAG_ENABLE 6 - -/* 82443 PCI Device 0 */ -#define I82443BXGX_EAP 0x80 /* 32bit register starting at this PCI - * config space offset, Error Address - * Pointer Register */ -#define I82443BXGX_EAP_OFFSET_EAP 12 /* High 20 bits of error address */ -#define I82443BXGX_EAP_OFFSET_MBE BIT(1) /* Err at EAP was multi-bit (W1TC) */ -#define I82443BXGX_EAP_OFFSET_SBE BIT(0) /* Err at EAP was single-bit (W1TC) */ - -#define I82443BXGX_ERRCMD 0x90 /* 8bit register starting at this PCI - * config space offset. */ -#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_MBE BIT(1) /* 1 = enable */ -#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_SBE BIT(0) /* 1 = enable */ - -#define I82443BXGX_ERRSTS 0x91 /* 16bit register starting at this PCI - * config space offset. */ -#define I82443BXGX_ERRSTS_OFFSET_MBFRE 5 /* 3 bits - first err row multibit */ -#define I82443BXGX_ERRSTS_OFFSET_MEF BIT(4) /* 1 = MBE occurred */ -#define I82443BXGX_ERRSTS_OFFSET_SBFRE 1 /* 3 bits - first err row singlebit */ -#define I82443BXGX_ERRSTS_OFFSET_SEF BIT(0) /* 1 = SBE occurred */ - -#define I82443BXGX_DRAMC 0x57 /* 8bit register starting at this PCI - * config space offset. */ -#define I82443BXGX_DRAMC_OFFSET_DT 3 /* 2 bits, DRAM Type */ -#define I82443BXGX_DRAMC_DRAM_IS_EDO 0 /* 00 = EDO */ -#define I82443BXGX_DRAMC_DRAM_IS_SDRAM 1 /* 01 = SDRAM */ -#define I82443BXGX_DRAMC_DRAM_IS_RSDRAM 2 /* 10 = Registered SDRAM */ - -#define I82443BXGX_DRB 0x60 /* 8x 8bit registers starting at this PCI - * config space offset. */ - -/* FIXME - don't poll when ECC disabled? */ - -struct i82443bxgx_edacmc_error_info { - u32 eap; -}; - -static struct edac_pci_ctl_info *i82443bxgx_pci; - -static struct pci_dev *mci_pdev; /* init dev: in case that AGP code has - * already registered driver - */ - -static int i82443bxgx_registered = 1; - -static void i82443bxgx_edacmc_get_error_info(struct mem_ctl_info *mci, - struct i82443bxgx_edacmc_error_info - *info) -{ - struct pci_dev *pdev; - pdev = to_pci_dev(mci->pdev); - pci_read_config_dword(pdev, I82443BXGX_EAP, &info->eap); - if (info->eap & I82443BXGX_EAP_OFFSET_SBE) - /* Clear error to allow next error to be reported [p.61] */ - pci_write_bits32(pdev, I82443BXGX_EAP, - I82443BXGX_EAP_OFFSET_SBE, - I82443BXGX_EAP_OFFSET_SBE); - - if (info->eap & I82443BXGX_EAP_OFFSET_MBE) - /* Clear error to allow next error to be reported [p.61] */ - pci_write_bits32(pdev, I82443BXGX_EAP, - I82443BXGX_EAP_OFFSET_MBE, - I82443BXGX_EAP_OFFSET_MBE); -} - -static int i82443bxgx_edacmc_process_error_info(struct mem_ctl_info *mci, - struct - i82443bxgx_edacmc_error_info - *info, int handle_errors) -{ - int error_found = 0; - u32 eapaddr, page, pageoffset; - - /* bits 30:12 hold the 4kb block in which the error occurred - * [p.61] */ - eapaddr = (info->eap & 0xfffff000); - page = eapaddr >> PAGE_SHIFT; - pageoffset = eapaddr - (page << PAGE_SHIFT); - - if (info->eap & I82443BXGX_EAP_OFFSET_SBE) { - error_found = 1; - if (handle_errors) - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, - page, pageoffset, 0, - edac_mc_find_csrow_by_page(mci, page), - 0, -1, mci->ctl_name, ""); - } - - if (info->eap & I82443BXGX_EAP_OFFSET_MBE) { - error_found = 1; - if (handle_errors) - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, - page, pageoffset, 0, - edac_mc_find_csrow_by_page(mci, page), - 0, -1, mci->ctl_name, ""); - } - - return error_found; -} - -static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci) -{ - struct i82443bxgx_edacmc_error_info info; - - i82443bxgx_edacmc_get_error_info(mci, &info); - i82443bxgx_edacmc_process_error_info(mci, &info, 1); -} - -static void i82443bxgx_init_csrows(struct mem_ctl_info *mci, - struct pci_dev *pdev, - enum edac_type edac_mode, - enum mem_type mtype) -{ - struct csrow_info *csrow; - struct dimm_info *dimm; - int index; - u8 drbar, dramc; - u32 row_base, row_high_limit, row_high_limit_last; - - pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc); - row_high_limit_last = 0; - for (index = 0; index < mci->nr_csrows; index++) { - csrow = mci->csrows[index]; - dimm = csrow->channels[0]->dimm; - - pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar); - edac_dbg(1, "MC%d: Row=%d DRB = %#0x\n", - mci->mc_idx, index, drbar); - row_high_limit = ((u32) drbar << 23); - /* find the DRAM Chip Select Base address and mask */ - edac_dbg(1, "MC%d: Row=%d, Boundary Address=%#0x, Last = %#0x\n", - mci->mc_idx, index, row_high_limit, - row_high_limit_last); - - /* 440GX goes to 2GB, represented with a DRB of 0. */ - if (row_high_limit_last && !row_high_limit) - row_high_limit = 1UL << 31; - - /* This row is empty [p.49] */ - if (row_high_limit == row_high_limit_last) - continue; - row_base = row_high_limit_last; - csrow->first_page = row_base >> PAGE_SHIFT; - csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1; - dimm->nr_pages = csrow->last_page - csrow->first_page + 1; - /* EAP reports in 4kilobyte granularity [61] */ - dimm->grain = 1 << 12; - dimm->mtype = mtype; - /* I don't think 440BX can tell you device type? FIXME? */ - dimm->dtype = DEV_UNKNOWN; - /* Mode is global to all rows on 440BX */ - dimm->edac_mode = edac_mode; - row_high_limit_last = row_high_limit; - } -} - -static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx) -{ - struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; - u8 dramc; - u32 nbxcfg, ecc_mode; - enum mem_type mtype; - enum edac_type edac_mode; - - edac_dbg(0, "MC:\n"); - - /* Something is really hosed if PCI config space reads from - * the MC aren't working. - */ - if (pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg)) - return -EIO; - - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = I82443BXGX_NR_CSROWS; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = I82443BXGX_NR_CHANS; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0); - if (mci == NULL) - return -ENOMEM; - - edac_dbg(0, "MC: mci = %p\n", mci); - mci->pdev = &pdev->dev; - mci->mtype_cap = MEM_FLAG_EDO | MEM_FLAG_SDR | MEM_FLAG_RDR; - mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; - pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc); - switch ((dramc >> I82443BXGX_DRAMC_OFFSET_DT) & (BIT(0) | BIT(1))) { - case I82443BXGX_DRAMC_DRAM_IS_EDO: - mtype = MEM_EDO; - break; - case I82443BXGX_DRAMC_DRAM_IS_SDRAM: - mtype = MEM_SDR; - break; - case I82443BXGX_DRAMC_DRAM_IS_RSDRAM: - mtype = MEM_RDR; - break; - default: - edac_dbg(0, "Unknown/reserved DRAM type value in DRAMC register!\n"); - mtype = -MEM_UNKNOWN; - } - - if ((mtype == MEM_SDR) || (mtype == MEM_RDR)) - mci->edac_cap = mci->edac_ctl_cap; - else - mci->edac_cap = EDAC_FLAG_NONE; - - mci->scrub_cap = SCRUB_FLAG_HW_SRC; - pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg); - ecc_mode = ((nbxcfg >> I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY) & - (BIT(0) | BIT(1))); - - mci->scrub_mode = (ecc_mode == I82443BXGX_NBXCFG_INTEGRITY_SCRUB) - ? SCRUB_HW_SRC : SCRUB_NONE; - - switch (ecc_mode) { - case I82443BXGX_NBXCFG_INTEGRITY_NONE: - edac_mode = EDAC_NONE; - break; - case I82443BXGX_NBXCFG_INTEGRITY_EC: - edac_mode = EDAC_EC; - break; - case I82443BXGX_NBXCFG_INTEGRITY_ECC: - case I82443BXGX_NBXCFG_INTEGRITY_SCRUB: - edac_mode = EDAC_SECDED; - break; - default: - edac_dbg(0, "Unknown/reserved ECC state in NBXCFG register!\n"); - edac_mode = EDAC_UNKNOWN; - break; - } - - i82443bxgx_init_csrows(mci, pdev, edac_mode, mtype); - - /* Many BIOSes don't clear error flags on boot, so do this - * here, or we get "phantom" errors occurring at module-load - * time. */ - pci_write_bits32(pdev, I82443BXGX_EAP, - (I82443BXGX_EAP_OFFSET_SBE | - I82443BXGX_EAP_OFFSET_MBE), - (I82443BXGX_EAP_OFFSET_SBE | - I82443BXGX_EAP_OFFSET_MBE)); - - mci->mod_name = EDAC_MOD_STR; - mci->ctl_name = "I82443BXGX"; - mci->dev_name = pci_name(pdev); - mci->edac_check = i82443bxgx_edacmc_check; - mci->ctl_page_to_phys = NULL; - - if (edac_mc_add_mc(mci)) { - edac_dbg(3, "failed edac_mc_add_mc()\n"); - goto fail; - } - - /* allocating generic PCI control info */ - i82443bxgx_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); - if (!i82443bxgx_pci) { - printk(KERN_WARNING - "%s(): Unable to create PCI control\n", - __func__); - printk(KERN_WARNING - "%s(): PCI error report via EDAC not setup\n", - __func__); - } - - edac_dbg(3, "MC: success\n"); - return 0; - -fail: - edac_mc_free(mci); - return -ENODEV; -} - -/* returns count (>= 0), or negative on error */ -static int i82443bxgx_edacmc_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int rc; - - edac_dbg(0, "MC:\n"); - - /* don't need to call pci_enable_device() */ - rc = i82443bxgx_edacmc_probe1(pdev, ent->driver_data); - - if (mci_pdev == NULL) - mci_pdev = pci_dev_get(pdev); - - return rc; -} - -static void i82443bxgx_edacmc_remove_one(struct pci_dev *pdev) -{ - struct mem_ctl_info *mci; - - edac_dbg(0, "\n"); - - if (i82443bxgx_pci) - edac_pci_release_generic_ctl(i82443bxgx_pci); - - if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) - return; - - edac_mc_free(mci); -} - -static const struct pci_device_id i82443bxgx_pci_tbl[] = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2)}, - {0,} /* 0 terminated list. */ -}; - -MODULE_DEVICE_TABLE(pci, i82443bxgx_pci_tbl); - -static struct pci_driver i82443bxgx_edacmc_driver = { - .name = EDAC_MOD_STR, - .probe = i82443bxgx_edacmc_init_one, - .remove = i82443bxgx_edacmc_remove_one, - .id_table = i82443bxgx_pci_tbl, -}; - -static int __init i82443bxgx_edacmc_init(void) -{ - int pci_rc; - /* Ensure that the OPSTATE is set correctly for POLL or NMI */ - opstate_init(); - - pci_rc = pci_register_driver(&i82443bxgx_edacmc_driver); - if (pci_rc < 0) - goto fail0; - - if (mci_pdev == NULL) { - const struct pci_device_id *id = &i82443bxgx_pci_tbl[0]; - int i = 0; - i82443bxgx_registered = 0; - - while (mci_pdev == NULL && id->vendor != 0) { - mci_pdev = pci_get_device(id->vendor, - id->device, NULL); - i++; - id = &i82443bxgx_pci_tbl[i]; - } - if (!mci_pdev) { - edac_dbg(0, "i82443bxgx pci_get_device fail\n"); - pci_rc = -ENODEV; - goto fail1; - } - - pci_rc = i82443bxgx_edacmc_init_one(mci_pdev, i82443bxgx_pci_tbl); - - if (pci_rc < 0) { - edac_dbg(0, "i82443bxgx init fail\n"); - pci_rc = -ENODEV; - goto fail1; - } - } - - return 0; - -fail1: - pci_unregister_driver(&i82443bxgx_edacmc_driver); - -fail0: - pci_dev_put(mci_pdev); - return pci_rc; -} - -static void __exit i82443bxgx_edacmc_exit(void) -{ - pci_unregister_driver(&i82443bxgx_edacmc_driver); - - if (!i82443bxgx_registered) - i82443bxgx_edacmc_remove_one(mci_pdev); - - pci_dev_put(mci_pdev); -} - -module_init(i82443bxgx_edacmc_init); -module_exit(i82443bxgx_edacmc_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Tim Small - WPAD"); -MODULE_DESCRIPTION("EDAC MC support for Intel 82443BX/GX memory controllers"); - -module_param(edac_op_state, int, 0444); -MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); From 1795dc528c13c4cb731c6db2322d0c995c997fa4 Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Thu, 29 Jan 2026 21:26:23 -0800 Subject: [PATCH 9/9] EDAC/r82600: Remove this obsolete driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver supports the Radisys 82600 embedded chipset, which was used with Pentium III-era CPUs. It is highly unlikely that it is still used. Besides its own documentation, the only information I was able to find about the R82600, after looking through many pages of Google results, was that it was used in a Nokia 2G GSM base station. The original author said: "This was after Bluesmoke (watch was out-of-tree), and was pay of the first set of in tree edac drivers (a fresh design as far as I remember). This particular driver did apparently get used by Akamai quite heavily and widely  but all ancient history now. The Radisys r82600 edac driver  r82600_edac.c was closely related hardware from the same era, and can probably go too (although being embedded hardware, it's possible its production lifespan was considerably longer). Tim." Mail is https://lore.kernel.org/r/01BCCA37-F6A2-458B-BFE7-99C7724CDDEA@buttersideup.com but lkml drops html mail so quoting the relevant info here too. [ bp: Massage and extend commit message. ] Signed-off-by: Ethan Nelson-Moore Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260130052633.13119-1-enelsonmoore@gmail.com --- CREDITS | 1 + MAINTAINERS | 6 - drivers/edac/Kconfig | 7 - drivers/edac/Makefile | 1 - drivers/edac/r82600_edac.c | 426 ------------------------------------- 5 files changed, 1 insertion(+), 440 deletions(-) delete mode 100644 drivers/edac/r82600_edac.c diff --git a/CREDITS b/CREDITS index b007f9a71a87..6dffb2cf472d 100644 --- a/CREDITS +++ b/CREDITS @@ -3769,6 +3769,7 @@ S: Australia N: Tim Small E: tim@buttersideup.com D: Intel 82443BX/GX (440BX/GX chipset) EDAC driver +D: Radisys 82600 embedded chipset EDAC driver N: Stephen Smalley E: sds@tycho.nsa.gov diff --git a/MAINTAINERS b/MAINTAINERS index 4de00ed0955c..f7e03e2a4511 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9141,12 +9141,6 @@ L: linux-edac@vger.kernel.org S: Maintained F: drivers/edac/qcom_edac.c -EDAC-R82600 -M: Tim Small -L: linux-edac@vger.kernel.org -S: Maintained -F: drivers/edac/r82600_edac.c - EDAC-SBRIDGE M: Tony Luck R: Qiuxu Zhuo diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index b1dfb657f1b2..a44b85c440ca 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -215,13 +215,6 @@ config EDAC_I82860 Support for error detection and correction on the Intel 82860 chipset. -config EDAC_R82600 - tristate "Radisys 82600 embedded chipset" - depends on PCI && X86_32 - help - Support for error detection and correction on the Radisys - 82600 embedded chipset. - config EDAC_I5000 tristate "Intel Greencreek/Blackford chipset" depends on X86 && PCI diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 4f6a46321b32..a37534300ab9 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -45,7 +45,6 @@ obj-$(CONFIG_EDAC_I3200) += i3200_edac.o obj-$(CONFIG_EDAC_IE31200) += ie31200_edac.o obj-$(CONFIG_EDAC_X38) += x38_edac.o obj-$(CONFIG_EDAC_I82860) += i82860_edac.o -obj-$(CONFIG_EDAC_R82600) += r82600_edac.o obj-$(CONFIG_EDAC_AMD64) += amd64_edac.o obj-$(CONFIG_EDAC_PASEMI) += pasemi_edac.o diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c deleted file mode 100644 index 61e979d5437a..000000000000 --- a/drivers/edac/r82600_edac.c +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Radisys 82600 Embedded chipset Memory Controller kernel module - * (C) 2005 EADS Astrium - * This file may be distributed under the terms of the - * GNU General Public License. - * - * Written by Tim Small , based on work by Thayne - * Harbaugh, Dan Hollis and others. - * - * $Id: edac_r82600.c,v 1.1.2.6 2005/10/05 00:43:44 dsp_llnl Exp $ - * - * Written with reference to 82600 High Integration Dual PCI System - * Controller Data Book: - * www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf - * references to this document given in [] - */ - -#include -#include -#include -#include -#include -#include "edac_module.h" - -#define EDAC_MOD_STR "r82600_edac" - -#define r82600_printk(level, fmt, arg...) \ - edac_printk(level, "r82600", fmt, ##arg) - -#define r82600_mc_printk(mci, level, fmt, arg...) \ - edac_mc_chipset_printk(mci, level, "r82600", fmt, ##arg) - -/* Radisys say "The 82600 integrates a main memory SDRAM controller that - * supports up to four banks of memory. The four banks can support a mix of - * sizes of 64 bit wide (72 bits with ECC) Synchronous DRAM (SDRAM) DIMMs, - * each of which can be any size from 16MB to 512MB. Both registered (control - * signals buffered) and unbuffered DIMM types are supported. Mixing of - * registered and unbuffered DIMMs as well as mixing of ECC and non-ECC DIMMs - * is not allowed. The 82600 SDRAM interface operates at the same frequency as - * the CPU bus, 66MHz, 100MHz or 133MHz." - */ - -#define R82600_NR_CSROWS 4 -#define R82600_NR_CHANS 1 -#define R82600_NR_DIMMS 4 - -#define R82600_BRIDGE_ID 0x8200 - -/* Radisys 82600 register addresses - device 0 function 0 - PCI bridge */ -#define R82600_DRAMC 0x57 /* Various SDRAM related control bits - * all bits are R/W - * - * 7 SDRAM ISA Hole Enable - * 6 Flash Page Mode Enable - * 5 ECC Enable: 1=ECC 0=noECC - * 4 DRAM DIMM Type: 1= - * 3 BIOS Alias Disable - * 2 SDRAM BIOS Flash Write Enable - * 1:0 SDRAM Refresh Rate: 00=Disabled - * 01=7.8usec (256Mbit SDRAMs) - * 10=15.6us 11=125usec - */ - -#define R82600_SDRAMC 0x76 /* "SDRAM Control Register" - * More SDRAM related control bits - * all bits are R/W - * - * 15:8 Reserved. - * - * 7:5 Special SDRAM Mode Select - * - * 4 Force ECC - * - * 1=Drive ECC bits to 0 during - * write cycles (i.e. ECC test mode) - * - * 0=Normal ECC functioning - * - * 3 Enhanced Paging Enable - * - * 2 CAS# Latency 0=3clks 1=2clks - * - * 1 RAS# to CAS# Delay 0=3 1=2 - * - * 0 RAS# Precharge 0=3 1=2 - */ - -#define R82600_EAP 0x80 /* ECC Error Address Pointer Register - * - * 31 Disable Hardware Scrubbing (RW) - * 0=Scrub on corrected read - * 1=Don't scrub on corrected read - * - * 30:12 Error Address Pointer (RO) - * Upper 19 bits of error address - * - * 11:4 Syndrome Bits (RO) - * - * 3 BSERR# on multibit error (RW) - * 1=enable 0=disable - * - * 2 NMI on Single Bit Eror (RW) - * 1=NMI triggered by SBE n.b. other - * prerequeists - * 0=NMI not triggered - * - * 1 MBE (R/WC) - * read 1=MBE at EAP (see above) - * read 0=no MBE, or SBE occurred first - * write 1=Clear MBE status (must also - * clear SBE) - * write 0=NOP - * - * 1 SBE (R/WC) - * read 1=SBE at EAP (see above) - * read 0=no SBE, or MBE occurred first - * write 1=Clear SBE status (must also - * clear MBE) - * write 0=NOP - */ - -#define R82600_DRBA 0x60 /* + 0x60..0x63 SDRAM Row Boundary Address - * Registers - * - * 7:0 Address lines 30:24 - upper limit of - * each row [p57] - */ - -struct r82600_error_info { - u32 eapr; -}; - -static bool disable_hardware_scrub; - -static struct edac_pci_ctl_info *r82600_pci; - -static void r82600_get_error_info(struct mem_ctl_info *mci, - struct r82600_error_info *info) -{ - struct pci_dev *pdev; - - pdev = to_pci_dev(mci->pdev); - pci_read_config_dword(pdev, R82600_EAP, &info->eapr); - - if (info->eapr & BIT(0)) - /* Clear error to allow next error to be reported [p.62] */ - pci_write_bits32(pdev, R82600_EAP, - ((u32) BIT(0) & (u32) BIT(1)), - ((u32) BIT(0) & (u32) BIT(1))); - - if (info->eapr & BIT(1)) - /* Clear error to allow next error to be reported [p.62] */ - pci_write_bits32(pdev, R82600_EAP, - ((u32) BIT(0) & (u32) BIT(1)), - ((u32) BIT(0) & (u32) BIT(1))); -} - -static int r82600_process_error_info(struct mem_ctl_info *mci, - struct r82600_error_info *info, - int handle_errors) -{ - int error_found; - u32 eapaddr, page; - u32 syndrome; - - error_found = 0; - - /* bits 30:12 store the upper 19 bits of the 32 bit error address */ - eapaddr = ((info->eapr >> 12) & 0x7FFF) << 13; - /* Syndrome in bits 11:4 [p.62] */ - syndrome = (info->eapr >> 4) & 0xFF; - - /* the R82600 reports at less than page * - * granularity (upper 19 bits only) */ - page = eapaddr >> PAGE_SHIFT; - - if (info->eapr & BIT(0)) { /* CE? */ - error_found = 1; - - if (handle_errors) - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, - page, 0, syndrome, - edac_mc_find_csrow_by_page(mci, page), - 0, -1, - mci->ctl_name, ""); - } - - if (info->eapr & BIT(1)) { /* UE? */ - error_found = 1; - - if (handle_errors) - /* 82600 doesn't give enough info */ - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, - page, 0, 0, - edac_mc_find_csrow_by_page(mci, page), - 0, -1, - mci->ctl_name, ""); - } - - return error_found; -} - -static void r82600_check(struct mem_ctl_info *mci) -{ - struct r82600_error_info info; - - r82600_get_error_info(mci, &info); - r82600_process_error_info(mci, &info, 1); -} - -static inline int ecc_enabled(u8 dramcr) -{ - return dramcr & BIT(5); -} - -static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, - u8 dramcr) -{ - struct csrow_info *csrow; - struct dimm_info *dimm; - int index; - u8 drbar; /* SDRAM Row Boundary Address Register */ - u32 row_high_limit, row_high_limit_last; - u32 reg_sdram, ecc_on, row_base; - - ecc_on = ecc_enabled(dramcr); - reg_sdram = dramcr & BIT(4); - row_high_limit_last = 0; - - for (index = 0; index < mci->nr_csrows; index++) { - csrow = mci->csrows[index]; - dimm = csrow->channels[0]->dimm; - - /* find the DRAM Chip Select Base address and mask */ - pci_read_config_byte(pdev, R82600_DRBA + index, &drbar); - - edac_dbg(1, "Row=%d DRBA = %#0x\n", index, drbar); - - row_high_limit = ((u32) drbar << 24); -/* row_high_limit = ((u32)drbar << 24) | 0xffffffUL; */ - - edac_dbg(1, "Row=%d, Boundary Address=%#0x, Last = %#0x\n", - index, row_high_limit, row_high_limit_last); - - /* Empty row [p.57] */ - if (row_high_limit == row_high_limit_last) - continue; - - row_base = row_high_limit_last; - - csrow->first_page = row_base >> PAGE_SHIFT; - csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1; - - dimm->nr_pages = csrow->last_page - csrow->first_page + 1; - /* Error address is top 19 bits - so granularity is * - * 14 bits */ - dimm->grain = 1 << 14; - dimm->mtype = reg_sdram ? MEM_RDDR : MEM_DDR; - /* FIXME - check that this is unknowable with this chipset */ - dimm->dtype = DEV_UNKNOWN; - - /* Mode is global on 82600 */ - dimm->edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE; - row_high_limit_last = row_high_limit; - } -} - -static int r82600_probe1(struct pci_dev *pdev, int dev_idx) -{ - struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; - u8 dramcr; - u32 eapr; - u32 scrub_disabled; - u32 sdram_refresh_rate; - struct r82600_error_info discard; - - edac_dbg(0, "\n"); - pci_read_config_byte(pdev, R82600_DRAMC, &dramcr); - pci_read_config_dword(pdev, R82600_EAP, &eapr); - scrub_disabled = eapr & BIT(31); - sdram_refresh_rate = dramcr & (BIT(0) | BIT(1)); - edac_dbg(2, "sdram refresh rate = %#0x\n", sdram_refresh_rate); - edac_dbg(2, "DRAMC register = %#0x\n", dramcr); - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = R82600_NR_CSROWS; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = R82600_NR_CHANS; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0); - if (mci == NULL) - return -ENOMEM; - - edac_dbg(0, "mci = %p\n", mci); - mci->pdev = &pdev->dev; - mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR; - mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; - /* FIXME try to work out if the chip leads have been used for COM2 - * instead on this board? [MA6?] MAYBE: - */ - - /* On the R82600, the pins for memory bits 72:65 - i.e. the * - * EC bits are shared with the pins for COM2 (!), so if COM2 * - * is enabled, we assume COM2 is wired up, and thus no EDAC * - * is possible. */ - mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; - - if (ecc_enabled(dramcr)) { - if (scrub_disabled) - edac_dbg(3, "mci = %p - Scrubbing disabled! EAP: %#0x\n", - mci, eapr); - } else - mci->edac_cap = EDAC_FLAG_NONE; - - mci->mod_name = EDAC_MOD_STR; - mci->ctl_name = "R82600"; - mci->dev_name = pci_name(pdev); - mci->edac_check = r82600_check; - mci->ctl_page_to_phys = NULL; - r82600_init_csrows(mci, pdev, dramcr); - r82600_get_error_info(mci, &discard); /* clear counters */ - - /* Here we assume that we will never see multiple instances of this - * type of memory controller. The ID is therefore hardcoded to 0. - */ - if (edac_mc_add_mc(mci)) { - edac_dbg(3, "failed edac_mc_add_mc()\n"); - goto fail; - } - - /* get this far and it's successful */ - - if (disable_hardware_scrub) { - edac_dbg(3, "Disabling Hardware Scrub (scrub on error)\n"); - pci_write_bits32(pdev, R82600_EAP, BIT(31), BIT(31)); - } - - /* allocating generic PCI control info */ - r82600_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); - if (!r82600_pci) { - printk(KERN_WARNING - "%s(): Unable to create PCI control\n", - __func__); - printk(KERN_WARNING - "%s(): PCI error report via EDAC not setup\n", - __func__); - } - - edac_dbg(3, "success\n"); - return 0; - -fail: - edac_mc_free(mci); - return -ENODEV; -} - -/* returns count (>= 0), or negative on error */ -static int r82600_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - edac_dbg(0, "\n"); - - /* don't need to call pci_enable_device() */ - return r82600_probe1(pdev, ent->driver_data); -} - -static void r82600_remove_one(struct pci_dev *pdev) -{ - struct mem_ctl_info *mci; - - edac_dbg(0, "\n"); - - if (r82600_pci) - edac_pci_release_generic_ctl(r82600_pci); - - if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) - return; - - edac_mc_free(mci); -} - -static const struct pci_device_id r82600_pci_tbl[] = { - { - PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID) - }, - { - 0, - } /* 0 terminated list. */ -}; - -MODULE_DEVICE_TABLE(pci, r82600_pci_tbl); - -static struct pci_driver r82600_driver = { - .name = EDAC_MOD_STR, - .probe = r82600_init_one, - .remove = r82600_remove_one, - .id_table = r82600_pci_tbl, -}; - -static int __init r82600_init(void) -{ - /* Ensure that the OPSTATE is set correctly for POLL or NMI */ - opstate_init(); - - return pci_register_driver(&r82600_driver); -} - -static void __exit r82600_exit(void) -{ - pci_unregister_driver(&r82600_driver); -} - -module_init(r82600_init); -module_exit(r82600_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Tim Small - WPAD Ltd. on behalf of EADS Astrium"); -MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers"); - -module_param(disable_hardware_scrub, bool, 0644); -MODULE_PARM_DESC(disable_hardware_scrub, - "If set, disable the chipset's automatic scrub for CEs"); - -module_param(edac_op_state, int, 0444); -MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");