aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac/altera_edac.c
diff options
context:
space:
mode:
authorThor Thayer <tthayer@opensource.altera.com>2016-08-09 10:40:52 -0400
committerBorislav Petkov <bp@suse.de>2016-08-10 08:43:14 -0400
commit911049845d7096c27304930ff478cbf3f2623ba3 (patch)
tree5cef3310ecfab5ef2bd1a401a620912c5de34f5b /drivers/edac/altera_edac.c
parent5e40cd4d258cc0728585a94fd81f73488f7cdce7 (diff)
EDAC, altera: Add Arria10 SD-MMC EDAC support
Add Altera Arria10 SD-MMC FIFO memory EDAC support. The SD-MMC is a dual port RAM implementation which is different than any of the other peripherals and therefore requires additional code. Signed-off-by: Thor Thayer <tthayer@opensource.altera.com> Cc: dinguyen@opensource.altera.com Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac <linux-edac@vger.kernel.org> Link: http://lkml.kernel.org/r/1470753653-23465-3-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov <bp@suse.de>
Diffstat (limited to 'drivers/edac/altera_edac.c')
-rw-r--r--drivers/edac/altera_edac.c188
1 files changed, 187 insertions, 1 deletions
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index 28247f82e1d5..efaf727be25a 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -1393,6 +1393,188 @@ early_initcall(socfpga_init_qspi_ecc);
1393 1393
1394#endif /* CONFIG_EDAC_ALTERA_QSPI */ 1394#endif /* CONFIG_EDAC_ALTERA_QSPI */
1395 1395
1396/********************* SDMMC Device Functions **********************/
1397
1398#ifdef CONFIG_EDAC_ALTERA_SDMMC
1399
1400static const struct edac_device_prv_data a10_sdmmceccb_data;
1401static int altr_portb_setup(struct altr_edac_device_dev *device)
1402{
1403 struct edac_device_ctl_info *dci;
1404 struct altr_edac_device_dev *altdev;
1405 char *ecc_name = "sdmmcb-ecc";
1406 int edac_idx, rc;
1407 struct device_node *np;
1408 const struct edac_device_prv_data *prv = &a10_sdmmceccb_data;
1409
1410 rc = altr_check_ecc_deps(device);
1411 if (rc)
1412 return rc;
1413
1414 np = of_find_compatible_node(NULL, NULL, "altr,socfpga-sdmmc-ecc");
1415 if (!np) {
1416 edac_printk(KERN_WARNING, EDAC_DEVICE, "SDMMC node not found\n");
1417 return -ENODEV;
1418 }
1419
1420 /* Create the PortB EDAC device */
1421 edac_idx = edac_device_alloc_index();
1422 dci = edac_device_alloc_ctl_info(sizeof(*altdev), ecc_name, 1,
1423 ecc_name, 1, 0, NULL, 0, edac_idx);
1424 if (!dci) {
1425 edac_printk(KERN_ERR, EDAC_DEVICE,
1426 "%s: Unable to allocate PortB EDAC device\n",
1427 ecc_name);
1428 return -ENOMEM;
1429 }
1430
1431 /* Initialize the PortB EDAC device structure from PortA structure */
1432 altdev = dci->pvt_info;
1433 *altdev = *device;
1434
1435 if (!devres_open_group(&altdev->ddev, altr_portb_setup, GFP_KERNEL))
1436 return -ENOMEM;
1437
1438 /* Update PortB specific values */
1439 altdev->edac_dev_name = ecc_name;
1440 altdev->edac_idx = edac_idx;
1441 altdev->edac_dev = dci;
1442 altdev->data = prv;
1443 dci->dev = &altdev->ddev;
1444 dci->ctl_name = "Altera ECC Manager";
1445 dci->mod_name = ecc_name;
1446 dci->dev_name = ecc_name;
1447
1448 /* Update the IRQs for PortB */
1449 altdev->sb_irq = irq_of_parse_and_map(np, 2);
1450 if (!altdev->sb_irq) {
1451 edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB SBIRQ alloc\n");
1452 rc = -ENODEV;
1453 goto err_release_group_1;
1454 }
1455 rc = devm_request_irq(&altdev->ddev, altdev->sb_irq,
1456 prv->ecc_irq_handler,
1457 IRQF_SHARED, ecc_name, altdev);
1458 if (rc) {
1459 edac_printk(KERN_ERR, EDAC_DEVICE, "PortB SBERR IRQ error\n");
1460 goto err_release_group_1;
1461 }
1462
1463 altdev->db_irq = irq_of_parse_and_map(np, 3);
1464 if (!altdev->db_irq) {
1465 edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB DBIRQ alloc\n");
1466 rc = -ENODEV;
1467 goto err_release_group_1;
1468 }
1469 rc = devm_request_irq(&altdev->ddev, altdev->db_irq,
1470 prv->ecc_irq_handler,
1471 IRQF_SHARED, ecc_name, altdev);
1472 if (rc) {
1473 edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n");
1474 goto err_release_group_1;
1475 }
1476
1477 rc = edac_device_add_device(dci);
1478 if (rc) {
1479 edac_printk(KERN_ERR, EDAC_DEVICE,
1480 "edac_device_add_device portB failed\n");
1481 rc = -ENOMEM;
1482 goto err_release_group_1;
1483 }
1484 altr_create_edacdev_dbgfs(dci, prv);
1485
1486 list_add(&altdev->next, &altdev->edac->a10_ecc_devices);
1487
1488 devres_remove_group(&altdev->ddev, altr_portb_setup);
1489
1490 return 0;
1491
1492err_release_group_1:
1493 edac_device_free_ctl_info(dci);
1494 devres_release_group(&altdev->ddev, altr_portb_setup);
1495 edac_printk(KERN_ERR, EDAC_DEVICE,
1496 "%s:Error setting up EDAC device: %d\n", ecc_name, rc);
1497 return rc;
1498}
1499
1500static irqreturn_t altr_edac_a10_ecc_irq_portb(int irq, void *dev_id)
1501{
1502 struct altr_edac_device_dev *ad = dev_id;
1503 void __iomem *base = ad->base;
1504 const struct edac_device_prv_data *priv = ad->data;
1505
1506 if (irq == ad->sb_irq) {
1507 writel(priv->ce_clear_mask,
1508 base + ALTR_A10_ECC_INTSTAT_OFST);
1509 edac_device_handle_ce(ad->edac_dev, 0, 0, ad->edac_dev_name);
1510 return IRQ_HANDLED;
1511 } else if (irq == ad->db_irq) {
1512 writel(priv->ue_clear_mask,
1513 base + ALTR_A10_ECC_INTSTAT_OFST);
1514 edac_device_handle_ue(ad->edac_dev, 0, 0, ad->edac_dev_name);
1515 return IRQ_HANDLED;
1516 }
1517
1518 WARN_ONCE(1, "Unhandled IRQ%d on Port B.", irq);
1519
1520 return IRQ_NONE;
1521}
1522
1523static const struct edac_device_prv_data a10_sdmmcecca_data = {
1524 .setup = altr_portb_setup,
1525 .ce_clear_mask = ALTR_A10_ECC_SERRPENA,
1526 .ue_clear_mask = ALTR_A10_ECC_DERRPENA,
1527 .dbgfs_name = "altr_trigger",
1528 .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL,
1529 .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST,
1530 .ce_set_mask = ALTR_A10_ECC_SERRPENA,
1531 .ue_set_mask = ALTR_A10_ECC_DERRPENA,
1532 .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST,
1533 .ecc_irq_handler = altr_edac_a10_ecc_irq,
1534 .inject_fops = &altr_edac_a10_device_inject_fops,
1535};
1536
1537static const struct edac_device_prv_data a10_sdmmceccb_data = {
1538 .setup = altr_portb_setup,
1539 .ce_clear_mask = ALTR_A10_ECC_SERRPENB,
1540 .ue_clear_mask = ALTR_A10_ECC_DERRPENB,
1541 .dbgfs_name = "altr_trigger",
1542 .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL,
1543 .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST,
1544 .ce_set_mask = ALTR_A10_ECC_TSERRB,
1545 .ue_set_mask = ALTR_A10_ECC_TDERRB,
1546 .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST,
1547 .ecc_irq_handler = altr_edac_a10_ecc_irq_portb,
1548 .inject_fops = &altr_edac_a10_device_inject_fops,
1549};
1550
1551static int __init socfpga_init_sdmmc_ecc(void)
1552{
1553 int rc = -ENODEV;
1554 struct device_node *child = of_find_compatible_node(NULL, NULL,
1555 "altr,socfpga-sdmmc-ecc");
1556 if (!child) {
1557 edac_printk(KERN_WARNING, EDAC_DEVICE, "SDMMC node not found\n");
1558 return -ENODEV;
1559 }
1560
1561 if (!of_device_is_available(child))
1562 goto exit;
1563
1564 if (validate_parent_available(child))
1565 goto exit;
1566
1567 rc = altr_init_a10_ecc_block(child, ALTR_A10_SDMMC_IRQ_MASK,
1568 a10_sdmmcecca_data.ecc_enable_mask, 1);
1569exit:
1570 of_node_put(child);
1571 return rc;
1572}
1573
1574early_initcall(socfpga_init_sdmmc_ecc);
1575
1576#endif /* CONFIG_EDAC_ALTERA_SDMMC */
1577
1396/********************* Arria10 EDAC Device Functions *************************/ 1578/********************* Arria10 EDAC Device Functions *************************/
1397static const struct of_device_id altr_edac_a10_device_of_match[] = { 1579static const struct of_device_id altr_edac_a10_device_of_match[] = {
1398#ifdef CONFIG_EDAC_ALTERA_L2C 1580#ifdef CONFIG_EDAC_ALTERA_L2C
@@ -1418,6 +1600,9 @@ static const struct of_device_id altr_edac_a10_device_of_match[] = {
1418#ifdef CONFIG_EDAC_ALTERA_QSPI 1600#ifdef CONFIG_EDAC_ALTERA_QSPI
1419 { .compatible = "altr,socfpga-qspi-ecc", .data = &a10_qspiecc_data }, 1601 { .compatible = "altr,socfpga-qspi-ecc", .data = &a10_qspiecc_data },
1420#endif 1602#endif
1603#ifdef CONFIG_EDAC_ALTERA_SDMMC
1604 { .compatible = "altr,socfpga-sdmmc-ecc", .data = &a10_sdmmcecca_data },
1605#endif
1421 {}, 1606 {},
1422}; 1607};
1423MODULE_DEVICE_TABLE(of, altr_edac_a10_device_of_match); 1608MODULE_DEVICE_TABLE(of, altr_edac_a10_device_of_match);
@@ -1711,7 +1896,8 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
1711 of_device_is_compatible(child, "altr,socfpga-nand-ecc") || 1896 of_device_is_compatible(child, "altr,socfpga-nand-ecc") ||
1712 of_device_is_compatible(child, "altr,socfpga-dma-ecc") || 1897 of_device_is_compatible(child, "altr,socfpga-dma-ecc") ||
1713 of_device_is_compatible(child, "altr,socfpga-usb-ecc") || 1898 of_device_is_compatible(child, "altr,socfpga-usb-ecc") ||
1714 of_device_is_compatible(child, "altr,socfpga-qspi-ecc")) 1899 of_device_is_compatible(child, "altr,socfpga-qspi-ecc") ||
1900 of_device_is_compatible(child, "altr,socfpga-sdmmc-ecc"))
1715 1901
1716 altr_edac_a10_device_add(edac, child); 1902 altr_edac_a10_device_add(edac, child);
1717 1903