diff options
author | Nick Piggin <npiggin@suse.de> | 2007-10-18 06:06:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-18 17:37:29 -0400 |
commit | 728697cd6b3c8c12d0ad5ebdce5616ef5d25bf18 (patch) | |
tree | 48d08bf438bbc41ed7c2b32387ca91eed2b20a7f /include/asm-mips | |
parent | c8f30ae54714abf494d79826d90b5e4844fbf355 (diff) |
mips: lock bitops
mips can avoid one mb when acquiring a lock with test_and_set_bit_lock.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Cc: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/asm-mips')
-rw-r--r-- | include/asm-mips/bitops.h | 97 |
1 files changed, 96 insertions, 1 deletions
diff --git a/include/asm-mips/bitops.h b/include/asm-mips/bitops.h index 5478d947e289..77ed0c79830b 100644 --- a/include/asm-mips/bitops.h +++ b/include/asm-mips/bitops.h | |||
@@ -172,6 +172,20 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr) | |||
172 | } | 172 | } |
173 | 173 | ||
174 | /* | 174 | /* |
175 | * clear_bit_unlock - Clears a bit in memory | ||
176 | * @nr: Bit to clear | ||
177 | * @addr: Address to start counting from | ||
178 | * | ||
179 | * clear_bit() is atomic and implies release semantics before the memory | ||
180 | * operation. It can be used for an unlock. | ||
181 | */ | ||
182 | static inline void clear_bit_unlock(unsigned long nr, volatile unsigned long *addr) | ||
183 | { | ||
184 | smp_mb__before_clear_bit(); | ||
185 | clear_bit(nr, addr); | ||
186 | } | ||
187 | |||
188 | /* | ||
175 | * change_bit - Toggle a bit in memory | 189 | * change_bit - Toggle a bit in memory |
176 | * @nr: Bit to change | 190 | * @nr: Bit to change |
177 | * @addr: Address to start counting from | 191 | * @addr: Address to start counting from |
@@ -297,6 +311,73 @@ static inline int test_and_set_bit(unsigned long nr, | |||
297 | } | 311 | } |
298 | 312 | ||
299 | /* | 313 | /* |
314 | * test_and_set_bit_lock - Set a bit and return its old value | ||
315 | * @nr: Bit to set | ||
316 | * @addr: Address to count from | ||
317 | * | ||
318 | * This operation is atomic and implies acquire ordering semantics | ||
319 | * after the memory operation. | ||
320 | */ | ||
321 | static inline int test_and_set_bit_lock(unsigned long nr, | ||
322 | volatile unsigned long *addr) | ||
323 | { | ||
324 | unsigned short bit = nr & SZLONG_MASK; | ||
325 | unsigned long res; | ||
326 | |||
327 | if (cpu_has_llsc && R10000_LLSC_WAR) { | ||
328 | unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG); | ||
329 | unsigned long temp; | ||
330 | |||
331 | __asm__ __volatile__( | ||
332 | " .set mips3 \n" | ||
333 | "1: " __LL "%0, %1 # test_and_set_bit \n" | ||
334 | " or %2, %0, %3 \n" | ||
335 | " " __SC "%2, %1 \n" | ||
336 | " beqzl %2, 1b \n" | ||
337 | " and %2, %0, %3 \n" | ||
338 | " .set mips0 \n" | ||
339 | : "=&r" (temp), "=m" (*m), "=&r" (res) | ||
340 | : "r" (1UL << bit), "m" (*m) | ||
341 | : "memory"); | ||
342 | } else if (cpu_has_llsc) { | ||
343 | unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG); | ||
344 | unsigned long temp; | ||
345 | |||
346 | __asm__ __volatile__( | ||
347 | " .set push \n" | ||
348 | " .set noreorder \n" | ||
349 | " .set mips3 \n" | ||
350 | "1: " __LL "%0, %1 # test_and_set_bit \n" | ||
351 | " or %2, %0, %3 \n" | ||
352 | " " __SC "%2, %1 \n" | ||
353 | " beqz %2, 2f \n" | ||
354 | " and %2, %0, %3 \n" | ||
355 | " .subsection 2 \n" | ||
356 | "2: b 1b \n" | ||
357 | " nop \n" | ||
358 | " .previous \n" | ||
359 | " .set pop \n" | ||
360 | : "=&r" (temp), "=m" (*m), "=&r" (res) | ||
361 | : "r" (1UL << bit), "m" (*m) | ||
362 | : "memory"); | ||
363 | } else { | ||
364 | volatile unsigned long *a = addr; | ||
365 | unsigned long mask; | ||
366 | unsigned long flags; | ||
367 | |||
368 | a += nr >> SZLONG_LOG; | ||
369 | mask = 1UL << bit; | ||
370 | raw_local_irq_save(flags); | ||
371 | res = (mask & *a); | ||
372 | *a |= mask; | ||
373 | raw_local_irq_restore(flags); | ||
374 | } | ||
375 | |||
376 | smp_llsc_mb(); | ||
377 | |||
378 | return res != 0; | ||
379 | } | ||
380 | /* | ||
300 | * test_and_clear_bit - Clear a bit and return its old value | 381 | * test_and_clear_bit - Clear a bit and return its old value |
301 | * @nr: Bit to clear | 382 | * @nr: Bit to clear |
302 | * @addr: Address to count from | 383 | * @addr: Address to count from |
@@ -459,6 +540,21 @@ static inline int test_and_change_bit(unsigned long nr, | |||
459 | #include <asm-generic/bitops/non-atomic.h> | 540 | #include <asm-generic/bitops/non-atomic.h> |
460 | 541 | ||
461 | /* | 542 | /* |
543 | * __clear_bit_unlock - Clears a bit in memory | ||
544 | * @nr: Bit to clear | ||
545 | * @addr: Address to start counting from | ||
546 | * | ||
547 | * __clear_bit() is non-atomic and implies release semantics before the memory | ||
548 | * operation. It can be used for an unlock if no other CPUs can concurrently | ||
549 | * modify other bits in the word. | ||
550 | */ | ||
551 | static inline void __clear_bit_unlock(unsigned long nr, volatile unsigned long *addr) | ||
552 | { | ||
553 | smp_mb(); | ||
554 | __clear_bit(nr, addr); | ||
555 | } | ||
556 | |||
557 | /* | ||
462 | * Return the bit position (0..63) of the most significant 1 bit in a word | 558 | * Return the bit position (0..63) of the most significant 1 bit in a word |
463 | * Returns -1 if no 1 bit exists | 559 | * Returns -1 if no 1 bit exists |
464 | */ | 560 | */ |
@@ -562,7 +658,6 @@ static inline int ffs(int word) | |||
562 | 658 | ||
563 | #include <asm-generic/bitops/sched.h> | 659 | #include <asm-generic/bitops/sched.h> |
564 | #include <asm-generic/bitops/hweight.h> | 660 | #include <asm-generic/bitops/hweight.h> |
565 | #include <asm-generic/bitops/lock.h> | ||
566 | #include <asm-generic/bitops/ext2-non-atomic.h> | 661 | #include <asm-generic/bitops/ext2-non-atomic.h> |
567 | #include <asm-generic/bitops/ext2-atomic.h> | 662 | #include <asm-generic/bitops/ext2-atomic.h> |
568 | #include <asm-generic/bitops/minix.h> | 663 | #include <asm-generic/bitops/minix.h> |