Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
entry.h
Go to the documentation of this file.
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 */