/*1* This file is subject to the terms and conditions of the GNU General Public2* License. See the file "COPYING" in the main directory of this archive3* for more details.4*5* Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle6* Copyright (C) 1999, 2000 Silicon Graphics, Inc.7* Copyright (C) 2001 MIPS Technologies, Inc.8* Copyright (C) 2002, 2007 Maciej W. Rozycki9*/10#include <linux/init.h>1112#include <asm/asm.h>13#include <asm/asmmacro.h>14#include <asm/cacheops.h>15#include <asm/irqflags.h>16#include <asm/regdef.h>17#include <asm/fpregdef.h>18#include <asm/mipsregs.h>19#include <asm/stackframe.h>20#include <asm/war.h>21#include <asm/page.h>22#include <asm/thread_info.h>2324#define PANIC_PIC(msg) \25.set push; \26.set reorder; \27PTR_LA a0,8f; \28.set noat; \29PTR_LA AT, panic; \30jr AT; \319: b 9b; \32.set pop; \33TEXT(msg)3435__INIT3637NESTED(except_vec0_generic, 0, sp)38PANIC_PIC("Exception vector 0 called")39END(except_vec0_generic)4041NESTED(except_vec1_generic, 0, sp)42PANIC_PIC("Exception vector 1 called")43END(except_vec1_generic)4445/*46* General exception vector for all other CPUs.47*48* Be careful when changing this, it has to be at most 128 bytes49* to fit into space reserved for the exception handler.50*/51NESTED(except_vec3_generic, 0, sp)52.set push53.set noat54#if R5432_CP0_INTERRUPT_WAR55mfc0 k0, CP0_INDEX56#endif57mfc0 k1, CP0_CAUSE58andi k1, k1, 0x7c59#ifdef CONFIG_64BIT60dsll k1, k1, 161#endif62PTR_L k0, exception_handlers(k1)63jr k064.set pop65END(except_vec3_generic)6667/*68* General exception handler for CPUs with virtual coherency exception.69*70* Be careful when changing this, it has to be at most 256 (as a special71* exception) bytes to fit into space reserved for the exception handler.72*/73NESTED(except_vec3_r4000, 0, sp)74.set push75.set mips376.set noat77mfc0 k1, CP0_CAUSE78li k0, 31<<279andi k1, k1, 0x7c80.set push81.set noreorder82.set nomacro83beq k1, k0, handle_vced84li k0, 14<<285beq k1, k0, handle_vcei86#ifdef CONFIG_64BIT87dsll k1, k1, 188#endif89.set pop90PTR_L k0, exception_handlers(k1)91jr k09293/*94* Big shit, we now may have two dirty primary cache lines for the same95* physical address. We can safely invalidate the line pointed to by96* c0_badvaddr because after return from this exception handler the97* load / store will be re-executed.98*/99handle_vced:100MFC0 k0, CP0_BADVADDR101li k1, -4 # Is this ...102and k0, k1 # ... really needed?103mtc0 zero, CP0_TAGLO104cache Index_Store_Tag_D, (k0)105cache Hit_Writeback_Inv_SD, (k0)106#ifdef CONFIG_PROC_FS107PTR_LA k0, vced_count108lw k1, (k0)109addiu k1, 1110sw k1, (k0)111#endif112eret113114handle_vcei:115MFC0 k0, CP0_BADVADDR116cache Hit_Writeback_Inv_SD, (k0) # also cleans pi117#ifdef CONFIG_PROC_FS118PTR_LA k0, vcei_count119lw k1, (k0)120addiu k1, 1121sw k1, (k0)122#endif123eret124.set pop125END(except_vec3_r4000)126127__FINIT128129.align 5 /* 32 byte rollback region */130LEAF(r4k_wait)131.set push132.set noreorder133/* start of rollback region */134LONG_L t0, TI_FLAGS($28)135nop136andi t0, _TIF_NEED_RESCHED137bnez t0, 1f138nop139nop140nop141.set mips3142wait143/* end of rollback region (the region size must be power of two) */144.set pop1451:146jr ra147END(r4k_wait)148149.macro BUILD_ROLLBACK_PROLOGUE handler150FEXPORT(rollback_\handler)151.set push152.set noat153MFC0 k0, CP0_EPC154PTR_LA k1, r4k_wait155ori k0, 0x1f /* 32 byte rollback region */156xori k0, 0x1f157bne k0, k1, 9f158MTC0 k0, CP0_EPC1599:160.set pop161.endm162163.align 5164BUILD_ROLLBACK_PROLOGUE handle_int165NESTED(handle_int, PT_SIZE, sp)166#ifdef CONFIG_TRACE_IRQFLAGS167/*168* Check to see if the interrupted code has just disabled169* interrupts and ignore this interrupt for now if so.170*171* local_irq_disable() disables interrupts and then calls172* trace_hardirqs_off() to track the state. If an interrupt is taken173* after interrupts are disabled but before the state is updated174* it will appear to restore_all that it is incorrectly returning with175* interrupts disabled176*/177.set push178.set noat179mfc0 k0, CP0_STATUS180#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)181and k0, ST0_IEP182bnez k0, 1f183184mfc0 k0, CP0_EPC185.set noreorder186j k0187rfe188#else189and k0, ST0_IE190bnez k0, 1f191192eret193#endif1941:195.set pop196#endif197SAVE_ALL198CLI199TRACE_IRQS_OFF200201LONG_L s0, TI_REGS($28)202LONG_S sp, TI_REGS($28)203PTR_LA ra, ret_from_irq204j plat_irq_dispatch205END(handle_int)206207__INIT208209/*210* Special interrupt vector for MIPS64 ISA & embedded MIPS processors.211* This is a dedicated interrupt exception vector which reduces the212* interrupt processing overhead. The jump instruction will be replaced213* at the initialization time.214*215* Be careful when changing this, it has to be at most 128 bytes216* to fit into space reserved for the exception handler.217*/218NESTED(except_vec4, 0, sp)2191: j 1b /* Dummy, will be replaced */220END(except_vec4)221222/*223* EJTAG debug exception handler.224* The EJTAG debug exception entry point is 0xbfc00480, which225* normally is in the boot PROM, so the boot PROM must do a226* unconditional jump to this vector.227*/228NESTED(except_vec_ejtag_debug, 0, sp)229j ejtag_debug_handler230END(except_vec_ejtag_debug)231232__FINIT233234/*235* Vectored interrupt handler.236* This prototype is copied to ebase + n*IntCtl.VS and patched237* to invoke the handler238*/239BUILD_ROLLBACK_PROLOGUE except_vec_vi240NESTED(except_vec_vi, 0, sp)241SAVE_SOME242SAVE_AT243.set push244.set noreorder245#ifdef CONFIG_MIPS_MT_SMTC246/*247* To keep from blindly blocking *all* interrupts248* during service by SMTC kernel, we also want to249* pass the IM value to be cleared.250*/251FEXPORT(except_vec_vi_mori)252ori a0, $0, 0253#endif /* CONFIG_MIPS_MT_SMTC */254FEXPORT(except_vec_vi_lui)255lui v0, 0 /* Patched */256j except_vec_vi_handler257FEXPORT(except_vec_vi_ori)258ori v0, 0 /* Patched */259.set pop260END(except_vec_vi)261EXPORT(except_vec_vi_end)262263/*264* Common Vectored Interrupt code265* Complete the register saves and invoke the handler which is passed in $v0266*/267NESTED(except_vec_vi_handler, 0, sp)268SAVE_TEMP269SAVE_STATIC270#ifdef CONFIG_MIPS_MT_SMTC271/*272* SMTC has an interesting problem that interrupts are level-triggered,273* and the CLI macro will clear EXL, potentially causing a duplicate274* interrupt service invocation. So we need to clear the associated275* IM bit of Status prior to doing CLI, and restore it after the276* service routine has been invoked - we must assume that the277* service routine will have cleared the state, and any active278* level represents a new or otherwised unserviced event...279*/280mfc0 t1, CP0_STATUS281and t0, a0, t1282#ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP283mfc0 t2, CP0_TCCONTEXT284or t2, t0, t2285mtc0 t2, CP0_TCCONTEXT286#endif /* CONFIG_MIPS_MT_SMTC_IM_BACKSTOP */287xor t1, t1, t0288mtc0 t1, CP0_STATUS289_ehb290#endif /* CONFIG_MIPS_MT_SMTC */291CLI292#ifdef CONFIG_TRACE_IRQFLAGS293move s0, v0294#ifdef CONFIG_MIPS_MT_SMTC295move s1, a0296#endif297TRACE_IRQS_OFF298#ifdef CONFIG_MIPS_MT_SMTC299move a0, s1300#endif301move v0, s0302#endif303304LONG_L s0, TI_REGS($28)305LONG_S sp, TI_REGS($28)306PTR_LA ra, ret_from_irq307jr v0308END(except_vec_vi_handler)309310/*311* EJTAG debug exception handler.312*/313NESTED(ejtag_debug_handler, PT_SIZE, sp)314.set push315.set noat316MTC0 k0, CP0_DESAVE317mfc0 k0, CP0_DEBUG318319sll k0, k0, 30 # Check for SDBBP.320bgez k0, ejtag_return321322PTR_LA k0, ejtag_debug_buffer323LONG_S k1, 0(k0)324SAVE_ALL325move a0, sp326jal ejtag_exception_handler327RESTORE_ALL328PTR_LA k0, ejtag_debug_buffer329LONG_L k1, 0(k0)330331ejtag_return:332MFC0 k0, CP0_DESAVE333.set mips32334deret335.set pop336END(ejtag_debug_handler)337338/*339* This buffer is reserved for the use of the EJTAG debug340* handler.341*/342.data343EXPORT(ejtag_debug_buffer)344.fill LONGSIZE345.previous346347__INIT348349/*350* NMI debug exception handler for MIPS reference boards.351* The NMI debug exception entry point is 0xbfc00000, which352* normally is in the boot PROM, so the boot PROM must do a353* unconditional jump to this vector.354*/355NESTED(except_vec_nmi, 0, sp)356j nmi_handler357END(except_vec_nmi)358359__FINIT360361NESTED(nmi_handler, PT_SIZE, sp)362.set push363.set noat364SAVE_ALL365move a0, sp366jal nmi_exception_handler367RESTORE_ALL368.set mips3369eret370.set pop371END(nmi_handler)372373.macro __build_clear_none374.endm375376.macro __build_clear_sti377TRACE_IRQS_ON378STI379.endm380381.macro __build_clear_cli382CLI383TRACE_IRQS_OFF384.endm385386.macro __build_clear_fpe387.set push388/* gas fails to assemble cfc1 for some archs (octeon).*/ \389.set mips1390cfc1 a1, fcr31391li a2, ~(0x3f << 12)392and a2, a1393ctc1 a2, fcr31394.set pop395TRACE_IRQS_ON396STI397.endm398399.macro __build_clear_ade400MFC0 t0, CP0_BADVADDR401PTR_S t0, PT_BVADDR(sp)402KMODE403.endm404405.macro __BUILD_silent exception406.endm407408/* Gas tries to parse the PRINT argument as a string containing409string escapes and emits bogus warnings if it believes to410recognize an unknown escape code. So make the arguments411start with an n and gas will believe \n is ok ... */412.macro __BUILD_verbose nexception413LONG_L a1, PT_EPC(sp)414#ifdef CONFIG_32BIT415PRINT("Got \nexception at %08lx\012")416#endif417#ifdef CONFIG_64BIT418PRINT("Got \nexception at %016lx\012")419#endif420.endm421422.macro __BUILD_count exception423LONG_L t0,exception_count_\exception424LONG_ADDIU t0, 1425LONG_S t0,exception_count_\exception426.comm exception_count\exception, 8, 8427.endm428429.macro __BUILD_HANDLER exception handler clear verbose ext430.align 5431NESTED(handle_\exception, PT_SIZE, sp)432.set noat433SAVE_ALL434FEXPORT(handle_\exception\ext)435__BUILD_clear_\clear436.set at437__BUILD_\verbose \exception438move a0, sp439PTR_LA ra, ret_from_exception440j do_\handler441END(handle_\exception)442.endm443444.macro BUILD_HANDLER exception handler clear verbose445__BUILD_HANDLER \exception \handler \clear \verbose _int446.endm447448BUILD_HANDLER adel ade ade silent /* #4 */449BUILD_HANDLER ades ade ade silent /* #5 */450BUILD_HANDLER ibe be cli silent /* #6 */451BUILD_HANDLER dbe be cli silent /* #7 */452BUILD_HANDLER bp bp sti silent /* #9 */453BUILD_HANDLER ri ri sti silent /* #10 */454BUILD_HANDLER cpu cpu sti silent /* #11 */455BUILD_HANDLER ov ov sti silent /* #12 */456BUILD_HANDLER tr tr sti silent /* #13 */457BUILD_HANDLER fpe fpe fpe silent /* #15 */458BUILD_HANDLER mdmx mdmx sti silent /* #22 */459#ifdef CONFIG_HARDWARE_WATCHPOINTS460/*461* For watch, interrupts will be enabled after the watch462* registers are read.463*/464BUILD_HANDLER watch watch cli silent /* #23 */465#else466BUILD_HANDLER watch watch sti verbose /* #23 */467#endif468BUILD_HANDLER mcheck mcheck cli verbose /* #24 */469BUILD_HANDLER mt mt sti silent /* #25 */470BUILD_HANDLER dsp dsp sti silent /* #26 */471BUILD_HANDLER reserved reserved sti verbose /* others */472473.align 5474LEAF(handle_ri_rdhwr_vivt)475#ifdef CONFIG_MIPS_MT_SMTC476PANIC_PIC("handle_ri_rdhwr_vivt called")477#else478.set push479.set noat480.set noreorder481/* check if TLB contains a entry for EPC */482MFC0 k1, CP0_ENTRYHI483andi k1, 0xff /* ASID_MASK */484MFC0 k0, CP0_EPC485PTR_SRL k0, PAGE_SHIFT + 1486PTR_SLL k0, PAGE_SHIFT + 1487or k1, k0488MTC0 k1, CP0_ENTRYHI489mtc0_tlbw_hazard490tlbp491tlb_probe_hazard492mfc0 k1, CP0_INDEX493.set pop494bltz k1, handle_ri /* slow path */495/* fall thru */496#endif497END(handle_ri_rdhwr_vivt)498499LEAF(handle_ri_rdhwr)500.set push501.set noat502.set noreorder503/* 0x7c03e83b: rdhwr v1,$29 */504MFC0 k1, CP0_EPC505lui k0, 0x7c03506lw k1, (k1)507ori k0, 0xe83b508.set reorder509bne k0, k1, handle_ri /* if not ours */510/* The insn is rdhwr. No need to check CAUSE.BD here. */511get_saved_sp /* k1 := current_thread_info */512.set noreorder513MFC0 k0, CP0_EPC514#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)515ori k1, _THREAD_MASK516xori k1, _THREAD_MASK517LONG_L v1, TI_TP_VALUE(k1)518LONG_ADDIU k0, 4519jr k0520rfe521#else522#ifndef CONFIG_CPU_DADDI_WORKAROUNDS523LONG_ADDIU k0, 4 /* stall on $k0 */524#else525.set at=v1526LONG_ADDIU k0, 4527.set noat528#endif529MTC0 k0, CP0_EPC530/* I hope three instructions between MTC0 and ERET are enough... */531ori k1, _THREAD_MASK532xori k1, _THREAD_MASK533LONG_L v1, TI_TP_VALUE(k1)534.set mips3535eret536.set mips0537#endif538.set pop539END(handle_ri_rdhwr)540541#ifdef CONFIG_64BIT542/* A temporary overflow handler used by check_daddi(). */543544__INIT545546BUILD_HANDLER daddi_ov daddi_ov none silent /* #12 */547#endif548549550