/* * Copyright 2004-2009 Analog Devices Inc. * * Licensed under the GPL-2 or later. */ #ifndef __BFIN_ENTRY_H #define __BFIN_ENTRY_H #include <asm/setup.h> #include <asm/page.h> #ifdef __ASSEMBLY__ #define LFLUSH_I_AND_D 0x00000808 #define LSIGTRAP 5 /* * NOTE! The single-stepping code assumes that all interrupt handlers * start by saving SYSCFG on the stack with their first instruction. */ /* This one is used for exceptions, emulation, and NMI. It doesn't push RETI and doesn't do cli. */ #define SAVE_ALL_SYS save_context_no_interrupts /* This is used for all normal interrupts. It saves a minimum of registers to the stack, loads the IRQ number, and jumps to common code. */ #ifdef CONFIG_IPIPE # define LOAD_IPIPE_IPEND \ P0.l = lo(IPEND); \ P0.h = hi(IPEND); \ R1 = [P0]; #else # define LOAD_IPIPE_IPEND #endif /* * Workaround for anomalies 05000283 and 05000315 */ #if ANOMALY_05000283 || ANOMALY_05000315 # define ANOMALY_283_315_WORKAROUND(preg, dreg) \ cc = dreg == dreg; \ preg.h = HI(CHIPID); \ preg.l = LO(CHIPID); \ if cc jump 1f; \ dreg.l = W[preg]; \ 1: #else # define ANOMALY_283_315_WORKAROUND(preg, dreg) #endif /* ANOMALY_05000283 || ANOMALY_05000315 */ #ifndef CONFIG_EXACT_HWERR /* As a debugging aid - we save IPEND when DEBUG_KERNEL is on, * otherwise it is a waste of cycles. */ # ifndef CONFIG_DEBUG_KERNEL #define INTERRUPT_ENTRY(N) \ [--sp] = SYSCFG; \ [--sp] = P0; /*orig_p0*/ \ [--sp] = R0; /*orig_r0*/ \ [--sp] = (R7:0,P5:0); \ R0 = (N); \ LOAD_IPIPE_IPEND \ jump __common_int_entry; # else /* CONFIG_DEBUG_KERNEL */ #define INTERRUPT_ENTRY(N) \ [--sp] = SYSCFG; \ [--sp] = P0; /*orig_p0*/ \ [--sp] = R0; /*orig_r0*/ \ [--sp] = (R7:0,P5:0); \ p0.l = lo(IPEND); \ p0.h = hi(IPEND); \ r1 = [p0]; \ R0 = (N); \ LOAD_IPIPE_IPEND \ jump __common_int_entry; # endif /* CONFIG_DEBUG_KERNEL */ /* For timer interrupts, we need to save IPEND, since the user_mode *macro accesses it to determine where to account time. */ #define TIMER_INTERRUPT_ENTRY(N) \ [--sp] = SYSCFG; \ [--sp] = P0; /*orig_p0*/ \ [--sp] = R0; /*orig_r0*/ \ [--sp] = (R7:0,P5:0); \ p0.l = lo(IPEND); \ p0.h = hi(IPEND); \ r1 = [p0]; \ R0 = (N); \ jump __common_int_entry; #else /* CONFIG_EXACT_HWERR is defined */ /* if we want hardware error to be exact, we need to do a SSYNC (which forces * read/writes to complete to the memory controllers), and check to see that * caused a pending HW error condition. If so, we assume it was caused by user * space, by setting the same interrupt that we are in (so it goes off again) * and context restore, and a RTI (without servicing anything). This should * cause the pending HWERR to fire, and when that is done, this interrupt will * be re-serviced properly. * As you can see by the code - we actually need to do two SSYNCS - one to * make sure the read/writes complete, and another to make sure the hardware * error is recognized by the core. * * The extra nop before the SSYNC is to make sure we work around 05000244, * since the 283/315 workaround includes a branch to the end */ #define INTERRUPT_ENTRY(N) \ [--sp] = SYSCFG; \ [--sp] = P0; /*orig_p0*/ \ [--sp] = R0; /*orig_r0*/ \ [--sp] = (R7:0,P5:0); \ R1 = ASTAT; \ ANOMALY_283_315_WORKAROUND(p0, r0) \ P0.L = LO(ILAT); \ P0.H = HI(ILAT); \ NOP; \ SSYNC; \ SSYNC; \ R0 = [P0]; \ CC = BITTST(R0, EVT_IVHW_P); \ IF CC JUMP 1f; \ ASTAT = R1; \ p0.l = lo(IPEND); \ p0.h = hi(IPEND); \ r1 = [p0]; \ R0 = (N); \ LOAD_IPIPE_IPEND \ jump __common_int_entry; \ 1: ASTAT = R1; \ RAISE N; \ (R7:0, P5:0) = [SP++]; \ SP += 0x8; \ SYSCFG = [SP++]; \ CSYNC; \ RTI; #define TIMER_INTERRUPT_ENTRY(N) \ [--sp] = SYSCFG; \ [--sp] = P0; /*orig_p0*/ \ [--sp] = R0; /*orig_r0*/ \ [--sp] = (R7:0,P5:0); \ R1 = ASTAT; \ ANOMALY_283_315_WORKAROUND(p0, r0) \ P0.L = LO(ILAT); \ P0.H = HI(ILAT); \ NOP; \ SSYNC; \ SSYNC; \ R0 = [P0]; \ CC = BITTST(R0, EVT_IVHW_P); \ IF CC JUMP 1f; \ ASTAT = R1; \ p0.l = lo(IPEND); \ p0.h = hi(IPEND); \ r1 = [p0]; \ R0 = (N); \ jump __common_int_entry; \ 1: ASTAT = R1; \ RAISE N; \ (R7:0, P5:0) = [SP++]; \ SP += 0x8; \ SYSCFG = [SP++]; \ CSYNC; \ RTI; #endif /* CONFIG_EXACT_HWERR */ /* This one pushes RETI without using CLI. Interrupts are enabled. */ #define SAVE_CONTEXT_SYSCALL save_context_syscall #define SAVE_CONTEXT save_context_with_interrupts #define SAVE_CONTEXT_CPLB save_context_cplb #define RESTORE_ALL_SYS restore_context_no_interrupts #define RESTORE_CONTEXT restore_context_with_interrupts #define RESTORE_CONTEXT_CPLB restore_context_cplb #endif /* __ASSEMBLY__ */ #endif /* __BFIN_ENTRY_H */