Rev 1408 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1408 | Rev 1631 | ||
---|---|---|---|
Line 24... | Line 24... | ||
24 | #define __xchg(x, ptr, size) \ |
24 | #define __xchg(x, ptr, size) \ |
25 | ({ \ |
25 | ({ \ |
26 | __typeof(*(ptr)) __x = (x); \ |
26 | __typeof(*(ptr)) __x = (x); \ |
27 | switch (size) { \ |
27 | switch (size) { \ |
28 | case 1: \ |
28 | case 1: \ |
- | 29 | { \ |
|
- | 30 | volatile u8 *__ptr = (volatile u8 *)(ptr); \ |
|
29 | asm volatile("xchgb %b0,%1" \ |
31 | asm volatile("xchgb %0,%1" \ |
30 | : "=q" (__x) \ |
32 | : "=q" (__x), "+m" (*__ptr) \ |
31 | : "m" (*__xg(ptr)), "0" (__x) \ |
33 | : "0" (__x) \ |
32 | : "memory"); \ |
34 | : "memory"); \ |
33 | break; \ |
35 | break; \ |
- | 36 | } \ |
|
34 | case 2: \ |
37 | case 2: \ |
- | 38 | { \ |
|
- | 39 | volatile u16 *__ptr = (volatile u16 *)(ptr); \ |
|
35 | asm volatile("xchgw %w0,%1" \ |
40 | asm volatile("xchgw %0,%1" \ |
36 | : "=r" (__x) \ |
41 | : "=r" (__x), "+m" (*__ptr) \ |
37 | : "m" (*__xg(ptr)), "0" (__x) \ |
42 | : "0" (__x) \ |
38 | : "memory"); \ |
43 | : "memory"); \ |
39 | break; \ |
44 | break; \ |
- | 45 | } \ |
|
40 | case 4: \ |
46 | case 4: \ |
- | 47 | { \ |
|
- | 48 | volatile u32 *__ptr = (volatile u32 *)(ptr); \ |
|
41 | asm volatile("xchgl %0,%1" \ |
49 | asm volatile("xchgl %0,%1" \ |
42 | : "=r" (__x) \ |
50 | : "=r" (__x), "+m" (*__ptr) \ |
43 | : "m" (*__xg(ptr)), "0" (__x) \ |
51 | : "0" (__x) \ |
44 | : "memory"); \ |
52 | : "memory"); \ |
45 | break; \ |
53 | break; \ |
- | 54 | } \ |
|
46 | default: \ |
55 | default: \ |
47 | __xchg_wrong_size(); \ |
56 | __xchg_wrong_size(); \ |
48 | } \ |
57 | } \ |
49 | __x; \ |
58 | __x; \ |
50 | }) |
59 | }) |
Line 51... | Line 60... | ||
51 | 60 | ||
52 | #define xchg(ptr, v) \ |
61 | #define xchg(ptr, v) \ |
Line 53... | Line 62... | ||
53 | __xchg((v), (ptr), sizeof(*ptr)) |
62 | __xchg((v), (ptr), sizeof(*ptr)) |
54 | 63 | ||
55 | /* |
64 | /* |
56 | * The semantics of XCHGCMP8B are a bit strange, this is why |
65 | * CMPXCHG8B only writes to the target if we had the previous |
57 | * there is a loop and the loading of %%eax and %%edx has to |
66 | * value in registers, otherwise it acts as a read and gives us the |
58 | * be inside. This inlines well in most cases, the cached |
- | |
59 | * cost is around ~38 cycles. (in the future we might want |
- | |
60 | * to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that |
67 | * "new previous" value. That is why there is a loop. Preloading |
61 | * might have an implicit FPU-save as a cost, so it's not |
68 | * EDX:EAX is a performance optimization: in the common case it means |
- | 69 | * we need only one locked operation. |
|
- | 70 | * |
|
- | 71 | * A SIMD/3DNOW!/MMX/FPU 64-bit store here would require at the very |
|
62 | * clear which path to go.) |
72 | * least an FPU save and/or %cr0.ts manipulation. |
63 | * |
73 | * |
64 | * cmpxchg8b must be used with the lock prefix here to allow |
- | |
65 | * the instruction to be executed atomically, see page 3-102 |
74 | * cmpxchg8b must be used with the lock prefix here to allow the |
66 | * of the instruction set reference 24319102.pdf. We need |
75 | * instruction to be executed atomically. We need to have the reader |
67 | * the reader side to see the coherent 64bit value. |
76 | * side to see the coherent 64bit value. |
68 | */ |
- | |
69 | static inline void __set_64bit(unsigned long long *ptr, |
77 | */ |
- | 78 | static inline void set_64bit(volatile u64 *ptr, u64 value) |
|
- | 79 | { |
|
- | 80 | u32 low = value; |
|
- | 81 | u32 high = value >> 32; |
|
70 | unsigned int low, unsigned int high) |
82 | u64 prev = *ptr; |
71 | { |
- | |
72 | asm volatile("\n1:\t" |
- | |
73 | "movl (%0), %%eax\n\t" |
83 | |
74 | "movl 4(%0), %%edx\n\t" |
84 | asm volatile("\n1:\t" |
75 | LOCK_PREFIX "cmpxchg8b (%0)\n\t" |
- | |
76 | "jnz 1b" |
85 | LOCK_PREFIX "cmpxchg8b %0\n\t" |
77 | : /* no outputs */ |
- | |
78 | : "D"(ptr), |
86 | "jnz 1b" |
79 | "b"(low), |
87 | : "=m" (*ptr), "+A" (prev) |
80 | "c"(high) |
- | |
81 | : "ax", "dx", "memory"); |
- | |
82 | } |
- | |
83 | - | ||
84 | static inline void __set_64bit_constant(unsigned long long *ptr, |
- | |
85 | unsigned long long value) |
- | |
86 | { |
- | |
87 | __set_64bit(ptr, (unsigned int)value, (unsigned int)(value >> 32)); |
- | |
88 | } |
- | |
89 | - | ||
90 | #define ll_low(x) *(((unsigned int *)&(x)) + 0) |
- | |
91 | #define ll_high(x) *(((unsigned int *)&(x)) + 1) |
- | |
92 | - | ||
93 | static inline void __set_64bit_var(unsigned long long *ptr, |
- | |
94 | unsigned long long value) |
- | |
95 | { |
88 | : "b" (low), "c" (high) |
Line 96... | Line -... | ||
96 | __set_64bit(ptr, ll_low(value), ll_high(value)); |
- | |
97 | } |
- | |
98 | - | ||
99 | #define set_64bit(ptr, value) \ |
- | |
100 | (__builtin_constant_p((value)) \ |
- | |
101 | ? __set_64bit_constant((ptr), (value)) \ |
- | |
102 | : __set_64bit_var((ptr), (value))) |
- | |
103 | - | ||
104 | #define _set_64bit(ptr, value) \ |
- | |
105 | (__builtin_constant_p(value) \ |
- | |
106 | ? __set_64bit(ptr, (unsigned int)(value), \ |
- | |
107 | (unsigned int)((value) >> 32)) \ |
89 | : "memory"); |
Line 108... | Line 90... | ||
108 | : __set_64bit(ptr, ll_low((value)), ll_high((value)))) |
90 | } |
109 | 91 | ||
110 | extern void __cmpxchg_wrong_size(void); |
92 | extern void __cmpxchg_wrong_size(void); |
Line 119... | Line 101... | ||
119 | __typeof__(*(ptr)) __ret; \ |
101 | __typeof__(*(ptr)) __ret; \ |
120 | __typeof__(*(ptr)) __old = (old); \ |
102 | __typeof__(*(ptr)) __old = (old); \ |
121 | __typeof__(*(ptr)) __new = (new); \ |
103 | __typeof__(*(ptr)) __new = (new); \ |
122 | switch (size) { \ |
104 | switch (size) { \ |
123 | case 1: \ |
105 | case 1: \ |
- | 106 | { \ |
|
- | 107 | volatile u8 *__ptr = (volatile u8 *)(ptr); \ |
|
124 | asm volatile(lock "cmpxchgb %b1,%2" \ |
108 | asm volatile(lock "cmpxchgb %2,%1" \ |
125 | : "=a"(__ret) \ |
109 | : "=a" (__ret), "+m" (*__ptr) \ |
126 | : "q"(__new), "m"(*__xg(ptr)), "0"(__old) \ |
110 | : "q" (__new), "0" (__old) \ |
127 | : "memory"); \ |
111 | : "memory"); \ |
128 | break; \ |
112 | break; \ |
- | 113 | } \ |
|
129 | case 2: \ |
114 | case 2: \ |
- | 115 | { \ |
|
- | 116 | volatile u16 *__ptr = (volatile u16 *)(ptr); \ |
|
130 | asm volatile(lock "cmpxchgw %w1,%2" \ |
117 | asm volatile(lock "cmpxchgw %2,%1" \ |
131 | : "=a"(__ret) \ |
118 | : "=a" (__ret), "+m" (*__ptr) \ |
132 | : "r"(__new), "m"(*__xg(ptr)), "0"(__old) \ |
119 | : "r" (__new), "0" (__old) \ |
133 | : "memory"); \ |
120 | : "memory"); \ |
134 | break; \ |
121 | break; \ |
- | 122 | } \ |
|
135 | case 4: \ |
123 | case 4: \ |
- | 124 | { \ |
|
- | 125 | volatile u32 *__ptr = (volatile u32 *)(ptr); \ |
|
136 | asm volatile(lock "cmpxchgl %1,%2" \ |
126 | asm volatile(lock "cmpxchgl %2,%1" \ |
137 | : "=a"(__ret) \ |
127 | : "=a" (__ret), "+m" (*__ptr) \ |
138 | : "r"(__new), "m"(*__xg(ptr)), "0"(__old) \ |
128 | : "r" (__new), "0" (__old) \ |
139 | : "memory"); \ |
129 | : "memory"); \ |
140 | break; \ |
130 | break; \ |
- | 131 | } \ |
|
141 | default: \ |
132 | default: \ |
142 | __cmpxchg_wrong_size(); \ |
133 | __cmpxchg_wrong_size(); \ |
143 | } \ |
134 | } \ |
144 | __ret; \ |
135 | __ret; \ |
145 | }) |
136 | }) |
Line 173... | Line 164... | ||
173 | #define cmpxchg64_local(ptr, o, n) \ |
164 | #define cmpxchg64_local(ptr, o, n) \ |
174 | ((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o), \ |
165 | ((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o), \ |
175 | (unsigned long long)(n))) |
166 | (unsigned long long)(n))) |
176 | #endif |
167 | #endif |
Line 177... | Line 168... | ||
177 | 168 | ||
178 | static inline unsigned long long __cmpxchg64(volatile void *ptr, |
- | |
179 | unsigned long long old, |
- | |
180 | unsigned long long new) |
169 | static inline u64 __cmpxchg64(volatile u64 *ptr, u64 old, u64 new) |
181 | { |
170 | { |
182 | unsigned long long prev; |
171 | u64 prev; |
183 | asm volatile(LOCK_PREFIX "cmpxchg8b %3" |
172 | asm volatile(LOCK_PREFIX "cmpxchg8b %1" |
184 | : "=A"(prev) |
173 | : "=A" (prev), |
185 | : "b"((unsigned long)new), |
174 | "+m" (*ptr) |
186 | "c"((unsigned long)(new >> 32)), |
175 | : "b" ((u32)new), |
187 | "m"(*__xg(ptr)), |
176 | "c" ((u32)(new >> 32)), |
188 | "0"(old) |
177 | "0" (old) |
189 | : "memory"); |
178 | : "memory"); |
190 | return prev; |
179 | return prev; |
Line 191... | Line 180... | ||
191 | } |
180 | } |
192 | - | ||
193 | static inline unsigned long long __cmpxchg64_local(volatile void *ptr, |
- | |
194 | unsigned long long old, |
181 | |
195 | unsigned long long new) |
182 | static inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new) |
196 | { |
183 | { |
197 | unsigned long long prev; |
184 | u64 prev; |
198 | asm volatile("cmpxchg8b %3" |
185 | asm volatile("cmpxchg8b %1" |
199 | : "=A"(prev) |
186 | : "=A" (prev), |
200 | : "b"((unsigned long)new), |
187 | "+m" (*ptr) |
201 | "c"((unsigned long)(new >> 32)), |
188 | : "b" ((u32)new), |
202 | "m"(*__xg(ptr)), |
189 | "c" ((u32)(new >> 32)), |
203 | "0"(old) |
190 | "0" (old) |
204 | : "memory"); |
191 | : "memory"); |
Line 210... | Line 197... | ||
210 | * Building a kernel capable running on 80386. It may be necessary to |
197 | * Building a kernel capable running on 80386. It may be necessary to |
211 | * simulate the cmpxchg on the 80386 CPU. For that purpose we define |
198 | * simulate the cmpxchg on the 80386 CPU. For that purpose we define |
212 | * a function for each of the sizes we support. |
199 | * a function for each of the sizes we support. |
213 | */ |
200 | */ |
Line -... | Line 201... | ||
- | 201 | ||
- | 202 | extern unsigned long cmpxchg_386_u8(volatile void *, u8, u8); |
|
- | 203 | extern unsigned long cmpxchg_386_u16(volatile void *, u16, u16); |
|
- | 204 | extern unsigned long cmpxchg_386_u32(volatile void *, u32, u32); |
|
- | 205 | ||
- | 206 | static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old, |
|
- | 207 | unsigned long new, int size) |
|
- | 208 | { |
|
- | 209 | switch (size) { |
|
- | 210 | case 1: |
|
- | 211 | return cmpxchg_386_u8(ptr, old, new); |
|
- | 212 | case 2: |
|
- | 213 | return cmpxchg_386_u16(ptr, old, new); |
|
- | 214 | case 4: |
|
- | 215 | return cmpxchg_386_u32(ptr, old, new); |
|
- | 216 | } |
|
- | 217 | return old; |
|
- | 218 | } |
|
214 | 219 | ||
215 | #define cmpxchg(ptr, o, n) \ |
220 | #define cmpxchg(ptr, o, n) \ |
216 | ({ \ |
221 | ({ \ |
217 | __typeof__(*(ptr)) __ret; \ |
222 | __typeof__(*(ptr)) __ret; \ |
218 | __ret = (__typeof__(*(ptr)))__cmpxchg((ptr), \ |
223 | __ret = (__typeof__(*(ptr)))__cmpxchg((ptr), \ |
Line 234... | Line 239... | ||
234 | /* |
239 | /* |
235 | * Building a kernel capable running on 80386 and 80486. It may be necessary |
240 | * Building a kernel capable running on 80386 and 80486. It may be necessary |
236 | * to simulate the cmpxchg8b on the 80386 and 80486 CPU. |
241 | * to simulate the cmpxchg8b on the 80386 and 80486 CPU. |
237 | */ |
242 | */ |
Line 238... | Line -... | ||
238 | - | ||
239 | extern unsigned long long cmpxchg_486_u64(volatile void *, u64, u64); |
- | |
240 | 243 | ||
241 | #define cmpxchg64(ptr, o, n) \ |
244 | #define cmpxchg64(ptr, o, n) \ |
242 | ({ \ |
245 | ({ \ |
243 | __typeof__(*(ptr)) __ret; \ |
246 | __typeof__(*(ptr)) __ret; \ |
244 | __typeof__(*(ptr)) __old = (o); \ |
247 | __typeof__(*(ptr)) __old = (o); \ |
- | 248 | __typeof__(*(ptr)) __new = (n); \ |
|
245 | __typeof__(*(ptr)) __new = (n); \ |
249 | alternative_io(LOCK_PREFIX_HERE \ |
246 | alternative_io("call cmpxchg8b_emu", \ |
250 | "call cmpxchg8b_emu", \ |
247 | "lock; cmpxchg8b (%%esi)" , \ |
251 | "lock; cmpxchg8b (%%esi)" , \ |
248 | X86_FEATURE_CX8, \ |
252 | X86_FEATURE_CX8, \ |
249 | "=A" (__ret), \ |
253 | "=A" (__ret), \ |
250 | "S" ((ptr)), "0" (__old), \ |
254 | "S" ((ptr)), "0" (__old), \ |
251 | "b" ((unsigned int)__new), \ |
255 | "b" ((unsigned int)__new), \ |
252 | "c" ((unsigned int)(__new>>32)) \ |
256 | "c" ((unsigned int)(__new>>32)) \ |
253 | : "memory"); \ |
257 | : "memory"); \ |
Line 254... | Line -... | ||
254 | __ret; }) |
- | |
255 | 258 | __ret; }) |
|
256 | 259 | ||
257 | 260 | ||
258 | #define cmpxchg64_local(ptr, o, n) \ |
261 | #define cmpxchg64_local(ptr, o, n) \ |
259 | ({ \ |
262 | ({ \ |
- | 263 | __typeof__(*(ptr)) __ret; \ |
|
260 | __typeof__(*(ptr)) __ret; \ |
264 | __typeof__(*(ptr)) __old = (o); \ |
261 | if (likely(boot_cpu_data.x86 > 4)) \ |
265 | __typeof__(*(ptr)) __new = (n); \ |
262 | __ret = (__typeof__(*(ptr)))__cmpxchg64_local((ptr), \ |
266 | alternative_io("call cmpxchg8b_emu", \ |
263 | (unsigned long long)(o), \ |
267 | "cmpxchg8b (%%esi)" , \ |
264 | (unsigned long long)(n)); \ |
268 | X86_FEATURE_CX8, \ |
265 | else \ |
269 | "=A" (__ret), \ |
266 | __ret = (__typeof__(*(ptr)))cmpxchg_486_u64((ptr), \ |
270 | "S" ((ptr)), "0" (__old), \ |
267 | (unsigned long long)(o), \ |
271 | "b" ((unsigned int)__new), \ |
Line 268... | Line 272... | ||
268 | (unsigned long long)(n)); \ |
272 | "c" ((unsigned int)(__new>>32)) \ |
Line 269... | Line 273... | ||
269 | __ret; \ |
273 | : "memory"); \ |