diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2012-06-23 21:56:07 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2012-06-23 21:56:07 +0000 |
commit | 8d6e67f24f75d0dfc4af3cffcf6de71a924bce9a (patch) | |
tree | 483e298143b8eba7f4b2cc2fa0aff76402953d9d | |
parent | 324f4b04e0878b995b836bdbbb069e524a5b6615 (diff) |
Replace R5000 and R10000 family assembly cache routines with C equivalents,
which will be easier to maintain on the long run. Be sure to rm cache_r*.d in
your kernel compile directories after updating.
-rw-r--r-- | sys/arch/mips64/conf/files.mips64 | 6 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/cache_r10k.S | 498 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/cache_r10k.c | 305 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/cache_r5k.S | 923 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/cache_r5k.c | 842 |
5 files changed, 1150 insertions, 1424 deletions
diff --git a/sys/arch/mips64/conf/files.mips64 b/sys/arch/mips64/conf/files.mips64 index 0e0d5801095..d49a3c47652 100644 --- a/sys/arch/mips64/conf/files.mips64 +++ b/sys/arch/mips64/conf/files.mips64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.mips64,v 1.19 2012/05/27 14:32:04 miod Exp $ +# $OpenBSD: files.mips64,v 1.20 2012/06/23 21:56:06 miod Exp $ file arch/mips64/mips64/arcbios.c arcbios file arch/mips64/mips64/clock.c @@ -16,8 +16,8 @@ file arch/mips64/mips64/vm_machdep.c file arch/mips64/mips64/cache_loongson2.c cpu_loongson2 file arch/mips64/mips64/cache_r4k.c cpu_r4000 -file arch/mips64/mips64/cache_r5k.S cpu_r5000 | cpu_rm7000 -file arch/mips64/mips64/cache_r10k.S cpu_r10000 +file arch/mips64/mips64/cache_r5k.c cpu_r5000 | cpu_rm7000 +file arch/mips64/mips64/cache_r10k.c cpu_r10000 file arch/mips64/mips64/cache_octeon.c cpu_octeon file arch/mips64/mips64/context.S file arch/mips64/mips64/cp0access.S diff --git a/sys/arch/mips64/mips64/cache_r10k.S b/sys/arch/mips64/mips64/cache_r10k.S deleted file mode 100644 index 3325ec31d7b..00000000000 --- a/sys/arch/mips64/mips64/cache_r10k.S +++ /dev/null @@ -1,498 +0,0 @@ -/* $OpenBSD: cache_r10k.S,v 1.16 2012/04/21 12:20:30 miod Exp $ */ - -/* - * Copyright (c) 2004 Opsycon AB (www.opsycon.se) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -/* - * Processors supported: - * R10000, R12000, R14000 and R16000. - * - * The following assumptions are made: - * - L1 I$ is 2 way, 64 bytes/line - * - L1 D$ is WB, 2 way, 32 bytes/line - * - L2 is WT, 2 way - */ - -#include <sys/errno.h> -#include <sys/syscall.h> - -#include <machine/param.h> -#include <machine/asm.h> -#include <machine/cpu.h> -#include <machine/regnum.h> - -#include "assym.h" - - .set mips3 - -/* - * Skip the .h file. Noone else need to know! - */ - -#define IndexInvalidate_I 0x00 -#define IndexWBInvalidate_D 0x01 -#define IndexFlashInvalidate_T 0x02 -#define IndexWBInvalidate_S 0x03 - -#define IndexLoadTag_I 0x04 -#define IndexLoadTag_D 0x05 -#define IndexLoadTag_S 0x07 - -#define IndexStoreTag_I 0x08 -#define IndexStoreTag_D 0x09 -#define IndexStoreTag_S 0x0b - -#define CreateDirtyExclusive 0x09 - -#define HitInvalidate_I 0x10 -#define HitInvalidate_D 0x11 -#define HitInvalidate_S 0x13 - -#define Fill_I 0x14 -#define HitWBInvalidate_D 0x15 -#define HitWBInvalidate_S 0x17 - -#define HitWB_I 0x18 -#define HitWB_D 0x19 -#define HitWB_S 0x1b - -/* - * Define cache type definition bits. NOTE! the 3 lsb may NOT change! - */ -#define CTYPE_DIR 0x0001 /* Cache is direct mapped */ -#define CTYPE_2WAY 0x0002 /* Cache is TWO way */ -#define CTYPE_4WAY 0x0004 /* Cache is FOUR way */ -#define CTYPE_WAYMASK 0x0007 - -#define CTYPE_HAS_XL2 0x0200 /* External L2 Cache present */ - - .set noreorder # Noreorder is default style! - -/*---------------------------------------------------------------------------- - * - * Mips10k_ConfigCache(struct cpu_info *ci) - * - * Size and configure the caches. - * NOTE: should only be called from mips_init(). - * - * Side effects: - * The size of the data cache is stored into ci_l1datacachesize. - * The size of instruction cache is stored into ci_l1instcachesize. - * Alignment mask for cache aliasing test is stored in cache_valias_mask. - * ci_l2size is set to the size of the secondary cache. - * ci_l3size is set to the size of the tertiary cache. - * ci_cacheways is set to 0 for direct mapped caches, 2 for two way - * caches and 4 for four way caches. This primarily indicates the - * primary cache associativity. - * - * Allocation: - * ta0, ta1 ta2 used to hold I and D set size and Alias mask. - * - *---------------------------------------------------------------------------- - */ -LEAF(Mips10k_ConfigCache, 0) - .set noreorder - mfc0 v0, COP_0_CONFIG # Get configuration register - - srl t1, v0, 29 # Get I cache size. - and t1, 7 - li t2, 4096 - sllv ta0, t2, t1 # ta0 = Initial I set size. - - li t2, 64 - sw t2, CI_L1INSTCACHELINE(a0) - - srl t1, v0, 26 # Get D cache size. - and t1, 7 - li t2, 4096 # Fixed page size. - sllv ta1, t2, t1 - - li t2, 32 # Get D cache line size. - sw t2, CI_L1DATACACHELINE(a0) - - li t2, CTYPE_2WAY # Assume two way cache - li ta3, 0 # Tertiary size 0. - - or t2, CTYPE_HAS_XL2 # External L2 present. - srl t1, v0, 16 # Get L2 cache size. - and t1, 7 - li ta2, 512*1024 # 512k per 'click'. - sll ta2, t1 - -/* - * Get here with t2 = Cache type, ta0 = L1 I size, ta1 = L1 D size. - * ta2 = secondary size, ta3 = tertiary size. - */ -ConfResult: - sw t2, CI_CACHECONFIGURATION(a0) # Save cache attributes - and t2, CTYPE_WAYMASK # isolate number of sets. - sw t2, CI_CACHEWAYS(a0) - srl t2, 1 # get div shift for set size. - - sw ta2, CI_L2SIZE(a0) - sw ta3, CI_L3SIZE(a0) - - addu t1, ta0, -1 # Use icache for alias mask - srl t1, t2 - and t1, ~(PAGE_SIZE - 1) - beqz t1, 1f - nop - or t1, (PAGE_SIZE - 1) -1: -#ifdef MULTIPROCESSOR - PTR_L ta2, cache_valias_mask - or t1, ta2 # Pick largest mask -#endif - PTR_S t1, cache_valias_mask - PTR_S t1, pmap_prefer_mask - - sw ta0, CI_L1INSTCACHESIZE(a0) # store cache size. - srl ta0, t2 # calculate set size. - sw ta0, CI_L1INSTCACHESET(a0) - - sw ta1, CI_L1DATACACHESIZE(a0) # store cache size. - srl ta1, t2 # calculate set size. - sw ta1, CI_L1DATACACHESET(a0) - - j ra - nop -END(Mips10k_ConfigCache) - -/*---------------------------------------------------------------------------- - * - * Mips10k_SyncCache(struct cpu_info *ci) - * - * Sync ALL caches. - * No need to look at number of sets since we are cleaning out - * the entire cache and thus will address all sets anyway. - * - * Side effects: - * The contents of ALL caches are Invalidated or Synched. - * - *---------------------------------------------------------------------------- - */ -LEAF(Mips10k_SyncCache, 0) - .set noreorder - lw t1, CI_L1INSTCACHESET(a0) - lw t2, CI_L1DATACACHESET(a0) - -/* - * Sync the instruction cache. - */ - - LOAD_XKPHYS(t0, CCA_CACHED) - PTR_ADDU t1, t0, t1 # Compute end address - PTR_SUBU t1, 128 - -1: - cache IndexInvalidate_I, 0(t0) - cache IndexInvalidate_I, 64(t0) - - cache IndexInvalidate_I, 1(t0) - cache IndexInvalidate_I, 65(t0) - - bne t0, t1, 1b - PTR_ADDU t0, t0, 128 - -/* - * Sync the data cache. Do L1 first. Indexed only operate on - * the selected cache and differs from Hit in that sense. - */ - - LOAD_XKPHYS(t0, CCA_CACHED) - PTR_ADDU t1, t0, t2 # End address - PTR_SUBU t1, t1, 128 -1: - cache IndexWBInvalidate_D, 0(t0) - cache IndexWBInvalidate_D, 32(t0) - cache IndexWBInvalidate_D, 64(t0) - cache IndexWBInvalidate_D, 96(t0) - - cache IndexWBInvalidate_D, 1(t0) - cache IndexWBInvalidate_D, 33(t0) - cache IndexWBInvalidate_D, 65(t0) - cache IndexWBInvalidate_D, 97(t0) - - bne t0, t1, 1b - PTR_ADDU t0, t0, 128 - -/* Do L2 */ - LOAD_XKPHYS(t3, CCA_CACHED) - lw ta0, CI_L2SIZE(a0) - PTR_SRL ta0, ta0, 1 # proper set size -10: - cache IndexWBInvalidate_S, 0(t3) - cache IndexWBInvalidate_S, 1(t3) - PTR_SUBU ta0, 64 # Fixed L2 cache line size. - bgtz ta0, 10b - PTR_ADDU t3, 64 - - j ra - nop -END(Mips10k_SyncCache) - -/*---------------------------------------------------------------------------- - * - * Mips10k_InvalidateICache(struct cpu_info *ci, vaddr_t va, size_t len) - * - * Invalidate the L1 instruction cache for at least range of va to - * va + len - 1. - * - * Side effects: - * The contents of the L1 Instruction cache are invalidated. - * - *---------------------------------------------------------------------------- - */ -LEAF(Mips10k_InvalidateICache, 0) - LOAD_XKPHYS(a3, CCA_CACHED) - and a1, 0x00ffffff # Reduce addr to cache index - PTR_ADDU a2, 63 # Round up size - PTR_ADDU a2, a1 # Add extra from address - and a1, -64 # Align start address - PTR_SUBU a2, a2, a1 - PTR_ADDU a1, a3 # a1 now new XKPHYS address - srl a2, a2, 6 # Number of unrolled loops -1: - addu a2, -1 - - cache IndexInvalidate_I, 0(a1) # do set A - cache IndexInvalidate_I, 1(a1) # do set B - - bne a2, zero, 1b - PTR_ADDU a1, 64 - - j ra - nop -END(Mips10k_InvalidateICache) - -/*---------------------------------------------------------------------------- - * - * Mips10k_SyncDCachePage(struct cpu_info *ci, vaddr_t va, paddr_t pa) - * - * Sync the L1 data cache page for address va. - * The physical address is not used. - * - * Side effects: - * The contents of the cache is written back to primary memory. - * The cache line is invalidated. - * - *---------------------------------------------------------------------------- - */ -LEAF(Mips10k_SyncDCachePage, 0) - LOAD_XKPHYS(a3, CCA_CACHED) - dsll a1, (64 - 57) - dsrl a1, (64 - 57) - PTR_ADDU a1, a3 # a1 now new XKPHYS address - and a1, ~PAGE_MASK # Page align start address - PTR_ADDU a2, a1, PAGE_SIZE-128 - -1: - cache IndexWBInvalidate_D, 0(a1) # do set A - cache IndexWBInvalidate_D, 32(a1) - cache IndexWBInvalidate_D, 64(a1) - cache IndexWBInvalidate_D, 96(a1) - - cache IndexWBInvalidate_D, 1(a1) # do set B - cache IndexWBInvalidate_D, 33(a1) - cache IndexWBInvalidate_D, 65(a1) - cache IndexWBInvalidate_D, 97(a1) - - bne a2, a1, 1b - PTR_ADDU a1, 128 - - j ra - nop -END(Mips10k_SyncDCachePage) - -/*---------------------------------------------------------------------------- - * - * Mips10k_HitSyncDCache(struct cpu_info *ci, vaddr_t va, size_t len) - * - * Sync data cache for range of va to va + len - 1. - * Only lines with matching address are flushed. - * - * Side effects: - * The contents of the L1 cache is written back to primary memory. - * The cache line is invalidated. - * - *---------------------------------------------------------------------------- - */ -LEAF(Mips10k_HitSyncDCache, 0) - beq a2, zero, 3f # size is zero! - PTR_ADDU a2, 31 # Round up - PTR_ADDU a2, a2, a1 # Add extra from address - and a1, a1, -32 # align address - PTR_SUBU a2, a2, a1 - srl a2, a2, 5 # Compute number of cache lines - -1: - PTR_ADDU a2, -1 - cache HitWBInvalidate_D, 0(a1) - bne a2, zero, 1b - PTR_ADDU a1, 32 - -3: - j ra - nop -END(Mips10k_HitSyncDCache) - -/*---------------------------------------------------------------------------- - * - * _mips10k_HitSyncSCache(struct cpu_info *ci, vaddr_t va, size_t len) - * - * Sync secondary cache for range of va to va + len - 1. - * Only lines with matching address are flushed. - * - * Side effects: - * The contents of the L2 cache is written back to primary memory. - * The cache line is invalidated. - * - *---------------------------------------------------------------------------- - */ -ALEAF(_mips10k_HitSyncSCache) - beq a2, zero, 3f # size is zero! - PTR_ADDU a2, a2, a1 # Add in extra from align - and a1, a1, -32 # Align address - PTR_SUBU a2, a2, a1 -1: - PTR_ADDU a2, -32 - - cache HitWBInvalidate_S, 0(a1) - - bgtz a2, 1b - PTR_ADDU a1, 32 - -3: - j ra - nop - -/*---------------------------------------------------------------------------- - * - * Mips10k_HitInvalidateDCache(struct cpu_info *ci, vaddr_t va, size_t len) - * - * Invalidate data cache for range of va to va + len - 1. - * Only lines with matching addresses are invalidated. - * - * Side effects: - * The L1 cache line is invalidated. - * - *---------------------------------------------------------------------------- - */ -LEAF(Mips10k_HitInvalidateDCache, 0) - beq a2, zero, 3f # size is zero! - PTR_ADDU a2, a2, a1 # Add in extra from align - and a1, a1, -32 # Align address - PTR_SUBU a2, a2, a1 - -1: - PTR_ADDU a2, -32 - - cache HitInvalidate_D, 0(a1) - - bgtz a2, 1b - PTR_ADDU a1, 32 - -3: - j ra - nop -END(Mips10k_HitInvalidateDCache) - -/*---------------------------------------------------------------------------- - * - * _mips10k_HitInvalidateSCache(struct cpu_info *ci, vaddr_t va, size_t len) - * - * Invalidate secondary cache for range of va to va + len - 1. - * Only lines with matching addresses are invalidated. - * - * Side effects: - * The L2 cache line is invalidated. - * - *---------------------------------------------------------------------------- - */ -ALEAF(_mips10k_HitInvalidateSCache) - beq a2, zero, 3f # size is zero! - PTR_ADDU a2, a2, a1 # Add in extra from align - and a1, a1, -32 # Align address - PTR_SUBU a2, a2, a1 -1: - PTR_ADDU a2, -32 - - cache HitInvalidate_S, 0(a1) - - bgtz a2, 1b - PTR_ADDU a1, 32 - -3: - j ra - nop - -/*---------------------------------------------------------------------------- - * - * Mips10k_IOSyncDCache(struct cpu_info *ci, vaddr_t va, size_t len, int how) - * - * Invalidate or flush data cache for range of va to va + len - 1. - * - * Side effects: - * If how == 0 (read), L1 and L2 caches are invalidated or flushed if - * the area does not match the alignment requirements. - * If how == 1 (write), L1 and L2 caches are written back - * to memory and invalidated. - * If how == 2 (write-read), L1 and L2 caches are written back - * to memory and invalidated. - * - *---------------------------------------------------------------------------- - */ -LEAF(Mips10k_IOSyncDCache, 0) - beqz a3, SyncRD # Sync PREREAD - nop - addiu a3, -1 - bnez a3, SyncRDWB # Sync PREWRITE+PREREAD - nop - -SyncWR: - j _mips10k_HitSyncSCache # Do L2 cache - nop # L1 done in parallel - -SyncRD: - and t0, a1, 63 # check if invalidate possible - bnez t0, SyncRDWB # both address and size must - and t0, a2, 63 # be aligned at the cache size - bnez t0, SyncRDWB - nop - - /* - * Sync for aligned read, no writeback required. - */ - j _mips10k_HitInvalidateSCache # L2 cache - nop # L1 done in parallel - -SyncRDWB: - /* - * Sync for unaligned read or write-read. - */ - j _mips10k_HitSyncSCache # L2 cache - nop # L1 done in parallel -END(Mips10k_IOSyncDCache) diff --git a/sys/arch/mips64/mips64/cache_r10k.c b/sys/arch/mips64/mips64/cache_r10k.c new file mode 100644 index 00000000000..916475983aa --- /dev/null +++ b/sys/arch/mips64/mips64/cache_r10k.c @@ -0,0 +1,305 @@ +/* $OpenBSD: cache_r10k.c,v 1.1 2012/06/23 21:56:06 miod Exp $ */ + +/* + * Copyright (c) 2012 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Cache handling code for R10000 processor family (R10000, R12000, + * R14000, R16000). + * + * R10000 caches are : + * - L1 I$ is 2-way, VIPT, 64 bytes/line, 32KB total + * - L1 D$ is 2-way, VIPT, write-back, 32 bytes/line, 32KB total + * - L2 is 2-way, PIPT, write-back, 64 or 128 bytes/line, 512KB up to 16MB + */ + +#include <sys/param.h> +#include <sys/systm.h> + +#include <mips64/cache.h> +#include <machine/cpu.h> + +#include <uvm/uvm_extern.h> + +#define IndexInvalidate_I 0x00 +#define IndexWBInvalidate_D 0x01 +#define IndexWBInvalidate_S 0x03 + +#define HitInvalidate_D 0x11 +#define HitInvalidate_S 0x13 + +#define CacheBarrier 0x14 + +#define HitWBInvalidate_D 0x15 +#define HitWBInvalidate_S 0x17 + +#define cache(op,set,addr) \ + __asm__ __volatile__ \ + ("cache %0, %1(%2)" :: "i"(op), "i"(set), "r"(addr) : "memory") + +static __inline__ void mips10k_hitinv_primary(vaddr_t, vsize_t); +static __inline__ void mips10k_hitinv_secondary(vaddr_t, vsize_t); +static __inline__ void mips10k_hitwbinv_primary(vaddr_t, vsize_t); +static __inline__ void mips10k_hitwbinv_secondary(vaddr_t, vsize_t); + +#define R10K_L1I_LINE 64UL +#define R10K_L1D_LINE 32UL + +void +Mips10k_ConfigCache(struct cpu_info *ci) +{ + uint32_t cfg, valias_mask; + + cfg = cp0_get_config(); + + ci->ci_l1instcacheline = R10K_L1I_LINE; + ci->ci_l1instcachesize = (1 << 12) << ((cfg >> 29) & 0x07); /* IC */ + + ci->ci_l1datacacheline = R10K_L1D_LINE; + ci->ci_l1datacachesize = (1 << 12) << ((cfg >> 26) & 0x07); /* DC */ + + ci->ci_l2line = 64; /* XXX could be 128 */ + ci->ci_l2size = (1 << 19) << ((cfg >> 16) & 0x07); + + ci->ci_l3size = 0; + + ci->ci_cacheways = 2; + ci->ci_l1instcacheset = ci->ci_l1instcachesize / 2; + ci->ci_l1datacacheset = ci->ci_l1datacachesize / 2; + + valias_mask = (max(ci->ci_l1instcacheset, ci->ci_l1datacacheset) - 1) & + ~PAGE_MASK; + + if (valias_mask != 0) { + valias_mask |= PAGE_MASK; +#ifdef MULTIPROCESSOR + if (valias_mask > cache_valias_mask) { +#endif + cache_valias_mask = valias_mask; + pmap_prefer_mask = valias_mask; +#ifdef MULTIPROCESSOR + } +#endif + } +} + +static __inline__ void +mips10k_hitwbinv_primary(vaddr_t va, vsize_t sz) +{ + vaddr_t eva; + + eva = va + sz; + while (va != eva) { + cache(HitWBInvalidate_D, 0, va); + va += R10K_L1D_LINE; + } +} + +static __inline__ void +mips10k_hitwbinv_secondary(vaddr_t va, vsize_t sz) +{ + vaddr_t eva; + + eva = va + sz; + while (va != eva) { + cache(HitWBInvalidate_S, 0, va); + va += 64UL; + } +} + +static __inline__ void +mips10k_hitinv_primary(vaddr_t va, vsize_t sz) +{ + vaddr_t eva; + + eva = va + sz; + while (va != eva) { + cache(HitInvalidate_D, 0, va); + va += R10K_L1D_LINE; + } +} + +static __inline__ void +mips10k_hitinv_secondary(vaddr_t va, vsize_t sz) +{ + vaddr_t eva; + + eva = va + sz; + while (va != eva) { + cache(HitInvalidate_S, 0, va); + va += 64UL; + } +} + +/* + * Writeback and invalidate all caches. + */ +void +Mips10k_SyncCache(struct cpu_info *ci) +{ + vaddr_t sva, eva; + + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + eva = sva + ci->ci_l1instcacheset; + while (sva != eva) { + cache(IndexInvalidate_I, 0, sva); + cache(IndexInvalidate_I, 1, sva); + sva += R10K_L1I_LINE; + } + + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + eva = sva + ci->ci_l1datacacheset; + while (sva != eva) { + cache(IndexWBInvalidate_D, 0, sva); + cache(IndexWBInvalidate_D, 1, sva); + sva += R10K_L1D_LINE; + } + + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + eva = sva + ci->ci_l2size / 2; + while (sva != eva) { + cache(IndexWBInvalidate_S, 0, sva); + cache(IndexWBInvalidate_S, 1, sva); + sva += 64UL; + } +} + +/* + * Invalidate I$ for the given range. + */ +void +Mips10k_InvalidateICache(struct cpu_info *ci, vaddr_t _va, size_t _sz) +{ + vaddr_t va, sva, eva; + vsize_t sz; + + /* extend the range to integral cache lines */ + va = _va & ~(R10K_L1I_LINE - 1); + sz = ((_va + _sz + R10K_L1I_LINE - 1) & ~(R10K_L1I_LINE - 1)) - va; + + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + /* keep only the index bits */ + sva |= va & ((1UL << 14) - 1); + eva = sva + sz; + while (sva != eva) { + cache(IndexInvalidate_I, 0, sva); + cache(IndexInvalidate_I, 1, sva); + sva += R10K_L1I_LINE; + } +} + +/* + * Writeback D$ for the given page. + */ +void +Mips10k_SyncDCachePage(struct cpu_info *ci, vaddr_t va, paddr_t pa) +{ + vaddr_t sva, eva; + + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + /* keep only the index bits */ + sva += va & ((1UL << 14) - 1); + eva = sva + PAGE_SIZE; + while (sva != eva) { + cache(IndexWBInvalidate_D, 0 + 0 * R10K_L1D_LINE, sva); + cache(IndexWBInvalidate_D, 0 + 1 * R10K_L1D_LINE, sva); + cache(IndexWBInvalidate_D, 0 + 2 * R10K_L1D_LINE, sva); + cache(IndexWBInvalidate_D, 0 + 3 * R10K_L1D_LINE, sva); + cache(IndexWBInvalidate_D, 1 + 0 * R10K_L1D_LINE, sva); + cache(IndexWBInvalidate_D, 1 + 1 * R10K_L1D_LINE, sva); + cache(IndexWBInvalidate_D, 1 + 2 * R10K_L1D_LINE, sva); + cache(IndexWBInvalidate_D, 1 + 3 * R10K_L1D_LINE, sva); + sva += 4 * R10K_L1D_LINE; + } +} + +/* + * Writeback D$ for the given range. Range is expected to be currently + * mapped, allowing the use of `Hit' operations. This is less aggressive + * than using `Index' operations. + */ + +void +Mips10k_HitSyncDCache(struct cpu_info *ci, vaddr_t _va, size_t _sz) +{ + vaddr_t va; + vsize_t sz; + + /* extend the range to integral cache lines */ + va = _va & ~(R10K_L1D_LINE - 1); + sz = ((_va + _sz + R10K_L1D_LINE - 1) & ~(R10K_L1D_LINE - 1)) - va; + mips10k_hitwbinv_primary(va, sz); +} + +/* + * Invalidate D$ for the given range. Range is expected to be currently + * mapped, allowing the use of `Hit' operations. This is less aggressive + * than using `Index' operations. + */ + +void +Mips10k_HitInvalidateDCache(struct cpu_info *ci, vaddr_t _va, size_t _sz) +{ + vaddr_t va; + vsize_t sz; + + /* extend the range to integral cache lines */ + va = _va & ~(R10K_L1D_LINE - 1); + sz = ((_va + _sz + R10K_L1D_LINE - 1) & ~(R10K_L1D_LINE - 1)) - va; + mips10k_hitinv_primary(va, sz); +} + +/* + * Backend for bus_dmamap_sync(). Enforce coherency of the given range + * by performing the necessary cache writeback and/or invalidate + * operations. + */ +void +Mips10k_IOSyncDCache(struct cpu_info *ci, vaddr_t _va, size_t _sz, int how) +{ + vaddr_t va; + vsize_t sz; + int partial_start, partial_end; + + /* extend the range to integral L2 cache lines */ + va = _va & ~(64UL - 1); + sz = ((_va + _sz + 64UL - 1) & ~(64UL - 1)) - va; + + switch (how) { + case CACHE_SYNC_R: + /* writeback partial cachelines */ + if (((_va | _sz) & (64UL - 1)) != 0) { + partial_start = va != _va; + partial_end = va + sz != _va + _sz; + } else { + partial_start = partial_end = 0; + } + if (partial_start) { + cache(HitWBInvalidate_S, 0, va); + va += 64UL; + sz -= 64UL; + } + if (sz != 0 && partial_end) { + cache(HitWBInvalidate_S, 0, va + sz - 64UL); + sz -= 64UL; + } + mips10k_hitinv_secondary(va, sz); + break; + case CACHE_SYNC_X: + case CACHE_SYNC_W: + mips10k_hitwbinv_secondary(va, sz); + } +} diff --git a/sys/arch/mips64/mips64/cache_r5k.S b/sys/arch/mips64/mips64/cache_r5k.S deleted file mode 100644 index fd8ed5dca43..00000000000 --- a/sys/arch/mips64/mips64/cache_r5k.S +++ /dev/null @@ -1,923 +0,0 @@ -/* $OpenBSD: cache_r5k.S,v 1.36 2012/04/24 20:06:21 miod Exp $ */ - -/* - * Copyright (c) 1998-2004 Opsycon AB (www.opsycon.se) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -/* - * Processors supported: - * R4600/R4700 (if option CPU_R4600) - * R5000, RM52xx, RM7xxx, RM9xxx - * - * The following assumptions are made: - * - L1 I$ is 2 way, 32 bytes/line - * - L1 D$ is WB, 2 way, 32 bytes/line - * - L2 may not exist - * - L3 may not exist - * - L3 implies internal L2 - * - all external caches are WT - */ - -#include <sys/errno.h> -#include <sys/syscall.h> - -#include <machine/param.h> -#include <machine/asm.h> -#include <machine/cpu.h> -#include <machine/regnum.h> - -#include "assym.h" - - .set mips3 - -/* - * Skip the .h file. Noone else need to know! - */ - -#define IndexInvalidate_I 0x00 -#define IndexWBInvalidate_D 0x01 -#define IndexWBInvalidate_S 0x03 - -#define IndexStoreTag_S 0x0b - -#define HitInvalidate_D 0x11 -#define HitInvalidate_S 0x13 - -#define HitWBInvalidate_D 0x15 -#define InvalidatePage_T 0x16 -#define HitWBInvalidate_S 0x17 -#define InvalidatePage_S 0x17 /* Only RM527[0-1] */ - -/* - * R5000 and RM52xx config register bits. - */ -#define CF_5_SE (1 << 12) /* Secondary cache enable */ -#define CF_5_SC (1 << 17) /* Secondary cache not present */ -#define CF_5_SS (3 << 20) /* Secondary cache size */ -#define CF_5_SS_AL 20 /* Shift to align */ - -/* - * RM7000 config register bits. - */ -#define CF_7_SE (1 << 3) /* Secondary cache enable */ -#define CF_7_SC (1 << 31) /* Secondary cache not present */ -#define CF_7_TE (1 << 12) /* Tertiary cache enable */ -#define CF_7_TC (1 << 17) /* Tertiary cache not present */ -#define CF_7_TS (3 << 20) /* Tertiary cache size */ -#define CF_7_TS_AL 20 /* Shift to align */ - -/* - * Define cache type definition bits. NOTE! the 3 lsb may NOT change! - */ -#define CTYPE_DIR 0x0001 /* Cache is direct mapped */ -#define CTYPE_2WAY 0x0002 /* Cache is TWO way */ -#define CTYPE_4WAY 0x0004 /* Cache is FOUR way */ -#define CTYPE_WAYMASK 0x0007 - -#define CTYPE_HAS_IL2 0x0100 /* Internal L2 Cache present */ -#define CTYPE_HAS_XL2 0x0200 /* External L2 Cache present */ -#define CTYPE_HAS_XL3 0x0400 /* External L3 Cache present */ - -/* - * Due to a flaw in RM7000 1.x processors a pipeline 'drain' is - * required after some mtc0 instructions. - * Ten nops in sequence does the trick. - */ -#define NOP10 nop;nop;nop;nop;nop;\ - nop;nop;nop;nop;nop /* Two cycles for dual issue machine */ - - .set noreorder # Noreorder is default style! - -/*---------------------------------------------------------------------------- - * - * Mips5k_ConfigCache(struct cpu_info *ci) -- - * - * Size and configure the caches. - * NOTE: should only be called from mips_init(). - * - * Side effects: - * The size of the data cache is stored into ci_l1datacachesize. - * The size of instruction cache is stored into ci_l1instcachesize. - * Alignment mask for cache aliasing test is stored in cache_valias_mask. - * ci_l2size is set to the size of the secondary cache. - * ci_l3size is set to the size of the tertiary cache. - * ci_cacheways is set to 0 for direct mapped caches, 2 for two way - * caches and 4 for four way caches. This primarily indicates the - * primary cache associativity. - * - * Allocation: - * ta0, ta1 ta2 used to hold I and D set size and Alias mask. - * - *---------------------------------------------------------------------------- - */ -LEAF(Mips5k_ConfigCache, 0) - .set noreorder - LA v0, 1f - LA v1, CKSEG1_BASE - or v0, v1 - jr v0 # Switch to uncached. - nop -1: - mfc0 v1, COP_0_PRID # read processor ID register - mfc0 v0, COP_0_CONFIG # Get configuration register - - srl t1, v0, 9 # Get I cache size. - and t1, 7 - li t2, 4096 - sllv ta0, t2, t1 # ta0 = Initial I set size. - - and t2, v0, 0x20 - srl t2, 1 # Get I cache line size. - addu t2, 16 - sw t2, CI_L1INSTCACHELINE(a0) - - srl t1, v0, 6 # Get D cache size. - and t1, 7 - li t2, 4096 # Fixed page size. - sllv ta1, t2, t1 - - and t2, v0, 0x10 - addu t2, 16 # Get D cache line size. - sw t2, CI_L1DATACACHELINE(a0) - - li t2, CTYPE_2WAY # Assume two way cache - li ta2, 0 # Secondary size 0. - li ta3, 0 # Tertiary size 0. - - and v1, 0xff00 # Recognize CPU's with - li t1, (MIPS_R5000 << 8) # N way L1 caches only. - beq v1, t1, Conf5K # R5K 2 way, check L2 - li t1, (MIPS_RM52X0 << 8) - beq v1, t1, Conf5K # RM52xx 2 way, check L2 - li t1, (MIPS_RM7000 << 8) - beq v1, t1, Conf7K - li t1, (MIPS_RM9000 << 8) - beq v1, t1, Conf7K - nop - - b ConfResult # R4[67]00 2 way, No L2 control - nop - -#---- R5K ------------------------------ -Conf5K: # R5xxx type, check for L2 cache - and t1, v0, CF_5_SC - bnez t1, ConfResult # not enabled - li ta2, 0 # set size to 0. - - li t3, CF_5_SS - and t1, t3, v0 - beq t1, t3, ConfResult # No L2 cache - srl t1, CF_5_SS_AL - - li t3, CF_5_SE # Set SE in conf - or v0, t3 # Update config register - li ta2, 512*1024 # 512k per 'click'. - sll ta2, t1 - - mtc0 v0, COP_0_CONFIG # Enable L2 cache - or t2, CTYPE_HAS_XL2 # External L2 present. - mtc0 zero, COP_0_TAG_LO # necessary for RM52xx - LOAD_XKPHYS(t0, CCA_CACHED) - PTR_ADDU t1, t0, ta2 -1: - cache InvalidatePage_S, 0(t0) - PTR_ADDU t0, 4096 - bne t0, t1, 1b - nop - - b ConfResult - nop - -#---- RM7K ----------------------------- -Conf7K: # RM7000, check for L2 and L3 cache - li t2, CTYPE_4WAY # 4-way cache - and t1, v0, CF_7_TC - bnez t1, Conf7KL2 # No L3 cache if set - li ta3, 0 # Set size = 0 - -#ifndef L3SZEXT - li t3, CF_7_TS - and t1, t3, v0 - beq t1, t3, Conf7KL2 # No L3 cache - srl t1, CF_7_TS_AL - - or t2, CTYPE_HAS_XL3 # External L2 present. - li t3, CF_7_TE # Set TE in conf - or v0, t3 # Update config register - li ta3, 512*1024 # 512k per 'click'. - sll ta3, t1 -#else - lw ta3, CI_L3SIZE(a0) - and t2, ~CTYPE_HAS_XL3 - beqz ta3, Conf7KL2 # No L3 cache present - nop - - li t3, CF_7_TE # Set SE in conf - or v0, t3 # Update config register - mtc0 v0, COP_0_CONFIG # Enable L3 cache - or t2, CTYPE_HAS_XL3 -#endif - - mtc0 zero, COP_0_TAG_LO - LOAD_XKPHYS(t0, CCA_CACHED) - PTR_ADDU t1, t0, ta3 -1: - cache InvalidatePage_T, 0(t0) - PTR_ADDU t0, 4096 - bne t0, t1, 1b - nop - -Conf7KL2: - and t1, v0, CF_7_SC # check for L2 cache - bnez t1, ConfResult - li ta2, 0 # No L2? - - and t1, v0, CF_7_SE - bnez t1, 3f - ori v0, CF_7_SE - - mtc0 v0, COP_0_CONFIG # Enable and init L2 cache - LOAD_XKPHYS(t0, CCA_CACHED) - PTR_ADDU t1, t0, ta3 -1: - PTR_ADDU t0, 32 - bne t0, t1, 1b - cache IndexStoreTag_S, -4(t0) - sync - - LOAD_XKPHYS(t0, CCA_CACHED) - PTR_ADDU t1, t0, ta3 -1: - PTR_ADDU t0, 32 - bne t0, t1, 1b - lw zero, -4(t0) - sync - - LOAD_XKPHYS(t0, CCA_CACHED) - PTR_ADDU t1, t0, ta3 -1: - PTR_ADDU t0, 32 - bne t0, t1, 1b - cache IndexStoreTag_S, -4(t0) - sync - -3: - or t2, CTYPE_HAS_IL2 # L2 is on chip - b ConfResult - li ta2, 256*1024 # L2 size = 256k - -/* - * Get here with t2 = Cache type, ta0 = L1 I size, ta1 = L1 D size. - * ta2 = secondary size, ta3 = tertiary size. - */ -ConfResult: - sw t2, CI_CACHECONFIGURATION(a0) # Save cache attributes - and t2, CTYPE_WAYMASK # isolate number of sets. - sw t2, CI_CACHEWAYS(a0) - srl t2, 1 # get div shift for set size. - - sw ta2, CI_L2SIZE(a0) - sw ta3, CI_L3SIZE(a0) - - addu t1, ta0, -1 # Use icache for alias mask - srl t1, t2 - srl t1, PAGE_SHIFT - beqz t1, 1f - sll t1, PAGE_SHIFT - or t1, (PAGE_SIZE - 1) -1: - PTR_S t1, cache_valias_mask - PTR_S t1, pmap_prefer_mask - - sw ta0, CI_L1INSTCACHESIZE(a0) # store cache size. - srl ta0, t2 # calculate set size. - sw ta0, CI_L1INSTCACHESET(a0) - - sw ta1, CI_L1DATACACHESIZE(a0) # store cache size. - srl ta1, t2 # calculate set size. - sw ta1, CI_L1DATACACHESET(a0) - - and v0, ~7 - or v0, CCA_CACHED # set cachable writeback kseg0 - mtc0 v0, COP_0_CONFIG # establish any new config - NOP10 - j ra - nop -END(Mips5k_ConfigCache) - -/*---------------------------------------------------------------------------- - * - * Mips5k_SyncCache(struct cpu_info *ci) -- - * - * Sync ALL caches. - * No need to look at number of sets since we are cleaning out - * the entire cache and thus will address all sets anyway. - * - * Side effects: - * The contents of ALL caches are Invalidated or Synched. - * - *---------------------------------------------------------------------------- - */ -LEAF(Mips5k_SyncCache, 0) - .set noreorder - lw t1, CI_L1INSTCACHESIZE(a0) - lw t2, CI_L1DATACACHESIZE(a0) - -/* - * Sync the instruction cache. - */ -#ifdef CPUR4600 - mfc0 v1, COP_0_STATUS_REG # Save the status register. - li v0, SR_DIAG_DE - mtc0 v0, COP_0_STATUS_REG # Disable interrupts -#endif - - LOAD_XKPHYS(t0, CCA_CACHED) - PTR_ADDU t1, t0, t1 # Compute end address - PTR_SUBU t1, 128 - -1: - cache IndexInvalidate_I, 0(t0) - cache IndexInvalidate_I, 32(t0) - cache IndexInvalidate_I, 64(t0) - cache IndexInvalidate_I, 96(t0) - - bne t0, t1, 1b - PTR_ADDU t0, 128 - -/* - * Sync the data cache. Do L1 first. Indexed only operate on - * the selected cache and differs from Hit in that sense. - */ - - LOAD_XKPHYS(t0, CCA_CACHED) - PTR_ADDU t1, t0, t2 # End address - PTR_SUBU t1, 128 -1: - cache IndexWBInvalidate_D, 0(t0) - cache IndexWBInvalidate_D, 32(t0) - cache IndexWBInvalidate_D, 64(t0) - cache IndexWBInvalidate_D, 96(t0) - - bne t0, t1, 1b - PTR_ADDU t0, 128 - -/* Do on chip L2 if present */ - lw t0, CI_CACHECONFIGURATION(a0) - and t0, CTYPE_HAS_IL2 - beqz t0, 20f - nop - -3: - LOAD_XKPHYS(t3, CCA_CACHED) - lw ta0, CI_L2SIZE(a0) -1: - cache IndexWBInvalidate_S, 0(t3) - PTR_SUBU ta0, 32 # Fixed cache line size. - bgtz ta0, 1b - PTR_ADDU t3, 32 - -/* Do off chip L2 if present */ -20: - lw t0, CI_CACHECONFIGURATION(a0) - and t0, CTYPE_HAS_XL2 - beqz t0, 30f - nop - - mtc0 zero, COP_0_TAG_LO - LOAD_XKPHYS(t3, CCA_CACHED) - lw ta0, CI_L2SIZE(a0) -1: - cache InvalidatePage_S, 0(t3) - PTR_SUBU ta0, 4096 # Fixed external cache page size - bgtz ta0, 1b - PTR_ADDU t3, 4096 - -/* Do off chip L3 if present */ -30: - lw t0, CI_CACHECONFIGURATION(a0) - and t0, CTYPE_HAS_XL3 - beqz t0, 99f - nop - - mtc0 zero, COP_0_TAG_LO - LOAD_XKPHYS(t3, CCA_CACHED) - lw ta0, CI_L3SIZE(a0) -1: - cache InvalidatePage_T, 0(t3) - PTR_SUBU ta0, 4096 # Fixed external cache page size - bgtz ta0, 1b - PTR_ADDU t3, 4096 - -99: -#ifdef CPUR4600 - mtc0 v1, COP_0_STATUS_REG # Restore the status register. - NOP10 -#endif - sync - j ra - nop -END(Mips5k_SyncCache) - -/*---------------------------------------------------------------------------- - * - * Mips5k_SyncICache(struct cpu_info *, vaddr_t va, size_t len) - * - * Invalidate the L1 instruction cache for at least range of va to - * va + len - 1. - * - * Side effects: - * The contents of the L1 Instruction cache is flushed. - * - *---------------------------------------------------------------------------- - */ -LEAF(Mips5k_InvalidateICache, 0) -#ifdef CPUR4600 - mfc0 v1, COP_0_STATUS_REG # Save the status register. - li v0, SR_DIAG_DE - mtc0 v0, COP_0_STATUS_REG # Disable interrupts -#endif - lw v0, CI_CACHEWAYS(a0) # Cache properties - lw t0, CI_L1INSTCACHESET(a0) # Set size - dsll a1, (64 - 57) - dsrl a1, (64 - 57) - LOAD_XKPHYS(a3, CCA_CACHED) - PTR_ADDU a2, 31 # Round up size - PTR_ADDU a2, a1 # Add extra from address - dsrl a1, 5 # Align start address - dsll a1, 5 - PTR_SUBU a2, a1 - PTR_ADDU a1, a3 # a1 now new XKPHYS address - dsrl a2, 5 # Number of unrolled loops - addiu v0, -2 # <0 1way, 0 = two, >0 four -1: - bltz v0, 3f - PTR_ADDU a2, -1 - -2: - PTR_ADDU t1, t0, a1 # Nway cache, flush set B. - cache IndexInvalidate_I, 0(t1) - beqz v0, 3f # If two way do set A - PTR_ADDU t1, t0 # else step to set C. - - cache IndexInvalidate_I, 0(t1) - - PTR_ADDU t1, t0 # step to set D - cache IndexInvalidate_I, 0(t1) - -3: - cache IndexInvalidate_I, 0(a1) # do set (A if NWay) - - bnez a2, 1b - PTR_ADDU a1, 32 - -#ifdef CPUR4600 - mtc0 v1, COP_0_STATUS_REG # Restore the status register. - NOP10 -#endif - sync - j ra - nop -END(Mips5k_InvalidateICache) - -/*---------------------------------------------------------------------------- - * - * Mips5k_SyncDCachePage(struct cpu_info *ci, vaddr_t va, paddr_t pa) - * - * Sync the L1 data cache page for address va. - * The physical address is used to compute the L2 index. - * - * Side effects: - * The contents of the cache is written back to primary memory. - * The cache line is invalidated. - * - *---------------------------------------------------------------------------- - */ -LEAF(Mips5k_SyncDCachePage, 0) -#ifdef CPUR4600 - mfc0 v1, COP_0_STATUS_REG # Save the status register. - li v0, SR_DIAG_DE - mtc0 v0, COP_0_STATUS_REG # Disable interrupts -#endif - LOAD_XKPHYS(a3, CCA_CACHED) - lw v0, CI_CACHEWAYS(a0) - dsll a1, (64 - 57) - dsrl a1, (64 - 57) + PAGE_SHIFT - dsll a1, PAGE_SHIFT # Page align start address - PTR_ADDU a1, a3 # a1 now new XKPHYS address - PTR_ADDU a4, a1, PAGE_SIZE-128 - addiu v0, -2 # <0 1way, 0 = two, >0 four - lw a3, CI_L1DATACACHESET(a0) - -1: - bltz v0, 3f - PTR_ADDU t1, a1, a3 - cache IndexWBInvalidate_D, 0(t1) # flush set B. - cache IndexWBInvalidate_D, 32(t1) - cache IndexWBInvalidate_D, 64(t1) - cache IndexWBInvalidate_D, 96(t1) - beqz v0, 3f # two way, skip C and D. - PTR_ADDU t1, a3 - - cache IndexWBInvalidate_D, 0(t1) # do set C - cache IndexWBInvalidate_D, 32(t1) - cache IndexWBInvalidate_D, 64(t1) - cache IndexWBInvalidate_D, 96(t1) - - PTR_ADDU t1, a3 # do set D - cache IndexWBInvalidate_D, 0(t1) - cache IndexWBInvalidate_D, 32(t1) - cache IndexWBInvalidate_D, 64(t1) - cache IndexWBInvalidate_D, 96(t1) -3: - cache IndexWBInvalidate_D, 0(a1) # do set A - cache IndexWBInvalidate_D, 32(a1) - cache IndexWBInvalidate_D, 64(a1) - cache IndexWBInvalidate_D, 96(a1) - - bne a4, a1, 1b - PTR_ADDU a1, 128 - - lw t0, CI_CACHECONFIGURATION(a0) - and t0, CTYPE_HAS_IL2 # Have internal L2? - beqz t0, 9f - - LOAD_XKPHYS(a3, CCA_CACHED) # Yes, do L2 with the physical - dsrl a2, PAGE_SHIFT - dsll a2, PAGE_SHIFT # Page align start address - PTR_ADDU a1, a2, a3 # address for the index - PTR_ADDU a4, a1, PAGE_SIZE-128 - lw a3, CI_L2SIZE(a0) - srl a3, 2 # Hardcoded 4-way - -1: - cache IndexWBInvalidate_S, 0(a1) # do set A - cache IndexWBInvalidate_S, 32(a1) - cache IndexWBInvalidate_S, 64(a1) - cache IndexWBInvalidate_S, 96(a1) - - PTR_ADDU t1, a1, a3 - cache IndexWBInvalidate_S, 0(t1) # do set B. - cache IndexWBInvalidate_S, 32(t1) - cache IndexWBInvalidate_S, 64(t1) - cache IndexWBInvalidate_S, 96(t1) - - PTR_ADDU t1, a3 - cache IndexWBInvalidate_S, 0(t1) # do set C - cache IndexWBInvalidate_S, 32(t1) - cache IndexWBInvalidate_S, 64(t1) - cache IndexWBInvalidate_S, 96(t1) - - PTR_ADDU t1, a3 # do set D - cache IndexWBInvalidate_S, 0(t1) - cache IndexWBInvalidate_S, 32(t1) - cache IndexWBInvalidate_S, 64(t1) - cache IndexWBInvalidate_S, 96(t1) - - bne a4, a1, 1b - PTR_ADDU a1, 128 - -9: -#ifdef CPUR4600 - mtc0 v1, COP_0_STATUS_REG # Restore the status register. -#endif - sync - j ra - nop -END(Mips5k_SyncDCachePage) - -/*---------------------------------------------------------------------------- - * - * Mips5k_HitSyncDCache(struct cpu_info *ci, vaddr_t va, size_t len) - * - * Sync data cache for range of va to va + len - 1. - * Only lines with matching addresses are flushed. - * - * Side effects: - * The contents of the L1 cache is written back to primary memory. - * The cache line is invalidated. - * - * IMPORTANT NOTE: - * Since orphaned L1 cache entries will not be synched it is - * mandatory to pass over the L1 cache once after the L2 is done. - * - *---------------------------------------------------------------------------- - */ -LEAF(Mips5k_HitSyncDCache, 0) -#ifdef CPUR4600 - mfc0 v1, COP_0_STATUS_REG # Save the status register. - li v0, SR_DIAG_DE - mtc0 v0, COP_0_STATUS_REG # Disable interrupts -#endif - beqz a2, 3f # size is zero! - PTR_ADDU a2, 31 # Round up - PTR_ADDU a2, a1 # Add extra from address - dsrl a1, 5 - dsll a1, 5 # align address - PTR_SUBU a2, a1 - dsrl a2, 5 # Compute number of cache lines - -1: - PTR_ADDU a2, -1 - cache HitWBInvalidate_D, 0(a1) - bnez a2, 1b - PTR_ADDU a1, 32 - -3: -#ifdef CPUR4600 - mtc0 v1, COP_0_STATUS_REG # Restore the status register. - NOP10 -#endif - sync - j ra - nop -END(Mips5k_HitSyncDCache) - - -/*---------------------------------------------------------------------------- - * - * _mips5k_HitSyncSCache(struct cpu_info *ci, vaddr_t va, size_t len) - * - * Sync secondary cache for range of va to va + len - 1. - * Only lines with matching addresses are flushed. - * - * Side effects: - * The contents of the L2 cache is written back to primary memory. - * The cache line is invalidated. - * - * IMPORTANT NOTE: - * Since orphaned L1 cache entries will not be synched it is - * mandatory to pass over the L1 cache once after the L2 is done. - * - *---------------------------------------------------------------------------- - */ -ALEAF(_mips5k_HitSyncSCache) -#ifdef CPUR4600 - mfc0 v1, COP_0_STATUS_REG # Save the status register. - li v0, SR_DIAG_DE - mtc0 v0, COP_0_STATUS_REG # Disable interrupts -#endif - - beqz a2, 3f # size is zero! - PTR_ADDU a2, 31 # Round up - PTR_ADDU a2, a1 # Add in extra from align - dsrl a1, 5 - dsll a1, 5 # align address - PTR_SUBU a2, a1 - dsrl a2, 5 # Compute number of cache lines -1: - PTR_ADDU a2, -1 - cache HitWBInvalidate_S, 0(a1) - cache HitWBInvalidate_D, 0(a1) # Orphans in L1 - bnez a2, 1b - PTR_ADDU a1, 32 - -3: -#ifdef CPUR4600 - mtc0 v1, COP_0_STATUS_REG # Restore the status register. - NOP10 -#endif - sync - j ra - nop - -/*---------------------------------------------------------------------------- - * - * Mips5k_HitInvalidateDCache(struct cpu_info *ci, vaddr_t va, size_t len) - * - * Invalidate data cache for range of va to va + len - 1. - * Only lines with matching addresses are invalidated. - * - * Side effects: - * The L1 cache line is invalidated. - * - *---------------------------------------------------------------------------- - */ -LEAF(Mips5k_HitInvalidateDCache, 0) -#ifdef CPUR4600 - mfc0 v1, COP_0_STATUS_REG # Save the status register. - li v0, SR_DIAG_DE - mtc0 v0, COP_0_STATUS_REG # Disable interrupts -#endif - - beqz a2, 3f # size is zero! - PTR_ADDU a2, 31 # Round up - PTR_ADDU a2, a1 # Add in extra from align - dsrl a1, 5 - dsll a1, 5 # align address - PTR_SUBU a2, a1 - dsrl a2, 5 # Compute number of cache lines -1: - PTR_ADDU a2, -1 - cache HitInvalidate_D, 0(a1) - bnez a2, 1b - PTR_ADDU a1, 32 - -3: -#ifdef CPUR4600 - mtc0 v1, COP_0_STATUS_REG # Restore the status register. - NOP10 -#endif - sync - j ra - nop -END(Mips5k_HitInvalidateDCache) - -/*---------------------------------------------------------------------------- - * - * _mips5k_HitInvalidateSCache(struct cpu_info *ci, vaddr_t va, size_t len) - * - * Invalidate secondary cache for range of va to va + len - 1. - * Only lines with matching addresses are invalidated. - * - * Side effects: - * The L2 cache line is invalidated. - * - *---------------------------------------------------------------------------- - */ -ALEAF(_mips5k_HitInvalidateSCache) -#ifdef CPUR4600 - mfc0 v1, COP_0_STATUS_REG # Save the status register. - li v0, SR_DIAG_DE - mtc0 v0, COP_0_STATUS_REG # Disable interrupts -#endif - - beqz a2, 3f # size is zero! - PTR_ADDU a2, 31 # Round up - PTR_ADDU a2, a1 # Add in extra from align - dsrl a1, 5 - dsll a1, 5 # align address - PTR_SUBU a2, a1 - dsrl a2, 5 # Compute number of cache lines -1: - PTR_ADDU a2, -1 - cache HitInvalidate_S, 0(a1) - cache HitInvalidate_D, 0(a1) # Orphans in L1 - bnez a2, 1b - PTR_ADDU a1, 32 - -3: -#ifdef CPUR4600 - mtc0 v1, COP_0_STATUS_REG # Restore the status register. - NOP10 -#endif - sync - j ra - nop - -/*---------------------------------------------------------------------------- - * - * Mips5k_IOSyncDCache(struct cpu_info *ci, vaddr_t va, size_t len, int how) - * - * Invalidate or flush data cache for range of va to va + len - 1. - * - * In case of the existence of an external cache we invalidate pages - * which are in the given range ONLY if transfer direction is READ. - * The assumption here is a 'write through' external cache which is - * true for all now supported processors. - * - * Side effects: - * If how == 0 (read), L1 and on-chip L2 caches are invalidated or - * flushed if the area does not match the alignment requirements. - * Writethrough L2 and L3 cache are invalidated for the address - * range. - * If how == 1 (write), L1 and on-chip L2 caches are written back to - * memory and invalidated. Writethrough L2 and L3 caches are - * left alone. - * If how == 2 (write-read), L1 and on-chip L2 caches are written back - * to memory and invalidated. Writethrough L2 and L3 caches are - * invalidated. - * - *---------------------------------------------------------------------------- - */ -NON_LEAF(Mips5k_IOSyncDCache, FRAMESZ(CF_SZ+2*REGSZ), ra) - PTR_SUBU sp, FRAMESZ(CF_SZ+2*REGSZ) - PTR_S ra, CF_RA_OFFS+2*REGSZ(sp) - REG_S a1, CF_ARGSZ(sp) # save args - REG_S a2, CF_ARGSZ+REGSZ(sp) - beqz a3, SyncRD # Sync PREREAD - lw t0, CI_CACHECONFIGURATION(a0) - - addiu a3, -1 - bnez a3, SyncRDWB # Sync PREWRITE+PREREAD - nop - - and t0, CTYPE_HAS_IL2 # Sync PREWRITE - bnez t0, SyncSC # Have internal L2? - PTR_ADDU sp, FRAMESZ(CF_SZ+2*REGSZ) - j Mips5k_HitSyncDCache # No flush L1. - nop -SyncSC: - j _mips5k_HitSyncSCache # Do internal L2 cache - nop # L1 done in parallel - -SyncRD: - or t1, a1, a2 # check if invalidate possible - and t1, 31 # both address and size must - bnez t1, SyncRDWB # be aligned to the cache size - nop - -/* - * Sync for aligned read, no writeback required. - */ - and t0, CTYPE_HAS_IL2 # Have internal L2? - bnez t0, SyncRDL2 - nop - - jal Mips5k_HitInvalidateDCache # External L2 or no L2. Do L1. - nop - - b SyncRDXL2 - PTR_L ra, CF_RA_OFFS+2*REGSZ(sp) # External L2 if present - -SyncRDL2: - jal _mips5k_HitInvalidateSCache # Internal L2 cache - nop # L1 done in parallel - - b SyncRDL3 - PTR_L ra, CF_RA_OFFS+2*REGSZ(sp) # L3 invalidate if present - -/* - * Sync for unaligned read or write-read. - */ -SyncRDWB: - and t0, CTYPE_HAS_IL2 # Have internal L2? - bnez t0, SyncRDWBL2 # Yes, do L2 - nop - - jal Mips5k_HitSyncDCache - nop - - b SyncRDXL2 - PTR_L ra, CF_RA_OFFS+2*REGSZ(sp) # External L2 if present - -SyncRDWBL2: - jal _mips5k_HitSyncSCache # Internal L2 cache - nop # L1 done in parallel - - b SyncRDL3 - PTR_L ra, CF_RA_OFFS+2*REGSZ(sp) # L3 invalidate if present - -SyncRDXL2: - lw t0, CI_CACHECONFIGURATION(a0) - and t0, CTYPE_HAS_XL2 # Have external L2? - beqz t0, SyncRDL3 # Nope. - REG_L a1, CF_ARGSZ(sp) - REG_L a2, CF_ARGSZ+REGSZ(sp) - and a3, a1, 4095 # align on external page size - mtc0 zero, COP_0_TAG_LO - PTR_SUBU a1, a3 - PTR_ADDU a2, a3 -1: - blez a2, SyncDone - PTR_SUBU a2, 4096 # Fixed external cache page size - - cache InvalidatePage_S, 0(a1) - b 1b - PTR_ADDU a1, 4096 - -SyncRDL3: - lw t0, CI_CACHECONFIGURATION(a0) - and t0, CTYPE_HAS_XL3 # Have L3? - beqz t0, SyncDone # Nope. - REG_L a1, CF_ARGSZ(sp) - REG_L a2, CF_ARGSZ+REGSZ(sp) - and a3, a1, 4095 # align on external page size - mtc0 zero, COP_0_TAG_LO - PTR_SUBU a1, a3 - PTR_ADDU a2, a3 -1: - blez a2, SyncDone - PTR_SUBU a2, 4096 # Fixed external cache page size - - cache InvalidatePage_T, 0(a1) - b 1b - PTR_ADDU a1, 4096 - -SyncDone: - sync - j ra - PTR_ADDU sp, FRAMESZ(CF_SZ+2*REGSZ) -END(Mips5k_IOSyncDCache) diff --git a/sys/arch/mips64/mips64/cache_r5k.c b/sys/arch/mips64/mips64/cache_r5k.c new file mode 100644 index 00000000000..f0c28fe499e --- /dev/null +++ b/sys/arch/mips64/mips64/cache_r5k.c @@ -0,0 +1,842 @@ +/* $OpenBSD: cache_r5k.c,v 1.1 2012/06/23 21:56:06 miod Exp $ */ + +/* + * Copyright (c) 2012 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Copyright (c) 1998-2004 Opsycon AB (www.opsycon.se) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* + * Cache handling for R5000 processor and close relatives: + * R4600/R4700, R5000, RM52xx, RM7xxx, RM9xxx. + * + * The following assumptions are made: + * - L1 I$ is 2-way or 4-way (RM7k/RM9k), VIPT, 32 bytes/line, up to 32KB + * - L1 D$ is 2-way or 4-way (RM7k/RM9k), VIPT, write-back, 32 bytes/line, + * up to 32KB + * - `internal' L2 on RM7k/RM9k is 4-way, PIPT, write-back, 32 bytes/line, + * 256KB total + * - L3 (on RM7k/RM9k) or `external' L2 (all others) may not exist. If it + * does, it is direct-mapped, PIPT, write-through + */ + +#include <sys/param.h> +#include <sys/systm.h> + +#include <mips64/cache.h> +#include <machine/cpu.h> + +#include <uvm/uvm_extern.h> + +#define IndexInvalidate_I 0x00 +#define IndexWBInvalidate_D 0x01 +#define IndexWBInvalidate_S 0x03 + +#define IndexStoreTag_S 0x0b + +#define HitInvalidate_D 0x11 +#define HitInvalidate_S 0x13 + +#define HitWBInvalidate_D 0x15 +#define InvalidatePage_T 0x16 /* Only RM7k/RM9k */ +#define HitWBInvalidate_S 0x17 +#define InvalidatePage_S 0x17 /* Only RM527[0-1] */ + +/* + * R5000 and RM52xx config register bits. + */ +#define CF_5_SE (1 << 12) /* Secondary cache enable */ +#define CF_5_SC (1 << 17) /* Secondary cache not present */ +#define CF_5_SS (3 << 20) /* Secondary cache size */ +#define CF_5_SS_AL 20 /* Shift to align */ + +/* + * RM7000 config register bits. + */ +#define CF_7_SE (1 << 3) /* Secondary cache enable */ +#define CF_7_SC (1 << 31) /* Secondary cache not present */ +#define CF_7_TE (1 << 12) /* Tertiary cache enable */ +#define CF_7_TC (1 << 17) /* Tertiary cache not present */ +#define CF_7_TS (3 << 20) /* Tertiary cache size */ +#define CF_7_TS_AL 20 /* Shift to align */ + + +#define R5K_LINE 32UL /* internal cache line */ +#define R5K_PAGE 4096UL /* external cache page */ + + +/* + * Cache configuration + */ +#define CTYPE_HAS_IL2 0x01 /* Internal L2 Cache present */ +#define CTYPE_HAS_XL2 0x02 /* External L2 Cache present */ +#define CTYPE_HAS_XL3 0x04 /* External L3 Cache present */ + +#define nop4() __asm__ __volatile__ \ + ("nop; nop; nop; nop") +#define nop10() __asm__ __volatile__ \ + ("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop") + +#define cache(op,offs,addr) __asm__ __volatile__ \ + ("cache %0, %1(%2)" :: "i"(op), "i"(offs), "r"(addr) : "memory") + +#define sync() __asm__ __volatile__ ("sync" ::: "memory") + +#define reset_taglo() __asm__ __volatile__ \ + ("mtc0 $zero, $28") /* COP_0_TAG_LO */ + +static __inline__ uint32_t +get_config(void) +{ + uint32_t cfg; + __asm__ __volatile__ ("mfc0 %0, $16" : "=r"(cfg)); /* COP_0_CONFIG */ + return cfg; +} + +static __inline__ void +set_config(uint32_t cfg) +{ + __asm__ __volatile__ ("mtc0 %0, $16" :: "r"(cfg)); /* COP_0_CONFIG */ + /* ITLBNOPFIX */ +#ifdef CPU_RM7000 + nop10(); +#else + nop4(); +#endif +} + +static __inline__ void mips5k_hitinv_primary(vaddr_t, vsize_t); +static __inline__ void mips5k_hitinv_secondary(vaddr_t, vsize_t); +static __inline__ void mips5k_hitwbinv_primary(vaddr_t, vsize_t); +static __inline__ void mips5k_hitwbinv_secondary(vaddr_t, vsize_t); + +void mips5k_l2_init(uint32_t); +void mips7k_l2_init(uint32_t); +void mips7k_l3_init(uint32_t); +static void run_uncached(void (*)(uint32_t), uint32_t); + +/* + * Invoke a simple routine from uncached space (either CKSEG1 or uncached + * XKPHYS). + */ + +static void +run_uncached(void (*fn)(uint32_t), uint32_t arg) +{ + vaddr_t va; + paddr_t pa; + + va = (vaddr_t)fn; + if (IS_XKPHYS(va)) { + pa = XKPHYS_TO_PHYS(va); + va = PHYS_TO_XKPHYS(pa, CCA_NC); + } else { + pa = CKSEG0_TO_PHYS(va); + va = PHYS_TO_CKSEG1(pa); + } + fn = (void (*)(uint32_t))va; + + (*fn)(arg); +} + + +/* + * Initialize the external L2 cache of an R5000 (or close relative) processor. + * INTENDED TO BE RUN UNCACHED - BE SURE TO CHECK THAT IT WON'T STORE ANYTHING + * ON THE STACK IN THE ASSEMBLY OUTPUT EVERYTIME YOU CHANGE IT. + */ +void +mips5k_l2_init(uint32_t l2size) +{ + register vaddr_t va, eva; + register uint32_t cfg; + + cfg = get_config(); + cfg |= CF_5_SE; + set_config(cfg); + + reset_taglo(); + + va = PHYS_TO_XKPHYS(0, CCA_CACHED); + eva = va + l2size; + while (va != eva) { + cache(InvalidatePage_S, 0, va); + va += R5K_PAGE; + } +} + +/* + * Initialize the internal L2 cache of an RM7000 (or close relative) processor. + * INTENDED TO BE RUN UNCACHED - BE SURE TO CHECK THAT IT WON'T STORE ANYTHING + * ON THE STACK IN THE ASSEMBLY OUTPUT EVERYTIME YOU CHANGE IT. + */ +void +mips7k_l2_init(uint32_t l2size) +{ + register vaddr_t va, eva; + register uint32_t cfg; + + cfg = get_config(); + cfg |= CF_7_SE; + set_config(cfg); + + reset_taglo(); + + va = PHYS_TO_XKPHYS(0, CCA_CACHED); + eva = va + l2size; + while (va != eva) { + va += R5K_LINE; + cache(IndexStoreTag_S, -4, va); + } + sync(); + + va = PHYS_TO_XKPHYS(0, CCA_CACHED); + eva = va + l2size; + while (va != eva) { + va += R5K_LINE; + __asm__ __volatile__ + ("lw $zero, %0(%1)" :: "i"(-4), "r"(va)); + } + sync(); + + va = PHYS_TO_XKPHYS(0, CCA_CACHED); + eva = va + l2size; + while (va != eva) { + va += R5K_LINE; + cache(IndexStoreTag_S, -4, va); + } + sync(); +} + +/* + * Initialize the external L3 cache of an RM7000 (or close relative) processor. + * INTENDED TO BE RUN UNCACHED - BE SURE TO CHECK THAT IT WON'T STORE ANYTHING + * ON THE STACK IN THE ASSEMBLY OUTPUT EVERYTIME YOU CHANGE IT. + */ +void +mips7k_l3_init(uint32_t l3size) +{ + register vaddr_t va, eva; + register uint32_t cfg; + + cfg = get_config(); + cfg |= CF_7_TE; + set_config(cfg); + + reset_taglo(); + + va = PHYS_TO_XKPHYS(0, CCA_CACHED); + eva = va + l3size; + while (va != eva) { + cache(InvalidatePage_T, 0, va); + va += R5K_PAGE; + } +} + +/* + * Discover cache configuration and update cpu_info accordingly. + * Initialize L2 and L3 caches found if necessary. + */ +void +Mips5k_ConfigCache(struct cpu_info *ci) +{ + uint32_t cfg, ncfg; + uint setshift; + + cfg = cp0_get_config(); + + /* L1 cache */ + ci->ci_l1instcacheline = R5K_LINE; + ci->ci_l1instcachesize = (1 << 12) << ((cfg >> 9) & 0x07); /* IC */ + ci->ci_l1datacacheline = R5K_LINE; + ci->ci_l1datacachesize = (1 << 12) << ((cfg >> 6) & 0x07); /* DC */ + + /* sane defaults */ + ci->ci_cacheways = 2; + setshift = 1; + ci->ci_l2line = 0; + ci->ci_l2size = 0; + ci->ci_l3size = 0; + ci->ci_cacheconfiguration = 0; + + switch ((cp0_get_prid() >> 8) & 0xff) { + default: + /* shouldn't happen, really; but we can't panic here */ + break; +#ifdef CPU_R4600 + case MIPS_R4600: + case MIPS_R4700: + /* no external L2 interface */ + break; +#endif +#ifdef CPU_R5000 + case MIPS_R5000: + case MIPS_RM52X0: + /* optional external L2 cache */ + if ((cfg & CF_5_SC) == 0) { + ci->ci_l2line = R5K_LINE; + ci->ci_l2size = (1 << 19) << + ((cfg & CF_5_SS) >> CF_5_SS_AL); + } + if (ci->ci_l2size != 0) { + ci->ci_cacheconfiguration |= CTYPE_HAS_XL2; + cfg |= CF_5_SE; + run_uncached(mips5k_l2_init, ci->ci_l2size); + } + break; +#endif /* CPU_R5000 */ +#ifdef CPU_RM7000 + case MIPS_RM7000: + case MIPS_RM9000: + ci->ci_cacheways = 4; + setshift = 2; + /* optional external L3 cache */ + if ((cfg & CF_7_TC) == 0) { +#ifndef L3SZEXT + /* + * Assume L3 size is provided in the system information + * field of the Config register. This is usually the + * case on systems where the RM7k/RM9k processor is + * an upgrade from an R5000/RM52xx processor, such as + * the SGI O2. + */ + ci->ci_l3size = (1 << 19) << + ((cfg & CF_7_TS) >> CF_7_TS_AL); +#else + /* + * Assume machdep has initialized ci_l3size for us. + */ +#endif + } + if (ci->ci_l3size != 0) { + ci->ci_cacheconfiguration |= CTYPE_HAS_XL3; + cfg |= CF_7_TE; + run_uncached(mips7k_l3_init, ci->ci_l3size); + } + /* internal L2 cache */ + if ((cfg & CF_7_SC) == 0) { + ci->ci_l2line = R5K_LINE; + ci->ci_l2size = 256 * 1024; /* fixed size */ + } + if (ci->ci_l2size != 0) { + ci->ci_cacheconfiguration |= CTYPE_HAS_IL2; + if ((cfg & CF_7_SE) == 0) { + cfg |= CF_7_SE; + run_uncached(mips7k_l2_init, ci->ci_l2size); + } + } + break; +#endif /* CPU_RM7000 */ + } + + ci->ci_l1instcacheset = ci->ci_l1instcachesize >> setshift; + ci->ci_l1datacacheset = ci->ci_l1datacachesize >> setshift; + + cache_valias_mask = + (max(ci->ci_l1instcacheset, ci->ci_l1datacacheset) - 1) & + ~PAGE_MASK; + + if (cache_valias_mask != 0) { + cache_valias_mask |= PAGE_MASK; + pmap_prefer_mask = cache_valias_mask; + } + + ncfg = (cfg & ~7) | CCA_CACHED; + if (cfg != ncfg) + run_uncached(cp0_set_config, ncfg); +} + +/* + * Writeback and invalidate all caches. + */ +void +Mips5k_SyncCache(struct cpu_info *ci) +{ + vaddr_t sva, eva; +#ifdef CPU_R4600 + /* + * Revision 1 R4600 need to perform `Index' cache operations with + * interrupt disabled, to make sure both ways are correctly updated. + */ + uint32_t sr = disableintr(); +#endif + + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + eva = sva + ci->ci_l1instcachesize; + while (sva != eva) { + cache(IndexInvalidate_I, 0, sva); + sva += R5K_LINE; + } + + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + eva = sva + ci->ci_l1datacachesize; + while (sva != eva) { + cache(IndexWBInvalidate_D, 0, sva); + sva += R5K_LINE; + } + +#ifdef CPU_R4600 + setsr(sr); +#endif + +#ifdef CPU_RM7000 + if (ci->ci_cacheconfiguration & CTYPE_HAS_IL2) { + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + eva = sva + ci->ci_l2size; + while (sva != eva) { + cache(IndexWBInvalidate_S, 0, sva); + sva += R5K_LINE; + } + } else +#endif +#ifdef CPU_R5000 + if (ci->ci_cacheconfiguration & CTYPE_HAS_XL2) { + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + eva = sva + ci->ci_l2size; + reset_taglo(); + while (sva != eva) { + cache(InvalidatePage_S, 0, sva); + sva += R5K_PAGE; + } + } else +#endif + { + } + +#ifdef CPU_RM7000 + if (ci->ci_cacheconfiguration & CTYPE_HAS_XL3) { + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + eva = sva + ci->ci_l3size; + reset_taglo(); + while (sva != eva) { + cache(InvalidatePage_T, 0, sva); + sva += R5K_PAGE; + } + } +#endif + + sync(); +} + +/* + * Invalidate I$ for the given range. + */ +void +Mips5k_InvalidateICache(struct cpu_info *ci, vaddr_t _va, size_t _sz) +{ + vaddr_t va, sva, eva, iva; + vsize_t sz, offs; +#ifdef CPU_R4600 + /* + * Revision 1 R4600 need to perform `Index' cache operations with + * interrupt disabled, to make sure both ways are correctly updated. + */ + uint32_t sr = disableintr(); +#endif + + /* extend the range to integral cache lines */ + va = _va & ~(R5K_LINE - 1); + sz = ((_va + _sz + R5K_LINE - 1) & ~(R5K_LINE - 1)) - va; + + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + offs = ci->ci_l1instcacheset; + /* keep only the index bits */ + sva |= va & (offs - 1); + eva = sva + sz; + + switch (ci->ci_cacheways) { + default: +#ifdef CPU_RM7000 + case 4: + while (sva != eva) { + iva = sva; + cache(IndexInvalidate_I, 0, iva); + iva += offs; + cache(IndexInvalidate_I, 0, iva); + iva += offs; + cache(IndexInvalidate_I, 0, iva); + iva += offs; + cache(IndexInvalidate_I, 0, iva); + sva += R5K_LINE; + } + break; +#endif +#if defined(CPU_R5000) || defined(CPU_R4600) + case 2: + iva = sva + offs; + while (sva != eva) { + cache(IndexInvalidate_I, 0, iva); + cache(IndexInvalidate_I, 0, sva); + iva += R5K_LINE; + sva += R5K_LINE; + } + break; +#endif + } + +#ifdef CPU_R4600 + setsr(sr); +#endif + sync(); +} + +/* + * Writeback D$ for the given page. + */ +void +Mips5k_SyncDCachePage(struct cpu_info *ci, vaddr_t va, paddr_t pa) +{ + vaddr_t sva, eva, iva; + vsize_t offs; +#ifdef CPU_R4600 + /* + * Revision 1 R4600 need to perform `Index' cache operations with + * interrupt disabled, to make sure both ways are correctly updated. + */ + uint32_t sr = disableintr(); +#endif + + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + offs = ci->ci_l1datacacheset; + /* keep only the index bits */ + sva |= va & (offs - 1); + eva = sva + PAGE_SIZE; + + switch (ci->ci_cacheways) { + default: +#ifdef CPU_RM7000 + case 4: + while (sva != eva) { + iva = sva; + cache(IndexWBInvalidate_D, 0, iva); + iva += offs; + cache(IndexWBInvalidate_D, 0, iva); + iva += offs; + cache(IndexWBInvalidate_D, 0, iva); + iva += offs; + cache(IndexWBInvalidate_D, 0, iva); + sva += R5K_LINE; + } + break; +#endif +#if defined(CPU_R5000) || defined(CPU_R4600) + case 2: + iva = sva + offs; + while (sva != eva) { + cache(IndexWBInvalidate_D, 0, iva); + cache(IndexWBInvalidate_D, 0, sva); + iva += R5K_LINE; + sva += R5K_LINE; + } + break; +#endif + } + +#ifdef CPU_R4600 + setsr(sr); +#endif + +#ifdef CPU_RM7000 + if (ci->ci_cacheconfiguration & CTYPE_HAS_IL2) { + sva = PHYS_TO_XKPHYS(pa, CCA_CACHED); + offs = ci->ci_l2size / 4; /* hardcoded 4 way */ + eva = sva + PAGE_SIZE; + while (sva != eva) { + iva = sva; + cache(IndexWBInvalidate_S, 0, iva); + iva += offs; + cache(IndexWBInvalidate_S, 0, iva); + iva += offs; + cache(IndexWBInvalidate_S, 0, iva); + iva += offs; + cache(IndexWBInvalidate_S, 0, iva); + sva += R5K_LINE; + } + } +#endif + + sync(); +} + +/* + * Writeback D$ for the given range. Range is expected to be currently + * mapped, allowing the use of `Hit' operations. This is less aggressive + * than using `Index' operations. + */ + +static __inline__ void +mips5k_hitwbinv_primary(vaddr_t va, vsize_t sz) +{ + vaddr_t eva; + + eva = va + sz; + while (va != eva) { + cache(HitWBInvalidate_D, 0, va); + va += R5K_LINE; + } +} + +static __inline__ void +mips5k_hitwbinv_secondary(vaddr_t va, vsize_t sz) +{ + vaddr_t eva; + + eva = va + sz; + while (va != eva) { + cache(HitWBInvalidate_S, 0, va); + cache(HitWBInvalidate_D, 0, va); /* orphans in L1 */ + va += R5K_LINE; + } +} + +void +Mips5k_HitSyncDCache(struct cpu_info *ci, vaddr_t _va, size_t _sz) +{ + vaddr_t va; + vsize_t sz; + + /* extend the range to integral cache lines */ + va = _va & ~(R5K_LINE - 1); + sz = ((_va + _sz + R5K_LINE - 1) & ~(R5K_LINE - 1)) - va; + +#if 0 + if (ci->ci_cacheconfiguration & CTYPE_HAS_IL2) + mips5k_hitwbinv_secondary(va, sz); + else +#endif + { +#ifdef CPU_R4600 + /* + * R4600 revision 2 needs to load from an uncached address + * before any Hit or CreateDEX operation. Alternatively, 12 + * nop (cycles) will empty the cache load buffer. + * We are only putting 10 here, and hope the overhead of the + * code around will provide the rest. + */ + nop10(); +#endif + mips5k_hitwbinv_primary(va, sz); + } + + sync(); +} + +/* + * Invalidate D$ for the given range. Range is expected to be currently + * mapped, allowing the use of `Hit' operations. This is less aggressive + * than using `Index' operations. + */ + +static __inline__ void +mips5k_hitinv_primary(vaddr_t va, vsize_t sz) +{ + vaddr_t eva; + + eva = va + sz; + while (va != eva) { + cache(HitInvalidate_D, 0, va); + va += R5K_LINE; + } +} + +static __inline__ void +mips5k_hitinv_secondary(vaddr_t va, vsize_t sz) +{ + vaddr_t eva; + + eva = va + sz; + while (va != eva) { + cache(HitInvalidate_S, 0, va); + cache(HitInvalidate_D, 0, va); /* orphans in L1 */ + va += R5K_LINE; + } +} + +void +Mips5k_HitInvalidateDCache(struct cpu_info *ci, vaddr_t _va, size_t _sz) +{ + vaddr_t va; + vsize_t sz; + + /* extend the range to integral cache lines */ + va = _va & ~(R5K_LINE - 1); + sz = ((_va + _sz + R5K_LINE - 1) & ~(R5K_LINE - 1)) - va; + +#if 0 + if (ci->ci_cacheconfiguration & CTYPE_HAS_IL2) + mips5k_hitinv_secondary(va, sz); + else +#endif + { +#ifdef CPU_R4600 + /* + * R4600 revision 2 needs to load from an uncached address + * before any Hit or CreateDEX operation. Alternatively, 12 + * nop (cycles) will empty the cache load buffer. + * We are only putting 10 here, and hope the overhead of the + * code around will provide the rest. + */ + nop10(); +#endif + mips5k_hitinv_primary(va, sz); + } + + sync(); +} + +/* + * Backend for bus_dmamap_sync(). Enforce coherency of the given range + * by performing the necessary cache writeback and/or invalidate + * operations. + */ +void +Mips5k_IOSyncDCache(struct cpu_info *ci, vaddr_t _va, size_t _sz, int how) +{ + vaddr_t va; + vsize_t sz; + int partial_start, partial_end; + + /* + * internal cache + */ + + /* extend the range to integral cache lines */ + va = _va & ~(R5K_LINE - 1); + sz = ((_va + _sz + R5K_LINE - 1) & ~(R5K_LINE - 1)) - va; + +#ifdef CPU_R4600 + /* + * R4600 revision 2 needs to load from an uncached address + * before any Hit or CreateDEX operation. Alternatively, 12 + * nop (cycles) will empty the cache load buffer. + * We are only putting 10 here, and hope the overhead of the + * code around will provide the rest. + */ + nop10(); +#endif + + switch (how) { + case CACHE_SYNC_R: + /* writeback partial cachelines */ + if (((_va | _sz) & (R5K_LINE - 1)) != 0) { + partial_start = va != _va; + partial_end = va + sz != _va + _sz; + } else { + partial_start = partial_end = 0; + } + if (partial_start) { +#ifdef CPU_RM7000 + if (ci->ci_cacheconfiguration & CTYPE_HAS_IL2) + cache(HitWBInvalidate_S, 0, va); +#endif + cache(HitWBInvalidate_D, 0, va); + va += R5K_LINE; + sz -= R5K_LINE; + } + if (sz != 0 && partial_end) { + sz -= R5K_LINE; +#ifdef CPU_RM7000 + if (ci->ci_cacheconfiguration & CTYPE_HAS_IL2) + cache(HitWBInvalidate_S, 0, va + sz); +#endif + cache(HitWBInvalidate_D, 0, va + sz); + } + + if (sz != 0) { +#ifdef CPU_RM7000 + if (ci->ci_cacheconfiguration & CTYPE_HAS_IL2) + mips5k_hitinv_secondary(va, sz); + else +#endif + mips5k_hitinv_primary(va, sz); + } + break; + + case CACHE_SYNC_X: + case CACHE_SYNC_W: +#ifdef CPU_RM7000 + if (ci->ci_cacheconfiguration & CTYPE_HAS_IL2) + mips5k_hitwbinv_secondary(va, sz); + else +#endif + mips5k_hitwbinv_primary(va, sz); + break; + } + + /* + * external cache + */ + + switch (how) { + case CACHE_SYNC_W: + break; + case CACHE_SYNC_X: + case CACHE_SYNC_R: +#ifdef CPU_R5000 + if (ci->ci_cacheconfiguration & CTYPE_HAS_XL2) { + /* align on external page size */ + va = _va & ~(R5K_PAGE - 1); + sz = ((_va + _sz + R5K_PAGE - 1) - va) / R5K_PAGE; + reset_taglo(); + while (sz != 0) { + cache(InvalidatePage_S, 0, va); + va += R5K_PAGE; + sz--; + } + } else +#endif +#ifdef CPU_RM7000 + if (ci->ci_cacheconfiguration & CTYPE_HAS_XL3) { + /* align on external page size */ + va = _va & ~(R5K_PAGE - 1); + sz = ((_va + _sz + R5K_PAGE - 1) - va) / R5K_PAGE; + reset_taglo(); + while (sz != 0) { + cache(InvalidatePage_T, 0, va); + va += R5K_PAGE; + sz--; + } + } else +#endif + { + } + break; + } + + sync(); +} |