1 /* 2 * Copyright 2004-2009 Analog Devices Inc. 3 * 4 * Licensed under the GPL-2 or later. 5 */ 6 7 #ifndef __BFIN_ENTRY_H 8 #define __BFIN_ENTRY_H 9 10 #include <asm/setup.h> 11 #include <asm/page.h> 12 13 #ifdef __ASSEMBLY__ 14 15 #define LFLUSH_I_AND_D 0x00000808 16 #define LSIGTRAP 5 17 18 /* 19 * NOTE! The single-stepping code assumes that all interrupt handlers 20 * start by saving SYSCFG on the stack with their first instruction. 21 */ 22 23 /* This one is used for exceptions, emulation, and NMI. It doesn't push 24 RETI and doesn't do cli. */ 25 #define SAVE_ALL_SYS save_context_no_interrupts 26 /* This is used for all normal interrupts. It saves a minimum of registers 27 to the stack, loads the IRQ number, and jumps to common code. */ 28 #ifdef CONFIG_IPIPE 29 # define LOAD_IPIPE_IPEND \ 30 P0.l = lo(IPEND); \ 31 P0.h = hi(IPEND); \ 32 R1 = [P0]; 33 #else 34 # define LOAD_IPIPE_IPEND 35 #endif 36 37 /* 38 * Workaround for anomalies 05000283 and 05000315 39 */ 40 #if ANOMALY_05000283 || ANOMALY_05000315 41 # define ANOMALY_283_315_WORKAROUND(preg, dreg) \ 42 cc = dreg == dreg; \ 43 preg.h = HI(CHIPID); \ 44 preg.l = LO(CHIPID); \ 45 if cc jump 1f; \ 46 dreg.l = W[preg]; \ 47 1: 48 #else 49 # define ANOMALY_283_315_WORKAROUND(preg, dreg) 50 #endif /* ANOMALY_05000283 || ANOMALY_05000315 */ 51 52 #ifndef CONFIG_EXACT_HWERR 53 /* As a debugging aid - we save IPEND when DEBUG_KERNEL is on, 54 * otherwise it is a waste of cycles. 55 */ 56 # ifndef CONFIG_DEBUG_KERNEL 57 #define INTERRUPT_ENTRY(N) \ 58 [--sp] = SYSCFG; \ 59 [--sp] = P0; /*orig_p0*/ \ 60 [--sp] = R0; /*orig_r0*/ \ 61 [--sp] = (R7:0,P5:0); \ 62 R0 = (N); \ 63 LOAD_IPIPE_IPEND \ 64 jump __common_int_entry; 65 # else /* CONFIG_DEBUG_KERNEL */ 66 #define INTERRUPT_ENTRY(N) \ 67 [--sp] = SYSCFG; \ 68 [--sp] = P0; /*orig_p0*/ \ 69 [--sp] = R0; /*orig_r0*/ \ 70 [--sp] = (R7:0,P5:0); \ 71 p0.l = lo(IPEND); \ 72 p0.h = hi(IPEND); \ 73 r1 = [p0]; \ 74 R0 = (N); \ 75 LOAD_IPIPE_IPEND \ 76 jump __common_int_entry; 77 # endif /* CONFIG_DEBUG_KERNEL */ 78 79 /* For timer interrupts, we need to save IPEND, since the user_mode 80 *macro accesses it to determine where to account time. 81 */ 82 #define TIMER_INTERRUPT_ENTRY(N) \ 83 [--sp] = SYSCFG; \ 84 [--sp] = P0; /*orig_p0*/ \ 85 [--sp] = R0; /*orig_r0*/ \ 86 [--sp] = (R7:0,P5:0); \ 87 p0.l = lo(IPEND); \ 88 p0.h = hi(IPEND); \ 89 r1 = [p0]; \ 90 R0 = (N); \ 91 jump __common_int_entry; 92 #else /* CONFIG_EXACT_HWERR is defined */ 93 94 /* if we want hardware error to be exact, we need to do a SSYNC (which forces 95 * read/writes to complete to the memory controllers), and check to see that 96 * caused a pending HW error condition. If so, we assume it was caused by user 97 * space, by setting the same interrupt that we are in (so it goes off again) 98 * and context restore, and a RTI (without servicing anything). This should 99 * cause the pending HWERR to fire, and when that is done, this interrupt will 100 * be re-serviced properly. 101 * As you can see by the code - we actually need to do two SSYNCS - one to 102 * make sure the read/writes complete, and another to make sure the hardware 103 * error is recognized by the core. 104 * 105 * The extra nop before the SSYNC is to make sure we work around 05000244, 106 * since the 283/315 workaround includes a branch to the end 107 */ 108 #define INTERRUPT_ENTRY(N) \ 109 [--sp] = SYSCFG; \ 110 [--sp] = P0; /*orig_p0*/ \ 111 [--sp] = R0; /*orig_r0*/ \ 112 [--sp] = (R7:0,P5:0); \ 113 R1 = ASTAT; \ 114 ANOMALY_283_315_WORKAROUND(p0, r0) \ 115 P0.L = LO(ILAT); \ 116 P0.H = HI(ILAT); \ 117 NOP; \ 118 SSYNC; \ 119 SSYNC; \ 120 R0 = [P0]; \ 121 CC = BITTST(R0, EVT_IVHW_P); \ 122 IF CC JUMP 1f; \ 123 ASTAT = R1; \ 124 p0.l = lo(IPEND); \ 125 p0.h = hi(IPEND); \ 126 r1 = [p0]; \ 127 R0 = (N); \ 128 LOAD_IPIPE_IPEND \ 129 jump __common_int_entry; \ 130 1: ASTAT = R1; \ 131 RAISE N; \ 132 (R7:0, P5:0) = [SP++]; \ 133 SP += 0x8; \ 134 SYSCFG = [SP++]; \ 135 CSYNC; \ 136 RTI; 137 138 #define TIMER_INTERRUPT_ENTRY(N) \ 139 [--sp] = SYSCFG; \ 140 [--sp] = P0; /*orig_p0*/ \ 141 [--sp] = R0; /*orig_r0*/ \ 142 [--sp] = (R7:0,P5:0); \ 143 R1 = ASTAT; \ 144 ANOMALY_283_315_WORKAROUND(p0, r0) \ 145 P0.L = LO(ILAT); \ 146 P0.H = HI(ILAT); \ 147 NOP; \ 148 SSYNC; \ 149 SSYNC; \ 150 R0 = [P0]; \ 151 CC = BITTST(R0, EVT_IVHW_P); \ 152 IF CC JUMP 1f; \ 153 ASTAT = R1; \ 154 p0.l = lo(IPEND); \ 155 p0.h = hi(IPEND); \ 156 r1 = [p0]; \ 157 R0 = (N); \ 158 jump __common_int_entry; \ 159 1: ASTAT = R1; \ 160 RAISE N; \ 161 (R7:0, P5:0) = [SP++]; \ 162 SP += 0x8; \ 163 SYSCFG = [SP++]; \ 164 CSYNC; \ 165 RTI; 166 #endif /* CONFIG_EXACT_HWERR */ 167 168 /* This one pushes RETI without using CLI. Interrupts are enabled. */ 169 #define SAVE_CONTEXT_SYSCALL save_context_syscall 170 #define SAVE_CONTEXT save_context_with_interrupts 171 #define SAVE_CONTEXT_CPLB save_context_cplb 172 173 #define RESTORE_ALL_SYS restore_context_no_interrupts 174 #define RESTORE_CONTEXT restore_context_with_interrupts 175 #define RESTORE_CONTEXT_CPLB restore_context_cplb 176 177 #endif /* __ASSEMBLY__ */ 178 #endif /* __BFIN_ENTRY_H */ 179