Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[linux-2.6.git] / arch / frv / include / asm / irqflags.h
1 /* FR-V interrupt 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 /*
16  * interrupt flag manipulation
17  * - use virtual interrupt management since touching the PSR is slow
18  *   - ICC2.Z: T if interrupts virtually disabled
19  *   - ICC2.C: F if interrupts really disabled
20  * - if Z==1 upon interrupt:
21  *   - C is set to 0
22  *   - interrupts are really disabled
23  *   - entry.S returns immediately
24  * - uses TIHI (TRAP if Z==0 && C==0) #2 to really reenable interrupts
25  *   - if taken, the trap:
26  *     - sets ICC2.C
27  *     - enables interrupts
28  */
29 static inline void arch_local_irq_disable(void)
30 {
31         /* set Z flag, but don't change the C flag */
32         asm volatile("  andcc   gr0,gr0,gr0,icc2        \n"
33                      :
34                      :
35                      : "memory", "icc2"
36                      );
37 }
38
39 static inline void arch_local_irq_enable(void)
40 {
41         /* clear Z flag and then test the C flag */
42         asm volatile("  oricc   gr0,#1,gr0,icc2         \n"
43                      "  tihi    icc2,gr0,#2             \n"
44                      :
45                      :
46                      : "memory", "icc2"
47                      );
48 }
49
50 static inline unsigned long arch_local_save_flags(void)
51 {
52         unsigned long flags;
53
54         asm volatile("movsg ccr,%0"
55                      : "=r"(flags)
56                      :
57                      : "memory");
58
59         /* shift ICC2.Z to bit 0 */
60         flags >>= 26;
61
62         /* make flags 1 if interrupts disabled, 0 otherwise */
63         return flags & 1UL;
64
65 }
66
67 static inline unsigned long arch_local_irq_save(void)
68 {
69         unsigned long flags = arch_local_save_flags();
70         arch_local_irq_disable();
71         return flags;
72 }
73
74 static inline void arch_local_irq_restore(unsigned long flags)
75 {
76         /* load the Z flag by turning 1 if disabled into 0 if disabled
77          * and thus setting the Z flag but not the C flag */
78         asm volatile("  xoricc  %0,#1,gr0,icc2          \n"
79                      /* then trap if Z=0 and C=0 */
80                      "  tihi    icc2,gr0,#2             \n"
81                      :
82                      : "r"(flags)
83                      : "memory", "icc2"
84                      );
85
86 }
87
88 static inline bool arch_irqs_disabled_flags(unsigned long flags)
89 {
90         return flags;
91 }
92
93 static inline bool arch_irqs_disabled(void)
94 {
95         return arch_irqs_disabled_flags(arch_local_save_flags());
96 }
97
98 /*
99  * real interrupt flag manipulation
100  */
101 #define __arch_local_irq_disable()                      \
102 do {                                                    \
103         unsigned long psr;                              \
104         asm volatile("  movsg   psr,%0          \n"     \
105                      "  andi    %0,%2,%0        \n"     \
106                      "  ori     %0,%1,%0        \n"     \
107                      "  movgs   %0,psr          \n"     \
108                      : "=r"(psr)                        \
109                      : "i" (PSR_PIL_14), "i" (~PSR_PIL) \
110                      : "memory");                       \
111 } while (0)
112
113 #define __arch_local_irq_enable()                       \
114 do {                                                    \
115         unsigned long psr;                              \
116         asm volatile("  movsg   psr,%0          \n"     \
117                      "  andi    %0,%1,%0        \n"     \
118                      "  movgs   %0,psr          \n"     \
119                      : "=r"(psr)                        \
120                      : "i" (~PSR_PIL)                   \
121                      : "memory");                       \
122 } while (0)
123
124 #define __arch_local_save_flags(flags)          \
125 do {                                            \
126         typecheck(unsigned long, flags);        \
127         asm("movsg psr,%0"                      \
128             : "=r"(flags)                       \
129             :                                   \
130             : "memory");                        \
131 } while (0)
132
133 #define __arch_local_irq_save(flags)                    \
134 do {                                                    \
135         unsigned long npsr;                             \
136         typecheck(unsigned long, flags);                \
137         asm volatile("  movsg   psr,%0          \n"     \
138                      "  andi    %0,%3,%1        \n"     \
139                      "  ori     %1,%2,%1        \n"     \
140                      "  movgs   %1,psr          \n"     \
141                      : "=r"(flags), "=r"(npsr)          \
142                      : "i" (PSR_PIL_14), "i" (~PSR_PIL) \
143                      : "memory");                       \
144 } while (0)
145
146 #define __arch_local_irq_restore(flags)                 \
147 do {                                                    \
148         typecheck(unsigned long, flags);                \
149         asm volatile("  movgs   %0,psr          \n"     \
150                      :                                  \
151                      : "r" (flags)                      \
152                      : "memory");                       \
153 } while (0)
154
155 #define __arch_irqs_disabled()                  \
156         ((__get_PSR() & PSR_PIL) >= PSR_PIL_14)
157
158 #endif /* _ASM_IRQFLAGS_H */