diff options
-rw-r--r-- | arch/arm/mach-tegra/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/board.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/common-t2.c | 191 | ||||
-rw-r--r-- | arch/arm/mach-tegra/common.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_memctrl.c | 65 |
5 files changed, 195 insertions, 64 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index f02189fda030..419bb92384cd 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -1,4 +1,5 @@ obj-y += common.o +obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += common-t2.o obj-y += board-common.o obj-y += io.o obj-y += irq.o diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h index 702a52ff1936..a5cf92369052 100644 --- a/arch/arm/mach-tegra/board.h +++ b/arch/arm/mach-tegra/board.h @@ -25,6 +25,7 @@ struct tegra_suspend_platform_data; +void __init tegra_mc_init(void); void __init tegra_common_init(void); void __init tegra_map_common_io(void); void __init tegra_init_irq(void); diff --git a/arch/arm/mach-tegra/common-t2.c b/arch/arm/mach-tegra/common-t2.c new file mode 100644 index 000000000000..f9eade8311d9 --- /dev/null +++ b/arch/arm/mach-tegra/common-t2.c @@ -0,0 +1,191 @@ +/* + * arch/arm/mach-tegra/common-t2.c + * + * Tegra 2 SoC-specific initialization (memory controller, etc.) + * + * Copyright (c) 2009-2010, 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> + +#include <mach/iomap.h> +#include <mach/irqs.h> + +#define MC_INT_STATUS 0x0 +#define MC_INT_MASK 0x4 +#define MC_INT_DECERR_EMEM_OTHERS (1<<6) +#define MC_INT_INVALID_GART_PAGE (1<<7) +#define MC_INT_SECURITY_VIOLATION (1<<8) + +#define MC_GART_ERROR_STATUS 0x30 +#define MC_GART_ERROR_ADDRESS 0x34 + +#define MC_DECERR_EMEM_OTHERS_STATUS 0x58 +#define MC_DECERR_EMEM_OTHERS_ADDRESS 0x5c + +#define MC_SECURITY_VIOLATION_STATUS 0x74 +#define MC_SECURITY_VIOLATION_ADDRESS 0x78 + +struct mc_client { + bool write; + const char *name; +}; + +#define client(_name,_write) \ + { \ + .write = _write, \ + .name = _name, \ + } + +static const struct mc_client mc_clients[] = { + client("display0_wina", false), client("display1_wina", false), + client("display0_winb", false), client("display1_winb", false), + client("display0_winc", false), client("display1_winc", false), + client("display0_winb_vfilter", false), + client("display1_winb_vfilter", false), + client("epp", false), client("gr2d_pat", false), + client("gr2d_src", false), client("mpe_unified", false), + client("vi_chroma_filter", false), client("cop", false), + client("display0_cursor", false), client("display1_cursor", false), + client("gr3d_fdc", false), client("gr2d_dst", false), + client("host1x_dma", false), client("host1x_generic", false), + client("gr3d_idx", false), client("cpu_uncached", false), + client("mpe_intrapred", false), client("mpe_mpea", false), + client("mpe_mpec", false), client("ahb_dma", false), + client("ahb_slave", false), client("gr3d_tex", false), + client("vde_bsev", false), client("vde_mbe", false), + client("vde_mce", false), client("vde_tpe", false), + client("epp_u", true), client("epp_v", true), + client("epp_y", true), client("mpe_unified", true), + client("vi_sb", true), client("vi_u", true), + client("vi_v", true), client("vi_y", true), + client("gr2d_dst", true), client("gr3d_fdc", true), + client("host1x", true), client("isp", true), + client("cpu_uncached", true), client("mpe_mpec", true), + client("ahb_dma", true), client("ahb_slave", true), + client("avp_bsev", true), client("avp_mbe", true), + client("avp_tpm", true), +}; + +static DEFINE_SPINLOCK(mc_lock); +static unsigned long error_count = 0; +#define MAX_PRINTS 5 + +static void unthrottle_prints(struct work_struct *work) +{ + 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) +{ + void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE); + unsigned long count; + u32 stat; + + stat = readl(mc + MC_INT_STATUS); + stat &= (MC_INT_SECURITY_VIOLATION | + MC_INT_INVALID_GART_PAGE | + MC_INT_DECERR_EMEM_OTHERS); + + 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; + } + + if (stat & MC_INT_DECERR_EMEM_OTHERS) { + const struct mc_client *client = NULL; + u32 addr, req; + + req = readl(mc + MC_DECERR_EMEM_OTHERS_STATUS); + addr = readl(mc + MC_DECERR_EMEM_OTHERS_ADDRESS); + req &= 0x3f; + if (req < ARRAY_SIZE(mc_clients)) + client = &mc_clients[req]; + + pr_err("MC_DECERR: %p %s (%s)\n", (void*)addr, + (client) ? client->name : "unknown", + (client && client->write) ? "write" : "read"); + } + + if (stat & MC_INT_INVALID_GART_PAGE) { + const struct mc_client *client = NULL; + u32 addr, req; + + req = readl(mc + MC_GART_ERROR_STATUS); + addr = readl(mc + MC_GART_ERROR_ADDRESS); + req = (req >> 1) & 0x3f; + + if (req < ARRAY_SIZE(mc_clients)) + client = &mc_clients[req]; + + pr_err("MC_GART_ERR: %p %s (%s)\n", (void*)addr, + (client) ? client->name : "unknown", + (client && client->write) ? "write" : "read"); + } + + if (stat & MC_INT_SECURITY_VIOLATION) { + const struct mc_client *client = NULL; + const char *type = NULL; + u32 addr, req; + + req = readl(mc + MC_SECURITY_VIOLATION_STATUS); + addr = readl(mc + MC_SECURITY_VIOLATION_ADDRESS); + + type = (req & (1<<30)) ? "carveout" : "trustzone"; + + req &= 0x3f; + if (req < ARRAY_SIZE(mc_clients)) + client = &mc_clients[req]; + + pr_err("MC_SECURITY_ERR (%s): %p %s (%s)\n", type, (void*)addr, + (client) ? client->name : "unknown", + (client && client->write) ? "write" : "read"); + } +out: + writel(stat, mc + MC_INT_STATUS); + return IRQ_HANDLED; +} + +void __init tegra_mc_init(void) +{ + 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__); + } else { + void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE); + u32 reg = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE | + MC_INT_DECERR_EMEM_OTHERS; + writel(reg, mc + MC_INT_MASK); + } +} diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 33eb91e8c2ab..42a41d2442f8 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -68,5 +68,6 @@ void __init tegra_common_init(void) tegra_init_clock(); tegra_init_cache(); tegra_dma_init(); + tegra_mc_init(); arm_pm_restart = tegra_machine_restart; } diff --git a/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_memctrl.c b/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_memctrl.c index d589049ed4b4..d034d5d145ae 100644 --- a/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_memctrl.c +++ b/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_memctrl.c @@ -45,7 +45,6 @@ NvError NvRmPrivAp20McErrorMonitorStart(NvRmDeviceHandle hRm); void NvRmPrivAp20McErrorMonitorStop(NvRmDeviceHandle hRm); void NvRmPrivAp20SetupMc(NvRmDeviceHandle hRm); static void McErrorIntHandler(void* args); -static NvOsInterruptHandle s_McInterruptHandle = NULL; void McStatAp20_Start( @@ -64,77 +63,15 @@ McStatAp20_Stop( void McErrorIntHandler(void* args) { - NvU32 RegVal; - NvU32 IntStatus; - NvU32 IntClear = 0; - NvRmDeviceHandle hRm = (NvRmDeviceHandle)args; - - IntStatus = NV_REGR(hRm, NvRmPrivModuleID_MemoryController, 0, MC_INTSTATUS_0); - if ( NV_DRF_VAL(MC, INTSTATUS, SECURITY_VIOLATION_INT, IntStatus) ) - { - IntClear |= NV_DRF_DEF(MC, INTSTATUS, SECURITY_VIOLATION_INT, SET); - RegVal = NV_REGR(hRm, NvRmPrivModuleID_MemoryController, 0, - MC_SECURITY_VIOLATION_ADR_0); - NvOsDebugPrintf("SECURITY_VIOLATION DecErrAddress=0x%x ", RegVal); - RegVal = NV_REGR(hRm, NvRmPrivModuleID_MemoryController, 0, - MC_SECURITY_VIOLATION_STATUS_0); - NvOsDebugPrintf("SECURITY_VIOLATION DecErrStatus=0x%x ", RegVal); - } - if ( NV_DRF_VAL(MC, INTSTATUS, DECERR_EMEM_OTHERS_INT, IntStatus) ) - { - IntClear |= NV_DRF_DEF(MC, INTSTATUS, DECERR_EMEM_OTHERS_INT, SET); - RegVal = NV_REGR(hRm, NvRmPrivModuleID_MemoryController, 0, - MC_DECERR_EMEM_OTHERS_ADR_0); - NvOsDebugPrintf("EMEM DecErrAddress=0x%x ", RegVal); - RegVal = NV_REGR(hRm, NvRmPrivModuleID_MemoryController, 0, - MC_DECERR_EMEM_OTHERS_STATUS_0); - NvOsDebugPrintf("EMEM DecErrStatus=0x%x ", RegVal); - } - if ( NV_DRF_VAL(MC, INTSTATUS, INVALID_GART_PAGE_INT, IntStatus) ) - { - IntClear |= NV_DRF_DEF(MC, INTSTATUS, INVALID_GART_PAGE_INT, SET); - RegVal = NV_REGR(hRm, NvRmPrivModuleID_MemoryController, 0, - MC_GART_ERROR_ADDR_0); - NvOsDebugPrintf("GART DecErrAddress=0x%x ", RegVal); - RegVal = NV_REGR(hRm, NvRmPrivModuleID_MemoryController, 0, - MC_GART_ERROR_REQ_0); - NvOsDebugPrintf("GART DecErrStatus=0x%x ", RegVal); - } - - NV_ASSERT(!"MC Decode Error "); - // Clear the interrupt. - NV_REGW(hRm, NvRmPrivModuleID_MemoryController, 0, MC_INTSTATUS_0, IntClear); - NvRmInterruptDone(s_McInterruptHandle); } NvError NvRmPrivAp20McErrorMonitorStart(NvRmDeviceHandle hRm) { - NvU32 val; - NvU32 IrqList; - NvError e = NvSuccess; - NvOsInterruptHandler handler; - - if (s_McInterruptHandle == NULL) - { - // Install an interrupt handler. - handler = McErrorIntHandler; - IrqList = NvRmGetIrqForLogicalInterrupt(hRm, - NvRmPrivModuleID_MemoryController, 0); - NV_CHECK_ERROR( NvRmInterruptRegister(hRm, 1, &IrqList, &handler, - hRm, &s_McInterruptHandle, NV_TRUE) ); - // Enable Dec Err interrupts in memory Controller. - val = NV_DRF_DEF(MC, INTMASK, SECURITY_VIOLATION_INTMASK, UNMASKED) | - NV_DRF_DEF(MC, INTMASK, DECERR_EMEM_OTHERS_INTMASK, UNMASKED) | - NV_DRF_DEF(MC, INTMASK, INVALID_GART_PAGE_INTMASK, UNMASKED); - NV_REGW(hRm, NvRmPrivModuleID_MemoryController, 0, MC_INTMASK_0, val); - } - return e; + return NvSuccess; } void NvRmPrivAp20McErrorMonitorStop(NvRmDeviceHandle hRm) { - NvRmInterruptUnregister(hRm, s_McInterruptHandle); - s_McInterruptHandle = NULL; } /* This function sets some performance timings for Mc & Emc. Numbers are from |