summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2010-02-20 16:13:43 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2010-02-20 16:13:43 +0000
commit1a4ed70d204022e6b929701d21300c4593da8513 (patch)
tree54fc7caf881b3b1a012a7c6ef6e223507f177454
parent0b363d5ac3998739989ea3f6af616294d64ed696 (diff)
downloadFreeBSD-src-1a4ed70d204022e6b929701d21300c4593da8513.zip
FreeBSD-src-1a4ed70d204022e6b929701d21300c4593da8513.tar.gz
Merge r198724 to Book-E. casuword() non-atomically read the current value
of its argument before atomically replacing it, which could occasionally return the wrong value on an SMP system. This resulted in user mutex operations hanging when using threaded applications.
-rw-r--r--sys/powerpc/booke/copyinout.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/sys/powerpc/booke/copyinout.c b/sys/powerpc/booke/copyinout.c
index fd3bdf3..91195dd 100644
--- a/sys/powerpc/booke/copyinout.c
+++ b/sys/powerpc/booke/copyinout.c
@@ -295,8 +295,19 @@ casuword(volatile u_long *addr, u_long old, u_long new)
return (EFAULT);
}
- val = *addr;
- (void) atomic_cmpset_32((volatile uint32_t *)addr, old, new);
+ __asm __volatile (
+ "1:\tlwarx %0, 0, %2\n\t" /* load old value */
+ "cmplw %3, %0\n\t" /* compare */
+ "bne 2f\n\t" /* exit if not equal */
+ "stwcx. %4, 0, %2\n\t" /* attempt to store */
+ "bne- 1b\n\t" /* spin if failed */
+ "b 3f\n\t" /* we've succeeded */
+ "2:\n\t"
+ "stwcx. %0, 0, %2\n\t" /* clear reservation (74xx) */
+ "3:\n\t"
+ : "=&r" (val), "=m" (*addr)
+ : "r" (addr), "r" (old), "r" (new), "m" (*addr)
+ : "cc", "memory");
td->td_pcb->pcb_onfault = NULL;
OpenPOWER on IntegriCloud