static int altr_portb_setup()

in altera_edac.c [1466:1584]


static int altr_portb_setup(struct altr_edac_device_dev *device)
{
	struct edac_device_ctl_info *dci;
	struct altr_edac_device_dev *altdev;
	char *ecc_name = "sdmmcb-ecc";
	int edac_idx, rc;
	struct device_node *np;
	const struct edac_device_prv_data *prv = &a10_sdmmceccb_data;

	rc = altr_check_ecc_deps(device);
	if (rc)
		return rc;

	np = of_find_compatible_node(NULL, NULL, "altr,socfpga-sdmmc-ecc");
	if (!np) {
		edac_printk(KERN_WARNING, EDAC_DEVICE, "SDMMC node not found\n");
		return -ENODEV;
	}

	/* Create the PortB EDAC device */
	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 PortB EDAC device\n",
			    ecc_name);
		return -ENOMEM;
	}

	/* Initialize the PortB EDAC device structure from PortA structure */
	altdev = dci->pvt_info;
	*altdev = *device;

	if (!devres_open_group(&altdev->ddev, altr_portb_setup, GFP_KERNEL))
		return -ENOMEM;

	/* Update PortB specific values */
	altdev->edac_dev_name = ecc_name;
	altdev->edac_idx = edac_idx;
	altdev->edac_dev = dci;
	altdev->data = prv;
	dci->dev = &altdev->ddev;
	dci->ctl_name = "Altera ECC Manager";
	dci->mod_name = ecc_name;
	dci->dev_name = ecc_name;

	/*
	 * Update the PortB IRQs - A10 has 4, S10 has 2, Index accordingly
	 *
	 * FIXME: Instead of ifdefs with different architectures the driver
	 *        should properly use compatibles.
	 */
#ifdef CONFIG_64BIT
	altdev->sb_irq = irq_of_parse_and_map(np, 1);
#else
	altdev->sb_irq = irq_of_parse_and_map(np, 2);
#endif
	if (!altdev->sb_irq) {
		edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB SBIRQ alloc\n");
		rc = -ENODEV;
		goto err_release_group_1;
	}
	rc = devm_request_irq(&altdev->ddev, altdev->sb_irq,
			      prv->ecc_irq_handler,
			      IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
			      ecc_name, altdev);
	if (rc) {
		edac_printk(KERN_ERR, EDAC_DEVICE, "PortB SBERR IRQ error\n");
		goto err_release_group_1;
	}

#ifdef CONFIG_64BIT
	/* Use IRQ to determine SError origin instead of assigning IRQ */
	rc = of_property_read_u32_index(np, "interrupts", 1, &altdev->db_irq);
	if (rc) {
		edac_printk(KERN_ERR, EDAC_DEVICE,
			    "Error PortB DBIRQ alloc\n");
		goto err_release_group_1;
	}
#else
	altdev->db_irq = irq_of_parse_and_map(np, 3);
	if (!altdev->db_irq) {
		edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB DBIRQ alloc\n");
		rc = -ENODEV;
		goto err_release_group_1;
	}
	rc = devm_request_irq(&altdev->ddev, altdev->db_irq,
			      prv->ecc_irq_handler,
			      IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
			      ecc_name, altdev);
	if (rc) {
		edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n");
		goto err_release_group_1;
	}
#endif

	rc = edac_device_add_device(dci);
	if (rc) {
		edac_printk(KERN_ERR, EDAC_DEVICE,
			    "edac_device_add_device portB failed\n");
		rc = -ENOMEM;
		goto err_release_group_1;
	}
	altr_create_edacdev_dbgfs(dci, prv);

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

	devres_remove_group(&altdev->ddev, altr_portb_setup);

	return 0;

err_release_group_1:
	edac_device_free_ctl_info(dci);
	devres_release_group(&altdev->ddev, altr_portb_setup);
	edac_printk(KERN_ERR, EDAC_DEVICE,
		    "%s:Error setting up EDAC device: %d\n", ecc_name, rc);
	return rc;
}