memory: tegra: Parameterize interrupt handler
authorThierry Reding <treding@nvidia.com>
Wed, 2 Jun 2021 16:32:57 +0000 (18:32 +0200)
committerKrzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
Thu, 3 Jun 2021 19:49:41 +0000 (21:49 +0200)
Tegra20 requires a slightly different interrupt handler than Tegra30 and
later, so parameterize the handler, so that each SoC implementation can
provide its own.

Signed-off-by: Thierry Reding <treding@nvidia.com>
Link: https://lore.kernel.org/r/20210602163302.120041-8-thierry.reding@gmail.com
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
drivers/memory/tegra/mc.c
drivers/memory/tegra/mc.h
drivers/memory/tegra/tegra20.c
include/soc/tegra/mc.h

index edb3c4a253654771e4b99a48d5fe32b1df9d629a..e6c928633b12bd059c5a44f28ab0ecc0198ffb33 100644 (file)
@@ -492,32 +492,7 @@ int tegra30_mc_probe(struct tegra_mc *mc)
        return 0;
 }
 
-const struct tegra_mc_ops tegra30_mc_ops = {
-       .probe = tegra30_mc_probe,
-};
-#endif
-
-static const char *const status_names[32] = {
-       [ 1] = "External interrupt",
-       [ 6] = "EMEM address decode error",
-       [ 7] = "GART page fault",
-       [ 8] = "Security violation",
-       [ 9] = "EMEM arbitration error",
-       [10] = "Page fault",
-       [11] = "Invalid APB ASID update",
-       [12] = "VPR violation",
-       [13] = "Secure carveout violation",
-       [16] = "MTS carveout violation",
-};
-
-static const char *const error_names[8] = {
-       [2] = "EMEM decode error",
-       [3] = "TrustZone violation",
-       [4] = "Carveout violation",
-       [6] = "SMMU translation error",
-};
-
-static irqreturn_t tegra_mc_irq(int irq, void *data)
+static irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
 {
        struct tegra_mc *mc = data;
        unsigned long status;
@@ -529,7 +504,7 @@ static irqreturn_t tegra_mc_irq(int irq, void *data)
                return IRQ_NONE;
 
        for_each_set_bit(bit, &status, 32) {
-               const char *error = status_names[bit] ?: "unknown";
+               const char *error = tegra_mc_status_names[bit] ?: "unknown";
                const char *client = "unknown", *desc;
                const char *direction, *secure;
                phys_addr_t addr = 0;
@@ -569,7 +544,7 @@ static irqreturn_t tegra_mc_irq(int irq, void *data)
 
                type = (value & MC_ERR_STATUS_TYPE_MASK) >>
                       MC_ERR_STATUS_TYPE_SHIFT;
-               desc = error_names[type];
+               desc = tegra_mc_error_names[type];
 
                switch (value & MC_ERR_STATUS_TYPE_MASK) {
                case MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE:
@@ -614,78 +589,31 @@ static irqreturn_t tegra_mc_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static __maybe_unused irqreturn_t tegra20_mc_irq(int irq, void *data)
-{
-       struct tegra_mc *mc = data;
-       unsigned long status;
-       unsigned int bit;
-
-       /* mask all interrupts to avoid flooding */
-       status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask;
-       if (!status)
-               return IRQ_NONE;
-
-       for_each_set_bit(bit, &status, 32) {
-               const char *direction = "read", *secure = "";
-               const char *error = status_names[bit];
-               const char *client, *desc;
-               phys_addr_t addr;
-               u32 value, reg;
-               u8 id, type;
-
-               switch (BIT(bit)) {
-               case MC_INT_DECERR_EMEM:
-                       reg = MC_DECERR_EMEM_OTHERS_STATUS;
-                       value = mc_readl(mc, reg);
-
-                       id = value & mc->soc->client_id_mask;
-                       desc = error_names[2];
-
-                       if (value & BIT(31))
-                               direction = "write";
-                       break;
-
-               case MC_INT_INVALID_GART_PAGE:
-                       reg = MC_GART_ERROR_REQ;
-                       value = mc_readl(mc, reg);
-
-                       id = (value >> 1) & mc->soc->client_id_mask;
-                       desc = error_names[2];
-
-                       if (value & BIT(0))
-                               direction = "write";
-                       break;
-
-               case MC_INT_SECURITY_VIOLATION:
-                       reg = MC_SECURITY_VIOLATION_STATUS;
-                       value = mc_readl(mc, reg);
-
-                       id = value & mc->soc->client_id_mask;
-                       type = (value & BIT(30)) ? 4 : 3;
-                       desc = error_names[type];
-                       secure = "secure ";
-
-                       if (value & BIT(31))
-                               direction = "write";
-                       break;
-
-               default:
-                       continue;
-               }
-
-               client = mc->soc->clients[id].name;
-               addr = mc_readl(mc, reg + sizeof(u32));
-
-               dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s)\n",
-                                   client, secure, direction, &addr, error,
-                                   desc);
-       }
+const struct tegra_mc_ops tegra30_mc_ops = {
+       .probe = tegra30_mc_probe,
+       .handle_irq = tegra30_mc_handle_irq,
+};
+#endif
 
-       /* clear interrupts */
-       mc_writel(mc, status, MC_INTSTATUS);
+const char *const tegra_mc_status_names[32] = {
+       [ 1] = "External interrupt",
+       [ 6] = "EMEM address decode error",
+       [ 7] = "GART page fault",
+       [ 8] = "Security violation",
+       [ 9] = "EMEM arbitration error",
+       [10] = "Page fault",
+       [11] = "Invalid APB ASID update",
+       [12] = "VPR violation",
+       [13] = "Secure carveout violation",
+       [16] = "MTS carveout violation",
+};
 
-       return IRQ_HANDLED;
-}
+const char *const tegra_mc_error_names[8] = {
+       [2] = "EMEM decode error",
+       [3] = "TrustZone violation",
+       [4] = "Carveout violation",
+       [6] = "SMMU translation error",
+};
 
 /*
  * Memory Controller (MC) has few Memory Clients that are issuing memory
@@ -786,7 +714,6 @@ static int tegra_mc_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct tegra_mc *mc;
-       void *isr;
        u64 mask;
        int err;
 
@@ -823,15 +750,6 @@ static int tegra_mc_probe(struct platform_device *pdev)
                        return err;
        }
 
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-       if (mc->soc == &tegra20_mc_soc) {
-               isr = tegra20_mc_irq;
-       } else
-#endif
-       {
-               isr = tegra_mc_irq;
-       }
-
        mc->irq = platform_get_irq(pdev, 0);
        if (mc->irq < 0)
                return mc->irq;
@@ -840,7 +758,7 @@ static int tegra_mc_probe(struct platform_device *pdev)
 
        mc_writel(mc, mc->soc->intmask, MC_INTMASK);
 
-       err = devm_request_irq(&pdev->dev, mc->irq, isr, 0,
+       err = devm_request_irq(&pdev->dev, mc->irq, mc->soc->ops->handle_irq, 0,
                               dev_name(&pdev->dev), mc);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq,
index 731896169cf31af02521d44fc0508e4fc54018b5..83c605e42e9a0ff7e93fc4f93d3e05191470e8e4 100644 (file)
@@ -138,6 +138,9 @@ int tegra30_mc_probe(struct tegra_mc *mc);
 extern const struct tegra_mc_ops tegra30_mc_ops;
 #endif
 
+extern const char * const tegra_mc_status_names[32];
+extern const char * const tegra_mc_error_names[8];
+
 /*
  * These IDs are for internal use of Tegra ICC drivers. The ID numbers are
  * chosen such that they don't conflict with the device-tree ICC node IDs.
index 2c86c0d70d59f0faee500ed635af4fdccc2228a6..fcd7738fcb536c6b6318cde5ee4785bede3cd2b4 100644 (file)
@@ -713,10 +713,84 @@ static int tegra20_mc_resume(struct tegra_mc *mc)
        return 0;
 }
 
+static irqreturn_t tegra20_mc_handle_irq(int irq, void *data)
+{
+       struct tegra_mc *mc = data;
+       unsigned long status;
+       unsigned int bit;
+
+       /* mask all interrupts to avoid flooding */
+       status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask;
+       if (!status)
+               return IRQ_NONE;
+
+       for_each_set_bit(bit, &status, 32) {
+               const char *error = tegra_mc_status_names[bit];
+               const char *direction = "read", *secure = "";
+               const char *client, *desc;
+               phys_addr_t addr;
+               u32 value, reg;
+               u8 id, type;
+
+               switch (BIT(bit)) {
+               case MC_INT_DECERR_EMEM:
+                       reg = MC_DECERR_EMEM_OTHERS_STATUS;
+                       value = mc_readl(mc, reg);
+
+                       id = value & mc->soc->client_id_mask;
+                       desc = tegra_mc_error_names[2];
+
+                       if (value & BIT(31))
+                               direction = "write";
+                       break;
+
+               case MC_INT_INVALID_GART_PAGE:
+                       reg = MC_GART_ERROR_REQ;
+                       value = mc_readl(mc, reg);
+
+                       id = (value >> 1) & mc->soc->client_id_mask;
+                       desc = tegra_mc_error_names[2];
+
+                       if (value & BIT(0))
+                               direction = "write";
+                       break;
+
+               case MC_INT_SECURITY_VIOLATION:
+                       reg = MC_SECURITY_VIOLATION_STATUS;
+                       value = mc_readl(mc, reg);
+
+                       id = value & mc->soc->client_id_mask;
+                       type = (value & BIT(30)) ? 4 : 3;
+                       desc = tegra_mc_error_names[type];
+                       secure = "secure ";
+
+                       if (value & BIT(31))
+                               direction = "write";
+                       break;
+
+               default:
+                       continue;
+               }
+
+               client = mc->soc->clients[id].name;
+               addr = mc_readl(mc, reg + sizeof(u32));
+
+               dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s)\n",
+                                   client, secure, direction, &addr, error,
+                                   desc);
+       }
+
+       /* clear interrupts */
+       mc_writel(mc, status, MC_INTSTATUS);
+
+       return IRQ_HANDLED;
+}
+
 static const struct tegra_mc_ops tegra20_mc_ops = {
        .probe = tegra20_mc_probe,
        .suspend = tegra20_mc_suspend,
        .resume = tegra20_mc_resume,
+       .handle_irq = tegra20_mc_handle_irq,
 };
 
 const struct tegra_mc_soc tegra20_mc_soc = {
index 00d16c356db8425d36cc00fac2852613101a3116..87668ebab2a1202570177d12ce2e76256e53aace 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/debugfs.h>
 #include <linux/err.h>
 #include <linux/interconnect-provider.h>
+#include <linux/irq.h>
 #include <linux/reset-controller.h>
 #include <linux/types.h>
 
@@ -177,6 +178,7 @@ struct tegra_mc_ops {
        int (*probe)(struct tegra_mc *mc);
        int (*suspend)(struct tegra_mc *mc);
        int (*resume)(struct tegra_mc *mc);
+       irqreturn_t (*handle_irq)(int irq, void *data);
 };
 
 struct tegra_mc_soc {