summaryrefslogtreecommitdiff
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorxxie <xxie@nvidia.com>2011-01-31 20:03:45 -0800
committerNiket Sirsi <nsirsi@nvidia.com>2011-05-25 15:57:59 -0700
commit9b8f82db8279b0add89e3ef4fc06f3d23c2fce80 (patch)
tree59fcd75073d6d1f750d8eedd659c0d59cfd15dc5 /arch/arm/kernel
parent30015f8be08a183d4942d9849fa38e97754f36cd (diff)
ARM: Fix strex() in SWP emulation
Found an application hanging using this SWP emulation on a SMP system. A memory barrier is needed right after the strex() otherwise we have the synchronization issues on SMP. This patch let ldrex()+strex()+memory_barrier() loop continuesly until the strex() is successful, this is same as ARM kernel spinlock implementation and Bionic library's mutex's SWP() routine. Tested the new implementation in a user space program running 100 threads using the SWP based mutex on SMP systems, it did not show any race conditions. Change-Id: Ib5de14ba41a3fdb31510752114990be9ef35e144 Reviewed-on: http://git-master/r/29745 Reviewed-by: Xin Xie <xxie@nvidia.com> Tested-by: Xin Xie <xxie@nvidia.com> Reviewed-by: Scott Williams <scwilliams@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/swp_emulate.c48
1 files changed, 17 insertions, 31 deletions
diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c
index 7a5760922914..8fbb954da483 100644
--- a/arch/arm/kernel/swp_emulate.c
+++ b/arch/arm/kernel/swp_emulate.c
@@ -36,12 +36,13 @@
" mov %2, %1\n" \
"0: ldrex"B" %1, [%3]\n" \
"1: strex"B" %0, %2, [%3]\n" \
- " cmp %0, #0\n" \
- " movne %0, %4\n" \
+ " dmb\n" \
+ " teq %0, #0\n" \
+ " bne 0b\n" \
"2:\n" \
" .section .fixup,\"ax\"\n" \
" .align 2\n" \
- "3: mov %0, %5\n" \
+ "3: mov %0, %4\n" \
" b 2b\n" \
" .previous\n" \
" .section __ex_table,\"a\"\n" \
@@ -50,7 +51,7 @@
" .long 1b, 3b\n" \
" .previous" \
: "=&r" (res), "+r" (data), "=&r" (temp) \
- : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \
+ : "r" (addr), "i" (-EFAULT) \
: "cc", "memory")
#define __user_swp_asm(data, addr, res, temp) \
@@ -127,6 +128,7 @@ static int emulate_swpX(unsigned int address, unsigned int *data,
unsigned int type)
{
unsigned int res = 0;
+ unsigned long temp;
if ((type != TYPE_SWPB) && (address & 0x3)) {
/* SWP to unaligned address not permitted */
@@ -134,36 +136,20 @@ static int emulate_swpX(unsigned int address, unsigned int *data,
return -EFAULT;
}
- while (1) {
- unsigned long temp;
+ /*
+ * Barrier required between accessing protected resource and
+ * releasing a lock for it. Legacy code might not have done
+ * this, and we cannot determine that this is not the case
+ * being emulated, so insert always.
+ */
+ smp_mb();
- /*
- * Barrier required between accessing protected resource and
- * releasing a lock for it. Legacy code might not have done
- * this, and we cannot determine that this is not the case
- * being emulated, so insert always.
- */
- smp_mb();
-
- if (type == TYPE_SWPB)
- __user_swpb_asm(*data, address, res, temp);
- else
- __user_swp_asm(*data, address, res, temp);
-
- if (likely(res != -EAGAIN) || signal_pending(current))
- break;
-
- cond_resched();
- }
+ if (type == TYPE_SWPB)
+ __user_swpb_asm(*data, address, res, temp);
+ else
+ __user_swp_asm(*data, address, res, temp);
if (res == 0) {
- /*
- * Barrier also required between aquiring a lock for a
- * protected resource and accessing the resource. Inserted for
- * same reason as above.
- */
- smp_mb();
-
if (type == TYPE_SWPB)
swpbcounter++;
else