diff options
author | Alex Waterman <alexw@nvidia.com> | 2012-10-11 11:10:02 -0700 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2012-10-25 11:16:23 -0700 |
commit | 23fc7dd5a06d15bec976df82f8a892648d79d8b9 (patch) | |
tree | 5cd854c31f05a0d7c1f9755f359c8caeaf9802b1 /arch/arm/mach-tegra/common-t3.c | |
parent | db127b14d8318a9257b91cfaeb4c00357a2dbaa8 (diff) |
arm: tegra: Update MC error reporting
The error reporting done by the kernel needed updating from T30
to support new T11x specific features and additions.
BUG 1156719
Change-Id: Iffdedfec54f2a673d97cfe42186b71fe4842c64b
Signed-off-by: Alex Waterman <alexw@nvidia.com>
Reviewed-on: http://git-master/r/143813
(cherry-picked from 18272401c76a80b49c3f1af1ada61209cd944d89)
Reviewed-on: http://git-master/r/145772
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Krishna Reddy <vdumpa@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/common-t3.c')
-rw-r--r-- | arch/arm/mach-tegra/common-t3.c | 275 |
1 files changed, 13 insertions, 262 deletions
diff --git a/arch/arm/mach-tegra/common-t3.c b/arch/arm/mach-tegra/common-t3.c index ad9889c98e75..9f700dce4eb8 100644 --- a/arch/arm/mach-tegra/common-t3.c +++ b/arch/arm/mach-tegra/common-t3.c @@ -1,9 +1,9 @@ /* * arch/arm/mach-tegra/common-t3.c * - * Tegra 3 SoC-specific initialization (memory controller, etc.) + * Tegra 3 SoC-specific initialization. * - * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved. + * Copyright (c) 2009-2012 NVIDIA Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,87 +22,21 @@ #include <linux/kernel.h> #include <linux/io.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <linux/stat.h> -#include <linux/sched.h> -#include <linux/moduleparam.h> -#include <linux/spinlock_types.h> #include <mach/iomap.h> -#include <mach/irqs.h> -#include "tegra3_emc.h" +#include "mcerr.h" -#define MC_INT_STATUS 0x0 -#define MC_INT_MASK 0x4 -#define MC_INT_DECERR_EMEM (1<<6) -#define MC_INT_SECURITY_VIOLATION (1<<8) -#define MC_INT_ARBITRATION_EMEM (1<<9) -#define MC_INT_INVALID_SMMU_PAGE (1<<10) - -#define MC_ERROR_STATUS 0x8 -#define MC_ERROR_ADDRESS 0xC - -#define MC_TIMING_REG_NUM1 \ +#define MC_TIMING_REG_NUM1 \ ((MC_EMEM_ARB_TIMING_W2R - MC_EMEM_ARB_CFG) / 4 + 1) -#define MC_TIMING_REG_NUM2 \ +#define MC_TIMING_REG_NUM2 \ ((MC_EMEM_ARB_MISC1 - MC_EMEM_ARB_DA_TURNS) / 4 + 1) -#define MC_TIMING_REG_NUM3 \ - ((MC_LATENCY_ALLOWANCE_VI_2 - MC_LATENCY_ALLOWANCE_AFI) / 4 + 1) - -struct mc_client { - const char *name; -}; - -#define client(_name) \ - { \ - .name = _name, \ - } - - -static void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE); - -#define MMA_HISTORY_SAMPLES 20 -struct arb_emem_intr_info { - int arb_intr_mma; - u64 time; - spinlock_t lock; -}; - -static struct arb_emem_intr_info arb_intr_info = { - .lock = __SPIN_LOCK_UNLOCKED(arb_intr_info.lock), -}; - -static int arb_intr_count; -static int arb_intr_mma_set(const char *arg, const struct kernel_param *kp) -{ - int ret; - unsigned long flags; - - spin_lock_irqsave(&arb_intr_info.lock, flags); - ret = param_set_int(arg, kp); - spin_unlock_irqrestore(&arb_intr_info.lock, flags); - return ret; -} - -static int arb_intr_mma_get(char *buff, const struct kernel_param *kp) -{ - return param_get_int(buff, kp); -} - -static struct kernel_param_ops arb_intr_mma_ops = { - .get = arb_intr_mma_get, - .set = arb_intr_mma_set, -}; - -module_param_cb(arb_intr_mma_in_ms, &arb_intr_mma_ops,\ - &arb_intr_info.arb_intr_mma, S_IRUGO | S_IWUSR); -module_param(arb_intr_count, int, S_IRUGO | S_IWUSR); +#define MC_TIMING_REG_NUM3 \ + ((MC_LATENCY_ALLOWANCE_VI_2 - MC_LATENCY_ALLOWANCE_BASE) / 4 + 1) #ifdef CONFIG_PM_SLEEP static u32 mc_boot_timing[MC_TIMING_REG_NUM1 + MC_TIMING_REG_NUM2 - + MC_TIMING_REG_NUM3 + 4]; + + MC_TIMING_REG_NUM3 + 4]; static void tegra_mc_timing_save(void) { @@ -119,7 +53,7 @@ static void tegra_mc_timing_save(void) *ctx++ = readl(mc + MC_EMEM_ARB_OVERRIDE); *ctx++ = readl(mc + MC_RESERVED_RSV); - for (off = MC_LATENCY_ALLOWANCE_AFI; off <= MC_LATENCY_ALLOWANCE_VI_2; + for (off = MC_LATENCY_ALLOWANCE_BASE; off <= MC_LATENCY_ALLOWANCE_VI_2; off += 4) *ctx++ = readl((u32)mc + off); @@ -141,7 +75,7 @@ void tegra_mc_timing_restore(void) __raw_writel(*ctx++, mc + MC_EMEM_ARB_OVERRIDE); __raw_writel(*ctx++, mc + MC_RESERVED_RSV); - for (off = MC_LATENCY_ALLOWANCE_AFI; off <= MC_LATENCY_ALLOWANCE_VI_2; + for (off = MC_LATENCY_ALLOWANCE_BASE; off <= MC_LATENCY_ALLOWANCE_VI_2; off += 4) __raw_writel(*ctx++, (u32)mc + off); @@ -161,192 +95,9 @@ void tegra_mc_timing_restore(void) #define tegra_mc_timing_save() #endif - -static const struct mc_client mc_clients[] = { - client("ptc"), - client("display0_wina"), client("display1_wina"), - client("display0_winb"), client("display1_winb"), - client("display0_winc"), client("display1_winc"), - client("display0_winb_vfilter"), - client("display1_winb_vfilter"), - client("epp"), client("gr2d_pat"), - client("gr2d_src"), client("mpe_unified"), - client("vi_chroma_filter"), client("pcie"), - client("avp"), - client("display0_cursor"), client("display1_cursor"), - client("gr3d0_fdc"), client("gr3d1_fdc"), - client("gr2d_dst"), client("hda"), - client("host1x_dma"), client("host1x_generic"), - client("gr3d0_idx"), client("gr3d1_idx"), - client("mpe_intrapred"), client("mpe_mpea"), - client("mpe_mpec"), client("ahb_dma"), - client("ahb_slave"), client("sata"), - client("gr3d0_tex"), client("gr3d1_tex"), - client("vde_bsev"), client("vde_mbe"), - client("vde_mce"), client("vde_tpe"), - client("cpu_lp"), client("cpu"), - client("epp_u"), client("epp_v"), - client("epp_y"), client("mpe_unified"), - client("vi_sb"), client("vi_u"), - client("vi_v"), client("vi_y"), - client("gr2d_dst"), client("pcie"), - client("avp"), client("gr3d0_fdc"), - client("gr3d1_fdc"), client("hda"), - client("host1x"), client("isp"), - client("cpu_lp"), client("cpu"), - client("mpe_mpec"), client("ahb_dma"), - client("ahb_slave"), client("sata"), - client("vde_bsev"), client("vde_dbg"), - client("vde_mbe"), client("vde_tpm"), -}; - -static const char *smmu_page_attrib[] = { - "SMMU: nr-nw-s", - "SMMU: nr-nw-ns", - "SMMU: nr-wr-s", - "SMMU: nr-wr-ns", - "SMMU: rd-nw-s", - "SMMU: rd-nw-ns", - "SMMU: rd-wr-s", - "SMMU: rd-wr-ns" -}; - -static DEFINE_SPINLOCK(mc_lock); -static unsigned long error_count = 0; -#define MAX_PRINTS 5 - -static void unthrottle_prints(struct work_struct *work) +static int __init tegra_mc_timing_init(void) { - unsigned long flags; - - spin_lock_irqsave(&mc_lock, flags); - error_count = 0; - spin_unlock_irqrestore(&mc_lock, flags); -} - -static DECLARE_DELAYED_WORK(unthrottle_prints_work, unthrottle_prints); - -static irqreturn_t tegra_mc_error_isr(int irq, void *data) -{ - const struct mc_client *client = NULL; - const char *mc_err; - const char *mc_err_info; - unsigned long count; - u32 stat; - u32 addr; - u32 err; - u32 type; - u32 is_write; - u32 is_secure; - u32 client_id; - u64 time; - u32 time_diff_ms; - unsigned long flags; - - stat = readl(mc + MC_INT_STATUS); - stat &= (MC_INT_DECERR_EMEM | - MC_INT_SECURITY_VIOLATION | - MC_INT_ARBITRATION_EMEM | - MC_INT_INVALID_SMMU_PAGE); - - if (stat & MC_INT_ARBITRATION_EMEM) { - spin_lock_irqsave(&arb_intr_info.lock, flags); - arb_intr_count++; - time = sched_clock(); - time_diff_ms = (time - arb_intr_info.time) >> 20; - arb_intr_info.time = time; - arb_intr_info.arb_intr_mma = - ((MMA_HISTORY_SAMPLES - 1) * time_diff_ms + - arb_intr_info.arb_intr_mma) / MMA_HISTORY_SAMPLES; - spin_unlock_irqrestore(&arb_intr_info.lock, flags); - if (stat == MC_INT_ARBITRATION_EMEM) - goto out; - } - - __cancel_delayed_work(&unthrottle_prints_work); - - spin_lock(&mc_lock); - count = ++error_count; - spin_unlock(&mc_lock); - - if (count >= MAX_PRINTS) { - if (count == MAX_PRINTS) - pr_err("Too many MC errors; throttling prints\n"); - schedule_delayed_work(&unthrottle_prints_work, HZ/2); - goto out; - } - - err = readl(mc + MC_ERROR_STATUS); - addr = readl(mc + MC_ERROR_ADDRESS); - is_write = err & (1<<16); - is_secure = err & (1<<17); - type = (err >> 28) & 7; - client_id = err & 0x7f; - if (client_id < ARRAY_SIZE(mc_clients)) - client = &mc_clients[client_id]; - - if (stat & MC_INT_DECERR_EMEM) - mc_err = "MC_DECERR"; - else if (stat & MC_INT_SECURITY_VIOLATION) - mc_err = "MC_SECURITY_ERR"; - else if (stat & MC_INT_INVALID_SMMU_PAGE) - mc_err = "MC_SMMU_ERR"; - else - mc_err = "unknown"; - - mc_err_info = ""; - if (type == 2) { - mc_err_info = "DECERR_EMEM"; - } else if (type == 3) { - mc_err_info = "SECURITY_TRUSTZONE"; - } else if (type == 4) { - mc_err_info = "SECURITY_CARVEOUT"; - } else if (type == 6) { - u32 attrib = (err >> 25) & 7; - mc_err_info = smmu_page_attrib[attrib]; - } - - pr_err("%s (0x%08X): %p %s (%s %s %s)\n", mc_err, err, (void*)addr, - (client) ? client->name : "unknown", - (is_secure)? "secure" : "non-secure", - (is_write) ? "write" : "read", - mc_err_info); - -out: - writel(stat, mc + MC_INT_STATUS); - return IRQ_HANDLED; -} - -static int __init tegra30_mc_init(void) -{ - u32 reg; - int ret = 0; - - reg = 0x0F7F1010; - writel(reg, mc + MC_RESERVED_RSV); - -#if defined(CONFIG_TEGRA_MC_EARLY_ACK) - reg = readl(mc + MC_EMEM_ARB_OVERRIDE); - reg |= 3; - writel(reg, mc + MC_EMEM_ARB_OVERRIDE); -#endif - if (request_irq(INT_MC_GENERAL, tegra_mc_error_isr, 0, - "mc_status", NULL)) { - pr_err("%s: unable to register MC error interrupt\n", __func__); - ret = -ENXIO; - } else { - reg = MC_INT_DECERR_EMEM | MC_INT_SECURITY_VIOLATION | - MC_INT_ARBITRATION_EMEM | MC_INT_INVALID_SMMU_PAGE; - writel(reg, mc + MC_INT_MASK); - } tegra_mc_timing_save(); -#if defined(CONFIG_ARCH_TEGRA_3x_SOC) - /* Bug 1059264 - * Set extra snap level to avoid VI starving and dropping data. - */ - writel(1, mc + MC_VE_EXTRA_SNAP_LEVELS); -#endif - - return ret; + return 0; } -arch_initcall(tegra30_mc_init); +arch_initcall(tegra_mc_timing_init); |