in dmc520_edac.c [473:603]
static int dmc520_edac_probe(struct platform_device *pdev)
{
bool registered[NUMBER_OF_IRQS] = { false };
int irqs[NUMBER_OF_IRQS] = { -ENXIO };
int masks[NUMBER_OF_IRQS] = { 0 };
struct edac_mc_layer layers[1];
struct dmc520_edac *pvt = NULL;
struct mem_ctl_info *mci;
void __iomem *reg_base;
u32 irq_mask_all = 0;
struct resource *res;
struct device *dev;
int ret, idx, irq;
u32 reg_val;
/* Parse the device node */
dev = &pdev->dev;
for (idx = 0; idx < NUMBER_OF_IRQS; idx++) {
irq = platform_get_irq_byname(pdev, dmc520_irq_configs[idx].name);
irqs[idx] = irq;
masks[idx] = dmc520_irq_configs[idx].mask;
if (irq >= 0) {
irq_mask_all |= dmc520_irq_configs[idx].mask;
edac_dbg(0, "Discovered %s, irq: %d.\n", dmc520_irq_configs[idx].name, irq);
}
}
if (!irq_mask_all) {
edac_printk(KERN_ERR, EDAC_MOD_NAME,
"At least one valid interrupt line is expected.\n");
return -EINVAL;
}
/* Initialize dmc520 edac */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg_base = devm_ioremap_resource(dev, res);
if (IS_ERR(reg_base))
return PTR_ERR(reg_base);
if (!dmc520_is_ecc_enabled(reg_base))
return -ENXIO;
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = dmc520_get_rank_count(reg_base);
layers[0].is_virt_csrow = true;
mci = edac_mc_alloc(dmc520_mc_idx++, ARRAY_SIZE(layers), layers, sizeof(*pvt));
if (!mci) {
edac_printk(KERN_ERR, EDAC_MOD_NAME,
"Failed to allocate memory for mc instance\n");
ret = -ENOMEM;
goto err;
}
pvt = mci->pvt_info;
pvt->reg_base = reg_base;
spin_lock_init(&pvt->error_lock);
memcpy(pvt->irqs, irqs, sizeof(irqs));
memcpy(pvt->masks, masks, sizeof(masks));
platform_set_drvdata(pdev, mci);
mci->pdev = dev;
mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR4;
mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
mci->edac_cap = EDAC_FLAG_SECDED;
mci->scrub_cap = SCRUB_FLAG_HW_SRC;
mci->scrub_mode = dmc520_get_scrub_type(pvt);
mci->ctl_name = EDAC_CTL_NAME;
mci->dev_name = dev_name(mci->pdev);
mci->mod_name = EDAC_MOD_NAME;
edac_op_state = EDAC_OPSTATE_INT;
pvt->mem_width_in_bytes = dmc520_get_memory_width(pvt);
dmc520_init_csrow(mci);
/* Clear interrupts, not affecting other unrelated interrupts */
reg_val = dmc520_read_reg(pvt, REG_OFFSET_INTERRUPT_CONTROL);
dmc520_write_reg(pvt, reg_val & (~irq_mask_all),
REG_OFFSET_INTERRUPT_CONTROL);
dmc520_write_reg(pvt, irq_mask_all, REG_OFFSET_INTERRUPT_CLR);
for (idx = 0; idx < NUMBER_OF_IRQS; idx++) {
irq = irqs[idx];
if (irq >= 0) {
ret = devm_request_irq(&pdev->dev, irq,
dmc520_isr, IRQF_SHARED,
dev_name(&pdev->dev), mci);
if (ret < 0) {
edac_printk(KERN_ERR, EDAC_MC,
"Failed to request irq %d\n", irq);
goto err;
}
registered[idx] = true;
}
}
/* Reset DRAM CE/UE counters */
if (irq_mask_all & DRAM_ECC_INT_CE_BIT)
dmc520_get_dram_ecc_error_count(pvt, true);
if (irq_mask_all & DRAM_ECC_INT_UE_BIT)
dmc520_get_dram_ecc_error_count(pvt, false);
ret = edac_mc_add_mc(mci);
if (ret) {
edac_printk(KERN_ERR, EDAC_MOD_NAME,
"Failed to register with EDAC core\n");
goto err;
}
/* Enable interrupts, not affecting other unrelated interrupts */
dmc520_write_reg(pvt, reg_val | irq_mask_all,
REG_OFFSET_INTERRUPT_CONTROL);
return 0;
err:
for (idx = 0; idx < NUMBER_OF_IRQS; idx++) {
if (registered[idx])
devm_free_irq(&pdev->dev, pvt->irqs[idx], mci);
}
if (mci)
edac_mc_free(mci);
return ret;
}