1/*
2 * interface to Blackfin CEC
3 *
4 * Copyright 2009 Analog Devices Inc.
5 * Licensed under the GPL-2 or later.
6 */
7
8#ifndef __ASM_BFIN_IRQFLAGS_H__
9#define __ASM_BFIN_IRQFLAGS_H__
10
11#include <mach/blackfin.h>
12
13#ifdef CONFIG_SMP
14# include <asm/pda.h>
15# include <asm/processor.h>
16# define bfin_irq_flags cpu_pda[blackfin_core_id()].imask
17#else
18extern unsigned long bfin_irq_flags;
19#endif
20
21static inline notrace void bfin_sti(unsigned long flags)
22{
23	asm volatile("sti %0;" : : "d" (flags));
24}
25
26static inline notrace unsigned long bfin_cli(void)
27{
28	unsigned long flags;
29	asm volatile("cli %0;" : "=d" (flags));
30	return flags;
31}
32
33#ifdef CONFIG_DEBUG_HWERR
34# define bfin_no_irqs 0x3f
35#else
36# define bfin_no_irqs 0x1f
37#endif
38
39/*****************************************************************************/
40/*
41 * Hard, untraced CPU interrupt flag manipulation and access.
42 */
43static inline notrace void __hard_local_irq_disable(void)
44{
45	bfin_cli();
46}
47
48static inline notrace void __hard_local_irq_enable(void)
49{
50	bfin_sti(bfin_irq_flags);
51}
52
53static inline notrace unsigned long hard_local_save_flags(void)
54{
55	return bfin_read_IMASK();
56}
57
58static inline notrace unsigned long __hard_local_irq_save(void)
59{
60	unsigned long flags;
61	flags = bfin_cli();
62#ifdef CONFIG_DEBUG_HWERR
63	bfin_sti(0x3f);
64#endif
65	return flags;
66}
67
68static inline notrace int hard_irqs_disabled_flags(unsigned long flags)
69{
70#ifdef CONFIG_BF60x
71	return (flags & IMASK_IVG11) == 0;
72#else
73	return (flags & ~0x3f) == 0;
74#endif
75}
76
77static inline notrace int hard_irqs_disabled(void)
78{
79	unsigned long flags = hard_local_save_flags();
80	return hard_irqs_disabled_flags(flags);
81}
82
83static inline notrace void __hard_local_irq_restore(unsigned long flags)
84{
85	if (!hard_irqs_disabled_flags(flags))
86		__hard_local_irq_enable();
87}
88
89/*****************************************************************************/
90/*
91 * Interrupt pipe handling.
92 */
93#ifdef CONFIG_IPIPE
94
95#include <linux/compiler.h>
96#include <linux/ipipe_trace.h>
97/*
98 * Way too many inter-deps between low-level headers in this port, so
99 * we redeclare the required bits we cannot pick from
100 * <asm/ipipe_base.h> to prevent circular dependencies.
101 */
102void __ipipe_stall_root(void);
103void __ipipe_unstall_root(void);
104unsigned long __ipipe_test_root(void);
105unsigned long __ipipe_test_and_stall_root(void);
106void __ipipe_restore_root(unsigned long flags);
107
108#ifdef CONFIG_IPIPE_DEBUG_CONTEXT
109struct ipipe_domain;
110extern struct ipipe_domain ipipe_root;
111void ipipe_check_context(struct ipipe_domain *ipd);
112#define __check_irqop_context(ipd)  ipipe_check_context(&ipipe_root)
113#else /* !CONFIG_IPIPE_DEBUG_CONTEXT */
114#define __check_irqop_context(ipd)  do { } while (0)
115#endif /* !CONFIG_IPIPE_DEBUG_CONTEXT */
116
117/*
118 * Interrupt pipe interface to linux/irqflags.h.
119 */
120static inline notrace void arch_local_irq_disable(void)
121{
122	__check_irqop_context();
123	__ipipe_stall_root();
124	barrier();
125}
126
127static inline notrace void arch_local_irq_enable(void)
128{
129	barrier();
130	__check_irqop_context();
131	__ipipe_unstall_root();
132}
133
134static inline notrace unsigned long arch_local_save_flags(void)
135{
136	return __ipipe_test_root() ? bfin_no_irqs : bfin_irq_flags;
137}
138
139static inline notrace int arch_irqs_disabled_flags(unsigned long flags)
140{
141	return flags == bfin_no_irqs;
142}
143
144static inline notrace unsigned long arch_local_irq_save(void)
145{
146	unsigned long flags;
147
148	__check_irqop_context();
149	flags = __ipipe_test_and_stall_root() ? bfin_no_irqs : bfin_irq_flags;
150	barrier();
151
152	return flags;
153}
154
155static inline notrace void arch_local_irq_restore(unsigned long flags)
156{
157	__check_irqop_context();
158	__ipipe_restore_root(flags == bfin_no_irqs);
159}
160
161static inline notrace unsigned long arch_mangle_irq_bits(int virt, unsigned long real)
162{
163	/*
164	 * Merge virtual and real interrupt mask bits into a single
165	 * 32bit word.
166	 */
167	return (real & ~(1 << 31)) | ((virt != 0) << 31);
168}
169
170static inline notrace int arch_demangle_irq_bits(unsigned long *x)
171{
172	int virt = (*x & (1 << 31)) != 0;
173	*x &= ~(1L << 31);
174	return virt;
175}
176
177/*
178 * Interface to various arch routines that may be traced.
179 */
180#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
181static inline notrace void hard_local_irq_disable(void)
182{
183	if (!hard_irqs_disabled()) {
184		__hard_local_irq_disable();
185		ipipe_trace_begin(0x80000000);
186	}
187}
188
189static inline notrace void hard_local_irq_enable(void)
190{
191	if (hard_irqs_disabled()) {
192		ipipe_trace_end(0x80000000);
193		__hard_local_irq_enable();
194	}
195}
196
197static inline notrace unsigned long hard_local_irq_save(void)
198{
199	unsigned long flags = hard_local_save_flags();
200	if (!hard_irqs_disabled_flags(flags)) {
201		__hard_local_irq_disable();
202		ipipe_trace_begin(0x80000001);
203	}
204	return flags;
205}
206
207static inline notrace void hard_local_irq_restore(unsigned long flags)
208{
209	if (!hard_irqs_disabled_flags(flags)) {
210		ipipe_trace_end(0x80000001);
211		__hard_local_irq_enable();
212	}
213}
214
215#else /* !CONFIG_IPIPE_TRACE_IRQSOFF */
216# define hard_local_irq_disable()	__hard_local_irq_disable()
217# define hard_local_irq_enable()	__hard_local_irq_enable()
218# define hard_local_irq_save()		__hard_local_irq_save()
219# define hard_local_irq_restore(flags)	__hard_local_irq_restore(flags)
220#endif /* !CONFIG_IPIPE_TRACE_IRQSOFF */
221
222#define hard_local_irq_save_cond()		hard_local_irq_save()
223#define hard_local_irq_restore_cond(flags)	hard_local_irq_restore(flags)
224
225#else /* !CONFIG_IPIPE */
226
227/*
228 * Direct interface to linux/irqflags.h.
229 */
230#define arch_local_save_flags()		hard_local_save_flags()
231#define arch_local_irq_save()		__hard_local_irq_save()
232#define arch_local_irq_restore(flags)	__hard_local_irq_restore(flags)
233#define arch_local_irq_enable()		__hard_local_irq_enable()
234#define arch_local_irq_disable()	__hard_local_irq_disable()
235#define arch_irqs_disabled_flags(flags)	hard_irqs_disabled_flags(flags)
236#define arch_irqs_disabled()		hard_irqs_disabled()
237
238/*
239 * Interface to various arch routines that may be traced.
240 */
241#define hard_local_irq_save()		__hard_local_irq_save()
242#define hard_local_irq_restore(flags)	__hard_local_irq_restore(flags)
243#define hard_local_irq_enable()		__hard_local_irq_enable()
244#define hard_local_irq_disable()	__hard_local_irq_disable()
245#define hard_local_irq_save_cond()		hard_local_save_flags()
246#define hard_local_irq_restore_cond(flags)	do { (void)(flags); } while (0)
247
248#endif /* !CONFIG_IPIPE */
249
250#ifdef CONFIG_SMP
251#define hard_local_irq_save_smp()		hard_local_irq_save()
252#define hard_local_irq_restore_smp(flags)	hard_local_irq_restore(flags)
253#else
254#define hard_local_irq_save_smp()		hard_local_save_flags()
255#define hard_local_irq_restore_smp(flags)	do { (void)(flags); } while (0)
256#endif
257
258/*
259 * Remap the arch-neutral IRQ state manipulation macros to the
260 * blackfin-specific hard_local_irq_* API.
261 */
262#define local_irq_save_hw(flags)			\
263	do {						\
264		(flags) = hard_local_irq_save();	\
265	} while (0)
266#define local_irq_restore_hw(flags)		\
267	do {					\
268		hard_local_irq_restore(flags);	\
269	} while (0)
270#define local_irq_disable_hw()			\
271	do {					\
272		hard_local_irq_disable();	\
273	} while (0)
274#define local_irq_enable_hw()			\
275	do {					\
276		hard_local_irq_enable();	\
277	} while (0)
278#define local_irq_save_hw_notrace(flags)		\
279	do {						\
280		(flags) = __hard_local_irq_save();	\
281	} while (0)
282#define local_irq_restore_hw_notrace(flags)		\
283	do {						\
284		__hard_local_irq_restore(flags);	\
285	} while (0)
286
287#define irqs_disabled_hw()	hard_irqs_disabled()
288
289#endif
290