Skip to content

Commit 20e190b

Browse files
qzhuo2aegl
authored andcommitted
EDAC/igen6: Skip absent memory controllers
Some BIOS versions may fuse off certain memory controllers and set the registers of these absent memory controllers to ~0. The current igen6_edac mistakenly enumerates these absent memory controllers and registers them with the EDAC core. Skip the absent memory controllers to avoid mistakenly enumerating them. Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com> Signed-off-by: Tony Luck <tony.luck@intel.com> Link: https://lore.kernel.org/r/20250408132455.489046-2-qiuxu.zhuo@intel.com
1 parent 8ffd015 commit 20e190b

File tree

1 file changed

+62
-16
lines changed

1 file changed

+62
-16
lines changed

drivers/edac/igen6_edac.c

Lines changed: 62 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127

128128
static const struct res_config {
129129
bool machine_check;
130+
/* The number of present memory controllers. */
130131
int num_imc;
131132
u32 imc_base;
132133
u32 cmf_base;
@@ -1201,23 +1202,21 @@ static void igen6_check(struct mem_ctl_info *mci)
12011202
irq_work_queue(&ecclog_irq_work);
12021203
}
12031204

1204-
static int igen6_register_mci(int mc, u64 mchbar, struct pci_dev *pdev)
1205+
/* Check whether the memory controller is absent. */
1206+
static bool igen6_imc_absent(void __iomem *window)
1207+
{
1208+
return readl(window + MAD_INTER_CHANNEL_OFFSET) == ~0;
1209+
}
1210+
1211+
static int igen6_register_mci(int mc, void __iomem *window, struct pci_dev *pdev)
12051212
{
12061213
struct edac_mc_layer layers[2];
12071214
struct mem_ctl_info *mci;
12081215
struct igen6_imc *imc;
1209-
void __iomem *window;
12101216
int rc;
12111217

12121218
edac_dbg(2, "\n");
12131219

1214-
mchbar += mc * MCHBAR_SIZE;
1215-
window = ioremap(mchbar, MCHBAR_SIZE);
1216-
if (!window) {
1217-
igen6_printk(KERN_ERR, "Failed to ioremap 0x%llx\n", mchbar);
1218-
return -ENODEV;
1219-
}
1220-
12211220
layers[0].type = EDAC_MC_LAYER_CHANNEL;
12221221
layers[0].size = NUM_CHANNELS;
12231222
layers[0].is_virt_csrow = false;
@@ -1283,7 +1282,6 @@ static int igen6_register_mci(int mc, u64 mchbar, struct pci_dev *pdev)
12831282
fail2:
12841283
edac_mc_free(mci);
12851284
fail:
1286-
iounmap(window);
12871285
return rc;
12881286
}
12891287

@@ -1309,6 +1307,56 @@ static void igen6_unregister_mcis(void)
13091307
}
13101308
}
13111309

1310+
static int igen6_register_mcis(struct pci_dev *pdev, u64 mchbar)
1311+
{
1312+
void __iomem *window;
1313+
int lmc, pmc, rc;
1314+
u64 base;
1315+
1316+
for (lmc = 0, pmc = 0; pmc < NUM_IMC; pmc++) {
1317+
base = mchbar + pmc * MCHBAR_SIZE;
1318+
window = ioremap(base, MCHBAR_SIZE);
1319+
if (!window) {
1320+
igen6_printk(KERN_ERR, "Failed to ioremap 0x%llx for mc%d\n", base, pmc);
1321+
rc = -ENOMEM;
1322+
goto out_unregister_mcis;
1323+
}
1324+
1325+
if (igen6_imc_absent(window)) {
1326+
iounmap(window);
1327+
edac_dbg(2, "Skip absent mc%d\n", pmc);
1328+
continue;
1329+
}
1330+
1331+
rc = igen6_register_mci(lmc, window, pdev);
1332+
if (rc)
1333+
goto out_iounmap;
1334+
1335+
/* Done, if all present MCs are detected and registered. */
1336+
if (++lmc >= res_cfg->num_imc)
1337+
break;
1338+
}
1339+
1340+
if (!lmc) {
1341+
igen6_printk(KERN_ERR, "No mc found.\n");
1342+
return -ENODEV;
1343+
}
1344+
1345+
if (lmc < res_cfg->num_imc)
1346+
igen6_printk(KERN_WARNING, "Expected %d mcs, but only %d detected.",
1347+
res_cfg->num_imc, lmc);
1348+
1349+
return 0;
1350+
1351+
out_iounmap:
1352+
iounmap(window);
1353+
1354+
out_unregister_mcis:
1355+
igen6_unregister_mcis();
1356+
1357+
return rc;
1358+
}
1359+
13121360
static int igen6_mem_slice_setup(u64 mchbar)
13131361
{
13141362
struct igen6_imc *imc = &igen6_pvt->imc[0];
@@ -1405,7 +1453,7 @@ static void opstate_set(const struct res_config *cfg, const struct pci_device_id
14051453
static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
14061454
{
14071455
u64 mchbar;
1408-
int i, rc;
1456+
int rc;
14091457

14101458
edac_dbg(2, "\n");
14111459

@@ -1421,11 +1469,9 @@ static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
14211469

14221470
opstate_set(res_cfg, ent);
14231471

1424-
for (i = 0; i < res_cfg->num_imc; i++) {
1425-
rc = igen6_register_mci(i, mchbar, pdev);
1426-
if (rc)
1427-
goto fail2;
1428-
}
1472+
rc = igen6_register_mcis(pdev, mchbar);
1473+
if (rc)
1474+
goto fail;
14291475

14301476
if (res_cfg->num_imc > 1) {
14311477
rc = igen6_mem_slice_setup(mchbar);

0 commit comments

Comments
 (0)