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 @@ | |||
5 | * | 5 | * |
6 | * Copyright (C) 2005-2007 Cavium Networks | 6 | * Copyright (C) 2005-2007 Cavium Networks |
7 | */ | 7 | */ |
8 | #include <linux/export.h> | ||
8 | #include <linux/init.h> | 9 | #include <linux/init.h> |
9 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
10 | #include <linux/sched.h> | 11 | #include <linux/sched.h> |
@@ -28,6 +29,7 @@ | |||
28 | #include <asm/octeon/octeon.h> | 29 | #include <asm/octeon/octeon.h> |
29 | 30 | ||
30 | unsigned long long cache_err_dcache[NR_CPUS]; | 31 | unsigned long long cache_err_dcache[NR_CPUS]; |
32 | EXPORT_SYMBOL_GPL(cache_err_dcache); | ||
31 | 33 | ||
32 | /** | 34 | /** |
33 | * Octeon automatically flushes the dcache on tlb changes, so | 35 | * Octeon automatically flushes the dcache on tlb changes, so |
@@ -284,39 +286,59 @@ void __cpuinit octeon_cache_init(void) | |||
284 | board_cache_error_setup = octeon_cache_error_setup; | 286 | board_cache_error_setup = octeon_cache_error_setup; |
285 | } | 287 | } |
286 | 288 | ||
287 | /** | 289 | /* |
288 | * Handle a cache error exception | 290 | * Handle a cache error exception |
289 | */ | 291 | */ |
292 | static RAW_NOTIFIER_HEAD(co_cache_error_chain); | ||
290 | 293 | ||
291 | static void cache_parity_error_octeon(int non_recoverable) | 294 | int register_co_cache_error_notifier(struct notifier_block *nb) |
292 | { | 295 | { |
293 | unsigned long coreid = cvmx_get_core_num(); | 296 | return raw_notifier_chain_register(&co_cache_error_chain, nb); |
294 | uint64_t icache_err = read_octeon_c0_icacheerr(); | 297 | } |
295 | 298 | EXPORT_SYMBOL_GPL(register_co_cache_error_notifier); | |
296 | pr_err("Cache error exception:\n"); | 299 | |
297 | pr_err("cp0_errorepc == %lx\n", read_c0_errorepc()); | 300 | int unregister_co_cache_error_notifier(struct notifier_block *nb) |
298 | if (icache_err & 1) { | 301 | { |
299 | pr_err("CacheErr (Icache) == %llx\n", | 302 | return raw_notifier_chain_unregister(&co_cache_error_chain, nb); |
300 | (unsigned long long)icache_err); | 303 | } |
301 | write_octeon_c0_icacheerr(0); | 304 | EXPORT_SYMBOL_GPL(unregister_co_cache_error_notifier); |
302 | } | ||
303 | if (cache_err_dcache[coreid] & 1) { | ||
304 | pr_err("CacheErr (Dcache) == %llx\n", | ||
305 | (unsigned long long)cache_err_dcache[coreid]); | ||
306 | cache_err_dcache[coreid] = 0; | ||
307 | } | ||
308 | 305 | ||
309 | if (non_recoverable) | 306 | static void co_cache_error_call_notifiers(unsigned long val) |
310 | panic("Can't handle cache error: nested exception"); | 307 | { |
308 | int rv = raw_notifier_call_chain(&co_cache_error_chain, val, NULL); | ||
309 | if ((rv & ~NOTIFY_STOP_MASK) != NOTIFY_OK) { | ||
310 | u64 dcache_err; | ||
311 | unsigned long coreid = cvmx_get_core_num(); | ||
312 | u64 icache_err = read_octeon_c0_icacheerr(); | ||
313 | |||
314 | if (val) { | ||
315 | dcache_err = cache_err_dcache[coreid]; | ||
316 | cache_err_dcache[coreid] = 0; | ||
317 | } else { | ||
318 | dcache_err = read_octeon_c0_dcacheerr(); | ||
319 | } | ||
320 | |||
321 | pr_err("Core%lu: Cache error exception:\n", coreid); | ||
322 | pr_err("cp0_errorepc == %lx\n", read_c0_errorepc()); | ||
323 | if (icache_err & 1) { | ||
324 | pr_err("CacheErr (Icache) == %llx\n", | ||
325 | (unsigned long long)icache_err); | ||
326 | write_octeon_c0_icacheerr(0); | ||
327 | } | ||
328 | if (dcache_err & 1) { | ||
329 | pr_err("CacheErr (Dcache) == %llx\n", | ||
330 | (unsigned long long)dcache_err); | ||
331 | } | ||
332 | } | ||
311 | } | 333 | } |
312 | 334 | ||
313 | /** | 335 | /* |
314 | * Called when the the exception is recoverable | 336 | * Called when the the exception is recoverable |
315 | */ | 337 | */ |
316 | 338 | ||
317 | asmlinkage void cache_parity_error_octeon_recoverable(void) | 339 | asmlinkage void cache_parity_error_octeon_recoverable(void) |
318 | { | 340 | { |
319 | cache_parity_error_octeon(0); | 341 | co_cache_error_call_notifiers(0); |
320 | } | 342 | } |
321 | 343 | ||
322 | /** | 344 | /** |
@@ -325,5 +347,6 @@ asmlinkage void cache_parity_error_octeon_recoverable(void) | |||
325 | 347 | ||
326 | asmlinkage void cache_parity_error_octeon_non_recoverable(void) | 348 | asmlinkage void cache_parity_error_octeon_non_recoverable(void) |
327 | { | 349 | { |
328 | cache_parity_error_octeon(1); | 350 | co_cache_error_call_notifiers(1); |
351 | panic("Can't handle cache error: nested exception"); | ||
329 | } | 352 | } |