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 #include <linux/config.h>
14 
15 /*
16  * Save the current interrupt enable state & disable IRQs
17  */
18 #define local_irq_save(x)					\
19 	({							\
20 		unsigned long temp;				\
21 	__asm__ __volatile__(					\
22 	"mrs	%0, cpsr		@ local_irq_save\n"	\
23 "	orr	%1, %0, #128\n"					\
24 "	msr	cpsr_c, %1"					\
25 	: "=r" (x), "=r" (temp)					\
26 	:							\
27 	: "memory");						\
28 	})
29 
30 /*
31  * Enable IRQs
32  */
33 #define local_irq_enable()					\
34 	({							\
35 		unsigned long temp;				\
36 	__asm__ __volatile__(					\
37 	"mrs	%0, cpsr		@ local_irq_enable\n"	\
38 "	bic	%0, %0, #128\n"					\
39 "	msr	cpsr_c, %0"					\
40 	: "=r" (temp)						\
41 	:							\
42 	: "memory");						\
43 	})
44 
45 /*
46  * Disable IRQs
47  */
48 #define local_irq_disable()					\
49 	({							\
50 		unsigned long temp;				\
51 	__asm__ __volatile__(					\
52 	"mrs	%0, cpsr		@ local_irq_disable\n"	\
53 "	orr	%0, %0, #128\n"					\
54 "	msr	cpsr_c, %0"					\
55 	: "=r" (temp)						\
56 	:							\
57 	: "memory");						\
58 	})
59 
60 /*
61  * Enable FIQs
62  */
63 #define __stf()							\
64 	({							\
65 		unsigned long temp;				\
66 	__asm__ __volatile__(					\
67 	"mrs	%0, cpsr		@ stf\n"		\
68 "	bic	%0, %0, #64\n"					\
69 "	msr	cpsr_c, %0"					\
70 	: "=r" (temp)						\
71 	:							\
72 	: "memory");						\
73 	})
74 
75 /*
76  * Disable FIQs
77  */
78 #define __clf()							\
79 	({							\
80 		unsigned long temp;				\
81 	__asm__ __volatile__(					\
82 	"mrs	%0, cpsr		@ clf\n"		\
83 "	orr	%0, %0, #64\n"					\
84 "	msr	cpsr_c, %0"					\
85 	: "=r" (temp)						\
86 	:							\
87 	: "memory");						\
88 	})
89 
90 /*
91  * Save the current interrupt enable state.
92  */
93 #define local_save_flags(x)					\
94 	({							\
95 	__asm__ __volatile__(					\
96 	"mrs	%0, cpsr		@ local_save_flags\n"	\
97 	  : "=r" (x)						\
98 	  :							\
99 	  : "memory");						\
100 	})
101 
102 /*
103  * restore saved IRQ & FIQ state
104  */
105 #define local_irq_restore(x)					\
106 	__asm__ __volatile__(					\
107 	"msr	cpsr_c, %0		@ local_irq_restore\n"	\
108 	:							\
109 	: "r" (x)						\
110 	: "memory")
111 
112 #if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110)
113 /*
114  * On the StrongARM, "swp" is terminally broken since it bypasses the
115  * cache totally.  This means that the cache becomes inconsistent, and,
116  * since we use normal loads/stores as well, this is really bad.
117  * Typically, this causes oopsen in filp_close, but could have other,
118  * more disasterous effects.  There are two work-arounds:
119  *  1. Disable interrupts and emulate the atomic swap
120  *  2. Clean the cache, perform atomic swap, flush the cache
121  *
122  * We choose (1) since its the "easiest" to achieve here and is not
123  * dependent on the processor type.
124  */
125 #define swp_is_buggy
126 #endif
127 
128 static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
129 {
130 	extern void __bad_xchg(volatile void *, int);
131 	unsigned long ret;
132 #ifdef swp_is_buggy
133 	unsigned long flags;
134 #endif
135 
136 	switch (size) {
137 #ifdef swp_is_buggy
138 		case 1:
139 			local_irq_save(flags);
140 			ret = *(volatile unsigned char *)ptr;
141 			*(volatile unsigned char *)ptr = x;
142 			local_irq_restore(flags);
143 			break;
144 
145 		case 4:
146 			local_irq_save(flags);
147 			ret = *(volatile unsigned long *)ptr;
148 			*(volatile unsigned long *)ptr = x;
149 			local_irq_restore(flags);
150 			break;
151 #else
152 		case 1:	__asm__ __volatile__ ("swpb %0, %1, [%2]"
153 					: "=&r" (ret)
154 					: "r" (x), "r" (ptr)
155 					: "memory");
156 			break;
157 		case 4:	__asm__ __volatile__ ("swp %0, %1, [%2]"
158 					: "=&r" (ret)
159 					: "r" (x), "r" (ptr)
160 					: "memory");
161 			break;
162 #endif
163 		default: __bad_xchg(ptr, size), ret = 0;
164 	}
165 
166 	return ret;
167 }
168 
169 #endif
170