]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
EDAC/igen6: Add Intel Nova Lake-H SoC support
authorQiuxu Zhuo <qiuxu.zhuo@intel.com>
Thu, 21 May 2026 12:38:12 +0000 (20:38 +0800)
committerTony Luck <tony.luck@intel.com>
Fri, 29 May 2026 15:34:13 +0000 (08:34 -0700)
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 <qiuxu.zhuo@intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Tested-by: Jie Wang <jie.wang@intel.com>
Link: https://patch.msgid.link/20260521123812.3961038-3-qiuxu.zhuo@intel.com
drivers/edac/igen6_edac.c

index a761d683eae335a74326c42598c2a0f39e5ce96f..9af15ac6ff84ac43511bd2e7fa3477e6b11735df 100644 (file)
@@ -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);