1fd3db0a6SMichal Simek #ifndef _ASM_MICROBLAZE_FUTEX_H 2fd3db0a6SMichal Simek #define _ASM_MICROBLAZE_FUTEX_H 3fd3db0a6SMichal Simek 4fd3db0a6SMichal Simek #ifdef __KERNEL__ 5fd3db0a6SMichal Simek 6fd3db0a6SMichal Simek #include <linux/futex.h> 7fd3db0a6SMichal Simek #include <linux/uaccess.h> 8fd3db0a6SMichal Simek #include <asm/errno.h> 9fd3db0a6SMichal Simek 10fd3db0a6SMichal Simek #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ 11fd3db0a6SMichal Simek ({ \ 12fd3db0a6SMichal Simek __asm__ __volatile__ ( \ 13fd3db0a6SMichal Simek "1: lwx %0, %2, r0; " \ 14fd3db0a6SMichal Simek insn \ 15fd3db0a6SMichal Simek "2: swx %1, %2, r0; \ 16fd3db0a6SMichal Simek addic %1, r0, 0; \ 17fd3db0a6SMichal Simek bnei %1, 1b; \ 18fd3db0a6SMichal Simek 3: \ 19fd3db0a6SMichal Simek .section .fixup,\"ax\"; \ 20fd3db0a6SMichal Simek 4: brid 3b; \ 21fd3db0a6SMichal Simek addik %1, r0, %3; \ 22fd3db0a6SMichal Simek .previous; \ 23fd3db0a6SMichal Simek .section __ex_table,\"a\"; \ 24fd3db0a6SMichal Simek .word 1b,4b,2b,4b; \ 25fd3db0a6SMichal Simek .previous;" \ 26fd3db0a6SMichal Simek : "=&r" (oldval), "=&r" (ret) \ 278cf662edSMichal Simek : "r" (uaddr), "i" (-EFAULT), "r" (oparg) \ 28fd3db0a6SMichal Simek ); \ 29fd3db0a6SMichal Simek }) 30fd3db0a6SMichal Simek 31fd3db0a6SMichal Simek static inline int 328d7718aaSMichel Lespinasse futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) 33fd3db0a6SMichal Simek { 34fd3db0a6SMichal Simek int op = (encoded_op >> 28) & 7; 35fd3db0a6SMichal Simek int cmp = (encoded_op >> 24) & 15; 36fd3db0a6SMichal Simek int oparg = (encoded_op << 8) >> 20; 37fd3db0a6SMichal Simek int cmparg = (encoded_op << 20) >> 20; 38fd3db0a6SMichal Simek int oldval = 0, ret; 39fd3db0a6SMichal Simek if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) 40fd3db0a6SMichal Simek oparg = 1 << oparg; 41fd3db0a6SMichal Simek 428d7718aaSMichel Lespinasse if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) 43fd3db0a6SMichal Simek return -EFAULT; 44fd3db0a6SMichal Simek 45fd3db0a6SMichal Simek pagefault_disable(); 46fd3db0a6SMichal Simek 47fd3db0a6SMichal Simek switch (op) { 48fd3db0a6SMichal Simek case FUTEX_OP_SET: 49fd3db0a6SMichal Simek __futex_atomic_op("or %1,%4,%4;", ret, oldval, uaddr, oparg); 50fd3db0a6SMichal Simek break; 51fd3db0a6SMichal Simek case FUTEX_OP_ADD: 52fd3db0a6SMichal Simek __futex_atomic_op("add %1,%0,%4;", ret, oldval, uaddr, oparg); 53fd3db0a6SMichal Simek break; 54fd3db0a6SMichal Simek case FUTEX_OP_OR: 55fd3db0a6SMichal Simek __futex_atomic_op("or %1,%0,%4;", ret, oldval, uaddr, oparg); 56fd3db0a6SMichal Simek break; 57fd3db0a6SMichal Simek case FUTEX_OP_ANDN: 584bb30baaSMichal Simek __futex_atomic_op("andn %1,%0,%4;", ret, oldval, uaddr, oparg); 59fd3db0a6SMichal Simek break; 60fd3db0a6SMichal Simek case FUTEX_OP_XOR: 61fd3db0a6SMichal Simek __futex_atomic_op("xor %1,%0,%4;", ret, oldval, uaddr, oparg); 62fd3db0a6SMichal Simek break; 63fd3db0a6SMichal Simek default: 64fd3db0a6SMichal Simek ret = -ENOSYS; 65fd3db0a6SMichal Simek } 66fd3db0a6SMichal Simek 67fd3db0a6SMichal Simek pagefault_enable(); 68fd3db0a6SMichal Simek 69fd3db0a6SMichal Simek if (!ret) { 70fd3db0a6SMichal Simek switch (cmp) { 71fd3db0a6SMichal Simek case FUTEX_OP_CMP_EQ: 72fd3db0a6SMichal Simek ret = (oldval == cmparg); 73fd3db0a6SMichal Simek break; 74fd3db0a6SMichal Simek case FUTEX_OP_CMP_NE: 75fd3db0a6SMichal Simek ret = (oldval != cmparg); 76fd3db0a6SMichal Simek break; 77fd3db0a6SMichal Simek case FUTEX_OP_CMP_LT: 78fd3db0a6SMichal Simek ret = (oldval < cmparg); 79fd3db0a6SMichal Simek break; 80fd3db0a6SMichal Simek case FUTEX_OP_CMP_GE: 81fd3db0a6SMichal Simek ret = (oldval >= cmparg); 82fd3db0a6SMichal Simek break; 83fd3db0a6SMichal Simek case FUTEX_OP_CMP_LE: 84fd3db0a6SMichal Simek ret = (oldval <= cmparg); 85fd3db0a6SMichal Simek break; 86fd3db0a6SMichal Simek case FUTEX_OP_CMP_GT: 87fd3db0a6SMichal Simek ret = (oldval > cmparg); 88fd3db0a6SMichal Simek break; 89fd3db0a6SMichal Simek default: 90fd3db0a6SMichal Simek ret = -ENOSYS; 91fd3db0a6SMichal Simek } 92fd3db0a6SMichal Simek } 93fd3db0a6SMichal Simek return ret; 94fd3db0a6SMichal Simek } 95fd3db0a6SMichal Simek 96fd3db0a6SMichal Simek static inline int 978d7718aaSMichel Lespinasse futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, 988d7718aaSMichel Lespinasse u32 oldval, u32 newval) 99fd3db0a6SMichal Simek { 1008d7718aaSMichel Lespinasse int ret = 0, cmp; 1018d7718aaSMichel Lespinasse u32 prev; 102fd3db0a6SMichal Simek 1038d7718aaSMichel Lespinasse if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) 104fd3db0a6SMichal Simek return -EFAULT; 105fd3db0a6SMichal Simek 10637a9d912SMichel Lespinasse __asm__ __volatile__ ("1: lwx %1, %3, r0; \ 10737a9d912SMichel Lespinasse cmp %2, %1, %4; \ 108f6a12a7dSMeyer, Kirk bnei %2, 3f; \ 10937a9d912SMichel Lespinasse 2: swx %5, %3, r0; \ 11037a9d912SMichel Lespinasse addic %2, r0, 0; \ 11137a9d912SMichel Lespinasse bnei %2, 1b; \ 112fd3db0a6SMichal Simek 3: \ 113fd3db0a6SMichal Simek .section .fixup,\"ax\"; \ 114fd3db0a6SMichal Simek 4: brid 3b; \ 11537a9d912SMichel Lespinasse addik %0, r0, %6; \ 116fd3db0a6SMichal Simek .previous; \ 117fd3db0a6SMichal Simek .section __ex_table,\"a\"; \ 118fd3db0a6SMichal Simek .word 1b,4b,2b,4b; \ 119fd3db0a6SMichal Simek .previous;" \ 12037a9d912SMichel Lespinasse : "+r" (ret), "=&r" (prev), "=&r"(cmp) \ 121fd3db0a6SMichal Simek : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT)); 122fd3db0a6SMichal Simek 12337a9d912SMichel Lespinasse *uval = prev; 12437a9d912SMichel Lespinasse return ret; 125fd3db0a6SMichal Simek } 126fd3db0a6SMichal Simek 127fd3db0a6SMichal Simek #endif /* __KERNEL__ */ 128fd3db0a6SMichal Simek 129fd3db0a6SMichal Simek #endif 130