atomic.h revision 165786
1129198Scognet/* $NetBSD: atomic.h,v 1.1 2002/10/19 12:22:34 bsh Exp $ */ 2129198Scognet 3139735Simp/*- 4129198Scognet * Copyright (C) 2003-2004 Olivier Houchard 5129198Scognet * Copyright (C) 1994-1997 Mark Brinicombe 6129198Scognet * Copyright (C) 1994 Brini 7129198Scognet * All rights reserved. 8129198Scognet * 9129198Scognet * This code is derived from software written for Brini by Mark Brinicombe 10129198Scognet * 11129198Scognet * Redistribution and use in source and binary forms, with or without 12129198Scognet * modification, are permitted provided that the following conditions 13129198Scognet * are met: 14129198Scognet * 1. Redistributions of source code must retain the above copyright 15129198Scognet * notice, this list of conditions and the following disclaimer. 16129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 17129198Scognet * notice, this list of conditions and the following disclaimer in the 18129198Scognet * documentation and/or other materials provided with the distribution. 19129198Scognet * 3. All advertising materials mentioning features or use of this software 20129198Scognet * must display the following acknowledgement: 21129198Scognet * This product includes software developed by Brini. 22129198Scognet * 4. The name of Brini may not be used to endorse or promote products 23129198Scognet * derived from this software without specific prior written permission. 24129198Scognet * 25129198Scognet * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR 26129198Scognet * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27129198Scognet * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28129198Scognet * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29129198Scognet * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30129198Scognet * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 31129198Scognet * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 32129198Scognet * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 33129198Scognet * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 34129198Scognet * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35129198Scognet * 36129198Scognet * $FreeBSD: head/sys/arm/include/atomic.h 165786 2007-01-05 02:50:27Z ticso $ 37129198Scognet */ 38129198Scognet 39129198Scognet#ifndef _MACHINE_ATOMIC_H_ 40129198Scognet#define _MACHINE_ATOMIC_H_ 41129198Scognet 42129198Scognet 43129198Scognet 44129198Scognet#ifndef _LOCORE 45129198Scognet 46129198Scognet#include <sys/types.h> 47129198Scognet 48129198Scognet#ifndef I32_bit 49129198Scognet#define I32_bit (1 << 7) /* IRQ disable */ 50129198Scognet#endif 51129198Scognet#ifndef F32_bit 52129198Scognet#define F32_bit (1 << 6) /* FIQ disable */ 53129198Scognet#endif 54129198Scognet 55129198Scognet#define __with_interrupts_disabled(expr) \ 56129198Scognet do { \ 57129198Scognet u_int cpsr_save, tmp; \ 58129198Scognet \ 59129198Scognet __asm __volatile( \ 60129198Scognet "mrs %0, cpsr;" \ 61129198Scognet "orr %1, %0, %2;" \ 62129198Scognet "msr cpsr_all, %1;" \ 63129198Scognet : "=r" (cpsr_save), "=r" (tmp) \ 64157725Scognet : "I" (I32_bit | F32_bit) \ 65129198Scognet : "cc" ); \ 66129198Scognet (expr); \ 67129198Scognet __asm __volatile( \ 68129198Scognet "msr cpsr_all, %0" \ 69129198Scognet : /* no output */ \ 70129198Scognet : "r" (cpsr_save) \ 71129198Scognet : "cc" ); \ 72129198Scognet } while(0) 73129198Scognet 74144761Scognet#define ARM_RAS_START 0xe0000004 75144761Scognet#define ARM_RAS_END 0xe0000008 76144761Scognet 77137222Scognetstatic __inline uint32_t 78137222Scognet__swp(uint32_t val, volatile uint32_t *ptr) 79129198Scognet{ 80148453Sjhb __asm __volatile("swp %0, %2, [%3]" 81148453Sjhb : "=&r" (val), "=m" (*ptr) 82151340Sjhb : "r" (val), "r" (ptr), "m" (*ptr) 83148453Sjhb : "memory"); 84137222Scognet return (val); 85129198Scognet} 86129198Scognet 87137222Scognet 88144761Scognet#ifdef _KERNEL 89129198Scognetstatic __inline void 90137222Scognetatomic_set_32(volatile uint32_t *address, uint32_t setmask) 91129198Scognet{ 92144761Scognet __with_interrupts_disabled(*address |= setmask); 93129198Scognet} 94129198Scognet 95129198Scognetstatic __inline void 96129198Scognetatomic_clear_32(volatile uint32_t *address, uint32_t clearmask) 97129198Scognet{ 98144761Scognet __with_interrupts_disabled(*address &= ~clearmask); 99129198Scognet} 100129198Scognet 101144761Scognetstatic __inline u_int32_t 102144761Scognetatomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval) 103129198Scognet{ 104144761Scognet int ret; 105144761Scognet 106144761Scognet __with_interrupts_disabled( 107144761Scognet { 108144761Scognet if (*p == cmpval) { 109144761Scognet *p = newval; 110144761Scognet ret = 1; 111144761Scognet } else { 112144761Scognet ret = 0; 113144761Scognet } 114144761Scognet }); 115144761Scognet return (ret); 116129198Scognet} 117129198Scognet 118129198Scognetstatic __inline void 119144761Scognetatomic_add_32(volatile u_int32_t *p, u_int32_t val) 120129198Scognet{ 121144761Scognet __with_interrupts_disabled(*p += val); 122129198Scognet} 123129198Scognet 124144761Scognetstatic __inline void 125144761Scognetatomic_subtract_32(volatile u_int32_t *p, u_int32_t val) 126129198Scognet{ 127144761Scognet __with_interrupts_disabled(*p -= val); 128129198Scognet} 129129198Scognet 130150627Sjhbstatic __inline uint32_t 131150627Sjhbatomic_fetchadd_32(volatile uint32_t *p, uint32_t v) 132150627Sjhb{ 133150627Sjhb uint32_t value; 134150627Sjhb 135150627Sjhb __with_interrupts_disabled( 136150627Sjhb { 137150627Sjhb value = *p; 138150627Sjhb *p += v; 139150627Sjhb }); 140150627Sjhb return (value); 141150627Sjhb} 142150627Sjhb 143144761Scognet#else /* !_KERNEL */ 144144761Scognet 145129198Scognetstatic __inline u_int32_t 146144761Scognetatomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval) 147129198Scognet{ 148144761Scognet register int done, ras_start; 149144761Scognet 150144761Scognet __asm __volatile("1:\n" 151144761Scognet "mov %0, #0xe0000008\n" 152144761Scognet "adr %1, 2f\n" 153144761Scognet "str %1, [%0]\n" 154144761Scognet "adr %1, 1b\n" 155144761Scognet "mov %0, #0xe0000004\n" 156144761Scognet "str %1, [%0]\n" 157155355Scognet "ldr %1, [%2]\n" 158144761Scognet "cmp %1, %3\n" 159155355Scognet "streq %4, [%2]\n" 160144761Scognet "2:\n" 161146591Scognet "mov %1, #0\n" 162146591Scognet "str %1, [%0]\n" 163144761Scognet "moveq %1, #1\n" 164144761Scognet "movne %1, #0\n" 165144761Scognet : "=r" (ras_start), "=r" (done) 166155391Scognet ,"+r" (p), "+r" (cmpval), "+r" (newval) : : "memory"); 167137282Scognet return (done); 168129198Scognet} 169129198Scognet 170129198Scognetstatic __inline void 171129198Scognetatomic_add_32(volatile u_int32_t *p, u_int32_t val) 172129198Scognet{ 173144761Scognet int ras_start, start; 174144761Scognet 175144761Scognet __asm __volatile("1:\n" 176144761Scognet "mov %0, #0xe0000008\n" 177144761Scognet "adr %1, 2f\n" 178144761Scognet "str %1, [%0]\n" 179144761Scognet "adr %1, 1b\n" 180144761Scognet "mov %0, #0xe0000004\n" 181144761Scognet "str %1, [%0]\n" 182155355Scognet "ldr %1, [%2]\n" 183144761Scognet "add %1, %1, %3\n" 184155355Scognet "str %1, [%2]\n" 185144761Scognet "2:\n" 186146591Scognet "mov %1, #0\n" 187146591Scognet "str %1, [%0]\n" 188155391Scognet : "=r" (ras_start), "=r" (start), "+r" (p), "+r" (val) 189155391Scognet : : "memory"); 190129198Scognet} 191129198Scognet 192129198Scognetstatic __inline void 193129198Scognetatomic_subtract_32(volatile u_int32_t *p, u_int32_t val) 194129198Scognet{ 195144761Scognet int ras_start, start; 196144761Scognet 197144761Scognet __asm __volatile("1:\n" 198144761Scognet "mov %0, #0xe0000008\n" 199144761Scognet "adr %1, 2f\n" 200144761Scognet "str %1, [%0]\n" 201144761Scognet "adr %1, 1b\n" 202144761Scognet "mov %0, #0xe0000004\n" 203144761Scognet "str %1, [%0]\n" 204155355Scognet "ldr %1, [%2]\n" 205144761Scognet "sub %1, %1, %3\n" 206155355Scognet "str %1, [%2]\n" 207144761Scognet "2:\n" 208146591Scognet "mov %1, #0\n" 209146591Scognet "str %1, [%0]\n" 210146591Scognet 211155391Scognet : "=r" (ras_start), "=r" (start), "+r" (p), "+r" (val) 212155391Scognet : : "memory"); 213129198Scognet} 214129198Scognet 215144761Scognetstatic __inline void 216144761Scognetatomic_set_32(volatile uint32_t *address, uint32_t setmask) 217144761Scognet{ 218144761Scognet int ras_start, start; 219144761Scognet 220144761Scognet __asm __volatile("1:\n" 221144761Scognet "mov %0, #0xe0000008\n" 222144761Scognet "adr %1, 2f\n" 223144761Scognet "str %1, [%0]\n" 224144761Scognet "adr %1, 1b\n" 225144761Scognet "mov %0, #0xe0000004\n" 226144761Scognet "str %1, [%0]\n" 227155355Scognet "ldr %1, [%2]\n" 228144761Scognet "orr %1, %1, %3\n" 229155355Scognet "str %1, [%2]\n" 230144761Scognet "2:\n" 231146591Scognet "mov %1, #0\n" 232146591Scognet "str %1, [%0]\n" 233146591Scognet 234155391Scognet : "=r" (ras_start), "=r" (start), "+r" (address), "+r" (setmask) 235155391Scognet : : "memory"); 236144761Scognet} 237144761Scognet 238144761Scognetstatic __inline void 239144761Scognetatomic_clear_32(volatile uint32_t *address, uint32_t clearmask) 240144761Scognet{ 241144761Scognet int ras_start, start; 242144761Scognet 243144761Scognet __asm __volatile("1:\n" 244144761Scognet "mov %0, #0xe0000008\n" 245144761Scognet "adr %1, 2f\n" 246144761Scognet "str %1, [%0]\n" 247144761Scognet "adr %1, 1b\n" 248144761Scognet "mov %0, #0xe0000004\n" 249144761Scognet "str %1, [%0]\n" 250155355Scognet "ldr %1, [%2]\n" 251144761Scognet "bic %1, %1, %3\n" 252155355Scognet "str %1, [%2]\n" 253144761Scognet "2:\n" 254146591Scognet "mov %1, #0\n" 255146591Scognet "str %1, [%0]\n" 256155391Scognet : "=r" (ras_start), "=r" (start), "+r" (address), "+r" (clearmask) 257155391Scognet : : "memory"); 258144761Scognet 259144761Scognet} 260150627Sjhb 261150627Sjhbstatic __inline uint32_t 262150627Sjhbatomic_fetchadd_32(volatile uint32_t *p, uint32_t v) 263150627Sjhb{ 264150627Sjhb uint32_t ras_start, start; 265150627Sjhb 266150627Sjhb __asm __volatile("1:\n" 267150627Sjhb "mov %0, #0xe0000008\n" 268150627Sjhb "adr %1, 2f\n" 269150627Sjhb "str %1, [%0]\n" 270150627Sjhb "adr %1, 1b\n" 271150627Sjhb "mov %0, #0xe0000004\n" 272150627Sjhb "str %1, [%0]\n" 273155355Scognet "ldr %1, [%2]\n" 274150627Sjhb "add %3, %1, %3\n" 275155355Scognet "str %3, [%2]\n" 276150627Sjhb "2:\n" 277150627Sjhb "mov %3, #0\n" 278150627Sjhb "str %3, [%0]\n" 279155391Scognet : "=r" (ras_start), "=r" (start), "+r" (p), "+r" (v) 280155391Scognet : : "memory"); 281150627Sjhb return (start); 282150627Sjhb} 283150627Sjhb 284150627Sjhb 285144761Scognet#endif /* _KERNEL */ 286144761Scognet 287144761Scognetstatic __inline int 288144761Scognetatomic_load_32(volatile uint32_t *v) 289144761Scognet{ 290144761Scognet 291144761Scognet return (*v); 292144761Scognet} 293144761Scognet 294144761Scognetstatic __inline void 295144761Scognetatomic_store_32(volatile uint32_t *dst, uint32_t src) 296144761Scognet{ 297144761Scognet *dst = src; 298144761Scognet} 299144761Scognet 300144761Scognetstatic __inline uint32_t 301144761Scognetatomic_readandclear_32(volatile u_int32_t *p) 302144761Scognet{ 303144761Scognet 304144761Scognet return (__swp(0, p)); 305144761Scognet} 306144761Scognet 307137222Scognet#undef __with_interrupts_disabled 308129198Scognet 309137222Scognet#endif /* _LOCORE */ 310129198Scognet 311165786Sticso#define atomic_add_long(p, v) \ 312165786Sticso atomic_add_32((volatile u_int *)(p), (u_int)(v)) 313165786Sticso#define atomic_add_acq_long atomic_add_long 314165786Sticso#define atomic_add_rel_long atomic_add_long 315165786Sticso#define atomic_subtract_long(p, v) \ 316165786Sticso atomic_subtract_32((volatile u_int *)(p), (u_int)(v)) 317165786Sticso#define atomic_subtract_acq_long atomic_subtract_long 318165786Sticso#define atomic_subtract_rel_long atomic_subtract_long 319165786Sticso#define atomic_clear_long(p, v) \ 320165786Sticso atomic_clear_32((volatile u_int *)(p), (u_int)(v)) 321165786Sticso#define atomic_clear_acq_long atomic_clear_long 322165786Sticso#define atomic_clear_rel_long atomic_clear_long 323165786Sticso#define atomic_set_long(p, v) \ 324165786Sticso atomic_set_32((volatile u_int *)(p), (u_int)(v)) 325165786Sticso#define atomic_set_acq_long atomic_set_long 326165786Sticso#define atomic_set_rel_long atomic_set_long 327165786Sticso#define atomic_cmpset_long(dst, old, new) \ 328165786Sticso atomic_cmpset_32((volatile u_int *)(dst), (u_int)(old), (u_int)(new)) 329165786Sticso#define atomic_cmpset_acq_long atomic_cmpset_long 330165786Sticso#define atomic_cmpset_rel_long atomic_cmpset_long 331165786Sticso#define atomic_fetchadd_long(p, v) \ 332165786Sticso atomic_fetchadd_32((volatile u_int *)(p), (u_int)(v)) 333165786Sticso#define atomic_readandclear_long(p) \ 334165786Sticso atomic_readandclear_long((volatile u_int *)(p)) 335165786Sticso#define atomic_load_long(p) \ 336165786Sticso atomic_load_32((volatile u_int *)(p)) 337165786Sticso#define atomic_load_acq_long atomic_load_long 338165786Sticso#define atomic_store_rel_long(p, v) \ 339165786Sticso atomic_store_rel_32((volatile u_int *)(p), (u_int)(v)) 340129198Scognet 341153276Scognet 342165786Sticso#define atomic_clear_ptr atomic_clear_32 343165786Sticso#define atomic_set_ptr atomic_set_32 344165786Sticso#define atomic_cmpset_ptr atomic_cmpset_32 345165786Sticso#define atomic_cmpset_rel_ptr atomic_cmpset_ptr 346165786Sticso#define atomic_cmpset_acq_ptr atomic_cmpset_ptr 347165786Sticso#define atomic_store_ptr atomic_store_32 348165786Sticso#define atomic_store_rel_ptr atomic_store_ptr 349165786Sticso 350165786Sticso#define atomic_add_int atomic_add_32 351165786Sticso#define atomic_add_acq_int atomic_add_int 352165786Sticso#define atomic_add_rel_int atomic_add_int 353165786Sticso#define atomic_subtract_int atomic_subtract_32 354165786Sticso#define atomic_subtract_acq_int atomic_subtract_int 355165786Sticso#define atomic_subtract_rel_int atomic_subtract_int 356165786Sticso#define atomic_clear_int atomic_clear_32 357165786Sticso#define atomic_clear_acq_int atomic_clear_int 358165786Sticso#define atomic_clear_rel_int atomic_clear_int 359137222Scognet#define atomic_set_int atomic_set_32 360165786Sticso#define atomic_set_acq_int atomic_set_int 361165786Sticso#define atomic_set_rel_int atomic_set_int 362165786Sticso#define atomic_cmpset_int atomic_cmpset_32 363165786Sticso#define atomic_cmpset_acq_int atomic_cmpset_int 364165786Sticso#define atomic_cmpset_rel_int atomic_cmpset_int 365165786Sticso#define atomic_fetchadd_int atomic_fetchadd_32 366137222Scognet#define atomic_readandclear_int atomic_readandclear_32 367165786Sticso#define atomic_load_acq_int atomic_load_32 368165786Sticso#define atomic_store_rel_int atomic_store_32 369165786Sticso 370165786Sticso#define atomic_add_acq_32 atomic_add_32 371165786Sticso#define atomic_add_rel_32 atomic_add_32 372165786Sticso#define atomic_subtract_acq_32 atomic_subtract_32 373158593Scognet#define atomic_subtract_rel_32 atomic_subtract_32 374165786Sticso#define atomic_clear_acq_32 atomic_clear_32 375165786Sticso#define atomic_clear_rel_32 atomic_clear_32 376165786Sticso#define atomic_set_acq_32 atomic_set_32 377165786Sticso#define atomic_set_rel_32 atomic_set_32 378164059Scognet#define atomic_cmpset_acq_32 atomic_cmpset_32 379137222Scognet#define atomic_cmpset_rel_32 atomic_cmpset_32 380158593Scognet#define atomic_load_acq_32 atomic_load_32 381165786Sticso#define atomic_store_rel_32 atomic_store_32 382129198Scognet 383129198Scognet#endif /* _MACHINE_ATOMIC_H_ */ 384