static int altr_edac_a10_device_add()

in altera_edac.c [1855:1992]


static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
				    struct device_node *np)
{
	struct edac_device_ctl_info *dci;
	struct altr_edac_device_dev *altdev;
	char *ecc_name = (char *)np->name;
	struct resource res;
	int edac_idx;
	int rc = 0;
	const struct edac_device_prv_data *prv;
	/* Get matching node and check for valid result */
	const struct of_device_id *pdev_id =
		of_match_node(altr_edac_a10_device_of_match, np);
	if (IS_ERR_OR_NULL(pdev_id))
		return -ENODEV;

	/* Get driver specific data for this EDAC device */
	prv = pdev_id->data;
	if (IS_ERR_OR_NULL(prv))
		return -ENODEV;

	if (validate_parent_available(np))
		return -ENODEV;

	if (!devres_open_group(edac->dev, altr_edac_a10_device_add, GFP_KERNEL))
		return -ENOMEM;

	if (of_device_is_compatible(np, "altr,sdram-edac-s10"))
		rc = get_s10_sdram_edac_resource(np, &res);
	else
		rc = of_address_to_resource(np, 0, &res);

	if (rc < 0) {
		edac_printk(KERN_ERR, EDAC_DEVICE,
			    "%s: no resource address\n", ecc_name);
		goto err_release_group;
	}

	edac_idx = edac_device_alloc_index();
	dci = edac_device_alloc_ctl_info(sizeof(*altdev), ecc_name,
					 1, ecc_name, 1, 0, NULL, 0,
					 edac_idx);

	if (!dci) {
		edac_printk(KERN_ERR, EDAC_DEVICE,
			    "%s: Unable to allocate EDAC device\n", ecc_name);
		rc = -ENOMEM;
		goto err_release_group;
	}

	altdev = dci->pvt_info;
	dci->dev = edac->dev;
	altdev->edac_dev_name = ecc_name;
	altdev->edac_idx = edac_idx;
	altdev->edac = edac;
	altdev->edac_dev = dci;
	altdev->data = prv;
	altdev->ddev = *edac->dev;
	dci->dev = &altdev->ddev;
	dci->ctl_name = "Altera ECC Manager";
	dci->mod_name = ecc_name;
	dci->dev_name = ecc_name;

	altdev->base = devm_ioremap_resource(edac->dev, &res);
	if (IS_ERR(altdev->base)) {
		rc = PTR_ERR(altdev->base);
		goto err_release_group1;
	}

	/* Check specific dependencies for the module */
	if (altdev->data->setup) {
		rc = altdev->data->setup(altdev);
		if (rc)
			goto err_release_group1;
	}

	altdev->sb_irq = irq_of_parse_and_map(np, 0);
	if (!altdev->sb_irq) {
		edac_printk(KERN_ERR, EDAC_DEVICE, "Error allocating SBIRQ\n");
		rc = -ENODEV;
		goto err_release_group1;
	}
	rc = devm_request_irq(edac->dev, altdev->sb_irq, prv->ecc_irq_handler,
			      IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
			      ecc_name, altdev);
	if (rc) {
		edac_printk(KERN_ERR, EDAC_DEVICE, "No SBERR IRQ resource\n");
		goto err_release_group1;
	}

#ifdef CONFIG_64BIT
	/* Use IRQ to determine SError origin instead of assigning IRQ */
	rc = of_property_read_u32_index(np, "interrupts", 0, &altdev->db_irq);
	if (rc) {
		edac_printk(KERN_ERR, EDAC_DEVICE,
			    "Unable to parse DB IRQ index\n");
		goto err_release_group1;
	}
#else
	altdev->db_irq = irq_of_parse_and_map(np, 1);
	if (!altdev->db_irq) {
		edac_printk(KERN_ERR, EDAC_DEVICE, "Error allocating DBIRQ\n");
		rc = -ENODEV;
		goto err_release_group1;
	}
	rc = devm_request_irq(edac->dev, altdev->db_irq, prv->ecc_irq_handler,
			      IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
			      ecc_name, altdev);
	if (rc) {
		edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n");
		goto err_release_group1;
	}
#endif

	rc = edac_device_add_device(dci);
	if (rc) {
		dev_err(edac->dev, "edac_device_add_device failed\n");
		rc = -ENOMEM;
		goto err_release_group1;
	}

	altr_create_edacdev_dbgfs(dci, prv);

	list_add(&altdev->next, &edac->a10_ecc_devices);

	devres_remove_group(edac->dev, altr_edac_a10_device_add);

	return 0;

err_release_group1:
	edac_device_free_ctl_info(dci);
err_release_group:
	devres_release_group(edac->dev, NULL);
	edac_printk(KERN_ERR, EDAC_DEVICE,
		    "%s:Error setting up EDAC device: %d\n", ecc_name, rc);

	return rc;
}