Commit | Line | Data |
---|---|---|
df9ee292 DH |
1 | /* MN10300 IRQ flag handling |
2 | * | |
3 | * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. | |
4 | * Written by David Howells (dhowells@redhat.com) | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public Licence | |
8 | * as published by the Free Software Foundation; either version | |
9 | * 2 of the Licence, or (at your option) any later version. | |
10 | */ | |
11 | ||
12 | #ifndef _ASM_IRQFLAGS_H | |
13 | #define _ASM_IRQFLAGS_H | |
14 | ||
15 | #include <asm/cpu-regs.h> | |
368dd5ac AT |
16 | #ifndef __ASSEMBLY__ |
17 | #include <linux/smp.h> | |
18 | #endif | |
df9ee292 DH |
19 | |
20 | /* | |
21 | * interrupt control | |
22 | * - "disabled": run in IM1/2 | |
67ddb405 | 23 | * - level 0 - kernel debugger |
df9ee292 DH |
24 | * - level 1 - virtual serial DMA (if present) |
25 | * - level 5 - normal interrupt priority | |
26 | * - level 6 - timer interrupt | |
27 | * - "enabled": run in IM7 | |
28 | */ | |
37e4ec96 | 29 | #define MN10300_CLI_LEVEL (CONFIG_LINUX_CLI_LEVEL << EPSW_IM_SHIFT) |
df9ee292 DH |
30 | |
31 | #ifndef __ASSEMBLY__ | |
32 | ||
33 | static inline unsigned long arch_local_save_flags(void) | |
34 | { | |
35 | unsigned long flags; | |
36 | ||
37 | asm volatile("mov epsw,%0" : "=d"(flags)); | |
38 | return flags; | |
39 | } | |
40 | ||
41 | static inline void arch_local_irq_disable(void) | |
42 | { | |
43 | asm volatile( | |
44 | " and %0,epsw \n" | |
45 | " or %1,epsw \n" | |
46 | " nop \n" | |
47 | " nop \n" | |
48 | " nop \n" | |
49 | : | |
50 | : "i"(~EPSW_IM), "i"(EPSW_IE | MN10300_CLI_LEVEL) | |
51 | : "memory"); | |
52 | } | |
53 | ||
54 | static inline unsigned long arch_local_irq_save(void) | |
55 | { | |
56 | unsigned long flags; | |
57 | ||
58 | flags = arch_local_save_flags(); | |
59 | arch_local_irq_disable(); | |
60 | return flags; | |
61 | } | |
62 | ||
63 | /* | |
64 | * we make sure arch_irq_enable() doesn't cause priority inversion | |
65 | */ | |
368dd5ac | 66 | extern unsigned long __mn10300_irq_enabled_epsw[]; |
df9ee292 DH |
67 | |
68 | static inline void arch_local_irq_enable(void) | |
69 | { | |
70 | unsigned long tmp; | |
368dd5ac | 71 | int cpu = raw_smp_processor_id(); |
df9ee292 DH |
72 | |
73 | asm volatile( | |
74 | " mov epsw,%0 \n" | |
75 | " and %1,%0 \n" | |
76 | " or %2,%0 \n" | |
77 | " mov %0,epsw \n" | |
78 | : "=&d"(tmp) | |
368dd5ac AT |
79 | : "i"(~EPSW_IM), "r"(__mn10300_irq_enabled_epsw[cpu]) |
80 | : "memory", "cc"); | |
df9ee292 DH |
81 | } |
82 | ||
83 | static inline void arch_local_irq_restore(unsigned long flags) | |
84 | { | |
85 | asm volatile( | |
86 | " mov %0,epsw \n" | |
87 | " nop \n" | |
88 | " nop \n" | |
89 | " nop \n" | |
90 | : | |
91 | : "d"(flags) | |
92 | : "memory", "cc"); | |
93 | } | |
94 | ||
95 | static inline bool arch_irqs_disabled_flags(unsigned long flags) | |
96 | { | |
37e4ec96 | 97 | return (flags & (EPSW_IE | EPSW_IM)) != (EPSW_IE | EPSW_IM_7); |
df9ee292 DH |
98 | } |
99 | ||
100 | static inline bool arch_irqs_disabled(void) | |
101 | { | |
102 | return arch_irqs_disabled_flags(arch_local_save_flags()); | |
103 | } | |
104 | ||
105 | /* | |
106 | * Hook to save power by halting the CPU | |
107 | * - called from the idle loop | |
108 | * - must reenable interrupts (which takes three instruction cycles to complete) | |
109 | */ | |
110 | static inline void arch_safe_halt(void) | |
111 | { | |
368dd5ac AT |
112 | #ifdef CONFIG_SMP |
113 | arch_local_irq_enable(); | |
114 | #else | |
df9ee292 DH |
115 | asm volatile( |
116 | " or %0,epsw \n" | |
117 | " nop \n" | |
118 | " nop \n" | |
119 | " bset %2,(%1) \n" | |
120 | : | |
121 | : "i"(EPSW_IE|EPSW_IM), "n"(&CPUM), "i"(CPUM_SLEEP) | |
122 | : "cc"); | |
368dd5ac | 123 | #endif |
df9ee292 DH |
124 | } |
125 | ||
368dd5ac AT |
126 | #define __sleep_cpu() \ |
127 | do { \ | |
128 | asm volatile( \ | |
129 | " bset %1,(%0)\n" \ | |
130 | "1: btst %1,(%0)\n" \ | |
131 | " bne 1b\n" \ | |
132 | : \ | |
133 | : "i"(&CPUM), "i"(CPUM_SLEEP) \ | |
134 | : "cc" \ | |
135 | ); \ | |
136 | } while (0) | |
137 | ||
9f200d3f AT |
138 | static inline void arch_local_cli(void) |
139 | { | |
140 | asm volatile( | |
141 | " and %0,epsw \n" | |
142 | " nop \n" | |
143 | " nop \n" | |
144 | " nop \n" | |
145 | : | |
146 | : "i"(~EPSW_IE) | |
147 | : "memory" | |
148 | ); | |
149 | } | |
150 | ||
151 | static inline unsigned long arch_local_cli_save(void) | |
152 | { | |
153 | unsigned long flags = arch_local_save_flags(); | |
154 | arch_local_cli(); | |
155 | return flags; | |
156 | } | |
157 | ||
158 | static inline void arch_local_sti(void) | |
159 | { | |
160 | asm volatile( | |
161 | " or %0,epsw \n" | |
162 | : | |
163 | : "i"(EPSW_IE) | |
164 | : "memory"); | |
165 | } | |
166 | ||
167 | static inline void arch_local_change_intr_mask_level(unsigned long level) | |
168 | { | |
169 | asm volatile( | |
170 | " and %0,epsw \n" | |
171 | " or %1,epsw \n" | |
172 | : | |
173 | : "i"(~EPSW_IM), "i"(EPSW_IE | level) | |
174 | : "cc", "memory"); | |
175 | } | |
176 | ||
177 | #else /* !__ASSEMBLY__ */ | |
178 | ||
179 | #define LOCAL_SAVE_FLAGS(reg) \ | |
180 | mov epsw,reg | |
181 | ||
182 | #define LOCAL_IRQ_DISABLE \ | |
183 | and ~EPSW_IM,epsw; \ | |
184 | or EPSW_IE|MN10300_CLI_LEVEL,epsw; \ | |
185 | nop; \ | |
186 | nop; \ | |
187 | nop | |
188 | ||
189 | #define LOCAL_IRQ_ENABLE \ | |
190 | or EPSW_IE|EPSW_IM_7,epsw | |
191 | ||
192 | #define LOCAL_IRQ_RESTORE(reg) \ | |
193 | mov reg,epsw | |
194 | ||
195 | #define LOCAL_CLI_SAVE(reg) \ | |
196 | mov epsw,reg; \ | |
197 | and ~EPSW_IE,epsw; \ | |
198 | nop; \ | |
199 | nop; \ | |
200 | nop | |
201 | ||
202 | #define LOCAL_CLI \ | |
203 | and ~EPSW_IE,epsw; \ | |
204 | nop; \ | |
205 | nop; \ | |
206 | nop | |
207 | ||
208 | #define LOCAL_STI \ | |
209 | or EPSW_IE,epsw | |
210 | ||
211 | #define LOCAL_CHANGE_INTR_MASK_LEVEL(level) \ | |
212 | and ~EPSW_IM,epsw; \ | |
213 | or EPSW_IE|(level),epsw | |
214 | ||
df9ee292 DH |
215 | #endif /* __ASSEMBLY__ */ |
216 | #endif /* _ASM_IRQFLAGS_H */ |