123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- /*
- * 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 */
|