diff options
Diffstat (limited to 'include/asm-arm/spinlock.h')
| -rw-r--r-- | include/asm-arm/spinlock.h | 82 |
1 files changed, 54 insertions, 28 deletions
diff --git a/include/asm-arm/spinlock.h b/include/asm-arm/spinlock.h index 182323619caa..1f906d09b688 100644 --- a/include/asm-arm/spinlock.h +++ b/include/asm-arm/spinlock.h | |||
| @@ -8,9 +8,10 @@ | |||
| 8 | /* | 8 | /* |
| 9 | * ARMv6 Spin-locking. | 9 | * ARMv6 Spin-locking. |
| 10 | * | 10 | * |
| 11 | * We (exclusively) read the old value, and decrement it. If it | 11 | * We exclusively read the old value. If it is zero, we may have |
| 12 | * hits zero, we may have won the lock, so we try (exclusively) | 12 | * won the lock, so we try exclusively storing it. A memory barrier |
| 13 | * storing it. | 13 | * is required after we get a lock, and before we release it, because |
| 14 | * V6 CPUs are assumed to have weakly ordered memory. | ||
| 14 | * | 15 | * |
| 15 | * Unlocked value: 0 | 16 | * Unlocked value: 0 |
| 16 | * Locked value: 1 | 17 | * Locked value: 1 |
| @@ -41,7 +42,9 @@ static inline void _raw_spin_lock(spinlock_t *lock) | |||
| 41 | " bne 1b" | 42 | " bne 1b" |
| 42 | : "=&r" (tmp) | 43 | : "=&r" (tmp) |
| 43 | : "r" (&lock->lock), "r" (1) | 44 | : "r" (&lock->lock), "r" (1) |
| 44 | : "cc", "memory"); | 45 | : "cc"); |
| 46 | |||
| 47 | smp_mb(); | ||
| 45 | } | 48 | } |
| 46 | 49 | ||
| 47 | static inline int _raw_spin_trylock(spinlock_t *lock) | 50 | static inline int _raw_spin_trylock(spinlock_t *lock) |
| @@ -54,18 +57,25 @@ static inline int _raw_spin_trylock(spinlock_t *lock) | |||
| 54 | " strexeq %0, %2, [%1]" | 57 | " strexeq %0, %2, [%1]" |
| 55 | : "=&r" (tmp) | 58 | : "=&r" (tmp) |
| 56 | : "r" (&lock->lock), "r" (1) | 59 | : "r" (&lock->lock), "r" (1) |
| 57 | : "cc", "memory"); | 60 | : "cc"); |
| 58 | 61 | ||
| 59 | return tmp == 0; | 62 | if (tmp == 0) { |
| 63 | smp_mb(); | ||
| 64 | return 1; | ||
| 65 | } else { | ||
| 66 | return 0; | ||
| 67 | } | ||
| 60 | } | 68 | } |
| 61 | 69 | ||
| 62 | static inline void _raw_spin_unlock(spinlock_t *lock) | 70 | static inline void _raw_spin_unlock(spinlock_t *lock) |
| 63 | { | 71 | { |
| 72 | smp_mb(); | ||
| 73 | |||
| 64 | __asm__ __volatile__( | 74 | __asm__ __volatile__( |
| 65 | " str %1, [%0]" | 75 | " str %1, [%0]" |
| 66 | : | 76 | : |
| 67 | : "r" (&lock->lock), "r" (0) | 77 | : "r" (&lock->lock), "r" (0) |
| 68 | : "cc", "memory"); | 78 | : "cc"); |
| 69 | } | 79 | } |
| 70 | 80 | ||
| 71 | /* | 81 | /* |
| @@ -79,7 +89,8 @@ typedef struct { | |||
| 79 | } rwlock_t; | 89 | } rwlock_t; |
| 80 | 90 | ||
| 81 | #define RW_LOCK_UNLOCKED (rwlock_t) { 0 } | 91 | #define RW_LOCK_UNLOCKED (rwlock_t) { 0 } |
| 82 | #define rwlock_init(x) do { *(x) + RW_LOCK_UNLOCKED; } while (0) | 92 | #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while (0) |
| 93 | #define rwlock_is_locked(x) (*((volatile unsigned int *)(x)) != 0) | ||
| 83 | 94 | ||
| 84 | /* | 95 | /* |
| 85 | * Write locks are easy - we just set bit 31. When unlocking, we can | 96 | * Write locks are easy - we just set bit 31. When unlocking, we can |
| @@ -97,16 +108,40 @@ static inline void _raw_write_lock(rwlock_t *rw) | |||
| 97 | " bne 1b" | 108 | " bne 1b" |
| 98 | : "=&r" (tmp) | 109 | : "=&r" (tmp) |
| 99 | : "r" (&rw->lock), "r" (0x80000000) | 110 | : "r" (&rw->lock), "r" (0x80000000) |
| 100 | : "cc", "memory"); | 111 | : "cc"); |
| 112 | |||
| 113 | smp_mb(); | ||
| 114 | } | ||
| 115 | |||
| 116 | static inline int _raw_write_trylock(rwlock_t *rw) | ||
| 117 | { | ||
| 118 | unsigned long tmp; | ||
| 119 | |||
| 120 | __asm__ __volatile__( | ||
| 121 | "1: ldrex %0, [%1]\n" | ||
| 122 | " teq %0, #0\n" | ||
| 123 | " strexeq %0, %2, [%1]" | ||
| 124 | : "=&r" (tmp) | ||
| 125 | : "r" (&rw->lock), "r" (0x80000000) | ||
| 126 | : "cc"); | ||
| 127 | |||
| 128 | if (tmp == 0) { | ||
| 129 | smp_mb(); | ||
| 130 | return 1; | ||
| 131 | } else { | ||
| 132 | return 0; | ||
| 133 | } | ||
| 101 | } | 134 | } |
| 102 | 135 | ||
| 103 | static inline void _raw_write_unlock(rwlock_t *rw) | 136 | static inline void _raw_write_unlock(rwlock_t *rw) |
| 104 | { | 137 | { |
| 138 | smp_mb(); | ||
| 139 | |||
| 105 | __asm__ __volatile__( | 140 | __asm__ __volatile__( |
| 106 | "str %1, [%0]" | 141 | "str %1, [%0]" |
| 107 | : | 142 | : |
| 108 | : "r" (&rw->lock), "r" (0) | 143 | : "r" (&rw->lock), "r" (0) |
| 109 | : "cc", "memory"); | 144 | : "cc"); |
| 110 | } | 145 | } |
| 111 | 146 | ||
| 112 | /* | 147 | /* |
| @@ -133,11 +168,17 @@ static inline void _raw_read_lock(rwlock_t *rw) | |||
| 133 | " bmi 1b" | 168 | " bmi 1b" |
| 134 | : "=&r" (tmp), "=&r" (tmp2) | 169 | : "=&r" (tmp), "=&r" (tmp2) |
| 135 | : "r" (&rw->lock) | 170 | : "r" (&rw->lock) |
| 136 | : "cc", "memory"); | 171 | : "cc"); |
| 172 | |||
| 173 | smp_mb(); | ||
| 137 | } | 174 | } |
| 138 | 175 | ||
| 139 | static inline void _raw_read_unlock(rwlock_t *rw) | 176 | static inline void _raw_read_unlock(rwlock_t *rw) |
| 140 | { | 177 | { |
| 178 | unsigned long tmp, tmp2; | ||
| 179 | |||
| 180 | smp_mb(); | ||
| 181 | |||
| 141 | __asm__ __volatile__( | 182 | __asm__ __volatile__( |
| 142 | "1: ldrex %0, [%2]\n" | 183 | "1: ldrex %0, [%2]\n" |
| 143 | " sub %0, %0, #1\n" | 184 | " sub %0, %0, #1\n" |
| @@ -146,24 +187,9 @@ static inline void _raw_read_unlock(rwlock_t *rw) | |||
| 146 | " bne 1b" | 187 | " bne 1b" |
| 147 | : "=&r" (tmp), "=&r" (tmp2) | 188 | : "=&r" (tmp), "=&r" (tmp2) |
| 148 | : "r" (&rw->lock) | 189 | : "r" (&rw->lock) |
| 149 | : "cc", "memory"); | 190 | : "cc"); |
| 150 | } | 191 | } |
| 151 | 192 | ||
| 152 | #define _raw_read_trylock(lock) generic_raw_read_trylock(lock) | 193 | #define _raw_read_trylock(lock) generic_raw_read_trylock(lock) |
| 153 | 194 | ||
| 154 | static inline int _raw_write_trylock(rwlock_t *rw) | ||
| 155 | { | ||
| 156 | unsigned long tmp; | ||
| 157 | |||
| 158 | __asm__ __volatile__( | ||
| 159 | "1: ldrex %0, [%1]\n" | ||
| 160 | " teq %0, #0\n" | ||
| 161 | " strexeq %0, %2, [%1]" | ||
| 162 | : "=&r" (tmp) | ||
| 163 | : "r" (&rw->lock), "r" (0x80000000) | ||
| 164 | : "cc", "memory"); | ||
| 165 | |||
| 166 | return tmp == 0; | ||
| 167 | } | ||
| 168 | |||
| 169 | #endif /* __ASM_SPINLOCK_H */ | 195 | #endif /* __ASM_SPINLOCK_H */ |
