summaryrefslogtreecommitdiffstats
path: root/arch/sparc/lib/atomic_32.S
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2009-01-05 10:50:33 +0100
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-01-05 10:50:33 +0100
commit353816f43d1fb340ff2d9a911dd5d0799c09f6a5 (patch)
tree517290fd884d286fe2971137ac89f89e3567785a /arch/sparc/lib/atomic_32.S
parent160bbab3000dafccbe43688e48208cecf4deb879 (diff)
parentfe0bdec68b77020281dc814805edfe594ae89e0f (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts: arch/arm/mach-pxa/corgi.c arch/arm/mach-pxa/poodle.c arch/arm/mach-pxa/spitz.c
Diffstat (limited to 'arch/sparc/lib/atomic_32.S')
-rw-r--r--arch/sparc/lib/atomic_32.S99
1 files changed, 99 insertions, 0 deletions
diff --git a/arch/sparc/lib/atomic_32.S b/arch/sparc/lib/atomic_32.S
new file mode 100644
index 00000000000..178cbb8ae1b
--- /dev/null
+++ b/arch/sparc/lib/atomic_32.S
@@ -0,0 +1,99 @@
+/* atomic.S: Move this stuff here for better ICACHE hit rates.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+#include <asm/ptrace.h>
+#include <asm/psr.h>
+
+ .text
+ .align 4
+
+ .globl __atomic_begin
+__atomic_begin:
+
+#ifndef CONFIG_SMP
+ .globl ___xchg32_sun4c
+___xchg32_sun4c:
+ rd %psr, %g3
+ andcc %g3, PSR_PIL, %g0
+ bne 1f
+ nop
+ wr %g3, PSR_PIL, %psr
+ nop; nop; nop
+1:
+ andcc %g3, PSR_PIL, %g0
+ ld [%g1], %g7
+ bne 1f
+ st %g2, [%g1]
+ wr %g3, 0x0, %psr
+ nop; nop; nop
+1:
+ mov %g7, %g2
+ jmpl %o7 + 8, %g0
+ mov %g4, %o7
+
+ .globl ___xchg32_sun4md
+___xchg32_sun4md:
+ swap [%g1], %g2
+ jmpl %o7 + 8, %g0
+ mov %g4, %o7
+#endif
+
+ /* Read asm-sparc/atomic.h carefully to understand how this works for SMP.
+ * Really, some things here for SMP are overly clever, go read the header.
+ */
+ .globl ___atomic24_add
+___atomic24_add:
+ rd %psr, %g3 ! Keep the code small, old way was stupid
+ nop; nop; nop; ! Let the bits set
+ or %g3, PSR_PIL, %g7 ! Disable interrupts
+ wr %g7, 0x0, %psr ! Set %psr
+ nop; nop; nop; ! Let the bits set
+#ifdef CONFIG_SMP
+1: ldstub [%g1 + 3], %g7 ! Spin on the byte lock for SMP.
+ orcc %g7, 0x0, %g0 ! Did we get it?
+ bne 1b ! Nope...
+ ld [%g1], %g7 ! Load locked atomic24_t
+ sra %g7, 8, %g7 ! Get signed 24-bit integer
+ add %g7, %g2, %g2 ! Add in argument
+ sll %g2, 8, %g7 ! Transpose back to atomic24_t
+ st %g7, [%g1] ! Clever: This releases the lock as well.
+#else
+ ld [%g1], %g7 ! Load locked atomic24_t
+ add %g7, %g2, %g2 ! Add in argument
+ st %g2, [%g1] ! Store it back
+#endif
+ wr %g3, 0x0, %psr ! Restore original PSR_PIL
+ nop; nop; nop; ! Let the bits set
+ jmpl %o7, %g0 ! NOTE: not + 8, see callers in atomic.h
+ mov %g4, %o7 ! Restore %o7
+
+ .globl ___atomic24_sub
+___atomic24_sub:
+ rd %psr, %g3 ! Keep the code small, old way was stupid
+ nop; nop; nop; ! Let the bits set
+ or %g3, PSR_PIL, %g7 ! Disable interrupts
+ wr %g7, 0x0, %psr ! Set %psr
+ nop; nop; nop; ! Let the bits set
+#ifdef CONFIG_SMP
+1: ldstub [%g1 + 3], %g7 ! Spin on the byte lock for SMP.
+ orcc %g7, 0x0, %g0 ! Did we get it?
+ bne 1b ! Nope...
+ ld [%g1], %g7 ! Load locked atomic24_t
+ sra %g7, 8, %g7 ! Get signed 24-bit integer
+ sub %g7, %g2, %g2 ! Subtract argument
+ sll %g2, 8, %g7 ! Transpose back to atomic24_t
+ st %g7, [%g1] ! Clever: This releases the lock as well
+#else
+ ld [%g1], %g7 ! Load locked atomic24_t
+ sub %g7, %g2, %g2 ! Subtract argument
+ st %g2, [%g1] ! Store it back
+#endif
+ wr %g3, 0x0, %psr ! Restore original PSR_PIL
+ nop; nop; nop; ! Let the bits set
+ jmpl %o7, %g0 ! NOTE: not + 8, see callers in atomic.h
+ mov %g4, %o7 ! Restore %o7
+
+ .globl __atomic_end
+__atomic_end: