summaryrefslogtreecommitdiff
path: root/arch/mips/mm/c-octeon.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2013-05-01 08:47:44 -0700
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2013-05-01 08:47:44 -0700
commitbf61c8840efe60fd8f91446860b63338fb424158 (patch)
tree7a71832407a4f0d6346db773343f4c3ae2257b19 /arch/mips/mm/c-octeon.c
parent5846115b30f3a881e542c8bfde59a699c1c13740 (diff)
parent0c6a61657da78098472fd0eb71cc01f2387fa1bb (diff)
Merge branch 'next' into for-linus
Prepare first set of updates for 3.10 merge window.
Diffstat (limited to 'arch/mips/mm/c-octeon.c')
-rw-r--r--arch/mips/mm/c-octeon.c69
1 files changed, 46 insertions, 23 deletions
diff --git a/arch/mips/mm/c-octeon.c b/arch/mips/mm/c-octeon.c
index 44e69e7a4519..8557fb552863 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
@@ -104,7 +106,7 @@ static void octeon_flush_icache_all(void)
* Called to flush all memory associated with a memory
* context.
*
- * @mm: Memory context to flush
+ * @mm: Memory context to flush
*/
static void octeon_flush_cache_mm(struct mm_struct *mm)
{
@@ -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");
}