mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
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
This commit is contained in:
parent
8ffd015db8
commit
20e190b1c1
@ -127,6 +127,7 @@
|
||||
|
||||
static const struct res_config {
|
||||
bool machine_check;
|
||||
/* The number of present memory controllers. */
|
||||
int num_imc;
|
||||
u32 imc_base;
|
||||
u32 cmf_base;
|
||||
@ -1201,23 +1202,21 @@ static void igen6_check(struct mem_ctl_info *mci)
|
||||
irq_work_queue(&ecclog_irq_work);
|
||||
}
|
||||
|
||||
static int igen6_register_mci(int mc, u64 mchbar, struct pci_dev *pdev)
|
||||
/* Check whether the memory controller is absent. */
|
||||
static bool igen6_imc_absent(void __iomem *window)
|
||||
{
|
||||
return readl(window + MAD_INTER_CHANNEL_OFFSET) == ~0;
|
||||
}
|
||||
|
||||
static int igen6_register_mci(int mc, void __iomem *window, struct pci_dev *pdev)
|
||||
{
|
||||
struct edac_mc_layer layers[2];
|
||||
struct mem_ctl_info *mci;
|
||||
struct igen6_imc *imc;
|
||||
void __iomem *window;
|
||||
int rc;
|
||||
|
||||
edac_dbg(2, "\n");
|
||||
|
||||
mchbar += mc * MCHBAR_SIZE;
|
||||
window = ioremap(mchbar, MCHBAR_SIZE);
|
||||
if (!window) {
|
||||
igen6_printk(KERN_ERR, "Failed to ioremap 0x%llx\n", mchbar);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
layers[0].type = EDAC_MC_LAYER_CHANNEL;
|
||||
layers[0].size = NUM_CHANNELS;
|
||||
layers[0].is_virt_csrow = false;
|
||||
@ -1283,7 +1282,6 @@ fail3:
|
||||
fail2:
|
||||
edac_mc_free(mci);
|
||||
fail:
|
||||
iounmap(window);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1309,6 +1307,56 @@ static void igen6_unregister_mcis(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int igen6_register_mcis(struct pci_dev *pdev, u64 mchbar)
|
||||
{
|
||||
void __iomem *window;
|
||||
int lmc, pmc, rc;
|
||||
u64 base;
|
||||
|
||||
for (lmc = 0, pmc = 0; pmc < NUM_IMC; pmc++) {
|
||||
base = mchbar + pmc * MCHBAR_SIZE;
|
||||
window = ioremap(base, MCHBAR_SIZE);
|
||||
if (!window) {
|
||||
igen6_printk(KERN_ERR, "Failed to ioremap 0x%llx for mc%d\n", base, pmc);
|
||||
rc = -ENOMEM;
|
||||
goto out_unregister_mcis;
|
||||
}
|
||||
|
||||
if (igen6_imc_absent(window)) {
|
||||
iounmap(window);
|
||||
edac_dbg(2, "Skip absent mc%d\n", pmc);
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = igen6_register_mci(lmc, window, pdev);
|
||||
if (rc)
|
||||
goto out_iounmap;
|
||||
|
||||
/* Done, if all present MCs are detected and registered. */
|
||||
if (++lmc >= res_cfg->num_imc)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!lmc) {
|
||||
igen6_printk(KERN_ERR, "No mc found.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (lmc < res_cfg->num_imc)
|
||||
igen6_printk(KERN_WARNING, "Expected %d mcs, but only %d detected.",
|
||||
res_cfg->num_imc, lmc);
|
||||
|
||||
return 0;
|
||||
|
||||
out_iounmap:
|
||||
iounmap(window);
|
||||
|
||||
out_unregister_mcis:
|
||||
igen6_unregister_mcis();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int igen6_mem_slice_setup(u64 mchbar)
|
||||
{
|
||||
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
|
||||
static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
u64 mchbar;
|
||||
int i, rc;
|
||||
int rc;
|
||||
|
||||
edac_dbg(2, "\n");
|
||||
|
||||
@ -1421,11 +1469,9 @@ static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
||||
opstate_set(res_cfg, ent);
|
||||
|
||||
for (i = 0; i < res_cfg->num_imc; i++) {
|
||||
rc = igen6_register_mci(i, mchbar, pdev);
|
||||
if (rc)
|
||||
goto fail2;
|
||||
}
|
||||
rc = igen6_register_mcis(pdev, mchbar);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
if (res_cfg->num_imc > 1) {
|
||||
rc = igen6_mem_slice_setup(mchbar);
|
||||
|
Loading…
Reference in New Issue
Block a user