aboutsummaryrefslogtreecommitdiffstats
path: root/include/asm-powerpc
diff options
context:
space:
mode:
authorRobert Jennings <rcj@linux.vnet.ibm.com>2007-01-17 11:50:20 -0500
committerPaul Mackerras <paulus@samba.org>2007-01-22 05:27:36 -0500
commit434f98c48fc1d2a1f562a28a1562a7b53e940957 (patch)
treedc722bebcbbe74282b0170955a45848b49720e16 /include/asm-powerpc
parent06cd9396778d5b70ba27fa8158db78d6bc0f007b (diff)
[POWERPC] atomic_dec_if_positive sign extension fix
On 64-bit machines, if an atomic counter is explicitly set to a negative value, the atomic_dec_if_positive function will decrement and store the next smallest value in the atomic counter, contrary to its intended operation. The comparison to determine if the decrement will make the result negative was done by the "addic." instruction, which operates on a 64-bit value, namely the zero-extended word loaded from the atomic variable. This patch uses an explicit word compare (cmpwi) and changes the addic. to an addi (also changing "=&r" to "=&b" so that r0 isn't used, and addi doesn't become li). This also fixes a bug for both 32-bit and 64-bit in that previously 0x80000000 was considered positive, since the result after decrementing is positive. Now it is considered negative. Also, I clarify the return value in the comments just to make it clear that the value returned is always the decremented value, even if that value is not stored back to the atomic counter. Signed-off-by: Robert Jennings <rcj@linux.vnet.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'include/asm-powerpc')
-rw-r--r--include/asm-powerpc/atomic.h8
1 files changed, 5 insertions, 3 deletions
diff --git a/include/asm-powerpc/atomic.h b/include/asm-powerpc/atomic.h
index 53283e2540b3..f038e33e6d48 100644
--- a/include/asm-powerpc/atomic.h
+++ b/include/asm-powerpc/atomic.h
@@ -207,7 +207,8 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
207 207
208/* 208/*
209 * Atomically test *v and decrement if it is greater than 0. 209 * Atomically test *v and decrement if it is greater than 0.
210 * The function returns the old value of *v minus 1. 210 * The function returns the old value of *v minus 1, even if
211 * the atomic variable, v, was not decremented.
211 */ 212 */
212static __inline__ int atomic_dec_if_positive(atomic_t *v) 213static __inline__ int atomic_dec_if_positive(atomic_t *v)
213{ 214{
@@ -216,14 +217,15 @@ static __inline__ int atomic_dec_if_positive(atomic_t *v)
216 __asm__ __volatile__( 217 __asm__ __volatile__(
217 LWSYNC_ON_SMP 218 LWSYNC_ON_SMP
218"1: lwarx %0,0,%1 # atomic_dec_if_positive\n\ 219"1: lwarx %0,0,%1 # atomic_dec_if_positive\n\
219 addic. %0,%0,-1\n\ 220 cmpwi %0,1\n\
221 addi %0,%0,-1\n\
220 blt- 2f\n" 222 blt- 2f\n"
221 PPC405_ERR77(0,%1) 223 PPC405_ERR77(0,%1)
222" stwcx. %0,0,%1\n\ 224" stwcx. %0,0,%1\n\
223 bne- 1b" 225 bne- 1b"
224 ISYNC_ON_SMP 226 ISYNC_ON_SMP
225 "\n\ 227 "\n\
2262:" : "=&r" (t) 2282:" : "=&b" (t)
227 : "r" (&v->counter) 229 : "r" (&v->counter)
228 : "cc", "memory"); 230 : "cc", "memory");
229 231