diff options
Diffstat (limited to 'arch/mips/mm/c-octeon.c')
-rw-r--r-- | arch/mips/mm/c-octeon.c | 67 |
1 files changed, 45 insertions, 22 deletions
diff --git a/arch/mips/mm/c-octeon.c b/arch/mips/mm/c-octeon.c index 44e69e7a451..6ec04daf423 100644 --- a/arch/mips/mm/c-octeon.c +++ b/arch/mips/mm/c-octeon.c @@ -5,6 +5,7 @@ * * Copyright (C) 2005-2007 Cavium Networks */ +#include <linux/export.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -28,6 +29,7 @@ #include <asm/octeon/octeon.h> unsigned long long cache_err_dcache[NR_CPUS]; +EXPORT_SYMBOL_GPL(cache_err_dcache); /** * Octeon automatically flushes the dcache on tlb changes, so @@ -284,39 +286,59 @@ void __cpuinit octeon_cache_init(void) board_cache_error_setup = octeon_cache_error_setup; } -/** +/* * Handle a cache error exception */ +static RAW_NOTIFIER_HEAD(co_cache_error_chain); -static void cache_parity_error_octeon(int non_recoverable) +int register_co_cache_error_notifier(struct notifier_block *nb) { - unsigned long coreid = cvmx_get_core_num(); - uint64_t icache_err = read_octeon_c0_icacheerr(); - - pr_err("Cache error exception:\n"); - pr_err("cp0_errorepc == %lx\n", read_c0_errorepc()); - if (icache_err & 1) { - pr_err("CacheErr (Icache) == %llx\n", - (unsigned long long)icache_err); - write_octeon_c0_icacheerr(0); - } - if (cache_err_dcache[coreid] & 1) { - pr_err("CacheErr (Dcache) == %llx\n", - (unsigned long long)cache_err_dcache[coreid]); - cache_err_dcache[coreid] = 0; - } + return raw_notifier_chain_register(&co_cache_error_chain, nb); +} +EXPORT_SYMBOL_GPL(register_co_cache_error_notifier); + +int unregister_co_cache_error_notifier(struct notifier_block *nb) +{ + return raw_notifier_chain_unregister(&co_cache_error_chain, nb); +} +EXPORT_SYMBOL_GPL(unregister_co_cache_error_notifier); - if (non_recoverable) - panic("Can't handle cache error: nested exception"); +static void co_cache_error_call_notifiers(unsigned long val) +{ + int rv = raw_notifier_call_chain(&co_cache_error_chain, val, NULL); + if ((rv & ~NOTIFY_STOP_MASK) != NOTIFY_OK) { + u64 dcache_err; + unsigned long coreid = cvmx_get_core_num(); + u64 icache_err = read_octeon_c0_icacheerr(); + + if (val) { + dcache_err = cache_err_dcache[coreid]; + cache_err_dcache[coreid] = 0; + } else { + dcache_err = read_octeon_c0_dcacheerr(); + } + + pr_err("Core%lu: Cache error exception:\n", coreid); + pr_err("cp0_errorepc == %lx\n", read_c0_errorepc()); + if (icache_err & 1) { + pr_err("CacheErr (Icache) == %llx\n", + (unsigned long long)icache_err); + write_octeon_c0_icacheerr(0); + } + if (dcache_err & 1) { + pr_err("CacheErr (Dcache) == %llx\n", + (unsigned long long)dcache_err); + } + } } -/** +/* * Called when the the exception is recoverable */ asmlinkage void cache_parity_error_octeon_recoverable(void) { - cache_parity_error_octeon(0); + co_cache_error_call_notifiers(0); } /** @@ -325,5 +347,6 @@ asmlinkage void cache_parity_error_octeon_recoverable(void) asmlinkage void cache_parity_error_octeon_non_recoverable(void) { - cache_parity_error_octeon(1); + co_cache_error_call_notifiers(1); + panic("Can't handle cache error: nested exception"); } |