aboutsummaryrefslogtreecommitdiffstats
path: root/arch/tile/include/asm/irqflags.h
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2010-05-28 23:09:12 -0400
committerChris Metcalf <cmetcalf@tilera.com>2010-06-04 17:11:18 -0400
commit867e359b97c970a60626d5d76bbe2a8fadbf38fb (patch)
treec5ccbb7f5172e8555977119608ecb1eee3cc37e3 /arch/tile/include/asm/irqflags.h
parent5360bd776f73d0a7da571d72a09a03f237e99900 (diff)
arch/tile: core support for Tilera 32-bit chips.
This change is the core kernel support for TILEPro and TILE64 chips. No driver support (except the console driver) is included yet. This includes the relevant Linux headers in asm/; the low-level low-level "Tile architecture" headers in arch/, which are shared with the hypervisor, etc., and are build-system agnostic; and the relevant hypervisor headers in hv/. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Acked-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> Reviewed-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/tile/include/asm/irqflags.h')
-rw-r--r--arch/tile/include/asm/irqflags.h267
1 files changed, 267 insertions, 0 deletions
diff --git a/arch/tile/include/asm/irqflags.h b/arch/tile/include/asm/irqflags.h
new file mode 100644
index 000000000000..cf5bffd00fef
--- /dev/null
+++ b/arch/tile/include/asm/irqflags.h
@@ -0,0 +1,267 @@
1/*
2 * Copyright 2010 Tilera Corporation. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11 * NON INFRINGEMENT. See the GNU General Public License for
12 * more details.
13 */
14
15#ifndef _ASM_TILE_IRQFLAGS_H
16#define _ASM_TILE_IRQFLAGS_H
17
18#include <asm/processor.h>
19#include <arch/interrupts.h>
20#include <arch/chip.h>
21
22/*
23 * The set of interrupts we want to allow when interrupts are nominally
24 * disabled. The remainder are effectively "NMI" interrupts from
25 * the point of view of the generic Linux code. Note that synchronous
26 * interrupts (aka "non-queued") are not blocked by the mask in any case.
27 */
28#if CHIP_HAS_AUX_PERF_COUNTERS()
29#define LINUX_MASKABLE_INTERRUPTS \
30 (~(INT_MASK(INT_PERF_COUNT) | INT_MASK(INT_AUX_PERF_COUNT)))
31#else
32#define LINUX_MASKABLE_INTERRUPTS \
33 (~(INT_MASK(INT_PERF_COUNT)))
34#endif
35
36#ifndef __ASSEMBLY__
37
38/* NOTE: we can't include <linux/percpu.h> due to #include dependencies. */
39#include <asm/percpu.h>
40#include <arch/spr_def.h>
41
42/* Set and clear kernel interrupt masks. */
43#if CHIP_HAS_SPLIT_INTR_MASK()
44#if INT_PERF_COUNT < 32 || INT_AUX_PERF_COUNT < 32 || INT_MEM_ERROR >= 32
45# error Fix assumptions about which word various interrupts are in
46#endif
47#define interrupt_mask_set(n) do { \
48 int __n = (n); \
49 int __mask = 1 << (__n & 0x1f); \
50 if (__n < 32) \
51 __insn_mtspr(SPR_INTERRUPT_MASK_SET_1_0, __mask); \
52 else \
53 __insn_mtspr(SPR_INTERRUPT_MASK_SET_1_1, __mask); \
54} while (0)
55#define interrupt_mask_reset(n) do { \
56 int __n = (n); \
57 int __mask = 1 << (__n & 0x1f); \
58 if (__n < 32) \
59 __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_0, __mask); \
60 else \
61 __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_1, __mask); \
62} while (0)
63#define interrupt_mask_check(n) ({ \
64 int __n = (n); \
65 (((__n < 32) ? \
66 __insn_mfspr(SPR_INTERRUPT_MASK_1_0) : \
67 __insn_mfspr(SPR_INTERRUPT_MASK_1_1)) \
68 >> (__n & 0x1f)) & 1; \
69})
70#define interrupt_mask_set_mask(mask) do { \
71 unsigned long long __m = (mask); \
72 __insn_mtspr(SPR_INTERRUPT_MASK_SET_1_0, (unsigned long)(__m)); \
73 __insn_mtspr(SPR_INTERRUPT_MASK_SET_1_1, (unsigned long)(__m>>32)); \
74} while (0)
75#define interrupt_mask_reset_mask(mask) do { \
76 unsigned long long __m = (mask); \
77 __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_0, (unsigned long)(__m)); \
78 __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_1, (unsigned long)(__m>>32)); \
79} while (0)
80#else
81#define interrupt_mask_set(n) \
82 __insn_mtspr(SPR_INTERRUPT_MASK_SET_1, (1UL << (n)))
83#define interrupt_mask_reset(n) \
84 __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1, (1UL << (n)))
85#define interrupt_mask_check(n) \
86 ((__insn_mfspr(SPR_INTERRUPT_MASK_1) >> (n)) & 1)
87#define interrupt_mask_set_mask(mask) \
88 __insn_mtspr(SPR_INTERRUPT_MASK_SET_1, (mask))
89#define interrupt_mask_reset_mask(mask) \
90 __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1, (mask))
91#endif
92
93/*
94 * The set of interrupts we want active if irqs are enabled.
95 * Note that in particular, the tile timer interrupt comes and goes
96 * from this set, since we have no other way to turn off the timer.
97 * Likewise, INTCTRL_1 is removed and re-added during device
98 * interrupts, as is the the hardwall UDN_FIREWALL interrupt.
99 * We use a low bit (MEM_ERROR) as our sentinel value and make sure it
100 * is always claimed as an "active interrupt" so we can query that bit
101 * to know our current state.
102 */
103DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
104#define INITIAL_INTERRUPTS_ENABLED INT_MASK(INT_MEM_ERROR)
105
106/* Disable interrupts. */
107#define raw_local_irq_disable() \
108 interrupt_mask_set_mask(LINUX_MASKABLE_INTERRUPTS)
109
110/* Disable all interrupts, including NMIs. */
111#define raw_local_irq_disable_all() \
112 interrupt_mask_set_mask(-1UL)
113
114/* Re-enable all maskable interrupts. */
115#define raw_local_irq_enable() \
116 interrupt_mask_reset_mask(__get_cpu_var(interrupts_enabled_mask))
117
118/* Disable or enable interrupts based on flag argument. */
119#define raw_local_irq_restore(disabled) do { \
120 if (disabled) \
121 raw_local_irq_disable(); \
122 else \
123 raw_local_irq_enable(); \
124} while (0)
125
126/* Return true if "flags" argument means interrupts are disabled. */
127#define raw_irqs_disabled_flags(flags) ((flags) != 0)
128
129/* Return true if interrupts are currently disabled. */
130#define raw_irqs_disabled() interrupt_mask_check(INT_MEM_ERROR)
131
132/* Save whether interrupts are currently disabled. */
133#define raw_local_save_flags(flags) ((flags) = raw_irqs_disabled())
134
135/* Save whether interrupts are currently disabled, then disable them. */
136#define raw_local_irq_save(flags) \
137 do { raw_local_save_flags(flags); raw_local_irq_disable(); } while (0)
138
139/* Prevent the given interrupt from being enabled next time we enable irqs. */
140#define raw_local_irq_mask(interrupt) \
141 (__get_cpu_var(interrupts_enabled_mask) &= ~INT_MASK(interrupt))
142
143/* Prevent the given interrupt from being enabled immediately. */
144#define raw_local_irq_mask_now(interrupt) do { \
145 raw_local_irq_mask(interrupt); \
146 interrupt_mask_set(interrupt); \
147} while (0)
148
149/* Allow the given interrupt to be enabled next time we enable irqs. */
150#define raw_local_irq_unmask(interrupt) \
151 (__get_cpu_var(interrupts_enabled_mask) |= INT_MASK(interrupt))
152
153/* Allow the given interrupt to be enabled immediately, if !irqs_disabled. */
154#define raw_local_irq_unmask_now(interrupt) do { \
155 raw_local_irq_unmask(interrupt); \
156 if (!irqs_disabled()) \
157 interrupt_mask_reset(interrupt); \
158} while (0)
159
160#else /* __ASSEMBLY__ */
161
162/* We provide a somewhat more restricted set for assembly. */
163
164#ifdef __tilegx__
165
166#if INT_MEM_ERROR != 0
167# error Fix IRQ_DISABLED() macro
168#endif
169
170/* Return 0 or 1 to indicate whether interrupts are currently disabled. */
171#define IRQS_DISABLED(tmp) \
172 mfspr tmp, INTERRUPT_MASK_1; \
173 andi tmp, tmp, 1
174
175/* Load up a pointer to &interrupts_enabled_mask. */
176#define GET_INTERRUPTS_ENABLED_MASK_PTR(reg) \
177 moveli reg, hw2_last(interrupts_enabled_mask); \
178 shl16insli reg, reg, hw1(interrupts_enabled_mask); \
179 shl16insli reg, reg, hw0(interrupts_enabled_mask); \
180 add reg, reg, tp
181
182/* Disable interrupts. */
183#define IRQ_DISABLE(tmp0, tmp1) \
184 moveli tmp0, hw2_last(LINUX_MASKABLE_INTERRUPTS); \
185 shl16insli tmp0, tmp0, hw1(LINUX_MASKABLE_INTERRUPTS); \
186 shl16insli tmp0, tmp0, hw0(LINUX_MASKABLE_INTERRUPTS); \
187 mtspr INTERRUPT_MASK_SET_1, tmp0
188
189/* Disable ALL synchronous interrupts (used by NMI entry). */
190#define IRQ_DISABLE_ALL(tmp) \
191 movei tmp, -1; \
192 mtspr INTERRUPT_MASK_SET_1, tmp
193
194/* Enable interrupts. */
195#define IRQ_ENABLE(tmp0, tmp1) \
196 GET_INTERRUPTS_ENABLED_MASK_PTR(tmp0); \
197 ld tmp0, tmp0; \
198 mtspr INTERRUPT_MASK_RESET_1, tmp0
199
200#else /* !__tilegx__ */
201
202/*
203 * Return 0 or 1 to indicate whether interrupts are currently disabled.
204 * Note that it's important that we use a bit from the "low" mask word,
205 * since when we are enabling, that is the word we write first, so if we
206 * are interrupted after only writing half of the mask, the interrupt
207 * handler will correctly observe that we have interrupts enabled, and
208 * will enable interrupts itself on return from the interrupt handler
209 * (making the original code's write of the "high" mask word idempotent).
210 */
211#define IRQS_DISABLED(tmp) \
212 mfspr tmp, INTERRUPT_MASK_1_0; \
213 shri tmp, tmp, INT_MEM_ERROR; \
214 andi tmp, tmp, 1
215
216/* Load up a pointer to &interrupts_enabled_mask. */
217#define GET_INTERRUPTS_ENABLED_MASK_PTR(reg) \
218 moveli reg, lo16(interrupts_enabled_mask); \
219 auli reg, reg, ha16(interrupts_enabled_mask);\
220 add reg, reg, tp
221
222/* Disable interrupts. */
223#define IRQ_DISABLE(tmp0, tmp1) \
224 { \
225 movei tmp0, -1; \
226 moveli tmp1, lo16(LINUX_MASKABLE_INTERRUPTS) \
227 }; \
228 { \
229 mtspr INTERRUPT_MASK_SET_1_0, tmp0; \
230 auli tmp1, tmp1, ha16(LINUX_MASKABLE_INTERRUPTS) \
231 }; \
232 mtspr INTERRUPT_MASK_SET_1_1, tmp1
233
234/* Disable ALL synchronous interrupts (used by NMI entry). */
235#define IRQ_DISABLE_ALL(tmp) \
236 movei tmp, -1; \
237 mtspr INTERRUPT_MASK_SET_1_0, tmp; \
238 mtspr INTERRUPT_MASK_SET_1_1, tmp
239
240/* Enable interrupts. */
241#define IRQ_ENABLE(tmp0, tmp1) \
242 GET_INTERRUPTS_ENABLED_MASK_PTR(tmp0); \
243 { \
244 lw tmp0, tmp0; \
245 addi tmp1, tmp0, 4 \
246 }; \
247 lw tmp1, tmp1; \
248 mtspr INTERRUPT_MASK_RESET_1_0, tmp0; \
249 mtspr INTERRUPT_MASK_RESET_1_1, tmp1
250#endif
251
252/*
253 * Do the CPU's IRQ-state tracing from assembly code. We call a
254 * C function, but almost everywhere we do, we don't mind clobbering
255 * all the caller-saved registers.
256 */
257#ifdef CONFIG_TRACE_IRQFLAGS
258# define TRACE_IRQS_ON jal trace_hardirqs_on
259# define TRACE_IRQS_OFF jal trace_hardirqs_off
260#else
261# define TRACE_IRQS_ON
262# define TRACE_IRQS_OFF
263#endif
264
265#endif /* __ASSEMBLY__ */
266
267#endif /* _ASM_TILE_IRQFLAGS_H */