1 /*
2  *  linux/include/asm-arm/proc-armv/system.h
3  *
4  *  Copyright (C) 1996 Russell King
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10 #ifndef __ASM_PROC_SYSTEM_H
11 #define __ASM_PROC_SYSTEM_H
12 
13 /*
14  * Save the current interrupt enable state & disable IRQs
15  */
16 #ifdef CONFIG_ARM64
17 
18 /*
19  * Save the current interrupt enable state
20  * and disable IRQs/FIQs
21  */
22 #define local_irq_save(flags)					\
23 	({							\
24 	asm volatile(						\
25 	"mrs	%0, daif\n"					\
26 	"msr	daifset, #3"					\
27 	: "=r" (flags)						\
28 	:							\
29 	: "memory");						\
30 	})
31 
32 /*
33  * restore saved IRQ & FIQ state
34  */
35 #define local_irq_restore(flags)				\
36 	({							\
37 	asm volatile(						\
38 	"msr	daif, %0"					\
39 	:							\
40 	: "r" (flags)						\
41 	: "memory");						\
42 	})
43 
44 /*
45  * Enable IRQs/FIQs
46  */
47 #define local_irq_enable()					\
48 	({							\
49 	asm volatile(						\
50 	"msr	daifclr, #3"					\
51 	:							\
52 	:							\
53 	: "memory");						\
54 	})
55 
56 /*
57  * Disable IRQs/FIQs
58  */
59 #define local_irq_disable()					\
60 	({							\
61 	asm volatile(						\
62 	"msr	daifset, #3"					\
63 	:							\
64 	:							\
65 	: "memory");						\
66 	})
67 
68 #else	/* CONFIG_ARM64 */
69 
70 #define local_irq_save(x)					\
71 	({							\
72 		unsigned long temp;				\
73 	__asm__ __volatile__(					\
74 	"mrs	%0, cpsr		@ local_irq_save\n"	\
75 "	orr	%1, %0, #128\n"					\
76 "	msr	cpsr_c, %1"					\
77 	: "=r" (x), "=r" (temp)					\
78 	:							\
79 	: "memory");						\
80 	})
81 
82 /*
83  * Enable IRQs
84  */
85 #define local_irq_enable()					\
86 	({							\
87 		unsigned long temp;				\
88 	__asm__ __volatile__(					\
89 	"mrs	%0, cpsr		@ local_irq_enable\n"	\
90 "	bic	%0, %0, #128\n"					\
91 "	msr	cpsr_c, %0"					\
92 	: "=r" (temp)						\
93 	:							\
94 	: "memory");						\
95 	})
96 
97 /*
98  * Disable IRQs
99  */
100 #define local_irq_disable()					\
101 	({							\
102 		unsigned long temp;				\
103 	__asm__ __volatile__(					\
104 	"mrs	%0, cpsr		@ local_irq_disable\n"	\
105 "	orr	%0, %0, #128\n"					\
106 "	msr	cpsr_c, %0"					\
107 	: "=r" (temp)						\
108 	:							\
109 	: "memory");						\
110 	})
111 
112 /*
113  * Enable FIQs
114  */
115 #define __stf()							\
116 	({							\
117 		unsigned long temp;				\
118 	__asm__ __volatile__(					\
119 	"mrs	%0, cpsr		@ stf\n"		\
120 "	bic	%0, %0, #64\n"					\
121 "	msr	cpsr_c, %0"					\
122 	: "=r" (temp)						\
123 	:							\
124 	: "memory");						\
125 	})
126 
127 /*
128  * Disable FIQs
129  */
130 #define __clf()							\
131 	({							\
132 		unsigned long temp;				\
133 	__asm__ __volatile__(					\
134 	"mrs	%0, cpsr		@ clf\n"		\
135 "	orr	%0, %0, #64\n"					\
136 "	msr	cpsr_c, %0"					\
137 	: "=r" (temp)						\
138 	:							\
139 	: "memory");						\
140 	})
141 
142 /*
143  * Save the current interrupt enable state.
144  */
145 #define local_save_flags(x)					\
146 	({							\
147 	__asm__ __volatile__(					\
148 	"mrs	%0, cpsr		@ local_save_flags\n"	\
149 	  : "=r" (x)						\
150 	  :							\
151 	  : "memory");						\
152 	})
153 
154 /*
155  * restore saved IRQ & FIQ state
156  */
157 #define local_irq_restore(x)					\
158 	__asm__ __volatile__(					\
159 	"msr	cpsr_c, %0		@ local_irq_restore\n"	\
160 	:							\
161 	: "r" (x)						\
162 	: "memory")
163 
164 #endif	/* CONFIG_ARM64 */
165 
166 #if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110) || \
167 	defined(CONFIG_ARM64)
168 /*
169  * On the StrongARM, "swp" is terminally broken since it bypasses the
170  * cache totally.  This means that the cache becomes inconsistent, and,
171  * since we use normal loads/stores as well, this is really bad.
172  * Typically, this causes oopsen in filp_close, but could have other,
173  * more disasterous effects.  There are two work-arounds:
174  *  1. Disable interrupts and emulate the atomic swap
175  *  2. Clean the cache, perform atomic swap, flush the cache
176  *
177  * We choose (1) since its the "easiest" to achieve here and is not
178  * dependent on the processor type.
179  */
180 #define swp_is_buggy
181 #endif
182 
183 static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
184 {
185 	extern void __bad_xchg(volatile void *, int);
186 	unsigned long ret;
187 #ifdef swp_is_buggy
188 	unsigned long flags;
189 #endif
190 
191 	switch (size) {
192 #ifdef swp_is_buggy
193 		case 1:
194 			local_irq_save(flags);
195 			ret = *(volatile unsigned char *)ptr;
196 			*(volatile unsigned char *)ptr = x;
197 			local_irq_restore(flags);
198 			break;
199 
200 		case 4:
201 			local_irq_save(flags);
202 			ret = *(volatile unsigned long *)ptr;
203 			*(volatile unsigned long *)ptr = x;
204 			local_irq_restore(flags);
205 			break;
206 #else
207 		case 1:	__asm__ __volatile__ ("swpb %0, %1, [%2]"
208 					: "=&r" (ret)
209 					: "r" (x), "r" (ptr)
210 					: "memory");
211 			break;
212 		case 4:	__asm__ __volatile__ ("swp %0, %1, [%2]"
213 					: "=&r" (ret)
214 					: "r" (x), "r" (ptr)
215 					: "memory");
216 			break;
217 #endif
218 		default: __bad_xchg(ptr, size), ret = 0;
219 	}
220 
221 	return ret;
222 }
223 
224 #endif
225