#include <linux/init.h>
#include <asm/asm.h>
#include <asm/asmmacro.h>
#include <asm/cacheops.h>
#include <asm/irqflags.h>
#include <asm/regdef.h>
#include <asm/fpregdef.h>
#include <asm/mipsregs.h>
#include <asm/stackframe.h>
#include <asm/sync.h>
#include <asm/thread_info.h>
__INIT
NESTED(except_vec3_generic, 0, sp)
.set push
.set noat
mfc0 k1, CP0_CAUSE
andi k1, k1, 0x7c
#ifdef CONFIG_64BIT
dsll k1, k1, 1
#endif
PTR_L k0, exception_handlers(k1)
jr k0
.set pop
END(except_vec3_generic)
NESTED(except_vec3_r4000, 0, sp)
.set push
.set arch=r4000
.set noat
mfc0 k1, CP0_CAUSE
li k0, 31<<2
andi k1, k1, 0x7c
.set push
.set noreorder
.set nomacro
beq k1, k0, handle_vced
li k0, 14<<2
beq k1, k0, handle_vcei
#ifdef CONFIG_64BIT
dsll k1, k1, 1
#endif
.set pop
PTR_L k0, exception_handlers(k1)
jr k0
handle_vced:
MFC0 k0, CP0_BADVADDR
li k1, -4 # Is this ...
and k0, k1 # ... really needed?
mtc0 zero, CP0_TAGLO
cache Index_Store_Tag_D, (k0)
cache Hit_Writeback_Inv_SD, (k0)
#ifdef CONFIG_PROC_FS
PTR_LA k0, vced_count
lw k1, (k0)
addiu k1, 1
sw k1, (k0)
#endif
eret
handle_vcei:
MFC0 k0, CP0_BADVADDR
cache Hit_Writeback_Inv_SD, (k0) # also cleans pi
#ifdef CONFIG_PROC_FS
PTR_LA k0, vcei_count
lw k1, (k0)
addiu k1, 1
sw k1, (k0)
#endif
eret
.set pop
END(except_vec3_r4000)
__FINIT
.section .cpuidle.text,"ax"
.align 5
LEAF(r4k_wait)
0: .fill 0
local_irq_enable
1: .fill 0
.if 1b - 0b > 32
.error "overlong idle interrupt region"
.elseif 1b - 0b > 8
.align 4
.endif
2: .fill 0
.equ r4k_wait_idle_size, 2b - 0b
.set MIPS_ISA_ARCH_LEVEL_RAW
r4k_wait_insn:
wait
r4k_wait_exit:
.set mips0
local_irq_disable
jr ra
END(r4k_wait)
.previous
.macro BUILD_SKIPOVER_PROLOGUE handler
FEXPORT(skipover_\handler)
.set push
.set noat
MFC0 k0, CP0_EPC
PTR_LA k1, r4k_wait_insn - 2
ori k0, r4k_wait_idle_size - 2
.set noreorder
bne k0, k1, \handler
PTR_ADDIU k0, r4k_wait_exit - r4k_wait_insn + 2
.set reorder
MTC0 k0, CP0_EPC
.set pop
.endm
.align 5
BUILD_SKIPOVER_PROLOGUE handle_int
NESTED(handle_int, PT_SIZE, sp)
.cfi_signal_frame
#ifdef CONFIG_TRACE_IRQFLAGS
.set push
.set noat
mfc0 k0, CP0_STATUS
#if defined(CONFIG_CPU_R3000)
and k0, ST0_IEP
bnez k0, 1f
mfc0 k0, CP0_EPC
.set noreorder
j k0
rfe
#else
and k0, ST0_IE
bnez k0, 1f
eret
#endif
1:
.set pop
#endif
SAVE_ALL docfi=1
CLI
TRACE_IRQS_OFF
LONG_L s0, TI_REGS($28)
LONG_S sp, TI_REGS($28)
move s1, sp # Preserve the sp
ASM_CPUID_MFC0 k0, ASM_SMP_CPUID_REG
#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
lui k1, %hi(irq_stack)
#else
lui k1, %highest(irq_stack)
daddiu k1, %higher(irq_stack)
dsll k1, 16
daddiu k1, %hi(irq_stack)
dsll k1, 16
#endif
LONG_SRL k0, SMP_CPUID_PTRSHIFT
LONG_ADDU k1, k0
LONG_L t0, %lo(irq_stack)(k1)
PTR_LI t1, ~(_THREAD_SIZE-1)
and t1, t1, sp
beq t0, t1, 2f
li t1, _IRQ_STACK_START
PTR_ADD sp, t0, t1
LONG_S s1, 0(sp)
2:
jal plat_irq_dispatch
move sp, s1
j ret_from_irq
#ifdef CONFIG_CPU_MICROMIPS
nop
#endif
END(handle_int)
__INIT
NESTED(except_vec4, 0, sp)
1: j 1b
END(except_vec4)
NESTED(except_vec_ejtag_debug, 0, sp)
j ejtag_debug_handler
#ifdef CONFIG_CPU_MICROMIPS
nop
#endif
END(except_vec_ejtag_debug)
__FINIT
BUILD_SKIPOVER_PROLOGUE except_vec_vi
NESTED(except_vec_vi, 0, sp)
SAVE_SOME docfi=1
SAVE_AT docfi=1
.set push
.set noreorder
PTR_LA v1, except_vec_vi_handler
jr v1
FEXPORT(except_vec_vi_ori)
ori v0, zero, 0
.set pop
END(except_vec_vi)
EXPORT(except_vec_vi_end)
NESTED(except_vec_vi_handler, 0, sp)
SAVE_TEMP
SAVE_STATIC
CLI
#ifdef CONFIG_TRACE_IRQFLAGS
move s0, v0
TRACE_IRQS_OFF
move v0, s0
#endif
LONG_L s0, TI_REGS($28)
LONG_S sp, TI_REGS($28)
move s1, sp # Preserve the sp
ASM_CPUID_MFC0 k0, ASM_SMP_CPUID_REG
#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
lui k1, %hi(irq_stack)
#else
lui k1, %highest(irq_stack)
daddiu k1, %higher(irq_stack)
dsll k1, 16
daddiu k1, %hi(irq_stack)
dsll k1, 16
#endif
LONG_SRL k0, SMP_CPUID_PTRSHIFT
LONG_ADDU k1, k0
LONG_L t0, %lo(irq_stack)(k1)
PTR_LI t1, ~(_THREAD_SIZE-1)
and t1, t1, sp
beq t0, t1, 2f
li t1, _IRQ_STACK_START
PTR_ADD sp, t0, t1
LONG_S s1, 0(sp)
2:
PTR_L v0, vi_handlers(v0)
jalr v0
move sp, s1
j ret_from_irq
END(except_vec_vi_handler)
NESTED(ejtag_debug_handler, PT_SIZE, sp)
.set push
.set noat
MTC0 k0, CP0_DESAVE
mfc0 k0, CP0_DEBUG
andi k0, k0, MIPS_DEBUG_DBP # Check for SDBBP.
beqz k0, ejtag_return
#ifdef CONFIG_SMP
1: PTR_LA k0, ejtag_debug_buffer_spinlock
__SYNC(full, loongson3_war)
2: ll k0, 0(k0)
bnez k0, 2b
PTR_LA k0, ejtag_debug_buffer_spinlock
sc k0, 0(k0)
beqz k0, 1b
# ifdef CONFIG_WEAK_REORDERING_BEYOND_LLSC
sync
# endif
PTR_LA k0, ejtag_debug_buffer
LONG_S k1, 0(k0)
ASM_CPUID_MFC0 k1, ASM_SMP_CPUID_REG
PTR_SRL k1, SMP_CPUID_PTRSHIFT
PTR_SLL k1, LONGLOG
PTR_LA k0, ejtag_debug_buffer_per_cpu
PTR_ADDU k0, k1
PTR_LA k1, ejtag_debug_buffer
LONG_L k1, 0(k1)
LONG_S k1, 0(k0)
PTR_LA k0, ejtag_debug_buffer_spinlock
sw zero, 0(k0)
#else
PTR_LA k0, ejtag_debug_buffer
LONG_S k1, 0(k0)
#endif
SAVE_ALL
move a0, sp
jal ejtag_exception_handler
RESTORE_ALL
#ifdef CONFIG_SMP
ASM_CPUID_MFC0 k1, ASM_SMP_CPUID_REG
PTR_SRL k1, SMP_CPUID_PTRSHIFT
PTR_SLL k1, LONGLOG
PTR_LA k0, ejtag_debug_buffer_per_cpu
PTR_ADDU k0, k1
LONG_L k1, 0(k0)
#else
PTR_LA k0, ejtag_debug_buffer
LONG_L k1, 0(k0)
#endif
ejtag_return:
back_to_back_c0_hazard
MFC0 k0, CP0_DESAVE
.set mips32
deret
.set pop
END(ejtag_debug_handler)
.data
EXPORT(ejtag_debug_buffer)
.fill LONGSIZE
#ifdef CONFIG_SMP
EXPORT(ejtag_debug_buffer_spinlock)
.fill LONGSIZE
EXPORT(ejtag_debug_buffer_per_cpu)
.fill LONGSIZE * NR_CPUS
#endif
.previous
__INIT
NESTED(except_vec_nmi, 0, sp)
j nmi_handler
#ifdef CONFIG_CPU_MICROMIPS
nop
#endif
END(except_vec_nmi)
__FINIT
NESTED(nmi_handler, PT_SIZE, sp)
.cfi_signal_frame
.set push
.set noat
mfc0 k0, CP0_STATUS
ori k0, k0, ST0_EXL
li k1, ~(ST0_BEV | ST0_ERL)
and k0, k0, k1
mtc0 k0, CP0_STATUS
_ehb
SAVE_ALL
move a0, sp
jal nmi_exception_handler
.set pop
END(nmi_handler)
.macro __build_clear_none
.endm
.macro __build_clear_sti
TRACE_IRQS_ON
STI
.endm
.macro __build_clear_cli
CLI
TRACE_IRQS_OFF
.endm
.macro __build_clear_fpe
CLI
TRACE_IRQS_OFF
.set push
\
.set mips1
.set hardfloat
cfc1 a1, fcr31
.set pop
.endm
.macro __build_clear_msa_fpe
CLI
TRACE_IRQS_OFF
_cfcmsa a1, MSA_CSR
.endm
.macro __build_clear_ade
MFC0 t0, CP0_BADVADDR
PTR_S t0, PT_BVADDR(sp)
KMODE
.endm
.macro __build_clear_gsexc
.set push
.set mips32
mfc0 a1, CP0_DIAGNOSTIC1
.set pop
TRACE_IRQS_ON
STI
.endm
.macro __BUILD_silent exception
.endm
.macro __BUILD_verbose nexception
LONG_L a1, PT_EPC(sp)
#ifdef CONFIG_32BIT
ASM_PRINT("Got \nexception at %08lx\012")
#endif
#ifdef CONFIG_64BIT
ASM_PRINT("Got \nexception at %016lx\012")
#endif
.endm
.macro __BUILD_count exception
LONG_L t0,exception_count_\exception
LONG_ADDIU t0, 1
LONG_S t0,exception_count_\exception
.comm exception_count\exception, 8, 8
.endm
.macro __BUILD_HANDLER exception handler clear verbose ext
.align 5
NESTED(handle_\exception, PT_SIZE, sp)
.cfi_signal_frame
.set noat
SAVE_ALL
FEXPORT(handle_\exception\ext)
__build_clear_\clear
.set at
__BUILD_\verbose \exception
move a0, sp
jal do_\handler
j ret_from_exception
END(handle_\exception)
.endm
.macro BUILD_HANDLER exception handler clear verbose
__BUILD_HANDLER \exception \handler \clear \verbose _int
.endm
BUILD_HANDLER adel ade ade silent
BUILD_HANDLER ades ade ade silent
BUILD_HANDLER ibe be cli silent
BUILD_HANDLER dbe be cli silent
BUILD_HANDLER bp bp sti silent
BUILD_HANDLER ri ri sti silent
BUILD_HANDLER cpu cpu sti silent
BUILD_HANDLER ov ov sti silent
BUILD_HANDLER tr tr sti silent
BUILD_HANDLER msa_fpe msa_fpe msa_fpe silent
#ifdef CONFIG_MIPS_FP_SUPPORT
BUILD_HANDLER fpe fpe fpe silent
#endif
BUILD_HANDLER ftlb ftlb none silent
BUILD_HANDLER gsexc gsexc gsexc silent
BUILD_HANDLER msa msa sti silent
BUILD_HANDLER mdmx mdmx sti silent
#ifdef CONFIG_HARDWARE_WATCHPOINTS
BUILD_HANDLER watch watch cli silent
#else
BUILD_HANDLER watch watch sti verbose
#endif
BUILD_HANDLER mcheck mcheck cli verbose
BUILD_HANDLER mt mt sti silent
BUILD_HANDLER dsp dsp sti silent
BUILD_HANDLER reserved reserved sti verbose
.align 5
LEAF(handle_ri_rdhwr_tlbp)
.set push
.set noat
.set noreorder
MFC0 k1, CP0_ENTRYHI
andi k1, MIPS_ENTRYHI_ASID | MIPS_ENTRYHI_ASIDX
MFC0 k0, CP0_EPC
PTR_SRL k0, _PAGE_SHIFT + 1
PTR_SLL k0, _PAGE_SHIFT + 1
or k1, k0
MTC0 k1, CP0_ENTRYHI
mtc0_tlbw_hazard
tlbp
tlb_probe_hazard
mfc0 k1, CP0_INDEX
.set pop
bltz k1, handle_ri
END(handle_ri_rdhwr_tlbp)
LEAF(handle_ri_rdhwr)
.set push
.set noat
.set noreorder
MFC0 k1, CP0_EPC
#if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_CPU_MIPS64_R2)
and k0, k1, 1
beqz k0, 1f
xor k1, k0
lhu k0, (k1)
lhu k1, 2(k1)
ins k1, k0, 16, 16
lui k0, 0x007d
b docheck
ori k0, 0x6b3c
1:
lui k0, 0x7c03
lw k1, (k1)
ori k0, 0xe83b
#else
andi k0, k1, 1
bnez k0, handle_ri
lui k0, 0x7c03
lw k1, (k1)
ori k0, 0xe83b
#endif
.set reorder
docheck:
bne k0, k1, handle_ri
isrdhwr:
get_saved_sp
.set noreorder
MFC0 k0, CP0_EPC
#if defined(CONFIG_CPU_R3000)
ori k1, _THREAD_MASK
xori k1, _THREAD_MASK
LONG_L v1, TI_TP_VALUE(k1)
LONG_ADDIU k0, 4
jr k0
rfe
#else
#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
LONG_ADDIU k0, 4
#else
.set at=v1
LONG_ADDIU k0, 4
.set noat
#endif
MTC0 k0, CP0_EPC
ori k1, _THREAD_MASK
xori k1, _THREAD_MASK
LONG_L v1, TI_TP_VALUE(k1)
.set push
.set arch=r4000
eret
.set pop
#endif
.set pop
END(handle_ri_rdhwr)
#ifdef CONFIG_CPU_R4X00_BUGS64
__INIT
BUILD_HANDLER daddi_ov daddi_ov none silent
#endif