162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 362306a36Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 462306a36Sopenharmony_ci * for more details. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 1996 David S. Miller (davem@davemloft.net) 762306a36Sopenharmony_ci * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Ralf Baechle (ralf@gnu.org) 862306a36Sopenharmony_ci * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/cpu_pm.h> 1162306a36Sopenharmony_ci#include <linux/hardirq.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/highmem.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/linkage.h> 1662306a36Sopenharmony_ci#include <linux/preempt.h> 1762306a36Sopenharmony_ci#include <linux/sched.h> 1862306a36Sopenharmony_ci#include <linux/smp.h> 1962306a36Sopenharmony_ci#include <linux/mm.h> 2062306a36Sopenharmony_ci#include <linux/export.h> 2162306a36Sopenharmony_ci#include <linux/bitops.h> 2262306a36Sopenharmony_ci#include <linux/dma-map-ops.h> /* for dma_default_coherent */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <asm/bcache.h> 2562306a36Sopenharmony_ci#include <asm/bootinfo.h> 2662306a36Sopenharmony_ci#include <asm/cache.h> 2762306a36Sopenharmony_ci#include <asm/cacheops.h> 2862306a36Sopenharmony_ci#include <asm/cpu.h> 2962306a36Sopenharmony_ci#include <asm/cpu-features.h> 3062306a36Sopenharmony_ci#include <asm/cpu-type.h> 3162306a36Sopenharmony_ci#include <asm/io.h> 3262306a36Sopenharmony_ci#include <asm/page.h> 3362306a36Sopenharmony_ci#include <asm/r4kcache.h> 3462306a36Sopenharmony_ci#include <asm/sections.h> 3562306a36Sopenharmony_ci#include <asm/mmu_context.h> 3662306a36Sopenharmony_ci#include <asm/cacheflush.h> /* for run_uncached() */ 3762306a36Sopenharmony_ci#include <asm/traps.h> 3862306a36Sopenharmony_ci#include <asm/mips-cps.h> 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* 4162306a36Sopenharmony_ci * Bits describing what cache ops an SMP callback function may perform. 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * R4K_HIT - Virtual user or kernel address based cache operations. The 4462306a36Sopenharmony_ci * active_mm must be checked before using user addresses, falling 4562306a36Sopenharmony_ci * back to kmap. 4662306a36Sopenharmony_ci * R4K_INDEX - Index based cache operations. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define R4K_HIT BIT(0) 5062306a36Sopenharmony_ci#define R4K_INDEX BIT(1) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/** 5362306a36Sopenharmony_ci * r4k_op_needs_ipi() - Decide if a cache op needs to be done on every core. 5462306a36Sopenharmony_ci * @type: Type of cache operations (R4K_HIT or R4K_INDEX). 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * Decides whether a cache op needs to be performed on every core in the system. 5762306a36Sopenharmony_ci * This may change depending on the @type of cache operation, as well as the set 5862306a36Sopenharmony_ci * of online CPUs, so preemption should be disabled by the caller to prevent CPU 5962306a36Sopenharmony_ci * hotplug from changing the result. 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * Returns: 1 if the cache operation @type should be done on every core in 6262306a36Sopenharmony_ci * the system. 6362306a36Sopenharmony_ci * 0 if the cache operation @type is globalized and only needs to 6462306a36Sopenharmony_ci * be performed on a simple CPU. 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_cistatic inline bool r4k_op_needs_ipi(unsigned int type) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci /* The MIPS Coherence Manager (CM) globalizes address-based cache ops */ 6962306a36Sopenharmony_ci if (type == R4K_HIT && mips_cm_present()) 7062306a36Sopenharmony_ci return false; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci /* 7362306a36Sopenharmony_ci * Hardware doesn't globalize the required cache ops, so SMP calls may 7462306a36Sopenharmony_ci * be needed, but only if there are foreign CPUs (non-siblings with 7562306a36Sopenharmony_ci * separate caches). 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ci /* cpu_foreign_map[] undeclared when !CONFIG_SMP */ 7862306a36Sopenharmony_ci#ifdef CONFIG_SMP 7962306a36Sopenharmony_ci return !cpumask_empty(&cpu_foreign_map[0]); 8062306a36Sopenharmony_ci#else 8162306a36Sopenharmony_ci return false; 8262306a36Sopenharmony_ci#endif 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* 8662306a36Sopenharmony_ci * Special Variant of smp_call_function for use by cache functions: 8762306a36Sopenharmony_ci * 8862306a36Sopenharmony_ci * o No return value 8962306a36Sopenharmony_ci * o collapses to normal function call on UP kernels 9062306a36Sopenharmony_ci * o collapses to normal function call on systems with a single shared 9162306a36Sopenharmony_ci * primary cache. 9262306a36Sopenharmony_ci * o doesn't disable interrupts on the local CPU 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_cistatic inline void r4k_on_each_cpu(unsigned int type, 9562306a36Sopenharmony_ci void (*func)(void *info), void *info) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci preempt_disable(); 9862306a36Sopenharmony_ci if (r4k_op_needs_ipi(type)) 9962306a36Sopenharmony_ci smp_call_function_many(&cpu_foreign_map[smp_processor_id()], 10062306a36Sopenharmony_ci func, info, 1); 10162306a36Sopenharmony_ci func(info); 10262306a36Sopenharmony_ci preempt_enable(); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* 10662306a36Sopenharmony_ci * Must die. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_cistatic unsigned long icache_size __read_mostly; 10962306a36Sopenharmony_cistatic unsigned long dcache_size __read_mostly; 11062306a36Sopenharmony_cistatic unsigned long vcache_size __read_mostly; 11162306a36Sopenharmony_cistatic unsigned long scache_size __read_mostly; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci#define cpu_is_r4600_v1_x() ((read_c0_prid() & 0xfffffff0) == 0x00002010) 11462306a36Sopenharmony_ci#define cpu_is_r4600_v2_x() ((read_c0_prid() & 0xfffffff0) == 0x00002020) 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci#define R4600_HIT_CACHEOP_WAR_IMPL \ 11762306a36Sopenharmony_cido { \ 11862306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_WAR_R4600_V2_HIT_CACHEOP) && \ 11962306a36Sopenharmony_ci cpu_is_r4600_v2_x()) \ 12062306a36Sopenharmony_ci *(volatile unsigned long *)CKSEG1; \ 12162306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_WAR_R4600_V1_HIT_CACHEOP)) \ 12262306a36Sopenharmony_ci __asm__ __volatile__("nop;nop;nop;nop"); \ 12362306a36Sopenharmony_ci} while (0) 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic void (*r4k_blast_dcache_page)(unsigned long addr); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic inline void r4k_blast_dcache_page_dc32(unsigned long addr) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci R4600_HIT_CACHEOP_WAR_IMPL; 13062306a36Sopenharmony_ci blast_dcache32_page(addr); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic inline void r4k_blast_dcache_page_dc64(unsigned long addr) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci blast_dcache64_page(addr); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic inline void r4k_blast_dcache_page_dc128(unsigned long addr) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci blast_dcache128_page(addr); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic void r4k_blast_dcache_page_setup(void) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci unsigned long dc_lsize = cpu_dcache_line_size(); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci switch (dc_lsize) { 14862306a36Sopenharmony_ci case 0: 14962306a36Sopenharmony_ci r4k_blast_dcache_page = (void *)cache_noop; 15062306a36Sopenharmony_ci break; 15162306a36Sopenharmony_ci case 16: 15262306a36Sopenharmony_ci r4k_blast_dcache_page = blast_dcache16_page; 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci case 32: 15562306a36Sopenharmony_ci r4k_blast_dcache_page = r4k_blast_dcache_page_dc32; 15662306a36Sopenharmony_ci break; 15762306a36Sopenharmony_ci case 64: 15862306a36Sopenharmony_ci r4k_blast_dcache_page = r4k_blast_dcache_page_dc64; 15962306a36Sopenharmony_ci break; 16062306a36Sopenharmony_ci case 128: 16162306a36Sopenharmony_ci r4k_blast_dcache_page = r4k_blast_dcache_page_dc128; 16262306a36Sopenharmony_ci break; 16362306a36Sopenharmony_ci default: 16462306a36Sopenharmony_ci break; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci#ifndef CONFIG_EVA 16962306a36Sopenharmony_ci#define r4k_blast_dcache_user_page r4k_blast_dcache_page 17062306a36Sopenharmony_ci#else 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic void (*r4k_blast_dcache_user_page)(unsigned long addr); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic void r4k_blast_dcache_user_page_setup(void) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci unsigned long dc_lsize = cpu_dcache_line_size(); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (dc_lsize == 0) 17962306a36Sopenharmony_ci r4k_blast_dcache_user_page = (void *)cache_noop; 18062306a36Sopenharmony_ci else if (dc_lsize == 16) 18162306a36Sopenharmony_ci r4k_blast_dcache_user_page = blast_dcache16_user_page; 18262306a36Sopenharmony_ci else if (dc_lsize == 32) 18362306a36Sopenharmony_ci r4k_blast_dcache_user_page = blast_dcache32_user_page; 18462306a36Sopenharmony_ci else if (dc_lsize == 64) 18562306a36Sopenharmony_ci r4k_blast_dcache_user_page = blast_dcache64_user_page; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci#endif 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_civoid (* r4k_blast_dcache)(void); 19162306a36Sopenharmony_ciEXPORT_SYMBOL(r4k_blast_dcache); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic void r4k_blast_dcache_setup(void) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci unsigned long dc_lsize = cpu_dcache_line_size(); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (dc_lsize == 0) 19862306a36Sopenharmony_ci r4k_blast_dcache = (void *)cache_noop; 19962306a36Sopenharmony_ci else if (dc_lsize == 16) 20062306a36Sopenharmony_ci r4k_blast_dcache = blast_dcache16; 20162306a36Sopenharmony_ci else if (dc_lsize == 32) 20262306a36Sopenharmony_ci r4k_blast_dcache = blast_dcache32; 20362306a36Sopenharmony_ci else if (dc_lsize == 64) 20462306a36Sopenharmony_ci r4k_blast_dcache = blast_dcache64; 20562306a36Sopenharmony_ci else if (dc_lsize == 128) 20662306a36Sopenharmony_ci r4k_blast_dcache = blast_dcache128; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci/* force code alignment (used for CONFIG_WAR_TX49XX_ICACHE_INDEX_INV) */ 21062306a36Sopenharmony_ci#define JUMP_TO_ALIGN(order) \ 21162306a36Sopenharmony_ci __asm__ __volatile__( \ 21262306a36Sopenharmony_ci "b\t1f\n\t" \ 21362306a36Sopenharmony_ci ".align\t" #order "\n\t" \ 21462306a36Sopenharmony_ci "1:\n\t" \ 21562306a36Sopenharmony_ci ) 21662306a36Sopenharmony_ci#define CACHE32_UNROLL32_ALIGN JUMP_TO_ALIGN(10) /* 32 * 32 = 1024 */ 21762306a36Sopenharmony_ci#define CACHE32_UNROLL32_ALIGN2 JUMP_TO_ALIGN(11) 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic inline void blast_r4600_v1_icache32(void) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci unsigned long flags; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci local_irq_save(flags); 22462306a36Sopenharmony_ci blast_icache32(); 22562306a36Sopenharmony_ci local_irq_restore(flags); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic inline void tx49_blast_icache32(void) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci unsigned long start = INDEX_BASE; 23162306a36Sopenharmony_ci unsigned long end = start + current_cpu_data.icache.waysize; 23262306a36Sopenharmony_ci unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit; 23362306a36Sopenharmony_ci unsigned long ws_end = current_cpu_data.icache.ways << 23462306a36Sopenharmony_ci current_cpu_data.icache.waybit; 23562306a36Sopenharmony_ci unsigned long ws, addr; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci CACHE32_UNROLL32_ALIGN2; 23862306a36Sopenharmony_ci /* I'm in even chunk. blast odd chunks */ 23962306a36Sopenharmony_ci for (ws = 0; ws < ws_end; ws += ws_inc) 24062306a36Sopenharmony_ci for (addr = start + 0x400; addr < end; addr += 0x400 * 2) 24162306a36Sopenharmony_ci cache_unroll(32, kernel_cache, Index_Invalidate_I, 24262306a36Sopenharmony_ci addr | ws, 32); 24362306a36Sopenharmony_ci CACHE32_UNROLL32_ALIGN; 24462306a36Sopenharmony_ci /* I'm in odd chunk. blast even chunks */ 24562306a36Sopenharmony_ci for (ws = 0; ws < ws_end; ws += ws_inc) 24662306a36Sopenharmony_ci for (addr = start; addr < end; addr += 0x400 * 2) 24762306a36Sopenharmony_ci cache_unroll(32, kernel_cache, Index_Invalidate_I, 24862306a36Sopenharmony_ci addr | ws, 32); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic void (* r4k_blast_icache_page)(unsigned long addr); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic void r4k_blast_icache_page_setup(void) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci unsigned long ic_lsize = cpu_icache_line_size(); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (ic_lsize == 0) 25862306a36Sopenharmony_ci r4k_blast_icache_page = (void *)cache_noop; 25962306a36Sopenharmony_ci else if (ic_lsize == 16) 26062306a36Sopenharmony_ci r4k_blast_icache_page = blast_icache16_page; 26162306a36Sopenharmony_ci else if (ic_lsize == 32 && current_cpu_type() == CPU_LOONGSON2EF) 26262306a36Sopenharmony_ci r4k_blast_icache_page = loongson2_blast_icache32_page; 26362306a36Sopenharmony_ci else if (ic_lsize == 32) 26462306a36Sopenharmony_ci r4k_blast_icache_page = blast_icache32_page; 26562306a36Sopenharmony_ci else if (ic_lsize == 64) 26662306a36Sopenharmony_ci r4k_blast_icache_page = blast_icache64_page; 26762306a36Sopenharmony_ci else if (ic_lsize == 128) 26862306a36Sopenharmony_ci r4k_blast_icache_page = blast_icache128_page; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci#ifndef CONFIG_EVA 27262306a36Sopenharmony_ci#define r4k_blast_icache_user_page r4k_blast_icache_page 27362306a36Sopenharmony_ci#else 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic void (*r4k_blast_icache_user_page)(unsigned long addr); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic void r4k_blast_icache_user_page_setup(void) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci unsigned long ic_lsize = cpu_icache_line_size(); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (ic_lsize == 0) 28262306a36Sopenharmony_ci r4k_blast_icache_user_page = (void *)cache_noop; 28362306a36Sopenharmony_ci else if (ic_lsize == 16) 28462306a36Sopenharmony_ci r4k_blast_icache_user_page = blast_icache16_user_page; 28562306a36Sopenharmony_ci else if (ic_lsize == 32) 28662306a36Sopenharmony_ci r4k_blast_icache_user_page = blast_icache32_user_page; 28762306a36Sopenharmony_ci else if (ic_lsize == 64) 28862306a36Sopenharmony_ci r4k_blast_icache_user_page = blast_icache64_user_page; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci#endif 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_civoid (* r4k_blast_icache)(void); 29462306a36Sopenharmony_ciEXPORT_SYMBOL(r4k_blast_icache); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic void r4k_blast_icache_setup(void) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci unsigned long ic_lsize = cpu_icache_line_size(); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (ic_lsize == 0) 30162306a36Sopenharmony_ci r4k_blast_icache = (void *)cache_noop; 30262306a36Sopenharmony_ci else if (ic_lsize == 16) 30362306a36Sopenharmony_ci r4k_blast_icache = blast_icache16; 30462306a36Sopenharmony_ci else if (ic_lsize == 32) { 30562306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_WAR_R4600_V1_INDEX_ICACHEOP) && 30662306a36Sopenharmony_ci cpu_is_r4600_v1_x()) 30762306a36Sopenharmony_ci r4k_blast_icache = blast_r4600_v1_icache32; 30862306a36Sopenharmony_ci else if (IS_ENABLED(CONFIG_WAR_TX49XX_ICACHE_INDEX_INV)) 30962306a36Sopenharmony_ci r4k_blast_icache = tx49_blast_icache32; 31062306a36Sopenharmony_ci else if (current_cpu_type() == CPU_LOONGSON2EF) 31162306a36Sopenharmony_ci r4k_blast_icache = loongson2_blast_icache32; 31262306a36Sopenharmony_ci else 31362306a36Sopenharmony_ci r4k_blast_icache = blast_icache32; 31462306a36Sopenharmony_ci } else if (ic_lsize == 64) 31562306a36Sopenharmony_ci r4k_blast_icache = blast_icache64; 31662306a36Sopenharmony_ci else if (ic_lsize == 128) 31762306a36Sopenharmony_ci r4k_blast_icache = blast_icache128; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic void (* r4k_blast_scache_page)(unsigned long addr); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic void r4k_blast_scache_page_setup(void) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci unsigned long sc_lsize = cpu_scache_line_size(); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (scache_size == 0) 32762306a36Sopenharmony_ci r4k_blast_scache_page = (void *)cache_noop; 32862306a36Sopenharmony_ci else if (sc_lsize == 16) 32962306a36Sopenharmony_ci r4k_blast_scache_page = blast_scache16_page; 33062306a36Sopenharmony_ci else if (sc_lsize == 32) 33162306a36Sopenharmony_ci r4k_blast_scache_page = blast_scache32_page; 33262306a36Sopenharmony_ci else if (sc_lsize == 64) 33362306a36Sopenharmony_ci r4k_blast_scache_page = blast_scache64_page; 33462306a36Sopenharmony_ci else if (sc_lsize == 128) 33562306a36Sopenharmony_ci r4k_blast_scache_page = blast_scache128_page; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic void (* r4k_blast_scache)(void); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic void r4k_blast_scache_setup(void) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci unsigned long sc_lsize = cpu_scache_line_size(); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (scache_size == 0) 34562306a36Sopenharmony_ci r4k_blast_scache = (void *)cache_noop; 34662306a36Sopenharmony_ci else if (sc_lsize == 16) 34762306a36Sopenharmony_ci r4k_blast_scache = blast_scache16; 34862306a36Sopenharmony_ci else if (sc_lsize == 32) 34962306a36Sopenharmony_ci r4k_blast_scache = blast_scache32; 35062306a36Sopenharmony_ci else if (sc_lsize == 64) 35162306a36Sopenharmony_ci r4k_blast_scache = blast_scache64; 35262306a36Sopenharmony_ci else if (sc_lsize == 128) 35362306a36Sopenharmony_ci r4k_blast_scache = blast_scache128; 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic void (*r4k_blast_scache_node)(long node); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic void r4k_blast_scache_node_setup(void) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci unsigned long sc_lsize = cpu_scache_line_size(); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (current_cpu_type() != CPU_LOONGSON64) 36362306a36Sopenharmony_ci r4k_blast_scache_node = (void *)cache_noop; 36462306a36Sopenharmony_ci else if (sc_lsize == 16) 36562306a36Sopenharmony_ci r4k_blast_scache_node = blast_scache16_node; 36662306a36Sopenharmony_ci else if (sc_lsize == 32) 36762306a36Sopenharmony_ci r4k_blast_scache_node = blast_scache32_node; 36862306a36Sopenharmony_ci else if (sc_lsize == 64) 36962306a36Sopenharmony_ci r4k_blast_scache_node = blast_scache64_node; 37062306a36Sopenharmony_ci else if (sc_lsize == 128) 37162306a36Sopenharmony_ci r4k_blast_scache_node = blast_scache128_node; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic inline void local_r4k___flush_cache_all(void * args) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci switch (current_cpu_type()) { 37762306a36Sopenharmony_ci case CPU_LOONGSON2EF: 37862306a36Sopenharmony_ci case CPU_R4000SC: 37962306a36Sopenharmony_ci case CPU_R4000MC: 38062306a36Sopenharmony_ci case CPU_R4400SC: 38162306a36Sopenharmony_ci case CPU_R4400MC: 38262306a36Sopenharmony_ci case CPU_R10000: 38362306a36Sopenharmony_ci case CPU_R12000: 38462306a36Sopenharmony_ci case CPU_R14000: 38562306a36Sopenharmony_ci case CPU_R16000: 38662306a36Sopenharmony_ci /* 38762306a36Sopenharmony_ci * These caches are inclusive caches, that is, if something 38862306a36Sopenharmony_ci * is not cached in the S-cache, we know it also won't be 38962306a36Sopenharmony_ci * in one of the primary caches. 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_ci r4k_blast_scache(); 39262306a36Sopenharmony_ci break; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci case CPU_LOONGSON64: 39562306a36Sopenharmony_ci /* Use get_ebase_cpunum() for both NUMA=y/n */ 39662306a36Sopenharmony_ci r4k_blast_scache_node(get_ebase_cpunum() >> 2); 39762306a36Sopenharmony_ci break; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci case CPU_BMIPS5000: 40062306a36Sopenharmony_ci r4k_blast_scache(); 40162306a36Sopenharmony_ci __sync(); 40262306a36Sopenharmony_ci break; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci default: 40562306a36Sopenharmony_ci r4k_blast_dcache(); 40662306a36Sopenharmony_ci r4k_blast_icache(); 40762306a36Sopenharmony_ci break; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic void r4k___flush_cache_all(void) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci r4k_on_each_cpu(R4K_INDEX, local_r4k___flush_cache_all, NULL); 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci/** 41762306a36Sopenharmony_ci * has_valid_asid() - Determine if an mm already has an ASID. 41862306a36Sopenharmony_ci * @mm: Memory map. 41962306a36Sopenharmony_ci * @type: R4K_HIT or R4K_INDEX, type of cache op. 42062306a36Sopenharmony_ci * 42162306a36Sopenharmony_ci * Determines whether @mm already has an ASID on any of the CPUs which cache ops 42262306a36Sopenharmony_ci * of type @type within an r4k_on_each_cpu() call will affect. If 42362306a36Sopenharmony_ci * r4k_on_each_cpu() does an SMP call to a single VPE in each core, then the 42462306a36Sopenharmony_ci * scope of the operation is confined to sibling CPUs, otherwise all online CPUs 42562306a36Sopenharmony_ci * will need to be checked. 42662306a36Sopenharmony_ci * 42762306a36Sopenharmony_ci * Must be called in non-preemptive context. 42862306a36Sopenharmony_ci * 42962306a36Sopenharmony_ci * Returns: 1 if the CPUs affected by @type cache ops have an ASID for @mm. 43062306a36Sopenharmony_ci * 0 otherwise. 43162306a36Sopenharmony_ci */ 43262306a36Sopenharmony_cistatic inline int has_valid_asid(const struct mm_struct *mm, unsigned int type) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci unsigned int i; 43562306a36Sopenharmony_ci const cpumask_t *mask = cpu_present_mask; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (cpu_has_mmid) 43862306a36Sopenharmony_ci return cpu_context(0, mm) != 0; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci /* cpu_sibling_map[] undeclared when !CONFIG_SMP */ 44162306a36Sopenharmony_ci#ifdef CONFIG_SMP 44262306a36Sopenharmony_ci /* 44362306a36Sopenharmony_ci * If r4k_on_each_cpu does SMP calls, it does them to a single VPE in 44462306a36Sopenharmony_ci * each foreign core, so we only need to worry about siblings. 44562306a36Sopenharmony_ci * Otherwise we need to worry about all present CPUs. 44662306a36Sopenharmony_ci */ 44762306a36Sopenharmony_ci if (r4k_op_needs_ipi(type)) 44862306a36Sopenharmony_ci mask = &cpu_sibling_map[smp_processor_id()]; 44962306a36Sopenharmony_ci#endif 45062306a36Sopenharmony_ci for_each_cpu(i, mask) 45162306a36Sopenharmony_ci if (cpu_context(i, mm)) 45262306a36Sopenharmony_ci return 1; 45362306a36Sopenharmony_ci return 0; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic void r4k__flush_cache_vmap(void) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci r4k_blast_dcache(); 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic void r4k__flush_cache_vunmap(void) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci r4k_blast_dcache(); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci/* 46762306a36Sopenharmony_ci * Note: flush_tlb_range() assumes flush_cache_range() sufficiently flushes 46862306a36Sopenharmony_ci * whole caches when vma is executable. 46962306a36Sopenharmony_ci */ 47062306a36Sopenharmony_cistatic inline void local_r4k_flush_cache_range(void * args) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci struct vm_area_struct *vma = args; 47362306a36Sopenharmony_ci int exec = vma->vm_flags & VM_EXEC; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (!has_valid_asid(vma->vm_mm, R4K_INDEX)) 47662306a36Sopenharmony_ci return; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* 47962306a36Sopenharmony_ci * If dcache can alias, we must blast it since mapping is changing. 48062306a36Sopenharmony_ci * If executable, we must ensure any dirty lines are written back far 48162306a36Sopenharmony_ci * enough to be visible to icache. 48262306a36Sopenharmony_ci */ 48362306a36Sopenharmony_ci if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) 48462306a36Sopenharmony_ci r4k_blast_dcache(); 48562306a36Sopenharmony_ci /* If executable, blast stale lines from icache */ 48662306a36Sopenharmony_ci if (exec) 48762306a36Sopenharmony_ci r4k_blast_icache(); 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic void r4k_flush_cache_range(struct vm_area_struct *vma, 49162306a36Sopenharmony_ci unsigned long start, unsigned long end) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci int exec = vma->vm_flags & VM_EXEC; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (cpu_has_dc_aliases || exec) 49662306a36Sopenharmony_ci r4k_on_each_cpu(R4K_INDEX, local_r4k_flush_cache_range, vma); 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic inline void local_r4k_flush_cache_mm(void * args) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci struct mm_struct *mm = args; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (!has_valid_asid(mm, R4K_INDEX)) 50462306a36Sopenharmony_ci return; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* 50762306a36Sopenharmony_ci * Kludge alert. For obscure reasons R4000SC and R4400SC go nuts if we 50862306a36Sopenharmony_ci * only flush the primary caches but R1x000 behave sane ... 50962306a36Sopenharmony_ci * R4000SC and R4400SC indexed S-cache ops also invalidate primary 51062306a36Sopenharmony_ci * caches, so we can bail out early. 51162306a36Sopenharmony_ci */ 51262306a36Sopenharmony_ci if (current_cpu_type() == CPU_R4000SC || 51362306a36Sopenharmony_ci current_cpu_type() == CPU_R4000MC || 51462306a36Sopenharmony_ci current_cpu_type() == CPU_R4400SC || 51562306a36Sopenharmony_ci current_cpu_type() == CPU_R4400MC) { 51662306a36Sopenharmony_ci r4k_blast_scache(); 51762306a36Sopenharmony_ci return; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci r4k_blast_dcache(); 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic void r4k_flush_cache_mm(struct mm_struct *mm) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci if (!cpu_has_dc_aliases) 52662306a36Sopenharmony_ci return; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci r4k_on_each_cpu(R4K_INDEX, local_r4k_flush_cache_mm, mm); 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistruct flush_cache_page_args { 53262306a36Sopenharmony_ci struct vm_area_struct *vma; 53362306a36Sopenharmony_ci unsigned long addr; 53462306a36Sopenharmony_ci unsigned long pfn; 53562306a36Sopenharmony_ci}; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic inline void local_r4k_flush_cache_page(void *args) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci struct flush_cache_page_args *fcp_args = args; 54062306a36Sopenharmony_ci struct vm_area_struct *vma = fcp_args->vma; 54162306a36Sopenharmony_ci unsigned long addr = fcp_args->addr; 54262306a36Sopenharmony_ci struct page *page = pfn_to_page(fcp_args->pfn); 54362306a36Sopenharmony_ci int exec = vma->vm_flags & VM_EXEC; 54462306a36Sopenharmony_ci struct mm_struct *mm = vma->vm_mm; 54562306a36Sopenharmony_ci int map_coherent = 0; 54662306a36Sopenharmony_ci pmd_t *pmdp; 54762306a36Sopenharmony_ci pte_t *ptep; 54862306a36Sopenharmony_ci void *vaddr; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci /* 55162306a36Sopenharmony_ci * If owns no valid ASID yet, cannot possibly have gotten 55262306a36Sopenharmony_ci * this page into the cache. 55362306a36Sopenharmony_ci */ 55462306a36Sopenharmony_ci if (!has_valid_asid(mm, R4K_HIT)) 55562306a36Sopenharmony_ci return; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci addr &= PAGE_MASK; 55862306a36Sopenharmony_ci pmdp = pmd_off(mm, addr); 55962306a36Sopenharmony_ci ptep = pte_offset_kernel(pmdp, addr); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* 56262306a36Sopenharmony_ci * If the page isn't marked valid, the page cannot possibly be 56362306a36Sopenharmony_ci * in the cache. 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_ci if (!(pte_present(*ptep))) 56662306a36Sopenharmony_ci return; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) 56962306a36Sopenharmony_ci vaddr = NULL; 57062306a36Sopenharmony_ci else { 57162306a36Sopenharmony_ci struct folio *folio = page_folio(page); 57262306a36Sopenharmony_ci /* 57362306a36Sopenharmony_ci * Use kmap_coherent or kmap_atomic to do flushes for 57462306a36Sopenharmony_ci * another ASID than the current one. 57562306a36Sopenharmony_ci */ 57662306a36Sopenharmony_ci map_coherent = (cpu_has_dc_aliases && 57762306a36Sopenharmony_ci folio_mapped(folio) && 57862306a36Sopenharmony_ci !folio_test_dcache_dirty(folio)); 57962306a36Sopenharmony_ci if (map_coherent) 58062306a36Sopenharmony_ci vaddr = kmap_coherent(page, addr); 58162306a36Sopenharmony_ci else 58262306a36Sopenharmony_ci vaddr = kmap_atomic(page); 58362306a36Sopenharmony_ci addr = (unsigned long)vaddr; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) { 58762306a36Sopenharmony_ci vaddr ? r4k_blast_dcache_page(addr) : 58862306a36Sopenharmony_ci r4k_blast_dcache_user_page(addr); 58962306a36Sopenharmony_ci if (exec && !cpu_icache_snoops_remote_store) 59062306a36Sopenharmony_ci r4k_blast_scache_page(addr); 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci if (exec) { 59362306a36Sopenharmony_ci if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) { 59462306a36Sopenharmony_ci drop_mmu_context(mm); 59562306a36Sopenharmony_ci } else 59662306a36Sopenharmony_ci vaddr ? r4k_blast_icache_page(addr) : 59762306a36Sopenharmony_ci r4k_blast_icache_user_page(addr); 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (vaddr) { 60162306a36Sopenharmony_ci if (map_coherent) 60262306a36Sopenharmony_ci kunmap_coherent(); 60362306a36Sopenharmony_ci else 60462306a36Sopenharmony_ci kunmap_atomic(vaddr); 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic void r4k_flush_cache_page(struct vm_area_struct *vma, 60962306a36Sopenharmony_ci unsigned long addr, unsigned long pfn) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci struct flush_cache_page_args args; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci args.vma = vma; 61462306a36Sopenharmony_ci args.addr = addr; 61562306a36Sopenharmony_ci args.pfn = pfn; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci r4k_on_each_cpu(R4K_HIT, local_r4k_flush_cache_page, &args); 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic inline void local_r4k_flush_data_cache_page(void * addr) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci r4k_blast_dcache_page((unsigned long) addr); 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic void r4k_flush_data_cache_page(unsigned long addr) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci if (in_atomic()) 62862306a36Sopenharmony_ci local_r4k_flush_data_cache_page((void *)addr); 62962306a36Sopenharmony_ci else 63062306a36Sopenharmony_ci r4k_on_each_cpu(R4K_HIT, local_r4k_flush_data_cache_page, 63162306a36Sopenharmony_ci (void *) addr); 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistruct flush_icache_range_args { 63562306a36Sopenharmony_ci unsigned long start; 63662306a36Sopenharmony_ci unsigned long end; 63762306a36Sopenharmony_ci unsigned int type; 63862306a36Sopenharmony_ci bool user; 63962306a36Sopenharmony_ci}; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic inline void __local_r4k_flush_icache_range(unsigned long start, 64262306a36Sopenharmony_ci unsigned long end, 64362306a36Sopenharmony_ci unsigned int type, 64462306a36Sopenharmony_ci bool user) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci if (!cpu_has_ic_fills_f_dc) { 64762306a36Sopenharmony_ci if (type == R4K_INDEX || 64862306a36Sopenharmony_ci (type & R4K_INDEX && end - start >= dcache_size)) { 64962306a36Sopenharmony_ci r4k_blast_dcache(); 65062306a36Sopenharmony_ci } else { 65162306a36Sopenharmony_ci R4600_HIT_CACHEOP_WAR_IMPL; 65262306a36Sopenharmony_ci if (user) 65362306a36Sopenharmony_ci protected_blast_dcache_range(start, end); 65462306a36Sopenharmony_ci else 65562306a36Sopenharmony_ci blast_dcache_range(start, end); 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if (type == R4K_INDEX || 66062306a36Sopenharmony_ci (type & R4K_INDEX && end - start > icache_size)) 66162306a36Sopenharmony_ci r4k_blast_icache(); 66262306a36Sopenharmony_ci else { 66362306a36Sopenharmony_ci switch (boot_cpu_type()) { 66462306a36Sopenharmony_ci case CPU_LOONGSON2EF: 66562306a36Sopenharmony_ci protected_loongson2_blast_icache_range(start, end); 66662306a36Sopenharmony_ci break; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci default: 66962306a36Sopenharmony_ci if (user) 67062306a36Sopenharmony_ci protected_blast_icache_range(start, end); 67162306a36Sopenharmony_ci else 67262306a36Sopenharmony_ci blast_icache_range(start, end); 67362306a36Sopenharmony_ci break; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic inline void local_r4k_flush_icache_range(unsigned long start, 67962306a36Sopenharmony_ci unsigned long end) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci __local_r4k_flush_icache_range(start, end, R4K_HIT | R4K_INDEX, false); 68262306a36Sopenharmony_ci} 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_cistatic inline void local_r4k_flush_icache_user_range(unsigned long start, 68562306a36Sopenharmony_ci unsigned long end) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci __local_r4k_flush_icache_range(start, end, R4K_HIT | R4K_INDEX, true); 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic inline void local_r4k_flush_icache_range_ipi(void *args) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci struct flush_icache_range_args *fir_args = args; 69362306a36Sopenharmony_ci unsigned long start = fir_args->start; 69462306a36Sopenharmony_ci unsigned long end = fir_args->end; 69562306a36Sopenharmony_ci unsigned int type = fir_args->type; 69662306a36Sopenharmony_ci bool user = fir_args->user; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci __local_r4k_flush_icache_range(start, end, type, user); 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_cistatic void __r4k_flush_icache_range(unsigned long start, unsigned long end, 70262306a36Sopenharmony_ci bool user) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci struct flush_icache_range_args args; 70562306a36Sopenharmony_ci unsigned long size, cache_size; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci args.start = start; 70862306a36Sopenharmony_ci args.end = end; 70962306a36Sopenharmony_ci args.type = R4K_HIT | R4K_INDEX; 71062306a36Sopenharmony_ci args.user = user; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci /* 71362306a36Sopenharmony_ci * Indexed cache ops require an SMP call. 71462306a36Sopenharmony_ci * Consider if that can or should be avoided. 71562306a36Sopenharmony_ci */ 71662306a36Sopenharmony_ci preempt_disable(); 71762306a36Sopenharmony_ci if (r4k_op_needs_ipi(R4K_INDEX) && !r4k_op_needs_ipi(R4K_HIT)) { 71862306a36Sopenharmony_ci /* 71962306a36Sopenharmony_ci * If address-based cache ops don't require an SMP call, then 72062306a36Sopenharmony_ci * use them exclusively for small flushes. 72162306a36Sopenharmony_ci */ 72262306a36Sopenharmony_ci size = end - start; 72362306a36Sopenharmony_ci cache_size = icache_size; 72462306a36Sopenharmony_ci if (!cpu_has_ic_fills_f_dc) { 72562306a36Sopenharmony_ci size *= 2; 72662306a36Sopenharmony_ci cache_size += dcache_size; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci if (size <= cache_size) 72962306a36Sopenharmony_ci args.type &= ~R4K_INDEX; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci r4k_on_each_cpu(args.type, local_r4k_flush_icache_range_ipi, &args); 73262306a36Sopenharmony_ci preempt_enable(); 73362306a36Sopenharmony_ci instruction_hazard(); 73462306a36Sopenharmony_ci} 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_cistatic void r4k_flush_icache_range(unsigned long start, unsigned long end) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci return __r4k_flush_icache_range(start, end, false); 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic void r4k_flush_icache_user_range(unsigned long start, unsigned long end) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci return __r4k_flush_icache_range(start, end, true); 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci#ifdef CONFIG_DMA_NONCOHERENT 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_cistatic void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci /* Catch bad driver code */ 75162306a36Sopenharmony_ci if (WARN_ON(size == 0)) 75262306a36Sopenharmony_ci return; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci preempt_disable(); 75562306a36Sopenharmony_ci if (cpu_has_inclusive_pcaches) { 75662306a36Sopenharmony_ci if (size >= scache_size) { 75762306a36Sopenharmony_ci if (current_cpu_type() != CPU_LOONGSON64) 75862306a36Sopenharmony_ci r4k_blast_scache(); 75962306a36Sopenharmony_ci else 76062306a36Sopenharmony_ci r4k_blast_scache_node(pa_to_nid(addr)); 76162306a36Sopenharmony_ci } else { 76262306a36Sopenharmony_ci blast_scache_range(addr, addr + size); 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci preempt_enable(); 76562306a36Sopenharmony_ci __sync(); 76662306a36Sopenharmony_ci return; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* 77062306a36Sopenharmony_ci * Either no secondary cache or the available caches don't have the 77162306a36Sopenharmony_ci * subset property so we have to flush the primary caches 77262306a36Sopenharmony_ci * explicitly. 77362306a36Sopenharmony_ci * If we would need IPI to perform an INDEX-type operation, then 77462306a36Sopenharmony_ci * we have to use the HIT-type alternative as IPI cannot be used 77562306a36Sopenharmony_ci * here due to interrupts possibly being disabled. 77662306a36Sopenharmony_ci */ 77762306a36Sopenharmony_ci if (!r4k_op_needs_ipi(R4K_INDEX) && size >= dcache_size) { 77862306a36Sopenharmony_ci r4k_blast_dcache(); 77962306a36Sopenharmony_ci } else { 78062306a36Sopenharmony_ci R4600_HIT_CACHEOP_WAR_IMPL; 78162306a36Sopenharmony_ci blast_dcache_range(addr, addr + size); 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci preempt_enable(); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci bc_wback_inv(addr, size); 78662306a36Sopenharmony_ci __sync(); 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic void prefetch_cache_inv(unsigned long addr, unsigned long size) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci unsigned int linesz = cpu_scache_line_size(); 79262306a36Sopenharmony_ci unsigned long addr0 = addr, addr1; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci addr0 &= ~(linesz - 1); 79562306a36Sopenharmony_ci addr1 = (addr0 + size - 1) & ~(linesz - 1); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci protected_writeback_scache_line(addr0); 79862306a36Sopenharmony_ci if (likely(addr1 != addr0)) 79962306a36Sopenharmony_ci protected_writeback_scache_line(addr1); 80062306a36Sopenharmony_ci else 80162306a36Sopenharmony_ci return; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci addr0 += linesz; 80462306a36Sopenharmony_ci if (likely(addr1 != addr0)) 80562306a36Sopenharmony_ci protected_writeback_scache_line(addr0); 80662306a36Sopenharmony_ci else 80762306a36Sopenharmony_ci return; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci addr1 -= linesz; 81062306a36Sopenharmony_ci if (likely(addr1 > addr0)) 81162306a36Sopenharmony_ci protected_writeback_scache_line(addr0); 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic void r4k_dma_cache_inv(unsigned long addr, unsigned long size) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci /* Catch bad driver code */ 81762306a36Sopenharmony_ci if (WARN_ON(size == 0)) 81862306a36Sopenharmony_ci return; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci preempt_disable(); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci if (current_cpu_type() == CPU_BMIPS5000) 82362306a36Sopenharmony_ci prefetch_cache_inv(addr, size); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci if (cpu_has_inclusive_pcaches) { 82662306a36Sopenharmony_ci if (size >= scache_size) { 82762306a36Sopenharmony_ci if (current_cpu_type() != CPU_LOONGSON64) 82862306a36Sopenharmony_ci r4k_blast_scache(); 82962306a36Sopenharmony_ci else 83062306a36Sopenharmony_ci r4k_blast_scache_node(pa_to_nid(addr)); 83162306a36Sopenharmony_ci } else { 83262306a36Sopenharmony_ci /* 83362306a36Sopenharmony_ci * There is no clearly documented alignment requirement 83462306a36Sopenharmony_ci * for the cache instruction on MIPS processors and 83562306a36Sopenharmony_ci * some processors, among them the RM5200 and RM7000 83662306a36Sopenharmony_ci * QED processors will throw an address error for cache 83762306a36Sopenharmony_ci * hit ops with insufficient alignment. Solved by 83862306a36Sopenharmony_ci * aligning the address to cache line size. 83962306a36Sopenharmony_ci */ 84062306a36Sopenharmony_ci blast_inv_scache_range(addr, addr + size); 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci preempt_enable(); 84362306a36Sopenharmony_ci __sync(); 84462306a36Sopenharmony_ci return; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci if (!r4k_op_needs_ipi(R4K_INDEX) && size >= dcache_size) { 84862306a36Sopenharmony_ci r4k_blast_dcache(); 84962306a36Sopenharmony_ci } else { 85062306a36Sopenharmony_ci R4600_HIT_CACHEOP_WAR_IMPL; 85162306a36Sopenharmony_ci blast_inv_dcache_range(addr, addr + size); 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci preempt_enable(); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci bc_inv(addr, size); 85662306a36Sopenharmony_ci __sync(); 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci#endif /* CONFIG_DMA_NONCOHERENT */ 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_cistatic void r4k_flush_icache_all(void) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci if (cpu_has_vtag_icache) 86362306a36Sopenharmony_ci r4k_blast_icache(); 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cistruct flush_kernel_vmap_range_args { 86762306a36Sopenharmony_ci unsigned long vaddr; 86862306a36Sopenharmony_ci int size; 86962306a36Sopenharmony_ci}; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cistatic inline void local_r4k_flush_kernel_vmap_range_index(void *args) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci /* 87462306a36Sopenharmony_ci * Aliases only affect the primary caches so don't bother with 87562306a36Sopenharmony_ci * S-caches or T-caches. 87662306a36Sopenharmony_ci */ 87762306a36Sopenharmony_ci r4k_blast_dcache(); 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cistatic inline void local_r4k_flush_kernel_vmap_range(void *args) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci struct flush_kernel_vmap_range_args *vmra = args; 88362306a36Sopenharmony_ci unsigned long vaddr = vmra->vaddr; 88462306a36Sopenharmony_ci int size = vmra->size; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci /* 88762306a36Sopenharmony_ci * Aliases only affect the primary caches so don't bother with 88862306a36Sopenharmony_ci * S-caches or T-caches. 88962306a36Sopenharmony_ci */ 89062306a36Sopenharmony_ci R4600_HIT_CACHEOP_WAR_IMPL; 89162306a36Sopenharmony_ci blast_dcache_range(vaddr, vaddr + size); 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cistatic void r4k_flush_kernel_vmap_range(unsigned long vaddr, int size) 89562306a36Sopenharmony_ci{ 89662306a36Sopenharmony_ci struct flush_kernel_vmap_range_args args; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci args.vaddr = (unsigned long) vaddr; 89962306a36Sopenharmony_ci args.size = size; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (size >= dcache_size) 90262306a36Sopenharmony_ci r4k_on_each_cpu(R4K_INDEX, 90362306a36Sopenharmony_ci local_r4k_flush_kernel_vmap_range_index, NULL); 90462306a36Sopenharmony_ci else 90562306a36Sopenharmony_ci r4k_on_each_cpu(R4K_HIT, local_r4k_flush_kernel_vmap_range, 90662306a36Sopenharmony_ci &args); 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_cistatic inline void rm7k_erratum31(void) 91062306a36Sopenharmony_ci{ 91162306a36Sopenharmony_ci const unsigned long ic_lsize = 32; 91262306a36Sopenharmony_ci unsigned long addr; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci /* RM7000 erratum #31. The icache is screwed at startup. */ 91562306a36Sopenharmony_ci write_c0_taglo(0); 91662306a36Sopenharmony_ci write_c0_taghi(0); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci for (addr = INDEX_BASE; addr <= INDEX_BASE + 4096; addr += ic_lsize) { 91962306a36Sopenharmony_ci __asm__ __volatile__ ( 92062306a36Sopenharmony_ci ".set push\n\t" 92162306a36Sopenharmony_ci ".set noreorder\n\t" 92262306a36Sopenharmony_ci ".set mips3\n\t" 92362306a36Sopenharmony_ci "cache\t%1, 0(%0)\n\t" 92462306a36Sopenharmony_ci "cache\t%1, 0x1000(%0)\n\t" 92562306a36Sopenharmony_ci "cache\t%1, 0x2000(%0)\n\t" 92662306a36Sopenharmony_ci "cache\t%1, 0x3000(%0)\n\t" 92762306a36Sopenharmony_ci "cache\t%2, 0(%0)\n\t" 92862306a36Sopenharmony_ci "cache\t%2, 0x1000(%0)\n\t" 92962306a36Sopenharmony_ci "cache\t%2, 0x2000(%0)\n\t" 93062306a36Sopenharmony_ci "cache\t%2, 0x3000(%0)\n\t" 93162306a36Sopenharmony_ci "cache\t%1, 0(%0)\n\t" 93262306a36Sopenharmony_ci "cache\t%1, 0x1000(%0)\n\t" 93362306a36Sopenharmony_ci "cache\t%1, 0x2000(%0)\n\t" 93462306a36Sopenharmony_ci "cache\t%1, 0x3000(%0)\n\t" 93562306a36Sopenharmony_ci ".set pop\n" 93662306a36Sopenharmony_ci : 93762306a36Sopenharmony_ci : "r" (addr), "i" (Index_Store_Tag_I), "i" (Fill_I)); 93862306a36Sopenharmony_ci } 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_cistatic inline int alias_74k_erratum(struct cpuinfo_mips *c) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci unsigned int imp = c->processor_id & PRID_IMP_MASK; 94462306a36Sopenharmony_ci unsigned int rev = c->processor_id & PRID_REV_MASK; 94562306a36Sopenharmony_ci int present = 0; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci /* 94862306a36Sopenharmony_ci * Early versions of the 74K do not update the cache tags on a 94962306a36Sopenharmony_ci * vtag miss/ptag hit which can occur in the case of KSEG0/KUSEG 95062306a36Sopenharmony_ci * aliases. In this case it is better to treat the cache as always 95162306a36Sopenharmony_ci * having aliases. Also disable the synonym tag update feature 95262306a36Sopenharmony_ci * where available. In this case no opportunistic tag update will 95362306a36Sopenharmony_ci * happen where a load causes a virtual address miss but a physical 95462306a36Sopenharmony_ci * address hit during a D-cache look-up. 95562306a36Sopenharmony_ci */ 95662306a36Sopenharmony_ci switch (imp) { 95762306a36Sopenharmony_ci case PRID_IMP_74K: 95862306a36Sopenharmony_ci if (rev <= PRID_REV_ENCODE_332(2, 4, 0)) 95962306a36Sopenharmony_ci present = 1; 96062306a36Sopenharmony_ci if (rev == PRID_REV_ENCODE_332(2, 4, 0)) 96162306a36Sopenharmony_ci write_c0_config6(read_c0_config6() | MTI_CONF6_SYND); 96262306a36Sopenharmony_ci break; 96362306a36Sopenharmony_ci case PRID_IMP_1074K: 96462306a36Sopenharmony_ci if (rev <= PRID_REV_ENCODE_332(1, 1, 0)) { 96562306a36Sopenharmony_ci present = 1; 96662306a36Sopenharmony_ci write_c0_config6(read_c0_config6() | MTI_CONF6_SYND); 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci break; 96962306a36Sopenharmony_ci default: 97062306a36Sopenharmony_ci BUG(); 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci return present; 97462306a36Sopenharmony_ci} 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_cistatic void b5k_instruction_hazard(void) 97762306a36Sopenharmony_ci{ 97862306a36Sopenharmony_ci __sync(); 97962306a36Sopenharmony_ci __sync(); 98062306a36Sopenharmony_ci __asm__ __volatile__( 98162306a36Sopenharmony_ci " nop; nop; nop; nop; nop; nop; nop; nop\n" 98262306a36Sopenharmony_ci " nop; nop; nop; nop; nop; nop; nop; nop\n" 98362306a36Sopenharmony_ci " nop; nop; nop; nop; nop; nop; nop; nop\n" 98462306a36Sopenharmony_ci " nop; nop; nop; nop; nop; nop; nop; nop\n" 98562306a36Sopenharmony_ci : : : "memory"); 98662306a36Sopenharmony_ci} 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_cistatic char *way_string[] = { NULL, "direct mapped", "2-way", 98962306a36Sopenharmony_ci "3-way", "4-way", "5-way", "6-way", "7-way", "8-way", 99062306a36Sopenharmony_ci "9-way", "10-way", "11-way", "12-way", 99162306a36Sopenharmony_ci "13-way", "14-way", "15-way", "16-way", 99262306a36Sopenharmony_ci}; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_cistatic void probe_pcache(void) 99562306a36Sopenharmony_ci{ 99662306a36Sopenharmony_ci struct cpuinfo_mips *c = ¤t_cpu_data; 99762306a36Sopenharmony_ci unsigned int config = read_c0_config(); 99862306a36Sopenharmony_ci unsigned int prid = read_c0_prid(); 99962306a36Sopenharmony_ci int has_74k_erratum = 0; 100062306a36Sopenharmony_ci unsigned long config1; 100162306a36Sopenharmony_ci unsigned int lsize; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci switch (current_cpu_type()) { 100462306a36Sopenharmony_ci case CPU_R4600: /* QED style two way caches? */ 100562306a36Sopenharmony_ci case CPU_R4700: 100662306a36Sopenharmony_ci case CPU_R5000: 100762306a36Sopenharmony_ci case CPU_NEVADA: 100862306a36Sopenharmony_ci icache_size = 1 << (12 + ((config & CONF_IC) >> 9)); 100962306a36Sopenharmony_ci c->icache.linesz = 16 << ((config & CONF_IB) >> 5); 101062306a36Sopenharmony_ci c->icache.ways = 2; 101162306a36Sopenharmony_ci c->icache.waybit = __ffs(icache_size/2); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci dcache_size = 1 << (12 + ((config & CONF_DC) >> 6)); 101462306a36Sopenharmony_ci c->dcache.linesz = 16 << ((config & CONF_DB) >> 4); 101562306a36Sopenharmony_ci c->dcache.ways = 2; 101662306a36Sopenharmony_ci c->dcache.waybit= __ffs(dcache_size/2); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci c->options |= MIPS_CPU_CACHE_CDEX_P; 101962306a36Sopenharmony_ci break; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci case CPU_R5500: 102262306a36Sopenharmony_ci icache_size = 1 << (12 + ((config & CONF_IC) >> 9)); 102362306a36Sopenharmony_ci c->icache.linesz = 16 << ((config & CONF_IB) >> 5); 102462306a36Sopenharmony_ci c->icache.ways = 2; 102562306a36Sopenharmony_ci c->icache.waybit= 0; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci dcache_size = 1 << (12 + ((config & CONF_DC) >> 6)); 102862306a36Sopenharmony_ci c->dcache.linesz = 16 << ((config & CONF_DB) >> 4); 102962306a36Sopenharmony_ci c->dcache.ways = 2; 103062306a36Sopenharmony_ci c->dcache.waybit = 0; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci c->options |= MIPS_CPU_CACHE_CDEX_P | MIPS_CPU_PREFETCH; 103362306a36Sopenharmony_ci break; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci case CPU_TX49XX: 103662306a36Sopenharmony_ci icache_size = 1 << (12 + ((config & CONF_IC) >> 9)); 103762306a36Sopenharmony_ci c->icache.linesz = 16 << ((config & CONF_IB) >> 5); 103862306a36Sopenharmony_ci c->icache.ways = 4; 103962306a36Sopenharmony_ci c->icache.waybit= 0; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci dcache_size = 1 << (12 + ((config & CONF_DC) >> 6)); 104262306a36Sopenharmony_ci c->dcache.linesz = 16 << ((config & CONF_DB) >> 4); 104362306a36Sopenharmony_ci c->dcache.ways = 4; 104462306a36Sopenharmony_ci c->dcache.waybit = 0; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci c->options |= MIPS_CPU_CACHE_CDEX_P; 104762306a36Sopenharmony_ci c->options |= MIPS_CPU_PREFETCH; 104862306a36Sopenharmony_ci break; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci case CPU_R4000PC: 105162306a36Sopenharmony_ci case CPU_R4000SC: 105262306a36Sopenharmony_ci case CPU_R4000MC: 105362306a36Sopenharmony_ci case CPU_R4400PC: 105462306a36Sopenharmony_ci case CPU_R4400SC: 105562306a36Sopenharmony_ci case CPU_R4400MC: 105662306a36Sopenharmony_ci case CPU_R4300: 105762306a36Sopenharmony_ci icache_size = 1 << (12 + ((config & CONF_IC) >> 9)); 105862306a36Sopenharmony_ci c->icache.linesz = 16 << ((config & CONF_IB) >> 5); 105962306a36Sopenharmony_ci c->icache.ways = 1; 106062306a36Sopenharmony_ci c->icache.waybit = 0; /* doesn't matter */ 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci dcache_size = 1 << (12 + ((config & CONF_DC) >> 6)); 106362306a36Sopenharmony_ci c->dcache.linesz = 16 << ((config & CONF_DB) >> 4); 106462306a36Sopenharmony_ci c->dcache.ways = 1; 106562306a36Sopenharmony_ci c->dcache.waybit = 0; /* does not matter */ 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci c->options |= MIPS_CPU_CACHE_CDEX_P; 106862306a36Sopenharmony_ci break; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci case CPU_R10000: 107162306a36Sopenharmony_ci case CPU_R12000: 107262306a36Sopenharmony_ci case CPU_R14000: 107362306a36Sopenharmony_ci case CPU_R16000: 107462306a36Sopenharmony_ci icache_size = 1 << (12 + ((config & R10K_CONF_IC) >> 29)); 107562306a36Sopenharmony_ci c->icache.linesz = 64; 107662306a36Sopenharmony_ci c->icache.ways = 2; 107762306a36Sopenharmony_ci c->icache.waybit = 0; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci dcache_size = 1 << (12 + ((config & R10K_CONF_DC) >> 26)); 108062306a36Sopenharmony_ci c->dcache.linesz = 32; 108162306a36Sopenharmony_ci c->dcache.ways = 2; 108262306a36Sopenharmony_ci c->dcache.waybit = 0; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci c->options |= MIPS_CPU_PREFETCH; 108562306a36Sopenharmony_ci break; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci case CPU_RM7000: 108862306a36Sopenharmony_ci rm7k_erratum31(); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci icache_size = 1 << (12 + ((config & CONF_IC) >> 9)); 109162306a36Sopenharmony_ci c->icache.linesz = 16 << ((config & CONF_IB) >> 5); 109262306a36Sopenharmony_ci c->icache.ways = 4; 109362306a36Sopenharmony_ci c->icache.waybit = __ffs(icache_size / c->icache.ways); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci dcache_size = 1 << (12 + ((config & CONF_DC) >> 6)); 109662306a36Sopenharmony_ci c->dcache.linesz = 16 << ((config & CONF_DB) >> 4); 109762306a36Sopenharmony_ci c->dcache.ways = 4; 109862306a36Sopenharmony_ci c->dcache.waybit = __ffs(dcache_size / c->dcache.ways); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci c->options |= MIPS_CPU_CACHE_CDEX_P; 110162306a36Sopenharmony_ci c->options |= MIPS_CPU_PREFETCH; 110262306a36Sopenharmony_ci break; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci case CPU_LOONGSON2EF: 110562306a36Sopenharmony_ci icache_size = 1 << (12 + ((config & CONF_IC) >> 9)); 110662306a36Sopenharmony_ci c->icache.linesz = 16 << ((config & CONF_IB) >> 5); 110762306a36Sopenharmony_ci if (prid & 0x3) 110862306a36Sopenharmony_ci c->icache.ways = 4; 110962306a36Sopenharmony_ci else 111062306a36Sopenharmony_ci c->icache.ways = 2; 111162306a36Sopenharmony_ci c->icache.waybit = 0; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci dcache_size = 1 << (12 + ((config & CONF_DC) >> 6)); 111462306a36Sopenharmony_ci c->dcache.linesz = 16 << ((config & CONF_DB) >> 4); 111562306a36Sopenharmony_ci if (prid & 0x3) 111662306a36Sopenharmony_ci c->dcache.ways = 4; 111762306a36Sopenharmony_ci else 111862306a36Sopenharmony_ci c->dcache.ways = 2; 111962306a36Sopenharmony_ci c->dcache.waybit = 0; 112062306a36Sopenharmony_ci break; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci case CPU_LOONGSON64: 112362306a36Sopenharmony_ci config1 = read_c0_config1(); 112462306a36Sopenharmony_ci lsize = (config1 >> 19) & 7; 112562306a36Sopenharmony_ci if (lsize) 112662306a36Sopenharmony_ci c->icache.linesz = 2 << lsize; 112762306a36Sopenharmony_ci else 112862306a36Sopenharmony_ci c->icache.linesz = 0; 112962306a36Sopenharmony_ci c->icache.sets = 64 << ((config1 >> 22) & 7); 113062306a36Sopenharmony_ci c->icache.ways = 1 + ((config1 >> 16) & 7); 113162306a36Sopenharmony_ci icache_size = c->icache.sets * 113262306a36Sopenharmony_ci c->icache.ways * 113362306a36Sopenharmony_ci c->icache.linesz; 113462306a36Sopenharmony_ci c->icache.waybit = 0; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci lsize = (config1 >> 10) & 7; 113762306a36Sopenharmony_ci if (lsize) 113862306a36Sopenharmony_ci c->dcache.linesz = 2 << lsize; 113962306a36Sopenharmony_ci else 114062306a36Sopenharmony_ci c->dcache.linesz = 0; 114162306a36Sopenharmony_ci c->dcache.sets = 64 << ((config1 >> 13) & 7); 114262306a36Sopenharmony_ci c->dcache.ways = 1 + ((config1 >> 7) & 7); 114362306a36Sopenharmony_ci dcache_size = c->dcache.sets * 114462306a36Sopenharmony_ci c->dcache.ways * 114562306a36Sopenharmony_ci c->dcache.linesz; 114662306a36Sopenharmony_ci c->dcache.waybit = 0; 114762306a36Sopenharmony_ci if ((c->processor_id & (PRID_IMP_MASK | PRID_REV_MASK)) >= 114862306a36Sopenharmony_ci (PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R2_0) || 114962306a36Sopenharmony_ci (c->processor_id & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64R) 115062306a36Sopenharmony_ci c->options |= MIPS_CPU_PREFETCH; 115162306a36Sopenharmony_ci break; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci case CPU_CAVIUM_OCTEON3: 115462306a36Sopenharmony_ci /* For now lie about the number of ways. */ 115562306a36Sopenharmony_ci c->icache.linesz = 128; 115662306a36Sopenharmony_ci c->icache.sets = 16; 115762306a36Sopenharmony_ci c->icache.ways = 8; 115862306a36Sopenharmony_ci c->icache.flags |= MIPS_CACHE_VTAG; 115962306a36Sopenharmony_ci icache_size = c->icache.sets * c->icache.ways * c->icache.linesz; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci c->dcache.linesz = 128; 116262306a36Sopenharmony_ci c->dcache.ways = 8; 116362306a36Sopenharmony_ci c->dcache.sets = 8; 116462306a36Sopenharmony_ci dcache_size = c->dcache.sets * c->dcache.ways * c->dcache.linesz; 116562306a36Sopenharmony_ci c->options |= MIPS_CPU_PREFETCH; 116662306a36Sopenharmony_ci break; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci default: 116962306a36Sopenharmony_ci if (!(config & MIPS_CONF_M)) 117062306a36Sopenharmony_ci panic("Don't know how to probe P-caches on this cpu."); 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci /* 117362306a36Sopenharmony_ci * So we seem to be a MIPS32 or MIPS64 CPU 117462306a36Sopenharmony_ci * So let's probe the I-cache ... 117562306a36Sopenharmony_ci */ 117662306a36Sopenharmony_ci config1 = read_c0_config1(); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci lsize = (config1 >> 19) & 7; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci /* IL == 7 is reserved */ 118162306a36Sopenharmony_ci if (lsize == 7) 118262306a36Sopenharmony_ci panic("Invalid icache line size"); 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci c->icache.linesz = lsize ? 2 << lsize : 0; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci c->icache.sets = 32 << (((config1 >> 22) + 1) & 7); 118762306a36Sopenharmony_ci c->icache.ways = 1 + ((config1 >> 16) & 7); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci icache_size = c->icache.sets * 119062306a36Sopenharmony_ci c->icache.ways * 119162306a36Sopenharmony_ci c->icache.linesz; 119262306a36Sopenharmony_ci c->icache.waybit = __ffs(icache_size/c->icache.ways); 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci if (config & MIPS_CONF_VI) 119562306a36Sopenharmony_ci c->icache.flags |= MIPS_CACHE_VTAG; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci /* 119862306a36Sopenharmony_ci * Now probe the MIPS32 / MIPS64 data cache. 119962306a36Sopenharmony_ci */ 120062306a36Sopenharmony_ci c->dcache.flags = 0; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci lsize = (config1 >> 10) & 7; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci /* DL == 7 is reserved */ 120562306a36Sopenharmony_ci if (lsize == 7) 120662306a36Sopenharmony_ci panic("Invalid dcache line size"); 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci c->dcache.linesz = lsize ? 2 << lsize : 0; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci c->dcache.sets = 32 << (((config1 >> 13) + 1) & 7); 121162306a36Sopenharmony_ci c->dcache.ways = 1 + ((config1 >> 7) & 7); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci dcache_size = c->dcache.sets * 121462306a36Sopenharmony_ci c->dcache.ways * 121562306a36Sopenharmony_ci c->dcache.linesz; 121662306a36Sopenharmony_ci c->dcache.waybit = __ffs(dcache_size/c->dcache.ways); 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci c->options |= MIPS_CPU_PREFETCH; 121962306a36Sopenharmony_ci break; 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci /* 122362306a36Sopenharmony_ci * Processor configuration sanity check for the R4000SC erratum 122462306a36Sopenharmony_ci * #5. With page sizes larger than 32kB there is no possibility 122562306a36Sopenharmony_ci * to get a VCE exception anymore so we don't care about this 122662306a36Sopenharmony_ci * misconfiguration. The case is rather theoretical anyway; 122762306a36Sopenharmony_ci * presumably no vendor is shipping his hardware in the "bad" 122862306a36Sopenharmony_ci * configuration. 122962306a36Sopenharmony_ci */ 123062306a36Sopenharmony_ci if ((prid & PRID_IMP_MASK) == PRID_IMP_R4000 && 123162306a36Sopenharmony_ci (prid & PRID_REV_MASK) < PRID_REV_R4400 && 123262306a36Sopenharmony_ci !(config & CONF_SC) && c->icache.linesz != 16 && 123362306a36Sopenharmony_ci PAGE_SIZE <= 0x8000) 123462306a36Sopenharmony_ci panic("Improper R4000SC processor configuration detected"); 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci /* compute a couple of other cache variables */ 123762306a36Sopenharmony_ci c->icache.waysize = icache_size / c->icache.ways; 123862306a36Sopenharmony_ci c->dcache.waysize = dcache_size / c->dcache.ways; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci c->icache.sets = c->icache.linesz ? 124162306a36Sopenharmony_ci icache_size / (c->icache.linesz * c->icache.ways) : 0; 124262306a36Sopenharmony_ci c->dcache.sets = c->dcache.linesz ? 124362306a36Sopenharmony_ci dcache_size / (c->dcache.linesz * c->dcache.ways) : 0; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci /* 124662306a36Sopenharmony_ci * R1x000 P-caches are odd in a positive way. They're 32kB 2-way 124762306a36Sopenharmony_ci * virtually indexed so normally would suffer from aliases. So 124862306a36Sopenharmony_ci * normally they'd suffer from aliases but magic in the hardware deals 124962306a36Sopenharmony_ci * with that for us so we don't need to take care ourselves. 125062306a36Sopenharmony_ci */ 125162306a36Sopenharmony_ci switch (current_cpu_type()) { 125262306a36Sopenharmony_ci case CPU_20KC: 125362306a36Sopenharmony_ci case CPU_25KF: 125462306a36Sopenharmony_ci case CPU_I6400: 125562306a36Sopenharmony_ci case CPU_I6500: 125662306a36Sopenharmony_ci case CPU_SB1: 125762306a36Sopenharmony_ci case CPU_SB1A: 125862306a36Sopenharmony_ci c->dcache.flags |= MIPS_CACHE_PINDEX; 125962306a36Sopenharmony_ci break; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci case CPU_R10000: 126262306a36Sopenharmony_ci case CPU_R12000: 126362306a36Sopenharmony_ci case CPU_R14000: 126462306a36Sopenharmony_ci case CPU_R16000: 126562306a36Sopenharmony_ci break; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci case CPU_74K: 126862306a36Sopenharmony_ci case CPU_1074K: 126962306a36Sopenharmony_ci has_74k_erratum = alias_74k_erratum(c); 127062306a36Sopenharmony_ci fallthrough; 127162306a36Sopenharmony_ci case CPU_M14KC: 127262306a36Sopenharmony_ci case CPU_M14KEC: 127362306a36Sopenharmony_ci case CPU_24K: 127462306a36Sopenharmony_ci case CPU_34K: 127562306a36Sopenharmony_ci case CPU_1004K: 127662306a36Sopenharmony_ci case CPU_INTERAPTIV: 127762306a36Sopenharmony_ci case CPU_P5600: 127862306a36Sopenharmony_ci case CPU_PROAPTIV: 127962306a36Sopenharmony_ci case CPU_M5150: 128062306a36Sopenharmony_ci case CPU_QEMU_GENERIC: 128162306a36Sopenharmony_ci case CPU_P6600: 128262306a36Sopenharmony_ci case CPU_M6250: 128362306a36Sopenharmony_ci if (!(read_c0_config7() & MIPS_CONF7_IAR) && 128462306a36Sopenharmony_ci (c->icache.waysize > PAGE_SIZE)) 128562306a36Sopenharmony_ci c->icache.flags |= MIPS_CACHE_ALIASES; 128662306a36Sopenharmony_ci if (!has_74k_erratum && (read_c0_config7() & MIPS_CONF7_AR)) { 128762306a36Sopenharmony_ci /* 128862306a36Sopenharmony_ci * Effectively physically indexed dcache, 128962306a36Sopenharmony_ci * thus no virtual aliases. 129062306a36Sopenharmony_ci */ 129162306a36Sopenharmony_ci c->dcache.flags |= MIPS_CACHE_PINDEX; 129262306a36Sopenharmony_ci break; 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci fallthrough; 129562306a36Sopenharmony_ci default: 129662306a36Sopenharmony_ci if (has_74k_erratum || c->dcache.waysize > PAGE_SIZE) 129762306a36Sopenharmony_ci c->dcache.flags |= MIPS_CACHE_ALIASES; 129862306a36Sopenharmony_ci } 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci /* Physically indexed caches don't suffer from virtual aliasing */ 130162306a36Sopenharmony_ci if (c->dcache.flags & MIPS_CACHE_PINDEX) 130262306a36Sopenharmony_ci c->dcache.flags &= ~MIPS_CACHE_ALIASES; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci /* 130562306a36Sopenharmony_ci * In systems with CM the icache fills from L2 or closer caches, and 130662306a36Sopenharmony_ci * thus sees remote stores without needing to write them back any 130762306a36Sopenharmony_ci * further than that. 130862306a36Sopenharmony_ci */ 130962306a36Sopenharmony_ci if (mips_cm_present()) 131062306a36Sopenharmony_ci c->icache.flags |= MIPS_IC_SNOOPS_REMOTE; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci switch (current_cpu_type()) { 131362306a36Sopenharmony_ci case CPU_20KC: 131462306a36Sopenharmony_ci /* 131562306a36Sopenharmony_ci * Some older 20Kc chips doesn't have the 'VI' bit in 131662306a36Sopenharmony_ci * the config register. 131762306a36Sopenharmony_ci */ 131862306a36Sopenharmony_ci c->icache.flags |= MIPS_CACHE_VTAG; 131962306a36Sopenharmony_ci break; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci case CPU_ALCHEMY: 132262306a36Sopenharmony_ci case CPU_I6400: 132362306a36Sopenharmony_ci case CPU_I6500: 132462306a36Sopenharmony_ci c->icache.flags |= MIPS_CACHE_IC_F_DC; 132562306a36Sopenharmony_ci break; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci case CPU_BMIPS5000: 132862306a36Sopenharmony_ci c->icache.flags |= MIPS_CACHE_IC_F_DC; 132962306a36Sopenharmony_ci /* Cache aliases are handled in hardware; allow HIGHMEM */ 133062306a36Sopenharmony_ci c->dcache.flags &= ~MIPS_CACHE_ALIASES; 133162306a36Sopenharmony_ci break; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci case CPU_LOONGSON2EF: 133462306a36Sopenharmony_ci /* 133562306a36Sopenharmony_ci * LOONGSON2 has 4 way icache, but when using indexed cache op, 133662306a36Sopenharmony_ci * one op will act on all 4 ways 133762306a36Sopenharmony_ci */ 133862306a36Sopenharmony_ci c->icache.ways = 1; 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci pr_info("Primary instruction cache %ldkB, %s, %s, linesize %d bytes.\n", 134262306a36Sopenharmony_ci icache_size >> 10, 134362306a36Sopenharmony_ci c->icache.flags & MIPS_CACHE_VTAG ? "VIVT" : "VIPT", 134462306a36Sopenharmony_ci way_string[c->icache.ways], c->icache.linesz); 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci pr_info("Primary data cache %ldkB, %s, %s, %s, linesize %d bytes\n", 134762306a36Sopenharmony_ci dcache_size >> 10, way_string[c->dcache.ways], 134862306a36Sopenharmony_ci (c->dcache.flags & MIPS_CACHE_PINDEX) ? "PIPT" : "VIPT", 134962306a36Sopenharmony_ci (c->dcache.flags & MIPS_CACHE_ALIASES) ? 135062306a36Sopenharmony_ci "cache aliases" : "no aliases", 135162306a36Sopenharmony_ci c->dcache.linesz); 135262306a36Sopenharmony_ci} 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_cistatic void probe_vcache(void) 135562306a36Sopenharmony_ci{ 135662306a36Sopenharmony_ci struct cpuinfo_mips *c = ¤t_cpu_data; 135762306a36Sopenharmony_ci unsigned int config2, lsize; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci if (current_cpu_type() != CPU_LOONGSON64) 136062306a36Sopenharmony_ci return; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci config2 = read_c0_config2(); 136362306a36Sopenharmony_ci if ((lsize = ((config2 >> 20) & 15))) 136462306a36Sopenharmony_ci c->vcache.linesz = 2 << lsize; 136562306a36Sopenharmony_ci else 136662306a36Sopenharmony_ci c->vcache.linesz = lsize; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci c->vcache.sets = 64 << ((config2 >> 24) & 15); 136962306a36Sopenharmony_ci c->vcache.ways = 1 + ((config2 >> 16) & 15); 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci vcache_size = c->vcache.sets * c->vcache.ways * c->vcache.linesz; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci c->vcache.waybit = 0; 137462306a36Sopenharmony_ci c->vcache.waysize = vcache_size / c->vcache.ways; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci pr_info("Unified victim cache %ldkB %s, linesize %d bytes.\n", 137762306a36Sopenharmony_ci vcache_size >> 10, way_string[c->vcache.ways], c->vcache.linesz); 137862306a36Sopenharmony_ci} 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci/* 138162306a36Sopenharmony_ci * If you even _breathe_ on this function, look at the gcc output and make sure 138262306a36Sopenharmony_ci * it does not pop things on and off the stack for the cache sizing loop that 138362306a36Sopenharmony_ci * executes in KSEG1 space or else you will crash and burn badly. You have 138462306a36Sopenharmony_ci * been warned. 138562306a36Sopenharmony_ci */ 138662306a36Sopenharmony_cistatic int probe_scache(void) 138762306a36Sopenharmony_ci{ 138862306a36Sopenharmony_ci unsigned long flags, addr, begin, end, pow2; 138962306a36Sopenharmony_ci unsigned int config = read_c0_config(); 139062306a36Sopenharmony_ci struct cpuinfo_mips *c = ¤t_cpu_data; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci if (config & CONF_SC) 139362306a36Sopenharmony_ci return 0; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci begin = (unsigned long) &_stext; 139662306a36Sopenharmony_ci begin &= ~((4 * 1024 * 1024) - 1); 139762306a36Sopenharmony_ci end = begin + (4 * 1024 * 1024); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci /* 140062306a36Sopenharmony_ci * This is such a bitch, you'd think they would make it easy to do 140162306a36Sopenharmony_ci * this. Away you daemons of stupidity! 140262306a36Sopenharmony_ci */ 140362306a36Sopenharmony_ci local_irq_save(flags); 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci /* Fill each size-multiple cache line with a valid tag. */ 140662306a36Sopenharmony_ci pow2 = (64 * 1024); 140762306a36Sopenharmony_ci for (addr = begin; addr < end; addr = (begin + pow2)) { 140862306a36Sopenharmony_ci unsigned long *p = (unsigned long *) addr; 140962306a36Sopenharmony_ci __asm__ __volatile__("nop" : : "r" (*p)); /* whee... */ 141062306a36Sopenharmony_ci pow2 <<= 1; 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci /* Load first line with zero (therefore invalid) tag. */ 141462306a36Sopenharmony_ci write_c0_taglo(0); 141562306a36Sopenharmony_ci write_c0_taghi(0); 141662306a36Sopenharmony_ci __asm__ __volatile__("nop; nop; nop; nop;"); /* avoid the hazard */ 141762306a36Sopenharmony_ci cache_op(Index_Store_Tag_I, begin); 141862306a36Sopenharmony_ci cache_op(Index_Store_Tag_D, begin); 141962306a36Sopenharmony_ci cache_op(Index_Store_Tag_SD, begin); 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci /* Now search for the wrap around point. */ 142262306a36Sopenharmony_ci pow2 = (128 * 1024); 142362306a36Sopenharmony_ci for (addr = begin + (128 * 1024); addr < end; addr = begin + pow2) { 142462306a36Sopenharmony_ci cache_op(Index_Load_Tag_SD, addr); 142562306a36Sopenharmony_ci __asm__ __volatile__("nop; nop; nop; nop;"); /* hazard... */ 142662306a36Sopenharmony_ci if (!read_c0_taglo()) 142762306a36Sopenharmony_ci break; 142862306a36Sopenharmony_ci pow2 <<= 1; 142962306a36Sopenharmony_ci } 143062306a36Sopenharmony_ci local_irq_restore(flags); 143162306a36Sopenharmony_ci addr -= begin; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci scache_size = addr; 143462306a36Sopenharmony_ci c->scache.linesz = 16 << ((config & R4K_CONF_SB) >> 22); 143562306a36Sopenharmony_ci c->scache.ways = 1; 143662306a36Sopenharmony_ci c->scache.waybit = 0; /* does not matter */ 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci return 1; 143962306a36Sopenharmony_ci} 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_cistatic void loongson2_sc_init(void) 144262306a36Sopenharmony_ci{ 144362306a36Sopenharmony_ci struct cpuinfo_mips *c = ¤t_cpu_data; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci scache_size = 512*1024; 144662306a36Sopenharmony_ci c->scache.linesz = 32; 144762306a36Sopenharmony_ci c->scache.ways = 4; 144862306a36Sopenharmony_ci c->scache.waybit = 0; 144962306a36Sopenharmony_ci c->scache.waysize = scache_size / (c->scache.ways); 145062306a36Sopenharmony_ci c->scache.sets = scache_size / (c->scache.linesz * c->scache.ways); 145162306a36Sopenharmony_ci pr_info("Unified secondary cache %ldkB %s, linesize %d bytes.\n", 145262306a36Sopenharmony_ci scache_size >> 10, way_string[c->scache.ways], c->scache.linesz); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci c->options |= MIPS_CPU_INCLUSIVE_CACHES; 145562306a36Sopenharmony_ci} 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_cistatic void loongson3_sc_init(void) 145862306a36Sopenharmony_ci{ 145962306a36Sopenharmony_ci struct cpuinfo_mips *c = ¤t_cpu_data; 146062306a36Sopenharmony_ci unsigned int config2, lsize; 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci config2 = read_c0_config2(); 146362306a36Sopenharmony_ci lsize = (config2 >> 4) & 15; 146462306a36Sopenharmony_ci if (lsize) 146562306a36Sopenharmony_ci c->scache.linesz = 2 << lsize; 146662306a36Sopenharmony_ci else 146762306a36Sopenharmony_ci c->scache.linesz = 0; 146862306a36Sopenharmony_ci c->scache.sets = 64 << ((config2 >> 8) & 15); 146962306a36Sopenharmony_ci c->scache.ways = 1 + (config2 & 15); 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci /* Loongson-3 has 4-Scache banks, while Loongson-2K have only 2 banks */ 147262306a36Sopenharmony_ci if ((c->processor_id & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64R) 147362306a36Sopenharmony_ci c->scache.sets *= 2; 147462306a36Sopenharmony_ci else 147562306a36Sopenharmony_ci c->scache.sets *= 4; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci scache_size = c->scache.sets * c->scache.ways * c->scache.linesz; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci c->scache.waybit = 0; 148062306a36Sopenharmony_ci c->scache.waysize = scache_size / c->scache.ways; 148162306a36Sopenharmony_ci pr_info("Unified secondary cache %ldkB %s, linesize %d bytes.\n", 148262306a36Sopenharmony_ci scache_size >> 10, way_string[c->scache.ways], c->scache.linesz); 148362306a36Sopenharmony_ci if (scache_size) 148462306a36Sopenharmony_ci c->options |= MIPS_CPU_INCLUSIVE_CACHES; 148562306a36Sopenharmony_ci return; 148662306a36Sopenharmony_ci} 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ciextern int r5k_sc_init(void); 148962306a36Sopenharmony_ciextern int rm7k_sc_init(void); 149062306a36Sopenharmony_ciextern int mips_sc_init(void); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_cistatic void setup_scache(void) 149362306a36Sopenharmony_ci{ 149462306a36Sopenharmony_ci struct cpuinfo_mips *c = ¤t_cpu_data; 149562306a36Sopenharmony_ci unsigned int config = read_c0_config(); 149662306a36Sopenharmony_ci int sc_present = 0; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci /* 149962306a36Sopenharmony_ci * Do the probing thing on R4000SC and R4400SC processors. Other 150062306a36Sopenharmony_ci * processors don't have a S-cache that would be relevant to the 150162306a36Sopenharmony_ci * Linux memory management. 150262306a36Sopenharmony_ci */ 150362306a36Sopenharmony_ci switch (current_cpu_type()) { 150462306a36Sopenharmony_ci case CPU_R4000SC: 150562306a36Sopenharmony_ci case CPU_R4000MC: 150662306a36Sopenharmony_ci case CPU_R4400SC: 150762306a36Sopenharmony_ci case CPU_R4400MC: 150862306a36Sopenharmony_ci sc_present = run_uncached(probe_scache); 150962306a36Sopenharmony_ci if (sc_present) 151062306a36Sopenharmony_ci c->options |= MIPS_CPU_CACHE_CDEX_S; 151162306a36Sopenharmony_ci break; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci case CPU_R10000: 151462306a36Sopenharmony_ci case CPU_R12000: 151562306a36Sopenharmony_ci case CPU_R14000: 151662306a36Sopenharmony_ci case CPU_R16000: 151762306a36Sopenharmony_ci scache_size = 0x80000 << ((config & R10K_CONF_SS) >> 16); 151862306a36Sopenharmony_ci c->scache.linesz = 64 << ((config >> 13) & 1); 151962306a36Sopenharmony_ci c->scache.ways = 2; 152062306a36Sopenharmony_ci c->scache.waybit= 0; 152162306a36Sopenharmony_ci sc_present = 1; 152262306a36Sopenharmony_ci break; 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci case CPU_R5000: 152562306a36Sopenharmony_ci case CPU_NEVADA: 152662306a36Sopenharmony_ci#ifdef CONFIG_R5000_CPU_SCACHE 152762306a36Sopenharmony_ci r5k_sc_init(); 152862306a36Sopenharmony_ci#endif 152962306a36Sopenharmony_ci return; 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci case CPU_RM7000: 153262306a36Sopenharmony_ci#ifdef CONFIG_RM7000_CPU_SCACHE 153362306a36Sopenharmony_ci rm7k_sc_init(); 153462306a36Sopenharmony_ci#endif 153562306a36Sopenharmony_ci return; 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci case CPU_LOONGSON2EF: 153862306a36Sopenharmony_ci loongson2_sc_init(); 153962306a36Sopenharmony_ci return; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci case CPU_LOONGSON64: 154262306a36Sopenharmony_ci loongson3_sc_init(); 154362306a36Sopenharmony_ci return; 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci case CPU_CAVIUM_OCTEON3: 154662306a36Sopenharmony_ci /* don't need to worry about L2, fully coherent */ 154762306a36Sopenharmony_ci return; 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci default: 155062306a36Sopenharmony_ci if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | 155162306a36Sopenharmony_ci MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | 155262306a36Sopenharmony_ci MIPS_CPU_ISA_M32R5 | MIPS_CPU_ISA_M64R5 | 155362306a36Sopenharmony_ci MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { 155462306a36Sopenharmony_ci#ifdef CONFIG_MIPS_CPU_SCACHE 155562306a36Sopenharmony_ci if (mips_sc_init ()) { 155662306a36Sopenharmony_ci scache_size = c->scache.ways * c->scache.sets * c->scache.linesz; 155762306a36Sopenharmony_ci printk("MIPS secondary cache %ldkB, %s, linesize %d bytes.\n", 155862306a36Sopenharmony_ci scache_size >> 10, 155962306a36Sopenharmony_ci way_string[c->scache.ways], c->scache.linesz); 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci if (current_cpu_type() == CPU_BMIPS5000) 156262306a36Sopenharmony_ci c->options |= MIPS_CPU_INCLUSIVE_CACHES; 156362306a36Sopenharmony_ci } 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci#else 156662306a36Sopenharmony_ci if (!(c->scache.flags & MIPS_CACHE_NOT_PRESENT)) 156762306a36Sopenharmony_ci panic("Dunno how to handle MIPS32 / MIPS64 second level cache"); 156862306a36Sopenharmony_ci#endif 156962306a36Sopenharmony_ci return; 157062306a36Sopenharmony_ci } 157162306a36Sopenharmony_ci sc_present = 0; 157262306a36Sopenharmony_ci } 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci if (!sc_present) 157562306a36Sopenharmony_ci return; 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci /* compute a couple of other cache variables */ 157862306a36Sopenharmony_ci c->scache.waysize = scache_size / c->scache.ways; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci c->scache.sets = scache_size / (c->scache.linesz * c->scache.ways); 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci printk("Unified secondary cache %ldkB %s, linesize %d bytes.\n", 158362306a36Sopenharmony_ci scache_size >> 10, way_string[c->scache.ways], c->scache.linesz); 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci c->options |= MIPS_CPU_INCLUSIVE_CACHES; 158662306a36Sopenharmony_ci} 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_civoid au1x00_fixup_config_od(void) 158962306a36Sopenharmony_ci{ 159062306a36Sopenharmony_ci /* 159162306a36Sopenharmony_ci * c0_config.od (bit 19) was write only (and read as 0) 159262306a36Sopenharmony_ci * on the early revisions of Alchemy SOCs. It disables the bus 159362306a36Sopenharmony_ci * transaction overlapping and needs to be set to fix various errata. 159462306a36Sopenharmony_ci */ 159562306a36Sopenharmony_ci switch (read_c0_prid()) { 159662306a36Sopenharmony_ci case 0x00030100: /* Au1000 DA */ 159762306a36Sopenharmony_ci case 0x00030201: /* Au1000 HA */ 159862306a36Sopenharmony_ci case 0x00030202: /* Au1000 HB */ 159962306a36Sopenharmony_ci case 0x01030200: /* Au1500 AB */ 160062306a36Sopenharmony_ci /* 160162306a36Sopenharmony_ci * Au1100 errata actually keeps silence about this bit, so we set it 160262306a36Sopenharmony_ci * just in case for those revisions that require it to be set according 160362306a36Sopenharmony_ci * to the (now gone) cpu table. 160462306a36Sopenharmony_ci */ 160562306a36Sopenharmony_ci case 0x02030200: /* Au1100 AB */ 160662306a36Sopenharmony_ci case 0x02030201: /* Au1100 BA */ 160762306a36Sopenharmony_ci case 0x02030202: /* Au1100 BC */ 160862306a36Sopenharmony_ci set_c0_config(1 << 19); 160962306a36Sopenharmony_ci break; 161062306a36Sopenharmony_ci } 161162306a36Sopenharmony_ci} 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci/* CP0 hazard avoidance. */ 161462306a36Sopenharmony_ci#define NXP_BARRIER() \ 161562306a36Sopenharmony_ci __asm__ __volatile__( \ 161662306a36Sopenharmony_ci ".set noreorder\n\t" \ 161762306a36Sopenharmony_ci "nop; nop; nop; nop; nop; nop;\n\t" \ 161862306a36Sopenharmony_ci ".set reorder\n\t") 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_cistatic void nxp_pr4450_fixup_config(void) 162162306a36Sopenharmony_ci{ 162262306a36Sopenharmony_ci unsigned long config0; 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci config0 = read_c0_config(); 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci /* clear all three cache coherency fields */ 162762306a36Sopenharmony_ci config0 &= ~(0x7 | (7 << 25) | (7 << 28)); 162862306a36Sopenharmony_ci config0 |= (((_page_cachable_default >> _CACHE_SHIFT) << 0) | 162962306a36Sopenharmony_ci ((_page_cachable_default >> _CACHE_SHIFT) << 25) | 163062306a36Sopenharmony_ci ((_page_cachable_default >> _CACHE_SHIFT) << 28)); 163162306a36Sopenharmony_ci write_c0_config(config0); 163262306a36Sopenharmony_ci NXP_BARRIER(); 163362306a36Sopenharmony_ci} 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_cistatic int cca = -1; 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_cistatic int __init cca_setup(char *str) 163862306a36Sopenharmony_ci{ 163962306a36Sopenharmony_ci get_option(&str, &cca); 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci return 0; 164262306a36Sopenharmony_ci} 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ciearly_param("cca", cca_setup); 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_cistatic void coherency_setup(void) 164762306a36Sopenharmony_ci{ 164862306a36Sopenharmony_ci if (cca < 0 || cca > 7) 164962306a36Sopenharmony_ci cca = read_c0_config() & CONF_CM_CMASK; 165062306a36Sopenharmony_ci _page_cachable_default = cca << _CACHE_SHIFT; 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci pr_debug("Using cache attribute %d\n", cca); 165362306a36Sopenharmony_ci change_c0_config(CONF_CM_CMASK, cca); 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci /* 165662306a36Sopenharmony_ci * c0_status.cu=0 specifies that updates by the sc instruction use 165762306a36Sopenharmony_ci * the coherency mode specified by the TLB; 1 means cachable 165862306a36Sopenharmony_ci * coherent update on write will be used. Not all processors have 165962306a36Sopenharmony_ci * this bit and; some wire it to zero, others like Toshiba had the 166062306a36Sopenharmony_ci * silly idea of putting something else there ... 166162306a36Sopenharmony_ci */ 166262306a36Sopenharmony_ci switch (current_cpu_type()) { 166362306a36Sopenharmony_ci case CPU_R4000PC: 166462306a36Sopenharmony_ci case CPU_R4000SC: 166562306a36Sopenharmony_ci case CPU_R4000MC: 166662306a36Sopenharmony_ci case CPU_R4400PC: 166762306a36Sopenharmony_ci case CPU_R4400SC: 166862306a36Sopenharmony_ci case CPU_R4400MC: 166962306a36Sopenharmony_ci clear_c0_config(CONF_CU); 167062306a36Sopenharmony_ci break; 167162306a36Sopenharmony_ci /* 167262306a36Sopenharmony_ci * We need to catch the early Alchemy SOCs with 167362306a36Sopenharmony_ci * the write-only co_config.od bit and set it back to one on: 167462306a36Sopenharmony_ci * Au1000 rev DA, HA, HB; Au1100 AB, BA, BC, Au1500 AB 167562306a36Sopenharmony_ci */ 167662306a36Sopenharmony_ci case CPU_ALCHEMY: 167762306a36Sopenharmony_ci au1x00_fixup_config_od(); 167862306a36Sopenharmony_ci break; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci case PRID_IMP_PR4450: 168162306a36Sopenharmony_ci nxp_pr4450_fixup_config(); 168262306a36Sopenharmony_ci break; 168362306a36Sopenharmony_ci } 168462306a36Sopenharmony_ci} 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_cistatic void r4k_cache_error_setup(void) 168762306a36Sopenharmony_ci{ 168862306a36Sopenharmony_ci extern char __weak except_vec2_generic; 168962306a36Sopenharmony_ci extern char __weak except_vec2_sb1; 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci switch (current_cpu_type()) { 169262306a36Sopenharmony_ci case CPU_SB1: 169362306a36Sopenharmony_ci case CPU_SB1A: 169462306a36Sopenharmony_ci set_uncached_handler(0x100, &except_vec2_sb1, 0x80); 169562306a36Sopenharmony_ci break; 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci default: 169862306a36Sopenharmony_ci set_uncached_handler(0x100, &except_vec2_generic, 0x80); 169962306a36Sopenharmony_ci break; 170062306a36Sopenharmony_ci } 170162306a36Sopenharmony_ci} 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_civoid r4k_cache_init(void) 170462306a36Sopenharmony_ci{ 170562306a36Sopenharmony_ci extern void build_clear_page(void); 170662306a36Sopenharmony_ci extern void build_copy_page(void); 170762306a36Sopenharmony_ci struct cpuinfo_mips *c = ¤t_cpu_data; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci probe_pcache(); 171062306a36Sopenharmony_ci probe_vcache(); 171162306a36Sopenharmony_ci setup_scache(); 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci r4k_blast_dcache_page_setup(); 171462306a36Sopenharmony_ci r4k_blast_dcache_setup(); 171562306a36Sopenharmony_ci r4k_blast_icache_page_setup(); 171662306a36Sopenharmony_ci r4k_blast_icache_setup(); 171762306a36Sopenharmony_ci r4k_blast_scache_page_setup(); 171862306a36Sopenharmony_ci r4k_blast_scache_setup(); 171962306a36Sopenharmony_ci r4k_blast_scache_node_setup(); 172062306a36Sopenharmony_ci#ifdef CONFIG_EVA 172162306a36Sopenharmony_ci r4k_blast_dcache_user_page_setup(); 172262306a36Sopenharmony_ci r4k_blast_icache_user_page_setup(); 172362306a36Sopenharmony_ci#endif 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci /* 172662306a36Sopenharmony_ci * Some MIPS32 and MIPS64 processors have physically indexed caches. 172762306a36Sopenharmony_ci * This code supports virtually indexed processors and will be 172862306a36Sopenharmony_ci * unnecessarily inefficient on physically indexed processors. 172962306a36Sopenharmony_ci */ 173062306a36Sopenharmony_ci if (c->dcache.linesz && cpu_has_dc_aliases) 173162306a36Sopenharmony_ci shm_align_mask = max_t( unsigned long, 173262306a36Sopenharmony_ci c->dcache.sets * c->dcache.linesz - 1, 173362306a36Sopenharmony_ci PAGE_SIZE - 1); 173462306a36Sopenharmony_ci else 173562306a36Sopenharmony_ci shm_align_mask = PAGE_SIZE-1; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci __flush_cache_vmap = r4k__flush_cache_vmap; 173862306a36Sopenharmony_ci __flush_cache_vunmap = r4k__flush_cache_vunmap; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci flush_cache_all = cache_noop; 174162306a36Sopenharmony_ci __flush_cache_all = r4k___flush_cache_all; 174262306a36Sopenharmony_ci flush_cache_mm = r4k_flush_cache_mm; 174362306a36Sopenharmony_ci flush_cache_page = r4k_flush_cache_page; 174462306a36Sopenharmony_ci flush_cache_range = r4k_flush_cache_range; 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci __flush_kernel_vmap_range = r4k_flush_kernel_vmap_range; 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci flush_icache_all = r4k_flush_icache_all; 174962306a36Sopenharmony_ci flush_data_cache_page = r4k_flush_data_cache_page; 175062306a36Sopenharmony_ci flush_icache_range = r4k_flush_icache_range; 175162306a36Sopenharmony_ci local_flush_icache_range = local_r4k_flush_icache_range; 175262306a36Sopenharmony_ci __flush_icache_user_range = r4k_flush_icache_user_range; 175362306a36Sopenharmony_ci __local_flush_icache_user_range = local_r4k_flush_icache_user_range; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci#ifdef CONFIG_DMA_NONCOHERENT 175662306a36Sopenharmony_ci _dma_cache_wback_inv = r4k_dma_cache_wback_inv; 175762306a36Sopenharmony_ci _dma_cache_wback = r4k_dma_cache_wback_inv; 175862306a36Sopenharmony_ci _dma_cache_inv = r4k_dma_cache_inv; 175962306a36Sopenharmony_ci#endif /* CONFIG_DMA_NONCOHERENT */ 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci build_clear_page(); 176262306a36Sopenharmony_ci build_copy_page(); 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci /* 176562306a36Sopenharmony_ci * We want to run CMP kernels on core with and without coherent 176662306a36Sopenharmony_ci * caches. Therefore, do not use CONFIG_MIPS_CMP to decide whether 176762306a36Sopenharmony_ci * or not to flush caches. 176862306a36Sopenharmony_ci */ 176962306a36Sopenharmony_ci local_r4k___flush_cache_all(NULL); 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci coherency_setup(); 177262306a36Sopenharmony_ci board_cache_error_setup = r4k_cache_error_setup; 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci /* 177562306a36Sopenharmony_ci * Per-CPU overrides 177662306a36Sopenharmony_ci */ 177762306a36Sopenharmony_ci switch (current_cpu_type()) { 177862306a36Sopenharmony_ci case CPU_BMIPS4350: 177962306a36Sopenharmony_ci case CPU_BMIPS4380: 178062306a36Sopenharmony_ci /* No IPI is needed because all CPUs share the same D$ */ 178162306a36Sopenharmony_ci flush_data_cache_page = r4k_blast_dcache_page; 178262306a36Sopenharmony_ci break; 178362306a36Sopenharmony_ci case CPU_BMIPS5000: 178462306a36Sopenharmony_ci /* We lose our superpowers if L2 is disabled */ 178562306a36Sopenharmony_ci if (c->scache.flags & MIPS_CACHE_NOT_PRESENT) 178662306a36Sopenharmony_ci break; 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci /* I$ fills from D$ just by emptying the write buffers */ 178962306a36Sopenharmony_ci flush_cache_page = (void *)b5k_instruction_hazard; 179062306a36Sopenharmony_ci flush_cache_range = (void *)b5k_instruction_hazard; 179162306a36Sopenharmony_ci flush_data_cache_page = (void *)b5k_instruction_hazard; 179262306a36Sopenharmony_ci flush_icache_range = (void *)b5k_instruction_hazard; 179362306a36Sopenharmony_ci local_flush_icache_range = (void *)b5k_instruction_hazard; 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci /* Optimization: an L2 flush implicitly flushes the L1 */ 179762306a36Sopenharmony_ci current_cpu_data.options |= MIPS_CPU_INCLUSIVE_CACHES; 179862306a36Sopenharmony_ci break; 179962306a36Sopenharmony_ci case CPU_LOONGSON64: 180062306a36Sopenharmony_ci /* Loongson-3 maintains cache coherency by hardware */ 180162306a36Sopenharmony_ci __flush_cache_all = cache_noop; 180262306a36Sopenharmony_ci __flush_cache_vmap = cache_noop; 180362306a36Sopenharmony_ci __flush_cache_vunmap = cache_noop; 180462306a36Sopenharmony_ci __flush_kernel_vmap_range = (void *)cache_noop; 180562306a36Sopenharmony_ci flush_cache_mm = (void *)cache_noop; 180662306a36Sopenharmony_ci flush_cache_page = (void *)cache_noop; 180762306a36Sopenharmony_ci flush_cache_range = (void *)cache_noop; 180862306a36Sopenharmony_ci flush_icache_all = (void *)cache_noop; 180962306a36Sopenharmony_ci flush_data_cache_page = (void *)cache_noop; 181062306a36Sopenharmony_ci break; 181162306a36Sopenharmony_ci } 181262306a36Sopenharmony_ci} 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_cistatic int r4k_cache_pm_notifier(struct notifier_block *self, unsigned long cmd, 181562306a36Sopenharmony_ci void *v) 181662306a36Sopenharmony_ci{ 181762306a36Sopenharmony_ci switch (cmd) { 181862306a36Sopenharmony_ci case CPU_PM_ENTER_FAILED: 181962306a36Sopenharmony_ci case CPU_PM_EXIT: 182062306a36Sopenharmony_ci coherency_setup(); 182162306a36Sopenharmony_ci break; 182262306a36Sopenharmony_ci } 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci return NOTIFY_OK; 182562306a36Sopenharmony_ci} 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_cistatic struct notifier_block r4k_cache_pm_notifier_block = { 182862306a36Sopenharmony_ci .notifier_call = r4k_cache_pm_notifier, 182962306a36Sopenharmony_ci}; 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ciint __init r4k_cache_init_pm(void) 183262306a36Sopenharmony_ci{ 183362306a36Sopenharmony_ci return cpu_pm_register_notifier(&r4k_cache_pm_notifier_block); 183462306a36Sopenharmony_ci} 183562306a36Sopenharmony_ciarch_initcall(r4k_cache_init_pm); 1836