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
_futex_hash_index(unsigned long ua)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
_futex_spin_lock_irqsave(arch_spinlock_t * s,unsigned long * flags)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
_futex_spin_unlock_irqrestore(arch_spinlock_t * s,unsigned long * flags)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
arch_futex_atomic_op_inuser(int op,int oparg,int * oval,u32 __user * uaddr)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
futex_atomic_cmpxchg_inatomic(u32 * uval,u32 __user * uaddr,u32 oldval,u32 newval)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
9996d4f267SLinus Torvalds if (!access_ok(uaddr, sizeof(u32)))
100deae26bfSKyle McMartin return -EFAULT;
101deae26bfSKyle McMartin
102d9ba5fe7SCarlos O'Donell /* HPPA has no cmpxchg in hardware and therefore the
103d9ba5fe7SCarlos O'Donell * best we can do here is use an array of locks. The
104*d0585d74SJohn David Anglin * lock selected is based on a hash of the virtual
105*d0585d74SJohn David Anglin * address of the futex. This should scale to a couple
106*d0585d74SJohn David Anglin * of CPUs.
107d9ba5fe7SCarlos O'Donell */
108d9ba5fe7SCarlos O'Donell
109*d0585d74SJohn David Anglin s = (arch_spinlock_t *)&lws_lock_start[_futex_hash_index(ua)];
110*d0585d74SJohn David Anglin _futex_spin_lock_irqsave(s, &flags);
11199aed91aSJohn David Anglin if (unlikely(get_user(val, uaddr) != 0)) {
112*d0585d74SJohn David Anglin _futex_spin_unlock_irqrestore(s, &flags);
11399aed91aSJohn David Anglin return -EFAULT;
11499aed91aSJohn David Anglin }
115d9ba5fe7SCarlos O'Donell
11699aed91aSJohn David Anglin if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) {
117*d0585d74SJohn David Anglin _futex_spin_unlock_irqrestore(s, &flags);
11899aed91aSJohn David Anglin return -EFAULT;
11999aed91aSJohn David Anglin }
120d9ba5fe7SCarlos O'Donell
12137a9d912SMichel Lespinasse *uval = val;
122*d0585d74SJohn David Anglin _futex_spin_unlock_irqrestore(s, &flags);
123d9ba5fe7SCarlos O'Donell
12499aed91aSJohn David Anglin return 0;
125deae26bfSKyle McMartin }
126deae26bfSKyle McMartin
127deae26bfSKyle McMartin #endif /*_ASM_PARISC_FUTEX_H*/
128