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