1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */ 2deae26bfSKyle McMartin #ifndef _ASM_PARISC_FUTEX_H 3deae26bfSKyle McMartin #define _ASM_PARISC_FUTEX_H 4deae26bfSKyle McMartin 5deae26bfSKyle McMartin #include <linux/futex.h> 6deae26bfSKyle McMartin #include <linux/uaccess.h> 7d9ba5fe7SCarlos O'Donell #include <asm/atomic.h> 8deae26bfSKyle McMartin #include <asm/errno.h> 9deae26bfSKyle McMartin 108b232816SJohn David Anglin /* The following has to match the LWS code in syscall.S. We have 11*d0585d74SJohn David Anglin * 256 four-word locks. We use bits 20-27 of the futex virtual 12*d0585d74SJohn David Anglin * address for the hash index. 13*d0585d74SJohn David Anglin */ 14*d0585d74SJohn David Anglin 15*d0585d74SJohn David Anglin static inline unsigned long _futex_hash_index(unsigned long ua) 16*d0585d74SJohn David Anglin { 17*d0585d74SJohn David Anglin return (ua >> 2) & 0x3fc; 18*d0585d74SJohn David Anglin } 198b232816SJohn David Anglin 208b232816SJohn David Anglin static inline void 21*d0585d74SJohn David Anglin _futex_spin_lock_irqsave(arch_spinlock_t *s, unsigned long *flags) 228b232816SJohn David Anglin { 23*d0585d74SJohn David Anglin local_irq_save(*flags); 248b232816SJohn David Anglin arch_spin_lock(s); 258b232816SJohn David Anglin } 268b232816SJohn David Anglin 278b232816SJohn David Anglin static inline void 28*d0585d74SJohn David Anglin _futex_spin_unlock_irqrestore(arch_spinlock_t *s, unsigned long *flags) 298b232816SJohn David Anglin { 308b232816SJohn David Anglin arch_spin_unlock(s); 31*d0585d74SJohn David Anglin local_irq_restore(*flags); 328b232816SJohn David Anglin } 338b232816SJohn David Anglin 34deae26bfSKyle McMartin static inline int 3530d6e0a4SJiri Slaby arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) 36deae26bfSKyle McMartin { 37*d0585d74SJohn David Anglin extern u32 lws_lock_start[]; 38*d0585d74SJohn David Anglin unsigned long ua = (unsigned long)uaddr; 39*d0585d74SJohn David Anglin arch_spinlock_t *s; 40*d0585d74SJohn David Anglin unsigned long flags; 4199aed91aSJohn David Anglin int oldval, ret; 4299aed91aSJohn David Anglin u32 tmp; 4399aed91aSJohn David Anglin 44*d0585d74SJohn David Anglin s = (arch_spinlock_t *)&lws_lock_start[_futex_hash_index(ua)]; 45*d0585d74SJohn David Anglin _futex_spin_lock_irqsave(s, &flags); 467e992711SDave Anglin 47*d0585d74SJohn David Anglin /* Return -EFAULT if we encounter a page fault or COW break */ 48*d0585d74SJohn David Anglin if (unlikely(get_user(oldval, uaddr) != 0)) { 49*d0585d74SJohn David Anglin ret = -EFAULT; 5099aed91aSJohn David Anglin goto out_pagefault_enable; 51*d0585d74SJohn David Anglin } 5299aed91aSJohn David Anglin 5399aed91aSJohn David Anglin ret = 0; 5499aed91aSJohn David Anglin tmp = oldval; 55d9ba5fe7SCarlos O'Donell 56deae26bfSKyle McMartin switch (op) { 57deae26bfSKyle McMartin case FUTEX_OP_SET: 5899aed91aSJohn David Anglin tmp = oparg; 59d9ba5fe7SCarlos O'Donell break; 60deae26bfSKyle McMartin case FUTEX_OP_ADD: 6199aed91aSJohn David Anglin tmp += oparg; 62d9ba5fe7SCarlos O'Donell break; 63deae26bfSKyle McMartin case FUTEX_OP_OR: 6499aed91aSJohn David Anglin tmp |= oparg; 65d9ba5fe7SCarlos O'Donell break; 66deae26bfSKyle McMartin case FUTEX_OP_ANDN: 6799aed91aSJohn David Anglin tmp &= ~oparg; 68d9ba5fe7SCarlos O'Donell break; 69deae26bfSKyle McMartin case FUTEX_OP_XOR: 7099aed91aSJohn David Anglin tmp ^= oparg; 71d9ba5fe7SCarlos O'Donell break; 72deae26bfSKyle McMartin default: 73deae26bfSKyle McMartin ret = -ENOSYS; 74*d0585d74SJohn David Anglin goto out_pagefault_enable; 75deae26bfSKyle McMartin } 76deae26bfSKyle McMartin 77*d0585d74SJohn David Anglin if (unlikely(put_user(tmp, uaddr) != 0)) 7899aed91aSJohn David Anglin ret = -EFAULT; 7999aed91aSJohn David Anglin 8099aed91aSJohn David Anglin out_pagefault_enable: 81*d0585d74SJohn David Anglin _futex_spin_unlock_irqrestore(s, &flags); 82d9ba5fe7SCarlos O'Donell 8330d6e0a4SJiri Slaby if (!ret) 8430d6e0a4SJiri Slaby *oval = oldval; 8530d6e0a4SJiri Slaby 86deae26bfSKyle McMartin return ret; 87deae26bfSKyle McMartin } 88deae26bfSKyle McMartin 89deae26bfSKyle McMartin static inline int 908d7718aaSMichel Lespinasse futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, 918d7718aaSMichel Lespinasse u32 oldval, u32 newval) 92deae26bfSKyle McMartin { 93*d0585d74SJohn David Anglin extern u32 lws_lock_start[]; 94*d0585d74SJohn David Anglin unsigned long ua = (unsigned long)uaddr; 95*d0585d74SJohn David Anglin arch_spinlock_t *s; 968d7718aaSMichel Lespinasse u32 val; 97*d0585d74SJohn David Anglin unsigned long flags; 98deae26bfSKyle McMartin 99deae26bfSKyle McMartin /* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is 100deae26bfSKyle McMartin * our gateway page, and causes no end of trouble... 101deae26bfSKyle McMartin */ 102db68ce10SAl Viro if (uaccess_kernel() && !uaddr) 103deae26bfSKyle McMartin return -EFAULT; 104deae26bfSKyle McMartin 10596d4f267SLinus Torvalds if (!access_ok(uaddr, sizeof(u32))) 106deae26bfSKyle McMartin return -EFAULT; 107deae26bfSKyle McMartin 108d9ba5fe7SCarlos O'Donell /* HPPA has no cmpxchg in hardware and therefore the 109d9ba5fe7SCarlos O'Donell * best we can do here is use an array of locks. The 110*d0585d74SJohn David Anglin * lock selected is based on a hash of the virtual 111*d0585d74SJohn David Anglin * address of the futex. This should scale to a couple 112*d0585d74SJohn David Anglin * of CPUs. 113d9ba5fe7SCarlos O'Donell */ 114d9ba5fe7SCarlos O'Donell 115*d0585d74SJohn David Anglin s = (arch_spinlock_t *)&lws_lock_start[_futex_hash_index(ua)]; 116*d0585d74SJohn David Anglin _futex_spin_lock_irqsave(s, &flags); 11799aed91aSJohn David Anglin if (unlikely(get_user(val, uaddr) != 0)) { 118*d0585d74SJohn David Anglin _futex_spin_unlock_irqrestore(s, &flags); 11999aed91aSJohn David Anglin return -EFAULT; 12099aed91aSJohn David Anglin } 121d9ba5fe7SCarlos O'Donell 12299aed91aSJohn David Anglin if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) { 123*d0585d74SJohn David Anglin _futex_spin_unlock_irqrestore(s, &flags); 12499aed91aSJohn David Anglin return -EFAULT; 12599aed91aSJohn David Anglin } 126d9ba5fe7SCarlos O'Donell 12737a9d912SMichel Lespinasse *uval = val; 128*d0585d74SJohn David Anglin _futex_spin_unlock_irqrestore(s, &flags); 129d9ba5fe7SCarlos O'Donell 13099aed91aSJohn David Anglin return 0; 131deae26bfSKyle McMartin } 132deae26bfSKyle McMartin 133deae26bfSKyle McMartin #endif /*_ASM_PARISC_FUTEX_H*/ 134