1/* 2 * Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi> 3 * 4 * This file is licensed under the terms of the GNU General Public License 5 * version 2. This program is licensed "as is" without any warranty of any 6 * kind, whether express or implied. 7 */ 8 9#ifndef __ASM_OPENRISC_ATOMIC_H 10#define __ASM_OPENRISC_ATOMIC_H 11 12#include <linux/types.h> 13 14/* Atomically perform op with v->counter and i */ 15#define ATOMIC_OP(op) \ 16static inline void atomic_##op(int i, atomic_t *v) \ 17{ \ 18 int tmp; \ 19 \ 20 __asm__ __volatile__( \ 21 "1: l.lwa %0,0(%1) \n" \ 22 " l." #op " %0,%0,%2 \n" \ 23 " l.swa 0(%1),%0 \n" \ 24 " l.bnf 1b \n" \ 25 " l.nop \n" \ 26 : "=&r"(tmp) \ 27 : "r"(&v->counter), "r"(i) \ 28 : "cc", "memory"); \ 29} 30 31/* Atomically perform op with v->counter and i, return the result */ 32#define ATOMIC_OP_RETURN(op) \ 33static inline int atomic_##op##_return(int i, atomic_t *v) \ 34{ \ 35 int tmp; \ 36 \ 37 __asm__ __volatile__( \ 38 "1: l.lwa %0,0(%1) \n" \ 39 " l." #op " %0,%0,%2 \n" \ 40 " l.swa 0(%1),%0 \n" \ 41 " l.bnf 1b \n" \ 42 " l.nop \n" \ 43 : "=&r"(tmp) \ 44 : "r"(&v->counter), "r"(i) \ 45 : "cc", "memory"); \ 46 \ 47 return tmp; \ 48} 49 50/* Atomically perform op with v->counter and i, return orig v->counter */ 51#define ATOMIC_FETCH_OP(op) \ 52static inline int atomic_fetch_##op(int i, atomic_t *v) \ 53{ \ 54 int tmp, old; \ 55 \ 56 __asm__ __volatile__( \ 57 "1: l.lwa %0,0(%2) \n" \ 58 " l." #op " %1,%0,%3 \n" \ 59 " l.swa 0(%2),%1 \n" \ 60 " l.bnf 1b \n" \ 61 " l.nop \n" \ 62 : "=&r"(old), "=&r"(tmp) \ 63 : "r"(&v->counter), "r"(i) \ 64 : "cc", "memory"); \ 65 \ 66 return old; \ 67} 68 69ATOMIC_OP_RETURN(add) 70ATOMIC_OP_RETURN(sub) 71 72ATOMIC_FETCH_OP(add) 73ATOMIC_FETCH_OP(sub) 74ATOMIC_FETCH_OP(and) 75ATOMIC_FETCH_OP(or) 76ATOMIC_FETCH_OP(xor) 77 78ATOMIC_OP(and) 79ATOMIC_OP(or) 80ATOMIC_OP(xor) 81 82#undef ATOMIC_FETCH_OP 83#undef ATOMIC_OP_RETURN 84#undef ATOMIC_OP 85 86#define atomic_add_return atomic_add_return 87#define atomic_sub_return atomic_sub_return 88#define atomic_fetch_add atomic_fetch_add 89#define atomic_fetch_sub atomic_fetch_sub 90#define atomic_fetch_and atomic_fetch_and 91#define atomic_fetch_or atomic_fetch_or 92#define atomic_fetch_xor atomic_fetch_xor 93#define atomic_and atomic_and 94#define atomic_or atomic_or 95#define atomic_xor atomic_xor 96 97/* 98 * Atomically add a to v->counter as long as v is not already u. 99 * Returns the original value at v->counter. 100 * 101 * This is often used through atomic_inc_not_zero() 102 */ 103static inline int atomic_fetch_add_unless(atomic_t *v, int a, int u) 104{ 105 int old, tmp; 106 107 __asm__ __volatile__( 108 "1: l.lwa %0, 0(%2) \n" 109 " l.sfeq %0, %4 \n" 110 " l.bf 2f \n" 111 " l.add %1, %0, %3 \n" 112 " l.swa 0(%2), %1 \n" 113 " l.bnf 1b \n" 114 " l.nop \n" 115 "2: \n" 116 : "=&r"(old), "=&r" (tmp) 117 : "r"(&v->counter), "r"(a), "r"(u) 118 : "cc", "memory"); 119 120 return old; 121} 122#define atomic_fetch_add_unless atomic_fetch_add_unless 123 124#include <asm-generic/atomic.h> 125 126#endif /* __ASM_OPENRISC_ATOMIC_H */ 127