diff options
| -rw-r--r-- | arch/x86/include/asm/rwsem.h | 53 |
1 files changed, 40 insertions, 13 deletions
diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h index 5f9af3081d66..10204a25bf93 100644 --- a/arch/x86/include/asm/rwsem.h +++ b/arch/x86/include/asm/rwsem.h | |||
| @@ -41,6 +41,7 @@ | |||
| 41 | #include <linux/list.h> | 41 | #include <linux/list.h> |
| 42 | #include <linux/spinlock.h> | 42 | #include <linux/spinlock.h> |
| 43 | #include <linux/lockdep.h> | 43 | #include <linux/lockdep.h> |
| 44 | #include <asm/asm.h> | ||
| 44 | 45 | ||
| 45 | struct rwsem_waiter; | 46 | struct rwsem_waiter; |
| 46 | 47 | ||
| @@ -56,18 +57,24 @@ extern asmregparm struct rw_semaphore * | |||
| 56 | /* | 57 | /* |
| 57 | * the semaphore definition | 58 | * the semaphore definition |
| 58 | * | 59 | * |
| 59 | * The bias values and the counter type needs to be extended to 64 bits | 60 | * The bias values and the counter type limits the number of |
| 60 | * if we want to have more than 32767 potential readers/writers | 61 | * potential readers/writers to 32767 for 32 bits and 2147483647 |
| 62 | * for 64 bits. | ||
| 61 | */ | 63 | */ |
| 62 | 64 | ||
| 63 | #define RWSEM_UNLOCKED_VALUE 0x00000000 | 65 | #ifdef CONFIG_X86_64 |
| 64 | #define RWSEM_ACTIVE_BIAS 0x00000001 | 66 | # define RWSEM_ACTIVE_MASK 0xffffffffL |
| 65 | #define RWSEM_ACTIVE_MASK 0x0000ffff | 67 | #else |
| 66 | #define RWSEM_WAITING_BIAS (-0x00010000) | 68 | # define RWSEM_ACTIVE_MASK 0x0000ffffL |
| 69 | #endif | ||
| 70 | |||
| 71 | #define RWSEM_UNLOCKED_VALUE 0x00000000L | ||
| 72 | #define RWSEM_ACTIVE_BIAS 0x00000001L | ||
| 73 | #define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1) | ||
| 67 | #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS | 74 | #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS |
| 68 | #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) | 75 | #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) |
| 69 | 76 | ||
| 70 | typedef signed int rwsem_count_t; | 77 | typedef signed long rwsem_count_t; |
| 71 | 78 | ||
| 72 | struct rw_semaphore { | 79 | struct rw_semaphore { |
| 73 | rwsem_count_t count; | 80 | rwsem_count_t count; |
| @@ -110,7 +117,7 @@ do { \ | |||
| 110 | static inline void __down_read(struct rw_semaphore *sem) | 117 | static inline void __down_read(struct rw_semaphore *sem) |
| 111 | { | 118 | { |
| 112 | asm volatile("# beginning down_read\n\t" | 119 | asm volatile("# beginning down_read\n\t" |
| 113 | LOCK_PREFIX " inc%z0 (%1)\n\t" | 120 | LOCK_PREFIX _ASM_INC "(%1)\n\t" |
| 114 | /* adds 0x00000001, returns the old value */ | 121 | /* adds 0x00000001, returns the old value */ |
| 115 | " jns 1f\n" | 122 | " jns 1f\n" |
| 116 | " call call_rwsem_down_read_failed\n" | 123 | " call call_rwsem_down_read_failed\n" |
| @@ -225,8 +232,25 @@ static inline void __up_write(struct rw_semaphore *sem) | |||
| 225 | */ | 232 | */ |
| 226 | static inline void __downgrade_write(struct rw_semaphore *sem) | 233 | static inline void __downgrade_write(struct rw_semaphore *sem) |
| 227 | { | 234 | { |
| 235 | #ifdef CONFIG_X86_64 | ||
| 236 | # if RWSEM_WAITING_BIAS != -0x100000000 | ||
| 237 | # error "This code assumes RWSEM_WAITING_BIAS == -2^32" | ||
| 238 | # endif | ||
| 239 | |||
| 240 | /* 64-bit immediates are special and expensive, and not needed here */ | ||
| 241 | asm volatile("# beginning __downgrade_write\n\t" | ||
| 242 | LOCK_PREFIX "incl 4(%1)\n\t" | ||
| 243 | /* transitions 0xZZZZZZZZ00000001 -> 0xYYYYYYYY00000001 */ | ||
| 244 | " jns 1f\n\t" | ||
| 245 | " call call_rwsem_downgrade_wake\n" | ||
| 246 | "1:\n\t" | ||
| 247 | "# ending __downgrade_write\n" | ||
| 248 | : "+m" (sem->count) | ||
| 249 | : "a" (sem) | ||
| 250 | : "memory", "cc"); | ||
| 251 | #else | ||
| 228 | asm volatile("# beginning __downgrade_write\n\t" | 252 | asm volatile("# beginning __downgrade_write\n\t" |
| 229 | LOCK_PREFIX " add%z0 %2,(%1)\n\t" | 253 | LOCK_PREFIX _ASM_ADD "%2,(%1)\n\t" |
| 230 | /* transitions 0xZZZZ0001 -> 0xYYYY0001 */ | 254 | /* transitions 0xZZZZ0001 -> 0xYYYY0001 */ |
| 231 | " jns 1f\n\t" | 255 | " jns 1f\n\t" |
| 232 | " call call_rwsem_downgrade_wake\n" | 256 | " call call_rwsem_downgrade_wake\n" |
| @@ -235,22 +259,25 @@ static inline void __downgrade_write(struct rw_semaphore *sem) | |||
| 235 | : "+m" (sem->count) | 259 | : "+m" (sem->count) |
| 236 | : "a" (sem), "i" (-RWSEM_WAITING_BIAS) | 260 | : "a" (sem), "i" (-RWSEM_WAITING_BIAS) |
| 237 | : "memory", "cc"); | 261 | : "memory", "cc"); |
| 262 | #endif | ||
| 238 | } | 263 | } |
| 239 | 264 | ||
| 240 | /* | 265 | /* |
| 241 | * implement atomic add functionality | 266 | * implement atomic add functionality |
| 242 | */ | 267 | */ |
| 243 | static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) | 268 | static inline void rwsem_atomic_add(rwsem_count_t delta, |
| 269 | struct rw_semaphore *sem) | ||
| 244 | { | 270 | { |
| 245 | asm volatile(LOCK_PREFIX "add%z0 %1,%0" | 271 | asm volatile(LOCK_PREFIX _ASM_ADD "%1,%0" |
| 246 | : "+m" (sem->count) | 272 | : "+m" (sem->count) |
| 247 | : "ir" (delta)); | 273 | : "er" (delta)); |
| 248 | } | 274 | } |
| 249 | 275 | ||
| 250 | /* | 276 | /* |
| 251 | * implement exchange and add functionality | 277 | * implement exchange and add functionality |
| 252 | */ | 278 | */ |
| 253 | static inline rwsem_count_t rwsem_atomic_update(int delta, struct rw_semaphore *sem) | 279 | static inline rwsem_count_t rwsem_atomic_update(rwsem_count_t delta, |
| 280 | struct rw_semaphore *sem) | ||
| 254 | { | 281 | { |
| 255 | rwsem_count_t tmp = delta; | 282 | rwsem_count_t tmp = delta; |
| 256 | 283 | ||
