diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/asm-i386/alternative.h | 129 | ||||
-rw-r--r-- | include/asm-i386/atomic.h | 28 | ||||
-rw-r--r-- | include/asm-i386/bitops.h | 7 | ||||
-rw-r--r-- | include/asm-i386/cpufeature.h | 1 | ||||
-rw-r--r-- | include/asm-i386/mutex.h | 6 | ||||
-rw-r--r-- | include/asm-i386/rwlock.h | 56 | ||||
-rw-r--r-- | include/asm-i386/semaphore.h | 8 | ||||
-rw-r--r-- | include/asm-i386/spinlock.h | 21 | ||||
-rw-r--r-- | include/asm-i386/system.h | 62 | ||||
-rw-r--r-- | include/asm-um/alternative.h | 6 |
10 files changed, 200 insertions, 124 deletions
diff --git a/include/asm-i386/alternative.h b/include/asm-i386/alternative.h new file mode 100644 index 000000000000..e201decea0c9 --- /dev/null +++ b/include/asm-i386/alternative.h | |||
@@ -0,0 +1,129 @@ | |||
1 | #ifndef _I386_ALTERNATIVE_H | ||
2 | #define _I386_ALTERNATIVE_H | ||
3 | |||
4 | #ifdef __KERNEL__ | ||
5 | |||
6 | struct alt_instr { | ||
7 | u8 *instr; /* original instruction */ | ||
8 | u8 *replacement; | ||
9 | u8 cpuid; /* cpuid bit set for replacement */ | ||
10 | u8 instrlen; /* length of original instruction */ | ||
11 | u8 replacementlen; /* length of new instruction, <= instrlen */ | ||
12 | u8 pad; | ||
13 | }; | ||
14 | |||
15 | extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end); | ||
16 | |||
17 | struct module; | ||
18 | extern void alternatives_smp_module_add(struct module *mod, char *name, | ||
19 | void *locks, void *locks_end, | ||
20 | void *text, void *text_end); | ||
21 | extern void alternatives_smp_module_del(struct module *mod); | ||
22 | extern void alternatives_smp_switch(int smp); | ||
23 | |||
24 | #endif | ||
25 | |||
26 | /* | ||
27 | * Alternative instructions for different CPU types or capabilities. | ||
28 | * | ||
29 | * This allows to use optimized instructions even on generic binary | ||
30 | * kernels. | ||
31 | * | ||
32 | * length of oldinstr must be longer or equal the length of newinstr | ||
33 | * It can be padded with nops as needed. | ||
34 | * | ||
35 | * For non barrier like inlines please define new variants | ||
36 | * without volatile and memory clobber. | ||
37 | */ | ||
38 | #define alternative(oldinstr, newinstr, feature) \ | ||
39 | asm volatile ("661:\n\t" oldinstr "\n662:\n" \ | ||
40 | ".section .altinstructions,\"a\"\n" \ | ||
41 | " .align 4\n" \ | ||
42 | " .long 661b\n" /* label */ \ | ||
43 | " .long 663f\n" /* new instruction */ \ | ||
44 | " .byte %c0\n" /* feature bit */ \ | ||
45 | " .byte 662b-661b\n" /* sourcelen */ \ | ||
46 | " .byte 664f-663f\n" /* replacementlen */ \ | ||
47 | ".previous\n" \ | ||
48 | ".section .altinstr_replacement,\"ax\"\n" \ | ||
49 | "663:\n\t" newinstr "\n664:\n" /* replacement */\ | ||
50 | ".previous" :: "i" (feature) : "memory") | ||
51 | |||
52 | /* | ||
53 | * Alternative inline assembly with input. | ||
54 | * | ||
55 | * Pecularities: | ||
56 | * No memory clobber here. | ||
57 | * Argument numbers start with 1. | ||
58 | * Best is to use constraints that are fixed size (like (%1) ... "r") | ||
59 | * If you use variable sized constraints like "m" or "g" in the | ||
60 | * replacement maake sure to pad to the worst case length. | ||
61 | */ | ||
62 | #define alternative_input(oldinstr, newinstr, feature, input...) \ | ||
63 | asm volatile ("661:\n\t" oldinstr "\n662:\n" \ | ||
64 | ".section .altinstructions,\"a\"\n" \ | ||
65 | " .align 4\n" \ | ||
66 | " .long 661b\n" /* label */ \ | ||
67 | " .long 663f\n" /* new instruction */ \ | ||
68 | " .byte %c0\n" /* feature bit */ \ | ||
69 | " .byte 662b-661b\n" /* sourcelen */ \ | ||
70 | " .byte 664f-663f\n" /* replacementlen */ \ | ||
71 | ".previous\n" \ | ||
72 | ".section .altinstr_replacement,\"ax\"\n" \ | ||
73 | "663:\n\t" newinstr "\n664:\n" /* replacement */\ | ||
74 | ".previous" :: "i" (feature), ##input) | ||
75 | |||
76 | /* | ||
77 | * Alternative inline assembly for SMP. | ||
78 | * | ||
79 | * alternative_smp() takes two versions (SMP first, UP second) and is | ||
80 | * for more complex stuff such as spinlocks. | ||
81 | * | ||
82 | * The LOCK_PREFIX macro defined here replaces the LOCK and | ||
83 | * LOCK_PREFIX macros used everywhere in the source tree. | ||
84 | * | ||
85 | * SMP alternatives use the same data structures as the other | ||
86 | * alternatives and the X86_FEATURE_UP flag to indicate the case of a | ||
87 | * UP system running a SMP kernel. The existing apply_alternatives() | ||
88 | * works fine for patching a SMP kernel for UP. | ||
89 | * | ||
90 | * The SMP alternative tables can be kept after boot and contain both | ||
91 | * UP and SMP versions of the instructions to allow switching back to | ||
92 | * SMP at runtime, when hotplugging in a new CPU, which is especially | ||
93 | * useful in virtualized environments. | ||
94 | * | ||
95 | * The very common lock prefix is handled as special case in a | ||
96 | * separate table which is a pure address list without replacement ptr | ||
97 | * and size information. That keeps the table sizes small. | ||
98 | */ | ||
99 | |||
100 | #ifdef CONFIG_SMP | ||
101 | #define alternative_smp(smpinstr, upinstr, args...) \ | ||
102 | asm volatile ("661:\n\t" smpinstr "\n662:\n" \ | ||
103 | ".section .smp_altinstructions,\"a\"\n" \ | ||
104 | " .align 4\n" \ | ||
105 | " .long 661b\n" /* label */ \ | ||
106 | " .long 663f\n" /* new instruction */ \ | ||
107 | " .byte 0x68\n" /* X86_FEATURE_UP */ \ | ||
108 | " .byte 662b-661b\n" /* sourcelen */ \ | ||
109 | " .byte 664f-663f\n" /* replacementlen */ \ | ||
110 | ".previous\n" \ | ||
111 | ".section .smp_altinstr_replacement,\"awx\"\n" \ | ||
112 | "663:\n\t" upinstr "\n" /* replacement */ \ | ||
113 | "664:\n\t.fill 662b-661b,1,0x42\n" /* space for original */ \ | ||
114 | ".previous" : args) | ||
115 | |||
116 | #define LOCK_PREFIX \ | ||
117 | ".section .smp_locks,\"a\"\n" \ | ||
118 | " .align 4\n" \ | ||
119 | " .long 661f\n" /* address */ \ | ||
120 | ".previous\n" \ | ||
121 | "661:\n\tlock; " | ||
122 | |||
123 | #else /* ! CONFIG_SMP */ | ||
124 | #define alternative_smp(smpinstr, upinstr, args...) \ | ||
125 | asm volatile (upinstr : args) | ||
126 | #define LOCK_PREFIX "" | ||
127 | #endif | ||
128 | |||
129 | #endif /* _I386_ALTERNATIVE_H */ | ||
diff --git a/include/asm-i386/atomic.h b/include/asm-i386/atomic.h index de649d3aa2d4..78b0032d1f29 100644 --- a/include/asm-i386/atomic.h +++ b/include/asm-i386/atomic.h | |||
@@ -10,12 +10,6 @@ | |||
10 | * resource counting etc.. | 10 | * resource counting etc.. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #ifdef CONFIG_SMP | ||
14 | #define LOCK "lock ; " | ||
15 | #else | ||
16 | #define LOCK "" | ||
17 | #endif | ||
18 | |||
19 | /* | 13 | /* |
20 | * Make sure gcc doesn't try to be clever and move things around | 14 | * Make sure gcc doesn't try to be clever and move things around |
21 | * on us. We need to use _exactly_ the address the user gave us, | 15 | * on us. We need to use _exactly_ the address the user gave us, |
@@ -52,7 +46,7 @@ typedef struct { volatile int counter; } atomic_t; | |||
52 | static __inline__ void atomic_add(int i, atomic_t *v) | 46 | static __inline__ void atomic_add(int i, atomic_t *v) |
53 | { | 47 | { |
54 | __asm__ __volatile__( | 48 | __asm__ __volatile__( |
55 | LOCK "addl %1,%0" | 49 | LOCK_PREFIX "addl %1,%0" |
56 | :"=m" (v->counter) | 50 | :"=m" (v->counter) |
57 | :"ir" (i), "m" (v->counter)); | 51 | :"ir" (i), "m" (v->counter)); |
58 | } | 52 | } |
@@ -67,7 +61,7 @@ static __inline__ void atomic_add(int i, atomic_t *v) | |||
67 | static __inline__ void atomic_sub(int i, atomic_t *v) | 61 | static __inline__ void atomic_sub(int i, atomic_t *v) |
68 | { | 62 | { |
69 | __asm__ __volatile__( | 63 | __asm__ __volatile__( |
70 | LOCK "subl %1,%0" | 64 | LOCK_PREFIX "subl %1,%0" |
71 | :"=m" (v->counter) | 65 | :"=m" (v->counter) |
72 | :"ir" (i), "m" (v->counter)); | 66 | :"ir" (i), "m" (v->counter)); |
73 | } | 67 | } |
@@ -86,7 +80,7 @@ static __inline__ int atomic_sub_and_test(int i, atomic_t *v) | |||
86 | unsigned char c; | 80 | unsigned char c; |
87 | 81 | ||
88 | __asm__ __volatile__( | 82 | __asm__ __volatile__( |
89 | LOCK "subl %2,%0; sete %1" | 83 | LOCK_PREFIX "subl %2,%0; sete %1" |
90 | :"=m" (v->counter), "=qm" (c) | 84 | :"=m" (v->counter), "=qm" (c) |
91 | :"ir" (i), "m" (v->counter) : "memory"); | 85 | :"ir" (i), "m" (v->counter) : "memory"); |
92 | return c; | 86 | return c; |
@@ -101,7 +95,7 @@ static __inline__ int atomic_sub_and_test(int i, atomic_t *v) | |||
101 | static __inline__ void atomic_inc(atomic_t *v) | 95 | static __inline__ void atomic_inc(atomic_t *v) |
102 | { | 96 | { |
103 | __asm__ __volatile__( | 97 | __asm__ __volatile__( |
104 | LOCK "incl %0" | 98 | LOCK_PREFIX "incl %0" |
105 | :"=m" (v->counter) | 99 | :"=m" (v->counter) |
106 | :"m" (v->counter)); | 100 | :"m" (v->counter)); |
107 | } | 101 | } |
@@ -115,7 +109,7 @@ static __inline__ void atomic_inc(atomic_t *v) | |||
115 | static __inline__ void atomic_dec(atomic_t *v) | 109 | static __inline__ void atomic_dec(atomic_t *v) |
116 | { | 110 | { |
117 | __asm__ __volatile__( | 111 | __asm__ __volatile__( |
118 | LOCK "decl %0" | 112 | LOCK_PREFIX "decl %0" |
119 | :"=m" (v->counter) | 113 | :"=m" (v->counter) |
120 | :"m" (v->counter)); | 114 | :"m" (v->counter)); |
121 | } | 115 | } |
@@ -133,7 +127,7 @@ static __inline__ int atomic_dec_and_test(atomic_t *v) | |||
133 | unsigned char c; | 127 | unsigned char c; |
134 | 128 | ||
135 | __asm__ __volatile__( | 129 | __asm__ __volatile__( |
136 | LOCK "decl %0; sete %1" | 130 | LOCK_PREFIX "decl %0; sete %1" |
137 | :"=m" (v->counter), "=qm" (c) | 131 | :"=m" (v->counter), "=qm" (c) |
138 | :"m" (v->counter) : "memory"); | 132 | :"m" (v->counter) : "memory"); |
139 | return c != 0; | 133 | return c != 0; |
@@ -152,7 +146,7 @@ static __inline__ int atomic_inc_and_test(atomic_t *v) | |||
152 | unsigned char c; | 146 | unsigned char c; |
153 | 147 | ||
154 | __asm__ __volatile__( | 148 | __asm__ __volatile__( |
155 | LOCK "incl %0; sete %1" | 149 | LOCK_PREFIX "incl %0; sete %1" |
156 | :"=m" (v->counter), "=qm" (c) | 150 | :"=m" (v->counter), "=qm" (c) |
157 | :"m" (v->counter) : "memory"); | 151 | :"m" (v->counter) : "memory"); |
158 | return c != 0; | 152 | return c != 0; |
@@ -172,7 +166,7 @@ static __inline__ int atomic_add_negative(int i, atomic_t *v) | |||
172 | unsigned char c; | 166 | unsigned char c; |
173 | 167 | ||
174 | __asm__ __volatile__( | 168 | __asm__ __volatile__( |
175 | LOCK "addl %2,%0; sets %1" | 169 | LOCK_PREFIX "addl %2,%0; sets %1" |
176 | :"=m" (v->counter), "=qm" (c) | 170 | :"=m" (v->counter), "=qm" (c) |
177 | :"ir" (i), "m" (v->counter) : "memory"); | 171 | :"ir" (i), "m" (v->counter) : "memory"); |
178 | return c; | 172 | return c; |
@@ -195,7 +189,7 @@ static __inline__ int atomic_add_return(int i, atomic_t *v) | |||
195 | /* Modern 486+ processor */ | 189 | /* Modern 486+ processor */ |
196 | __i = i; | 190 | __i = i; |
197 | __asm__ __volatile__( | 191 | __asm__ __volatile__( |
198 | LOCK "xaddl %0, %1;" | 192 | LOCK_PREFIX "xaddl %0, %1;" |
199 | :"=r"(i) | 193 | :"=r"(i) |
200 | :"m"(v->counter), "0"(i)); | 194 | :"m"(v->counter), "0"(i)); |
201 | return i + __i; | 195 | return i + __i; |
@@ -242,11 +236,11 @@ static __inline__ int atomic_sub_return(int i, atomic_t *v) | |||
242 | 236 | ||
243 | /* These are x86-specific, used by some header files */ | 237 | /* These are x86-specific, used by some header files */ |
244 | #define atomic_clear_mask(mask, addr) \ | 238 | #define atomic_clear_mask(mask, addr) \ |
245 | __asm__ __volatile__(LOCK "andl %0,%1" \ | 239 | __asm__ __volatile__(LOCK_PREFIX "andl %0,%1" \ |
246 | : : "r" (~(mask)),"m" (*addr) : "memory") | 240 | : : "r" (~(mask)),"m" (*addr) : "memory") |
247 | 241 | ||
248 | #define atomic_set_mask(mask, addr) \ | 242 | #define atomic_set_mask(mask, addr) \ |
249 | __asm__ __volatile__(LOCK "orl %0,%1" \ | 243 | __asm__ __volatile__(LOCK_PREFIX "orl %0,%1" \ |
250 | : : "r" (mask),"m" (*(addr)) : "memory") | 244 | : : "r" (mask),"m" (*(addr)) : "memory") |
251 | 245 | ||
252 | /* Atomic operations are already serializing on x86 */ | 246 | /* Atomic operations are already serializing on x86 */ |
diff --git a/include/asm-i386/bitops.h b/include/asm-i386/bitops.h index 88e6ca248cd7..7d20b95edb3b 100644 --- a/include/asm-i386/bitops.h +++ b/include/asm-i386/bitops.h | |||
@@ -7,6 +7,7 @@ | |||
7 | 7 | ||
8 | #include <linux/config.h> | 8 | #include <linux/config.h> |
9 | #include <linux/compiler.h> | 9 | #include <linux/compiler.h> |
10 | #include <asm/alternative.h> | ||
10 | 11 | ||
11 | /* | 12 | /* |
12 | * These have to be done with inline assembly: that way the bit-setting | 13 | * These have to be done with inline assembly: that way the bit-setting |
@@ -16,12 +17,6 @@ | |||
16 | * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1). | 17 | * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1). |
17 | */ | 18 | */ |
18 | 19 | ||
19 | #ifdef CONFIG_SMP | ||
20 | #define LOCK_PREFIX "lock ; " | ||
21 | #else | ||
22 | #define LOCK_PREFIX "" | ||
23 | #endif | ||
24 | |||
25 | #define ADDR (*(volatile long *) addr) | 20 | #define ADDR (*(volatile long *) addr) |
26 | 21 | ||
27 | /** | 22 | /** |
diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h index c4ec2a4d8fdf..5c0b5876b931 100644 --- a/include/asm-i386/cpufeature.h +++ b/include/asm-i386/cpufeature.h | |||
@@ -70,6 +70,7 @@ | |||
70 | #define X86_FEATURE_P3 (3*32+ 6) /* P3 */ | 70 | #define X86_FEATURE_P3 (3*32+ 6) /* P3 */ |
71 | #define X86_FEATURE_P4 (3*32+ 7) /* P4 */ | 71 | #define X86_FEATURE_P4 (3*32+ 7) /* P4 */ |
72 | #define X86_FEATURE_CONSTANT_TSC (3*32+ 8) /* TSC ticks at a constant rate */ | 72 | #define X86_FEATURE_CONSTANT_TSC (3*32+ 8) /* TSC ticks at a constant rate */ |
73 | #define X86_FEATURE_UP (3*32+ 9) /* smp kernel running on up */ | ||
73 | 74 | ||
74 | /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ | 75 | /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ |
75 | #define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */ | 76 | #define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */ |
diff --git a/include/asm-i386/mutex.h b/include/asm-i386/mutex.h index 9b2199e829f3..05a538531229 100644 --- a/include/asm-i386/mutex.h +++ b/include/asm-i386/mutex.h | |||
@@ -9,6 +9,8 @@ | |||
9 | #ifndef _ASM_MUTEX_H | 9 | #ifndef _ASM_MUTEX_H |
10 | #define _ASM_MUTEX_H | 10 | #define _ASM_MUTEX_H |
11 | 11 | ||
12 | #include "asm/alternative.h" | ||
13 | |||
12 | /** | 14 | /** |
13 | * __mutex_fastpath_lock - try to take the lock by moving the count | 15 | * __mutex_fastpath_lock - try to take the lock by moving the count |
14 | * from 1 to a 0 value | 16 | * from 1 to a 0 value |
@@ -27,7 +29,7 @@ do { \ | |||
27 | typecheck_fn(fastcall void (*)(atomic_t *), fail_fn); \ | 29 | typecheck_fn(fastcall void (*)(atomic_t *), fail_fn); \ |
28 | \ | 30 | \ |
29 | __asm__ __volatile__( \ | 31 | __asm__ __volatile__( \ |
30 | LOCK " decl (%%eax) \n" \ | 32 | LOCK_PREFIX " decl (%%eax) \n" \ |
31 | " js 2f \n" \ | 33 | " js 2f \n" \ |
32 | "1: \n" \ | 34 | "1: \n" \ |
33 | \ | 35 | \ |
@@ -83,7 +85,7 @@ do { \ | |||
83 | typecheck_fn(fastcall void (*)(atomic_t *), fail_fn); \ | 85 | typecheck_fn(fastcall void (*)(atomic_t *), fail_fn); \ |
84 | \ | 86 | \ |
85 | __asm__ __volatile__( \ | 87 | __asm__ __volatile__( \ |
86 | LOCK " incl (%%eax) \n" \ | 88 | LOCK_PREFIX " incl (%%eax) \n" \ |
87 | " jle 2f \n" \ | 89 | " jle 2f \n" \ |
88 | "1: \n" \ | 90 | "1: \n" \ |
89 | \ | 91 | \ |
diff --git a/include/asm-i386/rwlock.h b/include/asm-i386/rwlock.h index b57cc7afdf7e..94f00195d543 100644 --- a/include/asm-i386/rwlock.h +++ b/include/asm-i386/rwlock.h | |||
@@ -21,21 +21,23 @@ | |||
21 | #define RW_LOCK_BIAS_STR "0x01000000" | 21 | #define RW_LOCK_BIAS_STR "0x01000000" |
22 | 22 | ||
23 | #define __build_read_lock_ptr(rw, helper) \ | 23 | #define __build_read_lock_ptr(rw, helper) \ |
24 | asm volatile(LOCK "subl $1,(%0)\n\t" \ | 24 | alternative_smp("lock; subl $1,(%0)\n\t" \ |
25 | "jns 1f\n" \ | 25 | "jns 1f\n" \ |
26 | "call " helper "\n\t" \ | 26 | "call " helper "\n\t" \ |
27 | "1:\n" \ | 27 | "1:\n", \ |
28 | ::"a" (rw) : "memory") | 28 | "subl $1,(%0)\n\t", \ |
29 | :"a" (rw) : "memory") | ||
29 | 30 | ||
30 | #define __build_read_lock_const(rw, helper) \ | 31 | #define __build_read_lock_const(rw, helper) \ |
31 | asm volatile(LOCK "subl $1,%0\n\t" \ | 32 | alternative_smp("lock; subl $1,%0\n\t" \ |
32 | "jns 1f\n" \ | 33 | "jns 1f\n" \ |
33 | "pushl %%eax\n\t" \ | 34 | "pushl %%eax\n\t" \ |
34 | "leal %0,%%eax\n\t" \ | 35 | "leal %0,%%eax\n\t" \ |
35 | "call " helper "\n\t" \ | 36 | "call " helper "\n\t" \ |
36 | "popl %%eax\n\t" \ | 37 | "popl %%eax\n\t" \ |
37 | "1:\n" \ | 38 | "1:\n", \ |
38 | :"=m" (*(volatile int *)rw) : : "memory") | 39 | "subl $1,%0\n\t", \ |
40 | "=m" (*(volatile int *)rw) : : "memory") | ||
39 | 41 | ||
40 | #define __build_read_lock(rw, helper) do { \ | 42 | #define __build_read_lock(rw, helper) do { \ |
41 | if (__builtin_constant_p(rw)) \ | 43 | if (__builtin_constant_p(rw)) \ |
@@ -45,21 +47,23 @@ | |||
45 | } while (0) | 47 | } while (0) |
46 | 48 | ||
47 | #define __build_write_lock_ptr(rw, helper) \ | 49 | #define __build_write_lock_ptr(rw, helper) \ |
48 | asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \ | 50 | alternative_smp("lock; subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \ |
49 | "jz 1f\n" \ | 51 | "jz 1f\n" \ |
50 | "call " helper "\n\t" \ | 52 | "call " helper "\n\t" \ |
51 | "1:\n" \ | 53 | "1:\n", \ |
52 | ::"a" (rw) : "memory") | 54 | "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t", \ |
55 | :"a" (rw) : "memory") | ||
53 | 56 | ||
54 | #define __build_write_lock_const(rw, helper) \ | 57 | #define __build_write_lock_const(rw, helper) \ |
55 | asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \ | 58 | alternative_smp("lock; subl $" RW_LOCK_BIAS_STR ",%0\n\t" \ |
56 | "jz 1f\n" \ | 59 | "jz 1f\n" \ |
57 | "pushl %%eax\n\t" \ | 60 | "pushl %%eax\n\t" \ |
58 | "leal %0,%%eax\n\t" \ | 61 | "leal %0,%%eax\n\t" \ |
59 | "call " helper "\n\t" \ | 62 | "call " helper "\n\t" \ |
60 | "popl %%eax\n\t" \ | 63 | "popl %%eax\n\t" \ |
61 | "1:\n" \ | 64 | "1:\n", \ |
62 | :"=m" (*(volatile int *)rw) : : "memory") | 65 | "subl $" RW_LOCK_BIAS_STR ",%0\n\t", \ |
66 | "=m" (*(volatile int *)rw) : : "memory") | ||
63 | 67 | ||
64 | #define __build_write_lock(rw, helper) do { \ | 68 | #define __build_write_lock(rw, helper) do { \ |
65 | if (__builtin_constant_p(rw)) \ | 69 | if (__builtin_constant_p(rw)) \ |
diff --git a/include/asm-i386/semaphore.h b/include/asm-i386/semaphore.h index 6a42b2142fd6..f7a0f310c524 100644 --- a/include/asm-i386/semaphore.h +++ b/include/asm-i386/semaphore.h | |||
@@ -99,7 +99,7 @@ static inline void down(struct semaphore * sem) | |||
99 | might_sleep(); | 99 | might_sleep(); |
100 | __asm__ __volatile__( | 100 | __asm__ __volatile__( |
101 | "# atomic down operation\n\t" | 101 | "# atomic down operation\n\t" |
102 | LOCK "decl %0\n\t" /* --sem->count */ | 102 | LOCK_PREFIX "decl %0\n\t" /* --sem->count */ |
103 | "js 2f\n" | 103 | "js 2f\n" |
104 | "1:\n" | 104 | "1:\n" |
105 | LOCK_SECTION_START("") | 105 | LOCK_SECTION_START("") |
@@ -123,7 +123,7 @@ static inline int down_interruptible(struct semaphore * sem) | |||
123 | might_sleep(); | 123 | might_sleep(); |
124 | __asm__ __volatile__( | 124 | __asm__ __volatile__( |
125 | "# atomic interruptible down operation\n\t" | 125 | "# atomic interruptible down operation\n\t" |
126 | LOCK "decl %1\n\t" /* --sem->count */ | 126 | LOCK_PREFIX "decl %1\n\t" /* --sem->count */ |
127 | "js 2f\n\t" | 127 | "js 2f\n\t" |
128 | "xorl %0,%0\n" | 128 | "xorl %0,%0\n" |
129 | "1:\n" | 129 | "1:\n" |
@@ -148,7 +148,7 @@ static inline int down_trylock(struct semaphore * sem) | |||
148 | 148 | ||
149 | __asm__ __volatile__( | 149 | __asm__ __volatile__( |
150 | "# atomic interruptible down operation\n\t" | 150 | "# atomic interruptible down operation\n\t" |
151 | LOCK "decl %1\n\t" /* --sem->count */ | 151 | LOCK_PREFIX "decl %1\n\t" /* --sem->count */ |
152 | "js 2f\n\t" | 152 | "js 2f\n\t" |
153 | "xorl %0,%0\n" | 153 | "xorl %0,%0\n" |
154 | "1:\n" | 154 | "1:\n" |
@@ -173,7 +173,7 @@ static inline void up(struct semaphore * sem) | |||
173 | { | 173 | { |
174 | __asm__ __volatile__( | 174 | __asm__ __volatile__( |
175 | "# atomic up operation\n\t" | 175 | "# atomic up operation\n\t" |
176 | LOCK "incl %0\n\t" /* ++sem->count */ | 176 | LOCK_PREFIX "incl %0\n\t" /* ++sem->count */ |
177 | "jle 2f\n" | 177 | "jle 2f\n" |
178 | "1:\n" | 178 | "1:\n" |
179 | LOCK_SECTION_START("") | 179 | LOCK_SECTION_START("") |
diff --git a/include/asm-i386/spinlock.h b/include/asm-i386/spinlock.h index 23604350cdf4..a1b8a8a30e21 100644 --- a/include/asm-i386/spinlock.h +++ b/include/asm-i386/spinlock.h | |||
@@ -48,18 +48,23 @@ | |||
48 | "jmp 1b\n" \ | 48 | "jmp 1b\n" \ |
49 | "4:\n\t" | 49 | "4:\n\t" |
50 | 50 | ||
51 | #define __raw_spin_lock_string_up \ | ||
52 | "\n\tdecb %0" | ||
53 | |||
51 | static inline void __raw_spin_lock(raw_spinlock_t *lock) | 54 | static inline void __raw_spin_lock(raw_spinlock_t *lock) |
52 | { | 55 | { |
53 | __asm__ __volatile__( | 56 | alternative_smp( |
54 | __raw_spin_lock_string | 57 | __raw_spin_lock_string, |
55 | :"=m" (lock->slock) : : "memory"); | 58 | __raw_spin_lock_string_up, |
59 | "=m" (lock->slock) : : "memory"); | ||
56 | } | 60 | } |
57 | 61 | ||
58 | static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags) | 62 | static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags) |
59 | { | 63 | { |
60 | __asm__ __volatile__( | 64 | alternative_smp( |
61 | __raw_spin_lock_string_flags | 65 | __raw_spin_lock_string_flags, |
62 | :"=m" (lock->slock) : "r" (flags) : "memory"); | 66 | __raw_spin_lock_string_up, |
67 | "=m" (lock->slock) : "r" (flags) : "memory"); | ||
63 | } | 68 | } |
64 | 69 | ||
65 | static inline int __raw_spin_trylock(raw_spinlock_t *lock) | 70 | static inline int __raw_spin_trylock(raw_spinlock_t *lock) |
@@ -178,12 +183,12 @@ static inline int __raw_write_trylock(raw_rwlock_t *lock) | |||
178 | 183 | ||
179 | static inline void __raw_read_unlock(raw_rwlock_t *rw) | 184 | static inline void __raw_read_unlock(raw_rwlock_t *rw) |
180 | { | 185 | { |
181 | asm volatile("lock ; incl %0" :"=m" (rw->lock) : : "memory"); | 186 | asm volatile(LOCK_PREFIX "incl %0" :"=m" (rw->lock) : : "memory"); |
182 | } | 187 | } |
183 | 188 | ||
184 | static inline void __raw_write_unlock(raw_rwlock_t *rw) | 189 | static inline void __raw_write_unlock(raw_rwlock_t *rw) |
185 | { | 190 | { |
186 | asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ", %0" | 191 | asm volatile(LOCK_PREFIX "addl $" RW_LOCK_BIAS_STR ", %0" |
187 | : "=m" (rw->lock) : : "memory"); | 192 | : "=m" (rw->lock) : : "memory"); |
188 | } | 193 | } |
189 | 194 | ||
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h index 399145a247f2..d0d8d7448d88 100644 --- a/include/asm-i386/system.h +++ b/include/asm-i386/system.h | |||
@@ -352,67 +352,6 @@ static inline unsigned long long __cmpxchg64(volatile void *ptr, unsigned long l | |||
352 | 352 | ||
353 | #endif | 353 | #endif |
354 | 354 | ||
355 | #ifdef __KERNEL__ | ||
356 | struct alt_instr { | ||
357 | __u8 *instr; /* original instruction */ | ||
358 | __u8 *replacement; | ||
359 | __u8 cpuid; /* cpuid bit set for replacement */ | ||
360 | __u8 instrlen; /* length of original instruction */ | ||
361 | __u8 replacementlen; /* length of new instruction, <= instrlen */ | ||
362 | __u8 pad; | ||
363 | }; | ||
364 | #endif | ||
365 | |||
366 | /* | ||
367 | * Alternative instructions for different CPU types or capabilities. | ||
368 | * | ||
369 | * This allows to use optimized instructions even on generic binary | ||
370 | * kernels. | ||
371 | * | ||
372 | * length of oldinstr must be longer or equal the length of newinstr | ||
373 | * It can be padded with nops as needed. | ||
374 | * | ||
375 | * For non barrier like inlines please define new variants | ||
376 | * without volatile and memory clobber. | ||
377 | */ | ||
378 | #define alternative(oldinstr, newinstr, feature) \ | ||
379 | asm volatile ("661:\n\t" oldinstr "\n662:\n" \ | ||
380 | ".section .altinstructions,\"a\"\n" \ | ||
381 | " .align 4\n" \ | ||
382 | " .long 661b\n" /* label */ \ | ||
383 | " .long 663f\n" /* new instruction */ \ | ||
384 | " .byte %c0\n" /* feature bit */ \ | ||
385 | " .byte 662b-661b\n" /* sourcelen */ \ | ||
386 | " .byte 664f-663f\n" /* replacementlen */ \ | ||
387 | ".previous\n" \ | ||
388 | ".section .altinstr_replacement,\"ax\"\n" \ | ||
389 | "663:\n\t" newinstr "\n664:\n" /* replacement */ \ | ||
390 | ".previous" :: "i" (feature) : "memory") | ||
391 | |||
392 | /* | ||
393 | * Alternative inline assembly with input. | ||
394 | * | ||
395 | * Pecularities: | ||
396 | * No memory clobber here. | ||
397 | * Argument numbers start with 1. | ||
398 | * Best is to use constraints that are fixed size (like (%1) ... "r") | ||
399 | * If you use variable sized constraints like "m" or "g" in the | ||
400 | * replacement maake sure to pad to the worst case length. | ||
401 | */ | ||
402 | #define alternative_input(oldinstr, newinstr, feature, input...) \ | ||
403 | asm volatile ("661:\n\t" oldinstr "\n662:\n" \ | ||
404 | ".section .altinstructions,\"a\"\n" \ | ||
405 | " .align 4\n" \ | ||
406 | " .long 661b\n" /* label */ \ | ||
407 | " .long 663f\n" /* new instruction */ \ | ||
408 | " .byte %c0\n" /* feature bit */ \ | ||
409 | " .byte 662b-661b\n" /* sourcelen */ \ | ||
410 | " .byte 664f-663f\n" /* replacementlen */ \ | ||
411 | ".previous\n" \ | ||
412 | ".section .altinstr_replacement,\"ax\"\n" \ | ||
413 | "663:\n\t" newinstr "\n664:\n" /* replacement */ \ | ||
414 | ".previous" :: "i" (feature), ##input) | ||
415 | |||
416 | /* | 355 | /* |
417 | * Force strict CPU ordering. | 356 | * Force strict CPU ordering. |
418 | * And yes, this is required on UP too when we're talking | 357 | * And yes, this is required on UP too when we're talking |
@@ -558,5 +497,6 @@ static inline void sched_cacheflush(void) | |||
558 | } | 497 | } |
559 | 498 | ||
560 | extern unsigned long arch_align_stack(unsigned long sp); | 499 | extern unsigned long arch_align_stack(unsigned long sp); |
500 | extern void free_init_pages(char *what, unsigned long begin, unsigned long end); | ||
561 | 501 | ||
562 | #endif | 502 | #endif |
diff --git a/include/asm-um/alternative.h b/include/asm-um/alternative.h new file mode 100644 index 000000000000..b6434396bd42 --- /dev/null +++ b/include/asm-um/alternative.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef __UM_ALTERNATIVE_H | ||
2 | #define __UM_ALTERNATIVE_H | ||
3 | |||
4 | #include "asm/arch/alternative.h" | ||
5 | |||
6 | #endif | ||