| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This file is subject to the terms and conditions of the GNU General Public | 
					
						
							|  |  |  |  * License.  See the file "COPYING" in the main directory of this archive | 
					
						
							|  |  |  |  * for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2005-2007 Cavium Networks | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-10-17 00:39:09 +02:00
										 |  |  | #include <linux/export.h>
 | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  | #include <linux/kernel.h>
 | 
					
						
							|  |  |  | #include <linux/sched.h>
 | 
					
						
							| 
									
										
										
										
											2009-06-19 14:05:26 +01:00
										 |  |  | #include <linux/smp.h>
 | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | #include <linux/mm.h>
 | 
					
						
							|  |  |  | #include <linux/bitops.h>
 | 
					
						
							|  |  |  | #include <linux/cpu.h>
 | 
					
						
							|  |  |  | #include <linux/io.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <asm/bcache.h>
 | 
					
						
							|  |  |  | #include <asm/bootinfo.h>
 | 
					
						
							|  |  |  | #include <asm/cacheops.h>
 | 
					
						
							|  |  |  | #include <asm/cpu-features.h>
 | 
					
						
							|  |  |  | #include <asm/page.h>
 | 
					
						
							|  |  |  | #include <asm/pgtable.h>
 | 
					
						
							|  |  |  | #include <asm/r4kcache.h>
 | 
					
						
							| 
									
										
										
										
											2012-05-15 00:04:48 -07:00
										 |  |  | #include <asm/traps.h>
 | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | #include <asm/mmu_context.h>
 | 
					
						
							|  |  |  | #include <asm/war.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <asm/octeon/octeon.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | unsigned long long cache_err_dcache[NR_CPUS]; | 
					
						
							| 
									
										
										
										
											2012-10-17 00:39:09 +02:00
										 |  |  | EXPORT_SYMBOL_GPL(cache_err_dcache); | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Octeon automatically flushes the dcache on tlb changes, so | 
					
						
							|  |  |  |  * from Linux's viewpoint it acts much like a physically | 
					
						
							|  |  |  |  * tagged cache. No flushing is needed | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void octeon_flush_data_cache_page(unsigned long addr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /* Nothing to do */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void octeon_local_flush_icache(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	asm volatile ("synci 0($0)"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Flush local I-cache for the specified range. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void local_octeon_flush_icache_range(unsigned long start, | 
					
						
							|  |  |  | 					    unsigned long end) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	octeon_local_flush_icache(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Flush caches as necessary for all cores affected by a | 
					
						
							|  |  |  |  * vma. If no vma is supplied, all cores are flushed. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @vma:    VMA to flush or NULL to flush all icaches. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void octeon_flush_icache_all_cores(struct vm_area_struct *vma) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	extern void octeon_send_ipi_single(int cpu, unsigned int action); | 
					
						
							|  |  |  | #ifdef CONFIG_SMP
 | 
					
						
							|  |  |  | 	int cpu; | 
					
						
							|  |  |  | 	cpumask_t mask; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mb(); | 
					
						
							|  |  |  | 	octeon_local_flush_icache(); | 
					
						
							|  |  |  | #ifdef CONFIG_SMP
 | 
					
						
							|  |  |  | 	preempt_disable(); | 
					
						
							|  |  |  | 	cpu = smp_processor_id(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * If we have a vma structure, we only need to worry about | 
					
						
							|  |  |  | 	 * cores it has been used on | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (vma) | 
					
						
							| 
									
										
										
										
											2009-09-24 09:34:50 -06:00
										 |  |  | 		mask = *mm_cpumask(vma->vm_mm); | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2012-03-29 15:38:30 +10:30
										 |  |  | 		mask = *cpu_online_mask; | 
					
						
							|  |  |  | 	cpumask_clear_cpu(cpu, &mask); | 
					
						
							|  |  |  | 	for_each_cpu(cpu, &mask) | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | 		octeon_send_ipi_single(cpu, SMP_ICACHE_FLUSH); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	preempt_enable(); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Called to flush the icache on all cores | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void octeon_flush_icache_all(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	octeon_flush_icache_all_cores(NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Called to flush all memory associated with a memory | 
					
						
							|  |  |  |  * context. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2013-01-22 12:59:30 +01:00
										 |  |  |  * @mm:	    Memory context to flush | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  |  */ | 
					
						
							|  |  |  | static void octeon_flush_cache_mm(struct mm_struct *mm) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * According to the R4K version of this file, CPUs without | 
					
						
							|  |  |  | 	 * dcache aliases don't need to do anything here | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Flush a range of kernel addresses out of the icache | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void octeon_flush_icache_range(unsigned long start, unsigned long end) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	octeon_flush_icache_all_cores(NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Flush the icache for a trampoline. These are used for interrupt | 
					
						
							|  |  |  |  * and exception hooking. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @addr:   Address to flush | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void octeon_flush_cache_sigtramp(unsigned long addr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct vm_area_struct *vma; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vma = find_vma(current->mm, addr); | 
					
						
							|  |  |  | 	octeon_flush_icache_all_cores(vma); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Flush a range out of a vma | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @vma:    VMA to flush | 
					
						
							|  |  |  |  * @start: | 
					
						
							|  |  |  |  * @end: | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void octeon_flush_cache_range(struct vm_area_struct *vma, | 
					
						
							|  |  |  | 				     unsigned long start, unsigned long end) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (vma->vm_flags & VM_EXEC) | 
					
						
							|  |  |  | 		octeon_flush_icache_all_cores(vma); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Flush a specific page of a vma | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @vma:    VMA to flush page for | 
					
						
							|  |  |  |  * @page:   Page to flush | 
					
						
							|  |  |  |  * @pfn: | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void octeon_flush_cache_page(struct vm_area_struct *vma, | 
					
						
							|  |  |  | 				    unsigned long page, unsigned long pfn) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (vma->vm_flags & VM_EXEC) | 
					
						
							|  |  |  | 		octeon_flush_icache_all_cores(vma); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-17 16:20:28 +01:00
										 |  |  | static void octeon_flush_kernel_vmap_range(unsigned long vaddr, int size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	BUG(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Probe Octeon's caches | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2010-02-04 15:48:49 -08:00
										 |  |  | static void __cpuinit probe_octeon(void) | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned long icache_size; | 
					
						
							|  |  |  | 	unsigned long dcache_size; | 
					
						
							|  |  |  | 	unsigned int config1; | 
					
						
							|  |  |  | 	struct cpuinfo_mips *c = ¤t_cpu_data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-07 16:03:44 -07:00
										 |  |  | 	config1 = read_c0_config1(); | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | 	switch (c->cputype) { | 
					
						
							|  |  |  | 	case CPU_CAVIUM_OCTEON: | 
					
						
							| 
									
										
										
										
											2010-02-10 15:12:48 -08:00
										 |  |  | 	case CPU_CAVIUM_OCTEON_PLUS: | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | 		c->icache.linesz = 2 << ((config1 >> 19) & 7); | 
					
						
							|  |  |  | 		c->icache.sets = 64 << ((config1 >> 22) & 7); | 
					
						
							|  |  |  | 		c->icache.ways = 1 + ((config1 >> 16) & 7); | 
					
						
							|  |  |  | 		c->icache.flags |= MIPS_CACHE_VTAG; | 
					
						
							|  |  |  | 		icache_size = | 
					
						
							|  |  |  | 			c->icache.sets * c->icache.ways * c->icache.linesz; | 
					
						
							|  |  |  | 		c->icache.waybit = ffs(icache_size / c->icache.ways) - 1; | 
					
						
							|  |  |  | 		c->dcache.linesz = 128; | 
					
						
							| 
									
										
										
										
											2010-02-10 15:12:48 -08:00
										 |  |  | 		if (c->cputype == CPU_CAVIUM_OCTEON_PLUS) | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | 			c->dcache.sets = 2; /* CN5XXX has two Dcache sets */ | 
					
						
							| 
									
										
										
										
											2010-02-10 15:12:48 -08:00
										 |  |  | 		else | 
					
						
							|  |  |  | 			c->dcache.sets = 1; /* CN3XXX has one Dcache set */ | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | 		c->dcache.ways = 64; | 
					
						
							|  |  |  | 		dcache_size = | 
					
						
							|  |  |  | 			c->dcache.sets * c->dcache.ways * c->dcache.linesz; | 
					
						
							|  |  |  | 		c->dcache.waybit = ffs(dcache_size / c->dcache.ways) - 1; | 
					
						
							|  |  |  | 		c->options |= MIPS_CPU_PREFETCH; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-07 16:03:44 -07:00
										 |  |  | 	case CPU_CAVIUM_OCTEON2: | 
					
						
							|  |  |  | 		c->icache.linesz = 2 << ((config1 >> 19) & 7); | 
					
						
							|  |  |  | 		c->icache.sets = 8; | 
					
						
							|  |  |  | 		c->icache.ways = 37; | 
					
						
							|  |  |  | 		c->icache.flags |= MIPS_CACHE_VTAG; | 
					
						
							|  |  |  | 		icache_size = c->icache.sets * c->icache.ways * c->icache.linesz; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		c->dcache.linesz = 128; | 
					
						
							|  |  |  | 		c->dcache.ways = 32; | 
					
						
							|  |  |  | 		c->dcache.sets = 8; | 
					
						
							|  |  |  | 		dcache_size = c->dcache.sets * c->dcache.ways * c->dcache.linesz; | 
					
						
							|  |  |  | 		c->options |= MIPS_CPU_PREFETCH; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2011-11-17 15:07:31 +00:00
										 |  |  | 		panic("Unsupported Cavium Networks CPU type"); | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* compute a couple of other cache variables */ | 
					
						
							|  |  |  | 	c->icache.waysize = icache_size / c->icache.ways; | 
					
						
							|  |  |  | 	c->dcache.waysize = dcache_size / c->dcache.ways; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	c->icache.sets = icache_size / (c->icache.linesz * c->icache.ways); | 
					
						
							|  |  |  | 	c->dcache.sets = dcache_size / (c->dcache.linesz * c->dcache.ways); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (smp_processor_id() == 0) { | 
					
						
							|  |  |  | 		pr_notice("Primary instruction cache %ldkB, %s, %d way, " | 
					
						
							|  |  |  | 			  "%d sets, linesize %d bytes.\n", | 
					
						
							|  |  |  | 			  icache_size >> 10, | 
					
						
							|  |  |  | 			  cpu_has_vtag_icache ? | 
					
						
							|  |  |  | 				"virtually tagged" : "physically tagged", | 
					
						
							|  |  |  | 			  c->icache.ways, c->icache.sets, c->icache.linesz); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		pr_notice("Primary data cache %ldkB, %d-way, %d sets, " | 
					
						
							|  |  |  | 			  "linesize %d bytes.\n", | 
					
						
							|  |  |  | 			  dcache_size >> 10, c->dcache.ways, | 
					
						
							|  |  |  | 			  c->dcache.sets, c->dcache.linesz); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-15 00:04:48 -07:00
										 |  |  | static void  __cpuinit octeon_cache_error_setup(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	extern char except_vec2_octeon; | 
					
						
							|  |  |  | 	set_handler(0x100, &except_vec2_octeon, 0x80); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Setup the Octeon cache flush routines | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2010-02-04 15:48:49 -08:00
										 |  |  | void __cpuinit octeon_cache_init(void) | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | { | 
					
						
							|  |  |  | 	probe_octeon(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	shm_align_mask = PAGE_SIZE - 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	flush_cache_all			= octeon_flush_icache_all; | 
					
						
							|  |  |  | 	__flush_cache_all		= octeon_flush_icache_all; | 
					
						
							|  |  |  | 	flush_cache_mm			= octeon_flush_cache_mm; | 
					
						
							|  |  |  | 	flush_cache_page		= octeon_flush_cache_page; | 
					
						
							|  |  |  | 	flush_cache_range		= octeon_flush_cache_range; | 
					
						
							|  |  |  | 	flush_cache_sigtramp		= octeon_flush_cache_sigtramp; | 
					
						
							|  |  |  | 	flush_icache_all		= octeon_flush_icache_all; | 
					
						
							|  |  |  | 	flush_data_cache_page		= octeon_flush_data_cache_page; | 
					
						
							|  |  |  | 	flush_icache_range		= octeon_flush_icache_range; | 
					
						
							|  |  |  | 	local_flush_icache_range	= local_octeon_flush_icache_range; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-17 16:20:28 +01:00
										 |  |  | 	__flush_kernel_vmap_range	= octeon_flush_kernel_vmap_range; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | 	build_clear_page(); | 
					
						
							|  |  |  | 	build_copy_page(); | 
					
						
							| 
									
										
										
										
											2012-05-15 00:04:48 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	board_cache_error_setup = octeon_cache_error_setup; | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-15 13:58:59 -08:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  |  * Handle a cache error exception | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-10-17 00:39:09 +02:00
										 |  |  | static RAW_NOTIFIER_HEAD(co_cache_error_chain); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int register_co_cache_error_notifier(struct notifier_block *nb) | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-17 00:39:09 +02:00
										 |  |  | 	return raw_notifier_chain_register(&co_cache_error_chain, nb); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(register_co_cache_error_notifier); | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-17 00:39:09 +02:00
										 |  |  | 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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-15 13:58:59 -08:00
										 |  |  | static void co_cache_error_call_notifiers(unsigned long val) | 
					
						
							| 
									
										
										
										
											2012-10-17 00:39:09 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-11-15 13:58:59 -08:00
										 |  |  | 	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); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-15 13:58:59 -08:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2009-07-05 19:23:30 +01:00
										 |  |  |  * Called when the the exception is recoverable | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-11-15 13:58:59 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | asmlinkage void cache_parity_error_octeon_recoverable(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-17 00:39:09 +02:00
										 |  |  | 	co_cache_error_call_notifiers(0); | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2009-07-05 19:23:30 +01:00
										 |  |  |  * Called when the the exception is not recoverable | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-11-15 13:58:59 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | asmlinkage void cache_parity_error_octeon_non_recoverable(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-17 00:39:09 +02:00
										 |  |  | 	co_cache_error_call_notifiers(1); | 
					
						
							|  |  |  | 	panic("Can't handle cache error: nested exception"); | 
					
						
							| 
									
										
										
										
											2009-01-08 16:46:40 -08:00
										 |  |  | } |