--- parisc-2.6/arch/parisc/include/asm/futex.h	2010-12-21 08:59:48.000000000 -0500
+++ parisc-2.6-jejb/arch/parisc/include/asm/futex.h	2011-07-04 01:55:19.000000000 -0400
@@ -5,11 +5,14 @@
 
 #include <linux/futex.h>
 #include <linux/uaccess.h>
+#include <asm/atomic.h>
 #include <asm/errno.h>
 
 static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
 {
+	unsigned long int flags;
+	u32 val;
 	int op = (encoded_op >> 28) & 7;
 	int cmp = (encoded_op >> 24) & 15;
 	int oparg = (encoded_op << 8) >> 20;
@@ -18,32 +21,69 @@
 	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
 		oparg = 1 << oparg;
 
-	if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+	if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
 		return -EFAULT;
 
 	pagefault_disable();
 
+	_atomic_spin_lock_irqsave (uaddr, flags);
+
 	switch (op) {
-	case FUTEX_OP_SET:
-	case FUTEX_OP_ADD:
-	case FUTEX_OP_OR:
-	case FUTEX_OP_ANDN:
-	case FUTEX_OP_XOR:
-	default:
-		ret = -ENOSYS;
+		case FUTEX_OP_SET:
+			/* *(int *)UADDR2 = OPARG; */
+			ret = get_user (oldval, uaddr);
+			if (!ret)
+				ret = put_user (oparg, uaddr);
+			break;
+		case FUTEX_OP_ADD:
+			/* *(int *)UADDR2 += OPARG; */
+			ret = get_user (oldval, uaddr);
+			if (!ret) {
+				val = oldval + oparg;
+				ret = put_user (val, uaddr);
+			}
+			break;
+		case FUTEX_OP_OR:
+			/* *(int *)UADDR2 |= OPARG; */
+			ret = get_user (oldval, uaddr);
+			if (!ret) {
+				val = oldval | oparg;
+				ret = put_user (val, uaddr);
+			}
+			break;
+		case FUTEX_OP_ANDN:
+			/* *(int *)UADDR2 &= ~OPARG; */
+			ret = get_user (oldval, uaddr);
+			if (!ret) {
+				val = oldval & ~oparg;
+				ret = put_user (val, uaddr);
+			}
+			break;
+		case FUTEX_OP_XOR:
+			/* *(int *)UADDR2 ^= OPARG; */
+			ret = get_user (oldval, uaddr);
+			if (!ret) {
+				val = oldval ^ oparg;
+				ret = put_user (val, uaddr);
+			}
+			break;
+		default:
+			ret = -ENOSYS;
 	}
 
+	_atomic_spin_unlock_irqrestore (uaddr, flags);
+
 	pagefault_enable();
 
 	if (!ret) {
 		switch (cmp) {
-		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
-		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
-		default: ret = -ENOSYS;
+			case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+			case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+			case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+			case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+			case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+			case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+			default: ret = -ENOSYS;
 		}
 	}
 	return ret;
@@ -51,10 +91,12 @@
 
 /* Non-atomic version */
 static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+			      u32 oldval, u32 newval)
 {
-	int err = 0;
-	int uval;
+	int ret;
+	u32 val;
+	unsigned long flags;
 
 	/* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
 	 * our gateway page, and causes no end of trouble...
@@ -62,15 +104,28 @@
 	if (segment_eq(KERNEL_DS, get_fs()) && !uaddr)
 		return -EFAULT;
 
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
 		return -EFAULT;
 
-	err = get_user(uval, uaddr);
-	if (err) return -EFAULT;
-	if (uval == oldval)
-		err = put_user(newval, uaddr);
-	if (err) return -EFAULT;
-	return uval;
+	/* HPPA has no cmpxchg in hardware and therefore the 
+	 * best we can do here is use an array of locks. The
+	 * lock selected is based on a hash of the userspace
+	 * address. This should scale to a couple of CPUs.
+	 */
+
+	_atomic_spin_lock_irqsave (uaddr, flags);
+
+	ret = get_user(val, uaddr);
+
+	if (!ret)
+		if (val == oldval)
+			ret = put_user (newval, uaddr);
+
+	*uval = val;
+
+	_atomic_spin_unlock_irqrestore (uaddr, flags);
+
+	return ret;
 }
 
 #endif /*__KERNEL__*/

