diff options
| -rw-r--r-- | arch/tile/include/asm/spinlock_32.h | 83 | ||||
| -rw-r--r-- | arch/tile/lib/spinlock_32.c | 161 |
2 files changed, 103 insertions, 141 deletions
diff --git a/arch/tile/include/asm/spinlock_32.h b/arch/tile/include/asm/spinlock_32.h index 88efdde8dd2b..a8f2c6e31a87 100644 --- a/arch/tile/include/asm/spinlock_32.h +++ b/arch/tile/include/asm/spinlock_32.h | |||
| @@ -78,13 +78,6 @@ void arch_spin_unlock_wait(arch_spinlock_t *lock); | |||
| 78 | #define _RD_COUNT_SHIFT 24 | 78 | #define _RD_COUNT_SHIFT 24 |
| 79 | #define _RD_COUNT_WIDTH 8 | 79 | #define _RD_COUNT_WIDTH 8 |
| 80 | 80 | ||
| 81 | /* Internal functions; do not use. */ | ||
| 82 | void arch_read_lock_slow(arch_rwlock_t *, u32); | ||
| 83 | int arch_read_trylock_slow(arch_rwlock_t *); | ||
| 84 | void arch_read_unlock_slow(arch_rwlock_t *); | ||
| 85 | void arch_write_lock_slow(arch_rwlock_t *, u32); | ||
| 86 | void arch_write_unlock_slow(arch_rwlock_t *, u32); | ||
| 87 | |||
| 88 | /** | 81 | /** |
| 89 | * arch_read_can_lock() - would read_trylock() succeed? | 82 | * arch_read_can_lock() - would read_trylock() succeed? |
| 90 | */ | 83 | */ |
| @@ -104,94 +97,32 @@ static inline int arch_write_can_lock(arch_rwlock_t *rwlock) | |||
| 104 | /** | 97 | /** |
| 105 | * arch_read_lock() - acquire a read lock. | 98 | * arch_read_lock() - acquire a read lock. |
| 106 | */ | 99 | */ |
| 107 | static inline void arch_read_lock(arch_rwlock_t *rwlock) | 100 | void arch_read_lock(arch_rwlock_t *rwlock); |
| 108 | { | ||
| 109 | u32 val = __insn_tns((int *)&rwlock->lock); | ||
| 110 | if (unlikely(val << _RD_COUNT_WIDTH)) { | ||
| 111 | arch_read_lock_slow(rwlock, val); | ||
| 112 | return; | ||
| 113 | } | ||
| 114 | rwlock->lock = val + (1 << _RD_COUNT_SHIFT); | ||
| 115 | } | ||
| 116 | 101 | ||
| 117 | /** | 102 | /** |
| 118 | * arch_read_lock() - acquire a write lock. | 103 | * arch_write_lock() - acquire a write lock. |
| 119 | */ | 104 | */ |
| 120 | static inline void arch_write_lock(arch_rwlock_t *rwlock) | 105 | void arch_write_lock(arch_rwlock_t *rwlock); |
| 121 | { | ||
| 122 | u32 val = __insn_tns((int *)&rwlock->lock); | ||
| 123 | if (unlikely(val != 0)) { | ||
| 124 | arch_write_lock_slow(rwlock, val); | ||
| 125 | return; | ||
| 126 | } | ||
| 127 | rwlock->lock = 1 << _WR_NEXT_SHIFT; | ||
| 128 | } | ||
| 129 | 106 | ||
| 130 | /** | 107 | /** |
| 131 | * arch_read_trylock() - try to acquire a read lock. | 108 | * arch_read_trylock() - try to acquire a read lock. |
| 132 | */ | 109 | */ |
| 133 | static inline int arch_read_trylock(arch_rwlock_t *rwlock) | 110 | int arch_read_trylock(arch_rwlock_t *rwlock); |
| 134 | { | ||
| 135 | int locked; | ||
| 136 | u32 val = __insn_tns((int *)&rwlock->lock); | ||
| 137 | if (unlikely(val & 1)) | ||
| 138 | return arch_read_trylock_slow(rwlock); | ||
| 139 | locked = (val << _RD_COUNT_WIDTH) == 0; | ||
| 140 | rwlock->lock = val + (locked << _RD_COUNT_SHIFT); | ||
| 141 | return locked; | ||
| 142 | } | ||
| 143 | 111 | ||
| 144 | /** | 112 | /** |
| 145 | * arch_write_trylock() - try to acquire a write lock. | 113 | * arch_write_trylock() - try to acquire a write lock. |
| 146 | */ | 114 | */ |
| 147 | static inline int arch_write_trylock(arch_rwlock_t *rwlock) | 115 | int arch_write_trylock(arch_rwlock_t *rwlock); |
| 148 | { | ||
| 149 | u32 val = __insn_tns((int *)&rwlock->lock); | ||
| 150 | |||
| 151 | /* | ||
| 152 | * If a tns is in progress, or there's a waiting or active locker, | ||
| 153 | * or active readers, we can't take the lock, so give up. | ||
| 154 | */ | ||
| 155 | if (unlikely(val != 0)) { | ||
| 156 | if (!(val & 1)) | ||
| 157 | rwlock->lock = val; | ||
| 158 | return 0; | ||
| 159 | } | ||
| 160 | |||
| 161 | /* Set the "next" field to mark it locked. */ | ||
| 162 | rwlock->lock = 1 << _WR_NEXT_SHIFT; | ||
| 163 | return 1; | ||
| 164 | } | ||
| 165 | 116 | ||
| 166 | /** | 117 | /** |
| 167 | * arch_read_unlock() - release a read lock. | 118 | * arch_read_unlock() - release a read lock. |
| 168 | */ | 119 | */ |
| 169 | static inline void arch_read_unlock(arch_rwlock_t *rwlock) | 120 | void arch_read_unlock(arch_rwlock_t *rwlock); |
| 170 | { | ||
| 171 | u32 val; | ||
| 172 | mb(); /* guarantee anything modified under the lock is visible */ | ||
| 173 | val = __insn_tns((int *)&rwlock->lock); | ||
| 174 | if (unlikely(val & 1)) { | ||
| 175 | arch_read_unlock_slow(rwlock); | ||
| 176 | return; | ||
| 177 | } | ||
| 178 | rwlock->lock = val - (1 << _RD_COUNT_SHIFT); | ||
| 179 | } | ||
| 180 | 121 | ||
| 181 | /** | 122 | /** |
| 182 | * arch_write_unlock() - release a write lock. | 123 | * arch_write_unlock() - release a write lock. |
| 183 | */ | 124 | */ |
| 184 | static inline void arch_write_unlock(arch_rwlock_t *rwlock) | 125 | void arch_write_unlock(arch_rwlock_t *rwlock); |
| 185 | { | ||
| 186 | u32 val; | ||
| 187 | mb(); /* guarantee anything modified under the lock is visible */ | ||
| 188 | val = __insn_tns((int *)&rwlock->lock); | ||
| 189 | if (unlikely(val != (1 << _WR_NEXT_SHIFT))) { | ||
| 190 | arch_write_unlock_slow(rwlock, val); | ||
| 191 | return; | ||
| 192 | } | ||
| 193 | rwlock->lock = 0; | ||
| 194 | } | ||
| 195 | 126 | ||
| 196 | #define arch_read_lock_flags(lock, flags) arch_read_lock(lock) | 127 | #define arch_read_lock_flags(lock, flags) arch_read_lock(lock) |
| 197 | #define arch_write_lock_flags(lock, flags) arch_write_lock(lock) | 128 | #define arch_write_lock_flags(lock, flags) arch_write_lock(lock) |
diff --git a/arch/tile/lib/spinlock_32.c b/arch/tile/lib/spinlock_32.c index 5cd1c4004eca..cb0999fb64b4 100644 --- a/arch/tile/lib/spinlock_32.c +++ b/arch/tile/lib/spinlock_32.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <asm/processor.h> | 17 | #include <asm/processor.h> |
| 18 | #include <arch/spr_def.h> | ||
| 18 | 19 | ||
| 19 | #include "spinlock_common.h" | 20 | #include "spinlock_common.h" |
| 20 | 21 | ||
| @@ -91,75 +92,75 @@ EXPORT_SYMBOL(arch_spin_unlock_wait); | |||
| 91 | #define RD_COUNT_MASK ((1 << RD_COUNT_WIDTH) - 1) | 92 | #define RD_COUNT_MASK ((1 << RD_COUNT_WIDTH) - 1) |
| 92 | 93 | ||
| 93 | 94 | ||
| 94 | /* Lock the word, spinning until there are no tns-ers. */ | 95 | /* |
| 95 | static inline u32 get_rwlock(arch_rwlock_t *rwlock) | 96 | * We can get the read lock if everything but the reader bits (which |
| 96 | { | 97 | * are in the high part of the word) is zero, i.e. no active or |
| 97 | u32 iterations = 0; | 98 | * waiting writers, no tns. |
| 98 | for (;;) { | 99 | * |
| 99 | u32 val = __insn_tns((int *)&rwlock->lock); | 100 | * We guard the tns/store-back with an interrupt critical section to |
| 100 | if (unlikely(val & 1)) { | 101 | * preserve the semantic that the same read lock can be acquired in an |
| 101 | delay_backoff(iterations++); | 102 | * interrupt context. |
| 102 | continue; | 103 | */ |
| 103 | } | 104 | inline int arch_read_trylock(arch_rwlock_t *rwlock) |
| 104 | return val; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | int arch_read_trylock_slow(arch_rwlock_t *rwlock) | ||
| 109 | { | ||
| 110 | u32 val = get_rwlock(rwlock); | ||
| 111 | int locked = (val << RD_COUNT_WIDTH) == 0; | ||
| 112 | rwlock->lock = val + (locked << RD_COUNT_SHIFT); | ||
| 113 | return locked; | ||
| 114 | } | ||
| 115 | EXPORT_SYMBOL(arch_read_trylock_slow); | ||
| 116 | |||
| 117 | void arch_read_unlock_slow(arch_rwlock_t *rwlock) | ||
| 118 | { | ||
| 119 | u32 val = get_rwlock(rwlock); | ||
| 120 | rwlock->lock = val - (1 << RD_COUNT_SHIFT); | ||
| 121 | } | ||
| 122 | EXPORT_SYMBOL(arch_read_unlock_slow); | ||
| 123 | |||
| 124 | void arch_write_unlock_slow(arch_rwlock_t *rwlock, u32 val) | ||
| 125 | { | 105 | { |
| 126 | u32 eq, mask = 1 << WR_CURR_SHIFT; | 106 | u32 val; |
| 127 | while (unlikely(val & 1)) { | 107 | __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 1); |
| 128 | /* Limited backoff since we are the highest-priority task. */ | 108 | val = __insn_tns((int *)&rwlock->lock); |
| 129 | relax(4); | 109 | if (likely((val << _RD_COUNT_WIDTH) == 0)) { |
| 130 | val = __insn_tns((int *)&rwlock->lock); | 110 | val += 1 << RD_COUNT_SHIFT; |
| 111 | rwlock->lock = val; | ||
| 112 | __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0); | ||
