18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi> 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public License 58c2ecf20Sopenharmony_ci * version 2. This program is licensed "as is" without any warranty of any 68c2ecf20Sopenharmony_ci * kind, whether express or implied. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#ifndef __ASM_OPENRISC_ATOMIC_H 108c2ecf20Sopenharmony_ci#define __ASM_OPENRISC_ATOMIC_H 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/types.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* Atomically perform op with v->counter and i */ 158c2ecf20Sopenharmony_ci#define ATOMIC_OP(op) \ 168c2ecf20Sopenharmony_cistatic inline void atomic_##op(int i, atomic_t *v) \ 178c2ecf20Sopenharmony_ci{ \ 188c2ecf20Sopenharmony_ci int tmp; \ 198c2ecf20Sopenharmony_ci \ 208c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 218c2ecf20Sopenharmony_ci "1: l.lwa %0,0(%1) \n" \ 228c2ecf20Sopenharmony_ci " l." #op " %0,%0,%2 \n" \ 238c2ecf20Sopenharmony_ci " l.swa 0(%1),%0 \n" \ 248c2ecf20Sopenharmony_ci " l.bnf 1b \n" \ 258c2ecf20Sopenharmony_ci " l.nop \n" \ 268c2ecf20Sopenharmony_ci : "=&r"(tmp) \ 278c2ecf20Sopenharmony_ci : "r"(&v->counter), "r"(i) \ 288c2ecf20Sopenharmony_ci : "cc", "memory"); \ 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* Atomically perform op with v->counter and i, return the result */ 328c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op) \ 338c2ecf20Sopenharmony_cistatic inline int atomic_##op##_return(int i, atomic_t *v) \ 348c2ecf20Sopenharmony_ci{ \ 358c2ecf20Sopenharmony_ci int tmp; \ 368c2ecf20Sopenharmony_ci \ 378c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 388c2ecf20Sopenharmony_ci "1: l.lwa %0,0(%1) \n" \ 398c2ecf20Sopenharmony_ci " l." #op " %0,%0,%2 \n" \ 408c2ecf20Sopenharmony_ci " l.swa 0(%1),%0 \n" \ 418c2ecf20Sopenharmony_ci " l.bnf 1b \n" \ 428c2ecf20Sopenharmony_ci " l.nop \n" \ 438c2ecf20Sopenharmony_ci : "=&r"(tmp) \ 448c2ecf20Sopenharmony_ci : "r"(&v->counter), "r"(i) \ 458c2ecf20Sopenharmony_ci : "cc", "memory"); \ 468c2ecf20Sopenharmony_ci \ 478c2ecf20Sopenharmony_ci return tmp; \ 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* Atomically perform op with v->counter and i, return orig v->counter */ 518c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op) \ 528c2ecf20Sopenharmony_cistatic inline int atomic_fetch_##op(int i, atomic_t *v) \ 538c2ecf20Sopenharmony_ci{ \ 548c2ecf20Sopenharmony_ci int tmp, old; \ 558c2ecf20Sopenharmony_ci \ 568c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 578c2ecf20Sopenharmony_ci "1: l.lwa %0,0(%2) \n" \ 588c2ecf20Sopenharmony_ci " l." #op " %1,%0,%3 \n" \ 598c2ecf20Sopenharmony_ci " l.swa 0(%2),%1 \n" \ 608c2ecf20Sopenharmony_ci " l.bnf 1b \n" \ 618c2ecf20Sopenharmony_ci " l.nop \n" \ 628c2ecf20Sopenharmony_ci : "=&r"(old), "=&r"(tmp) \ 638c2ecf20Sopenharmony_ci : "r"(&v->counter), "r"(i) \ 648c2ecf20Sopenharmony_ci : "cc", "memory"); \ 658c2ecf20Sopenharmony_ci \ 668c2ecf20Sopenharmony_ci return old; \ 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ciATOMIC_OP_RETURN(add) 708c2ecf20Sopenharmony_ciATOMIC_OP_RETURN(sub) 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(add) 738c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(sub) 748c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(and) 758c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(or) 768c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(xor) 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ciATOMIC_OP(and) 798c2ecf20Sopenharmony_ciATOMIC_OP(or) 808c2ecf20Sopenharmony_ciATOMIC_OP(xor) 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#undef ATOMIC_FETCH_OP 838c2ecf20Sopenharmony_ci#undef ATOMIC_OP_RETURN 848c2ecf20Sopenharmony_ci#undef ATOMIC_OP 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define atomic_add_return atomic_add_return 878c2ecf20Sopenharmony_ci#define atomic_sub_return atomic_sub_return 888c2ecf20Sopenharmony_ci#define atomic_fetch_add atomic_fetch_add 898c2ecf20Sopenharmony_ci#define atomic_fetch_sub atomic_fetch_sub 908c2ecf20Sopenharmony_ci#define atomic_fetch_and atomic_fetch_and 918c2ecf20Sopenharmony_ci#define atomic_fetch_or atomic_fetch_or 928c2ecf20Sopenharmony_ci#define atomic_fetch_xor atomic_fetch_xor 938c2ecf20Sopenharmony_ci#define atomic_and atomic_and 948c2ecf20Sopenharmony_ci#define atomic_or atomic_or 958c2ecf20Sopenharmony_ci#define atomic_xor atomic_xor 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/* 988c2ecf20Sopenharmony_ci * Atomically add a to v->counter as long as v is not already u. 998c2ecf20Sopenharmony_ci * Returns the original value at v->counter. 1008c2ecf20Sopenharmony_ci * 1018c2ecf20Sopenharmony_ci * This is often used through atomic_inc_not_zero() 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_cistatic inline int atomic_fetch_add_unless(atomic_t *v, int a, int u) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci int old, tmp; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci __asm__ __volatile__( 1088c2ecf20Sopenharmony_ci "1: l.lwa %0, 0(%2) \n" 1098c2ecf20Sopenharmony_ci " l.sfeq %0, %4 \n" 1108c2ecf20Sopenharmony_ci " l.bf 2f \n" 1118c2ecf20Sopenharmony_ci " l.add %1, %0, %3 \n" 1128c2ecf20Sopenharmony_ci " l.swa 0(%2), %1 \n" 1138c2ecf20Sopenharmony_ci " l.bnf 1b \n" 1148c2ecf20Sopenharmony_ci " l.nop \n" 1158c2ecf20Sopenharmony_ci "2: \n" 1168c2ecf20Sopenharmony_ci : "=&r"(old), "=&r" (tmp) 1178c2ecf20Sopenharmony_ci : "r"(&v->counter), "r"(a), "r"(u) 1188c2ecf20Sopenharmony_ci : "cc", "memory"); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return old; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci#define atomic_fetch_add_unless atomic_fetch_add_unless 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#include <asm-generic/atomic.h> 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci#endif /* __ASM_OPENRISC_ATOMIC_H */ 127