380 lines
8.8 KiB
C
380 lines
8.8 KiB
C
#ident "$Revision: 1.1 $"
|
|
|
|
#include "sys/asm.h"
|
|
#include "sys/regdef.h"
|
|
#include "sys/fpu.h"
|
|
#include "sys/softfp.h"
|
|
#include "sys/signal.h"
|
|
#include "sys/sbd.h"
|
|
#include "IP32_assym.h"
|
|
|
|
#ifdef EVEREST
|
|
#include "sys/EVEREST/everest.h"
|
|
#include "sys/EVEREST/evintr.h"
|
|
#endif /* EVEREST */
|
|
#if TFP
|
|
#include "sys/tfp.h"
|
|
#endif
|
|
|
|
#if defined(_K32U64) || defined(_K64U64)
|
|
#define lreg ld
|
|
#define sreg sd
|
|
#define BPREG 8
|
|
#else
|
|
#define lreg lw
|
|
#define sreg sw
|
|
#define BPREG 4
|
|
#endif
|
|
|
|
#ifdef PTE_64BIT
|
|
#define PTE_L ld
|
|
#define PTE_S sd
|
|
#define PTESZ_WORD .dword
|
|
#else
|
|
#define PTE_L lw
|
|
#define PTE_S sw
|
|
#define PTESZ_WORD .word
|
|
#endif /* PTE_64BIT */
|
|
|
|
/*
|
|
* flush any write buffer - this macro/routine needs to make sure that any
|
|
* write-behind writes are out and any possible errors (bus-error) have had
|
|
* time to be received
|
|
* WARNING: uses label 9
|
|
*/
|
|
|
|
#if IP19 || IP21 || IP25 || IPMHSIM
|
|
#define wbflushm /* TBD */
|
|
#endif
|
|
|
|
#if IP17
|
|
#define wbflushm \
|
|
.set noreorder ; \
|
|
.set noat ; \
|
|
lui AT,(MPSR_ADDR>>16) /* force a xfer through the WB chip */;\
|
|
lw AT,0(AT) ;\
|
|
nop ;\
|
|
.set at ; \
|
|
.set reorder
|
|
#endif
|
|
|
|
|
|
/* XXX these don't really guarantee WB (of 1) is really out ... */
|
|
|
|
|
|
|
|
#if MCCHIP
|
|
#if TFP || R10000
|
|
#define MC_NOP ssnop
|
|
#else
|
|
#define MC_NOP nop
|
|
#endif
|
|
/*
|
|
* Do an uncached read to flush the write buffer
|
|
*
|
|
* This routine is mostly used to affect changes to interrupts and
|
|
* since it takes a little time for interrupts to propagate on the
|
|
* R4000, some nops are added at the end.
|
|
*/
|
|
#define wbflushm_setup(RX) \
|
|
LI RX,(CPUCTRL0|K1BASE)
|
|
#define wbflushm_reg(RX) \
|
|
lw zero,0(RX)
|
|
#define wbflushm \
|
|
.set noreorder ; \
|
|
.set noat ; \
|
|
wbflushm_setup(AT) ; \
|
|
wbflushm_reg(AT) ; \
|
|
MC_NOP ; \
|
|
MC_NOP ; \
|
|
MC_NOP ; \
|
|
MC_NOP ; \
|
|
MC_NOP ; \
|
|
.set at ; \
|
|
.set reorder
|
|
#endif
|
|
|
|
#if IP30
|
|
#define wbflushm \
|
|
.set noreorder; \
|
|
.set noat; \
|
|
li AT,PHYS_TO_COMPATK1(HEART_SYNC);\
|
|
ld zero,0(AT); \
|
|
sync; \
|
|
.set at; \
|
|
.set reorder
|
|
#endif
|
|
|
|
#if IP32
|
|
/*
|
|
* Do an uncached read to flush the write buffer
|
|
*
|
|
* This routine is mostly used to affect changes to interrupts and
|
|
* since it takes a little time for interrupts to propagate on the
|
|
* R4000, some nops are added at the end.
|
|
*/
|
|
#define wbflushm \
|
|
.set noreorder ; \
|
|
.set noat ; \
|
|
lui AT,(CRM_CONTROL|K1BASE)>>16 ; \
|
|
or AT,CRM_CONTROL&0xffff ; \
|
|
ld AT,0(AT) ; \
|
|
nop ; \
|
|
nop ; \
|
|
nop ; \
|
|
nop ; \
|
|
nop ; \
|
|
.set at ; \
|
|
.set reorder
|
|
#endif
|
|
|
|
#if IP19 || IP21 || IP25 || (IP30 && MP)
|
|
/* On 64-bit kernels, doing an LI to load the address generates about 6
|
|
* instructions requiring several cycles to execute. Provide an alternate
|
|
* interface to the timer routines which lets us preserve the address
|
|
* of the timer for subsequent calls.
|
|
*/
|
|
#if SABLE && EVEREST
|
|
#define LOAD_TIMERADDR(reg) \
|
|
LI reg,EV_RTC;
|
|
#define _GET_TIMESTAMP2(reg,rtc) \
|
|
ld reg,(rtc) ; \
|
|
dsll reg,32 ; \
|
|
dsrl reg,32 ;
|
|
#elif EVEREST
|
|
#define LOAD_TIMERADDR(reg) \
|
|
LI reg,EV_RTC;
|
|
#define _GET_TIMESTAMP2(reg,rtc) \
|
|
lw reg,4(rtc) ;
|
|
#elif IP30
|
|
/* Use 32-bits of heart's counter so all cpus have coordinated timestamps */
|
|
#define LOAD_TIMERADDR(reg) \
|
|
CLI reg,PHYS_TO_COMPATK1(HEART_COUNT);
|
|
#define _GET_TIMESTAMP2(reg,rtc) \
|
|
lwu reg,4(rtc);
|
|
#endif
|
|
|
|
#define _GET_TIMESTAMP(reg) \
|
|
LOAD_TIMERADDR(reg); \
|
|
_GET_TIMESTAMP2(reg,reg) ;
|
|
|
|
#define USR2SYS_TIMER_SWITCH2(rtc) /* trash a0-3,ra,t0-7 and need stack */ \
|
|
_GET_TIMESTAMP2(a0,rtc) \
|
|
jal usr2sys_timer_switch
|
|
|
|
#define BACK2USR_TIMER_SWITCH2(rtc) /* trash a0-3,ra,t0-7 and need stack */ \
|
|
_GET_TIMESTAMP2(a0,rtc) \
|
|
jal back2usr_timer_switch
|
|
|
|
#define USR2SYS_TIMER_SWITCH /* trash a0-3,ra,t0-7 and need stack */ \
|
|
_GET_TIMESTAMP(a0) \
|
|
jal usr2sys_timer_switch
|
|
|
|
#define BACK2USR_TIMER_SWITCH /* trash a0-3,ra,t0-7 and need stack */ \
|
|
_GET_TIMESTAMP(a0) \
|
|
jal back2usr_timer_switch
|
|
|
|
#define INTTRAP_TIMER_SWITCH /* trash a0-3,ra,t0-7 and need stack */ \
|
|
lw a1, VPDA_TIMERSTATE(zero) ; \
|
|
beq a1, zero, 1f ; \
|
|
_GET_TIMESTAMP(a0) \
|
|
jal inttrap_timer_switch ; \
|
|
1:
|
|
|
|
/* really intr timer back to idle or process system timer */
|
|
#define INT2KERN_TIMER_RETURN \
|
|
_GET_TIMESTAMP(a0) \
|
|
jal int2kern_timer_return
|
|
|
|
#define INT2KERN_TIMER_SWITCH \
|
|
_GET_TIMESTAMP(a0) \
|
|
jal int2kern_timer_switch
|
|
#endif
|
|
#if IP17 || IP20 || IP22 || IP26 || IP28 || (IP30 && !MP) || IP32 || IPMHSIM
|
|
/* take advantage of the C0_COUNT register -- must be called .set reorder */
|
|
#define USR2SYS_TIMER_SWITCH /* trash a0-3,ra,t0-7 and need stack */ \
|
|
jal get_r4k_counter ; \
|
|
move a0, v0 ; \
|
|
jal usr2sys_timer_switch
|
|
|
|
#define BACK2USR_TIMER_SWITCH /* trash a0-3,ra,t0-7 and need stack */ \
|
|
jal get_r4k_counter ; \
|
|
move a0, v0 ; \
|
|
jal back2usr_timer_switch
|
|
|
|
#define INTTRAP_TIMER_SWITCH /* trash a0-3,ra,t0-7 and need stack */ \
|
|
lw a1, VPDA_TIMERSTATE(zero) ; \
|
|
beq a1, zero, 1f ; \
|
|
jal get_r4k_counter ; \
|
|
move a0, v0 ; \
|
|
jal inttrap_timer_switch ; \
|
|
1:
|
|
|
|
/* really intr timer back to idle or process system timer */
|
|
#define INT2KERN_TIMER_RETURN \
|
|
jal get_r4k_counter ; \
|
|
move a0, v0 ; \
|
|
jal int2kern_timer_return
|
|
|
|
#define INT2KERN_TIMER_SWITCH \
|
|
jal get_r4k_counter ; \
|
|
move a0, v0 ; \
|
|
jal int2kern_timer_switch
|
|
#endif /* IP17 || IP20 || IP22 || IP26 || IP28 || IP30 || IP32 || IPMHSIM */
|
|
|
|
#if TFP
|
|
#if IP26
|
|
#define TLBLO_FIX_HWBITS(lo) \
|
|
sll lo, TLBLO_HWBITSHIFT
|
|
#else
|
|
#define TLBLO_FIX_HWBITS(lo) \
|
|
dsll lo, TLBLO_HWBITSHIFT
|
|
#endif
|
|
#define NOINTS(x,y) \
|
|
LI x,SR_DEFAULT; \
|
|
MTC0_NO_HAZ(x,C0_SR); \
|
|
NOP_MTC0_HAZ
|
|
#else /* !TFP */
|
|
#if SR_KADDR
|
|
#define NOINTS(x,y) li x,SR_KERN_SET; MTC0_NO_HAZ(x,C0_SR)
|
|
#else
|
|
#define NOINTS(x,y) MTC0_NO_HAZ(zero,C0_SR)
|
|
#endif
|
|
#endif /* !TFP */
|
|
|
|
/* TLBLO_FIX_HWBITS is used to take a pte_t and convert to TLBLO (HW) format.
|
|
* TLBLO_UNFIX_HWBITS is used to take TLBLO (HW) and convert to pte_t (SW)
|
|
* but without the SW bits present.
|
|
*/
|
|
#if R4000
|
|
#if MCCHIP || IP32 || IPMHSIM
|
|
#define TLBLO_FIX_HWBITS(lo) \
|
|
sll lo, TLBLO_HWBITSHIFT; \
|
|
srl lo, TLBLO_HWBITSHIFT
|
|
#define TLBLO_UNFIX_HWBITS(lo)
|
|
#else
|
|
#define TLBLO_FIX_HWBITS(lo) \
|
|
srl lo, TLBLO_HWBITSHIFT
|
|
#define TLBLO_UNFIX_HWBITS(lo) \
|
|
sll lo, TLBLO_HWBITSHIFT
|
|
#endif /* MCCHIP || IP32 || IPMHSIM */
|
|
#endif /* R3000 || R4000 */
|
|
|
|
#if R10000
|
|
#define TLBLO_FIX_HWBITS(lo)
|
|
#define TLBLO_UNFIX_HWBITS(lo)
|
|
#endif
|
|
|
|
/*
|
|
* TLBLO_FIX_250MHz is a workaround for a problem seen on the 250MHz
|
|
* R4400 modules where entrylo values may be written incorrectly when
|
|
* certain previous values exist in the register. The workaround is to
|
|
* make sure a zero is there before updating the register (no hazard
|
|
* cycles needed when writing the zero). Currently this affects IP19
|
|
* and IP22's.
|
|
*/
|
|
#if R4000 && (IP19 || IP22)
|
|
#define TLBLO_FIX_250MHz(entrylo) mtc0 zero, entrylo
|
|
#else
|
|
#define TLBLO_FIX_250MHz(mumble)
|
|
#endif
|
|
|
|
#if IP20 || IP26 || IP28
|
|
#define FASTCLK_ACK(x) li x ACK_TIMER1; sb x TIMER_ACK_ADDR
|
|
#elif defined(IP22)
|
|
#define IS_IOC1(t) \
|
|
lw t, (K1BASE|HPC3_SYS_ID); \
|
|
andi t, CHIP_IOC1
|
|
|
|
#define FASTCLK_ACK(x) \
|
|
IS_IOC1(x); \
|
|
bnez x,1f; \
|
|
li x,ACK_TIMER1; \
|
|
sb x,(K1BASE|TIMER_ACK_OFFSET+HPC3_INT2_ADDR); \
|
|
b 2f; \
|
|
1: li x,ACK_TIMER1; \
|
|
sb x,(K1BASE|TIMER_ACK_OFFSET+HPC3_INT3_ADDR); \
|
|
2:
|
|
#else
|
|
#define FASTCLK_ACK(x) lbu x,FASTCLK_ADDR
|
|
#endif
|
|
|
|
#ifdef EVEREST
|
|
#define LoadCpumask ld
|
|
#define LLcpumask lld
|
|
#define SCcpumask scd
|
|
#else
|
|
#define LoadCpumask lw
|
|
#define LLcpumask ll
|
|
#define SCcpumask sc
|
|
#endif
|
|
|
|
#if IP17 || IP20 || IP22 || IP26 || IP28
|
|
#define PTCW_SC(x) ((x)<<6)
|
|
#define PTCW_16B (3<<4)
|
|
#define PTCW_MODE(x) ((x)<<1)
|
|
#define PTCW_CLCMD (0<<4)
|
|
#endif
|
|
|
|
#ifdef _R4600_2_0_CACHEOP_WAR
|
|
|
|
#define ERET_PATCH(xx) \
|
|
EXPORT(xx) ; \
|
|
j _r4600_2_0_cacheop_eret ; \
|
|
nop
|
|
|
|
#if (IP20 || IP22 || IPMHSIM)
|
|
#define PD_REFILL_WAIT(xx) \
|
|
.set noreorder ; \
|
|
PD_REFILL_WAIT_NR(xx) ; \
|
|
.set reorder
|
|
|
|
#ifdef _K64U64
|
|
#define PD_REFILL_K1BASE COMPAT_K1BASE32
|
|
#else
|
|
#define PD_REFILL_K1BASE K1BASE
|
|
#endif
|
|
|
|
#if (CPUCTRL0 & 0x8000)
|
|
#define PD_REFILL_WAIT_NR(xx) \
|
|
EXPORT(xx) ; \
|
|
.set noat ; \
|
|
lui AT,(CPUCTRL0|PD_REFILL_K1BASE)>>16 ; \
|
|
or AT,CPUCTRL0&0xffff ; \
|
|
lw AT,0(AT) ; \
|
|
nop ; \
|
|
.set at
|
|
#else
|
|
#define PD_REFILL_WAIT_NR(xx) \
|
|
EXPORT(xx) ; \
|
|
.set noat ; \
|
|
lui AT,(CPUCTRL0|PD_REFILL_K1BASE)>>16 ; \
|
|
lw AT,CPUCTRL0&0xffff(AT) ; \
|
|
nop ; \
|
|
.set at
|
|
#endif
|
|
#elif IP32
|
|
#define PD_REFILL_WAIT(xx) \
|
|
.set noreorder ; \
|
|
PD_REFILL_WAIT_NR(xx) ; \
|
|
.set reorder
|
|
|
|
#define PD_REFILL_WAIT_NR(xx) \
|
|
EXPORT(xx) ; \
|
|
.set noat ; \
|
|
lui AT,(CRM_ID|K1BASE)>>16 ; \
|
|
ld AT,CRM_ID&0xffff(AT) ; \
|
|
nop ; \
|
|
.set at
|
|
#else
|
|
<< bomb: must define PD_REFILL_WAIT and PD_REFILL_WAIT_NR >>
|
|
#endif
|
|
|
|
#else /* _R4600_2_0_CACHEOP_WAR */
|
|
|
|
#define ERET_PATCH(xx) eret
|
|
#define PD_REFILL_WAIT(xx)
|
|
#define PD_REFILL_WAIT_NR(xx)
|
|
|
|
#endif /* _R4600_2_0_CACHEOP_WAR */
|