SiFive FU740 has 4 ECC interrupt sources as compared to 3 in FU540.
Update the L2 cache controller driver to support this additional
interrupt in case of FU740-C000 chip.

Signed-off-by: Yash Shah <yash.s...@sifive.com>
---
 drivers/soc/sifive/sifive_l2_cache.c | 49 +++++++++++++++++++++++++++++++-----
 1 file changed, 43 insertions(+), 6 deletions(-)

diff --git a/drivers/soc/sifive/sifive_l2_cache.c 
b/drivers/soc/sifive/sifive_l2_cache.c
index 44d7e19..4e5e841 100644
--- a/drivers/soc/sifive/sifive_l2_cache.c
+++ b/drivers/soc/sifive/sifive_l2_cache.c
@@ -17,6 +17,10 @@
 #define SIFIVE_L2_DIRECCFIX_HIGH 0x104
 #define SIFIVE_L2_DIRECCFIX_COUNT 0x108
 
+#define SIFIVE_L2_DIRECCFAIL_LOW 0x120
+#define SIFIVE_L2_DIRECCFAIL_HIGH 0x124
+#define SIFIVE_L2_DIRECCFAIL_COUNT 0x128
+
 #define SIFIVE_L2_DATECCFIX_LOW 0x140
 #define SIFIVE_L2_DATECCFIX_HIGH 0x144
 #define SIFIVE_L2_DATECCFIX_COUNT 0x148
@@ -29,7 +33,7 @@
 #define SIFIVE_L2_WAYENABLE 0x08
 #define SIFIVE_L2_ECCINJECTERR 0x40
 
-#define SIFIVE_L2_MAX_ECCINTR 3
+#define SIFIVE_L2_MAX_ECCINTR 4
 
 static void __iomem *l2_base;
 static int g_irq[SIFIVE_L2_MAX_ECCINTR];
@@ -37,6 +41,7 @@ static struct riscv_cacheinfo_ops l2_cache_ops;
 
 enum {
        DIR_CORR = 0,
+       DIR_UNCORR,
        DATA_CORR,
        DATA_UNCORR,
 };
@@ -93,6 +98,7 @@ static void l2_config_read(void)
 
 static const struct of_device_id sifive_l2_ids[] = {
        { .compatible = "sifive,fu540-c000-ccache" },
+       { .compatible = "sifive,fu740-c000-ccache" },
        { /* end of table */ },
 };
 
@@ -155,6 +161,15 @@ static irqreturn_t l2_int_handler(int irq, void *device)
                atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_CE,
                                           "DirECCFix");
        }
+       if (irq == g_irq[DIR_UNCORR]) {
+               add_h = readl(l2_base + SIFIVE_L2_DIRECCFAIL_HIGH);
+               add_l = readl(l2_base + SIFIVE_L2_DIRECCFAIL_LOW);
+               /* Reading this register clears the DirFail interrupt sig */
+               readl(l2_base + SIFIVE_L2_DIRECCFAIL_COUNT);
+               atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_UE,
+                                          "DirECCFail");
+               panic("L2CACHE: DirFail @ 0x%08X.%08X\n", add_h, add_l);
+       }
        if (irq == g_irq[DATA_CORR]) {
                add_h = readl(l2_base + SIFIVE_L2_DATECCFIX_HIGH);
                add_l = readl(l2_base + SIFIVE_L2_DATECCFIX_LOW);
@@ -179,9 +194,9 @@ static irqreturn_t l2_int_handler(int irq, void *device)
 
 static int __init sifive_l2_init(void)
 {
+       int i, k, rc, intr_num, offset = 0;
        struct device_node *np;
        struct resource res;
-       int i, rc;
 
        np = of_find_matching_node(NULL, sifive_l2_ids);
        if (!np)
@@ -194,11 +209,33 @@ static int __init sifive_l2_init(void)
        if (!l2_base)
                return -ENOMEM;
 
-       for (i = 0; i < SIFIVE_L2_MAX_ECCINTR; i++) {
-               g_irq[i] = irq_of_parse_and_map(np, i);
-               rc = request_irq(g_irq[i], l2_int_handler, 0, "l2_ecc", NULL);
+       intr_num = of_property_count_u32_elems(np, "interrupts");
+       if (!intr_num) {
+               pr_err("L2CACHE: no interrupts property\n");
+               return -ENODEV;
+       }
+
+       /*
+        * Only FU540 have 3 interrupts. Rest all other variants have
+        * 4 interrupts (+dirfail). Therefore offset is required to skip
+        * 'dirfail' interrupt entry in case of FU540
+        */
+       if (of_device_is_compatible(np, "sifive,fu540-c000-ccache"))
+               offset = 1;
+
+       g_irq[0] = irq_of_parse_and_map(np, 0);
+       rc = request_irq(g_irq[0], l2_int_handler, 0, "l2_ecc", NULL);
+       if (rc) {
+               pr_err("L2CACHE: Could not request IRQ %d\n", g_irq[0]);
+               return rc;
+       }
+
+       for (i = 1; i < intr_num; i++) {
+               k = i + offset;
+               g_irq[k] = irq_of_parse_and_map(np, i);
+               rc = request_irq(g_irq[k], l2_int_handler, 0, "l2_ecc", NULL);
                if (rc) {
-                       pr_err("L2CACHE: Could not request IRQ %d\n", g_irq[i]);
+                       pr_err("L2CACHE: Could not request IRQ %d\n", g_irq[k]);
                        return rc;
                }
        }
-- 
2.7.4

Reply via email to