1deae26bfSKyle McMartin #ifndef _ASM_PARISC_FUTEX_H 2deae26bfSKyle McMartin #define _ASM_PARISC_FUTEX_H 3deae26bfSKyle McMartin 4deae26bfSKyle McMartin #ifdef __KERNEL__ 5deae26bfSKyle McMartin 6deae26bfSKyle McMartin #include <linux/futex.h> 7deae26bfSKyle McMartin #include <linux/uaccess.h> 8d9ba5fe7SCarlos O'Donell #include <asm/atomic.h> 9deae26bfSKyle McMartin #include <asm/errno.h> 10deae26bfSKyle McMartin 118b232816SJohn David Anglin /* The following has to match the LWS code in syscall.S. We have 128b232816SJohn David Anglin sixteen four-word locks. */ 138b232816SJohn David Anglin 148b232816SJohn David Anglin static inline void 158b232816SJohn David Anglin _futex_spin_lock_irqsave(u32 __user *uaddr, unsigned long int *flags) 168b232816SJohn David Anglin { 178b232816SJohn David Anglin extern u32 lws_lock_start[]; 188b232816SJohn David Anglin long index = ((long)uaddr & 0xf0) >> 2; 198b232816SJohn David Anglin arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index]; 208b232816SJohn David Anglin local_irq_save(*flags); 218b232816SJohn David Anglin arch_spin_lock(s); 228b232816SJohn David Anglin } 238b232816SJohn David Anglin 248b232816SJohn David Anglin static inline void 258b232816SJohn David Anglin _futex_spin_unlock_irqrestore(u32 __user *uaddr, unsigned long int *flags) 268b232816SJohn David Anglin { 278b232816SJohn David Anglin extern u32 lws_lock_start[]; 288b232816SJohn David Anglin long index = ((long)uaddr & 0xf0) >> 2; 298b232816SJohn David Anglin arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index]; 308b232816SJohn David Anglin arch_spin_unlock(s); 318b232816SJohn David Anglin local_irq_restore(*flags); 328b232816SJohn David Anglin } 338b232816SJohn David Anglin 34deae26bfSKyle McMartin static inline int 358d7718aaSMichel Lespinasse futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) 36deae26bfSKyle McMartin { 37d9ba5fe7SCarlos O'Donell unsigned long int flags; 38deae26bfSKyle McMartin int op = (encoded_op >> 28) & 7; 39deae26bfSKyle McMartin int cmp = (encoded_op >> 24) & 15; 40deae26bfSKyle McMartin int oparg = (encoded_op << 8) >> 20; 41deae26bfSKyle McMartin int cmparg = (encoded_op << 20) >> 20; 42*99aed91aSJohn David Anglin int oldval, ret; 43*99aed91aSJohn David Anglin u32 tmp; 44*99aed91aSJohn David Anglin 45deae26bfSKyle McMartin if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) 46deae26bfSKyle McMartin oparg = 1 << oparg; 47deae26bfSKyle McMartin 48d9ba5fe7SCarlos O'Donell if (!access_ok(VERIFY_WRITE, uaddr, sizeof(*uaddr))) 49deae26bfSKyle McMartin return -EFAULT; 50deae26bfSKyle McMartin 51*99aed91aSJohn David Anglin _futex_spin_lock_irqsave(uaddr, &flags); 52deae26bfSKyle McMartin pagefault_disable(); 53deae26bfSKyle McMartin 54*99aed91aSJohn David Anglin ret = -EFAULT; 55*99aed91aSJohn David Anglin if (unlikely(get_user(oldval, uaddr) != 0)) 56*99aed91aSJohn David Anglin goto out_pagefault_enable; 57*99aed91aSJohn David Anglin 58*99aed91aSJohn David Anglin ret = 0; 59*99aed91aSJohn David Anglin tmp = oldval; 60d9ba5fe7SCarlos O'Donell 61deae26bfSKyle McMartin switch (op) { 62deae26bfSKyle McMartin case FUTEX_OP_SET: 63*99aed91aSJohn David Anglin tmp = oparg; 64d9ba5fe7SCarlos O'Donell break; 65deae26bfSKyle McMartin case FUTEX_OP_ADD: 66*99aed91aSJohn David Anglin tmp += oparg; 67d9ba5fe7SCarlos O'Donell break; 68deae26bfSKyle McMartin case FUTEX_OP_OR: 69*99aed91aSJohn David Anglin tmp |= oparg; 70d9ba5fe7SCarlos O'Donell break; 71deae26bfSKyle McMartin case FUTEX_OP_ANDN: 72*99aed91aSJohn David Anglin tmp &= ~oparg; 73d9ba5fe7SCarlos O'Donell break; 74deae26bfSKyle McMartin case FUTEX_OP_XOR: 75*99aed91aSJohn David Anglin tmp ^= oparg; 76d9ba5fe7SCarlos O'Donell break; 77deae26bfSKyle McMartin default: 78deae26bfSKyle McMartin ret = -ENOSYS; 79deae26bfSKyle McMartin } 80deae26bfSKyle McMartin 81*99aed91aSJohn David Anglin if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0)) 82*99aed91aSJohn David Anglin ret = -EFAULT; 83*99aed91aSJohn David Anglin 84*99aed91aSJohn David Anglin out_pagefault_enable: 85*99aed91aSJohn David Anglin pagefault_enable(); 868b232816SJohn David Anglin _futex_spin_unlock_irqrestore(uaddr, &flags); 87d9ba5fe7SCarlos O'Donell 88*99aed91aSJohn David Anglin if (ret == 0) { 89deae26bfSKyle McMartin switch (cmp) { 90deae26bfSKyle McMartin case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; 91deae26bfSKyle McMartin case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; 92deae26bfSKyle McMartin case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; 93deae26bfSKyle McMartin case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; 94deae26bfSKyle McMartin case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; 95deae26bfSKyle McMartin case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; 96deae26bfSKyle McMartin default: ret = -ENOSYS; 97deae26bfSKyle McMartin } 98deae26bfSKyle McMartin } 99deae26bfSKyle McMartin return ret; 100deae26bfSKyle McMartin } 101deae26bfSKyle McMartin 102deae26bfSKyle McMartin static inline int 1038d7718aaSMichel Lespinasse futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, 1048d7718aaSMichel Lespinasse u32 oldval, u32 newval) 105deae26bfSKyle McMartin { 1068d7718aaSMichel Lespinasse u32 val; 107d9ba5fe7SCarlos O'Donell unsigned long flags; 108deae26bfSKyle McMartin 109deae26bfSKyle McMartin /* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is 110deae26bfSKyle McMartin * our gateway page, and causes no end of trouble... 111deae26bfSKyle McMartin */ 112deae26bfSKyle McMartin if (segment_eq(KERNEL_DS, get_fs()) && !uaddr) 113deae26bfSKyle McMartin return -EFAULT; 114deae26bfSKyle McMartin 1158d7718aaSMichel Lespinasse if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) 116deae26bfSKyle McMartin return -EFAULT; 117deae26bfSKyle McMartin 118d9ba5fe7SCarlos O'Donell /* HPPA has no cmpxchg in hardware and therefore the 119d9ba5fe7SCarlos O'Donell * best we can do here is use an array of locks. The 120d9ba5fe7SCarlos O'Donell * lock selected is based on a hash of the userspace 121d9ba5fe7SCarlos O'Donell * address. This should scale to a couple of CPUs. 122d9ba5fe7SCarlos O'Donell */ 123d9ba5fe7SCarlos O'Donell 1248b232816SJohn David Anglin _futex_spin_lock_irqsave(uaddr, &flags); 125*99aed91aSJohn David Anglin if (unlikely(get_user(val, uaddr) != 0)) { 126*99aed91aSJohn David Anglin _futex_spin_unlock_irqrestore(uaddr, &flags); 127*99aed91aSJohn David Anglin return -EFAULT; 128*99aed91aSJohn David Anglin } 129d9ba5fe7SCarlos O'Donell 130*99aed91aSJohn David Anglin if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) { 131*99aed91aSJohn David Anglin _futex_spin_unlock_irqrestore(uaddr, &flags); 132*99aed91aSJohn David Anglin return -EFAULT; 133*99aed91aSJohn David Anglin } 134d9ba5fe7SCarlos O'Donell 13537a9d912SMichel Lespinasse *uval = val; 1368b232816SJohn David Anglin _futex_spin_unlock_irqrestore(uaddr, &flags); 137d9ba5fe7SCarlos O'Donell 138*99aed91aSJohn David Anglin return 0; 139deae26bfSKyle McMartin } 140deae26bfSKyle McMartin 141deae26bfSKyle McMartin #endif /*__KERNEL__*/ 142deae26bfSKyle McMartin #endif /*_ASM_PARISC_FUTEX_H*/ 143