4246 lines
96 KiB
ArmAsm
4246 lines
96 KiB
ArmAsm
/**************************************************************************
|
|
* *
|
|
* Copyright (C) 1989, Silicon Graphics, Inc. *
|
|
* *
|
|
* These coded instructions, statements, and computer programs contain *
|
|
* unpublished proprietary information of Silicon Graphics, Inc., and *
|
|
* are protected by Federal copyright law. They may not be disclosed *
|
|
* to third parties or copied or duplicated in any form, in whole or *
|
|
* in part, without the prior written consent of Silicon Graphics, Inc. *
|
|
* *
|
|
**************************************************************************/
|
|
|
|
#ident "$Revision: 1.118 $"
|
|
|
|
#include "ml/ml.h"
|
|
#if IP19
|
|
#include "sys/EVEREST/evmp.h" /* Needed for MPCONF definitions */
|
|
#include "sys/loaddrs.h"
|
|
#endif
|
|
|
|
/*
|
|
* _R4600SC_LAZY is defined to assure that a0 and a1
|
|
* are unmodified in all of the code paths which result in a branch to
|
|
* _r4600sc_index_inval() or _r4600sc_inval_cache(). During this time
|
|
* the original values of a0 and a1 will be stored in a2 and a3 and the
|
|
* called routines will expect their two arguments to be passed in a2
|
|
* and a3.
|
|
*/
|
|
/* #define _R4600SC_LAZY */
|
|
/* #define R4600SC_STATS */
|
|
|
|
/*
|
|
* Cache flushing, cache sizing routines.
|
|
*
|
|
* The globals icache_size, dcache_size no longer refer to
|
|
* the size of the primary i/d caches, but are the size
|
|
* of the largest cache that must be written back/invalidated:
|
|
* e.g. clean_dcache(K0BASE, dcache_size) for IP17 needs to refer
|
|
* to the size of the 2nd cache. The same call for IP6 needs refer
|
|
* to the size of the primary dcache. This allows code in other
|
|
* directories to just use icache_size, dcache_size.
|
|
*
|
|
* Sizes of specific caches are computed and stored in variables such
|
|
* as picache_size, boot_sdcache_size etc. These sizes are used in the
|
|
* add_to_inventory() calls
|
|
*/
|
|
|
|
|
|
|
|
#if R4000 || R10000
|
|
|
|
#if IP19 || IP20 || IP22 || IP25 || IP27 || IP28 || IP30 || IP32 || IPMHSIM
|
|
#if R10000 && (IP32 || IPMHSIM)
|
|
#define SCACHE_LINESIZE (16*4)
|
|
#define SCACHE_LINEMASK ((16*4)-1)
|
|
#else /* R10000 && (IP32 || IPMHSIM) */
|
|
#ifndef SCACHE_LINESIZE
|
|
#define SCACHE_LINESIZE (32*4)
|
|
#endif
|
|
#ifndef SCACHE_LINEMASK
|
|
#define SCACHE_LINEMASK ((32*4)-1)
|
|
#endif
|
|
#endif /* R10000 && (IP32 || IPMHSIM) */
|
|
|
|
#ifdef BLOCKSIZE_8WORDS
|
|
#define DCACHE_LINESIZE (8*4)
|
|
#define ICACHE_LINESIZE (8*4)
|
|
#define DCACHE_LINEMASK ((8*4)-1)
|
|
#define ICACHE_LINEMASK ((8*4)-1)
|
|
#elif R10000
|
|
#define DCACHE_LINESIZE (8*4)
|
|
#define ICACHE_LINESIZE (16*4)
|
|
#define DCACHE_LINEMASK ((8*4)-1)
|
|
#define ICACHE_LINEMASK ((16*4)-1)
|
|
#else
|
|
#define DCACHE_LINESIZE (4*4)
|
|
#define ICACHE_LINESIZE (4*4)
|
|
#define DCACHE_LINEMASK ((4*4)-1)
|
|
#define ICACHE_LINEMASK ((4*4)-1)
|
|
#endif /* BLOCKSIZE_8WORDS */
|
|
|
|
#ifdef R4600
|
|
#define R4600_DCACHE_LINESIZE (8*4)
|
|
#define R4600_ICACHE_LINESIZE (8*4)
|
|
#define R4600_DCACHE_LINEMASK ((8*4)-1)
|
|
#define R4600_ICACHE_LINEMASK ((8*4)-1)
|
|
#endif /* R4600 */
|
|
|
|
#ifdef R4600SC
|
|
#define R4600_SCACHE_LINESIZE (8*4)
|
|
#define R4600_SCACHE_LINEMASK ((8*4)-1)
|
|
#define R4600_CCC_BASE 0x80000000
|
|
#define R4600_PHYSMASK 0x1fffffff # convert k0 & k1 to physical
|
|
#define R4600_SCACHE_SIZE 0x80000
|
|
#define XKPHYS_UNCACHED_BASE 0x9000
|
|
#define XKPHYS_UNCACHED_SHIFT 0x20
|
|
#define EEROM 0xbfa00034 # stolen from sys/mc.h
|
|
#define CACHESZ_REG 0x11 # where the size is stored
|
|
#endif
|
|
|
|
#else
|
|
#define SCACHE_LINEMASK 0
|
|
#endif /* IP19 || IP20 || IP22 || IP25 || IP28 || IP30 || IP32 || IPMHSIM */
|
|
|
|
#if IP20 || IP22 || IP28 || IP30 || IP32 || IPMHSIM
|
|
#define K0_CACHEFLUSHBASE K0_RAMBASE
|
|
#else
|
|
#define K0_CACHEFLUSHBASE K0BASE
|
|
#endif
|
|
|
|
#ifdef R4600SC
|
|
/*
|
|
* _r4600sc_disable_cache()
|
|
*
|
|
* disable the secondary cache on an R4600SC
|
|
* returns 0 if the cache was not previously disabled, 1 if it was.
|
|
*
|
|
* NB: since this code might be called from the ECC exception handler
|
|
* it may run either cached or uncached. Because of this we extract
|
|
* the virtual address space selector bits from the return address
|
|
* and or them into the virtual address space selector bits of any
|
|
* addresses which we must access in order to ensure that we do not
|
|
* touch the caches if we are running in kseg1.
|
|
*/
|
|
LEAF(_r4600sc_disable_scache)
|
|
li a0,0
|
|
#if _MIPS_SIM != _ABI64
|
|
lui a1,0xE000
|
|
#else
|
|
LI a1,0xf800000000000000 # assume not in compat space (hack)
|
|
#endif
|
|
and a1,ra # a1 now contains the VAS selector bits
|
|
#ifdef TRITON
|
|
.set noreorder
|
|
mfc0 t2,C0_PRID
|
|
NOP_0_4
|
|
.set reorder
|
|
andi t2,C0_IMPMASK
|
|
subu t2,(C0_IMP_TRITON << C0_IMPSHIFT)
|
|
beqz t2,4f
|
|
subu t2,((C0_IMP_RM5271 << C0_IMPSHIFT) - (C0_IMP_TRITON << C0_IMPSHIFT))
|
|
bnez t2,5f
|
|
4:
|
|
|
|
.set noreorder
|
|
mfc0 t2,C0_CONFIG
|
|
NOP_0_4
|
|
#ifdef TRITON_INDYSC
|
|
and t1,t2,CONFIG_TR_SC
|
|
bnez t1,5f
|
|
nop # BDSLOT
|
|
#endif /* TRITON_INDYSC */
|
|
and t2,~CONFIG_TR_SE
|
|
mtc0 t2,C0_CONFIG
|
|
NOP_0_4
|
|
.set reorder
|
|
b 6f
|
|
5:
|
|
#endif /* TRITON */
|
|
#if IP22
|
|
LA v0,_r4600sc_cache_index
|
|
or v0,a1 # make sure we call in same seg we came
|
|
# from (could be kseg0 or kseg1)
|
|
.set noreorder
|
|
jalr t9,v0
|
|
nop
|
|
mfc0 t0,C0_SR
|
|
nop
|
|
#if _MIPS_SIM != _ABI64
|
|
mtc0 zero,C0_SR
|
|
#else
|
|
and ta0,t0,SR_KX
|
|
mtc0 ta0,C0_SR
|
|
#endif
|
|
LI a2,K1BASE
|
|
beql a1,a2,1f
|
|
li t1,SR_KX # BDSLOT
|
|
LA t1,1f
|
|
cache CACH_PI|C_FILL, 0(t1)
|
|
nop
|
|
cache CACH_PI|C_FILL, 32(t1)
|
|
j 1f
|
|
li t1,SR_KX
|
|
nop
|
|
1:
|
|
.align 6
|
|
mtc0 t1,C0_SR
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
sh zero, 0(v0)
|
|
#if _MIPS_SIM != _ABI64
|
|
mtc0 zero,C0_SR
|
|
#endif
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
mtc0 t0,C0_SR
|
|
nop
|
|
.set reorder
|
|
#endif /* IP22 */
|
|
6:
|
|
LA a0,_r4600sc_scache_disabled
|
|
or a0,a1
|
|
lw v0, 0(a0)
|
|
li t0,1
|
|
sw t0,0(a0)
|
|
j ra
|
|
END(_r4600sc_disable_scache)
|
|
|
|
#ifdef _MEM_PARITY_WAR
|
|
LEAF(_r4600sc_disable_scache_erl)
|
|
li a0,0
|
|
#if _MIPS_SIM != _ABI64
|
|
lui a1,0xE000
|
|
#else
|
|
LI a1,0xf800000000000000 # assume not in compat space (hack)
|
|
#endif
|
|
and a1,ra # a1 now contains the VAS selector bits
|
|
LA v0,_r4600sc_cache_index
|
|
or v0,a1 # make sure we call in same seg we came
|
|
# from (could be kseg0 or kseg1)
|
|
.set noreorder
|
|
jalr t9,v0
|
|
nop
|
|
mfc0 t0,C0_SR
|
|
nop
|
|
or t1,t0,SR_KX
|
|
mtc0 t1,C0_SR
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
sh zero, 0(v0)
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
mtc0 t0,C0_SR
|
|
nop
|
|
.set reorder
|
|
lw v0,_r4600sc_scache_disabled
|
|
li t0,1
|
|
sw t0,_r4600sc_scache_disabled
|
|
j ra
|
|
END(_r4600sc_disable_scache_erl)
|
|
#endif /* _MEM_PARITY_WAR */
|
|
|
|
/*
|
|
* _r4600sc_enable_cache()
|
|
*
|
|
* enable and invalidate the secondary cache on an R4600SC
|
|
*
|
|
* NB: since this code might be called from the ECC exception handler
|
|
* it may run either cached or uncached. Because of this we extract
|
|
* the virtual address space selector bits from the return address
|
|
* and or them into the virtual address space selector bits of any
|
|
* addresses which we must access in order to ensure that we do not
|
|
* touch the caches if we are running in kseg1.
|
|
*/
|
|
LEAF(_r4600sc_enable_scache)
|
|
li a0,0
|
|
#if _MIPS_SIM != _ABI64
|
|
lui a1,0xE000
|
|
#else
|
|
LI a1,0xf800000000000000 # assume not in compat space (hack)
|
|
#endif
|
|
and a1,ra # a1 now contains the VAS selector bits
|
|
#ifdef TRITON
|
|
.set noreorder
|
|
mfc0 t2,C0_PRID
|
|
NOP_0_4
|
|
.set reorder
|
|
andi t2,C0_IMPMASK
|
|
subu t2,(C0_IMP_TRITON << C0_IMPSHIFT)
|
|
beqz t2,4f
|
|
subu t2,((C0_IMP_RM5271 << C0_IMPSHIFT) - (C0_IMP_TRITON << C0_IMPSHIFT))
|
|
bnez t2,5f
|
|
4:
|
|
|
|
.set noreorder
|
|
mfc0 t2,C0_CONFIG
|
|
NOP_0_4
|
|
.set reorder
|
|
#ifdef TRITON_INDYSC
|
|
and ta0,t2,CONFIG_TR_SC
|
|
bnez ta0,5f
|
|
#endif /* TRITON_INDYSC *//
|
|
lw v1,boot_sidcache_size
|
|
LA ta0,K0BASE
|
|
and t3,t2,CONFIG_TR_SE
|
|
bnez t3,6f
|
|
or t2,CONFIG_TR_SE
|
|
LA v0,11f
|
|
or v0,SEXT_K1BASE
|
|
LA t9,6f
|
|
or t9,a1 # stay in same segment on return
|
|
j v0 # be sure we are uncached
|
|
|
|
.set noreorder
|
|
11:
|
|
mfc0 ta1,C0_SR # ensure that interrupts are
|
|
nop # disabled if SR_ERL is not set
|
|
and t3,ta1,SR_ERL
|
|
bnez t3,111f
|
|
nop
|
|
mtc0 zero,C0_SR
|
|
111:
|
|
lw t3,_triton_use_invall # CACH_SD|C_INVALL available?
|
|
bnez t3,12f # --> CACH_SD|C_INVALL is available
|
|
mtc0 t2,C0_CONFIG # enable scache
|
|
nop
|
|
mfc0 ta2,C0_TAGLO
|
|
NOP_0_4
|
|
mtc0 zero,C0_TAGLO
|
|
add v1,ta0
|
|
add ta0,0x1000
|
|
13:
|
|
cache CACH_SD|C_INVPAGE,-0x1000(ta0)
|
|
bne ta0,v1,13b
|
|
add ta0,0x1000
|
|
mtc0 ta2,C0_TAGLO
|
|
b 14f
|
|
nop
|
|
|
|
12:
|
|
NOP_0_4
|
|
cache CACH_SD|C_INVALL,0(ta0) # invalidate scache
|
|
14:
|
|
and t3,ta1,SR_ERL # restore interrupts if we
|
|
bnez t3,141f # disabled them earlier
|
|
nop
|
|
mtc0 ta1,C0_SR # with interrupts restored
|
|
141:
|
|
j t9 # back to previous space
|
|
nop
|
|
.set reorder
|
|
|
|
5:
|
|
#endif /* TRITON */
|
|
#if IP22
|
|
LA v0,_r4600sc_cache_index
|
|
or v0,a1 # make sure we call in same seg we came
|
|
# from (could be kseg0 or kseg1)
|
|
.set noreorder
|
|
jalr t9,v0
|
|
nop
|
|
mfc0 t0,C0_SR
|
|
nop
|
|
#if _MIPS_SIM != _ABI64
|
|
mtc0 zero,C0_SR
|
|
#else
|
|
li ta0,SR_KX
|
|
mtc0 ta0,C0_SR
|
|
#endif
|
|
LI a2,K1BASE
|
|
beql a1,a2,1f
|
|
li t1,SR_KX # BDSLOT
|
|
LA t1,1f
|
|
cache CACH_PI|C_FILL, 0(t1)
|
|
nop
|
|
cache CACH_PI|C_FILL, 32(t1)
|
|
j 1f
|
|
li t1,SR_KX
|
|
nop
|
|
1:
|
|
.align 6
|
|
mtc0 t1,C0_SR
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
sb zero, 0(v0)
|
|
#if _MIPS_SIM != _ABI64
|
|
mtc0 zero,C0_SR
|
|
#endif
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
mtc0 t0,C0_SR
|
|
nop
|
|
.set reorder
|
|
#endif /* IP22 */
|
|
6:
|
|
LA a0,_r4600sc_scache_disabled
|
|
or a0,a1
|
|
sw zero, 0(a0)
|
|
j ra
|
|
END(_r4600sc_enable_scache)
|
|
|
|
#ifdef _MEM_PARITY_WAR
|
|
LEAF(_r4600sc_enable_scache_erl)
|
|
li a0,0
|
|
#if _MIPS_SIM != _ABI64
|
|
lui a1,0xE000
|
|
#else
|
|
LI a1,0xf800000000000000 # assume not in compat space (hack)
|
|
#endif
|
|
|
|
and a1,ra # a1 now contains the VAS selector bits
|
|
LA v0,_r4600sc_cache_index
|
|
or v0,a1 # make sure we call in same seg we came
|
|
# from (could be kseg0 or kseg1)
|
|
.set noreorder
|
|
jalr t9,v0
|
|
nop
|
|
mfc0 t0,C0_SR
|
|
nop
|
|
or t1,t0,SR_KX
|
|
mtc0 t1,C0_SR
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
sb zero, 0(v0)
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
mtc0 t0,C0_SR
|
|
nop
|
|
.set reorder
|
|
lw v0,_r4600sc_scache_disabled
|
|
sw zero,_r4600sc_scache_disabled
|
|
j ra
|
|
END(_r4600sc_enable_scache_erl)
|
|
#endif /* _MEM_PARITY_WAR */
|
|
|
|
/*
|
|
* _r4600sc_vtop(vaddr)
|
|
*
|
|
* a0 has the virtual address on which we wish to do the translation
|
|
* on return v0 contains the 32 bit physical address we will use.
|
|
* t9 contains the return address
|
|
* XXX: this routine should always be called w/interrupts disabled.
|
|
*/
|
|
LEAF(_r4600sc_vtop)
|
|
sll ta1,a0,1
|
|
bgez a0,3f # bit 31 == 0 --> KUSEG use TLB
|
|
bltz ta1,3f # bit 30 == 0 --> K2SEG use TLB
|
|
|
|
# this address is in unmapped space
|
|
# get rid of the va selector bits 29-31
|
|
sll v0,a0,3
|
|
srl v0,v0,3
|
|
j t9 # to complete the translation
|
|
|
|
.set noreorder
|
|
3: dmfc0 ta3,C0_TLBHI # save current pid
|
|
.set reorder
|
|
and ta2,ta3,TLBHI_PIDMASK
|
|
|
|
dsrl32 ta1,ta3,8 # get rid of the old VPN
|
|
dsll32 ta1,8
|
|
|
|
and t3,a0,TLBHI_VPNMASK # chop any offset bits from vaddr
|
|
or v0,ta1,ta2 # vpn/pid ready for entryhi
|
|
or v0,t3,v0
|
|
|
|
.set noreorder
|
|
dmtc0 v0,C0_TLBHI # vpn and pid of new entry
|
|
nop # tlbhi get through pipe
|
|
c0 C0_PROBE
|
|
nop
|
|
mfc0 t3,C0_INX
|
|
nop # wait for t3 to be filled
|
|
bltz t3,1f # not found
|
|
li v0,-1 # BDSLOT
|
|
|
|
c0 C0_READI # read slot
|
|
nop
|
|
srl t8,a0,BPCSHIFT # even or odd page?
|
|
andi ta2,t8,1
|
|
bnez ta2,2f
|
|
|
|
dmfc0 v0, C0_TLBLO_0 # even page, get EntryLo0
|
|
j 3f
|
|
nop
|
|
|
|
2: dmfc0 v0, C0_TLBLO_1 # odd page, get EntryLo1
|
|
nop
|
|
.set reorder
|
|
|
|
3: dsrl v0, 6 # strip off EntryLo bits
|
|
dsll v0, 12 # shift to align for offset
|
|
li t3, 0xFFF # mask for page offset
|
|
and t3, a0, t3 # get the page offset from vaddr
|
|
or v0, t3 # add in the offset bits
|
|
|
|
.set noreorder
|
|
1: dmtc0 ta3,C0_TLBHI # restore TLBPID
|
|
j t9
|
|
nop # BDSLOT
|
|
.set reorder
|
|
END(_r4600sc_vtop)
|
|
|
|
/*
|
|
* _r4600sc_cache_index(paddr)
|
|
*
|
|
* calculate the address to write to flush the line containing
|
|
* the physical address "paddr".
|
|
* note that since bits 4:0 are ignored, the index is contained
|
|
* in bits 18:5
|
|
*
|
|
* The CCC only looks at bits 18:5 when determining which line to
|
|
* invalidate, so we don't have to extract the index bits from
|
|
* the address here -- the hardware is nice to us.
|
|
*/
|
|
LEAF(_r4600sc_cache_index)
|
|
li ta3,0x1 # create R4600_CCC_BASE
|
|
dsll ta3,31 # ...
|
|
or v0,a0,ta3 # physical address to write
|
|
|
|
lui ta3,XKPHYS_UNCACHED_BASE
|
|
dsll32 ta3,XKPHYS_UNCACHED_SHIFT-0x20 # create 64 bit base address
|
|
or v0,ta3 # xkphys address to write
|
|
j t9
|
|
END(_r4600sc_cache_index)
|
|
|
|
/*
|
|
* _r4600sc_limit(current, end)
|
|
* current -- the next address to be operated on
|
|
* end -- the ending address for this entire set of
|
|
* cache operations.
|
|
*
|
|
* on exit v0 contains the page offset in bytes which is the
|
|
* limit for the next chunk of invalidates.
|
|
*
|
|
* if (current page == end page)
|
|
* // we will do the rest in a singe operation
|
|
* v0 = (end address - current address)
|
|
* else
|
|
* // we will do lines up to the end of the current page
|
|
* v0 = ((current address + NBPP) & 0xFFFFF000) - current address
|
|
* v0 &= 0xFFFFFFE0
|
|
*/
|
|
LEAF(_r4600sc_limit)
|
|
srl v0,a0,BPCSHIFT
|
|
srl v1,a1,BPCSHIFT
|
|
bne v0,v1,1f # are both addresses on the same page?
|
|
PTR_SUBU v0,a1,a0 # yes --> use remaining count
|
|
and v0, ~R4600_SCACHE_LINEMASK
|
|
j t9 # return the count
|
|
|
|
1: PTR_ADDU v0,a0,NBPP # get count to end of page
|
|
srl v0,BPCSHIFT
|
|
sll v0,BPCSHIFT # get rid of offset bits
|
|
PTR_SUBU v0,v0,a0 # count to end of page
|
|
and v0,~R4600_SCACHE_LINEMASK
|
|
j t9
|
|
END(_r4600sc_limit)
|
|
|
|
/*
|
|
* _r4600sc_inval_cache(void)
|
|
*
|
|
* invalidate the entire secondary cache if the request is the same size
|
|
* as the secondary cache or larger -- otherwise do a line by line invalidate.
|
|
*/
|
|
LEAF(_r4600sc_inval_cache)
|
|
lw t0,VPDA_PSCACHESIZE(zero)
|
|
beqz t0,99f # no secondary cache, --> exit
|
|
|
|
#ifdef _R4600SC_LAZY
|
|
move a1,a3 # a1 is the length of this request
|
|
#endif
|
|
|
|
bltu a1,t0,_r4600sc_index_inval
|
|
|
|
#
|
|
# check to see if the cache is disabled, if so
|
|
# we don't want to do anything since the sb in
|
|
# this routine would have the effect of turning
|
|
# on the scache.
|
|
#
|
|
lw t0,_r4600sc_scache_disabled
|
|
bnez t0,99f
|
|
|
|
#ifdef TRITON
|
|
.set noreorder
|
|
mfc0 t2,C0_PRID
|
|
NOP_0_4
|
|
.set reorder
|
|
andi t2,C0_IMPMASK
|
|
subu t2,(C0_IMP_TRITON << C0_IMPSHIFT)
|
|
beqz t2,4f
|
|
subu t2,((C0_IMP_RM5271 << C0_IMPSHIFT) - (C0_IMP_TRITON << C0_IMPSHIFT))
|
|
bnez t2,5f
|
|
4:
|
|
|
|
#ifdef TRITON_INDYSC
|
|
.set noreorder
|
|
mfc0 t2,C0_CONFIG
|
|
NOP_0_4
|
|
.set reorder
|
|
and v1,t2,CONFIG_TR_SC
|
|
bnez v1,5f
|
|
#endif /* TRITON_INDYSC */
|
|
lw t3,_triton_use_invall # CACH_SD|C_INVALL available?
|
|
LA t2,K0BASE
|
|
bnez t3,12f # --> CACH_SD|C_INVALL is available
|
|
lw v1,boot_sidcache_size
|
|
add v1,t2
|
|
add t2,0x1000
|
|
.set noreorder
|
|
mfc0 t1,C0_SR
|
|
nop
|
|
mtc0 zero,C0_SR
|
|
nop
|
|
mfc0 t3,C0_TAGLO
|
|
nop
|
|
mtc0 zero,C0_TAGLO
|
|
NOP_0_4
|
|
13:
|
|
cache CACH_SD|C_INVPAGE,-0x1000(t2)
|
|
bne t2,v1,13b
|
|
add t2,0x1000
|
|
mtc0 t3,C0_TAGLO
|
|
b 99f
|
|
mtc0 t1,C0_SR
|
|
.set reorder
|
|
|
|
12:
|
|
.set noreorder
|
|
cache CACH_SD|C_INVALL,0(t2)
|
|
.set reorder
|
|
b 99f
|
|
5:
|
|
#endif /* TRITON */
|
|
#if IP22
|
|
.set noreorder
|
|
mfc0 ta0,C0_SR
|
|
nop
|
|
#if _MIPS_SIM != _ABI64
|
|
mtc0 zero,C0_SR
|
|
#else
|
|
li ta0,SR_KX
|
|
mtc0 ta0,C0_SR
|
|
#endif
|
|
.set reorder
|
|
#ifdef R4600SC_STATS
|
|
lw t0,_r4600sc_nuke
|
|
addu t0,1
|
|
sw t0,_r4600sc_nuke
|
|
#endif
|
|
li a0,0
|
|
LA v0,_r4600sc_cache_index
|
|
jalr t9,v0 # get xkphys address to write
|
|
|
|
.set noreorder
|
|
LA t9,1f # fill icache to try and prevent
|
|
cache CACH_PI|C_FILL,0(t9) # taking exceptions while in
|
|
nop # KX mode
|
|
cache CACH_PI|C_FILL,32(t9)
|
|
nop
|
|
j 1f
|
|
li t9,SR_KX
|
|
.align 6
|
|
1: mtc0 t9,C0_SR
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
sb zero, 0(v0)
|
|
#if _MIPS_SIM != _ABI64
|
|
mtc0 zero,C0_SR
|
|
#endif
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
mtc0 ta0, C0_SR
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
.set reorder
|
|
#endif /* IP22 */
|
|
99:
|
|
j ra
|
|
END(_r4600sc_inval_cache)
|
|
|
|
/*
|
|
* _r4600sc_index_inval(addr, len)
|
|
*
|
|
* arguments arrive in a2 and a3 if _R4600SC_LAZY is defined.
|
|
*
|
|
* register usage:
|
|
* a0 -- starting address and argument passing
|
|
* a1 -- length and argument passing
|
|
* a2 -- value of SR_KX bit
|
|
* a3 -- scratch
|
|
* t0 -- virtual starting address (used to get xlation)
|
|
* t1 -- virtual ending address
|
|
* t2 -- saved value of C0_SR
|
|
* t3 -- scratch (used by _r4600sc_vtop as scratch)
|
|
* ta0 -- scratch
|
|
* ta1 -- scratch (used by subroutines)
|
|
* ta2 -- scratch (used by subroutines)
|
|
* ta3 -- scratch (used by subroutines)
|
|
* t8 -- scratch (used by subroutines)
|
|
* t9 -- return address for subroutine calls
|
|
* v0 -- address to call & function return values
|
|
* v0 -- function return values
|
|
*
|
|
* XXX: if the length to be invalidated is a multiple of the linesize
|
|
* then an extra line is invalidated -- we will check for this
|
|
* condition and decrement the length by the linesize to prevent
|
|
* the extra line from being invalidated.
|
|
*/
|
|
LEAF(_r4600sc_index_inval)
|
|
lw t0,VPDA_PSCACHESIZE(zero)
|
|
beqz t0,99f
|
|
|
|
lw t2,_r4600sc_scache_disabled
|
|
bnez t2,99f
|
|
|
|
#ifdef _R4600SC_LAZY
|
|
move a0,a2
|
|
move a1,a3
|
|
#endif
|
|
|
|
#ifdef TRITON
|
|
.set noreorder
|
|
mfc0 t2,C0_PRID
|
|
NOP_0_4
|
|
.set reorder
|
|
andi t2,C0_IMPMASK
|
|
subu t2,(C0_IMP_TRITON << C0_IMPSHIFT)
|
|
beqz t2,4f
|
|
subu t2,((C0_IMP_RM5271 << C0_IMPSHIFT) - (C0_IMP_TRITON << C0_IMPSHIFT))
|
|
bnez t2,5f
|
|
4:
|
|
|
|
#ifdef TRITON_INDYSC
|
|
.set noreorder
|
|
mfc0 t2,C0_CONFIG
|
|
NOP_0_4
|
|
.set reorder
|
|
and t0,t2,CONFIG_TR_SC
|
|
bnez t0,5f
|
|
#endif /* TRITON_INDYSC */
|
|
sltu t2, t0, a1 # size > scache_size?
|
|
bnez t2, 6f # yes-->invalidate all
|
|
move t0,a1
|
|
addu t0,a0
|
|
move t1,a0
|
|
li t3,(0x1000>>1)
|
|
sltu t2, t3, a1 # size > 1/2 page size?
|
|
bnez t2, 9f # yes-->invalidate page
|
|
and t1,~0x1F
|
|
addu t0,0x1F
|
|
and t0,~0x1F
|
|
addu t1,0x20
|
|
bgtu t1,t0,99f
|
|
.set noreorder
|
|
mfc0 ta1,C0_SR
|
|
nop
|
|
mtc0 zero,C0_SR
|
|
nop
|
|
mfc0 ta2,C0_TAGLO
|
|
NOP_0_4
|
|
mtc0 zero,C0_TAGLO
|
|
8:
|
|
cache CACH_SD|C_IST,-0x20(t1)
|
|
bne t1,t0,8b
|
|
addu t1,0x20
|
|
mtc0 ta2,C0_TAGLO
|
|
b 99f
|
|
mtc0 ta1,C0_SR
|
|
.set reorder
|
|
9:
|
|
and t1,~0xFFF
|
|
addu t0,0xFFF
|
|
and t0,~0xFFF
|
|
addu t1,0x1000
|
|
bgtu t1,t0,99f
|
|
|
|
.set noreorder
|
|
mfc0 ta1,C0_SR
|
|
nop
|
|
mtc0 zero,C0_SR
|
|
nop
|
|
mfc0 ta2,C0_TAGLO
|
|
NOP_0_4
|
|
mtc0 zero,C0_TAGLO
|
|
NOP_0_4
|
|
7:
|
|
cache CACH_SD|C_INVPAGE,-0x1000(t1)
|
|
bne t1,t0,7b
|
|
addu t1,0x1000
|
|
mtc0 ta2,C0_TAGLO
|
|
b 99f
|
|
mtc0 ta1,C0_SR
|
|
.set reorder
|
|
6:
|
|
lw t3,_triton_use_invall # CACH_SD|C_INVALL available?
|
|
LA t1,K0BASE
|
|
bnez t3,12f # --> CACH_SD|C_INVALL is available
|
|
lw v1,boot_sidcache_size
|
|
add v1,t1
|
|
add t1,0x1000
|
|
.set noreorder
|
|
mfc0 ta1,C0_SR
|
|
nop
|
|
mtc0 zero,C0_SR
|
|
nop
|
|
mfc0 ta2,C0_TAGLO
|
|
NOP_0_4
|
|
mtc0 zero,C0_TAGLO
|
|
13:
|
|
cache CACH_SD|C_INVPAGE,-0x1000(t1)
|
|
bne t1,v1,13b
|
|
add t1,0x1000
|
|
mtc0 ta2,C0_TAGLO
|
|
b 99f
|
|
mtc0 ta1,C0_SR
|
|
.set reorder
|
|
|
|
12:
|
|
.set noreorder
|
|
cache CACH_SD|C_INVALL,0(t1)
|
|
.set reorder
|
|
b 99f
|
|
5:
|
|
#endif /* TRITON */
|
|
#if IP22
|
|
#ifdef R4600SC_STATS
|
|
#
|
|
# we are going to collect some stats here for
|
|
# analyzing performance of this routine.
|
|
# we want counts of the following:
|
|
# counts over a page
|
|
# counts under a page
|
|
# start + len cross a page -- len < 0x1000.
|
|
# mapped starting addresses
|
|
# unmapped starting addresses
|
|
# mapped addresses whose ending address is in a different page
|
|
#
|
|
li t2,0
|
|
.set noreorder
|
|
mfc0 t3,C0_SR
|
|
nop
|
|
#if _MIPS_SIM != _ABI64
|
|
mtc0 zero,C0_SR
|
|
#else
|
|
li t0,SR_KX
|
|
mtc0 t0,C0_SR
|
|
#endif
|
|
.set reorder
|
|
bgtu a1,0x1000,10f
|
|
lw t0,_r4600sc_short
|
|
addu t0,1
|
|
PTR_ADDU t1,a0,a1
|
|
srl v0,a0,BPCSHIFT
|
|
srl v1,t1,BPCSHIFT
|
|
bne v0,v1,1f # are both addresses on the same page?
|
|
sw t0,_r4600sc_short
|
|
j 100f
|
|
|
|
1: lw t0,_r4600sc_cross
|
|
addu t0,1
|
|
sw t0,_r4600sc_cross
|
|
addu t2,1
|
|
j 100f
|
|
|
|
10: lw t0,_r4600sc_long
|
|
addu t0,1
|
|
sw t0,_r4600sc_long
|
|
addu t2,1
|
|
|
|
100: sll ta1,a0,1
|
|
bgez a0,3f # bit 31 == 0 --> KUSEG use TLB
|
|
bltz ta1,3f # bit 30 == 0 --> K2SEG use TLB
|
|
|
|
lw t0,_r4600sc_unmapped
|
|
addu t0,1
|
|
sw t0,_r4600sc_unmapped
|
|
j 1f
|
|
|
|
3: lw t0,_r4600sc_mapped
|
|
addu t0,1
|
|
sw t0,_r4600sc_mapped
|
|
beqz t2,1f
|
|
lw t0,_r4600sc_mandc
|
|
addu t0,1
|
|
sw t0,_r4600sc_mandc
|
|
|
|
.set noreorder
|
|
1: mtc0 t3,C0_SR
|
|
nop
|
|
.set reorder
|
|
#endif /* R4600SC_STATS */
|
|
|
|
and t0,a0,~R4600_SCACHE_LINEMASK
|
|
addu t1,a0,a1
|
|
and t3,t1,~R4600_SCACHE_LINEMASK
|
|
|
|
beq t3,t1,1f # is the ending address cache line aligned?
|
|
|
|
#
|
|
# no --> round up to the start of the first cache line which
|
|
# should *not* be invalidated.
|
|
#
|
|
PTR_ADDU t1,t3,R4600_SCACHE_LINESIZE
|
|
|
|
1:
|
|
li a2,SR_KX
|
|
.set noreorder
|
|
mfc0 t2,C0_SR
|
|
nop
|
|
|
|
10:
|
|
nop # CP0 hazard for mfc0 at end of loop
|
|
mtc0 zero,C0_SR # turn off interrupts
|
|
move a0,t0 # start address for next inner loop
|
|
cache CACH_PD|C_ILT,0(t0) # force an address translation
|
|
.set reorder # w/o doing anything to the line
|
|
|
|
LA v0,_r4600sc_vtop # get the virtual -> physical
|
|
# translation for this address
|
|
jalr t9,v0
|
|
move a3,v0 # save physical address
|
|
|
|
move a1,t1 # limit for entire operation
|
|
LA v0,_r4600sc_limit # get limit (byte count) for the
|
|
jalr t9,v0 # inner loop in this interation of
|
|
# the outer loop
|
|
|
|
move v1,v0 # save the count
|
|
move a0,a3 # get physical address
|
|
move a3,v1 # save the count again
|
|
LA v0,_r4600sc_cache_index # get the address in xkphys
|
|
jalr t9,v0 # to write to
|
|
#
|
|
# calculate limit address in xkphys
|
|
# we decrement the ending address by R4600_SCACHE_LINESIZE
|
|
# to ensure that the inner loop will execute only the specified
|
|
# number of times. In order for this to work, register t1 --
|
|
# the ending address -- must point to the first line *not* to
|
|
# be invalidated.
|
|
#
|
|
daddu v1,v0
|
|
dsubu v1,R4600_SCACHE_LINESIZE
|
|
|
|
#
|
|
# v0 --> starting xkphys address
|
|
# v1 --> ending xkphys address
|
|
# t0 --> starting virtual address
|
|
# t1 --> ending virtual address
|
|
# a3 --> count of bytes done in this iteration
|
|
#
|
|
# we now need to prepare for the change to 64 bit addressing
|
|
# mode by filling the cache with the code to be executed with
|
|
# KX addressing mode turned on.
|
|
#
|
|
LA t3,1f
|
|
.set noreorder
|
|
cache CACH_PI|C_FILL, 0(t3)
|
|
cache CACH_PI|C_FILL, 32(t3)
|
|
j 1f
|
|
nop
|
|
.align 6
|
|
1: mtc0 a2,C0_SR # put the CPU in 64 bit mode
|
|
nop # we should play with the number
|
|
2: sw zero, 0(v0) # invalidate the line
|
|
bltu v0,v1,2b
|
|
daddu v0,R4600_SCACHE_LINESIZE
|
|
mtc0 zero,C0_SR # leave 64 bit mode
|
|
nop
|
|
PTR_ADDU t0,a3 # we've done this much
|
|
#
|
|
# XXX: could this be changed to a "bne t0,t1,10b"?
|
|
#
|
|
bltu t0,t1,10b # are we done?
|
|
mtc0 t2,C0_SR
|
|
.set reorder
|
|
#endif /* IP22 */
|
|
99:
|
|
j ra
|
|
END(_r4600sc_index_inval)
|
|
#endif /* R4600SC */
|
|
|
|
#if !IP25
|
|
/*
|
|
* __dcache_inval(addr, len)
|
|
* invalidate data cache for range of physical addr to addr+len-1
|
|
*
|
|
* We use the HIT_INVALIDATE cache op. Therefore, this requires
|
|
* that 'addr'..'len' be the actual addresses which we want to
|
|
* invalidate in the caches.
|
|
* addr/len are not necessarily cache line aligned. Any lines
|
|
* partially covered by addr/len are written out with the
|
|
* HIT_WRITEBACK_INVALIDATE op.
|
|
*
|
|
* Invalidate lines in both the primary and secondary cache.
|
|
*
|
|
* XXX Assumes 32 word line size for secondary cache.
|
|
* XXX Assumes 32 byte line size for primary data cache.
|
|
* XXX Assumes 4 primary lines per secondary line
|
|
* XXX Assumes that primary linesize == secondary linesize for 4600SC
|
|
*/
|
|
|
|
LEAF(__dcache_inval)
|
|
#ifdef IP20
|
|
lw t0,mc_rev_level
|
|
bne t0,zero,1f
|
|
j rmi_cacheflush
|
|
1:
|
|
#endif
|
|
|
|
#ifdef defined(R4600SC) && defined(_R4600SC_LAZY)
|
|
move a2,a0
|
|
move a3,a1
|
|
#endif
|
|
blez a1,41f # if length <= 0, we are done
|
|
lw ta3,VPDA_PSCACHESIZE(zero)
|
|
#ifdef R4000PC
|
|
beqz ta3,99f # no scache--do primary only
|
|
#endif
|
|
|
|
#ifdef R4600SC
|
|
lw t0, two_set_pcaches # are we on a 4600SC?
|
|
bnez t0, 99f
|
|
#endif
|
|
|
|
sltu t2, ta3, a1 # size > scache_size?
|
|
bnez t2, 102f # yes --> use indexed invalidate
|
|
|
|
move t0,a0
|
|
PTR_ADDU t1,a0,a1 # ending address + 1
|
|
bgeu t0,t1,3f # paranoid
|
|
PTR_SUBU t1,SCACHE_LINESIZE
|
|
|
|
# check and align starting and ending addresses.
|
|
and t2,t0,SCACHE_LINEMASK
|
|
beq t2,zero,1f # starting addr is aligned
|
|
|
|
# align the address to the start of the line
|
|
PTR_SUBU t0,t2
|
|
|
|
# 'hit writeback invalidate' the secondary line indicated
|
|
# by 'addr'. This also does writeback/invalidates in the primary
|
|
# I and D caches as necessary.
|
|
.set noreorder
|
|
cache CACH_SD|C_HWBINV,0(t0) # writeback + inval
|
|
|
|
bgeu t0,t1,3f # Out if we are done
|
|
# align addr to the next line
|
|
PTR_ADDU t0,SCACHE_LINESIZE # BDSLOT
|
|
1:
|
|
# check if ending address is cache-line aligned.
|
|
and t2,t1,SCACHE_LINEMASK
|
|
beq t2,zero,1f # ending address is full cache line
|
|
PTR_SUBU t1,t2 # BDSLOT align to start of line
|
|
cache CACH_SD|C_HWBINV,SCACHE_LINESIZE(t1) # writeback + inval
|
|
PTR_ADDU t1,1
|
|
bgeu t0,t1,3f
|
|
nop # BDSLOT
|
|
|
|
1: # top of loop
|
|
cache CACH_SD|C_HINV,0(t0) # invalidate secondary and primary
|
|
|
|
bltu t0,t1,1b
|
|
PTR_ADDU t0,SCACHE_LINESIZE # BDSLOT
|
|
.set reorder
|
|
3:
|
|
#ifdef R4600SC_DEBUG
|
|
lw t9, _r4600sc_2nd_flush_error
|
|
or t9, 1
|
|
sw t9, _r4600sc_2nd_flush_error
|
|
#endif
|
|
|
|
#ifdef MH_R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,VPDA_PSCACHESIZE(zero)
|
|
.set reorder
|
|
#elif R10000 && !R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,-SCACHE_LINESIZE(t0)
|
|
.set reorder
|
|
#ifdef HEART_COHERENCY_WAR /* ensure flush to memory */
|
|
ld zero,PHYS_TO_COMPATK1(HEART_SYNC)
|
|
#endif
|
|
#endif
|
|
|
|
j ra
|
|
|
|
/* clean scache using index invalidate */
|
|
102: LI t0, K0_CACHEFLUSHBASE # set up current address
|
|
#ifdef R10000
|
|
srl ta3,1 # cache is 2 way set associative
|
|
#endif
|
|
PTR_ADDU t1, t0, ta3 # set up limit address
|
|
PTR_SUBU t1, SCACHE_LINESIZE # (base + scache_size - scache_linesize)
|
|
|
|
.set noreorder
|
|
3: cache CACH_SD|C_IWBINV, 0(t0) # Invalidate cache line
|
|
#ifdef R10000
|
|
cache CACH_SD|C_IWBINV, 1(t0) # Invalidate cache line (way 1)
|
|
#endif
|
|
bltu t0, t1, 3b
|
|
PTR_ADDU t0, SCACHE_LINESIZE # BDSLOT increase invalidate address
|
|
.set reorder
|
|
|
|
#ifdef R4600SC_DEBUG
|
|
lw t9, _r4600sc_2nd_flush_error
|
|
or t9, 2
|
|
sw t9, _r4600sc_2nd_flush_error
|
|
#endif
|
|
|
|
#ifdef MH_R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,VPDA_PSCACHESIZE(zero)
|
|
.set reorder
|
|
#elif R10000 && !R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,-SCACHE_LINESIZE(t0)
|
|
.set reorder
|
|
#ifdef HEART_COHERENCY_WAR /* ensure flush to memory */
|
|
ld zero,PHYS_TO_COMPATK1(HEART_SYNC)
|
|
#endif
|
|
#endif
|
|
|
|
j ra
|
|
|
|
#ifdef R4000PC
|
|
99:
|
|
lw ta3,pdcache_size
|
|
beqz ta3, 3f # no dcache --> done
|
|
|
|
#ifdef R4600
|
|
lw t3,two_set_pcaches
|
|
#endif
|
|
sltu t2, ta3, a1 # size > dcache_size?
|
|
bnez t2, 102f # yes --> use indexed invalidate
|
|
#ifdef R4600
|
|
beqz t3,17f
|
|
|
|
move t0,a0
|
|
PTR_ADDU t1,a0,a1 # ending address + 1
|
|
bgeu t0,t1,3f # paranoid
|
|
PTR_SUBU t1,R4600_DCACHE_LINESIZE
|
|
|
|
PD_REFILL_WAIT(cacheops_refill_0)
|
|
|
|
# check and align starting and ending addresses.
|
|
and t2,t0,R4600_DCACHE_LINEMASK
|
|
beq t2,zero,1f # starting addr is aligned
|
|
|
|
# align the address to the start of the line
|
|
PTR_SUBU t0,t2
|
|
|
|
# 'hit writeback invalidate' the primary data line indicated
|
|
# by 'addr'.
|
|
.set noreorder
|
|
cache CACH_PD|C_HWBINV,0(t0) # writeback + inval
|
|
|
|
bgeu t0,t1,3f # Out if we are done
|
|
# align addr to the next line
|
|
PTR_ADDU t0,R4600_DCACHE_LINESIZE # BDSLOT
|
|
1:
|
|
# check if ending address is cache-line aligned.
|
|
and t2,t1,R4600_DCACHE_LINEMASK
|
|
beq t2,zero,1f # ending address is full cache line
|
|
PTR_SUBU t1,t2 # BDSLOT align to start of line
|
|
cache CACH_PD|C_HWBINV,R4600_DCACHE_LINESIZE(t1) # writeback + inval
|
|
PTR_ADDU t1,1
|
|
bgeu t0,t1,3f
|
|
nop # BDSLOT
|
|
|
|
1: # top of loop
|
|
#ifdef TWO_SET_HINV_WAR
|
|
cache CACH_PD|C_HWBINV,0(t0) # invalidate primary
|
|
#else
|
|
cache CACH_PD|C_HINV,0(t0) # invalidate primary
|
|
#endif
|
|
|
|
bltu t0,t1,1b
|
|
PTR_ADDU t0,R4600_DCACHE_LINESIZE
|
|
.set reorder
|
|
3:
|
|
#ifdef R4600SC
|
|
b _r4600sc_index_inval
|
|
#else
|
|
j ra
|
|
#endif
|
|
|
|
|
|
17:
|
|
#endif /* R4600 */
|
|
move t0,a0
|
|
PTR_ADDU t1,a0,a1 # ending address + 1
|
|
bgeu t0,t1,3f # paranoid
|
|
PTR_SUBU t1,DCACHE_LINESIZE
|
|
|
|
# check and align starting and ending addresses.
|
|
and t2,t0,DCACHE_LINEMASK
|
|
beq t2,zero,1f # starting addr is aligned
|
|
|
|
# align the address to the start of the line
|
|
PTR_SUBU t0,t2
|
|
|
|
# 'hit writeback invalidate' the primary data line indicated
|
|
# by 'addr'.
|
|
.set noreorder
|
|
cache CACH_PD|C_HWBINV,0(t0) # writeback + inval
|
|
|
|
bgeu t0,t1,3f # Out if we are done
|
|
# align addr to the next line
|
|
PTR_ADDU t0,DCACHE_LINESIZE # BDSLOT
|
|
1:
|
|
# check if ending address is cache-line aligned.
|
|
and t2,t1,DCACHE_LINEMASK
|
|
beq t2,zero,1f # ending address is full cache line
|
|
PTR_SUBU t1,t2 # BDSLOT align to start of line
|
|
cache CACH_PD|C_HWBINV,DCACHE_LINESIZE(t1) # writeback + inval
|
|
PTR_ADDU t1,1
|
|
bgeu t0,t1,3f
|
|
nop # BDSLOT
|
|
|
|
1: # top of loop
|
|
cache CACH_PD|C_HINV,0(t0) # invalidate primary
|
|
|
|
bltu t0,t1,1b
|
|
PTR_ADDU t0,DCACHE_LINESIZE
|
|
.set reorder
|
|
3:
|
|
#ifdef R4600SC_DEBUG
|
|
lw t9, _r4600sc_2nd_flush_error
|
|
or t9, (1<<2)
|
|
sw t9, _r4600sc_2nd_flush_error
|
|
#endif
|
|
|
|
j ra
|
|
|
|
/* clean dcache using index invalidate */
|
|
102: LI t0, K0_CACHEFLUSHBASE # set up current address
|
|
#ifdef R4600
|
|
beqz t3,17f
|
|
PTR_ADDU t1, t0, t3 # set up limit address
|
|
PTR_SUBU t1, R4600_DCACHE_LINESIZE # (base + scache_size - scache_linesize)
|
|
.set noreorder
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mfc0 ta0, C0_SR
|
|
#endif
|
|
4:
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mtc0 zero, C0_SR
|
|
nop
|
|
#endif
|
|
cache CACH_PD|C_IWBINV, 0(t0) # Invalidate cache line
|
|
xor t2,t0,t3
|
|
cache CACH_PD|C_IWBINV, 0(t2) # Invalidate second line in set
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mtc0 ta0, C0_SR
|
|
#endif
|
|
bltu t0, t1, 4b
|
|
PTR_ADDU t0, R4600_DCACHE_LINESIZE # BDSLOT increase invalidate address
|
|
.set reorder
|
|
#ifdef R4600SC
|
|
b _r4600sc_inval_cache
|
|
#else
|
|
j ra
|
|
#endif
|
|
|
|
17:
|
|
#endif
|
|
PTR_ADDU t1, t0, ta3 # set up limit address
|
|
PTR_SUBU t1, DCACHE_LINESIZE # (base + scache_size - scache_linesize)
|
|
|
|
.set noreorder
|
|
3: cache CACH_PD|C_IWBINV, 0(t0) # Invalidate cache line
|
|
bltu t0, t1, 3b
|
|
PTR_ADDU t0, DCACHE_LINESIZE # BDSLOT increase invalidate address
|
|
.set reorder
|
|
|
|
#ifdef R4600SC_DEBUG
|
|
lw t9, _r4600sc_2nd_flush_error
|
|
or t9, (1<<3)
|
|
sw t9, _r4600sc_2nd_flush_error
|
|
#endif
|
|
|
|
j ra
|
|
#endif /* R4000PC */
|
|
END(__dcache_inval)
|
|
|
|
/*
|
|
* __dcache_wb(addr,len)
|
|
* write back data from the primary data and secondary cache.
|
|
*
|
|
* XXX Assumes 32 word line size for secondary cache.
|
|
* XXX Assumes 32 byte line size for primary data cache.
|
|
* XXX Assumes 4 primary lines per secondary line
|
|
* XXX note that since 2ndary cache on 4600SC is write through
|
|
* nothing needs to be done since data is already written
|
|
* to memory.
|
|
*/
|
|
|
|
LEAF(__dcache_wb)
|
|
#if IP20
|
|
lw t0,mc_rev_level
|
|
bne t0,zero,1f
|
|
j rmi_cacheflush
|
|
1:
|
|
#endif
|
|
|
|
blez a1,41f # if length <= 0, we are done
|
|
lw ta3,VPDA_PSCACHESIZE(zero)
|
|
#ifdef R4000PC
|
|
#ifdef R4600SC
|
|
lw t0,two_set_pcaches
|
|
bnez t0,99f # scache is writethru--do primary only
|
|
#endif
|
|
beqz ta3,99f # no scache--do primary only
|
|
#endif
|
|
|
|
sltu t2, ta3, a1 # size > scache_size?
|
|
bnez t2, 102f # yes --> use indexed invalidate
|
|
|
|
move t0,a0
|
|
PTR_ADDU t1,a0,a1 # ending address + 1
|
|
bgeu t0,t1,3f # paranoid
|
|
PTR_SUBU t1,SCACHE_LINESIZE
|
|
|
|
# align the starting address.
|
|
and t2,t0,SCACHE_LINEMASK
|
|
PTR_SUBU t0,t2
|
|
|
|
.set noreorder
|
|
1: # top of loop
|
|
#ifdef R10000
|
|
cache CACH_SD|C_HWBINV,0(t0) # writeback secondary
|
|
#else /* R10000 */
|
|
cache CACH_SD|C_HWB,0(t0) # writeback secondary
|
|
#endif /* R10000 */
|
|
|
|
bltu t0,t1,1b
|
|
PTR_ADDU t0,SCACHE_LINESIZE
|
|
.set reorder
|
|
3:
|
|
#ifdef R4600SC_DEBUG
|
|
lw t9, _r4600sc_2nd_flush_error
|
|
or t9, (1<<4)
|
|
sw t9, _r4600sc_2nd_flush_error
|
|
#endif
|
|
|
|
#ifdef MH_R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,VPDA_PSCACHESIZE(zero)
|
|
.set reorder
|
|
#elif R10000 && !R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,-SCACHE_LINESIZE(t0)
|
|
.set reorder
|
|
#ifdef HEART_COHERENCY_WAR /* ensure flush to memory */
|
|
ld zero,PHYS_TO_COMPATK1(HEART_SYNC)
|
|
#endif
|
|
#endif
|
|
|
|
j ra
|
|
|
|
/* clean scache using index invalidate */
|
|
102: LI t0, K0_CACHEFLUSHBASE # set up current address
|
|
#ifdef R10000
|
|
srl ta3,1 # cache is 2 way set associative
|
|
#endif
|
|
PTR_ADDU t1, t0, ta3 # set up limit address
|
|
PTR_SUBU t1, SCACHE_LINESIZE # (base + scache_size - scache_linesize)
|
|
|
|
.set noreorder
|
|
3: cache CACH_SD|C_IWBINV, 0(t0) # Invalidate cache line
|
|
#ifdef R10000
|
|
cache CACH_SD|C_IWBINV, 1(t0) # Invalidate cache line (way 1)
|
|
#endif
|
|
bltu t0, t1, 3b
|
|
PTR_ADDU t0, SCACHE_LINESIZE # BDSLOT increase invalidate address
|
|
.set reorder
|
|
|
|
#ifdef R4600SC_DEBUG
|
|
lw t9, _r4600sc_2nd_flush_error
|
|
or t9, (1<<5)
|
|
sw t9, _r4600sc_2nd_flush_error
|
|
#endif
|
|
|
|
#ifdef MH_R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,VPDA_PSCACHESIZE(zero)
|
|
.set reorder
|
|
#elif R10000 && !R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,-SCACHE_LINESIZE(t0)
|
|
.set reorder
|
|
#ifdef HEART_COHERENCY_WAR /* ensure flush to memory */
|
|
ld zero,PHYS_TO_COMPATK1(HEART_SYNC)
|
|
#endif
|
|
#endif
|
|
|
|
j ra
|
|
|
|
#ifdef R4000PC
|
|
99:
|
|
lw ta3,pdcache_size
|
|
beqz ta3, 3f # no dcache --> done
|
|
|
|
#ifdef R4600
|
|
lw t3,two_set_pcaches
|
|
#endif
|
|
sltu t2, ta3, a1 # size > dcache_size?
|
|
bnez t2, 102f # yes --> use indexed invalidate
|
|
#ifdef R4600
|
|
beqz t3,17f
|
|
|
|
move t0,a0
|
|
PTR_ADDU t1,a0,a1 # ending address + 1
|
|
bgeu t0,t1,3f # paranoid
|
|
PTR_SUBU t1,R4600_DCACHE_LINESIZE
|
|
|
|
# check and align starting and ending addresses.
|
|
and t2,t0,R4600_DCACHE_LINEMASK
|
|
# align the address to the start of the line
|
|
PTR_SUBU t0,t2
|
|
|
|
PD_REFILL_WAIT(cacheops_refill_1)
|
|
|
|
# 'hit writeback' the primary data line indicated
|
|
# by 'addr'.
|
|
.set noreorder
|
|
1: # top of loop
|
|
cache CACH_PD|C_HWB,0(t0) # invalidate primary
|
|
|
|
bltu t0,t1,1b
|
|
PTR_ADDU t0,R4600_DCACHE_LINESIZE
|
|
.set reorder
|
|
3:
|
|
|
|
j ra
|
|
17:
|
|
#endif /* R4600 */
|
|
move t0,a0
|
|
PTR_ADDU t1,a0,a1 # ending address + 1
|
|
bgeu t0,t1,3f # paranoid
|
|
PTR_SUBU t1,DCACHE_LINESIZE
|
|
|
|
# check and align starting and ending addresses.
|
|
and t2,t0,DCACHE_LINEMASK
|
|
# align the address to the start of the line
|
|
PTR_SUBU t0,t2
|
|
|
|
# 'hit writeback' the primary data line indicated
|
|
# by 'addr'.
|
|
.set noreorder
|
|
1: # top of loop
|
|
cache CACH_PD|C_HWB,0(t0) # invalidate primary
|
|
|
|
bltu t0,t1,1b
|
|
PTR_ADDU t0,DCACHE_LINESIZE
|
|
.set reorder
|
|
3:
|
|
j ra
|
|
|
|
/* clean dcache using index invalidate */
|
|
102: LI t0, K0_CACHEFLUSHBASE # set up current address
|
|
#ifdef R4600
|
|
beqz t3,17f
|
|
PTR_ADDU t1, t0, t3 # set up limit address
|
|
PTR_SUBU t1, R4600_DCACHE_LINESIZE # (base + scache_size - scache_linesize)
|
|
.set noreorder
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mfc0 ta0, C0_SR
|
|
#endif
|
|
3:
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mtc0 zero, C0_SR
|
|
nop
|
|
#endif
|
|
cache CACH_PD|C_IWBINV, 0(t0) # Invalidate cache line
|
|
xor t2,t0,t3
|
|
cache CACH_PD|C_IWBINV, 0(t2) # Invalidate second line in set
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mtc0 ta0, C0_SR
|
|
#endif
|
|
bltu t0, t1, 3b
|
|
PTR_ADDU t0, R4600_DCACHE_LINESIZE # BDSLOT increase invalidate address
|
|
.set reorder
|
|
|
|
j ra
|
|
|
|
17:
|
|
#endif /* R4600 */
|
|
PTR_ADDU t1, t0, ta3 # set up limit address
|
|
PTR_SUBU t1, DCACHE_LINESIZE # (base + scache_size - scache_linesize)
|
|
|
|
.set noreorder
|
|
3: cache CACH_PD|C_IWBINV, 0(t0) # Invalidate cache line
|
|
bltu t0, t1, 3b
|
|
PTR_ADDU t0, DCACHE_LINESIZE # BDSLOT increase invalidate address
|
|
.set reorder
|
|
|
|
j ra
|
|
#endif /* R4000PC */
|
|
END(__dcache_wb)
|
|
|
|
/*
|
|
* __dcache_wb_inval(addr, len)
|
|
* writeback-invalidate data cache for range of physical addr to addr+len-1
|
|
*
|
|
* XXX Assumes 32 word line size for secondary cache.
|
|
* XXX Assumes 32 byte line size for primary data cache.
|
|
* XXX Assumes 4 primary lines per secondary line
|
|
* XXX Assumes that primary linesize == secondary linesize for 4600SC
|
|
*/
|
|
|
|
LEAF(__dcache_wb_inval)
|
|
#if IP20
|
|
lw t0,mc_rev_level
|
|
bne t0,zero,1f
|
|
j rmi_cacheflush
|
|
1:
|
|
#endif
|
|
|
|
#ifdef defined(R4600SC) && defined(_R4600SC_LAZY)
|
|
move a2,a0
|
|
move a3,a1
|
|
#endif
|
|
blez a1,41f # if length <= 0, we are done
|
|
lw ta3,VPDA_PSCACHESIZE(zero)
|
|
#ifdef R4000PC
|
|
beqz ta3,99f # no scache--do primary only
|
|
#endif
|
|
|
|
#ifdef R4600SC
|
|
lw t0, two_set_pcaches # are we on a 4600?
|
|
bnez t0, 99f
|
|
#endif
|
|
|
|
sltu t2, ta3, a1 # size > scache_size?
|
|
bnez t2, 102f # yes --> use indexed invalidate
|
|
|
|
move t0,a0
|
|
PTR_ADDU t1,a0,a1 # ending address + 1
|
|
bgeu t0,t1,3f # paranoid
|
|
PTR_SUBU t1,SCACHE_LINESIZE
|
|
|
|
# align the starting address.
|
|
and t2,t0,SCACHE_LINEMASK
|
|
PTR_SUBU t0,t2
|
|
|
|
.set noreorder
|
|
1: # top of loop
|
|
cache CACH_SD|C_HWBINV,0(t0) # writeback secondary
|
|
bltu t0,t1,1b
|
|
PTR_ADDU t0,SCACHE_LINESIZE
|
|
.set reorder
|
|
3:
|
|
#ifdef R4600SC_DEBUG
|
|
lw t9, _r4600sc_2nd_flush_error
|
|
or t9, (1<<10)
|
|
sw t9, _r4600sc_2nd_flush_error
|
|
#endif
|
|
|
|
#ifdef MH_R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,VPDA_PSCACHESIZE(zero)
|
|
.set reorder
|
|
#elif R10000 && !R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,-SCACHE_LINESIZE(t0)
|
|
.set reorder
|
|
#ifdef HEART_COHERENCY_WAR /* ensure flush to memory */
|
|
ld zero,PHYS_TO_COMPATK1(HEART_SYNC)
|
|
#endif
|
|
#endif
|
|
|
|
41:
|
|
|
|
j ra
|
|
|
|
/* clean scache using index invalidate */
|
|
102: LI t0, K0_CACHEFLUSHBASE # set up current address
|
|
#ifdef R10000
|
|
srl ta3,1 # cache is 2 way set associative
|
|
#endif
|
|
PTR_ADDU t1, t0, ta3 # set up limit address
|
|
PTR_SUBU t1, SCACHE_LINESIZE # (base + scache_size - scache_linesize)
|
|
|
|
.set noreorder
|
|
3: cache CACH_SD|C_IWBINV, 0(t0) # Invalidate cache line
|
|
#ifdef R10000
|
|
cache CACH_SD|C_IWBINV, 1(t0) # Invalidate cache line (way 1)
|
|
#endif
|
|
bltu t0, t1, 3b
|
|
PTR_ADDU t0, SCACHE_LINESIZE # BDSLOT increase invalidate address
|
|
.set reorder
|
|
|
|
#ifdef R4600SC_DEBUG
|
|
lw t9, _r4600sc_2nd_flush_error
|
|
or t9, (1<<11)
|
|
sw t9, _r4600sc_2nd_flush_error
|
|
#endif
|
|
|
|
#ifdef MH_R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,VPDA_PSCACHESIZE(zero)
|
|
.set reorder
|
|
#elif R10000 && !R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,-SCACHE_LINESIZE(t0)
|
|
.set reorder
|
|
#ifdef HEART_COHERENCY_WAR /* ensure flush to memory */
|
|
ld zero,PHYS_TO_COMPATK1(HEART_SYNC)
|
|
#endif
|
|
#endif
|
|
|
|
j ra
|
|
|
|
#ifdef R4000PC
|
|
99:
|
|
lw ta3,pdcache_size
|
|
beqz ta3, 3f # no dcache --> done
|
|
|
|
#ifdef R4600
|
|
lw t3,two_set_pcaches
|
|
#endif
|
|
sltu t2, ta3, a1 # size > dcache_size?
|
|
bnez t2, 102f # yes --> use indexed invalidate
|
|
#ifdef R4600
|
|
beqz t3,17f
|
|
move t0,a0
|
|
PTR_ADDU t1,a0,a1 # ending address + 1
|
|
bgeu t0,t1,3f # paranoid
|
|
PTR_SUBU t1,R4600_DCACHE_LINESIZE
|
|
|
|
# check and align starting and ending addresses.
|
|
and t2,t0,R4600_DCACHE_LINEMASK
|
|
# align the address to the start of the line
|
|
PTR_SUBU t0,t2
|
|
|
|
PD_REFILL_WAIT(cacheops_refill_2)
|
|
|
|
# 'hit writeback' the primary data line indicated
|
|
# by 'addr'.
|
|
.set noreorder
|
|
1: # top of loop
|
|
cache CACH_PD|C_HWBINV,0(t0) # invalidate primary
|
|
|
|
bltu t0,t1,1b
|
|
PTR_ADDU t0,R4600_DCACHE_LINESIZE
|
|
.set reorder
|
|
3:
|
|
#ifdef R4600SC
|
|
b _r4600sc_index_inval
|
|
#else
|
|
j ra
|
|
#endif
|
|
17:
|
|
#endif /* R4600 */
|
|
move t0,a0
|
|
PTR_ADDU t1,a0,a1 # ending address + 1
|
|
bgeu t0,t1,3f # paranoid
|
|
PTR_SUBU t1,DCACHE_LINESIZE
|
|
|
|
# check and align starting and ending addresses.
|
|
and t2,t0,DCACHE_LINEMASK
|
|
# align the address to the start of the line
|
|
PTR_SUBU t0,t2
|
|
|
|
# 'hit writeback' the primary data line indicated
|
|
# by 'addr'.
|
|
.set noreorder
|
|
1: # top of loop
|
|
cache CACH_PD|C_HWBINV,0(t0) # invalidate primary
|
|
|
|
bltu t0,t1,1b
|
|
PTR_ADDU t0,DCACHE_LINESIZE
|
|
.set reorder
|
|
3:
|
|
#ifdef R4600SC_DEBUG
|
|
lw t9, _r4600sc_2nd_flush_error
|
|
or t9, (1<<12)
|
|
sw t9, _r4600sc_2nd_flush_error
|
|
#endif
|
|
|
|
j ra
|
|
|
|
/* clean dcache using index invalidate */
|
|
102: LI t0, K0_CACHEFLUSHBASE # set up current address
|
|
#ifdef R4600
|
|
beqz t3,17f
|
|
PTR_ADDU t1, t0, t3 # set up limit address
|
|
PTR_SUBU t1, R4600_DCACHE_LINESIZE # (base + scache_size - scache_linesize)
|
|
|
|
.set noreorder
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mfc0 ta0, C0_SR
|
|
#endif
|
|
3:
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mtc0 zero, C0_SR
|
|
nop
|
|
#endif
|
|
cache CACH_PD|C_IWBINV, 0(t0) # Invalidate cache line
|
|
xor t2,t0,t3
|
|
cache CACH_PD|C_IWBINV, 0(t2) # Invalidate cache line
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mtc0 ta0, C0_SR
|
|
#endif
|
|
bltu t0, t1, 3b
|
|
PTR_ADDU t0, R4600_DCACHE_LINESIZE # BDSLOT increase invalidate address
|
|
.set reorder
|
|
|
|
#ifdef R4600SC
|
|
b _r4600sc_inval_cache
|
|
#else
|
|
j ra
|
|
#endif
|
|
|
|
17:
|
|
#endif /* R4600 */
|
|
PTR_ADDU t1, t0, ta3 # set up limit address
|
|
PTR_SUBU t1, DCACHE_LINESIZE # (base + scache_size - scache_linesize)
|
|
|
|
.set noreorder
|
|
3: cache CACH_PD|C_IWBINV, 0(t0) # Invalidate cache line
|
|
bltu t0, t1, 3b
|
|
PTR_ADDU t0, DCACHE_LINESIZE # BDSLOT increase invalidate address
|
|
.set reorder
|
|
|
|
#ifdef R4600SC_DEBUG
|
|
lw t9, _r4600sc_2nd_flush_error
|
|
or t9, (1<<13)
|
|
sw t9, _r4600sc_2nd_flush_error
|
|
#endif
|
|
|
|
j ra
|
|
#endif /* R4000PC */
|
|
END(__dcache_wb_inval)
|
|
|
|
/*
|
|
* __icache_inval(addr, len)
|
|
* invalidate instruction cache for range of physical addr to addr+len-1
|
|
*
|
|
* We use the HIT_INVALIDATE cache op. Therefore, this requires
|
|
* that 'addr'..'len' be the actual addresses which we want to
|
|
* invalidate in the caches. (i.e. won't work for user virtual
|
|
* addresses that the kernel converts to K0 before calling.)
|
|
* addr/len are not necessarily cache line aligned.
|
|
*
|
|
* Invalidate lines in both the primary and secondary cache.
|
|
*
|
|
* XXX Assumes 32 word line size for secondary cache.
|
|
* XXX Assumes 32 byte line size for primary instruction cache.
|
|
* XXX Assumes 4 primary lines per secondary line
|
|
*/
|
|
|
|
LEAF(__icache_inval)
|
|
#if IP20
|
|
lw t0,mc_rev_level
|
|
bne t0,zero,1f
|
|
j rmi_cacheflush
|
|
1:
|
|
#endif
|
|
|
|
#ifdef defined(R4600SC) && defined(_R4600SC_LAZY)
|
|
move a2,a0
|
|
move a3,a1
|
|
#endif
|
|
blez a1,41f # if length <= 0, we are done
|
|
lw ta3,VPDA_PSCACHESIZE(zero)
|
|
#ifdef R4000PC
|
|
beqz ta3,99f # no scache--do primary only
|
|
#endif
|
|
|
|
#ifdef R4600SC
|
|
lw t0, two_set_pcaches # are we on a 4600SC?
|
|
bnez t0, 99f
|
|
#endif
|
|
|
|
sltu t2, ta3, a1 # size > scache_size?
|
|
bnez t2, 102f # yes --> use indexed invalidate
|
|
|
|
move t0,a0
|
|
PTR_ADDU t1,a0,a1 # ending address + 1
|
|
bgeu t0,t1,3f # paranoid
|
|
PTR_SUBU t1,SCACHE_LINESIZE
|
|
|
|
# align the starting address.
|
|
and t2,t0,SCACHE_LINEMASK
|
|
PTR_SUBU t0,t2
|
|
|
|
.set noreorder
|
|
1: # top of loop
|
|
cache CACH_SD|C_HWBINV,0(t0) # writeback secondary
|
|
|
|
bltu t0,t1,1b
|
|
PTR_ADDU t0,SCACHE_LINESIZE
|
|
.set reorder
|
|
3:
|
|
#ifdef R4600SC_DEBUG
|
|
lw t9, _r4600sc_2nd_flush_error
|
|
or t9, (1<<14)
|
|
sw t9, _r4600sc_2nd_flush_error
|
|
#endif
|
|
|
|
#ifdef MH_R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,VPDA_PSCACHESIZE(zero)
|
|
.set reorder
|
|
#elif R10000 && !R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,-SCACHE_LINESIZE(t0)
|
|
.set reorder
|
|
#ifdef HEART_COHERENCY_WAR /* ensure flush to memory */
|
|
ld zero,PHYS_TO_COMPATK1(HEART_SYNC)
|
|
#endif
|
|
#endif
|
|
|
|
j ra
|
|
|
|
/* clean scache using index invalidate */
|
|
102: LI t0, K0_CACHEFLUSHBASE # set up current address
|
|
#ifdef R10000
|
|
srl ta3,1 # cache is 2 way set associative
|
|
#endif
|
|
PTR_ADDU t1, t0, ta3 # set up limit address
|
|
PTR_SUBU t1, SCACHE_LINESIZE # (base + scache_size - scache_linesize)
|
|
|
|
.set noreorder
|
|
3: cache CACH_SD|C_IWBINV, 0(t0) # Invalidate cache line
|
|
#ifdef R10000
|
|
cache CACH_SD|C_IWBINV, 1(t0) # Invalidate cache line (way 1)
|
|
#endif
|
|
bltu t0, t1, 3b
|
|
PTR_ADDU t0, SCACHE_LINESIZE # BDSLOT increase invalidate address
|
|
.set reorder
|
|
|
|
#ifdef R4600SC_DEBUG
|
|
lw t9, _r4600sc_2nd_flush_error
|
|
or t9, (1<<15)
|
|
sw t9, _r4600sc_2nd_flush_error
|
|
#endif
|
|
|
|
#ifdef MH_R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,VPDA_PSCACHESIZE(zero)
|
|
.set reorder
|
|
#elif R10000 && !R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,-SCACHE_LINESIZE(t0)
|
|
.set reorder
|
|
#ifdef HEART_COHERENCY_WAR /* ensure flush to memory */
|
|
ld zero,PHYS_TO_COMPATK1(HEART_SYNC)
|
|
#endif
|
|
#endif
|
|
|
|
j ra
|
|
|
|
#ifdef R4000PC
|
|
/* for R4000PC, we clean both caches, as assumed by higher levels */
|
|
99:
|
|
lw ta3,pdcache_size
|
|
beqz ta3, 3f # no dcache --> done
|
|
|
|
#ifdef R4600
|
|
lw t3,two_set_pcaches
|
|
#endif
|
|
sltu t2, ta3, a1 # size > dcache_size?
|
|
bnez t2, 102f # yes --> use indexed invalidate
|
|
#ifdef R4600
|
|
beqz t3,17f
|
|
move t0,a0
|
|
PTR_ADDU t1,a0,a1 # ending address + 1
|
|
bgeu t0,t1,103f # paranoid
|
|
PTR_SUBU t1,R4600_DCACHE_LINESIZE
|
|
|
|
# check and align starting and ending addresses.
|
|
and t2,t0,R4600_DCACHE_LINEMASK
|
|
# align the address to the start of the line
|
|
PTR_SUBU t0,t2
|
|
|
|
PD_REFILL_WAIT(cacheops_refill_3)
|
|
|
|
# 'hit writeback invalidate' the primary data line indicated
|
|
# by 'addr'.
|
|
.set noreorder
|
|
1: # top of loop
|
|
cache CACH_PD|C_HWBINV,0(t0) # invalidate primary
|
|
|
|
bltu t0,t1,1b
|
|
PTR_ADDU t0,R4600_DCACHE_LINESIZE
|
|
.set reorder
|
|
3:
|
|
b 103f
|
|
|
|
|
|
/* clean dcache using index invalidate */
|
|
102: LI t0, K0_CACHEFLUSHBASE # set up current address
|
|
PTR_ADDU t1, t0, t3 # set up limit address
|
|
PTR_SUBU t1, R4600_DCACHE_LINESIZE # (base + dcache_size - dcache_linesize)
|
|
|
|
.set noreorder
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mfc0 ta0, C0_SR
|
|
#endif
|
|
3:
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mtc0 zero, C0_SR
|
|
nop
|
|
#endif
|
|
cache CACH_PD|C_IWBINV, 0(t0) # Invalidate cache line
|
|
xor t2,t0,t3
|
|
cache CACH_PD|C_IWBINV, 0(t2) # Invalidate cache line
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mtc0 ta0, C0_SR
|
|
#endif
|
|
bltu t0, t1, 3b
|
|
PTR_ADDU t0, R4600_DCACHE_LINESIZE # BDSLOT increase invalidate address
|
|
.set reorder
|
|
|
|
103:
|
|
lw ta3,picache_size
|
|
beqz ta3, 3f # no icache --> done
|
|
|
|
sltu t2, ta3, a1 # size > icache_size?
|
|
bnez t2, 102f # yes --> use indexed invalidate
|
|
|
|
move t0,a0
|
|
PTR_ADDU t1,a0,a1 # ending address + 1
|
|
bgeu t0,t1,3f # paranoid
|
|
PTR_SUBU t1,R4600_ICACHE_LINESIZE
|
|
|
|
# check and align starting and ending addresses.
|
|
and t2,t0,R4600_ICACHE_LINEMASK
|
|
# align the address to the start of the line
|
|
PTR_SUBU t0,t2
|
|
|
|
# 'hit invalidate' the primary data line indicated
|
|
# by 'addr'.
|
|
.set noreorder
|
|
1: # top of loop
|
|
cache CACH_PI|C_HINV,0(t0) # invalidate primary
|
|
bltu t0,t1,1b
|
|
PTR_ADDU t0,R4600_ICACHE_LINESIZE
|
|
.set reorder
|
|
3:
|
|
#ifdef R4600SC
|
|
b _r4600sc_index_inval
|
|
#else
|
|
j ra
|
|
#endif
|
|
|
|
/* clean icache using index invalidate */
|
|
102: LI t0, K0_CACHEFLUSHBASE # set up current address
|
|
PTR_ADDU t1, t0, t3 # set up limit address
|
|
PTR_SUBU t1, R4600_ICACHE_LINESIZE # (base + icache_size - icache_linesize)
|
|
|
|
.set noreorder
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mfc0 ta0, C0_SR
|
|
mtc0 zero, C0_SR
|
|
nop
|
|
#endif
|
|
3: cache CACH_PI|C_IINV,0(t0) # Invalidate cache line
|
|
xor t2,t0,t3
|
|
cache CACH_PI|C_IINV,0(t2) # Invalidate cache line
|
|
bltu t0, t1, 3b
|
|
PTR_ADDU t0, R4600_ICACHE_LINESIZE # BDSLOT increase invalidate address
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mtc0 ta0, C0_SR
|
|
nop
|
|
#endif
|
|
.set reorder
|
|
|
|
#ifdef R4600SC
|
|
b _r4600sc_inval_cache
|
|
#else
|
|
j ra
|
|
#endif
|
|
17:
|
|
#endif /* R4600 */
|
|
move t0,a0
|
|
PTR_ADDU t1,a0,a1 # ending address + 1
|
|
bgeu t0,t1,103f # paranoid
|
|
PTR_SUBU t1,DCACHE_LINESIZE
|
|
|
|
# check and align starting and ending addresses.
|
|
and t2,t0,DCACHE_LINEMASK
|
|
# align the address to the start of the line
|
|
PTR_SUBU t0,t2
|
|
|
|
# 'hit writeback invalidate' the primary data line indicated
|
|
# by 'addr'.
|
|
.set noreorder
|
|
1: # top of loop
|
|
cache CACH_PD|C_HWBINV,0(t0) # invalidate primary
|
|
|
|
bltu t0,t1,1b
|
|
PTR_ADDU t0,DCACHE_LINESIZE
|
|
.set reorder
|
|
3:
|
|
b 103f
|
|
|
|
|
|
/* clean dcache using index invalidate */
|
|
102: LI t0, K0_CACHEFLUSHBASE # set up current address
|
|
PTR_ADDU t1, t0, ta3 # set up limit address
|
|
PTR_SUBU t1, DCACHE_LINESIZE # (base + dcache_size - dcache_linesize)
|
|
|
|
.set noreorder
|
|
3: cache CACH_PD|C_IWBINV, 0(t0) # Invalidate cache line
|
|
bltu t0, t1, 3b
|
|
PTR_ADDU t0, DCACHE_LINESIZE # BDSLOT increase invalidate address
|
|
.set reorder
|
|
|
|
103:
|
|
lw ta3,picache_size
|
|
beqz ta3, 3f # no icache --> done
|
|
|
|
sltu t2, ta3, a1 # size > icache_size?
|
|
bnez t2, 102f # yes --> use indexed invalidate
|
|
|
|
move t0,a0
|
|
PTR_ADDU t1,a0,a1 # ending address + 1
|
|
bgeu t0,t1,3f # paranoid
|
|
PTR_SUBU t1,ICACHE_LINESIZE
|
|
|
|
# check and align starting and ending addresses.
|
|
and t2,t0,ICACHE_LINEMASK
|
|
# align the address to the start of the line
|
|
PTR_SUBU t0,t2
|
|
|
|
# 'hit invalidate' the primary data line indicated
|
|
# by 'addr'.
|
|
.set noreorder
|
|
1: # top of loop
|
|
cache CACH_PI|C_HINV,0(t0) # invalidate primary
|
|
|
|
bltu t0,t1,1b
|
|
PTR_ADDU t0,ICACHE_LINESIZE
|
|
.set reorder
|
|
3:
|
|
#ifdef R4600SC_DEBUG
|
|
lw t9, _r4600sc_2nd_flush_error
|
|
or t9, (1<<16)
|
|
sw t9, _r4600sc_2nd_flush_error
|
|
#endif
|
|
|
|
j ra
|
|
|
|
/* clean icache using index invalidate */
|
|
102: LI t0, K0_CACHEFLUSHBASE # set up current address
|
|
PTR_ADDU t1, t0, ta3 # set up limit address
|
|
PTR_SUBU t1, ICACHE_LINESIZE # (base + icache_size - icache_linesize)
|
|
|
|
.set noreorder
|
|
3: cache CACH_PI|C_IINV,0(t0) # Invalidate cache line
|
|
bltu t0, t1, 3b
|
|
PTR_ADDU t0, ICACHE_LINESIZE # BDSLOT increase invalidate address
|
|
.set reorder
|
|
|
|
#ifdef R4600SC_DEBUG
|
|
lw t9, _r4600sc_2nd_flush_error
|
|
or t9, (1<<17)
|
|
sw t9, _r4600sc_2nd_flush_error
|
|
#endif
|
|
|
|
j ra
|
|
#endif /* R4000PC */
|
|
END(__icache_inval)
|
|
/*
|
|
* __cache_wb_inval(addr, len)
|
|
*
|
|
* Uses the INDEX_INVALIDATE and INDEX_WRITEBACK_INVALIDATE
|
|
* cacheops. Should be called with K0 addresses, to avoid
|
|
* the tlb translation (and tlb miss fault) overhead.
|
|
*
|
|
* XXX Assumes 32 word line size for secondary cache.
|
|
* XXX Assumes 32 byte line size for primary I/D caches.
|
|
*/
|
|
LEAF(__cache_wb_inval)
|
|
#if IP20
|
|
lw t0,mc_rev_level
|
|
bne t0,zero,1f
|
|
j rmi_cacheflush
|
|
1:
|
|
#endif
|
|
|
|
#ifdef defined(R4600SC) && defined(_R4600SC_LAZY)
|
|
move a2,a0
|
|
move a3,a1
|
|
#endif
|
|
blez a1, 41f # if we don't have anything return
|
|
#ifdef R4600
|
|
lw ta2,two_set_pcaches # are we on a 4600?
|
|
bnez ta2,1f # yes --> we may have a secondary
|
|
# cache, but we will deal with that
|
|
# later, after the primaries have
|
|
# been invalidated.
|
|
#endif
|
|
lw ta0,VPDA_PSCACHESIZE(zero)
|
|
|
|
#ifdef R10000
|
|
srl ta0,1 # cache is 2 way set associative
|
|
#endif
|
|
|
|
#ifdef R4000PC
|
|
/* do we have an scache? */
|
|
bnez ta0,101f # yes --> just use scache operations
|
|
|
|
#ifdef R4600
|
|
1:
|
|
#endif
|
|
lw ta3, pdcache_size
|
|
lw v0, picache_size
|
|
#ifdef R4600
|
|
beqz ta2,17f
|
|
|
|
/* do dcache */
|
|
beqz ta3, 31f # no dcache --> check icache
|
|
|
|
/* clean dcache using indexed invalidate */
|
|
move t0, a0 # set up current address
|
|
|
|
PTR_ADDU t1, t0, a1 # set up limit address
|
|
#ifdef R4600SC
|
|
bleu a1,ta2,21f
|
|
PTR_ADDU t1, t0, ta2
|
|
21:
|
|
#endif /* R4600SC */
|
|
PTR_SUBU t1, R4600_DCACHE_LINESIZE # (base + count - R4600_DCACHE_LINESIZE)
|
|
|
|
and t3, t0, R4600_DCACHE_LINEMASK # align start to dcache line
|
|
PTR_SUBU t0, t3 # pull off extra
|
|
|
|
.set noreorder
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mfc0 ta0, C0_SR
|
|
#endif
|
|
2:
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mtc0 zero, C0_SR
|
|
nop
|
|
#endif
|
|
cache CACH_PD|C_IWBINV, 0(t0) # Invalidate cache line
|
|
xor ta1,t0,ta2
|
|
cache CACH_PD|C_IWBINV, 0(ta1) # Invalidate cache line
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mtc0 ta0, C0_SR
|
|
#endif
|
|
bltu t0, t1, 2b
|
|
PTR_ADDU t0, R4600_DCACHE_LINESIZE # BDSLOT
|
|
.set reorder
|
|
|
|
/* now do icache */
|
|
31: beqz v0, 51f
|
|
|
|
/* clean icache using indexed invalidate */
|
|
move t0, a0 # set up current address
|
|
|
|
PTR_ADDU t1, t0, a1 # set up target address
|
|
#ifdef R4600SC
|
|
bleu a1,ta2,22f
|
|
PTR_ADDU t1, t0, ta2
|
|
22:
|
|
#endif /* R4600SC */
|
|
PTR_SUBU t1, R4600_ICACHE_LINESIZE # (base + size - R4600_ICACHE_LINESIZE)
|
|
|
|
and t3, t0, R4600_ICACHE_LINEMASK # align start to icache line
|
|
PTR_SUBU t0, t3 # pull off extra
|
|
|
|
and t3, t1, R4600_ICACHE_LINEMASK # align ending to icache line
|
|
PTR_SUBU t1, t3
|
|
|
|
.set noreorder
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mfc0 ta0, C0_SR
|
|
mtc0 zero, C0_SR
|
|
nop
|
|
#endif
|
|
4: cache CACH_PI|C_IINV, 0(t0) # Invalidate cache line
|
|
xor ta1,t0,ta2
|
|
cache CACH_PI|C_IINV, 0(ta1) # Invalidate cache line
|
|
bltu t0, t1, 4b
|
|
PTR_ADDU t0, R4600_ICACHE_LINESIZE # BDSLOT
|
|
#ifdef _R4600_CACHEOP_WAR
|
|
mtc0 ta0, C0_SR
|
|
nop
|
|
#endif
|
|
.set reorder
|
|
|
|
#ifdef R4600SC
|
|
51: b _r4600sc_index_inval
|
|
#else
|
|
51: j ra
|
|
#endif
|
|
|
|
17:
|
|
#endif /* R4600 */
|
|
/* do dcache */
|
|
beqz ta3, 31f # no dcache --> check icache
|
|
|
|
/* clean dcache using indexed invalidate */
|
|
move t0, a0 # set up current address
|
|
|
|
PTR_ADDU t1, t0, a1 # set up limit address
|
|
PTR_SUBU t1, DCACHE_LINESIZE # (base + count - DCACHE_LINESIZE)
|
|
|
|
and t3, t0, DCACHE_LINEMASK # align start to dcache line
|
|
PTR_SUBU t0, t3 # pull off extra
|
|
|
|
.set noreorder
|
|
2: cache CACH_PD|C_IWBINV, 0(t0) # Invalidate cache line
|
|
bltu t0, t1, 2b
|
|
PTR_ADDU t0, DCACHE_LINESIZE # BDSLOT
|
|
.set reorder
|
|
|
|
/* now do icache */
|
|
31: beqz v0, 41f
|
|
|
|
/* clean icache using indexed invalidate */
|
|
move t0, a0 # set up current address
|
|
|
|
PTR_ADDU t1, t0, a1 # set up target address
|
|
PTR_SUBU t1, ICACHE_LINESIZE # (base + size - ICACHE_LINESIZE)
|
|
|
|
and t3, t0, ICACHE_LINEMASK # align start to icache line
|
|
PTR_SUBU t0, t3 # pull off extra
|
|
|
|
and t3, t1, ICACHE_LINEMASK # align ending to icache line
|
|
PTR_SUBU t1, t3
|
|
|
|
.set noreorder
|
|
4: cache CACH_PI|C_IINV, 0(t0) # Invalidate cache line
|
|
bltu t0, t1, 4b
|
|
PTR_ADDU t0, ICACHE_LINESIZE # BDSLOT
|
|
.set reorder
|
|
|
|
41:
|
|
#ifdef R4600SC_DEBUG
|
|
lw t9, _r4600sc_2nd_flush_error
|
|
or t9, (1<<18)
|
|
sw t9, _r4600sc_2nd_flush_error
|
|
#endif
|
|
|
|
j ra
|
|
#endif /* R4000PC */
|
|
|
|
101: /* do scache */
|
|
|
|
move t0,a0 # starting address
|
|
|
|
#ifdef R10000
|
|
move ta1,ta0 # save s$ size for use below
|
|
#endif
|
|
# align the starting address to a 2nd cache line
|
|
and t2,t0,SCACHE_LINEMASK
|
|
bltu ta0,a1,1f # 2nd cache is smaller than count
|
|
move ta0,a1
|
|
1:
|
|
PTR_ADDU ta0,t0 # ending addr + 1
|
|
PTR_SUBU t0,t2 # line-align
|
|
PTR_SUBU ta0,SCACHE_LINESIZE
|
|
|
|
#ifdef R10000
|
|
/* R10000 only checks ptag for primary caches, so also hit them
|
|
* explicitly as this is an indexed operation.
|
|
*/
|
|
bleu ta1,a1,3f # skip primary if flushing full cache
|
|
|
|
move ta1,a0 # base addr
|
|
lw t2,pdcache_size # cache size (isize == dsize)
|
|
move ta2,a1 # base + length
|
|
srl t2,1 # 2 way assoc
|
|
PTR_ADDU t2,ta1 # addr + cache size
|
|
bltu ta2,t2,2f # len > cachesize?
|
|
move ta2,t2 # cap primary loop @ cachesize
|
|
|
|
.set noreorder
|
|
2:
|
|
PTR_ADDU ta1,CACHE_ILINE_SIZE
|
|
cache CACH_PD|C_IWBINV,-CACHE_DLINE_SIZE(ta1) # dcache 1 way 0
|
|
cache CACH_PD|C_IWBINV,-CACHE_DLINE_SIZE+1(ta1) # dcache 1 way 1
|
|
cache CACH_PD|C_IWBINV,-(2*CACHE_DLINE_SIZE)(ta1) # dcache 2 way 0
|
|
cache CACH_PD|C_IWBINV,-(2*CACHE_DLINE_SIZE)+1(ta1) # dcache 2 way 1
|
|
cache CACH_PI|C_IINV,-CACHE_ILINE_SIZE(ta1) # icache way 0
|
|
bltu ta1,ta2,2b
|
|
cache CACH_PI|C_IINV,-CACHE_ILINE_SIZE+1(ta1) # BDSLOT way 1
|
|
.set reorder
|
|
3:
|
|
#if CACHE_ILINE_SIZE != (2*CACHE_DLINE_SIZE)
|
|
#error R10000 CACHE_ILINE_SIZE != (2*CACHE_DLINE_SIZE)
|
|
#endif
|
|
#endif /* R10000 */
|
|
|
|
.set noreorder
|
|
1:
|
|
cache CACH_SD|C_IWBINV,0(t0) # writeback + inval 2nd cache lines
|
|
#ifdef R10000
|
|
cache CACH_SD|C_IWBINV,1(t0) # writeback + inval 2nd (way 1) lines
|
|
#endif
|
|
bltu t0,ta0,1b
|
|
PTR_ADDU t0,SCACHE_LINESIZE # BDSLOT
|
|
.set reorder
|
|
|
|
#ifdef MH_R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,VPDA_PSCACHESIZE(zero)
|
|
.set reorder
|
|
#elif R10000 && !R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,-SCACHE_LINESIZE(t0)
|
|
.set reorder
|
|
#ifdef HEART_COHERENCY_WAR /* ensure flush to memory */
|
|
ld zero,PHYS_TO_COMPATK1(HEART_SYNC)
|
|
#endif
|
|
#endif
|
|
|
|
41:
|
|
#ifdef R4600SC_DEBUG
|
|
lw t9, _r4600sc_2nd_flush_error
|
|
or t9, (1<<19)
|
|
sw t9, _r4600sc_2nd_flush_error
|
|
#endif
|
|
|
|
j ra # restores cached mode.
|
|
END(__cache_wb_inval)
|
|
|
|
#endif /* !IP25 */
|
|
|
|
|
|
#if IP19 || IP25 || IP27
|
|
/*
|
|
* __cache_hwb_inval_pfn(poffset, len, pfn)
|
|
* Uses the HIT_WRITEBACK_INVALIDATE
|
|
* cacheops. Should be called with xkphys addresses, to avoid
|
|
* the tlb translation (and tlb miss fault) overhead.
|
|
*
|
|
*/
|
|
LEAF(__cache_hwb_inval_pfn)
|
|
#if _MIPS_SIM != _ABI64
|
|
.set noreorder
|
|
MFC0(t3,C0_SR)
|
|
.set reorder
|
|
#endif
|
|
dsll a2,PNUMSHFT
|
|
lui t0,0xa800 /* cacheable, coh. excl on write */
|
|
dsll t0,32 /* t0 = 0xa800000000000000 */
|
|
dadd a2,t0
|
|
dadd t0,a0,a2 /* t0 = 64 bit starting address */
|
|
lw ta0,VPDA_PSCACHESIZE(zero)
|
|
#if _MIPS_SIM != _ABI64
|
|
/* Not normally running in 64-bit mode, so turn it on.
|
|
* Don't need to restore original state since no real harm in
|
|
* running the kernel in 64-bit mode.
|
|
*/
|
|
ori t3,SR_KX /* enable 64 bit addressing */
|
|
.set noreorder
|
|
MTC0(t3,C0_SR)
|
|
.set reorder
|
|
#endif
|
|
|
|
# align the starting address to a 2nd cache line
|
|
#if IP25
|
|
and t2,t0,ICACHE_LINEMASK
|
|
#else
|
|
and t2,t0,SCACHE_LINEMASK
|
|
#endif
|
|
bltu ta0,a1,1f # 2nd cache is smaller than count
|
|
move ta0,a1
|
|
1:
|
|
daddu ta0,t0 # ending addr + 1
|
|
dsubu t0,t2 # line-align
|
|
1:
|
|
.set noreorder
|
|
#if IP25
|
|
#if ICACHE_LINESIZE != (2*DCACHE_LINESIZE)
|
|
# error "Icache line size assumed 2 * dcache line size"
|
|
#endif
|
|
/*
|
|
* SCC (< REV E) can hang if we invalidate an scache line. So we
|
|
* work on the primary only.
|
|
*/
|
|
ICACHE(C_HINV, 0(t0))
|
|
DCACHE(C_HWBINV, 0(t0))
|
|
DCACHE(C_HWBINV, DCACHE_LINESIZE(t0))
|
|
.set reorder
|
|
daddu t0,ICACHE_LINESIZE
|
|
#else /* IP19 */
|
|
cache CACH_SD|C_HWBINV,0(t0) # writeback + inval 2nd cache lines
|
|
.set reorder
|
|
daddu t0,SCACHE_LINESIZE
|
|
#endif
|
|
bltu t0,ta0,1b
|
|
|
|
j ra # restores cached mode.
|
|
END(__cache_hwb_inval_pfn)
|
|
#endif /* IP19 || IP25 || IP27 */
|
|
|
|
/*
|
|
* Config_cache() -- determine sizes of i and d caches
|
|
* Sizes stored in globals picache_size, pdcache_size, icache_size
|
|
* and dcache_size.
|
|
* For R4000, 2nd cache size stored in global boot_sidcache_size.
|
|
* Determines size of secondary cache - assumes 2nd cache is
|
|
* data or unified I+D.
|
|
* Can be extended to look for 2nd instruction
|
|
* cache by reading the config register. By definition, if 2nd
|
|
* cache is present and 'split', then both secondary caches are
|
|
* the same size.
|
|
*/
|
|
|
|
#define MIN_CACH_POW2 12
|
|
|
|
CFGLOCALSZ= 4 # Save ra, s0, s1, s1
|
|
CFGFRM= FRAMESZ((NARGSAVE+CFGLOCALSZ)*SZREG)
|
|
CFGRAOFF= CFGFRM-(1*SZREG)
|
|
CFGS0OFF= CFGFRM-(2*SZREG)
|
|
CFGS1OFF= CFGFRM-(3*SZREG)
|
|
CFGS2OFF= CFGFRM-(4*SZREG)
|
|
|
|
NESTED(config_cache, CFGFRM, zero)
|
|
PTR_SUBU sp,CFGFRM
|
|
REG_S ra,CFGRAOFF(sp)
|
|
REG_S s0,CFGS0OFF(sp) # save s0 on stack
|
|
REG_S s1,CFGS1OFF(sp) # save s1 on stack
|
|
REG_S s2,CFGS2OFF(sp) # save s2 on stack
|
|
.set noreorder
|
|
MFC0(s0,C0_SR) # save SR
|
|
NOP_1_1 # get thru pipe before we zero it
|
|
NOINTS(t0,C0_SR) # disable interrupts
|
|
|
|
# Size primary instruction cache.
|
|
NOP_0_1 # required between mtco/mfc0
|
|
mfc0 t0,C0_CONFIG
|
|
.set reorder
|
|
#if R4000 && R10000
|
|
.set noreorder
|
|
mfc0 t3,C0_PRID
|
|
NOP_0_4
|
|
.set reorder
|
|
andi t3,C0_IMPMASK
|
|
subu t3,(C0_IMP_R5000 << C0_IMPSHIFT)
|
|
beqz t3,72f
|
|
subu t3,((C0_IMP_RM5271 << C0_IMPSHIFT)-(C0_IMP_R5000 << C0_IMPSHIFT))
|
|
beqz t3,72f
|
|
|
|
and t1,t0,CONFIG_R10K_IC
|
|
srl t1,CONFIG_R10K_IC_SHFT
|
|
addi t1,MIN_CACH_POW2
|
|
li t2,1
|
|
sll t2,t1
|
|
sw t2,picache_size
|
|
|
|
# Size primary data cache.
|
|
and t1,t0,CONFIG_R10K_DC
|
|
srl t1,CONFIG_R10K_DC_SHFT
|
|
addi t1,MIN_CACH_POW2
|
|
b 73f
|
|
#endif
|
|
72:
|
|
and t1,t0,CONFIG_IC
|
|
srl t1,CONFIG_IC_SHFT
|
|
addi t1,MIN_CACH_POW2
|
|
li t2,1
|
|
sll t2,t1
|
|
sw t2,picache_size
|
|
|
|
# Size primary data cache.
|
|
and t1,t0,CONFIG_DC
|
|
srl t1,CONFIG_DC_SHFT
|
|
addi t1,MIN_CACH_POW2
|
|
73:
|
|
li t2,1
|
|
sll t2,t1
|
|
sw t2,pdcache_size
|
|
|
|
li t2,SCACHE_LINEMASK
|
|
sw t2,scache_linemask
|
|
|
|
#if IP19
|
|
/* Determine CPU # and pick up cache size from our MPCONF block */
|
|
jal get_mpconf
|
|
lw t0,MP_SCACHESZ(v0) # cache size (sorta)
|
|
li v0,1
|
|
sll v0,t0 # Cache size in bytes
|
|
|
|
.set noreorder
|
|
#endif /* IP19 */
|
|
|
|
#if (!(defined(R10000) && !defined(R4000)))
|
|
#ifdef R10000
|
|
bnez t3,74f
|
|
#endif /* R10000 */
|
|
#ifndef IP19
|
|
LA v0,1f
|
|
#if _MIPS_SIM == _ABI64
|
|
xor v0,K0BASE
|
|
#endif
|
|
or v0,SEXT_K1BASE
|
|
.set noreorder
|
|
j v0 # run uncached
|
|
nop
|
|
|
|
1: jal size_2nd_cache
|
|
nop
|
|
#endif /* IP19 */
|
|
# v0 has the size of the secondary (data or unified) cache.
|
|
sw v0,boot_sidcache_size
|
|
.set reorder
|
|
#ifdef R4000PC
|
|
bnez v0, 3f
|
|
lw t0,picache_size
|
|
lw t1,pdcache_size
|
|
sw t0,icache_size
|
|
sw t1,dcache_size
|
|
srl t3,t1,PNUMSHFT
|
|
#ifdef R4600
|
|
.set noreorder
|
|
mfc0 t2,C0_PRID
|
|
NOP_0_4
|
|
.set reorder
|
|
andi t2,C0_IMPMASK
|
|
subu t2,(C0_IMP_R4600 << C0_IMPSHIFT)
|
|
beqz t2,4f
|
|
subu t2,((C0_IMP_R4700 << C0_IMPSHIFT)-(C0_IMP_R4600 << C0_IMPSHIFT))
|
|
#ifdef TRITON
|
|
beqz t2,4f
|
|
subu t2,((C0_IMP_TRITON << C0_IMPSHIFT)-(C0_IMP_R4700 << C0_IMPSHIFT))
|
|
beqz t2,4f
|
|
subu t2,((C0_IMP_RM5271 << C0_IMPSHIFT)-(C0_IMP_TRITON << C0_IMPSHIFT))
|
|
#endif /* TRITON */
|
|
bnez t2,5f
|
|
4:
|
|
srl t2,t1,1
|
|
sw t2,two_set_pcaches
|
|
srl t3,t2,PNUMSHFT
|
|
5:
|
|
#endif
|
|
sw t3,cachecolorsize
|
|
subu t3,1
|
|
sw t3,cachecolormask
|
|
j 2f
|
|
|
|
3:
|
|
#endif
|
|
sw v0,icache_size
|
|
sw v0,dcache_size
|
|
|
|
#ifdef R4600SC
|
|
.set noreorder
|
|
mfc0 t2,C0_PRID
|
|
NOP_0_4
|
|
.set reorder
|
|
andi t2,C0_IMPMASK
|
|
subu t2,(C0_IMP_R4600 << C0_IMPSHIFT)
|
|
beqz t2,41f
|
|
subu t2,((C0_IMP_R4700 << C0_IMPSHIFT)-(C0_IMP_R4600 << C0_IMPSHIFT))
|
|
#ifdef TRITON
|
|
beqz t2,41f
|
|
subu t2,((C0_IMP_TRITON << C0_IMPSHIFT)-(C0_IMP_R4700 << C0_IMPSHIFT))
|
|
beqz t2,41f
|
|
subu t2,((C0_IMP_RM5271 << C0_IMPSHIFT)-(C0_IMP_TRITON << C0_IMPSHIFT))
|
|
#endif /* TRITON */
|
|
bnez t2,2f
|
|
41:
|
|
jal _r4600sc_enable_scache
|
|
lw t1,pdcache_size
|
|
li t3,R4600_SCACHE_LINEMASK
|
|
sw t3,scache_linemask
|
|
b 4b
|
|
#endif
|
|
|
|
#ifdef R4000PC
|
|
2:
|
|
#endif
|
|
.set noreorder
|
|
#ifndef EVEREST
|
|
LA t0,1f
|
|
j t0 # back to cached mode
|
|
nop
|
|
#endif
|
|
#else /* R10000 */
|
|
.set noreorder
|
|
#endif /* R10000 */
|
|
|
|
74:
|
|
1: MTC0(s0,C0_SR) # restore SR
|
|
.set reorder
|
|
REG_L s2,CFGS2OFF(sp) # restore old s2
|
|
REG_L s1,CFGS1OFF(sp) # restore old s1
|
|
REG_L s0,CFGS0OFF(sp) # restore old s0
|
|
REG_L ra,CFGRAOFF(sp)
|
|
PTR_ADDU sp,CFGFRM
|
|
j ra
|
|
END(config_cache)
|
|
|
|
#if !IP19
|
|
/*
|
|
* size_2nd_cache()
|
|
* return size of current data cache
|
|
* called while running in uncached space.
|
|
*
|
|
* sizing secondary cache: (assumes running uncached, 2nd cache is
|
|
* a data or unified cache)
|
|
* 1: Load up the cache in powers of 2, from MINCACHE to MAXCACHE. Then
|
|
* each of these lines guarenteed to be valid (may cycle around the cache.)
|
|
* 2. do an index store tag zero to line 0 - this tag is guaranteed to be
|
|
* invalid for any address we use.
|
|
* 3. Starting at MINCACHE, do an index load tag. Continue until find the
|
|
* zero tag.
|
|
*
|
|
* XXX: for R4600 we read the cache size from the EEROM. If it is an R4600PC
|
|
* register 17 in the EEROM will contain zeros, otherwise it will contain
|
|
* the cache size in pages for an R4600SC.
|
|
*/
|
|
LEAF(size_2nd_cache)
|
|
#ifdef R4600SC
|
|
.set noreorder
|
|
mfc0 t0,C0_PRID # get processor ID
|
|
NOP_0_4
|
|
.set reorder
|
|
and t0,C0_IMPMASK
|
|
subu t0,(C0_IMP_R4600 << C0_IMPSHIFT)
|
|
beqz t0,6f
|
|
subu t0,((C0_IMP_R4700 << C0_IMPSHIFT)-(C0_IMP_R4600 << C0_IMPSHIFT))
|
|
#ifdef TRITON
|
|
beqz t0,6f
|
|
subu t0,((C0_IMP_TRITON << C0_IMPSHIFT)-(C0_IMP_R4700 << C0_IMPSHIFT))
|
|
beqz t0,4f
|
|
subu t0,((C0_IMP_RM5271 << C0_IMPSHIFT)-(C0_IMP_TRITON << C0_IMPSHIFT))
|
|
bnez t0,1f
|
|
4:
|
|
.set noreorder
|
|
mfc0 t0,C0_CONFIG
|
|
nop
|
|
and v0,t0,CONFIG_TR_SC
|
|
#ifdef TRITON_INDYSC
|
|
bnez v0,6f
|
|
#else /* TRITON_INDYSC */
|
|
bnez v0,2f
|
|
#endif /* TRITON_INDYSC */
|
|
and v0,zero
|
|
.set reorder
|
|
and t0,CONFIG_TR_SS
|
|
srl t0,CONFIG_TR_SS_SHFT
|
|
li v0,512*1024
|
|
sll v0,t0
|
|
b 2f
|
|
#else /* TRITON */
|
|
bnez t0,1f
|
|
#endif /* TRITON */
|
|
6:
|
|
#if IP22
|
|
li t0,1
|
|
sw t0,early_delay_flag
|
|
li t0,EEROM # yes --> get cache size from EEROM
|
|
lw s1,cpu_auxctl
|
|
move s2,ra
|
|
sw t0,cpu_auxctl
|
|
li a0,CACHESZ_REG # we want the 18th halfword
|
|
jal get_nvreg # get cache size from EEROM, 4K page
|
|
li t0,0
|
|
sw t0,early_delay_flag
|
|
sw s1,cpu_auxctl
|
|
sll v0,BPCSHIFT # cache size in bytes
|
|
move ra,s2 # restore old ra
|
|
#else /* IP22 */
|
|
move v0,zero
|
|
#endif /* IP22 */
|
|
b 2f
|
|
#endif /* R4600SC */
|
|
|
|
#ifndef R10000
|
|
# R10000 always has a secondary cache.
|
|
.set noreorder
|
|
1:
|
|
mfc0 t0,C0_CONFIG
|
|
.set reorder
|
|
and t0,CONFIG_SC # 0 -> 2nd cache present
|
|
beq t0,zero,1f
|
|
move v0,zero # No second cache
|
|
j ra
|
|
#endif
|
|
1:
|
|
li v0,MINCACHE # If MINCACHE == MAXCACHE, just
|
|
li t0,MAXCACHE # return that
|
|
bne t0,v0,1f
|
|
j ra
|
|
1:
|
|
# Load valid tags at each cache boundary up to MAXCACHE.
|
|
# v0 has MINCACHE value.
|
|
1:
|
|
LI t2,K0_CACHEFLUSHBASE
|
|
PTR_ADDU t2,v0
|
|
lw zero,0(t2)
|
|
PTR_SLL v0,1
|
|
ble v0,MAXCACHE,1b
|
|
|
|
# Invalidate cache tag at 0th index in all caches.
|
|
# Invalidating the primaries insures that we do not
|
|
# create a non-subset of the secondary cache in
|
|
# either of the primary caches.
|
|
.set noreorder
|
|
mtc0 zero,C0_TAGLO
|
|
mtc0 zero,C0_TAGHI
|
|
LI t0,K0_CACHEFLUSHBASE # LDSLOT
|
|
li v0,MINCACHE # LDSLOT
|
|
cache CACH_PI|C_IST,0(t0)
|
|
cache CACH_PD|C_IST,0(t0)
|
|
cache CACH_SD|C_IST,0(t0)
|
|
.set reorder
|
|
|
|
# Now loop until that tag is found
|
|
# v0 - MINCACHE
|
|
1:
|
|
LI t0,K0_CACHEFLUSHBASE # Reload K0_CACHEFLUSHBASE for each iteration.
|
|
PTR_ADDU t0,v0
|
|
.set noreorder
|
|
cache CACH_SD|C_ILT,0(t0)
|
|
NOP_0_3
|
|
mfc0 t1,C0_TAGLO
|
|
.set reorder
|
|
beq t1,zero,2f # Found the marker
|
|
PTR_SLL v0,1 # Next power of 2
|
|
blt v0,MAXCACHE,1b # Iterate until MAXCACHE
|
|
2:
|
|
#if defined(R10000) && !defined(R4000)
|
|
sll v0,1 # double the size as there are 2 sets
|
|
#endif
|
|
j ra
|
|
END(size_2nd_cache)
|
|
#endif
|
|
|
|
#if IP20
|
|
/*
|
|
* rmi_cacheflush(addr,len)
|
|
*/
|
|
LEAF(rmi_cacheflush)
|
|
#define RMI_CACHEMASK 0xfffff # Mask for 1 meg cache
|
|
#define RMI_LOWLIMIT 0x8000 # 32k
|
|
/* start = megmask(start) */
|
|
beq a1,zero,2f # return quietly if length = 0
|
|
|
|
li t0,RMI_CACHEMASK
|
|
and t0,a0
|
|
#---------------------------------------------------
|
|
/* Here is the algorithm:
|
|
* if (start >= 32k)
|
|
* flush(start, end)
|
|
* return
|
|
* else if (start < 32k && start + count > 32k)
|
|
* count = count - (32k - start)
|
|
* end = PHYS_TO_K0(32k) + 1meg
|
|
* start = PHYS_TO_K0(start) + 1meg
|
|
* flush(start, end)
|
|
* flush(K0(32k), K0(count))
|
|
* return
|
|
* else ( start < 32k && start + count <= 32k)
|
|
* start = K0(start) + 1meg
|
|
* end = K0(end) + 1meg
|
|
* flush(start, end)
|
|
* return
|
|
*/
|
|
/* if (start >= 32k) goto normal_flush; */
|
|
move ta1,zero # only 1 iteration
|
|
li ta0,RMI_LOWLIMIT
|
|
bge t0,ta0,normal_flush
|
|
|
|
/* else if (start < 32k && start + count > 32k) goto splitflush */
|
|
|
|
addu ta1,t0,a1 # ta1 = start + count
|
|
bgt ta1,ta0,splitflush
|
|
|
|
/* it must be true that start < 32k && start + count <= 32k */
|
|
move ta1,zero # only 1 iteration
|
|
addu t0,0x100000
|
|
b normal_flush
|
|
|
|
splitflush:
|
|
/* start < 32k && start + count > 32k */
|
|
/* Flush from start to 32k */
|
|
subu ta2,ta0,t0 # 32k - start
|
|
subu ta2,a1,ta2 # save modified count in ta2
|
|
li ta1,1 # 2 iterations
|
|
li a1,RMI_LOWLIMIT # flush from start to 32k
|
|
addu t0,0x100000
|
|
b normal_flush
|
|
comebackhere:
|
|
/* Now flush from 32k to ending address */
|
|
li t0,RMI_LOWLIMIT
|
|
move a1,ta2
|
|
move ta1,zero # no more passes
|
|
|
|
normal_flush:
|
|
#---------------------------------------------------
|
|
or t0,_S_EXT_(K0_CACHEFLUSHBASE)
|
|
|
|
PTR_ADDU t1,t0,a1 # ending address + 1
|
|
bgeu t0,t1,3f # paranoid
|
|
|
|
# check and align starting address
|
|
and t2,t0,SCACHE_LINEMASK
|
|
PTR_SUBU t0,t2
|
|
|
|
1: # top of loop
|
|
lw zero,0(t0) # wb secondary line
|
|
PTR_ADDU t0,SCACHE_LINESIZE
|
|
bltu t0,t1,1b
|
|
|
|
#---------------------------------------------------
|
|
bne ta1,zero,comebackhere # another iteration?
|
|
#---------------------------------------------------
|
|
|
|
2:
|
|
j ra
|
|
3:
|
|
PTR_L sp,VPDA_LBOOTSTACK(zero)
|
|
ASMASSFAIL("Bad args to rmi_cacheflush");
|
|
/* NOTREACHED */
|
|
END(rmi_cacheflush)
|
|
#endif /* IP20 */
|
|
|
|
|
|
/* _c_hwb(which_cache, k0addr): hit writeback specified cache.
|
|
* a0: which_cache: CACH_PI, CACH_PD, or CACH_SD (CACH_SI illegal).
|
|
* a1: K0 address of line to writeback.
|
|
* if called for CACH_SI return -1, if for 2ndary data cache
|
|
* return SR_CH bit, else return 0.
|
|
*/
|
|
LEAF(_c_hwb)
|
|
move v0, zero
|
|
li t0, CACH_PD
|
|
bltu a0, t0, 3f # writeback primary i-cache tag
|
|
beq a0, t0, 4f # primary d-cache tag
|
|
li t0, CACH_SI # 2nd i-cache illegal for hwb
|
|
beq a0, t0, 2f # return error
|
|
.set noreorder
|
|
#ifdef R10000
|
|
cache CACH_SD|C_HWBINV, 0(a1) # inval secondary (I|D) cache tag
|
|
#else /* R10000 */
|
|
cache CACH_SD|C_HWB, 0(a1) # inval secondary (I|D) cache tag
|
|
#endif /* R10000 */
|
|
NOP_0_4
|
|
MFC0(v0, C0_SR) # check if we hit the 2ndary cache
|
|
NOP_0_4
|
|
and v0, SR_CH
|
|
.set reorder
|
|
|
|
1: # hwbout:
|
|
j ra
|
|
|
|
2: # hwbsi:
|
|
li v0, -1
|
|
b 1b
|
|
|
|
3: # hwbpi:
|
|
.set noreorder
|
|
#ifdef R10000
|
|
cache CACH_PI|C_HWBINV, 0(a1) # writeback primary icache tag if hit
|
|
#else /* R10000 */
|
|
cache CACH_PI|C_HWB, 0(a1) # writeback primary icache tag if hit
|
|
#endif /* R10000 */
|
|
.set reorder
|
|
b 1b
|
|
|
|
4: # hwbpd:
|
|
#ifdef R4600
|
|
PD_REFILL_WAIT(cacheops_refill_4)
|
|
#endif
|
|
.set noreorder
|
|
#ifdef R10000
|
|
cache CACH_PD|C_HWBINV, 0(a1) # primary data cache tag
|
|
#else /* R10000 */
|
|
cache CACH_PD|C_HWB, 0(a1) # primary data cache tag
|
|
#endif /* R10000 */
|
|
.set reorder
|
|
b 1b
|
|
END(_c_hwb)
|
|
|
|
|
|
/* NOTE: this routine is called only by force_ecc, which needs it to
|
|
* force the desired data ecc/parity value into the cache line. It
|
|
* isn't used by the ecc handler, so any ecc errors caused by the RMI
|
|
* write bug are acceptable. Please don't change it to use the
|
|
* RMI workaround method (flush by reading addr one cache-size away) */
|
|
|
|
/* _c_hwbinv(which_cache, k0addr): hit writeback invalidate specified cache.
|
|
* a0: which_cache: CACH_PD or CACH_SD (icaches illegal).
|
|
* a1: K0 address of line to writeback invalidate.
|
|
* if called for CACH_SI or CACH_PI return -1, if for 2ndary data cache
|
|
* return SR_CH bit, else return 0.
|
|
*/
|
|
LEAF(_c_hwbinv)
|
|
move v0, zero
|
|
li t0, CACH_PD
|
|
bltu a0, t0, 2f # wb primary i-cache tag: illegal
|
|
beq a0, t0, 4f # primary d-cache tag
|
|
li t0, CACH_SI # 2nd i-cache illegal for hwb
|
|
beq a0, t0, 3f # return error
|
|
.set noreorder
|
|
cache CACH_SD|C_HWBINV, 0(a1)
|
|
NOP_0_4
|
|
MFC0(v0, C0_SR) # check if we hit the 2ndary cache
|
|
NOP_0_4
|
|
and v0, SR_CH
|
|
.set reorder
|
|
|
|
1: # hwbiout:
|
|
j ra
|
|
|
|
2: # hwbipi:
|
|
3: # hwbisi:
|
|
li v0, -1
|
|
b 1b
|
|
|
|
4: # hwbipd:
|
|
#ifdef R4600
|
|
PD_REFILL_WAIT(cacheops_refill_5)
|
|
#endif
|
|
.set noreorder
|
|
cache CACH_PD|C_HWBINV, 0(a1)
|
|
.set reorder
|
|
b 1b
|
|
END(_c_hwbinv)
|
|
|
|
|
|
/* _c_hinv(which_cache, k0addr): hit invalidate specified cache.
|
|
* a0: which_cache: CACH_PI, CACH_PD, CACH_SI, or CACH_SD.
|
|
* a1: K0 address of line to invalidate.
|
|
* if called for 2ndary, return SR_CH bit, else return 0.
|
|
*/
|
|
LEAF(_c_hinv)
|
|
move v0, zero
|
|
li t0, CACH_PD
|
|
bltu a0, t0, 2f # invalidate primary i-cache tag
|
|
beq a0, t0, 3f # primary d-cache tag
|
|
.set noreorder
|
|
cache CACH_SD|C_HINV, 0(a1) # inval secondary (I|D) cache tag
|
|
NOP_0_4
|
|
MFC0(v0, C0_SR) # check if we hit the 2ndary cache
|
|
NOP_0_4
|
|
and v0, SR_CH
|
|
.set reorder
|
|
|
|
1: # hiout:
|
|
j ra
|
|
|
|
2: # hiprimi:
|
|
.set noreorder
|
|
cache CACH_PI|C_HINV, 0(a1) # fetch primary instruction cache tag
|
|
.set reorder
|
|
b 1b
|
|
|
|
3: # hiprimd:
|
|
#ifdef R4600
|
|
PD_REFILL_WAIT(cacheops_refill_6)
|
|
#endif
|
|
.set noreorder
|
|
cache CACH_PD|C_HINV, 0(a1) # fetch primary data cache tag
|
|
.set reorder
|
|
b 1b
|
|
END(_c_hinv)
|
|
|
|
|
|
/* _c_ilt_n_ecc(cache,k0addr,tagptr,&ecc):
|
|
* load tag & data ecc from specified cache.
|
|
* a0: which_cache: CACH_PI, CACH_PD, CACH_SI, or CACH_SD.
|
|
* a1: K0 address of line.
|
|
* a2: ptr to 2 uints (taglo [0] and taghi [1]).
|
|
* a3: ptr to uint (data ecc).
|
|
*/
|
|
LEAF(_c_ilt_n_ecc)
|
|
move v0, zero
|
|
li t0, CACH_PD
|
|
bltu a0, t0, 2f # fetch primary i-cache tag
|
|
beq a0, t0, 3f # primary d-cache tag
|
|
.set noreorder
|
|
cache CACH_SD|C_ILT, 0(a1) # secondary (I|D) cache tag
|
|
.set reorder
|
|
|
|
1: # iltnout:
|
|
.set noreorder
|
|
NOP_0_4
|
|
mfc0 t0, C0_TAGLO
|
|
NOP_0_4
|
|
mfc0 t1, C0_ECC
|
|
NOP_0_4
|
|
.set reorder
|
|
sw t0, 0(a2)
|
|
sw t1, 0(a3)
|
|
j ra
|
|
|
|
2: # iltnpi:
|
|
.set noreorder
|
|
cache CACH_PI|C_ILT, 0(a1)
|
|
.set reorder
|
|
b 1b
|
|
|
|
3: # iltnpd:
|
|
.set noreorder
|
|
cache CACH_PD|C_ILT, 0(a1)
|
|
.set reorder
|
|
b 1b
|
|
END(_c_ilt_n_ecc)
|
|
|
|
|
|
/* _c_ilt(cache,k0addr,tagptr): load tag from specified cache-line.
|
|
* a0: which_cache: CACH_PI, CACH_PD, CACH_SI, or CACH_SD.
|
|
* a1: K0 address of line.
|
|
* a2: ptr to 2 uints (taglo [0] and taghi [1]).
|
|
*/
|
|
LEAF(_c_ilt)
|
|
move v0, zero
|
|
li t0, CACH_PD
|
|
bltu a0, t0, 2f # fetch primary i-cache tag
|
|
beq a0, t0, 3f # primary d-cache tag
|
|
.set noreorder
|
|
cache CACH_SD|C_ILT, 0(a1) # secondary (I|D) cache tag
|
|
.set reorder
|
|
|
|
1: # iltout:
|
|
.set noreorder
|
|
NOP_0_4
|
|
CACHE_BARRIER # should be ok, but not perf path
|
|
mfc0 t0, C0_TAGLO
|
|
NOP_0_4
|
|
sw t0, 0(a2)
|
|
.set reorder
|
|
j ra
|
|
|
|
2: # iltpi:
|
|
.set noreorder
|
|
cache CACH_PI|C_ILT, 0(a1)
|
|
.set reorder
|
|
b 1b
|
|
|
|
3: # iltpd:
|
|
.set noreorder
|
|
cache CACH_PD|C_ILT, 0(a1)
|
|
.set reorder
|
|
b 1b
|
|
END(_c_ilt)
|
|
|
|
|
|
/* _c_ist(which_cache,k0addr,tagptr): store tag to specified cache.
|
|
* a0: which_cache: CACH_PI, CACH_PD, CACH_SI, or CACH_SD.
|
|
* a1: K0 address of line.
|
|
* a2: ptr to 2 uints (taglo and taghi).
|
|
* tagptr[0] = taglo, uintptr[1] = taghi
|
|
*/
|
|
LEAF(_c_ist)
|
|
move v0, zero
|
|
lw t1, 0(a2)
|
|
.set noreorder
|
|
NOP_0_4
|
|
mtc0 t1, C0_TAGLO
|
|
.set reorder
|
|
li t0, CACH_PD
|
|
bltu a0, t0, 1f # store primary i-cache tag
|
|
beq a0, t0, 2f # primary d-cache tag
|
|
.set noreorder
|
|
NOP_0_2
|
|
cache CACH_SD|C_IST, 0(a1) # store secondary (I|D) cache tag
|
|
.set reorder
|
|
j ra
|
|
|
|
1: # istpi:
|
|
.set noreorder
|
|
NOP_0_2
|
|
cache CACH_PI|C_IST, 0(a1)
|
|
.set reorder
|
|
j ra
|
|
|
|
2: # istpd:
|
|
.set noreorder
|
|
NOP_0_2
|
|
cache CACH_PD|C_IST, 0(a1)
|
|
.set reorder
|
|
j ra
|
|
END(_c_ist)
|
|
|
|
|
|
#ifndef R10000
|
|
/* pi_fill(vaddr): load P icache with instruction line
|
|
* a0: vaddr
|
|
*/
|
|
LEAF(_pi_fill)
|
|
.set noreorder
|
|
cache CACH_PI|C_FILL, 0(a0)
|
|
NOP_0_2
|
|
.set reorder
|
|
j ra
|
|
END(_pi_fill)
|
|
#endif
|
|
|
|
|
|
LEAF(getecc)
|
|
.set noreorder
|
|
mfc0 v0,C0_ECC # get the current ECC value
|
|
.set reorder
|
|
j ra
|
|
END(getecc)
|
|
|
|
LEAF(setecc)
|
|
.set noreorder
|
|
mtc0 a0,C0_ECC # set the ECC register
|
|
.set reorder
|
|
j ra
|
|
END(setecc)
|
|
|
|
|
|
#if _MIPS_SIM != _ABI64
|
|
LEAF(runcached)
|
|
PTR_SUBU v0,ra,K0SIZE
|
|
1: j v0
|
|
END(runcached)
|
|
|
|
LEAF(uncached)
|
|
PTR_ADDU v0,ra,K0SIZE
|
|
1: j v0
|
|
END(uncached)
|
|
#else
|
|
LEAF(runcached)
|
|
#ifdef R10000
|
|
|
|
dsll v0,ra,7 /* First shift region/cache/attribute bits */
|
|
dsrl v0,7
|
|
|
|
#else /* !R10000 */
|
|
|
|
dsll v0,ra,5 /* First shift off region/cache bits */
|
|
dsrl v0,5
|
|
|
|
#endif /* !R10000 */
|
|
|
|
PTR_ADDU v0,K0BASE /* then add K0BASE */
|
|
1: j v0
|
|
END(runcached)
|
|
|
|
LEAF(uncached)
|
|
#ifdef R10000
|
|
|
|
dsll v0,ra,7 /* First shift region/cache/attribute bits */
|
|
dsrl v0,7
|
|
|
|
#else /* !R10000 */
|
|
|
|
dsll v0,ra,5 /* First shift off region/cache bits */
|
|
dsrl v0,5
|
|
|
|
#endif /* !R10000 */
|
|
|
|
PTR_ADDU v0,K1BASE /* then add K1BASE */
|
|
1: j v0
|
|
END(uncached)
|
|
#endif
|
|
|
|
|
|
/* _munge_decc(c_addr, status_reg): force the contents of the ECC register
|
|
* to be used in generating the checkbits for the double word of data
|
|
* at c_addr.
|
|
* a0: K0addr at which to force the bad checkbits
|
|
* a1: status register to use during the forced-write (must include SR_CE
|
|
* and NOT include SR_DE: the CE bit does not work when DE is set). In
|
|
* order to avoid unintentionally munging some i-cache checkbits interrupts
|
|
* had better be disabled and the kernel should be running uncached also
|
|
* (just during this munging operation).
|
|
*/
|
|
LEAF(_munge_decc)
|
|
#ifdef R4600
|
|
PD_REFILL_WAIT(cacheops_refill_7)
|
|
#endif
|
|
.set noreorder
|
|
MFC0(t1, C0_SR) # save current status register
|
|
NOP_0_4
|
|
MTC0(a1, C0_SR) # swap in specified sr
|
|
NOP_0_4
|
|
NOP_0_4
|
|
cache CACH_PD|C_HWBINV, 0(a0) # with CE bit set, this uses ECC reg
|
|
NOP_0_4
|
|
NOP_0_4
|
|
MTC0(t1, C0_SR) # restore orig status reg
|
|
NOP_0_4
|
|
NOP_0_4
|
|
.set reorder
|
|
j ra
|
|
END(_munge_decc)
|
|
|
|
|
|
/* _read_tag(WhichCache, address, &destination)
|
|
* WhichCache == CACH_PI, CACH_PD, CACH_SI, or CACH_SD.
|
|
* address may be in KUSER or K0SEG space.
|
|
* destination is a pointer to two uints.
|
|
* a0: WhichCache
|
|
* a1: address
|
|
* a2: destination ptr
|
|
*/
|
|
LEAF(_read_tag)
|
|
move v0, zero # success by default
|
|
li t0, CACH_PD
|
|
bltu a0, t0, 2f # fetch primary i-cache tag
|
|
beq a0, t0, 3f # primary d-cache tag
|
|
.set noreorder
|
|
cache CACH_SD|C_ILT, 0(a1) # fetch secondary (I|D) cache tag
|
|
.set reorder
|
|
|
|
1: # getout:
|
|
.set noreorder
|
|
nop
|
|
CACHE_BARRIER # should be ok, but not perf path
|
|
nop
|
|
mfc0 t0, C0_TAGLO
|
|
# DO NOT READ C0_TAGHI IN CURRENT IMPLEMENTATION OF R4K!
|
|
nop
|
|
nop
|
|
sw t0, 0(a2) # taglo is 1st uint in tag struct
|
|
# sw t1, 4(a2) # taghi is 2nd
|
|
.set reorder
|
|
j ra
|
|
|
|
2: # rprimi:
|
|
.set noreorder
|
|
cache CACH_PI|C_ILT, 0(a1) # fetch primary instruction cache tag
|
|
.set reorder
|
|
b 1b
|
|
|
|
3: # rprimd:
|
|
.set noreorder
|
|
cache CACH_PD|C_ILT, 0(a1) # fetch primary data cache tag
|
|
.set reorder
|
|
b 1b
|
|
|
|
END(_read_tag)
|
|
|
|
|
|
/* _write_tag(WhichCache, address, &source)
|
|
* WhichCache == CACH_PI, CACH_PD, CACH_SI, or CACH_SD.
|
|
* address may be in KUSER or K0SEG space.
|
|
* source is a pointer to two uints.
|
|
* a0: WhichCache
|
|
* a1: address
|
|
* a2: source ptr
|
|
*/
|
|
LEAF(_write_tag)
|
|
lw t0, 0(a2)
|
|
.set noreorder
|
|
mtc0 t0, C0_TAGLO # just set taglo
|
|
NOP_0_2
|
|
.set reorder
|
|
li t0, CACH_PD
|
|
bltu a0, t0, 2f # fetch primary i-cache tag
|
|
beq a0, t0, 3f # primary d-cache tag
|
|
.set noreorder
|
|
cache CACH_SD|C_IST, 0(a1) # set secondary (I|D) cache tag
|
|
.set reorder
|
|
|
|
1: # setout:
|
|
j ra
|
|
|
|
2: # wprimi:
|
|
.set noreorder
|
|
cache CACH_PI|C_IST, 0(a1) # set primary instruction cache tag
|
|
.set reorder
|
|
b 1b
|
|
|
|
3: # wprimd:
|
|
.set noreorder
|
|
cache CACH_PD|C_IST, 0(a1) # set primary data cache tag
|
|
.set reorder
|
|
b 1b
|
|
|
|
END(_write_tag)
|
|
|
|
LOCALSZ= 1 # save ra
|
|
CACHEFRM= FRAMESZ((NARGSAVE+LOCALSZ)*SZREG)
|
|
RAOFF= CACHEFRM-(1*SZREG)
|
|
|
|
/*
|
|
* flush_cache()
|
|
* flush entire I & D cache
|
|
*/
|
|
NESTED(flush_cache, CACHEFRM, zero)
|
|
PTR_SUBU sp,CACHEFRM
|
|
REG_S ra,RAOFF(sp)
|
|
LI a0, K0_CACHEFLUSHBASE
|
|
lw a1,VPDA_PSCACHESIZE(zero)
|
|
#ifdef R4000PC
|
|
bnez a1, 1f
|
|
lw a1, pdcache_size
|
|
#ifdef R4600
|
|
lw a2, two_set_pcaches
|
|
beqz a2,1f
|
|
move a1,a2
|
|
#endif /* R4600 */
|
|
1:
|
|
#endif /* R4000PC */
|
|
jal __cache_wb_inval
|
|
REG_L ra,RAOFF(sp)
|
|
PTR_ADDU sp,CACHEFRM
|
|
j ra
|
|
END(flush_cache)
|
|
|
|
#endif /* R4000 || R10000 */
|
|
|
|
|
|
#if IP19
|
|
LEAF(ip19_cache_init)
|
|
/*
|
|
* Routine: ip19_cache_init
|
|
* Purpose: Initialize the cache tags to a known "legal" state.
|
|
* Parameters: None
|
|
* Returns: Nothing
|
|
* Notes: This routine accomplishes its task in
|
|
* the following steps, and uses the CONFIG register and the
|
|
* MPCONF structure to determine the cache sizes.
|
|
*
|
|
* 1) Index write-back, invalidate on all secondary cache lines.
|
|
* This is required if symmon is running cached to be sure
|
|
* we don't lose any data. This in itself *COULD* cause a
|
|
* problem if the caches are not inited properly, but it
|
|
* appears to usually work - so if an older prom is installed,
|
|
* this makes things more likely to work.
|
|
* 2) Set all Primary data/instruction tags to contain a valid
|
|
* address but set the line invalid.
|
|
* 3) Set all secondary cache tags to contain a valid address,
|
|
* such that the primary cache tags are a subset of the
|
|
* secondary tags even though all are invalid.
|
|
*
|
|
*/
|
|
/* Get secondary cache size */
|
|
|
|
move a0,ra
|
|
jal get_mpconf /* ONLY KILLS T registers +v0/v1 */
|
|
move ra,a0
|
|
.set noreorder
|
|
|
|
lw t2,MP_SCACHESZ(v0) /* Secondary cache size - sorta */
|
|
|
|
LI v0,1
|
|
sll v0,t2 /* Size in bytes */
|
|
|
|
LI a0,K0BASE
|
|
PTR_ADDU a1,a0,v0 /* address of byte after last line */
|
|
|
|
LA t1,1f /* Set up to run uncached */
|
|
LI t2,TO_PHYS_MASK
|
|
and t1,t2
|
|
LI t2,K1BASE
|
|
or t1,t2
|
|
j t1 /* Bang - uncached */
|
|
nop
|
|
|
|
.align 7
|
|
.set noreorder
|
|
/* Flush cache */
|
|
|
|
1:
|
|
cache CACH_SD+C_IWBINV,0(a0)
|
|
bltu a0,a1,1b
|
|
PTR_ADDU a0,SCACHE_LINESIZE /* BDSLOT */
|
|
|
|
/* Write primary tags */
|
|
|
|
mfc0 t0,C0_CONFIG
|
|
and t0,CONFIG_IC
|
|
srl t0,CONFIG_IC_SHFT
|
|
add t0,12
|
|
li a1,1
|
|
sll a1,t0 /* IC size in a1 */
|
|
|
|
move a0,zero /* Start Address in a0 */
|
|
mtc0 zero,C0_TAGHI
|
|
1:
|
|
|
|
PTR_SRL a2,a0,12
|
|
PTR_SLL a2,8
|
|
mtc0 a2,C0_TAGLO
|
|
or a2,a0,K0BASE
|
|
cache CACH_PI+C_IST,0(a2)
|
|
PTR_ADD a0,ICACHE_LINESIZE /* Next cache line */
|
|
bltu a0,a1,1b
|
|
nop
|
|
|
|
mfc0 t0,C0_CONFIG
|
|
and t0,CONFIG_DC
|
|
srl t0,CONFIG_DC_SHFT
|
|
add t0,12
|
|
li a1,1
|
|
sll a1,t0 /* IC size in a1 */
|
|
|
|
move a0,zero /* Start Address in a0 */
|
|
mtc0 zero,C0_TAGHI
|
|
1:
|
|
|
|
PTR_SRL a2,a0,12
|
|
PTR_SLL a2,8
|
|
mtc0 a2,C0_TAGLO
|
|
or a2,a0,K0BASE
|
|
cache CACH_PD+C_IST,0(a2)
|
|
PTR_ADD a0,DCACHE_LINESIZE /* Next cache line */
|
|
bltu a0,a1,1b
|
|
nop
|
|
|
|
/* Write secondary tags */
|
|
|
|
move a0,zero
|
|
move a1,v0
|
|
1:
|
|
PTR_SRL a2,a0,17
|
|
PTR_SLL a2,13
|
|
PTR_SRL a3,a0,12
|
|
and a3,7
|
|
PTR_SLL a3,7
|
|
or a3,a2
|
|
mtc0 a3,C0_TAGLO
|
|
or a3,a0,K0BASE
|
|
cache CACH_SD+C_IST,0(a3)
|
|
PTR_ADDI a0,SCACHE_LINESIZE
|
|
bltu a0,a1,1b
|
|
nop
|
|
|
|
j ra /* Back to cached space */
|
|
nop
|
|
|
|
.align 7
|
|
|
|
END(ip19_cache_init)
|
|
#endif /* IP19 */
|
|
#if IP19 || SN0
|
|
/*
|
|
* __pdcache_inval(addr, len)
|
|
*
|
|
* invalidate data cache for range of physical addr to addr+len-1
|
|
* Routine can only be used on rev 2.0 or later R4400 (which is MAJ revision
|
|
* 5 in the C0_PRID).
|
|
*
|
|
* We use the HIT_INVALIDATE cache op. Therefore, this requires
|
|
* that 'addr'..'len' be the actual addresses which we want to
|
|
* invalidate in the caches.
|
|
* addr/len are not necessarily cache line aligned. Any lines
|
|
* partially covered by addr/len are written out with the
|
|
* HIT_WRITEBACK_INVALIDATE op.
|
|
*
|
|
* Invalidate lines in the primary dcache.
|
|
*
|
|
* XXX Assumes 32 byte line size for primary data cache.
|
|
* Returns 0 if cache was flushed, -1 otherwise.
|
|
*/
|
|
|
|
LEAF(__pdcache_wbinval)
|
|
#if R4000
|
|
/* Earliest version of R4400 has a chip problem which can cause
|
|
* scache corruption if you wb-inval a primary line.
|
|
*/
|
|
mfc0 t2,C0_PRID
|
|
NOP_0_4
|
|
andi t2,C0_MAJREVMASK
|
|
srl t2,C0_MAJREVSHIFT
|
|
li ta3,C0_MAJREVMIN_R4400 # min R4400 rev == 1.0
|
|
bgt t2,ta3,1f
|
|
li v0,-1
|
|
j ra
|
|
nop
|
|
1:
|
|
#endif
|
|
li v0,0
|
|
lw ta3,pdcache_size
|
|
sltu t2, ta3, a1 # size > dcache_size?
|
|
bnez t2, 102f # yes --> use indexed invalidate
|
|
move t0,a0
|
|
PTR_ADDU t1,a0,a1 # ending address + 1
|
|
bgeu t0,t1,3f # paranoid
|
|
PTR_SUBU t1,DCACHE_LINESIZE
|
|
|
|
# check and align starting and ending addresses.
|
|
and t2,t0,DCACHE_LINEMASK
|
|
beq t2,zero,1f # starting addr is aligned
|
|
|
|
# align the address to the start of the line
|
|
PTR_SUBU t0,t2
|
|
|
|
# 'hit writeback invalidate' the primary data line indicated
|
|
# by 'addr'.
|
|
.set noreorder
|
|
cache CACH_PD|C_HWBINV,0(t0) # writeback + inval
|
|
|
|
bgeu t0,t1,3f # Out if we are done
|
|
# align addr to the next line
|
|
PTR_ADDU t0,DCACHE_LINESIZE # BDSLOT
|
|
1:
|
|
# check if ending address is cache-line aligned.
|
|
and t2,t1,DCACHE_LINEMASK
|
|
beq t2,zero,1f # ending address is full cache line
|
|
PTR_SUBU t1,t2 # BDSLOT align to start of line
|
|
cache CACH_PD|C_HWBINV,DCACHE_LINESIZE(t1) # writeback + inval
|
|
PTR_ADDU t1,1
|
|
bgeu t0,t1,3f
|
|
nop # BDSLOT
|
|
|
|
1: # top of loop
|
|
cache CACH_PD|C_HWBINV,0(t0) # invalidate primary
|
|
|
|
bltu t0,t1,1b
|
|
PTR_ADDU t0,DCACHE_LINESIZE
|
|
.set reorder
|
|
3:
|
|
j ra
|
|
|
|
/* clean dcache using index invalidate */
|
|
102: LI t0, K0_CACHEFLUSHBASE # set up current address
|
|
PTR_ADDU t1, t0, ta3 # set up limit address
|
|
PTR_SUBU t1, DCACHE_LINESIZE # (base + scache_size - scache_linesize)
|
|
.set noreorder
|
|
3: cache CACH_PD|C_IWBINV, 0(t0) # Invalidate cache line
|
|
#ifdef R10000
|
|
3: cache CACH_PD|C_IWBINV, 1(t0) # Invalidate cache line (way 1)
|
|
#endif /* R10000 */
|
|
bltu t0, t1, 3b
|
|
PTR_ADDU t0, DCACHE_LINESIZE # BDSLOT increase invalidate address
|
|
.set reorder
|
|
j ra
|
|
END(__pdcache_wbinval)
|
|
/*
|
|
* __picache_inval(addr, len)
|
|
* invalidate data cache for range of physical addr to addr+len-1
|
|
*
|
|
* We use the HIT_INVALIDATE cache op. Therefore, this requires
|
|
* that 'addr'..'len' be the actual addresses which we want to
|
|
* invalidate in the caches.
|
|
* addr/len are not necessarily cache line aligned. Any lines
|
|
* partially covered by addr/len are written out with the
|
|
* HIT_WRITEBACK_INVALIDATE op.
|
|
*
|
|
* Invalidate lines in the primary icache.
|
|
*
|
|
* XXX Assumes 32 byte line size for primary data cache.
|
|
*/
|
|
|
|
LEAF(__picache_inval)
|
|
lw ta3,picache_size
|
|
sltu t2, ta3, a1 # size > dcache_size?
|
|
bnez t2, 102f # yes --> use indexed invalidate
|
|
move t0,a0
|
|
PTR_ADDU t1,a0,a1 # ending address + 1
|
|
bgeu t0,t1,3f # paranoid
|
|
PTR_SUBU t1,ICACHE_LINESIZE
|
|
|
|
# check and align starting and ending addresses.
|
|
and t2,t0,ICACHE_LINEMASK
|
|
beq t2,zero,1f # starting addr is aligned
|
|
|
|
# align the address to the start of the line
|
|
PTR_SUBU t0,t2
|
|
|
|
# 'hit writeback invalidate' the primary icache line indicated
|
|
# by 'addr'.
|
|
.set noreorder
|
|
cache CACH_PI|C_HWBINV,0(t0) # writeback + inval
|
|
|
|
bgeu t0,t1,3f # Out if we are done
|
|
# align addr to the next line
|
|
PTR_ADDU t0,ICACHE_LINESIZE # BDSLOT
|
|
1:
|
|
# check if ending address is cache-line aligned.
|
|
and t2,t1,ICACHE_LINEMASK
|
|
beq t2,zero,1f # ending address is full cache line
|
|
PTR_SUBU t1,t2 # BDSLOT align to start of line
|
|
cache CACH_PI|C_HINV,ICACHE_LINESIZE(t1) # writeback + inval
|
|
PTR_ADDU t1,1
|
|
bgeu t0,t1,3f
|
|
nop # BDSLOT
|
|
|
|
1: # top of loop
|
|
cache CACH_PI|C_HINV,0(t0) # invalidate primary
|
|
|
|
bltu t0,t1,1b
|
|
PTR_ADDU t0,ICACHE_LINESIZE
|
|
.set reorder
|
|
3:
|
|
j ra
|
|
|
|
/* clean dcache using index invalidate */
|
|
102: LI t0, K0_CACHEFLUSHBASE # set up current address
|
|
PTR_ADDU t1, t0, ta3 # set up limit address
|
|
PTR_SUBU t1, ICACHE_LINESIZE # (base + scache_size - scache_linesize)
|
|
.set noreorder
|
|
3: cache CACH_PI|C_IINV, 0(t0) # Invalidate cache line
|
|
#ifdef R10000
|
|
cache CACH_PI|C_IINV, 1(t0) # Invalidate cache line (way 1)
|
|
#endif
|
|
bltu t0, t1, 3b
|
|
PTR_ADDU t0, ICACHE_LINESIZE # BDSLOT increase invalidate address
|
|
.set reorder
|
|
j ra
|
|
END(__picache_inval)
|
|
#endif /* IP19 */
|
|
|
|
#if IP25
|
|
|
|
LEAF(__cache_exclusive)
|
|
/*
|
|
* Routine: __cache_exclusive
|
|
* Purpose: Perform opration to assure the cache line containing
|
|
* the passed address is owned exclusivly by calling CPU.
|
|
* This has the side affect of flushing any dirty data out
|
|
* of all other CPU's data caches.
|
|
* Parameters: a0 - address (arbitrary alignment).
|
|
* a1 - length (in bytes)
|
|
* Returns: nothing
|
|
*/
|
|
.set reorder
|
|
PTR_ADDU a1,a0 /* Ending line address */
|
|
and a0,CACHE_SLINE_MASK /* Starting line */
|
|
1:
|
|
ll a2,0(a0)
|
|
move a3,a2
|
|
sc a2,0(a0)
|
|
#ifdef R10K_LLSC_WAR
|
|
.set noreorder
|
|
beql a2,zero,1b
|
|
nop
|
|
.set reorder
|
|
#else
|
|
beqz a2,1b
|
|
#endif
|
|
PTR_ADDU a0,CACHE_SLINE_SIZE /* Next line please */
|
|
bltu a0,a1,1b
|
|
|
|
j ra
|
|
END(__cache_exclusive)
|
|
|
|
LEAF(__dcache_wb)
|
|
/*
|
|
* Routine: __dcache_wb
|
|
* Purpose: Write back the specified addresses from the primary
|
|
* dcache. Does not operate on secondary cache.
|
|
* Parameters: addr, len
|
|
* Returns: nothing
|
|
*/
|
|
PTR_ADDU a1,a0 /* ending line */
|
|
and a0, CACHE_DLINE_MASK /* Starting line */
|
|
|
|
1: .set noreorder
|
|
DCACHE(C_HWB, 0(a0))
|
|
.set reorder
|
|
PTR_ADDU a0, CACHE_DLINE_SIZE
|
|
bltu a0,a1,1b
|
|
j ra
|
|
END(__dcache_wb)
|
|
|
|
LEAF(__cache_wb_inval)
|
|
/*
|
|
* Routine: __cache_wb_inval
|
|
* Purpose: Flush and invalidate the specified memory from the primary
|
|
* caches.
|
|
* Parameters: a0 - address to flush/invalidate
|
|
* a1 - number of bytes
|
|
* Returns: nothing
|
|
*/
|
|
lw t0, pdcache_size
|
|
bgtu a1, t0, 2f
|
|
PTR_ADDU a1,a0 /* ending line */
|
|
and a0, CACHE_ILINE_MASK /* Starting line */
|
|
|
|
1: .set noreorder
|
|
ICACHE(C_HINV, 0(a0))
|
|
DCACHE(C_HWBINV, 0(a0))
|
|
DCACHE(C_HWBINV, CACHE_DLINE_SIZE(a0))
|
|
.set reorder
|
|
PTR_ADDU a0, CACHE_ILINE_SIZE
|
|
bltu a0,a1,1b
|
|
|
|
j ra
|
|
|
|
2: PTR_ADDU t0,a0 /* ending line */
|
|
and a0, CACHE_ILINE_MASK /* Starting line */
|
|
3: .set noreorder
|
|
ICACHE(C_IINV, 0(a0))
|
|
ICACHE(C_IINV, 1(a0))
|
|
DCACHE(C_IWBINV, 0(a0))
|
|
DCACHE(C_IWBINV, 1(a0))
|
|
DCACHE(C_IWBINV, CACHE_DLINE_SIZE(a0))
|
|
DCACHE(C_IWBINV, CACHE_DLINE_SIZE+1(a0))
|
|
.set reorder
|
|
PTR_ADDU a0, CACHE_ILINE_SIZE
|
|
bltu a0,t0,3b
|
|
|
|
j ra
|
|
|
|
END(__cache_wb_inval)
|
|
|
|
LEAF(__dcache_inval)
|
|
XLEAF(__dcache_wb_inval)
|
|
/*
|
|
* Routine: __dcache_inval
|
|
* Purpose: Flush and invalidate the specified region from the
|
|
* primary Dcache.
|
|
* Parameters: a0 - actuial virtual address to flush
|
|
* a1 - length in bytes.
|
|
* Returns: nothing.
|
|
*/
|
|
PTR_ADDU a1,a0 /* ending line */
|
|
and a0, CACHE_DLINE_MASK /* Starting line */
|
|
1: .set noreorder
|
|
DCACHE(C_HWBINV, 0(a0))
|
|
.set reorder
|
|
PTR_ADDU a0, CACHE_DLINE_SIZE
|
|
bltu a0,a1,1b
|
|
j ra
|
|
END(__dcache_inval)
|
|
|
|
#endif /* IP25 */
|
|
|
|
|
|
#if R10000
|
|
#if _MIPS_SIM != _ABI64
|
|
#define TO_COMPAT_PHYS_MASK TO_PHYS_MASK
|
|
#endif /* _MIPS_SIM != _ABI64 */
|
|
|
|
LEAF(cacheOP)
|
|
/*
|
|
* Routine: cacheOP
|
|
* Purpose: Perform a cache operation
|
|
* Parameters: a0 - cacheop_t * - pointer to cache op structure.
|
|
* Returns: v0 - undefined, for Load data, taghi, taglo, and ECC
|
|
* values filled in.
|
|
*/
|
|
.set noreorder
|
|
lw v0,COP_TAGLO(a0) /* First setup CP0 */
|
|
MTC0(v0, C0_TAGLO)
|
|
lw v0,COP_TAGHI(a0)
|
|
MTC0(v0, C0_TAGHI)
|
|
lw v0,COP_ECC(a0)
|
|
MTC0(v0, C0_ECC)
|
|
|
|
ld a1,COP_ADDRESS(a0) /* Address to use */
|
|
lw v1,COP_OP(a0) /* Operation */
|
|
dla v0,cacheOP_table
|
|
/*
|
|
* To ensure we access the cacheOP_table uncached during
|
|
* ecc errors, we pick the offset within the kernel to the
|
|
* cacheop table and use the significant bits from RA.
|
|
* Since ra could be pointing to compatibility space as well,
|
|
* the mask we use is COMPAT_PHYS_MASK. Since the kernel
|
|
* is typically within the lower 16MB, this works out fine.
|
|
*/
|
|
and v0, TO_COMPAT_PHYS_MASK
|
|
and t0, ra, ~TO_COMPAT_PHYS_MASK
|
|
or v0, t0 /* Force uncached access */
|
|
sll v1,3 /* Index into table. */
|
|
daddu v0,v1
|
|
jalr a2,v0
|
|
nop
|
|
CACHE_BARRIER # should be ok, but not perf path
|
|
MFC0(v0, C0_TAGLO)
|
|
sw v0,COP_TAGLO(a0)
|
|
MFC0(v0, C0_TAGHI)
|
|
sw v0,COP_TAGHI(a0)
|
|
MFC0(v0, C0_ECC)
|
|
j ra
|
|
sw v0,COP_ECC(a0)
|
|
.set reorder
|
|
|
|
/*
|
|
* There are 32 possible operations to perform, each is
|
|
* defined in the table below, and uses 2 instructions (8 bytes).
|
|
*/
|
|
|
|
cacheOP_table:
|
|
.set noreorder
|
|
jr a2
|
|
cache 0, 0(a1)
|
|
jr a2
|
|
cache 1, 0(a1)
|
|
jr a2
|
|
cache 2, 0(a1)
|
|
jr a2
|
|
cache 3, 0(a1)
|
|
jr a2
|
|
cache 4, 0(a1)
|
|
jr a2
|
|
cache 5, 0(a1)
|
|
jr a2
|
|
cache 6, 0(a1)
|
|
jr a2
|
|
cache 7, 0(a1)
|
|
jr a2
|
|
cache 8, 0(a1)
|
|
jr a2
|
|
cache 9, 0(a1)
|
|
jr a2
|
|
cache 10, 0(a1)
|
|
jr a2
|
|
cache 11, 0(a1)
|
|
jr a2
|
|
cache 12, 0(a1)
|
|
jr a2
|
|
cache 13, 0(a1)
|
|
jr a2
|
|
cache 14, 0(a1)
|
|
jr a2
|
|
cache 15, 0(a1)
|
|
jr a2
|
|
cache 16, 0(a1)
|
|
jr a2
|
|
cache 17, 0(a1)
|
|
jr a2
|
|
cache 18, 0(a1)
|
|
jr a2
|
|
cache 19, 0(a1)
|
|
jr a2
|
|
cache 20, 0(a1)
|
|
jr a2
|
|
cache 21, 0(a1)
|
|
jr a2
|
|
cache 22, 0(a1)
|
|
jr a2
|
|
cache 23, 0(a1)
|
|
jr a2
|
|
cache 24, 0(a1)
|
|
jr a2
|
|
cache 25, 0(a1)
|
|
jr a2
|
|
cache 26, 0(a1)
|
|
jr a2
|
|
cache 27, 0(a1)
|
|
jr a2
|
|
cache 28, 0(a1)
|
|
jr a2
|
|
cache 29, 0(a1)
|
|
jr a2
|
|
cache 30, 0(a1)
|
|
jr a2
|
|
cache 31, 0(a1)
|
|
.set reorder
|
|
END(cacheOP)
|
|
|
|
/*
|
|
* void prefetch_store(void *addr, int len)
|
|
* Prefetch from addr:len for storing
|
|
* addr should be cache-aligned
|
|
*/
|
|
LEAF(__prefetch_store)
|
|
1:
|
|
blez a1,3f
|
|
|
|
# Align starting addresses, and length
|
|
dli t0, ~SCACHE_LINEMASK
|
|
and a0, t0
|
|
|
|
# (len = (len >> 7)
|
|
dsrl a1, 7
|
|
2:
|
|
.set noreorder
|
|
CACHE_BARRIER
|
|
pref 0x1,0(a0)
|
|
.set reorder
|
|
daddiu a0,a0,128
|
|
daddiu a1,a1,-1
|
|
bgez a1, 2b
|
|
3:
|
|
j ra
|
|
END(__prefetch_store)
|
|
|
|
/* void prefetch_load( void *addr, int len );
|
|
*
|
|
* addr should be cache line aligned.
|
|
*/
|
|
LEAF(__prefetch_load)
|
|
1:
|
|
blez a1,3f
|
|
|
|
# Align starting address and length
|
|
dli t0, ~SCACHE_LINEMASK
|
|
and a0, t0
|
|
|
|
# len = (len >> 7)
|
|
dsrl a1, 7
|
|
|
|
2:
|
|
pref 0x0,0(a0)
|
|
daddiu a0,a0,128
|
|
daddiu a1,-1
|
|
bgez a1,2b
|
|
3:
|
|
j ra
|
|
END(__prefetch_load)
|
|
|
|
#ifdef DEBUG
|
|
/* Inject bad parity into icache (recoverable error testing) at offset,
|
|
* which can have the way encoded in it. This is hooked up to syssgi()
|
|
* in debug kernels.
|
|
*/
|
|
#ifndef K0_RAMBASE
|
|
#define K0_RAMBASE K0BASE
|
|
#endif
|
|
LEAF(try_icache_err)
|
|
LA a1,1f # need to run uncached
|
|
and a1,TO_PHYS_MASK
|
|
or a1,SEXT_K1BASE
|
|
|
|
LI t1,K0_RAMBASE # memory base
|
|
and a0,~0x3e # index, but keep way
|
|
PTR_ADDU t1,a0 # cache op addr
|
|
|
|
.set noreorder
|
|
mfc0 t0,C0_SR # disable interrupts
|
|
or v0,t0,SR_IE
|
|
xor v0,SR_IE
|
|
mtc0 v0,C0_SR
|
|
|
|
jr a1
|
|
nop # BDSLOT
|
|
|
|
1:
|
|
cache CACH_PI+C_ILT,0(t1) # load tag
|
|
|
|
mfc0 a1,C0_TAGLO # flip tag parity
|
|
xori a1,1
|
|
mtc0 a1,C0_TAGLO
|
|
|
|
cache CACH_PI+C_IST,0(t1) # store tag
|
|
|
|
mtc0 t0,C0_SR # restore interrupts
|
|
.set reorder
|
|
|
|
j ra # return + restore cacheability
|
|
END(try_icache_err)
|
|
#endif /* DEBUG */
|
|
#endif /* R10000 */
|
|
|
|
#if SW_FAST_CACHE_SYNCH
|
|
/* we start off with a 32-byte primary cache line size.
|
|
* The following patch code will change that to work with
|
|
* 16 bytes if we we running on R4000/R4400.
|
|
*/
|
|
#define CACHE_LINESIZE (8*4)
|
|
#define CACHE_LINEMASK ((8*4)-1)
|
|
#define CACHE_ALT_LINESIZE (4*4)
|
|
#define CACHE_ALT_LINEMASK ((4*4)-1)
|
|
|
|
LEAF(sw_cachesynch_patch_insts)
|
|
.set noreorder
|
|
.set noat
|
|
PTR_SUBU k1, CACHE_ALT_LINESIZE
|
|
and k0,a0,CACHE_ALT_LINEMASK
|
|
PTR_ADDU k0, CACHE_ALT_LINESIZE
|
|
|
|
#ifdef PROBE_WAR
|
|
/*
|
|
* On R4000, we can't execute probes from the instruction cache
|
|
* Thus we need to patch the CO_PROBE instruction with call to
|
|
* this routine for R4000.
|
|
*/
|
|
EXPORT(sw_cachesynch_patch_insts_R4000)
|
|
jal sw_probe_war
|
|
|
|
EXPORT(sw_probe_war)
|
|
la v0, sw_tlb_probe
|
|
LI AT, K1BASE
|
|
or v0, AT
|
|
jal AT, v0
|
|
nop
|
|
jr ra
|
|
nop
|
|
|
|
.align 6
|
|
EXPORT(sw_tlb_probe)
|
|
NOP_0_3
|
|
c0 C0_PROBE # probe for address
|
|
NOP_0_3
|
|
j AT
|
|
NOP_0_1
|
|
#endif /* PROBE_WAR */
|
|
|
|
/*
|
|
* The following code is copied to cache synch handler
|
|
* when requested by the library using syssgi system
|
|
* call with argument SGI_SYNCH_CACHE_HANDLER.
|
|
*/
|
|
EXPORT(cache_sync_bp_start)
|
|
break BRK_CACHE_SYNC
|
|
j ra
|
|
EXPORT(cache_sync_bp_end)
|
|
END(sw_cachesynch_patch_insts)
|
|
|
|
/* In-line implementation of fast cache synchronization */
|
|
LEAF(cache_sync)
|
|
.set noat
|
|
sreg t0, VPDA_T0SAVE(zero)
|
|
#ifdef PROBE_WAR
|
|
sreg ra, VPDA_SWINSAVE_TMP(zero)
|
|
#endif
|
|
|
|
/* a0: start of user address to synch caches
|
|
* a1: length
|
|
*
|
|
* synchronize icache with dcache in the user address range
|
|
* a0..(a0+a1-1). If length is more than 0x100, we take the
|
|
* slow path otherwise try to do it here. If the TLB entry
|
|
* is missing, again take the slow path.
|
|
*/
|
|
blez a1,fastexit
|
|
sltiu AT,a1,0x101 # threshold for fast path
|
|
bne AT,zero,1f # above threshold, take slow path
|
|
lui AT,0x8000 # BDSLOT if range in user addr space (KUBASE+KUSIZE)
|
|
j longway
|
|
nop
|
|
1: addu t0,a0,a1
|
|
addiu t0,t0,-1 # (addr+length-1)
|
|
sltu AT,t0,AT
|
|
bne t0,zero,bigloop # let slowpath handle the error
|
|
nop
|
|
j longway
|
|
nop
|
|
|
|
|
|
bigloop:
|
|
/* prepare tlbhi for proble */
|
|
DMFC0 (k0,C0_TLBHI) # current tlbhi
|
|
NOP_1_3
|
|
.set at # we can let as use AT for a while
|
|
and t0,a0,TLBHI_VPNMASK # chop any offset bits from vadd
|
|
andi k1,k0,TLBHI_PIDMASK # save pid off entryhi
|
|
or t0,k1 # vpn/pid ready for entryhi
|
|
DMTC0 (t0,C0_TLBHI) # vpn and pid of new entry
|
|
NOP_1_3 # let tlbhi get through pipe
|
|
|
|
/* calculate bytes to flush in this page */
|
|
li t0, NBPP
|
|
andi k1,a0,POFFMASK
|
|
subu t0, k1 # rem = NBPP - poff(addr)
|
|
ble t0,a1,countok # rem <= bcnt
|
|
nop # BDSLOT
|
|
move t0,a1 # else rem = bcnt
|
|
|
|
/* at this point
|
|
* t0: bytes to synch in this page
|
|
* a0: actual base vaddr to start synch
|
|
* a1: remaining length
|
|
*/
|
|
|
|
countok:
|
|
PTR_ADDU k1,a0,t0 # ending address + 1
|
|
EXPORT(sw_cachesynch_op1)
|
|
PTR_SUBU k1,CACHE_LINESIZE
|
|
|
|
# check and align starting and ending addresses.
|
|
# align the address to the start of the line
|
|
EXPORT(sw_cachesynch_op2)
|
|
and k0,a0,CACHE_LINEMASK
|
|
PTR_SUBU k0,a0,k0
|
|
|
|
1: # top of loop
|
|
# for R4000 we can't execute probe from the instruction cache
|
|
EXPORT(sw_cachesynch_op4)
|
|
.set noat
|
|
c0 C0_PROBE # probe for address
|
|
nop
|
|
mfc0 AT,C0_INX
|
|
nop
|
|
bgez AT,2f # found
|
|
nop # BDSLOT
|
|
|
|
# tlb entry not found. Restore registers from saved locations and take trap
|
|
#ifdef PROBE_WAR
|
|
lreg ra, VPDA_SWINSAVE_TMP(zero)
|
|
#endif
|
|
lreg AT, VPDA_ATSAVE(zero)
|
|
j longway
|
|
lreg t0, VPDA_T0SAVE(zero)
|
|
.set at
|
|
|
|
2:
|
|
# 'hit writeback' the primary data line and
|
|
# "hit invalidate' the primary icache indicated by addr
|
|
.set noreorder
|
|
#ifdef R10000
|
|
cache CACH_PD|C_HWBINV,0(k0) # invalidate primary
|
|
#else
|
|
cache CACH_PD|C_HWB,0(k0) # invalidate primary
|
|
#endif
|
|
nop
|
|
cache CACH_PI|C_HINV,0(k0) # invalidate primary
|
|
nop
|
|
|
|
bltu k0,k1,1b
|
|
EXPORT(sw_cachesynch_op3)
|
|
PTR_ADDU k0,CACHE_LINESIZE # BDSLOT
|
|
|
|
# adjust a0 for next page and a1 for total count
|
|
PTR_ADDU a0,t0 # addr = addr + rem
|
|
PTR_SUBU a1,t0 # count = count - rem
|
|
bne a1,zero,bigloop
|
|
nop # BDSLOT
|
|
|
|
fastexit:
|
|
# all done - let's go!
|
|
# Don't need AT and t0 anymore
|
|
.set noat
|
|
.set noreorder
|
|
DMFC0(k0,C0_EPC)
|
|
li v0,0 # no error
|
|
PTR_ADDIU k0, 4 # skip over BREAK instruction
|
|
DMTC0(k0,C0_EPC)
|
|
#ifdef PROBE_WAR
|
|
lreg ra, VPDA_SWINSAVE_TMP(zero)
|
|
#endif
|
|
lreg AT, VPDA_ATSAVE(zero)
|
|
lreg t0, VPDA_T0SAVE(zero)
|
|
ERET_PATCH(softwin_eret_0) # patchable eret
|
|
eret
|
|
END(cache_sync)
|
|
.set reorder
|
|
.set at
|
|
#endif /* SW_FAST_CACHE_SYNCH */
|
|
|
|
|
|
#ifdef SN0
|
|
/*
|
|
* __hub_poq_dcache_wbinval(addr, len)
|
|
* writeback-invalidate data cache for range of physical addr to addr+len-1
|
|
*
|
|
* POQWAR_CACHELINE_SIZE defines the rate at which we flush caches for
|
|
* avoiding POQ bug. Ideally we flush all cachelines in which case
|
|
* POQWAR_CACHE_LINESIZE == SCACHE_LINESIZE
|
|
* We could flush less often since we are trying to do some probabilistic
|
|
* flushing to avoid Hub POQ bug. So, do it every 3 cachelines instead
|
|
* of every cacheline. No idea if 3 is the right number.
|
|
*
|
|
* Note that there is no cache-coherency or data corruption issue here.
|
|
* Cache writeback invalidates helps in reducing interventions to CPU,
|
|
* and hence increases the probability of avoiding POQ bug.
|
|
*/
|
|
#define POQWAR_CACHE_LINESIZE (SCACHE_LINESIZE * 4)
|
|
|
|
LEAF(__hub_poq_dcache_wbinval)
|
|
|
|
blez a1,7f # if length <= 0, we are done
|
|
lw ta3,VPDA_PSCACHESIZE(zero)
|
|
|
|
sltu t2, ta3, a1 # size > scache_size?
|
|
bnez t2, 2f # yes --> use indexed invalidate
|
|
|
|
move t0,a0
|
|
PTR_ADDU t1,a0,a1 # ending address + 1
|
|
bgeu t0,t1,6f # paranoid
|
|
PTR_SUBU t1,POQWAR_CACHE_LINESIZE
|
|
|
|
# align the starting address.
|
|
and t2,t0,SCACHE_LINEMASK
|
|
PTR_SUBU t0,t2
|
|
|
|
.set noreorder
|
|
1: # top of loop
|
|
cache CACH_SD|C_HWBINV,0(t0) # writeback secondary
|
|
|
|
cache CACH_SD|C_HWBINV,1(t0) # writeback secondary
|
|
bltu t0,t1,1b
|
|
PTR_ADDU t0, POQWAR_CACHE_LINESIZE # BDSLOT increase invalidate address
|
|
.set reorder
|
|
|
|
# Done head back..
|
|
b 6f
|
|
|
|
2:
|
|
/* clean scache using index invalidate */
|
|
LI t0, K0_CACHEFLUSHBASE # set up current address
|
|
srl ta3,1 # cache is 2 way set associative
|
|
|
|
PTR_ADDU t1, t0, ta3 # set up limit address
|
|
PTR_SUBU t1, POQWAR_CACHE_LINESIZE # (base + scache_size - POQ line size)
|
|
3:
|
|
.set noreorder
|
|
cache CACH_SD|C_IWBINV, 0(t0) # Invalidate cache line
|
|
|
|
cache CACH_SD|C_IWBINV, 1(t0) # Invalidate cache line (way 1)
|
|
|
|
bltu t0, t1, 3b
|
|
PTR_ADDU t0, POQWAR_CACHE_LINESIZE # BDSLOT increase invalidate address
|
|
.set reorder
|
|
|
|
6:
|
|
#if R10000 && !R10000_SPECULATION_WAR
|
|
/* ensure previous cache instructions have graduated */
|
|
.set noreorder
|
|
cache CACH_BARRIER,-POQWAR_CACHE_LINESIZE(t0)
|
|
.set reorder
|
|
#endif
|
|
|
|
7:
|
|
|
|
j ra
|
|
|
|
END(__hub_poq_dcache_wbinval)
|
|
|
|
#endif /* SN0 */
|
|
|
|
|
|
.data
|
|
lmsg: .asciiz "cache.s"
|
|
#ifdef R4600SC
|
|
#ifdef _MEM_PARITY_WAR
|
|
.globl _r4600sc_scache_disabled
|
|
#endif /* _MEM_PARITY_WAR */
|
|
_r4600sc_scache_disabled: .word 1
|
|
#endif
|
|
#ifdef R4600SC_DEBUG
|
|
_r4600sc_2nd_flush_error: .word 0
|
|
#endif
|
|
#ifdef R4600SC_STATS
|
|
_r4600sc_mapped: .word 0 # number using mapped addresses
|
|
_r4600sc_unmapped: .word 0 # number using unmapped
|
|
_r4600sc_short: .word 0 # number len lt 1 page
|
|
_r4600sc_long: .word 0 # number len gt 1 page
|
|
_r4600sc_cross: .word 0 # number len lt 1 page but
|
|
# cross page boundry
|
|
_r4600sc_nuke: .word 0 # times cache is nuked
|
|
_r4600sc_mandc: .word 0 # mapped and cross
|
|
#endif
|
|
#ifdef TRITON
|
|
.sdata
|
|
.globl _triton_use_invall
|
|
_triton_use_invall: .word 0 # enable C_INVALL
|
|
#endif /* TRITON */
|