aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2007-10-18 06:06:53 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-18 17:37:29 -0400
commit728697cd6b3c8c12d0ad5ebdce5616ef5d25bf18 (patch)
tree48d08bf438bbc41ed7c2b32387ca91eed2b20a7f /include
parentc8f30ae54714abf494d79826d90b5e4844fbf355 (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')
-rw-r--r--include/asm-mips/bitops.h97
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 */
182static 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 */
321static 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 */
551static 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>