435 lines
9.8 KiB
ArmAsm
435 lines
9.8 KiB
ArmAsm
/*
|
|
* @(#)module_vik_asm.s 1.1 94/10/31 SMI
|
|
* Copyright (c) 1990 by Sun Microsystems, Inc.
|
|
*
|
|
* assembly code support for modules based on the
|
|
* TI VIKING chip set.
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <machine/asm_linkage.h>
|
|
#include <machine/mmu.h>
|
|
#include <machine/pte.h>
|
|
#include <machine/cpu.h>
|
|
#include <machine/psl.h>
|
|
#include <machine/trap.h>
|
|
#include <machine/devaddr.h>
|
|
#include <machine/module.h>
|
|
#include <percpu_def.h>
|
|
#include "assym.s"
|
|
|
|
ALTENTRY(vik_mmu_getasyncflt)
|
|
! %%% need to work out how to talk with
|
|
! %%% viking write pipe.
|
|
! get mfsr/mfar registers
|
|
! Viking/NE: a store buffer error will cause both a trap 0x2b and
|
|
! a broadcast l15 interrupt. The trap will be taken first, but
|
|
! afterwards there will be a pending l15 interrupt waiting for
|
|
! this module.
|
|
! Viking/E: async fault status is in the mxcc error register
|
|
!
|
|
! %o0 = MFSR
|
|
! %o0+4 = MFAR
|
|
! %o0+8 = -1 in Mbus mode;
|
|
! = Error register <63:32>
|
|
! %o0+12 = Error register <31:0>
|
|
!
|
|
|
|
set RMMU_FAV_REG, %o1 ! MFSR and MFAR
|
|
lda [%o1]ASI_MOD, %o1
|
|
st %o1, [%o0+4]
|
|
set RMMU_FSR_REG, %o1
|
|
lda [%o1]ASI_MOD, %o1
|
|
st %o1, [%o0]
|
|
|
|
sethi %hi(_mod_info), %o1
|
|
ld [%o1+%lo(_mod_info)], %o1 ! get mod_info[0].mod_type
|
|
cmp %o1, CPU_VIKING ! in MBus mode?
|
|
be 1f
|
|
set -1, %o4
|
|
|
|
set MXCC_ERROR, %o1
|
|
ldda [%o1]ASI_MXCC, %o2 ! get 64-bit error register
|
|
st %o2, [%o0+12] ! %o2 has PA<31 : 0>
|
|
mov %o3, %o4 ! %o3 (high nibble) status
|
|
sub %g0, 1, %o2 ! set 0xFFFFFFFF to %o2
|
|
sub %g0, 1, %o3 ! set 0xFFFFFFFF to %o3
|
|
stda %o2, [%o1]ASI_MXCC ! clear error register
|
|
1:
|
|
retl
|
|
st %o4, [%o0+8]
|
|
|
|
ALTENTRY(vik_mmu_chk_wdreset)
|
|
set RMMU_FSR_REG, %o0
|
|
lda [%o0]ASI_MOD, %o0
|
|
set MMU_SFSR_EM, %o1
|
|
retl
|
|
and %o0, %o1, %o0
|
|
|
|
ENTRY(probe_pte_0)
|
|
|
|
set 0xFFF, %o1
|
|
andn %o0, %o1, %o0
|
|
retl
|
|
lda [%o0]ASI_FLPR, %o0
|
|
|
|
ENTRY(probe_1)
|
|
|
|
set 0xFFF, %o1
|
|
andn %o0, %o1, %o0
|
|
set 0x100, %o1
|
|
or %o0, %o1, %o0
|
|
retl
|
|
lda [%o0]ASI_FLPR, %o0
|
|
|
|
|
|
ENTRY(probe_2)
|
|
|
|
set 0xFFF, %o1
|
|
andn %o0, %o1, %o0
|
|
set 0x200, %o1
|
|
or %o0, %o1, %o0
|
|
retl
|
|
lda [%o0]ASI_FLPR, %o0
|
|
|
|
ENTRY(probe_3)
|
|
|
|
set 0xFFF, %o1
|
|
andn %o0, %o1, %o0
|
|
set 0x300, %o1
|
|
or %o0, %o1, %o0
|
|
retl
|
|
lda [%o0]ASI_FLPR, %o0
|
|
|
|
/*
|
|
* Breakpoint register
|
|
* set or unset bits
|
|
* bpt_reg(onbits, offbits)
|
|
*/
|
|
ENTRY(bpt_reg)
|
|
lda [%g0]ASI_MBAR, %o2 /* get the contents */
|
|
or %o0, %o2, %o0 /* set the "onbits" bits */
|
|
|
|
andn %o0, %o1, %o0 /* reset th "offbits" bits */
|
|
|
|
retl
|
|
sta %o0, [%g0]ASI_MBAR
|
|
|
|
/*
|
|
* vik_pte_rmw: update a pte.
|
|
* does no flushing.
|
|
*
|
|
* breaks if we update the m-bit
|
|
* between storing the new data
|
|
* and flusing our tlb, so we
|
|
* disable traps and do no stores.
|
|
*
|
|
* %o0 - virtual address of pte
|
|
* %o1 - bits to turn off
|
|
* %o2 - bits to turn on
|
|
* %o3 - flush address
|
|
* %o4 -
|
|
* %o5 - pte value
|
|
*/
|
|
ALTENTRY(vik_pte_rmw) ! (ppte, aval, oval)
|
|
mov %psr, %g2
|
|
andn %g2, PSR_ET, %g1
|
|
mov %g1, %psr ! disable traps
|
|
nop; nop; nop ! psr delay
|
|
ld [%o0], %o5 ! get old value
|
|
andn %o5, %o1, %o5 ! turn some bits off
|
|
or %o5, %o2, %o5 ! turn some bits on
|
|
swap [%o0], %o5 ! update the PTE
|
|
mov %g2, %psr ! restore traps
|
|
nop ! psr delay
|
|
retl
|
|
mov %o5, %o0
|
|
|
|
#ifdef VAC
|
|
/*
|
|
* Actually, this is a PAC, not a VAC,
|
|
* but this seems to be the right place
|
|
* to put the code. Note: it is extremely
|
|
* rare to need to flush physical caches,
|
|
* like just when going from cacheable to
|
|
* noncacheable. It is also fairly hard
|
|
* to flush the viking cache.
|
|
*/
|
|
ALTENTRY(vik_vac_init_asm) ! (clrbits, setbits)
|
|
|
|
/*
|
|
* Don't clear the tags here. The viking bootprom will clear the cache
|
|
* tags and leave the cache on.
|
|
* If we clear the tags here, all hell will break loose.
|
|
*
|
|
* sub %g0, 1, %g1
|
|
* sta %g1, [%g0]ASI_ICFCLR ! clear i-$ lock bits
|
|
* sta %g0, [%g0]ASI_ICFCLR ! clear i-$ valid bits
|
|
* sta %g1, [%g0]ASI_DCFCLR ! clear d-$ lock bits
|
|
* sta %g0, [%g0]ASI_DCFCLR ! clear d-$ valid bits
|
|
*/
|
|
|
|
set RMMU_CTL_REG, %o5 ! initialize viking
|
|
lda [%o5]ASI_MOD, %o4 ! read control register
|
|
andn %o4, %o0, %o4 ! turn some bits off
|
|
or %o4, %o1, %o4 ! turn some bits on
|
|
sta %o4, [%o5]ASI_MOD ! update control register
|
|
|
|
retl
|
|
nop
|
|
|
|
/* %%% TODO: initialize MXCC
|
|
* - write 0xFFFFFFFFFFFFFFFF to mxcc error register. individual
|
|
* bits in this register are write-1-to-clear. This register
|
|
* is not affected by system reset.
|
|
* - initialize MXCC control register
|
|
* CE <bit 2>- E$ enable.
|
|
* PE <bit 3>- Parity enable.
|
|
* MC <bit 4>- Multiple command enable
|
|
* PF <bit 5>- Prefetch enable
|
|
* RC <bit 9>- Read reference count only
|
|
*/
|
|
ALTENTRY(vik_mxcc_init_asm) ! (clrbits, setbits)
|
|
set MXCC_ERROR, %o4
|
|
sub %g0, 1, %o2 ! set 0xFFFFFFFFFFFFFFFF to %o2 and %o3
|
|
sub %g0, 1, %o3 ! set 0xFFFFFFFFFFFFFFFF to %o2 and %o3
|
|
stda %o2, [%o4]ASI_MXCC
|
|
|
|
set MXCC_CNTL, %o4
|
|
lda [%o4]ASI_MXCC, %o5 ! read mxcc control reg
|
|
andn %o5, %o0, %o5 ! turn some bits off
|
|
or %o5, %o1, %o5 ! turn some bits on
|
|
sta %o5, [%o4]ASI_MXCC ! update mxcc control reg
|
|
|
|
retl
|
|
nop
|
|
|
|
ALTENTRY(vik_cache_on)
|
|
! %%% what do we stuff in here?
|
|
! do we need to turn on MXCC here?
|
|
set CACHE_VIK_ON, %o2 !MBus mode
|
|
set RMMU_CTL_REG, %o0
|
|
lda [%o0]ASI_MOD, %o1
|
|
andcc %o1, CPU_VIK_MB, %g0
|
|
bnz 1f !MBus mode
|
|
nop
|
|
set CACHE_VIK_ON_E, %o2 !CC mode
|
|
1: or %o1, %o2, %o1
|
|
sta %o1, [%o0]ASI_MOD
|
|
retl
|
|
nop
|
|
|
|
ALTENTRY(mxcc_vac_parity_chk_dis)
|
|
set MMU_SFSR_UD, %o3
|
|
btst %o3, %o0
|
|
bnz 1f
|
|
set MMU_SFSR_P, %o4
|
|
btst %o4, %o0
|
|
bnz 1f
|
|
set MXCC_ERR_CP, %o5
|
|
btst %o5, %o1
|
|
bnz 1f
|
|
nop
|
|
|
|
retl
|
|
mov %g0, %o0
|
|
1:
|
|
set MXCC_CNTL, %o1
|
|
lda [%o1]ASI_MXCC, %o2 ! read mxcc control reg
|
|
set MXCC_PE, %o3
|
|
andn %o3, %o2, %o2
|
|
|
|
set RMMU_CTL_REG, %o3 ! initialize viking
|
|
lda [%o3]ASI_MOD, %o4 ! read control register
|
|
set CPU_VIK_PE, %o5
|
|
andn %o5, %o4, %o4
|
|
|
|
sta %o2, [%o1]ASI_MXCC ! Turn off E$ parity bit
|
|
sta %o4, [%o3]ASI_MOD ! Turn off Viking parity bit
|
|
|
|
retl
|
|
mov 0x1, %o0
|
|
#endif VAC
|
|
|
|
/*
|
|
* Taken from module_srmmu_asm.s in order to handle the manipulation
|
|
* of the AC bit for Viking/MXCC. Only this module should now use
|
|
* these routines. All others, including VIKING/NE should still
|
|
* point to the "srmmu_XXX" routines.
|
|
* %%% Maybe we dont need to do the ASI_MEM at all within BORROW_CONTEXT?
|
|
*
|
|
* BORROW_CONTEXT: temporarily set the context number
|
|
* to that given in %o1.
|
|
*
|
|
* NOTE: traps are disabled while we are in a borrowed context. It is
|
|
* not possible to prove that the only traps that can happen while the
|
|
* context is borrowed are safe to activate while we are in a borrowed
|
|
* context (this includes random level-15 interrupts!).
|
|
*
|
|
* %o0 flush/probe address [don't touch!]
|
|
* %o1 context number to borrow
|
|
* %o2 saved context number
|
|
* %o3 saved mmu csr contents
|
|
* %o4 psr temp / probe temp / RMMU_CTX_REG
|
|
* %o5 saved psr
|
|
*
|
|
*/
|
|
|
|
#define BORROW_CONTEXT \
|
|
mov %psr, %o5; \
|
|
andn %o5, PSR_ET, %o4; \
|
|
mov %o4, %psr; \
|
|
nop ; nop; \
|
|
\
|
|
set RMMU_CTP_REG, %o4; \
|
|
lda [%o4]ASI_MOD, %o4; \
|
|
sll %o1, 2, %o2; \
|
|
sll %o4, 4, %o4; \
|
|
add %o4, %o2, %o4; \
|
|
\
|
|
set CPU_VIK_AC, %o2; \
|
|
lda [%g0]ASI_MOD, %o3; \
|
|
or %o3, %o2, %o2; \
|
|
sta %o2, [%g0]ASI_MOD; \
|
|
\
|
|
lda [%o4]ASI_MEM, %o4; \
|
|
sta %o3, [%g0]ASI_MOD; \
|
|
and %o4, 3, %o4; \
|
|
subcc %o4, MMU_ET_PTP, %g0; \
|
|
\
|
|
set RMMU_CTX_REG, %o4; \
|
|
bne 1f; \
|
|
lda [%o4]ASI_MOD, %o2; \
|
|
sta %o1, [%o4]ASI_MOD; \
|
|
1:
|
|
|
|
/*
|
|
* RESTORE_CONTEXT: back out from whatever BORROW_CONTEXT did.
|
|
* Assumes that two cycles of PSR DELAY follow.
|
|
*/
|
|
#define RESTORE_CONTEXT \
|
|
sta %o2, [%o4]ASI_MOD; \
|
|
mov %o5, %psr; \
|
|
nop
|
|
|
|
ALTENTRY(vik_mmu_flushctx) ! void vik_mmu_flushctx(int ctx);
|
|
set FT_CTX<<8, %o0
|
|
BORROW_CONTEXT
|
|
sta %g0, [%o0]ASI_FLPR ! do the flush
|
|
RESTORE_CONTEXT
|
|
retl
|
|
nop ! psr delay
|
|
|
|
ALTENTRY(vik_mmu_flushrgn) ! void vik_mmu_flushrgn(caddr_t base);
|
|
b vik_flushcommon ! flush region in context from mmu
|
|
or %o0, FT_RGN<<8, %o0
|
|
|
|
ALTENTRY(vik_mmu_flushseg) ! void vik_mmu_flushseg(caddr_t base);
|
|
b vik_flushcommon ! flush segment in context from mmu
|
|
or %o0, FT_SEG<<8, %o0
|
|
|
|
ALTENTRY(vik_mmu_flushpage) ! void vik_mmu_flushpage(caddr_t base)
|
|
or %o0, FT_PAGE<<8, %o0
|
|
|
|
vik_flushcommon:
|
|
#ifdef MULTIPROCESSOR
|
|
BORROW_CONTEXT
|
|
#endif MULTIPROCESSOR
|
|
sta %g0, [%o0]ASI_FLPR ! do the flush
|
|
#ifdef MULTIPROCESSOR
|
|
RESTORE_CONTEXT
|
|
#endif MULTIPROCESSOR
|
|
retl
|
|
nop ! PSR or MMU delay.
|
|
|
|
ALTENTRY(vik_mmu_flushpagectx) ! void
|
|
! vik_mmu_flushpagectx (caddr_t
|
|
! base, int ctx)
|
|
or %o0, FT_PAGE<<8, %o0
|
|
BORROW_CONTEXT
|
|
sta %g0, [%o0]ASI_FLPR ! do the flush
|
|
RESTORE_CONTEXT
|
|
retl
|
|
nop ! PSR or MMU delay.
|
|
|
|
!
|
|
! Workaround for SuperSPARC bug... disable 3/4 of SuperSPARC's on-board
|
|
! d-cache.
|
|
!
|
|
#if !defined(VIK_STAGADDR)
|
|
#define VIK_STAGADDR (1 << 30)
|
|
#endif
|
|
#if !defined(VIK_PTAGADDR)
|
|
#define VIK_PTAGADDR (2 << 30)
|
|
#endif
|
|
|
|
ALTENTRY(vik_1137125_wa)
|
|
save %sp, -SA(MINFRAME), %sp
|
|
|
|
mov %psr, %g1
|
|
andn %g1, PSR_ET, %g2 ! disable traps
|
|
mov %g2, %psr
|
|
nop; nop; nop;
|
|
|
|
! Quick'n'dirty displacement flush of dcache (for Viking-only)
|
|
clr %o0
|
|
set _start, %o1
|
|
set 0x8000, %o3
|
|
mov %o1, %o2
|
|
1:
|
|
ld [%o2], %g0
|
|
add %o0, 32, %o0
|
|
cmp %o0, %o3
|
|
ble 1b
|
|
add %o1, %o0, %o2
|
|
|
|
! Start mucking with tags
|
|
sethi %hi(VIK_STAGADDR), %i5
|
|
mov 0x0, %o0 ! upper 32-bits stag data
|
|
set 0xe, %o1 ! lower 32-bits stag data
|
|
sethi %hi(VIK_PTAGADDR), %i4
|
|
|
|
mov 0, %i2
|
|
or %i2, %i5, %l2 ! beginning stag addr
|
|
vhwb_nextset:
|
|
stda %o0, [%l2]ASI_DCT ! set stag to 0xe
|
|
|
|
sethi %hi(0x04000000),%i0 ! line[0]
|
|
sethi %hi(0x0c000000),%i3 ! line[3]
|
|
or %i0, %i4, %l2
|
|
vhwb_nextline:
|
|
or %i2, %l2, %l2
|
|
mov 0, %o2
|
|
mov 0, %o3
|
|
stda %o2, [%l2]ASI_DCT ! clear ptag
|
|
|
|
mov 0, %l3
|
|
or %i2, %i0, %i1
|
|
sll %l3, 3, %l2
|
|
vhwb_nextdword:
|
|
or %i1, %l2, %l2
|
|
mov 0, %o2
|
|
mov 0, %o3
|
|
stda %o2, [%l2]ASI_DCD ! clear dword
|
|
add %l3, 1, %l3
|
|
cmp %l3, 3
|
|
ble vhwb_nextdword
|
|
sll %l3, 3, %l2
|
|
|
|
sethi %hi(0x04000000),%l2 ! 1 << 26
|
|
add %i0, %l2, %i0 ! increment line#
|
|
cmp %i0, %i3 ! %i3 = maxline
|
|
ble,a vhwb_nextline
|
|
or %i0, %i4, %l2
|
|
|
|
add %i2, 32, %i2 ! increment set#
|
|
cmp %i2, 4064 ! 4063 = maxset
|
|
ble vhwb_nextset
|
|
or %i2, %i5, %l2
|
|
|
|
mov %g1, %psr
|
|
nop; nop; nop;
|
|
|
|
ret
|
|
restore
|