18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
38c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
48c2ecf20Sopenharmony_ci * for more details.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2005-2007 Cavium Networks
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/export.h>
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/sched.h>
118c2ecf20Sopenharmony_ci#include <linux/smp.h>
128c2ecf20Sopenharmony_ci#include <linux/mm.h>
138c2ecf20Sopenharmony_ci#include <linux/bitops.h>
148c2ecf20Sopenharmony_ci#include <linux/cpu.h>
158c2ecf20Sopenharmony_ci#include <linux/io.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <asm/bcache.h>
188c2ecf20Sopenharmony_ci#include <asm/bootinfo.h>
198c2ecf20Sopenharmony_ci#include <asm/cacheops.h>
208c2ecf20Sopenharmony_ci#include <asm/cpu-features.h>
218c2ecf20Sopenharmony_ci#include <asm/cpu-type.h>
228c2ecf20Sopenharmony_ci#include <asm/page.h>
238c2ecf20Sopenharmony_ci#include <asm/r4kcache.h>
248c2ecf20Sopenharmony_ci#include <asm/traps.h>
258c2ecf20Sopenharmony_ci#include <asm/mmu_context.h>
268c2ecf20Sopenharmony_ci#include <asm/war.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include <asm/octeon/octeon.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ciunsigned long long cache_err_dcache[NR_CPUS];
318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cache_err_dcache);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/**
348c2ecf20Sopenharmony_ci * Octeon automatically flushes the dcache on tlb changes, so
358c2ecf20Sopenharmony_ci * from Linux's viewpoint it acts much like a physically
368c2ecf20Sopenharmony_ci * tagged cache. No flushing is needed
378c2ecf20Sopenharmony_ci *
388c2ecf20Sopenharmony_ci */
398c2ecf20Sopenharmony_cistatic void octeon_flush_data_cache_page(unsigned long addr)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci    /* Nothing to do */
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic inline void octeon_local_flush_icache(void)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	asm volatile ("synci 0($0)");
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/*
508c2ecf20Sopenharmony_ci * Flush local I-cache for the specified range.
518c2ecf20Sopenharmony_ci */
528c2ecf20Sopenharmony_cistatic void local_octeon_flush_icache_range(unsigned long start,
538c2ecf20Sopenharmony_ci					    unsigned long end)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	octeon_local_flush_icache();
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/**
598c2ecf20Sopenharmony_ci * Flush caches as necessary for all cores affected by a
608c2ecf20Sopenharmony_ci * vma. If no vma is supplied, all cores are flushed.
618c2ecf20Sopenharmony_ci *
628c2ecf20Sopenharmony_ci * @vma:    VMA to flush or NULL to flush all icaches.
638c2ecf20Sopenharmony_ci */
648c2ecf20Sopenharmony_cistatic void octeon_flush_icache_all_cores(struct vm_area_struct *vma)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	extern void octeon_send_ipi_single(int cpu, unsigned int action);
678c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
688c2ecf20Sopenharmony_ci	int cpu;
698c2ecf20Sopenharmony_ci	cpumask_t mask;
708c2ecf20Sopenharmony_ci#endif
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	mb();
738c2ecf20Sopenharmony_ci	octeon_local_flush_icache();
748c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
758c2ecf20Sopenharmony_ci	preempt_disable();
768c2ecf20Sopenharmony_ci	cpu = smp_processor_id();
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	/*
798c2ecf20Sopenharmony_ci	 * If we have a vma structure, we only need to worry about
808c2ecf20Sopenharmony_ci	 * cores it has been used on
818c2ecf20Sopenharmony_ci	 */
828c2ecf20Sopenharmony_ci	if (vma)
838c2ecf20Sopenharmony_ci		mask = *mm_cpumask(vma->vm_mm);
848c2ecf20Sopenharmony_ci	else
858c2ecf20Sopenharmony_ci		mask = *cpu_online_mask;
868c2ecf20Sopenharmony_ci	cpumask_clear_cpu(cpu, &mask);
878c2ecf20Sopenharmony_ci	for_each_cpu(cpu, &mask)
888c2ecf20Sopenharmony_ci		octeon_send_ipi_single(cpu, SMP_ICACHE_FLUSH);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	preempt_enable();
918c2ecf20Sopenharmony_ci#endif
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci/**
968c2ecf20Sopenharmony_ci * Called to flush the icache on all cores
978c2ecf20Sopenharmony_ci */
988c2ecf20Sopenharmony_cistatic void octeon_flush_icache_all(void)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	octeon_flush_icache_all_cores(NULL);
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci/**
1058c2ecf20Sopenharmony_ci * Called to flush all memory associated with a memory
1068c2ecf20Sopenharmony_ci * context.
1078c2ecf20Sopenharmony_ci *
1088c2ecf20Sopenharmony_ci * @mm:	    Memory context to flush
1098c2ecf20Sopenharmony_ci */
1108c2ecf20Sopenharmony_cistatic void octeon_flush_cache_mm(struct mm_struct *mm)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	/*
1138c2ecf20Sopenharmony_ci	 * According to the R4K version of this file, CPUs without
1148c2ecf20Sopenharmony_ci	 * dcache aliases don't need to do anything here
1158c2ecf20Sopenharmony_ci	 */
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci/**
1208c2ecf20Sopenharmony_ci * Flush a range of kernel addresses out of the icache
1218c2ecf20Sopenharmony_ci *
1228c2ecf20Sopenharmony_ci */
1238c2ecf20Sopenharmony_cistatic void octeon_flush_icache_range(unsigned long start, unsigned long end)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	octeon_flush_icache_all_cores(NULL);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci/**
1308c2ecf20Sopenharmony_ci * Flush a range out of a vma
1318c2ecf20Sopenharmony_ci *
1328c2ecf20Sopenharmony_ci * @vma:    VMA to flush
1338c2ecf20Sopenharmony_ci * @start:
1348c2ecf20Sopenharmony_ci * @end:
1358c2ecf20Sopenharmony_ci */
1368c2ecf20Sopenharmony_cistatic void octeon_flush_cache_range(struct vm_area_struct *vma,
1378c2ecf20Sopenharmony_ci				     unsigned long start, unsigned long end)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	if (vma->vm_flags & VM_EXEC)
1408c2ecf20Sopenharmony_ci		octeon_flush_icache_all_cores(vma);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci/**
1458c2ecf20Sopenharmony_ci * Flush a specific page of a vma
1468c2ecf20Sopenharmony_ci *
1478c2ecf20Sopenharmony_ci * @vma:    VMA to flush page for
1488c2ecf20Sopenharmony_ci * @page:   Page to flush
1498c2ecf20Sopenharmony_ci * @pfn:
1508c2ecf20Sopenharmony_ci */
1518c2ecf20Sopenharmony_cistatic void octeon_flush_cache_page(struct vm_area_struct *vma,
1528c2ecf20Sopenharmony_ci				    unsigned long page, unsigned long pfn)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	if (vma->vm_flags & VM_EXEC)
1558c2ecf20Sopenharmony_ci		octeon_flush_icache_all_cores(vma);
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic void octeon_flush_kernel_vmap_range(unsigned long vaddr, int size)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	BUG();
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci/**
1648c2ecf20Sopenharmony_ci * Probe Octeon's caches
1658c2ecf20Sopenharmony_ci *
1668c2ecf20Sopenharmony_ci */
1678c2ecf20Sopenharmony_cistatic void probe_octeon(void)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	unsigned long icache_size;
1708c2ecf20Sopenharmony_ci	unsigned long dcache_size;
1718c2ecf20Sopenharmony_ci	unsigned int config1;
1728c2ecf20Sopenharmony_ci	struct cpuinfo_mips *c = &current_cpu_data;
1738c2ecf20Sopenharmony_ci	int cputype = current_cpu_type();
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	config1 = read_c0_config1();
1768c2ecf20Sopenharmony_ci	switch (cputype) {
1778c2ecf20Sopenharmony_ci	case CPU_CAVIUM_OCTEON:
1788c2ecf20Sopenharmony_ci	case CPU_CAVIUM_OCTEON_PLUS:
1798c2ecf20Sopenharmony_ci		c->icache.linesz = 2 << ((config1 >> 19) & 7);
1808c2ecf20Sopenharmony_ci		c->icache.sets = 64 << ((config1 >> 22) & 7);
1818c2ecf20Sopenharmony_ci		c->icache.ways = 1 + ((config1 >> 16) & 7);
1828c2ecf20Sopenharmony_ci		c->icache.flags |= MIPS_CACHE_VTAG;
1838c2ecf20Sopenharmony_ci		icache_size =
1848c2ecf20Sopenharmony_ci			c->icache.sets * c->icache.ways * c->icache.linesz;
1858c2ecf20Sopenharmony_ci		c->icache.waybit = ffs(icache_size / c->icache.ways) - 1;
1868c2ecf20Sopenharmony_ci		c->dcache.linesz = 128;
1878c2ecf20Sopenharmony_ci		if (cputype == CPU_CAVIUM_OCTEON_PLUS)
1888c2ecf20Sopenharmony_ci			c->dcache.sets = 2; /* CN5XXX has two Dcache sets */
1898c2ecf20Sopenharmony_ci		else
1908c2ecf20Sopenharmony_ci			c->dcache.sets = 1; /* CN3XXX has one Dcache set */
1918c2ecf20Sopenharmony_ci		c->dcache.ways = 64;
1928c2ecf20Sopenharmony_ci		dcache_size =
1938c2ecf20Sopenharmony_ci			c->dcache.sets * c->dcache.ways * c->dcache.linesz;
1948c2ecf20Sopenharmony_ci		c->dcache.waybit = ffs(dcache_size / c->dcache.ways) - 1;
1958c2ecf20Sopenharmony_ci		c->options |= MIPS_CPU_PREFETCH;
1968c2ecf20Sopenharmony_ci		break;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	case CPU_CAVIUM_OCTEON2:
1998c2ecf20Sopenharmony_ci		c->icache.linesz = 2 << ((config1 >> 19) & 7);
2008c2ecf20Sopenharmony_ci		c->icache.sets = 8;
2018c2ecf20Sopenharmony_ci		c->icache.ways = 37;
2028c2ecf20Sopenharmony_ci		c->icache.flags |= MIPS_CACHE_VTAG;
2038c2ecf20Sopenharmony_ci		icache_size = c->icache.sets * c->icache.ways * c->icache.linesz;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci		c->dcache.linesz = 128;
2068c2ecf20Sopenharmony_ci		c->dcache.ways = 32;
2078c2ecf20Sopenharmony_ci		c->dcache.sets = 8;
2088c2ecf20Sopenharmony_ci		dcache_size = c->dcache.sets * c->dcache.ways * c->dcache.linesz;
2098c2ecf20Sopenharmony_ci		c->options |= MIPS_CPU_PREFETCH;
2108c2ecf20Sopenharmony_ci		break;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	case CPU_CAVIUM_OCTEON3:
2138c2ecf20Sopenharmony_ci		c->icache.linesz = 128;
2148c2ecf20Sopenharmony_ci		c->icache.sets = 16;
2158c2ecf20Sopenharmony_ci		c->icache.ways = 39;
2168c2ecf20Sopenharmony_ci		c->icache.flags |= MIPS_CACHE_VTAG;
2178c2ecf20Sopenharmony_ci		icache_size = c->icache.sets * c->icache.ways * c->icache.linesz;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci		c->dcache.linesz = 128;
2208c2ecf20Sopenharmony_ci		c->dcache.ways = 32;
2218c2ecf20Sopenharmony_ci		c->dcache.sets = 8;
2228c2ecf20Sopenharmony_ci		dcache_size = c->dcache.sets * c->dcache.ways * c->dcache.linesz;
2238c2ecf20Sopenharmony_ci		c->options |= MIPS_CPU_PREFETCH;
2248c2ecf20Sopenharmony_ci		break;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	default:
2278c2ecf20Sopenharmony_ci		panic("Unsupported Cavium Networks CPU type");
2288c2ecf20Sopenharmony_ci		break;
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	/* compute a couple of other cache variables */
2328c2ecf20Sopenharmony_ci	c->icache.waysize = icache_size / c->icache.ways;
2338c2ecf20Sopenharmony_ci	c->dcache.waysize = dcache_size / c->dcache.ways;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	c->icache.sets = icache_size / (c->icache.linesz * c->icache.ways);
2368c2ecf20Sopenharmony_ci	c->dcache.sets = dcache_size / (c->dcache.linesz * c->dcache.ways);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	if (smp_processor_id() == 0) {
2398c2ecf20Sopenharmony_ci		pr_info("Primary instruction cache %ldkB, %s, %d way, "
2408c2ecf20Sopenharmony_ci			"%d sets, linesize %d bytes.\n",
2418c2ecf20Sopenharmony_ci			icache_size >> 10,
2428c2ecf20Sopenharmony_ci			cpu_has_vtag_icache ?
2438c2ecf20Sopenharmony_ci				"virtually tagged" : "physically tagged",
2448c2ecf20Sopenharmony_ci			c->icache.ways, c->icache.sets, c->icache.linesz);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci		pr_info("Primary data cache %ldkB, %d-way, %d sets, "
2478c2ecf20Sopenharmony_ci			"linesize %d bytes.\n",
2488c2ecf20Sopenharmony_ci			dcache_size >> 10, c->dcache.ways,
2498c2ecf20Sopenharmony_ci			c->dcache.sets, c->dcache.linesz);
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic void  octeon_cache_error_setup(void)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	extern char except_vec2_octeon;
2568c2ecf20Sopenharmony_ci	set_handler(0x100, &except_vec2_octeon, 0x80);
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci/**
2608c2ecf20Sopenharmony_ci * Setup the Octeon cache flush routines
2618c2ecf20Sopenharmony_ci *
2628c2ecf20Sopenharmony_ci */
2638c2ecf20Sopenharmony_civoid octeon_cache_init(void)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	probe_octeon();
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	shm_align_mask = PAGE_SIZE - 1;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	flush_cache_all			= octeon_flush_icache_all;
2708c2ecf20Sopenharmony_ci	__flush_cache_all		= octeon_flush_icache_all;
2718c2ecf20Sopenharmony_ci	flush_cache_mm			= octeon_flush_cache_mm;
2728c2ecf20Sopenharmony_ci	flush_cache_page		= octeon_flush_cache_page;
2738c2ecf20Sopenharmony_ci	flush_cache_range		= octeon_flush_cache_range;
2748c2ecf20Sopenharmony_ci	flush_icache_all		= octeon_flush_icache_all;
2758c2ecf20Sopenharmony_ci	flush_data_cache_page		= octeon_flush_data_cache_page;
2768c2ecf20Sopenharmony_ci	flush_icache_range		= octeon_flush_icache_range;
2778c2ecf20Sopenharmony_ci	local_flush_icache_range	= local_octeon_flush_icache_range;
2788c2ecf20Sopenharmony_ci	__flush_icache_user_range	= octeon_flush_icache_range;
2798c2ecf20Sopenharmony_ci	__local_flush_icache_user_range	= local_octeon_flush_icache_range;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	__flush_kernel_vmap_range	= octeon_flush_kernel_vmap_range;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	build_clear_page();
2848c2ecf20Sopenharmony_ci	build_copy_page();
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	board_cache_error_setup = octeon_cache_error_setup;
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci/*
2908c2ecf20Sopenharmony_ci * Handle a cache error exception
2918c2ecf20Sopenharmony_ci */
2928c2ecf20Sopenharmony_cistatic RAW_NOTIFIER_HEAD(co_cache_error_chain);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ciint register_co_cache_error_notifier(struct notifier_block *nb)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	return raw_notifier_chain_register(&co_cache_error_chain, nb);
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(register_co_cache_error_notifier);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ciint unregister_co_cache_error_notifier(struct notifier_block *nb)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	return raw_notifier_chain_unregister(&co_cache_error_chain, nb);
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(unregister_co_cache_error_notifier);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic void co_cache_error_call_notifiers(unsigned long val)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	int rv = raw_notifier_call_chain(&co_cache_error_chain, val, NULL);
3098c2ecf20Sopenharmony_ci	if ((rv & ~NOTIFY_STOP_MASK) != NOTIFY_OK) {
3108c2ecf20Sopenharmony_ci		u64 dcache_err;
3118c2ecf20Sopenharmony_ci		unsigned long coreid = cvmx_get_core_num();
3128c2ecf20Sopenharmony_ci		u64 icache_err = read_octeon_c0_icacheerr();
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci		if (val) {
3158c2ecf20Sopenharmony_ci			dcache_err = cache_err_dcache[coreid];
3168c2ecf20Sopenharmony_ci			cache_err_dcache[coreid] = 0;
3178c2ecf20Sopenharmony_ci		} else {
3188c2ecf20Sopenharmony_ci			dcache_err = read_octeon_c0_dcacheerr();
3198c2ecf20Sopenharmony_ci		}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci		pr_err("Core%lu: Cache error exception:\n", coreid);
3228c2ecf20Sopenharmony_ci		pr_err("cp0_errorepc == %lx\n", read_c0_errorepc());
3238c2ecf20Sopenharmony_ci		if (icache_err & 1) {
3248c2ecf20Sopenharmony_ci			pr_err("CacheErr (Icache) == %llx\n",
3258c2ecf20Sopenharmony_ci			       (unsigned long long)icache_err);
3268c2ecf20Sopenharmony_ci			write_octeon_c0_icacheerr(0);
3278c2ecf20Sopenharmony_ci		}
3288c2ecf20Sopenharmony_ci		if (dcache_err & 1) {
3298c2ecf20Sopenharmony_ci			pr_err("CacheErr (Dcache) == %llx\n",
3308c2ecf20Sopenharmony_ci			       (unsigned long long)dcache_err);
3318c2ecf20Sopenharmony_ci		}
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci/*
3368c2ecf20Sopenharmony_ci * Called when the the exception is recoverable
3378c2ecf20Sopenharmony_ci */
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ciasmlinkage void cache_parity_error_octeon_recoverable(void)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	co_cache_error_call_notifiers(0);
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci/**
3458c2ecf20Sopenharmony_ci * Called when the the exception is not recoverable
3468c2ecf20Sopenharmony_ci */
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ciasmlinkage void cache_parity_error_octeon_non_recoverable(void)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	co_cache_error_call_notifiers(1);
3518c2ecf20Sopenharmony_ci	panic("Can't handle cache error: nested exception");
3528c2ecf20Sopenharmony_ci}
353