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