From 2c6a0994e9f15da5aba8cb108df35a257a792030 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 13 May 2026 22:48:55 +0200 Subject: [PATCH 01/22] RAS/AMD/ATL: Drop malformed default N from Kconfig The capital letters are for symbols and N in 'default N' will be evaluated as another, nonexistent, Kconfig symbol, and not as the 'no' it should be. More importantly, 'n' *is* the default already. Hence just drop the malformed line. Signed-off-by: Andy Shevchenko Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260513205021.368190-1-andriy.shevchenko@linux.intel.com --- drivers/ras/amd/atl/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/ras/amd/atl/Kconfig b/drivers/ras/amd/atl/Kconfig index 6e03942cd7da..44c2fd7febc5 100644 --- a/drivers/ras/amd/atl/Kconfig +++ b/drivers/ras/amd/atl/Kconfig @@ -12,7 +12,6 @@ config AMD_ATL depends on AMD_NB && X86_64 && RAS depends on AMD_NODE depends on MEMORY_FAILURE - default N help This library includes support for implementation-specific address translation procedures needed for various error From e360a6d65bb46c527a5909430a31d640cdd5036e Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Tue, 14 Apr 2026 11:17:16 -0700 Subject: [PATCH 02/22] EDAC/i10nm: Don't fail probing if ADXL is missing ADXL is not present in Coreboot- or Slimbootloader-based BIOSes and as result, the driver fails to probe there. Since commit 2738c69a8813 ("EDAC/i10nm: Add driver decoder for Ice Lake and Tremont CPUs"), i10nm_edac supports driver decoder. Switch to driver decoding when ADXL is not present. Signed-off-by: Vasily Khoruzhick Signed-off-by: Tony Luck Reviewed-by: Qiuxu Zhuo Cc: stable@vger.kernel.org # v6.1+ Link: https://patch.msgid.link/20260414181735.87023-1-anarsoul@gmail.com --- drivers/edac/i10nm_base.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c index 63df35444214..de6c52dbd9d2 100644 --- a/drivers/edac/i10nm_base.c +++ b/drivers/edac/i10nm_base.c @@ -79,6 +79,7 @@ static struct res_config *res_cfg; static int retry_rd_err_log; static int decoding_via_mca; static bool mem_cfg_2lm; +static bool no_adxl; static struct reg_rrl icx_reg_rrl_ddr = { .set_num = 2, @@ -1222,8 +1223,14 @@ static int __init i10nm_init(void) } rc = skx_adxl_get(); - if (rc) - goto fail; + if (rc) { + /* Decoding errors via MCA banks for 2LM isn't supported yet */ + if (rc != -ENODEV || mem_cfg_2lm) + goto fail; + i10nm_printk(KERN_INFO, "ADXL not found, falling back to MCA-based decoding.\n"); + no_adxl = true; + decoding_via_mca = true; + } opstate_init(); mce_register_decode_chain(&i10nm_mce_dec); @@ -1257,7 +1264,8 @@ static void __exit i10nm_exit(void) skx_teardown_debug(); mce_unregister_decode_chain(&i10nm_mce_dec); - skx_adxl_put(); + if (!no_adxl) + skx_adxl_put(); skx_remove(); } From 7944f44098c277d0a5e34a4d9d078077d05f51af Mon Sep 17 00:00:00 2001 From: Tushar Tibude Date: Wed, 29 Apr 2026 15:18:06 +0530 Subject: [PATCH 03/22] EDAC/i7300: disable error reporting if init fails and refactor helper If error reporting is enabled during initialization but initialization fails immediately after, or during normal driver exit, error reporting is left enabled in the mask register even after exit. Replace i7300_enable_error_reporting() with i7300_set_error_reporting() to combine enabling/disabling. Disable reporting at initialization failure and driver exit, before call to i7300_put_devices() for cleanup. Add enabled reporting flag to i7300_pvt. This ensures clean hardware handling by disabling any unused error reporting bits before exiting. Signed-off-by: Tushar Tibude Signed-off-by: Tony Luck Reviewed-by: Qiuxu Zhuo Link: https://patch.msgid.link/20260429094806.25097-1-tushar.tibude1000@gmail.com --- drivers/edac/i7300_edac.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c index 69068f8d0cad..64bc2d805a62 100644 --- a/drivers/edac/i7300_edac.c +++ b/drivers/edac/i7300_edac.c @@ -111,6 +111,9 @@ struct i7300_pvt { /* Temporary buffer for use when preparing error messages */ char *tmp_prt_buffer; + + /* Hardware error reporting status */ + bool enabled_error_reporting; }; /* FIXME: Why do we need to have this static? */ @@ -550,11 +553,12 @@ static void i7300_clear_error(struct mem_ctl_info *mci) } /** - * i7300_enable_error_reporting() - Enable the memory reporting logic at the + * i7300_set_error_reporting() - Enable or disable the memory reporting logic at the * hardware * @mci: struct mem_ctl_info pointer + * @enable: enables if 'true', disables if 'false' */ -static void i7300_enable_error_reporting(struct mem_ctl_info *mci) +static void i7300_set_error_reporting(struct mem_ctl_info *mci, bool enable) { struct i7300_pvt *pvt = mci->pvt_info; u32 fbd_error_mask; @@ -563,8 +567,11 @@ static void i7300_enable_error_reporting(struct mem_ctl_info *mci) pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, EMASK_FBD, &fbd_error_mask); - /* Enable with a '0' */ - fbd_error_mask &= ~(EMASK_FBD_ERR_MASK); + /* Enable with 0, disable with 1 */ + if (enable) + fbd_error_mask &= ~(EMASK_FBD_ERR_MASK); + else + fbd_error_mask |= EMASK_FBD_ERR_MASK; pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, EMASK_FBD, fbd_error_mask); @@ -1087,17 +1094,19 @@ static int i7300_init_one(struct pci_dev *pdev, const struct pci_device_id *id) if (i7300_get_mc_regs(mci)) { edac_dbg(0, "MC: Setting mci->edac_cap to EDAC_FLAG_NONE because i7300_init_csrows() returned nonzero value\n"); mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */ + pvt->enabled_error_reporting = false; } else { edac_dbg(1, "MC: Enable error reporting now\n"); - i7300_enable_error_reporting(mci); + i7300_set_error_reporting(mci, true); + pvt->enabled_error_reporting = true; } /* add this new MC control structure to EDAC's list of MCs */ if (edac_mc_add_mc(mci)) { edac_dbg(0, "MC: failed edac_mc_add_mc()\n"); - /* FIXME: perhaps some code should go here that disables error - * reporting if we just enabled it - */ + /* Disable error reporting if we just enabled it */ + if (pvt->enabled_error_reporting) + i7300_set_error_reporting(mci, false); goto fail1; } @@ -1134,6 +1143,7 @@ static int i7300_init_one(struct pci_dev *pdev, const struct pci_device_id *id) static void i7300_remove_one(struct pci_dev *pdev) { struct mem_ctl_info *mci; + struct i7300_pvt *pvt; char *tmp; edac_dbg(0, "\n"); @@ -1145,7 +1155,12 @@ static void i7300_remove_one(struct pci_dev *pdev) if (!mci) return; - tmp = ((struct i7300_pvt *)mci->pvt_info)->tmp_prt_buffer; + pvt = (struct i7300_pvt *)mci->pvt_info; + tmp = pvt->tmp_prt_buffer; + + /* Disable error reporting before unregistering device */ + if (pvt->enabled_error_reporting) + i7300_set_error_reporting(mci, false); /* retrieve references to resources, and free those resources */ i7300_put_devices(mci); From dfe7d89d200b08f8387ca224039495b210272e28 Mon Sep 17 00:00:00 2001 From: Tushar Tibude Date: Thu, 30 Apr 2026 14:12:21 +0530 Subject: [PATCH 04/22] EDAC/i5000: disable error reporting at teardown and refactor helper If error reporting is enabled during initialization but initialization fails immediately after, or during normal driver teardown, error reporting is left enabled in the mask register even after exit. Replace i5000_enable_error_reporting() with i5000_set_error_reporting() to combine enabling/disabling. Disable reporting at initialization failure and driver exit, before call to i5000_put_devices() for cleanup. This ensures clean hardware handling by disabling any unused error reporting bits before exiting. Signed-off-by: Tushar Tibude Signed-off-by: Tony Luck Reviewed-by: Qiuxu Zhuo Link: https://patch.msgid.link/20260430084223.9298-2-tushar.tibude1000@gmail.com --- drivers/edac/i5000_edac.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c index 471b8540d18b..c0faf55f7812 100644 --- a/drivers/edac/i5000_edac.c +++ b/drivers/edac/i5000_edac.c @@ -352,6 +352,9 @@ struct i5000_pvt { /* Actual values for this controller */ int maxch; /* Max channels */ int maxdimmperch; /* Max DIMMs per channel */ + + /* Hardware error reporting status */ + bool enabled_error_reporting; }; /* I5000 MCH error information retrieved from Hardware */ @@ -1302,10 +1305,10 @@ static int i5000_init_csrows(struct mem_ctl_info *mci) } /* - * i5000_enable_error_reporting - * Turn on the memory reporting features of the hardware + * i5000_set_error_reporting + * Turn on/off the memory reporting features of the hardware */ -static void i5000_enable_error_reporting(struct mem_ctl_info *mci) +static void i5000_set_error_reporting(struct mem_ctl_info *mci, bool enable) { struct i5000_pvt *pvt; u32 fbd_error_mask; @@ -1316,8 +1319,11 @@ static void i5000_enable_error_reporting(struct mem_ctl_info *mci) pci_read_config_dword(pvt->branchmap_werrors, EMASK_FBD, &fbd_error_mask); - /* Enable with a '0' */ - fbd_error_mask &= ~(ENABLE_EMASK_ALL); + /* Enable with 0, disable with 1 */ + if (enable) + fbd_error_mask &= ~(ENABLE_EMASK_ALL); + else + fbd_error_mask |= ENABLE_EMASK_ALL; pci_write_config_dword(pvt->branchmap_werrors, EMASK_FBD, fbd_error_mask); @@ -1435,17 +1441,19 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx) if (i5000_init_csrows(mci)) { edac_dbg(0, "MC: Setting mci->edac_cap to EDAC_FLAG_NONE because i5000_init_csrows() returned nonzero value\n"); mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */ + pvt->enabled_error_reporting = false; } else { edac_dbg(1, "MC: Enable error reporting now\n"); - i5000_enable_error_reporting(mci); + i5000_set_error_reporting(mci, true); + pvt->enabled_error_reporting = true; } /* add this new MC control structure to EDAC's list of MCs */ if (edac_mc_add_mc(mci)) { edac_dbg(0, "MC: failed edac_mc_add_mc()\n"); - /* FIXME: perhaps some code should go here that disables error - * reporting if we just enabled it - */ + /* Disable error reporting if we previously enabled it */ + if (pvt->enabled_error_reporting) + i5000_set_error_reporting(mci, false); goto fail1; } @@ -1503,6 +1511,7 @@ static int i5000_init_one(struct pci_dev *pdev, const struct pci_device_id *id) static void i5000_remove_one(struct pci_dev *pdev) { struct mem_ctl_info *mci; + struct i5000_pvt *pvt; edac_dbg(0, "\n"); @@ -1512,6 +1521,12 @@ static void i5000_remove_one(struct pci_dev *pdev) if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) return; + pvt = mci->pvt_info; + + /* Disable error reporting on teardown */ + if (pvt->enabled_error_reporting) + i5000_set_error_reporting(mci, false); + /* retrieve references to resources, and free those resources */ i5000_put_devices(mci); edac_mc_free(mci); From 2951f7bc4e8a6514112f365a971b8606824361b6 Mon Sep 17 00:00:00 2001 From: Tushar Tibude Date: Thu, 30 Apr 2026 14:12:22 +0530 Subject: [PATCH 05/22] EDAC/i5100: disable error reporting at teardown and create helper Error reporting is enabled during init but not reverted when init fails. It is also not disabled at normal driver teardown. Create i5100_set_error_reporting() to enable/disable reporting. Move enable reporting write to after initialization success. Disable reporting at driver teardown. Signed-off-by: Tushar Tibude Signed-off-by: Tony Luck Reviewed-by: Qiuxu Zhuo Link: https://patch.msgid.link/20260430084223.9298-3-tushar.tibude1000@gmail.com --- drivers/edac/i5100_edac.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c index d470afe65001..d30919ceb22b 100644 --- a/drivers/edac/i5100_edac.c +++ b/drivers/edac/i5100_edac.c @@ -859,6 +859,21 @@ static void i5100_init_csrows(struct mem_ctl_info *mci) } } +static void i5100_set_error_reporting(struct pci_dev *pdev, bool enable) +{ + u32 dw; + + pci_read_config_dword(pdev, I5100_EMASK_MEM, &dw); + + /* Enable with 0, disable with 1 */ + if (enable) + dw &= ~I5100_FERR_NF_MEM_ANY_MASK; + else + dw |= I5100_FERR_NF_MEM_ANY_MASK; + + pci_write_config_dword(pdev, I5100_EMASK_MEM, dw); +} + /**************************************************************************** * Error injection routines ****************************************************************************/ @@ -1004,11 +1019,6 @@ static int i5100_init_one(struct pci_dev *pdev, const struct pci_device_id *id) pci_read_config_dword(pdev, I5100_MS, &dw); ranksperch = !!(dw & (1 << 8)) * 2 + 4; - /* enable error reporting... */ - pci_read_config_dword(pdev, I5100_EMASK_MEM, &dw); - dw &= ~I5100_FERR_NF_MEM_ANY_MASK; - pci_write_config_dword(pdev, I5100_EMASK_MEM, dw); - /* device 21, func 0, Channel 0 Memory Map, Error Flag/Mask, etc... */ ch0mm = pci_get_device_func(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5100_21, 0); @@ -1125,6 +1135,9 @@ static int i5100_init_one(struct pci_dev *pdev, const struct pci_device_id *id) i5100_setup_debugfs(mci); + /* Enable error reporting on success */ + i5100_set_error_reporting(pdev, true); + return ret; bail_scrub: @@ -1169,6 +1182,9 @@ static void i5100_remove_one(struct pci_dev *pdev) priv = mci->pvt_info; + /* Disable error reporting at teardown */ + i5100_set_error_reporting(pdev, false); + edac_debugfs_remove_recursive(priv->debugfs); priv->scrub_enable = 0; From 0dc6ed85303e691dc657607cee6b68be5ade3988 Mon Sep 17 00:00:00 2001 From: Tushar Tibude Date: Thu, 30 Apr 2026 14:12:23 +0530 Subject: [PATCH 06/22] EDAC/i5400: disable error reporting at teardown and refactor helper If error reporting is enabled during initialization but initialization fails immediately after, or during normal driver teardown, error reporting is left enabled in the mask register even after exit. Replace i5400_enable_error_reporting() with i5400_set_error_reporting() to combine enabling/disabling. Disable reporting at initialization failure and driver exit, before call to i5400_put_devices() for cleanup. This ensures clean hardware handling by disabling any unused error reporting bits before exiting. Signed-off-by: Tushar Tibude Signed-off-by: Tony Luck Reviewed-by: Qiuxu Zhuo Link: https://patch.msgid.link/20260430084223.9298-4-tushar.tibude1000@gmail.com --- drivers/edac/i5400_edac.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c index fb49a1d1df11..ae4f9298952d 100644 --- a/drivers/edac/i5400_edac.c +++ b/drivers/edac/i5400_edac.c @@ -353,6 +353,9 @@ struct i5400_pvt { /* Actual values for this controller */ int maxch; /* Max channels */ int maxdimmperch; /* Max DIMMs per channel */ + + /* Hardware error reporting status */ + bool enabled_error_reporting; }; /* I5400 MCH error information retrieved from Hardware */ @@ -1223,10 +1226,10 @@ static int i5400_init_dimms(struct mem_ctl_info *mci) } /* - * i5400_enable_error_reporting - * Turn on the memory reporting features of the hardware + * i5400_set_error_reporting + * Turn on/off the memory reporting features of the hardware */ -static void i5400_enable_error_reporting(struct mem_ctl_info *mci) +static void i5400_set_error_reporting(struct mem_ctl_info *mci, bool enable) { struct i5400_pvt *pvt; u32 fbd_error_mask; @@ -1237,8 +1240,11 @@ static void i5400_enable_error_reporting(struct mem_ctl_info *mci) pci_read_config_dword(pvt->branchmap_werrors, EMASK_FBD, &fbd_error_mask); - /* Enable with a '0' */ - fbd_error_mask &= ~(ENABLE_EMASK_ALL); + /* Enable with 0, disable with 1 */ + if (enable) + fbd_error_mask &= ~(ENABLE_EMASK_ALL); + else + fbd_error_mask |= ENABLE_EMASK_ALL; pci_write_config_dword(pvt->branchmap_werrors, EMASK_FBD, fbd_error_mask); @@ -1319,17 +1325,19 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx) if (i5400_init_dimms(mci)) { edac_dbg(0, "MC: Setting mci->edac_cap to EDAC_FLAG_NONE because i5400_init_dimms() returned nonzero value\n"); mci->edac_cap = EDAC_FLAG_NONE; /* no dimms found */ + pvt->enabled_error_reporting = false; } else { edac_dbg(1, "MC: Enable error reporting now\n"); - i5400_enable_error_reporting(mci); + i5400_set_error_reporting(mci, true); + pvt->enabled_error_reporting = true; } /* add this new MC control structure to EDAC's list of MCs */ if (edac_mc_add_mc(mci)) { edac_dbg(0, "MC: failed edac_mc_add_mc()\n"); - /* FIXME: perhaps some code should go here that disables error - * reporting if we just enabled it - */ + /* Disable error reporting if we just enabled it */ + if (pvt->enabled_error_reporting) + i5400_set_error_reporting(mci, false); goto fail1; } @@ -1387,6 +1395,7 @@ static int i5400_init_one(struct pci_dev *pdev, const struct pci_device_id *id) static void i5400_remove_one(struct pci_dev *pdev) { struct mem_ctl_info *mci; + struct i5400_pvt *pvt; edac_dbg(0, "\n"); @@ -1397,6 +1406,12 @@ static void i5400_remove_one(struct pci_dev *pdev) if (!mci) return; + pvt = mci->pvt_info; + + /* Disable error reporting on teardown */ + if (pvt->enabled_error_reporting) + i5400_set_error_reporting(mci, false); + /* retrieve references to resources, and free those resources */ i5400_put_devices(mci); From b0947c6d2464ce58a6a80548d2135f9e95d2aa02 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Fri, 8 May 2026 16:38:46 +0200 Subject: [PATCH 07/22] EDAC/sb_edac: fix grammar in sb_decode_ddr3 warning Fix the warning in sb_decode_ddr3() by adding the missing verb "is" and using "supported" instead of "support" to match the LockStep warning in sb_decode_ddr4(). Signed-off-by: Thorsten Blum Signed-off-by: Tony Luck Reviewed-by: Qiuxu Zhuo Link: https://patch.msgid.link/20260508143844.2996-3-thorsten.blum@linux.dev --- drivers/edac/sb_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 7b282dfd093f..35eb7a2038ab 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -2016,7 +2016,7 @@ static bool sb_decode_ddr4(struct mem_ctl_info *mci, int ch, u8 rank, static bool sb_decode_ddr3(struct mem_ctl_info *mci, int ch, u8 rank, u64 rank_addr, char *msg) { - pr_warn_once("DDR3 row/column decode not support yet!\n"); + pr_warn_once("DDR3 row/column decode is not supported yet!\n"); msg[0] = '\0'; return false; } From ab1f9d466c7d83ab0d2a529e07984e53b5960dcd Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Fri, 3 Apr 2026 13:40:27 +0800 Subject: [PATCH 08/22] EDAC/igen6: Fix call trace due to missing release() When unloading the igen6_edac driver, there is a call trace: Device '(null)' does not have a release() function, it is broken and must be fixed. See Documentation/core-api/kobject.rst. WARNING: drivers/base/core.c:2567 at device_release+0x84/0x90, CPU#5: rmmod/127209 ... RIP: 0010:device_release+0x84/0x90 Call Trace: kobject_put+0x8c/0x220 put_device+0x17/0x30 igen6_unregister_mcis+0xa2/0xe0 [igen6_edac] igen6_remove+0x82/0xb0 [igen6_edac] ... Fix the call trace by providing empty release() functions for the memory controller devices. Fixes: 10590a9d4f23 ("EDAC/igen6: Add EDAC driver for Intel client SoCs using IBECC") Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Link: https://patch.msgid.link/20260403054029.3950383-2-qiuxu.zhuo@intel.com --- drivers/edac/igen6_edac.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c index fcb8ab44cba5..0bf9cf349d0b 100644 --- a/drivers/edac/igen6_edac.c +++ b/drivers/edac/igen6_edac.c @@ -1296,6 +1296,11 @@ static bool igen6_imc_absent(void __iomem *window) return readl(window + MAD_INTER_CHANNEL_OFFSET) == ~0; } +static void imc_release(struct device *dev) +{ + /* Nothing to do, the 'imc' owns the 'dev' and will also release it. */ +} + static int igen6_register_mci(int mc, void __iomem *window, struct pci_dev *pdev) { struct edac_mc_layer layers[2]; @@ -1334,6 +1339,7 @@ static int igen6_register_mci(int mc, void __iomem *window, struct pci_dev *pdev mci->pvt_info = &igen6_pvt->imc[mc]; imc = mci->pvt_info; + imc->dev.release = imc_release; device_initialize(&imc->dev); /* * EDAC core uses mci->pdev(pointer of structure device) as From 114bfa24eacb688488caa2e459358a1b9b89b16d Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Fri, 3 Apr 2026 13:40:28 +0800 Subject: [PATCH 09/22] EDAC/igen6: Fix memory topology parsing for Panther Lake-H SoCs Panther Lake-H SoC memory controller registers for memory topology have been updated, but the current igen6_edac driver still uses old generation ones to incorrectly parse memory topology. Fix the issue by adding memory topology parsing function pointers to the 'struct res_config' and creating a new configuration structure for Panther Lake-H SoCs to enable igen6_edac to parse memory correctly. Fixes: 0be9f1af3902 ("EDAC/igen6: Add Intel Panther Lake-H SoCs support") Fixes: 4c36e6106997 ("EDAC/igen6: Add more Intel Panther Lake-H SoCs support") Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Link: https://patch.msgid.link/20260403054029.3950383-3-qiuxu.zhuo@intel.com --- drivers/edac/igen6_edac.c | 399 ++++++++++++++++++++++++++++++-------- include/linux/edac.h | 3 + 2 files changed, 320 insertions(+), 82 deletions(-) diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c index 0bf9cf349d0b..f849e3299593 100644 --- a/drivers/edac/igen6_edac.c +++ b/drivers/edac/igen6_edac.c @@ -122,33 +122,6 @@ #define MEM_SLICE_HASH_MASK(v) (GET_BITFIELD(v, 6, 19) << 6) #define MEM_SLICE_HASH_LSB_MASK_BIT(v) GET_BITFIELD(v, 24, 26) -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; - u32 ms_hash_offset; - u32 ibecc_base; - u32 ibecc_error_log_offset; - bool (*ibecc_available)(struct pci_dev *pdev); - /* Extract error address logged in IBECC */ - u64 (*err_addr)(u64 ecclog); - /* Convert error address logged in IBECC to system physical address */ - u64 (*err_addr_to_sys_addr)(u64 eaddr, int mc); - /* Convert error address logged in IBECC to integrated memory controller address */ - u64 (*err_addr_to_imc_addr)(u64 eaddr, int mc); -} *res_cfg; - struct igen6_imc { int mc; struct mem_ctl_info *mci; @@ -163,8 +136,53 @@ struct igen6_imc { int dimm_l_map[NUM_CHANNELS]; }; +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; + /* MEMSS_PMA_CR registers. */ + u32 reg_mem_config_offset; + u32 reg_mem_config_ddr_type_mask; + /* Memory controller registers. */ + u32 reg_mad_inter_size_mask[NUM_CHANNELS]; + u64 reg_mad_inter_size_granularity; + u32 reg_mad_intra_rank_mask[NUM_DIMMS]; + u32 reg_mad_intra_width_mask[NUM_DIMMS]; + u32 reg_mad_intra_density_mask[NUM_DIMMS]; + u32 imc_base; + u32 cmf_base; + u32 cmf_size; + u32 ms_hash_offset; + u32 ibecc_base; + u32 ibecc_error_log_offset; + /* Get memory type. */ + enum mem_type (*get_mem_type)(struct igen6_imc *imc); + /* Get DRAM chip type. */ + enum dev_type (*get_dev_type)(struct igen6_imc *imc, int chan, int dimm_l); + /* Set imc->ch_{s_size,l_map}. */ + void (*set_chan_params)(struct igen6_imc *imc); + /* Set imc->dimm_{l_size,s_size,l_map}[chan]. */ + void (*set_dimm_params)(struct igen6_imc *imc, int chan); + bool (*ibecc_available)(struct pci_dev *pdev); + /* Extract error address logged in IBECC */ + u64 (*err_addr)(u64 ecclog); + /* Convert error address logged in IBECC to system physical address */ + u64 (*err_addr_to_sys_addr)(u64 eaddr, int mc); + /* Convert error address logged in IBECC to integrated memory controller address */ + u64 (*err_addr_to_imc_addr)(u64 eaddr, int mc); +} *res_cfg; + static struct igen6_pvt { struct igen6_imc imc[NUM_IMC]; + void __iomem *memss_pma_cr; u64 ms_hash; u64 ms_s_size; int ms_l_map; @@ -500,6 +518,119 @@ static u64 rpl_p_err_addr(u64 ecclog) return field_get(res_cfg->reg_eccerrlog_addr_mask, ecclog); } +static enum mem_type ptl_h_get_mem_type(struct igen6_imc *imc) +{ + u32 mtype, val; + + val = readl(igen6_pvt->memss_pma_cr + res_cfg->reg_mem_config_offset); + mtype = field_get(res_cfg->reg_mem_config_ddr_type_mask, val); + + edac_dbg(2, "mtype %u (reg 0x%x)\n", mtype, val); + + switch (mtype) { + case 1: + return MEM_DDR5; + case 2: + return MEM_LPDDR5; + case 3: + return MEM_LPDDR4; + default: + return MEM_UNKNOWN; + } +} + +static enum dev_type ptl_h_get_dev_type(struct igen6_imc *imc, int chan, int dimm) +{ + u32 width, val; + + val = readl(imc->window + MAD_INTRA_CH0_OFFSET + chan * 4); + width = field_get(res_cfg->reg_mad_intra_width_mask[dimm], val); + + switch (width) { + case 1: + return DEV_X8; + default: + return DEV_X16; + } +} + +static u64 ptl_h_get_chan_size(struct igen6_imc *imc, int chan) +{ + u32 val = readl(imc->window + MAD_INTER_CHANNEL_OFFSET); + + return field_get(res_cfg->reg_mad_inter_size_mask[chan], val) * + res_cfg->reg_mad_inter_size_granularity; +} + +static u64 ptl_h_get_dimm_size(struct igen6_imc *imc, int chan, int dimm) +{ + u32 val = readl(imc->window + MAD_INTRA_CH0_OFFSET + chan * 4); + u32 ranks = 1 << field_get(res_cfg->reg_mad_intra_rank_mask[dimm], val); + /* DRAM device density in Gb */ + u64 density = field_get(res_cfg->reg_mad_intra_density_mask[dimm], val) * 4; + + enum mem_type mtype = ptl_h_get_mem_type(imc); + enum dev_type dtype = ptl_h_get_dev_type(imc, chan, dimm); + u64 sub_ch_width, dev_num; + + switch (mtype) { + case MEM_DDR5: + sub_ch_width = 32; + break; + case MEM_LPDDR5: + case MEM_LPDDR4: + sub_ch_width = 16; + break; + default: + sub_ch_width = 0; + } + + switch (dtype) { + case DEV_X8: + dev_num = sub_ch_width / 8; + break; + case DEV_X16: + dev_num = sub_ch_width / 16; + break; + default: + dev_num = 0; + } + + edac_dbg(2, "ranks %d, density %lluGb, sub_ch_width %llu, dev_num %llu (reg 0x%x)\n", ranks, density, sub_ch_width, dev_num, val); + + return ((dev_num * density / 8) * ranks) << 30; +} + +static void ptl_h_set_chan_params(struct igen6_imc *imc) +{ + u64 ch0_size = ptl_h_get_chan_size(imc, 0); + u64 ch1_size = ptl_h_get_chan_size(imc, 1); + + if (ch0_size <= ch1_size) { + imc->ch_s_size = ch0_size; + imc->ch_l_map = 1; + } else { + imc->ch_s_size = ch1_size; + imc->ch_l_map = 0; + } +} + +static void ptl_h_set_dimm_params(struct igen6_imc *imc, int chan) +{ + u64 dimm0_size = ptl_h_get_dimm_size(imc, chan, 0); + u64 dimm1_size = ptl_h_get_dimm_size(imc, chan, 1); + + if (dimm0_size <= dimm1_size) { + imc->dimm_s_size[chan] = dimm0_size; + imc->dimm_l_size[chan] = dimm1_size; + imc->dimm_l_map[chan] = 1; + } else { + imc->dimm_s_size[chan] = dimm1_size; + imc->dimm_l_size[chan] = dimm0_size; + imc->dimm_l_map[chan] = 0; + } +} + static struct res_config ehl_cfg = { .num_imc = 1, .reg_mchbar_mask = GENMASK_ULL(38, 16), @@ -622,6 +753,36 @@ static struct res_config mtl_p_cfg = { .err_addr_to_imc_addr = adl_err_addr_to_imc_addr, }; +static struct res_config ptl_h_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), + .reg_mem_config_offset = 0x13d04, + .reg_mem_config_ddr_type_mask = GENMASK(8, 6), + .reg_mad_inter_size_mask[0] = GENMASK(15, 8), + .reg_mad_inter_size_mask[1] = GENMASK(23, 16), + .reg_mad_inter_size_granularity = BIT_ULL(29), + .reg_mad_intra_rank_mask[0] = BIT(7), + .reg_mad_intra_rank_mask[1] = BIT(15), + .reg_mad_intra_width_mask[0] = BIT(6), + .reg_mad_intra_width_mask[1] = BIT(14), + .reg_mad_intra_density_mask[0] = GENMASK(3, 0), + .reg_mad_intra_density_mask[1] = GENMASK(11, 8), + .imc_base = 0xd800, + .ibecc_base = 0xd400, + .ibecc_error_log_offset = 0x170, + .get_mem_type = ptl_h_get_mem_type, + .get_dev_type = ptl_h_get_dev_type, + .set_chan_params = ptl_h_set_chan_params, + .set_dimm_params = ptl_h_set_dimm_params, + .ibecc_available = mtl_p_ibecc_available, + .err_addr_to_sys_addr = adl_err_addr_to_sys_addr, + .err_addr_to_imc_addr = adl_err_addr_to_imc_addr, +}; + static struct res_config wcl_cfg = { .machine_check = true, .num_imc = 1, @@ -689,46 +850,34 @@ static struct pci_device_id igen6_pci_tbl[] = { { PCI_VDEVICE(INTEL, DID_ARL_UH_SKU1), (kernel_ulong_t)&mtl_p_cfg }, { PCI_VDEVICE(INTEL, DID_ARL_UH_SKU2), (kernel_ulong_t)&mtl_p_cfg }, { PCI_VDEVICE(INTEL, DID_ARL_UH_SKU3), (kernel_ulong_t)&mtl_p_cfg }, - { 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_PTL_H_SKU1), (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU2), (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU3), (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU4), (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU5), (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU6), (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU7), (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU8), (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU9), (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU10), (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU11), (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU12), (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU13), (kernel_ulong_t)&ptl_h_cfg }, { PCI_VDEVICE(INTEL, DID_WCL_SKU1), (kernel_ulong_t)&wcl_cfg }, { }, }; MODULE_DEVICE_TABLE(pci, igen6_pci_tbl); -static enum dev_type get_width(int dimm_l, u32 mad_dimm) +static enum mem_type get_mem_type(struct igen6_imc *imc) { - u32 w = dimm_l ? MAD_DIMM_CH_DLW(mad_dimm) : - MAD_DIMM_CH_DSW(mad_dimm); + u32 val; - switch (w) { - case 0: - return DEV_X8; - case 1: - return DEV_X16; - case 2: - return DEV_X32; - default: - return DEV_UNKNOWN; - } -} + if (res_cfg->get_mem_type) + return res_cfg->get_mem_type(imc); -static enum mem_type get_memory_type(u32 mad_inter) -{ - u32 t = MAD_INTER_CHANNEL_DDR_TYPE(mad_inter); + val = readl(imc->window + MAD_INTER_CHANNEL_OFFSET); - switch (t) { + switch (MAD_INTER_CHANNEL_DDR_TYPE(val)) { case 0: return MEM_DDR4; case 1: @@ -744,6 +893,73 @@ static enum mem_type get_memory_type(u32 mad_inter) } } +static bool large_dimm(struct igen6_imc *imc, int chan, int dimm) +{ + return dimm == imc->dimm_l_map[chan]; +} + +static enum dev_type get_dev_type(struct igen6_imc *imc, int chan, int dimm) +{ + u32 width, val; + + if (res_cfg->get_dev_type) + return res_cfg->get_dev_type(imc, chan, dimm); + + val = readl(imc->window + MAD_DIMM_CH0_OFFSET + chan * 4); + width = large_dimm(imc, chan, dimm) ? MAD_DIMM_CH_DLW(val) : + MAD_DIMM_CH_DSW(val); + + switch (width) { + case 0: + return DEV_X8; + case 1: + return DEV_X16; + case 2: + return DEV_X32; + default: + return DEV_UNKNOWN; + } +} + +static u64 get_dimm_size(struct igen6_imc *imc, int chan, int dimm) +{ + if (large_dimm(imc, chan, dimm)) + return imc->dimm_l_size[chan]; + + return imc->dimm_s_size[chan]; +} + +static void set_chan_params(struct igen6_imc *imc) +{ + u32 val; + + if (res_cfg->set_chan_params) { + res_cfg->set_chan_params(imc); + return; + } + + val = readl(imc->window + MAD_INTER_CHANNEL_OFFSET); + imc->ch_s_size = MAD_INTER_CHANNEL_CH_S_SIZE(val); + imc->ch_l_map = MAD_INTER_CHANNEL_CH_L_MAP(val); +} + +static void set_dimm_params(struct igen6_imc *imc, int chan) +{ + u32 val; + + if (res_cfg->set_dimm_params) { + res_cfg->set_dimm_params(imc, chan); + return; + } + + val = readl(imc->window + MAD_INTRA_CH0_OFFSET + chan * 4); + imc->dimm_l_map[chan] = MAD_INTRA_CH_DIMM_L_MAP(val); + + val = readl(imc->window + MAD_DIMM_CH0_OFFSET + chan * 4); + imc->dimm_l_size[chan] = MAD_DIMM_CH_DIMM_L_SIZE(val); + imc->dimm_s_size[chan] = MAD_DIMM_CH_DIMM_S_SIZE(val); +} + static int decode_chan_idx(u64 addr, u64 mask, int intlv_bit) { u64 hash_addr = addr & mask, hash = 0; @@ -1084,7 +1300,6 @@ static bool igen6_check_ecc(struct igen6_imc *imc) static int igen6_get_dimm_config(struct mem_ctl_info *mci) { struct igen6_imc *imc = mci->pvt_info; - u32 mad_inter, mad_intra, mad_dimm; int i, j, ndimms, mc = imc->mc; struct dimm_info *dimm; enum mem_type mtype; @@ -1094,33 +1309,20 @@ static int igen6_get_dimm_config(struct mem_ctl_info *mci) edac_dbg(2, "\n"); - mad_inter = readl(imc->window + MAD_INTER_CHANNEL_OFFSET); - mtype = get_memory_type(mad_inter); + mtype = get_mem_type(imc); ecc = igen6_check_ecc(imc); - imc->ch_s_size = MAD_INTER_CHANNEL_CH_S_SIZE(mad_inter); - imc->ch_l_map = MAD_INTER_CHANNEL_CH_L_MAP(mad_inter); + set_chan_params(imc); for (i = 0; i < NUM_CHANNELS; i++) { - mad_intra = readl(imc->window + MAD_INTRA_CH0_OFFSET + i * 4); - mad_dimm = readl(imc->window + MAD_DIMM_CH0_OFFSET + i * 4); - - imc->dimm_l_size[i] = MAD_DIMM_CH_DIMM_L_SIZE(mad_dimm); - imc->dimm_s_size[i] = MAD_DIMM_CH_DIMM_S_SIZE(mad_dimm); - imc->dimm_l_map[i] = MAD_INTRA_CH_DIMM_L_MAP(mad_intra); + set_dimm_params(imc, i); imc->size += imc->dimm_s_size[i]; imc->size += imc->dimm_l_size[i]; ndimms = 0; for (j = 0; j < NUM_DIMMS; j++) { dimm = edac_get_dimm(mci, i, j, 0); - - if (j ^ imc->dimm_l_map[i]) { - dtype = get_width(0, mad_dimm); - dsize = imc->dimm_s_size[i]; - } else { - dtype = get_width(1, mad_dimm); - dsize = imc->dimm_l_size[i]; - } + dtype = get_dev_type(imc, i, j); + dsize = get_dimm_size(imc, i, j); if (!dsize) continue; @@ -1223,6 +1425,39 @@ static void igen6_debug_setup(void) {} static void igen6_debug_teardown(void) {} #endif +static struct igen6_pvt *igen6_pvt_setup(struct pci_dev *pdev) +{ + void __iomem *memss_pma_cr; + struct igen6_pvt *pvt; + u64 mchbar; + int rc; + + pvt = kzalloc_obj(*igen6_pvt); + if (!pvt) + return NULL; + + rc = get_mchbar(pdev, &mchbar); + if (rc) { + kfree(pvt); + return NULL; + } + + memss_pma_cr = ioremap(mchbar, MCHBAR_SIZE * 2); + if (!memss_pma_cr) { + kfree(pvt); + return NULL; + } + pvt->memss_pma_cr = memss_pma_cr; + + return pvt; +} + +static void igen6_pvt_release(struct igen6_pvt *pvt) +{ + iounmap(pvt->memss_pma_cr); + kfree(pvt); +} + static int igen6_pci_setup(struct pci_dev *pdev, u64 *mchbar) { union { @@ -1555,12 +1790,12 @@ static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent) edac_dbg(2, "\n"); - igen6_pvt = kzalloc_obj(*igen6_pvt); + res_cfg = (struct res_config *)ent->driver_data; + + igen6_pvt = igen6_pvt_setup(pdev); if (!igen6_pvt) return -ENOMEM; - res_cfg = (struct res_config *)ent->driver_data; - rc = igen6_pci_setup(pdev, &mchbar); if (rc) goto fail; @@ -1609,7 +1844,7 @@ static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent) fail2: igen6_unregister_mcis(); fail: - kfree(igen6_pvt); + igen6_pvt_release(igen6_pvt); return rc; } @@ -1624,7 +1859,7 @@ static void igen6_remove(struct pci_dev *pdev) flush_work(&ecclog_work); gen_pool_destroy(ecclog_pool); igen6_unregister_mcis(); - kfree(igen6_pvt); + igen6_pvt_release(igen6_pvt); } static struct pci_driver igen6_driver = { diff --git a/include/linux/edac.h b/include/linux/edac.h index deba46b3ee25..e6b4e51130e5 100644 --- a/include/linux/edac.h +++ b/include/linux/edac.h @@ -184,6 +184,7 @@ static inline char *mc_event_error_type(const unsigned int err_type) * @MEM_DDR5: Unbuffered DDR5 RAM * @MEM_RDDR5: Registered DDR5 RAM * @MEM_LRDDR5: Load-Reduced DDR5 memory. + * @MEM_LPDDR5: Low-Power DDR5 memory. * @MEM_NVDIMM: Non-volatile RAM * @MEM_WIO2: Wide I/O 2. * @MEM_HBM2: High bandwidth Memory Gen 2. @@ -216,6 +217,7 @@ enum mem_type { MEM_DDR5, MEM_RDDR5, MEM_LRDDR5, + MEM_LPDDR5, MEM_NVDIMM, MEM_WIO2, MEM_HBM2, @@ -247,6 +249,7 @@ enum mem_type { #define MEM_FLAG_DDR5 BIT(MEM_DDR5) #define MEM_FLAG_RDDR5 BIT(MEM_RDDR5) #define MEM_FLAG_LRDDR5 BIT(MEM_LRDDR5) +#define MEM_FLAG_LPDDR5 BIT(MEM_LPDDR5) #define MEM_FLAG_NVDIMM BIT(MEM_NVDIMM) #define MEM_FLAG_WIO2 BIT(MEM_WIO2) #define MEM_FLAG_HBM2 BIT(MEM_HBM2) From d9b75e35503959a81ab175a40b9690b7c9da34a0 Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Fri, 3 Apr 2026 13:40:29 +0800 Subject: [PATCH 10/22] EDAC/igen6: Add one Intel Panther Lake-H SoC support Add one Intel Panther Lake-H SoC compute die ID for EDAC support. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Link: https://patch.msgid.link/20260403054029.3950383-4-qiuxu.zhuo@intel.com --- drivers/edac/igen6_edac.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c index f849e3299593..f3e53d63eb54 100644 --- a/drivers/edac/igen6_edac.c +++ b/drivers/edac/igen6_edac.c @@ -309,6 +309,7 @@ static struct work_struct ecclog_work; #define DID_PTL_H_SKU11 0xb028 #define DID_PTL_H_SKU12 0xb029 #define DID_PTL_H_SKU13 0xb02a +#define DID_PTL_H_SKU14 0xb00a /* Compute die IDs for Wildcat Lake with IBECC */ #define DID_WCL_SKU1 0xfd00 @@ -863,6 +864,7 @@ static struct pci_device_id igen6_pci_tbl[] = { { PCI_VDEVICE(INTEL, DID_PTL_H_SKU11), (kernel_ulong_t)&ptl_h_cfg }, { PCI_VDEVICE(INTEL, DID_PTL_H_SKU12), (kernel_ulong_t)&ptl_h_cfg }, { PCI_VDEVICE(INTEL, DID_PTL_H_SKU13), (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU14), (kernel_ulong_t)&ptl_h_cfg }, { PCI_VDEVICE(INTEL, DID_WCL_SKU1), (kernel_ulong_t)&wcl_cfg }, { }, }; From c63ed6e1f5fe648a4a099b6717f679999be482ef Mon Sep 17 00:00:00 2001 From: zhoumin Date: Thu, 26 Mar 2026 17:14:03 +0800 Subject: [PATCH 11/22] EDAC/{skx_common,skx}: Fix UBSAN shift-out-of-bounds in skx_get_dimm_info When the skx_get_dimm_attr() helper returns -EINVAL, skx_get_dimm_info() does not validate these return values before using them in a shift operation: size = ((1ull << (rows + cols + ranks)) * banks) >> (20 - 3); If all three values are -22, the shift exponent becomes -66, triggering a UBSAN shift-out-of-bounds error: UBSAN: shift-out-of-bounds in drivers/edac/skx_common.c shift exponent -66 is negative Fixes: 88a242c98740 ("EDAC, skx_common: Separate common code out from skx_edac") Signed-off-by: zhoumin Signed-off-by: Tony Luck Link: https://patch.msgid.link/tencent_2A0CC835A18366643CBD2865B169948AB409@qq.com --- drivers/edac/skx_common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c index a9557c8344bc..f15de0ea96c8 100644 --- a/drivers/edac/skx_common.c +++ b/drivers/edac/skx_common.c @@ -466,6 +466,9 @@ int skx_get_dimm_info(u32 mtr, u32 mcmtr, u32 amap, struct dimm_info *dimm, rows = numrow(mtr); cols = imc->hbm_mc ? 6 : numcol(mtr); + if (ranks < 0 || rows < 0 || cols < 0) + return 0; + if (imc->hbm_mc) { banks = 32; mtype = MEM_HBM2; From bebda0aba2cf64271ded37746c48f9ab6652ca31 Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Thu, 21 May 2026 15:31:05 +0800 Subject: [PATCH 12/22] EDAC/{skx_common,i10nm,imh}: Move MC register access helpers to skx_common Both i10nm_basic.c and imh_basic.c use identical helpers for accessing memory controller MMIO-based registers. Move these helpers to skx_common.c to eliminate code duplication. This change also prepares for an upcoming patch that will move RRL(retry_rd_err_log) code from i10nm_basic.c to skx_common.c, which requires these helpers to be available in skx_common.c. Additionally, prefix these function names with 'skx_' to maintain naming consistency within the file. No functional changes intended. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Tested-by: Yi Lai Link: https://patch.msgid.link/20260521073112.3881223-2-qiuxu.zhuo@intel.com --- drivers/edac/i10nm_base.c | 39 ++++-------------------------- drivers/edac/imh_base.c | 33 ++++---------------------- drivers/edac/skx_common.c | 50 +++++++++++++++++++++++++++++++++++++++ drivers/edac/skx_common.h | 3 +++ 4 files changed, 63 insertions(+), 62 deletions(-) diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c index de6c52dbd9d2..0a0236583eb7 100644 --- a/drivers/edac/i10nm_base.c +++ b/drivers/edac/i10nm_base.c @@ -47,12 +47,6 @@ readl((m)->mbase + ((m)->hbm_mc ? 0xef8 : \ (res_cfg->type == GNR ? 0xaf8 : 0x20ef8)) + \ (i) * (m)->chan_mmio_sz) -#define I10NM_GET_REG32(m, i, offset) \ - readl((m)->mbase + (i) * (m)->chan_mmio_sz + (offset)) -#define I10NM_GET_REG64(m, i, offset) \ - readq((m)->mbase + (i) * (m)->chan_mmio_sz + (offset)) -#define I10NM_SET_REG32(m, i, offset, v) \ - writel(v, (m)->mbase + (i) * (m)->chan_mmio_sz + (offset)) #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) @@ -189,29 +183,6 @@ static struct reg_rrl gnr_reg_rrl_ddr = { .cecnt_widths = {4, 4, 4, 4, 4, 4, 4, 4}, }; -static u64 read_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width) -{ - switch (width) { - case 4: - return I10NM_GET_REG32(imc, chan, offset); - case 8: - return I10NM_GET_REG64(imc, chan, offset); - default: - i10nm_printk(KERN_ERR, "Invalid read RRL 0x%x width %d\n", offset, width); - return 0; - } -} - -static void write_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width, u64 val) -{ - switch (width) { - case 4: - return I10NM_SET_REG32(imc, chan, offset, (u32)val); - default: - i10nm_printk(KERN_ERR, "Invalid write RRL 0x%x width %d\n", offset, width); - } -} - static void enable_rrl(struct skx_imc *imc, int chan, struct reg_rrl *rrl, int rrl_set, bool enable, u32 *rrl_ctl) { @@ -225,7 +196,7 @@ static void enable_rrl(struct skx_imc *imc, int chan, struct reg_rrl *rrl, /* Patrol scrub or on-demand read error. */ scrub = (mode == FRE_SCRUB || mode == LRE_SCRUB); - v = read_imc_reg(imc, chan, offset, width); + v = skx_read_imc_reg(imc, chan, offset, width); if (enable) { /* Save default configurations. */ @@ -268,7 +239,7 @@ static void enable_rrl(struct skx_imc *imc, int chan, struct reg_rrl *rrl, v &= ~rrl->en_mask; } - write_imc_reg(imc, chan, offset, width, v); + skx_write_imc_reg(imc, chan, offset, width, v); } static void enable_rrls(struct skx_imc *imc, int chan, struct reg_rrl *rrl, @@ -354,7 +325,7 @@ static void show_retry_rd_err_log(struct decoded_addr *res, char *msg, for (j = 0; j < rrl->reg_num && len - n > 0; j++) { offset = rrl->offsets[i][j]; width = rrl->widths[j]; - log = read_imc_reg(imc, ch, offset, width); + log = skx_read_imc_reg(imc, ch, offset, width); if (width == 4) n += scnprintf(msg + n, len - n, "%.8llx ", log); @@ -363,7 +334,7 @@ static void show_retry_rd_err_log(struct decoded_addr *res, char *msg, /* Clear RRL status if RRL in Linux control mode. */ if (retry_rd_err_log == 2 && !j && (log & status_mask)) - write_imc_reg(imc, ch, offset, width, log & ~status_mask); + skx_write_imc_reg(imc, ch, offset, width, log & ~status_mask); } } @@ -376,7 +347,7 @@ static void show_retry_rd_err_log(struct decoded_addr *res, char *msg, for (i = 0; i < rrl->cecnt_num && len - n > 0; i++) { offset = rrl->cecnt_offsets[i]; width = rrl->cecnt_widths[i]; - corr = read_imc_reg(imc, ch, offset, width); + corr = skx_read_imc_reg(imc, ch, offset, width); /* CPUs {ICX,SPR} encode two counters per 4-byte CORRERRCNT register. */ if (res_cfg->type <= SPR) { diff --git a/drivers/edac/imh_base.c b/drivers/edac/imh_base.c index 40082ba45e62..dfdcfa127ce7 100644 --- a/drivers/edac/imh_base.c +++ b/drivers/edac/imh_base.c @@ -71,28 +71,11 @@ struct local_reg { .width = (cfg)->ip_name##_reg_##reg_name##_width, \ } -static u64 readx(void __iomem *addr, u8 width) -{ - switch (width) { - case 1: - return readb(addr); - case 2: - return readw(addr); - case 4: - return readl(addr); - case 8: - return readq(addr); - default: - imh_printk(KERN_ERR, "Invalid reg 0x%p width %d\n", addr, width); - return 0; - } -} - static void __read_local_reg(void *reg) { struct local_reg *r = (struct local_reg *)reg; - r->val = readx(r->vbase + r->offset, r->width); + r->val = skx_readx(r->vbase + r->offset, r->width); } /* Read a local-view register. */ @@ -378,22 +361,16 @@ static bool imh_2lm_enabled(struct res_config *cfg, struct list_head *head) return false; } -/* Helpers to read memory controller registers */ -static u64 read_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width) -{ - return readx(imc->mbase + imc->chan_mmio_sz * chan + offset, width); -} - static u32 read_imc_mcmtr(struct res_config *cfg, struct skx_imc *imc, int chan) { - return (u32)read_imc_reg(imc, chan, cfg->ddr_reg_mcmtr_offset, cfg->ddr_reg_mcmtr_width); + return (u32)skx_read_imc_reg(imc, chan, cfg->ddr_reg_mcmtr_offset, cfg->ddr_reg_mcmtr_width); } static u32 read_imc_dimmmtr(struct res_config *cfg, struct skx_imc *imc, int chan, int dimm) { - return (u32)read_imc_reg(imc, chan, cfg->ddr_reg_dimmmtr_offset + - cfg->ddr_reg_dimmmtr_width * dimm, - cfg->ddr_reg_dimmmtr_width); + return (u32)skx_read_imc_reg(imc, chan, cfg->ddr_reg_dimmmtr_offset + + cfg->ddr_reg_dimmmtr_width * dimm, + cfg->ddr_reg_dimmmtr_width); } static bool ecc_enabled(u32 mcmtr) diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c index f15de0ea96c8..1c4cc21679bc 100644 --- a/drivers/edac/skx_common.c +++ b/drivers/edac/skx_common.c @@ -52,6 +52,56 @@ static LIST_HEAD(dev_edac_list); static bool skx_mem_cfg_2lm; static struct res_config *skx_res_cfg; +u64 skx_readx(void __iomem *addr, u8 width) +{ + switch (width) { + case 1: + return readb(addr); + case 2: + return readw(addr); + case 4: + return readl(addr); + case 8: + return readq(addr); + default: + skx_printk(KERN_ERR, "Invalid reg 0x%p width %u to read.\n", addr, width); + return 0; + } +} +EXPORT_SYMBOL_GPL(skx_readx); + +static void skx_writex(void __iomem *addr, u8 width, u64 val) +{ + switch (width) { + case 1: + writeb((u8)val, addr); + return; + case 2: + writew((u16)val, addr); + return; + case 4: + writel((u32)val, addr); + return; + case 8: + writeq(val, addr); + return; + default: + skx_printk(KERN_ERR, "Invalid reg 0x%p width %u to write 0x%llx.\n", addr, width, val); + } +} + +u64 skx_read_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width) +{ + return skx_readx(imc->mbase + imc->chan_mmio_sz * chan + offset, width); +} +EXPORT_SYMBOL_GPL(skx_read_imc_reg); + +void skx_write_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width, u64 val) +{ + skx_writex(imc->mbase + imc->chan_mmio_sz * chan + offset, width, val); +} +EXPORT_SYMBOL_GPL(skx_write_imc_reg); + int skx_adxl_get(void) { const char * const *names; diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h index f88038e5b18c..95412459a84f 100644 --- a/drivers/edac/skx_common.h +++ b/drivers/edac/skx_common.h @@ -326,6 +326,9 @@ typedef int (*get_dimm_config_f)(struct mem_ctl_info *mci, typedef bool (*skx_decode_f)(struct decoded_addr *res); typedef void (*skx_show_retry_log_f)(struct decoded_addr *res, char *msg, int len, bool scrub_err); +u64 skx_readx(void __iomem *addr, u8 width); +u64 skx_read_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width); +void skx_write_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width, u64 val); int skx_adxl_get(void); void skx_adxl_put(void); void skx_set_decode(skx_decode_f decode, skx_show_retry_log_f show_retry_log); From bb7902db79dd423085474febb1f2aaeb105b9447 Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Thu, 21 May 2026 15:31:06 +0800 Subject: [PATCH 13/22] EDAC/{skx_common,skx,i10nm}: Split skx_set_decode() skx_set_decode() currently handles both address decoding and Retry Read error Log (RRL) reporting, coupling two independent functions in a single API. This complicates setup/teardown and forces callers to update unrelated state. Introduce skx_set_show_rrl() and keep skx_set_decode() focused on decode setup, allowing decode and RRL handling to be managed independently. Also rename the callback type and variable to skx_show_rrl_f and show_rrl for clearer RRL terminology and consistency. No functional changes intended. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Tested-by: Yi Lai Link: https://patch.msgid.link/20260521073112.3881223-3-qiuxu.zhuo@intel.com --- drivers/edac/i10nm_base.c | 10 ++++++---- drivers/edac/skx_base.c | 6 +++--- drivers/edac/skx_common.c | 15 ++++++++++----- drivers/edac/skx_common.h | 5 +++-- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c index 0a0236583eb7..c09790d5b95e 100644 --- a/drivers/edac/i10nm_base.c +++ b/drivers/edac/i10nm_base.c @@ -1208,13 +1208,13 @@ static int __init i10nm_init(void) skx_setup_debug("i10nm_test"); if (retry_rd_err_log && res_cfg->reg_rrl_ddr) { - skx_set_decode(i10nm_mc_decode, show_retry_rd_err_log); + skx_set_show_rrl(show_retry_rd_err_log); if (retry_rd_err_log == 2) enable_retry_rd_err_log(true); - } else { - skx_set_decode(i10nm_mc_decode, NULL); } + skx_set_decode(i10nm_mc_decode); + i10nm_printk(KERN_INFO, "%s\n", I10NM_REVISION); return 0; @@ -1227,10 +1227,12 @@ static void __exit i10nm_exit(void) { edac_dbg(2, "\n"); + skx_set_decode(NULL); + if (retry_rd_err_log && res_cfg->reg_rrl_ddr) { - skx_set_decode(NULL, NULL); if (retry_rd_err_log == 2) enable_retry_rd_err_log(false); + skx_set_show_rrl(NULL); } skx_teardown_debug(); diff --git a/drivers/edac/skx_base.c b/drivers/edac/skx_base.c index aa6593ccda2d..de749413ff9a 100644 --- a/drivers/edac/skx_base.c +++ b/drivers/edac/skx_base.c @@ -671,14 +671,14 @@ static int __init skx_init(void) } } - skx_set_decode(skx_decode, skx_show_retry_rd_err_log); + skx_set_show_rrl(skx_show_retry_rd_err_log); if (nvdimm_count && skx_adxl_get() != -ENODEV) { - skx_set_decode(NULL, skx_show_retry_rd_err_log); + skx_set_decode(NULL); } else { if (nvdimm_count) skx_printk(KERN_NOTICE, "Only decoding DDR4 address!\n"); - skx_set_decode(skx_decode, skx_show_retry_rd_err_log); + skx_set_decode(skx_decode); } /* Ensure that the OPSTATE is set correctly for POLL or NMI */ diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c index 1c4cc21679bc..2cdef2e69d71 100644 --- a/drivers/edac/skx_common.c +++ b/drivers/edac/skx_common.c @@ -46,7 +46,7 @@ static unsigned long adxl_nm_bitmap; static char skx_msg[MSG_SIZE]; static skx_decode_f driver_decode; -static skx_show_retry_log_f skx_show_retry_rd_err_log; +static skx_show_rrl_f show_rrl; static u64 skx_tolm, skx_tohm; static LIST_HEAD(dev_edac_list); static bool skx_mem_cfg_2lm; @@ -312,13 +312,18 @@ void skx_set_res_cfg(struct res_config *cfg) } EXPORT_SYMBOL_GPL(skx_set_res_cfg); -void skx_set_decode(skx_decode_f decode, skx_show_retry_log_f show_retry_log) +void skx_set_decode(skx_decode_f decode) { driver_decode = decode; - skx_show_retry_rd_err_log = show_retry_log; } EXPORT_SYMBOL_GPL(skx_set_decode); +void skx_set_show_rrl(skx_show_rrl_f rrl) +{ + show_rrl = rrl; +} +EXPORT_SYMBOL_GPL(skx_set_show_rrl); + static int skx_get_pkg_id(struct skx_dev *d, u8 *id) { int node; @@ -767,8 +772,8 @@ static void skx_mce_output_error(struct mem_ctl_info *mci, res->row, res->column, res->bank_address, res->bank_group); } - if (skx_show_retry_rd_err_log) - skx_show_retry_rd_err_log(res, skx_msg + len, MSG_SIZE - len, scrub_err); + if (show_rrl) + show_rrl(res, skx_msg + len, MSG_SIZE - len, scrub_err); edac_dbg(0, "%s\n", skx_msg); diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h index 95412459a84f..5a08f219e46d 100644 --- a/drivers/edac/skx_common.h +++ b/drivers/edac/skx_common.h @@ -324,14 +324,15 @@ struct res_config { typedef int (*get_dimm_config_f)(struct mem_ctl_info *mci, struct res_config *cfg); typedef bool (*skx_decode_f)(struct decoded_addr *res); -typedef void (*skx_show_retry_log_f)(struct decoded_addr *res, char *msg, int len, bool scrub_err); +typedef void (*skx_show_rrl_f)(struct decoded_addr *res, char *msg, int len, bool scrub_err); u64 skx_readx(void __iomem *addr, u8 width); u64 skx_read_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width); void skx_write_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width, u64 val); int skx_adxl_get(void); void skx_adxl_put(void); -void skx_set_decode(skx_decode_f decode, skx_show_retry_log_f show_retry_log); +void skx_set_decode(skx_decode_f decode); +void skx_set_show_rrl(skx_show_rrl_f rrl); void skx_set_mem_cfg(bool mem_cfg_2lm); void skx_set_res_cfg(struct res_config *cfg); void skx_init_mc_mapping(struct skx_dev *d); From 579f40db12f75eb15b2517b150814564857dd8c7 Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Thu, 21 May 2026 15:31:07 +0800 Subject: [PATCH 14/22] EDAC/{skx_common,i10nm}: Rename rrl_mode to rrl_source_type The RRL (Retry Read error Log) values describe where an error was logged from (first/last read and scrub/demand), not an operating mode. Rename rrl_mode to rrl_source_type and "modes" to "sources" to better reflect their meaning and improve code readability. No functional changes intended. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Tested-by: Yi Lai Link: https://patch.msgid.link/20260521073112.3881223-4-qiuxu.zhuo@intel.com --- drivers/edac/i10nm_base.c | 18 +++++++++--------- drivers/edac/skx_common.h | 14 +++++++------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c index c09790d5b95e..01cc86f697c8 100644 --- a/drivers/edac/i10nm_base.c +++ b/drivers/edac/i10nm_base.c @@ -78,7 +78,7 @@ static bool no_adxl; static struct reg_rrl icx_reg_rrl_ddr = { .set_num = 2, .reg_num = 6, - .modes = {LRE_SCRUB, LRE_DEMAND}, + .sources = {RRL_SRC_LRE_SCRUB, RRL_SRC_LRE_DEMAND}, .offsets = { {0x22c60, 0x22c54, 0x22c5c, 0x22c58, 0x22c28, 0x20ed8}, {0x22e54, 0x22e60, 0x22e64, 0x22e58, 0x22e5c, 0x20ee0}, @@ -99,7 +99,7 @@ static struct reg_rrl icx_reg_rrl_ddr = { static struct reg_rrl spr_reg_rrl_ddr = { .set_num = 3, .reg_num = 6, - .modes = {LRE_SCRUB, LRE_DEMAND, FRE_DEMAND}, + .sources = {RRL_SRC_LRE_SCRUB, RRL_SRC_LRE_DEMAND, RRL_SRC_FRE_DEMAND}, .offsets = { {0x22c60, 0x22c54, 0x22f08, 0x22c58, 0x22c28, 0x20ed8}, {0x22e54, 0x22e60, 0x22f10, 0x22e58, 0x22e5c, 0x20ee0}, @@ -121,7 +121,7 @@ static struct reg_rrl spr_reg_rrl_ddr = { static struct reg_rrl spr_reg_rrl_hbm_pch0 = { .set_num = 2, .reg_num = 6, - .modes = {LRE_SCRUB, LRE_DEMAND}, + .sources = {RRL_SRC_LRE_SCRUB, RRL_SRC_LRE_DEMAND}, .offsets = { {0x2860, 0x2854, 0x2b08, 0x2858, 0x2828, 0x0ed8}, {0x2a54, 0x2a60, 0x2b10, 0x2a58, 0x2a5c, 0x0ee0}, @@ -142,7 +142,7 @@ static struct reg_rrl spr_reg_rrl_hbm_pch0 = { static struct reg_rrl spr_reg_rrl_hbm_pch1 = { .set_num = 2, .reg_num = 6, - .modes = {LRE_SCRUB, LRE_DEMAND}, + .sources = {RRL_SRC_LRE_SCRUB, RRL_SRC_LRE_DEMAND}, .offsets = { {0x2c60, 0x2c54, 0x2f08, 0x2c58, 0x2c28, 0x0fa8}, {0x2e54, 0x2e60, 0x2f10, 0x2e58, 0x2e5c, 0x0fb0}, @@ -163,7 +163,7 @@ static struct reg_rrl spr_reg_rrl_hbm_pch1 = { static struct reg_rrl gnr_reg_rrl_ddr = { .set_num = 4, .reg_num = 6, - .modes = {FRE_SCRUB, FRE_DEMAND, LRE_SCRUB, LRE_DEMAND}, + .sources = {RRL_SRC_FRE_SCRUB, RRL_SRC_FRE_DEMAND, RRL_SRC_LRE_SCRUB, RRL_SRC_LRE_DEMAND}, .offsets = { {0x2f10, 0x2f20, 0x2f30, 0x2f50, 0x2f60, 0xba0}, {0x2f14, 0x2f24, 0x2f38, 0x2f54, 0x2f64, 0xba8}, @@ -186,15 +186,15 @@ static struct reg_rrl gnr_reg_rrl_ddr = { static void enable_rrl(struct skx_imc *imc, int chan, struct reg_rrl *rrl, int rrl_set, bool enable, u32 *rrl_ctl) { - enum rrl_mode mode = rrl->modes[rrl_set]; + enum rrl_source_type source = rrl->sources[rrl_set]; u32 offset = rrl->offsets[rrl_set][0], v; u8 width = rrl->widths[0]; bool first, scrub; /* First or last read error. */ - first = (mode == FRE_SCRUB || mode == FRE_DEMAND); + first = (source == RRL_SRC_FRE_SCRUB || source == RRL_SRC_FRE_DEMAND); /* Patrol scrub or on-demand read error. */ - scrub = (mode == FRE_SCRUB || mode == LRE_SCRUB); + scrub = (source == RRL_SRC_FRE_SCRUB || source == RRL_SRC_LRE_SCRUB); v = skx_read_imc_reg(imc, chan, offset, width); @@ -318,7 +318,7 @@ static void show_retry_rd_err_log(struct decoded_addr *res, char *msg, n = scnprintf(msg, len, " retry_rd_err_log["); for (i = 0; i < rrl->set_num; i++) { - scrub = (rrl->modes[i] == FRE_SCRUB || rrl->modes[i] == LRE_SCRUB); + scrub = (rrl->sources[i] == RRL_SRC_FRE_SCRUB || rrl->sources[i] == RRL_SRC_LRE_SCRUB); if (scrub_err != scrub) continue; diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h index 5a08f219e46d..f7f016db122f 100644 --- a/drivers/edac/skx_common.h +++ b/drivers/edac/skx_common.h @@ -81,23 +81,23 @@ /* Max correctable error count registers. */ #define NUM_CECNT_REG 8 -/* Modes of RRL register set. */ -enum rrl_mode { +/* Error source from which the RRL registers log errors. */ +enum rrl_source_type { /* Last read error from patrol scrub. */ - LRE_SCRUB, + RRL_SRC_LRE_SCRUB, /* Last read error from demand. */ - LRE_DEMAND, + RRL_SRC_LRE_DEMAND, /* First read error from patrol scrub. */ - FRE_SCRUB, + RRL_SRC_FRE_SCRUB, /* First read error from demand. */ - FRE_DEMAND, + RRL_SRC_FRE_DEMAND, }; /* RRL registers per {,sub-,pseudo-}channel. */ struct reg_rrl { /* RRL register parts. */ int set_num, reg_num; - enum rrl_mode modes[NUM_RRL_SET]; + enum rrl_source_type sources[NUM_RRL_SET]; u32 offsets[NUM_RRL_SET][NUM_RRL_REG]; /* RRL register widths in byte per set. */ u8 widths[NUM_RRL_REG]; From 1286fc30cc08a12c2b6d2cf4a1d5dbb0b6bc76d9 Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Thu, 21 May 2026 15:31:08 +0800 Subject: [PATCH 15/22] EDAC/{skx_common,i10nm}: Introduce rrl_ctrl_mode RRL (Retry Read error Log) ownership is currently inferred from retry_rd_err_log magic values, making control semantics implicit and harder to understand. Introduce rrl_ctrl_mode to explicitly describe whether RRL is controlled by none, BIOS, or Linux, and replace direct checks with named control states to improve readability and maintainability. No functional change intended. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Tested-by: Yi Lai Link: https://patch.msgid.link/20260521073112.3881223-5-qiuxu.zhuo@intel.com --- drivers/edac/i10nm_base.c | 7 ++++--- drivers/edac/skx_common.h | 11 +++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c index 01cc86f697c8..fe148f1f2319 100644 --- a/drivers/edac/i10nm_base.c +++ b/drivers/edac/i10nm_base.c @@ -333,7 +333,7 @@ static void show_retry_rd_err_log(struct decoded_addr *res, char *msg, n += scnprintf(msg + n, len - n, "%.16llx ", log); /* Clear RRL status if RRL in Linux control mode. */ - if (retry_rd_err_log == 2 && !j && (log & status_mask)) + if (res_cfg->rrl_ctrl_mode == RRL_CTRL_LINUX && !j && (log & status_mask)) skx_write_imc_reg(imc, ch, offset, width, log & ~status_mask); } } @@ -1207,9 +1207,10 @@ static int __init i10nm_init(void) mce_register_decode_chain(&i10nm_mce_dec); skx_setup_debug("i10nm_test"); + res_cfg->rrl_ctrl_mode = retry_rd_err_log; if (retry_rd_err_log && res_cfg->reg_rrl_ddr) { skx_set_show_rrl(show_retry_rd_err_log); - if (retry_rd_err_log == 2) + if (retry_rd_err_log == RRL_CTRL_LINUX) enable_retry_rd_err_log(true); } @@ -1230,7 +1231,7 @@ static void __exit i10nm_exit(void) skx_set_decode(NULL); if (retry_rd_err_log && res_cfg->reg_rrl_ddr) { - if (retry_rd_err_log == 2) + if (retry_rd_err_log == RRL_CTRL_LINUX) enable_retry_rd_err_log(false); skx_set_show_rrl(NULL); } diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h index f7f016db122f..4091431356d6 100644 --- a/drivers/edac/skx_common.h +++ b/drivers/edac/skx_common.h @@ -93,6 +93,15 @@ enum rrl_source_type { RRL_SRC_FRE_DEMAND, }; +enum rrl_ctrl_mode { + /* Linux does not control RRL or reports values. */ + RRL_CTRL_NONE, + /* Firmware retains control. Linux only reports values. */ + RRL_CTRL_BIOS, + /* Linux takes control, resets mode bits, and clears valid/UC bits; reports values. */ + RRL_CTRL_LINUX, +}; + /* RRL registers per {,sub-,pseudo-}channel. */ struct reg_rrl { /* RRL register parts. */ @@ -272,6 +281,8 @@ struct res_config { struct reg_rrl *reg_rrl_ddr; /* RRL register sets per HBM channel */ struct reg_rrl *reg_rrl_hbm[2]; + /* RRL control mode */ + enum rrl_ctrl_mode rrl_ctrl_mode; union { /* {skx,i10nm}_edac */ struct { From 8998a4a646471dc218f6499c5580e252891ccaa4 Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Thu, 21 May 2026 15:31:09 +0800 Subject: [PATCH 16/22] EDAC/{skx_common,i10nm}: Move RRL handling to common code Move RRL (Retry Read error Log) handling from i10nm_edac to skx_common so it can be shared across EDAC drivers (e.g. imh_edac). - Move RRL enable/disable and log dumping helpers to skx_common to avoid code duplication and enable reuse by other drivers. - Export skx_enable_rrl() and skx_show_rrl() so common RRL handling can be used by i10nm_edac and imh_edac. No functional change intended. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Tested-by: Yi Lai Link: https://patch.msgid.link/20260521073112.3881223-6-qiuxu.zhuo@intel.com --- drivers/edac/i10nm_base.c | 191 +------------------------------------- drivers/edac/skx_common.c | 186 +++++++++++++++++++++++++++++++++++++ drivers/edac/skx_common.h | 2 + 3 files changed, 191 insertions(+), 188 deletions(-) diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c index fe148f1f2319..2e21eefbb4f5 100644 --- a/drivers/edac/i10nm_base.c +++ b/drivers/edac/i10nm_base.c @@ -183,191 +183,6 @@ static struct reg_rrl gnr_reg_rrl_ddr = { .cecnt_widths = {4, 4, 4, 4, 4, 4, 4, 4}, }; -static void enable_rrl(struct skx_imc *imc, int chan, struct reg_rrl *rrl, - int rrl_set, bool enable, u32 *rrl_ctl) -{ - enum rrl_source_type source = rrl->sources[rrl_set]; - u32 offset = rrl->offsets[rrl_set][0], v; - u8 width = rrl->widths[0]; - bool first, scrub; - - /* First or last read error. */ - first = (source == RRL_SRC_FRE_SCRUB || source == RRL_SRC_FRE_DEMAND); - /* Patrol scrub or on-demand read error. */ - scrub = (source == RRL_SRC_FRE_SCRUB || source == RRL_SRC_LRE_SCRUB); - - v = skx_read_imc_reg(imc, chan, offset, width); - - if (enable) { - /* Save default configurations. */ - *rrl_ctl = v; - v &= ~rrl->uc_mask; - - if (first) - v |= rrl->noover_mask; - else - v &= ~rrl->noover_mask; - - if (scrub) - v |= rrl->en_patspr_mask; - else - v &= ~rrl->en_patspr_mask; - - v |= rrl->en_mask; - } else { - /* Restore default configurations. */ - if (*rrl_ctl & rrl->uc_mask) - v |= rrl->uc_mask; - - if (first) { - if (!(*rrl_ctl & rrl->noover_mask)) - v &= ~rrl->noover_mask; - } else { - if (*rrl_ctl & rrl->noover_mask) - v |= rrl->noover_mask; - } - - if (scrub) { - if (!(*rrl_ctl & rrl->en_patspr_mask)) - v &= ~rrl->en_patspr_mask; - } else { - if (*rrl_ctl & rrl->en_patspr_mask) - v |= rrl->en_patspr_mask; - } - - if (!(*rrl_ctl & rrl->en_mask)) - v &= ~rrl->en_mask; - } - - skx_write_imc_reg(imc, chan, offset, width, v); -} - -static void enable_rrls(struct skx_imc *imc, int chan, struct reg_rrl *rrl, - bool enable, u32 *rrl_ctl) -{ - for (int i = 0; i < rrl->set_num; i++) - enable_rrl(imc, chan, rrl, i, enable, rrl_ctl + i); -} - -static void enable_rrls_ddr(struct skx_imc *imc, bool enable) -{ - struct reg_rrl *rrl_ddr = res_cfg->reg_rrl_ddr; - int i, chan_num = res_cfg->ddr_chan_num; - struct skx_channel *chan = imc->chan; - - if (!imc->mbase) - return; - - for (i = 0; i < chan_num; i++) - enable_rrls(imc, i, rrl_ddr, enable, chan[i].rrl_ctl[0]); -} - -static void enable_rrls_hbm(struct skx_imc *imc, bool enable) -{ - struct reg_rrl **rrl_hbm = res_cfg->reg_rrl_hbm; - int i, chan_num = res_cfg->hbm_chan_num; - struct skx_channel *chan = imc->chan; - - if (!imc->mbase || !imc->hbm_mc || !rrl_hbm[0] || !rrl_hbm[1]) - return; - - for (i = 0; i < chan_num; i++) { - enable_rrls(imc, i, rrl_hbm[0], enable, chan[i].rrl_ctl[0]); - enable_rrls(imc, i, rrl_hbm[1], enable, chan[i].rrl_ctl[1]); - } -} - -static void enable_retry_rd_err_log(bool enable) -{ - struct skx_dev *d; - int i, imc_num; - - edac_dbg(2, "\n"); - - list_for_each_entry(d, i10nm_edac_list, list) { - imc_num = res_cfg->ddr_imc_num; - for (i = 0; i < imc_num; i++) - enable_rrls_ddr(&d->imc[i], enable); - - imc_num += res_cfg->hbm_imc_num; - for (; i < imc_num; i++) - enable_rrls_hbm(&d->imc[i], enable); - } -} - -static void show_retry_rd_err_log(struct decoded_addr *res, char *msg, - int len, bool scrub_err) -{ - int i, j, n, ch = res->channel, pch = res->cs & 1; - struct skx_imc *imc = &res->dev->imc[res->imc]; - u64 log, corr, status_mask; - struct reg_rrl *rrl; - bool scrub; - u32 offset; - u8 width; - - if (!imc->mbase) - return; - - rrl = imc->hbm_mc ? res_cfg->reg_rrl_hbm[pch] : res_cfg->reg_rrl_ddr; - - if (!rrl) - return; - - status_mask = rrl->over_mask | rrl->uc_mask | rrl->v_mask; - - n = scnprintf(msg, len, " retry_rd_err_log["); - for (i = 0; i < rrl->set_num; i++) { - scrub = (rrl->sources[i] == RRL_SRC_FRE_SCRUB || rrl->sources[i] == RRL_SRC_LRE_SCRUB); - if (scrub_err != scrub) - continue; - - for (j = 0; j < rrl->reg_num && len - n > 0; j++) { - offset = rrl->offsets[i][j]; - width = rrl->widths[j]; - log = skx_read_imc_reg(imc, ch, offset, width); - - if (width == 4) - n += scnprintf(msg + n, len - n, "%.8llx ", log); - else - n += scnprintf(msg + n, len - n, "%.16llx ", log); - - /* Clear RRL status if RRL in Linux control mode. */ - if (res_cfg->rrl_ctrl_mode == RRL_CTRL_LINUX && !j && (log & status_mask)) - skx_write_imc_reg(imc, ch, offset, width, log & ~status_mask); - } - } - - /* Move back one space. */ - n--; - n += scnprintf(msg + n, len - n, "]"); - - if (len - n > 0) { - n += scnprintf(msg + n, len - n, " correrrcnt["); - for (i = 0; i < rrl->cecnt_num && len - n > 0; i++) { - offset = rrl->cecnt_offsets[i]; - width = rrl->cecnt_widths[i]; - corr = skx_read_imc_reg(imc, ch, offset, width); - - /* CPUs {ICX,SPR} encode two counters per 4-byte CORRERRCNT register. */ - if (res_cfg->type <= SPR) { - n += scnprintf(msg + n, len - n, "%.4llx %.4llx ", - corr & 0xffff, corr >> 16); - } else { - /* CPUs {GNR} encode one counter per CORRERRCNT register. */ - if (width == 4) - n += scnprintf(msg + n, len - n, "%.8llx ", corr); - else - n += scnprintf(msg + n, len - n, "%.16llx ", corr); - } - } - - /* Move back one space. */ - n--; - n += scnprintf(msg + n, len - n, "]"); - } -} - static struct pci_dev *pci_get_dev_wrapper(int dom, unsigned int bus, unsigned int dev, unsigned int fun) { @@ -1209,9 +1024,9 @@ static int __init i10nm_init(void) res_cfg->rrl_ctrl_mode = retry_rd_err_log; if (retry_rd_err_log && res_cfg->reg_rrl_ddr) { - skx_set_show_rrl(show_retry_rd_err_log); + skx_set_show_rrl(skx_show_rrl); if (retry_rd_err_log == RRL_CTRL_LINUX) - enable_retry_rd_err_log(true); + skx_enable_rrl(true); } skx_set_decode(i10nm_mc_decode); @@ -1232,7 +1047,7 @@ static void __exit i10nm_exit(void) if (retry_rd_err_log && res_cfg->reg_rrl_ddr) { if (retry_rd_err_log == RRL_CTRL_LINUX) - enable_retry_rd_err_log(false); + skx_enable_rrl(false); skx_set_show_rrl(NULL); } diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c index 2cdef2e69d71..f769a354ea45 100644 --- a/drivers/edac/skx_common.c +++ b/drivers/edac/skx_common.c @@ -102,6 +102,192 @@ void skx_write_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width, u64 } EXPORT_SYMBOL_GPL(skx_write_imc_reg); +static void enable_rrl(struct skx_imc *imc, int chan, struct reg_rrl *rrl, + int rrl_set, bool enable, u32 *rrl_ctl) +{ + enum rrl_source_type source = rrl->sources[rrl_set]; + u32 offset = rrl->offsets[rrl_set][0], v; + u8 width = rrl->widths[0]; + bool first, scrub; + + /* First or last read error. */ + first = (source == RRL_SRC_FRE_SCRUB || source == RRL_SRC_FRE_DEMAND); + /* Patrol scrub or on-demand read error. */ + scrub = (source == RRL_SRC_FRE_SCRUB || source == RRL_SRC_LRE_SCRUB); + + v = skx_read_imc_reg(imc, chan, offset, width); + + if (enable) { + /* Save default configurations. */ + *rrl_ctl = v; + v &= ~rrl->uc_mask; + + if (first) + v |= rrl->noover_mask; + else + v &= ~rrl->noover_mask; + + if (scrub) + v |= rrl->en_patspr_mask; + else + v &= ~rrl->en_patspr_mask; + + v |= rrl->en_mask; + } else { + /* Restore default configurations. */ + if (*rrl_ctl & rrl->uc_mask) + v |= rrl->uc_mask; + + if (first) { + if (!(*rrl_ctl & rrl->noover_mask)) + v &= ~rrl->noover_mask; + } else { + if (*rrl_ctl & rrl->noover_mask) + v |= rrl->noover_mask; + } + + if (scrub) { + if (!(*rrl_ctl & rrl->en_patspr_mask)) + v &= ~rrl->en_patspr_mask; + } else { + if (*rrl_ctl & rrl->en_patspr_mask) + v |= rrl->en_patspr_mask; + } + + if (!(*rrl_ctl & rrl->en_mask)) + v &= ~rrl->en_mask; + } + + skx_write_imc_reg(imc, chan, offset, width, v); +} + +static void enable_rrls(struct skx_imc *imc, int chan, struct reg_rrl *rrl, + bool enable, u32 *rrl_ctl) +{ + for (int i = 0; i < rrl->set_num; i++) + enable_rrl(imc, chan, rrl, i, enable, rrl_ctl + i); +} + +static void enable_rrls_ddr(struct skx_imc *imc, bool enable) +{ + struct reg_rrl *rrl_ddr = skx_res_cfg->reg_rrl_ddr; + int i, chan_num = skx_res_cfg->ddr_chan_num; + struct skx_channel *chan = imc->chan; + + if (!imc->mbase) + return; + + for (i = 0; i < chan_num; i++) + enable_rrls(imc, i, rrl_ddr, enable, chan[i].rrl_ctl[0]); +} + +static void enable_rrls_hbm(struct skx_imc *imc, bool enable) +{ + struct reg_rrl **rrl_hbm = skx_res_cfg->reg_rrl_hbm; + int i, chan_num = skx_res_cfg->hbm_chan_num; + struct skx_channel *chan = imc->chan; + + if (!imc->mbase || !imc->hbm_mc || !rrl_hbm[0] || !rrl_hbm[1]) + return; + + for (i = 0; i < chan_num; i++) { + enable_rrls(imc, i, rrl_hbm[0], enable, chan[i].rrl_ctl[0]); + enable_rrls(imc, i, rrl_hbm[1], enable, chan[i].rrl_ctl[1]); + } +} + +void skx_enable_rrl(bool enable) +{ + struct skx_dev *d; + int i, imc_num; + + edac_dbg(2, "\n"); + + list_for_each_entry(d, &dev_edac_list, list) { + imc_num = skx_res_cfg->ddr_imc_num; + for (i = 0; i < imc_num; i++) + enable_rrls_ddr(&d->imc[i], enable); + + imc_num += skx_res_cfg->hbm_imc_num; + for (; i < imc_num; i++) + enable_rrls_hbm(&d->imc[i], enable); + } +} +EXPORT_SYMBOL_GPL(skx_enable_rrl); + +void skx_show_rrl(struct decoded_addr *res, char *msg, int len, bool scrub_err) +{ + int i, j, n, ch = res->channel, pch = res->cs & 1; + struct skx_imc *imc = &res->dev->imc[res->imc]; + u64 log, corr, status_mask; + struct reg_rrl *rrl; + bool scrub; + u32 offset; + u8 width; + + if (!imc->mbase) + return; + + rrl = imc->hbm_mc ? skx_res_cfg->reg_rrl_hbm[pch] : skx_res_cfg->reg_rrl_ddr; + + if (!rrl) + return; + + status_mask = rrl->over_mask | rrl->uc_mask | rrl->v_mask; + + n = scnprintf(msg, len, " retry_rd_err_log["); + for (i = 0; i < rrl->set_num; i++) { + scrub = (rrl->sources[i] == RRL_SRC_FRE_SCRUB || rrl->sources[i] == RRL_SRC_LRE_SCRUB); + if (scrub_err != scrub) + continue; + + for (j = 0; j < rrl->reg_num && len - n > 0; j++) { + offset = rrl->offsets[i][j]; + width = rrl->widths[j]; + log = skx_read_imc_reg(imc, ch, offset, width); + + if (width == 4) + n += scnprintf(msg + n, len - n, "%.8llx ", log); + else + n += scnprintf(msg + n, len - n, "%.16llx ", log); + + /* Clear RRL status if RRL in Linux control mode. */ + if (skx_res_cfg->rrl_ctrl_mode == RRL_CTRL_LINUX && !j && (log & status_mask)) + skx_write_imc_reg(imc, ch, offset, width, log & ~status_mask); + } + } + + /* Move back one space. */ + n--; + n += scnprintf(msg + n, len - n, "]"); + + if (len - n > 0) { + n += scnprintf(msg + n, len - n, " correrrcnt["); + for (i = 0; i < rrl->cecnt_num && len - n > 0; i++) { + offset = rrl->cecnt_offsets[i]; + width = rrl->cecnt_widths[i]; + corr = skx_read_imc_reg(imc, ch, offset, width); + + /* CPUs {ICX,SPR} encode two counters per 4-byte CORRERRCNT register. */ + if (skx_res_cfg->type <= SPR) { + n += scnprintf(msg + n, len - n, "%.4llx %.4llx ", + corr & 0xffff, corr >> 16); + } else { + /* CPUs {GNR} encode one counter per CORRERRCNT register. */ + if (width == 4) + n += scnprintf(msg + n, len - n, "%.8llx ", corr); + else + n += scnprintf(msg + n, len - n, "%.16llx ", corr); + } + } + + /* Move back one space. */ + n--; + n += scnprintf(msg + n, len - n, "]"); + } +} +EXPORT_SYMBOL_GPL(skx_show_rrl); + int skx_adxl_get(void) { const char * const *names; diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h index 4091431356d6..eea2d95cc0ac 100644 --- a/drivers/edac/skx_common.h +++ b/drivers/edac/skx_common.h @@ -344,6 +344,8 @@ int skx_adxl_get(void); void skx_adxl_put(void); void skx_set_decode(skx_decode_f decode); void skx_set_show_rrl(skx_show_rrl_f rrl); +void skx_show_rrl(struct decoded_addr *res, char *msg, int len, bool scrub_err); +void skx_enable_rrl(bool enable); void skx_set_mem_cfg(bool mem_cfg_2lm); void skx_set_res_cfg(struct res_config *cfg); void skx_init_mc_mapping(struct skx_dev *d); From 5b33d5a7be01000014f81e426ff20c3a20b5d9b0 Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Thu, 21 May 2026 15:31:10 +0800 Subject: [PATCH 17/22] EDAC/skx_common: Add SubChannel support to ADXL decode Diamond Rapids server RRL (Retry Read error Log) operates at sub-channel granularity. Add SubChannel support to ADXL decoding in preparation for enabling this feature. Also introduce adxl_component_required() to validate mandatory ADXL components to improve code readability. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Tested-by: Yi Lai Link: https://patch.msgid.link/20260521073112.3881223-7-qiuxu.zhuo@intel.com --- drivers/edac/skx_common.c | 20 +++++++++++++++++++- drivers/edac/skx_common.h | 5 +++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c index f769a354ea45..4d832f02fb59 100644 --- a/drivers/edac/skx_common.c +++ b/drivers/edac/skx_common.c @@ -31,10 +31,12 @@ static const char * const component_names[] = { [INDEX_CHANNEL] = "ChannelId", [INDEX_DIMM] = "DimmSlotId", [INDEX_CS] = "ChipSelect", + [INDEX_SUBCH] = "SubChId", [INDEX_NM_MEMCTRL] = "NmMemoryControllerId", [INDEX_NM_CHANNEL] = "NmChannelId", [INDEX_NM_DIMM] = "NmDimmSlotId", [INDEX_NM_CS] = "NmChipSelect", + [INDEX_NM_SUBCH] = "NmSubChId", }; static int component_indices[ARRAY_SIZE(component_names)]; @@ -43,6 +45,7 @@ static const char * const *adxl_component_names; static u64 *adxl_values; static char *adxl_msg; static unsigned long adxl_nm_bitmap; +static unsigned long adxl_bitmap; static char skx_msg[MSG_SIZE]; static skx_decode_f driver_decode; @@ -288,6 +291,15 @@ void skx_show_rrl(struct decoded_addr *res, char *msg, int len, bool scrub_err) } EXPORT_SYMBOL_GPL(skx_show_rrl); +static bool adxl_component_required(int idx) +{ + return idx == INDEX_SOCKET || + idx == INDEX_MEMCTRL || + idx == INDEX_CHANNEL || + idx == INDEX_DIMM || + idx == INDEX_CS; +} + int skx_adxl_get(void) { const char * const *names; @@ -306,12 +318,14 @@ int skx_adxl_get(void) if (i >= INDEX_NM_FIRST) adxl_nm_bitmap |= 1 << i; + else + adxl_bitmap |= 1 << i; break; } } - if (!names[j] && i < INDEX_NM_FIRST) + if (!names[j] && adxl_component_required(i)) goto err; } @@ -438,11 +452,15 @@ static bool skx_adxl_decode(struct decoded_addr *res, enum error_source err_src) (int)adxl_values[component_indices[INDEX_NM_DIMM]] : -1; res->cs = (adxl_nm_bitmap & BIT_NM_CS) ? (int)adxl_values[component_indices[INDEX_NM_CS]] : -1; + res->subch = (adxl_nm_bitmap & BIT_NM_SUBCH) ? + (int)adxl_values[component_indices[INDEX_NM_SUBCH]] : -1; } else { res->imc = (int)adxl_values[component_indices[INDEX_MEMCTRL]]; res->channel = (int)adxl_values[component_indices[INDEX_CHANNEL]]; res->dimm = (int)adxl_values[component_indices[INDEX_DIMM]]; res->cs = (int)adxl_values[component_indices[INDEX_CS]]; + res->subch = (adxl_bitmap & BIT_SUBCH) ? + (int)adxl_values[component_indices[INDEX_SUBCH]] : -1; } if (res->imc < 0) { diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h index eea2d95cc0ac..38d96bf71fd9 100644 --- a/drivers/edac/skx_common.h +++ b/drivers/edac/skx_common.h @@ -210,11 +210,13 @@ enum { INDEX_CHANNEL, INDEX_DIMM, INDEX_CS, + INDEX_SUBCH, INDEX_NM_FIRST, INDEX_NM_MEMCTRL = INDEX_NM_FIRST, INDEX_NM_CHANNEL, INDEX_NM_DIMM, INDEX_NM_CS, + INDEX_NM_SUBCH, INDEX_MAX }; @@ -225,10 +227,12 @@ enum error_source { ERR_SRC_NOT_MEMORY, }; +#define BIT_SUBCH BIT_ULL(INDEX_SUBCH) #define BIT_NM_MEMCTRL BIT_ULL(INDEX_NM_MEMCTRL) #define BIT_NM_CHANNEL BIT_ULL(INDEX_NM_CHANNEL) #define BIT_NM_DIMM BIT_ULL(INDEX_NM_DIMM) #define BIT_NM_CS BIT_ULL(INDEX_NM_CS) +#define BIT_NM_SUBCH BIT_ULL(INDEX_NM_SUBCH) struct decoded_addr { struct mce *mce; @@ -242,6 +246,7 @@ struct decoded_addr { int chanways; int dimm; int cs; + int subch; int rank; int channel_rank; u64 rank_address; From 4742ae4d82454af4eb21c9eefb17c5e80a08d392 Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Thu, 21 May 2026 15:31:11 +0800 Subject: [PATCH 18/22] EDAC/{skx_common,i10nm}: Prepare RRL for sub-channel granularity To prepare for enabling Diamond Rapids server RRL (Retry Read error Log), which operates at sub-channel granularity by converting struct res_config::reg_rrl_ddr from a single pointer to an array (reg_rrl_ddr[2]) and updating all users in i10nm_edac and skx_common accordingly. Initialize only reg_rrl_ddr[0] for existing platforms and prepare for supporting two RRL set groups per DDR channel (one per sub-channel) when present. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Tested-by: Yi Lai Link: https://patch.msgid.link/20260521073112.3881223-8-qiuxu.zhuo@intel.com --- drivers/edac/i10nm_base.c | 12 ++++++------ drivers/edac/skx_common.c | 35 +++++++++++++++++++++++++++++------ drivers/edac/skx_common.h | 2 +- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c index 2e21eefbb4f5..fa1853f252b0 100644 --- a/drivers/edac/i10nm_base.c +++ b/drivers/edac/i10nm_base.c @@ -767,7 +767,7 @@ static struct res_config i10nm_cfg0 = { .ddr_mdev_bdf = {0, 12, 0}, .hbm_mdev_bdf = {0, 12, 1}, .sad_all_offset = 0x108, - .reg_rrl_ddr = &icx_reg_rrl_ddr, + .reg_rrl_ddr[0] = &icx_reg_rrl_ddr, }; static struct res_config i10nm_cfg1 = { @@ -785,7 +785,7 @@ static struct res_config i10nm_cfg1 = { .ddr_mdev_bdf = {0, 12, 0}, .hbm_mdev_bdf = {0, 12, 1}, .sad_all_offset = 0x108, - .reg_rrl_ddr = &icx_reg_rrl_ddr, + .reg_rrl_ddr[0] = &icx_reg_rrl_ddr, }; static struct res_config spr_cfg = { @@ -808,7 +808,7 @@ static struct res_config spr_cfg = { .ddr_mdev_bdf = {0, 12, 0}, .hbm_mdev_bdf = {0, 12, 1}, .sad_all_offset = 0x300, - .reg_rrl_ddr = &spr_reg_rrl_ddr, + .reg_rrl_ddr[0] = &spr_reg_rrl_ddr, .reg_rrl_hbm[0] = &spr_reg_rrl_hbm_pch0, .reg_rrl_hbm[1] = &spr_reg_rrl_hbm_pch1, }; @@ -828,7 +828,7 @@ static struct res_config gnr_cfg = { .uracu_bdf = {0, 0, 1}, .ddr_mdev_bdf = {0, 5, 1}, .sad_all_offset = 0x300, - .reg_rrl_ddr = &gnr_reg_rrl_ddr, + .reg_rrl_ddr[0] = &gnr_reg_rrl_ddr, }; static const struct x86_cpu_id i10nm_cpuids[] = { @@ -1023,7 +1023,7 @@ static int __init i10nm_init(void) skx_setup_debug("i10nm_test"); res_cfg->rrl_ctrl_mode = retry_rd_err_log; - if (retry_rd_err_log && res_cfg->reg_rrl_ddr) { + if (retry_rd_err_log && res_cfg->reg_rrl_ddr[0]) { skx_set_show_rrl(skx_show_rrl); if (retry_rd_err_log == RRL_CTRL_LINUX) skx_enable_rrl(true); @@ -1045,7 +1045,7 @@ static void __exit i10nm_exit(void) skx_set_decode(NULL); - if (retry_rd_err_log && res_cfg->reg_rrl_ddr) { + if (retry_rd_err_log && res_cfg->reg_rrl_ddr[0]) { if (retry_rd_err_log == RRL_CTRL_LINUX) skx_enable_rrl(false); skx_set_show_rrl(NULL); diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c index 4d832f02fb59..bfd0cd1689ed 100644 --- a/drivers/edac/skx_common.c +++ b/drivers/edac/skx_common.c @@ -173,15 +173,18 @@ static void enable_rrls(struct skx_imc *imc, int chan, struct reg_rrl *rrl, static void enable_rrls_ddr(struct skx_imc *imc, bool enable) { - struct reg_rrl *rrl_ddr = skx_res_cfg->reg_rrl_ddr; + struct reg_rrl **rrl_ddr = skx_res_cfg->reg_rrl_ddr; int i, chan_num = skx_res_cfg->ddr_chan_num; struct skx_channel *chan = imc->chan; if (!imc->mbase) return; - for (i = 0; i < chan_num; i++) - enable_rrls(imc, i, rrl_ddr, enable, chan[i].rrl_ctl[0]); + for (i = 0; i < chan_num; i++) { + enable_rrls(imc, i, rrl_ddr[0], enable, chan[i].rrl_ctl[0]); + if (rrl_ddr[1]) + enable_rrls(imc, i, rrl_ddr[1], enable, chan[i].rrl_ctl[1]); + } } static void enable_rrls_hbm(struct skx_imc *imc, bool enable) @@ -218,10 +221,31 @@ void skx_enable_rrl(bool enable) } EXPORT_SYMBOL_GPL(skx_enable_rrl); +static struct reg_rrl *get_rrl_reg(struct decoded_addr *res, struct res_config *cfg) +{ + struct skx_imc *imc = &res->dev->imc[res->imc]; + + /* HBM has two groups of RRL sets, one per pseudo-channel. */ + if (imc->hbm_mc) + return cfg->reg_rrl_hbm[res->cs & 1]; + + /* One group of RRL sets per DDR channel. */ + if (!cfg->reg_rrl_ddr[1]) + return cfg->reg_rrl_ddr[0]; + + if (res->subch == -1) { + skx_printk(KERN_ERR, "Invalid sub-channel id (-1), possibly missing %s ADXL component.\n", component_names[INDEX_SUBCH]); + return NULL; + } + + /* Two groups of RRL sets per DDR channel (e.g., DMR: one group per sub-channel). */ + return cfg->reg_rrl_ddr[res->subch & 1]; +} + void skx_show_rrl(struct decoded_addr *res, char *msg, int len, bool scrub_err) { - int i, j, n, ch = res->channel, pch = res->cs & 1; struct skx_imc *imc = &res->dev->imc[res->imc]; + int i, j, n, ch = res->channel; u64 log, corr, status_mask; struct reg_rrl *rrl; bool scrub; @@ -231,8 +255,7 @@ void skx_show_rrl(struct decoded_addr *res, char *msg, int len, bool scrub_err) if (!imc->mbase) return; - rrl = imc->hbm_mc ? skx_res_cfg->reg_rrl_hbm[pch] : skx_res_cfg->reg_rrl_ddr; - + rrl = get_rrl_reg(res, skx_res_cfg); if (!rrl) return; diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h index 38d96bf71fd9..6d4cf0dd412a 100644 --- a/drivers/edac/skx_common.h +++ b/drivers/edac/skx_common.h @@ -283,7 +283,7 @@ struct res_config { int hbm_chan_mmio_sz; bool support_ddr5; /* RRL register sets per DDR channel */ - struct reg_rrl *reg_rrl_ddr; + struct reg_rrl *reg_rrl_ddr[2]; /* RRL register sets per HBM channel */ struct reg_rrl *reg_rrl_hbm[2]; /* RRL control mode */ From bdfc4367e3f516479e0a68c731bea5c6638a6c7e Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Thu, 21 May 2026 15:31:12 +0800 Subject: [PATCH 19/22] EDAC/imh: Add RRL support for Intel Diamond Rapids server Compared to previous generations, Diamond Rapids RRL (Retry Read error Log) operates at DDR sub-channel granularity and adds an extra register per set. It also increases the CORRERRCNT register width from 4 to 8 bytes while reducing the number of registers from 8 to 4. Add the Diamond Rapids RRL register configuration table and enable support. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Tested-by: Yi Lai Link: https://patch.msgid.link/20260521073112.3881223-9-qiuxu.zhuo@intel.com --- drivers/edac/imh_base.c | 52 +++++++++++++++++++++++++++++++++++++++ drivers/edac/skx_common.h | 2 +- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/drivers/edac/imh_base.c b/drivers/edac/imh_base.c index dfdcfa127ce7..6ca0df031bf5 100644 --- a/drivers/edac/imh_base.c +++ b/drivers/edac/imh_base.c @@ -71,6 +71,39 @@ struct local_reg { .width = (cfg)->ip_name##_reg_##reg_name##_width, \ } +static struct res_config *res_cfg; +static int retry_rd_err_log; + +#define REG_RRL_DEFINE(a0, a1, a2, a3, a4, a5, a6, b0, b1, b2, b3) \ + { \ + .set_num = 4, \ + .reg_num = 7, \ + .sources = {RRL_SRC_FRE_SCRUB, RRL_SRC_FRE_DEMAND, RRL_SRC_LRE_SCRUB, RRL_SRC_LRE_DEMAND}, \ + .offsets = { \ + {a0, a1, a2, a3, a4, a5, a6}, \ + {a0 + 4, a1 + 4, a2 + 8, a3 + 4, a4 + 4, a5 + 8, a6 + 8}, \ + {a0 + 8, a1 + 8, a2 + 16, a3 + 8, a4 + 8, a5 + 16, a6 + 16}, \ + {a0 + 12, a1 + 12, a2 + 24, a3 + 12, a4 + 12, a5 + 24, a6 + 24}, \ + }, \ + .widths = {4, 4, 8, 4, 4, 8, 8}, \ + .v_mask = BIT(0), \ + .uc_mask = BIT(1), \ + .over_mask = BIT(2), \ + .en_mask = BIT(12), \ + .en_patspr_mask = BIT(14), \ + .noover_mask = BIT(15), \ + .cecnt_num = 4, \ + .cecnt_offsets = {b0, b1, b2, b3}, \ + .cecnt_widths = {8, 8, 8, 8}, \ +} + +static struct reg_rrl dmr_reg_rrl_ddr_subch0 = REG_RRL_DEFINE( + 0x2dc0, 0x2dd0, 0x2de0, 0x2e00, 0x2e10, 0x2f70, 0x0200, + 0x2c10, 0x2c18, 0x2c20, 0x2c28); +static struct reg_rrl dmr_reg_rrl_ddr_subch1 = REG_RRL_DEFINE( + 0x6dc0, 0x6dd0, 0x6de0, 0x6e00, 0x6e10, 0x6f70, 0x4200, + 0x6c10, 0x6c18, 0x6c20, 0x6c28); + static void __read_local_reg(void *reg) { struct local_reg *r = (struct local_reg *)reg; @@ -480,6 +513,8 @@ static struct res_config dmr_cfg = { .ha_size = 0x1000, .ha_reg_mode_offset = 0x4a0, .ha_reg_mode_width = 4, + .reg_rrl_ddr[0] = &dmr_reg_rrl_ddr_subch0, + .reg_rrl_ddr[1] = &dmr_reg_rrl_ddr_subch1, }; static const struct x86_cpu_id imh_cpuids[] = { @@ -519,6 +554,7 @@ static int __init imh_init(void) return -ENODEV; cfg = (struct res_config *)id->driver_data; skx_set_res_cfg(cfg); + res_cfg = cfg; if (!imh_get_tolm_tohm(cfg, &tolm, &tohm)) return -ENODEV; @@ -553,6 +589,13 @@ static int __init imh_init(void) mce_register_decode_chain(&imh_mce_dec); skx_setup_debug("imh_test"); + cfg->rrl_ctrl_mode = retry_rd_err_log; + if (retry_rd_err_log && cfg->reg_rrl_ddr[0]) { + skx_set_show_rrl(skx_show_rrl); + if (retry_rd_err_log == RRL_CTRL_LINUX) + skx_enable_rrl(true); + } + imh_printk(KERN_INFO, "%s\n", IMH_REVISION); return 0; @@ -565,6 +608,12 @@ static void __exit imh_exit(void) { edac_dbg(2, "\n"); + if (retry_rd_err_log && res_cfg->reg_rrl_ddr[0]) { + if (retry_rd_err_log == RRL_CTRL_LINUX) + skx_enable_rrl(false); + skx_set_show_rrl(NULL); + } + skx_teardown_debug(); mce_unregister_decode_chain(&imh_mce_dec); skx_adxl_put(); @@ -574,6 +623,9 @@ static void __exit imh_exit(void) module_init(imh_init); module_exit(imh_exit); +module_param(retry_rd_err_log, int, 0444); +MODULE_PARM_DESC(retry_rd_err_log, "retry_rd_err_log: 0=off(default), 1=bios(Linux doesn't reset any control bits, but just reports values.), 2=linux(Linux tries to take control and resets mode bits, clear valid/UC bits after reading.)"); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Qiuxu Zhuo"); MODULE_DESCRIPTION("MC Driver for Intel servers using IMH-based memory controller"); diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h index 6d4cf0dd412a..777252cca809 100644 --- a/drivers/edac/skx_common.h +++ b/drivers/edac/skx_common.h @@ -77,7 +77,7 @@ /* Max RRL register sets per {,sub-,pseudo-}channel. */ #define NUM_RRL_SET 4 /* Max RRL registers per set. */ -#define NUM_RRL_REG 6 +#define NUM_RRL_REG 7 /* Max correctable error count registers. */ #define NUM_CECNT_REG 8 From 407791a6228da6a2a88b046d0bdf85255b444bab Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Thu, 21 May 2026 20:38:11 +0800 Subject: [PATCH 20/22] EDAC/igen6: Make registers for detecting IBECC configurable Some Intel CPUs with IBECC (In-Band ECC) capability use different registers to indicate IBECC presence. Make IBECC detection registers CPU-model specific and configure them properly for scalable IBECC detection. No functional changes intended. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Tested-by: Jie Wang Link: https://patch.msgid.link/20260521123812.3961038-2-qiuxu.zhuo@intel.com --- drivers/edac/igen6_edac.c | 55 +++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c index f3e53d63eb54..a761d683eae3 100644 --- a/drivers/edac/igen6_edac.c +++ b/drivers/edac/igen6_edac.c @@ -151,6 +151,8 @@ static struct res_config { /* MEMSS_PMA_CR registers. */ u32 reg_mem_config_offset; u32 reg_mem_config_ddr_type_mask; + u32 reg_capabilities_misc_offset; + u32 reg_capabilities_misc_ibecc_dis; /* Memory controller registers. */ u32 reg_mad_inter_size_mask[NUM_CHANNELS]; u64 reg_mad_inter_size_granularity; @@ -405,27 +407,22 @@ static bool mtl_p_ibecc_available(struct pci_dev *pdev) return !(CAPID_E_IBECC_BIT18 & v); } -static bool mtl_ps_ibecc_available(struct pci_dev *pdev) +static bool generic_ibecc_available(struct pci_dev *pdev) { -#define MCHBAR_MEMSS_IBECCDIS 0x13c00 - void __iomem *window; - u64 mchbar; + void __iomem *base = igen6_pvt->memss_pma_cr; + bool present; u32 val; - if (get_mchbar(pdev, &mchbar)) - return false; - - window = ioremap(mchbar, MCHBAR_SIZE * 2); - if (!window) { - igen6_printk(KERN_ERR, "Failed to ioremap 0x%llx\n", mchbar); - return false; + if (res_cfg->reg_capabilities_misc_offset) { + val = readl(base + res_cfg->reg_capabilities_misc_offset); + present = !(val & res_cfg->reg_capabilities_misc_ibecc_dis); + edac_dbg(2, "capabilities misc reg 0x%x\n", val); + } else { + igen6_printk(KERN_ERR, "No register for detecting IBECC presence.\n"); + present = false; } - val = readl(window + MCHBAR_MEMSS_IBECCDIS); - iounmap(window); - - /* Bit6: 1 - IBECC is disabled, 0 - IBECC isn't disabled */ - return !GET_BITFIELD(val, 6, 6); + return present; } static u64 mem_addr_to_sys_addr(u64 maddr) @@ -725,18 +722,20 @@ 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, - .ibecc_available = mtl_ps_ibecc_available, - .err_addr_to_sys_addr = adl_err_addr_to_sys_addr, - .err_addr_to_imc_addr = adl_err_addr_to_imc_addr, + .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), + .reg_capabilities_misc_offset = 0x13c00, + .reg_capabilities_misc_ibecc_dis = BIT(6), + .imc_base = 0xd800, + .ibecc_base = 0xd400, + .ibecc_error_log_offset = 0x170, + .ibecc_available = generic_ibecc_available, + .err_addr_to_sys_addr = adl_err_addr_to_sys_addr, + .err_addr_to_imc_addr = adl_err_addr_to_imc_addr, }; static struct res_config mtl_p_cfg = { From 96780b953bac89bc624c3bf326a090f069d8d277 Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Thu, 21 May 2026 20:38:12 +0800 Subject: [PATCH 21/22] EDAC/igen6: Add Intel Nova Lake-H SoC support Nova Lake-H SoCs share similar memory controller registers and IBECC (In-Band ECC) registers with Panther Lake-H SoCs but use a new memory subsystem register for IBECC presence detection. Add Nova Lake-H SoC compute die IDs and create a new configuration structure for Nova Lake-H SoCs to enable EDAC support. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Tested-by: Jie Wang Link: https://patch.msgid.link/20260521123812.3961038-3-qiuxu.zhuo@intel.com --- drivers/edac/igen6_edac.c | 46 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c index a761d683eae3..9af15ac6ff84 100644 --- a/drivers/edac/igen6_edac.c +++ b/drivers/edac/igen6_edac.c @@ -151,6 +151,7 @@ static struct res_config { /* MEMSS_PMA_CR registers. */ u32 reg_mem_config_offset; u32 reg_mem_config_ddr_type_mask; + u32 reg_mem_config_ibecc_en_mask; u32 reg_capabilities_misc_offset; u32 reg_capabilities_misc_ibecc_dis; /* Memory controller registers. */ @@ -316,6 +317,12 @@ static struct work_struct ecclog_work; /* Compute die IDs for Wildcat Lake with IBECC */ #define DID_WCL_SKU1 0xfd00 +/* Compute die IDs for Nova Lake-H/HX with IBECC */ +#define DID_NVL_H_SKU1 0xd701 +#define DID_NVL_H_SKU2 0xd702 +#define DID_NVL_H_SKU3 0xd704 +#define DID_NVL_H_SKU4 0xd705 + static int get_mchbar(struct pci_dev *pdev, u64 *mchbar) { union { @@ -417,6 +424,10 @@ static bool generic_ibecc_available(struct pci_dev *pdev) val = readl(base + res_cfg->reg_capabilities_misc_offset); present = !(val & res_cfg->reg_capabilities_misc_ibecc_dis); edac_dbg(2, "capabilities misc reg 0x%x\n", val); + } else if (res_cfg->reg_mem_config_offset) { + val = readl(base + res_cfg->reg_mem_config_offset); + present = !!(val & res_cfg->reg_mem_config_ibecc_en_mask); + edac_dbg(2, "mem config reg 0x%x\n", val); } else { igen6_printk(KERN_ERR, "No register for detecting IBECC presence.\n"); present = false; @@ -798,6 +809,37 @@ static struct res_config wcl_cfg = { .err_addr_to_imc_addr = adl_err_addr_to_imc_addr, }; +static struct res_config nvl_h_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), + .reg_mem_config_offset = 0x12904, + .reg_mem_config_ddr_type_mask = GENMASK(8, 6), + .reg_mem_config_ibecc_en_mask = GENMASK(3, 2), + .reg_mad_inter_size_mask[0] = GENMASK(15, 8), + .reg_mad_inter_size_mask[1] = GENMASK(23, 16), + .reg_mad_inter_size_granularity = BIT_ULL(29), + .reg_mad_intra_rank_mask[0] = BIT(7), + .reg_mad_intra_rank_mask[1] = BIT(15), + .reg_mad_intra_width_mask[0] = BIT(6), + .reg_mad_intra_width_mask[1] = BIT(14), + .reg_mad_intra_density_mask[0] = GENMASK(3, 0), + .reg_mad_intra_density_mask[1] = GENMASK(11, 8), + .imc_base = 0xd800, + .ibecc_base = 0xd400, + .ibecc_error_log_offset = 0x170, + .get_mem_type = ptl_h_get_mem_type, + .get_dev_type = ptl_h_get_dev_type, + .set_chan_params = ptl_h_set_chan_params, + .set_dimm_params = ptl_h_set_dimm_params, + .ibecc_available = generic_ibecc_available, + .err_addr_to_sys_addr = adl_err_addr_to_sys_addr, + .err_addr_to_imc_addr = adl_err_addr_to_imc_addr, +}; + static struct pci_device_id igen6_pci_tbl[] = { { PCI_VDEVICE(INTEL, DID_EHL_SKU5), (kernel_ulong_t)&ehl_cfg }, { PCI_VDEVICE(INTEL, DID_EHL_SKU6), (kernel_ulong_t)&ehl_cfg }, @@ -865,6 +907,10 @@ static struct pci_device_id igen6_pci_tbl[] = { { PCI_VDEVICE(INTEL, DID_PTL_H_SKU13), (kernel_ulong_t)&ptl_h_cfg }, { PCI_VDEVICE(INTEL, DID_PTL_H_SKU14), (kernel_ulong_t)&ptl_h_cfg }, { PCI_VDEVICE(INTEL, DID_WCL_SKU1), (kernel_ulong_t)&wcl_cfg }, + { PCI_VDEVICE(INTEL, DID_NVL_H_SKU1), (kernel_ulong_t)&nvl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_NVL_H_SKU2), (kernel_ulong_t)&nvl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_NVL_H_SKU3), (kernel_ulong_t)&nvl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_NVL_H_SKU4), (kernel_ulong_t)&nvl_h_cfg }, { }, }; MODULE_DEVICE_TABLE(pci, igen6_pci_tbl); From 78d86a71de6ea70c6228e7817f3962c618c1eb54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Wed, 27 May 2026 08:10:56 +0200 Subject: [PATCH 22/22] EDAC: Consistently define pci_device_ids using named initializers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... and PCI device helpers. The various struct pci_device_id arrays were initialized mostly by one of the PCI_DEVICE macros and then list expressions. The latter aren't easily readable if you're not into PCI. Using named initializers is more explicit and thus easier to parse. Also use PCI_DEVICE* helper macros to assign .vendor, .device, .subvendor and .subdevice where appropriate and skip explicit assignments of 0 (which the compiler takes care of). The secret plan is to make struct pci_device_id::driver_data an anonymous union (similar to https://lore.kernel.org/all/cover.1776579304.git.u.kleine-koenig@baylibre.com/ and that requires named initializers. But it's also a nice cleanup on its own. [ bp: Massage commit message. ] Signed-off-by: Uwe Kleine-König (The Capable Hub) Signed-off-by: Borislav Petkov (AMD) Signed-off-by: Tony Luck Reviewed-by: Qiuxu Zhuo Tested-by: Qiuxu Zhuo Link: https://patch.msgid.link/20260527061057.3796383-2-u.kleine-koenig@baylibre.com --- drivers/edac/amd76x_edac.c | 16 ++--- drivers/edac/e752x_edac.c | 28 ++++---- drivers/edac/e7xxx_edac.c | 28 ++++---- drivers/edac/edac_mc.h | 4 +- drivers/edac/i3000_edac.c | 10 +-- drivers/edac/i3200_edac.c | 10 +-- drivers/edac/i82860_edac.c | 10 +-- drivers/edac/i82875p_edac.c | 12 ++-- drivers/edac/i82975x_edac.c | 11 ++- drivers/edac/ie31200_edac.c | 86 +++++++++++----------- drivers/edac/igen6_edac.c | 140 ++++++++++++++++++------------------ drivers/edac/x38_edac.c | 10 +-- 12 files changed, 182 insertions(+), 183 deletions(-) diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c index 2a49f68a7cf9..7bb11ffdb0c9 100644 --- a/drivers/edac/amd76x_edac.c +++ b/drivers/edac/amd76x_edac.c @@ -332,14 +332,14 @@ static void amd76x_remove_one(struct pci_dev *pdev) static const struct pci_device_id amd76x_pci_tbl[] = { { - PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - AMD762}, - { - PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - AMD761}, - { - 0, - } /* 0 terminated list. */ + PCI_VEND_DEV(AMD, FE_GATE_700C), + .driver_data = AMD762 + }, { + PCI_VEND_DEV(AMD, FE_GATE_700E), + .driver_data = AMD761, + }, { + /* 0 terminated list. */ + } }; MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl); diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index 7221b4bb6df2..77c1fe75451e 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c @@ -1414,20 +1414,20 @@ static void e752x_remove_one(struct pci_dev *pdev) static const struct pci_device_id e752x_pci_tbl[] = { { - PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - E7520}, - { - PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - E7525}, - { - PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - E7320}, - { - PCI_VEND_DEV(INTEL, 3100_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - I3100}, - { - 0, - } /* 0 terminated list. */ + PCI_VEND_DEV(INTEL, 7520_0), + .driver_data = E7520, + }, { + PCI_VEND_DEV(INTEL, 7525_0), + .driver_data = E7525, + }, { + PCI_VEND_DEV(INTEL, 7320_0), + .driver_data = E7320, + }, { + PCI_VEND_DEV(INTEL, 3100_0), + .driver_data = I3100, + }, { + /* 0 terminated list. */ + } }; MODULE_DEVICE_TABLE(pci, e752x_pci_tbl); diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c index 5852b95fa470..02071180b638 100644 --- a/drivers/edac/e7xxx_edac.c +++ b/drivers/edac/e7xxx_edac.c @@ -554,20 +554,20 @@ static void e7xxx_remove_one(struct pci_dev *pdev) static const struct pci_device_id e7xxx_pci_tbl[] = { { - PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - E7205}, - { - PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - E7500}, - { - PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - E7501}, - { - PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - E7505}, - { - 0, - } /* 0 terminated list. */ + PCI_VEND_DEV(INTEL, 7205_0), + .driver_data = E7205, + }, { + PCI_VEND_DEV(INTEL, 7500_0), + .driver_data = E7500, + }, { + PCI_VEND_DEV(INTEL, 7501_0), + .driver_data = E7501, + }, { + PCI_VEND_DEV(INTEL, 7505_0), + .driver_data = E7505 + }, { + /* 0 terminated list. */ + } }; MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl); diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h index 881b00eadf7a..9505bbd41784 100644 --- a/drivers/edac/edac_mc.h +++ b/drivers/edac/edac_mc.h @@ -88,8 +88,8 @@ do { \ #endif /* !CONFIG_EDAC_DEBUG */ -#define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \ - PCI_DEVICE_ID_ ## vend ## _ ## dev +#define PCI_VEND_DEV(vend, dev) \ + PCI_DEVICE(PCI_VENDOR_ID_ ## vend, PCI_DEVICE_ID_ ## vend ## _ ## dev) #define edac_dev_name(dev) (dev)->dev_name diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c index 9065bc4386ff..04a231660b88 100644 --- a/drivers/edac/i3000_edac.c +++ b/drivers/edac/i3000_edac.c @@ -485,11 +485,11 @@ static void i3000_remove_one(struct pci_dev *pdev) static const struct pci_device_id i3000_pci_tbl[] = { { - PCI_VEND_DEV(INTEL, 3000_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - I3000}, - { - 0, - } /* 0 terminated list. */ + PCI_VEND_DEV(INTEL, 3000_HB), + .driver_data = I3000, + }, { + /* 0 terminated list. */ + } }; MODULE_DEVICE_TABLE(pci, i3000_pci_tbl); diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c index 6cade6d7ceff..d600b6c05217 100644 --- a/drivers/edac/i3200_edac.c +++ b/drivers/edac/i3200_edac.c @@ -466,11 +466,11 @@ static void i3200_remove_one(struct pci_dev *pdev) static const struct pci_device_id i3200_pci_tbl[] = { { - PCI_VEND_DEV(INTEL, 3200_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - I3200}, - { - 0, - } /* 0 terminated list. */ + PCI_VEND_DEV(INTEL, 3200_HB), + .driver_data = I3200, + }, { + /* 0 terminated list. */ + } }; MODULE_DEVICE_TABLE(pci, i3200_pci_tbl); diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c index b8a497f0de28..e8c1ee80bba8 100644 --- a/drivers/edac/i82860_edac.c +++ b/drivers/edac/i82860_edac.c @@ -287,11 +287,11 @@ static void i82860_remove_one(struct pci_dev *pdev) static const struct pci_device_id i82860_pci_tbl[] = { { - PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - I82860}, - { - 0, - } /* 0 terminated list. */ + PCI_VEND_DEV(INTEL, 82860_0), + .driver_data = I82860, + }, { + /* 0 terminated list. */ + } }; MODULE_DEVICE_TABLE(pci, i82860_pci_tbl); diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c index 553880b9fc12..869de8e372b3 100644 --- a/drivers/edac/i82875p_edac.c +++ b/drivers/edac/i82875p_edac.c @@ -276,7 +276,7 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev, *ovrfl_pdev = NULL; *ovrfl_window = NULL; - dev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL); + dev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82875_6, NULL); if (dev == NULL) { /* Intel tells BIOS developers to hide device 6 which @@ -518,11 +518,11 @@ static void i82875p_remove_one(struct pci_dev *pdev) static const struct pci_device_id i82875p_pci_tbl[] = { { - PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - I82875P}, - { - 0, - } /* 0 terminated list. */ + PCI_VEND_DEV(INTEL, 82875_0), + .driver_data = I82875P, + }, { + /* 0 terminated list. */ + } }; MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl); diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c index d99f005832cf..09a79eaaa486 100644 --- a/drivers/edac/i82975x_edac.c +++ b/drivers/edac/i82975x_edac.c @@ -624,12 +624,11 @@ static void i82975x_remove_one(struct pci_dev *pdev) static const struct pci_device_id i82975x_pci_tbl[] = { { - PCI_VEND_DEV(INTEL, 82975_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - I82975X - }, - { - 0, - } /* 0 terminated list. */ + PCI_VEND_DEV(INTEL, 82975_0), + .driver_data = I82975X + }, { + /* 0 terminated list. */ + } }; MODULE_DEVICE_TABLE(pci, i82975x_pci_tbl); diff --git a/drivers/edac/ie31200_edac.c b/drivers/edac/ie31200_edac.c index a5dc4b88097f..e3bd6436669b 100644 --- a/drivers/edac/ie31200_edac.c +++ b/drivers/edac/ie31200_edac.c @@ -733,49 +733,49 @@ static struct res_config rpl_s_cfg = { }; static const struct pci_device_id ie31200_pci_tbl[] = { - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_1), (kernel_ulong_t)&snb_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_2), (kernel_ulong_t)&snb_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_3), (kernel_ulong_t)&snb_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_4), (kernel_ulong_t)&snb_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_5), (kernel_ulong_t)&snb_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_6), (kernel_ulong_t)&snb_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_7), (kernel_ulong_t)&snb_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_8), (kernel_ulong_t)&skl_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_9), (kernel_ulong_t)&skl_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_10), (kernel_ulong_t)&skl_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_11), (kernel_ulong_t)&skl_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_12), (kernel_ulong_t)&skl_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_1), (kernel_ulong_t)&skl_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_2), (kernel_ulong_t)&skl_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_3), (kernel_ulong_t)&skl_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_4), (kernel_ulong_t)&skl_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_5), (kernel_ulong_t)&skl_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_6), (kernel_ulong_t)&skl_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_7), (kernel_ulong_t)&skl_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_8), (kernel_ulong_t)&skl_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_9), (kernel_ulong_t)&skl_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_10), (kernel_ulong_t)&skl_cfg }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_1), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_2), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_3), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_4), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_5), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_6), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_HX_1), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_ADL_S_1), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_ADL_S_2), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_ADL_S_3), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_1), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_2), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_3), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_4), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_5), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_6), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_7), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_8), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_9), (kernel_ulong_t)&rpl_s_cfg}, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_10), (kernel_ulong_t)&rpl_s_cfg}, - { 0, } /* 0 terminated list. */ + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_1), .driver_data = (kernel_ulong_t)&snb_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_2), .driver_data = (kernel_ulong_t)&snb_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_3), .driver_data = (kernel_ulong_t)&snb_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_4), .driver_data = (kernel_ulong_t)&snb_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_5), .driver_data = (kernel_ulong_t)&snb_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_6), .driver_data = (kernel_ulong_t)&snb_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_7), .driver_data = (kernel_ulong_t)&snb_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_8), .driver_data = (kernel_ulong_t)&skl_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_9), .driver_data = (kernel_ulong_t)&skl_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_10), .driver_data = (kernel_ulong_t)&skl_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_11), .driver_data = (kernel_ulong_t)&skl_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_12), .driver_data = (kernel_ulong_t)&skl_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_1), .driver_data = (kernel_ulong_t)&skl_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_2), .driver_data = (kernel_ulong_t)&skl_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_3), .driver_data = (kernel_ulong_t)&skl_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_4), .driver_data = (kernel_ulong_t)&skl_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_5), .driver_data = (kernel_ulong_t)&skl_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_6), .driver_data = (kernel_ulong_t)&skl_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_7), .driver_data = (kernel_ulong_t)&skl_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_8), .driver_data = (kernel_ulong_t)&skl_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_9), .driver_data = (kernel_ulong_t)&skl_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_10), .driver_data = (kernel_ulong_t)&skl_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_1), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_2), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_3), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_4), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_5), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_6), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_HX_1), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_ADL_S_1), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_ADL_S_2), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_ADL_S_3), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_1), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_2), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_3), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_4), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_5), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_6), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_7), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_8), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_9), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_10), .driver_data = (kernel_ulong_t)&rpl_s_cfg }, + { } /* 0 terminated list. */ }; MODULE_DEVICE_TABLE(pci, ie31200_pci_tbl); diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c index 9af15ac6ff84..f1fc20d4ebf6 100644 --- a/drivers/edac/igen6_edac.c +++ b/drivers/edac/igen6_edac.c @@ -841,76 +841,76 @@ static struct res_config nvl_h_cfg = { }; static struct pci_device_id igen6_pci_tbl[] = { - { PCI_VDEVICE(INTEL, DID_EHL_SKU5), (kernel_ulong_t)&ehl_cfg }, - { PCI_VDEVICE(INTEL, DID_EHL_SKU6), (kernel_ulong_t)&ehl_cfg }, - { PCI_VDEVICE(INTEL, DID_EHL_SKU7), (kernel_ulong_t)&ehl_cfg }, - { PCI_VDEVICE(INTEL, DID_EHL_SKU8), (kernel_ulong_t)&ehl_cfg }, - { PCI_VDEVICE(INTEL, DID_EHL_SKU9), (kernel_ulong_t)&ehl_cfg }, - { PCI_VDEVICE(INTEL, DID_EHL_SKU10), (kernel_ulong_t)&ehl_cfg }, - { PCI_VDEVICE(INTEL, DID_EHL_SKU11), (kernel_ulong_t)&ehl_cfg }, - { PCI_VDEVICE(INTEL, DID_EHL_SKU12), (kernel_ulong_t)&ehl_cfg }, - { PCI_VDEVICE(INTEL, DID_EHL_SKU13), (kernel_ulong_t)&ehl_cfg }, - { PCI_VDEVICE(INTEL, DID_EHL_SKU14), (kernel_ulong_t)&ehl_cfg }, - { PCI_VDEVICE(INTEL, DID_EHL_SKU15), (kernel_ulong_t)&ehl_cfg }, - { PCI_VDEVICE(INTEL, DID_ICL_SKU8), (kernel_ulong_t)&icl_cfg }, - { PCI_VDEVICE(INTEL, DID_ICL_SKU10), (kernel_ulong_t)&icl_cfg }, - { PCI_VDEVICE(INTEL, DID_ICL_SKU11), (kernel_ulong_t)&icl_cfg }, - { PCI_VDEVICE(INTEL, DID_ICL_SKU12), (kernel_ulong_t)&icl_cfg }, - { PCI_VDEVICE(INTEL, DID_TGL_SKU), (kernel_ulong_t)&tgl_cfg }, - { PCI_VDEVICE(INTEL, DID_ADL_SKU1), (kernel_ulong_t)&adl_cfg }, - { PCI_VDEVICE(INTEL, DID_ADL_SKU2), (kernel_ulong_t)&adl_cfg }, - { PCI_VDEVICE(INTEL, DID_ADL_SKU3), (kernel_ulong_t)&adl_cfg }, - { PCI_VDEVICE(INTEL, DID_ADL_SKU4), (kernel_ulong_t)&adl_cfg }, - { PCI_VDEVICE(INTEL, DID_ADL_N_SKU1), (kernel_ulong_t)&adl_n_cfg }, - { PCI_VDEVICE(INTEL, DID_ADL_N_SKU2), (kernel_ulong_t)&adl_n_cfg }, - { PCI_VDEVICE(INTEL, DID_ADL_N_SKU3), (kernel_ulong_t)&adl_n_cfg }, - { PCI_VDEVICE(INTEL, DID_ADL_N_SKU4), (kernel_ulong_t)&adl_n_cfg }, - { PCI_VDEVICE(INTEL, DID_ADL_N_SKU5), (kernel_ulong_t)&adl_n_cfg }, - { PCI_VDEVICE(INTEL, DID_ADL_N_SKU6), (kernel_ulong_t)&adl_n_cfg }, - { PCI_VDEVICE(INTEL, DID_ADL_N_SKU7), (kernel_ulong_t)&adl_n_cfg }, - { PCI_VDEVICE(INTEL, DID_ADL_N_SKU8), (kernel_ulong_t)&adl_n_cfg }, - { PCI_VDEVICE(INTEL, DID_ADL_N_SKU9), (kernel_ulong_t)&adl_n_cfg }, - { PCI_VDEVICE(INTEL, DID_ADL_N_SKU10), (kernel_ulong_t)&adl_n_cfg }, - { PCI_VDEVICE(INTEL, DID_ADL_N_SKU11), (kernel_ulong_t)&adl_n_cfg }, - { 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 }, - { PCI_VDEVICE(INTEL, DID_RPL_P_SKU4), (kernel_ulong_t)&rpl_p_cfg }, - { PCI_VDEVICE(INTEL, DID_RPL_P_SKU5), (kernel_ulong_t)&rpl_p_cfg }, - { PCI_VDEVICE(INTEL, DID_MTL_PS_SKU1), (kernel_ulong_t)&mtl_ps_cfg }, - { PCI_VDEVICE(INTEL, DID_MTL_PS_SKU2), (kernel_ulong_t)&mtl_ps_cfg }, - { PCI_VDEVICE(INTEL, DID_MTL_PS_SKU3), (kernel_ulong_t)&mtl_ps_cfg }, - { PCI_VDEVICE(INTEL, DID_MTL_PS_SKU4), (kernel_ulong_t)&mtl_ps_cfg }, - { PCI_VDEVICE(INTEL, DID_MTL_P_SKU1), (kernel_ulong_t)&mtl_p_cfg }, - { PCI_VDEVICE(INTEL, DID_MTL_P_SKU2), (kernel_ulong_t)&mtl_p_cfg }, - { PCI_VDEVICE(INTEL, DID_MTL_P_SKU3), (kernel_ulong_t)&mtl_p_cfg }, - { PCI_VDEVICE(INTEL, DID_ARL_UH_SKU1), (kernel_ulong_t)&mtl_p_cfg }, - { PCI_VDEVICE(INTEL, DID_ARL_UH_SKU2), (kernel_ulong_t)&mtl_p_cfg }, - { PCI_VDEVICE(INTEL, DID_ARL_UH_SKU3), (kernel_ulong_t)&mtl_p_cfg }, - { PCI_VDEVICE(INTEL, DID_PTL_H_SKU1), (kernel_ulong_t)&ptl_h_cfg }, - { PCI_VDEVICE(INTEL, DID_PTL_H_SKU2), (kernel_ulong_t)&ptl_h_cfg }, - { PCI_VDEVICE(INTEL, DID_PTL_H_SKU3), (kernel_ulong_t)&ptl_h_cfg }, - { PCI_VDEVICE(INTEL, DID_PTL_H_SKU4), (kernel_ulong_t)&ptl_h_cfg }, - { PCI_VDEVICE(INTEL, DID_PTL_H_SKU5), (kernel_ulong_t)&ptl_h_cfg }, - { PCI_VDEVICE(INTEL, DID_PTL_H_SKU6), (kernel_ulong_t)&ptl_h_cfg }, - { PCI_VDEVICE(INTEL, DID_PTL_H_SKU7), (kernel_ulong_t)&ptl_h_cfg }, - { PCI_VDEVICE(INTEL, DID_PTL_H_SKU8), (kernel_ulong_t)&ptl_h_cfg }, - { PCI_VDEVICE(INTEL, DID_PTL_H_SKU9), (kernel_ulong_t)&ptl_h_cfg }, - { PCI_VDEVICE(INTEL, DID_PTL_H_SKU10), (kernel_ulong_t)&ptl_h_cfg }, - { PCI_VDEVICE(INTEL, DID_PTL_H_SKU11), (kernel_ulong_t)&ptl_h_cfg }, - { PCI_VDEVICE(INTEL, DID_PTL_H_SKU12), (kernel_ulong_t)&ptl_h_cfg }, - { PCI_VDEVICE(INTEL, DID_PTL_H_SKU13), (kernel_ulong_t)&ptl_h_cfg }, - { PCI_VDEVICE(INTEL, DID_PTL_H_SKU14), (kernel_ulong_t)&ptl_h_cfg }, - { PCI_VDEVICE(INTEL, DID_WCL_SKU1), (kernel_ulong_t)&wcl_cfg }, - { PCI_VDEVICE(INTEL, DID_NVL_H_SKU1), (kernel_ulong_t)&nvl_h_cfg }, - { PCI_VDEVICE(INTEL, DID_NVL_H_SKU2), (kernel_ulong_t)&nvl_h_cfg }, - { PCI_VDEVICE(INTEL, DID_NVL_H_SKU3), (kernel_ulong_t)&nvl_h_cfg }, - { PCI_VDEVICE(INTEL, DID_NVL_H_SKU4), (kernel_ulong_t)&nvl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_EHL_SKU5), .driver_data = (kernel_ulong_t)&ehl_cfg }, + { PCI_VDEVICE(INTEL, DID_EHL_SKU6), .driver_data = (kernel_ulong_t)&ehl_cfg }, + { PCI_VDEVICE(INTEL, DID_EHL_SKU7), .driver_data = (kernel_ulong_t)&ehl_cfg }, + { PCI_VDEVICE(INTEL, DID_EHL_SKU8), .driver_data = (kernel_ulong_t)&ehl_cfg }, + { PCI_VDEVICE(INTEL, DID_EHL_SKU9), .driver_data = (kernel_ulong_t)&ehl_cfg }, + { PCI_VDEVICE(INTEL, DID_EHL_SKU10), .driver_data = (kernel_ulong_t)&ehl_cfg }, + { PCI_VDEVICE(INTEL, DID_EHL_SKU11), .driver_data = (kernel_ulong_t)&ehl_cfg }, + { PCI_VDEVICE(INTEL, DID_EHL_SKU12), .driver_data = (kernel_ulong_t)&ehl_cfg }, + { PCI_VDEVICE(INTEL, DID_EHL_SKU13), .driver_data = (kernel_ulong_t)&ehl_cfg }, + { PCI_VDEVICE(INTEL, DID_EHL_SKU14), .driver_data = (kernel_ulong_t)&ehl_cfg }, + { PCI_VDEVICE(INTEL, DID_EHL_SKU15), .driver_data = (kernel_ulong_t)&ehl_cfg }, + { PCI_VDEVICE(INTEL, DID_ICL_SKU8), .driver_data = (kernel_ulong_t)&icl_cfg }, + { PCI_VDEVICE(INTEL, DID_ICL_SKU10), .driver_data = (kernel_ulong_t)&icl_cfg }, + { PCI_VDEVICE(INTEL, DID_ICL_SKU11), .driver_data = (kernel_ulong_t)&icl_cfg }, + { PCI_VDEVICE(INTEL, DID_ICL_SKU12), .driver_data = (kernel_ulong_t)&icl_cfg }, + { PCI_VDEVICE(INTEL, DID_TGL_SKU), .driver_data = (kernel_ulong_t)&tgl_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_SKU1), .driver_data = (kernel_ulong_t)&adl_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_SKU2), .driver_data = (kernel_ulong_t)&adl_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_SKU3), .driver_data = (kernel_ulong_t)&adl_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_SKU4), .driver_data = (kernel_ulong_t)&adl_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU1), .driver_data = (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU2), .driver_data = (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU3), .driver_data = (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU4), .driver_data = (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU5), .driver_data = (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU6), .driver_data = (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU7), .driver_data = (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU8), .driver_data = (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU9), .driver_data = (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU10), .driver_data = (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU11), .driver_data = (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU12), .driver_data = (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_AZB_SKU1), .driver_data = (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ASL_SKU1), .driver_data = (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ASL_SKU2), .driver_data = (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ASL_SKU3), .driver_data = (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_RPL_P_SKU1), .driver_data = (kernel_ulong_t)&rpl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_RPL_P_SKU2), .driver_data = (kernel_ulong_t)&rpl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_RPL_P_SKU3), .driver_data = (kernel_ulong_t)&rpl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_RPL_P_SKU4), .driver_data = (kernel_ulong_t)&rpl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_RPL_P_SKU5), .driver_data = (kernel_ulong_t)&rpl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_MTL_PS_SKU1), .driver_data = (kernel_ulong_t)&mtl_ps_cfg }, + { PCI_VDEVICE(INTEL, DID_MTL_PS_SKU2), .driver_data = (kernel_ulong_t)&mtl_ps_cfg }, + { PCI_VDEVICE(INTEL, DID_MTL_PS_SKU3), .driver_data = (kernel_ulong_t)&mtl_ps_cfg }, + { PCI_VDEVICE(INTEL, DID_MTL_PS_SKU4), .driver_data = (kernel_ulong_t)&mtl_ps_cfg }, + { PCI_VDEVICE(INTEL, DID_MTL_P_SKU1), .driver_data = (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_MTL_P_SKU2), .driver_data = (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_MTL_P_SKU3), .driver_data = (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_ARL_UH_SKU1), .driver_data = (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_ARL_UH_SKU2), .driver_data = (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_ARL_UH_SKU3), .driver_data = (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU1), .driver_data = (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU2), .driver_data = (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU3), .driver_data = (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU4), .driver_data = (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU5), .driver_data = (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU6), .driver_data = (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU7), .driver_data = (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU8), .driver_data = (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU9), .driver_data = (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU10), .driver_data = (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU11), .driver_data = (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU12), .driver_data = (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU13), .driver_data = (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU14), .driver_data = (kernel_ulong_t)&ptl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_WCL_SKU1), .driver_data = (kernel_ulong_t)&wcl_cfg }, + { PCI_VDEVICE(INTEL, DID_NVL_H_SKU1), .driver_data = (kernel_ulong_t)&nvl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_NVL_H_SKU2), .driver_data = (kernel_ulong_t)&nvl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_NVL_H_SKU3), .driver_data = (kernel_ulong_t)&nvl_h_cfg }, + { PCI_VDEVICE(INTEL, DID_NVL_H_SKU4), .driver_data = (kernel_ulong_t)&nvl_h_cfg }, { }, }; MODULE_DEVICE_TABLE(pci, igen6_pci_tbl); diff --git a/drivers/edac/x38_edac.c b/drivers/edac/x38_edac.c index 292dda754c23..2b55daca33b0 100644 --- a/drivers/edac/x38_edac.c +++ b/drivers/edac/x38_edac.c @@ -446,11 +446,11 @@ static void x38_remove_one(struct pci_dev *pdev) static const struct pci_device_id x38_pci_tbl[] = { { - PCI_VEND_DEV(INTEL, X38_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0, - X38}, - { - 0, - } /* 0 terminated list. */ + PCI_VEND_DEV(INTEL, X38_HB), + .driver_data = X38, + }, { + /* 0 terminated list. */ + } }; MODULE_DEVICE_TABLE(pci, x38_pci_tbl);