static int dmc520_edac_probe()

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;
}