Merge branches 'irq-core-for-linus' and 'core-locking-for-linus' of git://git.kernel...
[pandora-kernel.git] / arch / blackfin / include / asm / entry.h
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 */